Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Merge updates from trunk. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | toTypeFuncs |
Files: | files | file ages | folders |
SHA1: |
6fbad957259eb8c15eaf7e5657240ae2 |
User & Date: | mistachkin 2013-05-15 08:00:44.446 |
Context
2013-06-21
| ||
18:32 | Merge updates from trunk. (check-in: fa2a91e6c6 user: mistachkin tags: toTypeFuncs) | |
2013-05-15
| ||
08:00 | Merge updates from trunk. (check-in: 6fbad95725 user: mistachkin tags: toTypeFuncs) | |
2013-05-09
| ||
18:12 | Add assert()s to the implementation of xRead() in the built-in VFSes to verify that the offset parameter is always non-negative. (check-in: cf5c364224 user: drh tags: trunk) | |
2013-03-13
| ||
20:52 | Merge updates from trunk. (check-in: d63fa039a0 user: mistachkin tags: toTypeFuncs) | |
Changes
Changes to Makefile.in.
︙ | ︙ | |||
163 164 165 166 167 168 169 170 171 172 173 174 175 176 | # LIBOBJS0 = alter.lo analyze.lo attach.lo auth.lo \ backup.lo bitvec.lo btmutex.lo btree.lo build.lo \ callback.lo complete.lo ctime.lo date.lo delete.lo \ 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_unicode.lo fts3_unicode2.lo fts3_write.lo \ func.lo global.lo hash.lo \ icu.lo insert.lo journal.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 \ | > | 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 | # LIBOBJS0 = alter.lo analyze.lo attach.lo auth.lo \ backup.lo bitvec.lo btmutex.lo btree.lo build.lo \ callback.lo complete.lo ctime.lo date.lo delete.lo \ 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 \ func.lo global.lo hash.lo \ icu.lo insert.lo journal.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 \ |
︙ | ︙ | |||
312 313 314 315 316 317 318 319 320 321 322 323 324 325 | $(TOP)/ext/fts3/fts3_hash.h \ $(TOP)/ext/fts3/fts3_icu.c \ $(TOP)/ext/fts3/fts3_porter.c \ $(TOP)/ext/fts3/fts3_snippet.c \ $(TOP)/ext/fts3/fts3_tokenizer.h \ $(TOP)/ext/fts3/fts3_tokenizer.c \ $(TOP)/ext/fts3/fts3_tokenizer1.c \ $(TOP)/ext/fts3/fts3_unicode.c \ $(TOP)/ext/fts3/fts3_unicode2.c \ $(TOP)/ext/fts3/fts3_write.c SRC += \ $(TOP)/ext/icu/sqliteicu.h \ $(TOP)/ext/icu/icu.c SRC += \ | > | 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 | $(TOP)/ext/fts3/fts3_hash.h \ $(TOP)/ext/fts3/fts3_icu.c \ $(TOP)/ext/fts3/fts3_porter.c \ $(TOP)/ext/fts3/fts3_snippet.c \ $(TOP)/ext/fts3/fts3_tokenizer.h \ $(TOP)/ext/fts3/fts3_tokenizer.c \ $(TOP)/ext/fts3/fts3_tokenizer1.c \ $(TOP)/ext/fts3/fts3_tokenize_vtab.c \ $(TOP)/ext/fts3/fts3_unicode.c \ $(TOP)/ext/fts3/fts3_unicode2.c \ $(TOP)/ext/fts3/fts3_write.c SRC += \ $(TOP)/ext/icu/sqliteicu.h \ $(TOP)/ext/icu/icu.c SRC += \ |
︙ | ︙ | |||
355 356 357 358 359 360 361 | $(TOP)/src/test_backup.c \ $(TOP)/src/test_btree.c \ $(TOP)/src/test_config.c \ $(TOP)/src/test_demovfs.c \ $(TOP)/src/test_devsym.c \ $(TOP)/src/test_fs.c \ $(TOP)/src/test_func.c \ | < < < > > > > > > > > > > > > | 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 | $(TOP)/src/test_backup.c \ $(TOP)/src/test_btree.c \ $(TOP)/src/test_config.c \ $(TOP)/src/test_demovfs.c \ $(TOP)/src/test_devsym.c \ $(TOP)/src/test_fs.c \ $(TOP)/src/test_func.c \ $(TOP)/src/test_hexio.c \ $(TOP)/src/test_init.c \ $(TOP)/src/test_intarray.c \ $(TOP)/src/test_journal.c \ $(TOP)/src/test_malloc.c \ $(TOP)/src/test_multiplex.c \ $(TOP)/src/test_mutex.c \ $(TOP)/src/test_onefile.c \ $(TOP)/src/test_osinst.c \ $(TOP)/src/test_pcache.c \ $(TOP)/src/test_quota.c \ $(TOP)/src/test_rtree.c \ $(TOP)/src/test_schema.c \ $(TOP)/src/test_server.c \ $(TOP)/src/test_superlock.c \ $(TOP)/src/test_syscall.c \ $(TOP)/src/test_stat.c \ $(TOP)/src/test_tclvar.c \ $(TOP)/src/test_thread.c \ $(TOP)/src/test_vfs.c \ $(TOP)/src/test_wsd.c \ $(TOP)/ext/fts3/fts3_term.c \ $(TOP)/ext/fts3/fts3_test.c # Statically linked extensions # TESTSRC += \ $(TOP)/ext/misc/amatch.c \ $(TOP)/ext/misc/closure.c \ $(TOP)/ext/misc/fuzzer.c \ $(TOP)/ext/misc/ieee754.c \ $(TOP)/ext/misc/nextchar.c \ $(TOP)/ext/misc/regexp.c \ $(TOP)/ext/misc/spellfix.c \ $(TOP)/ext/misc/wholenumber.c # Source code to the library files needed by the test fixture # TESTSRC2 = \ $(TOP)/src/attach.c \ $(TOP)/src/backup.c \ $(TOP)/src/bitvec.c \ $(TOP)/src/btree.c \ |
︙ | ︙ | |||
497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 | -version-info "8:6:8" \ -avoid-version sqlite3$(TEXE): $(TOP)/src/shell.c libsqlite3.la sqlite3.h $(LTLINK) $(READLINE_FLAGS) \ -o $@ $(TOP)/src/shell.c libsqlite3.la \ $(LIBREADLINE) $(TLIBS) -rpath "$(libdir)" # 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 rm -rf tsrc mkdir tsrc cp -f $(SRC) tsrc rm tsrc/sqlite.h.in tsrc/parse.y $(TCLSH_CMD) $(TOP)/tool/vdbe-compress.tcl <tsrc/vdbe.c >vdbe.new mv vdbe.new tsrc/vdbe.c touch .target_source sqlite3.c: .target_source $(TOP)/tool/mksqlite3c.tcl $(TCLSH_CMD) $(TOP)/tool/mksqlite3c.tcl 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 | > > > > > > | 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 | -version-info "8:6:8" \ -avoid-version sqlite3$(TEXE): $(TOP)/src/shell.c libsqlite3.la sqlite3.h $(LTLINK) $(READLINE_FLAGS) \ -o $@ $(TOP)/src/shell.c libsqlite3.la \ $(LIBREADLINE) $(TLIBS) -rpath "$(libdir)" mptester$(EXE): sqlite3.c $(TOP)/mptest/mptest.c $(LTLINK) -o $@ -I. $(TOP)/mptest/mptest.c sqlite3.c \ $(TLIBS) -rpath "$(libdir)" # 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 rm -rf tsrc mkdir tsrc cp -f $(SRC) tsrc rm tsrc/sqlite.h.in tsrc/parse.y $(TCLSH_CMD) $(TOP)/tool/vdbe-compress.tcl <tsrc/vdbe.c >vdbe.new mv vdbe.new tsrc/vdbe.c touch .target_source sqlite3.c: .target_source $(TOP)/tool/mksqlite3c.tcl $(TCLSH_CMD) $(TOP)/tool/mksqlite3c.tcl cp tsrc/shell.c 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 |
︙ | ︙ | |||
848 849 850 851 852 853 854 855 856 857 858 859 860 861 | fts3_tokenizer.lo: $(TOP)/ext/fts3/fts3_tokenizer.c $(HDR) $(EXTHDR) $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3_tokenizer.c fts3_tokenizer1.lo: $(TOP)/ext/fts3/fts3_tokenizer1.c $(HDR) $(EXTHDR) $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3_tokenizer1.c fts3_unicode.lo: $(TOP)/ext/fts3/fts3_unicode.c $(HDR) $(EXTHDR) $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3_unicode.c fts3_unicode2.lo: $(TOP)/ext/fts3/fts3_unicode2.c $(HDR) $(EXTHDR) $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3_unicode2.c fts3_write.lo: $(TOP)/ext/fts3/fts3_write.c $(HDR) $(EXTHDR) | > > > | 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 | fts3_tokenizer.lo: $(TOP)/ext/fts3/fts3_tokenizer.c $(HDR) $(EXTHDR) $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3_tokenizer.c fts3_tokenizer1.lo: $(TOP)/ext/fts3/fts3_tokenizer1.c $(HDR) $(EXTHDR) $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3_tokenizer1.c fts3_tokenizer_vtab.lo: $(TOP)/ext/fts3/fts3_tokenizer_vtab.c $(HDR) $(EXTHDR) $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3_tokenizer_vtab.c fts3_unicode.lo: $(TOP)/ext/fts3/fts3_unicode.c $(HDR) $(EXTHDR) $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3_unicode.c fts3_unicode2.lo: $(TOP)/ext/fts3/fts3_unicode2.c $(HDR) $(EXTHDR) $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3_unicode2.c fts3_write.lo: $(TOP)/ext/fts3/fts3_write.c $(HDR) $(EXTHDR) |
︙ | ︙ | |||
874 875 876 877 878 879 880 | # TESTFIXTURE_FLAGS = -DTCLSH=1 -DSQLITE_TEST=1 -DSQLITE_CRASH_TEST=1 TESTFIXTURE_FLAGS += -DSQLITE_SERVER=1 -DSQLITE_PRIVATE="" -DSQLITE_CORE TESTFIXTURE_FLAGS += -DBUILD_sqlite TESTFIXTURE_SRC0 = $(TESTSRC2) libsqlite3.la TESTFIXTURE_SRC1 = sqlite3.c | | > | 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 | # TESTFIXTURE_FLAGS = -DTCLSH=1 -DSQLITE_TEST=1 -DSQLITE_CRASH_TEST=1 TESTFIXTURE_FLAGS += -DSQLITE_SERVER=1 -DSQLITE_PRIVATE="" -DSQLITE_CORE TESTFIXTURE_FLAGS += -DBUILD_sqlite TESTFIXTURE_SRC0 = $(TESTSRC2) libsqlite3.la TESTFIXTURE_SRC1 = sqlite3.c TESTFIXTURE_SRC = $(TESTSRC) $(TOP)/src/tclsqlite.c TESTFIXTURE_SRC += $(TESTFIXTURE_SRC$(USE_AMALGAMATION)) testfixture$(TEXE): $(TESTFIXTURE_SRC) $(LTLINK) -DSQLITE_NO_SYNC=1 $(TEMP_STORE) $(TESTFIXTURE_FLAGS) \ -o $@ $(TESTFIXTURE_SRC) $(LIBTCL) $(TLIBS) fulltest: testfixture$(TEXE) sqlite3$(TEXE) |
︙ | ︙ | |||
940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 | rm -f *.da *.bb *.bbg gmon.out rm -rf quota2a quota2b quota2c rm -rf tsrc .target_source rm -f tclsqlite3$(TEXE) rm -f testfixture$(TEXE) test.db rm -f sqlite3.dll sqlite3.lib sqlite3.exp sqlite3.def rm -f sqlite3.c rm -f sqlite3_analyzer$(TEXE) sqlite3_analyzer.c rm -f sqlite-*-output.vsix distclean: clean rm -f config.log config.status libtool Makefile sqlite3.pc # # Windows section # | > > > | 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 | rm -f *.da *.bb *.bbg gmon.out rm -rf quota2a quota2b quota2c rm -rf tsrc .target_source rm -f tclsqlite3$(TEXE) rm -f testfixture$(TEXE) test.db rm -f sqlite3.dll sqlite3.lib sqlite3.exp sqlite3.def rm -f sqlite3.c rm -f sqlite3rc.h rm -f shell.c sqlite3ext.h rm -f sqlite3_analyzer$(TEXE) sqlite3_analyzer.c rm -f sqlite-*-output.vsix rm -f mptester mptester.exe distclean: clean rm -f config.log config.status libtool Makefile sqlite3.pc # # Windows section # |
︙ | ︙ |
Changes to Makefile.msc.
︙ | ︙ | |||
474 475 476 477 478 479 480 | # LIBOBJS0 = alter.lo analyze.lo attach.lo auth.lo \ backup.lo bitvec.lo btmutex.lo btree.lo build.lo \ callback.lo complete.lo ctime.lo date.lo delete.lo \ 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 \ | | | 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 | # LIBOBJS0 = alter.lo analyze.lo attach.lo auth.lo \ backup.lo bitvec.lo btmutex.lo btree.lo build.lo \ callback.lo complete.lo ctime.lo date.lo delete.lo \ 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 \ func.lo global.lo hash.lo \ icu.lo insert.lo journal.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 \ |
︙ | ︙ | |||
634 635 636 637 638 639 640 641 642 643 644 645 646 647 | $(TOP)\ext\fts3\fts3_hash.h \ $(TOP)\ext\fts3\fts3_icu.c \ $(TOP)\ext\fts3\fts3_porter.c \ $(TOP)\ext\fts3\fts3_snippet.c \ $(TOP)\ext\fts3\fts3_tokenizer.h \ $(TOP)\ext\fts3\fts3_tokenizer.c \ $(TOP)\ext\fts3\fts3_tokenizer1.c \ $(TOP)\ext\fts3\fts3_unicode.c \ $(TOP)\ext\fts3\fts3_unicode2.c \ $(TOP)\ext\fts3\fts3_write.c SRC = $(SRC) \ $(TOP)\ext\icu\sqliteicu.h \ $(TOP)\ext\icu\icu.c SRC = $(SRC) \ | > | 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 | $(TOP)\ext\fts3\fts3_hash.h \ $(TOP)\ext\fts3\fts3_icu.c \ $(TOP)\ext\fts3\fts3_porter.c \ $(TOP)\ext\fts3\fts3_snippet.c \ $(TOP)\ext\fts3\fts3_tokenizer.h \ $(TOP)\ext\fts3\fts3_tokenizer.c \ $(TOP)\ext\fts3\fts3_tokenizer1.c \ $(TOP)\ext\fts3\fts3_tokenize_vtab.c \ $(TOP)\ext\fts3\fts3_unicode.c \ $(TOP)\ext\fts3\fts3_unicode2.c \ $(TOP)\ext\fts3\fts3_write.c SRC = $(SRC) \ $(TOP)\ext\icu\sqliteicu.h \ $(TOP)\ext\icu\icu.c SRC = $(SRC) \ |
︙ | ︙ | |||
676 677 678 679 680 681 682 | $(TOP)\src\test_backup.c \ $(TOP)\src\test_btree.c \ $(TOP)\src\test_config.c \ $(TOP)\src\test_demovfs.c \ $(TOP)\src\test_devsym.c \ $(TOP)\src\test_fs.c \ $(TOP)\src\test_func.c \ | < < < > > > > > > > > > > > > > | 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 | $(TOP)\src\test_backup.c \ $(TOP)\src\test_btree.c \ $(TOP)\src\test_config.c \ $(TOP)\src\test_demovfs.c \ $(TOP)\src\test_devsym.c \ $(TOP)\src\test_fs.c \ $(TOP)\src\test_func.c \ $(TOP)\src\test_hexio.c \ $(TOP)\src\test_init.c \ $(TOP)\src\test_intarray.c \ $(TOP)\src\test_journal.c \ $(TOP)\src\test_malloc.c \ $(TOP)\src\test_multiplex.c \ $(TOP)\src\test_mutex.c \ $(TOP)\src\test_onefile.c \ $(TOP)\src\test_osinst.c \ $(TOP)\src\test_pcache.c \ $(TOP)\src\test_quota.c \ $(TOP)\src\test_rtree.c \ $(TOP)\src\test_schema.c \ $(TOP)\src\test_server.c \ $(TOP)\src\test_superlock.c \ $(TOP)\src\test_syscall.c \ $(TOP)\src\test_stat.c \ $(TOP)\src\test_tclvar.c \ $(TOP)\src\test_thread.c \ $(TOP)\src\test_vfs.c \ $(TOP)\src\test_wsd.c \ $(TOP)\ext\fts3\fts3_term.c \ $(TOP)\ext\fts3\fts3_test.c # Statically linked extensions # TESTEXT = \ $(TOP)\ext\misc\amatch.c \ $(TOP)\ext\misc\closure.c \ $(TOP)\ext\misc\fuzzer.c \ $(TOP)\ext\misc\ieee754.c \ $(TOP)\ext\misc\nextchar.c \ $(TOP)\ext\misc\regexp.c \ $(TOP)\ext\misc\spellfix.c \ $(TOP)\ext\misc\wholenumber.c # Source code to the library files needed by the test fixture # TESTSRC2 = \ $(TOP)\src\attach.c \ $(TOP)\src\backup.c \ $(TOP)\src\bitvec.c \ |
︙ | ︙ | |||
744 745 746 747 748 749 750 751 752 753 754 755 756 757 | $(TOP)\src\vdbetrace.c \ $(TOP)\src\where.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_unicode.c \ $(TOP)\ext\fts3\fts3_unicode2.c \ $(TOP)\ext\fts3\fts3_write.c \ $(TOP)\ext\async\sqlite3async.c # Header files used by all library source files. # | > | 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 | $(TOP)\src\vdbetrace.c \ $(TOP)\src\where.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_tokenize_vtab.c \ $(TOP)\ext\fts3\fts3_unicode.c \ $(TOP)\ext\fts3\fts3_unicode2.c \ $(TOP)\ext\fts3\fts3_write.c \ $(TOP)\ext\async\sqlite3async.c # Header files used by all library source files. # |
︙ | ︙ | |||
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 | $(LTLIB) $(LTLIBOPTS) $(LTLIBPATHS) /OUT:$@ tclsqlite.lo libsqlite3.lib $(LIBTCL:tcl=tclstub) $(TLIBS) sqlite3.exe: $(TOP)\src\shell.c libsqlite3.lib $(LIBRESOBJS) sqlite3.h $(LTLINK) $(READLINE_FLAGS) \ $(TOP)\src\shell.c \ /link $(LTLINKOPTS) $(LTLIBPATHS) libsqlite3.lib $(LIBRESOBJS) $(LIBREADLINE) $(LTLIBS) $(TLIBS) # 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 -rmdir /S/Q tsrc -mkdir tsrc for %i in ($(SRC)) do copy /Y %i tsrc del /Q tsrc\sqlite.h.in tsrc\parse.y $(TCLSH_CMD) $(TOP)\tool\vdbe-compress.tcl < tsrc\vdbe.c > vdbe.new move vdbe.new tsrc\vdbe.c echo > .target_source sqlite3.c: .target_source $(TOP)\tool\mksqlite3c.tcl $(TCLSH_CMD) $(TOP)\tool\mksqlite3c.tcl sqlite3-all.c: sqlite3.c $(TOP)\tool\split-sqlite3c.tcl $(TCLSH_CMD) $(TOP)\tool\split-sqlite3c.tcl # Rule to build the amalgamation # sqlite3.lo: sqlite3.c | > > > > > > | 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 | $(LTLIB) $(LTLIBOPTS) $(LTLIBPATHS) /OUT:$@ tclsqlite.lo libsqlite3.lib $(LIBTCL:tcl=tclstub) $(TLIBS) sqlite3.exe: $(TOP)\src\shell.c libsqlite3.lib $(LIBRESOBJS) sqlite3.h $(LTLINK) $(READLINE_FLAGS) \ $(TOP)\src\shell.c \ /link $(LTLINKOPTS) $(LTLIBPATHS) libsqlite3.lib $(LIBRESOBJS) $(LIBREADLINE) $(LTLIBS) $(TLIBS) mptester.exe: $(TOP)\mptest\mptest.c libsqlite3.lib $(LIBRESOBJS) sqlite3.h $(LTLINK) $(TOP)\mptest\mptest.c \ /link $(LTLINKOPTS) $(LTLIBPATHS) libsqlite3.lib $(LIBRESOBJS) $(LIBREADLINE) $(LTLIBS) $(TLIBS) # 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 -rmdir /S/Q tsrc -mkdir tsrc for %i in ($(SRC)) do copy /Y %i tsrc del /Q tsrc\sqlite.h.in tsrc\parse.y $(TCLSH_CMD) $(TOP)\tool\vdbe-compress.tcl < tsrc\vdbe.c > vdbe.new move vdbe.new tsrc\vdbe.c echo > .target_source sqlite3.c: .target_source $(TOP)\tool\mksqlite3c.tcl $(TCLSH_CMD) $(TOP)\tool\mksqlite3c.tcl copy tsrc\shell.c . copy tsrc\sqlite3ext.h . sqlite3-all.c: sqlite3.c $(TOP)\tool\split-sqlite3c.tcl $(TCLSH_CMD) $(TOP)\tool\split-sqlite3c.tcl # Rule to build the amalgamation # sqlite3.lo: sqlite3.c |
︙ | ︙ | |||
1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 | fts3_tokenizer.lo: $(TOP)\ext\fts3\fts3_tokenizer.c $(HDR) $(EXTHDR) $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)\ext\fts3\fts3_tokenizer.c fts3_tokenizer1.lo: $(TOP)\ext\fts3\fts3_tokenizer1.c $(HDR) $(EXTHDR) $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)\ext\fts3\fts3_tokenizer1.c fts3_unicode.lo: $(TOP)\ext\fts3\fts3_unicode.c $(HDR) $(EXTHDR) $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)\ext\fts3\fts3_unicode.c fts3_unicode2.lo: $(TOP)\ext\fts3\fts3_unicode2.c $(HDR) $(EXTHDR) $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)\ext\fts3\fts3_unicode2.c fts3_write.lo: $(TOP)\ext\fts3\fts3_write.c $(HDR) $(EXTHDR) | > > > | 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 | fts3_tokenizer.lo: $(TOP)\ext\fts3\fts3_tokenizer.c $(HDR) $(EXTHDR) $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)\ext\fts3\fts3_tokenizer.c fts3_tokenizer1.lo: $(TOP)\ext\fts3\fts3_tokenizer1.c $(HDR) $(EXTHDR) $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)\ext\fts3\fts3_tokenizer1.c fts3_tokenize_vtab.lo: $(TOP)\ext\fts3\fts3_tokenize_vtab.c $(HDR) $(EXTHDR) $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)\ext\fts3\fts3_tokenize_vtab.c fts3_unicode.lo: $(TOP)\ext\fts3\fts3_unicode.c $(HDR) $(EXTHDR) $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)\ext\fts3\fts3_unicode.c fts3_unicode2.lo: $(TOP)\ext\fts3\fts3_unicode2.c $(HDR) $(EXTHDR) $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)\ext\fts3\fts3_unicode2.c fts3_write.lo: $(TOP)\ext\fts3\fts3_write.c $(HDR) $(EXTHDR) |
︙ | ︙ | |||
1189 1190 1191 1192 1193 1194 1195 | # fixture. Otherwise link against libsqlite3.lib. (This distinction is # necessary because the test fixture requires non-API symbols which are # hidden when the library is built via the amalgamation). # TESTFIXTURE_FLAGS = -DTCLSH=1 -DSQLITE_TEST=1 -DSQLITE_CRASH_TEST=1 TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_SERVER=1 -DSQLITE_PRIVATE="" -DSQLITE_CORE | | | | 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 | # fixture. Otherwise link against libsqlite3.lib. (This distinction is # necessary because the test fixture requires non-API symbols which are # hidden when the library is built via the amalgamation). # TESTFIXTURE_FLAGS = -DTCLSH=1 -DSQLITE_TEST=1 -DSQLITE_CRASH_TEST=1 TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_SERVER=1 -DSQLITE_PRIVATE="" -DSQLITE_CORE TESTFIXTURE_SRC0 = $(TESTEXT) $(TESTSRC2) libsqlite3.lib TESTFIXTURE_SRC1 = $(TESTEXT) sqlite3.c !IF $(USE_AMALGAMATION)==0 TESTFIXTURE_SRC = $(TESTSRC) $(TOP)\src\tclsqlite.c $(TESTFIXTURE_SRC0) !ELSE TESTFIXTURE_SRC = $(TESTSRC) $(TOP)\src\tclsqlite.c $(TESTFIXTURE_SRC1) !ENDIF testfixture.exe: $(TESTFIXTURE_SRC) $(LIBRESOBJS) $(HDR) |
︙ | ︙ | |||
1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 | -rmdir /Q/S tsrc del /Q .target_source del /Q tclsqlite3.exe tclsqlite3.exp del /Q testfixture.exe testfixture.exp test.db del /Q sqlite3.dll sqlite3.lib sqlite3.exp sqlite3.def del /Q sqlite3.c del /Q sqlite3rc.h del /Q sqlite3_analyzer.exe sqlite3_analyzer.exp sqlite3_analyzer.c del /Q sqlite-*-output.vsix # Dynamic link library section. # dll: sqlite3.dll sqlite3.def: libsqlite3.lib echo EXPORTS > sqlite3.def dumpbin /all libsqlite3.lib \ | $(NAWK) "/ 1 _?sqlite3_/ { sub(/^.* _?/,\"\");print }" \ | sort >> sqlite3.def sqlite3.dll: $(LIBOBJ) $(LIBRESOBJS) sqlite3.def $(LD) $(LDFLAGS) $(LTLINKOPTS) $(LTLIBPATHS) /DLL /DEF:sqlite3.def /OUT:$@ $(LIBOBJ) $(LIBRESOBJS) $(LTLIBS) $(TLIBS) | > > | 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 | -rmdir /Q/S tsrc del /Q .target_source del /Q tclsqlite3.exe tclsqlite3.exp del /Q testfixture.exe testfixture.exp test.db del /Q sqlite3.dll sqlite3.lib sqlite3.exp sqlite3.def del /Q sqlite3.c del /Q sqlite3rc.h del /Q shell.c sqlite3ext.h del /Q sqlite3_analyzer.exe sqlite3_analyzer.exp sqlite3_analyzer.c del /Q sqlite-*-output.vsix del /Q mptester.exe # Dynamic link library section. # dll: sqlite3.dll sqlite3.def: libsqlite3.lib echo EXPORTS > sqlite3.def dumpbin /all libsqlite3.lib \ | $(NAWK) "/ 1 _?sqlite3_/ { sub(/^.* _?/,\"\");print }" \ | sort >> sqlite3.def sqlite3.dll: $(LIBOBJ) $(LIBRESOBJS) sqlite3.def $(LD) $(LDFLAGS) $(LTLINKOPTS) $(LTLIBPATHS) /DLL /DEF:sqlite3.def /OUT:$@ $(LIBOBJ) $(LIBRESOBJS) $(LTLIBS) $(TLIBS) |
Changes to Makefile.vxworks.
︙ | ︙ | |||
658 659 660 661 662 663 664 665 | rm -f lemon lempar.c parse.* sqlite*.tar.gz mkkeywordhash keywordhash.h rm -f $(PUBLISH) rm -f *.da *.bb *.bbg gmon.out rm -rf quota2a quota2b quota2c rm -rf tsrc target_source rm -f testloadext.dll libtestloadext.so rm -f sqlite3.c fts?amal.c tclsqlite3.c rm -f $(SHPREFIX)sqlite3.$(SO) | > > | 658 659 660 661 662 663 664 665 666 667 | rm -f lemon lempar.c parse.* sqlite*.tar.gz mkkeywordhash keywordhash.h rm -f $(PUBLISH) rm -f *.da *.bb *.bbg gmon.out rm -rf quota2a quota2b quota2c rm -rf tsrc target_source rm -f testloadext.dll libtestloadext.so rm -f sqlite3.c fts?amal.c tclsqlite3.c rm -f sqlite3rc.h rm -f shell.c sqlite3ext.h rm -f $(SHPREFIX)sqlite3.$(SO) |
Changes to VERSION.
|
| | | 1 | 3.7.17 |
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.62 for sqlite 3.7.17. # # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, # 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## --------------------- ## ## M4sh Initialization. ## |
︙ | ︙ | |||
739 740 741 742 743 744 745 | MFLAGS= MAKEFLAGS= SHELL=${CONFIG_SHELL-/bin/sh} # Identity of this package. PACKAGE_NAME='sqlite' PACKAGE_TARNAME='sqlite' | | | | 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 | MFLAGS= MAKEFLAGS= SHELL=${CONFIG_SHELL-/bin/sh} # Identity of this package. PACKAGE_NAME='sqlite' PACKAGE_TARNAME='sqlite' PACKAGE_VERSION='3.7.17' PACKAGE_STRING='sqlite 3.7.17' PACKAGE_BUGREPORT='' # Factoring default headers for most tests. ac_includes_default="\ #include <stdio.h> #ifdef HAVE_SYS_TYPES_H # include <sys/types.h> |
︙ | ︙ | |||
1480 1481 1482 1483 1484 1485 1486 | # # 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 | | | 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 | # # 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.7.17 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. |
︙ | ︙ | |||
1545 1546 1547 1548 1549 1550 1551 | --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 | | | 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 | --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.7.17:";; 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] |
︙ | ︙ | |||
1661 1662 1663 1664 1665 1666 1667 | cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF | | | | 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 | 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.7.17 generated by GNU Autoconf 2.62 Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 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 fi 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.7.17, which was generated by GNU Autoconf 2.62. Invocation command line was $ $0 $@ _ACEOF exec 5>>config.log { |
︙ | ︙ | |||
14028 14029 14030 14031 14032 14033 14034 | exec 6>&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=" | | | 14028 14029 14030 14031 14032 14033 14034 14035 14036 14037 14038 14039 14040 14041 14042 | exec 6>&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.7.17, which was generated by GNU Autoconf 2.62. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ |
︙ | ︙ | |||
14081 14082 14083 14084 14085 14086 14087 | $config_commands Report bugs to <bug-autoconf@gnu.org>." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_version="\\ | | | 14081 14082 14083 14084 14085 14086 14087 14088 14089 14090 14091 14092 14093 14094 14095 | $config_commands Report bugs to <bug-autoconf@gnu.org>." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_version="\\ sqlite config.status 3.7.17 configured by $0, generated by GNU Autoconf 2.62, with options \\"`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\" Copyright (C) 2008 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." |
︙ | ︙ |
Changes to ext/fts1/ft_hash.h.
1 2 3 4 5 6 7 8 9 10 11 | /* ** 2001 September 22 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | /* ** 2001 September 22 ** ** 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 is the header file for the generic hash-table implementation ** used in SQLite. We've modified it slightly to serve as a standalone ** hash table implementation for the full-text indexing module. ** */ #ifndef _HASH_H_ #define _HASH_H_ |
︙ | ︙ |
Changes to ext/fts1/fts1_hash.h.
1 2 3 4 5 6 7 8 9 10 11 | /* ** 2001 September 22 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | /* ** 2001 September 22 ** ** 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 is the header file for the generic hash-table implementation ** used in SQLite. We've modified it slightly to serve as a standalone ** hash table implementation for the full-text indexing module. ** */ #ifndef _FTS1_HASH_H_ #define _FTS1_HASH_H_ |
︙ | ︙ |
Changes to ext/fts2/fts2.c.
︙ | ︙ | |||
6775 6776 6777 6778 6779 6780 6781 | void sqlite3Fts2SimpleTokenizerModule(sqlite3_tokenizer_module const**ppModule); void sqlite3Fts2PorterTokenizerModule(sqlite3_tokenizer_module const**ppModule); void sqlite3Fts2IcuTokenizerModule(sqlite3_tokenizer_module const**ppModule); int sqlite3Fts2InitHashTable(sqlite3 *, fts2Hash *, const char *); /* | | | | 6775 6776 6777 6778 6779 6780 6781 6782 6783 6784 6785 6786 6787 6788 6789 6790 6791 6792 6793 6794 6795 6796 6797 6798 6799 6800 6801 6802 6803 6804 6805 6806 6807 | void sqlite3Fts2SimpleTokenizerModule(sqlite3_tokenizer_module const**ppModule); void sqlite3Fts2PorterTokenizerModule(sqlite3_tokenizer_module const**ppModule); void sqlite3Fts2IcuTokenizerModule(sqlite3_tokenizer_module const**ppModule); int sqlite3Fts2InitHashTable(sqlite3 *, fts2Hash *, const char *); /* ** Initialize the fts2 extension. If this extension is built as part ** of the sqlite library, then this function is called directly by ** SQLite. If fts2 is built as a dynamically loadable extension, this ** function is called by the sqlite3_extension_init() entry point. */ int sqlite3Fts2Init(sqlite3 *db){ int rc = SQLITE_OK; fts2Hash *pHash = 0; const sqlite3_tokenizer_module *pSimple = 0; const sqlite3_tokenizer_module *pPorter = 0; const sqlite3_tokenizer_module *pIcu = 0; sqlite3Fts2SimpleTokenizerModule(&pSimple); sqlite3Fts2PorterTokenizerModule(&pPorter); #ifdef SQLITE_ENABLE_ICU sqlite3Fts2IcuTokenizerModule(&pIcu); #endif /* Allocate and initialize the hash-table used to store tokenizers. */ pHash = sqlite3_malloc(sizeof(fts2Hash)); if( !pHash ){ rc = SQLITE_NOMEM; }else{ sqlite3Fts2HashInit(pHash, FTS2_HASH_STRING, 1); } |
︙ | ︙ |
Changes to ext/fts2/fts2_hash.h.
1 2 3 4 5 6 7 8 9 10 11 | /* ** 2001 September 22 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | /* ** 2001 September 22 ** ** 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 is the header file for the generic hash-table implementation ** used in SQLite. We've modified it slightly to serve as a standalone ** hash table implementation for the full-text indexing module. ** */ #ifndef _FTS2_HASH_H_ #define _FTS2_HASH_H_ |
︙ | ︙ |
Changes to ext/fts2/fts2_tokenizer.c.
︙ | ︙ | |||
315 316 317 318 319 320 321 | } #endif /* ** Set up SQL objects in database db used to access the contents of ** the hash table pointed to by argument pHash. The hash table must | | | 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 | } #endif /* ** Set up SQL objects in database db used to access the contents of ** the hash table pointed to by argument pHash. The hash table must ** been initialized to use string keys, and to take a private copy ** of the key when a value is inserted. i.e. by a call similar to: ** ** sqlite3Fts2HashInit(pHash, FTS2_HASH_STRING, 1); ** ** This function adds a scalar function (see header comment above ** scalarFunc() in this file for details) and, if ENABLE_TABLE is ** defined at compilation time, a temporary virtual table (see header |
︙ | ︙ |
Changes to ext/fts2/fts2_tokenizer.h.
︙ | ︙ | |||
66 67 68 69 70 71 72 | ** ** then argc is set to 2, and the argv[] array contains pointers ** to the strings "arg1" and "arg2". ** ** This method should return either SQLITE_OK (0), or an SQLite error ** code. If SQLITE_OK is returned, then *ppTokenizer should be set ** to point at the newly created tokenizer structure. The generic | | | 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 | ** ** then argc is set to 2, and the argv[] array contains pointers ** to the strings "arg1" and "arg2". ** ** This method should return either SQLITE_OK (0), or an SQLite error ** code. If SQLITE_OK is returned, then *ppTokenizer should be set ** to point at the newly created tokenizer structure. The generic ** sqlite3_tokenizer.pModule variable should not be initialized by ** this callback. The caller will do so. */ int (*xCreate)( int argc, /* Size of argv array */ const char *const*argv, /* Tokenizer argument strings */ sqlite3_tokenizer **ppTokenizer /* OUT: Created tokenizer */ ); |
︙ | ︙ |
Changes to ext/fts3/fts3.c.
︙ | ︙ | |||
1567 1568 1569 1570 1571 1572 1573 | sqlite3_bind_int64(pCsr->pStmt, 1, pCsr->iPrevId); pCsr->isRequireSeek = 0; if( SQLITE_ROW==sqlite3_step(pCsr->pStmt) ){ return SQLITE_OK; }else{ rc = sqlite3_reset(pCsr->pStmt); if( rc==SQLITE_OK && ((Fts3Table *)pCsr->base.pVtab)->zContentTbl==0 ){ | | | 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 | sqlite3_bind_int64(pCsr->pStmt, 1, pCsr->iPrevId); pCsr->isRequireSeek = 0; if( SQLITE_ROW==sqlite3_step(pCsr->pStmt) ){ return SQLITE_OK; }else{ rc = sqlite3_reset(pCsr->pStmt); if( rc==SQLITE_OK && ((Fts3Table *)pCsr->base.pVtab)->zContentTbl==0 ){ /* If no row was found and no error has occurred, then the %_content ** table is missing a row that is present in the full-text index. ** The data structures are corrupt. */ rc = FTS_CORRUPT_VTAB; pCsr->isEof = 1; } } } |
︙ | ︙ | |||
2807 2808 2809 2810 2811 2812 2813 | */ static void fts3SegReaderCursorFree(Fts3MultiSegReader *pSegcsr){ sqlite3Fts3SegReaderFinish(pSegcsr); sqlite3_free(pSegcsr); } /* | | | 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 | */ static void fts3SegReaderCursorFree(Fts3MultiSegReader *pSegcsr){ sqlite3Fts3SegReaderFinish(pSegcsr); sqlite3_free(pSegcsr); } /* ** This function retrieves the doclist for the specified term (or term ** prefix) from the database. */ static int fts3TermSelect( Fts3Table *p, /* Virtual table handle */ Fts3PhraseToken *pTok, /* Token to query for */ int iColumn, /* Column to query (or -ve for all columns) */ int *pnOut, /* OUT: Size of buffer at *ppOut */ |
︙ | ︙ | |||
2971 2972 2973 2974 2975 2976 2977 2978 | if( zQuery==0 && sqlite3_value_type(apVal[0])!=SQLITE_NULL ){ return SQLITE_NOMEM; } pCsr->iLangid = 0; if( nVal==2 ) pCsr->iLangid = sqlite3_value_int(apVal[1]); rc = sqlite3Fts3ExprParse(p->pTokenizer, pCsr->iLangid, | > | > < < < < | 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 | if( zQuery==0 && sqlite3_value_type(apVal[0])!=SQLITE_NULL ){ return SQLITE_NOMEM; } pCsr->iLangid = 0; if( nVal==2 ) pCsr->iLangid = sqlite3_value_int(apVal[1]); assert( p->base.zErrMsg==0 ); rc = sqlite3Fts3ExprParse(p->pTokenizer, pCsr->iLangid, p->azColumn, p->bFts4, p->nColumn, iCol, zQuery, -1, &pCsr->pExpr, &p->base.zErrMsg ); if( rc!=SQLITE_OK ){ return rc; } rc = sqlite3Fts3ReadLock(p); if( rc!=SQLITE_OK ) return rc; rc = fts3EvalStart(pCsr); |
︙ | ︙ | |||
3558 3559 3560 3561 3562 3563 3564 | void sqlite3Fts3UnicodeTokenizer(sqlite3_tokenizer_module const**ppModule); #endif #ifdef SQLITE_ENABLE_ICU void sqlite3Fts3IcuTokenizerModule(sqlite3_tokenizer_module const**ppModule); #endif /* | | | 3556 3557 3558 3559 3560 3561 3562 3563 3564 3565 3566 3567 3568 3569 3570 | void sqlite3Fts3UnicodeTokenizer(sqlite3_tokenizer_module const**ppModule); #endif #ifdef SQLITE_ENABLE_ICU void sqlite3Fts3IcuTokenizerModule(sqlite3_tokenizer_module const**ppModule); #endif /* ** Initialize the fts3 extension. If this extension is built as part ** of the sqlite library, then this function is called directly by ** SQLite. If fts3 is built as a dynamically loadable extension, this ** function is called by the sqlite3_extension_init() entry point. */ int sqlite3Fts3Init(sqlite3 *db){ int rc = SQLITE_OK; Fts3Hash *pHash = 0; |
︙ | ︙ | |||
3592 3593 3594 3595 3596 3597 3598 | rc = sqlite3Fts3InitAux(db); if( rc!=SQLITE_OK ) return rc; sqlite3Fts3SimpleTokenizerModule(&pSimple); sqlite3Fts3PorterTokenizerModule(&pPorter); | | | 3590 3591 3592 3593 3594 3595 3596 3597 3598 3599 3600 3601 3602 3603 3604 | rc = sqlite3Fts3InitAux(db); if( rc!=SQLITE_OK ) return rc; sqlite3Fts3SimpleTokenizerModule(&pSimple); sqlite3Fts3PorterTokenizerModule(&pPorter); /* Allocate and initialize the hash-table used to store tokenizers. */ pHash = sqlite3_malloc(sizeof(Fts3Hash)); if( !pHash ){ rc = SQLITE_NOMEM; }else{ sqlite3Fts3HashInit(pHash, FTS3_HASH_STRING, 1); } |
︙ | ︙ | |||
3642 3643 3644 3645 3646 3647 3648 3649 3650 3651 3652 3653 3654 3655 3656 3657 | db, "fts3", &fts3Module, (void *)pHash, hashDestroy ); if( rc==SQLITE_OK ){ rc = sqlite3_create_module_v2( db, "fts4", &fts3Module, (void *)pHash, 0 ); } return rc; } /* An error has occurred. Delete the hash table and return the error code. */ assert( rc!=SQLITE_OK ); if( pHash ){ sqlite3Fts3HashClear(pHash); sqlite3_free(pHash); } | > > > > | 3640 3641 3642 3643 3644 3645 3646 3647 3648 3649 3650 3651 3652 3653 3654 3655 3656 3657 3658 3659 | db, "fts3", &fts3Module, (void *)pHash, hashDestroy ); if( rc==SQLITE_OK ){ rc = sqlite3_create_module_v2( db, "fts4", &fts3Module, (void *)pHash, 0 ); } if( rc==SQLITE_OK ){ rc = sqlite3Fts3InitTok(db, (void *)pHash); } return rc; } /* An error has occurred. Delete the hash table and return the error code. */ assert( rc!=SQLITE_OK ); if( pHash ){ sqlite3Fts3HashClear(pHash); sqlite3_free(pHash); } |
︙ | ︙ | |||
5191 5192 5193 5194 5195 5196 5197 | ** must be of type FTSQUERY_PHRASE. ** ** The returned value is either NULL or a pointer to a buffer containing ** a position-list indicating the occurrences of the phrase in column iCol ** of the current row. ** ** More specifically, the returned buffer contains 1 varint for each | | | 5193 5194 5195 5196 5197 5198 5199 5200 5201 5202 5203 5204 5205 5206 5207 | ** must be of type FTSQUERY_PHRASE. ** ** The returned value is either NULL or a pointer to a buffer containing ** a position-list indicating the occurrences of the phrase in column iCol ** of the current row. ** ** More specifically, the returned buffer contains 1 varint for each ** occurrence of the phrase in the column, stored using the normal (delta+2) ** compression and is terminated by either an 0x01 or 0x00 byte. For example, ** if the requested column contains "a b X c d X X" and the position-list ** for 'X' is requested, the buffer returned may contain: ** ** 0x04 0x05 0x03 0x01 or 0x04 0x05 0x03 0x00 ** ** This function works regardless of whether or not the phrase is deferred, |
︙ | ︙ |
Changes to ext/fts3/fts3Int.h.
︙ | ︙ | |||
520 521 522 523 524 525 526 | void sqlite3Fts3Snippet(sqlite3_context *, Fts3Cursor *, const char *, const char *, const char *, int, int ); void sqlite3Fts3Matchinfo(sqlite3_context *, Fts3Cursor *, const char *); /* fts3_expr.c */ int sqlite3Fts3ExprParse(sqlite3_tokenizer *, int, | | | 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 | void sqlite3Fts3Snippet(sqlite3_context *, Fts3Cursor *, const char *, const char *, const char *, int, int ); void sqlite3Fts3Matchinfo(sqlite3_context *, Fts3Cursor *, const char *); /* fts3_expr.c */ int sqlite3Fts3ExprParse(sqlite3_tokenizer *, int, char **, int, int, int, const char *, int, Fts3Expr **, char ** ); void sqlite3Fts3ExprFree(Fts3Expr *); #ifdef SQLITE_TEST int sqlite3Fts3ExprInitTestInterface(sqlite3 *db); int sqlite3Fts3InitTerm(sqlite3 *db); #endif |
︙ | ︙ | |||
545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 | Fts3Table*, Fts3MultiSegReader*, int, const char*, int); int sqlite3Fts3MsrIncrNext( Fts3Table *, Fts3MultiSegReader *, sqlite3_int64 *, char **, int *); int sqlite3Fts3EvalPhrasePoslist(Fts3Cursor *, Fts3Expr *, int iCol, char **); int sqlite3Fts3MsrOvfl(Fts3Cursor *, Fts3MultiSegReader *, int *); int sqlite3Fts3MsrIncrRestart(Fts3MultiSegReader *pCsr); /* fts3_unicode2.c (functions generated by parsing unicode text files) */ #ifdef SQLITE_ENABLE_FTS4_UNICODE61 int sqlite3FtsUnicodeFold(int, int); int sqlite3FtsUnicodeIsalnum(int); int sqlite3FtsUnicodeIsdiacritic(int); #endif #endif /* !SQLITE_CORE || SQLITE_ENABLE_FTS3 */ #endif /* _FTSINT_H */ | > > > | 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 | Fts3Table*, Fts3MultiSegReader*, int, const char*, int); int sqlite3Fts3MsrIncrNext( Fts3Table *, Fts3MultiSegReader *, sqlite3_int64 *, char **, int *); int sqlite3Fts3EvalPhrasePoslist(Fts3Cursor *, Fts3Expr *, int iCol, char **); int sqlite3Fts3MsrOvfl(Fts3Cursor *, Fts3MultiSegReader *, int *); int sqlite3Fts3MsrIncrRestart(Fts3MultiSegReader *pCsr); /* fts3_tokenize_vtab.c */ int sqlite3Fts3InitTok(sqlite3*, Fts3Hash *); /* fts3_unicode2.c (functions generated by parsing unicode text files) */ #ifdef SQLITE_ENABLE_FTS4_UNICODE61 int sqlite3FtsUnicodeFold(int, int); int sqlite3FtsUnicodeIsalnum(int); int sqlite3FtsUnicodeIsdiacritic(int); #endif #endif /* !SQLITE_CORE || SQLITE_ENABLE_FTS3 */ #endif /* _FTSINT_H */ |
Changes to ext/fts3/fts3_aux.c.
︙ | ︙ | |||
66 67 68 69 70 71 72 | int nFts3; /* Result of strlen(zFts3) */ int nByte; /* Bytes of space to allocate here */ int rc; /* value returned by declare_vtab() */ Fts3auxTable *p; /* Virtual table object to return */ UNUSED_PARAMETER(pUnused); | | > > > > | < < < < < > > > > > > > > > > | 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 | int nFts3; /* Result of strlen(zFts3) */ int nByte; /* Bytes of space to allocate here */ int rc; /* value returned by declare_vtab() */ Fts3auxTable *p; /* Virtual table object to return */ UNUSED_PARAMETER(pUnused); /* The user should invoke this in one of two forms: ** ** CREATE VIRTUAL TABLE xxx USING fts4aux(fts4-table); ** CREATE VIRTUAL TABLE xxx USING fts4aux(fts4-table-db, fts4-table); */ if( argc!=4 && argc!=5 ) goto bad_args; zDb = argv[1]; nDb = (int)strlen(zDb); if( argc==5 ){ if( nDb==4 && 0==sqlite3_strnicmp("temp", zDb, 4) ){ zDb = argv[3]; nDb = (int)strlen(zDb); zFts3 = argv[4]; }else{ goto bad_args; } }else{ zFts3 = argv[3]; } nFts3 = (int)strlen(zFts3); rc = sqlite3_declare_vtab(db, FTS3_TERMS_SCHEMA); if( rc!=SQLITE_OK ) return rc; nByte = sizeof(Fts3auxTable) + sizeof(Fts3Table) + nDb + nFts3 + 2; p = (Fts3auxTable *)sqlite3_malloc(nByte); |
︙ | ︙ | |||
99 100 101 102 103 104 105 106 107 108 109 110 111 112 | memcpy((char *)p->pFts3Tab->zDb, zDb, nDb); memcpy((char *)p->pFts3Tab->zName, zFts3, nFts3); sqlite3Fts3Dequote((char *)p->pFts3Tab->zName); *ppVtab = (sqlite3_vtab *)p; return SQLITE_OK; } /* ** This function does the work for both the xDisconnect and xDestroy methods. ** These tables have no persistent representation of their own, so xDisconnect ** and xDestroy are identical operations. */ | > > > > | 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 | memcpy((char *)p->pFts3Tab->zDb, zDb, nDb); memcpy((char *)p->pFts3Tab->zName, zFts3, nFts3); sqlite3Fts3Dequote((char *)p->pFts3Tab->zName); *ppVtab = (sqlite3_vtab *)p; return SQLITE_OK; bad_args: *pzErr = sqlite3_mprintf("invalid arguments to fts4aux constructor"); return SQLITE_ERROR; } /* ** This function does the work for both the xDisconnect and xDestroy methods. ** These tables have no persistent representation of their own, so xDisconnect ** and xDestroy are identical operations. */ |
︙ | ︙ |
Changes to ext/fts3/fts3_expr.c.
︙ | ︙ | |||
102 103 104 105 106 107 108 | int nNest; /* Number of nested brackets */ }; /* ** This function is equivalent to the standard isspace() function. ** ** The standard isspace() can be awkward to use safely, because although it | | | 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 | int nNest; /* Number of nested brackets */ }; /* ** This function is equivalent to the standard isspace() function. ** ** The standard isspace() can be awkward to use safely, because although it ** is defined to accept an argument of type int, its behavior when passed ** an integer that falls outside of the range of the unsigned char type ** is undefined (and sometimes, "undefined" means segfault). This wrapper ** is defined to accept an argument of type char, and always returns 0 for ** any values that fall outside of the range of the unsigned char type (i.e. ** negative values). */ static int fts3isspace(char c){ |
︙ | ︙ | |||
636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 | if( !pNot ){ sqlite3Fts3ExprFree(p); rc = SQLITE_NOMEM; goto exprparse_out; } pNot->eType = FTSQUERY_NOT; pNot->pRight = p; if( pNotBranch ){ pNot->pLeft = pNotBranch; } pNotBranch = pNot; p = pPrev; }else{ int eType = p->eType; isPhrase = (eType==FTSQUERY_PHRASE || p->pLeft); | > > | 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 | if( !pNot ){ sqlite3Fts3ExprFree(p); rc = SQLITE_NOMEM; goto exprparse_out; } pNot->eType = FTSQUERY_NOT; pNot->pRight = p; p->pParent = pNot; if( pNotBranch ){ pNot->pLeft = pNotBranch; pNotBranch->pParent = pNot; } pNotBranch = pNot; p = pPrev; }else{ int eType = p->eType; isPhrase = (eType==FTSQUERY_PHRASE || p->pLeft); |
︙ | ︙ | |||
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 | rc = SQLITE_ERROR; }else{ Fts3Expr *pIter = pNotBranch; while( pIter->pLeft ){ pIter = pIter->pLeft; } pIter->pLeft = pRet; pRet = pNotBranch; } } } *pnConsumed = n - nIn; exprparse_out: if( rc!=SQLITE_OK ){ sqlite3Fts3ExprFree(pRet); sqlite3Fts3ExprFree(pNotBranch); pRet = 0; } *ppExpr = pRet; return rc; } /* ** Parameters z and n contain a pointer to and length of a buffer containing ** an fts3 query expression, respectively. This function attempts to parse the ** query expression and create a tree of Fts3Expr structures representing the ** parsed expression. If successful, *ppExpr is set to point to the head ** of the parsed expression tree and SQLITE_OK is returned. If an error | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 | rc = SQLITE_ERROR; }else{ Fts3Expr *pIter = pNotBranch; while( pIter->pLeft ){ pIter = pIter->pLeft; } pIter->pLeft = pRet; pRet->pParent = pIter; pRet = pNotBranch; } } } *pnConsumed = n - nIn; exprparse_out: if( rc!=SQLITE_OK ){ sqlite3Fts3ExprFree(pRet); sqlite3Fts3ExprFree(pNotBranch); pRet = 0; } *ppExpr = pRet; return rc; } /* ** Return SQLITE_ERROR if the maximum depth of the expression tree passed ** as the only argument is more than nMaxDepth. */ static int fts3ExprCheckDepth(Fts3Expr *p, int nMaxDepth){ int rc = SQLITE_OK; if( p ){ if( nMaxDepth<0 ){ rc = SQLITE_TOOBIG; }else{ rc = fts3ExprCheckDepth(p->pLeft, nMaxDepth-1); if( rc==SQLITE_OK ){ rc = fts3ExprCheckDepth(p->pRight, nMaxDepth-1); } } } return rc; } /* ** This function attempts to transform the expression tree at (*pp) to ** an equivalent but more balanced form. The tree is modified in place. ** If successful, SQLITE_OK is returned and (*pp) set to point to the ** new root expression node. ** ** nMaxDepth is the maximum allowable depth of the balanced sub-tree. ** ** Otherwise, if an error occurs, an SQLite error code is returned and ** expression (*pp) freed. */ static int fts3ExprBalance(Fts3Expr **pp, int nMaxDepth){ int rc = SQLITE_OK; /* Return code */ Fts3Expr *pRoot = *pp; /* Initial root node */ 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 && (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 ); } } if( rc!=SQLITE_OK ){ sqlite3Fts3ExprFree(pRoot); pRoot = 0; } *pp = pRoot; return rc; } /* ** This function is similar to sqlite3Fts3ExprParse(), with the following ** differences: ** ** 1. It does not do expression rebalancing. ** 2. It does not check that the expression does not exceed the ** maximum allowable depth. ** 3. Even if it fails, *ppExpr may still be set to point to an ** expression tree. It should be deleted using sqlite3Fts3ExprFree() ** in this case. */ static int fts3ExprParseUnbalanced( sqlite3_tokenizer *pTokenizer, /* Tokenizer module */ int iLangid, /* Language id for tokenizer */ char **azCol, /* Array of column names for fts3 table */ int bFts4, /* True to allow FTS4-only syntax */ int nCol, /* Number of entries in azCol[] */ int iDefaultCol, /* Default column to query */ const char *z, int n, /* Text of MATCH query */ Fts3Expr **ppExpr /* OUT: Parsed query structure */ ){ int nParsed; int rc; ParseContext sParse; memset(&sParse, 0, sizeof(ParseContext)); sParse.pTokenizer = pTokenizer; sParse.iLangid = iLangid; sParse.azCol = (const char **)azCol; sParse.nCol = nCol; sParse.iDefaultCol = iDefaultCol; sParse.bFts4 = bFts4; if( z==0 ){ *ppExpr = 0; return SQLITE_OK; } if( n<0 ){ n = (int)strlen(z); } rc = fts3ExprParse(&sParse, z, n, ppExpr, &nParsed); assert( rc==SQLITE_OK || *ppExpr==0 ); /* Check for mismatched parenthesis */ if( rc==SQLITE_OK && sParse.nNest ){ rc = SQLITE_ERROR; } return rc; } /* ** Parameters z and n contain a pointer to and length of a buffer containing ** an fts3 query expression, respectively. This function attempts to parse the ** query expression and create a tree of Fts3Expr structures representing the ** parsed expression. If successful, *ppExpr is set to point to the head ** of the parsed expression tree and SQLITE_OK is returned. If an error |
︙ | ︙ | |||
773 774 775 776 777 778 779 | sqlite3_tokenizer *pTokenizer, /* Tokenizer module */ int iLangid, /* Language id for tokenizer */ char **azCol, /* Array of column names for fts3 table */ int bFts4, /* True to allow FTS4-only syntax */ int nCol, /* Number of entries in azCol[] */ int iDefaultCol, /* Default column to query */ const char *z, int n, /* Text of MATCH query */ | | > | | < > > < < | | < < < | | | > < < < < | < > > > > > > > > | | < < < > > > > > > > > > > > > > > > > > > > > > > > > > > > | 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 | sqlite3_tokenizer *pTokenizer, /* Tokenizer module */ int iLangid, /* Language id for tokenizer */ char **azCol, /* Array of column names for fts3 table */ int bFts4, /* True to allow FTS4-only syntax */ int nCol, /* Number of entries in azCol[] */ int iDefaultCol, /* Default column to query */ const char *z, int n, /* Text of MATCH query */ Fts3Expr **ppExpr, /* OUT: Parsed query structure */ char **pzErr /* OUT: Error message (sqlite3_malloc) */ ){ static const int MAX_EXPR_DEPTH = 12; int rc = fts3ExprParseUnbalanced( pTokenizer, iLangid, azCol, bFts4, nCol, iDefaultCol, z, n, ppExpr ); /* Rebalance the expression. And check that its depth does not exceed ** MAX_EXPR_DEPTH. */ if( rc==SQLITE_OK && *ppExpr ){ rc = fts3ExprBalance(ppExpr, MAX_EXPR_DEPTH); if( rc==SQLITE_OK ){ rc = fts3ExprCheckDepth(*ppExpr, MAX_EXPR_DEPTH); } } if( rc!=SQLITE_OK ){ sqlite3Fts3ExprFree(*ppExpr); *ppExpr = 0; if( rc==SQLITE_TOOBIG ){ *pzErr = sqlite3_mprintf( "FTS expression tree is too large (maximum depth %d)", MAX_EXPR_DEPTH ); rc = SQLITE_ERROR; }else if( rc==SQLITE_ERROR ){ *pzErr = sqlite3_mprintf("malformed MATCH expression: [%s]", z); } } return rc; } /* ** Free a single node of an expression tree. */ static void fts3FreeExprNode(Fts3Expr *p){ assert( p->eType==FTSQUERY_PHRASE || p->pPhrase==0 ); sqlite3Fts3EvalPhraseCleanup(p->pPhrase); sqlite3_free(p->aMI); sqlite3_free(p); } /* ** Free a parsed fts3 query expression allocated by sqlite3Fts3ExprParse(). ** ** This function would be simpler if it recursively called itself. But ** that would mean passing a sufficiently large expression to ExprParse() ** could cause a stack overflow. */ void sqlite3Fts3ExprFree(Fts3Expr *pDel){ Fts3Expr *p; assert( pDel==0 || pDel->pParent==0 ); for(p=pDel; p && (p->pLeft||p->pRight); p=(p->pLeft ? p->pLeft : p->pRight)){ assert( p->pParent==0 || p==p->pParent->pRight || p==p->pParent->pLeft ); } while( p ){ Fts3Expr *pParent = p->pParent; fts3FreeExprNode(p); if( pParent && p==pParent->pLeft && pParent->pRight ){ p = pParent->pRight; while( p && (p->pLeft || p->pRight) ){ assert( p==p->pParent->pRight || p==p->pParent->pLeft ); p = (p->pLeft ? p->pLeft : p->pRight); } }else{ p = pParent; } } } /**************************************************************************** ***************************************************************************** ** Everything after this point is just test code. */ |
︙ | ︙ | |||
867 868 869 870 871 872 873 874 875 876 877 878 879 880 | ** sqlite3_free() to release the memory. If an OOM condition is encountered, ** NULL is returned. ** ** If the second argument is not NULL, then its contents are prepended to ** the returned expression text and then freed using sqlite3_free(). */ static char *exprToString(Fts3Expr *pExpr, char *zBuf){ switch( pExpr->eType ){ case FTSQUERY_PHRASE: { Fts3Phrase *pPhrase = pExpr->pPhrase; int i; zBuf = sqlite3_mprintf( "%zPHRASE %d 0", zBuf, pPhrase->iColumn); for(i=0; zBuf && i<pPhrase->nToken; i++){ | > > > | 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 | ** sqlite3_free() to release the memory. If an OOM condition is encountered, ** NULL is returned. ** ** If the second argument is not NULL, then its contents are prepended to ** the returned expression text and then freed using sqlite3_free(). */ static char *exprToString(Fts3Expr *pExpr, char *zBuf){ if( pExpr==0 ){ return sqlite3_mprintf(""); } switch( pExpr->eType ){ case FTSQUERY_PHRASE: { Fts3Phrase *pPhrase = pExpr->pPhrase; int i; zBuf = sqlite3_mprintf( "%zPHRASE %d 0", zBuf, pPhrase->iColumn); for(i=0; zBuf && i<pPhrase->nToken; i++){ |
︙ | ︙ | |||
974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 | sqlite3_result_error_nomem(context); goto exprtest_out; } for(ii=0; ii<nCol; ii++){ azCol[ii] = (char *)sqlite3_value_text(argv[ii+2]); } rc = sqlite3Fts3ExprParse( pTokenizer, 0, azCol, 0, nCol, nCol, zExpr, nExpr, &pExpr ); if( rc!=SQLITE_OK && rc!=SQLITE_NOMEM ){ sqlite3_result_error(context, "Error parsing expression", -1); }else if( rc==SQLITE_NOMEM || !(zBuf = exprToString(pExpr, 0)) ){ sqlite3_result_error_nomem(context); }else{ sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT); sqlite3_free(zBuf); } | > > > > > > > > > > > | 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 | sqlite3_result_error_nomem(context); goto exprtest_out; } for(ii=0; ii<nCol; ii++){ azCol[ii] = (char *)sqlite3_value_text(argv[ii+2]); } if( sqlite3_user_data(context) ){ char *zDummy = 0; rc = sqlite3Fts3ExprParse( pTokenizer, 0, azCol, 0, nCol, nCol, zExpr, nExpr, &pExpr, &zDummy ); assert( rc==SQLITE_OK || pExpr==0 ); sqlite3_free(zDummy); }else{ rc = fts3ExprParseUnbalanced( pTokenizer, 0, azCol, 0, nCol, nCol, zExpr, nExpr, &pExpr ); } if( rc!=SQLITE_OK && rc!=SQLITE_NOMEM ){ sqlite3Fts3ExprFree(pExpr); sqlite3_result_error(context, "Error parsing expression", -1); }else if( rc==SQLITE_NOMEM || !(zBuf = exprToString(pExpr, 0)) ){ sqlite3_result_error_nomem(context); }else{ sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT); sqlite3_free(zBuf); } |
︙ | ︙ | |||
1000 1001 1002 1003 1004 1005 1006 | } /* ** Register the query expression parser test function fts3_exprtest() ** with database connection db. */ int sqlite3Fts3ExprInitTestInterface(sqlite3* db){ | | > > > > > > | 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 | } /* ** Register the query expression parser test function fts3_exprtest() ** with database connection db. */ int sqlite3Fts3ExprInitTestInterface(sqlite3* db){ int rc = sqlite3_create_function( db, "fts3_exprtest", -1, SQLITE_UTF8, 0, fts3ExprTest, 0, 0 ); if( rc==SQLITE_OK ){ rc = sqlite3_create_function(db, "fts3_exprtest_rebalance", -1, SQLITE_UTF8, (void *)1, fts3ExprTest, 0, 0 ); } return rc; } #endif #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */ |
Changes to ext/fts3/fts3_hash.h.
1 2 3 4 5 6 7 8 9 10 11 | /* ** 2001 September 22 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | /* ** 2001 September 22 ** ** 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 is the header file for the generic hash-table implementation ** used in SQLite. We've modified it slightly to serve as a standalone ** hash table implementation for the full-text indexing module. ** */ #ifndef _FTS3_HASH_H_ #define _FTS3_HASH_H_ |
︙ | ︙ |
Changes to ext/fts3/fts3_snippet.c.
︙ | ︙ | |||
385 386 387 388 389 390 391 | /* ** Select the fragment of text consisting of nFragment contiguous tokens ** from column iCol that represent the "best" snippet. The best snippet ** is the snippet with the highest score, where scores are calculated ** by adding: ** | | | | 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 | /* ** Select the fragment of text consisting of nFragment contiguous tokens ** from column iCol that represent the "best" snippet. The best snippet ** is the snippet with the highest score, where scores are calculated ** by adding: ** ** (a) +1 point for each occurrence of a matchable phrase in the snippet. ** ** (b) +1000 points for the first occurrence of each matchable phrase in ** the snippet for which the corresponding mCovered bit is not set. ** ** The selected snippet parameters are stored in structure *pFragment before ** returning. The score of the selected snippet is stored in *piScore ** before returning. */ static int fts3BestSnippet( |
︙ | ︙ |
Changes to ext/fts3/fts3_test.c.
︙ | ︙ | |||
263 264 265 266 267 268 269 | ** ** If present, the first argument is the chunksize in bytes to load doclists ** in. The second argument is the minimum doclist size in bytes to use ** incremental loading with. ** ** Whether or not the arguments are present, this command returns a list of ** two integers - the initial chunksize and threshold when the command is | | | 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 | ** ** If present, the first argument is the chunksize in bytes to load doclists ** in. The second argument is the minimum doclist size in bytes to use ** incremental loading with. ** ** Whether or not the arguments are present, this command returns a list of ** two integers - the initial chunksize and threshold when the command is ** invoked. This can be used to restore the default behavior after running ** tests. For example: ** ** # Override incr-load settings for testing: ** set cfg [fts3_configure_incr_load $new_chunksize $new_threshold] ** ** .... run tests .... ** |
︙ | ︙ |
Added ext/fts3/fts3_tokenize_vtab.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 | /* ** 2013 Apr 22 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ****************************************************************************** ** ** This file contains code for the "fts3tokenize" virtual table module. ** An fts3tokenize virtual table is created as follows: ** ** CREATE VIRTUAL TABLE <tbl> USING fts3tokenize( ** <tokenizer-name>, <arg-1>, ... ** ); ** ** The table created has the following schema: ** ** CREATE TABLE <tbl>(input, token, start, end, position) ** ** When queried, the query must include a WHERE clause of type: ** ** input = <string> ** ** The virtual table module tokenizes this <string>, using the FTS3 ** tokenizer specified by the arguments to the CREATE VIRTUAL TABLE ** statement and returns one row for each token in the result. With ** fields set as follows: ** ** input: Always set to a copy of <string> ** token: A token from the input. ** start: Byte offset of the token within the input <string>. ** end: Byte offset of the byte immediately following the end of the ** token within the input string. ** pos: Token offset of token within input. ** */ #include "fts3Int.h" #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) #include <string.h> #include <assert.h> typedef struct Fts3tokTable Fts3tokTable; typedef struct Fts3tokCursor Fts3tokCursor; /* ** Virtual table structure. */ struct Fts3tokTable { sqlite3_vtab base; /* Base class used by SQLite core */ const sqlite3_tokenizer_module *pMod; sqlite3_tokenizer *pTok; }; /* ** Virtual table cursor structure. */ struct Fts3tokCursor { sqlite3_vtab_cursor base; /* Base class used by SQLite core */ char *zInput; /* Input string */ sqlite3_tokenizer_cursor *pCsr; /* Cursor to iterate through zInput */ int iRowid; /* Current 'rowid' value */ const char *zToken; /* Current 'token' value */ int nToken; /* Size of zToken in bytes */ int iStart; /* Current 'start' value */ int iEnd; /* Current 'end' value */ int iPos; /* Current 'pos' value */ }; /* ** Query FTS for the tokenizer implementation named zName. */ static int fts3tokQueryTokenizer( Fts3Hash *pHash, const char *zName, const sqlite3_tokenizer_module **pp, char **pzErr ){ sqlite3_tokenizer_module *p; int nName = (int)strlen(zName); p = (sqlite3_tokenizer_module *)sqlite3Fts3HashFind(pHash, zName, nName+1); if( !p ){ *pzErr = sqlite3_mprintf("unknown tokenizer: %s", zName); return SQLITE_ERROR; } *pp = p; return SQLITE_OK; } /* ** The second argument, argv[], is an array of pointers to nul-terminated ** strings. This function makes a copy of the array and strings into a ** single block of memory. It then dequotes any of the strings that appear ** to be quoted. ** ** If successful, output parameter *pazDequote is set to point at the ** array of dequoted strings and SQLITE_OK is returned. The caller is ** responsible for eventually calling sqlite3_free() to free the array ** in this case. Or, if an error occurs, an SQLite error code is returned. ** The final value of *pazDequote is undefined in this case. */ static int fts3tokDequoteArray( int argc, /* Number of elements in argv[] */ const char * const *argv, /* Input array */ char ***pazDequote /* Output array */ ){ int rc = SQLITE_OK; /* Return code */ if( argc==0 ){ *pazDequote = 0; }else{ int i; int nByte = 0; char **azDequote; for(i=0; i<argc; i++){ nByte += (int)(strlen(argv[i]) + 1); } *pazDequote = azDequote = sqlite3_malloc(sizeof(char *)*argc + nByte); if( azDequote==0 ){ rc = SQLITE_NOMEM; }else{ char *pSpace = (char *)&azDequote[argc]; for(i=0; i<argc; i++){ int n = (int)strlen(argv[i]); azDequote[i] = pSpace; memcpy(pSpace, argv[i], n+1); sqlite3Fts3Dequote(pSpace); pSpace += (n+1); } } } return rc; } /* ** Schema of the tokenizer table. */ #define FTS3_TOK_SCHEMA "CREATE TABLE x(input, token, start, end, position)" /* ** This function does all the work for both the xConnect and xCreate methods. ** These tables have no persistent representation of their own, so xConnect ** and xCreate are identical operations. ** ** argv[0]: module name ** argv[1]: database name ** argv[2]: table name ** argv[3]: first argument (tokenizer name) */ static int fts3tokConnectMethod( sqlite3 *db, /* Database connection */ void *pHash, /* Hash table of tokenizers */ int argc, /* Number of elements in argv array */ const char * const *argv, /* xCreate/xConnect argument array */ sqlite3_vtab **ppVtab, /* OUT: New sqlite3_vtab object */ char **pzErr /* OUT: sqlite3_malloc'd error message */ ){ Fts3tokTable *pTab; const sqlite3_tokenizer_module *pMod = 0; sqlite3_tokenizer *pTok = 0; int rc; char **azDequote = 0; int nDequote; rc = sqlite3_declare_vtab(db, FTS3_TOK_SCHEMA); if( rc!=SQLITE_OK ) return rc; nDequote = argc-3; rc = fts3tokDequoteArray(nDequote, &argv[3], &azDequote); if( rc==SQLITE_OK ){ const char *zModule; if( nDequote<1 ){ zModule = "simple"; }else{ zModule = azDequote[0]; } rc = fts3tokQueryTokenizer((Fts3Hash*)pHash, zModule, &pMod, pzErr); } assert( (rc==SQLITE_OK)==(pMod!=0) ); if( rc==SQLITE_OK ){ const char * const *azArg = (const char * const *)&azDequote[1]; rc = pMod->xCreate((nDequote>1 ? nDequote-1 : 0), azArg, &pTok); } if( rc==SQLITE_OK ){ pTab = (Fts3tokTable *)sqlite3_malloc(sizeof(Fts3tokTable)); if( pTab==0 ){ rc = SQLITE_NOMEM; } } if( rc==SQLITE_OK ){ memset(pTab, 0, sizeof(Fts3tokTable)); pTab->pMod = pMod; pTab->pTok = pTok; *ppVtab = &pTab->base; }else{ if( pTok ){ pMod->xDestroy(pTok); } } sqlite3_free(azDequote); return rc; } /* ** This function does the work for both the xDisconnect and xDestroy methods. ** These tables have no persistent representation of their own, so xDisconnect ** and xDestroy are identical operations. */ static int fts3tokDisconnectMethod(sqlite3_vtab *pVtab){ Fts3tokTable *pTab = (Fts3tokTable *)pVtab; pTab->pMod->xDestroy(pTab->pTok); sqlite3_free(pTab); return SQLITE_OK; } /* ** xBestIndex - Analyze a WHERE and ORDER BY clause. */ static int fts3tokBestIndexMethod( sqlite3_vtab *pVTab, sqlite3_index_info *pInfo ){ int i; UNUSED_PARAMETER(pVTab); for(i=0; i<pInfo->nConstraint; i++){ if( pInfo->aConstraint[i].usable && pInfo->aConstraint[i].iColumn==0 && pInfo->aConstraint[i].op==SQLITE_INDEX_CONSTRAINT_EQ ){ pInfo->idxNum = 1; pInfo->aConstraintUsage[i].argvIndex = 1; pInfo->aConstraintUsage[i].omit = 1; pInfo->estimatedCost = 1; return SQLITE_OK; } } pInfo->idxNum = 0; assert( pInfo->estimatedCost>1000000.0 ); return SQLITE_OK; } /* ** xOpen - Open a cursor. */ static int fts3tokOpenMethod(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCsr){ Fts3tokCursor *pCsr; UNUSED_PARAMETER(pVTab); pCsr = (Fts3tokCursor *)sqlite3_malloc(sizeof(Fts3tokCursor)); if( pCsr==0 ){ return SQLITE_NOMEM; } memset(pCsr, 0, sizeof(Fts3tokCursor)); *ppCsr = (sqlite3_vtab_cursor *)pCsr; return SQLITE_OK; } /* ** Reset the tokenizer cursor passed as the only argument. As if it had ** just been returned by fts3tokOpenMethod(). */ static void fts3tokResetCursor(Fts3tokCursor *pCsr){ if( pCsr->pCsr ){ Fts3tokTable *pTab = (Fts3tokTable *)(pCsr->base.pVtab); pTab->pMod->xClose(pCsr->pCsr); pCsr->pCsr = 0; } sqlite3_free(pCsr->zInput); pCsr->zInput = 0; pCsr->zToken = 0; pCsr->nToken = 0; pCsr->iStart = 0; pCsr->iEnd = 0; pCsr->iPos = 0; pCsr->iRowid = 0; } /* ** xClose - Close a cursor. */ static int fts3tokCloseMethod(sqlite3_vtab_cursor *pCursor){ Fts3tokCursor *pCsr = (Fts3tokCursor *)pCursor; fts3tokResetCursor(pCsr); sqlite3_free(pCsr); return SQLITE_OK; } /* ** xNext - Advance the cursor to the next row, if any. */ static int fts3tokNextMethod(sqlite3_vtab_cursor *pCursor){ Fts3tokCursor *pCsr = (Fts3tokCursor *)pCursor; Fts3tokTable *pTab = (Fts3tokTable *)(pCursor->pVtab); int rc; /* Return code */ pCsr->iRowid++; rc = pTab->pMod->xNext(pCsr->pCsr, &pCsr->zToken, &pCsr->nToken, &pCsr->iStart, &pCsr->iEnd, &pCsr->iPos ); if( rc!=SQLITE_OK ){ fts3tokResetCursor(pCsr); if( rc==SQLITE_DONE ) rc = SQLITE_OK; } return rc; } /* ** xFilter - Initialize a cursor to point at the start of its data. */ static int fts3tokFilterMethod( sqlite3_vtab_cursor *pCursor, /* The cursor used for this query */ int idxNum, /* Strategy index */ const char *idxStr, /* Unused */ int nVal, /* Number of elements in apVal */ sqlite3_value **apVal /* Arguments for the indexing scheme */ ){ int rc = SQLITE_ERROR; Fts3tokCursor *pCsr = (Fts3tokCursor *)pCursor; Fts3tokTable *pTab = (Fts3tokTable *)(pCursor->pVtab); UNUSED_PARAMETER(idxStr); UNUSED_PARAMETER(nVal); fts3tokResetCursor(pCsr); if( idxNum==1 ){ const char *zByte = (const char *)sqlite3_value_text(apVal[0]); int nByte = sqlite3_value_bytes(apVal[0]); pCsr->zInput = sqlite3_malloc(nByte+1); if( pCsr->zInput==0 ){ rc = SQLITE_NOMEM; }else{ memcpy(pCsr->zInput, zByte, nByte); pCsr->zInput[nByte] = 0; rc = pTab->pMod->xOpen(pTab->pTok, pCsr->zInput, nByte, &pCsr->pCsr); if( rc==SQLITE_OK ){ pCsr->pCsr->pTokenizer = pTab->pTok; } } } if( rc!=SQLITE_OK ) return rc; return fts3tokNextMethod(pCursor); } /* ** xEof - Return true if the cursor is at EOF, or false otherwise. */ static int fts3tokEofMethod(sqlite3_vtab_cursor *pCursor){ Fts3tokCursor *pCsr = (Fts3tokCursor *)pCursor; return (pCsr->zToken==0); } /* ** xColumn - Return a column value. */ static int fts3tokColumnMethod( sqlite3_vtab_cursor *pCursor, /* Cursor to retrieve value from */ sqlite3_context *pCtx, /* Context for sqlite3_result_xxx() calls */ int iCol /* Index of column to read value from */ ){ Fts3tokCursor *pCsr = (Fts3tokCursor *)pCursor; /* CREATE TABLE x(input, token, start, end, position) */ switch( iCol ){ case 0: sqlite3_result_text(pCtx, pCsr->zInput, -1, SQLITE_TRANSIENT); break; case 1: sqlite3_result_text(pCtx, pCsr->zToken, pCsr->nToken, SQLITE_TRANSIENT); break; case 2: sqlite3_result_int(pCtx, pCsr->iStart); break; case 3: sqlite3_result_int(pCtx, pCsr->iEnd); break; default: assert( iCol==4 ); sqlite3_result_int(pCtx, pCsr->iPos); break; } return SQLITE_OK; } /* ** xRowid - Return the current rowid for the cursor. */ static int fts3tokRowidMethod( sqlite3_vtab_cursor *pCursor, /* Cursor to retrieve value from */ sqlite_int64 *pRowid /* OUT: Rowid value */ ){ Fts3tokCursor *pCsr = (Fts3tokCursor *)pCursor; *pRowid = (sqlite3_int64)pCsr->iRowid; return SQLITE_OK; } /* ** Register the fts3tok module with database connection db. Return SQLITE_OK ** if successful or an error code if sqlite3_create_module() fails. */ int sqlite3Fts3InitTok(sqlite3 *db, Fts3Hash *pHash){ static const sqlite3_module fts3tok_module = { 0, /* iVersion */ fts3tokConnectMethod, /* xCreate */ fts3tokConnectMethod, /* xConnect */ fts3tokBestIndexMethod, /* xBestIndex */ fts3tokDisconnectMethod, /* xDisconnect */ fts3tokDisconnectMethod, /* xDestroy */ fts3tokOpenMethod, /* xOpen */ fts3tokCloseMethod, /* xClose */ fts3tokFilterMethod, /* xFilter */ fts3tokNextMethod, /* xNext */ fts3tokEofMethod, /* xEof */ fts3tokColumnMethod, /* xColumn */ fts3tokRowidMethod, /* xRowid */ 0, /* xUpdate */ 0, /* xBegin */ 0, /* xSync */ 0, /* xCommit */ 0, /* xRollback */ 0, /* xFindFunction */ 0, /* xRename */ 0, /* xSavepoint */ 0, /* xRelease */ 0 /* xRollbackTo */ }; int rc; /* Return code */ rc = sqlite3_create_module(db, "fts3tokenize", &fts3tok_module, (void*)pHash); return rc; } #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */ |
Changes to ext/fts3/fts3_tokenizer.c.
︙ | ︙ | |||
424 425 426 427 428 429 430 | } #endif /* ** Set up SQL objects in database db used to access the contents of ** the hash table pointed to by argument pHash. The hash table must | | | 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 | } #endif /* ** Set up SQL objects in database db used to access the contents of ** the hash table pointed to by argument pHash. The hash table must ** been initialized to use string keys, and to take a private copy ** of the key when a value is inserted. i.e. by a call similar to: ** ** sqlite3Fts3HashInit(pHash, FTS3_HASH_STRING, 1); ** ** This function adds a scalar function (see header comment above ** scalarFunc() in this file for details) and, if ENABLE_TABLE is ** defined at compilation time, a temporary virtual table (see header |
︙ | ︙ |
Changes to ext/fts3/fts3_tokenizer.h.
︙ | ︙ | |||
66 67 68 69 70 71 72 | ** ** then argc is set to 2, and the argv[] array contains pointers ** to the strings "arg1" and "arg2". ** ** This method should return either SQLITE_OK (0), or an SQLite error ** code. If SQLITE_OK is returned, then *ppTokenizer should be set ** to point at the newly created tokenizer structure. The generic | | | 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 | ** ** then argc is set to 2, and the argv[] array contains pointers ** to the strings "arg1" and "arg2". ** ** This method should return either SQLITE_OK (0), or an SQLite error ** code. If SQLITE_OK is returned, then *ppTokenizer should be set ** to point at the newly created tokenizer structure. The generic ** sqlite3_tokenizer.pModule variable should not be initialized by ** this callback. The caller will do so. */ int (*xCreate)( int argc, /* Size of argv array */ const char *const*argv, /* Tokenizer argument strings */ sqlite3_tokenizer **ppTokenizer /* OUT: Created tokenizer */ ); |
︙ | ︙ |
Changes to ext/fts3/fts3_unicode.c.
︙ | ︙ | |||
121 122 123 124 125 126 127 | ** If so, no action is taken. Otherwise, the codepoint is added to the ** unicode_tokenizer.aiException[] array. For the purposes of tokenization, ** the return value of sqlite3FtsUnicodeIsalnum() is inverted for all ** codepoints in the aiException[] array. ** ** If a standalone diacritic mark (one that sqlite3FtsUnicodeIsdiacritic() ** identifies as a diacritic) occurs in the zIn/nIn string it is ignored. | | | 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 | ** If so, no action is taken. Otherwise, the codepoint is added to the ** unicode_tokenizer.aiException[] array. For the purposes of tokenization, ** the return value of sqlite3FtsUnicodeIsalnum() is inverted for all ** codepoints in the aiException[] array. ** ** If a standalone diacritic mark (one that sqlite3FtsUnicodeIsdiacritic() ** identifies as a diacritic) occurs in the zIn/nIn string it is ignored. ** It is not possible to change the behavior of the tokenizer with respect ** to these codepoints. */ static int unicodeAddExceptions( unicode_tokenizer *p, /* Tokenizer to add exceptions to */ int bAlnum, /* Replace Isalnum() return value with this */ const char *zIn, /* Array of characters to make exceptions */ int nIn /* Length of z in bytes */ |
︙ | ︙ |
Changes to ext/fts3/fts3_write.c.
︙ | ︙ | |||
1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 | ** size of the previous offset-list. */ if( ppOffsetList ){ *ppOffsetList = pReader->pOffsetList; *pnOffsetList = (int)(p - pReader->pOffsetList - 1); } while( p<pEnd && *p==0 ) p++; /* If there are no more entries in the doclist, set pOffsetList to ** NULL. Otherwise, set Fts3SegReader.iDocid to the next docid and ** Fts3SegReader.pOffsetList to point to the next offset list before ** returning. */ | > | 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 | ** size of the previous offset-list. */ if( ppOffsetList ){ *ppOffsetList = pReader->pOffsetList; *pnOffsetList = (int)(p - pReader->pOffsetList - 1); } /* List may have been edited in place by fts3EvalNearTrim() */ while( p<pEnd && *p==0 ) p++; /* If there are no more entries in the doclist, set pOffsetList to ** NULL. Otherwise, set Fts3SegReader.iDocid to the next docid and ** Fts3SegReader.pOffsetList to point to the next offset list before ** returning. */ |
︙ | ︙ | |||
2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 | ** When this function is called, buffer *ppList (size *pnList bytes) contains ** a position list that may (or may not) feature multiple columns. This ** function adjusts the pointer *ppList and the length *pnList so that they ** identify the subset of the position list that corresponds to column iCol. ** ** If there are no entries in the input position list for column iCol, then ** *pnList is set to zero before returning. */ static void fts3ColumnFilter( int iCol, /* Column to filter on */ char **ppList, /* IN/OUT: Pointer to position list */ int *pnList /* IN/OUT: Size of buffer *ppList in bytes */ ){ char *pList = *ppList; int nList = *pnList; char *pEnd = &pList[nList]; int iCurrent = 0; | > > > > | 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 | ** When this function is called, buffer *ppList (size *pnList bytes) contains ** a position list that may (or may not) feature multiple columns. This ** function adjusts the pointer *ppList and the length *pnList so that they ** identify the subset of the position list that corresponds to column iCol. ** ** If there are no entries in the input position list for column iCol, then ** *pnList is set to zero before returning. ** ** If parameter bZero is non-zero, then any part of the input list following ** the end of the output list is zeroed before returning. */ static void fts3ColumnFilter( int iCol, /* Column to filter on */ int bZero, /* Zero out anything following *ppList */ char **ppList, /* IN/OUT: Pointer to position list */ int *pnList /* IN/OUT: Size of buffer *ppList in bytes */ ){ char *pList = *ppList; int nList = *pnList; char *pEnd = &pList[nList]; int iCurrent = 0; |
︙ | ︙ | |||
2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 | if( nList==0 ){ break; } p = &pList[1]; p += sqlite3Fts3GetVarint32(p, &iCurrent); } *ppList = pList; *pnList = nList; } /* ** Cache data in the Fts3MultiSegReader.aBuffer[] buffer (overwriting any ** existing data). Grow the buffer if required. | > > > | 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 | if( nList==0 ){ break; } p = &pList[1]; p += sqlite3Fts3GetVarint32(p, &iCurrent); } if( bZero && &pList[nList]!=pEnd ){ memset(&pList[nList], 0, pEnd - &pList[nList]); } *ppList = pList; *pnList = nList; } /* ** Cache data in the Fts3MultiSegReader.aBuffer[] buffer (overwriting any ** existing data). Grow the buffer if required. |
︙ | ︙ | |||
2596 2597 2598 2599 2600 2601 2602 2603 2604 | && apSegment[j]->iDocid==iDocid ){ rc = fts3SegReaderNextDocid(p, apSegment[j], 0, 0); j++; } if( rc!=SQLITE_OK ) return rc; fts3SegReaderSort(pMsr->apSegment, nMerge, j, xCmp); if( pMsr->iColFilter>=0 ){ | > > > > > > > | < < < < < < < | 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 | && apSegment[j]->iDocid==iDocid ){ rc = fts3SegReaderNextDocid(p, apSegment[j], 0, 0); j++; } if( rc!=SQLITE_OK ) return rc; fts3SegReaderSort(pMsr->apSegment, nMerge, j, xCmp); if( nList>0 && fts3SegReaderIsPending(apSegment[0]) ){ rc = fts3MsrBufferData(pMsr, pList, nList+1); if( rc!=SQLITE_OK ) return rc; assert( (pMsr->aBuffer[nList] & 0xFE)==0x00 ); pList = pMsr->aBuffer; } if( pMsr->iColFilter>=0 ){ fts3ColumnFilter(pMsr->iColFilter, 1, &pList, &nList); } if( nList>0 ){ *paPoslist = pList; *piDocid = iDocid; *pnPoslist = nList; break; } } } |
︙ | ︙ | |||
2852 2853 2854 2855 2856 2857 2858 | && apSegment[j]->iDocid==iDocid ){ fts3SegReaderNextDocid(p, apSegment[j], 0, 0); j++; } if( isColFilter ){ | | | 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 | && apSegment[j]->iDocid==iDocid ){ fts3SegReaderNextDocid(p, apSegment[j], 0, 0); j++; } if( isColFilter ){ fts3ColumnFilter(pFilter->iCol, 0, &pList, &nList); } if( !isIgnoreEmpty || nList>0 ){ /* Calculate the 'docid' delta value to write into the merged ** doclist. */ sqlite3_int64 iDelta; |
︙ | ︙ |
Changes to ext/icu/README.txt.
︙ | ︙ | |||
94 95 96 97 98 99 100 | comparision operator "REGEXP", based on the regular expression functions provided by the ICU library. The syntax of the operator is as described in SQLite documentation: <string> REGEXP <re-pattern> This extension uses the ICU defaults for regular expression matching | | | 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 | comparision operator "REGEXP", based on the regular expression functions provided by the ICU library. The syntax of the operator is as described in SQLite documentation: <string> REGEXP <re-pattern> This extension uses the ICU defaults for regular expression matching behavior. Specifically, this means that: * Matching is case-sensitive, * Regular expression comments are not allowed within patterns, and * The '^' and '$' characters match the beginning and end of the <string> argument, not the beginning and end of lines within the <string> argument. |
︙ | ︙ |
Added ext/misc/amatch.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 | /* ** 2013-03-14 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** ** This file contains code for a demonstration virtual table that finds ** "approximate matches" - strings from a finite set that are nearly the ** same as a single input string. The virtual table is called "amatch". ** ** A amatch virtual table is created like this: ** ** CREATE VIRTUAL TABLE f USING approximate_match( ** vocabulary_table=<tablename>, -- V ** vocabulary_word=<columnname>, -- W ** vocabulary_language=<columnname>, -- L ** edit_distances=<edit-cost-table> ** ); ** ** When it is created, the new amatch table must be supplied with the ** the name of a table V and columns V.W and V.L such that ** ** SELECT W FROM V WHERE L=$language ** ** returns the allowed vocabulary for the match. If the "vocabulary_language" ** or L columnname is left unspecified or is an empty string, then no ** filtering of the vocabulary by language is performed. ** ** For efficiency, it is essential that the vocabulary table be indexed: ** ** CREATE vocab_index ON V(W) ** ** A separate edit-cost-table provides scoring information that defines ** what it means for one string to be "close" to another. ** ** The edit-cost-table must contain exactly four columns (more precisely, ** the statement "SELECT * FROM <edit-cost-table>" must return records ** that consist of four columns). It does not matter what the columns are ** named. ** ** Each row in the edit-cost-table represents a single character ** transformation going from user input to the vocabulary. The leftmost ** column of the row (column 0) contains an integer identifier of the ** language to which the transformation rule belongs (see "MULTIPLE LANGUAGES" ** below). The second column of the row (column 1) contains the input ** character or characters - the characters of user input. The third ** column contains characters as they appear in the vocabulary table. ** And the fourth column contains the integer cost of making the ** transformation. For example: ** ** CREATE TABLE f_data(iLang, cFrom, cTo, Cost); ** INSERT INTO f_data(iLang, cFrom, cTo, Cost) VALUES(0, '', 'a', 100); ** INSERT INTO f_data(iLang, cFrom, cTo, Cost) VALUES(0, 'b', '', 87); ** INSERT INTO f_data(iLang, cFrom, cTo, Cost) VALUES(0, 'o', 'oe', 38); ** INSERT INTO f_data(iLang, cFrom, cTo, Cost) VALUES(0, 'oe', 'o', 40); ** ** The first row inserted into the edit-cost-table by the SQL script ** above indicates that the cost of having an extra 'a' in the vocabulary ** table that is missing in the user input 100. (All costs are integers. ** Overall cost must not exceed 16777216.) The second INSERT statement ** creates a rule saying that the cost of having a single letter 'b' in ** user input which is missing in the vocabulary table is 87. The third ** INSERT statement mean that the cost of matching an 'o' in user input ** against an 'oe' in the vocabulary table is 38. And so forth. ** ** The following rules are special: ** ** INSERT INTO f_data(iLang, cFrom, cTo, Cost) VALUES(0, '?', '', 97); ** INSERT INTO f_data(iLang, cFrom, cTo, Cost) VALUES(0, '', '?', 98); ** INSERT INTO f_data(iLang, cFrom, cTo, Cost) VALUES(0, '?', '?', 99); ** ** The '?' to '' rule is the cost of having any single character in the input ** that is not found in the vocabular. The '' to '?' rule is the cost of ** having a character in the vocabulary table that is missing from input. ** And the '?' to '?' rule is the cost of doing an arbitrary character ** substitution. These three generic rules apply across all languages. ** In other words, the iLang field is ignored for the generic substitution ** rules. If more than one cost is given for a generic substitution rule, ** then the lowest cost is used. ** ** Once it has been created, the amatch virtual table can be queried ** as follows: ** ** SELECT word, distance FROM f ** WHERE word MATCH 'abcdefg' ** AND distance<200; ** ** This query outputs the strings contained in the T(F) field that ** are close to "abcdefg" and in order of increasing distance. No string ** is output more than once. If there are multiple ways to transform the ** target string ("abcdefg") into a string in the vocabulary table then ** the lowest cost transform is the one that is returned. In this example, ** the search is limited to strings with a total distance of less than 200. ** ** For efficiency, it is important to put tight bounds on the distance. ** The time and memory space needed to perform this query is exponential ** in the maximum distance. A good rule of thumb is to limit the distance ** to no more than 1.5 or 2 times the maximum cost of any rule in the ** edit-cost-table. ** ** The amatch is a read-only table. Any attempt to DELETE, INSERT, or ** UPDATE on a amatch table will throw an error. ** ** It is important to put some kind of a limit on the amatch output. This ** can be either in the form of a LIMIT clause at the end of the query, ** or better, a "distance<NNN" constraint where NNN is some number. The ** running time and memory requirement is exponential in the value of NNN ** so you want to make sure that NNN is not too big. A value of NNN that ** is about twice the average transformation cost seems to give good results. ** ** The amatch table can be useful for tasks such as spelling correction. ** Suppose all allowed words are in table vocabulary(w). Then one would create ** an amatch virtual table like this: ** ** CREATE VIRTUAL TABLE ex1 USING amatch( ** vocabtable=vocabulary, ** vocabcolumn=w, ** edit_distances=ec1 ** ); ** ** Then given an input word $word, look up close spellings this way: ** ** SELECT word, distance FROM ex1 ** WHERE word MATCH $word AND distance<200; ** ** MULTIPLE LANGUAGES ** ** Normally, the "iLang" value associated with all character transformations ** in the edit-cost-table is zero. However, if required, the amatch ** virtual table allows multiple languages to be defined. Each query uses ** only a single iLang value. This allows, for example, a single ** amatch table to support multiple languages. ** ** By default, only the rules with iLang=0 are used. To specify an ** alternative language, a "language = ?" expression must be added to the ** WHERE clause of a SELECT, where ? is the integer identifier of the desired ** language. For example: ** ** SELECT word, distance FROM ex1 ** WHERE word MATCH $word ** AND distance<=200 ** AND language=1 -- Specify use language 1 instead of 0 ** ** If no "language = ?" constraint is specified in the WHERE clause, language ** 0 is used. ** ** LIMITS ** ** The maximum language number is 2147483647. The maximum length of either ** of the strings in the second or third column of the amatch data table ** is 50 bytes. The maximum cost on a rule is 1000. */ #include "sqlite3ext.h" SQLITE_EXTENSION_INIT1 #include <stdlib.h> #include <string.h> #include <assert.h> #include <stdio.h> #include <ctype.h> /* ** Forward declaration of objects used by this implementation */ typedef struct amatch_vtab amatch_vtab; typedef struct amatch_cursor amatch_cursor; typedef struct amatch_rule amatch_rule; typedef struct amatch_word amatch_word; typedef struct amatch_avl amatch_avl; /***************************************************************************** ** AVL Tree implementation */ /* ** Objects that want to be members of the AVL tree should embedded an ** instance of this structure. */ struct amatch_avl { amatch_word *pWord; /* Points to the object being stored in the tree */ char *zKey; /* Key. zero-terminated string. Must be unique */ amatch_avl *pBefore; /* Other elements less than zKey */ amatch_avl *pAfter; /* Other elements greater than zKey */ amatch_avl *pUp; /* Parent element */ short int height; /* Height of this node. Leaf==1 */ short int imbalance; /* Height difference between pBefore and pAfter */ }; /* Recompute the amatch_avl.height and amatch_avl.imbalance fields for p. ** Assume that the children of p have correct heights. */ static void amatchAvlRecomputeHeight(amatch_avl *p){ short int hBefore = p->pBefore ? p->pBefore->height : 0; short int hAfter = p->pAfter ? p->pAfter->height : 0; p->imbalance = hBefore - hAfter; /* -: pAfter higher. +: pBefore higher */ p->height = (hBefore>hAfter ? hBefore : hAfter)+1; } /* ** P B ** / \ / \ ** B Z ==> X P ** / \ / \ ** X Y Y Z ** */ static amatch_avl *amatchAvlRotateBefore(amatch_avl *pP){ amatch_avl *pB = pP->pBefore; amatch_avl *pY = pB->pAfter; pB->pUp = pP->pUp; pB->pAfter = pP; pP->pUp = pB; pP->pBefore = pY; if( pY ) pY->pUp = pP; amatchAvlRecomputeHeight(pP); amatchAvlRecomputeHeight(pB); return pB; } /* ** P A ** / \ / \ ** X A ==> P Z ** / \ / \ ** Y Z X Y ** */ static amatch_avl *amatchAvlRotateAfter(amatch_avl *pP){ amatch_avl *pA = pP->pAfter; amatch_avl *pY = pA->pBefore; pA->pUp = pP->pUp; pA->pBefore = pP; pP->pUp = pA; pP->pAfter = pY; if( pY ) pY->pUp = pP; amatchAvlRecomputeHeight(pP); amatchAvlRecomputeHeight(pA); return pA; } /* ** Return a pointer to the pBefore or pAfter pointer in the parent ** of p that points to p. Or if p is the root node, return pp. */ static amatch_avl **amatchAvlFromPtr(amatch_avl *p, amatch_avl **pp){ amatch_avl *pUp = p->pUp; if( pUp==0 ) return pp; if( pUp->pAfter==p ) return &pUp->pAfter; return &pUp->pBefore; } /* ** Rebalance all nodes starting with p and working up to the root. ** Return the new root. */ static amatch_avl *amatchAvlBalance(amatch_avl *p){ amatch_avl *pTop = p; amatch_avl **pp; while( p ){ amatchAvlRecomputeHeight(p); if( p->imbalance>=2 ){ amatch_avl *pB = p->pBefore; if( pB->imbalance<0 ) p->pBefore = amatchAvlRotateAfter(pB); pp = amatchAvlFromPtr(p,&p); p = *pp = amatchAvlRotateBefore(p); }else if( p->imbalance<=(-2) ){ amatch_avl *pA = p->pAfter; if( pA->imbalance>0 ) p->pAfter = amatchAvlRotateBefore(pA); pp = amatchAvlFromPtr(p,&p); p = *pp = amatchAvlRotateAfter(p); } pTop = p; p = p->pUp; } return pTop; } /* Search the tree rooted at p for an entry with zKey. Return a pointer ** to the entry or return NULL. */ static amatch_avl *amatchAvlSearch(amatch_avl *p, const char *zKey){ int c; while( p && (c = strcmp(zKey, p->zKey))!=0 ){ p = (c<0) ? p->pBefore : p->pAfter; } return p; } /* Find the first node (the one with the smallest key). */ static amatch_avl *amatchAvlFirst(amatch_avl *p){ if( p ) while( p->pBefore ) p = p->pBefore; return p; } #if 0 /* NOT USED */ /* Return the node with the next larger key after p. */ static amatch_avl *amatchAvlNext(amatch_avl *p){ amatch_avl *pPrev = 0; while( p && p->pAfter==pPrev ){ pPrev = p; p = p->pUp; } if( p && pPrev==0 ){ p = amatchAvlFirst(p->pAfter); } return p; } #endif #if 0 /* NOT USED */ /* Verify AVL tree integrity */ static int amatchAvlIntegrity(amatch_avl *pHead){ amatch_avl *p; if( pHead==0 ) return 1; if( (p = pHead->pBefore)!=0 ){ assert( p->pUp==pHead ); assert( amatchAvlIntegrity(p) ); assert( strcmp(p->zKey, pHead->zKey)<0 ); while( p->pAfter ) p = p->pAfter; assert( strcmp(p->zKey, pHead->zKey)<0 ); } if( (p = pHead->pAfter)!=0 ){ assert( p->pUp==pHead ); assert( amatchAvlIntegrity(p) ); assert( strcmp(p->zKey, pHead->zKey)>0 ); p = amatchAvlFirst(p); assert( strcmp(p->zKey, pHead->zKey)>0 ); } return 1; } static int amatchAvlIntegrity2(amatch_avl *pHead){ amatch_avl *p, *pNext; for(p=amatchAvlFirst(pHead); p; p=pNext){ pNext = amatchAvlNext(p); if( pNext==0 ) break; assert( strcmp(p->zKey, pNext->zKey)<0 ); } return 1; } #endif /* Insert a new node pNew. Return NULL on success. If the key is not ** unique, then do not perform the insert but instead leave pNew unchanged ** and return a pointer to an existing node with the same key. */ static amatch_avl *amatchAvlInsert(amatch_avl **ppHead, amatch_avl *pNew){ int c; amatch_avl *p = *ppHead; if( p==0 ){ p = pNew; pNew->pUp = 0; }else{ while( p ){ c = strcmp(pNew->zKey, p->zKey); if( c<0 ){ if( p->pBefore ){ p = p->pBefore; }else{ p->pBefore = pNew; pNew->pUp = p; break; } }else if( c>0 ){ if( p->pAfter ){ p = p->pAfter; }else{ p->pAfter = pNew; pNew->pUp = p; break; } }else{ return p; } } } pNew->pBefore = 0; pNew->pAfter = 0; pNew->height = 1; pNew->imbalance = 0; *ppHead = amatchAvlBalance(p); /* assert( amatchAvlIntegrity(*ppHead) ); */ /* assert( amatchAvlIntegrity2(*ppHead) ); */ return 0; } /* Remove node pOld from the tree. pOld must be an element of the tree or ** the AVL tree will become corrupt. */ static void amatchAvlRemove(amatch_avl **ppHead, amatch_avl *pOld){ amatch_avl **ppParent; amatch_avl *pBalance; /* assert( amatchAvlSearch(*ppHead, pOld->zKey)==pOld ); */ ppParent = amatchAvlFromPtr(pOld, ppHead); if( pOld->pBefore==0 && pOld->pAfter==0 ){ *ppParent = 0; pBalance = pOld->pUp; }else if( pOld->pBefore && pOld->pAfter ){ amatch_avl *pX, *pY; pX = amatchAvlFirst(pOld->pAfter); *amatchAvlFromPtr(pX, 0) = pX->pAfter; if( pX->pAfter ) pX->pAfter->pUp = pX->pUp; pBalance = pX->pUp; pX->pAfter = pOld->pAfter; if( pX->pAfter ){ pX->pAfter->pUp = pX; }else{ assert( pBalance==pOld ); pBalance = pX; } pX->pBefore = pY = pOld->pBefore; if( pY ) pY->pUp = pX; pX->pUp = pOld->pUp; *ppParent = pX; }else if( pOld->pBefore==0 ){ *ppParent = pBalance = pOld->pAfter; pBalance->pUp = pOld->pUp; }else if( pOld->pAfter==0 ){ *ppParent = pBalance = pOld->pBefore; pBalance->pUp = pOld->pUp; } *ppHead = amatchAvlBalance(pBalance); pOld->pUp = 0; pOld->pBefore = 0; pOld->pAfter = 0; /* assert( amatchAvlIntegrity(*ppHead) ); */ /* assert( amatchAvlIntegrity2(*ppHead) ); */ } /* ** End of the AVL Tree implementation ******************************************************************************/ /* ** Various types. ** ** amatch_cost is the "cost" of an edit operation. ** ** amatch_len is the length of a matching string. ** ** amatch_langid is an ruleset identifier. */ typedef int amatch_cost; typedef signed char amatch_len; typedef int amatch_langid; /* ** Limits */ #define AMATCH_MX_LENGTH 50 /* Maximum length of a rule string */ #define AMATCH_MX_LANGID 2147483647 /* Maximum rule ID */ #define AMATCH_MX_COST 1000 /* Maximum single-rule cost */ /* ** A match or partial match */ struct amatch_word { amatch_word *pNext; /* Next on a list of all amatch_words */ amatch_avl sCost; /* Linkage of this node into the cost tree */ amatch_avl sWord; /* Linkage of this node into the word tree */ amatch_cost rCost; /* Cost of the match so far */ int iSeq; /* Sequence number */ char zCost[10]; /* Cost key (text rendering of rCost) */ short int nMatch; /* Input characters matched */ char zWord[4]; /* Text of the word. Extra space appended as needed */ }; /* ** Each transformation rule is stored as an instance of this object. ** All rules are kept on a linked list sorted by rCost. */ struct amatch_rule { amatch_rule *pNext; /* Next rule in order of increasing rCost */ char *zFrom; /* Transform from (a string from user input) */ amatch_cost rCost; /* Cost of this transformation */ amatch_langid iLang; /* The langauge to which this rule belongs */ amatch_len nFrom, nTo; /* Length of the zFrom and zTo strings */ char zTo[4]; /* Tranform to V.W value (extra space appended) */ }; /* ** A amatch virtual-table object */ struct amatch_vtab { sqlite3_vtab base; /* Base class - must be first */ char *zClassName; /* Name of this class. Default: "amatch" */ char *zDb; /* Name of database. (ex: "main") */ char *zSelf; /* Name of this virtual table */ char *zCostTab; /* Name of edit-cost-table */ char *zVocabTab; /* Name of vocabulary table */ char *zVocabWord; /* Name of vocabulary table word column */ char *zVocabLang; /* Name of vocabulary table language column */ amatch_rule *pRule; /* All active rules in this amatch */ amatch_cost rIns; /* Generic insertion cost '' -> ? */ amatch_cost rDel; /* Generic deletion cost ? -> '' */ amatch_cost rSub; /* Generic substitution cost ? -> ? */ sqlite3 *db; /* The database connection */ sqlite3_stmt *pVCheck; /* Query to check zVocabTab */ int nCursor; /* Number of active cursors */ }; /* A amatch cursor object */ struct amatch_cursor { sqlite3_vtab_cursor base; /* Base class - must be first */ sqlite3_int64 iRowid; /* The rowid of the current word */ amatch_langid iLang; /* Use this language ID */ amatch_cost rLimit; /* Maximum cost of any term */ int nBuf; /* Space allocated for zBuf */ int oomErr; /* True following an OOM error */ int nWord; /* Number of amatch_word objects */ char *zBuf; /* Temp-use buffer space */ char *zInput; /* Input word to match against */ amatch_vtab *pVtab; /* The virtual table this cursor belongs to */ amatch_word *pAllWords; /* List of all amatch_word objects */ amatch_word *pCurrent; /* Most recent solution */ amatch_avl *pCost; /* amatch_word objects keyed by iCost */ amatch_avl *pWord; /* amatch_word objects keyed by zWord */ }; /* ** The two input rule lists are both sorted in order of increasing ** cost. Merge them together into a single list, sorted by cost, and ** return a pointer to the head of that list. */ static amatch_rule *amatchMergeRules(amatch_rule *pA, amatch_rule *pB){ amatch_rule head; amatch_rule *pTail; pTail = &head; while( pA && pB ){ if( pA->rCost<=pB->rCost ){ pTail->pNext = pA; pTail = pA; pA = pA->pNext; }else{ pTail->pNext = pB; pTail = pB; pB = pB->pNext; } } if( pA==0 ){ pTail->pNext = pB; }else{ pTail->pNext = pA; } return head.pNext; } /* ** Statement pStmt currently points to a row in the amatch data table. This ** function allocates and populates a amatch_rule structure according to ** the content of the row. ** ** If successful, *ppRule is set to point to the new object and SQLITE_OK ** is returned. Otherwise, *ppRule is zeroed, *pzErr may be set to point ** to an error message and an SQLite error code returned. */ static int amatchLoadOneRule( amatch_vtab *p, /* Fuzzer virtual table handle */ sqlite3_stmt *pStmt, /* Base rule on statements current row */ amatch_rule **ppRule, /* OUT: New rule object */ char **pzErr /* OUT: Error message */ ){ sqlite3_int64 iLang = sqlite3_column_int64(pStmt, 0); const char *zFrom = (const char *)sqlite3_column_text(pStmt, 1); const char *zTo = (const char *)sqlite3_column_text(pStmt, 2); amatch_cost rCost = sqlite3_column_int(pStmt, 3); int rc = SQLITE_OK; /* Return code */ int nFrom; /* Size of string zFrom, in bytes */ int nTo; /* Size of string zTo, in bytes */ amatch_rule *pRule = 0; /* New rule object to return */ if( zFrom==0 ) zFrom = ""; if( zTo==0 ) zTo = ""; nFrom = (int)strlen(zFrom); nTo = (int)strlen(zTo); /* Silently ignore null transformations */ if( strcmp(zFrom, zTo)==0 ){ if( zFrom[0]=='?' && zFrom[1]==0 ){ if( p->rSub==0 || p->rSub>rCost ) p->rSub = rCost; } *ppRule = 0; return SQLITE_OK; } if( rCost<=0 || rCost>AMATCH_MX_COST ){ *pzErr = sqlite3_mprintf("%s: cost must be between 1 and %d", p->zClassName, AMATCH_MX_COST ); rc = SQLITE_ERROR; }else if( nFrom>AMATCH_MX_LENGTH || nTo>AMATCH_MX_LENGTH ){ *pzErr = sqlite3_mprintf("%s: maximum string length is %d", p->zClassName, AMATCH_MX_LENGTH ); rc = SQLITE_ERROR; }else if( iLang<0 || iLang>AMATCH_MX_LANGID ){ *pzErr = sqlite3_mprintf("%s: iLang must be between 0 and %d", p->zClassName, AMATCH_MX_LANGID ); rc = SQLITE_ERROR; }else if( strcmp(zFrom,"")==0 && strcmp(zTo,"?")==0 ){ if( p->rIns==0 || p->rIns>rCost ) p->rIns = rCost; }else if( strcmp(zFrom,"?")==0 && strcmp(zTo,"")==0 ){ if( p->rDel==0 || p->rDel>rCost ) p->rDel = rCost; }else { pRule = sqlite3_malloc( sizeof(*pRule) + nFrom + nTo ); if( pRule==0 ){ rc = SQLITE_NOMEM; }else{ memset(pRule, 0, sizeof(*pRule)); pRule->zFrom = &pRule->zTo[nTo+1]; pRule->nFrom = nFrom; memcpy(pRule->zFrom, zFrom, nFrom+1); memcpy(pRule->zTo, zTo, nTo+1); pRule->nTo = nTo; pRule->rCost = rCost; pRule->iLang = (int)iLang; } } *ppRule = pRule; return rc; } /* ** Free all the content in the edit-cost-table */ static void amatchFreeRules(amatch_vtab *p){ while( p->pRule ){ amatch_rule *pRule = p->pRule; p->pRule = pRule->pNext; sqlite3_free(pRule); } p->pRule = 0; } /* ** Load the content of the amatch data table into memory. */ static int amatchLoadRules( sqlite3 *db, /* Database handle */ amatch_vtab *p, /* Virtual amatch table to configure */ char **pzErr /* OUT: Error message */ ){ int rc = SQLITE_OK; /* Return code */ char *zSql; /* SELECT used to read from rules table */ amatch_rule *pHead = 0; zSql = sqlite3_mprintf("SELECT * FROM %Q.%Q", p->zDb, p->zCostTab); if( zSql==0 ){ rc = SQLITE_NOMEM; }else{ int rc2; /* finalize() return code */ sqlite3_stmt *pStmt = 0; rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0); if( rc!=SQLITE_OK ){ *pzErr = sqlite3_mprintf("%s: %s", p->zClassName, sqlite3_errmsg(db)); }else if( sqlite3_column_count(pStmt)!=4 ){ *pzErr = sqlite3_mprintf("%s: %s has %d columns, expected 4", p->zClassName, p->zCostTab, sqlite3_column_count(pStmt) ); rc = SQLITE_ERROR; }else{ while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){ amatch_rule *pRule = 0; rc = amatchLoadOneRule(p, pStmt, &pRule, pzErr); if( pRule ){ pRule->pNext = pHead; pHead = pRule; } } } rc2 = sqlite3_finalize(pStmt); if( rc==SQLITE_OK ) rc = rc2; } sqlite3_free(zSql); /* All rules are now in a singly linked list starting at pHead. This ** block sorts them by cost and then sets amatch_vtab.pRule to point to ** point to the head of the sorted list. */ if( rc==SQLITE_OK ){ unsigned int i; amatch_rule *pX; amatch_rule *a[15]; for(i=0; i<sizeof(a)/sizeof(a[0]); i++) a[i] = 0; while( (pX = pHead)!=0 ){ pHead = pX->pNext; pX->pNext = 0; for(i=0; a[i] && i<sizeof(a)/sizeof(a[0])-1; i++){ pX = amatchMergeRules(a[i], pX); a[i] = 0; } a[i] = amatchMergeRules(a[i], pX); } for(pX=a[0], i=1; i<sizeof(a)/sizeof(a[0]); i++){ pX = amatchMergeRules(a[i], pX); } p->pRule = amatchMergeRules(p->pRule, pX); }else{ /* An error has occurred. Setting p->pRule to point to the head of the ** allocated list ensures that the list will be cleaned up in this case. */ assert( p->pRule==0 ); p->pRule = pHead; } return rc; } /* ** This function converts an SQL quoted string into an unquoted string ** and returns a pointer to a buffer allocated using sqlite3_malloc() ** containing the result. The caller should eventually free this buffer ** using sqlite3_free. ** ** Examples: ** ** "abc" becomes abc ** 'xyz' becomes xyz ** [pqr] becomes pqr ** `mno` becomes mno */ static char *amatchDequote(const char *zIn){ int nIn; /* Size of input string, in bytes */ char *zOut; /* Output (dequoted) string */ nIn = (int)strlen(zIn); zOut = sqlite3_malloc(nIn+1); if( zOut ){ char q = zIn[0]; /* Quote character (if any ) */ if( q!='[' && q!= '\'' && q!='"' && q!='`' ){ memcpy(zOut, zIn, nIn+1); }else{ int iOut = 0; /* Index of next byte to write to output */ int iIn; /* Index of next byte to read from input */ if( q=='[' ) q = ']'; for(iIn=1; iIn<nIn; iIn++){ if( zIn[iIn]==q ) iIn++; zOut[iOut++] = zIn[iIn]; } } assert( (int)strlen(zOut)<=nIn ); } return zOut; } /* ** Deallocate the pVCheck prepared statement. */ static void amatchVCheckClear(amatch_vtab *p){ if( p->pVCheck ){ sqlite3_finalize(p->pVCheck); p->pVCheck = 0; } } /* ** Deallocate an amatch_vtab object */ static void amatchFree(amatch_vtab *p){ if( p ){ amatchFreeRules(p); amatchVCheckClear(p); sqlite3_free(p->zClassName); sqlite3_free(p->zDb); sqlite3_free(p->zCostTab); sqlite3_free(p->zVocabTab); sqlite3_free(p->zVocabWord); sqlite3_free(p->zVocabLang); memset(p, 0, sizeof(*p)); sqlite3_free(p); } } /* ** xDisconnect/xDestroy method for the amatch module. */ static int amatchDisconnect(sqlite3_vtab *pVtab){ amatch_vtab *p = (amatch_vtab*)pVtab; assert( p->nCursor==0 ); amatchFree(p); return SQLITE_OK; } /* ** Check to see if the argument is of the form: ** ** KEY = VALUE ** ** If it is, return a pointer to the first character of VALUE. ** If not, return NULL. Spaces around the = are ignored. */ static const char *amatchValueOfKey(const char *zKey, const char *zStr){ int nKey = (int)strlen(zKey); int nStr = (int)strlen(zStr); int i; if( nStr<nKey+1 ) return 0; if( memcmp(zStr, zKey, nKey)!=0 ) return 0; for(i=nKey; isspace(zStr[i]); i++){} if( zStr[i]!='=' ) return 0; i++; while( isspace(zStr[i]) ){ i++; } return zStr+i; } /* ** xConnect/xCreate method for the amatch module. Arguments are: ** ** argv[0] -> module name ("approximate_match") ** argv[1] -> database name ** argv[2] -> table name ** argv[3...] -> arguments */ static int amatchConnect( sqlite3 *db, void *pAux, int argc, const char *const*argv, sqlite3_vtab **ppVtab, char **pzErr ){ int rc = SQLITE_OK; /* Return code */ amatch_vtab *pNew = 0; /* New virtual table */ const char *zModule = argv[0]; const char *zDb = argv[1]; const char *zVal; int i; (void)pAux; *ppVtab = 0; pNew = sqlite3_malloc( sizeof(*pNew) ); if( pNew==0 ) return SQLITE_NOMEM; rc = SQLITE_NOMEM; memset(pNew, 0, sizeof(*pNew)); pNew->db = db; pNew->zClassName = sqlite3_mprintf("%s", zModule); if( pNew->zClassName==0 ) goto amatchConnectError; pNew->zDb = sqlite3_mprintf("%s", zDb); if( pNew->zDb==0 ) goto amatchConnectError; pNew->zSelf = sqlite3_mprintf("%s", argv[2]); if( pNew->zSelf==0 ) goto amatchConnectError; for(i=3; i<argc; i++){ zVal = amatchValueOfKey("vocabulary_table", argv[i]); if( zVal ){ sqlite3_free(pNew->zVocabTab); pNew->zVocabTab = amatchDequote(zVal); if( pNew->zVocabTab==0 ) goto amatchConnectError; continue; } zVal = amatchValueOfKey("vocabulary_word", argv[i]); if( zVal ){ sqlite3_free(pNew->zVocabWord); pNew->zVocabWord = amatchDequote(zVal); if( pNew->zVocabWord==0 ) goto amatchConnectError; continue; } zVal = amatchValueOfKey("vocabulary_language", argv[i]); if( zVal ){ sqlite3_free(pNew->zVocabLang); pNew->zVocabLang = amatchDequote(zVal); if( pNew->zVocabLang==0 ) goto amatchConnectError; continue; } zVal = amatchValueOfKey("edit_distances", argv[i]); if( zVal ){ sqlite3_free(pNew->zCostTab); pNew->zCostTab = amatchDequote(zVal); if( pNew->zCostTab==0 ) goto amatchConnectError; continue; } *pzErr = sqlite3_mprintf("unrecognized argument: [%s]\n", argv[i]); amatchFree(pNew); *ppVtab = 0; return SQLITE_ERROR; } rc = SQLITE_OK; if( pNew->zCostTab==0 ){ *pzErr = sqlite3_mprintf("no edit_distances table specified"); rc = SQLITE_ERROR; }else{ rc = amatchLoadRules(db, pNew, pzErr); } if( rc==SQLITE_OK ){ rc = sqlite3_declare_vtab(db, "CREATE TABLE x(word,distance,language," "command HIDDEN,nword HIDDEN)" ); #define AMATCH_COL_WORD 0 #define AMATCH_COL_DISTANCE 1 #define AMATCH_COL_LANGUAGE 2 #define AMATCH_COL_COMMAND 3 #define AMATCH_COL_NWORD 4 } if( rc!=SQLITE_OK ){ amatchFree(pNew); } *ppVtab = &pNew->base; return rc; amatchConnectError: amatchFree(pNew); return rc; } /* ** Open a new amatch cursor. */ static int amatchOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){ amatch_vtab *p = (amatch_vtab*)pVTab; amatch_cursor *pCur; pCur = sqlite3_malloc( sizeof(*pCur) ); if( pCur==0 ) return SQLITE_NOMEM; memset(pCur, 0, sizeof(*pCur)); pCur->pVtab = p; *ppCursor = &pCur->base; p->nCursor++; return SQLITE_OK; } /* ** Free up all the memory allocated by a cursor. Set it rLimit to 0 ** to indicate that it is at EOF. */ static void amatchClearCursor(amatch_cursor *pCur){ amatch_word *pWord, *pNextWord; for(pWord=pCur->pAllWords; pWord; pWord=pNextWord){ pNextWord = pWord->pNext; sqlite3_free(pWord); } pCur->pAllWords = 0; sqlite3_free(pCur->zInput); pCur->zInput = 0; pCur->pCost = 0; pCur->pWord = 0; pCur->pCurrent = 0; pCur->rLimit = 1000000; pCur->iLang = 0; pCur->nWord = 0; } /* ** Close a amatch cursor. */ static int amatchClose(sqlite3_vtab_cursor *cur){ amatch_cursor *pCur = (amatch_cursor *)cur; amatchClearCursor(pCur); pCur->pVtab->nCursor--; sqlite3_free(pCur); return SQLITE_OK; } /* ** Render a 24-bit unsigned integer as a 4-byte base-64 number. */ static void amatchEncodeInt(int x, char *z){ static const char a[] = "0123456789" "ABCDEFGHIJ" "KLMNOPQRST" "UVWXYZ^abc" "defghijklm" "nopqrstuvw" "xyz~"; z[0] = a[(x>>18)&0x3f]; z[1] = a[(x>>12)&0x3f]; z[2] = a[(x>>6)&0x3f]; z[3] = a[x&0x3f]; } /* ** Write the zCost[] field for a amatch_word object */ static void amatchWriteCost(amatch_word *pWord){ amatchEncodeInt(pWord->rCost, pWord->zCost); amatchEncodeInt(pWord->iSeq, pWord->zCost+4); pWord->zCost[8] = 0; } /* ** Add a new amatch_word object to the queue. ** ** If a prior amatch_word object with the same zWord, and nMatch ** already exists, update its rCost (if the new rCost is less) but ** otherwise leave it unchanged. Do not add a duplicate. ** ** Do nothing if the cost exceeds threshold. */ static void amatchAddWord( amatch_cursor *pCur, amatch_cost rCost, int nMatch, const char *zWordBase, const char *zWordTail ){ amatch_word *pWord; amatch_avl *pNode; amatch_avl *pOther; int nBase, nTail; char zBuf[4]; if( rCost>pCur->rLimit ){ return; } nBase = (int)strlen(zWordBase); nTail = (int)strlen(zWordTail); if( nBase+nTail+3>pCur->nBuf ){ pCur->nBuf = nBase+nTail+100; pCur->zBuf = sqlite3_realloc(pCur->zBuf, pCur->nBuf); if( pCur->zBuf==0 ){ pCur->nBuf = 0; return; } } amatchEncodeInt(nMatch, zBuf); memcpy(pCur->zBuf, zBuf+2, 2); memcpy(pCur->zBuf+2, zWordBase, nBase); memcpy(pCur->zBuf+2+nBase, zWordTail, nTail+1); pNode = amatchAvlSearch(pCur->pWord, pCur->zBuf); if( pNode ){ pWord = pNode->pWord; if( pWord->rCost>rCost ){ #ifdef AMATCH_TRACE_1 printf("UPDATE [%s][%.*s^%s] %d (\"%s\" \"%s\")\n", pWord->zWord+2, pWord->nMatch, pCur->zInput, pCur->zInput, pWord->rCost, pWord->zWord, pWord->zCost); #endif amatchAvlRemove(&pCur->pCost, &pWord->sCost); pWord->rCost = rCost; amatchWriteCost(pWord); #ifdef AMATCH_TRACE_1 printf(" ---> %d (\"%s\" \"%s\")\n", pWord->rCost, pWord->zWord, pWord->zCost); #endif pOther = amatchAvlInsert(&pCur->pCost, &pWord->sCost); assert( pOther==0 ); (void)pOther; } return; } pWord = sqlite3_malloc( sizeof(*pWord) + nBase + nTail - 1 ); if( pWord==0 ) return; memset(pWord, 0, sizeof(*pWord)); pWord->rCost = rCost; pWord->iSeq = pCur->nWord++; amatchWriteCost(pWord); pWord->nMatch = nMatch; pWord->pNext = pCur->pAllWords; pCur->pAllWords = pWord; pWord->sCost.zKey = pWord->zCost; pWord->sCost.pWord = pWord; pOther = amatchAvlInsert(&pCur->pCost, &pWord->sCost); assert( pOther==0 ); (void)pOther; pWord->sWord.zKey = pWord->zWord; pWord->sWord.pWord = pWord; strcpy(pWord->zWord, pCur->zBuf); pOther = amatchAvlInsert(&pCur->pWord, &pWord->sWord); assert( pOther==0 ); (void)pOther; #ifdef AMATCH_TRACE_1 printf("INSERT [%s][%.*s^%s] %d (\"%s\" \"%s\")\n", pWord->zWord+2, pWord->nMatch, pCur->zInput, pCur->zInput+pWord->nMatch, rCost, pWord->zWord, pWord->zCost); #endif } /* ** Advance a cursor to its next row of output */ static int amatchNext(sqlite3_vtab_cursor *cur){ amatch_cursor *pCur = (amatch_cursor*)cur; amatch_word *pWord = 0; amatch_avl *pNode; int isMatch = 0; amatch_vtab *p = pCur->pVtab; int nWord; int rc; int i; const char *zW; amatch_rule *pRule; char *zBuf = 0; char nBuf = 0; char zNext[8]; char zNextIn[8]; int nNextIn; if( p->pVCheck==0 ){ char *zSql; if( p->zVocabLang && p->zVocabLang[0] ){ zSql = sqlite3_mprintf( "SELECT \"%s\" FROM \"%s\"", " WHERE \"%w\">=?1 AND \"%w\"=?2" " ORDER BY 1", p->zVocabWord, p->zVocabTab, p->zVocabWord, p->zVocabLang ); }else{ zSql = sqlite3_mprintf( "SELECT \"%s\" FROM \"%s\"" " WHERE \"%w\">=?1" " ORDER BY 1", p->zVocabWord, p->zVocabTab, p->zVocabWord ); } rc = sqlite3_prepare_v2(p->db, zSql, -1, &p->pVCheck, 0); sqlite3_free(zSql); if( rc ) return rc; } sqlite3_bind_int(p->pVCheck, 2, pCur->iLang); do{ pNode = amatchAvlFirst(pCur->pCost); if( pNode==0 ){ pWord = 0; break; } pWord = pNode->pWord; amatchAvlRemove(&pCur->pCost, &pWord->sCost); #ifdef AMATCH_TRACE_1 printf("PROCESS [%s][%.*s^%s] %d (\"%s\" \"%s\")\n", pWord->zWord+2, pWord->nMatch, pCur->zInput, pCur->zInput+pWord->nMatch, pWord->rCost, pWord->zWord, pWord->zCost); #endif nWord = (int)strlen(pWord->zWord+2); if( nWord+20>nBuf ){ nBuf = nWord+100; zBuf = sqlite3_realloc(zBuf, nBuf); if( zBuf==0 ) return SQLITE_NOMEM; } strcpy(zBuf, pWord->zWord+2); zNext[0] = 0; zNextIn[0] = pCur->zInput[pWord->nMatch]; if( zNextIn[0] ){ for(i=1; i<=4 && (pCur->zInput[pWord->nMatch+i]&0xc0)==0x80; i++){ zNextIn[i] = pCur->zInput[pWord->nMatch+i]; } zNextIn[i] = 0; nNextIn = i; }else{ nNextIn = 0; } if( zNextIn[0] && zNextIn[0]!='*' ){ sqlite3_reset(p->pVCheck); strcat(zBuf, zNextIn); sqlite3_bind_text(p->pVCheck, 1, zBuf, nWord+nNextIn, SQLITE_STATIC); rc = sqlite3_step(p->pVCheck); if( rc==SQLITE_ROW ){ zW = (const char*)sqlite3_column_text(p->pVCheck, 0); if( strncmp(zBuf, zW, nWord+nNextIn)==0 ){ amatchAddWord(pCur, pWord->rCost, pWord->nMatch+nNextIn, zBuf, ""); } } zBuf[nWord] = 0; } while( 1 ){ strcpy(zBuf+nWord, zNext); sqlite3_reset(p->pVCheck); sqlite3_bind_text(p->pVCheck, 1, zBuf, -1, SQLITE_TRANSIENT); rc = sqlite3_step(p->pVCheck); if( rc!=SQLITE_ROW ) break; zW = (const char*)sqlite3_column_text(p->pVCheck, 0); strcpy(zBuf+nWord, zNext); if( strncmp(zW, zBuf, nWord)!=0 ) break; if( (zNextIn[0]=='*' && zNextIn[1]==0) || (zNextIn[0]==0 && zW[nWord]==0) ){ isMatch = 1; zNextIn[0] = 0; nNextIn = 0; break; } zNext[0] = zW[nWord]; for(i=1; i<=4 && (zW[nWord+i]&0xc0)==0x80; i++){ zNext[i] = zW[nWord+i]; } zNext[i] = 0; zBuf[nWord] = 0; if( p->rIns>0 ){ amatchAddWord(pCur, pWord->rCost+p->rIns, pWord->nMatch, zBuf, zNext); } if( p->rSub>0 ){ amatchAddWord(pCur, pWord->rCost+p->rSub, pWord->nMatch+nNextIn, zBuf, zNext); } if( p->rIns<0 && p->rSub<0 ) break; zNext[i-1]++; /* FIX ME */ } sqlite3_reset(p->pVCheck); if( p->rDel>0 ){ zBuf[nWord] = 0; amatchAddWord(pCur, pWord->rCost+p->rDel, pWord->nMatch+nNextIn, zBuf, ""); } for(pRule=p->pRule; pRule; pRule=pRule->pNext){ if( pRule->iLang!=pCur->iLang ) continue; if( strncmp(pRule->zFrom, pCur->zInput+pWord->nMatch, pRule->nFrom)==0 ){ amatchAddWord(pCur, pWord->rCost+pRule->rCost, pWord->nMatch+pRule->nFrom, pWord->zWord+2, pRule->zTo); } } }while( !isMatch ); pCur->pCurrent = pWord; sqlite3_free(zBuf); return SQLITE_OK; } /* ** Called to "rewind" a cursor back to the beginning so that ** it starts its output over again. Always called at least once ** prior to any amatchColumn, amatchRowid, or amatchEof call. */ static int amatchFilter( sqlite3_vtab_cursor *pVtabCursor, int idxNum, const char *idxStr, int argc, sqlite3_value **argv ){ amatch_cursor *pCur = (amatch_cursor *)pVtabCursor; const char *zWord = "*"; int idx; amatchClearCursor(pCur); idx = 0; if( idxNum & 1 ){ zWord = (const char*)sqlite3_value_text(argv[0]); idx++; } if( idxNum & 2 ){ pCur->rLimit = (amatch_cost)sqlite3_value_int(argv[idx]); idx++; } if( idxNum & 4 ){ pCur->iLang = (amatch_cost)sqlite3_value_int(argv[idx]); idx++; } pCur->zInput = sqlite3_mprintf("%s", zWord); if( pCur->zInput==0 ) return SQLITE_NOMEM; amatchAddWord(pCur, 0, 0, "", ""); amatchNext(pVtabCursor); return SQLITE_OK; } /* ** Only the word and distance columns have values. All other columns ** return NULL */ static int amatchColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){ amatch_cursor *pCur = (amatch_cursor*)cur; switch( i ){ case AMATCH_COL_WORD: { sqlite3_result_text(ctx, pCur->pCurrent->zWord+2, -1, SQLITE_STATIC); break; } case AMATCH_COL_DISTANCE: { sqlite3_result_int(ctx, pCur->pCurrent->rCost); break; } case AMATCH_COL_LANGUAGE: { sqlite3_result_int(ctx, pCur->iLang); break; } case AMATCH_COL_NWORD: { sqlite3_result_int(ctx, pCur->nWord); break; } default: { sqlite3_result_null(ctx); break; } } return SQLITE_OK; } /* ** The rowid. */ static int amatchRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){ amatch_cursor *pCur = (amatch_cursor*)cur; *pRowid = pCur->iRowid; return SQLITE_OK; } /* ** EOF indicator */ static int amatchEof(sqlite3_vtab_cursor *cur){ amatch_cursor *pCur = (amatch_cursor*)cur; return pCur->pCurrent==0; } /* ** Search for terms of these forms: ** ** (A) word MATCH $str ** (B1) distance < $value ** (B2) distance <= $value ** (C) language == $language ** ** The distance< and distance<= are both treated as distance<=. ** The query plan number is a bit vector: ** ** bit 1: Term of the form (A) found ** bit 2: Term like (B1) or (B2) found ** bit 3: Term like (C) found ** ** If bit-1 is set, $str is always in filter.argv[0]. If bit-2 is set ** then $value is in filter.argv[0] if bit-1 is clear and is in ** filter.argv[1] if bit-1 is set. If bit-3 is set, then $ruleid is ** in filter.argv[0] if bit-1 and bit-2 are both zero, is in ** filter.argv[1] if exactly one of bit-1 and bit-2 are set, and is in ** filter.argv[2] if both bit-1 and bit-2 are set. */ static int amatchBestIndex( sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo ){ int iPlan = 0; int iDistTerm = -1; int iLangTerm = -1; int i; const struct sqlite3_index_constraint *pConstraint; (void)tab; pConstraint = pIdxInfo->aConstraint; for(i=0; i<pIdxInfo->nConstraint; i++, pConstraint++){ if( pConstraint->usable==0 ) continue; if( (iPlan & 1)==0 && pConstraint->iColumn==0 && pConstraint->op==SQLITE_INDEX_CONSTRAINT_MATCH ){ iPlan |= 1; pIdxInfo->aConstraintUsage[i].argvIndex = 1; pIdxInfo->aConstraintUsage[i].omit = 1; } if( (iPlan & 2)==0 && pConstraint->iColumn==1 && (pConstraint->op==SQLITE_INDEX_CONSTRAINT_LT || pConstraint->op==SQLITE_INDEX_CONSTRAINT_LE) ){ iPlan |= 2; iDistTerm = i; } if( (iPlan & 4)==0 && pConstraint->iColumn==2 && pConstraint->op==SQLITE_INDEX_CONSTRAINT_EQ ){ iPlan |= 4; pIdxInfo->aConstraintUsage[i].omit = 1; iLangTerm = i; } } if( iPlan & 2 ){ pIdxInfo->aConstraintUsage[iDistTerm].argvIndex = 1+((iPlan&1)!=0); } if( iPlan & 4 ){ int idx = 1; if( iPlan & 1 ) idx++; if( iPlan & 2 ) idx++; pIdxInfo->aConstraintUsage[iLangTerm].argvIndex = idx; } pIdxInfo->idxNum = iPlan; if( pIdxInfo->nOrderBy==1 && pIdxInfo->aOrderBy[0].iColumn==1 && pIdxInfo->aOrderBy[0].desc==0 ){ pIdxInfo->orderByConsumed = 1; } pIdxInfo->estimatedCost = (double)10000; return SQLITE_OK; } /* ** The xUpdate() method. ** ** This implementation disallows DELETE and UPDATE. The only thing ** allowed is INSERT into the "command" column. */ static int amatchUpdate( sqlite3_vtab *pVTab, int argc, sqlite3_value **argv, sqlite_int64 *pRowid ){ amatch_vtab *p = (amatch_vtab*)pVTab; const unsigned char *zCmd; (void)pRowid; if( argc==1 ){ pVTab->zErrMsg = sqlite3_mprintf("DELETE from %s is not allowed", p->zSelf); return SQLITE_ERROR; } if( sqlite3_value_type(argv[0])!=SQLITE_NULL ){ pVTab->zErrMsg = sqlite3_mprintf("UPDATE of %s is not allowed", p->zSelf); return SQLITE_ERROR; } if( sqlite3_value_type(argv[2+AMATCH_COL_WORD])!=SQLITE_NULL || sqlite3_value_type(argv[2+AMATCH_COL_DISTANCE])!=SQLITE_NULL || sqlite3_value_type(argv[2+AMATCH_COL_LANGUAGE])!=SQLITE_NULL ){ pVTab->zErrMsg = sqlite3_mprintf( "INSERT INTO %s allowed for column [command] only", p->zSelf); return SQLITE_ERROR; } zCmd = sqlite3_value_text(argv[2+AMATCH_COL_COMMAND]); if( zCmd==0 ) return SQLITE_OK; return SQLITE_OK; } /* ** A virtual table module that implements the "approximate_match". */ static sqlite3_module amatchModule = { 0, /* iVersion */ amatchConnect, /* xCreate */ amatchConnect, /* xConnect */ amatchBestIndex, /* xBestIndex */ amatchDisconnect, /* xDisconnect */ amatchDisconnect, /* xDestroy */ amatchOpen, /* xOpen - open a cursor */ amatchClose, /* xClose - close a cursor */ amatchFilter, /* xFilter - configure scan constraints */ amatchNext, /* xNext - advance a cursor */ amatchEof, /* xEof - check for end of scan */ amatchColumn, /* xColumn - read data */ amatchRowid, /* xRowid - read data */ amatchUpdate, /* xUpdate */ 0, /* xBegin */ 0, /* xSync */ 0, /* xCommit */ 0, /* xRollback */ 0, /* xFindMethod */ 0, /* xRename */ 0, /* xSavepoint */ 0, /* xRelease */ 0 /* xRollbackTo */ }; /* ** Register the amatch virtual table */ #ifdef _WIN32 __declspec(dllexport) #endif int sqlite3_amatch_init( sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi ){ int rc = SQLITE_OK; SQLITE_EXTENSION_INIT2(pApi); (void)pzErrMsg; /* Not used */ rc = sqlite3_create_module(db, "approximate_match", &amatchModule, 0); return rc; } |
Added ext/misc/closure.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 | /* ** 2013-04-16 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** ** This file contains code for a virtual table that finds the transitive ** closure of a parent/child relationship in a real table. The virtual ** table is called "transitive_closure". ** ** A transitive_closure virtual table is created like this: ** ** CREATE VIRTUAL TABLE x USING transitive_closure( ** tablename=<tablename>, -- T ** idcolumn=<columnname>, -- X ** parentcolumn=<columnname> -- P ** ); ** ** When it is created, the new transitive_closure table may be supplied ** with default values for the name of a table T and columns T.X and T.P. ** The T.X and T.P columns must contain integers. The ideal case is for ** T.X to be the INTEGER PRIMARY KEY. The T.P column should reference ** the T.X column. The row referenced by T.P is the parent of the current row. ** ** The tablename, idcolumn, and parentcolumn supplied by the CREATE VIRTUAL ** TABLE statement may be overridden in individual queries by including ** terms like tablename='newtable', idcolumn='id2', or ** parentcolumn='parent3' in the WHERE clause of the query. ** ** For efficiency, it is essential that there be an index on the P column: ** ** CREATE Tidx1 ON T(P) ** ** Suppose a specific instance of the closure table is as follows: ** ** CREATE VIRTUAL TABLE ct1 USING transitive_closure( ** tablename='group', ** idcolumn='groupId', ** parentcolumn='parentId' ** ); ** ** Such an instance of the transitive_closure virtual table would be ** appropriate for walking a tree defined using a table like this, for example: ** ** CREATE TABLE group( ** groupId INTEGER PRIMARY KEY, ** parentId INTEGER REFERENCES group ** ); ** CREATE INDEX group_idx1 ON group(parentId); ** ** The group table above would presumably have other application-specific ** fields. The key point here is that rows of the group table form a ** tree. The purpose of the ct1 virtual table is to easily extract ** branches of that tree. ** ** Once it has been created, the ct1 virtual table can be queried ** as follows: ** ** SELECT * FROM element ** WHERE element.groupId IN (SELECT id FROM ct1 WHERE root=?1); ** ** The above query will return all elements that are part of group ?1 ** or children of group ?1 or grand-children of ?1 and so forth for all ** descendents of group ?1. The same query can be formulated as a join: ** ** SELECT element.* FROM element, ct1 ** WHERE element.groupid=ct1.id ** AND ct1.root=?1; ** ** The depth of the transitive_closure (the number of generations of ** parent/child relations to follow) can be limited by setting "depth" ** column in the WHERE clause. So, for example, the following query ** finds only children and grandchildren but no further descendents: ** ** SELECT element.* FROM element, ct1 ** WHERE element.groupid=ct1.id ** AND ct1.root=?1 ** AND ct1.depth<=2; ** ** The "ct1.depth<=2" term could be a strict equality "ct1.depth=2" in ** order to find only the grandchildren of ?1, not ?1 itself or the ** children of ?1. ** ** The root=?1 term must be supplied in WHERE clause or else the query ** of the ct1 virtual table will return an empty set. The tablename, ** idcolumn, and parentcolumn attributes can be overridden in the WHERE ** clause if desired. So, for example, the ct1 table could be repurposed ** to find ancestors rather than descendents by inverting the roles of ** the idcolumn and parentcolumn: ** ** SELECT element.* FROM element, ct1 ** WHERE element.groupid=ct1.id ** AND ct1.root=?1 ** AND ct1.idcolumn='parentId' ** AND ct1.parentcolumn='groupId'; ** ** Multiple calls to ct1 could be combined. For example, the following ** query finds all elements that "cousins" of groupId ?1. That is to say ** elements where the groupId is a grandchild of the grandparent of ?1. ** (This definition of "cousins" also includes siblings and self.) ** ** SELECT element.* FROM element, ct1 ** WHERE element.groupId=ct1.id ** AND ct1.depth=2 ** AND ct1.root IN (SELECT id FROM ct1 ** WHERE root=?1 ** AND depth=2 ** AND idcolumn='parentId' ** AND parentcolumn='groupId'); ** ** In our example, the group.groupId column is unique and thus the ** subquery will return exactly one row. For that reason, the IN ** operator could be replaced by "=" to get the same result. But ** in the general case where the idcolumn is not unique, an IN operator ** would be required for this kind of query. ** ** Note that because the tablename, idcolumn, and parentcolumn can ** all be specified in the query, it is possible for an application ** to define a single transitive_closure virtual table for use on lots ** of different hierarchy tables. One might say: ** ** CREATE VIRTUAL TABLE temp.closure USING transitive_closure; ** ** As each database connection is being opened. Then the application ** would always have a "closure" virtual table handy to use for querying. ** ** SELECT element.* FROM element, closure ** WHERE element.groupid=ct1.id ** AND closure.root=?1 ** AND closure.tablename='group' ** AND closure.idname='groupId' ** AND closure.parentname='parentId'; ** ** See the documentation at http://www.sqlite.org/loadext.html for information ** on how to compile and use loadable extensions such as this one. */ #include "sqlite3ext.h" SQLITE_EXTENSION_INIT1 #include <stdlib.h> #include <string.h> #include <assert.h> #include <stdio.h> #include <ctype.h> /* ** Forward declaration of objects used by this implementation */ typedef struct closure_vtab closure_vtab; typedef struct closure_cursor closure_cursor; typedef struct closure_queue closure_queue; typedef struct closure_avl closure_avl; /***************************************************************************** ** AVL Tree implementation */ /* ** Objects that want to be members of the AVL tree should embedded an ** instance of this structure. */ struct closure_avl { sqlite3_int64 id; /* Id of this entry in the table */ int iGeneration; /* Which generation is this entry part of */ closure_avl *pList; /* A linked list of nodes */ closure_avl *pBefore; /* Other elements less than id */ closure_avl *pAfter; /* Other elements greater than id */ closure_avl *pUp; /* Parent element */ short int height; /* Height of this node. Leaf==1 */ short int imbalance; /* Height difference between pBefore and pAfter */ }; /* Recompute the closure_avl.height and closure_avl.imbalance fields for p. ** Assume that the children of p have correct heights. */ static void closureAvlRecomputeHeight(closure_avl *p){ short int hBefore = p->pBefore ? p->pBefore->height : 0; short int hAfter = p->pAfter ? p->pAfter->height : 0; p->imbalance = hBefore - hAfter; /* -: pAfter higher. +: pBefore higher */ p->height = (hBefore>hAfter ? hBefore : hAfter)+1; } /* ** P B ** / \ / \ ** B Z ==> X P ** / \ / \ ** X Y Y Z ** */ static closure_avl *closureAvlRotateBefore(closure_avl *pP){ closure_avl *pB = pP->pBefore; closure_avl *pY = pB->pAfter; pB->pUp = pP->pUp; pB->pAfter = pP; pP->pUp = pB; pP->pBefore = pY; if( pY ) pY->pUp = pP; closureAvlRecomputeHeight(pP); closureAvlRecomputeHeight(pB); return pB; } /* ** P A ** / \ / \ ** X A ==> P Z ** / \ / \ ** Y Z X Y ** */ static closure_avl *closureAvlRotateAfter(closure_avl *pP){ closure_avl *pA = pP->pAfter; closure_avl *pY = pA->pBefore; pA->pUp = pP->pUp; pA->pBefore = pP; pP->pUp = pA; pP->pAfter = pY; if( pY ) pY->pUp = pP; closureAvlRecomputeHeight(pP); closureAvlRecomputeHeight(pA); return pA; } /* ** Return a pointer to the pBefore or pAfter pointer in the parent ** of p that points to p. Or if p is the root node, return pp. */ static closure_avl **closureAvlFromPtr(closure_avl *p, closure_avl **pp){ closure_avl *pUp = p->pUp; if( pUp==0 ) return pp; if( pUp->pAfter==p ) return &pUp->pAfter; return &pUp->pBefore; } /* ** Rebalance all nodes starting with p and working up to the root. ** Return the new root. */ static closure_avl *closureAvlBalance(closure_avl *p){ closure_avl *pTop = p; closure_avl **pp; while( p ){ closureAvlRecomputeHeight(p); if( p->imbalance>=2 ){ closure_avl *pB = p->pBefore; if( pB->imbalance<0 ) p->pBefore = closureAvlRotateAfter(pB); pp = closureAvlFromPtr(p,&p); p = *pp = closureAvlRotateBefore(p); }else if( p->imbalance<=(-2) ){ closure_avl *pA = p->pAfter; if( pA->imbalance>0 ) p->pAfter = closureAvlRotateBefore(pA); pp = closureAvlFromPtr(p,&p); p = *pp = closureAvlRotateAfter(p); } pTop = p; p = p->pUp; } return pTop; } /* Search the tree rooted at p for an entry with id. Return a pointer ** to the entry or return NULL. */ static closure_avl *closureAvlSearch(closure_avl *p, sqlite3_int64 id){ while( p && id!=p->id ){ p = (id<p->id) ? p->pBefore : p->pAfter; } return p; } /* Find the first node (the one with the smallest key). */ static closure_avl *closureAvlFirst(closure_avl *p){ if( p ) while( p->pBefore ) p = p->pBefore; return p; } /* Return the node with the next larger key after p. */ closure_avl *closureAvlNext(closure_avl *p){ closure_avl *pPrev = 0; while( p && p->pAfter==pPrev ){ pPrev = p; p = p->pUp; } if( p && pPrev==0 ){ p = closureAvlFirst(p->pAfter); } return p; } /* Insert a new node pNew. Return NULL on success. If the key is not ** unique, then do not perform the insert but instead leave pNew unchanged ** and return a pointer to an existing node with the same key. */ static closure_avl *closureAvlInsert( closure_avl **ppHead, /* Head of the tree */ closure_avl *pNew /* New node to be inserted */ ){ closure_avl *p = *ppHead; if( p==0 ){ p = pNew; pNew->pUp = 0; }else{ while( p ){ if( pNew->id<p->id ){ if( p->pBefore ){ p = p->pBefore; }else{ p->pBefore = pNew; pNew->pUp = p; break; } }else if( pNew->id>p->id ){ if( p->pAfter ){ p = p->pAfter; }else{ p->pAfter = pNew; pNew->pUp = p; break; } }else{ return p; } } } pNew->pBefore = 0; pNew->pAfter = 0; pNew->height = 1; pNew->imbalance = 0; *ppHead = closureAvlBalance(p); return 0; } /* Walk the tree can call xDestroy on each node */ static void closureAvlDestroy(closure_avl *p, void (*xDestroy)(closure_avl*)){ if( p ){ closureAvlDestroy(p->pBefore, xDestroy); closureAvlDestroy(p->pAfter, xDestroy); xDestroy(p); } } /* ** End of the AVL Tree implementation ******************************************************************************/ /* ** A closure virtual-table object */ struct closure_vtab { sqlite3_vtab base; /* Base class - must be first */ char *zDb; /* Name of database. (ex: "main") */ char *zSelf; /* Name of this virtual table */ char *zTableName; /* Name of table holding parent/child relation */ char *zIdColumn; /* Name of ID column of zTableName */ char *zParentColumn; /* Name of PARENT column in zTableName */ sqlite3 *db; /* The database connection */ int nCursor; /* Number of pending cursors */ }; /* A closure cursor object */ struct closure_cursor { sqlite3_vtab_cursor base; /* Base class - must be first */ closure_vtab *pVtab; /* The virtual table this cursor belongs to */ char *zTableName; /* Name of table holding parent/child relation */ char *zIdColumn; /* Name of ID column of zTableName */ char *zParentColumn; /* Name of PARENT column in zTableName */ closure_avl *pCurrent; /* Current element of output */ closure_avl *pClosure; /* The complete closure tree */ }; /* A queue of AVL nodes */ struct closure_queue { closure_avl *pFirst; /* Oldest node on the queue */ closure_avl *pLast; /* Youngest node on the queue */ }; /* ** Add a node to the end of the queue */ static void queuePush(closure_queue *pQueue, closure_avl *pNode){ pNode->pList = 0; if( pQueue->pLast ){ pQueue->pLast->pList = pNode; }else{ pQueue->pFirst = pNode; } pQueue->pLast = pNode; } /* ** Extract the oldest element (the front element) from the queue. */ static closure_avl *queuePull(closure_queue *pQueue){ closure_avl *p = pQueue->pFirst; if( p ){ pQueue->pFirst = p->pList; if( pQueue->pFirst==0 ) pQueue->pLast = 0; } return p; } /* ** This function converts an SQL quoted string into an unquoted string ** and returns a pointer to a buffer allocated using sqlite3_malloc() ** containing the result. The caller should eventually free this buffer ** using sqlite3_free. ** ** Examples: ** ** "abc" becomes abc ** 'xyz' becomes xyz ** [pqr] becomes pqr ** `mno` becomes mno */ static char *closureDequote(const char *zIn){ int nIn; /* Size of input string, in bytes */ char *zOut; /* Output (dequoted) string */ nIn = (int)strlen(zIn); zOut = sqlite3_malloc(nIn+1); if( zOut ){ char q = zIn[0]; /* Quote character (if any ) */ if( q!='[' && q!= '\'' && q!='"' && q!='`' ){ memcpy(zOut, zIn, nIn+1); }else{ int iOut = 0; /* Index of next byte to write to output */ int iIn; /* Index of next byte to read from input */ if( q=='[' ) q = ']'; for(iIn=1; iIn<nIn; iIn++){ if( zIn[iIn]==q ) iIn++; zOut[iOut++] = zIn[iIn]; } } assert( (int)strlen(zOut)<=nIn ); } return zOut; } /* ** Deallocate an closure_vtab object */ static void closureFree(closure_vtab *p){ if( p ){ sqlite3_free(p->zDb); sqlite3_free(p->zSelf); sqlite3_free(p->zTableName); sqlite3_free(p->zIdColumn); sqlite3_free(p->zParentColumn); memset(p, 0, sizeof(*p)); sqlite3_free(p); } } /* ** xDisconnect/xDestroy method for the closure module. */ static int closureDisconnect(sqlite3_vtab *pVtab){ closure_vtab *p = (closure_vtab*)pVtab; assert( p->nCursor==0 ); closureFree(p); return SQLITE_OK; } /* ** Check to see if the argument is of the form: ** ** KEY = VALUE ** ** If it is, return a pointer to the first character of VALUE. ** If not, return NULL. Spaces around the = are ignored. */ static const char *closureValueOfKey(const char *zKey, const char *zStr){ int nKey = (int)strlen(zKey); int nStr = (int)strlen(zStr); int i; if( nStr<nKey+1 ) return 0; if( memcmp(zStr, zKey, nKey)!=0 ) return 0; for(i=nKey; isspace(zStr[i]); i++){} if( zStr[i]!='=' ) return 0; i++; while( isspace(zStr[i]) ){ i++; } return zStr+i; } /* ** xConnect/xCreate method for the closure module. Arguments are: ** ** argv[0] -> module name ("approximate_match") ** argv[1] -> database name ** argv[2] -> table name ** argv[3...] -> arguments */ static int closureConnect( sqlite3 *db, void *pAux, int argc, const char *const*argv, sqlite3_vtab **ppVtab, char **pzErr ){ int rc = SQLITE_OK; /* Return code */ closure_vtab *pNew = 0; /* New virtual table */ const char *zDb = argv[1]; const char *zVal; int i; (void)pAux; *ppVtab = 0; pNew = sqlite3_malloc( sizeof(*pNew) ); if( pNew==0 ) return SQLITE_NOMEM; rc = SQLITE_NOMEM; memset(pNew, 0, sizeof(*pNew)); pNew->db = db; pNew->zDb = sqlite3_mprintf("%s", zDb); if( pNew->zDb==0 ) goto closureConnectError; pNew->zSelf = sqlite3_mprintf("%s", argv[2]); if( pNew->zSelf==0 ) goto closureConnectError; for(i=3; i<argc; i++){ zVal = closureValueOfKey("tablename", argv[i]); if( zVal ){ sqlite3_free(pNew->zTableName); pNew->zTableName = closureDequote(zVal); if( pNew->zTableName==0 ) goto closureConnectError; continue; } zVal = closureValueOfKey("idcolumn", argv[i]); if( zVal ){ sqlite3_free(pNew->zIdColumn); pNew->zIdColumn = closureDequote(zVal); if( pNew->zIdColumn==0 ) goto closureConnectError; continue; } zVal = closureValueOfKey("parentcolumn", argv[i]); if( zVal ){ sqlite3_free(pNew->zParentColumn); pNew->zParentColumn = closureDequote(zVal); if( pNew->zParentColumn==0 ) goto closureConnectError; continue; } *pzErr = sqlite3_mprintf("unrecognized argument: [%s]\n", argv[i]); closureFree(pNew); *ppVtab = 0; return SQLITE_ERROR; } rc = sqlite3_declare_vtab(db, "CREATE TABLE x(id,depth,root HIDDEN,tablename HIDDEN," "idcolumn HIDDEN,parentcolumn HIDDEN)" ); #define CLOSURE_COL_ID 0 #define CLOSURE_COL_DEPTH 1 #define CLOSURE_COL_ROOT 2 #define CLOSURE_COL_TABLENAME 3 #define CLOSURE_COL_IDCOLUMN 4 #define CLOSURE_COL_PARENTCOLUMN 5 if( rc!=SQLITE_OK ){ closureFree(pNew); } *ppVtab = &pNew->base; return rc; closureConnectError: closureFree(pNew); return rc; } /* ** Open a new closure cursor. */ static int closureOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){ closure_vtab *p = (closure_vtab*)pVTab; closure_cursor *pCur; pCur = sqlite3_malloc( sizeof(*pCur) ); if( pCur==0 ) return SQLITE_NOMEM; memset(pCur, 0, sizeof(*pCur)); pCur->pVtab = p; *ppCursor = &pCur->base; p->nCursor++; return SQLITE_OK; } /* ** Free up all the memory allocated by a cursor. Set it rLimit to 0 ** to indicate that it is at EOF. */ static void closureClearCursor(closure_cursor *pCur){ closureAvlDestroy(pCur->pClosure, (void(*)(closure_avl*))sqlite3_free); sqlite3_free(pCur->zTableName); sqlite3_free(pCur->zIdColumn); sqlite3_free(pCur->zParentColumn); pCur->zTableName = 0; pCur->zIdColumn = 0; pCur->zParentColumn = 0; pCur->pCurrent = 0; pCur->pClosure = 0; } /* ** Close a closure cursor. */ static int closureClose(sqlite3_vtab_cursor *cur){ closure_cursor *pCur = (closure_cursor *)cur; closureClearCursor(pCur); pCur->pVtab->nCursor--; sqlite3_free(pCur); return SQLITE_OK; } /* ** Advance a cursor to its next row of output */ static int closureNext(sqlite3_vtab_cursor *cur){ closure_cursor *pCur = (closure_cursor*)cur; pCur->pCurrent = closureAvlNext(pCur->pCurrent); return SQLITE_OK; } /* ** Allocate and insert a node */ static int closureInsertNode( closure_queue *pQueue, /* Add new node to this queue */ closure_cursor *pCur, /* The cursor into which to add the node */ sqlite3_int64 id, /* The node ID */ int iGeneration /* The generation number for this node */ ){ closure_avl *pNew = sqlite3_malloc( sizeof(*pNew) ); if( pNew==0 ) return SQLITE_NOMEM; memset(pNew, 0, sizeof(*pNew)); pNew->id = id; pNew->iGeneration = iGeneration; closureAvlInsert(&pCur->pClosure, pNew); queuePush(pQueue, pNew); return SQLITE_OK; } /* ** Called to "rewind" a cursor back to the beginning so that ** it starts its output over again. Always called at least once ** prior to any closureColumn, closureRowid, or closureEof call. ** ** This routine actually computes the closure. ** ** See the comment at the beginning of closureBestIndex() for a ** description of the meaning of idxNum. The idxStr parameter is ** not used. */ static int closureFilter( sqlite3_vtab_cursor *pVtabCursor, int idxNum, const char *idxStr, int argc, sqlite3_value **argv ){ closure_cursor *pCur = (closure_cursor *)pVtabCursor; closure_vtab *pVtab = pCur->pVtab; sqlite3_int64 iRoot; int mxGen = 999999999; char *zSql; sqlite3_stmt *pStmt; closure_avl *pAvl; int rc = SQLITE_OK; const char *zTableName = pVtab->zTableName; const char *zIdColumn = pVtab->zIdColumn; const char *zParentColumn = pVtab->zParentColumn; closure_queue sQueue; (void)idxStr; /* Unused parameter */ (void)argc; /* Unused parameter */ closureClearCursor(pCur); memset(&sQueue, 0, sizeof(sQueue)); if( (idxNum & 1)==0 ){ /* No root=$root in the WHERE clause. Return an empty set */ return SQLITE_OK; } iRoot = sqlite3_value_int64(argv[0]); if( (idxNum & 0x000f0)!=0 ){ mxGen = sqlite3_value_int(argv[(idxNum>>4)&0x0f]); if( (idxNum & 0x00002)!=0 ) mxGen--; } if( (idxNum & 0x00f00)!=0 ){ zTableName = (const char*)sqlite3_value_text(argv[(idxNum>>8)&0x0f]); pCur->zTableName = sqlite3_mprintf("%s", zTableName); } if( (idxNum & 0x0f000)!=0 ){ zIdColumn = (const char*)sqlite3_value_text(argv[(idxNum>>12)&0x0f]); pCur->zIdColumn = sqlite3_mprintf("%s", zIdColumn); } if( (idxNum & 0x0f0000)!=0 ){ zParentColumn = (const char*)sqlite3_value_text(argv[(idxNum>>16)&0x0f]); pCur->zParentColumn = sqlite3_mprintf("%s", zParentColumn); } zSql = sqlite3_mprintf( "SELECT \"%w\".\"%w\" FROM \"%w\" WHERE \"%w\".\"%w\"=?1", zTableName, zIdColumn, zTableName, zTableName, zParentColumn); if( zSql==0 ){ return SQLITE_NOMEM; }else{ rc = sqlite3_prepare_v2(pVtab->db, zSql, -1, &pStmt, 0); sqlite3_free(zSql); if( rc ){ sqlite3_free(pVtab->base.zErrMsg); pVtab->base.zErrMsg = sqlite3_mprintf("%s", sqlite3_errmsg(pVtab->db)); return rc; } } if( rc==SQLITE_OK ){ rc = closureInsertNode(&sQueue, pCur, iRoot, 0); } while( (pAvl = queuePull(&sQueue))!=0 ){ if( pAvl->iGeneration>=mxGen ) continue; sqlite3_bind_int64(pStmt, 1, pAvl->id); while( rc==SQLITE_OK && sqlite3_step(pStmt)==SQLITE_ROW ){ if( sqlite3_column_type(pStmt,0)==SQLITE_INTEGER ){ sqlite3_int64 iNew = sqlite3_column_int64(pStmt, 0); if( closureAvlSearch(pCur->pClosure, iNew)==0 ){ rc = closureInsertNode(&sQueue, pCur, iNew, pAvl->iGeneration+1); } } } sqlite3_reset(pStmt); } sqlite3_finalize(pStmt); if( rc==SQLITE_OK ){ pCur->pCurrent = closureAvlFirst(pCur->pClosure); } return rc; } /* ** Only the word and distance columns have values. All other columns ** return NULL */ static int closureColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){ closure_cursor *pCur = (closure_cursor*)cur; switch( i ){ case CLOSURE_COL_ID: { sqlite3_result_int64(ctx, pCur->pCurrent->id); break; } case CLOSURE_COL_DEPTH: { sqlite3_result_int(ctx, pCur->pCurrent->iGeneration); break; } case CLOSURE_COL_ROOT: { sqlite3_result_null(ctx); break; } case CLOSURE_COL_TABLENAME: { sqlite3_result_text(ctx, pCur->zTableName ? pCur->zTableName : pCur->pVtab->zTableName, -1, SQLITE_TRANSIENT); break; } case CLOSURE_COL_IDCOLUMN: { sqlite3_result_text(ctx, pCur->zIdColumn ? pCur->zIdColumn : pCur->pVtab->zIdColumn, -1, SQLITE_TRANSIENT); break; } case CLOSURE_COL_PARENTCOLUMN: { sqlite3_result_text(ctx, pCur->zParentColumn ? pCur->zParentColumn : pCur->pVtab->zParentColumn, -1, SQLITE_TRANSIENT); break; } } return SQLITE_OK; } /* ** The rowid. For the closure table, this is the same as the "id" column. */ static int closureRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){ closure_cursor *pCur = (closure_cursor*)cur; *pRowid = pCur->pCurrent->id; return SQLITE_OK; } /* ** EOF indicator */ static int closureEof(sqlite3_vtab_cursor *cur){ closure_cursor *pCur = (closure_cursor*)cur; return pCur->pCurrent==0; } /* ** Search for terms of these forms: ** ** (A) root = $root ** (B1) depth < $depth ** (B2) depth <= $depth ** (B3) depth = $depth ** (C) tablename = $tablename ** (D) idcolumn = $idcolumn ** (E) parentcolumn = $parentcolumn ** ** ** ** idxNum meaning ** ---------- ------------------------------------------------------ ** 0x00000001 Term of the form (A) found ** 0x00000002 The term of bit-2 is like (B1) ** 0x000000f0 Index in filter.argv[] of $depth. 0 if not used. ** 0x00000f00 Index in filter.argv[] of $tablename. 0 if not used. ** 0x0000f000 Index in filter.argv[] of $idcolumn. 0 if not used ** 0x000f0000 Index in filter.argv[] of $parentcolumn. 0 if not used. ** ** There must be a term of type (A). If there is not, then the index type ** is 0 and the query will return an empty set. */ static int closureBestIndex( sqlite3_vtab *pTab, /* The virtual table */ sqlite3_index_info *pIdxInfo /* Information about the query */ ){ int iPlan = 0; int i; int idx = 1; const struct sqlite3_index_constraint *pConstraint; closure_vtab *pVtab = (closure_vtab*)pTab; pConstraint = pIdxInfo->aConstraint; for(i=0; i<pIdxInfo->nConstraint; i++, pConstraint++){ if( pConstraint->usable==0 ) continue; if( (iPlan & 1)==0 && pConstraint->iColumn==CLOSURE_COL_ROOT && pConstraint->op==SQLITE_INDEX_CONSTRAINT_EQ ){ iPlan |= 1; pIdxInfo->aConstraintUsage[i].argvIndex = 1; pIdxInfo->aConstraintUsage[i].omit = 1; } if( (iPlan & 0x0000f0)==0 && pConstraint->iColumn==CLOSURE_COL_DEPTH && (pConstraint->op==SQLITE_INDEX_CONSTRAINT_LT || pConstraint->op==SQLITE_INDEX_CONSTRAINT_LE || pConstraint->op==SQLITE_INDEX_CONSTRAINT_EQ) ){ iPlan |= idx<<4; pIdxInfo->aConstraintUsage[i].argvIndex = ++idx; if( pConstraint->op==SQLITE_INDEX_CONSTRAINT_LT ) iPlan |= 0x000002; } if( (iPlan & 0x000f00)==0 && pConstraint->iColumn==CLOSURE_COL_TABLENAME && pConstraint->op==SQLITE_INDEX_CONSTRAINT_EQ ){ iPlan |= idx<<8; pIdxInfo->aConstraintUsage[i].argvIndex = ++idx; pIdxInfo->aConstraintUsage[i].omit = 1; } if( (iPlan & 0x00f000)==0 && pConstraint->iColumn==CLOSURE_COL_IDCOLUMN && pConstraint->op==SQLITE_INDEX_CONSTRAINT_EQ ){ iPlan |= idx<<12; pIdxInfo->aConstraintUsage[i].argvIndex = ++idx; pIdxInfo->aConstraintUsage[i].omit = 1; } if( (iPlan & 0x0f0000)==0 && pConstraint->iColumn==CLOSURE_COL_PARENTCOLUMN && pConstraint->op==SQLITE_INDEX_CONSTRAINT_EQ ){ iPlan |= idx<<16; pIdxInfo->aConstraintUsage[i].argvIndex = ++idx; pIdxInfo->aConstraintUsage[i].omit = 1; } } if( (pVtab->zTableName==0 && (iPlan & 0x000f00)==0) || (pVtab->zIdColumn==0 && (iPlan & 0x00f000)==0) || (pVtab->zParentColumn==0 && (iPlan & 0x0f0000)==0) ){ /* All of tablename, idcolumn, and parentcolumn must be specified ** in either the CREATE VIRTUAL TABLE or in the WHERE clause constraints ** or else the result is an empty set. */ iPlan = 0; } pIdxInfo->idxNum = iPlan; if( pIdxInfo->nOrderBy==1 && pIdxInfo->aOrderBy[0].iColumn==CLOSURE_COL_ID && pIdxInfo->aOrderBy[0].desc==0 ){ pIdxInfo->orderByConsumed = 1; } pIdxInfo->estimatedCost = (double)10000; return SQLITE_OK; } /* ** A virtual table module that implements the "approximate_match". */ static sqlite3_module closureModule = { 0, /* iVersion */ closureConnect, /* xCreate */ closureConnect, /* xConnect */ closureBestIndex, /* xBestIndex */ closureDisconnect, /* xDisconnect */ closureDisconnect, /* xDestroy */ closureOpen, /* xOpen - open a cursor */ closureClose, /* xClose - close a cursor */ closureFilter, /* xFilter - configure scan constraints */ closureNext, /* xNext - advance a cursor */ closureEof, /* xEof - check for end of scan */ closureColumn, /* xColumn - read data */ closureRowid, /* xRowid - read data */ 0, /* xUpdate */ 0, /* xBegin */ 0, /* xSync */ 0, /* xCommit */ 0, /* xRollback */ 0, /* xFindMethod */ 0, /* xRename */ 0, /* xSavepoint */ 0, /* xRelease */ 0 /* xRollbackTo */ }; /* ** Register the closure virtual table */ #ifdef _WIN32 __declspec(dllexport) #endif int sqlite3_closure_init( sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi ){ int rc = SQLITE_OK; SQLITE_EXTENSION_INIT2(pApi); (void)pzErrMsg; rc = sqlite3_create_module(db, "transitive_closure", &closureModule, 0); return rc; } |
Name change from src/test_fuzzer.c to ext/misc/fuzzer.c.
︙ | ︙ | |||
137 138 139 140 141 142 143 144 145 146 147 148 149 | ** ** LIMITS ** ** The maximum ruleset number is 2147483647. The maximum length of either ** of the strings in the second or third column of the fuzzer data table ** is 50 bytes. The maximum cost on a rule is 1000. */ /* If SQLITE_DEBUG is not defined, disable assert statements. */ #if !defined(NDEBUG) && !defined(SQLITE_DEBUG) # define NDEBUG #endif | > > < | 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 | ** ** LIMITS ** ** The maximum ruleset number is 2147483647. The maximum length of either ** of the strings in the second or third column of the fuzzer data table ** is 50 bytes. The maximum cost on a rule is 1000. */ #include "sqlite3ext.h" SQLITE_EXTENSION_INIT1 /* If SQLITE_DEBUG is not defined, disable assert statements. */ #if !defined(NDEBUG) && !defined(SQLITE_DEBUG) # define NDEBUG #endif #include <stdlib.h> #include <string.h> #include <assert.h> #include <stdio.h> #ifndef SQLITE_OMIT_VIRTUALTABLE |
︙ | ︙ | |||
1151 1152 1153 1154 1155 1156 1157 | 0, /* xFindMethod */ 0, /* xRename */ }; #endif /* SQLITE_OMIT_VIRTUALTABLE */ | < < < < < | < > < < | < < < | < < | < < < < | < < < < < < < < < < | < | | < < < < < < < < < < < < < < < < | < < | 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 | 0, /* xFindMethod */ 0, /* xRename */ }; #endif /* SQLITE_OMIT_VIRTUALTABLE */ #ifdef _WIN32 __declspec(dllexport) #endif int sqlite3_fuzzer_init( sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi ){ int rc = SQLITE_OK; SQLITE_EXTENSION_INIT2(pApi); rc = sqlite3_create_module(db, "fuzzer", &fuzzerModule, 0); return rc; } |
Added ext/misc/ieee754.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 | /* ** 2013-04-17 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ****************************************************************************** ** ** This SQLite extension implements functions for the exact display ** and input of IEEE754 Binary64 floating-point numbers. ** ** ieee754(X) ** ieee754(Y,Z) ** ** In the first form, the value X should be a floating-point number. ** The function will return a string of the form 'ieee754(Y,Z)' where ** Y and Z are integers such that X==Y*pow(w.0,Z). ** ** In the second form, Y and Z are integers which are the mantissa and ** base-2 exponent of a new floating point number. The function returns ** a floating-point value equal to Y*pow(2.0,Z). ** ** Examples: ** ** ieee754(2.0) -> 'ieee754(2,0)' ** ieee754(45.25) -> 'ieee754(181,-2)' ** ieee754(2, 0) -> 2.0 ** ieee754(181, -2) -> 45.25 */ #include "sqlite3ext.h" SQLITE_EXTENSION_INIT1 #include <assert.h> #include <string.h> /* ** Implementation of the ieee754() function */ static void ieee754func( sqlite3_context *context, int argc, sqlite3_value **argv ){ if( argc==1 ){ sqlite3_int64 m, a; double r; int e; int isNeg; char zResult[100]; assert( sizeof(m)==sizeof(r) ); if( sqlite3_value_type(argv[0])!=SQLITE_FLOAT ) return; r = sqlite3_value_double(argv[0]); if( r<0.0 ){ isNeg = 1; r = -r; }else{ isNeg = 0; } memcpy(&a,&r,sizeof(a)); if( a==0 ){ e = 0; m = 0; }else{ e = a>>52; m = a & ((((sqlite3_int64)1)<<52)-1); m |= ((sqlite3_int64)1)<<52; while( e<1075 && m>0 && (m&1)==0 ){ m >>= 1; e++; } if( isNeg ) m = -m; } sqlite3_snprintf(sizeof(zResult), zResult, "ieee754(%lld,%d)", m, e-1075); sqlite3_result_text(context, zResult, -1, SQLITE_TRANSIENT); }else if( argc==2 ){ sqlite3_int64 m, e, a; double r; int isNeg = 0; m = sqlite3_value_int64(argv[0]); e = sqlite3_value_int64(argv[1]); if( m<0 ){ isNeg = 1; m = -m; if( m<0 ) return; }else if( m==0 && e>1000 && e<1000 ){ sqlite3_result_double(context, 0.0); return; } while( (m>>32)&0xffe00000 ){ m >>= 1; e++; } while( ((m>>32)&0xfff00000)==0 ){ m <<= 1; e--; } e += 1075; if( e<0 ) e = m = 0; if( e>0x7ff ) m = 0; a = m & ((((sqlite3_int64)1)<<52)-1); a |= e<<52; if( isNeg ) a |= ((sqlite3_int64)1)<<63; memcpy(&r, &a, sizeof(r)); sqlite3_result_double(context, r); } } #ifdef _WIN32 __declspec(dllexport) #endif int sqlite3_ieee_init( sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi ){ int rc = SQLITE_OK; SQLITE_EXTENSION_INIT2(pApi); (void)pzErrMsg; /* Unused parameter */ rc = sqlite3_create_function(db, "ieee754", 1, SQLITE_UTF8, 0, ieee754func, 0, 0); if( rc==SQLITE_OK ){ rc = sqlite3_create_function(db, "ieee754", 2, SQLITE_UTF8, 0, ieee754func, 0, 0); } return rc; } |
Added ext/misc/nextchar.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 | /* ** 2013-02-28 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ****************************************************************************** ** ** This file contains code to implement the next_char(A,T,F,W) SQL function. ** ** The next_char(A,T,F,H) function finds all valid "next" characters for ** string A given the vocabulary in T.F. The T.F field should be indexed. ** If the W value exists and is a non-empty string, then it is an SQL ** expression that limits the entries in T.F that will be considered. ** ** For example, suppose an application has a dictionary like this: ** ** CREATE TABLE dictionary(word TEXT UNIQUE); ** ** Further suppose that for user keypad entry, it is desired to disable ** (gray out) keys that are not valid as the next character. If the ** the user has previously entered (say) 'cha' then to find all allowed ** next characters (and thereby determine when keys should not be grayed ** out) run the following query: ** ** SELECT next_char('cha','dictionary','word'); */ #include "sqlite3ext.h" SQLITE_EXTENSION_INIT1 #include <string.h> /* ** A structure to hold context of the next_char() computation across ** nested function calls. */ typedef struct nextCharContext nextCharContext; struct nextCharContext { sqlite3 *db; /* Database connection */ sqlite3_stmt *pStmt; /* Prepared statement used to query */ const unsigned char *zPrefix; /* Prefix to scan */ int nPrefix; /* Size of zPrefix in bytes */ int nAlloc; /* Space allocated to aResult */ int nUsed; /* Space used in aResult */ unsigned int *aResult; /* Array of next characters */ int mallocFailed; /* True if malloc fails */ int otherError; /* True for any other failure */ }; /* ** Append a result character if the character is not already in the ** result. */ static void nextCharAppend(nextCharContext *p, unsigned c){ int i; for(i=0; i<p->nUsed; i++){ if( p->aResult[i]==c ) return; } if( p->nUsed+1 > p->nAlloc ){ unsigned int *aNew; int n = p->nAlloc*2 + 30; aNew = sqlite3_realloc(p->aResult, n*sizeof(unsigned int)); if( aNew==0 ){ p->mallocFailed = 1; return; }else{ p->aResult = aNew; p->nAlloc = n; } } p->aResult[p->nUsed++] = c; } /* ** Write a character into z[] as UTF8. Return the number of bytes needed ** to hold the character */ static int writeUtf8(unsigned char *z, unsigned c){ if( c<0x00080 ){ z[0] = (unsigned char)(c&0xff); return 1; } if( c<0x00800 ){ z[0] = 0xC0 + (unsigned char)((c>>6)&0x1F); z[1] = 0x80 + (unsigned char)(c & 0x3F); return 2; } if( c<0x10000 ){ z[0] = 0xE0 + (unsigned char)((c>>12)&0x0F); z[1] = 0x80 + (unsigned char)((c>>6) & 0x3F); z[2] = 0x80 + (unsigned char)(c & 0x3F); return 3; } z[0] = 0xF0 + (unsigned char)((c>>18) & 0x07); z[1] = 0x80 + (unsigned char)((c>>12) & 0x3F); z[2] = 0x80 + (unsigned char)((c>>6) & 0x3F); z[3] = 0x80 + (unsigned char)(c & 0x3F); return 4; } /* ** Read a UTF8 character out of z[] and write it into *pOut. Return ** the number of bytes in z[] that were used to construct the character. */ static int readUtf8(const unsigned char *z, unsigned *pOut){ static const unsigned char validBits[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, 0x00, 0x01, 0x00, 0x00, }; unsigned c = z[0]; if( c<0xc0 ){ *pOut = c; return 1; }else{ int n = 1; c = validBits[c-0xc0]; while( (z[n] & 0xc0)==0x80 ){ c = (c<<6) + (0x3f & z[n++]); } if( c<0x80 || (c&0xFFFFF800)==0xD800 || (c&0xFFFFFFFE)==0xFFFE ){ c = 0xFFFD; } *pOut = c; return n; } } /* ** The nextCharContext structure has been set up. Add all "next" characters ** to the result set. */ static void findNextChars(nextCharContext *p){ unsigned cPrev = 0; unsigned char zPrev[8]; int n, rc; for(;;){ sqlite3_bind_text(p->pStmt, 1, (char*)p->zPrefix, p->nPrefix, SQLITE_STATIC); n = writeUtf8(zPrev, cPrev+1); sqlite3_bind_text(p->pStmt, 2, (char*)zPrev, n, SQLITE_STATIC); rc = sqlite3_step(p->pStmt); if( rc==SQLITE_DONE ){ sqlite3_reset(p->pStmt); return; }else if( rc!=SQLITE_ROW ){ p->otherError = rc; return; }else{ const unsigned char *zOut = sqlite3_column_text(p->pStmt, 0); unsigned cNext; n = readUtf8(zOut+p->nPrefix, &cNext); sqlite3_reset(p->pStmt); nextCharAppend(p, cNext); cPrev = cNext; if( p->mallocFailed ) return; } } } /* ** next_character(A,T,F,W) ** ** Return a string composted of all next possible characters after ** A for elements of T.F. If W is supplied, then it is an SQL expression ** that limits the elements in T.F that are considered. */ static void nextCharFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ nextCharContext c; const unsigned char *zTable = sqlite3_value_text(argv[1]); const unsigned char *zField = sqlite3_value_text(argv[2]); const unsigned char *zWhere; char *zSql; int rc; memset(&c, 0, sizeof(c)); c.db = sqlite3_context_db_handle(context); c.zPrefix = sqlite3_value_text(argv[0]); c.nPrefix = sqlite3_value_bytes(argv[0]); if( zTable==0 || zField==0 || c.zPrefix==0 ) return; if( argc<4 || (zWhere = sqlite3_value_text(argv[3]))==0 || zWhere[0]==0 ){ zSql = sqlite3_mprintf( "SELECT \"%w\" FROM \"%w\"" " WHERE \"%w\">=(?1 || ?2)" " AND \"%w\"<=(?1 || char(1114111))" /* 1114111 == 0x10ffff */ " ORDER BY 1 ASC LIMIT 1", zField, zTable, zField, zField); }else{ zSql = sqlite3_mprintf( "SELECT \"%w\" FROM \"%w\"" " WHERE \"%w\">=(?1 || ?2)" " AND \"%w\"<=(?1 || char(1114111))" /* 1114111 == 0x10ffff */ " AND (%s)" " ORDER BY 1 ASC LIMIT 1", zField, zTable, zField, zField, zWhere); } if( zSql==0 ){ sqlite3_result_error_nomem(context); return; } rc = sqlite3_prepare_v2(c.db, zSql, -1, &c.pStmt, 0); sqlite3_free(zSql); if( rc ){ sqlite3_result_error(context, sqlite3_errmsg(c.db), -1); return; } findNextChars(&c); if( c.mallocFailed ){ sqlite3_result_error_nomem(context); }else{ unsigned char *pRes; pRes = sqlite3_malloc( c.nUsed*4 + 1 ); if( pRes==0 ){ sqlite3_result_error_nomem(context); }else{ int i; int n = 0; for(i=0; i<c.nUsed; i++){ n += writeUtf8(pRes+n, c.aResult[i]); } pRes[n] = 0; sqlite3_result_text(context, (const char*)pRes, n, sqlite3_free); } } sqlite3_finalize(c.pStmt); sqlite3_free(c.aResult); } #ifdef _WIN32 __declspec(dllexport) #endif int sqlite3_nextchar_init( sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi ){ int rc = SQLITE_OK; SQLITE_EXTENSION_INIT2(pApi); (void)pzErrMsg; /* Unused parameter */ rc = sqlite3_create_function(db, "next_char", 3, SQLITE_UTF8, 0, nextCharFunc, 0, 0); if( rc==SQLITE_OK ){ rc = sqlite3_create_function(db, "next_char", 4, SQLITE_UTF8, 0, nextCharFunc, 0, 0); } return rc; } |
Name change from src/test_regexp.c to ext/misc/regexp.c.
︙ | ︙ | |||
8 9 10 11 12 13 14 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ****************************************************************************** ** ** The code in this file implements a compact but reasonably ** efficient regular-expression matcher for posix extended regular | | > > > > > > > > > | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ****************************************************************************** ** ** The code in this file implements a compact but reasonably ** efficient regular-expression matcher for posix extended regular ** expressions against UTF8 text. ** ** This file is an SQLite extension. It registers a single function ** named "regexp(A,B)" where A is the regular expression and B is the ** string to be matched. By registering this function, SQLite will also ** then implement the "B regexp A" operator. Note that with the function ** the regular expression comes first, but with the operator it comes ** second. ** ** The following regular expression syntax is supported: ** ** X* zero or more occurrences of X ** X+ one or more occurrences of X ** X? zero or one occurrences of X ** X{p,q} between p and q occurrences of X ** (X) match X ** X|Y X or Y |
︙ | ︙ | |||
45 46 47 48 49 50 51 | ** exhibits exponential behavior. Note that the X{p,q} operator expands ** to p copies of X following by q-p copies of X? and that the size of the ** regular expression in the O(N*M) performance bound is computed after ** this expansion. */ #include <string.h> #include <stdlib.h> | | > > > > > > > > > > | 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 | ** exhibits exponential behavior. Note that the X{p,q} operator expands ** to p copies of X following by q-p copies of X? and that the size of the ** regular expression in the O(N*M) performance bound is computed after ** this expansion. */ #include <string.h> #include <stdlib.h> #include "sqlite3ext.h" SQLITE_EXTENSION_INIT1 /* ** The following #defines change the names of some functions implemented in ** this file to prevent name collisions with C-library functions of the ** same name. */ #define re_match sqlite3re_match #define re_compile sqlite3re_compile #define re_free sqlite3re_free /* The end-of-input character */ #define RE_EOF 0 /* End of input */ /* The NFA is implemented as sequence of opcodes taken from the following ** set. Each opcode has a single integer argument. */ |
︙ | ︙ | |||
171 172 173 174 175 176 177 | static int re_space_char(int c){ return c==' ' || c=='\t' || c=='\n' || c=='\r' || c=='\v' || c=='\f'; } /* Run a compiled regular expression on the zero-terminated input ** string zIn[]. Return true on a match and false if there is no match. */ | | | | 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 | static int re_space_char(int c){ return c==' ' || c=='\t' || c=='\n' || c=='\r' || c=='\v' || c=='\f'; } /* Run a compiled regular expression on the zero-terminated input ** string zIn[]. Return true on a match and false if there is no match. */ static int re_match(ReCompiled *pRe, const unsigned char *zIn, int nIn){ ReStateSet aStateSet[2], *pThis, *pNext; ReStateNumber aSpace[100]; ReStateNumber *pToFree; unsigned int i = 0; unsigned int iSwap = 0; int c = RE_EOF+1; int cPrev = 0; int rc = 0; ReInput in; in.z = zIn; in.i = 0; in.mx = nIn>=0 ? nIn : (int)strlen((char const*)zIn); /* Look for the initial prefix match, if there is one. */ if( pRe->nInit ){ unsigned char x = pRe->zInit[0]; while( in.i+pRe->nInit<=in.mx && (zIn[in.i]!=x || strncmp((const char*)zIn+in.i, (const char*)pRe->zInit, pRe->nInit)!=0) |
︙ | ︙ | |||
624 625 626 627 628 629 630 | if( zIn[0]=='^' ){ zIn++; }else{ re_append(pRe, RE_OP_ANYSTAR, 0); } pRe->sIn.z = (unsigned char*)zIn; pRe->sIn.i = 0; | | | 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 | if( zIn[0]=='^' ){ zIn++; }else{ re_append(pRe, RE_OP_ANYSTAR, 0); } pRe->sIn.z = (unsigned char*)zIn; pRe->sIn.i = 0; pRe->sIn.mx = (int)strlen(zIn); zErr = re_subcompile_re(pRe); if( zErr ){ re_free(pRe); return zErr; } if( rePeek(pRe)=='$' && pRe->sIn.i+1>=pRe->sIn.mx ){ re_append(pRe, RE_OP_MATCH, RE_EOF); |
︙ | ︙ | |||
714 715 716 717 718 719 720 | zStr = (const unsigned char*)sqlite3_value_text(argv[1]); if( zStr!=0 ){ sqlite3_result_int(context, re_match(pRe, zStr, -1)); } } /* | | < < < < < < < < < < < < < < | | < | < < | < | | < | < < < < < < < < | < | < < < | | | < < | 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 | zStr = (const unsigned char*)sqlite3_value_text(argv[1]); if( zStr!=0 ){ sqlite3_result_int(context, re_match(pRe, zStr, -1)); } } /* ** Invoke this routine to register the regexp() function with the ** SQLite database connection. */ #ifdef _WIN32 __declspec(dllexport) #endif int sqlite3_regexp_init( sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi ){ int rc = SQLITE_OK; SQLITE_EXTENSION_INIT2(pApi); rc = sqlite3_create_function(db, "regexp", 2, SQLITE_UTF8, 0, re_sql_func, 0, 0); return rc; } |
Name change from src/test_spellfix.c to ext/misc/spellfix.c.
︙ | ︙ | |||
8 9 10 11 12 13 14 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** ** This module implements the spellfix1 VIRTUAL TABLE that can be used ** to search a large vocabulary for close matches. See separate | | < | > | > < < < > | 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 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** ** This module implements the spellfix1 VIRTUAL TABLE that can be used ** to search a large vocabulary for close matches. See separate ** documentation (http://www.sqlite.org/spellfix1.html) for details. */ #include "sqlite3ext.h" SQLITE_EXTENSION_INIT1 #ifndef SQLITE_AMALGAMATION # include <string.h> # include <stdio.h> # include <stdlib.h> # include <assert.h> # define ALWAYS(X) 1 # define NEVER(X) 0 typedef unsigned char u8; typedef unsigned short u16; #include <ctype.h> #endif /* ** Character classes for ASCII characters: ** ** 0 '' Silent letters: H W ** 1 'A' Any vowel: A E I O U (Y) ** 2 'B' A bilabeal stop or fricative: B F P V W |
︙ | ︙ | |||
2818 2819 2820 2821 2822 2823 2824 | for(i=0; i<sizeof(translit)/sizeof(translit[0])-1; i++){ assert( translit[i].cFrom<translit[i+1].cFrom ); } return rc; } | < < < < < < < < < < < > > > | < | 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 | for(i=0; i<sizeof(translit)/sizeof(translit[0])-1; i++){ assert( translit[i].cFrom<translit[i+1].cFrom ); } return rc; } /* ** Extension load function. */ #ifdef _WIN32 __declspec(dllexport) #endif int sqlite3_spellfix_init( sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi ){ SQLITE_EXTENSION_INIT2(pApi); return spellfix1Register(db); } |
Name change from src/test_wholenumber.c to ext/misc/wholenumber.c.
︙ | ︙ | |||
18 19 20 21 22 23 24 | ** CREATE VIRTUAL TABLE nums USING wholenumber; ** SELECT value FROM nums WHERE value<10; ** ** Results in: ** ** 1 2 3 4 5 6 7 8 9 */ | | > | 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | ** CREATE VIRTUAL TABLE nums USING wholenumber; ** SELECT value FROM nums WHERE value<10; ** ** Results in: ** ** 1 2 3 4 5 6 7 8 9 */ #include "sqlite3ext.h" SQLITE_EXTENSION_INIT1 #include <assert.h> #include <string.h> #ifndef SQLITE_OMIT_VIRTUALTABLE /* A wholenumber cursor object */ |
︙ | ︙ | |||
213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 | pIdxInfo->aConstraintUsage[gtIdx].omit = 1; } if( pIdxInfo->nOrderBy==1 && pIdxInfo->aOrderBy[0].desc==0 ){ pIdxInfo->orderByConsumed = 1; } pIdxInfo->estimatedCost = (double)1; return SQLITE_OK; } /* ** A virtual table module that provides read-only access to a ** Tcl global variable namespace. */ | > > > > > > | 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 | pIdxInfo->aConstraintUsage[gtIdx].omit = 1; } if( pIdxInfo->nOrderBy==1 && pIdxInfo->aOrderBy[0].desc==0 ){ pIdxInfo->orderByConsumed = 1; } if( (idxNum & 12)==0 ){ pIdxInfo->estimatedCost = (double)100000000; }else if( (idxNum & 3)==0 ){ pIdxInfo->estimatedCost = (double)5; }else{ pIdxInfo->estimatedCost = (double)1; } return SQLITE_OK; } /* ** A virtual table module that provides read-only access to a ** Tcl global variable namespace. */ |
︙ | ︙ | |||
246 247 248 249 250 251 252 | 0, /* xRollback */ 0, /* xFindMethod */ 0, /* xRename */ }; #endif /* SQLITE_OMIT_VIRTUALTABLE */ | | < > > | < | > > > > < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 | 0, /* xRollback */ 0, /* xFindMethod */ 0, /* xRename */ }; #endif /* SQLITE_OMIT_VIRTUALTABLE */ #ifdef _WIN32 __declspec(dllexport) #endif int sqlite3_wholenumber_init( sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi ){ int rc = SQLITE_OK; SQLITE_EXTENSION_INIT2(pApi); #ifndef SQLITE_OMIT_VIRTUALTABLE rc = sqlite3_create_module(db, "wholenumber", &wholenumberModule, 0); #endif return rc; } |
Changes to ext/rtree/rtree.c.
︙ | ︙ | |||
2661 2662 2663 2664 2665 2666 2667 | static int rtreeDeleteRowid(Rtree *pRtree, sqlite3_int64 iDelete){ int rc; /* Return code */ RtreeNode *pLeaf = 0; /* Leaf node containing record iDelete */ int iCell; /* Index of iDelete cell in pLeaf */ RtreeNode *pRoot; /* Root node of rtree structure */ | | | 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 | static int rtreeDeleteRowid(Rtree *pRtree, sqlite3_int64 iDelete){ int rc; /* Return code */ RtreeNode *pLeaf = 0; /* Leaf node containing record iDelete */ int iCell; /* Index of iDelete cell in pLeaf */ RtreeNode *pRoot; /* Root node of rtree structure */ /* Obtain a reference to the root node to initialize Rtree.iDepth */ rc = nodeAcquire(pRtree, 1, 0, &pRoot); /* Obtain a reference to the leaf node that contains the entry ** about to be deleted. */ if( rc==SQLITE_OK ){ rc = findLeafNode(pRtree, iDelete, &pLeaf); |
︙ | ︙ |
Changes to ext/rtree/rtree1.test.
︙ | ︙ | |||
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 [file join [file dirname [info script]] rtree_util.tcl] source $testdir/tester.tcl # Test plan: # # rtree-1.*: Creating/destroying r-tree tables. # rtree-2.*: Test the implicit constraints - unique rowid and # (coord[N]<=coord[N+1]) for even values of N. Also # automatic assigning of rowid values. | > | 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | # if {![info exists testdir]} { set testdir [file join [file dirname [info script]] .. .. test] } source [file join [file dirname [info script]] rtree_util.tcl] source $testdir/tester.tcl set testprefix rtree1 # Test plan: # # rtree-1.*: Creating/destroying r-tree tables. # rtree-2.*: Test the implicit constraints - unique rowid and # (coord[N]<=coord[N+1]) for even values of N. Also # automatic assigning of rowid values. |
︙ | ︙ |
Changes to ext/rtree/rtree5.test.
︙ | ︙ | |||
57 58 59 60 61 62 63 | do_test rtree5-1.9 { execsql { SELECT count(*) FROM t1 WHERE x1==5.0 } } {1} do_test rtree5-1.10 { execsql { SELECT (1<<31)-5, (1<<31)-1, -1*(1<<31), -1*(1<<31)+5 } } {2147483643 2147483647 -2147483648 -2147483643} | | | 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | do_test rtree5-1.9 { execsql { SELECT count(*) FROM t1 WHERE x1==5.0 } } {1} do_test rtree5-1.10 { execsql { SELECT (1<<31)-5, (1<<31)-1, -1*(1<<31), -1*(1<<31)+5 } } {2147483643 2147483647 -2147483648 -2147483643} do_test rtree5-1.11 { execsql { INSERT INTO t1 VALUES(2, (1<<31)-5, (1<<31)-1, -1*(1<<31), -1*(1<<31)+5) } } {} do_test rtree5-1.12 { execsql { SELECT * FROM t1 WHERE id=2 } } {2 2147483643 2147483647 -2147483648 -2147483643} |
︙ | ︙ |
Added magic.txt.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | # This file contains suggested magic(5) text for the unix file(1) # utility for recognizing SQLite3 databases. # # When SQLite is used as an application file format, it is desirable to # have file(1) recognize the database file as being with the specific # application. You can set the application_id for a database file # using: # # PRAGMA application_id = INTEGER; # # INTEGER can be any signed 32-bit integer. That integer is written as # a 4-byte big-endian integer into offset 68 of the database header. # # The Monotone application used "PRAGMA user_version=1598903374;" to set # its identifier long before "PRAGMA application_id" became available. # The user_version is very similar to application_id except that it is # stored at offset 68 instead of offset 60. The application_id pragma # is preferred. The rule using offset 60 for Monotone is for historical # compatibility only. # 0 string =SQLite\ format\ 3 >68 belong =0x0f055111 Fossil repository - >68 belong =0x0f055112 Fossil checkout - >68 belong =0x0f055113 Fossil global configuration - >68 belong =0x42654462 Bentley Systems BeSQLite Database - >68 belong =0x42654c6e Bentley Systems Localization File - >60 belong =0x5f4d544e Monotone source repository - >0 string =SQLite SQLite3 database |
Changes to main.mk.
︙ | ︙ | |||
51 52 53 54 55 56 57 58 59 60 61 62 63 64 | # Object files for the SQLite library. # LIBOBJ+= 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 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_unicode.o fts3_unicode2.o \ fts3_write.o func.o global.o hash.o \ icu.o insert.o journal.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 \ | > | 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | # Object files for the SQLite library. # LIBOBJ+= 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 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 func.o global.o hash.o \ icu.o insert.o journal.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 \ |
︙ | ︙ | |||
193 194 195 196 197 198 199 200 201 202 203 204 205 206 | $(TOP)/ext/fts3/fts3_hash.h \ $(TOP)/ext/fts3/fts3_icu.c \ $(TOP)/ext/fts3/fts3_porter.c \ $(TOP)/ext/fts3/fts3_snippet.c \ $(TOP)/ext/fts3/fts3_tokenizer.h \ $(TOP)/ext/fts3/fts3_tokenizer.c \ $(TOP)/ext/fts3/fts3_tokenizer1.c \ $(TOP)/ext/fts3/fts3_unicode.c \ $(TOP)/ext/fts3/fts3_unicode2.c \ $(TOP)/ext/fts3/fts3_write.c SRC += \ $(TOP)/ext/icu/sqliteicu.h \ $(TOP)/ext/icu/icu.c SRC += \ | > | 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 | $(TOP)/ext/fts3/fts3_hash.h \ $(TOP)/ext/fts3/fts3_icu.c \ $(TOP)/ext/fts3/fts3_porter.c \ $(TOP)/ext/fts3/fts3_snippet.c \ $(TOP)/ext/fts3/fts3_tokenizer.h \ $(TOP)/ext/fts3/fts3_tokenizer.c \ $(TOP)/ext/fts3/fts3_tokenizer1.c \ $(TOP)/ext/fts3/fts3_tokenize_vtab.c \ $(TOP)/ext/fts3/fts3_unicode.c \ $(TOP)/ext/fts3/fts3_unicode2.c \ $(TOP)/ext/fts3/fts3_write.c SRC += \ $(TOP)/ext/icu/sqliteicu.h \ $(TOP)/ext/icu/icu.c SRC += \ |
︙ | ︙ | |||
238 239 240 241 242 243 244 | $(TOP)/src/test_backup.c \ $(TOP)/src/test_btree.c \ $(TOP)/src/test_config.c \ $(TOP)/src/test_demovfs.c \ $(TOP)/src/test_devsym.c \ $(TOP)/src/test_fs.c \ $(TOP)/src/test_func.c \ | < < | | > > > > > > > > > > > > | 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 | $(TOP)/src/test_backup.c \ $(TOP)/src/test_btree.c \ $(TOP)/src/test_config.c \ $(TOP)/src/test_demovfs.c \ $(TOP)/src/test_devsym.c \ $(TOP)/src/test_fs.c \ $(TOP)/src/test_func.c \ $(TOP)/src/test_hexio.c \ $(TOP)/src/test_init.c \ $(TOP)/src/test_intarray.c \ $(TOP)/src/test_journal.c \ $(TOP)/src/test_malloc.c \ $(TOP)/src/test_multiplex.c \ $(TOP)/src/test_mutex.c \ $(TOP)/src/test_onefile.c \ $(TOP)/src/test_osinst.c \ $(TOP)/src/test_pcache.c \ $(TOP)/src/test_quota.c \ $(TOP)/src/test_rtree.c \ $(TOP)/src/test_schema.c \ $(TOP)/src/test_server.c \ $(TOP)/src/test_stat.c \ $(TOP)/src/test_sqllog.c \ $(TOP)/src/test_superlock.c \ $(TOP)/src/test_syscall.c \ $(TOP)/src/test_tclvar.c \ $(TOP)/src/test_thread.c \ $(TOP)/src/test_vfs.c \ $(TOP)/src/test_wsd.c # Extensions to be statically loaded. # TESTSRC += \ $(TOP)/ext/misc/amatch.c \ $(TOP)/ext/misc/closure.c \ $(TOP)/ext/misc/fuzzer.c \ $(TOP)/ext/misc/ieee754.c \ $(TOP)/ext/misc/nextchar.c \ $(TOP)/ext/misc/regexp.c \ $(TOP)/ext/misc/spellfix.c \ $(TOP)/ext/misc/wholenumber.c #TESTSRC += $(TOP)/ext/fts2/fts2_tokenizer.c #TESTSRC += $(TOP)/ext/fts3/fts3_tokenizer.c TESTSRC2 = \ $(TOP)/src/attach.c \ $(TOP)/src/backup.c \ |
︙ | ︙ | |||
361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 | $(RANLIB) libsqlite3.a sqlite3$(EXE): $(TOP)/src/shell.c libsqlite3.a sqlite3.h $(TCCX) $(READLINE_FLAGS) -o sqlite3$(EXE) \ $(TOP)/src/shell.c \ libsqlite3.a $(LIBREADLINE) $(TLIBS) $(THREADLIB) sqlite3.o: sqlite3.c $(TCCX) -c sqlite3.c # 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 rm -rf tsrc mkdir tsrc cp -f $(SRC) tsrc rm tsrc/sqlite.h.in tsrc/parse.y tclsh $(TOP)/tool/vdbe-compress.tcl <tsrc/vdbe.c >vdbe.new mv vdbe.new tsrc/vdbe.c touch target_source sqlite3.c: target_source $(TOP)/tool/mksqlite3c.tcl tclsh $(TOP)/tool/mksqlite3c.tcl 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 sqlite3.c-debug: target_source $(TOP)/tool/mksqlite3c.tcl tclsh $(TOP)/tool/mksqlite3c.tcl --linemacros | > > > > > | 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 | $(RANLIB) libsqlite3.a sqlite3$(EXE): $(TOP)/src/shell.c libsqlite3.a sqlite3.h $(TCCX) $(READLINE_FLAGS) -o sqlite3$(EXE) \ $(TOP)/src/shell.c \ libsqlite3.a $(LIBREADLINE) $(TLIBS) $(THREADLIB) mptester$(EXE): sqlite3.c $(TOP)/mptest/mptest.c $(TCCX) -o $@ -I. $(TOP)/mptest/mptest.c sqlite3.c \ $(TLIBS) $(THREADLIB) sqlite3.o: sqlite3.c $(TCCX) -c sqlite3.c # 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 rm -rf tsrc mkdir tsrc cp -f $(SRC) tsrc rm tsrc/sqlite.h.in tsrc/parse.y tclsh $(TOP)/tool/vdbe-compress.tcl <tsrc/vdbe.c >vdbe.new mv vdbe.new tsrc/vdbe.c 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 sqlite3.c-debug: target_source $(TOP)/tool/mksqlite3c.tcl tclsh $(TOP)/tool/mksqlite3c.tcl --linemacros |
︙ | ︙ | |||
506 507 508 509 510 511 512 513 514 515 516 517 518 519 | $(TCCX) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3_porter.c fts3_tokenizer.o: $(TOP)/ext/fts3/fts3_tokenizer.c $(HDR) $(EXTHDR) $(TCCX) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3_tokenizer.c fts3_tokenizer1.o: $(TOP)/ext/fts3/fts3_tokenizer1.c $(HDR) $(EXTHDR) $(TCCX) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3_tokenizer1.c fts3_unicode.o: $(TOP)/ext/fts3/fts3_unicode.c $(HDR) $(EXTHDR) $(TCCX) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3_unicode.c fts3_unicode2.o: $(TOP)/ext/fts3/fts3_unicode2.c $(HDR) $(EXTHDR) $(TCCX) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3_unicode2.c | > > > | 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 | $(TCCX) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3_porter.c fts3_tokenizer.o: $(TOP)/ext/fts3/fts3_tokenizer.c $(HDR) $(EXTHDR) $(TCCX) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3_tokenizer.c fts3_tokenizer1.o: $(TOP)/ext/fts3/fts3_tokenizer1.c $(HDR) $(EXTHDR) $(TCCX) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3_tokenizer1.c fts3_tokenize_vtab.o: $(TOP)/ext/fts3/fts3_tokenize_vtab.c $(HDR) $(EXTHDR) $(TCCX) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3_tokenize_vtab.c fts3_unicode.o: $(TOP)/ext/fts3/fts3_unicode.c $(HDR) $(EXTHDR) $(TCCX) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3_unicode.c fts3_unicode2.o: $(TOP)/ext/fts3/fts3_unicode2.c $(HDR) $(EXTHDR) $(TCCX) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3_unicode2.c |
︙ | ︙ | |||
617 618 619 620 621 622 623 624 625 | rm -rf tsrc target_source rm -f testloadext.dll libtestloadext.so rm -f amalgamation-testfixture amalgamation-testfixture.exe rm -f fts3-testfixture fts3-testfixture.exe rm -f testfixture testfixture.exe rm -f threadtest3 threadtest3.exe rm -f sqlite3.c fts?amal.c tclsqlite3.c rm -f sqlite3_analyzer sqlite3_analyzer.exe sqlite3_analyzer.c rm -f sqlite-*-output.vsix | > > > | 637 638 639 640 641 642 643 644 645 646 647 648 | rm -rf tsrc target_source rm -f testloadext.dll libtestloadext.so rm -f amalgamation-testfixture amalgamation-testfixture.exe rm -f fts3-testfixture fts3-testfixture.exe rm -f testfixture testfixture.exe rm -f threadtest3 threadtest3.exe rm -f sqlite3.c fts?amal.c tclsqlite3.c rm -f sqlite3rc.h rm -f shell.c sqlite3ext.h rm -f sqlite3_analyzer sqlite3_analyzer.exe sqlite3_analyzer.c rm -f sqlite-*-output.vsix rm -f mptester mptester.exe |
Added mptest/config01.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 | /* ** Configure five tasks in different ways, then run tests. */ --if vfsname() GLOB 'unix' PRAGMA page_size=8192; --task 1 PRAGMA journal_mode=PERSIST; PRAGMA mmap_size=0; --end --task 2 PRAGMA journal_mode=TRUNCATE; PRAGMA mmap_size=28672; --end --task 3 PRAGMA journal_mode=MEMORY; --end --task 4 PRAGMA journal_mode=OFF; --end --task 4 PRAGMA mmap_size(268435456); --end --source multiwrite01.test --wait all PRAGMA page_size=16384; VACUUM; CREATE TABLE pgsz(taskid, sz INTEGER); --task 1 INSERT INTO pgsz VALUES(1, eval('PRAGMA page_size')); --end --task 2 INSERT INTO pgsz VALUES(2, eval('PRAGMA page_size')); --end --task 3 INSERT INTO pgsz VALUES(3, eval('PRAGMA page_size')); --end --task 4 INSERT INTO pgsz VALUES(4, eval('PRAGMA page_size')); --end --task 5 INSERT INTO pgsz VALUES(5, eval('PRAGMA page_size')); --end --source multiwrite01.test --wait all SELECT sz FROM pgsz; --match 16384 16384 16384 16384 16384 |
Added mptest/config02.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 | /* ** Configure five tasks in different ways, then run tests. */ PRAGMA page_size=512; --task 1 PRAGMA mmap_size=0; --end --task 2 PRAGMA mmap_size=28672; --end --task 3 PRAGMA mmap_size=8192; --end --task 4 PRAGMA mmap_size=65536; --end --task 5 PRAGMA mmap_size=268435456; --end --source multiwrite01.test --source crash02.subtest PRAGMA page_size=1024; VACUUM; CREATE TABLE pgsz(taskid, sz INTEGER); --task 1 INSERT INTO pgsz VALUES(1, eval('PRAGMA page_size')); --end --task 2 INSERT INTO pgsz VALUES(2, eval('PRAGMA page_size')); --end --task 3 INSERT INTO pgsz VALUES(3, eval('PRAGMA page_size')); --end --task 4 INSERT INTO pgsz VALUES(4, eval('PRAGMA page_size')); --end --task 5 INSERT INTO pgsz VALUES(5, eval('PRAGMA page_size')); --end --source multiwrite01.test --source crash02.subtest --wait all SELECT sz FROM pgsz; --match 1024 1024 1024 1024 1024 PRAGMA page_size=2048; VACUUM; DELETE FROM pgsz; --task 1 INSERT INTO pgsz VALUES(1, eval('PRAGMA page_size')); --end --task 2 INSERT INTO pgsz VALUES(2, eval('PRAGMA page_size')); --end --task 3 INSERT INTO pgsz VALUES(3, eval('PRAGMA page_size')); --end --task 4 INSERT INTO pgsz VALUES(4, eval('PRAGMA page_size')); --end --task 5 INSERT INTO pgsz VALUES(5, eval('PRAGMA page_size')); --end --source multiwrite01.test --source crash02.subtest --wait all SELECT sz FROM pgsz; --match 2048 2048 2048 2048 2048 PRAGMA page_size=8192; VACUUM; DELETE FROM pgsz; --task 1 INSERT INTO pgsz VALUES(1, eval('PRAGMA page_size')); --end --task 2 INSERT INTO pgsz VALUES(2, eval('PRAGMA page_size')); --end --task 3 INSERT INTO pgsz VALUES(3, eval('PRAGMA page_size')); --end --task 4 INSERT INTO pgsz VALUES(4, eval('PRAGMA page_size')); --end --task 5 INSERT INTO pgsz VALUES(5, eval('PRAGMA page_size')); --end --source multiwrite01.test --source crash02.subtest --wait all SELECT sz FROM pgsz; --match 8192 8192 8192 8192 8192 PRAGMA page_size=16384; VACUUM; DELETE FROM pgsz; --task 1 INSERT INTO pgsz VALUES(1, eval('PRAGMA page_size')); --end --task 2 INSERT INTO pgsz VALUES(2, eval('PRAGMA page_size')); --end --task 3 INSERT INTO pgsz VALUES(3, eval('PRAGMA page_size')); --end --task 4 INSERT INTO pgsz VALUES(4, eval('PRAGMA page_size')); --end --task 5 INSERT INTO pgsz VALUES(5, eval('PRAGMA page_size')); --end --source multiwrite01.test --source crash02.subtest --wait all SELECT sz FROM pgsz; --match 16384 16384 16384 16384 16384 PRAGMA auto_vacuum=FULL; VACUUM; --source multiwrite01.test --source crash02.subtest --wait all PRAGMA auto_vacuum=FULL; PRAGMA page_size=512; VACUUM; --source multiwrite01.test --source crash02.subtest |
Added mptest/crash01.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 | /* Test cases involving incomplete transactions that must be rolled back. */ --task 1 DROP TABLE IF EXISTS t1; CREATE TABLE t1(a INTEGER PRIMARY KEY, b); --sleep 1 INSERT INTO t1 VALUES(1, randomblob(2000)); INSERT INTO t1 VALUES(2, randomblob(1000)); --sleep 1 INSERT INTO t1 SELECT a+2, randomblob(1500) FROM t1; INSERT INTO t1 SELECT a+4, randomblob(1500) FROM t1; INSERT INTO t1 SELECT a+8, randomblob(1500) FROM t1; --sleep 1 INSERT INTO t1 SELECT a+16, randomblob(1500) FROM t1; --sleep 1 INSERT INTO t1 SELECT a+32, randomblob(1500) FROM t1; SELECT count(*) FROM t1; --match 64 SELECT avg(length(b)) FROM t1; --match 1500.0 --sleep 2 UPDATE t1 SET b='x'||a||'y'; SELECT total(length(b)) FROM t1; --match 247 SELECT a FROM t1 WHERE b='x17y'; --match 17 CREATE INDEX t1b ON t1(b); SELECT a FROM t1 WHERE b='x17y'; --match 17 SELECT a FROM t1 WHERE b GLOB 'x2?y' ORDER BY b DESC LIMIT 5; --match 29 28 27 26 25 --end --wait 1 --task 2 CREATE TABLE t2(a INTEGER PRIMARY KEY, b); INSERT INTO t2 SELECT a, b FROM t1; UPDATE t1 SET b='x'||a||'y'; SELECT total(length(b)) FROM t2; --match 247 SELECT a FROM t2 WHERE b='x17y'; --match 17 CREATE INDEX t2b ON t2(b); SELECT a FROM t2 WHERE b='x17y'; --match 17 SELECT a FROM t2 WHERE b GLOB 'x2?y' ORDER BY b DESC LIMIT 5; --match 29 28 27 26 25 --end --task 3 CREATE TABLE t3(a INTEGER PRIMARY KEY, b); INSERT INTO t3 SELECT a, b FROM t1; UPDATE t1 SET b='x'||a||'y'; SELECT total(length(b)) FROM t3; --match 247 SELECT a FROM t3 WHERE b='x17y'; --match 17 CREATE INDEX t3b ON t3(b); SELECT a FROM t3 WHERE b='x17y'; --match 17 SELECT a FROM t3 WHERE b GLOB 'x2?y' ORDER BY b DESC LIMIT 5; --match 29 28 27 26 25 --end --task 4 CREATE TABLE t4(a INTEGER PRIMARY KEY, b); INSERT INTO t4 SELECT a, b FROM t1; UPDATE t1 SET b='x'||a||'y'; SELECT total(length(b)) FROM t4; --match 247 SELECT a FROM t4 WHERE b='x17y'; --match 17 CREATE INDEX t4b ON t4(b); SELECT a FROM t4 WHERE b='x17y'; --match 17 SELECT a FROM t4 WHERE b GLOB 'x2?y' ORDER BY b DESC LIMIT 5; --match 29 28 27 26 25 --end --task 5 CREATE TABLE t5(a INTEGER PRIMARY KEY, b); INSERT INTO t5 SELECT a, b FROM t1; UPDATE t1 SET b='x'||a||'y'; SELECT total(length(b)) FROM t5; --match 247 SELECT a FROM t5 WHERE b='x17y'; --match 17 CREATE INDEX t5b ON t5(b); SELECT a FROM t5 WHERE b='x17y'; --match 17 SELECT a FROM t5 WHERE b GLOB 'x2?y' ORDER BY b DESC LIMIT 5; --match 29 28 27 26 25 --end --wait all /* After the database file has been set up, run the crash2 subscript ** multiple times. */ --source crash02.subtest --source crash02.subtest --source crash02.subtest --source crash02.subtest --source crash02.subtest --source crash02.subtest --source crash02.subtest --source crash02.subtest --source crash02.subtest |
Added mptest/crash02.subtest.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* ** This script is called from crash01.test and config02.test and perhaps other ** script. After the database file has been set up, make a big rollback ** journal in client 1, then crash client 1. ** Then in the other clients, do an integrity check. */ --task 1 leave-hot-journal --sleep 5 --finish PRAGMA cache_size=10; BEGIN; UPDATE t1 SET b=randomblob(20000); UPDATE t2 SET b=randomblob(20000); UPDATE t3 SET b=randomblob(20000); UPDATE t4 SET b=randomblob(20000); UPDATE t5 SET b=randomblob(20000); UPDATE t1 SET b=NULL; UPDATE t2 SET b=NULL; UPDATE t3 SET b=NULL; UPDATE t4 SET b=NULL; UPDATE t5 SET b=NULL; --print Task one crashing an incomplete transaction --exit 1 --end --task 2 integrity_check-2 SELECT count(*) FROM t1; --match 64 --sleep 100 PRAGMA integrity_check(10); --match ok --end --task 3 integrity_check-3 SELECT count(*) FROM t1; --match 64 --sleep 100 PRAGMA integrity_check(10); --match ok --end --task 4 integrity_check-4 SELECT count(*) FROM t1; --match 64 --sleep 100 PRAGMA integrity_check(10); --match ok --end --task 5 integrity_check-5 SELECT count(*) FROM t1; --match 64 --sleep 100 PRAGMA integrity_check(10); --match ok --end --wait all |
Added mptest/mptest.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 | /* ** 2013-04-05 ** ** 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 is a program used for testing SQLite, and specifically for testing ** the ability of independent processes to access the same SQLite database ** concurrently. ** ** Compile this program as follows: ** ** gcc -g -c -Wall sqlite3.c $(OPTS) ** gcc -g -o mptest mptest.c sqlite3.o $(LIBS) ** ** Recommended options: ** ** -DHAVE_USLEEP ** -DSQLITE_NO_SYNC ** -DSQLITE_THREADSAFE=0 ** -DSQLITE_OMIT_LOAD_EXTENSION ** ** Run like this: ** ** ./mptest $database $script ** ** where $database is the database to use for testing and $script is a ** test script. */ #include "sqlite3.h" #include <stdio.h> #if defined(_WIN32) # define WIN32_LEAN_AND_MEAN # include <windows.h> #else # include <unistd.h> #endif #include <stdlib.h> #include <string.h> #include <assert.h> #include <ctype.h> /* The suffix to append to the child command lines, if any */ #if defined(_WIN32) # define GETPID (int)GetCurrentProcessId #else # define GETPID getpid #endif /* Mark a parameter as unused to suppress compiler warnings */ #define UNUSED_PARAMETER(x) (void)x /* Global data */ static struct Global { char *argv0; /* Name of the executable */ const char *zVfs; /* Name of VFS to use. Often NULL meaning "default" */ char *zDbFile; /* Name of the database */ sqlite3 *db; /* Open connection to database */ char *zErrLog; /* Filename for error log */ FILE *pErrLog; /* Where to write errors */ char *zLog; /* Name of output log file */ FILE *pLog; /* Where to write log messages */ char zName[32]; /* Symbolic name of this process */ int taskId; /* Task ID. 0 means supervisor. */ int iTrace; /* Tracing level */ int bSqlTrace; /* True to trace SQL commands */ int bIgnoreSqlErrors; /* Ignore errors in SQL statements */ int nError; /* Number of errors */ int nTest; /* Number of --match operators */ int iTimeout; /* Milliseconds until a busy timeout */ int bSync; /* Call fsync() */ } g; /* Default timeout */ #define DEFAULT_TIMEOUT 10000 /* ** Print a message adding zPrefix[] to the beginning of every line. */ static void printWithPrefix(FILE *pOut, const char *zPrefix, const char *zMsg){ while( zMsg && zMsg[0] ){ int i; for(i=0; zMsg[i] && zMsg[i]!='\n' && zMsg[i]!='\r'; i++){} fprintf(pOut, "%s%.*s\n", zPrefix, i, zMsg); zMsg += i; while( zMsg[0]=='\n' || zMsg[0]=='\r' ) zMsg++; } } /* ** Compare two pointers to strings, where the pointers might be NULL. */ static int safe_strcmp(const char *a, const char *b){ if( a==b ) return 0; if( a==0 ) return -1; if( b==0 ) return 1; return strcmp(a,b); } /* ** Return TRUE if string z[] matches glob pattern zGlob[]. ** Return FALSE if the pattern does not match. ** ** Globbing rules: ** ** '*' Matches any sequence of zero or more characters. ** ** '?' Matches exactly one character. ** ** [...] Matches one character from the enclosed list of ** characters. ** ** [^...] Matches one character not in the enclosed list. ** ** '#' Matches any sequence of one or more digits with an ** optional + or - sign in front */ int strglob(const char *zGlob, const char *z){ int c, c2; int invert; int seen; while( (c = (*(zGlob++)))!=0 ){ if( c=='*' ){ while( (c=(*(zGlob++))) == '*' || c=='?' ){ if( c=='?' && (*(z++))==0 ) return 0; } if( c==0 ){ return 1; }else if( c=='[' ){ while( *z && strglob(zGlob-1,z) ){ z++; } return (*z)!=0; } while( (c2 = (*(z++)))!=0 ){ while( c2!=c ){ c2 = *(z++); if( c2==0 ) return 0; } if( strglob(zGlob,z) ) return 1; } return 0; }else if( c=='?' ){ if( (*(z++))==0 ) return 0; }else if( c=='[' ){ int prior_c = 0; seen = 0; invert = 0; c = *(z++); if( c==0 ) return 0; c2 = *(zGlob++); if( c2=='^' ){ invert = 1; c2 = *(zGlob++); } if( c2==']' ){ if( c==']' ) seen = 1; c2 = *(zGlob++); } while( c2 && c2!=']' ){ if( c2=='-' && zGlob[0]!=']' && zGlob[0]!=0 && prior_c>0 ){ c2 = *(zGlob++); if( c>=prior_c && c<=c2 ) seen = 1; prior_c = 0; }else{ if( c==c2 ){ seen = 1; } prior_c = c2; } c2 = *(zGlob++); } if( c2==0 || (seen ^ invert)==0 ) return 0; }else if( c=='#' ){ if( (z[0]=='-' || z[0]=='+') && isdigit(z[1]) ) z++; if( !isdigit(z[0]) ) return 0; z++; while( isdigit(z[0]) ){ z++; } }else{ if( c!=(*(z++)) ) return 0; } } return *z==0; } /* ** Close output stream pOut if it is not stdout or stderr */ static void maybeClose(FILE *pOut){ if( pOut!=stdout && pOut!=stderr ) fclose(pOut); } /* ** Print an error message */ static void errorMessage(const char *zFormat, ...){ va_list ap; char *zMsg; char zPrefix[30]; va_start(ap, zFormat); zMsg = sqlite3_vmprintf(zFormat, ap); va_end(ap); sqlite3_snprintf(sizeof(zPrefix), zPrefix, "%s:ERROR: ", g.zName); if( g.pLog ){ printWithPrefix(g.pLog, zPrefix, zMsg); fflush(g.pLog); } if( g.pErrLog && safe_strcmp(g.zErrLog,g.zLog) ){ printWithPrefix(g.pErrLog, zPrefix, zMsg); fflush(g.pErrLog); } sqlite3_free(zMsg); g.nError++; } /* Forward declaration */ static int trySql(const char*, ...); /* ** Print an error message and then quit. */ static void fatalError(const char *zFormat, ...){ va_list ap; char *zMsg; char zPrefix[30]; va_start(ap, zFormat); zMsg = sqlite3_vmprintf(zFormat, ap); va_end(ap); sqlite3_snprintf(sizeof(zPrefix), zPrefix, "%s:FATAL: ", g.zName); if( g.pLog ){ printWithPrefix(g.pLog, zPrefix, zMsg); fflush(g.pLog); maybeClose(g.pLog); } if( g.pErrLog && safe_strcmp(g.zErrLog,g.zLog) ){ printWithPrefix(g.pErrLog, zPrefix, zMsg); fflush(g.pErrLog); maybeClose(g.pErrLog); } sqlite3_free(zMsg); if( g.db ){ int nTry = 0; g.iTimeout = 0; while( trySql("UPDATE client SET wantHalt=1;")==SQLITE_BUSY && (nTry++)<100 ){ sqlite3_sleep(10); } } sqlite3_close(g.db); exit(1); } /* ** Print a log message */ static void logMessage(const char *zFormat, ...){ va_list ap; char *zMsg; char zPrefix[30]; va_start(ap, zFormat); zMsg = sqlite3_vmprintf(zFormat, ap); va_end(ap); sqlite3_snprintf(sizeof(zPrefix), zPrefix, "%s: ", g.zName); if( g.pLog ){ printWithPrefix(g.pLog, zPrefix, zMsg); fflush(g.pLog); } sqlite3_free(zMsg); } /* ** Return the length of a string omitting trailing whitespace */ static int clipLength(const char *z){ int n = (int)strlen(z); while( n>0 && isspace(z[n-1]) ){ n--; } return n; } /* ** Auxiliary SQL function to return the name of the VFS */ static void vfsNameFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ sqlite3 *db = sqlite3_context_db_handle(context); char *zVfs = 0; UNUSED_PARAMETER(argc); UNUSED_PARAMETER(argv); sqlite3_file_control(db, "main", SQLITE_FCNTL_VFSNAME, &zVfs); if( zVfs ){ sqlite3_result_text(context, zVfs, -1, sqlite3_free); } } /* ** Busy handler with a g.iTimeout-millisecond timeout */ static int busyHandler(void *pCD, int count){ UNUSED_PARAMETER(pCD); if( count*10>g.iTimeout ){ if( g.iTimeout>0 ) errorMessage("timeout after %dms", g.iTimeout); return 0; } sqlite3_sleep(10); return 1; } /* ** SQL Trace callback */ static void sqlTraceCallback(void *NotUsed1, const char *zSql){ UNUSED_PARAMETER(NotUsed1); logMessage("[%.*s]", clipLength(zSql), zSql); } /* ** SQL error log callback */ static void sqlErrorCallback(void *pArg, int iErrCode, const char *zMsg){ UNUSED_PARAMETER(pArg); if( iErrCode==SQLITE_ERROR && g.bIgnoreSqlErrors ) return; if( (iErrCode&0xff)==SQLITE_SCHEMA && g.iTrace<3 ) return; if( g.iTimeout==0 && (iErrCode&0xff)==SQLITE_BUSY && g.iTrace<3 ) return; if( (iErrCode&0xff)==SQLITE_NOTICE ){ logMessage("(info) %s", zMsg); }else{ errorMessage("(errcode=%d) %s", iErrCode, zMsg); } } /* ** Prepare an SQL statement. Issue a fatal error if unable. */ static sqlite3_stmt *prepareSql(const char *zFormat, ...){ va_list ap; char *zSql; int rc; sqlite3_stmt *pStmt = 0; va_start(ap, zFormat); zSql = sqlite3_vmprintf(zFormat, ap); va_end(ap); rc = sqlite3_prepare_v2(g.db, zSql, -1, &pStmt, 0); if( rc!=SQLITE_OK ){ sqlite3_finalize(pStmt); fatalError("%s\n%s\n", sqlite3_errmsg(g.db), zSql); } sqlite3_free(zSql); return pStmt; } /* ** Run arbitrary SQL. Issue a fatal error on failure. */ static void runSql(const char *zFormat, ...){ va_list ap; char *zSql; int rc; va_start(ap, zFormat); zSql = sqlite3_vmprintf(zFormat, ap); va_end(ap); rc = sqlite3_exec(g.db, zSql, 0, 0, 0); if( rc!=SQLITE_OK ){ fatalError("%s\n%s\n", sqlite3_errmsg(g.db), zSql); } sqlite3_free(zSql); } /* ** Try to run arbitrary SQL. Return success code. */ static int trySql(const char *zFormat, ...){ va_list ap; char *zSql; int rc; va_start(ap, zFormat); zSql = sqlite3_vmprintf(zFormat, ap); va_end(ap); rc = sqlite3_exec(g.db, zSql, 0, 0, 0); sqlite3_free(zSql); return rc; } /* Structure for holding an arbitrary length string */ typedef struct String String; struct String { char *z; /* the string */ int n; /* Slots of z[] used */ int nAlloc; /* Slots of z[] allocated */ }; /* Free a string */ static void stringFree(String *p){ if( p->z ) sqlite3_free(p->z); memset(p, 0, sizeof(*p)); } /* Append n bytes of text to a string. If n<0 append the entire string. */ static void stringAppend(String *p, const char *z, int n){ if( n<0 ) n = (int)strlen(z); if( p->n+n>=p->nAlloc ){ int nAlloc = p->nAlloc*2 + n + 100; char *z = sqlite3_realloc(p->z, nAlloc); if( z==0 ) fatalError("out of memory"); p->z = z; p->nAlloc = nAlloc; } memcpy(p->z+p->n, z, n); p->n += n; p->z[p->n] = 0; } /* Reset a string to an empty string */ static void stringReset(String *p){ if( p->z==0 ) stringAppend(p, " ", 1); p->n = 0; p->z[0] = 0; } /* Append a new token onto the end of the string */ static void stringAppendTerm(String *p, const char *z){ int i; if( p->n ) stringAppend(p, " ", 1); if( z==0 ){ stringAppend(p, "nil", 3); return; } for(i=0; z[i] && !isspace(z[i]); i++){} if( i>0 && z[i]==0 ){ stringAppend(p, z, i); return; } stringAppend(p, "'", 1); while( z[0] ){ for(i=0; z[i] && z[i]!='\''; i++){} if( z[i] ){ stringAppend(p, z, i+1); stringAppend(p, "'", 1); z += i+1; }else{ stringAppend(p, z, i); break; } } stringAppend(p, "'", 1); } /* ** Callback function for evalSql() */ static int evalCallback(void *pCData, int argc, char **argv, char **azCol){ String *p = (String*)pCData; int i; UNUSED_PARAMETER(azCol); for(i=0; i<argc; i++) stringAppendTerm(p, argv[i]); return 0; } /* ** Run arbitrary SQL and record the results in an output string ** given by the first parameter. */ static int evalSql(String *p, const char *zFormat, ...){ va_list ap; char *zSql; int rc; char *zErrMsg = 0; va_start(ap, zFormat); zSql = sqlite3_vmprintf(zFormat, ap); va_end(ap); assert( g.iTimeout>0 ); rc = sqlite3_exec(g.db, zSql, evalCallback, p, &zErrMsg); sqlite3_free(zSql); if( rc ){ char zErr[30]; sqlite3_snprintf(sizeof(zErr), zErr, "error(%d)", rc); stringAppendTerm(p, zErr); if( zErrMsg ){ stringAppendTerm(p, zErrMsg); sqlite3_free(zErrMsg); } } return rc; } /* ** Auxiliary SQL function to recursively evaluate SQL. */ static void evalFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ sqlite3 *db = sqlite3_context_db_handle(context); const char *zSql = (const char*)sqlite3_value_text(argv[0]); String res; char *zErrMsg = 0; int rc; UNUSED_PARAMETER(argc); memset(&res, 0, sizeof(res)); rc = sqlite3_exec(db, zSql, evalCallback, &res, &zErrMsg); if( zErrMsg ){ sqlite3_result_error(context, zErrMsg, -1); sqlite3_free(zErrMsg); }else if( rc ){ sqlite3_result_error_code(context, rc); }else{ sqlite3_result_text(context, res.z, -1, SQLITE_TRANSIENT); } stringFree(&res); } /* ** Look up the next task for client iClient in the database. ** Return the task script and the task number and mark that ** task as being under way. */ static int startScript( int iClient, /* The client number */ char **pzScript, /* Write task script here */ int *pTaskId, /* Write task number here */ char **pzTaskName /* Name of the task */ ){ sqlite3_stmt *pStmt = 0; int taskId; int rc; int totalTime = 0; *pzScript = 0; g.iTimeout = 0; while(1){ rc = trySql("BEGIN IMMEDIATE"); if( rc==SQLITE_BUSY ){ sqlite3_sleep(10); totalTime += 10; continue; } if( rc!=SQLITE_OK ){ fatalError("in startScript: %s", sqlite3_errmsg(g.db)); } if( g.nError || g.nTest ){ runSql("UPDATE counters SET nError=nError+%d, nTest=nTest+%d", g.nError, g.nTest); g.nError = 0; g.nTest = 0; } pStmt = prepareSql("SELECT 1 FROM client WHERE id=%d AND wantHalt",iClient); rc = sqlite3_step(pStmt); sqlite3_finalize(pStmt); if( rc==SQLITE_ROW ){ runSql("DELETE FROM client WHERE id=%d", iClient); g.iTimeout = DEFAULT_TIMEOUT; runSql("COMMIT TRANSACTION;"); return SQLITE_DONE; } pStmt = prepareSql( "SELECT script, id, name FROM task" " WHERE client=%d AND starttime IS NULL" " ORDER BY id LIMIT 1", iClient); rc = sqlite3_step(pStmt); if( rc==SQLITE_ROW ){ int n = sqlite3_column_bytes(pStmt, 0); *pzScript = sqlite3_malloc(n+1); strcpy(*pzScript, (const char*)sqlite3_column_text(pStmt, 0)); *pTaskId = taskId = sqlite3_column_int(pStmt, 1); *pzTaskName = sqlite3_mprintf("%s", sqlite3_column_text(pStmt, 2)); sqlite3_finalize(pStmt); runSql("UPDATE task" " SET starttime=strftime('%%Y-%%m-%%d %%H:%%M:%%f','now')" " WHERE id=%d;", taskId); g.iTimeout = DEFAULT_TIMEOUT; runSql("COMMIT TRANSACTION;"); return SQLITE_OK; } sqlite3_finalize(pStmt); if( rc==SQLITE_DONE ){ if( totalTime>30000 ){ errorMessage("Waited over 30 seconds with no work. Giving up."); runSql("DELETE FROM client WHERE id=%d; COMMIT;", iClient); sqlite3_close(g.db); exit(1); } while( trySql("COMMIT")==SQLITE_BUSY ){ sqlite3_sleep(10); totalTime += 10; } sqlite3_sleep(100); totalTime += 100; continue; } fatalError("%s", sqlite3_errmsg(g.db)); } g.iTimeout = DEFAULT_TIMEOUT; } /* ** Mark a script as having finished. Remove the CLIENT table entry ** if bShutdown is true. */ static int finishScript(int iClient, int taskId, int bShutdown){ runSql("UPDATE task" " SET endtime=strftime('%%Y-%%m-%%d %%H:%%M:%%f','now')" " WHERE id=%d;", taskId); if( bShutdown ){ runSql("DELETE FROM client WHERE id=%d", iClient); } return SQLITE_OK; } /* ** Start up a client process for iClient, if it is not already ** running. If the client is already running, then this routine ** is a no-op. */ static void startClient(int iClient){ runSql("INSERT OR IGNORE INTO client VALUES(%d,0)", iClient); if( sqlite3_changes(g.db) ){ char *zSys; int rc; zSys = sqlite3_mprintf("%s \"%s\" --client %d --trace %d", g.argv0, g.zDbFile, iClient, g.iTrace); if( g.bSqlTrace ){ zSys = sqlite3_mprintf("%z --sqltrace", zSys); } if( g.bSync ){ zSys = sqlite3_mprintf("%z --sync", zSys); } if( g.zVfs ){ zSys = sqlite3_mprintf("%z --vfs \"%s\"", zSys, g.zVfs); } if( g.iTrace>=2 ) logMessage("system('%q')", zSys); #if !defined(_WIN32) zSys = sqlite3_mprintf("%z &", zSys); rc = system(zSys); if( rc ) errorMessage("system() fails with error code %d", rc); #else { STARTUPINFOA startupInfo; PROCESS_INFORMATION processInfo; memset(&startupInfo, 0, sizeof(startupInfo)); startupInfo.cb = sizeof(startupInfo); memset(&processInfo, 0, sizeof(processInfo)); rc = CreateProcessA(NULL, zSys, NULL, NULL, FALSE, 0, NULL, NULL, &startupInfo, &processInfo); if( rc ){ CloseHandle(processInfo.hThread); CloseHandle(processInfo.hProcess); }else{ errorMessage("CreateProcessA() fails with error code %lu", GetLastError()); } } #endif sqlite3_free(zSys); } } /* ** Read the entire content of a file into memory */ static char *readFile(const char *zFilename){ FILE *in = fopen(zFilename, "rb"); long sz; char *z; if( in==0 ){ fatalError("cannot open \"%s\" for reading", zFilename); } fseek(in, 0, SEEK_END); sz = ftell(in); rewind(in); z = sqlite3_malloc( sz+1 ); sz = (long)fread(z, 1, sz, in); z[sz] = 0; fclose(in); return z; } /* ** Return the length of the next token. */ static int tokenLength(const char *z, int *pnLine){ int n = 0; if( isspace(z[0]) || (z[0]=='/' && z[1]=='*') ){ int inC = 0; int c; if( z[0]=='/' ){ inC = 1; n = 2; } while( (c = z[n++])!=0 ){ if( c=='\n' ) (*pnLine)++; if( isspace(c) ) continue; if( inC && c=='*' && z[n]=='/' ){ n++; inC = 0; }else if( !inC && c=='/' && z[n]=='*' ){ n++; inC = 1; }else if( !inC ){ break; } } n--; }else if( z[0]=='-' && z[1]=='-' ){ for(n=2; z[n] && z[n]!='\n'; n++){} if( z[n] ){ (*pnLine)++; n++; } }else if( z[0]=='"' || z[0]=='\'' ){ int delim = z[0]; for(n=1; z[n]; n++){ if( z[n]=='\n' ) (*pnLine)++; if( z[n]==delim ){ n++; if( z[n+1]!=delim ) break; } } }else{ int c; for(n=1; (c = z[n])!=0 && !isspace(c) && c!='"' && c!='\'' && c!=';'; n++){} } return n; } /* ** Copy a single token into a string buffer. */ static int extractToken(const char *zIn, int nIn, char *zOut, int nOut){ int i; if( nIn<=0 ){ zOut[0] = 0; return 0; } for(i=0; i<nIn && i<nOut-1 && !isspace(zIn[i]); i++){ zOut[i] = zIn[i]; } zOut[i] = 0; return i; } /* ** Find the number of characters up to the start of the next "--end" token. */ static int findEnd(const char *z, int *pnLine){ int n = 0; while( z[n] && (strncmp(z+n,"--end",5) || !isspace(z[n+5])) ){ n += tokenLength(z+n, pnLine); } return n; } /* ** Find the number of characters up to the first character past the ** of the next "--endif" or "--else" token. Nested --if commands are ** also skipped. */ static int findEndif(const char *z, int stopAtElse, int *pnLine){ int n = 0; while( z[n] ){ int len = tokenLength(z+n, pnLine); if( (strncmp(z+n,"--endif",7)==0 && isspace(z[n+7])) || (stopAtElse && strncmp(z+n,"--else",6)==0 && isspace(z[n+6])) ){ return n+len; } if( strncmp(z+n,"--if",4)==0 && isspace(z[n+4]) ){ int skip = findEndif(z+n+len, 0, pnLine); n += skip + len; }else{ n += len; } } return n; } /* ** Wait for a client process to complete all its tasks */ static void waitForClient(int iClient, int iTimeout, char *zErrPrefix){ sqlite3_stmt *pStmt; int rc; if( iClient>0 ){ pStmt = prepareSql( "SELECT 1 FROM task" " WHERE client=%d" " AND client IN (SELECT id FROM client)" " AND endtime IS NULL", iClient); }else{ pStmt = prepareSql( "SELECT 1 FROM task" " WHERE client IN (SELECT id FROM client)" " AND endtime IS NULL"); } g.iTimeout = 0; while( ((rc = sqlite3_step(pStmt))==SQLITE_BUSY || rc==SQLITE_ROW) && iTimeout>0 ){ sqlite3_reset(pStmt); sqlite3_sleep(50); iTimeout -= 50; } sqlite3_finalize(pStmt); g.iTimeout = DEFAULT_TIMEOUT; if( rc!=SQLITE_DONE ){ if( zErrPrefix==0 ) zErrPrefix = ""; if( iClient>0 ){ errorMessage("%stimeout waiting for client %d", zErrPrefix, iClient); }else{ errorMessage("%stimeout waiting for all clients", zErrPrefix); } } } /* Return a pointer to the tail of a filename */ static char *filenameTail(char *z){ int i, j; for(i=j=0; z[i]; i++) if( z[i]=='/' ) j = i+1; return z+j; } /* ** Interpret zArg as a boolean value. Return either 0 or 1. */ static int booleanValue(char *zArg){ int i; if( zArg==0 ) return 0; for(i=0; zArg[i]>='0' && zArg[i]<='9'; i++){} if( i>0 && zArg[i]==0 ) return atoi(zArg); if( sqlite3_stricmp(zArg, "on")==0 || sqlite3_stricmp(zArg,"yes")==0 ){ return 1; } if( sqlite3_stricmp(zArg, "off")==0 || sqlite3_stricmp(zArg,"no")==0 ){ return 0; } errorMessage("unknown boolean: [%s]", zArg); return 0; } /* This routine exists as a convenient place to set a debugger ** breakpoint. */ static void test_breakpoint(void){ static volatile int cnt = 0; cnt++; } /* Maximum number of arguments to a --command */ #define MX_ARG 2 /* ** Run a script. */ static void runScript( int iClient, /* The client number, or 0 for the master */ int taskId, /* The task ID for clients. 0 for master */ char *zScript, /* Text of the script */ char *zFilename /* File from which script was read. */ ){ int lineno = 1; int prevLine = 1; int ii = 0; int iBegin = 0; int n, c, j; int len; int nArg; String sResult; char zCmd[30]; char zError[1000]; char azArg[MX_ARG][100]; memset(&sResult, 0, sizeof(sResult)); stringReset(&sResult); while( (c = zScript[ii])!=0 ){ prevLine = lineno; len = tokenLength(zScript+ii, &lineno); if( isspace(c) || (c=='/' && zScript[ii+1]=='*') ){ ii += len; continue; } if( c!='-' || zScript[ii+1]!='-' || !isalpha(zScript[ii+2]) ){ ii += len; continue; } /* Run any prior SQL before processing the new --command */ if( ii>iBegin ){ char *zSql = sqlite3_mprintf("%.*s", ii-iBegin, zScript+iBegin); evalSql(&sResult, zSql); sqlite3_free(zSql); iBegin = ii + len; } /* Parse the --command */ if( g.iTrace>=2 ) logMessage("%.*s", len, zScript+ii); n = extractToken(zScript+ii+2, len-2, zCmd, sizeof(zCmd)); for(nArg=0; n<len-2 && nArg<MX_ARG; nArg++){ while( n<len-2 && isspace(zScript[ii+2+n]) ){ n++; } if( n>=len-2 ) break; n += extractToken(zScript+ii+2+n, len-2-n, azArg[nArg], sizeof(azArg[nArg])); } for(j=nArg; j<MX_ARG; j++) azArg[j++][0] = 0; /* ** --sleep N ** ** Pause for N milliseconds */ if( strcmp(zCmd, "sleep")==0 ){ sqlite3_sleep(atoi(azArg[0])); }else /* ** --exit N ** ** Exit this process. If N>0 then exit without shutting down ** SQLite. (In other words, simulate a crash.) */ if( strcmp(zCmd, "exit")==0 ){ int rc = atoi(azArg[0]); finishScript(iClient, taskId, 1); if( rc==0 ) sqlite3_close(g.db); exit(rc); }else /* ** --testcase NAME ** ** Begin a new test case. Announce in the log that the test case ** has begun. */ if( strcmp(zCmd, "testcase")==0 ){ if( g.iTrace==1 ) logMessage("%.*s", len - 1, zScript+ii); stringReset(&sResult); }else /* ** --finish ** ** Mark the current task as having finished, even if it is not. ** This can be used in conjunction with --exit to simulate a crash. */ if( strcmp(zCmd, "finish")==0 && iClient>0 ){ finishScript(iClient, taskId, 1); }else /* ** --reset ** ** Reset accumulated results back to an empty string */ if( strcmp(zCmd, "reset")==0 ){ stringReset(&sResult); }else /* ** --match ANSWER... ** ** Check to see if output matches ANSWER. Report an error if not. */ if( strcmp(zCmd, "match")==0 ){ int jj; char *zAns = zScript+ii; for(jj=7; jj<len-1 && isspace(zAns[jj]); jj++){} zAns += jj; if( len-jj-1!=sResult.n || strncmp(sResult.z, zAns, len-jj-1) ){ errorMessage("line %d of %s:\nExpected [%.*s]\n Got [%s]", prevLine, zFilename, len-jj-1, zAns, sResult.z); } g.nTest++; stringReset(&sResult); }else /* ** --glob ANSWER... ** --notglob ANSWER.... ** ** Check to see if output does or does not match the glob pattern ** ANSWER. */ if( strcmp(zCmd, "glob")==0 || strcmp(zCmd, "notglob")==0 ){ int jj; char *zAns = zScript+ii; char *zCopy; int isGlob = (zCmd[0]=='g'); for(jj=9-3*isGlob; jj<len-1 && isspace(zAns[jj]); jj++){} zAns += jj; zCopy = sqlite3_mprintf("%.*s", len-jj-1, zAns); if( (sqlite3_strglob(zCopy, sResult.z)==0)^isGlob ){ errorMessage("line %d of %s:\nExpected [%s]\n Got [%s]", prevLine, zFilename, zCopy, sResult.z); } sqlite3_free(zCopy); g.nTest++; stringReset(&sResult); }else /* ** --output ** ** Output the result of the previous SQL. */ if( strcmp(zCmd, "output")==0 ){ logMessage("%s", sResult.z); }else /* ** --source FILENAME ** ** Run a subscript from a separate file. */ if( strcmp(zCmd, "source")==0 ){ char *zNewFile, *zNewScript; char *zToDel = 0; zNewFile = azArg[0]; if( zNewFile[0]!='/' ){ int k; for(k=(int)strlen(zFilename)-1; k>=0 && zFilename[k]!='/'; k--){} if( k>0 ){ zNewFile = zToDel = sqlite3_mprintf("%.*s/%s", k,zFilename,zNewFile); } } zNewScript = readFile(zNewFile); if( g.iTrace ) logMessage("begin script [%s]\n", zNewFile); runScript(0, 0, zNewScript, zNewFile); sqlite3_free(zNewScript); if( g.iTrace ) logMessage("end script [%s]\n", zNewFile); sqlite3_free(zToDel); }else /* ** --print MESSAGE.... ** ** Output the remainder of the line to the log file */ if( strcmp(zCmd, "print")==0 ){ int jj; for(jj=7; jj<len && isspace(zScript[ii+jj]); jj++){} logMessage("%.*s", len-jj, zScript+ii+jj); }else /* ** --if EXPR ** ** Skip forward to the next matching --endif or --else if EXPR is false. */ if( strcmp(zCmd, "if")==0 ){ int jj, rc; sqlite3_stmt *pStmt; for(jj=4; jj<len && isspace(zScript[ii+jj]); jj++){} pStmt = prepareSql("SELECT %.*s", len-jj, zScript+ii+jj); rc = sqlite3_step(pStmt); if( rc!=SQLITE_ROW || sqlite3_column_int(pStmt, 0)==0 ){ ii += findEndif(zScript+ii+len, 1, &lineno); } sqlite3_finalize(pStmt); }else /* ** --else ** ** This command can only be encountered if currently inside an --if that ** is true. Skip forward to the next matching --endif. */ if( strcmp(zCmd, "else")==0 ){ ii += findEndif(zScript+ii+len, 0, &lineno); }else /* ** --endif ** ** This command can only be encountered if currently inside an --if that ** is true or an --else of a false if. This is a no-op. */ if( strcmp(zCmd, "endif")==0 ){ /* no-op */ }else /* ** --start CLIENT ** ** Start up the given client. */ if( strcmp(zCmd, "start")==0 && iClient==0 ){ int iNewClient = atoi(azArg[0]); if( iNewClient>0 ){ startClient(iNewClient); } }else /* ** --wait CLIENT TIMEOUT ** ** Wait until all tasks complete for the given client. If CLIENT is ** "all" then wait for all clients to complete. Wait no longer than ** TIMEOUT milliseconds (default 10,000) */ if( strcmp(zCmd, "wait")==0 && iClient==0 ){ int iTimeout = nArg>=2 ? atoi(azArg[1]) : 10000; sqlite3_snprintf(sizeof(zError),zError,"line %d of %s\n", prevLine, zFilename); waitForClient(atoi(azArg[0]), iTimeout, zError); }else /* ** --task CLIENT ** <task-content-here> ** --end ** ** Assign work to a client. Start the client if it is not running ** already. */ if( strcmp(zCmd, "task")==0 && iClient==0 ){ int iTarget = atoi(azArg[0]); int iEnd; char *zTask; char *zTName; iEnd = findEnd(zScript+ii+len, &lineno); if( iTarget<0 ){ errorMessage("line %d of %s: bad client number: %d", prevLine, zFilename, iTarget); }else{ zTask = sqlite3_mprintf("%.*s", iEnd, zScript+ii+len); if( nArg>1 ){ zTName = sqlite3_mprintf("%s", azArg[1]); }else{ zTName = sqlite3_mprintf("%s:%d", filenameTail(zFilename), prevLine); } startClient(iTarget); runSql("INSERT INTO task(client,script,name)" " VALUES(%d,'%q',%Q)", iTarget, zTask, zTName); sqlite3_free(zTask); sqlite3_free(zTName); } iEnd += tokenLength(zScript+ii+len+iEnd, &lineno); len += iEnd; iBegin = ii+len; }else /* ** --breakpoint ** ** This command calls "test_breakpoint()" which is a routine provided ** as a convenient place to set a debugger breakpoint. */ if( strcmp(zCmd, "breakpoint")==0 ){ test_breakpoint(); }else /* ** --show-sql-errors BOOLEAN ** ** Turn display of SQL errors on and off. */ if( strcmp(zCmd, "show-sql-errors")==0 ){ g.bIgnoreSqlErrors = nArg>=1 ? !booleanValue(azArg[0]) : 1; }else /* error */{ errorMessage("line %d of %s: unknown command --%s", prevLine, zFilename, zCmd); } ii += len; } if( iBegin<ii ){ char *zSql = sqlite3_mprintf("%.*s", ii-iBegin, zScript+iBegin); runSql(zSql); sqlite3_free(zSql); } stringFree(&sResult); } /* ** Look for a command-line option. If present, return a pointer. ** Return NULL if missing. ** ** hasArg==0 means the option is a flag. It is either present or not. ** hasArg==1 means the option has an argument. Return a pointer to the ** argument. */ static char *findOption( char **azArg, int *pnArg, const char *zOption, int hasArg ){ int i, j; char *zReturn = 0; int nArg = *pnArg; assert( hasArg==0 || hasArg==1 ); for(i=0; i<nArg; i++){ const char *z; if( i+hasArg >= nArg ) break; z = azArg[i]; if( z[0]!='-' ) continue; z++; if( z[0]=='-' ){ if( z[1]==0 ) break; z++; } if( strcmp(z,zOption)==0 ){ if( hasArg && i==nArg-1 ){ fatalError("command-line option \"--%s\" requires an argument", z); } if( hasArg ){ zReturn = azArg[i+1]; }else{ zReturn = azArg[i]; } j = i+1+(hasArg!=0); while( j<nArg ) azArg[i++] = azArg[j++]; *pnArg = i; return zReturn; } } return zReturn; } /* Print a usage message for the program and exit */ static void usage(const char *argv0){ int i; const char *zTail = argv0; for(i=0; argv0[i]; i++){ if( argv0[i]=='/' ) zTail = argv0+i+1; } fprintf(stderr,"Usage: %s DATABASE ?OPTIONS? ?SCRIPT?\n", zTail); exit(1); } /* Report on unrecognized arguments */ static void unrecognizedArguments( const char *argv0, int nArg, char **azArg ){ int i; fprintf(stderr,"%s: unrecognized arguments:", argv0); for(i=0; i<nArg; i++){ fprintf(stderr," %s", azArg[i]); } fprintf(stderr,"\n"); exit(1); } int main(int argc, char **argv){ const char *zClient; int iClient; int n, i; int openFlags = SQLITE_OPEN_READWRITE; int rc; char *zScript; int taskId; const char *zTrace; const char *zCOption; g.argv0 = argv[0]; g.iTrace = 1; if( argc<2 ) usage(argv[0]); g.zDbFile = argv[1]; if( strglob("*.test", g.zDbFile) ) usage(argv[0]); if( strcmp(sqlite3_sourceid(), SQLITE_SOURCE_ID)!=0 ){ fprintf(stderr, "SQLite library and header mismatch\n" "Library: %s\n" "Header: %s\n", sqlite3_sourceid(), SQLITE_SOURCE_ID); exit(1); } n = argc-2; sqlite3_snprintf(sizeof(g.zName), g.zName, "%05d.mptest", GETPID()); g.zVfs = findOption(argv+2, &n, "vfs", 1); zClient = findOption(argv+2, &n, "client", 1); g.zErrLog = findOption(argv+2, &n, "errlog", 1); g.zLog = findOption(argv+2, &n, "log", 1); zTrace = findOption(argv+2, &n, "trace", 1); if( zTrace ) g.iTrace = atoi(zTrace); if( findOption(argv+2, &n, "quiet", 0)!=0 ) g.iTrace = 0; g.bSqlTrace = findOption(argv+2, &n, "sqltrace", 0)!=0; g.bSync = findOption(argv+2, &n, "sync", 0)!=0; if( g.zErrLog ){ g.pErrLog = fopen(g.zErrLog, "a"); }else{ g.pErrLog = stderr; } if( g.zLog ){ g.pLog = fopen(g.zLog, "a"); }else{ g.pLog = stdout; } sqlite3_config(SQLITE_CONFIG_LOG, sqlErrorCallback, 0); if( zClient ){ iClient = atoi(zClient); if( iClient<1 ) fatalError("illegal client number: %d\n", iClient); sqlite3_snprintf(sizeof(g.zName), g.zName, "%05d.client%02d", GETPID(), iClient); }else{ if( g.iTrace>0 ){ printf("With SQLite " SQLITE_VERSION " " SQLITE_SOURCE_ID "\n" ); for(i=0; (zCOption = sqlite3_compileoption_get(i))!=0; i++){ printf("-DSQLITE_%s\n", zCOption); } fflush(stdout); } iClient = 0; unlink(g.zDbFile); openFlags |= SQLITE_OPEN_CREATE; } rc = sqlite3_open_v2(g.zDbFile, &g.db, openFlags, g.zVfs); if( rc ) fatalError("cannot open [%s]", g.zDbFile); sqlite3_enable_load_extension(g.db, 1); sqlite3_busy_handler(g.db, busyHandler, 0); sqlite3_create_function(g.db, "vfsname", 0, SQLITE_UTF8, 0, vfsNameFunc, 0, 0); sqlite3_create_function(g.db, "eval", 1, SQLITE_UTF8, 0, evalFunc, 0, 0); g.iTimeout = DEFAULT_TIMEOUT; if( g.bSqlTrace ) sqlite3_trace(g.db, sqlTraceCallback, 0); if( !g.bSync ) trySql("PRAGMA synchronous=OFF"); if( iClient>0 ){ if( n>0 ) unrecognizedArguments(argv[0], n, argv+2); if( g.iTrace ) logMessage("start-client"); while(1){ char *zTaskName = 0; rc = startScript(iClient, &zScript, &taskId, &zTaskName); if( rc==SQLITE_DONE ) break; if( g.iTrace ) logMessage("begin %s (%d)", zTaskName, taskId); runScript(iClient, taskId, zScript, zTaskName); if( g.iTrace ) logMessage("end %s (%d)", zTaskName, taskId); finishScript(iClient, taskId, 0); sqlite3_free(zTaskName); sqlite3_sleep(10); } if( g.iTrace ) logMessage("end-client"); }else{ sqlite3_stmt *pStmt; int iTimeout; if( n==0 ){ fatalError("missing script filename"); } if( n>1 ) unrecognizedArguments(argv[0], n, argv+2); runSql( "CREATE TABLE task(\n" " id INTEGER PRIMARY KEY,\n" " name TEXT,\n" " client INTEGER,\n" " starttime DATE,\n" " endtime DATE,\n" " script TEXT\n" ");" "CREATE INDEX task_i1 ON task(client, starttime);\n" "CREATE INDEX task_i2 ON task(client, endtime);\n" "CREATE TABLE counters(nError,nTest);\n" "INSERT INTO counters VALUES(0,0);\n" "CREATE TABLE client(id INTEGER PRIMARY KEY, wantHalt);\n" ); zScript = readFile(argv[2]); if( g.iTrace ) logMessage("begin script [%s]\n", argv[2]); runScript(0, 0, zScript, argv[2]); sqlite3_free(zScript); if( g.iTrace ) logMessage("end script [%s]\n", argv[2]); waitForClient(0, 2000, "during shutdown...\n"); trySql("UPDATE client SET wantHalt=1"); sqlite3_sleep(10); g.iTimeout = 0; iTimeout = 1000; while( ((rc = trySql("SELECT 1 FROM client"))==SQLITE_BUSY || rc==SQLITE_ROW) && iTimeout>0 ){ sqlite3_sleep(10); iTimeout -= 10; } sqlite3_sleep(100); pStmt = prepareSql("SELECT nError, nTest FROM counters"); iTimeout = 1000; while( (rc = sqlite3_step(pStmt))==SQLITE_BUSY && iTimeout>0 ){ sqlite3_sleep(10); iTimeout -= 10; } if( rc==SQLITE_ROW ){ g.nError += sqlite3_column_int(pStmt, 0); g.nTest += sqlite3_column_int(pStmt, 1); } sqlite3_finalize(pStmt); } sqlite3_close(g.db); maybeClose(g.pLog); maybeClose(g.pErrLog); if( iClient==0 ){ printf("Summary: %d errors in %d tests\n", g.nError, g.nTest); } return g.nError>0; } |
Added mptest/multiwrite01.test.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 | /* ** This script sets up five different tasks all writing and updating ** the database at the same time, but each in its own table. */ --task 1 build-t1 DROP TABLE IF EXISTS t1; CREATE TABLE t1(a INTEGER PRIMARY KEY, b); --sleep 1 INSERT INTO t1 VALUES(1, randomblob(2000)); INSERT INTO t1 VALUES(2, randomblob(1000)); --sleep 1 INSERT INTO t1 SELECT a+2, randomblob(1500) FROM t1; INSERT INTO t1 SELECT a+4, randomblob(1500) FROM t1; INSERT INTO t1 SELECT a+8, randomblob(1500) FROM t1; --sleep 1 INSERT INTO t1 SELECT a+16, randomblob(1500) FROM t1; --sleep 1 INSERT INTO t1 SELECT a+32, randomblob(1500) FROM t1; SELECT count(*) FROM t1; --match 64 SELECT avg(length(b)) FROM t1; --match 1500.0 --sleep 2 UPDATE t1 SET b='x'||a||'y'; SELECT total(length(b)) FROM t1; --match 247 SELECT a FROM t1 WHERE b='x17y'; --match 17 CREATE INDEX t1b ON t1(b); SELECT a FROM t1 WHERE b='x17y'; --match 17 SELECT a FROM t1 WHERE b GLOB 'x2?y' ORDER BY b DESC LIMIT 5; --match 29 28 27 26 25 --end --task 2 build-t2 DROP TABLE IF EXISTS t2; CREATE TABLE t2(a INTEGER PRIMARY KEY, b); --sleep 1 INSERT INTO t2 VALUES(1, randomblob(2000)); INSERT INTO t2 VALUES(2, randomblob(1000)); --sleep 1 INSERT INTO t2 SELECT a+2, randomblob(1500) FROM t2; INSERT INTO t2 SELECT a+4, randomblob(1500) FROM t2; INSERT INTO t2 SELECT a+8, randomblob(1500) FROM t2; --sleep 1 INSERT INTO t2 SELECT a+16, randomblob(1500) FROM t2; --sleep 1 INSERT INTO t2 SELECT a+32, randomblob(1500) FROM t2; SELECT count(*) FROM t2; --match 64 SELECT avg(length(b)) FROM t2; --match 1500.0 --sleep 2 UPDATE t2 SET b='x'||a||'y'; SELECT total(length(b)) FROM t2; --match 247 SELECT a FROM t2 WHERE b='x17y'; --match 17 CREATE INDEX t2b ON t2(b); SELECT a FROM t2 WHERE b='x17y'; --match 17 SELECT a FROM t2 WHERE b GLOB 'x2?y' ORDER BY b DESC LIMIT 5; --match 29 28 27 26 25 --end --task 3 build-t3 DROP TABLE IF EXISTS t3; CREATE TABLE t3(a INTEGER PRIMARY KEY, b); --sleep 1 INSERT INTO t3 VALUES(1, randomblob(2000)); INSERT INTO t3 VALUES(2, randomblob(1000)); --sleep 1 INSERT INTO t3 SELECT a+2, randomblob(1500) FROM t3; INSERT INTO t3 SELECT a+4, randomblob(1500) FROM t3; INSERT INTO t3 SELECT a+8, randomblob(1500) FROM t3; --sleep 1 INSERT INTO t3 SELECT a+16, randomblob(1500) FROM t3; --sleep 1 INSERT INTO t3 SELECT a+32, randomblob(1500) FROM t3; SELECT count(*) FROM t3; --match 64 SELECT avg(length(b)) FROM t3; --match 1500.0 --sleep 2 UPDATE t3 SET b='x'||a||'y'; SELECT total(length(b)) FROM t3; --match 247 SELECT a FROM t3 WHERE b='x17y'; --match 17 CREATE INDEX t3b ON t3(b); SELECT a FROM t3 WHERE b='x17y'; --match 17 SELECT a FROM t3 WHERE b GLOB 'x2?y' ORDER BY b DESC LIMIT 5; --match 29 28 27 26 25 --end --task 4 build-t4 DROP TABLE IF EXISTS t4; CREATE TABLE t4(a INTEGER PRIMARY KEY, b); --sleep 1 INSERT INTO t4 VALUES(1, randomblob(2000)); INSERT INTO t4 VALUES(2, randomblob(1000)); --sleep 1 INSERT INTO t4 SELECT a+2, randomblob(1500) FROM t4; INSERT INTO t4 SELECT a+4, randomblob(1500) FROM t4; INSERT INTO t4 SELECT a+8, randomblob(1500) FROM t4; --sleep 1 INSERT INTO t4 SELECT a+16, randomblob(1500) FROM t4; --sleep 1 INSERT INTO t4 SELECT a+32, randomblob(1500) FROM t4; SELECT count(*) FROM t4; --match 64 SELECT avg(length(b)) FROM t4; --match 1500.0 --sleep 2 UPDATE t4 SET b='x'||a||'y'; SELECT total(length(b)) FROM t4; --match 247 SELECT a FROM t4 WHERE b='x17y'; --match 17 CREATE INDEX t4b ON t4(b); SELECT a FROM t4 WHERE b='x17y'; --match 17 SELECT a FROM t4 WHERE b GLOB 'x2?y' ORDER BY b DESC LIMIT 5; --match 29 28 27 26 25 --end --task 5 build-t5 DROP TABLE IF EXISTS t5; CREATE TABLE t5(a INTEGER PRIMARY KEY, b); --sleep 1 INSERT INTO t5 VALUES(1, randomblob(2000)); INSERT INTO t5 VALUES(2, randomblob(1000)); --sleep 1 INSERT INTO t5 SELECT a+2, randomblob(1500) FROM t5; INSERT INTO t5 SELECT a+4, randomblob(1500) FROM t5; INSERT INTO t5 SELECT a+8, randomblob(1500) FROM t5; --sleep 1 INSERT INTO t5 SELECT a+16, randomblob(1500) FROM t5; --sleep 1 INSERT INTO t5 SELECT a+32, randomblob(1500) FROM t5; SELECT count(*) FROM t5; --match 64 SELECT avg(length(b)) FROM t5; --match 1500.0 --sleep 2 UPDATE t5 SET b='x'||a||'y'; SELECT total(length(b)) FROM t5; --match 247 SELECT a FROM t5 WHERE b='x17y'; --match 17 CREATE INDEX t5b ON t5(b); SELECT a FROM t5 WHERE b='x17y'; --match 17 SELECT a FROM t5 WHERE b GLOB 'x2?y' ORDER BY b DESC LIMIT 5; --match 29 28 27 26 25 --end --wait all SELECT count(*), total(length(b)) FROM t1; --match 64 247 SELECT count(*), total(length(b)) FROM t2; --match 64 247 SELECT count(*), total(length(b)) FROM t3; --match 64 247 SELECT count(*), total(length(b)) FROM t4; --match 64 247 SELECT count(*), total(length(b)) FROM t5; --match 64 247 --task 1 SELECT t1.a FROM t1, t2 WHERE t2.b GLOB 'x3?y' AND t1.b=('x'||(t2.a+3)||'y') ORDER BY t1.a LIMIT 4 --match 33 34 35 36 SELECT t3.a FROM t3, t4 WHERE t4.b GLOB 'x4?y' AND t3.b=('x'||(t4.a+5)||'y') ORDER BY t3.a LIMIT 7 --match 45 46 47 48 49 50 51 --end --task 5 SELECT t1.a FROM t1, t2 WHERE t2.b GLOB 'x3?y' AND t1.b=('x'||(t2.a+3)||'y') ORDER BY t1.a LIMIT 4 --match 33 34 35 36 SELECT t3.a FROM t3, t4 WHERE t4.b GLOB 'x4?y' AND t3.b=('x'||(t4.a+5)||'y') ORDER BY t3.a LIMIT 7 --match 45 46 47 48 49 50 51 --end --task 3 SELECT t1.a FROM t1, t2 WHERE t2.b GLOB 'x3?y' AND t1.b=('x'||(t2.a+3)||'y') ORDER BY t1.a LIMIT 4 --match 33 34 35 36 SELECT t3.a FROM t3, t4 WHERE t4.b GLOB 'x4?y' AND t3.b=('x'||(t4.a+5)||'y') ORDER BY t3.a LIMIT 7 --match 45 46 47 48 49 50 51 --end --task 2 SELECT t1.a FROM t1, t2 WHERE t2.b GLOB 'x3?y' AND t1.b=('x'||(t2.a+3)||'y') ORDER BY t1.a LIMIT 4 --match 33 34 35 36 SELECT t3.a FROM t3, t4 WHERE t4.b GLOB 'x4?y' AND t3.b=('x'||(t4.a+5)||'y') ORDER BY t3.a LIMIT 7 --match 45 46 47 48 49 50 51 --end --task 4 SELECT t1.a FROM t1, t2 WHERE t2.b GLOB 'x3?y' AND t1.b=('x'||(t2.a+3)||'y') ORDER BY t1.a LIMIT 4 --match 33 34 35 36 SELECT t3.a FROM t3, t4 WHERE t4.b GLOB 'x4?y' AND t3.b=('x'||(t4.a+5)||'y') ORDER BY t3.a LIMIT 7 --match 45 46 47 48 49 50 51 --end --wait all --task 5 DROP INDEX t5b; --sleep 5 PRAGMA integrity_check(10); --match ok CREATE INDEX t5b ON t5(b DESC); --end --task 3 DROP INDEX t3b; --sleep 5 PRAGMA integrity_check(10); --match ok CREATE INDEX t3b ON t3(b DESC); --end --task 1 DROP INDEX t1b; --sleep 5 PRAGMA integrity_check(10); --match ok CREATE INDEX t1b ON t1(b DESC); --end --task 2 DROP INDEX t2b; --sleep 5 PRAGMA integrity_check(10); --match ok CREATE INDEX t2b ON t2(b DESC); --end --task 4 DROP INDEX t4b; --sleep 5 PRAGMA integrity_check(10); --match ok CREATE INDEX t4b ON t4(b DESC); --end --wait all --task 1 SELECT t1.a FROM t1, t2 WHERE t2.b GLOB 'x3?y' AND t1.b=('x'||(t2.a+3)||'y') ORDER BY t1.a LIMIT 4 --match 33 34 35 36 SELECT t3.a FROM t3, t4 WHERE t4.b GLOB 'x4?y' AND t3.b=('x'||(t4.a+5)||'y') ORDER BY t3.a LIMIT 7 --match 45 46 47 48 49 50 51 --end --task 5 SELECT t1.a FROM t1, t2 WHERE t2.b GLOB 'x3?y' AND t1.b=('x'||(t2.a+3)||'y') ORDER BY t1.a LIMIT 4 --match 33 34 35 36 SELECT t3.a FROM t3, t4 WHERE t4.b GLOB 'x4?y' AND t3.b=('x'||(t4.a+5)||'y') ORDER BY t3.a LIMIT 7 --match 45 46 47 48 49 50 51 --end --task 3 SELECT t1.a FROM t1, t2 WHERE t2.b GLOB 'x3?y' AND t1.b=('x'||(t2.a+3)||'y') ORDER BY t1.a LIMIT 4 --match 33 34 35 36 SELECT t3.a FROM t3, t4 WHERE t4.b GLOB 'x4?y' AND t3.b=('x'||(t4.a+5)||'y') ORDER BY t3.a LIMIT 7 --match 45 46 47 48 49 50 51 --end --task 2 SELECT t1.a FROM t1, t2 WHERE t2.b GLOB 'x3?y' AND t1.b=('x'||(t2.a+3)||'y') ORDER BY t1.a LIMIT 4 --match 33 34 35 36 SELECT t3.a FROM t3, t4 WHERE t4.b GLOB 'x4?y' AND t3.b=('x'||(t4.a+5)||'y') ORDER BY t3.a LIMIT 7 --match 45 46 47 48 49 50 51 --end --task 4 SELECT t1.a FROM t1, t2 WHERE t2.b GLOB 'x3?y' AND t1.b=('x'||(t2.a+3)||'y') ORDER BY t1.a LIMIT 4 --match 33 34 35 36 SELECT t3.a FROM t3, t4 WHERE t4.b GLOB 'x4?y' AND t3.b=('x'||(t4.a+5)||'y') ORDER BY t3.a LIMIT 7 --match 45 46 47 48 49 50 51 --end --wait all VACUUM; PRAGMA integrity_check(10); --match ok --task 1 UPDATE t1 SET b=randomblob(20000); --sleep 5 UPDATE t1 SET b='x'||a||'y'; SELECT a FROM t1 WHERE b='x63y'; --match 63 --end --task 2 UPDATE t2 SET b=randomblob(20000); --sleep 5 UPDATE t2 SET b='x'||a||'y'; SELECT a FROM t2 WHERE b='x63y'; --match 63 --end --task 3 UPDATE t3 SET b=randomblob(20000); --sleep 5 UPDATE t3 SET b='x'||a||'y'; SELECT a FROM t3 WHERE b='x63y'; --match 63 --end --task 4 UPDATE t4 SET b=randomblob(20000); --sleep 5 UPDATE t4 SET b='x'||a||'y'; SELECT a FROM t4 WHERE b='x63y'; --match 63 --end --task 5 UPDATE t5 SET b=randomblob(20000); --sleep 5 UPDATE t5 SET b='x'||a||'y'; SELECT a FROM t5 WHERE b='x63y'; --match 63 --end --wait all --task 1 SELECT t1.a FROM t1, t2 WHERE t2.b GLOB 'x3?y' AND t1.b=('x'||(t2.a+3)||'y') ORDER BY t1.a LIMIT 4 --match 33 34 35 36 SELECT t3.a FROM t3, t4 WHERE t4.b GLOB 'x4?y' AND t3.b=('x'||(t4.a+5)||'y') ORDER BY t3.a LIMIT 7 --match 45 46 47 48 49 50 51 --end --task 5 SELECT t1.a FROM t1, t2 WHERE t2.b GLOB 'x3?y' AND t1.b=('x'||(t2.a+3)||'y') ORDER BY t1.a LIMIT 4 --match 33 34 35 36 SELECT t3.a FROM t3, t4 WHERE t4.b GLOB 'x4?y' AND t3.b=('x'||(t4.a+5)||'y') ORDER BY t3.a LIMIT 7 --match 45 46 47 48 49 50 51 --end --task 3 SELECT t1.a FROM t1, t2 WHERE t2.b GLOB 'x3?y' AND t1.b=('x'||(t2.a+3)||'y') ORDER BY t1.a LIMIT 4 --match 33 34 35 36 SELECT t3.a FROM t3, t4 WHERE t4.b GLOB 'x4?y' AND t3.b=('x'||(t4.a+5)||'y') ORDER BY t3.a LIMIT 7 --match 45 46 47 48 49 50 51 --end --task 2 SELECT t1.a FROM t1, t2 WHERE t2.b GLOB 'x3?y' AND t1.b=('x'||(t2.a+3)||'y') ORDER BY t1.a LIMIT 4 --match 33 34 35 36 SELECT t3.a FROM t3, t4 WHERE t4.b GLOB 'x4?y' AND t3.b=('x'||(t4.a+5)||'y') ORDER BY t3.a LIMIT 7 --match 45 46 47 48 49 50 51 --end --task 4 SELECT t1.a FROM t1, t2 WHERE t2.b GLOB 'x3?y' AND t1.b=('x'||(t2.a+3)||'y') ORDER BY t1.a LIMIT 4 --match 33 34 35 36 SELECT t3.a FROM t3, t4 WHERE t4.b GLOB 'x4?y' AND t3.b=('x'||(t4.a+5)||'y') ORDER BY t3.a LIMIT 7 --match 45 46 47 48 49 50 51 --end --wait all |
Changes to src/attach.c.
︙ | ︙ | |||
105 106 107 108 109 110 111 | assert( z && zName ); if( sqlite3StrICmp(z, zName)==0 ){ zErrDyn = sqlite3MPrintf(db, "database %s is already in use", zName); goto attach_error; } } | | | | 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 | assert( z && zName ); if( sqlite3StrICmp(z, zName)==0 ){ zErrDyn = sqlite3MPrintf(db, "database %s is already in use", zName); goto attach_error; } } /* Allocate the new entry in the db->aDb[] array and initialize the schema ** hash tables. */ if( db->aDb==db->aDbStatic ){ aNew = sqlite3DbMallocRaw(db, sizeof(db->aDb[0])*3 ); if( aNew==0 ) return; memcpy(aNew, db->aDb, sizeof(db->aDb[0])*2); }else{ aNew = sqlite3DbRealloc(db, db->aDb, sizeof(db->aDb[0])*(db->nDb+1) ); if( aNew==0 ) return; } db->aDb = aNew; aNew = &db->aDb[db->nDb]; memset(aNew, 0, sizeof(*aNew)); /* Open the database file. If the btree is successfully opened, use ** it to obtain the database schema. At this point the schema may ** or may not be initialized. */ flags = db->openFlags; rc = sqlite3ParseUri(db->pVfs->zName, zFile, &flags, &pVfs, &zPath, &zErr); if( rc!=SQLITE_OK ){ if( rc==SQLITE_NOMEM ) db->mallocFailed = 1; sqlite3_result_error(context, zErr, -1); sqlite3_free(zErr); |
︙ | ︙ |
Changes to src/backup.c.
︙ | ︙ | |||
393 394 395 396 397 398 399 | */ nSrcPage = (int)sqlite3BtreeLastPage(p->pSrc); assert( nSrcPage>=0 ); for(ii=0; (nPage<0 || ii<nPage) && p->iNext<=(Pgno)nSrcPage && !rc; ii++){ const Pgno iSrcPg = p->iNext; /* Source page number */ if( iSrcPg!=PENDING_BYTE_PAGE(p->pSrc->pBt) ){ DbPage *pSrcPg; /* Source page object */ | | > | 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 | */ nSrcPage = (int)sqlite3BtreeLastPage(p->pSrc); assert( nSrcPage>=0 ); for(ii=0; (nPage<0 || ii<nPage) && p->iNext<=(Pgno)nSrcPage && !rc; ii++){ const Pgno iSrcPg = p->iNext; /* Source page number */ if( iSrcPg!=PENDING_BYTE_PAGE(p->pSrc->pBt) ){ DbPage *pSrcPg; /* Source page object */ rc = sqlite3PagerAcquire(pSrcPager, iSrcPg, &pSrcPg, PAGER_ACQUIRE_READONLY); if( rc==SQLITE_OK ){ rc = backupOnePage(p, iSrcPg, sqlite3PagerGetData(pSrcPg), 0); sqlite3PagerUnref(pSrcPg); } } p->iNext++; } |
︙ | ︙ |
Changes to src/bitvec.c.
︙ | ︙ | |||
68 69 70 71 72 73 74 | #define BITVEC_NPTR (BITVEC_USIZE/sizeof(Bitvec *)) /* ** A bitmap is an instance of the following structure. ** | | | 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 | #define BITVEC_NPTR (BITVEC_USIZE/sizeof(Bitvec *)) /* ** A bitmap is an instance of the following structure. ** ** This bitmap records the existence of zero or more bits ** with values between 1 and iSize, inclusive. ** ** There are three possible representations of the bitmap. ** If iSize<=BITVEC_NBIT, then Bitvec.u.aBitmap[] is a straight ** bitmap. The least significant bit is bit 1. ** ** If iSize>BITVEC_NBIT and iDivisor==0 then Bitvec.u.aHash[] is |
︙ | ︙ |
Changes to src/btree.c.
︙ | ︙ | |||
570 571 572 573 574 575 576 577 578 579 580 581 582 583 | ** Clear (destroy) the BtShared.pHasContent bitvec. This should be ** invoked at the conclusion of each write-transaction. */ static void btreeClearHasContent(BtShared *pBt){ sqlite3BitvecDestroy(pBt->pHasContent); pBt->pHasContent = 0; } /* ** Save the current cursor position in the variables BtCursor.nKey ** and BtCursor.pKey. The cursor's state is set to CURSOR_REQUIRESEEK. ** ** The caller must ensure that the cursor is valid (has eState==CURSOR_VALID) ** prior to calling this routine. | > > > > > > > > > > > > > | 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 | ** Clear (destroy) the BtShared.pHasContent bitvec. This should be ** invoked at the conclusion of each write-transaction. */ static void btreeClearHasContent(BtShared *pBt){ sqlite3BitvecDestroy(pBt->pHasContent); pBt->pHasContent = 0; } /* ** Release all of the apPage[] pages for a cursor. */ static void btreeReleaseAllCursorPages(BtCursor *pCur){ int i; for(i=0; i<=pCur->iPage; i++){ releasePage(pCur->apPage[i]); pCur->apPage[i] = 0; } pCur->iPage = -1; } /* ** Save the current cursor position in the variables BtCursor.nKey ** and BtCursor.pKey. The cursor's state is set to CURSOR_REQUIRESEEK. ** ** The caller must ensure that the cursor is valid (has eState==CURSOR_VALID) ** prior to calling this routine. |
︙ | ︙ | |||
610 611 612 613 614 615 616 | }else{ rc = SQLITE_NOMEM; } } assert( !pCur->apPage[0]->intKey || !pCur->pKey ); if( rc==SQLITE_OK ){ | < < | < < < | | > > > > | 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 | }else{ rc = SQLITE_NOMEM; } } assert( !pCur->apPage[0]->intKey || !pCur->pKey ); if( rc==SQLITE_OK ){ btreeReleaseAllCursorPages(pCur); pCur->eState = CURSOR_REQUIRESEEK; } invalidateOverflowCache(pCur); return rc; } /* ** Save the positions of all cursors (except pExcept) that are open on ** the table with root-page iRoot. Usually, this is called just before cursor ** pExcept is used to modify the table (BtreeDelete() or BtreeInsert()). */ static int saveAllCursors(BtShared *pBt, Pgno iRoot, BtCursor *pExcept){ BtCursor *p; assert( sqlite3_mutex_held(pBt->mutex) ); assert( pExcept==0 || pExcept->pBt==pBt ); for(p=pBt->pCursor; p; p=p->pNext){ if( p!=pExcept && (0==iRoot || p->pgnoRoot==iRoot) ){ if( p->eState==CURSOR_VALID ){ int rc = saveCursorPosition(p); if( SQLITE_OK!=rc ){ return rc; } }else{ testcase( p->iPage>0 ); btreeReleaseAllCursorPages(p); } } } return SQLITE_OK; } /* ** Clear the current cursor position. |
︙ | ︙ | |||
1565 1566 1567 1568 1569 1570 1571 | ** means we have started to be concerned about content and the disk ** read should occur at that point. */ static int btreeGetPage( BtShared *pBt, /* The btree */ Pgno pgno, /* Number of the page to fetch */ MemPage **ppPage, /* Return the page in this parameter */ | | > > > > | | 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 | ** means we have started to be concerned about content and the disk ** read should occur at that point. */ static int btreeGetPage( BtShared *pBt, /* The btree */ Pgno pgno, /* Number of the page to fetch */ MemPage **ppPage, /* Return the page in this parameter */ int noContent, /* Do not load page content if true */ int bReadonly /* True if a read-only (mmap) page is ok */ ){ int rc; DbPage *pDbPage; int flags = (noContent ? PAGER_ACQUIRE_NOCONTENT : 0) | (bReadonly ? PAGER_ACQUIRE_READONLY : 0); assert( noContent==0 || bReadonly==0 ); assert( sqlite3_mutex_held(pBt->mutex) ); rc = sqlite3PagerAcquire(pBt->pPager, pgno, (DbPage**)&pDbPage, flags); if( rc ) return rc; *ppPage = btreePageFromDbPage(pDbPage, pgno, pBt); return SQLITE_OK; } /* ** Retrieve a page from the pager cache. If the requested page is not |
︙ | ︙ | |||
1616 1617 1618 1619 1620 1621 1622 | ** ** If an error occurs, then the value *ppPage is set to is undefined. It ** may remain unchanged, or it may be set to an invalid value. */ static int getAndInitPage( BtShared *pBt, /* The database file */ Pgno pgno, /* Number of the page to get */ | | > | | 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 | ** ** If an error occurs, then the value *ppPage is set to is undefined. It ** may remain unchanged, or it may be set to an invalid value. */ static int getAndInitPage( BtShared *pBt, /* The database file */ Pgno pgno, /* Number of the page to get */ MemPage **ppPage, /* Write the page pointer here */ int bReadonly /* True if a read-only (mmap) page is ok */ ){ int rc; assert( sqlite3_mutex_held(pBt->mutex) ); if( pgno>btreePagecount(pBt) ){ rc = SQLITE_CORRUPT_BKPT; }else{ rc = btreeGetPage(pBt, pgno, ppPage, 0, bReadonly); if( rc==SQLITE_OK ){ rc = btreeInitPage(*ppPage); if( rc!=SQLITE_OK ){ releasePage(*ppPage); } } } |
︙ | ︙ | |||
1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 | if( pBt==0 ){ rc = SQLITE_NOMEM; goto btree_open_out; } rc = sqlite3PagerOpen(pVfs, &pBt->pPager, zFilename, EXTRA_SIZE, flags, vfsFlags, pageReinit); if( rc==SQLITE_OK ){ rc = sqlite3PagerReadFileheader(pBt->pPager,sizeof(zDbHeader),zDbHeader); } if( rc!=SQLITE_OK ){ goto btree_open_out; } pBt->openFlags = (u8)flags; pBt->db = db; | > | 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 | if( pBt==0 ){ rc = SQLITE_NOMEM; goto btree_open_out; } rc = sqlite3PagerOpen(pVfs, &pBt->pPager, zFilename, EXTRA_SIZE, flags, vfsFlags, pageReinit); if( rc==SQLITE_OK ){ sqlite3PagerSetMmapLimit(pBt->pPager, db->szMmap); rc = sqlite3PagerReadFileheader(pBt->pPager,sizeof(zDbHeader),zDbHeader); } if( rc!=SQLITE_OK ){ goto btree_open_out; } pBt->openFlags = (u8)flags; pBt->db = db; |
︙ | ︙ | |||
2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 | BtShared *pBt = p->pBt; assert( sqlite3_mutex_held(p->db->mutex) ); sqlite3BtreeEnter(p); sqlite3PagerSetCachesize(pBt->pPager, mxPage); sqlite3BtreeLeave(p); return SQLITE_OK; } /* ** Change the way data is synced to disk in order to increase or decrease ** how well the database resists damage due to OS crashes and power ** failures. Level 1 is the same as asynchronous (no syncs() occur and ** there is a high probability of damage) Level 2 is the default. There ** is a very low but non-zero probability of damage. Level 3 reduces the | > > > > > > > > > > > > > | 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 | BtShared *pBt = p->pBt; assert( sqlite3_mutex_held(p->db->mutex) ); sqlite3BtreeEnter(p); sqlite3PagerSetCachesize(pBt->pPager, mxPage); sqlite3BtreeLeave(p); return SQLITE_OK; } /* ** Change the limit on the amount of the database file that may be ** memory mapped. */ int sqlite3BtreeSetMmapLimit(Btree *p, sqlite3_int64 szMmap){ BtShared *pBt = p->pBt; assert( sqlite3_mutex_held(p->db->mutex) ); sqlite3BtreeEnter(p); sqlite3PagerSetMmapLimit(pBt->pPager, szMmap); sqlite3BtreeLeave(p); return SQLITE_OK; } /* ** Change the way data is synced to disk in order to increase or decrease ** how well the database resists damage due to OS crashes and power ** failures. Level 1 is the same as asynchronous (no syncs() occur and ** there is a high probability of damage) Level 2 is the default. There ** is a very low but non-zero probability of damage. Level 3 reduces the |
︙ | ︙ | |||
2225 2226 2227 2228 2229 2230 2231 | ** may only be called if it is guaranteed that the b-tree mutex is already ** held. ** ** This is useful in one special case in the backup API code where it is ** known that the shared b-tree mutex is held, but the mutex on the ** database handle that owns *p is not. In this case if sqlite3BtreeEnter() ** were to be called, it might collide with some other operation on the | | | 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 | ** may only be called if it is guaranteed that the b-tree mutex is already ** held. ** ** This is useful in one special case in the backup API code where it is ** known that the shared b-tree mutex is held, but the mutex on the ** database handle that owns *p is not. In this case if sqlite3BtreeEnter() ** were to be called, it might collide with some other operation on the ** database handle that owns *p, causing undefined behavior. */ int sqlite3BtreeGetReserveNoMutex(Btree *p){ assert( sqlite3_mutex_held(p->pBt->mutex) ); return p->pBt->pageSize - p->pBt->usableSize; } #endif /* SQLITE_HAS_CODEC || SQLITE_DEBUG */ |
︙ | ︙ | |||
2346 2347 2348 2349 2350 2351 2352 | int nPageFile = 0; /* Number of pages in the database file */ int nPageHeader; /* Number of pages in the database according to hdr */ assert( sqlite3_mutex_held(pBt->mutex) ); assert( pBt->pPage1==0 ); rc = sqlite3PagerSharedLock(pBt->pPager); if( rc!=SQLITE_OK ) return rc; | | | 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 | int nPageFile = 0; /* Number of pages in the database file */ int nPageHeader; /* Number of pages in the database according to hdr */ assert( sqlite3_mutex_held(pBt->mutex) ); assert( pBt->pPage1==0 ); rc = sqlite3PagerSharedLock(pBt->pPager); if( rc!=SQLITE_OK ) return rc; rc = btreeGetPage(pBt, 1, &pPage1, 0, 0); if( rc!=SQLITE_OK ) return rc; /* Do some checking to help insure the file we opened really is ** a valid database file. */ nPage = nPageHeader = get4byte(28+(u8*)pPage1->aData); sqlite3PagerPagecount(pBt->pPager, &nPageFile); |
︙ | ︙ | |||
2905 2906 2907 2908 2909 2910 2911 | } /* Fix the database pointer on page iPtrPage that pointed at iDbPage so ** that it points at iFreePage. Also fix the pointer map entry for ** iPtrPage. */ if( eType!=PTRMAP_ROOTPAGE ){ | | | 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 | } /* Fix the database pointer on page iPtrPage that pointed at iDbPage so ** that it points at iFreePage. Also fix the pointer map entry for ** iPtrPage. */ if( eType!=PTRMAP_ROOTPAGE ){ rc = btreeGetPage(pBt, iPtrPage, &pPtrPage, 0, 0); if( rc!=SQLITE_OK ){ return rc; } rc = sqlite3PagerWrite(pPtrPage->pDbPage); if( rc!=SQLITE_OK ){ releasePage(pPtrPage); return rc; |
︙ | ︙ | |||
2989 2990 2991 2992 2993 2994 2995 | } } else { Pgno iFreePg; /* Index of free page to move pLastPg to */ MemPage *pLastPg; u8 eMode = BTALLOC_ANY; /* Mode parameter for allocateBtreePage() */ Pgno iNear = 0; /* nearby parameter for allocateBtreePage() */ | | | 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 | } } else { Pgno iFreePg; /* Index of free page to move pLastPg to */ MemPage *pLastPg; u8 eMode = BTALLOC_ANY; /* Mode parameter for allocateBtreePage() */ Pgno iNear = 0; /* nearby parameter for allocateBtreePage() */ rc = btreeGetPage(pBt, iLastPg, &pLastPg, 0, 0); if( rc!=SQLITE_OK ){ return rc; } /* If bCommit is zero, this loop runs exactly once and page pLastPg ** is swapped with the first free page pulled off the free list. ** |
︙ | ︙ | |||
3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 | Pgno nOrig = btreePagecount(pBt); Pgno nFree = get4byte(&pBt->pPage1->aData[36]); Pgno nFin = finalDbSize(pBt, nOrig, nFree); if( nOrig<nFin ){ rc = SQLITE_CORRUPT_BKPT; }else if( nFree>0 ){ invalidateAllOverflowCache(pBt); rc = incrVacuumStep(pBt, nFin, nOrig, 0); if( rc==SQLITE_OK ){ rc = sqlite3PagerWrite(pBt->pPage1->pDbPage); put4byte(&pBt->pPage1->aData[28], pBt->nPage); } }else{ rc = SQLITE_DONE; } | > > > | 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130 | Pgno nOrig = btreePagecount(pBt); Pgno nFree = get4byte(&pBt->pPage1->aData[36]); Pgno nFin = finalDbSize(pBt, nOrig, nFree); if( nOrig<nFin ){ rc = SQLITE_CORRUPT_BKPT; }else if( nFree>0 ){ rc = saveAllCursors(pBt, 0, 0); if( rc==SQLITE_OK ){ invalidateAllOverflowCache(pBt); rc = incrVacuumStep(pBt, nFin, nOrig, 0); } if( rc==SQLITE_OK ){ rc = sqlite3PagerWrite(pBt->pPage1->pDbPage); put4byte(&pBt->pPage1->aData[28], pBt->nPage); } }else{ rc = SQLITE_DONE; } |
︙ | ︙ | |||
3130 3131 3132 3133 3134 3135 3136 | */ return SQLITE_CORRUPT_BKPT; } nFree = get4byte(&pBt->pPage1->aData[36]); nFin = finalDbSize(pBt, nOrig, nFree); if( nFin>nOrig ) return SQLITE_CORRUPT_BKPT; | > > | | | 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 | */ return SQLITE_CORRUPT_BKPT; } nFree = get4byte(&pBt->pPage1->aData[36]); nFin = finalDbSize(pBt, nOrig, nFree); if( nFin>nOrig ) return SQLITE_CORRUPT_BKPT; if( nFin<nOrig ){ rc = saveAllCursors(pBt, 0, 0); } for(iFree=nOrig; iFree>nFin && rc==SQLITE_OK; iFree--){ rc = incrVacuumStep(pBt, nFin, iFree, 1); } if( (rc==SQLITE_DONE || rc==SQLITE_OK) && nFree>0 ){ rc = sqlite3PagerWrite(pBt->pPage1->pDbPage); put4byte(&pBt->pPage1->aData[32], 0); put4byte(&pBt->pPage1->aData[36], 0); put4byte(&pBt->pPage1->aData[28], nFin); pBt->bDoTruncate = 1; pBt->nPage = nFin; } if( rc!=SQLITE_OK ){ sqlite3PagerRollback(pPager); } } assert( nRef>=sqlite3PagerRefcount(pPager) ); return rc; } #else /* ifndef SQLITE_OMIT_AUTOVACUUM */ # define setChildPtrmaps(x) SQLITE_OK #endif |
︙ | ︙ | |||
3403 3404 3405 3406 3407 3408 3409 | if( rc2!=SQLITE_OK ){ rc = rc2; } /* The rollback may have destroyed the pPage1->aData value. So ** call btreeGetPage() on page 1 again to make ** sure pPage1->aData is set correctly. */ | | | 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 | if( rc2!=SQLITE_OK ){ rc = rc2; } /* The rollback may have destroyed the pPage1->aData value. So ** call btreeGetPage() on page 1 again to make ** sure pPage1->aData is set correctly. */ if( btreeGetPage(pBt, 1, &pPage1, 0, 0)==SQLITE_OK ){ int nPage = get4byte(28+(u8*)pPage1->aData); testcase( nPage==0 ); if( nPage==0 ) sqlite3PagerPagecount(pBt->pPager, &nPage); testcase( pBt->nPage!=nPage ); pBt->nPage = nPage; releasePage(pPage1); } |
︙ | ︙ | |||
3837 3838 3839 3840 3841 3842 3843 | } } } #endif assert( next==0 || rc==SQLITE_DONE ); if( rc==SQLITE_OK ){ | | | 3873 3874 3875 3876 3877 3878 3879 3880 3881 3882 3883 3884 3885 3886 3887 | } } } #endif assert( next==0 || rc==SQLITE_DONE ); if( rc==SQLITE_OK ){ rc = btreeGetPage(pBt, ovfl, &pPage, 0, (ppPage==0)); assert( rc==SQLITE_OK || pPage==0 ); if( rc==SQLITE_OK ){ next = get4byte(pPage->aData); } } *pPgnoNext = next; |
︙ | ︙ | |||
4058 4059 4060 4061 4062 4063 4064 | nextPage = get4byte(aWrite); memcpy(aWrite, aSave, 4); }else #endif { DbPage *pDbPage; | | > > | 4094 4095 4096 4097 4098 4099 4100 4101 4102 4103 4104 4105 4106 4107 4108 4109 4110 | nextPage = get4byte(aWrite); memcpy(aWrite, aSave, 4); }else #endif { DbPage *pDbPage; rc = sqlite3PagerAcquire(pBt->pPager, nextPage, &pDbPage, (eOp==0 ? PAGER_ACQUIRE_READONLY : 0) ); if( rc==SQLITE_OK ){ aPayload = sqlite3PagerGetData(pDbPage); nextPage = get4byte(aPayload); rc = copyPayload(&aPayload[offset+4], pBuf, a, eOp, pDbPage); sqlite3PagerUnref(pDbPage); offset = 0; } |
︙ | ︙ | |||
4237 4238 4239 4240 4241 4242 4243 4244 4245 4246 | int i = pCur->iPage; MemPage *pNewPage; BtShared *pBt = pCur->pBt; assert( cursorHoldsMutex(pCur) ); assert( pCur->eState==CURSOR_VALID ); assert( pCur->iPage<BTCURSOR_MAX_DEPTH ); if( pCur->iPage>=(BTCURSOR_MAX_DEPTH-1) ){ return SQLITE_CORRUPT_BKPT; } | > | | 4275 4276 4277 4278 4279 4280 4281 4282 4283 4284 4285 4286 4287 4288 4289 4290 4291 4292 4293 | int i = pCur->iPage; MemPage *pNewPage; BtShared *pBt = pCur->pBt; assert( cursorHoldsMutex(pCur) ); assert( pCur->eState==CURSOR_VALID ); assert( pCur->iPage<BTCURSOR_MAX_DEPTH ); assert( pCur->iPage>=0 ); if( pCur->iPage>=(BTCURSOR_MAX_DEPTH-1) ){ return SQLITE_CORRUPT_BKPT; } rc = getAndInitPage(pBt, newPgno, &pNewPage, (pCur->wrFlag==0)); if( rc ) return rc; pCur->apPage[i+1] = pNewPage; pCur->aiIdx[i+1] = 0; pCur->iPage++; pCur->info.nSize = 0; pCur->validNKey = 0; |
︙ | ︙ | |||
4357 4358 4359 4360 4361 4362 4363 | releasePage(pCur->apPage[i]); } pCur->iPage = 0; }else if( pCur->pgnoRoot==0 ){ pCur->eState = CURSOR_INVALID; return SQLITE_OK; }else{ | | | 4396 4397 4398 4399 4400 4401 4402 4403 4404 4405 4406 4407 4408 4409 4410 | releasePage(pCur->apPage[i]); } pCur->iPage = 0; }else if( pCur->pgnoRoot==0 ){ pCur->eState = CURSOR_INVALID; return SQLITE_OK; }else{ rc = getAndInitPage(pBt, pCur->pgnoRoot, &pCur->apPage[0], pCur->wrFlag==0); if( rc!=SQLITE_OK ){ pCur->eState = CURSOR_INVALID; return rc; } pCur->iPage = 0; /* If pCur->pKeyInfo is not NULL, then the caller that opened this cursor |
︙ | ︙ | |||
4971 4972 4973 4974 4975 4976 4977 | }else{ iTrunk = get4byte(&pPage1->aData[32]); } testcase( iTrunk==mxPage ); if( iTrunk>mxPage ){ rc = SQLITE_CORRUPT_BKPT; }else{ | | | 5010 5011 5012 5013 5014 5015 5016 5017 5018 5019 5020 5021 5022 5023 5024 | }else{ iTrunk = get4byte(&pPage1->aData[32]); } testcase( iTrunk==mxPage ); if( iTrunk>mxPage ){ rc = SQLITE_CORRUPT_BKPT; }else{ rc = btreeGetPage(pBt, iTrunk, &pTrunk, 0, 0); } if( rc ){ pTrunk = 0; goto end_allocate_page; } assert( pTrunk!=0 ); assert( pTrunk->aData!=0 ); |
︙ | ︙ | |||
5035 5036 5037 5038 5039 5040 5041 | MemPage *pNewTrunk; Pgno iNewTrunk = get4byte(&pTrunk->aData[8]); if( iNewTrunk>mxPage ){ rc = SQLITE_CORRUPT_BKPT; goto end_allocate_page; } testcase( iNewTrunk==mxPage ); | | | 5074 5075 5076 5077 5078 5079 5080 5081 5082 5083 5084 5085 5086 5087 5088 | MemPage *pNewTrunk; Pgno iNewTrunk = get4byte(&pTrunk->aData[8]); if( iNewTrunk>mxPage ){ rc = SQLITE_CORRUPT_BKPT; goto end_allocate_page; } testcase( iNewTrunk==mxPage ); rc = btreeGetPage(pBt, iNewTrunk, &pNewTrunk, 0, 0); if( rc!=SQLITE_OK ){ goto end_allocate_page; } rc = sqlite3PagerWrite(pNewTrunk->pDbPage); if( rc!=SQLITE_OK ){ releasePage(pNewTrunk); goto end_allocate_page; |
︙ | ︙ | |||
5115 5116 5117 5118 5119 5120 5121 | rc = sqlite3PagerWrite(pTrunk->pDbPage); if( rc ) goto end_allocate_page; if( closest<k-1 ){ memcpy(&aData[8+closest*4], &aData[4+k*4], 4); } put4byte(&aData[4], k-1); noContent = !btreeGetHasContent(pBt, *pPgno); | | | 5154 5155 5156 5157 5158 5159 5160 5161 5162 5163 5164 5165 5166 5167 5168 | rc = sqlite3PagerWrite(pTrunk->pDbPage); if( rc ) goto end_allocate_page; if( closest<k-1 ){ memcpy(&aData[8+closest*4], &aData[4+k*4], 4); } put4byte(&aData[4], k-1); noContent = !btreeGetHasContent(pBt, *pPgno); rc = btreeGetPage(pBt, *pPgno, ppPage, noContent, 0); if( rc==SQLITE_OK ){ rc = sqlite3PagerWrite((*ppPage)->pDbPage); if( rc!=SQLITE_OK ){ releasePage(*ppPage); } } searchList = 0; |
︙ | ︙ | |||
5163 5164 5165 5166 5167 5168 5169 | /* If *pPgno refers to a pointer-map page, allocate two new pages ** at the end of the file instead of one. The first allocated page ** becomes a new pointer-map page, the second is used by the caller. */ MemPage *pPg = 0; TRACE(("ALLOCATE: %d from end of file (pointer-map page)\n", pBt->nPage)); assert( pBt->nPage!=PENDING_BYTE_PAGE(pBt) ); | | | | 5202 5203 5204 5205 5206 5207 5208 5209 5210 5211 5212 5213 5214 5215 5216 5217 5218 5219 5220 5221 5222 5223 5224 5225 5226 5227 5228 5229 5230 | /* If *pPgno refers to a pointer-map page, allocate two new pages ** at the end of the file instead of one. The first allocated page ** becomes a new pointer-map page, the second is used by the caller. */ MemPage *pPg = 0; TRACE(("ALLOCATE: %d from end of file (pointer-map page)\n", pBt->nPage)); assert( pBt->nPage!=PENDING_BYTE_PAGE(pBt) ); rc = btreeGetPage(pBt, pBt->nPage, &pPg, bNoContent, 0); if( rc==SQLITE_OK ){ rc = sqlite3PagerWrite(pPg->pDbPage); releasePage(pPg); } if( rc ) return rc; pBt->nPage++; if( pBt->nPage==PENDING_BYTE_PAGE(pBt) ){ pBt->nPage++; } } #endif put4byte(28 + (u8*)pBt->pPage1->aData, pBt->nPage); *pPgno = pBt->nPage; assert( *pPgno!=PENDING_BYTE_PAGE(pBt) ); rc = btreeGetPage(pBt, *pPgno, ppPage, bNoContent, 0); if( rc ) return rc; rc = sqlite3PagerWrite((*ppPage)->pDbPage); if( rc!=SQLITE_OK ){ releasePage(*ppPage); } TRACE(("ALLOCATE: %d from end of file\n", *pPgno)); } |
︙ | ︙ | |||
5245 5246 5247 5248 5249 5250 5251 | nFree = get4byte(&pPage1->aData[36]); put4byte(&pPage1->aData[36], nFree+1); if( pBt->btsFlags & BTS_SECURE_DELETE ){ /* If the secure_delete option is enabled, then ** always fully overwrite deleted information with zeros. */ | | | 5284 5285 5286 5287 5288 5289 5290 5291 5292 5293 5294 5295 5296 5297 5298 | nFree = get4byte(&pPage1->aData[36]); put4byte(&pPage1->aData[36], nFree+1); if( pBt->btsFlags & BTS_SECURE_DELETE ){ /* If the secure_delete option is enabled, then ** always fully overwrite deleted information with zeros. */ if( (!pPage && ((rc = btreeGetPage(pBt, iPage, &pPage, 0, 0))!=0) ) || ((rc = sqlite3PagerWrite(pPage->pDbPage))!=0) ){ goto freepage_out; } memset(pPage->aData, 0, pPage->pBt->pageSize); } |
︙ | ︙ | |||
5272 5273 5274 5275 5276 5277 5278 | ** first trunk page in the current free-list. This block tests if it ** is possible to add the page as a new free-list leaf. */ if( nFree!=0 ){ u32 nLeaf; /* Initial number of leaf cells on trunk page */ iTrunk = get4byte(&pPage1->aData[32]); | | | 5311 5312 5313 5314 5315 5316 5317 5318 5319 5320 5321 5322 5323 5324 5325 | ** first trunk page in the current free-list. This block tests if it ** is possible to add the page as a new free-list leaf. */ if( nFree!=0 ){ u32 nLeaf; /* Initial number of leaf cells on trunk page */ iTrunk = get4byte(&pPage1->aData[32]); rc = btreeGetPage(pBt, iTrunk, &pTrunk, 0, 0); if( rc!=SQLITE_OK ){ goto freepage_out; } nLeaf = get4byte(&pTrunk->aData[4]); assert( pBt->usableSize>32 ); if( nLeaf > (u32)pBt->usableSize/4 - 2 ){ |
︙ | ︙ | |||
5318 5319 5320 5321 5322 5323 5324 | /* If control flows to this point, then it was not possible to add the ** the page being freed as a leaf page of the first trunk in the free-list. ** Possibly because the free-list is empty, or possibly because the ** first trunk in the free-list is full. Either way, the page being freed ** will become the new first trunk page in the free-list. */ | | | 5357 5358 5359 5360 5361 5362 5363 5364 5365 5366 5367 5368 5369 5370 5371 | /* If control flows to this point, then it was not possible to add the ** the page being freed as a leaf page of the first trunk in the free-list. ** Possibly because the free-list is empty, or possibly because the ** first trunk in the free-list is full. Either way, the page being freed ** will become the new first trunk page in the free-list. */ if( pPage==0 && SQLITE_OK!=(rc = btreeGetPage(pBt, iPage, &pPage, 0, 0)) ){ goto freepage_out; } rc = sqlite3PagerWrite(pPage->pDbPage); if( rc!=SQLITE_OK ){ goto freepage_out; } put4byte(pPage->aData, iTrunk); |
︙ | ︙ | |||
5505 5506 5507 5508 5509 5510 5511 | /* If the database supports auto-vacuum, and the second or subsequent ** overflow page is being allocated, add an entry to the pointer-map ** for that page now. ** ** If this is the first overflow page, then write a partial entry ** to the pointer-map. If we write nothing to this pointer-map slot, ** then the optimistic overflow chain processing in clearCell() | | | 5544 5545 5546 5547 5548 5549 5550 5551 5552 5553 5554 5555 5556 5557 5558 | /* If the database supports auto-vacuum, and the second or subsequent ** overflow page is being allocated, add an entry to the pointer-map ** for that page now. ** ** If this is the first overflow page, then write a partial entry ** to the pointer-map. If we write nothing to this pointer-map slot, ** then the optimistic overflow chain processing in clearCell() ** may misinterpret the uninitialized values and delete the ** wrong pages from the database. */ if( pBt->autoVacuum && rc==SQLITE_OK ){ u8 eType = (pgnoPtrmap?PTRMAP_OVERFLOW2:PTRMAP_OVERFLOW1); ptrmapPut(pBt, pgnoOvfl, eType, pgnoPtrmap, &rc); if( rc ){ releasePage(pOvfl); |
︙ | ︙ | |||
6119 6120 6121 6122 6123 6124 6125 | if( (i+nxDiv-pParent->nOverflow)==pParent->nCell ){ pRight = &pParent->aData[pParent->hdrOffset+8]; }else{ pRight = findCell(pParent, i+nxDiv-pParent->nOverflow); } pgno = get4byte(pRight); while( 1 ){ | | | 6158 6159 6160 6161 6162 6163 6164 6165 6166 6167 6168 6169 6170 6171 6172 | if( (i+nxDiv-pParent->nOverflow)==pParent->nCell ){ pRight = &pParent->aData[pParent->hdrOffset+8]; }else{ pRight = findCell(pParent, i+nxDiv-pParent->nOverflow); } pgno = get4byte(pRight); while( 1 ){ rc = getAndInitPage(pBt, pgno, &apOld[i], 0); if( rc ){ memset(apOld, 0, (i+1)*sizeof(MemPage*)); goto balance_cleanup; } nMaxCells += 1+apOld[i]->nCell+apOld[i]->nOverflow; if( (i--)==0 ) break; |
︙ | ︙ | |||
6978 6979 6980 6981 6982 6983 6984 | idx = ++pCur->aiIdx[pCur->iPage]; }else{ assert( pPage->leaf ); } insertCell(pPage, idx, newCell, szNew, 0, 0, &rc); assert( rc!=SQLITE_OK || pPage->nCell>0 || pPage->nOverflow>0 ); | | | 7017 7018 7019 7020 7021 7022 7023 7024 7025 7026 7027 7028 7029 7030 7031 | idx = ++pCur->aiIdx[pCur->iPage]; }else{ assert( pPage->leaf ); } insertCell(pPage, idx, newCell, szNew, 0, 0, &rc); assert( rc!=SQLITE_OK || pPage->nCell>0 || pPage->nOverflow>0 ); /* If no error has occurred and pPage has an overflow cell, call balance() ** to redistribute the cells within the tree. Since balance() may move ** the cursor, zero the BtCursor.info.nSize and BtCursor.validNKey ** variables. ** ** Previous versions of SQLite called moveToRoot() to move the cursor ** back to the root page as balance() used to invalidate the contents ** of BtCursor.apPage[] and BtCursor.aiIdx[]. Instead of doing that, |
︙ | ︙ | |||
7207 7208 7209 7210 7211 7212 7213 7214 | ** allocated pgnoMove. If required (i.e. if it was not allocated ** by extending the file), the current page at position pgnoMove ** is already journaled. */ u8 eType = 0; Pgno iPtrPage = 0; releasePage(pPageMove); | > > > > > > | > | | | 7246 7247 7248 7249 7250 7251 7252 7253 7254 7255 7256 7257 7258 7259 7260 7261 7262 7263 7264 7265 7266 7267 7268 7269 7270 7271 7272 7273 7274 7275 7276 7277 7278 7279 7280 7281 7282 7283 7284 7285 7286 7287 7288 7289 7290 7291 | ** allocated pgnoMove. If required (i.e. if it was not allocated ** by extending the file), the current page at position pgnoMove ** is already journaled. */ u8 eType = 0; Pgno iPtrPage = 0; /* Save the positions of any open cursors. This is required in ** case they are holding a reference to an xFetch reference ** corresponding to page pgnoRoot. */ rc = saveAllCursors(pBt, 0, 0); releasePage(pPageMove); if( rc!=SQLITE_OK ){ return rc; } /* Move the page currently at pgnoRoot to pgnoMove. */ rc = btreeGetPage(pBt, pgnoRoot, &pRoot, 0, 0); if( rc!=SQLITE_OK ){ return rc; } rc = ptrmapGet(pBt, pgnoRoot, &eType, &iPtrPage); if( eType==PTRMAP_ROOTPAGE || eType==PTRMAP_FREEPAGE ){ rc = SQLITE_CORRUPT_BKPT; } if( rc!=SQLITE_OK ){ releasePage(pRoot); return rc; } assert( eType!=PTRMAP_ROOTPAGE ); assert( eType!=PTRMAP_FREEPAGE ); rc = relocatePage(pBt, pRoot, eType, iPtrPage, pgnoMove, 0); releasePage(pRoot); /* Obtain the page at pgnoRoot */ if( rc!=SQLITE_OK ){ return rc; } rc = btreeGetPage(pBt, pgnoRoot, &pRoot, 0, 0); if( rc!=SQLITE_OK ){ return rc; } rc = sqlite3PagerWrite(pRoot->pDbPage); if( rc!=SQLITE_OK ){ releasePage(pRoot); return rc; |
︙ | ︙ | |||
7307 7308 7309 7310 7311 7312 7313 | int i; assert( sqlite3_mutex_held(pBt->mutex) ); if( pgno>btreePagecount(pBt) ){ return SQLITE_CORRUPT_BKPT; } | | | 7353 7354 7355 7356 7357 7358 7359 7360 7361 7362 7363 7364 7365 7366 7367 | int i; assert( sqlite3_mutex_held(pBt->mutex) ); if( pgno>btreePagecount(pBt) ){ return SQLITE_CORRUPT_BKPT; } rc = getAndInitPage(pBt, pgno, &pPage, 0); if( rc ) return rc; for(i=0; i<pPage->nCell; i++){ pCell = findCell(pPage, i); if( !pPage->leaf ){ rc = clearDatabasePage(pBt, get4byte(pCell), 1, pnChange); if( rc ) goto cleardatabasepage_out; } |
︙ | ︙ | |||
7409 7410 7411 7412 7413 7414 7415 | ** This error is caught long before control reaches this point. */ if( NEVER(pBt->pCursor) ){ sqlite3ConnectionBlocked(p->db, pBt->pCursor->pBtree->db); return SQLITE_LOCKED_SHAREDCACHE; } | | | 7455 7456 7457 7458 7459 7460 7461 7462 7463 7464 7465 7466 7467 7468 7469 | ** This error is caught long before control reaches this point. */ if( NEVER(pBt->pCursor) ){ sqlite3ConnectionBlocked(p->db, pBt->pCursor->pBtree->db); return SQLITE_LOCKED_SHAREDCACHE; } rc = btreeGetPage(pBt, (Pgno)iTable, &pPage, 0, 0); if( rc ) return rc; rc = sqlite3BtreeClearTable(p, iTable, 0); if( rc ){ releasePage(pPage); return rc; } |
︙ | ︙ | |||
7444 7445 7446 7447 7448 7449 7450 | }else{ /* The table being dropped does not have the largest root-page ** number in the database. So move the page that does into the ** gap left by the deleted root-page. */ MemPage *pMove; releasePage(pPage); | | | | 7490 7491 7492 7493 7494 7495 7496 7497 7498 7499 7500 7501 7502 7503 7504 7505 7506 7507 7508 7509 7510 7511 7512 7513 7514 | }else{ /* The table being dropped does not have the largest root-page ** number in the database. So move the page that does into the ** gap left by the deleted root-page. */ MemPage *pMove; releasePage(pPage); rc = btreeGetPage(pBt, maxRootPgno, &pMove, 0, 0); if( rc!=SQLITE_OK ){ return rc; } rc = relocatePage(pBt, pMove, PTRMAP_ROOTPAGE, 0, iTable, 0); releasePage(pMove); if( rc!=SQLITE_OK ){ return rc; } pMove = 0; rc = btreeGetPage(pBt, maxRootPgno, &pMove, 0, 0); freePage(pMove, &rc); releasePage(pMove); if( rc!=SQLITE_OK ){ return rc; } *piMoved = maxRootPgno; } |
︙ | ︙ | |||
7866 7867 7868 7869 7870 7871 7872 | /* Check that the page exists */ pBt = pCheck->pBt; usableSize = pBt->usableSize; if( iPage==0 ) return 0; if( checkRef(pCheck, iPage, zParentContext) ) return 0; | | | 7912 7913 7914 7915 7916 7917 7918 7919 7920 7921 7922 7923 7924 7925 7926 | /* Check that the page exists */ pBt = pCheck->pBt; usableSize = pBt->usableSize; if( iPage==0 ) return 0; if( checkRef(pCheck, iPage, zParentContext) ) return 0; if( (rc = btreeGetPage(pBt, (Pgno)iPage, &pPage, 0, 0))!=0 ){ checkAppendMsg(pCheck, zContext, "unable to get the page. error code=%d", rc); return 0; } /* Clear MemPage.isInit to make sure the corruption detection code in ** btreeInitPage() is executed. */ |
︙ | ︙ | |||
8337 8338 8339 8340 8341 8342 8343 8344 8345 8346 8347 8348 8349 8350 | if( rc!=SQLITE_OK ){ return rc; } assert( pCsr->eState!=CURSOR_REQUIRESEEK ); if( pCsr->eState!=CURSOR_VALID ){ return SQLITE_ABORT; } /* Check some assumptions: ** (a) the cursor is open for writing, ** (b) there is a read/write transaction open, ** (c) the connection holds a write-lock on the table (if required), ** (d) there are no conflicting read-locks, and ** (e) the cursor points at a valid row of an intKey table. | > > > > > > > > > > > | 8383 8384 8385 8386 8387 8388 8389 8390 8391 8392 8393 8394 8395 8396 8397 8398 8399 8400 8401 8402 8403 8404 8405 8406 8407 | if( rc!=SQLITE_OK ){ return rc; } assert( pCsr->eState!=CURSOR_REQUIRESEEK ); if( pCsr->eState!=CURSOR_VALID ){ return SQLITE_ABORT; } /* Save the positions of all other cursors open on this table. This is ** required in case any of them are holding references to an xFetch ** version of the b-tree page modified by the accessPayload call below. ** ** Note that pCsr must be open on a BTREE_INTKEY table and saveCursorPosition() ** and hence saveAllCursors() cannot fail on a BTREE_INTKEY table, hence ** saveAllCursors can only return SQLITE_OK. */ VVA_ONLY(rc =) saveAllCursors(pCsr->pBt, pCsr->pgnoRoot, pCsr); assert( rc==SQLITE_OK ); /* Check some assumptions: ** (a) the cursor is open for writing, ** (b) there is a read/write transaction open, ** (c) the connection holds a write-lock on the table (if required), ** (d) there are no conflicting read-locks, and ** (e) the cursor points at a valid row of an intKey table. |
︙ | ︙ |
Changes to src/btree.h.
︙ | ︙ | |||
59 60 61 62 63 64 65 66 67 68 69 70 71 72 | #define BTREE_OMIT_JOURNAL 1 /* Do not create or use a rollback journal */ #define BTREE_MEMORY 2 /* This is an in-memory DB */ #define BTREE_SINGLE 4 /* The file contains at most 1 b-tree */ #define BTREE_UNORDERED 8 /* Use of a hash implementation is OK */ int sqlite3BtreeClose(Btree*); int sqlite3BtreeSetCacheSize(Btree*,int); int sqlite3BtreeSetSafetyLevel(Btree*,int,int,int); int sqlite3BtreeSyncDisabled(Btree*); int sqlite3BtreeSetPageSize(Btree *p, int nPagesize, int nReserve, int eFix); int sqlite3BtreeGetPageSize(Btree*); int sqlite3BtreeMaxPageCount(Btree*,int); u32 sqlite3BtreeLastPage(Btree*); int sqlite3BtreeSecureDelete(Btree*,int); | > | 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | #define BTREE_OMIT_JOURNAL 1 /* Do not create or use a rollback journal */ #define BTREE_MEMORY 2 /* This is an in-memory DB */ #define BTREE_SINGLE 4 /* The file contains at most 1 b-tree */ #define BTREE_UNORDERED 8 /* Use of a hash implementation is OK */ int sqlite3BtreeClose(Btree*); int sqlite3BtreeSetCacheSize(Btree*,int); int sqlite3BtreeSetMmapLimit(Btree*,sqlite3_int64); int sqlite3BtreeSetSafetyLevel(Btree*,int,int,int); int sqlite3BtreeSyncDisabled(Btree*); int sqlite3BtreeSetPageSize(Btree *p, int nPagesize, int nReserve, int eFix); int sqlite3BtreeGetPageSize(Btree*); int sqlite3BtreeMaxPageCount(Btree*,int); u32 sqlite3BtreeLastPage(Btree*); int sqlite3BtreeSecureDelete(Btree*,int); |
︙ | ︙ | |||
135 136 137 138 139 140 141 142 143 144 145 146 147 148 | #define BTREE_SCHEMA_VERSION 1 #define BTREE_FILE_FORMAT 2 #define BTREE_DEFAULT_CACHE_SIZE 3 #define BTREE_LARGEST_ROOT_PAGE 4 #define BTREE_TEXT_ENCODING 5 #define BTREE_USER_VERSION 6 #define BTREE_INCR_VACUUM 7 /* ** Values that may be OR'd together to form the second argument of an ** sqlite3BtreeCursorHints() call. */ #define BTREE_BULKLOAD 0x00000001 | > | 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 | #define BTREE_SCHEMA_VERSION 1 #define BTREE_FILE_FORMAT 2 #define BTREE_DEFAULT_CACHE_SIZE 3 #define BTREE_LARGEST_ROOT_PAGE 4 #define BTREE_TEXT_ENCODING 5 #define BTREE_USER_VERSION 6 #define BTREE_INCR_VACUUM 7 #define BTREE_APPLICATION_ID 8 /* ** Values that may be OR'd together to form the second argument of an ** sqlite3BtreeCursorHints() call. */ #define BTREE_BULKLOAD 0x00000001 |
︙ | ︙ |
Changes to src/build.c.
︙ | ︙ | |||
2096 2097 2098 2099 2100 2101 2102 | ); } #endif /* Drop all SQLITE_MASTER table and index entries that refer to the ** table. The program name loops through the master table and deletes ** every row that refers to a table of the same name as the one being | | | 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 | ); } #endif /* Drop all SQLITE_MASTER table and index entries that refer to the ** table. The program name loops through the master table and deletes ** every row that refers to a table of the same name as the one being ** dropped. Triggers are handled separately because a trigger can be ** created in the temp database that refers to a table in another ** database. */ sqlite3NestedParse(pParse, "DELETE FROM %Q.%s WHERE tbl_name=%Q and type!='trigger'", pDb->zName, SCHEMA_TABLE(iDb), pTab->zName); if( !isView && !IsVirtual(pTab) ){ |
︙ | ︙ | |||
2388 2389 2390 2391 2392 2393 2394 | int iIdx = pParse->nTab++; /* Btree cursor used for pIndex */ int iSorter; /* Cursor opened by OpenSorter (if in use) */ int addr1; /* Address of top of loop */ int addr2; /* Address to jump to for next iteration */ int tnum; /* Root page of index */ Vdbe *v; /* Generate code into this virtual machine */ KeyInfo *pKey; /* KeyInfo for index */ | < < < | 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 | int iIdx = pParse->nTab++; /* Btree cursor used for pIndex */ int iSorter; /* Cursor opened by OpenSorter (if in use) */ int addr1; /* Address of top of loop */ int addr2; /* Address to jump to for next iteration */ int tnum; /* Root page of index */ Vdbe *v; /* Generate code into this virtual machine */ KeyInfo *pKey; /* KeyInfo for index */ int regRecord; /* Register holding assemblied index record */ sqlite3 *db = pParse->db; /* The database connection */ int iDb = sqlite3SchemaToIndex(db, pIndex->pSchema); #ifndef SQLITE_OMIT_AUTHORIZATION if( sqlite3AuthCheck(pParse, SQLITE_REINDEX, pIndex->zName, 0, db->aDb[iDb].zName ) ){ |
︙ | ︙ | |||
2418 2419 2420 2421 2422 2423 2424 | sqlite3VdbeAddOp2(v, OP_Clear, tnum, iDb); } pKey = sqlite3IndexKeyinfo(pParse, pIndex); sqlite3VdbeAddOp4(v, OP_OpenWrite, iIdx, tnum, iDb, (char *)pKey, P4_KEYINFO_HANDOFF); sqlite3VdbeChangeP5(v, OPFLAG_BULKCSR|((memRootPage>=0)?OPFLAG_P2ISREG:0)); | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 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 | sqlite3VdbeAddOp2(v, OP_Clear, tnum, iDb); } pKey = sqlite3IndexKeyinfo(pParse, pIndex); sqlite3VdbeAddOp4(v, OP_OpenWrite, iIdx, tnum, iDb, (char *)pKey, P4_KEYINFO_HANDOFF); sqlite3VdbeChangeP5(v, OPFLAG_BULKCSR|((memRootPage>=0)?OPFLAG_P2ISREG:0)); /* Open the sorter cursor if we are to use one. */ iSorter = pParse->nTab++; sqlite3VdbeAddOp4(v, OP_SorterOpen, iSorter, 0, 0, (char*)pKey, P4_KEYINFO); /* Open the table. Loop through all rows of the table, inserting index ** records into the sorter. */ sqlite3OpenTable(pParse, iTab, iDb, pTab, OP_OpenRead); addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iTab, 0); regRecord = sqlite3GetTempReg(pParse); sqlite3GenerateIndexKey(pParse, pIndex, iTab, regRecord, 1); sqlite3VdbeAddOp2(v, OP_SorterInsert, iSorter, regRecord); sqlite3VdbeAddOp2(v, OP_Next, iTab, addr1+1); sqlite3VdbeJumpHere(v, addr1); addr1 = sqlite3VdbeAddOp2(v, OP_SorterSort, iSorter, 0); if( pIndex->onError!=OE_None ){ int j2 = sqlite3VdbeCurrentAddr(v) + 3; sqlite3VdbeAddOp2(v, OP_Goto, 0, j2); addr2 = sqlite3VdbeCurrentAddr(v); sqlite3VdbeAddOp3(v, OP_SorterCompare, iSorter, j2, regRecord); sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_UNIQUE, OE_Abort, "indexed columns are not unique", P4_STATIC ); }else{ addr2 = sqlite3VdbeCurrentAddr(v); } sqlite3VdbeAddOp2(v, OP_SorterData, iSorter, regRecord); sqlite3VdbeAddOp3(v, OP_IdxInsert, iIdx, regRecord, 1); sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT); sqlite3ReleaseTempReg(pParse, regRecord); sqlite3VdbeAddOp2(v, OP_SorterNext, iSorter, addr2); sqlite3VdbeJumpHere(v, addr1); sqlite3VdbeAddOp1(v, OP_Close, iTab); sqlite3VdbeAddOp1(v, OP_Close, iIdx); sqlite3VdbeAddOp1(v, OP_Close, iSorter); |
︙ | ︙ | |||
2835 2836 2837 2838 2839 2840 2841 | if( k==pIdx->nColumn ){ if( pIdx->onError!=pIndex->onError ){ /* This constraint creates the same index as a previous ** constraint specified somewhere in the CREATE TABLE statement. ** However the ON CONFLICT clauses are different. If both this ** constraint and the previous equivalent constraint have explicit ** ON CONFLICT clauses this is an error. Otherwise, use the | | | 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 | if( k==pIdx->nColumn ){ if( pIdx->onError!=pIndex->onError ){ /* This constraint creates the same index as a previous ** constraint specified somewhere in the CREATE TABLE statement. ** However the ON CONFLICT clauses are different. If both this ** constraint and the previous equivalent constraint have explicit ** ON CONFLICT clauses this is an error. Otherwise, use the ** explicitly specified behavior for the index. */ if( !(pIdx->onError==OE_Default || pIndex->onError==OE_Default) ){ sqlite3ErrorMsg(pParse, "conflicting ON CONFLICT clauses specified", 0); } if( pIdx->onError==OE_Default ){ pIdx->onError = pIndex->onError; |
︙ | ︙ |
Changes to src/ctime.c.
︙ | ︙ | |||
44 45 46 47 48 49 50 | #endif #ifdef SQLITE_CHECK_PAGES "CHECK_PAGES", #endif #ifdef SQLITE_COVERAGE_TEST "COVERAGE_TEST", #endif | < < < > > > | 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | #endif #ifdef SQLITE_CHECK_PAGES "CHECK_PAGES", #endif #ifdef SQLITE_COVERAGE_TEST "COVERAGE_TEST", #endif #ifdef SQLITE_DEBUG "DEBUG", #endif #ifdef SQLITE_DEFAULT_LOCKING_MODE "DEFAULT_LOCKING_MODE=" CTIMEOPT_VAL(SQLITE_DEFAULT_LOCKING_MODE), #endif #if defined(SQLITE_DEFAULT_MMAP_SIZE) && !defined(SQLITE_DEFAULT_MMAP_SIZE_xc) "DEFAULT_MMAP_SIZE=" CTIMEOPT_VAL(SQLITE_DEFAULT_MMAP_SIZE), #endif #ifdef SQLITE_DISABLE_DIRSYNC "DISABLE_DIRSYNC", #endif #ifdef SQLITE_DISABLE_LFS "DISABLE_LFS", #endif |
︙ | ︙ | |||
143 144 145 146 147 148 149 150 151 152 153 154 155 156 | #endif #ifdef SQLITE_INT64_TYPE "INT64_TYPE", #endif #ifdef SQLITE_LOCK_TRACE "LOCK_TRACE", #endif #ifdef SQLITE_MAX_SCHEMA_RETRY "MAX_SCHEMA_RETRY=" CTIMEOPT_VAL(SQLITE_MAX_SCHEMA_RETRY), #endif #ifdef SQLITE_MEMDEBUG "MEMDEBUG", #endif #ifdef SQLITE_MIXED_ENDIAN_64BIT_FLOAT | > > > | 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 | #endif #ifdef SQLITE_INT64_TYPE "INT64_TYPE", #endif #ifdef SQLITE_LOCK_TRACE "LOCK_TRACE", #endif #if defined(SQLITE_MAX_MMAP_SIZE) && !defined(SQLITE_MAX_MMAP_SIZE_xc) "MAX_MMAP_SIZE=" CTIMEOPT_VAL(SQLITE_MAX_MMAP_SIZE), #endif #ifdef SQLITE_MAX_SCHEMA_RETRY "MAX_SCHEMA_RETRY=" CTIMEOPT_VAL(SQLITE_MAX_SCHEMA_RETRY), #endif #ifdef SQLITE_MEMDEBUG "MEMDEBUG", #endif #ifdef SQLITE_MIXED_ENDIAN_64BIT_FLOAT |
︙ | ︙ | |||
200 201 202 203 204 205 206 | #endif #ifdef SQLITE_OMIT_CAST "OMIT_CAST", #endif #ifdef SQLITE_OMIT_CHECK "OMIT_CHECK", #endif | < < < < < | 203 204 205 206 207 208 209 210 211 212 213 214 215 216 | #endif #ifdef SQLITE_OMIT_CAST "OMIT_CAST", #endif #ifdef SQLITE_OMIT_CHECK "OMIT_CHECK", #endif #ifdef SQLITE_OMIT_COMPLETE "OMIT_COMPLETE", #endif #ifdef SQLITE_OMIT_COMPOUND_SELECT "OMIT_COMPOUND_SELECT", #endif #ifdef SQLITE_OMIT_DATETIME_FUNCS |
︙ | ︙ | |||
259 260 261 262 263 264 265 | #endif #ifdef SQLITE_OMIT_LOOKASIDE "OMIT_LOOKASIDE", #endif #ifdef SQLITE_OMIT_MEMORYDB "OMIT_MEMORYDB", #endif | < < < | 257 258 259 260 261 262 263 264 265 266 267 268 269 270 | #endif #ifdef SQLITE_OMIT_LOOKASIDE "OMIT_LOOKASIDE", #endif #ifdef SQLITE_OMIT_MEMORYDB "OMIT_MEMORYDB", #endif #ifdef SQLITE_OMIT_OR_OPTIMIZATION "OMIT_OR_OPTIMIZATION", #endif #ifdef SQLITE_OMIT_PAGER_PRAGMAS "OMIT_PAGER_PRAGMAS", #endif #ifdef SQLITE_OMIT_PRAGMA |
︙ | ︙ | |||
349 350 351 352 353 354 355 | #endif #ifdef SQLITE_SOUNDEX "SOUNDEX", #endif #ifdef SQLITE_TCL "TCL", #endif | | | | 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 | #endif #ifdef SQLITE_SOUNDEX "SOUNDEX", #endif #ifdef SQLITE_TCL "TCL", #endif #if defined(SQLITE_TEMP_STORE) && !defined(SQLITE_TEMP_STORE_xc) "TEMP_STORE=" CTIMEOPT_VAL(SQLITE_TEMP_STORE), #endif #ifdef SQLITE_TEST "TEST", #endif #if defined(SQLITE_THREADSAFE) "THREADSAFE=" CTIMEOPT_VAL(SQLITE_THREADSAFE), #endif #ifdef SQLITE_USE_ALLOCA "USE_ALLOCA", #endif #ifdef SQLITE_ZERO_MALLOC "ZERO_MALLOC" |
︙ | ︙ | |||
381 382 383 384 385 386 387 | int i, n; if( sqlite3StrNICmp(zOptName, "SQLITE_", 7)==0 ) zOptName += 7; n = sqlite3Strlen30(zOptName); /* Since ArraySize(azCompileOpt) is normally in single digits, a ** linear search is adequate. No need for a binary search. */ for(i=0; i<ArraySize(azCompileOpt); i++){ | | | > > > | 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 | int i, n; if( sqlite3StrNICmp(zOptName, "SQLITE_", 7)==0 ) zOptName += 7; n = sqlite3Strlen30(zOptName); /* Since ArraySize(azCompileOpt) is normally in single digits, a ** linear search is adequate. No need for a binary search. */ for(i=0; i<ArraySize(azCompileOpt); i++){ if( sqlite3StrNICmp(zOptName, azCompileOpt[i], n)==0 && sqlite3CtypeMap[(unsigned char)azCompileOpt[i][n]]==0 ){ return 1; } } return 0; } /* ** Return the N-th compile-time option string. If N is out of range, ** return a NULL pointer. |
︙ | ︙ |
Changes to src/expr.c.
︙ | ︙ | |||
1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 | static int selectNodeIsConstant(Walker *pWalker, Select *NotUsed){ UNUSED_PARAMETER(NotUsed); pWalker->u.i = 0; return WRC_Abort; } static int exprIsConst(Expr *p, int initFlag){ Walker w; w.u.i = initFlag; w.xExprCallback = exprNodeIsConstant; w.xSelectCallback = selectNodeIsConstant; sqlite3WalkExpr(&w, p); return w.u.i; } | > | 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 | static int selectNodeIsConstant(Walker *pWalker, Select *NotUsed){ UNUSED_PARAMETER(NotUsed); pWalker->u.i = 0; return WRC_Abort; } static int exprIsConst(Expr *p, int initFlag){ Walker w; memset(&w, 0, sizeof(w)); w.u.i = initFlag; w.xExprCallback = exprNodeIsConstant; w.xSelectCallback = selectNodeIsConstant; sqlite3WalkExpr(&w, p); return w.u.i; } |
︙ | ︙ | |||
3424 3425 3426 3427 3428 3429 3430 3431 | ** obtained for queries regardless of whether or not constants are ** precomputed into registers or if they are inserted in-line. */ void sqlite3ExprCodeConstants(Parse *pParse, Expr *pExpr){ Walker w; if( pParse->cookieGoto ) return; if( OptimizationDisabled(pParse->db, SQLITE_FactorOutConst) ) return; w.xExprCallback = evalConstExpr; | > < | 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 | ** obtained for queries regardless of whether or not constants are ** precomputed into registers or if they are inserted in-line. */ void sqlite3ExprCodeConstants(Parse *pParse, Expr *pExpr){ Walker w; if( pParse->cookieGoto ) return; if( OptimizationDisabled(pParse->db, SQLITE_FactorOutConst) ) return; memset(&w, 0, sizeof(w)); w.xExprCallback = evalConstExpr; w.pParse = pParse; sqlite3WalkExpr(&w, pExpr); } /* ** Generate code that pushes the value of every element of the given |
︙ | ︙ | |||
3538 3539 3540 3541 3542 3543 3544 | Vdbe *v = pParse->pVdbe; int op = 0; int regFree1 = 0; int regFree2 = 0; int r1, r2; assert( jumpIfNull==SQLITE_JUMPIFNULL || jumpIfNull==0 ); | | | 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 3551 3552 3553 | Vdbe *v = pParse->pVdbe; int op = 0; int regFree1 = 0; int regFree2 = 0; int r1, r2; assert( jumpIfNull==SQLITE_JUMPIFNULL || jumpIfNull==0 ); if( NEVER(v==0) ) return; /* Existence of VDBE checked by caller */ if( NEVER(pExpr==0) ) return; /* No way this can happen */ op = pExpr->op; switch( op ){ case TK_AND: { int d2 = sqlite3VdbeMakeLabel(v); testcase( jumpIfNull==0 ); sqlite3ExprCachePush(pParse); |
︙ | ︙ | |||
3658 3659 3660 3661 3662 3663 3664 | Vdbe *v = pParse->pVdbe; int op = 0; int regFree1 = 0; int regFree2 = 0; int r1, r2; assert( jumpIfNull==SQLITE_JUMPIFNULL || jumpIfNull==0 ); | | | 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 | Vdbe *v = pParse->pVdbe; int op = 0; int regFree1 = 0; int regFree2 = 0; int r1, r2; assert( jumpIfNull==SQLITE_JUMPIFNULL || jumpIfNull==0 ); if( NEVER(v==0) ) return; /* Existence of VDBE checked by caller */ if( pExpr==0 ) return; /* The value of pExpr->op and op are related as follows: ** ** pExpr->op op ** --------- ---------- ** TK_ISNULL OP_NotNull |
︙ | ︙ |
Changes to src/func.c.
︙ | ︙ | |||
691 692 693 694 695 696 697 698 699 700 701 702 703 704 | return 0; } prevEscape = 0; } } return *zString==0; } /* ** Count the number of times that the LIKE operator (or GLOB which is ** just a variation of LIKE) gets called. This is used for testing ** only. */ #ifdef SQLITE_TEST | > > > > > > > | 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 | return 0; } prevEscape = 0; } } return *zString==0; } /* ** The sqlite3_strglob() interface. */ int sqlite3_strglob(const char *zGlobPattern, const char *zString){ return patternCompare((u8*)zGlobPattern, (u8*)zString, &globInfo, 0)==0; } /* ** Count the number of times that the LIKE operator (or GLOB which is ** just a variation of LIKE) gets called. This is used for testing ** only. */ #ifdef SQLITE_TEST |
︙ | ︙ |
Changes to src/global.c.
︙ | ︙ | |||
152 153 154 155 156 157 158 159 160 161 162 163 164 165 | 500, /* nLookaside */ {0,0,0,0,0,0,0,0}, /* m */ {0,0,0,0,0,0,0,0,0}, /* mutex */ {0,0,0,0,0,0,0,0,0,0,0,0,0},/* pcache2 */ (void*)0, /* pHeap */ 0, /* nHeap */ 0, 0, /* mnHeap, mxHeap */ (void*)0, /* pScratch */ 0, /* szScratch */ 0, /* nScratch */ (void*)0, /* pPage */ 0, /* szPage */ 0, /* nPage */ 0, /* mxParserStack */ | > > | 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 | 500, /* nLookaside */ {0,0,0,0,0,0,0,0}, /* m */ {0,0,0,0,0,0,0,0,0}, /* mutex */ {0,0,0,0,0,0,0,0,0,0,0,0,0},/* pcache2 */ (void*)0, /* pHeap */ 0, /* nHeap */ 0, 0, /* mnHeap, mxHeap */ SQLITE_DEFAULT_MMAP_SIZE, /* szMmap */ SQLITE_MAX_MMAP_SIZE, /* mxMmap */ (void*)0, /* pScratch */ 0, /* szScratch */ 0, /* nScratch */ (void*)0, /* pPage */ 0, /* szPage */ 0, /* nPage */ 0, /* mxParserStack */ |
︙ | ︙ |
Changes to src/hash.h.
1 2 3 4 5 6 7 8 9 10 11 | /* ** 2001 September 22 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | /* ** 2001 September 22 ** ** 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 is the header file for the generic hash-table implementation ** used in SQLite. */ #ifndef _SQLITE_HASH_H_ #define _SQLITE_HASH_H_ /* Forward declarations of structures. */ typedef struct Hash Hash; |
︙ | ︙ |
Changes to src/legacy.c.
︙ | ︙ | |||
34 35 36 37 38 39 40 | void *pArg, /* First argument to xCallback() */ char **pzErrMsg /* Write error messages here */ ){ int rc = SQLITE_OK; /* Return code */ const char *zLeftover; /* Tail of unprocessed SQL */ sqlite3_stmt *pStmt = 0; /* The current SQL statement */ char **azCols = 0; /* Names of result columns */ | < | | | 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 | void *pArg, /* First argument to xCallback() */ char **pzErrMsg /* Write error messages here */ ){ int rc = SQLITE_OK; /* Return code */ const char *zLeftover; /* Tail of unprocessed SQL */ sqlite3_stmt *pStmt = 0; /* The current SQL statement */ char **azCols = 0; /* Names of result columns */ int callbackIsInit; /* True if callback data is initialized */ if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; if( zSql==0 ) zSql = ""; sqlite3_mutex_enter(db->mutex); sqlite3Error(db, SQLITE_OK, 0); while( rc==SQLITE_OK && zSql[0] ){ int nCol; char **azVals = 0; pStmt = 0; rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zLeftover); assert( rc==SQLITE_OK || pStmt==0 ); if( rc!=SQLITE_OK ){ continue; } if( !pStmt ){ /* this happens for a comment or white-space */ zSql = zLeftover; |
︙ | ︙ | |||
104 105 106 107 108 109 110 | goto exec_out; } } if( rc!=SQLITE_ROW ){ rc = sqlite3VdbeFinalize((Vdbe *)pStmt); pStmt = 0; | < < < | 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 | goto exec_out; } } if( rc!=SQLITE_ROW ){ rc = sqlite3VdbeFinalize((Vdbe *)pStmt); pStmt = 0; zSql = zLeftover; while( sqlite3Isspace(zSql[0]) ) zSql++; break; } } sqlite3DbFree(db, azCols); azCols = 0; } |
︙ | ︙ |
Changes to src/loadext.c.
︙ | ︙ | |||
411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 | const char *zProc, /* Entry point. Use "sqlite3_extension_init" if 0 */ char **pzErrMsg /* Put error message here if not 0 */ ){ sqlite3_vfs *pVfs = db->pVfs; void *handle; int (*xInit)(sqlite3*,char**,const sqlite3_api_routines*); char *zErrmsg = 0; void **aHandle; int nMsg = 300 + sqlite3Strlen30(zFile); if( pzErrMsg ) *pzErrMsg = 0; /* Ticket #1863. To avoid a creating security problems for older ** applications that relink against newer versions of SQLite, the ** ability to run load_extension is turned off by default. One ** must call sqlite3_enable_load_extension() to turn on extension ** loading. Otherwise you get the following error. */ if( (db->flags & SQLITE_LoadExtension)==0 ){ if( pzErrMsg ){ *pzErrMsg = sqlite3_mprintf("not authorized"); } return SQLITE_ERROR; } | > > > > > > > > > > > > > > > < | | | > > > > | > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | < > > > > | | 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 | const char *zProc, /* Entry point. Use "sqlite3_extension_init" if 0 */ char **pzErrMsg /* Put error message here if not 0 */ ){ sqlite3_vfs *pVfs = db->pVfs; void *handle; int (*xInit)(sqlite3*,char**,const sqlite3_api_routines*); char *zErrmsg = 0; const char *zEntry; char *zAltEntry = 0; void **aHandle; int nMsg = 300 + sqlite3Strlen30(zFile); int ii; /* Shared library endings to try if zFile cannot be loaded as written */ static const char *azEndings[] = { #if SQLITE_OS_WIN "dll" #elif defined(__APPLE__) "dylib" #else "so" #endif }; if( pzErrMsg ) *pzErrMsg = 0; /* Ticket #1863. To avoid a creating security problems for older ** applications that relink against newer versions of SQLite, the ** ability to run load_extension is turned off by default. One ** must call sqlite3_enable_load_extension() to turn on extension ** loading. Otherwise you get the following error. */ if( (db->flags & SQLITE_LoadExtension)==0 ){ if( pzErrMsg ){ *pzErrMsg = sqlite3_mprintf("not authorized"); } return SQLITE_ERROR; } zEntry = zProc ? zProc : "sqlite3_extension_init"; handle = sqlite3OsDlOpen(pVfs, zFile); #if SQLITE_OS_UNIX || SQLITE_OS_WIN for(ii=0; ii<ArraySize(azEndings) && handle==0; ii++){ char *zAltFile = sqlite3_mprintf("%s.%s", zFile, azEndings[ii]); if( zAltFile==0 ) return SQLITE_NOMEM; handle = sqlite3OsDlOpen(pVfs, zAltFile); sqlite3_free(zAltFile); } #endif if( handle==0 ){ if( pzErrMsg ){ *pzErrMsg = zErrmsg = sqlite3_malloc(nMsg); if( zErrmsg ){ sqlite3_snprintf(nMsg, zErrmsg, "unable to open shared library [%s]", zFile); sqlite3OsDlError(pVfs, nMsg-1, zErrmsg); } } return SQLITE_ERROR; } xInit = (int(*)(sqlite3*,char**,const sqlite3_api_routines*)) sqlite3OsDlSym(pVfs, handle, zEntry); /* If no entry point was specified and the default legacy ** entry point name "sqlite3_extension_init" was not found, then ** construct an entry point name "sqlite3_X_init" where the X is ** replaced by the lowercase value of every ASCII alphabetic ** character in the filename after the last "/" upto the first ".", ** and eliding the first three characters if they are "lib". ** Examples: ** ** /usr/local/lib/libExample5.4.3.so ==> sqlite3_example_init ** C:/lib/mathfuncs.dll ==> sqlite3_mathfuncs_init */ if( xInit==0 && zProc==0 ){ int iFile, iEntry, c; int ncFile = sqlite3Strlen30(zFile); zAltEntry = sqlite3_malloc(ncFile+30); if( zAltEntry==0 ){ sqlite3OsDlClose(pVfs, handle); return SQLITE_NOMEM; } memcpy(zAltEntry, "sqlite3_", 8); for(iFile=ncFile-1; iFile>=0 && zFile[iFile]!='/'; iFile--){} iFile++; if( sqlite3_strnicmp(zFile+iFile, "lib", 3)==0 ) iFile += 3; for(iEntry=8; (c = zFile[iFile])!=0 && c!='.'; iFile++){ if( sqlite3Isalpha(c) ){ zAltEntry[iEntry++] = (char)sqlite3UpperToLower[(unsigned)c]; } } memcpy(zAltEntry+iEntry, "_init", 6); zEntry = zAltEntry; xInit = (int(*)(sqlite3*,char**,const sqlite3_api_routines*)) sqlite3OsDlSym(pVfs, handle, zEntry); } if( xInit==0 ){ if( pzErrMsg ){ nMsg += sqlite3Strlen30(zEntry); *pzErrMsg = zErrmsg = sqlite3_malloc(nMsg); if( zErrmsg ){ sqlite3_snprintf(nMsg, zErrmsg, "no entry point [%s] in shared library [%s]", zEntry, zFile); sqlite3OsDlError(pVfs, nMsg-1, zErrmsg); } } sqlite3OsDlClose(pVfs, handle); sqlite3_free(zAltEntry); return SQLITE_ERROR; } sqlite3_free(zAltEntry); if( xInit(db, &zErrmsg, &sqlite3Apis) ){ if( pzErrMsg ){ *pzErrMsg = sqlite3_mprintf("error during initialization: %s", zErrmsg); } sqlite3_free(zErrmsg); sqlite3OsDlClose(pVfs, handle); return SQLITE_ERROR; } |
︙ | ︙ |
Changes to src/main.c.
︙ | ︙ | |||
491 492 493 494 495 496 497 498 499 500 501 502 503 504 | case SQLITE_CONFIG_SQLLOG: { typedef void(*SQLLOGFUNC_t)(void*, sqlite3*, const char*, int); sqlite3GlobalConfig.xSqllog = va_arg(ap, SQLLOGFUNC_t); sqlite3GlobalConfig.pSqllogArg = va_arg(ap, void *); break; } #endif default: { rc = SQLITE_ERROR; break; } } va_end(ap); | > > > > > > > > > > > > > | 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 | case SQLITE_CONFIG_SQLLOG: { typedef void(*SQLLOGFUNC_t)(void*, sqlite3*, const char*, int); sqlite3GlobalConfig.xSqllog = va_arg(ap, SQLLOGFUNC_t); sqlite3GlobalConfig.pSqllogArg = va_arg(ap, void *); break; } #endif case SQLITE_CONFIG_MMAP_SIZE: { sqlite3_int64 szMmap = va_arg(ap, sqlite3_int64); sqlite3_int64 mxMmap = va_arg(ap, sqlite3_int64); if( mxMmap<0 || mxMmap>SQLITE_MAX_MMAP_SIZE ){ mxMmap = SQLITE_MAX_MMAP_SIZE; } sqlite3GlobalConfig.mxMmap = mxMmap; if( szMmap<0 ) szMmap = SQLITE_DEFAULT_MMAP_SIZE; if( szMmap>mxMmap) szMmap = mxMmap; sqlite3GlobalConfig.szMmap = szMmap; break; } default: { rc = SQLITE_ERROR; break; } } va_end(ap); |
︙ | ︙ | |||
881 882 883 884 885 886 887 | if( db->magic!=SQLITE_MAGIC_ZOMBIE || connectionIsBusy(db) ){ sqlite3_mutex_leave(db->mutex); return; } /* If we reach this point, it means that the database connection has ** closed all sqlite3_stmt and sqlite3_backup objects and has been | | | 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 | if( db->magic!=SQLITE_MAGIC_ZOMBIE || connectionIsBusy(db) ){ sqlite3_mutex_leave(db->mutex); return; } /* If we reach this point, it means that the database connection has ** closed all sqlite3_stmt and sqlite3_backup objects and has been ** passed to sqlite3_close (meaning that it is a zombie). Therefore, ** go ahead and free all resources. */ /* Free any outstanding Savepoint structures. */ sqlite3CloseSavepoints(db); /* Close all database connections */ |
︙ | ︙ | |||
1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 | /* If one has been configured, invoke the rollback-hook callback */ if( db->xRollbackCallback && (inTrans || !db->autoCommit) ){ db->xRollbackCallback(db->pRollbackArg); } } /* ** Return a static string that describes the kind of error specified in the ** argument. */ const char *sqlite3ErrStr(int rc){ static const char* const aMsg[] = { /* SQLITE_OK */ "not an error", | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 | /* If one has been configured, invoke the rollback-hook callback */ if( db->xRollbackCallback && (inTrans || !db->autoCommit) ){ db->xRollbackCallback(db->pRollbackArg); } } /* ** Return a static string containing the name corresponding to the error code ** specified in the argument. */ #if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) || \ defined(SQLITE_DEBUG_OS_TRACE) const char *sqlite3ErrName(int rc){ const char *zName = 0; int i, origRc = rc; for(i=0; i<2 && zName==0; i++, rc &= 0xff){ switch( rc ){ case SQLITE_OK: zName = "SQLITE_OK"; break; case SQLITE_ERROR: zName = "SQLITE_ERROR"; break; case SQLITE_INTERNAL: zName = "SQLITE_INTERNAL"; break; case SQLITE_PERM: zName = "SQLITE_PERM"; break; case SQLITE_ABORT: zName = "SQLITE_ABORT"; break; case SQLITE_ABORT_ROLLBACK: zName = "SQLITE_ABORT_ROLLBACK"; break; case SQLITE_BUSY: zName = "SQLITE_BUSY"; break; case SQLITE_BUSY_RECOVERY: zName = "SQLITE_BUSY_RECOVERY"; break; case SQLITE_LOCKED: zName = "SQLITE_LOCKED"; break; case SQLITE_LOCKED_SHAREDCACHE: zName = "SQLITE_LOCKED_SHAREDCACHE";break; case SQLITE_NOMEM: zName = "SQLITE_NOMEM"; break; case SQLITE_READONLY: zName = "SQLITE_READONLY"; break; case SQLITE_READONLY_RECOVERY: zName = "SQLITE_READONLY_RECOVERY"; break; case SQLITE_READONLY_CANTLOCK: zName = "SQLITE_READONLY_CANTLOCK"; break; case SQLITE_READONLY_ROLLBACK: zName = "SQLITE_READONLY_ROLLBACK"; break; case SQLITE_INTERRUPT: zName = "SQLITE_INTERRUPT"; break; case SQLITE_IOERR: zName = "SQLITE_IOERR"; break; case SQLITE_IOERR_READ: zName = "SQLITE_IOERR_READ"; break; case SQLITE_IOERR_SHORT_READ: zName = "SQLITE_IOERR_SHORT_READ"; break; case SQLITE_IOERR_WRITE: zName = "SQLITE_IOERR_WRITE"; break; case SQLITE_IOERR_FSYNC: zName = "SQLITE_IOERR_FSYNC"; break; case SQLITE_IOERR_DIR_FSYNC: zName = "SQLITE_IOERR_DIR_FSYNC"; break; case SQLITE_IOERR_TRUNCATE: zName = "SQLITE_IOERR_TRUNCATE"; break; case SQLITE_IOERR_FSTAT: zName = "SQLITE_IOERR_FSTAT"; break; case SQLITE_IOERR_UNLOCK: zName = "SQLITE_IOERR_UNLOCK"; break; case SQLITE_IOERR_RDLOCK: zName = "SQLITE_IOERR_RDLOCK"; break; case SQLITE_IOERR_DELETE: zName = "SQLITE_IOERR_DELETE"; break; case SQLITE_IOERR_BLOCKED: zName = "SQLITE_IOERR_BLOCKED"; break; case SQLITE_IOERR_NOMEM: zName = "SQLITE_IOERR_NOMEM"; break; case SQLITE_IOERR_ACCESS: zName = "SQLITE_IOERR_ACCESS"; break; case SQLITE_IOERR_CHECKRESERVEDLOCK: zName = "SQLITE_IOERR_CHECKRESERVEDLOCK"; break; case SQLITE_IOERR_LOCK: zName = "SQLITE_IOERR_LOCK"; break; case SQLITE_IOERR_CLOSE: zName = "SQLITE_IOERR_CLOSE"; break; case SQLITE_IOERR_DIR_CLOSE: zName = "SQLITE_IOERR_DIR_CLOSE"; break; case SQLITE_IOERR_SHMOPEN: zName = "SQLITE_IOERR_SHMOPEN"; break; case SQLITE_IOERR_SHMSIZE: zName = "SQLITE_IOERR_SHMSIZE"; break; case SQLITE_IOERR_SHMLOCK: zName = "SQLITE_IOERR_SHMLOCK"; break; case SQLITE_IOERR_SHMMAP: zName = "SQLITE_IOERR_SHMMAP"; break; case SQLITE_IOERR_SEEK: zName = "SQLITE_IOERR_SEEK"; break; case SQLITE_IOERR_DELETE_NOENT: zName = "SQLITE_IOERR_DELETE_NOENT";break; case SQLITE_IOERR_MMAP: zName = "SQLITE_IOERR_MMAP"; break; case SQLITE_CORRUPT: zName = "SQLITE_CORRUPT"; break; case SQLITE_CORRUPT_VTAB: zName = "SQLITE_CORRUPT_VTAB"; break; case SQLITE_NOTFOUND: zName = "SQLITE_NOTFOUND"; break; case SQLITE_FULL: zName = "SQLITE_FULL"; break; case SQLITE_CANTOPEN: zName = "SQLITE_CANTOPEN"; break; case SQLITE_CANTOPEN_NOTEMPDIR: zName = "SQLITE_CANTOPEN_NOTEMPDIR";break; case SQLITE_CANTOPEN_ISDIR: zName = "SQLITE_CANTOPEN_ISDIR"; break; case SQLITE_CANTOPEN_FULLPATH: zName = "SQLITE_CANTOPEN_FULLPATH"; break; case SQLITE_PROTOCOL: zName = "SQLITE_PROTOCOL"; break; case SQLITE_EMPTY: zName = "SQLITE_EMPTY"; break; case SQLITE_SCHEMA: zName = "SQLITE_SCHEMA"; break; case SQLITE_TOOBIG: zName = "SQLITE_TOOBIG"; break; case SQLITE_CONSTRAINT: zName = "SQLITE_CONSTRAINT"; break; case SQLITE_CONSTRAINT_UNIQUE: zName = "SQLITE_CONSTRAINT_UNIQUE"; break; case SQLITE_CONSTRAINT_TRIGGER: zName = "SQLITE_CONSTRAINT_TRIGGER";break; case SQLITE_CONSTRAINT_FOREIGNKEY: zName = "SQLITE_CONSTRAINT_FOREIGNKEY"; break; case SQLITE_CONSTRAINT_CHECK: zName = "SQLITE_CONSTRAINT_CHECK"; break; case SQLITE_CONSTRAINT_PRIMARYKEY: zName = "SQLITE_CONSTRAINT_PRIMARYKEY"; break; case SQLITE_CONSTRAINT_NOTNULL: zName = "SQLITE_CONSTRAINT_NOTNULL";break; case SQLITE_CONSTRAINT_COMMITHOOK: zName = "SQLITE_CONSTRAINT_COMMITHOOK"; break; case SQLITE_CONSTRAINT_VTAB: zName = "SQLITE_CONSTRAINT_VTAB"; break; case SQLITE_CONSTRAINT_FUNCTION: zName = "SQLITE_CONSTRAINT_FUNCTION"; break; case SQLITE_MISMATCH: zName = "SQLITE_MISMATCH"; break; case SQLITE_MISUSE: zName = "SQLITE_MISUSE"; break; case SQLITE_NOLFS: zName = "SQLITE_NOLFS"; break; case SQLITE_AUTH: zName = "SQLITE_AUTH"; break; case SQLITE_FORMAT: zName = "SQLITE_FORMAT"; break; case SQLITE_RANGE: zName = "SQLITE_RANGE"; break; case SQLITE_NOTADB: zName = "SQLITE_NOTADB"; break; case SQLITE_ROW: zName = "SQLITE_ROW"; break; case SQLITE_NOTICE: zName = "SQLITE_NOTICE"; break; case SQLITE_NOTICE_RECOVER_WAL: zName = "SQLITE_NOTICE_RECOVER_WAL";break; case SQLITE_NOTICE_RECOVER_ROLLBACK: zName = "SQLITE_NOTICE_RECOVER_ROLLBACK"; break; case SQLITE_WARNING: zName = "SQLITE_WARNING"; break; case SQLITE_DONE: zName = "SQLITE_DONE"; break; } } if( zName==0 ){ static char zBuf[50]; sqlite3_snprintf(sizeof(zBuf), zBuf, "SQLITE_UNKNOWN(%d)", origRc); zName = zBuf; } return zName; } #endif /* ** Return a static string that describes the kind of error specified in the ** argument. */ const char *sqlite3ErrStr(int rc){ static const char* const aMsg[] = { /* SQLITE_OK */ "not an error", |
︙ | ︙ | |||
2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 | db->magic = SQLITE_MAGIC_BUSY; db->aDb = db->aDbStatic; assert( sizeof(db->aLimit)==sizeof(aHardLimit) ); memcpy(db->aLimit, aHardLimit, sizeof(db->aLimit)); db->autoCommit = 1; db->nextAutovac = -1; db->nextPagesize = 0; db->flags |= SQLITE_ShortColNames | SQLITE_AutoIndex | SQLITE_EnableTrigger #if SQLITE_DEFAULT_FILE_FORMAT<4 | SQLITE_LegacyFileFmt #endif #ifdef SQLITE_ENABLE_LOAD_EXTENSION | SQLITE_LoadExtension | > | 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 | db->magic = SQLITE_MAGIC_BUSY; db->aDb = db->aDbStatic; assert( sizeof(db->aLimit)==sizeof(aHardLimit) ); memcpy(db->aLimit, aHardLimit, sizeof(db->aLimit)); db->autoCommit = 1; db->nextAutovac = -1; db->szMmap = sqlite3GlobalConfig.szMmap; db->nextPagesize = 0; db->flags |= SQLITE_ShortColNames | SQLITE_AutoIndex | SQLITE_EnableTrigger #if SQLITE_DEFAULT_FILE_FORMAT<4 | SQLITE_LegacyFileFmt #endif #ifdef SQLITE_ENABLE_LOAD_EXTENSION | SQLITE_LoadExtension |
︙ | ︙ |
Changes to src/memjournal.c.
︙ | ︙ | |||
226 227 228 229 230 231 232 | 0, /* xCheckReservedLock */ 0, /* xFileControl */ 0, /* xSectorSize */ 0, /* xDeviceCharacteristics */ 0, /* xShmMap */ 0, /* xShmLock */ 0, /* xShmBarrier */ | > > | | 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 | 0, /* xCheckReservedLock */ 0, /* xFileControl */ 0, /* xSectorSize */ 0, /* xDeviceCharacteristics */ 0, /* xShmMap */ 0, /* xShmLock */ 0, /* xShmBarrier */ 0, /* xShmUnmap */ 0, /* xFetch */ 0 /* xUnfetch */ }; /* ** Open a journal file. */ void sqlite3MemJournalOpen(sqlite3_file *pJfd){ MemJournal *p = (MemJournal *)pJfd; |
︙ | ︙ |
Changes to src/os.c.
︙ | ︙ | |||
136 137 138 139 140 141 142 143 144 145 146 147 148 149 | int pgsz, int bExtend, /* True to extend file if necessary */ void volatile **pp /* OUT: Pointer to mapping */ ){ DO_OS_MALLOC_TEST(id); return id->pMethods->xShmMap(id, iPage, pgsz, bExtend, pp); } /* ** The next group of routines are convenience wrappers around the ** VFS methods. */ int sqlite3OsOpen( sqlite3_vfs *pVfs, | > > > > > > > > > > > > > > > > > > > > | 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 | int pgsz, int bExtend, /* True to extend file if necessary */ void volatile **pp /* OUT: Pointer to mapping */ ){ DO_OS_MALLOC_TEST(id); return id->pMethods->xShmMap(id, iPage, pgsz, bExtend, pp); } #if SQLITE_MAX_MMAP_SIZE>0 /* The real implementation of xFetch and xUnfetch */ int sqlite3OsFetch(sqlite3_file *id, i64 iOff, int iAmt, void **pp){ DO_OS_MALLOC_TEST(id); return id->pMethods->xFetch(id, iOff, iAmt, pp); } int sqlite3OsUnfetch(sqlite3_file *id, i64 iOff, void *p){ return id->pMethods->xUnfetch(id, iOff, p); } #else /* No-op stubs to use when memory-mapped I/O is disabled */ int sqlite3OsFetch(sqlite3_file *id, i64 iOff, int iAmt, void **pp){ *pp = 0; return SQLITE_OK; } int sqlite3OsUnfetch(sqlite3_file *id, i64 iOff, void *p){ return SQLITE_OK; } #endif /* ** The next group of routines are convenience wrappers around the ** VFS methods. */ int sqlite3OsOpen( sqlite3_vfs *pVfs, |
︙ | ︙ |
Changes to src/os.h.
︙ | ︙ | |||
95 96 97 98 99 100 101 | ** Determine if we are dealing with WinRT, which provides only a subset of ** the full Win32 API. */ #if !defined(SQLITE_OS_WINRT) # define SQLITE_OS_WINRT 0 #endif | < < < < < < < < | 95 96 97 98 99 100 101 102 103 104 105 106 107 108 | ** Determine if we are dealing with WinRT, which provides only a subset of ** the full Win32 API. */ #if !defined(SQLITE_OS_WINRT) # define SQLITE_OS_WINRT 0 #endif /* If the SET_FULLSYNC macro is not defined above, then make it ** a no-op */ #ifndef SET_FULLSYNC # define SET_FULLSYNC(x,y) #endif |
︙ | ︙ | |||
255 256 257 258 259 260 261 262 263 264 265 266 267 268 | #define SQLITE_FCNTL_DB_UNCHANGED 0xca093fa0 int sqlite3OsSectorSize(sqlite3_file *id); int sqlite3OsDeviceCharacteristics(sqlite3_file *id); int sqlite3OsShmMap(sqlite3_file *,int,int,int,void volatile **); int sqlite3OsShmLock(sqlite3_file *id, int, int, int); void sqlite3OsShmBarrier(sqlite3_file *id); int sqlite3OsShmUnmap(sqlite3_file *id, int); /* ** Functions for accessing sqlite3_vfs methods */ int sqlite3OsOpen(sqlite3_vfs *, const char *, sqlite3_file*, int, int *); int sqlite3OsDelete(sqlite3_vfs *, const char *, int); | > > | 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 | #define SQLITE_FCNTL_DB_UNCHANGED 0xca093fa0 int sqlite3OsSectorSize(sqlite3_file *id); int sqlite3OsDeviceCharacteristics(sqlite3_file *id); int sqlite3OsShmMap(sqlite3_file *,int,int,int,void volatile **); int sqlite3OsShmLock(sqlite3_file *id, int, int, int); void sqlite3OsShmBarrier(sqlite3_file *id); int sqlite3OsShmUnmap(sqlite3_file *id, int); int sqlite3OsFetch(sqlite3_file *id, i64, int, void **); int sqlite3OsUnfetch(sqlite3_file *, i64, void *); /* ** Functions for accessing sqlite3_vfs methods */ int sqlite3OsOpen(sqlite3_vfs *, const char *, sqlite3_file*, int, int *); int sqlite3OsDelete(sqlite3_vfs *, const char *, int); |
︙ | ︙ |
Changes to src/os_unix.c.
︙ | ︙ | |||
122 123 124 125 126 127 128 | #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <time.h> #include <sys/time.h> #include <errno.h> | | | 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 | #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <time.h> #include <sys/time.h> #include <errno.h> #if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0 #include <sys/mman.h> #endif #if SQLITE_ENABLE_LOCKING_STYLE # include <sys/ioctl.h> # if OS_VXWORKS |
︙ | ︙ | |||
221 222 223 224 225 226 227 228 229 230 231 232 233 234 | unsigned short int ctrlFlags; /* Behavioral bits. UNIXFILE_* flags */ int lastErrno; /* The unix errno from last I/O error */ void *lockingContext; /* Locking style specific state */ UnixUnusedFd *pUnused; /* Pre-allocated UnixUnusedFd */ const char *zPath; /* Name of the file */ unixShm *pShm; /* Shared memory segment information */ int szChunk; /* Configured by FCNTL_CHUNK_SIZE */ #ifdef __QNXNTO__ int sectorSize; /* Device sector size */ int deviceCharacteristics; /* Precomputed device characteristics */ #endif #if SQLITE_ENABLE_LOCKING_STYLE int openFlags; /* The flags specified at open() */ #endif | > > > > > | 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 | unsigned short int ctrlFlags; /* Behavioral bits. UNIXFILE_* flags */ int lastErrno; /* The unix errno from last I/O error */ void *lockingContext; /* Locking style specific state */ UnixUnusedFd *pUnused; /* Pre-allocated UnixUnusedFd */ const char *zPath; /* Name of the file */ unixShm *pShm; /* Shared memory segment information */ int szChunk; /* Configured by FCNTL_CHUNK_SIZE */ int nFetchOut; /* Number of outstanding xFetch refs */ sqlite3_int64 mmapSize; /* Usable size of mapping at pMapRegion */ sqlite3_int64 mmapSizeActual; /* Actual size of mapping at pMapRegion */ sqlite3_int64 mmapSizeMax; /* Configured FCNTL_MMAP_SIZE value */ void *pMapRegion; /* Memory mapped region */ #ifdef __QNXNTO__ int sectorSize; /* Device sector size */ int deviceCharacteristics; /* Precomputed device characteristics */ #endif #if SQLITE_ENABLE_LOCKING_STYLE int openFlags; /* The flags specified at open() */ #endif |
︙ | ︙ | |||
245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 | ** occur if a file is updated without also updating the transaction ** counter. This test is made to avoid new problems similar to the ** one described by ticket #3584. */ unsigned char transCntrChng; /* True if the transaction counter changed */ unsigned char dbUpdate; /* True if any part of database file changed */ unsigned char inNormalWrite; /* True if in a normal write operation */ #endif #ifdef SQLITE_TEST /* In test mode, increase the size of this structure a bit so that ** it is larger than the struct CrashFile defined in test6.c. */ char aPadding[32]; #endif }; | > > | 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 | ** occur if a file is updated without also updating the transaction ** counter. This test is made to avoid new problems similar to the ** one described by ticket #3584. */ unsigned char transCntrChng; /* True if the transaction counter changed */ unsigned char dbUpdate; /* True if any part of database file changed */ unsigned char inNormalWrite; /* True if in a normal write operation */ #endif #ifdef SQLITE_TEST /* In test mode, increase the size of this structure a bit so that ** it is larger than the struct CrashFile defined in test6.c. */ char aPadding[32]; #endif }; |
︙ | ︙ | |||
269 270 271 272 273 274 275 276 277 278 279 280 281 282 | #else # define UNIXFILE_DIRSYNC 0x00 #endif #define UNIXFILE_PSOW 0x10 /* SQLITE_IOCAP_POWERSAFE_OVERWRITE */ #define UNIXFILE_DELETE 0x20 /* Delete on close */ #define UNIXFILE_URI 0x40 /* Filename might have query parameters */ #define UNIXFILE_NOLOCK 0x80 /* Do no file locking */ /* ** Include code that is common to all os_*.c files */ #include "os_common.h" /* | > | 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 | #else # define UNIXFILE_DIRSYNC 0x00 #endif #define UNIXFILE_PSOW 0x10 /* SQLITE_IOCAP_POWERSAFE_OVERWRITE */ #define UNIXFILE_DELETE 0x20 /* Delete on close */ #define UNIXFILE_URI 0x40 /* Filename might have query parameters */ #define UNIXFILE_NOLOCK 0x80 /* Do no file locking */ #define UNIXFILE_WARNED 0x0100 /* verifyDbFile() warnings have been issued */ /* ** Include code that is common to all os_*.c files */ #include "os_common.h" /* |
︙ | ︙ | |||
302 303 304 305 306 307 308 309 310 311 312 313 314 315 | */ #if SQLITE_THREADSAFE #define threadid pthread_self() #else #define threadid 0 #endif /* ** Different Unix systems declare open() in different ways. Same use ** open(const char*,int,mode_t). Others use open(const char*,int,...). ** The difference is important when using a pointer to the function. ** ** The safest way to deal with the problem is to always use this wrapper ** which always has the same well-defined interface. | > > > > > > > > > > > | 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 | */ #if SQLITE_THREADSAFE #define threadid pthread_self() #else #define threadid 0 #endif /* ** HAVE_MREMAP defaults to true on Linux and false everywhere else. */ #if !defined(HAVE_MREMAP) # if defined(__linux__) && defined(_GNU_SOURCE) # define HAVE_MREMAP 1 # else # define HAVE_MREMAP 0 # endif #endif /* ** Different Unix systems declare open() in different ways. Same use ** open(const char*,int,mode_t). Others use open(const char*,int,...). ** The difference is important when using a pointer to the function. ** ** The safest way to deal with the problem is to always use this wrapper ** which always has the same well-defined interface. |
︙ | ︙ | |||
333 334 335 336 337 338 339 | /* ** Many system calls are accessed through pointer-to-functions so that ** they may be overridden at runtime to facilitate fault injection during ** testing and sandboxing. The following array holds the names and pointers ** to all overrideable system calls. */ static struct unix_syscall { | | | 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 | /* ** Many system calls are accessed through pointer-to-functions so that ** they may be overridden at runtime to facilitate fault injection during ** testing and sandboxing. The following array holds the names and pointers ** to all overrideable system calls. */ static struct unix_syscall { const char *zName; /* Name of the system call */ sqlite3_syscall_ptr pCurrent; /* Current value of the system call */ sqlite3_syscall_ptr pDefault; /* Default value */ } aSyscall[] = { { "open", (sqlite3_syscall_ptr)posixOpen, 0 }, #define osOpen ((int(*)(const char*,int,int))aSyscall[0].pCurrent) { "close", (sqlite3_syscall_ptr)close, 0 }, |
︙ | ︙ | |||
433 434 435 436 437 438 439 440 441 442 443 444 445 446 | { "rmdir", (sqlite3_syscall_ptr)rmdir, 0 }, #define osRmdir ((int(*)(const char*))aSyscall[19].pCurrent) { "fchown", (sqlite3_syscall_ptr)posixFchown, 0 }, #define osFchown ((int(*)(int,uid_t,gid_t))aSyscall[20].pCurrent) }; /* End of the overrideable system calls */ /* ** This is the xSetSystemCall() method of sqlite3_vfs for all of the ** "unix" VFSes. Return SQLITE_OK opon successfully updating the ** system call pointer, or SQLITE_NOTFOUND if there is no configurable ** system call named zName. | > > > > > > > > > > > > > | 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 | { "rmdir", (sqlite3_syscall_ptr)rmdir, 0 }, #define osRmdir ((int(*)(const char*))aSyscall[19].pCurrent) { "fchown", (sqlite3_syscall_ptr)posixFchown, 0 }, #define osFchown ((int(*)(int,uid_t,gid_t))aSyscall[20].pCurrent) { "mmap", (sqlite3_syscall_ptr)mmap, 0 }, #define osMmap ((void*(*)(void*,size_t,int,int,int,off_t))aSyscall[21].pCurrent) { "munmap", (sqlite3_syscall_ptr)munmap, 0 }, #define osMunmap ((void*(*)(void*,size_t))aSyscall[22].pCurrent) #if HAVE_MREMAP { "mremap", (sqlite3_syscall_ptr)mremap, 0 }, #else { "mremap", (sqlite3_syscall_ptr)0, 0 }, #endif #define osMremap ((void*(*)(void*,size_t,size_t,int,...))aSyscall[23].pCurrent) }; /* End of the overrideable system calls */ /* ** This is the xSetSystemCall() method of sqlite3_vfs for all of the ** "unix" VFSes. Return SQLITE_OK opon successfully updating the ** system call pointer, or SQLITE_NOTFOUND if there is no configurable ** system call named zName. |
︙ | ︙ | |||
762 763 764 765 766 767 768 | case ENOSYS: /* these should force the client to close the file and reconnect */ default: return sqliteIOErr; } } | < | 794 795 796 797 798 799 800 801 802 803 804 805 806 807 | case ENOSYS: /* these should force the client to close the file and reconnect */ default: return sqliteIOErr; } } /****************************************************************************** ****************** Begin Unique File ID Utility Used By VxWorks *************** ** ** On most versions of unix, we can get a unique ID for a file by concatenating ** the device number and the inode number. But this does not work on VxWorks. |
︙ | ︙ | |||
1100 1101 1102 1103 1104 1105 1106 | /* This is a threadsafe build, but strerror_r() is not available. */ zErr = ""; #else /* Non-threadsafe build, use strerror(). */ zErr = strerror(iErrno); #endif | < | 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 | /* This is a threadsafe build, but strerror_r() is not available. */ zErr = ""; #else /* Non-threadsafe build, use strerror(). */ zErr = strerror(iErrno); #endif if( zPath==0 ) zPath = ""; sqlite3_log(errcode, "os_unix.c:%d: (%d) %s(%s) - %s", iLine, iErrno, zFunc, zPath, zErr ); return errcode; |
︙ | ︙ | |||
1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 | }else{ pInode->nRef++; } *ppInode = pInode; return SQLITE_OK; } /* ** This routine checks if there is a RESERVED lock held on the specified ** file by this or any other process. If such a lock is held, set *pResOut ** to a non-zero value otherwise *pResOut is set to zero. The return value ** is set to SQLITE_OK unless an I/O error occurs during lock checking. */ | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 | }else{ pInode->nRef++; } *ppInode = pInode; return SQLITE_OK; } /* ** Check a unixFile that is a database. Verify the following: ** ** (1) There is exactly one hard link on the file ** (2) The file is not a symbolic link ** (3) The file has not been renamed or unlinked ** ** Issue sqlite3_log(SQLITE_WARNING,...) messages if anything is not right. */ static void verifyDbFile(unixFile *pFile){ struct stat buf; int rc; if( pFile->ctrlFlags & UNIXFILE_WARNED ){ /* One or more of the following warnings have already been issued. Do not ** repeat them so as not to clutter the error log */ return; } rc = osFstat(pFile->h, &buf); if( rc!=0 ){ sqlite3_log(SQLITE_WARNING, "cannot fstat db file %s", pFile->zPath); pFile->ctrlFlags |= UNIXFILE_WARNED; return; } if( buf.st_nlink==0 && (pFile->ctrlFlags & UNIXFILE_DELETE)==0 ){ sqlite3_log(SQLITE_WARNING, "file unlinked while open: %s", pFile->zPath); pFile->ctrlFlags |= UNIXFILE_WARNED; return; } if( buf.st_nlink>1 ){ sqlite3_log(SQLITE_WARNING, "multiple links to file: %s", pFile->zPath); pFile->ctrlFlags |= UNIXFILE_WARNED; return; } if( pFile->pInode!=0 && ((rc = osStat(pFile->zPath, &buf))!=0 || buf.st_ino!=pFile->pInode->fileId.ino) ){ sqlite3_log(SQLITE_WARNING, "file renamed while open: %s", pFile->zPath); pFile->ctrlFlags |= UNIXFILE_WARNED; return; } } /* ** This routine checks if there is a RESERVED lock held on the specified ** file by this or any other process. If such a lock is held, set *pResOut ** to a non-zero value otherwise *pResOut is set to zero. The return value ** is set to SQLITE_OK unless an I/O error occurs during lock checking. */ |
︙ | ︙ | |||
1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 | ** Lower the locking level on file descriptor pFile to eFileLock. eFileLock ** must be either NO_LOCK or SHARED_LOCK. ** ** If the locking level of the file descriptor is already at or below ** the requested locking level, this routine is a no-op. */ static int unixUnlock(sqlite3_file *id, int eFileLock){ return posixUnlock(id, eFileLock, 0); } /* ** This function performs the parts of the "close file" operation ** common to all locking schemes. It closes the directory and file ** handles, if they are valid, and sets all fields of the unixFile ** structure to 0. ** ** It is *not* necessary to hold the mutex when this routine is called, ** even on VxWorks. A mutex will be acquired on VxWorks by the ** vxworksReleaseFileId() routine. */ static int closeUnixFile(sqlite3_file *id){ unixFile *pFile = (unixFile*)id; if( pFile->h>=0 ){ robust_close(pFile, pFile->h, __LINE__); pFile->h = -1; } #if OS_VXWORKS if( pFile->pId ){ if( pFile->ctrlFlags & UNIXFILE_DELETE ){ | > > > > > | 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 | ** Lower the locking level on file descriptor pFile to eFileLock. eFileLock ** must be either NO_LOCK or SHARED_LOCK. ** ** If the locking level of the file descriptor is already at or below ** the requested locking level, this routine is a no-op. */ static int unixUnlock(sqlite3_file *id, int eFileLock){ assert( eFileLock==SHARED_LOCK || ((unixFile *)id)->nFetchOut==0 ); return posixUnlock(id, eFileLock, 0); } static int unixMapfile(unixFile *pFd, i64 nByte); static void unixUnmapfile(unixFile *pFd); /* ** This function performs the parts of the "close file" operation ** common to all locking schemes. It closes the directory and file ** handles, if they are valid, and sets all fields of the unixFile ** structure to 0. ** ** It is *not* necessary to hold the mutex when this routine is called, ** even on VxWorks. A mutex will be acquired on VxWorks by the ** vxworksReleaseFileId() routine. */ static int closeUnixFile(sqlite3_file *id){ unixFile *pFile = (unixFile*)id; unixUnmapfile(pFile); if( pFile->h>=0 ){ robust_close(pFile, pFile->h, __LINE__); pFile->h = -1; } #if OS_VXWORKS if( pFile->pId ){ if( pFile->ctrlFlags & UNIXFILE_DELETE ){ |
︙ | ︙ | |||
1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 | /* ** Close a file. */ static int unixClose(sqlite3_file *id){ int rc = SQLITE_OK; unixFile *pFile = (unixFile *)id; unixUnlock(id, NO_LOCK); unixEnterMutex(); /* unixFile.pInode is always valid here. Otherwise, a different close ** routine (e.g. nolockClose()) would be called instead. */ assert( pFile->pInode->nLock>0 || pFile->pInode->bProcessLock==0 ); | > | 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 | /* ** Close a file. */ static int unixClose(sqlite3_file *id){ int rc = SQLITE_OK; unixFile *pFile = (unixFile *)id; verifyDbFile(pFile); unixUnlock(id, NO_LOCK); unixEnterMutex(); /* unixFile.pInode is always valid here. Otherwise, a different close ** routine (e.g. nolockClose()) would be called instead. */ assert( pFile->pInode->nLock>0 || pFile->pInode->bProcessLock==0 ); |
︙ | ︙ | |||
1905 1906 1907 1908 1909 1910 1911 | /******************* End of the no-op lock implementation ********************* ******************************************************************************/ /****************************************************************************** ************************* Begin dot-file Locking ****************************** ** | | | | 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 2012 2013 2014 | /******************* End of the no-op lock implementation ********************* ******************************************************************************/ /****************************************************************************** ************************* Begin dot-file Locking ****************************** ** ** The dotfile locking implementation uses the existence of separate lock ** files (really a directory) to control access to the database. This works ** on just about every filesystem imaginable. But there are serious downsides: ** ** (1) There is zero concurrency. A single reader blocks all other ** connections from reading or writing the database. ** ** (2) An application crash or power loss can leave stale lock files ** sitting around that need to be cleared manually. ** ** Nevertheless, a dotlock is an appropriate locking mode for use if no ** other locking strategy is available. ** ** Dotfile locking works by creating a subdirectory in the same directory as ** the database and with the same name but with a ".lock" extension added. ** The existence of a lock directory implies an EXCLUSIVE lock. All other ** lock types (SHARED, RESERVED, PENDING) are mapped into EXCLUSIVE. */ /* ** The file suffix added to the data base filename in order to create the ** lock directory. */ |
︙ | ︙ | |||
3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 | void *pBuf, int amt, sqlite3_int64 offset ){ unixFile *pFile = (unixFile *)id; int got; assert( id ); /* If this is a database file (not a journal, master-journal or temp ** file), the bytes in the locking range should never be read or written. */ #if 0 assert( pFile->pUnused==0 || offset>=PENDING_BYTE+512 || offset+amt<=PENDING_BYTE ); #endif got = seekAndRead(pFile, offset, pBuf, amt); if( got==amt ){ return SQLITE_OK; }else if( got<0 ){ /* lastErrno set by seekAndRead */ return SQLITE_IOERR_READ; }else{ pFile->lastErrno = 0; /* not a system error */ /* Unread parts of the buffer must be zero-filled */ memset(&((char*)pBuf)[got], 0, amt-got); return SQLITE_IOERR_SHORT_READ; } } /* ** Seek to the offset in id->offset then read cnt bytes into pBuf. ** Return the number of bytes actually read. Update the offset. ** ** To avoid stomping the errno value on a failed write the lastErrno value ** is set before returning. */ static int seekAndWrite(unixFile *id, i64 offset, const void *pBuf, int cnt){ | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < | 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 | void *pBuf, int amt, sqlite3_int64 offset ){ unixFile *pFile = (unixFile *)id; int got; assert( id ); assert( offset>=0 ); assert( amt>0 ); /* If this is a database file (not a journal, master-journal or temp ** file), the bytes in the locking range should never be read or written. */ #if 0 assert( pFile->pUnused==0 || offset>=PENDING_BYTE+512 || offset+amt<=PENDING_BYTE ); #endif #if SQLITE_MAX_MMAP_SIZE>0 /* Deal with as much of this read request as possible by transfering ** data from the memory mapping using memcpy(). */ if( offset<pFile->mmapSize ){ if( offset+amt <= pFile->mmapSize ){ memcpy(pBuf, &((u8 *)(pFile->pMapRegion))[offset], amt); return SQLITE_OK; }else{ int nCopy = pFile->mmapSize - offset; memcpy(pBuf, &((u8 *)(pFile->pMapRegion))[offset], nCopy); pBuf = &((u8 *)pBuf)[nCopy]; amt -= nCopy; offset += nCopy; } } #endif got = seekAndRead(pFile, offset, pBuf, amt); if( got==amt ){ return SQLITE_OK; }else if( got<0 ){ /* lastErrno set by seekAndRead */ return SQLITE_IOERR_READ; }else{ pFile->lastErrno = 0; /* not a system error */ /* Unread parts of the buffer must be zero-filled */ memset(&((char*)pBuf)[got], 0, amt-got); return SQLITE_IOERR_SHORT_READ; } } /* ** Attempt to seek the file-descriptor passed as the first argument to ** absolute offset iOff, then attempt to write nBuf bytes of data from ** pBuf to it. If an error occurs, return -1 and set *piErrno. Otherwise, ** return the actual number of bytes written (which may be less than ** nBuf). */ static int seekAndWriteFd( int fd, /* File descriptor to write to */ i64 iOff, /* File offset to begin writing at */ const void *pBuf, /* Copy data from this buffer to the file */ int nBuf, /* Size of buffer pBuf in bytes */ int *piErrno /* OUT: Error number if error occurs */ ){ int rc = 0; /* Value returned by system call */ assert( nBuf==(nBuf&0x1ffff) ); nBuf &= 0x1ffff; TIMER_START; #if defined(USE_PREAD) do{ rc = osPwrite(fd, pBuf, nBuf, iOff); }while( rc<0 && errno==EINTR ); #elif defined(USE_PREAD64) do{ rc = osPwrite64(fd, pBuf, nBuf, iOff);}while( rc<0 && errno==EINTR); #else do{ i64 iSeek = lseek(fd, iOff, SEEK_SET); SimulateIOError( iSeek-- ); if( iSeek!=iOff ){ if( piErrno ) *piErrno = (iSeek==-1 ? errno : 0); return -1; } rc = osWrite(fd, pBuf, nBuf); }while( rc<0 && errno==EINTR ); #endif TIMER_END; OSTRACE(("WRITE %-3d %5d %7lld %llu\n", fd, rc, iOff, TIMER_ELAPSED)); if( rc<0 && piErrno ) *piErrno = errno; return rc; } /* ** Seek to the offset in id->offset then read cnt bytes into pBuf. ** Return the number of bytes actually read. Update the offset. ** ** To avoid stomping the errno value on a failed write the lastErrno value ** is set before returning. */ static int seekAndWrite(unixFile *id, i64 offset, const void *pBuf, int cnt){ return seekAndWriteFd(id->h, offset, pBuf, cnt, &id->lastErrno); } /* ** Write data from a buffer into a file. Return SQLITE_OK on success ** or some other error code on failure. */ |
︙ | ︙ | |||
3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 | SimulateIOErrorBenign(1); rc = seekAndRead(pFile, 24, oldCntr, 4); SimulateIOErrorBenign(0); if( rc!=4 || memcmp(oldCntr, &((char*)pBuf)[24-offset], 4)!=0 ){ pFile->transCntrChng = 1; /* The transaction counter has changed */ } } } #endif while( amt>0 && (wrote = seekAndWrite(pFile, offset, pBuf, amt))>0 ){ amt -= wrote; offset += wrote; pBuf = &((char*)pBuf)[wrote]; | > > > > > > > > > > > > > > > > > | 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 | SimulateIOErrorBenign(1); rc = seekAndRead(pFile, 24, oldCntr, 4); SimulateIOErrorBenign(0); if( rc!=4 || memcmp(oldCntr, &((char*)pBuf)[24-offset], 4)!=0 ){ pFile->transCntrChng = 1; /* The transaction counter has changed */ } } } #endif #if SQLITE_MAX_MMAP_SIZE>0 /* Deal with as much of this write request as possible by transfering ** data from the memory mapping using memcpy(). */ if( offset<pFile->mmapSize ){ if( offset+amt <= pFile->mmapSize ){ memcpy(&((u8 *)(pFile->pMapRegion))[offset], pBuf, amt); return SQLITE_OK; }else{ int nCopy = pFile->mmapSize - offset; memcpy(&((u8 *)(pFile->pMapRegion))[offset], pBuf, nCopy); pBuf = &((u8 *)pBuf)[nCopy]; amt -= nCopy; offset += nCopy; } } #endif while( amt>0 && (wrote = seekAndWrite(pFile, offset, pBuf, amt))>0 ){ amt -= wrote; offset += wrote; pBuf = &((char*)pBuf)[wrote]; |
︙ | ︙ | |||
3409 3410 3411 3412 3413 3414 3415 | SimulateIOError( rc=1 ); if( rc ){ pFile->lastErrno = errno; return unixLogError(SQLITE_IOERR_FSYNC, "full_fsync", pFile->zPath); } /* Also fsync the directory containing the file if the DIRSYNC flag | | | 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 3551 3552 | SimulateIOError( rc=1 ); if( rc ){ pFile->lastErrno = errno; return unixLogError(SQLITE_IOERR_FSYNC, "full_fsync", pFile->zPath); } /* Also fsync the directory containing the file if the DIRSYNC flag ** is set. This is a one-time occurrence. Many systems (examples: AIX) ** are unable to fsync a directory, so ignore errors on the fsync. */ if( pFile->ctrlFlags & UNIXFILE_DIRSYNC ){ int dirfd; OSTRACE(("DIRSYNC %s (have_fullfsync=%d fullsync=%d)\n", pFile->zPath, HAVE_FULLFSYNC, isFullsync)); rc = osOpenDirectory(pFile->zPath, &dirfd); |
︙ | ︙ | |||
3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 | ** when restoring a database using the backup API from a zero-length ** source. */ if( pFile->inNormalWrite && nByte==0 ){ pFile->transCntrChng = 1; } #endif return SQLITE_OK; } } /* ** Determine the current size of a file in bytes | > > > > > > > > | 3592 3593 3594 3595 3596 3597 3598 3599 3600 3601 3602 3603 3604 3605 3606 3607 3608 3609 3610 3611 3612 3613 | ** when restoring a database using the backup API from a zero-length ** source. */ if( pFile->inNormalWrite && nByte==0 ){ pFile->transCntrChng = 1; } #endif /* If the file was just truncated to a size smaller than the currently ** mapped region, reduce the effective mapping size as well. SQLite will ** use read() and write() to access data beyond this point from now on. */ if( nByte<pFile->mmapSize ){ pFile->mmapSize = nByte; } return SQLITE_OK; } } /* ** Determine the current size of a file in bytes |
︙ | ︙ | |||
3551 3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 3564 | int nWrite = seekAndWrite(pFile, iWrite, "", 1); if( nWrite!=1 ) return SQLITE_IOERR_WRITE; iWrite += nBlk; } #endif } } return SQLITE_OK; } /* ** If *pArg is inititially negative then this is a query. Set *pArg to ** 1 or 0 depending on whether or not bit mask of pFile->ctrlFlags is set. | > > > > > > > > > > > > > | 3688 3689 3690 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 | int nWrite = seekAndWrite(pFile, iWrite, "", 1); if( nWrite!=1 ) return SQLITE_IOERR_WRITE; iWrite += nBlk; } #endif } } if( pFile->mmapSizeMax>0 && nByte>pFile->mmapSize ){ int rc; if( pFile->szChunk<=0 ){ if( robust_ftruncate(pFile->h, nByte) ){ pFile->lastErrno = errno; return unixLogError(SQLITE_IOERR_TRUNCATE, "ftruncate", pFile->zPath); } } rc = unixMapfile(pFile, nByte); return rc; } return SQLITE_OK; } /* ** If *pArg is inititially negative then this is a query. Set *pArg to ** 1 or 0 depending on whether or not bit mask of pFile->ctrlFlags is set. |
︙ | ︙ | |||
3618 3619 3620 3621 3622 3623 3624 3625 3626 3627 3628 3629 3630 3631 | case SQLITE_FCNTL_TEMPFILENAME: { char *zTFile = sqlite3_malloc( pFile->pVfs->mxPathname ); if( zTFile ){ unixGetTempname(pFile->pVfs->mxPathname, zTFile); *(char**)pArg = zTFile; } return SQLITE_OK; } #ifdef SQLITE_DEBUG /* The pager calls this method to signal that it has done ** a rollback and that the database is therefore unchanged and ** it hence it is OK for the transaction change counter to be ** unchanged. */ | > > > > > > > > > > > > | 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 | case SQLITE_FCNTL_TEMPFILENAME: { char *zTFile = sqlite3_malloc( pFile->pVfs->mxPathname ); if( zTFile ){ unixGetTempname(pFile->pVfs->mxPathname, zTFile); *(char**)pArg = zTFile; } return SQLITE_OK; } case SQLITE_FCNTL_MMAP_SIZE: { i64 newLimit = *(i64*)pArg; if( newLimit>sqlite3GlobalConfig.mxMmap ){ newLimit = sqlite3GlobalConfig.mxMmap; } *(i64*)pArg = pFile->mmapSizeMax; if( newLimit>=0 ){ pFile->mmapSizeMax = newLimit; if( newLimit<pFile->mmapSize ) pFile->mmapSize = newLimit; } return SQLITE_OK; } #ifdef SQLITE_DEBUG /* The pager calls this method to signal that it has done ** a rollback and that the database is therefore unchanged and ** it hence it is OK for the transaction change counter to be ** unchanged. */ |
︙ | ︙ | |||
3931 3932 3933 3934 3935 3936 3937 | assert( unixMutexHeld() ); if( p && p->nRef==0 ){ int i; assert( p->pInode==pFd->pInode ); sqlite3_mutex_free(p->mutex); for(i=0; i<p->nRegion; i++){ if( p->h>=0 ){ | | | 4093 4094 4095 4096 4097 4098 4099 4100 4101 4102 4103 4104 4105 4106 4107 | assert( unixMutexHeld() ); if( p && p->nRef==0 ){ int i; assert( p->pInode==pFd->pInode ); sqlite3_mutex_free(p->mutex); for(i=0; i<p->nRegion; i++){ if( p->h>=0 ){ osMunmap(p->apRegion[i], p->szRegion); }else{ sqlite3_free(p->apRegion[i]); } } sqlite3_free(p->apRegion); if( p->h>=0 ){ robust_close(pFd, p->h, __LINE__); |
︙ | ︙ | |||
4171 4172 4173 4174 4175 4176 4177 | rc = SQLITE_IOERR_SHMSIZE; goto shmpage_out; } if( sStat.st_size<nByte ){ /* The requested memory region does not exist. If bExtend is set to ** false, exit early. *pp will be set to NULL and SQLITE_OK returned. | < < < | < < < < > > > > > > > > | > > | > > > > > | < < > > | | 4333 4334 4335 4336 4337 4338 4339 4340 4341 4342 4343 4344 4345 4346 4347 4348 4349 4350 4351 4352 4353 4354 4355 4356 4357 4358 4359 4360 4361 4362 4363 4364 4365 4366 4367 4368 4369 4370 4371 4372 4373 4374 4375 4376 4377 4378 4379 4380 4381 4382 4383 4384 4385 4386 4387 4388 | rc = SQLITE_IOERR_SHMSIZE; goto shmpage_out; } if( sStat.st_size<nByte ){ /* The requested memory region does not exist. If bExtend is set to ** false, exit early. *pp will be set to NULL and SQLITE_OK returned. */ if( !bExtend ){ goto shmpage_out; } /* Alternatively, if bExtend is true, extend the file. Do this by ** writing a single byte to the end of each (OS) page being ** allocated or extended. Technically, we need only write to the ** last page in order to extend the file. But writing to all new ** pages forces the OS to allocate them immediately, which reduces ** the chances of SIGBUS while accessing the mapped region later on. */ else{ static const int pgsz = 4096; int iPg; /* Write to the last byte of each newly allocated or extended page */ assert( (nByte % pgsz)==0 ); for(iPg=(sStat.st_size/pgsz); iPg<(nByte/pgsz); iPg++){ if( seekAndWriteFd(pShmNode->h, iPg*pgsz + pgsz-1, "", 1, 0)!=1 ){ const char *zFile = pShmNode->zFilename; rc = unixLogError(SQLITE_IOERR_SHMSIZE, "write", zFile); goto shmpage_out; } } } } } /* Map the requested memory region into this processes address space. */ apNew = (char **)sqlite3_realloc( pShmNode->apRegion, (iRegion+1)*sizeof(char *) ); if( !apNew ){ rc = SQLITE_IOERR_NOMEM; goto shmpage_out; } pShmNode->apRegion = apNew; while(pShmNode->nRegion<=iRegion){ void *pMem; if( pShmNode->h>=0 ){ pMem = osMmap(0, szRegion, pShmNode->isReadonly ? PROT_READ : PROT_READ|PROT_WRITE, MAP_SHARED, pShmNode->h, szRegion*(i64)pShmNode->nRegion ); if( pMem==MAP_FAILED ){ rc = unixLogError(SQLITE_IOERR_SHMMAP, "mmap", pShmNode->zFilename); goto shmpage_out; } |
︙ | ︙ | |||
4420 4421 4422 4423 4424 4425 4426 4427 4428 4429 4430 4431 4432 4433 | #else # define unixShmMap 0 # define unixShmLock 0 # define unixShmBarrier 0 # define unixShmUnmap 0 #endif /* #ifndef SQLITE_OMIT_WAL */ /* ** Here ends the implementation of all sqlite3_file methods. ** ********************** End sqlite3_file Methods ******************************* ******************************************************************************/ | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 4590 4591 4592 4593 4594 4595 4596 4597 4598 4599 4600 4601 4602 4603 4604 4605 4606 4607 4608 4609 4610 4611 4612 4613 4614 4615 4616 4617 4618 4619 4620 4621 4622 4623 4624 4625 4626 4627 4628 4629 4630 4631 4632 4633 4634 4635 4636 4637 4638 4639 4640 4641 4642 4643 4644 4645 4646 4647 4648 4649 4650 4651 4652 4653 4654 4655 4656 4657 4658 4659 4660 4661 4662 4663 4664 4665 4666 4667 4668 4669 4670 4671 4672 4673 4674 4675 4676 4677 4678 4679 4680 4681 4682 4683 4684 4685 4686 4687 4688 4689 4690 4691 4692 4693 4694 4695 4696 4697 4698 4699 4700 4701 4702 4703 4704 4705 4706 4707 4708 4709 4710 4711 4712 4713 4714 4715 4716 4717 4718 4719 4720 4721 4722 4723 4724 4725 4726 4727 4728 4729 4730 4731 4732 4733 4734 4735 4736 4737 4738 4739 4740 4741 4742 4743 4744 4745 4746 4747 4748 4749 4750 4751 4752 4753 4754 4755 4756 4757 4758 4759 4760 4761 4762 4763 4764 4765 4766 4767 4768 4769 4770 4771 4772 4773 4774 4775 4776 4777 4778 4779 4780 4781 4782 4783 4784 4785 4786 4787 4788 4789 4790 4791 4792 4793 4794 4795 4796 4797 4798 4799 4800 4801 4802 4803 4804 4805 4806 4807 4808 4809 4810 4811 4812 4813 4814 4815 4816 4817 4818 4819 4820 4821 4822 4823 4824 4825 4826 4827 4828 4829 4830 4831 4832 4833 | #else # define unixShmMap 0 # define unixShmLock 0 # define unixShmBarrier 0 # define unixShmUnmap 0 #endif /* #ifndef SQLITE_OMIT_WAL */ /* ** If it is currently memory mapped, unmap file pFd. */ static void unixUnmapfile(unixFile *pFd){ assert( pFd->nFetchOut==0 ); #if SQLITE_MAX_MMAP_SIZE>0 if( pFd->pMapRegion ){ osMunmap(pFd->pMapRegion, pFd->mmapSizeActual); pFd->pMapRegion = 0; pFd->mmapSize = 0; pFd->mmapSizeActual = 0; } #endif } #if SQLITE_MAX_MMAP_SIZE>0 /* ** Return the system page size. */ static int unixGetPagesize(void){ #if HAVE_MREMAP return 512; #elif defined(_BSD_SOURCE) return getpagesize(); #else return (int)sysconf(_SC_PAGESIZE); #endif } #endif /* SQLITE_MAX_MMAP_SIZE>0 */ #if SQLITE_MAX_MMAP_SIZE>0 /* ** Attempt to set the size of the memory mapping maintained by file ** descriptor pFd to nNew bytes. Any existing mapping is discarded. ** ** If successful, this function sets the following variables: ** ** unixFile.pMapRegion ** unixFile.mmapSize ** unixFile.mmapSizeActual ** ** If unsuccessful, an error message is logged via sqlite3_log() and ** the three variables above are zeroed. In this case SQLite should ** continue accessing the database using the xRead() and xWrite() ** methods. */ static void unixRemapfile( unixFile *pFd, /* File descriptor object */ i64 nNew /* Required mapping size */ ){ const char *zErr = "mmap"; int h = pFd->h; /* File descriptor open on db file */ u8 *pOrig = (u8 *)pFd->pMapRegion; /* Pointer to current file mapping */ i64 nOrig = pFd->mmapSizeActual; /* Size of pOrig region in bytes */ u8 *pNew = 0; /* Location of new mapping */ int flags = PROT_READ; /* Flags to pass to mmap() */ assert( pFd->nFetchOut==0 ); assert( nNew>pFd->mmapSize ); assert( nNew<=pFd->mmapSizeMax ); assert( nNew>0 ); assert( pFd->mmapSizeActual>=pFd->mmapSize ); assert( MAP_FAILED!=0 ); if( (pFd->ctrlFlags & UNIXFILE_RDONLY)==0 ) flags |= PROT_WRITE; if( pOrig ){ const int szSyspage = unixGetPagesize(); i64 nReuse = (pFd->mmapSize & ~(szSyspage-1)); u8 *pReq = &pOrig[nReuse]; /* Unmap any pages of the existing mapping that cannot be reused. */ if( nReuse!=nOrig ){ osMunmap(pReq, nOrig-nReuse); } #if HAVE_MREMAP pNew = osMremap(pOrig, nReuse, nNew, MREMAP_MAYMOVE); zErr = "mremap"; #else pNew = osMmap(pReq, nNew-nReuse, flags, MAP_SHARED, h, nReuse); if( pNew!=MAP_FAILED ){ if( pNew!=pReq ){ osMunmap(pNew, nNew - nReuse); pNew = 0; }else{ pNew = pOrig; } } #endif /* The attempt to extend the existing mapping failed. Free it. */ if( pNew==MAP_FAILED || pNew==0 ){ osMunmap(pOrig, nReuse); } } /* If pNew is still NULL, try to create an entirely new mapping. */ if( pNew==0 ){ pNew = osMmap(0, nNew, flags, MAP_SHARED, h, 0); } if( pNew==MAP_FAILED ){ pNew = 0; nNew = 0; unixLogError(SQLITE_OK, zErr, pFd->zPath); /* If the mmap() above failed, assume that all subsequent mmap() calls ** will probably fail too. Fall back to using xRead/xWrite exclusively ** in this case. */ pFd->mmapSizeMax = 0; } pFd->pMapRegion = (void *)pNew; pFd->mmapSize = pFd->mmapSizeActual = nNew; } #endif /* ** Memory map or remap the file opened by file-descriptor pFd (if the file ** is already mapped, the existing mapping is replaced by the new). Or, if ** there already exists a mapping for this file, and there are still ** outstanding xFetch() references to it, this function is a no-op. ** ** If parameter nByte is non-negative, then it is the requested size of ** the mapping to create. Otherwise, if nByte is less than zero, then the ** requested size is the size of the file on disk. The actual size of the ** created mapping is either the requested size or the value configured ** using SQLITE_FCNTL_MMAP_LIMIT, whichever is smaller. ** ** SQLITE_OK is returned if no error occurs (even if the mapping is not ** recreated as a result of outstanding references) or an SQLite error ** code otherwise. */ static int unixMapfile(unixFile *pFd, i64 nByte){ #if SQLITE_MAX_MMAP_SIZE>0 i64 nMap = nByte; int rc; assert( nMap>=0 || pFd->nFetchOut==0 ); if( pFd->nFetchOut>0 ) return SQLITE_OK; if( nMap<0 ){ struct stat statbuf; /* Low-level file information */ rc = osFstat(pFd->h, &statbuf); if( rc!=SQLITE_OK ){ return SQLITE_IOERR_FSTAT; } nMap = statbuf.st_size; } if( nMap>pFd->mmapSizeMax ){ nMap = pFd->mmapSizeMax; } if( nMap!=pFd->mmapSize ){ if( nMap>0 ){ unixRemapfile(pFd, nMap); }else{ unixUnmapfile(pFd); } } #endif return SQLITE_OK; } /* ** If possible, return a pointer to a mapping of file fd starting at offset ** iOff. The mapping must be valid for at least nAmt bytes. ** ** If such a pointer can be obtained, store it in *pp and return SQLITE_OK. ** Or, if one cannot but no error occurs, set *pp to 0 and return SQLITE_OK. ** Finally, if an error does occur, return an SQLite error code. The final ** value of *pp is undefined in this case. ** ** If this function does return a pointer, the caller must eventually ** release the reference by calling unixUnfetch(). */ static int unixFetch(sqlite3_file *fd, i64 iOff, int nAmt, void **pp){ #if SQLITE_MAX_MMAP_SIZE>0 unixFile *pFd = (unixFile *)fd; /* The underlying database file */ #endif *pp = 0; #if SQLITE_MAX_MMAP_SIZE>0 if( pFd->mmapSizeMax>0 ){ if( pFd->pMapRegion==0 ){ int rc = unixMapfile(pFd, -1); if( rc!=SQLITE_OK ) return rc; } if( pFd->mmapSize >= iOff+nAmt ){ *pp = &((u8 *)pFd->pMapRegion)[iOff]; pFd->nFetchOut++; } } #endif return SQLITE_OK; } /* ** If the third argument is non-NULL, then this function releases a ** reference obtained by an earlier call to unixFetch(). The second ** argument passed to this function must be the same as the corresponding ** argument that was passed to the unixFetch() invocation. ** ** Or, if the third argument is NULL, then this function is being called ** to inform the VFS layer that, according to POSIX, any existing mapping ** may now be invalid and should be unmapped. */ static int unixUnfetch(sqlite3_file *fd, i64 iOff, void *p){ unixFile *pFd = (unixFile *)fd; /* The underlying database file */ UNUSED_PARAMETER(iOff); /* If p==0 (unmap the entire file) then there must be no outstanding ** xFetch references. Or, if p!=0 (meaning it is an xFetch reference), ** then there must be at least one outstanding. */ assert( (p==0)==(pFd->nFetchOut==0) ); /* If p!=0, it must match the iOff value. */ assert( p==0 || p==&((u8 *)pFd->pMapRegion)[iOff] ); if( p ){ pFd->nFetchOut--; }else{ unixUnmapfile(pFd); } assert( pFd->nFetchOut>=0 ); return SQLITE_OK; } /* ** Here ends the implementation of all sqlite3_file methods. ** ********************** End sqlite3_file Methods ******************************* ******************************************************************************/ |
︙ | ︙ | |||
4479 4480 4481 4482 4483 4484 4485 | CKLOCK, /* xCheckReservedLock */ \ unixFileControl, /* xFileControl */ \ unixSectorSize, /* xSectorSize */ \ unixDeviceCharacteristics, /* xDeviceCapabilities */ \ unixShmMap, /* xShmMap */ \ unixShmLock, /* xShmLock */ \ unixShmBarrier, /* xShmBarrier */ \ | | > > | | 4879 4880 4881 4882 4883 4884 4885 4886 4887 4888 4889 4890 4891 4892 4893 4894 4895 4896 4897 4898 4899 4900 4901 4902 4903 4904 4905 4906 4907 4908 4909 4910 4911 4912 | CKLOCK, /* xCheckReservedLock */ \ unixFileControl, /* xFileControl */ \ unixSectorSize, /* xSectorSize */ \ unixDeviceCharacteristics, /* xDeviceCapabilities */ \ unixShmMap, /* xShmMap */ \ unixShmLock, /* xShmLock */ \ unixShmBarrier, /* xShmBarrier */ \ unixShmUnmap, /* xShmUnmap */ \ unixFetch, /* xFetch */ \ unixUnfetch, /* xUnfetch */ \ }; \ static const sqlite3_io_methods *FINDER##Impl(const char *z, unixFile *p){ \ UNUSED_PARAMETER(z); UNUSED_PARAMETER(p); \ return &METHOD; \ } \ static const sqlite3_io_methods *(*const FINDER)(const char*,unixFile *p) \ = FINDER##Impl; /* ** Here are all of the sqlite3_io_methods objects for each of the ** locking strategies. Functions that return pointers to these methods ** are also created. */ IOMETHODS( posixIoFinder, /* Finder function name */ posixIoMethods, /* sqlite3_io_methods object name */ 3, /* shared memory and mmap are enabled */ unixClose, /* xClose method */ unixLock, /* xLock method */ unixUnlock, /* xUnlock method */ unixCheckReservedLock /* xCheckReservedLock method */ ) IOMETHODS( nolockIoFinder, /* Finder function name */ |
︙ | ︙ | |||
4747 4748 4749 4750 4751 4752 4753 4754 4755 4756 4757 4758 4759 4760 | assert( zFilename!=0 || (ctrlFlags & UNIXFILE_NOLOCK)!=0 ); OSTRACE(("OPEN %-3d %s\n", h, zFilename)); pNew->h = h; pNew->pVfs = pVfs; pNew->zPath = zFilename; pNew->ctrlFlags = (u8)ctrlFlags; if( sqlite3_uri_boolean(((ctrlFlags & UNIXFILE_URI) ? zFilename : 0), "psow", SQLITE_POWERSAFE_OVERWRITE) ){ pNew->ctrlFlags |= UNIXFILE_PSOW; } if( strcmp(pVfs->zName,"unix-excl")==0 ){ pNew->ctrlFlags |= UNIXFILE_EXCL; } | > | 5149 5150 5151 5152 5153 5154 5155 5156 5157 5158 5159 5160 5161 5162 5163 | assert( zFilename!=0 || (ctrlFlags & UNIXFILE_NOLOCK)!=0 ); OSTRACE(("OPEN %-3d %s\n", h, zFilename)); pNew->h = h; pNew->pVfs = pVfs; pNew->zPath = zFilename; pNew->ctrlFlags = (u8)ctrlFlags; pNew->mmapSizeMax = sqlite3GlobalConfig.mxMmap; if( sqlite3_uri_boolean(((ctrlFlags & UNIXFILE_URI) ? zFilename : 0), "psow", SQLITE_POWERSAFE_OVERWRITE) ){ pNew->ctrlFlags |= UNIXFILE_PSOW; } if( strcmp(pVfs->zName,"unix-excl")==0 ){ pNew->ctrlFlags |= UNIXFILE_EXCL; } |
︙ | ︙ | |||
4783 4784 4785 4786 4787 4788 4789 | #if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE || pLockingStyle == &nfsIoMethods #endif ){ unixEnterMutex(); rc = findInodeInfo(pNew, &pNew->pInode); if( rc!=SQLITE_OK ){ | | | 5186 5187 5188 5189 5190 5191 5192 5193 5194 5195 5196 5197 5198 5199 5200 | #if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE || pLockingStyle == &nfsIoMethods #endif ){ unixEnterMutex(); rc = findInodeInfo(pNew, &pNew->pInode); if( rc!=SQLITE_OK ){ /* If an error occurred in findInodeInfo(), close the file descriptor ** immediately, before releasing the mutex. findInodeInfo() may fail ** in two scenarios: ** ** (a) A call to fstat() failed. ** (b) A malloc failed. ** ** Scenario (b) may only occur if the process is holding no other |
︙ | ︙ | |||
4882 4883 4884 4885 4886 4887 4888 | pNew->lastErrno = 0; #if OS_VXWORKS if( rc!=SQLITE_OK ){ if( h>=0 ) robust_close(pNew, h, __LINE__); h = -1; osUnlink(zFilename); | | < > | 5285 5286 5287 5288 5289 5290 5291 5292 5293 5294 5295 5296 5297 5298 5299 5300 5301 5302 5303 5304 5305 5306 5307 | pNew->lastErrno = 0; #if OS_VXWORKS if( rc!=SQLITE_OK ){ if( h>=0 ) robust_close(pNew, h, __LINE__); h = -1; osUnlink(zFilename); pNew->ctrlFlags |= UNIXFILE_DELETE; } #endif if( rc!=SQLITE_OK ){ if( h>=0 ) robust_close(pNew, h, __LINE__); }else{ pNew->pMethod = pLockingStyle; OpenCounter(+1); verifyDbFile(pNew); } return rc; } /* ** Return the name of a directory in which to put temporary files. ** If no suitable temporary file directory can be found, return NULL. |
︙ | ︙ | |||
5421 5422 5423 5424 5425 5426 5427 | } } #endif return rc; } /* | | | 5824 5825 5826 5827 5828 5829 5830 5831 5832 5833 5834 5835 5836 5837 5838 | } } #endif return rc; } /* ** Test the existence of or access permissions of file zPath. The ** test performed depends on the value of flags: ** ** SQLITE_ACCESS_EXISTS: Return 1 if the file exists ** SQLITE_ACCESS_READWRITE: Return 1 if the file is read and writable. ** SQLITE_ACCESS_READONLY: Return 1 if the file is readable. ** ** Otherwise return 0. |
︙ | ︙ | |||
6984 6985 6986 6987 6988 6989 6990 | UNIXVFS("unix-proxy", proxyIoFinder ), #endif }; unsigned int i; /* Loop counter */ /* Double-check that the aSyscall[] array has been constructed ** correctly. See ticket [bb3a86e890c8e96ab] */ | | | 7387 7388 7389 7390 7391 7392 7393 7394 7395 7396 7397 7398 7399 7400 7401 | UNIXVFS("unix-proxy", proxyIoFinder ), #endif }; unsigned int i; /* Loop counter */ /* Double-check that the aSyscall[] array has been constructed ** correctly. See ticket [bb3a86e890c8e96ab] */ assert( ArraySize(aSyscall)==24 ); /* Register all VFSes defined in the aVfs[] array */ for(i=0; i<(sizeof(aVfs)/sizeof(sqlite3_vfs)); i++){ sqlite3_vfs_register(&aVfs[i], i==0); } return SQLITE_OK; } |
︙ | ︙ |
Changes to src/os_win.c.
︙ | ︙ | |||
146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 | #if SQLITE_OS_WINCE LPWSTR zDeleteOnClose; /* Name of file to delete when closing */ HANDLE hMutex; /* Mutex used to control access to shared lock */ HANDLE hShared; /* Shared memory segment used for locking */ winceLock local; /* Locks obtained by this instance of winFile */ winceLock *shared; /* Global shared lock memory for the file */ #endif }; /* ** Allowed values for winFile.ctrlFlags */ #define WINFILE_PERSIST_WAL 0x04 /* Persistent WAL mode */ #define WINFILE_PSOW 0x10 /* SQLITE_IOCAP_POWERSAFE_OVERWRITE */ /* * The size of the buffer used by sqlite3_win32_write_debug(). */ #ifndef SQLITE_WIN32_DBG_BUF_SIZE | > > > > > > > > > | 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 | #if SQLITE_OS_WINCE LPWSTR zDeleteOnClose; /* Name of file to delete when closing */ HANDLE hMutex; /* Mutex used to control access to shared lock */ HANDLE hShared; /* Shared memory segment used for locking */ winceLock local; /* Locks obtained by this instance of winFile */ winceLock *shared; /* Global shared lock memory for the file */ #endif #if SQLITE_MAX_MMAP_SIZE>0 int nFetchOut; /* Number of outstanding xFetch references */ HANDLE hMap; /* Handle for accessing memory mapping */ void *pMapRegion; /* Area memory mapped */ sqlite3_int64 mmapSize; /* Usable size of mapped region */ sqlite3_int64 mmapSizeActual; /* Actual size of mapped region */ sqlite3_int64 mmapSizeMax; /* Configured FCNTL_MMAP_SIZE value */ #endif }; /* ** Allowed values for winFile.ctrlFlags */ #define WINFILE_RDONLY 0x02 /* Connection is read only */ #define WINFILE_PERSIST_WAL 0x04 /* Persistent WAL mode */ #define WINFILE_PSOW 0x10 /* SQLITE_IOCAP_POWERSAFE_OVERWRITE */ /* * The size of the buffer used by sqlite3_win32_write_debug(). */ #ifndef SQLITE_WIN32_DBG_BUF_SIZE |
︙ | ︙ | |||
304 305 306 307 308 309 310 | /* ** Many system calls are accessed through pointer-to-functions so that ** they may be overridden at runtime to facilitate fault injection during ** testing and sandboxing. The following array holds the names and pointers ** to all overrideable system calls. */ static struct win_syscall { | | | 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 | /* ** Many system calls are accessed through pointer-to-functions so that ** they may be overridden at runtime to facilitate fault injection during ** testing and sandboxing. The following array holds the names and pointers ** to all overrideable system calls. */ static struct win_syscall { const char *zName; /* Name of the system call */ sqlite3_syscall_ptr pCurrent; /* Current value of the system call */ sqlite3_syscall_ptr pDefault; /* Default value */ } aSyscall[] = { #if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT { "AreFileApisANSI", (SYSCALL)AreFileApisANSI, 0 }, #else { "AreFileApisANSI", (SYSCALL)0, 0 }, |
︙ | ︙ | |||
1510 1511 1512 1513 1514 1515 1516 | sqlite3EndBenignMalloc(); /* free the system buffer allocated by FormatMessage */ osLocalFree(zTemp); } } #endif if( 0 == dwLen ){ | | | 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 | sqlite3EndBenignMalloc(); /* free the system buffer allocated by FormatMessage */ osLocalFree(zTemp); } } #endif if( 0 == dwLen ){ sqlite3_snprintf(nBuf, zBuf, "OsError 0x%lx (%lu)", lastErrno, lastErrno); }else{ /* copy a maximum of nBuf chars to output buffer */ sqlite3_snprintf(nBuf, zBuf, "%s", zOut); /* free the UTF8 buffer */ sqlite3_free(zOut); } return 0; |
︙ | ︙ | |||
1553 1554 1555 1556 1557 1558 1559 | zMsg[0] = 0; getLastErrorMsg(lastErrno, sizeof(zMsg), zMsg); assert( errcode!=SQLITE_OK ); if( zPath==0 ) zPath = ""; for(i=0; zMsg[i] && zMsg[i]!='\r' && zMsg[i]!='\n'; i++){} zMsg[i] = 0; sqlite3_log(errcode, | | | 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 | zMsg[0] = 0; getLastErrorMsg(lastErrno, sizeof(zMsg), zMsg); assert( errcode!=SQLITE_OK ); if( zPath==0 ) zPath = ""; for(i=0; zMsg[i] && zMsg[i]!='\r' && zMsg[i]!='\n'; i++){} zMsg[i] = 0; sqlite3_log(errcode, "os_win.c:%d: (%lu) %s(%s) - %s", iLine, lastErrno, zFunc, zPath, zMsg ); return errcode; } /* |
︙ | ︙ | |||
2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 | static int seekWinFile(winFile *pFile, sqlite3_int64 iOffset){ #if !SQLITE_OS_WINRT LONG upperBits; /* Most sig. 32 bits of new offset */ LONG lowerBits; /* Least sig. 32 bits of new offset */ DWORD dwRet; /* Value returned by SetFilePointer() */ DWORD lastErrno; /* Value returned by GetLastError() */ upperBits = (LONG)((iOffset>>32) & 0x7fffffff); lowerBits = (LONG)(iOffset & 0xffffffff); /* API oddity: If successful, SetFilePointer() returns a dword ** containing the lower 32-bits of the new file-offset. Or, if it fails, ** it returns INVALID_SET_FILE_POINTER. However according to MSDN, ** INVALID_SET_FILE_POINTER may also be a valid new offset. So to determine | > > | > > > > > > > > > < > > > > > > > < > | 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 | static int seekWinFile(winFile *pFile, sqlite3_int64 iOffset){ #if !SQLITE_OS_WINRT LONG upperBits; /* Most sig. 32 bits of new offset */ LONG lowerBits; /* Least sig. 32 bits of new offset */ DWORD dwRet; /* Value returned by SetFilePointer() */ DWORD lastErrno; /* Value returned by GetLastError() */ OSTRACE(("SEEK file=%p, offset=%lld\n", pFile->h, iOffset)); upperBits = (LONG)((iOffset>>32) & 0x7fffffff); lowerBits = (LONG)(iOffset & 0xffffffff); /* API oddity: If successful, SetFilePointer() returns a dword ** containing the lower 32-bits of the new file-offset. Or, if it fails, ** it returns INVALID_SET_FILE_POINTER. However according to MSDN, ** INVALID_SET_FILE_POINTER may also be a valid new offset. So to determine ** whether an error has actually occurred, it is also necessary to call ** GetLastError(). */ dwRet = osSetFilePointer(pFile->h, lowerBits, &upperBits, FILE_BEGIN); if( (dwRet==INVALID_SET_FILE_POINTER && ((lastErrno = osGetLastError())!=NO_ERROR)) ){ pFile->lastErrno = lastErrno; winLogError(SQLITE_IOERR_SEEK, pFile->lastErrno, "seekWinFile", pFile->zPath); OSTRACE(("SEEK file=%p, rc=SQLITE_IOERR_SEEK\n", pFile->h)); return 1; } OSTRACE(("SEEK file=%p, rc=SQLITE_OK\n", pFile->h)); return 0; #else /* ** Same as above, except that this implementation works for WinRT. */ LARGE_INTEGER x; /* The new offset */ BOOL bRet; /* Value returned by SetFilePointerEx() */ x.QuadPart = iOffset; bRet = osSetFilePointerEx(pFile->h, x, 0, FILE_BEGIN); if(!bRet){ pFile->lastErrno = osGetLastError(); winLogError(SQLITE_IOERR_SEEK, pFile->lastErrno, "seekWinFile", pFile->zPath); OSTRACE(("SEEK file=%p, rc=SQLITE_IOERR_SEEK\n", pFile->h)); return 1; } OSTRACE(("SEEK file=%p, rc=SQLITE_OK\n", pFile->h)); return 0; #endif } #if SQLITE_MAX_MMAP_SIZE>0 /* Forward references to VFS methods */ static int winUnmapfile(winFile*); #endif /* ** Close a file. ** ** It is reported that an attempt to close a handle might sometimes ** fail. This is a very unreasonable result, but Windows is notorious ** for being unreasonable so I do not doubt that it might happen. If ** the close fails, we pause for 100 milliseconds and try again. As ** many as MX_CLOSE_ATTEMPT attempts to close the handle are made before ** giving up and returning an error. */ #define MX_CLOSE_ATTEMPT 3 static int winClose(sqlite3_file *id){ int rc, cnt = 0; winFile *pFile = (winFile*)id; assert( id!=0 ); #ifndef SQLITE_OMIT_WAL assert( pFile->pShm==0 ); #endif assert( pFile->h!=NULL && pFile->h!=INVALID_HANDLE_VALUE ); OSTRACE(("CLOSE file=%p\n", pFile->h)); #if SQLITE_MAX_MMAP_SIZE>0 rc = winUnmapfile(pFile); if( rc!=SQLITE_OK ) return rc; #endif do{ rc = osCloseHandle(pFile->h); /* SimulateIOError( rc=0; cnt=MX_CLOSE_ATTEMPT; ); */ }while( rc==0 && ++cnt < MX_CLOSE_ATTEMPT && (sqlite3_win32_sleep(100), 1) ); #if SQLITE_OS_WINCE #define WINCE_DELETION_ATTEMPTS 3 winceDestroyLock(pFile); if( pFile->zDeleteOnClose ){ int cnt = 0; while( osDeleteFileW(pFile->zDeleteOnClose)==0 && osGetFileAttributesW(pFile->zDeleteOnClose)!=0xffffffff && cnt++ < WINCE_DELETION_ATTEMPTS ){ sqlite3_win32_sleep(100); /* Wait a little before trying again */ } sqlite3_free(pFile->zDeleteOnClose); } #endif if( rc ){ pFile->h = NULL; } OpenCounter(-1); OSTRACE(("CLOSE file=%p, rc=%s\n", pFile->h, rc ? "ok" : "failed")); return rc ? SQLITE_OK : winLogError(SQLITE_IOERR_CLOSE, osGetLastError(), "winClose", pFile->zPath); } /* ** Read data from a file into a buffer. Return SQLITE_OK if all |
︙ | ︙ | |||
2126 2127 2128 2129 2130 2131 2132 2133 | OVERLAPPED overlapped; /* The offset for ReadFile. */ #endif winFile *pFile = (winFile*)id; /* file handle */ DWORD nRead; /* Number of bytes actually read from file */ int nRetry = 0; /* Number of retrys */ assert( id!=0 ); SimulateIOError(return SQLITE_IOERR_READ); | > > > > | > > > > > > > > > > > > > > > > > > > > > | > > | > > > > > > > > > > > > > > > > > | 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 | OVERLAPPED overlapped; /* The offset for ReadFile. */ #endif winFile *pFile = (winFile*)id; /* file handle */ DWORD nRead; /* Number of bytes actually read from file */ int nRetry = 0; /* Number of retrys */ assert( id!=0 ); assert( amt>0 ); assert( offset>=0 ); SimulateIOError(return SQLITE_IOERR_READ); OSTRACE(("READ file=%p, buffer=%p, amount=%d, offset=%lld, lock=%d\n", pFile->h, pBuf, amt, offset, pFile->locktype)); #if SQLITE_MAX_MMAP_SIZE>0 /* Deal with as much of this read request as possible by transfering ** data from the memory mapping using memcpy(). */ if( offset<pFile->mmapSize ){ if( offset+amt <= pFile->mmapSize ){ memcpy(pBuf, &((u8 *)(pFile->pMapRegion))[offset], amt); OSTRACE(("READ-MMAP file=%p, rc=SQLITE_OK\n", pFile->h)); return SQLITE_OK; }else{ int nCopy = (int)(pFile->mmapSize - offset); memcpy(pBuf, &((u8 *)(pFile->pMapRegion))[offset], nCopy); pBuf = &((u8 *)pBuf)[nCopy]; amt -= nCopy; offset += nCopy; } } #endif #if SQLITE_OS_WINCE if( seekWinFile(pFile, offset) ){ OSTRACE(("READ file=%p, rc=SQLITE_FULL\n", pFile->h)); return SQLITE_FULL; } while( !osReadFile(pFile->h, pBuf, amt, &nRead, 0) ){ #else memset(&overlapped, 0, sizeof(OVERLAPPED)); overlapped.Offset = (LONG)(offset & 0xffffffff); overlapped.OffsetHigh = (LONG)((offset>>32) & 0x7fffffff); while( !osReadFile(pFile->h, pBuf, amt, &nRead, &overlapped) && osGetLastError()!=ERROR_HANDLE_EOF ){ #endif DWORD lastErrno; if( retryIoerr(&nRetry, &lastErrno) ) continue; pFile->lastErrno = lastErrno; OSTRACE(("READ file=%p, rc=SQLITE_IOERR_READ\n", pFile->h)); return winLogError(SQLITE_IOERR_READ, pFile->lastErrno, "winRead", pFile->zPath); } logIoerr(nRetry); if( nRead<(DWORD)amt ){ /* Unread parts of the buffer must be zero-filled */ memset(&((char*)pBuf)[nRead], 0, amt-nRead); OSTRACE(("READ file=%p, rc=SQLITE_IOERR_SHORT_READ\n", pFile->h)); return SQLITE_IOERR_SHORT_READ; } OSTRACE(("READ file=%p, rc=SQLITE_OK\n", pFile->h)); return SQLITE_OK; } /* ** Write data from a buffer into a file. Return SQLITE_OK on success ** or some other error code on failure. */ static int winWrite( sqlite3_file *id, /* File to write into */ const void *pBuf, /* The bytes to be written */ int amt, /* Number of bytes to write */ sqlite3_int64 offset /* Offset into the file to begin writing at */ ){ int rc = 0; /* True if error has occurred, else false */ winFile *pFile = (winFile*)id; /* File handle */ int nRetry = 0; /* Number of retries */ assert( amt>0 ); assert( pFile ); SimulateIOError(return SQLITE_IOERR_WRITE); SimulateDiskfullError(return SQLITE_FULL); OSTRACE(("WRITE file=%p, buffer=%p, amount=%d, offset=%lld, lock=%d\n", pFile->h, pBuf, amt, offset, pFile->locktype)); #if SQLITE_MAX_MMAP_SIZE>0 /* Deal with as much of this write request as possible by transfering ** data from the memory mapping using memcpy(). */ if( offset<pFile->mmapSize ){ if( offset+amt <= pFile->mmapSize ){ memcpy(&((u8 *)(pFile->pMapRegion))[offset], pBuf, amt); OSTRACE(("WRITE-MMAP file=%p, rc=SQLITE_OK\n", pFile->h)); return SQLITE_OK; }else{ int nCopy = (int)(pFile->mmapSize - offset); memcpy(&((u8 *)(pFile->pMapRegion))[offset], pBuf, nCopy); pBuf = &((u8 *)pBuf)[nCopy]; amt -= nCopy; offset += nCopy; } } #endif #if SQLITE_OS_WINCE rc = seekWinFile(pFile, offset); if( rc==0 ){ #else { #endif |
︙ | ︙ | |||
2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 | rc = 1; } } if( rc ){ if( ( pFile->lastErrno==ERROR_HANDLE_DISK_FULL ) || ( pFile->lastErrno==ERROR_DISK_FULL )){ return SQLITE_FULL; } return winLogError(SQLITE_IOERR_WRITE, pFile->lastErrno, "winWrite", pFile->zPath); }else{ logIoerr(nRetry); } return SQLITE_OK; } /* ** Truncate an open file to a specified size */ static int winTruncate(sqlite3_file *id, sqlite3_int64 nByte){ winFile *pFile = (winFile*)id; /* File handle object */ int rc = SQLITE_OK; /* Return code for this function */ assert( pFile ); | > > > > < < > > | > | > > > > > > > > > | > | 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 | rc = 1; } } if( rc ){ if( ( pFile->lastErrno==ERROR_HANDLE_DISK_FULL ) || ( pFile->lastErrno==ERROR_DISK_FULL )){ OSTRACE(("WRITE file=%p, rc=SQLITE_FULL\n", pFile->h)); return SQLITE_FULL; } OSTRACE(("WRITE file=%p, rc=SQLITE_IOERR_WRITE\n", pFile->h)); return winLogError(SQLITE_IOERR_WRITE, pFile->lastErrno, "winWrite", pFile->zPath); }else{ logIoerr(nRetry); } OSTRACE(("WRITE file=%p, rc=SQLITE_OK\n", pFile->h)); return SQLITE_OK; } /* ** Truncate an open file to a specified size */ static int winTruncate(sqlite3_file *id, sqlite3_int64 nByte){ winFile *pFile = (winFile*)id; /* File handle object */ int rc = SQLITE_OK; /* Return code for this function */ DWORD lastErrno; assert( pFile ); SimulateIOError(return SQLITE_IOERR_TRUNCATE); OSTRACE(("TRUNCATE file=%p, size=%lld, lock=%d\n", pFile->h, nByte, pFile->locktype)); /* If the user has configured a chunk-size for this file, truncate the ** file so that it consists of an integer number of chunks (i.e. the ** actual file size after the operation may be larger than the requested ** size). */ if( pFile->szChunk>0 ){ nByte = ((nByte + pFile->szChunk - 1)/pFile->szChunk) * pFile->szChunk; } /* SetEndOfFile() returns non-zero when successful, or zero when it fails. */ if( seekWinFile(pFile, nByte) ){ rc = winLogError(SQLITE_IOERR_TRUNCATE, pFile->lastErrno, "winTruncate1", pFile->zPath); }else if( 0==osSetEndOfFile(pFile->h) && ((lastErrno = osGetLastError())!=ERROR_USER_MAPPED_FILE) ){ pFile->lastErrno = lastErrno; rc = winLogError(SQLITE_IOERR_TRUNCATE, pFile->lastErrno, "winTruncate2", pFile->zPath); } #if SQLITE_MAX_MMAP_SIZE>0 /* If the file was truncated to a size smaller than the currently ** mapped region, reduce the effective mapping size as well. SQLite will ** use read() and write() to access data beyond this point from now on. */ if( pFile->pMapRegion && nByte<pFile->mmapSize ){ pFile->mmapSize = nByte; } #endif OSTRACE(("TRUNCATE file=%p, rc=%s\n", pFile->h, sqlite3ErrName(rc))); return rc; } #ifdef SQLITE_TEST /* ** Count the number of fullsyncs and normal syncs. This is used to test ** that syncs and fullsyncs are occuring at the right times. |
︙ | ︙ | |||
2310 2311 2312 2313 2314 2315 2316 | assert( pFile ); /* Check that one of SQLITE_SYNC_NORMAL or FULL was passed */ assert((flags&0x0F)==SQLITE_SYNC_NORMAL || (flags&0x0F)==SQLITE_SYNC_FULL ); | < < > > > > > > > > | 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 2420 2421 2422 2423 2424 2425 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 | assert( pFile ); /* Check that one of SQLITE_SYNC_NORMAL or FULL was passed */ assert((flags&0x0F)==SQLITE_SYNC_NORMAL || (flags&0x0F)==SQLITE_SYNC_FULL ); /* Unix cannot, but some systems may return SQLITE_FULL from here. This ** line is to test that doing so does not cause any problems. */ SimulateDiskfullError( return SQLITE_FULL ); OSTRACE(("SYNC file=%p, flags=%x, lock=%d\n", pFile->h, flags, pFile->locktype)); #ifndef SQLITE_TEST UNUSED_PARAMETER(flags); #else if( (flags&0x0F)==SQLITE_SYNC_FULL ){ sqlite3_fullsync_count++; } sqlite3_sync_count++; #endif /* If we compiled with the SQLITE_NO_SYNC flag, then syncing is a ** no-op */ #ifdef SQLITE_NO_SYNC return SQLITE_OK; #else rc = osFlushFileBuffers(pFile->h); SimulateIOError( rc=FALSE ); if( rc ){ OSTRACE(("SYNC file=%p, rc=SQLITE_OK\n", pFile->h)); return SQLITE_OK; }else{ pFile->lastErrno = osGetLastError(); OSTRACE(("SYNC file=%p, rc=SQLITE_IOERR_FSYNC\n", pFile->h)); return winLogError(SQLITE_IOERR_FSYNC, pFile->lastErrno, "winSync", pFile->zPath); } #endif } /* ** Determine the current size of a file in bytes */ static int winFileSize(sqlite3_file *id, sqlite3_int64 *pSize){ winFile *pFile = (winFile*)id; int rc = SQLITE_OK; assert( id!=0 ); assert( pSize!=0 ); SimulateIOError(return SQLITE_IOERR_FSTAT); OSTRACE(("SIZE file=%p, pSize=%p\n", pFile->h, pSize)); #if SQLITE_OS_WINRT { FILE_STANDARD_INFO info; if( osGetFileInformationByHandleEx(pFile->h, FileStandardInfo, &info, sizeof(info)) ){ *pSize = info.EndOfFile.QuadPart; }else{ |
︙ | ︙ | |||
2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 | && ((lastErrno = osGetLastError())!=NO_ERROR) ){ pFile->lastErrno = lastErrno; rc = winLogError(SQLITE_IOERR_FSTAT, pFile->lastErrno, "winFileSize", pFile->zPath); } } #endif return rc; } /* ** LOCKFILE_FAIL_IMMEDIATELY is undefined on some Windows systems. */ #ifndef LOCKFILE_FAIL_IMMEDIATELY | > > | 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 | && ((lastErrno = osGetLastError())!=NO_ERROR) ){ pFile->lastErrno = lastErrno; rc = winLogError(SQLITE_IOERR_FSTAT, pFile->lastErrno, "winFileSize", pFile->zPath); } } #endif OSTRACE(("SIZE file=%p, pSize=%p, *pSize=%lld, rc=%s\n", pFile->h, pSize, *pSize, sqlite3ErrName(rc))); return rc; } /* ** LOCKFILE_FAIL_IMMEDIATELY is undefined on some Windows systems. */ #ifndef LOCKFILE_FAIL_IMMEDIATELY |
︙ | ︙ | |||
2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 | /* ** Acquire a reader lock. ** Different API routines are called depending on whether or not this ** is Win9x or WinNT. */ static int getReadLock(winFile *pFile){ int res; if( isNT() ){ #if SQLITE_OS_WINCE /* ** NOTE: Windows CE is handled differently here due its lack of the Win32 ** API LockFileEx. */ res = winceLockFile(&pFile->h, SHARED_FIRST, 0, 1, 0); | > | 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 | /* ** Acquire a reader lock. ** Different API routines are called depending on whether or not this ** is Win9x or WinNT. */ static int getReadLock(winFile *pFile){ int res; OSTRACE(("READ-LOCK file=%p, lock=%d\n", pFile->h, pFile->locktype)); if( isNT() ){ #if SQLITE_OS_WINCE /* ** NOTE: Windows CE is handled differently here due its lack of the Win32 ** API LockFileEx. */ res = winceLockFile(&pFile->h, SHARED_FIRST, 0, 1, 0); |
︙ | ︙ | |||
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 | SHARED_FIRST+pFile->sharedLockByte, 0, 1, 0); } #endif if( res == 0 ){ pFile->lastErrno = osGetLastError(); /* No need to log a failure to lock */ } return res; } /* ** Undo a readlock */ static int unlockReadLock(winFile *pFile){ int res; DWORD lastErrno; if( isNT() ){ res = winUnlockFile(&pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0); } #ifdef SQLITE_WIN32_HAS_ANSI else{ res = winUnlockFile(&pFile->h, SHARED_FIRST+pFile->sharedLockByte, 0, 1, 0); } #endif if( res==0 && ((lastErrno = osGetLastError())!=ERROR_NOT_LOCKED) ){ pFile->lastErrno = lastErrno; winLogError(SQLITE_IOERR_UNLOCK, pFile->lastErrno, "unlockReadLock", pFile->zPath); } return res; } /* ** Lock the file with the lock specified by parameter locktype - one ** of the following: ** | > > > | 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 | SHARED_FIRST+pFile->sharedLockByte, 0, 1, 0); } #endif if( res == 0 ){ pFile->lastErrno = osGetLastError(); /* No need to log a failure to lock */ } OSTRACE(("READ-LOCK file=%p, rc=%s\n", pFile->h, sqlite3ErrName(res))); return res; } /* ** Undo a readlock */ static int unlockReadLock(winFile *pFile){ int res; DWORD lastErrno; OSTRACE(("READ-UNLOCK file=%p, lock=%d\n", pFile->h, pFile->locktype)); if( isNT() ){ res = winUnlockFile(&pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0); } #ifdef SQLITE_WIN32_HAS_ANSI else{ res = winUnlockFile(&pFile->h, SHARED_FIRST+pFile->sharedLockByte, 0, 1, 0); } #endif if( res==0 && ((lastErrno = osGetLastError())!=ERROR_NOT_LOCKED) ){ pFile->lastErrno = lastErrno; winLogError(SQLITE_IOERR_UNLOCK, pFile->lastErrno, "unlockReadLock", pFile->zPath); } OSTRACE(("READ-UNLOCK file=%p, rc=%s\n", pFile->h, sqlite3ErrName(res))); return res; } /* ** Lock the file with the lock specified by parameter locktype - one ** of the following: ** |
︙ | ︙ | |||
2507 2508 2509 2510 2511 2512 2513 | int res = 1; /* Result of a Windows lock call */ int newLocktype; /* Set pFile->locktype to this value before exiting */ int gotPendingLock = 0;/* True if we acquired a PENDING lock this time */ winFile *pFile = (winFile*)id; DWORD lastErrno = NO_ERROR; assert( id!=0 ); | | | > | 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 | int res = 1; /* Result of a Windows lock call */ int newLocktype; /* Set pFile->locktype to this value before exiting */ int gotPendingLock = 0;/* True if we acquired a PENDING lock this time */ winFile *pFile = (winFile*)id; DWORD lastErrno = NO_ERROR; assert( id!=0 ); OSTRACE(("LOCK file=%p, oldLock=%d(%d), newLock=%d\n", pFile->h, pFile->locktype, pFile->sharedLockByte, locktype)); /* If there is already a lock of this type or more restrictive on the ** OsFile, do nothing. Don't use the end_lock: exit path, as ** sqlite3OsEnterMutex() hasn't been called yet. */ if( pFile->locktype>=locktype ){ OSTRACE(("LOCK-HELD file=%p, rc=SQLITE_OK\n", pFile->h)); return SQLITE_OK; } /* Make sure the locking sequence is correct */ assert( pFile->locktype!=NO_LOCK || locktype==SHARED_LOCK ); assert( locktype!=PENDING_LOCK ); |
︙ | ︙ | |||
2542 2543 2544 2545 2546 2547 2548 | PENDING_BYTE, 0, 1, 0))==0 ){ /* Try 3 times to get the pending lock. This is needed to work ** around problems caused by indexing and/or anti-virus software on ** Windows systems. ** If you are using this code as a model for alternative VFSes, do not ** copy this retry logic. It is a hack intended for Windows only. */ | | > | 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 | PENDING_BYTE, 0, 1, 0))==0 ){ /* Try 3 times to get the pending lock. This is needed to work ** around problems caused by indexing and/or anti-virus software on ** Windows systems. ** If you are using this code as a model for alternative VFSes, do not ** copy this retry logic. It is a hack intended for Windows only. */ OSTRACE(("LOCK-PENDING-FAIL file=%p, count=%d, rc=%s\n", pFile->h, cnt, sqlite3ErrName(res))); if( cnt ) sqlite3_win32_sleep(1); } gotPendingLock = res; if( !res ){ lastErrno = osGetLastError(); } } |
︙ | ︙ | |||
2587 2588 2589 2590 2591 2592 2593 | } /* Acquire an EXCLUSIVE lock */ if( locktype==EXCLUSIVE_LOCK && res ){ assert( pFile->locktype>=SHARED_LOCK ); res = unlockReadLock(pFile); | < < | | > > > | | | > > | | > > | 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 | } /* Acquire an EXCLUSIVE lock */ if( locktype==EXCLUSIVE_LOCK && res ){ assert( pFile->locktype>=SHARED_LOCK ); res = unlockReadLock(pFile); res = winLockFile(&pFile->h, SQLITE_LOCKFILE_FLAGS, SHARED_FIRST, 0, SHARED_SIZE, 0); if( res ){ newLocktype = EXCLUSIVE_LOCK; }else{ lastErrno = osGetLastError(); getReadLock(pFile); } } /* If we are holding a PENDING lock that ought to be released, then ** release it now. */ if( gotPendingLock && locktype==SHARED_LOCK ){ winUnlockFile(&pFile->h, PENDING_BYTE, 0, 1, 0); } /* Update the state of the lock has held in the file descriptor then ** return the appropriate result code. */ if( res ){ rc = SQLITE_OK; }else{ OSTRACE(("LOCK-FAIL file=%p, wanted=%d, got=%d\n", pFile->h, locktype, newLocktype)); pFile->lastErrno = lastErrno; rc = SQLITE_BUSY; } pFile->locktype = (u8)newLocktype; OSTRACE(("LOCK file=%p, lock=%d, rc=%s\n", pFile->h, pFile->locktype, sqlite3ErrName(rc))); return rc; } /* ** This routine checks if there is a RESERVED lock held on the specified ** file by this or any other process. If such a lock is held, return ** non-zero, otherwise zero. */ static int winCheckReservedLock(sqlite3_file *id, int *pResOut){ int rc; winFile *pFile = (winFile*)id; SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; ); OSTRACE(("TEST-WR-LOCK file=%p, pResOut=%p\n", pFile->h, pResOut)); assert( id!=0 ); if( pFile->locktype>=RESERVED_LOCK ){ rc = 1; OSTRACE(("TEST-WR-LOCK file=%p, rc=%d (local)\n", pFile->h, rc)); }else{ rc = winLockFile(&pFile->h, SQLITE_LOCKFILEEX_FLAGS,RESERVED_BYTE, 0, 1, 0); if( rc ){ winUnlockFile(&pFile->h, RESERVED_BYTE, 0, 1, 0); } rc = !rc; OSTRACE(("TEST-WR-LOCK file=%p, rc=%d (remote)\n", pFile->h, rc)); } *pResOut = rc; OSTRACE(("TEST-WR-LOCK file=%p, pResOut=%p, *pResOut=%d, rc=SQLITE_OK\n", pFile->h, pResOut, *pResOut)); return SQLITE_OK; } /* ** Lower the locking level on file descriptor id to locktype. locktype ** must be either NO_LOCK or SHARED_LOCK. ** ** If the locking level of the file descriptor is already at or below ** the requested locking level, this routine is a no-op. ** ** It is not possible for this routine to fail if the second argument ** is NO_LOCK. If the second argument is SHARED_LOCK then this routine ** might return SQLITE_IOERR; */ static int winUnlock(sqlite3_file *id, int locktype){ int type; winFile *pFile = (winFile*)id; int rc = SQLITE_OK; assert( pFile!=0 ); assert( locktype<=SHARED_LOCK ); OSTRACE(("UNLOCK file=%p, oldLock=%d(%d), newLock=%d\n", pFile->h, pFile->locktype, pFile->sharedLockByte, locktype)); type = pFile->locktype; if( type>=EXCLUSIVE_LOCK ){ winUnlockFile(&pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0); if( locktype==SHARED_LOCK && !getReadLock(pFile) ){ /* This should never happen. We should always be able to ** reacquire the read lock */ rc = winLogError(SQLITE_IOERR_UNLOCK, osGetLastError(), "winUnlock", pFile->zPath); } } if( type>=RESERVED_LOCK ){ winUnlockFile(&pFile->h, RESERVED_BYTE, 0, 1, 0); } if( locktype==NO_LOCK && type>=SHARED_LOCK ){ unlockReadLock(pFile); } if( type>=PENDING_LOCK ){ winUnlockFile(&pFile->h, PENDING_BYTE, 0, 1, 0); } pFile->locktype = (u8)locktype; OSTRACE(("UNLOCK file=%p, lock=%d, rc=%s\n", pFile->h, pFile->locktype, sqlite3ErrName(rc))); return rc; } /* ** If *pArg is inititially negative then this is a query. Set *pArg to ** 1 or 0 depending on whether or not bit mask of pFile->ctrlFlags is set. ** |
︙ | ︙ | |||
2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 | static int getTempname(int nBuf, char *zBuf); /* ** Control and query of the open file handle. */ static int winFileControl(sqlite3_file *id, int op, void *pArg){ winFile *pFile = (winFile*)id; switch( op ){ case SQLITE_FCNTL_LOCKSTATE: { *(int*)pArg = pFile->locktype; return SQLITE_OK; } case SQLITE_LAST_ERRNO: { *(int*)pArg = (int)pFile->lastErrno; return SQLITE_OK; } case SQLITE_FCNTL_CHUNK_SIZE: { pFile->szChunk = *(int *)pArg; return SQLITE_OK; } case SQLITE_FCNTL_SIZE_HINT: { if( pFile->szChunk>0 ){ sqlite3_int64 oldSz; int rc = winFileSize(id, &oldSz); if( rc==SQLITE_OK ){ sqlite3_int64 newSz = *(sqlite3_int64*)pArg; if( newSz>oldSz ){ SimulateIOErrorBenign(1); rc = winTruncate(id, newSz); SimulateIOErrorBenign(0); } } return rc; } return SQLITE_OK; } case SQLITE_FCNTL_PERSIST_WAL: { winModeBit(pFile, WINFILE_PERSIST_WAL, (int*)pArg); return SQLITE_OK; } case SQLITE_FCNTL_POWERSAFE_OVERWRITE: { winModeBit(pFile, WINFILE_PSOW, (int*)pArg); return SQLITE_OK; } case SQLITE_FCNTL_VFSNAME: { *(char**)pArg = sqlite3_mprintf("win32"); return SQLITE_OK; } case SQLITE_FCNTL_WIN32_AV_RETRY: { int *a = (int*)pArg; if( a[0]>0 ){ win32IoerrRetry = a[0]; }else{ a[0] = win32IoerrRetry; } if( a[1]>0 ){ win32IoerrRetryDelay = a[1]; }else{ a[1] = win32IoerrRetryDelay; } return SQLITE_OK; } case SQLITE_FCNTL_TEMPFILENAME: { char *zTFile = sqlite3MallocZero( pFile->pVfs->mxPathname ); if( zTFile ){ getTempname(pFile->pVfs->mxPathname, zTFile); *(char**)pArg = zTFile; } return SQLITE_OK; } } return SQLITE_NOTFOUND; } /* ** Return the sector size in bytes of the underlying block device for ** the specified file. This is almost always 512 bytes, but may be ** larger for some devices. | > > > > > > > > > > > > > > > > > > > > > > > > | 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 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 | static int getTempname(int nBuf, char *zBuf); /* ** Control and query of the open file handle. */ static int winFileControl(sqlite3_file *id, int op, void *pArg){ winFile *pFile = (winFile*)id; OSTRACE(("FCNTL file=%p, op=%d, pArg=%p\n", pFile->h, op, pArg)); switch( op ){ case SQLITE_FCNTL_LOCKSTATE: { *(int*)pArg = pFile->locktype; OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h)); return SQLITE_OK; } case SQLITE_LAST_ERRNO: { *(int*)pArg = (int)pFile->lastErrno; OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h)); return SQLITE_OK; } case SQLITE_FCNTL_CHUNK_SIZE: { pFile->szChunk = *(int *)pArg; OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h)); return SQLITE_OK; } case SQLITE_FCNTL_SIZE_HINT: { if( pFile->szChunk>0 ){ sqlite3_int64 oldSz; int rc = winFileSize(id, &oldSz); if( rc==SQLITE_OK ){ sqlite3_int64 newSz = *(sqlite3_int64*)pArg; if( newSz>oldSz ){ SimulateIOErrorBenign(1); rc = winTruncate(id, newSz); SimulateIOErrorBenign(0); } } OSTRACE(("FCNTL file=%p, rc=%s\n", pFile->h, sqlite3ErrName(rc))); return rc; } OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h)); return SQLITE_OK; } case SQLITE_FCNTL_PERSIST_WAL: { winModeBit(pFile, WINFILE_PERSIST_WAL, (int*)pArg); OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h)); return SQLITE_OK; } case SQLITE_FCNTL_POWERSAFE_OVERWRITE: { winModeBit(pFile, WINFILE_PSOW, (int*)pArg); OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h)); return SQLITE_OK; } case SQLITE_FCNTL_VFSNAME: { *(char**)pArg = sqlite3_mprintf("win32"); OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h)); return SQLITE_OK; } case SQLITE_FCNTL_WIN32_AV_RETRY: { int *a = (int*)pArg; if( a[0]>0 ){ win32IoerrRetry = a[0]; }else{ a[0] = win32IoerrRetry; } if( a[1]>0 ){ win32IoerrRetryDelay = a[1]; }else{ a[1] = win32IoerrRetryDelay; } OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h)); return SQLITE_OK; } case SQLITE_FCNTL_TEMPFILENAME: { char *zTFile = sqlite3MallocZero( pFile->pVfs->mxPathname ); if( zTFile ){ getTempname(pFile->pVfs->mxPathname, zTFile); *(char**)pArg = zTFile; } OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h)); return SQLITE_OK; } #if SQLITE_MAX_MMAP_SIZE>0 case SQLITE_FCNTL_MMAP_SIZE: { i64 newLimit = *(i64*)pArg; if( newLimit>sqlite3GlobalConfig.mxMmap ){ newLimit = sqlite3GlobalConfig.mxMmap; } *(i64*)pArg = pFile->mmapSizeMax; if( newLimit>=0 ) pFile->mmapSizeMax = newLimit; OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h)); return SQLITE_OK; } #endif } OSTRACE(("FCNTL file=%p, rc=SQLITE_NOTFOUND\n", pFile->h)); return SQLITE_NOTFOUND; } /* ** Return the sector size in bytes of the underlying block device for ** the specified file. This is almost always 512 bytes, but may be ** larger for some devices. |
︙ | ︙ | |||
2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 | int nByte /* Number of bytes to lock or unlock */ ){ int rc = 0; /* Result code form Lock/UnlockFileEx() */ /* Access to the winShmNode object is serialized by the caller */ assert( sqlite3_mutex_held(pFile->mutex) || pFile->nRef==0 ); /* Release/Acquire the system-level lock */ if( lockType==_SHM_UNLCK ){ rc = winUnlockFile(&pFile->hFile.h, ofst, 0, nByte, 0); }else{ /* Initialize the locking parameters */ DWORD dwFlags = LOCKFILE_FAIL_IMMEDIATELY; if( lockType == _SHM_WRLCK ) dwFlags |= LOCKFILE_EXCLUSIVE_LOCK; rc = winLockFile(&pFile->hFile.h, dwFlags, ofst, 0, nByte, 0); } if( rc!= 0 ){ rc = SQLITE_OK; }else{ pFile->lastErrno = osGetLastError(); rc = SQLITE_BUSY; } | > > > | | < < | > > | | < | | < | 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130 3131 3132 3133 3134 3135 | int nByte /* Number of bytes to lock or unlock */ ){ int rc = 0; /* Result code form Lock/UnlockFileEx() */ /* Access to the winShmNode object is serialized by the caller */ assert( sqlite3_mutex_held(pFile->mutex) || pFile->nRef==0 ); OSTRACE(("SHM-LOCK file=%p, lock=%d, offset=%d, size=%d\n", pFile->hFile.h, lockType, ofst, nByte)); /* Release/Acquire the system-level lock */ if( lockType==_SHM_UNLCK ){ rc = winUnlockFile(&pFile->hFile.h, ofst, 0, nByte, 0); }else{ /* Initialize the locking parameters */ DWORD dwFlags = LOCKFILE_FAIL_IMMEDIATELY; if( lockType == _SHM_WRLCK ) dwFlags |= LOCKFILE_EXCLUSIVE_LOCK; rc = winLockFile(&pFile->hFile.h, dwFlags, ofst, 0, nByte, 0); } if( rc!= 0 ){ rc = SQLITE_OK; }else{ pFile->lastErrno = osGetLastError(); rc = SQLITE_BUSY; } OSTRACE(("SHM-LOCK file=%p, func=%s, errno=%lu, rc=%s\n", pFile->hFile.h, (lockType == _SHM_UNLCK) ? "winUnlockFile" : "winLockFile", pFile->lastErrno, sqlite3ErrName(rc))); return rc; } /* Forward references to VFS methods */ static int winOpen(sqlite3_vfs*,const char*,sqlite3_file*,int,int*); static int winDelete(sqlite3_vfs *,const char*,int); /* ** Purge the winShmNodeList list of all entries with winShmNode.nRef==0. ** ** This is not a VFS shared-memory method; it is a utility function called ** by VFS shared-memory methods. */ static void winShmPurge(sqlite3_vfs *pVfs, int deleteFlag){ winShmNode **pp; winShmNode *p; BOOL bRc; assert( winShmMutexHeld() ); OSTRACE(("SHM-PURGE pid=%lu, deleteFlag=%d\n", osGetCurrentProcessId(), deleteFlag)); pp = &winShmNodeList; while( (p = *pp)!=0 ){ if( p->nRef==0 ){ int i; if( p->mutex ) sqlite3_mutex_free(p->mutex); for(i=0; i<p->nRegion; i++){ bRc = osUnmapViewOfFile(p->aRegion[i].pMap); OSTRACE(("SHM-PURGE-UNMAP pid=%lu, region=%d, rc=%s\n", osGetCurrentProcessId(), i, bRc ? "ok" : "failed")); bRc = osCloseHandle(p->aRegion[i].hMap); OSTRACE(("SHM-PURGE-CLOSE pid=%lu, region=%d, rc=%s\n", osGetCurrentProcessId(), i, bRc ? "ok" : "failed")); } if( p->hFile.h!=NULL && p->hFile.h!=INVALID_HANDLE_VALUE ){ SimulateIOErrorBenign(1); winClose((sqlite3_file *)&p->hFile); SimulateIOErrorBenign(0); } if( deleteFlag ){ |
︙ | ︙ | |||
3271 3272 3273 3274 3275 3276 3277 | if( rc==SQLITE_OK ){ assert( (p->sharedMask & mask)==0 ); p->exclMask |= mask; } } } sqlite3_mutex_leave(pShmNode->mutex); | | | | | 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 | if( rc==SQLITE_OK ){ assert( (p->sharedMask & mask)==0 ); p->exclMask |= mask; } } } sqlite3_mutex_leave(pShmNode->mutex); OSTRACE(("SHM-LOCK pid=%lu, id=%d, sharedMask=%03x, exclMask=%03x, rc=%s\n", osGetCurrentProcessId(), p->id, p->sharedMask, p->exclMask, sqlite3ErrName(rc))); return rc; } /* ** Implement a memory barrier or memory fence on shared memory. ** ** All loads and stores begun before the barrier must complete before |
︙ | ︙ | |||
3394 3395 3396 3397 3398 3399 3400 | NULL, PAGE_READWRITE, 0, nByte, NULL ); #elif defined(SQLITE_WIN32_HAS_ANSI) hMap = osCreateFileMappingA(pShmNode->hFile.h, NULL, PAGE_READWRITE, 0, nByte, NULL ); #endif | | | | | | 3523 3524 3525 3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 3551 3552 3553 | NULL, PAGE_READWRITE, 0, nByte, NULL ); #elif defined(SQLITE_WIN32_HAS_ANSI) hMap = osCreateFileMappingA(pShmNode->hFile.h, NULL, PAGE_READWRITE, 0, nByte, NULL ); #endif OSTRACE(("SHM-MAP-CREATE pid=%lu, region=%d, size=%d, rc=%s\n", osGetCurrentProcessId(), pShmNode->nRegion, nByte, hMap ? "ok" : "failed")); if( hMap ){ int iOffset = pShmNode->nRegion*szRegion; int iOffsetShift = iOffset % winSysInfo.dwAllocationGranularity; #if SQLITE_OS_WINRT pMap = osMapViewOfFileFromApp(hMap, FILE_MAP_WRITE | FILE_MAP_READ, iOffset - iOffsetShift, szRegion + iOffsetShift ); #else pMap = osMapViewOfFile(hMap, FILE_MAP_WRITE | FILE_MAP_READ, 0, iOffset - iOffsetShift, szRegion + iOffsetShift ); #endif OSTRACE(("SHM-MAP-MAP pid=%lu, region=%d, offset=%d, size=%d, rc=%s\n", osGetCurrentProcessId(), pShmNode->nRegion, iOffset, szRegion, pMap ? "ok" : "failed")); } if( !pMap ){ pShmNode->lastErrno = osGetLastError(); rc = winLogError(SQLITE_IOERR_SHMMAP, pShmNode->lastErrno, "winShmMap3", pDbFd->zPath); if( hMap ) osCloseHandle(hMap); |
︙ | ︙ | |||
3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464 | #else # define winShmMap 0 # define winShmLock 0 # define winShmBarrier 0 # define winShmUnmap 0 #endif /* #ifndef SQLITE_OMIT_WAL */ /* ** Here ends the implementation of all sqlite3_file methods. ** ********************** End sqlite3_file Methods ******************************* ******************************************************************************/ /* ** This vector defines all the methods that can operate on an ** sqlite3_file for win32. */ static const sqlite3_io_methods winIoMethod = { | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | > > | 3575 3576 3577 3578 3579 3580 3581 3582 3583 3584 3585 3586 3587 3588 3589 3590 3591 3592 3593 3594 3595 3596 3597 3598 3599 3600 3601 3602 3603 3604 3605 3606 3607 3608 3609 3610 3611 3612 3613 3614 3615 3616 3617 3618 3619 3620 3621 3622 3623 3624 3625 3626 3627 3628 3629 3630 3631 3632 3633 3634 3635 3636 3637 3638 3639 3640 3641 3642 3643 3644 3645 3646 3647 3648 3649 3650 3651 3652 3653 3654 3655 3656 3657 3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 3676 3677 3678 3679 3680 3681 3682 3683 3684 3685 3686 3687 3688 3689 3690 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 3716 3717 3718 3719 3720 3721 3722 3723 3724 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 3830 3831 3832 3833 3834 3835 3836 3837 3838 3839 3840 3841 3842 3843 | #else # define winShmMap 0 # define winShmLock 0 # define winShmBarrier 0 # define winShmUnmap 0 #endif /* #ifndef SQLITE_OMIT_WAL */ /* ** Cleans up the mapped region of the specified file, if any. */ #if SQLITE_MAX_MMAP_SIZE>0 static int winUnmapfile(winFile *pFile){ assert( pFile!=0 ); OSTRACE(("UNMAP-FILE pid=%lu, pFile=%p, hMap=%p, pMapRegion=%p, " "mmapSize=%lld, mmapSizeActual=%lld, mmapSizeMax=%lld\n", osGetCurrentProcessId(), pFile, pFile->hMap, pFile->pMapRegion, pFile->mmapSize, pFile->mmapSizeActual, pFile->mmapSizeMax)); if( pFile->pMapRegion ){ if( !osUnmapViewOfFile(pFile->pMapRegion) ){ pFile->lastErrno = osGetLastError(); OSTRACE(("UNMAP-FILE pid=%lu, pFile=%p, pMapRegion=%p, " "rc=SQLITE_IOERR_MMAP\n", osGetCurrentProcessId(), pFile, pFile->pMapRegion)); return winLogError(SQLITE_IOERR_MMAP, pFile->lastErrno, "winUnmap1", pFile->zPath); } pFile->pMapRegion = 0; pFile->mmapSize = 0; pFile->mmapSizeActual = 0; } if( pFile->hMap!=NULL ){ if( !osCloseHandle(pFile->hMap) ){ pFile->lastErrno = osGetLastError(); OSTRACE(("UNMAP-FILE pid=%lu, pFile=%p, hMap=%p, rc=SQLITE_IOERR_MMAP\n", osGetCurrentProcessId(), pFile, pFile->hMap)); return winLogError(SQLITE_IOERR_MMAP, pFile->lastErrno, "winUnmap2", pFile->zPath); } pFile->hMap = NULL; } OSTRACE(("UNMAP-FILE pid=%lu, pFile=%p, rc=SQLITE_OK\n", osGetCurrentProcessId(), pFile)); return SQLITE_OK; } /* ** Memory map or remap the file opened by file-descriptor pFd (if the file ** is already mapped, the existing mapping is replaced by the new). Or, if ** there already exists a mapping for this file, and there are still ** outstanding xFetch() references to it, this function is a no-op. ** ** If parameter nByte is non-negative, then it is the requested size of ** the mapping to create. Otherwise, if nByte is less than zero, then the ** requested size is the size of the file on disk. The actual size of the ** created mapping is either the requested size or the value configured ** using SQLITE_FCNTL_MMAP_SIZE, whichever is smaller. ** ** SQLITE_OK is returned if no error occurs (even if the mapping is not ** recreated as a result of outstanding references) or an SQLite error ** code otherwise. */ static int winMapfile(winFile *pFd, sqlite3_int64 nByte){ sqlite3_int64 nMap = nByte; int rc; assert( nMap>=0 || pFd->nFetchOut==0 ); OSTRACE(("MAP-FILE pid=%lu, pFile=%p, size=%lld\n", osGetCurrentProcessId(), pFd, nByte)); if( pFd->nFetchOut>0 ) return SQLITE_OK; if( nMap<0 ){ rc = winFileSize((sqlite3_file*)pFd, &nMap); if( rc ){ OSTRACE(("MAP-FILE pid=%lu, pFile=%p, rc=SQLITE_IOERR_FSTAT\n", osGetCurrentProcessId(), pFd)); return SQLITE_IOERR_FSTAT; } } if( nMap>pFd->mmapSizeMax ){ nMap = pFd->mmapSizeMax; } nMap &= ~(sqlite3_int64)(winSysInfo.dwPageSize - 1); if( nMap==0 && pFd->mmapSize>0 ){ winUnmapfile(pFd); } if( nMap!=pFd->mmapSize ){ void *pNew = 0; DWORD protect = PAGE_READONLY; DWORD flags = FILE_MAP_READ; winUnmapfile(pFd); if( (pFd->ctrlFlags & WINFILE_RDONLY)==0 ){ protect = PAGE_READWRITE; flags |= FILE_MAP_WRITE; } #if SQLITE_OS_WINRT pFd->hMap = osCreateFileMappingFromApp(pFd->h, NULL, protect, nMap, NULL); #elif defined(SQLITE_WIN32_HAS_WIDE) pFd->hMap = osCreateFileMappingW(pFd->h, NULL, protect, (DWORD)((nMap>>32) & 0xffffffff), (DWORD)(nMap & 0xffffffff), NULL); #elif defined(SQLITE_WIN32_HAS_ANSI) pFd->hMap = osCreateFileMappingA(pFd->h, NULL, protect, (DWORD)((nMap>>32) & 0xffffffff), (DWORD)(nMap & 0xffffffff), NULL); #endif if( pFd->hMap==NULL ){ pFd->lastErrno = osGetLastError(); rc = winLogError(SQLITE_IOERR_MMAP, pFd->lastErrno, "winMapfile", pFd->zPath); /* Log the error, but continue normal operation using xRead/xWrite */ OSTRACE(("MAP-FILE-CREATE pid=%lu, pFile=%p, rc=SQLITE_IOERR_MMAP\n", osGetCurrentProcessId(), pFd)); return SQLITE_OK; } assert( (nMap % winSysInfo.dwPageSize)==0 ); #if SQLITE_OS_WINRT pNew = osMapViewOfFileFromApp(pFd->hMap, flags, 0, nMap); #else assert( sizeof(SIZE_T)==sizeof(sqlite3_int64) || nMap<=0xffffffff ); pNew = osMapViewOfFile(pFd->hMap, flags, 0, 0, (SIZE_T)nMap); #endif if( pNew==NULL ){ osCloseHandle(pFd->hMap); pFd->hMap = NULL; pFd->lastErrno = osGetLastError(); winLogError(SQLITE_IOERR_MMAP, pFd->lastErrno, "winMapfile", pFd->zPath); OSTRACE(("MAP-FILE-MAP pid=%lu, pFile=%p, rc=SQLITE_IOERR_MMAP\n", osGetCurrentProcessId(), pFd)); return SQLITE_OK; } pFd->pMapRegion = pNew; pFd->mmapSize = nMap; pFd->mmapSizeActual = nMap; } OSTRACE(("MAP-FILE pid=%lu, pFile=%p, rc=SQLITE_OK\n", osGetCurrentProcessId(), pFd)); return SQLITE_OK; } #endif /* SQLITE_MAX_MMAP_SIZE>0 */ /* ** If possible, return a pointer to a mapping of file fd starting at offset ** iOff. The mapping must be valid for at least nAmt bytes. ** ** If such a pointer can be obtained, store it in *pp and return SQLITE_OK. ** Or, if one cannot but no error occurs, set *pp to 0 and return SQLITE_OK. ** Finally, if an error does occur, return an SQLite error code. The final ** value of *pp is undefined in this case. ** ** If this function does return a pointer, the caller must eventually ** release the reference by calling winUnfetch(). */ static int winFetch(sqlite3_file *fd, i64 iOff, int nAmt, void **pp){ #if SQLITE_MAX_MMAP_SIZE>0 winFile *pFd = (winFile*)fd; /* The underlying database file */ #endif *pp = 0; OSTRACE(("FETCH pid=%lu, pFile=%p, offset=%lld, amount=%d, pp=%p\n", osGetCurrentProcessId(), fd, iOff, nAmt, pp)); #if SQLITE_MAX_MMAP_SIZE>0 if( pFd->mmapSizeMax>0 ){ if( pFd->pMapRegion==0 ){ int rc = winMapfile(pFd, -1); if( rc!=SQLITE_OK ){ OSTRACE(("FETCH pid=%lu, pFile=%p, rc=%s\n", osGetCurrentProcessId(), pFd, sqlite3ErrName(rc))); return rc; } } if( pFd->mmapSize >= iOff+nAmt ){ *pp = &((u8 *)pFd->pMapRegion)[iOff]; pFd->nFetchOut++; } } #endif OSTRACE(("FETCH pid=%lu, pFile=%p, pp=%p, *pp=%p, rc=SQLITE_OK\n", osGetCurrentProcessId(), fd, pp, *pp)); return SQLITE_OK; } /* ** If the third argument is non-NULL, then this function releases a ** reference obtained by an earlier call to winFetch(). The second ** argument passed to this function must be the same as the corresponding ** argument that was passed to the winFetch() invocation. ** ** Or, if the third argument is NULL, then this function is being called ** to inform the VFS layer that, according to POSIX, any existing mapping ** may now be invalid and should be unmapped. */ static int winUnfetch(sqlite3_file *fd, i64 iOff, void *p){ #if SQLITE_MAX_MMAP_SIZE>0 winFile *pFd = (winFile*)fd; /* The underlying database file */ /* If p==0 (unmap the entire file) then there must be no outstanding ** xFetch references. Or, if p!=0 (meaning it is an xFetch reference), ** then there must be at least one outstanding. */ assert( (p==0)==(pFd->nFetchOut==0) ); /* If p!=0, it must match the iOff value. */ assert( p==0 || p==&((u8 *)pFd->pMapRegion)[iOff] ); OSTRACE(("UNFETCH pid=%lu, pFile=%p, offset=%lld, p=%p\n", osGetCurrentProcessId(), pFd, iOff, p)); if( p ){ pFd->nFetchOut--; }else{ /* FIXME: If Windows truly always prevents truncating or deleting a ** file while a mapping is held, then the following winUnmapfile() call ** is unnecessary can can be omitted - potentially improving ** performance. */ winUnmapfile(pFd); } assert( pFd->nFetchOut>=0 ); #endif OSTRACE(("UNFETCH pid=%lu, pFile=%p, rc=SQLITE_OK\n", osGetCurrentProcessId(), fd)); return SQLITE_OK; } /* ** Here ends the implementation of all sqlite3_file methods. ** ********************** End sqlite3_file Methods ******************************* ******************************************************************************/ /* ** This vector defines all the methods that can operate on an ** sqlite3_file for win32. */ static const sqlite3_io_methods winIoMethod = { 3, /* iVersion */ winClose, /* xClose */ winRead, /* xRead */ winWrite, /* xWrite */ winTruncate, /* xTruncate */ winSync, /* xSync */ winFileSize, /* xFileSize */ winLock, /* xLock */ winUnlock, /* xUnlock */ winCheckReservedLock, /* xCheckReservedLock */ winFileControl, /* xFileControl */ winSectorSize, /* xSectorSize */ winDeviceCharacteristics, /* xDeviceCharacteristics */ winShmMap, /* xShmMap */ winShmLock, /* xShmLock */ winShmBarrier, /* xShmBarrier */ winShmUnmap, /* xShmUnmap */ winFetch, /* xFetch */ winUnfetch /* xUnfetch */ }; /**************************************************************************** **************************** sqlite3_vfs methods **************************** ** ** This division contains the implementation of methods on the ** sqlite3_vfs object. |
︙ | ︙ | |||
3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 3551 3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 3564 3565 3566 3567 3568 3569 3570 3571 3572 3573 3574 3575 3576 3577 3578 3579 3580 3581 3582 3583 3584 3585 3586 | WCHAR zWidePath[MAX_PATH]; osGetTempPathW(MAX_PATH-30, zWidePath); zMulti = unicodeToUtf8(zWidePath); if( zMulti ){ sqlite3_snprintf(MAX_PATH-30, zTempPath, "%s", zMulti); sqlite3_free(zMulti); }else{ return SQLITE_IOERR_NOMEM; } } #ifdef SQLITE_WIN32_HAS_ANSI else{ char *zUtf8; char zMbcsPath[MAX_PATH]; osGetTempPathA(MAX_PATH-30, zMbcsPath); zUtf8 = sqlite3_win32_mbcs_to_utf8(zMbcsPath); if( zUtf8 ){ sqlite3_snprintf(MAX_PATH-30, zTempPath, "%s", zUtf8); sqlite3_free(zUtf8); }else{ return SQLITE_IOERR_NOMEM; } } #endif #endif /* Check that the output buffer is large enough for the temporary file ** name. If it is not, return SQLITE_ERROR. */ nTempPath = sqlite3Strlen30(zTempPath); if( (nTempPath + sqlite3Strlen30(SQLITE_TEMP_FILE_PREFIX) + 18) >= nBuf ){ return SQLITE_ERROR; } for(i=nTempPath; i>0 && zTempPath[i-1]=='\\'; i--){} zTempPath[i] = 0; sqlite3_snprintf(nBuf-18, zBuf, (nTempPath > 0) ? "%s\\"SQLITE_TEMP_FILE_PREFIX : SQLITE_TEMP_FILE_PREFIX, zTempPath); j = sqlite3Strlen30(zBuf); sqlite3_randomness(15, &zBuf[j]); for(i=0; i<15; i++, j++){ zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ]; } zBuf[j] = 0; zBuf[j+1] = 0; | > > > | | 3893 3894 3895 3896 3897 3898 3899 3900 3901 3902 3903 3904 3905 3906 3907 3908 3909 3910 3911 3912 3913 3914 3915 3916 3917 3918 3919 3920 3921 3922 3923 3924 3925 3926 3927 3928 3929 3930 3931 3932 3933 3934 3935 3936 3937 3938 3939 3940 3941 3942 3943 3944 3945 3946 3947 3948 3949 3950 3951 3952 | WCHAR zWidePath[MAX_PATH]; osGetTempPathW(MAX_PATH-30, zWidePath); zMulti = unicodeToUtf8(zWidePath); if( zMulti ){ sqlite3_snprintf(MAX_PATH-30, zTempPath, "%s", zMulti); sqlite3_free(zMulti); }else{ OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n")); return SQLITE_IOERR_NOMEM; } } #ifdef SQLITE_WIN32_HAS_ANSI else{ char *zUtf8; char zMbcsPath[MAX_PATH]; osGetTempPathA(MAX_PATH-30, zMbcsPath); zUtf8 = sqlite3_win32_mbcs_to_utf8(zMbcsPath); if( zUtf8 ){ sqlite3_snprintf(MAX_PATH-30, zTempPath, "%s", zUtf8); sqlite3_free(zUtf8); }else{ OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n")); return SQLITE_IOERR_NOMEM; } } #endif #endif /* Check that the output buffer is large enough for the temporary file ** name. If it is not, return SQLITE_ERROR. */ nTempPath = sqlite3Strlen30(zTempPath); if( (nTempPath + sqlite3Strlen30(SQLITE_TEMP_FILE_PREFIX) + 18) >= nBuf ){ OSTRACE(("TEMP-FILENAME rc=SQLITE_ERROR\n")); return SQLITE_ERROR; } for(i=nTempPath; i>0 && zTempPath[i-1]=='\\'; i--){} zTempPath[i] = 0; sqlite3_snprintf(nBuf-18, zBuf, (nTempPath > 0) ? "%s\\"SQLITE_TEMP_FILE_PREFIX : SQLITE_TEMP_FILE_PREFIX, zTempPath); j = sqlite3Strlen30(zBuf); sqlite3_randomness(15, &zBuf[j]); for(i=0; i<15; i++, j++){ zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ]; } zBuf[j] = 0; zBuf[j+1] = 0; OSTRACE(("TEMP-FILENAME name=%s, rc=SQLITE_OK\n", zBuf)); return SQLITE_OK; } /* ** Return TRUE if the named file is really a directory. Return false if ** it is something other than a directory, or if there is any kind of memory ** allocation failure. |
︙ | ︙ | |||
3650 3651 3652 3653 3654 3655 3656 | #if !defined(NDEBUG) || SQLITE_OS_WINCE int eType = flags&0xFFFFFF00; /* Type of file to open */ #endif int isExclusive = (flags & SQLITE_OPEN_EXCLUSIVE); int isDelete = (flags & SQLITE_OPEN_DELETEONCLOSE); int isCreate = (flags & SQLITE_OPEN_CREATE); | < < > > > | 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 | #if !defined(NDEBUG) || SQLITE_OS_WINCE int eType = flags&0xFFFFFF00; /* Type of file to open */ #endif int isExclusive = (flags & SQLITE_OPEN_EXCLUSIVE); int isDelete = (flags & SQLITE_OPEN_DELETEONCLOSE); int isCreate = (flags & SQLITE_OPEN_CREATE); int isReadonly = (flags & SQLITE_OPEN_READONLY); int isReadWrite = (flags & SQLITE_OPEN_READWRITE); #ifndef NDEBUG int isOpenJournal = (isCreate && ( eType==SQLITE_OPEN_MASTER_JOURNAL || eType==SQLITE_OPEN_MAIN_JOURNAL || eType==SQLITE_OPEN_WAL )); #endif OSTRACE(("OPEN name=%s, pFile=%p, flags=%x, pOutFlags=%p\n", zUtf8Name, id, flags, pOutFlags)); /* Check the following statements are true: ** ** (a) Exactly one of the READWRITE and READONLY flags must be set, and ** (b) if CREATE is set, then READWRITE must also be set, and ** (c) if EXCLUSIVE is set, then CREATE must also be set. ** (d) if DELETEONCLOSE is set, then CREATE must also be set. |
︙ | ︙ | |||
3708 3709 3710 3711 3712 3713 3714 3715 3716 3717 3718 3719 3720 3721 3722 3723 3724 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 3737 3738 3739 3740 3741 | ** temporary file name to use */ if( !zUtf8Name ){ assert(isDelete && !isOpenJournal); memset(zTmpname, 0, MAX_PATH+2); rc = getTempname(MAX_PATH+2, zTmpname); if( rc!=SQLITE_OK ){ return rc; } zUtf8Name = zTmpname; } /* Database filenames are double-zero terminated if they are not ** URIs with parameters. Hence, they can always be passed into ** sqlite3_uri_parameter(). */ assert( (eType!=SQLITE_OPEN_MAIN_DB) || (flags & SQLITE_OPEN_URI) || zUtf8Name[strlen(zUtf8Name)+1]==0 ); /* Convert the filename to the system encoding. */ zConverted = convertUtf8Filename(zUtf8Name); if( zConverted==0 ){ return SQLITE_IOERR_NOMEM; } if( winIsDir(zConverted) ){ sqlite3_free(zConverted); return SQLITE_CANTOPEN_ISDIR; } if( isReadWrite ){ dwDesiredAccess = GENERIC_READ | GENERIC_WRITE; }else{ dwDesiredAccess = GENERIC_READ; | > > > | 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 | ** temporary file name to use */ if( !zUtf8Name ){ assert(isDelete && !isOpenJournal); memset(zTmpname, 0, MAX_PATH+2); rc = getTempname(MAX_PATH+2, zTmpname); if( rc!=SQLITE_OK ){ OSTRACE(("OPEN name=%s, rc=%s", zUtf8Name, sqlite3ErrName(rc))); return rc; } zUtf8Name = zTmpname; } /* Database filenames are double-zero terminated if they are not ** URIs with parameters. Hence, they can always be passed into ** sqlite3_uri_parameter(). */ assert( (eType!=SQLITE_OPEN_MAIN_DB) || (flags & SQLITE_OPEN_URI) || zUtf8Name[strlen(zUtf8Name)+1]==0 ); /* Convert the filename to the system encoding. */ zConverted = convertUtf8Filename(zUtf8Name); if( zConverted==0 ){ OSTRACE(("OPEN name=%s, rc=SQLITE_IOERR_NOMEM", zUtf8Name)); return SQLITE_IOERR_NOMEM; } if( winIsDir(zConverted) ){ sqlite3_free(zConverted); OSTRACE(("OPEN name=%s, rc=SQLITE_CANTOPEN_ISDIR", zUtf8Name)); return SQLITE_CANTOPEN_ISDIR; } if( isReadWrite ){ dwDesiredAccess = GENERIC_READ | GENERIC_WRITE; }else{ dwDesiredAccess = GENERIC_READ; |
︙ | ︙ | |||
3818 3819 3820 3821 3822 3823 3824 | retryIoerr(&cnt, &lastErrno) ){ /* Noop */ } } #endif logIoerr(cnt); | | < | | 4180 4181 4182 4183 4184 4185 4186 4187 4188 4189 4190 4191 4192 4193 4194 4195 | retryIoerr(&cnt, &lastErrno) ){ /* Noop */ } } #endif logIoerr(cnt); OSTRACE(("OPEN file=%p, name=%s, access=%lx, rc=%s\n", h, zUtf8Name, dwDesiredAccess, (h==INVALID_HANDLE_VALUE) ? "failed" : "ok")); if( h==INVALID_HANDLE_VALUE ){ pFile->lastErrno = lastErrno; winLogError(SQLITE_CANTOPEN, pFile->lastErrno, "winOpen", zUtf8Name); sqlite3_free(zConverted); if( isReadWrite && !isExclusive ){ return winOpen(pVfs, zName, id, |
︙ | ︙ | |||
3844 3845 3846 3847 3848 3849 3850 3851 3852 3853 3854 3855 3856 3857 3858 3859 3860 3861 3862 3863 3864 3865 3866 3867 3868 3869 3870 3871 3872 3873 3874 3875 3876 3877 3878 3879 3880 3881 | if( isReadWrite ){ *pOutFlags = SQLITE_OPEN_READWRITE; }else{ *pOutFlags = SQLITE_OPEN_READONLY; } } #if SQLITE_OS_WINCE if( isReadWrite && eType==SQLITE_OPEN_MAIN_DB && (rc = winceCreateLock(zName, pFile))!=SQLITE_OK ){ osCloseHandle(h); sqlite3_free(zConverted); return rc; } if( isTemp ){ pFile->zDeleteOnClose = zConverted; }else #endif { sqlite3_free(zConverted); } pFile->pMethod = &winIoMethod; pFile->pVfs = pVfs; pFile->h = h; if( sqlite3_uri_boolean(zName, "psow", SQLITE_POWERSAFE_OVERWRITE) ){ pFile->ctrlFlags |= WINFILE_PSOW; } pFile->lastErrno = NO_ERROR; pFile->zPath = zName; OpenCounter(+1); return rc; } /* ** Delete the named file. | > > > > > > > > > > > > > > > | 4205 4206 4207 4208 4209 4210 4211 4212 4213 4214 4215 4216 4217 4218 4219 4220 4221 4222 4223 4224 4225 4226 4227 4228 4229 4230 4231 4232 4233 4234 4235 4236 4237 4238 4239 4240 4241 4242 4243 4244 4245 4246 4247 4248 4249 4250 4251 4252 4253 4254 4255 4256 4257 | if( isReadWrite ){ *pOutFlags = SQLITE_OPEN_READWRITE; }else{ *pOutFlags = SQLITE_OPEN_READONLY; } } OSTRACE(("OPEN file=%p, name=%s, access=%lx, pOutFlags=%p, *pOutFlags=%d, " "rc=%s\n", h, zUtf8Name, dwDesiredAccess, pOutFlags, pOutFlags ? *pOutFlags : 0, (h==INVALID_HANDLE_VALUE) ? "failed" : "ok")); #if SQLITE_OS_WINCE if( isReadWrite && eType==SQLITE_OPEN_MAIN_DB && (rc = winceCreateLock(zName, pFile))!=SQLITE_OK ){ osCloseHandle(h); sqlite3_free(zConverted); OSTRACE(("OPEN-CE-LOCK name=%s, rc=%s\n", zName, sqlite3ErrName(rc))); return rc; } if( isTemp ){ pFile->zDeleteOnClose = zConverted; }else #endif { sqlite3_free(zConverted); } pFile->pMethod = &winIoMethod; pFile->pVfs = pVfs; pFile->h = h; if( isReadonly ){ pFile->ctrlFlags |= WINFILE_RDONLY; } if( sqlite3_uri_boolean(zName, "psow", SQLITE_POWERSAFE_OVERWRITE) ){ pFile->ctrlFlags |= WINFILE_PSOW; } pFile->lastErrno = NO_ERROR; pFile->zPath = zName; #if SQLITE_MAX_MMAP_SIZE>0 pFile->hMap = NULL; pFile->pMapRegion = 0; pFile->mmapSize = 0; pFile->mmapSizeActual = 0; pFile->mmapSizeMax = sqlite3GlobalConfig.mxMmap; #endif OpenCounter(+1); return rc; } /* ** Delete the named file. |
︙ | ︙ | |||
3899 3900 3901 3902 3903 3904 3905 3906 3907 3908 3909 3910 3911 3912 | DWORD attr; DWORD lastErrno; void *zConverted; UNUSED_PARAMETER(pVfs); UNUSED_PARAMETER(syncDir); SimulateIOError(return SQLITE_IOERR_DELETE); zConverted = convertUtf8Filename(zFilename); if( zConverted==0 ){ return SQLITE_IOERR_NOMEM; } if( isNT() ){ do { #if SQLITE_OS_WINRT | > > | 4275 4276 4277 4278 4279 4280 4281 4282 4283 4284 4285 4286 4287 4288 4289 4290 | DWORD attr; DWORD lastErrno; void *zConverted; UNUSED_PARAMETER(pVfs); UNUSED_PARAMETER(syncDir); SimulateIOError(return SQLITE_IOERR_DELETE); OSTRACE(("DELETE name=%s, syncDir=%d\n", zFilename, syncDir)); zConverted = convertUtf8Filename(zFilename); if( zConverted==0 ){ return SQLITE_IOERR_NOMEM; } if( isNT() ){ do { #if SQLITE_OS_WINRT |
︙ | ︙ | |||
3984 3985 3986 3987 3988 3989 3990 | if( rc && rc!=SQLITE_IOERR_DELETE_NOENT ){ rc = winLogError(SQLITE_IOERR_DELETE, lastErrno, "winDelete", zFilename); }else{ logIoerr(cnt); } sqlite3_free(zConverted); | | | > > > > | 4362 4363 4364 4365 4366 4367 4368 4369 4370 4371 4372 4373 4374 4375 4376 4377 4378 4379 4380 4381 4382 4383 4384 4385 4386 4387 4388 4389 4390 4391 4392 4393 4394 4395 4396 4397 4398 4399 4400 4401 | if( rc && rc!=SQLITE_IOERR_DELETE_NOENT ){ rc = winLogError(SQLITE_IOERR_DELETE, lastErrno, "winDelete", zFilename); }else{ logIoerr(cnt); } sqlite3_free(zConverted); OSTRACE(("DELETE name=%s, rc=%s\n", zFilename, sqlite3ErrName(rc))); return rc; } /* ** Check the existence and status of a file. */ static int winAccess( sqlite3_vfs *pVfs, /* Not used on win32 */ const char *zFilename, /* Name of file to check */ int flags, /* Type of test to make on this file */ int *pResOut /* OUT: Result */ ){ DWORD attr; int rc = 0; DWORD lastErrno; void *zConverted; UNUSED_PARAMETER(pVfs); SimulateIOError( return SQLITE_IOERR_ACCESS; ); OSTRACE(("ACCESS name=%s, flags=%x, pResOut=%p\n", zFilename, flags, pResOut)); zConverted = convertUtf8Filename(zFilename); if( zConverted==0 ){ OSTRACE(("ACCESS name=%s, rc=SQLITE_IOERR_NOMEM\n", zFilename)); return SQLITE_IOERR_NOMEM; } if( isNT() ){ int cnt = 0; WIN32_FILE_ATTRIBUTE_DATA sAttrData; memset(&sAttrData, 0, sizeof(sAttrData)); while( !(rc = osGetFileAttributesExW((LPCWSTR)zConverted, |
︙ | ︙ | |||
4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 | rc = attr!=INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_READONLY)==0; break; default: assert(!"Invalid flags argument"); } *pResOut = rc; return SQLITE_OK; } /* ** Returns non-zero if the specified path name should be used verbatim. If ** non-zero is returned from this function, the calling function must simply | > > | 4438 4439 4440 4441 4442 4443 4444 4445 4446 4447 4448 4449 4450 4451 4452 4453 | rc = attr!=INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_READONLY)==0; break; default: assert(!"Invalid flags argument"); } *pResOut = rc; OSTRACE(("ACCESS name=%s, pResOut=%p, *pResOut=%d, rc=SQLITE_OK\n", zFilename, pResOut, *pResOut)); return SQLITE_OK; } /* ** Returns non-zero if the specified path name should be used verbatim. If ** non-zero is returned from this function, the calling function must simply |
︙ | ︙ | |||
4496 4497 4498 4499 4500 4501 4502 | winNextSystemCall, /* xNextSystemCall */ }; /* Double-check that the aSyscall[] array has been constructed ** correctly. See ticket [bb3a86e890c8e96ab] */ assert( ArraySize(aSyscall)==74 ); | < | | 4880 4881 4882 4883 4884 4885 4886 4887 4888 4889 4890 4891 4892 4893 4894 4895 4896 4897 4898 4899 4900 4901 4902 | winNextSystemCall, /* xNextSystemCall */ }; /* Double-check that the aSyscall[] array has been constructed ** correctly. See ticket [bb3a86e890c8e96ab] */ assert( ArraySize(aSyscall)==74 ); /* get memory map allocation granularity */ memset(&winSysInfo, 0, sizeof(SYSTEM_INFO)); #if SQLITE_OS_WINRT osGetNativeSystemInfo(&winSysInfo); #else osGetSystemInfo(&winSysInfo); #endif assert(winSysInfo.dwAllocationGranularity > 0); assert( winSysInfo.dwPageSize>0 ); sqlite3_vfs_register(&winVfs, 1); return SQLITE_OK; } int sqlite3_os_end(void){ #if SQLITE_OS_WINRT |
︙ | ︙ |
Changes to src/pager.c.
︙ | ︙ | |||
269 270 271 272 273 274 275 | ** by finalizing the journal file. Once in WRITER_FINISHED state, it is ** not possible to modify the database further. At this point, the upper ** layer must either commit or rollback the transaction. ** ** * A write transaction is active. ** * An EXCLUSIVE or greater lock is held on the database file. ** * All writing and syncing of journal and database data has finished. | | | 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 | ** by finalizing the journal file. Once in WRITER_FINISHED state, it is ** not possible to modify the database further. At this point, the upper ** layer must either commit or rollback the transaction. ** ** * A write transaction is active. ** * An EXCLUSIVE or greater lock is held on the database file. ** * All writing and syncing of journal and database data has finished. ** If no error occurred, all that remains is to finalize the journal to ** commit the transaction. If an error did occur, the caller will need ** to rollback the transaction. ** ** ERROR: ** ** The ERROR state is entered when an IO or disk-full error (including ** SQLITE_IOERR_NOMEM) occurs at a point in the code that makes it |
︙ | ︙ | |||
517 518 519 520 521 522 523 | ** The flag is cleared as soon as the journal file is finalized (either ** by PagerCommitPhaseTwo or PagerRollback). If an IO error prevents the ** journal file from being successfully finalized, the setMaster flag ** is cleared anyway (and the pager will move to ERROR state). ** ** doNotSpill, doNotSyncSpill ** | | | 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 | ** The flag is cleared as soon as the journal file is finalized (either ** by PagerCommitPhaseTwo or PagerRollback). If an IO error prevents the ** journal file from being successfully finalized, the setMaster flag ** is cleared anyway (and the pager will move to ERROR state). ** ** doNotSpill, doNotSyncSpill ** ** These two boolean variables control the behavior of cache-spills ** (calls made by the pcache module to the pagerStress() routine to ** write cached data to the file-system in order to free up memory). ** ** When doNotSpill is non-zero, writing to the database from pagerStress() ** is disabled altogether. This is done in a very obscure case that ** comes up during savepoint rollback that requires the pcache module ** to allocate a new page to prevent the journal file from being written |
︙ | ︙ | |||
651 652 653 654 655 656 657 658 659 660 661 662 663 664 | sqlite3_file *sjfd; /* File descriptor for sub-journal */ i64 journalOff; /* Current write offset in the journal file */ i64 journalHdr; /* Byte offset to previous journal header */ sqlite3_backup *pBackup; /* Pointer to list of ongoing backup processes */ PagerSavepoint *aSavepoint; /* Array of active savepoints */ int nSavepoint; /* Number of elements in aSavepoint[] */ char dbFileVers[16]; /* Changes whenever database file changes */ /* ** End of the routinely-changing class members ***************************************************************************/ u16 nExtra; /* Add this many bytes to each in-memory page */ i16 nReserve; /* Number of unused bytes at end of each page */ u32 vfsFlags; /* Flags for sqlite3_vfs.xOpen() */ | > > > > > | 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 | sqlite3_file *sjfd; /* File descriptor for sub-journal */ i64 journalOff; /* Current write offset in the journal file */ i64 journalHdr; /* Byte offset to previous journal header */ sqlite3_backup *pBackup; /* Pointer to list of ongoing backup processes */ PagerSavepoint *aSavepoint; /* Array of active savepoints */ int nSavepoint; /* Number of elements in aSavepoint[] */ char dbFileVers[16]; /* Changes whenever database file changes */ u8 bUseFetch; /* True to use xFetch() */ int nMmapOut; /* Number of mmap pages currently outstanding */ sqlite3_int64 szMmap; /* Desired maximum mmap size */ PgHdr *pMmapFreelist; /* List of free mmap page headers (pDirty) */ /* ** End of the routinely-changing class members ***************************************************************************/ u16 nExtra; /* Add this many bytes to each in-memory page */ i16 nReserve; /* Number of unused bytes at end of each page */ u32 vfsFlags; /* Flags for sqlite3_vfs.xOpen() */ |
︙ | ︙ | |||
761 762 763 764 765 766 767 768 769 770 771 772 773 774 | */ #ifdef SQLITE_OMIT_MEMORYDB # define MEMDB 0 #else # define MEMDB pPager->memDb #endif /* ** The maximum legal page number is (2^31 - 1). */ #define PAGER_MAX_PGNO 2147483647 /* ** The argument to this macro is a file descriptor (type sqlite3_file*). | > > > > > > > > > > | 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 | */ #ifdef SQLITE_OMIT_MEMORYDB # define MEMDB 0 #else # define MEMDB pPager->memDb #endif /* ** The macro USEFETCH is true if we are allowed to use the xFetch and xUnfetch ** interfaces to access the database using memory-mapped I/O. */ #if SQLITE_MAX_MMAP_SIZE>0 # define USEFETCH(x) ((x)->bUseFetch) #else # define USEFETCH(x) 0 #endif /* ** The maximum legal page number is (2^31 - 1). */ #define PAGER_MAX_PGNO 2147483647 /* ** The argument to this macro is a file descriptor (type sqlite3_file*). |
︙ | ︙ | |||
1395 1396 1397 1398 1399 1400 1401 | ){ memcpy(zHeader, aJournalMagic, sizeof(aJournalMagic)); put32bits(&zHeader[sizeof(aJournalMagic)], 0xffffffff); }else{ memset(zHeader, 0, sizeof(aJournalMagic)+4); } | | | 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 | ){ memcpy(zHeader, aJournalMagic, sizeof(aJournalMagic)); put32bits(&zHeader[sizeof(aJournalMagic)], 0xffffffff); }else{ memset(zHeader, 0, sizeof(aJournalMagic)+4); } /* The random check-hash initializer */ sqlite3_randomness(sizeof(pPager->cksumInit), &pPager->cksumInit); put32bits(&zHeader[sizeof(aJournalMagic)+4], pPager->cksumInit); /* The initial database size */ put32bits(&zHeader[sizeof(aJournalMagic)+8], pPager->dbOrigSize); /* The assumed sector size for this process */ put32bits(&zHeader[sizeof(aJournalMagic)+12], pPager->sectorSize); |
︙ | ︙ | |||
2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 | u32 nRec; /* Number of Records in the journal */ u32 u; /* Unsigned loop counter */ Pgno mxPg = 0; /* Size of the original file in pages */ int rc; /* Result code of a subroutine */ int res = 1; /* Value returned by sqlite3OsAccess() */ char *zMaster = 0; /* Name of master journal file if any */ int needPagerReset; /* True to reset page prior to first page rollback */ /* Figure out how many records are in the journal. Abort early if ** the journal is empty. */ assert( isOpen(pPager->jfd) ); rc = sqlite3OsFileSize(pPager->jfd, &szJ); if( rc!=SQLITE_OK ){ | > | 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 | u32 nRec; /* Number of Records in the journal */ u32 u; /* Unsigned loop counter */ Pgno mxPg = 0; /* Size of the original file in pages */ int rc; /* Result code of a subroutine */ int res = 1; /* Value returned by sqlite3OsAccess() */ char *zMaster = 0; /* Name of master journal file if any */ int needPagerReset; /* True to reset page prior to first page rollback */ int nPlayback = 0; /* Total number of pages restored from journal */ /* Figure out how many records are in the journal. Abort early if ** the journal is empty. */ assert( isOpen(pPager->jfd) ); rc = sqlite3OsFileSize(pPager->jfd, &szJ); if( rc!=SQLITE_OK ){ |
︙ | ︙ | |||
2739 2740 2741 2742 2743 2744 2745 | */ for(u=0; u<nRec; u++){ if( needPagerReset ){ pager_reset(pPager); needPagerReset = 0; } rc = pager_playback_one_page(pPager,&pPager->journalOff,0,1,0); | | > > | 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 | */ for(u=0; u<nRec; u++){ if( needPagerReset ){ pager_reset(pPager); needPagerReset = 0; } rc = pager_playback_one_page(pPager,&pPager->journalOff,0,1,0); if( rc==SQLITE_OK ){ nPlayback++; }else{ if( rc==SQLITE_DONE ){ pPager->journalOff = szJ; break; }else if( rc==SQLITE_IOERR_SHORT_READ ){ /* If the journal has been truncated, simply stop reading and ** processing the journal. This might happen if the journal was ** not completely written and synced prior to a crash. In that |
︙ | ︙ | |||
2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 | if( rc==SQLITE_OK && zMaster[0] && res ){ /* If there was a master journal and this routine will return success, ** see if it is possible to delete the master journal. */ rc = pager_delmaster(pPager, zMaster); testcase( rc!=SQLITE_OK ); } /* The Pager.sectorSize variable may have been updated while rolling ** back a journal created by a process with a different sector size ** value. Reset it to the correct value for this process. */ setSectorSize(pPager); return rc; | > > > > | 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 | if( rc==SQLITE_OK && zMaster[0] && res ){ /* If there was a master journal and this routine will return success, ** see if it is possible to delete the master journal. */ rc = pager_delmaster(pPager, zMaster); testcase( rc!=SQLITE_OK ); } if( isHot && nPlayback ){ sqlite3_log(SQLITE_NOTICE_RECOVER_ROLLBACK, "recovered %d pages from %s", nPlayback, pPager->zJournal); } /* The Pager.sectorSize variable may have been updated while rolling ** back a journal created by a process with a different sector size ** value. Reset it to the correct value for this process. */ setSectorSize(pPager); return rc; |
︙ | ︙ | |||
2830 2831 2832 2833 2834 2835 2836 | ** ** If page 1 is read, then the value of Pager.dbFileVers[] is set to ** the value read from the database file. ** ** If an IO error occurs, then the IO error is returned to the caller. ** Otherwise, SQLITE_OK is returned. */ | | < > | | | | > | 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 | ** ** If page 1 is read, then the value of Pager.dbFileVers[] is set to ** the value read from the database file. ** ** If an IO error occurs, then the IO error is returned to the caller. ** Otherwise, SQLITE_OK is returned. */ static int readDbPage(PgHdr *pPg, u32 iFrame){ Pager *pPager = pPg->pPager; /* Pager object associated with page pPg */ Pgno pgno = pPg->pgno; /* Page number to read */ int rc = SQLITE_OK; /* Return code */ int pgsz = pPager->pageSize; /* Number of bytes to read */ assert( pPager->eState>=PAGER_READER && !MEMDB ); assert( isOpen(pPager->fd) ); if( NEVER(!isOpen(pPager->fd)) ){ assert( pPager->tempFile ); memset(pPg->pData, 0, pPager->pageSize); return SQLITE_OK; } #ifndef SQLITE_OMIT_WAL if( iFrame ){ /* Try to pull the page from the write-ahead log. */ rc = sqlite3WalReadFrame(pPager->pWal, iFrame, pgsz, pPg->pData); }else #endif { i64 iOffset = (pgno-1)*(i64)pPager->pageSize; rc = sqlite3OsRead(pPager->fd, pPg->pData, pgsz, iOffset); if( rc==SQLITE_IOERR_SHORT_READ ){ rc = SQLITE_OK; } } |
︙ | ︙ | |||
2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 | ** return an SQLite error code. Otherwise, SQLITE_OK. */ static int pagerUndoCallback(void *pCtx, Pgno iPg){ int rc = SQLITE_OK; Pager *pPager = (Pager *)pCtx; PgHdr *pPg; pPg = sqlite3PagerLookup(pPager, iPg); if( pPg ){ if( sqlite3PcachePageRefcount(pPg)==1 ){ sqlite3PcacheDrop(pPg); }else{ | > > > > | > | 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 | ** return an SQLite error code. Otherwise, SQLITE_OK. */ static int pagerUndoCallback(void *pCtx, Pgno iPg){ int rc = SQLITE_OK; Pager *pPager = (Pager *)pCtx; PgHdr *pPg; assert( pagerUseWal(pPager) ); pPg = sqlite3PagerLookup(pPager, iPg); if( pPg ){ if( sqlite3PcachePageRefcount(pPg)==1 ){ sqlite3PcacheDrop(pPg); }else{ u32 iFrame = 0; rc = sqlite3WalFindFrame(pPager->pWal, pPg->pgno, &iFrame); if( rc==SQLITE_OK ){ rc = readDbPage(pPg, iFrame); } if( rc==SQLITE_OK ){ pPager->xReiniter(pPg); } sqlite3PagerUnref(pPg); } } |
︙ | ︙ | |||
3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 | ** the duplicate call is harmless. */ sqlite3WalEndReadTransaction(pPager->pWal); rc = sqlite3WalBeginReadTransaction(pPager->pWal, &changed); if( rc!=SQLITE_OK || changed ){ pager_reset(pPager); } return rc; } #endif /* | > | 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 | ** the duplicate call is harmless. */ sqlite3WalEndReadTransaction(pPager->pWal); rc = sqlite3WalBeginReadTransaction(pPager->pWal, &changed); if( rc!=SQLITE_OK || changed ){ pager_reset(pPager); if( USEFETCH(pPager) ) sqlite3OsUnfetch(pPager->fd, 0, 0); } return rc; } #endif /* |
︙ | ︙ | |||
3338 3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 | /* ** Change the maximum number of in-memory pages that are allowed. */ void sqlite3PagerSetCachesize(Pager *pPager, int mxPage){ sqlite3PcacheSetCachesize(pPager->pPCache, mxPage); } /* ** Free as much memory as possible from the pager. */ void sqlite3PagerShrink(Pager *pPager){ sqlite3PcacheShrink(pPager->pPCache); } | > > > > > > > > > > > > > > > > > > > > > > > | 3367 3368 3369 3370 3371 3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 3392 3393 3394 3395 3396 3397 3398 3399 3400 3401 3402 3403 | /* ** Change the maximum number of in-memory pages that are allowed. */ void sqlite3PagerSetCachesize(Pager *pPager, int mxPage){ sqlite3PcacheSetCachesize(pPager->pPCache, mxPage); } /* ** Invoke SQLITE_FCNTL_MMAP_SIZE based on the current value of szMmap. */ static void pagerFixMaplimit(Pager *pPager){ #if SQLITE_MAX_MMAP_SIZE>0 sqlite3_file *fd = pPager->fd; if( isOpen(fd) ){ sqlite3_int64 sz; pPager->bUseFetch = (fd->pMethods->iVersion>=3) && pPager->szMmap>0; sz = pPager->szMmap; sqlite3OsFileControlHint(pPager->fd, SQLITE_FCNTL_MMAP_SIZE, &sz); } #endif } /* ** Change the maximum size of any memory mapping made of the database file. */ void sqlite3PagerSetMmapLimit(Pager *pPager, sqlite3_int64 szMmap){ pPager->szMmap = szMmap; pagerFixMaplimit(pPager); } /* ** Free as much memory as possible from the pager. */ void sqlite3PagerShrink(Pager *pPager){ sqlite3PcacheShrink(pPager->pPCache); } |
︙ | ︙ | |||
3574 3575 3576 3577 3578 3579 3580 3581 3582 3583 3584 3585 3586 3587 | *pPageSize = pPager->pageSize; if( rc==SQLITE_OK ){ if( nReserve<0 ) nReserve = pPager->nReserve; assert( nReserve>=0 && nReserve<1000 ); pPager->nReserve = (i16)nReserve; pagerReportSize(pPager); } return rc; } /* ** Return a pointer to the "temporary page" buffer held internally ** by the pager. This is a buffer that is big enough to hold the | > | 3626 3627 3628 3629 3630 3631 3632 3633 3634 3635 3636 3637 3638 3639 3640 | *pPageSize = pPager->pageSize; if( rc==SQLITE_OK ){ if( nReserve<0 ) nReserve = pPager->nReserve; assert( nReserve>=0 && nReserve<1000 ); pPager->nReserve = (i16)nReserve; pagerReportSize(pPager); pagerFixMaplimit(pPager); } return rc; } /* ** Return a pointer to the "temporary page" buffer held internally ** by the pager. This is a buffer that is big enough to hold the |
︙ | ︙ | |||
3727 3728 3729 3730 3731 3732 3733 | ** be necessary to write the current content out to the sub-journal ** (as determined by function subjRequiresPage()). ** ** If the condition asserted by this function were not true, and the ** dirty page were to be discarded from the cache via the pagerStress() ** routine, pagerStress() would not write the current page content to ** the database file. If a savepoint transaction were rolled back after | | | 3780 3781 3782 3783 3784 3785 3786 3787 3788 3789 3790 3791 3792 3793 3794 | ** be necessary to write the current content out to the sub-journal ** (as determined by function subjRequiresPage()). ** ** If the condition asserted by this function were not true, and the ** dirty page were to be discarded from the cache via the pagerStress() ** routine, pagerStress() would not write the current page content to ** the database file. If a savepoint transaction were rolled back after ** this happened, the correct behavior would be to restore the current ** content of the page. However, since this content is not present in either ** the database file or the portion of the rollback journal and ** sub-journal rolled back the content could not be restored and the ** database image would become corrupt. It is therefore fortunate that ** this circumstance cannot arise. */ #if defined(SQLITE_DEBUG) |
︙ | ︙ | |||
3798 3799 3800 3801 3802 3803 3804 3805 3806 3807 3808 3809 3810 3811 | rc = sqlite3OsSync(pPager->jfd, SQLITE_SYNC_NORMAL); } if( rc==SQLITE_OK ){ rc = sqlite3OsFileSize(pPager->jfd, &pPager->journalHdr); } return rc; } /* ** Shutdown the page cache. Free all memory and close all files. ** ** If a transaction was in progress when this routine is called, that ** transaction is rolled back. All outstanding pages are invalidated ** and their memory is freed. Any attempt to use a page associated | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 3851 3852 3853 3854 3855 3856 3857 3858 3859 3860 3861 3862 3863 3864 3865 3866 3867 3868 3869 3870 3871 3872 3873 3874 3875 3876 3877 3878 3879 3880 3881 3882 3883 3884 3885 3886 3887 3888 3889 3890 3891 3892 3893 3894 3895 3896 3897 3898 3899 3900 3901 3902 3903 3904 3905 3906 3907 3908 3909 3910 3911 3912 3913 3914 3915 3916 3917 3918 3919 3920 3921 3922 3923 3924 3925 3926 3927 3928 3929 3930 3931 3932 3933 3934 3935 3936 3937 3938 3939 | rc = sqlite3OsSync(pPager->jfd, SQLITE_SYNC_NORMAL); } if( rc==SQLITE_OK ){ rc = sqlite3OsFileSize(pPager->jfd, &pPager->journalHdr); } return rc; } /* ** Obtain a reference to a memory mapped page object for page number pgno. ** The new object will use the pointer pData, obtained from xFetch(). ** If successful, set *ppPage to point to the new page reference ** and return SQLITE_OK. Otherwise, return an SQLite error code and set ** *ppPage to zero. ** ** Page references obtained by calling this function should be released ** by calling pagerReleaseMapPage(). */ static int pagerAcquireMapPage( Pager *pPager, /* Pager object */ Pgno pgno, /* Page number */ void *pData, /* xFetch()'d data for this page */ PgHdr **ppPage /* OUT: Acquired page object */ ){ PgHdr *p; /* Memory mapped page to return */ if( pPager->pMmapFreelist ){ *ppPage = p = pPager->pMmapFreelist; pPager->pMmapFreelist = p->pDirty; p->pDirty = 0; memset(p->pExtra, 0, pPager->nExtra); }else{ *ppPage = p = (PgHdr *)sqlite3MallocZero(sizeof(PgHdr) + pPager->nExtra); if( p==0 ){ sqlite3OsUnfetch(pPager->fd, (i64)(pgno-1) * pPager->pageSize, pData); return SQLITE_NOMEM; } p->pExtra = (void *)&p[1]; p->flags = PGHDR_MMAP; p->nRef = 1; p->pPager = pPager; } assert( p->pExtra==(void *)&p[1] ); assert( p->pPage==0 ); assert( p->flags==PGHDR_MMAP ); assert( p->pPager==pPager ); assert( p->nRef==1 ); p->pgno = pgno; p->pData = pData; pPager->nMmapOut++; return SQLITE_OK; } /* ** Release a reference to page pPg. pPg must have been returned by an ** earlier call to pagerAcquireMapPage(). */ static void pagerReleaseMapPage(PgHdr *pPg){ Pager *pPager = pPg->pPager; pPager->nMmapOut--; pPg->pDirty = pPager->pMmapFreelist; pPager->pMmapFreelist = pPg; assert( pPager->fd->pMethods->iVersion>=3 ); sqlite3OsUnfetch(pPager->fd, (i64)(pPg->pgno-1)*pPager->pageSize, pPg->pData); } /* ** Free all PgHdr objects stored in the Pager.pMmapFreelist list. */ static void pagerFreeMapHdrs(Pager *pPager){ PgHdr *p; PgHdr *pNext; for(p=pPager->pMmapFreelist; p; p=pNext){ pNext = p->pDirty; sqlite3_free(p); } } /* ** Shutdown the page cache. Free all memory and close all files. ** ** If a transaction was in progress when this routine is called, that ** transaction is rolled back. All outstanding pages are invalidated ** and their memory is freed. Any attempt to use a page associated |
︙ | ︙ | |||
3819 3820 3821 3822 3823 3824 3825 3826 3827 3828 3829 3830 3831 3832 | */ int sqlite3PagerClose(Pager *pPager){ u8 *pTmp = (u8 *)pPager->pTmpSpace; assert( assert_pager_state(pPager) ); disable_simulated_io_errors(); sqlite3BeginBenignMalloc(); /* pPager->errCode = 0; */ pPager->exclusiveMode = 0; #ifndef SQLITE_OMIT_WAL sqlite3WalClose(pPager->pWal, pPager->ckptSyncFlags, pPager->pageSize, pTmp); pPager->pWal = 0; #endif pager_reset(pPager); | > | 3947 3948 3949 3950 3951 3952 3953 3954 3955 3956 3957 3958 3959 3960 3961 | */ int sqlite3PagerClose(Pager *pPager){ u8 *pTmp = (u8 *)pPager->pTmpSpace; assert( assert_pager_state(pPager) ); disable_simulated_io_errors(); sqlite3BeginBenignMalloc(); pagerFreeMapHdrs(pPager); /* pPager->errCode = 0; */ pPager->exclusiveMode = 0; #ifndef SQLITE_OMIT_WAL sqlite3WalClose(pPager->pWal, pPager->ckptSyncFlags, pPager->pageSize, pTmp); pPager->pWal = 0; #endif pager_reset(pPager); |
︙ | ︙ | |||
4080 4081 4082 4083 4084 4085 4086 | rc = pagerOpentemp(pPager, pPager->fd, pPager->vfsFlags); } /* Before the first write, give the VFS a hint of what the final ** file size will be. */ assert( rc!=SQLITE_OK || isOpen(pPager->fd) ); | | > > | 4209 4210 4211 4212 4213 4214 4215 4216 4217 4218 4219 4220 4221 4222 4223 4224 4225 | rc = pagerOpentemp(pPager, pPager->fd, pPager->vfsFlags); } /* Before the first write, give the VFS a hint of what the final ** file size will be. */ assert( rc!=SQLITE_OK || isOpen(pPager->fd) ); if( rc==SQLITE_OK && (pList->pDirty ? pPager->dbSize : pList->pgno+1)>pPager->dbHintSize ){ sqlite3_int64 szFile = pPager->pageSize * (sqlite3_int64)pPager->dbSize; sqlite3OsFileControlHint(pPager->fd, SQLITE_FCNTL_SIZE_HINT, &szFile); pPager->dbHintSize = pPager->dbSize; } while( rc==SQLITE_OK && pList ){ Pgno pgno = pList->pgno; |
︙ | ︙ | |||
4634 4635 4636 4637 4638 4639 4640 4641 4642 4643 4644 4645 4646 4647 | }else if( memDb ){ pPager->journalMode = PAGER_JOURNALMODE_MEMORY; } /* pPager->xBusyHandler = 0; */ /* pPager->pBusyHandlerArg = 0; */ pPager->xReiniter = xReinit; /* memset(pPager->aHash, 0, sizeof(pPager->aHash)); */ *ppPager = pPager; return SQLITE_OK; } | > | 4765 4766 4767 4768 4769 4770 4771 4772 4773 4774 4775 4776 4777 4778 4779 | }else if( memDb ){ pPager->journalMode = PAGER_JOURNALMODE_MEMORY; } /* pPager->xBusyHandler = 0; */ /* pPager->pBusyHandlerArg = 0; */ pPager->xReiniter = xReinit; /* memset(pPager->aHash, 0, sizeof(pPager->aHash)); */ /* pPager->szMmap = SQLITE_DEFAULT_MMAP_SIZE // will be set by btree.c */ *ppPager = pPager; return SQLITE_OK; } |
︙ | ︙ | |||
4925 4926 4927 4928 4929 4930 4931 | assert( pPager->eState==PAGER_OPEN ); assert( (pPager->eLock==SHARED_LOCK) || (pPager->exclusiveMode && pPager->eLock>SHARED_LOCK) ); } | | > | > | | 5057 5058 5059 5060 5061 5062 5063 5064 5065 5066 5067 5068 5069 5070 5071 5072 5073 5074 5075 | assert( pPager->eState==PAGER_OPEN ); assert( (pPager->eLock==SHARED_LOCK) || (pPager->exclusiveMode && pPager->eLock>SHARED_LOCK) ); } if( !pPager->tempFile && ( pPager->pBackup || sqlite3PcachePagecount(pPager->pPCache)>0 || USEFETCH(pPager) )){ /* The shared-lock has just been acquired on the database file ** and there are already pages in the cache (from a previous ** read or write transaction). Check to see if the database ** has been modified. If the database has changed, flush the ** cache. ** ** Database changes is detected by looking at 15 bytes beginning |
︙ | ︙ | |||
4953 4954 4955 4956 4957 4958 4959 | rc = pagerPagecount(pPager, &nPage); if( rc ) goto failed; if( nPage>0 ){ IOTRACE(("CKVERS %p %d\n", pPager, sizeof(dbFileVers))); rc = sqlite3OsRead(pPager->fd, &dbFileVers, sizeof(dbFileVers), 24); | | > > > > > > > > > > | 5087 5088 5089 5090 5091 5092 5093 5094 5095 5096 5097 5098 5099 5100 5101 5102 5103 5104 5105 5106 5107 5108 5109 5110 5111 5112 5113 5114 5115 5116 5117 5118 5119 | rc = pagerPagecount(pPager, &nPage); if( rc ) goto failed; if( nPage>0 ){ IOTRACE(("CKVERS %p %d\n", pPager, sizeof(dbFileVers))); rc = sqlite3OsRead(pPager->fd, &dbFileVers, sizeof(dbFileVers), 24); if( rc!=SQLITE_OK && rc!=SQLITE_IOERR_SHORT_READ ){ goto failed; } }else{ memset(dbFileVers, 0, sizeof(dbFileVers)); } if( memcmp(pPager->dbFileVers, dbFileVers, sizeof(dbFileVers))!=0 ){ pager_reset(pPager); /* Unmap the database file. It is possible that external processes ** may have truncated the database file and then extended it back ** to its original size while this process was not holding a lock. ** In this case there may exist a Pager.pMap mapping that appears ** to be the right size but is not actually valid. Avoid this ** possibility by unmapping the db here. */ if( USEFETCH(pPager) ){ sqlite3OsUnfetch(pPager->fd, 0, 0); } } } /* If there is a WAL file in the file-system, open this database in WAL ** mode. Otherwise, the following function call is a no-op. */ rc = pagerOpenWalIfPresent(pPager); |
︙ | ︙ | |||
5003 5004 5005 5006 5007 5008 5009 | ** transaction and unlock the pager. ** ** Except, in locking_mode=EXCLUSIVE when there is nothing to in ** the rollback journal, the unlock is not performed and there is ** nothing to rollback, so this routine is a no-op. */ static void pagerUnlockIfUnused(Pager *pPager){ | | | 5147 5148 5149 5150 5151 5152 5153 5154 5155 5156 5157 5158 5159 5160 5161 | ** transaction and unlock the pager. ** ** Except, in locking_mode=EXCLUSIVE when there is nothing to in ** the rollback journal, the unlock is not performed and there is ** nothing to rollback, so this routine is a no-op. */ static void pagerUnlockIfUnused(Pager *pPager){ if( pPager->nMmapOut==0 && (sqlite3PcacheRefCount(pPager->pPCache)==0) ){ pagerUnlockAndRollback(pPager); } } /* ** Acquire a reference to page number pgno in pager pPager (a page ** reference has type DbPage*). If the requested reference is |
︙ | ︙ | |||
5062 5063 5064 5065 5066 5067 5068 | ** Since Lookup() never goes to disk, it never has to deal with locks ** or journal files. */ int sqlite3PagerAcquire( Pager *pPager, /* The pager open on the database file */ Pgno pgno, /* Page number to fetch */ DbPage **ppPage, /* Write a pointer to the page here */ | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 5206 5207 5208 5209 5210 5211 5212 5213 5214 5215 5216 5217 5218 5219 5220 5221 5222 5223 5224 5225 5226 5227 5228 5229 5230 5231 5232 5233 5234 5235 5236 5237 5238 5239 5240 5241 5242 5243 5244 5245 5246 5247 5248 5249 5250 5251 5252 5253 5254 5255 5256 5257 5258 5259 5260 5261 5262 5263 5264 5265 5266 5267 5268 5269 5270 5271 5272 5273 5274 5275 5276 5277 5278 5279 5280 5281 5282 5283 | ** Since Lookup() never goes to disk, it never has to deal with locks ** or journal files. */ int sqlite3PagerAcquire( Pager *pPager, /* The pager open on the database file */ Pgno pgno, /* Page number to fetch */ DbPage **ppPage, /* Write a pointer to the page here */ int flags /* PAGER_ACQUIRE_XXX flags */ ){ int rc = SQLITE_OK; PgHdr *pPg = 0; u32 iFrame = 0; /* Frame to read from WAL file */ const int noContent = (flags & PAGER_ACQUIRE_NOCONTENT); /* It is acceptable to use a read-only (mmap) page for any page except ** page 1 if there is no write-transaction open or the ACQUIRE_READONLY ** flag was specified by the caller. And so long as the db is not a ** temporary or in-memory database. */ const int bMmapOk = (pgno!=1 && USEFETCH(pPager) && (pPager->eState==PAGER_READER || (flags & PAGER_ACQUIRE_READONLY)) #ifdef SQLITE_HAS_CODEC && pPager->xCodec==0 #endif ); assert( pPager->eState>=PAGER_READER ); assert( assert_pager_state(pPager) ); assert( noContent==0 || bMmapOk==0 ); if( pgno==0 ){ return SQLITE_CORRUPT_BKPT; } /* If the pager is in the error state, return an error immediately. ** Otherwise, request the page from the PCache layer. */ if( pPager->errCode!=SQLITE_OK ){ rc = pPager->errCode; }else{ if( bMmapOk && pagerUseWal(pPager) ){ rc = sqlite3WalFindFrame(pPager->pWal, pgno, &iFrame); if( rc!=SQLITE_OK ) goto pager_acquire_err; } if( iFrame==0 && bMmapOk ){ void *pData = 0; rc = sqlite3OsFetch(pPager->fd, (i64)(pgno-1) * pPager->pageSize, pPager->pageSize, &pData ); if( rc==SQLITE_OK && pData ){ if( pPager->eState>PAGER_READER ){ (void)sqlite3PcacheFetch(pPager->pPCache, pgno, 0, &pPg); } if( pPg==0 ){ rc = pagerAcquireMapPage(pPager, pgno, pData, &pPg); }else{ sqlite3OsUnfetch(pPager->fd, (i64)(pgno-1)*pPager->pageSize, pData); } if( pPg ){ assert( rc==SQLITE_OK ); *ppPage = pPg; return SQLITE_OK; } } if( rc!=SQLITE_OK ){ goto pager_acquire_err; } } rc = sqlite3PcacheFetch(pPager->pPCache, pgno, 1, ppPage); } if( rc!=SQLITE_OK ){ /* Either the call to sqlite3PcacheFetch() returned an error or the ** pager was already in the error-state when this function was called. ** Set pPg to 0 and jump to the exception handler. */ |
︙ | ︙ | |||
5137 5138 5139 5140 5141 5142 5143 5144 5145 | TESTONLY( rc = ) addToSavepointBitvecs(pPager, pgno); testcase( rc==SQLITE_NOMEM ); sqlite3EndBenignMalloc(); } memset(pPg->pData, 0, pPager->pageSize); IOTRACE(("ZERO %p %d\n", pPager, pgno)); }else{ assert( pPg->pPager==pPager ); pPager->aStat[PAGER_STAT_MISS]++; | > > > > | | 5328 5329 5330 5331 5332 5333 5334 5335 5336 5337 5338 5339 5340 5341 5342 5343 5344 5345 5346 5347 5348 | TESTONLY( rc = ) addToSavepointBitvecs(pPager, pgno); testcase( rc==SQLITE_NOMEM ); sqlite3EndBenignMalloc(); } memset(pPg->pData, 0, pPager->pageSize); IOTRACE(("ZERO %p %d\n", pPager, pgno)); }else{ if( pagerUseWal(pPager) && bMmapOk==0 ){ rc = sqlite3WalFindFrame(pPager->pWal, pgno, &iFrame); if( rc!=SQLITE_OK ) goto pager_acquire_err; } assert( pPg->pPager==pPager ); pPager->aStat[PAGER_STAT_MISS]++; rc = readDbPage(pPg, iFrame); if( rc!=SQLITE_OK ){ goto pager_acquire_err; } } pager_set_pagehash(pPg); } |
︙ | ︙ | |||
5192 5193 5194 5195 5196 5197 5198 5199 5200 5201 5202 5203 5204 5205 5206 | ** page is added to the LRU list. When all references to all pages ** are released, a rollback occurs and the lock on the database is ** removed. */ void sqlite3PagerUnref(DbPage *pPg){ if( pPg ){ Pager *pPager = pPg->pPager; sqlite3PcacheRelease(pPg); pagerUnlockIfUnused(pPager); } } /* ** This function is called at the start of every write transaction. ** There must already be a RESERVED or EXCLUSIVE lock on the database | > > > > | 5387 5388 5389 5390 5391 5392 5393 5394 5395 5396 5397 5398 5399 5400 5401 5402 5403 5404 5405 | ** page is added to the LRU list. When all references to all pages ** are released, a rollback occurs and the lock on the database is ** removed. */ void sqlite3PagerUnref(DbPage *pPg){ if( pPg ){ Pager *pPager = pPg->pPager; if( pPg->flags & PGHDR_MMAP ){ pagerReleaseMapPage(pPg); }else{ sqlite3PcacheRelease(pPg); } pagerUnlockIfUnused(pPager); } } /* ** This function is called at the start of every write transaction. ** There must already be a RESERVED or EXCLUSIVE lock on the database |
︙ | ︙ | |||
5527 5528 5529 5530 5531 5532 5533 5534 5535 5536 5537 5538 5539 5540 | int sqlite3PagerWrite(DbPage *pDbPage){ int rc = SQLITE_OK; PgHdr *pPg = pDbPage; Pager *pPager = pPg->pPager; Pgno nPagePerSector = (pPager->sectorSize/pPager->pageSize); assert( pPager->eState>=PAGER_WRITER_LOCKED ); assert( pPager->eState!=PAGER_ERROR ); assert( assert_pager_state(pPager) ); if( nPagePerSector>1 ){ Pgno nPageCount; /* Total number of pages in database file */ Pgno pg1; /* First page of the sector pPg is located on. */ | > | 5726 5727 5728 5729 5730 5731 5732 5733 5734 5735 5736 5737 5738 5739 5740 | int sqlite3PagerWrite(DbPage *pDbPage){ int rc = SQLITE_OK; PgHdr *pPg = pDbPage; Pager *pPager = pPg->pPager; Pgno nPagePerSector = (pPager->sectorSize/pPager->pageSize); assert( (pPg->flags & PGHDR_MMAP)==0 ); assert( pPager->eState>=PAGER_WRITER_LOCKED ); assert( pPager->eState!=PAGER_ERROR ); assert( assert_pager_state(pPager) ); if( nPagePerSector>1 ){ Pgno nPageCount; /* Total number of pages in database file */ Pgno pg1; /* First page of the sector pPg is located on. */ |
︙ | ︙ | |||
5726 5727 5728 5729 5730 5731 5732 5733 5734 5735 5736 5737 5738 5739 | assert( pPager->dbFileSize>0 ); CODEC2(pPager, pPgHdr->pData, 1, 6, rc=SQLITE_NOMEM, zBuf); if( rc==SQLITE_OK ){ rc = sqlite3OsWrite(pPager->fd, zBuf, pPager->pageSize, 0); pPager->aStat[PAGER_STAT_WRITE]++; } if( rc==SQLITE_OK ){ pPager->changeCountDone = 1; } }else{ pPager->changeCountDone = 1; } } | > > > > > | 5926 5927 5928 5929 5930 5931 5932 5933 5934 5935 5936 5937 5938 5939 5940 5941 5942 5943 5944 | assert( pPager->dbFileSize>0 ); CODEC2(pPager, pPgHdr->pData, 1, 6, rc=SQLITE_NOMEM, zBuf); if( rc==SQLITE_OK ){ rc = sqlite3OsWrite(pPager->fd, zBuf, pPager->pageSize, 0); pPager->aStat[PAGER_STAT_WRITE]++; } if( rc==SQLITE_OK ){ /* Update the pager's copy of the change-counter. Otherwise, the ** next time a read transaction is opened the cache will be ** flushed (as the change-counter values will not match). */ const void *pCopy = (const void *)&((const char *)zBuf)[24]; memcpy(&pPager->dbFileVers, pCopy, sizeof(pPager->dbFileVers)); pPager->changeCountDone = 1; } }else{ pPager->changeCountDone = 1; } } |
︙ | ︙ | |||
6083 6084 6085 6086 6087 6088 6089 | return rc; } }else{ rc = pager_playback(pPager, 0); } assert( pPager->eState==PAGER_READER || rc!=SQLITE_OK ); | | | 6288 6289 6290 6291 6292 6293 6294 6295 6296 6297 6298 6299 6300 6301 6302 | return rc; } }else{ rc = pager_playback(pPager, 0); } assert( pPager->eState==PAGER_READER || rc!=SQLITE_OK ); assert( rc==SQLITE_OK || rc==SQLITE_FULL || rc==SQLITE_CORRUPT || rc==SQLITE_NOMEM || (rc&0xFF)==SQLITE_IOERR ); /* If an error occurs during a ROLLBACK, we can no longer trust the pager ** cache. So call pager_error() on the way out to make any error persistent. */ return pager_error(pPager, rc); } |
︙ | ︙ | |||
6822 6823 6824 6825 6826 6827 6828 6829 6830 6831 6832 6833 6834 6835 | */ if( rc==SQLITE_OK ){ rc = sqlite3WalOpen(pPager->pVfs, pPager->fd, pPager->zWal, pPager->exclusiveMode, pPager->journalSizeLimit, &pPager->pWal ); } return rc; } /* ** The caller must be holding a SHARED lock on the database file to call | > | 7027 7028 7029 7030 7031 7032 7033 7034 7035 7036 7037 7038 7039 7040 7041 | */ if( rc==SQLITE_OK ){ rc = sqlite3WalOpen(pPager->pVfs, pPager->fd, pPager->zWal, pPager->exclusiveMode, pPager->journalSizeLimit, &pPager->pWal ); } pagerFixMaplimit(pPager); return rc; } /* ** The caller must be holding a SHARED lock on the database file to call |
︙ | ︙ | |||
6912 6913 6914 6915 6916 6917 6918 6919 6920 6921 6922 6923 6924 6925 | */ if( rc==SQLITE_OK && pPager->pWal ){ rc = pagerExclusiveLock(pPager); if( rc==SQLITE_OK ){ rc = sqlite3WalClose(pPager->pWal, pPager->ckptSyncFlags, pPager->pageSize, (u8*)pPager->pTmpSpace); pPager->pWal = 0; } } return rc; } #endif /* !SQLITE_OMIT_WAL */ | > | 7118 7119 7120 7121 7122 7123 7124 7125 7126 7127 7128 7129 7130 7131 7132 | */ if( rc==SQLITE_OK && pPager->pWal ){ rc = pagerExclusiveLock(pPager); if( rc==SQLITE_OK ){ rc = sqlite3WalClose(pPager->pWal, pPager->ckptSyncFlags, pPager->pageSize, (u8*)pPager->pTmpSpace); pPager->pWal = 0; pagerFixMaplimit(pPager); } } return rc; } #endif /* !SQLITE_OMIT_WAL */ |
︙ | ︙ |
Changes to src/pager.h.
︙ | ︙ | |||
74 75 76 77 78 79 80 81 82 83 84 85 86 87 | #define PAGER_JOURNALMODE_DELETE 0 /* Commit by deleting journal file */ #define PAGER_JOURNALMODE_PERSIST 1 /* Commit by zeroing journal header */ #define PAGER_JOURNALMODE_OFF 2 /* Journal omitted. */ #define PAGER_JOURNALMODE_TRUNCATE 3 /* Commit by truncating journal */ #define PAGER_JOURNALMODE_MEMORY 4 /* In-memory journal file */ #define PAGER_JOURNALMODE_WAL 5 /* Use write-ahead logging */ /* ** The remainder of this file contains the declarations of the functions ** that make up the Pager sub-system API. See source code comments for ** a detailed description of each routine. */ /* Open and close a Pager connection. */ | > > > > > > | 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 | #define PAGER_JOURNALMODE_DELETE 0 /* Commit by deleting journal file */ #define PAGER_JOURNALMODE_PERSIST 1 /* Commit by zeroing journal header */ #define PAGER_JOURNALMODE_OFF 2 /* Journal omitted. */ #define PAGER_JOURNALMODE_TRUNCATE 3 /* Commit by truncating journal */ #define PAGER_JOURNALMODE_MEMORY 4 /* In-memory journal file */ #define PAGER_JOURNALMODE_WAL 5 /* Use write-ahead logging */ /* ** Flags that make up the mask passed to sqlite3PagerAcquire(). */ #define PAGER_ACQUIRE_NOCONTENT 0x01 /* Do not load data from disk */ #define PAGER_ACQUIRE_READONLY 0x02 /* Read-only page is acceptable */ /* ** The remainder of this file contains the declarations of the functions ** that make up the Pager sub-system API. See source code comments for ** a detailed description of each routine. */ /* Open and close a Pager connection. */ |
︙ | ︙ | |||
98 99 100 101 102 103 104 105 106 107 108 109 110 111 | int sqlite3PagerReadFileheader(Pager*, int, unsigned char*); /* Functions used to configure a Pager object. */ void sqlite3PagerSetBusyhandler(Pager*, int(*)(void *), void *); int sqlite3PagerSetPagesize(Pager*, u32*, int); int sqlite3PagerMaxPageCount(Pager*, int); void sqlite3PagerSetCachesize(Pager*, int); void sqlite3PagerShrink(Pager*); void sqlite3PagerSetSafetyLevel(Pager*,int,int,int); int sqlite3PagerLockingMode(Pager *, int); int sqlite3PagerSetJournalMode(Pager *, int); int sqlite3PagerGetJournalMode(Pager*); int sqlite3PagerOkToChangeJournalMode(Pager*); i64 sqlite3PagerJournalSizeLimit(Pager *, i64); | > | 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 | int sqlite3PagerReadFileheader(Pager*, int, unsigned char*); /* Functions used to configure a Pager object. */ void sqlite3PagerSetBusyhandler(Pager*, int(*)(void *), void *); int sqlite3PagerSetPagesize(Pager*, u32*, int); int sqlite3PagerMaxPageCount(Pager*, int); void sqlite3PagerSetCachesize(Pager*, int); void sqlite3PagerSetMmapLimit(Pager *, sqlite3_int64); void sqlite3PagerShrink(Pager*); void sqlite3PagerSetSafetyLevel(Pager*,int,int,int); int sqlite3PagerLockingMode(Pager *, int); int sqlite3PagerSetJournalMode(Pager *, int); int sqlite3PagerGetJournalMode(Pager*); int sqlite3PagerOkToChangeJournalMode(Pager*); i64 sqlite3PagerJournalSizeLimit(Pager *, i64); |
︙ | ︙ |
Changes to src/parse.y.
︙ | ︙ | |||
516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 | }else if( F->nSrc==1 ){ A = sqlite3SrcListAppendFromTerm(pParse,X,0,0,&Z,0,N,U); if( A ){ struct SrcList_item *pNew = &A->a[A->nSrc-1]; struct SrcList_item *pOld = F->a; pNew->zName = pOld->zName; pNew->zDatabase = pOld->zDatabase; pOld->zName = pOld->zDatabase = 0; } sqlite3SrcListDelete(pParse->db, F); }else{ Select *pSubquery; sqlite3SrcListShiftJoinType(F); pSubquery = sqlite3SelectNew(pParse,0,F,0,0,0,0,SF_NestedFrom,0,0); A = sqlite3SrcListAppendFromTerm(pParse,X,0,0,&Z,pSubquery,N,U); | > > | 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 | }else if( F->nSrc==1 ){ A = sqlite3SrcListAppendFromTerm(pParse,X,0,0,&Z,0,N,U); if( A ){ struct SrcList_item *pNew = &A->a[A->nSrc-1]; struct SrcList_item *pOld = F->a; pNew->zName = pOld->zName; pNew->zDatabase = pOld->zDatabase; pNew->pSelect = pOld->pSelect; pOld->zName = pOld->zDatabase = 0; pOld->pSelect = 0; } sqlite3SrcListDelete(pParse->db, F); }else{ Select *pSubquery; sqlite3SrcListShiftJoinType(F); pSubquery = sqlite3SelectNew(pParse,0,F,0,0,0,0,SF_NestedFrom,0,0); A = sqlite3SrcListAppendFromTerm(pParse,X,0,0,&Z,pSubquery,N,U); |
︙ | ︙ |
Changes to src/pcache.h.
︙ | ︙ | |||
48 49 50 51 52 53 54 55 56 57 58 59 60 61 | /* Bit values for PgHdr.flags */ #define PGHDR_DIRTY 0x002 /* Page has changed */ #define PGHDR_NEED_SYNC 0x004 /* Fsync the rollback journal before ** writing this page to the database */ #define PGHDR_NEED_READ 0x008 /* Content is unread */ #define PGHDR_REUSE_UNLIKELY 0x010 /* A hint that reuse is unlikely */ #define PGHDR_DONT_WRITE 0x020 /* Do not write content to disk */ /* Initialize and shutdown the page cache subsystem */ int sqlite3PcacheInitialize(void); void sqlite3PcacheShutdown(void); /* Page cache buffer management: ** These routines implement SQLITE_CONFIG_PAGECACHE. | > > | 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | /* Bit values for PgHdr.flags */ #define PGHDR_DIRTY 0x002 /* Page has changed */ #define PGHDR_NEED_SYNC 0x004 /* Fsync the rollback journal before ** writing this page to the database */ #define PGHDR_NEED_READ 0x008 /* Content is unread */ #define PGHDR_REUSE_UNLIKELY 0x010 /* A hint that reuse is unlikely */ #define PGHDR_DONT_WRITE 0x020 /* Do not write content to disk */ #define PGHDR_MMAP 0x040 /* This is an mmap page object */ /* Initialize and shutdown the page cache subsystem */ int sqlite3PcacheInitialize(void); void sqlite3PcacheShutdown(void); /* Page cache buffer management: ** These routines implement SQLITE_CONFIG_PAGECACHE. |
︙ | ︙ |
Changes to src/pragma.c.
︙ | ︙ | |||
315 316 317 318 319 320 321 | const char *zDb = 0; /* The database name */ Token *pId; /* Pointer to <id> token */ int iDb; /* Database index for <database> */ char *aFcntl[4]; /* Argument to SQLITE_FCNTL_PRAGMA */ int rc; /* return value form SQLITE_FCNTL_PRAGMA */ sqlite3 *db = pParse->db; /* The database connection */ Db *pDb; /* The specific database being pragmaed */ | | | 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 | const char *zDb = 0; /* The database name */ Token *pId; /* Pointer to <id> token */ int iDb; /* Database index for <database> */ char *aFcntl[4]; /* Argument to SQLITE_FCNTL_PRAGMA */ int rc; /* return value form SQLITE_FCNTL_PRAGMA */ sqlite3 *db = pParse->db; /* The database connection */ Db *pDb; /* The specific database being pragmaed */ Vdbe *v = sqlite3GetVdbe(pParse); /* Prepared statement */ if( v==0 ) return; sqlite3VdbeRunOnlyOnce(v); pParse->nMem = 2; /* Interpret the [database.] part of the pragma statement. iDb is the ** index of the database this pragma is being applied to in db.aDb[]. */ |
︙ | ︙ | |||
398 399 400 401 402 403 404 | ** size. But continue to take the absolute value of the default cache ** size of historical compatibility. */ if( sqlite3StrICmp(zLeft,"default_cache_size")==0 ){ static const VdbeOpList getCacheSize[] = { { OP_Transaction, 0, 0, 0}, /* 0 */ { OP_ReadCookie, 0, 1, BTREE_DEFAULT_CACHE_SIZE}, /* 1 */ | | | > | 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 | ** size. But continue to take the absolute value of the default cache ** size of historical compatibility. */ if( sqlite3StrICmp(zLeft,"default_cache_size")==0 ){ static const VdbeOpList getCacheSize[] = { { OP_Transaction, 0, 0, 0}, /* 0 */ { OP_ReadCookie, 0, 1, BTREE_DEFAULT_CACHE_SIZE}, /* 1 */ { OP_IfPos, 1, 8, 0}, { OP_Integer, 0, 2, 0}, { OP_Subtract, 1, 2, 1}, { OP_IfPos, 1, 8, 0}, { OP_Integer, 0, 1, 0}, /* 6 */ { OP_Noop, 0, 0, 0}, { OP_ResultRow, 1, 1, 0}, }; int addr; if( sqlite3ReadSchema(pParse) ) goto pragma_out; sqlite3VdbeUsesBtree(v, iDb); if( !zRight ){ sqlite3VdbeSetNumCols(v, 1); |
︙ | ︙ | |||
740 741 742 743 744 745 746 747 748 749 750 751 752 753 | }else{ int size = sqlite3Atoi(zRight); pDb->pSchema->cache_size = size; sqlite3BtreeSetCacheSize(pDb->pBt, pDb->pSchema->cache_size); } }else /* ** PRAGMA temp_store ** PRAGMA temp_store = "default"|"memory"|"file" ** ** Return or set the local value of the temp_store flag. Changing ** the local value does not make changes to the disk file and the default ** value will be restored the next time the database is opened. | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | }else{ int size = sqlite3Atoi(zRight); pDb->pSchema->cache_size = size; sqlite3BtreeSetCacheSize(pDb->pBt, pDb->pSchema->cache_size); } }else /* ** PRAGMA [database.]mmap_size(N) ** ** Used to set mapping size limit. The mapping size limit is ** used to limit the aggregate size of all memory mapped regions of the ** database file. If this parameter is set to zero, then memory mapping ** is not used at all. If N is negative, then the default memory map ** limit determined by sqlite3_config(SQLITE_CONFIG_MMAP_SIZE) is set. ** The parameter N is measured in bytes. ** ** This value is advisory. The underlying VFS is free to memory map ** as little or as much as it wants. Except, if N is set to 0 then the ** upper layers will never invoke the xFetch interfaces to the VFS. */ if( sqlite3StrICmp(zLeft,"mmap_size")==0 ){ sqlite3_int64 sz; assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); if( zRight ){ int ii; sqlite3Atoi64(zRight, &sz, 1000, SQLITE_UTF8); if( sz<0 ) sz = sqlite3GlobalConfig.szMmap; if( pId2->n==0 ) db->szMmap = sz; for(ii=db->nDb-1; ii>=0; ii--){ if( db->aDb[ii].pBt && (ii==iDb || pId2->n==0) ){ sqlite3BtreeSetMmapLimit(db->aDb[ii].pBt, sz); } } } sz = -1; if( sqlite3_file_control(db,zDb,SQLITE_FCNTL_MMAP_SIZE,&sz)==SQLITE_OK ){ #if SQLITE_MAX_MMAP_SIZE==0 sz = 0; #endif returnSingleInt(pParse, "mmap_size", sz); } }else /* ** PRAGMA temp_store ** PRAGMA temp_store = "default"|"memory"|"file" ** ** Return or set the local value of the temp_store flag. Changing ** the local value does not make changes to the disk file and the default ** value will be restored the next time the database is opened. |
︙ | ︙ | |||
1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 | #ifndef SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS /* ** PRAGMA [database.]schema_version ** PRAGMA [database.]schema_version = <integer> ** ** PRAGMA [database.]user_version ** PRAGMA [database.]user_version = <integer> ** ** The pragma's schema_version and user_version are used to set or get ** the value of the schema-version and user-version, respectively. Both ** the schema-version and the user-version are 32-bit signed integers ** stored in the database header. ** ** The schema-cookie is usually only manipulated internally by SQLite. It | > > > > > | 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 | #ifndef SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS /* ** PRAGMA [database.]schema_version ** PRAGMA [database.]schema_version = <integer> ** ** PRAGMA [database.]user_version ** PRAGMA [database.]user_version = <integer> ** ** PRAGMA [database.]freelist_count = <integer> ** ** PRAGMA [database.]application_id ** PRAGMA [database.]application_id = <integer> ** ** The pragma's schema_version and user_version are used to set or get ** the value of the schema-version and user-version, respectively. Both ** the schema-version and the user-version are 32-bit signed integers ** stored in the database header. ** ** The schema-cookie is usually only manipulated internally by SQLite. It |
︙ | ︙ | |||
1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 | ** ** The user-version is not used internally by SQLite. It may be used by ** applications for any purpose. */ if( sqlite3StrICmp(zLeft, "schema_version")==0 || sqlite3StrICmp(zLeft, "user_version")==0 || sqlite3StrICmp(zLeft, "freelist_count")==0 ){ int iCookie; /* Cookie index. 1 for schema-cookie, 6 for user-cookie. */ sqlite3VdbeUsesBtree(v, iDb); switch( zLeft[0] ){ case 'f': case 'F': iCookie = BTREE_FREE_PAGE_COUNT; break; case 's': case 'S': iCookie = BTREE_SCHEMA_VERSION; break; default: | > > > > | 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 | ** ** The user-version is not used internally by SQLite. It may be used by ** applications for any purpose. */ if( sqlite3StrICmp(zLeft, "schema_version")==0 || sqlite3StrICmp(zLeft, "user_version")==0 || sqlite3StrICmp(zLeft, "freelist_count")==0 || sqlite3StrICmp(zLeft, "application_id")==0 ){ int iCookie; /* Cookie index. 1 for schema-cookie, 6 for user-cookie. */ sqlite3VdbeUsesBtree(v, iDb); switch( zLeft[0] ){ case 'a': case 'A': iCookie = BTREE_APPLICATION_ID; break; case 'f': case 'F': iCookie = BTREE_FREE_PAGE_COUNT; break; case 's': case 'S': iCookie = BTREE_SCHEMA_VERSION; break; default: |
︙ | ︙ |
Changes to src/prepare.c.
︙ | ︙ | |||
175 176 177 178 179 180 181 | assert( iDb>=0 && iDb<db->nDb ); assert( db->aDb[iDb].pSchema ); assert( sqlite3_mutex_held(db->mutex) ); assert( iDb==1 || sqlite3BtreeHoldsMutex(db->aDb[iDb].pBt) ); /* zMasterSchema and zInitScript are set to point at the master schema ** and initialisation script appropriate for the database being | | | 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 | assert( iDb>=0 && iDb<db->nDb ); assert( db->aDb[iDb].pSchema ); assert( sqlite3_mutex_held(db->mutex) ); assert( iDb==1 || sqlite3BtreeHoldsMutex(db->aDb[iDb].pBt) ); /* zMasterSchema and zInitScript are set to point at the master schema ** and initialisation script appropriate for the database being ** initialized. zMasterName is the name of the master table. */ if( !OMIT_TEMPDB && iDb==1 ){ zMasterSchema = temp_master_schema; }else{ zMasterSchema = master_schema; } zMasterName = SCHEMA_TABLE(iDb); |
︙ | ︙ | |||
400 401 402 403 404 405 406 | if( DbHasProperty(db, i, DB_SchemaLoaded) || i==1 ) continue; rc = sqlite3InitOne(db, i, pzErrMsg); if( rc ){ sqlite3ResetOneSchema(db, i); } } | | | 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 | if( DbHasProperty(db, i, DB_SchemaLoaded) || i==1 ) continue; rc = sqlite3InitOne(db, i, pzErrMsg); if( rc ){ sqlite3ResetOneSchema(db, i); } } /* Once all the other databases have been initialized, load the schema ** for the TEMP database. This is loaded last, as the TEMP database ** schema may contain references to objects in other databases. */ #ifndef SQLITE_OMIT_TEMPDB if( rc==SQLITE_OK && ALWAYS(db->nDb>1) && !DbHasProperty(db, 1, DB_SchemaLoaded) ){ rc = sqlite3InitOne(db, 1, pzErrMsg); |
︙ | ︙ | |||
423 424 425 426 427 428 429 | sqlite3CommitInternalChanges(db); } return rc; } /* | | | 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 | sqlite3CommitInternalChanges(db); } return rc; } /* ** This routine is a no-op if the database schema is already initialized. ** Otherwise, the schema is loaded. An error code is returned. */ int sqlite3ReadSchema(Parse *pParse){ int rc = SQLITE_OK; sqlite3 *db = pParse->db; assert( sqlite3_mutex_held(db->mutex) ); if( !db->init.busy ){ |
︙ | ︙ | |||
650 651 652 653 654 655 656 | for(i=iFirst; i<mx; i++){ sqlite3VdbeSetColName(pParse->pVdbe, i-iFirst, COLNAME_NAME, azColName[i], SQLITE_STATIC); } } #endif | < | 650 651 652 653 654 655 656 657 658 659 660 661 662 663 | for(i=iFirst; i<mx; i++){ sqlite3VdbeSetColName(pParse->pVdbe, i-iFirst, COLNAME_NAME, azColName[i], SQLITE_STATIC); } } #endif if( db->init.busy==0 ){ Vdbe *pVdbe = pParse->pVdbe; sqlite3VdbeSetSql(pVdbe, zSql, (int)(pParse->zTail-zSql), saveSqlFlag); } if( pParse->pVdbe && (rc!=SQLITE_OK || db->mallocFailed) ){ sqlite3VdbeFinalize(pParse->pVdbe); assert(!(*ppStmt)); |
︙ | ︙ |
Changes to src/resolve.c.
︙ | ︙ | |||
384 385 386 387 388 389 390 | ** SELECT a+b AS x FROM table WHERE x<10; ** ** In cases like this, replace pExpr with a copy of the expression that ** forms the result set entry ("a+b" in the example) and return immediately. ** Note that the expression in the result set should have already been ** resolved by the time the WHERE clause is resolved. */ | | > > > | 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 | ** SELECT a+b AS x FROM table WHERE x<10; ** ** In cases like this, replace pExpr with a copy of the expression that ** forms the result set entry ("a+b" in the example) and return immediately. ** Note that the expression in the result set should have already been ** resolved by the time the WHERE clause is resolved. */ if( (pEList = pNC->pEList)!=0 && zTab==0 && ((pNC->ncFlags & NC_AsMaybe)==0 || cnt==0) ){ for(j=0; j<pEList->nExpr; j++){ char *zAs = pEList->a[j].zName; if( zAs!=0 && sqlite3StrICmp(zAs, zCol)==0 ){ Expr *pOrig; assert( pExpr->pLeft==0 && pExpr->pRight==0 ); assert( pExpr->x.pList==0 ); assert( pExpr->x.pSelect==0 ); |
︙ | ︙ | |||
475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 | pExpr->pLeft = 0; sqlite3ExprDelete(db, pExpr->pRight); pExpr->pRight = 0; pExpr->op = (isTrigger ? TK_TRIGGER : TK_COLUMN); lookupname_end: if( cnt==1 ){ assert( pNC!=0 ); sqlite3AuthRead(pParse, pExpr, pSchema, pNC->pSrcList); /* Increment the nRef value on all name contexts from TopNC up to ** the point where the name matched. */ for(;;){ assert( pTopNC!=0 ); pTopNC->nRef++; if( pTopNC==pNC ) break; pTopNC = pTopNC->pNext; | > > | 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 | pExpr->pLeft = 0; sqlite3ExprDelete(db, pExpr->pRight); pExpr->pRight = 0; pExpr->op = (isTrigger ? TK_TRIGGER : TK_COLUMN); lookupname_end: if( cnt==1 ){ assert( pNC!=0 ); if( pExpr->op!=TK_AS ){ sqlite3AuthRead(pParse, pExpr, pSchema, pNC->pSrcList); } /* Increment the nRef value on all name contexts from TopNC up to ** the point where the name matched. */ for(;;){ assert( pTopNC!=0 ); pTopNC->nRef++; if( pTopNC==pNC ) break; pTopNC = pTopNC->pNext; |
︙ | ︙ | |||
1150 1151 1152 1153 1154 1155 1156 | ** expressions in the WHERE clause (etc.) can refer to expressions by ** aliases in the result set. ** ** Minor point: If this is the case, then the expression will be ** re-evaluated for each reference to it. */ sNC.pEList = p->pEList; | | > | < | < | 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 | ** expressions in the WHERE clause (etc.) can refer to expressions by ** aliases in the result set. ** ** Minor point: If this is the case, then the expression will be ** re-evaluated for each reference to it. */ sNC.pEList = p->pEList; if( sqlite3ResolveExprNames(&sNC, p->pHaving) ) return WRC_Abort; sNC.ncFlags |= NC_AsMaybe; if( sqlite3ResolveExprNames(&sNC, p->pWhere) ) return WRC_Abort; sNC.ncFlags &= ~NC_AsMaybe; /* The ORDER BY and GROUP BY clauses may not refer to terms in ** outer queries */ sNC.pNext = 0; sNC.ncFlags |= NC_AllowAgg; |
︙ | ︙ | |||
1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 | return 1; } pParse->nHeight += pExpr->nHeight; } #endif savedHasAgg = pNC->ncFlags & NC_HasAgg; pNC->ncFlags &= ~NC_HasAgg; w.xExprCallback = resolveExprStep; w.xSelectCallback = resolveSelectStep; w.pParse = pNC->pParse; w.u.pNC = pNC; sqlite3WalkExpr(&w, pExpr); #if SQLITE_MAX_EXPR_DEPTH>0 pNC->pParse->nHeight -= pExpr->nHeight; | > | 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 | return 1; } pParse->nHeight += pExpr->nHeight; } #endif savedHasAgg = pNC->ncFlags & NC_HasAgg; pNC->ncFlags &= ~NC_HasAgg; memset(&w, 0, sizeof(w)); w.xExprCallback = resolveExprStep; w.xSelectCallback = resolveSelectStep; w.pParse = pNC->pParse; w.u.pNC = pNC; sqlite3WalkExpr(&w, pExpr); #if SQLITE_MAX_EXPR_DEPTH>0 pNC->pParse->nHeight -= pExpr->nHeight; |
︙ | ︙ | |||
1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 | Parse *pParse, /* The parser context */ Select *p, /* The SELECT statement being coded. */ NameContext *pOuterNC /* Name context for parent SELECT statement */ ){ Walker w; assert( p!=0 ); w.xExprCallback = resolveExprStep; w.xSelectCallback = resolveSelectStep; w.pParse = pParse; w.u.pNC = pOuterNC; sqlite3WalkSelect(&w, p); } | > | 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 | Parse *pParse, /* The parser context */ Select *p, /* The SELECT statement being coded. */ NameContext *pOuterNC /* Name context for parent SELECT statement */ ){ Walker w; assert( p!=0 ); memset(&w, 0, sizeof(w)); w.xExprCallback = resolveExprStep; w.xSelectCallback = resolveSelectStep; w.pParse = pParse; w.u.pNC = pOuterNC; sqlite3WalkSelect(&w, p); } |
Changes to src/select.c.
︙ | ︙ | |||
3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 | pParse->checkSchema = 1; return SQLITE_ERROR; } pFrom->pIndex = pIdx; } return SQLITE_OK; } /* ** This routine is a Walker callback for "expanding" a SELECT statement. ** "Expanding" means to do the following: ** ** (1) Make sure VDBE cursor numbers have been assigned to every ** element of the FROM clause. | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 | pParse->checkSchema = 1; return SQLITE_ERROR; } pFrom->pIndex = pIdx; } return SQLITE_OK; } /* ** Detect compound SELECT statements that use an ORDER BY clause with ** an alternative collating sequence. ** ** SELECT ... FROM t1 EXCEPT SELECT ... FROM t2 ORDER BY .. COLLATE ... ** ** These are rewritten as a subquery: ** ** SELECT * FROM (SELECT ... FROM t1 EXCEPT SELECT ... FROM t2) ** ORDER BY ... COLLATE ... ** ** This transformation is necessary because the multiSelectOrderBy() routine ** above that generates the code for a compound SELECT with an ORDER BY clause ** uses a merge algorithm that requires the same collating sequence on the ** result columns as on the ORDER BY clause. See ticket ** http://www.sqlite.org/src/info/6709574d2a ** ** This transformation is only needed for EXCEPT, INTERSECT, and UNION. ** The UNION ALL operator works fine with multiSelectOrderBy() even when ** there are COLLATE terms in the ORDER BY. */ static int convertCompoundSelectToSubquery(Walker *pWalker, Select *p){ int i; Select *pNew; Select *pX; sqlite3 *db; struct ExprList_item *a; SrcList *pNewSrc; Parse *pParse; Token dummy; if( p->pPrior==0 ) return WRC_Continue; if( p->pOrderBy==0 ) return WRC_Continue; for(pX=p; pX && (pX->op==TK_ALL || pX->op==TK_SELECT); pX=pX->pPrior){} if( pX==0 ) return WRC_Continue; a = p->pOrderBy->a; for(i=p->pOrderBy->nExpr-1; i>=0; i--){ if( a[i].pExpr->flags & EP_Collate ) break; } if( i<0 ) return WRC_Continue; /* If we reach this point, that means the transformation is required. */ pParse = pWalker->pParse; db = pParse->db; pNew = sqlite3DbMallocZero(db, sizeof(*pNew) ); if( pNew==0 ) return WRC_Abort; memset(&dummy, 0, sizeof(dummy)); pNewSrc = sqlite3SrcListAppendFromTerm(pParse,0,0,0,&dummy,pNew,0,0); if( pNewSrc==0 ) return WRC_Abort; *pNew = *p; p->pSrc = pNewSrc; p->pEList = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(db, TK_ALL, 0)); p->op = TK_SELECT; p->pWhere = 0; pNew->pGroupBy = 0; pNew->pHaving = 0; pNew->pOrderBy = 0; p->pPrior = 0; pNew->pLimit = 0; pNew->pOffset = 0; return WRC_Continue; } /* ** This routine is a Walker callback for "expanding" a SELECT statement. ** "Expanding" means to do the following: ** ** (1) Make sure VDBE cursor numbers have been assigned to every ** element of the FROM clause. |
︙ | ︙ | |||
3572 3573 3574 3575 3576 3577 3578 | ** ** If anything goes wrong, an error message is written into pParse. ** The calling function can detect the problem by looking at pParse->nErr ** and/or pParse->db->mallocFailed. */ static void sqlite3SelectExpand(Parse *pParse, Select *pSelect){ Walker w; | > | > > | 3635 3636 3637 3638 3639 3640 3641 3642 3643 3644 3645 3646 3647 3648 3649 3650 3651 3652 3653 3654 | ** ** If anything goes wrong, an error message is written into pParse. ** The calling function can detect the problem by looking at pParse->nErr ** and/or pParse->db->mallocFailed. */ static void sqlite3SelectExpand(Parse *pParse, Select *pSelect){ Walker w; memset(&w, 0, sizeof(w)); w.xSelectCallback = convertCompoundSelectToSubquery; w.xExprCallback = exprWalkNoop; w.pParse = pParse; sqlite3WalkSelect(&w, pSelect); w.xSelectCallback = selectExpander; sqlite3WalkSelect(&w, pSelect); } #ifndef SQLITE_OMIT_SUBQUERY /* ** This is a Walker.xSelectCallback callback for the sqlite3SelectTypeInfo() |
︙ | ︙ | |||
3630 3631 3632 3633 3634 3635 3636 3637 3638 3639 3640 3641 3642 3643 3644 3645 3646 | ** SELECT statement. ** ** Use this routine after name resolution. */ static void sqlite3SelectAddTypeInfo(Parse *pParse, Select *pSelect){ #ifndef SQLITE_OMIT_SUBQUERY Walker w; w.xSelectCallback = selectAddSubqueryTypeInfo; w.xExprCallback = exprWalkNoop; w.pParse = pParse; sqlite3WalkSelect(&w, pSelect); #endif } /* ** This routine sets up a SELECT statement for processing. The | > > | 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 | ** SELECT statement. ** ** Use this routine after name resolution. */ static void sqlite3SelectAddTypeInfo(Parse *pParse, Select *pSelect){ #ifndef SQLITE_OMIT_SUBQUERY Walker w; memset(&w, 0, sizeof(w)); w.xSelectCallback = selectAddSubqueryTypeInfo; w.xExprCallback = exprWalkNoop; w.pParse = pParse; w.bSelectDepthFirst = 1; sqlite3WalkSelect(&w, pSelect); #endif } /* ** This routine sets up a SELECT statement for processing. The |
︙ | ︙ | |||
4043 4044 4045 4046 4047 4048 4049 | int retAddr; assert( pItem->addrFillSub==0 ); pItem->regReturn = ++pParse->nMem; topAddr = sqlite3VdbeAddOp2(v, OP_Integer, 0, pItem->regReturn); pItem->addrFillSub = topAddr+1; VdbeNoopComment((v, "materialize %s", pItem->pTab->zName)); if( pItem->isCorrelated==0 ){ | | | 4111 4112 4113 4114 4115 4116 4117 4118 4119 4120 4121 4122 4123 4124 4125 | int retAddr; assert( pItem->addrFillSub==0 ); pItem->regReturn = ++pParse->nMem; topAddr = sqlite3VdbeAddOp2(v, OP_Integer, 0, pItem->regReturn); pItem->addrFillSub = topAddr+1; VdbeNoopComment((v, "materialize %s", pItem->pTab->zName)); if( pItem->isCorrelated==0 ){ /* If the subquery is not correlated and if we are not inside of ** a trigger, then we only need to compute the value of the subquery ** once. */ onceAddr = sqlite3CodeOnce(pParse); } sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor); explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId); sqlite3Select(pParse, pSub, &dest); |
︙ | ︙ | |||
4566 4567 4568 4569 4570 4571 4572 | ** If where.c is able to produce results sorted in this order, then ** add vdbe code to break out of the processing loop after the ** first iteration (since the first iteration of the loop is ** guaranteed to operate on the row with the minimum or maximum ** value of x, the only row required). ** ** A special flag must be passed to sqlite3WhereBegin() to slightly | | | 4634 4635 4636 4637 4638 4639 4640 4641 4642 4643 4644 4645 4646 4647 4648 | ** If where.c is able to produce results sorted in this order, then ** add vdbe code to break out of the processing loop after the ** first iteration (since the first iteration of the loop is ** guaranteed to operate on the row with the minimum or maximum ** value of x, the only row required). ** ** A special flag must be passed to sqlite3WhereBegin() to slightly ** modify behavior as follows: ** ** + If the query is a "SELECT min(x)", then the loop coded by ** where.c should not iterate over any values with a NULL value ** for x. ** ** + The optimizer code in where.c (the thing that decides which ** index or indices to use) should place a different priority on |
︙ | ︙ |
Changes to src/shell.c.
︙ | ︙ | |||
1476 1477 1478 1479 1480 1481 1482 | if( db==0 || SQLITE_OK!=sqlite3_errcode(db) ){ fprintf(stderr,"Error: unable to open database \"%s\": %s\n", p->zDbFilename, sqlite3_errmsg(db)); exit(1); } #ifndef SQLITE_OMIT_LOAD_EXTENSION sqlite3_enable_load_extension(p->db, 1); | < < < < < < < < < < < < | 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 | if( db==0 || SQLITE_OK!=sqlite3_errcode(db) ){ fprintf(stderr,"Error: unable to open database \"%s\": %s\n", p->zDbFilename, sqlite3_errmsg(db)); exit(1); } #ifndef SQLITE_OMIT_LOAD_EXTENSION sqlite3_enable_load_extension(p->db, 1); #endif } } /* ** Do C-language style dequoting. ** |
︙ | ︙ | |||
1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 | if( sqlite3_stricmp(zArg, "off")==0 || sqlite3_stricmp(zArg,"no")==0 ){ return 0; } fprintf(stderr, "ERROR: Not a boolean value: \"%s\". Assuming \"no\".\n", zArg); return 0; } /* ** Close an output file, assuming it is not stderr or stdout */ static void output_file_close(FILE *f){ if( f && f!=stdout && f!=stderr ) fclose(f); } | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 | if( sqlite3_stricmp(zArg, "off")==0 || sqlite3_stricmp(zArg,"no")==0 ){ return 0; } fprintf(stderr, "ERROR: Not a boolean value: \"%s\". Assuming \"no\".\n", zArg); return 0; } /* ** Interpret zArg as an integer value, possibly with suffixes. */ static sqlite3_int64 integerValue(const char *zArg){ sqlite3_int64 v = 0; static const struct { char *zSuffix; int iMult; } aMult[] = { { "KiB", 1024 }, { "MiB", 1024*1024 }, { "GiB", 1024*1024*1024 }, { "KB", 1000 }, { "MB", 1000000 }, { "GB", 1000000000 }, { "K", 1000 }, { "M", 1000000 }, { "G", 1000000000 }, }; int i; int isNeg = 0; if( zArg[0]=='-' ){ isNeg = 1; zArg++; }else if( zArg[0]=='+' ){ zArg++; } while( isdigit(zArg[0]) ){ v = v*10 + zArg[0] - '0'; zArg++; } for(i=0; i<sizeof(aMult)/sizeof(aMult[0]); i++){ if( sqlite3_stricmp(aMult[i].zSuffix, zArg)==0 ){ v *= aMult[i].iMult; break; } } return isNeg? -v : v; } /* ** Close an output file, assuming it is not stderr or stdout */ static void output_file_close(FILE *f){ if( f && f!=stdout && f!=stderr ) fclose(f); } |
︙ | ︙ | |||
2249 2250 2251 2252 2253 2254 2255 | rc = sqlite3_exec(p->db, "SELECT sql FROM " " (SELECT sql sql, type type, tbl_name tbl_name, name name, rowid x" " FROM sqlite_master UNION ALL" " SELECT sql, type, tbl_name, name, rowid FROM sqlite_temp_master) " "WHERE lower(tbl_name) LIKE shellstatic()" " AND type!='meta' AND sql NOTNULL " | | < | < | 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 | rc = sqlite3_exec(p->db, "SELECT sql FROM " " (SELECT sql sql, type type, tbl_name tbl_name, name name, rowid x" " FROM sqlite_master UNION ALL" " SELECT sql, type, tbl_name, name, rowid FROM sqlite_temp_master) " "WHERE lower(tbl_name) LIKE shellstatic()" " AND type!='meta' AND sql NOTNULL " "ORDER BY rowid", callback, &data, &zErrMsg); zShellStatic = 0; } }else{ rc = sqlite3_exec(p->db, "SELECT sql FROM " " (SELECT sql sql, type type, tbl_name tbl_name, name name, rowid x" " FROM sqlite_master UNION ALL" " SELECT sql, type, tbl_name, name, rowid FROM sqlite_temp_master) " "WHERE type!='meta' AND sql NOTNULL AND name NOT LIKE 'sqlite_%'" "ORDER BY rowid", callback, &data, &zErrMsg ); } if( zErrMsg ){ fprintf(stderr,"Error: %s\n", zErrMsg); sqlite3_free(zErrMsg); rc = 1; |
︙ | ︙ | |||
2384 2385 2386 2387 2388 2389 2390 | } 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 ? "" : " "; | | | | 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 | } 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 ){ |
︙ | ︙ | |||
2443 2444 2445 2446 2447 2448 2449 | /* sqlite3_test_control(int, db, int) */ case SQLITE_TESTCTRL_OPTIMIZATIONS: case SQLITE_TESTCTRL_RESERVE: if( nArg==3 ){ int opt = (int)strtol(azArg[2], 0, 0); rc = sqlite3_test_control(testctrl, p->db, opt); | | | | | | | | 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 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 | /* sqlite3_test_control(int, db, int) */ case SQLITE_TESTCTRL_OPTIMIZATIONS: case SQLITE_TESTCTRL_RESERVE: if( nArg==3 ){ int opt = (int)strtol(azArg[2], 0, 0); rc = sqlite3_test_control(testctrl, p->db, opt); fprintf(p->out, "%d (0x%08x)\n", rc, rc); } else { fprintf(stderr,"Error: testctrl %s takes a single int option\n", azArg[1]); } break; /* sqlite3_test_control(int) */ case SQLITE_TESTCTRL_PRNG_SAVE: case SQLITE_TESTCTRL_PRNG_RESTORE: case SQLITE_TESTCTRL_PRNG_RESET: if( nArg==2 ){ rc = sqlite3_test_control(testctrl); fprintf(p->out, "%d (0x%08x)\n", rc, rc); } else { fprintf(stderr,"Error: testctrl %s takes no options\n", azArg[1]); } break; /* sqlite3_test_control(int, uint) */ case SQLITE_TESTCTRL_PENDING_BYTE: if( nArg==3 ){ unsigned int opt = (unsigned int)integerValue(azArg[2]); rc = sqlite3_test_control(testctrl, opt); fprintf(p->out, "%d (0x%08x)\n", rc, rc); } else { fprintf(stderr,"Error: testctrl %s takes a single unsigned" " int option\n", azArg[1]); } break; /* sqlite3_test_control(int, int) */ case SQLITE_TESTCTRL_ASSERT: case SQLITE_TESTCTRL_ALWAYS: if( nArg==3 ){ int opt = atoi(azArg[2]); rc = sqlite3_test_control(testctrl, opt); fprintf(p->out, "%d (0x%08x)\n", rc, rc); } else { fprintf(stderr,"Error: testctrl %s takes a single int option\n", azArg[1]); } break; /* sqlite3_test_control(int, char *) */ #ifdef SQLITE_N_KEYWORD case SQLITE_TESTCTRL_ISKEYWORD: if( nArg==3 ){ const char *opt = azArg[2]; rc = sqlite3_test_control(testctrl, opt); fprintf(p->out, "%d (0x%08x)\n", rc, rc); } else { fprintf(stderr,"Error: testctrl %s takes a single char * option\n", azArg[1]); } break; #endif |
︙ | ︙ | |||
2538 2539 2540 2541 2542 2543 2544 | }else{ sqlite3_trace(p->db, sql_trace_callback, p->traceOut); } #endif }else if( c=='v' && strncmp(azArg[0], "version", n)==0 ){ | | | | | 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 | }else{ sqlite3_trace(p->db, sql_trace_callback, p->traceOut); } #endif }else if( c=='v' && strncmp(azArg[0], "version", n)==0 ){ fprintf(p->out, "SQLite %s %s\n" /*extra-version-info*/, sqlite3_libversion(), sqlite3_sourceid()); }else if( c=='v' && strncmp(azArg[0], "vfsname", n)==0 ){ const char *zDbName = nArg==2 ? azArg[1] : "main"; char *zVfsName = 0; if( p->db ){ sqlite3_file_control(p->db, zDbName, SQLITE_FCNTL_VFSNAME, &zVfsName); if( zVfsName ){ fprintf(p->out, "%s\n", zVfsName); sqlite3_free(zVfsName); } } }else #if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_WHERETRACE) if( c=='w' && strncmp(azArg[0], "wheretrace", n)==0 ){ extern int sqlite3WhereTrace; sqlite3WhereTrace = booleanValue(azArg[1]); }else #endif if( c=='w' && strncmp(azArg[0], "width", n)==0 && nArg>1 ){ int j; assert( nArg<=ArraySize(azArg) ); for(j=1; j<nArg && j<ArraySize(p->colWidth); j++){ |
︙ | ︙ | |||
2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 | fprintf(stderr, "%s %s\n", zPrefix, sqlite3_errmsg(p->db)); } errCnt++; } free(zSql); zSql = 0; nSql = 0; } } if( zSql ){ if( !_all_whitespace(zSql) ){ fprintf(stderr, "Error: incomplete SQL: %s\n", zSql); } free(zSql); | > > > > | 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 | fprintf(stderr, "%s %s\n", zPrefix, sqlite3_errmsg(p->db)); } errCnt++; } free(zSql); zSql = 0; nSql = 0; }else if( zSql && _all_whitespace(zSql) ){ free(zSql); zSql = 0; nSql = 0; } } if( zSql ){ if( !_all_whitespace(zSql) ){ fprintf(stderr, "Error: incomplete SQL: %s\n", zSql); } free(zSql); |
︙ | ︙ | |||
2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 | " -heap SIZE Size of heap for memsys3 or memsys5\n" #endif " -help show this message\n" " -html set output mode to HTML\n" " -interactive force interactive I/O\n" " -line set output mode to 'line'\n" " -list set output mode to 'list'\n" #ifdef SQLITE_ENABLE_MULTIPLEX " -multiplex enable the multiplexor VFS\n" #endif " -nullvalue TEXT set text string for NULL values. Default ''\n" " -separator SEP set output field separator. Default: '|'\n" " -stats print memory stats before each finalize\n" " -version show SQLite version\n" | > | 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 | " -heap SIZE Size of heap for memsys3 or memsys5\n" #endif " -help show this message\n" " -html set output mode to HTML\n" " -interactive force interactive I/O\n" " -line set output mode to 'line'\n" " -list set output mode to 'list'\n" " -mmap N default mmap size set to N\n" #ifdef SQLITE_ENABLE_MULTIPLEX " -multiplex enable the multiplexor VFS\n" #endif " -nullvalue TEXT set text string for NULL values. Default ''\n" " -separator SEP set output field separator. Default: '|'\n" " -stats print memory stats before each finalize\n" " -version show SQLite version\n" |
︙ | ︙ | |||
2997 2998 2999 3000 3001 3002 3003 | }else if( strcmp(z,"-heap")==0 ){ #if defined(SQLITE_ENABLE_MEMSYS3) || defined(SQLITE_ENABLE_MEMSYS5) int j, c; const char *zSize; sqlite3_int64 szHeap; zSize = cmdline_option_value(argc, argv, ++i); | | < < < < < > > > | 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 | }else if( strcmp(z,"-heap")==0 ){ #if defined(SQLITE_ENABLE_MEMSYS3) || defined(SQLITE_ENABLE_MEMSYS5) int j, c; const char *zSize; sqlite3_int64 szHeap; zSize = cmdline_option_value(argc, argv, ++i); szHeap = integerValue(zSize); if( szHeap>0x7fff0000 ) szHeap = 0x7fff0000; sqlite3_config(SQLITE_CONFIG_HEAP, malloc((int)szHeap), (int)szHeap, 64); #endif #ifdef SQLITE_ENABLE_VFSTRACE }else if( strcmp(z,"-vfstrace")==0 ){ extern int vfstrace_register( const char *zTraceName, const char *zOldVfsName, int (*xOut)(const char*,void*), void *pOutArg, int makeDefault ); vfstrace_register("trace",0,(int(*)(const char*,void*))fputs,stderr,1); #endif #ifdef SQLITE_ENABLE_MULTIPLEX }else if( strcmp(z,"-multiplex")==0 ){ extern int sqlite3_multiple_initialize(const char*,int); sqlite3_multiplex_initialize(0, 1); #endif }else if( strcmp(z,"-mmap")==0 ){ sqlite3_int64 sz = integerValue(cmdline_option_value(argc,argv,++i)); sqlite3_config(SQLITE_CONFIG_MMAP_SIZE, sz, sz); }else if( strcmp(z,"-vfs")==0 ){ sqlite3_vfs *pVfs = sqlite3_vfs_find(cmdline_option_value(argc,argv,++i)); if( pVfs ){ sqlite3_vfs_register(pVfs, 1); }else{ fprintf(stderr, "no such VFS: \"%s\"\n", argv[i]); exit(1); |
︙ | ︙ | |||
3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130 | return 0; }else if( strcmp(z,"-interactive")==0 ){ stdin_is_interactive = 1; }else if( strcmp(z,"-batch")==0 ){ stdin_is_interactive = 0; }else if( strcmp(z,"-heap")==0 ){ i++; }else if( strcmp(z,"-vfs")==0 ){ i++; #ifdef SQLITE_ENABLE_VFSTRACE }else if( strcmp(z,"-vfstrace")==0 ){ i++; #endif #ifdef SQLITE_ENABLE_MULTIPLEX }else if( strcmp(z,"-multiplex")==0 ){ i++; #endif }else if( strcmp(z,"-help")==0 ){ usage(1); }else if( strcmp(z,"-cmd")==0 ){ if( i==argc-1 ) break; z = cmdline_option_value(argc,argv,++i); if( z[0]=='.' ){ rc = do_meta_command(z, &data); | > > | | 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 | return 0; }else if( strcmp(z,"-interactive")==0 ){ stdin_is_interactive = 1; }else if( strcmp(z,"-batch")==0 ){ stdin_is_interactive = 0; }else if( strcmp(z,"-heap")==0 ){ i++; }else if( strcmp(z,"-mmap")==0 ){ i++; }else if( strcmp(z,"-vfs")==0 ){ i++; #ifdef SQLITE_ENABLE_VFSTRACE }else if( strcmp(z,"-vfstrace")==0 ){ i++; #endif #ifdef SQLITE_ENABLE_MULTIPLEX }else if( strcmp(z,"-multiplex")==0 ){ i++; #endif }else if( strcmp(z,"-help")==0 ){ usage(1); }else if( strcmp(z,"-cmd")==0 ){ if( i==argc-1 ) break; z = cmdline_option_value(argc,argv,++i); if( z[0]=='.' ){ rc = do_meta_command(z, &data); if( rc && bail_on_error ) return rc==2 ? 0 : rc; }else{ open_db(&data); rc = shell_exec(data.db, z, shell_callback, &data, &zErrMsg); if( zErrMsg!=0 ){ fprintf(stderr,"Error: %s\n", zErrMsg); if( bail_on_error ) return rc!=0 ? rc : 1; }else if( rc!=0 ){ |
︙ | ︙ | |||
3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 | } if( zFirstCmd ){ /* Run just the command that follows the database name */ if( zFirstCmd[0]=='.' ){ rc = do_meta_command(zFirstCmd, &data); }else{ open_db(&data); rc = shell_exec(data.db, zFirstCmd, shell_callback, &data, &zErrMsg); if( zErrMsg!=0 ){ fprintf(stderr,"Error: %s\n", zErrMsg); return rc!=0 ? rc : 1; }else if( rc!=0 ){ | > | 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 | } if( zFirstCmd ){ /* Run just the command that follows the database name */ if( zFirstCmd[0]=='.' ){ rc = do_meta_command(zFirstCmd, &data); if( rc==2 ) rc = 0; }else{ open_db(&data); rc = shell_exec(data.db, zFirstCmd, shell_callback, &data, &zErrMsg); if( zErrMsg!=0 ){ fprintf(stderr,"Error: %s\n", zErrMsg); return rc!=0 ? rc : 1; }else if( rc!=0 ){ |
︙ | ︙ |
Changes to src/sqlite.h.in.
︙ | ︙ | |||
416 417 418 419 420 421 422 423 424 425 426 427 428 429 | #define SQLITE_MISMATCH 20 /* Data type mismatch */ #define SQLITE_MISUSE 21 /* Library used incorrectly */ #define SQLITE_NOLFS 22 /* Uses OS features not supported on host */ #define SQLITE_AUTH 23 /* Authorization denied */ #define SQLITE_FORMAT 24 /* Auxiliary database format error */ #define SQLITE_RANGE 25 /* 2nd parameter to sqlite3_bind out of range */ #define SQLITE_NOTADB 26 /* File opened that is not a database file */ #define SQLITE_ROW 100 /* sqlite3_step() has another row ready */ #define SQLITE_DONE 101 /* sqlite3_step() has finished executing */ /* end-of-error-codes */ /* ** CAPI3REF: Extended Result Codes ** KEYWORDS: {extended error code} {extended error codes} | > > | 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 | #define SQLITE_MISMATCH 20 /* Data type mismatch */ #define SQLITE_MISUSE 21 /* Library used incorrectly */ #define SQLITE_NOLFS 22 /* Uses OS features not supported on host */ #define SQLITE_AUTH 23 /* Authorization denied */ #define SQLITE_FORMAT 24 /* Auxiliary database format error */ #define SQLITE_RANGE 25 /* 2nd parameter to sqlite3_bind out of range */ #define SQLITE_NOTADB 26 /* File opened that is not a database file */ #define SQLITE_NOTICE 27 /* Notifications from sqlite3_log() */ #define SQLITE_WARNING 28 /* Warnings from sqlite3_log() */ #define SQLITE_ROW 100 /* sqlite3_step() has another row ready */ #define SQLITE_DONE 101 /* sqlite3_step() has finished executing */ /* end-of-error-codes */ /* ** CAPI3REF: Extended Result Codes ** KEYWORDS: {extended error code} {extended error codes} |
︙ | ︙ | |||
466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 | #define SQLITE_IOERR_DIR_CLOSE (SQLITE_IOERR | (17<<8)) #define SQLITE_IOERR_SHMOPEN (SQLITE_IOERR | (18<<8)) #define SQLITE_IOERR_SHMSIZE (SQLITE_IOERR | (19<<8)) #define SQLITE_IOERR_SHMLOCK (SQLITE_IOERR | (20<<8)) #define SQLITE_IOERR_SHMMAP (SQLITE_IOERR | (21<<8)) #define SQLITE_IOERR_SEEK (SQLITE_IOERR | (22<<8)) #define SQLITE_IOERR_DELETE_NOENT (SQLITE_IOERR | (23<<8)) #define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8)) #define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8)) #define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1<<8)) #define SQLITE_CANTOPEN_ISDIR (SQLITE_CANTOPEN | (2<<8)) #define SQLITE_CANTOPEN_FULLPATH (SQLITE_CANTOPEN | (3<<8)) #define SQLITE_CORRUPT_VTAB (SQLITE_CORRUPT | (1<<8)) #define SQLITE_READONLY_RECOVERY (SQLITE_READONLY | (1<<8)) #define SQLITE_READONLY_CANTLOCK (SQLITE_READONLY | (2<<8)) #define SQLITE_READONLY_ROLLBACK (SQLITE_READONLY | (3<<8)) #define SQLITE_ABORT_ROLLBACK (SQLITE_ABORT | (2<<8)) #define SQLITE_CONSTRAINT_CHECK (SQLITE_CONSTRAINT | (1<<8)) #define SQLITE_CONSTRAINT_COMMITHOOK (SQLITE_CONSTRAINT | (2<<8)) #define SQLITE_CONSTRAINT_FOREIGNKEY (SQLITE_CONSTRAINT | (3<<8)) #define SQLITE_CONSTRAINT_FUNCTION (SQLITE_CONSTRAINT | (4<<8)) #define SQLITE_CONSTRAINT_NOTNULL (SQLITE_CONSTRAINT | (5<<8)) #define SQLITE_CONSTRAINT_PRIMARYKEY (SQLITE_CONSTRAINT | (6<<8)) #define SQLITE_CONSTRAINT_TRIGGER (SQLITE_CONSTRAINT | (7<<8)) #define SQLITE_CONSTRAINT_UNIQUE (SQLITE_CONSTRAINT | (8<<8)) #define SQLITE_CONSTRAINT_VTAB (SQLITE_CONSTRAINT | (9<<8)) /* ** CAPI3REF: Flags For File Open Operations ** ** These bit values are intended for use in the ** 3rd parameter to the [sqlite3_open_v2()] interface and ** in the 4th parameter to the [sqlite3_vfs.xOpen] method. | > > > | 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 | #define SQLITE_IOERR_DIR_CLOSE (SQLITE_IOERR | (17<<8)) #define SQLITE_IOERR_SHMOPEN (SQLITE_IOERR | (18<<8)) #define SQLITE_IOERR_SHMSIZE (SQLITE_IOERR | (19<<8)) #define SQLITE_IOERR_SHMLOCK (SQLITE_IOERR | (20<<8)) #define SQLITE_IOERR_SHMMAP (SQLITE_IOERR | (21<<8)) #define SQLITE_IOERR_SEEK (SQLITE_IOERR | (22<<8)) #define SQLITE_IOERR_DELETE_NOENT (SQLITE_IOERR | (23<<8)) #define SQLITE_IOERR_MMAP (SQLITE_IOERR | (24<<8)) #define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8)) #define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8)) #define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1<<8)) #define SQLITE_CANTOPEN_ISDIR (SQLITE_CANTOPEN | (2<<8)) #define SQLITE_CANTOPEN_FULLPATH (SQLITE_CANTOPEN | (3<<8)) #define SQLITE_CORRUPT_VTAB (SQLITE_CORRUPT | (1<<8)) #define SQLITE_READONLY_RECOVERY (SQLITE_READONLY | (1<<8)) #define SQLITE_READONLY_CANTLOCK (SQLITE_READONLY | (2<<8)) #define SQLITE_READONLY_ROLLBACK (SQLITE_READONLY | (3<<8)) #define SQLITE_ABORT_ROLLBACK (SQLITE_ABORT | (2<<8)) #define SQLITE_CONSTRAINT_CHECK (SQLITE_CONSTRAINT | (1<<8)) #define SQLITE_CONSTRAINT_COMMITHOOK (SQLITE_CONSTRAINT | (2<<8)) #define SQLITE_CONSTRAINT_FOREIGNKEY (SQLITE_CONSTRAINT | (3<<8)) #define SQLITE_CONSTRAINT_FUNCTION (SQLITE_CONSTRAINT | (4<<8)) #define SQLITE_CONSTRAINT_NOTNULL (SQLITE_CONSTRAINT | (5<<8)) #define SQLITE_CONSTRAINT_PRIMARYKEY (SQLITE_CONSTRAINT | (6<<8)) #define SQLITE_CONSTRAINT_TRIGGER (SQLITE_CONSTRAINT | (7<<8)) #define SQLITE_CONSTRAINT_UNIQUE (SQLITE_CONSTRAINT | (8<<8)) #define SQLITE_CONSTRAINT_VTAB (SQLITE_CONSTRAINT | (9<<8)) #define SQLITE_NOTICE_RECOVER_WAL (SQLITE_NOTICE | (1<<8)) #define SQLITE_NOTICE_RECOVER_ROLLBACK (SQLITE_NOTICE | (2<<8)) /* ** CAPI3REF: Flags For File Open Operations ** ** These bit values are intended for use in the ** 3rd parameter to the [sqlite3_open_v2()] interface and ** in the 4th parameter to the [sqlite3_vfs.xOpen] method. |
︙ | ︙ | |||
724 725 726 727 728 729 730 731 732 733 734 735 736 737 | int (*xDeviceCharacteristics)(sqlite3_file*); /* Methods above are valid for version 1 */ int (*xShmMap)(sqlite3_file*, int iPg, int pgsz, int, void volatile**); int (*xShmLock)(sqlite3_file*, int offset, int n, int flags); void (*xShmBarrier)(sqlite3_file*); int (*xShmUnmap)(sqlite3_file*, int deleteFlag); /* Methods above are valid for version 2 */ /* Additional methods may be added in future releases */ }; /* ** CAPI3REF: Standard File Control Opcodes ** ** These integer constants are opcodes for the xFileControl method | > > > | 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 | int (*xDeviceCharacteristics)(sqlite3_file*); /* Methods above are valid for version 1 */ int (*xShmMap)(sqlite3_file*, int iPg, int pgsz, int, void volatile**); int (*xShmLock)(sqlite3_file*, int offset, int n, int flags); void (*xShmBarrier)(sqlite3_file*); int (*xShmUnmap)(sqlite3_file*, int deleteFlag); /* Methods above are valid for version 2 */ int (*xFetch)(sqlite3_file*, sqlite3_int64 iOfst, int iAmt, void **pp); int (*xUnfetch)(sqlite3_file*, sqlite3_int64 iOfst, void *p); /* Methods above are valid for version 3 */ /* Additional methods may be added in future releases */ }; /* ** CAPI3REF: Standard File Control Opcodes ** ** These integer constants are opcodes for the xFileControl method |
︙ | ︙ | |||
860 861 862 863 864 865 866 | ** any result code other than [SQLITE_OK] or [SQLITE_NOTFOUND], that means ** that the VFS encountered an error while handling the [PRAGMA] and the ** compilation of the PRAGMA fails with an error. ^The [SQLITE_FCNTL_PRAGMA] ** file control occurs at the beginning of pragma statement analysis and so ** it is able to override built-in [PRAGMA] statements. ** ** <li>[[SQLITE_FCNTL_BUSYHANDLER]] | > | > | > > > > > > > > > > > | 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 | ** any result code other than [SQLITE_OK] or [SQLITE_NOTFOUND], that means ** that the VFS encountered an error while handling the [PRAGMA] and the ** compilation of the PRAGMA fails with an error. ^The [SQLITE_FCNTL_PRAGMA] ** file control occurs at the beginning of pragma statement analysis and so ** it is able to override built-in [PRAGMA] statements. ** ** <li>[[SQLITE_FCNTL_BUSYHANDLER]] ** ^The [SQLITE_FCNTL_BUSYHANDLER] ** file-control may be invoked by SQLite on the database file handle ** shortly after it is opened in order to provide a custom VFS with access ** to the connections busy-handler callback. The argument is of type (void **) ** - an array of two (void *) values. The first (void *) actually points ** to a function of type (int (*)(void *)). In order to invoke the connections ** busy-handler, this function should be invoked with the second (void *) in ** the array as the only argument. If it returns non-zero, then the operation ** should be retried. If it returns zero, the custom VFS should abandon the ** current operation. ** ** <li>[[SQLITE_FCNTL_TEMPFILENAME]] ** ^Application can invoke the [SQLITE_FCNTL_TEMPFILENAME] file-control ** to have SQLite generate a ** temporary filename using the same algorithm that is followed to generate ** temporary filenames for TEMP tables and other internal uses. The ** argument should be a char** which will be filled with the filename ** written into memory obtained from [sqlite3_malloc()]. The caller should ** invoke [sqlite3_free()] on the result to avoid a memory leak. ** ** <li>[[SQLITE_FCNTL_MMAP_SIZE]] ** The [SQLITE_FCNTL_MMAP_SIZE] file control is used to query or set the ** maximum number of bytes that will be used for memory-mapped I/O. ** The argument is a pointer to a value of type sqlite3_int64 that ** is an advisory maximum number of bytes in the file to memory map. The ** pointer is overwritten with the old value. The limit is not changed if ** the value originally pointed to is negative, and so the current limit ** can be queried by passing in a pointer to a negative number. This ** file-control is used internally to implement [PRAGMA mmap_size]. ** ** </ul> */ #define SQLITE_FCNTL_LOCKSTATE 1 #define SQLITE_GET_LOCKPROXYFILE 2 #define SQLITE_SET_LOCKPROXYFILE 3 #define SQLITE_LAST_ERRNO 4 #define SQLITE_FCNTL_SIZE_HINT 5 #define SQLITE_FCNTL_CHUNK_SIZE 6 #define SQLITE_FCNTL_FILE_POINTER 7 #define SQLITE_FCNTL_SYNC_OMITTED 8 #define SQLITE_FCNTL_WIN32_AV_RETRY 9 #define SQLITE_FCNTL_PERSIST_WAL 10 #define SQLITE_FCNTL_OVERWRITE 11 #define SQLITE_FCNTL_VFSNAME 12 #define SQLITE_FCNTL_POWERSAFE_OVERWRITE 13 #define SQLITE_FCNTL_PRAGMA 14 #define SQLITE_FCNTL_BUSYHANDLER 15 #define SQLITE_FCNTL_TEMPFILENAME 16 #define SQLITE_FCNTL_MMAP_SIZE 18 /* ** CAPI3REF: Mutex Handle ** ** The mutex module within SQLite defines [sqlite3_mutex] to be an ** abstract type for a mutex object. The SQLite core never looks ** at the internal representation of an [sqlite3_mutex]. It only |
︙ | ︙ | |||
1562 1563 1564 1565 1566 1567 1568 | ** ** [[SQLITE_CONFIG_GETPCACHE2]] <dt>SQLITE_CONFIG_GETPCACHE2</dt> ** <dd> ^(This option takes a single argument which is a pointer to an ** [sqlite3_pcache_methods2] object. SQLite copies of the current ** page cache implementation into that object.)^ </dd> ** ** [[SQLITE_CONFIG_LOG]] <dt>SQLITE_CONFIG_LOG</dt> | > > | | 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 | ** ** [[SQLITE_CONFIG_GETPCACHE2]] <dt>SQLITE_CONFIG_GETPCACHE2</dt> ** <dd> ^(This option takes a single argument which is a pointer to an ** [sqlite3_pcache_methods2] object. SQLite copies of the current ** page cache implementation into that object.)^ </dd> ** ** [[SQLITE_CONFIG_LOG]] <dt>SQLITE_CONFIG_LOG</dt> ** <dd> The SQLITE_CONFIG_LOG option is used to configure the SQLite ** global [error log]. ** (^The SQLITE_CONFIG_LOG option takes two arguments: a pointer to a ** function with a call signature of void(*)(void*,int,const char*), ** and a pointer to void. ^If the function pointer is not NULL, it is ** invoked by [sqlite3_log()] to process each logging event. ^If the ** function pointer is NULL, the [sqlite3_log()] interface becomes a no-op. ** ^The void pointer that is the second argument to SQLITE_CONFIG_LOG is ** passed through as the first parameter to the application-defined logger ** function whenever that function is invoked. ^The second parameter to |
︙ | ︙ | |||
1608 1609 1610 1611 1612 1613 1614 | ** disable the optimization allows the older, buggy application code to work ** without change even with newer versions of SQLite. ** ** [[SQLITE_CONFIG_PCACHE]] [[SQLITE_CONFIG_GETPCACHE]] ** <dt>SQLITE_CONFIG_PCACHE and SQLITE_CONFIG_GETPCACHE ** <dd> These options are obsolete and should not be used by new code. ** They are retained for backwards compatibility but are now no-ops. | | | | > > > > > > > > > > > > > > > > | 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 | ** disable the optimization allows the older, buggy application code to work ** without change even with newer versions of SQLite. ** ** [[SQLITE_CONFIG_PCACHE]] [[SQLITE_CONFIG_GETPCACHE]] ** <dt>SQLITE_CONFIG_PCACHE and SQLITE_CONFIG_GETPCACHE ** <dd> These options are obsolete and should not be used by new code. ** They are retained for backwards compatibility but are now no-ops. ** </dd> ** ** [[SQLITE_CONFIG_SQLLOG]] ** <dt>SQLITE_CONFIG_SQLLOG ** <dd>This option is only available if sqlite is compiled with the ** [SQLITE_ENABLE_SQLLOG] pre-processor macro defined. The first argument should ** be a pointer to a function of type void(*)(void*,sqlite3*,const char*, int). ** The second should be of type (void*). The callback is invoked by the library ** in three separate circumstances, identified by the value passed as the ** fourth parameter. If the fourth parameter is 0, then the database connection ** passed as the second argument has just been opened. The third argument ** points to a buffer containing the name of the main database file. If the ** fourth parameter is 1, then the SQL statement that the third parameter ** points to has just been executed. Or, if the fourth parameter is 2, then ** the connection being passed as the second parameter is being closed. The ** third parameter is passed NULL In this case. An example of using this ** configuration option can be seen in the "test_sqllog.c" source file in ** the canonical SQLite source tree.</dd> ** ** [[SQLITE_CONFIG_MMAP_SIZE]] ** <dt>SQLITE_CONFIG_MMAP_SIZE ** <dd>SQLITE_CONFIG_MMAP_SIZE takes two 64-bit integer (sqlite3_int64) values ** that are the default mmap size limit (the default setting for ** [PRAGMA mmap_size]) and the maximum allowed mmap size limit. ** The default setting can be overridden by each database connection using ** either the [PRAGMA mmap_size] command, or by using the ** [SQLITE_FCNTL_MMAP_SIZE] file control. The maximum allowed mmap size ** cannot be changed at run-time. Nor may the maximum allowed mmap size ** exceed the compile-time maximum mmap size set by the ** [SQLITE_MAX_MMAP_SIZE] compile-time option. ** If either argument to this option is negative, then that argument is ** changed to its compile-time default. ** </dl> */ #define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */ #define SQLITE_CONFIG_MULTITHREAD 2 /* nil */ #define SQLITE_CONFIG_SERIALIZED 3 /* nil */ #define SQLITE_CONFIG_MALLOC 4 /* sqlite3_mem_methods* */ #define SQLITE_CONFIG_GETMALLOC 5 /* sqlite3_mem_methods* */ |
︙ | ︙ | |||
1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 | #define SQLITE_CONFIG_GETPCACHE 15 /* no-op */ #define SQLITE_CONFIG_LOG 16 /* xFunc, void* */ #define SQLITE_CONFIG_URI 17 /* int */ #define SQLITE_CONFIG_PCACHE2 18 /* sqlite3_pcache_methods2* */ #define SQLITE_CONFIG_GETPCACHE2 19 /* sqlite3_pcache_methods2* */ #define SQLITE_CONFIG_COVERING_INDEX_SCAN 20 /* int */ #define SQLITE_CONFIG_SQLLOG 21 /* xSqllog, void* */ /* ** CAPI3REF: Database Connection Configuration Options ** ** These constants are the available integer configuration options that ** can be passed as the second argument to the [sqlite3_db_config()] interface. ** | > | 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 | #define SQLITE_CONFIG_GETPCACHE 15 /* no-op */ #define SQLITE_CONFIG_LOG 16 /* xFunc, void* */ #define SQLITE_CONFIG_URI 17 /* int */ #define SQLITE_CONFIG_PCACHE2 18 /* sqlite3_pcache_methods2* */ #define SQLITE_CONFIG_GETPCACHE2 19 /* sqlite3_pcache_methods2* */ #define SQLITE_CONFIG_COVERING_INDEX_SCAN 20 /* int */ #define SQLITE_CONFIG_SQLLOG 21 /* xSqllog, void* */ #define SQLITE_CONFIG_MMAP_SIZE 22 /* sqlite3_int64, sqlite3_int64 */ /* ** CAPI3REF: Database Connection Configuration Options ** ** These constants are the available integer configuration options that ** can be passed as the second argument to the [sqlite3_db_config()] interface. ** |
︙ | ︙ | |||
2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 | ** various times when an SQL statement is being run by [sqlite3_step()]. ** ^The sqlite3_trace() callback is invoked with a UTF-8 rendering of the ** SQL statement text as the statement first begins executing. ** ^(Additional sqlite3_trace() callbacks might occur ** as each triggered subprogram is entered. The callbacks for triggers ** contain a UTF-8 SQL comment that identifies the trigger.)^ ** ** ^The callback function registered by sqlite3_profile() is invoked ** as each SQL statement finishes. ^The profile callback contains ** the original statement text and an estimate of wall-clock time ** of how long that statement took to run. ^The profile callback ** time is in units of nanoseconds, however the current implementation ** is only capable of millisecond resolution so the six least significant ** digits in the time are meaningless. Future versions of SQLite | > > > | 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 | ** various times when an SQL statement is being run by [sqlite3_step()]. ** ^The sqlite3_trace() callback is invoked with a UTF-8 rendering of the ** SQL statement text as the statement first begins executing. ** ^(Additional sqlite3_trace() callbacks might occur ** as each triggered subprogram is entered. The callbacks for triggers ** contain a UTF-8 SQL comment that identifies the trigger.)^ ** ** The [SQLITE_TRACE_SIZE_LIMIT] compile-time option can be used to limit ** the length of [bound parameter] expansion in the output of sqlite3_trace(). ** ** ^The callback function registered by sqlite3_profile() is invoked ** as each SQL statement finishes. ^The profile callback contains ** the original statement text and an estimate of wall-clock time ** of how long that statement took to run. ^The profile callback ** time is in units of nanoseconds, however the current implementation ** is only capable of millisecond resolution so the six least significant ** digits in the time are meaningless. Future versions of SQLite |
︙ | ︙ | |||
2671 2672 2673 2674 2675 2676 2677 | ** ** <li> <b>cache</b>: ^The cache parameter may be set to either "shared" or ** "private". ^Setting it to "shared" is equivalent to setting the ** SQLITE_OPEN_SHAREDCACHE bit in the flags argument passed to ** sqlite3_open_v2(). ^Setting the cache parameter to "private" is ** equivalent to setting the SQLITE_OPEN_PRIVATECACHE bit. ** ^If sqlite3_open_v2() is used and the "cache" parameter is present in | | | 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 | ** ** <li> <b>cache</b>: ^The cache parameter may be set to either "shared" or ** "private". ^Setting it to "shared" is equivalent to setting the ** SQLITE_OPEN_SHAREDCACHE bit in the flags argument passed to ** sqlite3_open_v2(). ^Setting the cache parameter to "private" is ** equivalent to setting the SQLITE_OPEN_PRIVATECACHE bit. ** ^If sqlite3_open_v2() is used and the "cache" parameter is present in ** a URI filename, its value overrides any behavior requested by setting ** SQLITE_OPEN_PRIVATECACHE or SQLITE_OPEN_SHAREDCACHE flag. ** </ul> ** ** ^Specifying an unknown parameter in the query component of a URI is not an ** error. Future versions of SQLite might understand additional query ** parameters. See "[query parameters with special meaning to SQLite]" for ** additional information. |
︙ | ︙ | |||
3018 3019 3020 3021 3022 3023 3024 | ** original SQL text. This causes the [sqlite3_step()] interface to ** behave differently in three ways: ** ** <ol> ** <li> ** ^If the database schema changes, instead of returning [SQLITE_SCHEMA] as it ** always used to do, [sqlite3_step()] will automatically recompile the SQL | | > | 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 | ** original SQL text. This causes the [sqlite3_step()] interface to ** behave differently in three ways: ** ** <ol> ** <li> ** ^If the database schema changes, instead of returning [SQLITE_SCHEMA] as it ** always used to do, [sqlite3_step()] will automatically recompile the SQL ** statement and try to run it again. As many as [SQLITE_MAX_SCHEMA_RETRY] ** retries will occur before sqlite3_step() gives up and returns an error. ** </li> ** ** <li> ** ^When an error occurs, [sqlite3_step()] will return one of the detailed ** [error codes] or [extended error codes]. ^The legacy behavior was that ** [sqlite3_step()] would only return a generic [SQLITE_ERROR] result code ** and the application would have to make a second call to [sqlite3_reset()] |
︙ | ︙ | |||
3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 | ** ^The index for named parameters can be looked up using the ** [sqlite3_bind_parameter_index()] API if desired. ^The index ** for "?NNN" parameters is the value of NNN. ** ^The NNN value must be between 1 and the [sqlite3_limit()] ** parameter [SQLITE_LIMIT_VARIABLE_NUMBER] (default value: 999). ** ** ^The third argument is the value to bind to the parameter. ** ** ^(In those routines that have a fourth argument, its value is the ** number of bytes in the parameter. To be clear: the value is the ** number of <u>bytes</u> in the value, not the number of characters.)^ ** ^If the fourth parameter to sqlite3_bind_text() or sqlite3_bind_text16() ** is negative, then the length of the string is ** the number of bytes up to the first zero terminator. | > > > | 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 3282 | ** ^The index for named parameters can be looked up using the ** [sqlite3_bind_parameter_index()] API if desired. ^The index ** for "?NNN" parameters is the value of NNN. ** ^The NNN value must be between 1 and the [sqlite3_limit()] ** parameter [SQLITE_LIMIT_VARIABLE_NUMBER] (default value: 999). ** ** ^The third argument is the value to bind to the parameter. ** ^If the third parameter to sqlite3_bind_text() or sqlite3_bind_text16() ** or sqlite3_bind_blob() is a NULL pointer then the fourth parameter ** is ignored and the end result is the same as sqlite3_bind_null(). ** ** ^(In those routines that have a fourth argument, its value is the ** number of bytes in the parameter. To be clear: the value is the ** number of <u>bytes</u> in the value, not the number of characters.)^ ** ^If the fourth parameter to sqlite3_bind_text() or sqlite3_bind_text16() ** is negative, then the length of the string is ** the number of bytes up to the first zero terminator. |
︙ | ︙ | |||
3989 3990 3991 3992 3993 3994 3995 | */ #ifndef SQLITE_OMIT_DEPRECATED SQLITE_DEPRECATED int sqlite3_aggregate_count(sqlite3_context*); SQLITE_DEPRECATED int sqlite3_expired(sqlite3_stmt*); SQLITE_DEPRECATED int sqlite3_transfer_bindings(sqlite3_stmt*, sqlite3_stmt*); SQLITE_DEPRECATED int sqlite3_global_recover(void); SQLITE_DEPRECATED void sqlite3_thread_cleanup(void); | | > | 4036 4037 4038 4039 4040 4041 4042 4043 4044 4045 4046 4047 4048 4049 4050 4051 | */ #ifndef SQLITE_OMIT_DEPRECATED SQLITE_DEPRECATED int sqlite3_aggregate_count(sqlite3_context*); SQLITE_DEPRECATED int sqlite3_expired(sqlite3_stmt*); SQLITE_DEPRECATED int sqlite3_transfer_bindings(sqlite3_stmt*, sqlite3_stmt*); SQLITE_DEPRECATED int sqlite3_global_recover(void); SQLITE_DEPRECATED void sqlite3_thread_cleanup(void); SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int64,int), void*,sqlite3_int64); #endif /* ** CAPI3REF: Obtaining SQL Function Parameter Values ** ** The C-language implementation of SQL functions and aggregates uses ** this set of interface routines to access the parameter values on |
︙ | ︙ | |||
4069 4070 4071 4072 4073 4074 4075 | ** called once for each invocation of the xStep callback and then one ** last time when the xFinal callback is invoked. ^(When no rows match ** an aggregate query, the xStep() callback of the aggregate function ** implementation is never called and xFinal() is called exactly once. ** In those cases, sqlite3_aggregate_context() might be called for the ** first time from within xFinal().)^ ** | | > | | > > | 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 | ** called once for each invocation of the xStep callback and then one ** last time when the xFinal callback is invoked. ^(When no rows match ** an aggregate query, the xStep() callback of the aggregate function ** implementation is never called and xFinal() is called exactly once. ** In those cases, sqlite3_aggregate_context() might be called for the ** first time from within xFinal().)^ ** ** ^The sqlite3_aggregate_context(C,N) routine returns a NULL pointer ** when first called if N is less than or equal to zero or if a memory ** allocate error occurs. ** ** ^(The amount of space allocated by sqlite3_aggregate_context(C,N) is ** determined by the N parameter on first successful call. Changing the ** value of N in subsequent call to sqlite3_aggregate_context() within ** the same aggregate function instance will not resize the memory ** allocation.)^ Within the xFinal callback, it is customary to set ** N=0 in calls to sqlite3_aggregate_context(C,N) so that no ** pointless memory allocations occur. ** ** ^SQLite automatically frees the memory allocated by ** sqlite3_aggregate_context() when the aggregate query concludes. ** ** The first parameter must be a copy of the ** [sqlite3_context | SQL function context] that is the first parameter ** to the xStep or xFinal callback routine that implements the aggregate |
︙ | ︙ | |||
4174 4175 4176 4177 4178 4179 4180 | ** argument is SQLITE_STATIC, it means that the content pointer is constant ** and will never change. It does not need to be destroyed. ^The ** SQLITE_TRANSIENT value means that the content will likely change in ** the near future and that SQLite should make its own private copy of ** the content before returning. ** ** The typedef is necessary to work around problems in certain | | | 4225 4226 4227 4228 4229 4230 4231 4232 4233 4234 4235 4236 4237 4238 4239 | ** argument is SQLITE_STATIC, it means that the content pointer is constant ** and will never change. It does not need to be destroyed. ^The ** SQLITE_TRANSIENT value means that the content will likely change in ** the near future and that SQLite should make its own private copy of ** the content before returning. ** ** The typedef is necessary to work around problems in certain ** C++ compilers. */ typedef void (*sqlite3_destructor_type)(void*); #define SQLITE_STATIC ((sqlite3_destructor_type)0) #define SQLITE_TRANSIENT ((sqlite3_destructor_type)-1) /* ** CAPI3REF: Setting The Result Of An SQL Function |
︙ | ︙ | |||
4973 4974 4975 4976 4977 4978 4979 | /* ** CAPI3REF: Load An Extension ** ** ^This interface loads an SQLite extension library from the named file. ** ** ^The sqlite3_load_extension() interface attempts to load an | | > > > > > | | > > > > | 5024 5025 5026 5027 5028 5029 5030 5031 5032 5033 5034 5035 5036 5037 5038 5039 5040 5041 5042 5043 5044 5045 5046 5047 5048 5049 5050 5051 | /* ** CAPI3REF: Load An Extension ** ** ^This interface loads an SQLite extension library from the named file. ** ** ^The sqlite3_load_extension() interface attempts to load an ** [SQLite extension] library contained in the file zFile. If ** the file cannot be loaded directly, attempts are made to load ** with various operating-system specific extensions added. ** So for example, if "samplelib" cannot be loaded, then names like ** "samplelib.so" or "samplelib.dylib" or "samplelib.dll" might ** be tried also. ** ** ^The entry point is zProc. ** ^(zProc may be 0, in which case SQLite will try to come up with an ** entry point name on its own. It first tries "sqlite3_extension_init". ** If that does not work, it constructs a name "sqlite3_X_init" where the ** X is consists of the lower-case equivalent of all ASCII alphabetic ** characters in the filename from the last "/" to the first following ** "." and omitting any initial "lib".)^ ** ^The sqlite3_load_extension() interface returns ** [SQLITE_OK] on success and [SQLITE_ERROR] if something goes wrong. ** ^If an error occurs and pzErrMsg is not 0, then the ** [sqlite3_load_extension()] interface shall attempt to ** fill *pzErrMsg with error message text stored in memory ** obtained from [sqlite3_malloc()]. The calling function ** should free this memory by calling [sqlite3_free()]. |
︙ | ︙ | |||
5003 5004 5005 5006 5007 5008 5009 | char **pzErrMsg /* Put error message here if not 0 */ ); /* ** CAPI3REF: Enable Or Disable Extension Loading ** ** ^So as not to open security holes in older applications that are | | | | | | 5063 5064 5065 5066 5067 5068 5069 5070 5071 5072 5073 5074 5075 5076 5077 5078 5079 5080 5081 5082 5083 5084 5085 5086 5087 5088 5089 5090 5091 5092 5093 | char **pzErrMsg /* Put error message here if not 0 */ ); /* ** CAPI3REF: Enable Or Disable Extension Loading ** ** ^So as not to open security holes in older applications that are ** unprepared to deal with [extension loading], and as a means of disabling ** [extension loading] while evaluating user-entered SQL, the following API ** is provided to turn the [sqlite3_load_extension()] mechanism on and off. ** ** ^Extension loading is off by default. ** ^Call the sqlite3_enable_load_extension() routine with onoff==1 ** to turn extension loading on and call it with onoff==0 to turn ** it back off again. */ int sqlite3_enable_load_extension(sqlite3 *db, int onoff); /* ** CAPI3REF: Automatically Load Statically Linked Extensions ** ** ^This interface causes the xEntryPoint() function to be invoked for ** each new [database connection] that is created. The idea here is that ** xEntryPoint() is the entry point for a statically linked [SQLite extension] ** that is to be automatically loaded into all new database connections. ** ** ^(Even though the function prototype shows that xEntryPoint() takes ** no arguments and returns void, SQLite invokes xEntryPoint() with three ** arguments and expects and integer result as if the signature of the ** entry point where as follows: ** |
︙ | ︙ | |||
6370 6371 6372 6373 6374 6375 6376 | ** If the requested page is already in the page cache, then the page cache ** implementation must return a pointer to the page buffer with its content ** intact. If the requested page is not already in the cache, then the ** cache implementation should use the value of the createFlag ** parameter to help it determined what action to take: ** ** <table border=1 width=85% align=center> | | | 6430 6431 6432 6433 6434 6435 6436 6437 6438 6439 6440 6441 6442 6443 6444 | ** If the requested page is already in the page cache, then the page cache ** implementation must return a pointer to the page buffer with its content ** intact. If the requested page is not already in the cache, then the ** cache implementation should use the value of the createFlag ** parameter to help it determined what action to take: ** ** <table border=1 width=85% align=center> ** <tr><th> createFlag <th> Behavior when page is not already in cache ** <tr><td> 0 <td> Do not allocate a new page. Return NULL. ** <tr><td> 1 <td> Allocate a new page if it easy and convenient to do so. ** Otherwise return NULL. ** <tr><td> 2 <td> Make every effort to allocate a new page. Only return ** NULL if allocating a new page is effectively impossible. ** </table> ** |
︙ | ︙ | |||
6799 6800 6801 6802 6803 6804 6805 6806 6807 6808 | ** and extensions to compare the contents of two buffers containing UTF-8 ** strings in a case-independent fashion, using the same definition of "case ** independence" that SQLite uses internally when comparing identifiers. */ int sqlite3_stricmp(const char *, const char *); int sqlite3_strnicmp(const char *, const char *, int); /* ** CAPI3REF: Error Logging Interface ** | > > > > > > > > > > > > > > > | | 6859 6860 6861 6862 6863 6864 6865 6866 6867 6868 6869 6870 6871 6872 6873 6874 6875 6876 6877 6878 6879 6880 6881 6882 6883 6884 6885 6886 6887 6888 6889 6890 6891 | ** and extensions to compare the contents of two buffers containing UTF-8 ** strings in a case-independent fashion, using the same definition of "case ** independence" that SQLite uses internally when comparing identifiers. */ int sqlite3_stricmp(const char *, const char *); int sqlite3_strnicmp(const char *, const char *, int); /* ** CAPI3REF: String Globbing * ** ^The [sqlite3_strglob(P,X)] interface returns zero if string X matches ** the glob pattern P, and it returns non-zero if string X does not match ** the glob pattern P. ^The definition of glob pattern matching used in ** [sqlite3_strglob(P,X)] is the same as for the "X GLOB P" operator in the ** SQL dialect used by SQLite. ^The sqlite3_strglob(P,X) function is case ** sensitive. ** ** Note that this routine returns zero on a match and non-zero if the strings ** do not match, the same as [sqlite3_stricmp()] and [sqlite3_strnicmp()]. */ int sqlite3_strglob(const char *zGlob, const char *zStr); /* ** CAPI3REF: Error Logging Interface ** ** ^The [sqlite3_log()] interface writes a message into the [error log] ** established by the [SQLITE_CONFIG_LOG] option to [sqlite3_config()]. ** ^If logging is enabled, the zFormat string and subsequent arguments are ** used with [sqlite3_snprintf()] to generate the final output string. ** ** The sqlite3_log() interface is intended for use by extensions such as ** virtual tables, collating functions, and SQL functions. While there is ** nothing to prevent an application from calling sqlite3_log(), doing so |
︙ | ︙ |
Changes to src/sqlite3ext.h.
︙ | ︙ | |||
465 466 467 468 469 470 471 472 473 474 475 | #define sqlite3_uri_boolean sqlite3_api->uri_boolean #define sqlite3_uri_int64 sqlite3_api->uri_int64 #define sqlite3_uri_parameter sqlite3_api->uri_parameter #define sqlite3_uri_vsnprintf sqlite3_api->vsnprintf #define sqlite3_wal_checkpoint_v2 sqlite3_api->wal_checkpoint_v2 #endif /* SQLITE_CORE */ #define SQLITE_EXTENSION_INIT1 const sqlite3_api_routines *sqlite3_api = 0; #define SQLITE_EXTENSION_INIT2(v) sqlite3_api = v; #endif /* _SQLITE3EXT_H_ */ | > > > > > > > > > | 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 | #define sqlite3_uri_boolean sqlite3_api->uri_boolean #define sqlite3_uri_int64 sqlite3_api->uri_int64 #define sqlite3_uri_parameter sqlite3_api->uri_parameter #define sqlite3_uri_vsnprintf sqlite3_api->vsnprintf #define sqlite3_wal_checkpoint_v2 sqlite3_api->wal_checkpoint_v2 #endif /* SQLITE_CORE */ #ifndef SQLITE_CORE /* This case when the file really is being compiled as a loadable ** extension */ #define SQLITE_EXTENSION_INIT1 const sqlite3_api_routines *sqlite3_api = 0; #define SQLITE_EXTENSION_INIT2(v) sqlite3_api = v; #else /* This case when the file is being statically linked into the ** application */ # define SQLITE_EXTENSION_INIT1 /*no-op*/ # define SQLITE_EXTENSION_INIT2(v) (void)v; /* unused parameter */ #endif #endif /* _SQLITE3EXT_H_ */ |
Changes to src/sqliteInt.h.
︙ | ︙ | |||
390 391 392 393 394 395 396 397 398 399 400 401 402 403 | /* ** Provide a default value for SQLITE_TEMP_STORE in case it is not specified ** on the command-line */ #ifndef SQLITE_TEMP_STORE # define SQLITE_TEMP_STORE 1 #endif /* ** GCC does not define the offsetof() macro so we'll have to do it ** ourselves. */ #ifndef offsetof | > | 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 | /* ** Provide a default value for SQLITE_TEMP_STORE in case it is not specified ** on the command-line */ #ifndef SQLITE_TEMP_STORE # define SQLITE_TEMP_STORE 1 # define SQLITE_TEMP_STORE_xc 1 /* Exclude from ctime.c */ #endif /* ** GCC does not define the offsetof() macro so we'll have to do it ** ourselves. */ #ifndef offsetof |
︙ | ︙ | |||
537 538 539 540 541 542 543 544 545 546 547 548 549 550 | */ #ifdef SQLITE_4_BYTE_ALIGNED_MALLOC # define EIGHT_BYTE_ALIGNMENT(X) ((((char*)(X) - (char*)0)&3)==0) #else # define EIGHT_BYTE_ALIGNMENT(X) ((((char*)(X) - (char*)0)&7)==0) #endif /* ** An instance of the following structure is used to store the busy-handler ** callback for a given sqlite handle. ** ** The sqlite.busyHandler member of the sqlite struct contains the busy ** callback for the database handle. Each pager opened via the sqlite | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 | */ #ifdef SQLITE_4_BYTE_ALIGNED_MALLOC # define EIGHT_BYTE_ALIGNMENT(X) ((((char*)(X) - (char*)0)&3)==0) #else # define EIGHT_BYTE_ALIGNMENT(X) ((((char*)(X) - (char*)0)&7)==0) #endif /* ** Disable MMAP on platforms where it is known to not work */ #if defined(__OpenBSD__) || defined(__QNXNTO__) # undef SQLITE_MAX_MMAP_SIZE # define SQLITE_MAX_MMAP_SIZE 0 #endif /* ** Default maximum size of memory used by memory-mapped I/O in the VFS */ #ifdef __APPLE__ # include <TargetConditionals.h> # if TARGET_OS_IPHONE # undef SQLITE_MAX_MMAP_SIZE # define SQLITE_MAX_MMAP_SIZE 0 # endif #endif #ifndef SQLITE_MAX_MMAP_SIZE # if defined(__linux__) \ || defined(_WIN32) \ || (defined(__APPLE__) && defined(__MACH__)) \ || defined(__sun) # define SQLITE_MAX_MMAP_SIZE 0x7fff0000 /* 2147418112 */ # else # define SQLITE_MAX_MMAP_SIZE 0 # endif # define SQLITE_MAX_MMAP_SIZE_xc 1 /* exclude from ctime.c */ #endif /* ** The default MMAP_SIZE is zero on all platforms. Or, even if a larger ** default MMAP_SIZE is specified at compile-time, make sure that it does ** not exceed the maximum mmap size. */ #ifndef SQLITE_DEFAULT_MMAP_SIZE # define SQLITE_DEFAULT_MMAP_SIZE 0 # define SQLITE_DEFAULT_MMAP_SIZE_xc 1 /* Exclude from ctime.c */ #endif #if SQLITE_DEFAULT_MMAP_SIZE>SQLITE_MAX_MMAP_SIZE # undef SQLITE_DEFAULT_MMAP_SIZE # define SQLITE_DEFAULT_MMAP_SIZE SQLITE_MAX_MMAP_SIZE #endif /* ** An instance of the following structure is used to store the busy-handler ** callback for a given sqlite handle. ** ** The sqlite.busyHandler member of the sqlite struct contains the busy ** callback for the database handle. Each pager opened via the sqlite |
︙ | ︙ | |||
832 833 834 835 836 837 838 839 840 841 842 843 844 845 | struct Vdbe *pVdbe; /* List of active virtual machines */ CollSeq *pDfltColl; /* The default collating sequence (BINARY) */ sqlite3_mutex *mutex; /* Connection mutex */ Db *aDb; /* All backends */ int nDb; /* Number of backends currently in use */ int flags; /* Miscellaneous flags. See below */ i64 lastRowid; /* ROWID of most recent insert (see above) */ unsigned int openFlags; /* Flags passed to sqlite3_vfs.xOpen() */ int errCode; /* Most recent error code (SQLITE_*) */ int errMask; /* & result codes with this before returning */ u16 dbOptFlags; /* Flags to enable/disable optimizations */ u8 autoCommit; /* The auto-commit flag. */ u8 temp_store; /* 1: file 2: memory 0: default */ u8 mallocFailed; /* True if we have seen a malloc failure */ | > | 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 | struct Vdbe *pVdbe; /* List of active virtual machines */ CollSeq *pDfltColl; /* The default collating sequence (BINARY) */ sqlite3_mutex *mutex; /* Connection mutex */ Db *aDb; /* All backends */ int nDb; /* Number of backends currently in use */ int flags; /* Miscellaneous flags. See below */ i64 lastRowid; /* ROWID of most recent insert (see above) */ i64 szMmap; /* Default mmap_size setting */ unsigned int openFlags; /* Flags passed to sqlite3_vfs.xOpen() */ int errCode; /* Most recent error code (SQLITE_*) */ int errMask; /* & result codes with this before returning */ u16 dbOptFlags; /* Flags to enable/disable optimizations */ u8 autoCommit; /* The auto-commit flag. */ u8 temp_store; /* 1: file 2: memory 0: default */ u8 mallocFailed; /* True if we have seen a malloc failure */ |
︙ | ︙ | |||
2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 | /* ** Allowed values for the NameContext, ncFlags field. */ #define NC_AllowAgg 0x01 /* Aggregate functions are allowed here */ #define NC_HasAgg 0x02 /* One or more aggregate functions seen */ #define NC_IsCheck 0x04 /* True if resolving names in a CHECK constraint */ #define NC_InAggFunc 0x08 /* True if analyzing arguments to an agg func */ /* ** An instance of the following structure contains all information ** needed to generate code for a single SELECT statement. ** ** nLimit is set to -1 if there is no LIMIT clause. nOffset is set to 0. ** If there is a LIMIT clause, the parser sets nLimit to the value of the | > > | 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 | /* ** Allowed values for the NameContext, ncFlags field. */ #define NC_AllowAgg 0x01 /* Aggregate functions are allowed here */ #define NC_HasAgg 0x02 /* One or more aggregate functions seen */ #define NC_IsCheck 0x04 /* True if resolving names in a CHECK constraint */ #define NC_InAggFunc 0x08 /* True if analyzing arguments to an agg func */ #define NC_AsMaybe 0x10 /* Resolve to AS terms of the result set only ** if no other resolution is available */ /* ** An instance of the following structure contains all information ** needed to generate code for a single SELECT statement. ** ** nLimit is set to -1 if there is no LIMIT clause. nOffset is set to 0. ** If there is a LIMIT clause, the parser sets nLimit to the value of the |
︙ | ︙ | |||
2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 | int nLookaside; /* Default lookaside buffer count */ sqlite3_mem_methods m; /* Low-level memory allocation interface */ sqlite3_mutex_methods mutex; /* Low-level mutex interface */ sqlite3_pcache_methods2 pcache2; /* Low-level page-cache interface */ void *pHeap; /* Heap storage space */ int nHeap; /* Size of pHeap[] */ int mnReq, mxReq; /* Min and max heap requests sizes */ void *pScratch; /* Scratch memory */ int szScratch; /* Size of each scratch buffer */ int nScratch; /* Number of scratch buffers */ void *pPage; /* Page cache memory */ int szPage; /* Size of each page in pPage[] */ int nPage; /* Number of pages in pPage[] */ int mxParserStack; /* maximum depth of the parser stack */ | > > | 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 | int nLookaside; /* Default lookaside buffer count */ sqlite3_mem_methods m; /* Low-level memory allocation interface */ sqlite3_mutex_methods mutex; /* Low-level mutex interface */ sqlite3_pcache_methods2 pcache2; /* Low-level page-cache interface */ void *pHeap; /* Heap storage space */ int nHeap; /* Size of pHeap[] */ int mnReq, mxReq; /* Min and max heap requests sizes */ sqlite3_int64 szMmap; /* mmap() space per open file */ sqlite3_int64 mxMmap; /* Maximum value for szMmap */ void *pScratch; /* Scratch memory */ int szScratch; /* Size of each scratch buffer */ int nScratch; /* Number of scratch buffers */ void *pPage; /* Page cache memory */ int szPage; /* Size of each page in pPage[] */ int nPage; /* Number of pages in pPage[] */ int mxParserStack; /* maximum depth of the parser stack */ |
︙ | ︙ | |||
2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 | ** Context pointer passed down through the tree-walk. */ struct Walker { int (*xExprCallback)(Walker*, Expr*); /* Callback for expressions */ int (*xSelectCallback)(Walker*,Select*); /* Callback for SELECTs */ Parse *pParse; /* Parser context. */ int walkerDepth; /* Number of subqueries */ union { /* Extra data for callback */ NameContext *pNC; /* Naming context */ int i; /* Integer value */ SrcList *pSrcList; /* FROM clause */ struct SrcCount *pSrcCount; /* Counting column references */ } u; }; | > | 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 | ** Context pointer passed down through the tree-walk. */ struct Walker { int (*xExprCallback)(Walker*, Expr*); /* Callback for expressions */ int (*xSelectCallback)(Walker*,Select*); /* Callback for SELECTs */ Parse *pParse; /* Parser context. */ int walkerDepth; /* Number of subqueries */ u8 bSelectDepthFirst; /* Do subqueries first */ union { /* Extra data for callback */ NameContext *pNC; /* Naming context */ int i; /* Integer value */ SrcList *pSrcList; /* FROM clause */ struct SrcCount *pSrcCount; /* Counting column references */ } u; }; |
︙ | ︙ | |||
3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 | int sqlite3IndexAffinityOk(Expr *pExpr, char idx_affinity); char sqlite3ExprAffinity(Expr *pExpr); int sqlite3Atoi64(const char*, i64*, int, u8); void sqlite3Error(sqlite3*, int, const char*,...); void *sqlite3HexToBlob(sqlite3*, const char *z, int n); u8 sqlite3HexToInt(int h); int sqlite3TwoPartName(Parse *, Token *, Token *, Token **); const char *sqlite3ErrStr(int); int sqlite3ReadSchema(Parse *pParse); CollSeq *sqlite3FindCollSeq(sqlite3*,u8 enc, const char*,int); CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char*zName); CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr); Expr *sqlite3ExprAddCollateToken(Parse *pParse, Expr*, Token*); Expr *sqlite3ExprAddCollateString(Parse*,Expr*,const char*); | > > > > > > | 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 | int sqlite3IndexAffinityOk(Expr *pExpr, char idx_affinity); char sqlite3ExprAffinity(Expr *pExpr); int sqlite3Atoi64(const char*, i64*, int, u8); void sqlite3Error(sqlite3*, int, const char*,...); void *sqlite3HexToBlob(sqlite3*, const char *z, int n); u8 sqlite3HexToInt(int h); int sqlite3TwoPartName(Parse *, Token *, Token *, Token **); #if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) || \ defined(SQLITE_DEBUG_OS_TRACE) const char *sqlite3ErrName(int); #endif const char *sqlite3ErrStr(int); int sqlite3ReadSchema(Parse *pParse); CollSeq *sqlite3FindCollSeq(sqlite3*,u8 enc, const char*,int); CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char*zName); CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr); Expr *sqlite3ExprAddCollateToken(Parse *pParse, Expr*, Token*); Expr *sqlite3ExprAddCollateString(Parse*,Expr*,const char*); |
︙ | ︙ |
Changes to src/tclsqlite.c.
︙ | ︙ | |||
1001 1002 1003 1004 1005 1006 1007 | zEnd = azEnd[(rc==TCL_ERROR)*2 + (pDb->nTransaction==0)]; pDb->disableAuth++; if( sqlite3_exec(pDb->db, zEnd, 0, 0, 0) ){ /* This is a tricky scenario to handle. The most likely cause of an ** error is that the exec() above was an attempt to commit the ** top-level transaction that returned SQLITE_BUSY. Or, less likely, | | | 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 | zEnd = azEnd[(rc==TCL_ERROR)*2 + (pDb->nTransaction==0)]; pDb->disableAuth++; if( sqlite3_exec(pDb->db, zEnd, 0, 0, 0) ){ /* This is a tricky scenario to handle. The most likely cause of an ** error is that the exec() above was an attempt to commit the ** top-level transaction that returned SQLITE_BUSY. Or, less likely, ** that an IO-error has occurred. In either case, throw a Tcl exception ** and try to rollback the transaction. ** ** But it could also be that the user executed one or more BEGIN, ** COMMIT, SAVEPOINT, RELEASE or ROLLBACK commands that are confusing ** this method's logic. Not clear how this would be best handled. */ if( rc!=TCL_ERROR ){ |
︙ | ︙ | |||
3679 3680 3681 3682 3683 3684 3685 | extern int Sqlitetestintarray_Init(Tcl_Interp*); extern int Sqlitetestvfs_Init(Tcl_Interp *); extern int Sqlitetestrtree_Init(Tcl_Interp*); extern int Sqlitequota_Init(Tcl_Interp*); extern int Sqlitemultiplex_Init(Tcl_Interp*); extern int SqliteSuperlock_Init(Tcl_Interp*); extern int SqlitetestSyscall_Init(Tcl_Interp*); | < < < | 3679 3680 3681 3682 3683 3684 3685 3686 3687 3688 3689 3690 3691 3692 | extern int Sqlitetestintarray_Init(Tcl_Interp*); extern int Sqlitetestvfs_Init(Tcl_Interp *); extern int Sqlitetestrtree_Init(Tcl_Interp*); extern int Sqlitequota_Init(Tcl_Interp*); extern int Sqlitemultiplex_Init(Tcl_Interp*); extern int SqliteSuperlock_Init(Tcl_Interp*); extern int SqlitetestSyscall_Init(Tcl_Interp*); #if defined(SQLITE_ENABLE_FTS3) || defined(SQLITE_ENABLE_FTS4) extern int Sqlitetestfts3_Init(Tcl_Interp *interp); #endif #ifdef SQLITE_ENABLE_ZIPVFS extern int Zipvfs_Init(Tcl_Interp*); |
︙ | ︙ | |||
3724 3725 3726 3727 3728 3729 3730 | Sqlitetestintarray_Init(interp); Sqlitetestvfs_Init(interp); Sqlitetestrtree_Init(interp); Sqlitequota_Init(interp); Sqlitemultiplex_Init(interp); SqliteSuperlock_Init(interp); SqlitetestSyscall_Init(interp); | < < < | 3721 3722 3723 3724 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 | Sqlitetestintarray_Init(interp); Sqlitetestvfs_Init(interp); Sqlitetestrtree_Init(interp); Sqlitequota_Init(interp); Sqlitemultiplex_Init(interp); SqliteSuperlock_Init(interp); SqlitetestSyscall_Init(interp); #if defined(SQLITE_ENABLE_FTS3) || defined(SQLITE_ENABLE_FTS4) Sqlitetestfts3_Init(interp); #endif Tcl_CreateObjCommand( interp, "load_testfixture_extensions", init_all_cmd, 0, 0 |
︙ | ︙ |
Changes to src/test1.c.
︙ | ︙ | |||
109 110 111 112 113 114 115 | *ppDb = p->db; }else{ *ppDb = (sqlite3*)sqlite3TestTextToPtr(zA); } return TCL_OK; } | < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 | *ppDb = p->db; }else{ *ppDb = (sqlite3*)sqlite3TestTextToPtr(zA); } return TCL_OK; } extern const char *sqlite3ErrName(int); #define t1ErrorName sqlite3ErrName /* ** Convert an sqlite3_stmt* into an sqlite3*. This depends on the ** fact that the sqlite3* is the first field in the Vdbe structure. */ #define StmtToDb(X) sqlite3_db_handle(X) |
︙ | ︙ | |||
1724 1725 1726 1727 1728 1729 1730 | if( nByte>0 ){ zBuf = (unsigned char *)Tcl_Alloc(nByte); } rc = sqlite3_blob_read(pBlob, zBuf, nByte, iOffset); if( rc==SQLITE_OK ){ Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(zBuf, nByte)); }else{ | | | 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 | if( nByte>0 ){ zBuf = (unsigned char *)Tcl_Alloc(nByte); } rc = sqlite3_blob_read(pBlob, zBuf, nByte, iOffset); if( rc==SQLITE_OK ){ Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(zBuf, nByte)); }else{ Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE); } Tcl_Free((char *)zBuf); return (rc==SQLITE_OK ? TCL_OK : TCL_ERROR); } /* |
︙ | ︙ | |||
1774 1775 1776 1777 1778 1779 1780 | zBuf = Tcl_GetByteArrayFromObj(objv[3], &nBuf); if( objc==5 && Tcl_GetIntFromObj(interp, objv[4], &nBuf) ){ return TCL_ERROR; } rc = sqlite3_blob_write(pBlob, zBuf, nBuf, iOffset); if( rc!=SQLITE_OK ){ | | | 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 | zBuf = Tcl_GetByteArrayFromObj(objv[3], &nBuf); if( objc==5 && Tcl_GetIntFromObj(interp, objv[4], &nBuf) ){ return TCL_ERROR; } rc = sqlite3_blob_write(pBlob, zBuf, nBuf, iOffset); if( rc!=SQLITE_OK ){ Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE); } return (rc==SQLITE_OK ? TCL_OK : TCL_ERROR); } static int test_blob_reopen( ClientData clientData, /* Not used */ |
︙ | ︙ | |||
1800 1801 1802 1803 1804 1805 1806 | } if( blobHandleFromObj(interp, objv[1], &pBlob) ) return TCL_ERROR; if( Tcl_GetWideIntFromObj(interp, objv[2], &iRowid) ) return TCL_ERROR; rc = sqlite3_blob_reopen(pBlob, iRowid); if( rc!=SQLITE_OK ){ | | | 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 | } if( blobHandleFromObj(interp, objv[1], &pBlob) ) return TCL_ERROR; if( Tcl_GetWideIntFromObj(interp, objv[2], &iRowid) ) return TCL_ERROR; rc = sqlite3_blob_reopen(pBlob, iRowid); if( rc!=SQLITE_OK ){ Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE); } return (rc==SQLITE_OK ? TCL_OK : TCL_ERROR); } #endif |
︙ | ︙ | |||
2010 2011 2012 2013 2014 2015 2016 | (p->pFunc ? cf2Func : 0), (p->pStep ? cf2Step : 0), (p->pFinal ? cf2Final : 0), cf2Destroy ); if( rc!=SQLITE_OK ){ Tcl_ResetResult(interp); | | | 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 | (p->pFunc ? cf2Func : 0), (p->pStep ? cf2Step : 0), (p->pFinal ? cf2Final : 0), cf2Destroy ); if( rc!=SQLITE_OK ){ Tcl_ResetResult(interp); Tcl_AppendResult(interp, sqlite3ErrName(rc), 0); return TCL_ERROR; } return TCL_OK; } /* ** Usage: sqlite3_load_extension DB-HANDLE FILE ?PROC? |
︙ | ︙ | |||
2686 2687 2688 2689 2690 2691 2692 | } sqlite3ValueFree(pVal); sqlite3_mutex_leave(db->mutex); } if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR; if( rc!=SQLITE_OK ){ | | | 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 | } sqlite3ValueFree(pVal); sqlite3_mutex_leave(db->mutex); } if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR; if( rc!=SQLITE_OK ){ Tcl_AppendResult(interp, sqlite3ErrName(rc), 0); return TCL_ERROR; } return TCL_OK; bad_args: Tcl_AppendResult(interp, "wrong # args: should be \"", Tcl_GetStringFromObj(objv[0], 0), " <DB> <utf8> <utf16le> <utf16be>", 0); |
︙ | ︙ | |||
3244 3245 3246 3247 3248 3249 3250 | if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR; value = (char*)Tcl_GetByteArrayFromObj(objv[3], &bytes); if( Tcl_GetIntFromObj(interp, objv[4], &bytes) ) return TCL_ERROR; rc = sqlite3_bind_text(pStmt, idx, value, bytes, SQLITE_TRANSIENT); if( sqlite3TestErrCode(interp, StmtToDb(pStmt), rc) ) return TCL_ERROR; if( rc!=SQLITE_OK ){ | | | 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 | if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR; value = (char*)Tcl_GetByteArrayFromObj(objv[3], &bytes); if( Tcl_GetIntFromObj(interp, objv[4], &bytes) ) return TCL_ERROR; rc = sqlite3_bind_text(pStmt, idx, value, bytes, SQLITE_TRANSIENT); if( sqlite3TestErrCode(interp, StmtToDb(pStmt), rc) ) return TCL_ERROR; if( rc!=SQLITE_OK ){ Tcl_AppendResult(interp, sqlite3ErrName(rc), 0); return TCL_ERROR; } return TCL_OK; } /* |
︙ | ︙ | |||
3292 3293 3294 3295 3296 3297 3298 | if( Tcl_GetIntFromObj(interp, oN, &idx) ) return TCL_ERROR; value = (char*)Tcl_GetByteArrayFromObj(oString, 0); if( Tcl_GetIntFromObj(interp, oBytes, &bytes) ) return TCL_ERROR; rc = sqlite3_bind_text16(pStmt, idx, (void *)value, bytes, xDel); if( sqlite3TestErrCode(interp, StmtToDb(pStmt), rc) ) return TCL_ERROR; if( rc!=SQLITE_OK ){ | | | 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 | if( Tcl_GetIntFromObj(interp, oN, &idx) ) return TCL_ERROR; value = (char*)Tcl_GetByteArrayFromObj(oString, 0); if( Tcl_GetIntFromObj(interp, oBytes, &bytes) ) return TCL_ERROR; rc = sqlite3_bind_text16(pStmt, idx, (void *)value, bytes, xDel); if( sqlite3TestErrCode(interp, StmtToDb(pStmt), rc) ) return TCL_ERROR; if( rc!=SQLITE_OK ){ Tcl_AppendResult(interp, sqlite3ErrName(rc), 0); return TCL_ERROR; } #endif /* SQLITE_OMIT_UTF16 */ return TCL_OK; } |
︙ | ︙ | |||
4566 4567 4568 4569 4570 4571 4572 | Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " DB", 0); return TCL_ERROR; } if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; if( Tcl_GetInt(interp, argv[2], &ms) ) return TCL_ERROR; rc = sqlite3_busy_timeout(db, ms); | | | 4497 4498 4499 4500 4501 4502 4503 4504 4505 4506 4507 4508 4509 4510 4511 | Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " DB", 0); return TCL_ERROR; } if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; if( Tcl_GetInt(interp, argv[2], &ms) ) return TCL_ERROR; rc = sqlite3_busy_timeout(db, ms); Tcl_AppendResult(interp, sqlite3ErrName(rc), 0); return TCL_OK; } /* ** Usage: tcl_variable_type VARIABLENAME ** ** Return the name of the internal representation for the |
︙ | ︙ | |||
5087 5088 5089 5090 5091 5092 5093 | return TCL_ERROR; } zDb = Tcl_GetString(objv[2]); if( zDb[0]=='\0' ) zDb = NULL; rc = sqlite3_file_control(db, zDb, SQLITE_FCNTL_CHUNK_SIZE, (void *)&nSize); if( rc ){ | | | 5018 5019 5020 5021 5022 5023 5024 5025 5026 5027 5028 5029 5030 5031 5032 | return TCL_ERROR; } zDb = Tcl_GetString(objv[2]); if( zDb[0]=='\0' ) zDb = NULL; rc = sqlite3_file_control(db, zDb, SQLITE_FCNTL_CHUNK_SIZE, (void *)&nSize); if( rc ){ Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_STATIC); return TCL_ERROR; } return TCL_OK; } /* ** tclcmd: file_control_sizehint_test DB DBNAME SIZE |
︙ | ︙ | |||
5124 5125 5126 5127 5128 5129 5130 | return TCL_ERROR; } zDb = Tcl_GetString(objv[2]); if( zDb[0]=='\0' ) zDb = NULL; rc = sqlite3_file_control(db, zDb, SQLITE_FCNTL_SIZE_HINT, (void *)&nSize); if( rc ){ | | | 5055 5056 5057 5058 5059 5060 5061 5062 5063 5064 5065 5066 5067 5068 5069 | return TCL_ERROR; } zDb = Tcl_GetString(objv[2]); if( zDb[0]=='\0' ) zDb = NULL; rc = sqlite3_file_control(db, zDb, SQLITE_FCNTL_SIZE_HINT, (void *)&nSize); if( rc ){ Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_STATIC); return TCL_ERROR; } return TCL_OK; } /* ** tclcmd: file_control_lockproxy_test DB PWD |
︙ | ︙ | |||
5668 5669 5670 5671 5672 5673 5674 | Tcl_Interp *pInterp; Tcl_Obj *pObj; } logcallback = {0, 0}; static void xLogcallback(void *unused, int err, char *zMsg){ Tcl_Obj *pNew = Tcl_DuplicateObj(logcallback.pObj); Tcl_IncrRefCount(pNew); Tcl_ListObjAppendElement( | | | 5599 5600 5601 5602 5603 5604 5605 5606 5607 5608 5609 5610 5611 5612 5613 | Tcl_Interp *pInterp; Tcl_Obj *pObj; } logcallback = {0, 0}; static void xLogcallback(void *unused, int err, char *zMsg){ Tcl_Obj *pNew = Tcl_DuplicateObj(logcallback.pObj); Tcl_IncrRefCount(pNew); Tcl_ListObjAppendElement( 0, pNew, Tcl_NewStringObj(sqlite3ErrName(err), -1) ); Tcl_ListObjAppendElement(0, pNew, Tcl_NewStringObj(zMsg, -1)); Tcl_EvalObjEx(logcallback.pInterp, pNew, TCL_EVAL_GLOBAL|TCL_EVAL_DIRECT); Tcl_DecrRefCount(pNew); } static int test_sqlite3_log( ClientData clientData, |
︙ | ︙ | |||
5839 5840 5841 5842 5843 5844 5845 5846 5847 5848 5849 5850 5851 5852 | break; } } Tcl_ResetResult(interp); return TCL_OK; } #if SQLITE_OS_WIN /* ** Information passed from the main thread into the windows file locker ** background thread. */ struct win32FileLocker { | > > > > > > > > > > > > > > > > > > > > > > > > > | 5770 5771 5772 5773 5774 5775 5776 5777 5778 5779 5780 5781 5782 5783 5784 5785 5786 5787 5788 5789 5790 5791 5792 5793 5794 5795 5796 5797 5798 5799 5800 5801 5802 5803 5804 5805 5806 5807 5808 | break; } } Tcl_ResetResult(interp); return TCL_OK; } #if SQLITE_OS_UNIX #include <sys/time.h> #include <sys/resource.h> static int test_getrusage( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ char buf[1024]; struct rusage r; memset(&r, 0, sizeof(r)); getrusage(RUSAGE_SELF, &r); sprintf(buf, "ru_utime=%d.%06d ru_stime=%d.%06d ru_minflt=%d ru_majflt=%d", (int)r.ru_utime.tv_sec, (int)r.ru_utime.tv_usec, (int)r.ru_stime.tv_sec, (int)r.ru_stime.tv_usec, (int)r.ru_minflt, (int)r.ru_majflt ); Tcl_SetObjResult(interp, Tcl_NewStringObj(buf, -1)); return TCL_OK; } #endif #if SQLITE_OS_WIN /* ** Information passed from the main thread into the windows file locker ** background thread. */ struct win32FileLocker { |
︙ | ︙ | |||
6010 6011 6012 6013 6014 6015 6016 6017 6018 6019 6020 6021 6022 6023 | Tcl_AppendResult(interp, " ", aOpt[i].zOptName); } return TCL_ERROR; } sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS, db, mask); return TCL_OK; } /* ** Register commands with the TCL interpreter. */ int Sqlitetest1_Init(Tcl_Interp *interp){ extern int sqlite3_search_count; extern int sqlite3_found_count; | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 5966 5967 5968 5969 5970 5971 5972 5973 5974 5975 5976 5977 5978 5979 5980 5981 5982 5983 5984 5985 5986 5987 5988 5989 5990 5991 5992 5993 5994 5995 5996 5997 5998 5999 6000 6001 6002 6003 6004 6005 6006 6007 6008 6009 6010 6011 6012 6013 6014 6015 6016 6017 6018 6019 6020 6021 6022 6023 6024 6025 6026 6027 6028 6029 6030 6031 6032 6033 6034 6035 6036 6037 6038 6039 6040 6041 6042 | Tcl_AppendResult(interp, " ", aOpt[i].zOptName); } return TCL_ERROR; } sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS, db, mask); return TCL_OK; } typedef struct sqlite3_api_routines sqlite3_api_routines; /* ** load_static_extension DB NAME ... ** ** Load one or more statically linked extensions. */ static int tclLoadStaticExtensionCmd( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ 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_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_regexp_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_spellfix_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 }, { "fuzzer", sqlite3_fuzzer_init }, { "ieee754", sqlite3_ieee_init }, { "nextchar", sqlite3_nextchar_init }, { "regexp", sqlite3_regexp_init }, { "spellfix", sqlite3_spellfix_init }, { "wholenumber", sqlite3_wholenumber_init }, }; sqlite3 *db; const char *zName; int i, j, rc; char *zErrMsg = 0; if( objc<3 ){ Tcl_WrongNumArgs(interp, 1, objv, "DB NAME ..."); return TCL_ERROR; } if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; for(j=2; j<objc; j++){ zName = Tcl_GetString(objv[j]); 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; } rc = aExtension[i].pInit(db, &zErrMsg, 0); if( rc!=SQLITE_OK || zErrMsg ){ Tcl_AppendResult(interp, "initialization of ", zName, " failed: ", zErrMsg, (char*)0); sqlite3_free(zErrMsg); return TCL_ERROR; } } return TCL_OK; } /* ** Register commands with the TCL interpreter. */ int Sqlitetest1_Init(Tcl_Interp *interp){ extern int sqlite3_search_count; extern int sqlite3_found_count; |
︙ | ︙ | |||
6229 6230 6231 6232 6233 6234 6235 6236 6237 6238 6239 6240 6241 6242 | { "sqlite3_wal_checkpoint", test_wal_checkpoint, 0 }, { "sqlite3_wal_checkpoint_v2",test_wal_checkpoint_v2, 0 }, { "test_sqlite3_log", test_sqlite3_log, 0 }, #ifndef SQLITE_OMIT_EXPLAIN { "print_explain_query_plan", test_print_eqp, 0 }, #endif { "sqlite3_test_control", test_test_control }, }; static int bitmask_size = sizeof(Bitmask)*8; int i; extern int sqlite3_sync_count, sqlite3_fullsync_count; extern int sqlite3_opentemp_count; extern int sqlite3_like_count; extern int sqlite3_xferopt_count; | > > > > | 6248 6249 6250 6251 6252 6253 6254 6255 6256 6257 6258 6259 6260 6261 6262 6263 6264 6265 | { "sqlite3_wal_checkpoint", test_wal_checkpoint, 0 }, { "sqlite3_wal_checkpoint_v2",test_wal_checkpoint_v2, 0 }, { "test_sqlite3_log", test_sqlite3_log, 0 }, #ifndef SQLITE_OMIT_EXPLAIN { "print_explain_query_plan", test_print_eqp, 0 }, #endif { "sqlite3_test_control", test_test_control }, #if SQLITE_OS_UNIX { "getrusage", test_getrusage }, #endif { "load_static_extension", tclLoadStaticExtensionCmd }, }; static int bitmask_size = sizeof(Bitmask)*8; int i; extern int sqlite3_sync_count, sqlite3_fullsync_count; extern int sqlite3_opentemp_count; extern int sqlite3_like_count; extern int sqlite3_xferopt_count; |
︙ | ︙ |
Changes to src/test2.c.
︙ | ︙ | |||
15 16 17 18 19 20 21 | */ #include "sqliteInt.h" #include "tcl.h" #include <stdlib.h> #include <string.h> #include <ctype.h> | < < < < | < < < < < < < < < < < < < < < < < < < < < < < < | 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | */ #include "sqliteInt.h" #include "tcl.h" #include <stdlib.h> #include <string.h> #include <ctype.h> extern const char *sqlite3ErrName(int); /* ** Page size and reserved size used for testing. */ static int test_pagesize = 1024; /* |
︙ | ︙ | |||
83 84 85 86 87 88 89 | return TCL_ERROR; } if( Tcl_GetInt(interp, argv[2], &nPage) ) return TCL_ERROR; rc = sqlite3PagerOpen(sqlite3_vfs_find(0), &pPager, argv[1], 0, 0, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_MAIN_DB, pager_test_reiniter); if( rc!=SQLITE_OK ){ | | | 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 | return TCL_ERROR; } if( Tcl_GetInt(interp, argv[2], &nPage) ) return TCL_ERROR; rc = sqlite3PagerOpen(sqlite3_vfs_find(0), &pPager, argv[1], 0, 0, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_MAIN_DB, pager_test_reiniter); if( rc!=SQLITE_OK ){ Tcl_AppendResult(interp, sqlite3ErrName(rc), 0); return TCL_ERROR; } sqlite3PagerSetCachesize(pPager, nPage); pageSize = test_pagesize; sqlite3PagerSetPagesize(pPager, &pageSize, -1); sqlite3_snprintf(sizeof(zBuf),zBuf,"%p",pPager); Tcl_AppendResult(interp, zBuf, 0); |
︙ | ︙ | |||
115 116 117 118 119 120 121 | Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " ID\"", 0); return TCL_ERROR; } pPager = sqlite3TestTextToPtr(argv[1]); rc = sqlite3PagerClose(pPager); if( rc!=SQLITE_OK ){ | | | 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 | Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " ID\"", 0); return TCL_ERROR; } pPager = sqlite3TestTextToPtr(argv[1]); rc = sqlite3PagerClose(pPager); if( rc!=SQLITE_OK ){ Tcl_AppendResult(interp, sqlite3ErrName(rc), 0); return TCL_ERROR; } return TCL_OK; } /* ** Usage: pager_rollback ID |
︙ | ︙ | |||
142 143 144 145 146 147 148 | Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " ID\"", 0); return TCL_ERROR; } pPager = sqlite3TestTextToPtr(argv[1]); rc = sqlite3PagerRollback(pPager); if( rc!=SQLITE_OK ){ | | | 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 | Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " ID\"", 0); return TCL_ERROR; } pPager = sqlite3TestTextToPtr(argv[1]); rc = sqlite3PagerRollback(pPager); if( rc!=SQLITE_OK ){ Tcl_AppendResult(interp, sqlite3ErrName(rc), 0); return TCL_ERROR; } return TCL_OK; } /* ** Usage: pager_commit ID |
︙ | ︙ | |||
169 170 171 172 173 174 175 | Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " ID\"", 0); return TCL_ERROR; } pPager = sqlite3TestTextToPtr(argv[1]); rc = sqlite3PagerCommitPhaseOne(pPager, 0, 0); if( rc!=SQLITE_OK ){ | | | | 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 | Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " ID\"", 0); return TCL_ERROR; } pPager = sqlite3TestTextToPtr(argv[1]); rc = sqlite3PagerCommitPhaseOne(pPager, 0, 0); if( rc!=SQLITE_OK ){ Tcl_AppendResult(interp, sqlite3ErrName(rc), 0); return TCL_ERROR; } rc = sqlite3PagerCommitPhaseTwo(pPager); if( rc!=SQLITE_OK ){ Tcl_AppendResult(interp, sqlite3ErrName(rc), 0); return TCL_ERROR; } return TCL_OK; } /* ** Usage: pager_stmt_begin ID |
︙ | ︙ | |||
201 202 203 204 205 206 207 | Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " ID\"", 0); return TCL_ERROR; } pPager = sqlite3TestTextToPtr(argv[1]); rc = sqlite3PagerOpenSavepoint(pPager, 1); if( rc!=SQLITE_OK ){ | | | 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 | Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " ID\"", 0); return TCL_ERROR; } pPager = sqlite3TestTextToPtr(argv[1]); rc = sqlite3PagerOpenSavepoint(pPager, 1); if( rc!=SQLITE_OK ){ Tcl_AppendResult(interp, sqlite3ErrName(rc), 0); return TCL_ERROR; } return TCL_OK; } /* ** Usage: pager_stmt_rollback ID |
︙ | ︙ | |||
229 230 231 232 233 234 235 | " ID\"", 0); return TCL_ERROR; } pPager = sqlite3TestTextToPtr(argv[1]); rc = sqlite3PagerSavepoint(pPager, SAVEPOINT_ROLLBACK, 0); sqlite3PagerSavepoint(pPager, SAVEPOINT_RELEASE, 0); if( rc!=SQLITE_OK ){ | | | 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 | " ID\"", 0); return TCL_ERROR; } pPager = sqlite3TestTextToPtr(argv[1]); rc = sqlite3PagerSavepoint(pPager, SAVEPOINT_ROLLBACK, 0); sqlite3PagerSavepoint(pPager, SAVEPOINT_RELEASE, 0); if( rc!=SQLITE_OK ){ Tcl_AppendResult(interp, sqlite3ErrName(rc), 0); return TCL_ERROR; } return TCL_OK; } /* ** Usage: pager_stmt_commit ID |
︙ | ︙ | |||
256 257 258 259 260 261 262 | Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " ID\"", 0); return TCL_ERROR; } pPager = sqlite3TestTextToPtr(argv[1]); rc = sqlite3PagerSavepoint(pPager, SAVEPOINT_RELEASE, 0); if( rc!=SQLITE_OK ){ | | | 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 | Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " ID\"", 0); return TCL_ERROR; } pPager = sqlite3TestTextToPtr(argv[1]); rc = sqlite3PagerSavepoint(pPager, SAVEPOINT_RELEASE, 0); if( rc!=SQLITE_OK ){ Tcl_AppendResult(interp, sqlite3ErrName(rc), 0); return TCL_ERROR; } return TCL_OK; } /* ** Usage: pager_stats ID |
︙ | ︙ | |||
349 350 351 352 353 354 355 | pPager = sqlite3TestTextToPtr(argv[1]); if( Tcl_GetInt(interp, argv[2], &pgno) ) return TCL_ERROR; rc = sqlite3PagerSharedLock(pPager); if( rc==SQLITE_OK ){ rc = sqlite3PagerGet(pPager, pgno, &pPage); } if( rc!=SQLITE_OK ){ | | | 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 | pPager = sqlite3TestTextToPtr(argv[1]); if( Tcl_GetInt(interp, argv[2], &pgno) ) return TCL_ERROR; rc = sqlite3PagerSharedLock(pPager); if( rc==SQLITE_OK ){ rc = sqlite3PagerGet(pPager, pgno, &pPage); } if( rc!=SQLITE_OK ){ Tcl_AppendResult(interp, sqlite3ErrName(rc), 0); return TCL_ERROR; } sqlite3_snprintf(sizeof(zBuf),zBuf,"%p",pPage); Tcl_AppendResult(interp, zBuf, 0); return TCL_OK; } |
︙ | ︙ | |||
503 504 505 506 507 508 509 | Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " PAGE DATA\"", 0); return TCL_ERROR; } pPage = (DbPage *)sqlite3TestTextToPtr(argv[1]); rc = sqlite3PagerWrite(pPage); if( rc!=SQLITE_OK ){ | | | 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 | Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " PAGE DATA\"", 0); return TCL_ERROR; } pPage = (DbPage *)sqlite3TestTextToPtr(argv[1]); rc = sqlite3PagerWrite(pPage); if( rc!=SQLITE_OK ){ Tcl_AppendResult(interp, sqlite3ErrName(rc), 0); return TCL_ERROR; } pData = sqlite3PagerGetData(pPage); strncpy(pData, argv[2], test_pagesize-1); pData[test_pagesize-1] = 0; return TCL_OK; } |
︙ | ︙ | |||
552 553 554 555 556 557 558 | if( zFile==0 ) return TCL_ERROR; memcpy(zFile, argv[2], nFile+1); zFile[nFile+1] = 0; rc = sqlite3OsOpenMalloc(pVfs, zFile, &fd, (SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE|SQLITE_OPEN_MAIN_DB), 0 ); if( rc ){ | | | | 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 | if( zFile==0 ) return TCL_ERROR; memcpy(zFile, argv[2], nFile+1); zFile[nFile+1] = 0; rc = sqlite3OsOpenMalloc(pVfs, zFile, &fd, (SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE|SQLITE_OPEN_MAIN_DB), 0 ); if( rc ){ Tcl_AppendResult(interp, "open failed: ", sqlite3ErrName(rc), 0); sqlite3_free(zFile); return TCL_ERROR; } offset = n; offset *= 1024*1024; rc = sqlite3OsWrite(fd, "Hello, World!", 14, offset); sqlite3OsCloseFree(fd); sqlite3_free(zFile); if( rc ){ Tcl_AppendResult(interp, "write failed: ", sqlite3ErrName(rc), 0); return TCL_ERROR; } return TCL_OK; } #endif |
︙ | ︙ |
Changes to src/test3.c.
︙ | ︙ | |||
15 16 17 18 19 20 21 | */ #include "sqliteInt.h" #include "btreeInt.h" #include "tcl.h" #include <stdlib.h> #include <string.h> | < < < < | < < < < < < < < < < < < < < < < < < < < | 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | */ #include "sqliteInt.h" #include "btreeInt.h" #include "tcl.h" #include <stdlib.h> #include <string.h> extern const char *sqlite3ErrName(int); /* ** A bogus sqlite3 connection structure for use in the btree ** tests. */ static sqlite3 sDb; static int nRefSqlite3 = 0; |
︙ | ︙ | |||
85 86 87 88 89 90 91 | if( zFilename==0 ) return TCL_ERROR; memcpy(zFilename, argv[1], n+1); zFilename[n+1] = 0; rc = sqlite3BtreeOpen(sDb.pVfs, zFilename, &sDb, &pBt, 0, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_MAIN_DB); sqlite3_free(zFilename); if( rc!=SQLITE_OK ){ | | | 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 | if( zFilename==0 ) return TCL_ERROR; memcpy(zFilename, argv[1], n+1); zFilename[n+1] = 0; rc = sqlite3BtreeOpen(sDb.pVfs, zFilename, &sDb, &pBt, 0, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_MAIN_DB); sqlite3_free(zFilename); if( rc!=SQLITE_OK ){ Tcl_AppendResult(interp, sqlite3ErrName(rc), 0); return TCL_ERROR; } sqlite3BtreeSetCacheSize(pBt, nCache); sqlite3_snprintf(sizeof(zBuf), zBuf,"%p", pBt); Tcl_AppendResult(interp, zBuf, 0); return TCL_OK; } |
︙ | ︙ | |||
115 116 117 118 119 120 121 | Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " ID\"", 0); return TCL_ERROR; } pBt = sqlite3TestTextToPtr(argv[1]); rc = sqlite3BtreeClose(pBt); if( rc!=SQLITE_OK ){ | | | 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 | Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " ID\"", 0); return TCL_ERROR; } pBt = sqlite3TestTextToPtr(argv[1]); rc = sqlite3BtreeClose(pBt); if( rc!=SQLITE_OK ){ Tcl_AppendResult(interp, sqlite3ErrName(rc), 0); return TCL_ERROR; } nRefSqlite3--; if( nRefSqlite3==0 ){ sqlite3_mutex_leave(sDb.mutex); sqlite3_mutex_free(sDb.mutex); sDb.mutex = 0; |
︙ | ︙ | |||
152 153 154 155 156 157 158 | return TCL_ERROR; } pBt = sqlite3TestTextToPtr(argv[1]); sqlite3BtreeEnter(pBt); rc = sqlite3BtreeBeginTrans(pBt, 1); sqlite3BtreeLeave(pBt); if( rc!=SQLITE_OK ){ | | | 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 | return TCL_ERROR; } pBt = sqlite3TestTextToPtr(argv[1]); sqlite3BtreeEnter(pBt); rc = sqlite3BtreeBeginTrans(pBt, 1); sqlite3BtreeLeave(pBt); if( rc!=SQLITE_OK ){ Tcl_AppendResult(interp, sqlite3ErrName(rc), 0); return TCL_ERROR; } return TCL_OK; } /* ** Usage: btree_pager_stats ID |
︙ | ︙ | |||
246 247 248 249 250 251 252 | #endif if( rc==SQLITE_OK ){ rc = sqlite3BtreeCursor(pBt, iTable, wrFlag, 0, pCur); } sqlite3BtreeLeave(pBt); if( rc ){ ckfree((char *)pCur); | | | 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 | #endif if( rc==SQLITE_OK ){ rc = sqlite3BtreeCursor(pBt, iTable, wrFlag, 0, pCur); } sqlite3BtreeLeave(pBt); if( rc ){ ckfree((char *)pCur); Tcl_AppendResult(interp, sqlite3ErrName(rc), 0); return TCL_ERROR; } sqlite3_snprintf(sizeof(zBuf), zBuf,"%p", pCur); Tcl_AppendResult(interp, zBuf, 0); return SQLITE_OK; } |
︙ | ︙ | |||
281 282 283 284 285 286 287 | pCur = sqlite3TestTextToPtr(argv[1]); pBt = pCur->pBtree; sqlite3BtreeEnter(pBt); rc = sqlite3BtreeCloseCursor(pCur); sqlite3BtreeLeave(pBt); ckfree((char *)pCur); if( rc ){ | | | 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 | pCur = sqlite3TestTextToPtr(argv[1]); pBt = pCur->pBtree; sqlite3BtreeEnter(pBt); rc = sqlite3BtreeCloseCursor(pCur); sqlite3BtreeLeave(pBt); ckfree((char *)pCur); if( rc ){ Tcl_AppendResult(interp, sqlite3ErrName(rc), 0); return TCL_ERROR; } return SQLITE_OK; } /* ** Usage: btree_next ID |
︙ | ︙ | |||
315 316 317 318 319 320 321 | return TCL_ERROR; } pCur = sqlite3TestTextToPtr(argv[1]); sqlite3BtreeEnter(pCur->pBtree); rc = sqlite3BtreeNext(pCur, &res); sqlite3BtreeLeave(pCur->pBtree); if( rc ){ | | | 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 | return TCL_ERROR; } pCur = sqlite3TestTextToPtr(argv[1]); sqlite3BtreeEnter(pCur->pBtree); rc = sqlite3BtreeNext(pCur, &res); sqlite3BtreeLeave(pCur->pBtree); if( rc ){ Tcl_AppendResult(interp, sqlite3ErrName(rc), 0); return TCL_ERROR; } sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",res); Tcl_AppendResult(interp, zBuf, 0); return SQLITE_OK; } |
︙ | ︙ | |||
350 351 352 353 354 355 356 | return TCL_ERROR; } pCur = sqlite3TestTextToPtr(argv[1]); sqlite3BtreeEnter(pCur->pBtree); rc = sqlite3BtreeFirst(pCur, &res); sqlite3BtreeLeave(pCur->pBtree); if( rc ){ | | | 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 | return TCL_ERROR; } pCur = sqlite3TestTextToPtr(argv[1]); sqlite3BtreeEnter(pCur->pBtree); rc = sqlite3BtreeFirst(pCur, &res); sqlite3BtreeLeave(pCur->pBtree); if( rc ){ Tcl_AppendResult(interp, sqlite3ErrName(rc), 0); return TCL_ERROR; } sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",res); Tcl_AppendResult(interp, zBuf, 0); return SQLITE_OK; } |
︙ | ︙ |
Changes to src/test4.c.
︙ | ︙ | |||
16 17 18 19 20 21 22 23 24 25 26 27 28 29 | #if SQLITE_OS_UNIX && SQLITE_THREADSAFE #include <stdlib.h> #include <string.h> #include <pthread.h> #include <sched.h> #include <ctype.h> /* ** Each thread is controlled by an instance of the following ** structure. */ typedef struct Thread Thread; struct Thread { /* The first group of fields are writable by the master and read-only | > > | 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | #if SQLITE_OS_UNIX && SQLITE_THREADSAFE #include <stdlib.h> #include <string.h> #include <pthread.h> #include <sched.h> #include <ctype.h> extern const char *sqlite3ErrName(int); /* ** Each thread is controlled by an instance of the following ** structure. */ typedef struct Thread Thread; struct Thread { /* The first group of fields are writable by the master and read-only |
︙ | ︙ | |||
368 369 370 371 372 373 374 | i = parse_thread_id(interp, argv[1]); if( i<0 ) return TCL_ERROR; if( !threadset[i].busy ){ Tcl_AppendResult(interp, "no such thread", 0); return TCL_ERROR; } thread_wait(&threadset[i]); | | < < < < < < < < < < < < < < < < < < < < < < < < < < < | 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 | i = parse_thread_id(interp, argv[1]); if( i<0 ) return TCL_ERROR; if( !threadset[i].busy ){ Tcl_AppendResult(interp, "no such thread", 0); return TCL_ERROR; } thread_wait(&threadset[i]); zName = sqlite3ErrName(threadset[i].rc); Tcl_AppendResult(interp, zName, 0); return TCL_OK; } /* ** Usage: thread_error ID ** |
︙ | ︙ |
Changes to src/test6.c.
︙ | ︙ | |||
83 84 85 86 87 88 89 | ** If the IOCAP_ATOMIC flag is set, then option (3) above is ** never selected. ** ** If the IOCAP_ATOMIC512 flag is set, and the WriteBuffer represents ** an aligned write() of an integer number of 512 byte regions, then ** option (3) above is never selected. Instead, each 512 byte region ** is either correctly written or left completely untouched. Similar | | | 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 | ** If the IOCAP_ATOMIC flag is set, then option (3) above is ** never selected. ** ** If the IOCAP_ATOMIC512 flag is set, and the WriteBuffer represents ** an aligned write() of an integer number of 512 byte regions, then ** option (3) above is never selected. Instead, each 512 byte region ** is either correctly written or left completely untouched. Similar ** logic governs the behavior if any of the other ATOMICXXX flags ** is set. ** ** If either the IOCAP_SAFEAPPEND or IOCAP_SEQUENTIAL flags are set ** and a crash is being simulated, then an entry of the write-list is ** selected at random. Everything in the list after the selected entry ** is discarded before processing begins. ** |
︙ | ︙ |
Changes to src/test7.c.
︙ | ︙ | |||
372 373 374 375 376 377 378 379 380 381 382 383 384 385 | Tcl_AppendResult(interp, "column number out of range", 0); return TCL_ERROR; } Tcl_AppendResult(interp, threadset[i].colv[n], 0); return TCL_OK; } /* ** Usage: client_result ID ** ** Wait on the most recent operation to complete, then return the ** result code from that operation. */ static int tcl_client_result( | > > | 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 | Tcl_AppendResult(interp, "column number out of range", 0); return TCL_ERROR; } Tcl_AppendResult(interp, threadset[i].colv[n], 0); return TCL_OK; } extern const char *sqlite3ErrName(int); /* ** Usage: client_result ID ** ** Wait on the most recent operation to complete, then return the ** result code from that operation. */ static int tcl_client_result( |
︙ | ︙ | |||
399 400 401 402 403 404 405 | i = parse_client_id(interp, argv[1]); if( i<0 ) return TCL_ERROR; if( !threadset[i].busy ){ Tcl_AppendResult(interp, "no such thread", 0); return TCL_ERROR; } client_wait(&threadset[i]); | | < < < < < < < < < < < < < < < < < < < < < < < < < < < | 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 | i = parse_client_id(interp, argv[1]); if( i<0 ) return TCL_ERROR; if( !threadset[i].busy ){ Tcl_AppendResult(interp, "no such thread", 0); return TCL_ERROR; } client_wait(&threadset[i]); zName = sqlite3ErrName(threadset[i].rc); Tcl_AppendResult(interp, zName, 0); return TCL_OK; } /* ** Usage: client_error ID ** |
︙ | ︙ |
Changes to src/test8.c.
︙ | ︙ | |||
1296 1297 1298 1299 1300 1301 1302 | echoRollbackTo }; /* ** Decode a pointer to an sqlite3 object. */ extern int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb); | | | 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 | echoRollbackTo }; /* ** Decode a pointer to an sqlite3 object. */ extern int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb); extern const char *sqlite3ErrName(int); static void moduleDestroy(void *p){ sqlite3_free(p); } /* ** Register the echo virtual table module. |
︙ | ︙ | |||
1336 1337 1338 1339 1340 1341 1342 | pMod = sqlite3_malloc(sizeof(EchoModule)); pMod->interp = interp; rc = sqlite3_create_module_v2(db, "echo_v2", &echoModuleV2, (void*)pMod, moduleDestroy ); } | | | 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 | pMod = sqlite3_malloc(sizeof(EchoModule)); pMod->interp = interp; rc = sqlite3_create_module_v2(db, "echo_v2", &echoModuleV2, (void*)pMod, moduleDestroy ); } Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_STATIC); return TCL_OK; } /* ** Tcl interface to sqlite3_declare_vtab, invoked as follows from Tcl: ** ** sqlite3_declare_vtab DB SQL |
︙ | ︙ | |||
1366 1367 1368 1369 1370 1371 1372 | if( rc!=SQLITE_OK ){ Tcl_SetResult(interp, (char *)sqlite3_errmsg(db), TCL_VOLATILE); return TCL_ERROR; } return TCL_OK; } | < < < < < < < < < < < < < < < < < < < < < < < < | 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 | if( rc!=SQLITE_OK ){ Tcl_SetResult(interp, (char *)sqlite3_errmsg(db), TCL_VOLATILE); return TCL_ERROR; } return TCL_OK; } #endif /* ifndef SQLITE_OMIT_VIRTUALTABLE */ /* ** Register commands with the TCL interpreter. */ int Sqlitetest8_Init(Tcl_Interp *interp){ #ifndef SQLITE_OMIT_VIRTUALTABLE static struct { char *zName; Tcl_ObjCmdProc *xProc; void *clientData; } aObjCmd[] = { { "register_echo_module", register_echo_module, 0 }, { "sqlite3_declare_vtab", declare_vtab, 0 }, }; int i; for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){ Tcl_CreateObjCommand(interp, aObjCmd[i].zName, aObjCmd[i].xProc, aObjCmd[i].clientData, 0); } #endif return TCL_OK; } |
Changes to src/test_async.c.
︙ | ︙ | |||
19 20 21 22 23 24 25 | #ifdef SQLITE_ENABLE_ASYNCIO #include "sqlite3async.h" #include "sqlite3.h" #include <assert.h> | | | | 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | #ifdef SQLITE_ENABLE_ASYNCIO #include "sqlite3async.h" #include "sqlite3.h" #include <assert.h> /* From main.c */ extern const char *sqlite3ErrName(int); struct TestAsyncGlobal { int isInstalled; /* True when async VFS is installed */ } testasync_g = { 0 }; TCL_DECLARE_MUTEX(testasync_g_writerMutex); |
︙ | ︙ | |||
56 57 58 59 60 61 62 | } if( Tcl_GetBooleanFromObj(interp, objv[2], &isDefault) ){ return TCL_ERROR; } rc = sqlite3async_initialize(zParent, isDefault); if( rc!=SQLITE_OK ){ | | | 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | } if( Tcl_GetBooleanFromObj(interp, objv[2], &isDefault) ){ return TCL_ERROR; } rc = sqlite3async_initialize(zParent, isDefault); if( rc!=SQLITE_OK ){ Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1)); return TCL_ERROR; } return TCL_OK; } /* ** sqlite3async_shutdown |
︙ | ︙ | |||
204 205 206 207 208 209 210 | rc = sqlite3async_control( eOpt==SQLITEASYNC_HALT ? SQLITEASYNC_GET_HALT : eOpt==SQLITEASYNC_DELAY ? SQLITEASYNC_GET_DELAY : SQLITEASYNC_GET_LOCKFILES, &iVal); } if( rc!=SQLITE_OK ){ | | | 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 | rc = sqlite3async_control( eOpt==SQLITEASYNC_HALT ? SQLITEASYNC_GET_HALT : eOpt==SQLITEASYNC_DELAY ? SQLITEASYNC_GET_DELAY : SQLITEASYNC_GET_LOCKFILES, &iVal); } if( rc!=SQLITE_OK ){ Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1)); return TCL_ERROR; } if( eOpt==SQLITEASYNC_HALT ){ Tcl_SetObjResult(interp, Tcl_NewStringObj(az[iVal], -1)); }else{ Tcl_SetObjResult(interp, Tcl_NewIntObj(iVal)); |
︙ | ︙ |
Changes to src/test_autoext.c.
︙ | ︙ | |||
11 12 13 14 15 16 17 | ************************************************************************* ** Test extension for testing the sqlite3_auto_extension() function. */ #include "tcl.h" #include "sqlite3ext.h" #ifndef SQLITE_OMIT_LOAD_EXTENSION | | | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | ************************************************************************* ** Test extension for testing the sqlite3_auto_extension() function. */ #include "tcl.h" #include "sqlite3ext.h" #ifndef SQLITE_OMIT_LOAD_EXTENSION SQLITE_EXTENSION_INIT1 /* ** The sqr() SQL function returns the square of its input value. */ static void sqrFunc( sqlite3_context *context, int argc, |
︙ | ︙ |
Changes to src/test_backup.c.
︙ | ︙ | |||
12 13 14 15 16 17 18 19 20 | ** This file contains test logic for the sqlite3_backup() interface. ** */ #include "tcl.h" #include <sqlite3.h> #include <assert.h> /* These functions are implemented in test1.c. */ | > > > | < | 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | ** This file contains test logic for the sqlite3_backup() interface. ** */ #include "tcl.h" #include <sqlite3.h> #include <assert.h> /* These functions are implemented in main.c. */ extern const char *sqlite3ErrName(int); /* These functions are implemented in test1.c. */ extern int getDbPointer(Tcl_Interp *, const char *, sqlite3 **); static int backupTestCmd( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const*objv ){ |
︙ | ︙ | |||
66 67 68 69 70 71 72 | zCmdName = Tcl_GetString(objv[0]); Tcl_GetCommandInfo(interp, zCmdName, &cmdInfo); cmdInfo.deleteProc = 0; Tcl_SetCommandInfo(interp, zCmdName, &cmdInfo); Tcl_DeleteCommand(interp, zCmdName); rc = sqlite3_backup_finish(p); | | | | 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 | zCmdName = Tcl_GetString(objv[0]); Tcl_GetCommandInfo(interp, zCmdName, &cmdInfo); cmdInfo.deleteProc = 0; Tcl_SetCommandInfo(interp, zCmdName, &cmdInfo); Tcl_DeleteCommand(interp, zCmdName); rc = sqlite3_backup_finish(p); Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_STATIC); break; } case BACKUP_STEP: { int nPage; if( TCL_OK!=Tcl_GetIntFromObj(interp, objv[2], &nPage) ){ return TCL_ERROR; } rc = sqlite3_backup_step(p, nPage); Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_STATIC); break; } case BACKUP_REMAINING: Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_backup_remaining(p))); break; |
︙ | ︙ |
Changes to src/test_config.c.
︙ | ︙ | |||
53 54 55 56 57 58 59 | #ifdef SQLITE_CASE_SENSITIVE_LIKE Tcl_SetVar2(interp, "sqlite_options","casesensitivelike","1",TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options","casesensitivelike","0",TCL_GLOBAL_ONLY); #endif | | | 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | #ifdef SQLITE_CASE_SENSITIVE_LIKE Tcl_SetVar2(interp, "sqlite_options","casesensitivelike","1",TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options","casesensitivelike","0",TCL_GLOBAL_ONLY); #endif #if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT Tcl_SetVar2(interp, "sqlite_options", "curdir", "1", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "curdir", "0", TCL_GLOBAL_ONLY); #endif #ifdef SQLITE_DEBUG Tcl_SetVar2(interp, "sqlite_options", "debug", "1", TCL_GLOBAL_ONLY); |
︙ | ︙ | |||
82 83 84 85 86 87 88 89 90 91 92 93 94 95 | #endif #ifdef SQLITE_DISABLE_LFS Tcl_SetVar2(interp, "sqlite_options", "lfs", "0", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "lfs", "1", TCL_GLOBAL_ONLY); #endif #if 1 /* def SQLITE_MEMDEBUG */ Tcl_SetVar2(interp, "sqlite_options", "memdebug", "1", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "memdebug", "0", TCL_GLOBAL_ONLY); #endif | > > > > > > | 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 | #endif #ifdef SQLITE_DISABLE_LFS Tcl_SetVar2(interp, "sqlite_options", "lfs", "0", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "lfs", "1", TCL_GLOBAL_ONLY); #endif #if SQLITE_MAX_MMAP_SIZE>0 Tcl_SetVar2(interp, "sqlite_options", "mmap", "1", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "mmap", "0", TCL_GLOBAL_ONLY); #endif #if 1 /* def SQLITE_MEMDEBUG */ Tcl_SetVar2(interp, "sqlite_options", "memdebug", "1", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "memdebug", "0", TCL_GLOBAL_ONLY); #endif |
︙ | ︙ | |||
391 392 393 394 395 396 397 | #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT Tcl_SetVar2(interp, "sqlite_options", "memorymanage", "1", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "memorymanage", "0", TCL_GLOBAL_ONLY); #endif | < < < < | 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 | #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT Tcl_SetVar2(interp, "sqlite_options", "memorymanage", "1", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "memorymanage", "0", TCL_GLOBAL_ONLY); #endif Tcl_SetVar2(interp, "sqlite_options", "mergesort", "1", TCL_GLOBAL_ONLY); #ifdef SQLITE_OMIT_OR_OPTIMIZATION Tcl_SetVar2(interp, "sqlite_options", "or_opt", "0", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "or_opt", "1", TCL_GLOBAL_ONLY); #endif |
︙ | ︙ |
Changes to src/test_fs.c.
︙ | ︙ | |||
95 96 97 98 99 100 101 | if( argc!=4 ){ *pzErr = sqlite3_mprintf("wrong number of arguments"); return SQLITE_ERROR; } zTbl = argv[3]; | | | 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 | if( argc!=4 ){ *pzErr = sqlite3_mprintf("wrong number of arguments"); return SQLITE_ERROR; } zTbl = argv[3]; nByte = sizeof(fs_vtab) + (int)strlen(zTbl) + 1 + (int)strlen(zDb) + 1; pVtab = (fs_vtab *)sqlite3MallocZero( nByte ); if( !pVtab ) return SQLITE_NOMEM; pVtab->zTbl = (char *)&pVtab[1]; pVtab->zDb = &pVtab->zTbl[strlen(zTbl)+1]; pVtab->db = db; memcpy(pVtab->zTbl, zTbl, strlen(zTbl)); |
︙ | ︙ |
Changes to src/test_intarray.c.
︙ | ︙ | |||
274 275 276 277 278 279 280 | /* ** Routines to encode and decode pointers */ extern int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb); extern void *sqlite3TestTextToPtr(const char*); extern int sqlite3TestMakePointerStr(Tcl_Interp*, char *zPtr, void*); | | | 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 | /* ** Routines to encode and decode pointers */ extern int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb); extern void *sqlite3TestTextToPtr(const char*); extern int sqlite3TestMakePointerStr(Tcl_Interp*, char *zPtr, void*); extern const char *sqlite3ErrName(int); /* ** sqlite3_intarray_create DB NAME ** ** Invoke the sqlite3_intarray_create interface. A string that becomes ** the first parameter to sqlite3_intarray_bind. */ |
︙ | ︙ | |||
305 306 307 308 309 310 311 | if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; zName = Tcl_GetString(objv[2]); #ifndef SQLITE_OMIT_VIRTUALTABLE rc = sqlite3_intarray_create(db, zName, &pArray); #endif if( rc!=SQLITE_OK ){ assert( pArray==0 ); | | | 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 | if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; zName = Tcl_GetString(objv[2]); #ifndef SQLITE_OMIT_VIRTUALTABLE rc = sqlite3_intarray_create(db, zName, &pArray); #endif if( rc!=SQLITE_OK ){ assert( pArray==0 ); Tcl_AppendResult(interp, sqlite3ErrName(rc), (char*)0); return TCL_ERROR; } sqlite3TestMakePointerStr(interp, zPtr, pArray); Tcl_AppendResult(interp, zPtr, (char*)0); return TCL_OK; } |
︙ | ︙ | |||
348 349 350 351 352 353 354 | for(i=0; i<n; i++){ Tcl_WideInt x = 0; Tcl_GetWideIntFromObj(0, objv[i+2], &x); a[i] = x; } rc = sqlite3_intarray_bind(pArray, n, a, sqlite3_free); if( rc!=SQLITE_OK ){ | | | 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 | for(i=0; i<n; i++){ Tcl_WideInt x = 0; Tcl_GetWideIntFromObj(0, objv[i+2], &x); a[i] = x; } rc = sqlite3_intarray_bind(pArray, n, a, sqlite3_free); if( rc!=SQLITE_OK ){ Tcl_AppendResult(interp, sqlite3ErrName(rc), (char*)0); return TCL_ERROR; } #endif return TCL_OK; } /* |
︙ | ︙ |
Changes to src/test_malloc.c.
︙ | ︙ | |||
230 231 232 233 234 235 236 | } return rc; } #ifdef SQLITE_TEST /* | | | | | 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 | } return rc; } #ifdef SQLITE_TEST /* ** This function is implemented in main.c. Returns a pointer to a static ** buffer containing the symbolic SQLite error code that corresponds to ** the least-significant 8-bits of the integer passed as an argument. ** For example: ** ** sqlite3ErrName(1) -> "SQLITE_ERROR" */ extern const char *sqlite3ErrName(int); /* ** Transform pointers to text and back again */ static void pointerToText(void *p, char *z){ static const char zHex[] = "0123456789abcdef"; int i, k; |
︙ | ︙ | |||
1068 1069 1070 1071 1072 1073 1074 | Tcl_Obj *CONST objv[] ){ int rc; int sz, cnt; sqlite3 *db; int bufid; static char azBuf[2][10000]; | | | 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 | Tcl_Obj *CONST objv[] ){ int rc; int sz, cnt; sqlite3 *db; int bufid; static char azBuf[2][10000]; extern int getDbPointer(Tcl_Interp*, const char*, sqlite3**); if( objc!=5 ){ Tcl_WrongNumArgs(interp, 1, objv, "BUFID SIZE COUNT"); return TCL_ERROR; } if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; if( Tcl_GetIntFromObj(interp, objv[2], &bufid) ) return TCL_ERROR; if( Tcl_GetIntFromObj(interp, objv[3], &sz) ) return TCL_ERROR; |
︙ | ︙ | |||
1122 1123 1124 1125 1126 1127 1128 | zBuf = 0; rc = sqlite3_config(SQLITE_CONFIG_HEAP, (void*)0, 0, 0); }else{ zBuf = realloc(zBuf, nByte); rc = sqlite3_config(SQLITE_CONFIG_HEAP, zBuf, nByte, nMinAlloc); } | | | | 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 | zBuf = 0; rc = sqlite3_config(SQLITE_CONFIG_HEAP, (void*)0, 0, 0); }else{ zBuf = realloc(zBuf, nByte); rc = sqlite3_config(SQLITE_CONFIG_HEAP, zBuf, nByte, nMinAlloc); } Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE); return TCL_OK; } /* ** Usage: sqlite3_config_error [DB] ** ** Invoke sqlite3_config() or sqlite3_db_config() with invalid ** opcodes and verify that they return errors. */ static int test_config_error( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3 *db; extern int getDbPointer(Tcl_Interp*, const char*, sqlite3**); if( objc!=2 && objc!=1 ){ Tcl_WrongNumArgs(interp, 1, objv, "[DB]"); return TCL_ERROR; } if( objc==2 ){ if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; |
︙ | ︙ | |||
1188 1189 1190 1191 1192 1193 1194 | return TCL_ERROR; } if( Tcl_GetBooleanFromObj(interp, objv[1], &bOpenUri) ){ return TCL_ERROR; } rc = sqlite3_config(SQLITE_CONFIG_URI, bOpenUri); | | | 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 | return TCL_ERROR; } if( Tcl_GetBooleanFromObj(interp, objv[1], &bOpenUri) ){ return TCL_ERROR; } rc = sqlite3_config(SQLITE_CONFIG_URI, bOpenUri); Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE); return TCL_OK; } /* ** Usage: sqlite3_config_cis BOOLEAN ** |
︙ | ︙ | |||
1217 1218 1219 1220 1221 1222 1223 | return TCL_ERROR; } if( Tcl_GetBooleanFromObj(interp, objv[1], &bUseCis) ){ return TCL_ERROR; } rc = sqlite3_config(SQLITE_CONFIG_COVERING_INDEX_SCAN, bUseCis); | | | 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 | return TCL_ERROR; } if( Tcl_GetBooleanFromObj(interp, objv[1], &bUseCis) ){ return TCL_ERROR; } rc = sqlite3_config(SQLITE_CONFIG_COVERING_INDEX_SCAN, bUseCis); Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE); return TCL_OK; } /* ** Usage: sqlite3_dump_memsys3 FILENAME ** sqlite3_dump_memsys5 FILENAME |
︙ | ︙ | |||
1331 1332 1333 1334 1335 1336 1337 | int objc, Tcl_Obj *CONST objv[] ){ int rc, iValue, mxValue; int i, op, resetFlag; const char *zOpName; sqlite3 *db; | | | 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 | int objc, Tcl_Obj *CONST objv[] ){ int rc, iValue, mxValue; int i, op, resetFlag; const char *zOpName; sqlite3 *db; extern int getDbPointer(Tcl_Interp*, const char*, sqlite3**); static const struct { const char *zName; int op; } aOp[] = { { "LOOKASIDE_USED", SQLITE_DBSTATUS_LOOKASIDE_USED }, { "CACHE_USED", SQLITE_DBSTATUS_CACHE_USED }, { "SCHEMA_USED", SQLITE_DBSTATUS_SCHEMA_USED }, |
︙ | ︙ | |||
1397 1398 1399 1400 1401 1402 1403 | Tcl_WrongNumArgs(interp, 1, objv, "BOOLEAN"); return TCL_ERROR; } if( TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[1], &isInstall) ){ return TCL_ERROR; } rc = faultsimInstall(isInstall); | | | | 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 | Tcl_WrongNumArgs(interp, 1, objv, "BOOLEAN"); return TCL_ERROR; } if( TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[1], &isInstall) ){ return TCL_ERROR; } rc = faultsimInstall(isInstall); Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE); return TCL_OK; } /* ** sqlite3_install_memsys3 */ static int test_install_memsys3( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ int rc = SQLITE_MISUSE; #ifdef SQLITE_ENABLE_MEMSYS3 const sqlite3_mem_methods *sqlite3MemGetMemsys3(void); rc = sqlite3_config(SQLITE_CONFIG_MALLOC, sqlite3MemGetMemsys3()); #endif Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE); return TCL_OK; } static int test_vfs_oom_test( void * clientData, Tcl_Interp *interp, int objc, |
︙ | ︙ |
Changes to src/test_multiplex.c.
︙ | ︙ | |||
56 57 58 59 60 61 62 | #ifndef SQLITE_CORE #define SQLITE_CORE 1 /* Disable the API redefinition in sqlite3ext.h */ #endif #include "sqlite3ext.h" /* ** These should be defined to be the same as the values in | | | 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | #ifndef SQLITE_CORE #define SQLITE_CORE 1 /* Disable the API redefinition in sqlite3ext.h */ #endif #include "sqlite3ext.h" /* ** These should be defined to be the same as the values in ** sqliteInt.h. They are defined separately here so that ** the multiplex VFS shim can be built as a loadable ** module. */ #define UNUSED_PARAMETER(x) (void)(x) #define MAX_PAGE_SIZE 0x10000 #define DEFAULT_SECTOR_SIZE 0x1000 |
︙ | ︙ | |||
1179 1180 1181 1182 1183 1184 1185 | memset(&gMultiplex, 0, sizeof(gMultiplex)); return SQLITE_OK; } /***************************** Test Code ***********************************/ #ifdef SQLITE_TEST #include <tcl.h> | | | 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 | memset(&gMultiplex, 0, sizeof(gMultiplex)); return SQLITE_OK; } /***************************** Test Code ***********************************/ #ifdef SQLITE_TEST #include <tcl.h> extern const char *sqlite3ErrName(int); /* ** tclcmd: sqlite3_multiplex_initialize NAME MAKEDEFAULT */ static int test_multiplex_initialize( void * clientData, |
︙ | ︙ | |||
1208 1209 1210 1211 1212 1213 1214 | } zName = Tcl_GetString(objv[1]); if( Tcl_GetBooleanFromObj(interp, objv[2], &makeDefault) ) return TCL_ERROR; if( zName[0]=='\0' ) zName = 0; /* Call sqlite3_multiplex_initialize() */ rc = sqlite3_multiplex_initialize(zName, makeDefault); | | | 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 | } zName = Tcl_GetString(objv[1]); if( Tcl_GetBooleanFromObj(interp, objv[2], &makeDefault) ) return TCL_ERROR; if( zName[0]=='\0' ) zName = 0; /* Call sqlite3_multiplex_initialize() */ rc = sqlite3_multiplex_initialize(zName, makeDefault); Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_STATIC); return TCL_OK; } /* ** tclcmd: sqlite3_multiplex_shutdown */ |
︙ | ︙ | |||
1233 1234 1235 1236 1237 1238 1239 | if( objc!=1 ){ Tcl_WrongNumArgs(interp, 1, objv, ""); return TCL_ERROR; } /* Call sqlite3_multiplex_shutdown() */ rc = sqlite3_multiplex_shutdown(); | | | 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 | if( objc!=1 ){ Tcl_WrongNumArgs(interp, 1, objv, ""); return TCL_ERROR; } /* Call sqlite3_multiplex_shutdown() */ rc = sqlite3_multiplex_shutdown(); Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_STATIC); return TCL_OK; } /* ** tclcmd: sqlite3_multiplex_dump */ |
︙ | ︙ | |||
1351 1352 1353 1354 1355 1356 1357 | break; default: Tcl_WrongNumArgs(interp, 4, objv, "SUB-COMMAND"); return TCL_ERROR; } rc = sqlite3_file_control(db, Tcl_GetString(objv[2]), aSub[idx].op, pArg); | | | 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 | break; default: Tcl_WrongNumArgs(interp, 4, objv, "SUB-COMMAND"); return TCL_ERROR; } rc = sqlite3_file_control(db, Tcl_GetString(objv[2]), aSub[idx].op, pArg); Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_STATIC); return (rc==SQLITE_OK) ? TCL_OK : TCL_ERROR; } /* ** This routine registers the custom TCL commands defined in this ** module. This should be the only procedure visible from outside ** of this module. |
︙ | ︙ |
Changes to src/test_mutex.c.
︙ | ︙ | |||
15 16 17 18 19 20 21 | #include "tcl.h" #include "sqlite3.h" #include "sqliteInt.h" #include <stdlib.h> #include <assert.h> #include <string.h> | | | | 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | #include "tcl.h" #include "sqlite3.h" #include "sqliteInt.h" #include <stdlib.h> #include <assert.h> #include <string.h> /* defined in main.c */ extern const char *sqlite3ErrName(int); /* A countable mutex */ struct sqlite3_mutex { sqlite3_mutex *pReal; int eType; }; |
︙ | ︙ | |||
144 145 146 147 148 149 150 | if( objc!=1 ){ Tcl_WrongNumArgs(interp, 1, objv, ""); return TCL_ERROR; } rc = sqlite3_shutdown(); | | | | 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 | if( objc!=1 ){ Tcl_WrongNumArgs(interp, 1, objv, ""); return TCL_ERROR; } rc = sqlite3_shutdown(); Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE); return TCL_OK; } /* ** sqlite3_initialize */ static int test_initialize( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ int rc; if( objc!=1 ){ Tcl_WrongNumArgs(interp, 1, objv, ""); return TCL_ERROR; } rc = sqlite3_initialize(); Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE); return TCL_OK; } /* ** install_mutex_counters BOOLEAN */ static int test_install_mutex_counters( |
︙ | ︙ | |||
226 227 228 229 230 231 232 | memset(&g.m, 0, sizeof(sqlite3_mutex_methods)); } if( rc==SQLITE_OK ){ g.isInstalled = isInstall; } | | | 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 | memset(&g.m, 0, sizeof(sqlite3_mutex_methods)); } if( rc==SQLITE_OK ){ g.isInstalled = isInstall; } Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE); return TCL_OK; } /* ** read_mutex_counters */ static int test_read_mutex_counters( |
︙ | ︙ | |||
350 351 352 353 354 355 356 | return TCL_ERROR; } }else{ i = aOpt[i].iValue; } rc = sqlite3_config(i); | | | 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 | return TCL_ERROR; } }else{ i = aOpt[i].iValue; } rc = sqlite3_config(i); Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE); return TCL_OK; } static sqlite3 *getDbPointer(Tcl_Interp *pInterp, Tcl_Obj *pObj){ sqlite3 *db; Tcl_CmdInfo info; char *zCmd = Tcl_GetString(pObj); |
︙ | ︙ |
Changes to src/test_quota.c.
︙ | ︙ | |||
1321 1322 1323 1324 1325 1326 1327 | */ typedef struct TclQuotaCallback TclQuotaCallback; struct TclQuotaCallback { Tcl_Interp *interp; /* Interpreter in which to run the script */ Tcl_Obj *pScript; /* Script to be run */ }; | | | 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 | */ typedef struct TclQuotaCallback TclQuotaCallback; struct TclQuotaCallback { Tcl_Interp *interp; /* Interpreter in which to run the script */ Tcl_Obj *pScript; /* Script to be run */ }; extern const char *sqlite3ErrName(int); /* ** This is the callback from a quota-over-limit. */ static void tclQuotaCallback( const char *zFilename, /* Name of file whose size increases */ |
︙ | ︙ | |||
1403 1404 1405 1406 1407 1408 1409 | } zName = Tcl_GetString(objv[1]); if( Tcl_GetBooleanFromObj(interp, objv[2], &makeDefault) ) return TCL_ERROR; if( zName[0]=='\0' ) zName = 0; /* Call sqlite3_quota_initialize() */ rc = sqlite3_quota_initialize(zName, makeDefault); | | | 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 | } zName = Tcl_GetString(objv[1]); if( Tcl_GetBooleanFromObj(interp, objv[2], &makeDefault) ) return TCL_ERROR; if( zName[0]=='\0' ) zName = 0; /* Call sqlite3_quota_initialize() */ rc = sqlite3_quota_initialize(zName, makeDefault); Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_STATIC); return TCL_OK; } /* ** tclcmd: sqlite3_quota_shutdown */ |
︙ | ︙ | |||
1426 1427 1428 1429 1430 1431 1432 | if( objc!=1 ){ Tcl_WrongNumArgs(interp, 1, objv, ""); return TCL_ERROR; } /* Call sqlite3_quota_shutdown() */ rc = sqlite3_quota_shutdown(); | | | 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 | if( objc!=1 ){ Tcl_WrongNumArgs(interp, 1, objv, ""); return TCL_ERROR; } /* Call sqlite3_quota_shutdown() */ rc = sqlite3_quota_shutdown(); Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_STATIC); return TCL_OK; } /* ** tclcmd: sqlite3_quota_set PATTERN LIMIT SCRIPT */ |
︙ | ︙ | |||
1481 1482 1483 1484 1485 1486 1487 | xDestroy = 0; xCallback = 0; } /* Invoke sqlite3_quota_set() */ rc = sqlite3_quota_set(zPattern, iLimit, xCallback, (void*)p, xDestroy); | | | 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 | xDestroy = 0; xCallback = 0; } /* Invoke sqlite3_quota_set() */ rc = sqlite3_quota_set(zPattern, iLimit, xCallback, (void*)p, xDestroy); Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_STATIC); return TCL_OK; } /* ** tclcmd: sqlite3_quota_file FILENAME */ static int test_quota_file( |
︙ | ︙ | |||
1507 1508 1509 1510 1511 1512 1513 | return TCL_ERROR; } zFilename = Tcl_GetString(objv[1]); /* Invoke sqlite3_quota_file() */ rc = sqlite3_quota_file(zFilename); | | | 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 | return TCL_ERROR; } zFilename = Tcl_GetString(objv[1]); /* Invoke sqlite3_quota_file() */ rc = sqlite3_quota_file(zFilename); Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_STATIC); return TCL_OK; } /* ** tclcmd: sqlite3_quota_dump */ static int test_quota_dump( |
︙ | ︙ |
Changes to src/test_rtree.c.
︙ | ︙ | |||
250 251 252 253 254 255 256 | #ifndef SQLITE_ENABLE_RTREE UNUSED_PARAMETER(clientData); UNUSED_PARAMETER(interp); UNUSED_PARAMETER(objc); UNUSED_PARAMETER(objv); #else extern int getDbPointer(Tcl_Interp*, const char*, sqlite3**); | | | | | | 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 | #ifndef SQLITE_ENABLE_RTREE UNUSED_PARAMETER(clientData); UNUSED_PARAMETER(interp); UNUSED_PARAMETER(objc); UNUSED_PARAMETER(objv); #else extern int getDbPointer(Tcl_Interp*, const char*, sqlite3**); extern const char *sqlite3ErrName(int); sqlite3 *db; int rc; if( objc!=2 ){ Tcl_WrongNumArgs(interp, 1, objv, "DB"); return TCL_ERROR; } if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; rc = sqlite3_rtree_geometry_callback(db, "cube", cube_geom, (void *)&gHere); Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_STATIC); #endif return TCL_OK; } static int register_circle_geom( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ #ifndef SQLITE_ENABLE_RTREE UNUSED_PARAMETER(clientData); UNUSED_PARAMETER(interp); UNUSED_PARAMETER(objc); UNUSED_PARAMETER(objv); #else extern int getDbPointer(Tcl_Interp*, const char*, sqlite3**); extern const char *sqlite3ErrName(int); sqlite3 *db; int rc; if( objc!=2 ){ Tcl_WrongNumArgs(interp, 1, objv, "DB"); return TCL_ERROR; } if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; rc = sqlite3_rtree_geometry_callback(db, "circle", circle_geom, 0); Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_STATIC); #endif return TCL_OK; } int Sqlitetestrtree_Init(Tcl_Interp *interp){ Tcl_CreateObjCommand(interp, "register_cube_geom", register_cube_geom, 0, 0); Tcl_CreateObjCommand(interp, "register_circle_geom",register_circle_geom,0,0); return TCL_OK; } |
Changes to src/test_sqllog.c.
︙ | ︙ | |||
9 10 11 12 13 14 15 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** ** OVERVIEW ** ** This file contains experimental code used to record data from live | | > > > > > > > | > > > | | | | 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 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** ** OVERVIEW ** ** This file contains experimental code used to record data from live ** SQLite applications that may be useful for offline analysis. ** Specifically, this module can be used to capture the following ** information: ** ** 1) The initial contents of all database files opened by the ** application, and ** ** 2) All SQL statements executed by the application. ** ** The captured information can then be used to run (for example) ** performance analysis looking for slow queries or to look for ** optimization opportunities in either the application or in SQLite ** itself. ** ** USAGE ** ** To use this module, SQLite must be compiled with the SQLITE_ENABLE_SQLLOG ** pre-processor symbol defined and this file linked into the application. ** One way to link this file into the application is to append the content ** of this file onto the end of the "sqlite3.c" amalgamation and then ** recompile the application as normal except with the addition of the ** -DSQLITE_ENABLE_SQLLOG option. ** ** At runtime, logging is enabled by setting environment variable ** SQLITE_SQLLOG_DIR to the name of a directory in which to store logged ** data. The logging directory must already exist. ** ** Usually, if the application opens the same database file more than once ** (either by attaching it or by using more than one database handle), only ** a single copy is made. This behavior may be overridden (so that a ** separate copy is taken each time the database file is opened or attached) ** by setting the environment variable SQLITE_SQLLOG_REUSE_FILES to 0. ** ** OUTPUT: ** ** The SQLITE_SQLLOG_DIR is populated with three types of files: ** |
︙ | ︙ | |||
53 54 55 56 57 58 59 60 | ** ** This module attempts to make a best effort to continue logging if an ** IO or other error is encountered. For example, if a log file cannot ** be opened logs are not collected for that connection, but other ** logging proceeds as expected. Errors are logged by calling sqlite3_log(). */ #include "sqlite3.h" | > > | | | | | | | > > > > > | | 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 | ** ** This module attempts to make a best effort to continue logging if an ** IO or other error is encountered. For example, if a log file cannot ** be opened logs are not collected for that connection, but other ** logging proceeds as expected. Errors are logged by calling sqlite3_log(). */ #ifndef _SQLITE3_H_ #include "sqlite3.h" #endif #include <stdio.h> #include <stdlib.h> #include <string.h> #include <assert.h> #include <sys/types.h> #include <unistd.h> static int getProcessId(void){ #if SQLITE_OS_WIN return (int)_getpid(); #else return (int)getpid(); #endif } /* Names of environment variables to be used */ #define ENVIRONMENT_VARIABLE1_NAME "SQLITE_SQLLOG_DIR" #define ENVIRONMENT_VARIABLE2_NAME "SQLITE_SQLLOG_REUSE_FILES" /* Assume that all database and database file names are shorted than this. */ #define SQLLOG_NAMESZ 512 /* Maximum number of simultaneous database connections the process may ** open (if any more are opened an error is logged using sqlite3_log() ** and processing is halted). */ #define MAX_CONNECTIONS 256 /* There is one instance of this object for each SQLite database connection ** that is being logged. */ struct SLConn { int isErr; /* True if an error has occurred */ sqlite3 *db; /* Connection handle */ int iLog; /* First integer value used in file names */ FILE *fd; /* File descriptor for log file */ }; /* This object is a singleton that keeps track of all data loggers. */ static struct SLGlobal { /* Protected by MUTEX_STATIC_MASTER */ sqlite3_mutex *mutex; /* Recursive mutex */ int nConn; /* Size of aConn[] array */ /* Protected by SLGlobal.mutex */ int bReuse; /* True to avoid extra copies of db files */ char zPrefix[SQLLOG_NAMESZ]; /* Prefix for all created files */ |
︙ | ︙ | |||
384 385 386 387 388 389 390 391 392 393 394 395 396 397 | /* This is an ATTACH statement. Copy the database. */ sqllogCopydb(p, 0, 1); } } /* ** The SQLITE_CONFIG_SQLLOG callback registered by sqlite3_init_sqllog(). */ static void testSqllog(void *pCtx, sqlite3 *db, const char *zSql, int eType){ struct SLConn *p = 0; sqlite3_mutex *master = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER); assert( eType==0 || eType==1 || eType==2 ); assert( (eType==2)==(zSql==0) ); | > > > > > > > > > > > > > > > > > > | 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 | /* This is an ATTACH statement. Copy the database. */ sqllogCopydb(p, 0, 1); } } /* ** The SQLITE_CONFIG_SQLLOG callback registered by sqlite3_init_sqllog(). ** ** The eType parameter has the following values: ** ** 0: Opening a new database connection. zSql is the name of the ** file being opened. db is a pointer to the newly created database ** connection. ** ** 1: An SQL statement has run to completion. zSql is the text of the ** SQL statement with all parameters expanded to their actual values. ** ** 2: Closing a database connection. zSql is NULL. The db pointer to ** the database connection being closed has already been shut down ** and cannot be used for any further SQL. ** ** The pCtx parameter is a copy of the pointer that was originally passed ** into the sqlite3_config(SQLITE_CONFIG_SQLLOG) statement. In this ** particular implementation, pCtx is always a pointer to the ** sqllogglobal global variable define above. */ static void testSqllog(void *pCtx, sqlite3 *db, const char *zSql, int eType){ struct SLConn *p = 0; sqlite3_mutex *master = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER); assert( eType==0 || eType==1 || eType==2 ); assert( (eType==2)==(zSql==0) ); |
︙ | ︙ |
Changes to src/test_syscall.c.
︙ | ︙ | |||
19 20 21 22 23 24 25 | ** test_syscall install LIST ** Install wrapper functions for all system calls in argument LIST. ** LIST must be a list consisting of zero or more of the following ** literal values: ** ** open close access getcwd stat fstat ** ftruncate fcntl read pread pread64 write | | | 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | ** test_syscall install LIST ** Install wrapper functions for all system calls in argument LIST. ** LIST must be a list consisting of zero or more of the following ** literal values: ** ** open close access getcwd stat fstat ** ftruncate fcntl read pread pread64 write ** pwrite pwrite64 fchmod fallocate mmap ** ** test_syscall uninstall ** Uninstall all wrapper functions. ** ** test_syscall fault ?COUNT PERSIST? ** If [test_syscall fault] is invoked without the two arguments, fault ** injection is disabled. Otherwise, fault injection is configured to |
︙ | ︙ | |||
74 75 76 77 78 79 80 | #include <stdlib.h> #include <string.h> #include <assert.h> #include "sqliteInt.h" #if SQLITE_OS_UNIX | | | > | 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 | #include <stdlib.h> #include <string.h> #include <assert.h> #include "sqliteInt.h" #if SQLITE_OS_UNIX /* From main.c */ extern const char *sqlite3ErrName(int); #include <sys/mman.h> #include <sys/types.h> #include <errno.h> static struct TestSyscallGlobal { int bPersist; /* 1 for persistent errors, 0 for transient */ int nCount; /* Fail after this many more calls */ int nFail; /* Number of failures that have occurred */ |
︙ | ︙ | |||
102 103 104 105 106 107 108 | static int ts_pread(int fd, void *aBuf, size_t nBuf, off_t off); static int ts_pread64(int fd, void *aBuf, size_t nBuf, off_t off); static int ts_write(int fd, const void *aBuf, size_t nBuf); static int ts_pwrite(int fd, const void *aBuf, size_t nBuf, off_t off); static int ts_pwrite64(int fd, const void *aBuf, size_t nBuf, off_t off); static int ts_fchmod(int fd, mode_t mode); static int ts_fallocate(int fd, off_t off, off_t len); | | > | 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 | static int ts_pread(int fd, void *aBuf, size_t nBuf, off_t off); static int ts_pread64(int fd, void *aBuf, size_t nBuf, off_t off); static int ts_write(int fd, const void *aBuf, size_t nBuf); static int ts_pwrite(int fd, const void *aBuf, size_t nBuf, off_t off); static int ts_pwrite64(int fd, const void *aBuf, size_t nBuf, off_t off); static int ts_fchmod(int fd, mode_t mode); static int ts_fallocate(int fd, off_t off, off_t len); static void *ts_mmap(void *, size_t, int, int, int, off_t); static void *ts_mremap(void*, size_t, size_t, int, ...); struct TestSyscallArray { const char *zName; sqlite3_syscall_ptr xTest; sqlite3_syscall_ptr xOrig; int default_errno; /* Default value for errno following errors */ int custom_errno; /* Current value for errno if error */ |
︙ | ︙ | |||
127 128 129 130 131 132 133 134 135 136 137 138 139 140 | /* 9 */ { "pread", (sqlite3_syscall_ptr)ts_pread, 0, 0, 0 }, /* 10 */ { "pread64", (sqlite3_syscall_ptr)ts_pread64, 0, 0, 0 }, /* 11 */ { "write", (sqlite3_syscall_ptr)ts_write, 0, 0, 0 }, /* 12 */ { "pwrite", (sqlite3_syscall_ptr)ts_pwrite, 0, 0, 0 }, /* 13 */ { "pwrite64", (sqlite3_syscall_ptr)ts_pwrite64, 0, 0, 0 }, /* 14 */ { "fchmod", (sqlite3_syscall_ptr)ts_fchmod, 0, 0, 0 }, /* 15 */ { "fallocate", (sqlite3_syscall_ptr)ts_fallocate, 0, 0, 0 }, { 0, 0, 0, 0, 0 } }; #define orig_open ((int(*)(const char *, int, int))aSyscall[0].xOrig) #define orig_close ((int(*)(int))aSyscall[1].xOrig) #define orig_access ((int(*)(const char*,int))aSyscall[2].xOrig) #define orig_getcwd ((char*(*)(char*,size_t))aSyscall[3].xOrig) | > > | 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 | /* 9 */ { "pread", (sqlite3_syscall_ptr)ts_pread, 0, 0, 0 }, /* 10 */ { "pread64", (sqlite3_syscall_ptr)ts_pread64, 0, 0, 0 }, /* 11 */ { "write", (sqlite3_syscall_ptr)ts_write, 0, 0, 0 }, /* 12 */ { "pwrite", (sqlite3_syscall_ptr)ts_pwrite, 0, 0, 0 }, /* 13 */ { "pwrite64", (sqlite3_syscall_ptr)ts_pwrite64, 0, 0, 0 }, /* 14 */ { "fchmod", (sqlite3_syscall_ptr)ts_fchmod, 0, 0, 0 }, /* 15 */ { "fallocate", (sqlite3_syscall_ptr)ts_fallocate, 0, 0, 0 }, /* 16 */ { "mmap", (sqlite3_syscall_ptr)ts_mmap, 0, 0, 0 }, /* 17 */ { "mremap", (sqlite3_syscall_ptr)ts_mremap, 0, 0, 0 }, { 0, 0, 0, 0, 0 } }; #define orig_open ((int(*)(const char *, int, int))aSyscall[0].xOrig) #define orig_close ((int(*)(int))aSyscall[1].xOrig) #define orig_access ((int(*)(const char*,int))aSyscall[2].xOrig) #define orig_getcwd ((char*(*)(char*,size_t))aSyscall[3].xOrig) |
︙ | ︙ | |||
148 149 150 151 152 153 154 155 156 157 158 159 160 161 | #define orig_write ((ssize_t(*)(int,const void*,size_t))aSyscall[11].xOrig) #define orig_pwrite ((ssize_t(*)(int,const void*,size_t,off_t))\ aSyscall[12].xOrig) #define orig_pwrite64 ((ssize_t(*)(int,const void*,size_t,off_t))\ aSyscall[13].xOrig) #define orig_fchmod ((int(*)(int,mode_t))aSyscall[14].xOrig) #define orig_fallocate ((int(*)(int,off_t,off_t))aSyscall[15].xOrig) /* ** This function is called exactly once from within each invocation of a ** system call wrapper in this file. It returns 1 if the function should ** fail, or 0 if it should succeed. */ static int tsIsFail(void){ | > > | 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 | #define orig_write ((ssize_t(*)(int,const void*,size_t))aSyscall[11].xOrig) #define orig_pwrite ((ssize_t(*)(int,const void*,size_t,off_t))\ aSyscall[12].xOrig) #define orig_pwrite64 ((ssize_t(*)(int,const void*,size_t,off_t))\ aSyscall[13].xOrig) #define orig_fchmod ((int(*)(int,mode_t))aSyscall[14].xOrig) #define orig_fallocate ((int(*)(int,off_t,off_t))aSyscall[15].xOrig) #define orig_mmap ((void*(*)(void*,size_t,int,int,int,off_t))aSyscall[16].xOrig) #define orig_mremap ((void*(*)(void*,size_t,size_t,int,...))aSyscall[17].xOrig) /* ** This function is called exactly once from within each invocation of a ** system call wrapper in this file. It returns 1 if the function should ** fail, or 0 if it should succeed. */ static int tsIsFail(void){ |
︙ | ︙ | |||
372 373 374 375 376 377 378 379 380 381 382 383 384 385 | */ static int ts_fallocate(int fd, off_t off, off_t len){ if( tsIsFail() ){ return tsErrno("fallocate"); } return orig_fallocate(fd, off, len); } static int test_syscall_install( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ | > > > > > > > > > > > > > > > > > > > > > > > > > | 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 | */ static int ts_fallocate(int fd, off_t off, off_t len){ if( tsIsFail() ){ return tsErrno("fallocate"); } return orig_fallocate(fd, off, len); } static void *ts_mmap( void *pAddr, size_t nByte, int prot, int flags, int fd, off_t iOff ){ if( tsIsFailErrno("mmap") ){ return MAP_FAILED; } return orig_mmap(pAddr, nByte, prot, flags, fd, iOff); } static void *ts_mremap(void *a, size_t b, size_t c, int d, ...){ va_list ap; void *pArg; if( tsIsFailErrno("mremap") ){ return MAP_FAILED; } va_start(ap, d); pArg = va_arg(ap, void *); return orig_mremap(a, b, c, d, pArg); } static int test_syscall_install( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ |
︙ | ︙ | |||
463 464 465 466 467 468 469 | for(i=0; rc==SQLITE_OK && aSyscall[i].zName; i++){ if( strlen(aSyscall[i].zName)!=nFunc ) continue; if( memcmp(aSyscall[i].zName, zFunc, nFunc) ) continue; aSyscall[i].xOrig = 0; } } if( rc!=SQLITE_OK ){ | | | 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 | for(i=0; rc==SQLITE_OK && aSyscall[i].zName; i++){ if( strlen(aSyscall[i].zName)!=nFunc ) continue; if( memcmp(aSyscall[i].zName, zFunc, nFunc) ) continue; aSyscall[i].xOrig = 0; } } if( rc!=SQLITE_OK ){ Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1)); return TCL_ERROR; } Tcl_ResetResult(interp); return TCL_OK; } |
︙ | ︙ |
Changes to src/test_thread.c.
︙ | ︙ | |||
56 57 58 59 60 61 62 63 | #if SQLITE_OS_UNIX && defined(SQLITE_ENABLE_UNLOCK_NOTIFY) static Tcl_ObjCmdProc blocking_step_proc; static Tcl_ObjCmdProc blocking_prepare_v2_proc; #endif int Sqlitetest1_Init(Tcl_Interp *); int Sqlite3_Init(Tcl_Interp *); /* Functions from test1.c */ | > > > | < | | | | 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 | #if SQLITE_OS_UNIX && defined(SQLITE_ENABLE_UNLOCK_NOTIFY) static Tcl_ObjCmdProc blocking_step_proc; static Tcl_ObjCmdProc blocking_prepare_v2_proc; #endif int Sqlitetest1_Init(Tcl_Interp *); int Sqlite3_Init(Tcl_Interp *); /* Functions from main.c */ extern const char *sqlite3ErrName(int); /* Functions from test1.c */ extern void *sqlite3TestTextToPtr(const char *); extern int getDbPointer(Tcl_Interp *, const char *, sqlite3 **); extern int sqlite3TestMakePointerStr(Tcl_Interp *, char *, void *); extern int sqlite3TestErrCode(Tcl_Interp *, sqlite3 *, int); /* ** Handler for events of type EvalEvent. */ static int tclScriptEvent(Tcl_Event *evPtr, int flags){ int rc; EvalEvent *p = (EvalEvent *)evPtr; |
︙ | ︙ | |||
555 556 557 558 559 560 561 | Tcl_WrongNumArgs(interp, 1, objv, "STMT"); return TCL_ERROR; } pStmt = (sqlite3_stmt*)sqlite3TestTextToPtr(Tcl_GetString(objv[1])); rc = sqlite3_blocking_step(pStmt); | | | 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 | Tcl_WrongNumArgs(interp, 1, objv, "STMT"); return TCL_ERROR; } pStmt = (sqlite3_stmt*)sqlite3TestTextToPtr(Tcl_GetString(objv[1])); rc = sqlite3_blocking_step(pStmt); Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), 0); return TCL_OK; } /* ** Usage: sqlite3_blocking_prepare_v2 DB sql bytes ?tailvar? ** Usage: sqlite3_nonblocking_prepare_v2 DB sql bytes ?tailvar? */ |
︙ | ︙ | |||
602 603 604 605 606 607 608 | if( bytes>=0 ){ bytes = bytes - (zTail-zSql); } Tcl_ObjSetVar2(interp, objv[4], 0, Tcl_NewStringObj(zTail, bytes), 0); } if( rc!=SQLITE_OK ){ assert( pStmt==0 ); | | | 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 | if( bytes>=0 ){ bytes = bytes - (zTail-zSql); } Tcl_ObjSetVar2(interp, objv[4], 0, Tcl_NewStringObj(zTail, bytes), 0); } if( rc!=SQLITE_OK ){ assert( pStmt==0 ); sprintf(zBuf, "%s ", (char *)sqlite3ErrName(rc)); Tcl_AppendResult(interp, zBuf, sqlite3_errmsg(db), 0); return TCL_ERROR; } if( pStmt ){ if( sqlite3TestMakePointerStr(interp, zBuf, pStmt) ) return TCL_ERROR; Tcl_AppendResult(interp, zBuf, 0); |
︙ | ︙ |
Changes to src/test_vfs.c.
︙ | ︙ | |||
121 122 123 124 125 126 127 128 | #define TESTVFS_DELETE_MASK 0x00000400 #define TESTVFS_CLOSE_MASK 0x00000800 #define TESTVFS_WRITE_MASK 0x00001000 #define TESTVFS_TRUNCATE_MASK 0x00002000 #define TESTVFS_ACCESS_MASK 0x00004000 #define TESTVFS_FULLPATHNAME_MASK 0x00008000 #define TESTVFS_READ_MASK 0x00010000 | > | | 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 | #define TESTVFS_DELETE_MASK 0x00000400 #define TESTVFS_CLOSE_MASK 0x00000800 #define TESTVFS_WRITE_MASK 0x00001000 #define TESTVFS_TRUNCATE_MASK 0x00002000 #define TESTVFS_ACCESS_MASK 0x00004000 #define TESTVFS_FULLPATHNAME_MASK 0x00008000 #define TESTVFS_READ_MASK 0x00010000 #define TESTVFS_UNLOCK_MASK 0x00020000 #define TESTVFS_ALL_MASK 0x0003FFFF #define TESTVFS_MAX_PAGES 1024 /* ** A shared-memory buffer. There is one of these objects for each shared ** memory region opened by clients. If two clients open the same file, |
︙ | ︙ | |||
463 464 465 466 467 468 469 | return sqlite3OsLock(p->pReal, eLock); } /* ** Unlock an tvfs-file. */ static int tvfsUnlock(sqlite3_file *pFile, int eLock){ | | > > > > | | 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 | return sqlite3OsLock(p->pReal, eLock); } /* ** Unlock an tvfs-file. */ static int tvfsUnlock(sqlite3_file *pFile, int eLock){ TestvfsFd *pFd = tvfsGetFd(pFile); Testvfs *p = (Testvfs *)pFd->pVfs->pAppData; if( p->mask&TESTVFS_WRITE_MASK && tvfsInjectIoerr(p) ){ return SQLITE_IOERR_UNLOCK; } return sqlite3OsUnlock(pFd->pReal, eLock); } /* ** Check if another file-handle holds a RESERVED lock on an tvfs-file. */ static int tvfsCheckReservedLock(sqlite3_file *pFile, int *pResOut){ TestvfsFd *p = tvfsGetFd(pFile); |
︙ | ︙ | |||
1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 | { "xWrite", TESTVFS_WRITE_MASK }, { "xRead", TESTVFS_READ_MASK }, { "xTruncate", TESTVFS_TRUNCATE_MASK }, { "xOpen", TESTVFS_OPEN_MASK }, { "xClose", TESTVFS_CLOSE_MASK }, { "xAccess", TESTVFS_ACCESS_MASK }, { "xFullPathname", TESTVFS_FULLPATHNAME_MASK }, }; Tcl_Obj **apElem = 0; int nElem = 0; int i; int mask = 0; if( objc!=3 ){ Tcl_WrongNumArgs(interp, 2, objv, "LIST"); | > | 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 | { "xWrite", TESTVFS_WRITE_MASK }, { "xRead", TESTVFS_READ_MASK }, { "xTruncate", TESTVFS_TRUNCATE_MASK }, { "xOpen", TESTVFS_OPEN_MASK }, { "xClose", TESTVFS_CLOSE_MASK }, { "xAccess", TESTVFS_ACCESS_MASK }, { "xFullPathname", TESTVFS_FULLPATHNAME_MASK }, { "xUnlock", TESTVFS_UNLOCK_MASK }, }; Tcl_Obj **apElem = 0; int nElem = 0; int i; int mask = 0; if( objc!=3 ){ Tcl_WrongNumArgs(interp, 2, objv, "LIST"); |
︙ | ︙ |
Changes to src/update.c.
︙ | ︙ | |||
204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 | } aXRef[j] = i; break; } } if( j>=pTab->nCol ){ if( sqlite3IsRowid(pChanges->a[i].zName) ){ chngRowid = 1; pRowidExpr = pChanges->a[i].pExpr; }else{ sqlite3ErrorMsg(pParse, "no such column: %s", pChanges->a[i].zName); pParse->checkSchema = 1; goto update_cleanup; } } #ifndef SQLITE_OMIT_AUTHORIZATION { int rc; rc = sqlite3AuthCheck(pParse, SQLITE_UPDATE, pTab->zName, | > > | | 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 | } aXRef[j] = i; break; } } if( j>=pTab->nCol ){ if( sqlite3IsRowid(pChanges->a[i].zName) ){ j = -1; chngRowid = 1; pRowidExpr = pChanges->a[i].pExpr; }else{ sqlite3ErrorMsg(pParse, "no such column: %s", pChanges->a[i].zName); pParse->checkSchema = 1; goto update_cleanup; } } #ifndef SQLITE_OMIT_AUTHORIZATION { int rc; rc = sqlite3AuthCheck(pParse, SQLITE_UPDATE, pTab->zName, j<0 ? "ROWID" : pTab->aCol[j].zName, db->aDb[iDb].zName); if( rc==SQLITE_DENY ){ goto update_cleanup; }else if( rc==SQLITE_IGNORE ){ aXRef[j] = -1; } } #endif |
︙ | ︙ | |||
454 455 456 457 458 459 460 | sqlite3VdbeAddOp2(v, OP_Affinity, regNew, pTab->nCol); sqlite3TableAffinityStr(v, pTab); sqlite3CodeRowTrigger(pParse, pTrigger, TK_UPDATE, pChanges, TRIGGER_BEFORE, pTab, regOldRowid, onError, addr); /* The row-trigger may have deleted the row being updated. In this ** case, jump to the next row. No updates or AFTER triggers are | | | 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 | sqlite3VdbeAddOp2(v, OP_Affinity, regNew, pTab->nCol); sqlite3TableAffinityStr(v, pTab); sqlite3CodeRowTrigger(pParse, pTrigger, TK_UPDATE, pChanges, TRIGGER_BEFORE, pTab, regOldRowid, onError, addr); /* The row-trigger may have deleted the row being updated. In this ** case, jump to the next row. No updates or AFTER triggers are ** required. This behavior - what happens when the row being updated ** is deleted or renamed by a BEFORE trigger - is left undefined in the ** documentation. */ sqlite3VdbeAddOp3(v, OP_NotExists, iCur, addr, regOldRowid); /* If it did not delete it, the row-trigger may still have modified ** some of the columns of the row being updated. Load the values for |
︙ | ︙ |
Changes to src/util.c.
︙ | ︙ | |||
257 258 259 260 261 262 263 | ** ** If some prefix of the input string is a valid number, this routine ** returns FALSE but it still converts the prefix and writes the result ** into *pResult. */ int sqlite3AtoF(const char *z, double *pResult, int length, u8 enc){ #ifndef SQLITE_OMIT_FLOATING_POINT | | > > | > > > > > > > > > > | 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 | ** ** If some prefix of the input string is a valid number, this routine ** returns FALSE but it still converts the prefix and writes the result ** into *pResult. */ int sqlite3AtoF(const char *z, double *pResult, int length, u8 enc){ #ifndef SQLITE_OMIT_FLOATING_POINT int incr; const char *zEnd = z + length; /* sign * significand * (10 ^ (esign * exponent)) */ int sign = 1; /* sign of significand */ i64 s = 0; /* significand */ int d = 0; /* adjust exponent for shifting decimal point */ int esign = 1; /* sign of exponent */ int e = 0; /* exponent */ int eValid = 1; /* True exponent is either not used or is well-formed */ double result; int nDigits = 0; int nonNum = 0; assert( enc==SQLITE_UTF8 || enc==SQLITE_UTF16LE || enc==SQLITE_UTF16BE ); *pResult = 0.0; /* Default return value, in case of an error */ if( enc==SQLITE_UTF8 ){ incr = 1; }else{ int i; incr = 2; assert( SQLITE_UTF16LE==2 && SQLITE_UTF16BE==3 ); for(i=3-enc; i<length && z[i]==0; i+=2){} nonNum = i<length; zEnd = z+i+enc-3; z += (enc&1); } /* skip leading spaces */ while( z<zEnd && sqlite3Isspace(*z) ) z+=incr; if( z>=zEnd ) return 0; /* get sign of significand */ if( *z=='-' ){ |
︙ | ︙ | |||
404 405 406 407 408 409 410 | } } /* store the result */ *pResult = result; /* return true if number and no extra non-whitespace chracters after */ | | | 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 | } } /* store the result */ *pResult = result; /* return true if number and no extra non-whitespace chracters after */ return z>=zEnd && nDigits>0 && eValid && nonNum==0; #else return !sqlite3Atoi64(z, pResult, length, enc); #endif /* SQLITE_OMIT_FLOATING_POINT */ } /* ** Compare the 19-character string zNum against the text representation |
︙ | ︙ | |||
453 454 455 456 457 458 459 | ** integer, then write that value into *pNum and return 0. ** ** If zNum is exactly 9223372036854665808, return 2. This special ** case is broken out because while 9223372036854665808 cannot be a ** signed 64-bit integer, its negative -9223372036854665808 can be. ** ** If zNum is too big for a 64-bit integer and is not | | > | > > | > > > > > > > > > | 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 | ** integer, then write that value into *pNum and return 0. ** ** If zNum is exactly 9223372036854665808, return 2. This special ** case is broken out because while 9223372036854665808 cannot be a ** signed 64-bit integer, its negative -9223372036854665808 can be. ** ** If zNum is too big for a 64-bit integer and is not ** 9223372036854665808 or if zNum contains any non-numeric text, ** then return 1. ** ** length is the number of bytes in the string (bytes, not characters). ** The string is not necessarily zero-terminated. The encoding is ** given by enc. */ int sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8 enc){ int incr; u64 u = 0; int neg = 0; /* assume positive */ int i; int c = 0; int nonNum = 0; const char *zStart; const char *zEnd = zNum + length; assert( enc==SQLITE_UTF8 || enc==SQLITE_UTF16LE || enc==SQLITE_UTF16BE ); if( enc==SQLITE_UTF8 ){ incr = 1; }else{ incr = 2; assert( SQLITE_UTF16LE==2 && SQLITE_UTF16BE==3 ); for(i=3-enc; i<length && zNum[i]==0; i+=2){} nonNum = i<length; zEnd = zNum+i+enc-3; zNum += (enc&1); } while( zNum<zEnd && sqlite3Isspace(*zNum) ) zNum+=incr; if( zNum<zEnd ){ if( *zNum=='-' ){ neg = 1; zNum+=incr; }else if( *zNum=='+' ){ zNum+=incr; |
︙ | ︙ | |||
492 493 494 495 496 497 498 | *pNum = -(i64)u; }else{ *pNum = (i64)u; } testcase( i==18 ); testcase( i==19 ); testcase( i==20 ); | | | 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 | *pNum = -(i64)u; }else{ *pNum = (i64)u; } testcase( i==18 ); testcase( i==19 ); testcase( i==20 ); if( (c!=0 && &zNum[i]<zEnd) || (i==0 && zStart==zNum) || i>19*incr || nonNum ){ /* zNum is empty or contains non-numeric text or is longer ** than 19 digits (thus guaranteeing that it is too large) */ return 1; }else if( i<19*incr ){ /* Less than 19 digits, so we know that it fits in 64 bits */ assert( u<=LARGEST_INT64 ); return 0; |
︙ | ︙ |
Changes to src/vacuum.c.
︙ | ︙ | |||
285 286 287 288 289 290 291 292 293 294 295 296 297 298 | ** connections to the same database will know to reread the schema. */ static const unsigned char aCopy[] = { BTREE_SCHEMA_VERSION, 1, /* Add one to the old schema cookie */ BTREE_DEFAULT_CACHE_SIZE, 0, /* Preserve the default page cache size */ BTREE_TEXT_ENCODING, 0, /* Preserve the text encoding */ BTREE_USER_VERSION, 0, /* Preserve the user version */ }; assert( 1==sqlite3BtreeIsInTrans(pTemp) ); assert( 1==sqlite3BtreeIsInTrans(pMain) ); /* Copy Btree meta values */ for(i=0; i<ArraySize(aCopy); i+=2){ | > | 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 | ** connections to the same database will know to reread the schema. */ static const unsigned char aCopy[] = { BTREE_SCHEMA_VERSION, 1, /* Add one to the old schema cookie */ BTREE_DEFAULT_CACHE_SIZE, 0, /* Preserve the default page cache size */ BTREE_TEXT_ENCODING, 0, /* Preserve the text encoding */ BTREE_USER_VERSION, 0, /* Preserve the user version */ BTREE_APPLICATION_ID, 0, /* Preserve the application id */ }; assert( 1==sqlite3BtreeIsInTrans(pTemp) ); assert( 1==sqlite3BtreeIsInTrans(pMain) ); /* Copy Btree meta values */ for(i=0; i<ArraySize(aCopy); i+=2){ |
︙ | ︙ |
Changes to src/vdbe.c.
︙ | ︙ | |||
148 149 150 151 152 153 154 | ** converts an MEM_Ephem string into an MEM_Dyn string. */ #define Deephemeralize(P) \ if( ((P)->flags&MEM_Ephem)!=0 \ && sqlite3VdbeMemMakeWriteable(P) ){ goto no_mem;} /* Return true if the cursor was opened using the OP_OpenSorter opcode. */ | < < < < | 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 | ** converts an MEM_Ephem string into an MEM_Dyn string. */ #define Deephemeralize(P) \ if( ((P)->flags&MEM_Ephem)!=0 \ && sqlite3VdbeMemMakeWriteable(P) ){ goto no_mem;} /* Return true if the cursor was opened using the OP_OpenSorter opcode. */ # define isSorter(x) ((x)->pSorter!=0) /* ** Argument pMem points at a register that will be passed to a ** user-defined function or returned to the user as the result of a query. ** This routine sets the pMem->type variable used by the sqlite3_value_*() ** routines. */ |
︙ | ︙ | |||
3317 3318 3319 3320 3321 3322 3323 | ** This opcode works like OP_OpenEphemeral except that it opens ** a transient index that is specifically designed to sort large ** tables using an external merge-sort algorithm. */ case OP_SorterOpen: { VdbeCursor *pCx; | < < < < < | 3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 | ** This opcode works like OP_OpenEphemeral except that it opens ** a transient index that is specifically designed to sort large ** tables using an external merge-sort algorithm. */ case OP_SorterOpen: { VdbeCursor *pCx; pCx = allocateCursor(p, pOp->p1, pOp->p2, -1, 1); if( pCx==0 ) goto no_mem; pCx->pKeyInfo = pOp->p4.pKeyInfo; pCx->pKeyInfo->enc = ENC(p->db); pCx->isSorter = 1; rc = sqlite3VdbeSorterInit(db, pCx); break; } /* Opcode: OpenPseudo P1 P2 P3 * P5 ** ** Open a new cursor that points to a fake table that contains a single ** row of data. The content of that one row in the content of memory |
︙ | ︙ | |||
3520 3521 3522 3523 3524 3525 3526 | /* The next line of code computes as follows, only faster: ** if( oc==OP_SeekGt || oc==OP_SeekLe ){ ** r.flags = UNPACKED_INCRKEY; ** }else{ ** r.flags = 0; ** } */ | | | 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 | /* The next line of code computes as follows, only faster: ** if( oc==OP_SeekGt || oc==OP_SeekLe ){ ** r.flags = UNPACKED_INCRKEY; ** }else{ ** r.flags = 0; ** } */ r.flags = (u8)(UNPACKED_INCRKEY * (1 & (oc - OP_SeekLt))); assert( oc!=OP_SeekGt || r.flags==UNPACKED_INCRKEY ); assert( oc!=OP_SeekLe || r.flags==UNPACKED_INCRKEY ); assert( oc!=OP_SeekGe || r.flags==0 ); assert( oc!=OP_SeekLt || r.flags==0 ); r.aMem = &aMem[pOp->p3]; #ifdef SQLITE_DEBUG |
︙ | ︙ | |||
4210 4211 4212 4213 4214 4215 4216 | /* Opcode: SorterData P1 P2 * * * ** ** Write into register P2 the current sorter data for sorter cursor P1. */ case OP_SorterData: { VdbeCursor *pC; | < < < < < | 4201 4202 4203 4204 4205 4206 4207 4208 4209 4210 4211 4212 4213 4214 4215 4216 4217 4218 | /* Opcode: SorterData P1 P2 * * * ** ** Write into register P2 the current sorter data for sorter cursor P1. */ case OP_SorterData: { VdbeCursor *pC; pOut = &aMem[pOp->p2]; pC = p->apCsr[pOp->p1]; assert( pC->isSorter ); rc = sqlite3VdbeSorterRowkey(pC, pOut); break; } /* Opcode: RowData P1 P2 * * * ** ** Write into register P2 the complete row data for cursor P1. ** There is no interpretation of the data. |
︙ | ︙ | |||
4417 4418 4419 4420 4421 4422 4423 | ** then rewinding that index and playing it back from beginning to ** end. We use the OP_Sort opcode instead of OP_Rewind to do the ** rewinding so that the global variable will be incremented and ** regression tests can determine whether or not the optimizer is ** correctly optimizing out sorts. */ case OP_SorterSort: /* jump */ | < < < | 4403 4404 4405 4406 4407 4408 4409 4410 4411 4412 4413 4414 4415 4416 | ** then rewinding that index and playing it back from beginning to ** end. We use the OP_Sort opcode instead of OP_Rewind to do the ** rewinding so that the global variable will be incremented and ** regression tests can determine whether or not the optimizer is ** correctly optimizing out sorts. */ case OP_SorterSort: /* jump */ case OP_Sort: { /* jump */ #ifdef SQLITE_TEST sqlite3_sort_count++; sqlite3_search_count--; #endif p->aCounter[SQLITE_STMTSTATUS_SORT-1]++; /* Fall through into OP_Rewind */ |
︙ | ︙ | |||
4498 4499 4500 4501 4502 4503 4504 | ** P4 is always of type P4_ADVANCE. The function pointer points to ** sqlite3BtreePrevious(). ** ** If P5 is positive and the jump is taken, then event counter ** number P5-1 in the prepared statement is incremented. */ case OP_SorterNext: /* jump */ | < < < | 4481 4482 4483 4484 4485 4486 4487 4488 4489 4490 4491 4492 4493 4494 | ** P4 is always of type P4_ADVANCE. The function pointer points to ** sqlite3BtreePrevious(). ** ** If P5 is positive and the jump is taken, then event counter ** number P5-1 in the prepared statement is incremented. */ case OP_SorterNext: /* jump */ case OP_Prev: /* jump */ case OP_Next: { /* jump */ VdbeCursor *pC; int res; CHECK_FOR_INTERRUPT; assert( pOp->p1>=0 && pOp->p1<p->nCursor ); |
︙ | ︙ | |||
4551 4552 4553 4554 4555 4556 4557 | ** P3 is a flag that provides a hint to the b-tree layer that this ** insert is likely to be an append. ** ** This instruction only works for indices. The equivalent instruction ** for tables is OP_Insert. */ case OP_SorterInsert: /* in2 */ | < < < | 4531 4532 4533 4534 4535 4536 4537 4538 4539 4540 4541 4542 4543 4544 | ** P3 is a flag that provides a hint to the b-tree layer that this ** insert is likely to be an append. ** ** This instruction only works for indices. The equivalent instruction ** for tables is OP_Insert. */ case OP_SorterInsert: /* in2 */ case OP_IdxInsert: { /* in2 */ VdbeCursor *pC; BtCursor *pCrsr; int nKey; const char *zKey; assert( pOp->p1>=0 && pOp->p1<p->nCursor ); |
︙ | ︙ | |||
5780 5781 5782 5783 5784 5785 5786 | assert(pVtab && pModule); rc = pModule->xOpen(pVtab, &pVtabCursor); importVtabErrMsg(p, pVtab); if( SQLITE_OK==rc ){ /* Initialize sqlite3_vtab_cursor base class */ pVtabCursor->pVtab = pVtab; | | | 5757 5758 5759 5760 5761 5762 5763 5764 5765 5766 5767 5768 5769 5770 5771 | assert(pVtab && pModule); rc = pModule->xOpen(pVtab, &pVtabCursor); importVtabErrMsg(p, pVtab); if( SQLITE_OK==rc ){ /* Initialize sqlite3_vtab_cursor base class */ pVtabCursor->pVtab = pVtab; /* Initialize vdbe cursor object */ pCur = allocateCursor(p, pOp->p1, 0, -1, 0); if( pCur ){ pCur->pVtabCursor = pVtabCursor; pCur->pModule = pVtabCursor->pVtab->pModule; }else{ db->mallocFailed = 1; pModule->xClose(pVtabCursor); |
︙ | ︙ |
Changes to src/vdbeInt.h.
︙ | ︙ | |||
14 15 16 17 18 19 20 21 22 23 24 25 26 27 | ** source code file "vdbe.c". When that file became too big (over ** 6000 lines long) it was split up into several smaller files and ** this header information was factored out. */ #ifndef _VDBEINT_H_ #define _VDBEINT_H_ /* ** SQL is translated into a sequence of instructions to be ** executed by a virtual machine. Each instruction is an instance ** of the following structure. */ typedef struct VdbeOp Op; | > > > > > > > > | 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | ** source code file "vdbe.c". When that file became too big (over ** 6000 lines long) it was split up into several smaller files and ** this header information was factored out. */ #ifndef _VDBEINT_H_ #define _VDBEINT_H_ /* ** The maximum number of times that a statement will try to reparse ** itself before giving up and returning SQLITE_SCHEMA. */ #ifndef SQLITE_MAX_SCHEMA_RETRY # define SQLITE_MAX_SCHEMA_RETRY 50 #endif /* ** SQL is translated into a sequence of instructions to be ** executed by a virtual machine. Each instruction is an instance ** of the following structure. */ typedef struct VdbeOp Op; |
︙ | ︙ | |||
425 426 427 428 429 430 431 | int sqlite3VdbeMemGrow(Mem *pMem, int n, int preserve); int sqlite3VdbeCloseStatement(Vdbe *, int); void sqlite3VdbeFrameDelete(VdbeFrame*); int sqlite3VdbeFrameRestore(VdbeFrame *); void sqlite3VdbeMemStoreType(Mem *pMem); int sqlite3VdbeTransferError(Vdbe *p); | < < < < < < < < < < | 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 | int sqlite3VdbeMemGrow(Mem *pMem, int n, int preserve); int sqlite3VdbeCloseStatement(Vdbe *, int); void sqlite3VdbeFrameDelete(VdbeFrame*); int sqlite3VdbeFrameRestore(VdbeFrame *); void sqlite3VdbeMemStoreType(Mem *pMem); int sqlite3VdbeTransferError(Vdbe *p); int sqlite3VdbeSorterInit(sqlite3 *, VdbeCursor *); void sqlite3VdbeSorterClose(sqlite3 *, VdbeCursor *); int sqlite3VdbeSorterRowkey(const VdbeCursor *, Mem *); int sqlite3VdbeSorterNext(sqlite3 *, const VdbeCursor *, int *); int sqlite3VdbeSorterRewind(sqlite3 *, const VdbeCursor *, int *); int sqlite3VdbeSorterWrite(sqlite3 *, const VdbeCursor *, Mem *); int sqlite3VdbeSorterCompare(const VdbeCursor *, Mem *, int *); #if !defined(SQLITE_OMIT_SHARED_CACHE) && SQLITE_THREADSAFE>0 void sqlite3VdbeEnter(Vdbe*); void sqlite3VdbeLeave(Vdbe*); #else # define sqlite3VdbeEnter(X) # define sqlite3VdbeLeave(X) |
︙ | ︙ |
Changes to src/vdbeapi.c.
︙ | ︙ | |||
441 442 443 444 445 446 447 | */ assert( rc==SQLITE_ROW || rc==SQLITE_DONE || rc==SQLITE_ERROR || rc==SQLITE_BUSY || rc==SQLITE_MISUSE ); assert( p->rc!=SQLITE_ROW && p->rc!=SQLITE_DONE ); if( p->isPrepareV2 && rc!=SQLITE_ROW && rc!=SQLITE_DONE ){ /* If this statement was prepared using sqlite3_prepare_v2(), and an | | < < < < < < < < | 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 | */ assert( rc==SQLITE_ROW || rc==SQLITE_DONE || rc==SQLITE_ERROR || rc==SQLITE_BUSY || rc==SQLITE_MISUSE ); assert( p->rc!=SQLITE_ROW && p->rc!=SQLITE_DONE ); if( p->isPrepareV2 && rc!=SQLITE_ROW && rc!=SQLITE_DONE ){ /* If this statement was prepared using sqlite3_prepare_v2(), and an ** error has occurred, then return the error code in p->rc to the ** caller. Set the error code in the database handle to the same value. */ rc = sqlite3VdbeTransferError(p); } return (rc&db->errMask); } /* ** This is the top-level implementation of sqlite3_step(). Call ** sqlite3Step() to do most of the work. If a schema error occurs, ** call sqlite3Reprepare() and try again. */ int sqlite3_step(sqlite3_stmt *pStmt){ int rc = SQLITE_OK; /* Result from sqlite3Step() */ |
︙ | ︙ |
Changes to src/vdbeaux.c.
︙ | ︙ | |||
371 372 373 374 375 376 377 | ){ hasAbort = 1; break; } } sqlite3DbFree(v->db, sIter.apSub); | | | 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 | ){ hasAbort = 1; break; } } sqlite3DbFree(v->db, sIter.apSub); /* Return true if hasAbort==mayAbort. Or if a malloc failure occurred. ** If malloc failed, then the while() loop above may not have iterated ** through all opcodes and hasAbort may be set incorrectly. Return ** true for this case to prevent the assert() in the callers frame ** from failing. */ return ( v->db->mallocFailed || hasAbort==mayAbort ); } #endif /* SQLITE_DEBUG - the sqlite3AssertMayAbort() function */ |
︙ | ︙ | |||
2003 2004 2005 2006 2007 2008 2009 | */ int sqlite3VdbeCloseStatement(Vdbe *p, int eOp){ sqlite3 *const db = p->db; int rc = SQLITE_OK; /* If p->iStatement is greater than zero, then this Vdbe opened a ** statement transaction that should be closed here. The only exception | | | 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 | */ int sqlite3VdbeCloseStatement(Vdbe *p, int eOp){ sqlite3 *const db = p->db; int rc = SQLITE_OK; /* If p->iStatement is greater than zero, then this Vdbe opened a ** statement transaction that should be closed here. The only exception ** is that an IO error may have occurred, causing an emergency rollback. ** In this case (db->nStatement==0), and there is nothing to do. */ if( db->nStatement && p->iStatement ){ int i; const int iSavepoint = p->iStatement-1; assert( eOp==SAVEPOINT_ROLLBACK || eOp==SAVEPOINT_RELEASE); |
︙ | ︙ | |||
2139 2140 2141 2142 2143 2144 2145 | /* If the query was read-only and the error code is SQLITE_INTERRUPT, ** no rollback is necessary. Otherwise, at least a savepoint ** transaction must be rolled back to restore the database to a ** consistent state. ** ** Even if the statement is read-only, it is important to perform ** a statement or transaction rollback operation. If the error | | | 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 | /* If the query was read-only and the error code is SQLITE_INTERRUPT, ** no rollback is necessary. Otherwise, at least a savepoint ** transaction must be rolled back to restore the database to a ** consistent state. ** ** Even if the statement is read-only, it is important to perform ** a statement or transaction rollback operation. If the error ** occurred while writing to the journal, sub-journal or database ** file as part of an effort to free up cache space (see function ** pagerStress() in pager.c), the rollback is required to restore ** the pager to a consistent state. */ if( !p->readOnly || mrc!=SQLITE_INTERRUPT ){ if( (mrc==SQLITE_NOMEM || mrc==SQLITE_FULL) && p->usesStmtJournal ){ eStatementOp = SAVEPOINT_ROLLBACK; |
︙ | ︙ | |||
2553 2554 2555 2556 2557 2558 2559 | ** 'serial-type' and a blob of data. The serial type is an 8-byte unsigned ** integer, stored as a varint. ** ** In an SQLite index record, the serial type is stored directly before ** the blob of data that it corresponds to. In a table record, all serial ** types are stored at the start of the record, and the blobs of data at ** the end. Hence these functions allow the caller to handle the | | | 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 | ** 'serial-type' and a blob of data. The serial type is an 8-byte unsigned ** integer, stored as a varint. ** ** In an SQLite index record, the serial type is stored directly before ** the blob of data that it corresponds to. In a table record, all serial ** types are stored at the start of the record, and the blobs of data at ** the end. Hence these functions allow the caller to handle the ** serial-type and data blob separately. ** ** The following table describes the various storage classes for data: ** ** serial type bytes of data type ** -------------- --------------- --------------- ** 0 0 NULL ** 1 1 signed integer |
︙ | ︙ |
Changes to src/vdbeblob.c.
︙ | ︙ | |||
309 310 311 312 313 314 315 | pBlob->db = db; sqlite3BtreeLeaveAll(db); if( db->mallocFailed ){ goto blob_open_out; } sqlite3_bind_int64(pBlob->pStmt, 1, iRow); rc = blobSeekToRow(pBlob, iRow, &zErr); | | | 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 | pBlob->db = db; sqlite3BtreeLeaveAll(db); if( db->mallocFailed ){ goto blob_open_out; } sqlite3_bind_int64(pBlob->pStmt, 1, iRow); rc = blobSeekToRow(pBlob, iRow, &zErr); } while( (++nAttempt)<SQLITE_MAX_SCHEMA_RETRY && rc==SQLITE_SCHEMA ); blob_open_out: if( rc==SQLITE_OK && db->mallocFailed==0 ){ *ppBlob = (sqlite3_blob *)pBlob; }else{ if( pBlob && pBlob->pStmt ) sqlite3VdbeFinalize((Vdbe *)pBlob->pStmt); sqlite3DbFree(db, pBlob); |
︙ | ︙ |
Changes to src/vdbesort.c.
︙ | ︙ | |||
14 15 16 17 18 19 20 | ** example, by CREATE INDEX statements on tables too large to fit in main ** memory). */ #include "sqliteInt.h" #include "vdbeInt.h" | < | 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | ** example, by CREATE INDEX statements on tables too large to fit in main ** memory). */ #include "sqliteInt.h" #include "vdbeInt.h" typedef struct VdbeSorterIter VdbeSorterIter; typedef struct SorterRecord SorterRecord; typedef struct FileWriter FileWriter; /* ** NOTES ON DATA STRUCTURE USED FOR N-WAY MERGES: |
︙ | ︙ | |||
1033 1034 1035 1036 1037 1038 1039 | VdbeSorter *pSorter = pCsr->pSorter; void *pKey; int nKey; /* Sorter key to compare pVal with */ pKey = vdbeSorterRowkey(pSorter, &nKey); vdbeSorterCompare(pCsr, 1, pVal->z, pVal->n, pKey, nKey, pRes); return SQLITE_OK; } | < < | 1032 1033 1034 1035 1036 1037 1038 | VdbeSorter *pSorter = pCsr->pSorter; void *pKey; int nKey; /* Sorter key to compare pVal with */ pKey = vdbeSorterRowkey(pSorter, &nKey); vdbeSorterCompare(pCsr, 1, pVal->z, pVal->n, pKey, nKey, pRes); return SQLITE_OK; } |
Changes to src/vdbetrace.c.
︙ | ︙ | |||
48 49 50 51 52 53 54 55 56 57 58 59 60 61 | /* ** This function returns a pointer to a nul-terminated string in memory ** obtained from sqlite3DbMalloc(). If sqlite3.vdbeExecCnt is 1, then the ** string contains a copy of zRawSql but with host parameters expanded to ** their current bindings. Or, if sqlite3.vdbeExecCnt is greater than 1, ** then the returned string holds a copy of zRawSql with "-- " prepended ** to each line of text. ** ** The calling function is responsible for making sure the memory returned ** is eventually freed. ** ** ALGORITHM: Scan the input string looking for host parameters in any of ** these forms: ?, ?N, $A, @A, :A. Take care to avoid text within ** string literals, quoted identifier names, and comments. For text forms, | > > > > > | 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | /* ** This function returns a pointer to a nul-terminated string in memory ** obtained from sqlite3DbMalloc(). If sqlite3.vdbeExecCnt is 1, then the ** string contains a copy of zRawSql but with host parameters expanded to ** their current bindings. Or, if sqlite3.vdbeExecCnt is greater than 1, ** then the returned string holds a copy of zRawSql with "-- " prepended ** to each line of text. ** ** If the SQLITE_TRACE_SIZE_LIMIT macro is defined to an integer, then ** then long strings and blobs are truncated to that many bytes. This ** can be used to prevent unreasonably large trace strings when dealing ** with large (multi-megabyte) strings and blobs. ** ** The calling function is responsible for making sure the memory returned ** is eventually freed. ** ** ALGORITHM: Scan the input string looking for host parameters in any of ** these forms: ?, ?N, $A, @A, :A. Take care to avoid text within ** string literals, quoted identifier names, and comments. For text forms, |
︙ | ︙ | |||
119 120 121 122 123 124 125 126 127 | if( pVar->flags & MEM_Null ){ sqlite3StrAccumAppend(&out, "NULL", 4); }else if( pVar->flags & MEM_Int ){ sqlite3XPrintf(&out, "%lld", pVar->u.i); }else if( pVar->flags & MEM_Real ){ sqlite3XPrintf(&out, "%!.15g", pVar->r); }else if( pVar->flags & MEM_Str ){ #ifndef SQLITE_OMIT_UTF16 u8 enc = ENC(db); | > < > > > > > > > > > > > | > > > > | < < < < > > > > > | > > > | 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 | if( pVar->flags & MEM_Null ){ sqlite3StrAccumAppend(&out, "NULL", 4); }else if( pVar->flags & MEM_Int ){ sqlite3XPrintf(&out, "%lld", pVar->u.i); }else if( pVar->flags & MEM_Real ){ sqlite3XPrintf(&out, "%!.15g", pVar->r); }else if( pVar->flags & MEM_Str ){ int nOut; /* Number of bytes of the string text to include in output */ #ifndef SQLITE_OMIT_UTF16 u8 enc = ENC(db); Mem utf8; if( enc!=SQLITE_UTF8 ){ memset(&utf8, 0, sizeof(utf8)); utf8.db = db; sqlite3VdbeMemSetStr(&utf8, pVar->z, pVar->n, enc, SQLITE_STATIC); sqlite3VdbeChangeEncoding(&utf8, SQLITE_UTF8); pVar = &utf8; } #endif nOut = pVar->n; #ifdef SQLITE_TRACE_SIZE_LIMIT if( n>SQLITE_TRACE_SIZE_LIMIT ){ nOut = SQLITE_TRACE_SIZE_LIMIT; while( nOut<pVar->n && (pVar->z[n]&0xc0)==0x80 ){ n++; } } #endif sqlite3XPrintf(&out, "'%.*q'", nOut, pVar->z); #ifdef SQLITE_TRACE_SIZE_LIMIT if( nOut<pVar->n ) sqlite3XPrintf(&out, "/*+%d bytes*/", pVar->n-n); #endif #ifndef SQLITE_OMIT_UTF16 if( enc!=SQLITE_UTF8 ) sqlite3VdbeMemRelease(&utf8); #endif }else if( pVar->flags & MEM_Zero ){ sqlite3XPrintf(&out, "zeroblob(%d)", pVar->u.nZero); }else{ int nOut; /* Number of bytes of the blob to include in output */ assert( pVar->flags & MEM_Blob ); sqlite3StrAccumAppend(&out, "x'", 2); nOut = pVar->n; #ifdef SQLITE_TRACE_SIZE_LIMIT if( nOut>SQLITE_TRACE_SIZE_LIMIT ) nOut = SQLITE_TRACE_SIZE_LIMIT; #endif for(i=0; i<nOut; i++){ sqlite3XPrintf(&out, "%02x", pVar->z[i]&0xff); } sqlite3StrAccumAppend(&out, "'", 1); #ifdef SQLITE_TRACE_SIZE_LIMIT if( nOut<pVar->n ) sqlite3XPrintf(&out, "/*+%d bytes*/", pVar->n-n); #endif } } } return sqlite3StrAccumFinish(&out); } #endif /* #ifndef SQLITE_OMIT_TRACE */ |
︙ | ︙ |
Changes to src/wal.c.
︙ | ︙ | |||
1203 1204 1205 1206 1207 1208 1209 | /* If more than one frame was recovered from the log file, report an ** event via sqlite3_log(). This is to help with identifying performance ** problems caused by applications routinely shutting down without ** checkpointing the log file. */ if( pWal->hdr.nPage ){ | > | | | 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 | /* If more than one frame was recovered from the log file, report an ** event via sqlite3_log(). This is to help with identifying performance ** problems caused by applications routinely shutting down without ** checkpointing the log file. */ if( pWal->hdr.nPage ){ sqlite3_log(SQLITE_NOTICE_RECOVER_WAL, "recovered %d frames from WAL file %s", pWal->hdr.mxFrame, pWal->zWalName ); } } recovery_error: WALTRACE(("WAL%p: recovery %s\n", pWal, rc ? "failed" : "ok")); walUnlockExclusive(pWal, iLock, nLock); |
︙ | ︙ | |||
1718 1719 1720 1721 1722 1723 1724 | u32 nBackfill = pInfo->nBackfill; /* Sync the WAL to disk */ if( sync_flags ){ rc = sqlite3OsSync(pWal->pWalFd, sync_flags); } | | > | 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 | u32 nBackfill = pInfo->nBackfill; /* Sync the WAL to disk */ if( sync_flags ){ rc = sqlite3OsSync(pWal->pWalFd, sync_flags); } /* If the database may grow as a result of this checkpoint, hint ** about the eventual size of the db file to the VFS layer. */ if( rc==SQLITE_OK ){ i64 nReq = ((i64)mxPage * szPage); rc = sqlite3OsFileSize(pWal->pDbFd, &nSize); if( rc==SQLITE_OK && nSize<nReq ){ sqlite3OsFileControlHint(pWal->pDbFd, SQLITE_FCNTL_SIZE_HINT, &nReq); } } /* Iterate through the contents of the WAL, copying data to the db file. */ while( rc==SQLITE_OK && 0==walIteratorNext(pIter, &iDbpage, &iFrame) ){ i64 iOffset; assert( walFramePgno(pWal, iFrame)==iDbpage ); if( iFrame<=nBackfill || iFrame>mxSafeFrame || iDbpage>mxPage ) continue; iOffset = walFrameOffset(iFrame, szPage) + WAL_FRAME_HDRSIZE; |
︙ | ︙ | |||
2283 2284 2285 2286 2287 2288 2289 | if( pWal->readLock>=0 ){ walUnlockShared(pWal, WAL_READ_LOCK(pWal->readLock)); pWal->readLock = -1; } } /* | | > | < | | | | < < | | 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 | if( pWal->readLock>=0 ){ walUnlockShared(pWal, WAL_READ_LOCK(pWal->readLock)); pWal->readLock = -1; } } /* ** Search the wal file for page pgno. If found, set *piRead to the frame that ** contains the page. Otherwise, if pgno is not in the wal file, set *piRead ** to zero. ** ** Return SQLITE_OK if successful, or an error code if an error occurs. If an ** error does occur, the final value of *piRead is undefined. */ int sqlite3WalFindFrame( Wal *pWal, /* WAL handle */ Pgno pgno, /* Database page number to read data for */ u32 *piRead /* OUT: Frame number (or zero) */ ){ u32 iRead = 0; /* If !=0, WAL frame to return data from */ u32 iLast = pWal->hdr.mxFrame; /* Last page in WAL for this reader */ int iHash; /* Used to loop through N hash tables */ /* This routine is only be called from within a read transaction. */ assert( pWal->readLock>=0 || pWal->lockError ); /* If the "last page" field of the wal-index header snapshot is 0, then ** no data will be read from the wal under any circumstances. Return early ** in this case as an optimization. Likewise, if pWal->readLock==0, ** then the WAL is ignored by the reader so return early, as if the ** WAL were empty. */ if( iLast==0 || pWal->readLock==0 ){ *piRead = 0; return SQLITE_OK; } /* Search the hash table or tables for an entry matching page number ** pgno. Each iteration of the following for() loop searches one ** hash table (each hash table indexes up to HASHTABLE_NPAGE frames). ** |
︙ | ︙ | |||
2382 2383 2384 2385 2386 2387 2388 | break; } } assert( iRead==iRead2 ); } #endif | | > > | > > > > > > > > > | < < < < < < | 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 2420 | break; } } assert( iRead==iRead2 ); } #endif *piRead = iRead; return SQLITE_OK; } /* ** Read the contents of frame iRead from the wal file into buffer pOut ** (which is nOut bytes in size). Return SQLITE_OK if successful, or an ** error code otherwise. */ int sqlite3WalReadFrame( Wal *pWal, /* WAL handle */ u32 iRead, /* Frame to read */ int nOut, /* Size of buffer pOut in bytes */ u8 *pOut /* Buffer to write page data to */ ){ int sz; i64 iOffset; sz = pWal->hdr.szPage; sz = (sz&0xfe00) + ((sz&0x0001)<<16); testcase( sz<=32768 ); testcase( sz>=65536 ); iOffset = walFrameOffset(iRead, sz) + WAL_FRAME_HDRSIZE; /* testcase( IS_BIG_INT(iOffset) ); // requires a 4GiB WAL */ return sqlite3OsRead(pWal->pWalFd, pOut, (nOut>sz ? sz : nOut), iOffset); } /* ** Return the size of the database in pages (or zero, if unknown). */ Pgno sqlite3WalDbsize(Wal *pWal){ if( pWal && ALWAYS(pWal->readLock>=0) ){ return pWal->hdr.nPage; |
︙ | ︙ | |||
2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 | rc = SQLITE_OK; } } /* Read the wal-index header. */ if( rc==SQLITE_OK ){ rc = walIndexReadHdr(pWal, &isChanged); } /* Copy data from the log to the database file. */ if( rc==SQLITE_OK ){ if( pWal->hdr.mxFrame && walPagesize(pWal)!=nBuf ){ rc = SQLITE_CORRUPT_BKPT; }else{ | > > > | 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 | rc = SQLITE_OK; } } /* Read the wal-index header. */ if( rc==SQLITE_OK ){ rc = walIndexReadHdr(pWal, &isChanged); if( isChanged && pWal->pDbFd->pMethods->iVersion>=3 ){ sqlite3OsUnfetch(pWal->pDbFd, 0, 0); } } /* Copy data from the log to the database file. */ if( rc==SQLITE_OK ){ if( pWal->hdr.mxFrame && walPagesize(pWal)!=nBuf ){ rc = SQLITE_CORRUPT_BKPT; }else{ |
︙ | ︙ |
Changes to src/wal.h.
︙ | ︙ | |||
27 28 29 30 31 32 33 | #ifdef SQLITE_OMIT_WAL # define sqlite3WalOpen(x,y,z) 0 # define sqlite3WalLimit(x,y) # define sqlite3WalClose(w,x,y,z) 0 # define sqlite3WalBeginReadTransaction(y,z) 0 # define sqlite3WalEndReadTransaction(z) | < > | 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 | #ifdef SQLITE_OMIT_WAL # define sqlite3WalOpen(x,y,z) 0 # define sqlite3WalLimit(x,y) # define sqlite3WalClose(w,x,y,z) 0 # define sqlite3WalBeginReadTransaction(y,z) 0 # define sqlite3WalEndReadTransaction(z) # define sqlite3WalDbsize(y) 0 # define sqlite3WalBeginWriteTransaction(y) 0 # define sqlite3WalEndWriteTransaction(x) 0 # define sqlite3WalUndo(x,y,z) 0 # define sqlite3WalSavepoint(y,z) # define sqlite3WalSavepointUndo(y,z) 0 # define sqlite3WalFrames(u,v,w,x,y,z) 0 # define sqlite3WalCheckpoint(r,s,t,u,v,w,x,y,z) 0 # define sqlite3WalCallback(z) 0 # define sqlite3WalExclusiveMode(y,z) 0 # define sqlite3WalHeapMemory(z) 0 # define sqlite3WalFramesize(z) 0 # define sqlite3WalFindFrame(x,y,z) 0 #else #define WAL_SAVEPOINT_NDATA 4 /* Connection to a write-ahead log (WAL) file. ** There is one object of this type for each pager. */ |
︙ | ︙ | |||
67 68 69 70 71 72 73 | ** write to or checkpoint the WAL. sqlite3WalCloseSnapshot() closes the ** transaction and releases the lock. */ int sqlite3WalBeginReadTransaction(Wal *pWal, int *); void sqlite3WalEndReadTransaction(Wal *pWal); /* Read a page from the write-ahead log, if it is present. */ | > | | 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 | ** write to or checkpoint the WAL. sqlite3WalCloseSnapshot() closes the ** transaction and releases the lock. */ int sqlite3WalBeginReadTransaction(Wal *pWal, int *); void sqlite3WalEndReadTransaction(Wal *pWal); /* Read a page from the write-ahead log, if it is present. */ int sqlite3WalFindFrame(Wal *, Pgno, u32 *); int sqlite3WalReadFrame(Wal *, u32, int, u8 *); /* If the WAL is not empty, return the size of the database. */ Pgno sqlite3WalDbsize(Wal *pWal); /* Obtain or release the WRITER lock. */ int sqlite3WalBeginWriteTransaction(Wal *pWal); int sqlite3WalEndWriteTransaction(Wal *pWal); |
︙ | ︙ |
Changes to src/walker.c.
︙ | ︙ | |||
109 110 111 112 113 114 115 | } return WRC_Continue; } /* ** Call sqlite3WalkExpr() for every expression in Select statement p. ** Invoke sqlite3WalkSelect() for subqueries in the FROM clause and | | > > > > > > > > > > > | 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 | } return WRC_Continue; } /* ** Call sqlite3WalkExpr() for every expression in Select statement p. ** Invoke sqlite3WalkSelect() for subqueries in the FROM clause and ** on the compound select chain, p->pPrior. Invoke the xSelectCallback() ** either before or after the walk of expressions and FROM clause, depending ** on whether pWalker->bSelectDepthFirst is false or true, respectively. ** ** Return WRC_Continue under normal conditions. Return WRC_Abort if ** there is an abort request. ** ** If the Walker does not have an xSelectCallback() then this routine ** is a no-op returning WRC_Continue. */ int sqlite3WalkSelect(Walker *pWalker, Select *p){ int rc; if( p==0 || pWalker->xSelectCallback==0 ) return WRC_Continue; rc = WRC_Continue; pWalker->walkerDepth++; while( p ){ if( !pWalker->bSelectDepthFirst ){ rc = pWalker->xSelectCallback(pWalker, p); if( rc ) break; } if( sqlite3WalkSelectExpr(pWalker, p) || sqlite3WalkSelectFrom(pWalker, p) ){ pWalker->walkerDepth--; return WRC_Abort; } if( pWalker->bSelectDepthFirst ){ rc = pWalker->xSelectCallback(pWalker, p); /* Depth-first search is currently only used for ** selectAddSubqueryTypeInfo() and that routine always returns ** WRC_Continue (0). So the following branch is never taken. */ if( NEVER(rc) ) break; } p = p->pPrior; } pWalker->walkerDepth--; return rc & WRC_Abort; } |
Changes to src/where.c.
︙ | ︙ | |||
258 259 260 261 262 263 264 265 266 267 268 269 270 271 | #define WHERE_BTM_LIMIT 0x00200000 /* x>EXPR or x>=EXPR constraint */ #define WHERE_BOTH_LIMIT 0x00300000 /* Both x>EXPR and x<EXPR */ #define WHERE_IDX_ONLY 0x00400000 /* Use index only - omit table */ #define WHERE_ORDERED 0x00800000 /* Output will appear in correct order */ #define WHERE_REVERSE 0x01000000 /* Scan in reverse order */ #define WHERE_UNIQUE 0x02000000 /* Selects no more than one row */ #define WHERE_ALL_UNIQUE 0x04000000 /* This and all prior have one row */ #define WHERE_VIRTUALTABLE 0x08000000 /* Use virtual-table processing */ #define WHERE_MULTI_OR 0x10000000 /* OR using multiple indices */ #define WHERE_TEMP_INDEX 0x20000000 /* Uses an ephemeral index */ #define WHERE_DISTINCT 0x40000000 /* Correct order for DISTINCT */ #define WHERE_COVER_SCAN 0x80000000 /* Full scan of a covering index */ /* | > > | 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 | #define WHERE_BTM_LIMIT 0x00200000 /* x>EXPR or x>=EXPR constraint */ #define WHERE_BOTH_LIMIT 0x00300000 /* Both x>EXPR and x<EXPR */ #define WHERE_IDX_ONLY 0x00400000 /* Use index only - omit table */ #define WHERE_ORDERED 0x00800000 /* Output will appear in correct order */ #define WHERE_REVERSE 0x01000000 /* Scan in reverse order */ #define WHERE_UNIQUE 0x02000000 /* Selects no more than one row */ #define WHERE_ALL_UNIQUE 0x04000000 /* This and all prior have one row */ #define WHERE_OB_UNIQUE 0x00004000 /* Values in ORDER BY columns are ** different for every output row */ #define WHERE_VIRTUALTABLE 0x08000000 /* Use virtual-table processing */ #define WHERE_MULTI_OR 0x10000000 /* OR using multiple indices */ #define WHERE_TEMP_INDEX 0x20000000 /* Uses an ephemeral index */ #define WHERE_DISTINCT 0x40000000 /* Correct order for DISTINCT */ #define WHERE_COVER_SCAN 0x80000000 /* Full scan of a covering index */ /* |
︙ | ︙ | |||
558 559 560 561 562 563 564 | */ #define SWAP(TYPE,A,B) {TYPE t=A; A=B; B=t;} /* ** Commute a comparison operator. Expressions of the form "X op Y" ** are converted into "Y op X". ** | | | 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 | */ #define SWAP(TYPE,A,B) {TYPE t=A; A=B; B=t;} /* ** Commute a comparison operator. Expressions of the form "X op Y" ** are converted into "Y op X". ** ** If left/right precedence rules come into play when determining the ** collating ** side of the comparison, it remains associated with the same side after ** the commutation. So "Y collate NOCASE op X" becomes ** "X op Y". This is because any collation sequence on ** the left hand side of a comparison overrides any collation sequence ** attached to the right. For the same reason the EP_Collate flag ** is not commuted. |
︙ | ︙ | |||
699 700 701 702 703 704 705 | for(j=0; pIdx->aiColumn[j]!=iOrigCol; j++){ if( NEVER(j>=pIdx->nColumn) ) return 0; } if( sqlite3StrICmp(pColl->zName, pIdx->azColl[j]) ){ continue; } } | | | 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 | for(j=0; pIdx->aiColumn[j]!=iOrigCol; j++){ if( NEVER(j>=pIdx->nColumn) ) return 0; } if( sqlite3StrICmp(pColl->zName, pIdx->azColl[j]) ){ continue; } } if( pTerm->prereqRight==0 && (pTerm->eOperator&WO_EQ)!=0 ){ pResult = pTerm; goto findTerm_success; }else if( pResult==0 ){ pResult = pTerm; } } if( (pTerm->eOperator & WO_EQUIV)!=0 |
︙ | ︙ | |||
2269 2270 2271 2272 2273 2274 2275 | WhereClause *pWC = p->pWC; /* The WHERE clause */ struct SrcList_item *pSrc = p->pSrc; /* The FROM clause term to search */ Table *pTab = pSrc->pTab; sqlite3_index_info *pIdxInfo; struct sqlite3_index_constraint *pIdxCons; struct sqlite3_index_constraint_usage *pUsage; WhereTerm *pTerm; | | < | 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 | WhereClause *pWC = p->pWC; /* The WHERE clause */ struct SrcList_item *pSrc = p->pSrc; /* The FROM clause term to search */ Table *pTab = pSrc->pTab; sqlite3_index_info *pIdxInfo; struct sqlite3_index_constraint *pIdxCons; struct sqlite3_index_constraint_usage *pUsage; WhereTerm *pTerm; int i, j; int nOrderBy; int bAllowIN; /* Allow IN optimizations */ double rCost; /* Make sure wsFlags is initialized to some sane value. Otherwise, if the ** malloc in allocateIndexInfo() fails and this function returns leaving ** wsFlags in an uninitialized state, the caller may behave unpredictably. */ |
︙ | ︙ | |||
2370 2371 2372 2373 2374 2375 2376 | pIdxInfo->nOrderBy = 0; } if( vtabBestIndex(pParse, pTab, pIdxInfo) ){ return; } | < | | > > > | < < < > > > > > > > > > > > | 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 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 2420 | pIdxInfo->nOrderBy = 0; } if( vtabBestIndex(pParse, pTab, pIdxInfo) ){ return; } pIdxCons = *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint; for(i=0; i<pIdxInfo->nConstraint; i++, pIdxCons++){ if( pUsage[i].argvIndex>0 ){ j = pIdxCons->iTermOffset; pTerm = &pWC->a[j]; p->cost.used |= pTerm->prereqRight; if( (pTerm->eOperator & WO_IN)!=0 ){ if( pUsage[i].omit==0 ){ /* Do not attempt to use an IN constraint if the virtual table ** says that the equivalent EQ constraint cannot be safely omitted. ** If we do attempt to use such a constraint, some rows might be ** repeated in the output. */ break; } /* 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>=pIdxInfo->nConstraint ) break; } /* The orderByConsumed signal is only valid if all outer loops collectively ** generate just a single row of output. */ if( pIdxInfo->orderByConsumed ){ for(i=0; i<p->i; i++){ if( (p->aLevel[i].plan.wsFlags & WHERE_UNIQUE)==0 ){ pIdxInfo->orderByConsumed = 0; } } } /* If there is an ORDER BY clause, and the selected virtual table index ** does not satisfy it, increase the cost of the scan accordingly. This ** matches the processing for non-virtual tables in bestBtreeIndex(). */ rCost = pIdxInfo->estimatedCost; if( p->pOrderBy && pIdxInfo->orderByConsumed==0 ){ |
︙ | ︙ | |||
2420 2421 2422 2423 2424 2425 2426 | if( (SQLITE_BIG_DBL/((double)2))<rCost ){ p->cost.rCost = (SQLITE_BIG_DBL/((double)2)); }else{ p->cost.rCost = rCost; } p->cost.plan.u.pVtabIdx = pIdxInfo; if( pIdxInfo->orderByConsumed ){ | < | | 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 | if( (SQLITE_BIG_DBL/((double)2))<rCost ){ p->cost.rCost = (SQLITE_BIG_DBL/((double)2)); }else{ p->cost.rCost = rCost; } p->cost.plan.u.pVtabIdx = pIdxInfo; if( pIdxInfo->orderByConsumed ){ p->cost.plan.wsFlags |= WHERE_ORDERED; p->cost.plan.nOBSat = nOrderBy; }else{ p->cost.plan.nOBSat = p->i ? p->aLevel[p->i-1].plan.nOBSat : 0; } p->cost.plan.nEq = 0; pIdxInfo->nOrderBy = nOrderBy; |
︙ | ︙ | |||
2899 2900 2901 2902 2903 2904 2905 | ** The *pbRev value is set to 0 order 1 depending on whether or not ** pIdx should be run in the forward order or in reverse order. */ static int isSortingIndex( WhereBestIdx *p, /* Best index search context */ Index *pIdx, /* The index we are testing */ int base, /* Cursor number for the table to be sorted */ | | > > > > > | > > > | 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 | ** The *pbRev value is set to 0 order 1 depending on whether or not ** pIdx should be run in the forward order or in reverse order. */ static int isSortingIndex( WhereBestIdx *p, /* Best index search context */ Index *pIdx, /* The index we are testing */ int base, /* Cursor number for the table to be sorted */ int *pbRev, /* Set to 1 for reverse-order scan of pIdx */ int *pbObUnique /* ORDER BY column values will different in every row */ ){ int i; /* Number of pIdx terms used */ int j; /* Number of ORDER BY terms satisfied */ int sortOrder = 2; /* 0: forward. 1: backward. 2: unknown */ int nTerm; /* Number of ORDER BY terms */ struct ExprList_item *pOBItem;/* A term of the ORDER BY clause */ Table *pTab = pIdx->pTable; /* Table that owns index pIdx */ ExprList *pOrderBy; /* The ORDER BY clause */ Parse *pParse = p->pParse; /* Parser context */ sqlite3 *db = pParse->db; /* Database connection */ int nPriorSat; /* ORDER BY terms satisfied by outer loops */ int seenRowid = 0; /* True if an ORDER BY rowid term is seen */ int uniqueNotNull; /* pIdx is UNIQUE with all terms are NOT NULL */ int outerObUnique; /* Outer loops generate different values in ** every row for the ORDER BY columns */ if( p->i==0 ){ nPriorSat = 0; outerObUnique = 1; }else{ u32 wsFlags = p->aLevel[p->i-1].plan.wsFlags; nPriorSat = p->aLevel[p->i-1].plan.nOBSat; if( (wsFlags & WHERE_ORDERED)==0 ){ /* This loop cannot be ordered unless the next outer loop is ** also ordered */ return nPriorSat; } if( OptimizationDisabled(db, SQLITE_OrderByIdxJoin) ){ /* Only look at the outer-most loop if the OrderByIdxJoin ** optimization is disabled */ return nPriorSat; } testcase( wsFlags & WHERE_OB_UNIQUE ); testcase( wsFlags & WHERE_ALL_UNIQUE ); outerObUnique = (wsFlags & (WHERE_OB_UNIQUE|WHERE_ALL_UNIQUE))!=0; } pOrderBy = p->pOrderBy; assert( pOrderBy!=0 ); if( pIdx->bUnordered ){ /* Hash indices (indicated by the "unordered" tag on sqlite_stat1) cannot ** be used for sorting */ return nPriorSat; |
︙ | ︙ | |||
3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 | }else if( pTab->aCol[iColumn].notNull==0 && isEq!=1 ){ testcase( isEq==0 ); testcase( isEq==2 ); testcase( isEq==3 ); uniqueNotNull = 0; } } /* If we have not found at least one ORDER BY term that matches the ** index, then show no progress. */ if( pOBItem==&pOrderBy->a[nPriorSat] ) return nPriorSat; /* Return the necessary scan order back to the caller */ *pbRev = sortOrder & 1; /* If there was an "ORDER BY rowid" term that matched, or it is only ** possible for a single row from this table to match, then skip over ** any additional ORDER BY terms dealing with this table. */ | > > > > > > > > > > > > > > > | | 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128 | }else if( pTab->aCol[iColumn].notNull==0 && isEq!=1 ){ testcase( isEq==0 ); testcase( isEq==2 ); testcase( isEq==3 ); uniqueNotNull = 0; } } if( seenRowid ){ uniqueNotNull = 1; }else if( uniqueNotNull==0 || i<pIdx->nColumn ){ uniqueNotNull = 0; } /* If we have not found at least one ORDER BY term that matches the ** index, then show no progress. */ if( pOBItem==&pOrderBy->a[nPriorSat] ) return nPriorSat; /* Either the outer queries must generate rows where there are no two ** rows with the same values in all ORDER BY columns, or else this ** loop must generate just a single row of output. Example: Suppose ** the outer loops generate A=1 and A=1, and this loop generates B=3 ** and B=4. Then without the following test, ORDER BY A,B would ** generate the wrong order output: 1,3 1,4 1,3 1,4 */ if( outerObUnique==0 && uniqueNotNull==0 ) return nPriorSat; *pbObUnique = uniqueNotNull; /* Return the necessary scan order back to the caller */ *pbRev = sortOrder & 1; /* If there was an "ORDER BY rowid" term that matched, or it is only ** possible for a single row from this table to match, then skip over ** any additional ORDER BY terms dealing with this table. */ if( uniqueNotNull ){ /* Advance j over additional ORDER BY terms associated with base */ WhereMaskSet *pMS = p->pWC->pMaskSet; Bitmask m = ~getMask(pMS, base); while( j<nTerm && (exprTableUsage(pMS, pOrderBy->a[j].pExpr)&m)==0 ){ j++; } } |
︙ | ︙ | |||
3365 3366 3367 3368 3369 3370 3371 | /* If there is an ORDER BY clause and the index being considered will ** naturally scan rows in the required order, set the appropriate flags ** in pc.plan.wsFlags. Otherwise, if there is an ORDER BY clause but ** the index will scan rows in a different order, set the bSort ** variable. */ if( bSort && (pSrc->jointype & JT_LEFT)==0 ){ int bRev = 2; | > | | | | > | 3398 3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 | /* If there is an ORDER BY clause and the index being considered will ** naturally scan rows in the required order, set the appropriate flags ** in pc.plan.wsFlags. Otherwise, if there is an ORDER BY clause but ** the index will scan rows in a different order, set the bSort ** variable. */ if( bSort && (pSrc->jointype & JT_LEFT)==0 ){ int bRev = 2; int bObUnique = 0; WHERETRACE((" --> before isSortIndex: nPriorSat=%d\n",nPriorSat)); pc.plan.nOBSat = isSortingIndex(p, pProbe, iCur, &bRev, &bObUnique); WHERETRACE((" --> after isSortIndex: bRev=%d bObU=%d nOBSat=%d\n", bRev, bObUnique, pc.plan.nOBSat)); if( nPriorSat<pc.plan.nOBSat || (pc.plan.wsFlags & WHERE_ALL_UNIQUE)!=0 ){ pc.plan.wsFlags |= WHERE_ORDERED; if( bObUnique ) pc.plan.wsFlags |= WHERE_OB_UNIQUE; } if( nOrderBy==pc.plan.nOBSat ){ bSort = 0; pc.plan.wsFlags |= WHERE_ROWID_RANGE|WHERE_COLUMN_RANGE; } if( bRev & 1 ) pc.plan.wsFlags |= WHERE_REVERSE; } |
︙ | ︙ | |||
3464 3465 3466 3467 3468 3469 3470 | ** on one page and hence more pages have to be fetched. ** ** The ANALYZE command and the sqlite_stat1 and sqlite_stat3 tables do ** not give us data on the relative sizes of table and index records. ** So this computation assumes table records are about twice as big ** as index records */ | | > | 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 | ** on one page and hence more pages have to be fetched. ** ** The ANALYZE command and the sqlite_stat1 and sqlite_stat3 tables do ** not give us data on the relative sizes of table and index records. ** So this computation assumes table records are about twice as big ** as index records */ if( (pc.plan.wsFlags&~(WHERE_REVERSE|WHERE_ORDERED|WHERE_OB_UNIQUE)) ==WHERE_IDX_ONLY && (pWC->wctrlFlags & WHERE_ONEPASS_DESIRED)==0 && sqlite3GlobalConfig.bUseCis && OptimizationEnabled(pParse->db, SQLITE_CoverIdxScan) ){ /* This index is not useful for indexing, but it is a covering index. ** A full-scan of the index might be a little faster than a full-scan ** of the table, so give this case a cost slightly less than a table |
︙ | ︙ | |||
3624 3625 3626 3627 3628 3629 3630 | wsFlagMask = ~(WHERE_ROWID_EQ|WHERE_ROWID_RANGE); eqTermMask = idxEqTermMask; } /* If there is no ORDER BY clause and the SQLITE_ReverseOrder flag ** is set, then reverse the order that the index will be scanned ** in. This is used for application testing, to help find cases | | | 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 | wsFlagMask = ~(WHERE_ROWID_EQ|WHERE_ROWID_RANGE); eqTermMask = idxEqTermMask; } /* If there is no ORDER BY clause and the SQLITE_ReverseOrder flag ** is set, then reverse the order that the index will be scanned ** in. This is used for application testing, to help find cases ** where application behavior depends on the (undefined) order that ** SQLite outputs rows in in the absence of an ORDER BY clause. */ if( !p->pOrderBy && pParse->db->flags & SQLITE_ReverseOrder ){ p->cost.plan.wsFlags |= WHERE_REVERSE; } assert( p->pOrderBy || (p->cost.plan.wsFlags&WHERE_ORDERED)==0 ); assert( p->cost.plan.u.pIdx==0 || (p->cost.plan.wsFlags&WHERE_ROWID_EQ)==0 ); |
︙ | ︙ | |||
4132 4133 4134 4135 4136 4137 4138 4139 4140 4141 4142 4143 4144 4145 4146 4147 4148 4149 4150 4151 4152 4153 4154 4155 | Parse *pParse; /* Parsing context */ Vdbe *v; /* The prepared stmt under constructions */ struct SrcList_item *pTabItem; /* FROM clause term being coded */ int addrBrk; /* Jump here to break out of the loop */ int addrCont; /* Jump here to continue with next cycle */ int iRowidReg = 0; /* Rowid is stored in this register, if not zero */ int iReleaseReg = 0; /* Temp register to free before returning */ pParse = pWInfo->pParse; v = pParse->pVdbe; pWC = pWInfo->pWC; pLevel = &pWInfo->a[iLevel]; pTabItem = &pWInfo->pTabList->a[pLevel->iFrom]; iCur = pTabItem->iCursor; bRev = (pLevel->plan.wsFlags & WHERE_REVERSE)!=0; omitTable = (pLevel->plan.wsFlags & WHERE_IDX_ONLY)!=0 && (wctrlFlags & WHERE_FORCE_TABLE)==0; /* Create labels for the "break" and "continue" instructions ** for the current loop. Jump to addrBrk to break out of a loop. ** Jump to cont to go immediately to the next iteration of the ** loop. ** ** When there is an IN operator, we also have a "addrNxt" label that | > > | 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 | Parse *pParse; /* Parsing context */ Vdbe *v; /* The prepared stmt under constructions */ struct SrcList_item *pTabItem; /* FROM clause term being coded */ int addrBrk; /* Jump here to break out of the loop */ int addrCont; /* Jump here to continue with next cycle */ int iRowidReg = 0; /* Rowid is stored in this register, if not zero */ int iReleaseReg = 0; /* Temp register to free before returning */ Bitmask newNotReady; /* Return value */ pParse = pWInfo->pParse; v = pParse->pVdbe; pWC = pWInfo->pWC; pLevel = &pWInfo->a[iLevel]; pTabItem = &pWInfo->pTabList->a[pLevel->iFrom]; iCur = pTabItem->iCursor; bRev = (pLevel->plan.wsFlags & WHERE_REVERSE)!=0; omitTable = (pLevel->plan.wsFlags & WHERE_IDX_ONLY)!=0 && (wctrlFlags & WHERE_FORCE_TABLE)==0; VdbeNoopComment((v, "Begin Join Loop %d", iLevel)); /* Create labels for the "break" and "continue" instructions ** for the current loop. Jump to addrBrk to break out of a loop. ** Jump to cont to go immediately to the next iteration of the ** loop. ** ** When there is an IN operator, we also have a "addrNxt" label that |
︙ | ︙ | |||
4684 4685 4686 4687 4688 4689 4690 4691 4692 4693 4694 4695 4696 4697 | ** That way, terms in y that are factored into the disjunction will ** be picked up by the recursive calls to sqlite3WhereBegin() below. ** ** Actually, each subexpression is converted to "xN AND w" where w is ** the "interesting" terms of z - terms that did not originate in the ** ON or USING clause of a LEFT JOIN, and terms that are usable as ** indices. */ if( pWC->nTerm>1 ){ int iTerm; for(iTerm=0; iTerm<pWC->nTerm; iTerm++){ Expr *pExpr = pWC->a[iTerm].pExpr; if( ExprHasProperty(pExpr, EP_FromJoin) ) continue; if( pWC->a[iTerm].wtFlags & (TERM_VIRTUAL|TERM_ORINFO) ) continue; | > > > > | 4722 4723 4724 4725 4726 4727 4728 4729 4730 4731 4732 4733 4734 4735 4736 4737 4738 4739 | ** That way, terms in y that are factored into the disjunction will ** be picked up by the recursive calls to sqlite3WhereBegin() below. ** ** Actually, each subexpression is converted to "xN AND w" where w is ** the "interesting" terms of z - terms that did not originate in the ** ON or USING clause of a LEFT JOIN, and terms that are usable as ** indices. ** ** This optimization also only applies if the (x1 OR x2 OR ...) term ** is not contained in the ON clause of a LEFT JOIN. ** See ticket http://www.sqlite.org/src/info/f2369304e4 */ if( pWC->nTerm>1 ){ int iTerm; for(iTerm=0; iTerm<pWC->nTerm; iTerm++){ Expr *pExpr = pWC->a[iTerm].pExpr; if( ExprHasProperty(pExpr, EP_FromJoin) ) continue; if( pWC->a[iTerm].wtFlags & (TERM_VIRTUAL|TERM_ORINFO) ) continue; |
︙ | ︙ | |||
4705 4706 4707 4708 4709 4710 4711 | } for(ii=0; ii<pOrWc->nTerm; ii++){ WhereTerm *pOrTerm = &pOrWc->a[ii]; if( pOrTerm->leftCursor==iCur || (pOrTerm->eOperator & WO_AND)!=0 ){ WhereInfo *pSubWInfo; /* Info for single OR-term scan */ Expr *pOrExpr = pOrTerm->pExpr; | | | 4747 4748 4749 4750 4751 4752 4753 4754 4755 4756 4757 4758 4759 4760 4761 | } for(ii=0; ii<pOrWc->nTerm; ii++){ WhereTerm *pOrTerm = &pOrWc->a[ii]; if( pOrTerm->leftCursor==iCur || (pOrTerm->eOperator & WO_AND)!=0 ){ WhereInfo *pSubWInfo; /* Info for single OR-term scan */ Expr *pOrExpr = pOrTerm->pExpr; if( pAndExpr && !ExprHasProperty(pOrExpr, EP_FromJoin) ){ pAndExpr->pLeft = pOrExpr; pOrExpr = pAndExpr; } /* Loop through table entries that match term pOrTerm. */ pSubWInfo = sqlite3WhereBegin(pParse, pOrTab, pOrExpr, 0, 0, WHERE_OMIT_OPEN_CLOSE | WHERE_AND_ONLY | WHERE_FORCE_TABLE | WHERE_ONETABLE_ONLY, iCovCur); |
︙ | ︙ | |||
4792 4793 4794 4795 4796 4797 4798 | assert( bRev==0 || bRev==1 ); assert( omitTable==0 ); pLevel->op = aStep[bRev]; pLevel->p1 = iCur; pLevel->p2 = 1 + sqlite3VdbeAddOp2(v, aStart[bRev], iCur, addrBrk); pLevel->p5 = SQLITE_STMTSTATUS_FULLSCAN_STEP; } | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | 4834 4835 4836 4837 4838 4839 4840 4841 4842 4843 4844 4845 4846 4847 4848 4849 4850 4851 4852 4853 4854 4855 4856 4857 4858 4859 4860 4861 4862 4863 4864 4865 4866 4867 4868 4869 4870 4871 4872 4873 4874 4875 4876 4877 4878 4879 4880 4881 4882 4883 4884 4885 4886 4887 4888 4889 4890 4891 4892 4893 4894 4895 4896 4897 4898 4899 4900 4901 4902 4903 4904 4905 4906 4907 4908 4909 4910 4911 4912 4913 4914 4915 4916 4917 4918 4919 4920 4921 4922 4923 4924 4925 4926 4927 | assert( bRev==0 || bRev==1 ); assert( omitTable==0 ); pLevel->op = aStep[bRev]; pLevel->p1 = iCur; pLevel->p2 = 1 + sqlite3VdbeAddOp2(v, aStart[bRev], iCur, addrBrk); pLevel->p5 = SQLITE_STMTSTATUS_FULLSCAN_STEP; } newNotReady = notReady & ~getMask(pWC->pMaskSet, iCur); /* Insert code to test every subexpression that can be completely ** computed using the current set of tables. ** ** IMPLEMENTATION-OF: R-49525-50935 Terms that cannot be satisfied through ** the use of indices become tests that are evaluated against each row of ** the relevant input tables. */ for(pTerm=pWC->a, j=pWC->nTerm; j>0; j--, pTerm++){ Expr *pE; testcase( pTerm->wtFlags & TERM_VIRTUAL ); /* IMP: R-30575-11662 */ testcase( pTerm->wtFlags & TERM_CODED ); if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue; if( (pTerm->prereqAll & newNotReady)!=0 ){ testcase( pWInfo->untestedTerms==0 && (pWInfo->wctrlFlags & WHERE_ONETABLE_ONLY)!=0 ); pWInfo->untestedTerms = 1; continue; } pE = pTerm->pExpr; assert( pE!=0 ); if( pLevel->iLeftJoin && !ExprHasProperty(pE, EP_FromJoin) ){ continue; } sqlite3ExprIfFalse(pParse, pE, addrCont, SQLITE_JUMPIFNULL); pTerm->wtFlags |= TERM_CODED; } /* Insert code to test for implied constraints based on transitivity ** of the "==" operator. ** ** Example: If the WHERE clause contains "t1.a=t2.b" and "t2.b=123" ** and we are coding the t1 loop and the t2 loop has not yet coded, ** then we cannot use the "t1.a=t2.b" constraint, but we can code ** the implied "t1.a=123" constraint. */ for(pTerm=pWC->a, j=pWC->nTerm; j>0; j--, pTerm++){ Expr *pE; WhereTerm *pAlt; Expr sEq; if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue; if( pTerm->eOperator!=(WO_EQUIV|WO_EQ) ) continue; if( pTerm->leftCursor!=iCur ) continue; pE = pTerm->pExpr; assert( !ExprHasProperty(pE, EP_FromJoin) ); assert( (pTerm->prereqRight & newNotReady)!=0 ); pAlt = findTerm(pWC, iCur, pTerm->u.leftColumn, notReady, WO_EQ|WO_IN, 0); if( pAlt==0 ) continue; if( pAlt->wtFlags & (TERM_CODED) ) continue; VdbeNoopComment((v, "begin transitive constraint")); sEq = *pAlt->pExpr; sEq.pLeft = pE->pLeft; sqlite3ExprIfFalse(pParse, &sEq, addrCont, SQLITE_JUMPIFNULL); } /* For a LEFT OUTER JOIN, generate code that will record the fact that ** at least one row of the right table has matched the left table. */ if( pLevel->iLeftJoin ){ pLevel->addrFirst = sqlite3VdbeCurrentAddr(v); sqlite3VdbeAddOp2(v, OP_Integer, 1, pLevel->iLeftJoin); VdbeComment((v, "record LEFT JOIN hit")); sqlite3ExprCacheClear(pParse); for(pTerm=pWC->a, j=0; j<pWC->nTerm; j++, pTerm++){ testcase( pTerm->wtFlags & TERM_VIRTUAL ); /* IMP: R-30575-11662 */ testcase( pTerm->wtFlags & TERM_CODED ); if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue; if( (pTerm->prereqAll & newNotReady)!=0 ){ assert( pWInfo->untestedTerms ); continue; } assert( pTerm->pExpr ); sqlite3ExprIfFalse(pParse, pTerm->pExpr, addrCont, SQLITE_JUMPIFNULL); pTerm->wtFlags |= TERM_CODED; } } sqlite3ReleaseTempReg(pParse, iReleaseReg); return newNotReady; } #if defined(SQLITE_TEST) /* ** The following variable holds a text description of query plan generated ** by the most recent call to sqlite3WhereBegin(). Each call to WhereBegin ** overwrites the previous. This information is used for testing and |
︙ | ︙ |
Changes to test/8_3_names.test.
︙ | ︙ | |||
146 147 148 149 150 151 152 | finish_test return } db close forcedelete test.db do_test 8_3_names-5.0 { sqlite3 db file:./test.db?8_3_names=1 | | | | 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 | finish_test return } db close forcedelete test.db do_test 8_3_names-5.0 { sqlite3 db file:./test.db?8_3_names=1 load_static_extension db wholenumber db eval { PRAGMA journal_mode=WAL; CREATE TABLE t1(x); CREATE VIRTUAL TABLE nums USING wholenumber; INSERT INTO t1 SELECT value FROM nums WHERE value BETWEEN 1 AND 1000; BEGIN; UPDATE t1 SET x=x*2; } sqlite3 db2 file:./test.db?8_3_names=1 load_static_extension db2 wholenumber db2 eval { BEGIN; SELECT sum(x) FROM t1; } } {500500} do_test 8_3_names-5.1 { |
︙ | ︙ |
Changes to test/analyze7.test.
︙ | ︙ | |||
22 23 24 25 26 27 28 | finish_test return } # Generate some test data # do_test analyze7-1.0 { | | | 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | finish_test return } # Generate some test data # do_test analyze7-1.0 { load_static_extension db wholenumber execsql { CREATE TABLE t1(a,b,c,d); CREATE INDEX t1a ON t1(a); CREATE INDEX t1b ON t1(b); CREATE INDEX t1cd ON t1(c,d); CREATE VIRTUAL TABLE nums USING wholenumber; INSERT INTO t1 SELECT value, value, value/100, value FROM nums |
︙ | ︙ |
Changes to test/auth.test.
︙ | ︙ | |||
2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 | SQLITE_READ t5 x main t5_tr1 \ ] do_test auth-5.3.2 { execsql { SELECT * FROM t5 } } {1} } rename proc {} rename proc_real proc finish_test | > > > > > > > > > > > > > > > > > > > > > > > | 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 | SQLITE_READ t5 x main t5_tr1 \ ] do_test auth-5.3.2 { execsql { SELECT * FROM t5 } } {1} } # Ticket [0eb70d77cb05bb22720]: Invalid pointer passsed to the authorizer # callback when updating a ROWID. # do_test auth-6.1 { execsql { CREATE TABLE t6(a,b,c,d,e,f,g,h); INSERT INTO t6 VALUES(1,2,3,4,5,6,7,8); } } {} set ::authargs [list] proc auth {args} { eval lappend ::authargs $args return SQLITE_OK } do_test auth-6.2 { execsql {UPDATE t6 SET rowID=rowID+100} set ::authargs } [list SQLITE_READ t6 ROWID main {} \ SQLITE_UPDATE t6 ROWID main {} \ ] do_test auth-6.3 { execsql {SELECT rowid, * FROM t6} } {101 1 2 3 4 5 6 7 8} rename proc {} rename proc_real proc finish_test |
Changes to test/backup_ioerr.test.
︙ | ︙ | |||
111 112 113 114 115 116 117 | # from the next call to backup_step() (in step 5 of this test # procedure). # # 5) Step the backup process to finish the backup. If an IO error is # reported, then the backup process is concluded with a call to # backup_finish(). # | | | 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 | # from the next call to backup_step() (in step 5 of this test # procedure). # # 5) Step the backup process to finish the backup. If an IO error is # reported, then the backup process is concluded with a call to # backup_finish(). # # Test that if an IO error occurs, or if one occurred while updating # the backup database during step 4, then the conditions listed # under step 3 are all true. # # 6) Finish the backup process. # # * If the backup succeeds (backup_finish() returns SQLITE_OK), then # the contents of the backup database should match that of the |
︙ | ︙ | |||
210 211 212 213 214 215 216 | expr {$rc eq "SQLITE_OK"} } {1} # Step 4: Write to the source database. set rc [catchsql { UPDATE t1 SET b = randstr(1000,1000) WHERE a < 50 } sdb] if {[lindex $rc 0] && $::sqlite_io_error_persist==0} { | | | 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 | expr {$rc eq "SQLITE_OK"} } {1} # Step 4: Write to the source database. set rc [catchsql { UPDATE t1 SET b = randstr(1000,1000) WHERE a < 50 } sdb] if {[lindex $rc 0] && $::sqlite_io_error_persist==0} { # The IO error occurred while updating the source database. In this # case the backup should be able to continue. set rc [B step 5000] if { $rc != "SQLITE_IOERR_UNLOCK" } { do_test backup_ioerr-$iTest.$iError.7 { list [B step 5000] [B finish] } {SQLITE_DONE SQLITE_OK} |
︙ | ︙ |
Added test/btreefault.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 | # 2013 April 02 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # # This file contains fault injection tests designed to test the btree.c # module. # set testdir [file dirname $argv0] source $testdir/tester.tcl source $testdir/malloc_common.tcl set testprefix btreefault do_test 1-pre1 { execsql { PRAGMA auto_vacuum = incremental; PRAGMA journal_mode = DELETE; CREATE TABLE t1(a PRIMARY KEY, b); INSERT INTO t1 VALUES(randomblob(1000), randomblob(100)); INSERT INTO t1 SELECT randomblob(1000), randomblob(1000) FROM t1; INSERT INTO t1 SELECT randomblob(1000), randomblob(1000) FROM t1; INSERT INTO t1 SELECT randomblob(1000), randomblob(1000) FROM t1; INSERT INTO t1 SELECT randomblob(1000), randomblob(1000) FROM t1; DELETE FROM t1 WHERE rowid%2; } faultsim_save_and_close } {} do_faultsim_test 1 -prep { faultsim_restore_and_reopen set ::STMT [sqlite3_prepare db "SELECT * FROM t1 ORDER BY a" -1 DUMMY] sqlite3_step $::STMT sqlite3_step $::STMT } -body { execsql { PRAGMA incremental_vacuum = 10 } } -test { sqlite3_finalize $::STMT faultsim_test_result {0 {}} faultsim_integrity_check } finish_test |
Changes to test/cache.test.
︙ | ︙ | |||
42 43 44 45 46 47 48 | } {2} # At one point, repeatedly locking and unlocking the cache was causing # a resource leak of one page per repetition. The page wasn't actually # leaked, but would not be reused until the pager-cache was full (i.e. # 2000 pages by default). # | | | 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | } {2} # At one point, repeatedly locking and unlocking the cache was causing # a resource leak of one page per repetition. The page wasn't actually # leaked, but would not be reused until the pager-cache was full (i.e. # 2000 pages by default). # # This tests that once the pager-cache is initialized, it can be locked # and unlocked repeatedly without internally allocating any new pages. # set cache_size [pager_cache_size db] for {set ii 0} {$ii < 10} {incr ii} { do_test cache-1.3.$ii { execsql {SELECT * FROM abc} pager_cache_size db |
︙ | ︙ |
Added test/closure01.test.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 | # 2013-04-25 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # # Test cases for transitive_closure virtual table. set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix closure01 load_static_extension db closure do_execsql_test 1.0 { BEGIN; CREATE TABLE t1(x INTEGER PRIMARY KEY, y INTEGER); CREATE INDEX t1y ON t1(y); INSERT INTO t1(x) VALUES(1),(2); INSERT INTO t1(x) SELECT x+2 FROM t1; INSERT INTO t1(x) SELECT x+4 FROM t1; INSERT INTO t1(x) SELECT x+8 FROM t1; INSERT INTO t1(x) SELECT x+16 FROM t1; INSERT INTO t1(x) SELECT x+32 FROM t1; INSERT INTO t1(x) SELECT x+64 FROM t1; INSERT INTO t1(x) SELECT x+128 FROM t1; INSERT INTO t1(x) SELECT x+256 FROM t1; INSERT INTO t1(x) SELECT x+512 FROM t1; INSERT INTO t1(x) SELECT x+1024 FROM t1; INSERT INTO t1(x) SELECT x+2048 FROM t1; INSERT INTO t1(x) SELECT x+4096 FROM t1; INSERT INTO t1(x) SELECT x+8192 FROM t1; INSERT INTO t1(x) SELECT x+16384 FROM t1; INSERT INTO t1(x) SELECT x+32768 FROM t1; INSERT INTO t1(x) SELECT x+65536 FROM t1; UPDATE t1 SET y=x/2 WHERE x>1; COMMIT; CREATE VIRTUAL TABLE cx USING transitive_closure(tablename=t1, idcolumn=x, parentcolumn=y); } {} # The entire table do_execsql_test 1.1 { SELECT count(*), depth FROM cx WHERE root=1 GROUP BY depth ORDER BY 1; } {/1 0 1 17 2 1 4 2 8 3 16 4 .* 65536 16/} # descendents of 32768 do_execsql_test 1.2 { SELECT * FROM cx WHERE root=32768 ORDER BY id; } {32768 0 65536 1 65537 1 131072 2} # descendents of 16384 do_execsql_test 1.3 { SELECT * FROM cx WHERE root=16384 AND depth<=2 ORDER BY id; } {16384 0 32768 1 32769 1 65536 2 65537 2 65538 2 65539 2} # children of 16384 do_execsql_test 1.4 { SELECT id, depth, root, tablename, idcolumn, parentcolumn FROM cx WHERE root=16384 AND depth=1 ORDER BY id; } {32768 1 {} t1 x y 32769 1 {} t1 x y} # great-grandparent of 16384 do_execsql_test 1.5 { SELECT id, depth, root, tablename, idcolumn, parentcolumn FROM cx WHERE root=16384 AND depth=3 AND idcolumn='Y' AND parentcolumn='X'; } {2048 3 {} t1 Y X} # depth<5 do_execsql_test 1.6 { SELECT count(*), depth FROM cx WHERE root=1 AND depth<5 GROUP BY depth ORDER BY 1; } {1 0 2 1 4 2 8 3 16 4} # depth<=5 do_execsql_test 1.7 { SELECT count(*), depth FROM cx WHERE root=1 AND depth<=5 GROUP BY depth ORDER BY 1; } {1 0 2 1 4 2 8 3 16 4 32 5} # depth==5 do_execsql_test 1.8 { SELECT count(*), depth FROM cx WHERE root=1 AND depth=5 GROUP BY depth ORDER BY 1; } {32 5} # depth BETWEEN 3 AND 5 do_execsql_test 1.9 { SELECT count(*), depth FROM cx WHERE root=1 AND depth BETWEEN 3 AND 5 GROUP BY depth ORDER BY 1; } {8 3 16 4 32 5} # depth==5 with min() and max() do_execsql_test 1.10 { SELECT count(*), min(id), max(id) FROM cx WHERE root=1 AND depth=5; } {32 32 63} # Create a much smaller table t2 with only 32 elements db eval { CREATE TABLE t2(x INTEGER PRIMARY KEY, y INTEGER); INSERT INTO t2 SELECT x, y FROM t1 WHERE x<32; CREATE INDEX t2y ON t2(y); CREATE VIRTUAL TABLE c2 USING transitive_closure(tablename=t2, idcolumn=x, parentcolumn=y); } # t2 full-table do_execsql_test 2.1 { SELECT count(*), min(id), max(id) FROM c2 WHERE root=1; } {31 1 31} # t2 root=10 do_execsql_test 2.2 { SELECT id FROM c2 WHERE root=10; } {10 20 21} # t2 root=11 do_execsql_test 2.3 { SELECT id FROM c2 WHERE root=12; } {12 24 25} # t2 root IN [10,12] do_execsql_test 2.4 { SELECT id FROM c2 WHERE root IN (10,12) ORDER BY id; } {10 12 20 21 24 25} # t2 root IN [10,12] (sorted) do_execsql_test 2.5 { SELECT id FROM c2 WHERE root IN (10,12) ORDER BY +id; } {10 12 20 21 24 25} # t2 c2up from 20 do_execsql_test 3.0 { CREATE VIRTUAL TABLE c2up USING transitive_closure( tablename = t2, idcolumn = y, parentcolumn = x ); SELECT id FROM c2up WHERE root=20; } {1 2 5 10 20} # cx as c2up do_execsql_test 3.1 { SELECT id FROM cx WHERE root=20 AND tablename='t2' AND idcolumn='y' AND parentcolumn='x'; } {1 2 5 10 20} # t2 first cousins of 20 do_execsql_test 3.2 { SELECT DISTINCT id FROM c2 WHERE root IN (SELECT id FROM c2up WHERE root=20 AND depth<=2) ORDER BY id; } {5 10 11 20 21 22 23} # t2 first cousins of 20 do_execsql_test 3.3 { SELECT id FROM c2 WHERE root=(SELECT id FROM c2up WHERE root=20 AND depth=2) AND depth=2 EXCEPT SELECT id FROM c2 WHERE root=(SELECT id FROM c2up WHERE root=20 AND depth=1) AND depth<=1 ORDER BY id; } {22 23} # missing tablename. do_test 4.1 { catchsql { SELECT id FROM cx WHERE root=20 AND tablename='t3' AND idcolumn='y' AND parentcolumn='x'; } } {1 {no such table: t3}} # missing idcolumn do_test 4.2 { catchsql { SELECT id FROM cx WHERE root=20 AND tablename='t2' AND idcolumn='xyz' AND parentcolumn='x'; } } {1 {no such column: t2.xyz}} # missing parentcolumn do_test 4.3 { catchsql { SELECT id FROM cx WHERE root=20 AND tablename='t2' AND idcolumn='x' AND parentcolumn='pqr'; } } {1 {no such column: t2.pqr}} # generic closure do_execsql_test 5.1 { CREATE VIRTUAL TABLE temp.closure USING transitive_closure; SELECT id FROM closure WHERE root=1 AND depth=3 AND tablename='t1' AND idcolumn='x' AND parentcolumn='y' ORDER BY id; } {8 9 10 11 12 13 14 15} finish_test |
Changes to test/collate4.test.
︙ | ︙ | |||
56 57 58 59 60 61 62 | # # These tests - collate4-1.* - check that indices are correctly # selected or not selected to implement ORDER BY clauses when # user defined collation sequences are involved. # # Because these tests also exercise all the different ways indices # can be created, they also serve to verify that indices are correctly | | | 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | # # These tests - collate4-1.* - check that indices are correctly # selected or not selected to implement ORDER BY clauses when # user defined collation sequences are involved. # # Because these tests also exercise all the different ways indices # can be created, they also serve to verify that indices are correctly # initialized with user-defined collation sequences when they are # created. # # Tests named collate4-1.1.* use indices with a single column. Tests # collate4-1.2.* use indices with two columns. # do_test collate4-1.1.0 { execsql { |
︙ | ︙ |
Changes to test/crash5.test.
︙ | ︙ | |||
61 62 63 64 65 66 67 | # db eval BEGIN sqlite3_memdebug_fail $iFail -repeat 0 catch {db eval { CREATE UNIQUE INDEX i1 ON t1(a); }} msg # puts "$n $msg ac=[sqlite3_get_autocommit db]" # If the transaction is still active (it may not be if the malloc() | | | 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 | # db eval BEGIN sqlite3_memdebug_fail $iFail -repeat 0 catch {db eval { CREATE UNIQUE INDEX i1 ON t1(a); }} msg # puts "$n $msg ac=[sqlite3_get_autocommit db]" # If the transaction is still active (it may not be if the malloc() # failure occurred in the OS layer), write to the database. Make sure # page 4 is among those written. # if {![sqlite3_get_autocommit db]} { db eval { DELETE FROM t1; -- This will put page 4 on the free list. INSERT INTO t1 VALUES('111111111', '2222222222', '33333333'); INSERT INTO t1 SELECT * FROM t1; -- 2 |
︙ | ︙ |
Changes to test/dbstatus2.test.
︙ | ︙ | |||
36 37 38 39 40 41 42 43 44 45 46 47 48 49 | proc db_write {db {reset 0}} { sqlite3_db_status $db CACHE_WRITE $reset } do_test 1.1 { db close sqlite3 db test.db expr {[file size test.db] / 1024} } 6 do_test 1.2 { execsql { SELECT b FROM t1 WHERE a=2 } db_hit_miss db } {{0 2 0} {0 4 0}} | > | 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | proc db_write {db {reset 0}} { sqlite3_db_status $db CACHE_WRITE $reset } do_test 1.1 { db close sqlite3 db test.db execsql { PRAGMA mmap_size = 0 } expr {[file size test.db] / 1024} } 6 do_test 1.2 { execsql { SELECT b FROM t1 WHERE a=2 } db_hit_miss db } {{0 2 0} {0 4 0}} |
︙ | ︙ |
Changes to test/e_createtable.test.
︙ | ︙ | |||
1253 1254 1255 1256 1257 1258 1259 | 14 "INSERT INTO t2 VALUES(NULL, NULL)" {} } # EVIDENCE-OF: R-61866-38053 Unless the column is an INTEGER PRIMARY KEY # SQLite allows NULL values in a PRIMARY KEY column. # # If the column is an integer primary key, attempting to insert a NULL | | | 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 | 14 "INSERT INTO t2 VALUES(NULL, NULL)" {} } # EVIDENCE-OF: R-61866-38053 Unless the column is an INTEGER PRIMARY KEY # SQLite allows NULL values in a PRIMARY KEY column. # # If the column is an integer primary key, attempting to insert a NULL # into the column triggers the auto-increment behavior. Attempting # to use UPDATE to set an ipk column to a NULL value is an error. # do_createtable_tests 4.5.1 { 1 "SELECT count(*) FROM t1 WHERE x IS NULL" 3 2 "SELECT count(*) FROM t2 WHERE x IS NULL" 6 3 "SELECT count(*) FROM t2 WHERE y IS NULL" 7 4 "SELECT count(*) FROM t2 WHERE x IS NULL AND y IS NULL" 2 |
︙ | ︙ |
Changes to test/e_fkey.test.
︙ | ︙ | |||
2737 2738 2739 2740 2741 2742 2743 | } {1 {foreign key mismatch - "c2" referencing "p"}} do_test e_fkey-60.6 { execsql { DROP TABLE c2 } execsql { DELETE FROM p } } {} #------------------------------------------------------------------------- | | | | 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 | } {1 {foreign key mismatch - "c2" referencing "p"}} do_test e_fkey-60.6 { execsql { DROP TABLE c2 } execsql { DELETE FROM p } } {} #------------------------------------------------------------------------- # Test that the special behaviors of ALTER and DROP TABLE are only # activated when foreign keys are enabled. Special behaviors are: # # 1. ADD COLUMN not allowing a REFERENCES clause with a non-NULL # default value. # 2. Modifying foreign key definitions when a parent table is RENAMEd. # 3. Running an implicit DELETE FROM command as part of DROP TABLE. # # EVIDENCE-OF: R-54142-41346 The properties of the DROP TABLE and ALTER |
︙ | ︙ | |||
2833 2834 2835 2836 2837 2838 2839 | CREATE TABLE p(a, b, c, PRIMARY KEY(b, c)); CREATE TABLE c(d, e, f, FOREIGN KEY(e, f) REFERENCES p MATCH $zMatch); " } {} do_test e_fkey-62.$zMatch.2 { execsql { INSERT INTO p VALUES(1, 2, 3) } | | | 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 | CREATE TABLE p(a, b, c, PRIMARY KEY(b, c)); CREATE TABLE c(d, e, f, FOREIGN KEY(e, f) REFERENCES p MATCH $zMatch); " } {} do_test e_fkey-62.$zMatch.2 { execsql { INSERT INTO p VALUES(1, 2, 3) } # MATCH SIMPLE behavior: Allow any child key that contains one or more # NULL value to be inserted. Non-NULL values do not have to map to any # parent key values, so long as at least one field of the child key is # NULL. execsql { INSERT INTO c VALUES('w', 2, 3) } execsql { INSERT INTO c VALUES('x', 'x', NULL) } execsql { INSERT INTO c VALUES('y', NULL, 'x') } execsql { INSERT INTO c VALUES('z', NULL, NULL) } |
︙ | ︙ |
Changes to test/e_select.test.
︙ | ︙ | |||
1223 1224 1225 1226 1227 1228 1229 | 2 "SELECT DISTINCT a FROM h1" {1 4} } # EVIDENCE-OF: R-08861-34280 If the simple SELECT is a SELECT ALL, then # the entire set of result rows are returned by the SELECT. # # EVIDENCE-OF: R-47911-02086 If neither ALL or DISTINCT are present, | | | 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 | 2 "SELECT DISTINCT a FROM h1" {1 4} } # EVIDENCE-OF: R-08861-34280 If the simple SELECT is a SELECT ALL, then # the entire set of result rows are returned by the SELECT. # # EVIDENCE-OF: R-47911-02086 If neither ALL or DISTINCT are present, # then the behavior is as if ALL were specified. # # EVIDENCE-OF: R-14442-41305 If the simple SELECT is a SELECT DISTINCT, # then duplicate rows are removed from the set of result rows before it # is returned. # # The three testable statements above are tested by e_select-5.2.*, # 5.3.* and 5.4.* respectively. |
︙ | ︙ |
Changes to test/e_uri.test.
︙ | ︙ | |||
357 358 359 360 361 362 363 | # to sqlite3_open_v2(). # # EVIDENCE-OF: R-49793-28525 Setting the cache parameter to "private" is # equivalent to setting the SQLITE_OPEN_PRIVATECACHE bit. # # EVIDENCE-OF: R-19510-48080 If sqlite3_open_v2() is used and the # "cache" parameter is present in a URI filename, its value overrides | | | 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 | # to sqlite3_open_v2(). # # EVIDENCE-OF: R-49793-28525 Setting the cache parameter to "private" is # equivalent to setting the SQLITE_OPEN_PRIVATECACHE bit. # # EVIDENCE-OF: R-19510-48080 If sqlite3_open_v2() is used and the # "cache" parameter is present in a URI filename, its value overrides # any behavior requested by setting SQLITE_OPEN_PRIVATECACHE or # SQLITE_OPEN_SHAREDCACHE flag. # set orig [sqlite3_enable_shared_cache] foreach {tn uri flags shared_default isshared} { 1.1 "file:test.db" "" 0 0 1.2 "file:test.db" "" 1 1 1.3 "file:test.db" private 0 0 |
︙ | ︙ |
Changes to test/enc2.test.
︙ | ︙ | |||
28 29 30 31 32 33 34 | # The rough organisation of tests in this file is: # # enc2.1.*: Simple tests with a UTF-8 db. # enc2.2.*: Simple tests with a UTF-16LE db. # enc2.3.*: Simple tests with a UTF-16BE db. # enc2.4.*: Test that attached databases must have the same text encoding # as the main database. | | | 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | # The rough organisation of tests in this file is: # # enc2.1.*: Simple tests with a UTF-8 db. # enc2.2.*: Simple tests with a UTF-16LE db. # enc2.3.*: Simple tests with a UTF-16BE db. # enc2.4.*: Test that attached databases must have the same text encoding # as the main database. # enc2.5.*: Test the behavior of the library when a collation sequence is # not available for the most desirable text encoding. # enc2.6.*: Similar test for user functions. # enc2.7.*: Test that the VerifyCookie opcode protects against assuming the # wrong text encoding for the database. # enc2.8.*: Test sqlite3_complete16() # |
︙ | ︙ |
Changes to test/exclusive2.test.
︙ | ︙ | |||
20 21 22 23 24 25 26 27 28 29 30 31 32 33 | # do_not_use_codec ifcapable {!pager_pragmas} { finish_test return } # This module does not work right if the cache spills at unexpected # moments. So disable the soft-heap-limit. # sqlite3_soft_heap_limit 0 proc pagerChangeCounter {filename new {fd ""}} { | > > > > > > > > | 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | # do_not_use_codec ifcapable {!pager_pragmas} { finish_test return } # Tests in this file verify that locking_mode=exclusive causes SQLite to # use cached pages even if the database is changed on disk. This doesn't # work with mmap. if {[permutation]=="mmap"} { finish_test return } # This module does not work right if the cache spills at unexpected # moments. So disable the soft-heap-limit. # sqlite3_soft_heap_limit 0 proc pagerChangeCounter {filename new {fd ""}} { |
︙ | ︙ |
Changes to test/fts3aux1.test.
︙ | ︙ | |||
350 351 352 353 354 355 356 | do_execsql_test 3.1.1 { CREATE VIRTUAL TABLE t2 USING fts4; } do_catchsql_test 3.1.2 { CREATE VIRTUAL TABLE terms2 USING fts4aux; | | | | 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 | do_execsql_test 3.1.1 { CREATE VIRTUAL TABLE t2 USING fts4; } do_catchsql_test 3.1.2 { CREATE VIRTUAL TABLE terms2 USING fts4aux; } {1 {invalid arguments to fts4aux constructor}} do_catchsql_test 3.1.3 { CREATE VIRTUAL TABLE terms2 USING fts4aux(t2, t2); } {1 {invalid arguments to fts4aux constructor}} do_execsql_test 3.2.1 { CREATE VIRTUAL TABLE terms3 USING fts4aux(does_not_exist) } do_catchsql_test 3.2.2 { SELECT * FROM terms3 } {1 {SQL logic error or missing database}} |
︙ | ︙ | |||
440 441 442 443 444 445 446 | } #------------------------------------------------------------------------- # The following tests check that fts4aux can handle an fts table with an # odd name (one that requires quoting for use in SQL statements). And that # the argument to the fts4aux constructor is properly dequoted before use. # | < > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 | } #------------------------------------------------------------------------- # The following tests check that fts4aux can handle an fts table with an # odd name (one that requires quoting for use in SQL statements). And that # the argument to the fts4aux constructor is properly dequoted before use. # do_execsql_test 5.1 { CREATE VIRTUAL TABLE "abc '!' def" USING fts4(x, y); INSERT INTO "abc '!' def" VALUES('XX', 'YY'); CREATE VIRTUAL TABLE terms3 USING fts4aux("abc '!' def"); SELECT * FROM terms3; } {xx * 1 1 xx 0 1 1 yy * 1 1 yy 1 1 1} do_execsql_test 5.2 { CREATE VIRTUAL TABLE "%%^^%%" USING fts4aux('abc ''!'' def'); SELECT * FROM "%%^^%%"; } {xx * 1 1 xx 0 1 1 yy * 1 1 yy 1 1 1} #------------------------------------------------------------------------- # Test that we can create an fts4aux table in the temp database. # forcedelete test.db2 do_execsql_test 6.1 { CREATE VIRTUAL TABLE ft1 USING fts4(x, y); INSERT INTO ft1 VALUES('a b', 'c d'); INSERT INTO ft1 VALUES('e e', 'c d'); INSERT INTO ft1 VALUES('a a', 'b b'); CREATE VIRTUAL TABLE temp.aux1 USING fts4aux(main, ft1); SELECT * FROM aux1; } { a * 2 3 a 0 2 3 b * 2 3 b 0 1 1 b 1 1 2 c * 2 2 c 1 2 2 d * 2 2 d 1 2 2 e * 1 2 e 0 1 2 } do_execsql_test 6.2 { ATTACH 'test.db2' AS att; CREATE VIRTUAL TABLE att.ft1 USING fts4(x, y); INSERT INTO att.ft1 VALUES('v w', 'x y'); INSERT INTO att.ft1 VALUES('z z', 'x y'); INSERT INTO att.ft1 VALUES('v v', 'w w'); CREATE VIRTUAL TABLE temp.aux2 USING fts4aux(att, ft1); SELECT * FROM aux2; } { v * 2 3 v 0 2 3 w * 2 3 w 0 1 1 w 1 1 2 x * 2 2 x 1 2 2 y * 2 2 y 1 2 2 z * 1 2 z 0 1 2 } foreach {tn q res1 res2} { 1 { SELECT * FROM %%% WHERE term = 'a' } {a * 2 3 a 0 2 3} {} 2 { SELECT * FROM %%% WHERE term = 'x' } {} {x * 2 2 x 1 2 2} 3 { SELECT * FROM %%% WHERE term >= 'y' } {} {y * 2 2 y 1 2 2 z * 1 2 z 0 1 2} 4 { SELECT * FROM %%% WHERE term <= 'c' } {a * 2 3 a 0 2 3 b * 2 3 b 0 1 1 b 1 1 2 c * 2 2 c 1 2 2} {} } { set sql1 [string map {%%% aux1} $q] set sql2 [string map {%%% aux2} $q] do_execsql_test 7.$tn.1 $sql1 $res1 do_execsql_test 7.$tn.2 $sql2 $res2 } do_test 8.1 { catchsql { CREATE VIRTUAL TABLE att.aux3 USING fts4aux(main, ft1) } } {1 {invalid arguments to fts4aux constructor}} do_test 8.2 { execsql {DETACH att} catchsql { SELECT * FROM aux2 } } {1 {SQL logic error or missing database}} finish_test |
Added test/fts3expr3.test.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 | # 2009 January 1 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #************************************************************************* # This file implements regression tests for SQLite library. The # focus of this script is testing the part of the FTS3 expression # parser that rebalances large expressions. # # $Id: fts3expr2.test,v 1.2 2009/06/05 17:09:12 drh Exp $ # set testdir [file dirname $argv0] source $testdir/tester.tcl source $testdir/malloc_common.tcl set ::testprefix fts3expr3 # If SQLITE_ENABLE_FTS3 is defined, omit this file. ifcapable !fts3 { finish_test return } set sqlite_fts3_enable_parentheses 1 proc strip_phrase_data {L} { if {[lindex $L 0] eq "PHRASE"} { return [list P [lrange $L 3 end]] } return [list \ [lindex $L 0] \ [strip_phrase_data [lindex $L 1]] \ [strip_phrase_data [lindex $L 2]] \ ] } proc test_fts3expr2 {expr} { strip_phrase_data [ db one {SELECT fts3_exprtest_rebalance('simple', $expr, 'a', 'b', 'c')} ] } proc balanced_exprtree_structure {nEntry} { set L [list] for {set i 1} {$i <= $nEntry} {incr i} { lappend L xxx } while {[llength $L] > 1} { set N [list] if {[llength $L] % 2} { foreach {a b} [lrange $L 0 end-1] { lappend N [list AND $a $b] } lappend N [lindex $L end] } else { foreach {a b} $L { lappend N [list AND $a $b] } } set L $N } return [lindex $L 0] } proc balanced_and_tree {nEntry} { set query [balanced_exprtree_structure $nEntry] if {$query == "xxx"} { return "P 1" } for {set i 1} {$i <= $nEntry} {incr i} { regsub xxx $query "{P $i}" query } return $query } proc random_tree_structure {nEntry bParen op} { set query xxx for {set i 1} {$i < $nEntry} {incr i} { set x1 [expr int(rand()*4.0)] set x2 [expr int(rand()*2.0)] if {$x1==0 && $bParen} { set query "($query)" } if {$x2} { set query "xxx $op $query" } else { set query "$query $op xxx" } } return $query } proc random_and_query {nEntry {bParen 0}} { set query [random_tree_structure $nEntry $bParen AND] for {set i 1} {$i <= $nEntry} {incr i} { regsub xxx $query $i query } return $query } proc random_or_query {nEntry} { set query [random_tree_structure $nEntry 1 OR] for {set i 1} {$i <= $nEntry} {incr i} { regsub xxx $query $i query } return $query } proc random_andor_query {nEntry} { set query [random_tree_structure $nEntry 1 AND] for {set i 1} {$i <= $nEntry} {incr i} { regsub xxx $query "([random_or_query $nEntry])" query } return $query } 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] } [balanced_and_tree $i] } # Same again, except with parenthesis inserted at arbitrary points. # for {set i 1} {$i < 100} {incr i} { do_test 2.$i { test_fts3expr2 [random_and_query $i 1] } [balanced_and_tree $i] } # Now attempt to balance two AND trees joined by an OR. # for {set i 1} {$i < 100} {incr i} { do_test 3.$i { test_fts3expr2 "[random_and_query $i 1] OR [random_and_query $i 1]" } [list OR [balanced_and_tree $i] [balanced_and_tree $i]] } # Try trees of AND nodes with leaves that are themselves trees of OR nodes. # for {set i 2} {$i < 64} {incr i 4} { do_test 3.$i { test_fts3expr2 [random_andor_query $i] } [balanced_andor_tree $i] } # These exceed the depth limit. # for {set i 65} {$i < 70} {incr i} { do_test 3.$i { list [catch {test_fts3expr2 [random_andor_query $i]} msg] $msg } {1 {Error parsing expression}} } # This also exceeds the depth limit. # do_test 4.1.1 { set q "1" for {set i 2} {$i < 5000} {incr i} { append q " AND $i" } list [catch {test_fts3expr2 $q} msg] $msg } {1 {Error parsing expression}} do_test 4.1.2 { set q "1" for {set i 2} {$i < 4000} {incr i} { append q " AND $i" } catch {test_fts3expr2 $q} } {0} proc create_toggle_tree {nDepth} { if {$nDepth == 0} { return xxx } set nNew [expr $nDepth-1] if {$nDepth % 2} { return "([create_toggle_tree $nNew]) OR ([create_toggle_tree $nNew])" } return "([create_toggle_tree $nNew]) AND ([create_toggle_tree $nNew])" } do_test 4.2 { list [catch {test_fts3expr2 [create_toggle_tree 17]} msg] $msg } {1 {Error parsing expression}} 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 |
Changes to test/fts3near.test.
︙ | ︙ | |||
575 576 577 578 579 580 581 582 583 584 | } } {} do_test fts3near-6.5 { execsql { SELECT docid FROM t1 WHERE content MATCH 'abbrev NEAR/10000 zygosis' } } {3} finish_test | > > > > > > > > > > > > > > | 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 | } } {} do_test fts3near-6.5 { execsql { SELECT docid FROM t1 WHERE content MATCH 'abbrev NEAR/10000 zygosis' } } {3} # Ticket 38b1ae018f. # do_execsql_test fts3near-7.1 { CREATE VIRTUAL TABLE x USING fts4(y,z); INSERT INTO x VALUES('aaa bbb ccc ddd', 'bbb ddd aaa ccc'); SELECT * FROM x where y MATCH 'bbb NEAR/6 aaa'; } {{aaa bbb ccc ddd} {bbb ddd aaa ccc}} do_execsql_test fts3near-7.2 { CREATE VIRTUAL TABLE t2 USING fts4(a, b); INSERT INTO t2 VALUES('A B C', 'A D E'); SELECT * FROM t2 where t2 MATCH 'a:A NEAR E' } {} finish_test |
Added test/fts3tok1.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 | # 2013 April 22 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #************************************************************************* # This file implements regression tests for SQLite library. The # focus of this script is testing the "fts3tokenize" virtual table # that is part of the FTS3 module. # set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable !fts3 { finish_test ; return } set ::testprefix fts3tok1 #------------------------------------------------------------------------- # Simple test cases. Using the default (simple) tokenizer. # do_execsql_test 1.0 { CREATE VIRTUAL TABLE t1 USING fts3tokenize(simple); CREATE VIRTUAL TABLE t2 USING fts3tokenize(); CREATE VIRTUAL TABLE t3 USING fts3tokenize(simple, '', 'xyz '); } foreach {tn tbl} {1 t1 2 t2 3 t3} { do_execsql_test 1.$tn.1 "SELECT * FROM $tbl WHERE input = 'one two three'" { {one two three} one 0 3 0 {one two three} two 4 7 1 {one two three} three 8 13 2 } do_execsql_test 1.$tn.2 " SELECT token FROM $tbl WHERE input = 'OnE tWo tHrEe' " { one two three } } do_execsql_test 1.4 { SELECT token FROM t3 WHERE input = '1x2x3x' } {1 2 3} do_execsql_test 1.5 { SELECT token FROM t1 WHERE input = '1x2x3x' } {1x2x3x} do_execsql_test 1.6 { SELECT token FROM t3 WHERE input = '1''2x3x' } {1'2 3} do_execsql_test 1.7 { SELECT token FROM t3 WHERE input = '' } {} do_execsql_test 1.8 { SELECT token FROM t3 WHERE input = NULL } {} do_execsql_test 1.9 { SELECT * FROM t3 WHERE input = 123 } {123 123 0 3 0} do_execsql_test 1.10 { SELECT * FROM t1 WHERE input = 'a b c' AND token = 'b'; } { {a b c} b 2 3 1 } do_execsql_test 1.11 { SELECT * FROM t1 WHERE token = 'b' AND input = 'a b c'; } { {a b c} b 2 3 1 } do_execsql_test 1.12 { SELECT * FROM t1 WHERE input < 'b' AND input = 'a b c'; } { {a b c} a 0 1 0 {a b c} b 2 3 1 {a b c} c 4 5 2 } do_execsql_test 1.13.1 { CREATE TABLE c1(x); INSERT INTO c1(x) VALUES('a b c'); INSERT INTO c1(x) VALUES('d e f'); } breakpoint do_execsql_test 1.13.2 { SELECT * FROM c1, t1 WHERE input = x AND c1.rowid=t1.rowid; } { {a b c} {a b c} a 0 1 0 {d e f} {d e f} e 2 3 1 } #------------------------------------------------------------------------- # Error cases. # do_catchsql_test 2.0 { CREATE VIRTUAL TABLE tX USING fts3tokenize(nosuchtokenizer); } {1 {unknown tokenizer: nosuchtokenizer}} do_catchsql_test 2.1 { CREATE VIRTUAL TABLE t4 USING fts3tokenize; SELECT * FROM t4; } {1 {SQL logic error or missing database}} finish_test |
Added test/fts3tok_err.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 | # 2013 April 22 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #************************************************************************* # This file implements regression tests for SQLite library. The # focus of this script is testing the "fts3tokenize" virtual table # that is part of the FTS3 module. # set testdir [file dirname $argv0] source $testdir/tester.tcl source $testdir/malloc_common.tcl ifcapable !fts3 { finish_test ; return } set ::testprefix fts3tok_err faultsim_save_and_close do_faultsim_test fts3tok_err-1 -faults oom* -prep { faultsim_restore_and_reopen } -body { execsql { CREATE VIRTUAL TABLE t1 USING fts3tokenize("simple"); } } -test { faultsim_test_result {0 {}} } do_test fts3tok_err-2.prep { faultsim_delete_and_reopen execsql { CREATE VIRTUAL TABLE t1 USING fts3tokenize("simple"); } faultsim_save_and_close } {} do_faultsim_test fts3tok_err-2 -faults oom* -prep { faultsim_restore_and_reopen } -body { execsql { SELECT token FROM t1 WHERE input = 'A galaxy far, far away' } } -test { faultsim_test_result {0 {a galaxy far far away}} } finish_test |
Changes to test/func.test.
︙ | ︙ | |||
1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 | } {1} do_test func-29.3 { db close sqlite3 db test.db sqlite3_db_status db CACHE_MISS 1 db eval {SELECT typeof(+x) FROM t29 ORDER BY id} } {integer null real blob text} do_test func-29.4 { set x [lindex [sqlite3_db_status db CACHE_MISS 1] 1] if {$x>100} {set x many} set x } {many} do_test func-29.5 { db close sqlite3 db test.db sqlite3_db_status db CACHE_MISS 1 db eval {SELECT sum(length(x)) FROM t29} } {1000009} do_test func-29.6 { | > > | 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 | } {1} do_test func-29.3 { db close sqlite3 db test.db sqlite3_db_status db CACHE_MISS 1 db eval {SELECT typeof(+x) FROM t29 ORDER BY id} } {integer null real blob text} if {[permutation] != "mmap"} { do_test func-29.4 { set x [lindex [sqlite3_db_status db CACHE_MISS 1] 1] if {$x>100} {set x many} set x } {many} } do_test func-29.5 { db close sqlite3 db test.db sqlite3_db_status db CACHE_MISS 1 db eval {SELECT sum(length(x)) FROM t29} } {1000009} do_test func-29.6 { |
︙ | ︙ |
Changes to test/fuzzer1.test.
︙ | ︙ | |||
20 21 22 23 24 25 26 | ifcapable !vtab { finish_test return } set ::testprefix fuzzer1 | < < < < | < | 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | ifcapable !vtab { finish_test return } set ::testprefix fuzzer1 load_static_extension db fuzzer # Check configuration errors. # do_catchsql_test fuzzer1-1.1 { CREATE VIRTUAL TABLE f USING fuzzer; } {1 {fuzzer: wrong number of CREATE VIRTUAL TABLE arguments}} |
︙ | ︙ |
Changes to test/fuzzerfault.test.
︙ | ︙ | |||
13 14 15 16 17 18 19 | # set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable !vtab { finish_test ; return } set ::testprefix fuzzerfault | | | | | | 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 | # set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable !vtab { finish_test ; return } set ::testprefix fuzzerfault load_static_extension db fuzzer do_test 1-pre1 { execsql { CREATE TABLE x1_rules(ruleset, cFrom, cTo, cost); INSERT INTO x1_rules VALUES(0, 'a', 'b', 1); INSERT INTO x1_rules VALUES(0, 'a', 'c', 2); INSERT INTO x1_rules VALUES(0, 'a', 'd', 3); } faultsim_save_and_close } {} do_faultsim_test 1 -prep { faultsim_restore_and_reopen load_static_extension db fuzzer } -body { execsql { CREATE VIRTUAL TABLE x1 USING fuzzer(x1_rules); SELECT word FROM x1 WHERE word MATCH 'xax'; } } -test { faultsim_test_result {0 {xax xbx xcx xdx}} \ {1 {vtable constructor failed: x1}} } do_test 2-pre1 { faultsim_delete_and_reopen load_static_extension db fuzzer execsql { CREATE TABLE x2_rules(ruleset, cFrom, cTo, cost); INSERT INTO x2_rules VALUES(0, 'a', 'x', 1); INSERT INTO x2_rules VALUES(0, 'b', 'x', 2); INSERT INTO x2_rules VALUES(0, 'c', 'x', 3); CREATE VIRTUAL TABLE x2 USING fuzzer(x2_rules); } faultsim_save_and_close } {} do_faultsim_test 2 -prep { faultsim_restore_and_reopen load_static_extension db fuzzer } -body { execsql { SELECT count(*) FROM x2 WHERE word MATCH 'abc'; } } -test { faultsim_test_result {0 8} {1 {vtable constructor failed: x2}} } |
︙ | ︙ | |||
74 75 76 77 78 79 80 | ); } faultsim_save_and_close } {} do_faultsim_test 3 -prep { faultsim_restore_and_reopen | | | 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 | ); } faultsim_save_and_close } {} do_faultsim_test 3 -prep { faultsim_restore_and_reopen load_static_extension db fuzzer } -body { execsql { CREATE VIRTUAL TABLE x1 USING fuzzer(x1_rules); SELECT count(*) FROM (SELECT * FROM x1 WHERE word MATCH 'a' LIMIT 2); } } -test { faultsim_test_result {0 2} {1 {vtable constructor failed: x1}} } finish_test |
Changes to test/incrblob.test.
︙ | ︙ | |||
119 120 121 122 123 124 125 126 127 128 129 130 131 132 | } } db close forcedelete test.db test.db-journal sqlite3 db test.db execsql "PRAGMA auto_vacuum = $AutoVacuumMode" do_test incrblob-2.$AutoVacuumMode.1 { set ::str [string repeat abcdefghij 2900] execsql { BEGIN; CREATE TABLE blobs(k PRIMARY KEY, v BLOB, i INTEGER); | > | 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 | } } db close forcedelete test.db test.db-journal sqlite3 db test.db execsql "PRAGMA mmap_size = 0" execsql "PRAGMA auto_vacuum = $AutoVacuumMode" do_test incrblob-2.$AutoVacuumMode.1 { set ::str [string repeat abcdefghij 2900] execsql { BEGIN; CREATE TABLE blobs(k PRIMARY KEY, v BLOB, i INTEGER); |
︙ | ︙ | |||
145 146 147 148 149 150 151 152 153 154 155 156 157 158 | } $AutoVacuumMode } do_test incrblob-2.$AutoVacuumMode.3 { # Open and close the db to make sure the page cache is empty. db close sqlite3 db test.db # Read the last 20 bytes of the blob via a blob handle. set ::blob [db incrblob blobs v 1] seek $::blob -20 end set ::fragment [read $::blob] close $::blob | > | 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 | } $AutoVacuumMode } do_test incrblob-2.$AutoVacuumMode.3 { # Open and close the db to make sure the page cache is empty. db close sqlite3 db test.db execsql "PRAGMA mmap_size = 0" # Read the last 20 bytes of the blob via a blob handle. set ::blob [db incrblob blobs v 1] seek $::blob -20 end set ::fragment [read $::blob] close $::blob |
︙ | ︙ | |||
167 168 169 170 171 172 173 174 175 176 177 178 179 180 | string range [db one {SELECT v FROM blobs}] end-19 end } $::fragment do_test incrblob-2.$AutoVacuumMode.5 { # Open and close the db to make sure the page cache is empty. db close sqlite3 db test.db # Write the second-to-last 20 bytes of the blob via a blob handle. # set ::blob [db incrblob blobs v 1] seek $::blob -40 end puts -nonewline $::blob "1234567890abcdefghij" flush $::blob | > | 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 | string range [db one {SELECT v FROM blobs}] end-19 end } $::fragment do_test incrblob-2.$AutoVacuumMode.5 { # Open and close the db to make sure the page cache is empty. db close sqlite3 db test.db execsql "PRAGMA mmap_size = 0" # Write the second-to-last 20 bytes of the blob via a blob handle. # set ::blob [db incrblob blobs v 1] seek $::blob -40 end puts -nonewline $::blob "1234567890abcdefghij" flush $::blob |
︙ | ︙ | |||
196 197 198 199 200 201 202 203 204 205 206 207 208 209 | string range [db one {SELECT v FROM blobs}] end-39 end-20 } "1234567890abcdefghij" do_test incrblob-2.$AutoVacuumMode.8 { # Open and close the db to make sure the page cache is empty. db close sqlite3 db test.db execsql { SELECT i FROM blobs } } {45} do_test incrblob-2.$AutoVacuumMode.9 { nRead db } [expr $AutoVacuumMode ? 4 : 30] | > | 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 | string range [db one {SELECT v FROM blobs}] end-39 end-20 } "1234567890abcdefghij" do_test incrblob-2.$AutoVacuumMode.8 { # Open and close the db to make sure the page cache is empty. db close sqlite3 db test.db execsql { PRAGMA mmap_size = 0 } execsql { SELECT i FROM blobs } } {45} do_test incrblob-2.$AutoVacuumMode.9 { nRead db } [expr $AutoVacuumMode ? 4 : 30] |
︙ | ︙ | |||
501 502 503 504 505 506 507 | } } {a different invocation} db2 close } sqlite3_soft_heap_limit $cmdlinearg(soft-heap-limit) #----------------------------------------------------------------------- | | | | 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 | } } {a different invocation} db2 close } sqlite3_soft_heap_limit $cmdlinearg(soft-heap-limit) #----------------------------------------------------------------------- # The following tests verify the behavior of the incremental IO # APIs in the following cases: # # 7.1 A row that containing an open blob is modified. # # 7.2 A CREATE TABLE requires that an overflow page that is part # of an open blob is moved. # # 7.3 An INCREMENTAL VACUUM moves an overflow page that is part # of an open blob. # # In the first case above, correct behavior is for all subsequent # read/write operations on the blob-handle to return SQLITE_ABORT. # More accurately, blob-handles are invalidated whenever the table # they belong to is written to. # # The second two cases have no external effect. They are testing # that the internal cache of overflow page numbers is correctly # invalidated. |
︙ | ︙ |
Changes to test/io.test.
︙ | ︙ | |||
12 13 14 15 16 17 18 19 20 21 22 23 24 25 | # The focus of this file is testing some specific characteristics of the # IO traffic generated by SQLite (making sure SQLite is not writing out # more database pages than it has to, stuff like that). # set testdir [file dirname $argv0] source $testdir/tester.tcl db close sqlite3_simulate_device sqlite3 db test.db -vfs devsym # Test summary: # | > | 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | # The focus of this file is testing some specific characteristics of the # IO traffic generated by SQLite (making sure SQLite is not writing out # more database pages than it has to, stuff like that). # set testdir [file dirname $argv0] source $testdir/tester.tcl set ::testprefix io db close sqlite3_simulate_device sqlite3 db test.db -vfs devsym # Test summary: # |
︙ | ︙ | |||
34 35 36 37 38 39 40 41 42 43 44 45 46 47 | # io-4.* - Test the IO traffic enhancements triggered when the # IOCAP_SAFE_APPEND device capability flag is set (fewer # fsync() calls on the journal file, no need to set nRec # field in the single journal header). # # io-5.* - Test that the default page size is selected and used # correctly. # set ::nWrite 0 proc nWrite {db} { set bt [btree_from_db $db] db_enter $db array set stats [btree_pager_stats $bt] | > > > > | 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | # io-4.* - Test the IO traffic enhancements triggered when the # IOCAP_SAFE_APPEND device capability flag is set (fewer # fsync() calls on the journal file, no need to set nRec # field in the single journal header). # # io-5.* - Test that the default page size is selected and used # correctly. # # io-6.* - Test that the pager-cache is not being flushed unnecessarily # after a transaction that uses the special atomic-write path # is committed. # set ::nWrite 0 proc nWrite {db} { set bt [btree_from_db $db] db_enter $db array set stats [btree_pager_stats $bt] |
︙ | ︙ | |||
203 204 205 206 207 208 209 | # Internally, this case is handled differently to the one above. The # journal file is not actually created until the 'COMMIT' statement # is executed. # # Changed 2010-03-27: The size of the database is now stored in # bytes 28..31 and so when a page is added to the database, page 1 # is immediately modified and the journal file immediately comes into | | | 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 | # Internally, this case is handled differently to the one above. The # journal file is not actually created until the 'COMMIT' statement # is executed. # # Changed 2010-03-27: The size of the database is now stored in # bytes 28..31 and so when a page is added to the database, page 1 # is immediately modified and the journal file immediately comes into # existence. To fix this test, the BEGIN is changed into a a # BEGIN IMMEDIATE and the INSERT is omitted. # do_test io-2.6.1 { execsql { BEGIN IMMEDIATE; -- INSERT INTO abc VALUES(9, randstr(1000,1000)); } |
︙ | ︙ | |||
560 561 562 563 564 565 566 567 568 569 | do_test io-5.$tn { execsql { CREATE TABLE abc(a, b, c); } expr {[file size test.db]/2} } $pgsize } sqlite3_simulate_device -char {} -sectorsize 0 finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 | do_test io-5.$tn { execsql { CREATE TABLE abc(a, b, c); } expr {[file size test.db]/2} } $pgsize } #---------------------------------------------------------------------- # do_test io-6.1 { db close sqlite3_simulate_device -char atomic forcedelete test.db sqlite3 db test.db -vfs devsym execsql { PRAGMA mmap_size = 0; PRAGMA page_size = 1024; CREATE TABLE t1(x); CREATE TABLE t2(x); CREATE TABLE t3(x); CREATE INDEX i3 ON t3(x); INSERT INTO t3 VALUES(randomblob(100)); INSERT INTO t3 SELECT randomblob(100) FROM t3; INSERT INTO t3 SELECT randomblob(100) FROM t3; INSERT INTO t3 SELECT randomblob(100) FROM t3; INSERT INTO t3 SELECT randomblob(100) FROM t3; INSERT INTO t3 SELECT randomblob(100) FROM t3; INSERT INTO t3 SELECT randomblob(100) FROM t3; INSERT INTO t3 SELECT randomblob(100) FROM t3; INSERT INTO t3 SELECT randomblob(100) FROM t3; INSERT INTO t3 SELECT randomblob(100) FROM t3; INSERT INTO t3 SELECT randomblob(100) FROM t3; INSERT INTO t3 SELECT randomblob(100) FROM t3; } db_save_and_close } {} foreach {tn sql} { 1 { BEGIN; INSERT INTO t1 VALUES('123'); INSERT INTO t2 VALUES('456'); COMMIT; } 2 { BEGIN; INSERT INTO t1 VALUES('123'); COMMIT; } } { db_restore sqlite3 db test.db -vfs devsym execsql { PRAGMA mmap_size = 0; SELECT x FROM t3 ORDER BY rowid; SELECT x FROM t3 ORDER BY x; } do_execsql_test 6.2.$tn.1 { PRAGMA integrity_check } {ok} do_execsql_test 6.2.$tn.2 $sql # Corrupt the database file on disk. This should not matter for the # purposes of the following "PRAGMA integrity_check", as the entire # database should be cached in the pager-cache. If corruption is # reported, it indicates that executing $sql caused the pager cache # to be flushed. Which is a bug. hexio_write test.db [expr 1024 * 5] [string repeat 00 2048] do_execsql_test 6.2.$tn.3 { PRAGMA integrity_check } {ok} db close } sqlite3_simulate_device -char {} -sectorsize 0 finish_test |
Changes to test/loadext.test.
︙ | ︙ | |||
135 136 137 138 139 140 141 | # do_test loadext-2.1 { forcedelete ${testextension}xx set rc [catch { sqlite3_load_extension db "${testextension}xx" } msg] list $rc $msg | | | > > > | < | | | 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 | # do_test loadext-2.1 { forcedelete ${testextension}xx set rc [catch { sqlite3_load_extension db "${testextension}xx" } msg] list $rc $msg } /[list 1 [format $dlerror_nosuchfile ${testextension}xx.*]]/ # Try to load an extension for which the file is not a shared object # do_test loadext-2.2 { set fd [open "./notasharedlib.so" w] puts $fd blah close $fd set fd [open "./notasharedlib.dll" w] puts $fd blah close $fd set rc [catch { sqlite3_load_extension db "./notasharedlib" } msg] list $rc $msg } /[list 1 [format $dlerror_notadll ./notasharedlib.*]]/ # Try to load an extension for which the file is present but the # entry point is not. # do_test loadext-2.3 { set rc [catch { sqlite3_load_extension db $testextension icecream |
︙ | ︙ | |||
192 193 194 195 196 197 198 | set res [catchsql { SELECT load_extension($::testextension) }] if {$::tcl_platform(os) eq "Darwin"} { regsub {0x[1234567890abcdefABCDEF]*} $res XXX res } set res | | | 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 | set res [catchsql { SELECT load_extension($::testextension) }] if {$::tcl_platform(os) eq "Darwin"} { regsub {0x[1234567890abcdefABCDEF]*} $res XXX res } set res } /[list 1 [format $dlerror_nosymbol $testextension sqlite3_.*_init]]/ do_test loadext-3.3 { catchsql { SELECT load_extension($::testextension,'testloadext_init') } } {0 {{}}} do_test loadext-3.4 { catchsql { |
︙ | ︙ |
Changes to test/malloc.test.
︙ | ︙ | |||
838 839 840 841 842 843 844 | CREATE TABLE t1(a, b); INSERT INTO t1 VALUES(1, 2); INSERT INTO t1 VALUES(3, 4); } -sqlbody { SELECT test_agg_errmsg16(), group_concat(a) FROM t1 } | | | 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 | CREATE TABLE t1(a, b); INSERT INTO t1 VALUES(1, 2); INSERT INTO t1 VALUES(3, 4); } -sqlbody { SELECT test_agg_errmsg16(), group_concat(a) FROM t1 } # At one point, if an OOM occurred immediately after obtaining a shared lock # on the database file, the file remained locked. This test case ensures # that bug has been fixed.i if {[db eval {PRAGMA locking_mode}]!="exclusive"} { do_malloc_test 37 -tclprep { sqlite3 db2 test.db execsql { CREATE TABLE t1(a, b); |
︙ | ︙ |
Changes to test/malloc3.test.
︙ | ︙ | |||
591 592 593 594 595 596 597 | set ac [sqlite3_get_autocommit $::DB] ;# Auto-Commit sqlite3_memdebug_fail $iFail -repeat 0 set rc [catch {db eval [lindex $v 2]} msg] ;# True error occurs set nac [sqlite3_get_autocommit $::DB] ;# New Auto-Commit if {$rc != 0 && $nac && !$ac} { # Before [db eval] the auto-commit flag was clear. Now it | | | | 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 | set ac [sqlite3_get_autocommit $::DB] ;# Auto-Commit sqlite3_memdebug_fail $iFail -repeat 0 set rc [catch {db eval [lindex $v 2]} msg] ;# True error occurs set nac [sqlite3_get_autocommit $::DB] ;# New Auto-Commit if {$rc != 0 && $nac && !$ac} { # Before [db eval] the auto-commit flag was clear. Now it # is set. Since an error occurred we assume this was not a # commit - therefore a rollback occurred. Check that the # rollback-hook was invoked. do_test malloc3-rollback_hook_count.$iterid { set ::rollback_hook_count } {1} } set nFail [sqlite3_memdebug_fail -1 -benigncnt nBenign] |
︙ | ︙ |
Changes to test/malloc_common.tcl.
︙ | ︙ | |||
260 261 262 263 264 265 266 | # by -test scripts. # proc faultsim_test_result_int {args} { upvar testrc testrc testresult testresult testnfail testnfail set t [list $testrc $testresult] set r $args if { ($testnfail==0 && $t != [lindex $r 0]) || [lsearch $r $t]<0 } { | | | 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 | # by -test scripts. # proc faultsim_test_result_int {args} { upvar testrc testrc testresult testresult testnfail testnfail set t [list $testrc $testresult] set r $args if { ($testnfail==0 && $t != [lindex $r 0]) || [lsearch $r $t]<0 } { error "nfail=$testnfail rc=$testrc result=$testresult list=$r" } } #-------------------------------------------------------------------------- # Usage do_one_faultsim_test NAME ?OPTIONS...? # # The first argument, <test number>, is used as a prefix of the test names |
︙ | ︙ |
Changes to test/memdb.test.
︙ | ︙ | |||
361 362 363 364 365 366 367 | DELETE FROM t5 WHERE x>0; SELECT * FROM t5; } } {} ifcapable subquery&&vtab { do_test memdb-7.1 { | | | 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 | DELETE FROM t5 WHERE x>0; SELECT * FROM t5; } } {} ifcapable subquery&&vtab { do_test memdb-7.1 { load_static_extension db wholenumber execsql { CREATE TABLE t6(x); CREATE VIRTUAL TABLE nums USING wholenumber; INSERT INTO t6 SELECT value FROM nums WHERE value BETWEEN 1 AND 256; SELECT count(*) FROM (SELECT DISTINCT x FROM t6); } } {256} |
︙ | ︙ |
Added test/mmap1.test.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 | # 2013 March 20 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable !mmap { finish_test return } source $testdir/lock_common.tcl set testprefix mmap1 proc nRead {db} { set bt [btree_from_db $db] db_enter $db array set stats [btree_pager_stats $bt] db_leave $db # puts [array get stats] return $stats(read) } proc register_rblob_code {dbname seed} { return [subst -nocommands { set ::rcnt $seed proc rblob {n} { set ::rcnt [expr (([set ::rcnt] << 3) + [set ::rcnt] + 456) & 0xFFFFFFFF] set str [format %.8x [expr [set ::rcnt] ^ 0xbdf20da3]] string range [string repeat [set str] [expr [set n]/4]] 1 [set n] } $dbname func rblob rblob }] } # For cases 1.1 and 1.4, the number of pages read using xRead() is 4 on # unix and 9 on windows. The difference is that windows only ever maps # an integer number of OS pages (i.e. creates mappings that are a multiple # of 4KB in size). Whereas on unix any sized mapping may be created. # foreach {t mmap_size nRead c2init} { 1.1 { PRAGMA mmap_size = 67108864 } /[49]/ {PRAGMA mmap_size = 0} 1.2 { PRAGMA mmap_size = 53248 } 150 {PRAGMA mmap_size = 0} 1.3 { PRAGMA mmap_size = 0 } 344 {PRAGMA mmap_size = 0} 1.4 { PRAGMA mmap_size = 67108864 } /[49]/ {PRAGMA mmap_size = 67108864 } 1.5 { PRAGMA mmap_size = 53248 } 150 {PRAGMA mmap_size = 67108864 } 1.6 { PRAGMA mmap_size = 0 } 344 {PRAGMA mmap_size = 67108864 } } { do_multiclient_test tn { sql1 {PRAGMA page_size=1024} sql1 $mmap_size sql2 $c2init code2 [register_rblob_code db2 0] sql2 { PRAGMA page_size=1024; PRAGMA auto_vacuum = 1; CREATE TABLE t1(a, b, UNIQUE(a, b)); INSERT INTO t1 VALUES(rblob(500), rblob(500)); INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 2 INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 4 INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 8 INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 16 INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 32 } do_test $t.$tn.1 { sql1 "SELECT count(*) FROM t1; PRAGMA integrity_check ; PRAGMA page_count" } {32 ok 77} # Have connection 2 shrink the file. Check connection 1 can still read it. sql2 { DELETE FROM t1 WHERE rowid%2; } do_test $t.$tn.2 { sql1 "SELECT count(*) FROM t1; PRAGMA integrity_check ; PRAGMA page_count" } {16 ok 42} # Have connection 2 grow the file. Check connection 1 can still read it. sql2 { INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1 } do_test $t.$tn.3 { sql1 "SELECT count(*) FROM t1; PRAGMA integrity_check ; PRAGMA page_count" } {32 ok 79} # Have connection 2 grow the file again. Check connection 1 is still ok. sql2 { INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1 } do_test $t.$tn.4 { sql1 "SELECT count(*) FROM t1; PRAGMA integrity_check ; PRAGMA page_count" } {64 ok 149} # Check that the number of pages read by connection 1 indicates that the # "PRAGMA mmap_size" command worked. do_test $t.$tn.5 { nRead db } $nRead } } set ::rcnt 0 proc rblob {n} { set ::rcnt [expr (($::rcnt << 3) + $::rcnt + 456) & 0xFFFFFFFF] set str [format %.8x [expr $::rcnt ^ 0xbdf20da3]] string range [string repeat $str [expr $n/4]] 1 $n } reset_db db func rblob rblob do_execsql_test 2.1 { PRAGMA auto_vacuum = 1; PRAGMA mmap_size = 67108864; PRAGMA journal_mode = wal; CREATE TABLE t1(a, b, UNIQUE(a, b)); INSERT INTO t1 VALUES(rblob(500), rblob(500)); INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 2 INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 4 INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 8 INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 16 INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 32 PRAGMA wal_checkpoint; } {67108864 wal 0 103 103} do_execsql_test 2.2 { PRAGMA auto_vacuum; SELECT count(*) FROM t1; } {1 32} do_test 2.3 { sqlite3 db2 test.db db2 func rblob rblob db2 eval { DELETE FROM t1 WHERE (rowid%4); PRAGMA wal_checkpoint; } db2 eval { INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 16 SELECT count(*) FROM t1; } } {16} do_execsql_test 2.4 { PRAGMA wal_checkpoint; } {0 24 24} db2 close reset_db db func rblob rblob do_execsql_test 3.1 { PRAGMA auto_vacuum = 1; CREATE TABLE t1(a, b, UNIQUE(a, b)); INSERT INTO t1 VALUES(rblob(500), rblob(500)); INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 2 INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 4 INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 8 CREATE TABLE t2(a, b, UNIQUE(a, b)); INSERT INTO t2 SELECT * FROM t1; } {} do_test 3.2 { set nRow 0 db eval {SELECT * FROM t2 ORDER BY a, b} { if {$nRow==4} { db eval { DELETE FROM t1 } } incr nRow } set nRow } {8} #------------------------------------------------------------------------- # Ensure that existing cursors using xFetch() pages see changes made # to rows using the incrblob API. # reset_db set aaa [string repeat a 400] set bbb [string repeat b 400] set ccc [string repeat c 400] set ddd [string repeat d 400] set eee [string repeat e 400] do_execsql_test 4.1 { PRAGMA page_size = 1024; CREATE TABLE t1(x); INSERT INTO t1 VALUES($aaa); INSERT INTO t1 VALUES($bbb); INSERT INTO t1 VALUES($ccc); INSERT INTO t1 VALUES($ddd); SELECT * FROM t1; BEGIN; } [list $aaa $bbb $ccc $ddd] do_test 4.2 { set ::STMT [sqlite3_prepare db "SELECT * FROM t1 ORDER BY rowid" -1 dummy] sqlite3_step $::STMT sqlite3_column_text $::STMT 0 } $aaa do_test 4.3 { foreach r {2 3 4} { set fd [db incrblob t1 x $r] puts -nonewline $fd $eee close $fd } set res [list] while {"SQLITE_ROW" == [sqlite3_step $::STMT]} { lappend res [sqlite3_column_text $::STMT 0] } set res } [list $eee $eee $eee] do_test 4.4 { sqlite3_finalize $::STMT } SQLITE_OK do_execsql_test 4.5 { COMMIT } #------------------------------------------------------------------------- # Ensure that existing cursors holding xFetch() references are not # confused if those pages are moved to make way for the root page of a # new table or index. # reset_db do_execsql_test 5.1 { PRAGMA auto_vacuum = 2; PRAGMA page_size = 1024; CREATE TABLE t1(x); INSERT INTO t1 VALUES($aaa); INSERT INTO t1 VALUES($bbb); INSERT INTO t1 VALUES($ccc); INSERT INTO t1 VALUES($ddd); PRAGMA auto_vacuum; SELECT * FROM t1; } [list 2 $aaa $bbb $ccc $ddd] do_test 5.2 { set ::STMT [sqlite3_prepare db "SELECT * FROM t1 ORDER BY rowid" -1 dummy] sqlite3_step $::STMT sqlite3_column_text $::STMT 0 } $aaa do_execsql_test 5.3 { CREATE TABLE t2(x); INSERT INTO t2 VALUES('tricked you!'); INSERT INTO t2 VALUES('tricked you!'); } do_test 5.4 { sqlite3_step $::STMT sqlite3_column_text $::STMT 0 } $bbb do_test 5.5 { sqlite3_finalize $::STMT } SQLITE_OK #------------------------------------------------------------------------- # Test various mmap_size settings. # foreach {tn1 mmap1 mmap2} { 1 6144 167773 2 18432 140399 3 43008 401302 4 92160 253899 5 190464 2 6 387072 752431 7 780288 291143 8 1566720 594306 9 3139584 829137 10 6285312 793963 11 12576768 1015590 } { do_multiclient_test tn { sql1 { CREATE TABLE t1(a PRIMARY KEY); CREATE TABLE t2(x); INSERT INTO t2 VALUES(''); } code1 [register_rblob_code db 0] code2 [register_rblob_code db2 444] sql1 "PRAGMA mmap_size = $mmap1" sql2 "PRAGMA mmap_size = $mmap2" do_test $tn1.$tn { for {set i 1} {$i <= 100} {incr i} { if {$i % 2} { set c1 sql1 set c2 sql2 } else { set c1 sql2 set c2 sql1 } $c1 { INSERT INTO t1 VALUES( rblob(5000) ); UPDATE t2 SET x = (SELECT md5sum(a) FROM t1); } set res [$c2 { SELECT count(*) FROM t1; SELECT x == (SELECT md5sum(a) FROM t1) FROM t2; PRAGMA integrity_check; }] if {$res != [list $i 1 ok]} { do_test $tn1.$tn.$i { set ::res } [list $i 1 ok] } } set res 1 } {1} } } finish_test |
Added test/mmap2.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 | # 2013 March 20 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # # This file tests the effect of the mmap() or mremap() system calls # returning an error on the library. # # If either mmap() or mremap() fails, SQLite should log an error # message, then continue accessing the database using read() and # write() exclusively. # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix mmap2 if {$::tcl_platform(platform)!="unix" || [test_syscall defaultvfs] != "unix"} { finish_test return } ifcapable !mmap { finish_test return } db close sqlite3_shutdown test_sqlite3_log xLog proc xLog {error_code msg} { if {[string match os_unix.c* $msg]} { lappend ::log $msg } } foreach syscall {mmap mremap} { test_syscall uninstall if {[catch {test_syscall install $syscall}]} continue for {set i 1} {$i < 20} {incr i} { reset_db test_syscall fault $i 1 test_syscall errno $syscall ENOMEM set ::log "" do_execsql_test 1.$syscall.$i.1 { CREATE TABLE t1(a, b, UNIQUE(a, b)); INSERT INTO t1 VALUES(randomblob(1000), randomblob(1000)); INSERT INTO t1 SELECT randomblob(1000), randomblob(1000) FROM t1; INSERT INTO t1 SELECT randomblob(1000), randomblob(1000) FROM t1; INSERT INTO t1 SELECT randomblob(1000), randomblob(1000) FROM t1; INSERT INTO t1 SELECT randomblob(1000), randomblob(1000) FROM t1; INSERT INTO t1 SELECT randomblob(1000), randomblob(1000) FROM t1; INSERT INTO t1 SELECT randomblob(1000), randomblob(1000) FROM t1; } set nFail [test_syscall fault 0 0] do_execsql_test 1.$syscall.$i.2 { SELECT count(*) FROM t1; PRAGMA integrity_check; } {64 ok} do_test 1.$syscall.$i.3 { expr {$nFail==0 || $nFail==1} } {1} do_test 1.$syscall.$i.4.nFail=$nFail { regexp ".*${syscall}.*" $::log } [expr $nFail>0] } } db close test_syscall uninstall sqlite3_shutdown test_sqlite3_log sqlite3_initialize finish_test |
Changes to test/notify2.test.
︙ | ︙ | |||
146 147 148 149 150 151 152 | sqlite3_close $::DB opendb } } elseif {$rc} { # Hit some other kind of error. This is a malfunction. error $msg } else { | | | | 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 | sqlite3_close $::DB opendb } } elseif {$rc} { # Hit some other kind of error. This is a malfunction. error $msg } else { # No error occurred. Check that any SELECT statements in the transaction # returned "1". Otherwise, the invariant was false, indicating that # some malfunction has occurred. foreach r $msg { if {$r != 1} { puts "Invariant check failed: $msg" } } } } # Close the database connection and return 0. # sqlite3_close $::DB |
︙ | ︙ |
Added test/numcast.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 | # 2013 March 20 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. # This particular file does testing of casting strings into numeric # values. # set testdir [file dirname $argv0] source $testdir/tester.tcl foreach enc {utf8 utf16le utf16be} { do_test numcast-$enc.0 { db close sqlite3 db :memory: db eval "PRAGMA encoding='$enc'" set x [db eval {PRAGMA encoding}] string map {- {}} [string tolower $x] } $enc foreach {idx str rval ival} { 1 12345.0 12345.0 12345 2 12345.0e0 12345.0 12345 3 -12345.0e0 -12345.0 -12345 4 -12345.25 -12345.25 -12345 5 { -12345.0} -12345.0 -12345 6 { 876xyz} 876.0 876 7 { 456Ä·89} 456.0 456 8 { Ä 321.5} 0.0 0 } { do_test numcast-$enc.$idx.1 { db eval {SELECT CAST($str AS real)} } $rval do_test numcast-$enc.$idx.2 { db eval {SELECT CAST($str AS integer)} } $ival } } finish_test |
Added test/orderby4.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 | # 2013 March 26 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this file is testing that the optimizations that disable # ORDER BY clauses work correctly on multi-value primary keys and # unique indices when only some prefix of the terms in the key are # used. See ticket http://www.sqlite.org/src/info/a179fe74659 # set testdir [file dirname $argv0] source $testdir/tester.tcl set ::testprefix orderby4 # Generate test data for a join. Verify that the join gets the # correct answer. # do_execsql_test 1.1 { CREATE TABLE t1(a, b, PRIMARY KEY(a,b)); INSERT INTO t1 VALUES(1,1),(1,2); CREATE TABLE t2(x, y, PRIMARY KEY(x,y)); INSERT INTO t2 VALUES(3,3),(4,4); SELECT a, x FROM t1, t2 ORDER BY 1, 2; } {1 3 1 3 1 4 1 4} do_execsql_test 1.2 { SELECT a, x FROM t1 CROSS JOIN t2 ORDER BY 1, 2; } {1 3 1 3 1 4 1 4} do_execsql_test 1.3 { SELECT a, x FROM t2 CROSS JOIN t1 ORDER BY 1, 2; } {1 3 1 3 1 4 1 4} do_execsql_test 2.1 { CREATE TABLE t3(a); INSERT INTO t3 VALUES(1),(1); CREATE INDEX t3a ON t3(a); CREATE TABLE t4(x); INSERT INTO t4 VALUES(3),(4); CREATE INDEX t4x ON t4(x); SELECT a, x FROM t3, t4 ORDER BY 1, 2; } {1 3 1 3 1 4 1 4} do_execsql_test 2.2 { SELECT a, x FROM t3 CROSS JOIN t4 ORDER BY 1, 2; } {1 3 1 3 1 4 1 4} do_execsql_test 2.3 { SELECT a, x FROM t4 CROSS JOIN t3 ORDER BY 1, 2; } {1 3 1 3 1 4 1 4} finish_test |
Changes to test/pager1.test.
︙ | ︙ | |||
11 12 13 14 15 16 17 18 19 20 21 22 23 24 | # set testdir [file dirname $argv0] source $testdir/tester.tcl source $testdir/lock_common.tcl source $testdir/malloc_common.tcl source $testdir/wal_common.tcl # Do not use a codec for tests in this file, as the database file is # manipulated directly using tcl scripts (using the [hexio_write] command). # do_not_use_codec # | > | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | # set testdir [file dirname $argv0] source $testdir/tester.tcl source $testdir/lock_common.tcl source $testdir/malloc_common.tcl source $testdir/wal_common.tcl set testprefix pager1 # Do not use a codec for tests in this file, as the database file is # manipulated directly using tcl scripts (using the [hexio_write] command). # do_not_use_codec # |
︙ | ︙ | |||
1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 | #------------------------------------------------------------------------- # Test that regardless of the value returned by xSectorSize(), the # minimum effective sector-size is 512 and the maximum 65536 bytes. # testvfs tv -default 1 foreach sectorsize { 32 64 128 256 512 1024 2048 4096 8192 16384 32768 65536 131072 262144 } { tv sectorsize $sectorsize tv devchar {} set eff $sectorsize if {$sectorsize < 512} { set eff 512 } | > | 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 | #------------------------------------------------------------------------- # Test that regardless of the value returned by xSectorSize(), the # minimum effective sector-size is 512 and the maximum 65536 bytes. # testvfs tv -default 1 foreach sectorsize { 16 32 64 128 256 512 1024 2048 4096 8192 16384 32768 65536 131072 262144 } { tv sectorsize $sectorsize tv devchar {} set eff $sectorsize if {$sectorsize < 512} { set eff 512 } |
︙ | ︙ | |||
1400 1401 1402 1403 1404 1405 1406 | BEGIN; CREATE TABLE t1(a, b); CREATE TABLE t2(a, b); CREATE TABLE t3(a, b); COMMIT; } file size test.db-journal | | | 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 | BEGIN; CREATE TABLE t1(a, b); CREATE TABLE t2(a, b); CREATE TABLE t3(a, b); COMMIT; } file size test.db-journal } [expr $sectorsize > 65536 ? 65536 : ($sectorsize<32 ? 512 : $sectorsize)] do_test pager1-10.$sectorsize.2 { execsql { INSERT INTO t3 VALUES(a_string(300), a_string(300)); INSERT INTO t3 SELECT * FROM t3; /* 2 */ INSERT INTO t3 SELECT * FROM t3; /* 4 */ INSERT INTO t3 SELECT * FROM t3; /* 8 */ |
︙ | ︙ | |||
2239 2240 2241 2242 2243 2244 2245 | SAVEPOINT abc; CREATE TABLE t1(a, b); ROLLBACK TO abc; COMMIT; } db close } {} | < | 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 | SAVEPOINT abc; CREATE TABLE t1(a, b); ROLLBACK TO abc; COMMIT; } db close } {} do_test pager1-25-2 { faultsim_delete_and_reopen execsql { SAVEPOINT abc; CREATE TABLE t1(a, b); ROLLBACK TO abc; COMMIT; |
︙ | ︙ | |||
2518 2519 2520 2521 2522 2523 2524 2525 2526 | } {1 {disk I/O error}} do_test pager1-33.2 { file rename bak-journal test.db-journal execsql { SELECT * FROM t1 } } {one two} } finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 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 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 | } {1 {disk I/O error}} do_test pager1-33.2 { file rename bak-journal test.db-journal execsql { SELECT * FROM t1 } } {one two} } #------------------------------------------------------------------------- # Test that appending pages to the database file then moving those pages # to the free-list before the transaction is committed does not cause # an error. # foreach {tn pragma strsize} { 1 { PRAGMA mmap_size = 0 } 2400 2 { } 2400 3 { PRAGMA mmap_size = 0 } 4400 4 { } 4400 } { reset_db db func a_string a_string db eval $pragma do_execsql_test 34.$tn.1 { CREATE TABLE t1(a, b); INSERT INTO t1 VALUES(1, 2); } do_execsql_test 34.$tn.2 { BEGIN; INSERT INTO t1 VALUES(2, a_string($strsize)); DELETE FROM t1 WHERE oid=2; COMMIT; PRAGMA integrity_check; } {ok} } #------------------------------------------------------------------------- # reset_db do_test 35 { sqlite3 db test.db execsql { CREATE TABLE t1(x, y); PRAGMA journal_mode = WAL; INSERT INTO t1 VALUES(1, 2); } execsql { BEGIN; CREATE TABLE t2(a, b); } hexio_write test.db-shm [expr 16*1024] [string repeat 0055 8192] catchsql ROLLBACK } {0 {}} do_multiclient_test tn { sql1 { PRAGMA auto_vacuum = 0; CREATE TABLE t1(x, y); INSERT INTO t1 VALUES(1, 2); } do_test 36.$tn.1 { sql2 { PRAGMA max_page_count = 2 } list [catch { sql2 { CREATE TABLE t2(x) } } msg] $msg } {1 {database or disk is full}} sql1 { PRAGMA checkpoint_fullfsync = 1 } sql1 { CREATE TABLE t2(x) } do_test 36.$tn.2 { sql2 { INSERT INTO t2 VALUES('xyz') } list [catch { sql2 { CREATE TABLE t3(x) } } msg] $msg } {1 {database or disk is full}} } forcedelete test1 test2 foreach {tn uri} { 1 {file:?mode=memory&cache=shared} 2 {file:one?mode=memory&cache=shared} 3 {file:test1?cache=shared} 4 {file:test2?another=parameter&yet=anotherone} } { do_test 37.$tn { catch { db close } sqlite3_shutdown sqlite3_config_uri 1 sqlite3 db $uri db eval { CREATE TABLE t1(x); INSERT INTO t1 VALUES(1); SELECT * FROM t1; } } {1} do_execsql_test 37.$tn.2 { VACUUM; SELECT * FROM t1; } {1} db close sqlite3_shutdown sqlite3_config_uri 0 } do_test 38.1 { catch { db close } forcedelete test.db set fd [open test.db w] puts $fd "hello world" close $fd sqlite3 db test.db catchsql { CREATE TABLE t1(x) } } {1 {file is encrypted or is not a database}} do_test 38.2 { catch { db close } forcedelete test.db } {} do_test 39.1 { sqlite3 db test.db execsql { PRAGMA auto_vacuum = 1; CREATE TABLE t1(x); INSERT INTO t1 VALUES('xxx'); INSERT INTO t1 VALUES('two'); INSERT INTO t1 VALUES(randomblob(400)); INSERT INTO t1 VALUES(randomblob(400)); INSERT INTO t1 VALUES(randomblob(400)); INSERT INTO t1 VALUES(randomblob(400)); BEGIN; UPDATE t1 SET x = 'one' WHERE rowid=1; } set ::stmt [sqlite3_prepare db "SELECT * FROM t1 ORDER BY rowid" -1 dummy] sqlite3_step $::stmt sqlite3_column_text $::stmt 0 } {one} do_test 39.2 { execsql { CREATE TABLE t2(x) } sqlite3_step $::stmt sqlite3_column_text $::stmt 0 } {two} do_test 39.3 { sqlite3_finalize $::stmt execsql COMMIT } {} do_execsql_test 39.4 { PRAGMA auto_vacuum = 2; CREATE TABLE t3(x); CREATE TABLE t4(x); DROP TABLE t2; DROP TABLE t3; DROP TABLE t4; } do_test 39.5 { db close sqlite3 db test.db execsql { PRAGMA cache_size = 1; PRAGMA incremental_vacuum; PRAGMA integrity_check; } } {ok} do_test 40.1 { reset_db execsql { PRAGMA auto_vacuum = 1; CREATE TABLE t1(x PRIMARY KEY); INSERT INTO t1 VALUES(randomblob(1200)); PRAGMA page_count; } } {6} do_test 40.2 { execsql { INSERT INTO t1 VALUES(randomblob(1200)); INSERT INTO t1 VALUES(randomblob(1200)); INSERT INTO t1 VALUES(randomblob(1200)); } } {} do_test 40.3 { db close sqlite3 db test.db execsql { PRAGMA cache_size = 1; CREATE TABLE t2(x); PRAGMA integrity_check; } } {ok} do_test 41.1 { reset_db execsql { CREATE TABLE t1(x PRIMARY KEY); INSERT INTO t1 VALUES(randomblob(200)); INSERT INTO t1 SELECT randomblob(200) FROM t1; INSERT INTO t1 SELECT randomblob(200) FROM t1; INSERT INTO t1 SELECT randomblob(200) FROM t1; INSERT INTO t1 SELECT randomblob(200) FROM t1; INSERT INTO t1 SELECT randomblob(200) FROM t1; INSERT INTO t1 SELECT randomblob(200) FROM t1; } } {} do_test 41.2 { testvfs tv -default 1 tv sectorsize 16384; tv devchar [list] db close sqlite3 db test.db execsql { PRAGMA cache_size = 1; DELETE FROM t1 WHERE rowid%4; PRAGMA integrity_check; } } {ok} db close tv delete set pending_prev [sqlite3_test_control_pending_byte 0x1000000] do_test 42.1 { reset_db execsql { CREATE TABLE t1(x, y); INSERT INTO t1 VALUES(randomblob(200), randomblob(200)); INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1; INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1; INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1; INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1; INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1; INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1; INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1; INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1; INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1; } db close sqlite3_test_control_pending_byte 0x0010000 sqlite3 db test.db db eval { PRAGMA mmap_size = 0 } catchsql { SELECT sum(length(y)) FROM t1 } } {1 {database disk image is malformed}} do_test 42.2 { reset_db execsql { CREATE TABLE t1(x, y); INSERT INTO t1 VALUES(randomblob(200), randomblob(200)); INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1; INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1; INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1; INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1; INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1; INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1; INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1; INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1; } db close testvfs tv -default 1 tv sectorsize 16384; tv devchar [list] sqlite3 db test.db -vfs tv execsql { UPDATE t1 SET x = randomblob(200) } } {} db close tv delete sqlite3_test_control_pending_byte $pending_prev do_test 43.1 { reset_db execsql { CREATE TABLE t1(x, y); INSERT INTO t1 VALUES(1, 2); CREATE TABLE t2(x, y); INSERT INTO t2 VALUES(1, 2); CREATE TABLE t3(x, y); INSERT INTO t3 VALUES(1, 2); } db close sqlite3 db test.db db eval { PRAGMA mmap_size = 0 } db eval { SELECT * FROM t1 } sqlite3_db_status db CACHE_MISS 0 } {0 2 0} do_test 43.2 { db eval { SELECT * FROM t2 } sqlite3_db_status db CACHE_MISS 1 } {0 3 0} do_test 43.3 { db eval { SELECT * FROM t3 } sqlite3_db_status db CACHE_MISS 0 } {0 1 0} finish_test |
Changes to test/pager2.test.
︙ | ︙ | |||
114 115 116 117 118 119 120 | } } db close tv delete #------------------------------------------------------------------------- | < | 114 115 116 117 118 119 120 121 122 123 124 125 126 127 | } } db close tv delete #------------------------------------------------------------------------- # pager2-2.1: Test a ROLLBACK with journal_mode=off. # pager2-2.2: Test shrinking the database (auto-vacuum) with # journal_mode=off # do_test pager2-2.1 { faultsim_delete_and_reopen execsql { |
︙ | ︙ | |||
143 144 145 146 147 148 149 150 151 | CREATE TABLE t1(a, b); INSERT INTO t1 VALUES(zeroblob(5000), zeroblob(5000)); DELETE FROM t1; PRAGMA incremental_vacuum; } file size test.db } {3072} finish_test | > > > > > > > > > > > > > > > > > > | 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 | CREATE TABLE t1(a, b); INSERT INTO t1 VALUES(zeroblob(5000), zeroblob(5000)); DELETE FROM t1; PRAGMA incremental_vacuum; } file size test.db } {3072} #------------------------------------------------------------------------- # Test that shared in-memory databases seem to work. # db close do_test pager2-3.1 { forcedelete test.db sqlite3_shutdown sqlite3_config_uri 1 sqlite3 db1 {file:test.db?mode=memory&cache=shared} sqlite3 db2 {file:test.db?mode=memory&cache=shared} sqlite3 db3 test.db db1 eval { CREATE TABLE t1(a, b) } db2 eval { INSERT INTO t1 VALUES(1, 2) } list [catch { db3 eval { INSERT INTO t1 VALUES(3, 4) } } msg] $msg } {1 {no such table: t1}} finish_test |
Changes to test/pagerfault.test.
︙ | ︙ | |||
1242 1243 1244 1245 1246 1247 1248 1249 1250 | } -test { catchsql { UPDATE t2 SET a = a_string(800), b = a_string(800) } catch { close $::channel } catchsql { ROLLBACK } faultsim_integrity_check } finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 | } -test { catchsql { UPDATE t2 SET a = a_string(800), b = a_string(800) } catch { close $::channel } catchsql { ROLLBACK } faultsim_integrity_check } #------------------------------------------------------------------------- # do_test pagerfault-28-pre { faultsim_delete_and_reopen db func a_string a_string execsql { PRAGMA page_size = 512; PRAGMA journal_mode = wal; PRAGMA wal_autocheckpoint = 0; PRAGMA cache_size = 100000; BEGIN; CREATE TABLE t2(a UNIQUE, b UNIQUE); INSERT INTO t2 VALUES( a_string(800), a_string(800) ); INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2; INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2; INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2; INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2; INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2; INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2; INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2; INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2; INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2; INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2; INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2; COMMIT; CREATE TABLE t1(a PRIMARY KEY, b); } expr {[file size test.db-shm] >= 96*1024} } {1} faultsim_save_and_close do_faultsim_test pagerfault-28a -faults oom* -prep { faultsim_restore_and_reopen execsql { PRAGMA mmap_size=0 } sqlite3 db2 test.db db2 eval { SELECT count(*) FROM t2 } db func a_string a_string execsql { BEGIN; INSERT INTO t1 VALUES(a_string(2000), a_string(2000)); INSERT INTO t1 VALUES(a_string(2000), a_string(2000)); } set ::STMT [sqlite3_prepare db "SELECT * FROM t1 ORDER BY a" -1 DUMMY] sqlite3_step $::STMT } -body { execsql { ROLLBACK } } -test { db2 close sqlite3_finalize $::STMT catchsql { ROLLBACK } faultsim_integrity_check } faultsim_restore_and_reopen sqlite3 db2 test.db db2 eval {SELECT count(*) FROM t2} db close do_faultsim_test pagerfault-28b -faults oom* -prep { sqlite3 db test.db } -body { execsql { SELECT count(*) FROM t2 } } -test { faultsim_test_result {0 2048} db close } db2 close #------------------------------------------------------------------------- # Try this: # # 1) Put the pager in ERROR state (error during rollback) # # 2) Next time the connection is used inject errors into all xWrite() and # xUnlock() calls. This causes the hot-journal rollback to fail and # the pager to declare its locking state UNKNOWN. # # 3) Same again. # # 4a) Stop injecting errors. Allow the rollback to succeed. Check that # the database is Ok. Or, # # 4b) Close and reopen the db. Check that the db is Ok. # proc custom_injectinstall {} { testvfs custom -default true custom filter {xWrite xUnlock} } proc custom_injectuninstall {} { catch {db close} catch {db2 close} custom delete } proc custom_injectstart {iFail} { custom ioerr $iFail 1 } proc custom_injectstop {} { custom ioerr } set ::FAULTSIM(custom) [list \ -injectinstall custom_injectinstall \ -injectstart custom_injectstart \ -injectstop custom_injectstop \ -injecterrlist {{1 {disk I/O error}}} \ -injectuninstall custom_injectuninstall \ ] do_test pagerfault-29-pre { faultsim_delete_and_reopen db func a_string a_string execsql { PRAGMA page_size = 1024; PRAGMA cache_size = 5; BEGIN; CREATE TABLE t2(a UNIQUE, b UNIQUE); INSERT INTO t2 VALUES( a_string(800), a_string(800) ); INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2; INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2; INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2; INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2; COMMIT; } expr {[file size test.db] >= 50*1024} } {1} faultsim_save_and_close foreach {tn tt} { 29 { catchsql ROLLBACK } 30 { db close ; sqlite3 db test.db } } { do_faultsim_test pagerfault-$tn -faults custom -prep { faultsim_restore_and_reopen db func a_string a_string execsql { PRAGMA cache_size = 5; BEGIN; UPDATE t2 SET a = a_string(799); } } -body { catchsql ROLLBACK catchsql ROLLBACK catchsql ROLLBACK } -test { eval $::tt if {"ok" != [db one {PRAGMA integrity_check}]} { error "integrity check failed" } } } do_test pagerfault-31-pre { sqlite3_shutdown sqlite3_config_uri 1 } {SQLITE_OK} do_faultsim_test pagerfault-31 -faults oom* -body { sqlite3 db {file:one?mode=memory&cache=shared} db eval { CREATE TABLE t1(x); INSERT INTO t1 VALUES(1); SELECT * FROM t1; } } -test { faultsim_test_result {0 1} {1 {}} catch { db close } } sqlite3_shutdown sqlite3_config_uri 0 do_test pagerfault-32-pre { reset_db execsql { CREATE TABLE t1(x); INSERT INTO t1 VALUES('one'); } } {} faultsim_save_and_close do_faultsim_test pagerfault-32 -prep { faultsim_restore_and_reopen db eval { SELECT * FROM t1; } } -body { execsql { SELECT * FROM t1; } } -test { faultsim_test_result {0 one} } sqlite3_shutdown sqlite3_config_uri 0 do_faultsim_test pagerfault-33a -prep { sqlite3 db :memory: execsql { CREATE TABLE t1(a, b); INSERT INTO t1 VALUES(1, 2); } } -body { execsql { VACUUM } } -test { faultsim_test_result {0 {}} } do_faultsim_test pagerfault-33b -prep { sqlite3 db "" execsql { CREATE TABLE t1(a, b); INSERT INTO t1 VALUES(1, 2); } } -body { execsql { VACUUM } } -test { faultsim_test_result {0 {}} } do_test pagerfault-34-pre { reset_db execsql { CREATE TABLE t1(x PRIMARY KEY); } } {} faultsim_save_and_close do_faultsim_test pagerfault-34 -prep { faultsim_restore_and_reopen execsql { BEGIN; INSERT INTO t1 VALUES( randomblob(4000) ); DELETE FROM t1; } } -body { execsql COMMIT } -test { faultsim_test_result {0 {}} } do_test pagerfault-35-pre { faultsim_delete_and_reopen execsql { CREATE TABLE t1(x PRIMARY KEY, y); INSERT INTO t1 VALUES(randomblob(200), randomblob(200)); INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1; INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1; INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1; } faultsim_save_and_close } {} testvfs tv -default 1 tv sectorsize 8192; tv devchar [list] do_faultsim_test pagerfault-35 -prep { faultsim_restore_and_reopen } -body { execsql { UPDATE t1 SET x=randomblob(200) } } -test { faultsim_test_result {0 {}} } catch {db close} tv delete sqlite3_shutdown sqlite3_config_uri 1 do_test pagerfault-36-pre { faultsim_delete_and_reopen execsql { CREATE TABLE t1(x PRIMARY KEY, y); INSERT INTO t1 VALUES(randomblob(200), randomblob(200)); INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1; INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1; INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1; } faultsim_save_and_close } {} do_faultsim_test pagerfault-36 -prep { faultsim_restore sqlite3 db file:test.db?cache=shared sqlite3 db2 file:test.db?cache=shared db2 eval { BEGIN; SELECT count(*) FROM sqlite_master; } db eval { PRAGMA cache_size = 1; BEGIN; UPDATE t1 SET x = randomblob(200); } } -body { execsql ROLLBACK db } -test { catch { db eval {UPDATE t1 SET x = randomblob(200)} } faultsim_test_result {0 {}} catch { db close } catch { db2 close } } sqlite3_shutdown sqlite3_config_uri 0 finish_test |
Changes to test/pageropt.test.
︙ | ︙ | |||
83 84 85 86 87 88 89 90 91 92 93 94 | SELECT hex(x) FROM t1 } } [list 0 0 0 $blobcontent] # But if the other thread modifies the database, then the cache # must refill. # do_test pageropt-1.5 { db2 eval {CREATE TABLE t2(y)} pagercount_sql { SELECT hex(x) FROM t1 } | > > > > > | | 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 | SELECT hex(x) FROM t1 } } [list 0 0 0 $blobcontent] # But if the other thread modifies the database, then the cache # must refill. # ifcapable mmap { set x [expr {[permutation]=="mmap" ? 1 : 6}] } else { set x 6 } do_test pageropt-1.5 { db2 eval {CREATE TABLE t2(y)} pagercount_sql { SELECT hex(x) FROM t1 } } [list $x 0 0 $blobcontent] do_test pageropt-1.6 { pagercount_sql { SELECT hex(x) FROM t1 } } [list 0 0 0 $blobcontent] # Verify that the last page of an overflow chain is not read from |
︙ | ︙ |
Changes to test/permutations.test.
︙ | ︙ | |||
133 134 135 136 137 138 139 140 141 142 143 144 145 146 | test_suite "veryquick" -prefix "" -description { "Very" quick test suite. Runs in less than 5 minutes on a workstation. This test suite is the same as the "quick" tests, except that some files that test malloc and IO errors are omitted. } -files [ test_set $allquicktests -exclude *malloc* *ioerr* *fault* ] test_suite "valgrind" -prefix "" -description { Run the "veryquick" test suite with a couple of multi-process tests (that fail under valgrind) omitted. } -files [ test_set $allquicktests -exclude *malloc* *ioerr* *fault* wal.test atof1.test ] -initialize { | > > > > > > > > | 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 | test_suite "veryquick" -prefix "" -description { "Very" quick test suite. Runs in less than 5 minutes on a workstation. This test suite is the same as the "quick" tests, except that some files that test malloc and IO errors are omitted. } -files [ test_set $allquicktests -exclude *malloc* *ioerr* *fault* ] test_suite "mmap" -prefix "mm-" -description { Similar to veryquick. Except with memory mapping disabled. } -presql { pragma mmap_size = 268435456; } -files [ test_set $allquicktests -exclude *malloc* *ioerr* *fault* -include malloc.test ] test_suite "valgrind" -prefix "" -description { Run the "veryquick" test suite with a couple of multi-process tests (that fail under valgrind) omitted. } -files [ test_set $allquicktests -exclude *malloc* *ioerr* *fault* wal.test atof1.test ] -initialize { |
︙ | ︙ | |||
174 175 176 177 178 179 180 181 182 183 184 185 186 187 | All FTS3 tests except fts3rnd.test. } -files { fts3aa.test fts3ab.test fts3ac.test fts3ad.test fts3ae.test fts3af.test fts3ag.test fts3ah.test fts3ai.test fts3aj.test fts3ak.test fts3al.test fts3am.test fts3an.test fts3ao.test fts3atoken.test fts3b.test fts3c.test fts3cov.test fts3d.test fts3defer.test fts3defer2.test fts3e.test fts3expr.test fts3expr2.test fts3near.test fts3query.test fts3shared.test fts3snippet.test fts3sort.test fts3fault.test fts3malloc.test fts3matchinfo.test fts3aux1.test fts3comp1.test fts3auto.test fts4aa.test fts4content.test fts3conf.test fts3prefix.test fts3fault2.test fts3corrupt.test fts3corrupt2.test fts3first.test fts4langid.test fts4merge.test | > | 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 | All FTS3 tests except fts3rnd.test. } -files { fts3aa.test fts3ab.test fts3ac.test fts3ad.test fts3ae.test fts3af.test fts3ag.test fts3ah.test fts3ai.test fts3aj.test fts3ak.test fts3al.test fts3am.test fts3an.test fts3ao.test fts3atoken.test fts3b.test fts3c.test fts3cov.test fts3d.test fts3defer.test fts3defer2.test fts3e.test fts3expr.test fts3expr2.test fts3expr3.test fts3near.test fts3query.test fts3shared.test fts3snippet.test fts3sort.test fts3fault.test fts3malloc.test fts3matchinfo.test fts3aux1.test fts3comp1.test fts3auto.test fts4aa.test fts4content.test fts3conf.test fts3prefix.test fts3fault2.test fts3corrupt.test fts3corrupt2.test fts3first.test fts4langid.test fts4merge.test |
︙ | ︙ |
Changes to test/pragma.test.
︙ | ︙ | |||
932 933 934 935 936 937 938 939 940 941 942 943 944 945 | } return "disk" } } return "unknown" } # Test temp_store and temp_store_directory pragmas # ifcapable pager_pragmas { do_test pragma-9.1 { db close sqlite3 db test.db | > > > > > > > > > > | 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 | } return "disk" } } return "unknown" } # Application_ID # do_test pragma-8.3.1 { execsql { PRAGMA application_id; } } {0} do_test pragma-8.3.2 { execsql {PRAGMA Application_ID(12345); PRAGMA application_id;} } {12345} # Test temp_store and temp_store_directory pragmas # ifcapable pager_pragmas { do_test pragma-9.1 { db close sqlite3 db test.db |
︙ | ︙ |
Changes to test/regexp1.test.
︙ | ︙ | |||
12 13 14 15 16 17 18 | # This file implements test for the REGEXP operator in test_regexp.c. # set testdir [file dirname $argv0] source $testdir/tester.tcl do_test regexp1-1.1 { | | | 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | # This file implements test for the REGEXP operator in test_regexp.c. # set testdir [file dirname $argv0] source $testdir/tester.tcl do_test regexp1-1.1 { load_static_extension db regexp db eval { CREATE TABLE t1(x INTEGER PRIMARY KEY, y TEXT); INSERT INTO t1 VALUES(1, 'For since by man came death,'); INSERT INTO t1 VALUES(2, 'by man came also the resurrection of the dead.'); INSERT INTO t1 VALUES(3, 'For as in Adam all die,'); INSERT INTO t1 VALUES(4, 'even so in Christ shall all be made alive.'); |
︙ | ︙ |
Added test/resolver01.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 | # 2013-04-13 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # # This file tests features of the name resolver (the component that # figures out what identifiers in the SQL statement refer to) that # were fixed by ticket [2500cdb9be] # set testdir [file dirname $argv0] source $testdir/tester.tcl do_test resolver01-1.1 { catchsql { CREATE TABLE t1(x, y); INSERT INTO t1 VALUES(11,22); CREATE TABLE t2(y, z); INSERT INTO t2 VALUES(33,44); SELECT 1 AS y FROM t1, t2 ORDER BY y; } } {0 1} do_test resolver01-1.2 { catchsql { SELECT 2 AS y FROM t1, t2 ORDER BY y COLLATE nocase; } } {0 2} do_test resolver01-1.3 { catchsql { SELECT 3 AS y FROM t1, t2 ORDER BY +y; } } {0 3} finish_test |
Changes to test/selectA.test.
︙ | ︙ | |||
277 278 279 280 281 282 283 | SELECT x,y,z FROM t2 UNION SELECT a,b,c FROM t1 ORDER BY b,a,c } } {{} C c {} U u 5200000.0 X x -23 Y y mad Z z 1 a a 9.9 b B hello d D abc e e hare m M} do_test selectA-2.35 { execsql { SELECT x,y,z FROM t2 UNION SELECT a,b,c FROM t1 | | | | 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 | SELECT x,y,z FROM t2 UNION SELECT a,b,c FROM t1 ORDER BY b,a,c } } {{} C c {} U u 5200000.0 X x -23 Y y mad Z z 1 a a 9.9 b B hello d D abc e e hare m M} do_test selectA-2.35 { execsql { SELECT x,y,z FROM t2 UNION SELECT a,b,c FROM t1 ORDER BY y COLLATE NOCASE,x,z } } {1 a a 9.9 b B {} C c hello d D abc e e hare m M {} U u 5200000.0 X x -23 Y y mad Z z} do_test selectA-2.36 { execsql { SELECT x,y,z FROM t2 UNION SELECT a,b,c FROM t1 ORDER BY y COLLATE NOCASE DESC,x,z } } {mad Z z -23 Y y 5200000.0 X x {} U u hare m M abc e e hello d D {} C c 9.9 b B 1 a a} do_test selectA-2.37 { execsql { SELECT x,y,z FROM t2 UNION SELECT a,b,c FROM t1 ORDER BY c,b,a } |
︙ | ︙ | |||
307 308 309 310 311 312 313 | SELECT x,y,z FROM t2 UNION SELECT a,b,c FROM t1 ORDER BY c DESC,a,b } } {mad Z z -23 Y y 5200000.0 X x {} U u hare m M abc e e hello d D {} C c 9.9 b B 1 a a} do_test selectA-2.40 { execsql { SELECT x,y,z FROM t2 UNION SELECT a,b,c FROM t1 | | | 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 | SELECT x,y,z FROM t2 UNION SELECT a,b,c FROM t1 ORDER BY c DESC,a,b } } {mad Z z -23 Y y 5200000.0 X x {} U u hare m M abc e e hello d D {} C c 9.9 b B 1 a a} do_test selectA-2.40 { execsql { SELECT x,y,z FROM t2 UNION SELECT a,b,c FROM t1 ORDER BY z COLLATE BINARY DESC,x,y } } {mad Z z -23 Y y 5200000.0 X x {} U u abc e e {} C c 1 a a hare m M hello d D 9.9 b B} do_test selectA-2.41 { execsql { SELECT a,b,c FROM t1 EXCEPT SELECT a,b,c FROM t1 WHERE b>='d' ORDER BY a,b,c } |
︙ | ︙ | |||
598 599 600 601 602 603 604 | SELECT x,y,z FROM t2 UNION SELECT a,b,c FROM t3 ORDER BY b,a,c } } {{} C c {} U u 5200000.0 X x -23 Y y mad Z z 1 a a 9.9 b B hello d D abc e e hare m M} do_test selectA-2.86 { execsql { SELECT x,y,z FROM t2 UNION SELECT a,b,c FROM t3 | | | 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 | SELECT x,y,z FROM t2 UNION SELECT a,b,c FROM t3 ORDER BY b,a,c } } {{} C c {} U u 5200000.0 X x -23 Y y mad Z z 1 a a 9.9 b B hello d D abc e e hare m M} do_test selectA-2.86 { execsql { SELECT x,y,z FROM t2 UNION SELECT a,b,c FROM t3 ORDER BY y COLLATE NOCASE,x,z } } {1 a a 9.9 b B {} C c hello d D abc e e hare m M {} U u 5200000.0 X x -23 Y y mad Z z} do_test selectA-2.87 { execsql { SELECT x,y,z FROM t2 UNION SELECT a,b,c FROM t3 ORDER BY y COLLATE NOCASE DESC,x,z } |
︙ | ︙ | |||
628 629 630 631 632 633 634 | SELECT x,y,z FROM t2 UNION SELECT a,b,c FROM t3 ORDER BY c DESC,a,b } } {mad Z z -23 Y y 5200000.0 X x {} U u hare m M abc e e hello d D {} C c 9.9 b B 1 a a} do_test selectA-2.91 { execsql { SELECT x,y,z FROM t2 UNION SELECT a,b,c FROM t3 | | | 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 | SELECT x,y,z FROM t2 UNION SELECT a,b,c FROM t3 ORDER BY c DESC,a,b } } {mad Z z -23 Y y 5200000.0 X x {} U u hare m M abc e e hello d D {} C c 9.9 b B 1 a a} do_test selectA-2.91 { execsql { SELECT x,y,z FROM t2 UNION SELECT a,b,c FROM t3 ORDER BY z COLLATE BINARY DESC,x,y } } {mad Z z -23 Y y 5200000.0 X x {} U u abc e e {} C c 1 a a hare m M hello d D 9.9 b B} do_test selectA-2.92 { execsql { SELECT x,y,z FROM t2 INTERSECT SELECT a,b,c FROM t3 EXCEPT SELECT c,b,a FROM t1 |
︙ | ︙ | |||
889 890 891 892 893 894 895 | SELECT x,y,z FROM t2 UNION SELECT a,b,c FROM t1 ORDER BY b,a,c } } {{} C c {} U u 5200000.0 X x -23 Y y mad Z z 1 a a 9.9 b B hello d D abc e e hare m M} do_test selectA-3.35 { execsql { SELECT x,y,z FROM t2 UNION SELECT a,b,c FROM t1 | | | | 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 | SELECT x,y,z FROM t2 UNION SELECT a,b,c FROM t1 ORDER BY b,a,c } } {{} C c {} U u 5200000.0 X x -23 Y y mad Z z 1 a a 9.9 b B hello d D abc e e hare m M} do_test selectA-3.35 { execsql { SELECT x,y,z FROM t2 UNION SELECT a,b,c FROM t1 ORDER BY y COLLATE NOCASE,x,z } } {1 a a 9.9 b B {} C c hello d D abc e e hare m M {} U u 5200000.0 X x -23 Y y mad Z z} do_test selectA-3.36 { execsql { SELECT x,y,z FROM t2 UNION SELECT a,b,c FROM t1 ORDER BY y COLLATE NOCASE DESC,x,z } } {mad Z z -23 Y y 5200000.0 X x {} U u hare m M abc e e hello d D {} C c 9.9 b B 1 a a} do_test selectA-3.37 { execsql { SELECT x,y,z FROM t2 UNION SELECT a,b,c FROM t1 ORDER BY c,b,a } |
︙ | ︙ | |||
919 920 921 922 923 924 925 | SELECT x,y,z FROM t2 UNION SELECT a,b,c FROM t1 ORDER BY c DESC,a,b } } {mad Z z -23 Y y 5200000.0 X x {} U u hare m M abc e e hello d D {} C c 9.9 b B 1 a a} do_test selectA-3.40 { execsql { SELECT x,y,z FROM t2 UNION SELECT a,b,c FROM t1 | | | 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 | SELECT x,y,z FROM t2 UNION SELECT a,b,c FROM t1 ORDER BY c DESC,a,b } } {mad Z z -23 Y y 5200000.0 X x {} U u hare m M abc e e hello d D {} C c 9.9 b B 1 a a} do_test selectA-3.40 { execsql { SELECT x,y,z FROM t2 UNION SELECT a,b,c FROM t1 ORDER BY z COLLATE BINARY DESC,x,y } } {mad Z z -23 Y y 5200000.0 X x {} U u abc e e {} C c 1 a a hare m M hello d D 9.9 b B} do_test selectA-3.41 { execsql { SELECT a,b,c FROM t1 EXCEPT SELECT a,b,c FROM t1 WHERE b>='d' ORDER BY a,b,c } |
︙ | ︙ | |||
1210 1211 1212 1213 1214 1215 1216 | SELECT x,y,z FROM t2 UNION SELECT a,b,c FROM t3 ORDER BY b,a,c } } {{} C c {} U u 5200000.0 X x -23 Y y mad Z z 1 a a 9.9 b B hello d D abc e e hare m M} do_test selectA-3.86 { execsql { SELECT x,y,z FROM t2 UNION SELECT a,b,c FROM t3 | | | 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 | SELECT x,y,z FROM t2 UNION SELECT a,b,c FROM t3 ORDER BY b,a,c } } {{} C c {} U u 5200000.0 X x -23 Y y mad Z z 1 a a 9.9 b B hello d D abc e e hare m M} do_test selectA-3.86 { execsql { SELECT x,y,z FROM t2 UNION SELECT a,b,c FROM t3 ORDER BY y COLLATE NOCASE,x,z } } {1 a a 9.9 b B {} C c hello d D abc e e hare m M {} U u 5200000.0 X x -23 Y y mad Z z} do_test selectA-3.87 { execsql { SELECT x,y,z FROM t2 UNION SELECT a,b,c FROM t3 ORDER BY y COLLATE NOCASE DESC,x,z } |
︙ | ︙ | |||
1240 1241 1242 1243 1244 1245 1246 | SELECT x,y,z FROM t2 UNION SELECT a,b,c FROM t3 ORDER BY c DESC,a,b } } {mad Z z -23 Y y 5200000.0 X x {} U u hare m M abc e e hello d D {} C c 9.9 b B 1 a a} do_test selectA-3.91 { execsql { SELECT x,y,z FROM t2 UNION SELECT a,b,c FROM t3 | | | 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 | SELECT x,y,z FROM t2 UNION SELECT a,b,c FROM t3 ORDER BY c DESC,a,b } } {mad Z z -23 Y y 5200000.0 X x {} U u hare m M abc e e hello d D {} C c 9.9 b B 1 a a} do_test selectA-3.91 { execsql { SELECT x,y,z FROM t2 UNION SELECT a,b,c FROM t3 ORDER BY z COLLATE BINARY DESC,x,y } } {mad Z z -23 Y y 5200000.0 X x {} U u abc e e {} C c 1 a a hare m M hello d D 9.9 b B} do_test selectA-3.92 { execsql { SELECT x,y,z FROM t2 INTERSECT SELECT a,b,c FROM t3 EXCEPT SELECT c,b,a FROM t1 |
︙ | ︙ |
Changes to test/selectD.test.
︙ | ︙ | |||
147 148 149 150 151 152 153 154 155 | db eval { SELECT t1.*, t2.*, t3.*, t4.b FROM (t1 LEFT JOIN t2 USING(a)) JOIN (t3 LEFT JOIN t4 USING(a)) ON t1.a=t3.a-111; } } {111 x1 111 x2 222 x3 {}} } finish_test | > > > > > > > > > > > > > > > > > > > | 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 | db eval { SELECT t1.*, t2.*, t3.*, t4.b FROM (t1 LEFT JOIN t2 USING(a)) JOIN (t3 LEFT JOIN t4 USING(a)) ON t1.a=t3.a-111; } } {111 x1 111 x2 222 x3 {}} } # The following test was added on 2013-04-24 in order to verify that # the datatypes and affinities of sub-sub-queries are set prior to computing # the datatypes and affinities of the parent sub-queries because the # latter computation depends on the former. # do_execsql_test selectD-4.1 { CREATE TABLE t41(a INTEGER PRIMARY KEY, b INTEGER); CREATE TABLE t42(d INTEGER PRIMARY KEY, e INTEGER); CREATE TABLE t43(f INTEGER PRIMARY KEY, g INTEGER); EXPLAIN QUERY PLAN SELECT * FROM t41 LEFT JOIN (SELECT count(*) AS cnt, x1.d FROM (t42 INNER JOIN t43 ON d=g) AS x1 WHERE x1.d>5 GROUP BY x1.d) AS x2 ON t41.b=x2.d; } {/.*SEARCH SUBQUERY 1 AS x2 USING AUTOMATIC.*/} finish_test |
Added test/selectE.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 | # 2013-05-07 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for compound SELECT statements # that have ORDER BY clauses with collating sequences that differ # from the collating sequence used for comparison in the compound. # # Ticket 6709574d2a8d8b9be3a9cb1afbf4ff2de48ea4e7: # drh added on 2013-05-06 15:21:16: # # In the code shown below (which is intended to be run from the # sqlite3.exe command-line tool) the three SELECT statements should all # generate the same answer. But the third one does not. It is as if the # COLLATE clause on the ORDER BY somehow got pulled into the EXCEPT # operator. Note that the ".print" commands are instructions to the # sqlite3.exe shell program to output delimiter lines so that you can more # easily tell where the output of one query ends and the next query # begins. # # CREATE TABLE t1(a); # INSERT INTO t1 VALUES('abc'),('def'); # CREATE TABLE t2(a); # INSERT INTO t2 VALUES('DEF'); # # SELECT a FROM t1 EXCEPT SELECT a FROM t2 ORDER BY a; # .print ----- # SELECT a FROM (SELECT a FROM t1 EXCEPT SELECT a FROM t2) # ORDER BY a COLLATE nocase; # .print ----- # SELECT a FROM t1 EXCEPT SELECT a FROM t2 ORDER BY a COLLATE nocase; # # Bisecting shows that this problem was introduced in SQLite version 3.6.0 # by check-in [8bbfa97837a74ef] on 2008-06-15. # set testdir [file dirname $argv0] source $testdir/tester.tcl do_test selectE-1.0 { db eval { CREATE TABLE t1(a); INSERT INTO t1 VALUES('abc'),('def'),('ghi'); CREATE TABLE t2(a); INSERT INTO t2 VALUES('DEF'),('abc'); CREATE TABLE t3(a); INSERT INTO t3 VALUES('def'),('jkl'); SELECT a FROM t1 EXCEPT SELECT a FROM t2 ORDER BY a COLLATE nocase; } } {def ghi} do_test selectE-1.1 { db eval { SELECT a FROM t2 EXCEPT SELECT a FROM t3 ORDER BY a COLLATE nocase; } } {abc DEF} do_test selectE-1.2 { db eval { SELECT a FROM t2 EXCEPT SELECT a FROM t3 ORDER BY a COLLATE binary; } } {DEF abc} do_test selectE-1.3 { db eval { SELECT a FROM t2 EXCEPT SELECT a FROM t3 ORDER BY a; } } {DEF abc} do_test selectE-2.1 { db eval { DELETE FROM t2; DELETE FROM t3; INSERT INTO t2 VALUES('ABC'),('def'),('GHI'),('jkl'); INSERT INTO t3 SELECT lower(a) FROM t2; SELECT a COLLATE nocase FROM t2 EXCEPT SELECT a FROM t3 ORDER BY 1 } } {} do_test selectE-2.2 { db eval { SELECT a COLLATE nocase FROM t2 EXCEPT SELECT a FROM t3 ORDER BY 1 COLLATE binary } } {} finish_test |
Changes to test/speed1p.test.
︙ | ︙ | |||
20 21 22 23 24 25 26 27 28 29 30 31 32 33 | #sqlite3_config_scratch 29000 1 set old_lookaside [sqlite3_config_lookaside 2048 300] #sqlite3_config_pagecache 1024 11000 set testdir [file dirname $argv0] source $testdir/tester.tcl speed_trial_init speed1 # Set a uniform random seed expr srand(0) # The number_name procedure below converts its argment (an integer) # into a string which is the English-language name for that number. # # Example: | > > | 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | #sqlite3_config_scratch 29000 1 set old_lookaside [sqlite3_config_lookaside 2048 300] #sqlite3_config_pagecache 1024 11000 set testdir [file dirname $argv0] source $testdir/tester.tcl speed_trial_init speed1 sqlite3_memdebug_vfs_oom_test 0 # Set a uniform random seed expr srand(0) # The number_name procedure below converts its argment (an integer) # into a string which is the English-language name for that number. # # Example: |
︙ | ︙ | |||
73 74 75 76 77 78 79 | CREATE INDEX i2a ON t2(a); CREATE INDEX i2b ON t2(b); } execsql { SELECT name FROM sqlite_master ORDER BY 1; } } {i2a i2b t1 t2} | < | 75 76 77 78 79 80 81 82 83 84 85 86 87 88 | CREATE INDEX i2a ON t2(a); CREATE INDEX i2b ON t2(b); } execsql { SELECT name FROM sqlite_master ORDER BY 1; } } {i2a i2b t1 t2} # 50000 INSERTs on an unindexed table # set list {} for {set i 1} {$i<=50000} {incr i} { set r [expr {int(rand()*500000)}] set x [number_name $r] |
︙ | ︙ |
Changes to test/spellfix.test.
︙ | ︙ | |||
12 13 14 15 16 17 18 | set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix spellfix ifcapable !vtab { finish_test ; return } | | | 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix spellfix ifcapable !vtab { finish_test ; return } load_static_extension db spellfix nextchar set vocab { rabbi rabbit rabbits rabble rabid rabies raccoon raccoons race raced racer racers races racetrack racial racially racing rack racked racket racketeer racketeering racketeers rackets racking racks radar radars radial radially radian radiance radiant radiantly radiate radiated radiates radiating radiation radiations radiator radiators radical radically radicals radices radii radio |
︙ | ︙ | |||
80 81 82 83 84 85 86 87 88 89 90 91 92 93 | } { do_execsql_test 1.2.$tn { SELECT word, matchlen FROM t1 WHERE word MATCH $word ORDER BY score, word LIMIT 5 } $res } do_execsql_test 2.1 { CREATE VIRTUAL TABLE t2 USING spellfix1; INSERT INTO t2 (word, soundslike) VALUES('school', 'skuul'); INSERT INTO t2 (word, soundslike) VALUES('psalm', 'sarm'); SELECT word, matchlen FROM t2 WHERE word MATCH 'sar*' LIMIT 5; } {psalm 4} | > > > > > > > > > > > > > > > > > > > > | 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 | } { do_execsql_test 1.2.$tn { SELECT word, matchlen FROM t1 WHERE word MATCH $word ORDER BY score, word LIMIT 5 } $res } # Tests of the next_char function. # do_test 1.10 { db eval { CREATE TABLE vocab(w TEXT PRIMARY KEY); INSERT INTO vocab SELECT word FROM t1; } } {} do_execsql_test 1.11 { SELECT next_char('re','vocab','w'); } {a} do_execsql_test 1.12 { SELECT next_char('r','vocab','w'); } {ae} do_execsql_test 1.13 { SELECT next_char('','vocab','w'); } {r} do_test 1.14 { catchsql {SELECT next_char('','xyzzy','a')} } {1 {no such table: xyzzy}} do_execsql_test 2.1 { CREATE VIRTUAL TABLE t2 USING spellfix1; INSERT INTO t2 (word, soundslike) VALUES('school', 'skuul'); INSERT INTO t2 (word, soundslike) VALUES('psalm', 'sarm'); SELECT word, matchlen FROM t2 WHERE word MATCH 'sar*' LIMIT 5; } {psalm 4} |
︙ | ︙ |
Changes to test/subquery.test.
︙ | ︙ | |||
417 418 419 420 421 422 423 | #------------------------------------------------------------------ # These tests - subquery-4.* - use the TCL statement cache to try # and expose bugs to do with re-using statements that have been # passed to sqlite3_reset(). # | | | 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 | #------------------------------------------------------------------ # These tests - subquery-4.* - use the TCL statement cache to try # and expose bugs to do with re-using statements that have been # passed to sqlite3_reset(). # # One problem was that VDBE memory cells were not being initialized # to NULL on the second and subsequent executions. # do_test subquery-4.1.1 { execsql { SELECT (SELECT a FROM t1); } } {1} |
︙ | ︙ |
Changes to test/syscall.test.
︙ | ︙ | |||
56 57 58 59 60 61 62 | #------------------------------------------------------------------------- # Tests for the xNextSystemCall method. # foreach s { open close access getcwd stat fstat ftruncate fcntl read pread write pwrite fchmod fallocate pread64 pwrite64 unlink openDirectory mkdir rmdir | | | 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | #------------------------------------------------------------------------- # Tests for the xNextSystemCall method. # foreach s { open close access getcwd stat fstat ftruncate fcntl read pread write pwrite fchmod fallocate pread64 pwrite64 unlink openDirectory mkdir rmdir statvfs fchown umask mmap munmap mremap } { if {[test_syscall exists $s]} {lappend syscall_list $s} } do_test 3.1 { lsort [test_syscall list] } [lsort $syscall_list] #------------------------------------------------------------------------- # This test verifies that if a call to open() fails and errno is set to |
︙ | ︙ |
Changes to test/sysfault.test.
︙ | ︙ | |||
239 240 241 242 243 244 245 | SELECT length(a) + length(b) FROM t1; COMMIT; } } -test { faultsim_test_result {0 20000} } | > > > > > > > > > > > > > > > > > > > > > > > > > > > | > | > > | 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 | SELECT length(a) + length(b) FROM t1; COMMIT; } } -test { faultsim_test_result {0 20000} } #------------------------------------------------------------------------- # Test errors in mmap(). # proc vfsfault_install {} { test_syscall reset test_syscall install {mmap} } faultsim_delete_and_reopen execsql { CREATE TABLE t1(a, b); INSERT INTO t1 VALUES(1, 2); } faultsim_save_and_close do_faultsim_test 4 -faults vfsfault-* -prep { faultsim_restore_and_reopen file_control_chunksize_test db main 8192 execsql { PRAGMA mmap_size = 1000000; } } -body { test_syscall errno mmap EACCES execsql { SELECT * FROM t1; } } -test { faultsim_test_result {0 {1 2}} {1 {disk I/O error}} } finish_test |
Changes to test/temptable.test.
︙ | ︙ | |||
146 147 148 149 150 151 152 | } catchsql {DROP INDEX i2} } {1 {no such index: i2}} # Check for correct name collision processing. A name collision can # occur when process A creates a temporary table T then process B # creates a permanent table also named T. The temp table in process A | | | 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 | } catchsql {DROP INDEX i2} } {1 {no such index: i2}} # Check for correct name collision processing. A name collision can # occur when process A creates a temporary table T then process B # creates a permanent table also named T. The temp table in process A # hides the existence of the permanent table. # do_test temptable-4.1 { execsql { CREATE TEMP TABLE t2(x,y); INSERT INTO t2 VALUES(10,20); SELECT * FROM t2; } db2 |
︙ | ︙ |
Changes to test/tester.tcl.
︙ | ︙ | |||
119 120 121 122 123 124 125 | if {[info exists ::G(perm:dbconfig)]} { set ::dbhandle [lindex $args 0] uplevel #0 $::G(perm:dbconfig) } set res } else { # This command is not opening a new database connection. Pass the | | | 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 | if {[info exists ::G(perm:dbconfig)]} { set ::dbhandle [lindex $args 0] uplevel #0 $::G(perm:dbconfig) } set res } else { # This command is not opening a new database connection. Pass the # arguments through to the C implementation as the are. # uplevel 1 sqlite_orig $args } } } proc getFileRetries {} { |
︙ | ︙ | |||
458 459 460 461 462 463 464 465 466 467 468 469 470 471 | # counters in the parent interpreter. # if {0==[info exists ::SLAVE]} { set TC(errors) 0 set TC(count) 0 set TC(fail_list) [list] set TC(omit_list) [list] proc set_test_counter {counter args} { if {[llength $args]} { set ::TC($counter) [lindex $args 0] } set ::TC($counter) } | > | 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 | # counters in the parent interpreter. # if {0==[info exists ::SLAVE]} { set TC(errors) 0 set TC(count) 0 set TC(fail_list) [list] set TC(omit_list) [list] set TC(warn_list) [list] proc set_test_counter {counter args} { if {[llength $args]} { set ::TC($counter) [lindex $args 0] } set ::TC($counter) } |
︙ | ︙ | |||
491 492 493 494 495 496 497 498 499 500 501 502 503 504 | set nFail [set_test_counter errors] if {$nFail>=$::cmdlinearg(maxerror)} { puts "*** Giving up..." finalize_testing } } # Increment the number of tests run # proc incr_ntest {} { set_test_counter count [expr [set_test_counter count] + 1] } | > > > > > > > > > > > > | 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 | set nFail [set_test_counter errors] if {$nFail>=$::cmdlinearg(maxerror)} { puts "*** Giving up..." finalize_testing } } # Remember a warning message to be displayed at the conclusion of all testing # proc warning {msg {append 1}} { puts "Warning: $msg" set warnList [set_test_counter warn_list] if {$append} { lappend warnList $msg } set_test_counter warn_list $warnList } # Increment the number of tests run # proc incr_ntest {} { set_test_counter count [expr [set_test_counter count] + 1] } |
︙ | ︙ | |||
780 781 782 783 784 785 786 787 788 789 790 791 792 793 | set nTest [incr_ntest] set nErr [set_test_counter errors] puts "$nErr errors out of $nTest tests" if {$nErr>0} { puts "Failures on these tests: [set_test_counter fail_list]" } run_thread_tests 1 if {[llength $omitList]>0} { puts "Omitted test cases:" set prec {} foreach {rec} [lsort $omitList] { if {$rec==$prec} continue set prec $rec | > > > | 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 | set nTest [incr_ntest] set nErr [set_test_counter errors] puts "$nErr errors out of $nTest tests" if {$nErr>0} { puts "Failures on these tests: [set_test_counter fail_list]" } foreach warning [set_test_counter warn_list] { puts "Warning: $warning" } run_thread_tests 1 if {[llength $omitList]>0} { puts "Omitted test cases:" set prec {} foreach {rec} [lsort $omitList] { if {$rec==$prec} continue set prec $rec |
︙ | ︙ | |||
1033 1034 1035 1036 1037 1038 1039 | # written into the files on disk. Argument $crashdelay indicates the # number of file syncs to wait before crashing. # # The return value is a list of two elements. The first element is a # boolean, indicating whether or not the process actually crashed or # reported some other error. The second element in the returned list is the # error message. This is "child process exited abnormally" if the crash | | | 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 | # written into the files on disk. Argument $crashdelay indicates the # number of file syncs to wait before crashing. # # The return value is a list of two elements. The first element is a # boolean, indicating whether or not the process actually crashed or # reported some other error. The second element in the returned list is the # error message. This is "child process exited abnormally" if the crash # occurred. # # crashsql -delay CRASHDELAY -file CRASHFILE ?-blocksize BLOCKSIZE? $sql # proc crashsql {args} { set blocksize "" set crashdelay 1 |
︙ | ︙ | |||
1313 1314 1315 1316 1317 1318 1319 | array set stats [btree_pager_stats $bt] db_leave db set stats(state) } 0 } } | | | 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 | array set stats [btree_pager_stats $bt] db_leave db set stats(state) } 0 } } # If an IO error occurred, then the checksum of the database should # be the same as before the script that caused the IO error was run. # if {$::go && $::sqlite_io_error_hardhit && $::ioerropts(-cksum)} { do_test $testname.$n.6 { catch {db close} catch {db2 close} set ::DB [sqlite3 db test.db; sqlite3_connection_pointer db] |
︙ | ︙ |
Changes to test/tkt-2d1a5c67d.test.
︙ | ︙ | |||
42 43 44 45 46 47 48 | } } {wal A 3 4 B 1 2 C 1 2} } db close forcedelete test.db test.db-wal sqlite3 db test.db | | | 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | } } {wal A 3 4 B 1 2 C 1 2} } db close forcedelete test.db test.db-wal sqlite3 db test.db load_static_extension db wholenumber db eval { PRAGMA journal_mode=WAL; CREATE TABLE t1(a,b); CREATE INDEX t1b ON t1(b); CREATE TABLE t2(x,y); CREATE VIRTUAL TABLE nums USING wholenumber; INSERT INTO t2 SELECT value, randomblob(1000) FROM nums |
︙ | ︙ |
Added test/tkt-6bfb98dfc0.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 | # 2013 March 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. # #*********************************************************************** # This file implements regression tests for SQLite library. Specifically, # it tests that ticket [6bfb98dfc0] # # The final INSERT in the script below reports that the database is # corrupt (SQLITE_CORRUPT) and aborts even though the database is not # corrupt. # # PRAGMA page_size=512; # CREATE TABLE t1(x INTEGER PRIMARY KEY, y); # INSERT INTO t1 VALUES(1,randomblob(400)); # INSERT INTO t1 VALUES(2,randomblob(400)); # INSERT INTO t1 SELECT x+2, randomblob(400) FROM t1; # INSERT INTO t1 SELECT x+4, randomblob(400) FROM t1; # INSERT INTO t1 SELECT x+8, randomblob(400) FROM t1; # INSERT INTO t1 SELECT x+16, randomblob(400) FROM t1; # INSERT INTO t1 SELECT x+32, randomblob(400) FROM t1; # INSERT INTO t1 SELECT x+64, randomblob(400) FROM t1 WHERE x<10; # CREATE TRIGGER r1 AFTER INSERT ON t1 WHEN new.x=74 BEGIN # DELETE FROM t1; # INSERT INTO t1 VALUES(75, randomblob(400)); # INSERT INTO t1 VALUES(76, randomblob(400)); # END; # INSERT INTO t1 VALUES(74, randomblob(400)); # set testdir [file dirname $argv0] source $testdir/tester.tcl do_test tkt-6bfb98dfc0.100 { db eval { PRAGMA page_size=512; CREATE TABLE t1(x INTEGER PRIMARY KEY, y); INSERT INTO t1 VALUES(1,randomblob(400)); INSERT INTO t1 VALUES(2,randomblob(400)); INSERT INTO t1 SELECT x+2, randomblob(400) FROM t1; INSERT INTO t1 SELECT x+4, randomblob(400) FROM t1; INSERT INTO t1 SELECT x+8, randomblob(400) FROM t1; INSERT INTO t1 SELECT x+16, randomblob(400) FROM t1; INSERT INTO t1 SELECT x+32, randomblob(400) FROM t1; INSERT INTO t1 SELECT x+64, randomblob(400) FROM t1 WHERE x<10; CREATE TRIGGER r1 AFTER INSERT ON t1 WHEN new.x=74 BEGIN DELETE FROM t1; INSERT INTO t1 VALUES(75, randomblob(400)); INSERT INTO t1 VALUES(76, randomblob(400)); END; INSERT INTO t1 VALUES(74, randomblob(400)); SELECT x, length(y) FROM t1 ORDER BY x; } } {75 400 76 400} finish_test |
Changes to test/tkt2409.test.
︙ | ︙ | |||
103 104 105 106 107 108 109 | } {SQLITE_OK} # Check the integrity of the cache. # integrity_check tkt2409-1.3 # Check that the transaction was rolled back. Because the INSERT | | | 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 | } {SQLITE_OK} # Check the integrity of the cache. # integrity_check tkt2409-1.3 # Check that the transaction was rolled back. Because the INSERT # statement in which the "I/O error" occurred did not open a statement # transaction, SQLite had no choice but to roll back the transaction. # do_test tkt2409-1.4 { unread_lock_db catchsql { ROLLBACK } } {0 {}} |
︙ | ︙ | |||
171 172 173 174 175 176 177 | } {SQLITE_OK} # Check the integrity of the cache. # integrity_check tkt2409-3.3 # Check that the transaction was rolled back. Because the INSERT | | | 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 | } {SQLITE_OK} # Check the integrity of the cache. # integrity_check tkt2409-3.3 # Check that the transaction was rolled back. Because the INSERT # statement in which the "I/O error" occurred did not open a statement # transaction, SQLite had no choice but to roll back the transaction. # do_test tkt2409-3.4 { unread_lock_db catchsql { ROLLBACK } } {0 {}} integrity_check tkt2409-3.5 |
︙ | ︙ |
Changes to test/tkt2822.test.
︙ | ︙ | |||
205 206 207 208 209 210 211 212 213 214 215 | SELECT a AS "b" FROM t3 ORDER BY [B]; } } {1 9} # In "ORDER BY +b" the term is now an expression rather than # a label. It therefore matches by rule (3) instead of rule (2). # do_test tkt2822-5.5 { execsql { SELECT a AS b FROM t3 ORDER BY +b; } | > > > | | 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 | SELECT a AS "b" FROM t3 ORDER BY [B]; } } {1 9} # In "ORDER BY +b" the term is now an expression rather than # a label. It therefore matches by rule (3) instead of rule (2). # # 2013-04-13: This is busted. Changed to conform to PostgreSQL and # MySQL and Oracle behavior. # do_test tkt2822-5.5 { execsql { SELECT a AS b FROM t3 ORDER BY +b; } } {1 9} # Tests for rule 2 in compound queries # do_test tkt2822-6.1 { execsql { CREATE TABLE t6a(p,q); INSERT INTO t6a VALUES(1,8); |
︙ | ︙ |
Changes to test/wal.test.
︙ | ︙ | |||
723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 | list [expr [file size test.db]/1024] [file size test.db-wal] } [list 37 [wal_file_size 41 1024]] do_test wal-11.9 { db close list [expr [file size test.db]/1024] [log_deleted test.db-wal] } {37 1} sqlite3_wal db test.db do_test wal-11.10 { execsql { PRAGMA cache_size = 10; BEGIN; INSERT INTO t1 SELECT blob(900) FROM t1; -- 32 SELECT count(*) FROM t1; } list [expr [file size test.db]/1024] [file size test.db-wal] | > > > | | | | 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 | list [expr [file size test.db]/1024] [file size test.db-wal] } [list 37 [wal_file_size 41 1024]] do_test wal-11.9 { db close list [expr [file size test.db]/1024] [log_deleted test.db-wal] } {37 1} sqlite3_wal db test.db set nWal 39 if {[permutation]!="mmap"} {set nWal 37} ifcapable !mmap {set nWal 37} do_test wal-11.10 { execsql { PRAGMA cache_size = 10; BEGIN; INSERT INTO t1 SELECT blob(900) FROM t1; -- 32 SELECT count(*) FROM t1; } list [expr [file size test.db]/1024] [file size test.db-wal] } [list 37 [wal_file_size $nWal 1024]] do_test wal-11.11 { execsql { SELECT count(*) FROM t1; ROLLBACK; SELECT count(*) FROM t1; } } {32 16} do_test wal-11.12 { list [expr [file size test.db]/1024] [file size test.db-wal] } [list 37 [wal_file_size $nWal 1024]] do_test wal-11.13 { execsql { INSERT INTO t1 VALUES( blob(900) ); SELECT count(*) FROM t1; PRAGMA integrity_check; } } {17 ok} do_test wal-11.14 { list [expr [file size test.db]/1024] [file size test.db-wal] } [list 37 [wal_file_size $nWal 1024]] #------------------------------------------------------------------------- # This block of tests, wal-12.*, tests the fix for a problem that # could occur if a log that is a prefix of an older log is written # into a reused log file. # |
︙ | ︙ | |||
1508 1509 1510 1511 1512 1513 1514 | set ::log [list] faultsim_restore_and_reopen execsql { SELECT * FROM t1 } } {1 2 3 4} set nPage [expr 2+$AUTOVACUUM] do_test wal-23.4 { set ::log | > | | 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 | set ::log [list] faultsim_restore_and_reopen execsql { SELECT * FROM t1 } } {1 2 3 4} set nPage [expr 2+$AUTOVACUUM] do_test wal-23.4 { set ::log } [list SQLITE_NOTICE_RECOVER_WAL \ "recovered $nPage frames from WAL file $walfile"] ifcapable autovacuum { # This block tests that if the size of a database is reduced by a # transaction (because of an incremental or auto-vacuum), that no # data is written to the WAL file for the truncated pages as part # of the commit. e.g. if a transaction reduces the size of a database |
︙ | ︙ |
Changes to test/wal5.test.
︙ | ︙ | |||
231 232 233 234 235 236 237 | } {} do_test 2.3.$tn.2 { file_page_counts } {1 3 1 3} do_test 2.3.$tn.3 { sql2 { BEGIN; SELECT * FROM t1 } } {1 2} do_test 2.3.$tn.4 { sql1 { INSERT INTO t1 VALUES(3, 4) } } {} do_test 2.3.$tn.5 { sql1 { INSERT INTO t2 VALUES(3, 4) } } {} do_test 2.3.$tn.6 { file_page_counts } {1 4 1 4} do_test 2.3.$tn.7 { code1 { do_wal_checkpoint db -mode full } } {1 4 3} | > > > > > > > > > | | 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 | } {} do_test 2.3.$tn.2 { file_page_counts } {1 3 1 3} do_test 2.3.$tn.3 { sql2 { BEGIN; SELECT * FROM t1 } } {1 2} do_test 2.3.$tn.4 { sql1 { INSERT INTO t1 VALUES(3, 4) } } {} do_test 2.3.$tn.5 { sql1 { INSERT INTO t2 VALUES(3, 4) } } {} do_test 2.3.$tn.6 { file_page_counts } {1 4 1 4} do_test 2.3.$tn.7 { code1 { do_wal_checkpoint db -mode full } } {1 4 3} # The checkpoint above only writes page 1 of the db file. The other # page (page 2) is locked by the read-transaction opened by the # [sql2] commmand above. So normally, the db is 1 page in size here. # However, in mmap() mode, the db is pre-allocated to 2 pages at the # start of the checkpoint, even though page 2 cannot be written. set nDb 2 if {[permutation]!="mmap"} {set nDb 1} ifcapable !mmap {set nDb 1} do_test 2.3.$tn.8 { file_page_counts } [list $nDb 4 2 4] } # Check that checkpoints block on the correct locks. And respond correctly # if they cannot obtain those locks. There are three locks that a checkpoint # may block on (in the following order): # # 1. The writer lock: FULL and RESTART checkpoints block until any writer |
︙ | ︙ | |||
339 340 341 342 343 344 345 | do_test 3.$tn.6 { code3 { do_wal_checkpoint db3 } } {0 0 0} } } finish_test | < | 348 349 350 351 352 353 354 | do_test 3.$tn.6 { code3 { do_wal_checkpoint db3 } } {0 0 0} } } finish_test |
Changes to test/walfault.test.
︙ | ︙ | |||
544 545 546 547 548 549 550 | } } -test { faultsim_test_result {0 {0 9 9}} faultsim_integrity_check set nRow [db eval {SELECT count(*) FROM abc}] if {!(($nRow==2 && $testrc) || $nRow==3)} { error "Bad db content" } } | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > | 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 | } } -test { faultsim_test_result {0 {0 9 9}} faultsim_integrity_check set nRow [db eval {SELECT count(*) FROM abc}] if {!(($nRow==2 && $testrc) || $nRow==3)} { error "Bad db content" } } #------------------------------------------------------------------------- # Test fault-handling when switching out of exclusive-locking mode. # do_test walfault-14-pre { faultsim_delete_and_reopen execsql { PRAGMA auto_vacuum = 0; PRAGMA journal_mode = WAL; BEGIN; CREATE TABLE abc(a PRIMARY KEY); INSERT INTO abc VALUES(randomblob(1500)); INSERT INTO abc VALUES(randomblob(1500)); COMMIT; } faultsim_save_and_close } {} do_faultsim_test walfault-14 -prep { faultsim_restore_and_reopen breakpoint execsql { SELECT count(*) FROM abc; PRAGMA locking_mode = exclusive; BEGIN; INSERT INTO abc VALUES(randomblob(1500)); COMMIT; } } -body { db eval { PRAGMA locking_mode = normal; BEGIN; INSERT INTO abc VALUES(randomblob(1500)); COMMIT; } } -test { faultsim_integrity_check set nRow [db eval {SELECT count(*) FROM abc}] if {$nRow!=3 && $nRow!=4} { error "Bad db content" } } finish_test |
Changes to test/where8.test.
︙ | ︙ | |||
291 292 293 294 295 296 297 298 299 300 301 302 303 304 | } {I I I I I I I I I I II II II II II II II II II II III III III III III 9 1} do_test where8-3.21 { execsql_status { SELECT a, d FROM t1, (t2) WHERE (a=d OR b=e) AND a<5 ORDER BY a } } {1 1 2 2 3 3 4 2 4 4 0 0} do_test where8-3.22 { execsql_status { SELECT a, d FROM ((((((t1))), (((t2)))))) WHERE (a=d OR b=e) AND a<5 ORDER BY a } } {1 1 2 2 3 3 4 2 4 4 0 0} | > > > > > > > > > > > > > | > | 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 | } {I I I I I I I I I I II II II II II II II II II II III III III III III 9 1} do_test where8-3.21 { execsql_status { SELECT a, d FROM t1, (t2) WHERE (a=d OR b=e) AND a<5 ORDER BY a } } {1 1 2 2 3 3 4 2 4 4 0 0} do_test where8-3.21.1 { execsql_status { SELECT a, d FROM t1, ((t2)) AS t3 WHERE (a=d OR b=e) AND a<5 ORDER BY a } } {1 1 2 2 3 3 4 2 4 4 0 0} do_test where8-3.21.2 { execsql_status { SELECT a, d FROM t1, ((SELECT * FROM t2)) AS t3 WHERE (a=d OR b=e) AND a<5 ORDER BY a } } {1 1 2 2 3 3 4 2 4 4 0 0} do_test where8-3.22 { execsql_status { SELECT a, d FROM ((((((t1))), (((t2)))))) WHERE (a=d OR b=e) AND a<5 ORDER BY a } } {1 1 2 2 3 3 4 2 4 4 0 0} do_test where8-3.23 { execsql_status { SELECT * FROM ((SELECT * FROM t2)) AS t3; } } {1 {} I 2 four IV 3 {} IX 4 sixteen XVI 5 {} XXV 6 thirtysix XXXVI 7 fortynine XLIX 8 sixtyeight LXIV 9 eightyone LXXXIX 10 {} C 9 0} #----------------------------------------------------------------------- # The following tests - where8-4.* - verify that adding or removing # indexes does not change the results returned by various queries. # do_test where8-4.1 { execsql { |
︙ | ︙ |
Changes to test/where9.test.
︙ | ︙ | |||
888 889 890 891 892 893 894 895 896 | db eval { SELECT * FROM (t81) LEFT JOIN (main.t82) ON y=b JOIN t83 WHERE c==p OR d==p ORDER BY +a; } } {2 3 4 5 {} {} 5 55 3 4 5 6 2 4 5 55} finish_test | > > > > > > > > > > > > > > > > > > > > > | 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 | db eval { SELECT * FROM (t81) LEFT JOIN (main.t82) ON y=b JOIN t83 WHERE c==p OR d==p ORDER BY +a; } } {2 3 4 5 {} {} 5 55 3 4 5 6 2 4 5 55} # Fix for ticket [f2369304e47167e3e644e2f1fe9736063391d7b7] # Incorrect results when OR is used in the ON clause of a LEFT JOIN # do_test where9-9.1 { db eval { CREATE TABLE t91(x); INSERT INTO t91 VALUES(1); CREATE TABLE t92(y INTEGER PRIMARY KEY,a,b); INSERT INTO t92 VALUES(1,2,3); SELECT 1 FROM t91 LEFT JOIN t92 ON a=2 OR b=3; SELECT 2 FROM t91 LEFT JOIN t92 ON a=2 AND b=3; SELECT 3 FROM t91 LEFT JOIN t92 ON (a=2 OR b=3) AND y IS NULL; SELECT 4 FROM t91 LEFT JOIN t92 ON (a=2 AND b=3) AND y IS NULL; CREATE TEMP TABLE x9 AS SELECT * FROM t91 LEFT JOIN t92 ON a=2 OR b=3; SELECT 5 FROM x9 WHERE y IS NULL; SELECT 6 FROM t91 LEFT JOIN t92 ON a=2 OR b=3 WHERE y IS NULL; SELECT 7 FROM t91 LEFT JOIN t92 ON a=2 AND b=3 WHERE y IS NULL; SELECT 8 FROM t91 LEFT JOIN t92 ON a=22 OR b=33 WHERE y IS NULL; SELECT 9 FROM t91 LEFT JOIN t92 ON a=22 AND b=33 WHERE y IS NULL; } } {1 2 3 4 8 9} finish_test |
Changes to test/win32lock.test.
︙ | ︙ | |||
23 24 25 26 27 28 29 30 31 32 33 34 35 36 | db close sqlite3_shutdown test_sqlite3_log xLog proc xLog {error_code msg} { lappend ::log $msg } sqlite3 db test.db do_test win32lock-1.1 { db eval { PRAGMA cache_size=10; CREATE TABLE t1(x,y); INSERT INTO t1 VALUES(1,randomblob(100000)); INSERT INTO t1 VALUES(2,randomblob(50000)); | > | 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | db close sqlite3_shutdown test_sqlite3_log xLog proc xLog {error_code msg} { lappend ::log $msg } sqlite3 db test.db db eval {PRAGMA mmap_size=0} do_test win32lock-1.1 { db eval { PRAGMA cache_size=10; CREATE TABLE t1(x,y); INSERT INTO t1 VALUES(1,randomblob(100000)); INSERT INTO t1 VALUES(2,randomblob(50000)); |
︙ | ︙ |
Changes to test/zerodamage.test.
︙ | ︙ | |||
55 56 57 58 59 60 61 | set ::max_journal_size 0 proc xDeleteCallback {method file args} { set sz [file size $file] if {$sz>$::max_journal_size} {set ::max_journal_size $sz} } tv filter xDelete tv script xDeleteCallback | | | 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 | set ::max_journal_size 0 proc xDeleteCallback {method file args} { set sz [file size $file] if {$sz>$::max_journal_size} {set ::max_journal_size $sz} } tv filter xDelete tv script xDeleteCallback load_static_extension db wholenumber db eval { PRAGMA page_size=1024; PRAGMA journal_mode=DELETE; PRAGMA cache_size=5; CREATE VIRTUAL TABLE nums USING wholenumber; CREATE TABLE t1(x, y); INSERT INTO t1 SELECT value, randomblob(100) FROM nums |
︙ | ︙ |
Changes to tool/build-shell.sh.
︙ | ︙ | |||
11 12 13 14 15 16 17 | make sqlite3.c gcc -o sqlite3 -g -Os -I. \ -DSQLITE_THREADSAFE=0 \ -DSQLITE_ENABLE_VFSTRACE \ -DSQLITE_ENABLE_STAT3 \ -DSQLITE_ENABLE_FTS4 \ -DSQLITE_ENABLE_RTREE \ | < < < < | 11 12 13 14 15 16 17 18 19 20 21 22 | make sqlite3.c gcc -o sqlite3 -g -Os -I. \ -DSQLITE_THREADSAFE=0 \ -DSQLITE_ENABLE_VFSTRACE \ -DSQLITE_ENABLE_STAT3 \ -DSQLITE_ENABLE_FTS4 \ -DSQLITE_ENABLE_RTREE \ -DHAVE_READLINE \ -DHAVE_USLEEP=1 \ ../sqlite/src/shell.c \ ../sqlite/src/test_vfstrace.c \ sqlite3.c -ldl -lreadline -lncurses |
Changes to tool/mksqlite3c.tcl.
︙ | ︙ | |||
19 20 21 22 23 24 25 | # # tclsh mksqlite3c.tcl # # The amalgamated SQLite code will be written into sqlite3.c # # Begin by reading the "sqlite3.h" header file. Extract the version number | | | 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | # # tclsh mksqlite3c.tcl # # The amalgamated SQLite code will be written into sqlite3.c # # Begin by reading the "sqlite3.h" header file. Extract the version number # from in this file. The version number is needed to generate the header # comment of the amalgamation. # if {[lsearch $argv --nostatic]>=0} { set addstatic 0 } else { set addstatic 1 } |
︙ | ︙ | |||
307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 | fts3.c fts3_aux.c fts3_expr.c fts3_hash.c fts3_porter.c fts3_tokenizer.c fts3_tokenizer1.c fts3_write.c fts3_snippet.c fts3_unicode.c fts3_unicode2.c rtree.c icu.c fts3_icu.c } { copy_file tsrc/$file } close $out | > | 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 | fts3.c fts3_aux.c fts3_expr.c fts3_hash.c fts3_porter.c fts3_tokenizer.c fts3_tokenizer1.c fts3_tokenize_vtab.c fts3_write.c fts3_snippet.c fts3_unicode.c fts3_unicode2.c rtree.c icu.c fts3_icu.c } { copy_file tsrc/$file } close $out |
Changes to tool/mksqlite3h.tcl.
︙ | ︙ | |||
64 65 66 67 68 69 70 | # set varpattern {^[a-zA-Z][a-zA-Z_0-9 *]+sqlite3_[_a-zA-Z0-9]+(\[|;| =)} set declpattern {^ *[a-zA-Z][a-zA-Z_0-9 ]+ \**sqlite3_[_a-zA-Z0-9]+\(} # Force the output to use unix line endings, even on Windows. fconfigure stdout -translation lf | > > | > | > > | | 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 | # set varpattern {^[a-zA-Z][a-zA-Z_0-9 *]+sqlite3_[_a-zA-Z0-9]+(\[|;| =)} set declpattern {^ *[a-zA-Z][a-zA-Z_0-9 ]+ \**sqlite3_[_a-zA-Z0-9]+\(} # 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 }] # Process the source files. # foreach file $filelist { set in [open $file] while {![eof $in]} { set line [gets $in] # File sqlite3rtree.h contains a line "#include <sqlite3.h>". Omit this # line when copying sqlite3rtree.h into sqlite3.h. |
︙ | ︙ |
Changes to tool/showdb.c.
︙ | ︙ | |||
172 173 174 175 176 177 178 | print_decode_line(aData, 40, 4, "Schema cookie"); print_decode_line(aData, 44, 4, "Schema format version"); print_decode_line(aData, 48, 4, "Default page cache size"); print_decode_line(aData, 52, 4, "Largest auto-vac root page"); print_decode_line(aData, 56, 4, "Text encoding"); print_decode_line(aData, 60, 4, "User version"); print_decode_line(aData, 64, 4, "Incremental-vacuum mode"); | | | 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 | print_decode_line(aData, 40, 4, "Schema cookie"); print_decode_line(aData, 44, 4, "Schema format version"); print_decode_line(aData, 48, 4, "Default page cache size"); print_decode_line(aData, 52, 4, "Largest auto-vac root page"); print_decode_line(aData, 56, 4, "Text encoding"); print_decode_line(aData, 60, 4, "User version"); print_decode_line(aData, 64, 4, "Incremental-vacuum mode"); print_decode_line(aData, 68, 4, "Application ID"); print_decode_line(aData, 72, 4, "meta[8]"); print_decode_line(aData, 76, 4, "meta[9]"); print_decode_line(aData, 80, 4, "meta[10]"); print_decode_line(aData, 84, 4, "meta[11]"); print_decode_line(aData, 88, 4, "meta[12]"); print_decode_line(aData, 92, 4, "Change counter for version number"); print_decode_line(aData, 96, 4, "SQLite version number"); |
︙ | ︙ |