Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Changes In Branch begin-concurrent-pnu Excluding Merge-Ins
This is equivalent to a diff from 123cbb33 to 910001f2
2022-01-17
| ||
19:10 | Merge the begin-concurrent-pnuu branch into begin-concurrent. (check-in: 22fb5050 user: drh tags: begin-concurrent) | |
2022-01-07
| ||
14:09 | Merge 3.37.2 changes into the begin-concurrent-pnu branch. (Leaf check-in: e525892d user: drh tags: begin-concurrent-3.37) | |
2021-11-27
| ||
14:56 | Merge version 3.37.0 into the begin-concurrent-report branch. (check-in: 126d7a1d user: drh tags: begin-concurrent-report) | |
14:48 | Merge version 3.37.0 into the begin-concurrent-pnu branch. (Closed-Leaf check-in: 910001f2 user: drh tags: begin-concurrent-pnu) | |
14:13 | Version 3.37.0 (check-in: bd41822c user: drh tags: trunk, release, major-release, version-3.37.0) | |
2021-11-22
| ||
16:27 | Merge the latest trunk enhancements into the begin-concurrent-pnu branch. (check-in: aa045e7b user: drh tags: begin-concurrent-pnu) | |
2018-12-29
| ||
20:42 | Fix a problem causing a corrupt pager-cache if an OOM or IO error was encountered while committing a concurrent transacation. (check-in: 48ca30f9 user: dan tags: begin-concurrent) | |
2018-12-18
| ||
17:47 | Merge latest begin-concurrent changes into this branch. (check-in: a93ca38b user: dan tags: begin-concurrent-pnu) | |
17:20 | Merge latest trunk changes into this branch. (check-in: 123cbb33 user: dan tags: begin-concurrent) | |
2018-12-17
| ||
22:19 | Move variable declaration to address compilation issue (C89). (check-in: d64f248d user: mistachkin tags: trunk) | |
2018-12-06
| ||
02:08 | Merge bug fixes from trunk. (check-in: 1e13aaa2 user: drh tags: begin-concurrent) | |
Added LICENSE.md.
> > > > > > | 1 2 3 4 5 6 | 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. |
Changes to Makefile.in.
︙ | ︙ | |||
161 162 163 164 165 166 167 168 169 170 171 172 173 174 | LTLINK = $(LIBTOOL) --mode=link $(TCC) $(LTCOMPILE_EXTRAS) @LDFLAGS@ $(LTLINK_EXTRAS) LTINSTALL = $(LIBTOOL) --mode=install $(INSTALL) # You should not have to change anything below this line ############################################################################### USE_AMALGAMATION = @USE_AMALGAMATION@ # Object files for the SQLite library (non-amalgamation). # 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 dbpage.lo dbstat.lo delete.lo \ | > | 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 | LTLINK = $(LIBTOOL) --mode=link $(TCC) $(LTCOMPILE_EXTRAS) @LDFLAGS@ $(LTLINK_EXTRAS) LTINSTALL = $(LIBTOOL) --mode=install $(INSTALL) # You should not have to change anything below this line ############################################################################### USE_AMALGAMATION = @USE_AMALGAMATION@ AMALGAMATION_LINE_MACROS = @AMALGAMATION_LINE_MACROS@ # Object files for the SQLite library (non-amalgamation). # 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 dbpage.lo dbstat.lo delete.lo \ |
︙ | ︙ | |||
186 187 188 189 190 191 192 | notify.lo opcodes.lo os.lo os_unix.lo os_win.lo \ pager.lo parse.lo pcache.lo pcache1.lo pragma.lo prepare.lo printf.lo \ random.lo resolve.lo rowset.lo rtree.lo \ sqlite3session.lo select.lo sqlite3rbu.lo status.lo stmt.lo \ table.lo threads.lo tokenize.lo treeview.lo trigger.lo \ update.lo userauth.lo upsert.lo util.lo vacuum.lo \ vdbe.lo vdbeapi.lo vdbeaux.lo vdbeblob.lo vdbemem.lo vdbesort.lo \ | > | | 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 | notify.lo opcodes.lo os.lo os_unix.lo os_win.lo \ pager.lo parse.lo pcache.lo pcache1.lo pragma.lo prepare.lo printf.lo \ random.lo resolve.lo rowset.lo rtree.lo \ sqlite3session.lo select.lo sqlite3rbu.lo status.lo stmt.lo \ table.lo threads.lo tokenize.lo treeview.lo trigger.lo \ update.lo userauth.lo upsert.lo util.lo vacuum.lo \ vdbe.lo vdbeapi.lo vdbeaux.lo vdbeblob.lo vdbemem.lo vdbesort.lo \ vdbetrace.lo vdbevtab.lo \ wal.lo walker.lo where.lo wherecode.lo whereexpr.lo \ window.lo utf.lo vtab.lo # Object files for the amalgamation. # LIBOBJS1 = sqlite3.lo # Determine the real value of LIBOBJ based on the 'configure' script |
︙ | ︙ | |||
292 293 294 295 296 297 298 299 300 301 302 303 304 305 | $(TOP)/src/vdbe.h \ $(TOP)/src/vdbeapi.c \ $(TOP)/src/vdbeaux.c \ $(TOP)/src/vdbeblob.c \ $(TOP)/src/vdbemem.c \ $(TOP)/src/vdbesort.c \ $(TOP)/src/vdbetrace.c \ $(TOP)/src/vdbeInt.h \ $(TOP)/src/vtab.c \ $(TOP)/src/vxworks.h \ $(TOP)/src/wal.c \ $(TOP)/src/wal.h \ $(TOP)/src/walker.c \ $(TOP)/src/where.c \ | > | 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 | $(TOP)/src/vdbe.h \ $(TOP)/src/vdbeapi.c \ $(TOP)/src/vdbeaux.c \ $(TOP)/src/vdbeblob.c \ $(TOP)/src/vdbemem.c \ $(TOP)/src/vdbesort.c \ $(TOP)/src/vdbetrace.c \ $(TOP)/src/vdbevtab.c \ $(TOP)/src/vdbeInt.h \ $(TOP)/src/vtab.c \ $(TOP)/src/vxworks.h \ $(TOP)/src/wal.c \ $(TOP)/src/wal.h \ $(TOP)/src/walker.c \ $(TOP)/src/where.c \ |
︙ | ︙ | |||
418 419 420 421 422 423 424 425 426 427 428 429 430 431 | $(TOP)/src/test_schema.c \ $(TOP)/src/test_server.c \ $(TOP)/src/test_superlock.c \ $(TOP)/src/test_syscall.c \ $(TOP)/src/test_tclsh.c \ $(TOP)/src/test_tclvar.c \ $(TOP)/src/test_thread.c \ $(TOP)/src/test_vfs.c \ $(TOP)/src/test_windirent.c \ $(TOP)/src/test_window.c \ $(TOP)/src/test_wsd.c \ $(TOP)/ext/fts3/fts3_term.c \ $(TOP)/ext/fts3/fts3_test.c \ $(TOP)/ext/session/test_session.c \ | > > | > > > > | > | 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 | $(TOP)/src/test_schema.c \ $(TOP)/src/test_server.c \ $(TOP)/src/test_superlock.c \ $(TOP)/src/test_syscall.c \ $(TOP)/src/test_tclsh.c \ $(TOP)/src/test_tclvar.c \ $(TOP)/src/test_thread.c \ $(TOP)/src/test_vdbecov.c \ $(TOP)/src/test_vfs.c \ $(TOP)/src/test_windirent.c \ $(TOP)/src/test_window.c \ $(TOP)/src/test_wsd.c \ $(TOP)/ext/fts3/fts3_term.c \ $(TOP)/ext/fts3/fts3_test.c \ $(TOP)/ext/session/test_session.c \ $(TOP)/ext/session/sqlite3changebatch.c \ $(TOP)/ext/rbu/test_rbu.c # Statically linked extensions # TESTSRC += \ $(TOP)/ext/expert/sqlite3expert.c \ $(TOP)/ext/expert/test_expert.c \ $(TOP)/ext/misc/amatch.c \ $(TOP)/ext/misc/appendvfs.c \ $(TOP)/ext/misc/carray.c \ $(TOP)/ext/misc/cksumvfs.c \ $(TOP)/ext/misc/closure.c \ $(TOP)/ext/misc/csv.c \ $(TOP)/ext/misc/decimal.c \ $(TOP)/ext/misc/eval.c \ $(TOP)/ext/misc/explain.c \ $(TOP)/ext/misc/fileio.c \ $(TOP)/ext/misc/fuzzer.c \ $(TOP)/ext/fts5/fts5_tcl.c \ $(TOP)/ext/fts5/fts5_test_mi.c \ $(TOP)/ext/fts5/fts5_test_tok.c \ $(TOP)/ext/misc/ieee754.c \ $(TOP)/ext/misc/mmapwarm.c \ $(TOP)/ext/misc/nextchar.c \ $(TOP)/ext/misc/normalize.c \ $(TOP)/ext/misc/percentile.c \ $(TOP)/ext/misc/prefixes.c \ $(TOP)/ext/misc/regexp.c \ $(TOP)/ext/misc/remember.c \ $(TOP)/ext/misc/series.c \ $(TOP)/ext/misc/spellfix.c \ $(TOP)/ext/misc/totype.c \ $(TOP)/ext/misc/unionvtab.c \ $(TOP)/ext/misc/wholenumber.c \ $(TOP)/ext/misc/zipfile.c \ $(TOP)/ext/userauth/userauth.c \ $(TOP)/ext/rtree/test_rtreedoc.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 \ |
︙ | ︙ | |||
496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 | $(TOP)/src/utf.c \ $(TOP)/src/util.c \ $(TOP)/src/vdbeapi.c \ $(TOP)/src/vdbeaux.c \ $(TOP)/src/vdbe.c \ $(TOP)/src/vdbemem.c \ $(TOP)/src/vdbetrace.c \ $(TOP)/src/where.c \ $(TOP)/src/wherecode.c \ $(TOP)/src/whereexpr.c \ $(TOP)/src/window.c \ parse.c \ $(TOP)/ext/fts3/fts3.c \ $(TOP)/ext/fts3/fts3_aux.c \ $(TOP)/ext/fts3/fts3_expr.c \ $(TOP)/ext/fts3/fts3_term.c \ $(TOP)/ext/fts3/fts3_tokenizer.c \ $(TOP)/ext/fts3/fts3_write.c \ $(TOP)/ext/async/sqlite3async.c \ $(TOP)/ext/session/sqlite3session.c \ | > > | > | 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 | $(TOP)/src/utf.c \ $(TOP)/src/util.c \ $(TOP)/src/vdbeapi.c \ $(TOP)/src/vdbeaux.c \ $(TOP)/src/vdbe.c \ $(TOP)/src/vdbemem.c \ $(TOP)/src/vdbetrace.c \ $(TOP)/src/vdbevtab.c \ $(TOP)/src/where.c \ $(TOP)/src/wherecode.c \ $(TOP)/src/whereexpr.c \ $(TOP)/src/window.c \ parse.c \ $(TOP)/ext/fts3/fts3.c \ $(TOP)/ext/fts3/fts3_aux.c \ $(TOP)/ext/fts3/fts3_expr.c \ $(TOP)/ext/fts3/fts3_term.c \ $(TOP)/ext/fts3/fts3_tokenizer.c \ $(TOP)/ext/fts3/fts3_write.c \ $(TOP)/ext/async/sqlite3async.c \ $(TOP)/ext/misc/stmt.c \ $(TOP)/ext/session/sqlite3session.c \ $(TOP)/ext/session/test_session.c \ fts5.c # Header files used by all library source files. # HDR = \ $(TOP)/src/btree.h \ $(TOP)/src/btreeInt.h \ $(TOP)/src/hash.h \ |
︙ | ︙ | |||
584 585 586 587 588 589 590 | FUZZDATA = \ $(TOP)/test/fuzzdata1.db \ $(TOP)/test/fuzzdata2.db \ $(TOP)/test/fuzzdata3.db \ $(TOP)/test/fuzzdata4.db \ $(TOP)/test/fuzzdata5.db \ $(TOP)/test/fuzzdata6.db \ | | > | | < > > > > > > > | 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 | FUZZDATA = \ $(TOP)/test/fuzzdata1.db \ $(TOP)/test/fuzzdata2.db \ $(TOP)/test/fuzzdata3.db \ $(TOP)/test/fuzzdata4.db \ $(TOP)/test/fuzzdata5.db \ $(TOP)/test/fuzzdata6.db \ $(TOP)/test/fuzzdata7.db \ $(TOP)/test/fuzzdata8.db # Standard options to testfixture # TESTOPTS = --verbose=file --output=test-out.txt # Extra compiler options for various shell tools # SHELL_OPT = -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS4 #SHELL_OPT += -DSQLITE_ENABLE_FTS5 SHELL_OPT += -DSQLITE_ENABLE_RTREE SHELL_OPT += -DSQLITE_ENABLE_EXPLAIN_COMMENTS SHELL_OPT += -DSQLITE_ENABLE_UNKNOWN_SQL_FUNCTION SHELL_OPT += -DSQLITE_ENABLE_STMTVTAB SHELL_OPT += -DSQLITE_ENABLE_DBPAGE_VTAB SHELL_OPT += -DSQLITE_ENABLE_DBSTAT_VTAB SHELL_OPT += -DSQLITE_ENABLE_BYTECODE_VTAB SHELL_OPT += -DSQLITE_ENABLE_OFFSET_SQL_FUNC FUZZERSHELL_OPT = -DSQLITE_ENABLE_JSON1 FUZZCHECK_OPT = -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_MEMSYS5 -DSQLITE_OSS_FUZZ FUZZCHECK_OPT += -DSQLITE_MAX_MEMORY=50000000 FUZZCHECK_OPT += -DSQLITE_PRINTF_PRECISION_LIMIT=1000 FUZZCHECK_OPT += -DSQLITE_ENABLE_FTS4 FUZZCHECK_OPT += -DSQLITE_ENABLE_FTS3_PARENTHESIS FUZZCHECK_OPT += -DSQLITE_ENABLE_FTS5 FUZZCHECK_OPT += -DSQLITE_ENABLE_RTREE FUZZCHECK_OPT += -DSQLITE_ENABLE_GEOPOLY FUZZCHECK_OPT += -DSQLITE_ENABLE_DBSTAT_VTAB FUZZCHECK_OPT += -DSQLITE_ENABLE_BYTECODE_VTAB FUZZCHECK_SRC = $(TOP)/test/fuzzcheck.c $(TOP)/test/ossfuzz.c DBFUZZ_OPT = # This is the default Makefile target. The objects listed here # are what get build when you type just "make" with no arguments. # all: sqlite3.h libsqlite3.la sqlite3$(TEXE) $(HAVE_TCL:1=libtclsqlite3.la) |
︙ | ︙ | |||
673 674 675 676 677 678 679 | dbfuzz$(TEXE): $(TOP)/test/dbfuzz.c sqlite3.c sqlite3.h $(LTLINK) -o $@ $(DBFUZZ_OPT) $(TOP)/test/dbfuzz.c sqlite3.c $(TLIBS) DBFUZZ2_OPTS = \ -DSQLITE_THREADSAFE=0 \ -DSQLITE_OMIT_LOAD_EXTENSION \ | < > | > > > > > > > | | | > > > > > > > | 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 | dbfuzz$(TEXE): $(TOP)/test/dbfuzz.c sqlite3.c sqlite3.h $(LTLINK) -o $@ $(DBFUZZ_OPT) $(TOP)/test/dbfuzz.c sqlite3.c $(TLIBS) DBFUZZ2_OPTS = \ -DSQLITE_THREADSAFE=0 \ -DSQLITE_OMIT_LOAD_EXTENSION \ -DSQLITE_DEBUG \ -DSQLITE_ENABLE_DBSTAT_VTAB \ -DSQLITE_ENABLE_BYTECODE_VTAB \ -DSQLITE_ENABLE_RTREE \ -DSQLITE_ENABLE_FTS4 \ -DSQLITE_ENABLE_FTS5 dbfuzz2$(TEXE): $(TOP)/test/dbfuzz2.c sqlite3.c sqlite3.h $(CC) $(OPT_FEATURE_FLAGS) $(OPTS) -I. -g -O0 \ -DSTANDALONE -o dbfuzz2 \ $(DBFUZZ2_OPTS) $(TOP)/test/dbfuzz2.c sqlite3.c $(TLIBS) mkdir -p dbfuzz2-dir cp $(TOP)/test/dbfuzz2-seed* dbfuzz2-dir dbfuzz2-asan: $(TOP)/test/dbfuzz2.c sqlite3.c sqlite3.h clang-6.0 $(OPT_FEATURE_FLAGS) $(OPTS) -I. -g -O0 \ -fsanitize=fuzzer,undefined,address -o dbfuzz2-asan \ $(DBFUZZ2_OPTS) $(TOP)/test/dbfuzz2.c sqlite3.c $(TLIBS) mkdir -p dbfuzz2-dir cp $(TOP)/test/dbfuzz2-seed* dbfuzz2-dir dbfuzz2-msan: $(TOP)/test/dbfuzz2.c sqlite3.c sqlite3.h clang-6.0 $(OPT_FEATURE_FLAGS) $(OPTS) -I. -g -O0 \ -fsanitize=fuzzer,undefined,memory -o dbfuzz2-msan \ $(DBFUZZ2_OPTS) $(TOP)/test/dbfuzz2.c sqlite3.c $(TLIBS) mkdir -p dbfuzz2-dir cp $(TOP)/test/dbfuzz2-seed* dbfuzz2-dir mptester$(TEXE): sqlite3.lo $(TOP)/mptest/mptest.c $(LTLINK) -o $@ -I. $(TOP)/mptest/mptest.c sqlite3.lo \ $(TLIBS) -rpath "$(libdir)" |
︙ | ︙ | |||
722 723 724 725 726 727 728 | rm tsrc/sqlite.h.in tsrc/parse.y $(TCLSH_CMD) $(TOP)/tool/vdbe-compress.tcl $(OPTS) <tsrc/vdbe.c >vdbe.new mv vdbe.new tsrc/vdbe.c cp fts5.c fts5.h tsrc touch .target_source sqlite3.c: .target_source $(TOP)/tool/mksqlite3c.tcl | | | 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 | rm tsrc/sqlite.h.in tsrc/parse.y $(TCLSH_CMD) $(TOP)/tool/vdbe-compress.tcl $(OPTS) <tsrc/vdbe.c >vdbe.new mv vdbe.new tsrc/vdbe.c cp fts5.c fts5.h tsrc touch .target_source sqlite3.c: .target_source $(TOP)/tool/mksqlite3c.tcl $(TCLSH_CMD) $(TOP)/tool/mksqlite3c.tcl $(AMALGAMATION_LINE_MACROS) cp tsrc/sqlite3ext.h . cp $(TOP)/ext/session/sqlite3session.h . sqlite3ext.h: .target_source cp tsrc/sqlite3ext.h . tclsqlite3.c: sqlite3.c |
︙ | ︙ | |||
978 979 980 981 982 983 984 985 986 987 988 989 990 991 | vdbesort.lo: $(TOP)/src/vdbesort.c $(HDR) $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/vdbesort.c vdbetrace.lo: $(TOP)/src/vdbetrace.c $(HDR) $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/vdbetrace.c vtab.lo: $(TOP)/src/vtab.c $(HDR) $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/vtab.c wal.lo: $(TOP)/src/wal.c $(HDR) $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/wal.c walker.lo: $(TOP)/src/walker.c $(HDR) | > > > | 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 | vdbesort.lo: $(TOP)/src/vdbesort.c $(HDR) $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/vdbesort.c vdbetrace.lo: $(TOP)/src/vdbetrace.c $(HDR) $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/vdbetrace.c vdbevtab.lo: $(TOP)/src/vdbevtab.c $(HDR) $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/vdbevtab.c vtab.lo: $(TOP)/src/vtab.c $(HDR) $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/vtab.c wal.lo: $(TOP)/src/wal.c $(HDR) $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/wal.c walker.lo: $(TOP)/src/walker.c $(HDR) |
︙ | ︙ | |||
1024 1025 1026 1027 1028 1029 1030 | opcodes.h: parse.h $(TOP)/src/vdbe.c $(TOP)/tool/mkopcodeh.tcl cat parse.h $(TOP)/src/vdbe.c | $(TCLSH_CMD) $(TOP)/tool/mkopcodeh.tcl >opcodes.h # Rules to build parse.c and parse.h - the outputs of lemon. # parse.h: parse.c | | < | < < > > > > > > > | | > > > > > | 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 | opcodes.h: parse.h $(TOP)/src/vdbe.c $(TOP)/tool/mkopcodeh.tcl cat parse.h $(TOP)/src/vdbe.c | $(TCLSH_CMD) $(TOP)/tool/mkopcodeh.tcl >opcodes.h # Rules to build parse.c and parse.h - the outputs of lemon. # parse.h: parse.c parse.c: $(TOP)/src/parse.y lemon$(BEXE) cp $(TOP)/src/parse.y . ./lemon$(BEXE) $(OPT_FEATURE_FLAGS) $(OPTS) -S parse.y sqlite3.h: $(TOP)/src/sqlite.h.in $(TOP)/manifest mksourceid$(BEXE) $(TOP)/VERSION $(TCLSH_CMD) $(TOP)/tool/mksqlite3h.tcl $(TOP) >sqlite3.h sqlite3rc.h: $(TOP)/src/sqlite3.rc $(TOP)/VERSION echo '#ifndef SQLITE_RESOURCE_VERSION' >$@ echo -n '#define SQLITE_RESOURCE_VERSION ' >>$@ cat $(TOP)/VERSION | $(TCLSH_CMD) $(TOP)/tool/replace.tcl exact . , >>$@ echo '#endif' >>sqlite3rc.h keywordhash.h: $(TOP)/tool/mkkeywordhash.c $(BCC) -o mkkeywordhash$(BEXE) $(OPT_FEATURE_FLAGS) $(OPTS) $(TOP)/tool/mkkeywordhash.c ./mkkeywordhash$(BEXE) >keywordhash.h # Source files that go into making shell.c SHELL_SRC = \ $(TOP)/src/shell.c.in \ $(TOP)/ext/misc/appendvfs.c \ $(TOP)/ext/misc/completion.c \ $(TOP)/ext/misc/decimal.c \ $(TOP)/ext/misc/fileio.c \ $(TOP)/ext/misc/ieee754.c \ $(TOP)/ext/misc/regexp.c \ $(TOP)/ext/misc/series.c \ $(TOP)/ext/misc/shathree.c \ $(TOP)/ext/misc/sqlar.c \ $(TOP)/ext/misc/uint.c \ $(TOP)/ext/expert/sqlite3expert.c \ $(TOP)/ext/expert/sqlite3expert.h \ $(TOP)/ext/misc/zipfile.c \ $(TOP)/ext/misc/memtrace.c \ $(TOP)/src/test_windirent.c shell.c: $(SHELL_SRC) $(TOP)/tool/mkshellc.tcl $(TCLSH_CMD) $(TOP)/tool/mkshellc.tcl >shell.c |
︙ | ︙ | |||
1122 1123 1124 1125 1126 1127 1128 | fts3_write.lo: $(TOP)/ext/fts3/fts3_write.c $(HDR) $(EXTHDR) $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3_write.c rtree.lo: $(TOP)/ext/rtree/rtree.c $(HDR) $(EXTHDR) $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/rtree/rtree.c | | | | 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 | fts3_write.lo: $(TOP)/ext/fts3/fts3_write.c $(HDR) $(EXTHDR) $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3_write.c rtree.lo: $(TOP)/ext/rtree/rtree.c $(HDR) $(EXTHDR) $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/rtree/rtree.c userauth.lo: $(TOP)/ext/userauth/userauth.c $(HDR) $(EXTHDR) $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/userauth/userauth.c sqlite3session.lo: $(TOP)/ext/session/sqlite3session.c $(HDR) $(EXTHDR) $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/session/sqlite3session.c json1.lo: $(TOP)/ext/misc/json1.c $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/misc/json1.c stmt.lo: $(TOP)/ext/misc/stmt.c $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/misc/stmt.c |
︙ | ︙ | |||
1153 1154 1155 1156 1157 1158 1159 | fts5parse.c fts5parse.h \ $(TOP)/ext/fts5/fts5_storage.c \ $(TOP)/ext/fts5/fts5_tokenize.c \ $(TOP)/ext/fts5/fts5_unicode2.c \ $(TOP)/ext/fts5/fts5_varint.c \ $(TOP)/ext/fts5/fts5_vocab.c \ | | | | 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 | fts5parse.c fts5parse.h \ $(TOP)/ext/fts5/fts5_storage.c \ $(TOP)/ext/fts5/fts5_tokenize.c \ $(TOP)/ext/fts5/fts5_unicode2.c \ $(TOP)/ext/fts5/fts5_varint.c \ $(TOP)/ext/fts5/fts5_vocab.c \ fts5parse.c: $(TOP)/ext/fts5/fts5parse.y lemon$(BEXE) cp $(TOP)/ext/fts5/fts5parse.y . rm -f fts5parse.h ./lemon$(BEXE) $(OPTS) -S fts5parse.y fts5parse.h: fts5parse.c fts5.c: $(FTS5_SRC) $(TCLSH_CMD) $(TOP)/ext/fts5/tool/mkfts5c.tcl cp $(TOP)/ext/fts5/fts5.h . |
︙ | ︙ | |||
1186 1187 1188 1189 1190 1191 1192 | TESTFIXTURE_FLAGS += -DTCLSH_INIT_PROC=sqlite3TestInit TESTFIXTURE_FLAGS += -DSQLITE_SERVER=1 -DSQLITE_PRIVATE="" -DSQLITE_CORE TESTFIXTURE_FLAGS += -DBUILD_sqlite TESTFIXTURE_FLAGS += -DSQLITE_SERIES_CONSTRAINT_VERIFY=1 TESTFIXTURE_FLAGS += -DSQLITE_DEFAULT_PAGE_SIZE=1024 TESTFIXTURE_FLAGS += -DSQLITE_ENABLE_STMTVTAB TESTFIXTURE_FLAGS += -DSQLITE_ENABLE_DBPAGE_VTAB | | > > > > | < < < < | | > > > | 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 | TESTFIXTURE_FLAGS += -DTCLSH_INIT_PROC=sqlite3TestInit TESTFIXTURE_FLAGS += -DSQLITE_SERVER=1 -DSQLITE_PRIVATE="" -DSQLITE_CORE TESTFIXTURE_FLAGS += -DBUILD_sqlite TESTFIXTURE_FLAGS += -DSQLITE_SERIES_CONSTRAINT_VERIFY=1 TESTFIXTURE_FLAGS += -DSQLITE_DEFAULT_PAGE_SIZE=1024 TESTFIXTURE_FLAGS += -DSQLITE_ENABLE_STMTVTAB TESTFIXTURE_FLAGS += -DSQLITE_ENABLE_DBPAGE_VTAB TESTFIXTURE_FLAGS += -DSQLITE_ENABLE_BYTECODE_VTAB TESTFIXTURE_FLAGS += -DSQLITE_CKSUMVFS_STATIC 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) coretestprogs: $(TESTPROGS) testprogs: coretestprogs srcck1$(BEXE) fuzzcheck$(TEXE) sessionfuzz$(TEXE) # A very detailed test running most or all test cases fulltest: alltest fuzztest # Run most or all tcl test cases alltest: $(TESTPROGS) ./testfixture$(TEXE) $(TOP)/test/all.test $(TESTOPTS) # Really really long testing soaktest: $(TESTPROGS) ./testfixture$(TEXE) $(TOP)/test/all.test -soak=1 $(TESTOPTS) # Do extra testing but not everything. fulltestonly: $(TESTPROGS) fuzztest ./testfixture$(TEXE) $(TOP)/test/full.test # Fuzz testing fuzztest: fuzzcheck$(TEXE) $(FUZZDATA) sessionfuzz$(TEXE) $(TOP)/test/sessionfuzz-data1.db ./fuzzcheck$(TEXE) $(FUZZDATA) ./sessionfuzz$(TEXE) run $(TOP)/test/sessionfuzz-data1.db valgrindfuzz: fuzzcheck$(TEXT) $(FUZZDATA) sessionfuzz$(TEXE) $(TOP)/test/sessionfuzz-data1.db valgrind ./fuzzcheck$(TEXE) --cell-size-check --limit-mem 10M $(FUZZDATA) valgrind ./sessionfuzz$(TEXE) run $(TOP)/test/sessionfuzz-data1.db # The veryquick.test TCL tests. # tcltest: ./testfixture$(TEXE) ./testfixture$(TEXE) $(TOP)/test/veryquick.test $(TESTOPTS) # Minimal testing that runs in less than 3 minutes # quicktest: ./testfixture$(TEXE) ./testfixture$(TEXE) $(TOP)/test/extraquick.test $(TESTOPTS) # This is the common case. Run many tests that do not take too long, # including fuzzcheck, sqlite3_analyzer, and sqldiff tests. # test: fuzztest sourcetest $(TESTPROGS) tcltest # Run a test using valgrind. This can take a really long time # because valgrind is so much slower than a native machine. # valgrindtest: $(TESTPROGS) valgrindfuzz OMIT_MISUSE=1 valgrind -v ./testfixture$(TEXE) $(TOP)/test/permutations.test valgrind $(TESTOPTS) # A very fast test that checks basic sanity. The name comes from # the 60s-era electronics testing: "Turn it on and see if smoke # comes out." # smoketest: $(TESTPROGS) fuzzcheck$(TEXE) ./testfixture$(TEXE) $(TOP)/test/main.test $(TESTOPTS) shelltest: $(TESTPROGS) ./testfixture$(TEXT) $(TOP)/test/permutations.test shell sqlite3_analyzer.c: sqlite3.c $(TOP)/src/tclsqlite.c $(TOP)/tool/spaceanal.tcl $(TOP)/tool/mkccode.tcl $(TOP)/tool/sqlite3_analyzer.c.in $(TCLSH_CMD) $(TOP)/tool/mkccode.tcl $(TOP)/tool/sqlite3_analyzer.c.in >sqlite3_analyzer.c sqlite3_analyzer$(TEXE): sqlite3_analyzer.c $(LTLINK) sqlite3_analyzer.c -o $@ $(LIBTCL) $(TLIBS) sqltclsh.c: sqlite3.c $(TOP)/src/tclsqlite.c $(TOP)/tool/sqltclsh.tcl $(TOP)/ext/misc/appendvfs.c $(TOP)/tool/mkccode.tcl $(TOP)/tool/sqltclsh.c.in |
︙ | ︙ | |||
1308 1309 1310 1311 1312 1313 1314 | showwal$(TEXE): $(TOP)/tool/showwal.c sqlite3.lo $(LTLINK) -o $@ $(TOP)/tool/showwal.c sqlite3.lo $(TLIBS) showshm$(TEXE): $(TOP)/tool/showshm.c $(LTLINK) -o $@ $(TOP)/tool/showshm.c index_usage$(TEXE): $(TOP)/tool/index_usage.c sqlite3.lo | | | 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 | showwal$(TEXE): $(TOP)/tool/showwal.c sqlite3.lo $(LTLINK) -o $@ $(TOP)/tool/showwal.c sqlite3.lo $(TLIBS) showshm$(TEXE): $(TOP)/tool/showshm.c $(LTLINK) -o $@ $(TOP)/tool/showshm.c index_usage$(TEXE): $(TOP)/tool/index_usage.c sqlite3.lo $(LTLINK) $(SHELL_OPT) -o $@ $(TOP)/tool/index_usage.c sqlite3.lo $(TLIBS) changeset$(TEXE): $(TOP)/ext/session/changeset.c sqlite3.lo $(LTLINK) -o $@ $(TOP)/ext/session/changeset.c sqlite3.lo $(TLIBS) changesetfuzz$(TEXE): $(TOP)/ext/session/changesetfuzz.c sqlite3.lo $(LTLINK) -o $@ $(TOP)/ext/session/changesetfuzz.c sqlite3.lo $(TLIBS) |
︙ | ︙ | |||
1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 | wordcount$(TEXE): $(TOP)/test/wordcount.c sqlite3.lo $(LTLINK) -o $@ $(TOP)/test/wordcount.c sqlite3.lo $(TLIBS) speedtest1$(TEXE): $(TOP)/test/speedtest1.c sqlite3.c $(LTLINK) $(ST_OPT) -o $@ $(TOP)/test/speedtest1.c sqlite3.c $(TLIBS) KV_OPT += -DSQLITE_DIRECT_OVERFLOW_READ kvtest$(TEXE): $(TOP)/test/kvtest.c sqlite3.c $(LTLINK) $(KV_OPT) -o $@ $(TOP)/test/kvtest.c sqlite3.c $(TLIBS) rbu$(EXE): $(TOP)/ext/rbu/rbu.c $(TOP)/ext/rbu/sqlite3rbu.c sqlite3.lo $(LTLINK) -I. -o $@ $(TOP)/ext/rbu/rbu.c sqlite3.lo $(TLIBS) loadfts$(EXE): $(TOP)/tool/loadfts.c libsqlite3.la $(LTLINK) $(TOP)/tool/loadfts.c libsqlite3.la -o $@ $(TLIBS) # This target will fail if the SQLite amalgamation contains any exported # symbols that do not begin with "sqlite3_". It is run as part of the # releasetest.tcl script. # VALIDIDS=' sqlite3(changeset|changegroup|session)?_' | > > > | | > | | > > > | | 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 | wordcount$(TEXE): $(TOP)/test/wordcount.c sqlite3.lo $(LTLINK) -o $@ $(TOP)/test/wordcount.c sqlite3.lo $(TLIBS) speedtest1$(TEXE): $(TOP)/test/speedtest1.c sqlite3.c $(LTLINK) $(ST_OPT) -o $@ $(TOP)/test/speedtest1.c sqlite3.c $(TLIBS) startup$(TEXE): $(TOP)/test/startup.c sqlite3.c $(CC) -Os -g -DSQLITE_THREADSAFE=0 -o $@ $(TOP)/test/startup.c sqlite3.c $(TLIBS) KV_OPT += -DSQLITE_DIRECT_OVERFLOW_READ kvtest$(TEXE): $(TOP)/test/kvtest.c sqlite3.c $(LTLINK) $(KV_OPT) -o $@ $(TOP)/test/kvtest.c sqlite3.c $(TLIBS) rbu$(EXE): $(TOP)/ext/rbu/rbu.c $(TOP)/ext/rbu/sqlite3rbu.c sqlite3.lo $(LTLINK) -I. -o $@ $(TOP)/ext/rbu/rbu.c sqlite3.lo $(TLIBS) loadfts$(EXE): $(TOP)/tool/loadfts.c libsqlite3.la $(LTLINK) $(TOP)/tool/loadfts.c libsqlite3.la -o $@ $(TLIBS) # This target will fail if the SQLite amalgamation contains any exported # symbols that do not begin with "sqlite3_". It is run as part of the # releasetest.tcl script. # VALIDIDS=' sqlite3(changeset|changegroup|session)?_' checksymbols: sqlite3.o nm -g --defined-only sqlite3.o nm -g --defined-only sqlite3.o | egrep -v $(VALIDIDS); test $$? -ne 0 echo '0 errors out of 1 tests' # Build the amalgamation-autoconf package. The amalamgation-tarball target builds # a tarball named for the version number. Ex: sqlite-autoconf-3110000.tar.gz. # The snapshot-tarball target builds a tarball named by the SHA1 hash # amalgamation-tarball: sqlite3.c sqlite3rc.h TOP=$(TOP) sh $(TOP)/tool/mkautoconfamal.sh --normal snapshot-tarball: sqlite3.c sqlite3rc.h TOP=$(TOP) sh $(TOP)/tool/mkautoconfamal.sh --snapshot # The next two rules are used to support the "threadtest" target. Building # threadtest runs a few thread-safety tests that are implemented in C. This # target is invoked by the releasetest.tcl script. # THREADTEST3_SRC = $(TOP)/test/threadtest3.c \ $(TOP)/test/tt3_checkpoint.c \ $(TOP)/test/tt3_index.c \ $(TOP)/test/tt3_vacuum.c \ $(TOP)/test/tt3_stress.c \ $(TOP)/test/tt3_lookaside1.c threadtest3$(TEXE): sqlite3.lo $(THREADTEST3_SRC) $(LTLINK) $(TOP)/test/threadtest3.c $(TOP)/src/test_multiplex.c sqlite3.lo -o $@ $(TLIBS) threadtest: threadtest3$(TEXE) ./threadtest3$(TEXE) threadtest5: sqlite3.c $(TOP)/test/threadtest5.c $(LTLINK) $(TOP)/test/threadtest5.c sqlite3.c -o $@ $(TLIBS) releasetest: $(TCLSH_CMD) $(TOP)/test/releasetest.tcl # Standard install and cleanup targets # lib_install: libsqlite3.la $(INSTALL) -d $(DESTDIR)$(libdir) $(LTINSTALL) libsqlite3.la $(DESTDIR)$(libdir) install: sqlite3$(TEXE) lib_install sqlite3.h sqlite3.pc ${HAVE_TCL:1=tcl_install} $(INSTALL) -d $(DESTDIR)$(bindir) $(LTINSTALL) sqlite3$(TEXE) $(DESTDIR)$(bindir) $(INSTALL) -d $(DESTDIR)$(includedir) $(INSTALL) -m 0644 sqlite3.h $(DESTDIR)$(includedir) $(INSTALL) -m 0644 $(TOP)/src/sqlite3ext.h $(DESTDIR)$(includedir) $(INSTALL) -d $(DESTDIR)$(pkgconfigdir) $(INSTALL) -m 0644 sqlite3.pc $(DESTDIR)$(pkgconfigdir) pkgIndex.tcl: echo 'package ifneeded sqlite3 $(RELEASE) [list load [file join $$dir libtclsqlite3[info sharedlibextension]] sqlite3]' > $@ tcl_install: lib_install libtclsqlite3.la pkgIndex.tcl $(INSTALL) -d $(DESTDIR)$(TCLLIBDIR) $(LTINSTALL) libtclsqlite3.la $(DESTDIR)$(TCLLIBDIR) rm -f $(DESTDIR)$(TCLLIBDIR)/libtclsqlite3.la $(DESTDIR)$(TCLLIBDIR)/libtclsqlite3.a $(INSTALL) -m 0644 pkgIndex.tcl $(DESTDIR)$(TCLLIBDIR) clean: |
︙ | ︙ | |||
1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 | rm -f rbu rbu.exe rm -f srcck1 srcck1.exe rm -f fuzzershell fuzzershell.exe rm -f fuzzcheck fuzzcheck.exe rm -f sqldiff sqldiff.exe rm -f dbhash dbhash.exe rm -f fts5.* fts5parse.* distclean: clean rm -f config.h config.log config.status libtool Makefile sqlite3.pc # # Windows section # | > | 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 | rm -f rbu rbu.exe rm -f srcck1 srcck1.exe rm -f fuzzershell fuzzershell.exe rm -f fuzzcheck fuzzcheck.exe rm -f sqldiff sqldiff.exe rm -f dbhash dbhash.exe rm -f fts5.* fts5parse.* rm -f threadtest5 distclean: clean rm -f config.h config.log config.status libtool Makefile sqlite3.pc # # Windows section # |
︙ | ︙ |
Changes to Makefile.linux-gcc.
︙ | ︙ | |||
15 16 17 18 19 20 21 | # that contains this "Makefile.in" and the "configure.in" script. # TOP = ../sqlite #### C Compiler and options for use in building executables that # will run on the platform that is doing the build. # | | | | | | < < | | < < | < < | < < | 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 | # that contains this "Makefile.in" and the "configure.in" script. # TOP = ../sqlite #### C Compiler and options for use in building executables that # will run on the platform that is doing the build. # BCC = gcc -g -O0 #BCC = /opt/ancic/bin/c89 -0 #### If the target operating system supports the "usleep()" system # call, then define the HAVE_USLEEP macro for all C modules. # #USLEEP = USLEEP = -DHAVE_USLEEP=1 #### If you want the SQLite library to be safe for use within a # multi-threaded program, then define the following macro # appropriately: # #THREADSAFE = -DTHREADSAFE=1 THREADSAFE = -DTHREADSAFE=0 #### Specify any extra linker options needed to make the library # thread safe # THREADLIB = -lpthread -lm -ldl #THREADLIB = #### Specify any extra libraries needed to access required functions. # #TLIBS = -lrt # fdatasync on Solaris 8 TLIBS = #### Leave SQLITE_DEBUG undefined for maximum speed. Use SQLITE_DEBUG=1 # to check for memory leaks. Use SQLITE_DEBUG=2 to print a log of all # malloc()s and free()s in order to track down memory leaks. # # SQLite uses some expensive assert() statements in the inner loop. # You can make the library go almost twice as fast if you compile # with -DNDEBUG=1 # OPTS += -DSQLITE_DEBUG=1 OPTS += -DSQLITE_ENABLE_WHERETRACE OPTS += -DSQLITE_ENABLE_SELECTTRACE #### The suffix to add to executable files. ".exe" for windows. # Nothing for unix. # #EXE = .exe EXE = #### C Compile and options for use in building executables that # will run on the target platform. This is usually the same # as BCC, unless you are cross-compiling. # TCC = gcc -O0 #TCC = gcc -g -O0 -Wall #TCC = gcc -g -O0 -Wall -fprofile-arcs -ftest-coverage #TCC = /opt/mingw/bin/i386-mingw32-gcc -O6 #TCC = /opt/ansic/bin/c89 -O +z -Wl,-a,archive #### Tools used to build a static library. # AR = ar cr #AR = /opt/mingw/bin/i386-mingw32-ar cr RANLIB = ranlib #RANLIB = /opt/mingw/bin/i386-mingw32-ranlib MKSHLIB = gcc -shared SO = so SHPREFIX = lib # SO = dll # SHPREFIX = #### Extra compiler options needed for programs that use the TCL library. # TCL_FLAGS = -I/home/drh/tcl/include/tcl8.6 #### Linker options needed to link against the TCL library. # #LIBTCL = -ltcl -lm -ldl LIBTCL = /home/drh/tcl/lib/libtcl8.6.a -lm -lpthread -ldl -lz #### Additional objects for SQLite library when TCL support is enabled. #TCLOBJ = TCLOBJ = tclsqlite.o #### Compiler options needed for programs that use the readline() library. # |
︙ | ︙ |
Changes to Makefile.msc.
︙ | ︙ | |||
69 70 71 72 73 74 75 | # If necessary, create a list of harmless compiler warnings to disable when # compiling the various tools. For the SQLite source code itself, warnings, # if any, will be disabled from within it. # !IFNDEF NO_WARN !IF $(USE_FULLWARN)!=0 NO_WARN = -wd4054 -wd4055 -wd4100 -wd4127 -wd4130 -wd4152 -wd4189 -wd4206 | | | 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | # If necessary, create a list of harmless compiler warnings to disable when # compiling the various tools. For the SQLite source code itself, warnings, # if any, will be disabled from within it. # !IFNDEF NO_WARN !IF $(USE_FULLWARN)!=0 NO_WARN = -wd4054 -wd4055 -wd4100 -wd4127 -wd4130 -wd4152 -wd4189 -wd4206 NO_WARN = $(NO_WARN) -wd4210 -wd4232 -wd4244 -wd4305 -wd4306 -wd4702 -wd4706 !ENDIF !ENDIF # Set this non-0 to use the library paths and other options necessary for # Windows Phone 8.1. # !IFNDEF USE_WP81_OPTS |
︙ | ︙ | |||
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 | # 5 == SQLITE_DEBUG_OS_TRACE: Enables output from the OSTRACE() macros. # 6 == SQLITE_ENABLE_IOTRACE: Enables output from the IOTRACE() macros. # !IFNDEF DEBUG DEBUG = 0 !ENDIF # Enable use of available compiler optimizations? Normally, this should be # non-zero. Setting this to zero, thus disabling all compiler optimizations, # can be useful for testing. # !IFNDEF OPTIMIZATIONS OPTIMIZATIONS = 2 !ENDIF # Set this to non-0 to enable support for the session extension. # !IFNDEF SESSION SESSION = 0 !ENDIF # Set the source code file to be used by executables and libraries when # they need the amalgamation. # !IFNDEF SQLITE3C !IF $(SPLIT_AMALGAMATION)!=0 SQLITE3C = sqlite3-all.c | > > > > > > > > > > > > > > > > | 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 | # 5 == SQLITE_DEBUG_OS_TRACE: Enables output from the OSTRACE() macros. # 6 == SQLITE_ENABLE_IOTRACE: Enables output from the IOTRACE() macros. # !IFNDEF DEBUG DEBUG = 0 !ENDIF # <<mark>> # By default, use --linemacros=1 argument to the mksqlite3c.tcl tool, which # is used to build the amalgamation. This can be turned off to ease debug # of the amalgamation away from the source tree. # !IFNDEF NO_LINEMACROS NO_LINEMACROS = 0 !ENDIF # <</mark>> # Enable use of available compiler optimizations? Normally, this should be # non-zero. Setting this to zero, thus disabling all compiler optimizations, # can be useful for testing. # !IFNDEF OPTIMIZATIONS OPTIMIZATIONS = 2 !ENDIF # Set this to non-0 to enable support for the session extension. # !IFNDEF SESSION SESSION = 0 !ENDIF # Set this to non-0 to enable support for the rbu extension. # !IFNDEF RBU RBU = 0 !ENDIF # Set the source code file to be used by executables and libraries when # they need the amalgamation. # !IFNDEF SQLITE3C !IF $(SPLIT_AMALGAMATION)!=0 SQLITE3C = sqlite3-all.c |
︙ | ︙ | |||
315 316 317 318 319 320 321 322 323 324 325 326 327 328 | !IFNDEF SQLITETCLH SQLITETCLH = sqlite_tcl.h !ENDIF !IFNDEF SQLITETCLDECLSH SQLITETCLDECLSH = sqlite_tclDecls.h !ENDIF # These are the additional targets that the targets that integrate with the # Tcl library should depend on when compiling, etc. # !IFNDEF SQLITE_TCL_DEP !IF $(USE_STDCALL)!=0 || $(FOR_WIN10)!=0 SQLITE_TCL_DEP = $(SQLITETCLDECLSH) $(SQLITETCLH) | > > > > > > > | 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 | !IFNDEF SQLITETCLH SQLITETCLH = sqlite_tcl.h !ENDIF !IFNDEF SQLITETCLDECLSH SQLITETCLDECLSH = sqlite_tclDecls.h !ENDIF # This is the name to use for the dynamic link library (DLL) containing the # Tcl bindings for SQLite. # !IFNDEF SQLITE3TCLDLL SQLITE3TCLDLL = tclsqlite3.dll !ENDIF # These are the additional targets that the targets that integrate with the # Tcl library should depend on when compiling, etc. # !IFNDEF SQLITE_TCL_DEP !IF $(USE_STDCALL)!=0 || $(FOR_WIN10)!=0 SQLITE_TCL_DEP = $(SQLITETCLDECLSH) $(SQLITETCLH) |
︙ | ︙ | |||
340 341 342 343 344 345 346 | OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_FTS3=1 OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_RTREE=1 OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_GEOPOLY=1 OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_JSON1=1 OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_STMTVTAB=1 OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_DBPAGE_VTAB=1 OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_DBSTAT_VTAB=1 | | < > > > > > > > > > > | 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 | OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_FTS3=1 OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_RTREE=1 OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_GEOPOLY=1 OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_JSON1=1 OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_STMTVTAB=1 OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_DBPAGE_VTAB=1 OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_DBSTAT_VTAB=1 OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_BYTECODE_VTAB=1 !ENDIF OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_COLUMN_METADATA=1 !ENDIF # Should the session extension be enabled? If so, add compilation options # to enable it. # !IF $(SESSION)!=0 OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_SESSION=1 OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_PREUPDATE_HOOK=1 !ENDIF # Always enable math functions on Windows OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_MATH_FUNCTIONS # Should the rbu extension be enabled? If so, add compilation options # to enable it. # !IF $(RBU)!=0 OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_RBU=1 !ENDIF # These are the "extended" SQLite compilation options used when compiling for # the Windows 10 platform. # !IFNDEF EXT_FEATURE_FLAGS !IF $(FOR_WIN10)!=0 EXT_FEATURE_FLAGS = $(EXT_FEATURE_FLAGS) -DSQLITE_ENABLE_FTS4=1 |
︙ | ︙ | |||
491 492 493 494 495 496 497 | UCRTLIBPATH = $(UCRTLIBPATH:\\=\) # C compiler and options for use in building executables that # will run on the platform that is doing the build. # !IF $(USE_FULLWARN)!=0 | | | | 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 | UCRTLIBPATH = $(UCRTLIBPATH:\\=\) # C compiler and options for use in building executables that # will run on the platform that is doing the build. # !IF $(USE_FULLWARN)!=0 BCC = $(NCC) -nologo -W4 -Fd$*.pdb $(CCOPTS) $(BCCOPTS) !ELSE BCC = $(NCC) -nologo -W3 -Fd$*.pdb $(CCOPTS) $(BCCOPTS) !ENDIF # Check if assembly code listings should be generated for the source # code files to be compiled. # !IF $(USE_LISTINGS)!=0 BCC = $(BCC) -FAcs |
︙ | ︙ | |||
752 753 754 755 756 757 758 | MKSQLITE3C_TOOL = $(TOP)\tool\mksqlite3c-noext.tcl !ELSE MKSQLITE3C_TOOL = $(TOP)\tool\mksqlite3c.tcl !ENDIF !ENDIF !IFNDEF MKSQLITE3C_ARGS | | | | | 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 | MKSQLITE3C_TOOL = $(TOP)\tool\mksqlite3c-noext.tcl !ELSE MKSQLITE3C_TOOL = $(TOP)\tool\mksqlite3c.tcl !ENDIF !ENDIF !IFNDEF MKSQLITE3C_ARGS !IF $(DEBUG)>1 && $(NO_LINEMACROS)==0 MKSQLITE3C_ARGS = --linemacros=1 !ELSE MKSQLITE3C_ARGS = --linemacros=0 !ENDIF !IF $(USE_STDCALL)!=0 || $(FOR_WIN10)!=0 MKSQLITE3C_ARGS = $(MKSQLITE3C_ARGS) --useapicall !ENDIF !ENDIF # The mksqlite3h.tcl script accepts some options on the command line. |
︙ | ︙ | |||
849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 | # <<mark>> # The locations of the Tcl header and library files. Also, the library that # non-stubs enabled programs using Tcl must link against. These variables # (TCLINCDIR, TCLLIBDIR, and LIBTCL) may be overridden via the environment # prior to running nmake in order to match the actual installed location and # version on this machine. # !IFNDEF TCLDIR TCLDIR = $(TOP)\compat\tcl !ENDIF !IFNDEF TCLINCDIR TCLINCDIR = $(TCLDIR)\include !ENDIF !IFNDEF TCLLIBDIR TCLLIBDIR = $(TCLDIR)\lib !ENDIF !IFNDEF LIBTCL | > > > > > > > > | | | 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 | # <<mark>> # The locations of the Tcl header and library files. Also, the library that # non-stubs enabled programs using Tcl must link against. These variables # (TCLINCDIR, TCLLIBDIR, and LIBTCL) may be overridden via the environment # prior to running nmake in order to match the actual installed location and # version on this machine. # !IFNDEF TCLVERSION TCLVERSION = 86 !ENDIF !IFNDEF TCLSUFFIX TCLSUFFIX = !ENDIF !IFNDEF TCLDIR TCLDIR = $(TOP)\compat\tcl !ENDIF !IFNDEF TCLINCDIR TCLINCDIR = $(TCLDIR)\include !ENDIF !IFNDEF TCLLIBDIR TCLLIBDIR = $(TCLDIR)\lib !ENDIF !IFNDEF LIBTCL LIBTCL = tcl$(TCLVERSION)$(TCLSUFFIX).lib !ENDIF !IFNDEF LIBTCLSTUB LIBTCLSTUB = tclstub$(TCLVERSION)$(TCLSUFFIX).lib !ENDIF !IFNDEF LIBTCLPATH LIBTCLPATH = $(TCLDIR)\bin !ENDIF # The locations of the zlib header and library files. These variables |
︙ | ︙ | |||
1059 1060 1061 1062 1063 1064 1065 | RCC = $(RCC) -I$(ICUINCDIR) !ENDIF # <</mark>> # Command line prefixes for compiling code, compiling resources, # linking, etc. # | | > > > > > | 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 | RCC = $(RCC) -I$(ICUINCDIR) !ENDIF # <</mark>> # Command line prefixes for compiling code, compiling resources, # linking, etc. # LTCOMPILE = $(TCC) -Fo$@ -Fd$*.pdb LTRCOMPILE = $(RCC) -r LTLIB = lib.exe LTLINK = $(TCC) -Fe$@ # If requested, link to the RPCRT4 library. # !IF $(USE_RPCRT4_LIB)!=0 LTLIBS = $(LTLIBS) rpcrt4.lib !ENDIF # If a platform was set, force the linker to target that. # Note that the vcvars*.bat family of batch files typically # set this for you. Otherwise, the linker will attempt # to deduce the binary type based on the object files. !IFDEF PLATFORM LTLINKOPTS = /NOLOGO /MACHINE:$(PLATFORM) LTLIBOPTS = /NOLOGO /MACHINE:$(PLATFORM) !ELSEIF "$(VISUALSTUDIOVERSION)"=="12.0" || \ "$(VISUALSTUDIOVERSION)"=="14.0" || \ "$(VISUALSTUDIOVERSION)"=="15.0" LTLINKOPTS = /NOLOGO /MACHINE:x86 LTLIBOPTS = /NOLOGO /MACHINE:x86 !ELSE LTLINKOPTS = /NOLOGO LTLIBOPTS = /NOLOGO !ENDIF # When compiling for use in the WinRT environment, the following # linker option must be used to mark the executable as runnable |
︙ | ︙ | |||
1210 1211 1212 1213 1214 1215 1216 | notify.lo opcodes.lo os.lo os_unix.lo os_win.lo \ pager.lo pcache.lo pcache1.lo pragma.lo prepare.lo printf.lo \ random.lo resolve.lo rowset.lo rtree.lo \ sqlite3session.lo select.lo sqlite3rbu.lo status.lo stmt.lo \ table.lo threads.lo tokenize.lo treeview.lo trigger.lo \ update.lo upsert.lo util.lo vacuum.lo \ vdbeapi.lo vdbeaux.lo vdbeblob.lo vdbemem.lo vdbesort.lo \ | | > | 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 | notify.lo opcodes.lo os.lo os_unix.lo os_win.lo \ pager.lo pcache.lo pcache1.lo pragma.lo prepare.lo printf.lo \ random.lo resolve.lo rowset.lo rtree.lo \ sqlite3session.lo select.lo sqlite3rbu.lo status.lo stmt.lo \ table.lo threads.lo tokenize.lo treeview.lo trigger.lo \ update.lo upsert.lo util.lo vacuum.lo \ vdbeapi.lo vdbeaux.lo vdbeblob.lo vdbemem.lo vdbesort.lo \ vdbetrace.lo vdbevtab.lo wal.lo walker.lo where.lo wherecode.lo \ whereexpr.lo \ window.lo utf.lo vtab.lo # <</mark>> # Object files for the amalgamation. # LIBOBJS1 = sqlite3.lo |
︙ | ︙ | |||
1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 | $(TOP)\src\vdbe.c \ $(TOP)\src\vdbeapi.c \ $(TOP)\src\vdbeaux.c \ $(TOP)\src\vdbeblob.c \ $(TOP)\src\vdbemem.c \ $(TOP)\src\vdbesort.c \ $(TOP)\src\vdbetrace.c \ $(TOP)\src\vtab.c \ $(TOP)\src\wal.c \ $(TOP)\src\walker.c \ $(TOP)\src\where.c \ $(TOP)\src\wherecode.c \ $(TOP)\src\whereexpr.c \ $(TOP)\src\window.c | > | 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 | $(TOP)\src\vdbe.c \ $(TOP)\src\vdbeapi.c \ $(TOP)\src\vdbeaux.c \ $(TOP)\src\vdbeblob.c \ $(TOP)\src\vdbemem.c \ $(TOP)\src\vdbesort.c \ $(TOP)\src\vdbetrace.c \ $(TOP)\src\vdbevtab.c \ $(TOP)\src\vtab.c \ $(TOP)\src\wal.c \ $(TOP)\src\walker.c \ $(TOP)\src\where.c \ $(TOP)\src\wherecode.c \ $(TOP)\src\whereexpr.c \ $(TOP)\src\window.c |
︙ | ︙ | |||
1447 1448 1449 1450 1451 1452 1453 | $(SQLITETCLDECLSH) !ELSE SRC12 = !ENDIF # All source code files. # | | | 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 | $(SQLITETCLDECLSH) !ELSE SRC12 = !ENDIF # All source code files. # SRC = $(SRC00) $(SRC01) $(SRC03) $(SRC04) $(SRC05) $(SRC06) $(SRC07) $(SRC08) $(SRC09) $(SRC10) $(SRC11) $(SRC12) # Source code to the test files. # TESTSRC = \ $(TOP)\src\test1.c \ $(TOP)\src\test2.c \ $(TOP)\src\test3.c \ |
︙ | ︙ | |||
1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 | $(TOP)\src\test_schema.c \ $(TOP)\src\test_server.c \ $(TOP)\src\test_superlock.c \ $(TOP)\src\test_syscall.c \ $(TOP)\src\test_tclsh.c \ $(TOP)\src\test_tclvar.c \ $(TOP)\src\test_thread.c \ $(TOP)\src\test_vfs.c \ $(TOP)\src\test_windirent.c \ $(TOP)\src\test_window.c \ $(TOP)\src\test_wsd.c \ $(TOP)\ext\fts3\fts3_term.c \ $(TOP)\ext\fts3\fts3_test.c \ $(TOP)\ext\rbu\test_rbu.c \ | > | > > > > | > > | 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 | $(TOP)\src\test_schema.c \ $(TOP)\src\test_server.c \ $(TOP)\src\test_superlock.c \ $(TOP)\src\test_syscall.c \ $(TOP)\src\test_tclsh.c \ $(TOP)\src\test_tclvar.c \ $(TOP)\src\test_thread.c \ $(TOP)\src\test_vdbecov.c \ $(TOP)\src\test_vfs.c \ $(TOP)\src\test_windirent.c \ $(TOP)\src\test_window.c \ $(TOP)\src\test_wsd.c \ $(TOP)\ext\fts3\fts3_term.c \ $(TOP)\ext\fts3\fts3_test.c \ $(TOP)\ext\rbu\test_rbu.c \ $(TOP)\ext\session\test_session.c # Statically linked extensions. # TESTEXT = \ $(TOP)\ext\expert\sqlite3expert.c \ $(TOP)\ext\expert\test_expert.c \ $(TOP)\ext\misc\amatch.c \ $(TOP)\ext\misc\appendvfs.c \ $(TOP)\ext\misc\carray.c \ $(TOP)\ext\misc\cksumvfs.c \ $(TOP)\ext\misc\closure.c \ $(TOP)\ext\misc\csv.c \ $(TOP)\ext\misc\decimal.c \ $(TOP)\ext\misc\eval.c \ $(TOP)\ext\misc\explain.c \ $(TOP)\ext\misc\fileio.c \ $(TOP)\ext\misc\fuzzer.c \ $(TOP)\ext\fts5\fts5_tcl.c \ $(TOP)\ext\fts5\fts5_test_mi.c \ $(TOP)\ext\fts5\fts5_test_tok.c \ $(TOP)\ext\misc\ieee754.c \ $(TOP)\ext\misc\mmapwarm.c \ $(TOP)\ext\misc\nextchar.c \ $(TOP)\ext\misc\normalize.c \ $(TOP)\ext\misc\percentile.c \ $(TOP)\ext\misc\prefixes.c \ $(TOP)\ext\misc\regexp.c \ $(TOP)\ext\misc\remember.c \ $(TOP)\ext\misc\series.c \ $(TOP)\ext\misc\spellfix.c \ $(TOP)\ext\misc\totype.c \ $(TOP)\ext\misc\unionvtab.c \ $(TOP)\ext\misc\wholenumber.c \ $(TOP)\ext\rtree\test_rtreedoc.c \ fts5.c # If use of zlib is enabled, add the "zipfile.c" source file. # !IF $(USE_ZLIB)!=0 TESTEXT = $(TESTEXT) $(TOP)\ext\misc\zipfile.c !ENDIF |
︙ | ︙ | |||
1621 1622 1623 1624 1625 1626 1627 | FUZZDATA = \ $(TOP)\test\fuzzdata1.db \ $(TOP)\test\fuzzdata2.db \ $(TOP)\test\fuzzdata3.db \ $(TOP)\test\fuzzdata4.db \ $(TOP)\test\fuzzdata5.db \ $(TOP)\test\fuzzdata6.db \ | | > < | > > > > > > > | | 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 | FUZZDATA = \ $(TOP)\test\fuzzdata1.db \ $(TOP)\test\fuzzdata2.db \ $(TOP)\test\fuzzdata3.db \ $(TOP)\test\fuzzdata4.db \ $(TOP)\test\fuzzdata5.db \ $(TOP)\test\fuzzdata6.db \ $(TOP)\test\fuzzdata7.db \ $(TOP)\test\fuzzdata8.db # <</mark>> # Additional compiler options for the shell. These are only effective # when the shell is not being dynamically linked. # !IF $(DYNAMIC_SHELL)==0 && $(FOR_WIN10)==0 SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_FTS4=1 SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_EXPLAIN_COMMENTS=1 SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_OFFSET_SQL_FUNC=1 !ENDIF # <<mark>> # Extra compiler options for various test tools. # MPTESTER_COMPILE_OPTS = -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS5 FUZZERSHELL_COMPILE_OPTS = -DSQLITE_ENABLE_JSON1 FUZZCHECK_OPTS = -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_MEMSYS5 -DSQLITE_OSS_FUZZ -DSQLITE_MAX_MEMORY=50000000 -DSQLITE_PRINTF_PRECISION_LIMIT=1000 FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_FTS4 FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_FTS5 FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_RTREE FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_GEOPOLY FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_DBSTAT_VTAB FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_BYTECODE_VTAB FUZZCHECK_SRC = $(TOP)\test\fuzzcheck.c $(TOP)\test\ossfuzz.c OSSSHELL_SRC = $(TOP)\test\ossshell.c $(TOP)\test\ossfuzz.c DBFUZZ_COMPILE_OPTS = -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION KV_COMPILE_OPTS = -DSQLITE_THREADSAFE=0 -DSQLITE_DIRECT_OVERFLOW_READ ST_COMPILE_OPTS = -DSQLITE_THREADSAFE=0 # Standard options to testfixture. # TESTOPTS = --verbose=file --output=test-out.txt # Extra targets for the "all" target that require Tcl. # !IF $(NO_TCL)==0 ALL_TCL_TARGETS = $(SQLITE3TCLDLL) !ELSE ALL_TCL_TARGETS = !ENDIF # <</mark>> # This is the default Makefile target. The objects listed here # are what get build when you type just "make" with no arguments. |
︙ | ︙ | |||
1685 1686 1687 1688 1689 1690 1691 | shell: $(SQLITE3EXE) # <<mark>> libsqlite3.lib: $(LIBOBJ) $(LTLIB) $(LTLIBOPTS) /OUT:$@ $(LIBOBJ) $(TLIBS) libtclsqlite3.lib: tclsqlite.lo libsqlite3.lib | | > > > > > > > > > > > > > > > | | 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 | shell: $(SQLITE3EXE) # <<mark>> libsqlite3.lib: $(LIBOBJ) $(LTLIB) $(LTLIBOPTS) /OUT:$@ $(LIBOBJ) $(TLIBS) libtclsqlite3.lib: tclsqlite.lo libsqlite3.lib $(LTLIB) $(LTLIBOPTS) $(TCLLIBPATHS) $(LTLIBPATHS) /OUT:$@ tclsqlite.lo libsqlite3.lib $(LIBTCLSTUB) $(TLIBS) tclsqlite3.def: tclsqlite.lo echo EXPORTS > tclsqlite3.def dumpbin /all tclsqlite.lo \ | $(TCLSH_CMD) $(TOP)\tool\replace.tcl include "^\s+/EXPORT:_?((?:Sqlite3|Tclsqlite3)_[^@]*)(?:@\d+)?$$" \1 \ | sort >> tclsqlite3.def pkgIndex.tcl: $(TOP)\VERSION for /F %%V in ('type "$(TOP)\VERSION"') do ( \ echo package ifneeded sqlite3 @version@ [list load [file join $$dir $(SQLITE3TCLDLL)] sqlite3] \ | $(TCLSH_CMD) $(TOP)\tool\replace.tcl exact @version@ %%V > pkgIndex.tcl \ ) $(SQLITE3TCLDLL): libtclsqlite3.lib $(LIBRESOBJS) tclsqlite3.def pkgIndex.tcl $(LD) $(LDFLAGS) $(LTLINKOPTS) $(LTLIBPATHS) /DLL /DEF:tclsqlite3.def /OUT:$@ libtclsqlite3.lib $(LIBRESOBJS) $(LTLIBS) $(TLIBS) # <</mark>> $(SQLITE3DLL): $(LIBOBJ) $(LIBRESOBJS) $(CORE_LINK_DEP) $(LD) $(LDFLAGS) $(LTLINKOPTS) $(LTLIBPATHS) /DLL $(CORE_LINK_OPTS) /OUT:$@ $(LIBOBJ) $(LIBRESOBJS) $(LTLIBS) $(TLIBS) # <<block2>> sqlite3.def: libsqlite3.lib echo EXPORTS > sqlite3.def dumpbin /all libsqlite3.lib \ | $(TCLSH_CMD) $(TOP)\tool\replace.tcl include "^\s+1 _?(sqlite3(?:session|changeset|changegroup|rebaser|rbu)?_[^@]*)(?:@\d+)?$$" \1 \ | sort >> sqlite3.def # <</block2>> $(SQLITE3EXE): shell.c $(SHELL_CORE_DEP) $(LIBRESOBJS) $(SHELL_CORE_SRC) $(SQLITE3H) $(LTLINK) $(SHELL_COMPILE_OPTS) $(READLINE_FLAGS) shell.c $(SHELL_CORE_SRC) \ /link $(SQLITE3EXEPDB) $(LDFLAGS) $(LTLINKOPTS) $(SHELL_LINK_OPTS) $(LTLIBPATHS) $(LIBRESOBJS) $(LIBREADLINE) $(LTLIBS) $(TLIBS) |
︙ | ︙ | |||
1726 1727 1728 1729 1730 1731 1732 | fuzzershell.exe: $(TOP)\tool\fuzzershell.c $(SQLITE3C) $(SQLITE3H) $(LTLINK) $(NO_WARN) $(FUZZERSHELL_COMPILE_OPTS) $(TOP)\tool\fuzzershell.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS) dbfuzz.exe: $(TOP)\test\dbfuzz.c $(SQLITE3C) $(SQLITE3H) $(LTLINK) $(NO_WARN) $(DBFUZZ_COMPILE_OPTS) $(TOP)\test\dbfuzz.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS) fuzzcheck.exe: $(FUZZCHECK_SRC) $(SQLITE3C) $(SQLITE3H) | | | | 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 | fuzzershell.exe: $(TOP)\tool\fuzzershell.c $(SQLITE3C) $(SQLITE3H) $(LTLINK) $(NO_WARN) $(FUZZERSHELL_COMPILE_OPTS) $(TOP)\tool\fuzzershell.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS) dbfuzz.exe: $(TOP)\test\dbfuzz.c $(SQLITE3C) $(SQLITE3H) $(LTLINK) $(NO_WARN) $(DBFUZZ_COMPILE_OPTS) $(TOP)\test\dbfuzz.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS) fuzzcheck.exe: $(FUZZCHECK_SRC) $(SQLITE3C) $(SQLITE3H) $(LTLINK) $(NO_WARN) $(FUZZCHECK_OPTS) $(FUZZCHECK_SRC) $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS) ossshell.exe: $(OSSSHELL_SRC) $(SQLITE3C) $(SQLITE3H) $(LTLINK) $(NO_WARN) $(FUZZCHECK_OPTS) $(OSSSHELL_SRC) $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS) sessionfuzz.exe: zlib $(TOP)\test\sessionfuzz.c $(SQLITE3C) $(SQLITE3H) $(LTLINK) $(NO_WARN) -I$(ZLIBINCDIR) $(TOP)\test\sessionfuzz.c /link $(LDFLAGS) $(LTLINKOPTS) /LIBPATH:$(ZLIBLIBDIR) $(ZLIBLIB) mptester.exe: $(TOP)\mptest\mptest.c $(SQLITE3C) $(SQLITE3H) $(LTLINK) $(NO_WARN) $(MPTESTER_COMPILE_OPTS) $(TOP)\mptest\mptest.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS) |
︙ | ︙ | |||
1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 | for %i in ($(SRC07)) do copy /Y %i tsrc for %i in ($(SRC08)) do copy /Y %i tsrc for %i in ($(SRC09)) do copy /Y %i tsrc for %i in ($(SRC10)) do copy /Y %i tsrc for %i in ($(SRC11)) do copy /Y %i tsrc for %i in ($(SRC12)) do copy /Y %i tsrc copy /Y fts5.c tsrc copy /Y fts5.h tsrc del /Q tsrc\sqlite.h.in tsrc\parse.y 2>NUL $(TCLSH_CMD) $(TOP)\tool\vdbe-compress.tcl $(OPTS) < tsrc\vdbe.c > vdbe.new move vdbe.new tsrc\vdbe.c echo > .target_source | > > | < | > | 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 | for %i in ($(SRC07)) do copy /Y %i tsrc for %i in ($(SRC08)) do copy /Y %i tsrc for %i in ($(SRC09)) do copy /Y %i tsrc for %i in ($(SRC10)) do copy /Y %i tsrc for %i in ($(SRC11)) do copy /Y %i tsrc for %i in ($(SRC12)) do copy /Y %i tsrc copy /Y fts5.c tsrc copy /B tsrc\fts5.c +,, copy /Y fts5.h tsrc copy /B tsrc\fts5.h +,, del /Q tsrc\sqlite.h.in tsrc\parse.y 2>NUL $(TCLSH_CMD) $(TOP)\tool\vdbe-compress.tcl $(OPTS) < tsrc\vdbe.c > vdbe.new move vdbe.new tsrc\vdbe.c echo > .target_source sqlite3.c: .target_source sqlite3ext.h sqlite3session.h $(MKSQLITE3C_TOOL) $(TCLSH_CMD) $(MKSQLITE3C_TOOL) $(MKSQLITE3C_ARGS) sqlite3-all.c: sqlite3.c $(TOP)\tool\split-sqlite3c.tcl $(TCLSH_CMD) $(TOP)\tool\split-sqlite3c.tcl # <</mark>> # Rule to build the amalgamation # sqlite3.lo: $(SQLITE3C) $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(SQLITE3C) # <<mark>> # Rules to build the LEMON compiler generator # lempar.c: $(TOP)\tool\lempar.c copy /Y $(TOP)\tool\lempar.c . copy /B lempar.c +,, lemon.exe: $(TOP)\tool\lemon.c lempar.c $(BCC) $(NO_WARN) -Daccess=_access \ -Fe$@ $(TOP)\tool\lemon.c /link $(LDFLAGS) $(NLTLINKOPTS) $(NLTLIBPATHS) # <<mark>> # Rules to build the source-id generator tool |
︙ | ︙ | |||
1825 1826 1827 1828 1829 1830 1831 | $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c opcodes.c # <</mark>> # Rule to build the Win32 resources object file. # !IF $(USE_RC)!=0 # <<block1>> | | | 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 | $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c opcodes.c # <</mark>> # Rule to build the Win32 resources object file. # !IF $(USE_RC)!=0 # <<block1>> $(LIBRESOBJS): $(TOP)\src\sqlite3.rc $(SQLITE3H) $(TOP)\VERSION echo #ifndef SQLITE_RESOURCE_VERSION > sqlite3rc.h for /F %%V in ('type "$(TOP)\VERSION"') do ( \ echo #define SQLITE_RESOURCE_VERSION %%V \ | $(TCLSH_CMD) $(TOP)\tool\replace.tcl exact . ^, >> sqlite3rc.h \ ) echo #endif >> sqlite3rc.h $(LTRCOMPILE) -fo $(LIBRESOBJS) $(TOP)\src\sqlite3.rc |
︙ | ︙ | |||
2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 | vdbesort.lo: $(TOP)\src\vdbesort.c $(HDR) $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\vdbesort.c vdbetrace.lo: $(TOP)\src\vdbetrace.c $(HDR) $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\vdbetrace.c vtab.lo: $(TOP)\src\vtab.c $(HDR) $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\vtab.c wal.lo: $(TOP)\src\wal.c $(HDR) $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\wal.c walker.lo: $(TOP)\src\walker.c $(HDR) | > > > | 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 | vdbesort.lo: $(TOP)\src\vdbesort.c $(HDR) $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\vdbesort.c vdbetrace.lo: $(TOP)\src\vdbetrace.c $(HDR) $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\vdbetrace.c vdbevtab.lo: $(TOP)\src\vdbevtab.c $(HDR) $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\vdbevtab.c vtab.lo: $(TOP)\src\vtab.c $(HDR) $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\vtab.c wal.lo: $(TOP)\src\wal.c $(HDR) $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\wal.c walker.lo: $(TOP)\src\walker.c $(HDR) |
︙ | ︙ | |||
2091 2092 2093 2094 2095 2096 2097 | opcodes.h: parse.h $(TOP)\src\vdbe.c $(TOP)\tool\mkopcodeh.tcl type parse.h $(TOP)\src\vdbe.c | $(TCLSH_CMD) $(TOP)\tool\mkopcodeh.tcl > opcodes.h # Rules to build parse.c and parse.h - the outputs of lemon. # parse.h: parse.c | | | > | < < > > > > > > | > > > > | > | 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 | opcodes.h: parse.h $(TOP)\src\vdbe.c $(TOP)\tool\mkopcodeh.tcl type parse.h $(TOP)\src\vdbe.c | $(TCLSH_CMD) $(TOP)\tool\mkopcodeh.tcl > opcodes.h # Rules to build parse.c and parse.h - the outputs of lemon. # parse.h: parse.c parse.c: $(TOP)\src\parse.y lemon.exe del /Q parse.y parse.h parse.h.temp 2>NUL copy /Y $(TOP)\src\parse.y . copy /B parse.y +,, .\lemon.exe $(REQ_FEATURE_FLAGS) $(OPT_FEATURE_FLAGS) $(EXT_FEATURE_FLAGS) $(OPTS) -S parse.y $(SQLITE3H): $(TOP)\src\sqlite.h.in $(TOP)\manifest mksourceid.exe $(TOP)\VERSION $(TCLSH_CMD) $(TOP)\tool\mksqlite3h.tcl $(TOP:\=/) > $(SQLITE3H) $(MKSQLITE3H_ARGS) sqlite3ext.h: .target_source !IF $(USE_STDCALL)!=0 || $(FOR_WIN10)!=0 type tsrc\sqlite3ext.h | $(TCLSH_CMD) $(TOP)\tool\replace.tcl regsub "\(\*\)" "(SQLITE_CALLBACK *)" \ | $(TCLSH_CMD) $(TOP)\tool\replace.tcl regsub "\(\*" "(SQLITE_APICALL *" > sqlite3ext.h copy /Y sqlite3ext.h tsrc\sqlite3ext.h !ELSE copy /Y tsrc\sqlite3ext.h sqlite3ext.h copy /B sqlite3ext.h +,, !ENDIF sqlite3session.h: $(TOP)\ext\session\sqlite3session.h copy /Y $(TOP)\ext\session\sqlite3session.h . copy /B sqlite3session.h +,, mkkeywordhash.exe: $(TOP)\tool\mkkeywordhash.c $(BCC) $(NO_WARN) -Fe$@ $(REQ_FEATURE_FLAGS) $(OPT_FEATURE_FLAGS) $(EXT_FEATURE_FLAGS) $(OPTS) \ $(TOP)\tool\mkkeywordhash.c /link $(LDFLAGS) $(NLTLINKOPTS) $(NLTLIBPATHS) keywordhash.h: $(TOP)\tool\mkkeywordhash.c mkkeywordhash.exe .\mkkeywordhash.exe > keywordhash.h # Source files that go into making shell.c SHELL_SRC = \ $(TOP)\src\shell.c.in \ $(TOP)\ext\misc\appendvfs.c \ $(TOP)\ext\misc\completion.c \ $(TOP)\ext\misc\decimal.c \ $(TOP)\ext\misc\fileio.c \ $(TOP)\ext\misc\ieee754.c \ $(TOP)\ext\misc\regexp.c \ $(TOP)\ext\misc\series.c \ $(TOP)\ext\misc\shathree.c \ $(TOP)\ext\misc\uint.c \ $(TOP)\ext\expert\sqlite3expert.c \ $(TOP)\ext\expert\sqlite3expert.h \ $(TOP)\ext\misc\memtrace.c \ $(TOP)\src\test_windirent.c # If use of zlib is enabled, add the "zipfile.c" source file. # !IF $(USE_ZLIB)!=0 SHELL_SRC = $(SHELL_SRC) $(TOP)\ext\misc\sqlar.c SHELL_SRC = $(SHELL_SRC) $(TOP)\ext\misc\zipfile.c |
︙ | ︙ | |||
2253 2254 2255 2256 2257 2258 2259 | $(TOP)\ext\lsm1\lsm_tree.c \ $(TOP)\ext\lsm1\lsm_unix.c \ $(TOP)\ext\lsm1\lsm_varint.c \ $(TOP)\ext\lsm1\lsm_vtab.c \ $(TOP)\ext\lsm1\lsm_win32.c fts5parse.c: $(TOP)\ext\fts5\fts5parse.y lemon.exe | | > | | > | > | 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 | $(TOP)\ext\lsm1\lsm_tree.c \ $(TOP)\ext\lsm1\lsm_unix.c \ $(TOP)\ext\lsm1\lsm_varint.c \ $(TOP)\ext\lsm1\lsm_vtab.c \ $(TOP)\ext\lsm1\lsm_win32.c fts5parse.c: $(TOP)\ext\fts5\fts5parse.y lemon.exe copy /Y $(TOP)\ext\fts5\fts5parse.y . copy /B fts5parse.y +,, del /Q fts5parse.h 2>NUL .\lemon.exe $(REQ_FEATURE_FLAGS) $(OPT_FEATURE_FLAGS) $(EXT_FEATURE_FLAGS) $(OPTS) -S fts5parse.y fts5parse.h: fts5parse.c fts5.c: $(FTS5_SRC) $(TCLSH_CMD) $(TOP)\ext\fts5\tool\mkfts5c.tcl copy /Y $(TOP)\ext\fts5\fts5.h . copy /B fts5.h +,, lsm1.c: $(LSM1_SRC) $(TCLSH_CMD) $(TOP)\ext\lsm1\tool\mklsm1c.tcl copy /Y $(TOP)\ext\lsm1\lsm.h . copy /B lsm.h +,, fts5.lo: fts5.c $(HDR) $(EXTHDR) $(LTCOMPILE) $(CORE_COMPILE_OPTS) $(NO_WARN) -DSQLITE_CORE -c fts5.c fts5_ext.lo: fts5.c $(HDR) $(EXTHDR) $(LTCOMPILE) $(NO_WARN) -c fts5.c |
︙ | ︙ | |||
2293 2294 2295 2296 2297 2298 2299 2300 | TESTFIXTURE_FLAGS = -DTCLSH_INIT_PROC=sqlite3TestInit -DSQLITE_TEST=1 -DSQLITE_CRASH_TEST=1 TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_SERVER=1 -DSQLITE_PRIVATE="" TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_CORE $(NO_WARN) TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_SERIES_CONSTRAINT_VERIFY=1 TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_DEFAULT_PAGE_SIZE=1024 TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_ENABLE_STMTVTAB=1 TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_ENABLE_DBPAGE_VTAB=1 TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_ENABLE_JSON1=1 | > | | 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 | TESTFIXTURE_FLAGS = -DTCLSH_INIT_PROC=sqlite3TestInit -DSQLITE_TEST=1 -DSQLITE_CRASH_TEST=1 TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_SERVER=1 -DSQLITE_PRIVATE="" TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_CORE $(NO_WARN) TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_SERIES_CONSTRAINT_VERIFY=1 TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_DEFAULT_PAGE_SIZE=1024 TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_ENABLE_STMTVTAB=1 TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_ENABLE_DBPAGE_VTAB=1 TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_ENABLE_BYTECODE_VTAB=1 TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_ENABLE_JSON1=1 TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_CKSUMVFS_STATIC=1 TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) $(TEST_CCONV_OPTS) TESTFIXTURE_SRC0 = $(TESTEXT) $(TESTSRC2) TESTFIXTURE_SRC1 = $(TESTEXT) $(SQLITE3C) !IF $(USE_AMALGAMATION)==0 TESTFIXTURE_SRC = $(TESTSRC) $(TOP)\src\tclsqlite.c $(TESTFIXTURE_SRC0) !ELSE |
︙ | ︙ | |||
2339 2340 2341 2342 2343 2344 2345 | @set PATH=$(LIBTCLPATH);$(PATH) .\testfixture.exe $(TOP)\test\loadext.test $(TESTOPTS) coretestprogs: $(TESTPROGS) testprogs: coretestprogs srcck1.exe fuzzcheck.exe sessionfuzz.exe | > > | < < < | > > > > > > > | 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 | @set PATH=$(LIBTCLPATH);$(PATH) .\testfixture.exe $(TOP)\test\loadext.test $(TESTOPTS) coretestprogs: $(TESTPROGS) testprogs: coretestprogs srcck1.exe fuzzcheck.exe sessionfuzz.exe fulltest: alltest fuzztest alltest: $(TESTPROGS) @set PATH=$(LIBTCLPATH);$(PATH) .\testfixture.exe $(TOP)\test\all.test $(TESTOPTS) soaktest: $(TESTPROGS) @set PATH=$(LIBTCLPATH);$(PATH) .\testfixture.exe $(TOP)\test\all.test -soak=1 $(TESTOPTS) fulltestonly: $(TESTPROGS) fuzztest @set PATH=$(LIBTCLPATH);$(PATH) .\testfixture.exe $(TOP)\test\full.test queryplantest: testfixture.exe shell @set PATH=$(LIBTCLPATH);$(PATH) .\testfixture.exe $(TOP)\test\permutations.test queryplanner $(TESTOPTS) fuzztest: fuzzcheck.exe .\fuzzcheck.exe $(FUZZDATA) # Minimal testing that runs in less than 3 minutes (on a fast machine) # quicktest: testfixture.exe sourcetest @set PATH=$(LIBTCLPATH);$(PATH) .\testfixture.exe $(TOP)\test\extraquick.test $(TESTOPTS) # This is the common case. Run many tests that do not take too long, # including fuzzcheck, sqlite3_analyzer, and sqldiff tests. # test: $(TESTPROGS) sourcetest fuzztest tcltest # The veryquick.test TCL tests. # tcltest: testfixture.exe @set PATH=$(LIBTCLPATH);$(PATH) .\testfixture.exe $(TOP)\test\veryquick.test $(TESTOPTS) smoketest: $(TESTPROGS) @set PATH=$(LIBTCLPATH);$(PATH) .\testfixture.exe $(TOP)\test\main.test $(TESTOPTS) shelltest: $(TESTPROGS) .\testfixture.exe $(TOP)\test\permutations.test shell sqlite3_analyzer.c: $(SQLITE3C) $(SQLITE3H) $(TOP)\src\tclsqlite.c $(TOP)\tool\spaceanal.tcl $(TOP)\tool\mkccode.tcl $(TOP)\tool\sqlite3_analyzer.c.in $(SQLITE_TCL_DEP) $(TCLSH_CMD) $(TOP)\tool\mkccode.tcl $(TOP)\tool\sqlite3_analyzer.c.in > $@ sqlite3_analyzer.exe: sqlite3_analyzer.c $(LIBRESOBJS) $(LTLINK) $(NO_WARN) -DBUILD_sqlite -I$(TCLINCDIR) sqlite3_analyzer.c \ /link $(LDFLAGS) $(LTLINKOPTS) $(TCLLIBPATHS) $(LTLIBPATHS) $(LIBRESOBJS) $(TCLLIBS) $(LTLIBS) $(TLIBS) |
︙ | ︙ | |||
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 | $(LTLINK) $(NO_WARN) $(KV_COMPILE_OPTS) \ $(TOP)\test\kvtest.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS) rbu.exe: $(TOP)\ext\rbu\rbu.c $(TOP)\ext\rbu\sqlite3rbu.c $(SQLITE3C) $(SQLITE3H) $(LTLINK) $(NO_WARN) -DSQLITE_ENABLE_RBU \ $(TOP)\ext\rbu\rbu.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS) LSMDIR=$(TOP)\ext\lsm1 !INCLUDE $(LSMDIR)\Makefile.msc moreclean: clean del /Q $(SQLITE3C) $(SQLITE3H) 2>NUL # <</mark>> clean: del /Q *.exp *.lo *.ilk *.lib *.obj *.ncb *.pdb *.sdf *.suo 2>NUL del /Q *.bsc *.def *.cod *.da *.bb *.bbg *.vc gmon.out 2>NUL del /Q $(SQLITE3EXE) $(SQLITE3DLL) Replace.exe 2>NUL # <<mark>> del /Q opcodes.c opcodes.h 2>NUL del /Q lemon.* lempar.c parse.* 2>NUL del /Q mksourceid.* mkkeywordhash.* keywordhash.h 2>NUL del /Q notasharedlib.* 2>NUL -rmdir /Q/S .deps 2>NUL -rmdir /Q/S .libs 2>NUL -rmdir /Q/S tsrc 2>NUL del /Q .target_source 2>NUL del /Q tclsqlite3.exe $(SQLITETCLH) $(SQLITETCLDECLSH) 2>NUL del /Q lsm.dll lsmtest.exe 2>NUL del /Q testloadext.dll 2>NUL del /Q testfixture.exe test.db 2>NUL del /Q LogEst.exe fts3view.exe rollback-test.exe showdb.exe dbdump.exe 2>NUL del /Q changeset.exe 2>NUL del /Q showjournal.exe showstat4.exe showwal.exe speedtest1.exe 2>NUL del /Q mptester.exe wordcount.exe rbu.exe srcck1.exe 2>NUL del /Q sqlite3.c sqlite3-*.c sqlite3.h 2>NUL del /Q sqlite3rc.h 2>NUL del /Q shell.c sqlite3ext.h sqlite3session.h 2>NUL del /Q sqlite3_analyzer.exe sqlite3_analyzer.c 2>NUL del /Q sqlite-*-output.vsix 2>NUL del /Q fuzzershell.exe fuzzcheck.exe sqldiff.exe dbhash.exe 2>NUL del /Q sqltclsh.* 2>NUL | > > > > > > > > > > > > > | | 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 | $(LTLINK) $(NO_WARN) $(KV_COMPILE_OPTS) \ $(TOP)\test\kvtest.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS) rbu.exe: $(TOP)\ext\rbu\rbu.c $(TOP)\ext\rbu\sqlite3rbu.c $(SQLITE3C) $(SQLITE3H) $(LTLINK) $(NO_WARN) -DSQLITE_ENABLE_RBU \ $(TOP)\ext\rbu\rbu.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS) THREADTEST3_SRC = \ $(TOP)\test\threadtest3.c \ $(TOP)\test\tt3_checkpoint.c \ $(TOP)\test\tt3_index.c \ $(TOP)\test\tt3_vacuum.c \ $(TOP)\test\tt3_stress.c \ $(TOP)\test\tt3_lookaside1.c threadtest3.exe: $(THREADTEST3_SRC) $(TOP)\src\test_multiplex.c $(SQLITE3C) $(SQLITE3H) $(LTLINK) $(NO_WARN) $(TOP)\test\threadtest3.c $(TOP)\src\test_multiplex.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS) LSMDIR=$(TOP)\ext\lsm1 !INCLUDE $(LSMDIR)\Makefile.msc moreclean: clean del /Q $(SQLITE3C) $(SQLITE3H) 2>NUL # <</mark>> clean: del /Q *.exp *.lo *.ilk *.lib *.obj *.ncb *.pdb *.sdf *.suo 2>NUL del /Q *.bsc *.def *.cod *.da *.bb *.bbg *.vc gmon.out 2>NUL del /Q $(SQLITE3EXE) $(SQLITE3DLL) Replace.exe 2>NUL # <<mark>> del /Q $(SQLITE3TCLDLL) pkgIndex.tcl 2>NUL del /Q opcodes.c opcodes.h 2>NUL del /Q lemon.* lempar.c parse.* 2>NUL del /Q mksourceid.* mkkeywordhash.* keywordhash.h 2>NUL del /Q notasharedlib.* 2>NUL -rmdir /Q/S .deps 2>NUL -rmdir /Q/S .libs 2>NUL -rmdir /Q/S tsrc 2>NUL del /Q .target_source 2>NUL del /Q tclsqlite3.exe $(SQLITETCLH) $(SQLITETCLDECLSH) 2>NUL del /Q lsm.dll lsmtest.exe 2>NUL del /Q atrc.exe changesetfuzz.exe dbtotxt.exe index_usage.exe 2>NUL del /Q testloadext.dll 2>NUL del /Q testfixture.exe test.db 2>NUL del /Q LogEst.exe fts3view.exe rollback-test.exe showdb.exe dbdump.exe 2>NUL del /Q changeset.exe 2>NUL del /Q showjournal.exe showstat4.exe showwal.exe speedtest1.exe 2>NUL del /Q mptester.exe wordcount.exe rbu.exe srcck1.exe 2>NUL del /Q sqlite3.c sqlite3-*.c sqlite3.h 2>NUL del /Q sqlite3rc.h 2>NUL del /Q shell.c sqlite3ext.h sqlite3session.h 2>NUL del /Q sqlite3_analyzer.exe sqlite3_analyzer.c 2>NUL del /Q sqlite-*-output.vsix 2>NUL del /Q fuzzershell.exe fuzzcheck.exe sqldiff.exe dbhash.exe 2>NUL del /Q sqltclsh.* 2>NUL del /Q dbfuzz.exe sessionfuzz.exe threadtest3.exe 2>NUL del /Q kvtest.exe ossshell.exe scrub.exe 2>NUL del /Q showshm.exe sqlite3_checker.* sqlite3_expert.exe 2>NUL del /Q fts5.* fts5parse.* 2>NUL del /Q lsm.h lsm1.c 2>NUL # <</mark>> |
Changes to README.md.
1 2 3 4 5 6 7 | <h1 align="center">SQLite Source Repository</h1> This repository contains the complete source code for the [SQLite database engine](https://sqlite.org/). Some test scripts are also included. However, many other test scripts and most of the documentation are managed separately. | > | > > > > > | > > > > | > > | > > > < < < | | | | | | | 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 | <h1 align="center">SQLite Source Repository</h1> This repository contains the complete source code for the [SQLite database engine](https://sqlite.org/). Some test scripts are also included. However, many other test scripts and most of the documentation are managed separately. ## Version Control SQLite sources are managed using the [Fossil](https://www.fossil-scm.org/), a distributed version control system that was specifically designed and written to support SQLite development. The [Fossil repository](https://sqlite.org/src/timeline) contains the urtext. If you are reading this on GitHub or some other Git repository or service, then you are looking at a mirror. The names of check-ins and other artifacts in a Git mirror are different from the official names for those objects. The offical names for check-ins are found in a footer on the check-in comment for authorized mirrors. The official check-in name can also be seen in the `manifest.uuid` file in the root of the tree. Always use the official name, not the Git-name, when communicating about an SQLite check-in. If you pulled your SQLite source code from a secondary source and want to verify its integrity, there are hints on how to do that in the [Verifying Code Authenticity](#vauth) section below. ## Obtaining The Code If you do not want to use Fossil, you can download tarballs or ZIP archives or [SQLite archives](https://sqlite.org/cli.html#sqlar) as follows: * Lastest trunk check-in as [Tarball](https://www.sqlite.org/src/tarball/sqlite.tar.gz), [ZIP-archive](https://www.sqlite.org/src/zip/sqlite.zip), or [SQLite-archive](https://www.sqlite.org/src/sqlar/sqlite.sqlar). * Latest release as [Tarball](https://www.sqlite.org/src/tarball/sqlite.tar.gz?r=release), [ZIP-archive](https://www.sqlite.org/src/zip/sqlite.zip?r=release), or [SQLite-archive](https://www.sqlite.org/src/sqlar/sqlite.sqlar?r=release). * For other check-ins, substitute an appropriate branch name or tag or hash prefix in place of "release" in the URLs of the previous bullet. Or browse the [timeline](https://www.sqlite.org/src/timeline) to locate the check-in desired, click on its information page link, then click on the "Tarball" or "ZIP Archive" links on the information page. If you do want to use Fossil to check out the source tree, first install Fossil version 2.0 or later. (Source tarballs and precompiled binaries available [here](https://www.fossil-scm.org/fossil/uv/download.html). Fossil is a stand-alone program. To install, simply download or build the single executable file and put that file someplace on your $PATH.) Then run commands like this: mkdir -p ~/sqlite ~/Fossils cd ~/sqlite fossil clone https://www.sqlite.org/src ~/Fossils/sqlite.fossil fossil open ~/Fossils/sqlite.fossil After setting up a repository using the steps above, you can always update to the lastest version using: fossil update trunk ;# latest trunk check-in fossil update release ;# latest official release Or type "fossil ui" to get a web-based user interface. ## Compiling for Unix-like systems First create a directory in which to place the build products. It is recommended, but not required, that the build directory be separate from the source directory. Cd into the build directory and then from the build directory run the configure script found at the root of the source tree. Then run "make". |
︙ | ︙ | |||
78 79 80 81 82 83 84 | The configure script uses autoconf 2.61 and libtool. If the configure script does not work out for you, there is a generic makefile named "Makefile.linux-gcc" in the top directory of the source tree that you can copy and edit to suit your needs. Comments on the generic makefile show what changes are needed. | | | | | | | | | 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 | The configure script uses autoconf 2.61 and libtool. If the configure script does not work out for you, there is a generic makefile named "Makefile.linux-gcc" in the top directory of the source tree that you can copy and edit to suit your needs. Comments on the generic makefile show what changes are needed. ## Using MSVC for Windows systems On Windows, all applicable build products can be compiled with MSVC. First open the command prompt window associated with the desired compiler version (e.g. "Developer Command Prompt for VS2013"). Next, use NMAKE with the provided "Makefile.msc" to build one of the supported targets. For example, from the parent directory of the source subtree named "sqlite": mkdir bld cd bld nmake /f ..\sqlite\Makefile.msc TOP=..\sqlite nmake /f ..\sqlite\Makefile.msc sqlite3.c TOP=..\sqlite nmake /f ..\sqlite\Makefile.msc sqlite3.dll TOP=..\sqlite nmake /f ..\sqlite\Makefile.msc sqlite3.exe TOP=..\sqlite nmake /f ..\sqlite\Makefile.msc test TOP=..\sqlite There are several build options that can be set via the NMAKE command line. For example, to build for WinRT, simply add "FOR_WINRT=1" argument to the "sqlite3.dll" command line above. When debugging into the SQLite code, adding the "DEBUG=1" argument to one of the above command lines is recommended. |
︙ | ︙ | |||
159 160 161 162 163 164 165 | used to generate that documentation are in a separate source repository. The SQL language parser is **parse.c** which is generate from a grammar in the src/parse.y file. The conversion of "parse.y" into "parse.c" is done by the [lemon](./doc/lemon.html) LALR(1) parser generator. The source code for lemon is at tool/lemon.c. Lemon uses the tool/lempar.c file as a template for generating its parser. | < | < < | 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 | used to generate that documentation are in a separate source repository. The SQL language parser is **parse.c** which is generate from a grammar in the src/parse.y file. The conversion of "parse.y" into "parse.c" is done by the [lemon](./doc/lemon.html) LALR(1) parser generator. The source code for lemon is at tool/lemon.c. Lemon uses the tool/lempar.c file as a template for generating its parser. Lemon also generates the **parse.h** header file, at the same time it generates parse.c. The **opcodes.h** header file contains macros that define the numbers corresponding to opcodes in the "VDBE" virtual machine. The opcodes.h file is generated by the scanning the src/vdbe.c source file. The Tcl script at ./mkopcodeh.tcl does this scan and generates opcodes.h. A second Tcl script, ./mkopcodec.tcl, then scans opcodes.h to generate the **opcodes.c** source file, which contains a reverse mapping from |
︙ | ︙ | |||
290 291 292 293 294 295 296 297 298 299 | * **ext/misc/json1.c** - This file implements the various JSON functions that are build into SQLite. There are many other source files. Each has a succinct header comment that describes its purpose and role within the larger system. ## Contacts | > > > > > > > > > > > > > > > | | 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 | * **ext/misc/json1.c** - This file implements the various JSON functions that are build into SQLite. There are many other source files. Each has a succinct header comment that describes its purpose and role within the larger system. <a name="vauth"></a> ## Verifying Code Authenticity The `manifest` file at the root directory of the source tree contains either a SHA3-256 hash (for newer files) or a SHA1 hash (for older files) for every source file in the repository. The SHA3-256 hash of the `manifest` file itself is the official name of the version of the source tree that you have. The `manifest.uuid` file should contain the SHA3-256 hash of the `manifest` file. If all of the above hash comparisons are correct, then you can be confident that your source tree is authentic and unadulterated. The format of the `manifest` file should be mostly self-explanatory, but if you want details, they are available [here](https://fossil-scm.org/fossil/doc/trunk/www/fileformat.wiki#manifest). ## Contacts The main SQLite website is [http://www.sqlite.org/](http://www.sqlite.org/) with geographically distributed backups at [http://www2.sqlite.org/](http://www2.sqlite.org) and [http://www3.sqlite.org/](http://www3.sqlite.org). |
Changes to VERSION.
|
| | | 1 | 3.37.0 |
Changes to autoconf/Makefile.am.
︙ | ︙ | |||
9 10 11 12 13 14 15 | EXTRA_sqlite3_SOURCES = sqlite3.c sqlite3_LDADD = @EXTRA_SHELL_OBJ@ @READLINE_LIBS@ sqlite3_DEPENDENCIES = @EXTRA_SHELL_OBJ@ sqlite3_CFLAGS = $(AM_CFLAGS) -DSQLITE_ENABLE_EXPLAIN_COMMENTS -DSQLITE_ENABLE_DBPAGE_VTAB -DSQLITE_ENABLE_STMTVTAB -DSQLITE_ENABLE_DBSTAT_VTAB $(SHELL_CFLAGS) include_HEADERS = sqlite3.h sqlite3ext.h | | | 9 10 11 12 13 14 15 16 17 18 19 20 | EXTRA_sqlite3_SOURCES = sqlite3.c sqlite3_LDADD = @EXTRA_SHELL_OBJ@ @READLINE_LIBS@ sqlite3_DEPENDENCIES = @EXTRA_SHELL_OBJ@ sqlite3_CFLAGS = $(AM_CFLAGS) -DSQLITE_ENABLE_EXPLAIN_COMMENTS -DSQLITE_ENABLE_DBPAGE_VTAB -DSQLITE_ENABLE_STMTVTAB -DSQLITE_ENABLE_DBSTAT_VTAB $(SHELL_CFLAGS) include_HEADERS = sqlite3.h sqlite3ext.h EXTRA_DIST = sqlite3.1 tea Makefile.msc sqlite3.rc sqlite3rc.h README.txt Replace.cs Makefile.fallback pkgconfigdir = ${libdir}/pkgconfig pkgconfig_DATA = sqlite3.pc man_MANS = sqlite3.1 |
Changes to autoconf/Makefile.msc.
︙ | ︙ | |||
69 70 71 72 73 74 75 | # If necessary, create a list of harmless compiler warnings to disable when # compiling the various tools. For the SQLite source code itself, warnings, # if any, will be disabled from within it. # !IFNDEF NO_WARN !IF $(USE_FULLWARN)!=0 NO_WARN = -wd4054 -wd4055 -wd4100 -wd4127 -wd4130 -wd4152 -wd4189 -wd4206 | | | 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | # If necessary, create a list of harmless compiler warnings to disable when # compiling the various tools. For the SQLite source code itself, warnings, # if any, will be disabled from within it. # !IFNDEF NO_WARN !IF $(USE_FULLWARN)!=0 NO_WARN = -wd4054 -wd4055 -wd4100 -wd4127 -wd4130 -wd4152 -wd4189 -wd4206 NO_WARN = $(NO_WARN) -wd4210 -wd4232 -wd4244 -wd4305 -wd4306 -wd4702 -wd4706 !ENDIF !ENDIF # Set this non-0 to use the library paths and other options necessary for # Windows Phone 8.1. # !IFNDEF USE_WP81_OPTS |
︙ | ︙ | |||
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 | # 4 == SQLITE_WIN32_MALLOC_VALIDATE: Validate the Win32 native heap per call. # 5 == SQLITE_DEBUG_OS_TRACE: Enables output from the OSTRACE() macros. # 6 == SQLITE_ENABLE_IOTRACE: Enables output from the IOTRACE() macros. # !IFNDEF DEBUG DEBUG = 0 !ENDIF # Enable use of available compiler optimizations? Normally, this should be # non-zero. Setting this to zero, thus disabling all compiler optimizations, # can be useful for testing. # !IFNDEF OPTIMIZATIONS OPTIMIZATIONS = 2 !ENDIF # Set this to non-0 to enable support for the session extension. # !IFNDEF SESSION SESSION = 0 !ENDIF # Set the source code file to be used by executables and libraries when # they need the amalgamation. # !IFNDEF SQLITE3C !IF $(SPLIT_AMALGAMATION)!=0 SQLITE3C = sqlite3-all.c | > > > > > > > | 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 | # 4 == SQLITE_WIN32_MALLOC_VALIDATE: Validate the Win32 native heap per call. # 5 == SQLITE_DEBUG_OS_TRACE: Enables output from the OSTRACE() macros. # 6 == SQLITE_ENABLE_IOTRACE: Enables output from the IOTRACE() macros. # !IFNDEF DEBUG DEBUG = 0 !ENDIF # Enable use of available compiler optimizations? Normally, this should be # non-zero. Setting this to zero, thus disabling all compiler optimizations, # can be useful for testing. # !IFNDEF OPTIMIZATIONS OPTIMIZATIONS = 2 !ENDIF # Set this to non-0 to enable support for the session extension. # !IFNDEF SESSION SESSION = 0 !ENDIF # Set this to non-0 to enable support for the rbu extension. # !IFNDEF RBU RBU = 0 !ENDIF # Set the source code file to be used by executables and libraries when # they need the amalgamation. # !IFNDEF SQLITE3C !IF $(SPLIT_AMALGAMATION)!=0 SQLITE3C = sqlite3-all.c |
︙ | ︙ | |||
278 279 280 281 282 283 284 | OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_FTS3=1 OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_RTREE=1 OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_GEOPOLY=1 OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_JSON1=1 OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_STMTVTAB=1 OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_DBPAGE_VTAB=1 OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_DBSTAT_VTAB=1 | | < > > > > > > > > > > | 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 | OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_FTS3=1 OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_RTREE=1 OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_GEOPOLY=1 OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_JSON1=1 OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_STMTVTAB=1 OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_DBPAGE_VTAB=1 OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_DBSTAT_VTAB=1 OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_BYTECODE_VTAB=1 !ENDIF OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_COLUMN_METADATA=1 !ENDIF # Should the session extension be enabled? If so, add compilation options # to enable it. # !IF $(SESSION)!=0 OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_SESSION=1 OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_PREUPDATE_HOOK=1 !ENDIF # Always enable math functions on Windows OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_MATH_FUNCTIONS # Should the rbu extension be enabled? If so, add compilation options # to enable it. # !IF $(RBU)!=0 OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_RBU=1 !ENDIF # These are the "extended" SQLite compilation options used when compiling for # the Windows 10 platform. # !IFNDEF EXT_FEATURE_FLAGS !IF $(FOR_WIN10)!=0 EXT_FEATURE_FLAGS = $(EXT_FEATURE_FLAGS) -DSQLITE_ENABLE_FTS4=1 |
︙ | ︙ | |||
429 430 431 432 433 434 435 | UCRTLIBPATH = $(UCRTLIBPATH:\\=\) # C compiler and options for use in building executables that # will run on the platform that is doing the build. # !IF $(USE_FULLWARN)!=0 | | | | 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 | UCRTLIBPATH = $(UCRTLIBPATH:\\=\) # C compiler and options for use in building executables that # will run on the platform that is doing the build. # !IF $(USE_FULLWARN)!=0 BCC = $(NCC) -nologo -W4 -Fd$*.pdb $(CCOPTS) $(BCCOPTS) !ELSE BCC = $(NCC) -nologo -W3 -Fd$*.pdb $(CCOPTS) $(BCCOPTS) !ENDIF # Check if assembly code listings should be generated for the source # code files to be compiled. # !IF $(USE_LISTINGS)!=0 BCC = $(BCC) -FAcs |
︙ | ︙ | |||
804 805 806 807 808 809 810 | BCC = $(BCC) -Zi !ENDIF # Command line prefixes for compiling code, compiling resources, # linking, etc. # | | > > > > > | 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 | BCC = $(BCC) -Zi !ENDIF # Command line prefixes for compiling code, compiling resources, # linking, etc. # LTCOMPILE = $(TCC) -Fo$@ -Fd$*.pdb LTRCOMPILE = $(RCC) -r LTLIB = lib.exe LTLINK = $(TCC) -Fe$@ # If requested, link to the RPCRT4 library. # !IF $(USE_RPCRT4_LIB)!=0 LTLIBS = $(LTLIBS) rpcrt4.lib !ENDIF # If a platform was set, force the linker to target that. # Note that the vcvars*.bat family of batch files typically # set this for you. Otherwise, the linker will attempt # to deduce the binary type based on the object files. !IFDEF PLATFORM LTLINKOPTS = /NOLOGO /MACHINE:$(PLATFORM) LTLIBOPTS = /NOLOGO /MACHINE:$(PLATFORM) !ELSEIF "$(VISUALSTUDIOVERSION)"=="12.0" || \ "$(VISUALSTUDIOVERSION)"=="14.0" || \ "$(VISUALSTUDIOVERSION)"=="15.0" LTLINKOPTS = /NOLOGO /MACHINE:x86 LTLIBOPTS = /NOLOGO /MACHINE:x86 !ELSE LTLINKOPTS = /NOLOGO LTLIBOPTS = /NOLOGO !ENDIF # When compiling for use in the WinRT environment, the following # linker option must be used to mark the executable as runnable |
︙ | ︙ | |||
934 935 936 937 938 939 940 | # Additional compiler options for the shell. These are only effective # when the shell is not being dynamically linked. # !IF $(DYNAMIC_SHELL)==0 && $(FOR_WIN10)==0 SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_FTS4=1 SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_EXPLAIN_COMMENTS=1 SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_OFFSET_SQL_FUNC=1 | < | 955 956 957 958 959 960 961 962 963 964 965 966 967 968 | # Additional compiler options for the shell. These are only effective # when the shell is not being dynamically linked. # !IF $(DYNAMIC_SHELL)==0 && $(FOR_WIN10)==0 SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_FTS4=1 SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_EXPLAIN_COMMENTS=1 SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_OFFSET_SQL_FUNC=1 !ENDIF # This is the default Makefile target. The objects listed here # are what get build when you type just "make" with no arguments. # core: dll shell |
︙ | ︙ | |||
969 970 971 972 973 974 975 | Replace.exe: $(CSC) /target:exe $(TOP)\Replace.cs sqlite3.def: Replace.exe $(LIBOBJ) echo EXPORTS > sqlite3.def dumpbin /all $(LIBOBJ) \ | | | 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 | Replace.exe: $(CSC) /target:exe $(TOP)\Replace.cs sqlite3.def: Replace.exe $(LIBOBJ) echo EXPORTS > sqlite3.def dumpbin /all $(LIBOBJ) \ | .\Replace.exe "^\s+/EXPORT:_?(sqlite3(?:session|changeset|changegroup|rebaser|rbu)?_[^@,]*)(?:@\d+|,DATA)?$$" $$1 true \ | sort >> sqlite3.def $(SQLITE3EXE): shell.c $(SHELL_CORE_DEP) $(LIBRESOBJS) $(SHELL_CORE_SRC) $(SQLITE3H) $(LTLINK) $(SHELL_COMPILE_OPTS) $(READLINE_FLAGS) shell.c $(SHELL_CORE_SRC) \ /link $(SQLITE3EXEPDB) $(LDFLAGS) $(LTLINKOPTS) $(SHELL_LINK_OPTS) $(LTLIBPATHS) $(LIBRESOBJS) $(LIBREADLINE) $(LTLIBS) $(TLIBS) |
︙ | ︙ |
Changes to autoconf/configure.ac.
︙ | ︙ | |||
83 84 85 86 87 88 89 | #----------------------------------------------------------------------- # --enable-threadsafe # AC_ARG_ENABLE(threadsafe, [AS_HELP_STRING( [--enable-threadsafe], [build a thread-safe library [default=yes]])], [], [enable_threadsafe=yes]) | | > > | 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 | #----------------------------------------------------------------------- # --enable-threadsafe # AC_ARG_ENABLE(threadsafe, [AS_HELP_STRING( [--enable-threadsafe], [build a thread-safe library [default=yes]])], [], [enable_threadsafe=yes]) if test x"$enable_threadsafe" == "xno"; then BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_THREADSAFE=0" else BUILD_CFLAGS="$BUILD_CFLAGS -D_REENTRANT=1 -DSQLITE_THREADSAFE=1" AC_SEARCH_LIBS(pthread_create, pthread) AC_SEARCH_LIBS(pthread_mutexattr_init, pthread) fi #----------------------------------------------------------------------- #----------------------------------------------------------------------- |
︙ | ︙ | |||
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 | else BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_OMIT_LOAD_EXTENSION=1" fi AC_MSG_CHECKING([for whether to support dynamic extensions]) AC_MSG_RESULT($enable_dynamic_extensions) #----------------------------------------------------------------------- #----------------------------------------------------------------------- # --enable-fts4 # AC_ARG_ENABLE(fts4, [AS_HELP_STRING( [--enable-fts4], [include fts4 support [default=yes]])], [], [enable_fts4=yes]) if test x"$enable_fts4" = "xyes"; then BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_ENABLE_FTS4" fi #----------------------------------------------------------------------- #----------------------------------------------------------------------- # --enable-fts3 # AC_ARG_ENABLE(fts3, [AS_HELP_STRING( [--enable-fts3], [include fts3 support [default=no]])], [], []) if test x"$enable_fts3" = "xyes" -a x"$enable_fts4" = "xno"; then BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_ENABLE_FTS3" fi #----------------------------------------------------------------------- #----------------------------------------------------------------------- # --enable-fts5 # AC_ARG_ENABLE(fts5, [AS_HELP_STRING( [--enable-fts5], [include fts5 support [default=yes]])], [], [enable_fts5=yes]) if test x"$enable_fts5" = "xyes"; then AC_SEARCH_LIBS(log, m) BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_ENABLE_FTS5" fi #----------------------------------------------------------------------- #----------------------------------------------------------------------- # --enable-json1 # AC_ARG_ENABLE(json1, [AS_HELP_STRING( [--enable-json1], [include json1 support [default=yes]])], [],[enable_json1=yes]) if test x"$enable_json1" = "xyes"; then BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_ENABLE_JSON1" fi #----------------------------------------------------------------------- #----------------------------------------------------------------------- # --enable-rtree # AC_ARG_ENABLE(rtree, [AS_HELP_STRING( [--enable-rtree], [include rtree support [default=yes]])], [], [enable_rtree=yes]) if test x"$enable_rtree" = "xyes"; then | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > | 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 | else BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_OMIT_LOAD_EXTENSION=1" fi AC_MSG_CHECKING([for whether to support dynamic extensions]) AC_MSG_RESULT($enable_dynamic_extensions) #----------------------------------------------------------------------- #----------------------------------------------------------------------- # --enable-math # AC_ARG_ENABLE(math, [AS_HELP_STRING( [--enable-math], [SQL math functions [default=yes]])], [], [enable_math=yes]) AC_MSG_CHECKING([SQL math functions]) if test x"$enable_math" = "xyes"; then BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_ENABLE_MATH_FUNCTIONS" AC_MSG_RESULT([enabled]) AC_SEARCH_LIBS(ceil, m) else AC_MSG_RESULT([disabled]) fi #----------------------------------------------------------------------- #----------------------------------------------------------------------- # --enable-fts4 # AC_ARG_ENABLE(fts4, [AS_HELP_STRING( [--enable-fts4], [include fts4 support [default=yes]])], [], [enable_fts4=yes]) AC_MSG_CHECKING([FTS4 extension]) if test x"$enable_fts4" = "xyes"; then BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_ENABLE_FTS4" AC_MSG_RESULT([enabled]) else AC_MSG_RESULT([disabled]) fi #----------------------------------------------------------------------- #----------------------------------------------------------------------- # --enable-fts3 # AC_ARG_ENABLE(fts3, [AS_HELP_STRING( [--enable-fts3], [include fts3 support [default=no]])], [], []) AC_MSG_CHECKING([FTS3 extension]) if test x"$enable_fts3" = "xyes" -a x"$enable_fts4" = "xno"; then BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_ENABLE_FTS3" AC_MSG_RESULT([enabled]) else AC_MSG_RESULT([disabled]) fi #----------------------------------------------------------------------- #----------------------------------------------------------------------- # --enable-fts5 # AC_ARG_ENABLE(fts5, [AS_HELP_STRING( [--enable-fts5], [include fts5 support [default=yes]])], [], [enable_fts5=yes]) AC_MSG_CHECKING([FTS5 extension]) if test x"$enable_fts5" = "xyes"; then AC_MSG_RESULT([enabled]) AC_SEARCH_LIBS(log, m) BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_ENABLE_FTS5" else AC_MSG_RESULT([disabled]) fi #----------------------------------------------------------------------- #----------------------------------------------------------------------- # --enable-json1 # AC_ARG_ENABLE(json1, [AS_HELP_STRING( [--enable-json1], [include json1 support [default=yes]])], [],[enable_json1=yes]) AC_MSG_CHECKING([JSON functions]) if test x"$enable_json1" = "xyes"; then BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_ENABLE_JSON1" AC_MSG_RESULT([enabled]) else AC_MSG_RESULT([disabled]) fi #----------------------------------------------------------------------- #----------------------------------------------------------------------- # --enable-rtree # AC_ARG_ENABLE(rtree, [AS_HELP_STRING( [--enable-rtree], [include rtree support [default=yes]])], [], [enable_rtree=yes]) AC_MSG_CHECKING([RTREE extension]) if test x"$enable_rtree" = "xyes"; then BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_ENABLE_RTREE -DSQLITE_ENABLE_GEOPOLY" AC_MSG_RESULT([enabled]) else AC_MSG_RESULT([disabled]) fi #----------------------------------------------------------------------- #----------------------------------------------------------------------- # --enable-session # AC_ARG_ENABLE(session, [AS_HELP_STRING( [--enable-session], [enable the session extension [default=no]])], [], []) AC_MSG_CHECKING([Session extension]) if test x"$enable_session" = "xyes"; then BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_ENABLE_SESSION -DSQLITE_ENABLE_PREUPDATE_HOOK" AC_MSG_RESULT([enabled]) else AC_MSG_RESULT([disabled]) fi #----------------------------------------------------------------------- #----------------------------------------------------------------------- # --enable-debug # AC_ARG_ENABLE(debug, [AS_HELP_STRING( [--enable-debug], [build with debugging features enabled [default=no]])], [], []) AC_MSG_CHECKING([Build type]) if test x"$enable_debug" = "xyes"; then BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_DEBUG -DSQLITE_ENABLE_SELECTTRACE -DSQLITE_ENABLE_WHERETRACE" CFLAGS="-g -O0" AC_MSG_RESULT([debug]) else AC_MSG_RESULT([release]) fi #----------------------------------------------------------------------- #----------------------------------------------------------------------- # --enable-static-shell # AC_ARG_ENABLE(static-shell, [AS_HELP_STRING( |
︙ | ︙ |
Changes to autoconf/tea/configure.ac.
︙ | ︙ | |||
15 16 17 18 19 20 21 | # Set your package name and version numbers here. # # This initializes the environment with PACKAGE_NAME and PACKAGE_VERSION # set as provided. These will also be added as -D defs in your Makefile # so you can encode the package version directly into the source files. #----------------------------------------------------------------------- | | | 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | # Set your package name and version numbers here. # # This initializes the environment with PACKAGE_NAME and PACKAGE_VERSION # set as provided. These will also be added as -D defs in your Makefile # so you can encode the package version directly into the source files. #----------------------------------------------------------------------- AC_INIT([sqlite], [3.32.0]) #-------------------------------------------------------------------- # Call TEA_INIT as the first TEA_ macro to set up initial vars. # This will define a ${TEA_PLATFORM} variable == "unix" or "windows" # as well as PKG_LIB_FILE and PKG_STUB_LIB_FILE. #-------------------------------------------------------------------- |
︙ | ︙ |
Changes to autoconf/tea/win/makefile.vc.
︙ | ︙ | |||
158 159 160 161 162 163 164 | # nmakehelp -V <file> <tag> will search the file for tag, skips until a # number and returns all character until a character not in [0-9.ab] # is read. !if [echo REM = This file is generated from Makefile.vc > versions.vc] !endif | | | < < < | > > > > > > > > > > > | | | | 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 | # nmakehelp -V <file> <tag> will search the file for tag, skips until a # number and returns all character until a character not in [0-9.ab] # is read. !if [echo REM = This file is generated from Makefile.vc > versions.vc] !endif # get project version from row "AC_INIT([sqlite], [3.x.y])" !if [echo DOTVERSION = \>> versions.vc] \ && [nmakehlp -V ..\configure.ac AC_INIT >> versions.vc] !endif !include "versions.vc" VERSION = $(DOTVERSION:.=) STUBPREFIX = $(PROJECT)stub #------------------------------------------------------------------------- # Target names and paths ( shouldn't need changing ) #------------------------------------------------------------------------- BINROOT = . ROOT = .. PRJIMPLIB = $(OUT_DIR)\$(PROJECT)$(VERSION)$(SUFX).lib PRJLIBNAME = $(PROJECT).$(EXT) PRJLIB = $(OUT_DIR)\$(PRJLIBNAME) PRJSTUBLIBNAME = $(STUBPREFIX)$(VERSION).lib PRJSTUBLIB = $(OUT_DIR)\$(PRJSTUBLIBNAME) ### Make sure we use backslash only. PRJ_INSTALL_DIR = $(_INSTALLDIR)\$(PROJECT)$(DOTVERSION) LIB_INSTALL_DIR = $(PRJ_INSTALL_DIR) BIN_INSTALL_DIR = $(PRJ_INSTALL_DIR) DOC_INSTALL_DIR = $(PRJ_INSTALL_DIR) SCRIPT_INSTALL_DIR = $(PRJ_INSTALL_DIR) INCLUDE_INSTALL_DIR = $(_TCLDIR)\include ### The following paths CANNOT have spaces in them. GENERICDIR = $(ROOT)\generic WINDIR = $(ROOT)\win LIBDIR = $(ROOT)\library DOCDIR = $(ROOT)\doc TOOLSDIR = $(ROOT)\tools COMPATDIR = $(ROOT)\compat ### Figure out where the primary source code file(s) is/are. !if exist("$(ROOT)\..\..\sqlite3.c") && exist("$(ROOT)\..\..\src\tclsqlite.c") SQL_INCLUDES = -I"$(ROOT)\..\.." SQLITE_SRCDIR = $(ROOT)\..\.. TCLSQLITE_SRCDIR = $(ROOT)\..\..\src DLLOBJS = $(TMP_DIR)\sqlite3.obj $(TMP_DIR)\tclsqlite.obj !else TCLSQLITE_SRCDIR = $(ROOT)\generic DLLOBJS = $(TMP_DIR)\tclsqlite3.obj !endif #--------------------------------------------------------------------- # Compile flags #--------------------------------------------------------------------- !if !$(DEBUG) !if $(OPTIMIZING) ### This cranks the optimization level to maximize speed cdebug = -O2 -Op -Gs !else cdebug = !endif !else if "$(MACHINE)" == "IA64" ### Warnings are too many, can't support warnings into errors. cdebug = -Z7 -Od -GZ !else cdebug = -Z7 -WX -Od -GZ !endif ### Declarations common to all compiler options cflags = -nologo -c -W3 -D_CRT_SECURE_NO_WARNINGS -YX -Fp$(TMP_DIR)^\ !if $(MSVCRT) !if $(DEBUG) crt = -MDd !else crt = -MD !endif !else !if $(DEBUG) crt = -MTd !else crt = -MT !endif !endif INCLUDES = $(SQL_INCLUDES) $(TCL_INCLUDES) -I"$(WINDIR)" \ -I"$(GENERICDIR)" -I"$(ROOT)\.." BASE_CLFAGS = $(cflags) $(cdebug) $(crt) $(INCLUDES) \ -DSQLITE_3_SUFFIX_ONLY=1 -DSQLITE_ENABLE_RTREE=1 \ -DSQLITE_ENABLE_FTS3=1 -DSQLITE_OMIT_DEPRECATED=1 CON_CFLAGS = $(cflags) $(cdebug) $(crt) -DCONSOLE -DSQLITE_ENABLE_FTS3=1 TCL_CFLAGS = -DBUILD_sqlite -DUSE_TCL_STUBS \ -DPACKAGE_VERSION="\"$(DOTVERSION)\"" $(BASE_CLFAGS) \ $(OPTDEFINES) |
︙ | ︙ | |||
337 338 339 340 341 342 343 | $(PRJSTUBLIB): $(PRJSTUBOBJS) $(lib32) -nologo -out:$@ $(PRJSTUBOBJS) #--------------------------------------------------------------------- # Implicit rules #--------------------------------------------------------------------- | | | | < | | < < > | | < < > | 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 | $(PRJSTUBLIB): $(PRJSTUBOBJS) $(lib32) -nologo -out:$@ $(PRJSTUBOBJS) #--------------------------------------------------------------------- # Implicit rules #--------------------------------------------------------------------- $(TMP_DIR)\sqlite3.obj: $(SQLITE_SRCDIR)\sqlite3.c $(cc32) $(TCL_CFLAGS) -DBUILD_$(PROJECT) -Fo$(TMP_DIR)\ \ -c $(SQLITE_SRCDIR)\sqlite3.c $(TMP_DIR)\tclsqlite.obj: $(TCLSQLITE_SRCDIR)\tclsqlite.c $(cc32) $(TCL_CFLAGS) -DBUILD_$(PROJECT) -Fo$(TMP_DIR)\ \ -c $(TCLSQLITE_SRCDIR)\tclsqlite.c $(TMP_DIR)\tclsqlite3.obj: $(TCLSQLITE_SRCDIR)\tclsqlite3.c $(cc32) $(TCL_CFLAGS) -DBUILD_$(PROJECT) -Fo$(TMP_DIR)\ \ -c $(TCLSQLITE_SRCDIR)\tclsqlite3.c {$(WINDIR)}.rc{$(TMP_DIR)}.res: $(rc32) -fo $@ -r -i "$(GENERICDIR)" -D__WIN32__ \ !if $(DEBUG) -d DEBUG \ !endif !if $(TCL_THREADS) |
︙ | ︙ |
Changes to autoconf/tea/win/nmakehlp.c.
︙ | ︙ | |||
10 11 12 13 14 15 16 | * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. * ---------------------------------------------------------------------------- */ #define _CRT_SECURE_NO_DEPRECATE #include <windows.h> | | < < < | < | > | | | > | 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 | * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. * ---------------------------------------------------------------------------- */ #define _CRT_SECURE_NO_DEPRECATE #include <windows.h> #ifdef _MSC_VER #pragma comment (lib, "user32.lib") #pragma comment (lib, "kernel32.lib") #endif #include <stdio.h> #include <math.h> /* * This library is required for x64 builds with _some_ versions of MSVC */ #if defined(_M_IA64) || defined(_M_AMD64) #if _MSC_VER >= 1400 && _MSC_VER < 1500 #pragma comment(lib, "bufferoverflowU") #endif #endif /* ISO hack for dumb VC++ */ #ifdef _MSC_VER #define snprintf _snprintf #endif /* protos */ static int CheckForCompilerFeature(const char *option); static int CheckForLinkerFeature(char **options, int count); static int IsIn(const char *string, const char *substring); static int SubstituteFile(const char *substs, const char *filename); static int QualifyPath(const char *path); static int LocateDependency(const char *keyfile); static const char *GetVersionFromFile(const char *filename, const char *match, int numdots); static DWORD WINAPI ReadFromPipe(LPVOID args); /* globals */ #define CHUNK 25 #define STATICBUFFERSIZE 1000 typedef struct { HANDLE pipe; char buffer[STATICBUFFERSIZE]; } pipeinfo; pipeinfo Out = {INVALID_HANDLE_VALUE, ""}; pipeinfo Err = {INVALID_HANDLE_VALUE, ""}; /* * exitcodes: 0 == no, 1 == yes, 2 == error */ int main( int argc, char *argv[]) { char msg[300]; DWORD dwWritten; int chars; const char *s; /* * Make sure children (cl.exe and link.exe) are kept quiet. */ SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX); |
︙ | ︙ | |||
98 99 100 101 102 103 104 | "exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]); WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, &dwWritten, NULL); return 2; } return CheckForCompilerFeature(argv[2]); case 'l': | | | | | 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 | "exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]); WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, &dwWritten, NULL); return 2; } return CheckForCompilerFeature(argv[2]); case 'l': if (argc < 3) { chars = snprintf(msg, sizeof(msg) - 1, "usage: %s -l <linker option> ?<mandatory option> ...?\n" "Tests for whether link.exe supports an option\n" "exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]); WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, &dwWritten, NULL); return 2; } return CheckForLinkerFeature(&argv[2], argc-2); case 'f': if (argc == 2) { chars = snprintf(msg, sizeof(msg) - 1, "usage: %s -f <string> <substring>\n" "Find a substring within another\n" "exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]); WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, |
︙ | ︙ | |||
149 150 151 152 153 154 155 | "Extract a version from a file:\n" "eg: pkgIndex.tcl \"package ifneeded http\"", argv[0]); WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, &dwWritten, NULL); return 0; } | > > | | > > > > > > > > > > > > > > > | 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 | "Extract a version from a file:\n" "eg: pkgIndex.tcl \"package ifneeded http\"", argv[0]); WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, &dwWritten, NULL); return 0; } s = GetVersionFromFile(argv[2], argv[3], *(argv[1]+2) - '0'); if (s && *s) { printf("%s\n", s); return 0; } else return 1; /* Version not found. Return non-0 exit code */ case 'Q': if (argc != 3) { chars = snprintf(msg, sizeof(msg) - 1, "usage: %s -Q path\n" "Emit the fully qualified path\n" "exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]); WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, &dwWritten, NULL); return 2; } return QualifyPath(argv[2]); case 'L': if (argc != 3) { chars = snprintf(msg, sizeof(msg) - 1, "usage: %s -L keypath\n" "Emit the fully qualified path of directory containing keypath\n" "exitcodes: 0 == success, 1 == not found, 2 == error\n", argv[0]); WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, &dwWritten, NULL); return 2; } return LocateDependency(argv[2]); } } chars = snprintf(msg, sizeof(msg) - 1, "usage: %s -c|-f|-l|-Q|-s|-V ...\n" "This is a little helper app to equalize shell differences between WinNT and\n" "Win9x and get nmake.exe to accomplish its job.\n", argv[0]); |
︙ | ︙ | |||
256 257 258 259 260 261 262 | if (!ok) { DWORD err = GetLastError(); int chars = snprintf(msg, sizeof(msg) - 1, "Tried to launch: \"%s\", but got error [%u]: ", cmdline, err); FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS| | | | 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 | if (!ok) { DWORD err = GetLastError(); int chars = snprintf(msg, sizeof(msg) - 1, "Tried to launch: \"%s\", but got error [%u]: ", cmdline, err); FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS| FORMAT_MESSAGE_MAX_WIDTH_MASK, 0L, err, 0, (LPSTR)&msg[chars], (300-chars), 0); WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, lstrlen(msg), &err,NULL); return 2; } /* * Close our references to the write handles that have now been inherited. |
︙ | ︙ | |||
309 310 311 312 313 314 315 | || strstr(Err.buffer, "D9002") != NULL || strstr(Out.buffer, "D2021") != NULL || strstr(Err.buffer, "D2021") != NULL); } static int CheckForLinkerFeature( | | > > | | 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 | || strstr(Err.buffer, "D9002") != NULL || strstr(Out.buffer, "D2021") != NULL || strstr(Err.buffer, "D2021") != NULL); } static int CheckForLinkerFeature( char **options, int count) { STARTUPINFO si; PROCESS_INFORMATION pi; SECURITY_ATTRIBUTES sa; DWORD threadID; char msg[300]; BOOL ok; HANDLE hProcess, h, pipeThreads[2]; int i; char cmdline[255]; hProcess = GetCurrentProcess(); ZeroMemory(&pi, sizeof(PROCESS_INFORMATION)); ZeroMemory(&si, sizeof(STARTUPINFO)); si.cb = sizeof(STARTUPINFO); si.dwFlags = STARTF_USESTDHANDLES; |
︙ | ︙ | |||
364 365 366 367 368 369 370 | lstrcpy(cmdline, "link.exe -nologo "); /* * Append our option for testing. */ | > | > > > | | 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 | lstrcpy(cmdline, "link.exe -nologo "); /* * Append our option for testing. */ for (i = 0; i < count; i++) { lstrcat(cmdline, " \""); lstrcat(cmdline, options[i]); lstrcat(cmdline, "\""); } ok = CreateProcess( NULL, /* Module name. */ cmdline, /* Command line. */ NULL, /* Process handle not inheritable. */ NULL, /* Thread handle not inheritable. */ TRUE, /* yes, inherit handles. */ DETACHED_PROCESS, /* No console for you. */ NULL, /* Use parent's environment block. */ NULL, /* Use parent's starting directory. */ &si, /* Pointer to STARTUPINFO structure. */ &pi); /* Pointer to PROCESS_INFORMATION structure. */ if (!ok) { DWORD err = GetLastError(); int chars = snprintf(msg, sizeof(msg) - 1, "Tried to launch: \"%s\", but got error [%u]: ", cmdline, err); FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS| FORMAT_MESSAGE_MAX_WIDTH_MASK, 0L, err, 0, (LPSTR)&msg[chars], (300-chars), 0); WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, lstrlen(msg), &err,NULL); return 2; } /* * Close our references to the write handles that have now been inherited. |
︙ | ︙ | |||
429 430 431 432 433 434 435 | /* * Look for the commandline warning code in the stderr stream. */ return !(strstr(Out.buffer, "LNK1117") != NULL || strstr(Err.buffer, "LNK1117") != NULL || strstr(Out.buffer, "LNK4044") != NULL || | | > > | 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 | /* * Look for the commandline warning code in the stderr stream. */ return !(strstr(Out.buffer, "LNK1117") != NULL || strstr(Err.buffer, "LNK1117") != NULL || strstr(Out.buffer, "LNK4044") != NULL || strstr(Err.buffer, "LNK4044") != NULL || strstr(Out.buffer, "LNK4224") != NULL || strstr(Err.buffer, "LNK4224") != NULL); } static DWORD WINAPI ReadFromPipe( LPVOID args) { pipeinfo *pi = (pipeinfo *) args; |
︙ | ︙ | |||
475 476 477 478 479 480 481 | * following the match where a version is anything acceptable to * package provide or package ifneeded. */ static const char * GetVersionFromFile( const char *filename, | | > < | | > | | > < | | | 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 | * following the match where a version is anything acceptable to * package provide or package ifneeded. */ static const char * GetVersionFromFile( const char *filename, const char *match, int numdots) { static char szBuffer[100]; char *szResult = NULL; FILE *fp = fopen(filename, "rt"); if (fp != NULL) { /* * Read data until we see our match string. */ while (fgets(szBuffer, sizeof(szBuffer), fp) != NULL) { LPSTR p, q; p = strstr(szBuffer, match); if (p != NULL) { /* * Skip to first digit after the match. */ p += strlen(match); while (*p && !isdigit((unsigned char)*p)) { ++p; } /* * Find ending whitespace. */ q = p; while (*q && (strchr("0123456789.ab", *q)) && (((!strchr(".ab", *q) && !strchr("ab", q[-1])) || --numdots))) { ++q; } *q = 0; szResult = p; break; } } fclose(fp); } return szResult; } |
︙ | ︙ | |||
534 535 536 537 538 539 540 | char * value; } list_item_t; /* insert a list item into the list (list may be null) */ static list_item_t * list_insert(list_item_t **listPtrPtr, const char *key, const char *value) { | | | 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 | char * value; } list_item_t; /* insert a list item into the list (list may be null) */ static list_item_t * list_insert(list_item_t **listPtrPtr, const char *key, const char *value) { list_item_t *itemPtr = (list_item_t *)malloc(sizeof(list_item_t)); if (itemPtr) { itemPtr->key = strdup(key); itemPtr->value = strdup(value); itemPtr->nextPtr = NULL; while(*listPtrPtr) { listPtrPtr = &(*listPtrPtr)->nextPtr; |
︙ | ︙ | |||
583 584 585 586 587 588 589 | */ static int SubstituteFile( const char *substitutions, const char *filename) { | < < | | | | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > | > > > > > > > > | > > > > > > > > > > > > | > > > > > > > > > > > > > > | > > > > | > > > > > > > | > > > > > > > > > > > > > > > > > | > > > | | > > > | 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 | */ static int SubstituteFile( const char *substitutions, const char *filename) { static char szBuffer[1024], szCopy[1024]; list_item_t *substPtr = NULL; FILE *fp, *sp; fp = fopen(filename, "rt"); if (fp != NULL) { /* * Build a list of substutitions from the first filename */ sp = fopen(substitutions, "rt"); if (sp != NULL) { while (fgets(szBuffer, sizeof(szBuffer), sp) != NULL) { unsigned char *ks, *ke, *vs, *ve; ks = (unsigned char*)szBuffer; while (ks && *ks && isspace(*ks)) ++ks; ke = ks; while (ke && *ke && !isspace(*ke)) ++ke; vs = ke; while (vs && *vs && isspace(*vs)) ++vs; ve = vs; while (ve && *ve && !(*ve == '\r' || *ve == '\n')) ++ve; *ke = 0, *ve = 0; list_insert(&substPtr, (char*)ks, (char*)vs); } fclose(sp); } /* debug: dump the list */ #ifndef NDEBUG { int n = 0; list_item_t *p = NULL; for (p = substPtr; p != NULL; p = p->nextPtr, ++n) { fprintf(stderr, "% 3d '%s' => '%s'\n", n, p->key, p->value); } } #endif /* * Run the substitutions over each line of the input */ while (fgets(szBuffer, sizeof(szBuffer), fp) != NULL) { list_item_t *p = NULL; for (p = substPtr; p != NULL; p = p->nextPtr) { char *m = strstr(szBuffer, p->key); if (m) { char *cp, *op, *sp; cp = szCopy; op = szBuffer; while (op != m) *cp++ = *op++; sp = p->value; while (sp && *sp) *cp++ = *sp++; op += strlen(p->key); while (*op) *cp++ = *op++; *cp = 0; memcpy(szBuffer, szCopy, sizeof(szCopy)); } } printf("%s", szBuffer); } list_free(&substPtr); } fclose(fp); return 0; } BOOL FileExists(LPCTSTR szPath) { #ifndef INVALID_FILE_ATTRIBUTES #define INVALID_FILE_ATTRIBUTES ((DWORD)-1) #endif DWORD pathAttr = GetFileAttributes(szPath); return (pathAttr != INVALID_FILE_ATTRIBUTES && !(pathAttr & FILE_ATTRIBUTE_DIRECTORY)); } /* * QualifyPath -- * * This composes the current working directory with a provided path * and returns the fully qualified and normalized path. * Mostly needed to setup paths for testing. */ static int QualifyPath( const char *szPath) { char szCwd[MAX_PATH + 1]; GetFullPathName(szPath, sizeof(szCwd)-1, szCwd, NULL); printf("%s\n", szCwd); return 0; } /* * Implements LocateDependency for a single directory. See that command * for an explanation. * Returns 0 if found after printing the directory. * Returns 1 if not found but no errors. * Returns 2 on any kind of error * Basically, these are used as exit codes for the process. */ static int LocateDependencyHelper(const char *dir, const char *keypath) { HANDLE hSearch; char path[MAX_PATH+1]; size_t dirlen; int keylen, ret; WIN32_FIND_DATA finfo; if (dir == NULL || keypath == NULL) return 2; /* Have no real error reporting mechanism into nmake */ dirlen = strlen(dir); if ((dirlen + 3) > sizeof(path)) return 2; strncpy(path, dir, dirlen); strncpy(path+dirlen, "\\*", 3); /* Including terminating \0 */ keylen = strlen(keypath); #if 0 /* This function is not available in Visual C++ 6 */ /* * Use numerics 0 -> FindExInfoStandard, * 1 -> FindExSearchLimitToDirectories, * as these are not defined in Visual C++ 6 */ hSearch = FindFirstFileEx(path, 0, &finfo, 1, NULL, 0); #else hSearch = FindFirstFile(path, &finfo); #endif if (hSearch == INVALID_HANDLE_VALUE) return 1; /* Not found */ /* Loop through all subdirs checking if the keypath is under there */ ret = 1; /* Assume not found */ do { int sublen; /* * We need to check it is a directory despite the * FindExSearchLimitToDirectories in the above call. See SDK docs */ if ((finfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) continue; sublen = strlen(finfo.cFileName); if ((dirlen+1+sublen+1+keylen+1) > sizeof(path)) continue; /* Path does not fit, assume not matched */ strncpy(path+dirlen+1, finfo.cFileName, sublen); path[dirlen+1+sublen] = '\\'; strncpy(path+dirlen+1+sublen+1, keypath, keylen+1); if (FileExists(path)) { /* Found a match, print to stdout */ path[dirlen+1+sublen] = '\0'; QualifyPath(path); ret = 0; break; } } while (FindNextFile(hSearch, &finfo)); FindClose(hSearch); return ret; } /* * LocateDependency -- * * Locates a dependency for a package. * keypath - a relative path within the package directory * that is used to confirm it is the correct directory. * The search path for the package directory is currently only * the parent and grandparent of the current working directory. * If found, the command prints * name_DIRPATH=<full path of located directory> * and returns 0. If not found, does not print anything and returns 1. */ static int LocateDependency(const char *keypath) { size_t i; int ret; static const char *paths[] = {"..", "..\\..", "..\\..\\.."}; for (i = 0; i < (sizeof(paths)/sizeof(paths[0])); ++i) { ret = LocateDependencyHelper(paths[i], keypath); if (ret == 0) return ret; } return ret; } /* * Local variables: * mode: c * c-basic-offset: 4 * fill-column: 78 * indent-tabs-mode: t * tab-width: 8 * End: */ |
Changes to config.guess.
1 2 | #! /bin/sh # Attempt to guess a canonical system name. | < | < | | | < < | | > | | < < > | < < > | < | < | | 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 | #! /bin/sh # Attempt to guess a canonical system name. # Copyright 1992-2019 Free Software Foundation, Inc. timestamp='2019-05-28' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see <https://www.gnu.org/licenses/>. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that # program. This Exception is an additional permission under section 7 # of the GNU General Public License, version 3 ("GPLv3"). # # Originally written by Per Bothner; maintained since 2000 by Ben Elliston. # # You can get the latest version of this script from: # https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess # # Please send patches to <config-patches@gnu.org>. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] Output the configuration name of the system \`$me' is run on. Options: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to <config-patches@gnu.org>." version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. Copyright 1992-2019 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." |
︙ | ︙ | |||
87 88 89 90 91 92 93 | done if test $# != 0; then echo "$me: too many arguments$help" >&2 exit 1 fi | < < > > > > | < < | > | | | | | < | | | | | > | | | | | | | | | | > | | > > > > > | | | < < < > | | > | > > > > > | > > | | | > > | | > > > > > | | | > > > | | | > > > > > > > | | | > > > > > > > | > > > > | | | > > > | > > > > > > | | | | | | | | | | | | | | | | | > | < < < < < | < < | | | | | | | 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 | done if test $# != 0; then echo "$me: too many arguments$help" >&2 exit 1 fi # CC_FOR_BUILD -- compiler used by this script. Note that the use of a # compiler to aid in system detection is discouraged as it requires # temporary files to be created and, as you can see below, it is a # headache to deal with in a portable fashion. # Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still # use `HOST_CC' if defined, but it is deprecated. # Portable tmp directory creation inspired by the Autoconf team. tmp= # shellcheck disable=SC2172 trap 'test -z "$tmp" || rm -fr "$tmp"' 0 1 2 13 15 set_cc_for_build() { : "${TMPDIR=/tmp}" # shellcheck disable=SC2039 { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir "$tmp" 2>/dev/null) ; } || { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir "$tmp" 2>/dev/null) && echo "Warning: creating insecure temp directory" >&2 ; } || { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } dummy=$tmp/dummy case ${CC_FOR_BUILD-},${HOST_CC-},${CC-} in ,,) echo "int x;" > "$dummy.c" for driver in cc gcc c89 c99 ; do if ($driver -c -o "$dummy.o" "$dummy.c") >/dev/null 2>&1 ; then CC_FOR_BUILD="$driver" break fi done if test x"$CC_FOR_BUILD" = x ; then CC_FOR_BUILD=no_compiler_found fi ;; ,,*) CC_FOR_BUILD=$CC ;; ,*,*) CC_FOR_BUILD=$HOST_CC ;; esac } # This is needed to find uname on a Pyramid OSx when run in the BSD universe. # (ghazi@noc.rutgers.edu 1994-08-24) if test -f /.attbin/uname ; then PATH=$PATH:/.attbin ; export PATH fi UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown case "$UNAME_SYSTEM" in Linux|GNU|GNU/*) # If the system lacks a compiler, then just pick glibc. # We could probably try harder. LIBC=gnu set_cc_for_build cat <<-EOF > "$dummy.c" #include <features.h> #if defined(__UCLIBC__) LIBC=uclibc #elif defined(__dietlibc__) LIBC=dietlibc #else LIBC=gnu #endif EOF eval "`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | sed 's, ,,g'`" # If ldd exists, use it to detect musl libc. if command -v ldd >/dev/null && \ ldd --version 2>&1 | grep -q ^musl then LIBC=musl fi ;; esac # Note: order is significant - the case branches are not exclusive. case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in *:NetBSD:*:*) # NetBSD (nbsd) targets should (where applicable) match one or # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently # switched to ELF, *-*-netbsd* would select the old # object file format. This provides both forward # compatibility and a consistent mechanism for selecting the # object file format. # # Note: NetBSD doesn't particularly care about the vendor # portion of the name. We always set it to "unknown". sysctl="sysctl -n hw.machine_arch" UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \ "/sbin/$sysctl" 2>/dev/null || \ "/usr/sbin/$sysctl" 2>/dev/null || \ echo unknown)` case "$UNAME_MACHINE_ARCH" in armeb) machine=armeb-unknown ;; arm*) machine=arm-unknown ;; sh3el) machine=shl-unknown ;; sh3eb) machine=sh-unknown ;; sh5el) machine=sh5le-unknown ;; earmv*) arch=`echo "$UNAME_MACHINE_ARCH" | sed -e 's,^e\(armv[0-9]\).*$,\1,'` endian=`echo "$UNAME_MACHINE_ARCH" | sed -ne 's,^.*\(eb\)$,\1,p'` machine="${arch}${endian}"-unknown ;; *) machine="$UNAME_MACHINE_ARCH"-unknown ;; esac # The Operating System including object format, if it has switched # to ELF recently (or will in the future) and ABI. case "$UNAME_MACHINE_ARCH" in earm*) os=netbsdelf ;; arm*|i386|m68k|ns32k|sh3*|sparc|vax) set_cc_for_build if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ELF__ then # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). # Return netbsd for either. FIX? os=netbsd else os=netbsdelf fi ;; *) os=netbsd ;; esac # Determine ABI tags. case "$UNAME_MACHINE_ARCH" in earm*) expr='s/^earmv[0-9]/-eabi/;s/eb$//' abi=`echo "$UNAME_MACHINE_ARCH" | sed -e "$expr"` ;; esac # The OS release # Debian GNU/NetBSD machines have a different userland, and # thus, need a distinct triplet. However, they do not need # kernel version information, so it can be replaced with a # suitable tag, in the style of linux-gnu. case "$UNAME_VERSION" in Debian*) release='-gnu' ;; *) release=`echo "$UNAME_RELEASE" | sed -e 's/[-_].*//' | cut -d. -f1,2` ;; esac # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. echo "$machine-${os}${release}${abi-}" exit ;; *:Bitrig:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` echo "$UNAME_MACHINE_ARCH"-unknown-bitrig"$UNAME_RELEASE" exit ;; *:OpenBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` echo "$UNAME_MACHINE_ARCH"-unknown-openbsd"$UNAME_RELEASE" exit ;; *:LibertyBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'` echo "$UNAME_MACHINE_ARCH"-unknown-libertybsd"$UNAME_RELEASE" exit ;; *:MidnightBSD:*:*) echo "$UNAME_MACHINE"-unknown-midnightbsd"$UNAME_RELEASE" exit ;; *:ekkoBSD:*:*) echo "$UNAME_MACHINE"-unknown-ekkobsd"$UNAME_RELEASE" exit ;; *:SolidBSD:*:*) echo "$UNAME_MACHINE"-unknown-solidbsd"$UNAME_RELEASE" exit ;; macppc:MirBSD:*:*) echo powerpc-unknown-mirbsd"$UNAME_RELEASE" exit ;; *:MirBSD:*:*) echo "$UNAME_MACHINE"-unknown-mirbsd"$UNAME_RELEASE" exit ;; *:Sortix:*:*) echo "$UNAME_MACHINE"-unknown-sortix exit ;; *:Redox:*:*) echo "$UNAME_MACHINE"-unknown-redox exit ;; mips:OSF1:*.*) echo mips-dec-osf1 exit ;; alpha:OSF1:*:*) case $UNAME_RELEASE in *4.0) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` ;; *5.*) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` ;; esac # According to Compaq, /usr/sbin/psrinfo has been available on # OSF/1 and Tru64 systems produced since 1995. I hope that # covers most systems running today. This code pipes the CPU # types through head -n 1, so we only detect the type of CPU 0. ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` case "$ALPHA_CPU_TYPE" in "EV4 (21064)") UNAME_MACHINE=alpha ;; "EV4.5 (21064)") UNAME_MACHINE=alpha ;; "LCA4 (21066/21068)") UNAME_MACHINE=alpha ;; "EV5 (21164)") UNAME_MACHINE=alphaev5 ;; "EV5.6 (21164A)") UNAME_MACHINE=alphaev56 ;; "EV5.6 (21164PC)") UNAME_MACHINE=alphapca56 ;; "EV5.7 (21164PC)") UNAME_MACHINE=alphapca57 ;; "EV6 (21264)") UNAME_MACHINE=alphaev6 ;; "EV6.7 (21264A)") UNAME_MACHINE=alphaev67 ;; "EV6.8CB (21264C)") UNAME_MACHINE=alphaev68 ;; "EV6.8AL (21264B)") UNAME_MACHINE=alphaev68 ;; "EV6.8CX (21264D)") UNAME_MACHINE=alphaev68 ;; "EV6.9A (21264/EV69A)") UNAME_MACHINE=alphaev69 ;; "EV7 (21364)") UNAME_MACHINE=alphaev7 ;; "EV7.9 (21364A)") UNAME_MACHINE=alphaev79 ;; esac # A Pn.n version is a patched version. # A Vn.n version is a released version. # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. echo "$UNAME_MACHINE"-dec-osf"`echo "$UNAME_RELEASE" | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz`" # Reset EXIT trap before exiting to avoid spurious non-zero exit code. exitcode=$? trap '' 0 exit $exitcode ;; Amiga*:UNIX_System_V:4.0:*) echo m68k-unknown-sysv4 exit ;; *:[Aa]miga[Oo][Ss]:*:*) echo "$UNAME_MACHINE"-unknown-amigaos exit ;; *:[Mm]orph[Oo][Ss]:*:*) echo "$UNAME_MACHINE"-unknown-morphos exit ;; *:OS/390:*:*) echo i370-ibm-openedition exit ;; *:z/VM:*:*) echo s390-ibm-zvmoe exit ;; *:OS400:*:*) echo powerpc-ibm-os400 exit ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) echo arm-acorn-riscix"$UNAME_RELEASE" exit ;; arm*:riscos:*:*|arm*:RISCOS:*:*) echo arm-unknown-riscos exit ;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) echo hppa1.1-hitachi-hiuxmpp exit ;; Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. |
︙ | ︙ | |||
337 338 339 340 341 342 343 344 | DRS?6000:unix:4.0:6*) echo sparc-icl-nx6 exit ;; DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) case `/usr/bin/uname -p` in sparc) echo sparc-icl-nx7; exit ;; esac ;; sun4H:SunOS:5.*:*) | > > > | | > > > > > > > > > > > > > > > > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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 | DRS?6000:unix:4.0:6*) echo sparc-icl-nx6 exit ;; DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) case `/usr/bin/uname -p` in sparc) echo sparc-icl-nx7; exit ;; esac ;; s390x:SunOS:*:*) echo "$UNAME_MACHINE"-ibm-solaris2"`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`" exit ;; sun4H:SunOS:5.*:*) echo sparc-hal-solaris2"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`" exit ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) echo sparc-sun-solaris2"`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`" exit ;; i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) echo i386-pc-auroraux"$UNAME_RELEASE" exit ;; i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) set_cc_for_build SUN_ARCH=i386 # If there is a compiler, see if it is configured for 64-bit objects. # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. # This test works for both compilers. if [ "$CC_FOR_BUILD" != no_compiler_found ]; then if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then SUN_ARCH=x86_64 fi fi echo "$SUN_ARCH"-pc-solaris2"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`" exit ;; sun4*:SunOS:6*:*) # According to config.sub, this is the proper way to canonicalize # SunOS6. Hard to guess exactly what SunOS6 will be like, but # it's likely to be more like Solaris than SunOS4. echo sparc-sun-solaris3"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`" exit ;; sun4*:SunOS:*:*) case "`/usr/bin/arch -k`" in Series*|S4*) UNAME_RELEASE=`uname -v` ;; esac # Japanese Language versions have a version number like `4.1.3-JL'. echo sparc-sun-sunos"`echo "$UNAME_RELEASE"|sed -e 's/-/_/'`" exit ;; sun3*:SunOS:*:*) echo m68k-sun-sunos"$UNAME_RELEASE" exit ;; sun*:*:4.2BSD:*) UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` test "x$UNAME_RELEASE" = x && UNAME_RELEASE=3 case "`/bin/arch`" in sun3) echo m68k-sun-sunos"$UNAME_RELEASE" ;; sun4) echo sparc-sun-sunos"$UNAME_RELEASE" ;; esac exit ;; aushp:SunOS:*:*) echo sparc-auspex-sunos"$UNAME_RELEASE" exit ;; # The situation for MiNT is a little confusing. The machine name # can be virtually everything (everything which is not # "atarist" or "atariste" at least should have a processor # > m68000). The system name ranges from "MiNT" over "FreeMiNT" # to the lowercase version "mint" (or "freemint"). Finally # the system name "TOS" denotes a system which is actually not # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint"$UNAME_RELEASE" exit ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint"$UNAME_RELEASE" exit ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) echo m68k-atari-mint"$UNAME_RELEASE" exit ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) echo m68k-milan-mint"$UNAME_RELEASE" exit ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) echo m68k-hades-mint"$UNAME_RELEASE" exit ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) echo m68k-unknown-mint"$UNAME_RELEASE" exit ;; m68k:machten:*:*) echo m68k-apple-machten"$UNAME_RELEASE" exit ;; powerpc:machten:*:*) echo powerpc-apple-machten"$UNAME_RELEASE" exit ;; RISC*:Mach:*:*) echo mips-dec-mach_bsd4.3 exit ;; RISC*:ULTRIX:*:*) echo mips-dec-ultrix"$UNAME_RELEASE" exit ;; VAX*:ULTRIX*:*:*) echo vax-dec-ultrix"$UNAME_RELEASE" exit ;; 2020:CLIX:*:* | 2430:CLIX:*:*) echo clipper-intergraph-clix"$UNAME_RELEASE" exit ;; mips:*:*:UMIPS | mips:*:*:RISCos) set_cc_for_build sed 's/^ //' << EOF > "$dummy.c" #ifdef __cplusplus #include <stdio.h> /* for printf() prototype */ int main (int argc, char *argv[]) { #else int main (argc, argv) int argc; char *argv[]; { #endif #if defined (host_mips) && defined (MIPSEB) #if defined (SYSTYPE_SYSV) printf ("mips-mips-riscos%ssysv\\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_SVR4) printf ("mips-mips-riscos%ssvr4\\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) printf ("mips-mips-riscos%sbsd\\n", argv[1]); exit (0); #endif #endif exit (-1); } EOF $CC_FOR_BUILD -o "$dummy" "$dummy.c" && dummyarg=`echo "$UNAME_RELEASE" | sed -n 's/\([0-9]*\).*/\1/p'` && SYSTEM_NAME=`"$dummy" "$dummyarg"` && { echo "$SYSTEM_NAME"; exit; } echo mips-mips-riscos"$UNAME_RELEASE" exit ;; Motorola:PowerMAX_OS:*:*) echo powerpc-motorola-powermax exit ;; Motorola:*:4.3:PL8-*) echo powerpc-harris-powermax exit ;; |
︙ | ︙ | |||
474 475 476 477 478 479 480 | m88k:*:4*:R4*) echo m88k-motorola-sysv4 exit ;; m88k:*:3*:R3*) echo m88k-motorola-sysv3 exit ;; AViiON:dgux:*:*) | | | | | | | | | | | | | | | | | | | | > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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 | m88k:*:4*:R4*) echo m88k-motorola-sysv4 exit ;; m88k:*:3*:R3*) echo m88k-motorola-sysv3 exit ;; AViiON:dgux:*:*) # DG/UX returns AViiON for all architectures UNAME_PROCESSOR=`/usr/bin/uname -p` if [ "$UNAME_PROCESSOR" = mc88100 ] || [ "$UNAME_PROCESSOR" = mc88110 ] then if [ "$TARGET_BINARY_INTERFACE"x = m88kdguxelfx ] || \ [ "$TARGET_BINARY_INTERFACE"x = x ] then echo m88k-dg-dgux"$UNAME_RELEASE" else echo m88k-dg-dguxbcs"$UNAME_RELEASE" fi else echo i586-dg-dgux"$UNAME_RELEASE" fi exit ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) echo m88k-dolphin-sysv3 exit ;; M88*:*:R3*:*) # Delta 88k system running SVR3 echo m88k-motorola-sysv3 exit ;; XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) echo m88k-tektronix-sysv3 exit ;; Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) echo m68k-tektronix-bsd exit ;; *:IRIX*:*:*) echo mips-sgi-irix"`echo "$UNAME_RELEASE"|sed -e 's/-/_/g'`" exit ;; ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' i*86:AIX:*:*) echo i386-ibm-aix exit ;; ia64:AIX:*:*) if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV="$UNAME_VERSION.$UNAME_RELEASE" fi echo "$UNAME_MACHINE"-ibm-aix"$IBM_REV" exit ;; *:AIX:2:3) if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then set_cc_for_build sed 's/^ //' << EOF > "$dummy.c" #include <sys/systemcfg.h> main() { if (!__power_pc()) exit(1); puts("powerpc-ibm-aix3.2.5"); exit(0); } EOF if $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` then echo "$SYSTEM_NAME" else echo rs6000-ibm-aix3.2.5 fi elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then echo rs6000-ibm-aix3.2.4 else echo rs6000-ibm-aix3.2 fi exit ;; *:AIX:*:[4567]) IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` if /usr/sbin/lsattr -El "$IBM_CPU_ID" | grep ' POWER' >/dev/null 2>&1; then IBM_ARCH=rs6000 else IBM_ARCH=powerpc fi if [ -x /usr/bin/lslpp ] ; then IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc | awk -F: '{ print $3 }' | sed s/[0-9]*$/0/` else IBM_REV="$UNAME_VERSION.$UNAME_RELEASE" fi echo "$IBM_ARCH"-ibm-aix"$IBM_REV" exit ;; *:AIX:*:*) echo rs6000-ibm-aix exit ;; ibmrt:4.4BSD:*|romp-ibm:4.4BSD:*) echo romp-ibm-bsd4.4 exit ;; ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and echo romp-ibm-bsd"$UNAME_RELEASE" # 4.3 with uname added to exit ;; # report: romp-ibm BSD 4.3 *:BOSX:*:*) echo rs6000-bull-bosx exit ;; DPX/2?00:B.O.S.:*:*) echo m68k-bull-sysv3 exit ;; 9000/[34]??:4.3bsd:1.*:*) echo m68k-hp-bsd exit ;; hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) echo m68k-hp-bsd4.4 exit ;; 9000/[34678]??:HP-UX:*:*) HPUX_REV=`echo "$UNAME_RELEASE"|sed -e 's/[^.]*.[0B]*//'` case "$UNAME_MACHINE" in 9000/31?) HP_ARCH=m68000 ;; 9000/[34]??) HP_ARCH=m68k ;; 9000/[678][0-9][0-9]) if [ -x /usr/bin/getconf ]; then sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` case "$sc_cpu_version" in 523) HP_ARCH=hppa1.0 ;; # CPU_PA_RISC1_0 528) HP_ARCH=hppa1.1 ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 case "$sc_kernel_bits" in 32) HP_ARCH=hppa2.0n ;; 64) HP_ARCH=hppa2.0w ;; '') HP_ARCH=hppa2.0 ;; # HP-UX 10.20 esac ;; esac fi if [ "$HP_ARCH" = "" ]; then set_cc_for_build sed 's/^ //' << EOF > "$dummy.c" #define _HPUX_SOURCE #include <stdlib.h> #include <unistd.h> int main () { #if defined(_SC_KERNEL_BITS) long bits = sysconf(_SC_KERNEL_BITS); #endif long cpu = sysconf (_SC_CPU_VERSION); switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0"); break; case CPU_PA_RISC1_1: puts ("hppa1.1"); break; case CPU_PA_RISC2_0: #if defined(_SC_KERNEL_BITS) switch (bits) { case 64: puts ("hppa2.0w"); break; case 32: puts ("hppa2.0n"); break; default: puts ("hppa2.0"); break; } break; #else /* !defined(_SC_KERNEL_BITS) */ puts ("hppa2.0"); break; #endif default: puts ("hppa1.0"); break; } exit (0); } EOF (CCOPTS="" $CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null) && HP_ARCH=`"$dummy"` test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac if [ "$HP_ARCH" = hppa2.0w ] then set_cc_for_build # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler # generating 64-bit code. GNU and HP use different nomenclature: # # $ CC_FOR_BUILD=cc ./config.guess # => hppa2.0w-hp-hpux11.23 # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess # => hppa64-hp-hpux11.23 if echo __LP64__ | (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | grep -q __LP64__ then HP_ARCH=hppa2.0w else HP_ARCH=hppa64 fi fi echo "$HP_ARCH"-hp-hpux"$HPUX_REV" exit ;; ia64:HP-UX:*:*) HPUX_REV=`echo "$UNAME_RELEASE"|sed -e 's/[^.]*.[0B]*//'` echo ia64-hp-hpux"$HPUX_REV" exit ;; 3050*:HI-UX:*:*) set_cc_for_build sed 's/^ //' << EOF > "$dummy.c" #include <unistd.h> int main () { long cpu = sysconf (_SC_CPU_VERSION); /* The order matters, because CPU_IS_HP_MC68K erroneously returns true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct |
︙ | ︙ | |||
693 694 695 696 697 698 699 | } else if (CPU_IS_HP_MC68K (cpu)) puts ("m68k-hitachi-hiuxwe2"); else puts ("unknown-hitachi-hiuxwe2"); exit (0); } EOF | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | > > > | > > > > > > > | < > | > | > > > | | < | | | | | | | < < > | | < < < < < | | | < < < | | | | | < < < < < < < < < < < < < < < | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > | | | | | > > > > > > > > > > > > | | | | > > > | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | | | | | | | | | | | | | | | | | | | | > > > | | | | | | | | > > > > > > > > > > | | | | | | | | | | | | | | | | > > > > > > | | | | | | > > > | | | > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > | | | > > > | | | > > > > > > | > | | | | | | | | > > > > > > > > > > > > | < < | | | | > > > > > > > > | | | < < < < < < < < | 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 | } else if (CPU_IS_HP_MC68K (cpu)) puts ("m68k-hitachi-hiuxwe2"); else puts ("unknown-hitachi-hiuxwe2"); exit (0); } EOF $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` && { echo "$SYSTEM_NAME"; exit; } echo unknown-hitachi-hiuxwe2 exit ;; 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:*) echo hppa1.1-hp-bsd exit ;; 9000/8??:4.3bsd:*:*) echo hppa1.0-hp-bsd exit ;; *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) echo hppa1.0-hp-mpeix exit ;; hp7??:OSF1:*:* | hp8?[79]:OSF1:*:*) echo hppa1.1-hp-osf exit ;; hp8??:OSF1:*:*) echo hppa1.0-hp-osf exit ;; i*86:OSF1:*:*) if [ -x /usr/sbin/sysversion ] ; then echo "$UNAME_MACHINE"-unknown-osf1mk else echo "$UNAME_MACHINE"-unknown-osf1 fi exit ;; parisc*:Lites*:*:*) echo hppa1.1-hp-lites exit ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) echo c1-convex-bsd exit ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) echo c34-convex-bsd exit ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) echo c38-convex-bsd exit ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) echo c4-convex-bsd exit ;; CRAY*Y-MP:*:*:*) echo ymp-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*[A-Z]90:*:*:*) echo "$UNAME_MACHINE"-cray-unicos"$UNAME_RELEASE" \ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ -e 's/\.[^.]*$/.X/' exit ;; CRAY*TS:*:*:*) echo t90-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*T3E:*:*:*) echo alphaev5-cray-unicosmk"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*SV1:*:*:*) echo sv1-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' exit ;; *:UNICOS/mp:*:*) echo craynv-cray-unicosmp"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' exit ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) FUJITSU_PROC=`uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` FUJITSU_REL=`echo "$UNAME_RELEASE" | sed -e 's/ /_/'` echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; 5000:UNIX_System_V:4.*:*) FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` FUJITSU_REL=`echo "$UNAME_RELEASE" | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/'` echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) echo "$UNAME_MACHINE"-pc-bsdi"$UNAME_RELEASE" exit ;; sparc*:BSD/OS:*:*) echo sparc-unknown-bsdi"$UNAME_RELEASE" exit ;; *:BSD/OS:*:*) echo "$UNAME_MACHINE"-unknown-bsdi"$UNAME_RELEASE" exit ;; arm:FreeBSD:*:*) UNAME_PROCESSOR=`uname -p` set_cc_for_build if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_PCS_VFP then echo "${UNAME_PROCESSOR}"-unknown-freebsd"`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`"-gnueabi else echo "${UNAME_PROCESSOR}"-unknown-freebsd"`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`"-gnueabihf fi exit ;; *:FreeBSD:*:*) UNAME_PROCESSOR=`/usr/bin/uname -p` case "$UNAME_PROCESSOR" in amd64) UNAME_PROCESSOR=x86_64 ;; i386) UNAME_PROCESSOR=i586 ;; esac echo "$UNAME_PROCESSOR"-unknown-freebsd"`echo "$UNAME_RELEASE"|sed -e 's/[-(].*//'`" exit ;; i*:CYGWIN*:*) echo "$UNAME_MACHINE"-pc-cygwin exit ;; *:MINGW64*:*) echo "$UNAME_MACHINE"-pc-mingw64 exit ;; *:MINGW*:*) echo "$UNAME_MACHINE"-pc-mingw32 exit ;; *:MSYS*:*) echo "$UNAME_MACHINE"-pc-msys exit ;; i*:PW*:*) echo "$UNAME_MACHINE"-pc-pw32 exit ;; *:Interix*:*) case "$UNAME_MACHINE" in x86) echo i586-pc-interix"$UNAME_RELEASE" exit ;; authenticamd | genuineintel | EM64T) echo x86_64-unknown-interix"$UNAME_RELEASE" exit ;; IA64) echo ia64-unknown-interix"$UNAME_RELEASE" exit ;; esac ;; i*:UWIN*:*) echo "$UNAME_MACHINE"-pc-uwin exit ;; amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) echo x86_64-pc-cygwin exit ;; prep*:SunOS:5.*:*) echo powerpcle-unknown-solaris2"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`" exit ;; *:GNU:*:*) # the GNU system echo "`echo "$UNAME_MACHINE"|sed -e 's,[-/].*$,,'`-unknown-$LIBC`echo "$UNAME_RELEASE"|sed -e 's,/.*$,,'`" exit ;; *:GNU/*:*:*) # other systems with GNU libc and userland echo "$UNAME_MACHINE-unknown-`echo "$UNAME_SYSTEM" | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"``echo "$UNAME_RELEASE"|sed -e 's/[-(].*//'`-$LIBC" exit ;; *:Minix:*:*) echo "$UNAME_MACHINE"-unknown-minix exit ;; aarch64:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; aarch64_be:Linux:*:*) UNAME_MACHINE=aarch64_be echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; alpha:Linux:*:*) case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in EV5) UNAME_MACHINE=alphaev5 ;; EV56) UNAME_MACHINE=alphaev56 ;; PCA56) UNAME_MACHINE=alphapca56 ;; PCA57) UNAME_MACHINE=alphapca56 ;; EV6) UNAME_MACHINE=alphaev6 ;; EV67) UNAME_MACHINE=alphaev67 ;; EV68*) UNAME_MACHINE=alphaev68 ;; esac objdump --private-headers /bin/sh | grep -q ld.so.1 if test "$?" = 0 ; then LIBC=gnulibc1 ; fi echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; arc:Linux:*:* | arceb:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; arm*:Linux:*:*) set_cc_for_build if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_EABI__ then echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" else if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_PCS_VFP then echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"eabi else echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"eabihf fi fi exit ;; avr32*:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; cris:Linux:*:*) echo "$UNAME_MACHINE"-axis-linux-"$LIBC" exit ;; crisv32:Linux:*:*) echo "$UNAME_MACHINE"-axis-linux-"$LIBC" exit ;; e2k:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; frv:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; hexagon:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; i*86:Linux:*:*) echo "$UNAME_MACHINE"-pc-linux-"$LIBC" exit ;; ia64:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; k1om:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; m32r*:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; m68*:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; mips:Linux:*:* | mips64:Linux:*:*) set_cc_for_build IS_GLIBC=0 test x"${LIBC}" = xgnu && IS_GLIBC=1 sed 's/^ //' << EOF > "$dummy.c" #undef CPU #undef mips #undef mipsel #undef mips64 #undef mips64el #if ${IS_GLIBC} && defined(_ABI64) LIBCABI=gnuabi64 #else #if ${IS_GLIBC} && defined(_ABIN32) LIBCABI=gnuabin32 #else LIBCABI=${LIBC} #endif #endif #if ${IS_GLIBC} && defined(__mips64) && defined(__mips_isa_rev) && __mips_isa_rev>=6 CPU=mipsisa64r6 #else #if ${IS_GLIBC} && !defined(__mips64) && defined(__mips_isa_rev) && __mips_isa_rev>=6 CPU=mipsisa32r6 #else #if defined(__mips64) CPU=mips64 #else CPU=mips #endif #endif #endif #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) MIPS_ENDIAN=el #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) MIPS_ENDIAN= #else MIPS_ENDIAN= #endif #endif EOF eval "`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^CPU\|^MIPS_ENDIAN\|^LIBCABI'`" test "x$CPU" != x && { echo "$CPU${MIPS_ENDIAN}-unknown-linux-$LIBCABI"; exit; } ;; mips64el:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; openrisc*:Linux:*:*) echo or1k-unknown-linux-"$LIBC" exit ;; or32:Linux:*:* | or1k*:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; padre:Linux:*:*) echo sparc-unknown-linux-"$LIBC" exit ;; parisc64:Linux:*:* | hppa64:Linux:*:*) echo hppa64-unknown-linux-"$LIBC" exit ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in PA7*) echo hppa1.1-unknown-linux-"$LIBC" ;; PA8*) echo hppa2.0-unknown-linux-"$LIBC" ;; *) echo hppa-unknown-linux-"$LIBC" ;; esac exit ;; ppc64:Linux:*:*) echo powerpc64-unknown-linux-"$LIBC" exit ;; ppc:Linux:*:*) echo powerpc-unknown-linux-"$LIBC" exit ;; ppc64le:Linux:*:*) echo powerpc64le-unknown-linux-"$LIBC" exit ;; ppcle:Linux:*:*) echo powerpcle-unknown-linux-"$LIBC" exit ;; riscv32:Linux:*:* | riscv64:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; s390:Linux:*:* | s390x:Linux:*:*) echo "$UNAME_MACHINE"-ibm-linux-"$LIBC" exit ;; sh64*:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; sh*:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; sparc:Linux:*:* | sparc64:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; tile*:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; vax:Linux:*:*) echo "$UNAME_MACHINE"-dec-linux-"$LIBC" exit ;; x86_64:Linux:*:*) echo "$UNAME_MACHINE"-pc-linux-"$LIBC" exit ;; xtensa*:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; i*86:DYNIX/ptx:4*:*) # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. # earlier versions are messed up and put the nodename in both # sysname and nodename. echo i386-sequent-sysv4 exit ;; i*86:UNIX_SV:4.2MP:2.*) # Unixware is an offshoot of SVR4, but it has its own version # number series starting with 2... # I am not positive that other SVR4 systems won't match this, # I just have to hope. -- rms. # Use sysv4.2uw... so that sysv4* matches it. echo "$UNAME_MACHINE"-pc-sysv4.2uw"$UNAME_VERSION" exit ;; i*86:OS/2:*:*) # If we were able to find `uname', then EMX Unix compatibility # is probably installed. echo "$UNAME_MACHINE"-pc-os2-emx exit ;; i*86:XTS-300:*:STOP) echo "$UNAME_MACHINE"-unknown-stop exit ;; i*86:atheos:*:*) echo "$UNAME_MACHINE"-unknown-atheos exit ;; i*86:syllable:*:*) echo "$UNAME_MACHINE"-pc-syllable exit ;; i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) echo i386-unknown-lynxos"$UNAME_RELEASE" exit ;; i*86:*DOS:*:*) echo "$UNAME_MACHINE"-pc-msdosdjgpp exit ;; i*86:*:4.*:*) UNAME_REL=`echo "$UNAME_RELEASE" | sed 's/\/MP$//'` if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then echo "$UNAME_MACHINE"-univel-sysv"$UNAME_REL" else echo "$UNAME_MACHINE"-pc-sysv"$UNAME_REL" fi exit ;; i*86:*:5:[678]*) # UnixWare 7.x, OpenUNIX and OpenServer 6. case `/bin/uname -X | grep "^Machine"` in *486*) UNAME_MACHINE=i486 ;; *Pentium) UNAME_MACHINE=i586 ;; *Pent*|*Celeron) UNAME_MACHINE=i686 ;; esac echo "$UNAME_MACHINE-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}" exit ;; i*86:*:3.2:*) if test -f /usr/options/cb.name; then UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name` echo "$UNAME_MACHINE"-pc-isc"$UNAME_REL" elif /bin/uname -X 2>/dev/null >/dev/null ; then UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ && UNAME_MACHINE=i586 (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ && UNAME_MACHINE=i686 (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ && UNAME_MACHINE=i686 echo "$UNAME_MACHINE"-pc-sco"$UNAME_REL" else echo "$UNAME_MACHINE"-pc-sysv32 fi exit ;; pc:*:*:*) # Left here for compatibility: # uname -m prints for DJGPP always 'pc', but it prints nothing about # the processor, so we play safe by assuming i586. # Note: whatever this is, it MUST be the same as what config.sub # prints for the "djgpp" host, or else GDB configure will decide that # this is a cross-build. echo i586-pc-msdosdjgpp exit ;; Intel:Mach:3*:*) echo i386-pc-mach3 exit ;; paragon:*:*:*) echo i860-intel-osf1 exit ;; i860:*:4.*:*) # i860-SVR4 if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then echo i860-stardent-sysv"$UNAME_RELEASE" # Stardent Vistra i860-SVR4 else # Add other i860-SVR4 vendors below as they are discovered. echo i860-unknown-sysv"$UNAME_RELEASE" # Unknown i860-SVR4 fi exit ;; mini*:CTIX:SYS*5:*) # "miniframe" echo m68010-convergent-sysv exit ;; mc68k:UNIX:SYSTEM5:3.51m) echo m68k-convergent-sysv exit ;; M680?0:D-NIX:5.3:*) echo m68k-diab-dnix exit ;; M68*:*:R3V[5678]*:*) test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) OS_REL='' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3"$OS_REL"; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4; exit; } ;; NCR*:*:4.2:* | MPRAS*:*:4.2:*) OS_REL='.3' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3"$OS_REL"; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;; m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) echo m68k-unknown-lynxos"$UNAME_RELEASE" exit ;; mc68030:UNIX_System_V:4.*:*) echo m68k-atari-sysv4 exit ;; TSUNAMI:LynxOS:2.*:*) echo sparc-unknown-lynxos"$UNAME_RELEASE" exit ;; rs6000:LynxOS:2.*:*) echo rs6000-unknown-lynxos"$UNAME_RELEASE" exit ;; PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) echo powerpc-unknown-lynxos"$UNAME_RELEASE" exit ;; SM[BE]S:UNIX_SV:*:*) echo mips-dde-sysv"$UNAME_RELEASE" exit ;; RM*:ReliantUNIX-*:*:*) echo mips-sni-sysv4 exit ;; RM*:SINIX-*:*:*) echo mips-sni-sysv4 exit ;; *:SINIX-*:*:*) if uname -p 2>/dev/null >/dev/null ; then UNAME_MACHINE=`(uname -p) 2>/dev/null` echo "$UNAME_MACHINE"-sni-sysv4 else echo ns32k-sni-sysv fi exit ;; PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort # says <Richard.M.Bartel@ccMail.Census.GOV> echo i586-unisys-sysv4 exit ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes <hewes@openmarket.com>. # How about differentiating between stratus architectures? -djm echo hppa1.1-stratus-sysv4 exit ;; *:*:*:FTX*) # From seanf@swdc.stratus.com. echo i860-stratus-sysv4 exit ;; i*86:VOS:*:*) # From Paul.Green@stratus.com. echo "$UNAME_MACHINE"-stratus-vos exit ;; *:VOS:*:*) # From Paul.Green@stratus.com. echo hppa1.1-stratus-vos exit ;; mc68*:A/UX:*:*) echo m68k-apple-aux"$UNAME_RELEASE" exit ;; news*:NEWS-OS:6*:*) echo mips-sony-newsos6 exit ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) if [ -d /usr/nec ]; then echo mips-nec-sysv"$UNAME_RELEASE" else echo mips-unknown-sysv"$UNAME_RELEASE" fi exit ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. echo powerpc-be-beos exit ;; BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. echo powerpc-apple-beos exit ;; BePC:BeOS:*:*) # BeOS running on Intel PC compatible. echo i586-pc-beos exit ;; BePC:Haiku:*:*) # Haiku running on Intel PC compatible. echo i586-pc-haiku exit ;; x86_64:Haiku:*:*) echo x86_64-unknown-haiku exit ;; SX-4:SUPER-UX:*:*) echo sx4-nec-superux"$UNAME_RELEASE" exit ;; SX-5:SUPER-UX:*:*) echo sx5-nec-superux"$UNAME_RELEASE" exit ;; SX-6:SUPER-UX:*:*) echo sx6-nec-superux"$UNAME_RELEASE" exit ;; SX-7:SUPER-UX:*:*) echo sx7-nec-superux"$UNAME_RELEASE" exit ;; SX-8:SUPER-UX:*:*) echo sx8-nec-superux"$UNAME_RELEASE" exit ;; SX-8R:SUPER-UX:*:*) echo sx8r-nec-superux"$UNAME_RELEASE" exit ;; SX-ACE:SUPER-UX:*:*) echo sxace-nec-superux"$UNAME_RELEASE" exit ;; Power*:Rhapsody:*:*) echo powerpc-apple-rhapsody"$UNAME_RELEASE" exit ;; *:Rhapsody:*:*) echo "$UNAME_MACHINE"-apple-rhapsody"$UNAME_RELEASE" exit ;; *:Darwin:*:*) UNAME_PROCESSOR=`uname -p` case $UNAME_PROCESSOR in unknown) UNAME_PROCESSOR=powerpc ;; esac if command -v xcode-select > /dev/null 2> /dev/null && \ ! xcode-select --print-path > /dev/null 2> /dev/null ; then # Avoid executing cc if there is no toolchain installed as # cc will be a stub that puts up a graphical alert # prompting the user to install developer tools. CC_FOR_BUILD=no_compiler_found else set_cc_for_build fi if [ "$CC_FOR_BUILD" != no_compiler_found ]; then if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then case $UNAME_PROCESSOR in i386) UNAME_PROCESSOR=x86_64 ;; powerpc) UNAME_PROCESSOR=powerpc64 ;; esac fi # On 10.4-10.6 one might compile for PowerPC via gcc -arch ppc if (echo '#ifdef __POWERPC__'; echo IS_PPC; echo '#endif') | \ (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_PPC >/dev/null then UNAME_PROCESSOR=powerpc fi elif test "$UNAME_PROCESSOR" = i386 ; then # uname -m returns i386 or x86_64 UNAME_PROCESSOR=$UNAME_MACHINE fi echo "$UNAME_PROCESSOR"-apple-darwin"$UNAME_RELEASE" exit ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) UNAME_PROCESSOR=`uname -p` if test "$UNAME_PROCESSOR" = x86; then UNAME_PROCESSOR=i386 UNAME_MACHINE=pc fi echo "$UNAME_PROCESSOR"-"$UNAME_MACHINE"-nto-qnx"$UNAME_RELEASE" exit ;; *:QNX:*:4*) echo i386-pc-qnx exit ;; NEO-*:NONSTOP_KERNEL:*:*) echo neo-tandem-nsk"$UNAME_RELEASE" exit ;; NSE-*:NONSTOP_KERNEL:*:*) echo nse-tandem-nsk"$UNAME_RELEASE" exit ;; NSR-*:NONSTOP_KERNEL:*:*) echo nsr-tandem-nsk"$UNAME_RELEASE" exit ;; NSV-*:NONSTOP_KERNEL:*:*) echo nsv-tandem-nsk"$UNAME_RELEASE" exit ;; NSX-*:NONSTOP_KERNEL:*:*) echo nsx-tandem-nsk"$UNAME_RELEASE" exit ;; *:NonStop-UX:*:*) echo mips-compaq-nonstopux exit ;; BS2000:POSIX*:*:*) echo bs2000-siemens-sysv exit ;; DS/*:UNIX_System_V:*:*) echo "$UNAME_MACHINE"-"$UNAME_SYSTEM"-"$UNAME_RELEASE" exit ;; *:Plan9:*:*) # "uname -m" is not consistent, so use $cputype instead. 386 # is converted to i386 for consistency with other x86 # operating systems. # shellcheck disable=SC2154 if test "$cputype" = 386; then UNAME_MACHINE=i386 else UNAME_MACHINE="$cputype" fi echo "$UNAME_MACHINE"-unknown-plan9 exit ;; *:TOPS-10:*:*) echo pdp10-unknown-tops10 exit ;; *:TENEX:*:*) echo pdp10-unknown-tenex exit ;; KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) echo pdp10-dec-tops20 exit ;; XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) echo pdp10-xkl-tops20 exit ;; *:TOPS-20:*:*) echo pdp10-unknown-tops20 exit ;; *:ITS:*:*) echo pdp10-unknown-its exit ;; SEI:*:*:SEIUX) echo mips-sei-seiux"$UNAME_RELEASE" exit ;; *:DragonFly:*:*) echo "$UNAME_MACHINE"-unknown-dragonfly"`echo "$UNAME_RELEASE"|sed -e 's/[-(].*//'`" exit ;; *:*VMS:*:*) UNAME_MACHINE=`(uname -p) 2>/dev/null` case "$UNAME_MACHINE" in A*) echo alpha-dec-vms ; exit ;; I*) echo ia64-dec-vms ; exit ;; V*) echo vax-dec-vms ; exit ;; esac ;; *:XENIX:*:SysV) echo i386-pc-xenix exit ;; i*86:skyos:*:*) echo "$UNAME_MACHINE"-pc-skyos"`echo "$UNAME_RELEASE" | sed -e 's/ .*$//'`" exit ;; i*86:rdos:*:*) echo "$UNAME_MACHINE"-pc-rdos exit ;; i*86:AROS:*:*) echo "$UNAME_MACHINE"-pc-aros exit ;; x86_64:VMkernel:*:*) echo "$UNAME_MACHINE"-unknown-esx exit ;; amd64:Isilon\ OneFS:*:*) echo x86_64-unknown-onefs exit ;; *:Unleashed:*:*) echo "$UNAME_MACHINE"-unknown-unleashed"$UNAME_RELEASE" exit ;; esac # No uname command or uname output not recognized. set_cc_for_build cat > "$dummy.c" <<EOF #ifdef _SEQUENT_ #include <sys/types.h> #include <sys/utsname.h> #endif #if defined(ultrix) || defined(_ultrix) || defined(__ultrix) || defined(__ultrix__) #if defined (vax) || defined (__vax) || defined (__vax__) || defined(mips) || defined(__mips) || defined(__mips__) || defined(MIPS) || defined(__MIPS__) #include <signal.h> #if defined(_SIZE_T_) || defined(SIGLOST) #include <sys/utsname.h> #endif #endif #endif main () { #if defined (sony) #if defined (MIPSEB) /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, I don't know.... */ printf ("mips-sony-bsd\n"); exit (0); #else #include <sys/param.h> printf ("m68k-sony-newsos%s\n", #ifdef NEWSOS4 "4" #else "" #endif ); exit (0); #endif #endif #if defined (NeXT) #if !defined (__ARCHITECTURE__) #define __ARCHITECTURE__ "m68k" #endif int version; |
︙ | ︙ | |||
1406 1407 1408 1409 1410 1411 1412 | #endif #if defined (ns32000) printf ("ns32k-sequent-dynix\n"); exit (0); #endif #endif #if defined (_SEQUENT_) | | | < | | | | | | | < | | | | | | | | | | | | | | | | > > > > > | | > > > > > > > > > > > > | > | < > > > > < > | < < < > | < < < < < < < < < < < < < < < | < < | | | | | < | | | | | | | | | 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 | #endif #if defined (ns32000) printf ("ns32k-sequent-dynix\n"); exit (0); #endif #endif #if defined (_SEQUENT_) struct utsname un; uname(&un); if (strncmp(un.version, "V2", 2) == 0) { printf ("i386-sequent-ptx2\n"); exit (0); } if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ printf ("i386-sequent-ptx1\n"); exit (0); } printf ("i386-sequent-ptx\n"); exit (0); #endif #if defined (vax) #if !defined (ultrix) #include <sys/param.h> #if defined (BSD) #if BSD == 43 printf ("vax-dec-bsd4.3\n"); exit (0); #else #if BSD == 199006 printf ("vax-dec-bsd4.3reno\n"); exit (0); #else printf ("vax-dec-bsd\n"); exit (0); #endif #endif #else printf ("vax-dec-bsd\n"); exit (0); #endif #else #if defined(_SIZE_T_) || defined(SIGLOST) struct utsname un; uname (&un); printf ("vax-dec-ultrix%s\n", un.release); exit (0); #else printf ("vax-dec-ultrix\n"); exit (0); #endif #endif #endif #if defined(ultrix) || defined(_ultrix) || defined(__ultrix) || defined(__ultrix__) #if defined(mips) || defined(__mips) || defined(__mips__) || defined(MIPS) || defined(__MIPS__) #if defined(_SIZE_T_) || defined(SIGLOST) struct utsname *un; uname (&un); printf ("mips-dec-ultrix%s\n", un.release); exit (0); #else printf ("mips-dec-ultrix\n"); exit (0); #endif #endif #endif #if defined (alliant) && defined (i860) printf ("i860-alliant-bsd\n"); exit (0); #endif exit (1); } EOF $CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null && SYSTEM_NAME=`$dummy` && { echo "$SYSTEM_NAME"; exit; } # Apollos put the system type in the environment. test -d /usr/apollo && { echo "$ISP-apollo-$SYSTYPE"; exit; } echo "$0: unable to guess system type" >&2 case "$UNAME_MACHINE:$UNAME_SYSTEM" in mips:Linux | mips64:Linux) # If we got here on MIPS GNU/Linux, output extra information. cat >&2 <<EOF NOTE: MIPS GNU/Linux systems require a C compiler to fully recognize the system type. Please install a C compiler and try again. EOF ;; esac cat >&2 <<EOF This script (version $timestamp), has failed to recognize the operating system you are using. If your script is old, overwrite *all* copies of config.guess and config.sub with the latest versions from: https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess and https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub If $0 has already been updated, send the following data and any information you think might be pertinent to config-patches@gnu.org to provide the necessary information to handle your system. config.guess timestamp = $timestamp uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` /bin/uname -X = `(/bin/uname -X) 2>/dev/null` hostinfo = `(hostinfo) 2>/dev/null` /bin/universe = `(/bin/universe) 2>/dev/null` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` /bin/arch = `(/bin/arch) 2>/dev/null` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` UNAME_MACHINE = "$UNAME_MACHINE" UNAME_RELEASE = "$UNAME_RELEASE" UNAME_SYSTEM = "$UNAME_SYSTEM" UNAME_VERSION = "$UNAME_VERSION" EOF exit 1 # Local variables: # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: |
Changes to config.sub.
1 2 | #! /bin/sh # Configuration validation subroutine script. | < | < | < < < < | | | | | | | | < < | > > | < > > > | < | < | | 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 | #! /bin/sh # Configuration validation subroutine script. # Copyright 1992-2019 Free Software Foundation, Inc. timestamp='2019-05-23' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see <https://www.gnu.org/licenses/>. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that # program. This Exception is an additional permission under section 7 # of the GNU General Public License, version 3 ("GPLv3"). # Please send patches to <config-patches@gnu.org>. # # Configuration subroutine to validate and canonicalize a configuration type. # Supply the specified configuration type as an argument. # If it is invalid, we print an error message on stderr and exit with code 1. # Otherwise, we print the canonical config type on stdout and succeed. # You can get the latest version of this script from: # https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases # that are meaningful with *any* GNU software. # Each package is responsible for reporting which valid configurations # it does not support. The user should be able to distinguish # a failure to support a valid configuration from a meaningless # configuration. # The goal of this file is to map all the various variations of a given # machine specification into a single specification in the form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM # or in some cases, the newer four-part form: # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # It is wrong to echo any other type of specification. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS Canonicalize a configuration name. Options: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to <config-patches@gnu.org>." version="\ GNU config.sub ($timestamp) Copyright 1992-2019 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." |
︙ | ︙ | |||
91 92 93 94 95 96 97 | --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) | | | > > > > > | > > > > > > > > > > > | > | | | > | > | > | > > | > | | > > > > > > > > > | > > > > > > > | | > > > > > > > > > > > > | | > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | < > > > | > > > | > > > > > > > | > | > > | < < | < < < | | > > > > > > | > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > | > > | > | > > | | > > > > | > | > > | > > > > > | > > | > > > | > > | > | > > | > > > > > > > | > > | > | > > > > > > > | > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > | > > > | > > > > > > | > | | > | > > | > | | > | > > | > | > > > > > > > > > | | > > > > > > | > | > > > > | < > > > > | > | > > > > > > > > > > > > > > > > > > > > > > > > | < > > > > > > > > > > > > | > | > > | > > > | > > | > | > > > > > > > > > > > > > > > > | | > | > > > > > > > > > > | > > > > > > > > > > > | > > | > | > > > > | | > | > > | > > | > | | > | | | > > > > | > | > | > > > > | | > > | > > > | | > > > > > > > > > > > > > > > > > > > > > > > > > > | > > | > > > > | | | > > | | | > > > > | > > > > > > > > > > > > > > > | < < > > > | > > > | > > > > > > | > > > > | > > > | > | < < > > | > > > > | > > > > > > > > > | < > > > > | | | < > | | | < > | | > > | > > > > | > > > | > > > > > > > > > > > > > > > | > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > | > > > > | | > | > > > > > | > > > > > > > | > > | < | > > > > > | < | | < > > > > > > > > > > > > | < > > | > > > > > > > | < > > > > > > | < > | > | > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > < > > > > | | > > > > > > | > | < < > | > | > > > > > | | < < < < < < | < < < > > | < < < < < < | | | | | | | | | | < > | | | < > | | < < > | < < < | < < > | > > > > > | < < < < < < < | > | < < | < < < < < | | < > | > > > | | < < | > < | > > | | > | < | < < < < < < < | | < < > | < < < < | < < < < < < < < < < < < < < < < < < | < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < | < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < | < < < | < < < < < < | < < < < < < < < < < < < < | | | | > > > > | < > > > | > > > > > > > | > > > > > | < > | < > | > < < | > > > > | | < < > | < | < > > | > | < | < | | | | | | | > | < > > > | > > > | < > | | > | < | < < > | < | | > | | > | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < | < < < < < < < < < < | < | | < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | > > | | < > | | | | | | > > > > > > | | | < < < | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | | > | | | | | | | | | | | | | > | | | | | | | | | > > | | | > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < | | | | | | | | | | | > > > > > > > > > > > > > > > > > > | | | | | | < < < | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | < < < | | | | | | | | | | | > > > | | < | | | | | | | | | | | | > > > | | | | | | | | | | < | | | 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 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 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 | --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; *local*) # First pass through any local machine types. echo "$1" exit ;; * ) break ;; esac done case $# in 0) echo "$me: missing argument$help" >&2 exit 1;; 1) ;; *) echo "$me: too many arguments$help" >&2 exit 1;; esac # Split fields of configuration type # shellcheck disable=SC2162 IFS="-" read field1 field2 field3 field4 <<EOF $1 EOF # Separate into logical components for further validation case $1 in *-*-*-*-*) echo Invalid configuration \`"$1"\': more than four components >&2 exit 1 ;; *-*-*-*) basic_machine=$field1-$field2 os=$field3-$field4 ;; *-*-*) # Ambiguous whether COMPANY is present, or skipped and KERNEL-OS is two # parts maybe_os=$field2-$field3 case $maybe_os in nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc \ | linux-newlib* | linux-musl* | linux-uclibc* | uclinux-uclibc* \ | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* \ | netbsd*-eabi* | kopensolaris*-gnu* | cloudabi*-eabi* \ | storm-chaos* | os2-emx* | rtmk-nova*) basic_machine=$field1 os=$maybe_os ;; android-linux) basic_machine=$field1-unknown os=linux-android ;; *) basic_machine=$field1-$field2 os=$field3 ;; esac ;; *-*) # A lone config we happen to match not fitting any pattern case $field1-$field2 in decstation-3100) basic_machine=mips-dec os= ;; *-*) # Second component is usually, but not always the OS case $field2 in # Prevent following clause from handling this valid os sun*os*) basic_machine=$field1 os=$field2 ;; # Manufacturers dec* | mips* | sequent* | encore* | pc533* | sgi* | sony* \ | att* | 7300* | 3300* | delta* | motorola* | sun[234]* \ | unicom* | ibm* | next | hp | isi* | apollo | altos* \ | convergent* | ncr* | news | 32* | 3600* | 3100* \ | hitachi* | c[123]* | convex* | sun | crds | omron* | dg \ | ultra | tti* | harris | dolphin | highlevel | gould \ | cbm | ns | masscomp | apple | axis | knuth | cray \ | microblaze* | sim | cisco \ | oki | wec | wrs | winbond) basic_machine=$field1-$field2 os= ;; *) basic_machine=$field1 os=$field2 ;; esac ;; esac ;; *) # Convert single-component short-hands not valid as part of # multi-component configurations. case $field1 in 386bsd) basic_machine=i386-pc os=bsd ;; a29khif) basic_machine=a29k-amd os=udi ;; adobe68k) basic_machine=m68010-adobe os=scout ;; alliant) basic_machine=fx80-alliant os= ;; altos | altos3068) basic_machine=m68k-altos os= ;; am29k) basic_machine=a29k-none os=bsd ;; amdahl) basic_machine=580-amdahl os=sysv ;; amiga) basic_machine=m68k-unknown os= ;; amigaos | amigados) basic_machine=m68k-unknown os=amigaos ;; amigaunix | amix) basic_machine=m68k-unknown os=sysv4 ;; apollo68) basic_machine=m68k-apollo os=sysv ;; apollo68bsd) basic_machine=m68k-apollo os=bsd ;; aros) basic_machine=i386-pc os=aros ;; aux) basic_machine=m68k-apple os=aux ;; balance) basic_machine=ns32k-sequent os=dynix ;; blackfin) basic_machine=bfin-unknown os=linux ;; cegcc) basic_machine=arm-unknown os=cegcc ;; convex-c1) basic_machine=c1-convex os=bsd ;; convex-c2) basic_machine=c2-convex os=bsd ;; convex-c32) basic_machine=c32-convex os=bsd ;; convex-c34) basic_machine=c34-convex os=bsd ;; convex-c38) basic_machine=c38-convex os=bsd ;; cray) basic_machine=j90-cray os=unicos ;; crds | unos) basic_machine=m68k-crds os= ;; da30) basic_machine=m68k-da30 os= ;; decstation | pmax | pmin | dec3100 | decstatn) basic_machine=mips-dec os= ;; delta88) basic_machine=m88k-motorola os=sysv3 ;; dicos) basic_machine=i686-pc os=dicos ;; djgpp) basic_machine=i586-pc os=msdosdjgpp ;; ebmon29k) basic_machine=a29k-amd os=ebmon ;; es1800 | OSE68k | ose68k | ose | OSE) basic_machine=m68k-ericsson os=ose ;; gmicro) basic_machine=tron-gmicro os=sysv ;; go32) basic_machine=i386-pc os=go32 ;; h8300hms) basic_machine=h8300-hitachi os=hms ;; h8300xray) basic_machine=h8300-hitachi os=xray ;; h8500hms) basic_machine=h8500-hitachi os=hms ;; harris) basic_machine=m88k-harris os=sysv3 ;; hp300) basic_machine=m68k-hp ;; hp300bsd) basic_machine=m68k-hp os=bsd ;; hp300hpux) basic_machine=m68k-hp os=hpux ;; hppaosf) basic_machine=hppa1.1-hp os=osf ;; hppro) basic_machine=hppa1.1-hp os=proelf ;; i386mach) basic_machine=i386-mach os=mach ;; vsta) basic_machine=i386-pc os=vsta ;; isi68 | isi) basic_machine=m68k-isi os=sysv ;; m68knommu) basic_machine=m68k-unknown os=linux ;; magnum | m3230) basic_machine=mips-mips os=sysv ;; merlin) basic_machine=ns32k-utek os=sysv ;; mingw64) basic_machine=x86_64-pc os=mingw64 ;; mingw32) basic_machine=i686-pc os=mingw32 ;; mingw32ce) basic_machine=arm-unknown os=mingw32ce ;; monitor) basic_machine=m68k-rom68k os=coff ;; morphos) basic_machine=powerpc-unknown os=morphos ;; moxiebox) basic_machine=moxie-unknown os=moxiebox ;; msdos) basic_machine=i386-pc os=msdos ;; msys) basic_machine=i686-pc os=msys ;; mvs) basic_machine=i370-ibm os=mvs ;; nacl) basic_machine=le32-unknown os=nacl ;; ncr3000) basic_machine=i486-ncr os=sysv4 ;; netbsd386) basic_machine=i386-pc os=netbsd ;; netwinder) basic_machine=armv4l-rebel os=linux ;; news | news700 | news800 | news900) basic_machine=m68k-sony os=newsos ;; news1000) basic_machine=m68030-sony os=newsos ;; necv70) basic_machine=v70-nec os=sysv ;; nh3000) basic_machine=m68k-harris os=cxux ;; nh[45]000) basic_machine=m88k-harris os=cxux ;; nindy960) basic_machine=i960-intel os=nindy ;; mon960) basic_machine=i960-intel os=mon960 ;; nonstopux) basic_machine=mips-compaq os=nonstopux ;; os400) basic_machine=powerpc-ibm os=os400 ;; OSE68000 | ose68000) basic_machine=m68000-ericsson os=ose ;; os68k) basic_machine=m68k-none os=os68k ;; paragon) basic_machine=i860-intel os=osf ;; parisc) basic_machine=hppa-unknown os=linux ;; pw32) basic_machine=i586-unknown os=pw32 ;; rdos | rdos64) basic_machine=x86_64-pc os=rdos ;; rdos32) basic_machine=i386-pc os=rdos ;; rom68k) basic_machine=m68k-rom68k os=coff ;; sa29200) basic_machine=a29k-amd os=udi ;; sei) basic_machine=mips-sei os=seiux ;; sequent) basic_machine=i386-sequent os= ;; sps7) basic_machine=m68k-bull os=sysv2 ;; st2000) basic_machine=m68k-tandem os= ;; stratus) basic_machine=i860-stratus os=sysv4 ;; sun2) basic_machine=m68000-sun os= ;; sun2os3) basic_machine=m68000-sun os=sunos3 ;; sun2os4) basic_machine=m68000-sun os=sunos4 ;; sun3) basic_machine=m68k-sun os= ;; sun3os3) basic_machine=m68k-sun os=sunos3 ;; sun3os4) basic_machine=m68k-sun os=sunos4 ;; sun4) basic_machine=sparc-sun os= ;; sun4os3) basic_machine=sparc-sun os=sunos3 ;; sun4os4) basic_machine=sparc-sun os=sunos4 ;; sun4sol2) basic_machine=sparc-sun os=solaris2 ;; sun386 | sun386i | roadrunner) basic_machine=i386-sun os= ;; sv1) basic_machine=sv1-cray os=unicos ;; symmetry) basic_machine=i386-sequent os=dynix ;; t3e) basic_machine=alphaev5-cray os=unicos ;; t90) basic_machine=t90-cray os=unicos ;; toad1) basic_machine=pdp10-xkl os=tops20 ;; tpf) basic_machine=s390x-ibm os=tpf ;; udi29k) basic_machine=a29k-amd os=udi ;; ultra3) basic_machine=a29k-nyu os=sym1 ;; v810 | necv810) basic_machine=v810-nec os=none ;; vaxv) basic_machine=vax-dec os=sysv ;; vms) basic_machine=vax-dec os=vms ;; vxworks960) basic_machine=i960-wrs os=vxworks ;; vxworks68) basic_machine=m68k-wrs os=vxworks ;; vxworks29k) basic_machine=a29k-wrs os=vxworks ;; xbox) basic_machine=i686-pc os=mingw32 ;; ymp) basic_machine=ymp-cray os=unicos ;; *) basic_machine=$1 os= ;; esac ;; esac # Decode 1-component or ad-hoc basic machines case $basic_machine in # Here we handle the default manufacturer of certain CPU types. It is in # some cases the only manufacturer, in others, it is the most popular. w89k) cpu=hppa1.1 vendor=winbond ;; op50n) cpu=hppa1.1 vendor=oki ;; op60c) cpu=hppa1.1 vendor=oki ;; ibm*) cpu=i370 vendor=ibm ;; orion105) cpu=clipper vendor=highlevel ;; mac | mpw | mac-mpw) cpu=m68k vendor=apple ;; pmac | pmac-mpw) cpu=powerpc vendor=apple ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) cpu=m68000 vendor=att ;; 3b*) cpu=we32k vendor=att ;; bluegene*) cpu=powerpc vendor=ibm os=cnk ;; decsystem10* | dec10*) cpu=pdp10 vendor=dec os=tops10 ;; decsystem20* | dec20*) cpu=pdp10 vendor=dec os=tops20 ;; delta | 3300 | motorola-3300 | motorola-delta \ | 3300-motorola | delta-motorola) cpu=m68k vendor=motorola ;; dpx2*) cpu=m68k vendor=bull os=sysv3 ;; encore | umax | mmax) cpu=ns32k vendor=encore ;; elxsi) cpu=elxsi vendor=elxsi os=${os:-bsd} ;; fx2800) cpu=i860 vendor=alliant ;; genix) cpu=ns32k vendor=ns ;; h3050r* | hiux*) cpu=hppa1.1 vendor=hitachi os=hiuxwe2 ;; hp3k9[0-9][0-9] | hp9[0-9][0-9]) cpu=hppa1.0 vendor=hp ;; hp9k2[0-9][0-9] | hp9k31[0-9]) cpu=m68000 vendor=hp ;; hp9k3[2-9][0-9]) cpu=m68k vendor=hp ;; hp9k6[0-9][0-9] | hp6[0-9][0-9]) cpu=hppa1.0 vendor=hp ;; hp9k7[0-79][0-9] | hp7[0-79][0-9]) cpu=hppa1.1 vendor=hp ;; hp9k78[0-9] | hp78[0-9]) # FIXME: really hppa2.0-hp cpu=hppa1.1 vendor=hp ;; hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) # FIXME: really hppa2.0-hp cpu=hppa1.1 vendor=hp ;; hp9k8[0-9][13679] | hp8[0-9][13679]) cpu=hppa1.1 vendor=hp ;; hp9k8[0-9][0-9] | hp8[0-9][0-9]) cpu=hppa1.0 vendor=hp ;; i*86v32) cpu=`echo "$1" | sed -e 's/86.*/86/'` vendor=pc os=sysv32 ;; i*86v4*) cpu=`echo "$1" | sed -e 's/86.*/86/'` vendor=pc os=sysv4 ;; i*86v) cpu=`echo "$1" | sed -e 's/86.*/86/'` vendor=pc os=sysv ;; i*86sol2) cpu=`echo "$1" | sed -e 's/86.*/86/'` vendor=pc os=solaris2 ;; j90 | j90-cray) cpu=j90 vendor=cray os=${os:-unicos} ;; iris | iris4d) cpu=mips vendor=sgi case $os in irix*) ;; *) os=irix4 ;; esac ;; miniframe) cpu=m68000 vendor=convergent ;; *mint | mint[0-9]* | *MiNT | *MiNT[0-9]*) cpu=m68k vendor=atari os=mint ;; news-3600 | risc-news) cpu=mips vendor=sony os=newsos ;; next | m*-next) cpu=m68k vendor=next case $os in openstep*) ;; nextstep*) ;; ns2*) os=nextstep2 ;; *) os=nextstep3 ;; esac ;; np1) cpu=np1 vendor=gould ;; op50n-* | op60c-*) cpu=hppa1.1 vendor=oki os=proelf ;; pa-hitachi) cpu=hppa1.1 vendor=hitachi os=hiuxwe2 ;; pbd) cpu=sparc vendor=tti ;; pbb) cpu=m68k vendor=tti ;; pc532) cpu=ns32k vendor=pc532 ;; pn) cpu=pn vendor=gould ;; power) cpu=power vendor=ibm ;; ps2) cpu=i386 vendor=ibm ;; rm[46]00) cpu=mips vendor=siemens ;; rtpc | rtpc-*) cpu=romp vendor=ibm ;; sde) cpu=mipsisa32 vendor=sde os=${os:-elf} ;; simso-wrs) cpu=sparclite vendor=wrs os=vxworks ;; tower | tower-32) cpu=m68k vendor=ncr ;; vpp*|vx|vx-*) cpu=f301 vendor=fujitsu ;; w65) cpu=w65 vendor=wdc ;; w89k-*) cpu=hppa1.1 vendor=winbond os=proelf ;; none) cpu=none vendor=none ;; leon|leon[3-9]) cpu=sparc vendor=$basic_machine ;; leon-*|leon[3-9]-*) cpu=sparc vendor=`echo "$basic_machine" | sed 's/-.*//'` ;; *-*) # shellcheck disable=SC2162 IFS="-" read cpu vendor <<EOF $basic_machine EOF ;; # We use `pc' rather than `unknown' # because (1) that's what they normally are, and # (2) the word "unknown" tends to confuse beginning users. i*86 | x86_64) cpu=$basic_machine vendor=pc ;; # These rules are duplicated from below for sake of the special case above; # i.e. things that normalized to x86 arches should also default to "pc" pc98) cpu=i386 vendor=pc ;; x64 | amd64) cpu=x86_64 vendor=pc ;; # Recognize the basic CPU types without company name. *) cpu=$basic_machine vendor=unknown ;; esac unset -v basic_machine # Decode basic machines in the full and proper CPU-Company form. case $cpu-$vendor in # Here we handle the default manufacturer of certain CPU types in canonical form. It is in # some cases the only manufacturer, in others, it is the most popular. craynv-unknown) vendor=cray os=${os:-unicosmp} ;; c90-unknown | c90-cray) vendor=cray os=${os:-unicos} ;; fx80-unknown) vendor=alliant ;; romp-unknown) vendor=ibm ;; mmix-unknown) vendor=knuth ;; microblaze-unknown | microblazeel-unknown) vendor=xilinx ;; rs6000-unknown) vendor=ibm ;; vax-unknown) vendor=dec ;; pdp11-unknown) vendor=dec ;; we32k-unknown) vendor=att ;; cydra-unknown) vendor=cydrome ;; i370-ibm*) vendor=ibm ;; orion-unknown) vendor=highlevel ;; xps-unknown | xps100-unknown) cpu=xps100 vendor=honeywell ;; # Here we normalize CPU types with a missing or matching vendor dpx20-unknown | dpx20-bull) cpu=rs6000 vendor=bull os=${os:-bosx} ;; # Here we normalize CPU types irrespective of the vendor amd64-*) cpu=x86_64 ;; blackfin-*) cpu=bfin os=linux ;; c54x-*) cpu=tic54x ;; c55x-*) cpu=tic55x ;; c6x-*) cpu=tic6x ;; e500v[12]-*) cpu=powerpc os=$os"spe" ;; mips3*-*) cpu=mips64 ;; ms1-*) cpu=mt ;; m68knommu-*) cpu=m68k os=linux ;; m9s12z-* | m68hcs12z-* | hcs12z-* | s12z-*) cpu=s12z ;; openrisc-*) cpu=or32 ;; parisc-*) cpu=hppa os=linux ;; pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) cpu=i586 ;; pentiumpro-* | p6-* | 6x86-* | athlon-* | athalon_*-*) cpu=i686 ;; pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) cpu=i686 ;; pentium4-*) cpu=i786 ;; pc98-*) cpu=i386 ;; ppc-* | ppcbe-*) cpu=powerpc ;; ppcle-* | powerpclittle-*) cpu=powerpcle ;; ppc64-*) cpu=powerpc64 ;; ppc64le-* | powerpc64little-*) cpu=powerpc64le ;; sb1-*) cpu=mipsisa64sb1 ;; sb1el-*) cpu=mipsisa64sb1el ;; sh5e[lb]-*) cpu=`echo "$cpu" | sed 's/^\(sh.\)e\(.\)$/\1\2e/'` ;; spur-*) cpu=spur ;; strongarm-* | thumb-*) cpu=arm ;; tx39-*) cpu=mipstx39 ;; tx39el-*) cpu=mipstx39el ;; x64-*) cpu=x86_64 ;; xscale-* | xscalee[bl]-*) cpu=`echo "$cpu" | sed 's/^xscale/arm/'` ;; # Recognize the canonical CPU Types that limit and/or modify the # company names they are paired with. cr16-*) os=${os:-elf} ;; crisv32-* | etraxfs*-*) cpu=crisv32 vendor=axis ;; cris-* | etrax*-*) cpu=cris vendor=axis ;; crx-*) os=${os:-elf} ;; neo-tandem) cpu=neo vendor=tandem ;; nse-tandem) cpu=nse vendor=tandem ;; nsr-tandem) cpu=nsr vendor=tandem ;; nsv-tandem) cpu=nsv vendor=tandem ;; nsx-tandem) cpu=nsx vendor=tandem ;; s390-*) cpu=s390 vendor=ibm ;; s390x-*) cpu=s390x vendor=ibm ;; tile*-*) os=${os:-linux-gnu} ;; *) # Recognize the canonical CPU types that are allowed with any # company name. case $cpu in 1750a | 580 \ | a29k \ | aarch64 | aarch64_be \ | abacus \ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] \ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] \ | alphapca5[67] | alpha64pca5[67] \ | am33_2.0 \ | amdgcn \ | arc | arceb \ | arm | arm[lb]e | arme[lb] | armv* \ | avr | avr32 \ | asmjs \ | ba \ | be32 | be64 \ | bfin | bpf | bs2000 \ | c[123]* | c30 | [cjt]90 | c4x \ | c8051 | clipper | craynv | csky | cydra \ | d10v | d30v | dlx | dsp16xx \ | e2k | elxsi | epiphany \ | f30[01] | f700 | fido | fr30 | frv | ft32 | fx80 \ | h8300 | h8500 \ | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ | hexagon \ | i370 | i*86 | i860 | i960 | ia16 | ia64 \ | ip2k | iq2000 \ | k1om \ | le32 | le64 \ | lm32 \ | m32c | m32r | m32rle \ | m5200 | m68000 | m680[012346]0 | m68360 | m683?2 | m68k \ | m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x \ | m88110 | m88k | maxq | mb | mcore | mep | metag \ | microblaze | microblazeel \ | mips | mipsbe | mipseb | mipsel | mipsle \ | mips16 \ | mips64 | mips64eb | mips64el \ | mips64octeon | mips64octeonel \ | mips64orion | mips64orionel \ | mips64r5900 | mips64r5900el \ | mips64vr | mips64vrel \ | mips64vr4100 | mips64vr4100el \ | mips64vr4300 | mips64vr4300el \ | mips64vr5000 | mips64vr5000el \ | mips64vr5900 | mips64vr5900el \ | mipsisa32 | mipsisa32el \ | mipsisa32r2 | mipsisa32r2el \ | mipsisa32r6 | mipsisa32r6el \ | mipsisa64 | mipsisa64el \ | mipsisa64r2 | mipsisa64r2el \ | mipsisa64r6 | mipsisa64r6el \ | mipsisa64sb1 | mipsisa64sb1el \ | mipsisa64sr71k | mipsisa64sr71kel \ | mipsr5900 | mipsr5900el \ | mipstx39 | mipstx39el \ | mmix \ | mn10200 | mn10300 \ | moxie \ | mt \ | msp430 \ | nds32 | nds32le | nds32be \ | nfp \ | nios | nios2 | nios2eb | nios2el \ | none | np1 | ns16k | ns32k | nvptx \ | open8 \ | or1k* \ | or32 \ | orion \ | picochip \ | pdp10 | pdp11 | pj | pjl | pn | power \ | powerpc | powerpc64 | powerpc64le | powerpcle | powerpcspe \ | pru \ | pyramid \ | riscv | riscv32 | riscv64 \ | rl78 | romp | rs6000 | rx \ | score \ | sh | shl \ | sh[1234] | sh[24]a | sh[24]ae[lb] | sh[23]e | she[lb] | sh[lb]e \ | sh[1234]e[lb] | sh[12345][lb]e | sh[23]ele | sh64 | sh64le \ | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet \ | sparclite \ | sparcv8 | sparcv9 | sparcv9b | sparcv9v | sv1 | sx* \ | spu \ | tahoe \ | tic30 | tic4x | tic54x | tic55x | tic6x | tic80 \ | tron \ | ubicom32 \ | v70 | v850 | v850e | v850e1 | v850es | v850e2 | v850e2v3 \ | vax \ | visium \ | w65 \ | wasm32 | wasm64 \ | we32k \ | x86 | x86_64 | xc16x | xgate | xps100 \ | xstormy16 | xtensa* \ | ymp \ | z8k | z80) ;; *) echo Invalid configuration \`"$1"\': machine \`"$cpu-$vendor"\' not recognized 1>&2 exit 1 ;; esac ;; esac # Here we canonicalize certain aliases for manufacturers. case $vendor in digital*) vendor=dec ;; commodore*) vendor=cbm ;; *) ;; esac # Decode manufacturer-specific aliases for certain operating systems. if [ x$os != x ] then case $os in # First match some system type aliases that might get confused # with valid system types. # solaris* is a basic system type, with this one exception. auroraux) os=auroraux ;; bluegene*) os=cnk ;; solaris1 | solaris1.*) os=`echo $os | sed -e 's|solaris1|sunos4|'` ;; solaris) os=solaris2 ;; unixware*) os=sysv4.2uw ;; gnu/linux*) os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` ;; # es1800 is here to avoid being matched by es* (a different OS) es1800*) os=ose ;; # Some version numbers need modification chorusos*) os=chorusos ;; isc) os=isc2.2 ;; sco6) os=sco5v6 ;; sco5) os=sco3.2v5 ;; sco4) os=sco3.2v4 ;; sco3.2.[4-9]*) os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` ;; sco3.2v[4-9]* | sco5v6*) # Don't forget version if it is 3.2v4 or newer. ;; scout) # Don't match below ;; sco*) os=sco3.2v2 ;; psos*) os=psos ;; # Now accept the basic system types. # The portable systems comes first. # Each alternative MUST end in a * to match a version number. # sysv* is not here because it comes later, after sysvr4. gnu* | bsd* | mach* | minix* | genix* | ultrix* | irix* \ | *vms* | esix* | aix* | cnk* | sunos | sunos[34]*\ | hpux* | unos* | osf* | luna* | dgux* | auroraux* | solaris* \ | sym* | kopensolaris* | plan9* \ | amigaos* | amigados* | msdos* | newsos* | unicos* | aof* \ | aos* | aros* | cloudabi* | sortix* \ | nindy* | vxsim* | vxworks* | ebmon* | hms* | mvs* \ | clix* | riscos* | uniplus* | iris* | isc* | rtu* | xenix* \ | knetbsd* | mirbsd* | netbsd* \ | bitrig* | openbsd* | solidbsd* | libertybsd* \ | ekkobsd* | kfreebsd* | freebsd* | riscix* | lynxos* \ | bosx* | nextstep* | cxux* | aout* | elf* | oabi* \ | ptx* | coff* | ecoff* | winnt* | domain* | vsta* \ | udi* | eabi* | lites* | ieee* | go32* | aux* | hcos* \ | chorusrdb* | cegcc* | glidix* \ | cygwin* | msys* | pe* | moss* | proelf* | rtems* \ | midipix* | mingw32* | mingw64* | linux-gnu* | linux-android* \ | linux-newlib* | linux-musl* | linux-uclibc* \ | uxpv* | beos* | mpeix* | udk* | moxiebox* \ | interix* | uwin* | mks* | rhapsody* | darwin* \ | openstep* | oskit* | conix* | pw32* | nonstopux* \ | storm-chaos* | tops10* | tenex* | tops20* | its* \ | os2* | vos* | palmos* | uclinux* | nucleus* \ | morphos* | superux* | rtmk* | windiss* \ | powermax* | dnix* | nx6 | nx7 | sei* | dragonfly* \ | skyos* | haiku* | rdos* | toppers* | drops* | es* \ | onefs* | tirtos* | phoenix* | fuchsia* | redox* | bme* \ | midnightbsd* | amdhsa* | unleashed* | emscripten* | wasi*) # Remember, each alternative MUST END IN *, to match a version number. ;; qnx*) case $cpu in x86 | i*86) ;; *) os=nto-$os ;; esac ;; hiux*) os=hiuxwe2 ;; nto-qnx*) ;; nto*) os=`echo $os | sed -e 's|nto|nto-qnx|'` ;; sim | xray | os68k* | v88r* \ | windows* | osx | abug | netware* | os9* \ | macos* | mpw* | magic* | mmixware* | mon960* | lnews*) ;; linux-dietlibc) os=linux-dietlibc ;; linux*) os=`echo $os | sed -e 's|linux|linux-gnu|'` ;; lynx*178) os=lynxos178 ;; lynx*5) os=lynxos5 ;; lynx*) os=lynxos ;; mac*) os=`echo "$os" | sed -e 's|mac|macos|'` ;; opened*) os=openedition ;; os400*) os=os400 ;; sunos5*) os=`echo "$os" | sed -e 's|sunos5|solaris2|'` ;; sunos6*) os=`echo "$os" | sed -e 's|sunos6|solaris3|'` ;; wince*) os=wince ;; utek*) os=bsd ;; dynix*) os=bsd ;; acis*) os=aos ;; atheos*) os=atheos ;; syllable*) os=syllable ;; 386bsd) os=bsd ;; ctix* | uts*) os=sysv ;; nova*) os=rtmk-nova ;; ns2) os=nextstep2 ;; nsk*) os=nsk ;; # Preserve the version number of sinix5. sinix5.*) os=`echo $os | sed -e 's|sinix|sysv|'` ;; sinix*) os=sysv4 ;; tpf*) os=tpf ;; triton*) os=sysv3 ;; oss*) os=sysv3 ;; svr4*) os=sysv4 ;; svr3) os=sysv3 ;; sysvr4) os=sysv4 ;; # This must come after sysvr4. sysv*) ;; ose*) os=ose ;; *mint | mint[0-9]* | *MiNT | MiNT[0-9]*) os=mint ;; zvmoe) os=zvmoe ;; dicos*) os=dicos ;; pikeos*) # Until real need of OS specific support for # particular features comes up, bare metal # configurations are quite functional. case $cpu in arm*) os=eabi ;; *) os=elf ;; esac ;; nacl*) ;; ios) ;; none) ;; *-eabi) ;; *) echo Invalid configuration \`"$1"\': system \`"$os"\' not recognized 1>&2 exit 1 ;; esac else # Here we handle the default operating systems that come with various machines. # The value should be what the vendor currently ships out the door with their # machine or put another way, the most popular os provided with the machine. # Note that if you're going to try to match "-MANUFACTURER" here (say, # "-sun"), then you have to tell the case statement up towards the top # that MANUFACTURER isn't an operating system. Otherwise, code above # will signal an error saying that MANUFACTURER isn't an operating # system, and we'll never get to this point. case $cpu-$vendor in score-*) os=elf ;; spu-*) os=elf ;; *-acorn) os=riscix1.2 ;; arm*-rebel) os=linux ;; arm*-semi) os=aout ;; c4x-* | tic4x-*) os=coff ;; c8051-*) os=elf ;; clipper-intergraph) os=clix ;; hexagon-*) os=elf ;; tic54x-*) os=coff ;; tic55x-*) os=coff ;; tic6x-*) os=coff ;; # This must come before the *-dec entry. pdp10-*) os=tops20 ;; pdp11-*) os=none ;; *-dec | vax-*) os=ultrix4.2 ;; m68*-apollo) os=domain ;; i386-sun) os=sunos4.0.2 ;; m68000-sun) os=sunos3 ;; m68*-cisco) os=aout ;; mep-*) os=elf ;; mips*-cisco) os=elf ;; mips*-*) os=elf ;; or32-*) os=coff ;; *-tti) # must be before sparc entry or we get the wrong os. os=sysv3 ;; sparc-* | *-sun) os=sunos4.1.1 ;; pru-*) os=elf ;; *-be) os=beos ;; *-ibm) os=aix ;; *-knuth) os=mmixware ;; *-wec) os=proelf ;; *-winbond) os=proelf ;; *-oki) os=proelf ;; *-hp) os=hpux ;; *-hitachi) os=hiux ;; i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) os=sysv ;; *-cbm) os=amigaos ;; *-dg) os=dgux ;; *-dolphin) os=sysv3 ;; m68k-ccur) os=rtu ;; m88k-omron*) os=luna ;; *-next) os=nextstep ;; *-sequent) os=ptx ;; *-crds) os=unos ;; *-ns) os=genix ;; i370-*) os=mvs ;; *-gould) os=sysv ;; *-highlevel) os=bsd ;; *-encore) os=bsd ;; *-sgi) os=irix ;; *-siemens) os=sysv4 ;; *-masscomp) os=rtu ;; f30[01]-fujitsu | f700-fujitsu) os=uxpv ;; *-rom68k) os=coff ;; *-*bug) os=coff ;; *-apple) os=macos ;; *-atari*) os=mint ;; *-wrs) os=vxworks ;; *) os=none ;; esac fi # Here we handle the case where we know the os, and the CPU type, but not the # manufacturer. We pick the logical manufacturer. case $vendor in unknown) case $os in riscix*) vendor=acorn ;; sunos*) vendor=sun ;; cnk*|-aix*) vendor=ibm ;; beos*) vendor=be ;; hpux*) vendor=hp ;; mpeix*) vendor=hp ;; hiux*) vendor=hitachi ;; unos*) vendor=crds ;; dgux*) vendor=dg ;; luna*) vendor=omron ;; genix*) vendor=ns ;; clix*) vendor=intergraph ;; mvs* | opened*) vendor=ibm ;; os400*) vendor=ibm ;; ptx*) vendor=sequent ;; tpf*) vendor=ibm ;; vxsim* | vxworks* | windiss*) vendor=wrs ;; aux*) vendor=apple ;; hms*) vendor=hitachi ;; mpw* | macos*) vendor=apple ;; *mint | mint[0-9]* | *MiNT | MiNT[0-9]*) vendor=atari ;; vos*) vendor=stratus ;; esac ;; esac echo "$cpu-$vendor-$os" exit # Local variables: # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: |
Changes to configure.
1 2 | #! /bin/sh # Guess values for system-dependent variables and create Makefiles. | | | 1 2 3 4 5 6 7 8 9 10 | #! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.69 for sqlite 3.37.0. # # # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. # # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. |
︙ | ︙ | |||
722 723 724 725 726 727 728 | subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME='sqlite' PACKAGE_TARNAME='sqlite' | | | | 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 | subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME='sqlite' PACKAGE_TARNAME='sqlite' PACKAGE_VERSION='3.37.0' PACKAGE_STRING='sqlite 3.37.0' PACKAGE_BUGREPORT='' PACKAGE_URL='' # Factoring default headers for most tests. ac_includes_default="\ #include <stdio.h> #ifdef HAVE_SYS_TYPES_H |
︙ | ︙ | |||
770 771 772 773 774 775 776 777 778 779 780 781 782 783 | ac_subst_vars='LTLIBOBJS LIBOBJS BUILD_CFLAGS USE_GCOV OPT_FEATURE_FLAGS HAVE_ZLIB USE_AMALGAMATION TARGET_DEBUG TARGET_HAVE_EDITLINE TARGET_HAVE_READLINE TARGET_READLINE_INC TARGET_READLINE_LIBS HAVE_TCL TCL_SHLIB_SUFFIX | > | 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 | ac_subst_vars='LTLIBOBJS LIBOBJS BUILD_CFLAGS USE_GCOV OPT_FEATURE_FLAGS HAVE_ZLIB USE_AMALGAMATION AMALGAMATION_LINE_MACROS TARGET_DEBUG TARGET_HAVE_EDITLINE TARGET_HAVE_READLINE TARGET_READLINE_INC TARGET_READLINE_LIBS HAVE_TCL TCL_SHLIB_SUFFIX |
︙ | ︙ | |||
795 796 797 798 799 800 801 | SQLITE_OS_WIN SQLITE_OS_UNIX BUILD_EXEEXT TEMP_STORE ALLOWRELEASE SQLITE_THREADSAFE BUILD_CC | < | 796 797 798 799 800 801 802 803 804 805 806 807 808 809 | SQLITE_OS_WIN SQLITE_OS_UNIX BUILD_EXEEXT TEMP_STORE ALLOWRELEASE SQLITE_THREADSAFE BUILD_CC RELEASE VERSION program_prefix TCLLIBDIR TCLSH_CMD INSTALL_DATA INSTALL_SCRIPT |
︙ | ︙ | |||
899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 | with_tcl enable_editline enable_readline with_readline_lib with_readline_inc enable_debug enable_amalgamation enable_load_extension enable_memsys5 enable_memsys3 enable_fts3 enable_fts4 enable_fts5 enable_json1 enable_update_limit | > > > | 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 | with_tcl enable_editline enable_readline with_readline_lib with_readline_inc enable_debug enable_amalgamation amalgamation_line_macros enable_load_extension enable_math enable_all enable_memsys5 enable_memsys3 enable_fts3 enable_fts4 enable_fts5 enable_json1 enable_update_limit |
︙ | ︙ | |||
1462 1463 1464 1465 1466 1467 1468 | # # 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 | | | 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 | # # 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.37.0 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. |
︙ | ︙ | |||
1527 1528 1529 1530 1531 1532 1533 | --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 | | | 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 | --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.37.0:";; esac cat <<\_ACEOF Optional Features: --disable-option-checking ignore unrecognized --enable/--with options --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] |
︙ | ︙ | |||
1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 | --enable-editline enable BSD editline support --disable-readline disable readline support --enable-debug enable debugging & verbose explain --disable-amalgamation Disable the amalgamation and instead build all files separately --disable-load-extension Disable loading of external extensions --enable-memsys5 Enable MEMSYS5 --enable-memsys3 Enable MEMSYS3 --enable-fts3 Enable the FTS3 extension --enable-fts4 Enable the FTS4 extension --enable-fts5 Enable the FTS5 extension --enable-json1 Enable the JSON1 extension --enable-update-limit Enable the UPDATE/DELETE LIMIT clause | > > | 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 | --enable-editline enable BSD editline support --disable-readline disable readline support --enable-debug enable debugging & verbose explain --disable-amalgamation Disable the amalgamation and instead build all files separately --disable-load-extension Disable loading of external extensions --disable-math Disable math functions --enable-all Enable FTS4, FTS5, Geopoly, JSON, RTree, Sessions --enable-memsys5 Enable MEMSYS5 --enable-memsys3 Enable MEMSYS3 --enable-fts3 Enable the FTS3 extension --enable-fts4 Enable the FTS4 extension --enable-fts5 Enable the FTS5 extension --enable-json1 Enable the JSON1 extension --enable-update-limit Enable the UPDATE/DELETE LIMIT clause |
︙ | ︙ | |||
1653 1654 1655 1656 1657 1658 1659 | cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF | | | 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 | 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.37.0 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit |
︙ | ︙ | |||
2072 2073 2074 2075 2076 2077 2078 | eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_mongrel cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. | | | 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 | eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_mongrel cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by sqlite $as_me 3.37.0, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ _ACEOF exec 5>>config.log { |
︙ | ︙ | |||
3930 3931 3932 3933 3934 3935 3936 | { $as_echo "$as_me:${as_lineno-$LINENO}: checking the name lister ($NM) interface" >&5 $as_echo_n "checking the name lister ($NM) interface... " >&6; } if ${lt_cv_nm_interface+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_nm_interface="BSD nm" echo "int some_variable = 0;" > conftest.$ac_ext | | | | | 3935 3936 3937 3938 3939 3940 3941 3942 3943 3944 3945 3946 3947 3948 3949 3950 3951 3952 3953 3954 3955 | { $as_echo "$as_me:${as_lineno-$LINENO}: checking the name lister ($NM) interface" >&5 $as_echo_n "checking the name lister ($NM) interface... " >&6; } if ${lt_cv_nm_interface+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_nm_interface="BSD nm" echo "int some_variable = 0;" > conftest.$ac_ext (eval echo "\"\$as_me:3940: $ac_compile\"" >&5) (eval "$ac_compile" 2>conftest.err) cat conftest.err >&5 (eval echo "\"\$as_me:3943: $NM \\\"conftest.$ac_objext\\\"\"" >&5) (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) cat conftest.err >&5 (eval echo "\"\$as_me:3946: output\"" >&5) cat conftest.out >&5 if $GREP 'External.*some_variable' conftest.out > /dev/null; then lt_cv_nm_interface="MS dumpbin" fi rm -f conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_nm_interface" >&5 |
︙ | ︙ | |||
5142 5143 5144 5145 5146 5147 5148 | ;; esac fi rm -rf conftest* ;; *-*-irix6*) # Find out which ABI we are using. | | | 5147 5148 5149 5150 5151 5152 5153 5154 5155 5156 5157 5158 5159 5160 5161 | ;; esac fi rm -rf conftest* ;; *-*-irix6*) # Find out which ABI we are using. echo '#line 5152 "configure"' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then if test "$lt_cv_prog_gnu_ld" = yes; then case `/usr/bin/file conftest.$ac_objext` in |
︙ | ︙ | |||
6667 6668 6669 6670 6671 6672 6673 | # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` | | | | 6672 6673 6674 6675 6676 6677 6678 6679 6680 6681 6682 6683 6684 6685 6686 6687 6688 6689 6690 | # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:6677: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 echo "$as_me:6681: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler_rtti_exceptions=yes |
︙ | ︙ | |||
7006 7007 7008 7009 7010 7011 7012 | # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` | | | | 7011 7012 7013 7014 7015 7016 7017 7018 7019 7020 7021 7022 7023 7024 7025 7026 7027 7028 7029 | # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:7016: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 echo "$as_me:7020: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler_pic_works=yes |
︙ | ︙ | |||
7111 7112 7113 7114 7115 7116 7117 | # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` | | | | 7116 7117 7118 7119 7120 7121 7122 7123 7124 7125 7126 7127 7128 7129 7130 7131 7132 7133 7134 | # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:7121: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 echo "$as_me:7125: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then |
︙ | ︙ | |||
7166 7167 7168 7169 7170 7171 7172 | # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` | | | | 7171 7172 7173 7174 7175 7176 7177 7178 7179 7180 7181 7182 7183 7184 7185 7186 7187 7188 7189 | # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:7176: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 echo "$as_me:7180: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then |
︙ | ︙ | |||
9546 9547 9548 9549 9550 9551 9552 | else if test "$cross_compiling" = yes; then : lt_cv_dlopen_self=cross else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF | | | 9551 9552 9553 9554 9555 9556 9557 9558 9559 9560 9561 9562 9563 9564 9565 | else if test "$cross_compiling" = yes; then : lt_cv_dlopen_self=cross else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF #line 9556 "configure" #include "confdefs.h" #if HAVE_DLFCN_H #include <dlfcn.h> #endif #include <stdio.h> |
︙ | ︙ | |||
9642 9643 9644 9645 9646 9647 9648 | else if test "$cross_compiling" = yes; then : lt_cv_dlopen_self_static=cross else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF | | | 9647 9648 9649 9650 9651 9652 9653 9654 9655 9656 9657 9658 9659 9660 9661 | else if test "$cross_compiling" = yes; then : lt_cv_dlopen_self_static=cross else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF #line 9652 "configure" #include "confdefs.h" #if HAVE_DLFCN_H #include <dlfcn.h> #endif #include <stdio.h> |
︙ | ︙ | |||
10298 10299 10300 10301 10302 10303 10304 10305 10306 10307 10308 10309 10310 10311 | ######### # By default, we use the amalgamation (this may be changed below...) # USE_AMALGAMATION=1 ######### # See whether we can run specific tclsh versions known to work well; # if not, then we fall back to plain tclsh. # TODO: try other versions before falling back? # for ac_prog in tclsh8.7 tclsh8.6 tclsh8.5 tclsh do | > > > > > > > | 10303 10304 10305 10306 10307 10308 10309 10310 10311 10312 10313 10314 10315 10316 10317 10318 10319 10320 10321 10322 10323 | ######### # By default, we use the amalgamation (this may be changed below...) # USE_AMALGAMATION=1 ######### # By default, amalgamation sqlite3.c will have #line directives. # This is a build option not shown by ./configure --help # To control it, use configure option: amalgamation_line_macros=? # where ? is no to suppress #line directives or yes to create them. AMALGAMATION_LINE_MACROS=--linemacros=0 ######### # See whether we can run specific tclsh versions known to work well; # if not, then we fall back to plain tclsh. # TODO: try other versions before falling back? # for ac_prog in tclsh8.7 tclsh8.6 tclsh8.5 tclsh do |
︙ | ︙ | |||
10359 10360 10361 10362 10363 10364 10365 | fi if test "x${TCLLIBDIR+set}" != "xset" ; then TCLLIBDIR='$(libdir)' for i in `echo 'puts stdout $auto_path' | ${TCLSH_CMD}` ; do | > | | > | 10371 10372 10373 10374 10375 10376 10377 10378 10379 10380 10381 10382 10383 10384 10385 10386 10387 10388 | fi if test "x${TCLLIBDIR+set}" != "xset" ; then TCLLIBDIR='$(libdir)' for i in `echo 'puts stdout $auto_path' | ${TCLSH_CMD}` ; do if test -d $i ; then TCLLIBDIR=$i break fi done TCLLIBDIR="${TCLLIBDIR}/sqlite3" fi ######### # Set up an appropriate program prefix |
︙ | ︙ | |||
10382 10383 10384 10385 10386 10387 10388 | { $as_echo "$as_me:${as_lineno-$LINENO}: Version set to $VERSION" >&5 $as_echo "$as_me: Version set to $VERSION" >&6;} RELEASE=`cat $srcdir/VERSION` { $as_echo "$as_me:${as_lineno-$LINENO}: Release set to $RELEASE" >&5 $as_echo "$as_me: Release set to $RELEASE" >&6;} | < < < < < < | 10396 10397 10398 10399 10400 10401 10402 10403 10404 10405 10406 10407 10408 10409 | { $as_echo "$as_me:${as_lineno-$LINENO}: Version set to $VERSION" >&5 $as_echo "$as_me: Version set to $VERSION" >&6;} RELEASE=`cat $srcdir/VERSION` { $as_echo "$as_me:${as_lineno-$LINENO}: Release set to $RELEASE" >&5 $as_echo "$as_me: Release set to $RELEASE" >&6;} ######### # Locate a compiler for the build machine. This compiler should # generate command-line programs that run on the build machine. # if test x"$cross_compiling" = xno; then BUILD_CC=$CC |
︙ | ︙ | |||
11248 11249 11250 11251 11252 11253 11254 11255 11256 11257 11258 11259 11260 11261 11262 11263 11264 11265 11266 11267 11268 | ######### # check for debug enabled # Check whether --enable-debug was given. if test "${enable_debug+set}" = set; then : enableval=$enable_debug; fi if test "${enable_debug}" = "yes" ; then TARGET_DEBUG="-DSQLITE_DEBUG=1 -DSQLITE_ENABLE_SELECTTRACE -DSQLITE_ENABLE_WHERETRACE -O0" else TARGET_DEBUG="-DNDEBUG" fi ######### # See whether we should use the amalgamation to build # Check whether --enable-amalgamation was given. if test "${enable_amalgamation+set}" = set; then : enableval=$enable_amalgamation; fi | > > > > > > | > > > > > > > > > > > > > | 11256 11257 11258 11259 11260 11261 11262 11263 11264 11265 11266 11267 11268 11269 11270 11271 11272 11273 11274 11275 11276 11277 11278 11279 11280 11281 11282 11283 11284 11285 11286 11287 11288 11289 11290 11291 11292 11293 11294 11295 11296 11297 11298 11299 11300 11301 11302 11303 11304 11305 | ######### # check for debug enabled # Check whether --enable-debug was given. if test "${enable_debug+set}" = set; then : enableval=$enable_debug; fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking build type" >&5 $as_echo_n "checking build type... " >&6; } if test "${enable_debug}" = "yes" ; then TARGET_DEBUG="-DSQLITE_DEBUG=1 -DSQLITE_ENABLE_SELECTTRACE -DSQLITE_ENABLE_WHERETRACE -O0" { $as_echo "$as_me:${as_lineno-$LINENO}: result: debug" >&5 $as_echo "debug" >&6; } else TARGET_DEBUG="-DNDEBUG" { $as_echo "$as_me:${as_lineno-$LINENO}: result: release" >&5 $as_echo "release" >&6; } fi ######### # See whether we should use the amalgamation to build # Check whether --enable-amalgamation was given. if test "${enable_amalgamation+set}" = set; then : enableval=$enable_amalgamation; fi if test "${enable_amalgamation}" = "no" ; then USE_AMALGAMATION=0 fi ######## # See whether --disable if test "${amalgamation_line_macros+set}" = set; then : enableval=$amalgamation_line_macros; fi if test "${amalgamation_line_macros}" = "yes" ; then AMALGAMATION_LINE_MACROS=--linemacros=1 fi if test "${amalgamation_line_macros}" = "no" ; then AMALGAMATION_LINE_MACROS=--linemacros=0 fi ######### # Look for zlib. Only needed by extensions and by the sqlite3.exe shell for ac_header in zlib.h do : ac_fn_c_check_header_mongrel "$LINENO" "zlib.h" "ac_cv_header_zlib_h" "$ac_includes_default" |
︙ | ︙ | |||
11411 11412 11413 11414 11415 11416 11417 11418 11419 11420 11421 11422 11423 11424 | test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi else OPT_FEATURE_FLAGS="-DSQLITE_OMIT_LOAD_EXTENSION=1" fi ########## # Do we want to support memsys3 and/or memsys5 # # Check whether --enable-memsys5 was given. if test "${enable_memsys5+set}" = set; then : enableval=$enable_memsys5; | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 11438 11439 11440 11441 11442 11443 11444 11445 11446 11447 11448 11449 11450 11451 11452 11453 11454 11455 11456 11457 11458 11459 11460 11461 11462 11463 11464 11465 11466 11467 11468 11469 11470 11471 11472 11473 11474 11475 11476 11477 11478 11479 11480 11481 11482 11483 11484 11485 11486 11487 11488 11489 11490 11491 11492 11493 11494 11495 11496 11497 11498 11499 11500 11501 11502 11503 11504 11505 11506 11507 11508 11509 11510 11511 11512 11513 11514 11515 11516 11517 11518 11519 11520 11521 11522 11523 11524 11525 11526 11527 11528 11529 11530 11531 11532 11533 11534 11535 11536 | test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi else OPT_FEATURE_FLAGS="-DSQLITE_OMIT_LOAD_EXTENSION=1" fi ########## # Do we want to support math functions # # Check whether --enable-math was given. if test "${enable_math+set}" = set; then : enableval=$enable_math; fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to support math functions" >&5 $as_echo_n "checking whether to support math functions... " >&6; } if test "$enable_math" = "no"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_MATH_FUNCTIONS" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing ceil" >&5 $as_echo_n "checking for library containing ceil... " >&6; } if ${ac_cv_search_ceil+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char ceil (); int main () { return ceil (); ; return 0; } _ACEOF for ac_lib in '' m; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_ceil=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if ${ac_cv_search_ceil+:} false; then : break fi done if ${ac_cv_search_ceil+:} false; then : else ac_cv_search_ceil=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_ceil" >&5 $as_echo "$ac_cv_search_ceil" >&6; } ac_res=$ac_cv_search_ceil if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi fi ######## # The --enable-all argument is short-hand to enable # multiple extensions. # Check whether --enable-all was given. if test "${enable_all+set}" = set; then : enableval=$enable_all; fi ########## # Do we want to support memsys3 and/or memsys5 # # Check whether --enable-memsys5 was given. if test "${enable_memsys5+set}" = set; then : enableval=$enable_memsys5; |
︙ | ︙ | |||
11453 11454 11455 11456 11457 11458 11459 11460 11461 11462 11463 11464 11465 11466 11467 | ######### # See whether we should enable Full Text Search extensions # Check whether --enable-fts3 was given. if test "${enable_fts3+set}" = set; then : enableval=$enable_fts3; fi if test "${enable_fts3}" = "yes" ; then OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_FTS3" fi # Check whether --enable-fts4 was given. if test "${enable_fts4+set}" = set; then : enableval=$enable_fts4; fi | > > > > > > > > > | > > | 11565 11566 11567 11568 11569 11570 11571 11572 11573 11574 11575 11576 11577 11578 11579 11580 11581 11582 11583 11584 11585 11586 11587 11588 11589 11590 11591 11592 11593 11594 11595 11596 11597 11598 | ######### # See whether we should enable Full Text Search extensions # Check whether --enable-fts3 was given. if test "${enable_fts3+set}" = set; then : enableval=$enable_fts3; fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to support FTS3" >&5 $as_echo_n "checking whether to support FTS3... " >&6; } if test "${enable_fts3}" = "yes" ; then OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_FTS3" { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # Check whether --enable-fts4 was given. if test "${enable_fts4+set}" = set; then : enableval=$enable_fts4; fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to support FTS4" >&5 $as_echo_n "checking whether to support FTS4... " >&6; } if test "${enable_fts4}" = "yes" -o "${enable_all}" = "yes" ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_FTS4" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing log" >&5 $as_echo_n "checking for library containing log... " >&6; } if ${ac_cv_search_log+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS |
︙ | ︙ | |||
11519 11520 11521 11522 11523 11524 11525 11526 11527 11528 11529 11530 11531 | $as_echo "$ac_cv_search_log" >&6; } ac_res=$ac_cv_search_log if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi fi # Check whether --enable-fts5 was given. if test "${enable_fts5+set}" = set; then : enableval=$enable_fts5; fi | > > > > > | > > | 11642 11643 11644 11645 11646 11647 11648 11649 11650 11651 11652 11653 11654 11655 11656 11657 11658 11659 11660 11661 11662 11663 11664 11665 11666 11667 11668 11669 | $as_echo "$ac_cv_search_log" >&6; } ac_res=$ac_cv_search_log if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # Check whether --enable-fts5 was given. if test "${enable_fts5+set}" = set; then : enableval=$enable_fts5; fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to support FTS5" >&5 $as_echo_n "checking whether to support FTS5... " >&6; } if test "${enable_fts5}" = "yes" -o "${enable_all}" = "yes" ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_FTS5" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing log" >&5 $as_echo_n "checking for library containing log... " >&6; } if ${ac_cv_search_log+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS |
︙ | ︙ | |||
11583 11584 11585 11586 11587 11588 11589 11590 11591 11592 11593 11594 11595 11596 11597 11598 | $as_echo "$ac_cv_search_log" >&6; } ac_res=$ac_cv_search_log if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi fi ######### # See whether we should enable JSON1 # Check whether --enable-json1 was given. if test "${enable_json1+set}" = set; then : enableval=$enable_json1; fi | > > > > > | > > > > > > > | > > > > > > > | > > > > > > > > > > > > > > | > > > > > | 11713 11714 11715 11716 11717 11718 11719 11720 11721 11722 11723 11724 11725 11726 11727 11728 11729 11730 11731 11732 11733 11734 11735 11736 11737 11738 11739 11740 11741 11742 11743 11744 11745 11746 11747 11748 11749 11750 11751 11752 11753 11754 11755 11756 11757 11758 11759 11760 11761 11762 11763 11764 11765 11766 11767 11768 11769 11770 11771 11772 11773 11774 11775 11776 11777 11778 11779 11780 11781 11782 11783 11784 11785 11786 11787 11788 11789 11790 11791 11792 11793 11794 11795 11796 11797 11798 11799 11800 11801 11802 11803 11804 11805 11806 11807 11808 11809 11810 11811 11812 11813 11814 11815 11816 11817 11818 11819 11820 11821 11822 11823 11824 | $as_echo "$ac_cv_search_log" >&6; } ac_res=$ac_cv_search_log if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi ######### # See whether we should enable JSON1 # Check whether --enable-json1 was given. if test "${enable_json1+set}" = set; then : enableval=$enable_json1; fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to support JSON" >&5 $as_echo_n "checking whether to support JSON... " >&6; } if test "${enable_json1}" = "yes" -o "${enable_all}" = "yes" ; then OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_JSON1" { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi ######### # See whether we should enable the LIMIT clause on UPDATE and DELETE # statements. # Check whether --enable-update-limit was given. if test "${enable_update_limit+set}" = set; then : enableval=$enable_update_limit; fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to support LIMIT on UPDATE and DELETE statements" >&5 $as_echo_n "checking whether to support LIMIT on UPDATE and DELETE statements... " >&6; } if test "${enable_update_limit}" = "yes" ; then OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_UPDATE_DELETE_LIMIT" { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi ######### # See whether we should enable GEOPOLY # Check whether --enable-geopoly was given. if test "${enable_geopoly+set}" = set; then : enableval=$enable_geopoly; enable_geopoly=yes else enable_geopoly=no fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to support GEOPOLY" >&5 $as_echo_n "checking whether to support GEOPOLY... " >&6; } if test "${enable_geopoly}" = "yes" -o "${enable_all}" = "yes" ; then OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_GEOPOLY" enable_rtree=yes { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi ######### # See whether we should enable RTREE # Check whether --enable-rtree was given. if test "${enable_rtree+set}" = set; then : enableval=$enable_rtree; fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to support RTREE" >&5 $as_echo_n "checking whether to support RTREE... " >&6; } if test "${enable_rtree}" = "yes" ; then OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_RTREE" { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi ######### # See whether we should enable the SESSION extension # Check whether --enable-session was given. if test "${enable_session+set}" = set; then : enableval=$enable_session; fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to support SESSION" >&5 $as_echo_n "checking whether to support SESSION... " >&6; } if test "${enable_session}" = "yes" -o "${enable_all}" = "yes" ; then OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_SESSION" OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_PREUPDATE_HOOK" { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi ######### # attempt to duplicate any OMITS and ENABLES into the ${OPT_FEATURE_FLAGS} parameter for option in $CFLAGS $CPPFLAGS do case $option in |
︙ | ︙ | |||
12228 12229 12230 12231 12232 12233 12234 | test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" | | | 12396 12397 12398 12399 12400 12401 12402 12403 12404 12405 12406 12407 12408 12409 12410 | test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by sqlite $as_me 3.37.0, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ |
︙ | ︙ | |||
12294 12295 12296 12297 12298 12299 12300 | Report bugs to the package provider." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ | | | 12462 12463 12464 12465 12466 12467 12468 12469 12470 12471 12472 12473 12474 12475 12476 | Report bugs to the package provider." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ sqlite config.status 3.37.0 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" Copyright (C) 2012 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." |
︙ | ︙ |
Changes to configure.ac.
︙ | ︙ | |||
130 131 132 133 134 135 136 | fi AC_SUBST(TCLSH_CMD) AC_ARG_VAR([TCLLIBDIR], [Where to install tcl plugin]) if test "x${TCLLIBDIR+set}" != "xset" ; then TCLLIBDIR='$(libdir)' for i in `echo 'puts stdout $auto_path' | ${TCLSH_CMD}` ; do | > | | > < < < < < | 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 | fi AC_SUBST(TCLSH_CMD) AC_ARG_VAR([TCLLIBDIR], [Where to install tcl plugin]) if test "x${TCLLIBDIR+set}" != "xset" ; then TCLLIBDIR='$(libdir)' for i in `echo 'puts stdout $auto_path' | ${TCLSH_CMD}` ; do if test -d $i ; then TCLLIBDIR=$i break fi done TCLLIBDIR="${TCLLIBDIR}/sqlite3" fi ######### # Set up an appropriate program prefix # if test "$program_prefix" = "NONE"; then program_prefix="" fi AC_SUBST(program_prefix) VERSION=[`cat $srcdir/VERSION | sed 's/^\([0-9]*\.*[0-9]*\).*/\1/'`] AC_MSG_NOTICE(Version set to $VERSION) AC_SUBST(VERSION) RELEASE=`cat $srcdir/VERSION` AC_MSG_NOTICE(Release set to $RELEASE) AC_SUBST(RELEASE) ######### # Locate a compiler for the build machine. This compiler should # generate command-line programs that run on the build machine. # if test x"$cross_compiling" = xno; then BUILD_CC=$CC |
︙ | ︙ | |||
554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 | # that use "fdatasync()" function. # AC_SEARCH_LIBS(fdatasync, [rt]) ######### # check for debug enabled AC_ARG_ENABLE(debug, AC_HELP_STRING([--enable-debug],[enable debugging & verbose explain])) if test "${enable_debug}" = "yes" ; then TARGET_DEBUG="-DSQLITE_DEBUG=1 -DSQLITE_ENABLE_SELECTTRACE -DSQLITE_ENABLE_WHERETRACE -O0" else TARGET_DEBUG="-DNDEBUG" fi AC_SUBST(TARGET_DEBUG) ######### # See whether we should use the amalgamation to build AC_ARG_ENABLE(amalgamation, AC_HELP_STRING([--disable-amalgamation], [Disable the amalgamation and instead build all files separately])) | > > > | | 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 | # that use "fdatasync()" function. # AC_SEARCH_LIBS(fdatasync, [rt]) ######### # check for debug enabled AC_ARG_ENABLE(debug, AC_HELP_STRING([--enable-debug],[enable debugging & verbose explain])) AC_MSG_CHECKING([build type]) if test "${enable_debug}" = "yes" ; then TARGET_DEBUG="-DSQLITE_DEBUG=1 -DSQLITE_ENABLE_SELECTTRACE -DSQLITE_ENABLE_WHERETRACE -O0" AC_MSG_RESULT([debug]) else TARGET_DEBUG="-DNDEBUG" AC_MSG_RESULT([release]) fi AC_SUBST(TARGET_DEBUG) ######### # See whether we should use the amalgamation to build AC_ARG_ENABLE(amalgamation, AC_HELP_STRING([--disable-amalgamation], [Disable the amalgamation and instead build all files separately])) if test "${enable_amalgamation}" = "no" ; then USE_AMALGAMATION=0 fi AC_SUBST(USE_AMALGAMATION) ######### # Look for zlib. Only needed by extensions and by the sqlite3.exe shell AC_CHECK_HEADERS(zlib.h) |
︙ | ︙ | |||
587 588 589 590 591 592 593 594 595 596 597 598 599 600 | if test "${enable_load_extension}" = "yes" ; then OPT_FEATURE_FLAGS="" AC_SEARCH_LIBS(dlopen, dl) else OPT_FEATURE_FLAGS="-DSQLITE_OMIT_LOAD_EXTENSION=1" fi ########## # Do we want to support memsys3 and/or memsys5 # AC_ARG_ENABLE(memsys5, AC_HELP_STRING([--enable-memsys5],[Enable MEMSYS5])) AC_MSG_CHECKING([whether to support MEMSYS5]) if test "${enable_memsys5}" = "yes"; then | > > > > > > > > > > > > > > > > > > > > > | 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 | if test "${enable_load_extension}" = "yes" ; then OPT_FEATURE_FLAGS="" AC_SEARCH_LIBS(dlopen, dl) else OPT_FEATURE_FLAGS="-DSQLITE_OMIT_LOAD_EXTENSION=1" fi ########## # Do we want to support math functions # AC_ARG_ENABLE(math, AC_HELP_STRING([--disable-math],[Disable math functions])) AC_MSG_CHECKING([whether to support math functions]) if test "$enable_math" = "no"; then AC_MSG_RESULT([no]) else AC_MSG_RESULT([yes]) OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_MATH_FUNCTIONS" AC_SEARCH_LIBS(ceil, m) fi ######## # The --enable-all argument is short-hand to enable # multiple extensions. AC_ARG_ENABLE(all, AC_HELP_STRING([--enable-all], [Enable FTS4, FTS5, Geopoly, JSON, RTree, Sessions])) ########## # Do we want to support memsys3 and/or memsys5 # AC_ARG_ENABLE(memsys5, AC_HELP_STRING([--enable-memsys5],[Enable MEMSYS5])) AC_MSG_CHECKING([whether to support MEMSYS5]) if test "${enable_memsys5}" = "yes"; then |
︙ | ︙ | |||
613 614 615 616 617 618 619 620 621 622 623 624 | AC_MSG_RESULT([no]) fi ######### # See whether we should enable Full Text Search extensions AC_ARG_ENABLE(fts3, AC_HELP_STRING([--enable-fts3], [Enable the FTS3 extension])) if test "${enable_fts3}" = "yes" ; then OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_FTS3" fi AC_ARG_ENABLE(fts4, AC_HELP_STRING([--enable-fts4], [Enable the FTS4 extension])) | > > > > > | > > > > | > > > > | > > > > | > > > > | > > > > > > > > | > > > | 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 | AC_MSG_RESULT([no]) fi ######### # See whether we should enable Full Text Search extensions AC_ARG_ENABLE(fts3, AC_HELP_STRING([--enable-fts3], [Enable the FTS3 extension])) AC_MSG_CHECKING([whether to support FTS3]) if test "${enable_fts3}" = "yes" ; then OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_FTS3" AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi AC_ARG_ENABLE(fts4, AC_HELP_STRING([--enable-fts4], [Enable the FTS4 extension])) AC_MSG_CHECKING([whether to support FTS4]) if test "${enable_fts4}" = "yes" -o "${enable_all}" = "yes" ; then AC_MSG_RESULT([yes]) OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_FTS4" AC_SEARCH_LIBS([log],[m]) else AC_MSG_RESULT([no]) fi AC_ARG_ENABLE(fts5, AC_HELP_STRING([--enable-fts5], [Enable the FTS5 extension])) AC_MSG_CHECKING([whether to support FTS5]) if test "${enable_fts5}" = "yes" -o "${enable_all}" = "yes" ; then AC_MSG_RESULT([yes]) OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_FTS5" AC_SEARCH_LIBS([log],[m]) else AC_MSG_RESULT([no]) fi ######### # See whether we should enable JSON1 AC_ARG_ENABLE(json1, AC_HELP_STRING([--enable-json1],[Enable the JSON1 extension])) AC_MSG_CHECKING([whether to support JSON]) if test "${enable_json1}" = "yes" -o "${enable_all}" = "yes" ; then OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_JSON1" AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi ######### # See whether we should enable the LIMIT clause on UPDATE and DELETE # statements. AC_ARG_ENABLE(update-limit, AC_HELP_STRING([--enable-update-limit], [Enable the UPDATE/DELETE LIMIT clause])) AC_MSG_CHECKING([whether to support LIMIT on UPDATE and DELETE statements]) if test "${enable_update_limit}" = "yes" ; then OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_UPDATE_DELETE_LIMIT" AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi ######### # See whether we should enable GEOPOLY AC_ARG_ENABLE(geopoly, AC_HELP_STRING([--enable-geopoly], [Enable the GEOPOLY extension]), [enable_geopoly=yes],[enable_geopoly=no]) AC_MSG_CHECKING([whether to support GEOPOLY]) if test "${enable_geopoly}" = "yes" -o "${enable_all}" = "yes" ; then OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_GEOPOLY" enable_rtree=yes AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi ######### # See whether we should enable RTREE AC_ARG_ENABLE(rtree, AC_HELP_STRING([--enable-rtree], [Enable the RTREE extension])) AC_MSG_CHECKING([whether to support RTREE]) if test "${enable_rtree}" = "yes" ; then OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_RTREE" AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi ######### # See whether we should enable the SESSION extension AC_ARG_ENABLE(session, AC_HELP_STRING([--enable-session], [Enable the SESSION extension])) AC_MSG_CHECKING([whether to support SESSION]) if test "${enable_session}" = "yes" -o "${enable_all}" = "yes" ; then OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_SESSION" OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_PREUPDATE_HOOK" AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi ######### # attempt to duplicate any OMITS and ENABLES into the ${OPT_FEATURE_FLAGS} parameter for option in $CFLAGS $CPPFLAGS do case $option in |
︙ | ︙ |
Added doc/begin_concurrent.md.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | Begin Concurrent ================ ## Overview Usually, SQLite allows at most one writer to proceed concurrently. The BEGIN CONCURRENT enhancement allows multiple writers to process write transactions simultanously if the database is in "wal" or "wal2" mode, although the system still serializes COMMIT commands. When a write-transaction is opened with "BEGIN CONCURRENT", actually locking the database is deferred until a COMMIT is executed. This means that any number of transactions started with BEGIN CONCURRENT may proceed concurrently. The system uses optimistic page-level-locking to prevent conflicting concurrent transactions from being committed. When a BEGIN CONCURRENT transaction is committed, the system checks whether or not any of the database pages that the transaction has read have been modified since the BEGIN CONCURRENT was opened. In other words - it asks if the transaction being committed operates on a different set of data than all other concurrently executing transactions. If the answer is "yes, this transaction did not read or modify any data modified by any concurrent transaction", then the transaction is committed as normal. Otherwise, if the transaction does conflict, it cannot be committed and an SQLITE_BUSY_SNAPSHOT error is returned. At this point, all the client can do is ROLLBACK the transaction. If SQLITE_BUSY_SNAPSHOT is returned, messages are output via the sqlite3_log mechanism indicating the page and table or index on which the conflict occurred. This can be useful when optimizing concurrency. ## Application Programming Notes In order to serialize COMMIT processing, SQLite takes a lock on the database as part of each COMMIT command and releases it before returning. At most one writer may hold this lock at any one time. If a writer cannot obtain the lock, it uses SQLite's busy-handler to pause and retry for a while: <a href=https://www.sqlite.org/c3ref/busy_handler.html> https://www.sqlite.org/c3ref/busy_handler.html </a> If there is significant contention for the writer lock, this mechanism can be inefficient. In this case it is better for the application to use a mutex or some other mechanism that supports blocking to ensure that at most one writer is attempting to COMMIT a BEGIN CONCURRENT transaction at a time. This is usually easier if all writers are part of the same operating system process. If all database clients (readers and writers) are located in the same OS process, and if that OS is a Unix variant, then it can be more efficient to the built-in VFS "unix-excl" instead of the default "unix". This is because it uses more efficient locking primitives. The key to maximizing concurrency using BEGIN CONCURRENT is to ensure that there are a large number of non-conflicting transactions. In SQLite, each table and each index is stored as a separate b-tree, each of which is distributed over a discrete set of database pages. This means that: * Two transactions that write to different sets of tables never conflict, and that * Two transactions that write to the same tables or indexes only conflict if the values of the keys (either primary keys or indexed rows) are fairly close together. For example, given a large table with the schema: <pre> CREATE TABLE t1(a INTEGER PRIMARY KEY, b BLOB);</pre> writing two rows with adjacent values for "a" probably will cause a conflict (as the two keys are stored on the same page), but writing two rows with vastly different values for "a" will not (as the keys will likly be stored on different pages). Note that, in SQLite, if values are not explicitly supplied for an INTEGER PRIMARY KEY, as for example in: > INSERT INTO t1(b) VALUES(<blob-value>); then monotonically increasing values are assigned automatically. This is terrible for concurrency, as it all but ensures that all new rows are added to the same database page. In such situations, it is better to explicitly assign random values to INTEGER PRIMARY KEY fields. This problem also comes up for non-WITHOUT ROWID tables that do not have an explicit INTEGER PRIMARY KEY column. In these cases each table has an implicit INTEGER PRIMARY KEY column that is assigned increasing values, leading to the same problem as omitting to assign a value to an explicit INTEGER PRIMARY KEY column. For both explicit and implicit INTEGER PRIMARY KEYs, it is possible to have SQLite assign values at random (instead of the monotonically increasing values) by writing a row with a rowid equal to the largest possible signed 64-bit integer to the table. For example: INSERT INTO t1(a) VALUES(9223372036854775807); Applications should take care not to malfunction due to the presence of such rows. The nature of some types of indexes, for example indexes on timestamp fields, can also cause problems (as concurrent transactions may assign similar timestamps that will be stored on the same db page to new records). In these cases the database schema may need to be rethought to increase the concurrency provided by page-level-locking. |
Changes to doc/lemon.html.
1 2 3 4 | <html> <head> <title>The Lemon Parser Generator</title> </head> | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | > | | | | | > | | | | | > | | | > | | | | | > > > > | > | | | | | | | | 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 | <html> <head> <title>The Lemon Parser Generator</title> </head> <body> <a id="main"></a> <h1 align='center'>The Lemon Parser Generator</h1> <p>Lemon is an LALR(1) parser generator for C. It does the same job as "bison" and "yacc". But Lemon is not a bison or yacc clone. Lemon uses a different grammar syntax which is designed to reduce the number of coding errors. Lemon also uses a parsing engine that is faster than yacc and bison and which is both reentrant and threadsafe. (Update: Since the previous sentence was written, bison has also been updated so that it too can generate a reentrant and threadsafe parser.) Lemon also implements features that can be used to eliminate resource leaks, making it suitable for use in long-running programs such as graphical user interfaces or embedded controllers.</p> <p>This document is an introduction to the Lemon parser generator.</p> <a id="toc"></a> <h2>1.0 Table of Contents</h2> <ul> <li><a href="#main">Introduction</a> <li><a href="#toc">1.0 Table of Contents</a> <li><a href="#secnot">2.0 Security Notes</a><br> <li><a href="#optheory">3.0 Theory of Operation</a> <ul> <li><a href="#options">3.1 Command Line Options</a> <li><a href="#interface">3.2 The Parser Interface</a> <ul> <li><a href="#onstack">3.2.1 Allocating The Parse Object On Stack</a> <li><a href="#ifsum">3.2.2 Interface Summary</a> </ul> <li><a href="#yaccdiff">3.3 Differences With YACC and BISON</a> <li><a href="#build">3.4 Building The "lemon" Or "lemon.exe" Executable</a> </ul> <li><a href="#syntax">4.0 Input File Syntax</a> <ul> <li><a href="#tnt">4.1 Terminals and Nonterminals</a> <li><a href="#rules">4.2 Grammar Rules</a> <li><a href="#precrules">4.3 Precedence Rules</a> <li><a href="#special">4.4 Special Directives</a> </ul> <li><a href="#errors">5.0 Error Processing</a> <li><a href="#history">6.0 History of Lemon</a> <li><a href="#copyright">7.0 Copyright</a> </ul> <a id="secnot"></a> <h2>2.0 Security Note</h2> <p>The language parser code created by Lemon is very robust and is well-suited for use in internet-facing applications that need to safely process maliciously crafted inputs.</p> <p>The "lemon.exe" command-line tool itself works great when given a valid input grammar file and almost always gives helpful error messages for malformed inputs. However, it is possible for a malicious user to craft a grammar file that will cause lemon.exe to crash. We do not see this as a problem, as lemon.exe is not intended to be used with hostile inputs. To summarize:</p> <ul> <li>Parser code generated by lemon → Robust and secure <li>The "lemon.exe" command line tool itself → Not so much </ul> <a id="optheory"></a> <h2>3.0 Theory of Operation</h2> <p>Lemon is computer program that translates a context free grammar (CFG) for a particular language into C code that implements a parser for that language. The Lemon program has two inputs:</p> <ul> <li>The grammar specification. <li>A parser template file. </ul> <p>Typically, only the grammar specification is supplied by the programmer. Lemon comes with a default parser template ("<a href="https://sqlite.org/src/file/tool/lempar.c">lempar.c</a>") that works fine for most applications. But the user is free to substitute a different parser template if desired.</p> <p>Depending on command-line options, Lemon will generate up to three output files.</p> <ul> <li>C code to implement a parser for the input grammar. <li>A header file defining an integer ID for each terminal symbol (or "token"). <li>An information file that describes the states of the generated parser automaton. </ul> <p>By default, all three of these output files are generated. The header file is suppressed if the "-m" command-line option is used and the report file is omitted when "-q" is selected.</p> <p>The grammar specification file uses a ".y" suffix, by convention. In the examples used in this document, we'll assume the name of the grammar file is "gram.y". A typical use of Lemon would be the following command:</p> <pre> lemon gram.y </pre> <p>This command will generate three output files named "gram.c", "gram.h" and "gram.out". The first is C code to implement the parser. The second is the header file that defines numerical values for all terminal symbols, and the last is the report that explains the states used by the parser automaton.</p> <a id="options"></a> <h3>3.1 Command Line Options</h3> <p>The behavior of Lemon can be modified using command-line options. You can obtain a list of the available command-line options together with a brief explanation of what each does by typing</p> <pre> lemon "-?" </pre> <p>As of this writing, the following command-line options are supported:</p> <ul> <li><b>-b</b> Show only the basis for each parser state in the report file. <li><b>-c</b> Do not compress the generated action tables. The parser will be a little larger and slower, but it will detect syntax errors sooner. <li><b>-d</b><i>directory</i> Write all output files into <i>directory</i>. Normally, output files are written into the directory that contains the input grammar file. <li><b>-D<i>name</i></b> Define C preprocessor macro <i>name</i>. This macro is usable by "<tt><a href='#pifdef'>%ifdef</a></tt>", "<tt><a href='#pifdef'>%ifndef</a></tt>", and "<tt><a href="#pifdef">%if</a></tt> lines in the grammar file. <li><b>-E</b> Run the "%if" preprocessor step only and print the revised grammar file. <li><b>-g</b> Do not generate a parser. Instead write the input grammar to standard output with all comments, actions, and other extraneous text removed. <li><b>-l</b> Omit "#line" directives in the generated parser C code. <li><b>-m</b> Cause the output C source code to be compatible with the "makeheaders" program. <li><b>-p</b> Display all conflicts that are resolved by <a href='#precrules'>precedence rules</a>. <li><b>-q</b> Suppress generation of the report file. <li><b>-r</b> Do not sort or renumber the parser states as part of optimization. <li><b>-s</b> Show parser statistics before exiting. <li><b>-T<i>file</i></b> Use <i>file</i> as the template for the generated C-code parser implementation. <li><b>-x</b> Print the Lemon version number. </ul> <a id="interface"></a> <h3>3.2 The Parser Interface</h3> <p>Lemon doesn't generate a complete, working program. It only generates a few subroutines that implement a parser. This section describes the interface to those subroutines. It is up to the programmer to call these subroutines in an appropriate way in order to produce a complete system.</p> <p>Before a program begins using a Lemon-generated parser, the program must first create the parser. A new parser is created as follows:</p> <pre> void *pParser = ParseAlloc( malloc ); </pre> <p>The ParseAlloc() routine allocates and initializes a new parser and returns a pointer to it. The actual data structure used to represent a parser is opaque — its internal structure is not visible or usable by the calling routine. For this reason, the ParseAlloc() routine returns a pointer to void rather than a pointer to some particular structure. The sole argument to the ParseAlloc() routine is a pointer to the subroutine used to allocate memory. Typically this means malloc().</p> <p>After a program is finished using a parser, it can reclaim all memory allocated by that parser by calling</p> <pre> ParseFree(pParser, free); </pre> <p>The first argument is the same pointer returned by ParseAlloc(). The second argument is a pointer to the function used to release bulk memory back to the system.</p> <p>After a parser has been allocated using ParseAlloc(), the programmer must supply the parser with a sequence of tokens (terminal symbols) to be parsed. This is accomplished by calling the following function once for each token:<p> <pre> Parse(pParser, hTokenID, sTokenData, pArg); </pre> <p>The first argument to the Parse() routine is the pointer returned by ParseAlloc(). The second argument is a small positive integer that tells the parser the type of the next token in the data stream. There is one token type for each terminal symbol in the grammar. The gram.h file generated by Lemon contains #define statements that map symbolic terminal symbol names into appropriate integer values. A value of 0 for the second argument is a special flag to the |
︙ | ︙ | |||
191 192 193 194 195 196 197 | the Parse() function will have a fourth parameter that can be of any type chosen by the programmer. The parser doesn't do anything with this argument except to pass it through to action routines. This is a convenient mechanism for passing state information down to the action routines without having to use global variables.</p> <p>A typical use of a Lemon parser might look something like the | | | | | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | | > | | 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 | the Parse() function will have a fourth parameter that can be of any type chosen by the programmer. The parser doesn't do anything with this argument except to pass it through to action routines. This is a convenient mechanism for passing state information down to the action routines without having to use global variables.</p> <p>A typical use of a Lemon parser might look something like the following:</p> <pre> 1 ParseTree *ParseFile(const char *zFilename){ 2 Tokenizer *pTokenizer; 3 void *pParser; 4 Token sToken; 5 int hTokenId; 6 ParserState sState; 7 8 pTokenizer = TokenizerCreate(zFilename); 9 pParser = ParseAlloc( malloc ); 10 InitParserState(&sState); 11 while( GetNextToken(pTokenizer, &hTokenId, &sToken) ){ 12 Parse(pParser, hTokenId, sToken, &sState); 13 } 14 Parse(pParser, 0, sToken, &sState); 15 ParseFree(pParser, free ); 16 TokenizerFree(pTokenizer); 17 return sState.treeRoot; 18 } </pre> <p>This example shows a user-written routine that parses a file of text and returns a pointer to the parse tree. (All error-handling code is omitted from this example to keep it simple.) We assume the existence of some kind of tokenizer which is created using TokenizerCreate() on line 8 and deleted by TokenizerFree() on line 16. The GetNextToken() function on line 11 retrieves the next token from the input file and puts its type in the integer variable hTokenId. The sToken variable is assumed to be some kind of structure that contains details about each token, such as its complete text, what line it occurs on, etc.</p> <p>This example also assumes the existence of a structure of type ParserState that holds state information about a particular parse. An instance of such a structure is created on line 6 and initialized on line 10. A pointer to this structure is passed into the Parse() routine as the optional 4th argument. The action routine specified by the grammar for the parser can use the ParserState structure to hold whatever information is useful and appropriate. In the example, we note that the treeRoot field of the ParserState structure is left pointing to the root of the parse tree.</p> <p>The core of this example as it relates to Lemon is as follows:</p> <pre> ParseFile(){ pParser = ParseAlloc( malloc ); while( GetNextToken(pTokenizer,&hTokenId, &sToken) ){ Parse(pParser, hTokenId, sToken); } Parse(pParser, 0, sToken); ParseFree(pParser, free ); } </pre> <p>Basically, what a program has to do to use a Lemon-generated parser is first create the parser, then send it lots of tokens obtained by tokenizing an input source. When the end of input is reached, the Parse() routine should be called one last time with a token type of 0. This step is necessary to inform the parser that the end of input has been reached. Finally, we reclaim memory used by the parser by calling ParseFree().</p> <p>There is one other interface routine that should be mentioned before we move on. The ParseTrace() function can be used to generate debugging output from the parser. A prototype for this routine is as follows:</p> <pre> ParseTrace(FILE *stream, char *zPrefix); </pre> <p>After this routine is called, a short (one-line) message is written to the designated output stream every time the parser changes states or calls an action routine. Each such message is prefaced using the text given by zPrefix. This debugging output can be turned off by calling ParseTrace() again with a first argument of NULL (0).</p> <a id="onstack"></a> <h4>3.2.1 Allocating The Parse Object On Stack</h4> <p>If all calls to the Parse() interface are made from within <a href="#pcode"><tt>%code</tt> directives</a>, then the parse object can be allocated from the stack rather than from the heap. These are the steps: <ul> <li> Declare a local variable of type "yyParser" <li> Initialize the variable using ParseInit() <li> Pass a pointer to the variable in calls ot Parse() <li> Deallocate substructure in the parse variable using ParseFinalize(). </ul> <p>The following code illustrates how this is done: <pre> ParseFile(){ yyParser x; ParseInit( &x ); while( GetNextToken(pTokenizer,&hTokenId, &sToken) ){ Parse(&x, hTokenId, sToken); } Parse(&x, 0, sToken); ParseFinalize( &x ); } </pre> <a id="ifsum"></a> <h4>3.2.2 Interface Summary</h4> <p>Here is a quick overview of the C-language interface to a Lemon-generated parser:</p> <blockquote><pre> void *ParseAlloc( (void*(*malloc)(size_t) ); void ParseFree(void *pParser, (void(*free)(void*) ); void Parse(void *pParser, int tokenCode, ParseTOKENTYPE token, ...); void ParseTrace(FILE *stream, char *zPrefix); </pre></blockquote> <p>Notes:</p> <ul> <li> Use the <a href="#pname"><tt>%name</tt> directive</a> to change the "Parse" prefix names of the procedures in the interface. <li> Use the <a href="#token_type"><tt>%token_type</tt> directive</a> to define the "ParseTOKENTYPE" type. <li> Use the <a href="#extraarg"><tt>%extra_argument</tt> directive</a> to specify the type and name of the 4th parameter to the Parse() function. </ul> <a id="yaccdiff"></a> <h3>3.3 Differences With YACC and BISON</h3> <p>Programmers who have previously used the yacc or bison parser generator will notice several important differences between yacc and/or bison and Lemon.</p> <ul> <li>In yacc and bison, the parser calls the tokenizer. In Lemon, the tokenizer calls the parser. <li>Lemon uses no global variables. Yacc and bison use global variables to pass information between the tokenizer and parser. <li>Lemon allows multiple parsers to be running simultaneously. Yacc and bison do not. </ul> <p>These differences may cause some initial confusion for programmers with prior yacc and bison experience. But after years of experience using Lemon, I firmly believe that the Lemon way of doing things is better.</p> <p><i>Updated as of 2016-02-16:</i> The text above was written in the 1990s. We are told that Bison has lately been enhanced to support the tokenizer-calls-parser paradigm used by Lemon, eliminating the need for global variables.</p> <a id="build"><a> <h3>3.4 Building The "lemon" or "lemon.exe" Executable</h3> <p>The "lemon" or "lemon.exe" program is built from a single file of C-code named "<a href="https://sqlite.org/src/tool/lemon.c">lemon.c</a>". The Lemon source code is generic C89 code that uses no unusual or non-standard libraries. Any reasonable C compiler should suffice to compile the lemon program. A command-line like the following will usually work:</p> <blockquote><pre> cc -o lemon lemon.c </pre></blockquote <p>On Windows machines with Visual C++ installed, bring up a "VS20<i>NN</i> x64 Native Tools Command Prompt" window and enter: <blockquote><pre> cl lemon.c </pre></blockquote> <p>Compiling Lemon really is that simple. Additional compiler options such as "-O2" or "-g" or "-Wall" can be added if desired, but they are not necessary.</p> <a id="syntax"></a> <h2>4.0 Input File Syntax</h2> <p>The main purpose of the grammar specification file for Lemon is to define the grammar for the parser. But the input file also specifies additional information Lemon requires to do its job. Most of the work in using Lemon is in writing an appropriate grammar file.</p> <p>The grammar file for Lemon is, for the most part, a free format. It does not have sections or divisions like yacc or bison. Any declaration can occur at any point in the file. Lemon ignores whitespace (except where it is needed to separate tokens), and it honors the same commenting conventions as C and C++.</p> <a id="tnt"></a> <h3>4.1 Terminals and Nonterminals</h3> <p>A terminal symbol (token) is any string of alphanumeric and/or underscore characters that begins with an uppercase letter. A terminal can contain lowercase letters after the first character, but the usual convention is to make terminals all uppercase. A nonterminal, on the other hand, is any string of alphanumeric |
︙ | ︙ | |||
330 331 332 333 334 335 336 | <p>Yacc and bison allow terminal symbols to have either alphanumeric names or to be individual characters included in single quotes, like this: ')' or '$'. Lemon does not allow this alternative form for terminal symbols. With Lemon, all symbols, terminals and nonterminals, must have alphanumeric names.</p> | > | | < | < | | | | | | | | | | | | | | | | | | | | | | | | | > | | > > > | | | > > > | | | | | | | | | | | | 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 | <p>Yacc and bison allow terminal symbols to have either alphanumeric names or to be individual characters included in single quotes, like this: ')' or '$'. Lemon does not allow this alternative form for terminal symbols. With Lemon, all symbols, terminals and nonterminals, must have alphanumeric names.</p> <a id="rules"></a> <h3>4.2 Grammar Rules</h3> <p>The main component of a Lemon grammar file is a sequence of grammar rules. Each grammar rule consists of a nonterminal symbol followed by the special symbol "::=" and then a list of terminals and/or nonterminals. The rule is terminated by a period. The list of terminals and nonterminals on the right-hand side of the rule can be empty. Rules can occur in any order, except that the left-hand side of the first rule is assumed to be the start symbol for the grammar (unless specified otherwise using the <tt><a href='#start_symbol'>%start_symbol</a></tt> directive described below.) A typical sequence of grammar rules might look something like this:</p> <pre> expr ::= expr PLUS expr. expr ::= expr TIMES expr. expr ::= LPAREN expr RPAREN. expr ::= VALUE. </pre> <p>There is one non-terminal in this example, "expr", and five terminal symbols or tokens: "PLUS", "TIMES", "LPAREN", "RPAREN" and "VALUE".</p> <p>Like yacc and bison, Lemon allows the grammar to specify a block of C code that will be executed whenever a grammar rule is reduced by the parser. In Lemon, this action is specified by putting the C code (contained within curly braces <tt>{...}</tt>) immediately after the period that closes the rule. For example:</p> <pre> expr ::= expr PLUS expr. { printf("Doing an addition...\n"); } </pre> <p>In order to be useful, grammar actions must normally be linked to their associated grammar rules. In yacc and bison, this is accomplished by embedding a "$$" in the action to stand for the value of the left-hand side of the rule and symbols "$1", "$2", and so forth to stand for the value of the terminal or nonterminal at position 1, 2 and so forth on the right-hand side of the rule. This idea is very powerful, but it is also very error-prone. The single most common source of errors in a yacc or bison grammar is to miscount the number of symbols on the right-hand side of a grammar rule and say "$7" when you really mean "$8".</p> <p>Lemon avoids the need to count grammar symbols by assigning symbolic names to each symbol in a grammar rule and then using those symbolic names in the action. In yacc or bison, one would write this:</p> <pre> expr -> expr PLUS expr { $$ = $1 + $3; }; </pre> <p>But in Lemon, the same rule becomes the following:</p> <pre> expr(A) ::= expr(B) PLUS expr(C). { A = B+C; } </pre> <p>In the Lemon rule, any symbol in parentheses after a grammar rule symbol becomes a place holder for that symbol in the grammar rule. This place holder can then be used in the associated C action to stand for the value of that symbol.</p> <p>The Lemon notation for linking a grammar rule with its reduce action is superior to yacc/bison on several counts. First, as mentioned above, the Lemon method avoids the need to count grammar symbols. Secondly, if a terminal or nonterminal in a Lemon grammar rule includes a linking symbol in parentheses but that linking symbol is not actually used in the reduce action, then an error message is generated. For example, the rule</p> <pre> expr(A) ::= expr(B) PLUS expr(C). { A = B; } </pre> <p>will generate an error because the linking symbol "C" is used in the grammar rule but not in the reduce action.</p> <p>The Lemon notation for linking grammar rules to reduce actions also facilitates the use of destructors for reclaiming memory allocated by the values of terminals and nonterminals on the right-hand side of a rule.</p> <a id='precrules'></a> <h3>4.3 Precedence Rules</h3> <p>Lemon resolves parsing ambiguities in exactly the same way as yacc and bison. A shift-reduce conflict is resolved in favor of the shift, and a reduce-reduce conflict is resolved by reducing whichever rule comes first in the grammar file.</p> <p>Just like in yacc and bison, Lemon allows a measure of control over the resolution of parsing conflicts using precedence rules. A precedence value can be assigned to any terminal symbol using the <tt><a href='#pleft'>%left</a></tt>, <tt><a href='#pright'>%right</a></tt> or <tt><a href='#pnonassoc'>%nonassoc</a></tt> directives. Terminal symbols mentioned in earlier directives have a lower precedence than terminal symbols mentioned in later directives. For example:</p> <pre> %left AND. %left OR. %nonassoc EQ NE GT GE LT LE. %left PLUS MINUS. %left TIMES DIVIDE MOD. %right EXP NOT. </pre> <p>In the preceding sequence of directives, the AND operator is defined to have the lowest precedence. The OR operator is one precedence level higher. And so forth. Hence, the grammar would attempt to group the ambiguous expression</p> <pre> a AND b OR c </pre> <p>like this</p> <pre> a AND (b OR c). </pre> <p>The associativity (left, right or nonassoc) is used to determine the grouping when the precedence is the same. AND is left-associative in our example, so</p> <pre> a AND b AND c </pre> <p>is parsed like this</p> <pre> (a AND b) AND c. </pre> <p>The EXP operator is right-associative, though, so</p> <pre> a EXP b EXP c </pre> <p>is parsed like this</p> <pre> a EXP (b EXP c). </pre> <p>The nonassoc precedence is used for non-associative operators. So</p> <pre> a EQ b EQ c </pre> <p>is an error.</p> <p>The precedence of non-terminals is transferred to rules as follows: The precedence of a grammar rule is equal to the precedence of the left-most terminal symbol in the rule for which a precedence is defined. This is normally what you want, but in those cases where you want the precedence of a grammar rule to be something different, you can specify an alternative precedence symbol by putting the symbol in square braces after the period at the end of the rule and before any C-code. For example:</p> <pre> expr = MINUS expr. [NOT] </pre> <p>This rule has a precedence equal to that of the NOT symbol, not the MINUS symbol as would have been the case by default.</p> <p>With the knowledge of how precedence is assigned to terminal symbols and individual grammar rules, we can now explain precisely how parsing conflicts are resolved in Lemon. Shift-reduce conflicts are resolved as follows:</p> <ul> <li> If either the token to be shifted or the rule to be reduced lacks precedence information, then resolve in favor of the shift, but report a parsing conflict. <li> If the precedence of the token to be shifted is greater than the precedence of the rule to reduce, then resolve in favor of the shift. No parsing conflict is reported. <li> If the precedence of the token to be shifted is less than the precedence of the rule to reduce, then resolve in favor of the reduce action. No parsing conflict is reported. <li> If the precedences are the same and the shift token is right-associative, then resolve in favor of the shift. No parsing conflict is reported. <li> If the precedences are the same and the shift token is left-associative, then resolve in favor of the reduce. No parsing conflict is reported. <li> Otherwise, resolve the conflict by doing the shift, and report a parsing conflict. </ul> <p>Reduce-reduce conflicts are resolved this way:</p> <ul> <li> If either reduce rule lacks precedence information, then resolve in favor of the rule that appears first in the grammar, and report a parsing conflict. <li> If both rules have precedence and the precedence is different, then resolve the dispute in favor of the rule with the highest precedence, and do not report a conflict. <li> Otherwise, resolve the conflict by reducing by the rule that appears first in the grammar, and report a parsing conflict. </ul> <a id="special"></a> <h3>4.4 Special Directives</h3> <p>The input grammar to Lemon consists of grammar rules and special directives. We've described all the grammar rules, so now we'll talk about the special directives.</p> <p>Directives in Lemon can occur in any order. You can put them before the grammar rules, or after the grammar rules, or in the midst of the grammar rules. It doesn't matter. The relative order of directives used to assign precedence to terminals is important, but other than that, the order of directives in Lemon is arbitrary.</p> <p>Lemon supports the following special directives:</p> <ul> <li><tt><a href='#pcode'>%code</a></tt> <li><tt><a href='#default_destructor'>%default_destructor</a></tt> <li><tt><a href='#default_type'>%default_type</a></tt> <li><tt><a href='#destructor'>%destructor</a></tt> <li><tt><a href='#pifdef'>%else</a></tt> <li><tt><a href='#pifdef'>%endif</a></tt> <li><tt><a href='#extraarg'>%extra_argument</a></tt> <li><tt><a href='#pfallback'>%fallback</a></tt> <li><tt><a href='#pifdef'>%if</a></tt> <li><tt><a href='#pifdef'>%ifdef</a></tt> <li><tt><a href='#pifdef'>%ifndef</a></tt> <li><tt><a href='#pinclude'>%include</a></tt> <li><tt><a href='#pleft'>%left</a></tt> <li><tt><a href='#pname'>%name</a></tt> <li><tt><a href='#pnonassoc'>%nonassoc</a></tt> <li><tt><a href='#parse_accept'>%parse_accept</a></tt> <li><tt><a href='#parse_failure'>%parse_failure</a></tt> <li><tt><a href='#pright'>%right</a></tt> <li><tt><a href='#stack_overflow'>%stack_overflow</a></tt> <li><tt><a href='#stack_size'>%stack_size</a></tt> <li><tt><a href='#start_symbol'>%start_symbol</a></tt> <li><tt><a href='#syntax_error'>%syntax_error</a></tt> <li><tt><a href='#token'>%token</a></tt> <li><tt><a href='#token_class'>%token_class</a></tt> <li><tt><a href='#token_destructor'>%token_destructor</a></tt> <li><tt><a href='#token_prefix'>%token_prefix</a></tt> <li><tt><a href='#token_type'>%token_type</a></tt> <li><tt><a href='#ptype'>%type</a></tt> <li><tt><a href='#pwildcard'>%wildcard</a></tt> </ul> <p>Each of these directives will be described separately in the following sections:</p> <a id='pcode'></a> <h4>4.4.1 The <tt>%code</tt> directive</h4> <p>The <tt>%code</tt> directive is used to specify additional C code that is added to the end of the main output file. This is similar to the <tt><a href='#pinclude'>%include</a></tt> directive except that <tt>%include</tt> is inserted at the beginning of the main output file.</p> <p><tt>%code</tt> is typically used to include some action routines or perhaps a tokenizer or even the "main()" function as part of the output file.</p> <p>There can be multiple <tt>%code</tt> directives. The arguments of all <tt>%code</tt> directives are concatenated.</p> <a id='default_destructor'></a> <h4>4.4.2 The <tt>%default_destructor</tt> directive</h4> <p>The <tt>%default_destructor</tt> directive specifies a destructor to use for non-terminals that do not have their own destructor specified by a separate <tt>%destructor</tt> directive. See the documentation on the <tt><a href='#destructor'>%destructor</a></tt> directive below for additional information.</p> <p>In some grammars, many different non-terminal symbols have the same data type and hence the same destructor. This directive is a convenient way to specify the same destructor for all those non-terminals using a single statement.</p> <a id='default_type'></a> <h4>4.4.3 The <tt>%default_type</tt> directive</h4> <p>The <tt>%default_type</tt> directive specifies the data type of non-terminal symbols that do not have their own data type defined using a separate <tt><a href='#ptype'>%type</a></tt> directive.</p> <a id='destructor'></a> <h4>4.4.4 The <tt>%destructor</tt> directive</h4> <p>The <tt>%destructor</tt> directive is used to specify a destructor for a non-terminal symbol. (See also the <tt><a href='#token_destructor'>%token_destructor</a></tt> directive which is used to specify a destructor for terminal symbols.)</p> <p>A non-terminal's destructor is called to dispose of the non-terminal's value whenever the non-terminal is popped from the stack. This includes all of the following circumstances:</p> <ul> <li> When a rule reduces and the value of a non-terminal on the right-hand side is not linked to C code. <li> When the stack is popped during error processing. <li> When the ParseFree() function runs. </ul> <p>The destructor can do whatever it wants with the value of the non-terminal, but its design is to deallocate memory or other resources held by that non-terminal.</p> <p>Consider an example:</p> <pre> %type nt {void*} %destructor nt { free($$); } nt(A) ::= ID NUM. { A = malloc( 100 ); } </pre> <p>This example is a bit contrived, but it serves to illustrate how destructors work. The example shows a non-terminal named "nt" that holds values of type "void*". When the rule for an "nt" reduces, it sets the value of the non-terminal to space obtained from malloc(). Later, when the nt non-terminal is popped from the stack, the destructor will fire and call free() on this malloced space, thus avoiding a memory leak. (Note that the symbol "$$" in the destructor code is replaced |
︙ | ︙ | |||
660 661 662 663 664 665 666 | larger structure, and we don't want to destroy it, which is why the destructor is not called in this circumstance.</p> <p>Destructors help avoid memory leaks by automatically freeing allocated objects when they go out of scope. To do the same using yacc or bison is much more difficult.</p> | | | | | | | | | | | | | | | | | | | | | > | | | > > > > > > > > > > > | | < | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | > > > > > > > > > > > > > > > > > > > > > > > | | | | | | | | | | | | | | | | | | | | | | | 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 | larger structure, and we don't want to destroy it, which is why the destructor is not called in this circumstance.</p> <p>Destructors help avoid memory leaks by automatically freeing allocated objects when they go out of scope. To do the same using yacc or bison is much more difficult.</p> <a id='extraarg'></a> <h4>4.4.5 The <tt>%extra_argument</tt> directive</h4> <p>The <tt>%extra_argument</tt> directive instructs Lemon to add a 4th parameter to the parameter list of the Parse() function it generates. Lemon doesn't do anything itself with this extra argument, but it does make the argument available to C-code action routines, destructors, and so forth. For example, if the grammar file contains:</p> <pre> %extra_argument { MyStruct *pAbc } </pre> <p>Then the Parse() function generated will have an 4th parameter of type "MyStruct*" and all action routines will have access to a variable named "pAbc" that is the value of the 4th parameter in the most recent call to Parse().</p> <p>The <tt>%extra_context</tt> directive works the same except that it is passed in on the ParseAlloc() or ParseInit() routines instead of on Parse().</p> <a id='extractx'></a> <h4>4.4.6 The <tt>%extra_context</tt> directive</h4> <p>The <tt>%extra_context</tt> directive instructs Lemon to add a 2nd parameter to the parameter list of the ParseAlloc() and ParseInit() functions. Lemon doesn't do anything itself with these extra argument, but it does store the value make it available to C-code action routines, destructors, and so forth. For example, if the grammar file contains:</p> <pre> %extra_context { MyStruct *pAbc } </pre> <p>Then the ParseAlloc() and ParseInit() functions will have an 2nd parameter of type "MyStruct*" and all action routines will have access to a variable named "pAbc" that is the value of that 2nd parameter.</p> <p>The <tt>%extra_argument</tt> directive works the same except that it is passed in on the Parse() routine instead of on ParseAlloc()/ParseInit().</p> <a id='pfallback'></a> <h4>4.4.7 The <tt>%fallback</tt> directive</h4> <p>The <tt>%fallback</tt> directive specifies an alternative meaning for one or more tokens. The alternative meaning is tried if the original token would have generated a syntax error.</p> <p>The <tt>%fallback</tt> directive was added to support robust parsing of SQL syntax in <a href='https://www.sqlite.org/'>SQLite</a>. The SQL language contains a large assortment of keywords, each of which appears as a different token to the language parser. SQL contains so many keywords that it can be difficult for programmers to keep up with them all. Programmers will, therefore, sometimes mistakenly use an obscure language keyword for an identifier. The <tt>%fallback</tt> directive provides a mechanism to tell the parser: "If you are unable to parse this keyword, try treating it as an identifier instead."</p> <p>The syntax of <tt>%fallback</tt> is as follows:</p> <blockquote> <tt>%fallback</tt> <i>ID</i> <i>TOKEN...</i> <b>.</b> </blockquote></p> <p>In words, the <tt>%fallback</tt> directive is followed by a list of token names terminated by a period. The first token name is the fallback token — the token to which all the other tokens fall back to. The second and subsequent arguments are tokens which fall back to the token identified by the first argument.</p> <a id='pifdef'></a> <h4>4.4.8 The <tt>%if</tt> directive and its friends</h4> <p>The <tt>%if</tt>, <tt>%ifdef</tt>, <tt>%ifndef</tt>, <tt>%else</tt>, and <tt>%endif</tt> directives are similar to #if, #ifdef, #ifndef, #else, and #endif in the C-preprocessor, just not as general. Each of these directives must begin at the left margin. No whitespace is allowed between the "%" and the directive name.</p> <p>Grammar text in between "<tt>%ifdef MACRO</tt>" and the next nested "<tt>%endif</tt>" is ignored unless the "-DMACRO" command-line option is used. Grammar text betwen "<tt>%ifndef MACRO</tt>" and the next nested "<tt>%endif</tt>" is included except when the "-DMACRO" command-line option is used.<p> <p>The text in between "<tt>%if</tt> <i>CONDITIONAL</i>" and its corresponding <tt>%endif</tt> is included only if <i>CONDITIONAL</i> is true. The CONDITION is one or more macro names, optionally connected using the "||" and "&&" binary operators, the "!" unary operator, and grouped using balanced parentheses. Each term is true if the corresponding macro exists, and false if it does not exist.</p> <p>An optional "<tt>%else</tt>" directive can occur anywhere in between a <tt>%ifdef</tt>, <tt>%ifndef</tt>, or <tt>%if</tt> directive and its corresponding <tt>%endif</tt>.</p> <p>Note that the argument to <tt>%ifdef</tt> and <tt>%ifndef</tt> is intended to be a single preprocessor symbol name, not a general expression. Use the "<tt>%if</tt>" directive for general expressions.</p> <a id='pinclude'></a> <h4>4.4.9 The <tt>%include</tt> directive</h4> <p>The <tt>%include</tt> directive specifies C code that is included at the top of the generated parser. You can include any text you want — the Lemon parser generator copies it blindly. If you have multiple <tt>%include</tt> directives in your grammar file, their values are concatenated so that all <tt>%include</tt> code ultimately appears near the top of the generated parser, in the same order as it appeared in the grammar.</p> <p>The <tt>%include</tt> directive is very handy for getting some extra #include preprocessor statements at the beginning of the generated parser. For example:</p> <pre> %include {#include <unistd.h>} </pre> <p>This might be needed, for example, if some of the C actions in the grammar call functions that are prototyped in unistd.h.</p> <p>Use the <tt><a href="#pcode">%code</a></tt> directive to add code to the end of the generated parser.</p> <a id='pleft'></a> <h4>4.4.10 The <tt>%left</tt> directive</h4> The <tt>%left</tt> directive is used (along with the <tt><a href='#pright'>%right</a></tt> and <tt><a href='#pnonassoc'>%nonassoc</a></tt> directives) to declare precedences of terminal symbols. Every terminal symbol whose name appears after a <tt>%left</tt> directive but before the next period (".") is given the same left-associative precedence value. Subsequent <tt>%left</tt> directives have higher precedence. For example:</p> <pre> %left AND. %left OR. %nonassoc EQ NE GT GE LT LE. %left PLUS MINUS. %left TIMES DIVIDE MOD. %right EXP NOT. </pre> <p>Note the period that terminates each <tt>%left</tt>, <tt>%right</tt> or <tt>%nonassoc</tt> directive.</p> <p>LALR(1) grammars can get into a situation where they require a large amount of stack space if you make heavy use or right-associative operators. For this reason, it is recommended that you use <tt>%left</tt> rather than <tt>%right</tt> whenever possible.</p> <a id='pname'></a> <h4>4.4.11 The <tt>%name</tt> directive</h4> <p>By default, the functions generated by Lemon all begin with the five-character string "Parse". You can change this string to something different using the <tt>%name</tt> directive. For instance:</p> <pre> %name Abcde </pre> <p>Putting this directive in the grammar file will cause Lemon to generate functions named</p> <ul> <li> AbcdeAlloc(), <li> AbcdeFree(), <li> AbcdeTrace(), and <li> Abcde(). </ul> </p>The <tt>%name</tt> directive allows you to generate two or more different parsers and link them all into the same executable.</p> <a id='pnonassoc'></a> <h4>4.4.12 The <tt>%nonassoc</tt> directive</h4> <p>This directive is used to assign non-associative precedence to one or more terminal symbols. See the section on <a href='#precrules'>precedence rules</a> or on the <tt><a href='#pleft'>%left</a></tt> directive for additional information.</p> <a id='parse_accept'></a> <h4>4.4.13 The <tt>%parse_accept</tt> directive</h4> <p>The <tt>%parse_accept</tt> directive specifies a block of C code that is executed whenever the parser accepts its input string. To "accept" an input string means that the parser was able to process all tokens without error.</p> <p>For example:</p> <pre> %parse_accept { printf("parsing complete!\n"); } </pre> <a id='parse_failure'></a> <h4>4.4.14 The <tt>%parse_failure</tt> directive</h4> <p>The <tt>%parse_failure</tt> directive specifies a block of C code that is executed whenever the parser fails complete. This code is not executed until the parser has tried and failed to resolve an input error using is usual error recovery strategy. The routine is only invoked when parsing is unable to continue.</p> <pre> %parse_failure { fprintf(stderr,"Giving up. Parser is hopelessly lost...\n"); } </pre> <a id='pright'></a> <h4>4.4.15 The <tt>%right</tt> directive</h4> <p>This directive is used to assign right-associative precedence to one or more terminal symbols. See the section on <a href='#precrules'>precedence rules</a> or on the <a href='#pleft'>%left</a> directive for additional information.</p> <a id='stack_overflow'></a> <h4>4.4.16 The <tt>%stack_overflow</tt> directive</h4> <p>The <tt>%stack_overflow</tt> directive specifies a block of C code that is executed if the parser's internal stack ever overflows. Typically this just prints an error message. After a stack overflow, the parser will be unable to continue and must be reset.</p> <pre> %stack_overflow { fprintf(stderr,"Giving up. Parser stack overflow\n"); } </pre> <p>You can help prevent parser stack overflows by avoiding the use of right recursion and right-precedence operators in your grammar. Use left recursion and and left-precedence operators instead to encourage rules to reduce sooner and keep the stack size down. For example, do rules like this:</p> <pre> list ::= list element. // left-recursion. Good! list ::= . </pre> <p>Not like this:</p> <pre> list ::= element list. // right-recursion. Bad! list ::= . </pre> <a id='stack_size'></a> <h4>4.4.17 The <tt>%stack_size</tt> directive</h4> <p>If stack overflow is a problem and you can't resolve the trouble by using left-recursion, then you might want to increase the size of the parser's stack using this directive. Put an positive integer after the <tt>%stack_size</tt> directive and Lemon will generate a parse with a stack of the requested size. The default value is 100.</p> <pre> %stack_size 2000 </pre> <a id='start_symbol'></a> <h4>4.4.18 The <tt>%start_symbol</tt> directive</h4> <p>By default, the start symbol for the grammar that Lemon generates is the first non-terminal that appears in the grammar file. But you can choose a different start symbol using the <tt>%start_symbol</tt> directive.</p> <pre> %start_symbol prog </pre> <a id='syntax_error'></a> <h4>4.4.19 The <tt>%syntax_error</tt> directive</h4> <p>See <a href='#errors'>Error Processing</a>.</p> <a id='token'></a> <h4>4.4.20 The <tt>%token</tt> directive</h4> <p>Tokens are normally created automatically, the first time they are used. Any identifier that begins with an upper-case letter is a token. <p>Sometimes it is useful to declare tokens in advance, however. The integer values assigned to each token determined by the order in which the tokens are seen. So by declaring tokens in advance, it is possible to cause some tokens to have low-numbered values, which might be desirable in some grammers, or to have sequential values assigned to a sequence of related tokens. For this reason, the %token directive is provided to declare tokens in advance. The syntax is as follows: <blockquote> <tt>%token</tt> <i>TOKEN</i> <i>TOKEN...</i> <b>.</b> </blockquote></p> <p>The %token directive is followed by zero or more token symbols and terminated by a single ".". Each token named is created if it does not already exist. Tokens are created in order. <a id='token_class'></a> <h4>4.4.21 The <tt>%token_class</tt> directive</h4> <p>Undocumented. Appears to be related to the MULTITERMINAL concept. <a href='http://sqlite.org/src/fdiff?v1=796930d5fc2036c7&v2=624b24c5dc048e09&sbs=0'>Implementation</a>.</p> <a id='token_destructor'></a> <h4>4.4.22 The <tt>%token_destructor</tt> directive</h4> <p>The <tt>%destructor</tt> directive assigns a destructor to a non-terminal symbol. (See the description of the <tt><a href='%destructor'>%destructor</a></tt> directive above.) The <tt>%token_destructor</tt> directive does the same thing for all terminal symbols.</p> <p>Unlike non-terminal symbols, which may each have a different data type for their values, terminals all use the same data type (defined by the <tt><a href='#token_type'>%token_type</a></tt> directive) and so they use a common destructor. Other than that, the token destructor works just like the non-terminal destructors.</p> <a id='token_prefix'></a> <h4>4.4.23 The <tt>%token_prefix</tt> directive</h4> <p>Lemon generates #defines that assign small integer constants to each terminal symbol in the grammar. If desired, Lemon will add a prefix specified by this directive to each of the #defines it generates.</p> <p>So if the default output of Lemon looked like this:</p> <pre> #define AND 1 #define MINUS 2 #define OR 3 #define PLUS 4 </pre> <p>You can insert a statement into the grammar like this:</p> <pre> %token_prefix TOKEN_ </pre> <p>to cause Lemon to produce these symbols instead:</p> <pre> #define TOKEN_AND 1 #define TOKEN_MINUS 2 #define TOKEN_OR 3 #define TOKEN_PLUS 4 </pre> <a id='token_type'></a><a id='ptype'></a> <h4>4.4.24 The <tt>%token_type</tt> and <tt>%type</tt> directives</h4> <p>These directives are used to specify the data types for values on the parser's stack associated with terminal and non-terminal symbols. The values of all terminal symbols must be of the same type. This turns out to be the same data type as the 3rd parameter to the Parse() function generated by Lemon. Typically, you will make the value of a terminal symbol be a pointer to some kind of token structure. Like this:</p> <pre> %token_type {Token*} </pre> <p>If the data type of terminals is not specified, the default value is "void*".</p> <p>Non-terminal symbols can each have their own data types. Typically the data type of a non-terminal is a pointer to the root of a parse tree structure that contains all information about that non-terminal. For example:</p> <pre> %type expr {Expr*} </pre> <p>Each entry on the parser's stack is actually a union containing instances of all data types for every non-terminal and terminal symbol. Lemon will automatically use the correct element of this union depending on what the corresponding non-terminal or terminal symbol is. But the grammar designer should keep in mind that the size of the union will be the size of its largest element. So if you have a single non-terminal whose data type requires 1K of storage, then your 100 entry parser stack will require 100K of heap space. If you are willing and able to pay that price, fine. You just need to know.</p> <a id='pwildcard'></a> <h4>4.4.25 The <tt>%wildcard</tt> directive</h4> <p>The <tt>%wildcard</tt> directive is followed by a single token name and a period. This directive specifies that the identified token should match any input token.</p> <p>When the generated parser has the choice of matching an input against the wildcard token and some other token, the other token is always used. The wildcard token is only matched if there are no alternatives.</p> <a id='errors'></a> <h2>5.0 Error Processing</h2> <p>After extensive experimentation over several years, it has been discovered that the error recovery strategy used by yacc is about as good as it gets. And so that is what Lemon uses.</p> <p>When a Lemon-generated parser encounters a syntax error, it first invokes the code specified by the <tt>%syntax_error</tt> directive, if |
︙ | ︙ | |||
1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 | <p>If the parser pops its stack until the stack is empty, and it still is unable to shift the error symbol, then the <tt><a href='#parse_failure'>%parse_failure</a></tt> routine is invoked and the parser resets itself to its start state, ready to begin parsing a new file. This is what will happen at the very first syntax error, of course, if there are no instances of the "error" non-terminal in your grammar.</p> </body> </html> | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | <p>If the parser pops its stack until the stack is empty, and it still is unable to shift the error symbol, then the <tt><a href='#parse_failure'>%parse_failure</a></tt> routine is invoked and the parser resets itself to its start state, ready to begin parsing a new file. This is what will happen at the very first syntax error, of course, if there are no instances of the "error" non-terminal in your grammar.</p> <a id='history'></a> <h2>6.0 History of Lemon</h2> <p>Lemon was originally written by Richard Hipp sometime in the late 1980s on a Sun4 Workstation using K&R C. There was a companion LL(1) parser generator program named "Lime", the source code to which as been lost.</p> <p>The lemon.c source file was originally many separate files that were compiled together to generate the "lemon" executable. Sometime in the 1990s, the individual source code files were combined together into the current single large "lemon.c" source file. You can still see traces of original filenames in the code.</p> <p>Since 2001, Lemon has been part of the <a href="https://sqlite.org/">SQLite project</a> and the source code to Lemon has been managed as a part of the <a href="https://sqlite.org/src">SQLite source tree</a> in the following files:</p> <ul> <li> <a href="https://sqlite.org/src/file/tool/lemon.c">tool/lemon.c</a> <li> <a href="https://sqlite.org/src/file/tool/lempar.c">tool/lempar.c</a> <li> <a href="https://sqlite.org/src/file/doc/lemon.html">doc/lemon.html</a> </ul> <a id="copyright"></a> <h2>7.0 Copyright</h2> <p>All of the source code to Lemon, including the template parser file "lempar.c" and this documentation file ("lemon.html") are in the public domain. You can use the code for any purpose and without attribution.</p> <p>The code comes with no warranty. If it breaks, you get to keep both pieces.</p> </body> </html> |
Added doc/trusted-schema.md.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | # The new-security-options branch ## The problem that the [new-security-options](/timeline?r=new-security-options) branch tries to solve An attacker might modify the schema of an SQLite database by adding structures that cause code to run when some other application opens and reads the database. For example, the attacker might replace a table definition with a view. Or the attacker might add triggers to tables or views, or add new CHECK constraints or generated columns or indexes with expressions in the index list or in the WHERE clause. If the added features invoke SQL functions or virtual tables with side effects, that might cause harm to the system if run by a high-privilege victim. Or, the added features might exfiltrate information if the database is read by a high-privilege victim. The changes in this branch strive to make it easier for high-privilege applications to safely read SQLite database files that might have been maliciously corrupted by an attacker. ## Overview of changes in [new-security-options](/timeline?r=new-security-options) The basic idea is to tag every SQL function and virtual table with one of three risk levels: 1. Innocuous 2. Normal 3. Direct-Only Innocuous functions/vtabs are safe and can be used at any time. Direct-only elements, in contrast, might have cause side-effects and should only be used from top-level SQL, not from within triggers or views nor in elements of the schema such as CHECK constraint, DEFAULT values, generated columns, index expressions, or in the WHERE clause of a partial index that are potentially under the control of an attacker. Normal elements behave like Innocuous if TRUSTED\_SCHEMA=on and behave like direct-only if TRUSTED\_SCHEMA=off. Application-defined functions and virtual tables go in as Normal unless the application takes deliberate steps to change the risk level. For backwards compatibility, the default is TRUSTED\_SCHEMA=on. Documentation will be updated to recommend applications turn TRUSTED\_SCHEMA to off. An innocuous function or virtual table is one that can only read content from the database file in which it resides, and can only alter the database in which it resides. Most SQL functions are innocuous. For example, there is no harm in an attacker running the abs() function. Direct-only elements that have side-effects that go outside the database file in which it lives, or return information from outside of the database file. Examples of direct-only elements include: 1. The fts3\_tokenizer() function 2. The writefile() function 3. The readfile() function 4. The zipvfs virtual table 5. The csv virtual table We do not want an attacker to be able to add these kinds of things to the database schema and possibly trick a high-privilege application from performing any of these actions. Therefore, functions and vtabs with side-effects are marked as Direct-Only. Legacy applications might add other risky functions or vtabs. Those will go in as "Normal" by default. For optimal security, we want those risky app-defined functions and vtabs to be direct-only, but making that the default might break some legacy applications. Hence, all app-defined functions and vtabs go in as Normal, but the application can switch them over to "Direct-Only" behavior using a single pragma. The restrictions on the use of functions and virtual tables do not apply to TEMP. A TEMP VIEW or a TEMP TRIGGER can use any valid SQL function or virtual table. The idea is that TEMP views and triggers must be directly created by the application and are thus under the control of the application. TEMP views and triggers cannot be created by an attacker who corrupts the schema of a persistent database file. Hence TEMP views and triggers are safe. ## Specific changes 1. New sqlite3\_db\_config() option SQLITE\_DBCONFIG\_TRUSTED\_SCHEMA for turning TRUSTED\_SCHEMA on and off. It defaults to ON. 2. Compile-time option -DSQLITE\_TRUSTED\_SCHEMA=0 causes the default TRUSTED\_SCHEMA setting to be off. 3. New pragma "PRAGMA trusted\_schema=(ON\|OFF);". This provides access to the TRUSTED_SCHEMA setting for application coded using scripting languages or other secondary languages where they are unable to make calls to sqlite3\_db\_config(). 4. New options for the "enc" parameter to sqlite3\_create\_function() and its kin: <ol type="a"> <li> _SQLITE\_INNOCUOUS_ → tags the new functions as Innocuous <li> _SQLITE\_DIRECTONLY_ → tags the new functions as Direct-Only </ol> 5. New options to sqlite3\_vtab\_config(): <ol type="a"> <li> _SQLITE\_VTAB\_INNOCUOUS_ → tags the vtab as Innocuous <li> _SQLITE\_VTAB\_DIRECTONLY_ → tags the vtab as Direct-Only </ol> 6. Change many of the functions and virtual tables in the SQLite source tree to use one of the tags above. 7. Enhanced PRAGMA function\_list and virtual-table "pragma\_function\_list" with additional columns. The columns now are: <ul> <li> _name_ → Name of the function <li> _builtin_ → 1 for built-in functions. 0 otherwise. <li> _type_ → 's'=Scalar, 'a'=Aggregate, 'w'=Window <li> _enc_ → 'utf8', 'utf16le', or 'utf16be' <li> _narg_ → number of argument <li> _flags_ → Bitmask of SQLITE\_INNOCUOUS, SQLITE\_DIRECTONLY, SQLITE\_DETERMINISTIC, SQLITE\_SUBTYPE, and SQLITE\_FUNC\_INTERNAL flags. </ul> <p>The last four columns are new. 8. The function\_list PRAGMA now also shows all entries for each function. So, for example, if a function can take either 2 or 3 arguments, there are separate rows for the 2-argument and 3-argument versions of the function. ## Additional Notes The function_list enhancements allow the application to query the set of SQL functions that meet various criteria. For example, to see all SQL functions that are never allowed to be used in the schema or in trigger or views: ~~~ SELECT DISTINCT name FROM pragma_function_list WHERE (flags & 0x80000)!=0 ORDER BY name; ~~~ Doing the same is not possible for virtual tables, as a virtual table might be Innocuous, Normal, or Direct-Only depending on the arguments passed into the xConnect method. |
Added doc/vdbesort-memory.md.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | 20-11-2020 # Memory Allocation In vdbesort.c Memory allocation is slightly different depending on: * whether or not SQLITE_CONFIG_SMALL_MALLOC is set, and * whether or not worker threads are enabled. ## SQLITE_CONFIG_SMALL_MALLOC=0 Assuming SQLITE_CONFIG_SMALL_MALLOC is not set, keys passed to the sorter are added to an in-memory buffer. This buffer is grown using sqlite3Realloc() as required it reaches the size configured for the main pager cache using "PRAGMA cache_size". i.e. if the user has executed "PRAGMA main.cache_size = -2048", then this buffer is allowed to grow up to 2MB in size. Once the buffer has grown to its threshold, keys are sorted and written to a temp file. If worker threads are not enabled, this is the only significant allocation the sorter module makes. After keys are sorted and flushed out to the temp file, the buffer is reused to accumulate the next batch of keys. If worker threads are available, then the buffer is passed to a worker thread to sort and flush once it is full, and a new buffer allocated to allow the main thread to continue to accumulate keys. Buffers are reused once they have been flushed, so in this case at most (nWorker+1) buffers are allocated and used, where nWorker is the number of configured worker threads. There are no other significant users of heap memory in the sorter module. Once sorted buffers of keys have been flushed to disk, they are read back either by mapping the file (via sqlite3_file.xFetch()) or else read back in one page at a time. All buffers are allocated by the main thread. A sorter object is associated with a single database connection, to which it holds a pointer. ## SQLITE_CONFIG_SMALL_MALLOC=1 This case is similar to the above, except that instead of accumulating multiple keys in a single large buffer, sqlite3VdbeSorterWrite() stores keys in a regular heap-memory linked list (one allocation per element). List elements are freed as they are flushed to disk, either by the main thread or by a worker thread. Each time a key is added the sorter (and an allocation made), sqlite3HeapNearlyFull() is called. If it returns true, the current list of keys is flushed to a temporary file, even if it has not yet reached the size threshold. |
Added doc/wal-lock.md.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | # Wal-Mode Blocking Locks On some Unix-like systems, SQLite may be configured to use POSIX blocking locks by: * building the library with SQLITE\_ENABLE\_SETLK\_TIMEOUT defined, and * configuring a timeout in ms using the sqlite3\_busy\_timeout() API. Blocking locks may be advantageous as (a) waiting database clients do not need to continuously poll the database lock, and (b) using blocking locks facilitates transfer of OS priority between processes when a high priority process is blocked by a lower priority one. Only read/write clients use blocking locks. Clients that have read-only access to the \*-shm file nevery use blocking locks. Threads or processes that access a single database at a time never deadlock as a result of blocking database locks. But it is of course possible for threads that lock multiple databases simultaneously to do so. In most cases the OS will detect the deadlock and return an error. ## Wal Recovery Wal database "recovery" is a process required when the number of connected database clients changes from zero to one. In this case, a client is considered to connect to the database when it first reads data from it. Before recovery commences, an exclusive WRITER lock is taken. Without blocking locks, if two clients attempt recovery simultaneously, one fails to obtain the WRITER lock and either invokes the busy-handler callback or returns SQLITE\_BUSY to the user. With blocking locks configured, the second client blocks on the WRITER lock. ## Database Readers Usually, read-only are not blocked by any other database clients, so they have no need of blocking locks. If a read-only transaction is being opened on a snapshot, the CHECKPOINTER lock is required briefly as part of opening the transaction (to check that a checkpointer is not currently overwriting the snapshot being opened). A blocking lock is used to obtain the CHECKPOINTER lock in this case. A snapshot opener may therefore block on and transfer priority to a checkpointer in some cases. ## Database Writers A database writer must obtain the exclusive WRITER lock. It uses a blocking lock to do so if any of the following are true: * the transaction is an implicit one consisting of a single DML or DDL statement, or * the transaction is opened using BEGIN IMMEDIATE or BEGIN EXCLUSIVE, or * the first SQL statement executed following the BEGIN command is a DML or DDL statement (not a read-only statement like a SELECT). In other words, in all cases except when an open read-transaction is upgraded to a write-transaction. In that case a non-blocking lock is used. ## Database Checkpointers Database checkpointers takes the following locks, in order: * The exclusive CHECKPOINTER lock. * The exclusive WRITER lock (FULL, RESTART and TRUNCATE only). * Exclusive lock on read-mark slots 1-N. These are immediately released after being taken. * Exclusive lock on read-mark 0. * Exclusive lock on read-mark slots 1-N again. These are immediately released after being taken (RESTART and TRUNCATE only). All of the above use blocking locks. ## Summary With blocking locks configured, the only cases in which clients should see an SQLITE\_BUSY error are: * if the OS does not grant a blocking lock before the configured timeout expires, and * when an open read-transaction is upgraded to a write-transaction. In all other cases the blocking locks implementation should prevent clients from having to handle SQLITE\_BUSY errors and facilitate appropriate transfer of priorities between competing clients. Clients that lock multiple databases simultaneously must be wary of deadlock. |
Changes to ext/async/sqlite3async.c.
︙ | ︙ | |||
1700 1701 1702 1703 1704 1705 1706 | break; } va_end(ap); return rc; } #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ASYNCIO) */ | < | 1700 1701 1702 1703 1704 1705 1706 | break; } va_end(ap); return rc; } #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ASYNCIO) */ |
Changes to ext/async/sqlite3async.h.
︙ | ︙ | |||
216 217 218 219 220 221 222 | #define SQLITEASYNC_HALT_NOW 1 /* Halt as soon as possible */ #define SQLITEASYNC_HALT_IDLE 2 /* Halt when write-queue is empty */ #ifdef __cplusplus } /* End of the 'extern "C"' block */ #endif #endif /* ifndef __SQLITEASYNC_H_ */ | < | 216 217 218 219 220 221 222 | #define SQLITEASYNC_HALT_NOW 1 /* Halt as soon as possible */ #define SQLITEASYNC_HALT_IDLE 2 /* Halt when write-queue is empty */ #ifdef __cplusplus } /* End of the 'extern "C"' block */ #endif #endif /* ifndef __SQLITEASYNC_H_ */ |
Changes to ext/expert/expert1.test.
︙ | ︙ | |||
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | source $testdir/tester.tcl set testprefix expert1 if {[info commands sqlite3_expert_new]==""} { finish_test return } set CLI [test_binary_name sqlite3] set CMD [test_binary_name sqlite3_expert] proc squish {txt} { regsub -all {[[:space:]]+} $txt { } } proc do_setup_rec_test {tn setup sql res} { reset_db db eval $setup uplevel [list do_rec_test $tn $sql $res] } foreach {tn setup} { 1 { if {![file executable $CMD]} { continue } | > > > > | 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 | source $testdir/tester.tcl set testprefix expert1 if {[info commands sqlite3_expert_new]==""} { finish_test return } set CLI [test_binary_name sqlite3] set CMD [test_binary_name sqlite3_expert] proc squish {txt} { regsub -all {[[:space:]]+} $txt { } } proc do_setup_rec_test {tn setup sql res} { reset_db if {[info exists ::set_main_db_name]} { dbconfig_maindbname_icecube db } db eval $setup uplevel [list do_rec_test $tn $sql $res] } foreach {tn setup} { 1 { if {![file executable $CMD]} { continue } |
︙ | ︙ | |||
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 | $expert destroy set tst [subst -nocommands {set {} [squish [join {$result}]]}] uplevel [list do_test $tn $tst [string trim [squish $res]]] } } 3 { if {![file executable $CLI]} { continue } proc do_rec_test {tn sql res} { set res [squish [string trim $res]] set tst [subst -nocommands { squish [string trim [exec $::CLI test.db ".expert" {$sql;}]] }] uplevel [list do_test $tn $tst $res] } } } { eval $setup do_setup_rec_test $tn.1 { CREATE TABLE t1(a, b, c) } { SELECT * FROM t1 } { (no new indexes) | > > > > | | | | | > | > | | | | | | | | | | | | > | > | | | | | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | < | 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 | $expert destroy set tst [subst -nocommands {set {} [squish [join {$result}]]}] uplevel [list do_test $tn $tst [string trim [squish $res]]] } } 3 { if {[info commands sqlite3_expert_new]==""} { continue } set ::set_main_db_name 1 } 4 { if {![file executable $CLI]} { continue } proc do_rec_test {tn sql res} { set res [squish [string trim $res]] set tst [subst -nocommands { squish [string trim [exec $::CLI test.db ".expert" {$sql;}]] }] uplevel [list do_test $tn $tst $res] } } } { eval $setup do_setup_rec_test $tn.1 { CREATE TABLE t1(a, b, c) } { SELECT * FROM t1 } { (no new indexes) SCAN t1 } do_setup_rec_test $tn.2 { CREATE TABLE t1(a, b, c); } { SELECT * FROM t1 WHERE b>?; } { CREATE INDEX t1_idx_00000062 ON t1(b); SEARCH t1 USING INDEX t1_idx_00000062 (b>?) } do_setup_rec_test $tn.3 { CREATE TABLE t1(a, b, c); } { SELECT * FROM t1 WHERE b COLLATE nocase BETWEEN ? AND ? } { CREATE INDEX t1_idx_3e094c27 ON t1(b COLLATE NOCASE); SEARCH t1 USING INDEX t1_idx_3e094c27 (b>? AND b<?) } do_setup_rec_test $tn.4 { CREATE TABLE t1(a, b, c); } { SELECT a FROM t1 ORDER BY b; } { CREATE INDEX t1_idx_00000062 ON t1(b); SCAN t1 USING INDEX t1_idx_00000062 } do_setup_rec_test $tn.5 { CREATE TABLE t1(a, b, c); } { SELECT a FROM t1 WHERE a=? ORDER BY b; } { CREATE INDEX t1_idx_000123a7 ON t1(a, b); SEARCH t1 USING COVERING INDEX t1_idx_000123a7 (a=?) } if 0 { do_setup_rec_test $tn.6 { CREATE TABLE t1(a, b, c); } { SELECT min(a) FROM t1 } { CREATE INDEX t1_idx_00000061 ON t1(a); SEARCH t1 USING COVERING INDEX t1_idx_00000061 } } do_setup_rec_test $tn.7 { CREATE TABLE t1(a, b, c); } { SELECT * FROM t1 ORDER BY a, b, c; } { CREATE INDEX t1_idx_033e95fe ON t1(a, b, c); SCAN t1 USING COVERING INDEX t1_idx_033e95fe } #do_setup_rec_test $tn.1.8 { # CREATE TABLE t1(a, b, c); #} { # SELECT * FROM t1 ORDER BY a ASC, b COLLATE nocase DESC, c ASC; #} { # CREATE INDEX t1_idx_5be6e222 ON t1(a, b COLLATE NOCASE DESC, c); # 0|0|0|SCAN t1 USING COVERING INDEX t1_idx_5be6e222 #} do_setup_rec_test $tn.8.1 { CREATE TABLE t1(a COLLATE NOCase, b, c); } { SELECT * FROM t1 WHERE a=? } { CREATE INDEX t1_idx_00000061 ON t1(a); SEARCH t1 USING INDEX t1_idx_00000061 (a=?) } do_setup_rec_test $tn.8.2 { CREATE TABLE t1(a, b COLLATE nocase, c); } { SELECT * FROM t1 ORDER BY a ASC, b DESC, c ASC; } { CREATE INDEX t1_idx_5cb97285 ON t1(a, b DESC, c); SCAN t1 USING COVERING INDEX t1_idx_5cb97285 } # Tables with names that require quotes. # do_setup_rec_test $tn.9.1 { CREATE TABLE "t t"(a, b, c); } { SELECT * FROM "t t" WHERE a=? } { CREATE INDEX "t t_idx_00000061" ON "t t"(a); SEARCH t t USING INDEX t t_idx_00000061 (a=?) } do_setup_rec_test $tn.9.2 { CREATE TABLE "t t"(a, b, c); } { SELECT * FROM "t t" WHERE b BETWEEN ? AND ? } { CREATE INDEX "t t_idx_00000062" ON "t t"(b); SEARCH t t USING INDEX t t_idx_00000062 (b>? AND b<?) } # Columns with names that require quotes. # do_setup_rec_test $tn.10.1 { CREATE TABLE t3(a, "b b", c); } { SELECT * FROM t3 WHERE "b b" = ? } { CREATE INDEX t3_idx_00050c52 ON t3('b b'); SEARCH t3 USING INDEX t3_idx_00050c52 (b b=?) } do_setup_rec_test $tn.10.2 { CREATE TABLE t3(a, "b b", c); } { SELECT * FROM t3 ORDER BY "b b" } { CREATE INDEX t3_idx_00050c52 ON t3('b b'); SCAN t3 USING INDEX t3_idx_00050c52 } # Transitive constraints # do_setup_rec_test $tn.11.1 { CREATE TABLE t5(a, b); CREATE TABLE t6(c, d); } { SELECT * FROM t5, t6 WHERE a=? AND b=c AND c=? } { CREATE INDEX t5_idx_000123a7 ON t5(a, b); CREATE INDEX t6_idx_00000063 ON t6(c); SEARCH t6 USING INDEX t6_idx_00000063 (c=?) SEARCH t5 USING COVERING INDEX t5_idx_000123a7 (a=? AND b=?) } # OR terms. # do_setup_rec_test $tn.12.1 { CREATE TABLE t7(a, b); } { SELECT * FROM t7 WHERE a=? OR b=? } { CREATE INDEX t7_idx_00000062 ON t7(b); CREATE INDEX t7_idx_00000061 ON t7(a); MULTI-INDEX OR INDEX 1 SEARCH t7 USING INDEX t7_idx_00000061 (a=?) INDEX 2 SEARCH t7 USING INDEX t7_idx_00000062 (b=?) } # rowid terms. # do_setup_rec_test $tn.13.1 { CREATE TABLE t8(a, b); } { SELECT * FROM t8 WHERE rowid=? } { (no new indexes) SEARCH t8 USING INTEGER PRIMARY KEY (rowid=?) } do_setup_rec_test $tn.13.2 { CREATE TABLE t8(a, b); } { SELECT * FROM t8 ORDER BY rowid } { (no new indexes) SCAN t8 } do_setup_rec_test $tn.13.3 { CREATE TABLE t8(a, b); } { SELECT * FROM t8 WHERE a=? ORDER BY rowid } { CREATE INDEX t8_idx_00000061 ON t8(a); SEARCH t8 USING INDEX t8_idx_00000061 (a=?) } # Triggers # do_setup_rec_test $tn.14 { CREATE TABLE t9(a, b, c); CREATE TABLE t10(a, b, c); CREATE TRIGGER t9t AFTER INSERT ON t9 BEGIN UPDATE t10 SET a=new.a WHERE b = new.b; END; } { INSERT INTO t9 VALUES(?, ?, ?); } { CREATE INDEX t10_idx_00000062 ON t10(b); SEARCH t10 USING INDEX t10_idx_00000062 (b=?) } do_setup_rec_test $tn.15 { CREATE TABLE t1(a, b); CREATE TABLE t2(c, d); WITH s(i) AS ( VALUES(1) UNION ALL SELECT i+1 FROM s WHERE i<100) INSERT INTO t1 SELECT (i-1)/50, (i-1)/20 FROM s; WITH s(i) AS ( VALUES(1) UNION ALL SELECT i+1 FROM s WHERE i<100) INSERT INTO t2 SELECT (i-1)/20, (i-1)/5 FROM s; } { SELECT * FROM t2, t1 WHERE b=? AND d=? AND t2.rowid=t1.rowid } { CREATE INDEX t2_idx_00000064 ON t2(d); SEARCH t2 USING INDEX t2_idx_00000064 (d=?) SEARCH t1 USING INTEGER PRIMARY KEY (rowid=?) } do_setup_rec_test $tn.16 { CREATE TABLE t1(a, b); } { SELECT * FROM t1 WHERE b IS NOT NULL; } { (no new indexes) SCAN t1 } do_setup_rec_test $tn.17.1 { CREATE TABLE example (A INTEGER, B INTEGER, C INTEGER, PRIMARY KEY (A,B)); } { SELECT * FROM example WHERE a=? } { (no new indexes) SEARCH example USING INDEX sqlite_autoindex_example_1 (A=?) } do_setup_rec_test $tn.17.2 { CREATE TABLE example (A INTEGER, B INTEGER, C INTEGER, PRIMARY KEY (A,B)); } { SELECT * FROM example WHERE b=? } { CREATE INDEX example_idx_00000042 ON example(B); SEARCH example USING INDEX example_idx_00000042 (B=?) } do_setup_rec_test $tn.17.3 { CREATE TABLE example (A INTEGER, B INTEGER, C INTEGER, PRIMARY KEY (A,B)); } { SELECT * FROM example WHERE a=? AND b=? } { (no new indexes) SEARCH example USING INDEX sqlite_autoindex_example_1 (A=? AND B=?) } do_setup_rec_test $tn.17.4 { CREATE TABLE example (A INTEGER, B INTEGER, C INTEGER, PRIMARY KEY (A,B)); } { SELECT * FROM example WHERE a=? AND b>? } { (no new indexes) SEARCH example USING INDEX sqlite_autoindex_example_1 (A=? AND B>?) } do_setup_rec_test $tn.17.5 { CREATE TABLE example (A INTEGER, B INTEGER, C INTEGER, PRIMARY KEY (A,B)); } { SELECT * FROM example WHERE a>? AND b=? } { CREATE INDEX example_idx_0000cb3f ON example(B, A); SEARCH example USING INDEX example_idx_0000cb3f (B=? AND A>?) } do_setup_rec_test $tn.18.0 { CREATE TABLE SomeObject ( a INTEGER PRIMARY KEY, x TEXT GENERATED ALWAYS AS(HEX(a)) VIRTUAL ); } { SELECT x FROM SomeObject; } { (no new indexes) SCAN SomeObject } do_setup_rec_test $tn.18.1 { CREATE TABLE SomeObject ( a INTEGER PRIMARY KEY, x TEXT GENERATED ALWAYS AS(HEX(a)) VIRTUAL ); } { SELECT * FROM SomeObject WHERE x=?; } { CREATE INDEX SomeObject_idx_00000078 ON SomeObject(x); SEARCH SomeObject USING COVERING INDEX SomeObject_idx_00000078 (x=?) } } proc do_candidates_test {tn sql res} { set res [squish [string trim $res]] set expert [sqlite3_expert_new db] $expert sql $sql $expert analyze set candidates [squish [string trim [$expert report 0 candidates]]] $expert destroy uplevel [list do_test $tn [list set {} $candidates] $res] } reset_db do_execsql_test 5.0 { CREATE TABLE t1(a, b); CREATE TABLE t2(c, d); WITH s(i) AS ( VALUES(1) UNION ALL SELECT i+1 FROM s WHERE i<100) INSERT INTO t1 SELECT (i-1)/50, (i-1)/20 FROM s; WITH s(i) AS ( VALUES(1) UNION ALL SELECT i+1 FROM s WHERE i<100) INSERT INTO t2 SELECT (i-1)/20, (i-1)/5 FROM s; } do_candidates_test 5.1 { SELECT * FROM t1,t2 WHERE (b=? OR a=?) AND (c=? OR d=?) } { CREATE INDEX t1_idx_00000062 ON t1(b); -- stat1: 100 20 CREATE INDEX t1_idx_00000061 ON t1(a); -- stat1: 100 50 CREATE INDEX t2_idx_00000063 ON t2(c); -- stat1: 100 20 CREATE INDEX t2_idx_00000064 ON t2(d); -- stat1: 100 5 } do_candidates_test 5.2 { SELECT * FROM t1,t2 WHERE a=? AND b=? AND c=? AND d=? } { CREATE INDEX t1_idx_000123a7 ON t1(a, b); -- stat1: 100 50 17 CREATE INDEX t2_idx_0001295b ON t2(c, d); -- stat1: 100 20 5 } do_execsql_test 5.3 { CREATE INDEX t1_idx_00000061 ON t1(a); -- stat1: 100 50 CREATE INDEX t1_idx_00000062 ON t1(b); -- stat1: 100 20 CREATE INDEX t1_idx_000123a7 ON t1(a, b); -- stat1: 100 50 16 CREATE INDEX t2_idx_00000063 ON t2(c); -- stat1: 100 20 CREATE INDEX t2_idx_00000064 ON t2(d); -- stat1: 100 5 CREATE INDEX t2_idx_0001295b ON t2(c, d); -- stat1: 100 20 5 ANALYZE; SELECT * FROM sqlite_stat1 ORDER BY 1, 2; } { t1 t1_idx_00000061 {100 50} t1 t1_idx_00000062 {100 20} t1 t1_idx_000123a7 {100 50 17} t2 t2_idx_00000063 {100 20} t2 t2_idx_00000064 {100 5} t2 t2_idx_0001295b {100 20 5} } finish_test |
Changes to ext/expert/sqlite3expert.c.
︙ | ︙ | |||
10 11 12 13 14 15 16 17 18 19 20 21 22 23 | ** ************************************************************************* */ #include "sqlite3expert.h" #include <assert.h> #include <string.h> #include <stdio.h> #ifndef SQLITE_OMIT_VIRTUALTABLE typedef sqlite3_int64 i64; typedef sqlite3_uint64 u64; typedef struct IdxColumn IdxColumn; | > > > > > > > > > > > > > > > > > | 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 | ** ************************************************************************* */ #include "sqlite3expert.h" #include <assert.h> #include <string.h> #include <stdio.h> #if !defined(SQLITE_AMALGAMATION) #if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_MUTATION_TEST) # define SQLITE_OMIT_AUXILIARY_SAFETY_CHECKS 1 #endif #if defined(SQLITE_OMIT_AUXILIARY_SAFETY_CHECKS) # define ALWAYS(X) (1) # define NEVER(X) (0) #elif !defined(NDEBUG) # define ALWAYS(X) ((X)?1:(assert(0),0)) # define NEVER(X) ((X)?(assert(0),1):0) #else # define ALWAYS(X) (X) # define NEVER(X) (X) #endif #endif /* !defined(SQLITE_AMALGAMATION) */ #ifndef SQLITE_OMIT_VIRTUALTABLE typedef sqlite3_int64 i64; typedef sqlite3_uint64 u64; typedef struct IdxColumn IdxColumn; |
︙ | ︙ | |||
681 682 683 684 685 686 687 688 | sqlite3_stmt *p1 = 0; int nCol = 0; int nTab = STRLEN(zTab); int nByte = sizeof(IdxTable) + nTab + 1; IdxTable *pNew = 0; int rc, rc2; char *pCsr = 0; | > | > | > | > > | | > | | | | | 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 | sqlite3_stmt *p1 = 0; int nCol = 0; int nTab = STRLEN(zTab); int nByte = sizeof(IdxTable) + nTab + 1; IdxTable *pNew = 0; int rc, rc2; char *pCsr = 0; int nPk = 0; rc = idxPrintfPrepareStmt(db, &p1, pzErrmsg, "PRAGMA table_xinfo=%Q", zTab); while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(p1) ){ const char *zCol = (const char*)sqlite3_column_text(p1, 1); const char *zColSeq = 0; nByte += 1 + STRLEN(zCol); rc = sqlite3_table_column_metadata( db, "main", zTab, zCol, 0, &zColSeq, 0, 0, 0 ); if( zColSeq==0 ) zColSeq = "binary"; nByte += 1 + STRLEN(zColSeq); nCol++; nPk += (sqlite3_column_int(p1, 5)>0); } rc2 = sqlite3_reset(p1); if( rc==SQLITE_OK ) rc = rc2; nByte += sizeof(IdxColumn) * nCol; if( rc==SQLITE_OK ){ pNew = idxMalloc(&rc, nByte); } if( rc==SQLITE_OK ){ pNew->aCol = (IdxColumn*)&pNew[1]; pNew->nCol = nCol; pCsr = (char*)&pNew->aCol[nCol]; } nCol = 0; while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(p1) ){ const char *zCol = (const char*)sqlite3_column_text(p1, 1); const char *zColSeq = 0; int nCopy = STRLEN(zCol) + 1; pNew->aCol[nCol].zName = pCsr; pNew->aCol[nCol].iPk = (sqlite3_column_int(p1, 5)==1 && nPk==1); memcpy(pCsr, zCol, nCopy); pCsr += nCopy; rc = sqlite3_table_column_metadata( db, "main", zTab, zCol, 0, &zColSeq, 0, 0, 0 ); if( rc==SQLITE_OK ){ if( zColSeq==0 ) zColSeq = "binary"; nCopy = STRLEN(zColSeq) + 1; pNew->aCol[nCol].zColl = pCsr; memcpy(pCsr, zColSeq, nCopy); pCsr += nCopy; } nCol++; } idxFinalize(&rc, p1); if( rc!=SQLITE_OK ){ sqlite3_free(pNew); pNew = 0; }else if( ALWAYS(pNew!=0) ){ pNew->zName = pCsr; if( ALWAYS(pNew->zName!=0) ) memcpy(pNew->zName, zTab, nTab+1); } *ppOut = pNew; return rc; } /* |
︙ | ︙ | |||
903 904 905 906 907 908 909 910 911 912 913 914 915 916 | } } idxFinalize(&rc, pIdxList); *pRc = rc; return 0; } static int idxCreateFromCons( sqlite3expert *p, IdxScan *pScan, IdxConstraint *pEq, IdxConstraint *pTail ){ | > > > > > > > > > > > > > | 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 | } } idxFinalize(&rc, pIdxList); *pRc = rc; return 0; } /* Callback for sqlite3_exec() with query with leading count(*) column. * The first argument is expected to be an int*, referent to be incremented * if that leading column is not exactly '0'. */ static int countNonzeros(void* pCount, int nc, char* azResults[], char* azColumns[]){ (void)azColumns; /* Suppress unused parameter warning */ if( nc>0 && (azResults[0][0]!='0' || azResults[0][1]!=0) ){ *((int *)pCount) += 1; } return 0; } static int idxCreateFromCons( sqlite3expert *p, IdxScan *pScan, IdxConstraint *pEq, IdxConstraint *pTail ){ |
︙ | ︙ | |||
930 931 932 933 934 935 936 | for(pCons=pTail; pCons; pCons=pCons->pLink){ zCols = idxAppendColDefn(&rc, zCols, pTab, pCons); } if( rc==SQLITE_OK ){ /* Hash the list of columns to come up with a name for the index */ const char *zTable = pScan->pTab->zName; | > | > > | > | | | > | | > > > > > > > > > > > > > > > > > > | | > > > | > | 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 | for(pCons=pTail; pCons; pCons=pCons->pLink){ zCols = idxAppendColDefn(&rc, zCols, pTab, pCons); } if( rc==SQLITE_OK ){ /* Hash the list of columns to come up with a name for the index */ const char *zTable = pScan->pTab->zName; int quoteTable = idxIdentifierRequiresQuotes(zTable); char *zName = 0; /* Index name */ int collisions = 0; do{ int i; char *zFind; for(i=0; zCols[i]; i++){ h += ((h<<3) + zCols[i]); } sqlite3_free(zName); zName = sqlite3_mprintf("%s_idx_%08x", zTable, h); if( zName==0 ) break; /* Is is unique among table, view and index names? */ zFmt = "SELECT count(*) FROM sqlite_schema WHERE name=%Q" " AND type in ('index','table','view')"; zFind = sqlite3_mprintf(zFmt, zName); i = 0; rc = sqlite3_exec(dbm, zFind, countNonzeros, &i, 0); assert(rc==SQLITE_OK); sqlite3_free(zFind); if( i==0 ){ collisions = 0; break; } ++collisions; }while( collisions<50 && zName!=0 ); if( collisions ){ /* This return means "Gave up trying to find a unique index name." */ rc = SQLITE_BUSY_TIMEOUT; }else if( zName==0 ){ rc = SQLITE_NOMEM; }else{ if( quoteTable ){ zFmt = "CREATE INDEX \"%w\" ON \"%w\"(%s)"; }else{ zFmt = "CREATE INDEX %s ON %s(%s)"; } zIdx = sqlite3_mprintf(zFmt, zName, zTable, zCols); if( !zIdx ){ rc = SQLITE_NOMEM; }else{ rc = sqlite3_exec(dbm, zIdx, 0, 0, p->pzErrmsg); if( rc!=SQLITE_OK ){ rc = SQLITE_BUSY_TIMEOUT; }else{ idxHashAdd(&rc, &p->hIdx, zName, zIdx); } } sqlite3_free(zName); sqlite3_free(zIdx); } } sqlite3_free(zCols); |
︙ | ︙ | |||
1124 1125 1126 1127 1128 1129 1130 | "EXPLAIN QUERY PLAN %s", pStmt->zSql ); while( rc==SQLITE_OK && sqlite3_step(pExplain)==SQLITE_ROW ){ /* int iId = sqlite3_column_int(pExplain, 0); */ /* int iParent = sqlite3_column_int(pExplain, 1); */ /* int iNotUsed = sqlite3_column_int(pExplain, 2); */ const char *zDetail = (const char*)sqlite3_column_text(pExplain, 3); | | > > > | > | > | 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 | "EXPLAIN QUERY PLAN %s", pStmt->zSql ); while( rc==SQLITE_OK && sqlite3_step(pExplain)==SQLITE_ROW ){ /* int iId = sqlite3_column_int(pExplain, 0); */ /* int iParent = sqlite3_column_int(pExplain, 1); */ /* int iNotUsed = sqlite3_column_int(pExplain, 2); */ const char *zDetail = (const char*)sqlite3_column_text(pExplain, 3); int nDetail; int i; if( !zDetail ) continue; nDetail = STRLEN(zDetail); for(i=0; i<nDetail; i++){ const char *zIdx = 0; if( i+13<nDetail && memcmp(&zDetail[i], " USING INDEX ", 13)==0 ){ zIdx = &zDetail[i+13]; }else if( i+22<nDetail && memcmp(&zDetail[i], " USING COVERING INDEX ", 22)==0 ){ zIdx = &zDetail[i+22]; } if( zIdx ){ const char *zSql; int nIdx = 0; while( zIdx[nIdx]!='\0' && (zIdx[nIdx]!=' ' || zIdx[nIdx+1]!='(') ){ nIdx++; |
︙ | ︙ | |||
1214 1215 1216 1217 1218 1219 1220 | char **pzErr ){ static const char *zInt = UNIQUE_TABLE_NAME; static const char *zDrop = "DROP TABLE " UNIQUE_TABLE_NAME; IdxTable *pTab = pWrite->pTab; const char *zTab = pTab->zName; const char *zSql = | | | 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 | char **pzErr ){ static const char *zInt = UNIQUE_TABLE_NAME; static const char *zDrop = "DROP TABLE " UNIQUE_TABLE_NAME; IdxTable *pTab = pWrite->pTab; const char *zTab = pTab->zName; const char *zSql = "SELECT 'CREATE TEMP' || substr(sql, 7) FROM sqlite_schema " "WHERE tbl_name = %Q AND type IN ('table', 'trigger') " "ORDER BY type;"; sqlite3_stmt *pSelect = 0; int rc = SQLITE_OK; char *zWrite = 0; /* Create the table and its triggers in the temp schema */ |
︙ | ︙ | |||
1314 1315 1316 1317 1318 1319 1320 | /* For each table in the main db schema: ** ** 1) Add an entry to the p->pTable list, and ** 2) Create the equivalent virtual table in dbv. */ rc = idxPrepareStmt(p->db, &pSchema, pzErrmsg, | | | | | 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 | /* For each table in the main db schema: ** ** 1) Add an entry to the p->pTable list, and ** 2) Create the equivalent virtual table in dbv. */ rc = idxPrepareStmt(p->db, &pSchema, pzErrmsg, "SELECT type, name, sql, 1 FROM sqlite_schema " "WHERE type IN ('table','view') AND name NOT LIKE 'sqlite_%%' " " UNION ALL " "SELECT type, name, sql, 2 FROM sqlite_schema " "WHERE type = 'trigger'" " AND tbl_name IN(SELECT name FROM sqlite_schema WHERE type = 'view') " "ORDER BY 4, 1" ); while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSchema) ){ const char *zType = (const char*)sqlite3_column_text(pSchema, 0); const char *zName = (const char*)sqlite3_column_text(pSchema, 1); const char *zSql = (const char*)sqlite3_column_text(pSchema, 2); |
︙ | ︙ | |||
1489 1490 1491 1492 1493 1494 1495 | } } static int idxLargestIndex(sqlite3 *db, int *pnMax, char **pzErr){ int rc = SQLITE_OK; const char *zMax = "SELECT max(i.seqno) FROM " | | | 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 | } } static int idxLargestIndex(sqlite3 *db, int *pnMax, char **pzErr){ int rc = SQLITE_OK; const char *zMax = "SELECT max(i.seqno) FROM " " sqlite_schema AS s, " " pragma_index_list(s.name) AS l, " " pragma_index_info(l.name) AS i " "WHERE s.type = 'table'"; sqlite3_stmt *pMax = 0; *pnMax = 0; rc = idxPrepareStmt(db, &pMax, pzErr, zMax); |
︙ | ︙ | |||
1642 1643 1644 1645 1646 1647 1648 | i64 iPrev = -100000; sqlite3_stmt *pAllIndex = 0; sqlite3_stmt *pIndexXInfo = 0; sqlite3_stmt *pWrite = 0; const char *zAllIndex = "SELECT s.rowid, s.name, l.name FROM " | | | 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 | i64 iPrev = -100000; sqlite3_stmt *pAllIndex = 0; sqlite3_stmt *pIndexXInfo = 0; sqlite3_stmt *pWrite = 0; const char *zAllIndex = "SELECT s.rowid, s.name, l.name FROM " " sqlite_schema AS s, " " pragma_index_list(s.name) AS l " "WHERE s.type = 'table'"; const char *zIndexXInfo = "SELECT name, coll FROM pragma_index_xinfo(?) WHERE key"; const char *zWrite = "INSERT INTO sqlite_stat1 VALUES(?, ?, ?)"; /* If iSample==0, no sqlite_stat1 data is required. */ |
︙ | ︙ | |||
1710 1711 1712 1713 1714 1715 1716 | ); } idxFinalize(&rc, pAllIndex); idxFinalize(&rc, pIndexXInfo); idxFinalize(&rc, pWrite); | > | | | | | > | | 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 | ); } idxFinalize(&rc, pAllIndex); idxFinalize(&rc, pIndexXInfo); idxFinalize(&rc, pWrite); if( pCtx ){ for(i=0; i<pCtx->nSlot; i++){ sqlite3_free(pCtx->aSlot[i].z); } sqlite3_free(pCtx); } if( rc==SQLITE_OK ){ rc = sqlite3_exec(p->dbm, "ANALYZE sqlite_schema", 0, 0, 0); } sqlite3_exec(p->db, "DROP TABLE IF EXISTS temp."UNIQUE_TABLE_NAME,0,0,0); return rc; } /* |
︙ | ︙ | |||
1755 1756 1757 1758 1759 1760 1761 | } /* Copy the entire schema of database [db] into [dbm]. */ if( rc==SQLITE_OK ){ sqlite3_stmt *pSql; rc = idxPrintfPrepareStmt(pNew->db, &pSql, pzErrmsg, | | | 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 | } /* Copy the entire schema of database [db] into [dbm]. */ if( rc==SQLITE_OK ){ sqlite3_stmt *pSql; rc = idxPrintfPrepareStmt(pNew->db, &pSql, pzErrmsg, "SELECT sql FROM sqlite_schema WHERE name NOT LIKE 'sqlite_%%'" " AND sql NOT LIKE 'CREATE VIRTUAL %%'" ); while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSql) ){ const char *zSql = (const char*)sqlite3_column_text(pSql, 0); rc = sqlite3_exec(pNew->dbm, zSql, 0, 0, pzErrmsg); } idxFinalize(&rc, pSql); |
︙ | ︙ | |||
1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 | /* Do trigger processing to collect any extra IdxScan structures */ rc = idxProcessTriggers(p, pzErr); /* Create candidate indexes within the in-memory database file */ if( rc==SQLITE_OK ){ rc = idxCreateCandidates(p); } /* Generate the stat1 data */ if( rc==SQLITE_OK ){ rc = idxPopulateStat1(p, pzErr); } | > > > > | 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 | /* Do trigger processing to collect any extra IdxScan structures */ rc = idxProcessTriggers(p, pzErr); /* Create candidate indexes within the in-memory database file */ if( rc==SQLITE_OK ){ rc = idxCreateCandidates(p); }else if ( rc==SQLITE_BUSY_TIMEOUT ){ if( pzErr ) *pzErr = sqlite3_mprintf("Cannot find a unique index name to propose."); return rc; } /* Generate the stat1 data */ if( rc==SQLITE_OK ){ rc = idxPopulateStat1(p, pzErr); } |
︙ | ︙ | |||
1946 1947 1948 1949 1950 1951 1952 | idxWriteFree(p->pWrite); idxHashClear(&p->hIdx); sqlite3_free(p->zCandidates); sqlite3_free(p); } } | | | 2020 2021 2022 2023 2024 2025 2026 2027 | idxWriteFree(p->pWrite); idxHashClear(&p->hIdx); sqlite3_free(p->zCandidates); sqlite3_free(p); } } #endif /* ifndef SQLITE_OMIT_VIRTUALTABLE */ |
Changes to ext/expert/sqlite3expert.h.
1 2 3 4 5 6 7 8 9 10 11 12 | /* ** 2017 April 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. ** ************************************************************************* */ | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | /* ** 2017 April 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. ** ************************************************************************* */ #if !defined(SQLITEEXPERT_H) #define SQLITEEXPERT_H 1 #include "sqlite3.h" typedef struct sqlite3expert sqlite3expert; /* ** Create a new sqlite3expert object. ** |
︙ | ︙ | |||
161 162 163 164 165 166 167 | /* ** Free an (sqlite3expert*) handle and all associated resources. There ** should be one call to this function for each successful call to ** sqlite3-expert_new(). */ void sqlite3_expert_destroy(sqlite3expert*); | | | 161 162 163 164 165 166 167 168 | /* ** Free an (sqlite3expert*) handle and all associated resources. There ** should be one call to this function for each successful call to ** sqlite3-expert_new(). */ void sqlite3_expert_destroy(sqlite3expert*); #endif /* !defined(SQLITEEXPERT_H) */ |
Changes to ext/fts3/README.content.
︙ | ︙ | |||
170 171 172 173 174 175 176 | INSERT INTO t3(t3) VALUES('rebuild'); This command may also be used with ordinary FTS4 tables, although it may only be useful if the full-text index has somehow become corrupt. It is an error to attempt to rebuild the full-text index maintained by a contentless FTS4 table. | < < | 170 171 172 173 174 175 176 | INSERT INTO t3(t3) VALUES('rebuild'); This command may also be used with ordinary FTS4 tables, although it may only be useful if the full-text index has somehow become corrupt. It is an error to attempt to rebuild the full-text index maintained by a contentless FTS4 table. |
Changes to ext/fts3/README.tokenizers.
︙ | ︙ | |||
48 49 50 51 52 53 54 | returned. If only one argument is passed, a pointer to the tokenizer implementation currently registered as <tokenizer-name> is returned, encoded as a blob. Or, if no such tokenizer exists, an SQL exception (error) is raised. SECURITY: If the fts3 extension is used in an environment where potentially malicious users may execute arbitrary SQL (i.e. gears), they should be | | | > > | 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | returned. If only one argument is passed, a pointer to the tokenizer implementation currently registered as <tokenizer-name> is returned, encoded as a blob. Or, if no such tokenizer exists, an SQL exception (error) is raised. SECURITY: If the fts3 extension is used in an environment where potentially malicious users may execute arbitrary SQL (i.e. gears), they should be prevented from invoking the fts3_tokenizer() function. The fts3_tokenizer() function is disabled by default. It is only enabled by SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER. Do not enable it in security sensitive environments. See "Sample code" below for an example of calling the fts3_tokenizer() function from C code. 3. ICU Library Tokenizers If this extension is compiled with the SQLITE_ENABLE_ICU pre-processor |
︙ | ︙ |
Changes to ext/fts3/fts3.c.
︙ | ︙ | |||
309 310 311 312 313 314 315 | #endif static int fts3EvalNext(Fts3Cursor *pCsr); static int fts3EvalStart(Fts3Cursor *pCsr); static int fts3TermSegReaderCursor( Fts3Cursor *, const char *, int, int, Fts3MultiSegReader **); | < > > > > > > | | < < | < < < < < | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | | | | 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 | #endif static int fts3EvalNext(Fts3Cursor *pCsr); static int fts3EvalStart(Fts3Cursor *pCsr); static int fts3TermSegReaderCursor( Fts3Cursor *, const char *, int, int, Fts3MultiSegReader **); /* ** This variable is set to false when running tests for which the on disk ** structures should not be corrupt. Otherwise, true. If it is false, extra ** assert() conditions in the fts3 code are activated - conditions that are ** only true if it is guaranteed that the fts3 database is not corrupt. */ #ifdef SQLITE_DEBUG int sqlite3_fts3_may_be_corrupt = 1; #endif /* ** Write a 64-bit variable-length integer to memory starting at p[0]. ** The length of data written will be between 1 and FTS3_VARINT_MAX bytes. ** The number of bytes written is returned. */ int sqlite3Fts3PutVarint(char *p, sqlite_int64 v){ unsigned char *q = (unsigned char *) p; sqlite_uint64 vu = v; do{ *q++ = (unsigned char) ((vu & 0x7f) | 0x80); vu >>= 7; }while( vu!=0 ); q[-1] &= 0x7f; /* turn off high bit in final byte */ assert( q - (unsigned char *)p <= FTS3_VARINT_MAX ); return (int) (q - (unsigned char *)p); } #define GETVARINT_STEP(v, ptr, shift, mask1, mask2, var, ret) \ v = (v & mask1) | ( (*(const unsigned char*)(ptr++)) << shift ); \ if( (v & mask2)==0 ){ var = v; return ret; } #define GETVARINT_INIT(v, ptr, shift, mask1, mask2, var, ret) \ v = (*ptr++); \ if( (v & mask2)==0 ){ var = v; return ret; } int sqlite3Fts3GetVarintU(const char *pBuf, sqlite_uint64 *v){ const unsigned char *p = (const unsigned char*)pBuf; const unsigned char *pStart = p; u32 a; u64 b; int shift; GETVARINT_INIT(a, p, 0, 0x00, 0x80, *v, 1); GETVARINT_STEP(a, p, 7, 0x7F, 0x4000, *v, 2); GETVARINT_STEP(a, p, 14, 0x3FFF, 0x200000, *v, 3); GETVARINT_STEP(a, p, 21, 0x1FFFFF, 0x10000000, *v, 4); b = (a & 0x0FFFFFFF ); for(shift=28; shift<=63; shift+=7){ u64 c = *p++; b += (c&0x7F) << shift; if( (c & 0x80)==0 ) break; } *v = b; return (int)(p - pStart); } /* ** Read a 64-bit variable-length integer from memory starting at p[0]. ** Return the number of bytes read, or 0 on error. ** The value is stored in *v. */ int sqlite3Fts3GetVarint(const char *pBuf, sqlite_int64 *v){ return sqlite3Fts3GetVarintU(pBuf, (sqlite3_uint64*)v); } /* ** Read a 64-bit variable-length integer from memory starting at p[0] and ** not extending past pEnd[-1]. ** Return the number of bytes read, or 0 on error. ** The value is stored in *v. */ int sqlite3Fts3GetVarintBounded( const char *pBuf, const char *pEnd, sqlite_int64 *v ){ const unsigned char *p = (const unsigned char*)pBuf; const unsigned char *pStart = p; const unsigned char *pX = (const unsigned char*)pEnd; u64 b = 0; int shift; for(shift=0; shift<=63; shift+=7){ u64 c = p<pX ? *p : 0; p++; b += (c&0x7F) << shift; if( (c & 0x80)==0 ) break; } *v = b; return (int)(p - pStart); } /* ** Similar to sqlite3Fts3GetVarint(), except that the output is truncated to ** a non-negative 32-bit integer before it is returned. */ int sqlite3Fts3GetVarint32(const char *p, int *pi){ const unsigned char *ptr = (const unsigned char*)p; u32 a; #ifndef fts3GetVarint32 GETVARINT_INIT(a, ptr, 0, 0x00, 0x80, *pi, 1); #else a = (*ptr++); assert( a & 0x80 ); #endif GETVARINT_STEP(a, ptr, 7, 0x7F, 0x4000, *pi, 2); GETVARINT_STEP(a, ptr, 14, 0x3FFF, 0x200000, *pi, 3); GETVARINT_STEP(a, ptr, 21, 0x1FFFFF, 0x10000000, *pi, 4); a = (a & 0x0FFFFFFF ); *pi = (int)(a | ((u32)(*ptr & 0x07) << 28)); assert( 0==(a & 0x80000000) ); assert( *pi>=0 ); return 5; } /* ** Return the number of bytes required to encode v as a varint |
︙ | ︙ | |||
556 557 558 559 560 561 562 | static int fts3DestroyMethod(sqlite3_vtab *pVtab){ Fts3Table *p = (Fts3Table *)pVtab; int rc = SQLITE_OK; /* Return code */ const char *zDb = p->zDb; /* Name of database (e.g. "main", "temp") */ sqlite3 *db = p->db; /* Database handle */ /* Drop the shadow tables */ | < | < | | | | > > > > > > > | 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 | static int fts3DestroyMethod(sqlite3_vtab *pVtab){ Fts3Table *p = (Fts3Table *)pVtab; int rc = SQLITE_OK; /* Return code */ const char *zDb = p->zDb; /* Name of database (e.g. "main", "temp") */ sqlite3 *db = p->db; /* Database handle */ /* Drop the shadow tables */ fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_segments';" "DROP TABLE IF EXISTS %Q.'%q_segdir';" "DROP TABLE IF EXISTS %Q.'%q_docsize';" "DROP TABLE IF EXISTS %Q.'%q_stat';" "%s DROP TABLE IF EXISTS %Q.'%q_content';", zDb, p->zName, zDb, p->zName, zDb, p->zName, zDb, p->zName, (p->zContentTbl ? "--" : ""), zDb,p->zName ); /* If everything has worked, invoke fts3DisconnectMethod() to free the ** memory associated with the Fts3Table structure and return SQLITE_OK. ** Otherwise, return an SQLite error code. */ return (rc==SQLITE_OK ? fts3DisconnectMethod(pVtab) : rc); } |
︙ | ︙ | |||
794 795 796 797 798 799 800 | ** fts3QuoteId("un \"zip\"") -> "un \"\"zip\"\"" ** ** The pointer returned points to memory obtained from sqlite3_malloc(). It ** is the callers responsibility to call sqlite3_free() to release this ** memory. */ static char *fts3QuoteId(char const *zInput){ | | | | 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 | ** fts3QuoteId("un \"zip\"") -> "un \"\"zip\"\"" ** ** The pointer returned points to memory obtained from sqlite3_malloc(). It ** is the callers responsibility to call sqlite3_free() to release this ** memory. */ static char *fts3QuoteId(char const *zInput){ sqlite3_int64 nRet; char *zRet; nRet = 2 + (int)strlen(zInput)*2 + 1; zRet = sqlite3_malloc64(nRet); if( zRet ){ int i; char *z = zRet; *(z++) = '"'; for(i=0; zInput[i]; i++){ if( zInput[i]=='"' ) *(z++) = '"'; *(z++) = zInput[i]; |
︙ | ︙ | |||
913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 | } if( p->zLanguageid ){ fts3Appendf(pRc, &zRet, ", ?"); } sqlite3_free(zFree); return zRet; } /* ** This function interprets the string at (*pp) as a non-negative integer ** value. It reads the integer and sets *pnOut to the value read, then ** sets *pp to point to the byte immediately following the last byte of ** the integer value. ** ** Only decimal digits ('0'..'9') may be part of an integer value. ** ** If *pp does not being with a decimal digit SQLITE_ERROR is returned and ** the output value undefined. Otherwise SQLITE_OK is returned. ** ** This function is used when parsing the "prefix=" FTS4 parameter. */ static int fts3GobbleInt(const char **pp, int *pnOut){ const int MAX_NPREFIX = 10000000; | > > > > > > > > > > > > > > > > < | < | | | < | > > < | | 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 | } if( p->zLanguageid ){ fts3Appendf(pRc, &zRet, ", ?"); } sqlite3_free(zFree); return zRet; } /* ** Buffer z contains a positive integer value encoded as utf-8 text. ** Decode this value and store it in *pnOut, returning the number of bytes ** consumed. If an overflow error occurs return a negative value. */ int sqlite3Fts3ReadInt(const char *z, int *pnOut){ u64 iVal = 0; int i; for(i=0; z[i]>='0' && z[i]<='9'; i++){ iVal = iVal*10 + (z[i] - '0'); if( iVal>0x7FFFFFFF ) return -1; } *pnOut = (int)iVal; return i; } /* ** This function interprets the string at (*pp) as a non-negative integer ** value. It reads the integer and sets *pnOut to the value read, then ** sets *pp to point to the byte immediately following the last byte of ** the integer value. ** ** Only decimal digits ('0'..'9') may be part of an integer value. ** ** If *pp does not being with a decimal digit SQLITE_ERROR is returned and ** the output value undefined. Otherwise SQLITE_OK is returned. ** ** This function is used when parsing the "prefix=" FTS4 parameter. */ static int fts3GobbleInt(const char **pp, int *pnOut){ const int MAX_NPREFIX = 10000000; int nInt = 0; /* Output value */ int nByte; nByte = sqlite3Fts3ReadInt(*pp, &nInt); if( nInt>MAX_NPREFIX ){ nInt = 0; } if( nByte==0 ){ return SQLITE_ERROR; } *pnOut = nInt; *pp += nByte; return SQLITE_OK; } /* ** This function is called to allocate an array of Fts3Index structures ** representing the indexes maintained by the current FTS table. FTS tables ** always maintain the main "terms" index, but may also maintain one or |
︙ | ︙ | |||
978 979 980 981 982 983 984 | const char *p; nIndex++; for(p=zParam; *p; p++){ if( *p==',' ) nIndex++; } } | | | 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 | const char *p; nIndex++; for(p=zParam; *p; p++){ if( *p==',' ) nIndex++; } } aIndex = sqlite3_malloc64(sizeof(struct Fts3Index) * nIndex); *apIndex = aIndex; if( !aIndex ){ return SQLITE_NOMEM; } memset(aIndex, 0, sizeof(struct Fts3Index) * nIndex); if( zParam ){ |
︙ | ︙ | |||
1057 1058 1059 1060 1061 1062 1063 | sqlite3Fts3ErrMsg(pzErr, "%s", sqlite3_errmsg(db)); } } sqlite3_free(zSql); if( rc==SQLITE_OK ){ const char **azCol; /* Output array */ | | | | | 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 | sqlite3Fts3ErrMsg(pzErr, "%s", sqlite3_errmsg(db)); } } sqlite3_free(zSql); if( rc==SQLITE_OK ){ const char **azCol; /* Output array */ sqlite3_int64 nStr = 0; /* Size of all column names (incl. 0x00) */ int nCol; /* Number of table columns */ int i; /* Used to iterate through columns */ /* Loop through the returned columns. Set nStr to the number of bytes of ** space required to store a copy of each column name, including the ** nul-terminator byte. */ nCol = sqlite3_column_count(pStmt); for(i=0; i<nCol; i++){ const char *zCol = sqlite3_column_name(pStmt, i); nStr += strlen(zCol) + 1; } /* Allocate and populate the array to return. */ azCol = (const char **)sqlite3_malloc64(sizeof(char *) * nCol + nStr); if( azCol==0 ){ rc = SQLITE_NOMEM; }else{ char *p = (char *)&azCol[nCol]; for(i=0; i<nCol; i++){ const char *zCol = sqlite3_column_name(pStmt, i); int n = (int)strlen(zCol)+1; |
︙ | ︙ | |||
1119 1120 1121 1122 1123 1124 1125 | sqlite3_vtab **ppVTab, /* Write the resulting vtab structure here */ char **pzErr /* Write any error message here */ ){ Fts3Hash *pHash = (Fts3Hash *)pAux; Fts3Table *p = 0; /* Pointer to allocated vtab */ int rc = SQLITE_OK; /* Return code */ int i; /* Iterator variable */ | | | 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 | sqlite3_vtab **ppVTab, /* Write the resulting vtab structure here */ char **pzErr /* Write any error message here */ ){ Fts3Hash *pHash = (Fts3Hash *)pAux; Fts3Table *p = 0; /* Pointer to allocated vtab */ int rc = SQLITE_OK; /* Return code */ int i; /* Iterator variable */ sqlite3_int64 nByte; /* Size of allocation used for *p */ int iCol; /* Column index */ int nString = 0; /* Bytes required to hold all column names */ int nCol = 0; /* Number of columns in the FTS table */ char *zCsr; /* Space for holding column names */ int nDb; /* Bytes required to hold database name */ int nName; /* Bytes required to hold table name */ int isFts4 = (argv[0][3]=='4'); /* True for FTS4, false for FTS3 */ |
︙ | ︙ | |||
1153 1154 1155 1156 1157 1158 1159 | || (sqlite3_strnicmp(argv[0], "fts3", 4)==0 && !isFts4) ); nDb = (int)strlen(argv[1]) + 1; nName = (int)strlen(argv[2]) + 1; nByte = sizeof(const char *) * (argc-2); | | | | 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 | || (sqlite3_strnicmp(argv[0], "fts3", 4)==0 && !isFts4) ); nDb = (int)strlen(argv[1]) + 1; nName = (int)strlen(argv[2]) + 1; nByte = sizeof(const char *) * (argc-2); aCol = (const char **)sqlite3_malloc64(nByte); if( aCol ){ memset((void*)aCol, 0, nByte); azNotindexed = (char **)sqlite3_malloc64(nByte); } if( azNotindexed ){ memset(azNotindexed, 0, nByte); } if( !aCol || !azNotindexed ){ rc = SQLITE_NOMEM; goto fts3_init_out; |
︙ | ︙ | |||
1351 1352 1353 1354 1355 1356 1357 | nByte = sizeof(Fts3Table) + /* Fts3Table */ nCol * sizeof(char *) + /* azColumn */ nIndex * sizeof(struct Fts3Index) + /* aIndex */ nCol * sizeof(u8) + /* abNotindexed */ nName + /* zName */ nDb + /* zDb */ nString; /* Space for azColumn strings */ | | | 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 | nByte = sizeof(Fts3Table) + /* Fts3Table */ nCol * sizeof(char *) + /* azColumn */ nIndex * sizeof(struct Fts3Index) + /* aIndex */ nCol * sizeof(u8) + /* abNotindexed */ nName + /* zName */ nDb + /* zDb */ nString; /* Space for azColumn strings */ p = (Fts3Table*)sqlite3_malloc64(nByte); if( p==0 ){ rc = SQLITE_NOMEM; goto fts3_init_out; } memset(p, 0, nByte); p->db = db; p->nColumn = nCol; |
︙ | ︙ | |||
1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 | p->bHasStat = 2; } /* Figure out the page-size for the database. This is required in order to ** estimate the cost of loading large doclists from the database. */ fts3DatabasePageSize(&rc, p); p->nNodeSize = p->nPgsz-35; /* Declare the table schema to SQLite. */ fts3DeclareVtab(&rc, p); fts3_init_out: sqlite3_free(zPrefix); sqlite3_free(aIndex); | > > > > | 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 | p->bHasStat = 2; } /* Figure out the page-size for the database. This is required in order to ** estimate the cost of loading large doclists from the database. */ fts3DatabasePageSize(&rc, p); p->nNodeSize = p->nPgsz-35; #if defined(SQLITE_DEBUG)||defined(SQLITE_TEST) p->nMergeCount = FTS3_MERGE_COUNT; #endif /* Declare the table schema to SQLite. */ fts3DeclareVtab(&rc, p); fts3_init_out: sqlite3_free(zPrefix); sqlite3_free(aIndex); |
︙ | ︙ | |||
1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 | int i; /* Iterator variable */ int iCons = -1; /* Index of constraint to use */ int iLangidCons = -1; /* Index of langid=x constraint, if present */ int iDocidGe = -1; /* Index of docid>=x constraint, if present */ int iDocidLe = -1; /* Index of docid<=x constraint, if present */ int iIdx; /* By default use a full table scan. This is an expensive option, ** so search through the constraints to see if a more efficient ** strategy is possible. */ pInfo->idxNum = FTS3_FULLSCAN_SEARCH; pInfo->estimatedCost = 5000000; | > > > > | 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 | int i; /* Iterator variable */ int iCons = -1; /* Index of constraint to use */ int iLangidCons = -1; /* Index of langid=x constraint, if present */ int iDocidGe = -1; /* Index of docid>=x constraint, if present */ int iDocidLe = -1; /* Index of docid<=x constraint, if present */ int iIdx; if( p->bLock ){ return SQLITE_ERROR; } /* By default use a full table scan. This is an expensive option, ** so search through the constraints to see if a more efficient ** strategy is possible. */ pInfo->idxNum = FTS3_FULLSCAN_SEARCH; pInfo->estimatedCost = 5000000; |
︙ | ︙ | |||
1749 1750 1751 1752 1753 1754 1755 | char *zSql; if( p->pSeekStmt ){ pCsr->pStmt = p->pSeekStmt; p->pSeekStmt = 0; }else{ zSql = sqlite3_mprintf("SELECT %s WHERE rowid = ?", p->zReadExprlist); if( !zSql ) return SQLITE_NOMEM; | > > | > > > > > > | 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 | char *zSql; if( p->pSeekStmt ){ pCsr->pStmt = p->pSeekStmt; p->pSeekStmt = 0; }else{ zSql = sqlite3_mprintf("SELECT %s WHERE rowid = ?", p->zReadExprlist); if( !zSql ) return SQLITE_NOMEM; p->bLock++; rc = sqlite3_prepare_v3( p->db, zSql,-1,SQLITE_PREPARE_PERSISTENT,&pCsr->pStmt,0 ); p->bLock--; sqlite3_free(zSql); } if( rc==SQLITE_OK ) pCsr->bSeekStmt = 1; } return rc; } /* ** Position the pCsr->pStmt statement so that it is on the row ** of the %_content table that contains the last match. Return ** SQLITE_OK on success. */ static int fts3CursorSeek(sqlite3_context *pContext, Fts3Cursor *pCsr){ int rc = SQLITE_OK; if( pCsr->isRequireSeek ){ rc = fts3CursorSeekStmt(pCsr); if( rc==SQLITE_OK ){ Fts3Table *pTab = (Fts3Table*)pCsr->base.pVtab; pTab->bLock++; sqlite3_bind_int64(pCsr->pStmt, 1, pCsr->iPrevId); pCsr->isRequireSeek = 0; if( SQLITE_ROW==sqlite3_step(pCsr->pStmt) ){ pTab->bLock--; return SQLITE_OK; }else{ pTab->bLock--; 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; |
︙ | ︙ | |||
1819 1820 1821 1822 1823 1824 1825 | ){ int rc = SQLITE_OK; /* Return code */ const char *zCsr = zNode; /* Cursor to iterate through node */ const char *zEnd = &zCsr[nNode];/* End of interior node buffer */ char *zBuffer = 0; /* Buffer to load terms into */ i64 nAlloc = 0; /* Size of allocated buffer */ int isFirstTerm = 1; /* True when processing first term on page */ | | > | | < > > > > | | 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 | ){ int rc = SQLITE_OK; /* Return code */ const char *zCsr = zNode; /* Cursor to iterate through node */ const char *zEnd = &zCsr[nNode];/* End of interior node buffer */ char *zBuffer = 0; /* Buffer to load terms into */ i64 nAlloc = 0; /* Size of allocated buffer */ int isFirstTerm = 1; /* True when processing first term on page */ u64 iChild; /* Block id of child node to descend to */ int nBuffer = 0; /* Total term size */ /* Skip over the 'height' varint that occurs at the start of every ** interior node. Then load the blockid of the left-child of the b-tree ** node into variable iChild. ** ** Even if the data structure on disk is corrupted, this (reading two ** varints from the buffer) does not risk an overread. If zNode is a ** root node, then the buffer comes from a SELECT statement. SQLite does ** not make this guarantee explicitly, but in practice there are always ** either more than 20 bytes of allocated space following the nNode bytes of ** contents, or two zero bytes. Or, if the node is read from the %_segments ** table, then there are always 20 bytes of zeroed padding following the ** nNode bytes of content (see sqlite3Fts3ReadBlock() for details). */ zCsr += sqlite3Fts3GetVarintU(zCsr, &iChild); zCsr += sqlite3Fts3GetVarintU(zCsr, &iChild); if( zCsr>zEnd ){ return FTS_CORRUPT_VTAB; } while( zCsr<zEnd && (piFirst || piLast) ){ int cmp; /* memcmp() result */ int nSuffix; /* Size of term suffix */ int nPrefix = 0; /* Size of term prefix */ /* Load the next term on the node into zBuffer. Use realloc() to expand ** the size of zBuffer if required. */ if( !isFirstTerm ){ zCsr += fts3GetVarint32(zCsr, &nPrefix); if( nPrefix>nBuffer ){ rc = FTS_CORRUPT_VTAB; goto finish_scan; } } isFirstTerm = 0; zCsr += fts3GetVarint32(zCsr, &nSuffix); assert( nPrefix>=0 && nSuffix>=0 ); if( nPrefix>zCsr-zNode || nSuffix>zEnd-zCsr || nSuffix==0 ){ rc = FTS_CORRUPT_VTAB; goto finish_scan; } if( (i64)nPrefix+nSuffix>nAlloc ){ char *zNew; nAlloc = ((i64)nPrefix+nSuffix) * 2; zNew = (char *)sqlite3_realloc64(zBuffer, nAlloc); |
︙ | ︙ | |||
1885 1886 1887 1888 1889 1890 1891 | ** iChild. ** ** If the interior node term is larger than the specified term, then ** the tree headed by iChild may contain the specified term. */ cmp = memcmp(zTerm, zBuffer, (nBuffer>nTerm ? nTerm : nBuffer)); if( piFirst && (cmp<0 || (cmp==0 && nBuffer>nTerm)) ){ | | | | | | 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 | ** iChild. ** ** If the interior node term is larger than the specified term, then ** the tree headed by iChild may contain the specified term. */ cmp = memcmp(zTerm, zBuffer, (nBuffer>nTerm ? nTerm : nBuffer)); if( piFirst && (cmp<0 || (cmp==0 && nBuffer>nTerm)) ){ *piFirst = (i64)iChild; piFirst = 0; } if( piLast && cmp<0 ){ *piLast = (i64)iChild; piLast = 0; } iChild++; }; if( piFirst ) *piFirst = (i64)iChild; if( piLast ) *piLast = (i64)iChild; finish_scan: sqlite3_free(zBuffer); return rc; } |
︙ | ︙ | |||
1943 1944 1945 1946 1947 1948 1949 | int rc = SQLITE_OK; /* Return code */ int iHeight; /* Height of this node in tree */ assert( piLeaf || piLeaf2 ); fts3GetVarint32(zNode, &iHeight); rc = fts3ScanInteriorNode(zTerm, nTerm, zNode, nNode, piLeaf, piLeaf2); | | > > > > > | > | | 2016 2017 2018 2019 2020 2021 2022 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 | int rc = SQLITE_OK; /* Return code */ int iHeight; /* Height of this node in tree */ assert( piLeaf || piLeaf2 ); fts3GetVarint32(zNode, &iHeight); rc = fts3ScanInteriorNode(zTerm, nTerm, zNode, nNode, piLeaf, piLeaf2); assert_fts3_nc( !piLeaf2 || !piLeaf || rc!=SQLITE_OK || (*piLeaf<=*piLeaf2) ); if( rc==SQLITE_OK && iHeight>1 ){ char *zBlob = 0; /* Blob read from %_segments table */ int nBlob = 0; /* Size of zBlob in bytes */ if( piLeaf && piLeaf2 && (*piLeaf!=*piLeaf2) ){ rc = sqlite3Fts3ReadBlock(p, *piLeaf, &zBlob, &nBlob, 0); if( rc==SQLITE_OK ){ rc = fts3SelectLeaf(p, zTerm, nTerm, zBlob, nBlob, piLeaf, 0); } sqlite3_free(zBlob); piLeaf = 0; zBlob = 0; } if( rc==SQLITE_OK ){ rc = sqlite3Fts3ReadBlock(p, piLeaf?*piLeaf:*piLeaf2, &zBlob, &nBlob, 0); } if( rc==SQLITE_OK ){ int iNewHeight = 0; fts3GetVarint32(zBlob, &iNewHeight); if( iNewHeight>=iHeight ){ rc = FTS_CORRUPT_VTAB; }else{ rc = fts3SelectLeaf(p, zTerm, nTerm, zBlob, nBlob, piLeaf, piLeaf2); } } sqlite3_free(zBlob); } return rc; } /* ** This function is used to create delta-encoded serialized lists of FTS3 ** varints. Each call to this function appends a single varint to a list. */ static void fts3PutDeltaVarint( char **pp, /* IN/OUT: Output pointer */ sqlite3_int64 *piPrev, /* IN/OUT: Previous value written to list */ sqlite3_int64 iVal /* Write this value to the list */ ){ assert_fts3_nc( iVal-*piPrev > 0 || (*piPrev==0 && iVal==0) ); *pp += sqlite3Fts3PutVarint(*pp, iVal-*piPrev); *piPrev = iVal; } /* ** When this function is called, *ppPoslist is assumed to point to the ** start of a position-list. After it returns, *ppPoslist points to the |
︙ | ︙ | |||
2068 2069 2070 2071 2072 2073 2074 | p += n; *pp = p; } *ppPoslist = pEnd; } /* | | | > | | 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 | p += n; *pp = p; } *ppPoslist = pEnd; } /* ** Value used to signify the end of an position-list. This must be ** as large or larger than any value that might appear on the ** position-list, even a position list that has been corrupted. */ #define POSITION_LIST_END LARGEST_INT64 /* ** This function is used to help parse position-lists. When this function is ** called, *pp may point to the start of the next varint in the position-list ** being parsed, or it may point to 1 byte past the end of the position-list ** (in which case **pp will be a terminator bytes POS_END (0) or ** (1)). |
︙ | ︙ | |||
2096 2097 2098 2099 2100 2101 2102 | ** the next position. */ static void fts3ReadNextPos( char **pp, /* IN/OUT: Pointer into position-list buffer */ sqlite3_int64 *pi /* IN/OUT: Value read from position-list */ ){ if( (**pp)&0xFE ){ | > | > | 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 | ** the next position. */ static void fts3ReadNextPos( char **pp, /* IN/OUT: Pointer into position-list buffer */ sqlite3_int64 *pi /* IN/OUT: Value read from position-list */ ){ if( (**pp)&0xFE ){ int iVal; *pp += fts3GetVarint32((*pp), &iVal); *pi += iVal; *pi -= 2; }else{ *pi = POSITION_LIST_END; } } /* |
︙ | ︙ | |||
2130 2131 2132 2133 2134 2135 2136 | /* ** Compute the union of two position lists. The output written ** into *pp contains all positions of both *pp1 and *pp2 in sorted ** order and with any duplicates removed. All pointers are ** updated appropriately. The caller is responsible for insuring ** that there is enough space in *pp to hold the complete output. */ | | | > > > | | > > > | | 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 | /* ** Compute the union of two position lists. The output written ** into *pp contains all positions of both *pp1 and *pp2 in sorted ** order and with any duplicates removed. All pointers are ** updated appropriately. The caller is responsible for insuring ** that there is enough space in *pp to hold the complete output. */ static int fts3PoslistMerge( char **pp, /* Output buffer */ char **pp1, /* Left input list */ char **pp2 /* Right input list */ ){ char *p = *pp; char *p1 = *pp1; char *p2 = *pp2; while( *p1 || *p2 ){ int iCol1; /* The current column index in pp1 */ int iCol2; /* The current column index in pp2 */ if( *p1==POS_COLUMN ){ fts3GetVarint32(&p1[1], &iCol1); if( iCol1==0 ) return FTS_CORRUPT_VTAB; } else if( *p1==POS_END ) iCol1 = 0x7fffffff; else iCol1 = 0; if( *p2==POS_COLUMN ){ fts3GetVarint32(&p2[1], &iCol2); if( iCol2==0 ) return FTS_CORRUPT_VTAB; } else if( *p2==POS_END ) iCol2 = 0x7fffffff; else iCol2 = 0; if( iCol1==iCol2 ){ sqlite3_int64 i1 = 0; /* Last position from pp1 */ sqlite3_int64 i2 = 0; /* Last position from pp2 */ sqlite3_int64 iPrev = 0; int n = fts3PutColNumber(&p, iCol1); |
︙ | ︙ | |||
2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 | ** POS_END (0) or POS_COLUMN (1). The following block merges the two lists ** and writes the results to buffer p. p is left pointing to the byte ** after the list written. No terminator (POS_END or POS_COLUMN) is ** written to the output. */ fts3GetDeltaVarint(&p1, &i1); fts3GetDeltaVarint(&p2, &i2); do { fts3PutDeltaVarint(&p, &iPrev, (i1<i2) ? i1 : i2); iPrev -= 2; if( i1==i2 ){ fts3ReadNextPos(&p1, &i1); fts3ReadNextPos(&p2, &i2); }else if( i1<i2 ){ | > > > | 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 | ** POS_END (0) or POS_COLUMN (1). The following block merges the two lists ** and writes the results to buffer p. p is left pointing to the byte ** after the list written. No terminator (POS_END or POS_COLUMN) is ** written to the output. */ fts3GetDeltaVarint(&p1, &i1); fts3GetDeltaVarint(&p2, &i2); if( i1<2 || i2<2 ){ break; } do { fts3PutDeltaVarint(&p, &iPrev, (i1<i2) ? i1 : i2); iPrev -= 2; if( i1==i2 ){ fts3ReadNextPos(&p1, &i1); fts3ReadNextPos(&p2, &i2); }else if( i1<i2 ){ |
︙ | ︙ | |||
2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 | } } *p++ = POS_END; *pp = p; *pp1 = p1 + 1; *pp2 = p2 + 1; } /* ** This function is used to merge two position lists into one. When it is ** called, *pp1 and *pp2 must both point to position lists. A position-list is ** the part of a doclist that follows each document id. For example, if a row ** contains: | > | 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 | } } *p++ = POS_END; *pp = p; *pp1 = p1 + 1; *pp2 = p2 + 1; return SQLITE_OK; } /* ** This function is used to merge two position lists into one. When it is ** called, *pp1 and *pp2 must both point to position lists. A position-list is ** the part of a doclist that follows each document id. For example, if a row ** contains: |
︙ | ︙ | |||
2237 2238 2239 2240 2241 2242 2243 | char *p2 = *pp2; int iCol1 = 0; int iCol2 = 0; /* Never set both isSaveLeft and isExact for the same invocation. */ assert( isSaveLeft==0 || isExact==0 ); | | | 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 | char *p2 = *pp2; int iCol1 = 0; int iCol2 = 0; /* Never set both isSaveLeft and isExact for the same invocation. */ assert( isSaveLeft==0 || isExact==0 ); assert_fts3_nc( p!=0 && *p1!=0 && *p2!=0 ); if( *p1==POS_COLUMN ){ p1++; p1 += fts3GetVarint32(p1, &iCol1); } if( *p2==POS_COLUMN ){ p2++; p2 += fts3GetVarint32(p2, &iCol2); |
︙ | ︙ | |||
2259 2260 2261 2262 2263 2264 2265 | sqlite3_int64 iPos2 = 0; if( iCol1 ){ *p++ = POS_COLUMN; p += sqlite3Fts3PutVarint(p, iCol1); } | < < > | 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 | sqlite3_int64 iPos2 = 0; if( iCol1 ){ *p++ = POS_COLUMN; p += sqlite3Fts3PutVarint(p, iCol1); } fts3GetDeltaVarint(&p1, &iPos1); iPos1 -= 2; fts3GetDeltaVarint(&p2, &iPos2); iPos2 -= 2; if( iPos1<0 || iPos2<0 ) break; while( 1 ){ if( iPos2==iPos1+nToken || (isExact==0 && iPos2>iPos1 && iPos2<=iPos1+nToken) ){ sqlite3_int64 iSave; iSave = isSaveLeft ? iPos1 : iPos2; |
︙ | ︙ | |||
2411 2412 2413 2414 2415 2416 2417 | char *pEnd, /* End of buffer */ int bDescIdx, /* True if docids are descending */ sqlite3_int64 *pVal /* IN/OUT: Integer value */ ){ if( *pp>=pEnd ){ *pp = 0; }else{ | | | | | | 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 | char *pEnd, /* End of buffer */ int bDescIdx, /* True if docids are descending */ sqlite3_int64 *pVal /* IN/OUT: Integer value */ ){ if( *pp>=pEnd ){ *pp = 0; }else{ u64 iVal; *pp += sqlite3Fts3GetVarintU(*pp, &iVal); if( bDescIdx ){ *pVal = (i64)((u64)*pVal - iVal); }else{ *pVal = (i64)((u64)*pVal + iVal); } } } /* ** This function is used to write a single varint to a buffer. The varint ** is written to *pp. Before returning, *pp is set to point 1 byte past the |
︙ | ︙ | |||
2443 2444 2445 2446 2447 2448 2449 | static void fts3PutDeltaVarint3( char **pp, /* IN/OUT: Output pointer */ int bDescIdx, /* True for descending docids */ sqlite3_int64 *piPrev, /* IN/OUT: Previous value written to list */ int *pbFirst, /* IN/OUT: True after first int written */ sqlite3_int64 iVal /* Write this value to the list */ ){ | | > | > | | > | | 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 | static void fts3PutDeltaVarint3( char **pp, /* IN/OUT: Output pointer */ int bDescIdx, /* True for descending docids */ sqlite3_int64 *piPrev, /* IN/OUT: Previous value written to list */ int *pbFirst, /* IN/OUT: True after first int written */ sqlite3_int64 iVal /* Write this value to the list */ ){ sqlite3_uint64 iWrite; if( bDescIdx==0 || *pbFirst==0 ){ assert_fts3_nc( *pbFirst==0 || iVal>=*piPrev ); iWrite = (u64)iVal - (u64)*piPrev; }else{ assert_fts3_nc( *piPrev>=iVal ); iWrite = (u64)*piPrev - (u64)iVal; } assert( *pbFirst || *piPrev==0 ); assert_fts3_nc( *pbFirst==0 || iWrite>0 ); *pp += sqlite3Fts3PutVarint(*pp, iWrite); *piPrev = iVal; *pbFirst = 1; } /* ** This macro is used by various functions that merge doclists. The two ** arguments are 64-bit docid values. If the value of the stack variable ** bDescDoclist is 0 when this macro is invoked, then it returns (i1-i2). ** Otherwise, (i2-i1). ** ** Using this makes it easier to write code that can merge doclists that are ** sorted in either ascending or descending order. */ /* #define DOCID_CMP(i1, i2) ((bDescDoclist?-1:1) * (i64)((u64)i1-i2)) */ #define DOCID_CMP(i1, i2) ((bDescDoclist?-1:1) * (i1>i2?1:((i1==i2)?0:-1))) /* ** This function does an "OR" merge of two doclists (output contains all ** positions contained in either argument doclist). If the docids in the ** input doclists are sorted in ascending order, parameter bDescDoclist ** should be false. If they are sorted in ascending order, it should be ** passed a non-zero value. |
︙ | ︙ | |||
2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 | */ static int fts3DoclistOrMerge( int bDescDoclist, /* True if arguments are desc */ char *a1, int n1, /* First doclist */ char *a2, int n2, /* Second doclist */ char **paOut, int *pnOut /* OUT: Malloc'd doclist */ ){ sqlite3_int64 i1 = 0; sqlite3_int64 i2 = 0; sqlite3_int64 iPrev = 0; char *pEnd1 = &a1[n1]; char *pEnd2 = &a2[n2]; char *p1 = a1; char *p2 = a2; | > | 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 | */ static int fts3DoclistOrMerge( int bDescDoclist, /* True if arguments are desc */ char *a1, int n1, /* First doclist */ char *a2, int n2, /* Second doclist */ char **paOut, int *pnOut /* OUT: Malloc'd doclist */ ){ int rc = SQLITE_OK; sqlite3_int64 i1 = 0; sqlite3_int64 i2 = 0; sqlite3_int64 iPrev = 0; char *pEnd1 = &a1[n1]; char *pEnd2 = &a2[n2]; char *p1 = a1; char *p2 = a2; |
︙ | ︙ | |||
2531 2532 2533 2534 2535 2536 2537 | ** The space required to store the output is therefore the sum of the ** sizes of the two inputs, plus enough space for exactly one of the input ** docids to grow. ** ** A symetric argument may be made if the doclists are in descending ** order. */ | | | > | > | > > > > > > > > < | | 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 | ** The space required to store the output is therefore the sum of the ** sizes of the two inputs, plus enough space for exactly one of the input ** docids to grow. ** ** A symetric argument may be made if the doclists are in descending ** order. */ aOut = sqlite3_malloc64((i64)n1+n2+FTS3_VARINT_MAX-1+FTS3_BUFFER_PADDING); if( !aOut ) return SQLITE_NOMEM; p = aOut; fts3GetDeltaVarint3(&p1, pEnd1, 0, &i1); fts3GetDeltaVarint3(&p2, pEnd2, 0, &i2); while( p1 || p2 ){ sqlite3_int64 iDiff = DOCID_CMP(i1, i2); if( p2 && p1 && iDiff==0 ){ fts3PutDeltaVarint3(&p, bDescDoclist, &iPrev, &bFirstOut, i1); rc = fts3PoslistMerge(&p, &p1, &p2); if( rc ) break; fts3GetDeltaVarint3(&p1, pEnd1, bDescDoclist, &i1); fts3GetDeltaVarint3(&p2, pEnd2, bDescDoclist, &i2); }else if( !p2 || (p1 && iDiff<0) ){ fts3PutDeltaVarint3(&p, bDescDoclist, &iPrev, &bFirstOut, i1); fts3PoslistCopy(&p, &p1); fts3GetDeltaVarint3(&p1, pEnd1, bDescDoclist, &i1); }else{ fts3PutDeltaVarint3(&p, bDescDoclist, &iPrev, &bFirstOut, i2); fts3PoslistCopy(&p, &p2); fts3GetDeltaVarint3(&p2, pEnd2, bDescDoclist, &i2); } assert( (p-aOut)<=((p1?(p1-a1):n1)+(p2?(p2-a2):n2)+FTS3_VARINT_MAX-1) ); } if( rc!=SQLITE_OK ){ sqlite3_free(aOut); p = aOut = 0; }else{ assert( (p-aOut)<=n1+n2+FTS3_VARINT_MAX-1 ); memset(&aOut[(p-aOut)], 0, FTS3_BUFFER_PADDING); } *paOut = aOut; *pnOut = (int)(p-aOut); return rc; } /* ** This function does a "phrase" merge of two doclists. In a phrase merge, ** the output contains a copy of each position from the right-hand input ** doclist for which there is a position in the left-hand input doclist ** exactly nDist tokens before it. |
︙ | ︙ | |||
2594 2595 2596 2597 2598 2599 2600 | char *p2 = aRight; char *p; int bFirstOut = 0; char *aOut; assert( nDist>0 ); if( bDescDoclist ){ | | | 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 | char *p2 = aRight; char *p; int bFirstOut = 0; char *aOut; assert( nDist>0 ); if( bDescDoclist ){ aOut = sqlite3_malloc64((sqlite3_int64)*pnRight + FTS3_VARINT_MAX); if( aOut==0 ) return SQLITE_NOMEM; }else{ aOut = aRight; } p = aOut; fts3GetDeltaVarint3(&p1, pEnd1, 0, &i1); |
︙ | ︙ | |||
2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 | ** ** Similar padding is added in the fts3DoclistOrMerge() function. */ pTS->aaOutput[0] = sqlite3_malloc(nDoclist + FTS3_VARINT_MAX + 1); pTS->anOutput[0] = nDoclist; if( pTS->aaOutput[0] ){ memcpy(pTS->aaOutput[0], aDoclist, nDoclist); }else{ return SQLITE_NOMEM; } }else{ char *aMerge = aDoclist; int nMerge = nDoclist; int iOut; | > | 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 | ** ** Similar padding is added in the fts3DoclistOrMerge() function. */ pTS->aaOutput[0] = sqlite3_malloc(nDoclist + FTS3_VARINT_MAX + 1); pTS->anOutput[0] = nDoclist; if( pTS->aaOutput[0] ){ memcpy(pTS->aaOutput[0], aDoclist, nDoclist); memset(&pTS->aaOutput[0][nDoclist], 0, FTS3_VARINT_MAX); }else{ return SQLITE_NOMEM; } }else{ char *aMerge = aDoclist; int nMerge = nDoclist; int iOut; |
︙ | ︙ | |||
2829 2830 2831 2832 2833 2834 2835 | */ static int fts3SegReaderCursorAppend( Fts3MultiSegReader *pCsr, Fts3SegReader *pNew ){ if( (pCsr->nSegment%16)==0 ){ Fts3SegReader **apNew; | | | | 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 | */ static int fts3SegReaderCursorAppend( Fts3MultiSegReader *pCsr, Fts3SegReader *pNew ){ if( (pCsr->nSegment%16)==0 ){ Fts3SegReader **apNew; sqlite3_int64 nByte = (pCsr->nSegment + 16)*sizeof(Fts3SegReader*); apNew = (Fts3SegReader **)sqlite3_realloc64(pCsr->apSegment, nByte); if( !apNew ){ sqlite3Fts3SegReaderFree(pNew); return SQLITE_NOMEM; } pCsr->apSegment = apNew; } pCsr->apSegment[pCsr->nSegment++] = pNew; |
︙ | ︙ | |||
2869 2870 2871 2872 2873 2874 2875 | /* If iLevel is less than 0 and this is not a scan, include a seg-reader ** for the pending-terms. If this is a scan, then this call must be being ** made by an fts4aux module, not an FTS table. In this case calling ** Fts3SegReaderPending might segfault, as the data structures used by ** fts4aux are not completely populated. So it's easiest to filter these ** calls out here. */ | | | 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 | /* If iLevel is less than 0 and this is not a scan, include a seg-reader ** for the pending-terms. If this is a scan, then this call must be being ** made by an fts4aux module, not an FTS table. In this case calling ** Fts3SegReaderPending might segfault, as the data structures used by ** fts4aux are not completely populated. So it's easiest to filter these ** calls out here. */ if( iLevel<0 && p->aIndex && p->iPrevLangid==iLangid ){ Fts3SegReader *pSeg = 0; rc = sqlite3Fts3SegReaderPending(p, iIndex, zTerm, nTerm, isPrefix||isScan, &pSeg); if( rc==SQLITE_OK && pSeg ){ rc = fts3SegReaderCursorAppend(pCsr, pSeg); } } |
︙ | ︙ | |||
2894 2895 2896 2897 2898 2899 2900 | sqlite3_int64 iLeavesEndBlock = sqlite3_column_int64(pStmt, 2); sqlite3_int64 iEndBlock = sqlite3_column_int64(pStmt, 3); int nRoot = sqlite3_column_bytes(pStmt, 4); char const *zRoot = sqlite3_column_blob(pStmt, 4); /* If zTerm is not NULL, and this segment is not stored entirely on its ** root node, the range of leaves scanned can be reduced. Do this. */ | | | 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 | sqlite3_int64 iLeavesEndBlock = sqlite3_column_int64(pStmt, 2); sqlite3_int64 iEndBlock = sqlite3_column_int64(pStmt, 3); int nRoot = sqlite3_column_bytes(pStmt, 4); char const *zRoot = sqlite3_column_blob(pStmt, 4); /* If zTerm is not NULL, and this segment is not stored entirely on its ** root node, the range of leaves scanned can be reduced. Do this. */ if( iStartBlock && zTerm && zRoot ){ sqlite3_int64 *pi = (isPrefix ? &iLeavesEndBlock : 0); rc = fts3SelectLeaf(p, zTerm, nTerm, zRoot, nRoot, &iStartBlock, pi); if( rc!=SQLITE_OK ) goto finished; if( isPrefix==0 && isScan==0 ) iLeavesEndBlock = iStartBlock; } rc = sqlite3Fts3SegReaderNew(pCsr->nSegment+1, |
︙ | ︙ | |||
3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 | ** even if we reach end-of-file. The fts3EofMethod() will be called ** subsequently to determine whether or not an EOF was hit. */ static int fts3NextMethod(sqlite3_vtab_cursor *pCursor){ int rc; Fts3Cursor *pCsr = (Fts3Cursor *)pCursor; if( pCsr->eSearch==FTS3_DOCID_SEARCH || pCsr->eSearch==FTS3_FULLSCAN_SEARCH ){ if( SQLITE_ROW!=sqlite3_step(pCsr->pStmt) ){ pCsr->isEof = 1; rc = sqlite3_reset(pCsr->pStmt); }else{ pCsr->iPrevId = sqlite3_column_int64(pCsr->pStmt, 0); rc = SQLITE_OK; } }else{ rc = fts3EvalNext((Fts3Cursor *)pCursor); } assert( ((Fts3Table *)pCsr->base.pVtab)->pSegments==0 ); return rc; } | > > > < < < < < < < < < < < < | 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 | ** even if we reach end-of-file. The fts3EofMethod() will be called ** subsequently to determine whether or not an EOF was hit. */ static int fts3NextMethod(sqlite3_vtab_cursor *pCursor){ int rc; Fts3Cursor *pCsr = (Fts3Cursor *)pCursor; if( pCsr->eSearch==FTS3_DOCID_SEARCH || pCsr->eSearch==FTS3_FULLSCAN_SEARCH ){ Fts3Table *pTab = (Fts3Table*)pCursor->pVtab; pTab->bLock++; if( SQLITE_ROW!=sqlite3_step(pCsr->pStmt) ){ pCsr->isEof = 1; rc = sqlite3_reset(pCsr->pStmt); }else{ pCsr->iPrevId = sqlite3_column_int64(pCsr->pStmt, 0); rc = SQLITE_OK; } pTab->bLock--; }else{ rc = fts3EvalNext((Fts3Cursor *)pCursor); } assert( ((Fts3Table *)pCsr->base.pVtab)->pSegments==0 ); return rc; } /* ** If the numeric type of argument pVal is "integer", then return it ** converted to a 64-bit signed integer. Otherwise, return a copy of ** the second parameter, iDefault. */ static sqlite3_int64 fts3DocidRange(sqlite3_value *pVal, i64 iDefault){ if( pVal ){ |
︙ | ︙ | |||
3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 | sqlite3_value *pLangid = 0; /* The "langid = ?" constraint, if any */ sqlite3_value *pDocidGe = 0; /* The "docid >= ?" constraint, if any */ sqlite3_value *pDocidLe = 0; /* The "docid <= ?" constraint, if any */ int iIdx; UNUSED_PARAMETER(idxStr); UNUSED_PARAMETER(nVal); eSearch = (idxNum & 0x0000FFFF); assert( eSearch>=0 && eSearch<=(FTS3_FULLTEXT_SEARCH+p->nColumn) ); assert( p->pSegments==0 ); /* Collect arguments into local variables */ iIdx = 0; | > > > > | 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 | sqlite3_value *pLangid = 0; /* The "langid = ?" constraint, if any */ sqlite3_value *pDocidGe = 0; /* The "docid >= ?" constraint, if any */ sqlite3_value *pDocidLe = 0; /* The "docid <= ?" constraint, if any */ int iIdx; UNUSED_PARAMETER(idxStr); UNUSED_PARAMETER(nVal); if( p->bLock ){ return SQLITE_ERROR; } eSearch = (idxNum & 0x0000FFFF); assert( eSearch>=0 && eSearch<=(FTS3_FULLTEXT_SEARCH+p->nColumn) ); assert( p->pSegments==0 ); /* Collect arguments into local variables */ iIdx = 0; |
︙ | ︙ | |||
3282 3283 3284 3285 3286 3287 3288 | ); }else{ zSql = sqlite3_mprintf("SELECT %s ORDER BY rowid %s", p->zReadExprlist, (pCsr->bDesc ? "DESC" : "ASC") ); } if( zSql ){ | > > | > > | 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 3392 3393 3394 3395 3396 3397 3398 3399 3400 | ); }else{ zSql = sqlite3_mprintf("SELECT %s ORDER BY rowid %s", p->zReadExprlist, (pCsr->bDesc ? "DESC" : "ASC") ); } if( zSql ){ p->bLock++; rc = sqlite3_prepare_v3( p->db,zSql,-1,SQLITE_PREPARE_PERSISTENT,&pCsr->pStmt,0 ); p->bLock--; sqlite3_free(zSql); }else{ rc = SQLITE_NOMEM; } }else if( eSearch==FTS3_DOCID_SEARCH ){ rc = fts3CursorSeekStmt(pCsr); if( rc==SQLITE_OK ){ |
︙ | ︙ | |||
3366 3367 3368 3369 3370 3371 3372 | sqlite3_result_int64(pCtx, pCsr->iLangid); break; }else if( p->zLanguageid==0 ){ sqlite3_result_int(pCtx, 0); break; }else{ iCol = p->nColumn; | | | 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 | sqlite3_result_int64(pCtx, pCsr->iLangid); break; }else if( p->zLanguageid==0 ){ sqlite3_result_int(pCtx, 0); break; }else{ iCol = p->nColumn; /* no break */ deliberate_fall_through } default: /* A user column. Or, if this is a full-table scan, possibly the ** language-id column. Seek the cursor. */ rc = fts3CursorSeek(0, pCsr); if( rc==SQLITE_OK && sqlite3_data_count(pCsr->pStmt)-1>iCol ){ |
︙ | ︙ | |||
3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 | } /* ** Implementation of xBegin() method. */ static int fts3BeginMethod(sqlite3_vtab *pVtab){ Fts3Table *p = (Fts3Table*)pVtab; UNUSED_PARAMETER(pVtab); assert( p->pSegments==0 ); assert( p->nPendingData==0 ); assert( p->inTransaction!=1 ); | > > > > > | | < > > | | 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 | } /* ** Implementation of xBegin() method. */ static int fts3BeginMethod(sqlite3_vtab *pVtab){ Fts3Table *p = (Fts3Table*)pVtab; int rc; UNUSED_PARAMETER(pVtab); assert( p->pSegments==0 ); assert( p->nPendingData==0 ); assert( p->inTransaction!=1 ); p->nLeafAdd = 0; rc = fts3SetHasStat(p); #ifdef SQLITE_DEBUG if( rc==SQLITE_OK ){ p->inTransaction = 1; p->mxSavepoint = -1; } #endif return rc; } /* ** Implementation of xCommit() method. This is a no-op. The contents of ** the pending-terms hash-table have already been flushed into the database ** by fts3SyncMethod(). */ |
︙ | ︙ | |||
3609 3610 3611 3612 3613 3614 3615 3616 3617 3618 3619 3620 3621 3622 3623 3624 3625 | "wrong number of arguments to function snippet()", -1); return; } if( fts3FunctionArg(pContext, "snippet", apVal[0], &pCsr) ) return; switch( nVal ){ case 6: nToken = sqlite3_value_int(apVal[5]); case 5: iCol = sqlite3_value_int(apVal[4]); case 4: zEllipsis = (const char*)sqlite3_value_text(apVal[3]); case 3: zEnd = (const char*)sqlite3_value_text(apVal[2]); case 2: zStart = (const char*)sqlite3_value_text(apVal[1]); } if( !zEllipsis || !zEnd || !zStart ){ sqlite3_result_error_nomem(pContext); }else if( nToken==0 ){ sqlite3_result_text(pContext, "", -1, SQLITE_STATIC); }else if( SQLITE_OK==fts3CursorSeek(pContext, pCsr) ){ | > > > > | 3719 3720 3721 3722 3723 3724 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 3737 3738 3739 | "wrong number of arguments to function snippet()", -1); return; } if( fts3FunctionArg(pContext, "snippet", apVal[0], &pCsr) ) return; switch( nVal ){ case 6: nToken = sqlite3_value_int(apVal[5]); /* no break */ deliberate_fall_through case 5: iCol = sqlite3_value_int(apVal[4]); /* no break */ deliberate_fall_through case 4: zEllipsis = (const char*)sqlite3_value_text(apVal[3]); /* no break */ deliberate_fall_through case 3: zEnd = (const char*)sqlite3_value_text(apVal[2]); /* no break */ deliberate_fall_through case 2: zStart = (const char*)sqlite3_value_text(apVal[1]); } if( !zEllipsis || !zEnd || !zStart ){ sqlite3_result_error_nomem(pContext); }else if( nToken==0 ){ sqlite3_result_text(pContext, "", -1, SQLITE_STATIC); }else if( SQLITE_OK==fts3CursorSeek(pContext, pCsr) ){ |
︙ | ︙ | |||
3836 3837 3838 3839 3840 3841 3842 | ** ** Discard the contents of the pending terms table. */ static int fts3RollbackToMethod(sqlite3_vtab *pVtab, int iSavepoint){ Fts3Table *p = (Fts3Table*)pVtab; UNUSED_PARAMETER(iSavepoint); assert( p->inTransaction ); | < | 3950 3951 3952 3953 3954 3955 3956 3957 3958 3959 3960 3961 3962 3963 | ** ** Discard the contents of the pending terms table. */ static int fts3RollbackToMethod(sqlite3_vtab *pVtab, int iSavepoint){ Fts3Table *p = (Fts3Table*)pVtab; UNUSED_PARAMETER(iSavepoint); assert( p->inTransaction ); TESTONLY( p->mxSavepoint = iSavepoint ); sqlite3Fts3PendingTermsClear(p); return SQLITE_OK; } /* ** Return true if zName is the extension on one of the shadow tables used |
︙ | ︙ | |||
4300 4301 4302 4303 4304 4305 4306 | ** scanned in forward order, and the phrase consists of ** MAX_INCR_PHRASE_TOKENS or fewer tokens, none of which are are "^first" ** tokens or prefix tokens that cannot use a prefix-index. */ int bHaveIncr = 0; int bIncrOk = (bOptOk && pCsr->bDesc==pTab->bDescIdx && p->nToken<=MAX_INCR_PHRASE_TOKENS && p->nToken>0 | | | 4413 4414 4415 4416 4417 4418 4419 4420 4421 4422 4423 4424 4425 4426 4427 | ** scanned in forward order, and the phrase consists of ** MAX_INCR_PHRASE_TOKENS or fewer tokens, none of which are are "^first" ** tokens or prefix tokens that cannot use a prefix-index. */ int bHaveIncr = 0; int bIncrOk = (bOptOk && pCsr->bDesc==pTab->bDescIdx && p->nToken<=MAX_INCR_PHRASE_TOKENS && p->nToken>0 #if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) && pTab->bNoIncrDoclist==0 #endif ); for(i=0; bIncrOk==1 && i<p->nToken; i++){ Fts3PhraseToken *pToken = &p->aToken[i]; if( pToken->bFirst || (pToken->pSegcsr!=0 && !pToken->pSegcsr->bLookup) ){ bIncrOk = 0; |
︙ | ︙ | |||
4411 4412 4413 4414 4415 4416 4417 | sqlite3_int64 *piDocid, /* IN/OUT: Docid pointer */ u8 *pbEof /* OUT: End-of-file flag */ ){ char *p = *ppIter; assert( nDoclist>0 ); assert( *pbEof==0 ); | | | 4524 4525 4526 4527 4528 4529 4530 4531 4532 4533 4534 4535 4536 4537 4538 | sqlite3_int64 *piDocid, /* IN/OUT: Docid pointer */ u8 *pbEof /* OUT: End-of-file flag */ ){ char *p = *ppIter; assert( nDoclist>0 ); assert( *pbEof==0 ); assert_fts3_nc( p || *piDocid==0 ); assert( !p || (p>=aDoclist && p<=&aDoclist[nDoclist]) ); if( p==0 ){ p = aDoclist; p += sqlite3Fts3GetVarint(p, piDocid); }else{ fts3PoslistCopy(0, &p); |
︙ | ︙ | |||
4442 4443 4444 4445 4446 4447 4448 | */ static void fts3EvalDlPhraseNext( Fts3Table *pTab, Fts3Doclist *pDL, u8 *pbEof ){ char *pIter; /* Used to iterate through aAll */ | | > | | 4555 4556 4557 4558 4559 4560 4561 4562 4563 4564 4565 4566 4567 4568 4569 4570 4571 4572 4573 4574 4575 4576 4577 4578 | */ static void fts3EvalDlPhraseNext( Fts3Table *pTab, Fts3Doclist *pDL, u8 *pbEof ){ char *pIter; /* Used to iterate through aAll */ char *pEnd; /* 1 byte past end of aAll */ if( pDL->pNextDocid ){ pIter = pDL->pNextDocid; assert( pDL->aAll!=0 || pIter==0 ); }else{ pIter = pDL->aAll; } if( pIter==0 || pIter>=(pEnd = pDL->aAll + pDL->nAll) ){ /* We have already reached the end of this doclist. EOF. */ *pbEof = 1; }else{ sqlite3_int64 iDelta; pIter += sqlite3Fts3GetVarint(pIter, &iDelta); if( pTab->bDescIdx==0 || pDL->pNextDocid==0 ){ pDL->iDocid += iDelta; |
︙ | ︙ | |||
4611 4612 4613 4614 4615 4616 4617 | } } /* Check if the current entries really are a phrase match */ if( bEof==0 ){ int nList = 0; int nByte = a[p->nToken-1].nList; | | > | 4725 4726 4727 4728 4729 4730 4731 4732 4733 4734 4735 4736 4737 4738 4739 4740 4741 4742 | } } /* Check if the current entries really are a phrase match */ if( bEof==0 ){ int nList = 0; int nByte = a[p->nToken-1].nList; char *aDoclist = sqlite3_malloc(nByte+FTS3_BUFFER_PADDING); if( !aDoclist ) return SQLITE_NOMEM; memcpy(aDoclist, a[p->nToken-1].pList, nByte+1); memset(&aDoclist[nByte], 0, FTS3_BUFFER_PADDING); for(i=0; i<(p->nToken-1); i++){ if( a[i].bIgnore==0 ){ char *pL = a[i].pList; char *pR = aDoclist; char *pOut = aDoclist; int nDist = p->nToken-1-i; |
︙ | ︙ | |||
4821 4822 4823 4824 4825 4826 4827 | sqlite3_int64 nByte = 0; const char *pEnd; const char *a; rc = sqlite3Fts3SelectDoctotal(p, &pStmt); if( rc!=SQLITE_OK ) return rc; a = sqlite3_column_blob(pStmt, 0); | > | < | | | | > | 4936 4937 4938 4939 4940 4941 4942 4943 4944 4945 4946 4947 4948 4949 4950 4951 4952 4953 4954 4955 4956 | sqlite3_int64 nByte = 0; const char *pEnd; const char *a; rc = sqlite3Fts3SelectDoctotal(p, &pStmt); if( rc!=SQLITE_OK ) return rc; a = sqlite3_column_blob(pStmt, 0); testcase( a==0 ); /* If %_stat.value set to X'' */ if( a ){ pEnd = &a[sqlite3_column_bytes(pStmt, 0)]; a += sqlite3Fts3GetVarintBounded(a, pEnd, &nDoc); while( a<pEnd ){ a += sqlite3Fts3GetVarintBounded(a, pEnd, &nByte); } } if( nDoc==0 || nByte==0 ){ sqlite3_reset(pStmt); return FTS_CORRUPT_VTAB; } pCsr->nDoc = nDoc; |
︙ | ︙ | |||
5003 5004 5005 5006 5007 5008 5009 | /* Allocate a MultiSegReader for each token in the expression. */ fts3EvalAllocateReaders(pCsr, pCsr->pExpr, &nToken, &nOr, &rc); /* Determine which, if any, tokens in the expression should be deferred. */ #ifndef SQLITE_DISABLE_FTS4_DEFERRED if( rc==SQLITE_OK && nToken>1 && pTab->bFts4 ){ Fts3TokenAndCost *aTC; | < | < > | 5119 5120 5121 5122 5123 5124 5125 5126 5127 5128 5129 5130 5131 5132 5133 5134 5135 5136 5137 5138 5139 5140 5141 | /* Allocate a MultiSegReader for each token in the expression. */ fts3EvalAllocateReaders(pCsr, pCsr->pExpr, &nToken, &nOr, &rc); /* Determine which, if any, tokens in the expression should be deferred. */ #ifndef SQLITE_DISABLE_FTS4_DEFERRED if( rc==SQLITE_OK && nToken>1 && pTab->bFts4 ){ Fts3TokenAndCost *aTC; aTC = (Fts3TokenAndCost *)sqlite3_malloc64( sizeof(Fts3TokenAndCost) * nToken + sizeof(Fts3Expr *) * nOr * 2 ); if( !aTC ){ rc = SQLITE_NOMEM; }else{ Fts3Expr **apOr = (Fts3Expr **)&aTC[nToken]; int ii; Fts3TokenAndCost *pTC = aTC; Fts3Expr **ppOr = apOr; fts3EvalTokenCosts(pCsr, 0, pCsr->pExpr, &pTC, &ppOr, &rc); nToken = (int)(pTC-aTC); nOr = (int)(ppOr-apOr); |
︙ | ︙ | |||
5058 5059 5060 5061 5062 5063 5064 | ** the phrase object passed as the fifth argument according to a NEAR ** condition. For example: ** ** abc NEAR/5 "def ghi" ** ** Parameter nNear is passed the NEAR distance of the expression (5 in ** the example above). When this function is called, *paPoslist points to | | | 5173 5174 5175 5176 5177 5178 5179 5180 5181 5182 5183 5184 5185 5186 5187 | ** the phrase object passed as the fifth argument according to a NEAR ** condition. For example: ** ** abc NEAR/5 "def ghi" ** ** Parameter nNear is passed the NEAR distance of the expression (5 in ** the example above). When this function is called, *paPoslist points to ** the position list, and *pnToken is the number of phrase tokens in the ** phrase on the other side of the NEAR operator to pPhrase. For example, ** if pPhrase refers to the "def ghi" phrase, then *paPoslist points to ** the position list associated with phrase "abc". ** ** All positions in the pPhrase position list that are not sufficiently ** close to a position in the *paPoslist position list are removed. If this ** leaves 0 positions, zero is returned. Otherwise, non-zero. |
︙ | ︙ | |||
5093 5094 5095 5096 5097 5098 5099 | p2 = pOut = pPhrase->doclist.pList; res = fts3PoslistNearMerge( &pOut, aTmp, nParam1, nParam2, paPoslist, &p2 ); if( res ){ nNew = (int)(pOut - pPhrase->doclist.pList) - 1; | > > | < | | > | 5208 5209 5210 5211 5212 5213 5214 5215 5216 5217 5218 5219 5220 5221 5222 5223 5224 5225 5226 5227 | p2 = pOut = pPhrase->doclist.pList; res = fts3PoslistNearMerge( &pOut, aTmp, nParam1, nParam2, paPoslist, &p2 ); if( res ){ nNew = (int)(pOut - pPhrase->doclist.pList) - 1; assert_fts3_nc( nNew<=pPhrase->doclist.nList && nNew>0 ); if( nNew>=0 && nNew<=pPhrase->doclist.nList ){ assert( pPhrase->doclist.pList[nNew]=='\0' ); memset(&pPhrase->doclist.pList[nNew], 0, pPhrase->doclist.nList - nNew); pPhrase->doclist.nList = nNew; } *paPoslist = pPhrase->doclist.pList; *pnToken = pPhrase->nToken; } return res; } |
︙ | ︙ | |||
5205 5206 5207 5208 5209 5210 5211 5212 5213 5214 5215 5216 5217 5218 5219 5220 5221 | if( pLeft->pPhrase && pLeft->pPhrase->doclist.aAll ){ Fts3Doclist *pDl = &pLeft->pPhrase->doclist; while( *pRc==SQLITE_OK && pLeft->bEof==0 ){ memset(pDl->pList, 0, pDl->nList); fts3EvalNextRow(pCsr, pLeft, pRc); } } } } break; } case FTSQUERY_OR: { Fts3Expr *pLeft = pExpr->pLeft; Fts3Expr *pRight = pExpr->pRight; sqlite3_int64 iCmp = DOCID_CMP(pLeft->iDocid, pRight->iDocid); | > | | | 5322 5323 5324 5325 5326 5327 5328 5329 5330 5331 5332 5333 5334 5335 5336 5337 5338 5339 5340 5341 5342 5343 5344 5345 5346 5347 5348 | if( pLeft->pPhrase && pLeft->pPhrase->doclist.aAll ){ Fts3Doclist *pDl = &pLeft->pPhrase->doclist; while( *pRc==SQLITE_OK && pLeft->bEof==0 ){ memset(pDl->pList, 0, pDl->nList); fts3EvalNextRow(pCsr, pLeft, pRc); } } pRight->bEof = pLeft->bEof = 1; } } break; } case FTSQUERY_OR: { Fts3Expr *pLeft = pExpr->pLeft; Fts3Expr *pRight = pExpr->pRight; sqlite3_int64 iCmp = DOCID_CMP(pLeft->iDocid, pRight->iDocid); assert_fts3_nc( pLeft->bStart || pLeft->iDocid==pRight->iDocid ); assert_fts3_nc( pRight->bStart || pLeft->iDocid==pRight->iDocid ); if( pRight->bEof || (pLeft->bEof==0 && iCmp<0) ){ fts3EvalNextRow(pCsr, pLeft, pRc); }else if( pLeft->bEof || iCmp>0 ){ fts3EvalNextRow(pCsr, pRight, pRc); }else{ fts3EvalNextRow(pCsr, pLeft, pRc); |
︙ | ︙ | |||
5315 5316 5317 5318 5319 5320 5321 | ** no exceptions to this - it's the way the parser in fts3_expr.c works. */ if( *pRc==SQLITE_OK && pExpr->eType==FTSQUERY_NEAR && (pExpr->pParent==0 || pExpr->pParent->eType!=FTSQUERY_NEAR) ){ Fts3Expr *p; | | | | 5433 5434 5435 5436 5437 5438 5439 5440 5441 5442 5443 5444 5445 5446 5447 5448 5449 5450 5451 5452 5453 5454 5455 5456 | ** no exceptions to this - it's the way the parser in fts3_expr.c works. */ if( *pRc==SQLITE_OK && pExpr->eType==FTSQUERY_NEAR && (pExpr->pParent==0 || pExpr->pParent->eType!=FTSQUERY_NEAR) ){ Fts3Expr *p; sqlite3_int64 nTmp = 0; /* Bytes of temp space */ char *aTmp; /* Temp space for PoslistNearMerge() */ /* Allocate temporary working space. */ for(p=pExpr; p->pLeft; p=p->pLeft){ assert( p->pRight->pPhrase->doclist.nList>0 ); nTmp += p->pRight->pPhrase->doclist.nList; } nTmp += p->pPhrase->doclist.nList; aTmp = sqlite3_malloc64(nTmp*2); if( !aTmp ){ *pRc = SQLITE_NOMEM; res = 0; }else{ char *aPoslist = p->pPhrase->doclist.pList; int nToken = p->pPhrase->nToken; |
︙ | ︙ | |||
5447 5448 5449 5450 5451 5452 5453 | } *pRc = fts3EvalDeferredPhrase(pCsr, pPhrase); bHit = (pPhrase->doclist.pList!=0); pExpr->iDocid = pCsr->iPrevId; }else #endif { | > | > > | 5565 5566 5567 5568 5569 5570 5571 5572 5573 5574 5575 5576 5577 5578 5579 5580 5581 5582 | } *pRc = fts3EvalDeferredPhrase(pCsr, pPhrase); bHit = (pPhrase->doclist.pList!=0); pExpr->iDocid = pCsr->iPrevId; }else #endif { bHit = ( pExpr->bEof==0 && pExpr->iDocid==pCsr->iPrevId && pExpr->pPhrase->doclist.nList>0 ); } break; } } } return bHit; } |
︙ | ︙ | |||
5594 5595 5596 5597 5598 5599 5600 | ** After allocating the Fts3Expr.aMI[] array for each phrase in the ** expression rooted at pExpr, the cursor iterates through all rows matched ** by pExpr, calling this function for each row. This function increments ** the values in Fts3Expr.aMI[] according to the position-list currently ** found in Fts3Expr.pPhrase->doclist.pList for each of the phrase ** expression nodes. */ | | < < > | | | | 5715 5716 5717 5718 5719 5720 5721 5722 5723 5724 5725 5726 5727 5728 5729 5730 5731 5732 5733 5734 5735 5736 5737 5738 5739 5740 5741 5742 5743 5744 5745 5746 5747 5748 5749 5750 5751 5752 5753 5754 5755 5756 | ** After allocating the Fts3Expr.aMI[] array for each phrase in the ** expression rooted at pExpr, the cursor iterates through all rows matched ** by pExpr, calling this function for each row. This function increments ** the values in Fts3Expr.aMI[] according to the position-list currently ** found in Fts3Expr.pPhrase->doclist.pList for each of the phrase ** expression nodes. */ static void fts3EvalUpdateCounts(Fts3Expr *pExpr, int nCol){ if( pExpr ){ Fts3Phrase *pPhrase = pExpr->pPhrase; if( pPhrase && pPhrase->doclist.pList ){ int iCol = 0; char *p = pPhrase->doclist.pList; do{ u8 c = 0; int iCnt = 0; while( 0xFE & (*p | c) ){ if( (c&0x80)==0 ) iCnt++; c = *p++ & 0x80; } /* aMI[iCol*3 + 1] = Number of occurrences ** aMI[iCol*3 + 2] = Number of rows containing at least one instance */ pExpr->aMI[iCol*3 + 1] += iCnt; pExpr->aMI[iCol*3 + 2] += (iCnt>0); if( *p==0x00 ) break; p++; p += fts3GetVarint32(p, &iCol); }while( iCol<nCol ); } fts3EvalUpdateCounts(pExpr->pLeft, nCol); fts3EvalUpdateCounts(pExpr->pRight, nCol); } } /* ** Expression pExpr must be of type FTSQUERY_PHRASE. ** ** If it is not already allocated and populated, this function allocates and |
︙ | ︙ | |||
5666 5667 5668 5669 5670 5671 5672 | bEof = pRoot->bEof; assert( pRoot->bStart ); /* Allocate space for the aMSI[] array of each FTSQUERY_PHRASE node */ for(p=pRoot; p; p=p->pLeft){ Fts3Expr *pE = (p->eType==FTSQUERY_PHRASE?p:p->pRight); assert( pE->aMI==0 ); | | | 5786 5787 5788 5789 5790 5791 5792 5793 5794 5795 5796 5797 5798 5799 5800 | bEof = pRoot->bEof; assert( pRoot->bStart ); /* Allocate space for the aMSI[] array of each FTSQUERY_PHRASE node */ for(p=pRoot; p; p=p->pLeft){ Fts3Expr *pE = (p->eType==FTSQUERY_PHRASE?p:p->pRight); assert( pE->aMI==0 ); pE->aMI = (u32 *)sqlite3_malloc64(pTab->nColumn * 3 * sizeof(u32)); if( !pE->aMI ) return SQLITE_NOMEM; memset(pE->aMI, 0, pTab->nColumn * 3 * sizeof(u32)); } fts3EvalRestart(pCsr, pRoot, &rc); while( pCsr->isEof==0 && rc==SQLITE_OK ){ |
︙ | ︙ | |||
5692 5693 5694 5695 5696 5697 5698 | pCsr->iPrevId = pRoot->iDocid; }while( pCsr->isEof==0 && pRoot->eType==FTSQUERY_NEAR && sqlite3Fts3EvalTestDeferred(pCsr, &rc) ); if( rc==SQLITE_OK && pCsr->isEof==0 ){ | | | > | 5812 5813 5814 5815 5816 5817 5818 5819 5820 5821 5822 5823 5824 5825 5826 5827 5828 5829 5830 5831 5832 5833 5834 5835 5836 5837 5838 5839 5840 5841 5842 5843 5844 5845 5846 | pCsr->iPrevId = pRoot->iDocid; }while( pCsr->isEof==0 && pRoot->eType==FTSQUERY_NEAR && sqlite3Fts3EvalTestDeferred(pCsr, &rc) ); if( rc==SQLITE_OK && pCsr->isEof==0 ){ fts3EvalUpdateCounts(pRoot, pTab->nColumn); } } pCsr->isEof = 0; pCsr->iPrevId = iPrevId; if( bEof ){ pRoot->bEof = bEof; }else{ /* Caution: pRoot may iterate through docids in ascending or descending ** order. For this reason, even though it seems more defensive, the ** do loop can not be written: ** ** do {...} while( pRoot->iDocid<iDocid && rc==SQLITE_OK ); */ fts3EvalRestart(pCsr, pRoot, &rc); do { fts3EvalNextRow(pCsr, pRoot, &rc); assert_fts3_nc( pRoot->bEof==0 ); if( pRoot->bEof ) rc = FTS_CORRUPT_VTAB; }while( pRoot->iDocid!=iDocid && rc==SQLITE_OK ); } } return rc; } /* |
︙ | ︙ | |||
5851 5852 5853 5854 5855 5856 5857 5858 5859 5860 5861 5862 5863 5864 | int bEofSave = pNear->bEof; fts3EvalRestart(pCsr, pNear, &rc); while( rc==SQLITE_OK && !pNear->bEof ){ fts3EvalNextRow(pCsr, pNear, &rc); if( bEofSave==0 && pNear->iDocid==iDocid ) break; } assert( rc!=SQLITE_OK || pPhrase->bIncr==0 ); } if( bTreeEof ){ while( rc==SQLITE_OK && !pNear->bEof ){ fts3EvalNextRow(pCsr, pNear, &rc); } } if( rc!=SQLITE_OK ) return rc; | > > > | 5972 5973 5974 5975 5976 5977 5978 5979 5980 5981 5982 5983 5984 5985 5986 5987 5988 | int bEofSave = pNear->bEof; fts3EvalRestart(pCsr, pNear, &rc); while( rc==SQLITE_OK && !pNear->bEof ){ fts3EvalNextRow(pCsr, pNear, &rc); if( bEofSave==0 && pNear->iDocid==iDocid ) break; } assert( rc!=SQLITE_OK || pPhrase->bIncr==0 ); if( rc==SQLITE_OK && pNear->bEof!=bEofSave ){ rc = FTS_CORRUPT_VTAB; } } if( bTreeEof ){ while( rc==SQLITE_OK && !pNear->bEof ){ fts3EvalNextRow(pCsr, pNear, &rc); } } if( rc!=SQLITE_OK ) return rc; |
︙ | ︙ |
Changes to ext/fts3/fts3Int.h.
︙ | ︙ | |||
91 92 93 94 95 96 97 98 99 100 101 102 103 104 | /* ** Maximum length of a varint encoded integer. The varint format is different ** from that used by SQLite, so the maximum length is 10, not 9. */ #define FTS3_VARINT_MAX 10 /* ** FTS4 virtual tables may maintain multiple indexes - one index of all terms ** in the document set and zero or more prefix indexes. All indexes are stored ** as one or more b+-trees in the %_segments and %_segdir tables. ** ** It is possible to determine which index a b+-tree belongs to based on the ** value stored in the "%_segdir.level" column. Given this value L, the index | > > | 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 | /* ** Maximum length of a varint encoded integer. The varint format is different ** from that used by SQLite, so the maximum length is 10, not 9. */ #define FTS3_VARINT_MAX 10 #define FTS3_BUFFER_PADDING 8 /* ** FTS4 virtual tables may maintain multiple indexes - one index of all terms ** in the document set and zero or more prefix indexes. All indexes are stored ** as one or more b+-trees in the %_segments and %_segdir tables. ** ** It is possible to determine which index a b+-tree belongs to based on the ** value stored in the "%_segdir.level" column. Given this value L, the index |
︙ | ︙ | |||
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 | /* ** Terminator values for position-lists and column-lists. */ #define POS_COLUMN (1) /* Column-list terminator */ #define POS_END (0) /* Position-list terminator */ /* ** This section provides definitions to allow the ** FTS3 extension to be compiled outside of the ** amalgamation. */ #ifndef SQLITE_AMALGAMATION /* ** Macros indicating that conditional expressions are always true or ** false. */ | > > > > > > > > > > > > | > > > | | | | | < < | | | 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 | /* ** Terminator values for position-lists and column-lists. */ #define POS_COLUMN (1) /* Column-list terminator */ #define POS_END (0) /* Position-list terminator */ /* ** The assert_fts3_nc() macro is similar to the assert() macro, except that it ** is used for assert() conditions that are true only if it can be ** guranteed that the database is not corrupt. */ #ifdef SQLITE_DEBUG extern int sqlite3_fts3_may_be_corrupt; # define assert_fts3_nc(x) assert(sqlite3_fts3_may_be_corrupt || (x)) #else # define assert_fts3_nc(x) assert(x) #endif /* ** This section provides definitions to allow the ** FTS3 extension to be compiled outside of the ** amalgamation. */ #ifndef SQLITE_AMALGAMATION /* ** Macros indicating that conditional expressions are always true or ** false. */ #if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_MUTATION_TEST) # define SQLITE_OMIT_AUXILIARY_SAFETY_CHECKS 1 #endif #if defined(SQLITE_OMIT_AUXILIARY_SAFETY_CHECKS) # define ALWAYS(X) (1) # define NEVER(X) (0) #elif !defined(NDEBUG) # define ALWAYS(X) ((X)?1:(assert(0),0)) # define NEVER(X) ((X)?(assert(0),1):0) #else # define ALWAYS(X) (X) # define NEVER(X) (X) #endif /* ** Internal types used by SQLite. */ typedef unsigned char u8; /* 1-byte (or larger) unsigned integer */ typedef short int i16; /* 2-byte (or larger) signed integer */ |
︙ | ︙ | |||
177 178 179 180 181 182 183 184 185 186 187 188 189 190 | ** within testcase() and assert() macros. */ #if defined(SQLITE_DEBUG) || defined(SQLITE_COVERAGE_TEST) # define TESTONLY(X) X #else # define TESTONLY(X) #endif #endif /* SQLITE_AMALGAMATION */ #ifdef SQLITE_DEBUG int sqlite3Fts3Corrupt(void); # define FTS_CORRUPT_VTAB sqlite3Fts3Corrupt() #else | > > > > > | 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 | ** within testcase() and assert() macros. */ #if defined(SQLITE_DEBUG) || defined(SQLITE_COVERAGE_TEST) # define TESTONLY(X) X #else # define TESTONLY(X) #endif #define LARGEST_INT64 (0xffffffff|(((i64)0x7fffffff)<<32)) #define SMALLEST_INT64 (((i64)-1) - LARGEST_INT64) #define deliberate_fall_through #endif /* SQLITE_AMALGAMATION */ #ifdef SQLITE_DEBUG int sqlite3Fts3Corrupt(void); # define FTS_CORRUPT_VTAB sqlite3Fts3Corrupt() #else |
︙ | ︙ | |||
221 222 223 224 225 226 227 228 229 230 231 232 233 234 | char **azColumn; /* column names. malloced */ u8 *abNotindexed; /* True for 'notindexed' columns */ sqlite3_tokenizer *pTokenizer; /* tokenizer for inserts and queries */ char *zContentTbl; /* content=xxx option, or NULL */ char *zLanguageid; /* languageid=xxx option, or NULL */ int nAutoincrmerge; /* Value configured by 'automerge' */ u32 nLeafAdd; /* Number of leaf blocks added this trans */ /* Precompiled statements used by the implementation. Each of these ** statements is run and reset within a single virtual table API call. */ sqlite3_stmt *aStmt[40]; sqlite3_stmt *pSeekStmt; /* Cache for fts3CursorSeekStmt() */ | > | 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 | char **azColumn; /* column names. malloced */ u8 *abNotindexed; /* True for 'notindexed' columns */ sqlite3_tokenizer *pTokenizer; /* tokenizer for inserts and queries */ char *zContentTbl; /* content=xxx option, or NULL */ char *zLanguageid; /* languageid=xxx option, or NULL */ int nAutoincrmerge; /* Value configured by 'automerge' */ u32 nLeafAdd; /* Number of leaf blocks added this trans */ int bLock; /* Used to prevent recursive content= tbls */ /* Precompiled statements used by the implementation. Each of these ** statements is run and reset within a single virtual table API call. */ sqlite3_stmt *aStmt[40]; sqlite3_stmt *pSeekStmt; /* Cache for fts3CursorSeekStmt() */ |
︙ | ︙ | |||
279 280 281 282 283 284 285 | ** values do not contribute to FTS functionality; they are used for ** verifying the operation of the SQLite core. */ int inTransaction; /* True after xBegin but before xCommit/xRollback */ int mxSavepoint; /* Largest valid xSavepoint integer */ #endif | | > > > > > > > > > > | 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 | ** values do not contribute to FTS functionality; they are used for ** verifying the operation of the SQLite core. */ int inTransaction; /* True after xBegin but before xCommit/xRollback */ int mxSavepoint; /* Largest valid xSavepoint integer */ #endif #if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) /* True to disable the incremental doclist optimization. This is controled ** by special insert command 'test-no-incr-doclist'. */ int bNoIncrDoclist; /* Number of segments in a level */ int nMergeCount; #endif }; /* Macro to find the number of segments to merge */ #if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) # define MergeCount(P) ((P)->nMergeCount) #else # define MergeCount(P) FTS3_MERGE_COUNT #endif /* ** When the core wants to read from the virtual table, it creates a ** virtual table cursor (an instance of the following structure) using ** the xOpen method. Cursors are destroyed using the xClose method. */ struct Fts3Cursor { |
︙ | ︙ | |||
549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 | (*(u8*)(p)&0x80) ? sqlite3Fts3GetVarint32(p, piVal) : (*piVal=*(u8*)(p), 1) \ ) /* fts3.c */ void sqlite3Fts3ErrMsg(char**,const char*,...); int sqlite3Fts3PutVarint(char *, sqlite3_int64); int sqlite3Fts3GetVarint(const char *, sqlite_int64 *); int sqlite3Fts3GetVarint32(const char *, int *); int sqlite3Fts3VarintLen(sqlite3_uint64); void sqlite3Fts3Dequote(char *); void sqlite3Fts3DoclistPrev(int,char*,int,char**,sqlite3_int64*,int*,u8*); int sqlite3Fts3EvalPhraseStats(Fts3Cursor *, Fts3Expr *, u32 *); int sqlite3Fts3FirstFilter(sqlite3_int64, char *, int, char *); void sqlite3Fts3CreateStatTable(int*, Fts3Table*); int sqlite3Fts3EvalTestDeferred(Fts3Cursor *pCsr, int *pRc); /* fts3_tokenizer.c */ const char *sqlite3Fts3NextToken(const char *, int *); int sqlite3Fts3InitHashTable(sqlite3 *, Fts3Hash *, const char *); int sqlite3Fts3InitTokenizer(Fts3Hash *pHash, const char *, sqlite3_tokenizer **, char ** ); | > > > | 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 | (*(u8*)(p)&0x80) ? sqlite3Fts3GetVarint32(p, piVal) : (*piVal=*(u8*)(p), 1) \ ) /* fts3.c */ void sqlite3Fts3ErrMsg(char**,const char*,...); int sqlite3Fts3PutVarint(char *, sqlite3_int64); int sqlite3Fts3GetVarint(const char *, sqlite_int64 *); int sqlite3Fts3GetVarintU(const char *, sqlite_uint64 *); int sqlite3Fts3GetVarintBounded(const char*,const char*,sqlite3_int64*); int sqlite3Fts3GetVarint32(const char *, int *); int sqlite3Fts3VarintLen(sqlite3_uint64); void sqlite3Fts3Dequote(char *); void sqlite3Fts3DoclistPrev(int,char*,int,char**,sqlite3_int64*,int*,u8*); int sqlite3Fts3EvalPhraseStats(Fts3Cursor *, Fts3Expr *, u32 *); int sqlite3Fts3FirstFilter(sqlite3_int64, char *, int, char *); void sqlite3Fts3CreateStatTable(int*, Fts3Table*); int sqlite3Fts3EvalTestDeferred(Fts3Cursor *pCsr, int *pRc); int sqlite3Fts3ReadInt(const char *z, int *pnOut); /* fts3_tokenizer.c */ const char *sqlite3Fts3NextToken(const char *, int *); int sqlite3Fts3InitHashTable(sqlite3 *, Fts3Hash *, const char *); int sqlite3Fts3InitTokenizer(Fts3Hash *pHash, const char *, sqlite3_tokenizer **, char ** ); |
︙ | ︙ | |||
583 584 585 586 587 588 589 590 591 592 593 594 595 596 | char **, int, int, int, const char *, int, Fts3Expr **, char ** ); void sqlite3Fts3ExprFree(Fts3Expr *); #ifdef SQLITE_TEST int sqlite3Fts3ExprInitTestInterface(sqlite3 *db, Fts3Hash*); int sqlite3Fts3InitTerm(sqlite3 *db); #endif int sqlite3Fts3OpenTokenizer(sqlite3_tokenizer *, int, const char *, int, sqlite3_tokenizer_cursor ** ); /* fts3_aux.c */ int sqlite3Fts3InitAux(sqlite3 *db); | > | 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 | char **, int, int, int, const char *, int, Fts3Expr **, char ** ); void sqlite3Fts3ExprFree(Fts3Expr *); #ifdef SQLITE_TEST int sqlite3Fts3ExprInitTestInterface(sqlite3 *db, Fts3Hash*); int sqlite3Fts3InitTerm(sqlite3 *db); #endif void *sqlite3Fts3MallocZero(i64 nByte); int sqlite3Fts3OpenTokenizer(sqlite3_tokenizer *, int, const char *, int, sqlite3_tokenizer_cursor ** ); /* fts3_aux.c */ int sqlite3Fts3InitAux(sqlite3 *db); |
︙ | ︙ |
Changes to ext/fts3/fts3_aux.c.
︙ | ︙ | |||
62 63 64 65 66 67 68 | sqlite3_vtab **ppVtab, /* OUT: New sqlite3_vtab object */ char **pzErr /* OUT: sqlite3_malloc'd error message */ ){ char const *zDb; /* Name of database (e.g. "main") */ char const *zFts3; /* Name of fts3 table */ int nDb; /* Result of strlen(zDb) */ int nFts3; /* Result of strlen(zFts3) */ | | | 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 | sqlite3_vtab **ppVtab, /* OUT: New sqlite3_vtab object */ char **pzErr /* OUT: sqlite3_malloc'd error message */ ){ char const *zDb; /* Name of database (e.g. "main") */ char const *zFts3; /* Name of fts3 table */ int nDb; /* Result of strlen(zDb) */ int nFts3; /* Result of strlen(zFts3) */ sqlite3_int64 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: ** |
︙ | ︙ | |||
94 95 96 97 98 99 100 | } nFts3 = (int)strlen(zFts3); rc = sqlite3_declare_vtab(db, FTS3_AUX_SCHEMA); if( rc!=SQLITE_OK ) return rc; nByte = sizeof(Fts3auxTable) + sizeof(Fts3Table) + nDb + nFts3 + 2; | | | 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 | } nFts3 = (int)strlen(zFts3); rc = sqlite3_declare_vtab(db, FTS3_AUX_SCHEMA); if( rc!=SQLITE_OK ) return rc; nByte = sizeof(Fts3auxTable) + sizeof(Fts3Table) + nDb + nFts3 + 2; p = (Fts3auxTable *)sqlite3_malloc64(nByte); if( !p ) return SQLITE_NOMEM; memset(p, 0, nByte); p->pFts3Tab = (Fts3Table *)&p[1]; p->pFts3Tab->zDb = (char *)&p->pFts3Tab[1]; p->pFts3Tab->zName = &p->pFts3Tab->zDb[nDb+1]; p->pFts3Tab->db = db; |
︙ | ︙ | |||
244 245 246 247 248 249 250 | sqlite3_free(pCsr); return SQLITE_OK; } static int fts3auxGrowStatArray(Fts3auxCursor *pCsr, int nSize){ if( nSize>pCsr->nStat ){ struct Fts3auxColstats *aNew; | | | 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 | sqlite3_free(pCsr); return SQLITE_OK; } static int fts3auxGrowStatArray(Fts3auxCursor *pCsr, int nSize){ if( nSize>pCsr->nStat ){ struct Fts3auxColstats *aNew; aNew = (struct Fts3auxColstats *)sqlite3_realloc64(pCsr->aStat, sizeof(struct Fts3auxColstats) * nSize ); if( aNew==0 ) return SQLITE_NOMEM; memset(&aNew[pCsr->nStat], 0, sizeof(struct Fts3auxColstats) * (nSize - pCsr->nStat) ); pCsr->aStat = aNew; |
︙ | ︙ | |||
293 294 295 296 297 298 299 300 301 302 303 304 305 306 | return SQLITE_OK; } } if( fts3auxGrowStatArray(pCsr, 2) ) return SQLITE_NOMEM; memset(pCsr->aStat, 0, sizeof(struct Fts3auxColstats) * pCsr->nStat); iCol = 0; while( i<nDoclist ){ sqlite3_int64 v = 0; i += sqlite3Fts3GetVarint(&aDoclist[i], &v); switch( eState ){ /* State 0. In this state the integer just read was a docid. */ | > | 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 | return SQLITE_OK; } } if( fts3auxGrowStatArray(pCsr, 2) ) return SQLITE_NOMEM; memset(pCsr->aStat, 0, sizeof(struct Fts3auxColstats) * pCsr->nStat); iCol = 0; rc = SQLITE_OK; while( i<nDoclist ){ sqlite3_int64 v = 0; i += sqlite3Fts3GetVarint(&aDoclist[i], &v); switch( eState ){ /* State 0. In this state the integer just read was a docid. */ |
︙ | ︙ | |||
336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 | pCsr->aStat[0].nOcc++; } break; /* State 3. The integer just read is a column number. */ default: assert( eState==3 ); iCol = (int)v; if( fts3auxGrowStatArray(pCsr, iCol+2) ) return SQLITE_NOMEM; pCsr->aStat[iCol+1].nDoc++; eState = 2; break; } } pCsr->iCol = 0; | > > > > < | 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 | pCsr->aStat[0].nOcc++; } break; /* State 3. The integer just read is a column number. */ default: assert( eState==3 ); iCol = (int)v; if( iCol<1 ){ rc = SQLITE_CORRUPT_VTAB; break; } if( fts3auxGrowStatArray(pCsr, iCol+2) ) return SQLITE_NOMEM; pCsr->aStat[iCol+1].nDoc++; eState = 2; break; } } pCsr->iCol = 0; }else{ pCsr->isEof = 1; } return rc; } /* |
︙ | ︙ | |||
402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 | } /* In case this cursor is being reused, close and zero it. */ testcase(pCsr->filter.zTerm); sqlite3Fts3SegReaderFinish(&pCsr->csr); sqlite3_free((void *)pCsr->filter.zTerm); sqlite3_free(pCsr->aStat); memset(&pCsr->csr, 0, ((u8*)&pCsr[1]) - (u8*)&pCsr->csr); pCsr->filter.flags = FTS3_SEGMENT_REQUIRE_POS|FTS3_SEGMENT_IGNORE_EMPTY; if( isScan ) pCsr->filter.flags |= FTS3_SEGMENT_SCAN; if( iEq>=0 || iGe>=0 ){ const unsigned char *zStr = sqlite3_value_text(apVal[0]); assert( (iEq==0 && iGe==-1) || (iEq==-1 && iGe==0) ); if( zStr ){ pCsr->filter.zTerm = sqlite3_mprintf("%s", zStr); | > < > < > | 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 | } /* In case this cursor is being reused, close and zero it. */ testcase(pCsr->filter.zTerm); sqlite3Fts3SegReaderFinish(&pCsr->csr); sqlite3_free((void *)pCsr->filter.zTerm); sqlite3_free(pCsr->aStat); sqlite3_free(pCsr->zStop); memset(&pCsr->csr, 0, ((u8*)&pCsr[1]) - (u8*)&pCsr->csr); pCsr->filter.flags = FTS3_SEGMENT_REQUIRE_POS|FTS3_SEGMENT_IGNORE_EMPTY; if( isScan ) pCsr->filter.flags |= FTS3_SEGMENT_SCAN; if( iEq>=0 || iGe>=0 ){ const unsigned char *zStr = sqlite3_value_text(apVal[0]); assert( (iEq==0 && iGe==-1) || (iEq==-1 && iGe==0) ); if( zStr ){ pCsr->filter.zTerm = sqlite3_mprintf("%s", zStr); if( pCsr->filter.zTerm==0 ) return SQLITE_NOMEM; pCsr->filter.nTerm = (int)strlen(pCsr->filter.zTerm); } } if( iLe>=0 ){ pCsr->zStop = sqlite3_mprintf("%s", sqlite3_value_text(apVal[iLe])); if( pCsr->zStop==0 ) return SQLITE_NOMEM; pCsr->nStop = (int)strlen(pCsr->zStop); } if( iLangid>=0 ){ iLangVal = sqlite3_value_int(apVal[iLangid]); /* If the user specified a negative value for the languageid, use zero ** instead. This works, as the "languageid=?" constraint will also |
︙ | ︙ |
Changes to ext/fts3/fts3_expr.c.
︙ | ︙ | |||
118 119 120 121 122 123 124 | } /* ** Allocate nByte bytes of memory using sqlite3_malloc(). If successful, ** zero the memory before returning a pointer to it. If unsuccessful, ** return NULL. */ | | | | 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 | } /* ** Allocate nByte bytes of memory using sqlite3_malloc(). If successful, ** zero the memory before returning a pointer to it. If unsuccessful, ** return NULL. */ void *sqlite3Fts3MallocZero(sqlite3_int64 nByte){ void *pRet = sqlite3_malloc64(nByte); if( pRet ) memset(pRet, 0, nByte); return pRet; } int sqlite3Fts3OpenTokenizer( sqlite3_tokenizer *pTokenizer, int iLangid, |
︙ | ︙ | |||
194 195 196 197 198 199 200 | } *pnConsumed = i; rc = sqlite3Fts3OpenTokenizer(pTokenizer, pParse->iLangid, z, i, &pCursor); if( rc==SQLITE_OK ){ const char *zToken; int nToken = 0, iStart = 0, iEnd = 0, iPosition = 0; | | | | 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 | } *pnConsumed = i; rc = sqlite3Fts3OpenTokenizer(pTokenizer, pParse->iLangid, z, i, &pCursor); if( rc==SQLITE_OK ){ const char *zToken; int nToken = 0, iStart = 0, iEnd = 0, iPosition = 0; sqlite3_int64 nByte; /* total space to allocate */ rc = pModule->xNext(pCursor, &zToken, &nToken, &iStart, &iEnd, &iPosition); if( rc==SQLITE_OK ){ nByte = sizeof(Fts3Expr) + sizeof(Fts3Phrase) + nToken; pRet = (Fts3Expr *)sqlite3Fts3MallocZero(nByte); if( !pRet ){ rc = SQLITE_NOMEM; }else{ pRet->eType = FTSQUERY_PHRASE; pRet->pPhrase = (Fts3Phrase *)&pRet[1]; pRet->pPhrase->nToken = 1; pRet->pPhrase->iColumn = iCol; |
︙ | ︙ | |||
248 249 250 251 252 253 254 | } /* ** Enlarge a memory allocation. If an out-of-memory allocation occurs, ** then free the old allocation. */ | | | | 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 | } /* ** Enlarge a memory allocation. If an out-of-memory allocation occurs, ** then free the old allocation. */ static void *fts3ReallocOrFree(void *pOrig, sqlite3_int64 nNew){ void *pRet = sqlite3_realloc64(pOrig, nNew); if( !pRet ){ sqlite3_free(pOrig); } return pRet; } /* |
︙ | ︙ | |||
442 443 444 445 446 447 448 | int nKey = pKey->n; char cNext; /* If this is a "NEAR" keyword, check for an explicit nearness. */ if( pKey->eType==FTSQUERY_NEAR ){ assert( nKey==4 ); if( zInput[4]=='/' && zInput[5]>='0' && zInput[5]<='9' ){ | < < | < | | 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 | int nKey = pKey->n; char cNext; /* If this is a "NEAR" keyword, check for an explicit nearness. */ if( pKey->eType==FTSQUERY_NEAR ){ assert( nKey==4 ); if( zInput[4]=='/' && zInput[5]>='0' && zInput[5]<='9' ){ nKey += 1+sqlite3Fts3ReadInt(&zInput[nKey+1], &nNear); } } /* At this point this is probably a keyword. But for that to be true, ** the next byte must contain either whitespace, an open or close ** parenthesis, a quote character, or EOF. */ cNext = zInput[nKey]; if( fts3isspace(cNext) || cNext=='"' || cNext=='(' || cNext==')' || cNext==0 ){ pRet = (Fts3Expr *)sqlite3Fts3MallocZero(sizeof(Fts3Expr)); if( !pRet ){ return SQLITE_NOMEM; } pRet->eType = pKey->eType; pRet->nNear = nNear; *ppExpr = pRet; *pnConsumed = (int)((zInput - z) + nKey); |
︙ | ︙ | |||
492 493 494 495 496 497 498 499 | return getNextString(pParse, &zInput[1], ii-1, ppExpr); } if( sqlite3_fts3_enable_parentheses ){ if( *zInput=='(' ){ int nConsumed = 0; pParse->nNest++; rc = fts3ExprParse(pParse, zInput+1, nInput-1, ppExpr, &nConsumed); | > > > > > < | 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 | return getNextString(pParse, &zInput[1], ii-1, ppExpr); } if( sqlite3_fts3_enable_parentheses ){ if( *zInput=='(' ){ int nConsumed = 0; pParse->nNest++; #if !defined(SQLITE_MAX_EXPR_DEPTH) if( pParse->nNest>1000 ) return SQLITE_ERROR; #elif SQLITE_MAX_EXPR_DEPTH>0 if( pParse->nNest>SQLITE_MAX_EXPR_DEPTH ) return SQLITE_ERROR; #endif rc = fts3ExprParse(pParse, zInput+1, nInput-1, ppExpr, &nConsumed); *pnConsumed = (int)(zInput - z) + 1 + nConsumed; return rc; }else if( *zInput==')' ){ pParse->nNest--; *pnConsumed = (int)((zInput - z) + 1); *ppExpr = 0; return SQLITE_DONE; |
︙ | ︙ | |||
632 633 634 635 636 637 638 | if( p ){ int isPhrase; if( !sqlite3_fts3_enable_parentheses && p->eType==FTSQUERY_PHRASE && pParse->isNot ){ /* Create an implicit NOT operator. */ | | | 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 | if( p ){ int isPhrase; if( !sqlite3_fts3_enable_parentheses && p->eType==FTSQUERY_PHRASE && pParse->isNot ){ /* Create an implicit NOT operator. */ Fts3Expr *pNot = sqlite3Fts3MallocZero(sizeof(Fts3Expr)); if( !pNot ){ sqlite3Fts3ExprFree(p); rc = SQLITE_NOMEM; goto exprparse_out; } pNot->eType = FTSQUERY_NOT; pNot->pRight = p; |
︙ | ︙ | |||
666 667 668 669 670 671 672 | goto exprparse_out; } if( isPhrase && !isRequirePhrase ){ /* Insert an implicit AND operator. */ Fts3Expr *pAnd; assert( pRet && pPrev ); | | | 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 | goto exprparse_out; } if( isPhrase && !isRequirePhrase ){ /* Insert an implicit AND operator. */ Fts3Expr *pAnd; assert( pRet && pPrev ); pAnd = sqlite3Fts3MallocZero(sizeof(Fts3Expr)); if( !pAnd ){ sqlite3Fts3ExprFree(p); rc = SQLITE_NOMEM; goto exprparse_out; } pAnd->eType = FTSQUERY_AND; insertBinaryOperator(&pRet, pPrev, pAnd); |
︙ | ︙ | |||
792 793 794 795 796 797 798 | if( nMaxDepth==0 ){ rc = SQLITE_ERROR; } if( rc==SQLITE_OK ){ if( (eType==FTSQUERY_AND || eType==FTSQUERY_OR) ){ Fts3Expr **apLeaf; | | | 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 | if( nMaxDepth==0 ){ rc = SQLITE_ERROR; } if( rc==SQLITE_OK ){ if( (eType==FTSQUERY_AND || eType==FTSQUERY_OR) ){ Fts3Expr **apLeaf; apLeaf = (Fts3Expr **)sqlite3_malloc64(sizeof(Fts3Expr *) * nMaxDepth); if( 0==apLeaf ){ rc = SQLITE_NOMEM; }else{ memset(apLeaf, 0, sizeof(Fts3Expr *) * nMaxDepth); } if( rc==SQLITE_OK ){ |
︙ | ︙ | |||
1212 1213 1214 1215 1216 1217 1218 | sqlite3_free(zErr); return; } zExpr = (const char *)sqlite3_value_text(argv[1]); nExpr = sqlite3_value_bytes(argv[1]); nCol = argc-2; | | | 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 | sqlite3_free(zErr); return; } zExpr = (const char *)sqlite3_value_text(argv[1]); nExpr = sqlite3_value_bytes(argv[1]); nCol = argc-2; azCol = (char **)sqlite3_malloc64(nCol*sizeof(char *)); if( !azCol ){ sqlite3_result_error_nomem(context); goto exprtest_out; } for(ii=0; ii<nCol; ii++){ azCol[ii] = (char *)sqlite3_value_text(argv[ii+2]); } |
︙ | ︙ |
Changes to ext/fts3/fts3_hash.c.
︙ | ︙ | |||
31 32 33 34 35 36 37 | #include <string.h> #include "fts3_hash.h" /* ** Malloc and Free functions */ | | | | 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | #include <string.h> #include "fts3_hash.h" /* ** Malloc and Free functions */ static void *fts3HashMalloc(sqlite3_int64 n){ void *p = sqlite3_malloc64(n); if( p ){ memset(p, 0, n); } return p; } static void fts3HashFree(void *p){ sqlite3_free(p); |
︙ | ︙ |
Changes to ext/fts3/fts3_icu.c.
︙ | ︙ | |||
56 57 58 59 60 61 62 | ){ IcuTokenizer *p; int n = 0; if( argc>0 ){ n = strlen(argv[0])+1; } | | | 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | ){ IcuTokenizer *p; int n = 0; if( argc>0 ){ n = strlen(argv[0])+1; } p = (IcuTokenizer *)sqlite3_malloc64(sizeof(IcuTokenizer)+n); if( !p ){ return SQLITE_NOMEM; } memset(p, 0, sizeof(IcuTokenizer)); if( n ){ p->zLocale = (char *)&p[1]; |
︙ | ︙ | |||
113 114 115 116 117 118 119 | if( zInput==0 ){ nInput = 0; zInput = ""; }else if( nInput<0 ){ nInput = strlen(zInput); } nChar = nInput+1; | | | 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 | if( zInput==0 ){ nInput = 0; zInput = ""; }else if( nInput<0 ){ nInput = strlen(zInput); } nChar = nInput+1; pCsr = (IcuCursor *)sqlite3_malloc64( sizeof(IcuCursor) + /* IcuCursor */ ((nChar+3)&~3) * sizeof(UChar) + /* IcuCursor.aChar[] */ (nChar+1) * sizeof(int) /* IcuCursor.aOffset[] */ ); if( !pCsr ){ return SQLITE_NOMEM; } |
︙ | ︙ |
Changes to ext/fts3/fts3_snippet.c.
︙ | ︙ | |||
13 14 15 16 17 18 19 20 21 22 23 24 25 26 | #include "fts3Int.h" #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) #include <string.h> #include <assert.h> /* ** Characters that may appear in the second argument to matchinfo(). */ #define FTS3_MATCHINFO_NPHRASE 'p' /* 1 value */ #define FTS3_MATCHINFO_NCOL 'c' /* 1 value */ #define FTS3_MATCHINFO_NDOC 'n' /* 1 value */ #define FTS3_MATCHINFO_AVGLENGTH 'a' /* nCol values */ | > > > > | 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | #include "fts3Int.h" #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) #include <string.h> #include <assert.h> #ifndef SQLITE_AMALGAMATION typedef sqlite3_int64 i64; #endif /* ** Characters that may appear in the second argument to matchinfo(). */ #define FTS3_MATCHINFO_NPHRASE 'p' /* 1 value */ #define FTS3_MATCHINFO_NCOL 'c' /* 1 value */ #define FTS3_MATCHINFO_NDOC 'n' /* 1 value */ #define FTS3_MATCHINFO_AVGLENGTH 'a' /* nCol values */ |
︙ | ︙ | |||
63 64 65 66 67 68 69 | SnippetPhrase *aPhrase; /* Array of size nPhrase */ int iCurrent; /* First token of current snippet */ }; struct SnippetPhrase { int nToken; /* Number of tokens in phrase */ char *pList; /* Pointer to start of phrase position list */ | | | | 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | SnippetPhrase *aPhrase; /* Array of size nPhrase */ int iCurrent; /* First token of current snippet */ }; struct SnippetPhrase { int nToken; /* Number of tokens in phrase */ char *pList; /* Pointer to start of phrase position list */ i64 iHead; /* Next value in position list */ char *pHead; /* Position list data following iHead */ i64 iTail; /* Next value in trailing position list */ char *pTail; /* Position list data following iTail */ }; struct SnippetFragment { int iCol; /* Column snippet is extracted from */ int iPos; /* Index of first token in snippet */ u64 covered; /* Mask of query phrases covered */ |
︙ | ︙ | |||
124 125 126 127 128 129 130 | /************************************************************************* ** Start of MatchinfoBuffer code. */ /* ** Allocate a two-slot MatchinfoBuffer object. */ | | > | | | < | > | | 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 | /************************************************************************* ** Start of MatchinfoBuffer code. */ /* ** Allocate a two-slot MatchinfoBuffer object. */ static MatchinfoBuffer *fts3MIBufferNew(size_t nElem, const char *zMatchinfo){ MatchinfoBuffer *pRet; sqlite3_int64 nByte = sizeof(u32) * (2*(sqlite3_int64)nElem + 1) + sizeof(MatchinfoBuffer); sqlite3_int64 nStr = strlen(zMatchinfo); pRet = sqlite3Fts3MallocZero(nByte + nStr+1); if( pRet ){ pRet->aMatchinfo[0] = (u8*)(&pRet->aMatchinfo[1]) - (u8*)pRet; pRet->aMatchinfo[1+nElem] = pRet->aMatchinfo[0] + sizeof(u32)*((int)nElem+1); pRet->nElem = (int)nElem; pRet->zMatchinfo = ((char*)pRet) + nByte; memcpy(pRet->zMatchinfo, zMatchinfo, nStr+1); pRet->aRef[0] = 1; } return pRet; } |
︙ | ︙ | |||
174 175 176 177 178 179 180 | xRet = fts3MIBufferFree; } else if( p->aRef[2]==0 ){ p->aRef[2] = 1; aOut = &p->aMatchinfo[p->nElem+2]; xRet = fts3MIBufferFree; }else{ | | | 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 | xRet = fts3MIBufferFree; } else if( p->aRef[2]==0 ){ p->aRef[2] = 1; aOut = &p->aMatchinfo[p->nElem+2]; xRet = fts3MIBufferFree; }else{ aOut = (u32*)sqlite3_malloc64(p->nElem * sizeof(u32)); if( aOut ){ xRet = sqlite3_free; if( p->bGlobal ) memcpy(aOut, &p->aMatchinfo[1], p->nElem*sizeof(u32)); } } *paOut = aOut; |
︙ | ︙ | |||
228 229 230 231 232 233 234 | ** are encoded. ** ** When this function is called, *pp points to the start of an element of ** the list. *piPos contains the value of the previous entry in the list. ** After it returns, *piPos contains the value of the next element of the ** list and *pp is advanced to the following varint. */ | | | 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 | ** are encoded. ** ** When this function is called, *pp points to the start of an element of ** the list. *piPos contains the value of the previous entry in the list. ** After it returns, *piPos contains the value of the next element of the ** list and *pp is advanced to the following varint. */ static void fts3GetDeltaPosition(char **pp, i64 *piPos){ int iVal; *pp += fts3GetVarint32(*pp, &iVal); *piPos += (iVal-2); } /* ** Helper function for fts3ExprIterate() (see below). |
︙ | ︙ | |||
337 338 339 340 341 342 343 | } /* ** Advance the position list iterator specified by the first two ** arguments so that it points to the first element with a value greater ** than or equal to parameter iNext. */ | | | | 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 | } /* ** Advance the position list iterator specified by the first two ** arguments so that it points to the first element with a value greater ** than or equal to parameter iNext. */ static void fts3SnippetAdvance(char **ppIter, i64 *piIter, int iNext){ char *pIter = *ppIter; if( pIter ){ i64 iIter = *piIter; while( iIter<iNext ){ if( 0==(*pIter & 0xFE) ){ iIter = -1; pIter = 0; break; } |
︙ | ︙ | |||
423 424 425 426 427 428 429 | u64 mCover = 0; /* Mask of phrases covered by this snippet */ u64 mHighlight = 0; /* Mask of tokens to highlight in snippet */ for(i=0; i<pIter->nPhrase; i++){ SnippetPhrase *pPhrase = &pIter->aPhrase[i]; if( pPhrase->pTail ){ char *pCsr = pPhrase->pTail; | | | | | > | 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 | u64 mCover = 0; /* Mask of phrases covered by this snippet */ u64 mHighlight = 0; /* Mask of tokens to highlight in snippet */ for(i=0; i<pIter->nPhrase; i++){ SnippetPhrase *pPhrase = &pIter->aPhrase[i]; if( pPhrase->pTail ){ char *pCsr = pPhrase->pTail; i64 iCsr = pPhrase->iTail; while( iCsr<(iStart+pIter->nSnippet) && iCsr>=iStart ){ int j; u64 mPhrase = (u64)1 << (i%64); u64 mPos = (u64)1 << (iCsr - iStart); assert( iCsr>=iStart && (iCsr - iStart)<=64 ); assert( i>=0 ); if( (mCover|mCovered)&mPhrase ){ iScore++; }else{ iScore += 1000; } mCover |= mPhrase; |
︙ | ︙ | |||
468 469 470 471 472 473 474 | char *pCsr; int rc; pPhrase->nToken = pExpr->pPhrase->nToken; rc = sqlite3Fts3EvalPhrasePoslist(p->pCsr, pExpr, p->iCol, &pCsr); assert( rc==SQLITE_OK || pCsr==0 ); if( pCsr ){ | | | > > | | | | > | 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 | char *pCsr; int rc; pPhrase->nToken = pExpr->pPhrase->nToken; rc = sqlite3Fts3EvalPhrasePoslist(p->pCsr, pExpr, p->iCol, &pCsr); assert( rc==SQLITE_OK || pCsr==0 ); if( pCsr ){ i64 iFirst = 0; pPhrase->pList = pCsr; fts3GetDeltaPosition(&pCsr, &iFirst); if( iFirst<0 ){ rc = FTS_CORRUPT_VTAB; }else{ pPhrase->pHead = pCsr; pPhrase->pTail = pCsr; pPhrase->iHead = iFirst; pPhrase->iTail = iFirst; } }else{ assert( rc!=SQLITE_OK || ( pPhrase->pList==0 && pPhrase->pHead==0 && pPhrase->pTail==0 )); } return rc; |
︙ | ︙ | |||
512 513 514 515 516 517 518 | u64 *pmSeen, /* IN/OUT: Mask of phrases seen */ SnippetFragment *pFragment, /* OUT: Best snippet found */ int *piScore /* OUT: Score of snippet pFragment */ ){ int rc; /* Return Code */ int nList; /* Number of phrases in expression */ SnippetIter sIter; /* Iterates through snippet candidates */ | | | < | | 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 | u64 *pmSeen, /* IN/OUT: Mask of phrases seen */ SnippetFragment *pFragment, /* OUT: Best snippet found */ int *piScore /* OUT: Score of snippet pFragment */ ){ int rc; /* Return Code */ int nList; /* Number of phrases in expression */ SnippetIter sIter; /* Iterates through snippet candidates */ sqlite3_int64 nByte; /* Number of bytes of space to allocate */ int iBestScore = -1; /* Best snippet score found so far */ int i; /* Loop counter */ memset(&sIter, 0, sizeof(sIter)); /* Iterate through the phrases in the expression to count them. The same ** callback makes sure the doclists are loaded for each phrase. */ rc = fts3ExprLoadDoclists(pCsr, &nList, 0); if( rc!=SQLITE_OK ){ return rc; } /* Now that it is known how many phrases there are, allocate and zero ** the required space using malloc(). */ nByte = sizeof(SnippetPhrase) * nList; sIter.aPhrase = (SnippetPhrase *)sqlite3Fts3MallocZero(nByte); if( !sIter.aPhrase ){ return SQLITE_NOMEM; } /* Initialize the contents of the SnippetIter object. Then iterate through ** the set of phrases in the expression to populate the aPhrase[] array. */ sIter.pCsr = pCsr; sIter.iCol = iCol; sIter.nSnippet = nSnippet; sIter.nPhrase = nList; sIter.iCurrent = -1; rc = fts3ExprIterate(pCsr->pExpr, fts3SnippetFindPositions, (void*)&sIter); if( rc==SQLITE_OK ){ /* Set the *pmSeen output variable. */ for(i=0; i<nList; i++){ if( sIter.aPhrase[i].pHead ){ *pmSeen |= (u64)1 << (i%64); } } /* Loop through all candidate snippets. Store the best snippet in ** *pFragment. Store its associated 'score' in iBestScore. */ pFragment->iCol = iCol; |
︙ | ︙ | |||
600 601 602 603 604 605 606 | } /* If there is insufficient space allocated at StrBuffer.z, use realloc() ** to grow the buffer until so that it is big enough to accomadate the ** appended data. */ if( pStr->n+nAppend+1>=pStr->nAlloc ){ | | | | 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 | } /* If there is insufficient space allocated at StrBuffer.z, use realloc() ** to grow the buffer until so that it is big enough to accomadate the ** appended data. */ if( pStr->n+nAppend+1>=pStr->nAlloc ){ sqlite3_int64 nAlloc = pStr->nAlloc+(sqlite3_int64)nAppend+100; char *zNew = sqlite3_realloc64(pStr->z, nAlloc); if( !zNew ){ return SQLITE_NOMEM; } pStr->z = zNew; pStr->nAlloc = nAlloc; } assert( pStr->z!=0 && (pStr->nAlloc >= pStr->n+nAppend+1) ); |
︙ | ︙ | |||
656 657 658 659 660 661 662 663 664 665 666 667 668 669 | if( hlmask ){ int nLeft; /* Tokens to the left of first highlight */ int nRight; /* Tokens to the right of last highlight */ int nDesired; /* Ideal number of tokens to shift forward */ for(nLeft=0; !(hlmask & ((u64)1 << nLeft)); nLeft++); for(nRight=0; !(hlmask & ((u64)1 << (nSnippet-1-nRight))); nRight++); nDesired = (nLeft-nRight)/2; /* Ideally, the start of the snippet should be pushed forward in the ** document nDesired tokens. This block checks if there are actually ** nDesired tokens to the right of the snippet. If so, *piPos and ** *pHlMask are updated to shift the snippet nDesired tokens to the ** right. Otherwise, the snippet is shifted by the number of tokens | > | 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 | if( hlmask ){ int nLeft; /* Tokens to the left of first highlight */ int nRight; /* Tokens to the right of last highlight */ int nDesired; /* Ideal number of tokens to shift forward */ for(nLeft=0; !(hlmask & ((u64)1 << nLeft)); nLeft++); for(nRight=0; !(hlmask & ((u64)1 << (nSnippet-1-nRight))); nRight++); assert( (nSnippet-1-nRight)<=63 && (nSnippet-1-nRight)>=0 ); nDesired = (nLeft-nRight)/2; /* Ideally, the start of the snippet should be pushed forward in the ** document nDesired tokens. This block checks if there are actually ** nDesired tokens to the right of the snippet. If so, *piPos and ** *pHlMask are updated to shift the snippet nDesired tokens to the ** right. Otherwise, the snippet is shifted by the number of tokens |
︙ | ︙ | |||
848 849 850 851 852 853 854 | *ppCollist = pEnd; return nEntry; } /* ** This function gathers 'y' or 'b' data for a single phrase. */ | | | > > | > | | | > | 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 | *ppCollist = pEnd; return nEntry; } /* ** This function gathers 'y' or 'b' data for a single phrase. */ static int fts3ExprLHits( Fts3Expr *pExpr, /* Phrase expression node */ MatchInfo *p /* Matchinfo context */ ){ Fts3Table *pTab = (Fts3Table *)p->pCursor->base.pVtab; int iStart; Fts3Phrase *pPhrase = pExpr->pPhrase; char *pIter = pPhrase->doclist.pList; int iCol = 0; assert( p->flag==FTS3_MATCHINFO_LHITS_BM || p->flag==FTS3_MATCHINFO_LHITS ); if( p->flag==FTS3_MATCHINFO_LHITS ){ iStart = pExpr->iPhrase * p->nCol; }else{ iStart = pExpr->iPhrase * ((p->nCol + 31) / 32); } if( pIter ) while( 1 ){ int nHit = fts3ColumnlistCount(&pIter); if( (pPhrase->iColumn>=pTab->nColumn || pPhrase->iColumn==iCol) ){ if( p->flag==FTS3_MATCHINFO_LHITS ){ p->aMatchinfo[iStart + iCol] = (u32)nHit; }else if( nHit ){ p->aMatchinfo[iStart + (iCol+1)/32] |= (1 << (iCol&0x1F)); } } assert( *pIter==0x00 || *pIter==0x01 ); if( *pIter!=0x01 ) break; pIter++; pIter += fts3GetVarint32(pIter, &iCol); if( iCol>=p->nCol ) return FTS_CORRUPT_VTAB; } return SQLITE_OK; } /* ** Gather the results for matchinfo directives 'y' and 'b'. */ static int fts3ExprLHitGather( Fts3Expr *pExpr, MatchInfo *p ){ int rc = SQLITE_OK; assert( (pExpr->pLeft==0)==(pExpr->pRight==0) ); if( pExpr->bEof==0 && pExpr->iDocid==p->pCursor->iPrevId ){ if( pExpr->pLeft ){ rc = fts3ExprLHitGather(pExpr->pLeft, p); if( rc==SQLITE_OK ) rc = fts3ExprLHitGather(pExpr->pRight, p); }else{ rc = fts3ExprLHits(pExpr, p); } } return rc; } /* ** fts3ExprIterate() callback used to collect the "global" matchinfo stats ** for a single query. ** ** fts3ExprIterate() callback to load the 'global' elements of a |
︙ | ︙ | |||
986 987 988 989 990 991 992 | ){ return SQLITE_OK; } sqlite3Fts3ErrMsg(pzErr, "unrecognized matchinfo request: %c", cArg); return SQLITE_ERROR; } | | | | 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 | ){ return SQLITE_OK; } sqlite3Fts3ErrMsg(pzErr, "unrecognized matchinfo request: %c", cArg); return SQLITE_ERROR; } static size_t fts3MatchinfoSize(MatchInfo *pInfo, char cArg){ size_t nVal; /* Number of integers output by cArg */ switch( cArg ){ case FTS3_MATCHINFO_NDOC: case FTS3_MATCHINFO_NPHRASE: case FTS3_MATCHINFO_NCOL: nVal = 1; break; |
︙ | ︙ | |||
1023 1024 1025 1026 1027 1028 1029 | return nVal; } static int fts3MatchinfoSelectDoctotal( Fts3Table *pTab, sqlite3_stmt **ppStmt, sqlite3_int64 *pnDoc, | | > > > > > > > > > | > | > | > | 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 | return nVal; } static int fts3MatchinfoSelectDoctotal( Fts3Table *pTab, sqlite3_stmt **ppStmt, sqlite3_int64 *pnDoc, const char **paLen, const char **ppEnd ){ sqlite3_stmt *pStmt; const char *a; const char *pEnd; sqlite3_int64 nDoc; int n; if( !*ppStmt ){ int rc = sqlite3Fts3SelectDoctotal(pTab, ppStmt); if( rc!=SQLITE_OK ) return rc; } pStmt = *ppStmt; assert( sqlite3_data_count(pStmt)==1 ); n = sqlite3_column_bytes(pStmt, 0); a = sqlite3_column_blob(pStmt, 0); if( a==0 ){ return FTS_CORRUPT_VTAB; } pEnd = a + n; a += sqlite3Fts3GetVarintBounded(a, pEnd, &nDoc); if( nDoc<=0 || a>pEnd ){ return FTS_CORRUPT_VTAB; } *pnDoc = nDoc; if( paLen ) *paLen = a; if( ppEnd ) *ppEnd = pEnd; return SQLITE_OK; } /* ** An instance of the following structure is used to store state while ** iterating through a multi-column position-list corresponding to the ** hits for a single phrase on a single row in order to calculate the |
︙ | ︙ | |||
1081 1082 1083 1084 1085 1086 1087 | /* ** Advance the iterator passed as an argument to the next position. Return ** 1 if the iterator is at EOF or if it now points to the start of the ** position list for the next column. */ static int fts3LcsIteratorAdvance(LcsIterator *pIter){ | | > > | 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 | /* ** Advance the iterator passed as an argument to the next position. Return ** 1 if the iterator is at EOF or if it now points to the start of the ** position list for the next column. */ static int fts3LcsIteratorAdvance(LcsIterator *pIter){ char *pRead; sqlite3_int64 iRead; int rc = 0; if( NEVER(pIter==0) ) return 1; pRead = pIter->pRead; pRead += sqlite3Fts3GetVarint(pRead, &iRead); if( iRead==0 || iRead==1 ){ pRead = 0; rc = 1; }else{ pIter->iPos += (int)(iRead-2); } |
︙ | ︙ | |||
1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 | ** undefined. */ static int fts3MatchinfoLcs(Fts3Cursor *pCsr, MatchInfo *pInfo){ LcsIterator *aIter; int i; int iCol; int nToken = 0; /* Allocate and populate the array of LcsIterator objects. The array ** contains one element for each matchable phrase in the query. **/ | > | < < | | > > > > | 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 | ** undefined. */ static int fts3MatchinfoLcs(Fts3Cursor *pCsr, MatchInfo *pInfo){ LcsIterator *aIter; int i; int iCol; int nToken = 0; int rc = SQLITE_OK; /* Allocate and populate the array of LcsIterator objects. The array ** contains one element for each matchable phrase in the query. **/ aIter = sqlite3Fts3MallocZero(sizeof(LcsIterator) * pCsr->nPhrase); if( !aIter ) return SQLITE_NOMEM; (void)fts3ExprIterate(pCsr->pExpr, fts3MatchinfoLcsCb, (void*)aIter); for(i=0; i<pInfo->nPhrase; i++){ LcsIterator *pIter = &aIter[i]; nToken -= pIter->pExpr->pPhrase->nToken; pIter->iPosOffset = nToken; } for(iCol=0; iCol<pInfo->nCol; iCol++){ int nLcs = 0; /* LCS value for this column */ int nLive = 0; /* Number of iterators in aIter not at EOF */ for(i=0; i<pInfo->nPhrase; i++){ LcsIterator *pIt = &aIter[i]; rc = sqlite3Fts3EvalPhrasePoslist(pCsr, pIt->pExpr, iCol, &pIt->pRead); if( rc!=SQLITE_OK ) goto matchinfo_lcs_out; if( pIt->pRead ){ pIt->iPos = pIt->iPosOffset; fts3LcsIteratorAdvance(pIt); if( pIt->pRead==0 ){ rc = FTS_CORRUPT_VTAB; goto matchinfo_lcs_out; } nLive++; } } while( nLive>0 ){ LcsIterator *pAdv = 0; /* The iterator to advance by one position */ int nThisLcs = 0; /* LCS for the current iterator positions */ |
︙ | ︙ | |||
1171 1172 1173 1174 1175 1176 1177 1178 | } if( fts3LcsIteratorAdvance(pAdv) ) nLive--; } pInfo->aMatchinfo[iCol] = nLcs; } sqlite3_free(aIter); | > | | 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 | } if( fts3LcsIteratorAdvance(pAdv) ) nLive--; } pInfo->aMatchinfo[iCol] = nLcs; } matchinfo_lcs_out: sqlite3_free(aIter); return rc; } /* ** Populate the buffer pInfo->aMatchinfo[] with an array of integers to ** be returned by the matchinfo() function. Argument zArg contains the ** format string passed as the second argument to matchinfo (or the ** default value "pcx" if no second argument was specified). The format |
︙ | ︙ | |||
1217 1218 1219 1220 1221 1222 1223 | case FTS3_MATCHINFO_NCOL: if( bGlobal ) pInfo->aMatchinfo[0] = pInfo->nCol; break; case FTS3_MATCHINFO_NDOC: if( bGlobal ){ sqlite3_int64 nDoc = 0; | | > | > > > > > | > > > > | | | | 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 | case FTS3_MATCHINFO_NCOL: if( bGlobal ) pInfo->aMatchinfo[0] = pInfo->nCol; break; case FTS3_MATCHINFO_NDOC: if( bGlobal ){ sqlite3_int64 nDoc = 0; rc = fts3MatchinfoSelectDoctotal(pTab, &pSelect, &nDoc, 0, 0); pInfo->aMatchinfo[0] = (u32)nDoc; } break; case FTS3_MATCHINFO_AVGLENGTH: if( bGlobal ){ sqlite3_int64 nDoc; /* Number of rows in table */ const char *a; /* Aggregate column length array */ const char *pEnd; /* First byte past end of length array */ rc = fts3MatchinfoSelectDoctotal(pTab, &pSelect, &nDoc, &a, &pEnd); if( rc==SQLITE_OK ){ int iCol; for(iCol=0; iCol<pInfo->nCol; iCol++){ u32 iVal; sqlite3_int64 nToken; a += sqlite3Fts3GetVarint(a, &nToken); if( a>pEnd ){ rc = SQLITE_CORRUPT_VTAB; break; } iVal = (u32)(((u32)(nToken&0xffffffff)+nDoc/2)/nDoc); pInfo->aMatchinfo[iCol] = iVal; } } } break; case FTS3_MATCHINFO_LENGTH: { sqlite3_stmt *pSelectDocsize = 0; rc = sqlite3Fts3SelectDocsize(pTab, pCsr->iPrevId, &pSelectDocsize); if( rc==SQLITE_OK ){ int iCol; const char *a = sqlite3_column_blob(pSelectDocsize, 0); const char *pEnd = a + sqlite3_column_bytes(pSelectDocsize, 0); for(iCol=0; iCol<pInfo->nCol; iCol++){ sqlite3_int64 nToken; a += sqlite3Fts3GetVarintBounded(a, pEnd, &nToken); if( a>pEnd ){ rc = SQLITE_CORRUPT_VTAB; break; } pInfo->aMatchinfo[iCol] = (u32)nToken; } } sqlite3_reset(pSelectDocsize); break; } case FTS3_MATCHINFO_LCS: rc = fts3ExprLoadDoclists(pCsr, 0, 0); if( rc==SQLITE_OK ){ rc = fts3MatchinfoLcs(pCsr, pInfo); } break; case FTS3_MATCHINFO_LHITS_BM: case FTS3_MATCHINFO_LHITS: { size_t nZero = fts3MatchinfoSize(pInfo, zArg[i]) * sizeof(u32); memset(pInfo->aMatchinfo, 0, nZero); rc = fts3ExprLHitGather(pCsr->pExpr, pInfo); break; } default: { Fts3Expr *pExpr; assert( zArg[i]==FTS3_MATCHINFO_HITS ); pExpr = pCsr->pExpr; rc = fts3ExprLoadDoclists(pCsr, 0, 0); if( rc!=SQLITE_OK ) break; if( bGlobal ){ if( pCsr->pDeferred ){ rc = fts3MatchinfoSelectDoctotal(pTab, &pSelect, &pInfo->nDoc,0,0); if( rc!=SQLITE_OK ) break; } rc = fts3ExprIterate(pExpr, fts3ExprGlobalHitsCb,(void*)pInfo); sqlite3Fts3EvalTestDeferred(pCsr, &rc); if( rc!=SQLITE_OK ) break; } (void)fts3ExprIterate(pExpr, fts3ExprLocalHitsCb,(void*)pInfo); |
︙ | ︙ | |||
1335 1336 1337 1338 1339 1340 1341 | /* If Fts3Cursor.pMIBuffer is NULL, then this is the first time the ** matchinfo function has been called for this query. In this case ** allocate the array used to accumulate the matchinfo data and ** initialize those elements that are constant for every row. */ if( pCsr->pMIBuffer==0 ){ | | | 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 | /* If Fts3Cursor.pMIBuffer is NULL, then this is the first time the ** matchinfo function has been called for this query. In this case ** allocate the array used to accumulate the matchinfo data and ** initialize those elements that are constant for every row. */ if( pCsr->pMIBuffer==0 ){ size_t nMatchinfo = 0; /* Number of u32 elements in match-info */ int i; /* Used to iterate through zArg */ /* Determine the number of phrases in the query */ pCsr->nPhrase = fts3ExprPhraseCount(pCsr->pExpr); sInfo.nPhrase = pCsr->nPhrase; /* Determine the number of integers in the buffer returned by this call. */ |
︙ | ︙ | |||
1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 | SnippetFragment aSnippet[4]; /* Maximum of 4 fragments per snippet */ int nFToken = -1; /* Number of tokens in each fragment */ if( !pCsr->pExpr ){ sqlite3_result_text(pCtx, "", 0, SQLITE_STATIC); return; } for(nSnippet=1; 1; nSnippet++){ int iSnip; /* Loop counter 0..nSnippet-1 */ u64 mCovered = 0; /* Bitmask of phrases covered by snippet */ u64 mSeen = 0; /* Bitmask of phrases seen by BestSnippet() */ | > > > > | 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 | SnippetFragment aSnippet[4]; /* Maximum of 4 fragments per snippet */ int nFToken = -1; /* Number of tokens in each fragment */ if( !pCsr->pExpr ){ sqlite3_result_text(pCtx, "", 0, SQLITE_STATIC); return; } /* Limit the snippet length to 64 tokens. */ if( nToken<-64 ) nToken = -64; if( nToken>+64 ) nToken = +64; for(nSnippet=1; 1; nSnippet++){ int iSnip; /* Loop counter 0..nSnippet-1 */ u64 mCovered = 0; /* Bitmask of phrases covered by snippet */ u64 mSeen = 0; /* Bitmask of phrases seen by BestSnippet() */ |
︙ | ︙ | |||
1493 1494 1495 1496 1497 1498 1499 | typedef struct TermOffset TermOffset; typedef struct TermOffsetCtx TermOffsetCtx; struct TermOffset { char *pList; /* Position-list */ | | | | | | 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 | typedef struct TermOffset TermOffset; typedef struct TermOffsetCtx TermOffsetCtx; struct TermOffset { char *pList; /* Position-list */ i64 iPos; /* Position just read from pList */ i64 iOff; /* Offset of this term from read positions */ }; struct TermOffsetCtx { Fts3Cursor *pCsr; int iCol; /* Column of table to populate aTerm for */ int iTerm; sqlite3_int64 iDocid; TermOffset *aTerm; }; /* ** This function is an fts3ExprIterate() callback used by sqlite3Fts3Offsets(). */ static int fts3ExprTermOffsetInit(Fts3Expr *pExpr, int iPhrase, void *ctx){ TermOffsetCtx *p = (TermOffsetCtx *)ctx; int nTerm; /* Number of tokens in phrase */ int iTerm; /* For looping through nTerm phrase terms */ char *pList; /* Pointer to position list for phrase */ i64 iPos = 0; /* First position in position-list */ int rc; UNUSED_PARAMETER(iPhrase); rc = sqlite3Fts3EvalPhrasePoslist(p->pCsr, pExpr, p->iCol, &pList); nTerm = pExpr->pPhrase->nToken; if( pList ){ fts3GetDeltaPosition(&pList, &iPos); assert_fts3_nc( iPos>=0 ); } for(iTerm=0; iTerm<nTerm; iTerm++){ TermOffset *pT = &p->aTerm[p->iTerm++]; pT->iOff = nTerm-iTerm-1; pT->pList = pList; pT->iPos = iPos; |
︙ | ︙ | |||
1562 1563 1564 1565 1566 1567 1568 | assert( pCsr->isRequireSeek==0 ); /* Count the number of terms in the query */ rc = fts3ExprLoadDoclists(pCsr, 0, &nToken); if( rc!=SQLITE_OK ) goto offsets_out; /* Allocate the array of TermOffset iterators. */ | | | | < | > | 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 | assert( pCsr->isRequireSeek==0 ); /* Count the number of terms in the query */ rc = fts3ExprLoadDoclists(pCsr, 0, &nToken); if( rc!=SQLITE_OK ) goto offsets_out; /* Allocate the array of TermOffset iterators. */ sCtx.aTerm = (TermOffset *)sqlite3Fts3MallocZero(sizeof(TermOffset)*nToken); if( 0==sCtx.aTerm ){ rc = SQLITE_NOMEM; goto offsets_out; } sCtx.iDocid = pCsr->iPrevId; sCtx.pCsr = pCsr; /* Loop through the table columns, appending offset information to ** string-buffer res for each column. */ for(iCol=0; iCol<pTab->nColumn; iCol++){ sqlite3_tokenizer_cursor *pC; /* Tokenizer cursor */ const char *ZDUMMY; /* Dummy argument used with xNext() */ int NDUMMY = 0; /* Dummy argument used with xNext() */ int iStart = 0; int iEnd = 0; int iCurrent = 0; const char *zDoc; int nDoc; /* Initialize the contents of sCtx.aTerm[] for column iCol. This ** operation may fail if the database contains corrupt records. */ sCtx.iCol = iCol; sCtx.iTerm = 0; rc = fts3ExprIterate(pCsr->pExpr, fts3ExprTermOffsetInit, (void*)&sCtx); if( rc!=SQLITE_OK ) goto offsets_out; /* Retreive the text stored in column iCol. If an SQL NULL is stored ** in column iCol, jump immediately to the next iteration of the loop. ** If an OOM occurs while retrieving the data (this can happen if SQLite ** needs to transform the data from utf-16 to utf-8), return SQLITE_NOMEM ** to the caller. */ |
︙ | ︙ | |||
1631 1632 1633 1634 1635 1636 1637 | } } if( !pTerm ){ /* All offsets for this column have been gathered. */ rc = SQLITE_DONE; }else{ | | | 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 | } } if( !pTerm ){ /* All offsets for this column have been gathered. */ rc = SQLITE_DONE; }else{ assert_fts3_nc( iCurrent<=iMinPos ); if( 0==(0xFE&*pTerm->pList) ){ pTerm->pList = 0; }else{ fts3GetDeltaPosition(&pTerm->pList, &pTerm->iPos); } while( rc==SQLITE_OK && iCurrent<iMinPos ){ rc = pMod->xNext(pC, &ZDUMMY, &NDUMMY, &iStart, &iEnd, &iCurrent); |
︙ | ︙ |
Changes to ext/fts3/fts3_term.c.
︙ | ︙ | |||
64 65 66 67 68 69 70 | sqlite3_vtab **ppVtab, /* OUT: New sqlite3_vtab object */ char **pzErr /* OUT: sqlite3_malloc'd error message */ ){ char const *zDb; /* Name of database (e.g. "main") */ char const *zFts3; /* Name of fts3 table */ int nDb; /* Result of strlen(zDb) */ int nFts3; /* Result of strlen(zFts3) */ | | | | 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 | sqlite3_vtab **ppVtab, /* OUT: New sqlite3_vtab object */ char **pzErr /* OUT: sqlite3_malloc'd error message */ ){ char const *zDb; /* Name of database (e.g. "main") */ char const *zFts3; /* Name of fts3 table */ int nDb; /* Result of strlen(zDb) */ int nFts3; /* Result of strlen(zFts3) */ sqlite3_int64 nByte; /* Bytes of space to allocate here */ int rc; /* value returned by declare_vtab() */ Fts3termTable *p; /* Virtual table object to return */ int iIndex = 0; UNUSED_PARAMETER(pCtx); if( argc==5 ){ iIndex = atoi(argv[4]); argc--; } |
︙ | ︙ | |||
92 93 94 95 96 97 98 | zFts3 = argv[3]; nFts3 = (int)strlen(zFts3); rc = sqlite3_declare_vtab(db, FTS3_TERMS_SCHEMA); if( rc!=SQLITE_OK ) return rc; nByte = sizeof(Fts3termTable) + sizeof(Fts3Table) + nDb + nFts3 + 2; | | | | 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 | zFts3 = argv[3]; nFts3 = (int)strlen(zFts3); rc = sqlite3_declare_vtab(db, FTS3_TERMS_SCHEMA); if( rc!=SQLITE_OK ) return rc; nByte = sizeof(Fts3termTable) + sizeof(Fts3Table) + nDb + nFts3 + 2; p = (Fts3termTable *)sqlite3_malloc64(nByte); if( !p ) return SQLITE_NOMEM; memset(p, 0, (size_t)nByte); p->pFts3Tab = (Fts3Table *)&p[1]; p->pFts3Tab->zDb = (char *)&p->pFts3Tab[1]; p->pFts3Tab->zName = &p->pFts3Tab->zDb[nDb+1]; p->pFts3Tab->db = db; p->pFts3Tab->nIndex = iIndex+1; p->iIndex = iIndex; |
︙ | ︙ |
Changes to ext/fts3/fts3_test.c.
︙ | ︙ | |||
444 445 446 447 448 449 450 | while( p<pEnd && testIsTokenChar(*p)==0 ) p++; if( p==pEnd ){ rc = SQLITE_DONE; }else{ /* Advance to the end of the token */ const char *pToken = p; | | | | | | 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 | while( p<pEnd && testIsTokenChar(*p)==0 ) p++; if( p==pEnd ){ rc = SQLITE_DONE; }else{ /* Advance to the end of the token */ const char *pToken = p; sqlite3_int64 nToken; while( p<pEnd && testIsTokenChar(*p) ) p++; nToken = (sqlite3_int64)(p-pToken); /* Copy the token into the buffer */ if( nToken>pCsr->nBuffer ){ sqlite3_free(pCsr->aBuffer); pCsr->aBuffer = sqlite3_malloc64(nToken); } if( pCsr->aBuffer==0 ){ rc = SQLITE_NOMEM; }else{ int i; if( pCsr->iLangid & 0x00000001 ){ for(i=0; i<nToken; i++) pCsr->aBuffer[i] = pToken[i]; }else{ for(i=0; i<nToken; i++) pCsr->aBuffer[i] = (char)testTolower(pToken[i]); } pCsr->iToken++; pCsr->iInput = (int)(p - pCsr->aInput); *ppToken = pCsr->aBuffer; *pnBytes = (int)nToken; *piStartOffset = (int)(pToken - pCsr->aInput); *piEndOffset = (int)(p - pCsr->aInput); *piPosition = pCsr->iToken; } } return rc; |
︙ | ︙ | |||
569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 | UNUSED_PARAMETER(clientData); return TCL_OK; } /* ** End of tokenizer code. **************************************************************************/ int Sqlitetestfts3_Init(Tcl_Interp *interp){ Tcl_CreateObjCommand(interp, "fts3_near_match", fts3_near_match_cmd, 0, 0); Tcl_CreateObjCommand(interp, "fts3_configure_incr_load", fts3_configure_incr_load_cmd, 0, 0 ); Tcl_CreateObjCommand( interp, "fts3_test_tokenizer", fts3_test_tokenizer_cmd, 0, 0 ); | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > < > > > | 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 | UNUSED_PARAMETER(clientData); return TCL_OK; } /* ** End of tokenizer code. **************************************************************************/ /* ** sqlite3_fts3_may_be_corrupt BOOLEAN ** ** Set or clear the global "may-be-corrupt" flag. Return the old value. */ static int SQLITE_TCLAPI fts3_may_be_corrupt( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ #ifdef SQLITE_DEBUG int bOld = sqlite3_fts3_may_be_corrupt; if( objc!=2 && objc!=1 ){ Tcl_WrongNumArgs(interp, 1, objv, "?BOOLEAN?"); return TCL_ERROR; } if( objc==2 ){ int bNew; if( Tcl_GetBooleanFromObj(interp, objv[1], &bNew) ) return TCL_ERROR; sqlite3_fts3_may_be_corrupt = bNew; } Tcl_SetObjResult(interp, Tcl_NewIntObj(bOld)); #endif return TCL_OK; } int Sqlitetestfts3_Init(Tcl_Interp *interp){ Tcl_CreateObjCommand(interp, "fts3_near_match", fts3_near_match_cmd, 0, 0); Tcl_CreateObjCommand(interp, "fts3_configure_incr_load", fts3_configure_incr_load_cmd, 0, 0 ); Tcl_CreateObjCommand( interp, "fts3_test_tokenizer", fts3_test_tokenizer_cmd, 0, 0 ); Tcl_CreateObjCommand( interp, "fts3_test_varint", fts3_test_varint_cmd, 0, 0 ); Tcl_CreateObjCommand( interp, "sqlite3_fts3_may_be_corrupt", fts3_may_be_corrupt, 0, 0 ); return TCL_OK; } #endif /* SQLITE_ENABLE_FTS3 || SQLITE_ENABLE_FTS4 */ #endif /* ifdef SQLITE_TEST */ |
Changes to ext/fts3/fts3_tokenize_vtab.c.
︙ | ︙ | |||
118 119 120 121 122 123 124 | int nByte = 0; char **azDequote; for(i=0; i<argc; i++){ nByte += (int)(strlen(argv[i]) + 1); } | | | 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 | int nByte = 0; char **azDequote; for(i=0; i<argc; i++){ nByte += (int)(strlen(argv[i]) + 1); } *pazDequote = azDequote = sqlite3_malloc64(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; |
︙ | ︙ | |||
184 185 186 187 188 189 190 | zModule = azDequote[0]; } rc = fts3tokQueryTokenizer((Fts3Hash*)pHash, zModule, &pMod, pzErr); } assert( (rc==SQLITE_OK)==(pMod!=0) ); if( rc==SQLITE_OK ){ | | > | 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 | zModule = azDequote[0]; } rc = fts3tokQueryTokenizer((Fts3Hash*)pHash, zModule, &pMod, pzErr); } assert( (rc==SQLITE_OK)==(pMod!=0) ); if( rc==SQLITE_OK ){ const char * const *azArg = 0; if( nDequote>1 ) 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; |
︙ | ︙ | |||
342 343 344 345 346 347 348 | 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]); | | | | 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 | 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_malloc64(nByte+1); if( pCsr->zInput==0 ){ rc = SQLITE_NOMEM; }else{ if( nByte>0 ) 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; } } } |
︙ | ︙ |
Changes to ext/fts3/fts3_tokenizer.c.
︙ | ︙ | |||
75 76 77 78 79 80 81 | pHash = (Fts3Hash *)sqlite3_user_data(context); zName = sqlite3_value_text(argv[0]); nName = sqlite3_value_bytes(argv[0])+1; if( argc==2 ){ | | | 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 | pHash = (Fts3Hash *)sqlite3_user_data(context); zName = sqlite3_value_text(argv[0]); nName = sqlite3_value_bytes(argv[0])+1; if( argc==2 ){ if( fts3TokenizerEnabled(context) || sqlite3_value_frombind(argv[1]) ){ void *pOld; int n = sqlite3_value_bytes(argv[1]); if( zName==0 || n!=sizeof(pPtr) ){ sqlite3_result_error(context, "argument type mismatch", -1); return; } pPtr = *(void **)sqlite3_value_blob(argv[1]); |
︙ | ︙ | |||
102 103 104 105 106 107 108 | if( !pPtr ){ char *zErr = sqlite3_mprintf("unknown tokenizer: %s", zName); sqlite3_result_error(context, zErr, -1); sqlite3_free(zErr); return; } } | > | > | 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 | if( !pPtr ){ char *zErr = sqlite3_mprintf("unknown tokenizer: %s", zName); sqlite3_result_error(context, zErr, -1); sqlite3_free(zErr); return; } } if( fts3TokenizerEnabled(context) || sqlite3_value_frombind(argv[0]) ){ sqlite3_result_blob(context, (void *)&pPtr, sizeof(pPtr), SQLITE_TRANSIENT); } } int sqlite3Fts3IsIdChar(char c){ static const char isFtsIdChar[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1x */ 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 2x */ |
︙ | ︙ | |||
190 191 192 193 194 195 196 | sqlite3Fts3ErrMsg(pzErr, "unknown tokenizer: %s", z); rc = SQLITE_ERROR; }else{ char const **aArg = 0; int iArg = 0; z = &z[n+1]; while( z<zEnd && (NULL!=(z = (char *)sqlite3Fts3NextToken(z, &n))) ){ | | | | 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 | sqlite3Fts3ErrMsg(pzErr, "unknown tokenizer: %s", z); rc = SQLITE_ERROR; }else{ char const **aArg = 0; int iArg = 0; z = &z[n+1]; while( z<zEnd && (NULL!=(z = (char *)sqlite3Fts3NextToken(z, &n))) ){ sqlite3_int64 nNew = sizeof(char *)*(iArg+1); char const **aNew = (const char **)sqlite3_realloc64((void *)aArg, nNew); if( !aNew ){ sqlite3_free(zCopy); sqlite3_free((void *)aArg); return SQLITE_NOMEM; } aArg = aNew; aArg[iArg++] = z; |
︙ | ︙ | |||
384 385 386 387 388 389 390 | rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0); if( rc!=SQLITE_OK ){ return rc; } sqlite3_bind_text(pStmt, 1, zName, -1, SQLITE_STATIC); if( SQLITE_ROW==sqlite3_step(pStmt) ){ | | > > | 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 | rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0); if( rc!=SQLITE_OK ){ return rc; } sqlite3_bind_text(pStmt, 1, zName, -1, SQLITE_STATIC); if( SQLITE_ROW==sqlite3_step(pStmt) ){ if( sqlite3_column_type(pStmt, 0)==SQLITE_BLOB && sqlite3_column_bytes(pStmt, 0)==sizeof(*pp) ){ memcpy((void *)pp, sqlite3_column_blob(pStmt, 0), sizeof(*pp)); } } return sqlite3_finalize(pStmt); } |
︙ | ︙ | |||
473 474 475 476 477 478 479 | int sqlite3Fts3InitHashTable( sqlite3 *db, Fts3Hash *pHash, const char *zName ){ int rc = SQLITE_OK; void *p = (void *)pHash; | | | 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 | int sqlite3Fts3InitHashTable( sqlite3 *db, Fts3Hash *pHash, const char *zName ){ int rc = SQLITE_OK; void *p = (void *)pHash; const int any = SQLITE_UTF8|SQLITE_DIRECTONLY; #ifdef SQLITE_TEST char *zTest = 0; char *zTest2 = 0; void *pdb = (void *)db; zTest = sqlite3_mprintf("%s_test", zName); zTest2 = sqlite3_mprintf("%s_internal_test", zName); |
︙ | ︙ |
Changes to ext/fts3/fts3_unicode.c.
︙ | ︙ | |||
151 152 153 154 155 156 157 | } } if( nEntry ){ int *aNew; /* New aiException[] array */ int nNew; /* Number of valid entries in array aNew[] */ | | | 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 | } } if( nEntry ){ int *aNew; /* New aiException[] array */ int nNew; /* Number of valid entries in array aNew[] */ aNew = sqlite3_realloc64(p->aiException,(p->nException+nEntry)*sizeof(int)); if( aNew==0 ) return SQLITE_NOMEM; nNew = p->nException; z = (const unsigned char *)zIn; while( z<zTerm ){ READ_UTF8(z, zTerm, iCode); if( sqlite3FtsUnicodeIsalnum((int)iCode)!=bAlnum |
︙ | ︙ | |||
281 282 283 284 285 286 287 288 289 290 291 292 293 294 | return SQLITE_NOMEM; } memset(pCsr, 0, sizeof(unicode_cursor)); pCsr->aInput = (const unsigned char *)aInput; if( aInput==0 ){ pCsr->nInput = 0; }else if( nInput<0 ){ pCsr->nInput = (int)strlen(aInput); }else{ pCsr->nInput = nInput; } *pp = &pCsr->base; | > | 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 | return SQLITE_NOMEM; } memset(pCsr, 0, sizeof(unicode_cursor)); pCsr->aInput = (const unsigned char *)aInput; if( aInput==0 ){ pCsr->nInput = 0; pCsr->aInput = (const unsigned char*)""; }else if( nInput<0 ){ pCsr->nInput = (int)strlen(aInput); }else{ pCsr->nInput = nInput; } *pp = &pCsr->base; |
︙ | ︙ | |||
340 341 342 343 344 345 346 | zOut = pCsr->zToken; do { int iOut; /* Grow the output buffer if required. */ if( (zOut-pCsr->zToken)>=(pCsr->nAlloc-4) ){ | | | 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 | zOut = pCsr->zToken; do { int iOut; /* Grow the output buffer if required. */ if( (zOut-pCsr->zToken)>=(pCsr->nAlloc-4) ){ char *zNew = sqlite3_realloc64(pCsr->zToken, pCsr->nAlloc+64); if( !zNew ) return SQLITE_NOMEM; zOut = &zNew[zOut - pCsr->zToken]; pCsr->zToken = zNew; pCsr->nAlloc += 64; } /* Write the folded case of the last character read to the output */ |
︙ | ︙ |
Changes to ext/fts3/fts3_unicode2.c.
1 | /* | | | 1 2 3 4 5 6 7 8 9 | /* ** 2012-05-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. |
︙ | ︙ | |||
174 175 176 177 178 179 180 | 61726, 61784, 61800, 61816, 61836, 61880, 61896, 61914, 61948, 61998, 62062, 62122, 62154, 62184, 62200, 62218, 62252, 62302, 62364, 62410, 62442, 62478, 62536, 62554, 62584, 62604, 62640, 62648, 62656, 62664, 62730, 62766, 62830, 62890, 62924, 62974, 63032, 63050, 63082, 63118, 63182, 63242, 63274, 63310, 63368, 63390, }; | | | | | 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 | 61726, 61784, 61800, 61816, 61836, 61880, 61896, 61914, 61948, 61998, 62062, 62122, 62154, 62184, 62200, 62218, 62252, 62302, 62364, 62410, 62442, 62478, 62536, 62554, 62584, 62604, 62640, 62648, 62656, 62664, 62730, 62766, 62830, 62890, 62924, 62974, 63032, 63050, 63082, 63118, 63182, 63242, 63274, 63310, 63368, 63390, }; #define HIBIT ((unsigned char)0x80) unsigned char aChar[] = { '\0', 'a', 'c', 'e', 'i', 'n', 'o', 'u', 'y', 'y', 'a', 'c', 'd', 'e', 'e', 'g', 'h', 'i', 'j', 'k', 'l', 'n', 'o', 'r', 's', 't', 'u', 'u', 'w', 'y', 'z', 'o', 'u', 'a', 'i', 'o', 'u', 'u'|HIBIT, 'a'|HIBIT, 'g', 'k', 'o', 'o'|HIBIT, 'j', 'g', 'n', 'a'|HIBIT, 'a', 'e', 'i', 'o', 'r', 'u', 's', 't', 'h', 'a', 'e', 'o'|HIBIT, 'o', 'o'|HIBIT, 'y', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', 'a', 'b', 'c'|HIBIT, 'd', 'd', 'e'|HIBIT, 'e', 'e'|HIBIT, 'f', 'g', 'h', 'h', 'i', 'i'|HIBIT, 'k', 'l', 'l'|HIBIT, 'l', 'm', 'n', 'o'|HIBIT, 'p', 'r', 'r'|HIBIT, 'r', 's', 's'|HIBIT, 't', 'u', 'u'|HIBIT, 'v', 'w', 'w', 'x', 'y', 'z', 'h', 't', 'w', 'y', 'a', 'a'|HIBIT, 'a'|HIBIT, 'a'|HIBIT, 'e', 'e'|HIBIT, 'e'|HIBIT, 'i', 'o', 'o'|HIBIT, 'o'|HIBIT, 'o'|HIBIT, 'u', 'u'|HIBIT, 'u'|HIBIT, 'y', }; unsigned int key = (((unsigned int)c)<<3) | 0x00000007; int iRes = 0; int iHi = sizeof(aDia)/sizeof(aDia[0]) - 1; int iLo = 0; while( iHi>=iLo ){ |
︙ | ︙ | |||
227 228 229 230 231 232 233 | ** is a diacritical modifier character. */ int sqlite3FtsUnicodeIsdiacritic(int c){ unsigned int mask0 = 0x08029FDF; unsigned int mask1 = 0x000361F8; if( c<768 || c>817 ) return 0; return (c < 768+32) ? | | | | 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 | ** is a diacritical modifier character. */ int sqlite3FtsUnicodeIsdiacritic(int c){ unsigned int mask0 = 0x08029FDF; unsigned int mask1 = 0x000361F8; if( c<768 || c>817 ) return 0; return (c < 768+32) ? (mask0 & ((unsigned int)1 << (c-768))) : (mask1 & ((unsigned int)1 << (c-768-32))); } /* ** Interpret the argument as a unicode codepoint. If the codepoint ** is an upper case character that has a lower case equivalent, ** return the codepoint corresponding to the lower case version. |
︙ | ︙ |
Changes to ext/fts3/fts3_write.c.
︙ | ︙ | |||
19 20 21 22 23 24 25 | #include "fts3Int.h" #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) #include <string.h> #include <assert.h> #include <stdlib.h> | | | 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | #include "fts3Int.h" #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) #include <string.h> #include <assert.h> #include <stdlib.h> #include <stdio.h> #define FTS_MAX_APPENDABLE_HEIGHT 16 /* ** When full-text index nodes are loaded from disk, the buffer that they ** are loaded into has the following number of bytes of padding at the end ** of it. i.e. if a full-text index node is 900 bytes in size, then a buffer |
︙ | ︙ | |||
63 64 65 66 67 68 69 | # define FTS3_NODE_CHUNK_THRESHOLD test_fts3_node_chunk_threshold #else # define FTS3_NODE_CHUNKSIZE (4*1024) # define FTS3_NODE_CHUNK_THRESHOLD (FTS3_NODE_CHUNKSIZE*4) #endif /* | | | 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 | # define FTS3_NODE_CHUNK_THRESHOLD test_fts3_node_chunk_threshold #else # define FTS3_NODE_CHUNKSIZE (4*1024) # define FTS3_NODE_CHUNK_THRESHOLD (FTS3_NODE_CHUNKSIZE*4) #endif /* ** The values that may be meaningfully bound to the :1 parameter in ** statements SQL_REPLACE_STAT and SQL_SELECT_STAT. */ #define FTS_STAT_DOCTOTAL 0 #define FTS_STAT_INCRMERGEHINT 1 #define FTS_STAT_AUTOINCRMERGE 2 /* |
︙ | ︙ | |||
331 332 333 334 335 336 337 | /* This statement is used to determine which level to read the input from ** when performing an incremental merge. It returns the absolute level number ** of the oldest level in the db that contains at least ? segments. Or, ** if no level in the FTS index contains more than ? segments, the statement ** returns zero rows. */ /* 28 */ "SELECT level, count(*) AS cnt FROM %Q.'%q_segdir' " " GROUP BY level HAVING cnt>=?" | | | > > | 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 | /* This statement is used to determine which level to read the input from ** when performing an incremental merge. It returns the absolute level number ** of the oldest level in the db that contains at least ? segments. Or, ** if no level in the FTS index contains more than ? segments, the statement ** returns zero rows. */ /* 28 */ "SELECT level, count(*) AS cnt FROM %Q.'%q_segdir' " " GROUP BY level HAVING cnt>=?" " ORDER BY (level %% 1024) ASC, 2 DESC LIMIT 1", /* Estimate the upper limit on the number of leaf nodes in a new segment ** created by merging the oldest :2 segments from absolute level :1. See ** function sqlite3Fts3Incrmerge() for details. */ /* 29 */ "SELECT 2 * total(1 + leaves_end_block - start_block) " " FROM (SELECT * FROM %Q.'%q_segdir' " " WHERE level = ? ORDER BY idx ASC LIMIT ?" " )", /* SQL_DELETE_SEGDIR_ENTRY ** Delete the %_segdir entry on absolute level :1 with index :2. */ /* 30 */ "DELETE FROM %Q.'%q_segdir' WHERE level = ? AND idx = ?", /* SQL_SHIFT_SEGDIR_ENTRY ** Modify the idx value for the segment with idx=:3 on absolute level :2 |
︙ | ︙ | |||
392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 | sqlite3_stmt *pStmt; assert( SizeofArray(azSql)==SizeofArray(p->aStmt) ); assert( eStmt<SizeofArray(azSql) && eStmt>=0 ); pStmt = p->aStmt[eStmt]; if( !pStmt ){ char *zSql; if( eStmt==SQL_CONTENT_INSERT ){ zSql = sqlite3_mprintf(azSql[eStmt], p->zDb, p->zName, p->zWriteExprlist); }else if( eStmt==SQL_SELECT_CONTENT_BY_ROWID ){ zSql = sqlite3_mprintf(azSql[eStmt], p->zReadExprlist); }else{ zSql = sqlite3_mprintf(azSql[eStmt], p->zDb, p->zName); } if( !zSql ){ rc = SQLITE_NOMEM; }else{ | > > | < | 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 | sqlite3_stmt *pStmt; assert( SizeofArray(azSql)==SizeofArray(p->aStmt) ); assert( eStmt<SizeofArray(azSql) && eStmt>=0 ); pStmt = p->aStmt[eStmt]; if( !pStmt ){ int f = SQLITE_PREPARE_PERSISTENT|SQLITE_PREPARE_NO_VTAB; char *zSql; if( eStmt==SQL_CONTENT_INSERT ){ zSql = sqlite3_mprintf(azSql[eStmt], p->zDb, p->zName, p->zWriteExprlist); }else if( eStmt==SQL_SELECT_CONTENT_BY_ROWID ){ f &= ~SQLITE_PREPARE_NO_VTAB; zSql = sqlite3_mprintf(azSql[eStmt], p->zReadExprlist); }else{ zSql = sqlite3_mprintf(azSql[eStmt], p->zDb, p->zName); } if( !zSql ){ rc = SQLITE_NOMEM; }else{ rc = sqlite3_prepare_v3(p->db, zSql, -1, f, &pStmt, NULL); sqlite3_free(zSql); assert( rc==SQLITE_OK || pStmt==0 ); p->aStmt[eStmt] = pStmt; } } if( apVal ){ int i; |
︙ | ︙ | |||
562 563 564 565 566 567 568 | static sqlite3_int64 getAbsoluteLevel( Fts3Table *p, /* FTS3 table handle */ int iLangid, /* Language id */ int iIndex, /* Index in p->aIndex[] */ int iLevel /* Level of segments */ ){ sqlite3_int64 iBase; /* First absolute level for iLangid/iIndex */ | | | 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 | static sqlite3_int64 getAbsoluteLevel( Fts3Table *p, /* FTS3 table handle */ int iLangid, /* Language id */ int iIndex, /* Index in p->aIndex[] */ int iLevel /* Level of segments */ ){ sqlite3_int64 iBase; /* First absolute level for iLangid/iIndex */ assert_fts3_nc( iLangid>=0 ); assert( p->nIndex>0 ); assert( iIndex>=0 && iIndex<p->nIndex ); iBase = ((sqlite3_int64)iLangid * p->nIndex + iIndex) * FTS3_SEGDIR_MAXLEVEL; return iBase + iLevel; } |
︙ | ︙ | |||
691 692 693 694 695 696 697 | ){ PendingList *p = *pp; int rc = SQLITE_OK; assert( !p || p->iLastDocid<=iDocid ); if( !p || p->iLastDocid!=iDocid ){ | | | 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 | ){ PendingList *p = *pp; int rc = SQLITE_OK; assert( !p || p->iLastDocid<=iDocid ); if( !p || p->iLastDocid!=iDocid ){ u64 iDelta = (u64)iDocid - (u64)(p ? p->iLastDocid : 0); if( p ){ assert( p->nData<p->nSpace ); assert( p->aData[p->nData]==0 ); p->nData++; } if( SQLITE_OK!=(rc = fts3PendingListAppendVarint(&p, iDelta)) ){ goto pendinglistappend_out; |
︙ | ︙ | |||
1148 1149 1150 1151 1152 1153 1154 | if( rc==SQLITE_OK ){ /* If iNext is FTS3_MERGE_COUNT, indicating that level iLevel is already ** full, merge all segments in level iLevel into a single iLevel+1 ** segment and allocate (newly freed) index 0 at level iLevel. Otherwise, ** if iNext is less than FTS3_MERGE_COUNT, allocate index iNext. */ | | | 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 | if( rc==SQLITE_OK ){ /* If iNext is FTS3_MERGE_COUNT, indicating that level iLevel is already ** full, merge all segments in level iLevel into a single iLevel+1 ** segment and allocate (newly freed) index 0 at level iLevel. Otherwise, ** if iNext is less than FTS3_MERGE_COUNT, allocate index iNext. */ if( iNext>=MergeCount(p) ){ fts3LogMerge(16, getAbsoluteLevel(p, iLangid, iIndex, iLevel)); rc = fts3SegmentMerge(p, iLangid, iIndex, iLevel); *piIdx = 0; }else{ *piIdx = iNext; } } |
︙ | ︙ | |||
1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 | if( rc!=SQLITE_OK ){ sqlite3_free(aByte); aByte = 0; } } *paBlob = aByte; } } return rc; } /* ** Close the blob handle at p->pSegments, if it is open. See comments above | > > | 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 | if( rc!=SQLITE_OK ){ sqlite3_free(aByte); aByte = 0; } } *paBlob = aByte; } }else if( rc==SQLITE_ERROR ){ rc = FTS_CORRUPT_VTAB; } return rc; } /* ** Close the blob handle at p->pSegments, if it is open. See comments above |
︙ | ︙ | |||
1326 1327 1328 1329 1330 1331 1332 | Fts3HashElem *pElem = *(pReader->ppNextElem); sqlite3_free(pReader->aNode); pReader->aNode = 0; if( pElem ){ char *aCopy; PendingList *pList = (PendingList *)fts3HashData(pElem); int nCopy = pList->nData+1; | > > > > | > > > > > | > > | > | 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 | Fts3HashElem *pElem = *(pReader->ppNextElem); sqlite3_free(pReader->aNode); pReader->aNode = 0; if( pElem ){ char *aCopy; PendingList *pList = (PendingList *)fts3HashData(pElem); int nCopy = pList->nData+1; int nTerm = fts3HashKeysize(pElem); if( (nTerm+1)>pReader->nTermAlloc ){ sqlite3_free(pReader->zTerm); pReader->zTerm = (char*)sqlite3_malloc((nTerm+1)*2); if( !pReader->zTerm ) return SQLITE_NOMEM; pReader->nTermAlloc = (nTerm+1)*2; } memcpy(pReader->zTerm, fts3HashKey(pElem), nTerm); pReader->zTerm[nTerm] = '\0'; pReader->nTerm = nTerm; aCopy = (char*)sqlite3_malloc(nCopy); if( !aCopy ) return SQLITE_NOMEM; memcpy(aCopy, pList->aData, nCopy); pReader->nNode = pReader->nDoclist = nCopy; pReader->aNode = pReader->aDoclist = aCopy; pReader->ppNextElem++; assert( pReader->aNode ); } return SQLITE_OK; } fts3SegReaderSetEof(pReader); /* If iCurrentBlock>=iLeafEndBlock, this is an EOF condition. All leaf ** blocks have already been traversed. */ #ifdef CORRUPT_DB assert( pReader->iCurrentBlock<=pReader->iLeafEndBlock || CORRUPT_DB ); #endif if( pReader->iCurrentBlock>=pReader->iLeafEndBlock ){ return SQLITE_OK; } rc = sqlite3Fts3ReadBlock( p, ++pReader->iCurrentBlock, &pReader->aNode, &pReader->nNode, (bIncr ? &pReader->nPopulate : 0) |
︙ | ︙ | |||
1372 1373 1374 1375 1376 1377 1378 | /* Because of the FTS3_NODE_PADDING bytes of padding, the following is ** safe (no risk of overread) even if the node data is corrupted. */ pNext += fts3GetVarint32(pNext, &nPrefix); pNext += fts3GetVarint32(pNext, &nSuffix); if( nSuffix<=0 || (&pReader->aNode[pReader->nNode] - pNext)<nSuffix | | | 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 | /* Because of the FTS3_NODE_PADDING bytes of padding, the following is ** safe (no risk of overread) even if the node data is corrupted. */ pNext += fts3GetVarint32(pNext, &nPrefix); pNext += fts3GetVarint32(pNext, &nSuffix); if( nSuffix<=0 || (&pReader->aNode[pReader->nNode] - pNext)<nSuffix || nPrefix>pReader->nTerm ){ return FTS_CORRUPT_VTAB; } /* Both nPrefix and nSuffix were read by fts3GetVarint32() and so are ** between 0 and 0x7FFFFFFF. But the sum of the two may cause integer ** overflow - hence the (i64) casts. */ |
︙ | ︙ | |||
1404 1405 1406 1407 1408 1409 1410 | pReader->aDoclist = pNext; pReader->pOffsetList = 0; /* Check that the doclist does not appear to extend past the end of the ** b-tree node. And that the final byte of the doclist is 0x00. If either ** of these statements is untrue, then the data structure is corrupt. */ | | > | 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 | pReader->aDoclist = pNext; pReader->pOffsetList = 0; /* Check that the doclist does not appear to extend past the end of the ** b-tree node. And that the final byte of the doclist is 0x00. If either ** of these statements is untrue, then the data structure is corrupt. */ if( pReader->nDoclist > pReader->nNode-(pReader->aDoclist-pReader->aNode) || (pReader->nPopulate==0 && pReader->aDoclist[pReader->nDoclist-1]) || pReader->nDoclist==0 ){ return FTS_CORRUPT_VTAB; } return SQLITE_OK; } /* |
︙ | ︙ | |||
1522 1523 1524 1525 1526 1527 1528 | ** returning. */ if( p>=pEnd ){ pReader->pOffsetList = 0; }else{ rc = fts3SegReaderRequire(pReader, p, FTS3_VARINT_MAX); if( rc==SQLITE_OK ){ | | | | | | | 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 | ** returning. */ if( p>=pEnd ){ pReader->pOffsetList = 0; }else{ rc = fts3SegReaderRequire(pReader, p, FTS3_VARINT_MAX); if( rc==SQLITE_OK ){ u64 iDelta; pReader->pOffsetList = p + sqlite3Fts3GetVarintU(p, &iDelta); if( pTab->bDescIdx ){ pReader->iDocid = (i64)((u64)pReader->iDocid - iDelta); }else{ pReader->iDocid = (i64)((u64)pReader->iDocid + iDelta); } } } } return rc; } int sqlite3Fts3MsrOvfl( Fts3Cursor *pCsr, Fts3MultiSegReader *pMsr, int *pnOvfl |
︙ | ︙ | |||
1577 1578 1579 1580 1581 1582 1583 | /* ** Free all allocations associated with the iterator passed as the ** second argument. */ void sqlite3Fts3SegReaderFree(Fts3SegReader *pReader){ if( pReader ){ | < | < | 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 | /* ** Free all allocations associated with the iterator passed as the ** second argument. */ void sqlite3Fts3SegReaderFree(Fts3SegReader *pReader){ if( pReader ){ sqlite3_free(pReader->zTerm); if( !fts3SegReaderIsRootOnly(pReader) ){ sqlite3_free(pReader->aNode); } sqlite3_blob_close(pReader->pBlob); } sqlite3_free(pReader); } |
︙ | ︙ | |||
1604 1605 1606 1607 1608 1609 1610 | const char *zRoot, /* Buffer containing root node */ int nRoot, /* Size of buffer containing root node */ Fts3SegReader **ppReader /* OUT: Allocated Fts3SegReader */ ){ Fts3SegReader *pReader; /* Newly allocated SegReader object */ int nExtra = 0; /* Bytes to allocate segment root node */ | > > > > | > | | 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 | const char *zRoot, /* Buffer containing root node */ int nRoot, /* Size of buffer containing root node */ Fts3SegReader **ppReader /* OUT: Allocated Fts3SegReader */ ){ Fts3SegReader *pReader; /* Newly allocated SegReader object */ int nExtra = 0; /* Bytes to allocate segment root node */ assert( zRoot!=0 || nRoot==0 ); #ifdef CORRUPT_DB assert( zRoot!=0 || CORRUPT_DB ); #endif if( iStartLeaf==0 ){ if( iEndLeaf!=0 ) return FTS_CORRUPT_VTAB; nExtra = nRoot + FTS3_NODE_PADDING; } pReader = (Fts3SegReader *)sqlite3_malloc(sizeof(Fts3SegReader) + nExtra); if( !pReader ){ return SQLITE_NOMEM; } memset(pReader, 0, sizeof(Fts3SegReader)); pReader->iIdx = iAge; pReader->bLookup = bLookup!=0; pReader->iStartBlock = iStartLeaf; pReader->iLeafEndBlock = iEndLeaf; pReader->iEndBlock = iEndBlock; if( nExtra ){ /* The entire segment is stored in the root node. */ pReader->aNode = (char *)&pReader[1]; pReader->rootOnly = 1; pReader->nNode = nRoot; if( nRoot ) memcpy(pReader->aNode, zRoot, nRoot); memset(&pReader->aNode[nRoot], 0, FTS3_NODE_PADDING); }else{ pReader->iCurrentBlock = iStartLeaf-1; } *ppReader = pReader; return SQLITE_OK; } |
︙ | ︙ | |||
1740 1741 1742 1743 1744 1745 1746 | if( pE ){ aElem = &pE; nElem = 1; } } if( nElem>0 ){ | > | | | 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 | if( pE ){ aElem = &pE; nElem = 1; } } if( nElem>0 ){ sqlite3_int64 nByte; nByte = sizeof(Fts3SegReader) + (nElem+1)*sizeof(Fts3HashElem *); pReader = (Fts3SegReader *)sqlite3_malloc64(nByte); if( !pReader ){ rc = SQLITE_NOMEM; }else{ memset(pReader, 0, nByte); pReader->iIdx = 0x7FFFFFFF; pReader->ppNextElem = (Fts3HashElem **)&pReader[1]; memcpy(pReader->ppNextElem, aElem, nElem*sizeof(Fts3HashElem *)); |
︙ | ︙ | |||
1789 1790 1791 1792 1793 1794 1795 | } }else{ rc = (pLhs->aNode==0) - (pRhs->aNode==0); } if( rc==0 ){ rc = pRhs->iIdx - pLhs->iIdx; } | | | 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 | } }else{ rc = (pLhs->aNode==0) - (pRhs->aNode==0); } if( rc==0 ){ rc = pRhs->iIdx - pLhs->iIdx; } assert_fts3_nc( rc!=0 ); return rc; } /* ** A different comparison function for SegReader structures. In this ** version, it is assumed that each SegReader points to an entry in ** a doclist for identical terms. Comparison is made as follows: |
︙ | ︙ | |||
1985 1986 1987 1988 1989 1990 1991 | static int fts3PrefixCompress( const char *zPrev, /* Buffer containing previous term */ int nPrev, /* Size of buffer zPrev in bytes */ const char *zNext, /* Buffer containing next term */ int nNext /* Size of buffer zNext in bytes */ ){ int n; | < | > | 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 | static int fts3PrefixCompress( const char *zPrev, /* Buffer containing previous term */ int nPrev, /* Size of buffer zPrev in bytes */ const char *zNext, /* Buffer containing next term */ int nNext /* Size of buffer zNext in bytes */ ){ int n; for(n=0; n<nPrev && n<nNext && zPrev[n]==zNext[n]; n++); assert_fts3_nc( n<nNext ); return n; } /* ** Add term zTerm to the SegmentNode. It is guaranteed that zTerm is larger ** (according to memcmp) than the previous term. */ |
︙ | ︙ | |||
2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 | int nData = pTree->nData; /* Current size of node in bytes */ int nReq = nData; /* Required space after adding zTerm */ int nPrefix; /* Number of bytes of prefix compression */ int nSuffix; /* Suffix length */ nPrefix = fts3PrefixCompress(pTree->zTerm, pTree->nTerm, zTerm, nTerm); nSuffix = nTerm-nPrefix; nReq += sqlite3Fts3VarintLen(nPrefix)+sqlite3Fts3VarintLen(nSuffix)+nSuffix; if( nReq<=p->nNodeSize || !pTree->zTerm ){ if( nReq>p->nNodeSize ){ /* An unusual case: this is the first term to be added to the node ** and the static node buffer (p->nNodeSize bytes) is not large | > > > > > | 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 | int nData = pTree->nData; /* Current size of node in bytes */ int nReq = nData; /* Required space after adding zTerm */ int nPrefix; /* Number of bytes of prefix compression */ int nSuffix; /* Suffix length */ nPrefix = fts3PrefixCompress(pTree->zTerm, pTree->nTerm, zTerm, nTerm); nSuffix = nTerm-nPrefix; /* If nSuffix is zero or less, then zTerm/nTerm must be a prefix of ** pWriter->zTerm/pWriter->nTerm. i.e. must be equal to or less than when ** compared with BINARY collation. This indicates corruption. */ if( nSuffix<=0 ) return FTS_CORRUPT_VTAB; nReq += sqlite3Fts3VarintLen(nPrefix)+sqlite3Fts3VarintLen(nSuffix)+nSuffix; if( nReq<=p->nNodeSize || !pTree->zTerm ){ if( nReq>p->nNodeSize ){ /* An unusual case: this is the first term to be added to the node ** and the static node buffer (p->nNodeSize bytes) is not large |
︙ | ︙ | |||
2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 | rc = sqlite3_reset(pStmt); if( rc!=SQLITE_OK ) return rc; } nData = pWriter->nData; nPrefix = fts3PrefixCompress(pWriter->zTerm, pWriter->nTerm, zTerm, nTerm); nSuffix = nTerm-nPrefix; /* Figure out how many bytes are required by this new entry */ nReq = sqlite3Fts3VarintLen(nPrefix) + /* varint containing prefix size */ sqlite3Fts3VarintLen(nSuffix) + /* varint containing suffix size */ nSuffix + /* Term suffix */ sqlite3Fts3VarintLen(nDoclist) + /* Size of doclist */ nDoclist; /* Doclist data */ if( nData>0 && nData+nReq>p->nNodeSize ){ int rc; /* The current leaf node is full. Write it out to the database. */ rc = fts3WriteSegment(p, pWriter->iFree++, pWriter->aData, nData); if( rc!=SQLITE_OK ) return rc; p->nLeafAdd++; /* Add the current term to the interior node tree. The term added to ** the interior tree must: ** | > > > > > > | 2271 2272 2273 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 2300 2301 2302 | rc = sqlite3_reset(pStmt); if( rc!=SQLITE_OK ) return rc; } nData = pWriter->nData; nPrefix = fts3PrefixCompress(pWriter->zTerm, pWriter->nTerm, zTerm, nTerm); nSuffix = nTerm-nPrefix; /* If nSuffix is zero or less, then zTerm/nTerm must be a prefix of ** pWriter->zTerm/pWriter->nTerm. i.e. must be equal to or less than when ** compared with BINARY collation. This indicates corruption. */ if( nSuffix<=0 ) return FTS_CORRUPT_VTAB; /* Figure out how many bytes are required by this new entry */ nReq = sqlite3Fts3VarintLen(nPrefix) + /* varint containing prefix size */ sqlite3Fts3VarintLen(nSuffix) + /* varint containing suffix size */ nSuffix + /* Term suffix */ sqlite3Fts3VarintLen(nDoclist) + /* Size of doclist */ nDoclist; /* Doclist data */ if( nData>0 && nData+nReq>p->nNodeSize ){ int rc; /* The current leaf node is full. Write it out to the database. */ if( pWriter->iFree==LARGEST_INT64 ) return FTS_CORRUPT_VTAB; rc = fts3WriteSegment(p, pWriter->iFree++, pWriter->aData, nData); if( rc!=SQLITE_OK ) return rc; p->nLeafAdd++; /* Add the current term to the interior node tree. The term added to ** the interior tree must: ** |
︙ | ︙ | |||
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 | pWriter->nSize = nReq; } assert( nData+nReq<=pWriter->nSize ); /* Append the prefix-compressed term and doclist to the buffer. */ nData += sqlite3Fts3PutVarint(&pWriter->aData[nData], nPrefix); nData += sqlite3Fts3PutVarint(&pWriter->aData[nData], nSuffix); memcpy(&pWriter->aData[nData], &zTerm[nPrefix], nSuffix); nData += nSuffix; nData += sqlite3Fts3PutVarint(&pWriter->aData[nData], nDoclist); memcpy(&pWriter->aData[nData], aDoclist, nDoclist); pWriter->nData = nData + nDoclist; /* Save the current term so that it can be used to prefix-compress the next. ** If the isCopyTerm parameter is true, then the buffer pointed to by ** zTerm is transient, so take a copy of the term data. Otherwise, just ** store a copy of the pointer. */ if( isCopyTerm ){ if( nTerm>pWriter->nMalloc ){ char *zNew = sqlite3_realloc(pWriter->zMalloc, nTerm*2); if( !zNew ){ return SQLITE_NOMEM; } pWriter->nMalloc = nTerm*2; pWriter->zMalloc = zNew; pWriter->zTerm = zNew; } assert( pWriter->zTerm==pWriter->zMalloc ); memcpy(pWriter->zTerm, zTerm, nTerm); }else{ pWriter->zTerm = (char *)zTerm; } pWriter->nTerm = nTerm; return SQLITE_OK; | > > > | 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 | pWriter->nSize = nReq; } assert( nData+nReq<=pWriter->nSize ); /* Append the prefix-compressed term and doclist to the buffer. */ nData += sqlite3Fts3PutVarint(&pWriter->aData[nData], nPrefix); nData += sqlite3Fts3PutVarint(&pWriter->aData[nData], nSuffix); assert( nSuffix>0 ); memcpy(&pWriter->aData[nData], &zTerm[nPrefix], nSuffix); nData += nSuffix; nData += sqlite3Fts3PutVarint(&pWriter->aData[nData], nDoclist); assert( nDoclist>0 ); memcpy(&pWriter->aData[nData], aDoclist, nDoclist); pWriter->nData = nData + nDoclist; /* Save the current term so that it can be used to prefix-compress the next. ** If the isCopyTerm parameter is true, then the buffer pointed to by ** zTerm is transient, so take a copy of the term data. Otherwise, just ** store a copy of the pointer. */ if( isCopyTerm ){ if( nTerm>pWriter->nMalloc ){ char *zNew = sqlite3_realloc(pWriter->zMalloc, nTerm*2); if( !zNew ){ return SQLITE_NOMEM; } pWriter->nMalloc = nTerm*2; pWriter->zMalloc = zNew; pWriter->zTerm = zNew; } assert( pWriter->zTerm==pWriter->zMalloc ); assert( nTerm>0 ); memcpy(pWriter->zTerm, zTerm, nTerm); }else{ pWriter->zTerm = (char *)zTerm; } pWriter->nTerm = nTerm; return SQLITE_OK; |
︙ | ︙ | |||
2473 2474 2475 2476 2477 2478 2479 | ** (1024 is actually the value of macro FTS3_SEGDIR_PREFIXLEVEL_STR). */ sqlite3_stmt *pStmt; int rc = fts3SqlStmt(p, SQL_SELECT_SEGDIR_MAX_LEVEL, &pStmt, 0); if( rc!=SQLITE_OK ) return rc; sqlite3_bind_int64(pStmt, 1, iAbsLevel+1); sqlite3_bind_int64(pStmt, 2, | | | 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 | ** (1024 is actually the value of macro FTS3_SEGDIR_PREFIXLEVEL_STR). */ sqlite3_stmt *pStmt; int rc = fts3SqlStmt(p, SQL_SELECT_SEGDIR_MAX_LEVEL, &pStmt, 0); if( rc!=SQLITE_OK ) return rc; sqlite3_bind_int64(pStmt, 1, iAbsLevel+1); sqlite3_bind_int64(pStmt, 2, (((u64)iAbsLevel/FTS3_SEGDIR_MAXLEVEL)+1) * FTS3_SEGDIR_MAXLEVEL ); *pbMax = 0; if( SQLITE_ROW==sqlite3_step(pStmt) ){ *pbMax = sqlite3_column_type(pStmt, 0)==SQLITE_NULL; } return sqlite3_reset(pStmt); |
︙ | ︙ | |||
2601 2602 2603 2604 2605 2606 2607 | if( iCol==iCurrent ){ nList = (int)(p - pList); break; } nList -= (int)(p - pList); pList = p; | | | | 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 | if( iCol==iCurrent ){ nList = (int)(p - pList); break; } nList -= (int)(p - pList); pList = p; if( nList<=0 ){ break; } p = &pList[1]; p += fts3GetVarint32(p, &iCurrent); } if( bZero && (pEnd - &pList[nList])>0){ memset(&pList[nList], 0, pEnd - &pList[nList]); } *ppList = pList; *pnList = nList; } /* |
︙ | ︙ | |||
2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 | char *pNew; pMsr->nBuffer = nList*2; pNew = (char *)sqlite3_realloc(pMsr->aBuffer, pMsr->nBuffer); if( !pNew ) return SQLITE_NOMEM; pMsr->aBuffer = pNew; } memcpy(pMsr->aBuffer, pList, nList); return SQLITE_OK; } int sqlite3Fts3MsrIncrNext( Fts3Table *p, /* Virtual table handle */ Fts3MultiSegReader *pMsr, /* Multi-segment-reader handle */ | > | 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 | char *pNew; pMsr->nBuffer = nList*2; pNew = (char *)sqlite3_realloc(pMsr->aBuffer, pMsr->nBuffer); if( !pNew ) return SQLITE_NOMEM; pMsr->aBuffer = pNew; } assert( nList>0 ); memcpy(pMsr->aBuffer, pList, nList); return SQLITE_OK; } int sqlite3Fts3MsrIncrNext( Fts3Table *p, /* Virtual table handle */ Fts3MultiSegReader *pMsr, /* Multi-segment-reader handle */ |
︙ | ︙ | |||
2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 | pCsr->apSegment[i]->nOffsetList = 0; pCsr->apSegment[i]->iDocid = 0; } return SQLITE_OK; } int sqlite3Fts3SegReaderStep( Fts3Table *p, /* Virtual table handle */ Fts3MultiSegReader *pCsr /* Cursor object */ ){ int rc = SQLITE_OK; | > > > > > > > > > > > > > | 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 | pCsr->apSegment[i]->nOffsetList = 0; pCsr->apSegment[i]->iDocid = 0; } return SQLITE_OK; } static int fts3GrowSegReaderBuffer(Fts3MultiSegReader *pCsr, int nReq){ if( nReq>pCsr->nBuffer ){ char *aNew; pCsr->nBuffer = nReq*2; aNew = sqlite3_realloc(pCsr->aBuffer, pCsr->nBuffer); if( !aNew ){ return SQLITE_NOMEM; } pCsr->aBuffer = aNew; } return SQLITE_OK; } int sqlite3Fts3SegReaderStep( Fts3Table *p, /* Virtual table handle */ Fts3MultiSegReader *pCsr /* Cursor object */ ){ int rc = SQLITE_OK; |
︙ | ︙ | |||
2948 2949 2950 2951 2952 2953 2954 | if( !isIgnoreEmpty || nList>0 ){ /* Calculate the 'docid' delta value to write into the merged ** doclist. */ sqlite3_int64 iDelta; if( p->bDescIdx && nDoclist>0 ){ | > | > | < < < < < < < < | | < > | 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 | if( !isIgnoreEmpty || nList>0 ){ /* Calculate the 'docid' delta value to write into the merged ** doclist. */ sqlite3_int64 iDelta; if( p->bDescIdx && nDoclist>0 ){ if( iPrev<=iDocid ) return FTS_CORRUPT_VTAB; iDelta = (i64)((u64)iPrev - (u64)iDocid); }else{ if( nDoclist>0 && iPrev>=iDocid ) return FTS_CORRUPT_VTAB; iDelta = (i64)((u64)iDocid - (u64)iPrev); } nByte = sqlite3Fts3VarintLen(iDelta) + (isRequirePos?nList+1:0); rc = fts3GrowSegReaderBuffer(pCsr, nByte+nDoclist+FTS3_NODE_PADDING); if( rc ) return rc; if( isFirst ){ char *a = &pCsr->aBuffer[nDoclist]; int nWrite; nWrite = sqlite3Fts3FirstFilter(iDelta, pList, nList, a); if( nWrite ){ |
︙ | ︙ | |||
2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 | } } } fts3SegReaderSort(apSegment, nMerge, j, xCmp); } if( nDoclist>0 ){ pCsr->aDoclist = pCsr->aBuffer; pCsr->nDoclist = nDoclist; rc = SQLITE_ROW; } } pCsr->nAdvance = nMerge; }while( rc==SQLITE_OK ); | > > > | 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 | } } } fts3SegReaderSort(apSegment, nMerge, j, xCmp); } if( nDoclist>0 ){ rc = fts3GrowSegReaderBuffer(pCsr, nDoclist+FTS3_NODE_PADDING); if( rc ) return rc; memset(&pCsr->aBuffer[nDoclist], 0, FTS3_NODE_PADDING); pCsr->aDoclist = pCsr->aBuffer; pCsr->nDoclist = nDoclist; rc = SQLITE_ROW; } } pCsr->nAdvance = nMerge; }while( rc==SQLITE_OK ); |
︙ | ︙ | |||
3038 3039 3040 3041 3042 3043 3044 | i64 *piEndBlock, i64 *pnByte ){ const unsigned char *zText = sqlite3_column_text(pStmt, iCol); if( zText ){ int i; int iMul = 1; | | | | | 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 | i64 *piEndBlock, i64 *pnByte ){ const unsigned char *zText = sqlite3_column_text(pStmt, iCol); if( zText ){ int i; int iMul = 1; u64 iVal = 0; for(i=0; zText[i]>='0' && zText[i]<='9'; i++){ iVal = iVal*10 + (zText[i] - '0'); } *piEndBlock = (i64)iVal; while( zText[i]==' ' ) i++; iVal = 0; if( zText[i]=='-' ){ i++; iMul = -1; } for(/* no-op */; zText[i]>='0' && zText[i]<='9'; i++){ iVal = iVal*10 + (zText[i] - '0'); } *pnByte = ((i64)iVal * (i64)iMul); } } /* ** A segment of size nByte bytes has just been written to absolute level ** iAbsLevel. Promote any segments that should be promoted as a result. |
︙ | ︙ | |||
3218 3219 3220 3221 3222 3223 3224 | iNewLevel = getAbsoluteLevel(p, iLangid, iIndex, iLevel+1); rc = fts3AllocateSegdirIdx(p, iLangid, iIndex, iLevel+1, &iIdx); bIgnoreEmpty = (iLevel!=FTS3_SEGCURSOR_PENDING) && (iNewLevel>iMaxLevel); } if( rc!=SQLITE_OK ) goto finished; assert( csr.nSegment>0 ); | | > | > | | 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 | iNewLevel = getAbsoluteLevel(p, iLangid, iIndex, iLevel+1); rc = fts3AllocateSegdirIdx(p, iLangid, iIndex, iLevel+1, &iIdx); bIgnoreEmpty = (iLevel!=FTS3_SEGCURSOR_PENDING) && (iNewLevel>iMaxLevel); } if( rc!=SQLITE_OK ) goto finished; assert( csr.nSegment>0 ); assert_fts3_nc( iNewLevel>=getAbsoluteLevel(p, iLangid, iIndex, 0) ); assert_fts3_nc( iNewLevel<getAbsoluteLevel(p, iLangid, iIndex,FTS3_SEGDIR_MAXLEVEL) ); memset(&filter, 0, sizeof(Fts3SegFilter)); filter.flags = FTS3_SEGMENT_REQUIRE_POS; filter.flags |= (bIgnoreEmpty ? FTS3_SEGMENT_IGNORE_EMPTY : 0); rc = sqlite3Fts3SegReaderStart(p, &csr, &filter); while( SQLITE_OK==rc ){ rc = sqlite3Fts3SegReaderStep(p, &csr); if( rc!=SQLITE_ROW ) break; rc = fts3SegWriterAdd(p, &pWriter, 1, csr.zTerm, csr.nTerm, csr.aDoclist, csr.nDoclist); } if( rc!=SQLITE_OK ) goto finished; assert_fts3_nc( pWriter || bIgnoreEmpty ); if( iLevel!=FTS3_SEGCURSOR_PENDING ){ rc = fts3DeleteSegdir( p, iLangid, iIndex, iLevel, csr.apSegment, csr.nSegment ); if( rc!=SQLITE_OK ) goto finished; } |
︙ | ︙ | |||
3318 3319 3320 3321 3322 3323 3324 | */ static void fts3DecodeIntArray( int N, /* The number of integers to decode */ u32 *a, /* Write the integer values */ const char *zBuf, /* The BLOB containing the varints */ int nBuf /* size of the BLOB */ ){ | | | > | | | < | | > > | | 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 3404 3405 3406 3407 3408 3409 | */ static void fts3DecodeIntArray( int N, /* The number of integers to decode */ u32 *a, /* Write the integer values */ const char *zBuf, /* The BLOB containing the varints */ int nBuf /* size of the BLOB */ ){ int i = 0; if( nBuf && (zBuf[nBuf-1]&0x80)==0 ){ int j; for(i=j=0; i<N && j<nBuf; i++){ sqlite3_int64 x; j += sqlite3Fts3GetVarint(&zBuf[j], &x); a[i] = (u32)(x & 0xffffffff); } } while( i<N ) a[i++] = 0; } /* ** Insert the sizes (in tokens) for each column of the document ** with docid equal to p->iPrevDocid. The sizes are encoded as ** a blob of varints. */ static void fts3InsertDocsize( int *pRC, /* Result code */ Fts3Table *p, /* Table into which to insert */ u32 *aSz /* Sizes of each column, in tokens */ ){ char *pBlob; /* The BLOB encoding of the document size */ int nBlob; /* Number of bytes in the BLOB */ sqlite3_stmt *pStmt; /* Statement used to insert the encoding */ int rc; /* Result code from subfunctions */ if( *pRC ) return; pBlob = sqlite3_malloc64( 10*(sqlite3_int64)p->nColumn ); if( pBlob==0 ){ *pRC = SQLITE_NOMEM; return; } fts3EncodeIntArray(p->nColumn, aSz, pBlob, &nBlob); rc = fts3SqlStmt(p, SQL_REPLACE_DOCSIZE, &pStmt, 0); if( rc ){ |
︙ | ︙ | |||
3394 3395 3396 3397 3398 3399 3400 | sqlite3_stmt *pStmt; /* Statement for reading and writing */ int i; /* Loop counter */ int rc; /* Result code from subfunctions */ const int nStat = p->nColumn+2; if( *pRC ) return; | | | 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458 3459 | sqlite3_stmt *pStmt; /* Statement for reading and writing */ int i; /* Loop counter */ int rc; /* Result code from subfunctions */ const int nStat = p->nColumn+2; if( *pRC ) return; a = sqlite3_malloc64( (sizeof(u32)+10)*(sqlite3_int64)nStat ); if( a==0 ){ *pRC = SQLITE_NOMEM; return; } pBlob = (char*)&a[nStat]; rc = fts3SqlStmt(p, SQL_SELECT_STAT, &pStmt, 0); if( rc ){ |
︙ | ︙ | |||
3458 3459 3460 3461 3462 3463 3464 | ** iIndex/iLangid combination. */ static int fts3DoOptimize(Fts3Table *p, int bReturnDone){ int bSeenDone = 0; int rc; sqlite3_stmt *pAllLangid = 0; | > > | > < | 3509 3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 | ** iIndex/iLangid combination. */ static int fts3DoOptimize(Fts3Table *p, int bReturnDone){ int bSeenDone = 0; int rc; sqlite3_stmt *pAllLangid = 0; rc = sqlite3Fts3PendingTermsFlush(p); if( rc==SQLITE_OK ){ rc = fts3SqlStmt(p, SQL_SELECT_ALL_LANGID, &pAllLangid, 0); } if( rc==SQLITE_OK ){ int rc2; sqlite3_bind_int(pAllLangid, 1, p->iPrevLangid); sqlite3_bind_int(pAllLangid, 2, p->nIndex); while( sqlite3_step(pAllLangid)==SQLITE_ROW ){ int i; int iLangid = sqlite3_column_int(pAllLangid, 0); for(i=0; rc==SQLITE_OK && i<p->nIndex; i++){ rc = fts3SegmentMerge(p, iLangid, i, FTS3_SEGCURSOR_ALL); if( rc==SQLITE_DONE ){ bSeenDone = 1; rc = SQLITE_OK; } } } rc2 = sqlite3_reset(pAllLangid); if( rc==SQLITE_OK ) rc = rc2; } sqlite3Fts3SegmentsClose(p); return (rc==SQLITE_OK && bReturnDone && bSeenDone) ? SQLITE_DONE : rc; } /* ** This function is called when the user executes the following statement: ** |
︙ | ︙ | |||
3515 3516 3517 3518 3519 3520 3521 | rc = SQLITE_NOMEM; }else{ rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); sqlite3_free(zSql); } if( rc==SQLITE_OK ){ | | | | 3568 3569 3570 3571 3572 3573 3574 3575 3576 3577 3578 3579 3580 3581 3582 3583 | rc = SQLITE_NOMEM; }else{ rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); sqlite3_free(zSql); } if( rc==SQLITE_OK ){ sqlite3_int64 nByte = sizeof(u32) * ((sqlite3_int64)p->nColumn+1)*3; aSz = (u32 *)sqlite3_malloc64(nByte); if( aSz==0 ){ rc = SQLITE_NOMEM; }else{ memset(aSz, 0, nByte); aSzIns = &aSz[p->nColumn+1]; aSzDel = &aSzIns[p->nColumn+1]; } |
︙ | ︙ | |||
3582 3583 3584 3585 3586 3587 3588 | Fts3Table *p, /* FTS3 table handle */ sqlite3_int64 iAbsLevel, /* Absolute level to open */ int nSeg, /* Number of segments to merge */ Fts3MultiSegReader *pCsr /* Cursor object to populate */ ){ int rc; /* Return Code */ sqlite3_stmt *pStmt = 0; /* Statement used to read %_segdir entry */ | | | | 3635 3636 3637 3638 3639 3640 3641 3642 3643 3644 3645 3646 3647 3648 3649 3650 3651 3652 3653 3654 | Fts3Table *p, /* FTS3 table handle */ sqlite3_int64 iAbsLevel, /* Absolute level to open */ int nSeg, /* Number of segments to merge */ Fts3MultiSegReader *pCsr /* Cursor object to populate */ ){ int rc; /* Return Code */ sqlite3_stmt *pStmt = 0; /* Statement used to read %_segdir entry */ sqlite3_int64 nByte; /* Bytes allocated at pCsr->apSegment[] */ /* Allocate space for the Fts3MultiSegReader.aCsr[] array */ memset(pCsr, 0, sizeof(*pCsr)); nByte = sizeof(Fts3SegReader *) * nSeg; pCsr->apSegment = (Fts3SegReader **)sqlite3_malloc64(nByte); if( pCsr->apSegment==0 ){ rc = SQLITE_NOMEM; }else{ memset(pCsr->apSegment, 0, nByte); rc = fts3SqlStmt(p, SQL_SELECT_LEVEL, &pStmt, 0); } |
︙ | ︙ | |||
3730 3731 3732 3733 3734 3735 3736 | p->aNode = 0; }else{ if( bFirst==0 ){ p->iOff += fts3GetVarint32(&p->aNode[p->iOff], &nPrefix); } p->iOff += fts3GetVarint32(&p->aNode[p->iOff], &nSuffix); | | | | | | | 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 | p->aNode = 0; }else{ if( bFirst==0 ){ p->iOff += fts3GetVarint32(&p->aNode[p->iOff], &nPrefix); } p->iOff += fts3GetVarint32(&p->aNode[p->iOff], &nSuffix); if( nPrefix>p->term.n || nSuffix>p->nNode-p->iOff || nSuffix==0 ){ return FTS_CORRUPT_VTAB; } blobGrowBuffer(&p->term, nPrefix+nSuffix, &rc); if( rc==SQLITE_OK && ALWAYS(p->term.a!=0) ){ memcpy(&p->term.a[nPrefix], &p->aNode[p->iOff], nSuffix); p->term.n = nPrefix+nSuffix; p->iOff += nSuffix; if( p->iChild==0 ){ p->iOff += fts3GetVarint32(&p->aNode[p->iOff], &p->nDoclist); if( (p->nNode-p->iOff)<p->nDoclist ){ return FTS_CORRUPT_VTAB; } p->aDoclist = &p->aNode[p->iOff]; p->iOff += p->nDoclist; } } } assert_fts3_nc( p->iOff<=p->nNode ); return rc; } /* ** Release all dynamic resources held by node-reader object *p. */ static void nodeReaderRelease(NodeReader *p){ |
︙ | ︙ | |||
3773 3774 3775 3776 3777 3778 3779 | */ static int nodeReaderInit(NodeReader *p, const char *aNode, int nNode){ memset(p, 0, sizeof(NodeReader)); p->aNode = aNode; p->nNode = nNode; /* Figure out if this is a leaf or an internal node. */ | | | | 3826 3827 3828 3829 3830 3831 3832 3833 3834 3835 3836 3837 3838 3839 3840 3841 3842 3843 3844 3845 3846 3847 | */ static int nodeReaderInit(NodeReader *p, const char *aNode, int nNode){ memset(p, 0, sizeof(NodeReader)); p->aNode = aNode; p->nNode = nNode; /* Figure out if this is a leaf or an internal node. */ if( aNode && aNode[0] ){ /* An internal node. */ p->iOff = 1 + sqlite3Fts3GetVarint(&p->aNode[1], &p->iChild); }else{ p->iOff = 1; } return aNode ? nodeReaderNext(p) : SQLITE_OK; } /* ** This function is called while writing an FTS segment each time a leaf o ** node is finished and written to disk. The key (zTerm/nTerm) is guaranteed ** to be greater than the largest key on the node just written, but smaller ** than or equal to the first key that will be written to the next leaf |
︙ | ︙ | |||
3817 3818 3819 3820 3821 3822 3823 3824 3825 3826 3827 3828 3829 3830 | /* Figure out how much space the key will consume if it is written to ** the current node of layer iLayer. Due to the prefix compression, ** the space required changes depending on which node the key is to ** be added to. */ nPrefix = fts3PrefixCompress(pNode->key.a, pNode->key.n, zTerm, nTerm); nSuffix = nTerm - nPrefix; nSpace = sqlite3Fts3VarintLen(nPrefix); nSpace += sqlite3Fts3VarintLen(nSuffix) + nSuffix; if( pNode->key.n==0 || (pNode->block.n + nSpace)<=p->nNodeSize ){ /* If the current node of layer iLayer contains zero keys, or if adding ** the key to it will not cause it to grow to larger than nNodeSize ** bytes in size, write the key here. */ | > | 3870 3871 3872 3873 3874 3875 3876 3877 3878 3879 3880 3881 3882 3883 3884 | /* Figure out how much space the key will consume if it is written to ** the current node of layer iLayer. Due to the prefix compression, ** the space required changes depending on which node the key is to ** be added to. */ nPrefix = fts3PrefixCompress(pNode->key.a, pNode->key.n, zTerm, nTerm); nSuffix = nTerm - nPrefix; if(nSuffix<=0 ) return FTS_CORRUPT_VTAB; nSpace = sqlite3Fts3VarintLen(nPrefix); nSpace += sqlite3Fts3VarintLen(nSuffix) + nSuffix; if( pNode->key.n==0 || (pNode->block.n + nSpace)<=p->nNodeSize ){ /* If the current node of layer iLayer contains zero keys, or if adding ** the key to it will not cause it to grow to larger than nNodeSize ** bytes in size, write the key here. */ |
︙ | ︙ | |||
3910 3911 3912 3913 3914 3915 3916 | int bFirst = (pPrev->n==0); /* True if this is the first term written */ int nPrefix; /* Size of term prefix in bytes */ int nSuffix; /* Size of term suffix in bytes */ /* Node must have already been started. There must be a doclist for a ** leaf node, and there must not be a doclist for an internal node. */ assert( pNode->n>0 ); | | > | 3964 3965 3966 3967 3968 3969 3970 3971 3972 3973 3974 3975 3976 3977 3978 3979 3980 3981 3982 3983 3984 3985 | int bFirst = (pPrev->n==0); /* True if this is the first term written */ int nPrefix; /* Size of term prefix in bytes */ int nSuffix; /* Size of term suffix in bytes */ /* Node must have already been started. There must be a doclist for a ** leaf node, and there must not be a doclist for an internal node. */ assert( pNode->n>0 ); assert_fts3_nc( (pNode->a[0]=='\0')==(aDoclist!=0) ); blobGrowBuffer(pPrev, nTerm, &rc); if( rc!=SQLITE_OK ) return rc; nPrefix = fts3PrefixCompress(pPrev->a, pPrev->n, zTerm, nTerm); nSuffix = nTerm - nPrefix; if( nSuffix<=0 ) return FTS_CORRUPT_VTAB; memcpy(pPrev->a, zTerm, nTerm); pPrev->n = nTerm; if( bFirst==0 ){ pNode->n += sqlite3Fts3PutVarint(&pNode->a[pNode->n], nPrefix); } pNode->n += sqlite3Fts3PutVarint(&pNode->a[pNode->n], nSuffix); |
︙ | ︙ | |||
4126 4127 4128 4129 4130 4131 4132 | static int fts3TermCmp( const char *zLhs, int nLhs, /* LHS of comparison */ const char *zRhs, int nRhs /* RHS of comparison */ ){ int nCmp = MIN(nLhs, nRhs); int res; | > | > > > | 4181 4182 4183 4184 4185 4186 4187 4188 4189 4190 4191 4192 4193 4194 4195 4196 4197 4198 4199 | static int fts3TermCmp( const char *zLhs, int nLhs, /* LHS of comparison */ const char *zRhs, int nRhs /* RHS of comparison */ ){ int nCmp = MIN(nLhs, nRhs); int res; if( nCmp && ALWAYS(zLhs) && ALWAYS(zRhs) ){ res = memcmp(zLhs, zRhs, nCmp); }else{ res = 0; } if( res==0 ) res = nLhs - nRhs; return res; } /* |
︙ | ︙ | |||
4210 4211 4212 4213 4214 4215 4216 4217 4218 4219 4220 4221 4222 4223 | fts3ReadEndBlockField(pSelect, 3, &iEnd, &pWriter->nLeafData); if( pWriter->nLeafData<0 ){ pWriter->nLeafData = pWriter->nLeafData * -1; } pWriter->bNoLeafData = (pWriter->nLeafData==0); nRoot = sqlite3_column_bytes(pSelect, 4); aRoot = sqlite3_column_blob(pSelect, 4); }else{ return sqlite3_reset(pSelect); } /* Check for the zero-length marker in the %_segments table */ rc = fts3IsAppendable(p, iEnd, &bAppendable); | > > > > | 4269 4270 4271 4272 4273 4274 4275 4276 4277 4278 4279 4280 4281 4282 4283 4284 4285 4286 | fts3ReadEndBlockField(pSelect, 3, &iEnd, &pWriter->nLeafData); if( pWriter->nLeafData<0 ){ pWriter->nLeafData = pWriter->nLeafData * -1; } pWriter->bNoLeafData = (pWriter->nLeafData==0); nRoot = sqlite3_column_bytes(pSelect, 4); aRoot = sqlite3_column_blob(pSelect, 4); if( aRoot==0 ){ sqlite3_reset(pSelect); return nRoot ? SQLITE_NOMEM : FTS_CORRUPT_VTAB; } }else{ return sqlite3_reset(pSelect); } /* Check for the zero-length marker in the %_segments table */ rc = fts3IsAppendable(p, iEnd, &bAppendable); |
︙ | ︙ | |||
4245 4246 4247 4248 4249 4250 4251 4252 4253 4254 4255 4256 4257 4258 4259 4260 4261 4262 4263 4264 | if( rc==SQLITE_OK && bAppendable ){ /* It is possible to append to this segment. Set up the IncrmergeWriter ** object to do so. */ int i; int nHeight = (int)aRoot[0]; NodeWriter *pNode; pWriter->nLeafEst = (int)((iEnd - iStart) + 1)/FTS_MAX_APPENDABLE_HEIGHT; pWriter->iStart = iStart; pWriter->iEnd = iEnd; pWriter->iAbsLevel = iAbsLevel; pWriter->iIdx = iIdx; for(i=nHeight+1; i<FTS_MAX_APPENDABLE_HEIGHT; i++){ pWriter->aNodeWriter[i].iBlock = pWriter->iStart + i*pWriter->nLeafEst; } pNode = &pWriter->aNodeWriter[nHeight]; pNode->iBlock = pWriter->iStart + pWriter->nLeafEst*nHeight; | > > > > | > > > > | | | | > > | > | | | | | | | | > > | | | > | | > | 4308 4309 4310 4311 4312 4313 4314 4315 4316 4317 4318 4319 4320 4321 4322 4323 4324 4325 4326 4327 4328 4329 4330 4331 4332 4333 4334 4335 4336 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 | if( rc==SQLITE_OK && bAppendable ){ /* It is possible to append to this segment. Set up the IncrmergeWriter ** object to do so. */ int i; int nHeight = (int)aRoot[0]; NodeWriter *pNode; if( nHeight<1 || nHeight>=FTS_MAX_APPENDABLE_HEIGHT ){ sqlite3_reset(pSelect); return FTS_CORRUPT_VTAB; } pWriter->nLeafEst = (int)((iEnd - iStart) + 1)/FTS_MAX_APPENDABLE_HEIGHT; pWriter->iStart = iStart; pWriter->iEnd = iEnd; pWriter->iAbsLevel = iAbsLevel; pWriter->iIdx = iIdx; for(i=nHeight+1; i<FTS_MAX_APPENDABLE_HEIGHT; i++){ pWriter->aNodeWriter[i].iBlock = pWriter->iStart + i*pWriter->nLeafEst; } pNode = &pWriter->aNodeWriter[nHeight]; pNode->iBlock = pWriter->iStart + pWriter->nLeafEst*nHeight; blobGrowBuffer(&pNode->block, MAX(nRoot, p->nNodeSize)+FTS3_NODE_PADDING, &rc ); if( rc==SQLITE_OK ){ memcpy(pNode->block.a, aRoot, nRoot); pNode->block.n = nRoot; memset(&pNode->block.a[nRoot], 0, FTS3_NODE_PADDING); } for(i=nHeight; i>=0 && rc==SQLITE_OK; i--){ NodeReader reader; pNode = &pWriter->aNodeWriter[i]; if( pNode->block.a){ rc = nodeReaderInit(&reader, pNode->block.a, pNode->block.n); while( reader.aNode && rc==SQLITE_OK ) rc = nodeReaderNext(&reader); blobGrowBuffer(&pNode->key, reader.term.n, &rc); if( rc==SQLITE_OK ){ assert_fts3_nc( reader.term.n>0 || reader.aNode==0 ); if( reader.term.n>0 ){ memcpy(pNode->key.a, reader.term.a, reader.term.n); } pNode->key.n = reader.term.n; if( i>0 ){ char *aBlock = 0; int nBlock = 0; pNode = &pWriter->aNodeWriter[i-1]; pNode->iBlock = reader.iChild; rc = sqlite3Fts3ReadBlock(p, reader.iChild, &aBlock, &nBlock,0); blobGrowBuffer(&pNode->block, MAX(nBlock, p->nNodeSize)+FTS3_NODE_PADDING, &rc ); if( rc==SQLITE_OK ){ memcpy(pNode->block.a, aBlock, nBlock); pNode->block.n = nBlock; memset(&pNode->block.a[nBlock], 0, FTS3_NODE_PADDING); } sqlite3_free(aBlock); } } } nodeReaderRelease(&reader); } } rc2 = sqlite3_reset(pSelect); |
︙ | ︙ | |||
4528 4529 4530 4531 4532 4533 4534 | const char *zTerm, /* Omit all terms smaller than this */ int nTerm, /* Size of zTerm in bytes */ sqlite3_int64 *piBlock /* OUT: Block number in next layer down */ ){ NodeReader reader; /* Reader object */ Blob prev = {0, 0, 0}; /* Previous term written to new node */ int rc = SQLITE_OK; /* Return code */ | > > > | | 4606 4607 4608 4609 4610 4611 4612 4613 4614 4615 4616 4617 4618 4619 4620 4621 4622 4623 | const char *zTerm, /* Omit all terms smaller than this */ int nTerm, /* Size of zTerm in bytes */ sqlite3_int64 *piBlock /* OUT: Block number in next layer down */ ){ NodeReader reader; /* Reader object */ Blob prev = {0, 0, 0}; /* Previous term written to new node */ int rc = SQLITE_OK; /* Return code */ int bLeaf; /* True for a leaf node */ if( nNode<1 ) return FTS_CORRUPT_VTAB; bLeaf = aNode[0]=='\0'; /* Allocate required output space */ blobGrowBuffer(pNew, nNode, &rc); if( rc!=SQLITE_OK ) return rc; pNew->n = 0; /* Populate new node buffer */ |
︙ | ︙ | |||
4748 4749 4750 4751 4752 4753 4754 | sqlite3_bind_int(pSelect, 1, FTS_STAT_INCRMERGEHINT); if( SQLITE_ROW==sqlite3_step(pSelect) ){ const char *aHint = sqlite3_column_blob(pSelect, 0); int nHint = sqlite3_column_bytes(pSelect, 0); if( aHint ){ blobGrowBuffer(pHint, nHint, &rc); if( rc==SQLITE_OK ){ | | | 4829 4830 4831 4832 4833 4834 4835 4836 4837 4838 4839 4840 4841 4842 4843 | sqlite3_bind_int(pSelect, 1, FTS_STAT_INCRMERGEHINT); if( SQLITE_ROW==sqlite3_step(pSelect) ){ const char *aHint = sqlite3_column_blob(pSelect, 0); int nHint = sqlite3_column_bytes(pSelect, 0); if( aHint ){ blobGrowBuffer(pHint, nHint, &rc); if( rc==SQLITE_OK ){ if( ALWAYS(pHint->a!=0) ) memcpy(pHint->a, aHint, nHint); pHint->n = nHint; } } } rc2 = sqlite3_reset(pSelect); if( rc==SQLITE_OK ) rc = rc2; } |
︙ | ︙ | |||
4794 4795 4796 4797 4798 4799 4800 | ** If no error occurs, return SQLITE_OK. If the hint blob in *pHint does ** not contain at least two valid varints, return SQLITE_CORRUPT_VTAB. */ static int fts3IncrmergeHintPop(Blob *pHint, i64 *piAbsLevel, int *pnInput){ const int nHint = pHint->n; int i; | | > > > > | 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 | ** If no error occurs, return SQLITE_OK. If the hint blob in *pHint does ** not contain at least two valid varints, return SQLITE_CORRUPT_VTAB. */ static int fts3IncrmergeHintPop(Blob *pHint, i64 *piAbsLevel, int *pnInput){ const int nHint = pHint->n; int i; i = pHint->n-1; if( (pHint->a[i] & 0x80) ) return FTS_CORRUPT_VTAB; while( i>0 && (pHint->a[i-1] & 0x80) ) i--; if( i==0 ) return FTS_CORRUPT_VTAB; i--; while( i>0 && (pHint->a[i-1] & 0x80) ) i--; pHint->n = i; i += sqlite3Fts3GetVarint(&pHint->a[i], piAbsLevel); i += fts3GetVarint32(&pHint->a[i], pnInput); assert( i<=nHint ); if( i!=nHint ) return FTS_CORRUPT_VTAB; return SQLITE_OK; } /* |
︙ | ︙ | |||
4870 4871 4872 4873 4874 4875 4876 4877 | if( rc==SQLITE_OK && hint.n ){ int nHint = hint.n; sqlite3_int64 iHintAbsLevel = 0; /* Hint level */ int nHintSeg = 0; /* Hint number of segments */ rc = fts3IncrmergeHintPop(&hint, &iHintAbsLevel, &nHintSeg); if( nSeg<0 || (iAbsLevel % nMod) >= (iHintAbsLevel % nMod) ){ iAbsLevel = iHintAbsLevel; | > > > > > > | > > > > > | > | 4955 4956 4957 4958 4959 4960 4961 4962 4963 4964 4965 4966 4967 4968 4969 4970 4971 4972 4973 4974 4975 4976 4977 4978 4979 4980 4981 4982 4983 4984 4985 4986 4987 4988 4989 4990 4991 4992 4993 4994 4995 | if( rc==SQLITE_OK && hint.n ){ int nHint = hint.n; sqlite3_int64 iHintAbsLevel = 0; /* Hint level */ int nHintSeg = 0; /* Hint number of segments */ rc = fts3IncrmergeHintPop(&hint, &iHintAbsLevel, &nHintSeg); if( nSeg<0 || (iAbsLevel % nMod) >= (iHintAbsLevel % nMod) ){ /* Based on the scan in the block above, it is known that there ** are no levels with a relative level smaller than that of ** iAbsLevel with more than nSeg segments, or if nSeg is -1, ** no levels with more than nMin segments. Use this to limit the ** value of nHintSeg to avoid a large memory allocation in case the ** merge-hint is corrupt*/ iAbsLevel = iHintAbsLevel; nSeg = MIN(MAX(nMin,nSeg), nHintSeg); bUseHint = 1; bDirtyHint = 1; }else{ /* This undoes the effect of the HintPop() above - so that no entry ** is removed from the hint blob. */ hint.n = nHint; } } /* If nSeg is less that zero, then there is no level with at least ** nMin segments and no hint in the %_stat table. No work to do. ** Exit early in this case. */ if( nSeg<=0 ) break; assert( nMod<=0x7FFFFFFF ); if( iAbsLevel<0 || iAbsLevel>(nMod<<32) ){ rc = FTS_CORRUPT_VTAB; break; } /* Open a cursor to iterate through the contents of the oldest nSeg ** indexes of absolute level iAbsLevel. If this cursor is opened using ** the 'hint' parameters, it is possible that there are less than nSeg ** segments available in level iAbsLevel. In this case, no work is ** done on iAbsLevel - fall through to the next iteration of the loop ** to start work on some other level. */ |
︙ | ︙ | |||
4912 4913 4914 4915 4916 4917 4918 | } if( rc==SQLITE_OK ){ rc = fts3IncrmergeCsr(p, iAbsLevel, nSeg, pCsr); } if( SQLITE_OK==rc && pCsr->nSegment==nSeg && SQLITE_OK==(rc = sqlite3Fts3SegReaderStart(p, pCsr, pFilter)) | < > > > > > > > > > | | | | | > | 5009 5010 5011 5012 5013 5014 5015 5016 5017 5018 5019 5020 5021 5022 5023 5024 5025 5026 5027 5028 5029 5030 5031 5032 5033 5034 5035 5036 5037 5038 5039 5040 5041 5042 5043 5044 5045 5046 5047 5048 | } if( rc==SQLITE_OK ){ rc = fts3IncrmergeCsr(p, iAbsLevel, nSeg, pCsr); } if( SQLITE_OK==rc && pCsr->nSegment==nSeg && SQLITE_OK==(rc = sqlite3Fts3SegReaderStart(p, pCsr, pFilter)) ){ int bEmpty = 0; rc = sqlite3Fts3SegReaderStep(p, pCsr); if( rc==SQLITE_OK ){ bEmpty = 1; }else if( rc!=SQLITE_ROW ){ sqlite3Fts3SegReaderFinish(pCsr); break; } if( bUseHint && iIdx>0 ){ const char *zKey = pCsr->zTerm; int nKey = pCsr->nTerm; rc = fts3IncrmergeLoad(p, iAbsLevel, iIdx-1, zKey, nKey, pWriter); }else{ rc = fts3IncrmergeWriter(p, iAbsLevel, iIdx, pCsr, pWriter); } if( rc==SQLITE_OK && pWriter->nLeafEst ){ fts3LogMerge(nSeg, iAbsLevel); if( bEmpty==0 ){ do { rc = fts3IncrmergeAppend(p, pWriter, pCsr); if( rc==SQLITE_OK ) rc = sqlite3Fts3SegReaderStep(p, pCsr); if( pWriter->nWork>=nRem && rc==SQLITE_ROW ) rc = SQLITE_OK; }while( rc==SQLITE_ROW ); } /* Update or delete the input segments */ if( rc==SQLITE_OK ){ nRem -= (1 + pWriter->nWork); rc = fts3IncrmergeChomp(p, iAbsLevel, pCsr, &nSeg); if( nSeg!=0 ){ bDirtyHint = 1; |
︙ | ︙ | |||
4993 4994 4995 4996 4997 4998 4999 | ** before it will be selected for a merge, respectively. */ static int fts3DoIncrmerge( Fts3Table *p, /* FTS3 table handle */ const char *zParam /* Nul-terminated string containing "A,B" */ ){ int rc; | | | 5099 5100 5101 5102 5103 5104 5105 5106 5107 5108 5109 5110 5111 5112 5113 | ** before it will be selected for a merge, respectively. */ static int fts3DoIncrmerge( Fts3Table *p, /* FTS3 table handle */ const char *zParam /* Nul-terminated string containing "A,B" */ ){ int rc; int nMin = (MergeCount(p) / 2); int nMerge = 0; const char *z = zParam; /* Read the first integer value */ nMerge = fts3Getint(&z); /* If the first integer value is followed by a ',', read the second |
︙ | ︙ | |||
5038 5039 5040 5041 5042 5043 5044 | static int fts3DoAutoincrmerge( Fts3Table *p, /* FTS3 table handle */ const char *zParam /* Nul-terminated string containing boolean */ ){ int rc = SQLITE_OK; sqlite3_stmt *pStmt = 0; p->nAutoincrmerge = fts3Getint(&zParam); | | | 5144 5145 5146 5147 5148 5149 5150 5151 5152 5153 5154 5155 5156 5157 5158 | static int fts3DoAutoincrmerge( Fts3Table *p, /* FTS3 table handle */ const char *zParam /* Nul-terminated string containing boolean */ ){ int rc = SQLITE_OK; sqlite3_stmt *pStmt = 0; p->nAutoincrmerge = fts3Getint(&zParam); if( p->nAutoincrmerge==1 || p->nAutoincrmerge>MergeCount(p) ){ p->nAutoincrmerge = 8; } if( !p->bHasStat ){ assert( p->bFts4==0 ); sqlite3Fts3CreateStatTable(&rc, p); if( rc ) return rc; } |
︙ | ︙ | |||
5121 5122 5123 5124 5125 5126 5127 | if( rc==SQLITE_OK ){ while( SQLITE_ROW==(rc = sqlite3Fts3SegReaderStep(p, &csr)) ){ char *pCsr = csr.aDoclist; char *pEnd = &pCsr[csr.nDoclist]; i64 iDocid = 0; i64 iCol = 0; | | | | | > | > > > | 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 | if( rc==SQLITE_OK ){ while( SQLITE_ROW==(rc = sqlite3Fts3SegReaderStep(p, &csr)) ){ char *pCsr = csr.aDoclist; char *pEnd = &pCsr[csr.nDoclist]; i64 iDocid = 0; i64 iCol = 0; u64 iPos = 0; pCsr += sqlite3Fts3GetVarint(pCsr, &iDocid); while( pCsr<pEnd ){ u64 iVal = 0; pCsr += sqlite3Fts3GetVarintU(pCsr, &iVal); if( pCsr<pEnd ){ if( iVal==0 || iVal==1 ){ iCol = 0; iPos = 0; if( iVal ){ pCsr += sqlite3Fts3GetVarint(pCsr, &iCol); }else{ pCsr += sqlite3Fts3GetVarintU(pCsr, &iVal); if( p->bDescIdx ){ iDocid = (i64)((u64)iDocid - iVal); }else{ iDocid = (i64)((u64)iDocid + iVal); } } }else{ iPos += (iVal - 2); cksum = cksum ^ fts3ChecksumEntry( csr.zTerm, csr.nTerm, iLangid, iIndex, iDocid, (int)iCol, (int)iPos ); |
︙ | ︙ | |||
5208 5209 5210 5211 5212 5213 5214 | i64 iDocid = sqlite3_column_int64(pStmt, 0); int iLang = langidFromSelect(p, pStmt); int iCol; for(iCol=0; rc==SQLITE_OK && iCol<p->nColumn; iCol++){ if( p->abNotindexed[iCol]==0 ){ const char *zText = (const char *)sqlite3_column_text(pStmt, iCol+1); | < | | 5318 5319 5320 5321 5322 5323 5324 5325 5326 5327 5328 5329 5330 5331 5332 5333 5334 | i64 iDocid = sqlite3_column_int64(pStmt, 0); int iLang = langidFromSelect(p, pStmt); int iCol; for(iCol=0; rc==SQLITE_OK && iCol<p->nColumn; iCol++){ if( p->abNotindexed[iCol]==0 ){ const char *zText = (const char *)sqlite3_column_text(pStmt, iCol+1); sqlite3_tokenizer_cursor *pT = 0; rc = sqlite3Fts3OpenTokenizer(p->pTokenizer, iLang, zText, -1, &pT); while( rc==SQLITE_OK ){ char const *zToken; /* Buffer containing token */ int nToken = 0; /* Number of bytes in token */ int iDum1 = 0, iDum2 = 0; /* Dummy variables */ int iPos = 0; /* Position of token in zText */ rc = pModule->xNext(pT, &zToken, &nToken, &iDum1, &iDum2, &iPos); |
︙ | ︙ | |||
5296 5297 5298 5299 5300 5301 5302 | ** ** "INSERT INTO tbl(tbl) VALUES(<expr>)" ** ** Argument pVal contains the result of <expr>. Currently the only ** meaningful value to insert is the text 'optimize'. */ static int fts3SpecialInsert(Fts3Table *p, sqlite3_value *pVal){ | | | > > | | > | | | > | | | | < | > > | | > | | 5405 5406 5407 5408 5409 5410 5411 5412 5413 5414 5415 5416 5417 5418 5419 5420 5421 5422 5423 5424 5425 5426 5427 5428 5429 5430 5431 5432 5433 5434 5435 5436 5437 5438 5439 5440 5441 5442 5443 5444 5445 5446 5447 5448 5449 5450 5451 5452 5453 5454 5455 | ** ** "INSERT INTO tbl(tbl) VALUES(<expr>)" ** ** Argument pVal contains the result of <expr>. Currently the only ** meaningful value to insert is the text 'optimize'. */ static int fts3SpecialInsert(Fts3Table *p, sqlite3_value *pVal){ int rc = SQLITE_ERROR; /* Return Code */ const char *zVal = (const char *)sqlite3_value_text(pVal); int nVal = sqlite3_value_bytes(pVal); if( !zVal ){ return SQLITE_NOMEM; }else if( nVal==8 && 0==sqlite3_strnicmp(zVal, "optimize", 8) ){ rc = fts3DoOptimize(p, 0); }else if( nVal==7 && 0==sqlite3_strnicmp(zVal, "rebuild", 7) ){ rc = fts3DoRebuild(p); }else if( nVal==15 && 0==sqlite3_strnicmp(zVal, "integrity-check", 15) ){ rc = fts3DoIntegrityCheck(p); }else if( nVal>6 && 0==sqlite3_strnicmp(zVal, "merge=", 6) ){ rc = fts3DoIncrmerge(p, &zVal[6]); }else if( nVal>10 && 0==sqlite3_strnicmp(zVal, "automerge=", 10) ){ rc = fts3DoAutoincrmerge(p, &zVal[10]); #if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) }else{ int v; if( nVal>9 && 0==sqlite3_strnicmp(zVal, "nodesize=", 9) ){ v = atoi(&zVal[9]); if( v>=24 && v<=p->nPgsz-35 ) p->nNodeSize = v; rc = SQLITE_OK; }else if( nVal>11 && 0==sqlite3_strnicmp(zVal, "maxpending=", 9) ){ v = atoi(&zVal[11]); if( v>=64 && v<=FTS3_MAX_PENDING_DATA ) p->nMaxPendingData = v; rc = SQLITE_OK; }else if( nVal>21 && 0==sqlite3_strnicmp(zVal,"test-no-incr-doclist=",21) ){ p->bNoIncrDoclist = atoi(&zVal[21]); rc = SQLITE_OK; }else if( nVal>11 && 0==sqlite3_strnicmp(zVal,"mergecount=",11) ){ v = atoi(&zVal[11]); if( v>=4 && v<=FTS3_MERGE_COUNT && (v&1)==0 ) p->nMergeCount = v; rc = SQLITE_OK; } #endif } return rc; } #ifndef SQLITE_DISABLE_FTS4_DEFERRED /* ** Delete all cached deferred doclists. Deferred doclists are cached ** (allocated) by the sqlite3Fts3CacheDeferredDoclists() function. |
︙ | ︙ | |||
5567 5568 5569 5570 5571 5572 5573 | if( nArg>1 && sqlite3_value_int(apVal[2 + p->nColumn + 2])<0 ){ rc = SQLITE_CONSTRAINT; goto update_out; } /* Allocate space to hold the change in document sizes */ | | | 5682 5683 5684 5685 5686 5687 5688 5689 5690 5691 5692 5693 5694 5695 5696 | if( nArg>1 && sqlite3_value_int(apVal[2 + p->nColumn + 2])<0 ){ rc = SQLITE_CONSTRAINT; goto update_out; } /* Allocate space to hold the change in document sizes */ aSzDel = sqlite3_malloc64(sizeof(aSzDel[0])*((sqlite3_int64)p->nColumn+1)*2); if( aSzDel==0 ){ rc = SQLITE_NOMEM; goto update_out; } aSzIns = &aSzDel[p->nColumn+1]; memset(aSzDel, 0, sizeof(aSzDel[0])*(p->nColumn+1)*2); |
︙ | ︙ |
Changes to ext/fts3/tool/fts3view.c.
︙ | ︙ | |||
89 90 91 92 93 94 95 | /* ** Show the table schema */ static void showSchema(sqlite3 *db, const char *zTab){ sqlite3_stmt *pStmt; pStmt = prepare(db, | | | 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 | /* ** Show the table schema */ static void showSchema(sqlite3 *db, const char *zTab){ sqlite3_stmt *pStmt; pStmt = prepare(db, "SELECT sql FROM sqlite_schema" " WHERE name LIKE '%q%%'" " ORDER BY 1", zTab); while( sqlite3_step(pStmt)==SQLITE_ROW ){ printf("%s;\n", sqlite3_column_text(pStmt, 0)); } sqlite3_finalize(pStmt); |
︙ | ︙ | |||
827 828 829 830 831 832 833 | fprintf(stderr, "Cannot open %s\n", argv[1]); exit(1); } if( argc==2 ){ sqlite3_stmt *pStmt; int cnt = 0; pStmt = prepare(db, "SELECT b.sql" | | | 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 | fprintf(stderr, "Cannot open %s\n", argv[1]); exit(1); } if( argc==2 ){ sqlite3_stmt *pStmt; int cnt = 0; pStmt = prepare(db, "SELECT b.sql" " FROM sqlite_schema a, sqlite_schema b" " WHERE a.name GLOB '*_segdir'" " AND b.name=substr(a.name,1,length(a.name)-7)" " ORDER BY 1"); while( sqlite3_step(pStmt)==SQLITE_ROW ){ cnt++; printf("%s;\n", sqlite3_column_text(pStmt, 0)); } |
︙ | ︙ |
Changes to ext/fts3/unicode/mkunicode.tcl.
︙ | ︙ | |||
59 60 61 62 63 64 65 | incr i puts -nonewline [format "%5d" [expr ($iCode<<3) + $nRange-1]] puts -nonewline ", " } puts "" puts " \};" | > | | | | 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 | incr i puts -nonewline [format "%5d" [expr ($iCode<<3) + $nRange-1]] puts -nonewline ", " } puts "" puts " \};" puts "#define HIBIT ((unsigned char)0x80)" puts " unsigned char aChar\[\] = \{" puts -nonewline " '\\0', " set i 1 foreach c $aChar f $aFlag { if { $f } { set str "'$c'|HIBIT, " } else { set str "'$c', " } if {$c == ""} { set str "'\\0', " } if {($i % 6)==0} {puts "" ; puts -nonewline " " } incr i puts -nonewline "$str" } |
︙ | ︙ | |||
130 131 132 133 134 135 136 | puts "*/" puts "int ${zFunc}\(int c)\{" puts " unsigned int mask0 = [format "0x%08X" $i1];" puts " unsigned int mask1 = [format "0x%08X" $i2];" puts " if( c<$iFirst || c>$iLast ) return 0;" puts " return (c < $iFirst+32) ?" | | | | 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 | puts "*/" puts "int ${zFunc}\(int c)\{" puts " unsigned int mask0 = [format "0x%08X" $i1];" puts " unsigned int mask1 = [format "0x%08X" $i2];" puts " if( c<$iFirst || c>$iLast ) return 0;" puts " return (c < $iFirst+32) ?" puts " (mask0 & ((unsigned int)1 << (c-$iFirst))) :" puts " (mask1 & ((unsigned int)1 << (c-$iFirst-32)));" puts "\}" } #------------------------------------------------------------------------- proc an_load_separator_ranges {} { |
︙ | ︙ | |||
695 696 697 698 699 700 701 | set aMapArray [intarray $aMap] set aDataArray [intarray $aData] puts [code { static u16 aFts5UnicodeBlock[] = {$aBlockArray}; static u16 aFts5UnicodeMap[] = {$aMapArray}; static u16 aFts5UnicodeData[] = {$aDataArray}; | | | 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 | set aMapArray [intarray $aMap] set aDataArray [intarray $aData] puts [code { static u16 aFts5UnicodeBlock[] = {$aBlockArray}; static u16 aFts5UnicodeMap[] = {$aMapArray}; static u16 aFts5UnicodeData[] = {$aDataArray}; int sqlite3Fts5UnicodeCategory(u32 iCode) { int iRes = -1; int iHi; int iLo; int ret; u16 iKey; if( iCode>=(1<<20) ){ |
︙ | ︙ | |||
733 734 735 736 737 738 739 | void sqlite3Fts5UnicodeAscii(u8 *aArray, u8 *aAscii){ int i = 0; int iTbl = 0; while( i<128 ){ int bToken = aArray[ aFts5UnicodeData[iTbl] & 0x1F ]; int n = (aFts5UnicodeData[iTbl] >> 5) + i; for(; i<128 && i<n; i++){ | | > | 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 | void sqlite3Fts5UnicodeAscii(u8 *aArray, u8 *aAscii){ int i = 0; int iTbl = 0; while( i<128 ){ int bToken = aArray[ aFts5UnicodeData[iTbl] & 0x1F ]; int n = (aFts5UnicodeData[iTbl] >> 5) + i; for(; i<128 && i<n; i++){ aAscii[i] = (u8)bToken; } iTbl++; } aAscii[0] = 0; /* 0x00 is never a token character */ } }] } proc print_test_categories {lMap} { set lCP [list] |
︙ | ︙ | |||
778 779 780 781 782 783 784 | if( aCP[iCP].iCode==i ){ sqlite3Fts5UnicodeCatParse(aCP[iCP].zCat, aArray); iCP++; }else{ aArray[0] = 1; } | | | 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 | if( aCP[iCP].iCode==i ){ sqlite3Fts5UnicodeCatParse(aCP[iCP].zCat, aArray); iCP++; }else{ aArray[0] = 1; } c = sqlite3Fts5UnicodeCategory((u32)i); if( aArray[c]==0 ){ *piCode = i; return 1; } } return 0; |
︙ | ︙ | |||
833 834 835 836 837 838 839 | puts "\}" } proc print_fileheader {} { puts [string trim { /* | | | 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 | puts "\}" } proc print_fileheader {} { puts [string trim { /* ** 2012-05-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. |
︙ | ︙ |
Changes to ext/fts5/fts5.h.
︙ | ︙ | |||
116 117 118 119 120 121 122 | ** Query for the details of phrase match iIdx within the current row. ** Phrase matches are numbered starting from zero, so the iIdx argument ** should be greater than or equal to zero and smaller than the value ** output by xInstCount(). ** ** Usually, output parameter *piPhrase is set to the phrase number, *piCol ** to the column in which it occurs and *piOff the token offset of the | < < < < | | | 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 | ** Query for the details of phrase match iIdx within the current row. ** Phrase matches are numbered starting from zero, so the iIdx argument ** should be greater than or equal to zero and smaller than the value ** output by xInstCount(). ** ** Usually, output parameter *piPhrase is set to the phrase number, *piCol ** to the column in which it occurs and *piOff the token offset of the ** first token of the phrase. Returns SQLITE_OK if successful, or an error ** code (i.e. SQLITE_NOMEM) if an error occurs. ** ** This API can be quite slow if used with an FTS5 table created with the ** "detail=none" or "detail=column" option. ** ** xRowid: ** Returns the rowid of the current row. ** |
︙ | ︙ | |||
159 160 161 162 163 164 165 | ** If the query runs to completion without incident, SQLITE_OK is returned. ** Or, if some error occurs before the query completes or is aborted by ** the callback, an SQLite error code is returned. ** ** ** xSetAuxdata(pFts5, pAux, xDelete) ** | | | | | 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 | ** If the query runs to completion without incident, SQLITE_OK is returned. ** Or, if some error occurs before the query completes or is aborted by ** the callback, an SQLite error code is returned. ** ** ** xSetAuxdata(pFts5, pAux, xDelete) ** ** Save the pointer passed as the second argument as the extension function's ** "auxiliary data". The pointer may then be retrieved by the current or any ** future invocation of the same fts5 extension function made as part of ** the same MATCH query using the xGetAuxdata() API. ** ** Each extension function is allocated a single auxiliary data slot for ** each FTS query (MATCH expression). If the extension function is invoked ** more than once for a single FTS query, then all invocations share a ** single auxiliary data context. ** ** If there is already an auxiliary data pointer when this function is ** invoked, then it is replaced by the new pointer. If an xDelete callback ** was specified along with the original pointer, it is invoked at this ** point. ** ** The xDelete callback, if one is specified, is also invoked on the ** auxiliary data pointer after the FTS5 query has finished. ** ** If an error (e.g. an OOM condition) occurs within this function, ** the auxiliary data is set to NULL and an error code returned. If the ** xDelete parameter was not NULL, it is invoked on the auxiliary data ** pointer before returning. ** ** ** xGetAuxdata(pFts5, bClear) ** |
︙ | ︙ | |||
401 402 403 404 405 406 407 | ** of "first place" within the document set, but not alternative forms ** such as "1st place". In some applications, it would be better to match ** all instances of "first place" or "1st place" regardless of which form ** the user specified in the MATCH query text. ** ** There are several ways to approach this in FTS5: ** | | | | 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 | ** of "first place" within the document set, but not alternative forms ** such as "1st place". In some applications, it would be better to match ** all instances of "first place" or "1st place" regardless of which form ** the user specified in the MATCH query text. ** ** There are several ways to approach this in FTS5: ** ** <ol><li> By mapping all synonyms to a single token. In this case, using ** the above example, this means that the tokenizer returns the ** same token for inputs "first" and "1st". Say that token is in ** fact "first", so that when the user inserts the document "I won ** 1st place" entries are added to the index for tokens "i", "won", ** "first" and "place". If the user then queries for '1st + place', ** the tokenizer substitutes "first" for "1st" and the query works ** as expected. ** |
︙ | ︙ |
Changes to ext/fts5/fts5Int.h.
︙ | ︙ | |||
31 32 33 34 35 36 37 | typedef sqlite3_uint64 u64; #ifndef ArraySize # define ArraySize(x) ((int)(sizeof(x) / sizeof(x[0]))) #endif #define testcase(x) | > > > > > | | > > > > > > > | 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 | typedef sqlite3_uint64 u64; #ifndef ArraySize # define ArraySize(x) ((int)(sizeof(x) / sizeof(x[0]))) #endif #define testcase(x) #if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_MUTATION_TEST) # define SQLITE_OMIT_AUXILIARY_SAFETY_CHECKS 1 #endif #if defined(SQLITE_OMIT_AUXILIARY_SAFETY_CHECKS) # define ALWAYS(X) (1) # define NEVER(X) (0) #elif !defined(NDEBUG) # define ALWAYS(X) ((X)?1:(assert(0),0)) # define NEVER(X) ((X)?(assert(0),1):0) #else # define ALWAYS(X) (X) # define NEVER(X) (X) #endif #define MIN(x,y) (((x) < (y)) ? (x) : (y)) #define MAX(x,y) (((x) > (y)) ? (x) : (y)) /* ** Constants for the largest and smallest possible 64-bit signed integers. */ |
︙ | ︙ | |||
57 58 59 60 61 62 63 64 65 66 67 68 69 70 | /* ** Maximum number of prefix indexes on single FTS5 table. This must be ** less than 32. If it is set to anything large than that, an #error ** directive in fts5_index.c will cause the build to fail. */ #define FTS5_MAX_PREFIX_INDEXES 31 #define FTS5_DEFAULT_NEARDIST 10 #define FTS5_DEFAULT_RANK "bm25" /* Name of rank and rowid columns */ #define FTS5_RANK_NAME "rank" #define FTS5_ROWID_NAME "rowid" | > > > > > | 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 | /* ** Maximum number of prefix indexes on single FTS5 table. This must be ** less than 32. If it is set to anything large than that, an #error ** directive in fts5_index.c will cause the build to fail. */ #define FTS5_MAX_PREFIX_INDEXES 31 /* ** Maximum segments permitted in a single index */ #define FTS5_MAX_SEGMENT 2000 #define FTS5_DEFAULT_NEARDIST 10 #define FTS5_DEFAULT_RANK "bm25" /* Name of rank and rowid columns */ #define FTS5_RANK_NAME "rank" #define FTS5_ROWID_NAME "rowid" |
︙ | ︙ | |||
83 84 85 86 87 88 89 90 91 92 93 94 95 96 | #ifdef SQLITE_DEBUG extern int sqlite3_fts5_may_be_corrupt; # define assert_nc(x) assert(sqlite3_fts5_may_be_corrupt || (x)) #else # define assert_nc(x) assert(x) #endif /* Mark a function parameter as unused, to suppress nuisance compiler ** warnings. */ #ifndef UNUSED_PARAM # define UNUSED_PARAM(X) (void)(X) #endif #ifndef UNUSED_PARAM2 | > > > > > > | 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 | #ifdef SQLITE_DEBUG extern int sqlite3_fts5_may_be_corrupt; # define assert_nc(x) assert(sqlite3_fts5_may_be_corrupt || (x)) #else # define assert_nc(x) assert(x) #endif /* ** A version of memcmp() that does not cause asan errors if one of the pointer ** parameters is NULL and the number of bytes to compare is zero. */ #define fts5Memcmp(s1, s2, n) ((n)<=0 ? 0 : memcmp((s1), (s2), (n))) /* Mark a function parameter as unused, to suppress nuisance compiler ** warnings. */ #ifndef UNUSED_PARAM # define UNUSED_PARAM(X) (void)(X) #endif #ifndef UNUSED_PARAM2 |
︙ | ︙ | |||
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 | char *zContent; /* content table */ char *zContentRowid; /* "content_rowid=" option value */ int bColumnsize; /* "columnsize=" option value (dflt==1) */ int eDetail; /* FTS5_DETAIL_XXX value */ char *zContentExprlist; Fts5Tokenizer *pTok; fts5_tokenizer *pTokApi; /* Values loaded from the %_config table */ int iCookie; /* Incremented when %_config is modified */ int pgsz; /* Approximate page size used in %_data */ int nAutomerge; /* 'automerge' setting */ int nCrisisMerge; /* Maximum allowed segments per level */ int nUsermerge; /* 'usermerge' setting */ int nHashSize; /* Bytes of memory for in-memory hash */ char *zRank; /* Name of rank function */ char *zRankArgs; /* Arguments to rank function */ /* If non-NULL, points to sqlite3_vtab.base.zErrmsg. Often NULL. */ char **pzErrmsg; #ifdef SQLITE_DEBUG int bPrefixIndex; /* True to use prefix-indexes */ #endif }; /* Current expected value of %_config table 'version' field */ | > > | | | | | > > | 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 | char *zContent; /* content table */ char *zContentRowid; /* "content_rowid=" option value */ int bColumnsize; /* "columnsize=" option value (dflt==1) */ int eDetail; /* FTS5_DETAIL_XXX value */ char *zContentExprlist; Fts5Tokenizer *pTok; fts5_tokenizer *pTokApi; int bLock; /* True when table is preparing statement */ int ePattern; /* FTS_PATTERN_XXX constant */ /* Values loaded from the %_config table */ int iCookie; /* Incremented when %_config is modified */ int pgsz; /* Approximate page size used in %_data */ int nAutomerge; /* 'automerge' setting */ int nCrisisMerge; /* Maximum allowed segments per level */ int nUsermerge; /* 'usermerge' setting */ int nHashSize; /* Bytes of memory for in-memory hash */ char *zRank; /* Name of rank function */ char *zRankArgs; /* Arguments to rank function */ /* If non-NULL, points to sqlite3_vtab.base.zErrmsg. Often NULL. */ char **pzErrmsg; #ifdef SQLITE_DEBUG int bPrefixIndex; /* True to use prefix-indexes */ #endif }; /* Current expected value of %_config table 'version' field */ #define FTS5_CURRENT_VERSION 4 #define FTS5_CONTENT_NORMAL 0 #define FTS5_CONTENT_NONE 1 #define FTS5_CONTENT_EXTERNAL 2 #define FTS5_DETAIL_FULL 0 #define FTS5_DETAIL_NONE 1 #define FTS5_DETAIL_COLUMNS 2 #define FTS5_PATTERN_NONE 0 #define FTS5_PATTERN_LIKE 65 /* matches SQLITE_INDEX_CONSTRAINT_LIKE */ #define FTS5_PATTERN_GLOB 66 /* matches SQLITE_INDEX_CONSTRAINT_GLOB */ int sqlite3Fts5ConfigParse( Fts5Global*, sqlite3*, int, const char **, Fts5Config**, char** ); void sqlite3Fts5ConfigFree(Fts5Config*); int sqlite3Fts5ConfigDeclareVtab(Fts5Config *pConfig); |
︙ | ︙ | |||
270 271 272 273 274 275 276 | ) /* Write and decode big-endian 32-bit integer values */ void sqlite3Fts5Put32(u8*, int); int sqlite3Fts5Get32(const u8*); #define FTS5_POS2COLUMN(iPos) (int)(iPos >> 32) | | | 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 | ) /* Write and decode big-endian 32-bit integer values */ void sqlite3Fts5Put32(u8*, int); int sqlite3Fts5Get32(const u8*); #define FTS5_POS2COLUMN(iPos) (int)(iPos >> 32) #define FTS5_POS2OFFSET(iPos) (int)(iPos & 0x7FFFFFFF) typedef struct Fts5PoslistReader Fts5PoslistReader; struct Fts5PoslistReader { /* Variables used only by sqlite3Fts5PoslistIterXXX() functions. */ const u8 *a; /* Position list to iterate through */ int n; /* Size of buffer at a[] in bytes */ int i; /* Current offset in a[] */ |
︙ | ︙ | |||
305 306 307 308 309 310 311 | int sqlite3Fts5PoslistNext64( const u8 *a, int n, /* Buffer containing poslist */ int *pi, /* IN/OUT: Offset within a[] */ i64 *piOff /* IN/OUT: Current offset */ ); /* Malloc utility */ | | | 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 | int sqlite3Fts5PoslistNext64( const u8 *a, int n, /* Buffer containing poslist */ int *pi, /* IN/OUT: Offset within a[] */ i64 *piOff /* IN/OUT: Current offset */ ); /* Malloc utility */ void *sqlite3Fts5MallocZero(int *pRc, sqlite3_int64 nByte); char *sqlite3Fts5Strndup(int *pRc, const char *pIn, int nIn); /* Character set tests (like isspace(), isalpha() etc.) */ int sqlite3Fts5IsBareword(char t); /* Bucket of terms object used by the integrity-check in offsets=0 mode. */ |
︙ | ︙ | |||
406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 | int sqlite3Fts5IterNextFrom(Fts5IndexIter*, i64 iMatch); /* ** Close an iterator opened by sqlite3Fts5IndexQuery(). */ void sqlite3Fts5IterClose(Fts5IndexIter*); /* ** This interface is used by the fts5vocab module. */ const char *sqlite3Fts5IterTerm(Fts5IndexIter*, int*); int sqlite3Fts5IterNextScan(Fts5IndexIter*); /* ** Insert or remove data to or from the index. Each time a document is ** added to or removed from the index, this function is called one or more ** times. ** | > > > > > > > > | 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 | int sqlite3Fts5IterNextFrom(Fts5IndexIter*, i64 iMatch); /* ** Close an iterator opened by sqlite3Fts5IndexQuery(). */ void sqlite3Fts5IterClose(Fts5IndexIter*); /* ** Close the reader blob handle, if it is open. */ void sqlite3Fts5IndexCloseReader(Fts5Index*); /* ** This interface is used by the fts5vocab module. */ const char *sqlite3Fts5IterTerm(Fts5IndexIter*, int*); int sqlite3Fts5IterNextScan(Fts5IndexIter*); void *sqlite3Fts5StructureRef(Fts5Index*); void sqlite3Fts5StructureRelease(void*); int sqlite3Fts5StructureTest(Fts5Index*, void*); /* ** Insert or remove data to or from the index. Each time a document is ** added to or removed from the index, this function is called one or more ** times. ** |
︙ | ︙ | |||
463 464 465 466 467 468 469 | */ int sqlite3Fts5IndexGetAverages(Fts5Index *p, i64 *pnRow, i64 *anSize); int sqlite3Fts5IndexSetAverages(Fts5Index *p, const u8*, int); /* ** Functions called by the storage module as part of integrity-check. */ | | | 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 | */ int sqlite3Fts5IndexGetAverages(Fts5Index *p, i64 *pnRow, i64 *anSize); int sqlite3Fts5IndexSetAverages(Fts5Index *p, const u8*, int); /* ** Functions called by the storage module as part of integrity-check. */ int sqlite3Fts5IndexIntegrityCheck(Fts5Index*, u64 cksum, int bUseCksum); /* ** Called during virtual module initialization to register UDF ** fts5_decode() with SQLite */ int sqlite3Fts5IndexInit(sqlite3*); |
︙ | ︙ | |||
516 517 518 519 520 521 522 | /* ** End of interface to code in fts5_varint.c. **************************************************************************/ /************************************************************************** | | > > > > > > > > > > | < | > > | 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 | /* ** End of interface to code in fts5_varint.c. **************************************************************************/ /************************************************************************** ** Interface to code in fts5_main.c. */ /* ** Virtual-table object. */ typedef struct Fts5Table Fts5Table; struct Fts5Table { sqlite3_vtab base; /* Base class used by SQLite core */ Fts5Config *pConfig; /* Virtual table configuration */ Fts5Index *pIndex; /* Full-text index */ }; int sqlite3Fts5GetTokenizer( Fts5Global*, const char **azArg, int nArg, Fts5Config*, char **pzErr ); Fts5Table *sqlite3Fts5TableFromCsrid(Fts5Global*, i64); int sqlite3Fts5FlushToDisk(Fts5Table*); /* ** End of interface to code in fts5.c. **************************************************************************/ /************************************************************************** ** Interface to code in fts5_hash.c. |
︙ | ︙ | |||
561 562 563 564 565 566 567 568 | /* ** Empty (but do not delete) a hash table. */ void sqlite3Fts5HashClear(Fts5Hash*); int sqlite3Fts5HashQuery( Fts5Hash*, /* Hash table to query */ const char *pTerm, int nTerm, /* Query term */ | > | | 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 | /* ** Empty (but do not delete) a hash table. */ void sqlite3Fts5HashClear(Fts5Hash*); int sqlite3Fts5HashQuery( Fts5Hash*, /* Hash table to query */ int nPre, const char *pTerm, int nTerm, /* Query term */ void **ppObj, /* OUT: Pointer to doclist for pTerm */ int *pnDoclist /* OUT: Size of doclist in bytes */ ); int sqlite3Fts5HashScanInit( Fts5Hash*, /* Hash table to query */ const char *pTerm, int nTerm /* Query prefix */ ); |
︙ | ︙ | |||
605 606 607 608 609 610 611 | int sqlite3Fts5DropAll(Fts5Config*); int sqlite3Fts5CreateTable(Fts5Config*, const char*, const char*, int, char **); int sqlite3Fts5StorageDelete(Fts5Storage *p, i64, sqlite3_value**); int sqlite3Fts5StorageContentInsert(Fts5Storage *p, sqlite3_value**, i64*); int sqlite3Fts5StorageIndexInsert(Fts5Storage *p, sqlite3_value**, i64); | | | 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 | int sqlite3Fts5DropAll(Fts5Config*); int sqlite3Fts5CreateTable(Fts5Config*, const char*, const char*, int, char **); int sqlite3Fts5StorageDelete(Fts5Storage *p, i64, sqlite3_value**); int sqlite3Fts5StorageContentInsert(Fts5Storage *p, sqlite3_value**, i64*); int sqlite3Fts5StorageIndexInsert(Fts5Storage *p, sqlite3_value**, i64); int sqlite3Fts5StorageIntegrity(Fts5Storage *p, int iArg); int sqlite3Fts5StorageStmt(Fts5Storage *p, int eStmt, sqlite3_stmt**, char**); void sqlite3Fts5StorageStmtRelease(Fts5Storage *p, int eStmt, sqlite3_stmt*); int sqlite3Fts5StorageDocsize(Fts5Storage *p, i64 iRowid, int *aCol); int sqlite3Fts5StorageSize(Fts5Storage *p, int iCol, i64 *pnAvg); int sqlite3Fts5StorageRowCount(Fts5Storage *p, i64 *pnRow); |
︙ | ︙ | |||
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 | const char *p; /* Token text (not NULL terminated) */ int n; /* Size of buffer p in bytes */ }; /* Parse a MATCH expression. */ int sqlite3Fts5ExprNew( Fts5Config *pConfig, int iCol, /* Column on LHS of MATCH operator */ const char *zExpr, Fts5Expr **ppNew, char **pzErr ); /* ** for(rc = sqlite3Fts5ExprFirst(pExpr, pIdx, bDesc); ** rc==SQLITE_OK && 0==sqlite3Fts5ExprEof(pExpr); ** rc = sqlite3Fts5ExprNext(pExpr) ** ){ ** // The document with rowid iRowid matches the expression! ** i64 iRowid = sqlite3Fts5ExprRowid(pExpr); ** } */ int sqlite3Fts5ExprFirst(Fts5Expr*, Fts5Index *pIdx, i64 iMin, int bDesc); int sqlite3Fts5ExprNext(Fts5Expr*, i64 iMax); int sqlite3Fts5ExprEof(Fts5Expr*); i64 sqlite3Fts5ExprRowid(Fts5Expr*); void sqlite3Fts5ExprFree(Fts5Expr*); /* Called during startup to register a UDF with SQLite */ int sqlite3Fts5ExprInit(Fts5Global*, sqlite3*); int sqlite3Fts5ExprPhraseCount(Fts5Expr*); int sqlite3Fts5ExprPhraseSize(Fts5Expr*, int iPhrase); int sqlite3Fts5ExprPoslist(Fts5Expr*, int, const u8 **); | > > > > > > > > > | 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 | const char *p; /* Token text (not NULL terminated) */ int n; /* Size of buffer p in bytes */ }; /* Parse a MATCH expression. */ int sqlite3Fts5ExprNew( Fts5Config *pConfig, int bPhraseToAnd, int iCol, /* Column on LHS of MATCH operator */ const char *zExpr, Fts5Expr **ppNew, char **pzErr ); int sqlite3Fts5ExprPattern( Fts5Config *pConfig, int bGlob, int iCol, const char *zText, Fts5Expr **pp ); /* ** for(rc = sqlite3Fts5ExprFirst(pExpr, pIdx, bDesc); ** rc==SQLITE_OK && 0==sqlite3Fts5ExprEof(pExpr); ** rc = sqlite3Fts5ExprNext(pExpr) ** ){ ** // The document with rowid iRowid matches the expression! ** i64 iRowid = sqlite3Fts5ExprRowid(pExpr); ** } */ int sqlite3Fts5ExprFirst(Fts5Expr*, Fts5Index *pIdx, i64 iMin, int bDesc); int sqlite3Fts5ExprNext(Fts5Expr*, i64 iMax); int sqlite3Fts5ExprEof(Fts5Expr*); i64 sqlite3Fts5ExprRowid(Fts5Expr*); void sqlite3Fts5ExprFree(Fts5Expr*); int sqlite3Fts5ExprAnd(Fts5Expr **pp1, Fts5Expr *p2); /* Called during startup to register a UDF with SQLite */ int sqlite3Fts5ExprInit(Fts5Global*, sqlite3*); int sqlite3Fts5ExprPhraseCount(Fts5Expr*); int sqlite3Fts5ExprPhraseSize(Fts5Expr*, int iPhrase); int sqlite3Fts5ExprPoslist(Fts5Expr*, int, const u8 **); |
︙ | ︙ | |||
762 763 764 765 766 767 768 769 770 771 772 773 774 775 | **************************************************************************/ /************************************************************************** ** Interface to code in fts5_tokenizer.c. */ int sqlite3Fts5TokenizerInit(fts5_api*); /* ** End of interface to code in fts5_tokenizer.c. **************************************************************************/ /************************************************************************** ** Interface to code in fts5_vocab.c. */ | > > > > | 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 | **************************************************************************/ /************************************************************************** ** Interface to code in fts5_tokenizer.c. */ int sqlite3Fts5TokenizerInit(fts5_api*); int sqlite3Fts5TokenizerPattern( int (*xCreate)(void*, const char**, int, Fts5Tokenizer**), Fts5Tokenizer *pTok ); /* ** End of interface to code in fts5_tokenizer.c. **************************************************************************/ /************************************************************************** ** Interface to code in fts5_vocab.c. */ |
︙ | ︙ | |||
784 785 786 787 788 789 790 | /************************************************************************** ** Interface to automatically generated code in fts5_unicode2.c. */ int sqlite3Fts5UnicodeIsdiacritic(int c); int sqlite3Fts5UnicodeFold(int c, int bRemoveDiacritic); int sqlite3Fts5UnicodeCatParse(const char*, u8*); | | | 844 845 846 847 848 849 850 851 852 853 854 855 856 857 | /************************************************************************** ** Interface to automatically generated code in fts5_unicode2.c. */ int sqlite3Fts5UnicodeIsdiacritic(int c); int sqlite3Fts5UnicodeFold(int c, int bRemoveDiacritic); int sqlite3Fts5UnicodeCatParse(const char*, u8*); int sqlite3Fts5UnicodeCategory(u32 iCode); void sqlite3Fts5UnicodeAscii(u8*, u8*); /* ** End of interface to code in fts5_unicode2.c. **************************************************************************/ #endif |
Changes to ext/fts5/fts5_aux.c.
︙ | ︙ | |||
132 133 134 135 136 137 138 | ** *pRc is set to an error code before returning. */ static void fts5HighlightAppend( int *pRc, HighlightContext *p, const char *z, int n ){ | | | 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 | ** *pRc is set to an error code before returning. */ static void fts5HighlightAppend( int *pRc, HighlightContext *p, const char *z, int n ){ if( *pRc==SQLITE_OK && z ){ if( n<0 ) n = (int)strlen(z); p->zOut = sqlite3_mprintf("%z%.*s", p->zOut, n, z); if( p->zOut==0 ) *pRc = SQLITE_NOMEM; } } /* |
︙ | ︙ | |||
264 265 266 267 268 269 270 | ** error occurs. */ static int fts5SentenceFinderAdd(Fts5SFinder *p, int iAdd){ if( p->nFirstAlloc==p->nFirst ){ int nNew = p->nFirstAlloc ? p->nFirstAlloc*2 : 64; int *aNew; | | | 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 | ** error occurs. */ static int fts5SentenceFinderAdd(Fts5SFinder *p, int iAdd){ if( p->nFirstAlloc==p->nFirst ){ int nNew = p->nFirstAlloc ? p->nFirstAlloc*2 : 64; int *aNew; aNew = (int*)sqlite3_realloc64(p->aFirst, nNew*sizeof(int)); if( aNew==0 ) return SQLITE_NOMEM; p->aFirst = aNew; p->nFirstAlloc = nNew; } p->aFirst[p->nFirst++] = iAdd; return SQLITE_OK; } |
︙ | ︙ | |||
331 332 333 334 335 336 337 338 339 340 341 | int ip = 0; int ic = 0; int iOff = 0; int iFirst = -1; int nInst; int nScore = 0; int iLast = 0; rc = pApi->xInstCount(pFts, &nInst); for(i=0; i<nInst && rc==SQLITE_OK; i++){ rc = pApi->xInst(pFts, i, &ip, &ic, &iOff); | > | | | | 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 | int ip = 0; int ic = 0; int iOff = 0; int iFirst = -1; int nInst; int nScore = 0; int iLast = 0; sqlite3_int64 iEnd = (sqlite3_int64)iPos + nToken; rc = pApi->xInstCount(pFts, &nInst); for(i=0; i<nInst && rc==SQLITE_OK; i++){ rc = pApi->xInst(pFts, i, &ip, &ic, &iOff); if( rc==SQLITE_OK && ic==iCol && iOff>=iPos && iOff<iEnd ){ nScore += (aSeen[ip] ? 1 : 1000); aSeen[ip] = 1; if( iFirst<0 ) iFirst = iOff; iLast = iOff + pApi->xPhraseSize(pFts, ip); } } *pnScore = nScore; if( piPos ){ sqlite3_int64 iAdj = iFirst - (nToken - (iLast-iFirst)) / 2; if( (iAdj+nToken)>nDocsize ) iAdj = nDocsize - nToken; if( iAdj<0 ) iAdj = 0; *piPos = (int)iAdj; } return rc; } /* ** Return the value in pVal interpreted as utf-8 text. Except, if pVal |
︙ | ︙ | |||
438 439 440 441 442 443 444 | for(ii=0; rc==SQLITE_OK && ii<nInst; ii++){ int ip, ic, io; int iAdj; int nScore; int jj; rc = pApi->xInst(pFts, ii, &ip, &ic, &io); | > > | | 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 | for(ii=0; rc==SQLITE_OK && ii<nInst; ii++){ int ip, ic, io; int iAdj; int nScore; int jj; rc = pApi->xInst(pFts, ii, &ip, &ic, &io); if( ic!=i ) continue; if( io>nDocsize ) rc = FTS5_CORRUPT; if( rc!=SQLITE_OK ) continue; memset(aSeen, 0, nPhrase); rc = fts5SnippetScore(pApi, pFts, nDocsize, aSeen, i, io, nToken, &nScore, &iAdj ); if( rc==SQLITE_OK && nScore>nBestScore ){ nBestScore = nScore; iBestCol = i; |
︙ | ︙ | |||
559 560 561 562 563 564 565 | const Fts5ExtensionApi *pApi, Fts5Context *pFts, Fts5Bm25Data **ppData /* OUT: bm25-data object for this query */ ){ int rc = SQLITE_OK; /* Return code */ Fts5Bm25Data *p; /* Object to return */ | | | | | > | 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 | const Fts5ExtensionApi *pApi, Fts5Context *pFts, Fts5Bm25Data **ppData /* OUT: bm25-data object for this query */ ){ int rc = SQLITE_OK; /* Return code */ Fts5Bm25Data *p; /* Object to return */ p = (Fts5Bm25Data*)pApi->xGetAuxdata(pFts, 0); if( p==0 ){ int nPhrase; /* Number of phrases in query */ sqlite3_int64 nRow = 0; /* Number of rows in table */ sqlite3_int64 nToken = 0; /* Number of tokens in table */ sqlite3_int64 nByte; /* Bytes of space to allocate */ int i; /* Allocate the Fts5Bm25Data object */ nPhrase = pApi->xPhraseCount(pFts); nByte = sizeof(Fts5Bm25Data) + nPhrase*2*sizeof(double); p = (Fts5Bm25Data*)sqlite3_malloc64(nByte); if( p==0 ){ rc = SQLITE_NOMEM; }else{ memset(p, 0, (size_t)nByte); p->nPhrase = nPhrase; p->aIDF = (double*)&p[1]; p->aFreq = &p->aIDF[nPhrase]; } /* Calculate the average document length for this FTS5 table */ if( rc==SQLITE_OK ) rc = pApi->xRowCount(pFts, &nRow); assert( rc!=SQLITE_OK || nRow>0 ); if( rc==SQLITE_OK ) rc = pApi->xColumnTotalSize(pFts, -1, &nToken); if( rc==SQLITE_OK ) p->avgdl = (double)nToken / (double)nRow; /* Calculate an IDF for each phrase in the query */ for(i=0; rc==SQLITE_OK && i<nPhrase; i++){ sqlite3_int64 nHit = 0; rc = pApi->xQueryPhrase(pFts, i, (void*)&nHit, fts5CountCb); |
︙ | ︙ | |||
632 633 634 635 636 637 638 | Fts5Context *pFts, /* First arg to pass to pApi functions */ sqlite3_context *pCtx, /* Context for returning result/error */ int nVal, /* Number of values in apVal[] array */ sqlite3_value **apVal /* Array of trailing arguments */ ){ const double k1 = 1.2; /* Constant "k1" from BM25 formula */ const double b = 0.75; /* Constant "b" from BM25 formula */ | | | 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 | Fts5Context *pFts, /* First arg to pass to pApi functions */ sqlite3_context *pCtx, /* Context for returning result/error */ int nVal, /* Number of values in apVal[] array */ sqlite3_value **apVal /* Array of trailing arguments */ ){ const double k1 = 1.2; /* Constant "k1" from BM25 formula */ const double b = 0.75; /* Constant "b" from BM25 formula */ int rc; /* Error code */ double score = 0.0; /* SQL function return value */ Fts5Bm25Data *pData; /* Values allocated/calculated once only */ int i; /* Iterator variable */ int nInst = 0; /* Value returned by xInstCount() */ double D = 0.0; /* Total number of tokens in row */ double *aFreq = 0; /* Array of phrase freq. for current row */ |
︙ | ︙ | |||
664 665 666 667 668 669 670 | /* Figure out the total size of the current row in tokens. */ if( rc==SQLITE_OK ){ int nTok; rc = pApi->xColumnSize(pFts, -1, &nTok); D = (double)nTok; } | | > > | | | | | | < < < < | 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 | /* Figure out the total size of the current row in tokens. */ if( rc==SQLITE_OK ){ int nTok; rc = pApi->xColumnSize(pFts, -1, &nTok); D = (double)nTok; } /* Determine and return the BM25 score for the current row. Or, if an ** error has occurred, throw an exception. */ if( rc==SQLITE_OK ){ for(i=0; i<pData->nPhrase; i++){ score += pData->aIDF[i] * ( ( aFreq[i] * (k1 + 1.0) ) / ( aFreq[i] + k1 * (1 - b + b * D / pData->avgdl) ) ); } sqlite3_result_double(pCtx, -1.0 * score); }else{ sqlite3_result_error_code(pCtx, rc); } } int sqlite3Fts5AuxInit(fts5_api *pApi){ |
︙ | ︙ | |||
706 707 708 709 710 711 712 | aBuiltin[i].xFunc, aBuiltin[i].xDestroy ); } return rc; } | < < | 708 709 710 711 712 713 714 | aBuiltin[i].xFunc, aBuiltin[i].xDestroy ); } return rc; } |
Changes to ext/fts5/fts5_buffer.c.
︙ | ︙ | |||
13 14 15 16 17 18 19 | #include "fts5Int.h" int sqlite3Fts5BufferSize(int *pRc, Fts5Buffer *pBuf, u32 nByte){ if( (u32)pBuf->nSpace<nByte ){ | | | | | 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 | #include "fts5Int.h" int sqlite3Fts5BufferSize(int *pRc, Fts5Buffer *pBuf, u32 nByte){ if( (u32)pBuf->nSpace<nByte ){ u64 nNew = pBuf->nSpace ? pBuf->nSpace : 64; u8 *pNew; while( nNew<nByte ){ nNew = nNew * 2; } pNew = sqlite3_realloc64(pBuf->p, nNew); if( pNew==0 ){ *pRc = SQLITE_NOMEM; return 1; }else{ pBuf->nSpace = (int)nNew; pBuf->p = pNew; } } return 0; } |
︙ | ︙ | |||
48 49 50 51 52 53 54 | aBuf[0] = (iVal>>24) & 0x00FF; aBuf[1] = (iVal>>16) & 0x00FF; aBuf[2] = (iVal>> 8) & 0x00FF; aBuf[3] = (iVal>> 0) & 0x00FF; } int sqlite3Fts5Get32(const u8 *aBuf){ | | < | 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 | aBuf[0] = (iVal>>24) & 0x00FF; aBuf[1] = (iVal>>16) & 0x00FF; aBuf[2] = (iVal>> 8) & 0x00FF; aBuf[3] = (iVal>> 0) & 0x00FF; } int sqlite3Fts5Get32(const u8 *aBuf){ return (int)((((u32)aBuf[0])<<24) + (aBuf[1]<<16) + (aBuf[2]<<8) + aBuf[3]); } /* ** Append buffer nData/pData to buffer pBuf. If an OOM error occurs, set ** the error code in p. If an error has already occurred when this function ** is called, it is a no-op. */ void sqlite3Fts5BufferAppendBlob( int *pRc, Fts5Buffer *pBuf, u32 nData, const u8 *pData ){ if( nData ){ if( fts5BufferGrow(pRc, pBuf, nData) ) return; memcpy(&pBuf->p[pBuf->n], pData, nData); pBuf->n += nData; } } |
︙ | ︙ | |||
172 173 174 175 176 177 178 | int i = *pi; if( i>=n ){ /* EOF */ *piOff = -1; return 1; }else{ i64 iOff = *piOff; | | | > > > > > > > > > | | > > > > | 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 | int i = *pi; if( i>=n ){ /* EOF */ *piOff = -1; return 1; }else{ i64 iOff = *piOff; u32 iVal; fts5FastGetVarint32(a, i, iVal); if( iVal<=1 ){ if( iVal==0 ){ *pi = i; return 0; } fts5FastGetVarint32(a, i, iVal); iOff = ((i64)iVal) << 32; assert( iOff>=0 ); fts5FastGetVarint32(a, i, iVal); if( iVal<2 ){ /* This is a corrupt record. So stop parsing it here. */ *piOff = -1; return 1; } *piOff = iOff + ((iVal-2) & 0x7FFFFFFF); }else{ *piOff = (iOff & (i64)0x7FFFFFFF<<32)+((iOff + (iVal-2)) & 0x7FFFFFFF); } *pi = i; assert_nc( *piOff>=iOff ); return 0; } } /* ** Advance the iterator object passed as the only argument. Return true |
︙ | ︙ | |||
219 220 221 222 223 224 225 | ** to iPos before returning. */ void sqlite3Fts5PoslistSafeAppend( Fts5Buffer *pBuf, i64 *piPrev, i64 iPos ){ | > | | | | | | | | > | | | | 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 | ** to iPos before returning. */ void sqlite3Fts5PoslistSafeAppend( Fts5Buffer *pBuf, i64 *piPrev, i64 iPos ){ if( iPos>=*piPrev ){ static const i64 colmask = ((i64)(0x7FFFFFFF)) << 32; if( (iPos & colmask) != (*piPrev & colmask) ){ pBuf->p[pBuf->n++] = 1; pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], (iPos>>32)); *piPrev = (iPos & colmask); } pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], (iPos-*piPrev)+2); *piPrev = iPos; } } int sqlite3Fts5PoslistWriterAppend( Fts5Buffer *pBuf, Fts5PoslistWriter *pWriter, i64 iPos ){ int rc = 0; /* Initialized only to suppress erroneous warning from Clang */ if( fts5BufferGrow(&rc, pBuf, 5+5+5) ) return rc; sqlite3Fts5PoslistSafeAppend(pBuf, &pWriter->iPrev, iPos); return SQLITE_OK; } void *sqlite3Fts5MallocZero(int *pRc, sqlite3_int64 nByte){ void *pRet = 0; if( *pRc==SQLITE_OK ){ pRet = sqlite3_malloc64(nByte); if( pRet==0 ){ if( nByte>0 ) *pRc = SQLITE_NOMEM; }else{ memset(pRet, 0, (size_t)nByte); } } return pRet; } /* ** Return a nul-terminated copy of the string indicated by pIn. If nIn |
︙ | ︙ |
Changes to ext/fts5/fts5_config.c.
︙ | ︙ | |||
19 20 21 22 23 24 25 | #define FTS5_DEFAULT_PAGE_SIZE 4050 #define FTS5_DEFAULT_AUTOMERGE 4 #define FTS5_DEFAULT_USERMERGE 4 #define FTS5_DEFAULT_CRISISMERGE 16 #define FTS5_DEFAULT_HASHSIZE (1024*1024) /* Maximum allowed page size */ | | | 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | #define FTS5_DEFAULT_PAGE_SIZE 4050 #define FTS5_DEFAULT_AUTOMERGE 4 #define FTS5_DEFAULT_USERMERGE 4 #define FTS5_DEFAULT_CRISISMERGE 16 #define FTS5_DEFAULT_HASHSIZE (1024*1024) /* Maximum allowed page size */ #define FTS5_MAX_PAGE_SIZE (64*1024) static int fts5_iswhitespace(char x){ return (x==' '); } static int fts5_isopenquote(char x){ return (x=='"' || x=='\'' || x=='[' || x=='`'); |
︙ | ︙ | |||
146 147 148 149 150 151 152 | int iOut = 0; q = z[0]; /* Set stack variable q to the close-quote character */ assert( q=='[' || q=='\'' || q=='"' || q=='`' ); if( q=='[' ) q = ']'; | | | 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 | int iOut = 0; q = z[0]; /* Set stack variable q to the close-quote character */ assert( q=='[' || q=='\'' || q=='"' || q=='`' ); if( q=='[' ) q = ']'; while( z[iIn] ){ if( z[iIn]==q ){ if( z[iIn+1]!=q ){ /* Character iIn was the close quote. */ iIn++; break; }else{ /* Character iIn and iIn+1 form an escaped quote character. Skip |
︙ | ︙ | |||
291 292 293 294 295 296 297 | } assert( pConfig->nPrefix<=FTS5_MAX_PREFIX_INDEXES ); return rc; } if( sqlite3_strnicmp("tokenize", zCmd, nCmd)==0 ){ const char *p = (const char*)zArg; | | | 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 | } assert( pConfig->nPrefix<=FTS5_MAX_PREFIX_INDEXES ); return rc; } if( sqlite3_strnicmp("tokenize", zCmd, nCmd)==0 ){ const char *p = (const char*)zArg; sqlite3_int64 nArg = strlen(zArg) + 1; char **azArg = sqlite3Fts5MallocZero(&rc, sizeof(char*) * nArg); char *pDel = sqlite3Fts5MallocZero(&rc, nArg * 2); char *pSpace = pDel; if( azArg && pSpace ){ if( pConfig->pTok ){ *pzErr = sqlite3_mprintf("multiple tokenize=... directives"); |
︙ | ︙ | |||
321 322 323 324 325 326 327 | } } if( p==0 ){ *pzErr = sqlite3_mprintf("parse error in tokenize directive"); rc = SQLITE_ERROR; }else{ rc = sqlite3Fts5GetTokenizer(pGlobal, | | | 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 | } } if( p==0 ){ *pzErr = sqlite3_mprintf("parse error in tokenize directive"); rc = SQLITE_ERROR; }else{ rc = sqlite3Fts5GetTokenizer(pGlobal, (const char**)azArg, (int)nArg, pConfig, pzErr ); } } } sqlite3_free(azArg); |
︙ | ︙ | |||
393 394 395 396 397 398 399 | /* ** Allocate an instance of the default tokenizer ("simple") at ** Fts5Config.pTokenizer. Return SQLITE_OK if successful, or an SQLite error ** code if an error occurs. */ static int fts5ConfigDefaultTokenizer(Fts5Global *pGlobal, Fts5Config *pConfig){ assert( pConfig->pTok==0 && pConfig->pTokApi==0 ); | | < < | 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 | /* ** Allocate an instance of the default tokenizer ("simple") at ** Fts5Config.pTokenizer. Return SQLITE_OK if successful, or an SQLite error ** code if an error occurs. */ static int fts5ConfigDefaultTokenizer(Fts5Global *pGlobal, Fts5Config *pConfig){ assert( pConfig->pTok==0 && pConfig->pTokApi==0 ); return sqlite3Fts5GetTokenizer(pGlobal, 0, 0, pConfig, 0); } /* ** Gobble up the first bareword or quoted word from the input buffer zIn. ** Return a pointer to the character immediately following the last in ** the gobbled word if successful, or a NULL pointer otherwise (failed ** to find close-quote character). |
︙ | ︙ | |||
421 422 423 424 425 426 427 | int *pRc, /* IN/OUT: Error code */ const char *zIn, /* Buffer to gobble string/bareword from */ char **pzOut, /* OUT: malloc'd buffer containing str/bw */ int *pbQuoted /* OUT: Set to true if dequoting required */ ){ const char *zRet = 0; | | | | | 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 | int *pRc, /* IN/OUT: Error code */ const char *zIn, /* Buffer to gobble string/bareword from */ char **pzOut, /* OUT: malloc'd buffer containing str/bw */ int *pbQuoted /* OUT: Set to true if dequoting required */ ){ const char *zRet = 0; sqlite3_int64 nIn = strlen(zIn); char *zOut = sqlite3_malloc64(nIn+1); assert( *pRc==SQLITE_OK ); *pbQuoted = 0; *pzOut = 0; if( zOut==0 ){ *pRc = SQLITE_NOMEM; }else{ memcpy(zOut, zIn, (size_t)(nIn+1)); if( fts5_isopenquote(zOut[0]) ){ int ii = fts5Dequote(zOut); zRet = &zIn[ii]; *pbQuoted = 1; }else{ zRet = fts5ConfigSkipBareword(zIn); if( zRet ){ |
︙ | ︙ | |||
525 526 527 528 529 530 531 | const char **azArg, /* Array of nArg CREATE VIRTUAL TABLE args */ Fts5Config **ppOut, /* OUT: Results of parse */ char **pzErr /* OUT: Error message */ ){ int rc = SQLITE_OK; /* Return code */ Fts5Config *pRet; /* New object to return */ int i; | | | | 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 | const char **azArg, /* Array of nArg CREATE VIRTUAL TABLE args */ Fts5Config **ppOut, /* OUT: Results of parse */ char **pzErr /* OUT: Error message */ ){ int rc = SQLITE_OK; /* Return code */ Fts5Config *pRet; /* New object to return */ int i; sqlite3_int64 nByte; *ppOut = pRet = (Fts5Config*)sqlite3_malloc(sizeof(Fts5Config)); if( pRet==0 ) return SQLITE_NOMEM; memset(pRet, 0, sizeof(Fts5Config)); pRet->db = db; pRet->iCookie = -1; nByte = nArg * (sizeof(char*) + sizeof(u8)); pRet->azCol = (char**)sqlite3Fts5MallocZero(&rc, nByte); pRet->abUnindexed = pRet->azCol ? (u8*)&pRet->azCol[nArg] : 0; pRet->zDb = sqlite3Fts5Strndup(&rc, azArg[1], -1); pRet->zName = sqlite3Fts5Strndup(&rc, azArg[2], -1); pRet->bColumnsize = 1; pRet->eDetail = FTS5_DETAIL_FULL; #ifdef SQLITE_DEBUG pRet->bPrefixIndex = 1; #endif |
︙ | ︙ | |||
560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 | int bOption = 0; int bMustBeCol = 0; z = fts5ConfigGobbleWord(&rc, zOrig, &zOne, &bMustBeCol); z = fts5ConfigSkipWhitespace(z); if( z && *z=='=' ){ bOption = 1; z++; if( bMustBeCol ) z = 0; } z = fts5ConfigSkipWhitespace(z); if( z && z[0] ){ int bDummy; z = fts5ConfigGobbleWord(&rc, z, &zTwo, &bDummy); if( z && z[0] ) z = 0; } if( rc==SQLITE_OK ){ if( z==0 ){ *pzErr = sqlite3_mprintf("parse error in \"%s\"", zOrig); rc = SQLITE_ERROR; }else{ if( bOption ){ | > | > > > > | 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 | int bOption = 0; int bMustBeCol = 0; z = fts5ConfigGobbleWord(&rc, zOrig, &zOne, &bMustBeCol); z = fts5ConfigSkipWhitespace(z); if( z && *z=='=' ){ bOption = 1; assert( zOne!=0 ); z++; if( bMustBeCol ) z = 0; } z = fts5ConfigSkipWhitespace(z); if( z && z[0] ){ int bDummy; z = fts5ConfigGobbleWord(&rc, z, &zTwo, &bDummy); if( z && z[0] ) z = 0; } if( rc==SQLITE_OK ){ if( z==0 ){ *pzErr = sqlite3_mprintf("parse error in \"%s\"", zOrig); rc = SQLITE_ERROR; }else{ if( bOption ){ rc = fts5ConfigParseSpecial(pGlobal, pRet, ALWAYS(zOne)?zOne:"", zTwo?zTwo:"", pzErr ); }else{ rc = fts5ConfigParseColumn(pRet, zOne, zTwo, pzErr); zOne = 0; } } } |
︙ | ︙ | |||
679 680 681 682 683 684 685 | ); assert( zSql || rc==SQLITE_NOMEM ); if( zSql ){ rc = sqlite3_declare_vtab(pConfig->db, zSql); sqlite3_free(zSql); } | | | 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 | ); assert( zSql || rc==SQLITE_NOMEM ); if( zSql ){ rc = sqlite3_declare_vtab(pConfig->db, zSql); sqlite3_free(zSql); } return rc; } /* ** Tokenize the text passed via the second and third arguments. ** ** The callback is invoked once for each token in the input text. The |
︙ | ︙ | |||
824 825 826 827 828 829 830 | int rc = SQLITE_OK; if( 0==sqlite3_stricmp(zKey, "pgsz") ){ int pgsz = 0; if( SQLITE_INTEGER==sqlite3_value_numeric_type(pVal) ){ pgsz = sqlite3_value_int(pVal); } | | | 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 | int rc = SQLITE_OK; if( 0==sqlite3_stricmp(zKey, "pgsz") ){ int pgsz = 0; if( SQLITE_INTEGER==sqlite3_value_numeric_type(pVal) ){ pgsz = sqlite3_value_int(pVal); } if( pgsz<32 || pgsz>FTS5_MAX_PAGE_SIZE ){ *pbBadkey = 1; }else{ pConfig->pgsz = pgsz; } } else if( 0==sqlite3_stricmp(zKey, "hashsize") ){ |
︙ | ︙ | |||
877 878 879 880 881 882 883 884 885 886 887 888 889 890 | if( SQLITE_INTEGER==sqlite3_value_numeric_type(pVal) ){ nCrisisMerge = sqlite3_value_int(pVal); } if( nCrisisMerge<0 ){ *pbBadkey = 1; }else{ if( nCrisisMerge<=1 ) nCrisisMerge = FTS5_DEFAULT_CRISISMERGE; pConfig->nCrisisMerge = nCrisisMerge; } } else if( 0==sqlite3_stricmp(zKey, "rank") ){ const char *zIn = (const char*)sqlite3_value_text(pVal); char *zRank; | > | 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 | if( SQLITE_INTEGER==sqlite3_value_numeric_type(pVal) ){ nCrisisMerge = sqlite3_value_int(pVal); } if( nCrisisMerge<0 ){ *pbBadkey = 1; }else{ if( nCrisisMerge<=1 ) nCrisisMerge = FTS5_DEFAULT_CRISISMERGE; if( nCrisisMerge>=FTS5_MAX_SEGMENT ) nCrisisMerge = FTS5_MAX_SEGMENT-1; pConfig->nCrisisMerge = nCrisisMerge; } } else if( 0==sqlite3_stricmp(zKey, "rank") ){ const char *zIn = (const char*)sqlite3_value_text(pVal); char *zRank; |
︙ | ︙ |
Changes to ext/fts5/fts5_expr.c.
︙ | ︙ | |||
124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 | struct Fts5Parse { Fts5Config *pConfig; char *zErr; int rc; int nPhrase; /* Size of apPhrase array */ Fts5ExprPhrase **apPhrase; /* Array of all phrases */ Fts5ExprNode *pExpr; /* Result of a successful parse */ }; void sqlite3Fts5ParseError(Fts5Parse *pParse, const char *zFmt, ...){ va_list ap; va_start(ap, zFmt); if( pParse->rc==SQLITE_OK ){ pParse->zErr = sqlite3_vmprintf(zFmt, ap); pParse->rc = SQLITE_ERROR; } va_end(ap); } static int fts5ExprIsspace(char t){ | > > | 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 | struct Fts5Parse { Fts5Config *pConfig; char *zErr; int rc; int nPhrase; /* Size of apPhrase array */ Fts5ExprPhrase **apPhrase; /* Array of all phrases */ Fts5ExprNode *pExpr; /* Result of a successful parse */ int bPhraseToAnd; /* Convert "a+b" to "a AND b" */ }; void sqlite3Fts5ParseError(Fts5Parse *pParse, const char *zFmt, ...){ va_list ap; va_start(ap, zFmt); if( pParse->rc==SQLITE_OK ){ assert( pParse->zErr==0 ); pParse->zErr = sqlite3_vmprintf(zFmt, ap); pParse->rc = SQLITE_ERROR; } va_end(ap); } static int fts5ExprIsspace(char t){ |
︙ | ︙ | |||
207 208 209 210 211 212 213 | } } *pz = &pToken->p[pToken->n]; return tok; } | | > > | 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 | } } *pz = &pToken->p[pToken->n]; return tok; } static void *fts5ParseAlloc(u64 t){ return sqlite3_malloc64((sqlite3_int64)t);} static void fts5ParseFree(void *p){ sqlite3_free(p); } int sqlite3Fts5ExprNew( Fts5Config *pConfig, /* FTS5 Configuration */ int bPhraseToAnd, int iCol, const char *zExpr, /* Expression text */ Fts5Expr **ppNew, char **pzErr ){ Fts5Parse sParse; Fts5Token token; const char *z = zExpr; int t; /* Next token type */ void *pEngine; Fts5Expr *pNew; *ppNew = 0; *pzErr = 0; memset(&sParse, 0, sizeof(sParse)); sParse.bPhraseToAnd = bPhraseToAnd; pEngine = sqlite3Fts5ParserAlloc(fts5ParseAlloc); if( pEngine==0 ){ return SQLITE_NOMEM; } sParse.pConfig = pConfig; do { t = fts5ExprGetToken(&sParse, &z, &token); sqlite3Fts5Parser(pEngine, t, token, &sParse); |
︙ | ︙ | |||
269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 | }else{ pNew->pRoot = sParse.pExpr; } pNew->pIndex = 0; pNew->pConfig = pConfig; pNew->apExprPhrase = sParse.apPhrase; pNew->nPhrase = sParse.nPhrase; sParse.apPhrase = 0; } }else{ sqlite3Fts5ParseNodeFree(sParse.pExpr); } sqlite3_free(sParse.apPhrase); *pzErr = sParse.zErr; return sParse.rc; } /* ** Free the expression node object passed as the only argument. */ void sqlite3Fts5ParseNodeFree(Fts5ExprNode *p){ if( p ){ int i; | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | }else{ pNew->pRoot = sParse.pExpr; } pNew->pIndex = 0; pNew->pConfig = pConfig; pNew->apExprPhrase = sParse.apPhrase; pNew->nPhrase = sParse.nPhrase; pNew->bDesc = 0; sParse.apPhrase = 0; } }else{ sqlite3Fts5ParseNodeFree(sParse.pExpr); } sqlite3_free(sParse.apPhrase); *pzErr = sParse.zErr; return sParse.rc; } /* ** This function is only called when using the special 'trigram' tokenizer. ** Argument zText contains the text of a LIKE or GLOB pattern matched ** against column iCol. This function creates and compiles an FTS5 MATCH ** expression that will match a superset of the rows matched by the LIKE or ** GLOB. If successful, SQLITE_OK is returned. Otherwise, an SQLite error ** code. */ int sqlite3Fts5ExprPattern( Fts5Config *pConfig, int bGlob, int iCol, const char *zText, Fts5Expr **pp ){ i64 nText = strlen(zText); char *zExpr = (char*)sqlite3_malloc64(nText*4 + 1); int rc = SQLITE_OK; if( zExpr==0 ){ rc = SQLITE_NOMEM; }else{ char aSpec[3]; int iOut = 0; int i = 0; int iFirst = 0; if( bGlob==0 ){ aSpec[0] = '_'; aSpec[1] = '%'; aSpec[2] = 0; }else{ aSpec[0] = '*'; aSpec[1] = '?'; aSpec[2] = '['; } while( i<=nText ){ if( i==nText || zText[i]==aSpec[0] || zText[i]==aSpec[1] || zText[i]==aSpec[2] ){ if( i-iFirst>=3 ){ int jj; zExpr[iOut++] = '"'; for(jj=iFirst; jj<i; jj++){ zExpr[iOut++] = zText[jj]; if( zText[jj]=='"' ) zExpr[iOut++] = '"'; } zExpr[iOut++] = '"'; zExpr[iOut++] = ' '; } if( zText[i]==aSpec[2] ){ i += 2; if( zText[i-1]=='^' ) i++; while( i<nText && zText[i]!=']' ) i++; } iFirst = i+1; } i++; } if( iOut>0 ){ int bAnd = 0; if( pConfig->eDetail!=FTS5_DETAIL_FULL ){ bAnd = 1; if( pConfig->eDetail==FTS5_DETAIL_NONE ){ iCol = pConfig->nCol; } } zExpr[iOut] = '\0'; rc = sqlite3Fts5ExprNew(pConfig, bAnd, iCol, zExpr, pp,pConfig->pzErrmsg); }else{ *pp = 0; } sqlite3_free(zExpr); } return rc; } /* ** Free the expression node object passed as the only argument. */ void sqlite3Fts5ParseNodeFree(Fts5ExprNode *p){ if( p ){ int i; |
︙ | ︙ | |||
304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 | void sqlite3Fts5ExprFree(Fts5Expr *p){ if( p ){ sqlite3Fts5ParseNodeFree(p->pRoot); sqlite3_free(p->apExprPhrase); sqlite3_free(p); } } /* ** Argument pTerm must be a synonym iterator. Return the current rowid ** that it points to. */ static i64 fts5ExprSynonymRowid(Fts5ExprTerm *pTerm, int bDesc, int *pbEof){ i64 iRet = 0; int bRetValid = 0; Fts5ExprTerm *p; assert( pTerm->pSynonym ); assert( bDesc==0 || bDesc==1 ); for(p=pTerm; p; p=p->pSynonym){ if( 0==sqlite3Fts5IterEof(p->pIter) ){ i64 iRowid = p->pIter->iRowid; if( bRetValid==0 || (bDesc!=(iRowid<iRet)) ){ iRet = iRowid; | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | void sqlite3Fts5ExprFree(Fts5Expr *p){ if( p ){ sqlite3Fts5ParseNodeFree(p->pRoot); sqlite3_free(p->apExprPhrase); sqlite3_free(p); } } int sqlite3Fts5ExprAnd(Fts5Expr **pp1, Fts5Expr *p2){ Fts5Parse sParse; memset(&sParse, 0, sizeof(sParse)); if( *pp1 ){ Fts5Expr *p1 = *pp1; int nPhrase = p1->nPhrase + p2->nPhrase; p1->pRoot = sqlite3Fts5ParseNode(&sParse, FTS5_AND, p1->pRoot, p2->pRoot,0); p2->pRoot = 0; if( sParse.rc==SQLITE_OK ){ Fts5ExprPhrase **ap = (Fts5ExprPhrase**)sqlite3_realloc( p1->apExprPhrase, nPhrase * sizeof(Fts5ExprPhrase*) ); if( ap==0 ){ sParse.rc = SQLITE_NOMEM; }else{ int i; memmove(&ap[p2->nPhrase], ap, p1->nPhrase*sizeof(Fts5ExprPhrase*)); for(i=0; i<p2->nPhrase; i++){ ap[i] = p2->apExprPhrase[i]; } p1->nPhrase = nPhrase; p1->apExprPhrase = ap; } } sqlite3_free(p2->apExprPhrase); sqlite3_free(p2); }else{ *pp1 = p2; } return sParse.rc; } /* ** Argument pTerm must be a synonym iterator. Return the current rowid ** that it points to. */ static i64 fts5ExprSynonymRowid(Fts5ExprTerm *pTerm, int bDesc, int *pbEof){ i64 iRet = 0; int bRetValid = 0; Fts5ExprTerm *p; assert( pTerm ); assert( pTerm->pSynonym ); assert( bDesc==0 || bDesc==1 ); for(p=pTerm; p; p=p->pSynonym){ if( 0==sqlite3Fts5IterEof(p->pIter) ){ i64 iRowid = p->pIter->iRowid; if( bRetValid==0 || (bDesc!=(iRowid<iRet)) ){ iRet = iRowid; |
︙ | ︙ | |||
352 353 354 355 356 357 358 | assert( pTerm->pSynonym ); for(p=pTerm; p; p=p->pSynonym){ Fts5IndexIter *pIter = p->pIter; if( sqlite3Fts5IterEof(pIter)==0 && pIter->iRowid==iRowid ){ if( pIter->nData==0 ) continue; if( nIter==nAlloc ){ | | | | 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 | assert( pTerm->pSynonym ); for(p=pTerm; p; p=p->pSynonym){ Fts5IndexIter *pIter = p->pIter; if( sqlite3Fts5IterEof(pIter)==0 && pIter->iRowid==iRowid ){ if( pIter->nData==0 ) continue; if( nIter==nAlloc ){ sqlite3_int64 nByte = sizeof(Fts5PoslistReader) * nAlloc * 2; Fts5PoslistReader *aNew = (Fts5PoslistReader*)sqlite3_malloc64(nByte); if( aNew==0 ){ rc = SQLITE_NOMEM; goto synonym_poslist_out; } memcpy(aNew, aIter, sizeof(Fts5PoslistReader) * nIter); nAlloc = nAlloc*2; if( aIter!=aStatic ) sqlite3_free(aIter); |
︙ | ︙ | |||
433 434 435 436 437 438 439 | int bFirst = pPhrase->aTerm[0].bFirst; fts5BufferZero(&pPhrase->poslist); /* If the aStatic[] array is not large enough, allocate a large array ** using sqlite3_malloc(). This approach could be improved upon. */ if( pPhrase->nTerm>ArraySize(aStatic) ){ | | | | 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 | int bFirst = pPhrase->aTerm[0].bFirst; fts5BufferZero(&pPhrase->poslist); /* If the aStatic[] array is not large enough, allocate a large array ** using sqlite3_malloc(). This approach could be improved upon. */ if( pPhrase->nTerm>ArraySize(aStatic) ){ sqlite3_int64 nByte = sizeof(Fts5PoslistReader) * pPhrase->nTerm; aIter = (Fts5PoslistReader*)sqlite3_malloc64(nByte); if( !aIter ) return SQLITE_NOMEM; } memset(aIter, 0, sizeof(Fts5PoslistReader) * pPhrase->nTerm); /* Initialize a term iterator for each term in the phrase */ for(i=0; i<pPhrase->nTerm; i++){ Fts5ExprTerm *pTerm = &pPhrase->aTerm[i]; |
︙ | ︙ | |||
568 569 570 571 572 573 574 | int bMatch; assert( pNear->nPhrase>1 ); /* If the aStatic[] array is not large enough, allocate a large array ** using sqlite3_malloc(). This approach could be improved upon. */ if( pNear->nPhrase>ArraySize(aStatic) ){ | | | 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 | int bMatch; assert( pNear->nPhrase>1 ); /* If the aStatic[] array is not large enough, allocate a large array ** using sqlite3_malloc(). This approach could be improved upon. */ if( pNear->nPhrase>ArraySize(aStatic) ){ sqlite3_int64 nByte = sizeof(Fts5NearTrimmer) * pNear->nPhrase; a = (Fts5NearTrimmer*)sqlite3Fts5MallocZero(&rc, nByte); }else{ memset(aStatic, 0, sizeof(aStatic)); } if( rc!=SQLITE_OK ){ *pRc = rc; return 0; |
︙ | ︙ | |||
1381 1382 1383 1384 1385 1386 1387 | && 0==pRoot->bEof && fts5RowidCmp(p, pRoot->iRowid, iFirst)<0 ){ rc = fts5ExprNodeNext(p, pRoot, 1, iFirst); } /* If the iterator is not at a real match, skip forward until it is. */ | | | | 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 | && 0==pRoot->bEof && fts5RowidCmp(p, pRoot->iRowid, iFirst)<0 ){ rc = fts5ExprNodeNext(p, pRoot, 1, iFirst); } /* If the iterator is not at a real match, skip forward until it is. */ while( pRoot->bNomatch && rc==SQLITE_OK ){ assert( pRoot->bEof==0 ); rc = fts5ExprNodeNext(p, pRoot, 0, 0); } return rc; } /* ** Move to the next document |
︙ | ︙ | |||
1477 1478 1479 1480 1481 1482 1483 | Fts5ExprNearset *pRet = 0; if( pParse->rc==SQLITE_OK ){ if( pPhrase==0 ){ return pNear; } if( pNear==0 ){ | > | | | | > | | 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 | Fts5ExprNearset *pRet = 0; if( pParse->rc==SQLITE_OK ){ if( pPhrase==0 ){ return pNear; } if( pNear==0 ){ sqlite3_int64 nByte; nByte = sizeof(Fts5ExprNearset) + SZALLOC * sizeof(Fts5ExprPhrase*); pRet = sqlite3_malloc64(nByte); if( pRet==0 ){ pParse->rc = SQLITE_NOMEM; }else{ memset(pRet, 0, (size_t)nByte); } }else if( (pNear->nPhrase % SZALLOC)==0 ){ int nNew = pNear->nPhrase + SZALLOC; sqlite3_int64 nByte; nByte = sizeof(Fts5ExprNearset) + nNew * sizeof(Fts5ExprPhrase*); pRet = (Fts5ExprNearset*)sqlite3_realloc64(pNear, nByte); if( pRet==0 ){ pParse->rc = SQLITE_NOMEM; } }else{ pRet = pNear; } } |
︙ | ︙ | |||
1552 1553 1554 1555 1556 1557 1558 | /* If an error has already occurred, this is a no-op */ if( pCtx->rc!=SQLITE_OK ) return pCtx->rc; if( nToken>FTS5_MAX_TOKEN_SIZE ) nToken = FTS5_MAX_TOKEN_SIZE; if( pPhrase && pPhrase->nTerm>0 && (tflags & FTS5_TOKEN_COLOCATED) ){ Fts5ExprTerm *pSyn; | | | | | | 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 | /* If an error has already occurred, this is a no-op */ if( pCtx->rc!=SQLITE_OK ) return pCtx->rc; if( nToken>FTS5_MAX_TOKEN_SIZE ) nToken = FTS5_MAX_TOKEN_SIZE; if( pPhrase && pPhrase->nTerm>0 && (tflags & FTS5_TOKEN_COLOCATED) ){ Fts5ExprTerm *pSyn; sqlite3_int64 nByte = sizeof(Fts5ExprTerm) + sizeof(Fts5Buffer) + nToken+1; pSyn = (Fts5ExprTerm*)sqlite3_malloc64(nByte); if( pSyn==0 ){ rc = SQLITE_NOMEM; }else{ memset(pSyn, 0, (size_t)nByte); pSyn->zTerm = ((char*)pSyn) + sizeof(Fts5ExprTerm) + sizeof(Fts5Buffer); memcpy(pSyn->zTerm, pToken, nToken); pSyn->pSynonym = pPhrase->aTerm[pPhrase->nTerm-1].pSynonym; pPhrase->aTerm[pPhrase->nTerm-1].pSynonym = pSyn; } }else{ Fts5ExprTerm *pTerm; if( pPhrase==0 || (pPhrase->nTerm % SZALLOC)==0 ){ Fts5ExprPhrase *pNew; int nNew = SZALLOC + (pPhrase ? pPhrase->nTerm : 0); pNew = (Fts5ExprPhrase*)sqlite3_realloc64(pPhrase, sizeof(Fts5ExprPhrase) + sizeof(Fts5ExprTerm) * nNew ); if( pNew==0 ){ rc = SQLITE_NOMEM; }else{ if( pPhrase==0 ) memset(pNew, 0, sizeof(Fts5ExprPhrase)); pCtx->pPhrase = pPhrase = pNew; |
︙ | ︙ | |||
1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 | } } void sqlite3Fts5ParseFinished(Fts5Parse *pParse, Fts5ExprNode *p){ assert( pParse->pExpr==0 ); pParse->pExpr = p; } /* ** This function is called by the parser to process a string token. The ** string may or may not be quoted. In any case it is tokenized and a ** phrase object consisting of all tokens returned. */ Fts5ExprPhrase *sqlite3Fts5ParseTerm( | > > > > > > > > > > > > > > | 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 | } } void sqlite3Fts5ParseFinished(Fts5Parse *pParse, Fts5ExprNode *p){ assert( pParse->pExpr==0 ); pParse->pExpr = p; } static int parseGrowPhraseArray(Fts5Parse *pParse){ if( (pParse->nPhrase % 8)==0 ){ sqlite3_int64 nByte = sizeof(Fts5ExprPhrase*) * (pParse->nPhrase + 8); Fts5ExprPhrase **apNew; apNew = (Fts5ExprPhrase**)sqlite3_realloc64(pParse->apPhrase, nByte); if( apNew==0 ){ pParse->rc = SQLITE_NOMEM; return SQLITE_NOMEM; } pParse->apPhrase = apNew; } return SQLITE_OK; } /* ** This function is called by the parser to process a string token. The ** string may or may not be quoted. In any case it is tokenized and a ** phrase object consisting of all tokens returned. */ Fts5ExprPhrase *sqlite3Fts5ParseTerm( |
︙ | ︙ | |||
1654 1655 1656 1657 1658 1659 1660 | if( rc || (rc = sCtx.rc) ){ pParse->rc = rc; fts5ExprPhraseFree(sCtx.pPhrase); sCtx.pPhrase = 0; }else{ if( pAppend==0 ){ | < < | < < < | | < < | 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 | if( rc || (rc = sCtx.rc) ){ pParse->rc = rc; fts5ExprPhraseFree(sCtx.pPhrase); sCtx.pPhrase = 0; }else{ if( pAppend==0 ){ if( parseGrowPhraseArray(pParse) ){ fts5ExprPhraseFree(sCtx.pPhrase); return 0; } pParse->nPhrase++; } if( sCtx.pPhrase==0 ){ /* This happens when parsing a token or quoted phrase that contains ** no token characters at all. (e.g ... MATCH '""'). */ |
︙ | ︙ | |||
1712 1713 1714 1715 1716 1717 1718 | if( rc==SQLITE_OK ){ pNew->pRoot->pNear = (Fts5ExprNearset*)sqlite3Fts5MallocZero(&rc, sizeof(Fts5ExprNearset) + sizeof(Fts5ExprPhrase*)); } if( rc==SQLITE_OK ){ Fts5Colset *pColsetOrig = pOrig->pNode->pNear->pColset; if( pColsetOrig ){ | > > | | | | 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 | if( rc==SQLITE_OK ){ pNew->pRoot->pNear = (Fts5ExprNearset*)sqlite3Fts5MallocZero(&rc, sizeof(Fts5ExprNearset) + sizeof(Fts5ExprPhrase*)); } if( rc==SQLITE_OK ){ Fts5Colset *pColsetOrig = pOrig->pNode->pNear->pColset; if( pColsetOrig ){ sqlite3_int64 nByte; Fts5Colset *pColset; nByte = sizeof(Fts5Colset) + (pColsetOrig->nCol-1) * sizeof(int); pColset = (Fts5Colset*)sqlite3Fts5MallocZero(&rc, nByte); if( pColset ){ memcpy(pColset, pColsetOrig, (size_t)nByte); } pNew->pRoot->pNear->pColset = pColset; } } if( pOrig->nTerm ){ int i; /* Used to iterate through phrase terms */ |
︙ | ︙ | |||
1743 1744 1745 1746 1747 1748 1749 | } }else{ /* This happens when parsing a token or quoted phrase that contains ** no token characters at all. (e.g ... MATCH '""'). */ sCtx.pPhrase = sqlite3Fts5MallocZero(&rc, sizeof(Fts5ExprPhrase)); } | | | 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 | } }else{ /* This happens when parsing a token or quoted phrase that contains ** no token characters at all. (e.g ... MATCH '""'). */ sCtx.pPhrase = sqlite3Fts5MallocZero(&rc, sizeof(Fts5ExprPhrase)); } if( rc==SQLITE_OK && ALWAYS(sCtx.pPhrase) ){ /* All the allocations succeeded. Put the expression object together. */ pNew->pIndex = pExpr->pIndex; pNew->pConfig = pExpr->pConfig; pNew->nPhrase = 1; pNew->apExprPhrase[0] = sCtx.pPhrase; pNew->pRoot->pNear->apPhrase[0] = sCtx.pPhrase; pNew->pRoot->pNear->nPhrase = 1; |
︙ | ︙ | |||
1833 1834 1835 1836 1837 1838 1839 | ){ int nCol = p ? p->nCol : 0; /* Num. columns already in colset object */ Fts5Colset *pNew; /* New colset object to return */ assert( pParse->rc==SQLITE_OK ); assert( iCol>=0 && iCol<pParse->pConfig->nCol ); | | | 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 | ){ int nCol = p ? p->nCol : 0; /* Num. columns already in colset object */ Fts5Colset *pNew; /* New colset object to return */ assert( pParse->rc==SQLITE_OK ); assert( iCol>=0 && iCol<pParse->pConfig->nCol ); pNew = sqlite3_realloc64(p, sizeof(Fts5Colset) + sizeof(int)*nCol); if( pNew==0 ){ pParse->rc = SQLITE_NOMEM; }else{ int *aiCol = pNew->aiCol; int i, j; for(i=0; i<nCol; i++){ if( aiCol[i]==iCol ) return pNew; |
︙ | ︙ | |||
1929 1930 1931 1932 1933 1934 1935 | ** Otherwise, a copy of (*pOrig) is made into memory obtained from ** sqlite3Fts5MallocZero() and a pointer to it returned. If the allocation ** fails, (*pRc) is set to SQLITE_NOMEM and NULL is returned. */ static Fts5Colset *fts5CloneColset(int *pRc, Fts5Colset *pOrig){ Fts5Colset *pRet; if( pOrig ){ | | | | 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 | ** Otherwise, a copy of (*pOrig) is made into memory obtained from ** sqlite3Fts5MallocZero() and a pointer to it returned. If the allocation ** fails, (*pRc) is set to SQLITE_NOMEM and NULL is returned. */ static Fts5Colset *fts5CloneColset(int *pRc, Fts5Colset *pOrig){ Fts5Colset *pRet; if( pOrig ){ sqlite3_int64 nByte = sizeof(Fts5Colset) + (pOrig->nCol-1) * sizeof(int); pRet = (Fts5Colset*)sqlite3Fts5MallocZero(pRc, nByte); if( pRet ){ memcpy(pRet, pOrig, (size_t)nByte); } }else{ pRet = 0; } return pRet; } |
︙ | ︙ | |||
2014 2015 2016 2017 2018 2019 2020 | void sqlite3Fts5ParseSetColset( Fts5Parse *pParse, Fts5ExprNode *pExpr, Fts5Colset *pColset ){ Fts5Colset *pFree = pColset; if( pParse->pConfig->eDetail==FTS5_DETAIL_NONE ){ | < | | | 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 | void sqlite3Fts5ParseSetColset( Fts5Parse *pParse, Fts5ExprNode *pExpr, Fts5Colset *pColset ){ Fts5Colset *pFree = pColset; if( pParse->pConfig->eDetail==FTS5_DETAIL_NONE ){ sqlite3Fts5ParseError(pParse, "fts5: column queries are not supported (detail=none)" ); }else{ fts5ParseSetColset(pParse, pExpr, pColset, &pFree); } sqlite3_free(pFree); } |
︙ | ︙ | |||
2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 | memcpy(&p->apChild[p->nChild], pSub->apChild, nByte); p->nChild += pSub->nChild; sqlite3_free(pSub); }else{ p->apChild[p->nChild++] = pSub; } } /* ** Allocate and return a new expression object. If anything goes wrong (i.e. ** OOM error), leave an error code in pParse and return NULL. */ Fts5ExprNode *sqlite3Fts5ParseNode( Fts5Parse *pParse, /* Parse context */ int eType, /* FTS5_STRING, AND, OR or NOT */ Fts5ExprNode *pLeft, /* Left hand child expression */ Fts5ExprNode *pRight, /* Right hand child expression */ Fts5ExprNearset *pNear /* For STRING expressions, the near cluster */ ){ Fts5ExprNode *pRet = 0; if( pParse->rc==SQLITE_OK ){ int nChild = 0; /* Number of children of returned node */ | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > | | | | | | | | | | | | | | | | | | | | | | | | | | | | < < < | | | | | | | | | | | > | 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 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 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 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 | memcpy(&p->apChild[p->nChild], pSub->apChild, nByte); p->nChild += pSub->nChild; sqlite3_free(pSub); }else{ p->apChild[p->nChild++] = pSub; } } /* ** This function is used when parsing LIKE or GLOB patterns against ** trigram indexes that specify either detail=column or detail=none. ** It converts a phrase: ** ** abc + def + ghi ** ** into an AND tree: ** ** abc AND def AND ghi */ static Fts5ExprNode *fts5ParsePhraseToAnd( Fts5Parse *pParse, Fts5ExprNearset *pNear ){ int nTerm = pNear->apPhrase[0]->nTerm; int ii; int nByte; Fts5ExprNode *pRet; assert( pNear->nPhrase==1 ); assert( pParse->bPhraseToAnd ); nByte = sizeof(Fts5ExprNode) + nTerm*sizeof(Fts5ExprNode*); pRet = (Fts5ExprNode*)sqlite3Fts5MallocZero(&pParse->rc, nByte); if( pRet ){ pRet->eType = FTS5_AND; pRet->nChild = nTerm; fts5ExprAssignXNext(pRet); pParse->nPhrase--; for(ii=0; ii<nTerm; ii++){ Fts5ExprPhrase *pPhrase = (Fts5ExprPhrase*)sqlite3Fts5MallocZero( &pParse->rc, sizeof(Fts5ExprPhrase) ); if( pPhrase ){ if( parseGrowPhraseArray(pParse) ){ fts5ExprPhraseFree(pPhrase); }else{ pParse->apPhrase[pParse->nPhrase++] = pPhrase; pPhrase->nTerm = 1; pPhrase->aTerm[0].zTerm = sqlite3Fts5Strndup( &pParse->rc, pNear->apPhrase[0]->aTerm[ii].zTerm, -1 ); pRet->apChild[ii] = sqlite3Fts5ParseNode(pParse, FTS5_STRING, 0, 0, sqlite3Fts5ParseNearset(pParse, 0, pPhrase) ); } } } if( pParse->rc ){ sqlite3Fts5ParseNodeFree(pRet); pRet = 0; }else{ sqlite3Fts5ParseNearsetFree(pNear); } } return pRet; } /* ** Allocate and return a new expression object. If anything goes wrong (i.e. ** OOM error), leave an error code in pParse and return NULL. */ Fts5ExprNode *sqlite3Fts5ParseNode( Fts5Parse *pParse, /* Parse context */ int eType, /* FTS5_STRING, AND, OR or NOT */ Fts5ExprNode *pLeft, /* Left hand child expression */ Fts5ExprNode *pRight, /* Right hand child expression */ Fts5ExprNearset *pNear /* For STRING expressions, the near cluster */ ){ Fts5ExprNode *pRet = 0; if( pParse->rc==SQLITE_OK ){ int nChild = 0; /* Number of children of returned node */ sqlite3_int64 nByte; /* Bytes of space to allocate for this node */ assert( (eType!=FTS5_STRING && !pNear) || (eType==FTS5_STRING && !pLeft && !pRight) ); if( eType==FTS5_STRING && pNear==0 ) return 0; if( eType!=FTS5_STRING && pLeft==0 ) return pRight; if( eType!=FTS5_STRING && pRight==0 ) return pLeft; if( eType==FTS5_STRING && pParse->bPhraseToAnd && pNear->apPhrase[0]->nTerm>1 ){ pRet = fts5ParsePhraseToAnd(pParse, pNear); }else{ if( eType==FTS5_NOT ){ nChild = 2; }else if( eType==FTS5_AND || eType==FTS5_OR ){ nChild = 2; if( pLeft->eType==eType ) nChild += pLeft->nChild-1; if( pRight->eType==eType ) nChild += pRight->nChild-1; } nByte = sizeof(Fts5ExprNode) + sizeof(Fts5ExprNode*)*(nChild-1); pRet = (Fts5ExprNode*)sqlite3Fts5MallocZero(&pParse->rc, nByte); if( pRet ){ pRet->eType = eType; pRet->pNear = pNear; fts5ExprAssignXNext(pRet); if( eType==FTS5_STRING ){ int iPhrase; for(iPhrase=0; iPhrase<pNear->nPhrase; iPhrase++){ pNear->apPhrase[iPhrase]->pNode = pRet; if( pNear->apPhrase[iPhrase]->nTerm==0 ){ pRet->xNext = 0; pRet->eType = FTS5_EOF; } } if( pParse->pConfig->eDetail!=FTS5_DETAIL_FULL ){ Fts5ExprPhrase *pPhrase = pNear->apPhrase[0]; if( pNear->nPhrase!=1 || pPhrase->nTerm>1 || (pPhrase->nTerm>0 && pPhrase->aTerm[0].bFirst) ){ sqlite3Fts5ParseError(pParse, "fts5: %s queries are not supported (detail!=full)", pNear->nPhrase==1 ? "phrase": "NEAR" ); sqlite3_free(pRet); pRet = 0; } } }else{ fts5ExprAddChildren(pRet, pLeft); fts5ExprAddChildren(pRet, pRight); } } } } if( pRet==0 ){ assert( pParse->rc!=SQLITE_OK ); sqlite3Fts5ParseNodeFree(pLeft); |
︙ | ︙ | |||
2214 2215 2216 2217 2218 2219 2220 2221 | pRet = sqlite3Fts5ParseNode(pParse, FTS5_AND, pLeft, pRight, 0); } } return pRet; } static char *fts5ExprTermPrint(Fts5ExprTerm *pTerm){ | > | | | 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 | pRet = sqlite3Fts5ParseNode(pParse, FTS5_AND, pLeft, pRight, 0); } } return pRet; } #ifdef SQLITE_TEST static char *fts5ExprTermPrint(Fts5ExprTerm *pTerm){ sqlite3_int64 nByte = 0; Fts5ExprTerm *p; char *zQuoted; /* Determine the maximum amount of space required. */ for(p=pTerm; p; p=p->pSynonym){ nByte += (int)strlen(pTerm->zTerm) * 2 + 3 + 2; } zQuoted = sqlite3_malloc64(nByte); if( zQuoted ){ int i = 0; for(p=pTerm; p; p=p->pSynonym){ char *zIn = p->zTerm; zQuoted[i++] = '"'; while( *zIn ){ |
︙ | ︙ | |||
2357 2358 2359 2360 2361 2362 2363 | }else if( pExpr->eType==FTS5_STRING || pExpr->eType==FTS5_TERM ){ Fts5ExprNearset *pNear = pExpr->pNear; int i; int iTerm; if( pNear->pColset ){ | > | > > > > > > > | > | 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 | }else if( pExpr->eType==FTS5_STRING || pExpr->eType==FTS5_TERM ){ Fts5ExprNearset *pNear = pExpr->pNear; int i; int iTerm; if( pNear->pColset ){ int ii; Fts5Colset *pColset = pNear->pColset; if( pColset->nCol>1 ) zRet = fts5PrintfAppend(zRet, "{"); for(ii=0; ii<pColset->nCol; ii++){ zRet = fts5PrintfAppend(zRet, "%s%s", pConfig->azCol[pColset->aiCol[ii]], ii==pColset->nCol-1 ? "" : " " ); } if( zRet ){ zRet = fts5PrintfAppend(zRet, "%s : ", pColset->nCol>1 ? "}" : ""); } if( zRet==0 ) return 0; } if( pNear->nPhrase>1 ){ zRet = fts5PrintfAppend(zRet, "NEAR("); if( zRet==0 ) return 0; } |
︙ | ︙ | |||
2463 2464 2465 2466 2467 2468 2469 | if( bTcl && nArg>1 ){ zNearsetCmd = (const char*)sqlite3_value_text(apVal[1]); iArg = 2; } nConfig = 3 + (nArg-iArg); | | | > > | | 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 | if( bTcl && nArg>1 ){ zNearsetCmd = (const char*)sqlite3_value_text(apVal[1]); iArg = 2; } nConfig = 3 + (nArg-iArg); azConfig = (const char**)sqlite3_malloc64(sizeof(char*) * nConfig); if( azConfig==0 ){ sqlite3_result_error_nomem(pCtx); return; } azConfig[0] = 0; azConfig[1] = "main"; azConfig[2] = "tbl"; for(i=3; iArg<nArg; iArg++){ const char *z = (const char*)sqlite3_value_text(apVal[iArg]); azConfig[i++] = (z ? z : ""); } zExpr = (const char*)sqlite3_value_text(apVal[0]); if( zExpr==0 ) zExpr = ""; rc = sqlite3Fts5ConfigParse(pGlobal, db, nConfig, azConfig, &pConfig, &zErr); if( rc==SQLITE_OK ){ rc = sqlite3Fts5ExprNew(pConfig, 0, pConfig->nCol, zExpr, &pExpr, &zErr); } if( rc==SQLITE_OK ){ char *zText; if( pExpr->pRoot->xNext==0 ){ zText = sqlite3_mprintf(""); }else if( bTcl ){ zText = fts5ExprPrintTcl(pConfig, zNearsetCmd, pExpr->pRoot); |
︙ | ︙ | |||
2549 2550 2551 2552 2553 2554 2555 | return; } memset(aArr, 0, sizeof(aArr)); sqlite3Fts5UnicodeCatParse("L*", aArr); sqlite3Fts5UnicodeCatParse("N*", aArr); sqlite3Fts5UnicodeCatParse("Co", aArr); iCode = sqlite3_value_int(apVal[0]); | | > > > > > > | 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 | return; } memset(aArr, 0, sizeof(aArr)); sqlite3Fts5UnicodeCatParse("L*", aArr); sqlite3Fts5UnicodeCatParse("N*", aArr); sqlite3Fts5UnicodeCatParse("Co", aArr); iCode = sqlite3_value_int(apVal[0]); sqlite3_result_int(pCtx, aArr[sqlite3Fts5UnicodeCategory((u32)iCode)]); } static void fts5ExprFold( sqlite3_context *pCtx, /* Function call context */ int nArg, /* Number of args */ sqlite3_value **apVal /* Function arguments */ ){ if( nArg!=1 && nArg!=2 ){ sqlite3_result_error(pCtx, "wrong number of arguments to function fts5_fold", -1 ); }else{ int iCode; int bRemoveDiacritics = 0; iCode = sqlite3_value_int(apVal[0]); if( nArg==2 ) bRemoveDiacritics = sqlite3_value_int(apVal[1]); sqlite3_result_int(pCtx, sqlite3Fts5UnicodeFold(iCode, bRemoveDiacritics)); } } #endif /* ifdef SQLITE_TEST */ /* ** This is called during initialization to register the fts5_expr() scalar ** UDF with the SQLite handle passed as the only argument. */ int sqlite3Fts5ExprInit(Fts5Global *pGlobal, sqlite3 *db){ #ifdef SQLITE_TEST struct Fts5ExprFunc { const char *z; void (*x)(sqlite3_context*,int,sqlite3_value**); } aFunc[] = { { "fts5_expr", fts5ExprFunctionHr }, { "fts5_expr_tcl", fts5ExprFunctionTcl }, { "fts5_isalnum", fts5ExprIsAlnum }, { "fts5_fold", fts5ExprFold }, }; int i; int rc = SQLITE_OK; void *pCtx = (void*)pGlobal; for(i=0; rc==SQLITE_OK && i<ArraySize(aFunc); i++){ struct Fts5ExprFunc *p = &aFunc[i]; rc = sqlite3_create_function(db, p->z, -1, SQLITE_UTF8, pCtx, p->x, 0, 0); } #else int rc = SQLITE_OK; UNUSED_PARAM2(pGlobal,db); #endif /* Avoid warnings indicating that sqlite3Fts5ParserTrace() and ** sqlite3Fts5ParserFallback() are unused */ #ifndef NDEBUG (void)sqlite3Fts5ParserTrace; #endif (void)sqlite3Fts5ParserFallback; |
︙ | ︙ | |||
2642 2643 2644 2645 2646 2647 2648 2649 2650 | struct Fts5PoslistPopulator { Fts5PoslistWriter writer; int bOk; /* True if ok to populate */ int bMiss; }; Fts5PoslistPopulator *sqlite3Fts5ExprClearPoslists(Fts5Expr *pExpr, int bLive){ Fts5PoslistPopulator *pRet; | > > > > > > > > > | | | 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 | struct Fts5PoslistPopulator { Fts5PoslistWriter writer; int bOk; /* True if ok to populate */ int bMiss; }; /* ** Clear the position lists associated with all phrases in the expression ** passed as the first argument. Argument bLive is true if the expression ** might be pointing to a real entry, otherwise it has just been reset. ** ** At present this function is only used for detail=col and detail=none ** fts5 tables. This implies that all phrases must be at most 1 token ** in size, as phrase matches are not supported without detail=full. */ Fts5PoslistPopulator *sqlite3Fts5ExprClearPoslists(Fts5Expr *pExpr, int bLive){ Fts5PoslistPopulator *pRet; pRet = sqlite3_malloc64(sizeof(Fts5PoslistPopulator)*pExpr->nPhrase); if( pRet ){ int i; memset(pRet, 0, sizeof(Fts5PoslistPopulator)*pExpr->nPhrase); for(i=0; i<pExpr->nPhrase; i++){ Fts5Buffer *pBuf = &pExpr->apExprPhrase[i]->poslist; Fts5ExprNode *pNode = pExpr->apExprPhrase[i]->pNode; assert( pExpr->apExprPhrase[i]->nTerm<=1 ); if( bLive && (pBuf->n==0 || pNode->iRowid!=pExpr->pRoot->iRowid || pNode->bEof) ){ pRet[i].bMiss = 1; }else{ pBuf->n = 0; } |
︙ | ︙ | |||
2843 2844 2845 2846 2847 2848 2849 | }else{ *ppCollist = 0; *pnCollist = 0; } return rc; } | < | 3062 3063 3064 3065 3066 3067 3068 | }else{ *ppCollist = 0; *pnCollist = 0; } return rc; } |
Changes to ext/fts5/fts5_hash.c.
︙ | ︙ | |||
86 87 88 89 90 91 92 | int rc = SQLITE_OK; Fts5Hash *pNew; *ppNew = pNew = (Fts5Hash*)sqlite3_malloc(sizeof(Fts5Hash)); if( pNew==0 ){ rc = SQLITE_NOMEM; }else{ | | | | | 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 | int rc = SQLITE_OK; Fts5Hash *pNew; *ppNew = pNew = (Fts5Hash*)sqlite3_malloc(sizeof(Fts5Hash)); if( pNew==0 ){ rc = SQLITE_NOMEM; }else{ sqlite3_int64 nByte; memset(pNew, 0, sizeof(Fts5Hash)); pNew->pnByte = pnByte; pNew->eDetail = pConfig->eDetail; pNew->nSlot = 1024; nByte = sizeof(Fts5HashEntry*) * pNew->nSlot; pNew->aSlot = (Fts5HashEntry**)sqlite3_malloc64(nByte); if( pNew->aSlot==0 ){ sqlite3_free(pNew); *ppNew = 0; rc = SQLITE_NOMEM; }else{ memset(pNew->aSlot, 0, (size_t)nByte); } } return rc; } /* ** Free a hash table object. |
︙ | ︙ | |||
161 162 163 164 165 166 167 | */ static int fts5HashResize(Fts5Hash *pHash){ int nNew = pHash->nSlot*2; int i; Fts5HashEntry **apNew; Fts5HashEntry **apOld = pHash->aSlot; | | | 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 | */ static int fts5HashResize(Fts5Hash *pHash){ int nNew = pHash->nSlot*2; int i; Fts5HashEntry **apNew; Fts5HashEntry **apOld = pHash->aSlot; apNew = (Fts5HashEntry**)sqlite3_malloc64(nNew*sizeof(Fts5HashEntry*)); if( !apNew ) return SQLITE_NOMEM; memset(apNew, 0, nNew*sizeof(Fts5HashEntry*)); for(i=0; i<pHash->nSlot; i++){ while( apOld[i] ){ unsigned int iHash; Fts5HashEntry *p = apOld[i]; |
︙ | ︙ | |||
183 184 185 186 187 188 189 | sqlite3_free(apOld); pHash->nSlot = nNew; pHash->aSlot = apNew; return SQLITE_OK; } | | > > > > > | > | | | | | > > | | | > | > > | 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 | sqlite3_free(apOld); pHash->nSlot = nNew; pHash->aSlot = apNew; return SQLITE_OK; } static int fts5HashAddPoslistSize( Fts5Hash *pHash, Fts5HashEntry *p, Fts5HashEntry *p2 ){ int nRet = 0; if( p->iSzPoslist ){ u8 *pPtr = p2 ? (u8*)p2 : (u8*)p; int nData = p->nData; if( pHash->eDetail==FTS5_DETAIL_NONE ){ assert( nData==p->iSzPoslist ); if( p->bDel ){ pPtr[nData++] = 0x00; if( p->bContent ){ pPtr[nData++] = 0x00; } } }else{ int nSz = (nData - p->iSzPoslist - 1); /* Size in bytes */ int nPos = nSz*2 + p->bDel; /* Value of nPos field */ assert( p->bDel==0 || p->bDel==1 ); if( nPos<=127 ){ pPtr[p->iSzPoslist] = (u8)nPos; }else{ int nByte = sqlite3Fts5GetVarintLen((u32)nPos); memmove(&pPtr[p->iSzPoslist + nByte], &pPtr[p->iSzPoslist + 1], nSz); sqlite3Fts5PutVarint(&pPtr[p->iSzPoslist], nPos); nData += (nByte-1); } } nRet = nData - p->nData; if( p2==0 ){ p->iSzPoslist = 0; p->bDel = 0; p->bContent = 0; p->nData = nData; } } return nRet; } /* ** Add an entry to the in-memory hash table. The key is the concatenation ** of bByte and (pToken/nToken). The value is (iRowid/iCol/iPos). ** ** (bByte || pToken) -> (iRowid,iCol,iPos) |
︙ | ︙ | |||
255 256 257 258 259 260 261 | } } /* If an existing hash entry cannot be found, create a new one. */ if( p==0 ){ /* Figure out how much space to allocate */ char *zKey; | | | | | 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 | } } /* If an existing hash entry cannot be found, create a new one. */ if( p==0 ){ /* Figure out how much space to allocate */ char *zKey; sqlite3_int64 nByte = sizeof(Fts5HashEntry) + (nToken+1) + 1 + 64; if( nByte<128 ) nByte = 128; /* Grow the Fts5Hash.aSlot[] array if necessary. */ if( (pHash->nEntry*2)>=pHash->nSlot ){ int rc = fts5HashResize(pHash); if( rc!=SQLITE_OK ) return rc; iHash = fts5HashKey2(pHash->nSlot, (u8)bByte, (const u8*)pToken, nToken); } /* Allocate new Fts5HashEntry and add it to the hash table. */ p = (Fts5HashEntry*)sqlite3_malloc64(nByte); if( !p ) return SQLITE_NOMEM; memset(p, 0, sizeof(Fts5HashEntry)); p->nAlloc = (int)nByte; zKey = fts5EntryKey(p); zKey[0] = bByte; memcpy(&zKey[1], pToken, nToken); assert( iHash==fts5HashKey(pHash->nSlot, (u8*)zKey, nToken+1) ); p->nKey = nToken; zKey[nToken+1] = '\0'; p->nData = nToken+1 + 1 + sizeof(Fts5HashEntry); |
︙ | ︙ | |||
291 292 293 294 295 296 297 | p->iSzPoslist = p->nData; if( pHash->eDetail!=FTS5_DETAIL_NONE ){ p->nData += 1; p->iCol = (pHash->eDetail==FTS5_DETAIL_FULL ? 0 : -1); } | < | | | > | | | | 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 | p->iSzPoslist = p->nData; if( pHash->eDetail!=FTS5_DETAIL_NONE ){ p->nData += 1; p->iCol = (pHash->eDetail==FTS5_DETAIL_FULL ? 0 : -1); } }else{ /* Appending to an existing hash-entry. Check that there is enough ** space to append the largest possible new entry. Worst case scenario ** is: ** ** + 9 bytes for a new rowid, ** + 4 byte reserved for the "poslist size" varint. ** + 1 byte for a "new column" byte, ** + 3 bytes for a new column number (16-bit max) as a varint, ** + 5 bytes for the new position offset (32-bit max). */ if( (p->nAlloc - p->nData) < (9 + 4 + 1 + 3 + 5) ){ sqlite3_int64 nNew = p->nAlloc * 2; Fts5HashEntry *pNew; Fts5HashEntry **pp; pNew = (Fts5HashEntry*)sqlite3_realloc64(p, nNew); if( pNew==0 ) return SQLITE_NOMEM; pNew->nAlloc = (int)nNew; for(pp=&pHash->aSlot[iHash]; *pp!=p; pp=&(*pp)->pHashNext); *pp = pNew; p = pNew; } nIncr -= p->nData; } assert( (p->nAlloc - p->nData) >= (9 + 4 + 1 + 3 + 5) ); pPtr = (u8*)p; /* If this is a new rowid, append the 4-byte size field for the previous ** entry, and the new rowid for this entry. */ if( iRowid!=p->iRowid ){ u64 iDiff = (u64)iRowid - (u64)p->iRowid; fts5HashAddPoslistSize(pHash, p, 0); p->nData += sqlite3Fts5PutVarint(&pPtr[p->nData], iDiff); p->iRowid = iRowid; bNew = 1; p->iSzPoslist = p->nData; if( pHash->eDetail!=FTS5_DETAIL_NONE ){ p->nData += 1; p->iCol = (pHash->eDetail==FTS5_DETAIL_FULL ? 0 : -1); p->iPos = 0; } } if( iCol>=0 ){ if( pHash->eDetail==FTS5_DETAIL_NONE ){ p->bContent = 1; }else{ /* Append a new column value, if necessary */ assert_nc( iCol>=p->iCol ); if( iCol!=p->iCol ){ if( pHash->eDetail==FTS5_DETAIL_FULL ){ pPtr[p->nData++] = 0x01; p->nData += sqlite3Fts5PutVarint(&pPtr[p->nData], iCol); p->iCol = (i16)iCol; p->iPos = 0; }else{ |
︙ | ︙ | |||
434 435 436 437 438 439 440 | const int nMergeSlot = 32; Fts5HashEntry **ap; Fts5HashEntry *pList; int iSlot; int i; *ppSorted = 0; | | > | > | 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 | const int nMergeSlot = 32; Fts5HashEntry **ap; Fts5HashEntry *pList; int iSlot; int i; *ppSorted = 0; ap = sqlite3_malloc64(sizeof(Fts5HashEntry*) * nMergeSlot); if( !ap ) return SQLITE_NOMEM; memset(ap, 0, sizeof(Fts5HashEntry*) * nMergeSlot); for(iSlot=0; iSlot<pHash->nSlot; iSlot++){ Fts5HashEntry *pIter; for(pIter=pHash->aSlot[iSlot]; pIter; pIter=pIter->pHashNext){ if( pTerm==0 || (pIter->nKey+1>=nTerm && 0==memcmp(fts5EntryKey(pIter), pTerm, nTerm)) ){ Fts5HashEntry *pEntry = pIter; pEntry->pScanNext = 0; for(i=0; ap[i]; i++){ pEntry = fts5HashEntryMerge(pEntry, ap[i]); ap[i] = 0; } ap[i] = pEntry; |
︙ | ︙ | |||
469 470 471 472 473 474 475 476 | } /* ** Query the hash table for a doclist associated with term pTerm/nTerm. */ int sqlite3Fts5HashQuery( Fts5Hash *pHash, /* Hash table to query */ const char *pTerm, int nTerm, /* Query term */ | > | > | > > > > > > | | > | > > | | 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 | } /* ** Query the hash table for a doclist associated with term pTerm/nTerm. */ int sqlite3Fts5HashQuery( Fts5Hash *pHash, /* Hash table to query */ int nPre, const char *pTerm, int nTerm, /* Query term */ void **ppOut, /* OUT: Pointer to new object */ int *pnDoclist /* OUT: Size of doclist in bytes */ ){ unsigned int iHash = fts5HashKey(pHash->nSlot, (const u8*)pTerm, nTerm); char *zKey = 0; Fts5HashEntry *p; for(p=pHash->aSlot[iHash]; p; p=p->pHashNext){ zKey = fts5EntryKey(p); assert( p->nKey+1==(int)strlen(zKey) ); if( nTerm==p->nKey+1 && memcmp(zKey, pTerm, nTerm)==0 ) break; } if( p ){ int nHashPre = sizeof(Fts5HashEntry) + nTerm + 1; int nList = p->nData - nHashPre; u8 *pRet = (u8*)(*ppOut = sqlite3_malloc64(nPre + nList + 10)); if( pRet ){ Fts5HashEntry *pFaux = (Fts5HashEntry*)&pRet[nPre-nHashPre]; memcpy(&pRet[nPre], &((u8*)p)[nHashPre], nList); nList += fts5HashAddPoslistSize(pHash, p, pFaux); *pnDoclist = nList; }else{ *pnDoclist = 0; return SQLITE_NOMEM; } }else{ *ppOut = 0; *pnDoclist = 0; } return SQLITE_OK; } int sqlite3Fts5HashScanInit( |
︙ | ︙ | |||
520 521 522 523 524 525 526 | const u8 **ppDoclist, /* OUT: pointer to doclist */ int *pnDoclist /* OUT: size of doclist in bytes */ ){ Fts5HashEntry *p; if( (p = pHash->pScan) ){ char *zKey = fts5EntryKey(p); int nTerm = (int)strlen(zKey); | | < | 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 | const u8 **ppDoclist, /* OUT: pointer to doclist */ int *pnDoclist /* OUT: size of doclist in bytes */ ){ Fts5HashEntry *p; if( (p = pHash->pScan) ){ char *zKey = fts5EntryKey(p); int nTerm = (int)strlen(zKey); fts5HashAddPoslistSize(pHash, p, 0); *pzTerm = zKey; *ppDoclist = (const u8*)&zKey[nTerm+1]; *pnDoclist = p->nData - (sizeof(Fts5HashEntry) + nTerm + 1); }else{ *pzTerm = 0; *ppDoclist = 0; *pnDoclist = 0; } } |
Changes to ext/fts5/fts5_index.c.
︙ | ︙ | |||
235 236 237 238 239 240 241 | ((i64)(height) << (FTS5_DATA_PAGE_B)) + \ ((i64)(pgno)) \ ) #define FTS5_SEGMENT_ROWID(segid, pgno) fts5_dri(segid, 0, 0, pgno) #define FTS5_DLIDX_ROWID(segid, height, pgno) fts5_dri(segid, 1, height, pgno) | < < < < < | 235 236 237 238 239 240 241 242 243 244 245 246 247 248 | ((i64)(height) << (FTS5_DATA_PAGE_B)) + \ ((i64)(pgno)) \ ) #define FTS5_SEGMENT_ROWID(segid, pgno) fts5_dri(segid, 0, 0, pgno) #define FTS5_DLIDX_ROWID(segid, height, pgno) fts5_dri(segid, 1, height, pgno) #ifdef SQLITE_DEBUG int sqlite3Fts5Corrupt() { return SQLITE_CORRUPT_VTAB; } #endif /* ** Each time a blob is read from the %_data table, it is padded with this |
︙ | ︙ | |||
432 433 434 435 436 437 438 | */ struct Fts5SegIter { Fts5StructureSegment *pSeg; /* Segment to iterate through */ int flags; /* Mask of configuration flags */ int iLeafPgno; /* Current leaf page number */ Fts5Data *pLeaf; /* Current leaf data */ Fts5Data *pNextLeaf; /* Leaf page (iLeafPgno+1) */ | | | 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 | */ struct Fts5SegIter { Fts5StructureSegment *pSeg; /* Segment to iterate through */ int flags; /* Mask of configuration flags */ int iLeafPgno; /* Current leaf page number */ Fts5Data *pLeaf; /* Current leaf data */ Fts5Data *pNextLeaf; /* Leaf page (iLeafPgno+1) */ i64 iLeafOffset; /* Byte offset within current leaf */ /* Next method */ void (*xNext)(Fts5Index*, Fts5SegIter*, int*); /* The page and offset from which the current term was read. The offset ** is the offset of the first rowid in the current doclist. */ int iTermLeafPgno; |
︙ | ︙ | |||
508 509 510 511 512 513 514 | ** Used by sqlite3Fts5IterPoslist() when the poslist needs to be buffered. ** There is no way to tell if this is populated or not. */ struct Fts5Iter { Fts5IndexIter base; /* Base class containing output vars */ Fts5Index *pIndex; /* Index that owns this iterator */ | < | 503 504 505 506 507 508 509 510 511 512 513 514 515 516 | ** Used by sqlite3Fts5IterPoslist() when the poslist needs to be buffered. ** There is no way to tell if this is populated or not. */ struct Fts5Iter { Fts5IndexIter base; /* Base class containing output vars */ Fts5Index *pIndex; /* Index that owns this iterator */ Fts5Buffer poslist; /* Buffer containing current poslist */ Fts5Colset *pColset; /* Restrict matches to these columns */ /* Invoked to set output variables. */ void (*xSetOutputs)(Fts5Iter*, Fts5SegIter*); int nSeg; /* Size of aSeg[] array */ |
︙ | ︙ | |||
569 570 571 572 573 574 575 | /* ** Allocate and return a buffer at least nByte bytes in size. ** ** If an OOM error is encountered, return NULL and set the error code in ** the Fts5Index handle passed as the first argument. */ | | | 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 | /* ** Allocate and return a buffer at least nByte bytes in size. ** ** If an OOM error is encountered, return NULL and set the error code in ** the Fts5Index handle passed as the first argument. */ static void *fts5IdxMalloc(Fts5Index *p, sqlite3_int64 nByte){ return sqlite3Fts5MallocZero(&p->rc, nByte); } /* ** Compare the contents of the pLeft buffer with the pRight/nRight blob. ** ** Return -ve if pLeft is smaller than pRight, 0 if they are equal or |
︙ | ︙ | |||
602 603 604 605 606 607 608 | ** ** Return -ve if pLeft is smaller than pRight, 0 if they are equal or ** +ve if pRight is smaller than pLeft. In other words: ** ** res = *pLeft - *pRight */ static int fts5BufferCompare(Fts5Buffer *pLeft, Fts5Buffer *pRight){ | > | > > | | | 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 | ** ** Return -ve if pLeft is smaller than pRight, 0 if they are equal or ** +ve if pRight is smaller than pLeft. In other words: ** ** res = *pLeft - *pRight */ static int fts5BufferCompare(Fts5Buffer *pLeft, Fts5Buffer *pRight){ int nCmp, res; nCmp = MIN(pLeft->n, pRight->n); assert( nCmp<=0 || pLeft->p!=0 ); assert( nCmp<=0 || pRight->p!=0 ); res = fts5Memcmp(pLeft->p, pRight->p, nCmp); return (res==0 ? (pLeft->n - pRight->n) : res); } static int fts5LeafFirstTermOff(Fts5Data *pLeaf){ int ret; fts5GetVarint32(&pLeaf->p[pLeaf->szLeaf], ret); return ret; } /* ** Close the read-only blob handle, if it is open. */ void sqlite3Fts5IndexCloseReader(Fts5Index *p){ if( p->pReader ){ sqlite3_blob *pReader = p->pReader; p->pReader = 0; sqlite3_blob_close(pReader); } } |
︙ | ︙ | |||
645 646 647 648 649 650 651 | ** is required. */ sqlite3_blob *pBlob = p->pReader; p->pReader = 0; rc = sqlite3_blob_reopen(pBlob, iRowid); assert( p->pReader==0 ); p->pReader = pBlob; if( rc!=SQLITE_OK ){ | | | 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 | ** is required. */ sqlite3_blob *pBlob = p->pReader; p->pReader = 0; rc = sqlite3_blob_reopen(pBlob, iRowid); assert( p->pReader==0 ); p->pReader = pBlob; if( rc!=SQLITE_OK ){ sqlite3Fts5IndexCloseReader(p); } if( rc==SQLITE_ABORT ) rc = SQLITE_OK; } /* If the blob handle is not open at this point, open it and seek ** to the requested entry. */ if( p->pReader==0 && rc==SQLITE_OK ){ |
︙ | ︙ | |||
669 670 671 672 673 674 675 | ** table, missing row, non-blob/text in block column - indicate ** backing store corruption. */ if( rc==SQLITE_ERROR ) rc = FTS5_CORRUPT; if( rc==SQLITE_OK ){ u8 *aOut = 0; /* Read blob data into this buffer */ int nByte = sqlite3_blob_bytes(p->pReader); | | | > > > | | > | 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 | ** table, missing row, non-blob/text in block column - indicate ** backing store corruption. */ if( rc==SQLITE_ERROR ) rc = FTS5_CORRUPT; if( rc==SQLITE_OK ){ u8 *aOut = 0; /* Read blob data into this buffer */ int nByte = sqlite3_blob_bytes(p->pReader); sqlite3_int64 nAlloc = sizeof(Fts5Data) + nByte + FTS5_DATA_PADDING; pRet = (Fts5Data*)sqlite3_malloc64(nAlloc); if( pRet ){ pRet->nn = nByte; aOut = pRet->p = (u8*)&pRet[1]; }else{ rc = SQLITE_NOMEM; } if( rc==SQLITE_OK ){ rc = sqlite3_blob_read(p->pReader, aOut, nByte, 0); } if( rc!=SQLITE_OK ){ sqlite3_free(pRet); pRet = 0; }else{ /* TODO1: Fix this */ pRet->p[nByte] = 0x00; pRet->p[nByte+1] = 0x00; pRet->szLeaf = fts5GetU16(&pRet->p[2]); } } p->rc = rc; p->nRead++; } assert( (pRet==0)==(p->rc!=SQLITE_OK) ); return pRet; } /* ** Release a reference to data record returned by an earlier call to ** fts5DataRead(). */ static void fts5DataRelease(Fts5Data *pData){ sqlite3_free(pData); } static Fts5Data *fts5LeafRead(Fts5Index *p, i64 iRowid){ Fts5Data *pRet = fts5DataRead(p, iRowid); if( pRet ){ if( pRet->nn<4 || pRet->szLeaf>pRet->nn ){ p->rc = FTS5_CORRUPT; fts5DataRelease(pRet); pRet = 0; } } return pRet; } static int fts5IndexPrepareStmt( Fts5Index *p, sqlite3_stmt **ppStmt, char *zSql ){ if( p->rc==SQLITE_OK ){ if( zSql ){ p->rc = sqlite3_prepare_v3(p->pConfig->db, zSql, -1, SQLITE_PREPARE_PERSISTENT|SQLITE_PREPARE_NO_VTAB, ppStmt, 0); }else{ p->rc = SQLITE_NOMEM; } } sqlite3_free(zSql); return p->rc; } |
︙ | ︙ | |||
766 767 768 769 770 771 772 | ** ** DELETE FROM %_data WHERE id BETWEEN $iFirst AND $iLast */ static void fts5DataDelete(Fts5Index *p, i64 iFirst, i64 iLast){ if( p->rc!=SQLITE_OK ) return; if( p->pDeleter==0 ){ | < < < < < | < < < < < < | 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 | ** ** DELETE FROM %_data WHERE id BETWEEN $iFirst AND $iLast */ static void fts5DataDelete(Fts5Index *p, i64 iFirst, i64 iLast){ if( p->rc!=SQLITE_OK ) return; if( p->pDeleter==0 ){ Fts5Config *pConfig = p->pConfig; char *zSql = sqlite3_mprintf( "DELETE FROM '%q'.'%q_data' WHERE id>=? AND id<=?", pConfig->zDb, pConfig->zName ); if( fts5IndexPrepareStmt(p, &p->pDeleter, zSql) ) return; } sqlite3_bind_int64(p->pDeleter, 1, iFirst); sqlite3_bind_int64(p->pDeleter, 2, iLast); sqlite3_step(p->pDeleter); p->rc = sqlite3_reset(p->pDeleter); } |
︙ | ︙ | |||
830 831 832 833 834 835 836 837 838 839 840 841 842 843 | sqlite3_free(pStruct); } } static void fts5StructureRef(Fts5Structure *pStruct){ pStruct->nRef++; } /* ** Deserialize and return the structure record currently stored in serialized ** form within buffer pData/nData. ** ** The Fts5Structure.aLevel[] and each Fts5StructureLevel.aSeg[] array ** are over-allocated by one slot. This allows the structure contents | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | sqlite3_free(pStruct); } } static void fts5StructureRef(Fts5Structure *pStruct){ pStruct->nRef++; } void *sqlite3Fts5StructureRef(Fts5Index *p){ fts5StructureRef(p->pStruct); return (void*)p->pStruct; } void sqlite3Fts5StructureRelease(void *p){ if( p ){ fts5StructureRelease((Fts5Structure*)p); } } int sqlite3Fts5StructureTest(Fts5Index *p, void *pStruct){ if( p->pStruct!=(Fts5Structure*)pStruct ){ return SQLITE_ABORT; } return SQLITE_OK; } /* ** Ensure that structure object (*pp) is writable. ** ** This function is a no-op if (*pRc) is not SQLITE_OK when it is called. If ** an error occurs, (*pRc) is set to an SQLite error code before returning. */ static void fts5StructureMakeWritable(int *pRc, Fts5Structure **pp){ Fts5Structure *p = *pp; if( *pRc==SQLITE_OK && p->nRef>1 ){ i64 nByte = sizeof(Fts5Structure)+(p->nLevel-1)*sizeof(Fts5StructureLevel); Fts5Structure *pNew; pNew = (Fts5Structure*)sqlite3Fts5MallocZero(pRc, nByte); if( pNew ){ int i; memcpy(pNew, p, nByte); for(i=0; i<p->nLevel; i++) pNew->aLevel[i].aSeg = 0; for(i=0; i<p->nLevel; i++){ Fts5StructureLevel *pLvl = &pNew->aLevel[i]; nByte = sizeof(Fts5StructureSegment) * pNew->aLevel[i].nSeg; pLvl->aSeg = (Fts5StructureSegment*)sqlite3Fts5MallocZero(pRc, nByte); if( pLvl->aSeg==0 ){ for(i=0; i<p->nLevel; i++){ sqlite3_free(pNew->aLevel[i].aSeg); } sqlite3_free(pNew); return; } memcpy(pLvl->aSeg, p->aLevel[i].aSeg, nByte); } p->nRef--; pNew->nRef = 1; } *pp = pNew; } } /* ** Deserialize and return the structure record currently stored in serialized ** form within buffer pData/nData. ** ** The Fts5Structure.aLevel[] and each Fts5StructureLevel.aSeg[] array ** are over-allocated by one slot. This allows the structure contents |
︙ | ︙ | |||
854 855 856 857 858 859 860 | Fts5Structure **ppOut /* OUT: Deserialized object */ ){ int rc = SQLITE_OK; int i = 0; int iLvl; int nLevel = 0; int nSegment = 0; | | > > > > > | 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 | Fts5Structure **ppOut /* OUT: Deserialized object */ ){ int rc = SQLITE_OK; int i = 0; int iLvl; int nLevel = 0; int nSegment = 0; sqlite3_int64 nByte; /* Bytes of space to allocate at pRet */ Fts5Structure *pRet = 0; /* Structure object to return */ /* Grab the cookie value */ if( piCookie ) *piCookie = sqlite3Fts5Get32(pData); i = 4; /* Read the total number of levels and segments from the start of the ** structure record. */ i += fts5GetVarint32(&pData[i], nLevel); i += fts5GetVarint32(&pData[i], nSegment); if( nLevel>FTS5_MAX_SEGMENT || nLevel<0 || nSegment>FTS5_MAX_SEGMENT || nSegment<0 ){ return FTS5_CORRUPT; } nByte = ( sizeof(Fts5Structure) + /* Main structure */ sizeof(Fts5StructureLevel) * (nLevel-1) /* aLevel[] array */ ); pRet = (Fts5Structure*)sqlite3Fts5MallocZero(&rc, nByte); if( pRet ){ |
︙ | ︙ | |||
887 888 889 890 891 892 893 | int iSeg; if( i>=nData ){ rc = FTS5_CORRUPT; }else{ i += fts5GetVarint32(&pData[i], pLvl->nMerge); i += fts5GetVarint32(&pData[i], nTotal); | | > > | | | > > > | | > > | > > > > | > | | | 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 | int iSeg; if( i>=nData ){ rc = FTS5_CORRUPT; }else{ i += fts5GetVarint32(&pData[i], pLvl->nMerge); i += fts5GetVarint32(&pData[i], nTotal); if( nTotal<pLvl->nMerge ) rc = FTS5_CORRUPT; pLvl->aSeg = (Fts5StructureSegment*)sqlite3Fts5MallocZero(&rc, nTotal * sizeof(Fts5StructureSegment) ); nSegment -= nTotal; } if( rc==SQLITE_OK ){ pLvl->nSeg = nTotal; for(iSeg=0; iSeg<nTotal; iSeg++){ Fts5StructureSegment *pSeg = &pLvl->aSeg[iSeg]; if( i>=nData ){ rc = FTS5_CORRUPT; break; } i += fts5GetVarint32(&pData[i], pSeg->iSegid); i += fts5GetVarint32(&pData[i], pSeg->pgnoFirst); i += fts5GetVarint32(&pData[i], pSeg->pgnoLast); if( pSeg->pgnoLast<pSeg->pgnoFirst ){ rc = FTS5_CORRUPT; break; } } if( iLvl>0 && pLvl[-1].nMerge && nTotal==0 ) rc = FTS5_CORRUPT; if( iLvl==nLevel-1 && pLvl->nMerge ) rc = FTS5_CORRUPT; } } if( nSegment!=0 && rc==SQLITE_OK ) rc = FTS5_CORRUPT; if( rc!=SQLITE_OK ){ fts5StructureRelease(pRet); pRet = 0; } } *ppOut = pRet; return rc; } /* ** Add a level to the Fts5Structure.aLevel[] array of structure object ** (*ppStruct). */ static void fts5StructureAddLevel(int *pRc, Fts5Structure **ppStruct){ fts5StructureMakeWritable(pRc, ppStruct); if( *pRc==SQLITE_OK ){ Fts5Structure *pStruct = *ppStruct; int nLevel = pStruct->nLevel; sqlite3_int64 nByte = ( sizeof(Fts5Structure) + /* Main structure */ sizeof(Fts5StructureLevel) * (nLevel+1) /* aLevel[] array */ ); pStruct = sqlite3_realloc64(pStruct, nByte); if( pStruct ){ memset(&pStruct->aLevel[nLevel], 0, sizeof(Fts5StructureLevel)); pStruct->nLevel++; *ppStruct = pStruct; }else{ *pRc = SQLITE_NOMEM; } |
︙ | ︙ | |||
953 954 955 956 957 958 959 | int iLvl, int nExtra, int bInsert ){ if( *pRc==SQLITE_OK ){ Fts5StructureLevel *pLvl = &pStruct->aLevel[iLvl]; Fts5StructureSegment *aNew; | | | | 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 | int iLvl, int nExtra, int bInsert ){ if( *pRc==SQLITE_OK ){ Fts5StructureLevel *pLvl = &pStruct->aLevel[iLvl]; Fts5StructureSegment *aNew; sqlite3_int64 nByte; nByte = (pLvl->nSeg + nExtra) * sizeof(Fts5StructureSegment); aNew = sqlite3_realloc64(pLvl->aSeg, nByte); if( aNew ){ if( bInsert==0 ){ memset(&aNew[pLvl->nSeg], 0, sizeof(Fts5StructureSegment) * nExtra); }else{ int nMove = pLvl->nSeg * sizeof(Fts5StructureSegment); memmove(&aNew[nExtra], aNew, nMove); memset(aNew, 0, sizeof(Fts5StructureSegment) * nExtra); |
︙ | ︙ | |||
983 984 985 986 987 988 989 | Fts5Data *pData; pData = fts5DataRead(p, FTS5_STRUCTURE_ROWID); if( p->rc==SQLITE_OK ){ /* TODO: Do we need this if the leaf-index is appended? Probably... */ memset(&pData->p[pData->nn], 0, FTS5_DATA_PADDING); p->rc = fts5StructureDecode(pData->p, pData->nn, &iCookie, &pRet); | | | 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 | Fts5Data *pData; pData = fts5DataRead(p, FTS5_STRUCTURE_ROWID); if( p->rc==SQLITE_OK ){ /* TODO: Do we need this if the leaf-index is appended? Probably... */ memset(&pData->p[pData->nn], 0, FTS5_DATA_PADDING); p->rc = fts5StructureDecode(pData->p, pData->nn, &iCookie, &pRet); if( p->rc==SQLITE_OK && (pConfig->pgsz==0 || pConfig->iCookie!=iCookie) ){ p->rc = sqlite3Fts5ConfigLoad(pConfig, iCookie); } fts5DataRelease(pData); if( p->rc!=SQLITE_OK ){ fts5StructureRelease(pRet); pRet = 0; } |
︙ | ︙ | |||
1470 1471 1472 1473 1474 1475 1476 | int iLeafPg /* Leaf page number to load dlidx for */ ){ Fts5DlidxIter *pIter = 0; int i; int bDone = 0; for(i=0; p->rc==SQLITE_OK && bDone==0; i++){ | | | | 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 | int iLeafPg /* Leaf page number to load dlidx for */ ){ Fts5DlidxIter *pIter = 0; int i; int bDone = 0; for(i=0; p->rc==SQLITE_OK && bDone==0; i++){ sqlite3_int64 nByte = sizeof(Fts5DlidxIter) + i * sizeof(Fts5DlidxLvl); Fts5DlidxIter *pNew; pNew = (Fts5DlidxIter*)sqlite3_realloc64(pIter, nByte); if( pNew==0 ){ p->rc = SQLITE_NOMEM; }else{ i64 iRowid = FTS5_DLIDX_ROWID(iSegid, i, iLeafPg); Fts5DlidxLvl *pLvl = &pNew->aLvl[i]; pIter = pNew; memset(pLvl, 0, sizeof(Fts5DlidxLvl)); |
︙ | ︙ | |||
1606 1607 1608 1609 1610 1611 1612 | } pIter->iLeafOffset = iOff; } } static void fts5SegIterLoadRowid(Fts5Index *p, Fts5SegIter *pIter){ u8 *a = pIter->pLeaf->p; /* Buffer to read data from */ | | | 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 | } pIter->iLeafOffset = iOff; } } static void fts5SegIterLoadRowid(Fts5Index *p, Fts5SegIter *pIter){ u8 *a = pIter->pLeaf->p; /* Buffer to read data from */ i64 iOff = pIter->iLeafOffset; ASSERT_SZLEAF_OK(pIter->pLeaf); if( iOff>=pIter->pLeaf->szLeaf ){ fts5SegIterNextPage(p, pIter); if( pIter->pLeaf==0 ){ if( p->rc==SQLITE_OK ) p->rc = FTS5_CORRUPT; return; |
︙ | ︙ | |||
1639 1640 1641 1642 1643 1644 1645 | ** ** accordingly and leaves (Fts5SegIter.iLeafOffset) set to the content of ** the first position list. The position list belonging to document ** (Fts5SegIter.iRowid). */ static void fts5SegIterLoadTerm(Fts5Index *p, Fts5SegIter *pIter, int nKeep){ u8 *a = pIter->pLeaf->p; /* Buffer to read data from */ | | | > | 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 | ** ** accordingly and leaves (Fts5SegIter.iLeafOffset) set to the content of ** the first position list. The position list belonging to document ** (Fts5SegIter.iRowid). */ static void fts5SegIterLoadTerm(Fts5Index *p, Fts5SegIter *pIter, int nKeep){ u8 *a = pIter->pLeaf->p; /* Buffer to read data from */ i64 iOff = pIter->iLeafOffset; /* Offset to read at */ int nNew; /* Bytes of new data */ iOff += fts5GetVarint32(&a[iOff], nNew); if( iOff+nNew>pIter->pLeaf->szLeaf || nKeep>pIter->term.n || nNew==0 ){ p->rc = FTS5_CORRUPT; return; } pIter->term.n = nKeep; fts5BufferAppendBlob(&p->rc, &pIter->term, nNew, &a[iOff]); assert( pIter->term.n<=pIter->term.nSpace ); iOff += nNew; pIter->iTermLeafOffset = iOff; pIter->iTermLeafPgno = pIter->iLeafPgno; pIter->iLeafOffset = iOff; if( pIter->iPgidxOff>=pIter->pLeaf->nn ){ pIter->iEndofDoclist = pIter->pLeaf->nn+1; |
︙ | ︙ | |||
1712 1713 1714 1715 1716 1717 1718 1719 | pIter->pSeg = pSeg; pIter->iLeafPgno = pSeg->pgnoFirst-1; fts5SegIterNextPage(p, pIter); } if( p->rc==SQLITE_OK ){ pIter->iLeafOffset = 4; assert_nc( pIter->pLeaf->nn>4 ); | > | | 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 | pIter->pSeg = pSeg; pIter->iLeafPgno = pSeg->pgnoFirst-1; fts5SegIterNextPage(p, pIter); } if( p->rc==SQLITE_OK ){ pIter->iLeafOffset = 4; assert( pIter->pLeaf!=0 ); assert_nc( pIter->pLeaf->nn>4 ); assert_nc( fts5LeafFirstTermOff(pIter->pLeaf)==4 ); pIter->iPgidxOff = pIter->pLeaf->szLeaf+1; fts5SegIterLoadTerm(p, pIter, 0); fts5SegIterLoadNPos(p, pIter); } } /* |
︙ | ︙ | |||
1748 1749 1750 1751 1752 1753 1754 | if( n>pIter->iEndofDoclist ){ n = pIter->iEndofDoclist; } ASSERT_SZLEAF_OK(pIter->pLeaf); while( 1 ){ | | | | | 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 | if( n>pIter->iEndofDoclist ){ n = pIter->iEndofDoclist; } ASSERT_SZLEAF_OK(pIter->pLeaf); while( 1 ){ u64 iDelta = 0; if( eDetail==FTS5_DETAIL_NONE ){ /* todo */ if( i<n && a[i]==0 ){ i++; if( i<n && a[i]==0 ) i++; } }else{ int nPos; int bDummy; i += fts5GetPoslistSize(&a[i], &nPos, &bDummy); i += nPos; } if( i>=n ) break; i += fts5GetVarint(&a[i], &iDelta); pIter->iRowid += iDelta; /* If necessary, grow the pIter->aRowidOffset[] array. */ if( iRowidOffset>=pIter->nRowidOffset ){ int nNew = pIter->nRowidOffset + 8; int *aNew = (int*)sqlite3_realloc64(pIter->aRowidOffset,nNew*sizeof(int)); if( aNew==0 ){ p->rc = SQLITE_NOMEM; break; } pIter->aRowidOffset = aNew; pIter->nRowidOffset = nNew; } |
︙ | ︙ | |||
1862 1863 1864 1865 1866 1867 1868 | assert( pIter->flags & FTS5_SEGITER_REVERSE ); assert( pIter->pNextLeaf==0 ); UNUSED_PARAM(pbUnused); if( pIter->iRowidOffset>0 ){ u8 *a = pIter->pLeaf->p; int iOff; | | | | 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 | assert( pIter->flags & FTS5_SEGITER_REVERSE ); assert( pIter->pNextLeaf==0 ); UNUSED_PARAM(pbUnused); if( pIter->iRowidOffset>0 ){ u8 *a = pIter->pLeaf->p; int iOff; u64 iDelta; pIter->iRowidOffset--; pIter->iLeafOffset = pIter->aRowidOffset[pIter->iRowidOffset]; fts5SegIterLoadNPos(p, pIter); iOff = pIter->iLeafOffset; if( p->pConfig->eDetail!=FTS5_DETAIL_NONE ){ iOff += pIter->nPos; } fts5GetVarint(&a[iOff], &iDelta); pIter->iRowid -= iDelta; }else{ fts5SegIterReverseNewPage(p, pIter); } } /* |
︙ | ︙ | |||
2064 2065 2066 2067 2068 2069 2070 | fts5SegIterLoadTerm(p, pIter, nKeep); fts5SegIterLoadNPos(p, pIter); if( pbNewTerm ) *pbNewTerm = 1; } }else{ /* The following could be done by calling fts5SegIterLoadNPos(). But ** this block is particularly performance critical, so equivalent | | < < < < < | | 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 | fts5SegIterLoadTerm(p, pIter, nKeep); fts5SegIterLoadNPos(p, pIter); if( pbNewTerm ) *pbNewTerm = 1; } }else{ /* The following could be done by calling fts5SegIterLoadNPos(). But ** this block is particularly performance critical, so equivalent ** code is inlined. */ int nSz; assert_nc( pIter->iLeafOffset<=pIter->pLeaf->nn ); fts5FastGetVarint32(pIter->pLeaf->p, pIter->iLeafOffset, nSz); pIter->bDel = (nSz & 0x0001); pIter->nPos = nSz>>1; assert_nc( pIter->nPos>=0 ); } } } |
︙ | ︙ | |||
2100 2101 2102 2103 2104 2105 2106 | Fts5DlidxIter *pDlidx = pIter->pDlidx; Fts5Data *pLast = 0; int pgnoLast = 0; if( pDlidx ){ int iSegid = pIter->pSeg->iSegid; pgnoLast = fts5DlidxIterPgno(pDlidx); | | | 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 | Fts5DlidxIter *pDlidx = pIter->pDlidx; Fts5Data *pLast = 0; int pgnoLast = 0; if( pDlidx ){ int iSegid = pIter->pSeg->iSegid; pgnoLast = fts5DlidxIterPgno(pDlidx); pLast = fts5LeafRead(p, FTS5_SEGMENT_ROWID(iSegid, pgnoLast)); }else{ Fts5Data *pLeaf = pIter->pLeaf; /* Current leaf data */ /* Currently, Fts5SegIter.iLeafOffset points to the first byte of ** position-list content for the current rowid. Back it up so that it ** points to the start of the position-list size field. */ int iPoslist; |
︙ | ︙ | |||
2127 2128 2129 2130 2131 2132 2133 | int pgno; Fts5StructureSegment *pSeg = pIter->pSeg; /* The last rowid in the doclist may not be on the current page. Search ** forward to find the page containing the last rowid. */ for(pgno=pIter->iLeafPgno+1; !p->rc && pgno<=pSeg->pgnoLast; pgno++){ i64 iAbs = FTS5_SEGMENT_ROWID(pSeg->iSegid, pgno); | | | 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 | int pgno; Fts5StructureSegment *pSeg = pIter->pSeg; /* The last rowid in the doclist may not be on the current page. Search ** forward to find the page containing the last rowid. */ for(pgno=pIter->iLeafPgno+1; !p->rc && pgno<=pSeg->pgnoLast; pgno++){ i64 iAbs = FTS5_SEGMENT_ROWID(pSeg->iSegid, pgno); Fts5Data *pNew = fts5LeafRead(p, iAbs); if( pNew ){ int iRowid, bTermless; iRowid = fts5LeafFirstRowidOff(pNew); bTermless = fts5LeafIsTermless(pNew); if( iRowid ){ SWAPVAL(Fts5Data*, pNew, pLast); pgnoLast = pgno; |
︙ | ︙ | |||
2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 | */ if( pLast ){ int iOff; fts5DataRelease(pIter->pLeaf); pIter->pLeaf = pLast; pIter->iLeafPgno = pgnoLast; iOff = fts5LeafFirstRowidOff(pLast); iOff += fts5GetVarint(&pLast->p[iOff], (u64*)&pIter->iRowid); pIter->iLeafOffset = iOff; if( fts5LeafIsTermless(pLast) ){ pIter->iEndofDoclist = pLast->nn+1; }else{ pIter->iEndofDoclist = fts5LeafFirstTermOff(pLast); } | > > > > < | 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 | */ if( pLast ){ int iOff; fts5DataRelease(pIter->pLeaf); pIter->pLeaf = pLast; pIter->iLeafPgno = pgnoLast; iOff = fts5LeafFirstRowidOff(pLast); if( iOff>pLast->szLeaf ){ p->rc = FTS5_CORRUPT; return; } iOff += fts5GetVarint(&pLast->p[iOff], (u64*)&pIter->iRowid); pIter->iLeafOffset = iOff; if( fts5LeafIsTermless(pLast) ){ pIter->iEndofDoclist = pLast->nn+1; }else{ pIter->iEndofDoclist = fts5LeafFirstTermOff(pLast); } } fts5SegIterReverseInitPage(p, pIter); } /* ** Iterator pIter currently points to the first rowid of a doclist. |
︙ | ︙ | |||
2218 2219 2220 2221 2222 2223 2224 | */ static void fts5LeafSeek( Fts5Index *p, /* Leave any error code here */ int bGe, /* True for a >= search */ Fts5SegIter *pIter, /* Iterator to seek */ const u8 *pTerm, int nTerm /* Term to search for */ ){ | | < | | | | | | | | | | | | 2277 2278 2279 2280 2281 2282 2283 2284 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 2326 2327 2328 2329 2330 | */ static void fts5LeafSeek( Fts5Index *p, /* Leave any error code here */ int bGe, /* True for a >= search */ Fts5SegIter *pIter, /* Iterator to seek */ const u8 *pTerm, int nTerm /* Term to search for */ ){ u32 iOff; const u8 *a = pIter->pLeaf->p; u32 n = (u32)pIter->pLeaf->nn; u32 nMatch = 0; u32 nKeep = 0; u32 nNew = 0; u32 iTermOff; u32 iPgidx; /* Current offset in pgidx */ int bEndOfPage = 0; assert( p->rc==SQLITE_OK ); iPgidx = (u32)pIter->pLeaf->szLeaf; iPgidx += fts5GetVarint32(&a[iPgidx], iTermOff); iOff = iTermOff; if( iOff>n ){ p->rc = FTS5_CORRUPT; return; } while( 1 ){ /* Figure out how many new bytes are in this term */ fts5FastGetVarint32(a, iOff, nNew); if( nKeep<nMatch ){ goto search_failed; } assert( nKeep>=nMatch ); if( nKeep==nMatch ){ u32 nCmp; u32 i; nCmp = (u32)MIN(nNew, nTerm-nMatch); for(i=0; i<nCmp; i++){ if( a[iOff+i]!=pTerm[nMatch+i] ) break; } nMatch += i; if( (u32)nTerm==nMatch ){ if( i==nNew ){ goto search_success; }else{ goto search_failed; } }else if( i<nNew && a[iOff+i]>pTerm[nMatch] ){ goto search_failed; |
︙ | ︙ | |||
2298 2299 2300 2301 2302 2303 2304 | return; }else if( bEndOfPage ){ do { fts5SegIterNextPage(p, pIter); if( pIter->pLeaf==0 ) return; a = pIter->pLeaf->p; if( fts5LeafIsTermless(pIter->pLeaf)==0 ){ | | | > | > > > | | 2356 2357 2358 2359 2360 2361 2362 2363 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 | return; }else if( bEndOfPage ){ do { fts5SegIterNextPage(p, pIter); if( pIter->pLeaf==0 ) return; a = pIter->pLeaf->p; if( fts5LeafIsTermless(pIter->pLeaf)==0 ){ iPgidx = (u32)pIter->pLeaf->szLeaf; iPgidx += fts5GetVarint32(&pIter->pLeaf->p[iPgidx], iOff); if( iOff<4 || (i64)iOff>=pIter->pLeaf->szLeaf ){ p->rc = FTS5_CORRUPT; return; }else{ nKeep = 0; iTermOff = iOff; n = (u32)pIter->pLeaf->nn; iOff += fts5GetVarint32(&a[iOff], nNew); break; } } }while( 1 ); } search_success: if( (i64)iOff+nNew>n || nNew<1 ){ p->rc = FTS5_CORRUPT; return; } pIter->iLeafOffset = iOff + nNew; pIter->iTermLeafOffset = pIter->iLeafOffset; pIter->iTermLeafPgno = pIter->iLeafPgno; fts5BufferSet(&p->rc, &pIter->term, nKeep, pTerm); fts5BufferAppendBlob(&p->rc, &pIter->term, nNew, &a[iOff]); |
︙ | ︙ | |||
2422 2423 2424 2425 2426 2427 2428 | ** ** 1) an error has occurred, or ** 2) the iterator points to EOF, or ** 3) the iterator points to an entry with term (pTerm/nTerm), or ** 4) the FTS5INDEX_QUERY_SCAN flag was set and the iterator points ** to an entry with a term greater than or equal to (pTerm/nTerm). */ | | < > > > > > > > > > < | > > > > > > | < < < < | 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 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 | ** ** 1) an error has occurred, or ** 2) the iterator points to EOF, or ** 3) the iterator points to an entry with term (pTerm/nTerm), or ** 4) the FTS5INDEX_QUERY_SCAN flag was set and the iterator points ** to an entry with a term greater than or equal to (pTerm/nTerm). */ assert_nc( p->rc!=SQLITE_OK /* 1 */ || pIter->pLeaf==0 /* 2 */ || fts5BufferCompareBlob(&pIter->term, pTerm, nTerm)==0 /* 3 */ || (bGe && fts5BufferCompareBlob(&pIter->term, pTerm, nTerm)>0) /* 4 */ ); } /* ** Initialize the object pIter to point to term pTerm/nTerm within the ** in-memory hash table. If there is no such term in the hash-table, the ** iterator is set to EOF. ** ** If an error occurs, Fts5Index.rc is set to an appropriate error code. If ** an error has already occurred when this function is called, it is a no-op. */ static void fts5SegIterHashInit( Fts5Index *p, /* FTS5 backend */ const u8 *pTerm, int nTerm, /* Term to seek to */ int flags, /* Mask of FTS5INDEX_XXX flags */ Fts5SegIter *pIter /* Object to populate */ ){ int nList = 0; const u8 *z = 0; int n = 0; Fts5Data *pLeaf = 0; assert( p->pHash ); assert( p->rc==SQLITE_OK ); if( pTerm==0 || (flags & FTS5INDEX_QUERY_SCAN) ){ const u8 *pList = 0; p->rc = sqlite3Fts5HashScanInit(p->pHash, (const char*)pTerm, nTerm); sqlite3Fts5HashScanEntry(p->pHash, (const char**)&z, &pList, &nList); n = (z ? (int)strlen((const char*)z) : 0); if( pList ){ pLeaf = fts5IdxMalloc(p, sizeof(Fts5Data)); if( pLeaf ){ pLeaf->p = (u8*)pList; } } }else{ p->rc = sqlite3Fts5HashQuery(p->pHash, sizeof(Fts5Data), (const char*)pTerm, nTerm, (void**)&pLeaf, &nList ); if( pLeaf ){ pLeaf->p = (u8*)&pLeaf[1]; } z = pTerm; n = nTerm; pIter->flags |= FTS5_SEGITER_ONETERM; } if( pLeaf ){ sqlite3Fts5BufferSet(&p->rc, &pIter->term, n, z); pLeaf->nn = pLeaf->szLeaf = nList; pIter->pLeaf = pLeaf; pIter->iLeafOffset = fts5GetVarint(pLeaf->p, (u64*)&pIter->iRowid); pIter->iEndofDoclist = pLeaf->nn; if( flags & FTS5INDEX_QUERY_DESC ){ pIter->flags |= FTS5_SEGITER_REVERSE; |
︙ | ︙ | |||
2520 2521 2522 2523 2524 2525 2526 | if( p1->pLeaf || p2->pLeaf ){ if( p1->pLeaf==0 ){ assert( pRes->iFirst==i2 ); }else if( p2->pLeaf==0 ){ assert( pRes->iFirst==i1 ); }else{ int nMin = MIN(p1->term.n, p2->term.n); | | | 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 | if( p1->pLeaf || p2->pLeaf ){ if( p1->pLeaf==0 ){ assert( pRes->iFirst==i2 ); }else if( p2->pLeaf==0 ){ assert( pRes->iFirst==i1 ); }else{ int nMin = MIN(p1->term.n, p2->term.n); int res = fts5Memcmp(p1->term.p, p2->term.p, nMin); if( res==0 ) res = p1->term.n - p2->term.n; if( res==0 ){ assert( pRes->bTermEq==1 ); assert( p1->iRowid!=p2->iRowid ); res = ((p1->iRowid > p2->iRowid)==pIter->bRev) ? -1 : 1; }else{ |
︙ | ︙ | |||
2620 2621 2622 2623 2624 2625 2626 | if( p1->pLeaf==0 ){ /* If p1 is at EOF */ iRes = i2; }else if( p2->pLeaf==0 ){ /* If p2 is at EOF */ iRes = i1; }else{ int res = fts5BufferCompare(&p1->term, &p2->term); if( res==0 ){ | | | | 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 | if( p1->pLeaf==0 ){ /* If p1 is at EOF */ iRes = i2; }else if( p2->pLeaf==0 ){ /* If p2 is at EOF */ iRes = i1; }else{ int res = fts5BufferCompare(&p1->term, &p2->term); if( res==0 ){ assert_nc( i2>i1 ); assert_nc( i2!=0 ); pRes->bTermEq = 1; if( p1->iRowid==p2->iRowid ){ p1->bDel = p2->bDel; return i2; } res = ((p1->iRowid > p2->iRowid)==pIter->bRev) ? -1 : +1; } |
︙ | ︙ | |||
2661 2662 2663 2664 2665 2666 2667 | }else{ fts5DataRelease(pIter->pNextLeaf); pIter->pNextLeaf = 0; pIter->iLeafPgno = iLeafPgno-1; fts5SegIterNextPage(p, pIter); assert( p->rc!=SQLITE_OK || pIter->iLeafPgno==iLeafPgno ); | | | 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 | }else{ fts5DataRelease(pIter->pNextLeaf); pIter->pNextLeaf = 0; pIter->iLeafPgno = iLeafPgno-1; fts5SegIterNextPage(p, pIter); assert( p->rc!=SQLITE_OK || pIter->iLeafPgno==iLeafPgno ); if( p->rc==SQLITE_OK && ALWAYS(pIter->pLeaf!=0) ){ int iOff; u8 *a = pIter->pLeaf->p; int n = pIter->pLeaf->szLeaf; iOff = fts5LeafFirstRowidOff(pIter->pLeaf); if( iOff<4 || iOff>=n ){ p->rc = FTS5_CORRUPT; |
︙ | ︙ | |||
2743 2744 2745 2746 2747 2748 2749 | */ static void fts5MultiIterFree(Fts5Iter *pIter){ if( pIter ){ int i; for(i=0; i<pIter->nSeg; i++){ fts5SegIterClear(&pIter->aSeg[i]); } | < | 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 | */ static void fts5MultiIterFree(Fts5Iter *pIter){ if( pIter ){ int i; for(i=0; i<pIter->nSeg; i++){ fts5SegIterClear(&pIter->aSeg[i]); } fts5BufferFree(&pIter->poslist); sqlite3_free(pIter); } } static void fts5MultiIterAdvanced( Fts5Index *p, /* FTS5 backend to iterate within */ |
︙ | ︙ | |||
3051 3052 3053 3054 3055 3056 3057 | int nRem = pSeg->nPos; /* Number of bytes still to come */ Fts5Data *pData = 0; u8 *pChunk = &pSeg->pLeaf->p[pSeg->iLeafOffset]; int nChunk = MIN(nRem, pSeg->pLeaf->szLeaf - pSeg->iLeafOffset); int pgno = pSeg->iLeafPgno; int pgnoSave = 0; | | > > > | 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 | int nRem = pSeg->nPos; /* Number of bytes still to come */ Fts5Data *pData = 0; u8 *pChunk = &pSeg->pLeaf->p[pSeg->iLeafOffset]; int nChunk = MIN(nRem, pSeg->pLeaf->szLeaf - pSeg->iLeafOffset); int pgno = pSeg->iLeafPgno; int pgnoSave = 0; /* This function does not work with detail=none databases. */ assert( p->pConfig->eDetail!=FTS5_DETAIL_NONE ); if( (pSeg->flags & FTS5_SEGITER_REVERSE)==0 ){ pgnoSave = pgno+1; } while( 1 ){ xChunk(p, pCtx, pChunk, nChunk); nRem -= nChunk; fts5DataRelease(pData); if( nRem<=0 ){ break; }else if( pSeg->pSeg==0 ){ p->rc = FTS5_CORRUPT; return; }else{ pgno++; pData = fts5LeafRead(p, FTS5_SEGMENT_ROWID(pSeg->pSeg->iSegid, pgno)); if( pData==0 ) break; pChunk = &pData->p[4]; nChunk = MIN(nRem, pData->szLeaf - 4); if( pgno==pgnoSave ){ |
︙ | ︙ | |||
3091 3092 3093 3094 3095 3096 3097 | */ static void fts5SegiterPoslist( Fts5Index *p, Fts5SegIter *pSeg, Fts5Colset *pColset, Fts5Buffer *pBuf ){ | > > | > > > | 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 | */ static void fts5SegiterPoslist( Fts5Index *p, Fts5SegIter *pSeg, Fts5Colset *pColset, Fts5Buffer *pBuf ){ assert( pBuf!=0 ); assert( pSeg!=0 ); if( 0==fts5BufferGrow(&p->rc, pBuf, pSeg->nPos+FTS5_DATA_ZERO_PADDING) ){ assert( pBuf->p!=0 ); assert( pBuf->nSpace >= pBuf->n+pSeg->nPos+FTS5_DATA_ZERO_PADDING ); memset(&pBuf->p[pBuf->n+pSeg->nPos], 0, FTS5_DATA_ZERO_PADDING); if( pColset==0 ){ fts5ChunkIterate(p, pSeg, (void*)pBuf, fts5PoslistCallback); }else{ if( p->pConfig->eDetail==FTS5_DETAIL_FULL ){ PoslistCallbackCtx sCtx; sCtx.pBuf = pBuf; sCtx.pColset = pColset; |
︙ | ︙ | |||
3114 3115 3116 3117 3118 3119 3120 | fts5ChunkIterate(p, pSeg, (void*)&sCtx, fts5PoslistOffsetsCallback); } } } } /* | | | | | < < < < < < < < < | | < < < < < | < < < < < < < < < < < < | < < < < < | | < | | > > > | > | > > > > > > > | > > > > > | > > > > > > | | > > > > | > > > > | > > > > > | > > > | 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 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 | fts5ChunkIterate(p, pSeg, (void*)&sCtx, fts5PoslistOffsetsCallback); } } } } /* ** Parameter pPos points to a buffer containing a position list, size nPos. ** This function filters it according to pColset (which must be non-NULL) ** and sets pIter->base.pData/nData to point to the new position list. ** If memory is required for the new position list, use buffer pIter->poslist. ** Or, if the new position list is a contiguous subset of the input, set ** pIter->base.pData/nData to point directly to it. ** ** This function is a no-op if *pRc is other than SQLITE_OK when it is ** called. If an OOM error is encountered, *pRc is set to SQLITE_NOMEM ** before returning. */ static void fts5IndexExtractColset( int *pRc, Fts5Colset *pColset, /* Colset to filter on */ const u8 *pPos, int nPos, /* Position list */ Fts5Iter *pIter ){ if( *pRc==SQLITE_OK ){ const u8 *p = pPos; const u8 *aCopy = p; const u8 *pEnd = &p[nPos]; /* One byte past end of position list */ int i = 0; int iCurrent = 0; if( pColset->nCol>1 && sqlite3Fts5BufferSize(pRc, &pIter->poslist, nPos) ){ return; } while( 1 ){ while( pColset->aiCol[i]<iCurrent ){ i++; if( i==pColset->nCol ){ pIter->base.pData = pIter->poslist.p; pIter->base.nData = pIter->poslist.n; return; } } /* Advance pointer p until it points to pEnd or an 0x01 byte that is ** not part of a varint */ while( p<pEnd && *p!=0x01 ){ while( *p++ & 0x80 ); } if( pColset->aiCol[i]==iCurrent ){ if( pColset->nCol==1 ){ pIter->base.pData = aCopy; pIter->base.nData = p-aCopy; return; } fts5BufferSafeAppendBlob(&pIter->poslist, aCopy, p-aCopy); } if( p>=pEnd ){ pIter->base.pData = pIter->poslist.p; pIter->base.nData = pIter->poslist.n; return; } aCopy = p++; iCurrent = *p++; if( iCurrent & 0x80 ){ p--; p += fts5GetVarint32(p, iCurrent); } } } } /* ** xSetOutputs callback used by detail=none tables. */ static void fts5IterSetOutputs_None(Fts5Iter *pIter, Fts5SegIter *pSeg){ assert( pIter->pIndex->pConfig->eDetail==FTS5_DETAIL_NONE ); |
︙ | ︙ | |||
3293 3294 3295 3296 3297 3298 3299 | assert( pIter->pIndex->pConfig->eDetail==FTS5_DETAIL_FULL ); assert( pColset ); if( pSeg->iLeafOffset+pSeg->nPos<=pSeg->pLeaf->szLeaf ){ /* All data is stored on the current page. Populate the output ** variables to point into the body of the page object. */ const u8 *a = &pSeg->pLeaf->p[pSeg->iLeafOffset]; | < < < < | | | < < < > | 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 3404 3405 3406 | assert( pIter->pIndex->pConfig->eDetail==FTS5_DETAIL_FULL ); assert( pColset ); if( pSeg->iLeafOffset+pSeg->nPos<=pSeg->pLeaf->szLeaf ){ /* All data is stored on the current page. Populate the output ** variables to point into the body of the page object. */ const u8 *a = &pSeg->pLeaf->p[pSeg->iLeafOffset]; int *pRc = &pIter->pIndex->rc; fts5BufferZero(&pIter->poslist); fts5IndexExtractColset(pRc, pColset, a, pSeg->nPos, pIter); }else{ /* The data is distributed over two or more pages. Copy it into the ** Fts5Iter.poslist buffer and then set the output pointer to point ** to this buffer. */ fts5BufferZero(&pIter->poslist); fts5SegiterPoslist(pIter->pIndex, pSeg, pColset, &pIter->poslist); pIter->base.pData = pIter->poslist.p; pIter->base.nData = pIter->poslist.n; } } static void fts5IterSetOutputCb(int *pRc, Fts5Iter *pIter){ assert( pIter!=0 || (*pRc)!=SQLITE_OK ); if( *pRc==SQLITE_OK ){ Fts5Config *pConfig = pIter->pIndex->pConfig; if( pConfig->eDetail==FTS5_DETAIL_NONE ){ pIter->xSetOutputs = fts5IterSetOutputs_None; } else if( pIter->pColset==0 ){ |
︙ | ︙ | |||
3386 3387 3388 3389 3390 3391 3392 | nSeg = pStruct->nSegment; nSeg += (p->pHash ? 1 : 0); }else{ nSeg = MIN(pStruct->aLevel[iLevel].nSeg, nSegment); } } *ppOut = pNew = fts5MultiIterAlloc(p, nSeg); | | > > > < < | 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 | nSeg = pStruct->nSegment; nSeg += (p->pHash ? 1 : 0); }else{ nSeg = MIN(pStruct->aLevel[iLevel].nSeg, nSegment); } } *ppOut = pNew = fts5MultiIterAlloc(p, nSeg); if( pNew==0 ){ assert( p->rc!=SQLITE_OK ); goto fts5MultiIterNew_post_check; } pNew->bRev = (0!=(flags & FTS5INDEX_QUERY_DESC)); pNew->bSkipEmpty = (0!=(flags & FTS5INDEX_QUERY_SKIPEMPTY)); pNew->pColset = pColset; if( (flags & FTS5INDEX_QUERY_NOOUTPUT)==0 ){ fts5IterSetOutputCb(&p->rc, pNew); } /* Initialize each of the component segment iterators. */ if( p->rc==SQLITE_OK ){ if( iLevel<0 ){ |
︙ | ︙ | |||
3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464 3465 | pNew->xSetOutputs(pNew, pSeg); } }else{ fts5MultiIterFree(pNew); *ppOut = 0; } } /* ** Create an Fts5Iter that iterates through the doclist provided ** as the second argument. */ static void fts5MultiIterNew2( | > > > > | 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 | pNew->xSetOutputs(pNew, pSeg); } }else{ fts5MultiIterFree(pNew); *ppOut = 0; } fts5MultiIterNew_post_check: assert( (*ppOut)!=0 || p->rc!=SQLITE_OK ); return; } /* ** Create an Fts5Iter that iterates through the doclist provided ** as the second argument. */ static void fts5MultiIterNew2( |
︙ | ︙ | |||
3499 3500 3501 3502 3503 3504 3505 | } /* ** Return true if the iterator is at EOF or if an error has occurred. ** False otherwise. */ static int fts5MultiIterEof(Fts5Index *p, Fts5Iter *pIter){ | > | | 3582 3583 3584 3585 3586 3587 3588 3589 3590 3591 3592 3593 3594 3595 3596 3597 | } /* ** Return true if the iterator is at EOF or if an error has occurred. ** False otherwise. */ static int fts5MultiIterEof(Fts5Index *p, Fts5Iter *pIter){ assert( pIter!=0 || p->rc!=SQLITE_OK ); assert( p->rc!=SQLITE_OK || (pIter->aSeg[ pIter->aFirst[1].iFirst ].pLeaf==0)==pIter->base.bEof ); return (p->rc || pIter->base.bEof); } /* ** Return the rowid of the entry that the iterator currently points |
︙ | ︙ | |||
3569 3570 3571 3572 3573 3574 3575 | int iLvl, iSeg; int i; u32 mask; memset(aUsed, 0, sizeof(aUsed)); for(iLvl=0; iLvl<pStruct->nLevel; iLvl++){ for(iSeg=0; iSeg<pStruct->aLevel[iLvl].nSeg; iSeg++){ int iId = pStruct->aLevel[iLvl].aSeg[iSeg].iSegid; | | | | | | | | 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 | int iLvl, iSeg; int i; u32 mask; memset(aUsed, 0, sizeof(aUsed)); for(iLvl=0; iLvl<pStruct->nLevel; iLvl++){ for(iSeg=0; iSeg<pStruct->aLevel[iLvl].nSeg; iSeg++){ int iId = pStruct->aLevel[iLvl].aSeg[iSeg].iSegid; if( iId<=FTS5_MAX_SEGMENT && iId>0 ){ aUsed[(iId-1) / 32] |= (u32)1 << ((iId-1) % 32); } } } for(i=0; aUsed[i]==0xFFFFFFFF; i++); mask = aUsed[i]; for(iSegid=0; mask & ((u32)1 << iSegid); iSegid++); iSegid += 1 + i*32; #ifdef SQLITE_DEBUG for(iLvl=0; iLvl<pStruct->nLevel; iLvl++){ for(iSeg=0; iSeg<pStruct->aLevel[iLvl].nSeg; iSeg++){ assert_nc( iSegid!=pStruct->aLevel[iLvl].aSeg[iSeg].iSegid ); } } assert_nc( iSegid>0 && iSegid<=FTS5_MAX_SEGMENT ); { sqlite3_stmt *pIdxSelect = fts5IdxSelectStmt(p); if( p->rc==SQLITE_OK ){ u8 aBlob[2] = {0xff, 0xff}; sqlite3_bind_int(pIdxSelect, 1, iSegid); sqlite3_bind_blob(pIdxSelect, 2, aBlob, 2, SQLITE_STATIC); assert_nc( sqlite3_step(pIdxSelect)!=SQLITE_ROW ); p->rc = sqlite3_reset(pIdxSelect); sqlite3_bind_null(pIdxSelect, 2); } } #endif } } |
︙ | ︙ | |||
3664 3665 3666 3667 3668 3669 3670 | */ static int fts5WriteDlidxGrow( Fts5Index *p, Fts5SegWriter *pWriter, int nLvl ){ if( p->rc==SQLITE_OK && nLvl>=pWriter->nDlidx ){ | | | | 3748 3749 3750 3751 3752 3753 3754 3755 3756 3757 3758 3759 3760 3761 3762 3763 3764 3765 3766 3767 3768 | */ static int fts5WriteDlidxGrow( Fts5Index *p, Fts5SegWriter *pWriter, int nLvl ){ if( p->rc==SQLITE_OK && nLvl>=pWriter->nDlidx ){ Fts5DlidxWriter *aDlidx = (Fts5DlidxWriter*)sqlite3_realloc64( pWriter->aDlidx, sizeof(Fts5DlidxWriter) * nLvl ); if( aDlidx==0 ){ p->rc = SQLITE_NOMEM; }else{ size_t nByte = sizeof(Fts5DlidxWriter) * (nLvl - pWriter->nDlidx); memset(&aDlidx[pWriter->nDlidx], 0, nByte); pWriter->aDlidx = aDlidx; pWriter->nDlidx = nLvl; } } return p->rc; } |
︙ | ︙ | |||
3743 3744 3745 3746 3747 3748 3749 | */ static void fts5WriteBtreeTerm( Fts5Index *p, /* FTS5 backend object */ Fts5SegWriter *pWriter, /* Writer object */ int nTerm, const u8 *pTerm /* First term on new page */ ){ fts5WriteFlushBtree(p, pWriter); | > | | > | 3827 3828 3829 3830 3831 3832 3833 3834 3835 3836 3837 3838 3839 3840 3841 3842 3843 3844 | */ static void fts5WriteBtreeTerm( Fts5Index *p, /* FTS5 backend object */ Fts5SegWriter *pWriter, /* Writer object */ int nTerm, const u8 *pTerm /* First term on new page */ ){ fts5WriteFlushBtree(p, pWriter); if( p->rc==SQLITE_OK ){ fts5BufferSet(&p->rc, &pWriter->btterm, nTerm, pTerm); pWriter->iBtPage = pWriter->writer.pgno; } } /* ** This function is called when flushing a leaf page that contains no ** terms at all to disk. */ static void fts5WriteBtreeNoTerm( |
︙ | ︙ | |||
3895 3896 3897 3898 3899 3900 3901 3902 3903 3904 3905 3906 3907 3908 3909 3910 3911 3912 3913 3914 3915 3916 3917 | Fts5Index *p, Fts5SegWriter *pWriter, int nTerm, const u8 *pTerm ){ int nPrefix; /* Bytes of prefix compression for term */ Fts5PageWriter *pPage = &pWriter->writer; Fts5Buffer *pPgidx = &pWriter->writer.pgidx; assert( p->rc==SQLITE_OK ); assert( pPage->buf.n>=4 ); assert( pPage->buf.n>4 || pWriter->bFirstTermInPage ); /* If the current leaf page is full, flush it to disk. */ if( (pPage->buf.n + pPgidx->n + nTerm + 2)>=p->pConfig->pgsz ){ if( pPage->buf.n>4 ){ fts5WriteFlushLeaf(p, pWriter); } fts5BufferGrow(&p->rc, &pPage->buf, nTerm+FTS5_DATA_PADDING); } /* TODO1: Updating pgidx here. */ pPgidx->n += sqlite3Fts5PutVarint( &pPgidx->p[pPgidx->n], pPage->buf.n - pPage->iPrevPgidx | > > | 3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994 3995 3996 3997 3998 3999 4000 4001 4002 4003 4004 4005 | Fts5Index *p, Fts5SegWriter *pWriter, int nTerm, const u8 *pTerm ){ int nPrefix; /* Bytes of prefix compression for term */ Fts5PageWriter *pPage = &pWriter->writer; Fts5Buffer *pPgidx = &pWriter->writer.pgidx; int nMin = MIN(pPage->term.n, nTerm); assert( p->rc==SQLITE_OK ); assert( pPage->buf.n>=4 ); assert( pPage->buf.n>4 || pWriter->bFirstTermInPage ); /* If the current leaf page is full, flush it to disk. */ if( (pPage->buf.n + pPgidx->n + nTerm + 2)>=p->pConfig->pgsz ){ if( pPage->buf.n>4 ){ fts5WriteFlushLeaf(p, pWriter); if( p->rc!=SQLITE_OK ) return; } fts5BufferGrow(&p->rc, &pPage->buf, nTerm+FTS5_DATA_PADDING); } /* TODO1: Updating pgidx here. */ pPgidx->n += sqlite3Fts5PutVarint( &pPgidx->p[pPgidx->n], pPage->buf.n - pPage->iPrevPgidx |
︙ | ︙ | |||
3936 3937 3938 3939 3940 3941 3942 | ** Usually, the previous term is available in pPage->term. The exception ** is if this is the first term written in an incremental-merge step. ** In this case the previous term is not available, so just write a ** copy of (pTerm/nTerm) into the parent node. This is slightly ** inefficient, but still correct. */ int n = nTerm; if( pPage->term.n ){ | | > | | 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 4034 4035 4036 4037 4038 4039 4040 4041 4042 4043 4044 4045 | ** Usually, the previous term is available in pPage->term. The exception ** is if this is the first term written in an incremental-merge step. ** In this case the previous term is not available, so just write a ** copy of (pTerm/nTerm) into the parent node. This is slightly ** inefficient, but still correct. */ int n = nTerm; if( pPage->term.n ){ n = 1 + fts5PrefixCompress(nMin, pPage->term.p, pTerm); } fts5WriteBtreeTerm(p, pWriter, n, pTerm); if( p->rc!=SQLITE_OK ) return; pPage = &pWriter->writer; } }else{ nPrefix = fts5PrefixCompress(nMin, pPage->term.p, pTerm); fts5BufferAppendVarint(&p->rc, &pPage->buf, nPrefix); } /* Append the number of bytes of new data, then the term data itself ** to the page. */ fts5BufferAppendVarint(&p->rc, &pPage->buf, nTerm - nPrefix); fts5BufferAppendBlob(&p->rc, &pPage->buf, nTerm - nPrefix, &pTerm[nPrefix]); |
︙ | ︙ | |||
3989 3990 3991 3992 3993 3994 3995 | fts5WriteDlidxAppend(p, pWriter, iRowid); } /* Write the rowid. */ if( pWriter->bFirstRowidInDoclist || pWriter->bFirstRowidInPage ){ fts5BufferAppendVarint(&p->rc, &pPage->buf, iRowid); }else{ | | | 4078 4079 4080 4081 4082 4083 4084 4085 4086 4087 4088 4089 4090 4091 4092 | fts5WriteDlidxAppend(p, pWriter, iRowid); } /* Write the rowid. */ if( pWriter->bFirstRowidInDoclist || pWriter->bFirstRowidInPage ){ fts5BufferAppendVarint(&p->rc, &pPage->buf, iRowid); }else{ assert_nc( p->rc || iRowid>pWriter->iPrevRowid ); fts5BufferAppendVarint(&p->rc, &pPage->buf, iRowid - pWriter->iPrevRowid); } pWriter->iPrevRowid = iRowid; pWriter->bFirstRowidInDoclist = 0; pWriter->bFirstRowidInPage = 0; } } |
︙ | ︙ | |||
4111 4112 4113 4114 4115 4116 4117 | ** incremental merge operation. This function is called if the incremental ** merge step has finished but the input has not been completely exhausted. */ static void fts5TrimSegments(Fts5Index *p, Fts5Iter *pIter){ int i; Fts5Buffer buf; memset(&buf, 0, sizeof(Fts5Buffer)); | | | > > > > > > > | | | | | | | | | | | | | | > | | | | | | | < | | | > > | 4200 4201 4202 4203 4204 4205 4206 4207 4208 4209 4210 4211 4212 4213 4214 4215 4216 4217 4218 4219 4220 4221 4222 4223 4224 4225 4226 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 4258 4259 4260 4261 4262 4263 4264 4265 4266 4267 4268 4269 | ** incremental merge operation. This function is called if the incremental ** merge step has finished but the input has not been completely exhausted. */ static void fts5TrimSegments(Fts5Index *p, Fts5Iter *pIter){ int i; Fts5Buffer buf; memset(&buf, 0, sizeof(Fts5Buffer)); for(i=0; i<pIter->nSeg && p->rc==SQLITE_OK; i++){ Fts5SegIter *pSeg = &pIter->aSeg[i]; if( pSeg->pSeg==0 ){ /* no-op */ }else if( pSeg->pLeaf==0 ){ /* All keys from this input segment have been transfered to the output. ** Set both the first and last page-numbers to 0 to indicate that the ** segment is now empty. */ pSeg->pSeg->pgnoLast = 0; pSeg->pSeg->pgnoFirst = 0; }else{ int iOff = pSeg->iTermLeafOffset; /* Offset on new first leaf page */ i64 iLeafRowid; Fts5Data *pData; int iId = pSeg->pSeg->iSegid; u8 aHdr[4] = {0x00, 0x00, 0x00, 0x00}; iLeafRowid = FTS5_SEGMENT_ROWID(iId, pSeg->iTermLeafPgno); pData = fts5LeafRead(p, iLeafRowid); if( pData ){ if( iOff>pData->szLeaf ){ /* This can occur if the pages that the segments occupy overlap - if ** a single page has been assigned to more than one segment. In ** this case a prior iteration of this loop may have corrupted the ** segment currently being trimmed. */ p->rc = FTS5_CORRUPT; }else{ fts5BufferZero(&buf); fts5BufferGrow(&p->rc, &buf, pData->nn); fts5BufferAppendBlob(&p->rc, &buf, sizeof(aHdr), aHdr); fts5BufferAppendVarint(&p->rc, &buf, pSeg->term.n); fts5BufferAppendBlob(&p->rc, &buf, pSeg->term.n, pSeg->term.p); fts5BufferAppendBlob(&p->rc, &buf, pData->szLeaf-iOff,&pData->p[iOff]); if( p->rc==SQLITE_OK ){ /* Set the szLeaf field */ fts5PutU16(&buf.p[2], (u16)buf.n); } /* Set up the new page-index array */ fts5BufferAppendVarint(&p->rc, &buf, 4); if( pSeg->iLeafPgno==pSeg->iTermLeafPgno && pSeg->iEndofDoclist<pData->szLeaf && pSeg->iPgidxOff<=pData->nn ){ int nDiff = pData->szLeaf - pSeg->iEndofDoclist; fts5BufferAppendVarint(&p->rc, &buf, buf.n - 1 - nDiff - 4); fts5BufferAppendBlob(&p->rc, &buf, pData->nn - pSeg->iPgidxOff, &pData->p[pSeg->iPgidxOff] ); } pSeg->pSeg->pgnoFirst = pSeg->iTermLeafPgno; fts5DataDelete(p, FTS5_SEGMENT_ROWID(iId, 1), iLeafRowid); fts5DataWrite(p, iLeafRowid, buf.p, buf.n); } fts5DataRelease(pData); } } } fts5BufferFree(&buf); } static void fts5MergeChunkCallback( |
︙ | ︙ | |||
4249 4250 4251 4252 4253 4254 4255 | ){ Fts5SegIter *pSegIter = &pIter->aSeg[ pIter->aFirst[1].iFirst ]; int nPos; /* position-list size field value */ int nTerm; const u8 *pTerm; pTerm = fts5MultiIterTerm(pIter, &nTerm); | | | 4347 4348 4349 4350 4351 4352 4353 4354 4355 4356 4357 4358 4359 4360 4361 | ){ Fts5SegIter *pSegIter = &pIter->aSeg[ pIter->aFirst[1].iFirst ]; int nPos; /* position-list size field value */ int nTerm; const u8 *pTerm; pTerm = fts5MultiIterTerm(pIter, &nTerm); if( nTerm!=term.n || fts5Memcmp(pTerm, term.p, nTerm) ){ if( pnRem && writer.nLeafWritten>nRem ){ break; } fts5BufferSet(&p->rc, &term, nTerm, pTerm); bTermWritten =0; } |
︙ | ︙ | |||
4289 4290 4291 4292 4293 4294 4295 4296 4297 4298 4299 4300 4301 4302 | } } /* Flush the last leaf page to disk. Set the output segment b-tree height ** and last leaf page number at the same time. */ fts5WriteFinish(p, &writer, &pSeg->pgnoLast); if( fts5MultiIterEof(p, pIter) ){ int i; /* Remove the redundant segments from the %_data table */ for(i=0; i<nInput; i++){ fts5DataRemoveSegment(p, pLvl->aSeg[i].iSegid); } | > | 4387 4388 4389 4390 4391 4392 4393 4394 4395 4396 4397 4398 4399 4400 4401 | } } /* Flush the last leaf page to disk. Set the output segment b-tree height ** and last leaf page number at the same time. */ fts5WriteFinish(p, &writer, &pSeg->pgnoLast); assert( pIter!=0 || p->rc!=SQLITE_OK ); if( fts5MultiIterEof(p, pIter) ){ int i; /* Remove the redundant segments from the %_data table */ for(i=0; i<nInput; i++){ fts5DataRemoveSegment(p, pLvl->aSeg[i].iSegid); } |
︙ | ︙ | |||
4389 4390 4391 4392 4393 4394 4395 | ** already occurred, this function is a no-op. */ static void fts5IndexAutomerge( Fts5Index *p, /* FTS5 backend object */ Fts5Structure **ppStruct, /* IN/OUT: Current structure of index */ int nLeaf /* Number of output leaves just written */ ){ | | | 4488 4489 4490 4491 4492 4493 4494 4495 4496 4497 4498 4499 4500 4501 4502 | ** already occurred, this function is a no-op. */ static void fts5IndexAutomerge( Fts5Index *p, /* FTS5 backend object */ Fts5Structure **ppStruct, /* IN/OUT: Current structure of index */ int nLeaf /* Number of output leaves just written */ ){ if( p->rc==SQLITE_OK && p->pConfig->nAutomerge>0 && ALWAYS((*ppStruct)!=0) ){ Fts5Structure *pStruct = *ppStruct; u64 nWrite; /* Initial value of write-counter */ int nWork; /* Number of work-quanta to perform */ int nRem; /* Number of leaf pages left to write */ /* Update the write-counter. While doing so, set nWork. */ nWrite = pStruct->nWriteCounter; |
︙ | ︙ | |||
4504 4505 4506 4507 4508 4509 4510 4511 4512 4513 4514 4515 4516 4517 | const char *zTerm; /* Buffer containing term */ const u8 *pDoclist; /* Pointer to doclist for this term */ int nDoclist; /* Size of doclist in bytes */ /* Write the term for this entry to disk. */ sqlite3Fts5HashScanEntry(pHash, &zTerm, &pDoclist, &nDoclist); fts5WriteAppendTerm(p, &writer, (int)strlen(zTerm), (const u8*)zTerm); assert( writer.bFirstRowidInPage==0 ); if( pgsz>=(pBuf->n + pPgidx->n + nDoclist + 1) ){ /* The entire doclist will fit on the current leaf. */ fts5BufferSafeAppendBlob(pBuf, pDoclist, nDoclist); }else{ i64 iRowid = 0; | > | | > | 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 | const char *zTerm; /* Buffer containing term */ const u8 *pDoclist; /* Pointer to doclist for this term */ int nDoclist; /* Size of doclist in bytes */ /* Write the term for this entry to disk. */ sqlite3Fts5HashScanEntry(pHash, &zTerm, &pDoclist, &nDoclist); fts5WriteAppendTerm(p, &writer, (int)strlen(zTerm), (const u8*)zTerm); if( p->rc!=SQLITE_OK ) break; assert( writer.bFirstRowidInPage==0 ); if( pgsz>=(pBuf->n + pPgidx->n + nDoclist + 1) ){ /* The entire doclist will fit on the current leaf. */ fts5BufferSafeAppendBlob(pBuf, pDoclist, nDoclist); }else{ i64 iRowid = 0; u64 iDelta = 0; int iOff = 0; /* The entire doclist will not fit on this leaf. The following ** loop iterates through the poslists that make up the current ** doclist. */ while( p->rc==SQLITE_OK && iOff<nDoclist ){ iOff += fts5GetVarint(&pDoclist[iOff], &iDelta); iRowid += iDelta; if( writer.bFirstRowidInPage ){ fts5PutU16(&pBuf->p[0], (u16)pBuf->n); /* first rowid on page */ pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], iRowid); writer.bFirstRowidInPage = 0; fts5WriteDlidxAppend(p, &writer, iRowid); if( p->rc!=SQLITE_OK ) break; }else{ pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], iDelta); } assert( pBuf->n<=pBuf->nSpace ); if( eDetail==FTS5_DETAIL_NONE ){ if( iOff<nDoclist && pDoclist[iOff]==0 ){ |
︙ | ︙ | |||
4583 4584 4585 4586 4587 4588 4589 | } } } /* TODO2: Doclist terminator written here. */ /* pBuf->p[pBuf->n++] = '\0'; */ assert( pBuf->n<=pBuf->nSpace ); | | | 4684 4685 4686 4687 4688 4689 4690 4691 4692 4693 4694 4695 4696 4697 4698 | } } } /* TODO2: Doclist terminator written here. */ /* pBuf->p[pBuf->n++] = '\0'; */ assert( pBuf->n<=pBuf->nSpace ); if( p->rc==SQLITE_OK ) sqlite3Fts5HashScanNext(pHash); } sqlite3Fts5HashClear(pHash); fts5WriteFinish(p, &writer, &pgnoLast); /* Update the Fts5Structure. It is written back to the database by the ** fts5StructureRelease() call below. */ if( pStruct->nLevel==0 ){ |
︙ | ︙ | |||
4627 4628 4629 4630 4631 4632 4633 | } static Fts5Structure *fts5IndexOptimizeStruct( Fts5Index *p, Fts5Structure *pStruct ){ Fts5Structure *pNew = 0; | | | 4728 4729 4730 4731 4732 4733 4734 4735 4736 4737 4738 4739 4740 4741 4742 | } static Fts5Structure *fts5IndexOptimizeStruct( Fts5Index *p, Fts5Structure *pStruct ){ Fts5Structure *pNew = 0; sqlite3_int64 nByte = sizeof(Fts5Structure); int nSeg = pStruct->nSegment; int i; /* Figure out if this structure requires optimization. A structure does ** not require optimization if either: ** ** + it consists of fewer than two segments, or |
︙ | ︙ | |||
4757 4758 4759 4760 4761 4762 4763 4764 | static void fts5AppendPoslist( Fts5Index *p, i64 iDelta, Fts5Iter *pMulti, Fts5Buffer *pBuf ){ int nData = pMulti->base.nData; assert( nData>0 ); | > | > | > > > > | | | > | 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 | static void fts5AppendPoslist( Fts5Index *p, i64 iDelta, Fts5Iter *pMulti, Fts5Buffer *pBuf ){ int nData = pMulti->base.nData; int nByte = nData + 9 + 9 + FTS5_DATA_ZERO_PADDING; assert( nData>0 ); if( p->rc==SQLITE_OK && 0==fts5BufferGrow(&p->rc, pBuf, nByte) ){ fts5BufferSafeAppendVarint(pBuf, iDelta); fts5BufferSafeAppendVarint(pBuf, nData*2); fts5BufferSafeAppendBlob(pBuf, pMulti->base.pData, nData); memset(&pBuf->p[pBuf->n], 0, FTS5_DATA_ZERO_PADDING); } } static void fts5DoclistIterNext(Fts5DoclistIter *pIter){ u8 *p = pIter->aPoslist + pIter->nSize + pIter->nPoslist; assert( pIter->aPoslist || (p==0 && pIter->aPoslist==0) ); if( p>=pIter->aEof ){ pIter->aPoslist = 0; }else{ i64 iDelta; p += fts5GetVarint(p, (u64*)&iDelta); pIter->iRowid += iDelta; /* Read position list size */ if( p[0] & 0x80 ){ int nPos; pIter->nSize = fts5GetVarint32(p, nPos); pIter->nPoslist = (nPos>>1); }else{ pIter->nPoslist = ((int)(p[0])) >> 1; pIter->nSize = 1; } pIter->aPoslist = p; if( &pIter->aPoslist[pIter->nPoslist]>pIter->aEof ){ pIter->aPoslist = 0; } } } static void fts5DoclistIterInit( Fts5Buffer *pBuf, Fts5DoclistIter *pIter ){ memset(pIter, 0, sizeof(*pIter)); if( pBuf->n>0 ){ pIter->aPoslist = pBuf->p; pIter->aEof = &pBuf->p[pBuf->n]; fts5DoclistIterNext(pIter); } } #if 0 /* ** Append a doclist to buffer pBuf. ** ** This function assumes that space within the buffer has already been |
︙ | ︙ | |||
4853 4854 4855 4856 4857 4858 4859 | /* ** This is the equivalent of fts5MergePrefixLists() for detail=none mode. ** In this case the buffers consist of a delta-encoded list of rowids only. */ static void fts5MergeRowidLists( Fts5Index *p, /* FTS5 backend object */ Fts5Buffer *p1, /* First list to merge */ | > | | > > > | 4961 4962 4963 4964 4965 4966 4967 4968 4969 4970 4971 4972 4973 4974 4975 4976 4977 4978 4979 4980 4981 4982 4983 4984 4985 4986 4987 4988 | /* ** This is the equivalent of fts5MergePrefixLists() for detail=none mode. ** In this case the buffers consist of a delta-encoded list of rowids only. */ static void fts5MergeRowidLists( Fts5Index *p, /* FTS5 backend object */ Fts5Buffer *p1, /* First list to merge */ int nBuf, /* Number of entries in apBuf[] */ Fts5Buffer *aBuf /* Array of other lists to merge into p1 */ ){ int i1 = 0; int i2 = 0; i64 iRowid1 = 0; i64 iRowid2 = 0; i64 iOut = 0; Fts5Buffer *p2 = &aBuf[0]; Fts5Buffer out; (void)nBuf; memset(&out, 0, sizeof(out)); assert( nBuf==1 ); sqlite3Fts5BufferSize(&p->rc, &out, p1->n + p2->n); if( p->rc ) return; fts5NextRowid(p1, &i1, &iRowid1); fts5NextRowid(p2, &i2, &iRowid2); while( i1>=0 || i2>=0 ){ if( i1>=0 && (i2<0 || iRowid1<iRowid2) ){ |
︙ | ︙ | |||
4888 4889 4890 4891 4892 4893 4894 4895 | fts5NextRowid(p2, &i2, &iRowid2); } } fts5BufferSwap(&out, p1); fts5BufferFree(&out); } | > > > > > | > > | > > > > > > > > > > > > > | > > | > > > > > > > | > > | | > > > > | < > > > > | | < > | | > > > > > > > > > > > > > > > > | | | | | | > > > > > > | < < | < < | < < < | | | > > | < | | < > | < | > | | | | > | | > | < < | < < < < < < < > > > | | > > > | < | < < | > > > > > > | | < > | | | < | > > > | | | < < | > | < > > | | | | | > | | < < | | > | | | | | < | | > | | > | > > > < < < | < < | | < > > > | | > | > > > > > > > > > > > > > > > > > > > > > > > > > | > | | | | > > > | > | > > | > | > | > | | 5000 5001 5002 5003 5004 5005 5006 5007 5008 5009 5010 5011 5012 5013 5014 5015 5016 5017 5018 5019 5020 5021 5022 5023 5024 5025 5026 5027 5028 5029 5030 5031 5032 5033 5034 5035 5036 5037 5038 5039 5040 5041 5042 5043 5044 5045 5046 5047 5048 5049 5050 5051 5052 5053 5054 5055 5056 5057 5058 5059 5060 5061 5062 5063 5064 5065 5066 5067 5068 5069 5070 5071 5072 5073 5074 5075 5076 5077 5078 5079 5080 5081 5082 5083 5084 5085 5086 5087 5088 5089 5090 5091 5092 5093 5094 5095 5096 5097 5098 5099 5100 5101 5102 5103 5104 5105 5106 5107 5108 5109 5110 5111 5112 5113 5114 5115 5116 5117 5118 5119 5120 5121 5122 5123 5124 5125 5126 5127 5128 5129 5130 5131 5132 5133 5134 5135 5136 5137 5138 5139 5140 5141 5142 5143 5144 5145 5146 5147 5148 5149 5150 5151 5152 5153 5154 5155 5156 5157 5158 5159 5160 5161 5162 5163 5164 5165 5166 5167 5168 5169 5170 5171 5172 5173 5174 5175 5176 5177 5178 5179 5180 5181 5182 5183 5184 5185 5186 5187 5188 5189 5190 5191 5192 5193 5194 5195 5196 5197 5198 5199 5200 5201 5202 5203 5204 5205 5206 5207 5208 5209 5210 5211 5212 5213 5214 5215 5216 5217 5218 5219 5220 5221 5222 5223 5224 5225 5226 5227 5228 5229 5230 5231 5232 5233 5234 5235 5236 5237 5238 5239 5240 5241 5242 5243 5244 5245 5246 5247 5248 5249 5250 5251 5252 5253 5254 5255 5256 5257 5258 5259 5260 5261 5262 5263 5264 5265 5266 5267 5268 5269 5270 5271 5272 5273 5274 5275 5276 5277 5278 5279 5280 5281 5282 5283 5284 5285 5286 5287 5288 5289 5290 5291 5292 5293 5294 5295 5296 5297 5298 5299 5300 5301 5302 5303 5304 5305 5306 5307 5308 5309 5310 5311 5312 5313 5314 5315 5316 5317 5318 5319 | fts5NextRowid(p2, &i2, &iRowid2); } } fts5BufferSwap(&out, p1); fts5BufferFree(&out); } typedef struct PrefixMerger PrefixMerger; struct PrefixMerger { Fts5DoclistIter iter; /* Doclist iterator */ i64 iPos; /* For iterating through a position list */ int iOff; u8 *aPos; PrefixMerger *pNext; /* Next in docid/poslist order */ }; static void fts5PrefixMergerInsertByRowid( PrefixMerger **ppHead, PrefixMerger *p ){ if( p->iter.aPoslist ){ PrefixMerger **pp = ppHead; while( *pp && p->iter.iRowid>(*pp)->iter.iRowid ){ pp = &(*pp)->pNext; } p->pNext = *pp; *pp = p; } } static void fts5PrefixMergerInsertByPosition( PrefixMerger **ppHead, PrefixMerger *p ){ if( p->iPos>=0 ){ PrefixMerger **pp = ppHead; while( *pp && p->iPos>(*pp)->iPos ){ pp = &(*pp)->pNext; } p->pNext = *pp; *pp = p; } } /* ** Array aBuf[] contains nBuf doclists. These are all merged in with the ** doclist in buffer p1. */ static void fts5MergePrefixLists( Fts5Index *p, /* FTS5 backend object */ Fts5Buffer *p1, /* First list to merge */ int nBuf, /* Number of buffers in array aBuf[] */ Fts5Buffer *aBuf /* Other lists to merge in */ ){ #define fts5PrefixMergerNextPosition(p) \ sqlite3Fts5PoslistNext64((p)->aPos,(p)->iter.nPoslist,&(p)->iOff,&(p)->iPos) #define FTS5_MERGE_NLIST 16 PrefixMerger aMerger[FTS5_MERGE_NLIST]; PrefixMerger *pHead = 0; int i; int nOut = 0; Fts5Buffer out = {0, 0, 0}; Fts5Buffer tmp = {0, 0, 0}; i64 iLastRowid = 0; /* Initialize a doclist-iterator for each input buffer. Arrange them in ** a linked-list starting at pHead in ascending order of rowid. Avoid ** linking any iterators already at EOF into the linked list at all. */ assert( nBuf+1<=sizeof(aMerger)/sizeof(aMerger[0]) ); memset(aMerger, 0, sizeof(PrefixMerger)*(nBuf+1)); pHead = &aMerger[nBuf]; fts5DoclistIterInit(p1, &pHead->iter); for(i=0; i<nBuf; i++){ fts5DoclistIterInit(&aBuf[i], &aMerger[i].iter); fts5PrefixMergerInsertByRowid(&pHead, &aMerger[i]); nOut += aBuf[i].n; } if( nOut==0 ) return; nOut += p1->n + 9 + 10*nBuf; /* The maximum size of the output is equal to the sum of the ** input sizes + 1 varint (9 bytes). The extra varint is because if the ** first rowid in one input is a large negative number, and the first in ** the other a non-negative number, the delta for the non-negative ** number will be larger on disk than the literal integer value ** was. ** ** Or, if the input position-lists are corrupt, then the output might ** include up to (nBuf+1) extra 10-byte positions created by interpreting -1 ** (the value PoslistNext64() uses for EOF) as a position and appending ** it to the output. This can happen at most once for each input ** position-list, hence (nBuf+1) 10 byte paddings. */ if( sqlite3Fts5BufferSize(&p->rc, &out, nOut) ) return; while( pHead ){ fts5MergeAppendDocid(&out, iLastRowid, pHead->iter.iRowid); if( pHead->pNext && iLastRowid==pHead->pNext->iter.iRowid ){ /* Merge data from two or more poslists */ i64 iPrev = 0; int nTmp = FTS5_DATA_ZERO_PADDING; int nMerge = 0; PrefixMerger *pSave = pHead; PrefixMerger *pThis = 0; int nTail = 0; pHead = 0; while( pSave && pSave->iter.iRowid==iLastRowid ){ PrefixMerger *pNext = pSave->pNext; pSave->iOff = 0; pSave->iPos = 0; pSave->aPos = &pSave->iter.aPoslist[pSave->iter.nSize]; fts5PrefixMergerNextPosition(pSave); nTmp += pSave->iter.nPoslist + 10; nMerge++; fts5PrefixMergerInsertByPosition(&pHead, pSave); pSave = pNext; } if( pHead==0 || pHead->pNext==0 ){ p->rc = FTS5_CORRUPT; break; } /* See the earlier comment in this function for an explanation of why ** corrupt input position lists might cause the output to consume ** at most nMerge*10 bytes of unexpected space. */ if( sqlite3Fts5BufferSize(&p->rc, &tmp, nTmp+nMerge*10) ){ break; } fts5BufferZero(&tmp); pThis = pHead; pHead = pThis->pNext; sqlite3Fts5PoslistSafeAppend(&tmp, &iPrev, pThis->iPos); fts5PrefixMergerNextPosition(pThis); fts5PrefixMergerInsertByPosition(&pHead, pThis); while( pHead->pNext ){ pThis = pHead; if( pThis->iPos!=iPrev ){ sqlite3Fts5PoslistSafeAppend(&tmp, &iPrev, pThis->iPos); } fts5PrefixMergerNextPosition(pThis); pHead = pThis->pNext; fts5PrefixMergerInsertByPosition(&pHead, pThis); } if( pHead->iPos!=iPrev ){ sqlite3Fts5PoslistSafeAppend(&tmp, &iPrev, pHead->iPos); } nTail = pHead->iter.nPoslist - pHead->iOff; /* WRITEPOSLISTSIZE */ assert_nc( tmp.n+nTail<=nTmp ); assert( tmp.n+nTail<=nTmp+nMerge*10 ); if( tmp.n+nTail>nTmp-FTS5_DATA_ZERO_PADDING ){ if( p->rc==SQLITE_OK ) p->rc = FTS5_CORRUPT; break; } fts5BufferSafeAppendVarint(&out, (tmp.n+nTail) * 2); fts5BufferSafeAppendBlob(&out, tmp.p, tmp.n); if( nTail>0 ){ fts5BufferSafeAppendBlob(&out, &pHead->aPos[pHead->iOff], nTail); } pHead = pSave; for(i=0; i<nBuf+1; i++){ PrefixMerger *pX = &aMerger[i]; if( pX->iter.aPoslist && pX->iter.iRowid==iLastRowid ){ fts5DoclistIterNext(&pX->iter); fts5PrefixMergerInsertByRowid(&pHead, pX); } } }else{ /* Copy poslist from pHead to output */ PrefixMerger *pThis = pHead; Fts5DoclistIter *pI = &pThis->iter; fts5BufferSafeAppendBlob(&out, pI->aPoslist, pI->nPoslist+pI->nSize); fts5DoclistIterNext(pI); pHead = pThis->pNext; fts5PrefixMergerInsertByRowid(&pHead, pThis); } } fts5BufferFree(p1); fts5BufferFree(&tmp); memset(&out.p[out.n], 0, FTS5_DATA_ZERO_PADDING); *p1 = out; } static void fts5SetupPrefixIter( Fts5Index *p, /* Index to read from */ int bDesc, /* True for "ORDER BY rowid DESC" */ int iIdx, /* Index to scan for data */ u8 *pToken, /* Buffer containing prefix to match */ int nToken, /* Size of buffer pToken in bytes */ Fts5Colset *pColset, /* Restrict matches to these columns */ Fts5Iter **ppIter /* OUT: New iterator */ ){ Fts5Structure *pStruct; Fts5Buffer *aBuf; int nBuf = 32; int nMerge = 1; void (*xMerge)(Fts5Index*, Fts5Buffer*, int, Fts5Buffer*); void (*xAppend)(Fts5Index*, i64, Fts5Iter*, Fts5Buffer*); if( p->pConfig->eDetail==FTS5_DETAIL_NONE ){ xMerge = fts5MergeRowidLists; xAppend = fts5AppendRowid; }else{ nMerge = FTS5_MERGE_NLIST-1; nBuf = nMerge*8; /* Sufficient to merge (16^8)==(2^32) lists */ xMerge = fts5MergePrefixLists; xAppend = fts5AppendPoslist; } aBuf = (Fts5Buffer*)fts5IdxMalloc(p, sizeof(Fts5Buffer)*nBuf); pStruct = fts5StructureRead(p); if( aBuf && pStruct ){ const int flags = FTS5INDEX_QUERY_SCAN | FTS5INDEX_QUERY_SKIPEMPTY | FTS5INDEX_QUERY_NOOUTPUT; int i; i64 iLastRowid = 0; Fts5Iter *p1 = 0; /* Iterator used to gather data from index */ Fts5Data *pData; Fts5Buffer doclist; int bNewTerm = 1; memset(&doclist, 0, sizeof(doclist)); if( iIdx!=0 ){ int dummy = 0; const int f2 = FTS5INDEX_QUERY_SKIPEMPTY|FTS5INDEX_QUERY_NOOUTPUT; pToken[0] = FTS5_MAIN_PREFIX; fts5MultiIterNew(p, pStruct, f2, pColset, pToken, nToken, -1, 0, &p1); fts5IterSetOutputCb(&p->rc, p1); for(; fts5MultiIterEof(p, p1)==0; fts5MultiIterNext2(p, p1, &dummy) ){ Fts5SegIter *pSeg = &p1->aSeg[ p1->aFirst[1].iFirst ]; p1->xSetOutputs(p1, pSeg); if( p1->base.nData ){ xAppend(p, p1->base.iRowid-iLastRowid, p1, &doclist); iLastRowid = p1->base.iRowid; } } fts5MultiIterFree(p1); } pToken[0] = FTS5_MAIN_PREFIX + iIdx; fts5MultiIterNew(p, pStruct, flags, pColset, pToken, nToken, -1, 0, &p1); fts5IterSetOutputCb(&p->rc, p1); for( /* no-op */ ; fts5MultiIterEof(p, p1)==0; fts5MultiIterNext2(p, p1, &bNewTerm) ){ Fts5SegIter *pSeg = &p1->aSeg[ p1->aFirst[1].iFirst ]; int nTerm = pSeg->term.n; const u8 *pTerm = pSeg->term.p; p1->xSetOutputs(p1, pSeg); assert_nc( memcmp(pToken, pTerm, MIN(nToken, nTerm))<=0 ); if( bNewTerm ){ if( nTerm<nToken || memcmp(pToken, pTerm, nToken) ) break; } if( p1->base.nData==0 ) continue; if( p1->base.iRowid<=iLastRowid && doclist.n>0 ){ for(i=0; p->rc==SQLITE_OK && doclist.n; i++){ int i1 = i*nMerge; int iStore; assert( i1+nMerge<=nBuf ); for(iStore=i1; iStore<i1+nMerge; iStore++){ if( aBuf[iStore].n==0 ){ fts5BufferSwap(&doclist, &aBuf[iStore]); fts5BufferZero(&doclist); break; } } if( iStore==i1+nMerge ){ xMerge(p, &doclist, nMerge, &aBuf[i1]); for(iStore=i1; iStore<i1+nMerge; iStore++){ fts5BufferZero(&aBuf[iStore]); } } } iLastRowid = 0; } xAppend(p, p1->base.iRowid-iLastRowid, p1, &doclist); iLastRowid = p1->base.iRowid; } assert( (nBuf%nMerge)==0 ); for(i=0; i<nBuf; i+=nMerge){ int iFree; if( p->rc==SQLITE_OK ){ xMerge(p, &doclist, nMerge, &aBuf[i]); } for(iFree=i; iFree<i+nMerge; iFree++){ fts5BufferFree(&aBuf[iFree]); } } fts5MultiIterFree(p1); pData = fts5IdxMalloc(p, sizeof(Fts5Data)+doclist.n+FTS5_DATA_ZERO_PADDING); if( pData ){ pData->p = (u8*)&pData[1]; pData->nn = pData->szLeaf = doclist.n; if( doclist.n ) memcpy(pData->p, doclist.p, doclist.n); fts5MultiIterNew2(p, pData, bDesc, ppIter); } fts5BufferFree(&doclist); |
︙ | ︙ | |||
5144 5145 5146 5147 5148 5149 5150 | /* ** Commit data to disk. */ int sqlite3Fts5IndexSync(Fts5Index *p){ assert( p->rc==SQLITE_OK ); fts5IndexFlush(p); | | | > | 5351 5352 5353 5354 5355 5356 5357 5358 5359 5360 5361 5362 5363 5364 5365 5366 5367 5368 5369 5370 5371 5372 5373 5374 5375 5376 5377 5378 5379 5380 5381 5382 5383 5384 5385 5386 5387 5388 5389 5390 5391 | /* ** Commit data to disk. */ int sqlite3Fts5IndexSync(Fts5Index *p){ assert( p->rc==SQLITE_OK ); fts5IndexFlush(p); sqlite3Fts5IndexCloseReader(p); return fts5IndexReturn(p); } /* ** Discard any data stored in the in-memory hash tables. Do not write it ** to the database. Additionally, assume that the contents of the %_data ** table may have changed on disk. So any in-memory caches of %_data ** records must be invalidated. */ int sqlite3Fts5IndexRollback(Fts5Index *p){ sqlite3Fts5IndexCloseReader(p); fts5IndexDiscardData(p); fts5StructureInvalidate(p); /* assert( p->rc==SQLITE_OK ); */ return SQLITE_OK; } /* ** The %_data table is completely empty when this function is called. This ** function populates it with the initial structure objects for each index, ** and the initial version of the "averages" record (a zero-byte blob). */ int sqlite3Fts5IndexReinit(Fts5Index *p){ Fts5Structure s; fts5StructureInvalidate(p); fts5IndexDiscardData(p); memset(&s, 0, sizeof(Fts5Structure)); fts5DataWrite(p, FTS5_AVERAGES_ROWID, (const u8*)"", 0); fts5StructureWrite(p, &s); return fts5IndexReturn(p); } /* |
︙ | ︙ | |||
5257 5258 5259 5260 5261 5262 5263 5264 5265 | int nChar ){ int n = 0; int i; for(i=0; i<nChar; i++){ if( n>=nByte ) return 0; /* Input contains fewer than nChar chars */ if( (unsigned char)p[n++]>=0xc0 ){ while( (p[n] & 0xc0)==0x80 ){ n++; | > | > > > | 5465 5466 5467 5468 5469 5470 5471 5472 5473 5474 5475 5476 5477 5478 5479 5480 5481 5482 5483 5484 5485 | int nChar ){ int n = 0; int i; for(i=0; i<nChar; i++){ if( n>=nByte ) return 0; /* Input contains fewer than nChar chars */ if( (unsigned char)p[n++]>=0xc0 ){ if( n>=nByte ) return 0; while( (p[n] & 0xc0)==0x80 ){ n++; if( n>=nByte ){ if( i+1==nChar ) break; return 0; } } } } return n; } /* |
︙ | ︙ | |||
5344 5345 5346 5347 5348 5349 5350 5351 5352 5353 5354 5355 5356 5357 | Fts5Buffer buf = {0, 0, 0}; /* If the QUERY_SCAN flag is set, all other flags must be clear. */ assert( (flags & FTS5INDEX_QUERY_SCAN)==0 || flags==FTS5INDEX_QUERY_SCAN ); if( sqlite3Fts5BufferSize(&p->rc, &buf, nToken+1)==0 ){ int iIdx = 0; /* Index to search */ if( nToken ) memcpy(&buf.p[1], pToken, nToken); /* Figure out which index to search and set iIdx accordingly. If this ** is a prefix query for which there is no prefix index, set iIdx to ** greater than pConfig->nPrefix to indicate that the query will be ** satisfied by scanning multiple terms in the main index. ** | > | 5556 5557 5558 5559 5560 5561 5562 5563 5564 5565 5566 5567 5568 5569 5570 | Fts5Buffer buf = {0, 0, 0}; /* If the QUERY_SCAN flag is set, all other flags must be clear. */ assert( (flags & FTS5INDEX_QUERY_SCAN)==0 || flags==FTS5INDEX_QUERY_SCAN ); if( sqlite3Fts5BufferSize(&p->rc, &buf, nToken+1)==0 ){ int iIdx = 0; /* Index to search */ int iPrefixIdx = 0; /* +1 prefix index */ if( nToken ) memcpy(&buf.p[1], pToken, nToken); /* Figure out which index to search and set iIdx accordingly. If this ** is a prefix query for which there is no prefix index, set iIdx to ** greater than pConfig->nPrefix to indicate that the query will be ** satisfied by scanning multiple terms in the main index. ** |
︙ | ︙ | |||
5365 5366 5367 5368 5369 5370 5371 | assert( flags & FTS5INDEX_QUERY_PREFIX ); iIdx = 1+pConfig->nPrefix; }else #endif if( flags & FTS5INDEX_QUERY_PREFIX ){ int nChar = fts5IndexCharlen(pToken, nToken); for(iIdx=1; iIdx<=pConfig->nPrefix; iIdx++){ | | > > < | > | > > | | | | > | | 5578 5579 5580 5581 5582 5583 5584 5585 5586 5587 5588 5589 5590 5591 5592 5593 5594 5595 5596 5597 5598 5599 5600 5601 5602 5603 5604 5605 5606 5607 5608 5609 5610 5611 5612 5613 5614 5615 5616 5617 5618 5619 5620 5621 5622 5623 5624 5625 5626 5627 | assert( flags & FTS5INDEX_QUERY_PREFIX ); iIdx = 1+pConfig->nPrefix; }else #endif if( flags & FTS5INDEX_QUERY_PREFIX ){ int nChar = fts5IndexCharlen(pToken, nToken); for(iIdx=1; iIdx<=pConfig->nPrefix; iIdx++){ int nIdxChar = pConfig->aPrefix[iIdx-1]; if( nIdxChar==nChar ) break; if( nIdxChar==nChar+1 ) iPrefixIdx = iIdx; } } if( iIdx<=pConfig->nPrefix ){ /* Straight index lookup */ Fts5Structure *pStruct = fts5StructureRead(p); buf.p[0] = (u8)(FTS5_MAIN_PREFIX + iIdx); if( pStruct ){ fts5MultiIterNew(p, pStruct, flags | FTS5INDEX_QUERY_SKIPEMPTY, pColset, buf.p, nToken+1, -1, 0, &pRet ); fts5StructureRelease(pStruct); } }else{ /* Scan multiple terms in the main index */ int bDesc = (flags & FTS5INDEX_QUERY_DESC)!=0; fts5SetupPrefixIter(p, bDesc, iPrefixIdx, buf.p, nToken+1, pColset,&pRet); if( pRet==0 ){ assert( p->rc!=SQLITE_OK ); }else{ assert( pRet->pColset==0 ); fts5IterSetOutputCb(&p->rc, pRet); if( p->rc==SQLITE_OK ){ Fts5SegIter *pSeg = &pRet->aSeg[pRet->aFirst[1].iFirst]; if( pSeg->pLeaf ) pRet->xSetOutputs(pRet, pSeg); } } } if( p->rc ){ sqlite3Fts5IterClose((Fts5IndexIter*)pRet); pRet = 0; sqlite3Fts5IndexCloseReader(p); } *ppIter = (Fts5IndexIter*)pRet; sqlite3Fts5BufferFree(&buf); } return fts5IndexReturn(p); } |
︙ | ︙ | |||
5456 5457 5458 5459 5460 5461 5462 5463 | /* ** Return the current term. */ const char *sqlite3Fts5IterTerm(Fts5IndexIter *pIndexIter, int *pn){ int n; const char *z = (const char*)fts5MultiIterTerm((Fts5Iter*)pIndexIter, &n); *pn = n-1; | > | | | 5674 5675 5676 5677 5678 5679 5680 5681 5682 5683 5684 5685 5686 5687 5688 5689 5690 5691 5692 5693 5694 5695 5696 5697 5698 5699 5700 5701 | /* ** Return the current term. */ const char *sqlite3Fts5IterTerm(Fts5IndexIter *pIndexIter, int *pn){ int n; const char *z = (const char*)fts5MultiIterTerm((Fts5Iter*)pIndexIter, &n); assert_nc( z || n<=1 ); *pn = n-1; return (z ? &z[1] : 0); } /* ** Close an iterator opened by an earlier call to sqlite3Fts5IndexQuery(). */ void sqlite3Fts5IterClose(Fts5IndexIter *pIndexIter){ if( pIndexIter ){ Fts5Iter *pIter = (Fts5Iter*)pIndexIter; Fts5Index *pIndex = pIter->pIndex; fts5MultiIterFree(pIter); sqlite3Fts5IndexCloseReader(pIndex); } } /* ** Read and decode the "averages" record from the database. ** ** Parameter anSize must point to an array of size nCol, where nCol is |
︙ | ︙ | |||
5635 5636 5637 5638 5639 5640 5641 | u64 *pCksum /* IN/OUT: Checksum value */ ){ int eDetail = p->pConfig->eDetail; u64 cksum = *pCksum; Fts5IndexIter *pIter = 0; int rc = sqlite3Fts5IndexQuery(p, z, n, flags, 0, &pIter); | | | 5854 5855 5856 5857 5858 5859 5860 5861 5862 5863 5864 5865 5866 5867 5868 | u64 *pCksum /* IN/OUT: Checksum value */ ){ int eDetail = p->pConfig->eDetail; u64 cksum = *pCksum; Fts5IndexIter *pIter = 0; int rc = sqlite3Fts5IndexQuery(p, z, n, flags, 0, &pIter); while( rc==SQLITE_OK && ALWAYS(pIter!=0) && 0==sqlite3Fts5IterEof(pIter) ){ i64 rowid = pIter->iRowid; if( eDetail==FTS5_DETAIL_NONE ){ cksum ^= sqlite3Fts5IndexEntryCksum(rowid, 0, 0, iIdx, z, n); }else{ Fts5PoslistReader sReader; for(sqlite3Fts5PoslistReaderInit(pIter->pData, pIter->nData, &sReader); |
︙ | ︙ | |||
5661 5662 5663 5664 5665 5666 5667 5668 5669 5670 5671 5672 5673 5674 | } sqlite3Fts5IterClose(pIter); *pCksum = cksum; return rc; } /* ** This function is also purely an internal test. It does not contribute to ** FTS functionality, or even the integrity-check, in any way. */ static void fts5TestTerm( Fts5Index *p, | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 5880 5881 5882 5883 5884 5885 5886 5887 5888 5889 5890 5891 5892 5893 5894 5895 5896 5897 5898 5899 5900 5901 5902 5903 5904 5905 5906 5907 5908 5909 5910 5911 5912 5913 5914 5915 5916 5917 5918 5919 5920 5921 5922 5923 5924 | } sqlite3Fts5IterClose(pIter); *pCksum = cksum; return rc; } /* ** Check if buffer z[], size n bytes, contains as series of valid utf-8 ** encoded codepoints. If so, return 0. Otherwise, if the buffer does not ** contain valid utf-8, return non-zero. */ static int fts5TestUtf8(const char *z, int n){ int i = 0; assert_nc( n>0 ); while( i<n ){ if( (z[i] & 0x80)==0x00 ){ i++; }else if( (z[i] & 0xE0)==0xC0 ){ if( i+1>=n || (z[i+1] & 0xC0)!=0x80 ) return 1; i += 2; }else if( (z[i] & 0xF0)==0xE0 ){ if( i+2>=n || (z[i+1] & 0xC0)!=0x80 || (z[i+2] & 0xC0)!=0x80 ) return 1; i += 3; }else if( (z[i] & 0xF8)==0xF0 ){ if( i+3>=n || (z[i+1] & 0xC0)!=0x80 || (z[i+2] & 0xC0)!=0x80 ) return 1; if( (z[i+2] & 0xC0)!=0x80 ) return 1; i += 3; }else{ return 1; } } return 0; } /* ** This function is also purely an internal test. It does not contribute to ** FTS functionality, or even the integrity-check, in any way. */ static void fts5TestTerm( Fts5Index *p, |
︙ | ︙ | |||
5701 5702 5703 5704 5705 5706 5707 | /* If this is a prefix query, check that the results returned if the ** the index is disabled are the same. In both ASC and DESC order. ** ** This check may only be performed if the hash table is empty. This ** is because the hash table only supports a single scan query at ** a time, and the multi-iter loop from which this function is called | | > > > > > > | | 5951 5952 5953 5954 5955 5956 5957 5958 5959 5960 5961 5962 5963 5964 5965 5966 5967 5968 5969 5970 5971 5972 | /* If this is a prefix query, check that the results returned if the ** the index is disabled are the same. In both ASC and DESC order. ** ** This check may only be performed if the hash table is empty. This ** is because the hash table only supports a single scan query at ** a time, and the multi-iter loop from which this function is called ** is already performing such a scan. ** ** Also only do this if buffer zTerm contains nTerm bytes of valid ** utf-8. Otherwise, the last part of the buffer contents might contain ** a non-utf-8 sequence that happens to be a prefix of a valid utf-8 ** character stored in the main fts index, which will cause the ** test to fail. */ if( p->nPendingData==0 && 0==fts5TestUtf8(zTerm, nTerm) ){ if( iIdx>0 && rc==SQLITE_OK ){ int f = flags|FTS5INDEX_QUERY_TEST_NOIDX; ck2 = 0; rc = fts5QueryCksum(p, iIdx, zTerm, nTerm, f, &ck2); if( rc==SQLITE_OK && ck1!=ck2 ) rc = FTS5_CORRUPT; } if( iIdx>0 && rc==SQLITE_OK ){ |
︙ | ︙ | |||
5825 5826 5827 5828 5829 5830 5831 | int rc2; int iIdxPrevLeaf = pSeg->pgnoFirst-1; int iDlidxPrevLeaf = pSeg->pgnoLast; if( pSeg->pgnoFirst==0 ) return; fts5IndexPrepareStmt(p, &pStmt, sqlite3_mprintf( | | > > < | 6081 6082 6083 6084 6085 6086 6087 6088 6089 6090 6091 6092 6093 6094 6095 6096 6097 6098 6099 6100 6101 6102 6103 6104 6105 6106 | int rc2; int iIdxPrevLeaf = pSeg->pgnoFirst-1; int iDlidxPrevLeaf = pSeg->pgnoLast; if( pSeg->pgnoFirst==0 ) return; fts5IndexPrepareStmt(p, &pStmt, sqlite3_mprintf( "SELECT segid, term, (pgno>>1), (pgno&1) FROM %Q.'%q_idx' WHERE segid=%d " "ORDER BY 1, 2", pConfig->zDb, pConfig->zName, pSeg->iSegid )); /* Iterate through the b-tree hierarchy. */ while( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){ i64 iRow; /* Rowid for this leaf */ Fts5Data *pLeaf; /* Data for this leaf */ const char *zIdxTerm = (const char*)sqlite3_column_blob(pStmt, 1); int nIdxTerm = sqlite3_column_bytes(pStmt, 1); int iIdxLeaf = sqlite3_column_int(pStmt, 2); int bIdxDlidx = sqlite3_column_int(pStmt, 3); /* If the leaf in question has already been trimmed from the segment, ** ignore this b-tree entry. Otherwise, load it into memory. */ if( iIdxLeaf<pSeg->pgnoFirst ) continue; iRow = FTS5_SEGMENT_ROWID(pSeg->iSegid, iIdxLeaf); |
︙ | ︙ | |||
5860 5861 5862 5863 5864 5865 5866 | int iOff; /* Offset of first term on leaf */ int iRowidOff; /* Offset of first rowid on leaf */ int nTerm; /* Size of term on leaf in bytes */ int res; /* Comparison of term and split-key */ iOff = fts5LeafFirstTermOff(pLeaf); iRowidOff = fts5LeafFirstRowidOff(pLeaf); | | | | 6117 6118 6119 6120 6121 6122 6123 6124 6125 6126 6127 6128 6129 6130 6131 6132 6133 6134 6135 | int iOff; /* Offset of first term on leaf */ int iRowidOff; /* Offset of first rowid on leaf */ int nTerm; /* Size of term on leaf in bytes */ int res; /* Comparison of term and split-key */ iOff = fts5LeafFirstTermOff(pLeaf); iRowidOff = fts5LeafFirstRowidOff(pLeaf); if( iRowidOff>=iOff || iOff>=pLeaf->szLeaf ){ p->rc = FTS5_CORRUPT; }else{ iOff += fts5GetVarint32(&pLeaf->p[iOff], nTerm); res = fts5Memcmp(&pLeaf->p[iOff], zIdxTerm, MIN(nTerm, nIdxTerm)); if( res==0 ) res = nTerm - nIdxTerm; if( res<0 ) p->rc = FTS5_CORRUPT; } fts5IntegrityCheckPgidx(p, pLeaf); } fts5DataRelease(pLeaf); |
︙ | ︙ | |||
5956 5957 5958 5959 5960 5961 5962 | ** as calculated by sqlite3Fts5IndexEntryCksum() is cksum. ** ** Return SQLITE_CORRUPT if any of the internal checks fail, or if the ** checksum does not match. Return SQLITE_OK if all checks pass without ** error, or some other SQLite error code if another error (e.g. OOM) ** occurs. */ | | > > > > | > < < | | | | < | 6213 6214 6215 6216 6217 6218 6219 6220 6221 6222 6223 6224 6225 6226 6227 6228 6229 6230 6231 6232 6233 6234 6235 6236 6237 6238 6239 6240 6241 6242 6243 6244 6245 6246 6247 6248 6249 6250 6251 6252 6253 | ** as calculated by sqlite3Fts5IndexEntryCksum() is cksum. ** ** Return SQLITE_CORRUPT if any of the internal checks fail, or if the ** checksum does not match. Return SQLITE_OK if all checks pass without ** error, or some other SQLite error code if another error (e.g. OOM) ** occurs. */ int sqlite3Fts5IndexIntegrityCheck(Fts5Index *p, u64 cksum, int bUseCksum){ int eDetail = p->pConfig->eDetail; u64 cksum2 = 0; /* Checksum based on contents of indexes */ Fts5Buffer poslist = {0,0,0}; /* Buffer used to hold a poslist */ Fts5Iter *pIter; /* Used to iterate through entire index */ Fts5Structure *pStruct; /* Index structure */ int iLvl, iSeg; #ifdef SQLITE_DEBUG /* Used by extra internal tests only run if NDEBUG is not defined */ u64 cksum3 = 0; /* Checksum based on contents of indexes */ Fts5Buffer term = {0,0,0}; /* Buffer used to hold most recent term */ #endif const int flags = FTS5INDEX_QUERY_NOOUTPUT; /* Load the FTS index structure */ pStruct = fts5StructureRead(p); if( pStruct==0 ){ assert( p->rc!=SQLITE_OK ); return fts5IndexReturn(p); } /* Check that the internal nodes of each segment match the leaves */ for(iLvl=0; iLvl<pStruct->nLevel; iLvl++){ for(iSeg=0; iSeg<pStruct->aLevel[iLvl].nSeg; iSeg++){ Fts5StructureSegment *pSeg = &pStruct->aLevel[iLvl].aSeg[iSeg]; fts5IndexIntegrityCheckSegment(p, pSeg); } } /* The cksum argument passed to this function is a checksum calculated ** based on all expected entries in the FTS index (including prefix index ** entries). This block checks that a checksum calculated based on the ** actual contents of FTS index is identical. |
︙ | ︙ | |||
6017 6018 6019 6020 6021 6022 6023 6024 6025 6026 6027 6028 6029 6030 6031 6032 6033 | if( eDetail==FTS5_DETAIL_NONE ){ if( 0==fts5MultiIterIsEmpty(p, pIter) ){ cksum2 ^= sqlite3Fts5IndexEntryCksum(iRowid, 0, 0, -1, z, n); } }else{ poslist.n = 0; fts5SegiterPoslist(p, &pIter->aSeg[pIter->aFirst[1].iFirst], 0, &poslist); while( 0==sqlite3Fts5PoslistNext64(poslist.p, poslist.n, &iOff, &iPos) ){ int iCol = FTS5_POS2COLUMN(iPos); int iTokOff = FTS5_POS2OFFSET(iPos); cksum2 ^= sqlite3Fts5IndexEntryCksum(iRowid, iCol, iTokOff, -1, z, n); } } } fts5TestTerm(p, &term, 0, 0, cksum2, &cksum3); fts5MultiIterFree(pIter); | > | > | 6276 6277 6278 6279 6280 6281 6282 6283 6284 6285 6286 6287 6288 6289 6290 6291 6292 6293 6294 6295 6296 6297 6298 6299 6300 6301 6302 6303 6304 6305 6306 6307 6308 6309 6310 6311 6312 6313 6314 6315 6316 6317 | if( eDetail==FTS5_DETAIL_NONE ){ if( 0==fts5MultiIterIsEmpty(p, pIter) ){ cksum2 ^= sqlite3Fts5IndexEntryCksum(iRowid, 0, 0, -1, z, n); } }else{ poslist.n = 0; fts5SegiterPoslist(p, &pIter->aSeg[pIter->aFirst[1].iFirst], 0, &poslist); fts5BufferAppendBlob(&p->rc, &poslist, 4, (const u8*)"\0\0\0\0"); while( 0==sqlite3Fts5PoslistNext64(poslist.p, poslist.n, &iOff, &iPos) ){ int iCol = FTS5_POS2COLUMN(iPos); int iTokOff = FTS5_POS2OFFSET(iPos); cksum2 ^= sqlite3Fts5IndexEntryCksum(iRowid, iCol, iTokOff, -1, z, n); } } } fts5TestTerm(p, &term, 0, 0, cksum2, &cksum3); fts5MultiIterFree(pIter); if( p->rc==SQLITE_OK && bUseCksum && cksum!=cksum2 ) p->rc = FTS5_CORRUPT; fts5StructureRelease(pStruct); #ifdef SQLITE_DEBUG fts5BufferFree(&term); #endif fts5BufferFree(&poslist); return fts5IndexReturn(p); } /************************************************************************* ************************************************************************** ** Below this point is the implementation of the fts5_decode() scalar ** function only. */ #ifdef SQLITE_TEST /* ** Decode a segment-data rowid from the %_data table. This function is ** the opposite of macro FTS5_SEGMENT_ROWID(). */ static void fts5DecodeRowid( i64 iRowid, /* Rowid from %_data table */ int *piSegid, /* OUT: Segment id */ |
︙ | ︙ | |||
6065 6066 6067 6068 6069 6070 6071 6072 6073 6074 6075 6076 6077 6078 6079 6080 6081 6082 6083 6084 6085 6086 6087 6088 6089 6090 6091 6092 6093 6094 6095 6096 6097 | iRowid >>= FTS5_DATA_HEIGHT_B; *pbDlidx = (int)(iRowid & 0x0001); iRowid >>= FTS5_DATA_DLI_B; *piSegid = (int)(iRowid & (((i64)1 << FTS5_DATA_ID_B) - 1)); } static void fts5DebugRowid(int *pRc, Fts5Buffer *pBuf, i64 iKey){ int iSegid, iHeight, iPgno, bDlidx; /* Rowid compenents */ fts5DecodeRowid(iKey, &iSegid, &bDlidx, &iHeight, &iPgno); if( iSegid==0 ){ if( iKey==FTS5_AVERAGES_ROWID ){ sqlite3Fts5BufferAppendPrintf(pRc, pBuf, "{averages} "); }else{ sqlite3Fts5BufferAppendPrintf(pRc, pBuf, "{structure}"); } } else{ sqlite3Fts5BufferAppendPrintf(pRc, pBuf, "{%ssegid=%d h=%d pgno=%d}", bDlidx ? "dlidx " : "", iSegid, iHeight, iPgno ); } } static void fts5DebugStructure( int *pRc, /* IN/OUT: error code */ Fts5Buffer *pBuf, Fts5Structure *p ){ int iLvl, iSeg; /* Iterate through levels, segments */ | > > > > | 6326 6327 6328 6329 6330 6331 6332 6333 6334 6335 6336 6337 6338 6339 6340 6341 6342 6343 6344 6345 6346 6347 6348 6349 6350 6351 6352 6353 6354 6355 6356 6357 6358 6359 6360 6361 6362 | iRowid >>= FTS5_DATA_HEIGHT_B; *pbDlidx = (int)(iRowid & 0x0001); iRowid >>= FTS5_DATA_DLI_B; *piSegid = (int)(iRowid & (((i64)1 << FTS5_DATA_ID_B) - 1)); } #endif /* SQLITE_TEST */ #ifdef SQLITE_TEST static void fts5DebugRowid(int *pRc, Fts5Buffer *pBuf, i64 iKey){ int iSegid, iHeight, iPgno, bDlidx; /* Rowid compenents */ fts5DecodeRowid(iKey, &iSegid, &bDlidx, &iHeight, &iPgno); if( iSegid==0 ){ if( iKey==FTS5_AVERAGES_ROWID ){ sqlite3Fts5BufferAppendPrintf(pRc, pBuf, "{averages} "); }else{ sqlite3Fts5BufferAppendPrintf(pRc, pBuf, "{structure}"); } } else{ sqlite3Fts5BufferAppendPrintf(pRc, pBuf, "{%ssegid=%d h=%d pgno=%d}", bDlidx ? "dlidx " : "", iSegid, iHeight, iPgno ); } } #endif /* SQLITE_TEST */ #ifdef SQLITE_TEST static void fts5DebugStructure( int *pRc, /* IN/OUT: error code */ Fts5Buffer *pBuf, Fts5Structure *p ){ int iLvl, iSeg; /* Iterate through levels, segments */ |
︙ | ︙ | |||
6105 6106 6107 6108 6109 6110 6111 6112 6113 6114 6115 6116 6117 6118 6119 | sqlite3Fts5BufferAppendPrintf(pRc, pBuf, " {id=%d leaves=%d..%d}", pSeg->iSegid, pSeg->pgnoFirst, pSeg->pgnoLast ); } sqlite3Fts5BufferAppendPrintf(pRc, pBuf, "}"); } } /* ** This is part of the fts5_decode() debugging aid. ** ** Arguments pBlob/nBlob contain a serialized Fts5Structure object. This ** function appends a human-readable representation of the same object ** to the buffer passed as the second argument. */ | > > | 6370 6371 6372 6373 6374 6375 6376 6377 6378 6379 6380 6381 6382 6383 6384 6385 6386 | sqlite3Fts5BufferAppendPrintf(pRc, pBuf, " {id=%d leaves=%d..%d}", pSeg->iSegid, pSeg->pgnoFirst, pSeg->pgnoLast ); } sqlite3Fts5BufferAppendPrintf(pRc, pBuf, "}"); } } #endif /* SQLITE_TEST */ #ifdef SQLITE_TEST /* ** This is part of the fts5_decode() debugging aid. ** ** Arguments pBlob/nBlob contain a serialized Fts5Structure object. This ** function appends a human-readable representation of the same object ** to the buffer passed as the second argument. */ |
︙ | ︙ | |||
6130 6131 6132 6133 6134 6135 6136 6137 6138 6139 6140 6141 6142 6143 6144 | *pRc = rc; return; } fts5DebugStructure(pRc, pBuf, p); fts5StructureRelease(p); } /* ** This is part of the fts5_decode() debugging aid. ** ** Arguments pBlob/nBlob contain an "averages" record. This function ** appends a human-readable representation of record to the buffer passed ** as the second argument. */ | > > | 6397 6398 6399 6400 6401 6402 6403 6404 6405 6406 6407 6408 6409 6410 6411 6412 6413 | *pRc = rc; return; } fts5DebugStructure(pRc, pBuf, p); fts5StructureRelease(p); } #endif /* SQLITE_TEST */ #ifdef SQLITE_TEST /* ** This is part of the fts5_decode() debugging aid. ** ** Arguments pBlob/nBlob contain an "averages" record. This function ** appends a human-readable representation of record to the buffer passed ** as the second argument. */ |
︙ | ︙ | |||
6153 6154 6155 6156 6157 6158 6159 6160 6161 6162 6163 6164 6165 6166 6167 6168 6169 6170 6171 6172 6173 6174 6175 6176 6177 6178 6179 6180 6181 6182 6183 6184 | while( i<nBlob ){ u64 iVal; i += sqlite3Fts5GetVarint(&pBlob[i], &iVal); sqlite3Fts5BufferAppendPrintf(pRc, pBuf, "%s%d", zSpace, (int)iVal); zSpace = " "; } } /* ** Buffer (a/n) is assumed to contain a list of serialized varints. Read ** each varint and append its string representation to buffer pBuf. Return ** after either the input buffer is exhausted or a 0 value is read. ** ** The return value is the number of bytes read from the input buffer. */ static int fts5DecodePoslist(int *pRc, Fts5Buffer *pBuf, const u8 *a, int n){ int iOff = 0; while( iOff<n ){ int iVal; iOff += fts5GetVarint32(&a[iOff], iVal); sqlite3Fts5BufferAppendPrintf(pRc, pBuf, " %d", iVal); } return iOff; } /* ** The start of buffer (a/n) contains the start of a doclist. The doclist ** may or may not finish within the buffer. This function appends a text ** representation of the part of the doclist that is present to buffer ** pBuf. ** ** The return value is the number of bytes read from the input buffer. | > > > > | 6422 6423 6424 6425 6426 6427 6428 6429 6430 6431 6432 6433 6434 6435 6436 6437 6438 6439 6440 6441 6442 6443 6444 6445 6446 6447 6448 6449 6450 6451 6452 6453 6454 6455 6456 6457 | while( i<nBlob ){ u64 iVal; i += sqlite3Fts5GetVarint(&pBlob[i], &iVal); sqlite3Fts5BufferAppendPrintf(pRc, pBuf, "%s%d", zSpace, (int)iVal); zSpace = " "; } } #endif /* SQLITE_TEST */ #ifdef SQLITE_TEST /* ** Buffer (a/n) is assumed to contain a list of serialized varints. Read ** each varint and append its string representation to buffer pBuf. Return ** after either the input buffer is exhausted or a 0 value is read. ** ** The return value is the number of bytes read from the input buffer. */ static int fts5DecodePoslist(int *pRc, Fts5Buffer *pBuf, const u8 *a, int n){ int iOff = 0; while( iOff<n ){ int iVal; iOff += fts5GetVarint32(&a[iOff], iVal); sqlite3Fts5BufferAppendPrintf(pRc, pBuf, " %d", iVal); } return iOff; } #endif /* SQLITE_TEST */ #ifdef SQLITE_TEST /* ** The start of buffer (a/n) contains the start of a doclist. The doclist ** may or may not finish within the buffer. This function appends a text ** representation of the part of the doclist that is present to buffer ** pBuf. ** ** The return value is the number of bytes read from the input buffer. |
︙ | ︙ | |||
6203 6204 6205 6206 6207 6208 6209 6210 6211 6212 6213 6214 6215 6216 6217 | iDocid += iDelta; sqlite3Fts5BufferAppendPrintf(pRc, pBuf, " id=%lld", iDocid); } } return iOff; } /* ** This function is part of the fts5_decode() debugging function. It is ** only ever used with detail=none tables. ** ** Buffer (pData/nData) contains a doclist in the format used by detail=none ** tables. This function appends a human-readable version of that list to ** buffer pBuf. | > > | 6476 6477 6478 6479 6480 6481 6482 6483 6484 6485 6486 6487 6488 6489 6490 6491 6492 | iDocid += iDelta; sqlite3Fts5BufferAppendPrintf(pRc, pBuf, " id=%lld", iDocid); } } return iOff; } #endif /* SQLITE_TEST */ #ifdef SQLITE_TEST /* ** This function is part of the fts5_decode() debugging function. It is ** only ever used with detail=none tables. ** ** Buffer (pData/nData) contains a doclist in the format used by detail=none ** tables. This function appends a human-readable version of that list to ** buffer pBuf. |
︙ | ︙ | |||
6244 6245 6246 6247 6248 6249 6250 6251 6252 6253 6254 6255 6256 6257 6258 6259 6260 6261 6262 6263 6264 6265 | zApp = "*"; } } sqlite3Fts5BufferAppendPrintf(pRc, pBuf, " %lld%s", iRowid, zApp); } } /* ** The implementation of user-defined scalar function fts5_decode(). */ static void fts5DecodeFunction( sqlite3_context *pCtx, /* Function call context */ int nArg, /* Number of args (always 2) */ sqlite3_value **apVal /* Function arguments */ ){ i64 iRowid; /* Rowid for record being decoded */ int iSegid,iHeight,iPgno,bDlidx;/* Rowid components */ const u8 *aBlob; int n; /* Record to decode */ u8 *a = 0; Fts5Buffer s; /* Build up text to return here */ int rc = SQLITE_OK; /* Return code */ | > > | | < | 6519 6520 6521 6522 6523 6524 6525 6526 6527 6528 6529 6530 6531 6532 6533 6534 6535 6536 6537 6538 6539 6540 6541 6542 6543 6544 6545 6546 6547 6548 6549 6550 6551 6552 6553 6554 6555 6556 6557 6558 6559 6560 6561 6562 6563 6564 6565 6566 | zApp = "*"; } } sqlite3Fts5BufferAppendPrintf(pRc, pBuf, " %lld%s", iRowid, zApp); } } #endif /* SQLITE_TEST */ #ifdef SQLITE_TEST /* ** The implementation of user-defined scalar function fts5_decode(). */ static void fts5DecodeFunction( sqlite3_context *pCtx, /* Function call context */ int nArg, /* Number of args (always 2) */ sqlite3_value **apVal /* Function arguments */ ){ i64 iRowid; /* Rowid for record being decoded */ int iSegid,iHeight,iPgno,bDlidx;/* Rowid components */ const u8 *aBlob; int n; /* Record to decode */ u8 *a = 0; Fts5Buffer s; /* Build up text to return here */ int rc = SQLITE_OK; /* Return code */ sqlite3_int64 nSpace = 0; int eDetailNone = (sqlite3_user_data(pCtx)!=0); assert( nArg==2 ); UNUSED_PARAM(nArg); memset(&s, 0, sizeof(Fts5Buffer)); iRowid = sqlite3_value_int64(apVal[0]); /* Make a copy of the second argument (a blob) in aBlob[]. The aBlob[] ** copy is followed by FTS5_DATA_ZERO_PADDING 0x00 bytes, which prevents ** buffer overreads even if the record is corrupt. */ n = sqlite3_value_bytes(apVal[1]); aBlob = sqlite3_value_blob(apVal[1]); nSpace = n + FTS5_DATA_ZERO_PADDING; a = (u8*)sqlite3Fts5MallocZero(&rc, nSpace); if( a==0 ) goto decode_out; if( n>0 ) memcpy(a, aBlob, n); fts5DecodeRowid(iRowid, &iSegid, &bDlidx, &iHeight, &iPgno); fts5DebugRowid(&rc, &s, iRowid); if( bDlidx ){ Fts5Data dlidx; Fts5DlidxLvl lvl; |
︙ | ︙ | |||
6371 6372 6373 6374 6375 6376 6377 6378 6379 6380 6381 6382 6383 6384 6385 6386 6387 6388 6389 6390 6391 6392 6393 6394 6395 | sqlite3Fts5BufferSet(&rc, &s, 7, (const u8*)"corrupt"); goto decode_out; }else{ iRowidOff = fts5GetU16(&a[0]); iPgidxOff = szLeaf = fts5GetU16(&a[2]); if( iPgidxOff<n ){ fts5GetVarint32(&a[iPgidxOff], iTermOff); } } /* Decode the position list tail at the start of the page */ if( iRowidOff!=0 ){ iOff = iRowidOff; }else if( iTermOff!=0 ){ iOff = iTermOff; }else{ iOff = szLeaf; } fts5DecodePoslist(&rc, &s, &a[4], iOff-4); /* Decode any more doclist data that appears on the page before the ** first term. */ nDoclist = (iTermOff ? iTermOff : szLeaf) - iOff; fts5DecodeDoclist(&rc, &s, &a[iOff], nDoclist); | > > > > > > > > > > > | > > > > > > > > > > > > | 6647 6648 6649 6650 6651 6652 6653 6654 6655 6656 6657 6658 6659 6660 6661 6662 6663 6664 6665 6666 6667 6668 6669 6670 6671 6672 6673 6674 6675 6676 6677 6678 6679 6680 6681 6682 6683 6684 6685 6686 6687 6688 6689 6690 6691 6692 6693 6694 6695 6696 6697 6698 6699 6700 6701 6702 6703 6704 6705 6706 6707 6708 6709 6710 6711 6712 6713 6714 6715 6716 6717 6718 6719 6720 6721 6722 | sqlite3Fts5BufferSet(&rc, &s, 7, (const u8*)"corrupt"); goto decode_out; }else{ iRowidOff = fts5GetU16(&a[0]); iPgidxOff = szLeaf = fts5GetU16(&a[2]); if( iPgidxOff<n ){ fts5GetVarint32(&a[iPgidxOff], iTermOff); }else if( iPgidxOff>n ){ rc = FTS5_CORRUPT; goto decode_out; } } /* Decode the position list tail at the start of the page */ if( iRowidOff!=0 ){ iOff = iRowidOff; }else if( iTermOff!=0 ){ iOff = iTermOff; }else{ iOff = szLeaf; } if( iOff>n ){ rc = FTS5_CORRUPT; goto decode_out; } fts5DecodePoslist(&rc, &s, &a[4], iOff-4); /* Decode any more doclist data that appears on the page before the ** first term. */ nDoclist = (iTermOff ? iTermOff : szLeaf) - iOff; if( nDoclist+iOff>n ){ rc = FTS5_CORRUPT; goto decode_out; } fts5DecodeDoclist(&rc, &s, &a[iOff], nDoclist); while( iPgidxOff<n && rc==SQLITE_OK ){ int bFirst = (iPgidxOff==szLeaf); /* True for first term on page */ int nByte; /* Bytes of data */ int iEnd; iPgidxOff += fts5GetVarint32(&a[iPgidxOff], nByte); iPgidxPrev += nByte; iOff = iPgidxPrev; if( iPgidxOff<n ){ fts5GetVarint32(&a[iPgidxOff], nByte); iEnd = iPgidxPrev + nByte; }else{ iEnd = szLeaf; } if( iEnd>szLeaf ){ rc = FTS5_CORRUPT; break; } if( bFirst==0 ){ iOff += fts5GetVarint32(&a[iOff], nByte); if( nByte>term.n ){ rc = FTS5_CORRUPT; break; } term.n = nByte; } iOff += fts5GetVarint32(&a[iOff], nByte); if( iOff+nByte>n ){ rc = FTS5_CORRUPT; break; } fts5BufferAppendBlob(&rc, &term, nByte, &a[iOff]); iOff += nByte; sqlite3Fts5BufferAppendPrintf( &rc, &s, " term=%.*s", term.n, (const char*)term.p ); iOff += fts5DecodeDoclist(&rc, &s, &a[iOff], iEnd-iOff); |
︙ | ︙ | |||
6431 6432 6433 6434 6435 6436 6437 6438 6439 6440 6441 6442 6443 6444 6445 | if( rc==SQLITE_OK ){ sqlite3_result_text(pCtx, (const char*)s.p, s.n, SQLITE_TRANSIENT); }else{ sqlite3_result_error_code(pCtx, rc); } fts5BufferFree(&s); } /* ** The implementation of user-defined scalar function fts5_rowid(). */ static void fts5RowidFunction( sqlite3_context *pCtx, /* Function call context */ int nArg, /* Number of args (always 2) */ sqlite3_value **apVal /* Function arguments */ | > > | 6730 6731 6732 6733 6734 6735 6736 6737 6738 6739 6740 6741 6742 6743 6744 6745 6746 | if( rc==SQLITE_OK ){ sqlite3_result_text(pCtx, (const char*)s.p, s.n, SQLITE_TRANSIENT); }else{ sqlite3_result_error_code(pCtx, rc); } fts5BufferFree(&s); } #endif /* SQLITE_TEST */ #ifdef SQLITE_TEST /* ** The implementation of user-defined scalar function fts5_rowid(). */ static void fts5RowidFunction( sqlite3_context *pCtx, /* Function call context */ int nArg, /* Number of args (always 2) */ sqlite3_value **apVal /* Function arguments */ |
︙ | ︙ | |||
6465 6466 6467 6468 6469 6470 6471 6472 6473 6474 6475 6476 6477 6478 6479 6480 6481 6482 6483 6484 6485 6486 6487 6488 6489 6490 6491 6492 6493 6494 6495 6496 6497 6498 6499 6500 6501 6502 6503 6504 6505 6506 6507 6508 | }else{ sqlite3_result_error(pCtx, "first arg to fts5_rowid() must be 'segment'" , -1 ); } } } /* ** This is called as part of registering the FTS5 module with database ** connection db. It registers several user-defined scalar functions useful ** with FTS5. ** ** If successful, SQLITE_OK is returned. If an error occurs, some other ** SQLite error code is returned instead. */ int sqlite3Fts5IndexInit(sqlite3 *db){ int rc = sqlite3_create_function( db, "fts5_decode", 2, SQLITE_UTF8, 0, fts5DecodeFunction, 0, 0 ); if( rc==SQLITE_OK ){ rc = sqlite3_create_function( db, "fts5_decode_none", 2, SQLITE_UTF8, (void*)db, fts5DecodeFunction, 0, 0 ); } if( rc==SQLITE_OK ){ rc = sqlite3_create_function( db, "fts5_rowid", -1, SQLITE_UTF8, 0, fts5RowidFunction, 0, 0 ); } return rc; } int sqlite3Fts5IndexReset(Fts5Index *p){ assert( p->pStruct==0 || p->iStructVersion!=0 ); if( fts5IndexDataVersion(p)!=p->iStructVersion ){ fts5StructureInvalidate(p); } return fts5IndexReturn(p); } | > > > > > > | 6766 6767 6768 6769 6770 6771 6772 6773 6774 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 6808 6809 6810 6811 6812 6813 6814 6815 | }else{ sqlite3_result_error(pCtx, "first arg to fts5_rowid() must be 'segment'" , -1 ); } } } #endif /* SQLITE_TEST */ /* ** This is called as part of registering the FTS5 module with database ** connection db. It registers several user-defined scalar functions useful ** with FTS5. ** ** If successful, SQLITE_OK is returned. If an error occurs, some other ** SQLite error code is returned instead. */ int sqlite3Fts5IndexInit(sqlite3 *db){ #ifdef SQLITE_TEST int rc = sqlite3_create_function( db, "fts5_decode", 2, SQLITE_UTF8, 0, fts5DecodeFunction, 0, 0 ); if( rc==SQLITE_OK ){ rc = sqlite3_create_function( db, "fts5_decode_none", 2, SQLITE_UTF8, (void*)db, fts5DecodeFunction, 0, 0 ); } if( rc==SQLITE_OK ){ rc = sqlite3_create_function( db, "fts5_rowid", -1, SQLITE_UTF8, 0, fts5RowidFunction, 0, 0 ); } return rc; #else return SQLITE_OK; UNUSED_PARAM(db); #endif } int sqlite3Fts5IndexReset(Fts5Index *p){ assert( p->pStruct==0 || p->iStructVersion!=0 ); if( fts5IndexDataVersion(p)!=p->iStructVersion ){ fts5StructureInvalidate(p); } return fts5IndexReturn(p); } |
Changes to ext/fts5/fts5_main.c.
︙ | ︙ | |||
18 19 20 21 22 23 24 25 26 27 28 29 30 | /* ** This variable is set to false when running tests for which the on disk ** structures should not be corrupt. Otherwise, true. If it is false, extra ** assert() conditions in the fts5 code are activated - conditions that are ** only true if it is guaranteed that the fts5 database is not corrupt. */ int sqlite3_fts5_may_be_corrupt = 1; typedef struct Fts5Auxdata Fts5Auxdata; typedef struct Fts5Auxiliary Fts5Auxiliary; typedef struct Fts5Cursor Fts5Cursor; | > > | | | 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | /* ** This variable is set to false when running tests for which the on disk ** structures should not be corrupt. Otherwise, true. If it is false, extra ** assert() conditions in the fts5 code are activated - conditions that are ** only true if it is guaranteed that the fts5 database is not corrupt. */ #ifdef SQLITE_DEBUG int sqlite3_fts5_may_be_corrupt = 1; #endif typedef struct Fts5Auxdata Fts5Auxdata; typedef struct Fts5Auxiliary Fts5Auxiliary; typedef struct Fts5Cursor Fts5Cursor; typedef struct Fts5FullTable Fts5FullTable; typedef struct Fts5Sorter Fts5Sorter; typedef struct Fts5TokenizerModule Fts5TokenizerModule; /* ** NOTES ON TRANSACTIONS: ** ** SQLite invokes the following virtual table methods as transactions are ** opened and closed by the user: |
︙ | ︙ | |||
106 107 108 109 110 111 112 | char *zName; /* Name of tokenizer */ void *pUserData; /* User pointer passed to xCreate() */ fts5_tokenizer x; /* Tokenizer functions */ void (*xDestroy)(void*); /* Destructor function */ Fts5TokenizerModule *pNext; /* Next registered tokenizer module */ }; | < < < | < < | | 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 | char *zName; /* Name of tokenizer */ void *pUserData; /* User pointer passed to xCreate() */ fts5_tokenizer x; /* Tokenizer functions */ void (*xDestroy)(void*); /* Destructor function */ Fts5TokenizerModule *pNext; /* Next registered tokenizer module */ }; struct Fts5FullTable { Fts5Table p; /* Public class members from fts5Int.h */ Fts5Storage *pStorage; /* Document store */ Fts5Global *pGlobal; /* Global (connection wide) data */ Fts5Cursor *pSortCsr; /* Sort data from this cursor */ #ifdef SQLITE_DEBUG struct Fts5TransactionState ts; #endif }; |
︙ | ︙ | |||
250 251 252 253 254 255 256 | #define FTS5_BEGIN 1 #define FTS5_SYNC 2 #define FTS5_COMMIT 3 #define FTS5_ROLLBACK 4 #define FTS5_SAVEPOINT 5 #define FTS5_RELEASE 6 #define FTS5_ROLLBACKTO 7 | | | 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 | #define FTS5_BEGIN 1 #define FTS5_SYNC 2 #define FTS5_COMMIT 3 #define FTS5_ROLLBACK 4 #define FTS5_SAVEPOINT 5 #define FTS5_RELEASE 6 #define FTS5_ROLLBACKTO 7 static void fts5CheckTransactionState(Fts5FullTable *p, int op, int iSavepoint){ switch( op ){ case FTS5_BEGIN: assert( p->ts.eState==0 ); p->ts.eState = 1; p->ts.iSavepoint = -1; break; |
︙ | ︙ | |||
289 290 291 292 293 294 295 | assert( iSavepoint>=0 ); assert( iSavepoint<=p->ts.iSavepoint ); p->ts.iSavepoint = iSavepoint-1; break; case FTS5_ROLLBACKTO: assert( p->ts.eState==1 ); | | > > > | | | | | | | | | 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 | assert( iSavepoint>=0 ); assert( iSavepoint<=p->ts.iSavepoint ); p->ts.iSavepoint = iSavepoint-1; break; case FTS5_ROLLBACKTO: assert( p->ts.eState==1 ); assert( iSavepoint>=-1 ); /* The following assert() can fail if another vtab strikes an error ** within an xSavepoint() call then SQLite calls xRollbackTo() - without ** having called xSavepoint() on this vtab. */ /* assert( iSavepoint<=p->ts.iSavepoint ); */ p->ts.iSavepoint = iSavepoint; break; } } #else # define fts5CheckTransactionState(x,y,z) #endif /* ** Return true if pTab is a contentless table. */ static int fts5IsContentless(Fts5FullTable *pTab){ return pTab->p.pConfig->eContent==FTS5_CONTENT_NONE; } /* ** Delete a virtual table handle allocated by fts5InitVtab(). */ static void fts5FreeVtab(Fts5FullTable *pTab){ if( pTab ){ sqlite3Fts5IndexClose(pTab->p.pIndex); sqlite3Fts5StorageClose(pTab->pStorage); sqlite3Fts5ConfigFree(pTab->p.pConfig); sqlite3_free(pTab); } } /* ** The xDisconnect() virtual table method. */ static int fts5DisconnectMethod(sqlite3_vtab *pVtab){ fts5FreeVtab((Fts5FullTable*)pVtab); return SQLITE_OK; } /* ** The xDestroy() virtual table method. */ static int fts5DestroyMethod(sqlite3_vtab *pVtab){ Fts5Table *pTab = (Fts5Table*)pVtab; int rc = sqlite3Fts5DropAll(pTab->pConfig); if( rc==SQLITE_OK ){ fts5FreeVtab((Fts5FullTable*)pVtab); } return rc; } /* ** This function is the implementation of both the xConnect and xCreate ** methods of the FTS3 virtual table. |
︙ | ︙ | |||
362 363 364 365 366 367 368 | sqlite3_vtab **ppVTab, /* Write the resulting vtab structure here */ char **pzErr /* Write any error message here */ ){ Fts5Global *pGlobal = (Fts5Global*)pAux; const char **azConfig = (const char**)argv; int rc = SQLITE_OK; /* Return code */ Fts5Config *pConfig = 0; /* Results of parsing argc/argv */ | | | | | | | | | 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 | sqlite3_vtab **ppVTab, /* Write the resulting vtab structure here */ char **pzErr /* Write any error message here */ ){ Fts5Global *pGlobal = (Fts5Global*)pAux; const char **azConfig = (const char**)argv; int rc = SQLITE_OK; /* Return code */ Fts5Config *pConfig = 0; /* Results of parsing argc/argv */ Fts5FullTable *pTab = 0; /* New virtual table object */ /* Allocate the new vtab object and parse the configuration */ pTab = (Fts5FullTable*)sqlite3Fts5MallocZero(&rc, sizeof(Fts5FullTable)); if( rc==SQLITE_OK ){ rc = sqlite3Fts5ConfigParse(pGlobal, db, argc, azConfig, &pConfig, pzErr); assert( (rc==SQLITE_OK && *pzErr==0) || pConfig==0 ); } if( rc==SQLITE_OK ){ pTab->p.pConfig = pConfig; pTab->pGlobal = pGlobal; } /* Open the index sub-system */ if( rc==SQLITE_OK ){ rc = sqlite3Fts5IndexOpen(pConfig, bCreate, &pTab->p.pIndex, pzErr); } /* Open the storage sub-system */ if( rc==SQLITE_OK ){ rc = sqlite3Fts5StorageOpen( pConfig, pTab->p.pIndex, bCreate, &pTab->pStorage, pzErr ); } /* Call sqlite3_declare_vtab() */ if( rc==SQLITE_OK ){ rc = sqlite3Fts5ConfigDeclareVtab(pConfig); } /* Load the initial configuration */ if( rc==SQLITE_OK ){ assert( pConfig->pzErrmsg==0 ); pConfig->pzErrmsg = pzErr; rc = sqlite3Fts5IndexLoadConfig(pTab->p.pIndex); sqlite3Fts5IndexRollback(pTab->p.pIndex); pConfig->pzErrmsg = 0; } if( rc!=SQLITE_OK ){ fts5FreeVtab(pTab); pTab = 0; }else if( bCreate ){ |
︙ | ︙ | |||
461 462 463 464 465 466 467 468 469 470 471 472 | if( sqlite3_libversion_number()>=3008012 ) #endif { pIdxInfo->idxFlags |= SQLITE_INDEX_SCAN_UNIQUE; } #endif } /* ** Implementation of the xBestIndex method for FTS5 tables. Within the ** WHERE constraint, it searches for the following: ** | > > > > > > > > > > > > > > > > > | > | | | | > > > > > > > > > > > > > > > > > > > > > > > | 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 | if( sqlite3_libversion_number()>=3008012 ) #endif { pIdxInfo->idxFlags |= SQLITE_INDEX_SCAN_UNIQUE; } #endif } static int fts5UsePatternMatch( Fts5Config *pConfig, struct sqlite3_index_constraint *p ){ assert( FTS5_PATTERN_GLOB==SQLITE_INDEX_CONSTRAINT_GLOB ); assert( FTS5_PATTERN_LIKE==SQLITE_INDEX_CONSTRAINT_LIKE ); if( pConfig->ePattern==FTS5_PATTERN_GLOB && p->op==FTS5_PATTERN_GLOB ){ return 1; } if( pConfig->ePattern==FTS5_PATTERN_LIKE && (p->op==FTS5_PATTERN_LIKE || p->op==FTS5_PATTERN_GLOB) ){ return 1; } return 0; } /* ** Implementation of the xBestIndex method for FTS5 tables. Within the ** WHERE constraint, it searches for the following: ** ** 1. A MATCH constraint against the table column. ** 2. A MATCH constraint against the "rank" column. ** 3. A MATCH constraint against some other column. ** 4. An == constraint against the rowid column. ** 5. A < or <= constraint against the rowid column. ** 6. A > or >= constraint against the rowid column. ** ** Within the ORDER BY, the following are supported: ** ** 5. ORDER BY rank [ASC|DESC] ** 6. ORDER BY rowid [ASC|DESC] ** ** Information for the xFilter call is passed via both the idxNum and ** idxStr variables. Specifically, idxNum is a bitmask of the following ** flags used to encode the ORDER BY clause: ** ** FTS5_BI_ORDER_RANK ** FTS5_BI_ORDER_ROWID ** FTS5_BI_ORDER_DESC ** ** idxStr is used to encode data from the WHERE clause. For each argument ** passed to the xFilter method, the following is appended to idxStr: ** ** Match against table column: "m" ** Match against rank column: "r" ** Match against other column: "M<column-number>" ** LIKE against other column: "L<column-number>" ** GLOB against other column: "G<column-number>" ** Equality constraint against the rowid: "=" ** A < or <= against the rowid: "<" ** A > or >= against the rowid: ">" ** ** This function ensures that there is at most one "r" or "=". And that if ** there exists an "=" then there is no "<" or ">". ** ** Costs are assigned as follows: ** ** a) If an unusable MATCH operator is present in the WHERE clause, the ** cost is unconditionally set to 1e50 (a really big number). ** ** a) If a MATCH operator is present, the cost depends on the other |
︙ | ︙ | |||
504 505 506 507 508 509 510 | ** Costs are not modified by the ORDER BY clause. */ static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){ Fts5Table *pTab = (Fts5Table*)pVTab; Fts5Config *pConfig = pTab->pConfig; const int nCol = pConfig->nCol; int idxFlags = 0; /* Parameter passed through to xFilter() */ | < < | < < | < | < < < < < < < < < < < | | | > > | > > > > > > | > > > > > < | | | < < < > > > > > > > > > > > > > | > > > | > > > > > > > > > > > > > > | > | | | > > > > > | > > > | > > > | < | | | | | | | | < < < < < < < < < < | | | | | | | 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 | ** Costs are not modified by the ORDER BY clause. */ static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){ Fts5Table *pTab = (Fts5Table*)pVTab; Fts5Config *pConfig = pTab->pConfig; const int nCol = pConfig->nCol; int idxFlags = 0; /* Parameter passed through to xFilter() */ int i; char *idxStr; int iIdxStr = 0; int iCons = 0; int bSeenEq = 0; int bSeenGt = 0; int bSeenLt = 0; int bSeenMatch = 0; int bSeenRank = 0; assert( SQLITE_INDEX_CONSTRAINT_EQ<SQLITE_INDEX_CONSTRAINT_MATCH ); assert( SQLITE_INDEX_CONSTRAINT_GT<SQLITE_INDEX_CONSTRAINT_MATCH ); assert( SQLITE_INDEX_CONSTRAINT_LE<SQLITE_INDEX_CONSTRAINT_MATCH ); assert( SQLITE_INDEX_CONSTRAINT_GE<SQLITE_INDEX_CONSTRAINT_MATCH ); assert( SQLITE_INDEX_CONSTRAINT_LE<SQLITE_INDEX_CONSTRAINT_MATCH ); if( pConfig->bLock ){ pTab->base.zErrMsg = sqlite3_mprintf( "recursively defined fts5 content table" ); return SQLITE_ERROR; } idxStr = (char*)sqlite3_malloc(pInfo->nConstraint * 8 + 1); if( idxStr==0 ) return SQLITE_NOMEM; pInfo->idxStr = idxStr; pInfo->needToFreeIdxStr = 1; for(i=0; i<pInfo->nConstraint; i++){ struct sqlite3_index_constraint *p = &pInfo->aConstraint[i]; int iCol = p->iColumn; if( p->op==SQLITE_INDEX_CONSTRAINT_MATCH || (p->op==SQLITE_INDEX_CONSTRAINT_EQ && iCol>=nCol) ){ /* A MATCH operator or equivalent */ if( p->usable==0 || iCol<0 ){ /* As there exists an unusable MATCH constraint this is an ** unusable plan. Set a prohibitively high cost. */ pInfo->estimatedCost = 1e50; assert( iIdxStr < pInfo->nConstraint*6 + 1 ); idxStr[iIdxStr] = 0; return SQLITE_OK; }else{ if( iCol==nCol+1 ){ if( bSeenRank ) continue; idxStr[iIdxStr++] = 'r'; bSeenRank = 1; }else if( iCol>=0 ){ bSeenMatch = 1; idxStr[iIdxStr++] = 'M'; sqlite3_snprintf(6, &idxStr[iIdxStr], "%d", iCol); idxStr += strlen(&idxStr[iIdxStr]); assert( idxStr[iIdxStr]=='\0' ); } pInfo->aConstraintUsage[i].argvIndex = ++iCons; pInfo->aConstraintUsage[i].omit = 1; } }else if( p->usable ){ if( iCol>=0 && iCol<nCol && fts5UsePatternMatch(pConfig, p) ){ assert( p->op==FTS5_PATTERN_LIKE || p->op==FTS5_PATTERN_GLOB ); idxStr[iIdxStr++] = p->op==FTS5_PATTERN_LIKE ? 'L' : 'G'; sqlite3_snprintf(6, &idxStr[iIdxStr], "%d", iCol); idxStr += strlen(&idxStr[iIdxStr]); pInfo->aConstraintUsage[i].argvIndex = ++iCons; assert( idxStr[iIdxStr]=='\0' ); }else if( bSeenEq==0 && p->op==SQLITE_INDEX_CONSTRAINT_EQ && iCol<0 ){ idxStr[iIdxStr++] = '='; bSeenEq = 1; pInfo->aConstraintUsage[i].argvIndex = ++iCons; } } } if( bSeenEq==0 ){ for(i=0; i<pInfo->nConstraint; i++){ struct sqlite3_index_constraint *p = &pInfo->aConstraint[i]; if( p->iColumn<0 && p->usable ){ int op = p->op; if( op==SQLITE_INDEX_CONSTRAINT_LT || op==SQLITE_INDEX_CONSTRAINT_LE ){ if( bSeenLt ) continue; idxStr[iIdxStr++] = '<'; pInfo->aConstraintUsage[i].argvIndex = ++iCons; bSeenLt = 1; }else if( op==SQLITE_INDEX_CONSTRAINT_GT || op==SQLITE_INDEX_CONSTRAINT_GE ){ if( bSeenGt ) continue; idxStr[iIdxStr++] = '>'; pInfo->aConstraintUsage[i].argvIndex = ++iCons; bSeenGt = 1; } } } } idxStr[iIdxStr] = '\0'; /* Set idxFlags flags for the ORDER BY clause */ if( pInfo->nOrderBy==1 ){ int iSort = pInfo->aOrderBy[0].iColumn; if( iSort==(pConfig->nCol+1) && bSeenMatch ){ idxFlags |= FTS5_BI_ORDER_RANK; }else if( iSort==-1 ){ idxFlags |= FTS5_BI_ORDER_ROWID; } if( BitFlagTest(idxFlags, FTS5_BI_ORDER_RANK|FTS5_BI_ORDER_ROWID) ){ pInfo->orderByConsumed = 1; if( pInfo->aOrderBy[0].desc ){ idxFlags |= FTS5_BI_ORDER_DESC; } } } /* Calculate the estimated cost based on the flags set in idxFlags. */ if( bSeenEq ){ pInfo->estimatedCost = bSeenMatch ? 100.0 : 10.0; if( bSeenMatch==0 ) fts5SetUniqueFlag(pInfo); }else if( bSeenLt && bSeenGt ){ pInfo->estimatedCost = bSeenMatch ? 500.0 : 250000.0; }else if( bSeenLt || bSeenGt ){ pInfo->estimatedCost = bSeenMatch ? 750.0 : 750000.0; }else{ pInfo->estimatedCost = bSeenMatch ? 1000.0 : 1000000.0; } pInfo->idxNum = idxFlags; return SQLITE_OK; } static int fts5NewTransaction(Fts5FullTable *pTab){ Fts5Cursor *pCsr; for(pCsr=pTab->pGlobal->pCsr; pCsr; pCsr=pCsr->pNext){ if( pCsr->base.pVtab==(sqlite3_vtab*)pTab ) return SQLITE_OK; } return sqlite3Fts5StorageReset(pTab->pStorage); } /* ** Implementation of xOpen method. */ static int fts5OpenMethod(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCsr){ Fts5FullTable *pTab = (Fts5FullTable*)pVTab; Fts5Config *pConfig = pTab->p.pConfig; Fts5Cursor *pCsr = 0; /* New cursor object */ sqlite3_int64 nByte; /* Bytes of space to allocate */ int rc; /* Return code */ rc = fts5NewTransaction(pTab); if( rc==SQLITE_OK ){ nByte = sizeof(Fts5Cursor) + pConfig->nCol * sizeof(int); pCsr = (Fts5Cursor*)sqlite3_malloc64(nByte); if( pCsr ){ Fts5Global *pGlobal = pTab->pGlobal; memset(pCsr, 0, (size_t)nByte); pCsr->aColumnSize = (int*)&pCsr[1]; pCsr->pNext = pGlobal->pCsr; pGlobal->pCsr = pCsr; pCsr->iCsrId = ++pGlobal->iNextId; }else{ rc = SQLITE_NOMEM; } |
︙ | ︙ | |||
669 670 671 672 673 674 675 | | FTS5CSR_REQUIRE_DOCSIZE | FTS5CSR_REQUIRE_INST | FTS5CSR_REQUIRE_POSLIST ); } static void fts5FreeCursorComponents(Fts5Cursor *pCsr){ | | | 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 | | FTS5CSR_REQUIRE_DOCSIZE | FTS5CSR_REQUIRE_INST | FTS5CSR_REQUIRE_POSLIST ); } static void fts5FreeCursorComponents(Fts5Cursor *pCsr){ Fts5FullTable *pTab = (Fts5FullTable*)(pCsr->base.pVtab); Fts5Auxdata *pData; Fts5Auxdata *pNext; sqlite3_free(pCsr->aInstIter); sqlite3_free(pCsr->aInst); if( pCsr->pStmt ){ int eStmt = fts5StmtType(pCsr); |
︙ | ︙ | |||
703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 | sqlite3_free(pCsr->apRankArg); if( CsrFlagTest(pCsr, FTS5CSR_FREE_ZRANK) ){ sqlite3_free(pCsr->zRank); sqlite3_free(pCsr->zRankArgs); } memset(&pCsr->ePlan, 0, sizeof(Fts5Cursor) - ((u8*)&pCsr->ePlan - (u8*)pCsr)); } /* ** Close the cursor. For additional information see the documentation ** on the xClose method of the virtual table interface. */ static int fts5CloseMethod(sqlite3_vtab_cursor *pCursor){ if( pCursor ){ | > | | 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 | sqlite3_free(pCsr->apRankArg); if( CsrFlagTest(pCsr, FTS5CSR_FREE_ZRANK) ){ sqlite3_free(pCsr->zRank); sqlite3_free(pCsr->zRankArgs); } sqlite3Fts5IndexCloseReader(pTab->p.pIndex); memset(&pCsr->ePlan, 0, sizeof(Fts5Cursor) - ((u8*)&pCsr->ePlan - (u8*)pCsr)); } /* ** Close the cursor. For additional information see the documentation ** on the xClose method of the virtual table interface. */ static int fts5CloseMethod(sqlite3_vtab_cursor *pCursor){ if( pCursor ){ Fts5FullTable *pTab = (Fts5FullTable*)(pCursor->pVtab); Fts5Cursor *pCsr = (Fts5Cursor*)pCursor; Fts5Cursor **pp; fts5FreeCursorComponents(pCsr); /* Remove the cursor from the Fts5Global.pCsr list */ for(pp=&pTab->pGlobal->pCsr; (*pp)!=pCsr; pp=&(*pp)->pNext); *pp = pCsr->pNext; |
︙ | ︙ | |||
770 771 772 773 774 775 776 | } /* ** Set the FTS5CSR_REQUIRE_RESEEK flag on all FTS5_PLAN_MATCH cursors ** open on table pTab. */ | | | 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 | } /* ** Set the FTS5CSR_REQUIRE_RESEEK flag on all FTS5_PLAN_MATCH cursors ** open on table pTab. */ static void fts5TripCursors(Fts5FullTable *pTab){ Fts5Cursor *pCsr; for(pCsr=pTab->pGlobal->pCsr; pCsr; pCsr=pCsr->pNext){ if( pCsr->ePlan==FTS5_PLAN_MATCH && pCsr->base.pVtab==(sqlite3_vtab*)pTab ){ CsrFlagSet(pCsr, FTS5CSR_REQUIRE_RESEEK); } |
︙ | ︙ | |||
797 798 799 800 801 802 803 | ** Return SQLITE_OK if successful or if no reseek was required, or an ** error code if an error occurred. */ static int fts5CursorReseek(Fts5Cursor *pCsr, int *pbSkip){ int rc = SQLITE_OK; assert( *pbSkip==0 ); if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_RESEEK) ){ | | | | 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 | ** Return SQLITE_OK if successful or if no reseek was required, or an ** error code if an error occurred. */ static int fts5CursorReseek(Fts5Cursor *pCsr, int *pbSkip){ int rc = SQLITE_OK; assert( *pbSkip==0 ); if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_RESEEK) ){ Fts5FullTable *pTab = (Fts5FullTable*)(pCsr->base.pVtab); int bDesc = pCsr->bDesc; i64 iRowid = sqlite3Fts5ExprRowid(pCsr->pExpr); rc = sqlite3Fts5ExprFirst(pCsr->pExpr, pTab->p.pIndex, iRowid, bDesc); if( rc==SQLITE_OK && iRowid!=sqlite3Fts5ExprRowid(pCsr->pExpr) ){ *pbSkip = 1; } CsrFlagClear(pCsr, FTS5CSR_REQUIRE_RESEEK); fts5CsrNewrow(pCsr); if( sqlite3Fts5ExprEof(pCsr->pExpr) ){ |
︙ | ︙ | |||
853 854 855 856 857 858 859 | } case FTS5_PLAN_SORTED_MATCH: { rc = fts5SorterNext(pCsr); break; } | | > > > > > > > > > | 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 | } case FTS5_PLAN_SORTED_MATCH: { rc = fts5SorterNext(pCsr); break; } default: { Fts5Config *pConfig = ((Fts5Table*)pCursor->pVtab)->pConfig; pConfig->bLock++; rc = sqlite3_step(pCsr->pStmt); pConfig->bLock--; if( rc!=SQLITE_ROW ){ CsrFlagSet(pCsr, FTS5CSR_EOF); rc = sqlite3_reset(pCsr->pStmt); if( rc!=SQLITE_OK ){ pCursor->pVtab->zErrMsg = sqlite3_mprintf( "%s", sqlite3_errmsg(pConfig->db) ); } }else{ rc = SQLITE_OK; } break; } } } return rc; } |
︙ | ︙ | |||
898 899 900 901 902 903 904 | } va_end(ap); *ppStmt = pRet; return rc; } | | > > > > | | | | | | 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 | } va_end(ap); *ppStmt = pRet; return rc; } static int fts5CursorFirstSorted( Fts5FullTable *pTab, Fts5Cursor *pCsr, int bDesc ){ Fts5Config *pConfig = pTab->p.pConfig; Fts5Sorter *pSorter; int nPhrase; sqlite3_int64 nByte; int rc; const char *zRank = pCsr->zRank; const char *zRankArgs = pCsr->zRankArgs; nPhrase = sqlite3Fts5ExprPhraseCount(pCsr->pExpr); nByte = sizeof(Fts5Sorter) + sizeof(int) * (nPhrase-1); pSorter = (Fts5Sorter*)sqlite3_malloc64(nByte); if( pSorter==0 ) return SQLITE_NOMEM; memset(pSorter, 0, (size_t)nByte); pSorter->nIdx = nPhrase; /* TODO: It would be better to have some system for reusing statement ** handles here, rather than preparing a new one for each query. But that ** is not possible as SQLite reference counts the virtual table objects. ** And since the statement required here reads from this very virtual ** table, saving it creates a circular reference. ** ** If SQLite a built-in statement cache, this wouldn't be a problem. */ rc = fts5PrepareStatement(&pSorter->pStmt, pConfig, "SELECT rowid, rank FROM %Q.%Q ORDER BY %s(\"%w\"%s%s) %s", pConfig->zDb, pConfig->zName, zRank, pConfig->zName, (zRankArgs ? ", " : ""), (zRankArgs ? zRankArgs : ""), bDesc ? "DESC" : "ASC" ); pCsr->pSorter = pSorter; |
︙ | ︙ | |||
946 947 948 949 950 951 952 | sqlite3_free(pSorter); pCsr->pSorter = 0; } return rc; } | | | | | | | | | | | | | | 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 | sqlite3_free(pSorter); pCsr->pSorter = 0; } return rc; } static int fts5CursorFirst(Fts5FullTable *pTab, Fts5Cursor *pCsr, int bDesc){ int rc; Fts5Expr *pExpr = pCsr->pExpr; rc = sqlite3Fts5ExprFirst(pExpr, pTab->p.pIndex, pCsr->iFirstRowid, bDesc); if( sqlite3Fts5ExprEof(pExpr) ){ CsrFlagSet(pCsr, FTS5CSR_EOF); } fts5CsrNewrow(pCsr); return rc; } /* ** Process a "special" query. A special query is identified as one with a ** MATCH expression that begins with a '*' character. The remainder of ** the text passed to the MATCH operator are used as the special query ** parameters. */ static int fts5SpecialMatch( Fts5FullTable *pTab, Fts5Cursor *pCsr, const char *zQuery ){ int rc = SQLITE_OK; /* Return code */ const char *z = zQuery; /* Special query text */ int n; /* Number of bytes in text at z */ while( z[0]==' ' ) z++; for(n=0; z[n] && z[n]!=' '; n++); assert( pTab->p.base.zErrMsg==0 ); pCsr->ePlan = FTS5_PLAN_SPECIAL; if( n==5 && 0==sqlite3_strnicmp("reads", z, n) ){ pCsr->iSpecial = sqlite3Fts5IndexReads(pTab->p.pIndex); } else if( n==2 && 0==sqlite3_strnicmp("id", z, n) ){ pCsr->iSpecial = pCsr->iCsrId; } else{ /* An unrecognized directive. Return an error message. */ pTab->p.base.zErrMsg = sqlite3_mprintf("unknown special query: %.*s", n, z); rc = SQLITE_ERROR; } return rc; } /* ** Search for an auxiliary function named zName that can be used with table ** pTab. If one is found, return a pointer to the corresponding Fts5Auxiliary ** structure. Otherwise, if no such function exists, return NULL. */ static Fts5Auxiliary *fts5FindAuxiliary(Fts5FullTable *pTab, const char *zName){ Fts5Auxiliary *pAux; for(pAux=pTab->pGlobal->pAux; pAux; pAux=pAux->pNext){ if( sqlite3_stricmp(zName, pAux->zFunc)==0 ) return pAux; } /* No function of the specified name was found. Return 0. */ return 0; } static int fts5FindRankFunction(Fts5Cursor *pCsr){ Fts5FullTable *pTab = (Fts5FullTable*)(pCsr->base.pVtab); Fts5Config *pConfig = pTab->p.pConfig; int rc = SQLITE_OK; Fts5Auxiliary *pAux = 0; const char *zRank = pCsr->zRank; const char *zRankArgs = pCsr->zRankArgs; if( zRankArgs ){ char *zSql = sqlite3Fts5Mprintf(&rc, "SELECT %s", zRankArgs); if( zSql ){ sqlite3_stmt *pStmt = 0; rc = sqlite3_prepare_v3(pConfig->db, zSql, -1, SQLITE_PREPARE_PERSISTENT, &pStmt, 0); sqlite3_free(zSql); assert( rc==SQLITE_OK || pCsr->pRankArgStmt==0 ); if( rc==SQLITE_OK ){ if( SQLITE_ROW==sqlite3_step(pStmt) ){ sqlite3_int64 nByte; pCsr->nRankArg = sqlite3_column_count(pStmt); nByte = sizeof(sqlite3_value*)*pCsr->nRankArg; pCsr->apRankArg = (sqlite3_value**)sqlite3Fts5MallocZero(&rc, nByte); if( rc==SQLITE_OK ){ int i; for(i=0; i<pCsr->nRankArg; i++){ pCsr->apRankArg[i] = sqlite3_column_value(pStmt, i); |
︙ | ︙ | |||
1050 1051 1052 1053 1054 1055 1056 | } } } if( rc==SQLITE_OK ){ pAux = fts5FindAuxiliary(pTab, zRank); if( pAux==0 ){ | | | | 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 | } } } if( rc==SQLITE_OK ){ pAux = fts5FindAuxiliary(pTab, zRank); if( pAux==0 ){ assert( pTab->p.base.zErrMsg==0 ); pTab->p.base.zErrMsg = sqlite3_mprintf("no such function: %s", zRank); rc = SQLITE_ERROR; } } pCsr->pRank = pAux; return rc; } |
︙ | ︙ | |||
1122 1123 1124 1125 1126 1127 1128 | ** 1. Full-text search using a MATCH operator. ** 2. A by-rowid lookup. ** 3. A full-table scan. */ static int fts5FilterMethod( sqlite3_vtab_cursor *pCursor, /* The cursor used for this query */ int idxNum, /* Strategy index */ | | | | < < > > > < > > > | > > > | | | < | | | < | > | > > > > > > > | > > > > > > > > > > > > > > > | > > > > > > | > | > > > > > > > > > > > > > > > > > > | > > > > | 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 | ** 1. Full-text search using a MATCH operator. ** 2. A by-rowid lookup. ** 3. A full-table scan. */ static int fts5FilterMethod( 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 */ ){ Fts5FullTable *pTab = (Fts5FullTable*)(pCursor->pVtab); Fts5Config *pConfig = pTab->p.pConfig; Fts5Cursor *pCsr = (Fts5Cursor*)pCursor; int rc = SQLITE_OK; /* Error code */ int bDesc; /* True if ORDER BY [rank|rowid] DESC */ int bOrderByRank; /* True if ORDER BY rank */ sqlite3_value *pRank = 0; /* rank MATCH ? expression (or NULL) */ sqlite3_value *pRowidEq = 0; /* rowid = ? expression (or NULL) */ sqlite3_value *pRowidLe = 0; /* rowid <= ? expression (or NULL) */ sqlite3_value *pRowidGe = 0; /* rowid >= ? expression (or NULL) */ int iCol; /* Column on LHS of MATCH operator */ char **pzErrmsg = pConfig->pzErrmsg; int i; int iIdxStr = 0; Fts5Expr *pExpr = 0; if( pConfig->bLock ){ pTab->p.base.zErrMsg = sqlite3_mprintf( "recursively defined fts5 content table" ); return SQLITE_ERROR; } if( pCsr->ePlan ){ fts5FreeCursorComponents(pCsr); memset(&pCsr->ePlan, 0, sizeof(Fts5Cursor) - ((u8*)&pCsr->ePlan-(u8*)pCsr)); } assert( pCsr->pStmt==0 ); assert( pCsr->pExpr==0 ); assert( pCsr->csrflags==0 ); assert( pCsr->pRank==0 ); assert( pCsr->zRank==0 ); assert( pCsr->zRankArgs==0 ); assert( pTab->pSortCsr==0 || nVal==0 ); assert( pzErrmsg==0 || pzErrmsg==&pTab->p.base.zErrMsg ); pConfig->pzErrmsg = &pTab->p.base.zErrMsg; /* Decode the arguments passed through to this function. */ for(i=0; i<nVal; i++){ switch( idxStr[iIdxStr++] ){ case 'r': pRank = apVal[i]; break; case 'M': { const char *zText = (const char*)sqlite3_value_text(apVal[i]); if( zText==0 ) zText = ""; iCol = 0; do{ iCol = iCol*10 + (idxStr[iIdxStr]-'0'); iIdxStr++; }while( idxStr[iIdxStr]>='0' && idxStr[iIdxStr]<='9' ); if( zText[0]=='*' ){ /* The user has issued a query of the form "MATCH '*...'". This ** indicates that the MATCH expression is not a full text query, ** but a request for an internal parameter. */ rc = fts5SpecialMatch(pTab, pCsr, &zText[1]); goto filter_out; }else{ char **pzErr = &pTab->p.base.zErrMsg; rc = sqlite3Fts5ExprNew(pConfig, 0, iCol, zText, &pExpr, pzErr); if( rc==SQLITE_OK ){ rc = sqlite3Fts5ExprAnd(&pCsr->pExpr, pExpr); pExpr = 0; } if( rc!=SQLITE_OK ) goto filter_out; } break; } case 'L': case 'G': { int bGlob = (idxStr[iIdxStr-1]=='G'); const char *zText = (const char*)sqlite3_value_text(apVal[i]); iCol = 0; do{ iCol = iCol*10 + (idxStr[iIdxStr]-'0'); iIdxStr++; }while( idxStr[iIdxStr]>='0' && idxStr[iIdxStr]<='9' ); if( zText ){ rc = sqlite3Fts5ExprPattern(pConfig, bGlob, iCol, zText, &pExpr); } if( rc==SQLITE_OK ){ rc = sqlite3Fts5ExprAnd(&pCsr->pExpr, pExpr); pExpr = 0; } if( rc!=SQLITE_OK ) goto filter_out; break; } case '=': pRowidEq = apVal[i]; break; case '<': pRowidLe = apVal[i]; break; default: assert( idxStr[iIdxStr-1]=='>' ); pRowidGe = apVal[i]; break; } } bOrderByRank = ((idxNum & FTS5_BI_ORDER_RANK) ? 1 : 0); pCsr->bDesc = bDesc = ((idxNum & FTS5_BI_ORDER_DESC) ? 1 : 0); /* Set the cursor upper and lower rowid limits. Only some strategies ** actually use them. This is ok, as the xBestIndex() method leaves the ** sqlite3_index_constraint.omit flag clear for range constraints ** on the rowid field. */ |
︙ | ︙ | |||
1198 1199 1200 1201 1202 1203 1204 | /* If pSortCsr is non-NULL, then this call is being made as part of ** processing for a "... MATCH <expr> ORDER BY rank" query (ePlan is ** set to FTS5_PLAN_SORTED_MATCH). pSortCsr is the cursor that will ** return results to the user for this query. The current cursor ** (pCursor) is used to execute the query issued by function ** fts5CursorFirstSorted() above. */ assert( pRowidEq==0 && pRowidLe==0 && pRowidGe==0 && pRank==0 ); | | | < < < < < < < < < < < < | | | | | | < < | > | | > > | 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 | /* If pSortCsr is non-NULL, then this call is being made as part of ** processing for a "... MATCH <expr> ORDER BY rank" query (ePlan is ** set to FTS5_PLAN_SORTED_MATCH). pSortCsr is the cursor that will ** return results to the user for this query. The current cursor ** (pCursor) is used to execute the query issued by function ** fts5CursorFirstSorted() above. */ assert( pRowidEq==0 && pRowidLe==0 && pRowidGe==0 && pRank==0 ); assert( nVal==0 && bOrderByRank==0 && bDesc==0 ); assert( pCsr->iLastRowid==LARGEST_INT64 ); assert( pCsr->iFirstRowid==SMALLEST_INT64 ); if( pTab->pSortCsr->bDesc ){ pCsr->iLastRowid = pTab->pSortCsr->iFirstRowid; pCsr->iFirstRowid = pTab->pSortCsr->iLastRowid; }else{ pCsr->iLastRowid = pTab->pSortCsr->iLastRowid; pCsr->iFirstRowid = pTab->pSortCsr->iFirstRowid; } pCsr->ePlan = FTS5_PLAN_SOURCE; pCsr->pExpr = pTab->pSortCsr->pExpr; rc = fts5CursorFirst(pTab, pCsr, bDesc); }else if( pCsr->pExpr ){ rc = fts5CursorParseRank(pConfig, pCsr, pRank); if( rc==SQLITE_OK ){ if( bOrderByRank ){ pCsr->ePlan = FTS5_PLAN_SORTED_MATCH; rc = fts5CursorFirstSorted(pTab, pCsr, bDesc); }else{ pCsr->ePlan = FTS5_PLAN_MATCH; rc = fts5CursorFirst(pTab, pCsr, bDesc); } } }else if( pConfig->zContent==0 ){ *pConfig->pzErrmsg = sqlite3_mprintf( "%s: table does not support scanning", pConfig->zName ); rc = SQLITE_ERROR; }else{ /* This is either a full-table scan (ePlan==FTS5_PLAN_SCAN) or a lookup ** by rowid (ePlan==FTS5_PLAN_ROWID). */ pCsr->ePlan = (pRowidEq ? FTS5_PLAN_ROWID : FTS5_PLAN_SCAN); rc = sqlite3Fts5StorageStmt( pTab->pStorage, fts5StmtType(pCsr), &pCsr->pStmt, &pTab->p.base.zErrMsg ); if( rc==SQLITE_OK ){ if( pRowidEq!=0 ){ assert( pCsr->ePlan==FTS5_PLAN_ROWID ); sqlite3_bind_value(pCsr->pStmt, 1, pRowidEq); }else{ sqlite3_bind_int64(pCsr->pStmt, 1, pCsr->iFirstRowid); sqlite3_bind_int64(pCsr->pStmt, 2, pCsr->iLastRowid); } rc = fts5NextMethod(pCursor); } } filter_out: sqlite3Fts5ExprFree(pExpr); pConfig->pzErrmsg = pzErrmsg; return rc; } /* ** This is the xEof method of the virtual table. SQLite calls this ** routine to find out if it has reached the end of a result set. |
︙ | ︙ | |||
1329 1330 1331 1332 1333 1334 1335 | ** be left in sqlite3_vtab.zErrMsg. */ static int fts5SeekCursor(Fts5Cursor *pCsr, int bErrormsg){ int rc = SQLITE_OK; /* If the cursor does not yet have a statement handle, obtain one now. */ if( pCsr->pStmt==0 ){ | | | | > > > > > > > | | | | | | 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 | ** be left in sqlite3_vtab.zErrMsg. */ static int fts5SeekCursor(Fts5Cursor *pCsr, int bErrormsg){ int rc = SQLITE_OK; /* If the cursor does not yet have a statement handle, obtain one now. */ if( pCsr->pStmt==0 ){ Fts5FullTable *pTab = (Fts5FullTable*)(pCsr->base.pVtab); int eStmt = fts5StmtType(pCsr); rc = sqlite3Fts5StorageStmt( pTab->pStorage, eStmt, &pCsr->pStmt, (bErrormsg?&pTab->p.base.zErrMsg:0) ); assert( rc!=SQLITE_OK || pTab->p.base.zErrMsg==0 ); assert( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_CONTENT) ); } if( rc==SQLITE_OK && CsrFlagTest(pCsr, FTS5CSR_REQUIRE_CONTENT) ){ Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab); assert( pCsr->pExpr ); sqlite3_reset(pCsr->pStmt); sqlite3_bind_int64(pCsr->pStmt, 1, fts5CursorRowid(pCsr)); pTab->pConfig->bLock++; rc = sqlite3_step(pCsr->pStmt); pTab->pConfig->bLock--; if( rc==SQLITE_ROW ){ rc = SQLITE_OK; CsrFlagClear(pCsr, FTS5CSR_REQUIRE_CONTENT); }else{ rc = sqlite3_reset(pCsr->pStmt); if( rc==SQLITE_OK ){ rc = FTS5_CORRUPT; }else if( pTab->pConfig->pzErrmsg ){ *pTab->pConfig->pzErrmsg = sqlite3_mprintf( "%s", sqlite3_errmsg(pTab->pConfig->db) ); } } } return rc; } static void fts5SetVtabError(Fts5FullTable *p, const char *zFormat, ...){ va_list ap; /* ... printf arguments */ va_start(ap, zFormat); assert( p->p.base.zErrMsg==0 ); p->p.base.zErrMsg = sqlite3_vmprintf(zFormat, ap); va_end(ap); } /* ** This function is called to handle an FTS INSERT command. In other words, ** an INSERT statement of the form: ** ** INSERT INTO fts(fts) VALUES($pCmd) ** INSERT INTO fts(fts, rank) VALUES($pCmd, $pVal) ** ** Argument pVal is the value assigned to column "fts" by the INSERT ** statement. This function returns SQLITE_OK if successful, or an SQLite ** error code if an error occurs. ** ** The commands implemented by this function are documented in the "Special ** INSERT Directives" section of the documentation. It should be updated if ** more commands are added to this function. */ static int fts5SpecialInsert( Fts5FullTable *pTab, /* Fts5 table object */ const char *zCmd, /* Text inserted into table-name column */ sqlite3_value *pVal /* Value inserted into rank column */ ){ Fts5Config *pConfig = pTab->p.pConfig; int rc = SQLITE_OK; int bError = 0; if( 0==sqlite3_stricmp("delete-all", zCmd) ){ if( pConfig->eContent==FTS5_CONTENT_NORMAL ){ fts5SetVtabError(pTab, "'delete-all' may only be used with a " |
︙ | ︙ | |||
1413 1414 1415 1416 1417 1418 1419 | } }else if( 0==sqlite3_stricmp("optimize", zCmd) ){ rc = sqlite3Fts5StorageOptimize(pTab->pStorage); }else if( 0==sqlite3_stricmp("merge", zCmd) ){ int nMerge = sqlite3_value_int(pVal); rc = sqlite3Fts5StorageMerge(pTab->pStorage, nMerge); }else if( 0==sqlite3_stricmp("integrity-check", zCmd) ){ | > | | | | | | 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 | } }else if( 0==sqlite3_stricmp("optimize", zCmd) ){ rc = sqlite3Fts5StorageOptimize(pTab->pStorage); }else if( 0==sqlite3_stricmp("merge", zCmd) ){ int nMerge = sqlite3_value_int(pVal); rc = sqlite3Fts5StorageMerge(pTab->pStorage, nMerge); }else if( 0==sqlite3_stricmp("integrity-check", zCmd) ){ int iArg = sqlite3_value_int(pVal); rc = sqlite3Fts5StorageIntegrity(pTab->pStorage, iArg); #ifdef SQLITE_DEBUG }else if( 0==sqlite3_stricmp("prefix-index", zCmd) ){ pConfig->bPrefixIndex = sqlite3_value_int(pVal); #endif }else{ rc = sqlite3Fts5IndexLoadConfig(pTab->p.pIndex); if( rc==SQLITE_OK ){ rc = sqlite3Fts5ConfigSetValue(pTab->p.pConfig, zCmd, pVal, &bError); } if( rc==SQLITE_OK ){ if( bError ){ rc = SQLITE_ERROR; }else{ rc = sqlite3Fts5StorageConfigValue(pTab->pStorage, zCmd, pVal, 0); } } } return rc; } static int fts5SpecialDelete( Fts5FullTable *pTab, sqlite3_value **apVal ){ int rc = SQLITE_OK; int eType1 = sqlite3_value_type(apVal[1]); if( eType1==SQLITE_INTEGER ){ sqlite3_int64 iDel = sqlite3_value_int64(apVal[1]); rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel, &apVal[2]); } return rc; } static void fts5StorageInsert( int *pRc, Fts5FullTable *pTab, sqlite3_value **apVal, i64 *piRowid ){ int rc = *pRc; if( rc==SQLITE_OK ){ rc = sqlite3Fts5StorageContentInsert(pTab->pStorage, apVal, piRowid); } |
︙ | ︙ | |||
1483 1484 1485 1486 1487 1488 1489 | */ static int fts5UpdateMethod( sqlite3_vtab *pVtab, /* Virtual table handle */ int nArg, /* Size of argument array */ sqlite3_value **apVal, /* Array of arguments */ sqlite_int64 *pRowid /* OUT: The affected (or effected) rowid */ ){ | | | < | | | | | 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 | */ static int fts5UpdateMethod( sqlite3_vtab *pVtab, /* Virtual table handle */ int nArg, /* Size of argument array */ sqlite3_value **apVal, /* Array of arguments */ sqlite_int64 *pRowid /* OUT: The affected (or effected) rowid */ ){ Fts5FullTable *pTab = (Fts5FullTable*)pVtab; Fts5Config *pConfig = pTab->p.pConfig; int eType0; /* value_type() of apVal[0] */ int rc = SQLITE_OK; /* Return code */ /* A transaction must be open when this is called. */ assert( pTab->ts.eState==1 ); assert( pVtab->zErrMsg==0 ); assert( nArg==1 || nArg==(2+pConfig->nCol+2) ); assert( sqlite3_value_type(apVal[0])==SQLITE_INTEGER || sqlite3_value_type(apVal[0])==SQLITE_NULL ); assert( pTab->p.pConfig->pzErrmsg==0 ); pTab->p.pConfig->pzErrmsg = &pTab->p.base.zErrMsg; /* Put any active cursors into REQUIRE_SEEK state. */ fts5TripCursors(pTab); eType0 = sqlite3_value_type(apVal[0]); if( eType0==SQLITE_NULL && sqlite3_value_type(apVal[2+pConfig->nCol])!=SQLITE_NULL |
︙ | ︙ | |||
1539 1540 1541 1542 1543 1544 1545 | assert( eType0==SQLITE_INTEGER || eType0==SQLITE_NULL ); assert( nArg!=1 || eType0==SQLITE_INTEGER ); /* Filter out attempts to run UPDATE or DELETE on contentless tables. ** This is not suported. */ if( eType0==SQLITE_INTEGER && fts5IsContentless(pTab) ){ | | | > > > > > > > | | | < < | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | > | | | | | | | | | 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 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 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 | assert( eType0==SQLITE_INTEGER || eType0==SQLITE_NULL ); assert( nArg!=1 || eType0==SQLITE_INTEGER ); /* Filter out attempts to run UPDATE or DELETE on contentless tables. ** This is not suported. */ if( eType0==SQLITE_INTEGER && fts5IsContentless(pTab) ){ pTab->p.base.zErrMsg = sqlite3_mprintf( "cannot %s contentless fts5 table: %s", (nArg>1 ? "UPDATE" : "DELETE from"), pConfig->zName ); rc = SQLITE_ERROR; } /* DELETE */ else if( nArg==1 ){ i64 iDel = sqlite3_value_int64(apVal[0]); /* Rowid to delete */ rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel, 0); } /* INSERT or UPDATE */ else{ int eType1 = sqlite3_value_numeric_type(apVal[1]); if( eType1!=SQLITE_INTEGER && eType1!=SQLITE_NULL ){ rc = SQLITE_MISMATCH; } else if( eType0!=SQLITE_INTEGER ){ /* If this is a REPLACE, first remove the current entry (if any) */ if( eConflict==SQLITE_REPLACE && eType1==SQLITE_INTEGER ){ i64 iNew = sqlite3_value_int64(apVal[1]); /* Rowid to delete */ rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew, 0); } fts5StorageInsert(&rc, pTab, apVal, pRowid); } /* UPDATE */ else{ i64 iOld = sqlite3_value_int64(apVal[0]); /* Old rowid */ i64 iNew = sqlite3_value_int64(apVal[1]); /* New rowid */ if( eType1==SQLITE_INTEGER && iOld!=iNew ){ if( eConflict==SQLITE_REPLACE ){ rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0); if( rc==SQLITE_OK ){ rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew, 0); } fts5StorageInsert(&rc, pTab, apVal, pRowid); }else{ rc = sqlite3Fts5StorageContentInsert(pTab->pStorage, apVal, pRowid); if( rc==SQLITE_OK ){ rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0); } if( rc==SQLITE_OK ){ rc = sqlite3Fts5StorageIndexInsert(pTab->pStorage, apVal,*pRowid); } } }else{ rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0); fts5StorageInsert(&rc, pTab, apVal, pRowid); } } } } pTab->p.pConfig->pzErrmsg = 0; return rc; } /* ** Implementation of xSync() method. */ static int fts5SyncMethod(sqlite3_vtab *pVtab){ int rc; Fts5FullTable *pTab = (Fts5FullTable*)pVtab; fts5CheckTransactionState(pTab, FTS5_SYNC, 0); pTab->p.pConfig->pzErrmsg = &pTab->p.base.zErrMsg; fts5TripCursors(pTab); rc = sqlite3Fts5StorageSync(pTab->pStorage); pTab->p.pConfig->pzErrmsg = 0; return rc; } /* ** Implementation of xBegin() method. */ static int fts5BeginMethod(sqlite3_vtab *pVtab){ fts5CheckTransactionState((Fts5FullTable*)pVtab, FTS5_BEGIN, 0); fts5NewTransaction((Fts5FullTable*)pVtab); return SQLITE_OK; } /* ** Implementation of xCommit() method. This is a no-op. The contents of ** the pending-terms hash-table have already been flushed into the database ** by fts5SyncMethod(). */ static int fts5CommitMethod(sqlite3_vtab *pVtab){ UNUSED_PARAM(pVtab); /* Call below is a no-op for NDEBUG builds */ fts5CheckTransactionState((Fts5FullTable*)pVtab, FTS5_COMMIT, 0); return SQLITE_OK; } /* ** Implementation of xRollback(). Discard the contents of the pending-terms ** hash-table. Any changes made to the database are reverted by SQLite. */ static int fts5RollbackMethod(sqlite3_vtab *pVtab){ int rc; Fts5FullTable *pTab = (Fts5FullTable*)pVtab; fts5CheckTransactionState(pTab, FTS5_ROLLBACK, 0); rc = sqlite3Fts5StorageRollback(pTab->pStorage); return rc; } static int fts5CsrPoslist(Fts5Cursor*, int, const u8**, int*); |
︙ | ︙ | |||
1659 1660 1661 1662 1663 1664 1665 | static int fts5ApiColumnTotalSize( Fts5Context *pCtx, int iCol, sqlite3_int64 *pnToken ){ Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; | | | | 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 | static int fts5ApiColumnTotalSize( Fts5Context *pCtx, int iCol, sqlite3_int64 *pnToken ){ Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; Fts5FullTable *pTab = (Fts5FullTable*)(pCsr->base.pVtab); return sqlite3Fts5StorageSize(pTab->pStorage, iCol, pnToken); } static int fts5ApiRowCount(Fts5Context *pCtx, i64 *pnRow){ Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; Fts5FullTable *pTab = (Fts5FullTable*)(pCsr->base.pVtab); return sqlite3Fts5StorageRowCount(pTab->pStorage, pnRow); } static int fts5ApiTokenize( Fts5Context *pCtx, const char *pText, int nText, void *pUserData, |
︙ | ︙ | |||
1700 1701 1702 1703 1704 1705 1706 | Fts5Context *pCtx, int iCol, const char **pz, int *pn ){ int rc = SQLITE_OK; Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; | | > > | 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 | Fts5Context *pCtx, int iCol, const char **pz, int *pn ){ int rc = SQLITE_OK; Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; if( fts5IsContentless((Fts5FullTable*)(pCsr->base.pVtab)) || pCsr->ePlan==FTS5_PLAN_SPECIAL ){ *pz = 0; *pn = 0; }else{ rc = fts5SeekCursor(pCsr, 0); if( rc==SQLITE_OK ){ *pz = (const char*)sqlite3_column_text(pCsr->pStmt, iCol+1); *pn = sqlite3_column_bytes(pCsr->pStmt, iCol+1); |
︙ | ︙ | |||
1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 | ** correctly for the current view. Return SQLITE_OK if successful, or an ** SQLite error code otherwise. */ static int fts5CacheInstArray(Fts5Cursor *pCsr){ int rc = SQLITE_OK; Fts5PoslistReader *aIter; /* One iterator for each phrase */ int nIter; /* Number of iterators/phrases */ nIter = sqlite3Fts5ExprPhraseCount(pCsr->pExpr); if( pCsr->aInstIter==0 ){ | > | | 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 | ** correctly for the current view. Return SQLITE_OK if successful, or an ** SQLite error code otherwise. */ static int fts5CacheInstArray(Fts5Cursor *pCsr){ int rc = SQLITE_OK; Fts5PoslistReader *aIter; /* One iterator for each phrase */ int nIter; /* Number of iterators/phrases */ int nCol = ((Fts5Table*)pCsr->base.pVtab)->pConfig->nCol; nIter = sqlite3Fts5ExprPhraseCount(pCsr->pExpr); if( pCsr->aInstIter==0 ){ sqlite3_int64 nByte = sizeof(Fts5PoslistReader) * nIter; pCsr->aInstIter = (Fts5PoslistReader*)sqlite3Fts5MallocZero(&rc, nByte); } aIter = pCsr->aInstIter; if( aIter ){ int nInst = 0; /* Number instances seen so far */ int i; |
︙ | ︙ | |||
1806 1807 1808 1809 1810 1811 1812 | iBest = i; } } if( iBest<0 ) break; nInst++; if( nInst>=pCsr->nInstAlloc ){ | | | | > > > > > > | 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 | iBest = i; } } if( iBest<0 ) break; nInst++; if( nInst>=pCsr->nInstAlloc ){ int nNewSize = pCsr->nInstAlloc ? pCsr->nInstAlloc*2 : 32; aInst = (int*)sqlite3_realloc64( pCsr->aInst, nNewSize*sizeof(int)*3 ); if( aInst ){ pCsr->aInst = aInst; pCsr->nInstAlloc = nNewSize; }else{ nInst--; rc = SQLITE_NOMEM; break; } } aInst = &pCsr->aInst[3 * (nInst-1)]; aInst[0] = iBest; aInst[1] = FTS5_POS2COLUMN(aIter[iBest].iPos); aInst[2] = FTS5_POS2OFFSET(aIter[iBest].iPos); if( aInst[1]<0 || aInst[1]>=nCol ){ rc = FTS5_CORRUPT; break; } sqlite3Fts5PoslistReaderNext(&aIter[iBest]); } } pCsr->nInstCount = nInst; CsrFlagClear(pCsr, FTS5CSR_REQUIRE_INST); } |
︙ | ︙ | |||
1894 1895 1896 1897 1898 1899 1900 | (*pCnt)++; } return SQLITE_OK; } static int fts5ApiColumnSize(Fts5Context *pCtx, int iCol, int *pnToken){ Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; | | | | 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 | (*pCnt)++; } return SQLITE_OK; } static int fts5ApiColumnSize(Fts5Context *pCtx, int iCol, int *pnToken){ Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; Fts5FullTable *pTab = (Fts5FullTable*)(pCsr->base.pVtab); Fts5Config *pConfig = pTab->p.pConfig; int rc = SQLITE_OK; if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_DOCSIZE) ){ if( pConfig->bColumnsize ){ i64 iRowid = fts5CursorRowid(pCsr); rc = sqlite3Fts5StorageDocsize(pTab->pStorage, iRowid, pCsr->aColumnSize); }else if( pConfig->zContent==0 ){ |
︙ | ︙ | |||
2032 2033 2034 2035 2036 2037 2038 | Fts5PhraseIter *pIter, int *piCol, int *piOff ){ Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; int n; int rc = fts5CsrPoslist(pCsr, iPhrase, &pIter->a, &n); if( rc==SQLITE_OK ){ | > | | 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 | Fts5PhraseIter *pIter, int *piCol, int *piOff ){ Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; int n; int rc = fts5CsrPoslist(pCsr, iPhrase, &pIter->a, &n); if( rc==SQLITE_OK ){ assert( pIter->a || n==0 ); pIter->b = (pIter->a ? &pIter->a[n] : 0); *piCol = 0; *piOff = 0; fts5ApiPhraseNext(pCtx, pIter, piCol, piOff); } return rc; } |
︙ | ︙ | |||
2091 2092 2093 2094 2095 2096 2097 | int i1 = (iPhrase==0 ? 0 : pSorter->aIdx[iPhrase-1]); n = pSorter->aIdx[iPhrase] - i1; pIter->a = &pSorter->aPoslist[i1]; }else{ rc = sqlite3Fts5ExprPhraseCollist(pCsr->pExpr, iPhrase, &pIter->a, &n); } if( rc==SQLITE_OK ){ | > | > | | 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 | int i1 = (iPhrase==0 ? 0 : pSorter->aIdx[iPhrase-1]); n = pSorter->aIdx[iPhrase] - i1; pIter->a = &pSorter->aPoslist[i1]; }else{ rc = sqlite3Fts5ExprPhraseCollist(pCsr->pExpr, iPhrase, &pIter->a, &n); } if( rc==SQLITE_OK ){ assert( pIter->a || n==0 ); pIter->b = (pIter->a ? &pIter->a[n] : 0); *piCol = 0; fts5ApiPhraseNextColumn(pCtx, pIter, piCol); } }else{ int n; rc = fts5CsrPoslist(pCsr, iPhrase, &pIter->a, &n); if( rc==SQLITE_OK ){ assert( pIter->a || n==0 ); pIter->b = (pIter->a ? &pIter->a[n] : 0); if( n<=0 ){ *piCol = -1; }else if( pIter->a[0]==0x01 ){ pIter->a += 1 + fts5GetVarint32(&pIter->a[1], *piCol); }else{ *piCol = 0; } |
︙ | ︙ | |||
2151 2152 2153 2154 2155 2156 2157 | static int fts5ApiQueryPhrase( Fts5Context *pCtx, int iPhrase, void *pUserData, int(*xCallback)(const Fts5ExtensionApi*, Fts5Context*, void*) ){ Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; | | | 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 | static int fts5ApiQueryPhrase( Fts5Context *pCtx, int iPhrase, void *pUserData, int(*xCallback)(const Fts5ExtensionApi*, Fts5Context*, void*) ){ Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; Fts5FullTable *pTab = (Fts5FullTable*)(pCsr->base.pVtab); int rc; Fts5Cursor *pNew = 0; rc = fts5OpenMethod(pCsr->base.pVtab, (sqlite3_vtab_cursor**)&pNew); if( rc==SQLITE_OK ){ pNew->ePlan = FTS5_PLAN_MATCH; pNew->iFirstRowid = SMALLEST_INT64; |
︙ | ︙ | |||
2217 2218 2219 2220 2221 2222 2223 | i64 iCsrId; assert( argc>=1 ); pAux = (Fts5Auxiliary*)sqlite3_user_data(context); iCsrId = sqlite3_value_int64(argv[0]); pCsr = fts5CursorFromCsrid(pAux->pGlobal, iCsrId); | | | < < < | | < < < > | < | | | 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 2400 2401 2402 2403 | i64 iCsrId; assert( argc>=1 ); pAux = (Fts5Auxiliary*)sqlite3_user_data(context); iCsrId = sqlite3_value_int64(argv[0]); pCsr = fts5CursorFromCsrid(pAux->pGlobal, iCsrId); if( pCsr==0 || pCsr->ePlan==0 ){ char *zErr = sqlite3_mprintf("no such cursor: %lld", iCsrId); sqlite3_result_error(context, zErr, -1); sqlite3_free(zErr); }else{ fts5ApiInvoke(pAux, pCsr, context, argc-1, &argv[1]); } } /* ** Given cursor id iId, return a pointer to the corresponding Fts5Table ** object. Or NULL If the cursor id does not exist. */ Fts5Table *sqlite3Fts5TableFromCsrid( Fts5Global *pGlobal, /* FTS5 global context for db handle */ i64 iCsrId /* Id of cursor to find */ ){ Fts5Cursor *pCsr; pCsr = fts5CursorFromCsrid(pGlobal, iCsrId); if( pCsr ){ return (Fts5Table*)pCsr->base.pVtab; } return 0; } /* ** Return a "position-list blob" corresponding to the current position of ** cursor pCsr via sqlite3_result_blob(). A position-list blob contains ** the current position-list for each phrase in the query associated with ** cursor pCsr. |
︙ | ︙ | |||
2326 2327 2328 2329 2330 2331 2332 | ** the row that the supplied cursor currently points to. */ static int fts5ColumnMethod( 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 */ ){ | | | | 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 | ** the row that the supplied cursor currently points to. */ static int fts5ColumnMethod( 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 */ ){ Fts5FullTable *pTab = (Fts5FullTable*)(pCursor->pVtab); Fts5Config *pConfig = pTab->p.pConfig; Fts5Cursor *pCsr = (Fts5Cursor*)pCursor; int rc = SQLITE_OK; assert( CsrFlagTest(pCsr, FTS5CSR_EOF)==0 ); if( pCsr->ePlan==FTS5_PLAN_SPECIAL ){ if( iCol==pConfig->nCol ){ |
︙ | ︙ | |||
2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 | || pCsr->ePlan==FTS5_PLAN_SORTED_MATCH ){ if( pCsr->pRank || SQLITE_OK==(rc = fts5FindRankFunction(pCsr)) ){ fts5ApiInvoke(pCsr->pRank, pCsr, pCtx, pCsr->nRankArg, pCsr->apRankArg); } } }else if( !fts5IsContentless(pTab) ){ rc = fts5SeekCursor(pCsr, 1); if( rc==SQLITE_OK ){ sqlite3_result_value(pCtx, sqlite3_column_value(pCsr->pStmt, iCol+1)); } } return rc; } /* ** This routine implements the xFindFunction method for the FTS3 ** virtual table. */ static int fts5FindFunctionMethod( sqlite3_vtab *pVtab, /* Virtual table handle */ int nUnused, /* Number of SQL function arguments */ const char *zName, /* Name of SQL function */ void (**pxFunc)(sqlite3_context*,int,sqlite3_value**), /* OUT: Result */ void **ppArg /* OUT: User data for *pxFunc */ ){ | > > | | 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 2531 2532 2533 2534 2535 2536 2537 2538 | || pCsr->ePlan==FTS5_PLAN_SORTED_MATCH ){ if( pCsr->pRank || SQLITE_OK==(rc = fts5FindRankFunction(pCsr)) ){ fts5ApiInvoke(pCsr->pRank, pCsr, pCtx, pCsr->nRankArg, pCsr->apRankArg); } } }else if( !fts5IsContentless(pTab) ){ pConfig->pzErrmsg = &pTab->p.base.zErrMsg; rc = fts5SeekCursor(pCsr, 1); if( rc==SQLITE_OK ){ sqlite3_result_value(pCtx, sqlite3_column_value(pCsr->pStmt, iCol+1)); } pConfig->pzErrmsg = 0; } return rc; } /* ** This routine implements the xFindFunction method for the FTS3 ** virtual table. */ static int fts5FindFunctionMethod( sqlite3_vtab *pVtab, /* Virtual table handle */ int nUnused, /* Number of SQL function arguments */ const char *zName, /* Name of SQL function */ void (**pxFunc)(sqlite3_context*,int,sqlite3_value**), /* OUT: Result */ void **ppArg /* OUT: User data for *pxFunc */ ){ Fts5FullTable *pTab = (Fts5FullTable*)pVtab; Fts5Auxiliary *pAux; UNUSED_PARAM(nUnused); pAux = fts5FindAuxiliary(pTab, zName); if( pAux ){ *pxFunc = fts5ApiCallback; *ppArg = (void*)pAux; |
︙ | ︙ | |||
2401 2402 2403 2404 2405 2406 2407 | /* ** Implementation of FTS5 xRename method. Rename an fts5 table. */ static int fts5RenameMethod( sqlite3_vtab *pVtab, /* Virtual table handle */ const char *zName /* New name of table */ ){ | | > > > > > < | < | < | < | | | | | | | | 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 | /* ** Implementation of FTS5 xRename method. Rename an fts5 table. */ static int fts5RenameMethod( sqlite3_vtab *pVtab, /* Virtual table handle */ const char *zName /* New name of table */ ){ Fts5FullTable *pTab = (Fts5FullTable*)pVtab; return sqlite3Fts5StorageRename(pTab->pStorage, zName); } int sqlite3Fts5FlushToDisk(Fts5Table *pTab){ fts5TripCursors((Fts5FullTable*)pTab); return sqlite3Fts5StorageSync(((Fts5FullTable*)pTab)->pStorage); } /* ** The xSavepoint() method. ** ** Flush the contents of the pending-terms table to disk. */ static int fts5SavepointMethod(sqlite3_vtab *pVtab, int iSavepoint){ UNUSED_PARAM(iSavepoint); /* Call below is a no-op for NDEBUG builds */ fts5CheckTransactionState((Fts5FullTable*)pVtab, FTS5_SAVEPOINT, iSavepoint); return sqlite3Fts5FlushToDisk((Fts5Table*)pVtab); } /* ** The xRelease() method. ** ** This is a no-op. */ static int fts5ReleaseMethod(sqlite3_vtab *pVtab, int iSavepoint){ UNUSED_PARAM(iSavepoint); /* Call below is a no-op for NDEBUG builds */ fts5CheckTransactionState((Fts5FullTable*)pVtab, FTS5_RELEASE, iSavepoint); return sqlite3Fts5FlushToDisk((Fts5Table*)pVtab); } /* ** The xRollbackTo() method. ** ** Discard the contents of the pending terms table. */ static int fts5RollbackToMethod(sqlite3_vtab *pVtab, int iSavepoint){ Fts5FullTable *pTab = (Fts5FullTable*)pVtab; UNUSED_PARAM(iSavepoint); /* Call below is a no-op for NDEBUG builds */ fts5CheckTransactionState(pTab, FTS5_ROLLBACKTO, iSavepoint); fts5TripCursors(pTab); return sqlite3Fts5StorageRollback(pTab->pStorage); } /* ** Register a new auxiliary function with global context pGlobal. */ static int fts5CreateAux( fts5_api *pApi, /* Global context (one per db handle) */ const char *zName, /* Name of new function */ void *pUserData, /* User data for aux. function */ fts5_extension_function xFunc, /* Aux. function implementation */ void(*xDestroy)(void*) /* Destructor for pUserData */ ){ Fts5Global *pGlobal = (Fts5Global*)pApi; int rc = sqlite3_overload_function(pGlobal->db, zName, -1); if( rc==SQLITE_OK ){ Fts5Auxiliary *pAux; sqlite3_int64 nName; /* Size of zName in bytes, including \0 */ sqlite3_int64 nByte; /* Bytes of space to allocate */ nName = strlen(zName) + 1; nByte = sizeof(Fts5Auxiliary) + nName; pAux = (Fts5Auxiliary*)sqlite3_malloc64(nByte); if( pAux ){ memset(pAux, 0, (size_t)nByte); pAux->zFunc = (char*)&pAux[1]; memcpy(pAux->zFunc, zName, nName); pAux->pGlobal = pGlobal; pAux->pUserData = pUserData; pAux->xFunc = xFunc; pAux->xDestroy = xDestroy; pAux->pNext = pGlobal->pAux; |
︙ | ︙ | |||
2495 2496 2497 2498 2499 2500 2501 | const char *zName, /* Name of new function */ void *pUserData, /* User data for aux. function */ fts5_tokenizer *pTokenizer, /* Tokenizer implementation */ void(*xDestroy)(void*) /* Destructor for pUserData */ ){ Fts5Global *pGlobal = (Fts5Global*)pApi; Fts5TokenizerModule *pNew; | | | | | | | 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 | const char *zName, /* Name of new function */ void *pUserData, /* User data for aux. function */ fts5_tokenizer *pTokenizer, /* Tokenizer implementation */ void(*xDestroy)(void*) /* Destructor for pUserData */ ){ Fts5Global *pGlobal = (Fts5Global*)pApi; Fts5TokenizerModule *pNew; sqlite3_int64 nName; /* Size of zName and its \0 terminator */ sqlite3_int64 nByte; /* Bytes of space to allocate */ int rc = SQLITE_OK; nName = strlen(zName) + 1; nByte = sizeof(Fts5TokenizerModule) + nName; pNew = (Fts5TokenizerModule*)sqlite3_malloc64(nByte); if( pNew ){ memset(pNew, 0, (size_t)nByte); pNew->zName = (char*)&pNew[1]; memcpy(pNew->zName, zName, nName); pNew->pUserData = pUserData; pNew->x = *pTokenizer; pNew->xDestroy = xDestroy; pNew->pNext = pGlobal->pTok; pGlobal->pTok = pNew; |
︙ | ︙ | |||
2567 2568 2569 2570 2571 2572 2573 | return rc; } int sqlite3Fts5GetTokenizer( Fts5Global *pGlobal, const char **azArg, int nArg, | | < | > > | | | > > > > | | | 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 | return rc; } int sqlite3Fts5GetTokenizer( Fts5Global *pGlobal, const char **azArg, int nArg, Fts5Config *pConfig, char **pzErr ){ Fts5TokenizerModule *pMod; int rc = SQLITE_OK; pMod = fts5LocateTokenizer(pGlobal, nArg==0 ? 0 : azArg[0]); if( pMod==0 ){ assert( nArg>0 ); rc = SQLITE_ERROR; *pzErr = sqlite3_mprintf("no such tokenizer: %s", azArg[0]); }else{ rc = pMod->x.xCreate( pMod->pUserData, (azArg?&azArg[1]:0), (nArg?nArg-1:0), &pConfig->pTok ); pConfig->pTokApi = &pMod->x; if( rc!=SQLITE_OK ){ if( pzErr ) *pzErr = sqlite3_mprintf("error in tokenizer constructor"); }else{ pConfig->ePattern = sqlite3Fts5TokenizerPattern( pMod->x.xCreate, pConfig->pTok ); } } if( rc!=SQLITE_OK ){ pConfig->pTokApi = 0; pConfig->pTok = 0; } return rc; } static void fts5ModuleDestroy(void *pCtx){ Fts5TokenizerModule *pTok, *pNextTok; |
︙ | ︙ |
Changes to ext/fts5/fts5_storage.c.
︙ | ︙ | |||
111 112 113 114 115 116 117 | case FTS5_STMT_INSERT_CONTENT: case FTS5_STMT_REPLACE_CONTENT: { int nCol = pC->nCol + 1; char *zBind; int i; | | > > > | < > | 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 | case FTS5_STMT_INSERT_CONTENT: case FTS5_STMT_REPLACE_CONTENT: { int nCol = pC->nCol + 1; char *zBind; int i; zBind = sqlite3_malloc64(1 + nCol*2); if( zBind ){ for(i=0; i<nCol; i++){ zBind[i*2] = '?'; zBind[i*2 + 1] = ','; } zBind[i*2-1] = '\0'; zSql = sqlite3_mprintf(azStmt[eStmt], pC->zDb, pC->zName, zBind); sqlite3_free(zBind); } break; } default: zSql = sqlite3_mprintf(azStmt[eStmt], pC->zDb, pC->zName); break; } if( zSql==0 ){ rc = SQLITE_NOMEM; }else{ int f = SQLITE_PREPARE_PERSISTENT; if( eStmt>FTS5_STMT_LOOKUP ) f |= SQLITE_PREPARE_NO_VTAB; p->pConfig->bLock++; rc = sqlite3_prepare_v3(pC->db, zSql, -1, f, &p->aStmt[eStmt], 0); p->pConfig->bLock--; sqlite3_free(zSql); if( rc!=SQLITE_OK && pzErrMsg ){ *pzErrMsg = sqlite3_mprintf("%s", sqlite3_errmsg(pC->db)); } } } |
︙ | ︙ | |||
277 278 279 280 281 282 283 | Fts5Index *pIndex, int bCreate, Fts5Storage **pp, char **pzErr /* OUT: Error message */ ){ int rc = SQLITE_OK; Fts5Storage *p; /* New object */ | | | | | | 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 | Fts5Index *pIndex, int bCreate, Fts5Storage **pp, char **pzErr /* OUT: Error message */ ){ int rc = SQLITE_OK; Fts5Storage *p; /* New object */ sqlite3_int64 nByte; /* Bytes of space to allocate */ nByte = sizeof(Fts5Storage) /* Fts5Storage object */ + pConfig->nCol * sizeof(i64); /* Fts5Storage.aTotalSize[] */ *pp = p = (Fts5Storage*)sqlite3_malloc64(nByte); if( !p ) return SQLITE_NOMEM; memset(p, 0, (size_t)nByte); p->aTotalSize = (i64*)&p[1]; p->pConfig = pConfig; p->pIndex = pIndex; if( bCreate ){ if( pConfig->eContent==FTS5_CONTENT_NORMAL ){ int nDefn = 32 + pConfig->nCol*10; char *zDefn = sqlite3_malloc64(32 + (sqlite3_int64)pConfig->nCol * 10); if( zDefn==0 ){ rc = SQLITE_NOMEM; }else{ int i; int iOff; sqlite3_snprintf(nDefn, zDefn, "id INTEGER PRIMARY KEY"); iOff = (int)strlen(zDefn); |
︙ | ︙ | |||
410 411 412 413 414 415 416 417 418 419 | ctx.pStorage = p; ctx.iCol = -1; rc = sqlite3Fts5IndexBeginWrite(p->pIndex, 1, iDel); for(iCol=1; rc==SQLITE_OK && iCol<=pConfig->nCol; iCol++){ if( pConfig->abUnindexed[iCol-1]==0 ){ const char *zText; int nText; if( pSeek ){ zText = (const char*)sqlite3_column_text(pSeek, iCol); nText = sqlite3_column_bytes(pSeek, iCol); | > > | > > > > | | > > > > | > | 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 | ctx.pStorage = p; ctx.iCol = -1; rc = sqlite3Fts5IndexBeginWrite(p->pIndex, 1, iDel); for(iCol=1; rc==SQLITE_OK && iCol<=pConfig->nCol; iCol++){ if( pConfig->abUnindexed[iCol-1]==0 ){ const char *zText; int nText; assert( pSeek==0 || apVal==0 ); assert( pSeek!=0 || apVal!=0 ); if( pSeek ){ zText = (const char*)sqlite3_column_text(pSeek, iCol); nText = sqlite3_column_bytes(pSeek, iCol); }else if( ALWAYS(apVal) ){ zText = (const char*)sqlite3_value_text(apVal[iCol-1]); nText = sqlite3_value_bytes(apVal[iCol-1]); }else{ continue; } ctx.szCol = 0; rc = sqlite3Fts5Tokenize(pConfig, FTS5_TOKENIZE_DOCUMENT, zText, nText, (void*)&ctx, fts5StorageInsertCallback ); p->aTotalSize[iCol-1] -= (i64)ctx.szCol; if( p->aTotalSize[iCol-1]<0 ){ rc = FTS5_CORRUPT; } } } if( rc==SQLITE_OK && p->nTotalRow<1 ){ rc = FTS5_CORRUPT; }else{ p->nTotalRow--; } rc2 = sqlite3_reset(pSeek); if( rc==SQLITE_OK ) rc = rc2; return rc; } |
︙ | ︙ | |||
552 553 554 555 556 557 558 559 560 561 562 563 564 565 | /* ** Delete all entries in the FTS5 index. */ int sqlite3Fts5StorageDeleteAll(Fts5Storage *p){ Fts5Config *pConfig = p->pConfig; int rc; /* Delete the contents of the %_data and %_docsize tables. */ rc = fts5ExecPrintf(pConfig->db, 0, "DELETE FROM %Q.'%q_data';" "DELETE FROM %Q.'%q_idx';", pConfig->zDb, pConfig->zName, pConfig->zDb, pConfig->zName | > > | 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 | /* ** Delete all entries in the FTS5 index. */ int sqlite3Fts5StorageDeleteAll(Fts5Storage *p){ Fts5Config *pConfig = p->pConfig; int rc; p->bTotalsValid = 0; /* Delete the contents of the %_data and %_docsize tables. */ rc = fts5ExecPrintf(pConfig->db, 0, "DELETE FROM %Q.'%q_data';" "DELETE FROM %Q.'%q_idx';", pConfig->zDb, pConfig->zName, pConfig->zDb, pConfig->zName |
︙ | ︙ | |||
583 584 585 586 587 588 589 | } int sqlite3Fts5StorageRebuild(Fts5Storage *p){ Fts5Buffer buf = {0,0,0}; Fts5Config *pConfig = p->pConfig; sqlite3_stmt *pScan = 0; Fts5InsertCtx ctx; | | > > < < > > > | 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 | } int sqlite3Fts5StorageRebuild(Fts5Storage *p){ Fts5Buffer buf = {0,0,0}; Fts5Config *pConfig = p->pConfig; sqlite3_stmt *pScan = 0; Fts5InsertCtx ctx; int rc, rc2; memset(&ctx, 0, sizeof(Fts5InsertCtx)); ctx.pStorage = p; rc = sqlite3Fts5StorageDeleteAll(p); if( rc==SQLITE_OK ){ rc = fts5StorageLoadTotals(p, 1); } if( rc==SQLITE_OK ){ rc = fts5StorageGetStmt(p, FTS5_STMT_SCAN, &pScan, 0); } while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pScan) ){ i64 iRowid = sqlite3_column_int64(pScan, 0); sqlite3Fts5BufferZero(&buf); rc = sqlite3Fts5IndexBeginWrite(p->pIndex, 0, iRowid); for(ctx.iCol=0; rc==SQLITE_OK && ctx.iCol<pConfig->nCol; ctx.iCol++){ ctx.szCol = 0; if( pConfig->abUnindexed[ctx.iCol]==0 ){ const char *zText = (const char*)sqlite3_column_text(pScan, ctx.iCol+1); int nText = sqlite3_column_bytes(pScan, ctx.iCol+1); rc = sqlite3Fts5Tokenize(pConfig, FTS5_TOKENIZE_DOCUMENT, zText, nText, (void*)&ctx, fts5StorageInsertCallback ); } sqlite3Fts5BufferAppendVarint(&rc, &buf, ctx.szCol); p->aTotalSize[ctx.iCol] += (i64)ctx.szCol; } p->nTotalRow++; if( rc==SQLITE_OK ){ rc = fts5StorageInsertDocsize(p, iRowid, &buf); } } sqlite3_free(buf.p); rc2 = sqlite3_reset(pScan); if( rc==SQLITE_OK ) rc = rc2; /* Write the averages record */ if( rc==SQLITE_OK ){ rc = fts5StorageSaveTotals(p); } return rc; } |
︙ | ︙ | |||
727 728 729 730 731 732 733 734 735 | if( rc==SQLITE_OK ){ rc = sqlite3Fts5IndexBeginWrite(p->pIndex, 0, iRowid); } for(ctx.iCol=0; rc==SQLITE_OK && ctx.iCol<pConfig->nCol; ctx.iCol++){ ctx.szCol = 0; if( pConfig->abUnindexed[ctx.iCol]==0 ){ rc = sqlite3Fts5Tokenize(pConfig, FTS5_TOKENIZE_DOCUMENT, | > > < < > | 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 | if( rc==SQLITE_OK ){ rc = sqlite3Fts5IndexBeginWrite(p->pIndex, 0, iRowid); } for(ctx.iCol=0; rc==SQLITE_OK && ctx.iCol<pConfig->nCol; ctx.iCol++){ ctx.szCol = 0; if( pConfig->abUnindexed[ctx.iCol]==0 ){ const char *zText = (const char*)sqlite3_value_text(apVal[ctx.iCol+2]); int nText = sqlite3_value_bytes(apVal[ctx.iCol+2]); rc = sqlite3Fts5Tokenize(pConfig, FTS5_TOKENIZE_DOCUMENT, zText, nText, (void*)&ctx, fts5StorageInsertCallback ); } sqlite3Fts5BufferAppendVarint(&rc, &buf, ctx.szCol); p->aTotalSize[ctx.iCol] += (i64)ctx.szCol; } |
︙ | ︙ | |||
861 862 863 864 865 866 867 | /* ** Check that the contents of the FTS index match that of the %_content ** table. Return SQLITE_OK if they do, or SQLITE_CORRUPT if not. Return ** some other SQLite error code if an error occurs while attempting to ** determine this. */ | | | > | > > > > | | | | | | | | | | | | | | | | | | | | | | | > > | | | < | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | > | | 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 | /* ** Check that the contents of the FTS index match that of the %_content ** table. Return SQLITE_OK if they do, or SQLITE_CORRUPT if not. Return ** some other SQLite error code if an error occurs while attempting to ** determine this. */ int sqlite3Fts5StorageIntegrity(Fts5Storage *p, int iArg){ Fts5Config *pConfig = p->pConfig; int rc = SQLITE_OK; /* Return code */ int *aColSize; /* Array of size pConfig->nCol */ i64 *aTotalSize; /* Array of size pConfig->nCol */ Fts5IntegrityCtx ctx; sqlite3_stmt *pScan; int bUseCksum; memset(&ctx, 0, sizeof(Fts5IntegrityCtx)); ctx.pConfig = p->pConfig; aTotalSize = (i64*)sqlite3_malloc64(pConfig->nCol*(sizeof(int)+sizeof(i64))); if( !aTotalSize ) return SQLITE_NOMEM; aColSize = (int*)&aTotalSize[pConfig->nCol]; memset(aTotalSize, 0, sizeof(i64) * pConfig->nCol); bUseCksum = (pConfig->eContent==FTS5_CONTENT_NORMAL || (pConfig->eContent==FTS5_CONTENT_EXTERNAL && iArg) ); if( bUseCksum ){ /* Generate the expected index checksum based on the contents of the ** %_content table. This block stores the checksum in ctx.cksum. */ rc = fts5StorageGetStmt(p, FTS5_STMT_SCAN, &pScan, 0); if( rc==SQLITE_OK ){ int rc2; while( SQLITE_ROW==sqlite3_step(pScan) ){ int i; ctx.iRowid = sqlite3_column_int64(pScan, 0); ctx.szCol = 0; if( pConfig->bColumnsize ){ rc = sqlite3Fts5StorageDocsize(p, ctx.iRowid, aColSize); } if( rc==SQLITE_OK && pConfig->eDetail==FTS5_DETAIL_NONE ){ rc = sqlite3Fts5TermsetNew(&ctx.pTermset); } for(i=0; rc==SQLITE_OK && i<pConfig->nCol; i++){ if( pConfig->abUnindexed[i] ) continue; ctx.iCol = i; ctx.szCol = 0; if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){ rc = sqlite3Fts5TermsetNew(&ctx.pTermset); } if( rc==SQLITE_OK ){ const char *zText = (const char*)sqlite3_column_text(pScan, i+1); int nText = sqlite3_column_bytes(pScan, i+1); rc = sqlite3Fts5Tokenize(pConfig, FTS5_TOKENIZE_DOCUMENT, zText, nText, (void*)&ctx, fts5StorageIntegrityCallback ); } if( rc==SQLITE_OK && pConfig->bColumnsize && ctx.szCol!=aColSize[i] ){ rc = FTS5_CORRUPT; } aTotalSize[i] += ctx.szCol; if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){ sqlite3Fts5TermsetFree(ctx.pTermset); ctx.pTermset = 0; } } sqlite3Fts5TermsetFree(ctx.pTermset); ctx.pTermset = 0; if( rc!=SQLITE_OK ) break; } rc2 = sqlite3_reset(pScan); if( rc==SQLITE_OK ) rc = rc2; } /* Test that the "totals" (sometimes called "averages") record looks Ok */ if( rc==SQLITE_OK ){ int i; rc = fts5StorageLoadTotals(p, 0); for(i=0; rc==SQLITE_OK && i<pConfig->nCol; i++){ if( p->aTotalSize[i]!=aTotalSize[i] ) rc = FTS5_CORRUPT; } } /* Check that the %_docsize and %_content tables contain the expected ** number of rows. */ if( rc==SQLITE_OK && pConfig->eContent==FTS5_CONTENT_NORMAL ){ i64 nRow = 0; rc = fts5StorageCount(p, "content", &nRow); if( rc==SQLITE_OK && nRow!=p->nTotalRow ) rc = FTS5_CORRUPT; } if( rc==SQLITE_OK && pConfig->bColumnsize ){ i64 nRow = 0; rc = fts5StorageCount(p, "docsize", &nRow); if( rc==SQLITE_OK && nRow!=p->nTotalRow ) rc = FTS5_CORRUPT; } } /* Pass the expected checksum down to the FTS index module. It will ** verify, amongst other things, that it matches the checksum generated by ** inspecting the index itself. */ if( rc==SQLITE_OK ){ rc = sqlite3Fts5IndexIntegrityCheck(p->pIndex, ctx.cksum, bUseCksum); } sqlite3_free(aTotalSize); return rc; } /* |
︙ | ︙ | |||
1031 1032 1033 1034 1035 1036 1037 | int sqlite3Fts5StorageDocsize(Fts5Storage *p, i64 iRowid, int *aCol){ int nCol = p->pConfig->nCol; /* Number of user columns in table */ sqlite3_stmt *pLookup = 0; /* Statement to query %_docsize */ int rc; /* Return Code */ assert( p->pConfig->bColumnsize ); rc = fts5StorageGetStmt(p, FTS5_STMT_LOOKUP_DOCSIZE, &pLookup, 0); | | > > > | 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 | int sqlite3Fts5StorageDocsize(Fts5Storage *p, i64 iRowid, int *aCol){ int nCol = p->pConfig->nCol; /* Number of user columns in table */ sqlite3_stmt *pLookup = 0; /* Statement to query %_docsize */ int rc; /* Return Code */ assert( p->pConfig->bColumnsize ); rc = fts5StorageGetStmt(p, FTS5_STMT_LOOKUP_DOCSIZE, &pLookup, 0); if( pLookup ){ int bCorrupt = 1; assert( rc==SQLITE_OK ); sqlite3_bind_int64(pLookup, 1, iRowid); if( SQLITE_ROW==sqlite3_step(pLookup) ){ const u8 *aBlob = sqlite3_column_blob(pLookup, 0); int nBlob = sqlite3_column_bytes(pLookup, 0); if( 0==fts5StorageDecodeSizeArray(aCol, nCol, aBlob, nBlob) ){ bCorrupt = 0; } } rc = sqlite3_reset(pLookup); if( bCorrupt && rc==SQLITE_OK ){ rc = FTS5_CORRUPT; } }else{ assert( rc!=SQLITE_OK ); } return rc; } int sqlite3Fts5StorageSize(Fts5Storage *p, int iCol, i64 *pnToken){ int rc = fts5StorageLoadTotals(p, 0); |
︙ | ︙ | |||
1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 | } return rc; } int sqlite3Fts5StorageRowCount(Fts5Storage *p, i64 *pnRow){ int rc = fts5StorageLoadTotals(p, 0); if( rc==SQLITE_OK ){ *pnRow = p->nTotalRow; } return rc; } /* ** Flush any data currently held in-memory to disk. */ | > > > > > > | 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 | } return rc; } int sqlite3Fts5StorageRowCount(Fts5Storage *p, i64 *pnRow){ int rc = fts5StorageLoadTotals(p, 0); if( rc==SQLITE_OK ){ /* nTotalRow being zero does not necessarily indicate a corrupt ** database - it might be that the FTS5 table really does contain zero ** rows. However this function is only called from the xRowCount() API, ** and there is no way for that API to be invoked if the table contains ** no rows. Hence the FTS5_CORRUPT return. */ *pnRow = p->nTotalRow; if( p->nTotalRow<=0 ) rc = FTS5_CORRUPT; } return rc; } /* ** Flush any data currently held in-memory to disk. */ |
︙ | ︙ |
Changes to ext/fts5/fts5_tcl.c.
︙ | ︙ | |||
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | #ifdef SQLITE_ENABLE_FTS5 #include "fts5.h" #include <string.h> #include <assert.h> extern int sqlite3_fts5_may_be_corrupt; extern int sqlite3Fts5TestRegisterMatchinfo(sqlite3*); extern int sqlite3Fts5TestRegisterTok(sqlite3*, fts5_api*); /************************************************************************* ** This is a copy of the first part of the SqliteDb structure in ** tclsqlite.c. We need it here so that the get_sqlite_pointer routine ** can extract the sqlite3* pointer from an existing Tcl SQLite | > > | 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | #ifdef SQLITE_ENABLE_FTS5 #include "fts5.h" #include <string.h> #include <assert.h> #ifdef SQLITE_DEBUG extern int sqlite3_fts5_may_be_corrupt; #endif extern int sqlite3Fts5TestRegisterMatchinfo(sqlite3*); extern int sqlite3Fts5TestRegisterTok(sqlite3*, fts5_api*); /************************************************************************* ** This is a copy of the first part of the SqliteDb structure in ** tclsqlite.c. We need it here so that the get_sqlite_pointer routine ** can extract the sqlite3* pointer from an existing Tcl SQLite |
︙ | ︙ | |||
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 | */ static int SQLITE_TCLAPI f5tMayBeCorrupt( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ int bOld = sqlite3_fts5_may_be_corrupt; if( objc!=2 && objc!=1 ){ Tcl_WrongNumArgs(interp, 1, objv, "?BOOLEAN?"); return TCL_ERROR; } if( objc==2 ){ int bNew; if( Tcl_GetBooleanFromObj(interp, objv[1], &bNew) ) return TCL_ERROR; sqlite3_fts5_may_be_corrupt = bNew; } Tcl_SetObjResult(interp, Tcl_NewIntObj(bOld)); return TCL_OK; } static unsigned int f5t_fts5HashKey(int nSlot, const char *p, int n){ int i; unsigned int h = 13; | > > | 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 | */ static int SQLITE_TCLAPI f5tMayBeCorrupt( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ #ifdef SQLITE_DEBUG int bOld = sqlite3_fts5_may_be_corrupt; if( objc!=2 && objc!=1 ){ Tcl_WrongNumArgs(interp, 1, objv, "?BOOLEAN?"); return TCL_ERROR; } if( objc==2 ){ int bNew; if( Tcl_GetBooleanFromObj(interp, objv[1], &bNew) ) return TCL_ERROR; sqlite3_fts5_may_be_corrupt = bNew; } Tcl_SetObjResult(interp, Tcl_NewIntObj(bOld)); #endif return TCL_OK; } static unsigned int f5t_fts5HashKey(int nSlot, const char *p, int n){ int i; unsigned int h = 13; |
︙ | ︙ |
Changes to ext/fts5/fts5_test_mi.c.
︙ | ︙ | |||
305 306 307 308 309 310 311 | const char *zArg /* Matchinfo flag string */ ){ Fts5MatchinfoCtx *p; int nCol; int nPhrase; int i; int nInt; | | | | 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 | const char *zArg /* Matchinfo flag string */ ){ Fts5MatchinfoCtx *p; int nCol; int nPhrase; int i; int nInt; sqlite3_int64 nByte; int rc; nCol = pApi->xColumnCount(pFts); nPhrase = pApi->xPhraseCount(pFts); nInt = 0; for(i=0; zArg[i]; i++){ int n = fts5MatchinfoFlagsize(nCol, nPhrase, zArg[i]); if( n<0 ){ char *zErr = sqlite3_mprintf("unrecognized matchinfo flag: %c", zArg[i]); sqlite3_result_error(pCtx, zErr, -1); sqlite3_free(zErr); return 0; } nInt += n; } nByte = sizeof(Fts5MatchinfoCtx) /* The struct itself */ + sizeof(u32) * nInt /* The p->aRet[] array */ + (i+1); /* The p->zArg string */ p = (Fts5MatchinfoCtx*)sqlite3_malloc64(nByte); if( p==0 ){ sqlite3_result_error_nomem(pCtx); return 0; } memset(p, 0, nByte); p->nCol = nCol; |
︙ | ︙ |
Changes to ext/fts5/fts5_test_tok.c.
︙ | ︙ | |||
133 134 135 136 137 138 139 | int nByte = 0; char **azDequote; for(i=0; i<argc; i++){ nByte += (int)(strlen(argv[i]) + 1); } | | | 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 | int nByte = 0; char **azDequote; for(i=0; i<argc; i++){ nByte += (int)(strlen(argv[i]) + 1); } *pazDequote = azDequote = sqlite3_malloc64(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; |
︙ | ︙ | |||
207 208 209 210 211 212 213 | const char *zModule = 0; if( nDequote>0 ){ zModule = azDequote[0]; } rc = pApi->xFindTokenizer(pApi, zModule, &pTokCtx, &pTab->tok); if( rc==SQLITE_OK ){ | | | 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 | const char *zModule = 0; if( nDequote>0 ){ zModule = azDequote[0]; } rc = pApi->xFindTokenizer(pApi, zModule, &pTokCtx, &pTab->tok); if( rc==SQLITE_OK ){ const char **azArg = (nDequote>1 ? (const char **)&azDequote[1] : 0); int nArg = nDequote>0 ? nDequote-1 : 0; rc = pTab->tok.xCreate(pTokCtx, azArg, nArg, &pTab->pTok); } } if( rc!=SQLITE_OK ){ sqlite3_free(pTab); |
︙ | ︙ | |||
331 332 333 334 335 336 337 | ){ Fts5tokCursor *pCsr = (Fts5tokCursor*)pCtx; Fts5tokRow *pRow; if( (pCsr->nRow & (pCsr->nRow-1))==0 ){ int nNew = pCsr->nRow ? pCsr->nRow*2 : 32; Fts5tokRow *aNew; | | | 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 | ){ Fts5tokCursor *pCsr = (Fts5tokCursor*)pCtx; Fts5tokRow *pRow; if( (pCsr->nRow & (pCsr->nRow-1))==0 ){ int nNew = pCsr->nRow ? pCsr->nRow*2 : 32; Fts5tokRow *aNew; aNew = (Fts5tokRow*)sqlite3_realloc64(pCsr->aRow, nNew*sizeof(Fts5tokRow)); if( aNew==0 ) return SQLITE_NOMEM; memset(&aNew[pCsr->nRow], 0, sizeof(Fts5tokRow)*(nNew-pCsr->nRow)); pCsr->aRow = aNew; } pRow = &pCsr->aRow[pCsr->nRow]; pRow->iStart = iStart; |
︙ | ︙ | |||
374 375 376 377 378 379 380 | 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{ | | | 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 | 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{ if( nByte>0 ) memcpy(pCsr->zInput, zByte, nByte); pCsr->zInput[nByte] = 0; rc = pTab->tok.xTokenize( pTab->pTok, (void*)pCsr, 0, zByte, nByte, fts5tokCb ); } } |
︙ | ︙ |
Changes to ext/fts5/fts5_tokenize.c.
︙ | ︙ | |||
148 149 150 151 152 153 154 | ie++; } /* Fold to lower case */ nByte = ie-is; if( nByte>nFold ){ if( pFold!=aFold ) sqlite3_free(pFold); | | | 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 | ie++; } /* Fold to lower case */ nByte = ie-is; if( nByte>nFold ){ if( pFold!=aFold ) sqlite3_free(pFold); pFold = sqlite3_malloc64((sqlite3_int64)nByte*2); if( pFold==0 ){ rc = SQLITE_NOMEM; break; } nFold = nByte*2; } asciiFold(pFold, &pText[is], nByte); |
︙ | ︙ | |||
252 253 254 255 256 257 258 | int bTokenChars /* 1 for 'tokenchars', 0 for 'separators' */ ){ int rc = SQLITE_OK; int n = (int)strlen(z); int *aNew; if( n>0 ){ | | > | | | 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 | int bTokenChars /* 1 for 'tokenchars', 0 for 'separators' */ ){ int rc = SQLITE_OK; int n = (int)strlen(z); int *aNew; if( n>0 ){ aNew = (int*)sqlite3_realloc64(p->aiException, (n+p->nException)*sizeof(int)); if( aNew ){ int nNew = p->nException; const unsigned char *zCsr = (const unsigned char*)z; const unsigned char *zTerm = (const unsigned char*)&z[n]; while( zCsr<zTerm ){ u32 iCode; int bToken; READ_UTF8(zCsr, zTerm, iCode); if( iCode<128 ){ p->aTokenChar[iCode] = (unsigned char)bTokenChars; }else{ bToken = p->aCategory[sqlite3Fts5UnicodeCategory(iCode)]; assert( (bToken==0 || bToken==1) ); assert( (bTokenChars==0 || bTokenChars==1) ); if( bToken!=bTokenChars && sqlite3Fts5UnicodeIsdiacritic(iCode)==0 ){ int i; for(i=0; i<nNew; i++){ if( (u32)aNew[i]>iCode ) break; } memmove(&aNew[i+1], &aNew[i], (nNew-i)*sizeof(int)); aNew[i] = iCode; nNew++; } } } |
︙ | ︙ | |||
364 365 366 367 368 369 370 | if( p ){ const char *zCat = "L* N* Co"; int i; memset(p, 0, sizeof(Unicode61Tokenizer)); p->eRemoveDiacritic = FTS5_REMOVE_DIACRITICS_SIMPLE; p->nFold = 64; | | | 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 | if( p ){ const char *zCat = "L* N* Co"; int i; memset(p, 0, sizeof(Unicode61Tokenizer)); p->eRemoveDiacritic = FTS5_REMOVE_DIACRITICS_SIMPLE; p->nFold = 64; p->aFold = sqlite3_malloc64(p->nFold * sizeof(char)); if( p->aFold==0 ){ rc = SQLITE_NOMEM; } /* Search for a "categories" argument */ for(i=0; rc==SQLITE_OK && i<nArg; i+=2){ if( 0==sqlite3_stricmp(azArg[i], "categories") ){ |
︙ | ︙ | |||
425 426 427 428 429 430 431 | /* ** Return true if, for the purposes of tokenizing with the tokenizer ** passed as the first argument, codepoint iCode is considered a token ** character (not a separator). */ static int fts5UnicodeIsAlnum(Unicode61Tokenizer *p, int iCode){ return ( | | | 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 | /* ** Return true if, for the purposes of tokenizing with the tokenizer ** passed as the first argument, codepoint iCode is considered a token ** character (not a separator). */ static int fts5UnicodeIsAlnum(Unicode61Tokenizer *p, int iCode){ return ( p->aCategory[sqlite3Fts5UnicodeCategory((u32)iCode)] ^ fts5UnicodeIsException(p, iCode) ); } static int fts5UnicodeTokenize( Fts5Tokenizer *pTokenizer, void *pCtx, |
︙ | ︙ | |||
454 455 456 457 458 459 460 | const char *pEnd = &aFold[nFold-6]; UNUSED_PARAM(iUnused); /* Each iteration of this loop gobbles up a contiguous run of separators, ** then the next token. */ while( rc==SQLITE_OK ){ | | | 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 | const char *pEnd = &aFold[nFold-6]; UNUSED_PARAM(iUnused); /* Each iteration of this loop gobbles up a contiguous run of separators, ** then the next token. */ while( rc==SQLITE_OK ){ u32 iCode; /* non-ASCII codepoint read from input */ char *zOut = aFold; int is; int ie; /* Skip any separator characters. */ while( 1 ){ if( zCsr>=zTerm ) goto tokenize_done; |
︙ | ︙ | |||
486 487 488 489 490 491 492 | /* Run through the tokenchars. Fold them into the output buffer along ** the way. */ while( zCsr<zTerm ){ /* Grow the output buffer so that there is sufficient space to fit the ** largest possible utf-8 character. */ if( zOut>pEnd ){ | | | 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 | /* Run through the tokenchars. Fold them into the output buffer along ** the way. */ while( zCsr<zTerm ){ /* Grow the output buffer so that there is sufficient space to fit the ** largest possible utf-8 character. */ if( zOut>pEnd ){ aFold = sqlite3_malloc64((sqlite3_int64)nFold*2); if( aFold==0 ){ rc = SQLITE_NOMEM; goto tokenize_done; } zOut = &aFold[zOut - p->aFold]; memcpy(aFold, p->aFold, nFold); sqlite3_free(p->aFold); |
︙ | ︙ | |||
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 | sCtx.xToken = xToken; sCtx.pCtx = pCtx; sCtx.aBuf = p->aBuf; return p->tokenizer.xTokenize( p->pTokenizer, (void*)&sCtx, flags, pText, nText, fts5PorterCb ); } /* ** Register all built-in tokenizers with FTS5. */ int sqlite3Fts5TokenizerInit(fts5_api *pApi){ struct BuiltinTokenizer { const char *zName; fts5_tokenizer x; } aBuiltin[] = { { "unicode61", {fts5UnicodeCreate, fts5UnicodeDelete, fts5UnicodeTokenize}}, { "ascii", {fts5AsciiCreate, fts5AsciiDelete, fts5AsciiTokenize }}, { "porter", {fts5PorterCreate, fts5PorterDelete, fts5PorterTokenize }}, }; int rc = SQLITE_OK; /* Return code */ int i; /* To iterate through builtin functions */ for(i=0; rc==SQLITE_OK && i<ArraySize(aBuiltin); i++){ rc = pApi->xCreateTokenizer(pApi, aBuiltin[i].zName, (void*)pApi, &aBuiltin[i].x, 0 ); } return rc; } | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > < < | 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 | sCtx.xToken = xToken; sCtx.pCtx = pCtx; sCtx.aBuf = p->aBuf; return p->tokenizer.xTokenize( p->pTokenizer, (void*)&sCtx, flags, pText, nText, fts5PorterCb ); } /************************************************************************** ** Start of trigram implementation. */ typedef struct TrigramTokenizer TrigramTokenizer; struct TrigramTokenizer { int bFold; /* True to fold to lower-case */ }; /* ** Free a trigram tokenizer. */ static void fts5TriDelete(Fts5Tokenizer *p){ sqlite3_free(p); } /* ** Allocate a trigram tokenizer. */ static int fts5TriCreate( void *pUnused, const char **azArg, int nArg, Fts5Tokenizer **ppOut ){ int rc = SQLITE_OK; TrigramTokenizer *pNew = (TrigramTokenizer*)sqlite3_malloc(sizeof(*pNew)); UNUSED_PARAM(pUnused); if( pNew==0 ){ rc = SQLITE_NOMEM; }else{ int i; pNew->bFold = 1; for(i=0; rc==SQLITE_OK && i<nArg; i+=2){ const char *zArg = azArg[i+1]; if( 0==sqlite3_stricmp(azArg[i], "case_sensitive") ){ if( (zArg[0]!='0' && zArg[0]!='1') || zArg[1] ){ rc = SQLITE_ERROR; }else{ pNew->bFold = (zArg[0]=='0'); } }else{ rc = SQLITE_ERROR; } } if( rc!=SQLITE_OK ){ fts5TriDelete((Fts5Tokenizer*)pNew); pNew = 0; } } *ppOut = (Fts5Tokenizer*)pNew; return rc; } /* ** Trigram tokenizer tokenize routine. */ static int fts5TriTokenize( Fts5Tokenizer *pTok, void *pCtx, int unusedFlags, const char *pText, int nText, int (*xToken)(void*, int, const char*, int, int, int) ){ TrigramTokenizer *p = (TrigramTokenizer*)pTok; int rc = SQLITE_OK; char aBuf[32]; const unsigned char *zIn = (const unsigned char*)pText; const unsigned char *zEof = &zIn[nText]; u32 iCode; UNUSED_PARAM(unusedFlags); while( 1 ){ char *zOut = aBuf; int iStart = zIn - (const unsigned char*)pText; const unsigned char *zNext; READ_UTF8(zIn, zEof, iCode); if( iCode==0 ) break; zNext = zIn; if( zIn<zEof ){ if( p->bFold ) iCode = sqlite3Fts5UnicodeFold(iCode, 0); WRITE_UTF8(zOut, iCode); READ_UTF8(zIn, zEof, iCode); if( iCode==0 ) break; }else{ break; } if( zIn<zEof ){ if( p->bFold ) iCode = sqlite3Fts5UnicodeFold(iCode, 0); WRITE_UTF8(zOut, iCode); READ_UTF8(zIn, zEof, iCode); if( iCode==0 ) break; if( p->bFold ) iCode = sqlite3Fts5UnicodeFold(iCode, 0); WRITE_UTF8(zOut, iCode); }else{ break; } rc = xToken(pCtx, 0, aBuf, zOut-aBuf, iStart, iStart + zOut-aBuf); if( rc!=SQLITE_OK ) break; zIn = zNext; } return rc; } /* ** Argument xCreate is a pointer to a constructor function for a tokenizer. ** pTok is a tokenizer previously created using the same method. This function ** returns one of FTS5_PATTERN_NONE, FTS5_PATTERN_LIKE or FTS5_PATTERN_GLOB ** indicating the style of pattern matching that the tokenizer can support. ** In practice, this is: ** ** "trigram" tokenizer, case_sensitive=1 - FTS5_PATTERN_GLOB ** "trigram" tokenizer, case_sensitive=0 (the default) - FTS5_PATTERN_LIKE ** all other tokenizers - FTS5_PATTERN_NONE */ int sqlite3Fts5TokenizerPattern( int (*xCreate)(void*, const char**, int, Fts5Tokenizer**), Fts5Tokenizer *pTok ){ if( xCreate==fts5TriCreate ){ TrigramTokenizer *p = (TrigramTokenizer*)pTok; return p->bFold ? FTS5_PATTERN_LIKE : FTS5_PATTERN_GLOB; } return FTS5_PATTERN_NONE; } /* ** Register all built-in tokenizers with FTS5. */ int sqlite3Fts5TokenizerInit(fts5_api *pApi){ struct BuiltinTokenizer { const char *zName; fts5_tokenizer x; } aBuiltin[] = { { "unicode61", {fts5UnicodeCreate, fts5UnicodeDelete, fts5UnicodeTokenize}}, { "ascii", {fts5AsciiCreate, fts5AsciiDelete, fts5AsciiTokenize }}, { "porter", {fts5PorterCreate, fts5PorterDelete, fts5PorterTokenize }}, { "trigram", {fts5TriCreate, fts5TriDelete, fts5TriTokenize}}, }; int rc = SQLITE_OK; /* Return code */ int i; /* To iterate through builtin functions */ for(i=0; rc==SQLITE_OK && i<ArraySize(aBuiltin); i++){ rc = pApi->xCreateTokenizer(pApi, aBuiltin[i].zName, (void*)pApi, &aBuiltin[i].x, 0 ); } return rc; } |
Changes to ext/fts5/fts5_unicode2.c.
1 | /* | | | 1 2 3 4 5 6 7 8 9 | /* ** 2012-05-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. |
︙ | ︙ | |||
43 44 45 46 47 48 49 | 61726, 61784, 61800, 61816, 61836, 61880, 61896, 61914, 61948, 61998, 62062, 62122, 62154, 62184, 62200, 62218, 62252, 62302, 62364, 62410, 62442, 62478, 62536, 62554, 62584, 62604, 62640, 62648, 62656, 62664, 62730, 62766, 62830, 62890, 62924, 62974, 63032, 63050, 63082, 63118, 63182, 63242, 63274, 63310, 63368, 63390, }; | | | | | 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 | 61726, 61784, 61800, 61816, 61836, 61880, 61896, 61914, 61948, 61998, 62062, 62122, 62154, 62184, 62200, 62218, 62252, 62302, 62364, 62410, 62442, 62478, 62536, 62554, 62584, 62604, 62640, 62648, 62656, 62664, 62730, 62766, 62830, 62890, 62924, 62974, 63032, 63050, 63082, 63118, 63182, 63242, 63274, 63310, 63368, 63390, }; #define HIBIT ((unsigned char)0x80) unsigned char aChar[] = { '\0', 'a', 'c', 'e', 'i', 'n', 'o', 'u', 'y', 'y', 'a', 'c', 'd', 'e', 'e', 'g', 'h', 'i', 'j', 'k', 'l', 'n', 'o', 'r', 's', 't', 'u', 'u', 'w', 'y', 'z', 'o', 'u', 'a', 'i', 'o', 'u', 'u'|HIBIT, 'a'|HIBIT, 'g', 'k', 'o', 'o'|HIBIT, 'j', 'g', 'n', 'a'|HIBIT, 'a', 'e', 'i', 'o', 'r', 'u', 's', 't', 'h', 'a', 'e', 'o'|HIBIT, 'o', 'o'|HIBIT, 'y', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', 'a', 'b', 'c'|HIBIT, 'd', 'd', 'e'|HIBIT, 'e', 'e'|HIBIT, 'f', 'g', 'h', 'h', 'i', 'i'|HIBIT, 'k', 'l', 'l'|HIBIT, 'l', 'm', 'n', 'o'|HIBIT, 'p', 'r', 'r'|HIBIT, 'r', 's', 's'|HIBIT, 't', 'u', 'u'|HIBIT, 'v', 'w', 'w', 'x', 'y', 'z', 'h', 't', 'w', 'y', 'a', 'a'|HIBIT, 'a'|HIBIT, 'a'|HIBIT, 'e', 'e'|HIBIT, 'e'|HIBIT, 'i', 'o', 'o'|HIBIT, 'o'|HIBIT, 'o'|HIBIT, 'u', 'u'|HIBIT, 'u'|HIBIT, 'y', }; unsigned int key = (((unsigned int)c)<<3) | 0x00000007; int iRes = 0; int iHi = sizeof(aDia)/sizeof(aDia[0]) - 1; int iLo = 0; while( iHi>=iLo ){ |
︙ | ︙ | |||
96 97 98 99 100 101 102 | ** is a diacritical modifier character. */ int sqlite3Fts5UnicodeIsdiacritic(int c){ unsigned int mask0 = 0x08029FDF; unsigned int mask1 = 0x000361F8; if( c<768 || c>817 ) return 0; return (c < 768+32) ? | | | | 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 | ** is a diacritical modifier character. */ int sqlite3Fts5UnicodeIsdiacritic(int c){ unsigned int mask0 = 0x08029FDF; unsigned int mask1 = 0x000361F8; if( c<768 || c>817 ) return 0; return (c < 768+32) ? (mask0 & ((unsigned int)1 << (c-768))) : (mask1 & ((unsigned int)1 << (c-768-32))); } /* ** Interpret the argument as a unicode codepoint. If the codepoint ** is an upper case character that has a lower case equivalent, ** return the codepoint corresponding to the lower case version. |
︙ | ︙ | |||
244 245 246 247 248 249 250 251 252 253 254 255 256 257 | else if( c>=66560 && c<66600 ){ ret = c + 40; } return ret; } int sqlite3Fts5UnicodeCatParse(const char *zCat, u8 *aArray){ aArray[0] = 1; switch( zCat[0] ){ case 'C': switch( zCat[1] ){ case 'c': aArray[1] = 1; break; | > | 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 | else if( c>=66560 && c<66600 ){ ret = c + 40; } return ret; } int sqlite3Fts5UnicodeCatParse(const char *zCat, u8 *aArray){ aArray[0] = 1; switch( zCat[0] ){ case 'C': switch( zCat[1] ){ case 'c': aArray[1] = 1; break; |
︙ | ︙ | |||
726 727 728 729 730 731 732 | 89, 1434, 3226, 506, 474, 506, 506, 367, 1018, 1946, 1402, 954, 1402, 314, 90, 1082, 218, 2266, 666, 1210, 186, 570, 2042, 58, 5850, 154, 2010, 154, 794, 2266, 378, 2266, 3738, 39, 39, 39, 39, 39, 39, 17351, 34, 3074, 7692, 63, 63, }; | | | 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 | 89, 1434, 3226, 506, 474, 506, 506, 367, 1018, 1946, 1402, 954, 1402, 314, 90, 1082, 218, 2266, 666, 1210, 186, 570, 2042, 58, 5850, 154, 2010, 154, 794, 2266, 378, 2266, 3738, 39, 39, 39, 39, 39, 39, 17351, 34, 3074, 7692, 63, 63, }; int sqlite3Fts5UnicodeCategory(u32 iCode) { int iRes = -1; int iHi; int iLo; int ret; u16 iKey; if( iCode>=(1<<20) ){ |
︙ | ︙ | |||
764 765 766 767 768 769 770 | void sqlite3Fts5UnicodeAscii(u8 *aArray, u8 *aAscii){ int i = 0; int iTbl = 0; while( i<128 ){ int bToken = aArray[ aFts5UnicodeData[iTbl] & 0x1F ]; int n = (aFts5UnicodeData[iTbl] >> 5) + i; for(; i<128 && i<n; i++){ | | > > | 765 766 767 768 769 770 771 772 773 774 775 776 777 778 | void sqlite3Fts5UnicodeAscii(u8 *aArray, u8 *aAscii){ int i = 0; int iTbl = 0; while( i<128 ){ int bToken = aArray[ aFts5UnicodeData[iTbl] & 0x1F ]; int n = (aFts5UnicodeData[iTbl] >> 5) + i; for(; i<128 && i<n; i++){ aAscii[i] = (u8)bToken; } iTbl++; } aAscii[0] = 0; /* 0x00 is never a token character */ } |
Changes to ext/fts5/fts5_varint.c.
︙ | ︙ | |||
72 73 74 75 76 77 78 | ** routine. */ { u64 v64; u8 n; p -= 2; n = sqlite3Fts5GetVarint(p, &v64); | | | 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 | ** routine. */ { u64 v64; u8 n; p -= 2; n = sqlite3Fts5GetVarint(p, &v64); *v = ((u32)v64) & 0x7FFFFFFF; assert( n>3 && n<=9 ); return n; } } /* |
︙ | ︙ | |||
338 339 340 341 342 343 344 | #endif assert( iVal>=(1 << 7) ); if( iVal<(1 << 14) ) return 2; if( iVal<(1 << 21) ) return 3; if( iVal<(1 << 28) ) return 4; return 5; } | < | 338 339 340 341 342 343 344 | #endif assert( iVal>=(1 << 7) ); if( iVal<(1 << 14) ) return 2; if( iVal<(1 << 21) ) return 3; if( iVal<(1 << 28) ) return 4; return 5; } |
Changes to ext/fts5/fts5_vocab.c.
︙ | ︙ | |||
46 47 48 49 50 51 52 53 54 55 56 57 | struct Fts5VocabTable { sqlite3_vtab base; char *zFts5Tbl; /* Name of fts5 table */ char *zFts5Db; /* Db containing fts5 table */ sqlite3 *db; /* Database handle */ Fts5Global *pGlobal; /* FTS5 global object for this database */ int eType; /* FTS5_VOCAB_COL, ROW or INSTANCE */ }; struct Fts5VocabCursor { sqlite3_vtab_cursor base; sqlite3_stmt *pStmt; /* Statement holding lock on pIndex */ | > | > < | 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 | struct Fts5VocabTable { sqlite3_vtab base; char *zFts5Tbl; /* Name of fts5 table */ char *zFts5Db; /* Db containing fts5 table */ sqlite3 *db; /* Database handle */ Fts5Global *pGlobal; /* FTS5 global object for this database */ int eType; /* FTS5_VOCAB_COL, ROW or INSTANCE */ unsigned bBusy; /* True if busy */ }; struct Fts5VocabCursor { sqlite3_vtab_cursor base; sqlite3_stmt *pStmt; /* Statement holding lock on pIndex */ Fts5Table *pFts5; /* Associated FTS5 table */ int bEof; /* True if this cursor is at EOF */ Fts5IndexIter *pIter; /* Term/rowid iterator object */ void *pStruct; /* From sqlite3Fts5StructureRef() */ int nLeTerm; /* Size of zLeTerm in bytes */ char *zLeTerm; /* (term <= $zLeTerm) paramater, or NULL */ /* These are used by 'col' tables only */ int iCol; i64 *aCnt; i64 *aDoc; /* Output values used by all tables. */ i64 rowid; /* This table's current rowid value */ Fts5Buffer term; /* Current value of 'term' column */ |
︙ | ︙ | |||
323 324 325 326 327 328 329 | ** Implementation of xOpen method. */ static int fts5VocabOpenMethod( sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCsr ){ Fts5VocabTable *pTab = (Fts5VocabTable*)pVTab; | | < > > > > > > > | > | > | | | | | | | > > > | | < | > > > | 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 | ** Implementation of xOpen method. */ static int fts5VocabOpenMethod( sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCsr ){ Fts5VocabTable *pTab = (Fts5VocabTable*)pVTab; Fts5Table *pFts5 = 0; Fts5VocabCursor *pCsr = 0; int rc = SQLITE_OK; sqlite3_stmt *pStmt = 0; char *zSql = 0; if( pTab->bBusy ){ pVTab->zErrMsg = sqlite3_mprintf( "recursive definition for %s.%s", pTab->zFts5Db, pTab->zFts5Tbl ); return SQLITE_ERROR; } zSql = sqlite3Fts5Mprintf(&rc, "SELECT t.%Q FROM %Q.%Q AS t WHERE t.%Q MATCH '*id'", pTab->zFts5Tbl, pTab->zFts5Db, pTab->zFts5Tbl, pTab->zFts5Tbl ); if( zSql ){ rc = sqlite3_prepare_v2(pTab->db, zSql, -1, &pStmt, 0); } sqlite3_free(zSql); assert( rc==SQLITE_OK || pStmt==0 ); if( rc==SQLITE_ERROR ) rc = SQLITE_OK; pTab->bBusy = 1; if( pStmt && sqlite3_step(pStmt)==SQLITE_ROW ){ i64 iId = sqlite3_column_int64(pStmt, 0); pFts5 = sqlite3Fts5TableFromCsrid(pTab->pGlobal, iId); } pTab->bBusy = 0; if( rc==SQLITE_OK ){ if( pFts5==0 ){ rc = sqlite3_finalize(pStmt); pStmt = 0; if( rc==SQLITE_OK ){ pVTab->zErrMsg = sqlite3_mprintf( "no such fts5 table: %s.%s", pTab->zFts5Db, pTab->zFts5Tbl ); rc = SQLITE_ERROR; } }else{ rc = sqlite3Fts5FlushToDisk(pFts5); } } if( rc==SQLITE_OK ){ i64 nByte = pFts5->pConfig->nCol * sizeof(i64)*2 + sizeof(Fts5VocabCursor); pCsr = (Fts5VocabCursor*)sqlite3Fts5MallocZero(&rc, nByte); } if( pCsr ){ pCsr->pFts5 = pFts5; pCsr->pStmt = pStmt; pCsr->aCnt = (i64*)&pCsr[1]; pCsr->aDoc = &pCsr->aCnt[pFts5->pConfig->nCol]; }else{ sqlite3_finalize(pStmt); } *ppCsr = (sqlite3_vtab_cursor*)pCsr; return rc; } static void fts5VocabResetCursor(Fts5VocabCursor *pCsr){ pCsr->rowid = 0; sqlite3Fts5IterClose(pCsr->pIter); sqlite3Fts5StructureRelease(pCsr->pStruct); pCsr->pStruct = 0; pCsr->pIter = 0; sqlite3_free(pCsr->zLeTerm); pCsr->nLeTerm = -1; pCsr->zLeTerm = 0; pCsr->bEof = 0; } /* ** Close the cursor. For additional information see the documentation ** on the xClose method of the virtual table interface. */ static int fts5VocabCloseMethod(sqlite3_vtab_cursor *pCursor){ |
︙ | ︙ | |||
421 422 423 424 425 426 427 | sqlite3Fts5BufferSet(&rc, &pCsr->term, nTerm, (const u8*)zTerm); } return rc; } static int fts5VocabInstanceNext(Fts5VocabCursor *pCsr){ | | | 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 | sqlite3Fts5BufferSet(&rc, &pCsr->term, nTerm, (const u8*)zTerm); } return rc; } static int fts5VocabInstanceNext(Fts5VocabCursor *pCsr){ int eDetail = pCsr->pFts5->pConfig->eDetail; int rc = SQLITE_OK; Fts5IndexIter *pIter = pCsr->pIter; i64 *pp = &pCsr->iInstPos; int *po = &pCsr->iInstOff; assert( sqlite3Fts5IterEof(pIter)==0 ); assert( pCsr->bEof==0 ); |
︙ | ︙ | |||
455 456 457 458 459 460 461 | /* ** Advance the cursor to the next row in the table. */ static int fts5VocabNextMethod(sqlite3_vtab_cursor *pCursor){ Fts5VocabCursor *pCsr = (Fts5VocabCursor*)pCursor; Fts5VocabTable *pTab = (Fts5VocabTable*)pCursor->pVtab; | < | > > > > | | 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 | /* ** Advance the cursor to the next row in the table. */ static int fts5VocabNextMethod(sqlite3_vtab_cursor *pCursor){ Fts5VocabCursor *pCsr = (Fts5VocabCursor*)pCursor; Fts5VocabTable *pTab = (Fts5VocabTable*)pCursor->pVtab; int nCol = pCsr->pFts5->pConfig->nCol; int rc; rc = sqlite3Fts5StructureTest(pCsr->pFts5->pIndex, pCsr->pStruct); if( rc!=SQLITE_OK ) return rc; pCsr->rowid++; if( pTab->eType==FTS5_VOCAB_INSTANCE ){ return fts5VocabInstanceNext(pCsr); } if( pTab->eType==FTS5_VOCAB_COL ){ for(pCsr->iCol++; pCsr->iCol<nCol; pCsr->iCol++){ if( pCsr->aDoc[pCsr->iCol] ) break; } } if( pTab->eType!=FTS5_VOCAB_COL || pCsr->iCol>=nCol ){ if( sqlite3Fts5IterEof(pCsr->pIter) ){ pCsr->bEof = 1; }else{ const char *zTerm; int nTerm; zTerm = sqlite3Fts5IterTerm(pCsr->pIter, &nTerm); assert( nTerm>=0 ); if( pCsr->nLeTerm>=0 ){ int nCmp = MIN(nTerm, pCsr->nLeTerm); int bCmp = memcmp(pCsr->zLeTerm, zTerm, nCmp); if( bCmp<0 || (bCmp==0 && pCsr->nLeTerm<nTerm) ){ pCsr->bEof = 1; return SQLITE_OK; } } sqlite3Fts5BufferSet(&rc, &pCsr->term, nTerm, (const u8*)zTerm); memset(pCsr->aCnt, 0, nCol * sizeof(i64)); memset(pCsr->aDoc, 0, nCol * sizeof(i64)); pCsr->iCol = 0; assert( pTab->eType==FTS5_VOCAB_COL || pTab->eType==FTS5_VOCAB_ROW ); while( rc==SQLITE_OK ){ int eDetail = pCsr->pFts5->pConfig->eDetail; const u8 *pPos; int nPos; /* Position list */ i64 iPos = 0; /* 64-bit position read from poslist */ int iOff = 0; /* Current offset within position list */ pPos = pCsr->pIter->pData; nPos = pCsr->pIter->nData; |
︙ | ︙ | |||
517 518 519 520 521 522 523 | break; case FTS5_VOCAB_COL: if( eDetail==FTS5_DETAIL_FULL ){ int iCol = -1; while( 0==sqlite3Fts5PoslistNext64(pPos, nPos, &iOff, &iPos) ){ int ii = FTS5_POS2COLUMN(iPos); | < > | 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 | break; case FTS5_VOCAB_COL: if( eDetail==FTS5_DETAIL_FULL ){ int iCol = -1; while( 0==sqlite3Fts5PoslistNext64(pPos, nPos, &iOff, &iPos) ){ int ii = FTS5_POS2COLUMN(iPos); if( iCol!=ii ){ if( ii>=nCol ){ rc = FTS5_CORRUPT; break; } pCsr->aDoc[ii]++; iCol = ii; } pCsr->aCnt[ii]++; } }else if( eDetail==FTS5_DETAIL_COLUMNS ){ while( 0==sqlite3Fts5PoslistNext64(pPos, nPos, &iOff,&iPos) ){ assert_nc( iPos>=0 && iPos<nCol ); if( iPos>=nCol ){ rc = FTS5_CORRUPT; break; |
︙ | ︙ | |||
554 555 556 557 558 559 560 | if( rc==SQLITE_OK ){ rc = sqlite3Fts5IterNextScan(pCsr->pIter); } if( pTab->eType==FTS5_VOCAB_INSTANCE ) break; if( rc==SQLITE_OK ){ zTerm = sqlite3Fts5IterTerm(pCsr->pIter, &nTerm); | | > > | | > > | 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 | if( rc==SQLITE_OK ){ rc = sqlite3Fts5IterNextScan(pCsr->pIter); } if( pTab->eType==FTS5_VOCAB_INSTANCE ) break; if( rc==SQLITE_OK ){ zTerm = sqlite3Fts5IterTerm(pCsr->pIter, &nTerm); if( nTerm!=pCsr->term.n || (nTerm>0 && memcmp(zTerm, pCsr->term.p, nTerm)) ){ break; } if( sqlite3Fts5IterEof(pCsr->pIter) ) break; } } } } if( rc==SQLITE_OK && pCsr->bEof==0 && pTab->eType==FTS5_VOCAB_COL ){ for(/* noop */; pCsr->iCol<nCol && pCsr->aDoc[pCsr->iCol]==0; pCsr->iCol++); if( pCsr->iCol==nCol ){ rc = FTS5_CORRUPT; } } return rc; } /* ** This is the xFilter implementation for the virtual table. */ |
︙ | ︙ | |||
612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 | }else{ if( pGe ){ zTerm = (const char *)sqlite3_value_text(pGe); nTerm = sqlite3_value_bytes(pGe); } if( pLe ){ const char *zCopy = (const char *)sqlite3_value_text(pLe); pCsr->nLeTerm = sqlite3_value_bytes(pLe); pCsr->zLeTerm = sqlite3_malloc(pCsr->nLeTerm+1); if( pCsr->zLeTerm==0 ){ rc = SQLITE_NOMEM; }else{ memcpy(pCsr->zLeTerm, zCopy, pCsr->nLeTerm+1); } } } if( rc==SQLITE_OK ){ | > > | > > > | < | > | 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 | }else{ if( pGe ){ zTerm = (const char *)sqlite3_value_text(pGe); nTerm = sqlite3_value_bytes(pGe); } if( pLe ){ const char *zCopy = (const char *)sqlite3_value_text(pLe); if( zCopy==0 ) zCopy = ""; pCsr->nLeTerm = sqlite3_value_bytes(pLe); pCsr->zLeTerm = sqlite3_malloc(pCsr->nLeTerm+1); if( pCsr->zLeTerm==0 ){ rc = SQLITE_NOMEM; }else{ memcpy(pCsr->zLeTerm, zCopy, pCsr->nLeTerm+1); } } } if( rc==SQLITE_OK ){ Fts5Index *pIndex = pCsr->pFts5->pIndex; rc = sqlite3Fts5IndexQuery(pIndex, zTerm, nTerm, f, 0, &pCsr->pIter); if( rc==SQLITE_OK ){ pCsr->pStruct = sqlite3Fts5StructureRef(pIndex); } } if( rc==SQLITE_OK && eType==FTS5_VOCAB_INSTANCE ){ rc = fts5VocabInstanceNewTerm(pCsr); } if( rc==SQLITE_OK && !pCsr->bEof && (eType!=FTS5_VOCAB_INSTANCE || pCsr->pFts5->pConfig->eDetail!=FTS5_DETAIL_NONE) ){ rc = fts5VocabNextMethod(pCursor); } return rc; } |
︙ | ︙ | |||
653 654 655 656 657 658 659 | static int fts5VocabColumnMethod( 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 */ ){ Fts5VocabCursor *pCsr = (Fts5VocabCursor*)pCursor; | | | | 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 | static int fts5VocabColumnMethod( 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 */ ){ Fts5VocabCursor *pCsr = (Fts5VocabCursor*)pCursor; int eDetail = pCsr->pFts5->pConfig->eDetail; int eType = ((Fts5VocabTable*)(pCursor->pVtab))->eType; i64 iVal = 0; if( iCol==0 ){ sqlite3_result_text( pCtx, (const char*)pCsr->term.p, pCsr->term.n, SQLITE_TRANSIENT ); }else if( eType==FTS5_VOCAB_COL ){ assert( iCol==1 || iCol==2 || iCol==3 ); if( iCol==1 ){ if( eDetail!=FTS5_DETAIL_NONE ){ const char *z = pCsr->pFts5->pConfig->azCol[pCsr->iCol]; sqlite3_result_text(pCtx, z, -1, SQLITE_STATIC); } }else if( iCol==2 ){ iVal = pCsr->aDoc[pCsr->iCol]; }else{ iVal = pCsr->aCnt[pCsr->iCol]; } |
︙ | ︙ | |||
693 694 695 696 697 698 699 | case 2: { int ii = -1; if( eDetail==FTS5_DETAIL_FULL ){ ii = FTS5_POS2COLUMN(pCsr->iInstPos); }else if( eDetail==FTS5_DETAIL_COLUMNS ){ ii = (int)pCsr->iInstPos; } | | | | 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 | case 2: { int ii = -1; if( eDetail==FTS5_DETAIL_FULL ){ ii = FTS5_POS2COLUMN(pCsr->iInstPos); }else if( eDetail==FTS5_DETAIL_COLUMNS ){ ii = (int)pCsr->iInstPos; } if( ii>=0 && ii<pCsr->pFts5->pConfig->nCol ){ const char *z = pCsr->pFts5->pConfig->azCol[ii]; sqlite3_result_text(pCtx, z, -1, SQLITE_STATIC); } break; } default: { assert( iCol==3 ); if( eDetail==FTS5_DETAIL_FULL ){ |
︙ | ︙ |
Changes to ext/fts5/test/fts5aa.test.
︙ | ︙ | |||
34 35 36 37 38 39 40 | t1_docsize {CREATE TABLE 't1_docsize'(id INTEGER PRIMARY KEY, sz BLOB)} t1_config {CREATE TABLE 't1_config'(k PRIMARY KEY, v) WITHOUT ROWID} } do_execsql_test 1.1 { DROP TABLE t1; SELECT name, sql FROM sqlite_master; | | < | 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | t1_docsize {CREATE TABLE 't1_docsize'(id INTEGER PRIMARY KEY, sz BLOB)} t1_config {CREATE TABLE 't1_config'(k PRIMARY KEY, v) WITHOUT ROWID} } do_execsql_test 1.1 { DROP TABLE t1; SELECT name, sql FROM sqlite_master; } {} #------------------------------------------------------------------------- # do_execsql_test 2.0 { CREATE VIRTUAL TABLE t1 USING fts5(x, y, detail=%DETAIL%); } |
︙ | ︙ | |||
424 425 426 427 428 429 430 | INSERT INTO n1 VALUES('a b c d'); } proc funk {} { db eval { UPDATE n1_config SET v=50 WHERE k='version' } set fd [db incrblob main n1_data block 10] fconfigure $fd -encoding binary -translation binary | | | 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 | INSERT INTO n1 VALUES('a b c d'); } proc funk {} { db eval { UPDATE n1_config SET v=50 WHERE k='version' } set fd [db incrblob main n1_data block 10] fconfigure $fd -encoding binary -translation binary # puts -nonewline $fd "\x44\x45" close $fd } db func funk funk # This test case corrupts the structure record within the first invocation # of function funk(). Which used to cause the bm25() function to throw an # exception. But since bm25() can now used the cached structure record, |
︙ | ︙ | |||
599 600 601 602 603 604 605 606 607 608 609 610 | } do_execsql_test 23.1 { SELECT * FROM t11, t10 WHERE t11.x = t10.x AND t10.rowid IS NULL; } do_execsql_test 23.2 { SELECT * FROM t11, t10 WHERE t10.rowid IS NULL; } } expand_all_sql db finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | } do_execsql_test 23.1 { SELECT * FROM t11, t10 WHERE t11.x = t10.x AND t10.rowid IS NULL; } do_execsql_test 23.2 { SELECT * FROM t11, t10 WHERE t10.rowid IS NULL; } #------------------------------------------------------------------------- do_execsql_test 24.0 { CREATE VIRTUAL TABLE t12 USING fts5(x, detail=%DETAIL%); INSERT INTO t12 VALUES('aaaa'); } do_execsql_test 24.1 { BEGIN; DELETE FROM t12 WHERE rowid=1; SELECT * FROM t12('aaaa'); INSERT INTO t12 VALUES('aaaa'); END; } do_execsql_test 24.2 { INSERT INTO t12(t12) VALUES('integrity-check'); } do_execsql_test 24.3 { SELECT * FROM t12('aaaa'); } {aaaa} #------------------------------------------------------------------------- do_execsql_test 25.0 { CREATE VIRTUAL TABLE t13 USING fts5(x, detail=%DETAIL%); } do_execsql_test 25.1 { BEGIN; INSERT INTO t13 VALUES('AAAA'); SELECT * FROM t13('BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB*'); END; } } expand_all_sql db finish_test |
Changes to ext/fts5/test/fts5af.test.
︙ | ︙ | |||
161 162 163 164 165 166 167 | INSERT INTO x1 VALUES('xyz', '1 2 3 4 5 6 7 8 9 10 11 12 13'); SELECT snippet(x1, 1, '[', ']', '...', 5) FROM x1('xyz'); } { {1 2 3 4 5...} } do_execsql_test 5.0 { | | > > > > > > | 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 | INSERT INTO x1 VALUES('xyz', '1 2 3 4 5 6 7 8 9 10 11 12 13'); SELECT snippet(x1, 1, '[', ']', '...', 5) FROM x1('xyz'); } { {1 2 3 4 5...} } do_execsql_test 5.0 { CREATE VIRTUAL TABLE p1 USING fts5(a, b, detail=%DETAIL%); INSERT INTO p1 VALUES( 'x a a a a a a a a a a', 'a a a a a a a a a a a a a a a a a a a x' ); } do_execsql_test 5.1 { SELECT snippet(p1, 0, '[', ']', '...', 6) FROM p1('x'); } {{[x] a a a a a...}} do_execsql_test 5.2 { SELECT snippet(p1, 0, '[', ']', NULL, 6) FROM p1('x'); } {{[x] a a a a a}} do_execsql_test 5.3 { SELECT snippet(p1, 0, NULL, ']', '...', 6) FROM p1('x'); } {{x] a a a a a...}} do_execsql_test 5.4 { SELECT snippet(p1, 0, '[', NULL, '...', 6) FROM p1('x'); } {{[x a a a a a...}} do_execsql_test 5.5 { SELECT snippet(p1, 0, '[', NULL, '...', 6) FROM p1('x OR ""'); } {{[x a a a a a...}} do_execsql_test 5.6 { SELECT snippet(p1, 0, '[', NULL, '...', 6) FROM p1('x OR ' || x'DB'); } {{[x a a a a a...}} } ;# foreach_detail_mode finish_test |
Changes to ext/fts5/test/fts5ai.test.
︙ | ︙ | |||
47 48 49 50 51 52 53 54 55 56 57 | ROLLBACK TO one; COMMIT; } do_execsql_test 1.2 { INSERT INTO t1(t1) VALUES('integrity-check'); } } finish_test | > > > > > > | 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | ROLLBACK TO one; COMMIT; } do_execsql_test 1.2 { INSERT INTO t1(t1) VALUES('integrity-check'); } do_execsql_test 1.3 { SAVEPOINT one; INSERT INTO t1 VALUES('v w x'); ROLLBACK TO one; } } finish_test |
Changes to ext/fts5/test/fts5ak.test.
︙ | ︙ | |||
139 140 141 142 143 144 145 146 147 148 149 | -- '[a b c d e]' SELECT highlight(ft, 0, '[', ']') FROM ft WHERE ft MATCH 'a+b+c AND c+d+e'; } { {[a b c] x [c d e]} {[a b c] [c d e]} {[a b c d e]} } } finish_test | > > > > > > > > | 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 | -- '[a b c d e]' SELECT highlight(ft, 0, '[', ']') FROM ft WHERE ft MATCH 'a+b+c AND c+d+e'; } { {[a b c] x [c d e]} {[a b c] [c d e]} {[a b c d e]} } do_execsql_test 3.2 { SELECT highlight(ft, 0, NULL, NULL) FROM ft WHERE ft MATCH 'a+b+c AND c+d+e'; } { {a b c x c d e} {a b c c d e} {a b c d e} } } finish_test |
Changes to ext/fts5/test/fts5aux.test.
︙ | ︙ | |||
271 272 273 274 275 276 277 | do_execsql_test 9.3 { SELECT rowid FROM t1('b:a AND b:b') ORDER BY rank; } { 9 10 } | > > | > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > | 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 | do_execsql_test 9.3 { SELECT rowid FROM t1('b:a AND b:b') ORDER BY rank; } { 9 10 } #------------------------------------------------------------------------- # Test that aux. functions may not be used in aggregate queries. # reset_db do_execsql_test 10.0 { CREATE VIRTUAL TABLE t1 USING fts5(x, y, z); INSERT INTO t1 VALUES('a', 'one two', 1); INSERT INTO t1 VALUES('b', 'two three', 2); INSERT INTO t1 VALUES('c', 'three four', 1); INSERT INTO t1 VALUES('d', 'four five', 2); INSERT INTO t1 VALUES('e', 'five six', 1); INSERT INTO t1 VALUES('f', 'six seven', 2); } proc firstcol {cmd} { $cmd xColumnText 0 } sqlite3_fts5_create_function db firstcol firstcol do_execsql_test 10.1.1 { SELECT firstcol(t1) FROM t1 } {a b c d e f} do_execsql_test 10.1.2 { SELECT group_concat(x, '.') FROM t1 } {a.b.c.d.e.f} do_catchsql_test 10.1.3 { SELECT group_concat(firstcol(t1), '.') FROM t1 } {1 {unable to use function firstcol in the requested context}} do_catchsql_test 10.1.4 { SELECT group_concat(firstcol(t1), '.') FROM t1 GROUP BY rowid } {1 {unable to use function firstcol in the requested context}} finish_test |
Added ext/fts5/test/fts5circref.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 | # 2018 Dec 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 FTS5 module. # source [file join [file dirname [info script]] fts5_common.tcl] set testprefix fts5circref # If SQLITE_ENABLE_FTS5 is not defined, omit this file. ifcapable !fts5 { finish_test return } do_execsql_test 1.0 { CREATE VIRTUAL TABLE tt USING fts5(a); SELECT name FROM sqlite_master ORDER BY 1; } { tt tt_config tt_content tt_data tt_docsize tt_idx } db_save_and_close foreach {tn schema sql} { 1 { CREATE TRIGGER tr1 AFTER INSERT ON tt_config BEGIN SELECT * FROM tt; END; } { INSERT INTO tt(tt, rank) VALUES('usermerge', 4); } 2 { CREATE TRIGGER tr1 AFTER INSERT ON tt_docsize BEGIN SELECT * FROM tt; END; } { INSERT INTO tt(a) VALUES('one two three'); } 3 { CREATE TRIGGER tr1 AFTER INSERT ON tt_content BEGIN SELECT * FROM tt; END; } { INSERT INTO tt(a) VALUES('one two three'); } 4 { CREATE TRIGGER tr1 AFTER INSERT ON tt_data BEGIN SELECT * FROM tt; END; } { INSERT INTO tt(a) VALUES('one two three'); } 5 { CREATE TRIGGER tr1 AFTER INSERT ON tt_idx BEGIN SELECT * FROM tt; END; } { INSERT INTO tt(a) VALUES('one two three'); } } { db_restore_and_reopen do_execsql_test 1.1.$tn.1 $schema do_catchsql_test 1.1.$tn.2 $sql {1 {SQL logic error}} db close } finish_test |
Changes to ext/fts5/test/fts5colset.test.
︙ | ︙ | |||
77 78 79 80 81 82 83 84 85 86 | " $res } do_catchsql_test 4.1 { SELECT * FROM t1 WHERE rowid MATCH 'a' } {1 {unable to use function MATCH in the requested context}} } finish_test | > > > > > > > > > > > > > > > > > > > | 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 | " $res } do_catchsql_test 4.1 { SELECT * FROM t1 WHERE rowid MATCH 'a' } {1 {unable to use function MATCH in the requested context}} } #------------------------------------------------------------------------- # Confirm that the expression parser creates the same expression tree # for: # # {a b} : (abc AND def) # -{c d} : (abc AND def) # # Assuming that the table columns are (a, b, c, d). # do_execsql_test 5.1 { SELECT fts5_expr('abcd AND cdef'); } {{"abcd" AND "cdef"}} do_execsql_test 5.2 { SELECT fts5_expr('{a b} : (abcd AND cdef)', 'a', 'b', 'c', 'd'); } {{{a b} : "abcd" AND {a b} : "cdef"}} do_execsql_test 5.3 { SELECT fts5_expr('-{c d} : (abcd AND cdef)', 'a', 'b', 'c', 'd'); } {{{a b} : "abcd" AND {a b} : "cdef"}} finish_test |
Changes to ext/fts5/test/fts5content.test.
︙ | ︙ | |||
249 250 251 252 253 254 255 | SELECT name FROM sqlite_master; } {xx xx_data xx_idx xx_docsize xx_config} do_execsql_test 6.2 { DROP TABLE xx; SELECT name FROM sqlite_master; } {} | > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | SELECT name FROM sqlite_master; } {xx xx_data xx_idx xx_docsize xx_config} do_execsql_test 6.2 { DROP TABLE xx; SELECT name FROM sqlite_master; } {} #--------------------------------------------------------------------------- # Check that an fts5 table cannot be its own content table. # reset_db do_execsql_test 7.1.1 { CREATE VIRTUAL TABLE t1 USING fts5(a, c=t1 ); INSERT INTO t1( a ) VALUES('abc'); } do_catchsql_test 7.1.2 { SELECT * FROM t1; } {1 {recursively defined fts5 content table}} do_catchsql_test 7.1.3 { SELECT * FROM t1('abc'); } {1 {recursively defined fts5 content table}} do_catchsql_test 7.1.4 { SELECT count(*) FROM t1; } {1 {recursively defined fts5 content table}} do_catchsql_test 7.1.5 { SELECT * FROM t1('abc') ORDER BY rank; } {1 {recursively defined fts5 content table}} reset_db do_execsql_test 7.2.1 { CREATE VIRTUAL TABLE t1 USING fts5(a, c=t2 ); CREATE VIRTUAL TABLE t2 USING fts5(a, c=t1 ); INSERT INTO t1( a ) VALUES('abc'); } do_catchsql_test 7.2.2 { SELECT * FROM t1; } {1 {recursively defined fts5 content table}} do_catchsql_test 7.2.3 { SELECT * FROM t1('abc'); } {1 {recursively defined fts5 content table}} do_catchsql_test 7.2.4 { SELECT count(*) FROM t1; } {1 {recursively defined fts5 content table}} do_catchsql_test 7.2.5 { SELECT * FROM t1('abc') ORDER BY rank; } {1 {recursively defined fts5 content table}} finish_test |
Changes to ext/fts5/test/fts5corrupt3.test.
more than 10,000 changes
Added ext/fts5/test/fts5corrupt4.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 | # 2019 May 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. # #*********************************************************************** # # source [file join [file dirname [info script]] fts5_common.tcl] set testprefix fts5corrupt4 # If SQLITE_ENABLE_FTS5 is defined, omit this file. ifcapable !fts5 { finish_test return } sqlite3_fts5_may_be_corrupt 1 do_execsql_test 1.0 { CREATE VIRTUAL TABLE ttt USING fts5(a, b); INSERT INTO ttt VALUES('e ee eee e ee eee e ee eee', 'eee ee e e e ee eee ee ee'); INSERT INTO ttt SELECT a||a, b||b FROM ttt; INSERT INTO ttt SELECT a||a, b||b FROM ttt; } expr srand(1) proc mutate {blob i} { set o [expr {$i % [string length $blob]}] set a [string range $blob 0 $o-1] set b [string range $blob $o+1 end] set v [expr int(rand()*255) - 127] return "$a[binary format c $v]$b" } db func mutate mutate for {set j 1000} {$j <= 5000} {incr j 1000} { do_test 1.$j { for {set i 0} {$i < 1000} {incr i} { execsql { BEGIN; UPDATE ttt_data SET block = mutate(block, $i) WHERE id>10; } foreach sql { {SELECT snippet(ttt, -1, '.', '..', '[', ']'), * FROM ttt('e*')} {SELECT snippet(ttt, -1, '.', '..', '[', ']'), * FROM ttt('e* NOT ee*')} } { catch { execsql $sql } } execsql ROLLBACK } } {} } sqlite3_fts5_may_be_corrupt 0 finish_test |
Added ext/fts5/test/fts5corrupt5.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 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 | # 2015 Apr 24 # # 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 that FTS5 handles corrupt databases (i.e. internal # inconsistencies in the backing tables) correctly. In this case # "correctly" means without crashing. # source [file join [file dirname [info script]] fts5_common.tcl] set testprefix fts5corrupt3 # If SQLITE_ENABLE_FTS5 is defined, omit this file. ifcapable !fts5 { finish_test return } sqlite3_fts5_may_be_corrupt 1 database_may_be_corrupt #------------------------------------------------------------------------- # dbsqlfuzz crash-0f47112aa7520cf08c6a835a88fdff8c2a32a188 # reset_db do_test 1.0 { sqlite3 db {} db deserialize [decode_hexdb { .open --hexdb | size 24576 pagesize 4096 filename crash-0f47112aa7520c.db | page 1 offset 0 | 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3. | 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 00 .....@ ........ | 96: 00 00 00 00 0d 00 00 00 06 0e 0f 00 0f aa 0f 53 ...............S | 112: 0e e8 0e 8b 0e 33 0e 0f 00 00 00 00 00 00 00 00 .....3.......... | 3584: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 22 ................ | 3600: 06 06 17 11 11 01 31 74 61 62 6c 65 62 62 62 62 ......1tablebbbb | 3616: 06 43 52 45 41 54 45 20 54 41 42 4c 45 20 62 62 .CREATE TABLE bb | 3632: 28 61 29 56 05 06 17 1f 1f 01 7d 74 61 62 6c 65 (a)V.......table | 3648: 74 31 5f 63 6f 6e 66 69 67 74 31 5f 63 6f 6e 66 t1_configt1_conf | 3664: 69 67 05 43 52 45 41 54 45 20 54 41 42 4c 45 20 ig.CREATE TABLE | 3680: 27 74 31 5f 63 6f 6e 66 69 67 27 28 6b 20 50 52 't1_config'(k PR | 3696: 49 4d 41 52 59 20 4b 45 59 2c 20 76 29 20 57 49 IMARY KEY, v) WI | 3712: 54 48 4f 55 54 20 52 4f 57 49 44 5b 04 07 17 21 THOUT ROWID[...! | 3728: 21 01 81 01 74 61 62 6c 65 74 31 5f 64 6f 63 73 !...tablet1_docs | 3744: 69 7a 65 74 31 5f 64 6f 63 73 69 7a 65 04 43 52 izet1_docsize.CR | 3760: 45 41 54 45 20 54 41 42 4c 45 20 27 74 31 5f 64 EATE TABLE 't1_d | 3776: 6f 63 73 69 7a 65 27 28 69 64 20 49 4e 54 45 47 ocsize'(id INTEG | 3792: 45 52 20 50 52 49 4d 41 52 59 20 4b 45 59 2c 20 ER PRIMARY KEY, | 3808: 73 7a 20 42 4c 4f 42 29 69 03 07 17 19 19 01 81 sz BLOB)i....... | 3824: 2d 74 61 62 6c 65 74 31 5f 69 64 78 74 31 5f 69 -tablet1_idxt1_i | 3840: 64 78 03 43 52 45 41 54 45 20 54 41 42 4c 45 20 dx.CREATE TABLE | 3856: 27 74 31 5f 69 64 78 27 28 73 65 67 69 64 2c 20 't1_idx'(segid, | 3872: 74 65 72 6d 2c 20 70 67 6e 6f 2c 20 50 52 49 4d term, pgno, PRIM | 3888: 41 52 59 20 4b 45 59 28 73 65 67 69 64 2c 20 74 ARY KEY(segid, t | 3904: 65 72 6d 29 29 20 57 49 54 48 4f 55 54 20 52 4f erm)) WITHOUT RO | 3920: 57 49 44 55 02 07 17 1b 1b 01 81 01 74 61 62 6c WIDU........tabl | 3936: 65 74 31 5f 64 61 74 61 74 31 5f 64 61 74 61 02 et1_datat1_data. | 3952: 43 52 45 41 54 45 20 54 41 42 4c 45 20 27 74 31 CREATE TABLE 't1 | 3968: 5f 64 61 74 61 27 28 69 64 20 49 4e 54 45 47 45 _data'(id INTEGE | 3984: 52 20 50 52 49 4d 41 52 59 20 4b 45 59 2c 20 62 R PRIMARY KEY, b | 4000: 6c 6f 63 6b 20 42 4c 4f 42 29 54 01 07 17 11 11 lock BLOB)T..... | 4016: 08 81 15 74 61 62 6c 65 74 31 74 31 43 52 45 41 ...tablet1t1CREA | 4032: 54 45 20 56 49 52 54 55 41 4c 20 54 41 42 4c 45 TE VIRTUAL TABLE | 4048: 20 74 31 20 55 53 49 4e 47 20 66 74 73 35 28 61 t1 USING fts5(a | 4064: 2c 62 2c 70 72 65 66 69 78 3d 22 31 2c 32 2c 33 ,b,prefix=.1,2,3 | 4080: 2c 34 22 2c 20 63 6f 6e 74 65 6e 74 3d 22 22 29 ,4., content=..) | page 2 offset 4096 | 0: 0d 0b 6a 00 37 09 4c 02 0f e7 09 4c 0f c6 0f a4 ..j.7.L....L.... | 16: 0f 88 0f 6d 0f 4b 0f 2c 0f 0e 0e ec 0e cd 0e ad ...m.K.,........ | 32: 0e 8e 0e 6c 0e 4b 0e 29 0e 08 0d e6 0d c4 0d b5 ...l.K.)........ | 48: 0d 97 0d 76 0d 54 0d 31 0d 15 0c f3 0c d3 0c b5 ...v.T.1........ | 64: 0c 95 0c 73 0c 54 0c 32 0c 10 0b ee 0b cc 0b b0 ...s.T.2........ | 80: 0b 8d 0b 7e 0b 48 0b 2e 0b 0b 0a ef 00 00 00 00 ...~.H.......... | 2368: 00 00 00 00 00 00 00 00 00 00 00 00 15 0a 03 00 ................ | 2384: 30 00 00 00 01 01 03 35 00 03 01 11 12 02 01 12 0......5........ | 2400: 03 01 11 1c 8c 80 80 80 80 10 03 00 3e 00 00 00 ............>... | 2416: 17 01 05 05 34 74 61 62 6c 03 02 03 01 04 77 68 ....4tabl.....wh | 2432: 65 72 03 02 06 09 1b 8c 80 80 80 80 0f 03 00 3c er.............< | 2448: 00 00 00 16 05 34 66 74 73 34 03 02 02 01 04 6e .....4fts4.....n | 2464: 75 6d 62 03 06 01 04 09 1b 8c 80 80 80 80 0e 03 umb............. | 2480: 00 3c 00 00 00 16 04 33 74 68 65 03 06 01 01 04 .<.....3the..... | 2496: 01 03 77 68 65 03 02 04 04 0a 1b 8c 80 80 80 80 ..whe........... | 2512: 0d 03 00 3c 00 00 00 16 04 33 6e 75 6d 03 06 01 ...<.....3num... | 2528: 01 05 01 03 74 61 62 03 02 03 04 0a 19 8c 80 80 ....tab......... | 2544: 80 80 0c 03 00 38 00 00 00 14 03 32 77 68 03 02 .....8.....2wh.. | 2560: 04 00 04 33 66 74 73 03 02 02 04 07 18 8c 80 80 ...3fts......... | 2576: 80 80 0b 03 00 36 00 00 00 13 03 32 74 61 03 02 .....6.....2ta.. | 2592: 03 02 01 68 03 06 01 01 04 04 07 1b 8c 80 80 80 ...h............ | 2608: 80 0a 03 00 3c 00 00 00 16 03 32 6e 75 03 06 01 ....<.....2nu... | 2624: 01 05 01 02 6f 66 03 06 01 01 06 04 09 19 8c 80 ....of.......... | 2640: 80 80 80 09 03 00 38 00 00 00 14 03 32 66 74 03 ......8.....2ft. | 2656: 02 02 01 02 69 73 03 06 01 01 03 04 07 18 8c 80 ....is.......... | 2672: 80 80 80 08 03 00 36 00 00 00 13 02 31 74 03 08 ......6.....1t.. | 2688: 03 01 01 04 01 01 77 03 02 04 04 09 1a 8c 80 80 ......w......... | 2704: 80 80 07 03 00 3a 00 00 00 15 02 31 6e 03 08 01 .....:.....1n... | 2720: 01 02 05 01 00 6f 03 06 01 01 06 04 09 18 8c 80 .....o.......... | 2736: 80 80 80 06 03 00 36 00 00 00 03 04 02 31 66 03 ......6......1f. | 2752: 02 02 01 01 69 03 06 01 01 03 04 f6 1c 8c 80 80 ....i........... | 2768: 80 80 05 03 00 3e 00 00 00 17 04 30 74 68 65 03 .....>.....0the. | 2784: f6 01 01 04 01 05 77 68 65 72 65 03 02 04 0a 15 ......where..... | 2800: 8c 80 80 80 80 04 03 00 30 00 00 00 11 01 01 06 ........0....... | 2816: 06 30 74 61 62 6c 65 0f 42 03 07 1c 8c 81 80 80 .0table.B....... | 2832: 80 03 03 00 3e 00 00 00 17 07 30 6e 75 6d 62 65 ....>.....0numbe | 2848: 72 03 06 01 01 05 01 02 6f 66 03 06 04 0d 13 8c r.......of...... | 2864: 80 80 80 80 02 03 00 2c 00 00 00 0f 01 01 03 02 .......,........ | 2880: 30 6e 03 06 01 01 02 07 1b 8c 80 80 80 80 01 03 0n.............. | 2896: 00 3c 00 00 00 16 08 30 66 74 73 34 61 75 78 03 .<.....0fts4aux. | 2912: 02 02 01 02 69 73 03 06 04 0c 00 00 00 14 2a 00 ....is........*. | 2928: 00 00 01 01 02 24 00 02 01 01 12 02 01 12 08 88 .....$.......... | 2944: 80 80 80 80 12 03 00 16 00 00 00 05 02 1c 88 80 ................ | 2960: 80 80 80 11 03 00 3e 00 00 00 17 05 34 72 6f 77 ......>.....4row | 2976: 73 02 06 01 01 05 01 04 74 68 65 72 02 02 04 0b s.......ther.... | 2992: 15 88 80 80 80 80 10 03 00 30 00 00 00 11 02 01 .........0...... | 3008: 01 07 05 34 62 65 74 77 02 02 04 08 1b 88 80 80 ...4betw........ | 3024: 80 80 0f 03 00 3c 00 00 00 16 04 04 33 72 6f 77 .....<......3row | 3040: 02 06 01 01 05 01 03 74 68 65 02 08 05 0a 1b 88 .......the...... | 3056: 80 80 80 80 0e 03 00 3c 00 00 00 16 01 01 02 04 .......<........ | 3072: 33 61 72 65 02 02 03 01 03 62 65 74 02 02 07 08 3are.....bet.... | 3088: 1b 88 80 80 80 80 0d 03 00 3c 00 00 00 16 13 32 .........<.....2 | 3104: 74 68 02 08 02 01 01 07 00 04 33 61 6e 64 02 06 th........3and.. | 3120: 04 0a 1b 88 80 80 80 80 0c 03 00 3c 00 00 00 16 ...........<.... | 3136: 03 32 69 6e 02 06 01 01 06 01 02 72 6f 02 06 01 .2in.......ro... | 3152: 01 05 04 09 18 88 80 80 80 80 0b 03 00 36 00 00 .............6.. | 3168: 00 13 02 03 32 61 72 02 02 03 01 02 62 65 02 02 ....2ar.....be.. | 3184: 04 05 07 1b 88 80 80 80 80 0a 03 00 3c 00 9e 00 ............<... | 3200: 16 02 31 74 02 08 02 01 01 07 00 03 32 61 6e 02 ..1t........2an. | 3216: 06 01 01 04 09 19 88 80 80 80 80 09 03 00 38 00 ..............8. | 3232: 00 00 14 02 31 6e 02 06 01 01 03 01 01 72 02 06 ....1n.......r.. | 3248: 01 01 05 04 08 17 88 80 80 80 80 08 03 00 34 00 ..............4. | 3264: 00 00 12 02 31 62 02 02 04 01 01 69 02 06 01 01 ....1b.....i.... | 3280: 06 04 06 19 88 80 80 80 80 07 03 00 38 00 00 00 ............8... | 3296: 14 04 02 31 32 02 02 05 01 01 61 02 08 03 01 01 ...12.....a..... | 3312: 02 05 06 1b 88 80 80 80 80 06 03 00 3c 00 00 00 ............<... | 3328: 16 06 30 74 68 65 72 65 02 02 02 00 02 31 31 02 ..0there.....11. | 3344: 06 01 01 04 0a 15 88 80 80 80 80 05 03 00 30 00 ..............0. | 3360: 00 00 11 01 01 05 04 30 74 68 65 02 06 01 01 07 .......0the..... | 3376: 07 1c 88 80 80 80 80 04 03 00 3e 00 00 00 17 01 ..........>..... | 3392: 01 06 02 30 6e 02 06 01 01 03 01 04 72 6f 77 73 ...0n.......rows | 3408: 02 06 07 08 1b 88 80 80 80 80 03 03 00 3c 00 00 .............<.. | 3424: 00 16 08 30 62 65 74 77 65 65 6e 02 02 04 01 02 ...0between..... | 3440: 69 6e 02 06 04 0c 1a 88 80 80 80 80 02 03 00 3a in.............: | 3456: 00 00 00 15 04 30 61 6e 64 02 06 01 01 02 02 02 .....0and....... | 3472: 72 65 02 02 03 04 0a 17 88 80 80 80 80 01 03 00 re.............. | 3488: 34 00 00 00 12 02 30 31 02 06 01 01 04 01 01 32 4.....01.......2 | 3504: 02 02 05 04 08 08 84 80 80 80 80 12 03 00 16 00 ................ | 3520: 00 00 05 04 1b 84 80 80 80 80 11 03 00 3c 00 00 .............<.. | 3536: 00 16 05 34 74 61 62 6c 01 06 01 01 05 02 03 65 ...4tabl.......e | 3552: 72 6d 01 02 04 0b 1b 84 80 80 80 80 10 03 00 3c rm.............< | 3568: 00 00 00 16 05 34 65 61 63 68 01 02 03 01 04 70 .....4each.....p | 3584: 72 65 73 01 02 05 04 08 1a 84 80 80 80 80 0f 03 res............. | 3600: 00 3a 00 00 00 15 04 33 74 65 72 01 02 04 02 02 .:.....3ter..... | 3616: 68 65 01 06 01 01 03 04 08 1b 84 80 80 80 80 0e he.............. | 3632: 03 00 3c 00 00 00 16 04 33 80 72 65 01 02 05 01 ..<.....3.re.... | 3648: 03 74 61 62 01 06 01 01 05 04 08 1a 84 80 80 80 .tab............ | 3664: 80 0d 03 00 3a 00 00 00 15 04 33 66 6f 72 01 02 ....:.....3for.. | 3680: 02 02 02 74 73 01 06 01 01 04 04 08 1b 84 80 80 ...ts........... | 3696: 80 80 0c 03 00 3c 00 00 00 17 03 32 74 68 01 06 .....<.....2th.. | 3712: 01 01 03 00 04 33 65 61 63 01 02 03 04 09 18 84 .....3eac....... | 3728: 80 80 80 80 0b 03 00 36 00 00 00 13 03 32 74 61 .......6.....2ta | 3744: 01 06 01 01 05 02 01 65 01 02 04 04 09 19 84 80 .......e........ | 3760: 80 80 80 0a 03 00 38 00 00 00 14 03 32 69 6e 01 ......8.....2in. | 3776: 06 01 01 02 01 02 70 72 01 02 05 04 09 18 84 80 ......pr........ | 3792: 80 80 80 09 03 00 36 00 00 00 13 03 32 66 6f 01 ......6.....2fo. | 3808: 02 02 02 01 74 01 06 01 01 04 04 07 1b 84 80 80 ....t........... | 3824: 80 80 08 03 00 3c 00 00 00 16 02 31 74 01 0a 04 .....<.....1t... | 3840: 01 01 03 04 00 03 32 65 61 01 02 03 04 0a 17 84 ......2ea....... | 3856: 80 80 80 80 07 03 00 34 00 00 00 12 02 31 69 01 .......4.....1i. | 3872: 06 01 01 02 01 01 70 01 02 05 04 08 18 84 80 80 ......p......... | 3888: 80 80 06 03 00 36 00 00 00 13 02 31 65 01 02 03 .....6.....1e... | 3904: 01 01 66 01 08 02 01 01 04 04 06 1b 84 80 80 80 ..f............. | 3920: 80 05 03 00 3c 00 00 00 16 05 30 74 65 72 6d 01 ....<.....0term. | 3936: 02 04 02 02 68 65 01 06 01 01 03 04 09 14 84 80 ....he.......... | 3952: 80 80 80 04 03 00 2e 00 00 00 10 06 30 64 61 62 ............0dab | 3968: 6c 65 01 06 01 01 05 04 15 84 80 80 80 80 03 03 le.............. | 3984: 00 30 00 00 00 11 02 08 30 70 72 65 73 65 6e 74 .0......0present | 4000: 01 02 05 05 1b 84 80 80 80 80 02 03 00 3c 00 00 .............<.. | 4016: 00 16 04 30 66 74 73 01 06 01 01 04 01 02 69 6e ...0fts.......in | 4032: 01 06 01 01 04 0a 1a 84 80 80 80 80 01 03 00 3a ...............: | 4048: 00 00 00 15 05 30 65 61 63 68 01 02 03 01 13 66 .....0each.....f | 4064: 6f 72 01 02 02 04 09 06 01 03 00 12 03 0b 0f 00 or.............. | 4080: 00 08 8c 80 80 80 80 11 03 00 16 00 00 00 05 04 ................ | page 3 offset 8192 | 0: 0a 00 00 00 32 0e 4f 00 0f fa 0f f1 0f e9 0f e1 ....2.O......... | 16: 0f d8 0f d1 0f c9 0f c1 0f b9 0f b1 0f a9 0f a0 ................ | 32: 0f 98 0f 90 0f 87 0f 80 0f 78 0f 71 0f 68 0f 5f .........x.q.h._ | 48: 0f 56 0f 4d 0f 41 0f 38 0f 2f 0f 26 0f 1d 0f 13 .V.M.A.8./.&.... | 64: 0f 0a 0f 01 0e f7 0e ee 0e e6 0e dd 0e d6 0e cd ................ | 80: 0e c3 0e ba 0e 00 00 00 00 00 00 00 00 00 00 00 ................ | 3648: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 08 ................ | 3664: 04 01 10 01 03 34 74 20 07 04 01 0e 01 03 34 1e .....4t ......4. | 3680: 09 04 01 12 01 03 33 74 68 1c 08 04 01 10 01 03 ......3th....... | 3696: 33 6e 1a 08 04 01 10 01 03 32 77 18 08 04 01 10 3n.......2w..... | 3712: 01 03 32 74 16 08 04 01 10 01 03 32 6e 14 07 04 ..2t.......2n... | 3728: 01 0e 01 03 32 12 08 04 01 10 01 03 31 74 10 08 ....2.......1t.. | 3744: 04 01 10 01 03 31 6e 0e 07 04 01 0e 01 03 31 0c .....1n.......1. | 3760: 09 04 01 12 01 03 30 74 68 0a 08 04 01 10 01 03 ......0th....... | 3776: 30 74 08 09 04 01 12 01 03 30 6e 75 06 08 04 01 0t.......0nu.... | 3792: 10 01 03 30 6e 04 06 04 01 0c 01 03 02 08 04 01 ...0n........... | 3808: 10 01 02 34 72 22 07 04 01 0e 01 02 34 20 08 04 ...4r.......4 .. | 3824: 01 10 01 02 33 72 1e 09 04 01 12 01 02 33 61 72 ....3r.......3ar | 3840: 1c 08 04 01 10 01 02 32 74 1a 08 04 01 10 01 02 .......2t....... | 3856: 32 69 18 09 04 01 12 01 02 32 61 72 16 08 04 01 2i.......2ar.... | 3872: 10 01 02 31 74 14 08 04 01 10 01 02 31 6e 12 08 ...1t.......1n.. | 3888: 04 01 10 01 02 31 62 10 08 04 01 10 01 02 31 32 .....1b.......12 | 3904: 0e 0b 04 01 16 01 02 30 74 68 65 72 0c 08 04 01 .......0ther.... | 3920: 10 01 02 30 74 0a 08 04 01 10 01 02 30 6e 08 08 ...0t.......0n.. | 3936: 14 01 10 01 02 30 62 06 08 04 01 10 01 02 30 61 .....0b.......0a | 3952: 04 06 04 01 0c 01 02 02 07 04 09 10 01 34 74 22 .............4t. | 3968: 06 04 09 0e 01 34 20 08 04 09 12 01 33 74 65 1e .....4 .....3te. | 3984: 07 04 09 10 01 33 70 1c 07 04 09 10 01 33 66 1a .....3p......3f. | 4000: 08 04 09 12 01 32 74 68 18 07 04 09 10 01 32 74 .....2th......2t | 4016: 16 01 64 09 10 01 32 69 14 07 04 09 10 01 32 66 ..d...2i......2f | 4032: 12 07 04 09 10 01 31 74 10 07 04 09 10 01 31 69 ......1t......1i | 4048: 0e 06 04 09 0e 01 31 0c 08 04 09 12 01 30 74 65 ......1......0te | 4064: 0a 06 04 09 10 01 30 74 08 07 04 09 10 01 30 70 ......0t......0p | 4080: 06 08 04 09 12 00 00 00 00 00 00 00 00 00 00 00 ................ | page 4 offset 12288 | 4064: 00 00 00 00 00 00 00 00 00 00 00 05 03 03 00 10 ................ | 4080: 03 05 05 02 03 00 10 04 06 05 01 03 00 10 04 04 ................ | page 5 offset 16384 | 0: 0a 00 00 00 02 0f eb 00 0f eb 0f f4 00 00 00 00 ................ | 4064: 00 00 00 00 00 00 00 00 00 00 00 08 03 15 01 70 ...............p | 4080: 67 73 7a 18 0b 03 1b 01 76 65 72 73 69 6f 6e 04 gsz.....version. | page 6 offset 20480 | 0: 0d 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ | 4080: 00 00 03 03 02 01 03 03 02 02 01 00 00 00 00 00 ................ | end crash-0f47112aa7520c.db }] } {} do_catchsql_test 1.1 { SELECT * FROM t1('R*') WHERE (a,b)<=(current_date,0) ORDER BY rowid DESC; } {1 {database disk image is malformed}} #------------------------------------------------------------------------- # reset_db do_test 2.0 { sqlite3 db {} db deserialize [decode_hexdb { .open --hexdb | size 24576 pagesize 4096 filename sql047467.txt.db | page 1 offset 0 | 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3. | 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 00 .....@ ........ | 96: 00 00 00 00 0d 00 00 00 06 0e 0f 00 0f aa 0f 53 ...............S | 112: 0e e8 0e 8b 0e 33 0e 0f 01 00 00 00 00 00 00 00 .....3.......... | 3584: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 22 ................ | 3600: 06 06 17 11 11 01 31 74 61 62 6c 65 62 62 62 62 ......1tablebbbb | 3616: 06 43 52 45 41 54 45 20 54 41 42 4c 45 20 62 62 .CREATE TABLE bb | 3632: 28 61 29 56 05 06 17 1f 1f 01 7d 74 61 62 6c 65 (a)V.......table | 3648: 74 31 5f 63 6f 6e 66 69 67 74 31 5f 63 6f 6e 66 t1_configt1_conf | 3664: 69 67 05 43 52 45 41 54 45 20 54 41 42 4c 45 20 ig.CREATE TABLE | 3680: 27 74 31 5f 63 6f 6e 66 69 67 27 28 6b 20 50 52 't1_config'(k PR | 3696: 49 4d 41 52 59 20 4b 45 59 2c 20 76 29 20 57 49 IMARY KEY, v) WI | 3712: 54 48 4f 55 54 20 52 4f 57 49 44 5b 04 07 17 21 THOUT ROWID[...! | 3728: 21 01 81 01 74 61 62 6c 65 74 31 5f 64 6f 63 73 !...tablet1_docs | 3744: 69 7a 65 74 31 5f 64 6f 63 73 69 7a 65 04 43 52 izet1_docsize.CR | 3760: 45 41 54 45 20 54 41 42 4c 45 20 27 74 31 5f 64 EATE TABLE 't1_d | 3776: 6f 63 73 69 7a 65 27 28 69 64 20 49 4e 54 45 47 ocsize'(id INTEG | 3792: 45 52 20 50 52 49 4d 41 52 59 20 4b 45 59 2c 20 ER PRIMARY KEY, | 3808: 73 7a 20 42 4c 4f 42 29 69 03 07 17 19 19 01 81 sz BLOB)i....... | 3824: 2d 74 61 62 6c 65 74 31 5f 69 64 78 74 31 5f 69 -tablet1_idxt1_i | 3840: 64 78 03 43 52 45 41 54 45 20 54 41 42 4c 45 20 dx.CREATE TABLE | 3856: 27 74 31 5f 69 64 78 27 28 73 65 67 69 64 2c 20 't1_idx'(segid, | 3872: 74 65 72 6d 2c 20 70 67 6e 6f 2c 20 50 52 49 4d term, pgno, PRIM | 3888: 41 52 59 20 4b 45 59 28 73 65 67 69 64 2c 20 74 ARY KEY(segid, t | 3904: 65 72 6d 29 29 20 57 49 54 48 4f 55 54 20 52 4f erm)) WITHOUT RO | 3920: 57 49 44 55 02 07 17 1b 1b 01 81 01 74 61 62 6c WIDU........tabl | 3936: 65 74 31 5f 64 61 74 61 74 31 5f 64 61 74 61 02 et1_datat1_data. | 3952: 43 52 45 41 54 45 20 54 41 42 4c 45 20 27 74 31 CREATE TABLE 't1 | 3968: 5f 64 61 74 61 27 28 69 64 20 49 4e 54 45 47 45 _data'(id INTEGE | 3984: 52 20 50 52 49 4d 41 52 59 20 4b 45 59 2c 20 62 R PRIMARY KEY, b | 4000: 6c 6f 63 6b 20 42 4c 4f 42 29 54 01 07 17 11 11 lock BLOB)T..... | 4016: 08 81 15 74 61 62 6c 65 74 31 74 31 43 52 45 41 ...tablet1t1CREA | 4032: 54 45 20 56 49 52 54 55 41 4c 20 54 41 42 4c 45 TE VIRTUAL TABLE | 4048: 20 74 31 20 55 53 49 4e 47 20 66 74 73 35 28 61 t1 USING fts5(a | 4064: 2c 62 2c 70 72 65 66 69 78 3d 22 31 2c 32 2c 33 ,b,prefix=.1,2,3 | 4080: 2c 34 22 2c 20 63 6f 6e 74 65 6e 74 3d 22 22 29 ,4., content=..) | page 2 offset 4096 | 0: 0d 0b 6a 00 37 09 4c 02 0f e7 09 4c 0f c6 0f a4 ..j.7.L....L.... | 16: 0f 88 0f 6d 0f 4b 0f 2c 0f 0e 0e ec 0e cd 0e ad ...m.K.,........ | 32: 0e 8e 0e 6c 0e 4b 0e 29 0e 08 0d e6 0d c4 0d b5 ...l.K.)........ | 48: 0d 97 0d 76 0d 54 0d 31 0d 15 0c f3 0c d3 0c b5 ...v.T.1........ | 64: 0c 95 0c 73 0c 54 0c 32 0c 10 0b ee 0b cc 0b b0 ...s.T.2........ | 80: 0b 8d 0b 7e 0b 48 0b 2e 0b 0b 0a ef 00 00 00 00 ...~.H.......... | 2368: 00 00 00 00 00 00 00 00 00 00 00 00 15 0a 03 00 ................ | 2384: 30 00 00 00 01 01 03 35 00 03 01 11 12 02 01 12 0......5........ | 2400: 03 01 11 1c 8c 80 80 80 80 10 03 00 3e 00 00 00 ............>... | 2416: 17 01 05 05 34 74 61 62 6c 03 02 03 01 04 77 68 ....4tabl.....wh | 2432: 65 72 03 02 06 09 1b 8c 80 80 80 80 0f 03 00 3c er.............< | 2448: 00 00 00 16 05 34 66 74 73 34 03 02 02 01 04 6e .....4fts4.....n | 2464: 75 6d 62 03 06 01 04 09 1b 8c 80 80 80 80 0e 03 umb............. | 2480: 00 3b ff f0 00 16 04 33 74 68 65 03 06 01 01 04 .;.....3the..... | 2496: 01 03 77 68 65 03 02 04 04 0a 1b 8c 80 80 80 80 ..whe........... | 2512: 0d 03 00 3c 00 00 00 16 04 33 6e 75 6d 03 06 01 ...<.....3num... | 2528: 01 05 01 03 74 61 62 03 02 03 04 0a 19 8c 80 80 ....tab......... | 2544: 80 80 0c 03 00 38 00 00 00 14 03 32 77 68 03 02 .....8.....2wh.. | 2560: 04 00 04 33 66 74 73 03 02 02 04 07 18 8c 80 80 ...3fts......... | 2576: 80 80 0b 03 00 36 00 00 00 13 03 32 74 61 03 02 .....6.....2ta.. | 2592: 03 02 01 68 03 06 01 01 04 04 07 1b 8c 80 80 80 ...h............ | 2608: 80 0a 03 00 3c 00 00 00 16 03 32 6e 75 03 06 01 ....<.....2nu... | 2624: 01 05 01 02 6f 66 03 06 01 01 06 04 09 19 8c 80 ....of.......... | 2640: 80 80 80 09 03 00 38 00 00 00 14 03 32 66 74 03 ......8.....2ft. | 2656: 02 02 01 02 69 73 03 06 01 01 03 04 07 18 8c 80 ....is.......... | 2672: 80 80 80 08 03 00 36 00 00 00 13 02 31 74 03 08 ......6.....1t.. | 2688: 03 01 01 04 01 01 77 03 02 04 04 09 1a 8c 80 80 ......w......... | 2704: 80 80 07 03 00 3a 00 00 00 15 02 31 6e 03 08 01 .....:.....1n... | 2720: 01 02 05 01 00 6f 03 06 01 01 06 14 09 18 8c 80 .....o.......... | 2736: 80 80 80 06 03 00 36 00 00 00 03 04 02 31 66 03 ......6......1f. | 2752: 02 02 01 01 69 03 06 01 01 03 04 f6 1c 8c 80 80 ....i........... | 2768: 80 80 05 03 00 3e 00 00 00 17 04 30 74 68 65 03 .....>.....0the. | 2784: f6 01 01 04 01 05 77 68 65 72 65 03 02 04 0a 15 ......where..... | 2800: 8c 80 80 80 80 04 03 00 30 00 00 00 11 01 01 06 ........0....... | 2816: 06 30 74 61 62 6c 65 0f 42 03 07 1c 8c 81 80 80 .0table.B....... | 2832: 80 03 03 00 3e 00 00 00 17 07 30 6e 75 6d 62 65 ....>.....0numbe | 2848: 72 03 06 01 01 05 01 02 6f 66 03 06 04 0d 13 8c r.......of...... | 2864: 80 80 80 80 02 03 00 2c 00 00 00 0f 01 01 03 02 .......,........ | 2880: 30 6e 03 06 01 01 02 07 1b 8c 80 80 80 80 01 03 0n.............. | 2896: 00 3c 00 00 00 16 08 30 66 74 73 34 61 75 78 03 .<.....0fts4aux. | 2912: 02 02 01 02 69 73 03 06 04 0c 00 00 00 14 2a 00 ....is........*. | 2928: 00 00 01 01 02 24 00 02 01 01 12 02 01 12 08 88 .....$.......... | 2944: 80 80 80 80 12 03 00 16 00 00 00 05 02 1c 88 80 ................ | 2960: 80 80 80 11 03 00 3e 00 00 00 17 05 34 72 6f 77 ......>.....4row | 2976: 73 02 06 01 01 05 01 04 74 68 65 72 02 02 04 0b s.......ther.... | 2992: 15 88 80 80 80 80 10 03 00 30 00 00 00 11 02 01 .........0...... | 3008: 01 07 05 34 62 65 74 77 02 02 04 08 1b 88 80 80 ...4betw........ | 3024: 80 80 0f 03 00 3c 00 00 00 16 04 04 33 72 6f 77 .....<......3row | 3040: 02 06 01 01 05 01 03 74 68 65 02 08 05 0a 1b 88 .......the...... | 3056: 80 80 80 80 0e 03 00 3c 00 00 00 16 01 01 02 04 .......<........ | 3072: 33 61 72 65 02 02 03 01 03 62 65 74 02 02 07 08 3are.....bet.... | 3088: 1b 88 80 80 80 80 0d 03 00 3c 00 00 00 16 13 32 .........<.....2 | 3104: 74 68 02 08 02 01 01 07 00 04 33 61 6e 64 02 06 th........3and.. | 3120: 04 0a 1b 88 80 80 80 80 0c 03 00 3c 00 00 00 16 ...........<.... | 3136: 03 32 69 6e 02 06 01 01 06 01 02 72 6f 02 06 01 .2in.......ro... | 3152: 01 05 04 09 18 88 80 80 80 80 0b 03 00 36 00 00 .............6.. | 3168: 00 13 02 03 32 61 72 02 02 03 01 02 62 65 02 02 ....2ar.....be.. | 3184: 04 05 07 1b 88 80 80 80 80 0a 03 00 3c 00 94 50 ............<..P | 3200: 16 02 31 74 02 08 02 01 01 07 00 03 32 61 6e 02 ..1t........2an. | 3216: 06 01 01 04 09 19 88 80 80 80 80 09 03 00 38 00 ..............8. | 3232: 00 00 14 02 31 6e 02 06 01 01 03 01 01 72 02 06 ....1n.......r.. | 3248: 01 01 05 04 08 17 88 80 80 80 80 08 03 00 34 00 ..............4. | 3264: 00 00 12 02 31 62 02 02 04 01 01 69 02 06 01 01 ....1b.....i.... | 3280: 06 04 06 19 88 80 80 80 80 07 03 00 38 00 00 00 ............8... | 3296: 14 04 02 31 32 02 02 05 01 01 61 02 08 03 01 01 ...12.....a..... | 3312: 02 05 06 1b 88 80 80 80 80 06 03 00 3c 00 00 00 ............<... | 3328: 16 06 30 74 68 65 72 65 02 02 02 00 02 31 31 02 ..0there.....11. | 3344: 06 01 01 04 0a 15 88 80 80 80 80 05 03 00 30 00 ..............0. | 3360: 00 00 11 01 01 05 04 30 74 68 65 02 06 01 01 07 .......0the..... | 3376: 07 1c 88 80 80 80 80 04 03 00 3e 00 00 00 17 01 ..........>..... | 3392: 01 06 02 30 6e 02 06 01 01 03 01 04 72 6f 77 73 ...0n.......rows | 3408: 02 06 07 08 1b 88 80 80 80 80 03 03 00 3c 00 00 .............<.. | 3424: 00 16 08 30 62 65 74 77 65 65 6e 02 02 04 01 02 ...0between..... | 3440: 69 6e 02 06 04 0c 1a 88 80 80 80 80 02 03 00 3a in.............: | 3456: 00 00 00 15 04 30 61 6e 64 02 06 01 01 02 02 02 .....0and....... | 3472: 72 65 02 02 03 04 0a 17 88 80 80 80 80 01 03 00 re.............. | 3488: 34 00 00 00 12 02 30 31 02 06 01 01 04 01 01 32 4.....01.......2 | 3504: 02 02 05 04 08 08 84 80 80 80 80 12 03 00 16 00 ................ | 3520: 00 00 05 04 1b 84 80 80 80 80 11 03 00 3c 00 00 .............<.. | 3536: 00 16 05 34 74 61 62 6c 01 06 01 01 05 02 03 65 ...4tabl.......e | 3552: 72 6d 01 02 04 0b 1b 84 80 80 80 80 10 03 00 3c rm.............< | 3568: 00 00 00 16 05 34 65 61 63 68 01 02 03 01 04 70 .....4each.....p | 3584: 72 65 73 01 02 05 04 08 1a 84 80 80 80 80 0f 03 res............. | 3600: 00 3a 00 00 00 15 04 33 74 65 72 01 02 04 02 02 .:.....3ter..... | 3616: 68 65 01 06 01 01 03 04 08 1b 84 80 80 80 80 0e he.............. | 3632: 03 00 3c 00 00 00 16 04 33 80 72 65 01 02 05 01 ..<.....3.re.... | 3648: 03 74 61 62 01 06 01 01 05 04 08 1a 84 80 80 80 .tab............ | 3664: 80 0d 03 00 3a 00 00 00 15 04 33 66 6f 72 01 02 ....:.....3for.. | 3680: 02 02 02 74 73 01 06 01 01 04 04 08 1b 84 80 80 ...ts........... | 3696: 80 80 0c 03 00 3c 00 00 00 17 03 32 74 68 01 06 .....<.....2th.. | 3712: 01 01 03 00 04 33 65 61 63 01 02 03 04 09 18 84 .....3eac....... | 3728: 80 80 80 80 0b 03 00 36 00 00 00 13 03 32 74 61 .......6.....2ta | 3744: 01 06 01 01 05 02 01 65 01 02 04 04 09 19 84 80 .......e........ | 3760: 80 80 80 0a 03 00 38 00 00 00 14 03 32 69 6e 01 ......8.....2in. | 3776: 06 01 01 02 01 02 70 72 01 02 05 04 09 18 84 80 ......pr........ | 3792: 80 80 80 09 03 00 36 00 00 00 13 03 32 66 6f 01 ......6.....2fo. | 3808: 02 02 02 01 74 01 06 01 01 04 04 07 1b 84 80 80 ....t........... | 3824: 80 80 08 03 00 3c 00 00 00 16 02 31 74 01 0a 04 .....<.....1t... | 3840: 01 01 03 04 00 03 32 65 61 01 02 03 04 0a 17 84 ......2ea....... | 3856: 80 80 80 80 07 03 00 34 00 00 00 12 02 31 69 01 .......4.....1i. | 3872: 06 01 01 02 01 01 70 01 02 05 04 08 18 84 80 80 ......p......... | 3888: 80 80 06 03 00 36 00 00 00 13 02 31 65 01 02 03 .....6.....1e... | 3904: 01 01 66 01 08 02 01 01 04 04 06 1b 84 80 80 80 ..f............. | 3920: 80 05 03 00 3c 00 00 00 16 05 30 74 65 72 6d 01 ....<.....0term. | 3936: 02 04 02 02 68 65 01 06 01 01 03 04 09 14 84 80 ....he.......... | 3952: 80 80 80 04 03 00 2e 00 00 00 10 06 30 64 61 62 ............0dab | 3968: 6c 65 01 06 01 01 05 04 15 84 80 80 80 80 03 03 le.............. | 3984: 00 30 00 00 00 11 02 08 30 70 72 65 73 65 6e 74 .0......0present | 4000: 01 02 05 05 1b 84 80 80 80 80 02 03 00 3c 00 00 .............<.. | 4016: 00 16 04 30 66 74 73 01 06 01 01 04 01 02 69 6e ...0fts.......in | 4032: 01 06 01 01 04 0a 1a 84 80 80 80 80 01 03 00 3a ...............: | 4048: 00 00 00 15 05 30 65 61 63 68 01 02 03 01 13 66 .....0each.....f | 4064: 6f 72 01 02 02 04 09 06 01 03 00 12 03 0b 0f 00 or.............. | 4080: 00 08 8c 80 80 80 80 11 03 00 16 00 00 00 05 04 ................ | page 3 offset 8192 | 0: 0a 00 00 00 32 0e 4f 00 0f fa 0f f1 0f e9 0f e1 ....2.O......... | 16: 0f d8 0f d1 0f c9 0f c1 0f b9 0f b1 0f a9 0f a0 ................ | 32: 0f 98 0f 90 0f 87 0f 80 0f 78 0f 71 0f 68 0f 5f .........x.q.h._ | 48: 0f 56 0f 4d 0f 41 0f 38 0f 2f 0f 26 0f 1d 0f 13 .V.M.A.8./.&.... | 64: 0f 0a 0f 01 0e f7 0e ee 0e e6 0e dd 0e d6 0e cd ................ | 80: 0e c3 0e ba 0e 00 00 00 00 00 00 00 00 00 00 00 ................ | 3648: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 08 ................ | 3664: 04 01 10 01 03 34 74 20 07 04 01 0e 01 03 34 1e .....4t ......4. | 3680: 09 04 01 12 01 03 33 74 68 1c 08 04 01 10 01 03 ......3th....... | 3696: 33 6e 1a 08 04 01 10 01 03 32 77 18 08 04 01 10 3n.......2w..... | 3712: 01 03 32 74 16 08 04 01 10 01 03 32 6e 14 07 04 ..2t.......2n... | 3728: 01 0e 01 03 32 12 08 04 01 10 01 03 31 74 10 08 ....2.......1t.. | 3744: 04 01 10 01 03 31 6e 0e 07 04 01 0e 01 03 31 0c .....1n.......1. | 3760: 09 04 01 12 01 03 30 74 68 0a 08 04 01 10 01 03 ......0th....... | 3776: 30 74 08 09 04 01 12 01 03 30 6e 75 06 08 04 01 0t.......0nu.... | 3792: 10 01 03 30 6e 04 06 04 01 0c 01 03 02 08 04 01 ...0n........... | 3808: 10 01 02 34 72 22 07 04 01 0e 01 02 34 20 08 04 ...4r.......4 .. | 3824: 01 10 01 02 33 72 1e 09 04 01 12 01 02 33 61 72 ....3r.......3ar | 3840: 1c 08 04 01 10 01 02 32 74 1a 08 04 01 10 01 02 .......2t....... | 3856: 32 69 18 09 04 01 12 01 02 32 61 72 16 08 04 01 2i.......2ar.... | 3872: 10 01 02 31 74 14 08 04 01 10 01 02 31 6e 12 08 ...1t.......1n.. | 3888: 04 01 10 01 02 31 62 10 08 04 01 10 01 02 31 32 .....1b.......12 | 3904: 0e 0b 04 01 16 01 02 30 74 68 65 72 0c 08 04 01 .......0ther.... | 3920: 10 01 02 30 74 0a 08 04 01 10 01 02 30 6e 08 08 ...0t.......0n.. | 3936: 14 01 10 01 02 30 62 06 08 04 01 10 01 02 30 61 .....0b.......0a | 3952: 04 06 04 01 0c 01 02 02 07 04 09 10 01 34 74 22 .............4t. | 3968: 06 04 09 0e 01 34 20 08 04 09 12 01 33 74 65 1e .....4 .....3te. | 3984: 07 04 09 10 01 33 70 1c 07 04 09 10 01 33 66 1a .....3p......3f. | 4000: 08 04 09 12 01 32 74 68 18 07 04 09 10 01 32 74 .....2th......2t | 4016: 16 01 64 09 10 01 32 69 14 07 04 09 10 01 32 66 ..d...2i......2f | 4032: 12 07 04 09 10 01 31 74 10 07 04 09 10 01 31 69 ......1t......1i | 4048: 0e 06 04 09 0e 01 31 0c 08 04 09 12 01 30 74 65 ......1......0te | 4064: 0a 06 04 09 10 01 30 74 08 07 04 09 10 01 30 70 ......0t......0p | 4080: 06 08 04 09 12 00 00 00 00 00 00 00 00 00 00 00 ................ | page 4 offset 12288 | 4064: 00 00 00 00 00 00 00 00 00 00 00 05 03 03 00 10 ................ | 4080: 03 05 05 02 03 00 10 04 06 05 01 03 00 10 04 04 ................ | page 5 offset 16384 | 0: 0a 00 00 00 02 0f eb 00 0f eb 0f f4 00 00 00 00 ................ | 4064: 00 00 00 00 00 00 00 00 00 00 00 08 03 15 01 70 ...............p | 4080: 67 73 7a 18 0b 03 1b 01 76 65 72 73 69 6f 6e 04 gsz.....version. | page 6 offset 20480 | 0: 0d 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ | 4080: 00 00 03 03 02 01 03 03 02 02 01 00 00 00 00 00 ................ | end sql047467.txt.db }]} {} do_catchsql_test 2.1 { SELECT * FROM t1('R*R*R*R*') WHERE (a,b)<=(current_date,0) ORDER BY rowid DESC; } {1 {database disk image is malformed}} #------------------------------------------------------------------------- reset_db do_test 3.0 { sqlite3 db {} db deserialize [decode_hexdb { .open --hexdb | size 32768 pagesize 4096 filename crash-c69fcaceff1e50.db | page 1 offset 0 | 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3. | 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 08 .....@ ........ | 32: 00 00 00 02 00 00 00 01 00 00 00 09 00 00 00 04 ................ | 96: 00 00 00 00 0d 0f c7 00 07 0d 92 00 0f 8d 0f 36 ...............6 | 112: 0e cb 0e 6b 0e 0e 0d b6 0d 92 0d 92 00 00 00 00 ...k............ | 3472: 00 00 22 08 06 17 11 11 01 31 74 61 62 6c 65 74 .........1tablet | 3488: 32 74 32 08 43 52 45 41 54 45 20 54 41 42 4c 45 2t2.CREATE TABLE | 3504: 20 74 32 28 78 29 56 07 06 17 1f 1f 01 7d 74 61 t2(x)V.......ta | 3520: 62 6c 65 74 31 5f 63 6f 6e 66 69 67 74 31 5f 63 blet1_configt1_c | 3536: 6f 6e 66 69 67 07 43 52 45 41 54 45 20 54 41 42 onfig.CREATE TAB | 3552: 4c 45 20 27 74 31 5f 63 6f 6e 66 69 67 27 28 6b LE 't1_config'(k | 3568: 20 50 52 49 4d 41 52 59 20 4b 45 59 2c 20 76 29 PRIMARY KEY, v) | 3584: 20 57 49 54 48 4f 55 54 20 52 4f 57 49 44 5b 06 WITHOUT ROWID[. | 3600: 07 17 21 21 01 81 01 74 61 62 6c 65 74 31 5f 64 ..!!...tablet1_d | 3616: 6f 63 73 69 7a 65 74 31 5f 64 6f 63 73 69 7a 65 ocsizet1_docsize | 3632: 06 43 52 45 41 54 45 20 54 41 42 4c 45 20 27 74 .CREATE TABLE 't | 3648: 31 5f 64 6f 63 73 69 7a 65 27 28 69 64 20 49 4e 1_docsize'(id IN | 3664: 54 45 47 45 52 20 50 52 49 4d 41 52 59 20 4b 45 TEGER PRIMARY KE | 3680: 59 2c 20 73 7a 20 42 4c 4f 42 29 5e 05 07 17 21 Y, sz BLOB)^...! | 3696: 21 01 81 07 74 61 62 6c 65 74 31 5f 63 6f 6e 74 !...tablet1_cont | 3712: 65 6e 74 74 31 5f 63 6f 6e 74 65 6e 74 05 43 52 entt1_content.CR | 3728: 45 41 54 45 20 54 41 42 4c 45 20 27 74 31 5f 63 EATE TABLE 't1_c | 3744: 6f 6e 74 65 6e 74 27 28 69 64 20 49 4e 54 45 47 ontent'(id INTEG | 3760: 45 52 20 50 52 49 4d 41 52 59 20 4b 45 59 2c 20 ER PRIMARY KEY, | 3776: 63 30 2c 20 63 31 2c 20 63 32 29 69 04 07 17 19 c0, c1, c2)i.... | 3792: 19 01 81 2d 74 61 62 6c 65 74 31 5f 69 64 78 74 ...-tablet1_idxt | 3808: 31 5f 69 64 78 04 43 52 45 41 54 45 20 54 41 42 1_idx.CREATE TAB | 3824: 4c 45 20 27 74 31 5f 69 64 78 27 28 73 65 67 69 LE 't1_idx'(segi | 3840: 64 2c 20 74 65 72 6d 2c 20 70 67 6e 6f 2c 20 50 d, term, pgno, P | 3856: 52 49 4d 41 52 59 20 4b 45 59 28 73 65 67 69 64 RIMARY KEY(segid | 3872: 2c 20 74 65 72 6d 29 29 20 57 49 54 48 4f 55 54 , term)) WITHOUT | 3888: 20 52 4f 57 49 44 55 03 07 17 1b 1b 01 81 01 74 ROWIDU........t | 3904: 61 62 6c 65 74 31 5f 64 61 74 61 74 31 5f 64 61 ablet1_datat1_da | 3920: 74 61 03 43 52 45 41 54 45 20 54 41 42 4c 45 20 ta.CREATE TABLE | 3936: 27 74 31 5f 64 61 74 61 27 28 69 64 20 49 4e 54 't1_data'(id INT | 3952: 45 47 45 52 20 50 52 49 4d 41 52 59 20 4b 45 59 EGER PRIMARY KEY | 3968: 2c 20 62 6c 6f 63 6b 20 42 4c 4f 42 29 38 02 06 , block BLOB)8.. | 3984: 17 11 11 08 5f 74 61 62 6c 65 74 31 74 31 43 52 ...._tablet1t1CR | 4000: 45 41 54 45 20 56 49 52 54 55 41 4c 20 54 41 42 EATE VIRTUAL TAB | 4016: 4c 45 20 74 31 20 55 53 49 4e 47 20 66 74 73 35 LE t1 USING fts5 | 4032: 28 61 2c 62 2c 63 29 00 00 00 00 00 00 00 00 00 (a,b,c)......... | page 3 offset 8192 | 0: 0d 00 00 00 03 0c 94 00 0f e6 0f ef 0c 94 00 00 ................ | 3216: 00 00 00 00 86 4a 84 80 80 80 80 01 04 00 8d 18 .....J.......... | 3232: 00 00 01 bb 02 30 30 01 02 06 01 02 06 01 02 06 .....00......... | 3248: 1f 02 03 01 02 03 01 02 03 01 08 32 30 31 36 30 ...........20160 | 3264: 36 30 39 01 02 07 01 02 07 01 02 07 01 01 34 01 609...........4. | 3280: 02 05 01 02 05 01 02 05 01 01 35 01 02 04 01 02 ..........5..... | 3296: 04 01 02 04 02 07 30 30 30 30 30 30 30 1c 02 04 ......0000000... | 3312: 01 02 04 01 02 04 01 06 62 69 6e 61 72 79 03 06 ........binary.. | 3328: 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 ................ | 3344: 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 ................ | 3360: 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02 ................ | 3376: 03 06 01 02 02 03 06 01 02 02 01 08 63 6f 6d 70 ............comp | 3392: 69 6c 65 72 01 02 02 01 02 02 01 02 02 01 06 64 iler...........d | 3408: 62 73 74 61 74 07 02 03 01 02 03 01 02 03 02 04 bstat........... | 3424: 65 62 75 67 04 02 02 01 02 02 01 02 02 01 06 65 ebug...........e | 3440: 6b b1 62 6c 65 07 02 02 01 02 02 01 02 02 01 02 k.ble........... | 3456: 02 01 02 02 01 02 02 01 02 02 01 02 02 01 02 02 ................ | 3472: 01 02 02 01 02 02 05 02 02 01 02 02 01 02 02 01 ................ | 3488: 02 02 01 02 02 01 02 02 01 02 02 01 02 02 01 02 ................ | 3504: 02 01 02 02 02 08 78 74 65 6e 73 69 6f 6e 1f 02 ......xtension.. | 3520: 04 01 02 04 01 02 04 01 04 66 74 73 34 1a 02 03 .........fts4... | 3536: 01 02 03 01 02 03 04 01 35 0d 02 03 01 02 03 01 ........5....... | 3552: 02 03 01 03 67 63 63 01 02 03 01 02 03 01 02 03 ....gcc......... | 3568: 02 06 65 6f 70 6f 6c 79 10 02 03 01 02 03 01 02 ..eopoly........ | 3584: 03 01 05 6a 73 6f 6e 31 13 02 03 01 02 03 01 02 ...json1........ | 3600: 03 01 04 6c 6f 61 64 1f 02 03 01 02 03 01 02 03 ...load......... | 3616: 01 03 6d 61 78 1c 02 02 01 02 02 01 02 02 02 05 ..max........... | 3632: 65 6d 6f 72 79 1c 02 03 01 02 03 01 02 03 04 04 emory........... | 3648: 73 79 73 35 16 02 03 01 02 03 01 02 03 01 06 6e sys5...........n | 3664: 6f 63 61 73 65 02 06 01 02 02 03 06 01 02 02 03 ocase........... | 3680: 06 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 ................ | 3696: 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 ................ | 3712: 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 ................ | 3728: 02 01 04 6f 6d 69 74 1f 02 02 01 02 02 01 02 01 ...omit......... | 3744: ff ff ff ff ff ff ff ff ff ff ff ff ff ff f1 02 ................ | 3760: 58 81 96 4d 01 06 01 02 02 03 06 01 02 02 03 06 X..M............ | 3776: 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 ................ | 3792: 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 ................ | 3808: 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02 ................ | 3824: 01 0a 74 68 72 65 61 64 73 61 66 65 22 02 02 01 ..threadsafe.... | 3840: 02 02 01 02 02 01 04 76 74 61 62 07 02 04 01 02 .......vtab..... | 3856: 04 01 02 04 01 01 78 01 06 01 01 02 01 06 01 01 ......x......... | 3872: 02 01 06 01 c6 02 01 06 01 01 02 01 06 01 01 02 ................ | 3888: 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 ................ | 3904: 06 01 01 02 00 f6 01 01 02 01 06 01 01 02 01 06 ................ | 3920: 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 ................ | 3936: 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 ................ | 3952: 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 ................ | 3968: 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 ................ | 3984: 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 ................ | 4000: 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 ................ | 4016: 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 ................ | 4032: 02 01 06 01 01 02 01 06 01 01 02 04 15 13 0c 0c ................ | 4048: 12 44 13 11 0f 47 13 0f 0c 0e 11 10 0f 0e 10 0f .D...G.......... | 4064: 44 0f 10 40 15 0f 07 01 03 00 14 24 5a 24 24 0f D..@.......$Z$$. | 4080: 0a 03 00 24 00 00 00 00 01 01 01 00 01 01 01 01 ...$............ | page 4 offset 12288 | 0: 0a 00 00 00 01 0f fa 00 0f fa 00 00 00 00 00 00 ................ | 4080: 00 00 00 00 00 00 00 00 00 00 05 04 09 0c 01 02 ................ | page 7 offset 24576 | 0: 0a 00 00 00 01 0f f4 00 0f f4 00 00 00 00 00 00 ................ | 4080: 00 00 00 00 0b 03 1b 01 76 65 72 73 69 6f 6e 04 ........version. | end crash-c69fcaceff1e50.db }]} {} do_catchsql_test 3.1 { UPDATE t1 SET b=quote(zeroblob(200)) WHERE a MATCH 'thra*T'; } {1 {database disk image is malformed}} #------------------------------------------------------------------------- reset_db do_test 4.0 { sqlite3 db {} db deserialize [decode_hexdb { .open --hexdb | size 24576 pagesize 4096 filename crash-ef6738247b1344.db | page 1 offset 0 | 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3. | 16: 10 00 01 01 00 40 20 20 00 10 00 06 40 00 00 06 .....@ ....@... | 32: 00 00 00 00 00 00 00 00 00 00 00 06 00 00 00 00 ................ | 96: 00 00 00 00 0d 00 00 00 06 0e 0f 00 0f aa 0f 53 ...............S | 112: 0e e8 0e 8b 0e 33 0e 0f 00 00 00 00 00 00 00 00 .....3.......... | 3584: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 22 ................ | 3600: 06 06 17 11 11 01 31 74 61 62 6c 65 62 62 62 62 ......1tablebbbb | 3616: 06 43 52 45 41 54 45 20 54 41 42 4c 45 20 62 62 .CREATE TABLE bb | 3632: 28 61 29 56 05 06 17 1f 1f 01 7d 74 61 62 6c 65 (a)V.......table | 3648: 74 31 5f 63 6f 6e 66 69 67 74 31 5f 63 6f 6e 66 t1_configt1_conf | 3664: 69 67 05 43 52 45 41 54 45 20 54 41 42 4c 45 20 ig.CREATE TABLE | 3680: 27 74 31 5f 63 6f 6e 66 69 67 27 28 6b 20 50 52 't1_config'(k PR | 3696: 49 4d 41 52 59 20 4b 45 59 2c 20 76 29 20 57 49 IMARY KEY, v) WI | 3712: 54 48 4f 55 54 20 52 4f 57 49 44 5b 04 07 17 21 THOUT ROWID[...! | 3728: 21 01 81 01 74 61 62 6c 65 74 31 5f 64 6f 63 73 !...tablet1_docs | 3744: 69 7a 65 74 31 5f 64 6f 63 73 69 7a 65 04 43 52 izet1_docsize.CR | 3760: 45 41 54 45 20 54 41 42 4c 45 20 27 74 31 5f 64 EATE TABLE 't1_d | 3776: 6f 63 73 69 7a 65 27 28 69 64 20 49 4e 54 45 47 ocsize'(id INTEG | 3792: 45 52 20 50 52 49 4d 41 52 59 20 4b 45 59 2c 20 ER PRIMARY KEY, | 3808: 73 7a 20 42 4c 4f 42 29 69 03 07 17 19 19 01 81 sz BLOB)i....... | 3824: 2d 74 61 62 6c 65 74 31 5f 69 64 78 74 31 5f 69 -tablet1_idxt1_i | 3840: 64 78 03 43 52 45 41 54 45 20 54 41 42 4c 45 20 dx.CREATE TABLE | 3856: 27 74 31 5f 69 64 78 27 28 73 65 67 69 64 2c 20 't1_idx'(segid, | 3872: 74 65 72 6d 2c 20 6f 67 6e 6f 2c 20 50 52 49 4d term, ogno, PRIM | 3888: 41 52 59 20 4b 45 59 28 73 65 67 69 64 2c 20 74 ARY KEY(segid, t | 3904: 65 72 6d 29 29 20 57 49 54 48 4f 55 54 20 52 4f erm)) WITHOUT RO | 3920: 57 49 44 55 35 07 17 1b 1b 01 81 01 74 61 62 6c WIDU5.......tabl | 3936: 65 74 31 5f 64 61 74 61 74 31 5f 64 61 74 61 02 et1_datat1_data. | 3952: 43 52 45 41 54 45 20 54 41 42 4c 45 20 27 74 31 CREATE TABLE 't1 | 3968: 5f 64 61 74 61 27 28 69 64 20 49 4e 54 45 47 45 _data'(id INTEGE | 3984: 52 20 50 52 49 4d 41 52 59 20 4b 45 59 2c 20 62 R PRIMARY KEY, b | 4000: 6c 6f 63 6b 20 42 4c 4f 42 29 54 01 07 17 11 11 lock BLOB)T..... | 4016: 08 81 15 74 61 62 6c 65 74 31 74 31 43 52 45 41 ...tablet1t1CREA | 4032: 54 45 20 56 49 52 54 55 41 4c 20 54 41 42 4c 45 TE VIRTUAL TABLE | 4048: 20 74 31 20 55 53 49 4e 47 20 66 74 73 35 28 61 t1 USING fts5(a | 4064: 2c 62 2c 70 72 65 66 69 78 3d 22 31 2c 32 2c 33 ,b,prefix=.1,2,3 | 4080: 2c 34 22 2c 20 63 6f 6e 74 65 6e 74 3d 22 22 29 ,4., content=..) | page 2 offset 4096 | 0: 0d 0b 6a 00 37 09 4c 02 0f e7 09 4c 0f c6 0f a4 ..j.7.L....L.... | 16: 0f 88 0f 6d 0f 4b 0f 2c 0f 0e 0e ec 0e cd 0e ad ...m.K.,........ | 32: 0e 8e 0e 6c 0e 4b 0e 29 0e 08 0d e6 0d c4 0d b5 ...l.K.)........ | 48: 0d 97 0d 76 0d 54 0d 31 0d 15 0c f3 0c d3 0c b5 ...v.T.1........ | 64: 0c 95 0c 73 0c 54 0c 32 0c 10 0b ee 0b cc 0b b0 ...s.T.2........ | 80: 0b 8d 0b 7e 0b 48 0b 2e 0b 0b 0a ef 0a cc 0a 00 ...~.H.......... | 2368: 00 00 00 00 00 00 00 00 00 00 00 00 15 0a 03 00 ................ | 2384: 30 00 00 00 01 01 03 35 00 03 01 01 12 02 01 12 0......5........ | 2400: 03 01 11 1c 8c 80 80 80 80 10 02 9c 3e 00 00 00 ............>... | 2416: 17 01 05 05 34 74 61 62 6c 03 02 03 01 04 77 68 ....4tabl.....wh | 2432: 65 72 03 02 06 09 1b 8c 80 80 80 80 0f 03 00 3c er.............< | 2448: 00 00 00 16 05 34 66 74 73 34 03 02 02 01 04 6e .....4fts4.....n | 2464: 75 6d 62 03 06 01 04 09 1b 8c 80 80 80 80 0e 03 umb............. | 2480: 00 3c 00 00 00 16 04 33 74 68 65 03 06 01 01 04 .<.....3the..... | 2496: 01 03 77 68 65 03 02 04 04 0a 1b 8c 80 80 80 80 ..whe........... | 2512: 0d 03 00 3c 00 00 00 16 04 33 6e 75 6d 03 06 01 ...<.....3num... | 2528: 01 05 01 03 74 61 62 03 02 03 04 0a 19 8c 80 80 ....tab......... | 2544: 80 80 0c 03 00 38 00 00 00 14 03 32 77 68 03 02 .....8.....2wh.. | 2560: 04 00 04 33 66 74 73 03 12 02 04 07 18 8c 80 80 ...3fts......... | 2576: 80 80 0b 03 00 36 00 00 00 13 03 32 74 61 03 02 .....6.....2ta.. | 2592: 03 02 01 68 03 06 01 01 04 04 07 1b 8c 80 80 80 ...h............ | 2608: 80 0a 03 00 3c 00 00 00 16 03 32 6e 75 03 06 01 ....<.....2nu... | 2624: 01 05 01 02 6f 66 03 06 01 01 06 04 09 19 8c 80 ....of.......... | 2640: 82 d0 80 09 03 00 38 00 00 00 14 03 32 66 74 03 ......8.....2ft. | 2656: 02 02 01 02 69 73 03 06 01 01 03 04 07 18 8c 80 ....is.......... | 2672: 80 80 80 08 03 00 36 00 00 00 13 02 31 74 03 08 ......6.....1t.. | 2688: 03 01 01 04 01 01 77 03 02 04 04 09 1a 8c 80 80 ......w......... | 2704: 80 80 07 03 00 3a 00 00 00 15 02 31 6e 03 08 01 .....:.....1n... | 2720: 01 02 05 01 01 6f 03 06 01 01 06 04 09 18 8c 80 .....o.......... | 2736: 81 80 80 06 03 00 36 00 00 00 13 04 12 31 66 03 ......6......1f. | 2752: 02 02 01 01 69 03 06 01 01 03 05 06 1c 8c 80 80 ....i........... | 2768: 80 80 05 03 00 3e 00 00 00 17 04 30 74 68 65 03 .....>.....0the. | 2784: 06 01 01 04 01 05 77 68 65 72 65 03 02 04 0a 15 ......where..... | 2800: 8c 80 65 80 80 04 03 00 30 00 00 00 11 01 01 06 ..e.....0....... | 2816: 06 30 74 61 62 6c 65 03 02 03 07 1c 8c 80 80 80 .0table......... | 2832: 80 03 03 00 3e 00 00 00 17 07 30 6e 75 6d 62 65 ....>.....0numbe | 2848: 72 03 06 01 01 05 01 02 6f 66 03 06 04 0d 13 8c r.......of...... | 2864: 80 80 80 80 02 03 00 2c 00 00 00 0f fc 01 03 02 .......,........ | 2880: 30 6e 03 06 01 00 f2 07 1b 8c 80 80 80 80 01 03 0n.............. | 2896: 00 3c 00 00 00 16 08 30 66 74 73 34 61 75 78 03 .<.....0fts4aux. | 2912: 03 02 01 02 69 73 03 06 04 0c 00 00 00 18 ea 00 ....is.......... | 2928: 00 00 01 01 02 24 00 02 01 01 12 02 01 12 08 88 .....$.......... | 2944: 80 80 80 80 12 03 00 12 10 00 00 05 02 1c 88 80 ................ | 2960: 80 80 80 11 03 00 3e 00 00 00 17 05 34 72 6f 77 ......>.....4row | 2976: 73 02 06 01 01 05 01 04 74 68 65 72 02 02 04 0b s.......ther.... | 2992: 15 88 80 80 80 80 10 03 00 2f ff ff f0 11 02 01 ........./...... | 3008: 01 07 05 34 62 65 74 77 02 02 04 08 1b 88 80 80 ...4betw........ | 3024: 80 80 0f cf 00 3c 00 00 00 16 04 04 33 72 6f 77 .....<......3row | 3040: 02 06 01 01 05 01 03 74 68 65 02 08 05 0a 1b 88 .......the...... | 3056: 80 80 80 80 0d 03 00 3c 00 00 00 16 00 01 02 04 .......<........ | 3072: 33 61 72 65 02 02 03 01 03 62 65 74 02 02 07 08 3are.....bet.... | 3088: 1b 88 80 80 80 80 0d 03 00 3c 00 00 00 16 03 32 .........<.....2 | 3104: 74 68 02 08 02 01 01 07 00 04 33 61 6e 64 02 06 th........3and.. | 3120: 04 0a 1b 88 80 80 80 80 0c 03 00 3c 00 00 00 16 ...........<.... | 3136: 03 32 69 6e 02 06 01 01 06 01 02 72 6f 02 06 01 .2in.......ro... | 3152: 01 05 04 09 18 88 80 80 80 80 0b 03 00 36 00 00 .............6.. | 3168: 00 13 02 03 32 61 72 02 02 03 01 02 62 65 02 02 ....2ar.....be.. | 3184: 04 05 07 1b 88 80 80 80 80 0a 03 00 3c 00 00 00 ............<... | 3200: 16 12 31 74 02 08 02 01 01 07 00 03 32 61 6e 02 ..1t........2an. | 3216: 06 01 01 04 09 19 88 80 80 80 80 09 03 00 38 00 ..............8. | 3232: 00 00 14 02 31 6e 02 06 01 01 03 01 01 72 02 06 ....1n.......r.. | 3248: 01 01 05 04 08 17 78 80 80 80 80 08 03 00 34 10 ......x.......4. | 3264: 01 00 12 02 31 62 02 02 04 01 01 69 02 06 01 01 ....1b.....i.... | 3280: 06 04 06 19 88 80 80 80 80 07 03 00 38 00 00 00 ............8... | 3296: 14 04 02 31 32 02 02 05 01 01 61 02 08 03 01 01 ...12.....a..... | 3312: 02 05 06 1b 88 80 80 80 80 06 03 00 3c 00 00 00 ............<... | 3328: 16 06 30 74 68 65 72 65 e7 02 02 00 02 31 31 02 ..0there.....11. | 3344: 06 01 01 04 0a 15 88 80 80 80 80 05 03 00 30 00 ..............0. | 3360: 00 00 11 01 01 05 e5 30 74 68 65 02 06 01 01 07 .......0the..... | 3376: 07 1c 88 80 80 80 80 04 03 00 3e 00 00 00 17 01 ..........>..... | 3392: 01 06 02 30 6e 02 06 01 01 03 01 04 72 6f 77 73 ...0n.......rows | 3408: 02 06 07 08 1b 88 80 80 80 80 03 03 00 3c 00 00 .............<.. | 3424: 00 16 08 30 62 65 74 77 65 65 6e 02 02 04 01 02 ...0between..... | 3440: 69 6e 02 06 04 0c 1a 88 80 80 80 80 02 03 00 3a in.............: | 3456: 00 00 00 15 04 30 61 6e 64 02 06 01 01 02 02 02 .....0and....... | 3472: 72 65 02 02 03 04 0a 17 88 80 80 80 80 01 03 00 re.............. | 3488: 34 01 00 00 12 02 30 31 02 06 01 01 04 01 01 32 4.....01.......2 | 3504: 02 02 05 04 08 08 84 80 80 80 80 12 03 00 16 00 ................ | 3520: 00 00 05 04 1b 84 80 80 80 80 11 03 00 3c 00 00 .............<.. | 3536: 00 16 05 34 74 61 62 6c 01 06 01 01 05 02 03 65 ...4tabl.......e | 3552: 72 6d 01 02 04 0b 1b 84 80 80 80 80 10 03 00 3c rm.............< | 3568: 00 00 00 16 05 34 65 61 63 68 01 02 02 01 04 70 .....4each.....p | 3584: 72 65 73 01 02 05 04 09 1a 84 80 80 80 80 0f 03 res............. | 3600: 00 3a 00 00 00 15 04 33 74 65 72 01 02 04 02 02 .:.....3ter..... | 3616: 68 65 01 06 01 01 03 04 08 1b 84 80 80 80 80 0e he.............. | 3632: 03 00 3c 00 00 00 16 04 33 70 72 65 01 02 05 01 ..<.....3pre.... | 3648: 03 74 61 62 01 06 01 01 05 04 08 1a 84 80 80 80 .tab............ | 3664: 80 0d 03 0d 1a 00 00 00 15 04 33 66 6e 72 01 02 ..........3fnr.. | 3680: 02 02 02 74 73 01 06 01 01 04 04 08 1b 84 80 80 ...ts........... | 3696: 80 80 0c 03 00 3c 00 00 00 16 03 32 74 68 01 06 .....<.....2th.. | 3712: 01 01 03 00 04 33 65 61 63 01 02 03 04 09 18 84 .....3eac....... | 3728: 80 80 80 80 0b 03 00 36 00 00 00 13 03 32 74 61 .......6.....2ta | 3744: 01 06 01 01 05 02 01 65 01 02 04 04 09 19 84 80 .......e........ | 3760: 80 80 80 0a 03 00 38 00 00 00 14 03 30 c9 6e 01 ......8.....0.n. | 3776: 06 01 01 02 01 02 70 72 01 02 05 04 09 18 84 80 ......pr........ | 3792: 80 80 80 09 03 00 36 00 00 00 13 03 32 66 6f 01 ......6.....2fo. | 3808: 02 0b e2 01 74 01 06 01 01 04 04 07 1b 84 80 80 ....t........... | 3824: 86 f0 08 03 00 3c 00 00 00 16 02 31 74 01 0a 04 .....<.....1t... | 3840: 01 01 03 04 00 03 32 65 61 01 02 03 04 0a 17 84 ......2ea....... | 3856: 80 80 80 80 07 03 00 34 00 00 00 12 02 31 69 01 .......4.....1i. | 3872: 06 01 01 02 01 01 70 01 02 05 04 08 18 84 80 80 ......p......... | 3888: 80 80 06 03 00 36 00 00 00 13 02 31 65 01 02 03 .....6.....1e... | 3904: 01 01 66 01 08 02 01 01 04 04 06 1b 84 80 80 80 ..f............. | 3920: 80 05 03 00 3c 00 00 00 16 05 30 74 65 72 6d 01 ....<.....0term. | 3936: 02 04 02 02 68 65 01 06 01 01 03 04 09 14 84 80 ....he.......... | 3952: 80 80 80 04 03 00 2e 00 00 00 10 06 30 74 61 62 ............0tab | 3968: 6c 65 01 06 01 01 05 04 15 84 7f 80 80 80 03 03 le.............. | 3984: 00 30 00 00 00 11 02 08 30 70 72 65 73 65 6e 74 .0......0present | 4000: 01 02 05 05 1b 84 80 22 80 80 02 03 00 3c 00 00 .............<.. | 4016: 00 16 04 30 66 74 73 01 06 01 01 04 01 02 69 6e ...0fts.......in | 4032: 01 06 01 01 04 0a 1a 84 80 80 80 80 01 03 00 3a ...............: | 4048: 00 00 00 15 05 30 65 61 63 68 01 02 03 01 03 66 .....0each.....f | 4064: 6f 72 01 02 02 04 09 06 01 03 00 12 03 0b 0f 00 or.............. | 4080: 00 08 8c 80 80 80 80 11 03 00 16 00 00 00 05 04 ................ | page 3 offset 8192 | 0: 0a 00 00 00 32 0e 4f 00 0f fa 0f f1 0f e9 0f e1 ....2.O......... | 16: 0f d8 0f d1 0f c9 0f c1 0f b9 0f b1 0f a9 0f a0 ................ | 32: 0f 98 0f 90 0f 87 0f 80 0f 78 0f 71 0f 68 0f 5f .........x.q.h._ | 48: 0f 56 0f 00 00 00 00 00 00 00 00 00 00 00 00 00 .V.............. | 3392: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 08 ................ | 3408: 04 01 10 01 03 34 74 20 07 04 01 0e 01 03 34 1e .....4t ......4. | 3424: 09 04 01 12 01 03 33 74 68 1c 08 04 01 10 01 03 ......3th....... | 3440: 34 6e 1a 08 04 01 10 01 03 32 67 18 08 04 01 10 4n.......2g..... | 3456: 01 03 32 74 16 08 04 01 10 01 03 32 6e 14 07 04 ..2t.......2n... | 3472: 01 0e 01 03 32 12 08 04 01 10 01 03 31 74 10 08 ....2.......1t.. | 3488: 04 01 10 01 03 31 6e 0e 07 04 01 0e 01 03 31 0c .....1n.......1. | 3504: 09 04 01 12 01 03 30 74 68 0a 08 04 01 10 01 03 ......0th....... | 3520: 30 74 08 09 04 01 12 01 03 30 6e 75 06 08 04 01 0t.......0nu.... | 3536: 10 01 03 30 6e 04 06 04 01 0c 01 03 02 08 04 01 ...0n........... | 3552: 10 01 02 34 72 22 07 04 01 0e 01 02 34 20 08 04 ...4r.......4 .. | 3568: 01 10 01 02 33 72 1e 09 04 01 12 01 02 33 61 72 ....3r.......3ar | 3584: 1c 18 04 01 10 01 02 32 74 1a 08 04 01 10 01 02 .......2t....... | 3600: 32 69 18 09 04 01 12 01 02 32 61 72 16 08 04 01 2i.......2ar.... | 3616: 10 01 02 31 74 2a 08 04 01 0f 01 02 31 6e 12 0a ...1t*......1n.. | 3632: d4 01 10 01 02 31 62 10 08 04 01 10 01 02 31 32 .....1b.......12 | 3648: 0e 0b 04 01 16 01 02 30 74 68 65 72 0c 08 04 01 .......0ther.... | 3664: 10 01 02 30 74 0a 08 04 01 10 01 02 30 6e 08 08 ...0t.......0n.. | 3680: 04 01 10 01 02 30 62 06 08 04 01 10 01 02 30 61 .....0b.......0a | 3696: 04 06 03 f1 0c 01 02 02 07 04 09 10 01 34 74 22 .............4t. | 3712: 06 04 09 0e 01 34 20 08 04 09 12 01 33 74 65 1e .....4 .....3te. | 3728: 07 04 09 10 01 33 70 1c 07 04 09 10 01 33 66 1a .....3p......3f. | 3744: 08 04 09 12 01 32 74 68 18 07 04 09 10 01 32 74 .....2th......2t | 3760: 16 07 04 09 10 01 32 69 14 07 04 09 10 01 32 66 ......2i......2f | 3776: 12 07 04 09 10 01 31 74 10 07 04 09 10 01 31 69 ......1t......1i | 3792: 0e 06 04 09 0e 01 31 0c 08 04 09 12 01 30 74 65 ......1......0te | 3808: 0a 07 04 09 10 01 30 74 08 07 04 09 10 01 30 70 ......0t......0p | 3824: 06 08 04 09 1e 61 30 66 74 04 05 00 00 00 00 00 .....a0ft....... | page 4 offset 12288 | 4064: 00 00 00 00 00 00 00 00 00 00 00 05 03 03 00 10 ................ | 4080: 03 05 05 02 03 00 10 04 06 05 01 03 00 10 04 04 ................ | page 5 offset 16384 | 0: 0a 00 00 00 02 0f eb 00 0f eb 0f f4 00 00 00 00 ................ | 4064: 00 00 00 00 00 00 00 00 00 00 00 08 03 15 01 70 ...............p | 4080: 67 73 7a 18 0b 03 1b 01 76 65 72 73 69 6f 6e 04 gsz.....version. | end crash-ef6738247b1344.db }]} {} do_catchsql_test 4.1 { BEGIN; REPLACE INTO t1(rowid,b,a,rowid) VALUES(200,1,2,3); } {1 {database disk image is malformed}} do_catchsql_test 4.2 { INSERT INTO t1(t1) VALUES('delete-all'); } {1 {database disk image is malformed}} do_catchsql_test 4.3 { REPLACE INTO t1(rowid,b,rowid,a) VALUES(200,1,2,3); } {1 {database disk image is malformed}} do_catchsql_test 4.4 { REPLACE INTO t1(rowid,b,a,rowid) VALUES(0,1,2,3); } {1 {database disk image is malformed}} do_catchsql_test 4.5 { REPLACE INTO t1(rowid,a,b,rowid) VALUES(200,1,2,3); } {1 {database disk image is malformed}} sqlite3_fts5_may_be_corrupt 0 finish_test |
Changes to ext/fts5/test/fts5delete.test.
︙ | ︙ | |||
45 46 47 48 49 50 51 52 53 | do_test 1.2 { execsql { INSERT INTO t1(t1, rank) VALUES('usermerge', 2); } for {set i 0} {$i < 5} {incr i} { execsql { INSERT INTO t1(t1, rank) VALUES('merge', 1) } execsql { INSERT INTO t1(t1) VALUES('integrity-check') } } } {} finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 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 | do_test 1.2 { execsql { INSERT INTO t1(t1, rank) VALUES('usermerge', 2); } for {set i 0} {$i < 5} {incr i} { execsql { INSERT INTO t1(t1, rank) VALUES('merge', 1) } execsql { INSERT INTO t1(t1) VALUES('integrity-check') } } } {} #------------------------------------------------------------------------- reset_db do_execsql_test 2.0 { CREATE TABLE test ( id INTEGER PRIMARY KEY, name TEXT, value TEXT ); CREATE VIRTUAL TABLE test_idx USING fts5( name, content=test, content_rowid=id ); } do_catchsql_test 2.1 { INSERT INTO test_idx (test_idx, rowid, name) VALUES('delete', 1, 'quick'); } {1 {database disk image is malformed}} do_catchsql_test 2.2 { INSERT INTO test_idx(rowid, name) VALUES(123, 'one one one'); INSERT INTO test_idx (test_idx, rowid, name) VALUES('delete', 123, 'one'); INSERT INTO test_idx (test_idx, rowid, name) VALUES('delete', 123, 'one'); } {1 {database disk image is malformed}} do_execsql_test 2.3 { DROP TABLE test_idx; CREATE VIRTUAL TABLE test_idx USING fts5( name, content=test, content_rowid=id ); INSERT INTO test_idx(rowid, name) VALUES(123, 'one one one'); INSERT INTO test_idx(rowid, name) VALUES(124, 'two two two'); INSERT INTO test_idx(rowid, name) VALUES(125, 'two two two'); INSERT INTO test_idx (test_idx, rowid, name) VALUES('delete', 123, 'one'); INSERT INTO test_idx (test_idx, rowid, name) VALUES('delete', 123, 'one'); INSERT INTO test_idx (test_idx, rowid, name) VALUES('delete', 123, 'one'); } do_catchsql_test 2.4 { SELECT rowid FROM test_idx WHERE test_idx MATCH 'two' ORDER BY rank; } {1 {database disk image is malformed}} #------------------------------------------------------------------------- reset_db do_execsql_test 3.0 { CREATE VIRTUAL TABLE tx USING fts5(a, b, c, d, content=); INSERT INTO tx(rowid, a, c) VALUES(1, 'abc def', 'a b c'); INSERT INTO tx(rowid, a, c) VALUES(5, 'a b c', 'a b d def'); } do_execsql_test 3.1 { INSERT INTO tx(tx, rowid, a, b, c, d) VALUES('delete', 5, 'a b c', NULL, 'a b d def', NULL); } do_execsql_test 3.2 { INSERT INTO tx(tx) VALUES('integrity-check'); } do_execsql_test 3.3 { INSERT INTO tx(tx, rowid, a, b, c, d) VALUES('delete', 1, 'abc def', NULL, 'a b c', NULL); } do_execsql_test 3.4 { INSERT INTO tx(tx) VALUES('integrity-check'); } finish_test |
Changes to ext/fts5/test/fts5detail.test.
︙ | ︙ | |||
208 209 210 211 212 213 214 215 216 217 218 219 220 221 | INSERT INTO t4 VALUES('1 2 3', '4 5 6', '7 8 9'); } do_catchsql_test 4.1 { SELECT * FROM t4('a:a') } {1 {fts5: column queries are not supported (detail=none)}} #------------------------------------------------------------------------- # Test that for the same content detail=none uses less space than # detail=col, and that detail=col uses less space than detail=full # reset_db do_test 5.1 { foreach {tbl detail} {t1 none t2 col t3 full} { | > > > > | 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 | INSERT INTO t4 VALUES('1 2 3', '4 5 6', '7 8 9'); } do_catchsql_test 4.1 { SELECT * FROM t4('a:a') } {1 {fts5: column queries are not supported (detail=none)}} do_catchsql_test 4.2 { SELECT * FROM t4('a:a &') } {1 {fts5: syntax error near "&"}} #------------------------------------------------------------------------- # Test that for the same content detail=none uses less space than # detail=col, and that detail=col uses less space than detail=full # reset_db do_test 5.1 { foreach {tbl detail} {t1 none t2 col t3 full} { |
︙ | ︙ |
Changes to ext/fts5/test/fts5doclist.test.
︙ | ︙ | |||
38 39 40 41 42 43 44 45 46 | INSERT INTO ccc(x899) SELECT rnddoc(500) FROM ii; } do_execsql_test 1.2 { INSERT INTO ccc(ccc) VALUES('integrity-check'); } finish_test | > > > > > > > > > > > > > > > > > > > > > | 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 | INSERT INTO ccc(x899) SELECT rnddoc(500) FROM ii; } do_execsql_test 1.2 { INSERT INTO ccc(ccc) VALUES('integrity-check'); } #------------------------------------------------------------------------- # reset_db do_execsql_test 2.1 { CREATE VIRTUAL TABLE tx USING fts5(x); } set doc [string repeat "abc " 5000] do_execsql_test 2.2 { BEGIN; INSERT INTO tx(rowid, x) VALUES(-9000000000000000000, $doc); INSERT INTO tx(rowid, x) VALUES(9000000000000000000, $doc); COMMIT; } do_execsql_test 2.3 { SELECT rowid FROM tx('abc'); } { -9000000000000000000 9000000000000000000 } finish_test |
Changes to ext/fts5/test/fts5eb.test.
︙ | ︙ | |||
55 56 57 58 59 60 61 | do_execsql_test 1.$tn {SELECT fts5_expr($expr)} [list $res] } do_catchsql_test 2.1 { SELECT fts5_expr() } {1 {wrong number of arguments to function fts5_expr}} | | > > > > > > > > > > > > > > > > > | 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 | do_execsql_test 1.$tn {SELECT fts5_expr($expr)} [list $res] } do_catchsql_test 2.1 { SELECT fts5_expr() } {1 {wrong number of arguments to function fts5_expr}} do_catchsql_test 2.2 { SELECT fts5_expr_tcl() } {1 {wrong number of arguments to function fts5_expr_tcl}} do_catchsql_test 2.3 { SELECT fts5_expr('') } {1 {fts5: syntax error near ""}} do_catchsql_test 2.4 { SELECT fts5_expr(NULL) } {1 {fts5: syntax error near ""}} do_catchsql_test 2.5 { SELECT fts5_expr(NULL, NULL) } {1 {parse error in ""}} for {set i 0} {$i < 255} {incr i} { do_test 2.6.$i { lindex [catchsql {sELECT fts5_expr(NULL, char($i));}] 0 } 1 } do_execsql_test 3.0 { CREATE VIRTUAL TABLE e1 USING fts5(text, tokenize = 'porter unicode61'); INSERT INTO e1 VALUES ("just a few words with a / inside"); } do_execsql_test 3.1 { SELECT rowid, bm25(e1) FROM e1 WHERE e1 MATCH '"just"' ORDER BY rank; |
︙ | ︙ |
Changes to ext/fts5/test/fts5faultB.test.
︙ | ︙ | |||
142 143 144 145 146 147 148 149 150 151 | INSERT INTO t1 VALUES('b c d a'); -- 4 } do_faultsim_test 5.1 -faults oom* -body { execsql { SELECT rowid FROM t1('^a OR ^b') } } -test { faultsim_test_result {0 {1 4}} } 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 169 170 171 172 173 | INSERT INTO t1 VALUES('b c d a'); -- 4 } do_faultsim_test 5.1 -faults oom* -body { execsql { SELECT rowid FROM t1('^a OR ^b') } } -test { faultsim_test_result {0 {1 4}} } #------------------------------------------------------------------------- # Test OOM injection in a query with two MATCH expressions # reset_db do_execsql_test 6.0 { CREATE VIRTUAL TABLE t1 USING fts5(a); INSERT INTO t1 VALUES('a b c d'); -- 1 INSERT INTO t1 VALUES('d a b c'); -- 2 INSERT INTO t1 VALUES('c d a b'); -- 3 INSERT INTO t1 VALUES('b c d a'); -- 4 } do_faultsim_test 6.1 -faults oom* -body { execsql { SELECT rowid FROM t1 WHERE t1 MATCH 'a' AND t1 MATCH 'b' } } -test { faultsim_test_result {0 {1 2 3 4}} } do_faultsim_test 6.2 -faults oom* -body { execsql { SELECT rowid FROM t1 WHERE t1 MATCH 'a OR b' AND t1 MATCH 'c OR d' } } -test { faultsim_test_result {0 {1 2 3 4}} } finish_test |
Changes to ext/fts5/test/fts5faultD.test.
︙ | ︙ | |||
10 11 12 13 14 15 16 | #************************************************************************* # # This file is focused on OOM errors. # source [file join [file dirname [info script]] fts5_common.tcl] source $testdir/malloc_common.tcl | | | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | #************************************************************************* # # This file is focused on OOM errors. # source [file join [file dirname [info script]] fts5_common.tcl] source $testdir/malloc_common.tcl set testprefix fts5faultD # If SQLITE_ENABLE_FTS3 is defined, omit this file. ifcapable !fts5 { finish_test return } |
︙ | ︙ |
Added ext/fts5/test/fts5faultE.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 | # 2016 February 2 # # 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 is focused on OOM errors. # source [file join [file dirname [info script]] fts5_common.tcl] source $testdir/malloc_common.tcl set testprefix fts5faultE # If SQLITE_ENABLE_FTS5 is not defined, omit this file. ifcapable !fts5 { finish_test return } faultsim_save_and_close do_faultsim_test 1 -prep { faultsim_restore_and_reopen } -body { execsql { CREATE VIRTUAL TABLE t1 USING fts5(x, y, tokenize=trigram) } } -test { faultsim_test_result {0 {}} {1 {vtable constructor failed: t1}} } reset_db do_execsql_test 2.0 { CREATE VIRTUAL TABLE t1 USING fts5(x, y, tokenize=trigram); } faultsim_save_and_close do_faultsim_test 2 -prep { faultsim_restore_and_reopen } -body { execsql { INSERT INTO t1 VALUES('abcdefghijklmnopqrstuvwxyz', NULL); SELECT count(*) FROM t1 WHERE x LIKE '%mnop%' AND t1 MATCH 'jkl'; } } -test { faultsim_test_result {0 1} {1 {vtable constructor failed: t1}} } reset_db do_execsql_test 3.0 { CREATE VIRTUAL TABLE t1 USING fts5(x, y, tokenize=trigram, detail=none); INSERT INTO t1 VALUES('abcdefghijklmnopqrstuvwxyz', NULL); } faultsim_save_and_close do_faultsim_test 3 -prep { faultsim_restore_and_reopen } -body { execsql { SELECT count(*) FROM t1 WHERE x LIKE '%mnopqrs%' AND t1 MATCH 'abc' } } -test { faultsim_test_result {0 1} {1 {vtable constructor failed: t1}} } finish_test |
Changes to ext/fts5/test/fts5full.test.
︙ | ︙ | |||
32 33 34 35 36 37 38 | db func rnddoc fts5_rnddoc do_test 1.1 { list [catch { for {set i 0} {$i < 2500} {incr i} { execsql { INSERT INTO x8 VALUES( rnddoc(5) ); } } } msg] $msg | | | 32 33 34 35 36 37 38 39 40 41 42 | db func rnddoc fts5_rnddoc do_test 1.1 { list [catch { for {set i 0} {$i < 2500} {incr i} { execsql { INSERT INTO x8 VALUES( rnddoc(5) ); } } } msg] $msg } {0 {}} finish_test |
Changes to ext/fts5/test/fts5hash.test.
︙ | ︙ | |||
108 109 110 111 112 113 114 | INSERT INTO eee(eee) VALUES('integrity-check'); } #----------------------------------------------------------------------- # Add a small and very large token with the same hash value to an # empty table. At one point this would provoke an asan error. # | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | INSERT INTO eee(eee) VALUES('integrity-check'); } #----------------------------------------------------------------------- # Add a small and very large token with the same hash value to an # empty table. At one point this would provoke an asan error. # do_test 1.5 { set big [string repeat 12345 40] set hash [sqlite3_fts5_token_hash 1024 $big] while {1} { set small [random_token] if {[sqlite3_fts5_token_hash 1024 $small]==$hash} break } execsql { CREATE VIRTUAL TABLE t2 USING fts5(x, detail=%DETAIL%) } execsql { INSERT INTO t2 VALUES($small || ' ' || $big); } } {} } ;# foreach_detail_mode #------------------------------------------------------------------------- reset_db do_execsql_test 2.1 { CREATE VIRTUAL TABLE t1 USING fts5(x); INSERT INTO t1(t1, rank) VALUES('hashsize', 1024); INSERT INTO t1(t1, rank) VALUES('automerge', 0); INSERT INTO t1(t1, rank) VALUES('crisismerge', 1000); } do_execsql_test 2.2 { BEGIN; INSERT INTO t1 VALUES('abc def ghi'); SELECT count(*) FROM t1_data; } {2} do_execsql_test 2.3 { WITH s(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<1024 ) INSERT INTO t1 SELECT 'abc def ghi' FROM s; SELECT (SELECT count(*) FROM t1_data) > 10; } {1} do_execsql_test 2.4 { COMMIT; DROP TABLE t1; CREATE VIRTUAL TABLE t1 USING fts5(x); INSERT INTO t1(t1, rank) VALUES('hashsize', 1024); INSERT INTO t1(t1, rank) VALUES('automerge', 0); INSERT INTO t1(t1, rank) VALUES('crisismerge', 1000); WITH s(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<1024 ) INSERT INTO t1 SELECT 'abc' || i || ' def' || i || ' ghi' || i FROM s; SELECT (SELECT count(*) FROM t1_data) > 100; } {1} finish_test |
Changes to ext/fts5/test/fts5integrity.test.
︙ | ︙ | |||
205 206 207 208 209 210 211 212 213 | set res [db eval { SELECT rowid FROM hh($T) ORDER BY rowid ASC }] set res2 [db eval { SELECT rowid FROM hh($T) ORDER BY rowid DESC }] if {$res == [lsort -integer $res2]} { incr ok } } set ok } {1000} } finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | set res [db eval { SELECT rowid FROM hh($T) ORDER BY rowid ASC }] set res2 [db eval { SELECT rowid FROM hh($T) ORDER BY rowid DESC }] if {$res == [lsort -integer $res2]} { incr ok } } set ok } {1000} } #------------------------------------------------------------------------- # reset_db do_execsql_test 7.0 { PRAGMA encoding = 'UTF-16'; CREATE VIRTUAL TABLE vt0 USING fts5(c0); INSERT INTO vt0 VALUES (x'46f0'); SELECT quote(c0) FROM vt0; } {X'46F0'} do_execsql_test 7.1 { INSERT INTO vt0(vt0) VALUES('integrity-check'); } do_execsql_test 7.2 { INSERT INTO vt0(vt0) VALUES('rebuild'); } do_execsql_test 7.3 { INSERT INTO vt0(vt0) VALUES('integrity-check'); } do_execsql_test 7.4 { UPDATE vt0 SET c0=''; } do_execsql_test 7.5 { INSERT INTO vt0(vt0) VALUES('integrity-check'); } #------------------------------------------------------------------------- # Ticket 7a458c2a5f4 # reset_db do_execsql_test 8.0 { PRAGMA locking_mode = EXCLUSIVE; PRAGMA journal_mode = PERSIST; CREATE VIRTUAL TABLE vt0 USING fts5(c0); } {exclusive persist} do_execsql_test 8.1 { PRAGMA data_version } {1} do_execsql_test 8.2 { INSERT INTO vt0(vt0) VALUES('integrity-check'); PRAGMA data_version; } {1} do_execsql_test 8.1 { INSERT INTO vt0(vt0, rank) VALUES('usermerge', 2); } #------------------------------------------------------------------------- # Ticket [771fe617] # reset_db do_execsql_test 9.0 { PRAGMA encoding = 'UTF16'; CREATE VIRTUAL TABLE vt0 USING fts5(c0); } #explain_i { SELECT quote(SUBSTR(x'37', 0)); } #execsql { PRAGMA vdbe_trace = 1 } do_execsql_test 9.1.1 { SELECT quote(SUBSTR(x'37', 0)); } {X'37'} do_execsql_test 9.1.2 { SELECT quote(x'37'); } {X'37'} do_execsql_test 9.2 { INSERT INTO vt0 VALUES (SUBSTR(x'37', 0)); -- INSERT INTO vt0 VALUES (x'37'); } do_execsql_test 9.3 { INSERT INTO vt0(vt0) VALUES('integrity-check'); } #------------------------------------------------------------------------- reset_db do_execsql_test 10.0 { CREATE TABLE t1(i INTEGER PRIMARY KEY, a, b); CREATE VIRTUAL TABLE vt0 USING fts5(a, b, content=t1); INSERT INTO vt0(rowid, a, b) VALUES(1, 'abc', 'def'); } do_catchsql_test 10.1 { INSERT INTO vt0(vt0) VALUES('integrity-check'); } {0 {}} do_catchsql_test 10.2 { INSERT INTO vt0(vt0, rank) VALUES('integrity-check', 0); } {0 {}} do_catchsql_test 10.3 { INSERT INTO vt0(vt0, rank) VALUES('integrity-check', 1); } {1 {database disk image is malformed}} do_catchsql_test 10.3 { INSERT INTO t1 VALUES(1, 'abc', 'def'); INSERT INTO vt0(vt0, rank) VALUES('integrity-check', 1); } {0 {}} do_execsql_test 10.4 { CREATE VIRTUAL TABLE vt1 USING fts5(a, b, content=); INSERT INTO vt1(rowid, a, b) VALUES(1, 'abc', 'def'); } do_catchsql_test 10.5.1 { INSERT INTO vt0(vt0, rank) VALUES('integrity-check', 0); } {0 {}} do_catchsql_test 10.5.2 { INSERT INTO vt0(vt0, rank) VALUES('integrity-check', 1); } {0 {}} do_catchsql_test 10.5.3 { INSERT INTO vt0(vt0) VALUES('integrity-check'); } {0 {}} finish_test |
Added ext/fts5/test/fts5interrupt.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 | # 2019 Jan 4 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #************************************************************************* # This file implements regression tests for SQLite library. The # focus of this script is testing the FTS5 module. # source [file join [file dirname [info script]] fts5_common.tcl] set testprefix fts5interrupt # If SQLITE_ENABLE_FTS5 is not defined, omit this file. ifcapable !fts5 { finish_test return } do_execsql_test 1.0 { CREATE VIRTUAL TABLE t1 USING fts5(a); INSERT INTO t1(t1, rank) VALUES('pgsz', 40); } db_save_and_close proc progress_handler {args} { incr ::progress_handler_delay -1 if {$::progress_handler_delay<=0} { return 1 } return 0 } foreach {tn sql} { 1 { INSERT INTO t1(rowid, a) VALUES(0, 'z z z z') } 2 { COMMIT } } { set bDone 0 for {set i 1} {$bDone==0} {incr i} { do_test 1.$tn.$i { db_restore_and_reopen execsql { BEGIN; INSERT INTO t1(rowid, a) VALUES(1, 'a b c d'); INSERT INTO t1(rowid, a) VALUES(2, 'd e f g'); INSERT INTO t1(rowid, a) VALUES(3, 'h i j k'); INSERT INTO t1(rowid, a) VALUES(4, 'l m n o'); } set ::progress_handler_delay $i db progress 1 progress_handler set res [catchsql $sql] db close if {$res=="0 {}"} { set bDone 1 } else { if {$res!="1 interrupted"} { error "got: $res" } } set {} {} } {} } } finish_test |
Changes to ext/fts5/test/fts5matchinfo.test.
︙ | ︙ | |||
486 487 488 489 490 491 492 493 494 | CREATE VIRTUAL TABLE x1 USING fts5(z); INSERT INTO x1 VALUES('a b c a b c a b c'); } {} do_catchsql_test 14.2 { SELECT matchinfo(x1, 'd') FROM x1('a b c'); } {1 {unrecognized matchinfo flag: d}} finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | CREATE VIRTUAL TABLE x1 USING fts5(z); INSERT INTO x1 VALUES('a b c a b c a b c'); } {} do_catchsql_test 14.2 { SELECT matchinfo(x1, 'd') FROM x1('a b c'); } {1 {unrecognized matchinfo flag: d}} #------------------------------------------------------------------------- # Test using matchinfo() and similar on a non-full-text query # do_execsql_test 15.0 { CREATE VIRTUAL TABLE t1 USING fts5(x, y); INSERT INTO t1 VALUES('a', 'b'); INSERT INTO t1 VALUES('c', 'd'); } if {$tcl_platform(byteOrder)=="littleEndian"} { set res {X'02000000'} } else { set res {X'00000002'} } do_execsql_test 15.1 { SELECT quote(matchinfo(t1, 'n')) FROM t1 LIMIT 1; } $res do_execsql_test 15.2 { DELETE FROM t1_content WHERE rowid=1; SELECT quote(matchinfo(t1, 'n')) FROM t1 LIMIT 1; } $res fts5_aux_test_functions db do_execsql_test 15.3 { SELECT fts5_test_all(t1) FROM t1 LIMIT 1; } { {columnsize {0 0} columntext {c d} columntotalsize {2 2} poslist {} tokenize {c d} rowcount 2} } finish_test |
Added ext/fts5/test/fts5misc.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 | # 2019 September 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 implements regression tests for SQLite library. The # focus of this script is testing the FTS5 module. # source [file join [file dirname [info script]] fts5_common.tcl] set testprefix fts5misc # If SQLITE_ENABLE_FTS5 is not defined, omit this file. ifcapable !fts5 { finish_test return } do_execsql_test 1.0 { CREATE VIRTUAL TABLE t1 USING fts5(a); } do_catchsql_test 1.1.1 { SELECT highlight(t1, 4, '<b>', '</b>') FROM t1('*'); } {1 {unknown special query: }} do_catchsql_test 1.1.2 { SELECT a FROM t1 WHERE rank = (SELECT highlight(t1, 4, '<b>', '</b>') FROM t1('*')); } {1 {unknown special query: }} do_catchsql_test 1.2.1 { SELECT highlight(t1, 4, '<b>', '</b>') FROM t1('*id'); } {0 {{}}} do_catchsql_test 1.2.2 { SELECT a FROM t1 WHERE rank = (SELECT highlight(t1, 4, '<b>', '</b>') FROM t1('*id')); } {0 {}} do_catchsql_test 1.3.1 { SELECT highlight(t1, 4, '<b>', '</b>') FROM t1('*reads'); } {1 {no such cursor: 1}} do_catchsql_test 1.3.2 { SELECT a FROM t1 WHERE rank = (SELECT highlight(t1, 4, '<b>', '</b>') FROM t1('*reads')); } {1 {no such cursor: 1}} db close sqlite3 db test.db do_catchsql_test 1.3.3 { SELECT a FROM t1 WHERE rank = (SELECT highlight(t1, 4, '<b>', '</b>') FROM t1('*reads')); } {1 {no such cursor: 1}} #------------------------------------------------------------------------- reset_db do_execsql_test 2.0 { CREATE TABLE t0(c0); CREATE VIRTUAL TABLE vt0 USING fts5(c0); } do_execsql_test 2.1.1 { BEGIN TRANSACTION; INSERT INTO vt0(c0) VALUES ('xyz'); } do_execsql_test 2.1.2 { ALTER TABLE t0 ADD COLUMN c5; } do_execsql_test 2.1.3 { INSERT INTO vt0(vt0) VALUES('integrity-check'); } do_execsql_test 2.1.4 { INSERT INTO vt0(c0) VALUES ('abc'); COMMIT } do_execsql_test 2.1.5 { INSERT INTO vt0(vt0) VALUES('integrity-check'); } reset_db do_execsql_test 2.2.1 { CREATE TABLE t0(c0); CREATE VIRTUAL TABLE vt0 USING fts5(c0); BEGIN TRANSACTION; INSERT INTO vt0(c0) VALUES ('xyz'); } breakpoint do_execsql_test 2.2.2 { ALTER TABLE t0 RENAME TO t1; } do_execsql_test 2.2.3 { INSERT INTO vt0(vt0) VALUES('integrity-check'); } do_execsql_test 2.2.4 { INSERT INTO vt0(c0) VALUES ('abc'); COMMIT; } do_execsql_test 2.2.5 { INSERT INTO vt0(vt0) VALUES('integrity-check'); } #------------------------------------------------------------------------- reset_db do_execsql_test 3.0 { CREATE VIRTUAL TABLE vt0 USING fts5(a); PRAGMA reverse_unordered_selects = true; INSERT INTO vt0 VALUES('365062398'), (0), (0); INSERT INTO vt0(vt0, rank) VALUES('pgsz', '38'); } do_execsql_test 3.1 { UPDATE vt0 SET a = 399905135; -- unexpected: database disk image is malformed } do_execsql_test 3.2 { INSERT INTO vt0(vt0) VALUES('integrity-check'); } #------------------------------------------------------------------------- reset_db do_execsql_test 4.0 { CREATE VIRTUAL TABLE vt0 USING fts5(c0); INSERT INTO vt0(c0) VALUES ('xyz'); } do_execsql_test 4.1 { BEGIN; INSERT INTO vt0(c0) VALUES ('abc'); INSERT INTO vt0(vt0) VALUES('rebuild'); COMMIT; } do_execsql_test 4.2 { INSERT INTO vt0(vt0) VALUES('integrity-check'); } do_execsql_test 4.3 { BEGIN; INSERT INTO vt0(vt0) VALUES('rebuild'); INSERT INTO vt0(vt0) VALUES('rebuild'); COMMIT; } do_execsql_test 4.4 { INSERT INTO vt0(vt0) VALUES('integrity-check'); } #------------------------------------------------------------------------- # Ticket [81a7f7b9]. # reset_db do_execsql_test 5.0 { CREATE VIRTUAL TABLE vt0 USING fts5(c0, c1); INSERT INTO vt0(vt0, rank) VALUES('pgsz', '65536'); WITH s(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<1236 ) INSERT INTO vt0(c0) SELECT '0' FROM s; } {} do_execsql_test 5.1 { UPDATE vt0 SET c1 = 'T,D&p^y/7#3*v<b<4j7|f'; } do_execsql_test 5.2 { INSERT INTO vt0(vt0) VALUES('integrity-check'); } do_catchsql_test 5.3 { INSERT INTO vt0(vt0, rank) VALUES('pgsz', '65537'); } {1 {SQL logic error}} #------------------------------------------------------------------------- # Ticket [d392017c]. # reset_db do_execsql_test 6.0 { CREATE VIRTUAL TABLE vt0 USING fts5(c0); WITH s(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<10000 ) INSERT INTO vt0(c0) SELECT '0' FROM s; INSERT INTO vt0(vt0, rank) VALUES('crisismerge', 2000); INSERT INTO vt0(vt0, rank) VALUES('automerge', 0); } {} do_execsql_test 6.1 { INSERT INTO vt0(vt0) VALUES('rebuild'); } #------------------------------------------------------------------------- # reset_db do_execsql_test 7.0 { CREATE VIRTUAL TABLE t1 USING fts5(x); INSERT INTO t1(rowid, x) VALUES(1, 'hello world'); INSERT INTO t1(rowid, x) VALUES(2, 'well said'); INSERT INTO t1(rowid, x) VALUES(3, 'hello said'); INSERT INTO t1(rowid, x) VALUES(4, 'well world'); CREATE TABLE t2 (a, b); INSERT INTO t2 VALUES(1, 'hello'); INSERT INTO t2 VALUES(2, 'world'); INSERT INTO t2 VALUES(3, 'said'); INSERT INTO t2 VALUES(4, 'hello'); } do_execsql_test 7.1 { SELECT rowid FROM t1 WHERE (rowid, x) IN (SELECT a, b FROM t2); } do_execsql_test 7.2 { SELECT rowid FROM t1 WHERE rowid=2 AND t1 = 'hello'; } #------------------------------------------------------------------------- # reset_db do_execsql_test 8.0 { CREATE VIRTUAL TABLE vt0 USING fts5(c0, tokenize = "ascii", prefix = 1); INSERT INTO vt0(c0) VALUES (x'd1'); } do_execsql_test 8.1 { INSERT INTO vt0(vt0) VALUES('integrity-check'); } #------------------------------------------------------------------------- # reset_db do_execsql_test 9.0 { CREATE VIRTUAL TABLE t1 using FTS5(mailcontent); insert into t1(rowid, mailcontent) values (-4764623217061966105, 'we are going to upgrade'), (8324454597464624651, 'we are going to upgrade'); } do_execsql_test 9.1 { INSERT INTO t1(t1) VALUES('integrity-check'); } do_execsql_test 9.2 { SELECT rowid FROM t1('upgrade'); } { -4764623217061966105 8324454597464624651 } #------------------------------------------------------------------------- # reset_db do_execsql_test 10.0 { CREATE VIRTUAL TABLE vt1 USING fts5(c1, c2, prefix = 1, tokenize = "ascii"); INSERT INTO vt1 VALUES (x'e4', '䔬'); } do_execsql_test 10.1 { SELECT quote(CAST(c1 AS blob)), quote(CAST(c2 AS blob)) FROM vt1 } {X'E4' X'E494AC'} do_execsql_test 10.2 { INSERT INTO vt1(vt1) VALUES('integrity-check'); } #------------------------------------------------------------------------- # reset_db do_execsql_test 11.0 { CREATE VIRTUAL TABLE vt0 USING fts5( c0, prefix = 71, tokenize = "porter ascii", prefix = 9 ); } {} do_execsql_test 11.1 { BEGIN; INSERT INTO vt0(c0) VALUES (x'e8'); } do_execsql_test 11.2 { INSERT INTO vt0(vt0) VALUES('integrity-check'); } #------------------------------------------------------------------------- # Ticket [752fdbf6] # reset_db do_execsql_test 11.0 { PRAGMA encoding = 'UTF-16'; CREATE VIRTUAL TABLE vt0 USING fts5(c0, c1); INSERT INTO vt0(vt0, rank) VALUES('pgsz', '37'); INSERT INTO vt0(c0, c1) VALUES (0.66077, 1957391816); } do_execsql_test 11.1 { INSERT INTO vt0(vt0) VALUES('integrity-check'); } #------------------------------------------------------------------------- # Ticket [7c0e06b16] # do_execsql_test 12.0 { CREATE TABLE t1(a, b, rank); INSERT INTO t1 VALUES('a', 'hello', ''); INSERT INTO t1 VALUES('b', 'world', ''); CREATE VIRTUAL TABLE ft USING fts5(a); INSERT INTO ft VALUES('b'); INSERT INTO ft VALUES('y'); CREATE TABLE t2(x, y, ft); INSERT INTO t2 VALUES(1, 2, 'x'); INSERT INTO t2 VALUES(3, 4, 'b'); } do_execsql_test 12.1 { SELECT * FROM t1 NATURAL JOIN ft WHERE ft MATCH('b') } {b world {}} do_execsql_test 12.2 { SELECT * FROM ft NATURAL JOIN t1 WHERE ft MATCH('b') } {b world {}} do_execsql_test 12.3 { SELECT * FROM t2 JOIN ft USING (ft) } {3 4 b b} #------------------------------------------------------------------------- # Forum post https://sqlite.org/forum/forumpost/21127c1160 # reset_db sqlite3_db_config db DEFENSIVE 1 do_execsql_test 13.0 { CREATE TABLE a (id INTEGER PRIMARY KEY, name TEXT); CREATE VIRTUAL TABLE b USING fts5(name); CREATE TRIGGER a_trigger AFTER INSERT ON a BEGIN INSERT INTO b (name) VALUES ('foo'); END; } do_test 13.1 { set ::STMT [ sqlite3_prepare db "INSERT INTO a VALUES (1, 'foo') RETURNING id;" -1 dummy ] sqlite3_step $::STMT } {SQLITE_ROW} do_test 13.2 { sqlite3_finalize $::STMT } {SQLITE_OK} do_test 13.3 { sqlite3_errmsg db } {not an error} finish_test |
Added ext/fts5/test/fts5multi.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 | # 2014 September 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 implements regression tests for SQLite library. The # focus of this script is testing the FTS5 module. # source [file join [file dirname [info script]] fts5_common.tcl] set testprefix fts5multi # If SQLITE_ENABLE_FTS5 is not defined, omit this file. ifcapable !fts5 { finish_test return } fts5_aux_test_functions db do_execsql_test 1.0 { CREATE VIRTUAL TABLE t1 USING fts5(a, b, c); INSERT INTO t1 VALUES('gg bb bb' ,'gg ff gg' ,'ii ii'); INSERT INTO t1 VALUES('dd dd hh kk','jj' ,'aa'); INSERT INTO t1 VALUES('kk gg ee' ,'hh cc' ,'hh jj aa cc'); INSERT INTO t1 VALUES('hh' ,'bb jj cc' ,'kk ii'); INSERT INTO t1 VALUES('kk dd kk ii','aa ee aa' ,'ee'); INSERT INTO t1 VALUES('ee' ,'ff gg kk aa','ee ff ee'); INSERT INTO t1 VALUES('ff jj' ,'gg ee' ,'kk ee gg kk'); INSERT INTO t1 VALUES('ff ee dd hh','kk ee' ,'gg dd'); INSERT INTO t1 VALUES('bb' ,'aa' ,'bb aa'); INSERT INTO t1 VALUES('hh cc bb' ,'ff bb' ,'cc'); INSERT INTO t1 VALUES('jj' ,'ff dd bb aa','dd dd ff ff'); INSERT INTO t1 VALUES('ff dd gg dd','gg aa bb ff','cc'); INSERT INTO t1 VALUES('ff aa cc jj','kk' ,'ii dd'); INSERT INTO t1 VALUES('jj dd' ,'cc' ,'ii hh ee aa'); INSERT INTO t1 VALUES('ff ii hh' ,'dd' ,'gg'); INSERT INTO t1 VALUES('ff dd gg hh','hh' ,'ff dd'); INSERT INTO t1 VALUES('cc cc' ,'ff dd ff' ,'bb'); INSERT INTO t1 VALUES('ii' ,'bb ii' ,'jj kk'); INSERT INTO t1 VALUES('ff hh' ,'hh bb' ,'bb dd ee'); INSERT INTO t1 VALUES('jj kk' ,'jj' ,'gg ff cc'); INSERT INTO t1 VALUES('dd kk' ,'ii gg' ,'dd'); INSERT INTO t1 VALUES('cc' ,'aa ff' ,'ii'); INSERT INTO t1 VALUES('bb ff bb ii','bb kk bb aa','hh ff ii dd'); INSERT INTO t1 VALUES('aa' ,'ee bb jj jj','dd'); INSERT INTO t1 VALUES('kk dd cc' ,'aa jj' ,'ee aa ff'); INSERT INTO t1 VALUES('aa gg aa' ,'jj' ,'ii kk hh gg'); INSERT INTO t1 VALUES('ff hh aa' ,'jj ii' ,'hh dd bb jj'); INSERT INTO t1 VALUES('hh' ,'aa gg kk' ,'bb ee'); INSERT INTO t1 VALUES('bb' ,'ee' ,'gg'); INSERT INTO t1 VALUES('dd kk' ,'kk bb aa' ,'ee'); } foreach {tn c1 e1 c2 e2} { 1 t1 aa t1 bb 2 a aa b bb 3 a "aa OR bb OR cc" b "jj OR ii OR hh" 4 t1 "aa AND bb" t1 "cc" 5 c "kk" b "aa OR bb OR cc OR dd OR ee" } { if {$c1=="t1"} { set lhs "( $e1 )" } else { set lhs "$c1 : ( $e1 )" } if {$c2=="t1"} { set rhs "( $e2 )" } else { set rhs "$c2 : ( $e2 )" } set q1 "t1 MATCH '($lhs) AND ($rhs)'" set q2 "$c1 MATCH '$e1' AND $c2 MATCH '$e2'" set ret [execsql "SELECT rowid FROM t1 WHERE $q1"] set N [llength $ret] do_execsql_test 1.$tn.1.($N) "SELECT rowid FROM t1 WHERE $q2" $ret set ret [execsql "SELECT fts5_test_poslist(t1) FROM t1 WHERE $q1"] do_execsql_test 1.$tn.2.($N) " SELECT fts5_test_poslist(t1) FROM t1 WHERE $q2 " $ret } do_catchsql_test 2.1.1 { SELECT rowid FROM t1 WHERE t1 MATCH '(NOT' AND t1 MATCH 'aa bb'; } {1 {fts5: syntax error near "NOT"}} do_catchsql_test 2.1.2 { SELECT rowid FROM t1 WHERE t1 MATCH 'aa bb' AND t1 MATCH '(NOT'; } {1 {fts5: syntax error near "NOT"}} finish_test |
Changes to ext/fts5/test/fts5plan.test.
︙ | ︙ | |||
26 27 28 29 30 31 32 | CREATE VIRTUAL TABLE f1 USING fts5(ff); } do_eqp_test 1.1 { SELECT * FROM t1, f1 WHERE f1 MATCH t1.x } { QUERY PLAN | | | | | | | | | 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 | CREATE VIRTUAL TABLE f1 USING fts5(ff); } do_eqp_test 1.1 { SELECT * FROM t1, f1 WHERE f1 MATCH t1.x } { QUERY PLAN |--SCAN t1 `--SCAN f1 VIRTUAL TABLE INDEX 0:M1 } do_eqp_test 1.2 { SELECT * FROM t1, f1 WHERE f1 > t1.x } { QUERY PLAN |--SCAN f1 VIRTUAL TABLE INDEX 0: `--SCAN t1 } do_eqp_test 1.3 { SELECT * FROM f1 WHERE f1 MATCH ? ORDER BY ff } { QUERY PLAN |--SCAN f1 VIRTUAL TABLE INDEX 0:M1 `--USE TEMP B-TREE FOR ORDER BY } do_eqp_test 1.4 { SELECT * FROM f1 ORDER BY rank } { QUERY PLAN |--SCAN f1 VIRTUAL TABLE INDEX 0: `--USE TEMP B-TREE FOR ORDER BY } do_eqp_test 1.5 { SELECT * FROM f1 WHERE rank MATCH ? } {SCAN f1 VIRTUAL TABLE INDEX 0:r} finish_test |
Added ext/fts5/test/fts5prefix2.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 | # 2020 Dec 3 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # # This file contains tests focused on prefix indexes. # source [file join [file dirname [info script]] fts5_common.tcl] set testprefix fts5prefix2 # If SQLITE_ENABLE_FTS5 is defined, omit this file. ifcapable !fts5 { finish_test return } foreach p {3 2 1} { reset_db do_execsql_test 1.$p.0 " CREATE VIRTUAL TABLE t1 USING fts5(xyz, prefix=$p); " do_execsql_test 1.$p.1 { INSERT INTO t1 VALUES ('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 f.'); } do_execsql_test 1.$p.2 { SELECT highlight(t1, 0, '[', ']') FROM t1('f*'); } { {May you [find] [forgiveness] [for] yourself and [forgive] others.} {May you share [freely], never taking more than you give [f].} } } do_execsql_test 2.0 { CREATE VIRTUAL TABLE t2 USING fts5(one, prefix=3); INSERT INTO t2 VALUES('top'); INSERT INTO t2 VALUES('to'); INSERT INTO t2 VALUES('tommy'); } do_execsql_test 2.1 { SELECT * FROM t2('to*'); } {top to tommy} finish_test |
Changes to ext/fts5/test/fts5rank.test.
︙ | ︙ | |||
157 158 159 160 161 162 163 164 165 | ) INSERT INTO ttt SELECT 'word ' || i FROM s; } do_execsql_test 5.1 { SELECT rowid FROM ttt('word') WHERE rowid BETWEEN 30 AND 40 ORDER BY rank; } {30 31 32 33 34 35 36 37 38 39 40} finish_test | > > > > > > > > > > > > > > > > > > | 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 | ) INSERT INTO ttt SELECT 'word ' || i FROM s; } do_execsql_test 5.1 { SELECT rowid FROM ttt('word') WHERE rowid BETWEEN 30 AND 40 ORDER BY rank; } {30 31 32 33 34 35 36 37 38 39 40} #------------------------------------------------------------------------- reset_db do_execsql_test 6.0 { CREATE VIRTUAL TABLE "My.Table" USING fts5(Text); INSERT INTO "My.Table" VALUES ('hello this is a test'); INSERT INTO "My.Table" VALUES ('of trying to order by'); INSERT INTO "My.Table" VALUES ('rank on an fts5 table'); INSERT INTO "My.Table" VALUES ('that have periods in'); INSERT INTO "My.Table" VALUES ('the table names.'); INSERT INTO "My.Table" VALUES ('table table table'); } do_execsql_test 6.1 { SELECT * FROM "My.Table" WHERE Text MATCH 'table' ORDER BY rank; } { {table table table} {the table names.} {rank on an fts5 table} } finish_test |
Added ext/fts5/test/fts5savepoint.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 | # 2019 Dec 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. # #*********************************************************************** # source [file join [file dirname [info script]] fts5_common.tcl] set testprefix fts5savepoint # If SQLITE_ENABLE_FTS5 is defined, omit this file. ifcapable !fts5 { finish_test return } do_execsql_test 1.0 { CREATE VIRTUAL TABLE ft USING fts5(c); BEGIN; SAVEPOINT one; INSERT INTO ft VALUES('a'); SAVEPOINT two; INSERT INTO ft VALUES('b'); RELEASE two; SAVEPOINT four; INSERT INTO ft VALUES('c'); RELEASE four; SAVEPOINT three; INSERT INTO ft VALUES('d'); ROLLBACK TO three; COMMIT; SELECT * FROM ft } {a b c} reset_db do_catchsql_test 2.0 { CREATE VIRTUAL TABLE ft1 USING fts5(c); CREATE VIRTUAL TABLE ft2 USING fts5(c); DROP TABLE ft2_idx; BEGIN; INSERT INTO ft2 VALUES('a'); INSERT INTO ft1 VALUES('a'); SAVEPOINT two; INSERT INTO ft1 VALUES('b'); COMMIT; } {1 {SQL logic error}} reset_db ifcapable fts3 { do_execsql_test 3.0 { CREATE VIRTUAL TABLE vt0 USING fts5(c0); CREATE VIRTUAL TABLE vt1 USING fts4(c0); INSERT INTO vt1(c0) VALUES(0); } do_execsql_test 3.1 { BEGIN; UPDATE vt1 SET c0 = 0; INSERT INTO vt1(c0) VALUES (0), (0); UPDATE vt0 SET c0 = 0; INSERT INTO vt1(c0) VALUES (0); UPDATE vt1 SET c0 = 0; INSERT INTO vt1(vt1) VALUES('automerge=1'); UPDATE vt1 SET c0 = 0; } do_catchsql_test 3.2 { DROP TABLE vt1; } {1 {SQL logic error}} do_execsql_test 3.3 { SAVEPOINT x; INSERT INTO vt0 VALUES('x'); COMMIT; INSERT INTO vt0(vt0) VALUES('integrity-check'); } } finish_test |
Changes to ext/fts5/test/fts5simple.test.
︙ | ︙ | |||
463 464 465 466 467 468 469 470 | } {11111 11112} do_execsql_test 21.3 { DELETE FROM x1 WHERE rowid=11111; INSERT INTO x1(x1) VALUES('integrity-check'); SELECT rowid FROM x1($doc); } {11112} finish_test | > > > > > > > > > > > > > | 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 | } {11111 11112} do_execsql_test 21.3 { DELETE FROM x1 WHERE rowid=11111; INSERT INTO x1(x1) VALUES('integrity-check'); SELECT rowid FROM x1($doc); } {11112} #------------------------------------------------------------------------- reset_db do_execsql_test 22.0 { CREATE VIRTUAL TABLE x1 USING fts5(x); INSERT INTO x1(x) VALUES('a b c'); INSERT INTO x1(x) VALUES('x y z'); INSERT INTO x1(x) VALUES('c b a'); INSERT INTO x1(x) VALUES('z y x'); } do_catchsql_test 22.1 {SELECT * FROM x1('')} {1 {fts5: syntax error near ""}} do_catchsql_test 22.2 {SELECT * FROM x1(NULL)} {1 {fts5: syntax error near ""}} finish_test |
Changes to ext/fts5/test/fts5tok1.test.
︙ | ︙ | |||
106 107 108 109 110 111 112 113 114 115 | CREATE VIRTUAL TABLE tX USING fts5tokenize(nosuchtokenizer); } {1 {vtable constructor failed: tX}} do_catchsql_test 2.1 { CREATE VIRTUAL TABLE t4 USING fts5tokenize; SELECT * FROM t4; } {1 {SQL logic error}} finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | CREATE VIRTUAL TABLE tX USING fts5tokenize(nosuchtokenizer); } {1 {vtable constructor failed: tX}} do_catchsql_test 2.1 { CREATE VIRTUAL TABLE t4 USING fts5tokenize; SELECT * FROM t4; } {1 {SQL logic error}} #------------------------------------------------------------------------- # Embedded 0x00 characters. # reset_db do_execsql_test 3.1.0 { CREATE VIRTUAL TABLE t1 USING fts5(z); CREATE VIRTUAL TABLE tt USING fts5vocab(t1, 'instance'); INSERT INTO t1 VALUES('abc' || char(0) || 'def'); SELECT * FROM tt; } { abc 1 z 0 def 1 z 1 } do_execsql_test 3.1.1 { SELECT hex(z) FROM t1; } {61626300646566} do_execsql_test 3.1.2 { INSERT INTO t1(t1) VALUES('integrity-check'); } {} do_execsql_test 3.2.0 { CREATE VIRTUAL TABLE t2 USING fts5(z, tokenize="unicode61 categories 'L* N* Co Cc'" ); CREATE VIRTUAL TABLE tu USING fts5vocab(t2, 'instance'); INSERT INTO t2 VALUES('abc' || char(0) || 'def'); SELECT * FROM tu; } { abc 1 z 0 def 1 z 1 } do_execsql_test 3.2.1 { SELECT hex(z) FROM t1; } {61626300646566} do_execsql_test 3.2.2 { INSERT INTO t1(t1) VALUES('integrity-check'); } {} finish_test |
Added ext/fts5/test/fts5trigram.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 | # 2020 September 30 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #************************************************************************* # # Tests for the fts5 "trigram" tokenizer. # source [file join [file dirname [info script]] fts5_common.tcl] ifcapable !fts5 { finish_test ; return } set ::testprefix fts5trigram do_execsql_test 1.0 { CREATE VIRTUAL TABLE t1 USING fts5(y, tokenize=trigram); INSERT INTO t1 VALUES('abcdefghijklm'); INSERT INTO t1 VALUES('กรุงเทพมหานคร'); } foreach {tn s res} { 1 abc "(abc)defghijklm" 2 defgh "abc(defgh)ijklm" 3 abcdefghijklm "(abcdefghijklm)" 4 กรุ "(กรุ)งเทพมหานคร" 5 งเทพมห "กรุ(งเทพมห)านคร" 6 กรุงเทพมหานคร "(กรุงเทพมหานคร)" 7 Abc "(abc)defghijklm" 8 deFgh "abc(defgh)ijklm" 9 aBcdefGhijKlm "(abcdefghijklm)" } { do_execsql_test 1.1.$tn { SELECT highlight(t1, 0, '(', ')') FROM t1($s) } $res } do_execsql_test 1.2.0 { SELECT fts5_expr('ABCD', 'tokenize=trigram') } {{"abc" + "bcd"}} do_execsql_test 1.2.1 { SELECT * FROM t1 WHERE y LIKE ? ESCAPE 'a' } foreach {tn like res} { 1 {%cDef%} 1 2 {cDef%} {} 3 {%f%} 1 4 {%f_h%} 1 5 {%f_g%} {} 6 {abc%klm} 1 7 {ABCDEFG%} 1 8 {%รุงเ%} 2 } { do_execsql_test 1.3.$tn { SELECT rowid FROM t1 WHERE y LIKE $like } $res } #------------------------------------------------------------------------- reset_db do_execsql_test 2.0 { CREATE VIRTUAL TABLE t1 USING fts5(y, tokenize="trigram case_sensitive 1"); INSERT INTO t1 VALUES('abcdefghijklm'); INSERT INTO t1 VALUES('กรุงเทพมหานคร'); } foreach {tn s res} { 1 abc "(abc)defghijklm" 2 defgh "abc(defgh)ijklm" 3 abcdefghijklm "(abcdefghijklm)" 4 กรุ "(กรุ)งเทพมหานคร" 5 งเทพมห "กรุ(งเทพมห)านคร" 6 กรุงเทพมหานคร "(กรุงเทพมหานคร)" 7 Abc "" 8 deFgh "" 9 aBcdefGhijKlm "" } { do_execsql_test 2.1.$tn { SELECT highlight(t1, 0, '(', ')') FROM t1($s) } $res } foreach {tn like res} { 1 {%cDef%} 1 2 {cDef%} {} 3 {%f%} 1 4 {%f_h%} 1 5 {%f_g%} {} 6 {abc%klm} 1 7 {ABCDEFG%} 1 8 {%รุงเ%} 2 } { do_execsql_test 2.2.$tn { SELECT rowid FROM t1 WHERE y LIKE $like } $res } foreach {tn like res} { 1 {*cdef*} 1 2 {cdef*} {} 3 {*f*} 1 4 {*f?h*} 1 5 {*f?g*} {} 6 {abc*klm} 1 7 {abcdefg*} 1 8 {*รุงเ*} 2 9 {abc[d]efg*} 1 10 {abc[]d]efg*} 1 11 {abc[^]d]efg*} {} 12 {abc[^]XYZ]efg*} 1 } { do_execsql_test 2.3.$tn { SELECT rowid FROM t1 WHERE y GLOB $like } $res } do_execsql_test 2.3.null.1 { SELECT rowid FROM t1 WHERE y LIKE NULL } #------------------------------------------------------------------------- reset_db do_catchsql_test 3.1 { CREATE VIRTUAL TABLE ttt USING fts5(c, tokenize="trigram case_sensitive 2"); } {1 {error in tokenizer constructor}} do_catchsql_test 3.2 { CREATE VIRTUAL TABLE ttt USING fts5(c, tokenize="trigram case_sensitive 11"); } {1 {error in tokenizer constructor}} do_catchsql_test 3.3 { CREATE VIRTUAL TABLE ttt USING fts5(c, "tokenize=trigram case_sensitive 1"); } {0 {}} #------------------------------------------------------------------------- reset_db do_execsql_test 4.0 { CREATE VIRTUAL TABLE t0 USING fts5(b, tokenize = "trigram"); } do_execsql_test 4.1 { INSERT INTO t0 VALUES (x'000b01'); } do_execsql_test 4.2 { INSERT INTO t0(t0) VALUES('integrity-check'); } #------------------------------------------------------------------------- reset_db foreach_detail_mode $::testprefix { foreach {ci} {0 1} { reset_db do_execsql_test 5.cs=$ci.0.1 " CREATE VIRTUAL TABLE t1 USING fts5( y, tokenize=\"trigram case_sensitive $ci\", detail=%DETAIL% ); " do_execsql_test 5.cs=$ci.0.2 { INSERT INTO t1 VALUES('abcdefghijklm'); INSERT INTO t1 VALUES('กรุงเทพมหานคร'); } foreach {tn like res} { 1 {%cDef%} 1 2 {cDef%} {} 3 {%f%} 1 4 {%f_h%} 1 5 {%f_g%} {} 6 {abc%klm} 1 7 {ABCDEFG%} 1 8 {%รุงเ%} 2 } { do_execsql_test 5.cs=$ci.1.$tn { SELECT rowid FROM t1 WHERE y LIKE $like } $res } } } do_execsql_test 6.0 { CREATE VIRTUAL TABLE ci0 USING fts5(x, tokenize="trigram"); CREATE VIRTUAL TABLE ci1 USING fts5(x, tokenize="trigram case_sensitive 1"); } # LIKE and GLOB both work with case-insensitive tokenizers. Only GLOB works # with case-sensitive. do_eqp_test 6.1 { SELECT * FROM ci0 WHERE x LIKE ? } {VIRTUAL TABLE INDEX 0:L0} do_eqp_test 6.2 { SELECT * FROM ci0 WHERE x GLOB ? } {VIRTUAL TABLE INDEX 0:G0} do_eqp_test 6.3 { SELECT * FROM ci1 WHERE x LIKE ? } {{SCAN ci1 VIRTUAL TABLE INDEX 0:}} do_eqp_test 6.4 { SELECT * FROM ci1 WHERE x GLOB ? } {VIRTUAL TABLE INDEX 0:G0} finish_test |
Changes to ext/fts5/test/fts5unicode3.test.
︙ | ︙ | |||
17 18 19 20 21 22 23 | # If SQLITE_ENABLE_FTS5 is defined, omit this file. ifcapable !fts5 { finish_test return } proc fts3_unicode_path {file} { | | | 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | # If SQLITE_ENABLE_FTS5 is defined, omit this file. ifcapable !fts5 { finish_test return } proc fts3_unicode_path {file} { file join .. [file dirname [info script]] .. .. fts3 unicode $file } source [fts3_unicode_path parseunicode.tcl] set testprefix fts5unicode3 set CF [fts3_unicode_path CaseFolding.txt] set UD [fts3_unicode_path UnicodeData.txt] |
︙ | ︙ |
Changes to ext/fts5/test/fts5update.test.
︙ | ︙ | |||
110 111 112 113 114 115 116 117 118 119 | for {set i 0} {$i < 1000} {incr i} { execsql { UPDATE x2 SET x=x WHERE rowid=2 } } } {} do_execsql_test 2.2.integrity { INSERT INTO x2(x2) VALUES('integrity-check'); } } finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 | for {set i 0} {$i < 1000} {incr i} { execsql { UPDATE x2 SET x=x WHERE rowid=2 } } } {} do_execsql_test 2.2.integrity { INSERT INTO x2(x2) VALUES('integrity-check'); } #------------------------------------------------------------------------- # do_execsql_test 3.0 { CREATE VIRTUAL TABLE x3 USING fts5(x, detail=%DETAIL%); INSERT INTO x3 VALUES('one'); INSERT INTO x3 VALUES('two'); INSERT INTO x3 VALUES('one'); INSERT INTO x3 VALUES('two'); INSERT INTO x3 VALUES('one'); } do_test 3.1 { db eval { SELECT * FROM x3('one') } { db eval { INSERT INTO x3(x3) VALUES('optimize'); } } } {} do_execsql_test 4.0 { CREATE VIRTUAL TABLE x4 USING fts5(a, detail=%DETAIL%); INSERT INTO x4 VALUES('one two three'); INSERT INTO x4(rowid, a) VALUES('2', 'one two three'); INSERT INTO x4(rowid, a) VALUES('3.0', 'one two three'); } do_catchsql_test 4.1 { INSERT INTO x4(rowid, a) VALUES('four', 'one two three'); } {1 {datatype mismatch}} do_catchsql_test 4.2 { UPDATE x4 SET rowid = 'four' WHERE rowid=1; } {1 {datatype mismatch}} } reset_db do_catchsql_test 4.0 { CREATE VIRTUAL TABLE t1 USING fts5(a,b,c); } {0 {}} do_catchsql_test 4.1 { DELETE FROM t1 WHERE t1 MATCH 'f*'; } {0 {}} finish_test |
Changes to ext/fts5/test/fts5vocab.test.
︙ | ︙ | |||
75 76 77 78 79 80 81 | } { 0 term {} 0 {} 0 1 col {} 0 {} 0 2 doc {} 0 {} 0 3 cnt {} 0 {} 0 } | | | | 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 | } { 0 term {} 0 {} 0 1 col {} 0 {} 0 2 doc {} 0 {} 0 3 cnt {} 0 {} 0 } do_execsql_test 1.2.1 { SELECT * FROM v1 } {} do_execsql_test 1.2.2 { SELECT * FROM v2 } {} do_execsql_test 1.3 { INSERT INTO t1 VALUES('x y z'); INSERT INTO t1 VALUES('x x x'); } do_execsql_test 1.4.1 { |
︙ | ︙ | |||
475 476 477 478 479 480 481 | expr [lsearch $e2 SorterSort]<0 } 1 do_test 9.6 { set e2 [db eval { EXPLAIN SELECT * FROM rrr ORDER BY term DESC }] expr [lsearch $e2 SorterSort]<0 } 0 | > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | expr [lsearch $e2 SorterSort]<0 } 1 do_test 9.6 { set e2 [db eval { EXPLAIN SELECT * FROM rrr ORDER BY term DESC }] expr [lsearch $e2 SorterSort]<0 } 0 #------------------------------------------------------------------------- do_execsql_test 10.0 { CREATE VIRTUAL TABLE ft USING fts5(a, b, c); CREATE VIRTUAL TABLE t2 USING fts5vocab('ft','row'); CREATE VIRTUAL TABLE t3 USING fts5vocab('ft','row'); } do_execsql_test 10.1 { BEGIN; INSERT INTO ft(b) VALUES('x y'); } do_execsql_test 10.2 { SELECT t2.term FROM t2; } {x y} do_execsql_test 10.3 { SELECT t2.term, t3.term FROM t2, t3; } {x x x y y x y y} do_execsql_test 10.4 { COMMIT; } do_execsql_test 10.5 { BEGIN; INSERT INTO ft(a) VALUES('1 2 3'); INSERT INTO ft(a) VALUES('4 5 6'); INSERT INTO ft(a) VALUES('1 2 3'); INSERT INTO ft(a) VALUES('4 5 6'); INSERT INTO ft(a) VALUES('1 2 3'); INSERT INTO ft(a) VALUES('4 5 6'); } do_test 10.6 { set res [list] db eval { SELECT rowid FROM ft('4') } x { db eval { SELECT * FROM t2 } lappend res $x(rowid) } db eval COMMIT set res } {3 5 7} do_execsql_test 10.6.1 { SELECT * FROM t2 WHERE term<NULL; } do_execsql_test 10.6.2 { SELECT * FROM t2 WHERE term>NULL; } do_execsql_test 10.6.3 { SELECT * FROM t2 WHERE term=NULL; } do_execsql_test 10.7.1 { SELECT * FROM t2 WHERE term<?; } do_execsql_test 10.7.2 { SELECT * FROM t2 WHERE term>?; } do_execsql_test 10.7.3 { SELECT * FROM t2 WHERE term=?; } # 2020-02-16 Detect recursively define fts5vocab() tables. # Error found by dbsqlfuzz. # reset_db do_execsql_test 11.100 { CREATE VIRTUAL TABLE t3 USING fts5vocab(rowid , 'col'); CREATE VIRTUAL TABLE rowid USING fts5vocab(rowid , 'instance'); } {} do_catchsql_test 11.110 { SELECT rowid+1,rowid, * FROM t3 WHERE null>rowid ; } {1 {SQL logic error}} finish_test |
Changes to ext/fts5/test/fts5vocab2.test.
︙ | ︙ | |||
76 77 78 79 80 81 82 | four 2 b 0 three 2 a 0 } do_execsql_test 1.5 { DELETE FROM t1; SELECT * FROM v1; | | < | 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 | four 2 b 0 three 2 a 0 } do_execsql_test 1.5 { DELETE FROM t1; SELECT * FROM v1; } {} #------------------------------------------------------------------------- # do_execsql_test 2.0 { DROP TABLE IF EXISTS t1; DROP TABLE IF EXISTS v1; |
︙ | ︙ | |||
139 140 141 142 143 144 145 | four 2 b {} three 2 a {} } do_execsql_test 2.5 { DELETE FROM t1; SELECT * FROM v1; | | < | 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 | four 2 b {} three 2 a {} } do_execsql_test 2.5 { DELETE FROM t1; SELECT * FROM v1; } {} #------------------------------------------------------------------------- # do_execsql_test 3.0 { DROP TABLE IF EXISTS t1; DROP TABLE IF EXISTS v1; |
︙ | ︙ | |||
198 199 200 201 202 203 204 | four 2 {} {} three 2 {} {} } do_execsql_test 3.5 { DELETE FROM t1; SELECT * FROM v1; | | | > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | four 2 {} {} three 2 {} {} } do_execsql_test 3.5 { DELETE FROM t1; SELECT * FROM v1; } {} #------------------------------------------------------------------------- # reset_db do_execsql_test 4.0 { CREATE VIRTUAL TABLE v1 USING fts5vocab(nosuchtable, col); } do_catchsql_test 4.1 { SELECT * FROM v1 WHERE term=='nosuchterm'; } {1 {no such fts5 table: main.nosuchtable}} do_execsql_test 4.2.1 { CREATE TABLE nosuchtable(nosuchtable, y, z); } do_catchsql_test 4.2.2 { SELECT * FROM v1 WHERE term=='nosuchterm'; } {1 {no such fts5 table: main.nosuchtable}} ifcapable fts3 { do_execsql_test 4.3.1 { DROP TABLE nosuchtable; CREATE VIRTUAL TABLE nosuchtable USING fts3(a, b); } {} do_catchsql_test 4.3.2 { SELECT * FROM v1 WHERE term=='nosuchterm'; } {1 {no such fts5 table: main.nosuchtable}} do_catchsql_test 4.3.3 { INSERT INTO nosuchtable VALUES('id', '*id'); SELECT * FROM v1 WHERE term=='nosuchterm'; } {1 {no such fts5 table: main.nosuchtable}} } #------------------------------------------------------------------------- # Check that the fts5 table cannot be written while there are vocab # cursors open. reset_db do_execsql_test 5.0 { CREATE VIRTUAL TABLE t1 USING fts5(a); CREATE VIRTUAL TABLE v1 USING fts5vocab(t1, instance); INSERT INTO t1 VALUES('one'), ('two'), ('three'), ('four'); } do_test 5.1 { list [catch { db eval { SELECT * FROM v1 } { db eval {INSERT INTO t1 VALUES('five')} } } msg] $msg } {1 {query aborted}} do_execsql_test 5.2 { SELECT * FROM t1 } {one two three four five} #------------------------------------------------------------------------- # Check that the fts5 table cannot be written while there are vocab # cursors open. reset_db do_execsql_test 5.0 { CREATE VIRTUAL TABLE t1 USING fts5(a); CREATE VIRTUAL TABLE v1 USING fts5vocab(t1, instance); WITH s(i) AS ( VALUES(1) UNION ALL SELECT i+1 FROM s WHERE i<10000 ) INSERT INTO t1 SELECT 'State Emergency Service (SES), Rural Fire Service (RFS) and Volunteers' FROM s; } do_catchsql_test 5.1 { INSERT INTO t1 SELECT rowid FROM v1 } {1 {query aborted}} do_catchsql_test 5.2 { DELETE FROM t1 WHERE rowid>100; INSERT INTO t1 SELECT randomblob(3000) FROM v1 } {1 {query aborted}} finish_test |
Changes to ext/fts5/tool/fts5txt2db.tcl.
︙ | ︙ | |||
8 9 10 11 12 13 14 15 16 17 18 19 20 21 | # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # proc process_cmdline {} { cmdline::process ::A $::argv { {fts5 "use fts5 (this is the default)"} {fts4 "use fts4"} {colsize "10 10 10" "list of column sizes"} {tblname "t1" "table name to create"} {detail "full" "Fts5 detail mode to use"} {repeat 1 "Load each file this many times"} {prefix "" "Fts prefix= option"} {trans 1 "True to use a transaction"} database | > | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # proc process_cmdline {} { cmdline::process ::A $::argv { {fts5 "use fts5 (this is the default)"} {fts4 "use fts4"} {trigram "Use tokenize=trigram"} {colsize "10 10 10" "list of column sizes"} {tblname "t1" "table name to create"} {detail "full" "Fts5 detail mode to use"} {repeat 1 "Load each file this many times"} {prefix "" "Fts prefix= option"} {trans 1 "True to use a transaction"} database |
︙ | ︙ | |||
171 172 173 174 175 176 177 178 179 180 181 182 183 184 | set nCol [llength $A(colsize)] set cols [lrange $cols 0 [expr $nCol-1]] set sql "CREATE VIRTUAL TABLE IF NOT EXISTS $A(tblname) USING $A(fts) (" append sql [join $cols ,] if {$A(fts)=="fts5"} { append sql ",detail=$A(detail)" } append sql ", prefix='$A(prefix)');" db eval $sql return $cols } # Return a list of tokens from the named file. | > | 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 | set nCol [llength $A(colsize)] set cols [lrange $cols 0 [expr $nCol-1]] set sql "CREATE VIRTUAL TABLE IF NOT EXISTS $A(tblname) USING $A(fts) (" append sql [join $cols ,] if {$A(fts)=="fts5"} { append sql ",detail=$A(detail)" } if {$A(trigram)} { append sql ",tokenize=trigram" } append sql ", prefix='$A(prefix)');" db eval $sql return $cols } # Return a list of tokens from the named file. |
︙ | ︙ |
Changes to ext/fts5/tool/mkfts5c.tcl.
︙ | ︙ | |||
56 57 58 59 60 61 62 | # proc fts5_source_id {zDir} { set top [file dirname [file dirname $zDir]] set uuid [string trim [readfile [file join $top manifest.uuid]]] set L [split [readfile [file join $top manifest]]] set date [lindex $L [expr [lsearch -exact $L D]+1]] | > | | 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | # proc fts5_source_id {zDir} { set top [file dirname [file dirname $zDir]] set uuid [string trim [readfile [file join $top manifest.uuid]]] set L [split [readfile [file join $top manifest]]] set date [lindex $L [expr [lsearch -exact $L D]+1]] set idx [expr {[string last . $date]-1}] set date [string range $date 0 $idx] set date [string map {T { }} $date] return "fts5: $date $uuid" } proc fts5c_init {zOut} { global G |
︙ | ︙ |
Changes to ext/icu/README.txt.
︙ | ︙ | |||
112 113 114 115 116 117 118 | 2 COMPILATION AND USAGE The easiest way to compile and use the ICU extension is to build and use it as a dynamically loadable SQLite extension. To do this using gcc on *nix: | > | | 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 | 2 COMPILATION AND USAGE The easiest way to compile and use the ICU extension is to build and use it as a dynamically loadable SQLite extension. To do this using gcc on *nix: gcc -fPIC -shared icu.c `pkg-config --libs --cflags icu-uc icu-io` \ -o libSqliteIcu.so You may need to add "-I" flags so that gcc can find sqlite3ext.h and sqlite3.h. The resulting shared lib, libSqliteIcu.so, may be loaded into sqlite in the same way as any other dynamically loadable extension. |
︙ | ︙ |
Changes to ext/icu/icu.c.
︙ | ︙ | |||
139 140 141 142 143 144 145 | /* There are now 4 possibilities: ** ** 1. uPattern is an unescaped match-all character "%", ** 2. uPattern is an unescaped match-one character "_", ** 3. uPattern is an unescaped escape character, or ** 4. uPattern is to be handled as an ordinary character */ | | | 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 | /* There are now 4 possibilities: ** ** 1. uPattern is an unescaped match-all character "%", ** 2. uPattern is an unescaped match-one character "_", ** 3. uPattern is an unescaped escape character, or ** 4. uPattern is to be handled as an ordinary character */ if( uPattern==MATCH_ALL && !prevEscape && uPattern!=(uint32_t)uEsc ){ /* Case 1. */ uint8_t c; /* Skip any MATCH_ALL or MATCH_ONE characters that follow a ** MATCH_ALL. For each MATCH_ONE, skip one character in the ** test string. */ |
︙ | ︙ | |||
165 166 167 168 169 170 171 | if( icuLikeCompare(zPattern, zString, uEsc) ){ return 1; } SQLITE_ICU_SKIP_UTF8(zString); } return 0; | | | | 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 | if( icuLikeCompare(zPattern, zString, uEsc) ){ return 1; } SQLITE_ICU_SKIP_UTF8(zString); } return 0; }else if( uPattern==MATCH_ONE && !prevEscape && uPattern!=(uint32_t)uEsc ){ /* Case 2. */ if( *zString==0 ) return 0; SQLITE_ICU_SKIP_UTF8(zString); }else if( uPattern==(uint32_t)uEsc && !prevEscape ){ /* Case 3. */ prevEscape = 1; }else{ /* Case 4. */ uint32_t uString; SQLITE_ICU_READ_UTF8(zString, uString); |
︙ | ︙ | |||
495 496 497 498 499 500 501 502 503 504 | } } /* ** Register the ICU extension functions with database db. */ int sqlite3IcuInit(sqlite3 *db){ static const struct IcuScalar { const char *zName; /* Function name */ unsigned char nArg; /* Number of arguments */ | > | | | | | | | | | | | | | | 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 | } } /* ** Register the ICU extension functions with database db. */ int sqlite3IcuInit(sqlite3 *db){ # define SQLITEICU_EXTRAFLAGS (SQLITE_DETERMINISTIC|SQLITE_INNOCUOUS) static const struct IcuScalar { const char *zName; /* Function name */ unsigned char nArg; /* Number of arguments */ unsigned int enc; /* Optimal text encoding */ unsigned char iContext; /* sqlite3_user_data() context */ void (*xFunc)(sqlite3_context*,int,sqlite3_value**); } scalars[] = { {"icu_load_collation",2,SQLITE_UTF8|SQLITE_DIRECTONLY,1, icuLoadCollation}, #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU) {"regexp", 2, SQLITE_ANY|SQLITEICU_EXTRAFLAGS, 0, icuRegexpFunc}, {"lower", 1, SQLITE_UTF16|SQLITEICU_EXTRAFLAGS, 0, icuCaseFunc16}, {"lower", 2, SQLITE_UTF16|SQLITEICU_EXTRAFLAGS, 0, icuCaseFunc16}, {"upper", 1, SQLITE_UTF16|SQLITEICU_EXTRAFLAGS, 1, icuCaseFunc16}, {"upper", 2, SQLITE_UTF16|SQLITEICU_EXTRAFLAGS, 1, icuCaseFunc16}, {"lower", 1, SQLITE_UTF8|SQLITEICU_EXTRAFLAGS, 0, icuCaseFunc16}, {"lower", 2, SQLITE_UTF8|SQLITEICU_EXTRAFLAGS, 0, icuCaseFunc16}, {"upper", 1, SQLITE_UTF8|SQLITEICU_EXTRAFLAGS, 1, icuCaseFunc16}, {"upper", 2, SQLITE_UTF8|SQLITEICU_EXTRAFLAGS, 1, icuCaseFunc16}, {"like", 2, SQLITE_UTF8|SQLITEICU_EXTRAFLAGS, 0, icuLikeFunc}, {"like", 3, SQLITE_UTF8|SQLITEICU_EXTRAFLAGS, 0, icuLikeFunc}, #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU) */ }; int rc = SQLITE_OK; int i; for(i=0; rc==SQLITE_OK && i<(int)(sizeof(scalars)/sizeof(scalars[0])); i++){ const struct IcuScalar *p = &scalars[i]; |
︙ | ︙ |
Changes to ext/icu/sqliteicu.h.
︙ | ︙ | |||
20 21 22 23 24 25 26 | #endif /* __cplusplus */ int sqlite3IcuInit(sqlite3 *db); #ifdef __cplusplus } /* extern "C" */ #endif /* __cplusplus */ | < | 20 21 22 23 24 25 26 | #endif /* __cplusplus */ int sqlite3IcuInit(sqlite3 *db); #ifdef __cplusplus } /* extern "C" */ #endif /* __cplusplus */ |
Changes to ext/lsm1/Makefile.
︙ | ︙ | |||
39 40 41 42 43 44 45 | $(LSMDIR)/lsm-test/lsmtest_main.c $(LSMDIR)/lsm-test/lsmtest_mem.c \ $(LSMDIR)/lsm-test/lsmtest_tdb.c $(LSMDIR)/lsm-test/lsmtest_tdb3.c \ $(LSMDIR)/lsm-test/lsmtest_util.c $(LSMDIR)/lsm-test/lsmtest_win32.c # all: lsm.so | | | | 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | $(LSMDIR)/lsm-test/lsmtest_main.c $(LSMDIR)/lsm-test/lsmtest_mem.c \ $(LSMDIR)/lsm-test/lsmtest_tdb.c $(LSMDIR)/lsm-test/lsmtest_tdb3.c \ $(LSMDIR)/lsm-test/lsmtest_util.c $(LSMDIR)/lsm-test/lsmtest_win32.c # all: lsm.so LSMOPTS += -fPIC -DLSM_MUTEX_PTHREADS=1 -I$(LSMDIR) -DHAVE_ZLIB lsm.so: $(LSMOBJ) $(TCCX) -shared -fPIC -o lsm.so $(LSMOBJ) %.o: $(LSMDIR)/%.c $(LSMHDR) sqlite3.h $(TCCX) $(LSMOPTS) -c $< lsmtest$(EXE): $(LSMOBJ) $(LSMTESTSRC) $(LSMTESTHDR) sqlite3.o # $(TCPPX) -c $(TOP)/lsm-test/lsmtest_tdb2.cc $(TCCX) $(LSMOPTS) $(LSMTESTSRC) $(LSMOBJ) sqlite3.o -o lsmtest$(EXE) $(THREADLIB) -lz |
Changes to ext/lsm1/lsm-test/lsmtest1.c.
︙ | ︙ | |||
650 651 652 653 654 655 656 | char *zName = getName3(zSystem, &aTest[i]); if( testCaseBegin(pRc, zPattern, "%s", zName) ){ doDataTest3(zSystem, &aTest[i], pRc); } testFree(zName); } } | < < | 650 651 652 653 654 655 656 | char *zName = getName3(zSystem, &aTest[i]); if( testCaseBegin(pRc, zPattern, "%s", zName) ){ doDataTest3(zSystem, &aTest[i], pRc); } testFree(zName); } } |
Changes to ext/lsm1/lsm-test/lsmtest8.c.
︙ | ︙ | |||
318 319 320 321 322 323 324 | if( testCaseBegin(pRc, zPattern, p->zName) ){ p->xFunc(pRc); testCaseFinish(*pRc); } } } | < < | 318 319 320 321 322 323 324 | if( testCaseBegin(pRc, zPattern, p->zName) ){ p->xFunc(pRc); testCaseFinish(*pRc); } } } |
Changes to ext/lsm1/lsm-test/lsmtest9.c.
︙ | ︙ | |||
134 135 136 137 138 139 140 | char *zName = getName4(zSystem, &aTest[i]); if( testCaseBegin(pRc, zPattern, "%s", zName) ){ doDataTest4(zSystem, &aTest[i], pRc); } testFree(zName); } } | < < < | 134 135 136 137 138 139 140 | char *zName = getName4(zSystem, &aTest[i]); if( testCaseBegin(pRc, zPattern, "%s", zName) ){ doDataTest4(zSystem, &aTest[i], pRc); } testFree(zName); } } |
Changes to ext/lsm1/lsm-test/lsmtest_bt.c.
︙ | ︙ | |||
65 66 67 68 69 70 71 | return -4; } printf("%s\n", (char*)buf.output.p); sqlite4_buffer_clear(&buf.output); return 0; } | < < < < | 65 66 67 68 69 70 71 | return -4; } printf("%s\n", (char*)buf.output.p); sqlite4_buffer_clear(&buf.output); return 0; } |
Changes to ext/lsm1/lsm-test/lsmtest_tdb.c.
︙ | ︙ | |||
549 550 551 552 553 554 555 | /* iLevel==0 is a no-op */ if( iLevel==0 ) return 0; /* If there are no transactions at all open, open a read transaction. */ if( pDb->nOpenTrans==0 ){ int rc = sqlite3_exec(pDb->db, | | | 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 | /* iLevel==0 is a no-op */ if( iLevel==0 ) return 0; /* If there are no transactions at all open, open a read transaction. */ if( pDb->nOpenTrans==0 ){ int rc = sqlite3_exec(pDb->db, "BEGIN; SELECT * FROM sqlite_schema LIMIT 1;" , 0, 0, 0 ); if( rc!=0 ) return rc; pDb->nOpenTrans = 1; } /* Open any required write transactions */ for(i=pDb->nOpenTrans; i<iLevel; i++){ |
︙ | ︙ |
Changes to ext/lsm1/lsm-test/lsmtest_tdb2.cc.
︙ | ︙ | |||
363 364 365 366 367 368 369 | } } return rc; } #endif /* HAVE_MDB */ | < | 363 364 365 366 367 368 369 | } } return rc; } #endif /* HAVE_MDB */ |
Changes to ext/lsm1/lsm-test/lsmtest_tdb4.c.
︙ | ︙ | |||
974 975 976 977 978 979 980 | } return rc; } /* ** End of background checkpointer. *************************************************************************/ | < < | 974 975 976 977 978 979 980 | } return rc; } /* ** End of background checkpointer. *************************************************************************/ |
Changes to ext/lsm1/lsm_unix.c.
︙ | ︙ | |||
224 225 226 227 228 229 230 231 232 233 234 235 236 237 | if( iSz<iMin ){ iSz = ((iMin + nIncrSz-1) / nIncrSz) * nIncrSz; prc = ftruncate(p->fd, iSz); if( prc!=0 ) return LSM_IOERR_BKPT; } p->pMap = mmap(0, iSz, PROT_READ|PROT_WRITE, MAP_SHARED, p->fd, 0); p->nMap = iSz; } *ppOut = p->pMap; *pnOut = p->nMap; return LSM_OK; } | > > > > | 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 | if( iSz<iMin ){ iSz = ((iMin + nIncrSz-1) / nIncrSz) * nIncrSz; prc = ftruncate(p->fd, iSz); if( prc!=0 ) return LSM_IOERR_BKPT; } p->pMap = mmap(0, iSz, PROT_READ|PROT_WRITE, MAP_SHARED, p->fd, 0); if( p->pMap==MAP_FAILED ){ p->pMap = 0; return LSM_IOERR_BKPT; } p->nMap = iSz; } *ppOut = p->pMap; *pnOut = p->nMap; return LSM_OK; } |
︙ | ︙ | |||
409 410 411 412 413 414 415 | p->nShm = nNew; } if( p->apShm[iChunk]==0 ){ p->apShm[iChunk] = mmap(0, LSM_SHM_CHUNK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, p->shmfd, iChunk*LSM_SHM_CHUNK_SIZE ); | | > > > | 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 | p->nShm = nNew; } if( p->apShm[iChunk]==0 ){ p->apShm[iChunk] = mmap(0, LSM_SHM_CHUNK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, p->shmfd, iChunk*LSM_SHM_CHUNK_SIZE ); if( p->apShm[iChunk]==MAP_FAILED ){ p->apShm[iChunk] = 0; return LSM_IOERR_BKPT; } } *ppShm = p->apShm[iChunk]; return LSM_OK; } static void lsmPosixOsShmBarrier(void){ |
︙ | ︙ |
Changes to ext/lsm1/lsm_vtab.c.
︙ | ︙ | |||
838 839 840 841 842 843 844 | int argIdx = -1; /* Index of the key== constraint, or -1 if none */ int iIdx2 = -1; /* The index of the second key */ int omit1 = 0; int omit2 = 0; const struct sqlite3_index_constraint *pConstraint; pConstraint = pIdxInfo->aConstraint; | | | 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 | int argIdx = -1; /* Index of the key== constraint, or -1 if none */ int iIdx2 = -1; /* The index of the second key */ int omit1 = 0; int omit2 = 0; const struct sqlite3_index_constraint *pConstraint; pConstraint = pIdxInfo->aConstraint; for(i=0; i<pIdxInfo->nConstraint; i++, pConstraint++){ if( pConstraint->usable==0 ) continue; if( pConstraint->iColumn!=0 ) continue; switch( pConstraint->op ){ case SQLITE_INDEX_CONSTRAINT_EQ: { if( idxNum>0 ){ argIdx = i; iIdx2 = -1; |
︙ | ︙ |
Changes to ext/lsm1/test/lsm1_simple.test.
︙ | ︙ | |||
84 85 86 87 88 89 90 91 92 93 | INSERT INTO x1(a,b,c,d) VALUES(15, 11, 22, 33),(8,'banjo',x'333231',NULL), (12,NULL,3.25,-559281390); SELECT quote(a), quote(b), quote(c), quote(d), '|' FROM x1; } {'12' NULL 3.25 -559281390 | '15' 11 22 33 | '8' 'banjo' X'333231' NULL |} do_execsql_test 211 { SELECT quote(a), quote(lsm1_key), quote(lsm1_value), '|' FROM x1; } {'12' X'3132' X'05320000000000000A401FFB42ABE9DB' | '15' X'3135' X'4284C6' | '8' X'38' X'2162616E6A6F1633323105' |} finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | INSERT INTO x1(a,b,c,d) VALUES(15, 11, 22, 33),(8,'banjo',x'333231',NULL), (12,NULL,3.25,-559281390); SELECT quote(a), quote(b), quote(c), quote(d), '|' FROM x1; } {'12' NULL 3.25 -559281390 | '15' 11 22 33 | '8' 'banjo' X'333231' NULL |} do_execsql_test 211 { SELECT quote(a), quote(lsm1_key), quote(lsm1_value), '|' FROM x1; } {'12' X'3132' X'05320000000000000A401FFB42ABE9DB' | '15' X'3135' X'4284C6' | '8' X'38' X'2162616E6A6F1633323105' |} do_execsql_test 212 { SELECT quote(a), quote(lsm1_key), quote(lsm1_value) FROM x1 WHERE a='12'; } {'12' X'3132' X'05320000000000000A401FFB42ABE9DB'} #------------------------------------------------------------------------- reset_db forcedelete testlsm.db load_lsm1_vtab db do_execsql_test 300 { CREATE VIRTUAL TABLE x1 USING lsm1(testlsm.db,a,TEXT,b,c,d); } do_eqp_test 310 { SELECT * FROM x1 WHERE a=? } {SCAN TABLE x1 VIRTUAL TABLE INDEX 0:} do_eqp_test 320 { SELECT * FROM x1 WHERE a>? } {SCAN TABLE x1 VIRTUAL TABLE INDEX 2:} do_eqp_test 330 { SELECT * FROM x1 WHERE a<? } {SCAN TABLE x1 VIRTUAL TABLE INDEX 3:} do_eqp_test 340 { SELECT * FROM x1 WHERE a BETWEEN ? AND ? } {SCAN TABLE x1 VIRTUAL TABLE INDEX 1:} #------------------------------------------------------------------------- reset_db forcedelete testlsm.db load_lsm1_vtab db do_execsql_test 400 { CREATE VIRTUAL TABLE x1 USING lsm1(testlsm.db,a,TEXT,b); INSERT INTO x1 VALUES('one', 1); INSERT INTO x1 VALUES('two', 2); INSERT INTO x1 VALUES('three', 3); INSERT INTO x1 VALUES('four', 4); INSERT INTO x1 VALUES('five', 5); } do_execsql_test 410 { SELECT b FROM x1 WHERE a = 'two' } {2} do_execsql_test 411 { SELECT b FROM x1 WHERE a = 'one' } {1} do_execsql_test 412 { SELECT b FROM x1 WHERE a = 'five' } {5} do_execsql_test 420 { SELECT b FROM x1 WHERE a BETWEEN 'one' AND 'three'; } {1 3} do_execsql_test 421 { SELECT b FROM x1 WHERE a BETWEEN 'five' AND 'two'; } {5 4 1 3 2} do_execsql_test 421 { SELECT b FROM x1 WHERE a > 'five'; } {4 1 3 2} do_execsql_test 421 { SELECT b FROM x1 WHERE a <= 'three'; } {3 1 4 5} finish_test |
Changes to ext/misc/amatch.c.
︙ | ︙ | |||
615 616 617 618 619 620 621 | 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 { | | | 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 | 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_malloc64( sizeof(*pRule) + nFrom + nTo ); if( pRule==0 ){ rc = SQLITE_NOMEM; }else{ memset(pRule, 0, sizeof(*pRule)); pRule->zFrom = &pRule->zTo[nTo+1]; pRule->nFrom = (amatch_len)nFrom; memcpy(pRule->zFrom, zFrom, nFrom+1); |
︙ | ︙ | |||
734 735 736 737 738 739 740 | ** ** "abc" becomes abc ** 'xyz' becomes xyz ** [pqr] becomes pqr ** `mno` becomes mno */ static char *amatchDequote(const char *zIn){ | | | | | | 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 | ** ** "abc" becomes abc ** 'xyz' becomes xyz ** [pqr] becomes pqr ** `mno` becomes mno */ static char *amatchDequote(const char *zIn){ sqlite3_int64 nIn; /* Size of input string, in bytes */ char *zOut; /* Output (dequoted) string */ nIn = strlen(zIn); zOut = sqlite3_malloc64(nIn+1); if( zOut ){ char q = zIn[0]; /* Quote character (if any ) */ if( q!='[' && q!= '\'' && q!='"' && q!='`' ){ memcpy(zOut, zIn, (size_t)(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++; |
︙ | ︙ | |||
896 897 898 899 900 901 902 903 904 905 906 907 908 909 | 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 | > | 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 | 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 ){ sqlite3_vtab_config(db, SQLITE_VTAB_INNOCUOUS); 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 |
︙ | ︙ | |||
1065 1066 1067 1068 1069 1070 1071 | pWord->rCost, pWord->zWord, pWord->zCost); #endif pOther = amatchAvlInsert(&pCur->pCost, &pWord->sCost); assert( pOther==0 ); (void)pOther; } return; } | | | 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 | pWord->rCost, pWord->zWord, pWord->zCost); #endif pOther = amatchAvlInsert(&pCur->pCost, &pWord->sCost); assert( pOther==0 ); (void)pOther; } return; } pWord = sqlite3_malloc64( 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 = (short)nMatch; pWord->pNext = pCur->pAllWords; |
︙ | ︙ |
Changes to ext/misc/appendvfs.c.
︙ | ︙ | |||
10 11 12 13 14 15 16 | ** ****************************************************************************** ** ** This file implements a VFS shim that allows an SQLite database to be ** appended onto the end of some other file, such as an executable. ** ** A special record must appear at the end of the file that identifies the | | > | | | | | < < < | < | | > > | | | | | | | | > | | > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | > | 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 | ** ****************************************************************************** ** ** This file implements a VFS shim that allows an SQLite database to be ** appended onto the end of some other file, such as an executable. ** ** A special record must appear at the end of the file that identifies the ** file as an appended database and provides the offset to the first page ** of the exposed content. (Or, it is the length of the content prefix.) ** For best performance page 1 should be located at a disk page boundary, ** though that is not required. ** ** When opening a database using this VFS, the connection might treat ** the file as an ordinary SQLite database, or it might treat it as a ** database appended onto some other file. The decision is made by ** applying the following rules in order: ** ** (1) An empty file is an ordinary database. ** ** (2) If the file ends with the appendvfs trailer string ** "Start-Of-SQLite3-NNNNNNNN" that file is an appended database. ** ** (3) If the file begins with the standard SQLite prefix string ** "SQLite format 3", that file is an ordinary database. ** ** (4) If none of the above apply and the SQLITE_OPEN_CREATE flag is ** set, then a new database is appended to the already existing file. ** ** (5) Otherwise, SQLITE_CANTOPEN is returned. ** ** To avoid unnecessary complications with the PENDING_BYTE, the size of ** the file containing the database is limited to 1GiB. (1073741824 bytes) ** This VFS will not read or write past the 1GiB mark. This restriction ** might be lifted in future versions. For now, if you need a larger ** database, then keep it in a separate file. ** ** If the file being opened is a plain database (not an appended one), then ** this shim is a pass-through into the default underlying VFS. (rule 3) **/ #include "sqlite3ext.h" SQLITE_EXTENSION_INIT1 #include <string.h> #include <assert.h> /* The append mark at the end of the database is: ** ** Start-Of-SQLite3-NNNNNNNN ** 123456789 123456789 12345 ** ** The NNNNNNNN represents a 64-bit big-endian unsigned integer which is ** the offset to page 1, and also the length of the prefix content. */ #define APND_MARK_PREFIX "Start-Of-SQLite3-" #define APND_MARK_PREFIX_SZ 17 #define APND_MARK_FOS_SZ 8 #define APND_MARK_SIZE (APND_MARK_PREFIX_SZ+APND_MARK_FOS_SZ) /* ** Maximum size of the combined prefix + database + append-mark. This ** must be less than 0x40000000 to avoid locking issues on Windows. */ #define APND_MAX_SIZE (0x40000000) /* ** Try to align the database to an even multiple of APND_ROUNDUP bytes. */ #ifndef APND_ROUNDUP #define APND_ROUNDUP 4096 #endif #define APND_ALIGN_MASK ((sqlite3_int64)(APND_ROUNDUP-1)) #define APND_START_ROUNDUP(fsz) (((fsz)+APND_ALIGN_MASK) & ~APND_ALIGN_MASK) /* ** Forward declaration of objects used by this utility */ typedef struct sqlite3_vfs ApndVfs; typedef struct ApndFile ApndFile; /* Access to a lower-level VFS that (might) implement dynamic loading, ** access to randomness, etc. */ #define ORIGVFS(p) ((sqlite3_vfs*)((p)->pAppData)) #define ORIGFILE(p) ((sqlite3_file*)(((ApndFile*)(p))+1)) /* An open appendvfs file ** ** An instance of this structure describes the appended database file. ** A separate sqlite3_file object is always appended. The appended ** sqlite3_file object (which can be accessed using ORIGFILE()) describes ** the entire file, including the prefix, the database, and the ** append-mark. ** ** The structure of an AppendVFS database is like this: ** ** +-------------+---------+----------+-------------+ ** | prefix-file | padding | database | append-mark | ** +-------------+---------+----------+-------------+ ** ^ ^ ** | | ** iPgOne iMark ** ** ** "prefix file" - file onto which the database has been appended. ** "padding" - zero or more bytes inserted so that "database" ** starts on an APND_ROUNDUP boundary ** "database" - The SQLite database file ** "append-mark" - The 25-byte "Start-Of-SQLite3-NNNNNNNN" that indicates ** the offset from the start of prefix-file to the start ** of "database". ** ** The size of the database is iMark - iPgOne. ** ** The NNNNNNNN in the "Start-Of-SQLite3-NNNNNNNN" suffix is the value ** of iPgOne stored as a big-ending 64-bit integer. ** ** iMark will be the size of the underlying file minus 25 (APND_MARKSIZE). ** Or, iMark is -1 to indicate that it has not yet been written. */ struct ApndFile { sqlite3_file base; /* Subclass. MUST BE FIRST! */ sqlite3_int64 iPgOne; /* Offset to the start of the database */ sqlite3_int64 iMark; /* Offset of the append mark. -1 if unwritten */ /* Always followed by another sqlite3_file that describes the whole file */ }; /* ** Methods for ApndFile */ static int apndClose(sqlite3_file*); static int apndRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst); |
︙ | ︙ | |||
174 175 176 177 178 179 180 | apndShmLock, /* xShmLock */ apndShmBarrier, /* xShmBarrier */ apndShmUnmap, /* xShmUnmap */ apndFetch, /* xFetch */ apndUnfetch /* xUnfetch */ }; | < < | | | > > | > > | > > > > > < > | > > > | > > > < | > > < | < < < < < < | | > | < < | < | < < < > | < > | > | < < < < | < | | 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 | apndShmLock, /* xShmLock */ apndShmBarrier, /* xShmBarrier */ apndShmUnmap, /* xShmUnmap */ apndFetch, /* xFetch */ apndUnfetch /* xUnfetch */ }; /* ** Close an apnd-file. */ static int apndClose(sqlite3_file *pFile){ pFile = ORIGFILE(pFile); return pFile->pMethods->xClose(pFile); } /* ** Read data from an apnd-file. */ static int apndRead( sqlite3_file *pFile, void *zBuf, int iAmt, sqlite_int64 iOfst ){ ApndFile *paf = (ApndFile *)pFile; pFile = ORIGFILE(pFile); return pFile->pMethods->xRead(pFile, zBuf, iAmt, paf->iPgOne+iOfst); } /* ** Add the append-mark onto what should become the end of the file. * If and only if this succeeds, internal ApndFile.iMark is updated. * Parameter iWriteEnd is the appendvfs-relative offset of the new mark. */ static int apndWriteMark( ApndFile *paf, sqlite3_file *pFile, sqlite_int64 iWriteEnd ){ sqlite_int64 iPgOne = paf->iPgOne; unsigned char a[APND_MARK_SIZE]; int i = APND_MARK_FOS_SZ; int rc; assert(pFile == ORIGFILE(paf)); memcpy(a, APND_MARK_PREFIX, APND_MARK_PREFIX_SZ); while( --i >= 0 ){ a[APND_MARK_PREFIX_SZ+i] = (unsigned char)(iPgOne & 0xff); iPgOne >>= 8; } iWriteEnd += paf->iPgOne; if( SQLITE_OK==(rc = pFile->pMethods->xWrite (pFile, a, APND_MARK_SIZE, iWriteEnd)) ){ paf->iMark = iWriteEnd; } return rc; } /* ** Write data to an apnd-file. */ static int apndWrite( sqlite3_file *pFile, const void *zBuf, int iAmt, sqlite_int64 iOfst ){ ApndFile *paf = (ApndFile *)pFile; sqlite_int64 iWriteEnd = iOfst + iAmt; if( iWriteEnd>=APND_MAX_SIZE ) return SQLITE_FULL; pFile = ORIGFILE(pFile); /* If append-mark is absent or will be overwritten, write it. */ if( paf->iMark < 0 || paf->iPgOne + iWriteEnd > paf->iMark ){ int rc = apndWriteMark(paf, pFile, iWriteEnd); if( SQLITE_OK!=rc ) return rc; } return pFile->pMethods->xWrite(pFile, zBuf, iAmt, paf->iPgOne+iOfst); } /* ** Truncate an apnd-file. */ static int apndTruncate(sqlite3_file *pFile, sqlite_int64 size){ ApndFile *paf = (ApndFile *)pFile; pFile = ORIGFILE(pFile); /* The append mark goes out first so truncate failure does not lose it. */ if( SQLITE_OK!=apndWriteMark(paf, pFile, size) ) return SQLITE_IOERR; /* Truncate underlying file just past append mark */ return pFile->pMethods->xTruncate(pFile, paf->iMark+APND_MARK_SIZE); } /* ** Sync an apnd-file. */ static int apndSync(sqlite3_file *pFile, int flags){ pFile = ORIGFILE(pFile); return pFile->pMethods->xSync(pFile, flags); } /* ** Return the current file-size of an apnd-file. ** If the append mark is not yet there, the file-size is 0. */ static int apndFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){ ApndFile *paf = (ApndFile *)pFile; *pSize = ( paf->iMark >= 0 )? (paf->iMark - paf->iPgOne) : 0; return SQLITE_OK; } /* ** Lock an apnd-file. */ static int apndLock(sqlite3_file *pFile, int eLock){ pFile = ORIGFILE(pFile); |
︙ | ︙ | |||
304 305 306 307 308 309 310 | return pFile->pMethods->xCheckReservedLock(pFile, pResOut); } /* ** File control method. For custom operations on an apnd-file. */ static int apndFileControl(sqlite3_file *pFile, int op, void *pArg){ | | > | | 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 | return pFile->pMethods->xCheckReservedLock(pFile, pResOut); } /* ** File control method. For custom operations on an apnd-file. */ static int apndFileControl(sqlite3_file *pFile, int op, void *pArg){ ApndFile *paf = (ApndFile *)pFile; int rc; pFile = ORIGFILE(pFile); if( op==SQLITE_FCNTL_SIZE_HINT ) *(sqlite3_int64*)pArg += paf->iPgOne; rc = pFile->pMethods->xFileControl(pFile, op, pArg); if( rc==SQLITE_OK && op==SQLITE_FCNTL_VFSNAME ){ *(char**)pArg = sqlite3_mprintf("apnd(%lld)/%z", paf->iPgOne,*(char**)pArg); } return rc; } /* ** Return the sector-size in bytes for an apnd-file. */ |
︙ | ︙ | |||
368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 | static int apndFetch( sqlite3_file *pFile, sqlite3_int64 iOfst, int iAmt, void **pp ){ ApndFile *p = (ApndFile *)pFile; pFile = ORIGFILE(pFile); return pFile->pMethods->xFetch(pFile, iOfst+p->iPgOne, iAmt, pp); } /* Release a memory-mapped page */ static int apndUnfetch(sqlite3_file *pFile, sqlite3_int64 iOfst, void *pPage){ ApndFile *p = (ApndFile *)pFile; pFile = ORIGFILE(pFile); return pFile->pMethods->xUnfetch(pFile, iOfst+p->iPgOne, pPage); } /* | > > > < < < < < < < < < < < < < | | > > > > > | | | > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | | < > > > > | < | < | > > | > > | | > > | < > | > > > | < | | > | > > > > > > > > < < < > > > > > > > > > > < < < | 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 | static int apndFetch( sqlite3_file *pFile, sqlite3_int64 iOfst, int iAmt, void **pp ){ ApndFile *p = (ApndFile *)pFile; if( p->iMark < 0 || iOfst+iAmt > p->iMark ){ return SQLITE_IOERR; /* Cannot read what is not yet there. */ } pFile = ORIGFILE(pFile); return pFile->pMethods->xFetch(pFile, iOfst+p->iPgOne, iAmt, pp); } /* Release a memory-mapped page */ static int apndUnfetch(sqlite3_file *pFile, sqlite3_int64 iOfst, void *pPage){ ApndFile *p = (ApndFile *)pFile; pFile = ORIGFILE(pFile); return pFile->pMethods->xUnfetch(pFile, iOfst+p->iPgOne, pPage); } /* ** Try to read the append-mark off the end of a file. Return the ** start of the appended database if the append-mark is present. ** If there is no valid append-mark, return -1; ** ** An append-mark is only valid if the NNNNNNNN start-of-database offset ** indicates that the appended database contains at least one page. The ** start-of-database value must be a multiple of 512. */ static sqlite3_int64 apndReadMark(sqlite3_int64 sz, sqlite3_file *pFile){ int rc, i; sqlite3_int64 iMark; int msbs = 8 * (APND_MARK_FOS_SZ-1); unsigned char a[APND_MARK_SIZE]; if( APND_MARK_SIZE!=(sz & 0x1ff) ) return -1; rc = pFile->pMethods->xRead(pFile, a, APND_MARK_SIZE, sz-APND_MARK_SIZE); if( rc ) return -1; if( memcmp(a, APND_MARK_PREFIX, APND_MARK_PREFIX_SZ)!=0 ) return -1; iMark = ((sqlite3_int64)(a[APND_MARK_PREFIX_SZ] & 0x7f)) << msbs; for(i=1; i<8; i++){ msbs -= 8; iMark |= (sqlite3_int64)a[APND_MARK_PREFIX_SZ+i]<<msbs; } if( iMark > (sz - APND_MARK_SIZE - 512) ) return -1; if( iMark & 0x1ff ) return -1; return iMark; } static const char apvfsSqliteHdr[] = "SQLite format 3"; /* ** Check to see if the file is an appendvfs SQLite database file. ** Return true iff it is such. Parameter sz is the file's size. */ static int apndIsAppendvfsDatabase(sqlite3_int64 sz, sqlite3_file *pFile){ int rc; char zHdr[16]; sqlite3_int64 iMark = apndReadMark(sz, pFile); if( iMark>=0 ){ /* If file has the correct end-marker, the expected odd size, and the ** SQLite DB type marker where the end-marker puts it, then it ** is an appendvfs database. */ rc = pFile->pMethods->xRead(pFile, zHdr, sizeof(zHdr), iMark); if( SQLITE_OK==rc && memcmp(zHdr, apvfsSqliteHdr, sizeof(zHdr))==0 && (sz & 0x1ff) == APND_MARK_SIZE && sz>=512+APND_MARK_SIZE ){ return 1; /* It's an appendvfs database */ } } return 0; } /* ** Check to see if the file is an ordinary SQLite database file. ** Return true iff so. Parameter sz is the file's size. */ static int apndIsOrdinaryDatabaseFile(sqlite3_int64 sz, sqlite3_file *pFile){ char zHdr[16]; if( apndIsAppendvfsDatabase(sz, pFile) /* rule 2 */ || (sz & 0x1ff) != 0 || SQLITE_OK!=pFile->pMethods->xRead(pFile, zHdr, sizeof(zHdr), 0) || memcmp(zHdr, apvfsSqliteHdr, sizeof(zHdr))!=0 ){ return 0; }else{ return 1; } } /* ** Open an apnd file handle. */ static int apndOpen( sqlite3_vfs *pApndVfs, const char *zName, sqlite3_file *pFile, int flags, int *pOutFlags ){ ApndFile *pApndFile = (ApndFile*)pFile; sqlite3_file *pBaseFile = ORIGFILE(pFile); sqlite3_vfs *pBaseVfs = ORIGVFS(pApndVfs); int rc; sqlite3_int64 sz = 0; if( (flags & SQLITE_OPEN_MAIN_DB)==0 ){ /* The appendvfs is not to be used for transient or temporary databases. ** Just use the base VFS open to initialize the given file object and ** open the underlying file. (Appendvfs is then unused for this file.) */ return pBaseVfs->xOpen(pBaseVfs, zName, pFile, flags, pOutFlags); } memset(pApndFile, 0, sizeof(ApndFile)); pFile->pMethods = &apnd_io_methods; pApndFile->iMark = -1; /* Append mark not yet written */ rc = pBaseVfs->xOpen(pBaseVfs, zName, pBaseFile, flags, pOutFlags); if( rc==SQLITE_OK ){ rc = pBaseFile->pMethods->xFileSize(pBaseFile, &sz); if( rc ){ pBaseFile->pMethods->xClose(pBaseFile); } } if( rc ){ pFile->pMethods = 0; return rc; } if( apndIsOrdinaryDatabaseFile(sz, pBaseFile) ){ /* The file being opened appears to be just an ordinary DB. Copy ** the base dispatch-table so this instance mimics the base VFS. */ memmove(pApndFile, pBaseFile, pBaseVfs->szOsFile); return SQLITE_OK; } pApndFile->iPgOne = apndReadMark(sz, pFile); if( pApndFile->iPgOne>=0 ){ pApndFile->iMark = sz - APND_MARK_SIZE; /* Append mark found */ return SQLITE_OK; } if( (flags & SQLITE_OPEN_CREATE)==0 ){ pBaseFile->pMethods->xClose(pBaseFile); rc = SQLITE_CANTOPEN; pFile->pMethods = 0; }else{ /* Round newly added appendvfs location to #define'd page boundary. ** Note that nothing has yet been written to the underlying file. ** The append mark will be written along with first content write. ** Until then, paf->iMark value indicates it is not yet written. */ pApndFile->iPgOne = APND_START_ROUNDUP(sz); } return rc; } /* ** Delete an apnd file. ** For an appendvfs, this could mean delete the appendvfs portion, ** leaving the appendee as it was before it gained an appendvfs. ** For now, this code deletes the underlying file too. */ static int apndDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){ return ORIGVFS(pVfs)->xDelete(ORIGVFS(pVfs), zPath, dirSync); } /* ** All other VFS methods are pass-thrus. */ static int apndAccess( sqlite3_vfs *pVfs, const char *zPath, int flags, int *pResOut ){ return ORIGVFS(pVfs)->xAccess(ORIGVFS(pVfs), zPath, flags, pResOut); |
︙ | ︙ | |||
547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 | ){ int rc = SQLITE_OK; sqlite3_vfs *pOrig; SQLITE_EXTENSION_INIT2(pApi); (void)pzErrMsg; (void)db; pOrig = sqlite3_vfs_find(0); apnd_vfs.iVersion = pOrig->iVersion; apnd_vfs.pAppData = pOrig; apnd_vfs.szOsFile = pOrig->szOsFile + sizeof(ApndFile); rc = sqlite3_vfs_register(&apnd_vfs, 0); #ifdef APPENDVFS_TEST if( rc==SQLITE_OK ){ rc = sqlite3_auto_extension((void(*)(void))apndvfsRegister); } #endif if( rc==SQLITE_OK ) rc = SQLITE_OK_LOAD_PERMANENTLY; return rc; } | > | 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 | ){ int rc = SQLITE_OK; sqlite3_vfs *pOrig; SQLITE_EXTENSION_INIT2(pApi); (void)pzErrMsg; (void)db; pOrig = sqlite3_vfs_find(0); if( pOrig==0 ) return SQLITE_ERROR; apnd_vfs.iVersion = pOrig->iVersion; apnd_vfs.pAppData = pOrig; apnd_vfs.szOsFile = pOrig->szOsFile + sizeof(ApndFile); rc = sqlite3_vfs_register(&apnd_vfs, 0); #ifdef APPENDVFS_TEST if( rc==SQLITE_OK ){ rc = sqlite3_auto_extension((void(*)(void))apndvfsRegister); } #endif if( rc==SQLITE_OK ) rc = SQLITE_OK_LOAD_PERMANENTLY; return rc; } |
Added ext/misc/blobio.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 | /* ** 2019-03-30 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ****************************************************************************** ** ** An SQL function that uses the incremental BLOB I/O mechanism of SQLite ** to read or write part of a blob. This is intended for debugging use ** in the CLI. ** ** readblob(SCHEMA,TABLE,COLUMN,ROWID,OFFSET,N) ** ** Returns N bytes of the blob starting at OFFSET. ** ** writeblob(SCHEMA,TABLE,COLUMN,ROWID,OFFSET,NEWDATA) ** ** NEWDATA must be a blob. The content of NEWDATA overwrites the ** existing BLOB data at SCHEMA.TABLE.COLUMN for row ROWID beginning ** at OFFSET bytes into the blob. */ #include "sqlite3ext.h" SQLITE_EXTENSION_INIT1 #include <assert.h> #include <string.h> static void readblobFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ sqlite3_blob *pBlob = 0; const char *zSchema; const char *zTable; const char *zColumn; sqlite3_int64 iRowid; int iOfst; unsigned char *aData; int nData; sqlite3 *db; int rc; zSchema = (const char*)sqlite3_value_text(argv[0]); zTable = (const char*)sqlite3_value_text(argv[1]); if( zTable==0 ){ sqlite3_result_error(context, "bad table name", -1); return; } zColumn = (const char*)sqlite3_value_text(argv[2]); if( zTable==0 ){ sqlite3_result_error(context, "bad column name", -1); return; } iRowid = sqlite3_value_int64(argv[3]); iOfst = sqlite3_value_int(argv[4]); nData = sqlite3_value_int(argv[5]); if( nData<=0 ) return; aData = sqlite3_malloc64( nData+1 ); if( aData==0 ){ sqlite3_result_error_nomem(context); return; } db = sqlite3_context_db_handle(context); rc = sqlite3_blob_open(db, zSchema, zTable, zColumn, iRowid, 0, &pBlob); if( rc ){ sqlite3_free(aData); sqlite3_result_error(context, "cannot open BLOB pointer", -1); return; } rc = sqlite3_blob_read(pBlob, aData, nData, iOfst); sqlite3_blob_close(pBlob); if( rc ){ sqlite3_free(aData); sqlite3_result_error(context, "BLOB read failed", -1); }else{ sqlite3_result_blob(context, aData, nData, sqlite3_free); } } static void writeblobFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ sqlite3_blob *pBlob = 0; const char *zSchema; const char *zTable; const char *zColumn; sqlite3_int64 iRowid; int iOfst; unsigned char *aData; int nData; sqlite3 *db; int rc; zSchema = (const char*)sqlite3_value_text(argv[0]); zTable = (const char*)sqlite3_value_text(argv[1]); if( zTable==0 ){ sqlite3_result_error(context, "bad table name", -1); return; } zColumn = (const char*)sqlite3_value_text(argv[2]); if( zTable==0 ){ sqlite3_result_error(context, "bad column name", -1); return; } iRowid = sqlite3_value_int64(argv[3]); iOfst = sqlite3_value_int(argv[4]); if( sqlite3_value_type(argv[5])!=SQLITE_BLOB ){ sqlite3_result_error(context, "6th argument must be a BLOB", -1); return; } nData = sqlite3_value_bytes(argv[5]); aData = (unsigned char *)sqlite3_value_blob(argv[5]); db = sqlite3_context_db_handle(context); rc = sqlite3_blob_open(db, zSchema, zTable, zColumn, iRowid, 1, &pBlob); if( rc ){ sqlite3_result_error(context, "cannot open BLOB pointer", -1); return; } rc = sqlite3_blob_write(pBlob, aData, nData, iOfst); sqlite3_blob_close(pBlob); if( rc ){ sqlite3_result_error(context, "BLOB write failed", -1); } } #ifdef _WIN32 __declspec(dllexport) #endif int sqlite3_blobio_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, "readblob", 6, SQLITE_UTF8, 0, readblobFunc, 0, 0); if( rc==SQLITE_OK ){ rc = sqlite3_create_function(db, "writeblob", 6, SQLITE_UTF8, 0, writeblobFunc, 0, 0); } return rc; } |
Changes to ext/misc/btreeinfo.c.
︙ | ︙ | |||
17 18 19 20 21 22 23 | ** The schema is like this: ** ** CREATE TABLE sqlite_btreeinfo( ** type TEXT, -- "table" or "index" ** name TEXT, -- Name of table or index for this btree. ** tbl_name TEXT, -- Associated table ** rootpage INT, -- The root page of the btree | | | | | | 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 | ** The schema is like this: ** ** CREATE TABLE sqlite_btreeinfo( ** type TEXT, -- "table" or "index" ** name TEXT, -- Name of table or index for this btree. ** tbl_name TEXT, -- Associated table ** rootpage INT, -- The root page of the btree ** sql TEXT, -- SQL for this btree - from sqlite_schema ** hasRowid BOOLEAN, -- True if the btree has a rowid ** nEntry INT, -- Estimated number of entries ** nPage INT, -- Estimated number of pages ** depth INT, -- Depth of the btree ** szPage INT, -- Size of each page in bytes ** zSchema TEXT HIDDEN -- The schema to which this btree belongs ** ); ** ** The first 5 fields are taken directly from the sqlite_schema table. ** Considering only the first 5 fields, the only difference between ** this virtual table and the sqlite_schema table is that this virtual ** table omits all entries that have a 0 or NULL rowid - in other words ** it omits triggers and views. ** ** The value added by this table comes in the next 5 fields. ** ** Note that nEntry and nPage are *estimated*. They are computed doing ** a single search from the root to a leaf, counting the number of cells |
︙ | ︙ | |||
84 85 86 87 88 89 90 | /* Forward declarations */ typedef struct BinfoTable BinfoTable; typedef struct BinfoCursor BinfoCursor; /* A cursor for the sqlite_btreeinfo table */ struct BinfoCursor { sqlite3_vtab_cursor base; /* Base class. Must be first */ | | | 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 | /* Forward declarations */ typedef struct BinfoTable BinfoTable; typedef struct BinfoCursor BinfoCursor; /* A cursor for the sqlite_btreeinfo table */ struct BinfoCursor { sqlite3_vtab_cursor base; /* Base class. Must be first */ sqlite3_stmt *pStmt; /* Query against sqlite_schema */ int rc; /* Result of previous sqlite_step() call */ int hasRowid; /* hasRowid value. Negative if unknown. */ sqlite3_int64 nEntry; /* nEntry value */ int nPage; /* nPage value */ int depth; /* depth value */ int szPage; /* size of a btree page. 0 if unknown */ char *zSchema; /* Schema being interrogated */ |
︙ | ︙ | |||
238 239 240 241 242 243 244 | sqlite3_free(pCsr->zSchema); if( idxNum==1 && sqlite3_value_type(argv[0])!=SQLITE_NULL ){ pCsr->zSchema = sqlite3_mprintf("%s", sqlite3_value_text(argv[0])); }else{ pCsr->zSchema = sqlite3_mprintf("main"); } zSql = sqlite3_mprintf( | | | | 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 | sqlite3_free(pCsr->zSchema); if( idxNum==1 && sqlite3_value_type(argv[0])!=SQLITE_NULL ){ pCsr->zSchema = sqlite3_mprintf("%s", sqlite3_value_text(argv[0])); }else{ pCsr->zSchema = sqlite3_mprintf("main"); } zSql = sqlite3_mprintf( "SELECT 0, 'table','sqlite_schema','sqlite_schema',1,NULL " "UNION ALL " "SELECT rowid, type, name, tbl_name, rootpage, sql" " FROM \"%w\".sqlite_schema WHERE rootpage>=1", pCsr->zSchema); sqlite3_finalize(pCsr->pStmt); pCsr->pStmt = 0; pCsr->hasRowid = -1; rc = sqlite3_prepare_v2(pTab->db, zSql, -1, &pCsr->pStmt, 0); sqlite3_free(zSql); if( rc==SQLITE_OK ){ |
︙ | ︙ |
Changes to ext/misc/carray.c.
︙ | ︙ | |||
20 21 22 23 24 25 26 | ** at the address $ptr. $ptr is a pointer to the array of integers. ** The pointer value must be assigned to $ptr using the ** sqlite3_bind_pointer() interface with a pointer type of "carray". ** For example: ** ** static int aX[] = { 53, 9, 17, 2231, 4, 99 }; ** int i = sqlite3_bind_parameter_index(pStmt, "$ptr"); | | | 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | ** at the address $ptr. $ptr is a pointer to the array of integers. ** The pointer value must be assigned to $ptr using the ** sqlite3_bind_pointer() interface with a pointer type of "carray". ** For example: ** ** static int aX[] = { 53, 9, 17, 2231, 4, 99 }; ** int i = sqlite3_bind_parameter_index(pStmt, "$ptr"); ** sqlite3_bind_pointer(pStmt, i, aX, "carray", 0); ** ** There is an optional third parameter to determine the datatype of ** the C-language array. Allowed values of the third parameter are ** 'int32', 'int64', 'double', 'char*'. Example: ** ** SELECT * FROM carray($ptr,10,'char*'); ** |
︙ | ︙ | |||
52 53 54 55 56 57 58 59 60 61 62 | ** as the number of elements in the array. The virtual table steps through ** the array, element by element. */ #include "sqlite3ext.h" SQLITE_EXTENSION_INIT1 #include <assert.h> #include <string.h> #ifndef SQLITE_OMIT_VIRTUALTABLE /* | > > > > > > > > > > > > > > > > > > | | < < < < > > > > | > > > | 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 | ** as the number of elements in the array. The virtual table steps through ** the array, element by element. */ #include "sqlite3ext.h" SQLITE_EXTENSION_INIT1 #include <assert.h> #include <string.h> /* Allowed values for the mFlags parameter to sqlite3_carray_bind(). ** Must exactly match the definitions in carray.h. */ #ifndef CARRAY_INT32 # define CARRAY_INT32 0 /* Data is 32-bit signed integers */ # define CARRAY_INT64 1 /* Data is 64-bit signed integers */ # define CARRAY_DOUBLE 2 /* Data is doubles */ # define CARRAY_TEXT 3 /* Data is char* */ #endif #ifndef SQLITE_API # ifdef _WIN32 # define SQLITE_API __declspec(dllexport) # else # define SQLITE_API # endif #endif #ifndef SQLITE_OMIT_VIRTUALTABLE /* ** Names of allowed datatypes */ static const char *azType[] = { "int32", "int64", "double", "char*" }; /* ** Structure used to hold the sqlite3_carray_bind() information */ typedef struct carray_bind carray_bind; struct carray_bind { void *aData; /* The data */ int nData; /* Number of elements */ int mFlags; /* Control flags */ void (*xDel)(void*); /* Destructor for aData */ }; /* carray_cursor is a subclass of sqlite3_vtab_cursor which will ** serve as the underlying representation of a cursor that scans ** over rows of the result */ typedef struct carray_cursor carray_cursor; |
︙ | ︙ | |||
235 236 237 238 239 240 241 | */ static int carrayFilter( sqlite3_vtab_cursor *pVtabCursor, int idxNum, const char *idxStr, int argc, sqlite3_value **argv ){ carray_cursor *pCur = (carray_cursor *)pVtabCursor; | > > | > > > > > > > > > > | | | | | | | | | | | | | | | | | | | < < > > > > > > | > | > | | 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 | */ static int carrayFilter( sqlite3_vtab_cursor *pVtabCursor, int idxNum, const char *idxStr, int argc, sqlite3_value **argv ){ carray_cursor *pCur = (carray_cursor *)pVtabCursor; pCur->pPtr = 0; pCur->iCnt = 0; switch( idxNum ){ case 1: { carray_bind *pBind = sqlite3_value_pointer(argv[0], "carray-bind"); if( pBind==0 ) break; pCur->pPtr = pBind->aData; pCur->iCnt = pBind->nData; pCur->eType = pBind->mFlags & 0x03; break; } case 2: case 3: { pCur->pPtr = sqlite3_value_pointer(argv[0], "carray"); pCur->iCnt = pCur->pPtr ? sqlite3_value_int64(argv[1]) : 0; if( idxNum<3 ){ pCur->eType = CARRAY_INT32; }else{ unsigned char i; const char *zType = (const char*)sqlite3_value_text(argv[2]); for(i=0; i<sizeof(azType)/sizeof(azType[0]); i++){ if( sqlite3_stricmp(zType, azType[i])==0 ) break; } if( i>=sizeof(azType)/sizeof(azType[0]) ){ pVtabCursor->pVtab->zErrMsg = sqlite3_mprintf( "unknown datatype: %Q", zType); return SQLITE_ERROR; }else{ pCur->eType = i; } } break; } } pCur->iRowid = 1; return SQLITE_OK; } /* ** SQLite will invoke this method one or more times while planning a query ** that uses the carray virtual table. This routine needs to create ** a query plan for each invocation and compute an estimated cost for that ** plan. ** ** In this implementation idxNum is used to represent the ** query plan. idxStr is unused. ** ** idxNum is: ** ** 1 If only the pointer= constraint exists. In this case, the ** parameter must be bound using sqlite3_carray_bind(). ** ** 2 if the pointer= and count= constraints exist. ** ** 3 if the ctype= constraint also exists. ** ** idxNum is 0 otherwise and carray becomes an empty table. */ static int carrayBestIndex( sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo ){ int i; /* Loop over constraints */ int ptrIdx = -1; /* Index of the pointer= constraint, or -1 if none */ |
︙ | ︙ | |||
301 302 303 304 305 306 307 | cntIdx = i; break; case CARRAY_COLUMN_CTYPE: ctypeIdx = i; break; } } | | < < > > > > | | | | | > | 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 | cntIdx = i; break; case CARRAY_COLUMN_CTYPE: ctypeIdx = i; break; } } if( ptrIdx>=0 ){ pIdxInfo->aConstraintUsage[ptrIdx].argvIndex = 1; pIdxInfo->aConstraintUsage[ptrIdx].omit = 1; pIdxInfo->estimatedCost = (double)1; pIdxInfo->estimatedRows = 100; pIdxInfo->idxNum = 1; if( cntIdx>=0 ){ pIdxInfo->aConstraintUsage[cntIdx].argvIndex = 2; pIdxInfo->aConstraintUsage[cntIdx].omit = 1; pIdxInfo->idxNum = 2; if( ctypeIdx>=0 ){ pIdxInfo->aConstraintUsage[ctypeIdx].argvIndex = 3; pIdxInfo->aConstraintUsage[ctypeIdx].omit = 1; pIdxInfo->idxNum = 3; } } }else{ pIdxInfo->estimatedCost = (double)2147483647; pIdxInfo->estimatedRows = 2147483647; pIdxInfo->idxNum = 0; } return SQLITE_OK; |
︙ | ︙ | |||
348 349 350 351 352 353 354 355 356 357 358 359 360 361 | 0, /* xBegin */ 0, /* xSync */ 0, /* xCommit */ 0, /* xRollback */ 0, /* xFindMethod */ 0, /* xRename */ }; /* ** For testing purpose in the TCL test harness, we need a method for ** setting the pointer value. The inttoptr(X) SQL function accomplishes ** this. Tcl script will bind an integer to X and the inttoptr() SQL ** function will use sqlite3_result_pointer() to convert that integer into ** a pointer. | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | 0, /* xBegin */ 0, /* xSync */ 0, /* xCommit */ 0, /* xRollback */ 0, /* xFindMethod */ 0, /* xRename */ }; /* ** Destructor for the carray_bind object */ static void carrayBindDel(void *pPtr){ carray_bind *p = (carray_bind*)pPtr; if( p->xDel!=SQLITE_STATIC ){ p->xDel(p->aData); } sqlite3_free(p); } /* ** Invoke this interface in order to bind to the single-argument ** version of CARRAY(). */ SQLITE_API int sqlite3_carray_bind( sqlite3_stmt *pStmt, int idx, void *aData, int nData, int mFlags, void (*xDestroy)(void*) ){ carray_bind *pNew; int i; pNew = sqlite3_malloc64(sizeof(*pNew)); if( pNew==0 ){ if( xDestroy!=SQLITE_STATIC && xDestroy!=SQLITE_TRANSIENT ){ xDestroy(aData); } return SQLITE_NOMEM; } pNew->nData = nData; pNew->mFlags = mFlags; if( xDestroy==SQLITE_TRANSIENT ){ sqlite3_int64 sz = nData; switch( mFlags & 0x03 ){ case CARRAY_INT32: sz *= 4; break; case CARRAY_INT64: sz *= 8; break; case CARRAY_DOUBLE: sz *= 8; break; case CARRAY_TEXT: sz *= sizeof(char*); break; } if( (mFlags & 0x03)==CARRAY_TEXT ){ for(i=0; i<nData; i++){ const char *z = ((char**)aData)[i]; if( z ) sz += strlen(z) + 1; } } pNew->aData = sqlite3_malloc64( sz ); if( pNew->aData==0 ){ sqlite3_free(pNew); return SQLITE_NOMEM; } if( (mFlags & 0x03)==CARRAY_TEXT ){ char **az = (char**)pNew->aData; char *z = (char*)&az[nData]; for(i=0; i<nData; i++){ const char *zData = ((char**)aData)[i]; sqlite3_int64 n; if( zData==0 ){ az[i] = 0; continue; } az[i] = z; n = strlen(zData); memcpy(z, zData, n+1); z += n+1; } }else{ memcpy(pNew->aData, aData, sz); } pNew->xDel = sqlite3_free; }else{ pNew->aData = aData; pNew->xDel = xDestroy; } return sqlite3_bind_pointer(pStmt, idx, pNew, "carray-bind", carrayBindDel); } /* ** For testing purpose in the TCL test harness, we need a method for ** setting the pointer value. The inttoptr(X) SQL function accomplishes ** this. Tcl script will bind an integer to X and the inttoptr() SQL ** function will use sqlite3_result_pointer() to convert that integer into ** a pointer. |
︙ | ︙ | |||
379 380 381 382 383 384 385 | } sqlite3_result_pointer(context, p, "carray", 0); } #endif /* SQLITE_TEST */ #endif /* SQLITE_OMIT_VIRTUALTABLE */ | < < < | | 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 | } sqlite3_result_pointer(context, p, "carray", 0); } #endif /* SQLITE_TEST */ #endif /* SQLITE_OMIT_VIRTUALTABLE */ SQLITE_API int sqlite3_carray_init( sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi ){ int rc = SQLITE_OK; SQLITE_EXTENSION_INIT2(pApi); #ifndef SQLITE_OMIT_VIRTUALTABLE |
︙ | ︙ |
Added ext/misc/carray.h.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | /* ** 2020-11-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. ** ************************************************************************* ** ** Interface definitions for the CARRAY table-valued function ** extension. */ #ifndef _CARRAY_H #define _CARRAY_H #include "sqlite3.h" /* Required for error code definitions */ #ifdef __cplusplus extern "C" { #endif /* Use this interface to bind an array to the single-argument version ** of CARRAY(). */ SQLITE_API int sqlite3_carray_bind( sqlite3_stmt *pStmt, /* Statement to be bound */ int i, /* Parameter index */ void *aData, /* Pointer to array data */ int nData, /* Number of data elements */ int mFlags, /* CARRAY flags */ void (*xDel)(void*) /* Destructgor for aData*/ ); /* Allowed values for the mFlags parameter to sqlite3_carray_bind(). */ #define CARRAY_INT32 0 /* Data is 32-bit signed integers */ #define CARRAY_INT64 1 /* Data is 64-bit signed integers */ #define CARRAY_DOUBLE 2 /* Data is doubles */ #define CARRAY_TEXT 3 /* Data is char* */ #ifdef __cplusplus } /* end of the 'extern "C"' block */ #endif #endif /* ifndef _CARRAY_H */ |
Added ext/misc/cksumvfs.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 | /* ** 2020-04-20 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ****************************************************************************** ** ** This file implements a VFS shim that writes a checksum on each page ** of an SQLite database file. When reading pages, the checksum is verified ** and an error is raised if the checksum is incorrect. ** ** COMPILING ** ** This extension requires SQLite 3.32.0 or later. It uses the ** sqlite3_database_file_object() interface which was added in ** version 3.32.0, so it will not link with an earlier version of ** SQLite. ** ** To build this extension as a separately loaded shared library or ** DLL, use compiler command-lines similar to the following: ** ** (linux) gcc -fPIC -shared cksumvfs.c -o cksumvfs.so ** (mac) clang -fPIC -dynamiclib cksumvfs.c -o cksumvfs.dylib ** (windows) cl cksumvfs.c -link -dll -out:cksumvfs.dll ** ** You may want to add additional compiler options, of course, ** according to the needs of your project. ** ** If you want to statically link this extension with your product, ** then compile it like any other C-language module but add the ** "-DSQLITE_CKSUMVFS_STATIC" option so that this module knows that ** it is being statically linked rather than dynamically linked ** ** LOADING ** ** To load this extension as a shared library, you first have to ** bring up a dummy SQLite database connection to use as the argument ** to the sqlite3_load_extension() API call. Then you invoke the ** sqlite3_load_extension() API and shutdown the dummy database ** connection. All subsequent database connections that are opened ** will include this extension. For example: ** ** sqlite3 *db; ** sqlite3_open(":memory:", &db); ** sqlite3_load_extention(db, "./cksumvfs"); ** sqlite3_close(db); ** ** If this extension is compiled with -DSQLITE_CKSUMVFS_STATIC and ** statically linked against the application, initialize it using ** a single API call as follows: ** ** sqlite3_register_cksumvfs(); ** ** Cksumvfs is a VFS Shim. When loaded, "cksmvfs" becomes the new ** default VFS and it uses the prior default VFS as the next VFS ** down in the stack. This is normally what you want. However, in ** complex situations where multiple VFS shims are being loaded, ** it might be important to ensure that cksumvfs is loaded in the ** correct order so that it sequences itself into the default VFS ** Shim stack in the right order. ** ** USING ** ** Open database connections using the sqlite3_open() or ** sqlite3_open_v2() interfaces, as normal. Ordinary database files ** (without a checksum) will operate normally. Databases with ** checksums will return an SQLITE_IOERR_DATA error if a page is ** encountered that contains an invalid checksum. ** ** Checksumming only works on databases that have a reserve-bytes ** value of exactly 8. The default value for reserve-bytes is 0. ** Hence, newly created database files will omit the checksum by ** default. To create a database that includes a checksum, change ** the reserve-bytes value to 8 by runing: ** ** int n = 8; ** sqlite3_file_control(db, 0, SQLITE_FCNTL_RESERVE_BYTES, &n); ** ** If you do this immediately after creating a new database file, ** before anything else has been written into the file, then that ** might be all that you need to do. Otherwise, the API call ** above should be followed by: ** ** sqlite3_exec(db, "VACUUM", 0, 0, 0); ** ** It never hurts to run the VACUUM, even if you don't need it. ** If the database is in WAL mode, you should shutdown and ** reopen all database connections before continuing. ** ** From the CLI, use the ".filectrl reserve_bytes 8" command, ** followed by "VACUUM;". ** ** Note that SQLite allows the number of reserve-bytes to be ** increased but not decreased. So if a database file already ** has a reserve-bytes value greater than 8, there is no way to ** activate checksumming on that database, other than to dump ** and restore the database file. Note also that other extensions ** might also make use of the reserve-bytes. Checksumming will ** be incompatible with those other extensions. ** ** VERIFICATION OF CHECKSUMS ** ** If any checksum is incorrect, the "PRAGMA quick_check" command ** will find it. To verify that checksums are actually enabled ** and running, use the following query: ** ** SELECT count(*), verify_checksum(data) ** FROM sqlite_dbpage ** GROUP BY 2; ** ** There are three possible outputs form the verify_checksum() ** function: 1, 0, and NULL. 1 is returned if the checksum is ** correct. 0 is returned if the checksum is incorrect. NULL ** is returned if the page is unreadable. If checksumming is ** enabled, the read will fail if the checksum is wrong, so the ** usual result from verify_checksum() on a bad checksum is NULL. ** ** If everything is OK, the query above should return a single ** row where the second column is 1. Any other result indicates ** either that there is a checksum error, or checksum validation ** is disabled. ** ** CONTROLLING CHECKSUM VERIFICATION ** ** The cksumvfs extension implements a new PRAGMA statement that can ** be used to disable, re-enable, or query the status of checksum ** verification: ** ** PRAGMA checksum_verification; -- query status ** PRAGMA checksum_verification=OFF; -- disable verification ** PRAGMA checksum_verification=ON; -- re-enable verification ** ** The "checksum_verification" pragma will return "1" (true) or "0" ** (false) if checksum verification is enabled or disabled, respectively. ** "Verification" in this context means the feature that causes ** SQLITE_IOERR_DATA errors if a checksum mismatch is detected while ** reading. Checksums are always kept up-to-date as long as the ** reserve-bytes value of the database is 8, regardless of the setting ** of this pragma. Checksum verification can be disabled (for example) ** to do forensic analysis of a database that has previously reported ** a checksum error. ** ** The "checksum_verification" pragma will always respond with "0" if ** the database file does not have a reserve-bytes value of 8. The ** pragma will return no rows at all if the cksumvfs extension is ** not loaded. ** ** IMPLEMENTATION NOTES ** ** The checksum is stored in the last 8 bytes of each page. This ** module only operates if the "bytes of reserved space on each page" ** value at offset 20 the SQLite database header is exactly 8. If ** the reserved-space value is not 8, this module is a no-op. */ #if defined(SQLITE_AMALGAMATION) && !defined(SQLITE_CKSUMVFS_STATIC) # define SQLITE_CKSUMVFS_STATIC #endif #ifdef SQLITE_CKSUMVFS_STATIC # include "sqlite3.h" #else # include "sqlite3ext.h" SQLITE_EXTENSION_INIT1 #endif #include <string.h> #include <assert.h> /* ** Forward declaration of objects used by this utility */ typedef struct sqlite3_vfs CksmVfs; typedef struct CksmFile CksmFile; /* ** Useful datatype abbreviations */ #if !defined(SQLITE_AMALGAMATION) typedef unsigned char u8; typedef unsigned int u32; #endif /* Access to a lower-level VFS that (might) implement dynamic loading, ** access to randomness, etc. */ #define ORIGVFS(p) ((sqlite3_vfs*)((p)->pAppData)) #define ORIGFILE(p) ((sqlite3_file*)(((CksmFile*)(p))+1)) /* An open file */ struct CksmFile { sqlite3_file base; /* IO methods */ const char *zFName; /* Original name of the file */ char computeCksm; /* True to compute checksums. ** Always true if reserve size is 8. */ char verifyCksm; /* True to verify checksums */ char isWal; /* True if processing a WAL file */ char inCkpt; /* Currently doing a checkpoint */ CksmFile *pPartner; /* Ptr from WAL to main-db, or from main-db to WAL */ }; /* ** Methods for CksmFile */ static int cksmClose(sqlite3_file*); static int cksmRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst); static int cksmWrite(sqlite3_file*,const void*,int iAmt, sqlite3_int64 iOfst); static int cksmTruncate(sqlite3_file*, sqlite3_int64 size); static int cksmSync(sqlite3_file*, int flags); static int cksmFileSize(sqlite3_file*, sqlite3_int64 *pSize); static int cksmLock(sqlite3_file*, int); static int cksmUnlock(sqlite3_file*, int); static int cksmCheckReservedLock(sqlite3_file*, int *pResOut); static int cksmFileControl(sqlite3_file*, int op, void *pArg); static int cksmSectorSize(sqlite3_file*); static int cksmDeviceCharacteristics(sqlite3_file*); static int cksmShmMap(sqlite3_file*, int iPg, int pgsz, int, void volatile**); static int cksmShmLock(sqlite3_file*, int offset, int n, int flags); static void cksmShmBarrier(sqlite3_file*); static int cksmShmUnmap(sqlite3_file*, int deleteFlag); static int cksmFetch(sqlite3_file*, sqlite3_int64 iOfst, int iAmt, void **pp); static int cksmUnfetch(sqlite3_file*, sqlite3_int64 iOfst, void *p); /* ** Methods for CksmVfs */ static int cksmOpen(sqlite3_vfs*, const char *, sqlite3_file*, int , int *); static int cksmDelete(sqlite3_vfs*, const char *zName, int syncDir); static int cksmAccess(sqlite3_vfs*, const char *zName, int flags, int *); static int cksmFullPathname(sqlite3_vfs*, const char *zName, int, char *zOut); static void *cksmDlOpen(sqlite3_vfs*, const char *zFilename); static void cksmDlError(sqlite3_vfs*, int nByte, char *zErrMsg); static void (*cksmDlSym(sqlite3_vfs *pVfs, void *p, const char*zSym))(void); static void cksmDlClose(sqlite3_vfs*, void*); static int cksmRandomness(sqlite3_vfs*, int nByte, char *zOut); static int cksmSleep(sqlite3_vfs*, int microseconds); static int cksmCurrentTime(sqlite3_vfs*, double*); static int cksmGetLastError(sqlite3_vfs*, int, char *); static int cksmCurrentTimeInt64(sqlite3_vfs*, sqlite3_int64*); static int cksmSetSystemCall(sqlite3_vfs*, const char*,sqlite3_syscall_ptr); static sqlite3_syscall_ptr cksmGetSystemCall(sqlite3_vfs*, const char *z); static const char *cksmNextSystemCall(sqlite3_vfs*, const char *zName); static sqlite3_vfs cksm_vfs = { 3, /* iVersion (set when registered) */ 0, /* szOsFile (set when registered) */ 1024, /* mxPathname */ 0, /* pNext */ "cksmvfs", /* zName */ 0, /* pAppData (set when registered) */ cksmOpen, /* xOpen */ cksmDelete, /* xDelete */ cksmAccess, /* xAccess */ cksmFullPathname, /* xFullPathname */ cksmDlOpen, /* xDlOpen */ cksmDlError, /* xDlError */ cksmDlSym, /* xDlSym */ cksmDlClose, /* xDlClose */ cksmRandomness, /* xRandomness */ cksmSleep, /* xSleep */ cksmCurrentTime, /* xCurrentTime */ cksmGetLastError, /* xGetLastError */ cksmCurrentTimeInt64, /* xCurrentTimeInt64 */ cksmSetSystemCall, /* xSetSystemCall */ cksmGetSystemCall, /* xGetSystemCall */ cksmNextSystemCall /* xNextSystemCall */ }; static const sqlite3_io_methods cksm_io_methods = { 3, /* iVersion */ cksmClose, /* xClose */ cksmRead, /* xRead */ cksmWrite, /* xWrite */ cksmTruncate, /* xTruncate */ cksmSync, /* xSync */ cksmFileSize, /* xFileSize */ cksmLock, /* xLock */ cksmUnlock, /* xUnlock */ cksmCheckReservedLock, /* xCheckReservedLock */ cksmFileControl, /* xFileControl */ cksmSectorSize, /* xSectorSize */ cksmDeviceCharacteristics, /* xDeviceCharacteristics */ cksmShmMap, /* xShmMap */ cksmShmLock, /* xShmLock */ cksmShmBarrier, /* xShmBarrier */ cksmShmUnmap, /* xShmUnmap */ cksmFetch, /* xFetch */ cksmUnfetch /* xUnfetch */ }; /* Do byte swapping on a unsigned 32-bit integer */ #define BYTESWAP32(x) ( \ (((x)&0x000000FF)<<24) + (((x)&0x0000FF00)<<8) \ + (((x)&0x00FF0000)>>8) + (((x)&0xFF000000)>>24) \ ) /* Compute a checksum on a buffer */ static void cksmCompute( u8 *a, /* Content to be checksummed */ int nByte, /* Bytes of content in a[]. Must be a multiple of 8. */ u8 *aOut /* OUT: Final 8-byte checksum value output */ ){ u32 s1 = 0, s2 = 0; u32 *aData = (u32*)a; u32 *aEnd = (u32*)&a[nByte]; u32 x = 1; assert( nByte>=8 ); assert( (nByte&0x00000007)==0 ); assert( nByte<=65536 ); if( 1 == *(u8*)&x ){ /* Little-endian */ do { s1 += *aData++ + s2; s2 += *aData++ + s1; }while( aData<aEnd ); }else{ /* Big-endian */ do { s1 += BYTESWAP32(aData[0]) + s2; s2 += BYTESWAP32(aData[1]) + s1; aData += 2; }while( aData<aEnd ); s1 = BYTESWAP32(s1); s2 = BYTESWAP32(s2); } memcpy(aOut, &s1, 4); memcpy(aOut+4, &s2, 4); } /* ** SQL function: verify_checksum(BLOB) ** ** Return 0 or 1 if the checksum is invalid or valid. Or return ** NULL if the input is not a BLOB that is the right size for a ** database page. */ static void cksmVerifyFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ int nByte; u8 *data; u8 cksum[8]; data = (u8*)sqlite3_value_blob(argv[0]); if( data==0 ) return; if( sqlite3_value_type(argv[0])!=SQLITE_BLOB ) return; nByte = sqlite3_value_bytes(argv[0]); if( nByte<512 || nByte>65536 || (nByte & (nByte-1))!=0 ) return; cksmCompute(data, nByte-8, cksum); sqlite3_result_int(context, memcmp(data+nByte-8,cksum,8)==0); } #ifdef SQLITE_CKSUMVFS_INIT_FUNCNAME /* ** SQL function: initialize_cksumvfs(SCHEMANAME) ** ** This SQL functions (whose name is actually determined at compile-time ** by the value of the SQLITE_CKSUMVFS_INIT_FUNCNAME macro) invokes: ** ** sqlite3_file_control(db, SCHEMANAME, SQLITE_FCNTL_RESERVE_BYTE, &n); ** ** In order to set the reserve bytes value to 8, so that cksumvfs will ** operation. This feature is provided (if and only if the ** SQLITE_CKSUMVFS_INIT_FUNCNAME compile-time option is set to a string ** which is the name of the SQL function) so as to provide the ability ** to invoke the file-control in programming languages that lack ** direct access to the sqlite3_file_control() interface (ex: Java). ** ** This interface is undocumented, apart from this comment. Usage ** example: ** ** 1. Compile with -DSQLITE_CKSUMVFS_INIT_FUNCNAME="ckvfs_init" ** 2. Run: "SELECT cksum_init('main'); VACUUM;" */ static void cksmInitFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ int nByte = 8; const char *zSchemaName = (const char*)sqlite3_value_text(argv[0]); sqlite3 *db = sqlite3_context_db_handle(context); sqlite3_file_control(db, zSchemaName, SQLITE_FCNTL_RESERVE_BYTES, &nByte); /* Return NULL */ } #endif /* SQLITE_CKSUMBFS_INIT_FUNCNAME */ /* ** Close a cksm-file. */ static int cksmClose(sqlite3_file *pFile){ CksmFile *p = (CksmFile *)pFile; if( p->pPartner ){ assert( p->pPartner->pPartner==p ); p->pPartner->pPartner = 0; p->pPartner = 0; } pFile = ORIGFILE(pFile); return pFile->pMethods->xClose(pFile); } /* ** Set the computeCkSm and verifyCksm flags, if they need to be ** changed. */ static void cksmSetFlags(CksmFile *p, int hasCorrectReserveSize){ if( hasCorrectReserveSize!=p->computeCksm ){ p->computeCksm = p->verifyCksm = hasCorrectReserveSize; if( p->pPartner ){ p->pPartner->verifyCksm = hasCorrectReserveSize; p->pPartner->computeCksm = hasCorrectReserveSize; } } } /* ** Read data from a cksm-file. */ static int cksmRead( sqlite3_file *pFile, void *zBuf, int iAmt, sqlite_int64 iOfst ){ int rc; CksmFile *p = (CksmFile *)pFile; pFile = ORIGFILE(pFile); rc = pFile->pMethods->xRead(pFile, zBuf, iAmt, iOfst); if( rc==SQLITE_OK ){ if( iOfst==0 && iAmt>=100 && ( memcmp(zBuf,"SQLite format 3",16)==0 || memcmp(zBuf,"ZV-",3)==0 )){ u8 *d = (u8*)zBuf; char hasCorrectReserveSize = (d[20]==8); cksmSetFlags(p, hasCorrectReserveSize); } /* Verify the checksum if ** (1) the size indicates that we are dealing with a complete ** database page ** (2) checksum verification is enabled ** (3) we are not in the middle of checkpoint */ if( iAmt>=512 /* (1) */ && p->verifyCksm /* (2) */ && !p->inCkpt /* (3) */ ){ u8 cksum[8]; cksmCompute((u8*)zBuf, iAmt-8, cksum); if( memcmp((u8*)zBuf+iAmt-8, cksum, 8)!=0 ){ sqlite3_log(SQLITE_IOERR_DATA, "checksum fault offset %lld of \"%s\"", iOfst, p->zFName); rc = SQLITE_IOERR_DATA; } } } return rc; } /* ** Write data to a cksm-file. */ static int cksmWrite( sqlite3_file *pFile, const void *zBuf, int iAmt, sqlite_int64 iOfst ){ CksmFile *p = (CksmFile *)pFile; pFile = ORIGFILE(pFile); if( iOfst==0 && iAmt>=100 && ( memcmp(zBuf,"SQLite format 3",16)==0 || memcmp(zBuf,"ZV-",3)==0 )){ u8 *d = (u8*)zBuf; char hasCorrectReserveSize = (d[20]==8); cksmSetFlags(p, hasCorrectReserveSize); } /* If the write size is appropriate for a database page and if ** checksums where ever enabled, then it will be safe to compute ** the checksums. The reserve byte size might have increased, but ** it will never decrease. And because it cannot decrease, the ** checksum will not overwrite anything. */ if( iAmt>=512 && p->computeCksm && !p->inCkpt ){ cksmCompute((u8*)zBuf, iAmt-8, ((u8*)zBuf)+iAmt-8); } return pFile->pMethods->xWrite(pFile, zBuf, iAmt, iOfst); } /* ** Truncate a cksm-file. */ static int cksmTruncate(sqlite3_file *pFile, sqlite_int64 size){ pFile = ORIGFILE(pFile); return pFile->pMethods->xTruncate(pFile, size); } /* ** Sync a cksm-file. */ static int cksmSync(sqlite3_file *pFile, int flags){ pFile = ORIGFILE(pFile); return pFile->pMethods->xSync(pFile, flags); } /* ** Return the current file-size of a cksm-file. */ static int cksmFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){ CksmFile *p = (CksmFile *)pFile; pFile = ORIGFILE(p); return pFile->pMethods->xFileSize(pFile, pSize); } /* ** Lock a cksm-file. */ static int cksmLock(sqlite3_file *pFile, int eLock){ pFile = ORIGFILE(pFile); return pFile->pMethods->xLock(pFile, eLock); } /* ** Unlock a cksm-file. */ static int cksmUnlock(sqlite3_file *pFile, int eLock){ pFile = ORIGFILE(pFile); return pFile->pMethods->xUnlock(pFile, eLock); } /* ** Check if another file-handle holds a RESERVED lock on a cksm-file. */ static int cksmCheckReservedLock(sqlite3_file *pFile, int *pResOut){ pFile = ORIGFILE(pFile); return pFile->pMethods->xCheckReservedLock(pFile, pResOut); } /* ** File control method. For custom operations on a cksm-file. */ static int cksmFileControl(sqlite3_file *pFile, int op, void *pArg){ int rc; CksmFile *p = (CksmFile*)pFile; pFile = ORIGFILE(pFile); if( op==SQLITE_FCNTL_PRAGMA ){ char **azArg = (char**)pArg; assert( azArg[1]!=0 ); if( sqlite3_stricmp(azArg[1],"checksum_verification")==0 ){ char *zArg = azArg[2]; if( zArg!=0 ){ if( (zArg[0]>='1' && zArg[0]<='9') || sqlite3_strlike("enable%",zArg,0)==0 || sqlite3_stricmp("yes",zArg)==0 || sqlite3_stricmp("on",zArg)==0 ){ p->verifyCksm = p->computeCksm; }else{ p->verifyCksm = 0; } if( p->pPartner ) p->pPartner->verifyCksm = p->verifyCksm; } azArg[0] = sqlite3_mprintf("%d",p->verifyCksm); return SQLITE_OK; }else if( p->computeCksm && azArg[2]!=0 && sqlite3_stricmp(azArg[1], "page_size")==0 ){ /* Do not allow page size changes on a checksum database */ return SQLITE_OK; } }else if( op==SQLITE_FCNTL_CKPT_START || op==SQLITE_FCNTL_CKPT_DONE ){ p->inCkpt = op==SQLITE_FCNTL_CKPT_START; if( p->pPartner ) p->pPartner->inCkpt = p->inCkpt; }else if( op==SQLITE_FCNTL_CKSM_FILE ){ /* This VFS needs to obtain a pointer to the corresponding database ** file handle from within xOpen() calls to open wal files. To do this, ** it uses the sqlite3_database_file_object() API to obtain a pointer ** to the file-handle used by SQLite to access the db file. This is ** fine if cksmvfs happens to be the top-level VFS, but not if there ** are one or more wrapper VFS. To handle this case, this file-control ** is used to extract the cksmvfs file-handle from any wrapper file ** handle. */ sqlite3_file **ppFile = (sqlite3_file**)pArg; *ppFile = (sqlite3_file*)p; return SQLITE_OK; } rc = pFile->pMethods->xFileControl(pFile, op, pArg); if( rc==SQLITE_OK && op==SQLITE_FCNTL_VFSNAME ){ *(char**)pArg = sqlite3_mprintf("cksm/%z", *(char**)pArg); } return rc; } /* ** Return the sector-size in bytes for a cksm-file. */ static int cksmSectorSize(sqlite3_file *pFile){ pFile = ORIGFILE(pFile); return pFile->pMethods->xSectorSize(pFile); } /* ** Return the device characteristic flags supported by a cksm-file. */ static int cksmDeviceCharacteristics(sqlite3_file *pFile){ pFile = ORIGFILE(pFile); return pFile->pMethods->xDeviceCharacteristics(pFile); } /* Create a shared memory file mapping */ static int cksmShmMap( sqlite3_file *pFile, int iPg, int pgsz, int bExtend, void volatile **pp ){ pFile = ORIGFILE(pFile); return pFile->pMethods->xShmMap(pFile,iPg,pgsz,bExtend,pp); } /* Perform locking on a shared-memory segment */ static int cksmShmLock(sqlite3_file *pFile, int offset, int n, int flags){ pFile = ORIGFILE(pFile); return pFile->pMethods->xShmLock(pFile,offset,n,flags); } /* Memory barrier operation on shared memory */ static void cksmShmBarrier(sqlite3_file *pFile){ pFile = ORIGFILE(pFile); pFile->pMethods->xShmBarrier(pFile); } /* Unmap a shared memory segment */ static int cksmShmUnmap(sqlite3_file *pFile, int deleteFlag){ pFile = ORIGFILE(pFile); return pFile->pMethods->xShmUnmap(pFile,deleteFlag); } /* Fetch a page of a memory-mapped file */ static int cksmFetch( sqlite3_file *pFile, sqlite3_int64 iOfst, int iAmt, void **pp ){ CksmFile *p = (CksmFile *)pFile; if( p->computeCksm ){ *pp = 0; return SQLITE_OK; } pFile = ORIGFILE(pFile); if( pFile->pMethods->iVersion>2 && pFile->pMethods->xFetch ){ return pFile->pMethods->xFetch(pFile, iOfst, iAmt, pp); } *pp = 0; return SQLITE_OK; } /* Release a memory-mapped page */ static int cksmUnfetch(sqlite3_file *pFile, sqlite3_int64 iOfst, void *pPage){ pFile = ORIGFILE(pFile); if( pFile->pMethods->iVersion>2 && pFile->pMethods->xUnfetch ){ return pFile->pMethods->xUnfetch(pFile, iOfst, pPage); } return SQLITE_OK; } /* ** Open a cksm file handle. */ static int cksmOpen( sqlite3_vfs *pVfs, const char *zName, sqlite3_file *pFile, int flags, int *pOutFlags ){ CksmFile *p; sqlite3_file *pSubFile; sqlite3_vfs *pSubVfs; int rc; pSubVfs = ORIGVFS(pVfs); if( (flags & (SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_WAL))==0 ){ return pSubVfs->xOpen(pSubVfs, zName, pFile, flags, pOutFlags); } p = (CksmFile*)pFile; memset(p, 0, sizeof(*p)); pSubFile = ORIGFILE(pFile); pFile->pMethods = &cksm_io_methods; rc = pSubVfs->xOpen(pSubVfs, zName, pSubFile, flags, pOutFlags); if( rc ) goto cksm_open_done; if( flags & SQLITE_OPEN_WAL ){ sqlite3_file *pDb = sqlite3_database_file_object(zName); rc = pDb->pMethods->xFileControl(pDb, SQLITE_FCNTL_CKSM_FILE, (void*)&pDb); assert( rc==SQLITE_OK ); p->pPartner = (CksmFile*)pDb; assert( p->pPartner->pPartner==0 ); p->pPartner->pPartner = p; p->isWal = 1; p->computeCksm = p->pPartner->computeCksm; }else{ p->isWal = 0; p->computeCksm = 0; } p->zFName = zName; cksm_open_done: if( rc ) pFile->pMethods = 0; return rc; } /* ** All other VFS methods are pass-thrus. */ static int cksmDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){ return ORIGVFS(pVfs)->xDelete(ORIGVFS(pVfs), zPath, dirSync); } static int cksmAccess( sqlite3_vfs *pVfs, const char *zPath, int flags, int *pResOut ){ return ORIGVFS(pVfs)->xAccess(ORIGVFS(pVfs), zPath, flags, pResOut); } static int cksmFullPathname( sqlite3_vfs *pVfs, const char *zPath, int nOut, char *zOut ){ return ORIGVFS(pVfs)->xFullPathname(ORIGVFS(pVfs),zPath,nOut,zOut); } static void *cksmDlOpen(sqlite3_vfs *pVfs, const char *zPath){ return ORIGVFS(pVfs)->xDlOpen(ORIGVFS(pVfs), zPath); } static void cksmDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){ ORIGVFS(pVfs)->xDlError(ORIGVFS(pVfs), nByte, zErrMsg); } static void (*cksmDlSym(sqlite3_vfs *pVfs, void *p, const char *zSym))(void){ return ORIGVFS(pVfs)->xDlSym(ORIGVFS(pVfs), p, zSym); } static void cksmDlClose(sqlite3_vfs *pVfs, void *pHandle){ ORIGVFS(pVfs)->xDlClose(ORIGVFS(pVfs), pHandle); } static int cksmRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){ return ORIGVFS(pVfs)->xRandomness(ORIGVFS(pVfs), nByte, zBufOut); } static int cksmSleep(sqlite3_vfs *pVfs, int nMicro){ return ORIGVFS(pVfs)->xSleep(ORIGVFS(pVfs), nMicro); } static int cksmCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){ return ORIGVFS(pVfs)->xCurrentTime(ORIGVFS(pVfs), pTimeOut); } static int cksmGetLastError(sqlite3_vfs *pVfs, int a, char *b){ return ORIGVFS(pVfs)->xGetLastError(ORIGVFS(pVfs), a, b); } static int cksmCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *p){ sqlite3_vfs *pOrig = ORIGVFS(pVfs); int rc; assert( pOrig->iVersion>=2 ); if( pOrig->xCurrentTimeInt64 ){ rc = pOrig->xCurrentTimeInt64(pOrig, p); }else{ double r; rc = pOrig->xCurrentTime(pOrig, &r); *p = (sqlite3_int64)(r*86400000.0); } return rc; } static int cksmSetSystemCall( sqlite3_vfs *pVfs, const char *zName, sqlite3_syscall_ptr pCall ){ return ORIGVFS(pVfs)->xSetSystemCall(ORIGVFS(pVfs),zName,pCall); } static sqlite3_syscall_ptr cksmGetSystemCall( sqlite3_vfs *pVfs, const char *zName ){ return ORIGVFS(pVfs)->xGetSystemCall(ORIGVFS(pVfs),zName); } static const char *cksmNextSystemCall(sqlite3_vfs *pVfs, const char *zName){ return ORIGVFS(pVfs)->xNextSystemCall(ORIGVFS(pVfs), zName); } /* Register the verify_checksum() SQL function. */ static int cksmRegisterFunc( sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi ){ int rc; if( db==0 ) return SQLITE_OK; rc = sqlite3_create_function(db, "verify_checksum", 1, SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_DETERMINISTIC, 0, cksmVerifyFunc, 0, 0); #ifdef SQLITE_CKSUMVFS_INIT_FUNCNAME (void)sqlite3_create_function(db, SQLITE_CKSUMVFS_INIT_FUNCNAME, 1, SQLITE_UTF8|SQLITE_DIRECTONLY, 0, cksmInitFunc, 0, 0); #endif return rc; } /* ** Register the cksum VFS as the default VFS for the system. ** Also make arrangements to automatically register the "verify_checksum()" ** SQL function on each new database connection. */ static int cksmRegisterVfs(void){ int rc = SQLITE_OK; sqlite3_vfs *pOrig; if( sqlite3_vfs_find("cksmvfs")!=0 ) return SQLITE_OK; pOrig = sqlite3_vfs_find(0); if( pOrig==0 ) return SQLITE_ERROR; cksm_vfs.iVersion = pOrig->iVersion; cksm_vfs.pAppData = pOrig; cksm_vfs.szOsFile = pOrig->szOsFile + sizeof(CksmFile); rc = sqlite3_vfs_register(&cksm_vfs, 1); if( rc==SQLITE_OK ){ rc = sqlite3_auto_extension((void(*)(void))cksmRegisterFunc); } return rc; } #if defined(SQLITE_CKSUMVFS_STATIC) /* This variant of the initializer runs when the extension is ** statically linked. */ int sqlite3_register_cksumvfs(const char *NotUsed){ (void)NotUsed; return cksmRegisterVfs(); } int sqlite3_unregister_cksumvfs(void){ if( sqlite3_vfs_find("cksmvfs") ){ sqlite3_vfs_unregister(&cksm_vfs); sqlite3_cancel_auto_extension((void(*)(void))cksmRegisterFunc); } return SQLITE_OK; } #endif /* defined(SQLITE_CKSUMVFS_STATIC */ #if !defined(SQLITE_CKSUMVFS_STATIC) /* This variant of the initializer function is used when the ** extension is shared library to be loaded at run-time. */ #ifdef _WIN32 __declspec(dllexport) #endif /* ** This routine is called by sqlite3_load_extension() when the ** extension is first loaded. ***/ int sqlite3_cksumvfs_init( sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi ){ int rc; SQLITE_EXTENSION_INIT2(pApi); (void)pzErrMsg; /* not used */ rc = cksmRegisterFunc(db, 0, 0); if( rc==SQLITE_OK ){ rc = cksmRegisterVfs(); } if( rc==SQLITE_OK ) rc = SQLITE_OK_LOAD_PERMANENTLY; return rc; } #endif /* !defined(SQLITE_CKSUMVFS_STATIC) */ |
Changes to ext/misc/closure.c.
︙ | ︙ | |||
418 419 420 421 422 423 424 | ** ** "abc" becomes abc ** 'xyz' becomes xyz ** [pqr] becomes pqr ** `mno` becomes mno */ static char *closureDequote(const char *zIn){ | | | | | | 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 | ** ** "abc" becomes abc ** 'xyz' becomes xyz ** [pqr] becomes pqr ** `mno` becomes mno */ static char *closureDequote(const char *zIn){ sqlite3_int64 nIn; /* Size of input string, in bytes */ char *zOut; /* Output (dequoted) string */ nIn = strlen(zIn); zOut = sqlite3_malloc64(nIn+1); if( zOut ){ char q = zIn[0]; /* Quote character (if any ) */ if( q!='[' && q!= '\'' && q!='"' && q!='`' ){ memcpy(zOut, zIn, (size_t)(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++; |
︙ | ︙ |
Changes to ext/misc/completion.c.
︙ | ︙ | |||
114 115 116 117 118 119 120 121 122 123 124 125 126 127 | /* Column numbers */ #define COMPLETION_COLUMN_CANDIDATE 0 /* Suggested completion of the input */ #define COMPLETION_COLUMN_PREFIX 1 /* Prefix of the word to be completed */ #define COMPLETION_COLUMN_WHOLELINE 2 /* Entire line seen so far */ #define COMPLETION_COLUMN_PHASE 3 /* ePhase - used for debugging only */ rc = sqlite3_declare_vtab(db, "CREATE TABLE x(" " candidate TEXT," " prefix TEXT HIDDEN," " wholeline TEXT HIDDEN," " phase INT HIDDEN" /* Used for debugging only */ ")"); | > | 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 | /* Column numbers */ #define COMPLETION_COLUMN_CANDIDATE 0 /* Suggested completion of the input */ #define COMPLETION_COLUMN_PREFIX 1 /* Prefix of the word to be completed */ #define COMPLETION_COLUMN_WHOLELINE 2 /* Entire line seen so far */ #define COMPLETION_COLUMN_PHASE 3 /* ePhase - used for debugging only */ sqlite3_vtab_config(db, SQLITE_VTAB_INNOCUOUS); rc = sqlite3_declare_vtab(db, "CREATE TABLE x(" " candidate TEXT," " prefix TEXT HIDDEN," " wholeline TEXT HIDDEN," " phase INT HIDDEN" /* Used for debugging only */ ")"); |
︙ | ︙ | |||
221 222 223 224 225 226 227 | char *zSql = 0; const char *zSep = ""; sqlite3_prepare_v2(pCur->db, "PRAGMA database_list", -1, &pS2, 0); while( sqlite3_step(pS2)==SQLITE_ROW ){ const char *zDb = (const char*)sqlite3_column_text(pS2, 1); zSql = sqlite3_mprintf( "%z%s" | | | 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 | char *zSql = 0; const char *zSep = ""; sqlite3_prepare_v2(pCur->db, "PRAGMA database_list", -1, &pS2, 0); while( sqlite3_step(pS2)==SQLITE_ROW ){ const char *zDb = (const char*)sqlite3_column_text(pS2, 1); zSql = sqlite3_mprintf( "%z%s" "SELECT name FROM \"%w\".sqlite_schema", zSql, zSep, zDb ); if( zSql==0 ) return SQLITE_NOMEM; zSep = " UNION "; } sqlite3_finalize(pS2); sqlite3_prepare_v2(pCur->db, zSql, -1, &pCur->pStmt, 0); |
︙ | ︙ | |||
245 246 247 248 249 250 251 | char *zSql = 0; const char *zSep = ""; sqlite3_prepare_v2(pCur->db, "PRAGMA database_list", -1, &pS2, 0); while( sqlite3_step(pS2)==SQLITE_ROW ){ const char *zDb = (const char*)sqlite3_column_text(pS2, 1); zSql = sqlite3_mprintf( "%z%s" | | | 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 | char *zSql = 0; const char *zSep = ""; sqlite3_prepare_v2(pCur->db, "PRAGMA database_list", -1, &pS2, 0); while( sqlite3_step(pS2)==SQLITE_ROW ){ const char *zDb = (const char*)sqlite3_column_text(pS2, 1); zSql = sqlite3_mprintf( "%z%s" "SELECT pti.name FROM \"%w\".sqlite_schema AS sm" " JOIN pragma_table_info(sm.name,%Q) AS pti" " WHERE sm.type='table'", zSql, zSep, zDb, zDb ); if( zSql==0 ) return SQLITE_NOMEM; zSep = " UNION "; } |
︙ | ︙ |
Changes to ext/misc/compress.c.
︙ | ︙ | |||
115 116 117 118 119 120 121 | sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi ){ int rc = SQLITE_OK; SQLITE_EXTENSION_INIT2(pApi); (void)pzErrMsg; /* Unused parameter */ | | > | | > | | 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 | 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, "compress", 1, SQLITE_UTF8 | SQLITE_INNOCUOUS, 0, compressFunc, 0, 0); if( rc==SQLITE_OK ){ rc = sqlite3_create_function(db, "uncompress", 1, SQLITE_UTF8 | SQLITE_INNOCUOUS | SQLITE_DETERMINISTIC, 0, uncompressFunc, 0, 0); } return rc; } |
Changes to ext/misc/csv.c.
︙ | ︙ | |||
617 618 619 620 621 622 623 | pNew->tstFlags = tstFlags; #endif if( bHeader!=1 ){ pNew->iStart = 0; }else if( pNew->zData ){ pNew->iStart = (int)sRdr.iIn; }else{ | | > > > > > > > > > | 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 | pNew->tstFlags = tstFlags; #endif if( bHeader!=1 ){ pNew->iStart = 0; }else if( pNew->zData ){ pNew->iStart = (int)sRdr.iIn; }else{ pNew->iStart = (int)(ftell(sRdr.in) - sRdr.nIn + sRdr.iIn); } csv_reader_reset(&sRdr); rc = sqlite3_declare_vtab(db, CSV_SCHEMA); if( rc ){ csv_errmsg(&sRdr, "bad schema: '%s' - %s", CSV_SCHEMA, sqlite3_errmsg(db)); goto csvtab_connect_error; } for(i=0; i<sizeof(azPValue)/sizeof(azPValue[0]); i++){ sqlite3_free(azPValue[i]); } /* Rationale for DIRECTONLY: ** An attacker who controls a database schema could use this vtab ** to exfiltrate sensitive data from other files in the filesystem. ** And, recommended practice is to put all CSV virtual tables in the ** TEMP namespace, so they should still be usable from within TEMP ** views, so there shouldn't be a serious loss of functionality by ** prohibiting the use of this vtab from persistent triggers and views. */ sqlite3_vtab_config(db, SQLITE_VTAB_DIRECTONLY); return SQLITE_OK; csvtab_connect_oom: rc = SQLITE_NOMEM; csv_errmsg(&sRdr, "out of memory"); csvtab_connect_error: |
︙ | ︙ | |||
763 764 765 766 767 768 769 | sqlite3_vtab_cursor *cur, /* The cursor */ sqlite3_context *ctx, /* First argument to sqlite3_result_...() */ int i /* Which column to return */ ){ CsvCursor *pCur = (CsvCursor*)cur; CsvTable *pTab = (CsvTable*)cur->pVtab; if( i>=0 && i<pTab->nCol && pCur->azVal[i]!=0 ){ | | | 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 | sqlite3_vtab_cursor *cur, /* The cursor */ sqlite3_context *ctx, /* First argument to sqlite3_result_...() */ int i /* Which column to return */ ){ CsvCursor *pCur = (CsvCursor*)cur; CsvTable *pTab = (CsvTable*)cur->pVtab; if( i>=0 && i<pTab->nCol && pCur->azVal[i]!=0 ){ sqlite3_result_text(ctx, pCur->azVal[i], -1, SQLITE_TRANSIENT); } return SQLITE_OK; } /* ** Return the rowid for the current row. */ |
︙ | ︙ |
Added ext/misc/dbdata.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 | /* ** 2019-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 file contains an implementation of two eponymous virtual tables, ** "sqlite_dbdata" and "sqlite_dbptr". Both modules require that the ** "sqlite_dbpage" eponymous virtual table be available. ** ** SQLITE_DBDATA: ** sqlite_dbdata is used to extract data directly from a database b-tree ** page and its associated overflow pages, bypassing the b-tree layer. ** The table schema is equivalent to: ** ** CREATE TABLE sqlite_dbdata( ** pgno INTEGER, ** cell INTEGER, ** field INTEGER, ** value ANY, ** schema TEXT HIDDEN ** ); ** ** IMPORTANT: THE VIRTUAL TABLE SCHEMA ABOVE IS SUBJECT TO CHANGE. IN THE ** FUTURE NEW NON-HIDDEN COLUMNS MAY BE ADDED BETWEEN "value" AND ** "schema". ** ** Each page of the database is inspected. If it cannot be interpreted as ** a b-tree page, or if it is a b-tree page containing 0 entries, the ** sqlite_dbdata table contains no rows for that page. Otherwise, the ** table contains one row for each field in the record associated with ** each cell on the page. For intkey b-trees, the key value is stored in ** field -1. ** ** For example, for the database: ** ** CREATE TABLE t1(a, b); -- root page is page 2 ** INSERT INTO t1(rowid, a, b) VALUES(5, 'v', 'five'); ** INSERT INTO t1(rowid, a, b) VALUES(10, 'x', 'ten'); ** ** the sqlite_dbdata table contains, as well as from entries related to ** page 1, content equivalent to: ** ** INSERT INTO sqlite_dbdata(pgno, cell, field, value) VALUES ** (2, 0, -1, 5 ), ** (2, 0, 0, 'v' ), ** (2, 0, 1, 'five'), ** (2, 1, -1, 10 ), ** (2, 1, 0, 'x' ), ** (2, 1, 1, 'ten' ); ** ** If database corruption is encountered, this module does not report an ** error. Instead, it attempts to extract as much data as possible and ** ignores the corruption. ** ** SQLITE_DBPTR: ** The sqlite_dbptr table has the following schema: ** ** CREATE TABLE sqlite_dbptr( ** pgno INTEGER, ** child INTEGER, ** schema TEXT HIDDEN ** ); ** ** It contains one entry for each b-tree pointer between a parent and ** child page in the database. */ #if !defined(SQLITEINT_H) #include "sqlite3ext.h" typedef unsigned char u8; #endif SQLITE_EXTENSION_INIT1 #include <string.h> #include <assert.h> #define DBDATA_PADDING_BYTES 100 typedef struct DbdataTable DbdataTable; typedef struct DbdataCursor DbdataCursor; /* Cursor object */ struct DbdataCursor { sqlite3_vtab_cursor base; /* Base class. Must be first */ sqlite3_stmt *pStmt; /* For fetching database pages */ int iPgno; /* Current page number */ u8 *aPage; /* Buffer containing page */ int nPage; /* Size of aPage[] in bytes */ int nCell; /* Number of cells on aPage[] */ int iCell; /* Current cell number */ int bOnePage; /* True to stop after one page */ int szDb; sqlite3_int64 iRowid; /* Only for the sqlite_dbdata table */ u8 *pRec; /* Buffer containing current record */ int nRec; /* Size of pRec[] in bytes */ int nHdr; /* Size of header in bytes */ int iField; /* Current field number */ u8 *pHdrPtr; u8 *pPtr; sqlite3_int64 iIntkey; /* Integer key value */ }; /* Table object */ struct DbdataTable { sqlite3_vtab base; /* Base class. Must be first */ sqlite3 *db; /* The database connection */ sqlite3_stmt *pStmt; /* For fetching database pages */ int bPtr; /* True for sqlite3_dbptr table */ }; /* Column and schema definitions for sqlite_dbdata */ #define DBDATA_COLUMN_PGNO 0 #define DBDATA_COLUMN_CELL 1 #define DBDATA_COLUMN_FIELD 2 #define DBDATA_COLUMN_VALUE 3 #define DBDATA_COLUMN_SCHEMA 4 #define DBDATA_SCHEMA \ "CREATE TABLE x(" \ " pgno INTEGER," \ " cell INTEGER," \ " field INTEGER," \ " value ANY," \ " schema TEXT HIDDEN" \ ")" /* Column and schema definitions for sqlite_dbptr */ #define DBPTR_COLUMN_PGNO 0 #define DBPTR_COLUMN_CHILD 1 #define DBPTR_COLUMN_SCHEMA 2 #define DBPTR_SCHEMA \ "CREATE TABLE x(" \ " pgno INTEGER," \ " child INTEGER," \ " schema TEXT HIDDEN" \ ")" /* ** Connect to an sqlite_dbdata (pAux==0) or sqlite_dbptr (pAux!=0) virtual ** table. */ static int dbdataConnect( sqlite3 *db, void *pAux, int argc, const char *const*argv, sqlite3_vtab **ppVtab, char **pzErr ){ DbdataTable *pTab = 0; int rc = sqlite3_declare_vtab(db, pAux ? DBPTR_SCHEMA : DBDATA_SCHEMA); if( rc==SQLITE_OK ){ pTab = (DbdataTable*)sqlite3_malloc64(sizeof(DbdataTable)); if( pTab==0 ){ rc = SQLITE_NOMEM; }else{ memset(pTab, 0, sizeof(DbdataTable)); pTab->db = db; pTab->bPtr = (pAux!=0); } } *ppVtab = (sqlite3_vtab*)pTab; return rc; } /* ** Disconnect from or destroy a sqlite_dbdata or sqlite_dbptr virtual table. */ static int dbdataDisconnect(sqlite3_vtab *pVtab){ DbdataTable *pTab = (DbdataTable*)pVtab; if( pTab ){ sqlite3_finalize(pTab->pStmt); sqlite3_free(pVtab); } return SQLITE_OK; } /* ** This function interprets two types of constraints: ** ** schema=? ** pgno=? ** ** If neither are present, idxNum is set to 0. If schema=? is present, ** the 0x01 bit in idxNum is set. If pgno=? is present, the 0x02 bit ** in idxNum is set. ** ** If both parameters are present, schema is in position 0 and pgno in ** position 1. */ static int dbdataBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdx){ DbdataTable *pTab = (DbdataTable*)tab; int i; int iSchema = -1; int iPgno = -1; int colSchema = (pTab->bPtr ? DBPTR_COLUMN_SCHEMA : DBDATA_COLUMN_SCHEMA); for(i=0; i<pIdx->nConstraint; i++){ struct sqlite3_index_constraint *p = &pIdx->aConstraint[i]; if( p->op==SQLITE_INDEX_CONSTRAINT_EQ ){ if( p->iColumn==colSchema ){ if( p->usable==0 ) return SQLITE_CONSTRAINT; iSchema = i; } if( p->iColumn==DBDATA_COLUMN_PGNO && p->usable ){ iPgno = i; } } } if( iSchema>=0 ){ pIdx->aConstraintUsage[iSchema].argvIndex = 1; pIdx->aConstraintUsage[iSchema].omit = 1; } if( iPgno>=0 ){ pIdx->aConstraintUsage[iPgno].argvIndex = 1 + (iSchema>=0); pIdx->aConstraintUsage[iPgno].omit = 1; pIdx->estimatedCost = 100; pIdx->estimatedRows = 50; if( pTab->bPtr==0 && pIdx->nOrderBy && pIdx->aOrderBy[0].desc==0 ){ int iCol = pIdx->aOrderBy[0].iColumn; if( pIdx->nOrderBy==1 ){ pIdx->orderByConsumed = (iCol==0 || iCol==1); }else if( pIdx->nOrderBy==2 && pIdx->aOrderBy[1].desc==0 && iCol==0 ){ pIdx->orderByConsumed = (pIdx->aOrderBy[1].iColumn==1); } } }else{ pIdx->estimatedCost = 100000000; pIdx->estimatedRows = 1000000000; } pIdx->idxNum = (iSchema>=0 ? 0x01 : 0x00) | (iPgno>=0 ? 0x02 : 0x00); return SQLITE_OK; } /* ** Open a new sqlite_dbdata or sqlite_dbptr cursor. */ static int dbdataOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){ DbdataCursor *pCsr; pCsr = (DbdataCursor*)sqlite3_malloc64(sizeof(DbdataCursor)); if( pCsr==0 ){ return SQLITE_NOMEM; }else{ memset(pCsr, 0, sizeof(DbdataCursor)); pCsr->base.pVtab = pVTab; } *ppCursor = (sqlite3_vtab_cursor *)pCsr; return SQLITE_OK; } /* ** Restore a cursor object to the state it was in when first allocated ** by dbdataOpen(). */ static void dbdataResetCursor(DbdataCursor *pCsr){ DbdataTable *pTab = (DbdataTable*)(pCsr->base.pVtab); if( pTab->pStmt==0 ){ pTab->pStmt = pCsr->pStmt; }else{ sqlite3_finalize(pCsr->pStmt); } pCsr->pStmt = 0; pCsr->iPgno = 1; pCsr->iCell = 0; pCsr->iField = 0; pCsr->bOnePage = 0; sqlite3_free(pCsr->aPage); sqlite3_free(pCsr->pRec); pCsr->pRec = 0; pCsr->aPage = 0; } /* ** Close an sqlite_dbdata or sqlite_dbptr cursor. */ static int dbdataClose(sqlite3_vtab_cursor *pCursor){ DbdataCursor *pCsr = (DbdataCursor*)pCursor; dbdataResetCursor(pCsr); sqlite3_free(pCsr); return SQLITE_OK; } /* ** Utility methods to decode 16 and 32-bit big-endian unsigned integers. */ static unsigned int get_uint16(unsigned char *a){ return (a[0]<<8)|a[1]; } static unsigned int get_uint32(unsigned char *a){ return ((unsigned int)a[0]<<24) | ((unsigned int)a[1]<<16) | ((unsigned int)a[2]<<8) | ((unsigned int)a[3]); } /* ** Load page pgno from the database via the sqlite_dbpage virtual table. ** If successful, set (*ppPage) to point to a buffer containing the page ** data, (*pnPage) to the size of that buffer in bytes and return ** SQLITE_OK. In this case it is the responsibility of the caller to ** eventually free the buffer using sqlite3_free(). ** ** Or, if an error occurs, set both (*ppPage) and (*pnPage) to 0 and ** return an SQLite error code. */ static int dbdataLoadPage( DbdataCursor *pCsr, /* Cursor object */ unsigned int pgno, /* Page number of page to load */ u8 **ppPage, /* OUT: pointer to page buffer */ int *pnPage /* OUT: Size of (*ppPage) in bytes */ ){ int rc2; int rc = SQLITE_OK; sqlite3_stmt *pStmt = pCsr->pStmt; *ppPage = 0; *pnPage = 0; sqlite3_bind_int64(pStmt, 2, pgno); if( SQLITE_ROW==sqlite3_step(pStmt) ){ int nCopy = sqlite3_column_bytes(pStmt, 0); if( nCopy>0 ){ u8 *pPage; pPage = (u8*)sqlite3_malloc64(nCopy + DBDATA_PADDING_BYTES); if( pPage==0 ){ rc = SQLITE_NOMEM; }else{ const u8 *pCopy = sqlite3_column_blob(pStmt, 0); memcpy(pPage, pCopy, nCopy); memset(&pPage[nCopy], 0, DBDATA_PADDING_BYTES); } *ppPage = pPage; *pnPage = nCopy; } } rc2 = sqlite3_reset(pStmt); if( rc==SQLITE_OK ) rc = rc2; return rc; } /* ** Read a varint. Put the value in *pVal and return the number of bytes. */ static int dbdataGetVarint(const u8 *z, sqlite3_int64 *pVal){ sqlite3_int64 v = 0; int i; for(i=0; i<8; i++){ v = (v<<7) + (z[i]&0x7f); if( (z[i]&0x80)==0 ){ *pVal = v; return i+1; } } v = (v<<8) + (z[i]&0xff); *pVal = v; return 9; } /* ** Return the number of bytes of space used by an SQLite value of type ** eType. */ static int dbdataValueBytes(int eType){ switch( eType ){ case 0: case 8: case 9: case 10: case 11: return 0; case 1: return 1; case 2: return 2; case 3: return 3; case 4: return 4; case 5: return 6; case 6: case 7: return 8; default: if( eType>0 ){ return ((eType-12) / 2); } return 0; } } /* ** Load a value of type eType from buffer pData and use it to set the ** result of context object pCtx. */ static void dbdataValue( sqlite3_context *pCtx, int eType, u8 *pData, int nData ){ if( eType>=0 && dbdataValueBytes(eType)<=nData ){ switch( eType ){ case 0: case 10: case 11: sqlite3_result_null(pCtx); break; case 8: sqlite3_result_int(pCtx, 0); break; case 9: sqlite3_result_int(pCtx, 1); break; case 1: case 2: case 3: case 4: case 5: case 6: case 7: { sqlite3_uint64 v = (signed char)pData[0]; pData++; switch( eType ){ case 7: case 6: v = (v<<16) + (pData[0]<<8) + pData[1]; pData += 2; case 5: v = (v<<16) + (pData[0]<<8) + pData[1]; pData += 2; case 4: v = (v<<8) + pData[0]; pData++; case 3: v = (v<<8) + pData[0]; pData++; case 2: v = (v<<8) + pData[0]; pData++; } if( eType==7 ){ double r; memcpy(&r, &v, sizeof(r)); sqlite3_result_double(pCtx, r); }else{ sqlite3_result_int64(pCtx, (sqlite3_int64)v); } break; } default: { int n = ((eType-12) / 2); if( eType % 2 ){ sqlite3_result_text(pCtx, (const char*)pData, n, SQLITE_TRANSIENT); }else{ sqlite3_result_blob(pCtx, pData, n, SQLITE_TRANSIENT); } } } } } /* ** Move an sqlite_dbdata or sqlite_dbptr cursor to the next entry. */ static int dbdataNext(sqlite3_vtab_cursor *pCursor){ DbdataCursor *pCsr = (DbdataCursor*)pCursor; DbdataTable *pTab = (DbdataTable*)pCursor->pVtab; pCsr->iRowid++; while( 1 ){ int rc; int iOff = (pCsr->iPgno==1 ? 100 : 0); int bNextPage = 0; if( pCsr->aPage==0 ){ while( 1 ){ if( pCsr->bOnePage==0 && pCsr->iPgno>pCsr->szDb ) return SQLITE_OK; rc = dbdataLoadPage(pCsr, pCsr->iPgno, &pCsr->aPage, &pCsr->nPage); if( rc!=SQLITE_OK ) return rc; if( pCsr->aPage ) break; pCsr->iPgno++; } pCsr->iCell = pTab->bPtr ? -2 : 0; pCsr->nCell = get_uint16(&pCsr->aPage[iOff+3]); } if( pTab->bPtr ){ if( pCsr->aPage[iOff]!=0x02 && pCsr->aPage[iOff]!=0x05 ){ pCsr->iCell = pCsr->nCell; } pCsr->iCell++; if( pCsr->iCell>=pCsr->nCell ){ sqlite3_free(pCsr->aPage); pCsr->aPage = 0; if( pCsr->bOnePage ) return SQLITE_OK; pCsr->iPgno++; }else{ return SQLITE_OK; } }else{ /* If there is no record loaded, load it now. */ if( pCsr->pRec==0 ){ int bHasRowid = 0; int nPointer = 0; sqlite3_int64 nPayload = 0; sqlite3_int64 nHdr = 0; int iHdr; int U, X; int nLocal; switch( pCsr->aPage[iOff] ){ case 0x02: nPointer = 4; break; case 0x0a: break; case 0x0d: bHasRowid = 1; break; default: /* This is not a b-tree page with records on it. Continue. */ pCsr->iCell = pCsr->nCell; break; } if( pCsr->iCell>=pCsr->nCell ){ bNextPage = 1; }else{ iOff += 8 + nPointer + pCsr->iCell*2; if( iOff>pCsr->nPage ){ bNextPage = 1; }else{ iOff = get_uint16(&pCsr->aPage[iOff]); } /* For an interior node cell, skip past the child-page number */ iOff += nPointer; /* Load the "byte of payload including overflow" field */ if( bNextPage || iOff>pCsr->nPage ){ bNextPage = 1; }else{ iOff += dbdataGetVarint(&pCsr->aPage[iOff], &nPayload); } /* If this is a leaf intkey cell, load the rowid */ if( bHasRowid && !bNextPage && iOff<pCsr->nPage ){ iOff += dbdataGetVarint(&pCsr->aPage[iOff], &pCsr->iIntkey); } /* Figure out how much data to read from the local page */ U = pCsr->nPage; if( bHasRowid ){ X = U-35; }else{ X = ((U-12)*64/255)-23; } if( nPayload<=X ){ nLocal = nPayload; }else{ int M, K; M = ((U-12)*32/255)-23; K = M+((nPayload-M)%(U-4)); if( K<=X ){ nLocal = K; }else{ nLocal = M; } } if( bNextPage || nLocal+iOff>pCsr->nPage ){ bNextPage = 1; }else{ /* Allocate space for payload. And a bit more to catch small buffer ** overruns caused by attempting to read a varint or similar from ** near the end of a corrupt record. */ pCsr->pRec = (u8*)sqlite3_malloc64(nPayload+DBDATA_PADDING_BYTES); if( pCsr->pRec==0 ) return SQLITE_NOMEM; memset(pCsr->pRec, 0, nPayload+DBDATA_PADDING_BYTES); pCsr->nRec = nPayload; /* Load the nLocal bytes of payload */ memcpy(pCsr->pRec, &pCsr->aPage[iOff], nLocal); iOff += nLocal; /* Load content from overflow pages */ if( nPayload>nLocal ){ sqlite3_int64 nRem = nPayload - nLocal; unsigned int pgnoOvfl = get_uint32(&pCsr->aPage[iOff]); while( nRem>0 ){ u8 *aOvfl = 0; int nOvfl = 0; int nCopy; rc = dbdataLoadPage(pCsr, pgnoOvfl, &aOvfl, &nOvfl); assert( rc!=SQLITE_OK || aOvfl==0 || nOvfl==pCsr->nPage ); if( rc!=SQLITE_OK ) return rc; if( aOvfl==0 ) break; nCopy = U-4; if( nCopy>nRem ) nCopy = nRem; memcpy(&pCsr->pRec[nPayload-nRem], &aOvfl[4], nCopy); nRem -= nCopy; pgnoOvfl = get_uint32(aOvfl); sqlite3_free(aOvfl); } } iHdr = dbdataGetVarint(pCsr->pRec, &nHdr); pCsr->nHdr = nHdr; pCsr->pHdrPtr = &pCsr->pRec[iHdr]; pCsr->pPtr = &pCsr->pRec[pCsr->nHdr]; pCsr->iField = (bHasRowid ? -1 : 0); } } }else{ pCsr->iField++; if( pCsr->iField>0 ){ sqlite3_int64 iType; if( pCsr->pHdrPtr>&pCsr->pRec[pCsr->nRec] ){ bNextPage = 1; }else{ pCsr->pHdrPtr += dbdataGetVarint(pCsr->pHdrPtr, &iType); pCsr->pPtr += dbdataValueBytes(iType); } } } if( bNextPage ){ sqlite3_free(pCsr->aPage); sqlite3_free(pCsr->pRec); pCsr->aPage = 0; pCsr->pRec = 0; if( pCsr->bOnePage ) return SQLITE_OK; pCsr->iPgno++; }else{ if( pCsr->iField<0 || pCsr->pHdrPtr<&pCsr->pRec[pCsr->nHdr] ){ return SQLITE_OK; } /* Advance to the next cell. The next iteration of the loop will load ** the record and so on. */ sqlite3_free(pCsr->pRec); pCsr->pRec = 0; pCsr->iCell++; } } } assert( !"can't get here" ); return SQLITE_OK; } /* ** Return true if the cursor is at EOF. */ static int dbdataEof(sqlite3_vtab_cursor *pCursor){ DbdataCursor *pCsr = (DbdataCursor*)pCursor; return pCsr->aPage==0; } /* ** Determine the size in pages of database zSchema (where zSchema is ** "main", "temp" or the name of an attached database) and set ** pCsr->szDb accordingly. If successful, return SQLITE_OK. Otherwise, ** an SQLite error code. */ static int dbdataDbsize(DbdataCursor *pCsr, const char *zSchema){ DbdataTable *pTab = (DbdataTable*)pCsr->base.pVtab; char *zSql = 0; int rc, rc2; sqlite3_stmt *pStmt = 0; zSql = sqlite3_mprintf("PRAGMA %Q.page_count", zSchema); if( zSql==0 ) return SQLITE_NOMEM; rc = sqlite3_prepare_v2(pTab->db, zSql, -1, &pStmt, 0); sqlite3_free(zSql); if( rc==SQLITE_OK && sqlite3_step(pStmt)==SQLITE_ROW ){ pCsr->szDb = sqlite3_column_int(pStmt, 0); } rc2 = sqlite3_finalize(pStmt); if( rc==SQLITE_OK ) rc = rc2; return rc; } /* ** xFilter method for sqlite_dbdata and sqlite_dbptr. */ static int dbdataFilter( sqlite3_vtab_cursor *pCursor, int idxNum, const char *idxStr, int argc, sqlite3_value **argv ){ DbdataCursor *pCsr = (DbdataCursor*)pCursor; DbdataTable *pTab = (DbdataTable*)pCursor->pVtab; int rc = SQLITE_OK; const char *zSchema = "main"; dbdataResetCursor(pCsr); assert( pCsr->iPgno==1 ); if( idxNum & 0x01 ){ zSchema = (const char*)sqlite3_value_text(argv[0]); } if( idxNum & 0x02 ){ pCsr->iPgno = sqlite3_value_int(argv[(idxNum & 0x01)]); pCsr->bOnePage = 1; }else{ pCsr->nPage = dbdataDbsize(pCsr, zSchema); rc = dbdataDbsize(pCsr, zSchema); } if( rc==SQLITE_OK ){ if( pTab->pStmt ){ pCsr->pStmt = pTab->pStmt; pTab->pStmt = 0; }else{ rc = sqlite3_prepare_v2(pTab->db, "SELECT data FROM sqlite_dbpage(?) WHERE pgno=?", -1, &pCsr->pStmt, 0 ); } } if( rc==SQLITE_OK ){ rc = sqlite3_bind_text(pCsr->pStmt, 1, zSchema, -1, SQLITE_TRANSIENT); }else{ pTab->base.zErrMsg = sqlite3_mprintf("%s", sqlite3_errmsg(pTab->db)); } if( rc==SQLITE_OK ){ rc = dbdataNext(pCursor); } return rc; } /* ** Return a column for the sqlite_dbdata or sqlite_dbptr table. */ static int dbdataColumn( sqlite3_vtab_cursor *pCursor, sqlite3_context *ctx, int i ){ DbdataCursor *pCsr = (DbdataCursor*)pCursor; DbdataTable *pTab = (DbdataTable*)pCursor->pVtab; if( pTab->bPtr ){ switch( i ){ case DBPTR_COLUMN_PGNO: sqlite3_result_int64(ctx, pCsr->iPgno); break; case DBPTR_COLUMN_CHILD: { int iOff = pCsr->iPgno==1 ? 100 : 0; if( pCsr->iCell<0 ){ iOff += 8; }else{ iOff += 12 + pCsr->iCell*2; if( iOff>pCsr->nPage ) return SQLITE_OK; iOff = get_uint16(&pCsr->aPage[iOff]); } if( iOff<=pCsr->nPage ){ sqlite3_result_int64(ctx, get_uint32(&pCsr->aPage[iOff])); } break; } } }else{ switch( i ){ case DBDATA_COLUMN_PGNO: sqlite3_result_int64(ctx, pCsr->iPgno); break; case DBDATA_COLUMN_CELL: sqlite3_result_int(ctx, pCsr->iCell); break; case DBDATA_COLUMN_FIELD: sqlite3_result_int(ctx, pCsr->iField); break; case DBDATA_COLUMN_VALUE: { if( pCsr->iField<0 ){ sqlite3_result_int64(ctx, pCsr->iIntkey); }else{ sqlite3_int64 iType; dbdataGetVarint(pCsr->pHdrPtr, &iType); dbdataValue( ctx, iType, pCsr->pPtr, &pCsr->pRec[pCsr->nRec] - pCsr->pPtr ); } break; } } } return SQLITE_OK; } /* ** Return the rowid for an sqlite_dbdata or sqlite_dptr table. */ static int dbdataRowid(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){ DbdataCursor *pCsr = (DbdataCursor*)pCursor; *pRowid = pCsr->iRowid; return SQLITE_OK; } /* ** Invoke this routine to register the "sqlite_dbdata" virtual table module */ static int sqlite3DbdataRegister(sqlite3 *db){ static sqlite3_module dbdata_module = { 0, /* iVersion */ 0, /* xCreate */ dbdataConnect, /* xConnect */ dbdataBestIndex, /* xBestIndex */ dbdataDisconnect, /* xDisconnect */ 0, /* xDestroy */ dbdataOpen, /* xOpen - open a cursor */ dbdataClose, /* xClose - close a cursor */ dbdataFilter, /* xFilter - configure scan constraints */ dbdataNext, /* xNext - advance a cursor */ dbdataEof, /* xEof - check for end of scan */ dbdataColumn, /* xColumn - read data */ dbdataRowid, /* xRowid - read data */ 0, /* xUpdate */ 0, /* xBegin */ 0, /* xSync */ 0, /* xCommit */ 0, /* xRollback */ 0, /* xFindMethod */ 0, /* xRename */ 0, /* xSavepoint */ 0, /* xRelease */ 0, /* xRollbackTo */ 0 /* xShadowName */ }; int rc = sqlite3_create_module(db, "sqlite_dbdata", &dbdata_module, 0); if( rc==SQLITE_OK ){ rc = sqlite3_create_module(db, "sqlite_dbptr", &dbdata_module, (void*)1); } return rc; } #ifdef _WIN32 __declspec(dllexport) #endif int sqlite3_dbdata_init( sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi ){ SQLITE_EXTENSION_INIT2(pApi); return sqlite3DbdataRegister(db); } |
Changes to ext/misc/dbdump.c.
︙ | ︙ | |||
191 192 193 194 195 196 197 | rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); sqlite3_free(zSql); if( rc ) return 0; while( sqlite3_step(pStmt)==SQLITE_ROW ){ if( nCol>=nAlloc-2 ){ char **azNew; nAlloc = nAlloc*2 + nCol + 10; | | | 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 | rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); sqlite3_free(zSql); if( rc ) return 0; while( sqlite3_step(pStmt)==SQLITE_ROW ){ if( nCol>=nAlloc-2 ){ char **azNew; nAlloc = nAlloc*2 + nCol + 10; azNew = sqlite3_realloc64(azCol, nAlloc*sizeof(azCol[0])); if( azNew==0 ) goto col_oom; azCol = azNew; azCol[0] = 0; } azCol[++nCol] = sqlite3_mprintf("%s", sqlite3_column_text(pStmt, 1)); if( azCol[nCol]==0 ) goto col_oom; if( sqlite3_column_int(pStmt, 5) ){ |
︙ | ︙ | |||
391 392 393 394 395 396 397 | zTable = azArg[0]; zType = azArg[1]; zSql = azArg[2]; if( strcmp(zTable, "sqlite_sequence")==0 ){ p->xCallback("DELETE FROM sqlite_sequence;\n", p->pArg); }else if( sqlite3_strglob("sqlite_stat?", zTable)==0 ){ | | | | 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 | zTable = azArg[0]; zType = azArg[1]; zSql = azArg[2]; if( strcmp(zTable, "sqlite_sequence")==0 ){ p->xCallback("DELETE FROM sqlite_sequence;\n", p->pArg); }else if( sqlite3_strglob("sqlite_stat?", zTable)==0 ){ p->xCallback("ANALYZE sqlite_schema;\n", p->pArg); }else if( strncmp(zTable, "sqlite_", 7)==0 ){ return 0; }else if( strncmp(zSql, "CREATE VIRTUAL TABLE", 20)==0 ){ if( !p->writableSchema ){ p->xCallback("PRAGMA writable_schema=ON;\n", p->pArg); p->writableSchema = 1; } output_formatted(p, "INSERT INTO sqlite_schema(type,name,tbl_name,rootpage,sql)" "VALUES('table','%q','%q',0,'%q');", zTable, zTable, zSql); return 0; }else{ if( sqlite3_strglob("CREATE TABLE ['\"]*", zSql)==0 ){ p->xCallback("CREATE TABLE IF NOT EXISTS ", p->pArg); p->xCallback(zSql+13, p->pArg); |
︙ | ︙ | |||
642 643 644 645 646 647 648 | if( x.rc ) return x.rc; x.db = db; x.xCallback = xCallback; x.pArg = pArg; xCallback("PRAGMA foreign_keys=OFF;\nBEGIN TRANSACTION;\n", pArg); if( zTable==0 ){ run_schema_dump_query(&x, | | | | | | | 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 | if( x.rc ) return x.rc; x.db = db; x.xCallback = xCallback; x.pArg = pArg; xCallback("PRAGMA foreign_keys=OFF;\nBEGIN TRANSACTION;\n", pArg); if( zTable==0 ){ run_schema_dump_query(&x, "SELECT name, type, sql FROM \"%w\".sqlite_schema " "WHERE sql NOT NULL AND type=='table' AND name!='sqlite_sequence'", zSchema ); run_schema_dump_query(&x, "SELECT name, type, sql FROM \"%w\".sqlite_schema " "WHERE name=='sqlite_sequence'", zSchema ); output_sql_from_query(&x, "SELECT sql FROM sqlite_schema " "WHERE sql NOT NULL AND type IN ('index','trigger','view')", 0 ); }else{ run_schema_dump_query(&x, "SELECT name, type, sql FROM \"%w\".sqlite_schema " "WHERE tbl_name=%Q COLLATE nocase AND type=='table'" " AND sql NOT NULL", zSchema, zTable ); output_sql_from_query(&x, "SELECT sql FROM \"%w\".sqlite_schema " "WHERE sql NOT NULL" " AND type IN ('index','trigger','view')" " AND tbl_name=%Q COLLATE nocase", zSchema, zTable ); } if( x.writableSchema ){ |
︙ | ︙ |
Added ext/misc/decimal.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 | /* ** 2020-06-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. ** ****************************************************************************** ** ** Routines to implement arbitrary-precision decimal math. ** ** The focus here is on simplicity and correctness, not performance. */ #include "sqlite3ext.h" SQLITE_EXTENSION_INIT1 #include <assert.h> #include <string.h> #include <ctype.h> #include <stdlib.h> /* Mark a function parameter as unused, to suppress nuisance compiler ** warnings. */ #ifndef UNUSED_PARAMETER # define UNUSED_PARAMETER(X) (void)(X) #endif /* A decimal object */ typedef struct Decimal Decimal; struct Decimal { char sign; /* 0 for positive, 1 for negative */ char oom; /* True if an OOM is encountered */ char isNull; /* True if holds a NULL rather than a number */ char isInit; /* True upon initialization */ int nDigit; /* Total number of digits */ int nFrac; /* Number of digits to the right of the decimal point */ signed char *a; /* Array of digits. Most significant first. */ }; /* ** Release memory held by a Decimal, but do not free the object itself. */ static void decimal_clear(Decimal *p){ sqlite3_free(p->a); } /* ** Destroy a Decimal object */ static void decimal_free(Decimal *p){ if( p ){ decimal_clear(p); sqlite3_free(p); } } /* ** Allocate a new Decimal object. Initialize it to the number given ** by the input string. */ static Decimal *decimal_new( sqlite3_context *pCtx, sqlite3_value *pIn, int nAlt, const unsigned char *zAlt ){ Decimal *p; int n, i; const unsigned char *zIn; int iExp = 0; p = sqlite3_malloc( sizeof(*p) ); if( p==0 ) goto new_no_mem; p->sign = 0; p->oom = 0; p->isInit = 1; p->isNull = 0; p->nDigit = 0; p->nFrac = 0; if( zAlt ){ n = nAlt, zIn = zAlt; }else{ if( sqlite3_value_type(pIn)==SQLITE_NULL ){ p->a = 0; p->isNull = 1; return p; } n = sqlite3_value_bytes(pIn); zIn = sqlite3_value_text(pIn); } p->a = sqlite3_malloc64( n+1 ); if( p->a==0 ) goto new_no_mem; for(i=0; isspace(zIn[i]); i++){} if( zIn[i]=='-' ){ p->sign = 1; i++; }else if( zIn[i]=='+' ){ i++; } while( i<n && zIn[i]=='0' ) i++; while( i<n ){ char c = zIn[i]; if( c>='0' && c<='9' ){ p->a[p->nDigit++] = c - '0'; }else if( c=='.' ){ p->nFrac = p->nDigit + 1; }else if( c=='e' || c=='E' ){ int j = i+1; int neg = 0; if( j>=n ) break; if( zIn[j]=='-' ){ neg = 1; j++; }else if( zIn[j]=='+' ){ j++; } while( j<n && iExp<1000000 ){ if( zIn[j]>='0' && zIn[j]<='9' ){ iExp = iExp*10 + zIn[j] - '0'; } j++; } if( neg ) iExp = -iExp; break; } i++; } if( p->nFrac ){ p->nFrac = p->nDigit - (p->nFrac - 1); } if( iExp>0 ){ if( p->nFrac>0 ){ if( iExp<=p->nFrac ){ p->nFrac -= iExp; iExp = 0; }else{ iExp -= p->nFrac; p->nFrac = 0; } } if( iExp>0 ){ p->a = sqlite3_realloc64(p->a, p->nDigit + iExp + 1 ); if( p->a==0 ) goto new_no_mem; memset(p->a+p->nDigit, 0, iExp); p->nDigit += iExp; } }else if( iExp<0 ){ int nExtra; iExp = -iExp; nExtra = p->nDigit - p->nFrac - 1; if( nExtra ){ if( nExtra>=iExp ){ p->nFrac += iExp; iExp = 0; }else{ iExp -= nExtra; p->nFrac = p->nDigit - 1; } } if( iExp>0 ){ p->a = sqlite3_realloc64(p->a, p->nDigit + iExp + 1 ); if( p->a==0 ) goto new_no_mem; memmove(p->a+iExp, p->a, p->nDigit); memset(p->a, 0, iExp); p->nDigit += iExp; p->nFrac += iExp; } } return p; new_no_mem: if( pCtx ) sqlite3_result_error_nomem(pCtx); sqlite3_free(p); return 0; } /* ** Make the given Decimal the result. */ static void decimal_result(sqlite3_context *pCtx, Decimal *p){ char *z; int i, j; int n; if( p==0 || p->oom ){ sqlite3_result_error_nomem(pCtx); return; } if( p->isNull ){ sqlite3_result_null(pCtx); return; } z = sqlite3_malloc( p->nDigit+4 ); if( z==0 ){ sqlite3_result_error_nomem(pCtx); return; } i = 0; if( p->nDigit==0 || (p->nDigit==1 && p->a[0]==0) ){ p->sign = 0; } if( p->sign ){ z[0] = '-'; i = 1; } n = p->nDigit - p->nFrac; if( n<=0 ){ z[i++] = '0'; } j = 0; while( n>1 && p->a[j]==0 ){ j++; n--; } while( n>0 ){ z[i++] = p->a[j] + '0'; j++; n--; } if( p->nFrac ){ z[i++] = '.'; do{ z[i++] = p->a[j] + '0'; j++; }while( j<p->nDigit ); } z[i] = 0; sqlite3_result_text(pCtx, z, i, sqlite3_free); } /* ** SQL Function: decimal(X) ** ** Convert input X into decimal and then back into text */ static void decimalFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ Decimal *p = decimal_new(context, argv[0], 0, 0); UNUSED_PARAMETER(argc); decimal_result(context, p); decimal_free(p); } /* ** Compare to Decimal objects. Return negative, 0, or positive if the ** first object is less than, equal to, or greater than the second. ** ** Preconditions for this routine: ** ** pA!=0 ** pA->isNull==0 ** pB!=0 ** pB->isNull==0 */ static int decimal_cmp(const Decimal *pA, const Decimal *pB){ int nASig, nBSig, rc, n; if( pA->sign!=pB->sign ){ return pA->sign ? -1 : +1; } if( pA->sign ){ const Decimal *pTemp = pA; pA = pB; pB = pTemp; } nASig = pA->nDigit - pA->nFrac; nBSig = pB->nDigit - pB->nFrac; if( nASig!=nBSig ){ return nASig - nBSig; } n = pA->nDigit; if( n>pB->nDigit ) n = pB->nDigit; rc = memcmp(pA->a, pB->a, n); if( rc==0 ){ rc = pA->nDigit - pB->nDigit; } return rc; } /* ** SQL Function: decimal_cmp(X, Y) ** ** Return negative, zero, or positive if X is less then, equal to, or ** greater than Y. */ static void decimalCmpFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ Decimal *pA = 0, *pB = 0; int rc; UNUSED_PARAMETER(argc); pA = decimal_new(context, argv[0], 0, 0); if( pA==0 || pA->isNull ) goto cmp_done; pB = decimal_new(context, argv[1], 0, 0); if( pB==0 || pB->isNull ) goto cmp_done; rc = decimal_cmp(pA, pB); if( rc<0 ) rc = -1; else if( rc>0 ) rc = +1; sqlite3_result_int(context, rc); cmp_done: decimal_free(pA); decimal_free(pB); } /* ** Expand the Decimal so that it has a least nDigit digits and nFrac ** digits to the right of the decimal point. */ static void decimal_expand(Decimal *p, int nDigit, int nFrac){ int nAddSig; int nAddFrac; if( p==0 ) return; nAddFrac = nFrac - p->nFrac; nAddSig = (nDigit - p->nDigit) - nAddFrac; if( nAddFrac==0 && nAddSig==0 ) return; p->a = sqlite3_realloc64(p->a, nDigit+1); if( p->a==0 ){ p->oom = 1; return; } if( nAddSig ){ memmove(p->a+nAddSig, p->a, p->nDigit); memset(p->a, 0, nAddSig); p->nDigit += nAddSig; } if( nAddFrac ){ memset(p->a+p->nDigit, 0, nAddFrac); p->nDigit += nAddFrac; p->nFrac += nAddFrac; } } /* ** Add the value pB into pA. ** ** Both pA and pB might become denormalized by this routine. */ static void decimal_add(Decimal *pA, Decimal *pB){ int nSig, nFrac, nDigit; int i, rc; if( pA==0 ){ return; } if( pA->oom || pB==0 || pB->oom ){ pA->oom = 1; return; } if( pA->isNull || pB->isNull ){ pA->isNull = 1; return; } nSig = pA->nDigit - pA->nFrac; if( nSig && pA->a[0]==0 ) nSig--; if( nSig<pB->nDigit-pB->nFrac ){ nSig = pB->nDigit - pB->nFrac; } nFrac = pA->nFrac; if( nFrac<pB->nFrac ) nFrac = pB->nFrac; nDigit = nSig + nFrac + 1; decimal_expand(pA, nDigit, nFrac); decimal_expand(pB, nDigit, nFrac); if( pA->oom || pB->oom ){ pA->oom = 1; }else{ if( pA->sign==pB->sign ){ int carry = 0; for(i=nDigit-1; i>=0; i--){ int x = pA->a[i] + pB->a[i] + carry; if( x>=10 ){ carry = 1; pA->a[i] = x - 10; }else{ carry = 0; pA->a[i] = x; } } }else{ signed char *aA, *aB; int borrow = 0; rc = memcmp(pA->a, pB->a, nDigit); if( rc<0 ){ aA = pB->a; aB = pA->a; pA->sign = !pA->sign; }else{ aA = pA->a; aB = pB->a; } for(i=nDigit-1; i>=0; i--){ int x = aA[i] - aB[i] - borrow; if( x<0 ){ pA->a[i] = x+10; borrow = 1; }else{ pA->a[i] = x; borrow = 0; } } } } } /* ** Compare text in decimal order. */ static int decimalCollFunc( void *notUsed, int nKey1, const void *pKey1, int nKey2, const void *pKey2 ){ const unsigned char *zA = (const unsigned char*)pKey1; const unsigned char *zB = (const unsigned char*)pKey2; Decimal *pA = decimal_new(0, 0, nKey1, zA); Decimal *pB = decimal_new(0, 0, nKey2, zB); int rc; UNUSED_PARAMETER(notUsed); if( pA==0 || pB==0 ){ rc = 0; }else{ rc = decimal_cmp(pA, pB); } decimal_free(pA); decimal_free(pB); return rc; } /* ** SQL Function: decimal_add(X, Y) ** decimal_sub(X, Y) ** ** Return the sum or difference of X and Y. */ static void decimalAddFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ Decimal *pA = decimal_new(context, argv[0], 0, 0); Decimal *pB = decimal_new(context, argv[1], 0, 0); UNUSED_PARAMETER(argc); decimal_add(pA, pB); decimal_result(context, pA); decimal_free(pA); decimal_free(pB); } static void decimalSubFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ Decimal *pA = decimal_new(context, argv[0], 0, 0); Decimal *pB = decimal_new(context, argv[1], 0, 0); UNUSED_PARAMETER(argc); if( pB ){ pB->sign = !pB->sign; decimal_add(pA, pB); decimal_result(context, pA); } decimal_free(pA); decimal_free(pB); } /* Aggregate funcion: decimal_sum(X) ** ** Works like sum() except that it uses decimal arithmetic for unlimited ** precision. */ static void decimalSumStep( sqlite3_context *context, int argc, sqlite3_value **argv ){ Decimal *p; Decimal *pArg; UNUSED_PARAMETER(argc); p = sqlite3_aggregate_context(context, sizeof(*p)); if( p==0 ) return; if( !p->isInit ){ p->isInit = 1; p->a = sqlite3_malloc(2); if( p->a==0 ){ p->oom = 1; }else{ p->a[0] = 0; } p->nDigit = 1; p->nFrac = 0; } if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return; pArg = decimal_new(context, argv[0], 0, 0); decimal_add(p, pArg); decimal_free(pArg); } static void decimalSumInverse( sqlite3_context *context, int argc, sqlite3_value **argv ){ Decimal *p; Decimal *pArg; UNUSED_PARAMETER(argc); p = sqlite3_aggregate_context(context, sizeof(*p)); if( p==0 ) return; if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return; pArg = decimal_new(context, argv[0], 0, 0); if( pArg ) pArg->sign = !pArg->sign; decimal_add(p, pArg); decimal_free(pArg); } static void decimalSumValue(sqlite3_context *context){ Decimal *p = sqlite3_aggregate_context(context, 0); if( p==0 ) return; decimal_result(context, p); } static void decimalSumFinalize(sqlite3_context *context){ Decimal *p = sqlite3_aggregate_context(context, 0); if( p==0 ) return; decimal_result(context, p); decimal_clear(p); } /* ** SQL Function: decimal_mul(X, Y) ** ** Return the product of X and Y. ** ** All significant digits after the decimal point are retained. ** Trailing zeros after the decimal point are omitted as long as ** the number of digits after the decimal point is no less than ** either the number of digits in either input. */ static void decimalMulFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ Decimal *pA = decimal_new(context, argv[0], 0, 0); Decimal *pB = decimal_new(context, argv[1], 0, 0); signed char *acc = 0; int i, j, k; int minFrac; UNUSED_PARAMETER(argc); if( pA==0 || pA->oom || pA->isNull || pB==0 || pB->oom || pB->isNull ){ goto mul_end; } acc = sqlite3_malloc64( pA->nDigit + pB->nDigit + 2 ); if( acc==0 ){ sqlite3_result_error_nomem(context); goto mul_end; } memset(acc, 0, pA->nDigit + pB->nDigit + 2); minFrac = pA->nFrac; if( pB->nFrac<minFrac ) minFrac = pB->nFrac; for(i=pA->nDigit-1; i>=0; i--){ signed char f = pA->a[i]; int carry = 0, x; for(j=pB->nDigit-1, k=i+j+3; j>=0; j--, k--){ x = acc[k] + f*pB->a[j] + carry; acc[k] = x%10; carry = x/10; } x = acc[k] + carry; acc[k] = x%10; acc[k-1] += x/10; } sqlite3_free(pA->a); pA->a = acc; acc = 0; pA->nDigit += pB->nDigit + 2; pA->nFrac += pB->nFrac; pA->sign ^= pB->sign; while( pA->nFrac>minFrac && pA->a[pA->nDigit-1]==0 ){ pA->nFrac--; pA->nDigit--; } decimal_result(context, pA); mul_end: sqlite3_free(acc); decimal_free(pA); decimal_free(pB); } #ifdef _WIN32 __declspec(dllexport) #endif int sqlite3_decimal_init( sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi ){ int rc = SQLITE_OK; static const struct { const char *zFuncName; int nArg; void (*xFunc)(sqlite3_context*,int,sqlite3_value**); } aFunc[] = { { "decimal", 1, decimalFunc }, { "decimal_cmp", 2, decimalCmpFunc }, { "decimal_add", 2, decimalAddFunc }, { "decimal_sub", 2, decimalSubFunc }, { "decimal_mul", 2, decimalMulFunc }, }; unsigned int i; (void)pzErrMsg; /* Unused parameter */ SQLITE_EXTENSION_INIT2(pApi); for(i=0; i<sizeof(aFunc)/sizeof(aFunc[0]) && rc==SQLITE_OK; i++){ rc = sqlite3_create_function(db, aFunc[i].zFuncName, aFunc[i].nArg, SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_DETERMINISTIC, 0, aFunc[i].xFunc, 0, 0); } if( rc==SQLITE_OK ){ rc = sqlite3_create_window_function(db, "decimal_sum", 1, SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_DETERMINISTIC, 0, decimalSumStep, decimalSumFinalize, decimalSumValue, decimalSumInverse, 0); } if( rc==SQLITE_OK ){ rc = sqlite3_create_collation(db, "decimal", SQLITE_UTF8, 0, decimalCollFunc); } return rc; } |
Changes to ext/misc/eval.c.
︙ | ︙ | |||
40 41 42 43 44 45 46 | size_t sz = strlen(z); if( (sqlite3_int64)sz+p->nUsed+p->szSep+1 > p->nAlloc ){ char *zNew; p->nAlloc = p->nAlloc*2 + sz + p->szSep + 1; /* Using sqlite3_realloc64() would be better, but it is a recent ** addition and will cause a segfault if loaded by an older version ** of SQLite. */ | | | 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | size_t sz = strlen(z); if( (sqlite3_int64)sz+p->nUsed+p->szSep+1 > p->nAlloc ){ char *zNew; p->nAlloc = p->nAlloc*2 + sz + p->szSep + 1; /* Using sqlite3_realloc64() would be better, but it is a recent ** addition and will cause a segfault if loaded by an older version ** of SQLite. */ zNew = p->nAlloc<=0x7fffffff ? sqlite3_realloc64(p->z, p->nAlloc) : 0; if( zNew==0 ){ sqlite3_free(p->z); memset(p, 0, sizeof(*p)); return 1; } p->z = zNew; } |
︙ | ︙ | |||
109 110 111 112 113 114 115 | sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi ){ int rc = SQLITE_OK; SQLITE_EXTENSION_INIT2(pApi); (void)pzErrMsg; /* Unused parameter */ | | > | > | 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 | 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, "eval", 1, SQLITE_UTF8|SQLITE_DIRECTONLY, 0, sqlEvalFunc, 0, 0); if( rc==SQLITE_OK ){ rc = sqlite3_create_function(db, "eval", 2, SQLITE_UTF8|SQLITE_DIRECTONLY, 0, sqlEvalFunc, 0, 0); } return rc; } |
Changes to ext/misc/explain.c.
︙ | ︙ | |||
12 13 14 15 16 17 18 | ** ** This file demonstrates an eponymous virtual table that returns the ** EXPLAIN output from an SQL statement. ** ** Usage example: ** ** .load ./explain | | | 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | ** ** This file demonstrates an eponymous virtual table that returns the ** EXPLAIN output from an SQL statement. ** ** Usage example: ** ** .load ./explain ** SELECT p2 FROM explain('SELECT * FROM sqlite_schema') ** WHERE opcode='OpenRead'; ** ** This module was originally written to help simplify SQLite testing, ** by providing an easier means of verifying certain patterns in the ** generated bytecode. */ #if !defined(SQLITEINT_H) |
︙ | ︙ |
Changes to ext/misc/fileio.c.
︙ | ︙ | |||
68 69 70 71 72 73 74 75 76 77 78 79 80 81 | ** symlink, a text value containing the text of the link. For a ** directory, NULL. ** ** If a non-NULL value is specified for the optional $dir parameter and ** $path is a relative path, then $path is interpreted relative to $dir. ** And the paths returned in the "name" column of the table are also ** relative to directory $dir. */ #include "sqlite3ext.h" SQLITE_EXTENSION_INIT1 #include <stdio.h> #include <string.h> #include <assert.h> | > > > > > | 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 | ** symlink, a text value containing the text of the link. For a ** directory, NULL. ** ** If a non-NULL value is specified for the optional $dir parameter and ** $path is a relative path, then $path is interpreted relative to $dir. ** And the paths returned in the "name" column of the table are also ** relative to directory $dir. ** ** Notes on building this extension for Windows: ** Unless linked statically with the SQLite library, a preprocessor ** symbol, FILEIO_WIN32_DLL, must be #define'd to create a stand-alone ** DLL form of this extension for WIN32. See its use below for details. */ #include "sqlite3ext.h" SQLITE_EXTENSION_INIT1 #include <stdio.h> #include <string.h> #include <assert.h> |
︙ | ︙ | |||
117 118 119 120 121 122 123 | #define FSDIR_COLUMN_DATA 3 /* File content */ #define FSDIR_COLUMN_PATH 4 /* Path to top of search */ #define FSDIR_COLUMN_DIR 5 /* Path is relative to this directory */ /* ** Set the result stored by context ctx to a blob containing the | | > > > > > > > | > > | > > > > > > > > > > | | > > > > > | > | 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 | #define FSDIR_COLUMN_DATA 3 /* File content */ #define FSDIR_COLUMN_PATH 4 /* Path to top of search */ #define FSDIR_COLUMN_DIR 5 /* Path is relative to this directory */ /* ** Set the result stored by context ctx to a blob containing the ** contents of file zName. Or, leave the result unchanged (NULL) ** if the file does not exist or is unreadable. ** ** If the file exceeds the SQLite blob size limit, through an ** SQLITE_TOOBIG error. ** ** Throw an SQLITE_IOERR if there are difficulties pulling the file ** off of disk. */ static void readFileContents(sqlite3_context *ctx, const char *zName){ FILE *in; sqlite3_int64 nIn; void *pBuf; sqlite3 *db; int mxBlob; in = fopen(zName, "rb"); if( in==0 ){ /* File does not exist or is unreadable. Leave the result set to NULL. */ return; } fseek(in, 0, SEEK_END); nIn = ftell(in); rewind(in); db = sqlite3_context_db_handle(ctx); mxBlob = sqlite3_limit(db, SQLITE_LIMIT_LENGTH, -1); if( nIn>mxBlob ){ sqlite3_result_error_code(ctx, SQLITE_TOOBIG); fclose(in); return; } pBuf = sqlite3_malloc64( nIn ? nIn : 1 ); if( pBuf==0 ){ sqlite3_result_error_nomem(ctx); fclose(in); return; } if( nIn==(sqlite3_int64)fread(pBuf, 1, (size_t)nIn, in) ){ sqlite3_result_blob64(ctx, pBuf, nIn, sqlite3_free); }else{ sqlite3_result_error_code(ctx, SQLITE_IOERR); sqlite3_free(pBuf); } fclose(in); } /* ** Implementation of the "readfile(X)" SQL function. The entire content |
︙ | ︙ | |||
196 197 198 199 200 201 202 203 204 205 206 207 208 209 | fileIntervals.LowPart = pFileTime->dwLowDateTime; fileIntervals.HighPart = pFileTime->dwHighDateTime; return (fileIntervals.QuadPart - epochIntervals.QuadPart) / 10000000; } /* ** This function attempts to normalize the time values found in the stat() ** buffer to UTC. This is necessary on Win32, where the runtime library ** appears to return these values as local times. */ static void statTimesToUtc( const char *zPath, | > > > > > > > > > > > > > > > > | 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 | fileIntervals.LowPart = pFileTime->dwLowDateTime; fileIntervals.HighPart = pFileTime->dwHighDateTime; return (fileIntervals.QuadPart - epochIntervals.QuadPart) / 10000000; } #if defined(FILEIO_WIN32_DLL) && (defined(_WIN32) || defined(WIN32)) # /* To allow a standalone DLL, use this next replacement function: */ # undef sqlite3_win32_utf8_to_unicode # define sqlite3_win32_utf8_to_unicode utf8_to_utf16 # LPWSTR utf8_to_utf16(const char *z){ int nAllot = MultiByteToWideChar(CP_UTF8, 0, z, -1, NULL, 0); LPWSTR rv = sqlite3_malloc(nAllot * sizeof(WCHAR)); if( rv!=0 && 0 < MultiByteToWideChar(CP_UTF8, 0, z, -1, rv, nAllot) ) return rv; sqlite3_free(rv); return 0; } #endif /* ** This function attempts to normalize the time values found in the stat() ** buffer to UTC. This is necessary on Win32, where the runtime library ** appears to return these values as local times. */ static void statTimesToUtc( const char *zPath, |
︙ | ︙ | |||
264 265 266 267 268 269 270 | #endif } /* ** Argument zFile is the name of a file that will be created and/or written ** by SQL function writefile(). This function ensures that the directory ** zFile will be written to exists, creating it if required. The permissions | | > | < | | 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 | #endif } /* ** Argument zFile is the name of a file that will be created and/or written ** by SQL function writefile(). This function ensures that the directory ** zFile will be written to exists, creating it if required. The permissions ** for any path components created by this function are set in accordance ** with the current umask. ** ** If an OOM condition is encountered, SQLITE_NOMEM is returned. Otherwise, ** SQLITE_OK is returned if the directory is successfully created, or ** SQLITE_ERROR otherwise. */ static int makeDirectory( const char *zFile ){ char *zCopy = sqlite3_mprintf("%s", zFile); int rc = SQLITE_OK; if( zCopy==0 ){ rc = SQLITE_NOMEM; }else{ int nCopy = (int)strlen(zCopy); int i = 1; while( rc==SQLITE_OK ){ struct stat sStat; int rc2; for(; zCopy[i]!='/' && i<nCopy; i++); if( i==nCopy ) break; zCopy[i] = '\0'; rc2 = fileStat(zCopy, &sStat); if( rc2!=0 ){ if( mkdir(zCopy, 0777) ) rc = SQLITE_ERROR; }else{ if( !S_ISDIR(sStat.st_mode) ) rc = SQLITE_ERROR; } zCopy[i] = '/'; i++; } |
︙ | ︙ | |||
365 366 367 368 369 370 371 372 373 374 375 376 377 378 | if( rc ) return 2; sqlite3_result_int64(pCtx, nWrite); } } if( mtime>=0 ){ #if defined(_WIN32) /* Windows */ FILETIME lastAccess; FILETIME lastWrite; SYSTEMTIME currentTime; LONGLONG intervals; HANDLE hFile; LPWSTR zUnicodeName; | > | 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 | if( rc ) return 2; sqlite3_result_int64(pCtx, nWrite); } } if( mtime>=0 ){ #if defined(_WIN32) #if !SQLITE_OS_WINRT /* Windows */ FILETIME lastAccess; FILETIME lastWrite; SYSTEMTIME currentTime; LONGLONG intervals; HANDLE hFile; LPWSTR zUnicodeName; |
︙ | ︙ | |||
395 396 397 398 399 400 401 402 403 404 405 406 407 408 | if( hFile!=INVALID_HANDLE_VALUE ){ BOOL bResult = SetFileTime(hFile, NULL, &lastAccess, &lastWrite); CloseHandle(hFile); return !bResult; }else{ return 1; } #elif defined(AT_FDCWD) && 0 /* utimensat() is not universally available */ /* Recent unix */ struct timespec times[2]; times[0].tv_nsec = times[1].tv_nsec = 0; times[0].tv_sec = time(0); times[1].tv_sec = mtime; if( utimensat(AT_FDCWD, zFile, times, AT_SYMLINK_NOFOLLOW) ){ | > | 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 | if( hFile!=INVALID_HANDLE_VALUE ){ BOOL bResult = SetFileTime(hFile, NULL, &lastAccess, &lastWrite); CloseHandle(hFile); return !bResult; }else{ return 1; } #endif #elif defined(AT_FDCWD) && 0 /* utimensat() is not universally available */ /* Recent unix */ struct timespec times[2]; times[0].tv_nsec = times[1].tv_nsec = 0; times[0].tv_sec = time(0); times[1].tv_sec = mtime; if( utimensat(AT_FDCWD, zFile, times, AT_SYMLINK_NOFOLLOW) ){ |
︙ | ︙ | |||
451 452 453 454 455 456 457 | } if( argc==4 ){ mtime = sqlite3_value_int64(argv[3]); } res = writeFile(context, zFile, argv[1], mode, mtime); if( res==1 && errno==ENOENT ){ | | | 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 | } if( argc==4 ){ mtime = sqlite3_value_int64(argv[3]); } res = writeFile(context, zFile, argv[1], mode, mtime); if( res==1 && errno==ENOENT ){ if( makeDirectory(zFile)==SQLITE_OK ){ res = writeFile(context, zFile, argv[1], mode, mtime); } } if( argc>2 && res!=0 ){ if( S_ISLNK(mode) ){ ctxErrorMsg(context, "failed to create symlink: %s", zFile); |
︙ | ︙ | |||
556 557 558 559 560 561 562 563 564 565 566 567 568 569 | (void)argv; (void)pzErr; rc = sqlite3_declare_vtab(db, "CREATE TABLE x" FSDIR_SCHEMA); if( rc==SQLITE_OK ){ pNew = (fsdir_tab*)sqlite3_malloc( sizeof(*pNew) ); if( pNew==0 ) return SQLITE_NOMEM; memset(pNew, 0, sizeof(*pNew)); } *ppVtab = (sqlite3_vtab*)pNew; return rc; } /* ** This method is the destructor for fsdir vtab objects. | > | 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 | (void)argv; (void)pzErr; rc = sqlite3_declare_vtab(db, "CREATE TABLE x" FSDIR_SCHEMA); if( rc==SQLITE_OK ){ pNew = (fsdir_tab*)sqlite3_malloc( sizeof(*pNew) ); if( pNew==0 ) return SQLITE_NOMEM; memset(pNew, 0, sizeof(*pNew)); sqlite3_vtab_config(db, SQLITE_VTAB_DIRECTONLY); } *ppVtab = (sqlite3_vtab*)pNew; return rc; } /* ** This method is the destructor for fsdir vtab objects. |
︙ | ︙ | |||
642 643 644 645 646 647 648 | pCur->iRowid++; if( S_ISDIR(m) ){ /* Descend into this directory */ int iNew = pCur->iLvl + 1; FsdirLevel *pLvl; if( iNew>=pCur->nLvl ){ int nNew = iNew+1; | | | | 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 | pCur->iRowid++; if( S_ISDIR(m) ){ /* Descend into this directory */ int iNew = pCur->iLvl + 1; FsdirLevel *pLvl; if( iNew>=pCur->nLvl ){ int nNew = iNew+1; sqlite3_int64 nByte = nNew*sizeof(FsdirLevel); FsdirLevel *aNew = (FsdirLevel*)sqlite3_realloc64(pCur->aLvl, nByte); if( aNew==0 ) return SQLITE_NOMEM; memset(&aNew[pCur->nLvl], 0, sizeof(FsdirLevel)*(nNew-pCur->nLvl)); pCur->aLvl = aNew; pCur->nLvl = nNew; } pCur->iLvl = iNew; pLvl = &pCur->aLvl[iNew]; |
︙ | ︙ | |||
723 724 725 726 727 728 729 | mode_t m = pCur->sStat.st_mode; if( S_ISDIR(m) ){ sqlite3_result_null(ctx); #if !defined(_WIN32) && !defined(WIN32) }else if( S_ISLNK(m) ){ char aStatic[64]; char *aBuf = aStatic; | | | | 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 | mode_t m = pCur->sStat.st_mode; if( S_ISDIR(m) ){ sqlite3_result_null(ctx); #if !defined(_WIN32) && !defined(WIN32) }else if( S_ISLNK(m) ){ char aStatic[64]; char *aBuf = aStatic; sqlite3_int64 nBuf = 64; int n; while( 1 ){ n = readlink(pCur->zPath, aBuf, nBuf); if( n<nBuf ) break; if( aBuf!=aStatic ) sqlite3_free(aBuf); nBuf = nBuf*2; aBuf = sqlite3_malloc64(nBuf); if( aBuf==0 ){ sqlite3_result_error_nomem(ctx); return SQLITE_NOMEM; } } sqlite3_result_text(ctx, aBuf, n, SQLITE_TRANSIENT); |
︙ | ︙ | |||
949 950 951 952 953 954 955 | sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi ){ int rc = SQLITE_OK; SQLITE_EXTENSION_INIT2(pApi); (void)pzErrMsg; /* Unused parameter */ | | > | > > > > > > > > > | 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 | sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi ){ int rc = SQLITE_OK; SQLITE_EXTENSION_INIT2(pApi); (void)pzErrMsg; /* Unused parameter */ rc = sqlite3_create_function(db, "readfile", 1, SQLITE_UTF8|SQLITE_DIRECTONLY, 0, readfileFunc, 0, 0); if( rc==SQLITE_OK ){ rc = sqlite3_create_function(db, "writefile", -1, SQLITE_UTF8|SQLITE_DIRECTONLY, 0, writefileFunc, 0, 0); } if( rc==SQLITE_OK ){ rc = sqlite3_create_function(db, "lsmode", 1, SQLITE_UTF8, 0, lsModeFunc, 0, 0); } if( rc==SQLITE_OK ){ rc = fsdirRegister(db); } return rc; } #if defined(FILEIO_WIN32_DLL) && (defined(_WIN32) || defined(WIN32)) /* To allow a standalone DLL, make test_windirent.c use the same * redefined SQLite API calls as the above extension code does. * Just pull in this .c to accomplish this. As a beneficial side * effect, this extension becomes a single translation unit. */ # include "test_windirent.c" #endif |
Added ext/misc/fossildelta.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 | /* ** 2019-02-19 ** ** 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 the delta functions used by the RBU ** extension. Three scalar functions and one table-valued function are ** implemented here: ** ** delta_apply(X,D) -- apply delta D to file X and return the result ** delta_create(X,Y) -- compute and return a delta that carries X into Y ** delta_output_size(D) -- blob size in bytes output from applying delta D ** delta_parse(D) -- returns rows describing delta D ** ** The delta format is the Fossil delta format, described in a comment ** on the delete_create() function implementation below, and also at ** ** https://www.fossil-scm.org/fossil/doc/trunk/www/delta_format.wiki ** ** This delta format is used by the RBU extension, which is the main ** reason that these routines are included in the extension library. ** RBU does not use this extension directly. Rather, this extension is ** provided as a convenience to developers who want to analyze RBU files ** that contain deltas. */ #include <string.h> #include <assert.h> #include <stdlib.h> #include "sqlite3ext.h" SQLITE_EXTENSION_INIT1 #ifndef SQLITE_AMALGAMATION /* ** The "u32" type must be an unsigned 32-bit integer. Adjust this */ typedef unsigned int u32; /* ** Must be a 16-bit value */ typedef short int s16; typedef unsigned short int u16; #endif /* SQLITE_AMALGAMATION */ /* ** The width of a hash window in bytes. The algorithm only works if this ** is a power of 2. */ #define NHASH 16 /* ** The current state of the rolling hash. ** ** z[] holds the values that have been hashed. z[] is a circular buffer. ** z[i] is the first entry and z[(i+NHASH-1)%NHASH] is the last entry of ** the window. ** ** Hash.a is the sum of all elements of hash.z[]. Hash.b is a weighted ** sum. Hash.b is z[i]*NHASH + z[i+1]*(NHASH-1) + ... + z[i+NHASH-1]*1. ** (Each index for z[] should be module NHASH, of course. The %NHASH operator ** is omitted in the prior expression for brevity.) */ typedef struct hash hash; struct hash { u16 a, b; /* Hash values */ u16 i; /* Start of the hash window */ char z[NHASH]; /* The values that have been hashed */ }; /* ** Initialize the rolling hash using the first NHASH characters of z[] */ static void hash_init(hash *pHash, const char *z){ u16 a, b, i; a = b = z[0]; for(i=1; i<NHASH; i++){ a += z[i]; b += a; } memcpy(pHash->z, z, NHASH); pHash->a = a & 0xffff; pHash->b = b & 0xffff; pHash->i = 0; } /* ** Advance the rolling hash by a single character "c" */ static void hash_next(hash *pHash, int c){ u16 old = pHash->z[pHash->i]; pHash->z[pHash->i] = c; pHash->i = (pHash->i+1)&(NHASH-1); pHash->a = pHash->a - old + c; pHash->b = pHash->b - NHASH*old + pHash->a; } /* ** Return a 32-bit hash value */ static u32 hash_32bit(hash *pHash){ return (pHash->a & 0xffff) | (((u32)(pHash->b & 0xffff))<<16); } /* ** Compute a hash on NHASH bytes. ** ** This routine is intended to be equivalent to: ** hash h; ** hash_init(&h, zInput); ** return hash_32bit(&h); */ static u32 hash_once(const char *z){ u16 a, b, i; a = b = z[0]; for(i=1; i<NHASH; i++){ a += z[i]; b += a; } return a | (((u32)b)<<16); } /* ** Write an base-64 integer into the given buffer. */ static void putInt(unsigned int v, char **pz){ static const char zDigits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz~"; /* 123456789 123456789 123456789 123456789 123456789 123456789 123 */ int i, j; char zBuf[20]; if( v==0 ){ *(*pz)++ = '0'; return; } for(i=0; v>0; i++, v>>=6){ zBuf[i] = zDigits[v&0x3f]; } for(j=i-1; j>=0; j--){ *(*pz)++ = zBuf[j]; } } /* ** Read bytes from *pz and convert them into a positive integer. When ** finished, leave *pz pointing to the first character past the end of ** the integer. The *pLen parameter holds the length of the string ** in *pz and is decremented once for each character in the integer. */ static unsigned int deltaGetInt(const char **pz, int *pLen){ static const signed char zValue[] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, -1, 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, -1, -1, -1, -1, 36, -1, 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, -1, -1, -1, 63, -1, }; unsigned int v = 0; int c; unsigned char *z = (unsigned char*)*pz; unsigned char *zStart = z; while( (c = zValue[0x7f&*(z++)])>=0 ){ v = (v<<6) + c; } z--; *pLen -= z - zStart; *pz = (char*)z; return v; } /* ** Return the number digits in the base-64 representation of a positive integer */ static int digit_count(int v){ unsigned int i, x; for(i=1, x=64; v>=x; i++, x <<= 6){} return i; } #ifdef __GNUC__ # define GCC_VERSION (__GNUC__*1000000+__GNUC_MINOR__*1000+__GNUC_PATCHLEVEL__) #else # define GCC_VERSION 0 #endif /* ** Compute a 32-bit big-endian checksum on the N-byte buffer. If the ** buffer is not a multiple of 4 bytes length, compute the sum that would ** have occurred if the buffer was padded with zeros to the next multiple ** of four bytes. */ static unsigned int checksum(const char *zIn, size_t N){ static const int byteOrderTest = 1; const unsigned char *z = (const unsigned char *)zIn; const unsigned char *zEnd = (const unsigned char*)&zIn[N&~3]; unsigned sum = 0; assert( (z - (const unsigned char*)0)%4==0 ); /* Four-byte alignment */ if( 0==*(char*)&byteOrderTest ){ /* This is a big-endian machine */ while( z<zEnd ){ sum += *(unsigned*)z; z += 4; } }else{ /* A little-endian machine */ #if GCC_VERSION>=4003000 while( z<zEnd ){ sum += __builtin_bswap32(*(unsigned*)z); z += 4; } #elif defined(_MSC_VER) && _MSC_VER>=1300 while( z<zEnd ){ sum += _byteswap_ulong(*(unsigned*)z); z += 4; } #else unsigned sum0 = 0; unsigned sum1 = 0; unsigned sum2 = 0; while(N >= 16){ sum0 += ((unsigned)z[0] + z[4] + z[8] + z[12]); sum1 += ((unsigned)z[1] + z[5] + z[9] + z[13]); sum2 += ((unsigned)z[2] + z[6] + z[10]+ z[14]); sum += ((unsigned)z[3] + z[7] + z[11]+ z[15]); z += 16; N -= 16; } while(N >= 4){ sum0 += z[0]; sum1 += z[1]; sum2 += z[2]; sum += z[3]; z += 4; N -= 4; } sum += (sum2 << 8) + (sum1 << 16) + (sum0 << 24); #endif } switch(N&3){ case 3: sum += (z[2] << 8); case 2: sum += (z[1] << 16); case 1: sum += (z[0] << 24); default: ; } return sum; } /* ** Create a new delta. ** ** The delta is written into a preallocated buffer, zDelta, which ** should be at least 60 bytes longer than the target file, zOut. ** The delta string will be NUL-terminated, but it might also contain ** embedded NUL characters if either the zSrc or zOut files are ** binary. This function returns the length of the delta string ** in bytes, excluding the final NUL terminator character. ** ** Output Format: ** ** The delta begins with a base64 number followed by a newline. This ** number is the number of bytes in the TARGET file. Thus, given a ** delta file z, a program can compute the size of the output file ** simply by reading the first line and decoding the base-64 number ** found there. The delta_output_size() routine does exactly this. ** ** After the initial size number, the delta consists of a series of ** literal text segments and commands to copy from the SOURCE file. ** A copy command looks like this: ** ** NNN@MMM, ** ** where NNN is the number of bytes to be copied and MMM is the offset ** into the source file of the first byte (both base-64). If NNN is 0 ** it means copy the rest of the input file. Literal text is like this: ** ** NNN:TTTTT ** ** where NNN is the number of bytes of text (base-64) and TTTTT is the text. ** ** The last term is of the form ** ** NNN; ** ** In this case, NNN is a 32-bit bigendian checksum of the output file ** that can be used to verify that the delta applied correctly. All ** numbers are in base-64. ** ** Pure text files generate a pure text delta. Binary files generate a ** delta that may contain some binary data. ** ** Algorithm: ** ** The encoder first builds a hash table to help it find matching ** patterns in the source file. 16-byte chunks of the source file ** sampled at evenly spaced intervals are used to populate the hash ** table. ** ** Next we begin scanning the target file using a sliding 16-byte ** window. The hash of the 16-byte window in the target is used to ** search for a matching section in the source file. When a match ** is found, a copy command is added to the delta. An effort is ** made to extend the matching section to regions that come before ** and after the 16-byte hash window. A copy command is only issued ** if the result would use less space that just quoting the text ** literally. Literal text is added to the delta for sections that ** do not match or which can not be encoded efficiently using copy ** commands. */ static int delta_create( const char *zSrc, /* The source or pattern file */ unsigned int lenSrc, /* Length of the source file */ const char *zOut, /* The target file */ unsigned int lenOut, /* Length of the target file */ char *zDelta /* Write the delta into this buffer */ ){ int i, base; char *zOrigDelta = zDelta; hash h; int nHash; /* Number of hash table entries */ int *landmark; /* Primary hash table */ int *collide; /* Collision chain */ int lastRead = -1; /* Last byte of zSrc read by a COPY command */ /* Add the target file size to the beginning of the delta */ putInt(lenOut, &zDelta); *(zDelta++) = '\n'; /* If the source file is very small, it means that we have no ** chance of ever doing a copy command. Just output a single ** literal segment for the entire target and exit. */ if( lenSrc<=NHASH ){ putInt(lenOut, &zDelta); *(zDelta++) = ':'; memcpy(zDelta, zOut, lenOut); zDelta += lenOut; putInt(checksum(zOut, lenOut), &zDelta); *(zDelta++) = ';'; return zDelta - zOrigDelta; } /* Compute the hash table used to locate matching sections in the ** source file. */ nHash = lenSrc/NHASH; collide = sqlite3_malloc64( (sqlite3_int64)nHash*2*sizeof(int) ); memset(collide, -1, nHash*2*sizeof(int)); landmark = &collide[nHash]; for(i=0; i<lenSrc-NHASH; i+=NHASH){ int hv = hash_once(&zSrc[i]) % nHash; collide[i/NHASH] = landmark[hv]; landmark[hv] = i/NHASH; } /* Begin scanning the target file and generating copy commands and ** literal sections of the delta. */ base = 0; /* We have already generated everything before zOut[base] */ while( base+NHASH<lenOut ){ int iSrc, iBlock; unsigned int bestCnt, bestOfst=0, bestLitsz=0; hash_init(&h, &zOut[base]); i = 0; /* Trying to match a landmark against zOut[base+i] */ bestCnt = 0; while( 1 ){ int hv; int limit = 250; hv = hash_32bit(&h) % nHash; iBlock = landmark[hv]; while( iBlock>=0 && (limit--)>0 ){ /* ** The hash window has identified a potential match against ** landmark block iBlock. But we need to investigate further. ** ** Look for a region in zOut that matches zSrc. Anchor the search ** at zSrc[iSrc] and zOut[base+i]. Do not include anything prior to ** zOut[base] or after zOut[outLen] nor anything after zSrc[srcLen]. ** ** Set cnt equal to the length of the match and set ofst so that ** zSrc[ofst] is the first element of the match. litsz is the number ** of characters between zOut[base] and the beginning of the match. ** sz will be the overhead (in bytes) needed to encode the copy ** command. Only generate copy command if the overhead of the ** copy command is less than the amount of literal text to be copied. */ int cnt, ofst, litsz; int j, k, x, y; int sz; int limitX; /* Beginning at iSrc, match forwards as far as we can. j counts ** the number of characters that match */ iSrc = iBlock*NHASH; y = base+i; limitX = ( lenSrc-iSrc <= lenOut-y ) ? lenSrc : iSrc + lenOut - y; for(x=iSrc; x<limitX; x++, y++){ if( zSrc[x]!=zOut[y] ) break; } j = x - iSrc - 1; /* Beginning at iSrc-1, match backwards as far as we can. k counts ** the number of characters that match */ for(k=1; k<iSrc && k<=i; k++){ if( zSrc[iSrc-k]!=zOut[base+i-k] ) break; } k--; /* Compute the offset and size of the matching region */ ofst = iSrc-k; cnt = j+k+1; litsz = i-k; /* Number of bytes of literal text before the copy */ /* sz will hold the number of bytes needed to encode the "insert" ** command and the copy command, not counting the "insert" text */ sz = digit_count(i-k)+digit_count(cnt)+digit_count(ofst)+3; if( cnt>=sz && cnt>bestCnt ){ /* Remember this match only if it is the best so far and it ** does not increase the file size */ bestCnt = cnt; bestOfst = iSrc-k; bestLitsz = litsz; } /* Check the next matching block */ iBlock = collide[iBlock]; } /* We have a copy command that does not cause the delta to be larger ** than a literal insert. So add the copy command to the delta. */ if( bestCnt>0 ){ if( bestLitsz>0 ){ /* Add an insert command before the copy */ putInt(bestLitsz,&zDelta); *(zDelta++) = ':'; memcpy(zDelta, &zOut[base], bestLitsz); zDelta += bestLitsz; base += bestLitsz; } base += bestCnt; putInt(bestCnt, &zDelta); *(zDelta++) = '@'; putInt(bestOfst, &zDelta); *(zDelta++) = ','; if( bestOfst + bestCnt -1 > lastRead ){ lastRead = bestOfst + bestCnt - 1; } bestCnt = 0; break; } /* If we reach this point, it means no match is found so far */ if( base+i+NHASH>=lenOut ){ /* We have reached the end of the file and have not found any ** matches. Do an "insert" for everything that does not match */ putInt(lenOut-base, &zDelta); *(zDelta++) = ':'; memcpy(zDelta, &zOut[base], lenOut-base); zDelta += lenOut-base; base = lenOut; break; } /* Advance the hash by one character. Keep looking for a match */ hash_next(&h, zOut[base+i+NHASH]); i++; } } /* Output a final "insert" record to get all the text at the end of ** the file that does not match anything in the source file. */ if( base<lenOut ){ putInt(lenOut-base, &zDelta); *(zDelta++) = ':'; memcpy(zDelta, &zOut[base], lenOut-base); zDelta += lenOut-base; } /* Output the final checksum record. */ putInt(checksum(zOut, lenOut), &zDelta); *(zDelta++) = ';'; sqlite3_free(collide); return zDelta - zOrigDelta; } /* ** Return the size (in bytes) of the output from applying ** a delta. ** ** This routine is provided so that an procedure that is able ** to call delta_apply() can learn how much space is required ** for the output and hence allocate nor more space that is really ** needed. */ static int delta_output_size(const char *zDelta, int lenDelta){ int size; size = deltaGetInt(&zDelta, &lenDelta); if( *zDelta!='\n' ){ /* ERROR: size integer not terminated by "\n" */ return -1; } return size; } /* ** Apply a delta. ** ** The output buffer should be big enough to hold the whole output ** file and a NUL terminator at the end. The delta_output_size() ** routine will determine this size for you. ** ** The delta string should be null-terminated. But the delta string ** may contain embedded NUL characters (if the input and output are ** binary files) so we also have to pass in the length of the delta in ** the lenDelta parameter. ** ** This function returns the size of the output file in bytes (excluding ** the final NUL terminator character). Except, if the delta string is ** malformed or intended for use with a source file other than zSrc, ** then this routine returns -1. ** ** Refer to the delta_create() documentation above for a description ** of the delta file format. */ static int delta_apply( const char *zSrc, /* The source or pattern file */ int lenSrc, /* Length of the source file */ const char *zDelta, /* Delta to apply to the pattern */ int lenDelta, /* Length of the delta */ char *zOut /* Write the output into this preallocated buffer */ ){ unsigned int limit; unsigned int total = 0; #ifdef FOSSIL_ENABLE_DELTA_CKSUM_TEST char *zOrigOut = zOut; #endif limit = deltaGetInt(&zDelta, &lenDelta); if( *zDelta!='\n' ){ /* ERROR: size integer not terminated by "\n" */ return -1; } zDelta++; lenDelta--; while( *zDelta && lenDelta>0 ){ unsigned int cnt, ofst; cnt = deltaGetInt(&zDelta, &lenDelta); switch( zDelta[0] ){ case '@': { zDelta++; lenDelta--; ofst = deltaGetInt(&zDelta, &lenDelta); if( lenDelta>0 && zDelta[0]!=',' ){ /* ERROR: copy command not terminated by ',' */ return -1; } zDelta++; lenDelta--; total += cnt; if( total>limit ){ /* ERROR: copy exceeds output file size */ return -1; } if( ofst+cnt > lenSrc ){ /* ERROR: copy extends past end of input */ return -1; } memcpy(zOut, &zSrc[ofst], cnt); zOut += cnt; break; } case ':': { zDelta++; lenDelta--; total += cnt; if( total>limit ){ /* ERROR: insert command gives an output larger than predicted */ return -1; } if( cnt>lenDelta ){ /* ERROR: insert count exceeds size of delta */ return -1; } memcpy(zOut, zDelta, cnt); zOut += cnt; zDelta += cnt; lenDelta -= cnt; break; } case ';': { zDelta++; lenDelta--; zOut[0] = 0; #ifdef FOSSIL_ENABLE_DELTA_CKSUM_TEST if( cnt!=checksum(zOrigOut, total) ){ /* ERROR: bad checksum */ return -1; } #endif if( total!=limit ){ /* ERROR: generated size does not match predicted size */ return -1; } return total; } default: { /* ERROR: unknown delta operator */ return -1; } } } /* ERROR: unterminated delta */ return -1; } /* ** SQL functions: delta_create(X,Y) ** ** Return a delta for carrying X into Y. */ static void deltaCreateFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ const char *aOrig; int nOrig; /* old blob */ const char *aNew; int nNew; /* new blob */ char *aOut; int nOut; /* output delta */ assert( argc==2 ); if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return; if( sqlite3_value_type(argv[1])==SQLITE_NULL ) return; nOrig = sqlite3_value_bytes(argv[0]); aOrig = (const char*)sqlite3_value_blob(argv[0]); nNew = sqlite3_value_bytes(argv[1]); aNew = (const char*)sqlite3_value_blob(argv[1]); aOut = sqlite3_malloc64(nNew+70); if( aOut==0 ){ sqlite3_result_error_nomem(context); }else{ nOut = delta_create(aOrig, nOrig, aNew, nNew, aOut); if( nOut<0 ){ sqlite3_free(aOut); sqlite3_result_error(context, "cannot create fossil delta", -1); }else{ sqlite3_result_blob(context, aOut, nOut, sqlite3_free); } } } /* ** SQL functions: delta_apply(X,D) ** ** Return the result of applying delta D to input X. */ static void deltaApplyFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ const char *aOrig; int nOrig; /* The X input */ const char *aDelta; int nDelta; /* The input delta (D) */ char *aOut; int nOut, nOut2; /* The output */ assert( argc==2 ); if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return; if( sqlite3_value_type(argv[1])==SQLITE_NULL ) return; nOrig = sqlite3_value_bytes(argv[0]); aOrig = (const char*)sqlite3_value_blob(argv[0]); nDelta = sqlite3_value_bytes(argv[1]); aDelta = (const char*)sqlite3_value_blob(argv[1]); /* Figure out the size of the output */ nOut = delta_output_size(aDelta, nDelta); if( nOut<0 ){ sqlite3_result_error(context, "corrupt fossil delta", -1); return; } aOut = sqlite3_malloc64((sqlite3_int64)nOut+1); if( aOut==0 ){ sqlite3_result_error_nomem(context); }else{ nOut2 = delta_apply(aOrig, nOrig, aDelta, nDelta, aOut); if( nOut2!=nOut ){ sqlite3_free(aOut); sqlite3_result_error(context, "corrupt fossil delta", -1); }else{ sqlite3_result_blob(context, aOut, nOut, sqlite3_free); } } } /* ** SQL functions: delta_output_size(D) ** ** Return the size of the output that results from applying delta D. */ static void deltaOutputSizeFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ const char *aDelta; int nDelta; /* The input delta (D) */ int nOut; /* Size of output */ assert( argc==1 ); if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return; nDelta = sqlite3_value_bytes(argv[0]); aDelta = (const char*)sqlite3_value_blob(argv[0]); /* Figure out the size of the output */ nOut = delta_output_size(aDelta, nDelta); if( nOut<0 ){ sqlite3_result_error(context, "corrupt fossil delta", -1); return; }else{ sqlite3_result_int(context, nOut); } } /***************************************************************************** ** Table-valued SQL function: delta_parse(DELTA) ** ** Schema: ** ** CREATE TABLE delta_parse( ** op TEXT, ** a1 INT, ** a2 ANY, ** delta HIDDEN BLOB ** ); ** ** Given an input DELTA, this function parses the delta and returns ** rows for each entry in the delta. The op column has one of the ** values SIZE, COPY, INSERT, CHECKSUM, ERROR. ** ** Assuming no errors, the first row has op='SIZE'. a1 is the size of ** the output in bytes and a2 is NULL. ** ** After the initial SIZE row, there are zero or more 'COPY' and/or 'INSERT' ** rows. A COPY row means content is copied from the source into the ** output. Column a1 is the number of bytes to copy and a2 is the offset ** into source from which to begin copying. An INSERT row means to ** insert text into the output stream. Column a1 is the number of bytes ** to insert and column is a BLOB that contains the text to be inserted. ** ** The last row of a well-formed delta will have an op value of 'CHECKSUM'. ** The a1 column will be the value of the checksum and a2 will be NULL. ** ** If the input delta is not well-formed, then a row with an op value ** of 'ERROR' is returned. The a1 value of the ERROR row is the offset ** into the delta where the error was encountered and a2 is NULL. */ typedef struct deltaparsevtab_vtab deltaparsevtab_vtab; typedef struct deltaparsevtab_cursor deltaparsevtab_cursor; struct deltaparsevtab_vtab { sqlite3_vtab base; /* Base class - must be first */ /* No additional information needed */ }; struct deltaparsevtab_cursor { sqlite3_vtab_cursor base; /* Base class - must be first */ char *aDelta; /* The delta being parsed */ int nDelta; /* Number of bytes in the delta */ int iCursor; /* Current cursor location */ int eOp; /* Name of current operator */ unsigned int a1, a2; /* Arguments to current operator */ int iNext; /* Next cursor value */ }; /* Operator names: */ static const char *azOp[] = { "SIZE", "COPY", "INSERT", "CHECKSUM", "ERROR", "EOF" }; #define DELTAPARSE_OP_SIZE 0 #define DELTAPARSE_OP_COPY 1 #define DELTAPARSE_OP_INSERT 2 #define DELTAPARSE_OP_CHECKSUM 3 #define DELTAPARSE_OP_ERROR 4 #define DELTAPARSE_OP_EOF 5 /* ** The deltaparsevtabConnect() method is invoked to create a new ** deltaparse virtual table. ** ** Think of this routine as the constructor for deltaparsevtab_vtab objects. ** ** All this routine needs to do is: ** ** (1) Allocate the deltaparsevtab_vtab object and initialize all fields. ** ** (2) Tell SQLite (via the sqlite3_declare_vtab() interface) what the ** result set of queries against the virtual table will look like. */ static int deltaparsevtabConnect( sqlite3 *db, void *pAux, int argc, const char *const*argv, sqlite3_vtab **ppVtab, char **pzErr ){ deltaparsevtab_vtab *pNew; int rc; rc = sqlite3_declare_vtab(db, "CREATE TABLE x(op,a1,a2,delta HIDDEN)" ); /* For convenience, define symbolic names for the index to each column. */ #define DELTAPARSEVTAB_OP 0 #define DELTAPARSEVTAB_A1 1 #define DELTAPARSEVTAB_A2 2 #define DELTAPARSEVTAB_DELTA 3 if( rc==SQLITE_OK ){ pNew = sqlite3_malloc64( sizeof(*pNew) ); *ppVtab = (sqlite3_vtab*)pNew; if( pNew==0 ) return SQLITE_NOMEM; memset(pNew, 0, sizeof(*pNew)); sqlite3_vtab_config(db, SQLITE_VTAB_INNOCUOUS); } return rc; } /* ** This method is the destructor for deltaparsevtab_vtab objects. */ static int deltaparsevtabDisconnect(sqlite3_vtab *pVtab){ deltaparsevtab_vtab *p = (deltaparsevtab_vtab*)pVtab; sqlite3_free(p); return SQLITE_OK; } /* ** Constructor for a new deltaparsevtab_cursor object. */ static int deltaparsevtabOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){ deltaparsevtab_cursor *pCur; pCur = sqlite3_malloc( sizeof(*pCur) ); if( pCur==0 ) return SQLITE_NOMEM; memset(pCur, 0, sizeof(*pCur)); *ppCursor = &pCur->base; return SQLITE_OK; } /* ** Destructor for a deltaparsevtab_cursor. */ static int deltaparsevtabClose(sqlite3_vtab_cursor *cur){ deltaparsevtab_cursor *pCur = (deltaparsevtab_cursor*)cur; sqlite3_free(pCur->aDelta); sqlite3_free(pCur); return SQLITE_OK; } /* ** Advance a deltaparsevtab_cursor to its next row of output. */ static int deltaparsevtabNext(sqlite3_vtab_cursor *cur){ deltaparsevtab_cursor *pCur = (deltaparsevtab_cursor*)cur; const char *z; int i = 0; pCur->iCursor = pCur->iNext; z = pCur->aDelta + pCur->iCursor; pCur->a1 = deltaGetInt(&z, &i); switch( z[0] ){ case '@': { z++; pCur->a2 = deltaGetInt(&z, &i); pCur->eOp = DELTAPARSE_OP_COPY; pCur->iNext = (int)(&z[1] - pCur->aDelta); break; } case ':': { z++; pCur->a2 = (unsigned int)(z - pCur->aDelta); pCur->eOp = DELTAPARSE_OP_INSERT; pCur->iNext = (int)(&z[pCur->a1] - pCur->aDelta); break; } case ';': { pCur->eOp = DELTAPARSE_OP_CHECKSUM; pCur->iNext = pCur->nDelta; break; } default: { if( pCur->iNext==pCur->nDelta ){ pCur->eOp = DELTAPARSE_OP_EOF; }else{ pCur->eOp = DELTAPARSE_OP_ERROR; pCur->iNext = pCur->nDelta; } break; } } return SQLITE_OK; } /* ** Return values of columns for the row at which the deltaparsevtab_cursor ** is currently pointing. */ static int deltaparsevtabColumn( sqlite3_vtab_cursor *cur, /* The cursor */ sqlite3_context *ctx, /* First argument to sqlite3_result_...() */ int i /* Which column to return */ ){ deltaparsevtab_cursor *pCur = (deltaparsevtab_cursor*)cur; switch( i ){ case DELTAPARSEVTAB_OP: { sqlite3_result_text(ctx, azOp[pCur->eOp], -1, SQLITE_STATIC); break; } case DELTAPARSEVTAB_A1: { sqlite3_result_int(ctx, pCur->a1); break; } case DELTAPARSEVTAB_A2: { if( pCur->eOp==DELTAPARSE_OP_COPY ){ sqlite3_result_int(ctx, pCur->a2); }else if( pCur->eOp==DELTAPARSE_OP_INSERT ){ sqlite3_result_blob(ctx, pCur->aDelta+pCur->a2, pCur->a1, SQLITE_TRANSIENT); } break; } case DELTAPARSEVTAB_DELTA: { sqlite3_result_blob(ctx, pCur->aDelta, pCur->nDelta, SQLITE_TRANSIENT); break; } } return SQLITE_OK; } /* ** Return the rowid for the current row. In this implementation, the ** rowid is the same as the output value. */ static int deltaparsevtabRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){ deltaparsevtab_cursor *pCur = (deltaparsevtab_cursor*)cur; *pRowid = pCur->iCursor; return SQLITE_OK; } /* ** Return TRUE if the cursor has been moved off of the last ** row of output. */ static int deltaparsevtabEof(sqlite3_vtab_cursor *cur){ deltaparsevtab_cursor *pCur = (deltaparsevtab_cursor*)cur; return pCur->eOp==DELTAPARSE_OP_EOF; } /* ** This method is called to "rewind" the deltaparsevtab_cursor object back ** to the first row of output. This method is always called at least ** once prior to any call to deltaparsevtabColumn() or deltaparsevtabRowid() or ** deltaparsevtabEof(). */ static int deltaparsevtabFilter( sqlite3_vtab_cursor *pVtabCursor, int idxNum, const char *idxStr, int argc, sqlite3_value **argv ){ deltaparsevtab_cursor *pCur = (deltaparsevtab_cursor *)pVtabCursor; const char *a; int i = 0; pCur->eOp = DELTAPARSE_OP_ERROR; if( idxNum!=1 ){ return SQLITE_OK; } pCur->nDelta = sqlite3_value_bytes(argv[0]); a = (const char*)sqlite3_value_blob(argv[0]); if( pCur->nDelta==0 || a==0 ){ return SQLITE_OK; } pCur->aDelta = sqlite3_malloc64( pCur->nDelta+1 ); if( pCur->aDelta==0 ){ pCur->nDelta = 0; return SQLITE_NOMEM; } memcpy(pCur->aDelta, a, pCur->nDelta); pCur->aDelta[pCur->nDelta] = 0; a = pCur->aDelta; pCur->eOp = DELTAPARSE_OP_SIZE; pCur->a1 = deltaGetInt(&a, &i); if( a[0]!='\n' ){ pCur->eOp = DELTAPARSE_OP_ERROR; pCur->a1 = pCur->a2 = 0; pCur->iNext = pCur->nDelta; return SQLITE_OK; } a++; pCur->iNext = (unsigned int)(a - pCur->aDelta); return SQLITE_OK; } /* ** SQLite will invoke this method one or more times while planning a query ** that uses the virtual table. This routine needs to create ** a query plan for each invocation and compute an estimated cost for that ** plan. */ static int deltaparsevtabBestIndex( sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo ){ int i; for(i=0; i<pIdxInfo->nConstraint; i++){ if( pIdxInfo->aConstraint[i].iColumn != DELTAPARSEVTAB_DELTA ) continue; if( pIdxInfo->aConstraint[i].usable==0 ) continue; if( pIdxInfo->aConstraint[i].op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue; pIdxInfo->aConstraintUsage[i].argvIndex = 1; pIdxInfo->aConstraintUsage[i].omit = 1; pIdxInfo->estimatedCost = (double)1; pIdxInfo->estimatedRows = 10; pIdxInfo->idxNum = 1; return SQLITE_OK; } pIdxInfo->idxNum = 0; pIdxInfo->estimatedCost = (double)0x7fffffff; pIdxInfo->estimatedRows = 0x7fffffff; return SQLITE_CONSTRAINT; } /* ** This following structure defines all the methods for the ** virtual table. */ static sqlite3_module deltaparsevtabModule = { /* iVersion */ 0, /* xCreate */ 0, /* xConnect */ deltaparsevtabConnect, /* xBestIndex */ deltaparsevtabBestIndex, /* xDisconnect */ deltaparsevtabDisconnect, /* xDestroy */ 0, /* xOpen */ deltaparsevtabOpen, /* xClose */ deltaparsevtabClose, /* xFilter */ deltaparsevtabFilter, /* xNext */ deltaparsevtabNext, /* xEof */ deltaparsevtabEof, /* xColumn */ deltaparsevtabColumn, /* xRowid */ deltaparsevtabRowid, /* xUpdate */ 0, /* xBegin */ 0, /* xSync */ 0, /* xCommit */ 0, /* xRollback */ 0, /* xFindMethod */ 0, /* xRename */ 0, /* xSavepoint */ 0, /* xRelease */ 0, /* xRollbackTo */ 0, /* xShadowName */ 0 }; #ifdef _WIN32 __declspec(dllexport) #endif int sqlite3_fossildelta_init( sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi ){ static const int enc = SQLITE_UTF8|SQLITE_INNOCUOUS; int rc = SQLITE_OK; SQLITE_EXTENSION_INIT2(pApi); (void)pzErrMsg; /* Unused parameter */ rc = sqlite3_create_function(db, "delta_create", 2, enc, 0, deltaCreateFunc, 0, 0); if( rc==SQLITE_OK ){ rc = sqlite3_create_function(db, "delta_apply", 2, enc, 0, deltaApplyFunc, 0, 0); } if( rc==SQLITE_OK ){ rc = sqlite3_create_function(db, "delta_output_size", 1, enc, 0, deltaOutputSizeFunc, 0, 0); } if( rc==SQLITE_OK ){ rc = sqlite3_create_module(db, "delta_parse", &deltaparsevtabModule, 0); } return rc; } |
Changes to ext/misc/fuzzer.c.
︙ | ︙ | |||
333 334 335 336 337 338 339 | if( iRuleset<0 || iRuleset>FUZZER_MX_RULEID ){ *pzErr = sqlite3_mprintf("%s: ruleset must be between 0 and %d", p->zClassName, FUZZER_MX_RULEID ); rc = SQLITE_ERROR; }else{ | | | 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 | if( iRuleset<0 || iRuleset>FUZZER_MX_RULEID ){ *pzErr = sqlite3_mprintf("%s: ruleset must be between 0 and %d", p->zClassName, FUZZER_MX_RULEID ); rc = SQLITE_ERROR; }else{ pRule = sqlite3_malloc64( sizeof(*pRule) + nFrom + nTo ); if( pRule==0 ){ rc = SQLITE_NOMEM; }else{ memset(pRule, 0, sizeof(*pRule)); pRule->zFrom = pRule->zTo; pRule->zFrom += nTo + 1; pRule->nFrom = (fuzzer_len)nFrom; |
︙ | ︙ | |||
443 444 445 446 447 448 449 | ** ** "abc" becomes abc ** 'xyz' becomes xyz ** [pqr] becomes pqr ** `mno` becomes mno */ static char *fuzzerDequote(const char *zIn){ | | | | | | 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 | ** ** "abc" becomes abc ** 'xyz' becomes xyz ** [pqr] becomes pqr ** `mno` becomes mno */ static char *fuzzerDequote(const char *zIn){ sqlite3_int64 nIn; /* Size of input string, in bytes */ char *zOut; /* Output (dequoted) string */ nIn = strlen(zIn); zOut = sqlite3_malloc64(nIn+1); if( zOut ){ char q = zIn[0]; /* Quote character (if any ) */ if( q!='[' && q!= '\'' && q!='"' && q!='`' ){ memcpy(zOut, zIn, (size_t)(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++; |
︙ | ︙ | |||
509 510 511 512 513 514 515 | if( argc!=4 ){ *pzErr = sqlite3_mprintf( "%s: wrong number of CREATE VIRTUAL TABLE arguments", zModule ); rc = SQLITE_ERROR; }else{ | | | | | > > | 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 | if( argc!=4 ){ *pzErr = sqlite3_mprintf( "%s: wrong number of CREATE VIRTUAL TABLE arguments", zModule ); rc = SQLITE_ERROR; }else{ sqlite3_int64 nModule; /* Length of zModule, in bytes */ nModule = strlen(zModule); pNew = sqlite3_malloc64( sizeof(*pNew) + nModule + 1); if( pNew==0 ){ rc = SQLITE_NOMEM; }else{ char *zTab; /* Dequoted name of fuzzer data table */ memset(pNew, 0, sizeof(*pNew)); pNew->zClassName = (char*)&pNew[1]; memcpy(pNew->zClassName, zModule, (size_t)(nModule+1)); zTab = fuzzerDequote(argv[3]); if( zTab==0 ){ rc = SQLITE_NOMEM; }else{ rc = fuzzerLoadRules(db, pNew, zDb, zTab, pzErr); sqlite3_free(zTab); } if( rc==SQLITE_OK ){ rc = sqlite3_declare_vtab(db, "CREATE TABLE x(word,distance,ruleset)"); } if( rc!=SQLITE_OK ){ fuzzerDisconnect((sqlite3_vtab *)pNew); pNew = 0; }else{ sqlite3_vtab_config(db, SQLITE_VTAB_INNOCUOUS); } } } *ppVtab = (sqlite3_vtab *)pNew; return rc; } |
︙ | ︙ | |||
868 869 870 871 872 873 874 | const char *zWord, fuzzer_cost rBaseCost ){ fuzzer_stem *pNew; fuzzer_rule *pRule; unsigned int h; | | | 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 | const char *zWord, fuzzer_cost rBaseCost ){ fuzzer_stem *pNew; fuzzer_rule *pRule; unsigned int h; pNew = sqlite3_malloc64( sizeof(*pNew) + strlen(zWord) + 1 ); if( pNew==0 ) return 0; memset(pNew, 0, sizeof(*pNew)); pNew->zBasis = (char*)&pNew[1]; pNew->nBasis = (fuzzer_len)strlen(zWord); memcpy(pNew->zBasis, zWord, pNew->nBasis+1); pRule = pCur->pVtab->pRule; while( fuzzerSkipRule(pRule, pNew, pCur->iRuleset) ){ |
︙ | ︙ |
Changes to ext/misc/ieee754.c.
︙ | ︙ | |||
22 23 24 25 26 27 28 | ** ** 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,Z). ** ** Examples: ** | | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > | > > > > | > > > | | | > > > > > > > > | > > > > > > > > | | > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | < | < > | | 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 | ** ** 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,Z). ** ** Examples: ** ** ieee754(2.0) -> 'ieee754(2,0)' ** ieee754(45.25) -> 'ieee754(181,-2)' ** ieee754(2, 0) -> 2.0 ** ieee754(181, -2) -> 45.25 ** ** Two additional functions break apart the one-argument ieee754() ** result into separate integer values: ** ** ieee754_mantissa(45.25) -> 181 ** ieee754_exponent(45.25) -> -2 ** ** These functions convert binary64 numbers into blobs and back again. ** ** ieee754_from_blob(x'3ff0000000000000') -> 1.0 ** ieee754_to_blob(1.0) -> x'3ff0000000000000' ** ** In all single-argument functions, if the argument is an 8-byte blob ** then that blob is interpreted as a big-endian binary64 value. ** ** ** EXACT DECIMAL REPRESENTATION OF BINARY64 VALUES ** ----------------------------------------------- ** ** This extension in combination with the separate 'decimal' extension ** can be used to compute the exact decimal representation of binary64 ** values. To begin, first compute a table of exponent values: ** ** CREATE TABLE pow2(x INTEGER PRIMARY KEY, v TEXT); ** WITH RECURSIVE c(x,v) AS ( ** VALUES(0,'1') ** UNION ALL ** SELECT x+1, decimal_mul(v,'2') FROM c WHERE x+1<=971 ** ) INSERT INTO pow2(x,v) SELECT x, v FROM c; ** WITH RECURSIVE c(x,v) AS ( ** VALUES(-1,'0.5') ** UNION ALL ** SELECT x-1, decimal_mul(v,'0.5') FROM c WHERE x-1>=-1075 ** ) INSERT INTO pow2(x,v) SELECT x, v FROM c; ** ** Then, to compute the exact decimal representation of a floating ** point value (the value 47.49 is used in the example) do: ** ** WITH c(n) AS (VALUES(47.49)) ** ---------------^^^^^---- Replace with whatever you want ** SELECT decimal_mul(ieee754_mantissa(c.n),pow2.v) ** FROM pow2, c WHERE pow2.x=ieee754_exponent(c.n); ** ** Here is a query to show various boundry values for the binary64 ** number format: ** ** WITH c(name,bin) AS (VALUES ** ('minimum positive value', x'0000000000000001'), ** ('maximum subnormal value', x'000fffffffffffff'), ** ('mininum positive nornal value', x'0010000000000000'), ** ('maximum value', x'7fefffffffffffff')) ** SELECT c.name, decimal_mul(ieee754_mantissa(c.bin),pow2.v) ** FROM pow2, c WHERE pow2.x=ieee754_exponent(c.bin); ** */ #include "sqlite3ext.h" SQLITE_EXTENSION_INIT1 #include <assert.h> #include <string.h> /* Mark a function parameter as unused, to suppress nuisance compiler ** warnings. */ #ifndef UNUSED_PARAMETER # define UNUSED_PARAMETER(X) (void)(X) #endif /* ** 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_BLOB && sqlite3_value_bytes(argv[0])==sizeof(r) ){ const unsigned char *x = sqlite3_value_blob(argv[0]); unsigned int i; sqlite3_uint64 v = 0; for(i=0; i<sizeof(r); i++){ v = (v<<8) | x[i]; } memcpy(&r, &v, sizeof(r)); }else{ 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); if( e==0 ){ m <<= 1; }else{ m |= ((sqlite3_int64)1)<<52; } while( e<1075 && m>0 && (m&1)==0 ){ m >>= 1; e++; } if( isNeg ) m = -m; } switch( *(int*)sqlite3_user_data(context) ){ case 0: sqlite3_snprintf(sizeof(zResult), zResult, "ieee754(%lld,%d)", m, e-1075); sqlite3_result_text(context, zResult, -1, SQLITE_TRANSIENT); break; case 1: sqlite3_result_int64(context, m); break; case 2: sqlite3_result_int(context, e-1075); break; } }else{ sqlite3_int64 m, e, a; double r; int isNeg = 0; m = sqlite3_value_int64(argv[0]); e = sqlite3_value_int64(argv[1]); /* Limit the range of e. Ticket 22dea1cfdb9151e4 2021-03-02 */ if( e>10000 ){ e = 10000; }else if( e<-10000 ){ e = -10000; } 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!=0 && ((m>>32)&0xfff00000)==0 ){ m <<= 1; e--; } e += 1075; if( e<=0 ){ /* Subnormal */ if( 1-e >= 64 ){ m = 0; }else{ m >>= 1-e; } e = 0; }else if( e>0x7ff ){ e = 0x7ff; } a = m & ((((sqlite3_int64)1)<<52)-1); a |= e<<52; if( isNeg ) a |= ((sqlite3_uint64)1)<<63; memcpy(&r, &a, sizeof(r)); sqlite3_result_double(context, r); } } /* ** Functions to convert between blobs and floats. */ static void ieee754func_from_blob( sqlite3_context *context, int argc, sqlite3_value **argv ){ UNUSED_PARAMETER(argc); if( sqlite3_value_type(argv[0])==SQLITE_BLOB && sqlite3_value_bytes(argv[0])==sizeof(double) ){ double r; const unsigned char *x = sqlite3_value_blob(argv[0]); unsigned int i; sqlite3_uint64 v = 0; for(i=0; i<sizeof(r); i++){ v = (v<<8) | x[i]; } memcpy(&r, &v, sizeof(r)); sqlite3_result_double(context, r); } } static void ieee754func_to_blob( sqlite3_context *context, int argc, sqlite3_value **argv ){ UNUSED_PARAMETER(argc); if( sqlite3_value_type(argv[0])==SQLITE_FLOAT || sqlite3_value_type(argv[0])==SQLITE_INTEGER ){ double r = sqlite3_value_double(argv[0]); sqlite3_uint64 v; unsigned char a[sizeof(r)]; unsigned int i; memcpy(&v, &r, sizeof(r)); for(i=1; i<=sizeof(r); i++){ a[sizeof(r)-i] = v&0xff; v >>= 8; } sqlite3_result_blob(context, a, sizeof(r), SQLITE_TRANSIENT); } } #ifdef _WIN32 __declspec(dllexport) #endif int sqlite3_ieee_init( sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi ){ static const struct { char *zFName; int nArg; int iAux; void (*xFunc)(sqlite3_context*,int,sqlite3_value**); } aFunc[] = { { "ieee754", 1, 0, ieee754func }, { "ieee754", 2, 0, ieee754func }, { "ieee754_mantissa", 1, 1, ieee754func }, { "ieee754_exponent", 1, 2, ieee754func }, { "ieee754_to_blob", 1, 0, ieee754func_to_blob }, { "ieee754_from_blob", 1, 0, ieee754func_from_blob }, }; unsigned int i; int rc = SQLITE_OK; SQLITE_EXTENSION_INIT2(pApi); (void)pzErrMsg; /* Unused parameter */ for(i=0; i<sizeof(aFunc)/sizeof(aFunc[0]) && rc==SQLITE_OK; i++){ rc = sqlite3_create_function(db, aFunc[i].zFName, aFunc[i].nArg, SQLITE_UTF8|SQLITE_INNOCUOUS, (void*)&aFunc[i].iAux, aFunc[i].xFunc, 0, 0); } return rc; } |
Changes to ext/misc/json1.c.
︙ | ︙ | |||
38 39 40 41 42 43 44 45 46 47 48 49 50 51 | #endif #ifndef LARGEST_INT64 # define LARGEST_INT64 (0xffffffff|(((sqlite3_int64)0x7fffffff)<<32)) # define SMALLEST_INT64 (((sqlite3_int64)-1) - LARGEST_INT64) #endif /* ** Versions of isspace(), isalnum() and isdigit() to which it is safe ** to pass signed char values. */ #ifdef sqlite3Isdigit /* Use the SQLite core versions if this routine is part of the ** SQLite amalgamation */ | > > > > | 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | #endif #ifndef LARGEST_INT64 # define LARGEST_INT64 (0xffffffff|(((sqlite3_int64)0x7fffffff)<<32)) # define SMALLEST_INT64 (((sqlite3_int64)-1) - LARGEST_INT64) #endif #ifndef deliberate_fall_through # define deliberate_fall_through #endif /* ** Versions of isspace(), isalnum() and isdigit() to which it is safe ** to pass signed char values. */ #ifdef sqlite3Isdigit /* Use the SQLite core versions if this routine is part of the ** SQLite amalgamation */ |
︙ | ︙ | |||
88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 | #ifndef SQLITE_AMALGAMATION /* Unsigned integer types. These are already defined in the sqliteInt.h, ** but the definitions need to be repeated for separate compilation. */ typedef sqlite3_uint64 u64; typedef unsigned int u32; typedef unsigned short int u16; typedef unsigned char u8; #endif /* Objects */ typedef struct JsonString JsonString; typedef struct JsonNode JsonNode; typedef struct JsonParse JsonParse; /* An instance of this object represents a JSON string ** under construction. Really, this is a generic string accumulator | > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | #ifndef SQLITE_AMALGAMATION /* Unsigned integer types. These are already defined in the sqliteInt.h, ** but the definitions need to be repeated for separate compilation. */ typedef sqlite3_uint64 u64; typedef unsigned int u32; typedef unsigned short int u16; typedef unsigned char u8; # if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_MUTATION_TEST) # define SQLITE_OMIT_AUXILIARY_SAFETY_CHECKS 1 # endif # if defined(SQLITE_OMIT_AUXILIARY_SAFETY_CHECKS) # define ALWAYS(X) (1) # define NEVER(X) (0) # elif !defined(NDEBUG) # define ALWAYS(X) ((X)?1:(assert(0),0)) # define NEVER(X) ((X)?(assert(0),1):0) # else # define ALWAYS(X) (X) # define NEVER(X) (X) # endif # define testcase(X) #endif #if !defined(SQLITE_DEBUG) && !defined(SQLITE_COVERAGE_TEST) # define VVA(X) #else # define VVA(X) X #endif /* ** Some of the testcase() macros in this file are problematic for gcov ** in that they generate false-miss errors randomly. This is a gcov problem, ** not a problem in this case. But to work around it, we disable the ** problematic test cases for production builds. */ #define json_testcase(X) /* Objects */ typedef struct JsonString JsonString; typedef struct JsonNode JsonNode; typedef struct JsonParse JsonParse; /* An instance of this object represents a JSON string ** under construction. Really, this is a generic string accumulator |
︙ | ︙ | |||
146 147 148 149 150 151 152 153 154 | /* A single node of parsed JSON */ struct JsonNode { u8 eType; /* One of the JSON_ type values */ u8 jnFlags; /* JNODE flags */ u32 n; /* Bytes of content, or number of sub-nodes */ union { | > | | | | | | 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 | /* A single node of parsed JSON */ struct JsonNode { u8 eType; /* One of the JSON_ type values */ u8 jnFlags; /* JNODE flags */ u8 eU; /* Which union element to use */ u32 n; /* Bytes of content, or number of sub-nodes */ union { const char *zJContent; /* 1: Content for INT, REAL, and STRING */ u32 iAppend; /* 2: More terms for ARRAY and OBJECT */ u32 iKey; /* 3: Key for ARRAY objects in json_tree() */ u32 iReplace; /* 4: Replacement content for JNODE_REPLACE */ JsonNode *pPatch; /* 5: Node chain of patch for JNODE_PATCH */ } u; }; /* A completely parsed JSON string */ struct JsonParse { u32 nNode; /* Number of slots of aNode[] used */ |
︙ | ︙ | |||
250 251 252 253 254 255 256 257 258 259 260 261 262 263 | p->nAlloc = nTotal; return SQLITE_OK; } /* Append N bytes from zIn onto the end of the JsonString string. */ static void jsonAppendRaw(JsonString *p, const char *zIn, u32 N){ if( (N+p->nUsed >= p->nAlloc) && jsonGrow(p,N)!=0 ) return; memcpy(p->zBuf+p->nUsed, zIn, N); p->nUsed += N; } /* Append formatted text (not to exceed N bytes) to the JsonString. */ | > | 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 | p->nAlloc = nTotal; return SQLITE_OK; } /* Append N bytes from zIn onto the end of the JsonString string. */ static void jsonAppendRaw(JsonString *p, const char *zIn, u32 N){ if( N==0 ) return; if( (N+p->nUsed >= p->nAlloc) && jsonGrow(p,N)!=0 ) return; memcpy(p->zBuf+p->nUsed, zIn, N); p->nUsed += N; } /* Append formatted text (not to exceed N bytes) to the JsonString. */ |
︙ | ︙ | |||
290 291 292 293 294 295 296 | /* Append the N-byte string in zIn to the end of the JsonString string ** under construction. Enclose the string in "..." and escape ** any double-quotes or backslash characters contained within the ** string. */ static void jsonAppendString(JsonString *p, const char *zIn, u32 N){ u32 i; | | | 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 | /* Append the N-byte string in zIn to the end of the JsonString string ** under construction. Enclose the string in "..." and escape ** any double-quotes or backslash characters contained within the ** string. */ static void jsonAppendString(JsonString *p, const char *zIn, u32 N){ u32 i; if( zIn==0 || ((N+p->nUsed+2 >= p->nAlloc) && jsonGrow(p,N+2)!=0) ) return; p->zBuf[p->nUsed++] = '"'; for(i=0; i<N; i++){ unsigned char c = ((unsigned const char*)zIn)[i]; if( c=='"' || c=='\\' ){ json_simple_escape: if( (p->nUsed+N+3-i > p->nAlloc) && jsonGrow(p,N+3-i)!=0 ) return; p->zBuf[p->nUsed++] = '\\'; |
︙ | ︙ | |||
429 430 431 432 433 434 435 436 | ** the number of JsonNode objects that are encoded. */ static void jsonRenderNode( JsonNode *pNode, /* The node to render */ JsonString *pOut, /* Write JSON here */ sqlite3_value **aReplace /* Replacement values */ ){ if( pNode->jnFlags & (JNODE_REPLACE|JNODE_PATCH) ){ | > | > > > | > > > | 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 | ** the number of JsonNode objects that are encoded. */ static void jsonRenderNode( JsonNode *pNode, /* The node to render */ JsonString *pOut, /* Write JSON here */ sqlite3_value **aReplace /* Replacement values */ ){ assert( pNode!=0 ); if( pNode->jnFlags & (JNODE_REPLACE|JNODE_PATCH) ){ if( (pNode->jnFlags & JNODE_REPLACE)!=0 && ALWAYS(aReplace!=0) ){ assert( pNode->eU==4 ); jsonAppendValue(pOut, aReplace[pNode->u.iReplace]); return; } assert( pNode->eU==5 ); pNode = pNode->u.pPatch; } switch( pNode->eType ){ default: { assert( pNode->eType==JSON_NULL ); jsonAppendRaw(pOut, "null", 4); break; } case JSON_TRUE: { jsonAppendRaw(pOut, "true", 4); break; } case JSON_FALSE: { jsonAppendRaw(pOut, "false", 5); break; } case JSON_STRING: { if( pNode->jnFlags & JNODE_RAW ){ assert( pNode->eU==1 ); jsonAppendString(pOut, pNode->u.zJContent, pNode->n); break; } /* no break */ deliberate_fall_through } case JSON_REAL: case JSON_INT: { assert( pNode->eU==1 ); jsonAppendRaw(pOut, pNode->u.zJContent, pNode->n); break; } case JSON_ARRAY: { u32 j = 1; jsonAppendChar(pOut, '['); for(;;){ while( j<=pNode->n ){ if( (pNode[j].jnFlags & JNODE_REMOVE)==0 ){ jsonAppendSeparator(pOut); jsonRenderNode(&pNode[j], pOut, aReplace); } j += jsonNodeSize(&pNode[j]); } if( (pNode->jnFlags & JNODE_APPEND)==0 ) break; assert( pNode->eU==2 ); pNode = &pNode[pNode->u.iAppend]; j = 1; } jsonAppendChar(pOut, ']'); break; } case JSON_OBJECT: { u32 j = 1; jsonAppendChar(pOut, '{'); for(;;){ while( j<=pNode->n ){ if( (pNode[j+1].jnFlags & JNODE_REMOVE)==0 ){ jsonAppendSeparator(pOut); jsonRenderNode(&pNode[j], pOut, aReplace); jsonAppendChar(pOut, ':'); jsonRenderNode(&pNode[j+1], pOut, aReplace); } j += 1 + jsonNodeSize(&pNode[j+1]); } if( (pNode->jnFlags & JNODE_APPEND)==0 ) break; assert( pNode->eU==2 ); pNode = &pNode[pNode->u.iAppend]; j = 1; } jsonAppendChar(pOut, '}'); break; } } |
︙ | ︙ | |||
517 518 519 520 521 522 523 524 525 526 527 528 529 530 | ){ JsonString s; jsonInit(&s, pCtx); jsonRenderNode(pNode, &s, aReplace); jsonResult(&s); sqlite3_result_subtype(pCtx, JSON_SUBTYPE); } /* ** Make the JsonNode the return value of the function. */ static void jsonReturn( JsonNode *pNode, /* Node to return */ sqlite3_context *pCtx, /* Return value for this function */ | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | ){ JsonString s; jsonInit(&s, pCtx); jsonRenderNode(pNode, &s, aReplace); jsonResult(&s); sqlite3_result_subtype(pCtx, JSON_SUBTYPE); } /* ** Translate a single byte of Hex into an integer. ** This routine only works if h really is a valid hexadecimal ** character: 0..9a..fA..F */ static u8 jsonHexToInt(int h){ assert( (h>='0' && h<='9') || (h>='a' && h<='f') || (h>='A' && h<='F') ); #ifdef SQLITE_EBCDIC h += 9*(1&~(h>>4)); #else h += 9*(1&(h>>6)); #endif return (u8)(h & 0xf); } /* ** Convert a 4-byte hex string into an integer */ static u32 jsonHexToInt4(const char *z){ u32 v; assert( safe_isxdigit(z[0]) ); assert( safe_isxdigit(z[1]) ); assert( safe_isxdigit(z[2]) ); assert( safe_isxdigit(z[3]) ); v = (jsonHexToInt(z[0])<<12) + (jsonHexToInt(z[1])<<8) + (jsonHexToInt(z[2])<<4) + jsonHexToInt(z[3]); return v; } /* ** Make the JsonNode the return value of the function. */ static void jsonReturn( JsonNode *pNode, /* Node to return */ sqlite3_context *pCtx, /* Return value for this function */ |
︙ | ︙ | |||
542 543 544 545 546 547 548 | } case JSON_FALSE: { sqlite3_result_int(pCtx, 0); break; } case JSON_INT: { sqlite3_int64 i = 0; | | > > | 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 | } case JSON_FALSE: { sqlite3_result_int(pCtx, 0); break; } case JSON_INT: { sqlite3_int64 i = 0; const char *z; assert( pNode->eU==1 ); z = pNode->u.zJContent; if( z[0]=='-' ){ z++; } while( z[0]>='0' && z[0]<='9' ){ unsigned v = *(z++) - '0'; if( i>=LARGEST_INT64/10 ){ if( i>LARGEST_INT64/10 ) goto int_as_real; if( z[0]>='0' && z[0]<='9' ) goto int_as_real; if( v==9 ) goto int_as_real; |
︙ | ︙ | |||
565 566 567 568 569 570 571 | } i = i*10 + v; } if( pNode->u.zJContent[0]=='-' ){ i = -i; } sqlite3_result_int64(pCtx, i); int_done: break; | | | > > > > > | > > | < < | < < < < < > > > > > > > > > > > > > > > | | | > | 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 | } i = i*10 + v; } if( pNode->u.zJContent[0]=='-' ){ i = -i; } sqlite3_result_int64(pCtx, i); int_done: break; int_as_real: ; /* no break */ deliberate_fall_through } case JSON_REAL: { double r; #ifdef SQLITE_AMALGAMATION const char *z; assert( pNode->eU==1 ); z = pNode->u.zJContent; sqlite3AtoF(z, &r, sqlite3Strlen30(z), SQLITE_UTF8); #else assert( pNode->eU==1 ); r = strtod(pNode->u.zJContent, 0); #endif sqlite3_result_double(pCtx, r); break; } case JSON_STRING: { #if 0 /* Never happens because JNODE_RAW is only set by json_set(), ** json_insert() and json_replace() and those routines do not ** call jsonReturn() */ if( pNode->jnFlags & JNODE_RAW ){ assert( pNode->eU==1 ); sqlite3_result_text(pCtx, pNode->u.zJContent, pNode->n, SQLITE_TRANSIENT); }else #endif assert( (pNode->jnFlags & JNODE_RAW)==0 ); if( (pNode->jnFlags & JNODE_ESCAPE)==0 ){ /* JSON formatted without any backslash-escapes */ assert( pNode->eU==1 ); sqlite3_result_text(pCtx, pNode->u.zJContent+1, pNode->n-2, SQLITE_TRANSIENT); }else{ /* Translate JSON formatted string into raw text */ u32 i; u32 n = pNode->n; const char *z; char *zOut; u32 j; assert( pNode->eU==1 ); z = pNode->u.zJContent; zOut = sqlite3_malloc( n+1 ); if( zOut==0 ){ sqlite3_result_error_nomem(pCtx); break; } for(i=1, j=0; i<n-1; i++){ char c = z[i]; if( c!='\\' ){ zOut[j++] = c; }else{ c = z[++i]; if( c=='u' ){ u32 v = jsonHexToInt4(z+i+1); i += 4; if( v==0 ) break; if( v<=0x7f ){ zOut[j++] = (char)v; }else if( v<=0x7ff ){ zOut[j++] = (char)(0xc0 | (v>>6)); zOut[j++] = 0x80 | (v&0x3f); }else{ u32 vlo; if( (v&0xfc00)==0xd800 && i<n-6 && z[i+1]=='\\' && z[i+2]=='u' && ((vlo = jsonHexToInt4(z+i+3))&0xfc00)==0xdc00 ){ /* We have a surrogate pair */ v = ((v&0x3ff)<<10) + (vlo&0x3ff) + 0x10000; i += 6; zOut[j++] = 0xf0 | (v>>18); zOut[j++] = 0x80 | ((v>>12)&0x3f); zOut[j++] = 0x80 | ((v>>6)&0x3f); zOut[j++] = 0x80 | (v&0x3f); }else{ zOut[j++] = 0xe0 | (v>>12); zOut[j++] = 0x80 | ((v>>6)&0x3f); zOut[j++] = 0x80 | (v&0x3f); } } }else{ if( c=='b' ){ c = '\b'; }else if( c=='f' ){ c = '\f'; }else if( c=='n' ){ |
︙ | ︙ | |||
687 688 689 690 691 692 693 | const char *zContent /* Content */ ){ u32 nNew; JsonNode *pNew; assert( pParse->nNode>=pParse->nAlloc ); if( pParse->oom ) return -1; nNew = pParse->nAlloc*2 + 10; | | | 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 | const char *zContent /* Content */ ){ u32 nNew; JsonNode *pNew; assert( pParse->nNode>=pParse->nAlloc ); if( pParse->oom ) return -1; nNew = pParse->nAlloc*2 + 10; pNew = sqlite3_realloc64(pParse->aNode, sizeof(JsonNode)*nNew); if( pNew==0 ){ pParse->oom = 1; return -1; } pParse->nAlloc = nNew; pParse->aNode = pNew; assert( pParse->nNode<pParse->nAlloc ); |
︙ | ︙ | |||
710 711 712 713 714 715 716 | static int jsonParseAddNode( JsonParse *pParse, /* Append the node to this object */ u32 eType, /* Node type */ u32 n, /* Content size or sub-node count */ const char *zContent /* Content */ ){ JsonNode *p; | | > | 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 | static int jsonParseAddNode( JsonParse *pParse, /* Append the node to this object */ u32 eType, /* Node type */ u32 n, /* Content size or sub-node count */ const char *zContent /* Content */ ){ JsonNode *p; if( pParse->aNode==0 || pParse->nNode>=pParse->nAlloc ){ return jsonParseAddNodeExpand(pParse, eType, n, zContent); } p = &pParse->aNode[pParse->nNode]; p->eType = (u8)eType; p->jnFlags = 0; VVA( p->eU = zContent ? 1 : 0 ); p->n = n; p->u.zJContent = zContent; return pParse->nNode++; } /* ** Return true if z[] begins with 4 (or more) hexadecimal digits |
︙ | ︙ | |||
783 784 785 786 787 788 789 790 791 792 793 794 795 796 | } pParse->aNode[iThis].n = pParse->nNode - (u32)iThis - 1; return j+1; }else if( c=='[' ){ /* Parse array */ iThis = jsonParseAddNode(pParse, JSON_ARRAY, 0, 0); if( iThis<0 ) return -1; for(j=i+1;;j++){ while( safe_isspace(z[j]) ){ j++; } if( ++pParse->iDepth > JSON_MAX_DEPTH ) return -1; x = jsonParseValue(pParse, j); pParse->iDepth--; if( x<0 ){ if( x==(-3) && pParse->nNode==(u32)iThis+1 ) return j+1; | > | 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 | } pParse->aNode[iThis].n = pParse->nNode - (u32)iThis - 1; return j+1; }else if( c=='[' ){ /* Parse array */ iThis = jsonParseAddNode(pParse, JSON_ARRAY, 0, 0); if( iThis<0 ) return -1; memset(&pParse->aNode[iThis].u, 0, sizeof(pParse->aNode[iThis].u)); for(j=i+1;;j++){ while( safe_isspace(z[j]) ){ j++; } if( ++pParse->iDepth > JSON_MAX_DEPTH ) return -1; x = jsonParseValue(pParse, j); pParse->iDepth--; if( x<0 ){ if( x==(-3) && pParse->nNode==(u32)iThis+1 ) return j+1; |
︙ | ︙ | |||
961 962 963 964 965 966 967 | /* ** Compute the parentage of all nodes in a completed parse. */ static int jsonParseFindParents(JsonParse *pParse){ u32 *aUp; assert( pParse->aUp==0 ); | | | 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 | /* ** Compute the parentage of all nodes in a completed parse. */ static int jsonParseFindParents(JsonParse *pParse){ u32 *aUp; assert( pParse->aUp==0 ); aUp = pParse->aUp = sqlite3_malloc64( sizeof(u32)*pParse->nNode ); if( aUp==0 ){ pParse->oom = 1; return SQLITE_NOMEM; } jsonParseFillInParentage(pParse, 0, 0); return SQLITE_OK; } |
︙ | ︙ | |||
1023 1024 1025 1026 1027 1028 1029 | } } if( pMatch ){ pMatch->nErr = 0; pMatch->iHold = iMaxHold+1; return pMatch; } | | | 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 | } } if( pMatch ){ pMatch->nErr = 0; pMatch->iHold = iMaxHold+1; return pMatch; } p = sqlite3_malloc64( sizeof(*p) + nJson + 1 ); if( p==0 ){ sqlite3_result_error_nomem(pCtx); return 0; } memset(p, 0, sizeof(*p)); p->zJson = (char*)&p[1]; memcpy((char*)p->zJson, zJson, nJson+1); |
︙ | ︙ | |||
1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 | } /* ** Compare the OBJECT label at pNode against zKey,nKey. Return true on ** a match. */ static int jsonLabelCompare(JsonNode *pNode, const char *zKey, u32 nKey){ if( pNode->jnFlags & JNODE_RAW ){ if( pNode->n!=nKey ) return 0; return strncmp(pNode->u.zJContent, zKey, nKey)==0; }else{ if( pNode->n!=nKey+2 ) return 0; return strncmp(pNode->u.zJContent+1, zKey, nKey)==0; } | > | 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 | } /* ** Compare the OBJECT label at pNode against zKey,nKey. Return true on ** a match. */ static int jsonLabelCompare(JsonNode *pNode, const char *zKey, u32 nKey){ assert( pNode->eU==1 ); if( pNode->jnFlags & JNODE_RAW ){ if( pNode->n!=nKey ) return 0; return strncmp(pNode->u.zJContent, zKey, nKey)==0; }else{ if( pNode->n!=nKey+2 ) return 0; return strncmp(pNode->u.zJContent+1, zKey, nKey)==0; } |
︙ | ︙ | |||
1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 | int *pApnd, /* Append nodes to complete path if not NULL */ const char **pzErr /* Make *pzErr point to any syntax error in zPath */ ){ u32 i, j, nKey; const char *zKey; JsonNode *pRoot = &pParse->aNode[iRoot]; if( zPath[0]==0 ) return pRoot; if( zPath[0]=='.' ){ if( pRoot->eType!=JSON_OBJECT ) return 0; zPath++; if( zPath[0]=='"' ){ zKey = zPath + 1; for(i=1; zPath[i] && zPath[i]!='"'; i++){} nKey = i-1; | > | 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 | int *pApnd, /* Append nodes to complete path if not NULL */ const char **pzErr /* Make *pzErr point to any syntax error in zPath */ ){ u32 i, j, nKey; const char *zKey; JsonNode *pRoot = &pParse->aNode[iRoot]; if( zPath[0]==0 ) return pRoot; if( pRoot->jnFlags & JNODE_REPLACE ) return 0; if( zPath[0]=='.' ){ if( pRoot->eType!=JSON_OBJECT ) return 0; zPath++; if( zPath[0]=='"' ){ zKey = zPath + 1; for(i=1; zPath[i] && zPath[i]!='"'; i++){} nKey = i-1; |
︙ | ︙ | |||
1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 | if( jsonLabelCompare(pRoot+j, zKey, nKey) ){ return jsonLookupStep(pParse, iRoot+j+1, &zPath[i], pApnd, pzErr); } j++; j += jsonNodeSize(&pRoot[j]); } if( (pRoot->jnFlags & JNODE_APPEND)==0 ) break; iRoot += pRoot->u.iAppend; pRoot = &pParse->aNode[iRoot]; j = 1; } if( pApnd ){ u32 iStart, iLabel; JsonNode *pNode; iStart = jsonParseAddNode(pParse, JSON_OBJECT, 2, 0); | > | > > | < > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | > > > > > > > > > | 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 | if( jsonLabelCompare(pRoot+j, zKey, nKey) ){ return jsonLookupStep(pParse, iRoot+j+1, &zPath[i], pApnd, pzErr); } j++; j += jsonNodeSize(&pRoot[j]); } if( (pRoot->jnFlags & JNODE_APPEND)==0 ) break; assert( pRoot->eU==2 ); iRoot += pRoot->u.iAppend; pRoot = &pParse->aNode[iRoot]; j = 1; } if( pApnd ){ u32 iStart, iLabel; JsonNode *pNode; iStart = jsonParseAddNode(pParse, JSON_OBJECT, 2, 0); iLabel = jsonParseAddNode(pParse, JSON_STRING, nKey, zKey); zPath += i; pNode = jsonLookupAppend(pParse, zPath, pApnd, pzErr); if( pParse->oom ) return 0; if( pNode ){ pRoot = &pParse->aNode[iRoot]; assert( pRoot->eU==0 ); pRoot->u.iAppend = iStart - iRoot; pRoot->jnFlags |= JNODE_APPEND; VVA( pRoot->eU = 2 ); pParse->aNode[iLabel].jnFlags |= JNODE_RAW; } return pNode; } }else if( zPath[0]=='[' ){ i = 0; j = 1; while( safe_isdigit(zPath[j]) ){ i = i*10 + zPath[j] - '0'; j++; } if( j<2 || zPath[j]!=']' ){ if( zPath[1]=='#' ){ JsonNode *pBase = pRoot; int iBase = iRoot; if( pRoot->eType!=JSON_ARRAY ) return 0; for(;;){ while( j<=pBase->n ){ if( (pBase[j].jnFlags & JNODE_REMOVE)==0 ) i++; j += jsonNodeSize(&pBase[j]); } if( (pBase->jnFlags & JNODE_APPEND)==0 ) break; assert( pBase->eU==2 ); iBase += pBase->u.iAppend; pBase = &pParse->aNode[iBase]; j = 1; } j = 2; if( zPath[2]=='-' && safe_isdigit(zPath[3]) ){ unsigned int x = 0; j = 3; do{ x = x*10 + zPath[j] - '0'; j++; }while( safe_isdigit(zPath[j]) ); if( x>i ) return 0; i -= x; } if( zPath[j]!=']' ){ *pzErr = zPath; return 0; } }else{ *pzErr = zPath; return 0; } } if( pRoot->eType!=JSON_ARRAY ) return 0; zPath += j + 1; j = 1; for(;;){ while( j<=pRoot->n && (i>0 || (pRoot[j].jnFlags & JNODE_REMOVE)!=0) ){ if( (pRoot[j].jnFlags & JNODE_REMOVE)==0 ) i--; j += jsonNodeSize(&pRoot[j]); } if( (pRoot->jnFlags & JNODE_APPEND)==0 ) break; assert( pRoot->eU==2 ); iRoot += pRoot->u.iAppend; pRoot = &pParse->aNode[iRoot]; j = 1; } if( j<=pRoot->n ){ return jsonLookupStep(pParse, iRoot+j, zPath, pApnd, pzErr); } if( i==0 && pApnd ){ u32 iStart; JsonNode *pNode; iStart = jsonParseAddNode(pParse, JSON_ARRAY, 1, 0); pNode = jsonLookupAppend(pParse, zPath, pApnd, pzErr); if( pParse->oom ) return 0; if( pNode ){ pRoot = &pParse->aNode[iRoot]; assert( pRoot->eU==0 ); pRoot->u.iAppend = iStart - iRoot; pRoot->jnFlags |= JNODE_APPEND; VVA( pRoot->eU = 2 ); } return pNode; } }else{ *pzErr = zPath; } return 0; |
︙ | ︙ | |||
1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 | assert( x.aNode[i].eType==JSON_STRING ); zType = "label"; }else{ zType = jsonType[x.aNode[i].eType]; } jsonPrintf(100, &s,"node %3u: %7s n=%-4d up=%-4d", i, zType, x.aNode[i].n, x.aUp[i]); if( x.aNode[i].u.zJContent!=0 ){ jsonAppendRaw(&s, " ", 1); jsonAppendRaw(&s, x.aNode[i].u.zJContent, x.aNode[i].n); } jsonAppendRaw(&s, "\n", 1); } jsonParseReset(&x); jsonResult(&s); } | > > > > | 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 | assert( x.aNode[i].eType==JSON_STRING ); zType = "label"; }else{ zType = jsonType[x.aNode[i].eType]; } jsonPrintf(100, &s,"node %3u: %7s n=%-4d up=%-4d", i, zType, x.aNode[i].n, x.aUp[i]); assert( x.aNode[i].eU==0 || x.aNode[i].eU==1 ); if( x.aNode[i].u.zJContent!=0 ){ assert( x.aNode[i].eU==1 ); jsonAppendRaw(&s, " ", 1); jsonAppendRaw(&s, x.aNode[i].u.zJContent, x.aNode[i].n); }else{ assert( x.aNode[i].eU==0 ); } jsonAppendRaw(&s, "\n", 1); } jsonParseReset(&x); jsonResult(&s); } |
︙ | ︙ | |||
1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 | } iRoot = iTarget; for(i=1; i<pPatch->n; i += jsonNodeSize(&pPatch[i+1])+1){ u32 nKey; const char *zKey; assert( pPatch[i].eType==JSON_STRING ); assert( pPatch[i].jnFlags & JNODE_LABEL ); nKey = pPatch[i].n; zKey = pPatch[i].u.zJContent; assert( (pPatch[i].jnFlags & JNODE_RAW)==0 ); for(j=1; j<pTarget->n; j += jsonNodeSize(&pTarget[j+1])+1 ){ assert( pTarget[j].eType==JSON_STRING ); assert( pTarget[j].jnFlags & JNODE_LABEL ); assert( (pPatch[i].jnFlags & JNODE_RAW)==0 ); if( pTarget[j].n==nKey && strncmp(pTarget[j].u.zJContent,zKey,nKey)==0 ){ if( pTarget[j+1].jnFlags & (JNODE_REMOVE|JNODE_PATCH) ) break; if( pPatch[i+1].eType==JSON_NULL ){ pTarget[j+1].jnFlags |= JNODE_REMOVE; }else{ JsonNode *pNew = jsonMergePatch(pParse, iTarget+j+1, &pPatch[i+1]); if( pNew==0 ) return 0; pTarget = &pParse->aNode[iTarget]; if( pNew!=&pTarget[j+1] ){ pTarget[j+1].u.pPatch = pNew; pTarget[j+1].jnFlags |= JNODE_PATCH; } } break; } } if( j>=pTarget->n && pPatch[i+1].eType!=JSON_NULL ){ int iStart, iPatch; iStart = jsonParseAddNode(pParse, JSON_OBJECT, 2, 0); jsonParseAddNode(pParse, JSON_STRING, nKey, zKey); iPatch = jsonParseAddNode(pParse, JSON_TRUE, 0, 0); if( pParse->oom ) return 0; jsonRemoveAllNulls(pPatch); pTarget = &pParse->aNode[iTarget]; pParse->aNode[iRoot].jnFlags |= JNODE_APPEND; pParse->aNode[iRoot].u.iAppend = iStart - iRoot; iRoot = iStart; pParse->aNode[iPatch].jnFlags |= JNODE_PATCH; pParse->aNode[iPatch].u.pPatch = &pPatch[i+1]; } } return pTarget; } | > > > > > > > > > > > > | 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 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 | } iRoot = iTarget; for(i=1; i<pPatch->n; i += jsonNodeSize(&pPatch[i+1])+1){ u32 nKey; const char *zKey; assert( pPatch[i].eType==JSON_STRING ); assert( pPatch[i].jnFlags & JNODE_LABEL ); assert( pPatch[i].eU==1 ); nKey = pPatch[i].n; zKey = pPatch[i].u.zJContent; assert( (pPatch[i].jnFlags & JNODE_RAW)==0 ); for(j=1; j<pTarget->n; j += jsonNodeSize(&pTarget[j+1])+1 ){ assert( pTarget[j].eType==JSON_STRING ); assert( pTarget[j].jnFlags & JNODE_LABEL ); assert( (pPatch[i].jnFlags & JNODE_RAW)==0 ); if( pTarget[j].n==nKey && strncmp(pTarget[j].u.zJContent,zKey,nKey)==0 ){ if( pTarget[j+1].jnFlags & (JNODE_REMOVE|JNODE_PATCH) ) break; if( pPatch[i+1].eType==JSON_NULL ){ pTarget[j+1].jnFlags |= JNODE_REMOVE; }else{ JsonNode *pNew = jsonMergePatch(pParse, iTarget+j+1, &pPatch[i+1]); if( pNew==0 ) return 0; pTarget = &pParse->aNode[iTarget]; if( pNew!=&pTarget[j+1] ){ assert( pTarget[j+1].eU==0 || pTarget[j+1].eU==1 || pTarget[j+1].eU==2 ); testcase( pTarget[j+1].eU==1 ); testcase( pTarget[j+1].eU==2 ); VVA( pTarget[j+1].eU = 5 ); pTarget[j+1].u.pPatch = pNew; pTarget[j+1].jnFlags |= JNODE_PATCH; } } break; } } if( j>=pTarget->n && pPatch[i+1].eType!=JSON_NULL ){ int iStart, iPatch; iStart = jsonParseAddNode(pParse, JSON_OBJECT, 2, 0); jsonParseAddNode(pParse, JSON_STRING, nKey, zKey); iPatch = jsonParseAddNode(pParse, JSON_TRUE, 0, 0); if( pParse->oom ) return 0; jsonRemoveAllNulls(pPatch); pTarget = &pParse->aNode[iTarget]; assert( pParse->aNode[iRoot].eU==0 || pParse->aNode[iRoot].eU==2 ); testcase( pParse->aNode[iRoot].eU==2 ); pParse->aNode[iRoot].jnFlags |= JNODE_APPEND; VVA( pParse->aNode[iRoot].eU = 2 ); pParse->aNode[iRoot].u.iAppend = iStart - iRoot; iRoot = iStart; assert( pParse->aNode[iPatch].eU==0 ); VVA( pParse->aNode[iPatch].eU = 5 ); pParse->aNode[iPatch].jnFlags |= JNODE_PATCH; pParse->aNode[iPatch].u.pPatch = &pPatch[i+1]; } } return pTarget; } |
︙ | ︙ | |||
1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 | if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return; assert( x.nNode ); for(i=1; i<(u32)argc; i+=2){ zPath = (const char*)sqlite3_value_text(argv[i]); pNode = jsonLookup(&x, zPath, 0, ctx); if( x.nErr ) goto replace_err; if( pNode ){ pNode->jnFlags |= (u8)JNODE_REPLACE; pNode->u.iReplace = i + 1; } } if( x.aNode[0].jnFlags & JNODE_REPLACE ){ sqlite3_result_value(ctx, argv[x.aNode[0].u.iReplace]); }else{ jsonReturnJson(x.aNode, ctx, argv); } replace_err: jsonParseReset(&x); } | > > > > | 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 | if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return; assert( x.nNode ); for(i=1; i<(u32)argc; i+=2){ zPath = (const char*)sqlite3_value_text(argv[i]); pNode = jsonLookup(&x, zPath, 0, ctx); if( x.nErr ) goto replace_err; if( pNode ){ assert( pNode->eU==0 || pNode->eU==1 || pNode->eU==4 ); json_testcase( pNode->eU!=0 && pNode->eU!=1 ); pNode->jnFlags |= (u8)JNODE_REPLACE; VVA( pNode->eU = 4 ); pNode->u.iReplace = i + 1; } } if( x.aNode[0].jnFlags & JNODE_REPLACE ){ assert( x.aNode[0].eU==4 ); sqlite3_result_value(ctx, argv[x.aNode[0].u.iReplace]); }else{ jsonReturnJson(x.aNode, ctx, argv); } replace_err: jsonParseReset(&x); } |
︙ | ︙ | |||
1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 | pNode = jsonLookup(&x, zPath, &bApnd, ctx); if( x.oom ){ sqlite3_result_error_nomem(ctx); goto jsonSetDone; }else if( x.nErr ){ goto jsonSetDone; }else if( pNode && (bApnd || bIsSet) ){ pNode->jnFlags |= (u8)JNODE_REPLACE; pNode->u.iReplace = i + 1; } } if( x.aNode[0].jnFlags & JNODE_REPLACE ){ sqlite3_result_value(ctx, argv[x.aNode[0].u.iReplace]); }else{ jsonReturnJson(x.aNode, ctx, argv); } jsonSetDone: jsonParseReset(&x); } | > > > > | 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 | pNode = jsonLookup(&x, zPath, &bApnd, ctx); if( x.oom ){ sqlite3_result_error_nomem(ctx); goto jsonSetDone; }else if( x.nErr ){ goto jsonSetDone; }else if( pNode && (bApnd || bIsSet) ){ json_testcase( pNode->eU!=0 && pNode->eU!=1 && pNode->eU!=4 ); assert( pNode->eU!=3 || pNode->eU!=5 ); VVA( pNode->eU = 4 ); pNode->jnFlags |= (u8)JNODE_REPLACE; pNode->u.iReplace = i + 1; } } if( x.aNode[0].jnFlags & JNODE_REPLACE ){ assert( x.aNode[0].eU==4 ); sqlite3_result_value(ctx, argv[x.aNode[0].u.iReplace]); }else{ jsonReturnJson(x.aNode, ctx, argv); } jsonSetDone: jsonParseReset(&x); } |
︙ | ︙ | |||
1815 1816 1817 1818 1819 1820 1821 | JsonString *pStr; UNUSED_PARAM(argc); pStr = (JsonString*)sqlite3_aggregate_context(ctx, sizeof(*pStr)); if( pStr ){ if( pStr->zBuf==0 ){ jsonInit(pStr, ctx); jsonAppendChar(pStr, '['); | | < > | 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 | JsonString *pStr; UNUSED_PARAM(argc); pStr = (JsonString*)sqlite3_aggregate_context(ctx, sizeof(*pStr)); if( pStr ){ if( pStr->zBuf==0 ){ jsonInit(pStr, ctx); jsonAppendChar(pStr, '['); }else if( pStr->nUsed>1 ){ jsonAppendChar(pStr, ','); } pStr->pCtx = ctx; jsonAppendValue(pStr, argv[0]); } } static void jsonArrayCompute(sqlite3_context *ctx, int isFinal){ JsonString *pStr; pStr = (JsonString*)sqlite3_aggregate_context(ctx, 0); if( pStr ){ |
︙ | ︙ | |||
1863 1864 1865 1866 1867 1868 1869 | ** text through that comma. */ static void jsonGroupInverse( sqlite3_context *ctx, int argc, sqlite3_value **argv ){ | | > > < | | | > > > > | | > > > > | 2018 2019 2020 2021 2022 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 | ** text through that comma. */ static void jsonGroupInverse( sqlite3_context *ctx, int argc, sqlite3_value **argv ){ unsigned int i; int inStr = 0; int nNest = 0; char *z; char c; JsonString *pStr; UNUSED_PARAM(argc); UNUSED_PARAM(argv); pStr = (JsonString*)sqlite3_aggregate_context(ctx, 0); #ifdef NEVER /* pStr is always non-NULL since jsonArrayStep() or jsonObjectStep() will ** always have been called to initalize it */ if( NEVER(!pStr) ) return; #endif z = pStr->zBuf; for(i=1; i<pStr->nUsed && ((c = z[i])!=',' || inStr || nNest); i++){ if( c=='"' ){ inStr = !inStr; }else if( c=='\\' ){ i++; }else if( !inStr ){ if( c=='{' || c=='[' ) nNest++; if( c=='}' || c==']' ) nNest--; } } if( i<pStr->nUsed ){ pStr->nUsed -= i; memmove(&z[1], &z[i+1], (size_t)pStr->nUsed-1); z[pStr->nUsed] = 0; }else{ pStr->nUsed = 1; } } #else # define jsonGroupInverse 0 #endif /* |
︙ | ︙ | |||
1911 1912 1913 1914 1915 1916 1917 | u32 n; UNUSED_PARAM(argc); pStr = (JsonString*)sqlite3_aggregate_context(ctx, sizeof(*pStr)); if( pStr ){ if( pStr->zBuf==0 ){ jsonInit(pStr, ctx); jsonAppendChar(pStr, '{'); | | < > | 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 | u32 n; UNUSED_PARAM(argc); pStr = (JsonString*)sqlite3_aggregate_context(ctx, sizeof(*pStr)); if( pStr ){ if( pStr->zBuf==0 ){ jsonInit(pStr, ctx); jsonAppendChar(pStr, '{'); }else if( pStr->nUsed>1 ){ jsonAppendChar(pStr, ','); } pStr->pCtx = ctx; z = (const char*)sqlite3_value_text(argv[0]); n = (u32)sqlite3_value_bytes(argv[0]); jsonAppendString(pStr, z, n); jsonAppendChar(pStr, ':'); jsonAppendValue(pStr, argv[1]); } } |
︙ | ︙ | |||
2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 | rc = sqlite3_declare_vtab(db, "CREATE TABLE x(key,value,type,atom,id,parent,fullkey,path," "json HIDDEN,root HIDDEN)"); if( rc==SQLITE_OK ){ pNew = *ppVtab = sqlite3_malloc( sizeof(*pNew) ); if( pNew==0 ) return SQLITE_NOMEM; memset(pNew, 0, sizeof(*pNew)); } return rc; } /* destructor for json_each virtual table */ static int jsonEachDisconnect(sqlite3_vtab *pVtab){ sqlite3_free(pVtab); | > | 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 | rc = sqlite3_declare_vtab(db, "CREATE TABLE x(key,value,type,atom,id,parent,fullkey,path," "json HIDDEN,root HIDDEN)"); if( rc==SQLITE_OK ){ pNew = *ppVtab = sqlite3_malloc( sizeof(*pNew) ); if( pNew==0 ) return SQLITE_NOMEM; memset(pNew, 0, sizeof(*pNew)); sqlite3_vtab_config(db, SQLITE_VTAB_INNOCUOUS); } return rc; } /* destructor for json_each virtual table */ static int jsonEachDisconnect(sqlite3_vtab *pVtab){ sqlite3_free(pVtab); |
︙ | ︙ | |||
2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 | p->i++; p->iRowid++; if( p->i<p->iEnd ){ u32 iUp = p->sParse.aUp[p->i]; JsonNode *pUp = &p->sParse.aNode[iUp]; p->eType = pUp->eType; if( pUp->eType==JSON_ARRAY ){ if( iUp==p->i-1 ){ pUp->u.iKey = 0; }else{ pUp->u.iKey++; } } } | > > > | 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 | p->i++; p->iRowid++; if( p->i<p->iEnd ){ u32 iUp = p->sParse.aUp[p->i]; JsonNode *pUp = &p->sParse.aNode[iUp]; p->eType = pUp->eType; if( pUp->eType==JSON_ARRAY ){ assert( pUp->eU==0 || pUp->eU==3 ); json_testcase( pUp->eU==3 ); VVA( pUp->eU = 3 ); if( iUp==p->i-1 ){ pUp->u.iKey = 0; }else{ pUp->u.iKey++; } } } |
︙ | ︙ | |||
2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 | return; } iUp = p->sParse.aUp[i]; jsonEachComputePath(p, pStr, iUp); pNode = &p->sParse.aNode[i]; pUp = &p->sParse.aNode[iUp]; if( pUp->eType==JSON_ARRAY ){ jsonPrintf(30, pStr, "[%d]", pUp->u.iKey); }else{ assert( pUp->eType==JSON_OBJECT ); if( (pNode->jnFlags & JNODE_LABEL)==0 ) pNode--; assert( pNode->eType==JSON_STRING ); assert( pNode->jnFlags & JNODE_LABEL ); jsonPrintf(pNode->n+1, pStr, ".%.*s", pNode->n-2, pNode->u.zJContent+1); } } /* Return the value of a column */ static int jsonEachColumn( sqlite3_vtab_cursor *cur, /* The cursor */ | > > > | 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 | return; } iUp = p->sParse.aUp[i]; jsonEachComputePath(p, pStr, iUp); pNode = &p->sParse.aNode[i]; pUp = &p->sParse.aNode[iUp]; if( pUp->eType==JSON_ARRAY ){ assert( pUp->eU==3 || (pUp->eU==0 && pUp->u.iKey==0) ); testcase( pUp->eU==0 ); jsonPrintf(30, pStr, "[%d]", pUp->u.iKey); }else{ assert( pUp->eType==JSON_OBJECT ); if( (pNode->jnFlags & JNODE_LABEL)==0 ) pNode--; assert( pNode->eType==JSON_STRING ); assert( pNode->jnFlags & JNODE_LABEL ); assert( pNode->eU==1 ); jsonPrintf(pNode->n+1, pStr, ".%.*s", pNode->n-2, pNode->u.zJContent+1); } } /* Return the value of a column */ static int jsonEachColumn( sqlite3_vtab_cursor *cur, /* The cursor */ |
︙ | ︙ | |||
2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 | if( p->i==0 ) break; if( p->eType==JSON_OBJECT ){ jsonReturn(pThis, ctx, 0); }else if( p->eType==JSON_ARRAY ){ u32 iKey; if( p->bRecursive ){ if( p->iRowid==0 ) break; iKey = p->sParse.aNode[p->sParse.aUp[p->i]].u.iKey; }else{ iKey = p->iRowid; } sqlite3_result_int64(ctx, (sqlite3_int64)iKey); } break; | > | 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 | if( p->i==0 ) break; if( p->eType==JSON_OBJECT ){ jsonReturn(pThis, ctx, 0); }else if( p->eType==JSON_ARRAY ){ u32 iKey; if( p->bRecursive ){ if( p->iRowid==0 ) break; assert( p->sParse.aNode[p->sParse.aUp[p->i]].eU==3 ); iKey = p->sParse.aNode[p->sParse.aUp[p->i]].u.iKey; }else{ iKey = p->iRowid; } sqlite3_result_int64(ctx, (sqlite3_int64)iKey); } break; |
︙ | ︙ | |||
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 | jsonAppendRaw(&x, p->zRoot, (int)strlen(p->zRoot)); }else{ jsonAppendChar(&x, '$'); } if( p->eType==JSON_ARRAY ){ jsonPrintf(30, &x, "[%d]", p->iRowid); }else if( p->eType==JSON_OBJECT ){ jsonPrintf(pThis->n, &x, ".%.*s", pThis->n-2, pThis->u.zJContent+1); } } jsonResult(&x); break; } case JEACH_PATH: { if( p->bRecursive ){ JsonString x; jsonInit(&x, ctx); jsonEachComputePath(p, &x, p->sParse.aUp[p->i]); jsonResult(&x); break; } /* For json_each() path and root are the same so fall through ** into the root case */ } default: { const char *zRoot = p->zRoot; if( zRoot==0 ) zRoot = "$"; sqlite3_result_text(ctx, zRoot, -1, SQLITE_STATIC); break; } | > > | 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 | jsonAppendRaw(&x, p->zRoot, (int)strlen(p->zRoot)); }else{ jsonAppendChar(&x, '$'); } if( p->eType==JSON_ARRAY ){ jsonPrintf(30, &x, "[%d]", p->iRowid); }else if( p->eType==JSON_OBJECT ){ assert( pThis->eU==1 ); jsonPrintf(pThis->n, &x, ".%.*s", pThis->n-2, pThis->u.zJContent+1); } } jsonResult(&x); break; } case JEACH_PATH: { if( p->bRecursive ){ JsonString x; jsonInit(&x, ctx); jsonEachComputePath(p, &x, p->sParse.aUp[p->i]); jsonResult(&x); break; } /* For json_each() path and root are the same so fall through ** into the root case */ /* no break */ deliberate_fall_through } default: { const char *zRoot = p->zRoot; if( zRoot==0 ) zRoot = "$"; sqlite3_result_text(ctx, zRoot, -1, SQLITE_STATIC); break; } |
︙ | ︙ | |||
2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 | pConstraint = pIdxInfo->aConstraint; for(i=0; i<pIdxInfo->nConstraint; i++, pConstraint++){ int iCol; int iMask; if( pConstraint->iColumn < JEACH_JSON ) continue; iCol = pConstraint->iColumn - JEACH_JSON; assert( iCol==0 || iCol==1 ); iMask = 1 << iCol; if( pConstraint->usable==0 ){ unusableMask |= iMask; }else if( pConstraint->op==SQLITE_INDEX_CONSTRAINT_EQ ){ aIdx[iCol] = i; idxMask |= iMask; } | > | 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 | pConstraint = pIdxInfo->aConstraint; for(i=0; i<pIdxInfo->nConstraint; i++, pConstraint++){ int iCol; int iMask; if( pConstraint->iColumn < JEACH_JSON ) continue; iCol = pConstraint->iColumn - JEACH_JSON; assert( iCol==0 || iCol==1 ); testcase( iCol==0 ); iMask = 1 << iCol; if( pConstraint->usable==0 ){ unusableMask |= iMask; }else if( pConstraint->op==SQLITE_INDEX_CONSTRAINT_EQ ){ aIdx[iCol] = i; idxMask |= iMask; } |
︙ | ︙ | |||
2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 | } }else{ pNode = p->sParse.aNode; } p->iBegin = p->i = (int)(pNode - p->sParse.aNode); p->eType = pNode->eType; if( p->eType>=JSON_ARRAY ){ pNode->u.iKey = 0; p->iEnd = p->i + pNode->n + 1; if( p->bRecursive ){ p->eType = p->sParse.aNode[p->sParse.aUp[p->i]].eType; if( p->i>0 && (p->sParse.aNode[p->i-1].jnFlags & JNODE_LABEL)!=0 ){ p->i--; } | > > | 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 | } }else{ pNode = p->sParse.aNode; } p->iBegin = p->i = (int)(pNode - p->sParse.aNode); p->eType = pNode->eType; if( p->eType>=JSON_ARRAY ){ assert( pNode->eU==0 ); VVA( pNode->eU = 3 ); pNode->u.iKey = 0; p->iEnd = p->i + pNode->n + 1; if( p->bRecursive ){ p->eType = p->sParse.aNode[p->sParse.aUp[p->i]].eType; if( p->i>0 && (p->sParse.aNode[p->i-1].jnFlags & JNODE_LABEL)!=0 ){ p->i--; } |
︙ | ︙ | |||
2497 2498 2499 2500 2501 2502 2503 2504 | const char *zName; sqlite3_module *pModule; } aMod[] = { { "json_each", &jsonEachModule }, { "json_tree", &jsonTreeModule }, }; #endif for(i=0; i<sizeof(aFunc)/sizeof(aFunc[0]) && rc==SQLITE_OK; i++){ | > > > > | < | | 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 | const char *zName; sqlite3_module *pModule; } aMod[] = { { "json_each", &jsonEachModule }, { "json_tree", &jsonTreeModule }, }; #endif static const int enc = SQLITE_UTF8 | SQLITE_DETERMINISTIC | SQLITE_INNOCUOUS; for(i=0; i<sizeof(aFunc)/sizeof(aFunc[0]) && rc==SQLITE_OK; i++){ rc = sqlite3_create_function(db, aFunc[i].zName, aFunc[i].nArg, enc, (void*)&aFunc[i].flag, aFunc[i].xFunc, 0, 0); } #ifndef SQLITE_OMIT_WINDOWFUNC for(i=0; i<sizeof(aAgg)/sizeof(aAgg[0]) && rc==SQLITE_OK; i++){ rc = sqlite3_create_window_function(db, aAgg[i].zName, aAgg[i].nArg, SQLITE_SUBTYPE | enc, 0, aAgg[i].xStep, aAgg[i].xFinal, aAgg[i].xValue, jsonGroupInverse, 0); } #endif #ifndef SQLITE_OMIT_VIRTUALTABLE for(i=0; i<sizeof(aMod)/sizeof(aMod[0]) && rc==SQLITE_OK; i++){ rc = sqlite3_create_module(db, aMod[i].zName, aMod[i].pModule, 0); |
︙ | ︙ |
Changes to ext/misc/memstat.c.
︙ | ︙ | |||
139 140 141 142 143 144 145 | rc = sqlite3_prepare_v2(pCur->db, "PRAGMA database_list", -1, &pStmt, 0); if( rc ){ sqlite3_finalize(pStmt); return rc; } while( sqlite3_step(pStmt)==SQLITE_ROW ){ char **az, *z; | | | 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 | rc = sqlite3_prepare_v2(pCur->db, "PRAGMA database_list", -1, &pStmt, 0); if( rc ){ sqlite3_finalize(pStmt); return rc; } while( sqlite3_step(pStmt)==SQLITE_ROW ){ char **az, *z; az = sqlite3_realloc64(pCur->azDb, sizeof(char*)*(pCur->nDb+1)); if( az==0 ){ memstatClearSchema(pCur); return SQLITE_NOMEM; } pCur->azDb = az; z = sqlite3_mprintf("%s", sqlite3_column_text(pStmt, 1)); if( z==0 ){ |
︙ | ︙ |
Added ext/misc/memtrace.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 | /* ** 2019-01-21 ** ** 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 an extension that uses the SQLITE_CONFIG_MALLOC ** mechanism to add a tracing layer on top of SQLite. If this extension ** is registered prior to sqlite3_initialize(), it will cause all memory ** allocation activities to be logged on standard output, or to some other ** FILE specified by the initializer. ** ** This file needs to be compiled into the application that uses it. ** ** This extension is used to implement the --memtrace option of the ** command-line shell. */ #include <assert.h> #include <string.h> #include <stdio.h> /* The original memory allocation routines */ static sqlite3_mem_methods memtraceBase; static FILE *memtraceOut; /* Methods that trace memory allocations */ static void *memtraceMalloc(int n){ if( memtraceOut ){ fprintf(memtraceOut, "MEMTRACE: allocate %d bytes\n", memtraceBase.xRoundup(n)); } return memtraceBase.xMalloc(n); } static void memtraceFree(void *p){ if( p==0 ) return; if( memtraceOut ){ fprintf(memtraceOut, "MEMTRACE: free %d bytes\n", memtraceBase.xSize(p)); } memtraceBase.xFree(p); } static void *memtraceRealloc(void *p, int n){ if( p==0 ) return memtraceMalloc(n); if( n==0 ){ memtraceFree(p); return 0; } if( memtraceOut ){ fprintf(memtraceOut, "MEMTRACE: resize %d -> %d bytes\n", memtraceBase.xSize(p), memtraceBase.xRoundup(n)); } return memtraceBase.xRealloc(p, n); } static int memtraceSize(void *p){ return memtraceBase.xSize(p); } static int memtraceRoundup(int n){ return memtraceBase.xRoundup(n); } static int memtraceInit(void *p){ return memtraceBase.xInit(p); } static void memtraceShutdown(void *p){ memtraceBase.xShutdown(p); } /* The substitute memory allocator */ static sqlite3_mem_methods ersaztMethods = { memtraceMalloc, memtraceFree, memtraceRealloc, memtraceSize, memtraceRoundup, memtraceInit, memtraceShutdown, 0 }; /* Begin tracing memory allocations to out. */ int sqlite3MemTraceActivate(FILE *out){ int rc = SQLITE_OK; if( memtraceBase.xMalloc==0 ){ rc = sqlite3_config(SQLITE_CONFIG_GETMALLOC, &memtraceBase); if( rc==SQLITE_OK ){ rc = sqlite3_config(SQLITE_CONFIG_MALLOC, &ersaztMethods); } } memtraceOut = out; return rc; } /* Deactivate memory tracing */ int sqlite3MemTraceDeactivate(void){ int rc = SQLITE_OK; if( memtraceBase.xMalloc!=0 ){ rc = sqlite3_config(SQLITE_CONFIG_MALLOC, &memtraceBase); if( rc==SQLITE_OK ){ memset(&memtraceBase, 0, sizeof(memtraceBase)); } } memtraceOut = 0; return rc; } |
Changes to ext/misc/memvfs.c.
︙ | ︙ | |||
555 556 557 558 559 560 561 562 563 564 565 566 567 568 | sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi ){ int rc = SQLITE_OK; SQLITE_EXTENSION_INIT2(pApi); mem_vfs.pAppData = sqlite3_vfs_find(0); mem_vfs.szOsFile = sizeof(MemFile); rc = sqlite3_vfs_register(&mem_vfs, 1); #ifdef MEMVFS_TEST if( rc==SQLITE_OK ){ rc = sqlite3_auto_extension((void(*)(void))memvfsRegister); } if( rc==SQLITE_OK ){ | > | 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 | sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi ){ int rc = SQLITE_OK; SQLITE_EXTENSION_INIT2(pApi); mem_vfs.pAppData = sqlite3_vfs_find(0); if( mem_vfs.pAppData==0 ) return SQLITE_ERROR; mem_vfs.szOsFile = sizeof(MemFile); rc = sqlite3_vfs_register(&mem_vfs, 1); #ifdef MEMVFS_TEST if( rc==SQLITE_OK ){ rc = sqlite3_auto_extension((void(*)(void))memvfsRegister); } if( rc==SQLITE_OK ){ |
︙ | ︙ |
Changes to ext/misc/mmapwarm.c.
︙ | ︙ | |||
39 40 41 42 43 44 45 | char *zSql = 0; int pgsz = 0; int nTotal = 0; if( 0==sqlite3_get_autocommit(db) ) return SQLITE_MISUSE; /* Open a read-only transaction on the file in question */ | | | 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | char *zSql = 0; int pgsz = 0; int nTotal = 0; if( 0==sqlite3_get_autocommit(db) ) return SQLITE_MISUSE; /* Open a read-only transaction on the file in question */ zSql = sqlite3_mprintf("BEGIN; SELECT * FROM %s%q%ssqlite_schema", (zDb ? "'" : ""), (zDb ? zDb : ""), (zDb ? "'." : "") ); if( zSql==0 ) return SQLITE_NOMEM; rc = sqlite3_exec(db, zSql, 0, 0, 0); sqlite3_free(zSql); /* Find the SQLite page size of the file */ |
︙ | ︙ | |||
101 102 103 104 105 106 107 | rc2 = sqlite3_exec(db, "END", 0, 0, 0); if( rc==SQLITE_OK ) rc = rc2; } return rc; } | < | 101 102 103 104 105 106 107 | rc2 = sqlite3_exec(db, "END", 0, 0, 0); if( rc==SQLITE_OK ) rc = rc2; } return rc; } |
Changes to ext/misc/nextchar.c.
︙ | ︙ | |||
81 82 83 84 85 86 87 | 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; | | | 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 | 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_realloc64(p->aResult, n*sizeof(unsigned int)); if( aNew==0 ){ p->mallocFailed = 1; return; }else{ p->aResult = aNew; p->nAlloc = n; } |
︙ | ︙ | |||
265 266 267 268 269 270 271 | return; } findNextChars(&c); if( c.mallocFailed ){ sqlite3_result_error_nomem(context); }else{ unsigned char *pRes; | | | 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 | return; } findNextChars(&c); if( c.mallocFailed ){ sqlite3_result_error_nomem(context); }else{ unsigned char *pRes; pRes = sqlite3_malloc64( 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]); |
︙ | ︙ | |||
293 294 295 296 297 298 299 | sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi ){ int rc = SQLITE_OK; SQLITE_EXTENSION_INIT2(pApi); (void)pzErrMsg; /* Unused parameter */ | | > | > | > | 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 | 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|SQLITE_INNOCUOUS, 0, nextCharFunc, 0, 0); if( rc==SQLITE_OK ){ rc = sqlite3_create_function(db, "next_char", 4, SQLITE_UTF8|SQLITE_INNOCUOUS, 0, nextCharFunc, 0, 0); } if( rc==SQLITE_OK ){ rc = sqlite3_create_function(db, "next_char", 5, SQLITE_UTF8|SQLITE_INNOCUOUS, 0, nextCharFunc, 0, 0); } return rc; } |
Added ext/misc/noop.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 | /* ** 2020-01-08 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ****************************************************************************** ** ** This SQLite extension implements a noop() function used for testing. ** ** Variants: ** ** noop(X) The default. Deterministic. ** noop_i(X) Deterministic and innocuous. ** noop_do(X) Deterministic and direct-only. ** noop_nd(X) Non-deterministic. */ #include "sqlite3ext.h" SQLITE_EXTENSION_INIT1 #include <assert.h> #include <string.h> /* ** Implementation of the noop() function. ** ** The function returns its argument, unchanged. */ static void noopfunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ assert( argc==1 ); sqlite3_result_value(context, argv[0]); } #ifdef _WIN32 __declspec(dllexport) #endif int sqlite3_noop_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, "noop", 1, SQLITE_UTF8 | SQLITE_DETERMINISTIC, 0, noopfunc, 0, 0); if( rc ) return rc; rc = sqlite3_create_function(db, "noop_i", 1, SQLITE_UTF8 | SQLITE_DETERMINISTIC | SQLITE_INNOCUOUS, 0, noopfunc, 0, 0); if( rc ) return rc; rc = sqlite3_create_function(db, "noop_do", 1, SQLITE_UTF8 | SQLITE_DETERMINISTIC | SQLITE_DIRECTONLY, 0, noopfunc, 0, 0); if( rc ) return rc; rc = sqlite3_create_function(db, "noop_nd", 1, SQLITE_UTF8, 0, noopfunc, 0, 0); return rc; } |
Changes to ext/misc/normalize.c.
︙ | ︙ | |||
282 283 284 285 286 287 288 289 290 291 292 293 294 295 | #define TK_ILLEGAL TK_ERROR #define TK_DOT TK_PUNCT #define TK_INTEGER TK_LITERAL #define TK_FLOAT TK_LITERAL #define TK_VARIABLE TK_LITERAL #define TK_BLOB TK_LITERAL /* ** Return the length (in bytes) of the token that begins at z[0]. ** Store the token type in *tokenType before returning. */ static int sqlite3GetToken(const unsigned char *z, int *tokenType){ int i, c; switch( aiClass[*z] ){ /* Switch on the character-class of the first byte | > > > > > > > | 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 | #define TK_ILLEGAL TK_ERROR #define TK_DOT TK_PUNCT #define TK_INTEGER TK_LITERAL #define TK_FLOAT TK_LITERAL #define TK_VARIABLE TK_LITERAL #define TK_BLOB TK_LITERAL /* Disable nuisence warnings about case fall-through */ #if !defined(deliberate_fall_through) && defined(__GCC__) && __GCC__>=7 # define deliberate_fall_through __attribute__((fallthrough)); #else # define deliberate_fall_through #endif /* ** Return the length (in bytes) of the token that begins at z[0]. ** Store the token type in *tokenType before returning. */ static int sqlite3GetToken(const unsigned char *z, int *tokenType){ int i, c; switch( aiClass[*z] ){ /* Switch on the character-class of the first byte |
︙ | ︙ | |||
432 433 434 435 436 437 438 439 440 441 442 443 444 445 | case CC_DOT: { if( !sqlite3Isdigit(z[1]) ){ *tokenType = TK_DOT; return 1; } /* If the next character is a digit, this is a floating point ** number that begins with ".". Fall thru into the next case */ } case CC_DIGIT: { *tokenType = TK_INTEGER; if( z[0]=='0' && (z[1]=='x' || z[1]=='X') && sqlite3Isxdigit(z[2]) ){ for(i=3; sqlite3Isxdigit(z[i]); i++){} return i; } | > | 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 | case CC_DOT: { if( !sqlite3Isdigit(z[1]) ){ *tokenType = TK_DOT; return 1; } /* If the next character is a digit, this is a floating point ** number that begins with ".". Fall thru into the next case */ /* no break */ deliberate_fall_through } case CC_DIGIT: { *tokenType = TK_INTEGER; if( z[0]=='0' && (z[1]=='x' || z[1]=='X') && sqlite3Isxdigit(z[2]) ){ for(i=3; sqlite3Isxdigit(z[i]); i++){} return i; } |
︙ | ︙ | |||
524 525 526 527 528 529 530 531 532 533 534 535 536 537 | while( z[i] && z[i]!='\'' ){ i++; } } if( z[i] ) i++; return i; } /* If it is not a BLOB literal, then it must be an ID, since no ** SQL keywords start with the letter 'x'. Fall through */ } case CC_ID: { i = 1; break; } default: { *tokenType = TK_ILLEGAL; | > | 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 | while( z[i] && z[i]!='\'' ){ i++; } } if( z[i] ) i++; return i; } /* If it is not a BLOB literal, then it must be an ID, since no ** SQL keywords start with the letter 'x'. Fall through */ /* no break */ deliberate_fall_through } case CC_ID: { i = 1; break; } default: { *tokenType = TK_ILLEGAL; |
︙ | ︙ |
Changes to ext/misc/percentile.c.
︙ | ︙ | |||
104 105 106 107 108 109 110 | int eType; double y; assert( argc==2 ); /* Requirement 3: P must be a number between 0 and 100 */ eType = sqlite3_value_numeric_type(argv[1]); rPct = sqlite3_value_double(argv[1]); | | | | 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 | int eType; double y; assert( argc==2 ); /* Requirement 3: P must be a number between 0 and 100 */ eType = sqlite3_value_numeric_type(argv[1]); rPct = sqlite3_value_double(argv[1]); if( (eType!=SQLITE_INTEGER && eType!=SQLITE_FLOAT) || rPct<0.0 || rPct>100.0 ){ sqlite3_result_error(pCtx, "2nd argument to percentile() is not " "a number between 0.0 and 100.0", -1); return; } /* Allocate the session context. */ p = (Percentile*)sqlite3_aggregate_context(pCtx, sizeof(*p)); |
︙ | ︙ | |||
147 148 149 150 151 152 153 | sqlite3_result_error(pCtx, "Inf input to percentile()", -1); return; } /* Allocate and store the Y */ if( p->nUsed>=p->nAlloc ){ unsigned n = p->nAlloc*2 + 250; | | | 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 | sqlite3_result_error(pCtx, "Inf input to percentile()", -1); return; } /* Allocate and store the Y */ if( p->nUsed>=p->nAlloc ){ unsigned n = p->nAlloc*2 + 250; double *a = sqlite3_realloc64(p->a, sizeof(double)*n); if( a==0 ){ sqlite3_free(p->a); memset(p, 0, sizeof(*p)); sqlite3_result_error_nomem(pCtx); return; } p->nAlloc = n; |
︙ | ︙ | |||
209 210 211 212 213 214 215 | sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi ){ int rc = SQLITE_OK; SQLITE_EXTENSION_INIT2(pApi); (void)pzErrMsg; /* Unused parameter */ | | > | 209 210 211 212 213 214 215 216 217 218 219 220 | 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, "percentile", 2, SQLITE_UTF8|SQLITE_INNOCUOUS, 0, 0, percentStep, percentFinal); return rc; } |
Added ext/misc/prefixes.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 | /* ** 2018-04-19 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** ** This file implements a table-valued function: ** ** prefixes('abcdefg') ** ** The function has a single (non-HIDDEN) column named prefix that takes ** on all prefixes of the string in its argument, including an empty string ** and the input string itself. The order of prefixes is from longest ** to shortest. */ #if !defined(SQLITE_CORE) || !defined(SQLITE_OMIT_VIRTUALTABLE) #if !defined(SQLITEINT_H) #include "sqlite3ext.h" #endif SQLITE_EXTENSION_INIT1 #include <string.h> #include <assert.h> /* prefixes_vtab is a subclass of sqlite3_vtab which is ** underlying representation of the virtual table */ typedef struct prefixes_vtab prefixes_vtab; struct prefixes_vtab { sqlite3_vtab base; /* Base class - must be first */ /* No additional fields are necessary */ }; /* prefixes_cursor is a subclass of sqlite3_vtab_cursor which will ** serve as the underlying representation of a cursor that scans ** over rows of the result */ typedef struct prefixes_cursor prefixes_cursor; struct prefixes_cursor { sqlite3_vtab_cursor base; /* Base class - must be first */ sqlite3_int64 iRowid; /* The rowid */ char *zStr; /* Original string to be prefixed */ int nStr; /* Length of the string in bytes */ }; /* ** The prefixesConnect() method is invoked to create a new ** template virtual table. ** ** Think of this routine as the constructor for prefixes_vtab objects. ** ** All this routine needs to do is: ** ** (1) Allocate the prefixes_vtab object and initialize all fields. ** ** (2) Tell SQLite (via the sqlite3_declare_vtab() interface) what the ** result set of queries against the virtual table will look like. */ static int prefixesConnect( sqlite3 *db, void *pAux, int argc, const char *const*argv, sqlite3_vtab **ppVtab, char **pzErr ){ prefixes_vtab *pNew; int rc; rc = sqlite3_declare_vtab(db, "CREATE TABLE prefixes(prefix TEXT, original_string TEXT HIDDEN)" ); if( rc==SQLITE_OK ){ pNew = sqlite3_malloc( sizeof(*pNew) ); *ppVtab = (sqlite3_vtab*)pNew; if( pNew==0 ) return SQLITE_NOMEM; memset(pNew, 0, sizeof(*pNew)); sqlite3_vtab_config(db, SQLITE_VTAB_INNOCUOUS); } return rc; } /* ** This method is the destructor for prefixes_vtab objects. */ static int prefixesDisconnect(sqlite3_vtab *pVtab){ prefixes_vtab *p = (prefixes_vtab*)pVtab; sqlite3_free(p); return SQLITE_OK; } /* ** Constructor for a new prefixes_cursor object. */ static int prefixesOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){ prefixes_cursor *pCur; pCur = sqlite3_malloc( sizeof(*pCur) ); if( pCur==0 ) return SQLITE_NOMEM; memset(pCur, 0, sizeof(*pCur)); *ppCursor = &pCur->base; return SQLITE_OK; } /* ** Destructor for a prefixes_cursor. */ static int prefixesClose(sqlite3_vtab_cursor *cur){ prefixes_cursor *pCur = (prefixes_cursor*)cur; sqlite3_free(pCur->zStr); sqlite3_free(pCur); return SQLITE_OK; } /* ** Advance a prefixes_cursor to its next row of output. */ static int prefixesNext(sqlite3_vtab_cursor *cur){ prefixes_cursor *pCur = (prefixes_cursor*)cur; pCur->iRowid++; return SQLITE_OK; } /* ** Return values of columns for the row at which the prefixes_cursor ** is currently pointing. */ static int prefixesColumn( sqlite3_vtab_cursor *cur, /* The cursor */ sqlite3_context *ctx, /* First argument to sqlite3_result_...() */ int i /* Which column to return */ ){ prefixes_cursor *pCur = (prefixes_cursor*)cur; switch( i ){ case 0: sqlite3_result_text(ctx, pCur->zStr, pCur->nStr - (int)pCur->iRowid, 0); break; default: sqlite3_result_text(ctx, pCur->zStr, pCur->nStr, 0); break; } return SQLITE_OK; } /* ** Return the rowid for the current row. In this implementation, the ** rowid is the same as the output value. */ static int prefixesRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){ prefixes_cursor *pCur = (prefixes_cursor*)cur; *pRowid = pCur->iRowid; return SQLITE_OK; } /* ** Return TRUE if the cursor has been moved off of the last ** row of output. */ static int prefixesEof(sqlite3_vtab_cursor *cur){ prefixes_cursor *pCur = (prefixes_cursor*)cur; return pCur->iRowid>pCur->nStr; } /* ** This method is called to "rewind" the prefixes_cursor object back ** to the first row of output. This method is always called at least ** once prior to any call to prefixesColumn() or prefixesRowid() or ** prefixesEof(). */ static int prefixesFilter( sqlite3_vtab_cursor *pVtabCursor, int idxNum, const char *idxStr, int argc, sqlite3_value **argv ){ prefixes_cursor *pCur = (prefixes_cursor *)pVtabCursor; sqlite3_free(pCur->zStr); if( argc>0 ){ pCur->zStr = sqlite3_mprintf("%s", sqlite3_value_text(argv[0])); pCur->nStr = pCur->zStr ? (int)strlen(pCur->zStr) : 0; }else{ pCur->zStr = 0; pCur->nStr = 0; } pCur->iRowid = 0; return SQLITE_OK; } /* ** SQLite will invoke this method one or more times while planning a query ** that uses the virtual table. This routine needs to create ** a query plan for each invocation and compute an estimated cost for that ** plan. */ static int prefixesBestIndex( sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo ){ /* Search for a usable equality constraint against column 1 ** (original_string) and use it if at all possible */ int i; const struct sqlite3_index_constraint *p; for(i=0, p=pIdxInfo->aConstraint; i<pIdxInfo->nConstraint; i++, p++){ if( p->iColumn!=1 ) continue; if( p->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue; if( !p->usable ) continue; pIdxInfo->aConstraintUsage[i].argvIndex = 1; pIdxInfo->aConstraintUsage[i].omit = 1; pIdxInfo->estimatedCost = (double)10; pIdxInfo->estimatedRows = 10; return SQLITE_OK; } pIdxInfo->estimatedCost = (double)1000000000; pIdxInfo->estimatedRows = 1000000000; return SQLITE_OK; } /* ** This following structure defines all the methods for the ** virtual table. */ static sqlite3_module prefixesModule = { /* iVersion */ 0, /* xCreate */ 0, /* xConnect */ prefixesConnect, /* xBestIndex */ prefixesBestIndex, /* xDisconnect */ prefixesDisconnect, /* xDestroy */ 0, /* xOpen */ prefixesOpen, /* xClose */ prefixesClose, /* xFilter */ prefixesFilter, /* xNext */ prefixesNext, /* xEof */ prefixesEof, /* xColumn */ prefixesColumn, /* xRowid */ prefixesRowid, /* xUpdate */ 0, /* xBegin */ 0, /* xSync */ 0, /* xCommit */ 0, /* xRollback */ 0, /* xFindMethod */ 0, /* xRename */ 0, /* xSavepoint */ 0, /* xRelease */ 0, /* xRollbackTo */ 0, /* xShadowName */ 0 }; /* ** This is a copy of the SQLITE_SKIP_UTF8(zIn) macro in sqliteInt.h. ** ** Assuming zIn points to the first byte of a UTF-8 character, ** advance zIn to point to the first byte of the next UTF-8 character. */ #define PREFIX_SKIP_UTF8(zIn) { \ if( (*(zIn++))>=0xc0 ){ \ while( (*zIn & 0xc0)==0x80 ){ zIn++; } \ } \ } /* ** Implementation of function prefix_length(). This function accepts two ** strings as arguments and returns the length in characters (not bytes), ** of the longest prefix shared by the two strings. For example: ** ** prefix_length('abcdxxx', 'abcyy') == 3 ** prefix_length('abcdxxx', 'bcyyy') == 0 ** prefix_length('abcdxxx', 'ab') == 2 ** prefix_length('ab', 'abcd') == 2 ** ** This function assumes the input is well-formed utf-8. If it is not, ** it is possible for this function to return -1. */ static void prefixLengthFunc( sqlite3_context *ctx, int nVal, sqlite3_value **apVal ){ int nByte; /* Number of bytes to compare */ int nRet = 0; /* Return value */ const unsigned char *zL = sqlite3_value_text(apVal[0]); const unsigned char *zR = sqlite3_value_text(apVal[1]); int nL = sqlite3_value_bytes(apVal[0]); int nR = sqlite3_value_bytes(apVal[1]); int i; nByte = (nL > nR ? nL : nR); for(i=0; i<nByte; i++){ if( zL[i]!=zR[i] ) break; if( (zL[i] & 0xC0)!=0x80 ) nRet++; } if( (zL[i] & 0xC0)==0x80 ) nRet--; sqlite3_result_int(ctx, nRet); } #ifdef _WIN32 __declspec(dllexport) #endif int sqlite3_prefixes_init( sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi ){ int rc = SQLITE_OK; SQLITE_EXTENSION_INIT2(pApi); rc = sqlite3_create_module(db, "prefixes", &prefixesModule, 0); if( rc==SQLITE_OK ){ rc = sqlite3_create_function( db, "prefix_length", 2, SQLITE_UTF8, 0, prefixLengthFunc, 0, 0 ); } return rc; } #endif /* !defined(SQLITE_CORE) || !defined(SQLITE_OMIT_VIRTUALTABLE) */ |
Changes to ext/misc/regexp.c.
︙ | ︙ | |||
152 153 154 155 156 157 158 | if( (c&0xe0)==0xc0 && p->i<p->mx && (p->z[p->i]&0xc0)==0x80 ){ c = (c&0x1f)<<6 | (p->z[p->i++]&0x3f); if( c<0x80 ) c = 0xfffd; }else if( (c&0xf0)==0xe0 && p->i+1<p->mx && (p->z[p->i]&0xc0)==0x80 && (p->z[p->i+1]&0xc0)==0x80 ){ c = (c&0x0f)<<12 | ((p->z[p->i]&0x3f)<<6) | (p->z[p->i+1]&0x3f); p->i += 2; | | | 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 | if( (c&0xe0)==0xc0 && p->i<p->mx && (p->z[p->i]&0xc0)==0x80 ){ c = (c&0x1f)<<6 | (p->z[p->i++]&0x3f); if( c<0x80 ) c = 0xfffd; }else if( (c&0xf0)==0xe0 && p->i+1<p->mx && (p->z[p->i]&0xc0)==0x80 && (p->z[p->i+1]&0xc0)==0x80 ){ c = (c&0x0f)<<12 | ((p->z[p->i]&0x3f)<<6) | (p->z[p->i+1]&0x3f); p->i += 2; if( c<=0x7ff || (c>=0xd800 && c<=0xdfff) ) c = 0xfffd; }else if( (c&0xf8)==0xf0 && p->i+3<p->mx && (p->z[p->i]&0xc0)==0x80 && (p->z[p->i+1]&0xc0)==0x80 && (p->z[p->i+2]&0xc0)==0x80 ){ c = (c&0x07)<<18 | ((p->z[p->i]&0x3f)<<12) | ((p->z[p->i+1]&0x3f)<<6) | (p->z[p->i+2]&0x3f); p->i += 3; if( c<=0xffff || c>0x10ffff ) c = 0xfffd; }else{ |
︙ | ︙ | |||
221 222 223 224 225 226 227 | if( in.i+pRe->nInit>in.mx ) return 0; } if( pRe->nState<=(sizeof(aSpace)/(sizeof(aSpace[0])*2)) ){ pToFree = 0; aStateSet[0].aState = aSpace; }else{ | | | 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 | if( in.i+pRe->nInit>in.mx ) return 0; } if( pRe->nState<=(sizeof(aSpace)/(sizeof(aSpace[0])*2)) ){ pToFree = 0; aStateSet[0].aState = aSpace; }else{ pToFree = sqlite3_malloc64( sizeof(ReStateNumber)*2*pRe->nState ); if( pToFree==0 ) return -1; aStateSet[0].aState = pToFree; } aStateSet[1].aState = &aStateSet[0].aState[pRe->nState]; pNext = &aStateSet[1]; pNext->nState = 0; re_add_state(pNext, 0); |
︙ | ︙ | |||
244 245 246 247 248 249 250 | int x = pThis->aState[i]; switch( pRe->aOp[x] ){ case RE_OP_MATCH: { if( pRe->aArg[x]==c ) re_add_state(pNext, x+1); break; } case RE_OP_ANY: { | | | | | | 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 | int x = pThis->aState[i]; switch( pRe->aOp[x] ){ case RE_OP_MATCH: { if( pRe->aArg[x]==c ) re_add_state(pNext, x+1); break; } case RE_OP_ANY: { if( c!=0 ) re_add_state(pNext, x+1); break; } case RE_OP_WORD: { if( re_word_char(c) ) re_add_state(pNext, x+1); break; } case RE_OP_NOTWORD: { if( !re_word_char(c) && c!=0 ) re_add_state(pNext, x+1); break; } case RE_OP_DIGIT: { if( re_digit_char(c) ) re_add_state(pNext, x+1); break; } case RE_OP_NOTDIGIT: { if( !re_digit_char(c) && c!=0 ) re_add_state(pNext, x+1); break; } case RE_OP_SPACE: { if( re_space_char(c) ) re_add_state(pNext, x+1); break; } case RE_OP_NOTSPACE: { if( !re_space_char(c) && c!=0 ) re_add_state(pNext, x+1); break; } case RE_OP_BOUNDARY: { if( re_word_char(c)!=re_word_char(cPrev) ) re_add_state(pThis, x+1); break; } case RE_OP_ANYSTAR: { |
︙ | ︙ | |||
293 294 295 296 297 298 299 | re_add_state(pThis, x+pRe->aArg[x]); break; } case RE_OP_ACCEPT: { rc = 1; goto re_match_end; } | | > > > | | | | | 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 | re_add_state(pThis, x+pRe->aArg[x]); break; } case RE_OP_ACCEPT: { rc = 1; goto re_match_end; } case RE_OP_CC_EXC: { if( c==0 ) break; /* fall-through */ goto re_op_cc_inc; } case RE_OP_CC_INC: re_op_cc_inc: { int j = 1; int n = pRe->aArg[x]; int hit = 0; for(j=1; j>0 && j<n; j++){ if( pRe->aOp[x+j]==RE_OP_CC_VALUE ){ if( pRe->aArg[x+j]==c ){ hit = 1; j = -1; } }else{ if( pRe->aArg[x+j]<=c && pRe->aArg[x+j+1]>=c ){ hit = 1; j = -1; }else{ j++; } } } if( pRe->aOp[x]==RE_OP_CC_EXC ) hit = !hit; if( hit ) re_add_state(pNext, x+n); break; } } } } for(i=0; i<pNext->nState; i++){ if( pRe->aOp[pNext->aState[i]]==RE_OP_ACCEPT ){ rc = 1; break; } } re_match_end: sqlite3_free(pToFree); return rc; } /* Resize the opcode and argument arrays for an RE under construction. */ static int re_resize(ReCompiled *p, int N){ char *aOp; int *aArg; aOp = sqlite3_realloc64(p->aOp, N*sizeof(p->aOp[0])); if( aOp==0 ) return 1; p->aOp = aOp; aArg = sqlite3_realloc64(p->aArg, N*sizeof(p->aArg[0])); if( aArg==0 ) return 1; p->aArg = aArg; p->nAlloc = N; return 0; } /* Insert a new opcode and argument into an RE under construction. The |
︙ | ︙ | |||
476 477 478 479 480 481 482 | int iStart; unsigned c; const char *zErr; while( (c = p->xNextChar(&p->sIn))!=0 ){ iStart = p->nState; switch( c ){ case '|': | | | | 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 | int iStart; unsigned c; const char *zErr; while( (c = p->xNextChar(&p->sIn))!=0 ){ iStart = p->nState; switch( c ){ case '|': case '$': case ')': { p->sIn.i--; return 0; } case '(': { zErr = re_subcompile_re(p); if( zErr ) return zErr; if( rePeek(p)!=')' ) return "unmatched '('"; p->sIn.i++; break; } case '.': { if( rePeek(p)=='*' ){ re_append(p, RE_OP_ANYSTAR, 0); p->sIn.i++; }else{ re_append(p, RE_OP_ANY, 0); } break; } case '*': { if( iPrev<0 ) return "'*' without operand"; re_insert(p, iPrev, RE_OP_GOTO, p->nState - iPrev + 1); |
︙ | ︙ | |||
606 607 608 609 610 611 612 | return 0; } /* Free and reclaim all the memory used by a previously compiled ** regular expression. Applications should invoke this routine once ** for every call to re_compile() to avoid memory leaks. */ | | | | 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 | return 0; } /* Free and reclaim all the memory used by a previously compiled ** regular expression. Applications should invoke this routine once ** for every call to re_compile() to avoid memory leaks. */ static void re_free(ReCompiled *pRe){ if( pRe ){ sqlite3_free(pRe->aOp); sqlite3_free(pRe->aArg); sqlite3_free(pRe); } } /* ** Compile a textual regular expression in zIn[] into a compiled regular ** expression suitable for us by re_match() and return a pointer to the ** compiled regular expression in *ppRe. Return NULL on success or an ** error message if something goes wrong. */ static const char *re_compile(ReCompiled **ppRe, const char *zIn, int noCase){ ReCompiled *pRe; const char *zErr; int i, j; *ppRe = 0; pRe = sqlite3_malloc( sizeof(*pRe) ); if( pRe==0 ){ |
︙ | ︙ | |||
669 670 671 672 673 674 675 | ** ".*" (if the input regex lacks an initial "^") and afterwards there are ** one or more matching characters, enter those matching characters into ** zInit[]. The re_match() routine can then search ahead in the input ** string looking for the initial match without having to run the whole ** regex engine over the string. Do not worry able trying to match ** unicode characters beyond plane 0 - those are very rare and this is ** just an optimization. */ | | | | 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 | ** ".*" (if the input regex lacks an initial "^") and afterwards there are ** one or more matching characters, enter those matching characters into ** zInit[]. The re_match() routine can then search ahead in the input ** string looking for the initial match without having to run the whole ** regex engine over the string. Do not worry able trying to match ** unicode characters beyond plane 0 - those are very rare and this is ** just an optimization. */ if( pRe->aOp[0]==RE_OP_ANYSTAR && !noCase ){ for(j=0, i=1; j<(int)sizeof(pRe->zInit)-2 && pRe->aOp[i]==RE_OP_MATCH; i++){ unsigned x = pRe->aArg[i]; if( x<=127 ){ pRe->zInit[j++] = (unsigned char)x; }else if( x<=0xfff ){ pRe->zInit[j++] = (unsigned char)(0xc0 | (x>>6)); pRe->zInit[j++] = 0x80 | (x&0x3f); }else if( x<=0xffff ){ |
︙ | ︙ | |||
701 702 703 704 705 706 707 | ** pattern and the second argument is the string. So, the SQL statements: ** ** A REGEXP B ** ** is implemented as regexp(B,A). */ static void re_sql_func( | | | > | | 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 | ** pattern and the second argument is the string. So, the SQL statements: ** ** A REGEXP B ** ** is implemented as regexp(B,A). */ static void re_sql_func( sqlite3_context *context, int argc, sqlite3_value **argv ){ ReCompiled *pRe; /* Compiled regular expression */ const char *zPattern; /* The regular expression */ const unsigned char *zStr;/* String being searched */ const char *zErr; /* Compile error message */ int setAux = 0; /* True to invoke sqlite3_set_auxdata() */ (void)argc; /* Unused */ pRe = sqlite3_get_auxdata(context, 0); if( pRe==0 ){ zPattern = (const char*)sqlite3_value_text(argv[0]); if( zPattern==0 ) return; zErr = re_compile(&pRe, zPattern, sqlite3_user_data(context)!=0); if( zErr ){ re_free(pRe); sqlite3_result_error(context, zErr, -1); return; } if( pRe==0 ){ sqlite3_result_error_nomem(context); |
︙ | ︙ | |||
750 751 752 753 754 755 756 | int sqlite3_regexp_init( sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi ){ int rc = SQLITE_OK; SQLITE_EXTENSION_INIT2(pApi); | > | | > > > > > > | 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 | int sqlite3_regexp_init( sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi ){ int rc = SQLITE_OK; SQLITE_EXTENSION_INIT2(pApi); (void)pzErrMsg; /* Unused */ rc = sqlite3_create_function(db, "regexp", 2, SQLITE_UTF8|SQLITE_INNOCUOUS, 0, re_sql_func, 0, 0); if( rc==SQLITE_OK ){ /* The regexpi(PATTERN,STRING) function is a case-insensitive version ** of regexp(PATTERN,STRING). */ rc = sqlite3_create_function(db, "regexpi", 2, SQLITE_UTF8|SQLITE_INNOCUOUS, (void*)db, re_sql_func, 0, 0); } return rc; } |
Changes to ext/misc/rot13.c.
︙ | ︙ | |||
101 102 103 104 105 106 107 | sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi ){ int rc = SQLITE_OK; SQLITE_EXTENSION_INIT2(pApi); (void)pzErrMsg; /* Unused parameter */ | | > | | 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 | 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, "rot13", 1, SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_DETERMINISTIC, 0, rot13func, 0, 0); if( rc==SQLITE_OK ){ rc = sqlite3_create_collation(db, "rot13", SQLITE_UTF8, 0, rot13CollFunc); } return rc; } |
Changes to ext/misc/scrub.c.
︙ | ︙ | |||
162 163 164 165 166 167 168 | SQLITE_OPEN_READWRITE | SQLITE_OPEN_URI | SQLITE_OPEN_PRIVATECACHE, 0); if( p->rcErr ){ scrubBackupErr(p, "cannot open source database: %s", sqlite3_errmsg(p->dbSrc)); return; } | | | 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 | SQLITE_OPEN_READWRITE | SQLITE_OPEN_URI | SQLITE_OPEN_PRIVATECACHE, 0); if( p->rcErr ){ scrubBackupErr(p, "cannot open source database: %s", sqlite3_errmsg(p->dbSrc)); return; } p->rcErr = sqlite3_exec(p->dbSrc, "SELECT 1 FROM sqlite_schema; BEGIN;", 0, 0, 0); if( p->rcErr ){ scrubBackupErr(p, "cannot start a read transaction on the source database: %s", sqlite3_errmsg(p->dbSrc)); return; } |
︙ | ︙ | |||
531 532 533 534 535 536 537 | /* Copy ptrmap pages */ n = scrubBackupInt32(&s.page1[52]); if( n ) scrubBackupPtrmap(&s); /* Copy all of the btrees */ scrubBackupBtree(&s, 1, 0); pStmt = scrubBackupPrepare(&s, s.dbSrc, | | | 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 | /* Copy ptrmap pages */ n = scrubBackupInt32(&s.page1[52]); if( n ) scrubBackupPtrmap(&s); /* Copy all of the btrees */ scrubBackupBtree(&s, 1, 0); pStmt = scrubBackupPrepare(&s, s.dbSrc, "SELECT rootpage FROM sqlite_schema WHERE coalesce(rootpage,0)>0"); if( pStmt==0 ) goto scrub_abort; while( sqlite3_step(pStmt)==SQLITE_ROW ){ i = (u32)sqlite3_column_int(pStmt, 0); scrubBackupBtree(&s, i, 0); } sqlite3_finalize(pStmt); |
︙ | ︙ |
Changes to ext/misc/series.c.
︙ | ︙ | |||
102 103 104 105 106 107 108 | ** (1) Allocate the series_vtab object and initialize all fields. ** ** (2) Tell SQLite (via the sqlite3_declare_vtab() interface) what the ** result set of queries against generate_series will look like. */ static int seriesConnect( sqlite3 *db, | | | | > > > > > | > | 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 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 | ** (1) Allocate the series_vtab object and initialize all fields. ** ** (2) Tell SQLite (via the sqlite3_declare_vtab() interface) what the ** result set of queries against generate_series will look like. */ static int seriesConnect( sqlite3 *db, void *pUnused, int argcUnused, const char *const*argvUnused, sqlite3_vtab **ppVtab, char **pzErrUnused ){ sqlite3_vtab *pNew; int rc; /* Column numbers */ #define SERIES_COLUMN_VALUE 0 #define SERIES_COLUMN_START 1 #define SERIES_COLUMN_STOP 2 #define SERIES_COLUMN_STEP 3 (void)pUnused; (void)argcUnused; (void)argvUnused; (void)pzErrUnused; rc = sqlite3_declare_vtab(db, "CREATE TABLE x(value,start hidden,stop hidden,step hidden)"); if( rc==SQLITE_OK ){ pNew = *ppVtab = sqlite3_malloc( sizeof(*pNew) ); if( pNew==0 ) return SQLITE_NOMEM; memset(pNew, 0, sizeof(*pNew)); sqlite3_vtab_config(db, SQLITE_VTAB_INNOCUOUS); } return rc; } /* ** This method is the destructor for series_cursor objects. */ static int seriesDisconnect(sqlite3_vtab *pVtab){ sqlite3_free(pVtab); return SQLITE_OK; } /* ** Constructor for a new series_cursor object. */ static int seriesOpen(sqlite3_vtab *pUnused, sqlite3_vtab_cursor **ppCursor){ series_cursor *pCur; (void)pUnused; pCur = sqlite3_malloc( sizeof(*pCur) ); if( pCur==0 ) return SQLITE_NOMEM; memset(pCur, 0, sizeof(*pCur)); *ppCursor = &pCur->base; return SQLITE_OK; } |
︙ | ︙ | |||
237 238 239 240 241 242 243 | ** is a bitmask showing which constraints are available: ** ** 1: start=VALUE ** 2: stop=VALUE ** 4: step=VALUE ** ** Also, if bit 8 is set, that means that the series should be output | | > | > | > > > > > | 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 | ** is a bitmask showing which constraints are available: ** ** 1: start=VALUE ** 2: stop=VALUE ** 4: step=VALUE ** ** Also, if bit 8 is set, that means that the series should be output ** in descending order rather than in ascending order. If bit 16 is ** set, then output must appear in ascending order. ** ** This routine should initialize the cursor and position it so that it ** is pointing at the first row, or pointing off the end of the table ** (so that seriesEof() will return true) if the table is empty. */ static int seriesFilter( sqlite3_vtab_cursor *pVtabCursor, int idxNum, const char *idxStrUnused, int argc, sqlite3_value **argv ){ series_cursor *pCur = (series_cursor *)pVtabCursor; int i = 0; (void)idxStrUnused; if( idxNum & 1 ){ pCur->mnValue = sqlite3_value_int64(argv[i++]); }else{ pCur->mnValue = 0; } if( idxNum & 2 ){ pCur->mxValue = sqlite3_value_int64(argv[i++]); }else{ pCur->mxValue = 0xffffffff; } if( idxNum & 4 ){ pCur->iStep = sqlite3_value_int64(argv[i++]); if( pCur->iStep==0 ){ pCur->iStep = 1; }else if( pCur->iStep<0 ){ pCur->iStep = -pCur->iStep; if( (idxNum & 16)==0 ) idxNum |= 8; } }else{ pCur->iStep = 1; } for(i=0; i<argc; i++){ if( sqlite3_value_type(argv[i])==SQLITE_NULL ){ /* If any of the constraints have a NULL value, then return no rows. ** See ticket https://www.sqlite.org/src/info/fac496b61722daf2 */ |
︙ | ︙ | |||
306 307 308 309 310 311 312 | ** ** (1) start = $value -- constraint exists ** (2) stop = $value -- constraint exists ** (4) step = $value -- constraint exists ** (8) output in descending order */ static int seriesBestIndex( | | > > > > > > > > > > > > > > > | > > > > | 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 | ** ** (1) start = $value -- constraint exists ** (2) stop = $value -- constraint exists ** (4) step = $value -- constraint exists ** (8) output in descending order */ static int seriesBestIndex( sqlite3_vtab *pVTab, sqlite3_index_info *pIdxInfo ){ int i, j; /* Loop over constraints */ int idxNum = 0; /* The query plan bitmask */ int bStartSeen = 0; /* EQ constraint seen on the START column */ int unusableMask = 0; /* Mask of unusable constraints */ int nArg = 0; /* Number of arguments that seriesFilter() expects */ int aIdx[3]; /* Constraints on start, stop, and step */ const struct sqlite3_index_constraint *pConstraint; /* This implementation assumes that the start, stop, and step columns ** are the last three columns in the virtual table. */ assert( SERIES_COLUMN_STOP == SERIES_COLUMN_START+1 ); assert( SERIES_COLUMN_STEP == SERIES_COLUMN_START+2 ); aIdx[0] = aIdx[1] = aIdx[2] = -1; pConstraint = pIdxInfo->aConstraint; for(i=0; i<pIdxInfo->nConstraint; i++, pConstraint++){ int iCol; /* 0 for start, 1 for stop, 2 for step */ int iMask; /* bitmask for those column */ if( pConstraint->iColumn<SERIES_COLUMN_START ) continue; iCol = pConstraint->iColumn - SERIES_COLUMN_START; assert( iCol>=0 && iCol<=2 ); iMask = 1 << iCol; if( iCol==0 ) bStartSeen = 1; if( pConstraint->usable==0 ){ unusableMask |= iMask; continue; }else if( pConstraint->op==SQLITE_INDEX_CONSTRAINT_EQ ){ idxNum |= iMask; aIdx[iCol] = i; } } for(i=0; i<3; i++){ if( (j = aIdx[i])>=0 ){ pIdxInfo->aConstraintUsage[j].argvIndex = ++nArg; pIdxInfo->aConstraintUsage[j].omit = !SQLITE_SERIES_CONSTRAINT_VERIFY; } } /* The current generate_column() implementation requires at least one ** argument (the START value). Legacy versions assumed START=0 if the ** first argument was omitted. Compile with -DZERO_ARGUMENT_GENERATE_SERIES ** to obtain the legacy behavior */ #ifndef ZERO_ARGUMENT_GENERATE_SERIES if( !bStartSeen ){ sqlite3_free(pVTab->zErrMsg); pVTab->zErrMsg = sqlite3_mprintf( "first argument to \"generate_series()\" missing or unusable"); return SQLITE_ERROR; } #endif if( (unusableMask & ~idxNum)!=0 ){ /* The start, stop, and step columns are inputs. Therefore if there ** are unusable constraints on any of start, stop, or step then ** this plan is unusable */ return SQLITE_CONSTRAINT; } if( (idxNum & 3)==3 ){ /* Both start= and stop= boundaries are available. This is the ** the preferred case */ pIdxInfo->estimatedCost = (double)(2 - ((idxNum&4)!=0)); pIdxInfo->estimatedRows = 1000; if( pIdxInfo->nOrderBy==1 ){ if( pIdxInfo->aOrderBy[0].desc ){ idxNum |= 8; }else{ idxNum |= 16; } pIdxInfo->orderByConsumed = 1; } }else{ /* If either boundary is missing, we have to generate a huge span ** of numbers. Make this case very expensive so that the query ** planner will work hard to avoid it. */ pIdxInfo->estimatedRows = 2147483647; |
︙ | ︙ | |||
393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 | 0, /* xUpdate */ 0, /* xBegin */ 0, /* xSync */ 0, /* xCommit */ 0, /* xRollback */ 0, /* xFindMethod */ 0, /* xRename */ }; #endif /* SQLITE_OMIT_VIRTUALTABLE */ #ifdef _WIN32 __declspec(dllexport) #endif int sqlite3_series_init( sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi ){ int rc = SQLITE_OK; SQLITE_EXTENSION_INIT2(pApi); #ifndef SQLITE_OMIT_VIRTUALTABLE | > > > > | | 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 | 0, /* xUpdate */ 0, /* xBegin */ 0, /* xSync */ 0, /* xCommit */ 0, /* xRollback */ 0, /* xFindMethod */ 0, /* xRename */ 0, /* xSavepoint */ 0, /* xRelease */ 0, /* xRollbackTo */ 0 /* xShadowName */ }; #endif /* SQLITE_OMIT_VIRTUALTABLE */ #ifdef _WIN32 __declspec(dllexport) #endif int sqlite3_series_init( sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi ){ int rc = SQLITE_OK; SQLITE_EXTENSION_INIT2(pApi); #ifndef SQLITE_OMIT_VIRTUALTABLE if( sqlite3_libversion_number()<3008012 && pzErrMsg!=0 ){ *pzErrMsg = sqlite3_mprintf( "generate_series() requires SQLite 3.8.12 or later"); return SQLITE_ERROR; } rc = sqlite3_create_module(db, "generate_series", &seriesModule, 0); #endif return rc; } |
Changes to ext/misc/sha1.c.
︙ | ︙ | |||
35 36 37 38 39 40 41 | typedef struct SHA1Context SHA1Context; struct SHA1Context { unsigned int state[5]; unsigned int count[2]; unsigned char buffer[64]; }; | < < < < < < < < < < < < < < < < | 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | typedef struct SHA1Context SHA1Context; struct SHA1Context { unsigned int state[5]; unsigned int count[2]; unsigned char buffer[64]; }; #define SHA_ROT(x,l,r) ((x) << (l) | (x) >> (r)) #define rol(x,k) SHA_ROT(x,k,32-(k)) #define ror(x,k) SHA_ROT(x,32-(k),k) #define blk0le(i) (block[i] = (ror(block[i],8)&0xFF00FF00) \ |(rol(block[i],8)&0x00FF00FF)) #define blk0be(i) block[i] #define blk(i) (block[i&15] = rol(block[(i+13)&15]^block[(i+8)&15] \ ^block[(i+2)&15]^block[i&15],1)) |
︙ | ︙ | |||
393 394 395 396 397 398 399 | sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi ){ int rc = SQLITE_OK; SQLITE_EXTENSION_INIT2(pApi); (void)pzErrMsg; /* Unused parameter */ | | > | | > | 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 | 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, "sha1", 1, SQLITE_UTF8 | SQLITE_INNOCUOUS | SQLITE_DETERMINISTIC, 0, sha1Func, 0, 0); if( rc==SQLITE_OK ){ rc = sqlite3_create_function(db, "sha1_query", 1, SQLITE_UTF8|SQLITE_DIRECTONLY, 0, sha1QueryFunc, 0, 0); } return rc; } |
Changes to ext/misc/shathree.c.
︙ | ︙ | |||
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | ** 384, or 512, to determine SHA3 hash variant that is computed. */ #include "sqlite3ext.h" SQLITE_EXTENSION_INIT1 #include <assert.h> #include <string.h> #include <stdarg.h> typedef sqlite3_uint64 u64; /****************************************************************************** ** The Hash Engine */ /* ** Macros to determine whether the machine is big or little endian, ** and whether or not that determination is run-time or compile-time. | > > > | 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | ** 384, or 512, to determine SHA3 hash variant that is computed. */ #include "sqlite3ext.h" SQLITE_EXTENSION_INIT1 #include <assert.h> #include <string.h> #include <stdarg.h> #ifndef SQLITE_AMALGAMATION typedef sqlite3_uint64 u64; #endif /* SQLITE_AMALGAMATION */ /****************************************************************************** ** The Hash Engine */ /* ** Macros to determine whether the machine is big or little endian, ** and whether or not that determination is run-time or compile-time. |
︙ | ︙ | |||
617 618 619 620 621 622 623 | sqlite3_finalize(pStmt); sqlite3_result_error(context, zMsg, -1); sqlite3_free(zMsg); return; } nCol = sqlite3_column_count(pStmt); z = sqlite3_sql(pStmt); | > | | | > | 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 | sqlite3_finalize(pStmt); sqlite3_result_error(context, zMsg, -1); sqlite3_free(zMsg); return; } nCol = sqlite3_column_count(pStmt); z = sqlite3_sql(pStmt); if( z ){ n = (int)strlen(z); hash_step_vformat(&cx,"S%d:",n); SHA3Update(&cx,(unsigned char*)z,n); } /* Compute a hash over the result of the query */ while( SQLITE_ROW==sqlite3_step(pStmt) ){ SHA3Update(&cx,(const unsigned char*)"R",1); for(i=0; i<nCol; i++){ switch( sqlite3_column_type(pStmt,i) ){ case SQLITE_NULL: { |
︙ | ︙ | |||
692 693 694 695 696 697 698 | sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi ){ int rc = SQLITE_OK; SQLITE_EXTENSION_INIT2(pApi); (void)pzErrMsg; /* Unused parameter */ | | > | | > | | > | | > | | 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 | 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, "sha3", 1, SQLITE_UTF8 | SQLITE_INNOCUOUS | SQLITE_DETERMINISTIC, 0, sha3Func, 0, 0); if( rc==SQLITE_OK ){ rc = sqlite3_create_function(db, "sha3", 2, SQLITE_UTF8 | SQLITE_INNOCUOUS | SQLITE_DETERMINISTIC, 0, sha3Func, 0, 0); } if( rc==SQLITE_OK ){ rc = sqlite3_create_function(db, "sha3_query", 1, SQLITE_UTF8 | SQLITE_DIRECTONLY, 0, sha3QueryFunc, 0, 0); } if( rc==SQLITE_OK ){ rc = sqlite3_create_function(db, "sha3_query", 2, SQLITE_UTF8 | SQLITE_DIRECTONLY, 0, sha3QueryFunc, 0, 0); } return rc; } |
Changes to ext/misc/spellfix.c.
︙ | ︙ | |||
2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 | pNew->zDbName = (char*)&pNew[1]; memcpy(pNew->zDbName, zDbName, nDbName+1); pNew->zTableName = sqlite3_mprintf("%s", zTableName); pNew->db = db; if( pNew->zTableName==0 ){ rc = SQLITE_NOMEM; }else{ rc = sqlite3_declare_vtab(db, "CREATE TABLE x(word,rank,distance,langid, " "score, matchlen, phonehash HIDDEN, " "top HIDDEN, scope HIDDEN, srchcnt HIDDEN, " "soundslike HIDDEN, command HIDDEN)" ); #define SPELLFIX_COL_WORD 0 | > | 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 | pNew->zDbName = (char*)&pNew[1]; memcpy(pNew->zDbName, zDbName, nDbName+1); pNew->zTableName = sqlite3_mprintf("%s", zTableName); pNew->db = db; if( pNew->zTableName==0 ){ rc = SQLITE_NOMEM; }else{ sqlite3_vtab_config(db, SQLITE_VTAB_INNOCUOUS); rc = sqlite3_declare_vtab(db, "CREATE TABLE x(word,rank,distance,langid, " "score, matchlen, phonehash HIDDEN, " "top HIDDEN, scope HIDDEN, srchcnt HIDDEN, " "soundslike HIDDEN, command HIDDEN)" ); #define SPELLFIX_COL_WORD 0 |
︙ | ︙ |
Changes to ext/misc/sqlar.c.
︙ | ︙ | |||
13 14 15 16 17 18 19 20 21 22 23 24 25 26 | ** Utility functions sqlar_compress() and sqlar_uncompress(). Useful ** for working with sqlar archives and used by the shell tool's built-in ** sqlar support. */ #include "sqlite3ext.h" SQLITE_EXTENSION_INIT1 #include <zlib.h> /* ** Implementation of the "sqlar_compress(X)" SQL function. ** ** If the type of X is SQLITE_BLOB, and compressing that blob using ** zlib utility function compress() yields a smaller blob, return the ** compressed blob. Otherwise, return a copy of X. | > | 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | ** Utility functions sqlar_compress() and sqlar_uncompress(). Useful ** for working with sqlar archives and used by the shell tool's built-in ** sqlar support. */ #include "sqlite3ext.h" SQLITE_EXTENSION_INIT1 #include <zlib.h> #include <assert.h> /* ** Implementation of the "sqlar_compress(X)" SQL function. ** ** If the type of X is SQLITE_BLOB, and compressing that blob using ** zlib utility function compress() yields a smaller blob, return the ** compressed blob. Otherwise, return a copy of X. |
︙ | ︙ | |||
107 108 109 110 111 112 113 | sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi ){ int rc = SQLITE_OK; SQLITE_EXTENSION_INIT2(pApi); (void)pzErrMsg; /* Unused parameter */ | | > | > | 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 | sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi ){ int rc = SQLITE_OK; SQLITE_EXTENSION_INIT2(pApi); (void)pzErrMsg; /* Unused parameter */ rc = sqlite3_create_function(db, "sqlar_compress", 1, SQLITE_UTF8|SQLITE_INNOCUOUS, 0, sqlarCompressFunc, 0, 0); if( rc==SQLITE_OK ){ rc = sqlite3_create_function(db, "sqlar_uncompress", 2, SQLITE_UTF8|SQLITE_INNOCUOUS, 0, sqlarUncompressFunc, 0, 0); } return rc; } |
Changes to ext/misc/stmt.c.
︙ | ︙ | |||
164 165 166 167 168 169 170 | sqlite3_result_int(ctx, sqlite3_stmt_readonly(pCur->pStmt)); break; } case STMT_COLUMN_BUSY: { sqlite3_result_int(ctx, sqlite3_stmt_busy(pCur->pStmt)); break; } | > | | 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 | sqlite3_result_int(ctx, sqlite3_stmt_readonly(pCur->pStmt)); break; } case STMT_COLUMN_BUSY: { sqlite3_result_int(ctx, sqlite3_stmt_busy(pCur->pStmt)); break; } default: { assert( i==STMT_COLUMN_MEM ); i = SQLITE_STMTSTATUS_MEMUSED + STMT_COLUMN_NSCAN - SQLITE_STMTSTATUS_FULLSCAN_STEP; /* Fall thru */ } case STMT_COLUMN_NSCAN: case STMT_COLUMN_NSORT: case STMT_COLUMN_NAIDX: |
︙ | ︙ |
Changes to ext/misc/totype.c.
︙ | ︙ | |||
498 499 500 501 502 503 504 | sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi ){ int rc = SQLITE_OK; SQLITE_EXTENSION_INIT2(pApi); (void)pzErrMsg; /* Unused parameter */ | | > | | > | | 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 | 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, "tointeger", 1, SQLITE_UTF8 | SQLITE_DETERMINISTIC | SQLITE_INNOCUOUS, 0, tointegerFunc, 0, 0); if( rc==SQLITE_OK ){ rc = sqlite3_create_function(db, "toreal", 1, SQLITE_UTF8 | SQLITE_DETERMINISTIC | SQLITE_INNOCUOUS, 0, torealFunc, 0, 0); } return rc; } |
Added ext/misc/uint.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 | /* ** 2020-04-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 SQLite extension implements the UINT collating sequence. ** ** UINT works like BINARY for text, except that embedded strings ** of digits compare in numeric order. ** ** * Leading zeros are handled properly, in the sense that ** they do not mess of the maginitude comparison of embedded ** strings of digits. "x00123y" is equal to "x123y". ** ** * Only unsigned integers are recognized. Plus and minus ** signs are ignored. Decimal points and exponential notation ** are ignored. ** ** * Embedded integers can be of arbitrary length. Comparison ** is *not* limited integers that can be expressed as a ** 64-bit machine integer. */ #include "sqlite3ext.h" SQLITE_EXTENSION_INIT1 #include <assert.h> #include <string.h> #include <ctype.h> /* ** Compare text in lexicographic order, except strings of digits ** compare in numeric order. */ static int uintCollFunc( void *notUsed, int nKey1, const void *pKey1, int nKey2, const void *pKey2 ){ const unsigned char *zA = (const unsigned char*)pKey1; const unsigned char *zB = (const unsigned char*)pKey2; int i=0, j=0, x; (void)notUsed; while( i<nKey1 && j<nKey2 ){ x = zA[i] - zB[j]; if( isdigit(zA[i]) ){ int k; if( !isdigit(zB[j]) ) return x; while( i<nKey1 && zA[i]=='0' ){ i++; } while( j<nKey2 && zB[j]=='0' ){ j++; } k = 0; while( i+k<nKey1 && isdigit(zA[i+k]) && j+k<nKey2 && isdigit(zB[j+k]) ){ k++; } if( i+k<nKey1 && isdigit(zA[i+k]) ){ return +1; }else if( j+k<nKey2 && isdigit(zB[j+k]) ){ return -1; }else{ x = memcmp(zA+i, zB+j, k); if( x ) return x; i += k; j += k; } }else if( x ){ return x; }else{ i++; j++; } } return (nKey1 - i) - (nKey2 - j); } #ifdef _WIN32 __declspec(dllexport) #endif int sqlite3_uint_init( sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi ){ SQLITE_EXTENSION_INIT2(pApi); (void)pzErrMsg; /* Unused parameter */ return sqlite3_create_collation(db, "uint", SQLITE_UTF8, 0, uintCollFunc); } |
Changes to ext/misc/unionvtab.c.
︙ | ︙ | |||
246 247 248 249 250 251 252 | /* ** If *pRc is other than SQLITE_OK when this function is called, it ** always returns NULL. Otherwise, it attempts to allocate and return ** a pointer to nByte bytes of zeroed memory. If the memory allocation ** is attempted but fails, NULL is returned and *pRc is set to ** SQLITE_NOMEM. */ | | | | | | | 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 | /* ** If *pRc is other than SQLITE_OK when this function is called, it ** always returns NULL. Otherwise, it attempts to allocate and return ** a pointer to nByte bytes of zeroed memory. If the memory allocation ** is attempted but fails, NULL is returned and *pRc is set to ** SQLITE_NOMEM. */ static void *unionMalloc(int *pRc, sqlite3_int64 nByte){ void *pRet; assert( nByte>0 ); if( *pRc==SQLITE_OK ){ pRet = sqlite3_malloc64(nByte); if( pRet ){ memset(pRet, 0, (size_t)nByte); }else{ *pRc = SQLITE_NOMEM; } }else{ pRet = 0; } return pRet; } /* ** If *pRc is other than SQLITE_OK when this function is called, it ** always returns NULL. Otherwise, it attempts to allocate and return ** a copy of the nul-terminated string passed as the second argument. ** If the allocation is attempted but fails, NULL is returned and *pRc is ** set to SQLITE_NOMEM. */ static char *unionStrdup(int *pRc, const char *zIn){ char *zRet = 0; if( zIn ){ sqlite3_int64 nByte = strlen(zIn) + 1; zRet = unionMalloc(pRc, nByte); if( zRet ){ memcpy(zRet, zIn, (size_t)nByte); } } return zRet; } /* ** If the first character of the string passed as the only argument to this |
︙ | ︙ | |||
935 936 937 938 939 940 941 | sqlite3_int64 iMin = sqlite3_column_int64(pStmt, 2); sqlite3_int64 iMax = sqlite3_column_int64(pStmt, 3); UnionSrc *pSrc; /* Grow the pTab->aSrc[] array if required. */ if( nAlloc<=pTab->nSrc ){ int nNew = nAlloc ? nAlloc*2 : 8; | | | 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 | sqlite3_int64 iMin = sqlite3_column_int64(pStmt, 2); sqlite3_int64 iMax = sqlite3_column_int64(pStmt, 3); UnionSrc *pSrc; /* Grow the pTab->aSrc[] array if required. */ if( nAlloc<=pTab->nSrc ){ int nNew = nAlloc ? nAlloc*2 : 8; UnionSrc *aNew = (UnionSrc*)sqlite3_realloc64( pTab->aSrc, nNew*sizeof(UnionSrc) ); if( aNew==0 ){ rc = SQLITE_NOMEM; break; }else{ memset(&aNew[pTab->nSrc], 0, (nNew-pTab->nSrc)*sizeof(UnionSrc)); |
︙ | ︙ |
Added ext/misc/urifuncs.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 | /* ** 2020-01-11 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ****************************************************************************** ** ** This SQLite extension implements various SQL functions used to access ** the following SQLite C-language APIs: ** ** sqlite3_uri_parameter() ** sqlite3_uri_boolean() ** sqlite3_uri_int64() ** sqlite3_uri_key() ** sqlite3_filename_database() ** sqlite3_filename_journal() ** sqlite3_filename_wal() ** sqlite3_db_filename() ** ** These SQL functions are for testing and demonstration purposes only. ** ** */ #include "sqlite3ext.h" SQLITE_EXTENSION_INIT1 #include <assert.h> #include <string.h> /* ** SQL function: sqlite3_db_filename(SCHEMA) ** ** Return the filename corresponding to SCHEMA. */ static void func_db_filename( sqlite3_context *context, int argc, sqlite3_value **argv ){ const char *zSchema = (const char*)sqlite3_value_text(argv[0]); sqlite3 *db = sqlite3_context_db_handle(context); const char *zFile = sqlite3_db_filename(db, zSchema); sqlite3_result_text(context, zFile, -1, SQLITE_TRANSIENT); } /* ** SQL function: sqlite3_uri_parameter(SCHEMA,NAME) ** ** Return the value of the NAME query parameter to the database for SCHEMA */ static void func_uri_parameter( sqlite3_context *context, int argc, sqlite3_value **argv ){ const char *zSchema = (const char*)sqlite3_value_text(argv[0]); sqlite3 *db = sqlite3_context_db_handle(context); const char *zName = (const char*)sqlite3_value_text(argv[1]); const char *zFile = sqlite3_db_filename(db, zSchema); const char *zRes = sqlite3_uri_parameter(zFile, zName); sqlite3_result_text(context, zRes, -1, SQLITE_TRANSIENT); } /* ** SQL function: sqlite3_uri_boolean(SCHEMA,NAME,DEFAULT) ** ** Return the boolean value of the NAME query parameter to ** the database for SCHEMA */ static void func_uri_boolean( sqlite3_context *context, int argc, sqlite3_value **argv ){ const char *zSchema = (const char*)sqlite3_value_text(argv[0]); sqlite3 *db = sqlite3_context_db_handle(context); const char *zName = (const char*)sqlite3_value_text(argv[1]); const char *zFile = sqlite3_db_filename(db, zSchema); int iDflt = sqlite3_value_int(argv[2]); int iRes = sqlite3_uri_boolean(zFile, zName, iDflt); sqlite3_result_int(context, iRes); } /* ** SQL function: sqlite3_uri_key(SCHEMA,N) ** ** Return the name of the Nth query parameter */ static void func_uri_key( sqlite3_context *context, int argc, sqlite3_value **argv ){ const char *zSchema = (const char*)sqlite3_value_text(argv[0]); sqlite3 *db = sqlite3_context_db_handle(context); int N = sqlite3_value_int(argv[1]); const char *zFile = sqlite3_db_filename(db, zSchema); const char *zRes = sqlite3_uri_key(zFile, N); sqlite3_result_text(context, zRes, -1, SQLITE_TRANSIENT); } /* ** SQL function: sqlite3_uri_int64(SCHEMA,NAME,DEFAULT) ** ** Return the int64 value of the NAME query parameter to ** the database for SCHEMA */ static void func_uri_int64( sqlite3_context *context, int argc, sqlite3_value **argv ){ const char *zSchema = (const char*)sqlite3_value_text(argv[0]); sqlite3 *db = sqlite3_context_db_handle(context); const char *zName = (const char*)sqlite3_value_text(argv[1]); const char *zFile = sqlite3_db_filename(db, zSchema); sqlite3_int64 iDflt = sqlite3_value_int64(argv[2]); sqlite3_int64 iRes = sqlite3_uri_int64(zFile, zName, iDflt); sqlite3_result_int64(context, iRes); } /* ** SQL function: sqlite3_filename_database(SCHEMA) ** ** Return the database filename for SCHEMA */ static void func_filename_database( sqlite3_context *context, int argc, sqlite3_value **argv ){ const char *zSchema = (const char*)sqlite3_value_text(argv[0]); sqlite3 *db = sqlite3_context_db_handle(context); const char *zFile = sqlite3_db_filename(db, zSchema); const char *zRes = zFile ? sqlite3_filename_database(zFile) : 0; sqlite3_result_text(context, zRes, -1, SQLITE_TRANSIENT); } /* ** SQL function: sqlite3_filename_journal(SCHEMA) ** ** Return the rollback journal filename for SCHEMA */ static void func_filename_journal( sqlite3_context *context, int argc, sqlite3_value **argv ){ const char *zSchema = (const char*)sqlite3_value_text(argv[0]); sqlite3 *db = sqlite3_context_db_handle(context); const char *zFile = sqlite3_db_filename(db, zSchema); const char *zRes = zFile ? sqlite3_filename_journal(zFile) : 0; sqlite3_result_text(context, zRes, -1, SQLITE_TRANSIENT); } /* ** SQL function: sqlite3_filename_wal(SCHEMA) ** ** Return the WAL filename for SCHEMA */ static void func_filename_wal( sqlite3_context *context, int argc, sqlite3_value **argv ){ const char *zSchema = (const char*)sqlite3_value_text(argv[0]); sqlite3 *db = sqlite3_context_db_handle(context); const char *zFile = sqlite3_db_filename(db, zSchema); const char *zRes = zFile ? sqlite3_filename_wal(zFile) : 0; sqlite3_result_text(context, zRes, -1, SQLITE_TRANSIENT); } #ifdef _WIN32 __declspec(dllexport) #endif int sqlite3_urifuncs_init( sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi ){ static const struct { const char *zFuncName; int nArg; void (*xFunc)(sqlite3_context*,int,sqlite3_value**); } aFunc[] = { { "sqlite3_db_filename", 1, func_db_filename }, { "sqlite3_uri_parameter", 2, func_uri_parameter }, { "sqlite3_uri_boolean", 3, func_uri_boolean }, { "sqlite3_uri_int64", 3, func_uri_int64 }, { "sqlite3_uri_key", 2, func_uri_key }, { "sqlite3_filename_database", 1, func_filename_database }, { "sqlite3_filename_journal", 1, func_filename_journal }, { "sqlite3_filename_wal", 1, func_filename_wal }, }; int rc = SQLITE_OK; int i; SQLITE_EXTENSION_INIT2(pApi); (void)pzErrMsg; /* Unused parameter */ for(i=0; rc==SQLITE_OK && i<sizeof(aFunc)/sizeof(aFunc[0]); i++){ rc = sqlite3_create_function(db, aFunc[i].zFuncName, aFunc[i].nArg, SQLITE_UTF8, 0, aFunc[i].xFunc, 0, 0); } return rc; } |
Added ext/misc/uuid.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 | /* ** 2019-10-23 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ****************************************************************************** ** ** This SQLite extension implements functions that handling RFC-4122 UUIDs ** Three SQL functions are implemented: ** ** uuid() - generate a version 4 UUID as a string ** uuid_str(X) - convert a UUID X into a well-formed UUID string ** uuid_blob(X) - convert a UUID X into a 16-byte blob ** ** The output from uuid() and uuid_str(X) are always well-formed RFC-4122 ** UUID strings in this format: ** ** xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx ** ** All of the 'x', 'M', and 'N' values are lower-case hexadecimal digits. ** The M digit indicates the "version". For uuid()-generated UUIDs, the ** version is always "4" (a random UUID). The upper three bits of N digit ** are the "variant". This library only supports variant 1 (indicated ** by values of N between '8' and 'b') as those are overwhelming the most ** common. Other variants are for legacy compatibility only. ** ** The output of uuid_blob(X) is always a 16-byte blob. The UUID input ** string is converted in network byte order (big-endian) in accordance ** with RFC-4122 specifications for variant-1 UUIDs. Note that network ** byte order is *always* used, even if the input self-identifies as a ** variant-2 UUID. ** ** The input X to the uuid_str() and uuid_blob() functions can be either ** a string or a BLOB. If it is a BLOB it must be exactly 16 bytes in ** length or else a NULL is returned. If the input is a string it must ** consist of 32 hexadecimal digits, upper or lower case, optionally ** surrounded by {...} and with optional "-" characters interposed in the ** middle. The flexibility of input is inspired by the PostgreSQL ** implementation of UUID functions that accept in all of the following ** formats: ** ** A0EEBC99-9C0B-4EF8-BB6D-6BB9BD380A11 ** {a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11} ** a0eebc999c0b4ef8bb6d6bb9bd380a11 ** a0ee-bc99-9c0b-4ef8-bb6d-6bb9-bd38-0a11 ** {a0eebc99-9c0b4ef8-bb6d6bb9-bd380a11} ** ** If any of the above inputs are passed into uuid_str(), the output will ** always be in the canonical RFC-4122 format: ** ** a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11 ** ** If the X input string has too few or too many digits or contains ** stray characters other than {, }, or -, then NULL is returned. */ #include "sqlite3ext.h" SQLITE_EXTENSION_INIT1 #include <assert.h> #include <string.h> #include <ctype.h> #if !defined(SQLITE_ASCII) && !defined(SQLITE_EBCDIC) # define SQLITE_ASCII 1 #endif /* ** Translate a single byte of Hex into an integer. ** This routine only works if h really is a valid hexadecimal ** character: 0..9a..fA..F */ static unsigned char sqlite3UuidHexToInt(int h){ assert( (h>='0' && h<='9') || (h>='a' && h<='f') || (h>='A' && h<='F') ); #ifdef SQLITE_ASCII h += 9*(1&(h>>6)); #endif #ifdef SQLITE_EBCDIC h += 9*(1&~(h>>4)); #endif return (unsigned char)(h & 0xf); } /* ** Convert a 16-byte BLOB into a well-formed RFC-4122 UUID. The output ** buffer zStr should be at least 37 bytes in length. The output will ** be zero-terminated. */ static void sqlite3UuidBlobToStr( const unsigned char *aBlob, /* Input blob */ unsigned char *zStr /* Write the answer here */ ){ static const char zDigits[] = "0123456789abcdef"; int i, k; unsigned char x; k = 0; for(i=0, k=0x550; i<16; i++, k=k>>1){ if( k&1 ){ zStr[0] = '-'; zStr++; } x = aBlob[i]; zStr[0] = zDigits[x>>4]; zStr[1] = zDigits[x&0xf]; zStr += 2; } *zStr = 0; } /* ** Attempt to parse a zero-terminated input string zStr into a binary ** UUID. Return 0 on success, or non-zero if the input string is not ** parsable. */ static int sqlite3UuidStrToBlob( const unsigned char *zStr, /* Input string */ unsigned char *aBlob /* Write results here */ ){ int i; if( zStr[0]=='{' ) zStr++; for(i=0; i<16; i++){ if( zStr[0]=='-' ) zStr++; if( isxdigit(zStr[0]) && isxdigit(zStr[1]) ){ aBlob[i] = (sqlite3UuidHexToInt(zStr[0])<<4) + sqlite3UuidHexToInt(zStr[1]); zStr += 2; }else{ return 1; } } if( zStr[0]=='}' ) zStr++; return zStr[0]!=0; } /* ** Render sqlite3_value pIn as a 16-byte UUID blob. Return a pointer ** to the blob, or NULL if the input is not well-formed. */ static const unsigned char *sqlite3UuidInputToBlob( sqlite3_value *pIn, /* Input text */ unsigned char *pBuf /* output buffer */ ){ switch( sqlite3_value_type(pIn) ){ case SQLITE_TEXT: { const unsigned char *z = sqlite3_value_text(pIn); if( sqlite3UuidStrToBlob(z, pBuf) ) return 0; return pBuf; } case SQLITE_BLOB: { int n = sqlite3_value_bytes(pIn); return n==16 ? sqlite3_value_blob(pIn) : 0; } default: { return 0; } } } /* Implementation of uuid() */ static void sqlite3UuidFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ unsigned char aBlob[16]; unsigned char zStr[37]; (void)argc; (void)argv; sqlite3_randomness(16, aBlob); aBlob[6] = (aBlob[6]&0x0f) + 0x40; aBlob[8] = (aBlob[8]&0x3f) + 0x80; sqlite3UuidBlobToStr(aBlob, zStr); sqlite3_result_text(context, (char*)zStr, 36, SQLITE_TRANSIENT); } /* Implementation of uuid_str() */ static void sqlite3UuidStrFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ unsigned char aBlob[16]; unsigned char zStr[37]; const unsigned char *pBlob; (void)argc; pBlob = sqlite3UuidInputToBlob(argv[0], aBlob); if( pBlob==0 ) return; sqlite3UuidBlobToStr(pBlob, zStr); sqlite3_result_text(context, (char*)zStr, 36, SQLITE_TRANSIENT); } /* Implementation of uuid_blob() */ static void sqlite3UuidBlobFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ unsigned char aBlob[16]; const unsigned char *pBlob; (void)argc; pBlob = sqlite3UuidInputToBlob(argv[0], aBlob); if( pBlob==0 ) return; sqlite3_result_blob(context, pBlob, 16, SQLITE_TRANSIENT); } #ifdef _WIN32 __declspec(dllexport) #endif int sqlite3_uuid_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, "uuid", 0, SQLITE_UTF8|SQLITE_INNOCUOUS, 0, sqlite3UuidFunc, 0, 0); if( rc==SQLITE_OK ){ rc = sqlite3_create_function(db, "uuid_str", 1, SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_DETERMINISTIC, 0, sqlite3UuidStrFunc, 0, 0); } if( rc==SQLITE_OK ){ rc = sqlite3_create_function(db, "uuid_blob", 1, SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_DETERMINISTIC, 0, sqlite3UuidBlobFunc, 0, 0); } return rc; } |
Changes to ext/misc/vfslog.c.
︙ | ︙ | |||
272 273 274 275 276 277 278 | if( nName>8 && strcmp(zFilename+nName-8,"-journal")==0 ){ nName -= 8; isJournal = 1; }else if( nName>12 && sqlite3_strglob("-mj??????9??", zFilename+nName-12)==0 ){ return 0; /* Do not log master journal files */ } | | | 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 | if( nName>8 && strcmp(zFilename+nName-8,"-journal")==0 ){ nName -= 8; isJournal = 1; }else if( nName>12 && sqlite3_strglob("-mj??????9??", zFilename+nName-12)==0 ){ return 0; /* Do not log master journal files */ } pTemp = sqlite3_malloc64( sizeof(*pLog)*2 + nName + 60 ); if( pTemp==0 ) return 0; pMutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER); sqlite3_mutex_enter(pMutex); for(pLog=allLogs; pLog; pLog=pLog->pNext){ if( pLog->nFilename==nName && !memcmp(pLog->zFilename, zFilename, nName) ){ break; } |
︙ | ︙ | |||
750 751 752 753 754 755 756 757 758 759 | } /* ** Register debugvfs as the default VFS for this process. */ int sqlite3_register_vfslog(const char *zArg){ vlog_vfs.pVfs = sqlite3_vfs_find(0); vlog_vfs.base.szOsFile = sizeof(VLogFile) + vlog_vfs.pVfs->szOsFile; return sqlite3_vfs_register(&vlog_vfs.base, 1); } | > | 750 751 752 753 754 755 756 757 758 759 760 | } /* ** Register debugvfs as the default VFS for this process. */ int sqlite3_register_vfslog(const char *zArg){ vlog_vfs.pVfs = sqlite3_vfs_find(0); if( vlog_vfs.pVfs==0 ) return SQLITE_ERROR; vlog_vfs.base.szOsFile = sizeof(VLogFile) + vlog_vfs.pVfs->szOsFile; return sqlite3_vfs_register(&vlog_vfs.base, 1); } |
Changes to ext/misc/vfsstat.c.
︙ | ︙ | |||
779 780 781 782 783 784 785 | /* ** This routine is an sqlite3_auto_extension() callback, invoked to register ** the vfsstat virtual table for all new database connections. */ static int vstatRegister( sqlite3 *db, | | | | 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 | /* ** This routine is an sqlite3_auto_extension() callback, invoked to register ** the vfsstat virtual table for all new database connections. */ static int vstatRegister( sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pThunk ){ return sqlite3_create_module(db, "vfsstat", &VfsStatModule, 0); } #ifdef _WIN32 __declspec(dllexport) #endif |
︙ | ︙ | |||
802 803 804 805 806 807 808 809 810 811 | sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi ){ int rc = SQLITE_OK; SQLITE_EXTENSION_INIT2(pApi); vstat_vfs.pVfs = sqlite3_vfs_find(0); vstat_vfs.base.szOsFile = sizeof(VStatFile) + vstat_vfs.pVfs->szOsFile; rc = sqlite3_vfs_register(&vstat_vfs.base, 1); if( rc==SQLITE_OK ){ | > > > | > | 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 | sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi ){ int rc = SQLITE_OK; SQLITE_EXTENSION_INIT2(pApi); vstat_vfs.pVfs = sqlite3_vfs_find(0); if( vstat_vfs.pVfs==0 ) return SQLITE_ERROR; vstat_vfs.base.szOsFile = sizeof(VStatFile) + vstat_vfs.pVfs->szOsFile; rc = sqlite3_vfs_register(&vstat_vfs.base, 1); if( rc==SQLITE_OK ){ rc = vstatRegister(db, pzErrMsg, pApi); if( rc==SQLITE_OK ){ rc = sqlite3_auto_extension((void(*)(void))vstatRegister); } } if( rc==SQLITE_OK ) rc = SQLITE_OK_LOAD_PERMANENTLY; return rc; } |
Changes to ext/misc/wholenumber.c.
︙ | ︙ | |||
46 47 48 49 50 51 52 53 54 55 56 57 58 59 | sqlite3_vtab **ppVtab, char **pzErr ){ sqlite3_vtab *pNew; pNew = *ppVtab = sqlite3_malloc( sizeof(*pNew) ); if( pNew==0 ) return SQLITE_NOMEM; sqlite3_declare_vtab(db, "CREATE TABLE x(value)"); memset(pNew, 0, sizeof(*pNew)); return SQLITE_OK; } /* Note that for this virtual table, the xCreate and xConnect ** methods are identical. */ static int wholenumberDisconnect(sqlite3_vtab *pVtab){ | > | 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | sqlite3_vtab **ppVtab, char **pzErr ){ sqlite3_vtab *pNew; pNew = *ppVtab = sqlite3_malloc( sizeof(*pNew) ); if( pNew==0 ) return SQLITE_NOMEM; sqlite3_declare_vtab(db, "CREATE TABLE x(value)"); sqlite3_vtab_config(db, SQLITE_VTAB_INNOCUOUS); memset(pNew, 0, sizeof(*pNew)); return SQLITE_OK; } /* Note that for this virtual table, the xCreate and xConnect ** methods are identical. */ static int wholenumberDisconnect(sqlite3_vtab *pVtab){ |
︙ | ︙ | |||
215 216 217 218 219 220 221 | } if( pIdxInfo->nOrderBy==1 && pIdxInfo->aOrderBy[0].desc==0 ){ pIdxInfo->orderByConsumed = 1; } if( (idxNum & 12)==0 ){ | | | 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 | } if( pIdxInfo->nOrderBy==1 && pIdxInfo->aOrderBy[0].desc==0 ){ pIdxInfo->orderByConsumed = 1; } if( (idxNum & 12)==0 ){ pIdxInfo->estimatedCost = 1e99; }else if( (idxNum & 3)==0 ){ pIdxInfo->estimatedCost = (double)5; }else{ pIdxInfo->estimatedCost = (double)1; } return SQLITE_OK; } |
︙ | ︙ |
Changes to ext/misc/zipfile.c.
︙ | ︙ | |||
32 33 34 35 36 37 38 39 40 | #include <zlib.h> #ifndef SQLITE_OMIT_VIRTUALTABLE #ifndef SQLITE_AMALGAMATION typedef sqlite3_int64 i64; typedef unsigned char u8; | > > > > > > > > > > > > > > | | > > > | 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 | #include <zlib.h> #ifndef SQLITE_OMIT_VIRTUALTABLE #ifndef SQLITE_AMALGAMATION #ifndef UINT32_TYPE # ifdef HAVE_UINT32_T # define UINT32_TYPE uint32_t # else # define UINT32_TYPE unsigned int # endif #endif #ifndef UINT16_TYPE # ifdef HAVE_UINT16_T # define UINT16_TYPE uint16_t # else # define UINT16_TYPE unsigned short int # endif #endif typedef sqlite3_int64 i64; typedef unsigned char u8; typedef UINT32_TYPE u32; /* 4-byte unsigned integer */ typedef UINT16_TYPE u16; /* 2-byte unsigned integer */ #define MIN(a,b) ((a)<(b) ? (a) : (b)) #if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_MUTATION_TEST) # define SQLITE_OMIT_AUXILIARY_SAFETY_CHECKS 1 #endif #if defined(SQLITE_OMIT_AUXILIARY_SAFETY_CHECKS) # define ALWAYS(X) (1) # define NEVER(X) (0) #elif !defined(NDEBUG) # define ALWAYS(X) ((X)?1:(assert(0),0)) # define NEVER(X) ((X)?(assert(0),1):0) #else # define ALWAYS(X) (X) |
︙ | ︙ | |||
354 355 356 357 358 359 360 | if( argc>3 ){ zFile = argv[3]; nFile = (int)strlen(zFile)+1; } rc = sqlite3_declare_vtab(db, ZIPFILE_SCHEMA); if( rc==SQLITE_OK ){ | | > | 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 | if( argc>3 ){ zFile = argv[3]; nFile = (int)strlen(zFile)+1; } rc = sqlite3_declare_vtab(db, ZIPFILE_SCHEMA); if( rc==SQLITE_OK ){ pNew = (ZipfileTab*)sqlite3_malloc64((sqlite3_int64)nByte+nFile); if( pNew==0 ) return SQLITE_NOMEM; memset(pNew, 0, nByte+nFile); pNew->db = db; pNew->aBuffer = (u8*)&pNew[1]; if( zFile ){ pNew->zFile = (char*)&pNew->aBuffer[ZIPFILE_BUFFER_SIZE]; memcpy(pNew->zFile, zFile, nFile); zipfileDequote(pNew->zFile); } } sqlite3_vtab_config(db, SQLITE_VTAB_DIRECTONLY); *ppVtab = (sqlite3_vtab*)pNew; return rc; } /* ** Free the ZipfileEntry structure indicated by the only argument. */ |
︙ | ︙ | |||
518 519 520 521 522 523 524 | } static int zipfileAppendData( ZipfileTab *pTab, const u8 *aWrite, int nWrite ){ | > | | | | | | | | > > | 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 | } static int zipfileAppendData( ZipfileTab *pTab, const u8 *aWrite, int nWrite ){ if( nWrite>0 ){ size_t n = nWrite; fseek(pTab->pWriteFd, (long)pTab->szCurrent, SEEK_SET); n = fwrite(aWrite, 1, nWrite, pTab->pWriteFd); if( (int)n!=nWrite ){ pTab->base.zErrMsg = sqlite3_mprintf("error in fwrite()"); return SQLITE_ERROR; } pTab->szCurrent += nWrite; } return SQLITE_OK; } /* ** Read and return a 16-bit little-endian unsigned integer from buffer aBuf. */ static u16 zipfileGetU16(const u8 *aBuf){ return (aBuf[1] << 8) + aBuf[0]; } /* ** Read and return a 32-bit little-endian unsigned integer from buffer aBuf. */ static u32 zipfileGetU32(const u8 *aBuf){ if( aBuf==0 ) return 0; return ((u32)(aBuf[3]) << 24) + ((u32)(aBuf[2]) << 16) + ((u32)(aBuf[1]) << 8) + ((u32)(aBuf[0]) << 0); } /* |
︙ | ︙ | |||
699 700 701 702 703 704 705 | ** Bits 00-04: day ** Bits 05-08: month (1-12) ** Bits 09-15: years from 1980 ** ** https://msdn.microsoft.com/en-us/library/9kkf9tah.aspx */ static u32 zipfileMtime(ZipfileCDS *pCDS){ | > > | | | < < | | | < < < < < | | | < | | < < | < < | < > | | 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 | ** Bits 00-04: day ** Bits 05-08: month (1-12) ** Bits 09-15: years from 1980 ** ** https://msdn.microsoft.com/en-us/library/9kkf9tah.aspx */ static u32 zipfileMtime(ZipfileCDS *pCDS){ int Y,M,D,X1,X2,A,B,sec,min,hr; i64 JDsec; Y = (1980 + ((pCDS->mDate >> 9) & 0x7F)); M = ((pCDS->mDate >> 5) & 0x0F); D = (pCDS->mDate & 0x1F); sec = (pCDS->mTime & 0x1F)*2; min = (pCDS->mTime >> 5) & 0x3F; hr = (pCDS->mTime >> 11) & 0x1F; if( M<=2 ){ Y--; M += 12; } X1 = 36525*(Y+4716)/100; X2 = 306001*(M+1)/10000; A = Y/100; B = 2 - A + (A/4); JDsec = (i64)((X1 + X2 + D + B - 1524.5)*86400) + hr*3600 + min*60 + sec; return (u32)(JDsec - (i64)24405875*(i64)8640); } /* ** The opposite of zipfileMtime(). This function populates the mTime and ** mDate fields of the CDS structure passed as the first argument according ** to the UNIX timestamp value passed as the second. */ |
︙ | ︙ | |||
802 803 804 805 806 807 808 | aRead = pTab->aBuffer; rc = zipfileReadData(pFile, aRead, ZIPFILE_CDS_FIXED_SZ, iOff, pzErr); }else{ aRead = (u8*)&aBlob[iOff]; } if( rc==SQLITE_OK ){ | | | | 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 | aRead = pTab->aBuffer; rc = zipfileReadData(pFile, aRead, ZIPFILE_CDS_FIXED_SZ, iOff, pzErr); }else{ aRead = (u8*)&aBlob[iOff]; } if( rc==SQLITE_OK ){ sqlite3_int64 nAlloc; ZipfileEntry *pNew; int nFile = zipfileGetU16(&aRead[ZIPFILE_CDS_NFILE_OFF]); int nExtra = zipfileGetU16(&aRead[ZIPFILE_CDS_NFILE_OFF+2]); nExtra += zipfileGetU16(&aRead[ZIPFILE_CDS_NFILE_OFF+4]); nAlloc = sizeof(ZipfileEntry) + nExtra; if( aBlob ){ nAlloc += zipfileGetU32(&aRead[ZIPFILE_CDS_SZCOMPRESSED_OFF]); } pNew = (ZipfileEntry*)sqlite3_malloc64(nAlloc); if( pNew==0 ){ rc = SQLITE_NOMEM; }else{ memset(pNew, 0, sizeof(ZipfileEntry)); rc = zipfileReadCDS(aRead, &pNew->cds); if( rc!=SQLITE_OK ){ *pzErr = sqlite3_mprintf("failed to read CDS at offset %lld", iOff); |
︙ | ︙ | |||
852 853 854 855 856 857 858 | ZipfileLFH lfh; if( pFile ){ rc = zipfileReadData(pFile, aRead, szFix, pNew->cds.iOffset, pzErr); }else{ aRead = (u8*)&aBlob[pNew->cds.iOffset]; } | | | 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 | ZipfileLFH lfh; if( pFile ){ rc = zipfileReadData(pFile, aRead, szFix, pNew->cds.iOffset, pzErr); }else{ aRead = (u8*)&aBlob[pNew->cds.iOffset]; } if( rc==SQLITE_OK ) rc = zipfileReadLFH(aRead, &lfh); if( rc==SQLITE_OK ){ pNew->iDataOff = pNew->cds.iOffset + ZIPFILE_LFH_FIXED_SZ; pNew->iDataOff += lfh.nFile + lfh.nExtra; if( aBlob && pNew->cds.szCompressed ){ pNew->aData = &pNew->aExtra[nExtra]; memcpy(pNew->aData, &aBlob[pNew->iDataOff], pNew->cds.szCompressed); } |
︙ | ︙ | |||
977 978 979 980 981 982 983 | ** case. */ static int zipfileDeflate( const u8 *aIn, int nIn, /* Input */ u8 **ppOut, int *pnOut, /* Output */ char **pzErr /* OUT: Error message */ ){ | > | > | > > > > > | < < < < < < < | 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 | ** case. */ static int zipfileDeflate( const u8 *aIn, int nIn, /* Input */ u8 **ppOut, int *pnOut, /* Output */ char **pzErr /* OUT: Error message */ ){ int rc = SQLITE_OK; sqlite3_int64 nAlloc; z_stream str; u8 *aOut; memset(&str, 0, sizeof(str)); str.next_in = (Bytef*)aIn; str.avail_in = nIn; deflateInit2(&str, 9, Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY); nAlloc = deflateBound(&str, nIn); aOut = (u8*)sqlite3_malloc64(nAlloc); if( aOut==0 ){ rc = SQLITE_NOMEM; }else{ int res; str.next_out = aOut; str.avail_out = nAlloc; res = deflate(&str, Z_FINISH); if( res==Z_STREAM_END ){ *ppOut = aOut; *pnOut = (int)str.total_out; }else{ sqlite3_free(aOut); *pzErr = sqlite3_mprintf("zipfile: deflate() error"); rc = SQLITE_ERROR; |
︙ | ︙ | |||
1054 1055 1056 1057 1058 1059 1060 | int szFinal = pCDS->szUncompressed; if( szFinal>0 ){ u8 *aBuf; u8 *aFree = 0; if( pCsr->pCurrent->aData ){ aBuf = pCsr->pCurrent->aData; }else{ | | | 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 | int szFinal = pCDS->szUncompressed; if( szFinal>0 ){ u8 *aBuf; u8 *aFree = 0; if( pCsr->pCurrent->aData ){ aBuf = pCsr->pCurrent->aData; }else{ aBuf = aFree = sqlite3_malloc64(sz); if( aBuf==0 ){ rc = SQLITE_NOMEM; }else{ FILE *pFile = pCsr->pFile; if( pFile==0 ){ pFile = ((ZipfileTab*)(pCsr->base.pVtab))->pWriteFd; } |
︙ | ︙ | |||
1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 | FILE *pFile, /* Read from this file if aBlob==0 */ ZipfileEOCD *pEOCD /* Object to populate */ ){ u8 *aRead = pTab->aBuffer; /* Temporary buffer */ int nRead; /* Bytes to read from file */ int rc = SQLITE_OK; if( aBlob==0 ){ i64 iOff; /* Offset to read from */ i64 szFile; /* Total size of file in bytes */ fseek(pFile, 0, SEEK_END); szFile = (i64)ftell(pFile); if( szFile==0 ){ | > < | 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 | FILE *pFile, /* Read from this file if aBlob==0 */ ZipfileEOCD *pEOCD /* Object to populate */ ){ u8 *aRead = pTab->aBuffer; /* Temporary buffer */ int nRead; /* Bytes to read from file */ int rc = SQLITE_OK; memset(pEOCD, 0, sizeof(ZipfileEOCD)); if( aBlob==0 ){ i64 iOff; /* Offset to read from */ i64 szFile; /* Total size of file in bytes */ fseek(pFile, 0, SEEK_END); szFile = (i64)ftell(pFile); if( szFile==0 ){ return SQLITE_OK; } nRead = (int)(MIN(szFile, ZIPFILE_BUFFER_SIZE)); iOff = szFile - nRead; rc = zipfileReadData(pFile, aRead, nRead, iOff, &pTab->base.zErrMsg); }else{ nRead = (int)(MIN(nBlob, ZIPFILE_BUFFER_SIZE)); |
︙ | ︙ | |||
1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 | if( pCons->iColumn!=ZIPFILE_F_COLUMN_IDX ) continue; if( pCons->usable==0 ){ unusable = 1; }else if( pCons->op==SQLITE_INDEX_CONSTRAINT_EQ ){ idx = i; } } if( idx>=0 ){ pIdxInfo->aConstraintUsage[idx].argvIndex = 1; pIdxInfo->aConstraintUsage[idx].omit = 1; | > < | 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 | if( pCons->iColumn!=ZIPFILE_F_COLUMN_IDX ) continue; if( pCons->usable==0 ){ unusable = 1; }else if( pCons->op==SQLITE_INDEX_CONSTRAINT_EQ ){ idx = i; } } pIdxInfo->estimatedCost = 1000.0; if( idx>=0 ){ pIdxInfo->aConstraintUsage[idx].argvIndex = 1; pIdxInfo->aConstraintUsage[idx].omit = 1; pIdxInfo->idxNum = 1; }else if( unusable ){ return SQLITE_CONSTRAINT; } return SQLITE_OK; } |
︙ | ︙ | |||
1429 1430 1431 1432 1433 1434 1435 | /* ** Both (const char*) arguments point to nul-terminated strings. Argument ** nB is the value of strlen(zB). This function returns 0 if the strings are ** identical, ignoring any trailing '/' character in either path. */ static int zipfileComparePath(const char *zA, const char *zB, int nB){ int nA = (int)strlen(zA); | | | > > > > | 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 | /* ** Both (const char*) arguments point to nul-terminated strings. Argument ** nB is the value of strlen(zB). This function returns 0 if the strings are ** identical, ignoring any trailing '/' character in either path. */ static int zipfileComparePath(const char *zA, const char *zB, int nB){ int nA = (int)strlen(zA); if( nA>0 && zA[nA-1]=='/' ) nA--; if( nB>0 && zB[nB-1]=='/' ) nB--; if( nA==nB && memcmp(zA, zB, nA)==0 ) return 0; return 1; } static int zipfileBegin(sqlite3_vtab *pVtab){ ZipfileTab *pTab = (ZipfileTab*)pVtab; int rc = SQLITE_OK; assert( pTab->pWriteFd==0 ); if( pTab->zFile==0 || pTab->zFile[0]==0 ){ pTab->base.zErrMsg = sqlite3_mprintf("zipfile: missing filename"); return SQLITE_ERROR; } /* Open a write fd on the file. Also load the entire central directory ** structure into memory. During the transaction any new file data is ** appended to the archive file, but the central directory is accumulated ** in main-memory until the transaction is committed. */ pTab->pWriteFd = fopen(pTab->zFile, "ab+"); if( pTab->pWriteFd==0 ){ |
︙ | ︙ | |||
1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 | /* ** Return the current time as a 32-bit timestamp in UNIX epoch format (like ** time(2)). */ static u32 zipfileTime(void){ sqlite3_vfs *pVfs = sqlite3_vfs_find(0); u32 ret; if( pVfs->iVersion>=2 && pVfs->xCurrentTimeInt64 ){ i64 ms; pVfs->xCurrentTimeInt64(pVfs, &ms); ret = (u32)((ms/1000) - ((i64)24405875 * 8640)); }else{ double day; pVfs->xCurrentTime(pVfs, &day); | > | 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 | /* ** Return the current time as a 32-bit timestamp in UNIX epoch format (like ** time(2)). */ static u32 zipfileTime(void){ sqlite3_vfs *pVfs = sqlite3_vfs_find(0); u32 ret; if( pVfs==0 ) return 0; if( pVfs->iVersion>=2 && pVfs->xCurrentTimeInt64 ){ i64 ms; pVfs->xCurrentTimeInt64(pVfs, &ms); ret = (u32)((ms/1000) - ((i64)24405875 * 8640)); }else{ double day; pVfs->xCurrentTime(pVfs, &day); |
︙ | ︙ | |||
1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 | if( rc==SQLITE_OK ){ rc = zipfileGetMode(apVal[3], bIsDir, &mode, &pTab->base.zErrMsg); } if( rc==SQLITE_OK ){ zPath = (const char*)sqlite3_value_text(apVal[2]); nPath = (int)strlen(zPath); mTime = zipfileGetTime(apVal[4]); } if( rc==SQLITE_OK && bIsDir ){ /* For a directory, check that the last character in the path is a ** '/'. This appears to be required for compatibility with info-zip ** (the unzip command on unix). It does not create directories ** otherwise. */ | > | < > > | > > > | 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 | if( rc==SQLITE_OK ){ rc = zipfileGetMode(apVal[3], bIsDir, &mode, &pTab->base.zErrMsg); } if( rc==SQLITE_OK ){ zPath = (const char*)sqlite3_value_text(apVal[2]); if( zPath==0 ) zPath = ""; nPath = (int)strlen(zPath); mTime = zipfileGetTime(apVal[4]); } if( rc==SQLITE_OK && bIsDir ){ /* For a directory, check that the last character in the path is a ** '/'. This appears to be required for compatibility with info-zip ** (the unzip command on unix). It does not create directories ** otherwise. */ if( nPath<=0 || zPath[nPath-1]!='/' ){ zFree = sqlite3_mprintf("%s/", zPath); zPath = (const char*)zFree; if( zFree==0 ){ rc = SQLITE_NOMEM; nPath = 0; }else{ nPath = (int)strlen(zPath); } } } /* Check that we're not inserting a duplicate entry -OR- updating an ** entry with a path, thereby making it into a duplicate. */ if( (pOld==0 || bUpdate) && rc==SQLITE_OK ){ ZipfileEntry *p; |
︙ | ︙ | |||
1893 1894 1895 1896 1897 1898 1899 | ZipfileBuffer body; ZipfileBuffer cds; }; static int zipfileBufferGrow(ZipfileBuffer *pBuf, int nByte){ if( pBuf->n+nByte>pBuf->nAlloc ){ u8 *aNew; | | | | | 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 | ZipfileBuffer body; ZipfileBuffer cds; }; static int zipfileBufferGrow(ZipfileBuffer *pBuf, int nByte){ if( pBuf->n+nByte>pBuf->nAlloc ){ u8 *aNew; sqlite3_int64 nNew = pBuf->n ? pBuf->n*2 : 512; int nReq = pBuf->n + nByte; while( nNew<nReq ) nNew = nNew*2; aNew = sqlite3_realloc64(pBuf->a, nNew); if( aNew==0 ) return SQLITE_NOMEM; pBuf->a = aNew; pBuf->nAlloc = (int)nNew; } return SQLITE_OK; } /* ** xStep() callback for the zipfile() aggregate. This can be called in ** any of the following ways: |
︙ | ︙ | |||
2020 2021 2022 2023 2024 2025 2026 | /* Decode the "mtime" argument. */ e.mUnixTime = zipfileGetTime(pMtime); /* If this is a directory entry, ensure that there is exactly one '/' ** at the end of the path. Or, if this is not a directory and the path ** ends in '/' it is an error. */ if( bIsDir==0 ){ | | | < > | 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 | /* Decode the "mtime" argument. */ e.mUnixTime = zipfileGetTime(pMtime); /* If this is a directory entry, ensure that there is exactly one '/' ** at the end of the path. Or, if this is not a directory and the path ** ends in '/' it is an error. */ if( bIsDir==0 ){ if( nName>0 && zName[nName-1]=='/' ){ zErr = sqlite3_mprintf("non-directory name must not end with /"); rc = SQLITE_ERROR; goto zipfile_step_out; } }else{ if( nName==0 || zName[nName-1]!='/' ){ zName = zFree = sqlite3_mprintf("%s/", zName); if( zName==0 ){ rc = SQLITE_NOMEM; goto zipfile_step_out; } nName = (int)strlen(zName); }else{ while( nName>1 && zName[nName-2]=='/' ) nName--; } } /* Assemble the ZipfileEntry object for the new zip archive entry */ e.cds.iVersionMadeBy = ZIPFILE_NEWENTRY_MADEBY; |
︙ | ︙ | |||
2091 2092 2093 2094 2095 2096 2097 | /* ** xFinalize() callback for zipfile aggregate function. */ void zipfileFinal(sqlite3_context *pCtx){ ZipfileCtx *p; ZipfileEOCD eocd; | | | | | 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 2142 2143 2144 2145 2146 | /* ** xFinalize() callback for zipfile aggregate function. */ void zipfileFinal(sqlite3_context *pCtx){ ZipfileCtx *p; ZipfileEOCD eocd; sqlite3_int64 nZip; u8 *aZip; p = (ZipfileCtx*)sqlite3_aggregate_context(pCtx, sizeof(ZipfileCtx)); if( p==0 ) return; if( p->nEntry>0 ){ memset(&eocd, 0, sizeof(eocd)); eocd.nEntry = (u16)p->nEntry; eocd.nEntryTotal = (u16)p->nEntry; eocd.nSize = p->cds.n; eocd.iOffset = p->body.n; nZip = p->body.n + p->cds.n + ZIPFILE_EOCD_FIXED_SZ; aZip = (u8*)sqlite3_malloc64(nZip); if( aZip==0 ){ sqlite3_result_error_nomem(pCtx); }else{ memcpy(aZip, p->body.a, p->body.n); memcpy(&aZip[p->body.n], p->cds.a, p->cds.n); zipfileSerializeEOCD(&eocd, &aZip[p->body.n + p->cds.n]); sqlite3_result_blob(pCtx, aZip, (int)nZip, zipfileFree); } } sqlite3_free(p->body.a); sqlite3_free(p->cds.a); } |
︙ | ︙ | |||
2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 | int rc = sqlite3_create_module(db, "zipfile" , &zipfileModule, 0); if( rc==SQLITE_OK ) rc = sqlite3_overload_function(db, "zipfile_cds", -1); if( rc==SQLITE_OK ){ rc = sqlite3_create_function(db, "zipfile", -1, SQLITE_UTF8, 0, 0, zipfileStep, zipfileFinal ); } return rc; } #else /* SQLITE_OMIT_VIRTUALTABLE */ # define zipfileRegister(x) SQLITE_OK #endif #ifdef _WIN32 | > > > > | 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 | int rc = sqlite3_create_module(db, "zipfile" , &zipfileModule, 0); if( rc==SQLITE_OK ) rc = sqlite3_overload_function(db, "zipfile_cds", -1); if( rc==SQLITE_OK ){ rc = sqlite3_create_function(db, "zipfile", -1, SQLITE_UTF8, 0, 0, zipfileStep, zipfileFinal ); } assert( sizeof(i64)==8 ); assert( sizeof(u32)==4 ); assert( sizeof(u16)==2 ); assert( sizeof(u8)==1 ); return rc; } #else /* SQLITE_OMIT_VIRTUALTABLE */ # define zipfileRegister(x) SQLITE_OK #endif #ifdef _WIN32 |
︙ | ︙ |
Changes to ext/rbu/rbu.c.
︙ | ︙ | |||
52 53 54 55 56 57 58 | "\n" , zArgv0); exit(1); } void report_default_vfs(){ sqlite3_vfs *pVfs = sqlite3_vfs_find(0); | | | 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | "\n" , zArgv0); exit(1); } void report_default_vfs(){ sqlite3_vfs *pVfs = sqlite3_vfs_find(0); fprintf(stdout, "default vfs is \"%s\"\n", pVfs ? pVfs->zName : "NULL"); } void report_rbu_vfs(sqlite3rbu *pRbu){ sqlite3 *db = sqlite3rbu_db(pRbu, 0); if( db ){ char *zName = 0; sqlite3_file_control(db, "main", SQLITE_FCNTL_VFSNAME, &zName); |
︙ | ︙ | |||
178 179 180 181 182 183 184 185 186 187 188 | fprintf(stdout, "%s", zBuf); break; default: fprintf(stderr, "error=%d: %s\n", rc, zErrmsg); break; } sqlite3_free(zErrmsg); return (rc==SQLITE_OK || rc==SQLITE_DONE) ? 0 : 1; } | > > > > > > > | 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 | fprintf(stdout, "%s", zBuf); break; default: fprintf(stderr, "error=%d: %s\n", rc, zErrmsg); break; } if( nStatStep>0 ){ sqlite3_int64 nUsed; sqlite3_int64 nHighwater; sqlite3_status64(SQLITE_STATUS_MEMORY_USED, &nUsed, &nHighwater, 0); fprintf(stdout, "memory used=%lld highwater=%lld\n", nUsed, nHighwater); } sqlite3_free(zErrmsg); return (rc==SQLITE_OK || rc==SQLITE_DONE) ? 0 : 1; } |
Changes to ext/rbu/rbu1.test.
︙ | ︙ | |||
128 129 130 131 132 133 134 135 136 137 138 139 140 141 | foreach {tn3 create_vfs destroy_vfs} { 1 {} {} 2 { sqlite3rbu_create_vfs -default myrbu "" } { sqlite3rbu_destroy_vfs myrbu } } { eval $create_vfs foreach {tn2 cmd} { 1 run_rbu 2 step_rbu 3 step_rbu_uri 4 step_rbu_state | > > > > > | 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 | foreach {tn3 create_vfs destroy_vfs} { 1 {} {} 2 { sqlite3rbu_create_vfs -default myrbu "" } { sqlite3rbu_destroy_vfs myrbu } 3 { sqlite3_register_cksumvfs } { sqlite3_unregister_cksumvfs } } { eval $create_vfs foreach {tn2 cmd} { 1 run_rbu 2 step_rbu 3 step_rbu_uri 4 step_rbu_state |
︙ | ︙ |
Changes to ext/rbu/rbu10.test.
︙ | ︙ | |||
46 47 48 49 50 51 52 | #-------------------------------------------------------------------- # Test that the hidden languageid column of an fts4 table can be # written. # ifcapable fts3 { do_execsql_test 2.0 { | | | 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | #-------------------------------------------------------------------- # Test that the hidden languageid column of an fts4 table can be # written. # ifcapable fts3 { do_execsql_test 2.0 { create virtual TABLE ft USING fts4(a, b, languageid='langid'); } do_test 2.1 { apply_rbu { CREATE TABLE data_ft(a, b, rbu_rowid, langid, rbu_control); INSERT INTO data_ft VALUES('a', 'b', 22, 1, 0); -- insert INSERT INTO data_ft VALUES('a', 'b', 23, 10, 0); -- insert INSERT INTO data_ft VALUES('a', 'b', 24, 100, 0); -- insert |
︙ | ︙ |
Changes to ext/rbu/rbu_common.tcl.
︙ | ︙ | |||
85 86 87 88 89 90 91 | } set rc } proc do_rbu_vacuum_test {tn step {statedb state.db}} { forcedelete $statedb if {$statedb=="" && $step==1} breakpoint | | | | | | 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 | } set rc } proc do_rbu_vacuum_test {tn step {statedb state.db}} { forcedelete $statedb if {$statedb=="" && $step==1} breakpoint uplevel [list do_test $tn.1 [string map [list %state% $statedb %step% $step] { if {%step%==0} { sqlite3rbu_vacuum rbu test.db {%state%}} while 1 { if {%step%==1} { sqlite3rbu_vacuum rbu test.db {%state%}} set state [rbu state] check_prestep_state test.db $state set rc [rbu step] check_poststep_state $rc test.db $state if {$rc!="SQLITE_OK"} break if {%step%==1} { rbu close } } rbu close }] {SQLITE_DONE}] uplevel [list do_execsql_test $tn.2 { PRAGMA integrity_check } ok] |
︙ | ︙ |
Changes to ext/rbu/rbudiff.test.
︙ | ︙ | |||
260 261 262 263 264 265 266 267 268 269 270 271 272 273 | } 3 { creAte virTUal tablE t1 USING FTs5(c); INSERT INTO t1 VALUES('a b c'); INSERT INTO t1 VALUES('a b c'); } { DELETE FROM t1 WHERE rowid = 1; INSERT INTO t1 VALUES('a b c'); } } { forcedelete test.db test.db2 | > > > > > > > > | 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 | } 3 { creAte virTUal tablE t1 USING FTs5(c); INSERT INTO t1 VALUES('a b c'); INSERT INTO t1 VALUES('a b c'); } { DELETE FROM t1 WHERE rowid = 1; INSERT INTO t1 VALUES('a b c'); } 4 { creAte virTUal tablE t1 USING FTs5(c); INSERT INTO t1 VALUES('a b c'); INSERT INTO t1 VALUES('a b c'); } { DELETE FROM t1 WHERE rowid = 1; INSERT INTO t1 VALUES('a b c'); } } { forcedelete test.db test.db2 |
︙ | ︙ |
Added ext/rbu/rbuexlock.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 | # 2021 November 06 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # source [file join [file dirname [info script]] rbu_common.tcl] set ::testprefix rbuexlock db close sqlite3_shutdown sqlite3_config_uri 1 # Create a simple RBU database. That expects to write to a table: # # CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c); # proc create_rbu {filename} { forcedelete $filename sqlite3 rbu1 $filename rbu1 eval { CREATE TABLE data_t1(a, b, c, rbu_control); INSERT INTO data_t1 VALUES(10, random(), random(), 0); INSERT INTO data_t1 VALUES(20, random(), random(), 0); INSERT INTO data_t1 VALUES(30, random(), random(), 0); INSERT INTO data_t1 VALUES(40, random(), random(), 0); INSERT INTO data_t1 VALUES(50, random(), random(), 0); INSERT INTO data_t1 VALUES(60, random(), random(), 0); INSERT INTO data_t1 VALUES(70, random(), random(), 0); INSERT INTO data_t1 VALUES(80, random(), random(), 0); } rbu1 close return $filename } reset_db do_execsql_test 1.0 { CREATE TABLE t1(a PRIMARY KEY, b INT, c INT); CREATE INDEX t1b ON t1(b); CREATE INDEX t1c ON t1(c); INSERT INTO t1 VALUES(1, 2, 3); } create_rbu rbu1.db do_test 1.1.0 { sqlite3rbu rbu file:test.db?rbu_exclusive_checkpoint=1 rbu1.db rbu step } SQLITE_OK do_catchsql_test 1.1.1 { SELECT * FROM t1 } {0 {1 2 3}} do_test 1.2.0 { for {set ii 0} {$ii < 10} {incr ii} { rbu step } rbu step } SQLITE_OK do_catchsql_test 1.2.1 { SELECT * FROM t1 } {0 {1 2 3}} do_test 1.2.2 { db eval {PRAGMA journal_mode} } {delete} do_test 1.3.0 { while {[file exists test.db-wal]==0} { rbu step } } {} do_catchsql_test 1.3.1 { SELECT * FROM t1 } {1 {database is locked}} do_test 1.3.2 { db eval {PRAGMA journal_mode} } {delete} do_test 1.4.0 { rbu step } SQLITE_OK do_catchsql_test 1.4.1 { SELECT * FROM t1 } {1 {database is locked}} do_test 1.4.2 { db eval {PRAGMA journal_mode} } {delete} rbu close do_test 1.5.0 { file exists test.db-wal } {1} do_test 1.5.1 { sqlite3rbu rbu file:test.db?rbu_exclusive_checkpoint=1 rbu1.db file exists test.db-wal } 1 do_catchsql_test 1.5.2 { SELECT * FROM t1 } {1 {database is locked}} do_test 1.5.2 { db eval {PRAGMA journal_mode} } {delete} do_test 1.6.0 { rbu step } SQLITE_OK do_catchsql_test 1.6.1 { SELECT * FROM t1 } {1 {database is locked}} do_test 1.6.2 { db eval {PRAGMA journal_mode} } {delete} do_test 1.7.0 { while {[rbu step]=="SQLITE_OK"} {} rbu close } SQLITE_DONE do_catchsql_test 1.7.2 { SELECT count(*) FROM t1 } {0 9} do_test 1.7.2 { db eval {PRAGMA journal_mode} } {delete} reset_db do_execsql_test 2.0 { CREATE TABLE t1(a PRIMARY KEY, b INT, c INT); CREATE INDEX t1b ON t1(b); CREATE INDEX t1c ON t1(c); INSERT INTO t1 VALUES(1, 2, 3); } create_rbu rbu1.db do_test 2.1.0 { sqlite3rbu rbu file:test.db?rbu_exclusive_checkpoint=0 rbu1.db rbu step } SQLITE_OK do_catchsql_test 2.1.1 { SELECT * FROM t1 } {0 {1 2 3}} do_test 2.2.0 { for {set ii 0} {$ii < 10} {incr ii} { rbu step } rbu step } SQLITE_OK do_catchsql_test 2.2.1 { SELECT * FROM t1 } {0 {1 2 3}} do_test 2.3.0 { while {[file exists test.db-wal]==0} { rbu step } } {} do_test 2.3.1 { llength [db eval {SELECT * FROM t1}] } {27} do_test 2.3.2 { db eval {PRAGMA journal_mode} } {wal} do_test 2.4.0 { rbu step } SQLITE_OK do_test 2.4.1 { llength [db eval {SELECT * FROM t1}] } {27} do_test 2.4.2 { db eval {PRAGMA journal_mode} } {wal} rbu close do_test 2.5.0 { db eval {PRAGMA journal_mode} } {wal} do_execsql_test 2.5.1 { DELETE FROM t1; } {} create_rbu rbu1.db do_test 3.1.0 { sqlite3rbu rbu file:test.db?rbu_exclusive_checkpoint=0 rbu1.db rbu step } SQLITE_ERROR do_test 3.1.1 { set rc [catch {rbu close} msg] lappend rc $msg } {1 {SQLITE_ERROR - cannot update wal mode database}} db eval {PRAGMA journal_mode=DELETE} create_rbu rbu1.db do_test 3.2.0 { sqlite3rbu rbu file:test.db?rbu_exclusive_checkpoint=0 rbu1.db rbu step } SQLITE_OK do_test 3.3.1 { set rc [catch {rbu close} msg] lappend rc $msg } {0 SQLITE_OK} db close create_rbu rbu1.db do_test 3.4.0 { sqlite3rbu rbu file:test.db?rbu_exclusive_checkpoint=0 rbu1.db rbu step } SQLITE_OK rbu close finish_test |
Added ext/rbu/rbuexpr.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 | # 2014 August 30 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # source [file join [file dirname [info script]] rbu_common.tcl] set ::testprefix rbuexpr db close sqlite3_shutdown sqlite3_config_uri 1 sqlite3 db test.db do_execsql_test 1.0 { CREATE TABLE t1(a, b, c PRIMARY KEY); CREATE INDEX i1 ON t1(a, null, b+1); CREATE INDEX i2 ON t1(a+1, b+1, c+1); INSERT INTO t1 VALUES(1, 2, 3); INSERT INTO t1 VALUES(4, 5, 6); INSERT INTO t1 VALUES(7, 8, 9); INSERT INTO t1 VALUES(10, 11, 12); PRAGMA integrity_check; } {ok} forcedelete rbu.db sqlite3 db2 rbu.db do_execsql_test -db db2 1.1 { CREATE TABLE data_t1(a, b, c, rbu_control); INSERT INTO data_t1 VALUES(13, 14, 15, 0); INSERT INTO data_t1 VALUES(NULL, NULL, 6, 1); INSERT INTO data_t1 VALUES(NULL, 'three', 3, '.x.'); } db2 close db close do_test 1.2 { run_rbu test.db rbu.db } {SQLITE_DONE} sqlite3 db test.db do_execsql_test 1.3 { SELECT * FROM t1 WHERE a=4; } integrity_check 1.4 #------------------------------------------------------------------------- # reset_db do_execsql_test 2.0 { CREATE TABLE t1(c1, c2, c3, i INTEGER PRIMARY KEY); INSERT INTO t1 VALUES('one', 'one', 'one', 1); INSERT INTO t1 VALUES('two', 'two', 'two', 2); INSERT INTO t1 VALUES('three', 'three', 'three', 3); INSERT INTO t1 VALUES('four', 'four', 'four', 4); CREATE INDEX i1 ON t1( substr(c1, 1, 2) ); CREATE INDEX i2 ON t1( c1 || c2 || c3 ); CREATE INDEX i3 ON t1( length(c1) + length(c2) - 1, c3||i ); } forcedelete rbu.db sqlite3 db2 rbu.db do_execsql_test -db db2 2.1 { CREATE TABLE data_t1(c1, c2, c3, i, rbu_control); INSERT INTO data_t1 VALUES(NULL, NULL, NULL, 2, 1); INSERT INTO data_t1 VALUES('thirty', NULL, NULL, 3, 'xx..'); INSERT INTO data_t1 VALUES('five', 'five', 'five', 5, 0); } db2 close db close do_test 2.2 { run_rbu test.db rbu.db } {SQLITE_DONE} sqlite3 db test.db integrity_check 2.3 finish_test |
Changes to ext/rbu/rbufault2.test.
︙ | ︙ | |||
48 49 50 51 52 53 54 55 56 57 | {1 SQLITE_CONSTRAINT} \ {1 SQLITE_NOMEM} \ {1 {SQLITE_NOMEM - unable to open a temporary database file for storing temporary tables}} \ {1 {SQLITE_NOMEM - out of memory}} } finish_test | > > > > > > > > > | 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | {1 SQLITE_CONSTRAINT} \ {1 SQLITE_NOMEM} \ {1 {SQLITE_NOMEM - unable to open a temporary database file for storing temporary tables}} \ {1 {SQLITE_NOMEM - out of memory}} } sqlite3rbu_create_vfs -default rbu "" sqlite3 db test.db set ::vfsname [file_control_vfsname db] do_faultsim_test 2 -faults oom* -prep { } -body { file_control_vfsname db } db close sqlite3rbu_destroy_vfs rbu finish_test |
Changes to ext/rbu/rbufault3.test.
︙ | ︙ | |||
79 80 81 82 83 84 85 | sqlite3rbu_vacuum rbu test.db test.db2 rbu step rbu close faultsim_save_and_close do_faultsim_test 3 -faults $fault -prep { faultsim_restore_and_reopen | < < | 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 | sqlite3rbu_vacuum rbu test.db test.db2 rbu step rbu close faultsim_save_and_close do_faultsim_test 3 -faults $fault -prep { faultsim_restore_and_reopen } -body { sqlite3rbu_vacuum rbu test.db test.db2 rbu step rbu close } -test { eval [list faultsim_test_result {0 SQLITE_OK} {*}$::errlist] } } finish_test |
Added ext/rbu/rbumisc.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 | # 2014 August 30 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # source [file join [file dirname [info script]] rbu_common.tcl] set ::testprefix rbumisc db close sqlite3_shutdown sqlite3_config_uri 1 reset_db proc populate_rbu_db {} { forcedelete rbu.db sqlite3 rbu rbu.db rbu eval { CREATE TABLE data_x1(a, b, c, rbu_control); INSERT INTO data_x1 VALUES(1, 1, 1, 0); INSERT INTO data_x1 VALUES(2, 2, 2, 0); CREATE TABLE dat(a, b, c, rbu_control); CREATE TABLE "data x1"(a, b, c, rbu_control); CREATE TABLE datax1(a, b, c, rbu_control); CREATE TABLE data_(a, b, c, rbu_control); INSERT INTO "data x1" VALUES(3, 3, 3, 0); INSERT INTO datax1 VALUES(3, 3, 3, 0); INSERT INTO data_ VALUES(3, 3, 3, 0); INSERT INTO dat VALUES(3, 3, 3, 0); } rbu close } #------------------------------------------------------------------------- # Ensure that RBU is not confused by oddly named tables in an RBU # database. # do_execsql_test 1.0 { CREATE TABLE x1(a, b, c INTEGER PRIMARY KEY); } do_test 1.1 { populate_rbu_db } {} do_test 1.2 { step_rbu test.db rbu.db db eval { SELECT * FROM x1 } } {1 1 1 2 2 2} do_test 1.3 { db eval { DELETE FROM x1 } sqlite3 rbu rbu.db rbu eval { DELETE FROM rbu_state } rbu close step_rbu test.db rbu.db db eval { SELECT * FROM x1 } } {1 1 1 2 2 2} do_test 1.4 { db eval { DELETE FROM x1 } populate_rbu_db sqlite3rbu rbu test.db rbu.db rbu step rbu step rbu close forcecopy test.db-oal test.db-wal sqlite3rbu rbu test.db rbu.db rbu step list [catch { rbu close } msg] $msg } {1 {SQLITE_ERROR - cannot update wal mode database}} #------------------------------------------------------------------------- # Test the effect of a wal file appearing after the target database has # been opened, but before it has been locked. # catch { db close } testvfs tvfs -default 1 for {set N 1} {$N < 10} {incr N} { reset_db populate_rbu_db do_execsql_test 2.$N.0 { CREATE TABLE x1(a, b, c INTEGER PRIMARY KEY); } set nAccessCnt 0 do_test 2.$N.1 { sqlite3rbu rbu test.db rbu.db rbu step rbu step rbu close } {SQLITE_OK} tvfs script xAccess tvfs filter xAccess set nAccessCnt 0 proc xAccess {method file args} { global nAccessCnt if {[file tail $file]=="test.db-wal"} { incr nAccessCnt -1 if {$nAccessCnt==0} { set fd [open test.db-wal w] puts -nonewline $fd [string repeat 0 2000] close $fd } } return SQLITE_OK } foreach r { {1 {SQLITE_ERROR - cannot update wal mode database}} {0 SQLITE_OK} {1 {SQLITE_CANTOPEN - unable to open database file}} } { set RES($r) 1 } do_test 2.$N.2 { set ::nAccessCnt $N set res [list [catch { sqlite3rbu rbu test.db rbu.db rbu step rbu close } msg ] $msg] set RES($res) } {1} catch {rbu close} } catch {db close} catch {tvfs delete} #------------------------------------------------------------------------- testvfs tvfs -default 1 reset_db populate_rbu_db do_execsql_test 3.0 { CREATE TABLE x1(a, b, c INTEGER PRIMARY KEY); } tvfs script xFileControl tvfs filter xFileControl proc xFileControl {method file verb args} { if {$verb=="ZIPVFS" && [info exists ::zipvfs_filecontrol]} { return $::zipvfs_filecontrol } return "SQLITE_NOTFOUND" } breakpoint foreach {tn ret err} { 1 SQLITE_OK 0 2 SQLITE_ERROR 1 3 SQLITE_NOTFOUND 0 4 SQLITE_OMIT 1 } { set ::zipvfs_filecontrol $ret do_test 3.$tn.1 { catch { sqlite3rbu rbu test.db rbu.db rbu step rbu close } } $err } catch {db close} catch {tvfs delete} #------------------------------------------------------------------------- finish_test |
Added ext/rbu/rbupartial.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 | # 2019 April 11 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # source [file join [file dirname [info script]] rbu_common.tcl] set ::testprefix rbupartial db close sqlite3_shutdown sqlite3_config_uri 1 foreach {tn without_rowid a b c d} { 1 "" a b c d 2 "WITHOUT ROWID" aaa bbb ccc ddd 3 "WITHOUT ROWID" "\"hello\"" {"one'two"} {[c]} ddd 4 "WITHOUT ROWID" {`a b`} {"one'two"} {[c c c]} ddd 5 "" a b c {"d""d"} 6 "" {'one''two'} b {"c""c"} {"d""d"} } { eval [string map [list \ %WITHOUT_ROWID% $without_rowid %A% $a %B% $b %C% $c %D% $d ] { reset_db do_execsql_test $tn.1.0 { CREATE TABLE t1(%A% PRIMARY KEY, %B%, %C%, %D%) %WITHOUT_ROWID% ; CREATE INDEX i1b ON t1(%B%); CREATE INDEX i1b2 ON t1(%B%) WHERE %C%<5; CREATE INDEX i1b3 ON t1(%B%) WHERE %C%>=5; CREATE INDEX i1c ON t1(%C%); CREATE INDEX i1c2 ON t1(%C%) WHERE %C% IS NULL; CREATE INDEX i1c3 ON t1(%C%) WHERE %C% IS NOT NULL; CREATE INDEX i1c4 ON t1(%C%) WHERE %D% < 'd'; CREATE INDEX i1c5 ON t1( %C% -- for (c = ... expressions ) WHERE %D% < 'd'; CREATE INDEX i1c6 ON t1( %C% /* Again, for (c=... expr */, %D% ) WHERE %D% < 'd'; CREATE INDEX i1c7 ON t1( %C% /* As before, for (c=... "expr */) WHERE %D% < 'd'; } do_execsql_test $tn.1.1 { INSERT INTO t1 VALUES(0, NULL, NULL, 'a'); INSERT INTO t1 VALUES(1, 2, 3, 'b'); INSERT INTO t1 VALUES(4, 5, 6, 'c'); INSERT INTO t1 VALUES(7, 8, 9, 'd'); } forcedelete rbu.db do_test $tn.1.2 { sqlite3 rbu rbu.db rbu eval { CREATE TABLE data_t1(%A%, %B%, %C%, %D%, rbu_control); INSERT INTO data_t1 VALUES(10, 11, 12, 'e', 0); INSERT INTO data_t1 VALUES(13, 14, NULL, 'f', 0); INSERT INTO data_t1 VALUES(0, NULL, NULL, NULL, 1); INSERT INTO data_t1 VALUES(4, NULL, NULL, NULL, 1); INSERT INTO data_t1 VALUES(7, NULL, 4, NULL, '..x.'); INSERT INTO data_t1 VALUES(1, 10, NULL, NULL, '.xx.'); } rbu close } {} do_test $tn.1.3 { run_rbu test.db rbu.db execsql { PRAGMA integrity_check } } {ok} do_execsql_test $tn.1.4 { SELECT * FROM t1 ORDER BY %A%; } { 1 10 {} b 7 8 4 d 10 11 12 e 13 14 {} f } set step 0 do_rbu_vacuum_test $tn.1.5 0 do_test $tn.1.6 { execsql { PRAGMA integrity_check } } {ok} }] } finish_test |
Changes to ext/rbu/rbuprogress.test.
︙ | ︙ | |||
409 410 411 412 413 414 415 416 417 418 | set R(nopk) $r1 set R(vtab) $r2 do_sp_test 5.$tn.$bReopen.$tn2.1 $bReopen test.db rbu.db $R($tn) } } } finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | set R(nopk) $r1 set R(vtab) $r2 do_sp_test 5.$tn.$bReopen.$tn2.1 $bReopen test.db rbu.db $R($tn) } } } #------------------------------------------------------------------------- # Test that sqlite3_bp_progress() works with an RBU vacuum if there # is an rbu_count table in the db being vacuumed. # reset_db do_execsql_test 6.0 { CREATE TABLE t1(a, b, c); CREATE INDEX i1 ON t1(a); CREATE INDEX i2 ON t1(b); WITH s(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<100 ) INSERT INTO t1 SELECT i, i, i FROM s; CREATE TABLE rbu_count(tbl TEXT PRIMARY KEY, cnt INTEGER) WITHOUT ROWID; INSERT INTO rbu_count VALUES('t1', (SELECT count(*) FROM t1)); INSERT INTO rbu_count VALUES('rbu_count', 2); } forcedelete state.db do_test 6.1 { set maxA 0 set maxB 0 sqlite3rbu_vacuum rbu test.db state.db while {[rbu step]=="SQLITE_OK"} { foreach {a b} [rbu bp_progress] { if {$a > $maxA} { set maxA $a } if {$b > $maxB} { set maxB $b } } } list [rbu close] $maxA $maxB } {SQLITE_DONE 10000 10000} finish_test |
Changes to ext/rbu/rbutemplimit.test.
︙ | ︙ | |||
61 62 63 64 65 66 67 68 69 70 71 72 73 74 | } proc step_rbu_cachesize {target rbu stepsize cachesize temp_limit} { set res "" while 1 { sqlite3rbu rbu $target $rbu rbu temp_size_limit $temp_limit sqlite3_exec_nr [rbu db 1] "PRAGMA cache_size = $cachesize" for {set i 0} {$i < $stepsize} {incr i} { set rc [rbu step] set ::A([rbu temp_size]) 1 if {$rc!="SQLITE_OK"} break } set res [list [catch {rbu close} msg] $msg] | > | 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 | } proc step_rbu_cachesize {target rbu stepsize cachesize temp_limit} { set res "" while 1 { sqlite3rbu rbu $target $rbu rbu temp_size_limit $temp_limit if { [rbu temp_size_limit -1]!=$temp_limit } { error "round trip problem!" } sqlite3_exec_nr [rbu db 1] "PRAGMA cache_size = $cachesize" for {set i 0} {$i < $stepsize} {incr i} { set rc [rbu step] set ::A([rbu temp_size]) 1 if {$rc!="SQLITE_OK"} break } set res [list [catch {rbu close} msg] $msg] |
︙ | ︙ |
Changes to ext/rbu/rbuvacuum2.test.
︙ | ︙ | |||
194 195 196 197 198 199 200 | do_test 5.$tn.1 { file attributes test.db -permissions $perm sqlite3rbu_vacuum rbu test.db rbu step } {SQLITE_OK} do_test 5.$tn.2 { file exists test.db-vacuum } 1 | > > > > | | 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 | do_test 5.$tn.1 { file attributes test.db -permissions $perm sqlite3rbu_vacuum rbu test.db rbu step } {SQLITE_OK} do_test 5.$tn.2 { file exists test.db-vacuum } 1 # The result pattern might be 00xxx or 0oxxx depending on which # version of TCL is being used. So make perm2 into a regexp that # will match either regsub {^00} $perm {0.} perm2 do_test 5.$tn.3 { file attributes test.db-vacuum -permissions} /$perm2/ rbu close } } #------------------------------------------------------------------------- # Test the outcome of some other connection running a checkpoint while # the incremental checkpoint is suspended. |
︙ | ︙ |
Added ext/rbu/rbuvacuum3.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 | # 2019 Jan 3 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # # This file contains tests for the RBU module. More specifically, it # contains tests to ensure that the sqlite3rbu_vacuum() API works as # expected. # source [file join [file dirname [info script]] rbu_common.tcl] set testprefix rbuvacuum3 do_execsql_test 1.0 { CREATE TABLE t1(a PRIMARY KEY, b, c); CREATE INDEX i1b ON t1(b); CREATE INDEX i1c ON t1(c); WITH s(i) AS ( VALUES(1) UNION ALL SELECT i+1 FROM s WHERE i<100 ) INSERT INTO t1 SELECT i, randomblob(100), randomblob(100) FROM s; } forcedelete state.db do_test 1.1 { sqlite3rbu_vacuum rbu test.db state.db while {1} { set rc [rbu step] if {$rc!="SQLITE_OK"} break rbu savestate } rbu close } {SQLITE_DONE} do_test 1.2 { sqlite3rbu_vacuum rbu test.db state.db while {1} { set rc [rbu step] if {$rc!="SQLITE_OK"} break rbu savestate } rbu close } {SQLITE_DONE} do_test 1.3 { while {1} { sqlite3rbu_vacuum rbu test.db state.db set rc [rbu step] if {$rc!="SQLITE_OK"} break rbu savestate rbu close } rbu close } {SQLITE_DONE} finish_test |
Added ext/rbu/rbuvacuum4.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 | # 2019 Jan 3 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # # This file contains tests for the RBU module. More specifically, it # contains tests to ensure that the sqlite3rbu_vacuum() API works as # expected. # source [file join [file dirname [info script]] rbu_common.tcl] set testprefix rbuvacuum4 set step 1 do_execsql_test 1.0 { CREATE TABLE t1(a PRIMARY KEY, b, c) WITHOUT ROWID; INSERT INTO t1 VALUES(1, 2, 3); INSERT INTO t1 VALUES(4, 5, 6); INSERT INTO t1 VALUES(7, 8, 9); } do_rbu_vacuum_test 1.1 1 #------------------------------------------------------------------------- reset_db do_execsql_test 2.0 { CREATE TABLE t1(a, b, c, PRIMARY KEY(a, b, c)) WITHOUT ROWID; INSERT INTO t1 VALUES(1, 2, 3); INSERT INTO t1 VALUES(4, 5, 6); INSERT INTO t1 VALUES(7, 8, 9); } do_rbu_vacuum_test 2.1 1 do_execsql_test 2.2 { SELECT * FROM t1; } {1 2 3 4 5 6 7 8 9} #------------------------------------------------------------------------- reset_db do_execsql_test 3.0 { CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c); CREATE INDEX i1 oN t1(b, c); INSERT INTO t1 VALUES(1, 2, 3); INSERT INTO t1 VALUES(4, 5, 6); INSERT INTO t1 VALUES(7, 8, 9); CREATE TABLE t2(a, b, c INTEGER, PRIMARY KEY(c)); CREATE INDEX i2 oN t2(b, a); INSERT INTO t2 VALUES('a', 'b', -1); INSERT INTO t2 VALUES('c', 'd', -2); INSERT INTO t2 VALUES('e', 'f', -3); } do_rbu_vacuum_test 3.1 1 do_execsql_test 3.2 { SELECT * FROM t1; SELECT * FROM t2; } {1 2 3 4 5 6 7 8 9 e f -3 c d -2 a b -1} #------------------------------------------------------------------------- reset_db do_execsql_test 4.0 { CREATE TABLE x1(a, b, c, d, PRIMARY KEY(c, b)) WITHOUT ROWID; INSERT INTO x1 VALUES(1, 1, 1, 1); INSERT INTO x1 VALUES(1, 1, 2, 1); INSERT INTO x1 VALUES(1, 2, 2, 1); INSERT INTO x1 VALUES(NULL, 2, 3, NULL); INSERT INTO x1 VALUES(NULL, 2, 4, NULL); INSERT INTO x1 VALUES(NULL, 2, 5, NULL); CREATE INDEX x1ad ON x1(d, a); CREATE INDEX x1null ON x1(d, a) WHERE d>15; } do_rbu_vacuum_test 4.1.1 1 do_execsql_test 4.2 { SELECT count(*) fROM x1 } 6 do_rbu_vacuum_test 4.1.2 0 #------------------------------------------------------------------------- reset_db do_execsql_test 5.0 { CREATE TABLE "a b c"(a, "b b" PRIMARY KEY, "c c"); CREATE INDEX abc1 ON "a b c"(a, "c c"); INSERT INTO "a b c" VALUES(NULL, 'a', NULL); INSERT INTO "a b c" VALUES(NULL, 'b', NULL); INSERT INTO "a b c" VALUES(NULL, 'c', NULL); INSERT INTO "a b c" VALUES(1, 2, 3); INSERT INTO "a b c" VALUES(3, 9, 1); INSERT INTO "a b c" VALUES('aaa', 'bbb', 'ccc'); CREATE INDEX abc2 ON "a b c"("c c" DESC, a); CREATE TABLE x(a); INSERT INTO x VALUES('a'), ('b'), ('d'); CREATE UNIQUE INDEX y ON x(a); } do_rbu_vacuum_test 5.1 1 finish_test |
Changes to ext/rbu/sqlite3rbu.c.
︙ | ︙ | |||
105 106 107 108 109 110 111 112 113 114 115 116 117 118 | /* ** Swap two objects of type TYPE. */ #if !defined(SQLITE_AMALGAMATION) # define SWAP(TYPE,A,B) {TYPE t=A; A=B; B=t;} #endif /* ** The rbu_state table is used to save the state of a partially applied ** update so that it can be resumed later. The table consists of integer ** keys mapped to values as follows: ** ** RBU_STATE_STAGE: | > > > > > > > | 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 | /* ** Swap two objects of type TYPE. */ #if !defined(SQLITE_AMALGAMATION) # define SWAP(TYPE,A,B) {TYPE t=A; A=B; B=t;} #endif /* ** Name of the URI option that causes RBU to take an exclusive lock as ** part of the incremental checkpoint operation. */ #define RBU_EXCLUSIVE_CHECKPOINT "rbu_exclusive_checkpoint" /* ** The rbu_state table is used to save the state of a partially applied ** update so that it can be resumed later. The table consists of integer ** keys mapped to values as follows: ** ** RBU_STATE_STAGE: |
︙ | ︙ | |||
178 179 180 181 182 183 184 185 186 187 188 189 190 191 | #define RBU_CREATE_STATE \ "CREATE TABLE IF NOT EXISTS %s.rbu_state(k INTEGER PRIMARY KEY, v)" typedef struct RbuFrame RbuFrame; typedef struct RbuObjIter RbuObjIter; typedef struct RbuState RbuState; typedef struct rbu_vfs rbu_vfs; typedef struct rbu_file rbu_file; typedef struct RbuUpdateStmt RbuUpdateStmt; #if !defined(SQLITE_AMALGAMATION) typedef unsigned int u32; typedef unsigned short u16; | > | 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 | #define RBU_CREATE_STATE \ "CREATE TABLE IF NOT EXISTS %s.rbu_state(k INTEGER PRIMARY KEY, v)" typedef struct RbuFrame RbuFrame; typedef struct RbuObjIter RbuObjIter; typedef struct RbuState RbuState; typedef struct RbuSpan RbuSpan; typedef struct rbu_vfs rbu_vfs; typedef struct rbu_file rbu_file; typedef struct RbuUpdateStmt RbuUpdateStmt; #if !defined(SQLITE_AMALGAMATION) typedef unsigned int u32; typedef unsigned short u16; |
︙ | ︙ | |||
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 | struct RbuUpdateStmt { char *zMask; /* Copy of update mask used with pUpdate */ sqlite3_stmt *pUpdate; /* Last update statement (or NULL) */ RbuUpdateStmt *pNext; }; /* ** An iterator of this type is used to iterate through all objects in ** the target database that require updating. For each such table, the ** iterator visits, in order: ** ** * the table itself, ** * each index of the table (zero or more points to visit), and ** * a special "cleanup table" state. ** ** abIndexed: ** If the table has no indexes on it, abIndexed is set to NULL. Otherwise, ** it points to an array of flags nTblCol elements in size. The flag is ** set for each column that is either a part of the PK or a part of an ** index. Or clear otherwise. ** */ struct RbuObjIter { sqlite3_stmt *pTblIter; /* Iterate through tables */ sqlite3_stmt *pIdxIter; /* Index iterator */ int nTblCol; /* Size of azTblCol[] array */ char **azTblCol; /* Array of unquoted target column names */ | > > > > > > > > > > | 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 | struct RbuUpdateStmt { char *zMask; /* Copy of update mask used with pUpdate */ sqlite3_stmt *pUpdate; /* Last update statement (or NULL) */ RbuUpdateStmt *pNext; }; struct RbuSpan { const char *zSpan; int nSpan; }; /* ** An iterator of this type is used to iterate through all objects in ** the target database that require updating. For each such table, the ** iterator visits, in order: ** ** * the table itself, ** * each index of the table (zero or more points to visit), and ** * a special "cleanup table" state. ** ** abIndexed: ** If the table has no indexes on it, abIndexed is set to NULL. Otherwise, ** it points to an array of flags nTblCol elements in size. The flag is ** set for each column that is either a part of the PK or a part of an ** index. Or clear otherwise. ** ** If there are one or more partial indexes on the table, all fields of ** this array set set to 1. This is because in that case, the module has ** no way to tell which fields will be required to add and remove entries ** from the partial indexes. ** */ struct RbuObjIter { sqlite3_stmt *pTblIter; /* Iterate through tables */ sqlite3_stmt *pIdxIter; /* Index iterator */ int nTblCol; /* Size of azTblCol[] array */ char **azTblCol; /* Array of unquoted target column names */ |
︙ | ︙ | |||
266 267 268 269 270 271 272 273 274 275 276 277 278 279 | /* Statements created by rbuObjIterPrepareAll() */ int nCol; /* Number of columns in current object */ sqlite3_stmt *pSelect; /* Source data */ sqlite3_stmt *pInsert; /* Statement for INSERT operations */ sqlite3_stmt *pDelete; /* Statement for DELETE ops */ sqlite3_stmt *pTmpInsert; /* Insert into rbu_tmp_$zDataTbl */ /* Last UPDATE used (for PK b-tree updates only), or NULL. */ RbuUpdateStmt *pRbuUpdate; }; /* ** Values for RbuObjIter.eType | > > > | 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 | /* Statements created by rbuObjIterPrepareAll() */ int nCol; /* Number of columns in current object */ sqlite3_stmt *pSelect; /* Source data */ sqlite3_stmt *pInsert; /* Statement for INSERT operations */ sqlite3_stmt *pDelete; /* Statement for DELETE ops */ sqlite3_stmt *pTmpInsert; /* Insert into rbu_tmp_$zDataTbl */ int nIdxCol; RbuSpan *aIdxCol; char *zIdxSql; /* Last UPDATE used (for PK b-tree updates only), or NULL. */ RbuUpdateStmt *pRbuUpdate; }; /* ** Values for RbuObjIter.eType |
︙ | ︙ | |||
680 681 682 683 684 685 686 687 688 689 690 691 692 693 | aOut = sqlite3_malloc(nOut+1); if( aOut==0 ){ sqlite3_result_error_nomem(context); }else{ nOut2 = rbuDeltaApply(aOrig, nOrig, aDelta, nDelta, aOut); if( nOut2!=nOut ){ sqlite3_result_error(context, "corrupt fossil delta", -1); }else{ sqlite3_result_blob(context, aOut, nOut, sqlite3_free); } } } | > | 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 | aOut = sqlite3_malloc(nOut+1); if( aOut==0 ){ sqlite3_result_error_nomem(context); }else{ nOut2 = rbuDeltaApply(aOrig, nOrig, aDelta, nDelta, aOut); if( nOut2!=nOut ){ sqlite3_free(aOut); sqlite3_result_error(context, "corrupt fossil delta", -1); }else{ sqlite3_result_blob(context, aOut, nOut, sqlite3_free); } } } |
︙ | ︙ | |||
799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 | pUp = pIter->pRbuUpdate; while( pUp ){ RbuUpdateStmt *pTmp = pUp->pNext; sqlite3_finalize(pUp->pUpdate); sqlite3_free(pUp); pUp = pTmp; } pIter->pSelect = 0; pIter->pInsert = 0; pIter->pDelete = 0; pIter->pRbuUpdate = 0; pIter->pTmpInsert = 0; pIter->nCol = 0; } /* ** Clean up any resources allocated as part of the iterator object passed ** as the only argument. */ static void rbuObjIterFinalize(RbuObjIter *pIter){ | > > > > > | 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 | pUp = pIter->pRbuUpdate; while( pUp ){ RbuUpdateStmt *pTmp = pUp->pNext; sqlite3_finalize(pUp->pUpdate); sqlite3_free(pUp); pUp = pTmp; } sqlite3_free(pIter->aIdxCol); sqlite3_free(pIter->zIdxSql); pIter->pSelect = 0; pIter->pInsert = 0; pIter->pDelete = 0; pIter->pRbuUpdate = 0; pIter->pTmpInsert = 0; pIter->nCol = 0; pIter->nIdxCol = 0; pIter->aIdxCol = 0; pIter->zIdxSql = 0; } /* ** Clean up any resources allocated as part of the iterator object passed ** as the only argument. */ static void rbuObjIterFinalize(RbuObjIter *pIter){ |
︙ | ︙ | |||
920 921 922 923 924 925 926 927 928 929 930 931 932 933 | sqlite3rbu *p = sqlite3_user_data(pCtx); const char *zIn; assert( argc==1 || argc==2 ); zIn = (const char*)sqlite3_value_text(argv[0]); if( zIn ){ if( rbuIsVacuum(p) ){ if( argc==1 || 0==sqlite3_value_int(argv[1]) ){ sqlite3_result_text(pCtx, zIn, -1, SQLITE_STATIC); } }else{ if( strlen(zIn)>4 && memcmp("data", zIn, 4)==0 ){ int i; for(i=4; zIn[i]>='0' && zIn[i]<='9'; i++); | > | 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 | sqlite3rbu *p = sqlite3_user_data(pCtx); const char *zIn; assert( argc==1 || argc==2 ); zIn = (const char*)sqlite3_value_text(argv[0]); if( zIn ){ if( rbuIsVacuum(p) ){ assert( argc==2 || argc==1 ); if( argc==1 || 0==sqlite3_value_int(argv[1]) ){ sqlite3_result_text(pCtx, zIn, -1, SQLITE_STATIC); } }else{ if( strlen(zIn)>4 && memcmp("data", zIn, 4)==0 ){ int i; for(i=4; zIn[i]>='0' && zIn[i]<='9'; i++); |
︙ | ︙ | |||
950 951 952 953 954 955 956 | static int rbuObjIterFirst(sqlite3rbu *p, RbuObjIter *pIter){ int rc; memset(pIter, 0, sizeof(RbuObjIter)); rc = prepareFreeAndCollectError(p->dbRbu, &pIter->pTblIter, &p->zErrmsg, sqlite3_mprintf( "SELECT rbu_target_name(name, type='view') AS target, name " | | | | 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 | static int rbuObjIterFirst(sqlite3rbu *p, RbuObjIter *pIter){ int rc; memset(pIter, 0, sizeof(RbuObjIter)); rc = prepareFreeAndCollectError(p->dbRbu, &pIter->pTblIter, &p->zErrmsg, sqlite3_mprintf( "SELECT rbu_target_name(name, type='view') AS target, name " "FROM sqlite_schema " "WHERE type IN ('table', 'view') AND target IS NOT NULL " " %s " "ORDER BY name" , rbuIsVacuum(p) ? "AND rootpage!=0 AND rootpage IS NOT NULL" : "")); if( rc==SQLITE_OK ){ rc = prepareAndCollectError(p->dbMain, &pIter->pIdxIter, &p->zErrmsg, "SELECT name, rootpage, sql IS NULL OR substr(8, 6)=='UNIQUE' " " FROM main.sqlite_schema " " WHERE type='index' AND tbl_name = ?" ); } pIter->bCleanup = 1; p->rc = rc; return rbuObjIterNext(p, pIter); |
︙ | ︙ | |||
1030 1031 1032 1033 1034 1035 1036 | ** ** If an error (i.e. an OOM condition) occurs, return NULL and leave an ** error code in the rbu handle passed as the first argument. Or, if an ** error has already occurred when this function is called, return NULL ** immediately without attempting the allocation or modifying the stored ** error code. */ | | | | 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 | ** ** If an error (i.e. an OOM condition) occurs, return NULL and leave an ** error code in the rbu handle passed as the first argument. Or, if an ** error has already occurred when this function is called, return NULL ** immediately without attempting the allocation or modifying the stored ** error code. */ static void *rbuMalloc(sqlite3rbu *p, sqlite3_int64 nByte){ void *pRet = 0; if( p->rc==SQLITE_OK ){ assert( nByte>0 ); pRet = sqlite3_malloc64(nByte); if( pRet==0 ){ p->rc = SQLITE_NOMEM; }else{ memset(pRet, 0, nByte); } } return pRet; } /* ** Allocate and zero the pIter->azTblCol[] and abTblPk[] arrays so that ** there is room for at least nCol elements. If an OOM occurs, store an ** error code in the RBU handle passed as the first argument. */ static void rbuAllocateIterArrays(sqlite3rbu *p, RbuObjIter *pIter, int nCol){ sqlite3_int64 nByte = (2*sizeof(char*) + sizeof(int) + 3*sizeof(u8)) * nCol; char **azNew; azNew = (char**)rbuMalloc(p, nByte); if( azNew ){ pIter->azTblCol = azNew; pIter->azTblType = &azNew[nCol]; pIter->aiSrcOrder = (int*)&pIter->azTblType[nCol]; |
︙ | ︙ | |||
1078 1079 1080 1081 1082 1083 1084 | ** If an OOM condition is encountered when attempting to allocate memory, ** output variable (*pRc) is set to SQLITE_NOMEM before returning. Otherwise, ** if the allocation succeeds, (*pRc) is left unchanged. */ static char *rbuStrndup(const char *zStr, int *pRc){ char *zRet = 0; | | | | | | | | | > | 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 | ** If an OOM condition is encountered when attempting to allocate memory, ** output variable (*pRc) is set to SQLITE_NOMEM before returning. Otherwise, ** if the allocation succeeds, (*pRc) is left unchanged. */ static char *rbuStrndup(const char *zStr, int *pRc){ char *zRet = 0; if( *pRc==SQLITE_OK ){ if( zStr ){ size_t nCopy = strlen(zStr) + 1; zRet = (char*)sqlite3_malloc64(nCopy); if( zRet ){ memcpy(zRet, zStr, nCopy); }else{ *pRc = SQLITE_NOMEM; } } } return zRet; } /* |
︙ | ︙ | |||
1130 1131 1132 1133 1134 1135 1136 | ** (i.e. unless *peType is set to 3), then *piPk is set to zero. Or, ** if the table does have an external primary key index, then *piPk ** is set to the root page number of the primary key index before ** returning. ** ** ALGORITHM: ** | | | | | | > > | | 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 | ** (i.e. unless *peType is set to 3), then *piPk is set to zero. Or, ** if the table does have an external primary key index, then *piPk ** is set to the root page number of the primary key index before ** returning. ** ** ALGORITHM: ** ** if( no entry exists in sqlite_schema ){ ** return RBU_PK_NOTABLE ** }else if( sql for the entry starts with "CREATE VIRTUAL" ){ ** return RBU_PK_VTAB ** }else if( "PRAGMA index_list()" for the table contains a "pk" index ){ ** if( the index that is the pk exists in sqlite_schema ){ ** *piPK = rootpage of that index. ** return RBU_PK_EXTERNAL ** }else{ ** return RBU_PK_WITHOUT_ROWID ** } ** }else if( "PRAGMA table_info()" lists one or more "pk" columns ){ ** return RBU_PK_IPK ** }else{ ** return RBU_PK_NONE ** } */ static void rbuTableType( sqlite3rbu *p, const char *zTab, int *peType, int *piTnum, int *piPk ){ /* ** 0) SELECT count(*) FROM sqlite_schema where name=%Q AND IsVirtual(%Q) ** 1) PRAGMA index_list = ? ** 2) SELECT count(*) FROM sqlite_schema where name=%Q ** 3) PRAGMA table_info = ? */ sqlite3_stmt *aStmt[4] = {0, 0, 0, 0}; *peType = RBU_PK_NOTABLE; *piPk = 0; assert( p->rc==SQLITE_OK ); p->rc = prepareFreeAndCollectError(p->dbMain, &aStmt[0], &p->zErrmsg, sqlite3_mprintf( "SELECT " " (sql COLLATE nocase BETWEEN 'CREATE VIRTUAL' AND 'CREATE VIRTUAM')," " rootpage" " FROM sqlite_schema" " WHERE name=%Q", zTab )); if( p->rc!=SQLITE_OK || sqlite3_step(aStmt[0])!=SQLITE_ROW ){ /* Either an error, or no such table. */ goto rbuTableType_end; } if( sqlite3_column_int(aStmt[0], 0) ){ |
︙ | ︙ | |||
1192 1193 1194 1195 1196 1197 1198 | if( p->rc ) goto rbuTableType_end; while( sqlite3_step(aStmt[1])==SQLITE_ROW ){ const u8 *zOrig = sqlite3_column_text(aStmt[1], 3); const u8 *zIdx = sqlite3_column_text(aStmt[1], 1); if( zOrig && zIdx && zOrig[0]=='p' ){ p->rc = prepareFreeAndCollectError(p->dbMain, &aStmt[2], &p->zErrmsg, sqlite3_mprintf( | | | 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 | if( p->rc ) goto rbuTableType_end; while( sqlite3_step(aStmt[1])==SQLITE_ROW ){ const u8 *zOrig = sqlite3_column_text(aStmt[1], 3); const u8 *zIdx = sqlite3_column_text(aStmt[1], 1); if( zOrig && zIdx && zOrig[0]=='p' ){ p->rc = prepareFreeAndCollectError(p->dbMain, &aStmt[2], &p->zErrmsg, sqlite3_mprintf( "SELECT rootpage FROM sqlite_schema WHERE name = %Q", zIdx )); if( p->rc==SQLITE_OK ){ if( sqlite3_step(aStmt[2])==SQLITE_ROW ){ *piPk = sqlite3_column_int(aStmt[2], 0); *peType = RBU_PK_EXTERNAL; }else{ *peType = RBU_PK_WITHOUT_ROWID; |
︙ | ︙ | |||
1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 | sqlite3_mprintf("PRAGMA main.index_list = %Q", pIter->zTbl) ); } pIter->nIndex = 0; while( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pList) ){ const char *zIdx = (const char*)sqlite3_column_text(pList, 1); sqlite3_stmt *pXInfo = 0; if( zIdx==0 ) break; p->rc = prepareFreeAndCollectError(p->dbMain, &pXInfo, &p->zErrmsg, sqlite3_mprintf("PRAGMA main.index_xinfo = %Q", zIdx) ); while( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pXInfo) ){ int iCid = sqlite3_column_int(pXInfo, 1); if( iCid>=0 ) pIter->abIndexed[iCid] = 1; } rbuFinalize(p, pXInfo); bIndex = 1; pIter->nIndex++; } if( pIter->eType==RBU_PK_WITHOUT_ROWID ){ | > > > > > > > | 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 | sqlite3_mprintf("PRAGMA main.index_list = %Q", pIter->zTbl) ); } pIter->nIndex = 0; while( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pList) ){ const char *zIdx = (const char*)sqlite3_column_text(pList, 1); int bPartial = sqlite3_column_int(pList, 4); sqlite3_stmt *pXInfo = 0; if( zIdx==0 ) break; if( bPartial ){ memset(pIter->abIndexed, 0x01, sizeof(u8)*pIter->nTblCol); } p->rc = prepareFreeAndCollectError(p->dbMain, &pXInfo, &p->zErrmsg, sqlite3_mprintf("PRAGMA main.index_xinfo = %Q", zIdx) ); while( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pXInfo) ){ int iCid = sqlite3_column_int(pXInfo, 1); if( iCid>=0 ) pIter->abIndexed[iCid] = 1; if( iCid==-2 ){ memset(pIter->abIndexed, 0x01, sizeof(u8)*pIter->nTblCol); } } rbuFinalize(p, pXInfo); bIndex = 1; pIter->nIndex++; } if( pIter->eType==RBU_PK_WITHOUT_ROWID ){ |
︙ | ︙ | |||
1367 1368 1369 1370 1371 1372 1373 | if( i!=iOrder ){ SWAP(int, pIter->aiSrcOrder[i], pIter->aiSrcOrder[iOrder]); SWAP(char*, pIter->azTblCol[i], pIter->azTblCol[iOrder]); } pIter->azTblType[iOrder] = rbuStrndup(zType, &p->rc); | > | | 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 | if( i!=iOrder ){ SWAP(int, pIter->aiSrcOrder[i], pIter->aiSrcOrder[iOrder]); SWAP(char*, pIter->azTblCol[i], pIter->azTblCol[iOrder]); } pIter->azTblType[iOrder] = rbuStrndup(zType, &p->rc); assert( iPk>=0 ); pIter->abTblPk[iOrder] = (u8)iPk; pIter->abNotNull[iOrder] = (u8)bNotNull || (iPk!=0); iOrder++; } } rbuFinalize(p, pStmt); rbuObjIterCacheIndexedCols(p, pIter); |
︙ | ︙ | |||
1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 | for(i=0; i<pIter->nTblCol; i++){ const char *z = pIter->azTblCol[i]; zList = rbuMPrintf(p, "%z%s\"%w\"", zList, zSep, z); zSep = ", "; } return zList; } /* ** This function is used to create a SELECT list (the list of SQL ** expressions that follows a SELECT keyword) for a SELECT statement ** used to read from an data_xxx or rbu_tmp_xxx table while updating the ** index object currently indicated by the iterator object passed as the ** second argument. A "PRAGMA index_xinfo = <idxname>" statement is used | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 | for(i=0; i<pIter->nTblCol; i++){ const char *z = pIter->azTblCol[i]; zList = rbuMPrintf(p, "%z%s\"%w\"", zList, zSep, z); zSep = ", "; } return zList; } /* ** Return a comma separated list of the quoted PRIMARY KEY column names, ** in order, for the current table. Before each column name, add the text ** zPre. After each column name, add the zPost text. Use zSeparator as ** the separator text (usually ", "). */ static char *rbuObjIterGetPkList( sqlite3rbu *p, /* RBU object */ RbuObjIter *pIter, /* Object iterator for column names */ const char *zPre, /* Before each quoted column name */ const char *zSeparator, /* Separator to use between columns */ const char *zPost /* After each quoted column name */ ){ int iPk = 1; char *zRet = 0; const char *zSep = ""; while( 1 ){ int i; for(i=0; i<pIter->nTblCol; i++){ if( (int)pIter->abTblPk[i]==iPk ){ const char *zCol = pIter->azTblCol[i]; zRet = rbuMPrintf(p, "%z%s%s\"%w\"%s", zRet, zSep, zPre, zCol, zPost); zSep = zSeparator; break; } } if( i==pIter->nTblCol ) break; iPk++; } return zRet; } /* ** This function is called as part of restarting an RBU vacuum within ** stage 1 of the process (while the *-oal file is being built) while ** updating a table (not an index). The table may be a rowid table or ** a WITHOUT ROWID table. It queries the target database to find the ** largest key that has already been written to the target table and ** constructs a WHERE clause that can be used to extract the remaining ** rows from the source table. For a rowid table, the WHERE clause ** is of the form: ** ** "WHERE _rowid_ > ?" ** ** and for WITHOUT ROWID tables: ** ** "WHERE (key1, key2) > (?, ?)" ** ** Instead of "?" placeholders, the actual WHERE clauses created by ** this function contain literal SQL values. */ static char *rbuVacuumTableStart( sqlite3rbu *p, /* RBU handle */ RbuObjIter *pIter, /* RBU iterator object */ int bRowid, /* True for a rowid table */ const char *zWrite /* Target table name prefix */ ){ sqlite3_stmt *pMax = 0; char *zRet = 0; if( bRowid ){ p->rc = prepareFreeAndCollectError(p->dbMain, &pMax, &p->zErrmsg, sqlite3_mprintf( "SELECT max(_rowid_) FROM \"%s%w\"", zWrite, pIter->zTbl ) ); if( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pMax) ){ sqlite3_int64 iMax = sqlite3_column_int64(pMax, 0); zRet = rbuMPrintf(p, " WHERE _rowid_ > %lld ", iMax); } rbuFinalize(p, pMax); }else{ char *zOrder = rbuObjIterGetPkList(p, pIter, "", ", ", " DESC"); char *zSelect = rbuObjIterGetPkList(p, pIter, "quote(", "||','||", ")"); char *zList = rbuObjIterGetPkList(p, pIter, "", ", ", ""); if( p->rc==SQLITE_OK ){ p->rc = prepareFreeAndCollectError(p->dbMain, &pMax, &p->zErrmsg, sqlite3_mprintf( "SELECT %s FROM \"%s%w\" ORDER BY %s LIMIT 1", zSelect, zWrite, pIter->zTbl, zOrder ) ); if( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pMax) ){ const char *zVal = (const char*)sqlite3_column_text(pMax, 0); zRet = rbuMPrintf(p, " WHERE (%s) > (%s) ", zList, zVal); } rbuFinalize(p, pMax); } sqlite3_free(zOrder); sqlite3_free(zSelect); sqlite3_free(zList); } return zRet; } /* ** This function is called as part of restating an RBU vacuum when the ** current operation is writing content to an index. If possible, it ** queries the target index b-tree for the largest key already written to ** it, then composes and returns an expression that can be used in a WHERE ** clause to select the remaining required rows from the source table. ** It is only possible to return such an expression if: ** ** * The index contains no DESC columns, and ** * The last key written to the index before the operation was ** suspended does not contain any NULL values. ** ** The expression is of the form: ** ** (index-field1, index-field2, ...) > (?, ?, ...) ** ** except that the "?" placeholders are replaced with literal values. ** ** If the expression cannot be created, NULL is returned. In this case, ** the caller has to use an OFFSET clause to extract only the required ** rows from the sourct table, just as it does for an RBU update operation. */ char *rbuVacuumIndexStart( sqlite3rbu *p, /* RBU handle */ RbuObjIter *pIter /* RBU iterator object */ ){ char *zOrder = 0; char *zLhs = 0; char *zSelect = 0; char *zVector = 0; char *zRet = 0; int bFailed = 0; const char *zSep = ""; int iCol = 0; sqlite3_stmt *pXInfo = 0; p->rc = prepareFreeAndCollectError(p->dbMain, &pXInfo, &p->zErrmsg, sqlite3_mprintf("PRAGMA main.index_xinfo = %Q", pIter->zIdx) ); while( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pXInfo) ){ int iCid = sqlite3_column_int(pXInfo, 1); const char *zCollate = (const char*)sqlite3_column_text(pXInfo, 4); const char *zCol; if( sqlite3_column_int(pXInfo, 3) ){ bFailed = 1; break; } if( iCid<0 ){ if( pIter->eType==RBU_PK_IPK ){ int i; for(i=0; pIter->abTblPk[i]==0; i++); assert( i<pIter->nTblCol ); zCol = pIter->azTblCol[i]; }else{ zCol = "_rowid_"; } }else{ zCol = pIter->azTblCol[iCid]; } zLhs = rbuMPrintf(p, "%z%s \"%w\" COLLATE %Q", zLhs, zSep, zCol, zCollate ); zOrder = rbuMPrintf(p, "%z%s \"rbu_imp_%d%w\" COLLATE %Q DESC", zOrder, zSep, iCol, zCol, zCollate ); zSelect = rbuMPrintf(p, "%z%s quote(\"rbu_imp_%d%w\")", zSelect, zSep, iCol, zCol ); zSep = ", "; iCol++; } rbuFinalize(p, pXInfo); if( bFailed ) goto index_start_out; if( p->rc==SQLITE_OK ){ sqlite3_stmt *pSel = 0; p->rc = prepareFreeAndCollectError(p->dbMain, &pSel, &p->zErrmsg, sqlite3_mprintf("SELECT %s FROM \"rbu_imp_%w\" ORDER BY %s LIMIT 1", zSelect, pIter->zTbl, zOrder ) ); if( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSel) ){ zSep = ""; for(iCol=0; iCol<pIter->nCol; iCol++){ const char *zQuoted = (const char*)sqlite3_column_text(pSel, iCol); if( zQuoted==0 ){ p->rc = SQLITE_NOMEM; }else if( zQuoted[0]=='N' ){ bFailed = 1; break; } zVector = rbuMPrintf(p, "%z%s%s", zVector, zSep, zQuoted); zSep = ", "; } if( !bFailed ){ zRet = rbuMPrintf(p, "(%s) > (%s)", zLhs, zVector); } } rbuFinalize(p, pSel); } index_start_out: sqlite3_free(zOrder); sqlite3_free(zSelect); sqlite3_free(zVector); sqlite3_free(zLhs); return zRet; } /* ** This function is used to create a SELECT list (the list of SQL ** expressions that follows a SELECT keyword) for a SELECT statement ** used to read from an data_xxx or rbu_tmp_xxx table while updating the ** index object currently indicated by the iterator object passed as the ** second argument. A "PRAGMA index_xinfo = <idxname>" statement is used |
︙ | ︙ | |||
1456 1457 1458 1459 1460 1461 1462 | ); } while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pXInfo) ){ int iCid = sqlite3_column_int(pXInfo, 1); int bDesc = sqlite3_column_int(pXInfo, 3); const char *zCollate = (const char*)sqlite3_column_text(pXInfo, 4); | | > > > > > > > | | | | | | | | | | | | | | | | | | > | | | 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 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 1744 1745 1746 1747 1748 | ); } while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pXInfo) ){ int iCid = sqlite3_column_int(pXInfo, 1); int bDesc = sqlite3_column_int(pXInfo, 3); const char *zCollate = (const char*)sqlite3_column_text(pXInfo, 4); const char *zCol = 0; const char *zType; if( iCid==-2 ){ int iSeq = sqlite3_column_int(pXInfo, 0); zRet = sqlite3_mprintf("%z%s(%.*s) COLLATE %Q", zRet, zCom, pIter->aIdxCol[iSeq].nSpan, pIter->aIdxCol[iSeq].zSpan, zCollate ); zType = ""; }else { if( iCid<0 ){ /* An integer primary key. If the table has an explicit IPK, use ** its name. Otherwise, use "rbu_rowid". */ if( pIter->eType==RBU_PK_IPK ){ int i; for(i=0; pIter->abTblPk[i]==0; i++); assert( i<pIter->nTblCol ); zCol = pIter->azTblCol[i]; }else if( rbuIsVacuum(p) ){ zCol = "_rowid_"; }else{ zCol = "rbu_rowid"; } zType = "INTEGER"; }else{ zCol = pIter->azTblCol[iCid]; zType = pIter->azTblType[iCid]; } zRet = sqlite3_mprintf("%z%s\"%w\" COLLATE %Q", zRet, zCom,zCol,zCollate); } if( pIter->bUnique==0 || sqlite3_column_int(pXInfo, 5) ){ const char *zOrder = (bDesc ? " DESC" : ""); zImpPK = sqlite3_mprintf("%z%s\"rbu_imp_%d%w\"%s", zImpPK, zCom, nBind, zCol, zOrder ); } zImpCols = sqlite3_mprintf("%z%s\"rbu_imp_%d%w\" %s COLLATE %Q", |
︙ | ︙ | |||
1691 1692 1693 1694 1695 1696 1697 | ** string, an error code is left in the rbu handle passed as the first ** argument and NULL is returned. Or, if an error has already occurred ** when this function is called, NULL is returned immediately, without ** attempting the allocation or modifying the stored error code. */ static char *rbuObjIterGetBindlist(sqlite3rbu *p, int nBind){ char *zRet = 0; | | | 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 | ** string, an error code is left in the rbu handle passed as the first ** argument and NULL is returned. Or, if an error has already occurred ** when this function is called, NULL is returned immediately, without ** attempting the allocation or modifying the stored error code. */ static char *rbuObjIterGetBindlist(sqlite3rbu *p, int nBind){ char *zRet = 0; sqlite3_int64 nByte = 2*(sqlite3_int64)nBind + 1; zRet = (char*)rbuMalloc(p, nByte); if( zRet ){ int i; for(i=0; i<nBind; i++){ zRet[i*2] = '?'; zRet[i*2+1] = (i+1==nBind) ? '\0' : ','; |
︙ | ︙ | |||
1789 1790 1791 1792 1793 1794 1795 | char *zCols = 0; /* Used to build up list of table cols */ char *zPk = 0; /* Used to build up table PK declaration */ /* Figure out the name of the primary key index for the current table. ** This is needed for the argument to "PRAGMA index_xinfo". Set ** zIdx to point to a nul-terminated string containing this name. */ p->rc = prepareAndCollectError(p->dbMain, &pQuery, &p->zErrmsg, | | | 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 | char *zCols = 0; /* Used to build up list of table cols */ char *zPk = 0; /* Used to build up table PK declaration */ /* Figure out the name of the primary key index for the current table. ** This is needed for the argument to "PRAGMA index_xinfo". Set ** zIdx to point to a nul-terminated string containing this name. */ p->rc = prepareAndCollectError(p->dbMain, &pQuery, &p->zErrmsg, "SELECT name FROM sqlite_schema WHERE rootpage = ?" ); if( p->rc==SQLITE_OK ){ sqlite3_bind_int(pQuery, 1, tnum); if( SQLITE_ROW==sqlite3_step(pQuery) ){ zIdx = (const char*)sqlite3_column_text(pQuery, 0); } } |
︙ | ︙ | |||
1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 | rc = sqlite3_reset(p->objiter.pTmpInsert); } if( rc!=SQLITE_OK ){ sqlite3_result_error_code(pCtx, rc); } } /* ** Ensure that the SQLite statement handles required to update the ** target database object currently indicated by the iterator passed ** as the second argument are available. */ static int rbuObjIterPrepareAll( | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 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 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 | rc = sqlite3_reset(p->objiter.pTmpInsert); } if( rc!=SQLITE_OK ){ sqlite3_result_error_code(pCtx, rc); } } static char *rbuObjIterGetIndexWhere(sqlite3rbu *p, RbuObjIter *pIter){ sqlite3_stmt *pStmt = 0; int rc = p->rc; char *zRet = 0; assert( pIter->zIdxSql==0 && pIter->nIdxCol==0 && pIter->aIdxCol==0 ); if( rc==SQLITE_OK ){ rc = prepareAndCollectError(p->dbMain, &pStmt, &p->zErrmsg, "SELECT trim(sql) FROM sqlite_schema WHERE type='index' AND name=?" ); } if( rc==SQLITE_OK ){ int rc2; rc = sqlite3_bind_text(pStmt, 1, pIter->zIdx, -1, SQLITE_STATIC); if( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){ char *zSql = (char*)sqlite3_column_text(pStmt, 0); if( zSql ){ pIter->zIdxSql = zSql = rbuStrndup(zSql, &rc); } if( zSql ){ int nParen = 0; /* Number of open parenthesis */ int i; int iIdxCol = 0; int nIdxAlloc = 0; for(i=0; zSql[i]; i++){ char c = zSql[i]; /* If necessary, grow the pIter->aIdxCol[] array */ if( iIdxCol==nIdxAlloc ){ RbuSpan *aIdxCol = (RbuSpan*)sqlite3_realloc( pIter->aIdxCol, (nIdxAlloc+16)*sizeof(RbuSpan) ); if( aIdxCol==0 ){ rc = SQLITE_NOMEM; break; } pIter->aIdxCol = aIdxCol; nIdxAlloc += 16; } if( c=='(' ){ if( nParen==0 ){ assert( iIdxCol==0 ); pIter->aIdxCol[0].zSpan = &zSql[i+1]; } nParen++; } else if( c==')' ){ nParen--; if( nParen==0 ){ int nSpan = &zSql[i] - pIter->aIdxCol[iIdxCol].zSpan; pIter->aIdxCol[iIdxCol++].nSpan = nSpan; i++; break; } }else if( c==',' && nParen==1 ){ int nSpan = &zSql[i] - pIter->aIdxCol[iIdxCol].zSpan; pIter->aIdxCol[iIdxCol++].nSpan = nSpan; pIter->aIdxCol[iIdxCol].zSpan = &zSql[i+1]; }else if( c=='"' || c=='\'' || c=='`' ){ for(i++; 1; i++){ if( zSql[i]==c ){ if( zSql[i+1]!=c ) break; i++; } } }else if( c=='[' ){ for(i++; 1; i++){ if( zSql[i]==']' ) break; } }else if( c=='-' && zSql[i+1]=='-' ){ for(i=i+2; zSql[i] && zSql[i]!='\n'; i++); if( zSql[i]=='\0' ) break; }else if( c=='/' && zSql[i+1]=='*' ){ for(i=i+2; zSql[i] && (zSql[i]!='*' || zSql[i+1]!='/'); i++); if( zSql[i]=='\0' ) break; i++; } } if( zSql[i] ){ zRet = rbuStrndup(&zSql[i], &rc); } pIter->nIdxCol = iIdxCol; } } rc2 = sqlite3_finalize(pStmt); if( rc==SQLITE_OK ) rc = rc2; } p->rc = rc; return zRet; } /* ** Ensure that the SQLite statement handles required to update the ** target database object currently indicated by the iterator passed ** as the second argument are available. */ static int rbuObjIterPrepareAll( |
︙ | ︙ | |||
1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 | if( zIdx ){ const char *zTbl = pIter->zTbl; char *zImposterCols = 0; /* Columns for imposter table */ char *zImposterPK = 0; /* Primary key declaration for imposter */ char *zWhere = 0; /* WHERE clause on PK columns */ char *zBind = 0; int nBind = 0; assert( pIter->eType!=RBU_PK_VTAB ); zCollist = rbuObjIterGetIndexCols( p, pIter, &zImposterCols, &zImposterPK, &zWhere, &nBind ); zBind = rbuObjIterGetBindlist(p, nBind); /* Create the imposter table used to write to this index. */ sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->dbMain, "main", 0, 1); | > > | 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 | if( zIdx ){ const char *zTbl = pIter->zTbl; char *zImposterCols = 0; /* Columns for imposter table */ char *zImposterPK = 0; /* Primary key declaration for imposter */ char *zWhere = 0; /* WHERE clause on PK columns */ char *zBind = 0; char *zPart = 0; int nBind = 0; assert( pIter->eType!=RBU_PK_VTAB ); zPart = rbuObjIterGetIndexWhere(p, pIter); zCollist = rbuObjIterGetIndexCols( p, pIter, &zImposterCols, &zImposterPK, &zWhere, &nBind ); zBind = rbuObjIterGetBindlist(p, nBind); /* Create the imposter table used to write to this index. */ sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->dbMain, "main", 0, 1); |
︙ | ︙ | |||
2020 2021 2022 2023 2024 2025 2026 2027 | ); } /* Create the SELECT statement to read keys in sorted order */ if( p->rc==SQLITE_OK ){ char *zSql; if( rbuIsVacuum(p) ){ zSql = sqlite3_mprintf( | > > > > > > > > > | > > > | | | | | > > > | > > > > | 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 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 | ); } /* Create the SELECT statement to read keys in sorted order */ if( p->rc==SQLITE_OK ){ char *zSql; if( rbuIsVacuum(p) ){ char *zStart = 0; if( nOffset ){ zStart = rbuVacuumIndexStart(p, pIter); if( zStart ){ sqlite3_free(zLimit); zLimit = 0; } } zSql = sqlite3_mprintf( "SELECT %s, 0 AS rbu_control FROM '%q' %s %s %s ORDER BY %s%s", zCollist, pIter->zDataTbl, zPart, (zStart ? (zPart ? "AND" : "WHERE") : ""), zStart, zCollist, zLimit ); sqlite3_free(zStart); }else if( pIter->eType==RBU_PK_EXTERNAL || pIter->eType==RBU_PK_NONE ){ zSql = sqlite3_mprintf( "SELECT %s, rbu_control FROM %s.'rbu_tmp_%q' %s ORDER BY %s%s", zCollist, p->zStateDb, pIter->zDataTbl, zPart, zCollist, zLimit ); }else{ zSql = sqlite3_mprintf( "SELECT %s, rbu_control FROM %s.'rbu_tmp_%q' %s " "UNION ALL " "SELECT %s, rbu_control FROM '%q' " "%s %s typeof(rbu_control)='integer' AND rbu_control!=1 " "ORDER BY %s%s", zCollist, p->zStateDb, pIter->zDataTbl, zPart, zCollist, pIter->zDataTbl, zPart, (zPart ? "AND" : "WHERE"), zCollist, zLimit ); } if( p->rc==SQLITE_OK ){ p->rc = prepareFreeAndCollectError(p->dbRbu,&pIter->pSelect,pz,zSql); }else{ sqlite3_free(zSql); } } sqlite3_free(zImposterCols); sqlite3_free(zImposterPK); sqlite3_free(zWhere); sqlite3_free(zBind); sqlite3_free(zPart); }else{ int bRbuRowid = (pIter->eType==RBU_PK_VTAB) ||(pIter->eType==RBU_PK_NONE) ||(pIter->eType==RBU_PK_EXTERNAL && rbuIsVacuum(p)); const char *zTbl = pIter->zTbl; /* Table this step applies to */ const char *zWrite; /* Imposter table name */ |
︙ | ︙ | |||
2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 | rbuObjIterPrepareTmpInsert(p, pIter, zCollist, zRbuRowid); } /* Create the SELECT statement to read keys from data_xxx */ if( p->rc==SQLITE_OK ){ const char *zRbuRowid = ""; if( bRbuRowid ){ zRbuRowid = rbuIsVacuum(p) ? ",_rowid_ " : ",rbu_rowid"; } | > > > > > > > > > > > > > > > > > > > | | | | | | | > > | | > > > | 2517 2518 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 | rbuObjIterPrepareTmpInsert(p, pIter, zCollist, zRbuRowid); } /* Create the SELECT statement to read keys from data_xxx */ if( p->rc==SQLITE_OK ){ const char *zRbuRowid = ""; char *zStart = 0; char *zOrder = 0; if( bRbuRowid ){ zRbuRowid = rbuIsVacuum(p) ? ",_rowid_ " : ",rbu_rowid"; } if( rbuIsVacuum(p) ){ if( nOffset ){ zStart = rbuVacuumTableStart(p, pIter, bRbuRowid, zWrite); if( zStart ){ sqlite3_free(zLimit); zLimit = 0; } } if( bRbuRowid ){ zOrder = rbuMPrintf(p, "_rowid_"); }else{ zOrder = rbuObjIterGetPkList(p, pIter, "", ", ", ""); } } if( p->rc==SQLITE_OK ){ p->rc = prepareFreeAndCollectError(p->dbRbu, &pIter->pSelect, pz, sqlite3_mprintf( "SELECT %s,%s rbu_control%s FROM '%q'%s %s %s %s", zCollist, (rbuIsVacuum(p) ? "0 AS " : ""), zRbuRowid, pIter->zDataTbl, (zStart ? zStart : ""), (zOrder ? "ORDER BY" : ""), zOrder, zLimit ) ); } sqlite3_free(zStart); sqlite3_free(zOrder); } sqlite3_free(zWhere); sqlite3_free(zOldlist); sqlite3_free(zNewlist); sqlite3_free(zBindings); } |
︙ | ︙ | |||
2336 2337 2338 2339 2340 2341 2342 | break; case RBU_STATE_COOKIE: pRet->iCookie = (u32)sqlite3_column_int64(pStmt, 1); break; case RBU_STATE_OALSZ: | | | 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 | break; case RBU_STATE_COOKIE: pRet->iCookie = (u32)sqlite3_column_int64(pStmt, 1); break; case RBU_STATE_OALSZ: pRet->iOalSz = sqlite3_column_int64(pStmt, 1); break; case RBU_STATE_PHASEONESTEP: pRet->nPhaseOneStep = sqlite3_column_int64(pStmt, 1); break; case RBU_STATE_DATATBL: |
︙ | ︙ | |||
2363 2364 2365 2366 2367 2368 2369 2370 | return pRet; } /* ** Open the database handle and attach the RBU database as "rbu". If an ** error occurs, leave an error code and message in the RBU handle. */ | > > > > | > > | 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 | return pRet; } /* ** Open the database handle and attach the RBU database as "rbu". If an ** error occurs, leave an error code and message in the RBU handle. ** ** If argument dbMain is not NULL, then it is a database handle already ** open on the target database. Use this handle instead of opening a new ** one. */ static void rbuOpenDatabase(sqlite3rbu *p, sqlite3 *dbMain, int *pbRetry){ assert( p->rc || (p->dbMain==0 && p->dbRbu==0) ); assert( p->rc || rbuIsVacuum(p) || p->zTarget!=0 ); assert( dbMain==0 || rbuIsVacuum(p)==0 ); /* Open the RBU database */ p->dbRbu = rbuOpenDbhandle(p, p->zRbu, 1); p->dbMain = dbMain; if( p->rc==SQLITE_OK && rbuIsVacuum(p) ){ sqlite3_file_control(p->dbRbu, "main", SQLITE_FCNTL_RBUCNT, (void*)p); if( p->zState==0 ){ const char *zFile = sqlite3_db_filename(p->dbRbu, "main"); p->zState = rbuMPrintf(p, "file://%s-vacuum?modeof=%s", zFile, zFile); } |
︙ | ︙ | |||
2404 2405 2406 2407 2408 2409 2410 | #if 0 if( rbuIsVacuum(p) ){ if( p->rc==SQLITE_OK ){ int rc2; int bOk = 0; sqlite3_stmt *pCnt = 0; p->rc = prepareAndCollectError(p->dbRbu, &pCnt, &p->zErrmsg, | | | 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 | #if 0 if( rbuIsVacuum(p) ){ if( p->rc==SQLITE_OK ){ int rc2; int bOk = 0; sqlite3_stmt *pCnt = 0; p->rc = prepareAndCollectError(p->dbRbu, &pCnt, &p->zErrmsg, "SELECT count(*) FROM stat.sqlite_schema" ); if( p->rc==SQLITE_OK && sqlite3_step(pCnt)==SQLITE_ROW && 1==sqlite3_column_int(pCnt, 0) ){ bOk = 1; } |
︙ | ︙ | |||
2508 2509 2510 2511 2512 2513 2514 | "rbu_target_name", -1, SQLITE_UTF8, (void*)p, rbuTargetNameFunc, 0, 0 ); } if( p->rc==SQLITE_OK ){ p->rc = sqlite3_file_control(p->dbMain, "main", SQLITE_FCNTL_RBU, (void*)p); } | | | 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 | "rbu_target_name", -1, SQLITE_UTF8, (void*)p, rbuTargetNameFunc, 0, 0 ); } if( p->rc==SQLITE_OK ){ p->rc = sqlite3_file_control(p->dbMain, "main", SQLITE_FCNTL_RBU, (void*)p); } rbuMPrintfExec(p, p->dbMain, "SELECT * FROM sqlite_schema"); /* Mark the database file just opened as an RBU target database. If ** this call returns SQLITE_NOTFOUND, then the RBU vfs is not in use. ** This is an error. */ if( p->rc==SQLITE_OK ){ p->rc = sqlite3_file_control(p->dbMain, "main", SQLITE_FCNTL_RBU, (void*)p); } |
︙ | ︙ | |||
2601 2602 2603 2604 2605 2606 2607 | /* If pState is NULL, then the wal file may not have been opened and ** recovered. Running a read-statement here to ensure that doing so ** does not interfere with the "capture" process below. */ if( pState==0 ){ p->eStage = 0; if( p->rc==SQLITE_OK ){ | | | 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 | /* If pState is NULL, then the wal file may not have been opened and ** recovered. Running a read-statement here to ensure that doing so ** does not interfere with the "capture" process below. */ if( pState==0 ){ p->eStage = 0; if( p->rc==SQLITE_OK ){ p->rc = sqlite3_exec(p->dbMain, "SELECT * FROM sqlite_schema", 0, 0, 0); } } /* Assuming no error has occurred, run a "restart" checkpoint with the ** sqlite3rbu.eStage variable set to CAPTURE. This turns on the following ** special behaviour in the rbu VFS: ** |
︙ | ︙ | |||
2735 2736 2737 2738 2739 2740 2741 | iOff = (i64)(pFrame->iDbPage-1) * p->pgsz; p->rc = pDb->pMethods->xWrite(pDb, p->aBuf, p->pgsz, iOff); } /* | | > | > | > | > | | | | > > > > > > > > > > > > | 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 3167 3168 3169 3170 3171 3172 3173 3174 3175 | iOff = (i64)(pFrame->iDbPage-1) * p->pgsz; p->rc = pDb->pMethods->xWrite(pDb, p->aBuf, p->pgsz, iOff); } /* ** Take an EXCLUSIVE lock on the database file. Return SQLITE_OK if ** successful, or an SQLite error code otherwise. */ static int rbuLockDatabase(sqlite3 *db){ int rc = SQLITE_OK; sqlite3_file *fd = 0; sqlite3_file_control(db, "main", SQLITE_FCNTL_FILE_POINTER, &fd); if( fd->pMethods ){ rc = fd->pMethods->xLock(fd, SQLITE_LOCK_SHARED); if( rc==SQLITE_OK ){ rc = fd->pMethods->xLock(fd, SQLITE_LOCK_EXCLUSIVE); } } return rc; } /* ** Return true if the database handle passed as the only argument ** was opened with the rbu_exclusive_checkpoint=1 URI parameter ** specified. Or false otherwise. */ static int rbuExclusiveCheckpoint(sqlite3 *db){ const char *zUri = sqlite3_db_filename(db, 0); return sqlite3_uri_boolean(zUri, RBU_EXCLUSIVE_CHECKPOINT, 0); } #if defined(_WIN32_WCE) static LPWSTR rbuWinUtf8ToUnicode(const char *zFilename){ int nChar; LPWSTR zWideFilename; |
︙ | ︙ | |||
2801 2802 2803 2804 2805 2806 2807 | /* Move the *-oal file to *-wal. At this point connection p->db is ** holding a SHARED lock on the target database file (because it is ** in WAL mode). So no other connection may be writing the db. ** ** In order to ensure that there are no database readers, an EXCLUSIVE ** lock is obtained here before the *-oal is moved to *-wal. */ | | < | | | | | | | | > > > > > > > | 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 | /* Move the *-oal file to *-wal. At this point connection p->db is ** holding a SHARED lock on the target database file (because it is ** in WAL mode). So no other connection may be writing the db. ** ** In order to ensure that there are no database readers, an EXCLUSIVE ** lock is obtained here before the *-oal is moved to *-wal. */ sqlite3 *dbMain = 0; rbuFileSuffix3(zBase, zWal); rbuFileSuffix3(zBase, zOal); /* Re-open the databases. */ rbuObjIterFinalize(&p->objiter); sqlite3_close(p->dbRbu); sqlite3_close(p->dbMain); p->dbMain = 0; p->dbRbu = 0; dbMain = rbuOpenDbhandle(p, p->zTarget, 1); if( dbMain ){ assert( p->rc==SQLITE_OK ); p->rc = rbuLockDatabase(dbMain); } if( p->rc==SQLITE_OK ){ #if defined(_WIN32_WCE) { LPWSTR zWideOal; LPWSTR zWideWal; zWideOal = rbuWinUtf8ToUnicode(zOal); if( zWideOal ){ |
︙ | ︙ | |||
2839 2840 2841 2842 2843 2844 2845 | }else{ p->rc = SQLITE_IOERR_NOMEM; } } #else p->rc = rename(zOal, zWal) ? SQLITE_IOERR : SQLITE_OK; #endif | | > > > > > > > > > | | | < | 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 | }else{ p->rc = SQLITE_IOERR_NOMEM; } } #else p->rc = rename(zOal, zWal) ? SQLITE_IOERR : SQLITE_OK; #endif } if( p->rc!=SQLITE_OK || rbuIsVacuum(p) || rbuExclusiveCheckpoint(dbMain)==0 ){ sqlite3_close(dbMain); dbMain = 0; } if( p->rc==SQLITE_OK ){ rbuOpenDatabase(p, dbMain, 0); rbuSetupCheckpoint(p, 0); } } sqlite3_free(zWal); sqlite3_free(zOal); } |
︙ | ︙ | |||
3192 3193 3194 3195 3196 3197 3198 | sqlite3_stmt *pSql = 0; sqlite3_stmt *pInsert = 0; assert( rbuIsVacuum(p) ); p->rc = sqlite3_exec(p->dbMain, "PRAGMA writable_schema=1", 0,0, &p->zErrmsg); if( p->rc==SQLITE_OK ){ p->rc = prepareAndCollectError(p->dbRbu, &pSql, &p->zErrmsg, | | | | | 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 | sqlite3_stmt *pSql = 0; sqlite3_stmt *pInsert = 0; assert( rbuIsVacuum(p) ); p->rc = sqlite3_exec(p->dbMain, "PRAGMA writable_schema=1", 0,0, &p->zErrmsg); if( p->rc==SQLITE_OK ){ p->rc = prepareAndCollectError(p->dbRbu, &pSql, &p->zErrmsg, "SELECT sql FROM sqlite_schema WHERE sql!='' AND rootpage!=0" " AND name!='sqlite_sequence' " " ORDER BY type DESC" ); } while( p->rc==SQLITE_OK && sqlite3_step(pSql)==SQLITE_ROW ){ const char *zSql = (const char*)sqlite3_column_text(pSql, 0); p->rc = sqlite3_exec(p->dbMain, zSql, 0, 0, &p->zErrmsg); } rbuFinalize(p, pSql); if( p->rc!=SQLITE_OK ) return; if( p->rc==SQLITE_OK ){ p->rc = prepareAndCollectError(p->dbRbu, &pSql, &p->zErrmsg, "SELECT * FROM sqlite_schema WHERE rootpage=0 OR rootpage IS NULL" ); } if( p->rc==SQLITE_OK ){ p->rc = prepareAndCollectError(p->dbMain, &pInsert, &p->zErrmsg, "INSERT INTO sqlite_schema VALUES(?,?,?,?,?)" ); } while( p->rc==SQLITE_OK && sqlite3_step(pSql)==SQLITE_ROW ){ int i; for(i=0; i<5; i++){ sqlite3_bind_value(pInsert, i+1, sqlite3_column_value(pSql, i)); |
︙ | ︙ | |||
3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 | int nVal, sqlite3_value **apVal ){ sqlite3rbu *p = (sqlite3rbu*)sqlite3_user_data(pCtx); sqlite3_stmt *pStmt = 0; char *zErrmsg = 0; int rc; assert( nVal==1 ); | > | | | | 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 | int nVal, sqlite3_value **apVal ){ sqlite3rbu *p = (sqlite3rbu*)sqlite3_user_data(pCtx); sqlite3_stmt *pStmt = 0; char *zErrmsg = 0; int rc; sqlite3 *db = (rbuIsVacuum(p) ? p->dbRbu : p->dbMain); assert( nVal==1 ); rc = prepareFreeAndCollectError(db, &pStmt, &zErrmsg, sqlite3_mprintf("SELECT count(*) FROM sqlite_schema " "WHERE type='index' AND tbl_name = %Q", sqlite3_value_text(apVal[0])) ); if( rc!=SQLITE_OK ){ sqlite3_result_error(pCtx, zErrmsg, -1); }else{ int nIndex = 0; if( SQLITE_ROW==sqlite3_step(pStmt) ){ nIndex = sqlite3_column_int(pStmt, 0); } rc = sqlite3_finalize(pStmt); if( rc==SQLITE_OK ){ sqlite3_result_int(pCtx, nIndex); }else{ sqlite3_result_error(pCtx, sqlite3_errmsg(db), -1); } } sqlite3_free(zErrmsg); } /* |
︙ | ︙ | |||
3526 3527 3528 3529 3530 3531 3532 | "rbu_index_cnt", 1, SQLITE_UTF8, (void*)p, rbuIndexCntFunc, 0, 0 ); /* Check for the rbu_count table. If it does not exist, or if an error ** occurs, nPhaseOneStep will be left set to -1. */ if( p->rc==SQLITE_OK ){ p->rc = prepareAndCollectError(p->dbRbu, &pStmt, &p->zErrmsg, | | | 3959 3960 3961 3962 3963 3964 3965 3966 3967 3968 3969 3970 3971 3972 3973 | "rbu_index_cnt", 1, SQLITE_UTF8, (void*)p, rbuIndexCntFunc, 0, 0 ); /* Check for the rbu_count table. If it does not exist, or if an error ** occurs, nPhaseOneStep will be left set to -1. */ if( p->rc==SQLITE_OK ){ p->rc = prepareAndCollectError(p->dbRbu, &pStmt, &p->zErrmsg, "SELECT 1 FROM sqlite_schema WHERE tbl_name = 'rbu_count'" ); } if( p->rc==SQLITE_OK ){ if( SQLITE_ROW==sqlite3_step(pStmt) ){ bExists = 1; } p->rc = sqlite3_finalize(pStmt); |
︙ | ︙ | |||
3593 3594 3595 3596 3597 3598 3599 | /* If the first attempt to open the database file fails and the bRetry ** flag it set, this means that the db was not opened because it seemed ** to be a wal-mode db. But, this may have happened due to an earlier ** RBU vacuum operation leaving an old wal file in the directory. ** If this is the case, it will have been checkpointed and deleted ** when the handle was closed and a second attempt to open the ** database may succeed. */ | | | | 4026 4027 4028 4029 4030 4031 4032 4033 4034 4035 4036 4037 4038 4039 4040 4041 4042 | /* If the first attempt to open the database file fails and the bRetry ** flag it set, this means that the db was not opened because it seemed ** to be a wal-mode db. But, this may have happened due to an earlier ** RBU vacuum operation leaving an old wal file in the directory. ** If this is the case, it will have been checkpointed and deleted ** when the handle was closed and a second attempt to open the ** database may succeed. */ rbuOpenDatabase(p, 0, &bRetry); if( bRetry ){ rbuOpenDatabase(p, 0, 0); } } if( p->rc==SQLITE_OK ){ pState = rbuLoadState(p); assert( pState || p->rc!=SQLITE_OK ); if( p->rc==SQLITE_OK ){ |
︙ | ︙ | |||
3690 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 | if( p->rc==SQLITE_OK ){ rbuSetupOal(p, pState); } } }else if( p->eStage==RBU_STAGE_MOVE ){ /* no-op */ }else if( p->eStage==RBU_STAGE_CKPT ){ rbuSetupCheckpoint(p, pState); }else if( p->eStage==RBU_STAGE_DONE ){ p->rc = SQLITE_DONE; }else{ p->rc = SQLITE_CORRUPT; } } | > > > > > > > > | 4123 4124 4125 4126 4127 4128 4129 4130 4131 4132 4133 4134 4135 4136 4137 4138 4139 4140 4141 4142 4143 4144 | if( p->rc==SQLITE_OK ){ rbuSetupOal(p, pState); } } }else if( p->eStage==RBU_STAGE_MOVE ){ /* no-op */ }else if( p->eStage==RBU_STAGE_CKPT ){ if( !rbuIsVacuum(p) && rbuExclusiveCheckpoint(p->dbMain) ){ /* If the rbu_exclusive_checkpoint=1 URI parameter was specified ** and an incremental checkpoint is being resumed, attempt an ** exclusive lock on the db file. If this fails, so be it. */ p->eStage = RBU_STAGE_DONE; rbuLockDatabase(p->dbMain); p->eStage = RBU_STAGE_CKPT; } rbuSetupCheckpoint(p, pState); }else if( p->eStage==RBU_STAGE_DONE ){ p->rc = SQLITE_DONE; }else{ p->rc = SQLITE_CORRUPT; } } |
︙ | ︙ | |||
3727 3728 3729 3730 3731 3732 3733 | */ sqlite3rbu *sqlite3rbu_open( const char *zTarget, const char *zRbu, const char *zState ){ if( zTarget==0 || zRbu==0 ){ return rbuMisuseError(); } | < | 4168 4169 4170 4171 4172 4173 4174 4175 4176 4177 4178 4179 4180 4181 | */ sqlite3rbu *sqlite3rbu_open( const char *zTarget, const char *zRbu, const char *zState ){ if( zTarget==0 || zRbu==0 ){ return rbuMisuseError(); } return openRbuHandle(zTarget, zRbu, zState); } /* ** Open a handle to begin or resume an RBU VACUUM operation. */ sqlite3rbu *sqlite3rbu_vacuum( |
︙ | ︙ | |||
3941 3942 3943 3944 3945 3946 3947 | p->rc = rc; rbuSaveState(p, p->eStage); rc = p->rc; if( p->eStage==RBU_STAGE_OAL ){ assert( rc!=SQLITE_DONE ); if( rc==SQLITE_OK ) rc = sqlite3_exec(p->dbRbu, "COMMIT", 0, 0, 0); | | > > > | 4381 4382 4383 4384 4385 4386 4387 4388 4389 4390 4391 4392 4393 4394 4395 4396 4397 4398 | p->rc = rc; rbuSaveState(p, p->eStage); rc = p->rc; if( p->eStage==RBU_STAGE_OAL ){ assert( rc!=SQLITE_DONE ); if( rc==SQLITE_OK ) rc = sqlite3_exec(p->dbRbu, "COMMIT", 0, 0, 0); if( rc==SQLITE_OK ){ const char *zBegin = rbuIsVacuum(p) ? "BEGIN" : "BEGIN IMMEDIATE"; rc = sqlite3_exec(p->dbRbu, zBegin, 0, 0, 0); } if( rc==SQLITE_OK ) rc = sqlite3_exec(p->dbMain, "BEGIN IMMEDIATE", 0, 0,0); } p->rc = rc; return rc; } |
︙ | ︙ | |||
4380 4381 4382 4383 4384 4385 4386 | rc = xControl(p->pReal, SQLITE_FCNTL_ZIPVFS, &dummy); if( rc==SQLITE_OK ){ rc = SQLITE_ERROR; pRbu->zErrmsg = sqlite3_mprintf("rbu/zipvfs setup error"); }else if( rc==SQLITE_NOTFOUND ){ pRbu->pTargetFd = p; p->pRbu = pRbu; | < | < | 4823 4824 4825 4826 4827 4828 4829 4830 4831 4832 4833 4834 4835 4836 4837 | rc = xControl(p->pReal, SQLITE_FCNTL_ZIPVFS, &dummy); if( rc==SQLITE_OK ){ rc = SQLITE_ERROR; pRbu->zErrmsg = sqlite3_mprintf("rbu/zipvfs setup error"); }else if( rc==SQLITE_NOTFOUND ){ pRbu->pTargetFd = p; p->pRbu = pRbu; rbuMainlistAdd(p); if( p->pWalFd ) p->pWalFd->pRbu = pRbu; rc = SQLITE_OK; } } return rc; } else if( op==SQLITE_FCNTL_RBUCNT ){ |
︙ | ︙ | |||
4437 4438 4439 4440 4441 4442 4443 | int rc = SQLITE_OK; #ifdef SQLITE_AMALGAMATION assert( WAL_CKPT_LOCK==1 ); #endif assert( p->openFlags & (SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_TEMP_DB) ); | > > | > > | < < < > > < | < < < | | 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 | int rc = SQLITE_OK; #ifdef SQLITE_AMALGAMATION assert( WAL_CKPT_LOCK==1 ); #endif assert( p->openFlags & (SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_TEMP_DB) ); if( pRbu && ( pRbu->eStage==RBU_STAGE_OAL || pRbu->eStage==RBU_STAGE_MOVE || pRbu->eStage==RBU_STAGE_DONE )){ /* Prevent SQLite from taking a shm-lock on the target file when it ** is supplying heap memory to the upper layer in place of *-shm ** segments. */ if( ofst==WAL_LOCK_CKPT && n==1 ) rc = SQLITE_BUSY; }else{ int bCapture = 0; if( pRbu && pRbu->eStage==RBU_STAGE_CAPTURE ){ bCapture = 1; } if( bCapture==0 || 0==(flags & SQLITE_SHM_UNLOCK) ){ rc = p->pReal->pMethods->xShmLock(p->pReal, ofst, n, flags); if( bCapture && rc==SQLITE_OK ){ pRbu->mLock |= ((1<<n) - 1) << ofst; } } } return rc; } |
︙ | ︙ | |||
4481 4482 4483 4484 4485 4486 4487 | int rc = SQLITE_OK; int eStage = (p->pRbu ? p->pRbu->eStage : 0); /* If not in RBU_STAGE_OAL, allow this call to pass through. Or, if this ** rbu is in the RBU_STAGE_OAL state, use heap memory for *-shm space ** instead of a file on disk. */ assert( p->openFlags & (SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_TEMP_DB) ); | | < | | > > > > > > | | | | | | | | < | | 4921 4922 4923 4924 4925 4926 4927 4928 4929 4930 4931 4932 4933 4934 4935 4936 4937 4938 4939 4940 4941 4942 4943 4944 4945 4946 4947 4948 4949 4950 4951 4952 | int rc = SQLITE_OK; int eStage = (p->pRbu ? p->pRbu->eStage : 0); /* If not in RBU_STAGE_OAL, allow this call to pass through. Or, if this ** rbu is in the RBU_STAGE_OAL state, use heap memory for *-shm space ** instead of a file on disk. */ assert( p->openFlags & (SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_TEMP_DB) ); if( eStage==RBU_STAGE_OAL ){ sqlite3_int64 nByte = (iRegion+1) * sizeof(char*); char **apNew = (char**)sqlite3_realloc64(p->apShm, nByte); /* This is an RBU connection that uses its own heap memory for the ** pages of the *-shm file. Since no other process can have run ** recovery, the connection must request *-shm pages in order ** from start to finish. */ assert( iRegion==p->nShm ); if( apNew==0 ){ rc = SQLITE_NOMEM; }else{ memset(&apNew[p->nShm], 0, sizeof(char*) * (1 + iRegion - p->nShm)); p->apShm = apNew; p->nShm = iRegion+1; } if( rc==SQLITE_OK ){ char *pNew = (char*)sqlite3_malloc64(szRegion); if( pNew==0 ){ rc = SQLITE_NOMEM; }else{ memset(pNew, 0, szRegion); p->apShm[iRegion] = pNew; } |
︙ | ︙ | |||
4544 4545 4546 4547 4548 4549 4550 | /* Release the checkpointer and writer locks */ rbuUnlockShm(p); rc = p->pReal->pMethods->xShmUnmap(p->pReal, delFlag); } return rc; } | < < < < < < < < < < < < < < < < < < < < < < < < < < < | 4988 4989 4990 4991 4992 4993 4994 4995 4996 4997 4998 4999 5000 5001 | /* Release the checkpointer and writer locks */ rbuUnlockShm(p); rc = p->pReal->pMethods->xShmUnmap(p->pReal, delFlag); } return rc; } /* ** Open an rbu file handle. */ static int rbuVfsOpen( sqlite3_vfs *pVfs, const char *zName, sqlite3_file *pFile, |
︙ | ︙ | |||
4619 4620 4621 4622 4623 4624 4625 | if( zName ){ if( flags & SQLITE_OPEN_MAIN_DB ){ /* A main database has just been opened. The following block sets ** (pFd->zWal) to point to a buffer owned by SQLite that contains ** the name of the *-wal file this db connection will use. SQLite ** happens to pass a pointer to this buffer when using xAccess() ** or xOpen() to operate on the *-wal file. */ | | | < < < < | < | < > | < < < | < < < < < < | 5036 5037 5038 5039 5040 5041 5042 5043 5044 5045 5046 5047 5048 5049 5050 5051 5052 5053 5054 5055 5056 5057 5058 5059 5060 5061 5062 5063 | if( zName ){ if( flags & SQLITE_OPEN_MAIN_DB ){ /* A main database has just been opened. The following block sets ** (pFd->zWal) to point to a buffer owned by SQLite that contains ** the name of the *-wal file this db connection will use. SQLite ** happens to pass a pointer to this buffer when using xAccess() ** or xOpen() to operate on the *-wal file. */ pFd->zWal = sqlite3_filename_wal(zName); } else if( flags & SQLITE_OPEN_WAL ){ rbu_file *pDb = rbuFindMaindb(pRbuVfs, zName, 0); if( pDb ){ if( pDb->pRbu && pDb->pRbu->eStage==RBU_STAGE_OAL ){ /* This call is to open a *-wal file. Intead, open the *-oal. */ size_t nOpen; if( rbuIsVacuum(pDb->pRbu) ){ zOpen = sqlite3_db_filename(pDb->pRbu->dbRbu, "main"); zOpen = sqlite3_filename_wal(zOpen); } nOpen = strlen(zOpen); ((char*)zOpen)[nOpen-3] = 'o'; pFd->pRbu = pDb->pRbu; } pDb->pWalFd = pFd; } } }else{ pFd->pRbu = pRbuVfs->pRbu; |
︙ | ︙ | |||
4723 4724 4725 4726 4727 4728 4729 | ** b) if the *-wal file does not exist, claim that it does anyway, ** causing SQLite to call xOpen() to open it. This call will also ** be intercepted (see the rbuVfsOpen() function) and the *-oal ** file opened instead. */ if( rc==SQLITE_OK && flags==SQLITE_ACCESS_EXISTS ){ rbu_file *pDb = rbuFindMaindb(pRbuVfs, zPath, 1); | | > | 5126 5127 5128 5129 5130 5131 5132 5133 5134 5135 5136 5137 5138 5139 5140 5141 | ** b) if the *-wal file does not exist, claim that it does anyway, ** causing SQLite to call xOpen() to open it. This call will also ** be intercepted (see the rbuVfsOpen() function) and the *-oal ** file opened instead. */ if( rc==SQLITE_OK && flags==SQLITE_ACCESS_EXISTS ){ rbu_file *pDb = rbuFindMaindb(pRbuVfs, zPath, 1); if( pDb && pDb->pRbu->eStage==RBU_STAGE_OAL ){ assert( pDb->pRbu ); if( *pResOut ){ rc = SQLITE_CANTOPEN; }else{ sqlite3_int64 sz = 0; rc = rbuVfsFileSize(&pDb->base, &sz); *pResOut = (sz>0); } |
︙ | ︙ |
Changes to ext/repair/checkfreelist.c.
︙ | ︙ | |||
40 41 42 43 44 45 46 | SQLITE_EXTENSION_INIT1 #ifndef SQLITE_AMALGAMATION # include <string.h> # include <stdio.h> # include <stdlib.h> # include <assert.h> | > > > > | | > > > > > > > | 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 | SQLITE_EXTENSION_INIT1 #ifndef SQLITE_AMALGAMATION # include <string.h> # include <stdio.h> # include <stdlib.h> # include <assert.h> # if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_MUTATION_TEST) # define SQLITE_OMIT_AUXILIARY_SAFETY_CHECKS 1 # endif # if defined(SQLITE_OMIT_AUXILIARY_SAFETY_CHECKS) # define ALWAYS(X) (1) # define NEVER(X) (0) # elif !defined(NDEBUG) # define ALWAYS(X) ((X)?1:(assert(0),0)) # define NEVER(X) ((X)?(assert(0),1):0) # else # define ALWAYS(X) (X) # define NEVER(X) (X) # endif typedef unsigned char u8; typedef unsigned short u16; typedef unsigned int u32; #define get4byte(x) ( \ ((u32)((x)[0])<<24) + \ ((u32)((x)[1])<<16) + \ ((u32)((x)[2])<<8) + \ |
︙ | ︙ |
Changes to ext/repair/checkindex.c.
︙ | ︙ | |||
469 470 471 472 473 474 475 | CidxIndex *pIdx = 0; sqlite3_stmt *pFindTab = 0; sqlite3_stmt *pInfo = 0; /* Find the table for this index. */ pFindTab = cidxPrepare(&rc, pCsr, | | | 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 | CidxIndex *pIdx = 0; sqlite3_stmt *pFindTab = 0; sqlite3_stmt *pInfo = 0; /* Find the table for this index. */ pFindTab = cidxPrepare(&rc, pCsr, "SELECT tbl_name, sql FROM sqlite_schema WHERE name=%Q AND type='index'", zIdx ); if( rc==SQLITE_OK && sqlite3_step(pFindTab)==SQLITE_ROW ){ const char *zSql = (const char*)sqlite3_column_text(pFindTab, 1); zTab = cidxStrdup(&rc, (const char*)sqlite3_column_text(pFindTab, 0)); pInfo = cidxPrepare(&rc, pCsr, "PRAGMA index_xinfo(%Q)", zIdx); |
︙ | ︙ |
Changes to ext/rtree/geopoly.c.
︙ | ︙ | |||
119 120 121 122 123 124 125 126 127 128 129 130 131 132 | GeoCoord a[8]; /* 2*nVertex values. X (longitude) first, then Y */ }; /* The size of a memory allocation needed for a GeoPoly object sufficient ** to hold N coordinate pairs. */ #define GEOPOLY_SZ(N) (sizeof(GeoPoly) + sizeof(GeoCoord)*2*((N)-4)) /* ** State of a parse of a GeoJSON input. */ typedef struct GeoParse GeoParse; struct GeoParse { const unsigned char *z; /* Unparsed input */ | > > > > > > > > | 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 | GeoCoord a[8]; /* 2*nVertex values. X (longitude) first, then Y */ }; /* The size of a memory allocation needed for a GeoPoly object sufficient ** to hold N coordinate pairs. */ #define GEOPOLY_SZ(N) (sizeof(GeoPoly) + sizeof(GeoCoord)*2*((N)-4)) /* Macros to access coordinates of a GeoPoly. ** We have to use these macros, rather than just say p->a[i] in order ** to silence (incorrect) UBSAN warnings if the array index is too large. */ #define GeoX(P,I) (((GeoCoord*)(P)->a)[(I)*2]) #define GeoY(P,I) (((GeoCoord*)(P)->a)[(I)*2+1]) /* ** State of a parse of a GeoJSON input. */ typedef struct GeoParse GeoParse; struct GeoParse { const unsigned char *z; /* Unparsed input */ |
︙ | ︙ | |||
257 258 259 260 261 262 263 | && s.a[0]==s.a[s.nVertex*2-2] && s.a[1]==s.a[s.nVertex*2-1] && (s.z++, geopolySkipSpace(&s)==0) ){ GeoPoly *pOut; int x = 1; s.nVertex--; /* Remove the redundant vertex at the end */ | | | 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 | && s.a[0]==s.a[s.nVertex*2-2] && s.a[1]==s.a[s.nVertex*2-1] && (s.z++, geopolySkipSpace(&s)==0) ){ GeoPoly *pOut; int x = 1; s.nVertex--; /* Remove the redundant vertex at the end */ pOut = sqlite3_malloc64( GEOPOLY_SZ((sqlite3_int64)s.nVertex) ); x = 1; if( pOut==0 ) goto parse_json_err; pOut->nVertex = s.nVertex; memcpy(pOut->a, s.a, s.nVertex*2*sizeof(GeoCoord)); pOut->hdr[0] = *(unsigned char*)&x; pOut->hdr[1] = (s.nVertex>>16)&0xff; pOut->hdr[2] = (s.nVertex>>8)&0xff; |
︙ | ︙ | |||
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 | static GeoPoly *geopolyFuncParam( sqlite3_context *pCtx, /* Context for error messages */ sqlite3_value *pVal, /* The value to decode */ int *pRc /* Write error here */ ){ GeoPoly *p = 0; int nByte; if( sqlite3_value_type(pVal)==SQLITE_BLOB && (nByte = sqlite3_value_bytes(pVal))>=(4+6*sizeof(GeoCoord)) ){ const unsigned char *a = sqlite3_value_blob(pVal); int nVertex; nVertex = (a[1]<<16) + (a[2]<<8) + a[3]; if( (a[0]==0 || a[0]==1) && (nVertex*2*sizeof(GeoCoord) + 4)==(unsigned int)nByte ){ p = sqlite3_malloc64( sizeof(*p) + (nVertex-1)*2*sizeof(GeoCoord) ); if( p==0 ){ if( pRc ) *pRc = SQLITE_NOMEM; if( pCtx ) sqlite3_result_error_nomem(pCtx); }else{ int x = 1; p->nVertex = nVertex; memcpy(p->hdr, a, nByte); if( a[0] != *(unsigned char*)&x ){ int ii; | > > > > > | | > | 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 | static GeoPoly *geopolyFuncParam( sqlite3_context *pCtx, /* Context for error messages */ sqlite3_value *pVal, /* The value to decode */ int *pRc /* Write error here */ ){ GeoPoly *p = 0; int nByte; testcase( pCtx==0 ); if( sqlite3_value_type(pVal)==SQLITE_BLOB && (nByte = sqlite3_value_bytes(pVal))>=(4+6*sizeof(GeoCoord)) ){ const unsigned char *a = sqlite3_value_blob(pVal); int nVertex; if( a==0 ){ if( pCtx ) sqlite3_result_error_nomem(pCtx); return 0; } nVertex = (a[1]<<16) + (a[2]<<8) + a[3]; if( (a[0]==0 || a[0]==1) && (nVertex*2*sizeof(GeoCoord) + 4)==(unsigned int)nByte ){ p = sqlite3_malloc64( sizeof(*p) + (nVertex-1)*2*sizeof(GeoCoord) ); if( p==0 ){ if( pRc ) *pRc = SQLITE_NOMEM; if( pCtx ) sqlite3_result_error_nomem(pCtx); }else{ int x = 1; p->nVertex = nVertex; memcpy(p->hdr, a, nByte); if( a[0] != *(unsigned char*)&x ){ int ii; for(ii=0; ii<nVertex; ii++){ geopolySwab32((unsigned char*)&GeoX(p,ii)); geopolySwab32((unsigned char*)&GeoY(p,ii)); } p->hdr[0] ^= 1; } } } if( pRc ) *pRc = SQLITE_OK; return p; |
︙ | ︙ | |||
372 373 374 375 376 377 378 | GeoPoly *p = geopolyFuncParam(context, argv[0], 0); if( p ){ sqlite3 *db = sqlite3_context_db_handle(context); sqlite3_str *x = sqlite3_str_new(db); int i; sqlite3_str_append(x, "[", 1); for(i=0; i<p->nVertex; i++){ | | | > > | | | | 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 | GeoPoly *p = geopolyFuncParam(context, argv[0], 0); if( p ){ sqlite3 *db = sqlite3_context_db_handle(context); sqlite3_str *x = sqlite3_str_new(db); int i; sqlite3_str_append(x, "[", 1); for(i=0; i<p->nVertex; i++){ sqlite3_str_appendf(x, "[%!g,%!g],", GeoX(p,i), GeoY(p,i)); } sqlite3_str_appendf(x, "[%!g,%!g]]", GeoX(p,0), GeoY(p,0)); sqlite3_result_text(context, sqlite3_str_finish(x), -1, sqlite3_free); sqlite3_free(p); } } /* ** SQL function: geopoly_svg(X, ....) ** ** Interpret X as a polygon and render it as a SVG <polyline>. ** Additional arguments are added as attributes to the <polyline>. */ static void geopolySvgFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ GeoPoly *p; if( argc<1 ) return; p = geopolyFuncParam(context, argv[0], 0); if( p ){ sqlite3 *db = sqlite3_context_db_handle(context); sqlite3_str *x = sqlite3_str_new(db); int i; char cSep = '\''; sqlite3_str_appendf(x, "<polyline points="); for(i=0; i<p->nVertex; i++){ sqlite3_str_appendf(x, "%c%g,%g", cSep, GeoX(p,i), GeoY(p,i)); cSep = ' '; } sqlite3_str_appendf(x, " %g,%g'", GeoX(p,0), GeoY(p,0)); for(i=1; i<argc; i++){ const char *z = (const char*)sqlite3_value_text(argv[i]); if( z && z[0] ){ sqlite3_str_appendf(x, " %s", z); } } sqlite3_str_appendf(x, "></polyline>"); |
︙ | ︙ | |||
447 448 449 450 451 452 453 | double D = sqlite3_value_double(argv[4]); double E = sqlite3_value_double(argv[5]); double F = sqlite3_value_double(argv[6]); GeoCoord x1, y1, x0, y0; int ii; if( p ){ for(ii=0; ii<p->nVertex; ii++){ | | | | | | | | | | 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 | double D = sqlite3_value_double(argv[4]); double E = sqlite3_value_double(argv[5]); double F = sqlite3_value_double(argv[6]); GeoCoord x1, y1, x0, y0; int ii; if( p ){ for(ii=0; ii<p->nVertex; ii++){ x0 = GeoX(p,ii); y0 = GeoY(p,ii); x1 = (GeoCoord)(A*x0 + B*y0 + E); y1 = (GeoCoord)(C*x0 + D*y0 + F); GeoX(p,ii) = x1; GeoY(p,ii) = y1; } sqlite3_result_blob(context, p->hdr, 4+8*p->nVertex, SQLITE_TRANSIENT); sqlite3_free(p); } } /* ** Compute the area enclosed by the polygon. ** ** This routine can also be used to detect polygons that rotate in ** the wrong direction. Polygons are suppose to be counter-clockwise (CCW). ** This routine returns a negative value for clockwise (CW) polygons. */ static double geopolyArea(GeoPoly *p){ double rArea = 0.0; int ii; for(ii=0; ii<p->nVertex-1; ii++){ rArea += (GeoX(p,ii) - GeoX(p,ii+1)) /* (x0 - x1) */ * (GeoY(p,ii) + GeoY(p,ii+1)) /* (y0 + y1) */ * 0.5; } rArea += (GeoX(p,ii) - GeoX(p,0)) /* (xN - x0) */ * (GeoY(p,ii) + GeoY(p,0)) /* (yN + y0) */ * 0.5; return rArea; } /* ** Implementation of the geopoly_area(X) function. ** |
︙ | ︙ | |||
523 524 525 526 527 528 529 | int argc, sqlite3_value **argv ){ GeoPoly *p = geopolyFuncParam(context, argv[0], 0); if( p ){ if( geopolyArea(p)<0.0 ){ int ii, jj; | | | | | | | | | 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 | int argc, sqlite3_value **argv ){ GeoPoly *p = geopolyFuncParam(context, argv[0], 0); if( p ){ if( geopolyArea(p)<0.0 ){ int ii, jj; for(ii=1, jj=p->nVertex-1; ii<jj; ii++, jj--){ GeoCoord t = GeoX(p,ii); GeoX(p,ii) = GeoX(p,jj); GeoX(p,jj) = t; t = GeoY(p,ii); GeoY(p,ii) = GeoY(p,jj); GeoY(p,jj) = t; } } sqlite3_result_blob(context, p->hdr, 4+8*p->nVertex, SQLITE_TRANSIENT); sqlite3_free(p); } } |
︙ | ︙ | |||
589 590 591 592 593 594 595 | i = 1; p->hdr[0] = *(unsigned char*)&i; p->hdr[1] = 0; p->hdr[2] = (n>>8)&0xff; p->hdr[3] = n&0xff; for(i=0; i<n; i++){ double rAngle = 2.0*GEOPOLY_PI*i/n; | | | | 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 | i = 1; p->hdr[0] = *(unsigned char*)&i; p->hdr[1] = 0; p->hdr[2] = (n>>8)&0xff; p->hdr[3] = n&0xff; for(i=0; i<n; i++){ double rAngle = 2.0*GEOPOLY_PI*i/n; GeoX(p,i) = x - r*geopolySine(rAngle-0.5*GEOPOLY_PI); GeoY(p,i) = y + r*geopolySine(rAngle); } sqlite3_result_blob(context, p->hdr, 4+8*n, SQLITE_TRANSIENT); sqlite3_free(p); } /* ** If pPoly is a polygon, compute its bounding box. Then: |
︙ | ︙ | |||
627 628 629 630 631 632 633 | mxY = aCoord[3].f; goto geopolyBboxFill; }else{ p = geopolyFuncParam(context, pPoly, pRc); } if( p ){ int ii; | | | | | | | | | | | | | | > > | 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 | mxY = aCoord[3].f; goto geopolyBboxFill; }else{ p = geopolyFuncParam(context, pPoly, pRc); } if( p ){ int ii; mnX = mxX = GeoX(p,0); mnY = mxY = GeoY(p,0); for(ii=1; ii<p->nVertex; ii++){ double r = GeoX(p,ii); if( r<mnX ) mnX = (float)r; else if( r>mxX ) mxX = (float)r; r = GeoY(p,ii); if( r<mnY ) mnY = (float)r; else if( r>mxY ) mxY = (float)r; } if( pRc ) *pRc = SQLITE_OK; if( aCoord==0 ){ geopolyBboxFill: pOut = sqlite3_realloc64(p, GEOPOLY_SZ(4)); if( pOut==0 ){ sqlite3_free(p); if( context ) sqlite3_result_error_nomem(context); if( pRc ) *pRc = SQLITE_NOMEM; return 0; } pOut->nVertex = 4; ii = 1; pOut->hdr[0] = *(unsigned char*)ⅈ pOut->hdr[1] = 0; pOut->hdr[2] = 0; pOut->hdr[3] = 4; GeoX(pOut,0) = mnX; GeoY(pOut,0) = mnY; GeoX(pOut,1) = mxX; GeoY(pOut,1) = mnY; GeoX(pOut,2) = mxX; GeoY(pOut,2) = mxY; GeoX(pOut,3) = mnX; GeoY(pOut,3) = mxY; }else{ sqlite3_free(p); aCoord[0].f = mnX; aCoord[1].f = mxX; aCoord[2].f = mnY; aCoord[3].f = mxY; } }else if( aCoord ){ memset(aCoord, 0, sizeof(RtreeCoord)*4); } return pOut; } /* ** Implementation of the geopoly_bbox(X) SQL function. */ |
︙ | ︙ | |||
798 799 800 801 802 803 804 | double x0 = sqlite3_value_double(argv[1]); double y0 = sqlite3_value_double(argv[2]); int v = 0; int cnt = 0; int ii; if( p1==0 ) return; for(ii=0; ii<p1->nVertex-1; ii++){ | | | | | | 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 | double x0 = sqlite3_value_double(argv[1]); double y0 = sqlite3_value_double(argv[2]); int v = 0; int cnt = 0; int ii; if( p1==0 ) return; for(ii=0; ii<p1->nVertex-1; ii++){ v = pointBeneathLine(x0,y0,GeoX(p1,ii), GeoY(p1,ii), GeoX(p1,ii+1),GeoY(p1,ii+1)); if( v==2 ) break; cnt += v; } if( v!=2 ){ v = pointBeneathLine(x0,y0,GeoX(p1,ii), GeoY(p1,ii), GeoX(p1,0), GeoY(p1,0)); } if( v==2 ){ sqlite3_result_int(context, 1); }else if( ((v+cnt)&1)==0 ){ sqlite3_result_int(context, 0); }else{ sqlite3_result_int(context, 2); |
︙ | ︙ | |||
927 928 929 930 931 932 933 | GeoOverlap *p, /* Add segments to this Overlap object */ GeoPoly *pPoly, /* Take all segments from this polygon */ unsigned char side /* The side of pPoly */ ){ unsigned int i; GeoCoord *x; for(i=0; i<(unsigned)pPoly->nVertex-1; i++){ | | | | 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 | GeoOverlap *p, /* Add segments to this Overlap object */ GeoPoly *pPoly, /* Take all segments from this polygon */ unsigned char side /* The side of pPoly */ ){ unsigned int i; GeoCoord *x; for(i=0; i<(unsigned)pPoly->nVertex-1; i++){ x = &GeoX(pPoly,i); geopolyAddOneSegment(p, x[0], x[1], x[2], x[3], side, i); } x = &GeoX(pPoly,i); geopolyAddOneSegment(p, x[0], x[1], pPoly->a[0], pPoly->a[1], side, i); } /* ** Merge two lists of sorted events by X coordinate */ static GeoEvent *geopolyEventMerge(GeoEvent *pLeft, GeoEvent *pRight){ |
︙ | ︙ | |||
1036 1037 1038 1039 1040 1041 1042 | return p; } /* ** Determine the overlap between two polygons */ static int geopolyOverlap(GeoPoly *p1, GeoPoly *p2){ | | | | | | 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 | return p; } /* ** Determine the overlap between two polygons */ static int geopolyOverlap(GeoPoly *p1, GeoPoly *p2){ sqlite3_int64 nVertex = p1->nVertex + p2->nVertex + 2; GeoOverlap *p; sqlite3_int64 nByte; GeoEvent *pThisEvent; double rX; int rc = 0; int needSort = 0; GeoSegment *pActive = 0; GeoSegment *pSeg; unsigned char aOverlap[4]; nByte = sizeof(GeoEvent)*nVertex*2 + sizeof(GeoSegment)*nVertex + sizeof(GeoOverlap); p = sqlite3_malloc64( nByte ); if( p==0 ) return -1; p->aEvent = (GeoEvent*)&p[1]; p->aSegment = (GeoSegment*)&p->aEvent[nVertex*2]; p->nEvent = p->nSegment = 0; geopolyAddSegments(p, p1, 1); geopolyAddSegments(p, p2, 2); pThisEvent = geopolySortEventsByX(p->aEvent, p->nEvent); rX = pThisEvent && pThisEvent->x==0.0 ? -1.0 : 0.0; memset(aOverlap, 0, sizeof(aOverlap)); while( pThisEvent ){ if( pThisEvent->x!=rX ){ GeoSegment *pPrev = 0; int iMask = 0; GEODEBUG(("Distinct X: %g\n", pThisEvent->x)); rX = pThisEvent->x; |
︙ | ︙ | |||
1117 1118 1119 1120 1121 1122 1123 | pSeg->y = pSeg->y0; pSeg->pNext = pActive; pActive = pSeg; needSort = 1; }else{ /* Remove a segment */ if( pActive==pThisEvent->pSeg ){ | | | | 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 | pSeg->y = pSeg->y0; pSeg->pNext = pActive; pActive = pSeg; needSort = 1; }else{ /* Remove a segment */ if( pActive==pThisEvent->pSeg ){ pActive = ALWAYS(pActive) ? pActive->pNext : 0; }else{ for(pSeg=pActive; pSeg; pSeg=pSeg->pNext){ if( pSeg->pNext==pThisEvent->pSeg ){ pSeg->pNext = ALWAYS(pSeg->pNext) ? pSeg->pNext->pNext : 0; break; } } } } pThisEvent = pThisEvent->pNext; } |
︙ | ︙ | |||
1209 1210 1211 1212 1213 1214 1215 | int argc, const char *const*argv, /* Parameters to CREATE TABLE statement */ sqlite3_vtab **ppVtab, /* OUT: New virtual table */ char **pzErr, /* OUT: Error message, if any */ int isCreate /* True for xCreate, false for xConnect */ ){ int rc = SQLITE_OK; Rtree *pRtree; | | | | | | | 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 | int argc, const char *const*argv, /* Parameters to CREATE TABLE statement */ sqlite3_vtab **ppVtab, /* OUT: New virtual table */ char **pzErr, /* OUT: Error message, if any */ int isCreate /* True for xCreate, false for xConnect */ ){ int rc = SQLITE_OK; Rtree *pRtree; sqlite3_int64 nDb; /* Length of string argv[1] */ sqlite3_int64 nName; /* Length of string argv[2] */ sqlite3_str *pSql; char *zSql; int ii; sqlite3_vtab_config(db, SQLITE_VTAB_CONSTRAINT_SUPPORT, 1); /* Allocate the sqlite3_vtab structure */ nDb = strlen(argv[1]); nName = strlen(argv[2]); pRtree = (Rtree *)sqlite3_malloc64(sizeof(Rtree)+nDb+nName+2); if( !pRtree ){ return SQLITE_NOMEM; } memset(pRtree, 0, sizeof(Rtree)+nDb+nName+2); pRtree->nBusy = 1; pRtree->base.pModule = &rtreeModule; pRtree->zDb = (char *)&pRtree[1]; |
︙ | ︙ | |||
1330 1331 1332 1333 1334 1335 1336 | int argc, sqlite3_value **argv /* Parameters to the query plan */ ){ Rtree *pRtree = (Rtree *)pVtabCursor->pVtab; RtreeCursor *pCsr = (RtreeCursor *)pVtabCursor; RtreeNode *pRoot = 0; int rc = SQLITE_OK; int iCell = 0; | < | < < < < < | 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 | int argc, sqlite3_value **argv /* Parameters to the query plan */ ){ Rtree *pRtree = (Rtree *)pVtabCursor->pVtab; RtreeCursor *pCsr = (RtreeCursor *)pVtabCursor; RtreeNode *pRoot = 0; int rc = SQLITE_OK; int iCell = 0; rtreeReference(pRtree); /* Reset the cursor to the same state as rtreeOpen() leaves it in. */ resetCursor(pCsr); pCsr->iStrategy = idxNum; if( idxNum==1 ){ /* Special case - lookup by rowid. */ RtreeNode *pLeaf; /* Leaf on which the required cell resides */ RtreeSearchPoint *p; /* Search point for the leaf */ i64 iRowid = sqlite3_value_int64(argv[0]); |
︙ | ︙ | |||
1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 | ** with the configured constraints. */ rc = nodeAcquire(pRtree, 1, 0, &pRoot); if( rc==SQLITE_OK && idxNum<=3 ){ RtreeCoord bbox[4]; RtreeConstraint *p; assert( argc==1 ); geopolyBBox(0, argv[0], bbox, &rc); if( rc ){ goto geopoly_filter_end; } pCsr->aConstraint = p = sqlite3_malloc(sizeof(RtreeConstraint)*4); pCsr->nConstraint = 4; if( p==0 ){ | > | 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 | ** with the configured constraints. */ rc = nodeAcquire(pRtree, 1, 0, &pRoot); if( rc==SQLITE_OK && idxNum<=3 ){ RtreeCoord bbox[4]; RtreeConstraint *p; assert( argc==1 ); assert( argv[0]!=0 ); geopolyBBox(0, argv[0], bbox, &rc); if( rc ){ goto geopoly_filter_end; } pCsr->aConstraint = p = sqlite3_malloc(sizeof(RtreeConstraint)*4); pCsr->nConstraint = 4; if( p==0 ){ |
︙ | ︙ | |||
1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 | cell.iRowid = newRowid; if( nData>1 /* not a DELETE */ && (!oldRowidValid /* INSERT */ || !sqlite3_value_nochange(aData[2]) /* UPDATE _shape */ || oldRowid!=newRowid) /* Rowid change */ ){ geopolyBBox(0, aData[2], cell.aCoord, &rc); if( rc ){ if( rc==SQLITE_ERROR ){ pVtab->zErrMsg = sqlite3_mprintf("_shape does not contain a valid polygon"); } goto geopoly_update_end; | > | 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 | cell.iRowid = newRowid; if( nData>1 /* not a DELETE */ && (!oldRowidValid /* INSERT */ || !sqlite3_value_nochange(aData[2]) /* UPDATE _shape */ || oldRowid!=newRowid) /* Rowid change */ ){ assert( aData[2]!=0 ); geopolyBBox(0, aData[2], cell.aCoord, &rc); if( rc ){ if( rc==SQLITE_ERROR ){ pVtab->zErrMsg = sqlite3_mprintf("_shape does not contain a valid polygon"); } goto geopoly_update_end; |
︙ | ︙ | |||
1777 1778 1779 1780 1781 1782 1783 | void (*xFinal)(sqlite3_context*); const char *zName; } aAgg[] = { { geopolyBBoxStep, geopolyBBoxFinal, "geopoly_group_bbox" }, }; int i; for(i=0; i<sizeof(aFunc)/sizeof(aFunc[0]) && rc==SQLITE_OK; i++){ | > > | > > > | > | | 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 | void (*xFinal)(sqlite3_context*); const char *zName; } aAgg[] = { { geopolyBBoxStep, geopolyBBoxFinal, "geopoly_group_bbox" }, }; int i; for(i=0; i<sizeof(aFunc)/sizeof(aFunc[0]) && rc==SQLITE_OK; i++){ int enc; if( aFunc[i].bPure ){ enc = SQLITE_UTF8|SQLITE_DETERMINISTIC|SQLITE_INNOCUOUS; }else{ enc = SQLITE_UTF8|SQLITE_DIRECTONLY; } rc = sqlite3_create_function(db, aFunc[i].zName, aFunc[i].nArg, enc, 0, aFunc[i].xFunc, 0, 0); } for(i=0; i<sizeof(aAgg)/sizeof(aAgg[0]) && rc==SQLITE_OK; i++){ rc = sqlite3_create_function(db, aAgg[i].zName, 1, SQLITE_UTF8|SQLITE_DETERMINISTIC|SQLITE_INNOCUOUS, 0, 0, aAgg[i].xStep, aAgg[i].xFinal); } if( rc==SQLITE_OK ){ rc = sqlite3_create_module_v2(db, "geopoly", &geopolyModule, 0, 0); } return rc; } |
Changes to ext/rtree/rtree.c.
︙ | ︙ | |||
58 59 60 61 62 63 64 65 | #ifndef SQLITE_CORE #include "sqlite3ext.h" SQLITE_EXTENSION_INIT1 #else #include "sqlite3.h" #endif | > > > | < < | | > > > > > > > > > > > > > > > > > > > > > > > > | 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 | #ifndef SQLITE_CORE #include "sqlite3ext.h" SQLITE_EXTENSION_INIT1 #else #include "sqlite3.h" #endif int sqlite3GetToken(const unsigned char*,int*); /* In the SQLite core */ /* ** If building separately, we will need some setup that is normally ** found in sqliteInt.h */ #if !defined(SQLITE_AMALGAMATION) #include "sqlite3rtree.h" typedef sqlite3_int64 i64; typedef sqlite3_uint64 u64; typedef unsigned char u8; typedef unsigned short u16; typedef unsigned int u32; #if !defined(NDEBUG) && !defined(SQLITE_DEBUG) # define NDEBUG 1 #endif #if defined(NDEBUG) && defined(SQLITE_DEBUG) # undef NDEBUG #endif #if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_MUTATION_TEST) # define SQLITE_OMIT_AUXILIARY_SAFETY_CHECKS 1 #endif #if defined(SQLITE_OMIT_AUXILIARY_SAFETY_CHECKS) # define ALWAYS(X) (1) # define NEVER(X) (0) #elif !defined(NDEBUG) # define ALWAYS(X) ((X)?1:(assert(0),0)) # define NEVER(X) ((X)?(assert(0),1):0) #else # define ALWAYS(X) (X) # define NEVER(X) (X) #endif #endif /* !defined(SQLITE_AMALGAMATION) */ #include <string.h> #include <stdio.h> #include <assert.h> #include <stdlib.h> /* The following macro is used to suppress compiler warnings. */ #ifndef UNUSED_PARAMETER # define UNUSED_PARAMETER(x) (void)(x) #endif |
︙ | ︙ | |||
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 | int iNodeSize; /* Size in bytes of each node in the node table */ u8 nDim; /* Number of dimensions */ u8 nDim2; /* Twice the number of dimensions */ u8 eCoordType; /* RTREE_COORD_REAL32 or RTREE_COORD_INT32 */ u8 nBytesPerCell; /* Bytes consumed per cell */ u8 inWrTrans; /* True if inside write transaction */ u8 nAux; /* # of auxiliary columns in %_rowid */ u8 nAuxNotNull; /* Number of initial not-null aux columns */ int iDepth; /* Current depth of the r-tree structure */ char *zDb; /* Name of database containing r-tree table */ char *zName; /* Name of r-tree table */ u32 nBusy; /* Current number of users of this structure */ i64 nRowEst; /* Estimated number of rows in this table */ u32 nCursor; /* Number of open cursors */ u32 nNodeRef; /* Number RtreeNodes with positive nRef */ | > > > > > | 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 | int iNodeSize; /* Size in bytes of each node in the node table */ u8 nDim; /* Number of dimensions */ u8 nDim2; /* Twice the number of dimensions */ u8 eCoordType; /* RTREE_COORD_REAL32 or RTREE_COORD_INT32 */ u8 nBytesPerCell; /* Bytes consumed per cell */ u8 inWrTrans; /* True if inside write transaction */ u8 nAux; /* # of auxiliary columns in %_rowid */ #ifdef SQLITE_ENABLE_GEOPOLY u8 nAuxNotNull; /* Number of initial not-null aux columns */ #endif #ifdef SQLITE_DEBUG u8 bCorrupt; /* Shadow table corruption detected */ #endif int iDepth; /* Current depth of the r-tree structure */ char *zDb; /* Name of database containing r-tree table */ char *zName; /* Name of r-tree table */ u32 nBusy; /* Current number of users of this structure */ i64 nRowEst; /* Estimated number of rows in this table */ u32 nCursor; /* Number of open cursors */ u32 nNodeRef; /* Number RtreeNodes with positive nRef */ |
︙ | ︙ | |||
183 184 185 186 187 188 189 190 191 192 193 194 195 196 | # define RTREE_ZERO 0 #else typedef double RtreeDValue; /* High accuracy coordinate */ typedef float RtreeValue; /* Low accuracy coordinate */ # define RTREE_ZERO 0.0 #endif /* ** When doing a search of an r-tree, instances of the following structure ** record intermediate results from the tree walk. ** ** The id is always a node-id. For iLevel>=1 the id is the node-id of ** the node that the RtreeSearchPoint represents. When iLevel==0, however, ** the id is of the parent node and the cell that RtreeSearchPoint | > > > > > > > > > | 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 | # define RTREE_ZERO 0 #else typedef double RtreeDValue; /* High accuracy coordinate */ typedef float RtreeValue; /* Low accuracy coordinate */ # define RTREE_ZERO 0.0 #endif /* ** Set the Rtree.bCorrupt flag */ #ifdef SQLITE_DEBUG # define RTREE_IS_CORRUPT(X) ((X)->bCorrupt = 1) #else # define RTREE_IS_CORRUPT(X) #endif /* ** When doing a search of an r-tree, instances of the following structure ** record intermediate results from the tree walk. ** ** The id is always a node-id. For iLevel>=1 the id is the node-id of ** the node that the RtreeSearchPoint represents. When iLevel==0, however, ** the id is of the parent node and the cell that RtreeSearchPoint |
︙ | ︙ | |||
303 304 305 306 307 308 309 310 311 312 313 314 315 316 | #define RTREE_LE 0x42 /* B */ #define RTREE_LT 0x43 /* C */ #define RTREE_GE 0x44 /* D */ #define RTREE_GT 0x45 /* E */ #define RTREE_MATCH 0x46 /* F: Old-style sqlite3_rtree_geometry_callback() */ #define RTREE_QUERY 0x47 /* G: New-style sqlite3_rtree_query_callback() */ /* ** An rtree structure node. */ struct RtreeNode { RtreeNode *pParent; /* Parent node */ i64 iNode; /* The node number */ | > > > > > > | 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 | #define RTREE_LE 0x42 /* B */ #define RTREE_LT 0x43 /* C */ #define RTREE_GE 0x44 /* D */ #define RTREE_GT 0x45 /* E */ #define RTREE_MATCH 0x46 /* F: Old-style sqlite3_rtree_geometry_callback() */ #define RTREE_QUERY 0x47 /* G: New-style sqlite3_rtree_query_callback() */ /* Special operators available only on cursors. Needs to be consecutive ** with the normal values above, but must be less than RTREE_MATCH. These ** are used in the cursor for contraints such as x=NULL (RTREE_FALSE) or ** x<'xyz' (RTREE_TRUE) */ #define RTREE_TRUE 0x3f /* ? */ #define RTREE_FALSE 0x40 /* @ */ /* ** An rtree structure node. */ struct RtreeNode { RtreeNode *pParent; /* Parent node */ i64 iNode; /* The node number */ |
︙ | ︙ | |||
387 388 389 390 391 392 393 | #endif #endif /* The testcase() macro should already be defined in the amalgamation. If ** it is not, make it a no-op. */ #ifndef SQLITE_AMALGAMATION | > > > > | > > > > > > > > > > > > > > > > > > | 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 | #endif #endif /* The testcase() macro should already be defined in the amalgamation. If ** it is not, make it a no-op. */ #ifndef SQLITE_AMALGAMATION # if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_DEBUG) unsigned int sqlite3RtreeTestcase = 0; # define testcase(X) if( X ){ sqlite3RtreeTestcase += __LINE__; } # else # define testcase(X) # endif #endif /* ** Make sure that the compiler intrinsics we desire are enabled when ** compiling with an appropriate version of MSVC unless prevented by ** the SQLITE_DISABLE_INTRINSIC define. */ #if !defined(SQLITE_DISABLE_INTRINSIC) # if defined(_MSC_VER) && _MSC_VER>=1400 # if !defined(_WIN32_WCE) # include <intrin.h> # pragma intrinsic(_byteswap_ulong) # pragma intrinsic(_byteswap_uint64) # else # include <cmnintrin.h> # endif # endif #endif /* ** Macros to determine whether the machine is big or little endian, ** and whether or not that determination is run-time or compile-time. ** ** For best performance, an attempt is made to guess at the byte-order |
︙ | ︙ | |||
549 550 551 552 553 554 555 | p->isDirty = 1; } /* ** Given a node number iNode, return the corresponding key to use ** in the Rtree.aHash table. */ | | | | 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 | p->isDirty = 1; } /* ** Given a node number iNode, return the corresponding key to use ** in the Rtree.aHash table. */ static unsigned int nodeHash(i64 iNode){ return ((unsigned)iNode) % HASHSIZE; } /* ** Search the node hash table for node iNode. If found, return a pointer ** to it. Otherwise, return 0. */ static RtreeNode *nodeHashLookup(Rtree *pRtree, i64 iNode){ |
︙ | ︙ | |||
595 596 597 598 599 600 601 | ** Allocate and return new r-tree node. Initially, (RtreeNode.iNode==0), ** indicating that node has not yet been assigned a node number. It is ** assigned a node number when nodeWrite() is called to write the ** node contents out to the database. */ static RtreeNode *nodeNew(Rtree *pRtree, RtreeNode *pParent){ RtreeNode *pNode; | | | 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 | ** Allocate and return new r-tree node. Initially, (RtreeNode.iNode==0), ** indicating that node has not yet been assigned a node number. It is ** assigned a node number when nodeWrite() is called to write the ** node contents out to the database. */ static RtreeNode *nodeNew(Rtree *pRtree, RtreeNode *pParent){ RtreeNode *pNode; pNode = (RtreeNode *)sqlite3_malloc64(sizeof(RtreeNode) + pRtree->iNodeSize); if( pNode ){ memset(pNode, 0, sizeof(RtreeNode) + pRtree->iNodeSize); pNode->zData = (u8 *)&pNode[1]; pNode->nRef = 1; pRtree->nNodeRef++; pNode->pParent = pParent; pNode->isDirty = 1; |
︙ | ︙ | |||
635 636 637 638 639 640 641 | int rc = SQLITE_OK; RtreeNode *pNode = 0; /* Check if the requested node is already in the hash table. If so, ** increase its reference count and return it. */ if( (pNode = nodeHashLookup(pRtree, iNode))!=0 ){ | < | | < > | 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 | int rc = SQLITE_OK; RtreeNode *pNode = 0; /* Check if the requested node is already in the hash table. If so, ** increase its reference count and return it. */ if( (pNode = nodeHashLookup(pRtree, iNode))!=0 ){ if( pParent && pParent!=pNode->pParent ){ RTREE_IS_CORRUPT(pRtree); return SQLITE_CORRUPT_VTAB; } pNode->nRef++; *ppNode = pNode; return SQLITE_OK; } if( pRtree->pNodeBlob ){ |
︙ | ︙ | |||
667 668 669 670 671 672 673 | sqlite3_free(zTab); } if( rc ){ nodeBlobReset(pRtree); *ppNode = 0; /* If unable to open an sqlite3_blob on the desired row, that can only ** be because the shadow tables hold erroneous data. */ | | > > > | < | > > > > | 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 | sqlite3_free(zTab); } if( rc ){ nodeBlobReset(pRtree); *ppNode = 0; /* If unable to open an sqlite3_blob on the desired row, that can only ** be because the shadow tables hold erroneous data. */ if( rc==SQLITE_ERROR ){ rc = SQLITE_CORRUPT_VTAB; RTREE_IS_CORRUPT(pRtree); } }else if( pRtree->iNodeSize==sqlite3_blob_bytes(pRtree->pNodeBlob) ){ pNode = (RtreeNode *)sqlite3_malloc64(sizeof(RtreeNode)+pRtree->iNodeSize); if( !pNode ){ rc = SQLITE_NOMEM; }else{ pNode->pParent = pParent; pNode->zData = (u8 *)&pNode[1]; pNode->nRef = 1; pRtree->nNodeRef++; pNode->iNode = iNode; pNode->isDirty = 0; pNode->pNext = 0; rc = sqlite3_blob_read(pRtree->pNodeBlob, pNode->zData, pRtree->iNodeSize, 0); } } /* If the root node was just loaded, set pRtree->iDepth to the height ** of the r-tree structure. A height of zero means all data is stored on ** the root node. A height of one means the children of the root node ** are the leaves, and so on. If the depth as specified on the root node ** is greater than RTREE_MAX_DEPTH, the r-tree structure must be corrupt. */ if( rc==SQLITE_OK && pNode && iNode==1 ){ pRtree->iDepth = readInt16(pNode->zData); if( pRtree->iDepth>RTREE_MAX_DEPTH ){ rc = SQLITE_CORRUPT_VTAB; RTREE_IS_CORRUPT(pRtree); } } /* If no error has occurred so far, check if the "number of entries" ** field on the node is too large. If so, set the return code to ** SQLITE_CORRUPT_VTAB. */ if( pNode && rc==SQLITE_OK ){ if( NCELL(pNode)>((pRtree->iNodeSize-4)/pRtree->nBytesPerCell) ){ rc = SQLITE_CORRUPT_VTAB; RTREE_IS_CORRUPT(pRtree); } } if( rc==SQLITE_OK ){ if( pNode!=0 ){ nodeReference(pParent); nodeHashInsert(pRtree, pNode); }else{ rc = SQLITE_CORRUPT_VTAB; RTREE_IS_CORRUPT(pRtree); } *ppNode = pNode; }else{ if( pNode ){ pRtree->nNodeRef--; sqlite3_free(pNode); } |
︙ | ︙ | |||
939 940 941 942 943 944 945 | */ static void rtreeRelease(Rtree *pRtree){ pRtree->nBusy--; if( pRtree->nBusy==0 ){ pRtree->inWrTrans = 0; assert( pRtree->nCursor==0 ); nodeBlobReset(pRtree); | | | 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 | */ static void rtreeRelease(Rtree *pRtree){ pRtree->nBusy--; if( pRtree->nBusy==0 ){ pRtree->inWrTrans = 0; assert( pRtree->nCursor==0 ); nodeBlobReset(pRtree); assert( pRtree->nNodeRef==0 || pRtree->bCorrupt ); sqlite3_finalize(pRtree->pWriteNode); sqlite3_finalize(pRtree->pDeleteNode); sqlite3_finalize(pRtree->pReadRowid); sqlite3_finalize(pRtree->pWriteRowid); sqlite3_finalize(pRtree->pDeleteRowid); sqlite3_finalize(pRtree->pReadParent); sqlite3_finalize(pRtree->pWriteParent); |
︙ | ︙ | |||
998 999 1000 1001 1002 1003 1004 | ** Rtree virtual table module xOpen method. */ static int rtreeOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){ int rc = SQLITE_NOMEM; Rtree *pRtree = (Rtree *)pVTab; RtreeCursor *pCsr; | | | | > > > > > > > > > > < | < < | 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 | ** Rtree virtual table module xOpen method. */ static int rtreeOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){ int rc = SQLITE_NOMEM; Rtree *pRtree = (Rtree *)pVTab; RtreeCursor *pCsr; pCsr = (RtreeCursor *)sqlite3_malloc64(sizeof(RtreeCursor)); if( pCsr ){ memset(pCsr, 0, sizeof(RtreeCursor)); pCsr->base.pVtab = pVTab; rc = SQLITE_OK; pRtree->nCursor++; } *ppCursor = (sqlite3_vtab_cursor *)pCsr; return rc; } /* ** Reset a cursor back to its initial state. */ static void resetCursor(RtreeCursor *pCsr){ Rtree *pRtree = (Rtree *)(pCsr->base.pVtab); int ii; sqlite3_stmt *pStmt; if( pCsr->aConstraint ){ int i; /* Used to iterate through constraint array */ for(i=0; i<pCsr->nConstraint; i++){ sqlite3_rtree_query_info *pInfo = pCsr->aConstraint[i].pInfo; if( pInfo ){ if( pInfo->xDelUser ) pInfo->xDelUser(pInfo->pUser); sqlite3_free(pInfo); } } sqlite3_free(pCsr->aConstraint); pCsr->aConstraint = 0; } for(ii=0; ii<RTREE_CACHE_SZ; ii++) nodeRelease(pRtree, pCsr->aNode[ii]); sqlite3_free(pCsr->aPoint); pStmt = pCsr->pReadAux; memset(pCsr, 0, sizeof(RtreeCursor)); pCsr->base.pVtab = (sqlite3_vtab*)pRtree; pCsr->pReadAux = pStmt; } /* ** Rtree virtual table module xClose method. */ static int rtreeClose(sqlite3_vtab_cursor *cur){ Rtree *pRtree = (Rtree *)(cur->pVtab); RtreeCursor *pCsr = (RtreeCursor *)cur; assert( pRtree->nCursor>0 ); resetCursor(pCsr); sqlite3_finalize(pCsr->pReadAux); sqlite3_free(pCsr); pRtree->nCursor--; nodeBlobReset(pRtree); return SQLITE_OK; } /* |
︙ | ︙ | |||
1198 1199 1200 1201 1202 1203 1204 | /* p->iCoord might point to either a lower or upper bound coordinate ** in a coordinate pair. But make pCellData point to the lower bound. */ pCellData += 8 + 4*(p->iCoord&0xfe); assert(p->op==RTREE_LE || p->op==RTREE_LT || p->op==RTREE_GE | | > | | | > > > > > > | | > > > > | > | 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 | /* p->iCoord might point to either a lower or upper bound coordinate ** in a coordinate pair. But make pCellData point to the lower bound. */ pCellData += 8 + 4*(p->iCoord&0xfe); assert(p->op==RTREE_LE || p->op==RTREE_LT || p->op==RTREE_GE || p->op==RTREE_GT || p->op==RTREE_EQ || p->op==RTREE_TRUE || p->op==RTREE_FALSE ); assert( ((((char*)pCellData) - (char*)0)&3)==0 ); /* 4-byte aligned */ switch( p->op ){ case RTREE_TRUE: return; /* Always satisfied */ case RTREE_FALSE: break; /* Never satisfied */ case RTREE_EQ: RTREE_DECODE_COORD(eInt, pCellData, val); /* val now holds the lower bound of the coordinate pair */ if( p->u.rValue>=val ){ pCellData += 4; RTREE_DECODE_COORD(eInt, pCellData, val); /* val now holds the upper bound of the coordinate pair */ if( p->u.rValue<=val ) return; } break; case RTREE_LE: case RTREE_LT: RTREE_DECODE_COORD(eInt, pCellData, val); /* val now holds the lower bound of the coordinate pair */ if( p->u.rValue>=val ) return; break; default: pCellData += 4; RTREE_DECODE_COORD(eInt, pCellData, val); /* val now holds the upper bound of the coordinate pair */ if( p->u.rValue<=val ) return; break; } *peWithin = NOT_WITHIN; } /* ** Check the leaf RTree cell given by pCellData against constraint p. ** If this constraint is not satisfied, set *peWithin to NOT_WITHIN. |
︙ | ︙ | |||
1238 1239 1240 1241 1242 1243 1244 | int eInt, /* True if RTree holds integer coordinates */ u8 *pCellData, /* Raw cell content as appears on disk */ int *peWithin /* Adjust downward, as appropriate */ ){ RtreeDValue xN; /* Coordinate value converted to a double */ assert(p->op==RTREE_LE || p->op==RTREE_LT || p->op==RTREE_GE | | > > > | | | | | | 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 | int eInt, /* True if RTree holds integer coordinates */ u8 *pCellData, /* Raw cell content as appears on disk */ int *peWithin /* Adjust downward, as appropriate */ ){ RtreeDValue xN; /* Coordinate value converted to a double */ assert(p->op==RTREE_LE || p->op==RTREE_LT || p->op==RTREE_GE || p->op==RTREE_GT || p->op==RTREE_EQ || p->op==RTREE_TRUE || p->op==RTREE_FALSE ); pCellData += 8 + p->iCoord*4; assert( ((((char*)pCellData) - (char*)0)&3)==0 ); /* 4-byte aligned */ RTREE_DECODE_COORD(eInt, pCellData, xN); switch( p->op ){ case RTREE_TRUE: return; /* Always satisfied */ case RTREE_FALSE: break; /* Never satisfied */ case RTREE_LE: if( xN <= p->u.rValue ) return; break; case RTREE_LT: if( xN < p->u.rValue ) return; break; case RTREE_GE: if( xN >= p->u.rValue ) return; break; case RTREE_GT: if( xN > p->u.rValue ) return; break; default: if( xN == p->u.rValue ) return; break; } *peWithin = NOT_WITHIN; } /* ** One of the cells in node pNode is guaranteed to have a 64-bit ** integer value equal to iRowid. Return the index of this cell. |
︙ | ︙ | |||
1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 | assert( nCell<200 ); for(ii=0; ii<nCell; ii++){ if( nodeGetRowid(pRtree, pNode, ii)==iRowid ){ *piIndex = ii; return SQLITE_OK; } } return SQLITE_CORRUPT_VTAB; } /* ** Return the index of the cell containing a pointer to node pNode ** in its parent. If pNode is the root node, return -1. */ static int nodeParentIndex(Rtree *pRtree, RtreeNode *pNode, int *piIndex){ RtreeNode *pParent = pNode->pParent; | > | | | | > | 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 | assert( nCell<200 ); for(ii=0; ii<nCell; ii++){ if( nodeGetRowid(pRtree, pNode, ii)==iRowid ){ *piIndex = ii; return SQLITE_OK; } } RTREE_IS_CORRUPT(pRtree); return SQLITE_CORRUPT_VTAB; } /* ** Return the index of the cell containing a pointer to node pNode ** in its parent. If pNode is the root node, return -1. */ static int nodeParentIndex(Rtree *pRtree, RtreeNode *pNode, int *piIndex){ RtreeNode *pParent = pNode->pParent; if( ALWAYS(pParent) ){ return nodeRowidIndex(pRtree, pParent, pNode->iNode, piIndex); }else{ *piIndex = -1; return SQLITE_OK; } } /* ** Compare two search points. Return negative, zero, or positive if the first ** is less than, equal to, or greater than the second. ** ** The rScore is the primary key. Smaller rScore values come first. |
︙ | ︙ | |||
1364 1365 1366 1367 1368 1369 1370 | RtreeDValue rScore, /* Score for the new search point */ u8 iLevel /* Level for the new search point */ ){ int i, j; RtreeSearchPoint *pNew; if( pCur->nPoint>=pCur->nPointAlloc ){ int nNew = pCur->nPointAlloc*2 + 8; | | | 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 | RtreeDValue rScore, /* Score for the new search point */ u8 iLevel /* Level for the new search point */ ){ int i, j; RtreeSearchPoint *pNew; if( pCur->nPoint>=pCur->nPointAlloc ){ int nNew = pCur->nPointAlloc*2 + 8; pNew = sqlite3_realloc64(pCur->aPoint, nNew*sizeof(pCur->aPoint[0])); if( pNew==0 ) return 0; pCur->aPoint = pNew; pCur->nPointAlloc = nNew; } i = pCur->nPoint++; pNew = pCur->aPoint + i; pNew->rScore = rScore; |
︙ | ︙ | |||
1407 1408 1409 1410 1411 1412 1413 | || (pFirst->rScore==rScore && pFirst->iLevel>iLevel) ){ if( pCur->bPoint ){ int ii; pNew = rtreeEnqueue(pCur, rScore, iLevel); if( pNew==0 ) return 0; ii = (int)(pNew - pCur->aPoint) + 1; | > | | 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 | || (pFirst->rScore==rScore && pFirst->iLevel>iLevel) ){ if( pCur->bPoint ){ int ii; pNew = rtreeEnqueue(pCur, rScore, iLevel); if( pNew==0 ) return 0; ii = (int)(pNew - pCur->aPoint) + 1; assert( ii==1 ); if( ALWAYS(ii<RTREE_CACHE_SZ) ){ assert( pCur->aNode[ii]==0 ); pCur->aNode[ii] = pCur->aNode[0]; }else{ nodeRelease(RTREE_OF_CURSOR(pCur), pCur->aNode[0]); } pCur->aNode[0] = 0; *pNew = pCur->sPoint; |
︙ | ︙ | |||
1468 1469 1470 1471 1472 1473 1474 | if( p->aNode[i] ){ nodeRelease(RTREE_OF_CURSOR(p), p->aNode[i]); p->aNode[i] = 0; } if( p->bPoint ){ p->anQueue[p->sPoint.iLevel]--; p->bPoint = 0; | | | 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 | if( p->aNode[i] ){ nodeRelease(RTREE_OF_CURSOR(p), p->aNode[i]); p->aNode[i] = 0; } if( p->bPoint ){ p->anQueue[p->sPoint.iLevel]--; p->bPoint = 0; }else if( ALWAYS(p->nPoint) ){ p->anQueue[p->aPoint[0].iLevel]--; n = --p->nPoint; p->aPoint[0] = p->aPoint[n]; if( n<RTREE_CACHE_SZ-1 ){ p->aNode[1] = p->aNode[n+1]; p->aNode[n+1] = 0; } |
︙ | ︙ | |||
1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 | int nConstraint = pCur->nConstraint; int ii; int eInt; RtreeSearchPoint x; eInt = pRtree->eCoordType==RTREE_COORD_INT32; while( (p = rtreeSearchPointFirst(pCur))!=0 && p->iLevel>0 ){ pNode = rtreeNodeOfFirstSearchPoint(pCur, &rc); if( rc ) return rc; nCell = NCELL(pNode); assert( nCell<200 ); while( p->iCell<nCell ){ sqlite3_rtree_dbl rScore = (sqlite3_rtree_dbl)-1; | > > < | < | > > > > > > > > > > > | 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 | int nConstraint = pCur->nConstraint; int ii; int eInt; RtreeSearchPoint x; eInt = pRtree->eCoordType==RTREE_COORD_INT32; while( (p = rtreeSearchPointFirst(pCur))!=0 && p->iLevel>0 ){ u8 *pCellData; pNode = rtreeNodeOfFirstSearchPoint(pCur, &rc); if( rc ) return rc; nCell = NCELL(pNode); assert( nCell<200 ); pCellData = pNode->zData + (4+pRtree->nBytesPerCell*p->iCell); while( p->iCell<nCell ){ sqlite3_rtree_dbl rScore = (sqlite3_rtree_dbl)-1; eWithin = FULLY_WITHIN; for(ii=0; ii<nConstraint; ii++){ RtreeConstraint *pConstraint = pCur->aConstraint + ii; if( pConstraint->op>=RTREE_MATCH ){ rc = rtreeCallbackConstraint(pConstraint, eInt, pCellData, p, &rScore, &eWithin); if( rc ) return rc; }else if( p->iLevel==1 ){ rtreeLeafConstraint(pConstraint, eInt, pCellData, &eWithin); }else{ rtreeNonleafConstraint(pConstraint, eInt, pCellData, &eWithin); } if( eWithin==NOT_WITHIN ){ p->iCell++; pCellData += pRtree->nBytesPerCell; break; } } if( eWithin==NOT_WITHIN ) continue; p->iCell++; x.iLevel = p->iLevel - 1; if( x.iLevel ){ x.id = readInt64(pCellData); for(ii=0; ii<pCur->nPoint; ii++){ if( pCur->aPoint[ii].id==x.id ){ RTREE_IS_CORRUPT(pRtree); return SQLITE_CORRUPT_VTAB; } } x.iCell = 0; }else{ x.id = p->id; x.iCell = p->iCell - 1; } if( p->iCell>=nCell ){ RTREE_QUEUE_TRACE(pCur, "POP-S:"); |
︙ | ︙ | |||
1598 1599 1600 1601 1602 1603 1604 | ** Rtree virtual table module xRowid method. */ static int rtreeRowid(sqlite3_vtab_cursor *pVtabCursor, sqlite_int64 *pRowid){ RtreeCursor *pCsr = (RtreeCursor *)pVtabCursor; RtreeSearchPoint *p = rtreeSearchPointFirst(pCsr); int rc = SQLITE_OK; RtreeNode *pNode = rtreeNodeOfFirstSearchPoint(pCsr, &rc); | | | | 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 | ** Rtree virtual table module xRowid method. */ static int rtreeRowid(sqlite3_vtab_cursor *pVtabCursor, sqlite_int64 *pRowid){ RtreeCursor *pCsr = (RtreeCursor *)pVtabCursor; RtreeSearchPoint *p = rtreeSearchPointFirst(pCsr); int rc = SQLITE_OK; RtreeNode *pNode = rtreeNodeOfFirstSearchPoint(pCsr, &rc); if( rc==SQLITE_OK && ALWAYS(p) ){ *pRowid = nodeGetRowid(RTREE_OF_CURSOR(pCsr), pNode, p->iCell); } return rc; } /* ** Rtree virtual table module xColumn method. */ static int rtreeColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){ Rtree *pRtree = (Rtree *)cur->pVtab; RtreeCursor *pCsr = (RtreeCursor *)cur; RtreeSearchPoint *p = rtreeSearchPointFirst(pCsr); RtreeCoord c; int rc = SQLITE_OK; RtreeNode *pNode = rtreeNodeOfFirstSearchPoint(pCsr, &rc); if( rc ) return rc; if( NEVER(p==0) ) return SQLITE_OK; if( i==0 ){ sqlite3_result_int64(ctx, nodeGetRowid(pRtree, pNode, p->iCell)); }else if( i<=pRtree->nDim2 ){ nodeGetCoord(pRtree, pNode, p->iCell, i-1, &c); #ifndef SQLITE_RTREE_INT_ONLY if( pRtree->eCoordType==RTREE_COORD_REAL32 ){ sqlite3_result_double(ctx, c.f); |
︙ | ︙ | |||
1728 1729 1730 1731 1732 1733 1734 | ){ Rtree *pRtree = (Rtree *)pVtabCursor->pVtab; RtreeCursor *pCsr = (RtreeCursor *)pVtabCursor; RtreeNode *pRoot = 0; int ii; int rc = SQLITE_OK; int iCell = 0; | < | < < < < < > > > > | > > > > | > | > > > > > > > > > > > | > | 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 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 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 | ){ Rtree *pRtree = (Rtree *)pVtabCursor->pVtab; RtreeCursor *pCsr = (RtreeCursor *)pVtabCursor; RtreeNode *pRoot = 0; int ii; int rc = SQLITE_OK; int iCell = 0; rtreeReference(pRtree); /* Reset the cursor to the same state as rtreeOpen() leaves it in. */ resetCursor(pCsr); pCsr->iStrategy = idxNum; if( idxNum==1 ){ /* Special case - lookup by rowid. */ RtreeNode *pLeaf; /* Leaf on which the required cell resides */ RtreeSearchPoint *p; /* Search point for the leaf */ i64 iRowid = sqlite3_value_int64(argv[0]); i64 iNode = 0; int eType = sqlite3_value_numeric_type(argv[0]); if( eType==SQLITE_INTEGER || (eType==SQLITE_FLOAT && sqlite3_value_double(argv[0])==iRowid) ){ rc = findLeafNode(pRtree, iRowid, &pLeaf, &iNode); }else{ rc = SQLITE_OK; pLeaf = 0; } if( rc==SQLITE_OK && pLeaf!=0 ){ p = rtreeSearchPointNew(pCsr, RTREE_ZERO, 0); assert( p!=0 ); /* Always returns pCsr->sPoint */ pCsr->aNode[0] = pLeaf; p->id = iNode; p->eWithin = PARTLY_WITHIN; rc = nodeRowidIndex(pRtree, pLeaf, iRowid, &iCell); p->iCell = (u8)iCell; RTREE_QUEUE_TRACE(pCsr, "PUSH-F1:"); }else{ pCsr->atEOF = 1; } }else{ /* Normal case - r-tree scan. Set up the RtreeCursor.aConstraint array ** with the configured constraints. */ rc = nodeAcquire(pRtree, 1, 0, &pRoot); if( rc==SQLITE_OK && argc>0 ){ pCsr->aConstraint = sqlite3_malloc64(sizeof(RtreeConstraint)*argc); pCsr->nConstraint = argc; if( !pCsr->aConstraint ){ rc = SQLITE_NOMEM; }else{ memset(pCsr->aConstraint, 0, sizeof(RtreeConstraint)*argc); memset(pCsr->anQueue, 0, sizeof(u32)*(pRtree->iDepth + 1)); assert( (idxStr==0 && argc==0) || (idxStr && (int)strlen(idxStr)==argc*2) ); for(ii=0; ii<argc; ii++){ RtreeConstraint *p = &pCsr->aConstraint[ii]; int eType = sqlite3_value_numeric_type(argv[ii]); p->op = idxStr[ii*2]; p->iCoord = idxStr[ii*2+1]-'0'; if( p->op>=RTREE_MATCH ){ /* A MATCH operator. The right-hand-side must be a blob that ** can be cast into an RtreeMatchArg object. One created using ** an sqlite3_rtree_geometry_callback() SQL user function. */ rc = deserializeGeometry(argv[ii], p); if( rc!=SQLITE_OK ){ break; } p->pInfo->nCoord = pRtree->nDim2; p->pInfo->anQueue = pCsr->anQueue; p->pInfo->mxLevel = pRtree->iDepth + 1; }else if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){ #ifdef SQLITE_RTREE_INT_ONLY p->u.rValue = sqlite3_value_int64(argv[ii]); #else p->u.rValue = sqlite3_value_double(argv[ii]); #endif }else{ p->u.rValue = RTREE_ZERO; if( eType==SQLITE_NULL ){ p->op = RTREE_FALSE; }else if( p->op==RTREE_LT || p->op==RTREE_LE ){ p->op = RTREE_TRUE; }else{ p->op = RTREE_FALSE; } } } } } if( rc==SQLITE_OK ){ RtreeSearchPoint *pNew; assert( pCsr->bPoint==0 ); /* Due to the resetCursor() call above */ pNew = rtreeSearchPointNew(pCsr, RTREE_ZERO, (u8)(pRtree->iDepth+1)); if( NEVER(pNew==0) ){ /* Because pCsr->bPoint was FALSE */ return SQLITE_NOMEM; } pNew->id = 1; pNew->iCell = 0; pNew->eWithin = PARTLY_WITHIN; assert( pCsr->bPoint==1 ); pCsr->aNode[0] = pRoot; pRoot = 0; RTREE_QUEUE_TRACE(pCsr, "PUSH-Fm:"); |
︙ | ︙ | |||
1881 1882 1883 1884 1885 1886 1887 | } assert( pIdxInfo->idxStr==0 ); for(ii=0; ii<pIdxInfo->nConstraint && iIdx<(int)(sizeof(zIdxStr)-1); ii++){ struct sqlite3_index_constraint *p = &pIdxInfo->aConstraint[ii]; if( bMatch==0 && p->usable | | | 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 | } assert( pIdxInfo->idxStr==0 ); for(ii=0; ii<pIdxInfo->nConstraint && iIdx<(int)(sizeof(zIdxStr)-1); ii++){ struct sqlite3_index_constraint *p = &pIdxInfo->aConstraint[ii]; if( bMatch==0 && p->usable && p->iColumn<=0 && p->op==SQLITE_INDEX_CONSTRAINT_EQ ){ /* We have an equality constraint on the rowid. Use strategy 1. */ int jj; for(jj=0; jj<ii; jj++){ pIdxInfo->aConstraintUsage[jj].argvIndex = 0; pIdxInfo->aConstraintUsage[jj].omit = 0; } |
︙ | ︙ | |||
1911 1912 1913 1914 1915 1916 1917 | if( p->usable && ((p->iColumn>0 && p->iColumn<=pRtree->nDim2) || p->op==SQLITE_INDEX_CONSTRAINT_MATCH) ){ u8 op; switch( p->op ){ | | | | | | < | < | > | | | | > | 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 | if( p->usable && ((p->iColumn>0 && p->iColumn<=pRtree->nDim2) || p->op==SQLITE_INDEX_CONSTRAINT_MATCH) ){ u8 op; switch( p->op ){ case SQLITE_INDEX_CONSTRAINT_EQ: op = RTREE_EQ; break; case SQLITE_INDEX_CONSTRAINT_GT: op = RTREE_GT; break; case SQLITE_INDEX_CONSTRAINT_LE: op = RTREE_LE; break; case SQLITE_INDEX_CONSTRAINT_LT: op = RTREE_LT; break; case SQLITE_INDEX_CONSTRAINT_GE: op = RTREE_GE; break; case SQLITE_INDEX_CONSTRAINT_MATCH: op = RTREE_MATCH; break; default: op = 0; break; } if( op ){ zIdxStr[iIdx++] = op; zIdxStr[iIdx++] = (char)(p->iColumn - 1 + '0'); pIdxInfo->aConstraintUsage[ii].argvIndex = (iIdx/2); pIdxInfo->aConstraintUsage[ii].omit = 1; } } } pIdxInfo->idxNum = 2; pIdxInfo->needToFreeIdxStr = 1; if( iIdx>0 && 0==(pIdxInfo->idxStr = sqlite3_mprintf("%s", zIdxStr)) ){ return SQLITE_NOMEM; |
︙ | ︙ | |||
1960 1961 1962 1963 1964 1965 1966 | case 2: area *= p->aCoord[3].f - p->aCoord[2].f; default: area *= p->aCoord[1].f - p->aCoord[0].f; } }else #endif { switch( pRtree->nDim ){ | | | | | | | 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 | case 2: area *= p->aCoord[3].f - p->aCoord[2].f; default: area *= p->aCoord[1].f - p->aCoord[0].f; } }else #endif { switch( pRtree->nDim ){ case 5: area = (i64)p->aCoord[9].i - (i64)p->aCoord[8].i; case 4: area *= (i64)p->aCoord[7].i - (i64)p->aCoord[6].i; case 3: area *= (i64)p->aCoord[5].i - (i64)p->aCoord[4].i; case 2: area *= (i64)p->aCoord[3].i - (i64)p->aCoord[2].i; default: area *= (i64)p->aCoord[1].i - (i64)p->aCoord[0].i; } } return area; } /* ** Return the margin length of cell p. The margin length is the sum |
︙ | ︙ | |||
2087 2088 2089 2090 2091 2092 2093 | sqlite3_int64 iBest = 0; RtreeDValue fMinGrowth = RTREE_ZERO; RtreeDValue fMinArea = RTREE_ZERO; int nCell = NCELL(pNode); RtreeCell cell; | | | 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 | sqlite3_int64 iBest = 0; RtreeDValue fMinGrowth = RTREE_ZERO; RtreeDValue fMinArea = RTREE_ZERO; int nCell = NCELL(pNode); RtreeCell cell; RtreeNode *pChild = 0; RtreeCell *aCell = 0; /* Select the child node which will be enlarged the least if pCell ** is inserted into it. Resolve ties by choosing the entry with ** the smallest area. */ |
︙ | ︙ | |||
2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 | */ static int AdjustTree( Rtree *pRtree, /* Rtree table */ RtreeNode *pNode, /* Adjust ancestry of this node. */ RtreeCell *pCell /* This cell was just inserted */ ){ RtreeNode *p = pNode; while( p->pParent ){ RtreeNode *pParent = p->pParent; RtreeCell cell; int iCell; | > > > > > > > | > > | 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 | */ static int AdjustTree( Rtree *pRtree, /* Rtree table */ RtreeNode *pNode, /* Adjust ancestry of this node. */ RtreeCell *pCell /* This cell was just inserted */ ){ RtreeNode *p = pNode; int cnt = 0; int rc; while( p->pParent ){ RtreeNode *pParent = p->pParent; RtreeCell cell; int iCell; cnt++; if( NEVER(cnt>100) ){ RTREE_IS_CORRUPT(pRtree); return SQLITE_CORRUPT_VTAB; } rc = nodeParentIndex(pRtree, p, &iCell); if( NEVER(rc!=SQLITE_OK) ){ RTREE_IS_CORRUPT(pRtree); return SQLITE_CORRUPT_VTAB; } nodeGetCell(pRtree, pParent, iCell, &cell); if( !cellContains(pRtree, &cell, pCell) ){ cellUnion(pRtree, &cell, pCell); nodeOverwriteCell(pRtree, pParent, &cell, iCell); |
︙ | ︙ | |||
2335 2336 2337 2338 2339 2340 2341 | int *aSpare; int ii; int iBestDim = 0; int iBestSplit = 0; RtreeDValue fBestMargin = RTREE_ZERO; | | | | 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 | int *aSpare; int ii; int iBestDim = 0; int iBestSplit = 0; RtreeDValue fBestMargin = RTREE_ZERO; sqlite3_int64 nByte = (pRtree->nDim+1)*(sizeof(int*)+nCell*sizeof(int)); aaSorted = (int **)sqlite3_malloc64(nByte); if( !aaSorted ){ return SQLITE_NOMEM; } aSpare = &((int *)&aaSorted[pRtree->nDim])[pRtree->nDim*nCell]; memset(aaSorted, 0, nByte); for(ii=0; ii<pRtree->nDim; ii++){ |
︙ | ︙ | |||
2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 | RtreeNode *pNode, int iHeight ){ int (*xSetMapping)(Rtree *, sqlite3_int64, sqlite3_int64); xSetMapping = ((iHeight==0)?rowidWrite:parentWrite); if( iHeight>0 ){ RtreeNode *pChild = nodeHashLookup(pRtree, iRowid); if( pChild ){ nodeRelease(pRtree, pChild->pParent); nodeReference(pNode); pChild->pParent = pNode; } } return xSetMapping(pRtree, iRowid, pNode->iNode); } static int SplitNode( Rtree *pRtree, RtreeNode *pNode, RtreeCell *pCell, | > > > > > | 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 | RtreeNode *pNode, int iHeight ){ int (*xSetMapping)(Rtree *, sqlite3_int64, sqlite3_int64); xSetMapping = ((iHeight==0)?rowidWrite:parentWrite); if( iHeight>0 ){ RtreeNode *pChild = nodeHashLookup(pRtree, iRowid); RtreeNode *p; for(p=pNode; p; p=p->pParent){ if( p==pChild ) return SQLITE_CORRUPT_VTAB; } if( pChild ){ nodeRelease(pRtree, pChild->pParent); nodeReference(pNode); pChild->pParent = pNode; } } if( NEVER(pNode==0) ) return SQLITE_ERROR; return xSetMapping(pRtree, iRowid, pNode->iNode); } static int SplitNode( Rtree *pRtree, RtreeNode *pNode, RtreeCell *pCell, |
︙ | ︙ | |||
2458 2459 2460 2461 2462 2463 2464 | RtreeCell leftbbox; RtreeCell rightbbox; /* Allocate an array and populate it with a copy of pCell and ** all cells from node pLeft. Then zero the original node. */ | | | 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 | RtreeCell leftbbox; RtreeCell rightbbox; /* Allocate an array and populate it with a copy of pCell and ** all cells from node pLeft. Then zero the original node. */ aCell = sqlite3_malloc64((sizeof(RtreeCell)+sizeof(int))*(nCell+1)); if( !aCell ){ rc = SQLITE_NOMEM; goto splitnode_out; } aiUsed = (int *)&aCell[nCell+1]; memset(aiUsed, 0, sizeof(int)*(nCell+1)); for(i=0; i<nCell; i++){ |
︙ | ︙ | |||
2521 2522 2523 2524 2525 2526 2527 | if( rc!=SQLITE_OK ){ goto splitnode_out; } }else{ RtreeNode *pParent = pLeft->pParent; int iCell; rc = nodeParentIndex(pRtree, pLeft, &iCell); | | > | | 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 | if( rc!=SQLITE_OK ){ goto splitnode_out; } }else{ RtreeNode *pParent = pLeft->pParent; int iCell; rc = nodeParentIndex(pRtree, pLeft, &iCell); if( ALWAYS(rc==SQLITE_OK) ){ nodeOverwriteCell(pRtree, pParent, &leftbbox, iCell); rc = AdjustTree(pRtree, pParent, &leftbbox); assert( rc==SQLITE_OK ); } if( NEVER(rc!=SQLITE_OK) ){ goto splitnode_out; } } if( (rc = rtreeInsertCell(pRtree, pRight->pParent, &rightbbox, iHeight+1)) ){ goto splitnode_out; } |
︙ | ︙ | |||
2600 2601 2602 2603 2604 2605 2606 | /* Before setting pChild->pParent, test that we are not creating a ** loop of references (as we would if, say, pChild==pParent). We don't ** want to do this as it leads to a memory leak when trying to delete ** the referenced counted node structures. */ iNode = sqlite3_column_int64(pRtree->pReadParent, 0); for(pTest=pLeaf; pTest && pTest->iNode!=iNode; pTest=pTest->pParent); | | | > > > | 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 | /* Before setting pChild->pParent, test that we are not creating a ** loop of references (as we would if, say, pChild==pParent). We don't ** want to do this as it leads to a memory leak when trying to delete ** the referenced counted node structures. */ iNode = sqlite3_column_int64(pRtree->pReadParent, 0); for(pTest=pLeaf; pTest && pTest->iNode!=iNode; pTest=pTest->pParent); if( pTest==0 ){ rc2 = nodeAcquire(pRtree, iNode, 0, &pChild->pParent); } } rc = sqlite3_reset(pRtree->pReadParent); if( rc==SQLITE_OK ) rc = rc2; if( rc==SQLITE_OK && !pChild->pParent ){ RTREE_IS_CORRUPT(pRtree); rc = SQLITE_CORRUPT_VTAB; } pChild = pChild->pParent; } return rc; } static int deleteCell(Rtree *, RtreeNode *, int, int); |
︙ | ︙ | |||
2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 | /* Remove the entry in the parent cell. */ rc = nodeParentIndex(pRtree, pNode, &iCell); if( rc==SQLITE_OK ){ pParent = pNode->pParent; pNode->pParent = 0; rc = deleteCell(pRtree, pParent, iCell, iHeight+1); } rc2 = nodeRelease(pRtree, pParent); if( rc==SQLITE_OK ){ rc = rc2; } if( rc!=SQLITE_OK ){ return rc; | > | 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 | /* Remove the entry in the parent cell. */ rc = nodeParentIndex(pRtree, pNode, &iCell); if( rc==SQLITE_OK ){ pParent = pNode->pParent; pNode->pParent = 0; rc = deleteCell(pRtree, pParent, iCell, iHeight+1); testcase( rc!=SQLITE_OK ); } rc2 = nodeRelease(pRtree, pParent); if( rc==SQLITE_OK ){ rc = rc2; } if( rc!=SQLITE_OK ){ return rc; |
︙ | ︙ | |||
2746 2747 2748 2749 2750 2751 2752 | nCell = NCELL(pNode)+1; n = (nCell+1)&(~1); /* Allocate the buffers used by this operation. The allocation is ** relinquished before this function returns. */ | | | 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 | nCell = NCELL(pNode)+1; n = (nCell+1)&(~1); /* Allocate the buffers used by this operation. The allocation is ** relinquished before this function returns. */ aCell = (RtreeCell *)sqlite3_malloc64(n * ( sizeof(RtreeCell) + /* aCell array */ sizeof(int) + /* aOrder array */ sizeof(int) + /* aSpare array */ sizeof(RtreeDValue) /* aDistance array */ )); if( !aCell ){ return SQLITE_NOMEM; |
︙ | ︙ | |||
2850 2851 2852 2853 2854 2855 2856 | rc = SplitNode(pRtree, pNode, pCell, iHeight); }else{ pRtree->iReinsertHeight = iHeight; rc = Reinsert(pRtree, pNode, pCell, iHeight); } }else{ rc = AdjustTree(pRtree, pNode, pCell); | | | 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 | rc = SplitNode(pRtree, pNode, pCell, iHeight); }else{ pRtree->iReinsertHeight = iHeight; rc = Reinsert(pRtree, pNode, pCell, iHeight); } }else{ rc = AdjustTree(pRtree, pNode, pCell); if( ALWAYS(rc==SQLITE_OK) ){ if( iHeight==0 ){ rc = rowidWrite(pRtree, pCell->iRowid, pNode->iNode); }else{ rc = parentWrite(pRtree, pCell->iRowid, pNode->iNode); } } } |
︙ | ︙ | |||
2919 2920 2921 2922 2923 2924 2925 2926 2927 | /* Obtain a reference to the leaf node that contains the entry ** about to be deleted. */ if( rc==SQLITE_OK ){ rc = findLeafNode(pRtree, iDelete, &pLeaf, 0); } /* Delete the cell in question from the leaf node. */ | > > > > | | 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 | /* Obtain a reference to the leaf node that contains the entry ** about to be deleted. */ if( rc==SQLITE_OK ){ rc = findLeafNode(pRtree, iDelete, &pLeaf, 0); } #ifdef CORRUPT_DB assert( pLeaf!=0 || rc!=SQLITE_OK || CORRUPT_DB ); #endif /* Delete the cell in question from the leaf node. */ if( rc==SQLITE_OK && pLeaf ){ int rc2; rc = nodeRowidIndex(pRtree, pLeaf, iDelete, &iCell); if( rc==SQLITE_OK ){ rc = deleteCell(pRtree, pLeaf, iCell, 0); } rc2 = nodeRelease(pRtree, pLeaf); if( rc==SQLITE_OK ){ |
︙ | ︙ | |||
2952 2953 2954 2955 2956 2957 2958 | ** the root node (the operation that Gutman's paper says to perform ** in this scenario). */ if( rc==SQLITE_OK && pRtree->iDepth>0 && NCELL(pRoot)==1 ){ int rc2; RtreeNode *pChild = 0; i64 iChild = nodeGetRowid(pRtree, pRoot, 0); | | | 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 | ** the root node (the operation that Gutman's paper says to perform ** in this scenario). */ if( rc==SQLITE_OK && pRtree->iDepth>0 && NCELL(pRoot)==1 ){ int rc2; RtreeNode *pChild = 0; i64 iChild = nodeGetRowid(pRtree, pRoot, 0); rc = nodeAcquire(pRtree, iChild, pRoot, &pChild); /* tag-20210916a */ if( rc==SQLITE_OK ){ rc = removeNode(pRtree, pChild, pRtree->iDepth-1); } rc2 = nodeRelease(pRtree, pChild); if( rc==SQLITE_OK ) rc = rc2; if( rc==SQLITE_OK ){ pRtree->iDepth--; |
︙ | ︙ | |||
3193 3194 3195 3196 3197 3198 3199 | pRtree->iReinsertHeight = -1; rc = rtreeInsertCell(pRtree, pLeaf, &cell, 0); rc2 = nodeRelease(pRtree, pLeaf); if( rc==SQLITE_OK ){ rc = rc2; } } | | | 3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 | pRtree->iReinsertHeight = -1; rc = rtreeInsertCell(pRtree, pLeaf, &cell, 0); rc2 = nodeRelease(pRtree, pLeaf); if( rc==SQLITE_OK ){ rc = rc2; } } if( rc==SQLITE_OK && pRtree->nAux ){ sqlite3_stmt *pUp = pRtree->pWriteAux; int jj; sqlite3_bind_int64(pUp, 1, *pRowid); for(jj=0; jj<pRtree->nAux; jj++){ sqlite3_bind_value(pUp, jj+2, aData[pRtree->nDim2+3+jj]); } sqlite3_step(pUp); |
︙ | ︙ | |||
3287 3288 3289 3290 3291 3292 3293 | ** on sqlite_stat1 data. Otherwise, use RTREE_DEFAULT_ROWEST. */ static int rtreeQueryStat1(sqlite3 *db, Rtree *pRtree){ const char *zFmt = "SELECT stat FROM %Q.sqlite_stat1 WHERE tbl = '%q_rowid'"; char *zSql; sqlite3_stmt *p; int rc; | | < < < < < < < < < < | | 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 | ** on sqlite_stat1 data. Otherwise, use RTREE_DEFAULT_ROWEST. */ static int rtreeQueryStat1(sqlite3 *db, Rtree *pRtree){ const char *zFmt = "SELECT stat FROM %Q.sqlite_stat1 WHERE tbl = '%q_rowid'"; char *zSql; sqlite3_stmt *p; int rc; i64 nRow = RTREE_MIN_ROWEST; rc = sqlite3_table_column_metadata( db, pRtree->zDb, "sqlite_stat1",0,0,0,0,0,0 ); if( rc!=SQLITE_OK ){ pRtree->nRowEst = RTREE_DEFAULT_ROWEST; return rc==SQLITE_ERROR ? SQLITE_OK : rc; } zSql = sqlite3_mprintf(zFmt, pRtree->zDb, pRtree->zName); if( zSql==0 ){ rc = SQLITE_NOMEM; }else{ rc = sqlite3_prepare_v2(db, zSql, -1, &p, 0); if( rc==SQLITE_OK ){ if( sqlite3_step(p)==SQLITE_ROW ) nRow = sqlite3_column_int64(p, 0); rc = sqlite3_finalize(p); } sqlite3_free(zSql); } pRtree->nRowEst = MAX(nRow, RTREE_MIN_ROWEST); return rc; } /* ** Return true if zName is the extension on one of the shadow tables used ** by this module. |
︙ | ︙ | |||
3391 3392 3393 3394 3395 3396 3397 3398 3399 3400 3401 3402 3403 3404 | /* Read and write the xxx_parent table */ "SELECT parentnode FROM '%q'.'%q_parent' WHERE nodeno = ?1", "INSERT OR REPLACE INTO '%q'.'%q_parent' VALUES(?1, ?2)", "DELETE FROM '%q'.'%q_parent' WHERE nodeno = ?1" }; sqlite3_stmt **appStmt[N_STATEMENT]; int i; pRtree->db = db; if( isCreate ){ char *zCreate; sqlite3_str *p = sqlite3_str_new(db); int ii; | > | 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 | /* Read and write the xxx_parent table */ "SELECT parentnode FROM '%q'.'%q_parent' WHERE nodeno = ?1", "INSERT OR REPLACE INTO '%q'.'%q_parent' VALUES(?1, ?2)", "DELETE FROM '%q'.'%q_parent' WHERE nodeno = ?1" }; sqlite3_stmt **appStmt[N_STATEMENT]; int i; const int f = SQLITE_PREPARE_PERSISTENT|SQLITE_PREPARE_NO_VTAB; pRtree->db = db; if( isCreate ){ char *zCreate; sqlite3_str *p = sqlite3_str_new(db); int ii; |
︙ | ︙ | |||
3447 3448 3449 3450 3451 3452 3453 | /* An UPSERT is very slightly slower than REPLACE, but it is needed ** if there are auxiliary columns */ zFormat = "INSERT INTO\"%w\".\"%w_rowid\"(rowid,nodeno)VALUES(?1,?2)" "ON CONFLICT(rowid)DO UPDATE SET nodeno=excluded.nodeno"; } zSql = sqlite3_mprintf(zFormat, zDb, zPrefix); if( zSql ){ | | < > | > > | < | 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 | /* An UPSERT is very slightly slower than REPLACE, but it is needed ** if there are auxiliary columns */ zFormat = "INSERT INTO\"%w\".\"%w_rowid\"(rowid,nodeno)VALUES(?1,?2)" "ON CONFLICT(rowid)DO UPDATE SET nodeno=excluded.nodeno"; } zSql = sqlite3_mprintf(zFormat, zDb, zPrefix); if( zSql ){ rc = sqlite3_prepare_v3(db, zSql, -1, f, appStmt[i], 0); }else{ rc = SQLITE_NOMEM; } sqlite3_free(zSql); } if( pRtree->nAux ){ pRtree->zReadAuxSql = sqlite3_mprintf( "SELECT * FROM \"%w\".\"%w_rowid\" WHERE rowid=?1", zDb, zPrefix); if( pRtree->zReadAuxSql==0 ){ rc = SQLITE_NOMEM; }else{ sqlite3_str *p = sqlite3_str_new(db); int ii; char *zSql; sqlite3_str_appendf(p, "UPDATE \"%w\".\"%w_rowid\"SET ", zDb, zPrefix); for(ii=0; ii<pRtree->nAux; ii++){ if( ii ) sqlite3_str_append(p, ",", 1); #ifdef SQLITE_ENABLE_GEOPOLY if( ii<pRtree->nAuxNotNull ){ sqlite3_str_appendf(p,"a%d=coalesce(?%d,a%d)",ii,ii+2,ii); }else #endif { sqlite3_str_appendf(p,"a%d=?%d",ii,ii+2); } } sqlite3_str_appendf(p, " WHERE rowid=?1"); zSql = sqlite3_str_finish(p); if( zSql==0 ){ rc = SQLITE_NOMEM; }else{ rc = sqlite3_prepare_v3(db, zSql, -1, f, &pRtree->pWriteAux, 0); sqlite3_free(zSql); } } } return rc; } |
︙ | ︙ | |||
3555 3556 3557 3558 3559 3560 3561 3562 3563 3564 3565 3566 3567 3568 3569 3570 3571 3572 3573 3574 3575 3576 | pRtree->zDb, pRtree->zName ); rc = getIntFromStmt(db, zSql, &pRtree->iNodeSize); if( rc!=SQLITE_OK ){ *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db)); }else if( pRtree->iNodeSize<(512-64) ){ rc = SQLITE_CORRUPT_VTAB; *pzErr = sqlite3_mprintf("undersize RTree blobs in \"%q_node\"", pRtree->zName); } } sqlite3_free(zSql); return rc; } /* ** This function is the implementation of both the xConnect and xCreate ** methods of the r-tree virtual table. ** ** argv[0] -> module name ** argv[1] -> database name | > > > > > > > > > | 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 | pRtree->zDb, pRtree->zName ); rc = getIntFromStmt(db, zSql, &pRtree->iNodeSize); if( rc!=SQLITE_OK ){ *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db)); }else if( pRtree->iNodeSize<(512-64) ){ rc = SQLITE_CORRUPT_VTAB; RTREE_IS_CORRUPT(pRtree); *pzErr = sqlite3_mprintf("undersize RTree blobs in \"%q_node\"", pRtree->zName); } } sqlite3_free(zSql); return rc; } /* ** Return the length of a token */ static int rtreeTokenLength(const char *z){ int dummy = 0; return sqlite3GetToken((const unsigned char*)z,&dummy); } /* ** This function is the implementation of both the xConnect and xCreate ** methods of the r-tree virtual table. ** ** argv[0] -> module name ** argv[1] -> database name |
︙ | ︙ | |||
3600 3601 3602 3603 3604 3605 3606 | "Wrong number of columns for an rtree table", /* 1 */ "Too few columns for an rtree table", /* 2 */ "Too many columns for an rtree table", /* 3 */ "Auxiliary rtree columns must be last" /* 4 */ }; assert( RTREE_MAX_AUX_COLUMN<256 ); /* Aux columns counted by a u8 */ | | | | | > > | | > | > | 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 | "Wrong number of columns for an rtree table", /* 1 */ "Too few columns for an rtree table", /* 2 */ "Too many columns for an rtree table", /* 3 */ "Auxiliary rtree columns must be last" /* 4 */ }; assert( RTREE_MAX_AUX_COLUMN<256 ); /* Aux columns counted by a u8 */ if( argc<6 || argc>RTREE_MAX_AUX_COLUMN+3 ){ *pzErr = sqlite3_mprintf("%s", aErrMsg[2 + (argc>=6)]); return SQLITE_ERROR; } sqlite3_vtab_config(db, SQLITE_VTAB_CONSTRAINT_SUPPORT, 1); /* Allocate the sqlite3_vtab structure */ nDb = (int)strlen(argv[1]); nName = (int)strlen(argv[2]); pRtree = (Rtree *)sqlite3_malloc64(sizeof(Rtree)+nDb+nName+2); if( !pRtree ){ return SQLITE_NOMEM; } memset(pRtree, 0, sizeof(Rtree)+nDb+nName+2); pRtree->nBusy = 1; pRtree->base.pModule = &rtreeModule; pRtree->zDb = (char *)&pRtree[1]; pRtree->zName = &pRtree->zDb[nDb+1]; pRtree->eCoordType = (u8)eCoordType; memcpy(pRtree->zDb, argv[1], nDb); memcpy(pRtree->zName, argv[2], nName); /* Create/Connect to the underlying relational database schema. If ** that is successful, call sqlite3_declare_vtab() to configure ** the r-tree table schema. */ pSql = sqlite3_str_new(db); sqlite3_str_appendf(pSql, "CREATE TABLE x(%.*s INT", rtreeTokenLength(argv[3]), argv[3]); for(ii=4; ii<argc; ii++){ const char *zArg = argv[ii]; if( zArg[0]=='+' ){ pRtree->nAux++; sqlite3_str_appendf(pSql, ",%.*s", rtreeTokenLength(zArg+1), zArg+1); }else if( pRtree->nAux>0 ){ break; }else{ static const char *azFormat[] = {",%.*s REAL", ",%.*s INT"}; pRtree->nDim2++; sqlite3_str_appendf(pSql, azFormat[eCoordType], rtreeTokenLength(zArg), zArg); } } sqlite3_str_appendf(pSql, ");"); zSql = sqlite3_str_finish(pSql); if( !zSql ){ rc = SQLITE_NOMEM; }else if( ii<argc ){ |
︙ | ︙ | |||
3707 3708 3709 3710 3711 3712 3713 | ** ** The human readable string takes the form of a Tcl list with one ** entry for each cell in the r-tree node. Each entry is itself a ** list, containing the 8-byte rowid/pageno followed by the ** <num-dimension>*2 coordinates. */ static void rtreenode(sqlite3_context *ctx, int nArg, sqlite3_value **apArg){ | < > > > > > > > > > < < > | < < | < | < | < < < < < < | < | | > > > | > > > | 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 | ** ** The human readable string takes the form of a Tcl list with one ** entry for each cell in the r-tree node. Each entry is itself a ** list, containing the 8-byte rowid/pageno followed by the ** <num-dimension>*2 coordinates. */ static void rtreenode(sqlite3_context *ctx, int nArg, sqlite3_value **apArg){ RtreeNode node; Rtree tree; int ii; int nData; int errCode; sqlite3_str *pOut; UNUSED_PARAMETER(nArg); memset(&node, 0, sizeof(RtreeNode)); memset(&tree, 0, sizeof(Rtree)); tree.nDim = (u8)sqlite3_value_int(apArg[0]); if( tree.nDim<1 || tree.nDim>5 ) return; tree.nDim2 = tree.nDim*2; tree.nBytesPerCell = 8 + 8 * tree.nDim; node.zData = (u8 *)sqlite3_value_blob(apArg[1]); if( node.zData==0 ) return; nData = sqlite3_value_bytes(apArg[1]); if( nData<4 ) return; if( nData<NCELL(&node)*tree.nBytesPerCell ) return; pOut = sqlite3_str_new(0); for(ii=0; ii<NCELL(&node); ii++){ RtreeCell cell; int jj; nodeGetCell(&tree, &node, ii, &cell); if( ii>0 ) sqlite3_str_append(pOut, " ", 1); sqlite3_str_appendf(pOut, "{%lld", cell.iRowid); for(jj=0; jj<tree.nDim2; jj++){ #ifndef SQLITE_RTREE_INT_ONLY sqlite3_str_appendf(pOut, " %g", (double)cell.aCoord[jj].f); #else sqlite3_str_appendf(pOut, " %d", cell.aCoord[jj].i); #endif } sqlite3_str_append(pOut, "}", 1); } errCode = sqlite3_str_errcode(pOut); sqlite3_result_text(ctx, sqlite3_str_finish(pOut), -1, sqlite3_free); sqlite3_result_error_code(ctx, errCode); } /* This routine implements an SQL function that returns the "depth" parameter ** from the front of a blob that is an r-tree node. For example: ** ** SELECT rtreedepth(data) FROM rt_node WHERE nodeno=1; ** ** The depth value is 0 for all nodes other than the root node, and the root ** node always has nodeno=1, so the example above is the primary use for this ** routine. This routine is intended for testing and analysis only. */ static void rtreedepth(sqlite3_context *ctx, int nArg, sqlite3_value **apArg){ UNUSED_PARAMETER(nArg); if( sqlite3_value_type(apArg[0])!=SQLITE_BLOB || sqlite3_value_bytes(apArg[0])<2 ){ sqlite3_result_error(ctx, "Invalid argument to rtreedepth()", -1); }else{ u8 *zBlob = (u8 *)sqlite3_value_blob(apArg[0]); if( zBlob ){ sqlite3_result_int(ctx, readInt16(zBlob)); }else{ sqlite3_result_error_nomem(ctx); } } } /* ** Context object passed between the various routines that make up the ** implementation of integrity-check function rtreecheck(). */ |
︙ | ︙ | |||
3878 3879 3880 3881 3882 3883 3884 | ** Or, if an error does occur, NULL is returned and an error code left ** in the RtreeCheck object. The final value of *pnNode is undefined in ** this case. */ static u8 *rtreeCheckGetNode(RtreeCheck *pCheck, i64 iNode, int *pnNode){ u8 *pRet = 0; /* Return value */ | | < | | 4031 4032 4033 4034 4035 4036 4037 4038 4039 4040 4041 4042 4043 4044 4045 4046 4047 4048 4049 4050 4051 4052 4053 4054 4055 4056 4057 | ** Or, if an error does occur, NULL is returned and an error code left ** in the RtreeCheck object. The final value of *pnNode is undefined in ** this case. */ static u8 *rtreeCheckGetNode(RtreeCheck *pCheck, i64 iNode, int *pnNode){ u8 *pRet = 0; /* Return value */ if( pCheck->rc==SQLITE_OK && pCheck->pGetNode==0 ){ pCheck->pGetNode = rtreeCheckPrepare(pCheck, "SELECT data FROM %Q.'%q_node' WHERE nodeno=?", pCheck->zDb, pCheck->zTab ); } if( pCheck->rc==SQLITE_OK ){ sqlite3_bind_int64(pCheck->pGetNode, 1, iNode); if( sqlite3_step(pCheck->pGetNode)==SQLITE_ROW ){ int nNode = sqlite3_column_bytes(pCheck->pGetNode, 0); const u8 *pNode = (const u8*)sqlite3_column_blob(pCheck->pGetNode, 0); pRet = sqlite3_malloc64(nNode); if( pRet==0 ){ pCheck->rc = SQLITE_NOMEM; }else{ memcpy(pRet, pNode, nNode); *pnNode = nNode; } } |
︙ | ︙ | |||
4136 4137 4138 4139 4140 4141 4142 | /* Find the number of auxiliary columns */ if( check.rc==SQLITE_OK ){ pStmt = rtreeCheckPrepare(&check, "SELECT * FROM %Q.'%q_rowid'", zDb, zTab); if( pStmt ){ nAux = sqlite3_column_count(pStmt) - 2; sqlite3_finalize(pStmt); | | > | > | 4288 4289 4290 4291 4292 4293 4294 4295 4296 4297 4298 4299 4300 4301 4302 4303 4304 4305 | /* Find the number of auxiliary columns */ if( check.rc==SQLITE_OK ){ pStmt = rtreeCheckPrepare(&check, "SELECT * FROM %Q.'%q_rowid'", zDb, zTab); if( pStmt ){ nAux = sqlite3_column_count(pStmt) - 2; sqlite3_finalize(pStmt); }else if( check.rc!=SQLITE_NOMEM ){ check.rc = SQLITE_OK; } } /* Find number of dimensions in the rtree table. */ pStmt = rtreeCheckPrepare(&check, "SELECT * FROM %Q.%Q", zDb, zTab); if( pStmt ){ int rc; check.nDim = (sqlite3_column_count(pStmt) - 1 - nAux) / 2; |
︙ | ︙ | |||
4324 4325 4326 4327 4328 4329 4330 | ** The R-Tree MATCH operator will read the returned BLOB, deserialize ** the RtreeMatchArg object, and use the RtreeMatchArg object to figure ** out which elements of the R-Tree should be returned by the query. */ static void geomCallback(sqlite3_context *ctx, int nArg, sqlite3_value **aArg){ RtreeGeomCallback *pGeomCtx = (RtreeGeomCallback *)sqlite3_user_data(ctx); RtreeMatchArg *pBlob; | | | | 4478 4479 4480 4481 4482 4483 4484 4485 4486 4487 4488 4489 4490 4491 4492 4493 4494 4495 4496 4497 | ** The R-Tree MATCH operator will read the returned BLOB, deserialize ** the RtreeMatchArg object, and use the RtreeMatchArg object to figure ** out which elements of the R-Tree should be returned by the query. */ static void geomCallback(sqlite3_context *ctx, int nArg, sqlite3_value **aArg){ RtreeGeomCallback *pGeomCtx = (RtreeGeomCallback *)sqlite3_user_data(ctx); RtreeMatchArg *pBlob; sqlite3_int64 nBlob; int memErr = 0; nBlob = sizeof(RtreeMatchArg) + (nArg-1)*sizeof(RtreeDValue) + nArg*sizeof(sqlite3_value*); pBlob = (RtreeMatchArg *)sqlite3_malloc64(nBlob); if( !pBlob ){ sqlite3_result_error_nomem(ctx); }else{ int i; pBlob->iSize = nBlob; pBlob->cb = pGeomCtx[0]; pBlob->apSqlParam = (sqlite3_value**)&pBlob->aParam[nArg]; |
︙ | ︙ | |||
4394 4395 4396 4397 4398 4399 4400 | void *pContext, /* Extra data passed into the callback */ void (*xDestructor)(void*) /* Destructor for the extra data */ ){ RtreeGeomCallback *pGeomCtx; /* Context object for new user-function */ /* Allocate and populate the context object. */ pGeomCtx = (RtreeGeomCallback *)sqlite3_malloc(sizeof(RtreeGeomCallback)); | | > > > | 4548 4549 4550 4551 4552 4553 4554 4555 4556 4557 4558 4559 4560 4561 4562 4563 4564 4565 | void *pContext, /* Extra data passed into the callback */ void (*xDestructor)(void*) /* Destructor for the extra data */ ){ RtreeGeomCallback *pGeomCtx; /* Context object for new user-function */ /* Allocate and populate the context object. */ pGeomCtx = (RtreeGeomCallback *)sqlite3_malloc(sizeof(RtreeGeomCallback)); if( !pGeomCtx ){ if( xDestructor ) xDestructor(pContext); return SQLITE_NOMEM; } pGeomCtx->xGeom = 0; pGeomCtx->xQueryFunc = xQueryFunc; pGeomCtx->xDestructor = xDestructor; pGeomCtx->pContext = pContext; return sqlite3_create_function_v2(db, zQueryFunc, -1, SQLITE_ANY, (void *)pGeomCtx, geomCallback, 0, 0, rtreeFreeCallback ); |
︙ | ︙ |
Changes to ext/rtree/rtree1.test.
︙ | ︙ | |||
53 54 55 56 57 58 59 | # # Test creating and dropping an rtree table. # do_test rtree-1.1.1 { execsql { CREATE VIRTUAL TABLE t1 USING rtree(ii, x1, x2, y1, y2) } } {} | | > > > | 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | # # Test creating and dropping an rtree table. # do_test rtree-1.1.1 { execsql { CREATE VIRTUAL TABLE t1 USING rtree(ii, x1, x2, y1, y2) } } {} do_test rtree-1.1.2a { execsql { SELECT name FROM sqlite_master ORDER BY name } } {t1 t1_node t1_parent t1_rowid} do_execsql_test rtree-1.1.2b { SELECT name FROM pragma_table_list WHERE type='shadow' ORDER BY name; } {t1_node t1_parent t1_rowid} do_test rtree-1.1.3 { execsql { DROP TABLE t1; SELECT name FROM sqlite_master ORDER BY name; } } {} |
︙ | ︙ | |||
108 109 110 111 112 113 114 115 116 117 118 119 120 121 | catchsql " CREATE VIRTUAL TABLE t1 USING rtree($columns); " } $X catchsql { DROP TABLE t1 } } # Like execsql except display output as integer where that can be # done without loss of information. # proc execsql_intout {sql} { set out {} foreach term [execsql $sql] { | > > > | 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 | catchsql " CREATE VIRTUAL TABLE t1 USING rtree($columns); " } $X catchsql { DROP TABLE t1 } } do_catchsql_test rtree-1.3.1000 { CREATE VIRTUAL TABLE t1000 USING rtree; } {1 {Too few columns for an rtree table}} # Like execsql except display output as integer where that can be # done without loss of information. # proc execsql_intout {sql} { set out {} foreach term [execsql $sql] { |
︙ | ︙ | |||
370 371 372 373 374 375 376 | do_test rtree-8.1.1 { execsql { CREATE VIRTUAL TABLE t6 USING rtree(ii, x1, x2); INSERT INTO t6 VALUES(1, 3, 7); INSERT INTO t6 VALUES(2, 4, 6); } } {} | | | | | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | do_test rtree-8.1.1 { execsql { CREATE VIRTUAL TABLE t6 USING rtree(ii, x1, x2); INSERT INTO t6 VALUES(1, 3, 7); INSERT INTO t6 VALUES(2, 4, 6); } } {} do_test rtree-8.1.2 { execsql { SELECT ii FROM t6 WHERE x1>2 } } {1 2} do_test rtree-8.1.3 { execsql { SELECT ii FROM t6 WHERE x1>3 } } {2} do_test rtree-8.1.4 { execsql { SELECT ii FROM t6 WHERE x1>4 } } {} do_test rtree-8.1.5 { execsql { SELECT ii FROM t6 WHERE x1>5 } } {} do_test rtree-8.1.6 { execsql { SELECT ii FROM t6 WHERE x1>''} } {} do_test rtree-8.1.7 { execsql { SELECT ii FROM t6 WHERE x1>null}} {} do_test rtree-8.1.8 { execsql { SELECT ii FROM t6 WHERE x1>'2'} } {1 2} do_test rtree-8.1.9 { execsql { SELECT ii FROM t6 WHERE x1>'3'} } {2} do_test rtree-8.2.2 { execsql { SELECT ii FROM t6 WHERE x1>=2 } } {1 2} do_test rtree-8.2.3 { execsql { SELECT ii FROM t6 WHERE x1>=3 } } {1 2} do_test rtree-8.2.4 { execsql { SELECT ii FROM t6 WHERE x1>=4 } } {2} do_test rtree-8.2.5 { execsql { SELECT ii FROM t6 WHERE x1>=5 } } {} do_test rtree-8.2.6 { execsql { SELECT ii FROM t6 WHERE x1>=''} } {} do_test rtree-8.2.7 { execsql { SELECT ii FROM t6 WHERE x1>=null}} {} do_test rtree-8.2.8 { execsql { SELECT ii FROM t6 WHERE x1>='4'} } {2} do_test rtree-8.2.9 { execsql { SELECT ii FROM t6 WHERE x1>='5'} } {} do_test rtree-8.3.2 { execsql { SELECT ii FROM t6 WHERE x1<2 } } {} do_test rtree-8.3.3 { execsql { SELECT ii FROM t6 WHERE x1<3 } } {} do_test rtree-8.3.4 { execsql { SELECT ii FROM t6 WHERE x1<4 } } {1} do_test rtree-8.3.5 { execsql { SELECT ii FROM t6 WHERE x1<5 } } {1 2} do_test rtree-8.3.6 { execsql { SELECT ii FROM t6 WHERE x1<''} } {1 2} do_test rtree-8.3.7 { execsql { SELECT ii FROM t6 WHERE x1<null}} {} do_test rtree-8.3.8 { execsql { SELECT ii FROM t6 WHERE x1<'3'} } {} do_test rtree-8.3.9 { execsql { SELECT ii FROM t6 WHERE x1<'4'} } {1} do_test rtree-8.4.2 { execsql { SELECT ii FROM t6 WHERE x1<=2 } } {} do_test rtree-8.4.3 { execsql { SELECT ii FROM t6 WHERE x1<=3 } } {1} do_test rtree-8.4.4 { execsql { SELECT ii FROM t6 WHERE x1<=4 } } {1 2} do_test rtree-8.4.5 { execsql { SELECT ii FROM t6 WHERE x1<=5 } } {1 2} do_test rtree-8.4.6 { execsql { SELECT ii FROM t6 WHERE x1<=''} } {1 2} do_test rtree-8.4.7 { execsql { SELECT ii FROM t6 WHERE x1<=null}} {} do_test rtree-8.5.2 { execsql { SELECT ii FROM t6 WHERE x1=2 } } {} do_test rtree-8.5.3 { execsql { SELECT ii FROM t6 WHERE x1=3 } } {1} do_test rtree-8.5.4 { execsql { SELECT ii FROM t6 WHERE x1=4 } } {2} do_test rtree-8.5.5 { execsql { SELECT ii FROM t6 WHERE x1=5 } } {} do_test rtree-8.5.6 { execsql { SELECT ii FROM t6 WHERE x1=''} } {} do_test rtree-8.5.7 { execsql { SELECT ii FROM t6 WHERE x1=null}} {} #---------------------------------------------------------------------------- # Test cases rtree-9.* # # Test that ticket #3549 is fixed. do_test rtree-9.1 { execsql { |
︙ | ︙ | |||
574 575 576 577 578 579 580 581 | } do_execsql_test 14.5 { SELECT * FROM t10; } { 1 0.0 0.0 2 52.0 81.0 } | > > > > > > > > > > > > > > | | | 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 | } do_execsql_test 14.5 { SELECT * FROM t10; } { 1 0.0 0.0 2 52.0 81.0 } do_execsql_test 14.6 { INSERT INTO t10 VALUES(0,10,20); SELECT * FROM t10 WHERE ii=NULL; } {} do_execsql_test 14.7 { SELECT * FROM t10 WHERE ii='xyz'; } {} do_execsql_test 14.8 { SELECT * FROM t10 WHERE ii='0.0'; } {0 10.0 20.0} do_execsql_test 14.9 { SELECT * FROM t10 WHERE ii=0.0; } {0 10.0 20.0} do_execsql_test 14.104 { DROP TABLE t10; CREATE VIRTUAL TABLE t10 USING rtree_i32(ii, x1, x2); INSERT INTO t10 VALUES(1, 'one', 'two'); INSERT INTO t10 VALUES(2, '52xyz', '81...'); INSERT INTO t10 VALUES(3, 42.3, 49.9); } do_execsql_test 14.105 { SELECT * FROM t10; } { 1 0 0 2 52 81 3 42 49 } |
︙ | ︙ | |||
642 643 644 645 646 647 648 649 650 651 | CREATE VIRTUAL TABLE rt1 USING rtree(id, x1, x2, +aux); INSERT INTO rt1 VALUES(1, 1, 2, 'aux1'); INSERT INTO rt1 VALUES(2, 2, 3, 'aux2'); INSERT INTO rt1 VALUES(3, 3, 4, 'aux3'); INSERT INTO rt1 VALUES(4, 4, 5, 'aux4'); SELECT * FROM rt1 WHERE id IN (1, 2, 3, 4); } {1 1.0 2.0 aux1 2 2.0 3.0 aux2 3 3.0 4.0 aux3 4 4.0 5.0 aux4} expand_all_sql db finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | CREATE VIRTUAL TABLE rt1 USING rtree(id, x1, x2, +aux); INSERT INTO rt1 VALUES(1, 1, 2, 'aux1'); INSERT INTO rt1 VALUES(2, 2, 3, 'aux2'); INSERT INTO rt1 VALUES(3, 3, 4, 'aux3'); INSERT INTO rt1 VALUES(4, 4, 5, 'aux4'); SELECT * FROM rt1 WHERE id IN (1, 2, 3, 4); } {1 1.0 2.0 aux1 2 2.0 3.0 aux2 3 3.0 4.0 aux3 4 4.0 5.0 aux4} reset_db do_execsql_test 17.0 { CREATE VIRTUAL TABLE t1 USING rtree(id, x1 PRIMARY KEY, x2, y1, y2); CREATE VIRTUAL TABLE t2 USING rtree(id, x1, x2, y1, y2 UNIQUE); } do_execsql_test 17.1 { REINDEX t1; REINDEX t2; } {} do_execsql_test 17.2 { REINDEX; } {} reset_db do_execsql_test 18.0 { CREATE VIRTUAL TABLE rt0 USING rtree(c0, c1, c2); INSERT INTO rt0(c0,c1,c2) VALUES(9,2,3); SELECT c0 FROM rt0 WHERE rt0.c1 > '-1'; SELECT rt0.c1 > '-1' FROM rt0; } {9 1} expand_all_sql db # 2020-02-28 ticket e63b4d1a65546532 reset_db do_execsql_test 19.0 { CREATE VIRTUAL TABLE rt0 USING rtree(a,b,c); INSERT INTO rt0(a,b,c) VALUES(0,0.0,0.0); CREATE VIEW v0(x) AS SELECT DISTINCT rt0.b FROM rt0; SELECT v0.x FROM v0, rt0; } {0.0} do_execsql_test 19.1 { SELECT v0.x FROM v0, rt0 WHERE v0.x = rt0.b; } {0.0} finish_test |
Changes to ext/rtree/rtree2.test.
︙ | ︙ | |||
29 30 31 32 33 34 35 36 37 38 39 40 | if {[info exists G(isquick)] && $G(isquick)} { set ::NROW 100 set ::NSELECT 10 } foreach module {rtree_i32 rtree} { for {set nDim 1} {$nDim <= 5} {incr nDim} { do_test rtree2-$module.$nDim.1 { set cols [list] foreach c [list c0 c1 c2 c3 c4 c5 c6 c7 c8 c9] { | > | | 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | if {[info exists G(isquick)] && $G(isquick)} { set ::NROW 100 set ::NSELECT 10 } foreach module {rtree_i32 rtree} { if {$module=="rtree_i32"} {set etype INT} {set etype REAL} for {set nDim 1} {$nDim <= 5} {incr nDim} { do_test rtree2-$module.$nDim.1 { set cols [list] foreach c [list c0 c1 c2 c3 c4 c5 c6 c7 c8 c9] { lappend cols "$c $etype" } set cols [join [lrange $cols 0 [expr {$nDim*2-1}]] ", "] execsql " CREATE VIRTUAL TABLE t1 USING ${module}(ii, $cols); CREATE TABLE t2 (ii, $cols); " } {} |
︙ | ︙ |
Changes to ext/rtree/rtree6.test.
︙ | ︙ | |||
11 12 13 14 15 16 17 18 19 20 21 22 23 24 | # # if {![info exists testdir]} { set testdir [file join [file dirname [info script]] .. .. test] } source $testdir/tester.tcl ifcapable {!rtree || rtree_int_only} { finish_test return } # Operator Byte Value | > | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | # # if {![info exists testdir]} { set testdir [file join [file dirname [info script]] .. .. test] } source $testdir/tester.tcl set testprefix rtree6 ifcapable {!rtree || rtree_int_only} { finish_test return } # Operator Byte Value |
︙ | ︙ | |||
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 | CREATE VIRTUAL TABLE t1 USING rtree(ii, x1, x2, y1, y2); } } {} do_test rtree6-1.2 { rtree_strategy {SELECT * FROM t1 WHERE x1>10} } {E0} do_test rtree6-1.3 { rtree_strategy {SELECT * FROM t1 WHERE x1<10} } {C0} do_test rtree6-1.4 { rtree_strategy {SELECT * FROM t1,t2 WHERE k=ii AND x1<10} } {C0} do_test rtree6-1.5 { rtree_strategy {SELECT * FROM t1,t2 WHERE k=+ii AND x1<10} } {C0} do_eqp_test rtree6.2.1 { SELECT * FROM t1,t2 WHERE k=+ii AND x1<10 } { QUERY PLAN | > > > | | | | | | | | | | | | | 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 | CREATE VIRTUAL TABLE t1 USING rtree(ii, x1, x2, y1, y2); } } {} do_test rtree6-1.2 { rtree_strategy {SELECT * FROM t1 WHERE x1>10} } {E0} do_test rtree6-1.2.1 { rtree_strategy {SELECT * FROM t1 WHERE x1>10 AND x2 LIKE '%x%'} } {E0} do_test rtree6-1.3 { rtree_strategy {SELECT * FROM t1 WHERE x1<10} } {C0} do_test rtree6-1.4 { rtree_strategy {SELECT * FROM t1,t2 WHERE k=ii AND x1<10} } {C0} do_test rtree6-1.5 { rtree_strategy {SELECT * FROM t1,t2 WHERE k=+ii AND x1<10} } {C0} do_eqp_test rtree6.2.1 { SELECT * FROM t1,t2 WHERE k=+ii AND x1<10 } { QUERY PLAN |--SCAN t1 VIRTUAL TABLE INDEX 2:C0 `--SEARCH t2 USING INTEGER PRIMARY KEY (rowid=?) } do_eqp_test rtree6.2.2 { SELECT * FROM t1,t2 WHERE k=ii AND x1<10 } { QUERY PLAN |--SCAN t1 VIRTUAL TABLE INDEX 2:C0 `--SEARCH t2 USING INTEGER PRIMARY KEY (rowid=?) } do_eqp_test rtree6.2.3 { SELECT * FROM t1,t2 WHERE k=ii } { QUERY PLAN |--SCAN t1 VIRTUAL TABLE INDEX 2: `--SEARCH t2 USING INTEGER PRIMARY KEY (rowid=?) } do_eqp_test rtree6.2.4.1 { SELECT * FROM t1,t2 WHERE v=+ii and x1<10 and x2>10 } { QUERY PLAN |--SCAN t1 VIRTUAL TABLE INDEX 2:C0E1 `--SEARCH t2 USING AUTOMATIC COVERING INDEX (v=?) } do_eqp_test rtree6.2.4.2 { SELECT * FROM t1,t2 WHERE v=10 and x1<10 and x2>10 } { QUERY PLAN |--SCAN t1 VIRTUAL TABLE INDEX 2:C0E1 `--SEARCH t2 USING AUTOMATIC PARTIAL COVERING INDEX (v=?) } do_eqp_test rtree6.2.5 { SELECT * FROM t1,t2 WHERE k=ii AND x1<v } { QUERY PLAN |--SCAN t1 VIRTUAL TABLE INDEX 2: `--SEARCH t2 USING INTEGER PRIMARY KEY (rowid=?) } do_execsql_test rtree6-3.1 { CREATE VIRTUAL TABLE t3 USING rtree(id, x1, x2, y1, y2); INSERT INTO t3 VALUES(NULL, 1, 1, 2, 2); SELECT * FROM t3 WHERE x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND |
︙ | ︙ | |||
159 160 161 162 163 164 165 166 167 168 | x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>1.1 } {} expand_all_sql db finish_test | > > > > > > > > > | 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 | x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>1.1 } {} #------------------------------------------------------------------------- reset_db do_execsql_test 4.0 { CREATE VIRTUAL TABLE t1 USING rtree(id,x0,x1,y0,y1); } do_execsql_test 4.1 { DELETE FROM t1 WHERE x0>1 AND x1<2 OR y0<92; } expand_all_sql db finish_test |
Changes to ext/rtree/rtree9.test.
︙ | ︙ | |||
32 33 34 35 36 37 38 | do_execsql_test rtree9-1.3 { SELECT * FROM rt WHERE id MATCH cube(3, 3, 3, 2, 2, 2); } {} do_execsql_test rtree9-1.4 { DELETE FROM rt; } {} | | | 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | do_execsql_test rtree9-1.3 { SELECT * FROM rt WHERE id MATCH cube(3, 3, 3, 2, 2, 2); } {} do_execsql_test rtree9-1.4 { DELETE FROM rt; } {} unset -nocomplain x for {set i 0} {$i < 1000} {incr i} { set x [expr $i%10] set y [expr ($i/10)%10] set z [expr ($i/100)%10] execsql { INSERT INTO rt VALUES($i, $x, $x+1, $y, $y+1, $z, $z+1) } } do_rtree_integrity_test rtree9-2.0 rt |
︙ | ︙ |
Changes to ext/rtree/rtreeA.test.
︙ | ︙ | |||
141 142 143 144 145 146 147 | } create_t1 populate_t1 do_test rtreeA-2.2.0 { truncate_node 1 200 } {} do_corruption_tests rtreeA-2.2 { 1 "SELECT * FROM t1" | | | | | | | | 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 | } create_t1 populate_t1 do_test rtreeA-2.2.0 { truncate_node 1 200 } {} do_corruption_tests rtreeA-2.2 { 1 "SELECT * FROM t1" 2 "SELECT * FROM t1 WHERE +rowid=5" 3 "INSERT INTO t1 VALUES(1000, 1, 2, 3, 4)" 4 "SELECT * FROM t1 WHERE x1<10 AND x2>12" } #------------------------------------------------------------------------- # Set the "depth" of the tree stored on the root node incorrectly. Test # that this does not cause any problems. # create_t1 populate_t1 do_test rtreeA-3.1.0.1 { set_tree_depth t1 } {1} do_test rtreeA-3.1.0.2 { set_tree_depth t1 3 } {3} do_corruption_tests rtreeA-3.1 { 1 "SELECT * FROM t1" 2 "SELECT * FROM t1 WHERE +rowid=5" 3 "INSERT INTO t1 VALUES(1000, 1, 2, 3, 4)" } do_execsql_test rtreeA-3.1.0.3 { SELECT rtreecheck('main', 't1')!="ok" } {1} do_test rtreeA-3.2.0 { set_tree_depth t1 1000 } {1000} do_corruption_tests rtreeA-3.2 { 1 "SELECT * FROM t1" 2 "SELECT * FROM t1 WHERE +rowid=5" 3 "INSERT INTO t1 VALUES(1000, 1, 2, 3, 4)" } create_t1 populate_t1 do_test rtreeA-3.3.0 { execsql { DELETE FROM t1 WHERE rowid = 0 } set_tree_depth t1 65535 } {65535} do_corruption_tests rtreeA-3.3 { 1 "SELECT * FROM t1" 2 "SELECT * FROM t1 WHERE +rowid=5" 3 "INSERT INTO t1 VALUES(1000, 1, 2, 3, 4)" } do_execsql_test rtreeA-3.3.3.4 { SELECT rtreecheck('main', 't1') } {{Rtree depth out of range (65535) Wrong number of entries in %_rowid table - expected 0, actual 499 Wrong number of entries in %_parent table - expected 0, actual 23}} #------------------------------------------------------------------------- # Set the "number of entries" field on some nodes incorrectly. # create_t1 populate_t1 do_test rtreeA-4.1.0 { set_entry_count t1 1 4000 } {4000} do_corruption_tests rtreeA-4.1 { 1 "SELECT * FROM t1" 2 "SELECT * FROM t1 WHERE +rowid=5" 3 "INSERT INTO t1 VALUES(1000, 1, 2, 3, 4)" 4 "SELECT * FROM t1 WHERE x1<10 AND x2>12" } #------------------------------------------------------------------------- # Remove entries from the %_parent table and check that this does not # cause a crash. # create_t1 populate_t1 do_execsql_test rtreeA-5.1.0 { DELETE FROM t1_parent } {} do_corruption_tests rtreeA-5.1 { 1 "DELETE FROM t1 WHERE +rowid = 5" 2 "DELETE FROM t1" } do_execsql_test rtreeA-5.2 { SELECT rtreecheck('main', 't1')!="ok" } {1} |
︙ | ︙ |
Changes to ext/rtree/rtreeC.test.
︙ | ︙ | |||
26 27 28 29 30 31 32 | } do_eqp_test 1.1 { SELECT * FROM r_tree, t WHERE t.x>=min_x AND t.x<=max_x AND t.y>=min_y AND t.x<=max_y } { QUERY PLAN | | | | | | | | | | 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 | } do_eqp_test 1.1 { SELECT * FROM r_tree, t WHERE t.x>=min_x AND t.x<=max_x AND t.y>=min_y AND t.x<=max_y } { QUERY PLAN |--SCAN t `--SCAN r_tree VIRTUAL TABLE INDEX 2:D3B2D1B0 } do_eqp_test 1.2 { SELECT * FROM t, r_tree WHERE t.x>=min_x AND t.x<=max_x AND t.y>=min_y AND t.x<=max_y } { QUERY PLAN |--SCAN t `--SCAN r_tree VIRTUAL TABLE INDEX 2:D3B2D1B0 } do_eqp_test 1.3 { SELECT * FROM t, r_tree WHERE t.x>=min_x AND t.x<=max_x AND t.y>=min_y AND ?<=max_y } { QUERY PLAN |--SCAN t `--SCAN r_tree VIRTUAL TABLE INDEX 2:D3B2D1B0 } do_eqp_test 1.5 { SELECT * FROM t, r_tree } { QUERY PLAN |--SCAN r_tree VIRTUAL TABLE INDEX 2: `--SCAN t } do_execsql_test 2.0 { INSERT INTO t VALUES(0, 0); INSERT INTO t VALUES(0, 1); INSERT INTO t VALUES(0, 2); INSERT INTO t VALUES(0, 3); |
︙ | ︙ | |||
83 84 85 86 87 88 89 | sqlite3 db test.db do_eqp_test 2.1 { SELECT * FROM r_tree, t WHERE t.x>=min_x AND t.x<=max_x AND t.y>=min_y AND t.x<=max_y } { QUERY PLAN | | | | | | | | | | | | | | | | | | 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 | sqlite3 db test.db do_eqp_test 2.1 { SELECT * FROM r_tree, t WHERE t.x>=min_x AND t.x<=max_x AND t.y>=min_y AND t.x<=max_y } { QUERY PLAN |--SCAN t `--SCAN r_tree VIRTUAL TABLE INDEX 2:D3B2D1B0 } do_eqp_test 2.2 { SELECT * FROM t, r_tree WHERE t.x>=min_x AND t.x<=max_x AND t.y>=min_y AND t.x<=max_y } { QUERY PLAN |--SCAN t `--SCAN r_tree VIRTUAL TABLE INDEX 2:D3B2D1B0 } do_eqp_test 2.3 { SELECT * FROM t, r_tree WHERE t.x>=min_x AND t.x<=max_x AND t.y>=min_y AND ?<=max_y } { QUERY PLAN |--SCAN t `--SCAN r_tree VIRTUAL TABLE INDEX 2:D3B2D1B0 } do_eqp_test 2.5 { SELECT * FROM t, r_tree } { QUERY PLAN |--SCAN r_tree VIRTUAL TABLE INDEX 2: `--SCAN t } #------------------------------------------------------------------------- # Test that the special CROSS JOIN handling works with rtree tables. # do_execsql_test 3.1 { CREATE TABLE t1(x); CREATE TABLE t2(y); CREATE VIRTUAL TABLE t3 USING rtree(z, x1,x2, y1,y2); } do_eqp_test 3.2.1 { SELECT * FROM t1 CROSS JOIN t2 } { QUERY PLAN |--SCAN t1 `--SCAN t2 } do_eqp_test 3.2.2 { SELECT * FROM t2 CROSS JOIN t1 } { QUERY PLAN |--SCAN t2 `--SCAN t1 } do_eqp_test 3.3.1 { SELECT * FROM t1 CROSS JOIN t3 } { QUERY PLAN |--SCAN t1 `--SCAN t3 VIRTUAL TABLE INDEX 2: } do_eqp_test 3.3.2 { SELECT * FROM t3 CROSS JOIN t1 } { QUERY PLAN |--SCAN t3 VIRTUAL TABLE INDEX 2: `--SCAN t1 } #-------------------------------------------------------------------- # Test that LEFT JOINs are not reordered if the right-hand-side is # a virtual table. # reset_db |
︙ | ︙ | |||
173 174 175 176 177 178 179 | } {1 1 3 {}} #-------------------------------------------------------------------- # Test that the sqlite_stat1 data is used correctly. # reset_db do_execsql_test 5.1 { | | | 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 | } {1 1 3 {}} #-------------------------------------------------------------------- # Test that the sqlite_stat1 data is used correctly. # reset_db do_execsql_test 5.1 { CREATE TABLE t1(x INT PRIMARY KEY, y); CREATE VIRTUAL TABLE rt USING rtree(id, x1, x2, +d1); INSERT INTO t1(x) VALUES(1); INSERT INTO t1(x) SELECT x+1 FROM t1; -- 2 INSERT INTO t1(x) SELECT x+2 FROM t1; -- 4 INSERT INTO t1(x) SELECT x+4 FROM t1; -- 8 INSERT INTO t1(x) SELECT x+8 FROM t1; -- 16 |
︙ | ︙ | |||
199 200 201 202 203 204 205 | # First test a query with no ANALYZE data at all. The outer loop is # real table "t1". # do_eqp_test 5.2 { SELECT * FROM t1, rt WHERE x==id; } { QUERY PLAN | | | | | | | | 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 | # First test a query with no ANALYZE data at all. The outer loop is # real table "t1". # do_eqp_test 5.2 { SELECT * FROM t1, rt WHERE x==id; } { QUERY PLAN |--SCAN t1 `--SCAN rt VIRTUAL TABLE INDEX 1: } # Now create enough ANALYZE data to tell SQLite that virtual table "rt" # contains very few rows. This causes it to move "rt" to the outer loop. # do_execsql_test 5.3 { ANALYZE; DELETE FROM sqlite_stat1 WHERE tbl='t1'; } db close sqlite3 db test.db do_eqp_test 5.4 { SELECT * FROM t1, rt WHERE x==id; } { QUERY PLAN |--SCAN rt VIRTUAL TABLE INDEX 2: `--SEARCH t1 USING INDEX sqlite_autoindex_t1_1 (x=?) } # Delete the ANALYZE data. "t1" should be the outer loop again. # do_execsql_test 5.5 { DROP TABLE sqlite_stat1; } db close sqlite3 db test.db do_eqp_test 5.6 { SELECT * FROM t1, rt WHERE x==id; } { QUERY PLAN |--SCAN t1 `--SCAN rt VIRTUAL TABLE INDEX 1: } # This time create and attach a database that contains ANALYZE data for # tables of the same names as those used internally by virtual table # "rt". Check that the rtree module is not fooled into using this data. # Table "t1" should remain the outer loop. # |
︙ | ︙ | |||
254 255 256 257 258 259 260 | sqlite3 db test.db execsql { ATTACH 'test.db2' AS aux; } } {} do_eqp_test 5.8 { SELECT * FROM t1, rt WHERE x==id; } { QUERY PLAN | | | | 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 | sqlite3 db test.db execsql { ATTACH 'test.db2' AS aux; } } {} do_eqp_test 5.8 { SELECT * FROM t1, rt WHERE x==id; } { QUERY PLAN |--SCAN t1 `--SCAN rt VIRTUAL TABLE INDEX 1: } #-------------------------------------------------------------------- # Test that having a second connection drop the sqlite_stat1 table # before it is required by rtreeConnect() does not cause problems. # ifcapable rtree { |
︙ | ︙ | |||
323 324 325 326 327 328 329 | do_eqp_execsql_test 7.1 { SELECT id FROM xdir, rt, ydir ON (y1 BETWEEN ymin AND ymax) WHERE (x1 BETWEEN xmin AND xmax); } { QUERY PLAN | | | | | | | | | | | | | | 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 | do_eqp_execsql_test 7.1 { SELECT id FROM xdir, rt, ydir ON (y1 BETWEEN ymin AND ymax) WHERE (x1 BETWEEN xmin AND xmax); } { QUERY PLAN |--SCAN xdir |--SCAN ydir `--SCAN rt VIRTUAL TABLE INDEX 2:B2D3B0D1 } { 2 4 } do_eqp_execsql_test 7.2 { SELECT * FROM xdir, rt LEFT JOIN ydir ON (y1 BETWEEN ymin AND ymax) WHERE (x1 BETWEEN xmin AND xmax); } { QUERY PLAN |--SCAN xdir |--SCAN rt VIRTUAL TABLE INDEX 2:B0D1 `--SCAN ydir } { 5 1 2 7 12 14 {} 5 2 2 7 8 12 10 5 4 5 5 10 10 10 } do_eqp_execsql_test 7.3 { SELECT id FROM xdir, rt CROSS JOIN ydir ON (y1 BETWEEN ymin AND ymax) WHERE (x1 BETWEEN xmin AND xmax); } { QUERY PLAN |--SCAN xdir |--SCAN rt VIRTUAL TABLE INDEX 2:B0D1 `--SCAN ydir } { 2 4 } do_eqp_execsql_test 7.4 { SELECT id FROM rt, xdir CROSS JOIN ydir ON (y1 BETWEEN ymin AND ymax) WHERE (x1 BETWEEN xmin AND xmax); } { QUERY PLAN |--SCAN xdir |--SCAN rt VIRTUAL TABLE INDEX 2:B0D1 `--SCAN ydir } { 2 4 } finish_test |
Changes to ext/rtree/rtreeH.test.
︙ | ︙ | |||
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | do_execsql_test rtreeH-101 { SELECT * FROM t1_rowid ORDER BY rowid } {1 1 {lower-left corner} {} 2 1 {upper-left corner} {} 3 1 {lower-right corner} {} 4 1 {upper-right corner} {} 5 1 center {} 6 1 {left edge} {} 7 1 {right edge} {} 8 1 {bottom edge} {} 9 1 {top edge} {} 10 1 {the whole thing} {} 11 1 {left half} {} 12 1 {right half} {} 13 1 {bottom half} {} 14 1 {top half} {}} do_execsql_test rtreeH-102 { SELECT * FROM t1 WHERE rowid=5; } {5 40.0 60.0 40.0 60.0 center {}} do_execsql_test rtreeH-103 { SELECT * FROM t1 WHERE label='center'; } {5 40.0 60.0 40.0 60.0 center {}} do_rtree_integrity_test rtreeH-110 t1 do_execsql_test rtreeH-120 { SELECT label FROM t1 WHERE x1<=50 ORDER BY id } {{lower-left corner} {upper-left corner} {left edge} {left half}} do_execsql_test rtreeH-121 { | > > > > > > > > > > > > > > > > > > > > > > > | 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 | do_execsql_test rtreeH-101 { SELECT * FROM t1_rowid ORDER BY rowid } {1 1 {lower-left corner} {} 2 1 {upper-left corner} {} 3 1 {lower-right corner} {} 4 1 {upper-right corner} {} 5 1 center {} 6 1 {left edge} {} 7 1 {right edge} {} 8 1 {bottom edge} {} 9 1 {top edge} {} 10 1 {the whole thing} {} 11 1 {left half} {} 12 1 {right half} {} 13 1 {bottom half} {} 14 1 {top half} {}} do_execsql_test rtreeH-102 { SELECT * FROM t1 WHERE rowid=5; } {5 40.0 60.0 40.0 60.0 center {}} do_execsql_test rtreeH-102b { SELECT * FROM t1 WHERE rowid=5.0; } {5 40.0 60.0 40.0 60.0 center {}} do_execsql_test rtreeH-102c { SELECT * FROM t1 WHERE rowid='5'; } {5 40.0 60.0 40.0 60.0 center {}} do_execsql_test rtreeH-102d { SELECT * FROM t1 WHERE rowid='0005'; } {5 40.0 60.0 40.0 60.0 center {}} do_execsql_test rtreeH-102e { SELECT * FROM t1 WHERE rowid='+5.0e+0'; } {5 40.0 60.0 40.0 60.0 center {}} do_execsql_test rtreeH-103 { SELECT * FROM t1 WHERE label='center'; } {5 40.0 60.0 40.0 60.0 center {}} do_execsql_test rtreeH-104 { SELECT * FROM t1 WHERE rowid='+5.0e+0x'; } {} do_execsql_test rtreeH-105 { SELECT * FROM t1 WHERE rowid=x'35'; } {} do_execsql_test rtreeH-106 { SELECT * FROM t1 WHERE rowid=null; } {} do_rtree_integrity_test rtreeH-110 t1 do_execsql_test rtreeH-120 { SELECT label FROM t1 WHERE x1<=50 ORDER BY id } {{lower-left corner} {upper-left corner} {left edge} {left half}} do_execsql_test rtreeH-121 { |
︙ | ︙ |
Added ext/rtree/rtreeI.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 | # 2019-12-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. # #*********************************************************************** # Additional test cases 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 ifcapable !rtree { finish_test ; return } # The following is a test of rowvalue handling on virtual tables that # deal with inequalities and that set the OMIT flag on terms of the # WHERE clause. This is not specific to rtree. We just use rtree because # it is a convenient test platform since it has all the right # characteristics. # do_execsql_test rtreeI-1.10 { CREATE TABLE t1(a); INSERT INTO t1 VALUES(2); CREATE VIRTUAL TABLE t2 USING rtree(id,x0,x1); INSERT INTO t2(id,x0,x1) VALUES(1,2,3); } {} do_execsql_test rtreeI-1.20 { SELECT 123 FROM t1, t2 WHERE (a,0)>(x0,0); } {} do_execsql_test rtreeI-1.21 { SELECT 123 FROM t1, t2 WHERE (a,0.1)>(x0,0); } {123} do_execsql_test rtreeI-1.22 { SELECT 123 FROM t1, t2 WHERE (a,0)>=(x0,0); } {123} do_execsql_test rtreeI-1.23 { SELECT 123 FROM t1, t2 WHERE (a,0)<=(x0,0); } {123} do_execsql_test rtreeI-1.24 { SELECT 123 FROM t1, t2 WHERE (a,0)<(x0,0); } {} do_execsql_test rtreeI-1.30 { SELECT 123 FROM t1, t2 WHERE (x0,0)<(a,0); } {} do_execsql_test rtreeI-1.31 { SELECT 123 FROM t1, t2 WHERE (x0,0)<(a,0.1); } {123} do_execsql_test rtreeI-1.40 { SELECT 123 FROM t1, t2 WHERE x1<5 AND id<99 AND (a,0)>(x0,0); } {} do_execsql_test rtreeI-1.41 { SELECT 123 FROM t1, t2 WHERE x1<5 AND id<99 AND (a,0.5)>(x0,0); } {123} do_execsql_test rtreeI-1.42 { SELECT 123 FROM t1, t2 WHERE x1<5 AND id<99 AND (a,0)>=(x0,0); } {123} do_execsql_test rtreeI-1.43 { SELECT 123 FROM t1, t2 WHERE x1<5 AND id<99 AND (a,0)<(x0,0); } {} do_execsql_test rtreeI-1.50 { SELECT 123 FROM t1, t2 WHERE 5>x1 AND 99>id AND (x0,0)<(a,0); } {} do_execsql_test rtreeI-1.51 { SELECT 123 FROM t1, t2 WHERE 5>x1 AND 99>id AND (x0,0)<(a,0.5); } {123} finish_test |
Added ext/rtree/rtreecirc.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 | # 2018 Dec 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 FTS5 module. # 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 rtreecirc ifcapable !rtree { finish_test return } do_execsql_test 1.0 { CREATE VIRTUAL TABLE rt USING rtree(id, x1, x2, y1, y2); SELECT name FROM sqlite_master ORDER BY 1; } { rt rt_node rt_parent rt_rowid } db_save_and_close foreach {tn schema sql} { 1 { CREATE TRIGGER tr1 AFTER INSERT ON rt_node BEGIN SELECT * FROM rt; END; } { INSERT INTO rt VALUES(1, 2, 3, 4, 5); } 2 { CREATE TRIGGER tr1 AFTER INSERT ON rt_parent BEGIN SELECT * FROM rt; END; } { INSERT INTO rt VALUES(1, 2, 3, 4, 5); } 3 { CREATE TRIGGER tr1 AFTER INSERT ON rt_rowid BEGIN SELECT * FROM rt; END; } { INSERT INTO rt VALUES(1, 2, 3, 4, 5); } } { db_restore_and_reopen do_execsql_test 1.1.$tn.1 $schema do_catchsql_test 1.1.$tn.2 $sql {1 {no such table: main.rt}} db close } finish_test |
Added ext/rtree/rtreedoc.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 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 | # 2021 September 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. # #*********************************************************************** # # The focus of this file is testing the r-tree extension. # 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 rtreedoc ifcapable !rtree { finish_test return } # This command returns the number of columns in table $tbl within the # database opened by database handle $db proc column_count {db tbl} { set nCol 0 $db eval "PRAGMA table_info = $tbl" { incr nCol } return $nCol } proc column_name_list {db tbl} { set lCol [list] $db eval "PRAGMA table_info = $tbl" { lappend lCol $name } return $lCol } unset -nocomplain res #------------------------------------------------------------------------- #------------------------------------------------------------------------- # Section 3 of documentation. #------------------------------------------------------------------------- #------------------------------------------------------------------------- set testprefix rtreedoc-1 # EVIDENCE-OF: R-15060-13876 A 1-dimensional R*Tree thus has 3 columns. do_execsql_test 1.1.1 { CREATE VIRTUAL TABLE rt1 USING rtree(id, x1,x2) } do_test 1.1.2 { column_count db rt1 } 3 # EVIDENCE-OF: R-19353-19546 A 2-dimensional R*Tree has 5 columns. do_execsql_test 1.2.1 { CREATE VIRTUAL TABLE rt2 USING rtree(id,x1,x2, y1,y2) } do_test 1.2.2 { column_count db rt2 } 5 # EVIDENCE-OF: R-13615-19528 A 3-dimensional R*Tree has 7 columns. do_execsql_test 1.3.1 { CREATE VIRTUAL TABLE rt3 USING rtree(id, x1,x2, y1,y2, z1,z2) } do_test 1.3.2 { column_count db rt3 } 7 # EVIDENCE-OF: R-53479-41922 A 4-dimensional R*Tree has 9 columns. do_execsql_test 1.4.1 { CREATE VIRTUAL TABLE rt4 USING rtree(id, x1,x2, y1,y2, z1,z2, v1,v2) } do_test 1.4.2 { column_count db rt4 } 9 # EVIDENCE-OF: R-13981-28768 And a 5-dimensional R*Tree has 11 columns. do_execsql_test 1.5.1 { CREATE VIRTUAL TABLE rt5 USING rtree(id, x1,x2, y1,y2, z1,z2, v1,v2, w1,w2) } do_test 1.5.2 { column_count db rt5 } 11 # Attempt to create r-tree tables with 6 and 7 dimensions. # # EVIDENCE-OF: R-61533-25862 The SQLite R*Tree implementation does not # support R*Trees wider than 5 dimensions. do_catchsql_test 2.1.1 { CREATE VIRTUAL TABLE rt6 USING rtree( id, x1,x2, y1,y2, z1,z2, v1,v2, w1,w2, a1,a2 ) } {1 {Too many columns for an rtree table}} do_catchsql_test 2.1.2 { CREATE VIRTUAL TABLE rt6 USING rtree( id, x1,x2, y1,y2, z1,z2, v1,v2, w1,w2, a1,a2, b1, b2 ) } {1 {Too many columns for an rtree table}} # Attempt to create r-tree tables with no columns, a single column, or # an even number of columns. This and the tests above establish that: # # EVIDENCE-OF: R-16717-50504 Each R*Tree index is a virtual table with # an odd number of columns between 3 and 11. foreach {tn cols err} { 1 "" "Too few columns for an rtree table" 2 "x" "Too few columns for an rtree table" 3 "x,y" "Too few columns for an rtree table" 4 "a,b,c,d" "Wrong number of columns for an rtree table" 5 "a,b,c,d,e,f" "Wrong number of columns for an rtree table" 6 "a,b,c,d,e,f,g,h" "Wrong number of columns for an rtree table" 7 "a,b,c,d,e,f,g,h,i,j" "Wrong number of columns for an rtree table" 8 "a,b,c,d,e,f,g,h,i,j,k,l" "Too many columns for an rtree table" } { do_catchsql_test 3.$tn " CREATE VIRTUAL TABLE xyz USING rtree($cols) " [list 1 $err] } # EVIDENCE-OF: R-17874-21123 The first column of an SQLite R*Tree is # similar to an integer primary key column of a normal SQLite table. # # EVIDENCE-OF: R-46619-65417 The first column is always a 64-bit signed # integer primary key. # # EVIDENCE-OF: R-46866-24036 It may only store a 64-bit signed integer # value. # # EVIDENCE-OF: R-00250-64843 If an attempt is made to insert any other # non-integer value into this column, the r-tree module silently # converts it to an integer before writing it into the database. # do_execsql_test 4.0 { CREATE VIRTUAL TABLE rt USING rtree(id, x1, x2) } foreach {tn val res} { 1 10 10 2 10.6 10 3 10.99 10 4 '123' 123 5 X'313233' 123 6 -10 -10 7 9223372036854775807 9223372036854775807 8 -9223372036854775808 -9223372036854775808 9 '9223372036854775807' 9223372036854775807 10 '-9223372036854775808' -9223372036854775808 11 'hello+world' 0 } { do_execsql_test 4.$tn.1 " DELETE FROM rt; INSERT INTO rt VALUES($val, 10, 20); " do_execsql_test 4.$tn.2 { SELECT typeof(id), id FROM rt } [list integer $res] } # EVIDENCE-OF: R-15544-29079 Inserting a NULL value into this column # causes SQLite to automatically generate a new unique primary key # value. do_execsql_test 5.1 { DELETE FROM rt; INSERT INTO rt VALUES(100, 1, 2); INSERT INTO rt VALUES(NULL, 1, 2); } do_execsql_test 5.2 { SELECT id FROM rt } {100 101} do_execsql_test 5.3 { INSERT INTO rt VALUES(9223372036854775807, 1, 2); INSERT INTO rt VALUES(NULL, 1, 2); } do_execsql_test 5.4 { SELECT count(*) FROM rt; } 4 do_execsql_test 5.5 { SELECT id IN(100, 101, 9223372036854775807) FROM rt ORDER BY 1; } {0 1 1 1} # EVIDENCE-OF: R-64317-38978 The other columns are pairs, one pair per # dimension, containing the minimum and maximum values for that # dimension, respectively. # # Show this by observing that attempts to insert rows with max>min fail. # do_execsql_test 6.1 { CREATE VIRTUAL TABLE rtF USING rtree(id, x1,x2, y1,y2); CREATE VIRTUAL TABLE rtI USING rtree_i32(id, x1,x2, y1,y2, z1,z2); } foreach {tn x1 x2 y1 y2 ok} { 1 10.3 20.1 30.9 40.2 1 2 10.3 20.1 40.2 30.9 0 3 10.3 30.9 20.1 40.2 1 4 20.1 10.3 30.9 40.2 0 } { do_test 6.2.$tn { catch { db eval { INSERT INTO rtF VALUES(NULL, $x1, $x2, $y1, $y2) } } } [expr $ok==0] } foreach {tn x1 x2 y1 y2 z1 z2 ok} { 1 10 20 30 40 50 60 1 2 10 20 30 40 60 50 0 3 10 20 30 50 40 60 1 4 10 20 40 30 50 60 0 5 10 30 20 40 50 60 1 6 20 10 30 40 50 60 0 } { do_test 6.3.$tn { catch { db eval { INSERT INTO rtI VALUES(NULL,$x1,$x2,$y1,$y2,$z1,$z2) } } } [expr $ok==0] } # EVIDENCE-OF: R-08054-15429 The min/max-value pair columns are stored # as 32-bit floating point values for "rtree" virtual tables or as # 32-bit signed integers in "rtree_i32" virtual tables. # # Show this by showing that large values are rounded in ways consistent # with those two 32-bit types. do_execsql_test 7.1 { DELETE FROM rtI; INSERT INTO rtI VALUES( 0, -2000000000, 2000000000, -5000000000, 5000000000, -1000000000000, 10000000000000 ); SELECT * FROM rtI; } { 0 -2000000000 2000000000 -705032704 705032704 727379968 1316134912 } do_execsql_test 7.2 { DELETE FROM rtF; INSERT INTO rtF VALUES( 0, -2000000000, 2000000000, -1000000000000, 10000000000000 ); SELECT * FROM rtF; } { 0 -2000000000.0 2000000000.0 -1000000126976.0 10000000876544.0 } # EVIDENCE-OF: R-47371-54529 Unlike regular SQLite tables which can # store data in a variety of datatypes and formats, the R*Tree rigidly # enforce these storage types. # # EVIDENCE-OF: R-39153-14977 If any other type of value is inserted into # such a column, the r-tree module silently converts it to the required # type before writing the new record to the database. do_execsql_test 8.1 { DELETE FROM rtI; INSERT INTO rtI VALUES( 1, 'hello world', X'616263', NULL, 44.5, 1000, 9999.9999 ); SELECT * FROM rtI; } { 1 0 0 0 44 1000 9999 } do_execsql_test 8.2 { SELECT typeof(x1), typeof(x2), typeof(y1), typeof(y2), typeof(z1), typeof(z2) FROM rtI } {integer integer integer integer integer integer} do_execsql_test 8.3 { DELETE FROM rtF; INSERT INTO rtF VALUES( 1, 'hello world', X'616263', NULL, 44 ); SELECT * FROM rtF; } { 1 0.0 0.0 0.0 44.0 } do_execsql_test 8.4 { SELECT typeof(x1), typeof(x2), typeof(y1), typeof(y2) FROM rtF } {real real real real} #------------------------------------------------------------------------- #------------------------------------------------------------------------- # Section 3.1 of documentation. #------------------------------------------------------------------------- #------------------------------------------------------------------------- set testprefix rtreedoc-2 reset_db foreach {tn name clist} { 1 t1 "id x1 x2" 2 t2 "id x1 x2 y1 y2 z1 z2" } { # EVIDENCE-OF: R-15142-18077 A new R*Tree index is created as follows: # CREATE VIRTUAL TABLE <name> USING rtree(<column-names>); do_execsql_test 1.$tn.1 " CREATE VIRTUAL TABLE $name USING rtree([join $clist ,]) " # EVIDENCE-OF: R-51698-09302 The <name> is the name your # application chooses for the R*Tree index and <column-names> is a # comma separated list of between 3 and 11 columns. do_test 1.$tn.2 { column_name_list db $name } [list {*}$clist] # EVIDENCE-OF: R-50130-53472 The virtual <name> table creates # three shadow tables to actually store its content. do_execsql_test 1.$tn.3 { SELECT count(*) FROM sqlite_schema } [expr 1+3] # EVIDENCE-OF: R-45256-35998 The names of these shadow tables are: # <name>_node <name>_rowid <name>_parent do_execsql_test 1.$tn.4 { SELECT name FROM sqlite_schema WHERE rootpage>0 ORDER BY 1 } [list ${name}_node ${name}_parent ${name}_rowid] do_execsql_test 1.$tn.5 "DROP TABLE $name" } # EVIDENCE-OF: R-11241-54478 As an example, consider creating a # two-dimensional R*Tree index for use in spatial queries: CREATE # VIRTUAL TABLE demo_index USING rtree( id, -- Integer primary key minX, # maxX, -- Minimum and maximum X coordinate minY, maxY -- Minimum and # maximum Y coordinate ); do_execsql_test 2.0 { CREATE VIRTUAL TABLE demo_index USING rtree( id, -- Integer primary key minX, maxX, -- Minimum and maximum X coordinate minY, maxY -- Minimum and maximum Y coordinate ); INSERT INTO demo_index VALUES(1,2,3,4,5); INSERT INTO demo_index VALUES(6,7,8,9,10); } # EVIDENCE-OF: R-02287-33529 The shadow tables are ordinary SQLite data # tables. # # Ordinary tables. With ordinary sqlite_schema entries. do_execsql_test 2.1 { SELECT type, name, sql FROM sqlite_schema WHERE sql NOT LIKE '%virtual%' } { table demo_index_rowid {CREATE TABLE "demo_index_rowid"(rowid INTEGER PRIMARY KEY,nodeno)} table demo_index_node {CREATE TABLE "demo_index_node"(nodeno INTEGER PRIMARY KEY,data)} table demo_index_parent {CREATE TABLE "demo_index_parent"(nodeno INTEGER PRIMARY KEY,parentnode)} } # EVIDENCE-OF: R-10863-13089 You can query them directly if you like, # though this unlikely to reveal anything particularly useful. # # Querying: do_execsql_test 2.2 { SELECT count(*) FROM demo_index_node; SELECT count(*) FROM demo_index_rowid; SELECT count(*) FROM demo_index_parent; } {1 2 0} # EVIDENCE-OF: R-05650-46070 And you can UPDATE, DELETE, INSERT or even # DROP the shadow tables, though doing so will corrupt your R*Tree # index. do_execsql_test 2.3 { DELETE FROM demo_index_rowid; INSERT INTO demo_index_parent VALUES(2, 3); UPDATE demo_index_node SET data = 'hello world' } do_catchsql_test 2.4 { SELECT * FROM demo_index WHERE minX>10 AND maxX<30 } {1 {database disk image is malformed}} do_execsql_test 2.5 { DROP TABLE demo_index_rowid } #------------------------------------------------------------------------- #------------------------------------------------------------------------- # Section 3.1.1 of documentation. #------------------------------------------------------------------------- #------------------------------------------------------------------------- set testprefix rtreedoc-3 reset_db # EVIDENCE-OF: R-44253-50720 In the argments to "rtree" in the CREATE # VIRTUAL TABLE statement, the names of the columns are taken from the # first token of each argument. All subsequent tokens within each # argument are silently ignored. # foreach {tn cols lCol} { 1 {(id TEXT, x1 TEXT, x2 TEXT, y1 TEXT, y2 TEXT)} {id x1 x2 y1 y2} 2 {(id TEXT, x1 UNIQUE, x2 TEXT, y1 NOT NULL, y2 TEXT)} {id x1 x2 y1 y2} 3 {(id, x1 DEFAULT 4, x2 TEXT, y1 NOT NULL, y2 TEXT)} {id x1 x2 y1 y2} } { do_execsql_test 1.$tn.1 " CREATE VIRTUAL TABLE abc USING rtree $cols " do_test 1.$tn.2 { column_name_list db abc } $lCol # EVIDENCE-OF: R-52032-06717 This means, for example, that if you try to # give a column a type affinity or add a constraint such as UNIQUE or # NOT NULL or DEFAULT to a column, those extra tokens are accepted as # valid, but they do not change the behavior of the rtree. # Show there are no UNIQUE constraints do_execsql_test 1.$tn.3 { INSERT INTO abc VALUES(1, 10.0, 20.0, 10.0, 20.0); INSERT INTO abc VALUES(2, 10.0, 20.0, 10.0, 20.0); } # Show the default values have not been modified do_execsql_test 1.$tn.4 { INSERT INTO abc DEFAULT VALUES; SELECT * FROM abc WHERE rowid NOT IN (1,2) } {3 0.0 0.0 0.0 0.0} # Show that there are no NOT NULL constraints do_execsql_test 1.$tn.5 { INSERT INTO abc VALUES(NULL, NULL, NULL, NULL, NULL); SELECT * FROM abc WHERE rowid NOT IN (1,2,3) } {4 0.0 0.0 0.0 0.0} # EVIDENCE-OF: R-06893-30579 In an RTREE virtual table, the first column # always has a type affinity of INTEGER and all other data columns have # a type affinity of REAL. do_execsql_test 1.$tn.5 { INSERT INTO abc VALUES('5', '5', '5', '5', '5'); SELECT * FROM abc WHERE rowid NOT IN (1,2,3,4) } {5 5.0 5.0 5.0 5.0} do_execsql_test 1.$tn.6 { SELECT type FROM pragma_table_info('abc') ORDER BY cid } {INT REAL REAL REAL REAL} do_execsql_test 1.$tn.7 " CREATE VIRTUAL TABLE abc2 USING rtree_i32 $cols " # EVIDENCE-OF: R-06224-52418 In an RTREE_I32 virtual table, all columns # have type affinity of INTEGER. do_execsql_test 1.$tn.8 { INSERT INTO abc2 VALUES('6.0', '6.0', '6.0', '6.0', '6.0'); SELECT * FROM abc2 } {6 6 6 6 6} do_execsql_test 1.$tn.9 { SELECT type FROM pragma_table_info('abc2') ORDER BY cid } {INT INT INT INT INT} do_execsql_test 1.$tn.10 { DROP TABLE abc; DROP TABLE abc2; } } #------------------------------------------------------------------------- #------------------------------------------------------------------------- # Section 3.2 of documentation. #------------------------------------------------------------------------- #------------------------------------------------------------------------- set testprefix rtreedoc-4 reset_db # EVIDENCE-OF: R-36195-31555 The usual INSERT, UPDATE, and DELETE # commands work on an R*Tree index just like on regular tables. # # Create a regular table and an rtree table. Perform INSERT, UPDATE and # DELETE operations, then observe that the contents of the two tables # are identical. do_execsql_test 1.0 { CREATE VIRTUAL TABLE rt USING rtree(id, x1, x2); CREATE TABLE t1(id INTEGER PRIMARY KEY, x1 REAL, x2 REAL); } foreach {tn sql} { 1 "INSERT INTO %TBL% VALUES(5, 11,12)" 2 "INSERT INTO %TBL% VALUES(11, -11,14.5)" 3 "UPDATE %TBL% SET x1=-99 WHERE id=11" 4 "DELETE FROM %TBL% WHERE x2=14.5" 5 "DELETE FROM %TBL%" } { set sql1 [string map {%TBL% rt} $sql] set sql2 [string map {%TBL% t1} $sql] do_execsql_test 1.$tn.0 $sql1 do_execsql_test 1.$tn.1 $sql2 set data1 [execsql {SELECT * FROM rt ORDER BY 1}] set data2 [execsql {SELECT * FROM t1 ORDER BY 1}] set res [expr {$data1==$data2}] do_test 1.$tn.2 {set res} 1 } # EVIDENCE-OF: R-56987-45305 do_execsql_test 2.0 { CREATE VIRTUAL TABLE demo_index USING rtree( id, -- Integer primary key minX, maxX, -- Minimum and maximum X coordinate minY, maxY -- Minimum and maximum Y coordinate ); INSERT INTO demo_index VALUES (28215, -80.781227, -80.604706, 35.208813, 35.297367), (28216, -80.957283, -80.840599, 35.235920, 35.367825), (28217, -80.960869, -80.869431, 35.133682, 35.208233), (28226, -80.878983, -80.778275, 35.060287, 35.154446), (28227, -80.745544, -80.555382, 35.130215, 35.236916), (28244, -80.844208, -80.841988, 35.223728, 35.225471), (28262, -80.809074, -80.682938, 35.276207, 35.377747), (28269, -80.851471, -80.735718, 35.272560, 35.407925), (28270, -80.794983, -80.728966, 35.059872, 35.161823), (28273, -80.994766, -80.875259, 35.074734, 35.172836), (28277, -80.876793, -80.767586, 35.001709, 35.101063), (28278, -81.058029, -80.956375, 35.044701, 35.223812), (28280, -80.844208, -80.841972, 35.225468, 35.227203), (28282, -80.846382, -80.844193, 35.223972, 35.225655); } #------------------------------------------------------------------------- #------------------------------------------------------------------------- # Section 3.3 of documentation. #------------------------------------------------------------------------- #------------------------------------------------------------------------- set testprefix rtreedoc-5 do_execsql_test 1.0 { INSERT INTO demo_index SELECT NULL, minX, maxX, minY+0.2, maxY+0.2 FROM demo_index; INSERT INTO demo_index SELECT NULL, minX+0.2, maxX+0.2, minY, maxY FROM demo_index; INSERT INTO demo_index SELECT NULL, minX, maxX, minY+0.4, maxY+0.4 FROM demo_index; INSERT INTO demo_index SELECT NULL, minX+0.4, maxX+0.4, minY, maxY FROM demo_index; INSERT INTO demo_index SELECT NULL, minX, maxX, minY+0.8, maxY+0.8 FROM demo_index; INSERT INTO demo_index SELECT NULL, minX+0.8, maxX+0.8, minY, maxY FROM demo_index; SELECT count(*) FROM demo_index; } {896} proc do_vmstep_test {tn sql expr} { execsql $sql set step [db status vmstep] do_test $tn.$step "expr {[subst $expr]}" 1 } # EVIDENCE-OF: R-45880-07724 Any valid query will work against an R*Tree # index. do_execsql_test 1.1.0 { CREATE TABLE demo_tbl AS SELECT * FROM demo_index; } foreach {tn sql} { 1 {SELECT * FROM %TBL% ORDER BY 1} 2 {SELECT max(minX) FROM %TBL% ORDER BY 1} 3 {SELECT max(minX) FROM %TBL% GROUP BY round(minY) ORDER BY 1} } { set sql1 [string map {%TBL% demo_index} $sql] set sql2 [string map {%TBL% demo_tbl} $sql] do_execsql_test 1.1.$tn $sql1 [execsql $sql2] } # EVIDENCE-OF: R-60814-18273 The R*Tree implementation just makes some # kinds of queries especially efficient. # # The second query is more efficient than the first. do_vmstep_test 1.2.1 {SELECT * FROM demo_index WHERE +rowid=28269} {$step>2000} do_vmstep_test 1.2.2 {SELECT * FROM demo_index WHERE rowid=28269} {$step<100} # EVIDENCE-OF: R-37800-50174 Queries against the primary key are # efficient: SELECT * FROM demo_index WHERE id=28269; do_vmstep_test 2.2 { SELECT * FROM demo_index WHERE id=28269 } {$step < 100} # EVIDENCE-OF: R-35847-18866 The big reason for using an R*Tree is so # that you can efficiently do range queries against the coordinate # ranges. # # EVIDENCE-OF: R-49927-54202 do_vmstep_test 2.3 { SELECT id FROM demo_index WHERE minX<=-80.77470 AND maxX>=-80.77470 AND minY<=35.37785 AND maxY>=35.37785; } {$step < 100} # EVIDENCE-OF: R-12823-37176 The query above will quickly locate all # zipcodes that contain the SQLite main office in their bounding box, # even if the R*Tree contains many entries. # do_execsql_test 2.4 { SELECT id FROM demo_index WHERE minX<=-80.77470 AND maxX>=-80.77470 AND minY<=35.37785 AND maxY>=35.37785; } { 28322 28269 } # EVIDENCE-OF: R-07351-00257 For example, to find all zipcode bounding # boxes that overlap with the 28269 zipcode: SELECT A.id FROM demo_index # AS A, demo_index AS B WHERE A.maxX>=B.minX AND A.minX<=B.maxX # AND A.maxY>=B.minY AND A.minY<=B.maxY AND B.id=28269; # # Also check that it is efficient # # EVIDENCE-OF: R-39094-01937 This second query will find both 28269 # entry (since every bounding box overlaps with itself) and also other # zipcode that is close enough to 28269 that their bounding boxes # overlap. # # 28269 is there in the result. # do_vmstep_test 2.5.1 { SELECT A.id FROM demo_index AS A, demo_index AS B WHERE A.maxX>=B.minX AND A.minX<=B.maxX AND A.maxY>=B.minY AND A.minY<=B.maxY AND B.id=28269 } {$step < 100} do_execsql_test 2.5.2 { SELECT A.id FROM demo_index AS A, demo_index AS B WHERE A.maxX>=B.minX AND A.minX<=B.maxX AND A.maxY>=B.minY AND A.minY<=B.maxY AND B.id=28269; } { 28293 28216 28322 28286 28269 28215 28336 28262 28291 28320 28313 28298 28287 } # EVIDENCE-OF: R-02723-34107 Note that it is not necessary for all # coordinates in an R*Tree index to be constrained in order for the # index search to be efficient. # # EVIDENCE-OF: R-22490-27246 One might, for example, want to query all # objects that overlap with the 35th parallel: SELECT id FROM demo_index # WHERE maxY>=35.0 AND minY<=35.0; do_vmstep_test 2.6.1 { SELECT id FROM demo_index WHERE maxY>=35.0 AND minY<=35.0; } {$step < 100} do_execsql_test 2.6.2 { SELECT id FROM demo_index WHERE maxY>=35.0 AND minY<=35.0; } {} #------------------------------------------------------------------------- #------------------------------------------------------------------------- # Section 3.4 of documentation. #------------------------------------------------------------------------- #------------------------------------------------------------------------- set testprefix rtreedoc-6 reset_db # EVIDENCE-OF: R-08327-00674 By default, coordinates are stored in an # R*Tree using 32-bit floating point values. # # EVIDENCE-OF: R-22000-53613 The default virtual table ("rtree") stores # coordinates as single-precision (4-byte) floating point numbers. # # Show this by showing that rounding is consistent with 32-bit float # rounding. do_execsql_test 1.0 { CREATE VIRTUAL TABLE rt USING rtree(id, a,b); } do_execsql_test 1.1 { INSERT INTO rt VALUES(14, -1000000000000, 1000000000000); SELECT * FROM rt; } {14 -1000000126976.0 1000000126976.0} # EVIDENCE-OF: R-39127-51288 When a coordinate cannot be exactly # represented by a 32-bit floating point number, the lower-bound # coordinates are rounded down and the upper-bound coordinates are # rounded up. foreach {tn val} { 1 100000000000 2 200000000000 3 300000000000 4 400000000000 5 -100000000000 6 -200000000000 7 -300000000000 8 -400000000000 } { set val [expr $val] do_execsql_test 2.$tn.0 {DELETE FROM rt} do_execsql_test 2.$tn.1 {INSERT INTO rt VALUES(23, $val, $val)} do_execsql_test 2.$tn.2 { SELECT $val>=a, $val<=b, a!=b FROM rt } {1 1 1} } do_execsql_test 3.0 { DROP TABLE rt; CREATE VIRTUAL TABLE rt USING rtree(id, x1,x2, y1,y2); } # EVIDENCE-OF: R-45870-62834 Thus, bounding boxes might be slightly # larger than specified, but will never be any smaller. foreach {tn x1 x2 y1 y2} { 1 100000000000 200000000000 300000000000 400000000000 } { set val [expr $val] do_execsql_test 3.$tn.0 {DELETE FROM rt} do_execsql_test 3.$tn.1 {INSERT INTO rt VALUES(23, $x1, $x2, $y1, $y2)} do_execsql_test 3.$tn.2 { SELECT (x2-x1)*(y2-y1) >= ($x2-$x1)*($y2-$y1) FROM rt } {1} } #------------------------------------------------------------------------- #------------------------------------------------------------------------- # Section 3.5 of documentation. #------------------------------------------------------------------------- #------------------------------------------------------------------------- set testprefix rtreedoc-7 reset_db # EVIDENCE-OF: R-55979-39402 It is the nature of the Guttman R-Tree # algorithm that any write might radically restructure the tree, and in # the process change the scan order of the nodes. # # In the test below, the INSERT marked "THIS INSERT!!" does not affect # the results of queries with an ORDER BY, but does affect the results # of one without an ORDER BY. Therefore the INSERT changed the scan # order. do_execsql_test 1.0 { CREATE VIRTUAL TABLE rt USING rtree(id, minX, maxX); WITH s(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<51 ) INSERT INTO rt SELECT NULL, i%10, (i%10)+5 FROM s } do_execsql_test 1.1 { SELECT count(*) FROM rt_node } 1 do_test 1.2 { set res1 [db eval {SELECT * FROM rt WHERE maxX < 30}] set res1o [db eval {SELECT * FROM rt WHERE maxX < 30 ORDER BY +id}] db eval { INSERT INTO rt VALUES(NULL, 50, 50) } ;# THIS INSERT!! set res2 [db eval {SELECT * FROM rt WHERE maxX < 30}] set res2o [db eval {SELECT * FROM rt WHERE maxX < 30 ORDER BY +id}] list [expr {$res1==$res2}] [expr {$res1o==$res2o}] } {0 1} do_execsql_test 1.3 { SELECT count(*) FROM rt_node } 3 # EVIDENCE-OF: R-00683-48865 For this reason, it is not generally # possible to modify the R-Tree in the middle of a query of the R-Tree. # Attempts to do so will fail with a SQLITE_LOCKED "database table is # locked" error. # # SQLITE_LOCKED==6 # do_test 1.4 { set nCnt 3 db eval { SELECT * FROM rt WHERE minX>0 AND maxX<12 } { incr nCnt -1 if {$nCnt==0} { set rc [catch {db eval { INSERT INTO rt VALUES(NULL, 51, 51); }} msg] set errorcode [db errorcode] break } } list $errorcode $rc $msg } {6 1 {database table is locked}} # EVIDENCE-OF: R-19740-29710 So, for example, suppose an application # runs one query against an R-Tree like this: SELECT id FROM demo_index # WHERE maxY>=35.0 AND minY<=35.0; Then for each "id" value # returned, suppose the application creates an UPDATE statement like the # following and binds the "id" value returned against the "?1" # parameter: UPDATE demo_index SET maxY=maxY+0.5 WHERE id=?1; # # EVIDENCE-OF: R-52919-32711 Then the UPDATE might fail with an # SQLITE_LOCKED error. do_execsql_test 2.0 { CREATE VIRTUAL TABLE demo_index USING rtree( id, -- Integer primary key minX, maxX, -- Minimum and maximum X coordinate minY, maxY -- Minimum and maximum Y coordinate ); INSERT INTO demo_index VALUES (28215, -80.781227, -80.604706, 35.208813, 35.297367), (28216, -80.957283, -80.840599, 35.235920, 35.367825), (28217, -80.960869, -80.869431, 35.133682, 35.208233), (28226, -80.878983, -80.778275, 35.060287, 35.154446); } do_test 2.1 { db eval { SELECT id FROM demo_index WHERE maxY>=35.0 AND minY<=35.0 } { set rc [catch { db eval { UPDATE demo_index SET maxY=maxY+0.5 WHERE id=$id } } msg] set errorcode [db errorcode] break } list $errorcode $rc $msg } {6 1 {database table is locked}} # EVIDENCE-OF: R-32604-49843 Ordinary tables in SQLite are able to read # and write at the same time. # do_execsql_test 3.0 { CREATE TABLE x1(a INTEGER PRIMARY KEY, b, c); INSERT INTO x1 VALUES(1, 1, 1); INSERT INTO x1 VALUES(2, 2, 2); INSERT INTO x1 VALUES(3, 3, 3); INSERT INTO x1 VALUES(4, 4, 4); } do_test 3.1 { unset -nocomplain res set res [list] db eval { SELECT * FROM x1 } { lappend res $a $b $c switch -- $a { 1 { db eval { INSERT INTO x1 VALUES(5, 5, 5) } } 2 { db eval { UPDATE x1 SET c=20 WHERE a=2 } } 3 { db eval { DELETE FROM x1 WHERE c IN (3,4) } } } } set res } {1 1 1 2 2 2 3 3 3 5 5 5} do_execsql_test 3.2 { SELECT * FROM x1 } {1 1 1 2 2 20 5 5 5} # EVIDENCE-OF: R-06177-00576 And R-Tree can appear to read and write at # the same time in some circumstances, if it can figure out how to # reliably run the query to completion before starting the update. # # In 8.2, it can, it 8.1, it cannot. do_test 8.1 { db eval { SELECT * FROM rt } { set rc [catch { db eval { INSERT INTO rt VALUES(53,53,53) } } msg] break; } list $rc $msg } {1 {database table is locked}} do_test 8.2 { db eval { SELECT * FROM rt ORDER BY +id } { set rc [catch { db eval { INSERT INTO rt VALUES(53,53,53) } } msg] break } list $rc $msg } {0 {}} #------------------------------------------------------------------------- #------------------------------------------------------------------------- # Section 4 of documentation. #------------------------------------------------------------------------- #------------------------------------------------------------------------- set testprefix rtreedoc-8 reset_db # EVIDENCE-OF: R-21062-30088 For the example above, one might create an # auxiliary table as follows: CREATE TABLE demo_data( id INTEGER PRIMARY # KEY, -- primary key objname TEXT, -- name of the object objtype TEXT, # -- object type boundary BLOB -- detailed boundary of object ); # # One might. # do_execsql_test 1.0 { CREATE TABLE demo_data( id INTEGER PRIMARY KEY, -- primary key objname TEXT, -- name of the object objtype TEXT, -- object type boundary BLOB -- detailed boundary of object ); } do_execsql_test 1.1 { CREATE VIRTUAL TABLE demo_index USING rtree( id, -- Integer primary key minX, maxX, -- Minimum and maximum X coordinate minY, maxY -- Minimum and maximum Y coordinate ); INSERT INTO demo_index VALUES (28215, -80.781227, -80.604706, 35.208813, 35.297367), (28216, -80.957283, -80.840599, 35.235920, 35.367825), (28217, -80.960869, -80.869431, 35.133682, 35.208233), (28226, -80.878983, -80.778275, 35.060287, 35.154446), (28227, -80.745544, -80.555382, 35.130215, 35.236916), (28244, -80.844208, -80.841988, 35.223728, 35.225471), (28262, -80.809074, -80.682938, 35.276207, 35.377747), (28269, -80.851471, -80.735718, 35.272560, 35.407925), (28270, -80.794983, -80.728966, 35.059872, 35.161823), (28273, -80.994766, -80.875259, 35.074734, 35.172836), (28277, -80.876793, -80.767586, 35.001709, 35.101063), (28278, -81.058029, -80.956375, 35.044701, 35.223812), (28280, -80.844208, -80.841972, 35.225468, 35.227203), (28282, -80.846382, -80.844193, 35.223972, 35.225655); INSERT INTO demo_index SELECT NULL, minX, maxX, minY+0.2, maxY+0.2 FROM demo_index; INSERT INTO demo_index SELECT NULL, minX+0.2, maxX+0.2, minY, maxY FROM demo_index; INSERT INTO demo_index SELECT NULL, minX, maxX, minY+0.4, maxY+0.4 FROM demo_index; INSERT INTO demo_index SELECT NULL, minX+0.4, maxX+0.4, minY, maxY FROM demo_index; INSERT INTO demo_index SELECT NULL, minX, maxX, minY+0.8, maxY+0.8 FROM demo_index; INSERT INTO demo_index SELECT NULL, minX+0.8, maxX+0.8, minY, maxY FROM demo_index; INSERT INTO demo_data(id) SELECT id FROM demo_index; SELECT count(*) FROM demo_index; } {896} set ::contained_in 0 proc contained_in {args} {incr ::contained_in ; return 0} db func contained_in contained_in # EVIDENCE-OF: R-32671-43888 Then an efficient way to find the specific # ZIP code for the main SQLite office would be to run a query like this: # SELECT objname FROM demo_data, demo_index WHERE # demo_data.id=demo_index.id AND contained_in(demo_data.boundary, # 35.37785, -80.77470) AND minX<=-80.77470 AND maxX>=-80.77470 AND # minY<=35.37785 AND maxY>=35.37785; do_vmstep_test 1.2 { SELECT objname FROM demo_data, demo_index WHERE demo_data.id=demo_index.id AND contained_in(demo_data.boundary, 35.37785, -80.77470) AND minX<=-80.77470 AND maxX>=-80.77470 AND minY<=35.37785 AND maxY>=35.37785; } {$step<100} set ::contained_in1 $::contained_in # EVIDENCE-OF: R-32761-23915 One would get the same answer without the # use of the R*Tree index using the following simpler query: SELECT # objname FROM demo_data WHERE contained_in(demo_data.boundary, # 35.37785, -80.77470); set ::contained_in 0 do_vmstep_test 1.3 { SELECT objname FROM demo_data WHERE contained_in(demo_data.boundary, 35.37785, -80.77470); } {$step>3200} # EVIDENCE-OF: R-40261-32799 The problem with this latter query is that # it must apply the contained_in() function to all entries in the # demo_data table. # # 896 of them, IIRC. do_test 1.4 { set ::contained_in } 896 # EVIDENCE-OF: R-24212-52761 The use of the R*Tree in the penultimate # query reduces the number of calls to contained_in() function to a # small subset of the entire table. # # 2 is a small subset of 896. # # EVIDENCE-OF: R-39057-63901 The R*Tree index did not find the exact # answer itself, it merely limited the search space. # # contained_in() filtered out those 2 rows. do_test 1.5 { set ::contained_in1 } {2} #------------------------------------------------------------------------- #------------------------------------------------------------------------- # Section 4.1 of documentation. #------------------------------------------------------------------------- #------------------------------------------------------------------------- set testprefix rtreedoc-9 reset_db # EVIDENCE-OF: R-46566-43213 Beginning with SQLite version 3.24.0 # (2018-06-04), r-tree tables can have auxiliary columns that store # arbitrary data. Auxiliary columns can be used in place of secondary # tables such as "demo_data". # # EVIDENCE-OF: R-41287-48160 Auxiliary columns are marked with a "+" # symbol before the column name. # # This interface cannot conveniently be used to prove anything about # versions of SQLite prior to 3.24.0. # do_execsql_test 1.0 { CREATE VIRTUAL TABLE rta USING rtree( id, u1,u2, v1,v2, +aux ); INSERT INTO rta(aux) VALUES(NULL); INSERT INTO rta(aux) VALUES(45); INSERT INTO rta(aux) VALUES(22.3); INSERT INTO rta(aux) VALUES('hello'); INSERT INTO rta(aux) VALUES(X'ABCD'); SELECT typeof(aux), quote(aux) FROM rta; } { null NULL integer 45 real 22.3 text 'hello' blob X'ABCD' } # EVIDENCE-OF: R-30514-26093 Auxiliary columns must come after all of # the coordinate boundary columns. foreach {tn cols} { 1 "id x1,x2, +extra, y1,y2" 2 "extra, +id x1,x2, y1,y2" 3 "id, x1,+x2, extra, y1,y2" } { do_catchsql_test 2.$tn " CREATE VIRTUAL TABLE rrr USING rtree($cols) " {1 {Auxiliary rtree columns must be last}} } do_catchsql_test 3.0 { CREATE VIRTUAL TABLE rrr USING rtree(+id, extra, x1, x2); } {1 {near "+": syntax error}} # EVIDENCE-OF: R-01280-03635 An RTREE table can have no more than 100 # columns total. In other words, the count of columns including the # integer primary key column, the coordinate boundary columns, and all # auxiliary columns must be 100 or less. do_catchsql_test 3.1 { CREATE VIRTUAL TABLE r1 USING rtree(intid, u1,u2, +c00, +c01, +c02, +c03, +c04, +c05, +c06, +c07, +c08, +c09, +c10, +c11, +c12, +c13, +c14, +c15, +c16, +c17, +c18, +c19, +c20, +c21, +c22, +c23, +c24, +c25, +c26, +c27, +c28, +c29, +c30, +c31, +c32, +c33, +c34, +c35, +c36, +c37, +c38, +c39, +c40, +c41, +c42, +c43, +c44, +c45, +c46, +c47, +c48, +c49, +c50, +c51, +c52, +c53, +c54, +c55, +c56, +c57, +c58, +c59, +c60, +c61, +c62, +c63, +c64, +c65, +c66, +c67, +c68, +c69, +c70, +c71, +c72, +c73, +c74, +c75, +c76, +c77, +c78, +c79, +c80, +c81, +c82, +c83, +c84, +c85, +c86, +c87, +c88, +c89, +c90, +c91, +c92, +c93, +c94, +c95, +c96 ); } {0 {}} do_catchsql_test 3.2 { DROP TABLE r1; CREATE VIRTUAL TABLE r1 USING rtree(intid, u1,u2, +c00, +c01, +c02, +c03, +c04, +c05, +c06, +c07, +c08, +c09, +c10, +c11, +c12, +c13, +c14, +c15, +c16, +c17, +c18, +c19, +c20, +c21, +c22, +c23, +c24, +c25, +c26, +c27, +c28, +c29, +c30, +c31, +c32, +c33, +c34, +c35, +c36, +c37, +c38, +c39, +c40, +c41, +c42, +c43, +c44, +c45, +c46, +c47, +c48, +c49, +c50, +c51, +c52, +c53, +c54, +c55, +c56, +c57, +c58, +c59, +c60, +c61, +c62, +c63, +c64, +c65, +c66, +c67, +c68, +c69, +c70, +c71, +c72, +c73, +c74, +c75, +c76, +c77, +c78, +c79, +c80, +c81, +c82, +c83, +c84, +c85, +c86, +c87, +c88, +c89, +c90, +c91, +c92, +c93, +c94, +c95, +c96, +c97 ); } {1 {Too many columns for an rtree table}} do_catchsql_test 3.3 { CREATE VIRTUAL TABLE r1 USING rtree(intid, u1,u2, v1,v2, +c00, +c01, +c02, +c03, +c04, +c05, +c06, +c07, +c08, +c09, +c10, +c11, +c12, +c13, +c14, +c15, +c16, +c17, +c18, +c19, +c20, +c21, +c22, +c23, +c24, +c25, +c26, +c27, +c28, +c29, +c30, +c31, +c32, +c33, +c34, +c35, +c36, +c37, +c38, +c39, +c40, +c41, +c42, +c43, +c44, +c45, +c46, +c47, +c48, +c49, +c50, +c51, +c52, +c53, +c54, +c55, +c56, +c57, +c58, +c59, +c60, +c61, +c62, +c63, +c64, +c65, +c66, +c67, +c68, +c69, +c70, +c71, +c72, +c73, +c74, +c75, +c76, +c77, +c78, +c79, +c80, +c81, +c82, +c83, +c84, +c85, +c86, +c87, +c88, +c89, +c90, +c91, +c92, +c93, +c94, ); } {0 {}} do_catchsql_test 3.4 { DROP TABLE r1; CREATE VIRTUAL TABLE r1 USING rtree(intid, u1,u2, v1,v2, +c00, +c01, +c02, +c03, +c04, +c05, +c06, +c07, +c08, +c09, +c10, +c11, +c12, +c13, +c14, +c15, +c16, +c17, +c18, +c19, +c20, +c21, +c22, +c23, +c24, +c25, +c26, +c27, +c28, +c29, +c30, +c31, +c32, +c33, +c34, +c35, +c36, +c37, +c38, +c39, +c40, +c41, +c42, +c43, +c44, +c45, +c46, +c47, +c48, +c49, +c50, +c51, +c52, +c53, +c54, +c55, +c56, +c57, +c58, +c59, +c60, +c61, +c62, +c63, +c64, +c65, +c66, +c67, +c68, +c69, +c70, +c71, +c72, +c73, +c74, +c75, +c76, +c77, +c78, +c79, +c80, +c81, +c82, +c83, +c84, +c85, +c86, +c87, +c88, +c89, +c90, +c91, +c92, +c93, +c94, +c95, ); } {1 {Too many columns for an rtree table}} # EVIDENCE-OF: R-05552-15084 do_execsql_test 4.0 { CREATE VIRTUAL TABLE demo_index2 USING rtree( id, -- Integer primary key minX, maxX, -- Minimum and maximum X coordinate minY, maxY, -- Minimum and maximum Y coordinate +objname TEXT, -- name of the object +objtype TEXT, -- object type +boundary BLOB -- detailed boundary of object ); } do_execsql_test 4.1 { CREATE VIRTUAL TABLE demo_index USING rtree( id, -- Integer primary key minX, maxX, -- Minimum and maximum X coordinate minY, maxY -- Minimum and maximum Y coordinate ); CREATE TABLE demo_data( id INTEGER PRIMARY KEY, -- primary key objname TEXT, -- name of the object objtype TEXT, -- object type boundary BLOB -- detailed boundary of object ); INSERT INTO demo_index2(id) VALUES(1); INSERT INTO demo_index(id) VALUES(1); INSERT INTO demo_data(id) VALUES(1); } do_test 4.2 { catch { array unset R } db eval {SELECT * FROM demo_index2} R { set r1 [array names R] } catch { array unset R } db eval {SELECT * FROM demo_index NATURAL JOIN demo_data } R { set r2 [array names R] } expr {$r1==$r2} } {1} # EVIDENCE-OF: R-26099-32169 SELECT objname FROM demo_index2 WHERE # contained_in(boundary, 35.37785, -80.77470) AND minX<=-80.77470 AND # maxX>=-80.77470 AND minY<=35.37785 AND maxY>=35.37785; do_execsql_test 4.3.1 { DELETE FROM demo_index2; INSERT INTO demo_index2(id,minX,maxX,minY,maxY) VALUES (28215, -80.781227, -80.604706, 35.208813, 35.297367), (28216, -80.957283, -80.840599, 35.235920, 35.367825), (28217, -80.960869, -80.869431, 35.133682, 35.208233), (28226, -80.878983, -80.778275, 35.060287, 35.154446), (28227, -80.745544, -80.555382, 35.130215, 35.236916), (28244, -80.844208, -80.841988, 35.223728, 35.225471), (28262, -80.809074, -80.682938, 35.276207, 35.377747), (28269, -80.851471, -80.735718, 35.272560, 35.407925), (28270, -80.794983, -80.728966, 35.059872, 35.161823), (28273, -80.994766, -80.875259, 35.074734, 35.172836), (28277, -80.876793, -80.767586, 35.001709, 35.101063), (28278, -81.058029, -80.956375, 35.044701, 35.223812), (28280, -80.844208, -80.841972, 35.225468, 35.227203), (28282, -80.846382, -80.844193, 35.223972, 35.225655); } set ::contained_in 0 proc contained_in {args} { incr ::contained_in return 0 } db func contained_in contained_in do_execsql_test 4.3.2 { SELECT objname FROM demo_index2 WHERE contained_in(boundary, 35.37785, -80.77470) AND minX<=-80.77470 AND maxX>=-80.77470 AND minY<=35.37785 AND maxY>=35.37785; } do_test 4.3.3 { # Function invoked only once because r-tree filtering happened first. set ::contained_in } 1 set ::contained_in 0 do_execsql_test 4.3.4 { SELECT objname FROM demo_index2 WHERE contained_in(boundary, 35.37785, -80.77470) } do_test 4.3.3 { # Function invoked 14 times because no r-tree filtering. Inefficient. set ::contained_in } 14 #------------------------------------------------------------------------- #------------------------------------------------------------------------- # Section 4.1.1 of documentation. #------------------------------------------------------------------------- #------------------------------------------------------------------------- set testprefix rtreedoc-9 reset_db # EVIDENCE-OF: R-24021-02490 For auxiliary columns, only the name of the # column matters. The type affinity is ignored. # # EVIDENCE-OF: R-39906-44154 Constraints such as NOT NULL, UNIQUE, # REFERENCES, or CHECK are also ignored. do_execsql_test 1.0 { PRAGMA foreign_keys = on } foreach {tn auxcol nm} { 1 "+extra INTEGER" extra 2 "+extra TEXT" extra 3 "+extra BLOB" extra 4 "+extra REAL" extra 5 "+col NOT NULL" col 6 "+col CHECK (col IS NOT NULL)" col 7 "+col REFERENCES tbl(x)" col } { do_execsql_test 1.$tn.1 " CREATE VIRTUAL TABLE rt USING rtree_i32(k, a,b, $auxcol) " # Check that the aux column has no affinity. Or NOT NULL constraint. # And that the aux column is the child key of an FK constraint. # do_execsql_test 1.$tn.2 " INSERT INTO rt($nm) VALUES(NULL), (45), (-123.2), ('456'), (X'ABCD'); SELECT typeof($nm), quote($nm) FROM rt; " { null NULL integer 45 real -123.2 text '456' blob X'ABCD' } # Check that there is no UNIQUE constraint either. # do_execsql_test 1.$tn.3 " INSERT INTO rt($nm) VALUES('xyz'), ('xyz'), ('xyz'); " do_execsql_test 1.$tn.2 { DROP TABLE rt } } #------------------------------------------------------------------------- #------------------------------------------------------------------------- # Section 5 of documentation. #------------------------------------------------------------------------- #------------------------------------------------------------------------- set testprefix rtreedoc-10 # EVIDENCE-OF: R-21011-43790 If integer coordinates are desired, declare # the table using "rtree_i32" instead: CREATE VIRTUAL TABLE intrtree # USING rtree_i32(id,x0,x1,y0,y1,z0,z1); do_execsql_test 1.0 { CREATE VIRTUAL TABLE intrtree USING rtree_i32(id,x0,x1,y0,y1,z0,z1); INSERT INTO intrtree DEFAULT VALUES; SELECT typeof(x0) FROM intrtree; } {integer} # EVIDENCE-OF: R-09193-49806 An rtree_i32 stores coordinates as 32-bit # signed integers. # # Show that coordinates are cast in a way consistent with casting to # a signed 32-bit integer. do_execsql_test 1.1 { DELETE FROM intrtree; INSERT INTO intrtree VALUES(333, 1<<44, (1<<44)+1, 10000000000, 10000000001, -10000000001, -10000000000 ); SELECT * FROM intrtree; } { 333 0 1 1410065408 1410065409 -1410065409 -1410065408 } #------------------------------------------------------------------------- #------------------------------------------------------------------------- # Section 7.1 of documentation. #------------------------------------------------------------------------- #------------------------------------------------------------------------- set testprefix rtreedoc-11 reset_db # This command assumes that the argument is a node blob for a 2 dimensional # i32 r-tree table. It decodes and returns a list of cells from the node # as a list. Each cell is itself a list of the following form: # # {$rowid $minX $maxX $minY $maxY} # # For internal (non-leaf) nodes, the rowid is replaced by the child node # number. # proc rnode {aData} { set nDim 2 set nData [string length $aData] set nBytePerCell [expr (8 + 2*$nDim*4)] binary scan [string range $aData 2 3] S nCell set res [list] for {set i 0} {$i < $nCell} {incr i} { set iOff [expr $i*$nBytePerCell+4] set cell [string range $aData $iOff [expr $iOff+$nBytePerCell-1]] binary scan $cell WIIII rowid x1 x2 y1 y2 lappend res [list $rowid $x1 $x2 $y1 $y2] } return $res } # aData must be a node blob. This command returns true if the node contains # rowid $rowid, or false otherwise. # proc rnode_contains {aData rowid} { set L [rnode $aData] foreach cell $L { set r [lindex $cell 0] if {$r==$rowid} { return 1 } } return 0 } proc rnode_replace_cell {aData iCell cell} { set aCell [binary format WIIII {*}$cell] set nDim 2 set nBytePerCell [expr (8 + 2*$nDim*4)] set iOff [expr $iCell*$nBytePerCell+4] set aNew [binary format a*a*a* \ [string range $aData 0 $iOff-1] \ $aCell \ [string range $aData $iOff+$nBytePerCell end] \ ] return $aNew } db function rnode rnode db function rnode_contains rnode_contains db function rnode_replace_cell rnode_replace_cell foreach {tn nm} { 1 x1 2 asdfghjkl 3 hello_world } { do_execsql_test 1.$tn.1 " CREATE VIRTUAL TABLE $nm USING rtree(a,b,c,d,e); " # EVIDENCE-OF: R-33789-46762 The content of an R*Tree index is actually # stored in three ordinary SQLite tables with names derived from the # name of the R*Tree. # # EVIDENCE-OF: R-39849-06566 This is their schema: CREATE TABLE # %_node(nodeno INTEGER PRIMARY KEY, data) CREATE TABLE %_parent(nodeno # INTEGER PRIMARY KEY, parentnode) CREATE TABLE %_rowid(rowid INTEGER # PRIMARY KEY, nodeno) # # EVIDENCE-OF: R-07489-10051 The "%" in the name of each shadow table is # replaced by the name of the R*Tree virtual table. So, if the name of # the R*Tree table is "xyz" then the three shadow tables would be # "xyz_node", "xyz_parent", and "xyz_rowid". do_execsql_test 1.$tn.2 { SELECT sql FROM sqlite_schema WHERE name!=$nm ORDER BY 1 } [string map [list % $nm] " {CREATE TABLE \"%_node\"(nodeno INTEGER PRIMARY KEY,data)} {CREATE TABLE \"%_parent\"(nodeno INTEGER PRIMARY KEY,parentnode)} {CREATE TABLE \"%_rowid\"(rowid INTEGER PRIMARY KEY,nodeno)} "] do_execsql_test 1.$tn "DROP TABLE $nm" } # EVIDENCE-OF: R-51070-59303 There is one entry in the %_node table for # each R*Tree node. # # The following creates a 6 node r-tree structure. # do_execsql_test 2.0 { CREATE VIRTUAL TABLE r1 USING rtree_i32(i, x1,x2, y1,y2); WITH t(i) AS ( VALUES(1) UNION SELECT i+1 FROM t WHERE i<110 ) INSERT INTO r1 SELECT i, (i%10), (i%10)+2, (i%6), (i%7)+6 FROM t; } do_execsql_test 2.1 { SELECT count(*) FROM r1_node; } 6 # EVIDENCE-OF: R-27261-09153 All nodes other than the root have an entry # in the %_parent shadow table that identifies the parent node. # # In this case nodes 2-6 are the children of node 1. # do_execsql_test 2.3 { SELECT nodeno, parentnode FROM r1_parent } {2 1 3 1 4 1 5 1 6 1} # EVIDENCE-OF: R-02358-35037 The %_rowid shadow table maps entry rowids # to the node that contains that entry. # do_execsql_test 2.4 { SELECT 'failed' FROM r1_rowid WHERE 0==rnode_contains( (SELECT data FROM r1_node WHERE nodeno=r1_rowid.nodeno), rowid ) } do_test 2.5 { db eval { SELECT nodeno, data FROM r1_node WHERE nodeno!=1 } { set L [rnode $data] foreach cell $L { set rowid [lindex $cell 0] set rowid_nodeno 0 db eval {SELECT nodeno AS rowid_nodeno FROM r1_rowid WHERE rowid=$rowid} { break } if {$rowid_nodeno!=$nodeno} { error "data mismatch!" } } } } {} # EVIDENCE-OF: R-65201-22208 Extra columns appended to the %_rowid table # hold the content of auxiliary columns. # # EVIDENCE-OF: R-44161-28345 The names of these extra %_rowid columns # are probably not the same as the actual auxiliary column names. # # In this case, the auxiliary columns are named "e1" and "e2". The # extra %_rowid columns are named "a0" and "a1". # do_execsql_test 3.0 { CREATE VIRTUAL TABLE rtaux USING rtree(id, x1,x2, y1,y2, +e1, +e2); SELECT sql FROM sqlite_schema WHERE name='rtaux_rowid'; } { {CREATE TABLE "rtaux_rowid"(rowid INTEGER PRIMARY KEY,nodeno,a0,a1)} } do_execsql_test 3.1 { INSERT INTO rtaux(e1, e2) VALUES('hello', 'world'), (123, 456); } do_execsql_test 3.2 { SELECT a0, a1 FROM rtaux_rowid; } { hello world 123 456 } #------------------------------------------------------------------------- #------------------------------------------------------------------------- # Section 7.2 of documentation. #------------------------------------------------------------------------- #------------------------------------------------------------------------- set testprefix rtreedoc-12 reset_db forcedelete test.db2 db function rnode rnode db function rnode_contains rnode_contains db function rnode_replace_cell rnode_replace_cell # EVIDENCE-OF: R-13571-45795 The scalar SQL function rtreecheck(R) or # rtreecheck(S,R) runs an integrity check on the rtree table named R # contained within database S. # # EVIDENCE-OF: R-36011-59963 The function returns a human-language # description of any problems found, or the string 'ok' if everything is # ok. # do_execsql_test 1.0 { CREATE VIRTUAL TABLE rt1 USING rtree(id, a, b); WITH s(i) AS ( VALUES(1) UNION ALL SELECT i+1 FROM s WHERE i<200 ) INSERT INTO rt1 SELECT i, i, i FROM s; ATTACH 'test.db2' AS 'aux'; CREATE VIRTUAL TABLE aux.rt1 USING rtree(id, a, b); INSERT INTO aux.rt1 SELECT * FROM rt1; } do_execsql_test 1.1.1 { SELECT rtreecheck('rt1'); } {ok} do_execsql_test 1.1.2 { SELECT rtreecheck('main', 'rt1'); } {ok} do_execsql_test 1.1.3 { SELECT rtreecheck('aux', 'rt1'); } {ok} do_catchsql_test 1.1.4 { SELECT rtreecheck('nosuchdb', 'rt1'); } {1 {SQL logic error}} # Corrupt the table in database 'main': do_execsql_test 1.2.1 { UPDATE rt1_node SET nodeno=21 WHERE nodeno=3; } do_execsql_test 1.2.1 { SELECT rtreecheck('rt1')=='ok'; } {0} do_execsql_test 1.2.2 { SELECT rtreecheck('main', 'rt1')=='ok'; } {0} do_execsql_test 1.2.3 { SELECT rtreecheck('aux', 'rt1')=='ok'; } {1} do_execsql_test 1.2.4 { UPDATE rt1_node SET nodeno=3 WHERE nodeno=21; } # Corrupt the table in database 'aux': do_execsql_test 1.2.1 { UPDATE aux.rt1_node SET nodeno=21 WHERE nodeno=3; } do_execsql_test 1.2.1 { SELECT rtreecheck('rt1')=='ok'; } {1} do_execsql_test 1.2.2 { SELECT rtreecheck('main', 'rt1')=='ok'; } {1} do_execsql_test 1.2.3 { SELECT rtreecheck('aux', 'rt1')=='ok'; } {0} do_execsql_test 1.2.4 { UPDATE rt1_node SET nodeno=3 WHERE nodeno=21; } # EVIDENCE-OF: R-45759-33459 Example: To verify that an R*Tree named # "demo_index" is well-formed and internally consistent, run: SELECT # rtreecheck('demo_index'); do_execsql_test 2.0 { CREATE VIRTUAL TABLE demo_index USING rtree(id, x1,x2, y1,y2); INSERT INTO demo_index SELECT id, a, b, a, b FROM rt1; } do_execsql_test 2.1 { SELECT rtreecheck('demo_index') } {ok} do_execsql_test 2.2 { UPDATE demo_index_rowid SET nodeno=44 WHERE rowid=44; SELECT rtreecheck('demo_index'); } {{Found (44 -> 44) in %_rowid table, expected (44 -> 4)}} do_execsql_test 3.0 { CREATE VIRTUAL TABLE rt2 USING rtree_i32(id, a, b, c, d); WITH s(i) AS ( VALUES(1) UNION ALL SELECT i+1 FROM s WHERE i<200 ) INSERT INTO rt2 SELECT i, i, i+2, i, i+2 FROM s; } # EVIDENCE-OF: R-02555-31045 for each dimension, (coord1 <= coord2). # execsql BEGIN do_test 3.1 { set cell [ lindex [execsql {SELECT rnode(data) FROM rt2_node WHERE nodeno=3}] 0 3 ] set cell [list [lindex $cell 0] \ [lindex $cell 2] [lindex $cell 1] \ [lindex $cell 3] [lindex $cell 4] \ ] execsql { UPDATE rt2_node SET data=rnode_replace_cell(data, 3, $cell) WHERE nodeno=3 } execsql { SELECT rtreecheck('rt2') } } {{Dimension 0 of cell 3 on node 3 is corrupt}} execsql ROLLBACK # EVIDENCE-OF: R-13844-15873 unless the cell is on the root node, that # the cell is bounded by the parent cell on the parent node. # execsql BEGIN do_test 3.2 { set cell [ lindex [execsql {SELECT rnode(data) FROM rt2_node WHERE nodeno=3}] 0 3 ] lset cell 3 450 lset cell 4 451 execsql { UPDATE rt2_node SET data=rnode_replace_cell(data, 3, $cell) WHERE nodeno=3 } execsql { SELECT rtreecheck('rt2') } } {{Dimension 1 of cell 3 on node 3 is corrupt relative to parent}} execsql ROLLBACK # EVIDENCE-OF: R-02505-03621 for leaf nodes, that there is an entry in # the %_rowid table corresponding to the cell's rowid value that points # to the correct node. # execsql BEGIN do_test 3.3 { execsql { UPDATE rt2_rowid SET rowid=452 WHERE rowid=100 } execsql { SELECT rtreecheck('rt2') } } {{Mapping (100 -> 6) missing from %_rowid table}} execsql ROLLBACK # EVIDENCE-OF: R-50927-02218 for cells on non-leaf nodes, that there is # an entry in the %_parent table mapping from the cell's child node to # the node that it resides on. # execsql BEGIN do_test 3.4.1 { execsql { UPDATE rt2_parent SET parentnode=123 WHERE nodeno=3 } execsql { SELECT rtreecheck('rt2') } } {{Found (3 -> 123) in %_parent table, expected (3 -> 1)}} execsql ROLLBACK execsql BEGIN do_test 3.4.2 { execsql { UPDATE rt2_parent SET nodeno=123 WHERE nodeno=3 } execsql { SELECT rtreecheck('rt2') } } {{Mapping (3 -> 1) missing from %_parent table}} execsql ROLLBACK # EVIDENCE-OF: R-23235-09153 That there are the same number of entries # in the %_rowid table as there are leaf cells in the r-tree structure, # and that there is a leaf cell that corresponds to each entry in the # %_rowid table. execsql BEGIN do_test 3.5 { execsql { INSERT INTO rt2_rowid VALUES(1000, 1000) } execsql { SELECT rtreecheck('rt2') } } {{Wrong number of entries in %_rowid table - expected 200, actual 201}} execsql ROLLBACK # EVIDENCE-OF: R-62800-43436 That there are the same number of entries # in the %_parent table as there are non-leaf cells in the r-tree # structure, and that there is a non-leaf cell that corresponds to each # entry in the %_parent table. execsql BEGIN do_test 3.6 { execsql { INSERT INTO rt2_parent VALUES(1000, 1000) } execsql { SELECT rtreecheck('rt2') } } {{Wrong number of entries in %_parent table - expected 9, actual 10}} execsql ROLLBACK finish_test |
Added ext/rtree/rtreedoc2.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 | # 2021 September 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. # #*********************************************************************** # # The focus of this file is testing the r-tree extension. # 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 rtreedoc2 ifcapable !rtree { finish_test return } #------------------------------------------------------------------------- #------------------------------------------------------------------------- # Section 6 of documentation. #------------------------------------------------------------------------- #------------------------------------------------------------------------- set testprefix rtreedoc2-1 # EVIDENCE-OF: R-35254-48865 A call to one of the above APIs creates a # new SQL function named by the second parameter (zQueryFunc or zGeom). # # [register_circle_geom db] registers new geometry callback "Qcircle" # and legacy implementation "circle". Test that these do actually appear. # do_execsql_test 1.1.0 { SELECT * FROM pragma_function_list WHERE name IN('circle', 'qcircle'); } { } do_test 1.1 { register_circle_geom db } {SQLITE_OK} do_execsql_test 1.1.2 { SELECT * FROM pragma_function_list WHERE name = 'circle' AND enc='utf8'; } { circle 0 s utf8 -1 0 } do_execsql_test 1.1.3 { SELECT * FROM pragma_function_list WHERE name = 'qcircle' AND enc='utf8'; } { qcircle 0 s utf8 -1 0 } do_execsql_test 1.2.0 { SELECT circle(1, 2, 3); } {{}} do_execsql_test 1.2.1 { SELECT qcircle(1, 2, 3); } {{}} # EVIDENCE-OF: R-61427-46983 do_execsql_test 1.3.0 { CREATE VIRTUAL TABLE demo_index USING rtree(id, x1,x2, y1,y2); INSERT INTO demo_index VALUES(10, 45,45, 24,24); INSERT INTO demo_index VALUES(20, 50,50, 28,28); INSERT INTO demo_index VALUES(30, 43,43, 22,22); } do_execsql_test 1.3.1 { SELECT id FROM demo_index WHERE id MATCH circle(45.3, 22.9, 5.0) } {10 30} # EVIDENCE-OF: R-16907-50223 The SQL syntax for custom queries is the # same regardless of which interface, sqlite3_rtree_geometry_callback() # or sqlite3_rtree_query_callback(), is used to register the SQL # function. do_execsql_test 1.3.2 { SELECT id FROM demo_index WHERE id MATCH qcircle(45.3, 22.9, 5.0, 1) } {10 30} # EVIDENCE-OF: R-59634-51678 When that SQL function appears on the # right-hand side of the MATCH operator and the left-hand side of the # MATCH operator is any column in the R*Tree virtual table, then the # callback defined by the third argument (xQueryFunc or xGeom) is # invoked to determine if a particular object or subtree overlaps the # desired region. proc box_geom {args} { lappend ::box_geom [concat [lindex $args 0] [lrange $args 2 end-1]] return "" } register_box_geom db box_geom set box_geom [list] do_execsql_test 1.3.2 { SELECT id FROM demo_index WHERE id MATCH box(43,46, 21,25); } {10 30} do_test 1.3.3 { set ::box_geom } [list {*}{ {box {43.0 46.0 21.0 25.0} {45.0 45.0 24.0 24.0}} {box {43.0 46.0 21.0 25.0} {50.0 50.0 28.0 28.0}} {box {43.0 46.0 21.0 25.0} {43.0 43.0 22.0 22.0}} }] #------------------------------------------------------------------------- #------------------------------------------------------------------------- # Section 6 of documentation. #------------------------------------------------------------------------- #------------------------------------------------------------------------- set testprefix rtreedoc2-2 # EVIDENCE-OF: R-02424-24769 The second argument is the number of # coordinates in each r-tree entry, and is always the same for any given # R*Tree. # # EVIDENCE-OF: R-40260-16838 The number of coordinates is 2 for a # 1-dimensional R*Tree, 4 for a 2-dimensional R*Tree, 6 for a # 3-dimensional R*Tree, and so forth. # # The second argument refered to above is the length of the list passed # as the 3rd parameter to the Tcl script. # do_execsql_test 1.0 { CREATE VIRTUAL TABLE rt1 USING rtree(id, x1,x2); CREATE VIRTUAL TABLE rt2 USING rtree(id, x1,x2, y1,y2); CREATE VIRTUAL TABLE rt3 USING rtree(id, x1,x2, y1,y2, z1,z2); INSERT INTO rt1 DEFAULT VALUES; INSERT INTO rt2 DEFAULT VALUES; INSERT INTO rt3 DEFAULT VALUES; } foreach {tn tbl nCoord} { 1 rt1 2 2 rt2 4 3 rt3 6 } { set ::box_geom [list] do_catchsql_test 1.$tn.1 " SELECT id FROM $tbl WHERE id MATCH box(); " {1 {SQL logic error}} do_test 1.$tn.2 { llength [lindex $::box_geom 0 2] } $nCoord } # EVIDENCE-OF: R-28051-48608 If xGeom returns anything other than # SQLITE_OK, then the r-tree query will abort with an error. proc box_geom {args} { error "an error!" } do_catchsql_test 2.0 { SELECT * FROM rt2 WHERE id MATCH box(22,23, 24,25); } {1 {SQL logic error}} do_execsql_test 3.0 { INSERT INTO rt1 VALUES(10, 10, 10); INSERT INTO rt1 VALUES(11, 11, 11); INSERT INTO rt1 VALUES(12, 12, 12); INSERT INTO rt1 VALUES(13, 13, 13); INSERT INTO rt1 VALUES(14, 14, 14); } # EVIDENCE-OF: R-53759-57366 The exact same sqlite3_rtree_geometry # structure is used for every callback for same MATCH operator in the # same query. proc box_geom {args} { lappend ::ptr_list [lindex $args 4] return 0 } set ::ptr_list [list] do_execsql_test 3.1 { SELECT * FROM rt1 WHERE id MATCH box(1,1); } do_test 3.2 { set val [lindex $::ptr_list 0] foreach p $::ptr_list { if {$p!=$val} {error "pointer mismatch"} } } {} # EVIDENCE-OF: R-60247-35692 The contents of the sqlite3_rtree_geometry # structure are initialized by SQLite but are not subsequently modified. proc box_geom {args} { lappend ::box_geom [concat [lindex $args 0] [lrange $args 2 end-1]] if {[llength $::box_geom]==3} { return "zero" } return "" } set ::box_geom [list] do_catchsql_test 3.2 { SELECT * FROM rt1 WHERE id MATCH box(1,1); } {1 {SQL logic error}} do_test 3.3 { set ::box_geom } [list {*}{ {box {1.0 1.0} {0.0 0.0}} {box {1.0 1.0} {10.0 10.0}} {box {1.0 1.0} {11.0 11.0}} {box 0.0 {12.0 12.0}} }] # EVIDENCE-OF: R-31246-29731 The pContext member of the # sqlite3_rtree_geometry structure is always set to a copy of the # pContext argument passed to sqlite3_rtree_geometry_callback() when the # callback is registered. reset_db do_execsql_test 4.0 { CREATE VIRTUAL TABLE r1 USING rtree(id, minX,maxX, minY,maxY); WITH s(i) AS ( VALUES(1) UNION ALL SELECT i+1 FROM s WHERE i<120 ) INSERT INTO r1 SELECT i,i,i+1, 200,201 FROM s; } set ctx [register_box_geom db box_geom] set ::box_geom [list] proc box_geom {args} { lappend ::box_geom [lindex $args 1] return "" } do_execsql_test 4.1 { SELECT count(*) FROM r1 WHERE id MATCH box(0,150,199,201) } 120 do_test 4.2 { foreach g $::box_geom { if {$g!=$ctx} {error "pointer mismatch"} } } {} # EVIDENCE-OF: R-09904-19077 The aParam[] array (size nParam) contains # the parameter values passed to the SQL function on the right-hand side # of the MATCH operator. proc box_geom {args} { set ::box_geom [lindex $args 2] } foreach {tn q vals} { 1 "SELECT count(*) FROM r1 WHERE id MATCH box(1,2,3)" {1.0 2.0 3.0} 2 "SELECT count(*) FROM r1 WHERE id MATCH box(10001)" {10001.0} 3 "SELECT count(*) FROM r1 WHERE id MATCH box(-10001)" {-10001.0} } { do_catchsql_test 5.$tn.1 $q {1 {SQL logic error}} do_test 5.$tn.2 { set ::box_geom } $vals } do_execsql_test 5.0 { CREATE VIRTUAL TABLE myrtree USING rtree(id, x1,x2); INSERT INTO myrtree VALUES(1, 1, 1); INSERT INTO myrtree VALUES(2, 2, 2); INSERT INTO myrtree VALUES(3, 3, 3); } # EVIDENCE-OF: R-44448-00687 The pUser and xDelUser members of the # sqlite3_rtree_geometry structure are initially set to NULL. set ::box_geom_calls 0 proc box_geom {args} { incr ::box_geom_calls return user_is_zero } do_execsql_test 5.1.1 { SELECT * FROM myrtree WHERE id MATCH box(4, 5); } do_test 5.1.2 { set ::box_geom_calls } 3 # EVIDENCE-OF: R-55837-00155 The pUser variable may be set by the # callback implementation to any arbitrary value that may be useful to # subsequent invocations of the callback within the same query (for # example, a pointer to a complicated data structure used to test for # region intersection). # # EVIDENCE-OF: R-34745-08839 If the xDelUser variable is set to a # non-NULL value, then after the query has finished running SQLite # automatically invokes it with the value of the pUser variable as the # only argument. # set ::box_geom_calls 0 proc box_geom {args} { incr ::box_geom_calls switch -- $::box_geom_calls { 1 { return user_is_zero } 2 { return [list user box_geom_finalizer] } } return "" } proc box_geom_finalizer {} { set ::box_geom_finalizer "::box_geom_calls is $::box_geom_calls" } do_execsql_test 5.1.1 { SELECT * FROM myrtree WHERE id MATCH box(4, 5); } do_test 5.1.2 { set ::box_geom_calls } 3 do_test 5.1.3 { set ::box_geom_finalizer } {::box_geom_calls is 3} # EVIDENCE-OF: R-28176-28813 The xGeom callback always does a # depth-first search of the r-tree. # # For a breadth first search, final test case would return "B L" only. # do_execsql_test 6.0 { CREATE VIRTUAL TABLE xyz USING rtree(x, x1,x2, y1,y2); WITH s(i) AS ( VALUES(1) UNION ALL SELECT i+1 FROM s WHERE i<15 ) INSERT INTO xyz SELECT NULL, one.i,one.i+1, two.i,two.i+1 FROM s one, s two; } do_execsql_test 6.1 { SELECT count(*) FROM xyz_node } {10} proc box_geom {args} { set coords [lindex $args 3] set area [expr { ([lindex $coords 1]-[lindex $coords 0]) * ([lindex $coords 3]-[lindex $coords 2]) }] if {$area==1} { lappend ::box_geom_calls L } else { lappend ::box_geom_calls B } } set ::box_geom_calls [list] do_execsql_test 6.2 { SELECT count(*) FROM xyz WHERE x MATCH box(0,20,0,20) } 225 do_test 6.3 { set prev "" set box_calls [list] foreach c $::box_geom_calls { if {$c!=$prev} { lappend ::box_calls $c set prev $c } } set ::box_calls } {B L B L B L B L B L B L B L B L B L} finish_test |
Added ext/rtree/rtreedoc3.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 | # 2021 September 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. # #*********************************************************************** # # The focus of this file is testing the r-tree extension. # 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 rtreedoc3 ifcapable !rtree { finish_test return } # This command assumes that the argument is a node blob for a 2 dimensional # i32 r-tree table. It decodes and returns a list of cells from the node # as a list. Each cell is itself a list of the following form: # # {$rowid $minX $maxX $minY $maxY} # # For internal (non-leaf) nodes, the rowid is replaced by the child node # number. # proc rnode_cells {aData} { set nDim 2 set nData [string length $aData] set nBytePerCell [expr (8 + 2*$nDim*4)] binary scan [string range $aData 2 3] S nCell set res [list] for {set i 0} {$i < $nCell} {incr i} { set iOff [expr $i*$nBytePerCell+4] set cell [string range $aData $iOff [expr $iOff+$nBytePerCell-1]] binary scan $cell WIIII rowid x1 x2 y1 y2 lappend res [list $rowid $x1 $x2 $y1 $y2] } return $res } # Interpret the first two bytes of the blob passed as the only parameter # as a 16-bit big-endian integer and return the value. If this blob is # the root node of an r-tree, this value is the height of the tree. # proc rnode_height {aData} { binary scan [string range $aData 0 1] S nHeight return $nHeight } # Return a blob containing node iNode of r-tree "rt". # proc rt_node_get {iNode} { db one { SELECT data FROM rt_node WHERE nodeno=$iNode } } #-------------------------------------------------------------- # API: # # pq_init # Initialize a new test. # # pq_test_callback # Invoked each time the xQueryCallback function is called. This Tcl # command checks that the arguments that SQLite passed to xQueryCallback # are as expected. # # pq_test_row # Invoked each time a row is returned. Checks that the row returned # was predicted by the documentation. # # DATA STRUCTURE: # The priority queue is stored as a Tcl list. The order of elements in # the list is unimportant - it is just used as a set here. Each element # in the priority queue is itself a list. The first element is the # priority value for the entry (a real). Following this is a list of # key-value pairs that make up the entries fields. # proc pq_init {} { global Q set Q(pri_queue) [list] set nHeight [rnode_height [rt_node_get 1]] set nCell [llength [rnode_cells [rt_node_get 1]]] # EVIDENCE-OF: R-54708-13595 An R*Tree query is initialized by making # the root node the only entry in a priority queue sorted by rScore. lappend Q(pri_queue) [list 0.0 [list \ iLevel [expr $nHeight+1] \ iChild 1 \ iCurrent 0 \ ]] } proc pq_extract {} { global Q if {[llength $Q(pri_queue)]==0} { error "priority queue is empty!" } # Find the priority queue entry with the lowest score. # # EVIDENCE-OF: R-47257-47871 Smaller scores are processed first. set iBest 0 set rBestScore [lindex $Q(pri_queue) 0 0] for {set ii 1} {$ii < [llength $Q(pri_queue)]} {incr ii} { set rScore [expr [lindex $Q(pri_queue) $ii 0]] if {$rScore<$rBestScore} { set rBestScore $rScore set iBest $ii } } # Extract the entry with the lowest score from the queue and return it. # # EVIDENCE-OF: R-60002-49798 The query proceeds by extracting the entry # from the priority queue that has the lowest score. set ret [lindex $Q(pri_queue) $iBest] set Q(pri_queue) [lreplace $Q(pri_queue) $iBest $iBest] return $ret } proc pq_new_entry {rScore iLevel cell} { global Q set rowid_name "iChild" if {$iLevel==0} { set rowid_name "iRowid" } set kv [list] lappend kv aCoord [lrange $cell 1 end] lappend kv iLevel $iLevel if {$iLevel==0} { lappend kv iRowid [lindex $cell 0] } else { lappend kv iChild [lindex $cell 0] lappend kv iCurrent 0 } lappend Q(pri_queue) [list $rScore $kv] } proc pq_test_callback {L res} { #pq_debug "pq_test_callback $L -> $res" global Q array set G $L ;# "Got" - as in stuff passed to xQuery # EVIDENCE-OF: R-65127-42665 If the extracted priority queue entry is a # node (a subtree), then the next child of that node is passed to the # xQueryFunc callback. # # If it had been a leaf, the row should have been returned, instead of # xQueryCallback being called on a child - as is happening here. foreach {rParentScore parent} [pq_extract] {} array set P $parent ;# "Parent" - as in parent of expected cell if {$P(iLevel)==0} { error "query callback mismatch (1)" } set child_node [rnode_cells [rt_node_get $P(iChild)]] set expected_cell [lindex $child_node $P(iCurrent)] set expected_coords [lrange $expected_cell 1 end] if {[llength $expected_coords] != [llength $G(aCoord)]} { puts [array get P] puts "E: $expected_coords G: $G(aCoord)" error "coordinate mismatch in query callback (1)" } foreach a [lrange $expected_cell 1 end] b $G(aCoord) { if {$a!=$b} { error "coordinate mismatch in query callback (2)" } } # Check level is as expected # if {$G(iLevel) != $P(iLevel)-1} { error "iLevel mismatch in query callback (1)" } # Unless the callback returned NOT_WITHIN, add the entry to the priority # queue. # # EVIDENCE-OF: R-28754-35153 Those subelements for which the xQueryFunc # callback sets eWithin to PARTLY_WITHIN or FULLY_WITHIN are added to # the priority queue using the score supplied by the callback. # # EVIDENCE-OF: R-08681-45277 Subelements that return NOT_WITHIN are # discarded. set r [lindex $res 0] set rScore [lindex $res 1] if {$r!="fully" && $r!="partly" && $r!="not"} { error "unknown result: $r - expected \"fully\", \"partly\" or \"not\"" } if {$r!="not"} { pq_new_entry $rScore [expr $P(iLevel)-1] $expected_cell } # EVIDENCE-OF: R-07194-63805 If the node has more children then it is # returned to the priority queue. Otherwise it is discarded. incr P(iCurrent) if {$P(iCurrent)<[llength $child_node]} { lappend Q(pri_queue) [list $rParentScore [array get P]] } } proc pq_test_result {id x1 x2 y1 y2} { #pq_debug "pq_test_result $id $x1 $x2 $y1 $y2" foreach {rScore next} [pq_extract] {} # The extracted entry must be a leaf (otherwise, xQueryCallback would # have been called on the extracted entries children instead of just # returning the data). # # EVIDENCE-OF: R-13214-54017 If that entry is a leaf (meaning that it is # an actual R*Tree entry and not a subtree) then that entry is returned # as one row of the query result. array set N $next if {$N(iLevel)!=0} { error "result row mismatch (1)" } if {$x1!=[lindex $N(aCoord) 0] || $x2!=[lindex $N(aCoord) 1] || $y1!=[lindex $N(aCoord) 2] || $y2!=[lindex $N(aCoord) 3] } { if {$N(iLevel)!=0} { error "result row mismatch (2)" } } if {$id!=$N(iRowid)} { error "result row mismatch (3)" } } proc pq_done {} { global Q # EVIDENCE-OF: R-57438-45968 The query runs until the priority queue is # empty. if {[llength $Q(pri_queue)]>0} { error "priority queue is not empty!" } } proc pq_debug {caption} { global Q puts "**** $caption ****" set i 0 foreach q [lsort -real -index 0 $Q(pri_queue)] { puts "PQ $i: $q" incr i } } #-------------------------------------------------------------- proc box_query {a} { set res [list fully [expr rand()]] pq_test_callback $a $res return $res } register_box_query db box_query do_execsql_test 1.0 { CREATE VIRTUAL TABLE rt USING rtree_i32(id, x1,x2, y1,y2); WITH s(i) AS ( SELECT 0 UNION ALL SELECT i+1 FROM s WHERE i<64 ) INSERT INTO rt SELECT NULL, a.i, a.i+1, b.i, b.i+1 FROM s a, s b; } proc box_query {a} { set res [list fully [expr rand()]] pq_test_callback $a $res return $res } pq_init db eval { SELECT id, x1,x2, y1,y2 FROM rt WHERE id MATCH qbox() } { pq_test_result $id $x1 $x2 $y1 $y2 } pq_done finish_test |
Added ext/rtree/rtreefuzz001.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 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 | # 2012-12-21 # # 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 corrupt database files. if {![info exists testdir]} { set testdir [file join [file dirname [info script]] .. .. test] } source $testdir/tester.tcl ifcapable !deserialize||!rtree { finish_test return } database_may_be_corrupt do_test rtreefuzz001-100 { sqlite3 db {} db deserialize [decode_hexdb { | size 24576 pagesize 4096 filename c1b.db | page 1 offset 0 | 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3. | 16: 10 00 01 01 00 40 20 20 00 00 00 03 00 00 00 06 .....@ ........ | 32: 00 00 00 00 00 00 00 00 00 00 00 03 00 00 00 04 ................ | 48: 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 ................ | 80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 03 ................ | 96: 00 2e 30 38 0d 00 00 00 04 0e 9c 00 0f ad 0f 4f ..08...........O | 112: 0e fc 0e 9c 00 00 00 00 00 00 00 00 00 00 00 00 ................ | 3728: 00 00 00 00 00 00 00 00 00 00 00 00 5e 04 07 17 ............^... | 3744: 1f 1f 01 81 0b 74 61 62 6c 65 74 31 5f 70 61 72 .....tablet1_par | 3760: 65 6e 74 74 31 5f 70 61 72 65 6e 74 04 43 52 45 entt1_parent.CRE | 3776: 41 54 45 20 54 41 42 4c 45 20 22 74 31 5f 70 61 ATE TABLE .t1_pa | 3792: 72 66 6e 74 22 28 6e 6f 64 65 6e 6f 20 49 4e 54 rfnt.(nodeno INT | 3808: 45 47 45 52 20 50 52 49 4d 41 52 59 20 4b 45 59 EGER PRIMARY KEY | 3824: 2c 70 61 72 65 6e 74 6e 6f 64 65 29 51 03 06 17 ,parentnode)Q... | 3840: 1b 1b 01 7b 74 61 62 6c 65 74 31 5f 6e 6f 64 65 ....tablet1_node | 3856: 74 31 5f 6e 6f 64 65 03 43 52 45 41 54 45 20 54 t1_node.CREATE T | 3872: 41 42 4c 45 20 22 74 31 5f 6e 6f 64 65 22 28 6e ABLE .t1_node.(n | 3888: 6f 64 65 6e 6f 20 49 4e 54 45 47 45 52 20 50 52 odeno INTEGER PR | 3904: 49 4d 41 52 59 20 4b 45 59 2c 64 61 74 61 29 5c IMARY KEY,data). | 3920: 02 07 17 1d 1d 01 81 0b 74 61 62 6c 65 74 31 5f ........tablet1_ | 3936: 72 6f 77 69 64 74 31 5f 72 6f 77 69 64 02 43 52 rowidt1_rowid.CR | 3952: 45 41 54 45 20 54 41 42 4c 45 20 22 74 31 5f 72 EATE TABLE .t1_r | 3968: 6f 77 69 64 22 28 72 6f 77 69 64 20 49 4e 54 45 owid.(rowid INTE | 3984: 47 45 52 20 50 52 49 4d 41 52 59 20 4b 45 59 2c GER PRIMARY KEY, | 4000: 6e 6f 64 65 6e 6f 2c 61 30 2c 61 31 29 51 01 07 nodeno,a0,a1)Q.. | 4016: 17 11 11 08 81 0f 74 61 62 6c 65 74 31 74 31 43 ......tablet1t1C | 4032: 52 45 41 54 45 20 56 49 52 54 55 41 4c 20 54 41 REATE VIRTUAL TA | 4048: 42 4c 45 20 74 31 20 55 53 49 4e 47 20 72 74 72 BLE t1 USING rtr | 4064: 65 65 28 69 64 2c 78 30 2c 78 31 2c 79 30 2c 79 ee(id,x0,x1,y0,y | 4080: 31 2c 2b 6c 61 62 65 6c 2c 2b 6f 74 68 65 72 29 1,+label,+other) | page 2 offset 4096 | 0: 0d 0c cd 00 74 08 75 01 0f e8 0c b3 0f d0 0f b7 ....t.u......... | 16: 0f 9e 0f 91 0f 81 0f 70 0f 5e 0f 4f 0f 39 0f 29 .......p.^.O.9.) | 32: 0f 18 0f 06 0e f7 0c 65 0e 58 0d c2 0d 2c 0c 25 .......e.X...,.% | 48: 0b 85 0a e5 0a 45 09 a5 09 05 0c 83 0c 93 0c a3 .....E.......... | 64: 0f f0 0c 15 0b 75 0a d5 0a 35 09 95 08 f5 0e d8 .....u...5...... | 80: 0e 42 0d ac 0d 16 0c 05 0b 65 0a c5 0a 25 09 85 .B.......e...%.. | 96: 08 e5 0e c8 0e 32 0d 9c 0d 06 0b f5 0b 55 0a b5 .....2.......U.. | 112: 0a 15 09 75 08 d5 0e b8 0e 22 0d 8c 0c f6 0b e5 ...u............ | 128: 0b 45 0a a5 0a 05 09 65 08 c5 0e a8 0e 12 0d 7c .E.....e.......| | 144: 0c e6 0b d5 0b 35 0a 95 09 f5 09 55 08 b5 0e 98 .....5.....U.... | 160: 0e 02 0d 6c 0c d6 0b c5 0b 25 0a 85 09 e5 09 45 ...l.....%.....E | 176: 08 a5 0e 88 0d f2 0d 5c 0c 55 0b b5 0b 15 0a 75 .........U.....u | 192: 09 d5 09 35 08 95 0e 78 0d e2 0d 4c 0c 45 0b a5 ...5...x...L.E.. | 208: 0b 05 0a 65 09 c5 09 25 08 85 0e 68 0d d2 0d 3c ...e...%...h...< | 224: 0c 35 0b 95 0a f5 0a 55 09 b5 09 15 08 75 0c 75 .5.....U.....u.u | 2160: 00 00 00 00 00 0d 8e 75 05 00 01 1b 00 04 62 6f .......u......bo | 2176: 78 2d 39 2c 39 0d 8e 11 05 00 01 1b 00 02 62 6f x-9,9.........bo | 2192: 78 2d 39 2c 38 0d 8d 2d 05 00 01 1b 00 02 62 6f x-9,8..-......bo | 2208: 78 2d 39 2c 37 0d 8c 49 05 00 01 1b 00 02 62 6f x-9,7..I......bo | 2224: 78 2d 39 2c 36 0d 8b 65 05 00 01 1b 00 02 62 6f x-9,6..e......bo | 2240: 78 2d 39 2c 35 0d 8b 01 05 00 01 1b 00 02 62 6f x-9,5.........bo | 2256: 78 2d 39 2c 34 0d 8a 1d 05 00 01 1b 00 02 62 6f x-9,4.........bo | 2272: 78 2d 39 2c 33 0d 89 39 05 00 01 1b 00 02 62 6f x-9,3..9......bo | 2288: 78 2d 39 2c 32 0d 88 55 05 00 01 1b 00 02 62 6f x-9,2..U......bo | 2304: 78 2d 39 2c 31 0d 87 71 05 00 01 1b 00 02 62 6f x-9,1..q......bo | 2320: 78 2d 39 2c 30 0d 8e 74 05 00 01 1b 00 04 62 6f x-9,0..t......bo | 2336: 78 2d 38 2c 39 0d 8e 10 05 00 01 1b 00 02 62 6f x-8,9.........bo | 2352: 78 2d 38 2c 38 0d 8d 2c 05 00 01 1b 00 02 62 6f x-8,8..,......bo | 2368: 78 2d 38 2c 37 0d 8c 48 05 00 01 1b 00 02 62 6f x-8,7..H......bo | 2384: 78 2d 38 2c 36 0d 8b 64 05 00 01 1b 00 02 62 6f x-8,6..d......bo | 2400: 78 2d 38 2c 35 0d 8b 00 05 00 01 1b 00 02 62 6f x-8,5.........bo | 2416: 78 2d 38 2c 34 0d 8a 1c 05 00 01 1b 00 02 62 6f x-8,4.........bo | 2432: 78 2d 38 2c 33 0d 89 38 05 00 01 1b 00 02 62 6f x-8,3..8......bo | 2448: 78 2d 38 2c 32 0d 88 54 05 00 01 1b 00 02 62 6f x-8,2..T......bo | 2464: 78 2d 38 2c 31 0d 87 70 05 00 01 1b 00 02 62 6f x-8,1..p......bo | 2480: 78 2d 38 2c 30 0d 8e 73 05 00 01 1b 00 05 62 6f x-8,0..s......bo | 2496: 78 2d 37 2c 39 0d 8e 0f 05 00 01 1b 00 05 62 6f x-7,9.........bo | 2512: 78 2d 37 2c 38 0d 8d 2b 05 00 01 1b 00 05 62 6f x-7,8..+......bo | 2528: 78 2d 37 2c 37 0d 8c 47 05 00 01 1b 00 05 62 6f x-7,7..G......bo | 2544: 78 2d 37 2c 36 0d 8b 63 05 00 01 1b 00 05 62 6f x-7,6..c......bo | 2560: 78 2d 37 2c 35 0d 8a 7f 05 00 01 1b 00 05 62 6f x-7,5.........bo | 2576: 78 2d 37 2c 34 0d 8a 1b 05 00 01 1b 00 05 62 6f x-7,4.........bo | 2592: 78 2d 37 2c 33 0d 89 37 05 00 01 1b 00 05 62 6f x-7,3..7......bo | 2608: 78 2d 37 2c 32 0d 88 53 05 00 01 1b 00 05 62 6f x-7,2..S......bo | 2624: 78 2d 37 2c 31 0d 87 6f 05 00 01 1b 00 05 62 6f x-7,1..o......bo | 2640: 78 2d 37 2c 30 0d 8e 72 05 00 01 1b 00 04 62 6f x-7,0..r......bo | 2656: 78 2d 36 2c 39 0d 8e 0e 05 00 01 1b 00 05 62 6f x-6,9.........bo | 2672: 78 2d 36 2c 38 0d 8d 2a 05 00 01 1b 00 05 62 6f x-6,8..*......bo | 2688: 78 2d 36 2c 37 0d 8c 46 05 00 01 1b 00 05 62 6f x-6,7..F......bo | 2704: 78 2d 36 2c 36 0d 8b 62 05 00 01 1b 00 05 62 6f x-6,6..b......bo | 2720: 78 2d 36 2c 35 0d 8a 7e 05 00 01 1b 00 05 62 6f x-6,5..~......bo | 2736: 78 2d 36 2c 34 0d 8a 1a 05 00 01 1b 00 05 62 6f x-6,4.........bo | 2752: 78 2d 36 2c 33 0d 89 36 05 00 01 1b 00 05 62 6f x-6,3..6......bo | 2768: 78 2d 36 2c 32 0d 88 52 05 00 01 1b 00 05 62 6f x-6,2..R......bo | 2784: 78 2d 36 2c 31 0d 87 6e 05 00 01 1b 00 05 62 6f x-6,1..n......bo | 2800: 78 2d 36 2c 30 0d 8e 71 05 00 01 1b 00 04 62 6f x-6,0..q......bo | 2816: 78 2d 35 2c 39 0d 8e 0d 05 00 01 1b 00 05 62 6f x-5,9.........bo | 2832: 78 2d 35 2c 38 0d 8d 29 05 00 01 1b 00 05 62 6f x-5,8..)......bo | 2848: 78 2d 35 2c 37 0d 8c 45 05 00 01 1b 00 05 62 6f x-5,7..E......bo | 2864: 78 2d 35 2c 36 0d 8b 61 05 00 01 1b 00 05 62 6f x-5,6..a......bo | 2880: 78 2d 35 2c 35 0d 8a 7d 05 00 01 1b 00 05 62 6f x-5,5.........bo | 2896: 78 2d 35 2c 34 0d 8a 19 05 00 01 1b 00 05 62 6f x-5,4.........bo | 2912: 78 2d 35 2c 33 0d 89 35 05 00 01 1b 00 05 62 6f x-5,3..5......bo | 2928: 78 2d 35 2c 32 0d 88 51 05 00 01 1b 00 05 62 6f x-5,2..Q......bo | 2944: 78 2d 35 2c 31 0d 87 6d 05 00 01 1b 00 05 62 6f x-5,1..m......bo | 2960: 78 2d 35 2c 30 0d 8e 70 05 00 01 1b 00 04 62 6f x-5,0..p......bo | 2976: 78 2d 34 2c 39 0d 8e 0c 05 00 01 1b 00 04 62 6f x-4,9.........bo | 2992: 78 2d 34 2c 38 0d 8d 28 05 00 01 1b 00 04 62 6f x-4,8..(......bo | 3008: 78 2d 34 2c 37 0d 8c 44 05 00 01 1b 00 04 62 6f x-4,7..D......bo | 3024: 78 2d 34 2c 36 0d 8b 60 05 00 01 1b 00 02 62 6f x-4,6..`......bo | 3040: 78 2d 34 2c 35 0d 8a 7c 05 00 01 1b 00 02 62 6f x-4,5..|......bo | 3056: 78 2d 34 2c 34 0d 8a 18 05 00 01 1b 00 02 62 6f x-4,4.........bo | 3072: 78 2d 34 2c 33 0d 89 34 05 00 01 1b 00 02 62 6f x-4,3..4......bo | 3088: 78 2d 34 2c 32 0d 88 50 05 00 01 1b 00 02 62 6f x-4,2..P......bo | 3104: 78 2d 34 2c 31 0d 87 6c 05 00 01 1b 00 02 62 6f x-4,1..l......bo | 3120: 78 2d 34 2c 30 0d 8e 6f 05 00 01 1b 00 04 62 6f x-4,0..o......bo | 3136: 78 2d 33 2c 39 0d 8e 0b 05 00 01 1b 00 04 62 6f x-3,9.........bo | 3152: 78 2d 33 2c 38 0d 8d 27 05 00 01 1b 00 04 62 6f x-3,8..'......bo | 3168: 78 2d 33 2c 37 0d 87 68 05 00 01 1b 00 03 62 6f x-3,7..h......bo | 3184: 78 2d 30 2c 30 06 90 d9 80 80 81 84 4c 05 00 01 x-0,0.......L... | 3200: 00 00 03 0d 88 4c 05 00 01 1b 00 02 62 6f 78 2d .....L......box- | 3216: 30 2c 31 0d 88 4d 05 00 01 1b 00 02 62 6f 78 2d 0,1..M......box- | 3232: 31 2c 31 0d 88 4e 05 00 01 1b 00 02 62 6f 78 2d 1,1..N......box- | 3248: 32 2c 31 17 01 05 00 01 2f 00 02 6c 6f 77 65 72 2,1...../..lower | 3264: 2d 6c 65 66 74 20 63 6f 72 6e 65 72 0d 0d 26 00 -left corner..&. | 3280: 09 00 01 00 00 04 0d 8c 43 05 00 01 1b 00 04 62 ........C......b | 3296: 6f 78 2d 33 2c 36 0d 8b 5f 05 00 01 1b 00 02 62 ox-3,6.._......b | 3312: 6f 78 2d 33 2c 35 0d 8a 7b 05 00 01 1b 00 02 62 ox-3,5.........b | 3328: 6f 78 2d 33 2c 34 0d 8a 17 05 00 01 1b 00 02 62 ox-3,4.........b | 3344: 6f 78 2d 33 2c 33 0d 89 33 05 00 01 1b 00 02 62 ox-3,3..3......b | 3360: 6f 78 2d 33 2c 32 0d bc 00 06 00 09 0d 87 6b 05 ox-3,2........k. | 3376: 00 01 1b 00 03 62 6f 78 2d 33 2c 30 0d 8e 6e 05 .....box-3,0..n. | 3392: 00 01 1b 00 04 62 6f 78 2d 32 2c 39 0d 8e 0a 05 .....box-2,9.... | 3408: 00 01 1b 00 04 62 6f 78 2d 32 2c 38 0d 8d 26 05 .....box-2,8..&. | 3424: 00 01 1b 00 04 62 6f 78 2d 32 2c 37 0d 8c 42 05 .....box-2,7..B. | 3440: 00 01 1b 00 04 62 6f 78 2d 32 2c 36 0d 8b 5e 05 .....box-2,6..^. | 3456: 00 01 1b 00 02 62 6f 78 2d 32 2c 35 0d 8a 7a 05 .....box-2,5..z. | 3472: 00 01 1b 00 02 62 6f 78 2d 32 2c 34 0d 8a 16 05 .....box-2,4.... | 3488: 00 01 1b 00 02 62 6f 78 2d 32 2c 33 0d 89 32 05 .....box-2,3..2. | 3504: 00 01 1b 00 02 62 6f 78 2d 32 2c 32 0e 52 00 06 .....box-2,2.R.. | 3520: 00 09 0d 87 6a 05 00 01 1b 00 03 62 6f 78 2d 32 ....j......box-2 | 3536: 2c 30 0d 8e 6d 05 00 01 1b 00 04 62 6f 78 2d 31 ,0..m......box-1 | 3552: 2c 39 0d 8e 09 05 00 01 1b 00 04 62 6f 78 2d 31 ,9.........box-1 | 3568: 2c 38 0d 8d 25 05 00 01 1b 00 04 62 6f 78 2d 31 ,8..%......box-1 | 3584: 2c 37 0d 8c 41 05 00 01 1b 00 04 62 6f 78 2d 31 ,7..A......box-1 | 3600: 2c 36 0d 8b 5d 05 00 01 1b 00 02 62 6f 78 2d 31 ,6..]......box-1 | 3616: 2c 35 0d 8a 79 05 00 01 1b 00 02 62 6f 78 2d 31 ,5..y......box-1 | 3632: 2c 34 0d 8a 15 05 00 01 1b 00 02 62 6f 78 2d 31 ,4.........box-1 | 3648: 2c 33 0d 89 31 05 00 01 1b 00 02 62 6f 78 2d 31 ,3..1......box-1 | 3664: 2c 32 0e e8 00 06 00 09 0d 87 69 05 00 01 1b 00 ,2........i..... | 3680: 03 62 6f 78 2d 31 2c 30 0d 8e 6c 05 00 01 1b 00 .box-1,0..l..... | 3696: 04 62 6f 78 2d 30 2c 39 0d 8e 08 05 00 01 1b 00 .box-0,9........ | 3712: 04 62 6f 78 2d 30 2c 38 0d 8d 24 05 00 01 1b 00 .box-0,8..$..... | 3728: 04 62 6f 78 2d 30 2c 37 0d 8c 40 05 00 01 1b 00 .box-0,7..@..... | 3744: 04 62 6f 78 2d 30 2c 36 0d 8b 5c 05 00 01 1b 00 .box-0,6........ | 3760: 02 62 6f 78 2d 30 2c 35 0d 8a 78 05 00 01 1b 00 .box-0,5..x..... | 3776: 02 62 6f 78 2d 30 2c 34 0d 8a 14 05 00 01 1b 00 .box-0,4........ | 3792: 02 62 6f 78 2d 30 2c 33 0d 89 30 05 00 01 1b 00 .box-0,3..0..... | 3808: 02 62 6f 78 2d 30 2c 32 00 00 00 0f 00 09 1b 00 .box-0,2........ | 3824: 62 6f 78 2d 30 2c 30 0d 0e 05 00 09 1d 00 74 6f box-0,0.......to | 3840: 70 20 68 61 6c 66 10 0d 05 00 09 23 00 62 6f 74 p half.....#.bot | 3856: 74 6f 6d 20 68 61 6c 66 0f 0c 02 05 09 01 00 72 tom half.......r | 3872: 69 67 68 74 20 68 61 6c 66 0e 0b 05 00 09 1f 00 ight half....... | 3888: 6c 65 66 74 20 68 61 6c 66 14 0a 05 00 09 2b 00 left half.....+. | 3904: 74 68 65 20 77 68 6f 6c 65 20 74 68 69 6e 67 0d the whole thing. | 3920: 09 05 00 09 1d 00 74 6f 70 20 65 64 67 65 10 08 ......top edge.. | 3936: 05 00 09 23 00 62 6f 74 74 6f 6d 20 65 64 67 65 ...#.bottom edge | 3952: 0f 07 05 00 09 21 00 72 69 67 68 74 20 65 64 67 .....!.right edg | 3968: 65 0e 06 05 00 09 1f 00 6c 65 66 74 20 65 64 67 e.......left edg | 3984: 65 0b 05 05 00 09 19 00 63 65 6e 74 65 72 17 04 e.......center.. | 4000: 05 00 09 31 00 75 70 70 65 72 2d 72 69 67 68 74 ...1.upper-right | 4016: 20 63 6f 72 6e 65 72 17 03 05 00 09 31 00 6c 6f corner.....1.lo | 4032: 77 65 72 2d 72 69 67 68 74 20 63 6f 72 6e 65 72 wer-right corner | 4048: 16 02 05 00 09 2f 00 75 70 70 65 72 2d 6c 65 66 ...../.upper-lef | 4064: 74 20 63 6f 72 6e 65 72 06 00 05 00 01 00 00 03 t corner........ | 4080: 0d 88 4f 05 00 01 1b 00 02 62 6f 78 2d 33 2c 31 ..O......box-3,1 | page 3 offset 8192 | 0: 05 00 00 00 01 0f fb 00 00 00 00 06 0f fb 00 00 ................ | 384: 00 00 00 00 00 00 00 89 50 03 04 00 93 24 00 00 ........P....$.. | 400: 00 11 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ | 688: 00 00 00 00 42 c8 00 00 42 4c 00 00 42 00 00 00 ....B...BL..B... | 720: 03 eb 40 40 00 00 40 80 00 00 00 00 00 00 3f 80 ..@@..@.......?. | 736: 00 00 00 00 00 00 00 00 03 ea 40 00 00 00 40 40 ..........@...@@ | 752: 00 00 00 00 00 00 3f 80 00 00 00 00 00 00 00 00 ......?......... | 768: 03 e9 3f 80 00 00 40 00 00 00 00 00 00 00 3f 80 ..?...@.......?. | 784: 00 00 00 00 00 00 00 00 03 e8 00 00 00 00 3f 80 ..............?. | 800: 00 00 00 00 00 00 3f 80 00 00 00 00 00 00 00 00 ......?......... | 1616: 00 00 00 00 00 00 00 00 00 00 89 50 02 04 00 93 ...........P.... | 1632: 24 00 00 00 33 00 00 00 00 00 00 00 01 00 00 00 $...3........... | 1648: 00 41 20 00 00 00 00 00 00 41 0e 00 00 00 00 00 .A ......A...... | 1664: 00 00 00 04 4f 40 40 00 00 40 80 00 00 3f 80 00 ....O@@..@...?.. | 1680: 00 40 00 00 00 00 00 00 00 00 00 04 4e 40 00 00 .@..........N@.. | 1696: 00 40 40 00 00 3f 80 00 00 40 00 00 00 00 00 00 .@@..?...@...... | 1712: 00 00 00 04 4d 3f 80 00 00 40 00 00 00 3f 80 00 ....M?...@...?.. | 1728: 00 40 00 00 00 00 00 00 00 00 00 04 4c 00 00 00 .@..........L... | 1744: 00 3f 80 00 00 3f 80 00 00 40 00 00 00 00 00 00 .?...?...@...... | 1760: 00 00 00 04 b3 40 40 00 00 40 80 00 00 40 00 00 .....@@..@...@.. | 1776: 00 40 40 00 00 00 00 00 00 00 00 04 b2 40 00 00 .@@..........@.. | 1792: 00 40 40 00 00 40 00 00 00 40 40 00 00 00 00 00 .@@..@...@@..... | 1808: 00 00 00 04 b1 3f 80 00 00 40 00 00 00 40 00 00 .....?...@...@.. | 1824: 00 40 40 00 00 00 00 00 00 00 00 04 b0 00 00 00 .@@............. | 1840: 00 3f 80 00 00 40 00 00 00 40 40 00 00 00 00 00 .?...@...@@..... | 1856: 00 00 00 05 17 40 40 00 00 40 80 00 00 40 40 00 .....@@..@...@@. | 1872: 00 40 80 00 00 00 00 00 00 00 00 05 16 40 00 00 .@...........@.. | 1888: 00 40 40 00 00 40 40 00 00 40 80 00 00 00 00 00 .@@..@@..@...... | 1904: 00 00 00 05 15 3f 80 00 00 40 00 00 00 40 40 00 .....?...@...@@. | 1920: 00 40 80 00 00 00 00 00 00 00 00 05 14 00 00 00 .@.............. | 1936: 00 3f 80 00 00 40 40 00 00 40 80 00 00 00 00 00 .?...@@..@...... | 1952: 00 00 00 05 7b 40 40 00 00 40 80 00 00 40 80 00 .....@@..@...@.. | 1968: 00 40 a0 00 00 00 00 00 00 00 00 05 7a 40 00 00 .@..........z@.. | 1984: 00 40 40 00 00 40 80 00 00 40 a0 00 00 00 00 00 .@@..@...@...... | 2000: 00 00 00 05 79 3f 80 00 00 40 00 00 00 40 80 00 ....y?...@...@.. | 2016: 00 40 a0 00 00 00 00 00 00 00 00 05 78 00 00 00 .@..........x... | 2032: 00 3f 80 00 00 40 80 00 00 40 a0 00 00 00 00 00 .?...@...@...... | 2048: 00 00 00 05 df 40 40 00 00 40 80 00 00 40 a0 00 .....@@..@...@.. | 2064: 00 40 c0 00 00 00 00 00 00 00 00 05 de 40 00 00 .@...........@.. | 2080: 00 40 40 00 00 40 a0 00 00 40 c0 00 00 00 00 00 .@@..@...@...... | 2096: 00 00 00 05 dd 3f 80 00 00 40 00 00 00 40 a0 00 .....?...@...@.. | 2112: 00 40 c0 00 00 00 00 00 00 00 00 05 dc 00 00 00 .@.............. | 2128: 00 3f 80 00 00 40 a0 00 00 40 c0 00 00 00 00 00 .?...@...@...... | 2144: 00 00 00 06 43 40 40 00 00 40 80 00 00 40 c0 00 ....C@@..@...@.. | 2160: 00 40 e0 00 00 00 00 00 00 00 00 06 42 40 00 00 .@..........B@.. | 2176: 00 40 40 00 00 40 c0 00 00 40 e0 00 00 00 00 00 .@@..@...@...... | 2192: 00 00 00 06 41 3f 80 00 00 40 00 00 00 40 c0 00 ....A?...@...@.. | 2208: 00 40 e0 00 00 00 00 00 00 00 00 06 40 00 00 00 .@..........@... | 2224: 00 3f 80 00 00 40 c0 00 00 40 e0 00 00 00 00 00 .?...@...@...... | 2240: 00 00 00 06 a7 40 40 00 00 40 80 00 00 40 e0 00 .....@@..@...@.. | 2256: 00 41 00 00 00 00 00 00 00 00 00 06 a6 40 00 00 .A...........@.. | 2272: 00 40 40 00 00 40 e0 00 00 41 00 00 00 00 00 00 .@@..@...A...... | 2288: 00 00 00 06 a5 3f 80 00 00 40 00 00 00 40 e0 00 .....?...@...@.. | 2304: 00 41 00 00 00 00 00 00 00 00 00 06 a4 00 00 00 .A.............. | 2320: 00 3f 80 00 00 40 e0 00 00 41 00 00 00 00 00 00 .?...@...A...... | 2336: 00 00 00 07 0a 40 00 00 00 40 40 00 00 41 00 00 .....@...@@..A.. | 2352: 00 41 10 00 00 00 00 00 00 00 00 07 09 3f 80 00 .A...........?.. | 2368: 00 40 00 00 00 41 00 00 00 41 10 00 00 00 00 00 .@...A...A...... | 2384: 00 00 00 07 08 00 00 00 00 3f 80 00 00 41 00 00 .........?...A.. | 2400: 00 41 10 00 00 00 00 00 00 00 00 07 6e 40 00 00 .A..........n@.. | 2416: 00 40 40 00 00 41 10 00 00 41 20 00 00 00 00 00 .@@..A...A ..... | 2432: 00 00 00 07 6d 3f 80 00 00 40 00 00 00 41 10 00 ....m?...@...A.. | 2448: 00 41 20 00 00 00 00 00 00 00 00 07 6c 00 00 00 .A .........l... | 2464: 00 3f 80 00 00 41 10 00 00 41 20 00 00 00 00 00 .?...A...A ..... | 2480: 00 00 00 07 0b 40 40 00 00 40 80 00 00 41 00 00 .....@@..@...A.. | 2496: 00 41 10 00 00 00 00 00 00 00 00 07 6f 40 40 00 .A..........o@@. | 2512: 00 40 80 00 00 41 10 00 00 41 20 00 00 00 00 00 .@...A...A ..... | 2528: 00 00 00 03 ec 40 80 00 00 40 a0 00 00 00 00 00 .....@...@...... | 2544: 00 3f 80 00 00 00 00 00 00 00 00 04 50 40 80 00 .?..........P@.. | 2560: 00 40 a0 00 00 3f 80 00 00 40 00 00 00 00 00 00 .@...?...@...... | 2576: 00 00 00 04 b4 40 80 00 00 40 a0 00 00 40 00 00 .....@...@...@.. | 2592: 00 40 40 00 00 00 00 00 00 00 00 05 18 40 80 00 .@@..........@.. | 2608: 00 40 a0 00 00 40 40 00 00 40 80 00 00 00 00 00 .@...@@..@...... | 2624: 00 00 00 05 7c 40 80 00 00 40 a0 00 00 40 80 00 ....|@...@...@.. | 2640: 00 40 a0 00 00 00 00 00 00 00 00 05 e0 40 80 00 .@...........@.. | 2656: 00 40 a0 00 00 40 a0 00 00 40 c0 00 00 00 00 00 .@...@...@...... | 2672: 00 00 00 06 44 40 80 00 00 40 a0 00 00 40 c0 00 ....D@...@...@.. | 2688: 00 40 e0 00 00 00 00 00 00 00 00 06 a8 40 80 00 .@...........@.. | 2704: 00 40 a0 00 00 40 e0 00 00 41 00 00 00 00 00 00 .@...@...A...... | 2720: 00 00 00 07 0c 40 80 00 00 40 a0 00 00 41 00 00 .....@...@...A.. | 2736: 00 41 10 00 00 00 00 00 00 00 00 07 70 40 80 00 .A..........p@.. | 2752: 00 40 a0 00 00 41 10 00 00 41 20 00 00 00 00 00 .@...A...A ..... | 2768: 00 00 00 03 ed 40 a0 00 00 40 c0 00 00 00 00 00 .....@...@...... | 2784: 00 3f 80 00 00 00 00 00 00 00 00 04 51 40 a0 00 .?..........Q@.. | 2800: 00 40 c0 00 00 3f 80 00 00 40 00 00 00 00 00 00 .@...?...@...... | 2816: 00 00 00 04 b5 40 a0 00 00 40 c0 00 00 40 00 00 .....@...@...@.. | 2832: 00 40 40 00 00 00 00 00 00 00 00 05 19 40 a0 00 .@@..........@.. | 2848: 00 40 c0 00 00 40 40 00 00 40 80 00 00 89 50 01 .@...@@..@....P. | 2864: 04 00 93 24 00 01 00 02 00 00 00 00 00 00 00 03 ...$............ | 2880: 00 00 00 00 40 80 00 00 00 00 00 00 3f 80 00 00 ....@.......?... | 2896: 00 00 00 00 00 00 00 02 00 00 00 00 41 20 00 00 ............A .. | 2912: 00 00 00 00 41 20 00 00 00 00 00 00 00 00 00 00 ....A .......... | 4080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 05 03 ................ | page 4 offset 12288 | 0: 0d 00 00 00 00 10 00 00 00 00 00 00 00 00 00 00 ................ | page 5 offset 16384 | 0: 0d 00 00 00 03 01 87 00 0b 2d 06 5a 01 87 00 00 .........-.Z.... | 384: 00 00 00 00 00 00 00 89 50 03 04 00 93 24 00 00 ........P....$.. | 400: 00 11 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ | 688: 00 00 00 00 42 c8 00 00 42 4c 00 00 42 00 00 00 ....B...BL..B... | 720: 03 eb 40 40 00 00 40 80 00 00 00 00 00 00 3f 80 ..@@..@.......?. | 736: 00 00 00 00 00 00 00 00 03 ea 40 00 00 00 40 40 ..........@...@@ | 752: 00 00 00 00 00 00 3f 80 00 00 00 00 00 00 00 00 ......?......... | 768: 03 e9 3f 80 00 00 40 00 00 00 00 00 00 00 3f 80 ..?...@.......?. | 784: 00 00 00 00 00 00 00 00 03 e8 00 00 00 00 3f 80 ..............?. | 800: 00 00 00 00 00 00 3f 80 00 00 00 00 00 00 00 00 ......?......... | 1616: 00 00 00 00 00 00 00 00 00 00 89 50 02 04 00 93 ...........P.... | 1632: 24 00 00 00 2d 00 00 00 00 00 00 04 4c 00 00 00 $...-.......L... | 1648: 00 3f 80 00 00 3f 80 00 00 40 00 00 00 00 00 00 .?...?...@...... | 1664: 00 00 00 04 b0 00 00 00 00 3f 80 00 00 40 00 00 .........?...@.. | 1680: 00 40 40 00 00 00 00 00 00 00 00 05 14 00 00 00 .@@............. | 1696: 00 3f 80 00 00 40 40 00 00 40 80 00 00 00 00 00 .?...@@..@...... | 1712: 00 00 00 05 78 00 00 00 00 3f 80 00 00 40 80 00 ....x....?...@.. | 1728: 00 40 a0 00 00 00 00 00 00 00 00 05 dc 00 00 00 .@.............. | 1744: 00 3f 80 00 00 40 a0 00 00 40 c0 00 00 00 00 00 .?...@...@...... | 1760: 00 00 00 00 01 00 00 00 00 41 20 00 00 00 00 00 .........A ..... | 1776: 00 41 0e 00 00 00 00 00 00 00 00 04 4d 3f 80 00 .A..........M?.. | 1792: 00 40 00 00 00 3f 80 00 00 40 00 00 00 00 00 00 .@...?...@...... | 1808: 00 00 00 04 b1 3f 80 00 00 40 00 00 00 40 00 00 .....?...@...@.. | 1824: 00 40 40 00 00 00 00 00 00 00 00 05 15 3f 80 00 .@@..........?.. | 1840: 00 40 00 00 00 40 40 00 00 40 80 00 00 00 00 00 .@...@@..@...... | 1856: 00 00 00 05 79 3f 80 00 00 40 00 00 00 40 80 00 ....y?...@...@.. | 1872: 00 40 a0 00 00 00 00 00 00 00 00 05 dd 3f 80 00 .@...........?.. | 1888: 00 40 00 00 00 40 a0 00 00 40 c0 00 00 00 00 00 .@...@...@...... | 1904: 00 00 00 04 4e 40 00 00 00 40 40 00 00 3f 80 00 ....N@...@@..?.. | 1920: 00 40 00 00 00 00 00 00 00 00 00 04 b2 40 00 00 .@...........@.. | 1936: 00 40 40 00 00 40 00 00 00 40 40 00 00 00 00 00 .@@..@...@@..... | 1952: 00 00 00 05 16 40 00 00 00 40 40 00 00 40 40 00 .....@...@@..@@. | 1968: 00 40 80 00 00 00 00 00 00 00 00 05 7a 40 00 00 .@..........z@.. | 1984: 00 40 40 00 00 40 80 00 00 40 a0 00 00 00 00 00 .@@..@...@...... | 2000: 00 00 00 05 de 40 00 00 00 40 40 00 00 40 a0 00 .....@...@@..@.. | 2016: 00 40 c0 00 00 00 00 00 00 00 00 04 4f 40 40 00 .@..........O@@. | 2032: 00 40 80 00 00 3f 80 00 00 40 00 00 00 00 00 00 .@...?...@...... | 2048: 00 00 00 04 b3 40 40 00 00 40 80 00 00 40 00 00 .....@@..@...@.. | 2064: 00 40 40 00 00 00 00 00 00 00 00 05 17 40 40 00 .@@..........@@. | 2080: 00 40 80 00 00 40 40 00 00 40 80 00 00 00 00 00 .@...@@..@...... | 2096: 00 00 00 05 7b 40 40 00 00 40 80 00 00 40 80 00 .....@@..@...@.. | 2112: 00 40 a0 00 00 00 00 00 00 00 00 05 df 40 40 00 .@...........@@. | 2128: 00 40 80 00 00 40 a0 00 00 40 c0 00 00 00 00 00 .@...@...@...... | 2144: 00 00 00 03 ec 40 80 00 00 40 a0 00 00 00 00 00 .....@...@...... | 2160: 00 3f 80 00 00 00 00 00 00 00 00 04 50 40 80 00 .?..........P@.. | 2176: 00 40 a0 00 00 3f 80 00 00 40 00 00 00 00 00 00 .@...?...@...... | 2192: 00 00 00 04 b4 40 80 00 00 40 a0 00 00 40 00 00 .....@...@...@.. | 2208: 00 40 40 00 00 00 00 00 00 00 00 05 18 40 80 00 .@@..........@.. | 2224: 00 40 a0 00 00 40 40 00 00 40 80 00 00 00 00 00 .@...@@..@...... | 2240: 00 00 00 05 7c 40 80 00 00 40 a0 00 00 40 80 00 ....|@...@...@.. | 2256: 00 40 a0 00 00 00 00 00 00 00 00 05 e0 40 80 00 .@...........@.. | 2272: 00 40 a0 00 00 40 a0 00 00 40 c0 00 00 00 00 00 .@...@...@...... | 2288: 00 00 00 03 f0 41 00 00 00 41 10 00 00 00 00 00 .....A...A...... | 2304: 00 3f 80 00 00 00 00 00 00 00 00 04 54 41 00 00 .?..........TA.. | 2320: 00 41 10 00 00 3f 80 00 00 40 00 00 00 00 00 00 .A...?...@...... | 2336: 00 00 00 04 b8 41 00 00 00 41 10 00 00 40 00 00 .....A...A...@.. | 2352: 00 40 40 00 00 00 00 00 00 00 00 05 1c 41 00 00 .@@..........A.. | 2368: 00 41 10 00 00 40 40 00 00 40 80 00 00 00 00 00 .A...@@..@...... | 2384: 00 00 00 05 80 41 00 00 00 41 10 00 00 40 80 00 .....A...A...@.. | 2400: 00 40 a0 00 00 00 00 00 00 00 00 05 e4 41 00 00 .@...........A.. | 2416: 00 41 10 00 00 40 a0 00 00 40 c0 00 00 00 00 00 .A...@...@...... | 2432: 00 00 00 06 48 41 00 00 00 41 10 00 00 40 c0 00 ....HA...A...@.. | 2448: 00 40 e0 00 00 00 00 00 00 00 00 06 ac 41 00 00 .@...........A.. | 2464: 00 41 10 00 00 40 e0 00 00 41 00 00 00 00 00 00 .A...@...A...... | 2480: 00 00 00 07 10 41 00 00 00 41 10 00 00 41 00 00 .....A...A...A.. | 2496: 00 41 10 00 00 00 00 00 00 00 00 03 f1 41 10 00 .A...........A.. | 2512: 00 41 20 00 00 00 00 00 00 3f 80 00 00 00 00 00 .A ......?...... | 2528: 00 00 00 04 55 41 10 00 00 41 20 00 00 3f 80 00 ....UA...A ..?.. | 2544: 00 40 00 00 00 00 00 00 00 00 00 04 b9 41 10 00 .@...........A.. | 2560: 00 41 20 00 00 40 00 00 00 40 40 00 00 00 00 00 .A ..@...@@..... | 2576: 00 00 00 05 1d 41 10 00 00 41 20 00 00 40 40 00 .....A...A ..@@. | 2592: 00 40 80 00 00 00 00 00 00 00 00 05 81 41 10 00 .@...........A.. | 2608: 00 41 20 00 00 40 80 00 00 40 a0 00 00 00 00 00 .A ..@...@...... | 2624: 00 00 00 05 e5 41 10 00 00 41 20 00 00 40 a0 00 .....A...A ..@.. | 2640: 00 40 c0 00 00 00 00 00 00 00 00 06 49 41 10 00 .@..........IA.. | 2656: 00 41 20 00 00 40 c0 00 00 40 e0 00 00 00 00 00 .A ..@...@...... | 2672: 00 00 00 06 ad 41 10 00 00 41 20 00 00 40 e0 00 .....A...A ..@.. | 2688: 00 41 00 00 00 00 00 00 00 00 00 07 11 41 10 00 .A...........A.. | 2704: 00 41 20 00 00 41 00 00 00 41 10 00 00 00 00 00 .A ..A...A...... | 2848: 00 00 00 00 00 00 00 00 00 00 00 00 00 89 50 01 ..............P. | 2864: 04 00 93 24 00 01 00 04 00 00 00 00 00 00 00 03 ...$............ | 2880: 00 00 00 00 40 80 00 00 00 00 00 00 3f 80 00 00 ....@.......?... | 2896: 00 00 00 00 00 00 00 02 00 00 00 00 41 20 00 00 ............A .. | 2912: 00 00 00 00 41 10 00 00 00 00 00 00 00 00 00 04 ....A........... | 2928: 00 00 00 00 41 20 00 00 40 c0 00 00 41 20 00 00 ....A ..@...A .. | 2944: 00 00 00 00 00 00 00 05 40 a0 00 00 41 00 00 00 ........@...A... | 2960: 00 00 00 00 41 20 00 00 00 00 00 00 00 00 00 00 ....A .......... | page 6 offset 20480 | 0: 0d 00 00 00 02 06 5a 00 0b 2d 06 5a 00 00 00 00 ......Z..-.Z.... | 1616: 00 00 00 00 00 00 00 00 00 00 89 50 05 04 00 93 ...........P.... | 1632: 24 00 00 00 1c 00 00 00 00 00 00 03 ed 40 a0 00 $............@.. | 1648: 00 40 c0 00 00 00 00 00 00 3f 80 00 00 00 00 00 .@.......?...... | 1664: 00 00 00 04 51 40 a0 00 00 40 c0 00 00 3f 80 00 ....Q@...@...?.. | 1680: 00 40 00 00 00 00 00 00 00 00 00 04 b5 40 a0 00 .@...........@.. | 1696: 00 40 c0 00 00 40 00 00 00 40 40 00 00 00 00 00 .@...@...@@..... | 1712: 00 00 00 05 19 40 a0 00 00 40 c0 00 00 40 40 00 .....@...@...@@. | 1728: 00 40 80 00 00 00 00 00 00 00 00 05 7d 40 a0 00 .@...........@.. | 1744: 00 40 c0 00 00 40 80 00 00 40 a0 00 00 00 00 00 .@...@...@...... | 1760: 00 00 00 05 e1 40 a0 00 00 40 c0 00 00 40 a0 00 .....@...@...@.. | 1776: 00 40 c0 00 00 00 00 00 00 00 00 06 45 40 a0 00 .@..........E@.. | 1792: 00 40 c0 00 00 40 c0 00 00 40 e0 00 00 00 00 00 .@...@...@...... | 1808: 00 00 00 06 a9 40 a0 00 00 40 c0 00 00 40 e0 00 .....@...@...@.. | 1824: 00 41 00 00 00 00 00 00 00 00 00 07 0d 40 a0 00 .A...........@.. | 1840: 00 40 c0 00 00 41 00 00 00 41 10 00 00 00 00 00 .@...A...A...... | 1856: 00 00 00 03 ee 40 c0 00 00 40 e0 00 00 00 00 00 .....@...@...... | 1872: 00 3f 80 00 00 00 00 00 00 00 00 04 52 40 c0 00 .?..........R@.. | 1888: 00 40 e0 00 00 3f 80 00 00 40 00 00 00 00 00 00 .@...?...@...... | 1904: 00 00 00 04 b6 40 c0 00 00 40 e0 00 00 40 00 00 .....@...@...@.. | 1920: 00 40 40 00 00 00 00 00 00 00 00 05 1a 40 c0 00 .@@..........@.. | 1936: 00 40 e0 00 00 40 40 00 00 40 80 00 00 00 00 00 .@...@@..@...... | 1952: 00 00 00 05 7e 40 c0 00 00 40 e0 00 00 40 80 00 ....~@...@...@.. | 1968: 00 40 a0 00 00 00 00 00 00 00 00 05 e2 40 c0 00 .@...........@.. | 1984: 00 40 e0 00 00 40 a0 00 00 40 c0 00 00 00 00 00 .@...@...@...... | 2000: 00 00 00 06 46 40 c0 00 00 40 e0 00 00 40 c0 00 ....F@...@...@.. | 2016: 00 40 e0 00 00 00 00 00 00 00 00 06 aa 40 c0 00 .@...........@.. | 2032: 00 40 e0 00 00 40 e0 00 00 41 00 00 00 00 00 00 .@...@...A...... | 2048: 00 00 00 07 0e 40 c0 00 00 40 e0 00 00 41 00 00 .....@...@...A.. | 2064: 00 41 10 00 00 00 00 00 00 00 00 03 ef 40 e0 00 .A...........@.. | 2080: 00 41 00 00 00 00 00 00 00 3f 80 00 00 00 00 00 .A.......?...... | 2096: 00 00 00 04 53 40 e0 00 00 41 00 00 00 3f 80 00 ....S@...A...?.. | 2112: 00 40 00 00 00 00 00 00 00 00 00 04 b7 40 e0 00 .@...........@.. | 2128: 00 41 00 00 00 40 00 00 00 40 40 00 00 00 00 00 .A...@...@@..... | 2144: 00 00 00 05 1b 40 e0 00 00 41 00 00 00 40 40 00 .....@...A...@@. | 2160: 00 40 80 00 00 00 00 00 00 00 00 05 7f 40 e0 00 .@...........@.. | 2176: 00 41 00 00 00 40 80 00 00 40 a0 00 00 00 00 00 .A...@...@...... | 2192: 00 00 00 05 e3 40 e0 00 00 41 00 00 00 40 a0 00 .....@...A...@.. | 2208: 00 40 c0 00 00 00 00 00 00 00 00 06 47 40 e0 00 .@..........G@.. | 2224: 00 41 00 00 00 40 c0 00 00 40 e0 00 00 00 00 00 .A...@...@...... | 2240: 00 00 00 06 ab 40 e0 00 00 41 00 00 00 40 e0 00 .....@...A...@.. | 2256: 00 41 00 00 00 00 00 00 00 00 00 07 0f 40 e0 00 .A...........@.. | 2272: 00 41 00 00 00 41 00 00 00 41 10 00 00 00 00 00 .A...A...A...... | 2288: 00 00 00 07 73 40 e0 00 00 41 00 00 00 41 10 00 ....s@...A...A.. | 2304: 00 41 20 00 00 00 00 00 00 00 00 00 00 00 00 00 .A ............. | 2848: 00 00 00 00 00 00 00 00 00 00 00 00 00 89 50 04 ..............P. | 2864: 04 00 93 24 00 00 00 18 00 00 00 00 00 00 06 43 ...$...........C | 2880: 40 40 00 00 40 80 00 00 40 c0 00 00 40 e0 00 00 @@..@...@...@... | 2896: 00 00 00 00 00 00 06 42 40 00 00 00 40 40 00 00 .......B@...@@.. | 2912: 40 c0 00 00 40 e0 00 00 00 00 00 00 00 00 06 41 @...@..........A | 2928: 3f 80 00 00 40 00 00 00 40 c0 00 00 40 e0 00 00 ?...@...@...@... | 2944: 00 00 00 00 00 00 06 40 00 00 00 00 3f 80 00 00 .......@....?... | 2960: 40 c0 00 00 40 e0 00 00 00 00 00 00 00 00 06 44 @...@..........D | 2976: 40 80 00 00 40 a0 00 00 40 c0 00 00 40 e0 00 00 @...@...@...@... | 2992: 00 00 00 00 00 00 06 a7 40 40 00 00 40 80 00 00 ........@@..@... | 3008: 40 e0 00 00 41 00 00 00 00 00 00 00 00 00 06 a6 @...A........... | 3024: 40 00 00 00 40 40 00 00 40 e0 00 00 41 00 00 00 @...@@..@...A... | 3040: 00 00 00 00 00 00 06 a5 3f 80 00 00 40 00 00 00 ........?...@... | 3056: 40 e0 00 00 41 00 00 00 00 00 00 00 00 00 06 a4 @...A........... | 3072: 00 00 00 00 3f 80 00 00 40 e0 00 00 41 00 00 00 ....?...@...A... | 3088: 00 00 00 00 00 00 06 a8 40 80 00 00 40 a0 00 00 ........@...@... | 3104: 40 e0 00 00 41 00 00 00 00 00 00 00 00 00 07 0a @...A........... | 3120: 40 00 00 00 40 40 00 00 41 00 00 00 41 10 00 00 @...@@..A...A... | 3136: 00 00 00 00 00 00 07 09 3f 80 00 00 40 00 00 00 ........?...@... | 3152: 41 00 00 00 41 10 00 00 00 00 00 00 00 00 07 08 A...A........... | 3168: 00 00 00 00 3f 80 00 00 41 00 00 00 41 10 00 00 ....?...A...A... | 3184: 00 00 00 00 00 00 07 0b 40 40 00 00 40 80 00 00 ........@@..@... | 3200: 41 00 00 00 41 10 00 00 00 00 00 00 00 00 07 0c A...A........... | 3216: 40 80 00 00 40 a0 00 00 41 00 00 00 41 10 00 00 @...@...A...A... | 3232: 00 00 00 00 00 00 07 6e 40 00 00 00 40 40 00 00 .......n@...@@.. | 3248: 41 10 00 00 41 20 00 00 00 00 00 00 00 00 07 6d A...A .........m | 3264: 3f 80 00 00 40 00 00 00 41 10 00 00 41 20 00 00 ?...@...A...A .. | 3280: 00 00 00 00 00 00 07 6c 00 00 00 00 3f 80 00 00 .......l....?... | 3296: 41 10 00 00 41 20 00 00 00 00 00 00 00 00 07 6f A...A .........o | 3312: 40 40 00 00 40 80 00 00 41 10 00 00 41 20 00 00 @@..@...A...A .. | 3328: 00 00 00 00 00 00 07 70 40 80 00 00 40 a0 00 00 .......p@...@... | 3344: 41 10 00 00 41 20 00 00 00 00 00 00 00 00 07 71 A...A .........q | 3360: 40 a0 00 00 40 c0 00 00 41 10 00 00 41 20 00 00 @...@...A...A .. | 3376: 00 00 00 00 00 00 07 72 40 c0 00 00 40 e0 00 00 .......r@...@... | 3392: 41 10 00 00 41 20 00 00 00 00 00 00 00 00 07 74 A...A .........t | 3408: 41 00 00 00 41 10 00 00 41 10 00 00 41 20 00 00 A...A...A...A .. | 3424: 00 00 00 00 00 00 07 75 41 10 00 00 41 20 00 00 .......uA...A .. | 3440: 41 10 00 00 41 20 00 00 00 00 00 00 00 00 00 00 A...A .......... | end c1b.db }] catchsql { PRAGMA writable_schema = 1; SELECT rtreecheck('t1'); } } {1 {SQL logic error}} do_test rtreefuzz001-200 { sqlite3 db {} db deserialize [decode_hexdb { | size 16384 pagesize 4096 filename c3.db | page 1 offset 0 | 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3. | 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 04 .....@ ........ | 32: 00 00 00 00 01 00 00 00 00 00 00 04 00 00 00 04 ................ | 48: 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 ................ | 96: 00 00 00 00 0d 00 00 00 04 0e 9c 00 0f ad 0f 4f ...............O | 112: 0e fc 0e 9c 00 00 00 00 00 00 00 00 00 00 00 00 ................ | 3728: 00 00 00 00 00 00 00 00 00 00 00 00 5e 04 07 17 ............^... | 3744: 1f 1f 01 81 0b 74 61 62 6c 65 74 31 5f 70 61 72 .....tablet1_par | 3760: 65 6e 74 74 31 5f 70 61 72 65 6e 74 04 43 52 45 entt1_parent.CRE | 3776: 41 54 45 20 54 41 42 4c 45 20 22 74 31 5f 70 61 ATE TABLE .t1_pa | 3792: 72 65 6e 74 22 28 6e 6f 64 65 6e 6f 20 49 4e 54 rent.(nodeno INT | 3808: 45 47 45 52 20 50 52 49 4d 41 52 59 20 4b 45 59 EGER PRIMARY KEY | 3824: 2c 70 61 72 65 6e 74 6e 6f 64 65 29 51 03 06 17 ,parentnode)Q... | 3840: 1b 1b 01 7b 74 61 62 6c 65 74 31 5f 6e 6f 64 65 ....tablet1_node | 3856: 74 31 5f 6e 6f 64 65 03 43 52 45 41 54 45 20 54 t1_node.CREATE T | 3872: 41 42 4c 45 20 22 74 31 5f 6e 6f 64 65 22 28 6e ABLE .t1_node.(n | 3888: 6f 64 65 6e 6f 20 49 4e 54 45 47 45 52 20 50 52 odeno INTEGER PR | 3904: 49 4d 41 52 59 20 4b 45 59 2c 64 61 74 61 29 5c IMARY KEY,data). | 3920: 02 07 17 1d 1d 01 81 0b 74 61 62 6c 65 74 31 5f ........tablet1_ | 3936: 72 6f 77 69 64 74 31 5f 72 6f 77 69 64 02 43 52 rowidt1_rowid.CR | 3952: 45 41 54 45 20 54 41 42 4c 45 20 22 74 31 5f 72 EATE TABLE .t1_r | 3968: 6f 77 69 64 22 28 72 6f 77 69 64 20 49 4e 54 45 owid.(rowid INTE | 3984: 47 45 52 20 50 52 49 4d 41 52 59 20 4b 45 59 2c GER PRIMARY KEY, | 4000: 6e 6f 64 65 6e 6f 2c 61 30 2c 61 31 29 51 01 07 nodeno,a0,a1)Q.. | 4016: 17 11 11 08 81 0f 74 61 62 6c 65 74 31 74 31 43 ......tablet1t1C | 4032: 52 45 41 54 45 20 56 49 52 54 55 41 4c 20 54 41 REATE VIRTUAL TA | 4048: 42 4c 45 20 74 31 20 55 53 49 4e 47 20 72 74 72 BLE t1 USING rtr | 4064: 65 65 28 69 64 2c 78 30 2c 78 31 2c 79 30 2c 79 ee(id,x0,x1,y0,y | 4080: 31 2c 2b 6c 61 62 65 6c 2c 2b 6f 74 68 65 72 29 1,+label,+other) | page 2 offset 4096 | 0: 0d 00 00 00 0e 0e f7 00 0f e8 0f d0 0f b7 0f 9e ................ | 16: 0f 91 0f 81 0f 70 0f 5e 0f 4f 0f 39 0f 29 0f 18 .....p.^.O.9.).. | 32: 0f 06 0e f7 00 00 00 00 00 00 00 00 00 00 00 00 ................ | 3824: 00 00 00 00 00 00 00 0d 0e 05 00 09 1d 00 74 6f ..............to | 3840: 70 20 68 61 6c 66 10 0d 05 00 09 23 00 62 6f 74 p half.....#.bot | 3856: 74 6f 6d 20 68 61 6c 66 0f 0c 05 00 09 21 00 72 tom half.....!.r | 3872: 69 67 68 74 20 68 61 6c 66 0e 0b 05 00 09 1f 00 ight half....... | 3888: 6c 65 66 74 20 68 61 6c 66 14 0a 05 00 09 2b 00 left half.....+. | 3904: 74 68 65 20 77 68 6f 6c 65 20 74 68 69 6e 67 0d the whole thing. | 3920: 09 05 00 09 1d 00 74 6f 70 20 65 64 67 65 10 08 ......top edge.. | 3936: 05 00 09 23 00 62 6f 74 74 6f 6d 20 65 64 67 65 ...#.bottom edge | 3952: 0f 07 05 00 09 21 00 72 69 67 68 74 20 65 64 67 .....!.right edg | 3968: 65 0e 06 05 00 09 1f 00 6c 65 66 74 20 65 64 67 e.......left edg | 3984: 65 0b 05 05 00 09 19 00 63 65 6e 74 65 72 17 04 e.......center.. | 4000: 05 00 09 31 00 75 70 70 65 72 2d 72 69 67 68 74 ...1.upper-right | 4016: 20 63 6f 72 6e 65 72 17 03 05 00 09 31 00 6c 6f corner.....1.lo | 4032: 77 65 72 2d 72 69 67 68 74 27 60 f6 32 6e 65 72 wer-right'`.2ner | 4048: 16 02 05 00 09 2f 00 75 70 70 65 72 2d 6c 65 66 ...../.upper-lef | 4064: 74 20 63 6f 72 6e 65 72 16 01 05 00 09 2f 00 6c t corner...../.l | 4080: 6f 77 65 72 2d 6c 65 66 74 20 63 6f 72 6e 65 72 ower-left corner | page 3 offset 8192 | 0: 0d 00 00 00 02 0b 2d 00 0b 2d 00 00 00 00 00 00 ......-..-...... | 2848: 00 00 00 00 00 00 00 00 00 00 00 00 00 89 50 01 ..............P. | 2864: 04 00 93 24 00 00 00 0e 00 00 00 00 00 00 00 01 ...$............ | 2880: 00 00 00 00 41 20 00 00 00 00 00 00 41 20 01 00 ....A ......A .. | 2896: 00 00 00 00 00 00 00 02 00 00 00 00 41 00 00 04 ............A... | 2912: 2b 40 00 0c 42 c8 00 00 00 00 00 00 00 00 00 03 +@..B........... | 2928: 42 b4 00 00 42 c8 00 00 00 00 00 00 41 20 00 00 B...B.......A .. | 2944: 00 00 00 00 00 00 00 04 42 b4 00 00 42 c8 00 00 ........B...B... | 2960: 42 b4 00 00 42 c8 00 00 00 00 00 00 00 00 00 05 B...B........... | 2976: 42 20 00 00 42 70 00 00 42 20 00 00 42 70 00 00 B ..Bp..B ..Bp.. | 2992: 00 00 00 00 00 00 00 60 00 00 00 04 0a 00 00 00 .......`........ | 3008: 00 00 00 42 c8 00 00 00 00 00 00 00 00 00 07 42 ...B...........B | 3024: be 00 00 42 c8 00 00 00 00 00 00 42 c8 00 00 00 ...B.......B.... | 3040: 00 00 00 00 00 00 08 00 00 00 00 42 c8 00 00 00 ...........B.... | 3056: 00 00 00 40 a0 00 00 00 00 00 00 00 00 00 09 00 ...@............ | 3072: 00 00 00 42 c8 00 00 42 be 00 00 42 c8 00 00 00 ...B...B...B.... | 3088: 00 00 00 00 00 00 0a 00 00 00 00 42 c8 00 00 00 ...........B.... | 3104: 00 00 00 42 c8 00 00 00 00 00 00 00 00 00 0b 00 ...B............ | 3120: 00 00 00 42 48 00 00 00 00 00 04 2c 80 00 00 00 ...BH......,.... | 3136: 00 00 00 00 00 00 c4 24 c0 00 04 2c 80 00 00 00 .......$...,.... | 3152: 00 00 04 2c 80 00 00 00 00 00 00 00 00 00 d0 00 ...,............ | 3168: 00 00 04 2c 80 00 00 00 00 00 04 24 80 00 00 00 ...,.......$.... | 3184: 00 00 00 00 00 00 e0 00 00 00 04 2c 80 00 04 24 ...........,...$ | 3200: c0 00 04 2c 00 00 00 00 00 00 00 00 00 00 00 00 ...,............ | page 4 offset 12288 | 0: 0d 00 00 00 00 10 00 00 00 00 00 00 00 00 00 00 ................ | end c3.db }] catchsql { WITH RECURSIVE c1(x) AS (VALUES(0) UNION ALL SELECT x+1 FROM c1 WHERE x<99), c2(y) AS (VALUES(0) UNION ALL SELECT y+1 FROM c2 WHERE y<99) INSERT INTO t1(id, x0,x1,y0,y1,label) SELECT 1000+x+y*100, x, x+1, y, y+1, printf('box-%d,%d',x,y) FROM c1, c2; } } {1 {database disk image is malformed}} do_test rtreefuzz001-210 { catchsql { SELECT rtreecheck('t1'); } } {/1 .*corrupt.*/} do_test rtreefuzz001-300 { sqlite3 db {} db deserialize [decode_hexdb { | size 16384 pagesize 4096 filename c4.db | page 1 offset 0 | 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3. | 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 04 .....@ ........ | 32: 00 00 00 00 00 00 00 00 00 00 00 04 00 00 00 04 ................ | 96: 00 00 00 00 0d 00 00 00 04 0e 9c 00 0f ad 0f 4f ...............O | 112: 0e fc 0e 9c 00 00 00 00 00 00 00 00 00 00 00 00 ................ | 3728: 00 00 00 00 00 00 00 00 00 00 00 00 5e 04 07 17 ............^... | 3744: 1f 1f 01 81 0b 74 61 62 6c 65 74 31 5f 70 61 72 .....tablet1_par | 3760: 65 6e 74 74 31 5f 70 61 72 65 6e 74 04 43 52 45 entt1_parent.CRE | 3776: 41 54 45 20 54 41 42 4c 45 20 22 74 31 5f 70 61 ATE TABLE .t1_pa | 3792: 72 65 6e 74 22 28 6e 6f 64 65 6e 6f 20 49 4e 54 rent.(nodeno INT | 3808: 45 47 45 52 20 50 52 49 4d 41 52 59 20 4b 45 59 EGER PRIMARY KEY | 3824: 2c 70 61 72 65 6e 74 6e 6f 64 65 29 51 03 06 17 ,parentnode)Q... | 3840: 1b 1b 01 7b 74 61 62 6c 65 74 31 5f 6e 6f 64 65 ....tablet1_node | 3856: 74 31 5f 6e 6f 64 65 03 43 52 45 41 54 45 20 54 t1_node.CREATE T | 3872: 41 42 4c 45 20 22 74 31 5f 6e 6f 64 65 22 28 6e ABLE .t1_node.(n | 3888: 6f 64 65 6e 6f 20 49 4e 54 45 47 45 52 20 50 52 odeno INTEGER PR | 3904: 49 4d 41 52 59 20 4b 45 59 2c 64 61 74 61 29 5c IMARY KEY,data). | 3920: 02 07 17 1d 1d 01 81 0b 74 61 62 6c 65 74 31 5f ........tablet1_ | 3936: 72 6f 77 69 64 74 31 5f 72 6f 77 69 64 02 43 52 rowidt1_rowid.CR | 3952: 45 41 54 45 20 54 41 42 4c 45 20 22 74 31 5f 72 EATE TABLE .t1_r | 3968: 6f 77 69 64 22 28 72 6f 77 69 64 20 49 4e 54 45 owid.(rowid INTE | 3984: 47 45 72 20 50 52 49 4d 41 52 59 20 4b 45 59 2c GEr PRIMARY KEY, | 4000: 6e 6f 64 65 6e 6f 2c 61 30 2c 61 31 29 51 01 07 nodeno,a0,a1)Q.. | 4016: 17 11 11 08 81 0f 74 61 62 6c 65 74 31 74 31 43 ......tablet1t1C | 4032: 52 45 41 54 45 20 56 49 52 54 55 41 4c 20 54 41 REATE VIRTUAL TA | 4048: 42 4c 45 20 74 31 20 55 53 49 4e 47 20 72 74 72 BLE t1 USING rtr | 4064: 65 65 28 69 64 2c 78 30 2c 78 31 2c 79 30 2c 79 ee(id,x0,x1,y0,y | 4080: 31 2c 2b 6c 61 62 65 6c 2c 2b 6f 74 68 65 72 29 1,+label,+other) | page 2 offset 4096 | 0: 0d 00 00 00 0e 0e f7 00 0f e8 0f 00 fb 70 f9 e0 .............p.. | 16: f9 10 f8 10 f7 00 f5 e0 f4 f0 f3 90 f2 90 f1 80 ................ | 32: f0 60 ef 00 00 00 00 00 00 00 00 00 00 00 00 00 .`.............. | 3824: 00 00 00 00 00 00 00 0d 0e 05 00 09 1d 00 74 6f ..............to | 3840: 70 20 68 61 6c 66 10 0d 05 00 09 23 00 62 6f 74 p half.....#.bot | 3856: 74 6f 6d 20 68 61 6c 66 0f 0c 05 00 09 21 00 72 tom half.....!.r | 3872: 69 67 68 74 20 68 61 6c 66 0e 0b 05 00 09 1f 00 ight half....... | 3888: 6c 65 66 74 20 68 61 6c 66 14 0a 05 00 09 2b 00 left half.....+. | 3904: 00 03 98 20 49 98 2f 6c 62 05 74 68 69 6e 67 0d ... I./lb.thing. | 3920: 09 05 00 09 1d 00 74 6f 70 20 65 64 67 65 10 08 ......top edge.. | 3936: 05 00 09 23 00 62 6f 74 74 6f 6d 20 65 64 67 65 ...#.bottom edge | 3952: 0f 07 05 00 09 21 00 72 69 67 68 74 20 65 64 67 .....!.right edg | 3968: 65 0e 06 05 00 09 1f 00 6c 65 66 74 20 65 64 67 e.......left edg | 3984: 65 0b 05 05 00 09 19 00 63 65 6e 74 65 72 17 04 e.......center.. | 4000: 05 00 09 31 00 75 70 70 65 72 2d 72 69 67 68 74 ...1.upper-right | 4016: 20 63 6f 72 6e 65 72 17 03 05 00 09 31 00 6c 6f corner.....1.lo | 4032: 77 65 72 2d 72 69 67 68 74 20 63 6f 72 6e 65 72 wer-right corner | 4048: 16 02 05 00 09 2f 00 75 70 70 65 72 2d 6c 65 66 ...../.upper-lef | 4064: 74 20 63 6f 72 6e 65 72 16 01 05 00 09 2f 00 6c t corner...../.l | 4080: 6f 77 65 72 2d 6c 65 66 74 20 63 6f 72 6e 65 72 ower-left corner | page 3 offset 8192 | 0: 0d 00 00 00 01 0b 2d 00 0b 2d 00 00 00 00 00 00 ......-..-...... | 2848: 00 00 00 00 00 00 00 00 00 00 00 00 00 89 50 01 ..............P. | 2864: 04 00 93 24 00 00 00 0e 00 00 00 00 00 00 00 01 ...$............ | 2880: 00 00 00 04 01 20 00 00 00 00 00 04 12 00 00 00 ..... .......... | 2896: 00 00 00 00 00 00 00 23 00 00 00 00 41 20 00 00 .......#....A .. | 2912: 42 b4 00 00 42 c8 00 00 00 00 00 00 00 00 00 03 B...B........... | 2928: 42 b4 00 00 42 c8 00 00 00 00 00 00 41 20 00 00 B...B.......A .. | 2944: 00 00 00 00 00 00 00 04 42 b4 00 00 42 c8 00 00 ........B...B... | 2960: 42 b4 00 00 42 c8 00 00 00 00 00 00 00 00 00 05 B...B........... | 2976: 42 20 00 00 42 70 00 00 42 20 00 00 42 70 00 00 B ..Bp..B ..Bp.. | 2992: 00 00 00 00 00 00 00 06 00 00 00 00 40 a0 00 00 ............@... | 3008: 00 00 00 04 2c 80 00 00 00 00 00 00 00 00 00 74 ....,..........t | 3024: 2b e0 00 04 2c 80 00 04 2c 80 00 00 00 00 00 00 +...,...,....... | 3040: 00 00 00 80 00 00 00 04 2c 80 00 00 00 00 00 04 ........,....... | 3056: 0a 00 00 00 00 00 b0 80 00 00 04 2c 80 00 04 2b ...........,...+ | 3072: e0 00 04 2c 80 00 00 00 00 00 00 00 00 00 a0 00 ...,............ | 3088: 00 00 04 2c 80 00 00 00 00 00 04 2c 80 00 00 00 ...,.......,.... | 3104: 00 00 00 00 00 00 b0 00 00 00 04 24 80 00 00 00 ...........$.... | 3120: 00 00 04 2c 80 00 00 00 00 00 00 00 50 00 91 f0 ...,........P... | 3136: 06 c6 56 67 42 06 86 16 c6 61 40 a0 50 00 92 b0 ..VgB....a@.P... | 3152: 07 46 86 52 07 76 86 f6 c6 52 07 46 86 96 e6 70 .F.R.v...R.F...p | 3168: d0 90 50 00 91 d0 07 46 f7 02 06 56 46 76 51 00 ..P....F...VFvQ. | 3184: 80 50 00 92 30 06 26 f7 47 46 f6 d2 06 56 46 76 .P..0.&.GF...VFv | 3200: 50 f0 70 50 00 92 10 07 26 96 76 87 42 06 56 46 P.pP....&.v.B.VF | 3216: 76 50 e0 60 50 00 91 f0 06 c6 56 67 42 06 56 46 vP.`P.....VgB.VF | 3232: 76 50 b0 50 50 00 91 90 06 36 56 e7 46 57 21 70 vP.PP....6V.FW!p | 3248: 40 50 00 93 10 07 57 07 06 57 22 d7 26 96 76 87 @P....W..W..&.v. | 3264: 42 06 36 f7 26 e6 57 21 70 30 50 00 93 10 06 c6 B.6.&.W!p0P..... | 3280: f7 76 57 22 d7 26 96 76 87 42 06 36 f7 26 e6 57 .vW..&.v.B.6.&.W | 3296: 21 60 20 50 00 92 f0 07 57 07 06 57 22 d6 c6 56 !` P....W..W...V | 3312: 60 00 00 c4 24 c0 00 04 2c 80 00 00 00 00 00 04 `...$...,....... | 3328: 2c 80 00 00 00 00 00 00 00 00 00 d0 00 00 00 04 ,............... | 3344: 2c 80 00 00 00 00 00 04 24 80 00 00 00 00 00 00 ,.......$....... | 3360: 00 00 00 e0 00 00 00 04 2c 80 00 04 24 c0 00 04 ........,...$... | 3376: 2c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ,............... | page 4 offset 12288 | 0: 0d 00 00 00 00 10 00 00 00 00 00 00 00 00 00 00 ................ | end c4.db }] catchsql { UPDATE t1 SET label='x'; } } {1 {rtree constraint failed: t1.(y0<=y1)}} do_test rtreefuzz001-310 { catchsql { SELECT rtreecheck('t1'); } } {/1 .*corrupt.*/} do_test rtreefuzz001-400 { sqlite3 db {} db deserialize [decode_hexdb { | size 16384 pagesize 4096 filename c7.db | page 1 offset 0 | 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3. | 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 04 .....@ ........ | 32: 00 00 00 00 01 00 00 00 00 00 00 04 00 00 00 04 ................ | 48: 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 ................ | 96: 00 00 00 00 0d 00 00 00 04 0e 9c 00 0f ad 0f 4f ...............O | 112: 0e fc 0e 9c 00 00 00 00 00 00 00 00 00 00 00 00 ................ | 3728: 00 00 00 00 00 00 00 00 00 00 00 00 5e 04 07 17 ............^... | 3744: 1f 1f 01 81 0b 74 61 62 6c 65 74 31 5f 70 61 72 .....tablet1_par | 3760: 65 6e 74 74 31 5f 70 61 72 65 6e 74 04 43 52 45 entt1_parent.CRE | 3776: 41 54 45 20 54 41 42 4c 45 20 22 74 31 5f 70 61 ATE TABLE .t1_pa | 3792: 72 65 6e 74 22 28 6e 6f 64 65 6e 6f 20 49 4e 54 rent.(nodeno INT | 3808: 45 47 45 52 20 50 52 49 4d 41 52 59 20 4b 45 59 EGER PRIMARY KEY | 3824: 2c 70 61 72 65 6e 74 6e 6f 64 65 29 51 03 06 17 ,parentnode)Q... | 3840: 1b 1b 01 7b 74 61 62 6c 65 74 31 5f 6e 6f 64 65 ....tablet1_node | 3856: 74 31 5f 6e 6f 64 65 03 43 52 45 41 54 45 20 54 t1_node.CREATE T | 3872: 41 42 4c 45 20 22 74 31 5f 6e 6f 64 65 22 28 6e ABLE .t1_node.(n | 3888: 6f 64 65 6e 6f 20 49 4e 54 45 47 45 52 20 50 52 odeno INTEGER PR | 3904: 49 4d 41 52 59 20 4b 45 59 2c 64 61 74 61 29 5c IMARY KEY,data). | 3920: 02 07 17 1d 1d 01 81 0b 74 61 62 6c 65 74 31 5f ........tablet1_ | 3936: 72 6f 77 69 64 74 31 5f 72 6f 77 69 64 02 43 52 rowidt1_rowid.CR | 3952: 45 41 54 45 20 54 41 42 4c 45 20 22 74 31 5f 72 EATE TABLE .t1_r | 3968: 6f 77 69 64 22 28 72 6f 77 69 64 20 49 4e 54 45 owid.(rowid INTE | 3984: 47 45 52 20 50 52 49 4d 41 52 59 20 4b 45 59 2c GER PRIMARY KEY, | 4000: 6e 6f 64 65 6e 6f 2c 61 30 2c 61 31 29 51 01 07 nodeno,a0,a1)Q.. | 4016: 17 11 11 08 81 0f 74 61 62 6c 65 74 31 74 31 43 ......tablet1t1C | 4032: 52 45 41 54 45 20 56 49 52 54 55 41 4c 20 54 41 REATE VIRTUAL TA | 4048: 42 4c 45 20 74 31 20 55 53 49 4e 47 20 72 74 72 BLE t1 USING rtr | 4064: 65 65 28 69 64 2c 78 30 2c 78 31 2c 79 30 2c 79 ee(id,x0,x1,y0,y | 4080: 31 2c 2b 6c 61 62 65 6c 2c 2b 6f 74 68 65 72 29 1,+label,+other) | page 2 offset 4096 | 0: 0d 00 00 00 0e 0e f7 00 0f e8 0f d0 0f b7 0f 9e ................ | 16: 0f 91 0f 81 0f 70 0f 5e 0f 4f 0f 39 0f 29 0f 18 .....p.^.O.9.).. | 32: 0f 06 0e f7 00 00 00 00 00 00 00 00 00 00 00 00 ................ | 3824: 00 00 00 00 00 00 00 0d 0e 05 00 09 1d 00 74 6f ..............to | 3840: 70 20 68 61 6c 66 10 0d 05 00 09 23 00 62 6f 74 p half.....#.bot | 3856: 74 6f 6d 20 68 61 6c 66 0f 0c 05 00 09 21 00 72 tom half.....!.r | 3872: 69 67 68 74 20 68 61 6c 66 0e 0b 05 00 09 1f 00 ight half....... | 3888: 6c 65 66 74 20 68 61 6c 66 14 0a 05 00 09 2b 00 left half.....+. | 3904: 74 68 65 20 77 68 6f 6c 65 20 74 68 69 6e 67 0d the whole thing. | 3920: 09 05 00 09 1d 00 74 6f 70 20 65 64 67 65 10 08 ......top edge.. | 3936: 05 00 09 23 00 62 6f 74 74 6f 6d 20 65 64 67 65 ...#.bottom edge | 3952: 0f 07 05 00 09 21 00 72 69 67 68 74 20 65 64 67 .....!.right edg | 3968: 65 0e 06 05 00 09 1f 00 6c 65 66 74 20 65 64 67 e.......left edg | 3984: 65 0b 05 05 00 09 19 00 23 65 6e 74 65 72 17 04 e.......#enter.. | 4000: 05 00 09 31 00 75 70 70 65 72 2d 72 69 67 68 74 ...1.upper-right | 4016: 20 63 6f 72 6e 65 72 17 03 05 00 09 31 00 6c 6f corner.....1.lo | 4032: 77 65 72 2d 72 69 67 68 74 20 63 6f 72 6e 65 72 wer-right corner | 4048: 16 02 05 00 09 2f 00 75 70 70 65 72 2d 6c 65 66 ...../.upper-lef | 4064: 74 20 63 6f 72 6e 65 72 16 01 05 00 09 2f 00 6c t corner...../.l | 4080: 6f 77 65 72 2d 6c 65 66 74 20 63 6f 72 6e 65 72 ower-left corner | page 3 offset 8192 | 0: 0d 00 00 00 02 0b 2d 00 0b 2d 00 00 00 00 00 00 ......-..-...... | 2848: 00 00 00 00 00 00 00 00 00 00 00 00 00 89 50 01 ..............P. | 2864: 04 00 93 24 00 00 00 00 00 00 00 00 08 00 00 00 ...$............ | 2880: 00 42 c8 00 00 00 00 00 00 40 a0 00 00 00 00 00 .B.......@...... | 2896: 00 00 00 00 42 c8 00 00 00 00 00 00 00 00 00 07 ....B........... | 2912: 42 be 00 00 42 c8 00 00 00 00 00 00 42 c8 00 00 B...B.......B... | 2928: 00 00 00 00 00 00 00 08 00 00 00 00 42 c8 00 00 ............B... | 2944: 00 00 00 00 40 a0 00 00 00 00 00 00 00 00 00 09 ....@........... | 2960: 00 00 00 00 42 c8 00 00 42 be 00 00 42 c8 00 00 ....B...B...B... | 2976: 00 00 00 00 00 00 00 0a 00 00 00 00 42 c8 00 00 ............B... | 2992: 00 00 00 00 42 c8 00 00 00 00 00 00 00 00 00 0b ....B........... | 3008: 00 00 00 00 42 48 00 00 00 00 00 04 2c 80 00 00 ....BH......,... | 3024: 00 00 00 00 00 00 00 c4 00 00 00 00 00 42 c8 00 .............B.. | 3040: 00 00 00 00 00 00 00 00 07 42 be 00 00 42 c8 00 .........B...B.. | 3056: 00 00 00 00 00 42 c8 00 00 00 00 00 00 00 00 00 .....B.......... | 3072: 08 00 00 00 00 42 c8 00 00 00 00 00 00 40 a0 00 .....B.......@.. | 3088: 00 00 00 00 00 00 00 00 09 00 00 00 00 42 c8 00 .............B.. | 3104: 00 42 be 00 00 42 c8 00 00 00 00 00 00 00 00 00 .B...B.......... | 3120: 0a 00 00 00 00 42 c8 00 00 00 00 00 00 42 c8 00 .....B.......B.. | 3136: 00 00 00 00 00 00 00 00 0b 00 00 00 00 42 48 00 .............BH. | 3152: 00 00 00 00 04 2c 80 00 00 00 00 00 00 00 00 00 .....,.......... | 3168: c4 24 c0 00 04 2c 80 00 00 00 00 00 04 2c 80 00 .$...,.......,.. | 3184: 00 00 00 00 00 00 00 00 d0 00 00 00 04 2c 80 00 .............,.. | 3200: 00 00 00 00 04 24 80 00 00 00 00 00 00 00 00 00 .....$.......... | 3216: e0 00 00 00 04 2c 80 00 04 24 c0 00 04 2c 00 00 .....,...$...,.. | page 4 offset 12288 | 0: 0d 00 00 00 00 10 00 00 00 00 00 00 0e 00 00 00 ................ | 16: 00 42 c8 00 00 42 4c 00 00 42 c8 00 00 00 00 00 .B...BL..B...... | 32: 00 00 00 0a 00 00 00 00 42 c8 00 00 00 00 00 00 ........B....... | 48: 42 c8 00 00 00 00 00 00 00 00 00 0b 00 00 00 00 B............... | 64: 42 48 00 00 00 00 00 04 2c 80 00 00 00 00 00 00 BH......,....... | 80: 00 00 00 c4 24 c0 00 04 2c 80 00 00 00 00 00 04 ....$...,....... | 96: 2c 80 00 00 00 00 00 00 00 00 00 d0 00 00 00 04 ,............... | 112: 2c 80 00 00 00 00 00 04 24 80 00 00 00 00 00 00 ,.......$....... | 128: 00 00 00 e0 00 00 00 04 2c 80 00 04 24 c0 00 04 ........,...$... | 144: 2c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ,............... | end c7.db }] catchsql { WITH RECURSIVE c1(x) AS (VALUES(0) UNION ALL SELECT x+1 FROM c1 WHERE x<8), c2(y) AS (VALUES(0) UNION ALL SELECT y+1 FROM c2 WHERE y<5) INSERT INTO t1(id, x0,x1,y0,y1,label) SELECT 1000+x+y*100, x, x+1, y, y+1, printf('box-%d,%d',x,y) FROM c1, c2; } } {1 {database disk image is malformed}} do_test rtreefuzz001-500 { sqlite3 db {} db deserialize [decode_hexdb { | size 16384 pagesize 4096 filename crash-2e81f5dce5cbd4.db | page 1 offset 0 | 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3. | 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 00 .....@ ........ | 96: 00 00 00 00 0d 00 00 00 05 0e 6d 00 0f c8 0f 7b ..........m..... | 112: 0f 20 0e cd 0e 6d 00 00 00 00 00 00 00 00 00 00 . ...m.......... | 3680: 00 00 00 00 00 00 00 00 00 00 00 00 00 5e 05 07 .............^.. | 3696: 17 1f 1f 01 81 0b 74 61 62 6c 65 74 31 5f 70 61 ......tablet1_pa | 3712: 72 65 6e 74 74 31 5f 70 61 72 65 6e 74 05 43 52 rentt1_parent.CR | 3728: 45 41 54 45 20 54 41 42 4c 45 20 22 74 31 5f 70 EATE TABLE .t1_p | 3744: 61 72 65 6e 74 22 28 6e 6f 64 65 6e 6f 20 49 4e arent.(nodeno IN | 3760: 54 45 47 45 42 20 50 52 49 4d 41 52 59 20 4b 45 TEGEB PRIMARY KE | 3776: 59 2c 70 61 72 65 6e 74 6e 6f 64 65 29 51 04 06 Y,parentnode)Q.. | 3792: 17 1b 1b 01 7b 74 61 62 6c 65 74 31 5f 6e 6f 64 .....tablet1_nod | 3808: 65 74 31 5f 6e 6f 64 65 04 43 52 45 41 54 45 20 et1_node.CREATE | 3824: 54 41 42 4c 45 20 22 74 31 5f 6e 6f 64 65 22 28 TABLE .t1_node.( | 3840: 6e 6f 64 65 6e 6f 20 49 4e 54 45 47 45 52 20 50 nodeno INTEGER P | 3856: 52 49 4d 41 52 59 20 4b 45 59 2c 64 61 74 61 29 RIMARY KEY,data) | 3872: 59 03 07 17 1d 1d 01 81 05 74 61 62 6c 65 84 31 Y........table.1 | 3888: 5f 72 6f 77 69 64 74 31 5f 72 6f 87 69 64 03 43 _rowidt1_ro.id.C | 3904: 52 45 41 54 45 20 54 41 42 4c 45 20 22 74 31 5f REATE TABLE .t1_ | 3920: 72 6f 77 69 64 22 28 72 6f 77 69 64 20 49 4e 54 rowid.(rowid INT | 3936: 45 47 45 52 20 50 52 49 4d 41 52 59 20 4b 45 59 EGER PRIMARY KEY | 3952: 2c 6e f8 64 65 6e 6f 2c 61 30 29 4b 02 07 17 11 ,n.deno,a0)K.... | 3968: 11 08 81 03 74 22 62 6c 65 74 31 74 31 43 52 45 ....t.blet1t1CRE | 3984: 41 54 45 20 56 49 52 54 55 41 4c 20 54 41 42 4c ATE VIRTUAL TABL | 4000: 45 20 74 31 20 55 53 49 4e 47 20 72 74 72 65 65 E t1 USING rtree | 4016: 5f 69 33 32 28 69 cc 2c 78 30 2c 78 31 2c 79 30 _i32(i.,x0,x1,y0 | 4032: 2c 79 31 2c 2b 65 78 29 36 01 06 17 17 17 01 4d ,y1,+ex)6......M | 4048: 74 61 62 6c 65 63 6f 6f 72 64 63 6f 6f 72 64 02 tablecoordcoord. | 4064: 43 52 45 41 54 45 20 54 41 42 4c 45 20 63 6f 6f CREATE TABLE coo | 4080: 71 64 28 76 20 49 4e 54 2c 20 77 20 49 4e 54 29 qd(v INT, w INT) | page 2 offset 4096 | 4016: 00 00 00 00 00 00 00 00 00 00 00 05 0a 03 01 01 ................ | 4032: 0a 02 05 09 03 01 01 09 02 05 08 03 01 01 08 02 ................ | 4048: 05 07 03 01 01 07 02 05 06 03 11 01 06 02 05 05 ................ | 4064: 03 01 01 05 02 05 04 03 01 01 04 02 05 03 03 01 ................ | 4080: 01 03 02 05 02 03 01 01 02 02 04 01 03 09 01 02 ................ | page 3 offset 8192 | 0: 0d 0e 4f 00 64 0b 5a 12 0d bb 0d 84 0f eb 0d c6 ..O.d.Z......... | 16: 0f d7 0e cc 0f c1 0f b6 0f ab 0f 9f 0f 94 0d 8f ................ | 32: 0f 86 0d d1 0f 62 0f 67 0f 5c 0f 51 1f 46 0f 3a .....b.g...Q.F.: | 48: 0f 30 0d 9a 0f 21 0d dc 0f 00 00 00 00 00 00 00 .0...!.......... | 2896: 00 00 00 00 00 00 00 00 00 00 0a ce 1a 04 00 01 ................ | 2912: 17 03 31 30 78 31 30 0a 4e 19 03 ff f1 15 03 31 ..10x10.N......1 | 2928: 30 78 39 09 ce 18 04 00 01 15 03 31 30 78 38 09 0x9........10x8. | 2944: ce 17 04 00 01 15 03 31 30 78 37 09 ce 16 04 00 .......10x7..... | 2960: 12 15 03 31 30 78 36 09 ce 15 04 00 01 15 03 31 ...10x6........1 | 2976: 30 78 35 09 ce 14 04 00 01 15 0d a1 30 78 34 09 0x5.........0x4. | 2992: ce 13 04 00 01 15 03 31 30 78 33 09 ce 12 04 00 .......10x3..... | 3008: 01 15 03 31 40 78 32 09 ce 11 04 00 01 15 03 31 ...1@x2........1 | 3024: 30 78 31 09 c6 32 04 00 01 15 03 39 78 31 30 08 0x1..2.....9x10. | 3040: c6 31 04 00 01 13 03 39 78 39 08 c6 30 04 00 01 .1.....9x9..0... | 3056: 13 03 39 78 38 08 c6 2f 04 00 01 14 03 39 78 37 ..9x8../.....9x7 | 3072: 08 c6 2e 04 00 01 13 03 39 78 36 08 c6 2d 04 00 ........9x6..-.. | 3088: 01 13 03 39 78 34 f8 c6 2c 04 00 01 13 03 39 78 ...9x4..,.....9x | 3104: 34 08 c6 2b 04 00 60 13 03 39 79 13 08 c6 2a 04 4..+..`..9y...*. | 3120: 00 11 13 03 39 78 32 08 c6 29 04 00 01 13 03 39 ....9x2..).....9 | 3136: 78 31 09 be 4a 04 00 01 15 03 38 78 31 30 08 be x1..J.....8x10.. | 3152: 49 04 00 01 13 03 38 78 39 08 be 48 04 00 01 13 I.....8x9..H.... | 3168: 03 38 77 98 08 be 47 04 00 01 14 23 38 78 37 08 .8w...G....#8x7. | 3184: be 46 04 00 01 13 03 38 78 36 08 be 45 04 00 01 .F.....8x6..E... | 3200: 13 03 38 78 35 08 be 44 04 00 01 13 03 38 78 34 ..8x5..D.....8x4 | 3216: 08 be 43 04 00 01 13 03 38 78 33 08 be 42 04 00 ..C.....8x3..B.. | 3232: 01 13 03 38 78 32 08 be 41 04 00 01 13 03 38 78 ...8x2..A.....8x | 3248: 31 09 b6 62 04 00 01 15 03 37 68 31 30 08 b6 61 1..b.....7h10..a | 3264: 04 00 01 13 03 37 79 39 08 b6 60 04 00 01 12 f3 .....7y9..`..... | 3280: 37 78 38 08 b6 5e 04 00 01 13 03 37 78 37 08 b6 7x8..^.....7x7.. | 3296: 5e 04 00 01 13 03 37 78 36 08 b6 5d 04 00 01 13 ^.....7x6..].... | 3312: 03 37 78 35 08 b6 5c 04 00 00 13 03 37 78 34 08 .7x5........7x4. | 3328: b6 5b 04 00 01 13 03 37 78 33 08 b6 5a 04 00 01 .[.....7x3..Z... | 3344: 13 03 37 78 32 08 b6 59 04 00 01 13 03 37 78 31 ..7x2..Y.....7x1 | 3360: 09 ae 7a 04 00 01 15 03 36 78 31 30 08 ae 79 04 ..z.....6x10..y. | 3376: 00 01 e2 03 36 78 39 08 ae 78 04 00 01 13 03 36 ....6x9..x.....6 | 3392: 78 38 08 ae 77 04 00 01 13 03 36 78 37 08 ae 76 x8..w.....6x7..v | 3408: 04 00 01 13 03 36 78 36 08 ae 85 04 00 01 13 03 .....6x6........ | 3424: 36 78 35 08 ae 73 f4 00 01 13 03 36 78 34 08 ae 6x5..s.....6x4.. | 3440: 73 04 00 01 13 03 36 78 33 08 ae 72 04 00 01 13 s.....6x3..r.... | 3456: 03 36 78 32 08 87 6a 04 00 01 13 02 3d e8 32 08 .6x2..j.....=.2. | 3472: 8f 52 04 00 01 13 02 32 78 32 08 97 3b 04 00 01 .R.....2x2..;... | 3488: 13 02 33 78 32 08 9f 22 04 00 01 13 02 34 78 32 ..3x2........4x2 | 3504: 08 a7 0a 04 00 01 13 02 35 78 32 08 87 69 04 00 ........5x2..i.. | 3520: 01 13 02 31 78 31 08 87 6c 04 00 01 13 02 31 78 ...1x1..l.....1x | 3536: 34 08 8f 54 04 00 01 13 02 32 78 34 08 97 3c 04 4..T.....2x4..<. | 3552: 00 01 12 f2 33 78 34 08 9f 24 04 00 01 13 02 34 ....3x4..$.....4 | 3568: 78 34 08 a7 0c 04 00 01 13 02 35 78 34 0e 6c 00 x4........5x4.l. | 3584: 08 ae 71 04 00 01 13 03 36 78 31 09 a7 12 04 00 ..q.....6x1..... | 3600: 01 15 02 35 78 31 30 08 a7 11 04 00 01 13 02 35 ...5x10........5 | 3616: 78 39 08 a7 10 04 00 01 13 02 35 78 38 08 a7 0f x9........5x8... | 3632: 04 00 01 14 02 35 78 37 08 a7 0e 04 00 01 13 02 .....5x7........ | 3648: 35 78 36 08 a7 0d 04 00 01 13 02 35 78 35 0e 0e 5x6........5x5.. | 3664: b3 00 08 00 01 00 03 08 a7 0b 04 00 01 13 02 35 ...............5 | 3680: 78 33 0e d1 00 08 a7 09 04 00 01 13 02 35 78 31 x3...........5x1 | 3696: 09 9f 2a 04 00 01 15 02 34 78 31 30 03 cf 29 04 ..*.....4x10..). | 3712: 00 01 13 02 34 78 39 08 9f 28 04 00 01 13 02 34 ....4x9..(.....4 | 3728: 78 38 09 9f 27 04 00 01 13 02 34 78 37 08 9f 26 x8..'.....4x7..& | 3744: 04 00 01 13 0e a4 78 36 08 9f 25 04 00 01 13 02 ......x6..%..... | 3760: 34 78 35 0f 18 00 09 00 09 13 34 78 08 9f 23 04 4x5.......4x..#. | 3776: 00 01 13 02 34 78 33 0f 36 00 08 9f 21 04 00 01 ....4x3.6...!... | 3792: 13 02 34 78 31 09 97 42 04 00 01 15 02 33 78 31 ..4x1..B.....3x1 | 3808: 30 08 97 41 04 00 01 13 02 33 78 39 08 97 40 04 0..A.....3x9..@. | 3824: 00 01 13 02 33 78 38 18 97 3f 04 00 01 13 02 33 ....3x8..?.....3 | 3840: 78 37 08 97 3e 04 00 01 13 02 33 78 36 08 97 3d x7..>.....3x6..= | 3856: 04 00 01 13 02 33 78 35 1f 7d 00 09 00 09 13 33 .....3x5.......3 | 3872: 78 07 97 3b 04 00 01 13 02 33 78 33 0f 9b 00 08 x..;.....3x3.... | 3888: 97 39 04 00 01 13 02 33 78 31 09 8f 5a 04 00 01 .9.....3x1..Z... | 3904: 15 02 32 79 31 30 08 8f 59 04 00 01 13 fa 32 78 ..2y10..Y.....2x | 3920: 39 08 8f 58 04 00 01 13 02 32 78 38 08 8f 57 04 9..X.....2x8..W. | 3936: 00 01 13 02 32 78 37 08 8f 56 04 00 01 13 02 32 ....2x7..V.....2 | 3952: 78 36 08 8f 55 04 00 01 13 02 32 78 35 0f e2 00 x6..U.....2x5... | 3968: 09 00 09 13 32 78 08 8f 53 04 00 01 13 02 32 78 ....2x..S.....2x | 3984: 33 00 00 00 08 8f 51 04 00 01 13 02 aa 78 31 09 3.....Q......x1. | 4000: 87 72 04 00 01 15 02 31 78 31 30 08 87 71 04 00 .r.....1x10..q.. | 4016: 01 13 03 31 78 39 08 87 70 04 00 01 13 02 31 78 ...1x9..p.....1x | 4032: 38 08 87 6f 04 00 01 13 02 31 78 37 08 87 6e 04 8..o.....1x7..n. | 4048: 00 01 13 02 31 78 36 08 87 6d 04 00 01 13 02 31 ....1x6..m.....1 | 4064: 7d 25 0f f9 00 08 ff f9 13 31 78 08 87 6b 04 00 .%.......1x..k.. | 4080: 01 13 02 31 78 33 00 00 00 00 00 08 00 01 00 03 ...1x3.......... | page 4 offset 12288 | 0: 0d 00 00 00 03 01 87 00 0b 2d 06 5a 01 87 00 00 .........-.Z.... | 384: 00 00 00 00 00 00 00 89 50 01 54 00 93 24 00 00 ........P.T..$.. | 400: 00 32 00 00 00 00 00 00 23 2f 00 00 00 09 00 00 .2......#/...... | 416: 00 0b 00 00 00 07 00 00 00 09 00 00 00 00 00 00 ................ | 432: 23 2e 00 00 10 09 00 00 00 0b 00 00 00 06 00 00 #............... | 448: 00 08 00 00 00 00 00 00 23 2d 00 00 00 09 00 00 ........#-...... | 464: 00 0b 00 00 00 05 00 00 00 07 00 00 00 00 00 00 ................ | 480: 23 2c 00 00 00 09 00 00 00 0b 00 00 00 04 00 00 #,.............. | 496: 00 06 00 00 00 00 00 00 23 2b 00 00 00 09 00 00 ........#+...... | 512: 00 0b 00 00 00 03 00 00 00 05 00 00 00 00 00 00 ................ | 528: 23 2a 00 00 00 09 00 00 00 0b 00 00 00 02 00 00 #*.............. | 544: 00 04 00 00 00 00 00 00 23 29 00 00 00 09 00 00 ........#)...... | 560: 00 0b 00 00 00 01 00 00 00 03 00 00 00 00 00 00 ................ | 576: 1f 4a 00 00 00 08 00 00 00 0a 00 00 00 0a 00 00 .J.............. | 592: 00 0c 00 00 00 00 00 00 0f 49 00 00 00 08 00 00 .........I...... | 608: 00 0a 00 00 00 09 00 00 00 0b 00 00 00 00 00 00 ................ | 624: 1f 48 00 00 00 08 00 00 00 0a 00 00 00 08 00 06 .H.............. | 640: 00 0a 00 00 00 00 00 00 1f 47 00 00 00 08 00 00 .........G...... | 656: 00 0a 00 00 00 07 00 00 00 09 00 00 00 00 00 00 ................ | 672: 15 d6 00 00 00 08 00 00 00 0a 00 00 00 06 00 00 ................ | 688: 00 08 00 00 00 00 00 00 1f 45 00 00 00 08 00 00 .........E...... | 704: 00 0a 00 00 00 05 00 00 00 07 00 00 00 00 00 00 ................ | 720: 1f 44 00 00 00 08 00 00 00 0a 00 00 00 04 00 00 .D.............. | 736: 00 06 00 00 00 00 00 00 1f 43 00 00 00 07 ff ff .........C...... | 752: f0 0a 00 00 00 03 00 00 00 05 00 00 00 00 00 00 ................ | 768: 1f 42 00 00 00 08 00 00 00 0a 00 00 00 01 ff f0 .B.............. | 784: 00 03 ff ff ff ff ff ff 1f 41 00 00 00 08 00 00 .........A...... | 800: 00 0a 00 00 00 01 00 00 00 03 00 00 00 00 00 00 ................ | 816: 1b 62 00 00 00 07 00 00 00 09 00 00 00 0a 00 00 .b.............. | 832: 00 0c 05 00 00 00 00 00 1b 64 10 00 00 07 00 00 .........d...... | 848: 00 09 00 00 00 09 00 00 00 0b 00 00 00 00 00 00 ................ | 864: 1b 60 00 00 00 07 00 00 00 09 00 00 00 08 00 00 .`.............. | 880: 00 0a 00 00 00 00 00 00 1b 5f 00 00 00 07 00 00 ........._...... | 896: 00 09 00 00 00 07 00 00 00 09 00 00 00 00 00 00 ................ | 912: 1b 5e 00 00 00 07 00 00 00 09 00 00 00 06 00 00 .^.............. | 928: 00 08 00 00 00 00 00 00 1b 5d 00 00 00 08 00 00 .........]...... | 944: 00 09 00 00 00 05 00 00 00 07 00 00 00 00 00 00 ................ | 960: 1b 5c 00 00 00 07 00 00 00 09 00 00 00 04 00 00 ................ | 976: 06 46 00 00 00 00 00 00 1b 5b 00 00 00 07 00 00 .F.......[...... | 992: 00 09 00 00 00 03 00 00 00 04 ff f0 00 00 00 00 ................ | 1008: 1b 5a 00 00 00 07 00 00 00 19 00 00 00 02 00 00 .Z.............. | 1024: 00 04 00 00 00 00 00 00 1b 59 00 00 00 07 00 00 .........Y...... | 1040: 00 09 00 00 00 01 00 00 00 03 00 00 00 00 ff f0 ................ | 1056: 17 7a 00 00 00 06 00 00 00 08 00 00 00 0a 00 00 .z.............. | 1072: 00 0c 00 00 00 00 00 00 17 79 00 00 00 06 00 00 .........y...... | 1088: 00 08 00 00 00 09 00 00 00 0b 00 00 00 00 00 00 ................ | 1104: 17 78 00 00 00 06 00 00 00 08 00 00 00 08 00 00 .x.............. | 1120: 00 0a 00 00 00 00 00 00 17 77 00 00 00 06 10 00 .........w...... | 1136: 00 08 00 00 00 07 00 09 c0 09 00 00 00 00 00 00 ................ | 1152: 17 76 00 00 00 06 00 00 00 08 00 00 00 06 00 00 .v.............. | 1168: 00 08 00 00 00 00 00 00 17 75 00 00 00 06 00 00 .........u...... | 1184: 00 08 00 00 00 05 00 00 00 07 00 00 00 00 00 00 ................ | 1200: 17 74 00 00 00 06 00 00 00 08 00 00 00 03 ff ff .t.............. | 1216: f0 06 00 00 00 83 00 00 17 73 00 00 00 06 00 00 .........s...... | 1232: 00 08 00 00 00 03 00 00 00 05 00 00 00 00 00 00 ................ | 1248: 17 71 ff 00 00 06 00 00 10 08 00 00 00 02 00 00 .q.............. | 1264: 00 04 00 00 c0 00 00 00 17 0d 00 00 00 06 00 00 ................ | 1280: 00 08 00 00 e7 01 00 00 00 03 00 00 09 e0 00 00 ................ | 1296: 23 30 00 00 00 09 00 00 00 0a 00 00 00 08 00 00 #0.............. | 1312: 00 0a 00 00 00 00 bb 00 23 31 00 00 00 09 00 00 ........#1...... | 1328: 00 0b 00 00 00 09 00 00 00 0b 00 00 00 00 00 00 ................ | 1344: 23 32 00 00 00 09 00 00 00 0b 00 00 00 0a 00 00 #2.............. | 1360: 00 0c 00 00 00 00 00 00 27 11 00 00 00 0a 00 00 ........'....... | 1376: 00 0c 00 00 00 01 00 08 c0 03 00 00 00 00 00 00 ................ | 1392: 27 12 00 00 00 0a 00 00 00 0c 51 00 00 02 00 00 '.........Q..... | 1408: 00 04 6f 00 00 00 00 00 27 13 00 00 00 09 ff ff ..o.....'....... | 1424: 00 0c 00 00 00 03 00 00 00 05 00 00 00 00 00 00 ................ | 1440: 27 14 00 00 00 0a 00 00 00 00 00 00 00 00 00 00 '............... | 1616: 00 00 00 00 00 00 00 00 00 00 89 50 02 04 00 93 ...........P.... | 1632: 24 00 00 00 32 00 00 00 00 00 00 23 8c 00 00 00 $...2......#.... | 1648: 05 00 00 00 07 00 00 00 04 00 00 00 06 00 00 00 ................ | 1664: 00 00 00 0f a4 00 00 00 04 00 00 00 06 00 00 00 ................ | 1680: 04 00 00 00 06 00 00 00 00 00 00 0b bc 00 00 00 ................ | 1696: 03 00 00 00 05 00 00 00 04 00 00 00 06 00 00 00 ................ | 1712: 00 00 00 07 d4 00 00 00 02 00 00 00 04 00 00 00 ................ | 1728: 04 00 00 00 06 00 00 00 10 00 00 03 ec 00 00 00 ................ | 1744: 01 00 00 00 03 00 00 00 04 00 00 00 06 00 00 00 ................ | 1760: 00 00 00 13 8d 00 00 00 05 00 00 00 07 00 00 00 ................ | 1776: 05 00 00 00 07 00 00 00 00 00 00 0f a5 00 00 00 ................ | 1792: 04 00 00 00 06 00 00 00 05 00 00 00 07 00 00 00 ................ | 1808: 00 00 00 0b bd 00 00 00 03 00 00 00 05 00 00 00 ................ | 1824: 05 00 00 00 07 00 00 00 00 00 00 07 d5 00 00 00 ................ | 1840: 02 00 00 00 05 00 00 00 05 00 00 00 07 00 00 00 ................ | 1856: 00 00 00 03 ed 00 00 00 01 00 00 00 03 00 00 00 ................ | 1872: 05 00 00 00 07 00 00 00 00 00 00 13 8e 00 00 00 ................ | 1888: 05 00 00 00 07 00 00 00 06 00 00 00 08 00 00 00 ................ | 1904: 00 00 00 0f a6 00 00 00 04 00 00 00 06 00 00 00 ................ | 1920: 06 00 00 00 07 ff ff 00 00 00 00 0b be 00 00 00 ................ | 1936: 0b 40 00 00 05 00 00 00 06 00 00 00 08 00 00 00 .@.............. | 1952: 00 00 00 07 d6 00 00 00 02 00 00 00 04 00 00 00 ................ | 1968: 05 00 00 00 08 00 00 00 00 00 00 03 ee 00 00 00 ................ | 1984: 01 00 00 00 02 ff ff 00 06 00 00 00 08 00 00 00 ................ | 2000: 00 00 00 13 8f 00 00 00 05 00 00 00 07 00 00 00 ................ | 2016: 07 00 00 00 09 00 00 00 00 00 00 0f a7 00 00 00 ................ | 2032: 04 00 00 00 06 00 00 00 07 00 00 00 09 00 00 08 ................ | 2048: 30 00 00 0b bf 00 00 00 03 00 00 00 05 00 00 00 0............... | 2064: 07 00 00 00 09 00 00 00 00 00 00 07 d7 00 00 00 ................ | 2080: 02 00 00 00 04 00 00 00 07 00 00 00 09 00 00 00 ................ | 2096: 00 00 00 03 ef 00 00 00 01 00 00 00 03 00 00 00 ................ | 2112: 07 00 00 00 09 00 00 00 00 00 00 13 90 00 00 00 ................ | 2128: 05 00 01 00 07 00 00 00 08 00 00 00 0a 00 00 00 ................ | 2144: 00 00 00 0f a8 00 00 00 04 00 00 00 06 00 00 00 ................ | 2160: 08 00 00 00 0a 00 00 00 00 00 00 0b f2 00 00 00 ................ | 2176: 03 00 00 00 05 00 00 00 08 00 00 00 0a 00 00 01 ................ | 2192: 00 00 00 07 d8 00 00 00 02 00 00 00 04 00 00 00 ................ | 2208: 08 00 00 00 0a 00 00 00 00 00 00 03 f0 00 00 00 ................ | 2224: 01 00 00 00 03 00 00 00 08 00 00 00 09 ff 00 00 ................ | 2240: 00 00 00 13 91 00 00 00 05 00 00 00 07 00 00 00 ................ | 2256: 09 00 00 00 0b 00 00 00 00 00 00 0f a9 00 00 00 ................ | 2272: 04 00 00 00 06 00 00 00 09 00 00 00 0b 00 00 00 ................ | 2288: 00 00 00 0b c1 00 00 00 03 00 00 00 05 00 00 00 ................ | 2304: 09 00 00 00 0b 00 00 00 00 00 00 07 d9 00 00 00 ................ | 2320: 02 00 00 00 04 00 00 00 09 00 00 00 0b 00 00 01 ................ | 2336: 00 00 00 03 f0 ff ff 00 01 00 00 00 03 00 00 00 ................ | 2352: 09 00 00 00 0b 00 00 00 00 00 00 13 92 00 00 00 ................ | 2368: 05 00 00 00 07 00 00 00 0a 00 00 00 0c 00 00 00 ................ | 2384: 00 00 00 0f aa 00 00 00 04 00 00 00 06 00 00 00 ................ | 2400: 0a 00 00 00 0c 00 00 00 00 00 00 0b c2 00 00 00 ................ | 2416: 03 00 00 00 05 00 00 00 0a 00 00 00 0c 00 00 00 ................ | 2432: 00 00 00 07 da 00 00 00 02 00 00 00 04 00 00 00 ................ | 2448: 0a 00 00 00 0c 00 00 00 00 00 00 03 f2 00 00 00 ................ | 2464: 01 00 00 10 03 00 00 00 0a 00 00 00 0c 00 00 00 ................ | 2480: 00 00 00 03 eb 00 00 00 01 00 00 00 03 00 00 00 ................ | 2496: 03 00 00 00 05 00 00 00 00 00 00 07 d3 00 00 00 ................ | 2512: 02 00 00 00 04 00 00 00 03 00 00 00 05 00 00 00 ................ | 2528: 00 00 00 0b bb 00 00 00 03 00 00 00 05 00 00 00 ................ | 2544: 03 00 00 00 05 00 00 00 00 00 00 0f a3 00 00 00 ................ | 2560: 04 00 00 00 06 00 00 00 03 00 00 00 05 00 00 00 ................ | 2576: 00 00 00 13 8b 00 00 00 05 00 00 00 07 00 00 00 ................ | 2592: 03 00 00 00 05 00 00 00 00 00 00 03 ea 00 00 00 ................ | 2608: 01 00 00 00 03 00 00 00 02 00 00 00 04 00 00 00 ................ | 2624: 00 00 00 07 d2 00 00 00 02 00 00 00 04 00 00 00 ................ | 2640: 02 00 00 00 04 00 00 00 00 00 00 0b ba 00 00 00 ................ | 2656: 03 00 00 00 05 00 00 00 02 00 00 00 04 00 00 00 ................ | 2672: 00 00 00 0f a1 ff ff ff 04 00 00 00 06 00 00 00 ................ | 2688: 02 00 00 00 04 00 00 00 00 00 00 13 8a 00 00 00 ................ | 2704: 05 00 00 00 06 ff ff ff f2 00 00 00 04 00 00 00 ................ | 2720: 00 00 00 03 e9 00 00 00 01 00 00 00 03 00 00 00 ................ | 2736: 01 00 00 00 03 00 00 00 00 00 00 07 d1 00 00 00 ................ | 2848: 00 00 00 00 00 00 00 00 00 00 00 00 00 89 50 01 ..............P. | 2864: 04 00 93 24 00 01 00 02 00 00 00 00 00 00 00 02 ...$............ | 2880: ff ff ff 06 00 00 00 0c 00 00 00 01 00 00 00 0b ................ | 2896: 00 00 00 00 00 00 00 02 40 00 00 00 00 00 00 00 ........@....... | end crash-2e81f5dce5cbd4.db}] execsql { PRAGMA writable_schema = 1;} catchsql {UPDATE t1 SET ex= ex ISNULL} } {1 {database disk image is malformed}} do_test rtreefuzz001-600 { sqlite3 db {} db deserialize [decode_hexdb { | size 20480 pagesize 4096 filename crash-7b37d80f000235.db | page 1 offset 0 | 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3. | 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 05 .....@ ........ | 32: 00 00 00 00 00 00 00 00 00 00 10 06 00 00 00 04 ................ | 96: 00 00 00 00 0d 00 00 00 05 0e 49 00 0f 99 0f 40 ..........I....@ | 112: 0e da 0e 8f 0e 49 00 00 00 00 00 00 00 00 00 00 .....I.......... | 3648: 00 00 00 00 00 00 00 00 00 44 05 06 17 15 15 08 .........D...... | 3664: 6f 74 61 62 6c 65 67 65 6f 31 67 65 6f 31 43 52 otablegeo1geo1CR | 3680: 45 41 54 45 20 56 49 52 54 55 41 4c 20 54 41 42 EATE VIRTUAL TAB | 3696: 4c 45 20 67 65 6f 31 20 55 53 49 4e 47 20 67 65 LE geo1 USING ge | 3712: 6f 70 6f 6c 79 28 74 79 70 65 2c 63 6c 72 29 49 opoly(type,clr)I | 3728: 04 06 17 1f 1f 01 63 74 61 62 6c 65 71 75 65 72 ......ctablequer | 3744: 79 70 6f 6c 79 71 75 65 72 79 70 6f 6c 79 05 43 ypolyquerypoly.C | 3760: 52 45 41 54 45 20 54 41 42 4c 45 20 71 75 65 72 REATE TABLE quer | 3776: 79 70 6f 6c 79 28 70 6f 6c 79 20 4a 53 4f 4e 2c ypoly(poly JSON, | 3792: 20 63 6c 72 20 54 45 58 54 29 64 03 07 17 23 23 clr TEXT)d...## | 3808: 01 81 0f 74 61 62 6c 65 67 65 6f 31 5f 70 61 72 ...tablegeo1_par | 3824: 65 6e 74 67 65 6f 31 5f 70 61 72 65 6e 74 04 43 entgeo1_parent.C | 3840: 52 45 41 54 45 20 54 41 42 4c 45 20 22 67 65 6f REATE TABLE .geo | 3856: 31 5f 70 61 72 65 6e 74 22 28 6e 6f 64 65 6e 6f 1_parent.(nodeno | 3872: 20 49 4e 54 45 47 45 52 20 50 52 49 4d 41 52 59 INTEGER PRIMARY | 3888: 20 4b 45 59 2c 70 61 72 65 6e 74 6e 6f 64 85 29 KEY,parentnod.) | 3904: 57 02 06 17 1f 1f 01 7f 74 61 62 6c 65 67 65 6f W.......tablegeo | 3920: 31 5f 6e 6f 64 65 67 65 6f 31 5f 6e 6f 64 65 03 1_nodegeo1_node. | 3936: 43 52 45 41 54 45 20 54 41 42 4c 45 20 22 67 65 CREATE TABLE .ge | 3952: 6f 31 5f 6e 6f 64 65 22 28 6e 6f 64 65 6e 6f 20 o1_node.(nodeno | 3968: 49 4e 54 45 47 45 52 20 50 52 49 4d 41 52 59 20 INTEGER PRIMARY | 3984: 4b 45 59 2c 64 61 74 61 29 65 01 07 17 21 21 01 KEY,data)e...!!. | 4000: 81 15 74 61 62 6c 65 67 65 6f 31 5f 72 6f 77 69 ..tablegeo1_rowi | 4016: 64 67 65 6f 31 5f 72 6f 77 69 64 02 43 52 45 41 dgeo1_rowid.CREA | 4032: 54 45 20 54 41 42 4c 45 20 22 67 65 6f 31 5f 72 TE TABLE .geo1_r | 4048: 6f 77 69 64 22 28 72 6f 77 69 64 20 49 4e 54 45 owid.(rowid INTE | 4064: 47 45 52 20 50 52 49 4d 41 52 59 20 4b 45 59 2c GER PRIMARY KEY, | 4080: 6e 6f 64 65 6e 6f 2c 61 30 2c 61 31 2c 61 32 29 nodeno,a0,a1,a2) | page 2 offset 4096 | 0: 0d 00 00 00 0a 0d ab 00 0f c9 0f 88 0f 48 0f 00 .............H.. | 3488: 00 00 00 00 00 00 00 00 00 00 00 45 82 0a 06 00 ...........E.... | 3504: 09 74 1d 13 01 00 00 06 00 80 b5 43 00 80 ac 43 .t.........C...C | 3520: 00 00 bd 43 8f 82 9f 43 71 fd c9 43 8f 02 a7 43 ...C...Cq..C...C | 3536: 71 fd c8 43 e4 bd a8 43 64 bb bd 43 f4 3d a2 43 q..C...Cd..C.=.C | 3552: 64 3b b7 43 00 80 ad 43 61 6e 67 6c 65 2d 33 30 d;.C...Cangle-30 | 3568: 72 65 64 32 81 4e 06 00 09 44 23 17 01 00 00 03 red2.N...D#..... | 3584: 00 40 3f 44 00 c0 20 44 00 c0 46 44 00 c0 20 44 .@?D.. D..FD.. D | 3600: 00 00 43 44 00 40 28 44 74 72 69 61 6e 67 6c 65 ..CD.@(Dtriangle | 3616: 2d 33 30 62 6c 61 63 6b 35 82 3e 06 00 09 54 1d -30black5.>...T. | 3632: 13 01 00 00 04 00 40 54 44 00 80 1d 44 9a c9 5c ......@TD...D... | 3648: 44 66 36 1b 44 33 13 5f 44 00 c0 23 44 9a 89 5b Df6.D3._D..#D..[ | 3664: 44 a4 60 1d 44 61 72 72 6f 77 2d 35 30 72 65 64 D.`.Darrow-50red | 3680: 36 74 06 00 09 54 1b 17 01 00 00 04 00 80 0d 44 6t...T.........D | 3696: 00 00 f2 42 0a d7 04 44 00 00 ca 42 0a 77 05 44 ...B...D...B.w.D | 3712: 0a 57 c1 42 00 20 0e 44 0a 57 e9 42 6c 69 6e 65 .W.B. .D.W.Bline | 3728: 2d 34 30 67 72 65 65 6e 36 72 06 00 09 54 1b 17 -40green6r...T.. | 3744: 01 00 00 04 00 00 7b 43 00 00 ea 42 29 5c 58 43 .......C...B).XC | 3760: 00 00 c2 42 29 dc 5a 43 0a 57 b9 42 00 80 7d 43 ...B).ZC.W.B...C | 3776: 0a 57 e1 42 6c 69 6e 65 2d 34 30 67 72 65 65 6e .W.Bline-40green | 3792: 36 54 06 00 09 54 1b 17 01 00 00 04 00 00 a2 43 6T...T.........C | 3808: 00 00 24 44 00 00 b6 43 00 00 24 44 00 00 b6 43 ..$D...C..$D...C | 3824: 00 40 25 44 00 00 a2 43 00 40 25 44 6c 69 6e 65 .@%D...C.@%Dline | 3840: 2d 34 30 62 6c 61 63 6b 3e 37 06 00 09 64 1d 15 -40black>7...d.. | 3856: 01 00 00 05 00 80 f0 43 00 00 54 43 66 16 01 44 .......C..TCf..D | 3872: 66 a6 30 43 cd ec 09 44 00 00 54 43 8f 0a 09 44 f.0C...D..TC...D | 3888: a4 d0 73 43 66 16 01 44 9a 59 77 43 68 6f 75 73 ..sCf..D.YwChous | 3904: 65 2d 37 30 62 6c 75 65 3e 35 06 00 09 64 1d 15 e-70blue>5...d.. | 3920: 01 00 00 05 00 00 a2 43 00 00 5a 43 cd ac b3 43 .......C..ZC...C | 3936: 66 a6 36 43 9a 59 c5 43 00 00 5a 43 1f 95 c3 43 f.6C.Y.C..ZC...C | 3952: a4 d0 79 43 cd ac b3 43 9a 59 7d 43 68 6f 75 73 ..yC...C.Y.Chous | 3968: 65 2d 37 30 62 6c 75 65 3f 2c 06 00 09 64 1d 17 e-70blue?,...d.. | 3984: 01 00 00 05 00 00 f5 43 00 00 2f 43 00 00 07 44 .......C../C...D | 4000: 00 00 2f 43 00 00 07 44 00 00 61 43 00 c0 00 44 ../C...D..aC...D | 4016: 00 00 75 43 00 00 f5 43 00 00 61 43 68 6f 75 73 ..uC...C..aChous | 4032: 65 2d 37 30 62 6c 61 63 6b 35 1f 06 10 09 54 19 e-70black5....T. | 4048: 17 01 00 00 04 00 00 9b 43 00 00 67 43 0a 57 92 ........C..gC.W. | 4064: 43 00 00 5d 43 0a 57 97 43 14 ae 4b 42 ff ff a0 C..]C.W.C..KB... | 4080: 43 14 ae 55 43 62 6f 78 2d 32 30 67 72 65 65 6e C..UCbox-20green | page 3 offset 8192 | 0: 0d 00 00 00 01 0b 2d 00 0b 2e 00 00 00 00 00 00 ......-......... | 2848: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 89 50 ...............P | 2864: 01 04 00 93 24 00 00 00 0a 00 00 00 00 00 00 01 ....$........... | 2880: 0a 43 b5 80 00 43 c9 fd 71 43 9f 82 8f 43 ad 80 .C...C..qC...C.. | 2896: 00 00 00 00 00 00 00 00 72 43 58 5c 29 43 7d 80 ........rCX.)C.. | 2912: 00 42 b9 57 0a 42 ea 00 00 00 00 00 00 00 00 00 .B.W.B.......... | 2928: 35 43 a2 00 00 43 c5 59 9a 43 36 a6 66 43 7d 59 5C...C.Y.C6.fC.Y | 2944: 9a 00 00 00 00 00 00 00 1f 43 92 57 0a 43 a0 00 .........C.W.C.. | 2960: 00 43 4b ae 14 43 67 00 00 00 00 00 00 00 00 00 .CK..Cg......... | 2976: 37 43 f0 80 00 44 09 ec cd 43 30 a6 66 43 77 59 7C...D...C0.fCwY | 2992: 9a 00 00 00 00 00 00 00 2c 43 f5 00 00 44 07 00 ........,C...D.. | 3008: 00 43 2f 00 00 43 75 00 00 00 00 00 00 00 00 00 .C/..Cu......... | 3024: 74 44 04 d7 0a 44 0e 20 00 42 c1 57 0a 42 f2 00 tD...D. .B.W.B.. | 3040: 00 00 00 00 00 00 00 00 ce 44 3f 40 00 44 46 c0 .........D?@.DF. | 3056: 00 44 20 c0 00 44 28 40 00 00 00 00 00 00 00 00 .D ..D(@........ | 3072: be 44 54 40 00 44 5f 13 33 44 1b 36 66 44 23 c0 .DT@.D_.3D.6fD#. | 3088: 00 00 00 00 00 00 00 00 54 43 a2 00 00 43 b6 00 ........TC...C.. | 3104: 00 44 24 00 00 44 25 40 00 00 00 00 00 00 00 00 .D$..D%@........ | 3120: 54 43 a2 00 00 43 b6 00 00 44 24 00 00 44 25 40 TC...C...D$..D%@ | 3136: 00 00 00 00 00 00 00 00 54 43 a2 00 00 43 b6 00 ........TC...C.. | 3152: 00 44 24 00 00 44 25 40 00 00 00 00 00 00 00 00 .D$..D%@........ | 3168: 54 43 a2 00 00 43 b6 00 00 44 24 00 00 44 25 40 TC...C...D$..D%@ | 3184: 00 00 00 00 00 00 00 00 54 43 a2 00 00 43 b6 00 ........TC...C.. | 3200: 00 44 24 00 00 44 25 40 00 00 00 00 00 00 00 00 .D$..D%@........ | 3216: 54 43 a2 00 00 43 b6 00 00 44 24 00 00 44 25 40 TC...C...D$..D%@ | 3232: 00 00 00 00 00 00 00 00 54 43 a2 00 00 43 b6 00 ........TC...C.. | 3248: 00 44 24 00 00 44 25 40 00 00 00 00 00 00 00 00 .D$..D%@........ | 3264: 54 43 a2 00 00 43 b6 00 00 44 24 00 00 44 25 40 TC...C...D$..D%@ | 3280: 00 00 00 00 00 00 00 00 54 43 a2 00 00 43 b6 00 ........TC...C.. | 3296: 00 44 24 00 00 44 25 40 00 00 00 00 00 00 00 00 .D$..D%@........ | 3312: 54 43 a2 00 00 43 b6 00 00 44 24 00 00 44 25 40 TC...C...D$..D%@ | 3328: 00 00 00 00 00 00 00 00 54 43 a2 00 00 43 b6 00 ........TC...C.. | 3344: 00 44 24 00 00 44 25 40 00 00 00 00 00 00 00 01 .D$..D%@........ | 3360: 36 44 53 e0 00 44 56 bb 64 43 71 34 bc 43 7d 00 6DS..DV.dCq4.C.. | 3376: 00 00 00 00 00 00 00 01 36 44 53 e0 00 44 56 bb ........6DS..DV. | 3392: 64 43 71 34 bc 43 7d 00 00 00 00 00 00 00 00 01 dCq4.C.......... | 3408: 36 44 53 e0 00 44 56 bb 64 43 71 34 bc 43 7d 00 6DS..DV.dCq4.C.. | 3424: 00 00 00 00 00 00 00 01 36 44 53 e0 00 44 56 bb ........6DS..DV. | 3440: 64 43 71 34 bc 43 7d 00 00 00 00 00 00 00 00 01 dCq4.C.......... | 3456: 36 44 53 e0 00 44 56 bb 64 43 71 34 bc 43 7d 00 6DS..DV.dCq4.C.. | 3472: 00 00 00 00 00 00 00 01 36 44 53 e0 00 44 56 bb ........6DS..DV. | 3488: 64 43 71 34 bc 43 7d 00 00 00 00 00 00 00 00 01 dCq4.C.......... | 3504: 36 44 53 e0 00 44 56 bb 64 43 71 34 bc 43 7d 00 6DS..DV.dCq4.C.. | 3520: 00 00 00 00 00 00 00 01 36 44 53 e0 00 44 56 bb ........6DS..DV. | 3536: 64 43 71 34 bc 43 7d 00 00 00 00 00 00 00 00 01 dCq4.C.......... | 3552: 36 44 53 e0 00 44 56 bb 64 43 71 34 bc 43 7d 00 6DS..DV.dCq4.C.. | 3568: 00 00 00 00 00 00 00 01 36 44 53 e0 00 44 56 bb ........6DS..DV. | 3584: 64 43 71 34 bc 43 7d 00 00 00 00 00 00 00 00 01 dCq4.C.......... | 3600: 36 44 53 e0 00 44 56 bb 64 43 71 34 bc 43 7d 00 6DS..DV.dCq4.C.. | 3616: 00 00 00 00 00 00 00 01 36 44 53 e0 00 44 56 bb ........6DS..DV. | 3632: 64 43 71 34 bc 43 7d 00 00 00 00 00 00 00 00 01 dCq4.C.......... | 3648: 36 44 53 e0 00 44 56 bb 64 43 71 34 bc 43 7d 00 6DS..DV.dCq4.C.. | 3664: 00 00 00 00 00 00 00 01 36 44 53 e0 00 44 56 bb ........6DS..DV. | 3680: 64 43 71 34 bc 43 7d 00 00 00 00 00 00 00 00 01 dCq4.C.......... | 3696: 36 44 53 e0 00 44 56 bb 64 43 71 34 bc 43 7d 00 6DS..DV.dCq4.C.. | page 4 offset 12288 | 0: 0d 00 00 00 00 10 00 00 00 00 00 00 00 00 00 00 ................ | page 5 offset 16384 | 0: 0d 00 00 00 01 0f 8f 00 00 00 00 00 00 00 00 00 ................ | 3968: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 6f ...............o | 3984: 01 04 81 57 19 5b 5b 33 30 30 2c 33 30 30 5d 2c ...W.[[300,300], | 4000: 5b 34 30 30 2c 33 35 30 5d 2c 5b 35 30 30 2c 32 [400,350],[500,2 | 4016: 35 30 5d 2c 5b 34 38 30 2c 35 30 30 5d 2c 5b 34 50],[480,500],[4 | 4032: 30 30 2c 34 38 30 5d 2c 5c 33 30 30 2c 35 35 30 00,480],.300,550 | 4048: 5d 2c 5b 32 38 30 2c 34 35 30 5d 2c 5b 33 32 30 ],[280,450],[320 | 4064: 2c 34 30 30 5d 2c 5b 32 38 30 2c 33 35 30 5d 2c ,400],[280,350], | 4080: 5b 33 30 30 2c 33 30 00 00 00 00 00 00 00 00 00 [300,30......... | end crash-7b37d80f000235.db }]} {} ifcapable geopoly { do_catchsql_test rtreefuzz001-601 { SAVEPOINT one; UPDATE geo1 SET clr=CASE WHEN rowid IN ( SELECT geo1.rowid FROM geo1, querypoly ) THEN 'e' ELSE 'blue' END; } {1 {database disk image is malformed}} do_catchsql_test rtreefuzz001-602 { SELECT geopoly_svg(_shape, printf('j',geo1.clr)) FROM geo1, querypoly WHERE geopoly_overlap(_shape, poly); } {1 {database disk image is malformed}} } ;# ifcapable geopoly finish_test |
Added ext/rtree/test_rtreedoc.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 | /* ** 2010 August 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. ** ************************************************************************* ** Code for testing all sorts of SQLite interfaces. This code ** is not included in the SQLite library. */ #include "sqlite3.h" #if defined(INCLUDE_SQLITE_TCL_H) # include "sqlite_tcl.h" #else # include "tcl.h" #endif /* Solely for the UNUSED_PARAMETER() macro. */ #include "sqliteInt.h" #ifdef SQLITE_ENABLE_RTREE typedef struct BoxGeomCtx BoxGeomCtx; struct BoxGeomCtx { Tcl_Interp *interp; Tcl_Obj *pScript; }; typedef struct BoxQueryCtx BoxQueryCtx; struct BoxQueryCtx { Tcl_Interp *interp; Tcl_Obj *pScript; }; static void testDelUser(void *pCtx){ BoxGeomCtx *p = (BoxGeomCtx*)pCtx; Tcl_EvalObjEx(p->interp, p->pScript, 0); Tcl_DecrRefCount(p->pScript); sqlite3_free(p); } static int invokeTclGeomCb( const char *zName, sqlite3_rtree_geometry *p, int nCoord, sqlite3_rtree_dbl *aCoord ){ int rc = SQLITE_OK; if( p->pContext ){ char aPtr[64]; BoxGeomCtx *pCtx = (BoxGeomCtx*)p->pContext; Tcl_Interp *interp = pCtx->interp; Tcl_Obj *pScript = 0; Tcl_Obj *pParam = 0; Tcl_Obj *pCoord = 0; int ii; Tcl_Obj *pRes; pScript = Tcl_DuplicateObj(pCtx->pScript); Tcl_IncrRefCount(pScript); Tcl_ListObjAppendElement(interp, pScript, Tcl_NewStringObj(zName,-1)); sqlite3_snprintf(sizeof(aPtr)-1, aPtr, "%p", (void*)p->pContext); Tcl_ListObjAppendElement(interp, pScript, Tcl_NewStringObj(aPtr,-1)); pParam = Tcl_NewObj(); for(ii=0; ii<p->nParam; ii++){ Tcl_ListObjAppendElement( interp, pParam, Tcl_NewDoubleObj(p->aParam[ii]) ); } Tcl_ListObjAppendElement(interp, pScript, pParam); pCoord = Tcl_NewObj(); for(ii=0; ii<nCoord; ii++){ Tcl_ListObjAppendElement(interp, pCoord, Tcl_NewDoubleObj(aCoord[ii])); } Tcl_ListObjAppendElement(interp, pScript, pCoord); sqlite3_snprintf(sizeof(aPtr)-1, aPtr, "%p", (void*)p); Tcl_ListObjAppendElement(interp, pScript, Tcl_NewStringObj(aPtr,-1)); rc = Tcl_EvalObjEx(interp, pScript, 0); if( rc!=TCL_OK ){ rc = SQLITE_ERROR; }else{ int nObj = 0; Tcl_Obj **aObj = 0; pRes = Tcl_GetObjResult(interp); if( Tcl_ListObjGetElements(interp, pRes, &nObj, &aObj) ) return TCL_ERROR; if( nObj>0 ){ const char *zCmd = Tcl_GetString(aObj[0]); if( 0==sqlite3_stricmp(zCmd, "zero") ){ p->aParam[0] = 0.0; p->nParam = 1; } else if( 0==sqlite3_stricmp(zCmd, "user") ){ if( p->pUser || p->xDelUser ){ rc = SQLITE_ERROR; }else{ BoxGeomCtx *pBGCtx = sqlite3_malloc(sizeof(BoxGeomCtx)); if( pBGCtx==0 ){ rc = SQLITE_NOMEM; }else{ pBGCtx->interp = interp; pBGCtx->pScript = Tcl_DuplicateObj(pRes); Tcl_IncrRefCount(pBGCtx->pScript); Tcl_ListObjReplace(interp, pBGCtx->pScript, 0, 1, 0, 0); p->pUser = (void*)pBGCtx; p->xDelUser = testDelUser; } } } else if( 0==sqlite3_stricmp(zCmd, "user_is_zero") ){ if( p->pUser || p->xDelUser ) rc = SQLITE_ERROR; } } } } return rc; } /* # EVIDENCE-OF: R-00693-36727 The legacy xGeom callback is invoked with # four arguments. # EVIDENCE-OF: R-50437-53270 The first argument is a pointer to an # sqlite3_rtree_geometry structure which provides information about how # the SQL function was invoked. # EVIDENCE-OF: R-00090-24248 The third argument, aCoord[], is an array # of nCoord coordinates that defines a bounding box to be tested. # EVIDENCE-OF: R-28207-40885 The last argument is a pointer into which # the callback result should be written. */ static int box_geom( sqlite3_rtree_geometry *p, /* R-50437-53270 */ int nCoord, /* R-02424-24769 */ sqlite3_rtree_dbl *aCoord, /* R-00090-24248 */ int *pRes /* R-28207-40885 */ ){ int ii; if( p->nParam!=nCoord ){ invokeTclGeomCb("box", p, nCoord, aCoord); return SQLITE_ERROR; } if( invokeTclGeomCb("box", p, nCoord, aCoord) ) return SQLITE_ERROR; for(ii=0; ii<nCoord; ii+=2){ if( aCoord[ii]>p->aParam[ii+1] || aCoord[ii+1]<p->aParam[ii] ){ /* R-28207-40885 */ *pRes = 0; return SQLITE_OK; } } /* R-28207-40885 */ *pRes = 1; return SQLITE_OK; } static int SQLITE_TCLAPI register_box_geom( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ extern int getDbPointer(Tcl_Interp*, const char*, sqlite3**); extern const char *sqlite3ErrName(int); sqlite3 *db; BoxGeomCtx *pCtx; char aPtr[64]; if( objc!=3 ){ Tcl_WrongNumArgs(interp, 1, objv, "DB SCRIPT"); return TCL_ERROR; } if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; pCtx = (BoxGeomCtx*)ckalloc(sizeof(BoxGeomCtx*)); pCtx->interp = interp; pCtx->pScript = Tcl_DuplicateObj(objv[2]); Tcl_IncrRefCount(pCtx->pScript); sqlite3_rtree_geometry_callback(db, "box", box_geom, (void*)pCtx); sqlite3_snprintf(64, aPtr, "%p", (void*)pCtx); Tcl_SetObjResult(interp, Tcl_NewStringObj(aPtr, -1)); return TCL_OK; } static int box_query(sqlite3_rtree_query_info *pInfo){ const char *azParentWithin[] = {"not", "partly", "fully", 0}; BoxQueryCtx *pCtx = (BoxQueryCtx*)pInfo->pContext; Tcl_Interp *interp = pCtx->interp; Tcl_Obj *pEval; Tcl_Obj *pArg; Tcl_Obj *pTmp = 0; int rc; int ii; pEval = Tcl_DuplicateObj(pCtx->pScript); Tcl_IncrRefCount(pEval); pArg = Tcl_NewObj(); Tcl_IncrRefCount(pArg); /* aParam[] */ pTmp = Tcl_NewObj(); Tcl_IncrRefCount(pTmp); for(ii=0; ii<pInfo->nParam; ii++){ Tcl_Obj *p = Tcl_NewDoubleObj(pInfo->aParam[ii]); Tcl_ListObjAppendElement(interp, pTmp, p); } Tcl_ListObjAppendElement(interp, pArg, Tcl_NewStringObj("aParam", -1)); Tcl_ListObjAppendElement(interp, pArg, pTmp); Tcl_DecrRefCount(pTmp); /* aCoord[] */ pTmp = Tcl_NewObj(); Tcl_IncrRefCount(pTmp); for(ii=0; ii<pInfo->nCoord; ii++){ Tcl_Obj *p = Tcl_NewDoubleObj(pInfo->aCoord[ii]); Tcl_ListObjAppendElement(interp, pTmp, p); } Tcl_ListObjAppendElement(interp, pArg, Tcl_NewStringObj("aCoord", -1)); Tcl_ListObjAppendElement(interp, pArg, pTmp); Tcl_DecrRefCount(pTmp); /* anQueue[] */ pTmp = Tcl_NewObj(); Tcl_IncrRefCount(pTmp); for(ii=0; ii<=pInfo->mxLevel; ii++){ Tcl_Obj *p = Tcl_NewIntObj((int)pInfo->anQueue[ii]); Tcl_ListObjAppendElement(interp, pTmp, p); } Tcl_ListObjAppendElement(interp, pArg, Tcl_NewStringObj("anQueue", -1)); Tcl_ListObjAppendElement(interp, pArg, pTmp); Tcl_DecrRefCount(pTmp); /* iLevel */ Tcl_ListObjAppendElement(interp, pArg, Tcl_NewStringObj("iLevel", -1)); Tcl_ListObjAppendElement(interp, pArg, Tcl_NewIntObj(pInfo->iLevel)); /* mxLevel */ Tcl_ListObjAppendElement(interp, pArg, Tcl_NewStringObj("mxLevel", -1)); Tcl_ListObjAppendElement(interp, pArg, Tcl_NewIntObj(pInfo->mxLevel)); /* iRowid */ Tcl_ListObjAppendElement(interp, pArg, Tcl_NewStringObj("iRowid", -1)); Tcl_ListObjAppendElement(interp, pArg, Tcl_NewWideIntObj(pInfo->iRowid)); /* rParentScore */ Tcl_ListObjAppendElement(interp, pArg, Tcl_NewStringObj("rParentScore", -1)); Tcl_ListObjAppendElement(interp, pArg, Tcl_NewDoubleObj(pInfo->rParentScore)); /* eParentWithin */ assert( pInfo->eParentWithin==0 || pInfo->eParentWithin==1 || pInfo->eParentWithin==2 ); Tcl_ListObjAppendElement(interp, pArg, Tcl_NewStringObj("eParentWithin", -1)); Tcl_ListObjAppendElement(interp, pArg, Tcl_NewStringObj(azParentWithin[pInfo->eParentWithin], -1) ); Tcl_ListObjAppendElement(interp, pEval, pArg); rc = Tcl_EvalObjEx(interp, pEval, 0) ? SQLITE_ERROR : SQLITE_OK; if( rc==SQLITE_OK ){ double rScore = 0.0; int nObj = 0; int eP = 0; Tcl_Obj **aObj = 0; Tcl_Obj *pRes = Tcl_GetObjResult(interp); if( Tcl_ListObjGetElements(interp, pRes, &nObj, &aObj) || nObj!=2 || Tcl_GetDoubleFromObj(interp, aObj[1], &rScore) || Tcl_GetIndexFromObj(interp, aObj[0], azParentWithin, "value", 0, &eP) ){ rc = SQLITE_ERROR; }else{ pInfo->rScore = rScore; pInfo->eParentWithin = eP; } } Tcl_DecrRefCount(pArg); Tcl_DecrRefCount(pEval); return rc; } static void box_query_destroy(void *p){ BoxQueryCtx *pCtx = (BoxQueryCtx*)p; Tcl_DecrRefCount(pCtx->pScript); ckfree(pCtx); } static int SQLITE_TCLAPI register_box_query( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ extern int getDbPointer(Tcl_Interp*, const char*, sqlite3**); extern const char *sqlite3ErrName(int); sqlite3 *db; BoxQueryCtx *pCtx; if( objc!=3 ){ Tcl_WrongNumArgs(interp, 1, objv, "DB SCRIPT"); return TCL_ERROR; } if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; pCtx = (BoxQueryCtx*)ckalloc(sizeof(BoxQueryCtx*)); pCtx->interp = interp; pCtx->pScript = Tcl_DuplicateObj(objv[2]); Tcl_IncrRefCount(pCtx->pScript); sqlite3_rtree_query_callback( db, "qbox", box_query, (void*)pCtx, box_query_destroy ); Tcl_ResetResult(interp); return TCL_OK; } #endif /* SQLITE_ENABLE_RTREE */ int Sqlitetestrtreedoc_Init(Tcl_Interp *interp){ #ifdef SQLITE_ENABLE_RTREE Tcl_CreateObjCommand(interp, "register_box_geom", register_box_geom, 0, 0); Tcl_CreateObjCommand(interp, "register_box_query", register_box_query, 0, 0); #endif /* SQLITE_ENABLE_RTREE */ return TCL_OK; } |
Changes to ext/session/changeset.c.
︙ | ︙ | |||
38 39 40 41 42 43 44 | } /* ** Read the content of a disk file into an in-memory buffer */ static void readFile(const char *zFilename, int *pSz, void **ppBuf){ FILE *f; | | | | | | | > | | 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 | } /* ** Read the content of a disk file into an in-memory buffer */ static void readFile(const char *zFilename, int *pSz, void **ppBuf){ FILE *f; sqlite3_int64 sz; void *pBuf; f = fopen(zFilename, "rb"); if( f==0 ){ fprintf(stderr, "cannot open \"%s\" for reading\n", zFilename); exit(1); } fseek(f, 0, SEEK_END); sz = ftell(f); rewind(f); pBuf = sqlite3_malloc64( sz ? sz : 1 ); if( pBuf==0 ){ fprintf(stderr, "cannot allocate %d to hold content of \"%s\"\n", (int)sz, zFilename); exit(1); } if( sz>0 ){ if( fread(pBuf, (size_t)sz, 1, f)!=1 ){ fprintf(stderr, "cannot read all %d bytes of \"%s\"\n", (int)sz, zFilename); exit(1); } fclose(f); } *pSz = (int)sz; *ppBuf = pBuf; } /* Array for converting from half-bytes (nybbles) into ASCII hex ** digits. */ static const char hexdigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', |
︙ | ︙ |
Changes to ext/session/changesetfuzz.c.
︙ | ︙ | |||
137 138 139 140 141 142 143 | } /* ** Read the content of a disk file into an in-memory buffer */ static void fuzzReadFile(const char *zFilename, int *pSz, void **ppBuf){ FILE *f; | | | | | | | > | | 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 | } /* ** Read the content of a disk file into an in-memory buffer */ static void fuzzReadFile(const char *zFilename, int *pSz, void **ppBuf){ FILE *f; sqlite3_int64 sz; void *pBuf; f = fopen(zFilename, "rb"); if( f==0 ){ fprintf(stderr, "cannot open \"%s\" for reading\n", zFilename); exit(1); } fseek(f, 0, SEEK_END); sz = ftell(f); rewind(f); pBuf = sqlite3_malloc64( sz ? sz : 1 ); if( pBuf==0 ){ fprintf(stderr, "cannot allocate %d to hold content of \"%s\"\n", (int)sz, zFilename); exit(1); } if( sz>0 ){ if( fread(pBuf, (size_t)sz, 1, f)!=1 ){ fprintf(stderr, "cannot read all %d bytes of \"%s\"\n", (int)sz, zFilename); exit(1); } fclose(f); } *pSz = (int)sz; *ppBuf = pBuf; } /* ** Write the contents of buffer pBuf, size nBuf bytes, into file zFilename ** on disk. zFilename, if it already exists, is clobbered. */ |
︙ | ︙ | |||
336 337 338 339 340 341 342 | u8 aSub[128]; /* Buffer for substitute value */ int iCurrent; /* Current change number */ }; /* ** Allocate and return nByte bytes of zeroed memory. */ | | | | | 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 | u8 aSub[128]; /* Buffer for substitute value */ int iCurrent; /* Current change number */ }; /* ** Allocate and return nByte bytes of zeroed memory. */ static void *fuzzMalloc(sqlite3_int64 nByte){ void *pRet = sqlite3_malloc64(nByte); if( pRet ){ memset(pRet, 0, (size_t)nByte); } return pRet; } /* ** Free the buffer indicated by the first argument. This function is used ** to free buffers allocated by fuzzMalloc(). |
︙ | ︙ | |||
380 381 382 383 384 385 386 | ** Write value nVal into the buffer indicated by argument p as an SQLite ** varint. nVal is guaranteed to be between 0 and (2^21-1), inclusive. ** Return the number of bytes written to buffer p. */ static int fuzzPutVarint(u8 *p, int nVal){ assert( nVal>0 && nVal<2097152 ); if( nVal<128 ){ | | | 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 | ** Write value nVal into the buffer indicated by argument p as an SQLite ** varint. nVal is guaranteed to be between 0 and (2^21-1), inclusive. ** Return the number of bytes written to buffer p. */ static int fuzzPutVarint(u8 *p, int nVal){ assert( nVal>0 && nVal<2097152 ); if( nVal<128 ){ p[0] = (u8)nVal; return 1; } if( nVal<16384 ){ p[0] = ((nVal >> 7) & 0x7F) | 0x80; p[1] = (nVal & 0x7F); return 2; } |
︙ | ︙ | |||
455 456 457 458 459 460 461 | rc = fuzzCorrupt(); }else{ p++; p += fuzzGetVarint(p, &pGrp->nCol); pGrp->aPK = p; p += pGrp->nCol; pGrp->zTab = (const char*)p; | | | 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 | rc = fuzzCorrupt(); }else{ p++; p += fuzzGetVarint(p, &pGrp->nCol); pGrp->aPK = p; p += pGrp->nCol; pGrp->zTab = (const char*)p; p = &p[strlen((const char*)p)+1]; if( p>=pEnd ){ rc = fuzzCorrupt(); } } *ppHdr = p; } |
︙ | ︙ | |||
627 628 629 630 631 632 633 | /* Read a table-header from the changeset */ rc = fuzzParseHeader(pParse, &p, pEnd, &pGrp); assert( (rc==SQLITE_OK)==(pGrp!=0) ); /* If the table-header was successfully parsed, add the new change-group ** to the array and parse the associated changes. */ if( rc==SQLITE_OK ){ | | | 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 | /* Read a table-header from the changeset */ rc = fuzzParseHeader(pParse, &p, pEnd, &pGrp); assert( (rc==SQLITE_OK)==(pGrp!=0) ); /* If the table-header was successfully parsed, add the new change-group ** to the array and parse the associated changes. */ if( rc==SQLITE_OK ){ FuzzChangesetGroup **apNew = (FuzzChangesetGroup**)sqlite3_realloc64( pParse->apGroup, sizeof(FuzzChangesetGroup*)*(pParse->nGroup+1) ); if( apNew==0 ){ rc = SQLITE_NOMEM; }else{ apNew[pParse->nGroup] = pGrp; pParse->apGroup = apNew; |
︙ | ︙ | |||
691 692 693 694 695 696 697 | p += 8; break; } case 0x03: /* text */ case 0x04: { /* blob */ int nTxt; | < < | 692 693 694 695 696 697 698 699 700 701 702 703 704 705 | p += 8; break; } case 0x03: /* text */ case 0x04: { /* blob */ int nTxt; p += fuzzGetVarint(p, &nTxt); printf("%s%s", zPre, eType==0x03 ? "'" : "X'"); for(i=0; i<nTxt; i++){ if( eType==0x03 ){ printf("%c", p[i]); }else{ char aHex[16] = {'0', '1', '2', '3', '4', '5', '6', '7', |
︙ | ︙ | |||
855 856 857 858 859 860 861 | fuzzPutU64(&pChange->aSub[1], iVal1); break; } case 0x03: /* text */ case 0x04: { /* blob */ int nByte = fuzzRandomInt(48); | | | 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 | fuzzPutU64(&pChange->aSub[1], iVal1); break; } case 0x03: /* text */ case 0x04: { /* blob */ int nByte = fuzzRandomInt(48); pChange->aSub[1] = (u8)nByte; fuzzRandomBlob(nByte, &pChange->aSub[2]); if( pChange->aSub[0]==0x03 ){ int i; for(i=0; i<nByte; i++){ pChange->aSub[2+i] &= 0x7F; } } |
︙ | ︙ | |||
1000 1001 1002 1003 1004 1005 1006 | } if( p==pFuzz->pSub1 ){ pCopy = pFuzz->pSub2; }else if( p==pFuzz->pSub2 ){ pCopy = pFuzz->pSub1; }else if( i==iUndef ){ | | | 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 | } if( p==pFuzz->pSub1 ){ pCopy = pFuzz->pSub2; }else if( p==pFuzz->pSub2 ){ pCopy = pFuzz->pSub1; }else if( i==iUndef ){ pCopy = (u8*)"\0"; } if( pCopy[0]==0x00 && eNew!=eType && eType==SQLITE_UPDATE && iRec==0 ){ while( pCopy[0]==0x00 ){ pCopy = pParse->apVal[fuzzRandomInt(pParse->nVal)]; } }else if( p[0]==0x00 && pCopy[0]!=0x00 ){ |
︙ | ︙ | |||
1063 1064 1065 1066 1067 1068 1069 | } if( eNew!=eType && eNew==SQLITE_UPDATE && !bPS ){ int i; u8 *pCsr = (*ppOut) + 2; for(i=0; i<pGrp->nCol; i++){ int sz; u8 *pCopy = pCsr; | | | 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 | } if( eNew!=eType && eNew==SQLITE_UPDATE && !bPS ){ int i; u8 *pCsr = (*ppOut) + 2; for(i=0; i<pGrp->nCol; i++){ int sz; u8 *pCopy = pCsr; if( pGrp->aPK[i] ) pCopy = (u8*)"\0"; fuzzChangeSize(pCopy, &sz); memcpy(pOut, pCopy, sz); pOut += sz; fuzzChangeSize(pCsr, &sz); pCsr += sz; } } |
︙ | ︙ | |||
1210 1211 1212 1213 1214 1215 1216 | if( rc==SQLITE_OK ){ if( argc==2 ){ for(i=0; i<changeset.nGroup; i++){ fuzzPrintGroup(&changeset, changeset.apGroup[i]); } }else{ | | | 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 | if( rc==SQLITE_OK ){ if( argc==2 ){ for(i=0; i<changeset.nGroup; i++){ fuzzPrintGroup(&changeset, changeset.apGroup[i]); } }else{ pBuf = (u8*)fuzzMalloc((sqlite3_int64)nChangeset*2 + 1024); if( pBuf==0 ){ rc = SQLITE_NOMEM; }else{ iSeed = atoi(argv[2]); nRepeat = atoi(argv[3]); fuzzRandomSeed((unsigned int)iSeed); for(i=0; rc==SQLITE_OK && i<nRepeat; i++){ |
︙ | ︙ | |||
1233 1234 1235 1236 1237 1238 1239 | if( rc!=SQLITE_OK ){ fprintf(stderr, "error while processing changeset: %d\n", rc); } return rc; } | < | 1232 1233 1234 1235 1236 1237 1238 | if( rc!=SQLITE_OK ){ fprintf(stderr, "error while processing changeset: %d\n", rc); } return rc; } |
Changes to ext/session/session1.test.
︙ | ︙ | |||
148 149 150 151 152 153 154 155 156 157 158 159 160 161 | execsql { INSERT INTO t1 VALUES(100, 'Bangkok') } execsql { DELETE FROM t1 WHERE x = 100 } } {} do_changeset_test $tn.2.4.2 S {} do_changeset_invert_test $tn.2.4.3 S {} do_test $tn.2.4.4 { S delete } {} #------------------------------------------------------------------------- # Test the application of simple changesets. These tests also test that # the conflict callback is invoked correctly. For these tests, the # conflict callback always returns OMIT. # db close forcedelete test.db test.db2 | > > > > > > > > > > > > > > > > > > > > | 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 | execsql { INSERT INTO t1 VALUES(100, 'Bangkok') } execsql { DELETE FROM t1 WHERE x = 100 } } {} do_changeset_test $tn.2.4.2 S {} do_changeset_invert_test $tn.2.4.3 S {} do_test $tn.2.4.4 { S delete } {} do_execsql_test $tn.2.5.0 { SELECT * FROM t1 ORDER BY x } { 2 Surin 10 Sukhothai 20 Thapae } do_test $tn.2.5.1 { sqlite3session S db main S attach t1 execsql { DELETE FROM t1 } } {} do_changeset_test $tn.2.5.2 S { {DELETE t1 0 X. {i 10 t Sukhothai} {}} {DELETE t1 0 X. {i 2 t Surin} {}} {DELETE t1 0 X. {i 20 t Thapae} {}} } do_test $tn.2.5.3 { S delete } {} #------------------------------------------------------------------------- # Test the application of simple changesets. These tests also test that # the conflict callback is invoked correctly. For these tests, the # conflict callback always returns OMIT. # db close forcedelete test.db test.db2 |
︙ | ︙ |
Changes to ext/session/session2.test.
︙ | ︙ | |||
31 32 33 34 35 36 37 | ########################################################################## # End of proc definitions. Start of tests. ########################################################################## test_reset do_execsql_test 1.0 { | | | 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | ########################################################################## # End of proc definitions. Start of tests. ########################################################################## test_reset do_execsql_test 1.0 { CREATE TABLE t1(a INT PRIMARY KEY, b); INSERT INTO t1 VALUES('i', 'one'); } do_iterator_test 1.1 t1 { DELETE FROM t1 WHERE a = 'i'; INSERT INTO t1 VALUES('ii', 'two'); } { {DELETE t1 0 X. {t i t one} {}} |
︙ | ︙ | |||
180 181 182 183 184 185 186 | DELETE FROM t1; INSERT INTO t1 VALUES('', NULL); } } test_reset do_common_sql { | | | 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 | DELETE FROM t1; INSERT INTO t1 VALUES('', NULL); } } test_reset do_common_sql { CREATE TABLE t1(a int PRIMARY KEY, b); CREATE TABLE t2(a, b INTEGER PRIMARY KEY); CREATE TABLE t3(a, b, c, PRIMARY KEY(a, b)); CREATE TABLE t4(a, b, PRIMARY KEY(b, a)); } foreach {tn sql} [string map {%T1% t1 %T2% t2 %T3% t3 %T4% t4} $set_of_tests] { do_then_apply_sql $sql |
︙ | ︙ | |||
202 203 204 205 206 207 208 | # test_reset forcedelete test.db3 sqlite3 db3 test.db3 do_test 3.0 { execsql { ATTACH 'test.db3' AS 'aux'; | | | | | 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 | # test_reset forcedelete test.db3 sqlite3 db3 test.db3 do_test 3.0 { execsql { ATTACH 'test.db3' AS 'aux'; CREATE TABLE t1(a int, b PRIMARY KEY); CREATE TABLE t2(x, y, z); CREATE TABLE t3(a); CREATE TABLE aux.t1(a int PRIMARY KEY, b); CREATE TABLE aux.t2(a, b INTEGER PRIMARY KEY); CREATE TABLE aux.t3(a, b, c, PRIMARY KEY(a, b)); CREATE TABLE aux.t4(a, b, PRIMARY KEY(b, a)); } execsql { CREATE TABLE t1(a int PRIMARY KEY, b); CREATE TABLE t2(a, b INTEGER PRIMARY KEY); CREATE TABLE t3(a, b, c, PRIMARY KEY(a, b)); CREATE TABLE t4(a, b, PRIMARY KEY(b, a)); } db2 } {} proc xTrace {args} { puts $args } |
︙ | ︙ | |||
583 584 585 586 587 588 589 590 591 | do_execsql_test 10.2 { SELECT enable(0); SELECT enable(-1); SELECT enable(1); SELECT enable(-1); } {0 0 1 1} S delete finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | do_execsql_test 10.2 { SELECT enable(0); SELECT enable(-1); SELECT enable(1); SELECT enable(-1); } {0 0 1 1} S delete #------------------------------------------------------------------------- test_reset do_common_sql { CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c, d, e, f); WITH s(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<32 ) INSERT INTO t1 SELECT NULL, 0, 0, 0, 0, 0 FROM s } do_then_apply_sql { UPDATE t1 SET f=f+1 WHERE a=1; UPDATE t1 SET e=e+1 WHERE a=2; UPDATE t1 SET e=e+1, f=f+1 WHERE a=3; UPDATE t1 SET d=d+1 WHERE a=4; UPDATE t1 SET d=d+1, f=f+1 WHERE a=5; UPDATE t1 SET d=d+1, e=e+1 WHERE a=6; UPDATE t1 SET d=d+1, e=e+1, f=f+1 WHERE a=7; UPDATE t1 SET c=c+1 WHERE a=8; UPDATE t1 SET c=c+1, f=f+1 WHERE a=9; UPDATE t1 SET c=c+1, e=e+1 WHERE a=10; UPDATE t1 SET c=c+1, e=e+1, f=f+1 WHERE a=11; UPDATE t1 SET c=c+1, d=d+1 WHERE a=12; UPDATE t1 SET c=c+1, d=d+1, f=f+1 WHERE a=13; UPDATE t1 SET c=c+1, d=d+1, e=e+1 WHERE a=14; UPDATE t1 SET c=c+1, d=d+1, e=e+1, f=f+1 WHERE a=15; UPDATE t1 SET d=d+1 WHERE a=16; UPDATE t1 SET d=d+1, f=f+1 WHERE a=17; UPDATE t1 SET d=d+1, e=e+1 WHERE a=18; UPDATE t1 SET d=d+1, e=e+1, f=f+1 WHERE a=19; UPDATE t1 SET d=d+1, d=d+1 WHERE a=20; UPDATE t1 SET d=d+1, d=d+1, f=f+1 WHERE a=21; UPDATE t1 SET d=d+1, d=d+1, e=e+1 WHERE a=22; UPDATE t1 SET d=d+1, d=d+1, e=e+1, f=f+1 WHERE a=23; UPDATE t1 SET d=d+1, c=c+1 WHERE a=24; UPDATE t1 SET d=d+1, c=c+1, f=f+1 WHERE a=25; UPDATE t1 SET d=d+1, c=c+1, e=e+1 WHERE a=26; UPDATE t1 SET d=d+1, c=c+1, e=e+1, f=f+1 WHERE a=27; UPDATE t1 SET d=d+1, c=c+1, d=d+1 WHERE a=28; UPDATE t1 SET d=d+1, c=c+1, d=d+1, f=f+1 WHERE a=29; UPDATE t1 SET d=d+1, c=c+1, d=d+1, e=e+1 WHERE a=30; UPDATE t1 SET d=d+1, c=c+1, d=d+1, e=e+1, f=f+1 WHERE a=31; } do_test 11.0 { compare_db db db2 } {} finish_test |
Changes to ext/session/session6.test.
︙ | ︙ | |||
15 16 17 18 19 20 21 22 23 24 25 26 27 28 | if {![info exists testdir]} { set testdir [file join [file dirname [info script]] .. .. test] } source [file join [file dirname [info script]] session_common.tcl] source $testdir/tester.tcl ifcapable !session {finish_test; return} set testprefix session6 proc do_then_apply_tcl {tcl {dbname main}} { proc xConflict args { return "OMIT" } set rc [catch { sqlite3session S db $dbname | > | 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | if {![info exists testdir]} { set testdir [file join [file dirname [info script]] .. .. test] } source [file join [file dirname [info script]] session_common.tcl] source $testdir/tester.tcl ifcapable !session {finish_test; return} ifcapable !incrblob {finish_test; return} set testprefix session6 proc do_then_apply_tcl {tcl {dbname main}} { proc xConflict args { return "OMIT" } set rc [catch { sqlite3session S db $dbname |
︙ | ︙ |
Changes to ext/session/sessionB.test.
︙ | ︙ | |||
254 255 256 257 258 259 260 | } # INSERT + DELETE do_patchconcat_test 4.3.3 { INSERT INTO t2 VALUES('a', 'a', 'a', 'a'); } { DELETE FROM t2 WHERE c = 'a'; | | < | 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 | } # INSERT + DELETE do_patchconcat_test 4.3.3 { INSERT INTO t2 VALUES('a', 'a', 'a', 'a'); } { DELETE FROM t2 WHERE c = 'a'; } {} # INSERT + UPDATE do_patchconcat_test 4.3.4 { INSERT INTO t2 VALUES('a', 'a', 'a', 'a'); } { UPDATE t2 SET d = 'b' WHERE c='a'; } { |
︙ | ︙ |
Changes to ext/session/sessionH.test.
︙ | ︙ | |||
25 26 27 28 29 30 31 | do_common_sql { CREATE TABLE t1(a, b, c, PRIMARY KEY(a, b)); } do_then_apply_sql { WITH s(i) AS ( VALUES(1) UNION ALL SELECT i+1 FROM s WHERe i<10000 ) | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | do_common_sql { CREATE TABLE t1(a, b, c, PRIMARY KEY(a, b)); } do_then_apply_sql { WITH s(i) AS ( VALUES(1) UNION ALL SELECT i+1 FROM s WHERe i<10000 ) INSERT INTO t1 SELECT 'abcde', randomblob(18), i FROM s; } compare_db db db2 } {} #------------------------------------------------------------------------ db2 close reset_db do_execsql_test 2.0 { CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c); INSERT INTO main.t1 VALUES(1, 2, 3), (4, 5, 6), (7, 8, 9); } do_test 2.1 { sqlite3session S db main S attach * db eval { BEGIN; INSERT INTO t1 VALUES(10, 11, 12); DELETE FROM t1 WHERE a=1; UPDATE t1 SET b='five', c='six' WHERE a=4; } set C [S changeset] db eval ROLLBACK S delete set {} {} } {} do_execsql_test 2.2 { CREATE TEMP TABLE t1(a INTEGER PRIMARY KEY, b, c); INSERT INTO temp.t1 VALUES(1, 2, 3), (4, 5, 6), (7, 8, 9); } set ::conflict [list] proc xConflict {args} { lappend ::conflict $args ; return "" } do_test 2.3 { sqlite3changeset_apply db $C xConflict set ::conflict } {} do_execsql_test 2.4 { SELECT * FROM main.t1; SELECT '****'; SELECT * FROM temp.t1; } { 4 five six 7 8 9 10 11 12 **** 1 2 3 4 5 6 7 8 9 } finish_test |
Changes to ext/session/session_common.tcl.
︙ | ︙ | |||
168 169 170 171 172 173 174 | $db2 eval "PRAGMA table_info = $tbl" { lappend col2 $name } if {$col1 != $col2} { error "table $tbl schema mismatch" } set sql "SELECT * FROM $tbl ORDER BY [join $col1 ,]" set data1 [$db1 eval $sql] set data2 [$db2 eval $sql] if {$data1 != $data2} { | | | | 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 | $db2 eval "PRAGMA table_info = $tbl" { lappend col2 $name } if {$col1 != $col2} { error "table $tbl schema mismatch" } set sql "SELECT * FROM $tbl ORDER BY [join $col1 ,]" set data1 [$db1 eval $sql] set data2 [$db2 eval $sql] if {$data1 != $data2} { puts "$db1: $data1" puts "$db2: $data2" error "table $tbl data mismatch" } } return "" } |
︙ | ︙ |
Changes to ext/session/session_speed_test.c.
︙ | ︙ | |||
352 353 354 355 356 357 358 | } } } return 0; } | < < | 352 353 354 355 356 357 358 | } } } return 0; } |
Changes to ext/session/sessionat.test.
︙ | ︙ | |||
16 17 18 19 20 21 22 23 | if {![info exists testdir]} { set testdir [file join [file dirname [info script]] .. .. test] } source [file join [file dirname [info script]] session_common.tcl] source $testdir/tester.tcl ifcapable !session {finish_test; return} | > > > | > > | 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | if {![info exists testdir]} { set testdir [file join [file dirname [info script]] .. .. test] } source [file join [file dirname [info script]] session_common.tcl] source $testdir/tester.tcl ifcapable !session {finish_test; return} set testprefix sessionat # If SQLITE_OMIT_ALTERTABLE is defined, omit this file. ifcapable !altertable { finish_test return } db close sqlite3_shutdown test_sqlite3_log log proc log {code msg} { lappend ::log $code $msg } proc reset_test {} { |
︙ | ︙ |
Added ext/session/sessionbig.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 | # 2014 August 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 implements regression tests for sessions SQLite extension. # Specifically, this file contains tests for "patchset" changes. # if {![info exists testdir]} { set testdir [file join [file dirname [info script]] .. .. test] } source [file join [file dirname [info script]] session_common.tcl] source $testdir/tester.tcl ifcapable !session {finish_test; return} if {[permutation]=="session_strm" || [permutation]=="session_eec"} { finish_test return } if {$::tcl_platform(pointerSize)<8} { finish_test return } set testprefix sessionbig forcedelete test.db2 sqlite3 db2 test.db2 do_execsql_test 1.0 { CREATE TABLE t1(a INTEGER PRIMARY KEY, b); } do_execsql_test -db db2 1.1 { CREATE TABLE t1(a INTEGER PRIMARY KEY, b); } do_test 1.2 { do_then_apply_sql { INSERT INTO t1(b) VALUES( zeroblob(100*1000*1000) ); INSERT INTO t1(b) VALUES( zeroblob(100*1000*1000) ); INSERT INTO t1(b) VALUES( zeroblob(100*1000*1000) ); INSERT INTO t1(b) VALUES( zeroblob(100*1000*1000) ); INSERT INTO t1(b) VALUES( zeroblob(100*1000*1000) ); INSERT INTO t1(b) VALUES( zeroblob(100*1000*1000) ); INSERT INTO t1(b) VALUES( zeroblob(100*1000*1000) ); INSERT INTO t1(b) VALUES( zeroblob(100*1000*1000) ); INSERT INTO t1(b) VALUES( zeroblob(100*1000*1000) ); INSERT INTO t1(b) VALUES( zeroblob(100*1000*1000) ); INSERT INTO t1(b) VALUES( zeroblob(100*1000*1000) ); INSERT INTO t1(b) VALUES( zeroblob(100*1000*1000) ); INSERT INTO t1(b) VALUES( zeroblob(100*1000*1000) ); INSERT INTO t1(b) VALUES( zeroblob(100*1000*1000) ); INSERT INTO t1(b) VALUES( zeroblob(100*1000*1000) ); } } {} do_test 1.3 { execsql { DELETE FROM t1 } execsql2 { DELETE FROM t1 } } {} do_test 1.4 { set rc [catch { do_then_apply_sql { INSERT INTO t1(b) VALUES( zeroblob(100*1000*1000) ); INSERT INTO t1(b) VALUES( zeroblob(100*1000*1000) ); INSERT INTO t1(b) VALUES( zeroblob(100*1000*1000) ); INSERT INTO t1(b) VALUES( zeroblob(100*1000*1000) ); INSERT INTO t1(b) VALUES( zeroblob(100*1000*1000) ); INSERT INTO t1(b) VALUES( zeroblob(100*1000*1000) ); INSERT INTO t1(b) VALUES( zeroblob(100*1000*1000) ); INSERT INTO t1(b) VALUES( zeroblob(100*1000*1000) ); INSERT INTO t1(b) VALUES( zeroblob(100*1000*1000) ); INSERT INTO t1(b) VALUES( zeroblob(100*1000*1000) ); INSERT INTO t1(b) VALUES( zeroblob(100*1000*1000) ); INSERT INTO t1(b) VALUES( zeroblob(100*1000*1000) ); INSERT INTO t1(b) VALUES( zeroblob(100*1000*1000) ); INSERT INTO t1(b) VALUES( zeroblob(100*1000*1000) ); INSERT INTO t1(b) VALUES( zeroblob(100*1000*1000) ); INSERT INTO t1(b) VALUES( zeroblob(100*1000*1000) ); INSERT INTO t1(b) VALUES( zeroblob(100*1000*1000) ); INSERT INTO t1(b) VALUES( zeroblob(100*1000*1000) ); INSERT INTO t1(b) VALUES( zeroblob(100*1000*1000) ); INSERT INTO t1(b) VALUES( zeroblob(100*1000*1000) ); INSERT INTO t1(b) VALUES( zeroblob(100*1000*1000) ); INSERT INTO t1(b) VALUES( zeroblob(100*1000*1000) ); } } msg] list $rc $msg } {1 SQLITE_NOMEM} finish_test |
Changes to ext/session/sessioninvert.test.
︙ | ︙ | |||
150 151 152 153 154 155 156 157 158 159 | list [catch { sqlite3session_foreach -invert db2 $P {} } msg] $msg } {1 SQLITE_CORRUPT} do_test 3.2 { sqlite3changeset_apply_v2 db2 $P {} compare_db db db2 } {} finish_test | > > > > > > > > > > > > > > > > > > > > > > > > | 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 | list [catch { sqlite3session_foreach -invert db2 $P {} } msg] $msg } {1 SQLITE_CORRUPT} do_test 3.2 { sqlite3changeset_apply_v2 db2 $P {} compare_db db db2 } {} #------------------------------------------------------------------------- # reset_db do_execsql_test 4.0 { CREATE TABLE t1(a INTEGER PRIMARY KEY, b UNIQUE); INSERT INTO t1 VALUES(1, 'one'); INSERT INTO t1 VALUES(2, 'two'); INSERT INTO t1 VALUES(3, 'three'); INSERT INTO t1 VALUES(4, 'four'); } do_invert_test 4.1 { DELETE FROM t1; INSERT INTO t1 VALUES(1, 'two'); INSERT INTO t1 VALUES(2, 'five'); INSERT INTO t1 VALUES(3, 'one'); INSERT INTO t1 VALUES(4, 'three'); } { {UPDATE t1 0 X. {i 1 t two} {{} {} t one}} {UPDATE t1 0 X. {i 2 t five} {{} {} t two}} {UPDATE t1 0 X. {i 3 t one} {{} {} t three}} {UPDATE t1 0 X. {i 4 t three} {{} {} t four}} } finish_test |
Added ext/session/sessionmem.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 | # 2020 December 23 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for the SQLite sessions module # Specifically, for the sqlite3session_memory_used() API. # if {![info exists testdir]} { set testdir [file join [file dirname [info script]] .. .. test] } source [file join [file dirname [info script]] session_common.tcl] source $testdir/tester.tcl ifcapable !session {finish_test; return} set testprefix sessionmem do_execsql_test 1.0 { CREATE TABLE t1(i INTEGER PRIMARY KEY, x, y); CREATE TABLE t2(i INTEGER, x, y, PRIMARY KEY(x, y)); } do_test 1.1 { sqlite3session S db main S attach * } {} foreach {tn sql eRes} { 1 { INSERT INTO t1 VALUES(1, 2, 3) } 1 2 { UPDATE t1 SET x=5 } 0 3 { UPDATE t1 SET i=5 } 1 4 { DELETE FROM t1 } 0 5 { INSERT INTO t1 VALUES(1, 2, 3) } 0 6 { INSERT INTO t1 VALUES(5, 2, 3) } 0 7 { INSERT INTO t2 VALUES('a', 'b', 'c') } 1 8 { INSERT INTO t2 VALUES('d', 'e', 'f') } 1 9 { UPDATE t2 SET i='e' } 0 } { set mem1 [S memory_used] do_test 1.2.$tn.(mu=$mem1) { execsql $sql set mem2 [S memory_used] expr {$mem2 > $mem1} } $eRes } do_test 1.3 { S delete } {} finish_test |
Added ext/session/sessionnoop.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 | # 2021 Februar 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. # if {![info exists testdir]} { set testdir [file join [file dirname [info script]] .. .. test] } source [file join [file dirname [info script]] session_common.tcl] source $testdir/tester.tcl ifcapable !session {finish_test; return} set testprefix sessionnoop #------------------------------------------------------------------------- # Test plan: # # 1.*: Test that concatenating changesets cannot produce a noop UPDATE. # 2.*: Test that rebasing changesets cannot produce a noop UPDATE. # 3.*: Test that sqlite3changeset_apply() ignores noop UPDATE changes. # do_execsql_test 1.0 { CREATE TABLE t1(a PRIMARY KEY, b, c, d); INSERT INTO t1 VALUES(1, 1, 1, 1); INSERT INTO t1 VALUES(2, 2, 2, 2); INSERT INTO t1 VALUES(3, 3, 3, 3); } proc do_concat_test {tn sql1 sql2 res} { uplevel [list do_test $tn [subst -nocommands { set C1 [changeset_from_sql {$sql1}] set C2 [changeset_from_sql {$sql2}] set C3 [sqlite3changeset_concat [set C1] [set C2]] set got [list] sqlite3session_foreach elem [set C3] { lappend got [set elem] } set got }] [list {*}$res]] } do_concat_test 1.1 { UPDATE t1 SET c=c+1; } { UPDATE t1 SET c=c-1; } { } #------------------------------------------------------------------------- reset_db do_execsql_test 2.0 { CREATE TABLE t1(a PRIMARY KEY, b, c); INSERT INTO t1 VALUES(1, 1, 1); INSERT INTO t1 VALUES(2, 2, 2); INSERT INTO t1 VALUES(3, 3, 3); } proc do_rebase_test {tn sql_local sql_remote conflict_res expected} { proc xConflict {args} [list return $conflict_res] uplevel [list \ do_test $tn [subst -nocommands { execsql BEGIN set c_remote [changeset_from_sql {$sql_remote}] execsql ROLLBACK execsql BEGIN set c_local [changeset_from_sql {$sql_local}] set base [sqlite3changeset_apply_v2 db [set c_remote] xConflict] execsql ROLLBACK sqlite3rebaser_create R R config [set base] set res [list] sqlite3session_foreach elem [R rebase [set c_local]] { lappend res [set elem] } R delete set res }] [list {*}$expected] ] } do_rebase_test 2.1 { UPDATE t1 SET c=2 WHERE a=1; -- local } { UPDATE t1 SET c=3 WHERE a=1; -- remote } OMIT { {UPDATE t1 0 X.. {i 1 {} {} i 3} {{} {} {} {} i 2}} } do_rebase_test 2.2 { UPDATE t1 SET c=2 WHERE a=1; -- local } { UPDATE t1 SET c=3 WHERE a=1; -- remote } REPLACE { } do_rebase_test 2.3.1 { UPDATE t1 SET c=4 WHERE a=1; -- local } { UPDATE t1 SET c=4 WHERE a=1 -- remote } OMIT { {UPDATE t1 0 X.. {i 1 {} {} i 4} {{} {} {} {} i 4}} } do_rebase_test 2.3.2 { UPDATE t1 SET c=5 WHERE a=1; -- local } { UPDATE t1 SET c=5 WHERE a=1 -- remote } REPLACE { } #------------------------------------------------------------------------- # reset_db do_execsql_test 3.0 { CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c); INSERT INTO t1 VALUES(1, 1, 1); INSERT INTO t1 VALUES(2, 2, 2); INSERT INTO t1 VALUES(3, 3, 3); INSERT INTO t1 VALUES(4, 4, 4); } # Arg $pkstr contains one character for each column in the table. An # "X" for PK column, or a "." for a non-PK. # proc mk_tbl_header {name pkstr} { set ret [binary format H2c 54 [string length $pkstr]] foreach i [split $pkstr {}] { if {$i=="X"} { append ret [binary format H2 01] } else { if {$i!="."} {error "bad pkstr: $pkstr ($i)"} append ret [binary format H2 00] } } append ret $name append ret [binary format H2 00] set ret } proc mk_update_change {args} { set ret [binary format H2H2 17 00] foreach a $args { if {$a==""} { append ret [binary format H2 00] } else { append ret [binary format H2W 01 $a] } } set ret } proc xConflict {args} { return "ABORT" } do_test 3.1 { set C [mk_tbl_header t1 X..] append C [mk_update_change 1 {} 1 {} {} 500] append C [mk_update_change 2 {} {} {} {} {}] append C [mk_update_change 3 3 {} {} 600 {}] append C [mk_update_change 4 {} {} {} {} {}] sqlite3changeset_apply_v2 db $C xConflict } {} do_execsql_test 3.2 { SELECT * FROM t1 } { 1 1 500 2 2 2 3 600 3 4 4 4 } finish_test |
Added ext/session/sessionsize.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 | # 2021 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. # if {![info exists testdir]} { set testdir [file join [file dirname [info script]] .. .. test] } source [file join [file dirname [info script]] session_common.tcl] source $testdir/tester.tcl ifcapable !session {finish_test; return} set testprefix sessionsize proc do_changeset_size_test {tn sql} { sqlite3session S db main S attach * db eval $sql set sz [S changeset_size] set C [S changeset] set szC [string length $C] S delete do_test $tn "expr $sz" $szC } do_execsql_test 1.0 { CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c); INSERT INTO t1 VALUES(1, 'abc', 'def'); INSERT INTO t1 VALUES(2, 'ghi', 'jkl'); } do_changeset_size_test 1.1 { INSERT INTO t1 VALUES(3, 'hello', 'world'); } do_changeset_size_test 1.2 { DELETE FROM t1 WHERE a=2; } do_changeset_size_test 1.3 { DELETE FROM t1 WHERE a=3; INSERT INTO t1 VALUES(3, 1, 2); } do_changeset_size_test 1.4 { UPDATE t1 SET c='hello world' WHERE a=3; } #------------------------------------------------------------------------- do_execsql_test 2.0 { CREATE TABlE t2(a, b, c, d, PRIMARY KEY(a, b)) WITHOUT ROWID; CREATE TABlE t3(a, b, c, d PRIMARY KEY); } do_changeset_size_test 2.1 { WITH s(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<50 ) INSERT INTO t2 SELECT i, i+1, i+2, i+3 FROM s; UPDATE t2 SET c=randomblob(a) WHERE a>10 } do_changeset_size_test 2.2 { DELETE FROM t2 WHERE a=1; INSERT INTO t2 VALUES(1, 4, 3, 4); } do_changeset_size_test 2.2 { UPDATE t2 SET b=4 WHERE a=2 } do_changeset_size_test 2.3 { INSERT INTO t2 VALUES('a', 'b', 'c', 'd'); UPDATE t2 SET c='qwertyuiop' WHERE a='a'; } do_changeset_size_test 2.4 { DELETE FROM t2 WHERE a='a'; INSERT INTO t2 VALUES('a', 'b', 'c', 'd'); } do_changeset_size_test 2.5 { UPDATE t2 SET a='aa', b='bb' WHERE (a, b) = ('a', 'b'); } do_changeset_size_test 2.6 { UPDATE t2 SET a='a', b='b' WHERE (a, b) = ('aa', 'bb'); } do_changeset_size_test 2.7 { INSERT INTO t3 DEFAULT VALUES; INSERT INTO t3 VALUES(1,2,3,4); } #------------------------------------------------------------------------- reset_db do_execsql_test 3.0 { CREATE TABLE t1(a INTEGER PRIMARY KEY, b); } do_test 3.1 { sqlite3session S db main S object_config_size -1 } 1 do_test 3.2.1 { S object_config_size 0 } 0 do_test 3.2.2 { S object_config_size -1 } 0 do_test 3.2.3 { S object_config_size 1 } 1 do_test 3.2.4 { S object_config_size -1 } 1 do_test 3.3 { S attach t1 } {} do_test 3.4 { S object_config_size 1 } {SQLITE_MISUSE} do_test 3.4 { S object_config_size -1 } {1} S delete finish_test |
Changes to ext/session/sessionwor.test.
︙ | ︙ | |||
26 27 28 29 30 31 32 | catch { db close } catch { db2 close } forcedelete test.db test.db2 sqlite3 db test.db sqlite3 db2 test.db2 } | | | | > > | > | | | | | | | | | | | | | | > > > > > > | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | catch { db close } catch { db2 close } forcedelete test.db test.db2 sqlite3 db test.db sqlite3 db2 test.db2 } foreach {tn wo} { 1 "" 2 "WITHOUT ROWID" } { reset_db do_execsql_test 1.$tn.0 "CREATE TABLE t1(a PRIMARY KEY, b) $wo ;" do_iterator_test 1.$tn.1 t1 { INSERT INTO t1 VALUES('one', 'two'); } { {INSERT t1 0 X. {} {t one t two}} } do_iterator_test 1.$tn.2 t1 { UPDATE t1 SET b='three' } { {UPDATE t1 0 X. {t one t two} {{} {} t three}} } do_iterator_test 1.$tn.3 t1 { REPLACE INTO t1 VALUES('one', 'four'); } { {UPDATE t1 0 X. {t one t three} {{} {} t four}} } do_iterator_test 1.$tn.4 t1 { DELETE FROM t1; } { {DELETE t1 0 X. {t one t four} {}} } } foreach {tn wo} { 1 "" 2 "WITHOUT ROWID" } { reset_db do_execsql_test 2.$tn.0.1 "CREATE TABLE t1(a INTEGER PRIMARY KEY, b) $wo ;" do_execsql_test 2.$tn.0.2 "CREATE TABLE t2(a INTEGER PRIMARY KEY, b) $wo ;" do_execsql_test 2.$tn.0.3 "CREATE TABLE t3(a INTEGER PRIMARY KEY, b) $wo ;" do_iterator_test 1.1 t1 { INSERT INTO t1 VALUES(1, 'two'); } { {INSERT t1 0 X. {} {i 1 t two}} } do_iterator_test 2.$tn.2 t1 { UPDATE t1 SET b='three' } { {UPDATE t1 0 X. {i 1 t two} {{} {} t three}} } do_iterator_test 2.$tn.3 t1 { REPLACE INTO t1 VALUES(1, 'four'); } { {UPDATE t1 0 X. {i 1 t three} {{} {} t four}} } do_iterator_test 2.$tn.4 t1 { DELETE FROM t1; } { {DELETE t1 0 X. {i 1 t four} {}} } do_execsql_test 2.$tn.5 { INSERT INTO t1 VALUES(1, 'one'); INSERT INTO t1 VALUES(2, 'two'); INSERT INTO t1 VALUES(3, 'three'); } do_iterator_test 2.$tn.6 t2 { INSERT INTO t2 SELECT a, b FROM t1 } { {INSERT t2 0 X. {} {i 1 t one}} {INSERT t2 0 X. {} {i 2 t two}} {INSERT t2 0 X. {} {i 3 t three}} } do_iterator_test 2.$tn.7 t3 { INSERT INTO t3 SELECT * FROM t1 } { {INSERT t3 0 X. {} {i 1 t one}} {INSERT t3 0 X. {} {i 2 t two}} {INSERT t3 0 X. {} {i 3 t three}} } } finish_test |
Changes to ext/session/sqlite3session.c.
︙ | ︙ | |||
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | /* ** Session handle structure. */ struct sqlite3_session { sqlite3 *db; /* Database handle session is attached to */ char *zDb; /* Name of database session is attached to */ int bEnable; /* True if currently recording */ int bIndirect; /* True if all changes are indirect */ int bAutoAttach; /* True to auto-attach tables */ int rc; /* Non-zero if an error has occurred */ void *pFilterCtx; /* First argument to pass to xTableFilter */ int (*xTableFilter)(void *pCtx, const char *zTab); sqlite3_value *pZeroBlob; /* Value containing X'' */ sqlite3_session *pNext; /* Next session object on same db. */ SessionTable *pTable; /* List of attached tables */ SessionHook hook; /* APIs to grab new and old data with */ }; /* | > > > | 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | /* ** Session handle structure. */ struct sqlite3_session { sqlite3 *db; /* Database handle session is attached to */ char *zDb; /* Name of database session is attached to */ int bEnableSize; /* True if changeset_size() enabled */ int bEnable; /* True if currently recording */ int bIndirect; /* True if all changes are indirect */ int bAutoAttach; /* True to auto-attach tables */ int rc; /* Non-zero if an error has occurred */ void *pFilterCtx; /* First argument to pass to xTableFilter */ int (*xTableFilter)(void *pCtx, const char *zTab); i64 nMalloc; /* Number of bytes of data allocated */ i64 nMaxChangesetSize; sqlite3_value *pZeroBlob; /* Value containing X'' */ sqlite3_session *pNext; /* Next session object on same db. */ SessionTable *pTable; /* List of attached tables */ SessionHook hook; /* APIs to grab new and old data with */ }; /* |
︙ | ︙ | |||
93 94 95 96 97 98 99 100 101 102 103 104 105 106 | ** Structure for changeset iterators. */ struct sqlite3_changeset_iter { SessionInput in; /* Input buffer or stream */ SessionBuffer tblhdr; /* Buffer to hold apValue/zTab/abPK/ */ int bPatchset; /* True if this is a patchset */ int bInvert; /* True to invert changeset */ int rc; /* Iterator error code */ sqlite3_stmt *pConflict; /* Points to conflicting row, if any */ char *zTab; /* Current table */ int nCol; /* Number of columns in zTab */ int op; /* Current operation */ int bIndirect; /* True if current change was indirect */ u8 *abPK; /* Primary key array */ | > | 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 | ** Structure for changeset iterators. */ struct sqlite3_changeset_iter { SessionInput in; /* Input buffer or stream */ SessionBuffer tblhdr; /* Buffer to hold apValue/zTab/abPK/ */ int bPatchset; /* True if this is a patchset */ int bInvert; /* True to invert changeset */ int bSkipEmpty; /* Skip noop UPDATE changes */ int rc; /* Iterator error code */ sqlite3_stmt *pConflict; /* Points to conflicting row, if any */ char *zTab; /* Current table */ int nCol; /* Number of columns in zTab */ int op; /* Current operation */ int bIndirect; /* True if current change was indirect */ u8 *abPK; /* Primary key array */ |
︙ | ︙ | |||
292 293 294 295 296 297 298 | */ /* ** For each row modified during a session, there exists a single instance of ** this structure stored in a SessionTable.aChange[] hash table. */ struct SessionChange { | | | > | 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 | */ /* ** For each row modified during a session, there exists a single instance of ** this structure stored in a SessionTable.aChange[] hash table. */ struct SessionChange { u8 op; /* One of UPDATE, DELETE, INSERT */ u8 bIndirect; /* True if this change is "indirect" */ int nMaxSize; /* Max size of eventual changeset record */ int nRecord; /* Number of bytes in buffer aRecord[] */ u8 *aRecord; /* Buffer containing old.* record */ SessionChange *pNext; /* For hash-table collisions */ }; /* ** Write a varint with value iVal into the buffer at aBuf. Return the |
︙ | ︙ | |||
366 367 368 369 370 371 372 | ** If no error occurs, SQLITE_OK is returned. Or, if an OOM error occurs ** within a call to sqlite3_value_text() (may fail if the db is utf-16)) ** SQLITE_NOMEM is returned. */ static int sessionSerializeValue( u8 *aBuf, /* If non-NULL, write serialized value here */ sqlite3_value *pValue, /* Value to serialize */ | | | 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 | ** If no error occurs, SQLITE_OK is returned. Or, if an OOM error occurs ** within a call to sqlite3_value_text() (may fail if the db is utf-16)) ** SQLITE_NOMEM is returned. */ static int sessionSerializeValue( u8 *aBuf, /* If non-NULL, write serialized value here */ sqlite3_value *pValue, /* Value to serialize */ sqlite3_int64 *pnWrite /* IN/OUT: Increment by bytes written */ ){ int nByte; /* Size of serialized value in bytes */ if( pValue ){ int eType; /* Value type (SQLITE_NULL, TEXT etc.) */ eType = sqlite3_value_type(pValue); |
︙ | ︙ | |||
418 419 420 421 422 423 424 | } n = sqlite3_value_bytes(pValue); if( z==0 && (eType!=SQLITE_BLOB || n>0) ) return SQLITE_NOMEM; nVarint = sessionVarintLen(n); if( aBuf ){ sessionVarintPut(&aBuf[1], n); | | > > > > > > > > > > > > > > > > > > > > | 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 | } n = sqlite3_value_bytes(pValue); if( z==0 && (eType!=SQLITE_BLOB || n>0) ) return SQLITE_NOMEM; nVarint = sessionVarintLen(n); if( aBuf ){ sessionVarintPut(&aBuf[1], n); if( n>0 ) memcpy(&aBuf[nVarint + 1], z, n); } nByte = 1 + nVarint + n; break; } } }else{ nByte = 1; if( aBuf ) aBuf[0] = '\0'; } if( pnWrite ) *pnWrite += nByte; return SQLITE_OK; } /* ** Allocate and return a pointer to a buffer nByte bytes in size. If ** pSession is not NULL, increase the sqlite3_session.nMalloc variable ** by the number of bytes allocated. */ static void *sessionMalloc64(sqlite3_session *pSession, i64 nByte){ void *pRet = sqlite3_malloc64(nByte); if( pSession ) pSession->nMalloc += sqlite3_msize(pRet); return pRet; } /* ** Free buffer pFree, which must have been allocated by an earlier ** call to sessionMalloc64(). If pSession is not NULL, decrease the ** sqlite3_session.nMalloc counter by the number of bytes freed. */ static void sessionFree(sqlite3_session *pSession, void *pFree){ if( pSession ) pSession->nMalloc -= sqlite3_msize(pFree); sqlite3_free(pFree); } /* ** This macro is used to calculate hash key values for data structures. In ** order to use this macro, the entire data structure must be represented ** as a series of unsigned integers. In order to calculate a hash-key value ** for a data structure represented as three such integers, the macro may ** then be used as follows: |
︙ | ︙ | |||
901 902 903 904 905 906 907 | ** SQLITE_OK. ** ** It is possible that a non-fatal OOM error occurs in this function. In ** that case the hash-table does not grow, but SQLITE_OK is returned anyway. ** Growing the hash table in this case is a performance optimization only, ** it is not required for correct operation. */ | | > > > > | | > > | | 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 | ** SQLITE_OK. ** ** It is possible that a non-fatal OOM error occurs in this function. In ** that case the hash-table does not grow, but SQLITE_OK is returned anyway. ** Growing the hash table in this case is a performance optimization only, ** it is not required for correct operation. */ static int sessionGrowHash( sqlite3_session *pSession, /* For memory accounting. May be NULL */ int bPatchset, SessionTable *pTab ){ if( pTab->nChange==0 || pTab->nEntry>=(pTab->nChange/2) ){ int i; SessionChange **apNew; sqlite3_int64 nNew = 2*(sqlite3_int64)(pTab->nChange ? pTab->nChange : 128); apNew = (SessionChange**)sessionMalloc64( pSession, sizeof(SessionChange*) * nNew ); if( apNew==0 ){ if( pTab->nChange==0 ){ return SQLITE_ERROR; } return SQLITE_OK; } memset(apNew, 0, sizeof(SessionChange *) * nNew); for(i=0; i<pTab->nChange; i++){ SessionChange *p; SessionChange *pNext; for(p=pTab->apChange[i]; p; p=pNext){ int bPkOnly = (p->op==SQLITE_DELETE && bPatchset); int iHash = sessionChangeHash(pTab, bPkOnly, p->aRecord, nNew); pNext = p->pNext; p->pNext = apNew[iHash]; apNew[iHash] = p; } } sessionFree(pSession, pTab->apChange); pTab->nChange = nNew; pTab->apChange = apNew; } return SQLITE_OK; } |
︙ | ︙ | |||
962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 | ** *pazCol = {"w", "x", "y", "z"} ** *pabPK = {1, 0, 0, 1} ** ** All returned buffers are part of the same single allocation, which must ** be freed using sqlite3_free() by the caller */ static int sessionTableInfo( sqlite3 *db, /* Database connection */ const char *zDb, /* Name of attached database (e.g. "main") */ const char *zThis, /* Table name */ int *pnCol, /* OUT: number of columns */ const char **pzTab, /* OUT: Copy of zThis */ const char ***pazCol, /* OUT: Array of column names for table */ u8 **pabPK /* OUT: Array of booleans - true for PK col */ ){ char *zPragma; sqlite3_stmt *pStmt; int rc; | > | | 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 | ** *pazCol = {"w", "x", "y", "z"} ** *pabPK = {1, 0, 0, 1} ** ** All returned buffers are part of the same single allocation, which must ** be freed using sqlite3_free() by the caller */ static int sessionTableInfo( sqlite3_session *pSession, /* For memory accounting. May be NULL */ sqlite3 *db, /* Database connection */ const char *zDb, /* Name of attached database (e.g. "main") */ const char *zThis, /* Table name */ int *pnCol, /* OUT: number of columns */ const char **pzTab, /* OUT: Copy of zThis */ const char ***pazCol, /* OUT: Array of column names for table */ u8 **pabPK /* OUT: Array of booleans - true for PK col */ ){ char *zPragma; sqlite3_stmt *pStmt; int rc; sqlite3_int64 nByte; int nDbCol = 0; int nThis; int i; u8 *pAlloc = 0; char **azCol = 0; u8 *abPK = 0; |
︙ | ︙ | |||
996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 | "SELECT 0, 'tbl', '', 0, '', 1 UNION ALL " "SELECT 1, 'idx', '', 0, '', 2 UNION ALL " "SELECT 2, 'stat', '', 0, '', 0" ); }else if( rc==SQLITE_ERROR ){ zPragma = sqlite3_mprintf(""); }else{ return rc; } }else{ zPragma = sqlite3_mprintf("PRAGMA '%q'.table_info('%q')", zDb, zThis); } | > > > > | > > > > > > | > > > > > > | | 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 | "SELECT 0, 'tbl', '', 0, '', 1 UNION ALL " "SELECT 1, 'idx', '', 0, '', 2 UNION ALL " "SELECT 2, 'stat', '', 0, '', 0" ); }else if( rc==SQLITE_ERROR ){ zPragma = sqlite3_mprintf(""); }else{ *pazCol = 0; *pabPK = 0; *pnCol = 0; if( pzTab ) *pzTab = 0; return rc; } }else{ zPragma = sqlite3_mprintf("PRAGMA '%q'.table_info('%q')", zDb, zThis); } if( !zPragma ){ *pazCol = 0; *pabPK = 0; *pnCol = 0; if( pzTab ) *pzTab = 0; return SQLITE_NOMEM; } rc = sqlite3_prepare_v2(db, zPragma, -1, &pStmt, 0); sqlite3_free(zPragma); if( rc!=SQLITE_OK ){ *pazCol = 0; *pabPK = 0; *pnCol = 0; if( pzTab ) *pzTab = 0; return rc; } nByte = nThis + 1; while( SQLITE_ROW==sqlite3_step(pStmt) ){ nByte += sqlite3_column_bytes(pStmt, 1); nDbCol++; } rc = sqlite3_reset(pStmt); if( rc==SQLITE_OK ){ nByte += nDbCol * (sizeof(const char *) + sizeof(u8) + 1); pAlloc = sessionMalloc64(pSession, nByte); if( pAlloc==0 ){ rc = SQLITE_NOMEM; } } if( rc==SQLITE_OK ){ azCol = (char **)pAlloc; pAlloc = (u8 *)&azCol[nDbCol]; |
︙ | ︙ | |||
1059 1060 1061 1062 1063 1064 1065 | *pabPK = abPK; *pnCol = nDbCol; }else{ *pazCol = 0; *pabPK = 0; *pnCol = 0; if( pzTab ) *pzTab = 0; | | | 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 | *pabPK = abPK; *pnCol = nDbCol; }else{ *pazCol = 0; *pabPK = 0; *pnCol = 0; if( pzTab ) *pzTab = 0; sessionFree(pSession, azCol); } sqlite3_finalize(pStmt); return rc; } /* ** This function is only called from within a pre-update handler for a |
︙ | ︙ | |||
1081 1082 1083 1084 1085 1086 1087 | ** indicate that updates on this table should be ignored. SessionTable.abPK ** is set to NULL in this case. */ static int sessionInitTable(sqlite3_session *pSession, SessionTable *pTab){ if( pTab->nCol==0 ){ u8 *abPK; assert( pTab->azCol==0 || pTab->abPK==0 ); | | > > > > > > | 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 | ** indicate that updates on this table should be ignored. SessionTable.abPK ** is set to NULL in this case. */ static int sessionInitTable(sqlite3_session *pSession, SessionTable *pTab){ if( pTab->nCol==0 ){ u8 *abPK; assert( pTab->azCol==0 || pTab->abPK==0 ); pSession->rc = sessionTableInfo(pSession, pSession->db, pSession->zDb, pTab->zName, &pTab->nCol, 0, &pTab->azCol, &abPK ); if( pSession->rc==SQLITE_OK ){ int i; for(i=0; i<pTab->nCol; i++){ if( abPK[i] ){ pTab->abPK = abPK; break; } } if( 0==sqlite3_stricmp("sqlite_stat1", pTab->zName) ){ pTab->bStat1 = 1; } if( pSession->bEnableSize ){ pSession->nMaxChangesetSize += ( 1 + sessionVarintLen(pTab->nCol) + pTab->nCol + strlen(pTab->zName)+1 ); } } } return (pSession->rc || pTab->abPK==0); } /* ** Versions of the four methods in object SessionHook for use with the |
︙ | ︙ | |||
1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 | return p->hook.xCount(p->hook.pCtx); } static int sessionStat1Depth(void *pCtx){ SessionStat1Ctx *p = (SessionStat1Ctx*)pCtx; return p->hook.xDepth(p->hook.pCtx); } /* ** This function is only called from with a pre-update-hook reporting a ** change on table pTab (attached to session pSession). The type of change ** (UPDATE, INSERT, DELETE) is specified by the first argument. ** ** Unless one is already present or an error occurs, an entry is added | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | return p->hook.xCount(p->hook.pCtx); } static int sessionStat1Depth(void *pCtx){ SessionStat1Ctx *p = (SessionStat1Ctx*)pCtx; return p->hook.xDepth(p->hook.pCtx); } static int sessionUpdateMaxSize( int op, sqlite3_session *pSession, /* Session object pTab is attached to */ SessionTable *pTab, /* Table that change applies to */ SessionChange *pC /* Update pC->nMaxSize */ ){ i64 nNew = 2; if( pC->op==SQLITE_INSERT ){ if( op!=SQLITE_DELETE ){ int ii; for(ii=0; ii<pTab->nCol; ii++){ sqlite3_value *p = 0; pSession->hook.xNew(pSession->hook.pCtx, ii, &p); sessionSerializeValue(0, p, &nNew); } } }else if( op==SQLITE_DELETE ){ nNew += pC->nRecord; if( sqlite3_preupdate_blobwrite(pSession->db)>=0 ){ nNew += pC->nRecord; } }else{ int ii; u8 *pCsr = pC->aRecord; for(ii=0; ii<pTab->nCol; ii++){ int bChanged = 1; int nOld = 0; int eType; sqlite3_value *p = 0; pSession->hook.xNew(pSession->hook.pCtx, ii, &p); if( p==0 ){ return SQLITE_NOMEM; } eType = *pCsr++; switch( eType ){ case SQLITE_NULL: bChanged = sqlite3_value_type(p)!=SQLITE_NULL; break; case SQLITE_FLOAT: case SQLITE_INTEGER: { if( eType==sqlite3_value_type(p) ){ sqlite3_int64 iVal = sessionGetI64(pCsr); if( eType==SQLITE_INTEGER ){ bChanged = (iVal!=sqlite3_value_int64(p)); }else{ double dVal; memcpy(&dVal, &iVal, 8); bChanged = (dVal!=sqlite3_value_double(p)); } } nOld = 8; pCsr += 8; break; } default: { int nByte; nOld = sessionVarintGet(pCsr, &nByte); pCsr += nOld; nOld += nByte; assert( eType==SQLITE_TEXT || eType==SQLITE_BLOB ); if( eType==sqlite3_value_type(p) && nByte==sqlite3_value_bytes(p) && (nByte==0 || 0==memcmp(pCsr, sqlite3_value_blob(p), nByte)) ){ bChanged = 0; } pCsr += nByte; break; } } if( bChanged && pTab->abPK[ii] ){ nNew = pC->nRecord + 2; break; } if( bChanged ){ nNew += 1 + nOld; sessionSerializeValue(0, p, &nNew); }else if( pTab->abPK[ii] ){ nNew += 2 + nOld; }else{ nNew += 2; } } } if( nNew>pC->nMaxSize ){ int nIncr = nNew - pC->nMaxSize; pC->nMaxSize = nNew; pSession->nMaxChangesetSize += nIncr; } return SQLITE_OK; } /* ** This function is only called from with a pre-update-hook reporting a ** change on table pTab (attached to session pSession). The type of change ** (UPDATE, INSERT, DELETE) is specified by the first argument. ** ** Unless one is already present or an error occurs, an entry is added |
︙ | ︙ | |||
1172 1173 1174 1175 1176 1177 1178 | ** number of columns in the table. */ if( pTab->nCol!=pSession->hook.xCount(pSession->hook.pCtx) ){ pSession->rc = SQLITE_SCHEMA; return; } /* Grow the hash table if required */ | | | 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 | ** number of columns in the table. */ if( pTab->nCol!=pSession->hook.xCount(pSession->hook.pCtx) ){ pSession->rc = SQLITE_SCHEMA; return; } /* Grow the hash table if required */ if( sessionGrowHash(pSession, 0, pTab) ){ pSession->rc = SQLITE_NOMEM; return; } if( pTab->bStat1 ){ stat1.hook = pSession->hook; stat1.pSession = pSession; |
︙ | ︙ | |||
1213 1214 1215 1216 1217 1218 1219 | if( sessionPreupdateEqual(pSession, pTab, pC, op) ) break; } if( pC==0 ){ /* Create a new change object containing all the old values (if ** this is an SQLITE_UPDATE or SQLITE_DELETE), or just the PK ** values (if this is an INSERT). */ | < | | 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 | if( sessionPreupdateEqual(pSession, pTab, pC, op) ) break; } if( pC==0 ){ /* Create a new change object containing all the old values (if ** this is an SQLITE_UPDATE or SQLITE_DELETE), or just the PK ** values (if this is an INSERT). */ sqlite3_int64 nByte; /* Number of bytes to allocate */ int i; /* Used to iterate through columns */ assert( rc==SQLITE_OK ); pTab->nEntry++; /* Figure out how large an allocation is required */ nByte = sizeof(SessionChange); |
︙ | ︙ | |||
1239 1240 1241 1242 1243 1244 1245 | /* This may fail if SQLite value p contains a utf-16 string that must ** be converted to utf-8 and an OOM error occurs while doing so. */ rc = sessionSerializeValue(0, p, &nByte); if( rc!=SQLITE_OK ) goto error_out; } /* Allocate the change object */ | | | | | | | | | | | | > > > > > > | 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 | /* This may fail if SQLite value p contains a utf-16 string that must ** be converted to utf-8 and an OOM error occurs while doing so. */ rc = sessionSerializeValue(0, p, &nByte); if( rc!=SQLITE_OK ) goto error_out; } /* Allocate the change object */ pC = (SessionChange *)sessionMalloc64(pSession, nByte); if( !pC ){ rc = SQLITE_NOMEM; goto error_out; }else{ memset(pC, 0, sizeof(SessionChange)); pC->aRecord = (u8 *)&pC[1]; } /* Populate the change object. None of the preupdate_old(), ** preupdate_new() or SerializeValue() calls below may fail as all ** required values and encodings have already been cached in memory. ** It is not possible for an OOM to occur in this block. */ nByte = 0; for(i=0; i<pTab->nCol; i++){ sqlite3_value *p = 0; if( op!=SQLITE_INSERT ){ pSession->hook.xOld(pSession->hook.pCtx, i, &p); }else if( pTab->abPK[i] ){ pSession->hook.xNew(pSession->hook.pCtx, i, &p); } sessionSerializeValue(&pC->aRecord[nByte], p, &nByte); } /* Add the change to the hash-table */ if( pSession->bIndirect || pSession->hook.xDepth(pSession->hook.pCtx) ){ pC->bIndirect = 1; } pC->nRecord = nByte; pC->op = op; pC->pNext = pTab->apChange[iHash]; pTab->apChange[iHash] = pC; }else if( pC->bIndirect ){ /* If the existing change is considered "indirect", but this current ** change is "direct", mark the change object as direct. */ if( pSession->hook.xDepth(pSession->hook.pCtx)==0 && pSession->bIndirect==0 ){ pC->bIndirect = 0; } } assert( rc==SQLITE_OK ); if( pSession->bEnableSize ){ rc = sessionUpdateMaxSize(op, pSession, pTab, pC); } } /* If an error has occurred, mark the session object as failed. */ error_out: if( pTab->bStat1 ){ pSession->hook = stat1.hook; } if( rc!=SQLITE_OK ){ |
︙ | ︙ | |||
1315 1316 1317 1318 1319 1320 1321 | /* If there is a table-filter configured, invoke it. If it returns 0, ** do not automatically add the new table. */ if( pSession->xTableFilter==0 || pSession->xTableFilter(pSession->pFilterCtx, zName) ){ rc = sqlite3session_attach(pSession, zName); if( rc==SQLITE_OK ){ | | > > > > | 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 | /* If there is a table-filter configured, invoke it. If it returns 0, ** do not automatically add the new table. */ if( pSession->xTableFilter==0 || pSession->xTableFilter(pSession->pFilterCtx, zName) ){ rc = sqlite3session_attach(pSession, zName); if( rc==SQLITE_OK ){ pRet = pSession->pTable; while( ALWAYS(pRet) && pRet->pNext ){ pRet = pRet->pNext; } assert( pRet!=0 ); assert( 0==sqlite3_strnicmp(pRet->zName, zName, nName+1) ); } } } assert( rc==SQLITE_OK || pRet==0 ); *ppTab = pRet; |
︙ | ︙ | |||
1612 1613 1614 1615 1616 1617 1618 | /* Check the table schemas match */ if( rc==SQLITE_OK ){ int bHasPk = 0; int bMismatch = 0; int nCol; /* Columns in zFrom.zTbl */ u8 *abPK; const char **azCol = 0; | | > | > | 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 | /* Check the table schemas match */ if( rc==SQLITE_OK ){ int bHasPk = 0; int bMismatch = 0; int nCol; /* Columns in zFrom.zTbl */ u8 *abPK; const char **azCol = 0; rc = sessionTableInfo(0, db, zFrom, zTbl, &nCol, 0, &azCol, &abPK); if( rc==SQLITE_OK ){ if( pTo->nCol!=nCol ){ bMismatch = 1; }else{ int i; for(i=0; i<nCol; i++){ if( pTo->abPK[i]!=abPK[i] ) bMismatch = 1; if( sqlite3_stricmp(azCol[i], pTo->azCol[i]) ) bMismatch = 1; if( abPK[i] ) bHasPk = 1; } } } sqlite3_free((char*)azCol); if( bMismatch ){ if( pzErrMsg ){ *pzErrMsg = sqlite3_mprintf("table schemas do not match"); } rc = SQLITE_SCHEMA; } if( bHasPk==0 ){ /* Ignore tables with no primary keys */ goto diff_out; } } |
︙ | ︙ | |||
1683 1684 1685 1686 1687 1688 1689 | sqlite3_session *pOld; /* Session object already attached to db */ int nDb = sqlite3Strlen30(zDb); /* Length of zDb in bytes */ /* Zero the output value in case an error occurs. */ *ppSession = 0; /* Allocate and populate the new session object. */ | | | 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 | sqlite3_session *pOld; /* Session object already attached to db */ int nDb = sqlite3Strlen30(zDb); /* Length of zDb in bytes */ /* Zero the output value in case an error occurs. */ *ppSession = 0; /* Allocate and populate the new session object. */ pNew = (sqlite3_session *)sqlite3_malloc64(sizeof(sqlite3_session) + nDb + 1); if( !pNew ) return SQLITE_NOMEM; memset(pNew, 0, sizeof(sqlite3_session)); pNew->db = db; pNew->zDb = (char *)&pNew[1]; pNew->bEnable = 1; memcpy(pNew->zDb, zDb, nDb+1); sessionPreupdateHooks(pNew); |
︙ | ︙ | |||
1708 1709 1710 1711 1712 1713 1714 | return SQLITE_OK; } /* ** Free the list of table objects passed as the first argument. The contents ** of the changed-rows hash tables are also deleted. */ | | | | | | | 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 | return SQLITE_OK; } /* ** Free the list of table objects passed as the first argument. The contents ** of the changed-rows hash tables are also deleted. */ static void sessionDeleteTable(sqlite3_session *pSession, SessionTable *pList){ SessionTable *pNext; SessionTable *pTab; for(pTab=pList; pTab; pTab=pNext){ int i; pNext = pTab->pNext; for(i=0; i<pTab->nChange; i++){ SessionChange *p; SessionChange *pNextChange; for(p=pTab->apChange[i]; p; p=pNextChange){ pNextChange = p->pNext; sessionFree(pSession, p); } } sessionFree(pSession, (char*)pTab->azCol); /* cast works around VC++ bug */ sessionFree(pSession, pTab->apChange); sessionFree(pSession, pTab); } } /* ** Delete a session object previously allocated using sqlite3session_create(). */ void sqlite3session_delete(sqlite3_session *pSession){ |
︙ | ︙ | |||
1753 1754 1755 1756 1757 1758 1759 | } } sqlite3_mutex_leave(sqlite3_db_mutex(db)); sqlite3ValueFree(pSession->pZeroBlob); /* Delete all attached table objects. And the contents of their ** associated hash-tables. */ | | > | > | 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 | } } sqlite3_mutex_leave(sqlite3_db_mutex(db)); sqlite3ValueFree(pSession->pZeroBlob); /* Delete all attached table objects. And the contents of their ** associated hash-tables. */ sessionDeleteTable(pSession, pSession->pTable); /* Assert that all allocations have been freed and then free the ** session object itself. */ assert( pSession->nMalloc==0 ); sqlite3_free(pSession); } /* ** Set a table filter on a Session Object. */ void sqlite3session_table_filter( |
︙ | ︙ | |||
1802 1803 1804 1805 1806 1807 1808 | nName = sqlite3Strlen30(zName); for(pTab=pSession->pTable; pTab; pTab=pTab->pNext){ if( 0==sqlite3_strnicmp(pTab->zName, zName, nName+1) ) break; } if( !pTab ){ /* Allocate new SessionTable object. */ | | > | 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 | nName = sqlite3Strlen30(zName); for(pTab=pSession->pTable; pTab; pTab=pTab->pNext){ if( 0==sqlite3_strnicmp(pTab->zName, zName, nName+1) ) break; } if( !pTab ){ /* Allocate new SessionTable object. */ int nByte = sizeof(SessionTable) + nName + 1; pTab = (SessionTable*)sessionMalloc64(pSession, nByte); if( !pTab ){ rc = SQLITE_NOMEM; }else{ /* Populate the new SessionTable object and link it into the list. ** The new object must be linked onto the end of the list, not ** simply added to the start of it in order to ensure that tables ** appear in the correct order when a changeset or patchset is |
︙ | ︙ | |||
1832 1833 1834 1835 1836 1837 1838 | /* ** Ensure that there is room in the buffer to append nByte bytes of data. ** If not, use sqlite3_realloc() to grow the buffer so that there is. ** ** If successful, return zero. Otherwise, if an OOM condition is encountered, ** set *pRc to SQLITE_NOMEM and return non-zero. */ | | > > | > > | > > > > > > > > > > > > | 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 | /* ** Ensure that there is room in the buffer to append nByte bytes of data. ** If not, use sqlite3_realloc() to grow the buffer so that there is. ** ** If successful, return zero. Otherwise, if an OOM condition is encountered, ** set *pRc to SQLITE_NOMEM and return non-zero. */ static int sessionBufferGrow(SessionBuffer *p, i64 nByte, int *pRc){ #define SESSION_MAX_BUFFER_SZ (0x7FFFFF00 - 1) i64 nReq = p->nBuf + nByte; if( *pRc==SQLITE_OK && nReq>p->nAlloc ){ u8 *aNew; i64 nNew = p->nAlloc ? p->nAlloc : 128; do { nNew = nNew*2; }while( nNew<nReq ); /* The value of SESSION_MAX_BUFFER_SZ is copied from the implementation ** of sqlite3_realloc64(). Allocations greater than this size in bytes ** always fail. It is used here to ensure that this routine can always ** allocate up to this limit - instead of up to the largest power of ** two smaller than the limit. */ if( nNew>SESSION_MAX_BUFFER_SZ ){ nNew = SESSION_MAX_BUFFER_SZ; if( nNew<nReq ){ *pRc = SQLITE_NOMEM; return 1; } } aNew = (u8 *)sqlite3_realloc64(p->aBuf, nNew); if( 0==aNew ){ *pRc = SQLITE_NOMEM; }else{ p->aBuf = aNew; p->nAlloc = nNew; |
︙ | ︙ | |||
1862 1863 1864 1865 1866 1867 1868 | ** This function is a no-op if *pRc is non-zero when it is called. ** Otherwise, if an error occurs, *pRc is set to an SQLite error code ** before returning. */ static void sessionAppendValue(SessionBuffer *p, sqlite3_value *pVal, int *pRc){ int rc = *pRc; if( rc==SQLITE_OK ){ | | | 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 | ** This function is a no-op if *pRc is non-zero when it is called. ** Otherwise, if an error occurs, *pRc is set to an SQLite error code ** before returning. */ static void sessionAppendValue(SessionBuffer *p, sqlite3_value *pVal, int *pRc){ int rc = *pRc; if( rc==SQLITE_OK ){ sqlite3_int64 nByte = 0; rc = sessionSerializeValue(0, pVal, &nByte); sessionBufferGrow(p, nByte, &rc); if( rc==SQLITE_OK ){ rc = sessionSerializeValue(&p->aBuf[p->nBuf], pVal, 0); p->nBuf += nByte; }else{ *pRc = rc; |
︙ | ︙ | |||
2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 | int rc = SQLITE_OK; SessionBuffer buf2 = {0,0,0}; /* Buffer to accumulate new.* record in */ int bNoop = 1; /* Set to zero if any values are modified */ int nRewind = pBuf->nBuf; /* Set to zero if any values are modified */ int i; /* Used to iterate through columns */ u8 *pCsr = p->aRecord; /* Used to iterate through old.* values */ sessionAppendByte(pBuf, SQLITE_UPDATE, &rc); sessionAppendByte(pBuf, p->bIndirect, &rc); for(i=0; i<sqlite3_column_count(pStmt); i++){ int bChanged = 0; int nAdvance; int eType = *pCsr; switch( eType ){ | > | 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 | int rc = SQLITE_OK; SessionBuffer buf2 = {0,0,0}; /* Buffer to accumulate new.* record in */ int bNoop = 1; /* Set to zero if any values are modified */ int nRewind = pBuf->nBuf; /* Set to zero if any values are modified */ int i; /* Used to iterate through columns */ u8 *pCsr = p->aRecord; /* Used to iterate through old.* values */ assert( abPK!=0 ); sessionAppendByte(pBuf, SQLITE_UPDATE, &rc); sessionAppendByte(pBuf, p->bIndirect, &rc); for(i=0; i<sqlite3_column_count(pStmt); i++){ int bChanged = 0; int nAdvance; int eType = *pCsr; switch( eType ){ |
︙ | ︙ | |||
2371 2372 2373 2374 2375 2376 2377 | void **ppChangeset /* OUT: Buffer containing changeset */ ){ sqlite3 *db = pSession->db; /* Source database handle */ SessionTable *pTab; /* Used to iterate through attached tables */ SessionBuffer buf = {0,0,0}; /* Buffer in which to accumlate changeset */ int rc; /* Return code */ | | > > | | | | 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 | void **ppChangeset /* OUT: Buffer containing changeset */ ){ sqlite3 *db = pSession->db; /* Source database handle */ SessionTable *pTab; /* Used to iterate through attached tables */ SessionBuffer buf = {0,0,0}; /* Buffer in which to accumlate changeset */ int rc; /* Return code */ assert( xOutput==0 || (pnChangeset==0 && ppChangeset==0) ); assert( xOutput!=0 || (pnChangeset!=0 && ppChangeset!=0) ); /* Zero the output variables in case an error occurs. If this session ** object is already in the error state (sqlite3_session.rc != SQLITE_OK), ** this call will be a no-op. */ if( xOutput==0 ){ assert( pnChangeset!=0 && ppChangeset!=0 ); *pnChangeset = 0; *ppChangeset = 0; } if( pSession->rc ) return pSession->rc; rc = sqlite3_exec(pSession->db, "SAVEPOINT changeset", 0, 0, 0); if( rc!=SQLITE_OK ) return rc; sqlite3_mutex_enter(sqlite3_db_mutex(db)); for(pTab=pSession->pTable; rc==SQLITE_OK && pTab; pTab=pTab->pNext){ if( pTab->nEntry ){ const char *zName = pTab->zName; int nCol = 0; /* Number of columns in table */ u8 *abPK = 0; /* Primary key array */ const char **azCol = 0; /* Table columns */ int i; /* Used to iterate through hash buckets */ sqlite3_stmt *pSel = 0; /* SELECT statement to query table pTab */ int nRewind = buf.nBuf; /* Initial size of write buffer */ int nNoop; /* Size of buffer after writing tbl header */ /* Check the table schema is still Ok. */ rc = sessionTableInfo(0, db, pSession->zDb, zName, &nCol, 0,&azCol,&abPK); if( !rc && (pTab->nCol!=nCol || memcmp(abPK, pTab->abPK, nCol)) ){ rc = SQLITE_SCHEMA; } /* Write a table header */ sessionAppendTableHdr(&buf, ePatchset, pTab, &rc); |
︙ | ︙ | |||
2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 | int iCol; sessionAppendByte(&buf, SQLITE_INSERT, &rc); sessionAppendByte(&buf, p->bIndirect, &rc); for(iCol=0; iCol<nCol; iCol++){ sessionAppendCol(&buf, pSel, iCol, &rc); } }else{ rc = sessionAppendUpdate(&buf, ePatchset, pSel, p, abPK); } }else if( p->op!=SQLITE_INSERT ){ rc = sessionAppendDelete(&buf, ePatchset, p, nCol, abPK); } if( rc==SQLITE_OK ){ rc = sqlite3_reset(pSel); | > | 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 | int iCol; sessionAppendByte(&buf, SQLITE_INSERT, &rc); sessionAppendByte(&buf, p->bIndirect, &rc); for(iCol=0; iCol<nCol; iCol++){ sessionAppendCol(&buf, pSel, iCol, &rc); } }else{ assert( abPK!=0 ); /* Because sessionSelectStmt() returned ok */ rc = sessionAppendUpdate(&buf, ePatchset, pSel, p, abPK); } }else if( p->op!=SQLITE_INSERT ){ rc = sessionAppendDelete(&buf, ePatchset, p, nCol, abPK); } if( rc==SQLITE_OK ){ rc = sqlite3_reset(pSel); |
︙ | ︙ | |||
2489 2490 2491 2492 2493 2494 2495 | ** using sqlite3_free(). */ int sqlite3session_changeset( sqlite3_session *pSession, /* Session object */ int *pnChangeset, /* OUT: Size of buffer at *ppChangeset */ void **ppChangeset /* OUT: Buffer containing changeset */ ){ | > > > | > > > > > > > | 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 | ** using sqlite3_free(). */ int sqlite3session_changeset( sqlite3_session *pSession, /* Session object */ int *pnChangeset, /* OUT: Size of buffer at *ppChangeset */ void **ppChangeset /* OUT: Buffer containing changeset */ ){ int rc; if( pnChangeset==0 || ppChangeset==0 ) return SQLITE_MISUSE; rc = sessionGenerateChangeset( pSession, SESSIONS_CHANGESET, 0, 0, pnChangeset, ppChangeset); assert( rc || pnChangeset==0 || pSession->bEnableSize==0 || *pnChangeset<=pSession->nMaxChangesetSize ); return rc; } /* ** Streaming version of sqlite3session_changeset(). */ int sqlite3session_changeset_strm( sqlite3_session *pSession, int (*xOutput)(void *pOut, const void *pData, int nData), void *pOut ){ if( xOutput==0 ) return SQLITE_MISUSE; return sessionGenerateChangeset( pSession, SESSIONS_CHANGESET, xOutput, pOut, 0, 0); } /* ** Streaming version of sqlite3session_patchset(). */ int sqlite3session_patchset_strm( sqlite3_session *pSession, int (*xOutput)(void *pOut, const void *pData, int nData), void *pOut ){ if( xOutput==0 ) return SQLITE_MISUSE; return sessionGenerateChangeset( pSession, SESSIONS_PATCHSET, xOutput, pOut, 0, 0); } /* ** Obtain a patchset object containing all changes recorded by the ** session object passed as the first argument. ** ** It is the responsibility of the caller to eventually free the buffer ** using sqlite3_free(). */ int sqlite3session_patchset( sqlite3_session *pSession, /* Session object */ int *pnPatchset, /* OUT: Size of buffer at *ppChangeset */ void **ppPatchset /* OUT: Buffer containing changeset */ ){ if( pnPatchset==0 || ppPatchset==0 ) return SQLITE_MISUSE; return sessionGenerateChangeset( pSession, SESSIONS_PATCHSET, 0, 0, pnPatchset, ppPatchset); } int sqlite3session_fullchangeset( sqlite3_session *pSession, /* Session object */ int *pnChangeset, /* OUT: Size of buffer at *ppChangeset */ |
︙ | ︙ | |||
2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 | for(pTab=pSession->pTable; pTab && ret==0; pTab=pTab->pNext){ ret = (pTab->nEntry>0); } sqlite3_mutex_leave(sqlite3_db_mutex(pSession->db)); return (ret==0); } /* ** Do the work for either sqlite3changeset_start() or start_strm(). */ static int sessionChangesetStart( sqlite3_changeset_iter **pp, /* OUT: Changeset iterator handle */ int (*xInput)(void *pIn, void *pData, int *pnData), void *pIn, int nChangeset, /* Size of buffer pChangeset in bytes */ void *pChangeset, /* Pointer to buffer containing changeset */ | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > | | | | | 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 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 | for(pTab=pSession->pTable; pTab && ret==0; pTab=pTab->pNext){ ret = (pTab->nEntry>0); } sqlite3_mutex_leave(sqlite3_db_mutex(pSession->db)); return (ret==0); } /* ** Return the amount of heap memory in use. */ sqlite3_int64 sqlite3session_memory_used(sqlite3_session *pSession){ return pSession->nMalloc; } /* ** Configure the session object passed as the first argument. */ int sqlite3session_object_config(sqlite3_session *pSession, int op, void *pArg){ int rc = SQLITE_OK; switch( op ){ case SQLITE_SESSION_OBJCONFIG_SIZE: { int iArg = *(int*)pArg; if( iArg>=0 ){ if( pSession->pTable ){ rc = SQLITE_MISUSE; }else{ pSession->bEnableSize = (iArg!=0); } } *(int*)pArg = pSession->bEnableSize; break; } default: rc = SQLITE_MISUSE; } return rc; } /* ** Return the maximum size of sqlite3session_changeset() output. */ sqlite3_int64 sqlite3session_changeset_size(sqlite3_session *pSession){ return pSession->nMaxChangesetSize; } /* ** Do the work for either sqlite3changeset_start() or start_strm(). */ static int sessionChangesetStart( sqlite3_changeset_iter **pp, /* OUT: Changeset iterator handle */ int (*xInput)(void *pIn, void *pData, int *pnData), void *pIn, int nChangeset, /* Size of buffer pChangeset in bytes */ void *pChangeset, /* Pointer to buffer containing changeset */ int bInvert, /* True to invert changeset */ int bSkipEmpty /* True to skip empty UPDATE changes */ ){ sqlite3_changeset_iter *pRet; /* Iterator to return */ int nByte; /* Number of bytes to allocate for iterator */ assert( xInput==0 || (pChangeset==0 && nChangeset==0) ); /* Zero the output variable in case an error occurs. */ *pp = 0; /* Allocate and initialize the iterator structure. */ nByte = sizeof(sqlite3_changeset_iter); pRet = (sqlite3_changeset_iter *)sqlite3_malloc(nByte); if( !pRet ) return SQLITE_NOMEM; memset(pRet, 0, sizeof(sqlite3_changeset_iter)); pRet->in.aData = (u8 *)pChangeset; pRet->in.nData = nChangeset; pRet->in.xInput = xInput; pRet->in.pIn = pIn; pRet->in.bEof = (xInput ? 0 : 1); pRet->bInvert = bInvert; pRet->bSkipEmpty = bSkipEmpty; /* Populate the output variable and return success. */ *pp = pRet; return SQLITE_OK; } /* ** Create an iterator used to iterate through the contents of a changeset. */ int sqlite3changeset_start( sqlite3_changeset_iter **pp, /* OUT: Changeset iterator handle */ int nChangeset, /* Size of buffer pChangeset in bytes */ void *pChangeset /* Pointer to buffer containing changeset */ ){ return sessionChangesetStart(pp, 0, 0, nChangeset, pChangeset, 0, 0); } int sqlite3changeset_start_v2( sqlite3_changeset_iter **pp, /* OUT: Changeset iterator handle */ int nChangeset, /* Size of buffer pChangeset in bytes */ void *pChangeset, /* Pointer to buffer containing changeset */ int flags ){ int bInvert = !!(flags & SQLITE_CHANGESETSTART_INVERT); return sessionChangesetStart(pp, 0, 0, nChangeset, pChangeset, bInvert, 0); } /* ** Streaming version of sqlite3changeset_start(). */ int sqlite3changeset_start_strm( sqlite3_changeset_iter **pp, /* OUT: Changeset iterator handle */ int (*xInput)(void *pIn, void *pData, int *pnData), void *pIn ){ return sessionChangesetStart(pp, xInput, pIn, 0, 0, 0, 0); } int sqlite3changeset_start_v2_strm( sqlite3_changeset_iter **pp, /* OUT: Changeset iterator handle */ int (*xInput)(void *pIn, void *pData, int *pnData), void *pIn, int flags ){ int bInvert = !!(flags & SQLITE_CHANGESETSTART_INVERT); return sessionChangesetStart(pp, xInput, pIn, 0, 0, bInvert, 0); } /* ** If the SessionInput object passed as the only argument is a streaming ** object and the buffer is full, discard some data to free up space. */ static void sessionDiscardData(SessionInput *pIn){ |
︙ | ︙ | |||
2752 2753 2754 2755 2756 2757 2758 | int nData, /* Size of buffer aData[] in bytes */ u8 enc /* String encoding (0 for blobs) */ ){ /* In theory this code could just pass SQLITE_TRANSIENT as the final ** argument to sqlite3ValueSetStr() and have the copy created ** automatically. But doing so makes it difficult to detect any OOM ** error. Hence the code to create the copy externally. */ | | | 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 | int nData, /* Size of buffer aData[] in bytes */ u8 enc /* String encoding (0 for blobs) */ ){ /* In theory this code could just pass SQLITE_TRANSIENT as the final ** argument to sqlite3ValueSetStr() and have the copy created ** automatically. But doing so makes it difficult to detect any OOM ** error. Hence the code to create the copy externally. */ u8 *aCopy = sqlite3_malloc64((sqlite3_int64)nData+1); if( aCopy==0 ) return SQLITE_NOMEM; memcpy(aCopy, aData, nData); sqlite3ValueSetStr(pVal, nData, (char*)aCopy, enc, sqlite3_free); return SQLITE_OK; } /* |
︙ | ︙ | |||
2787 2788 2789 2790 2791 2792 2793 | ** If an error occurs, an SQLite error code (e.g. SQLITE_NOMEM) is returned. ** The apOut[] array may have been partially populated in this case. */ static int sessionReadRecord( SessionInput *pIn, /* Input data */ int nCol, /* Number of values in record */ u8 *abPK, /* Array of primary key flags, or NULL */ | | > > > > | 3024 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 | ** If an error occurs, an SQLite error code (e.g. SQLITE_NOMEM) is returned. ** The apOut[] array may have been partially populated in this case. */ static int sessionReadRecord( SessionInput *pIn, /* Input data */ int nCol, /* Number of values in record */ u8 *abPK, /* Array of primary key flags, or NULL */ sqlite3_value **apOut, /* Write values to this array */ int *pbEmpty ){ int i; /* Used to iterate through columns */ int rc = SQLITE_OK; assert( pbEmpty==0 || *pbEmpty==0 ); if( pbEmpty ) *pbEmpty = 1; for(i=0; i<nCol && rc==SQLITE_OK; i++){ int eType = 0; /* Type of value (SQLITE_NULL, TEXT etc.) */ if( abPK && abPK[i]==0 ) continue; rc = sessionInputBuffer(pIn, 9); if( rc==SQLITE_OK ){ if( pIn->iNext>=pIn->nData ){ rc = SQLITE_CORRUPT_BKPT; }else{ eType = pIn->aData[pIn->iNext++]; assert( apOut[i]==0 ); if( eType ){ if( pbEmpty ) *pbEmpty = 0; apOut[i] = sqlite3ValueNew(0); if( !apOut[i] ) rc = SQLITE_NOMEM; } } } if( rc==SQLITE_OK ){ |
︙ | ︙ | |||
2964 2965 2966 2967 2968 2969 2970 | sessionBufferGrow(&p->tblhdr, nByte, &rc); }else{ rc = SQLITE_CORRUPT_BKPT; } } if( rc==SQLITE_OK ){ | | > > > > | | > | < | < < | < < > | < < | | | > > | 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 | sessionBufferGrow(&p->tblhdr, nByte, &rc); }else{ rc = SQLITE_CORRUPT_BKPT; } } if( rc==SQLITE_OK ){ size_t iPK = sizeof(sqlite3_value*)*p->nCol*2; memset(p->tblhdr.aBuf, 0, iPK); memcpy(&p->tblhdr.aBuf[iPK], &p->in.aData[p->in.iNext], nCopy); p->in.iNext += nCopy; } p->apValue = (sqlite3_value**)p->tblhdr.aBuf; if( p->apValue==0 ){ p->abPK = 0; p->zTab = 0; }else{ p->abPK = (u8*)&p->apValue[p->nCol*2]; p->zTab = p->abPK ? (char*)&p->abPK[p->nCol] : 0; } return (p->rc = rc); } /* ** Advance the changeset iterator to the next change. The differences between ** this function and sessionChangesetNext() are that ** ** * If pbEmpty is not NULL and the change is a no-op UPDATE (an UPDATE ** that modifies no columns), this function sets (*pbEmpty) to 1. ** ** * If the iterator is configured to skip no-op UPDATEs, ** sessionChangesetNext() does that. This function does not. */ static int sessionChangesetNextOne( sqlite3_changeset_iter *p, /* Changeset iterator */ u8 **paRec, /* If non-NULL, store record pointer here */ int *pnRec, /* If non-NULL, store size of record here */ int *pbNew, /* If non-NULL, true if new table */ int *pbEmpty ){ int i; u8 op; assert( (paRec==0 && pnRec==0) || (paRec && pnRec) ); assert( pbEmpty==0 || *pbEmpty==0 ); /* If the iterator is in the error-state, return immediately. */ if( p->rc!=SQLITE_OK ) return p->rc; /* Free the current contents of p->apValue[], if any. */ if( p->apValue ){ for(i=0; i<p->nCol*2; i++){ |
︙ | ︙ | |||
3074 3075 3076 3077 3078 3079 3080 | }else{ sqlite3_value **apOld = (p->bInvert ? &p->apValue[p->nCol] : p->apValue); sqlite3_value **apNew = (p->bInvert ? p->apValue : &p->apValue[p->nCol]); /* If this is an UPDATE or DELETE, read the old.* record. */ if( p->op!=SQLITE_INSERT && (p->bPatchset==0 || p->op==SQLITE_DELETE) ){ u8 *abPK = p->bPatchset ? p->abPK : 0; | | | | 3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 | }else{ sqlite3_value **apOld = (p->bInvert ? &p->apValue[p->nCol] : p->apValue); sqlite3_value **apNew = (p->bInvert ? p->apValue : &p->apValue[p->nCol]); /* If this is an UPDATE or DELETE, read the old.* record. */ if( p->op!=SQLITE_INSERT && (p->bPatchset==0 || p->op==SQLITE_DELETE) ){ u8 *abPK = p->bPatchset ? p->abPK : 0; p->rc = sessionReadRecord(&p->in, p->nCol, abPK, apOld, 0); if( p->rc!=SQLITE_OK ) return p->rc; } /* If this is an INSERT or UPDATE, read the new.* record. */ if( p->op!=SQLITE_DELETE ){ p->rc = sessionReadRecord(&p->in, p->nCol, 0, apNew, pbEmpty); if( p->rc!=SQLITE_OK ) return p->rc; } if( (p->bPatchset || p->bInvert) && p->op==SQLITE_UPDATE ){ /* If this is an UPDATE that is part of a patchset, then all PK and ** modified fields are present in the new.* record. The old.* record ** is currently completely empty. This block shifts the PK fields from |
︙ | ︙ | |||
3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 | if( p->op==SQLITE_INSERT ) p->op = SQLITE_DELETE; else if( p->op==SQLITE_DELETE ) p->op = SQLITE_INSERT; } } return SQLITE_ROW; } /* ** Advance an iterator created by sqlite3changeset_start() to the next ** change in the changeset. This function may return SQLITE_ROW, SQLITE_DONE ** or SQLITE_CORRUPT. ** ** This function may not be called on iterators passed to a conflict handler | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 3348 3349 3350 3351 3352 3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 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 | if( p->op==SQLITE_INSERT ) p->op = SQLITE_DELETE; else if( p->op==SQLITE_DELETE ) p->op = SQLITE_INSERT; } } return SQLITE_ROW; } /* ** Advance the changeset iterator to the next change. ** ** If both paRec and pnRec are NULL, then this function works like the public ** API sqlite3changeset_next(). If SQLITE_ROW is returned, then the ** sqlite3changeset_new() and old() APIs may be used to query for values. ** ** Otherwise, if paRec and pnRec are not NULL, then a pointer to the change ** record is written to *paRec before returning and the number of bytes in ** the record to *pnRec. ** ** Either way, this function returns SQLITE_ROW if the iterator is ** successfully advanced to the next change in the changeset, an SQLite ** error code if an error occurs, or SQLITE_DONE if there are no further ** changes in the changeset. */ static int sessionChangesetNext( sqlite3_changeset_iter *p, /* Changeset iterator */ u8 **paRec, /* If non-NULL, store record pointer here */ int *pnRec, /* If non-NULL, store size of record here */ int *pbNew /* If non-NULL, true if new table */ ){ int bEmpty; int rc; do { bEmpty = 0; rc = sessionChangesetNextOne(p, paRec, pnRec, pbNew, &bEmpty); }while( rc==SQLITE_ROW && p->bSkipEmpty && bEmpty); return rc; } /* ** Advance an iterator created by sqlite3changeset_start() to the next ** change in the changeset. This function may return SQLITE_ROW, SQLITE_DONE ** or SQLITE_CORRUPT. ** ** This function may not be called on iterators passed to a conflict handler |
︙ | ︙ | |||
3365 3366 3367 3368 3369 3370 3371 | break; } case SQLITE_UPDATE: { int iCol; if( 0==apVal ){ | | | | | 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 | break; } case SQLITE_UPDATE: { int iCol; if( 0==apVal ){ apVal = (sqlite3_value **)sqlite3_malloc64(sizeof(apVal[0])*nCol*2); if( 0==apVal ){ rc = SQLITE_NOMEM; goto finished_invert; } memset(apVal, 0, sizeof(apVal[0])*nCol*2); } /* Write the header for the new UPDATE change. Same as the original. */ sessionAppendByte(&sOut, eType, &rc); sessionAppendByte(&sOut, pInput->aData[pInput->iNext+1], &rc); /* Read the old.* and new.* records for the update change. */ pInput->iNext += 2; rc = sessionReadRecord(pInput, nCol, 0, &apVal[0], 0); if( rc==SQLITE_OK ){ rc = sessionReadRecord(pInput, nCol, 0, &apVal[nCol], 0); } /* Write the new old.* record. Consists of the PK columns from the ** original old.* record, and the other values from the original ** new.* record. */ for(iCol=0; iCol<nCol; iCol++){ sqlite3_value *pVal = apVal[iCol + (abPK[iCol] ? 0 : nCol)]; |
︙ | ︙ | |||
3425 3426 3427 3428 3429 3430 3431 | rc = xOutput(pOut, sOut.aBuf, sOut.nBuf); sOut.nBuf = 0; if( rc!=SQLITE_OK ) goto finished_invert; } } assert( rc==SQLITE_OK ); | | | | 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 3716 | rc = xOutput(pOut, sOut.aBuf, sOut.nBuf); sOut.nBuf = 0; if( rc!=SQLITE_OK ) goto finished_invert; } } assert( rc==SQLITE_OK ); if( pnInverted && ALWAYS(ppInverted) ){ *pnInverted = sOut.nBuf; *ppInverted = sOut.aBuf; sOut.aBuf = 0; }else if( sOut.nBuf>0 && ALWAYS(xOutput!=0) ){ rc = xOutput(pOut, sOut.aBuf, sOut.nBuf); } finished_invert: sqlite3_free(sOut.aBuf); sqlite3_free(apVal); sqlite3_free(sPK.aBuf); |
︙ | ︙ | |||
3482 3483 3484 3485 3486 3487 3488 3489 3490 3491 3492 | sInput.pIn = pIn; rc = sessionChangesetInvert(&sInput, xOutput, pOut, 0, 0); sqlite3_free(sInput.buf.aBuf); return rc; } typedef struct SessionApplyCtx SessionApplyCtx; struct SessionApplyCtx { sqlite3 *db; sqlite3_stmt *pDelete; /* DELETE statement */ | > > > > > > > > < > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 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 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 3940 3941 3942 3943 3944 3945 3946 3947 3948 3949 3950 3951 3952 3953 3954 3955 3956 | sInput.pIn = pIn; rc = sessionChangesetInvert(&sInput, xOutput, pOut, 0, 0); sqlite3_free(sInput.buf.aBuf); return rc; } typedef struct SessionUpdate SessionUpdate; struct SessionUpdate { sqlite3_stmt *pStmt; u32 *aMask; SessionUpdate *pNext; }; typedef struct SessionApplyCtx SessionApplyCtx; struct SessionApplyCtx { sqlite3 *db; sqlite3_stmt *pDelete; /* DELETE statement */ sqlite3_stmt *pInsert; /* INSERT statement */ sqlite3_stmt *pSelect; /* SELECT statement */ int nCol; /* Size of azCol[] and abPK[] arrays */ const char **azCol; /* Array of column names */ u8 *abPK; /* Boolean array - true if column is in PK */ u32 *aUpdateMask; /* Used by sessionUpdateFind */ SessionUpdate *pUp; int bStat1; /* True if table is sqlite_stat1 */ int bDeferConstraints; /* True to defer constraints */ int bInvertConstraints; /* Invert when iterating constraints buffer */ SessionBuffer constraints; /* Deferred constraints are stored here */ SessionBuffer rebase; /* Rebase information (if any) here */ u8 bRebaseStarted; /* If table header is already in rebase */ u8 bRebase; /* True to collect rebase information */ }; /* Number of prepared UPDATE statements to cache. */ #define SESSION_UPDATE_CACHE_SZ 12 /* ** Find a prepared UPDATE statement suitable for the UPDATE step currently ** being visited by the iterator. The UPDATE is of the form: ** ** UPDATE tbl SET col = ?, col2 = ? WHERE pk1 IS ? AND pk2 IS ? */ static int sessionUpdateFind( sqlite3_changeset_iter *pIter, SessionApplyCtx *p, int bPatchset, sqlite3_stmt **ppStmt ){ int rc = SQLITE_OK; SessionUpdate *pUp = 0; int nCol = pIter->nCol; int nU32 = (pIter->nCol+33)/32; int ii; if( p->aUpdateMask==0 ){ p->aUpdateMask = sqlite3_malloc(nU32*sizeof(u32)); if( p->aUpdateMask==0 ){ rc = SQLITE_NOMEM; } } if( rc==SQLITE_OK ){ memset(p->aUpdateMask, 0, nU32*sizeof(u32)); rc = SQLITE_CORRUPT; for(ii=0; ii<pIter->nCol; ii++){ if( sessionChangesetNew(pIter, ii) ){ p->aUpdateMask[ii/32] |= (1<<(ii%32)); rc = SQLITE_OK; } } } if( rc==SQLITE_OK ){ if( bPatchset ) p->aUpdateMask[nCol/32] |= (1<<(nCol%32)); if( p->pUp ){ int nUp = 0; SessionUpdate **pp = &p->pUp; while( 1 ){ nUp++; if( 0==memcmp(p->aUpdateMask, (*pp)->aMask, nU32*sizeof(u32)) ){ pUp = *pp; *pp = pUp->pNext; pUp->pNext = p->pUp; p->pUp = pUp; break; } if( (*pp)->pNext ){ pp = &(*pp)->pNext; }else{ if( nUp>=SESSION_UPDATE_CACHE_SZ ){ sqlite3_finalize((*pp)->pStmt); sqlite3_free(*pp); *pp = 0; } break; } } } if( pUp==0 ){ int nByte = sizeof(SessionUpdate) * nU32*sizeof(u32); int bStat1 = (sqlite3_stricmp(pIter->zTab, "sqlite_stat1")==0); pUp = (SessionUpdate*)sqlite3_malloc(nByte); if( pUp==0 ){ rc = SQLITE_NOMEM; }else{ const char *zSep = ""; SessionBuffer buf; memset(&buf, 0, sizeof(buf)); pUp->aMask = (u32*)&pUp[1]; memcpy(pUp->aMask, p->aUpdateMask, nU32*sizeof(u32)); sessionAppendStr(&buf, "UPDATE main.", &rc); sessionAppendIdent(&buf, pIter->zTab, &rc); sessionAppendStr(&buf, " SET ", &rc); /* Create the assignments part of the UPDATE */ for(ii=0; ii<pIter->nCol; ii++){ if( p->abPK[ii]==0 && sessionChangesetNew(pIter, ii) ){ sessionAppendStr(&buf, zSep, &rc); sessionAppendIdent(&buf, p->azCol[ii], &rc); sessionAppendStr(&buf, " = ?", &rc); sessionAppendInteger(&buf, ii*2+1, &rc); zSep = ", "; } } /* Create the WHERE clause part of the UPDATE */ zSep = ""; sessionAppendStr(&buf, " WHERE ", &rc); for(ii=0; ii<pIter->nCol; ii++){ if( p->abPK[ii] || (bPatchset==0 && sessionChangesetOld(pIter, ii)) ){ sessionAppendStr(&buf, zSep, &rc); if( bStat1 && ii==1 ){ assert( sqlite3_stricmp(p->azCol[ii], "idx")==0 ); sessionAppendStr(&buf, "idx IS CASE " "WHEN length(?4)=0 AND typeof(?4)='blob' THEN NULL " "ELSE ?4 END ", &rc ); }else{ sessionAppendIdent(&buf, p->azCol[ii], &rc); sessionAppendStr(&buf, " IS ?", &rc); sessionAppendInteger(&buf, ii*2+2, &rc); } zSep = " AND "; } } if( rc==SQLITE_OK ){ char *zSql = (char*)buf.aBuf; rc = sqlite3_prepare_v2(p->db, zSql, buf.nBuf, &pUp->pStmt, 0); } if( rc!=SQLITE_OK ){ sqlite3_free(pUp); pUp = 0; }else{ pUp->pNext = p->pUp; p->pUp = pUp; } sqlite3_free(buf.aBuf); } } } assert( (rc==SQLITE_OK)==(pUp!=0) ); if( pUp ){ *ppStmt = pUp->pStmt; }else{ *ppStmt = 0; } return rc; } /* ** Free all cached UPDATE statements. */ static void sessionUpdateFree(SessionApplyCtx *p){ SessionUpdate *pUp; SessionUpdate *pNext; for(pUp=p->pUp; pUp; pUp=pNext){ pNext = pUp->pNext; sqlite3_finalize(pUp->pStmt); sqlite3_free(pUp); } p->pUp = 0; sqlite3_free(p->aUpdateMask); p->aUpdateMask = 0; } /* ** Formulate a statement to DELETE a row from database db. Assuming a table ** structure like this: ** ** CREATE TABLE x(a, b, c, d, PRIMARY KEY(a, c)); ** |
︙ | ︙ | |||
3528 3529 3530 3531 3532 3533 3534 | ){ int i; const char *zSep = ""; int rc = SQLITE_OK; SessionBuffer buf = {0, 0, 0}; int nPk = 0; | | | 3972 3973 3974 3975 3976 3977 3978 3979 3980 3981 3982 3983 3984 3985 3986 | ){ int i; const char *zSep = ""; int rc = SQLITE_OK; SessionBuffer buf = {0, 0, 0}; int nPk = 0; sessionAppendStr(&buf, "DELETE FROM main.", &rc); sessionAppendIdent(&buf, zTab, &rc); sessionAppendStr(&buf, " WHERE ", &rc); for(i=0; i<p->nCol; i++){ if( p->abPK[i] ){ nPk++; sessionAppendStr(&buf, zSep, &rc); |
︙ | ︙ | |||
3568 3569 3570 3571 3572 3573 3574 | if( rc==SQLITE_OK ){ rc = sqlite3_prepare_v2(db, (char *)buf.aBuf, buf.nBuf, &p->pDelete, 0); } sqlite3_free(buf.aBuf); return rc; } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 4012 4013 4014 4015 4016 4017 4018 4019 4020 4021 4022 4023 4024 4025 | if( rc==SQLITE_OK ){ rc = sqlite3_prepare_v2(db, (char *)buf.aBuf, buf.nBuf, &p->pDelete, 0); } sqlite3_free(buf.aBuf); return rc; } /* ** Formulate and prepare an SQL statement to query table zTab by primary ** key. Assuming the following table structure: ** ** CREATE TABLE x(a, b, c, d, PRIMARY KEY(a, c)); ** |
︙ | ︙ | |||
3746 3747 3748 3749 3750 3751 3752 | if( rc==SQLITE_OK ){ rc = sessionPrepare(db, &p->pInsert, "INSERT INTO main.sqlite_stat1 VALUES(?1, " "CASE WHEN length(?2)=0 AND typeof(?2)='blob' THEN NULL ELSE ?2 END, " "?3)" ); } | < < < < < < < < < < < | 4093 4094 4095 4096 4097 4098 4099 4100 4101 4102 4103 4104 4105 4106 | if( rc==SQLITE_OK ){ rc = sessionPrepare(db, &p->pInsert, "INSERT INTO main.sqlite_stat1 VALUES(?1, " "CASE WHEN length(?2)=0 AND typeof(?2)='blob' THEN NULL ELSE ?2 END, " "?3)" ); } if( rc==SQLITE_OK ){ rc = sessionPrepare(db, &p->pDelete, "DELETE FROM main.sqlite_stat1 WHERE tbl=?1 AND idx IS " "CASE WHEN length(?2)=0 AND typeof(?2)='blob' THEN NULL ELSE ?2 END " "AND (?4 OR stat IS ?3)" ); } |
︙ | ︙ | |||
3822 3823 3824 3825 3826 3827 3828 | ** argument iterator points to a suitable entry. Make sure that xValue ** is one of these to guarantee that it is safe to ignore the return ** in the code below. */ assert( xValue==sqlite3changeset_old || xValue==sqlite3changeset_new ); for(i=0; rc==SQLITE_OK && i<nCol; i++){ if( !abPK || abPK[i] ){ | | | 4158 4159 4160 4161 4162 4163 4164 4165 4166 4167 4168 4169 4170 4171 4172 | ** argument iterator points to a suitable entry. Make sure that xValue ** is one of these to guarantee that it is safe to ignore the return ** in the code below. */ assert( xValue==sqlite3changeset_old || xValue==sqlite3changeset_new ); for(i=0; rc==SQLITE_OK && i<nCol; i++){ if( !abPK || abPK[i] ){ sqlite3_value *pVal = 0; (void)xValue(pIter, i, &pVal); if( pVal==0 ){ /* The value in the changeset was "undefined". This indicates a ** corrupt changeset blob. */ rc = SQLITE_CORRUPT_BKPT; }else{ rc = sessionBindValue(pStmt, i+1, pVal); |
︙ | ︙ | |||
3879 3880 3881 3882 3883 3884 3885 | if( rc!=SQLITE_ROW ) rc = sqlite3_reset(pSelect); } return rc; } /* | | | 4215 4216 4217 4218 4219 4220 4221 4222 4223 4224 4225 4226 4227 4228 4229 | if( rc!=SQLITE_ROW ) rc = sqlite3_reset(pSelect); } return rc; } /* ** This function is called from within sqlite3changeset_apply_v2() when ** a conflict is encountered and resolved using conflict resolution ** mode eType (either SQLITE_CHANGESET_OMIT or SQLITE_CHANGESET_REPLACE).. ** It adds a conflict resolution record to the buffer in ** SessionApplyCtx.rebase, which will eventually be returned to the caller ** of apply_v2() as the "rebase" buffer. ** ** Return SQLITE_OK if successful, or an SQLite error code otherwise. |
︙ | ︙ | |||
4073 4074 4075 4076 4077 4078 4079 | int *pbRetry /* OUT: True to retry. */ ){ const char *zDummy; int op; int nCol; int rc = SQLITE_OK; | | | 4409 4410 4411 4412 4413 4414 4415 4416 4417 4418 4419 4420 4421 4422 4423 | int *pbRetry /* OUT: True to retry. */ ){ const char *zDummy; int op; int nCol; int rc = SQLITE_OK; assert( p->pDelete && p->pInsert && p->pSelect ); assert( p->azCol && p->abPK ); assert( !pbReplace || *pbReplace==0 ); sqlite3changeset_op(pIter, &zDummy, &nCol, &op, 0); if( op==SQLITE_DELETE ){ |
︙ | ︙ | |||
4113 4114 4115 4116 4117 4118 4119 4120 4121 4122 4123 4124 | rc = sessionConflictHandler( SQLITE_CHANGESET_CONFLICT, p, pIter, xConflict, pCtx, 0 ); } }else if( op==SQLITE_UPDATE ){ int i; /* Bind values to the UPDATE statement. */ for(i=0; rc==SQLITE_OK && i<nCol; i++){ sqlite3_value *pOld = sessionChangesetOld(pIter, i); sqlite3_value *pNew = sessionChangesetNew(pIter, i); | > > > > | < < | | < < < | | | 4449 4450 4451 4452 4453 4454 4455 4456 4457 4458 4459 4460 4461 4462 4463 4464 4465 4466 4467 4468 4469 4470 4471 4472 4473 4474 4475 4476 4477 4478 4479 4480 4481 4482 4483 4484 | rc = sessionConflictHandler( SQLITE_CHANGESET_CONFLICT, p, pIter, xConflict, pCtx, 0 ); } }else if( op==SQLITE_UPDATE ){ int i; sqlite3_stmt *pUp = 0; int bPatchset = (pbRetry==0 || pIter->bPatchset); rc = sessionUpdateFind(pIter, p, bPatchset, &pUp); /* Bind values to the UPDATE statement. */ for(i=0; rc==SQLITE_OK && i<nCol; i++){ sqlite3_value *pOld = sessionChangesetOld(pIter, i); sqlite3_value *pNew = sessionChangesetNew(pIter, i); if( p->abPK[i] || (bPatchset==0 && pOld) ){ rc = sessionBindValue(pUp, i*2+2, pOld); } if( rc==SQLITE_OK && pNew ){ rc = sessionBindValue(pUp, i*2+1, pNew); } } if( rc!=SQLITE_OK ) return rc; /* Attempt the UPDATE. In the case of a NOTFOUND or DATA conflict, ** the result will be SQLITE_OK with 0 rows modified. */ sqlite3_step(pUp); rc = sqlite3_reset(pUp); if( rc==SQLITE_OK && sqlite3_changes(p->db)==0 ){ /* A NOTFOUND or DATA error. Search the table to see if it contains ** a row with a matching primary key. If so, this is a DATA conflict. ** Otherwise, if there is no primary key match, it is a NOTFOUND. */ rc = sessionConflictHandler( |
︙ | ︙ | |||
4266 4267 4268 4269 4270 4271 4272 | int rc = SQLITE_OK; while( pApply->constraints.nBuf ){ sqlite3_changeset_iter *pIter2 = 0; SessionBuffer cons = pApply->constraints; memset(&pApply->constraints, 0, sizeof(SessionBuffer)); | | > > | | 4601 4602 4603 4604 4605 4606 4607 4608 4609 4610 4611 4612 4613 4614 4615 4616 4617 4618 4619 | int rc = SQLITE_OK; while( pApply->constraints.nBuf ){ sqlite3_changeset_iter *pIter2 = 0; SessionBuffer cons = pApply->constraints; memset(&pApply->constraints, 0, sizeof(SessionBuffer)); rc = sessionChangesetStart( &pIter2, 0, 0, cons.nBuf, cons.aBuf, pApply->bInvertConstraints, 1 ); if( rc==SQLITE_OK ){ size_t nByte = 2*pApply->nCol*sizeof(sqlite3_value*); int rc2; pIter2->bPatchset = bPatchset; pIter2->zTab = (char*)zTab; pIter2->nCol = pApply->nCol; pIter2->abPK = pApply->abPK; sessionBufferGrow(&pIter2->tblhdr, nByte, &rc); pIter2->apValue = (sqlite3_value**)pIter2->tblhdr.aBuf; |
︙ | ︙ | |||
4333 4334 4335 4336 4337 4338 4339 4340 4341 4342 4343 4344 4345 4346 | int bPatchset; assert( xConflict!=0 ); pIter->in.bNoDiscard = 1; memset(&sApply, 0, sizeof(sApply)); sApply.bRebase = (ppRebase && pnRebase); sqlite3_mutex_enter(sqlite3_db_mutex(db)); if( (flags & SQLITE_CHANGESETAPPLY_NOSAVEPOINT)==0 ){ rc = sqlite3_exec(db, "SAVEPOINT changeset_apply", 0, 0, 0); } if( rc==SQLITE_OK ){ rc = sqlite3_exec(db, "PRAGMA defer_foreign_keys = 1", 0, 0, 0); } | > | 4670 4671 4672 4673 4674 4675 4676 4677 4678 4679 4680 4681 4682 4683 4684 | int bPatchset; assert( xConflict!=0 ); pIter->in.bNoDiscard = 1; memset(&sApply, 0, sizeof(sApply)); sApply.bRebase = (ppRebase && pnRebase); sApply.bInvertConstraints = !!(flags & SQLITE_CHANGESETAPPLY_INVERT); sqlite3_mutex_enter(sqlite3_db_mutex(db)); if( (flags & SQLITE_CHANGESETAPPLY_NOSAVEPOINT)==0 ){ rc = sqlite3_exec(db, "SAVEPOINT changeset_apply", 0, 0, 0); } if( rc==SQLITE_OK ){ rc = sqlite3_exec(db, "PRAGMA defer_foreign_keys = 1", 0, 0, 0); } |
︙ | ︙ | |||
4355 4356 4357 4358 4359 4360 4361 4362 4363 | u8 *abPK; rc = sessionRetryConstraints( db, pIter->bPatchset, zTab, &sApply, xConflict, pCtx ); if( rc!=SQLITE_OK ) break; sqlite3_free((char*)sApply.azCol); /* cast works around VC++ bug */ sqlite3_finalize(sApply.pDelete); | > < < | 4693 4694 4695 4696 4697 4698 4699 4700 4701 4702 4703 4704 4705 4706 4707 4708 4709 4710 4711 4712 4713 | u8 *abPK; rc = sessionRetryConstraints( db, pIter->bPatchset, zTab, &sApply, xConflict, pCtx ); if( rc!=SQLITE_OK ) break; sessionUpdateFree(&sApply); sqlite3_free((char*)sApply.azCol); /* cast works around VC++ bug */ sqlite3_finalize(sApply.pDelete); sqlite3_finalize(sApply.pInsert); sqlite3_finalize(sApply.pSelect); sApply.db = db; sApply.pDelete = 0; sApply.pInsert = 0; sApply.pSelect = 0; sApply.nCol = 0; sApply.azCol = 0; sApply.abPK = 0; sApply.bStat1 = 0; sApply.bDeferConstraints = 1; |
︙ | ︙ | |||
4390 4391 4392 4393 4394 4395 4396 | nTab = (int)strlen(zTab); sApply.azCol = (const char **)zTab; }else{ int nMinCol = 0; int i; sqlite3changeset_pk(pIter, &abPK, 0); | | | 4727 4728 4729 4730 4731 4732 4733 4734 4735 4736 4737 4738 4739 4740 4741 | nTab = (int)strlen(zTab); sApply.azCol = (const char **)zTab; }else{ int nMinCol = 0; int i; sqlite3changeset_pk(pIter, &abPK, 0); rc = sessionTableInfo(0, db, "main", zNew, &sApply.nCol, &zTab, &sApply.azCol, &sApply.abPK ); if( rc!=SQLITE_OK ) break; for(i=0; i<sApply.nCol; i++){ if( sApply.abPK[i] ) nMinCol = i+1; } |
︙ | ︙ | |||
4426 4427 4428 4429 4430 4431 4432 | sApply.nCol = nCol; if( 0==sqlite3_stricmp(zTab, "sqlite_stat1") ){ if( (rc = sessionStat1Sql(db, &sApply) ) ){ break; } sApply.bStat1 = 1; }else{ | | < | | | | 4763 4764 4765 4766 4767 4768 4769 4770 4771 4772 4773 4774 4775 4776 4777 4778 4779 4780 | sApply.nCol = nCol; if( 0==sqlite3_stricmp(zTab, "sqlite_stat1") ){ if( (rc = sessionStat1Sql(db, &sApply) ) ){ break; } sApply.bStat1 = 1; }else{ if( (rc = sessionSelectRow(db, zTab, &sApply)) || (rc = sessionDeleteRow(db, zTab, &sApply)) || (rc = sessionInsertRow(db, zTab, &sApply)) ){ break; } sApply.bStat1 = 0; } } nTab = sqlite3Strlen30(zTab); } |
︙ | ︙ | |||
4489 4490 4491 4492 4493 4494 4495 4496 4497 | assert( sApply.bRebase || sApply.rebase.nBuf==0 ); if( rc==SQLITE_OK && bPatchset==0 && sApply.bRebase ){ *ppRebase = (void*)sApply.rebase.aBuf; *pnRebase = sApply.rebase.nBuf; sApply.rebase.aBuf = 0; } sqlite3_finalize(sApply.pInsert); sqlite3_finalize(sApply.pDelete); | > < | 4825 4826 4827 4828 4829 4830 4831 4832 4833 4834 4835 4836 4837 4838 4839 4840 4841 | assert( sApply.bRebase || sApply.rebase.nBuf==0 ); if( rc==SQLITE_OK && bPatchset==0 && sApply.bRebase ){ *ppRebase = (void*)sApply.rebase.aBuf; *pnRebase = sApply.rebase.nBuf; sApply.rebase.aBuf = 0; } sessionUpdateFree(&sApply); sqlite3_finalize(sApply.pInsert); sqlite3_finalize(sApply.pDelete); sqlite3_finalize(sApply.pSelect); sqlite3_free((char*)sApply.azCol); /* cast works around VC++ bug */ sqlite3_free((char*)sApply.constraints.aBuf); sqlite3_free((char*)sApply.rebase.aBuf); sqlite3_mutex_leave(sqlite3_db_mutex(db)); return rc; } |
︙ | ︙ | |||
4522 4523 4524 4525 4526 4527 4528 | sqlite3_changeset_iter *p /* Handle describing change and conflict */ ), void *pCtx, /* First argument passed to xConflict */ void **ppRebase, int *pnRebase, int flags ){ sqlite3_changeset_iter *pIter; /* Iterator to skip through changeset */ | | | | 4858 4859 4860 4861 4862 4863 4864 4865 4866 4867 4868 4869 4870 4871 4872 4873 | sqlite3_changeset_iter *p /* Handle describing change and conflict */ ), void *pCtx, /* First argument passed to xConflict */ void **ppRebase, int *pnRebase, int flags ){ sqlite3_changeset_iter *pIter; /* Iterator to skip through changeset */ int bInv = !!(flags & SQLITE_CHANGESETAPPLY_INVERT); int rc = sessionChangesetStart(&pIter, 0, 0, nChangeset, pChangeset, bInv, 1); if( rc==SQLITE_OK ){ rc = sessionChangesetApply( db, pIter, xFilter, xConflict, pCtx, ppRebase, pnRebase, flags ); } return rc; } |
︙ | ︙ | |||
4581 4582 4583 4584 4585 4586 4587 | ), void *pCtx, /* First argument passed to xConflict */ void **ppRebase, int *pnRebase, int flags ){ sqlite3_changeset_iter *pIter; /* Iterator to skip through changeset */ int bInverse = !!(flags & SQLITE_CHANGESETAPPLY_INVERT); | | | 4917 4918 4919 4920 4921 4922 4923 4924 4925 4926 4927 4928 4929 4930 4931 | ), void *pCtx, /* First argument passed to xConflict */ void **ppRebase, int *pnRebase, int flags ){ sqlite3_changeset_iter *pIter; /* Iterator to skip through changeset */ int bInverse = !!(flags & SQLITE_CHANGESETAPPLY_INVERT); int rc = sessionChangesetStart(&pIter, xInput, pIn, 0, 0, bInverse, 1); if( rc==SQLITE_OK ){ rc = sessionChangesetApply( db, pIter, xFilter, xConflict, pCtx, ppRebase, pnRebase, flags ); } return rc; } |
︙ | ︙ | |||
4638 4639 4640 4641 4642 4643 4644 | int nRec, /* Number of bytes in aRec */ SessionChange **ppNew /* OUT: Merged change */ ){ SessionChange *pNew = 0; int rc = SQLITE_OK; if( !pExist ){ | | | 4974 4975 4976 4977 4978 4979 4980 4981 4982 4983 4984 4985 4986 4987 4988 | int nRec, /* Number of bytes in aRec */ SessionChange **ppNew /* OUT: Merged change */ ){ SessionChange *pNew = 0; int rc = SQLITE_OK; if( !pExist ){ pNew = (SessionChange *)sqlite3_malloc64(sizeof(SessionChange) + nRec); if( !pNew ){ return SQLITE_NOMEM; } memset(pNew, 0, sizeof(SessionChange)); pNew->op = op2; pNew->bIndirect = bIndirect; pNew->aRecord = (u8*)&pNew[1]; |
︙ | ︙ | |||
4671 4672 4673 4674 4675 4676 4677 | } pNew->nRecord = pOut - pNew->aRecord; } }else if( bRebase ){ if( pExist->op==SQLITE_DELETE && pExist->bIndirect ){ *ppNew = pExist; }else{ | | | | 5007 5008 5009 5010 5011 5012 5013 5014 5015 5016 5017 5018 5019 5020 5021 5022 | } pNew->nRecord = pOut - pNew->aRecord; } }else if( bRebase ){ if( pExist->op==SQLITE_DELETE && pExist->bIndirect ){ *ppNew = pExist; }else{ sqlite3_int64 nByte = nRec + pExist->nRecord + sizeof(SessionChange); pNew = (SessionChange*)sqlite3_malloc64(nByte); if( pNew==0 ){ rc = SQLITE_NOMEM; }else{ int i; u8 *a1 = pExist->aRecord; u8 *a2 = aRec; u8 *pOut; |
︙ | ︙ | |||
4732 4733 4734 4735 4736 4737 4738 | ){ pNew = pExist; }else if( op1==SQLITE_INSERT && op2==SQLITE_DELETE ){ sqlite3_free(pExist); assert( pNew==0 ); }else{ u8 *aExist = pExist->aRecord; | | | | 5068 5069 5070 5071 5072 5073 5074 5075 5076 5077 5078 5079 5080 5081 5082 5083 5084 5085 5086 5087 5088 5089 | ){ pNew = pExist; }else if( op1==SQLITE_INSERT && op2==SQLITE_DELETE ){ sqlite3_free(pExist); assert( pNew==0 ); }else{ u8 *aExist = pExist->aRecord; sqlite3_int64 nByte; u8 *aCsr; /* Allocate a new SessionChange object. Ensure that the aRecord[] ** buffer of the new object is large enough to hold any record that ** may be generated by combining the input records. */ nByte = sizeof(SessionChange) + pExist->nRecord + nRec; pNew = (SessionChange *)sqlite3_malloc64(nByte); if( !pNew ){ sqlite3_free(pExist); return SQLITE_NOMEM; } memset(pNew, 0, sizeof(SessionChange)); pNew->bIndirect = (bIndirect && pExist->bIndirect); aCsr = pNew->aRecord = (u8 *)&pNew[1]; |
︙ | ︙ | |||
4845 4846 4847 4848 4849 4850 4851 | sqlite3changeset_pk(pIter, &abPK, 0); for(pTab = pGrp->pList; pTab; pTab=pTab->pNext){ if( 0==sqlite3_strnicmp(pTab->zName, zNew, nNew+1) ) break; } if( !pTab ){ SessionTable **ppTab; | | | 5181 5182 5183 5184 5185 5186 5187 5188 5189 5190 5191 5192 5193 5194 5195 | sqlite3changeset_pk(pIter, &abPK, 0); for(pTab = pGrp->pList; pTab; pTab=pTab->pNext){ if( 0==sqlite3_strnicmp(pTab->zName, zNew, nNew+1) ) break; } if( !pTab ){ SessionTable **ppTab; pTab = sqlite3_malloc64(sizeof(SessionTable) + nCol + nNew+1); if( !pTab ){ rc = SQLITE_NOMEM; break; } memset(pTab, 0, sizeof(SessionTable)); pTab->nCol = nCol; pTab->abPK = (u8*)&pTab[1]; |
︙ | ︙ | |||
4869 4870 4871 4872 4873 4874 4875 | *ppTab = pTab; }else if( pTab->nCol!=nCol || memcmp(pTab->abPK, abPK, nCol) ){ rc = SQLITE_SCHEMA; break; } } | | | 5205 5206 5207 5208 5209 5210 5211 5212 5213 5214 5215 5216 5217 5218 5219 | *ppTab = pTab; }else if( pTab->nCol!=nCol || memcmp(pTab->abPK, abPK, nCol) ){ rc = SQLITE_SCHEMA; break; } } if( sessionGrowHash(0, pIter->bPatchset, pTab) ){ rc = SQLITE_NOMEM; break; } iHash = sessionChangeHash( pTab, (pIter->bPatchset && op==SQLITE_DELETE), aRec, pTab->nChange ); |
︙ | ︙ | |||
4966 4967 4968 4969 4970 4971 4972 | } } } if( rc==SQLITE_OK ){ if( xOutput ){ if( buf.nBuf>0 ) rc = xOutput(pOut, buf.aBuf, buf.nBuf); | | | | 5302 5303 5304 5305 5306 5307 5308 5309 5310 5311 5312 5313 5314 5315 5316 5317 5318 | } } } if( rc==SQLITE_OK ){ if( xOutput ){ if( buf.nBuf>0 ) rc = xOutput(pOut, buf.aBuf, buf.nBuf); }else if( ppOut ){ *ppOut = buf.aBuf; if( pnOut ) *pnOut = buf.nBuf; buf.aBuf = 0; } } sqlite3_free(buf.aBuf); return rc; } |
︙ | ︙ | |||
5056 5057 5058 5059 5060 5061 5062 | } /* ** Delete a changegroup object. */ void sqlite3changegroup_delete(sqlite3_changegroup *pGrp){ if( pGrp ){ | | | 5392 5393 5394 5395 5396 5397 5398 5399 5400 5401 5402 5403 5404 5405 5406 | } /* ** Delete a changegroup object. */ void sqlite3changegroup_delete(sqlite3_changegroup *pGrp){ if( pGrp ){ sessionDeleteTable(0, pGrp->pList); sqlite3_free(pGrp); } } /* ** Combine two changesets together. */ |
︙ | ︙ | |||
5202 5203 5204 5205 5206 5207 5208 | *pOut++ = SQLITE_UPDATE; *pOut++ = pIter->bIndirect; for(i=0; i<pIter->nCol; i++){ int n1 = sessionSerialLen(a1); int n2 = sessionSerialLen(a2); if( pIter->abPK[i] || a2[0]==0 ){ | | | 5538 5539 5540 5541 5542 5543 5544 5545 5546 5547 5548 5549 5550 5551 5552 | *pOut++ = SQLITE_UPDATE; *pOut++ = pIter->bIndirect; for(i=0; i<pIter->nCol; i++){ int n1 = sessionSerialLen(a1); int n2 = sessionSerialLen(a2); if( pIter->abPK[i] || a2[0]==0 ){ if( !pIter->abPK[i] && a1[0] ) bData = 1; memcpy(pOut, a1, n1); pOut += n1; }else if( a2[0]!=0xFF ){ bData = 1; memcpy(pOut, a2, n2); pOut += n2; }else{ |
︙ | ︙ | |||
5368 5369 5370 5371 5372 5373 5374 | } if( rc==SQLITE_OK ){ if( xOutput ){ if( sOut.nBuf>0 ){ rc = xOutput(pOut, sOut.aBuf, sOut.nBuf); } | | | 5704 5705 5706 5707 5708 5709 5710 5711 5712 5713 5714 5715 5716 5717 5718 | } if( rc==SQLITE_OK ){ if( xOutput ){ if( sOut.nBuf>0 ){ rc = xOutput(pOut, sOut.aBuf, sOut.nBuf); } }else if( ppOut ){ *ppOut = (void*)sOut.aBuf; *pnOut = sOut.nBuf; sOut.aBuf = 0; } } sqlite3_free(sOut.aBuf); return rc; |
︙ | ︙ | |||
5457 5458 5459 5460 5461 5462 5463 | } /* ** Destroy a rebaser object */ void sqlite3rebaser_delete(sqlite3_rebaser *p){ if( p ){ | | | 5793 5794 5795 5796 5797 5798 5799 5800 5801 5802 5803 5804 5805 5806 5807 | } /* ** Destroy a rebaser object */ void sqlite3rebaser_delete(sqlite3_rebaser *p){ if( p ){ sessionDeleteTable(0, p->grp.pList); sqlite3_free(p); } } /* ** Global configuration */ |
︙ | ︙ |
Changes to ext/session/sqlite3session.h.
︙ | ︙ | |||
75 76 77 78 79 80 81 82 83 84 85 86 87 88 | ** ** Session objects must be deleted before the database handle to which they ** are attached is closed. Refer to the documentation for ** [sqlite3session_create()] for details. */ void sqlite3session_delete(sqlite3_session *pSession); /* ** CAPI3REF: Enable Or Disable A Session Object ** METHOD: sqlite3_session ** ** Enable or disable the recording of changes by a session object. When ** enabled, a session object records changes made to the database. When | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | ** ** Session objects must be deleted before the database handle to which they ** are attached is closed. Refer to the documentation for ** [sqlite3session_create()] for details. */ void sqlite3session_delete(sqlite3_session *pSession); /* ** CAPIREF: Conigure a Session Object ** METHOD: sqlite3_session ** ** This method is used to configure a session object after it has been ** created. At present the only valid value for the second parameter is ** [SQLITE_SESSION_OBJCONFIG_SIZE]. ** ** Arguments for sqlite3session_object_config() ** ** The following values may passed as the the 4th parameter to ** sqlite3session_object_config(). ** ** <dt>SQLITE_SESSION_OBJCONFIG_SIZE <dd> ** This option is used to set, clear or query the flag that enables ** the [sqlite3session_changeset_size()] API. Because it imposes some ** computational overhead, this API is disabled by default. Argument ** pArg must point to a value of type (int). If the value is initially ** 0, then the sqlite3session_changeset_size() API is disabled. If it ** is greater than 0, then the same API is enabled. Or, if the initial ** value is less than zero, no change is made. In all cases the (int) ** variable is set to 1 if the sqlite3session_changeset_size() API is ** enabled following the current call, or 0 otherwise. ** ** It is an error (SQLITE_MISUSE) to attempt to modify this setting after ** the first table has been attached to the session object. */ int sqlite3session_object_config(sqlite3_session*, int op, void *pArg); /* */ #define SQLITE_SESSION_OBJCONFIG_SIZE 1 /* ** CAPI3REF: Enable Or Disable A Session Object ** METHOD: sqlite3_session ** ** Enable or disable the recording of changes by a session object. When ** enabled, a session object records changes made to the database. When |
︙ | ︙ | |||
196 197 198 199 200 201 202 | /* ** CAPI3REF: Set a table filter on a Session Object. ** METHOD: sqlite3_session ** ** The second argument (xFilter) is the "filter callback". For changes to rows ** in tables that are not attached to the Session object, the filter is called ** to determine whether changes to the table's rows should be tracked or not. | | | 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 | /* ** CAPI3REF: Set a table filter on a Session Object. ** METHOD: sqlite3_session ** ** The second argument (xFilter) is the "filter callback". For changes to rows ** in tables that are not attached to the Session object, the filter is called ** to determine whether changes to the table's rows should be tracked or not. ** If xFilter returns 0, changes are not tracked. Note that once a table is ** attached, xFilter will not be called again. */ void sqlite3session_table_filter( sqlite3_session *pSession, /* Session object */ int(*xFilter)( void *pCtx, /* Copy of third arg to _filter_table() */ const char *zTab /* Table name */ |
︙ | ︙ | |||
332 333 334 335 336 337 338 339 340 341 342 343 344 345 | */ int sqlite3session_fullchangeset( sqlite3_session *pSession, /* Session object */ int *pnChangeset, /* OUT: Size of buffer at *ppChangeset */ void **ppChangeset /* OUT: Buffer containing changeset */ ); /* ** CAPI3REF: Load The Difference Between Tables Into A Session ** METHOD: sqlite3_session ** ** If it is not already attached to the session object passed as the first ** argument, this function attaches table zTbl in the same manner as the ** [sqlite3session_attach()] function. If zTbl does not exist, or if it | > > > > > > > > > > > > > > > > | 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 | */ int sqlite3session_fullchangeset( sqlite3_session *pSession, /* Session object */ int *pnChangeset, /* OUT: Size of buffer at *ppChangeset */ void **ppChangeset /* OUT: Buffer containing changeset */ ); /* ** CAPI3REF: Return An Upper-limit For The Size Of The Changeset ** METHOD: sqlite3_session ** ** By default, this function always returns 0. For it to return ** a useful result, the sqlite3_session object must have been configured ** to enable this API using sqlite3session_object_config() with the ** SQLITE_SESSION_OBJCONFIG_SIZE verb. ** ** When enabled, this function returns an upper limit, in bytes, for the size ** of the changeset that might be produced if sqlite3session_changeset() were ** called. The final changeset size might be equal to or smaller than the ** size in bytes returned by this function. */ sqlite3_int64 sqlite3session_changeset_size(sqlite3_session *pSession); /* ** CAPI3REF: Load The Difference Between Tables Into A Session ** METHOD: sqlite3_session ** ** If it is not already attached to the session object passed as the first ** argument, this function attaches table zTbl in the same manner as the ** [sqlite3session_attach()] function. If zTbl does not exist, or if it |
︙ | ︙ | |||
383 384 385 386 387 388 389 | ** using [sqlite3session_changeset()], then after applying that changeset to ** database zFrom the contents of the two compatible tables would be ** identical. ** ** It an error if database zFrom does not exist or does not contain the ** required compatible table. ** | | | 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 | ** using [sqlite3session_changeset()], then after applying that changeset to ** database zFrom the contents of the two compatible tables would be ** identical. ** ** It an error if database zFrom does not exist or does not contain the ** required compatible table. ** ** If the operation is successful, SQLITE_OK is returned. Otherwise, an SQLite ** error code. In this case, if argument pzErrMsg is not NULL, *pzErrMsg ** may be set to point to a buffer containing an English language error ** message. It is the responsibility of the caller to free this buffer using ** sqlite3_free(). */ int sqlite3session_diff( sqlite3_session *pSession, |
︙ | ︙ | |||
449 450 451 452 453 454 455 456 457 458 459 460 461 462 | ** an attached table is modified and then later on the original values ** are restored. However, if this function returns non-zero, then it is ** guaranteed that a call to sqlite3session_changeset() will return a ** changeset containing zero changes. */ int sqlite3session_isempty(sqlite3_session *pSession); /* ** CAPI3REF: Create An Iterator To Traverse A Changeset ** CONSTRUCTOR: sqlite3_changeset_iter ** ** Create an iterator used to iterate through the contents of a changeset. ** If successful, *pp is set to point to the iterator handle and SQLITE_OK ** is returned. Otherwise, if an error occurs, *pp is set to zero and an | > > > > > > > > | 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 | ** an attached table is modified and then later on the original values ** are restored. However, if this function returns non-zero, then it is ** guaranteed that a call to sqlite3session_changeset() will return a ** changeset containing zero changes. */ int sqlite3session_isempty(sqlite3_session *pSession); /* ** CAPI3REF: Query for the amount of heap memory used by a session object. ** ** This API returns the total amount of heap memory in bytes currently ** used by the session object passed as the only argument. */ sqlite3_int64 sqlite3session_memory_used(sqlite3_session *pSession); /* ** CAPI3REF: Create An Iterator To Traverse A Changeset ** CONSTRUCTOR: sqlite3_changeset_iter ** ** Create an iterator used to iterate through the contents of a changeset. ** If successful, *pp is set to point to the iterator handle and SQLITE_OK ** is returned. Otherwise, if an error occurs, *pp is set to zero and an |
︙ | ︙ | |||
520 521 522 523 524 525 526 | #define SQLITE_CHANGESETSTART_INVERT 0x0002 /* ** CAPI3REF: Advance A Changeset Iterator ** METHOD: sqlite3_changeset_iter ** | | | 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 | #define SQLITE_CHANGESETSTART_INVERT 0x0002 /* ** CAPI3REF: Advance A Changeset Iterator ** METHOD: sqlite3_changeset_iter ** ** This function may only be used with iterators created by the function ** [sqlite3changeset_start()]. If it is called on an iterator passed to ** a conflict-handler callback by [sqlite3changeset_apply()], SQLITE_MISUSE ** is returned and the call has no effect. ** ** Immediately after an iterator is created by sqlite3changeset_start(), it ** does not point to any change in the changeset. Assuming the changeset ** is not empty, the first call to this function advances the iterator to |
︙ | ︙ | |||
551 552 553 554 555 556 557 | ** ** The pIter argument passed to this function may either be an iterator ** passed to a conflict-handler by [sqlite3changeset_apply()], or an iterator ** created by [sqlite3changeset_start()]. In the latter case, the most recent ** call to [sqlite3changeset_next()] must have returned [SQLITE_ROW]. If this ** is not the case, this function returns [SQLITE_MISUSE]. ** | > > > | > > > > | | | | < > | | < < | 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 | ** ** The pIter argument passed to this function may either be an iterator ** passed to a conflict-handler by [sqlite3changeset_apply()], or an iterator ** created by [sqlite3changeset_start()]. In the latter case, the most recent ** call to [sqlite3changeset_next()] must have returned [SQLITE_ROW]. If this ** is not the case, this function returns [SQLITE_MISUSE]. ** ** Arguments pOp, pnCol and pzTab may not be NULL. Upon return, three ** outputs are set through these pointers: ** ** *pOp is set to one of [SQLITE_INSERT], [SQLITE_DELETE] or [SQLITE_UPDATE], ** depending on the type of change that the iterator currently points to; ** ** *pnCol is set to the number of columns in the table affected by the change; and ** ** *pzTab is set to point to a nul-terminated utf-8 encoded string containing ** the name of the table affected by the current change. The buffer remains ** valid until either sqlite3changeset_next() is called on the iterator ** or until the conflict-handler function returns. ** ** If pbIndirect is not NULL, then *pbIndirect is set to true (1) if the change ** is an indirect change, or false (0) otherwise. See the documentation for ** [sqlite3session_indirect()] for a description of direct and indirect ** changes. ** ** If no error occurs, SQLITE_OK is returned. If an error does occur, an ** SQLite error code is returned. The values of the output variables may not ** be trusted in this case. */ int sqlite3changeset_op( sqlite3_changeset_iter *pIter, /* Iterator object */ |
︙ | ︙ | |||
936 937 938 939 940 941 942 | ** ** If the new changeset contains changes to a table that is already present ** in the changegroup, then the number of columns and the position of the ** primary key columns for the table must be consistent. If this is not the ** case, this function fails with SQLITE_SCHEMA. If the input changeset ** appears to be corrupt and the corruption is detected, SQLITE_CORRUPT is ** returned. Or, if an out-of-memory condition occurs during processing, this | | | | 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 | ** ** If the new changeset contains changes to a table that is already present ** in the changegroup, then the number of columns and the position of the ** primary key columns for the table must be consistent. If this is not the ** case, this function fails with SQLITE_SCHEMA. If the input changeset ** appears to be corrupt and the corruption is detected, SQLITE_CORRUPT is ** returned. Or, if an out-of-memory condition occurs during processing, this ** function returns SQLITE_NOMEM. In all cases, if an error occurs the state ** of the final contents of the changegroup is undefined. ** ** If no error occurs, SQLITE_OK is returned. */ int sqlite3changegroup_add(sqlite3_changegroup*, int nData, void *pData); /* ** CAPI3REF: Obtain A Composite Changeset From A Changegroup |
︙ | ︙ | |||
1112 1113 1114 1115 1116 1117 1118 | ** This includes the case where the UPDATE operation is attempted after ** an earlier call to the conflict handler function returned ** [SQLITE_CHANGESET_REPLACE]. ** </dl> ** ** It is safe to execute SQL statements, including those that write to the ** table that the callback related to, from within the xConflict callback. | | | 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 | ** This includes the case where the UPDATE operation is attempted after ** an earlier call to the conflict handler function returned ** [SQLITE_CHANGESET_REPLACE]. ** </dl> ** ** It is safe to execute SQL statements, including those that write to the ** table that the callback related to, from within the xConflict callback. ** This can be used to further customize the application's conflict ** resolution strategy. ** ** All changes made by these functions are enclosed in a savepoint transaction. ** If any other error (aside from a constraint failure when attempting to ** write to the target database) occurs, then the savepoint transaction is ** rolled back, restoring the target database to its original state, and an ** SQLite error code returned. |
︙ | ︙ | |||
1422 1423 1424 1425 1426 1427 1428 | /* ** CAPI3REF: Rebase a changeset ** EXPERIMENTAL ** ** Argument pIn must point to a buffer containing a changeset nIn bytes ** in size. This function allocates and populates a buffer with a copy | | | | 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 | /* ** CAPI3REF: Rebase a changeset ** EXPERIMENTAL ** ** Argument pIn must point to a buffer containing a changeset nIn bytes ** in size. This function allocates and populates a buffer with a copy ** of the changeset rebased according to the configuration of the ** rebaser object passed as the first argument. If successful, (*ppOut) ** is set to point to the new buffer containing the rebased changeset and ** (*pnOut) to its size in bytes and SQLITE_OK returned. It is the ** responsibility of the caller to eventually free the new buffer using ** sqlite3_free(). Otherwise, if an error occurs, (*ppOut) and (*pnOut) ** are set to zero and an SQLite error code returned. */ int sqlite3rebaser_rebase( sqlite3_rebaser*, |
︙ | ︙ |
Changes to ext/session/test_session.c.
︙ | ︙ | |||
142 143 144 145 146 147 148 | ** ** If the named variable cannot be found, or if it cannot be interpreted ** as a integer, return 0. */ static int test_tcl_integer(Tcl_Interp *interp, const char *zVar){ Tcl_Obj *pObj; int iVal = 0; | > > | > | 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 | ** ** If the named variable cannot be found, or if it cannot be interpreted ** as a integer, return 0. */ static int test_tcl_integer(Tcl_Interp *interp, const char *zVar){ Tcl_Obj *pObj; int iVal = 0; Tcl_Obj *pName = Tcl_NewStringObj(zVar, -1); Tcl_IncrRefCount(pName); pObj = Tcl_ObjGetVar2(interp, pName, 0, TCL_GLOBAL_ONLY); Tcl_DecrRefCount(pName); if( pObj ) Tcl_GetIntFromObj(0, pObj, &iVal); return iVal; } static int test_session_error(Tcl_Interp *interp, int rc, char *zErr){ extern const char *sqlite3ErrName(int); Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1)); |
︙ | ︙ | |||
224 225 226 227 228 229 230 | void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ TestSession *p = (TestSession*)clientData; sqlite3_session *pSession = p->pSession; | | > > > | 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 | void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ TestSession *p = (TestSession*)clientData; sqlite3_session *pSession = p->pSession; static struct SessionSubcmd { const char *zSub; int nArg; const char *zMsg; } aSub[] = { { "attach", 1, "TABLE" }, /* 0 */ { "changeset", 0, "" }, /* 1 */ { "delete", 0, "" }, /* 2 */ { "enable", 1, "BOOL" }, /* 3 */ { "indirect", 1, "BOOL" }, /* 4 */ { "isempty", 0, "" }, /* 5 */ { "table_filter", 1, "SCRIPT" }, /* 6 */ { "patchset", 0, "", }, /* 7 */ { "diff", 2, "FROMDB TBL" }, /* 8 */ { "fullchangeset",0, "" }, /* 9 */ { "memory_used", 0, "", }, /* 10 */ { "changeset_size", 0, "", }, /* 11 */ { "object_config_size", 1, "INTEGER", }, /* 12 */ { 0 } }; int iSub; int rc; if( objc<2 ){ Tcl_WrongNumArgs(interp, 1, objv, "SUBCOMMAND ..."); |
︙ | ︙ | |||
348 349 350 351 352 353 354 355 356 357 358 359 360 361 | ); assert( rc!=SQLITE_OK || zErr==0 ); if( rc ){ return test_session_error(interp, rc, zErr); } break; } } return TCL_OK; } static void SQLITE_TCLAPI test_session_del(void *clientData){ TestSession *p = (TestSession*)clientData; | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | ); assert( rc!=SQLITE_OK || zErr==0 ); if( rc ){ return test_session_error(interp, rc, zErr); } break; } case 10: { /* memory_used */ sqlite3_int64 nMalloc = sqlite3session_memory_used(pSession); Tcl_SetObjResult(interp, Tcl_NewWideIntObj(nMalloc)); break; } case 11: { sqlite3_int64 nSize = sqlite3session_changeset_size(pSession); Tcl_SetObjResult(interp, Tcl_NewWideIntObj(nSize)); break; } case 12: { int rc; int iArg; if( Tcl_GetIntFromObj(interp, objv[2], &iArg) ){ return TCL_ERROR; } rc = sqlite3session_object_config( pSession, SQLITE_SESSION_OBJCONFIG_SIZE, &iArg ); if( rc!=SQLITE_OK ){ extern const char *sqlite3ErrName(int); Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1)); }else{ Tcl_SetObjResult(interp, Tcl_NewIntObj(iArg)); } break; } } return TCL_OK; } static void SQLITE_TCLAPI test_session_del(void *clientData){ TestSession *p = (TestSession*)clientData; |
︙ | ︙ | |||
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 | int objc, Tcl_Obj *CONST objv[] ){ sqlite3 *db; Tcl_CmdInfo info; int rc; /* sqlite3session_create() return code */ TestSession *p; /* New wrapper object */ if( objc!=4 ){ Tcl_WrongNumArgs(interp, 1, objv, "CMD DB-HANDLE DB-NAME"); return TCL_ERROR; } if( 0==Tcl_GetCommandInfo(interp, Tcl_GetString(objv[2]), &info) ){ Tcl_AppendResult(interp, "no such handle: ", Tcl_GetString(objv[2]), 0); return TCL_ERROR; } db = *(sqlite3 **)info.objClientData; p = (TestSession*)ckalloc(sizeof(TestSession)); memset(p, 0, sizeof(TestSession)); rc = sqlite3session_create(db, Tcl_GetString(objv[3]), &p->pSession); if( rc!=SQLITE_OK ){ ckfree((char*)p); return test_session_error(interp, rc, 0); } Tcl_CreateObjCommand( interp, Tcl_GetString(objv[1]), test_session_cmd, (ClientData)p, test_session_del ); Tcl_SetObjResult(interp, objv[1]); return TCL_OK; } | > > > > > > > > | 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 | int objc, Tcl_Obj *CONST objv[] ){ sqlite3 *db; Tcl_CmdInfo info; int rc; /* sqlite3session_create() return code */ TestSession *p; /* New wrapper object */ int iArg = -1; if( objc!=4 ){ Tcl_WrongNumArgs(interp, 1, objv, "CMD DB-HANDLE DB-NAME"); return TCL_ERROR; } if( 0==Tcl_GetCommandInfo(interp, Tcl_GetString(objv[2]), &info) ){ Tcl_AppendResult(interp, "no such handle: ", Tcl_GetString(objv[2]), 0); return TCL_ERROR; } db = *(sqlite3 **)info.objClientData; p = (TestSession*)ckalloc(sizeof(TestSession)); memset(p, 0, sizeof(TestSession)); rc = sqlite3session_create(db, Tcl_GetString(objv[3]), &p->pSession); if( rc!=SQLITE_OK ){ ckfree((char*)p); return test_session_error(interp, rc, 0); } /* Query the SQLITE_SESSION_OBJCONFIG_SIZE option to ensure that it ** is clear by default. Then set it. */ sqlite3session_object_config(p->pSession,SQLITE_SESSION_OBJCONFIG_SIZE,&iArg); assert( iArg==0 ); iArg = 1; sqlite3session_object_config(p->pSession,SQLITE_SESSION_OBJCONFIG_SIZE,&iArg); Tcl_CreateObjCommand( interp, Tcl_GetString(objv[1]), test_session_cmd, (ClientData)p, test_session_del ); Tcl_SetObjResult(interp, objv[1]); return TCL_OK; } |
︙ | ︙ | |||
1253 1254 1255 1256 1257 1258 1259 | */ static int SQLITE_TCLAPI test_rebaser_cmd( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ | | | 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 | */ static int SQLITE_TCLAPI test_rebaser_cmd( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ static struct RebaseSubcmd { const char *zSub; int nArg; const char *zMsg; int iSub; } aSub[] = { { "configure", 1, "REBASE-BLOB" }, /* 0 */ { "delete", 0, "" }, /* 1 */ |
︙ | ︙ | |||
1370 1371 1372 1373 1374 1375 1376 | */ static int SQLITE_TCLAPI test_sqlite3session_config( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ | | | 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 | */ static int SQLITE_TCLAPI test_sqlite3session_config( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ static struct ConfigOpt { const char *zSub; int op; } aSub[] = { { "strm_size", SQLITE_SESSION_CONFIG_STRMSIZE }, { "invalid", 0 }, { 0 } }; |
︙ | ︙ |
Changes to ext/userauth/userauth.c.
︙ | ︙ | |||
36 37 38 39 40 41 42 | const char *zFormat, ... ){ sqlite3_stmt *pStmt; char *zSql; int rc; va_list ap; | | | 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | const char *zFormat, ... ){ sqlite3_stmt *pStmt; char *zSql; int rc; va_list ap; u64 savedFlags = db->flags; va_start(ap, zFormat); zSql = sqlite3_vmprintf(zFormat, ap); va_end(ap); if( zSql==0 ) return 0; db->flags |= SQLITE_WriteSchema; rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0); |
︙ | ︙ |
Changes to main.mk.
1 2 3 4 5 6 7 | ############################################################################### # The following macros should be defined before this script is # invoked: # # TOP The toplevel directory of the source tree. This is the # directory that contains this "Makefile.in" and the # "configure.in" script. | > | 1 2 3 4 5 6 7 8 | ############################################################################### # The following macros should be defined before this script is # invoked: # # TOP The toplevel directory of the source tree. This is the # directory that contains this "Makefile.in" and the # "configure.in" script. |
︙ | ︙ | |||
70 71 72 73 74 75 76 | notify.o opcodes.o os.o os_unix.o os_win.o \ pager.o pcache.o pcache1.o pragma.o prepare.o printf.o \ random.o resolve.o rowset.o rtree.o \ select.o sqlite3rbu.o status.o stmt.o \ table.o threads.o tokenize.o treeview.o trigger.o \ update.o upsert.o userauth.o util.o vacuum.o \ vdbeapi.o vdbeaux.o vdbeblob.o vdbemem.o vdbesort.o \ | > | | 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 | notify.o opcodes.o os.o os_unix.o os_win.o \ pager.o pcache.o pcache1.o pragma.o prepare.o printf.o \ random.o resolve.o rowset.o rtree.o \ select.o sqlite3rbu.o status.o stmt.o \ table.o threads.o tokenize.o treeview.o trigger.o \ update.o upsert.o userauth.o util.o vacuum.o \ vdbeapi.o vdbeaux.o vdbeblob.o vdbemem.o vdbesort.o \ vdbetrace.o vdbevtab.o \ wal.o walker.o where.o wherecode.o whereexpr.o \ utf.o vtab.o window.o LIBOBJ += sqlite3session.o # All of the source code files. # SRC = \ |
︙ | ︙ | |||
169 170 171 172 173 174 175 176 177 178 179 180 181 182 | $(TOP)/src/vdbe.h \ $(TOP)/src/vdbeapi.c \ $(TOP)/src/vdbeaux.c \ $(TOP)/src/vdbeblob.c \ $(TOP)/src/vdbemem.c \ $(TOP)/src/vdbesort.c \ $(TOP)/src/vdbetrace.c \ $(TOP)/src/vdbeInt.h \ $(TOP)/src/vtab.c \ $(TOP)/src/vxworks.h \ $(TOP)/src/wal.c \ $(TOP)/src/wal.h \ $(TOP)/src/walker.c \ $(TOP)/src/where.c \ | > | 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 | $(TOP)/src/vdbe.h \ $(TOP)/src/vdbeapi.c \ $(TOP)/src/vdbeaux.c \ $(TOP)/src/vdbeblob.c \ $(TOP)/src/vdbemem.c \ $(TOP)/src/vdbesort.c \ $(TOP)/src/vdbetrace.c \ $(TOP)/src/vdbevtab.c \ $(TOP)/src/vdbeInt.h \ $(TOP)/src/vtab.c \ $(TOP)/src/vxworks.h \ $(TOP)/src/wal.c \ $(TOP)/src/wal.h \ $(TOP)/src/walker.c \ $(TOP)/src/where.c \ |
︙ | ︙ | |||
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 | $(TOP)/src/test_server.c \ $(TOP)/src/test_sqllog.c \ $(TOP)/src/test_superlock.c \ $(TOP)/src/test_syscall.c \ $(TOP)/src/test_tclsh.c \ $(TOP)/src/test_tclvar.c \ $(TOP)/src/test_thread.c \ $(TOP)/src/test_vfs.c \ $(TOP)/src/test_windirent.c \ $(TOP)/src/test_window.c \ $(TOP)/src/test_wsd.c # Extensions to be statically loaded. # TESTSRC += \ $(TOP)/ext/misc/amatch.c \ $(TOP)/ext/misc/carray.c \ $(TOP)/ext/misc/closure.c \ $(TOP)/ext/misc/csv.c \ $(TOP)/ext/misc/eval.c \ $(TOP)/ext/misc/explain.c \ $(TOP)/ext/misc/fileio.c \ $(TOP)/ext/misc/fuzzer.c \ $(TOP)/ext/misc/ieee754.c \ $(TOP)/ext/misc/mmapwarm.c \ $(TOP)/ext/misc/nextchar.c \ $(TOP)/ext/misc/normalize.c \ $(TOP)/ext/misc/percentile.c \ $(TOP)/ext/misc/regexp.c \ $(TOP)/ext/misc/remember.c \ $(TOP)/ext/misc/series.c \ $(TOP)/ext/misc/spellfix.c \ $(TOP)/ext/misc/totype.c \ $(TOP)/ext/misc/unionvtab.c \ $(TOP)/ext/misc/wholenumber.c \ | > > > > > < | > | 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 | $(TOP)/src/test_server.c \ $(TOP)/src/test_sqllog.c \ $(TOP)/src/test_superlock.c \ $(TOP)/src/test_syscall.c \ $(TOP)/src/test_tclsh.c \ $(TOP)/src/test_tclvar.c \ $(TOP)/src/test_thread.c \ $(TOP)/src/test_vdbecov.c \ $(TOP)/src/test_vfs.c \ $(TOP)/src/test_windirent.c \ $(TOP)/src/test_window.c \ $(TOP)/src/test_wsd.c # Extensions to be statically loaded. # TESTSRC += \ $(TOP)/ext/misc/amatch.c \ $(TOP)/ext/misc/appendvfs.c \ $(TOP)/ext/misc/carray.c \ $(TOP)/ext/misc/cksumvfs.c \ $(TOP)/ext/misc/closure.c \ $(TOP)/ext/misc/csv.c \ $(TOP)/ext/misc/decimal.c \ $(TOP)/ext/misc/eval.c \ $(TOP)/ext/misc/explain.c \ $(TOP)/ext/misc/fileio.c \ $(TOP)/ext/misc/fuzzer.c \ $(TOP)/ext/misc/ieee754.c \ $(TOP)/ext/misc/mmapwarm.c \ $(TOP)/ext/misc/nextchar.c \ $(TOP)/ext/misc/normalize.c \ $(TOP)/ext/misc/percentile.c \ $(TOP)/ext/misc/prefixes.c \ $(TOP)/ext/misc/regexp.c \ $(TOP)/ext/misc/remember.c \ $(TOP)/ext/misc/series.c \ $(TOP)/ext/misc/spellfix.c \ $(TOP)/ext/misc/totype.c \ $(TOP)/ext/misc/unionvtab.c \ $(TOP)/ext/misc/wholenumber.c \ $(TOP)/ext/misc/zipfile.c \ $(TOP)/ext/fts5/fts5_tcl.c \ $(TOP)/ext/fts5/fts5_test_mi.c \ $(TOP)/ext/fts5/fts5_test_tok.c \ $(TOP)/ext/rtree/test_rtreedoc.c #TESTSRC += $(TOP)/ext/fts2/fts2_tokenizer.c #TESTSRC += $(TOP)/ext/fts3/fts3_tokenizer.c TESTSRC2 = \ $(TOP)/src/attach.c \ |
︙ | ︙ | |||
416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 | $(TOP)/src/tokenize.c \ $(TOP)/src/utf.c \ $(TOP)/src/util.c \ $(TOP)/src/vdbeapi.c \ $(TOP)/src/vdbeaux.c \ $(TOP)/src/vdbe.c \ $(TOP)/src/vdbemem.c \ $(TOP)/src/where.c \ $(TOP)/src/wherecode.c \ $(TOP)/src/whereexpr.c \ parse.c \ $(TOP)/ext/fts3/fts3.c \ $(TOP)/ext/fts3/fts3_aux.c \ $(TOP)/ext/fts3/fts3_expr.c \ $(TOP)/ext/fts3/fts3_tokenizer.c \ $(TOP)/ext/fts3/fts3_write.c \ $(TOP)/ext/async/sqlite3async.c \ $(TOP)/ext/misc/stmt.c \ $(TOP)/ext/session/sqlite3session.c \ $(TOP)/ext/session/sqlite3changebatch.c \ | > | > | 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 | $(TOP)/src/tokenize.c \ $(TOP)/src/utf.c \ $(TOP)/src/util.c \ $(TOP)/src/vdbeapi.c \ $(TOP)/src/vdbeaux.c \ $(TOP)/src/vdbe.c \ $(TOP)/src/vdbemem.c \ $(TOP)/src/vdbevtab.c \ $(TOP)/src/where.c \ $(TOP)/src/wherecode.c \ $(TOP)/src/whereexpr.c \ parse.c \ $(TOP)/ext/fts3/fts3.c \ $(TOP)/ext/fts3/fts3_aux.c \ $(TOP)/ext/fts3/fts3_expr.c \ $(TOP)/ext/fts3/fts3_tokenizer.c \ $(TOP)/ext/fts3/fts3_write.c \ $(TOP)/ext/async/sqlite3async.c \ $(TOP)/ext/misc/stmt.c \ $(TOP)/ext/session/sqlite3session.c \ $(TOP)/ext/session/sqlite3changebatch.c \ $(TOP)/ext/session/test_session.c \ fts5.c # Header files used by all library source files. # HDR = \ $(TOP)/src/btree.h \ $(TOP)/src/btreeInt.h \ $(TOP)/src/hash.h \ |
︙ | ︙ | |||
506 507 508 509 510 511 512 | FUZZDATA = \ $(TOP)/test/fuzzdata1.db \ $(TOP)/test/fuzzdata2.db \ $(TOP)/test/fuzzdata3.db \ $(TOP)/test/fuzzdata4.db \ $(TOP)/test/fuzzdata5.db \ $(TOP)/test/fuzzdata6.db \ | | > | | > > > > > | | | | 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 | FUZZDATA = \ $(TOP)/test/fuzzdata1.db \ $(TOP)/test/fuzzdata2.db \ $(TOP)/test/fuzzdata3.db \ $(TOP)/test/fuzzdata4.db \ $(TOP)/test/fuzzdata5.db \ $(TOP)/test/fuzzdata6.db \ $(TOP)/test/fuzzdata7.db \ $(TOP)/test/fuzzdata8.db # Standard options to testfixture # TESTOPTS = --verbose=file --output=test-out.txt # Extra compiler options for various shell tools # SHELL_OPT += -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_FTS5 SHELL_OPT += -DSQLITE_ENABLE_RTREE SHELL_OPT += -DSQLITE_ENABLE_EXPLAIN_COMMENTS SHELL_OPT += -DSQLITE_ENABLE_UNKNOWN_SQL_FUNCTION SHELL_OPT += -DSQLITE_ENABLE_STMTVTAB SHELL_OPT += -DSQLITE_ENABLE_DBPAGE_VTAB SHELL_OPT += -DSQLITE_ENABLE_DBSTAT_VTAB SHELL_OPT += -DSQLITE_ENABLE_BYTECODE_VTAB SHELL_OPT += -DSQLITE_ENABLE_OFFSET_SQL_FUNC FUZZERSHELL_OPT = -DSQLITE_ENABLE_JSON1 FUZZCHECK_OPT = -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_MEMSYS5 FUZZCHECK_OPT += -DSQLITE_MAX_MEMORY=50000000 FUZZCHECK_OPT += -DSQLITE_PRINTF_PRECISION_LIMIT=1000 FUZZCHECK_OPT += -DSQLITE_ENABLE_FTS4 FUZZCHECK_OPT += -DSQLITE_ENABLE_RTREE FUZZCHECK_OPT += -DSQLITE_ENABLE_GEOPOLY FUZZCHECK_OPT += -DSQLITE_ENABLE_DBSTAT_VTAB FUZZCHECK_OPT += -DSQLITE_ENABLE_BYTECODE_VTAB DBFUZZ_OPT = KV_OPT = -DSQLITE_THREADSAFE=0 -DSQLITE_DIRECT_OVERFLOW_READ ST_OPT = -DSQLITE_THREADSAFE=0 # This is the default Makefile target. The objects listed here # are what get build when you type just "make" with no arguments. # all: sqlite3.h sqlite3ext.h libsqlite3.a sqlite3$(EXE) libsqlite3.a: sqlite3.h $(LIBOBJ) $(AR) libsqlite3.a $(LIBOBJ) $(RANLIB) libsqlite3.a sqlite3$(EXE): sqlite3.h libsqlite3.a shell.c $(TCCX) $(READLINE_FLAGS) -o sqlite3$(EXE) $(SHELL_OPT) \ shell.c libsqlite3.a $(LIBREADLINE) $(TLIBS) $(THREADLIB) sqldiff$(EXE): $(TOP)/tool/sqldiff.c sqlite3.c sqlite3.h $(TCCX) -o sqldiff$(EXE) -DSQLITE_THREADSAFE=0 \ $(TOP)/tool/sqldiff.c sqlite3.c $(TLIBS) $(THREADLIB) |
︙ | ︙ | |||
571 572 573 574 575 576 577 578 579 580 581 582 583 584 | $(TLIBS) $(THREADLIB) dbfuzz$(EXE): $(TOP)/test/dbfuzz.c sqlite3.c sqlite3.h $(TCCX) -o dbfuzz$(EXE) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION \ $(DBFUZZ_OPT) $(TOP)/test/dbfuzz.c sqlite3.c \ $(TLIBS) $(THREADLIB) fuzzcheck$(EXE): $(TOP)/test/fuzzcheck.c sqlite3.c sqlite3.h $(TOP)/test/ossfuzz.c $(TCCX) -o fuzzcheck$(EXE) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION \ -DSQLITE_ENABLE_MEMSYS5 $(FUZZCHECK_OPT) -DSQLITE_OSS_FUZZ \ $(TOP)/test/fuzzcheck.c $(TOP)/test/ossfuzz.c sqlite3.c $(TLIBS) $(THREADLIB) ossshell$(EXE): $(TOP)/test/ossfuzz.c $(TOP)/test/ossshell.c sqlite3.c sqlite3.h $(TCCX) -o ossshell$(EXE) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION \ | > > > > > > > > > > > > > > | 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 | $(TLIBS) $(THREADLIB) dbfuzz$(EXE): $(TOP)/test/dbfuzz.c sqlite3.c sqlite3.h $(TCCX) -o dbfuzz$(EXE) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION \ $(DBFUZZ_OPT) $(TOP)/test/dbfuzz.c sqlite3.c \ $(TLIBS) $(THREADLIB) DBFUZZ2_OPTS = \ -DSQLITE_THREADSAFE=0 \ -DSQLITE_OMIT_LOAD_EXTENSION \ -DSQLITE_DEBUG \ -DSQLITE_ENABLE_DBSTAT_VTAB \ -DSQLITE_ENABLE_BYTECODE_VTAB \ -DSQLITE_ENABLE_RTREE \ -DSQLITE_ENABLE_FTS4 \ -DSQLITE_ENABLE_FTS5 dbfuzz2$(EXE): $(TOP)/test/dbfuzz2.c sqlite3.c sqlite3.h $(TCCX) -I. -g -O0 -DSTANDALONE -o dbfuzz2$(EXE) \ $(DBFUZZ2_OPTS) $(TOP)/test/dbfuzz2.c sqlite3.c $(TLIBS) $(THREADLIB) fuzzcheck$(EXE): $(TOP)/test/fuzzcheck.c sqlite3.c sqlite3.h $(TOP)/test/ossfuzz.c $(TCCX) -o fuzzcheck$(EXE) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION \ -DSQLITE_ENABLE_MEMSYS5 $(FUZZCHECK_OPT) -DSQLITE_OSS_FUZZ \ $(TOP)/test/fuzzcheck.c $(TOP)/test/ossfuzz.c sqlite3.c $(TLIBS) $(THREADLIB) ossshell$(EXE): $(TOP)/test/ossfuzz.c $(TOP)/test/ossshell.c sqlite3.c sqlite3.h $(TCCX) -o ossshell$(EXE) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION \ |
︙ | ︙ | |||
632 633 634 635 636 637 638 | echo '#endif /* USE_SYSTEM_SQLITE */' >>tclsqlite3.c cat $(TOP)/src/tclsqlite.c >>tclsqlite3.c sqlite3ext.h: target_source cp tsrc/sqlite3ext.h . sqlite3.c-debug: target_source $(TOP)/tool/mksqlite3c.tcl | | | 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 | echo '#endif /* USE_SYSTEM_SQLITE */' >>tclsqlite3.c cat $(TOP)/src/tclsqlite.c >>tclsqlite3.c sqlite3ext.h: target_source cp tsrc/sqlite3ext.h . sqlite3.c-debug: target_source $(TOP)/tool/mksqlite3c.tcl tclsh $(TOP)/tool/mksqlite3c.tcl --linemacros=1 echo '#ifndef USE_SYSTEM_SQLITE' >tclsqlite3.c cat sqlite3.c >>tclsqlite3.c echo '#endif /* USE_SYSTEM_SQLITE */' >>tclsqlite3.c echo '#line 1 "tclsqlite.c"' >>tclsqlite3.c cat $(TOP)/src/tclsqlite.c >>tclsqlite3.c sqlite3-all.c: sqlite3.c $(TOP)/tool/split-sqlite3c.tcl |
︙ | ︙ | |||
691 692 693 694 695 696 697 | cat parse.h $(TOP)/src/vdbe.c | \ tclsh $(TOP)/tool/mkopcodeh.tcl >opcodes.h # Rules to build parse.c and parse.h - the outputs of lemon. # parse.h: parse.c | | < < < > > > > > > > | | > > > > > > | 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 | cat parse.h $(TOP)/src/vdbe.c | \ tclsh $(TOP)/tool/mkopcodeh.tcl >opcodes.h # Rules to build parse.c and parse.h - the outputs of lemon. # parse.h: parse.c parse.c: $(TOP)/src/parse.y lemon cp $(TOP)/src/parse.y . ./lemon -s $(OPTS) parse.y sqlite3.h: $(TOP)/src/sqlite.h.in $(TOP)/manifest mksourceid $(TOP)/VERSION $(TOP)/ext/rtree/sqlite3rtree.h tclsh $(TOP)/tool/mksqlite3h.tcl $(TOP) >sqlite3.h sqlite3rc.h: $(TOP)/src/sqlite3.rc $(TOP)/VERSION echo '#ifndef SQLITE_RESOURCE_VERSION' >$@ echo -n '#define SQLITE_RESOURCE_VERSION ' >>$@ cat $(TOP)/VERSION | tclsh $(TOP)/tool/replace.tcl exact . , >>$@ echo '#endif' >>sqlite3rc.h keywordhash.h: $(TOP)/tool/mkkeywordhash.c $(BCC) -o mkkeywordhash $(OPTS) $(TOP)/tool/mkkeywordhash.c ./mkkeywordhash >keywordhash.h # Source files that go into making shell.c SHELL_SRC = \ $(TOP)/src/shell.c.in \ $(TOP)/ext/misc/appendvfs.c \ $(TOP)/ext/misc/completion.c \ $(TOP)/ext/misc/decimal.c \ $(TOP)/ext/misc/fileio.c \ $(TOP)/ext/misc/ieee754.c \ $(TOP)/ext/misc/regexp.c \ $(TOP)/ext/misc/series.c \ $(TOP)/ext/misc/shathree.c \ $(TOP)/ext/misc/sqlar.c \ $(TOP)/ext/misc/uint.c \ $(TOP)/ext/expert/sqlite3expert.c \ $(TOP)/ext/expert/sqlite3expert.h \ $(TOP)/ext/misc/zipfile.c \ $(TOP)/ext/misc/memtrace.c \ $(TOP)/ext/misc/dbdata.c \ $(TOP)/src/test_windirent.c shell.c: $(SHELL_SRC) $(TOP)/tool/mkshellc.tcl tclsh $(TOP)/tool/mkshellc.tcl >shell.c |
︙ | ︙ | |||
785 786 787 788 789 790 791 | fts3_unicode2.o: $(TOP)/ext/fts3/fts3_unicode2.c $(HDR) $(EXTHDR) $(TCCX) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3_unicode2.c fts3_write.o: $(TOP)/ext/fts3/fts3_write.c $(HDR) $(EXTHDR) $(TCCX) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3_write.c | | | | | 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 | fts3_unicode2.o: $(TOP)/ext/fts3/fts3_unicode2.c $(HDR) $(EXTHDR) $(TCCX) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3_unicode2.c fts3_write.o: $(TOP)/ext/fts3/fts3_write.c $(HDR) $(EXTHDR) $(TCCX) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3_write.c fts5.o: fts5.c sqlite3ext.h sqlite3.h $(TCCX) -DSQLITE_CORE -c fts5.c json1.o: $(TOP)/ext/misc/json1.c sqlite3ext.h sqlite3.h $(TCCX) -DSQLITE_CORE -c $(TOP)/ext/misc/json1.c stmt.o: $(TOP)/ext/misc/stmt.c sqlite3ext.h sqlite3.h $(TCCX) -DSQLITE_CORE -c $(TOP)/ext/misc/stmt.c rtree.o: $(TOP)/ext/rtree/rtree.c $(HDR) $(EXTHDR) $(TCCX) -DSQLITE_CORE -c $(TOP)/ext/rtree/rtree.c |
︙ | ︙ | |||
872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 | # TESTFIXTURE_FLAGS = -DSQLITE_TEST=1 -DSQLITE_CRASH_TEST=1 TESTFIXTURE_FLAGS += -DSQLITE_SERVER=1 -DSQLITE_PRIVATE="" -DSQLITE_CORE TESTFIXTURE_FLAGS += -DSQLITE_SERIES_CONSTRAINT_VERIFY=1 TESTFIXTURE_FLAGS += -DSQLITE_DEFAULT_PAGE_SIZE=1024 TESTFIXTURE_FLAGS += -DSQLITE_ENABLE_STMTVTAB TESTFIXTURE_FLAGS += -DSQLITE_ENABLE_DBPAGE_VTAB TESTFIXTURE_FLAGS += -DTCLSH_INIT_PROC=sqlite3TestInit testfixture$(EXE): $(TESTSRC2) libsqlite3.a $(TESTSRC) $(TOP)/src/tclsqlite.c $(TCCX) $(TCL_FLAGS) $(TESTFIXTURE_FLAGS) \ $(TESTSRC) $(TESTSRC2) $(TOP)/src/tclsqlite.c \ -o testfixture$(EXE) $(LIBTCL) libsqlite3.a $(THREADLIB) amalgamation-testfixture$(EXE): sqlite3.c $(TESTSRC) $(TOP)/src/tclsqlite.c \ | > > | 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 | # TESTFIXTURE_FLAGS = -DSQLITE_TEST=1 -DSQLITE_CRASH_TEST=1 TESTFIXTURE_FLAGS += -DSQLITE_SERVER=1 -DSQLITE_PRIVATE="" -DSQLITE_CORE TESTFIXTURE_FLAGS += -DSQLITE_SERIES_CONSTRAINT_VERIFY=1 TESTFIXTURE_FLAGS += -DSQLITE_DEFAULT_PAGE_SIZE=1024 TESTFIXTURE_FLAGS += -DSQLITE_ENABLE_STMTVTAB TESTFIXTURE_FLAGS += -DSQLITE_ENABLE_DBPAGE_VTAB TESTFIXTURE_FLAGS += -DSQLITE_ENABLE_BYTECODE_VTAB TESTFIXTURE_FLAGS += -DTCLSH_INIT_PROC=sqlite3TestInit TESTFIXTURE_FLAGS += -DSQLITE_CKSUMVFS_STATIC testfixture$(EXE): $(TESTSRC2) libsqlite3.a $(TESTSRC) $(TOP)/src/tclsqlite.c $(TCCX) $(TCL_FLAGS) $(TESTFIXTURE_FLAGS) \ $(TESTSRC) $(TESTSRC2) $(TOP)/src/tclsqlite.c \ -o testfixture$(EXE) $(LIBTCL) libsqlite3.a $(THREADLIB) amalgamation-testfixture$(EXE): sqlite3.c $(TESTSRC) $(TOP)/src/tclsqlite.c \ |
︙ | ︙ | |||
912 913 914 915 916 917 918 | queryplantest: testfixture$(EXE) sqlite3$(EXE) ./testfixture$(EXE) $(TOP)/test/permutations.test queryplanner $(TESTOPTS) fuzztest: fuzzcheck$(EXE) $(FUZZDATA) sessionfuzz$(EXE) $(TOP)/test/sessionfuzz-data1.db ./fuzzcheck$(EXE) $(FUZZDATA) ./sessionfuzz run $(TOP)/test/sessionfuzz-data1.db | < < < < | | > > > | 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 | queryplantest: testfixture$(EXE) sqlite3$(EXE) ./testfixture$(EXE) $(TOP)/test/permutations.test queryplanner $(TESTOPTS) fuzztest: fuzzcheck$(EXE) $(FUZZDATA) sessionfuzz$(EXE) $(TOP)/test/sessionfuzz-data1.db ./fuzzcheck$(EXE) $(FUZZDATA) ./sessionfuzz run $(TOP)/test/sessionfuzz-data1.db valgrindfuzz: fuzzcheck$(EXE) $(FUZZDATA) sessionfuzz$(EXE) $(TOP)/test/sessionfuzz-data1.db valgrind ./fuzzcheck$(EXE) --cell-size-check --limit-mem 10M $(FUZZDATA) valgrind ./sessionfuzz run $(TOP)/test/sessionfuzz-data1.db # The veryquick.test TCL tests. # tcltest: ./testfixture$(EXE) ./testfixture$(EXE) $(TOP)/test/veryquick.test $(TESTOPTS) # A very quick test using only testfixture and omitting all the slower # tests. Designed to run in under 3 minutes on a workstation. # quicktest: ./testfixture$(EXE) ./testfixture$(EXE) $(TOP)/test/extraquick.test $(TESTOPTS) # The default test case. Runs most of the faster standard TCL tests, # and fuzz tests, and sqlite3_analyzer and sqldiff tests. test: fuzztest sourcetest $(TESTPROGS) tcltest # Run a test using valgrind. This can take a really long time # because valgrind is so much slower than a native machine. # valgrindtest: $(TESTPROGS) valgrindfuzz OMIT_MISUSE=1 valgrind -v \ ./testfixture$(EXE) $(TOP)/test/permutations.test valgrind $(TESTOPTS) # A very fast test that checks basic sanity. The name comes from # the 60s-era electronics testing: "Turn it on and see if smoke # comes out." # smoketest: $(TESTPROGS) fuzzcheck$(EXE) ./testfixture$(EXE) $(TOP)/test/main.test $(TESTOPTS) shelltest: $(TESTPROGS) ./testfixture$(EXT) $(TOP)/test/permutations.test shell # The next two rules are used to support the "threadtest" target. Building # threadtest runs a few thread-safety tests that are implemented in C. This # target is invoked by the releasetest.tcl script. # THREADTEST3_SRC = $(TOP)/test/threadtest3.c \ $(TOP)/test/tt3_checkpoint.c \ $(TOP)/test/tt3_index.c \ |
︙ | ︙ | |||
999 1000 1001 1002 1003 1004 1005 | $(TCC) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION -o showwal$(EXE) \ $(TOP)/tool/showwal.c sqlite3.o $(THREADLIB) showshm$(EXE): $(TOP)/tool/showshm.c $(TCC) -o showshm$(EXE) $(TOP)/tool/showshm.c index_usage$(EXE): $(TOP)/tool/index_usage.c sqlite3.o | | | 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 | $(TCC) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION -o showwal$(EXE) \ $(TOP)/tool/showwal.c sqlite3.o $(THREADLIB) showshm$(EXE): $(TOP)/tool/showshm.c $(TCC) -o showshm$(EXE) $(TOP)/tool/showshm.c index_usage$(EXE): $(TOP)/tool/index_usage.c sqlite3.o $(TCC) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_DEPRECATED $(SHELL_OPTS) -o index_usage$(EXE) \ $(TOP)/tool/index_usage.c sqlite3.o $(THREADLIB) changeset$(EXE): $(TOP)/ext/session/changeset.c sqlite3.o $(TCC) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION -o changeset$(EXE) \ $(TOP)/ext/session/changeset.c sqlite3.o $(THREADLIB) changesetfuzz$(EXE): $(TOP)/ext/session/changesetfuzz.c sqlite3.o |
︙ | ︙ | |||
1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 | rbu$(EXE): $(TOP)/ext/rbu/rbu.c $(TOP)/ext/rbu/sqlite3rbu.c sqlite3.o $(TCC) -I. -o rbu$(EXE) $(TOP)/ext/rbu/rbu.c sqlite3.o \ $(THREADLIB) loadfts: $(TOP)/tool/loadfts.c libsqlite3.a $(TCC) $(TOP)/tool/loadfts.c libsqlite3.a -o loadfts $(THREADLIB) # This target will fail if the SQLite amalgamation contains any exported # symbols that do not begin with "sqlite3_". It is run as part of the # releasetest.tcl script. # checksymbols: sqlite3.o nm -g --defined-only sqlite3.o | grep -v " sqlite3_" ; test $$? -ne 0 # Build the amalgamation-autoconf package. The amalamgation-tarball target builds # a tarball named for the version number. Ex: sqlite-autoconf-3110000.tar.gz. # The snapshot-tarball target builds a tarball named by the SHA1 hash # | > > > | | | 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 | rbu$(EXE): $(TOP)/ext/rbu/rbu.c $(TOP)/ext/rbu/sqlite3rbu.c sqlite3.o $(TCC) -I. -o rbu$(EXE) $(TOP)/ext/rbu/rbu.c sqlite3.o \ $(THREADLIB) loadfts: $(TOP)/tool/loadfts.c libsqlite3.a $(TCC) $(TOP)/tool/loadfts.c libsqlite3.a -o loadfts $(THREADLIB) threadtest5: $(TOP)/test/threadtest5.c libsqlite3.a $(TCC) $(TOP)/test/threadtest5.c libsqlite3.a -o threadtest5 $(THREADLIB) # This target will fail if the SQLite amalgamation contains any exported # symbols that do not begin with "sqlite3_". It is run as part of the # releasetest.tcl script. # checksymbols: sqlite3.o nm -g --defined-only sqlite3.o | grep -v " sqlite3_" ; test $$? -ne 0 # Build the amalgamation-autoconf package. The amalamgation-tarball target builds # a tarball named for the version number. Ex: sqlite-autoconf-3110000.tar.gz. # The snapshot-tarball target builds a tarball named by the SHA1 hash # amalgamation-tarball: sqlite3.c sqlite3rc.h TOP=$(TOP) sh $(TOP)/tool/mkautoconfamal.sh --normal snapshot-tarball: sqlite3.c sqlite3rc.h TOP=$(TOP) sh $(TOP)/tool/mkautoconfamal.sh --snapshot # Standard install and cleanup targets # install: sqlite3 libsqlite3.a sqlite3.h mv sqlite3 /usr/bin |
︙ | ︙ | |||
1104 1105 1106 1107 1108 1109 1110 | rm -f mptester mptester.exe rm -f fuzzershell fuzzershell.exe rm -f fuzzcheck fuzzcheck.exe rm -f sessionfuzz rm -f sqldiff sqldiff.exe rm -f fts5.* fts5parse.* rm -f lsm.h lsm1.c | > | 1148 1149 1150 1151 1152 1153 1154 1155 | rm -f mptester mptester.exe rm -f fuzzershell fuzzershell.exe rm -f fuzzcheck fuzzcheck.exe rm -f sessionfuzz rm -f sqldiff sqldiff.exe rm -f fts5.* fts5parse.* rm -f lsm.h lsm1.c rm -f threadtest5 |
Changes to src/alter.c.
︙ | ︙ | |||
24 25 26 27 28 29 30 | ** Parameter zName is the name of a table that is about to be altered ** (either with ALTER TABLE ... RENAME TO or ALTER TABLE ... ADD COLUMN). ** If the table is a system table, this function leaves an error message ** in pParse->zErr (system tables may not be altered) and returns non-zero. ** ** Or, if zName is not a system table, zero is returned. */ | | | > > > > > > > | | > > > > > > > | | | | | | | | > > > > | > > > > > > > > > > > > > > > > > > > > | | | | 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 | ** Parameter zName is the name of a table that is about to be altered ** (either with ALTER TABLE ... RENAME TO or ALTER TABLE ... ADD COLUMN). ** If the table is a system table, this function leaves an error message ** in pParse->zErr (system tables may not be altered) and returns non-zero. ** ** Or, if zName is not a system table, zero is returned. */ static int isAlterableTable(Parse *pParse, Table *pTab){ if( 0==sqlite3StrNICmp(pTab->zName, "sqlite_", 7) #ifndef SQLITE_OMIT_VIRTUALTABLE || (pTab->tabFlags & TF_Eponymous)!=0 || ( (pTab->tabFlags & TF_Shadow)!=0 && sqlite3ReadOnlyShadowTables(pParse->db) ) #endif ){ sqlite3ErrorMsg(pParse, "table %s may not be altered", pTab->zName); return 1; } return 0; } /* ** Generate code to verify that the schemas of database zDb and, if ** bTemp is not true, database "temp", can still be parsed. This is ** called at the end of the generation of an ALTER TABLE ... RENAME ... ** statement to ensure that the operation has not rendered any schema ** objects unusable. */ static void renameTestSchema( Parse *pParse, /* Parse context */ const char *zDb, /* Name of db to verify schema of */ int bTemp, /* True if this is the temp db */ const char *zWhen, /* "when" part of error message */ int bNoDQS /* Do not allow DQS in the schema */ ){ pParse->colNamesSet = 1; sqlite3NestedParse(pParse, "SELECT 1 " "FROM \"%w\"." LEGACY_SCHEMA_TABLE " " "WHERE name NOT LIKE 'sqliteX_%%' ESCAPE 'X'" " AND sql NOT LIKE 'create virtual%%'" " AND sqlite_rename_test(%Q, sql, type, name, %d, %Q, %d)=NULL ", zDb, zDb, bTemp, zWhen, bNoDQS ); if( bTemp==0 ){ sqlite3NestedParse(pParse, "SELECT 1 " "FROM temp." LEGACY_SCHEMA_TABLE " " "WHERE name NOT LIKE 'sqliteX_%%' ESCAPE 'X'" " AND sql NOT LIKE 'create virtual%%'" " AND sqlite_rename_test(%Q, sql, type, name, 1, %Q, %d)=NULL ", zDb, zWhen, bNoDQS ); } } /* ** Generate VM code to replace any double-quoted strings (but not double-quoted ** identifiers) within the "sql" column of the sqlite_schema table in ** database zDb with their single-quoted equivalents. If argument bTemp is ** not true, similarly update all SQL statements in the sqlite_schema table ** of the temp db. */ static void renameFixQuotes(Parse *pParse, const char *zDb, int bTemp){ sqlite3NestedParse(pParse, "UPDATE \"%w\"." LEGACY_SCHEMA_TABLE " SET sql = sqlite_rename_quotefix(%Q, sql)" "WHERE name NOT LIKE 'sqliteX_%%' ESCAPE 'X'" " AND sql NOT LIKE 'create virtual%%'" , zDb, zDb ); if( bTemp==0 ){ sqlite3NestedParse(pParse, "UPDATE temp." LEGACY_SCHEMA_TABLE " SET sql = sqlite_rename_quotefix('temp', sql)" "WHERE name NOT LIKE 'sqliteX_%%' ESCAPE 'X'" " AND sql NOT LIKE 'create virtual%%'" ); } } /* ** Generate code to reload the schema for database iDb. And, if iDb!=1, for ** the temp database as well. */ static void renameReloadSchema(Parse *pParse, int iDb, u16 p5){ Vdbe *v = pParse->pVdbe; if( v ){ sqlite3ChangeCookie(pParse, iDb); sqlite3VdbeAddParseSchemaOp(pParse->pVdbe, iDb, 0, p5); if( iDb!=1 ) sqlite3VdbeAddParseSchemaOp(pParse->pVdbe, 1, 0, p5); } } /* ** Generate code to implement the "ALTER TABLE xxx RENAME TO yyy" ** command. */ |
︙ | ︙ | |||
93 94 95 96 97 98 99 | Table *pTab; /* Table being renamed */ char *zName = 0; /* NULL-terminated version of pName */ sqlite3 *db = pParse->db; /* Database connection */ int nTabName; /* Number of UTF-8 characters in zTabName */ const char *zTabName; /* Original name of the table */ Vdbe *v; VTable *pVTab = 0; /* Non-zero if this is a v-tab with an xRename() */ | < < < | > > > | | | | | 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 | Table *pTab; /* Table being renamed */ char *zName = 0; /* NULL-terminated version of pName */ sqlite3 *db = pParse->db; /* Database connection */ int nTabName; /* Number of UTF-8 characters in zTabName */ const char *zTabName; /* Original name of the table */ Vdbe *v; VTable *pVTab = 0; /* Non-zero if this is a v-tab with an xRename() */ if( NEVER(db->mallocFailed) ) goto exit_rename_table; assert( pSrc->nSrc==1 ); assert( sqlite3BtreeHoldsAllMutexes(pParse->db) ); pTab = sqlite3LocateTableItem(pParse, 0, &pSrc->a[0]); if( !pTab ) goto exit_rename_table; iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); zDb = db->aDb[iDb].zDbSName; /* Get a NULL terminated version of the new table name. */ zName = sqlite3NameFromToken(db, pName); if( !zName ) goto exit_rename_table; /* Check that a table or index named 'zName' does not already exist ** in database iDb. If so, this is an error. */ if( sqlite3FindTable(db, zName, zDb) || sqlite3FindIndex(db, zName, zDb) || sqlite3IsShadowTableOf(db, pTab, zName) ){ sqlite3ErrorMsg(pParse, "there is already another table or index with this name: %s", zName); goto exit_rename_table; } /* Make sure it is not a system table being altered, or a reserved name ** that the table is being renamed to. */ if( SQLITE_OK!=isAlterableTable(pParse, pTab) ){ goto exit_rename_table; } if( SQLITE_OK!=sqlite3CheckObjectName(pParse,zName,"table",zName) ){ goto exit_rename_table; } #ifndef SQLITE_OMIT_VIEW if( IsView(pTab) ){ sqlite3ErrorMsg(pParse, "view %s may not be altered", pTab->zName); goto exit_rename_table; } #endif #ifndef SQLITE_OMIT_AUTHORIZATION /* Invoke the authorization callback. */ |
︙ | ︙ | |||
155 156 157 158 159 160 161 | pVTab = sqlite3GetVTable(db, pTab); if( pVTab->pVtab->pModule->xRename==0 ){ pVTab = 0; } } #endif | | | | | < > | | | | | > | | | | < | | > | > > > > > > > > > > > > > > | 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 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 | pVTab = sqlite3GetVTable(db, pTab); if( pVTab->pVtab->pModule->xRename==0 ){ pVTab = 0; } } #endif /* Begin a transaction for database iDb. Then modify the schema cookie ** (since the ALTER TABLE modifies the schema). Call sqlite3MayAbort(), ** as the scalar functions (e.g. sqlite_rename_table()) invoked by the ** nested SQL may raise an exception. */ v = sqlite3GetVdbe(pParse); if( v==0 ){ goto exit_rename_table; } sqlite3MayAbort(pParse); /* figure out how many UTF-8 characters are in zName */ zTabName = pTab->zName; nTabName = sqlite3Utf8CharLen(zTabName, -1); /* Rewrite all CREATE TABLE, INDEX, TRIGGER or VIEW statements in ** the schema to use the new table name. */ sqlite3NestedParse(pParse, "UPDATE \"%w\"." LEGACY_SCHEMA_TABLE " SET " "sql = sqlite_rename_table(%Q, type, name, sql, %Q, %Q, %d) " "WHERE (type!='index' OR tbl_name=%Q COLLATE nocase)" "AND name NOT LIKE 'sqliteX_%%' ESCAPE 'X'" , zDb, zDb, zTabName, zName, (iDb==1), zTabName ); /* Update the tbl_name and name columns of the sqlite_schema table ** as required. */ sqlite3NestedParse(pParse, "UPDATE %Q." LEGACY_SCHEMA_TABLE " SET " "tbl_name = %Q, " "name = CASE " "WHEN type='table' THEN %Q " "WHEN name LIKE 'sqliteX_autoindex%%' ESCAPE 'X' " " AND type='index' THEN " "'sqlite_autoindex_' || %Q || substr(name,%d+18) " "ELSE name END " "WHERE tbl_name=%Q COLLATE nocase AND " "(type='table' OR type='index' OR type='trigger');", zDb, zName, zName, zName, nTabName, zTabName ); #ifndef SQLITE_OMIT_AUTOINCREMENT /* If the sqlite_sequence table exists in this database, then update ** it with the new table name. */ if( sqlite3FindTable(db, "sqlite_sequence", zDb) ){ sqlite3NestedParse(pParse, "UPDATE \"%w\".sqlite_sequence set name = %Q WHERE name = %Q", zDb, zName, pTab->zName); } #endif /* If the table being renamed is not itself part of the temp database, ** edit view and trigger definitions within the temp database ** as required. */ if( iDb!=1 ){ sqlite3NestedParse(pParse, "UPDATE sqlite_temp_schema SET " "sql = sqlite_rename_table(%Q, type, name, sql, %Q, %Q, 1), " "tbl_name = " "CASE WHEN tbl_name=%Q COLLATE nocase AND " " sqlite_rename_test(%Q, sql, type, name, 1, 'after rename', 0) " "THEN %Q ELSE tbl_name END " "WHERE type IN ('view', 'trigger')" , zDb, zTabName, zName, zTabName, zDb, zName); } /* If this is a virtual table, invoke the xRename() function if ** one is defined. The xRename() callback will modify the names ** of any resources used by the v-table implementation (including other ** SQLite tables) that are identified by the name of the virtual table. */ #ifndef SQLITE_OMIT_VIRTUALTABLE if( pVTab ){ int i = ++pParse->nMem; sqlite3VdbeLoadString(v, i, zName); sqlite3VdbeAddOp4(v, OP_VRename, i, 0, 0,(const char*)pVTab, P4_VTAB); } #endif renameReloadSchema(pParse, iDb, INITFLAG_AlterRename); renameTestSchema(pParse, zDb, iDb==1, "after rename", 0); exit_rename_table: sqlite3SrcListDelete(db, pSrc); sqlite3DbFree(db, zName); } /* ** Write code that will raise an error if the table described by ** zDb and zTab is not empty. */ static void sqlite3ErrorIfNotEmpty( Parse *pParse, /* Parsing context */ const char *zDb, /* Schema holding the table */ const char *zTab, /* Table to check for empty */ const char *zErr /* Error message text */ ){ sqlite3NestedParse(pParse, "SELECT raise(ABORT,%Q) FROM \"%w\".\"%w\"", zErr, zDb, zTab ); } /* ** This function is called after an "ALTER TABLE ... ADD" statement ** has been parsed. Argument pColDef contains the text of the new ** column definition. ** |
︙ | ︙ | |||
276 277 278 279 280 281 282 | assert( pNew ); assert( sqlite3BtreeHoldsAllMutexes(db) ); iDb = sqlite3SchemaToIndex(db, pNew->pSchema); zDb = db->aDb[iDb].zDbSName; zTab = &pNew->zName[16]; /* Skip the "sqlite_altertab_" prefix on the name */ pCol = &pNew->aCol[pNew->nCol-1]; | | < < < < < < < < | > > > > > > > > > > > | | | < | | | | < | > | | | | | | | | | | | | | > | < | | | > > > > < | > > > | > | | < > > | | | | < < | < | | > > > > > > > > > > > > > > > > | 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 | assert( pNew ); assert( sqlite3BtreeHoldsAllMutexes(db) ); iDb = sqlite3SchemaToIndex(db, pNew->pSchema); zDb = db->aDb[iDb].zDbSName; zTab = &pNew->zName[16]; /* Skip the "sqlite_altertab_" prefix on the name */ pCol = &pNew->aCol[pNew->nCol-1]; pDflt = sqlite3ColumnExpr(pNew, pCol); pTab = sqlite3FindTable(db, zTab, zDb); assert( pTab ); #ifndef SQLITE_OMIT_AUTHORIZATION /* Invoke the authorization callback. */ if( sqlite3AuthCheck(pParse, SQLITE_ALTER_TABLE, zDb, pTab->zName, 0) ){ return; } #endif /* Check that the new column is not specified as PRIMARY KEY or UNIQUE. ** If there is a NOT NULL constraint, then the default value for the ** column must not be NULL. */ if( pCol->colFlags & COLFLAG_PRIMKEY ){ sqlite3ErrorMsg(pParse, "Cannot add a PRIMARY KEY column"); return; } if( pNew->pIndex ){ sqlite3ErrorMsg(pParse, "Cannot add a UNIQUE column"); return; } if( (pCol->colFlags & COLFLAG_GENERATED)==0 ){ /* If the default value for the new column was specified with a ** literal NULL, then set pDflt to 0. This simplifies checking ** for an SQL NULL default below. */ assert( pDflt==0 || pDflt->op==TK_SPAN ); if( pDflt && pDflt->pLeft->op==TK_NULL ){ pDflt = 0; } assert( IsOrdinaryTable(pNew) ); if( (db->flags&SQLITE_ForeignKeys) && pNew->u.tab.pFKey && pDflt ){ sqlite3ErrorIfNotEmpty(pParse, zDb, zTab, "Cannot add a REFERENCES column with non-NULL default value"); } if( pCol->notNull && !pDflt ){ sqlite3ErrorIfNotEmpty(pParse, zDb, zTab, "Cannot add a NOT NULL column with default value NULL"); } /* Ensure the default expression is something that sqlite3ValueFromExpr() ** can handle (i.e. not CURRENT_TIME etc.) */ if( pDflt ){ sqlite3_value *pVal = 0; int rc; rc = sqlite3ValueFromExpr(db, pDflt, SQLITE_UTF8, SQLITE_AFF_BLOB, &pVal); assert( rc==SQLITE_OK || rc==SQLITE_NOMEM ); if( rc!=SQLITE_OK ){ assert( db->mallocFailed == 1 ); return; } if( !pVal ){ sqlite3ErrorIfNotEmpty(pParse, zDb, zTab, "Cannot add a column with non-constant default"); } sqlite3ValueFree(pVal); } }else if( pCol->colFlags & COLFLAG_STORED ){ sqlite3ErrorIfNotEmpty(pParse, zDb, zTab, "cannot add a STORED column"); } /* Modify the CREATE TABLE statement. */ zCol = sqlite3DbStrNDup(db, (char*)pColDef->z, pColDef->n); if( zCol ){ char *zEnd = &zCol[pColDef->n-1]; while( zEnd>zCol && (*zEnd==';' || sqlite3Isspace(*zEnd)) ){ *zEnd-- = '\0'; } /* substr() operations on characters, but addColOffset is in bytes. So we ** have to use printf() to translate between these units: */ assert( IsOrdinaryTable(pTab) ); assert( IsOrdinaryTable(pNew) ); sqlite3NestedParse(pParse, "UPDATE \"%w\"." LEGACY_SCHEMA_TABLE " SET " "sql = printf('%%.%ds, ',sql) || %Q" " || substr(sql,1+length(printf('%%.%ds',sql))) " "WHERE type = 'table' AND name = %Q", zDb, pNew->u.tab.addColOffset, zCol, pNew->u.tab.addColOffset, zTab ); sqlite3DbFree(db, zCol); } v = sqlite3GetVdbe(pParse); if( v ){ /* Make sure the schema version is at least 3. But do not upgrade ** from less than 3 to 4, as that will corrupt any preexisting DESC ** index. */ r1 = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp3(v, OP_ReadCookie, iDb, r1, BTREE_FILE_FORMAT); sqlite3VdbeUsesBtree(v, iDb); sqlite3VdbeAddOp2(v, OP_AddImm, r1, -2); sqlite3VdbeAddOp2(v, OP_IfPos, r1, sqlite3VdbeCurrentAddr(v)+2); VdbeCoverage(v); sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_FILE_FORMAT, 3); sqlite3ReleaseTempReg(pParse, r1); /* Reload the table definition */ renameReloadSchema(pParse, iDb, INITFLAG_AlterAdd); /* Verify that constraints are still satisfied */ if( pNew->pCheck!=0 || (pCol->notNull && (pCol->colFlags & COLFLAG_GENERATED)!=0) ){ sqlite3NestedParse(pParse, "SELECT CASE WHEN quick_check GLOB 'CHECK*'" " THEN raise(ABORT,'CHECK constraint failed')" " ELSE raise(ABORT,'NOT NULL constraint failed')" " END" " FROM pragma_quick_check(\"%w\",\"%w\")" " WHERE quick_check GLOB 'CHECK*' OR quick_check GLOB 'NULL*'", zTab, zDb ); } } } /* ** This function is called by the parser after the table-name in ** an "ALTER TABLE <table-name> ADD" statement is parsed. Argument ** pSrc is the full-name of the table being altered. ** |
︙ | ︙ | |||
416 417 418 419 420 421 422 | if( IsVirtual(pTab) ){ sqlite3ErrorMsg(pParse, "virtual tables may not be altered"); goto exit_begin_add_column; } #endif /* Make sure this is not an attempt to ALTER a view. */ | | | > > | | 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 | if( IsVirtual(pTab) ){ sqlite3ErrorMsg(pParse, "virtual tables may not be altered"); goto exit_begin_add_column; } #endif /* Make sure this is not an attempt to ALTER a view. */ if( IsView(pTab) ){ sqlite3ErrorMsg(pParse, "Cannot add a column to a view"); goto exit_begin_add_column; } if( SQLITE_OK!=isAlterableTable(pParse, pTab) ){ goto exit_begin_add_column; } sqlite3MayAbort(pParse); assert( IsOrdinaryTable(pTab) ); assert( pTab->u.tab.addColOffset>0 ); iDb = sqlite3SchemaToIndex(db, pTab->pSchema); /* Put a copy of the Table struct in Parse.pNewTable for the ** sqlite3AddColumn() function and friends to modify. But modify ** the name by adding an "sqlite_altertab_" prefix. By adding this ** prefix, we insure that the name will not collide with an existing ** table because user table are not allowed to have the "sqlite_" |
︙ | ︙ | |||
451 452 453 454 455 456 457 | if( !pNew->aCol || !pNew->zName ){ assert( db->mallocFailed ); goto exit_begin_add_column; } memcpy(pNew->aCol, pTab->aCol, sizeof(Column)*pNew->nCol); for(i=0; i<pNew->nCol; i++){ Column *pCol = &pNew->aCol[i]; | | | < > > | | | | > | | | 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 | if( !pNew->aCol || !pNew->zName ){ assert( db->mallocFailed ); goto exit_begin_add_column; } memcpy(pNew->aCol, pTab->aCol, sizeof(Column)*pNew->nCol); for(i=0; i<pNew->nCol; i++){ Column *pCol = &pNew->aCol[i]; pCol->zCnName = sqlite3DbStrDup(db, pCol->zCnName); pCol->hName = sqlite3StrIHash(pCol->zCnName); } assert( IsOrdinaryTable(pNew) ); pNew->u.tab.pDfltList = sqlite3ExprListDup(db, pTab->u.tab.pDfltList, 0); pNew->pSchema = db->aDb[iDb].pSchema; pNew->u.tab.addColOffset = pTab->u.tab.addColOffset; pNew->nTabRef = 1; exit_begin_add_column: sqlite3SrcListDelete(db, pSrc); return; } /* ** Parameter pTab is the subject of an ALTER TABLE ... RENAME COLUMN ** command. This function checks if the table is a view or virtual ** table (columns of views or virtual tables may not be renamed). If so, ** it loads an error message into pParse and returns non-zero. ** ** Or, if pTab is not a view or virtual table, zero is returned. */ #if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE) static int isRealTable(Parse *pParse, Table *pTab, int bDrop){ const char *zType = 0; #ifndef SQLITE_OMIT_VIEW if( IsView(pTab) ){ zType = "view"; } #endif #ifndef SQLITE_OMIT_VIRTUALTABLE if( IsVirtual(pTab) ){ zType = "virtual table"; } #endif if( zType ){ sqlite3ErrorMsg(pParse, "cannot %s %s \"%s\"", (bDrop ? "drop column from" : "rename columns of"), zType, pTab->zName ); return 1; } return 0; } #else /* !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE) */ # define isRealTable(x,y,z) (0) #endif /* ** Handles the following parser reduction: ** ** cmd ::= ALTER TABLE pSrc RENAME COLUMN pOld TO pNew */ |
︙ | ︙ | |||
522 523 524 525 526 527 528 | int bQuote; /* True to quote the new name */ /* Locate the table to be altered */ pTab = sqlite3LocateTableItem(pParse, 0, &pSrc->a[0]); if( !pTab ) goto exit_rename_column; /* Cannot alter a system table */ | | | | > > > > | > | | | | | < | | | 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 | int bQuote; /* True to quote the new name */ /* Locate the table to be altered */ pTab = sqlite3LocateTableItem(pParse, 0, &pSrc->a[0]); if( !pTab ) goto exit_rename_column; /* Cannot alter a system table */ if( SQLITE_OK!=isAlterableTable(pParse, pTab) ) goto exit_rename_column; if( SQLITE_OK!=isRealTable(pParse, pTab, 0) ) goto exit_rename_column; /* Which schema holds the table to be altered */ iSchema = sqlite3SchemaToIndex(db, pTab->pSchema); assert( iSchema>=0 ); zDb = db->aDb[iSchema].zDbSName; #ifndef SQLITE_OMIT_AUTHORIZATION /* Invoke the authorization callback. */ if( sqlite3AuthCheck(pParse, SQLITE_ALTER_TABLE, zDb, pTab->zName, 0) ){ goto exit_rename_column; } #endif /* Make sure the old name really is a column name in the table to be ** altered. Set iCol to be the index of the column being renamed */ zOld = sqlite3NameFromToken(db, pOld); if( !zOld ) goto exit_rename_column; for(iCol=0; iCol<pTab->nCol; iCol++){ if( 0==sqlite3StrICmp(pTab->aCol[iCol].zCnName, zOld) ) break; } if( iCol==pTab->nCol ){ sqlite3ErrorMsg(pParse, "no such column: \"%s\"", zOld); goto exit_rename_column; } /* Ensure the schema contains no double-quoted strings */ renameTestSchema(pParse, zDb, iSchema==1, "", 0); renameFixQuotes(pParse, zDb, iSchema==1); /* Do the rename operation using a recursive UPDATE statement that ** uses the sqlite_rename_column() SQL function to compute the new ** CREATE statement text for the sqlite_schema table. */ sqlite3MayAbort(pParse); zNew = sqlite3NameFromToken(db, pNew); if( !zNew ) goto exit_rename_column; assert( pNew->n>0 ); bQuote = sqlite3Isquote(pNew->z[0]); sqlite3NestedParse(pParse, "UPDATE \"%w\"." LEGACY_SCHEMA_TABLE " SET " "sql = sqlite_rename_column(sql, type, name, %Q, %Q, %d, %Q, %d, %d) " "WHERE name NOT LIKE 'sqliteX_%%' ESCAPE 'X' " " AND (type != 'index' OR tbl_name = %Q)", zDb, zDb, pTab->zName, iCol, zNew, bQuote, iSchema==1, pTab->zName ); sqlite3NestedParse(pParse, "UPDATE temp." LEGACY_SCHEMA_TABLE " SET " "sql = sqlite_rename_column(sql, type, name, %Q, %Q, %d, %Q, %d, 1) " "WHERE type IN ('trigger', 'view')", zDb, pTab->zName, iCol, zNew, bQuote ); /* Drop and reload the database schema. */ renameReloadSchema(pParse, iSchema, INITFLAG_AlterRename); renameTestSchema(pParse, zDb, iSchema==1, "after rename", 1); exit_rename_column: sqlite3SrcListDelete(db, pSrc); sqlite3DbFree(db, zOld); sqlite3DbFree(db, zNew); return; } |
︙ | ︙ | |||
604 605 606 607 608 609 610 | ** routine is used to keep the mapping current. ** ** After the parse finishes, renameTokenFind() routine can be used ** to look up the actual token value that created some element in ** the parse tree. */ struct RenameToken { | | | 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 | ** routine is used to keep the mapping current. ** ** After the parse finishes, renameTokenFind() routine can be used ** to look up the actual token value that created some element in ** the parse tree. */ struct RenameToken { const void *p; /* Parse tree element created by token t */ Token t; /* The token that created parse tree element p */ RenameToken *pNext; /* Next is a list of all RenameToken objects */ }; /* ** The context of an ALTER TABLE RENAME COLUMN operation that gets passed ** down into the Walker. |
︙ | ︙ | |||
646 647 648 649 650 651 652 | ** ** sqlite3_free(x); ** if( x==y ) ... ** ** Technically, as x no longer points into a valid object or to the byte ** following a valid object, it may not be used in comparison operations. */ | | | | 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 | ** ** sqlite3_free(x); ** if( x==y ) ... ** ** Technically, as x no longer points into a valid object or to the byte ** following a valid object, it may not be used in comparison operations. */ static void renameTokenCheckAll(Parse *pParse, const void *pPtr){ if( pParse->nErr==0 && pParse->db->mallocFailed==0 ){ const RenameToken *p; u8 i = 0; for(p=pParse->pRename; p; p=p->pNext){ if( p->p ){ assert( p->p!=pPtr ); i += *(u8*)(p->p); } } |
︙ | ︙ | |||
674 675 676 677 678 679 680 | ** to the list of RenameToken objects currently being built up ** in pParse->pRename. ** ** The pPtr argument is returned so that this routine can be used ** with tail recursion in tokenExpr() routine, for a small performance ** improvement. */ | | > > > > > | | | | | | > | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > | > > > | | > > | > > | > > > | | | | < | < < | < < < < < < < < < < < < < < > > > > > > | 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 | ** to the list of RenameToken objects currently being built up ** in pParse->pRename. ** ** The pPtr argument is returned so that this routine can be used ** with tail recursion in tokenExpr() routine, for a small performance ** improvement. */ const void *sqlite3RenameTokenMap( Parse *pParse, const void *pPtr, const Token *pToken ){ RenameToken *pNew; assert( pPtr || pParse->db->mallocFailed ); renameTokenCheckAll(pParse, pPtr); if( ALWAYS(pParse->eParseMode!=PARSE_MODE_UNMAP) ){ pNew = sqlite3DbMallocZero(pParse->db, sizeof(RenameToken)); if( pNew ){ pNew->p = pPtr; pNew->t = *pToken; pNew->pNext = pParse->pRename; pParse->pRename = pNew; } } return pPtr; } /* ** It is assumed that there is already a RenameToken object associated ** with parse tree element pFrom. This function remaps the associated token ** to parse tree element pTo. */ void sqlite3RenameTokenRemap(Parse *pParse, const void *pTo, const void *pFrom){ RenameToken *p; renameTokenCheckAll(pParse, pTo); for(p=pParse->pRename; p; p=p->pNext){ if( p->p==pFrom ){ p->p = pTo; break; } } } /* ** Walker callback used by sqlite3RenameExprUnmap(). */ static int renameUnmapExprCb(Walker *pWalker, Expr *pExpr){ Parse *pParse = pWalker->pParse; sqlite3RenameTokenRemap(pParse, 0, (const void*)pExpr); if( ExprUseYTab(pExpr) ){ sqlite3RenameTokenRemap(pParse, 0, (const void*)&pExpr->y.pTab); } return WRC_Continue; } /* ** Iterate through the Select objects that are part of WITH clauses attached ** to select statement pSelect. */ static void renameWalkWith(Walker *pWalker, Select *pSelect){ With *pWith = pSelect->pWith; if( pWith ){ Parse *pParse = pWalker->pParse; int i; With *pCopy = 0; assert( pWith->nCte>0 ); if( (pWith->a[0].pSelect->selFlags & SF_Expanded)==0 ){ /* Push a copy of the With object onto the with-stack. We use a copy ** here as the original will be expanded and resolved (flags SF_Expanded ** and SF_Resolved) below. And the parser code that uses the with-stack ** fails if the Select objects on it have already been expanded and ** resolved. */ pCopy = sqlite3WithDup(pParse->db, pWith); pCopy = sqlite3WithPush(pParse, pCopy, 1); } for(i=0; i<pWith->nCte; i++){ Select *p = pWith->a[i].pSelect; NameContext sNC; memset(&sNC, 0, sizeof(sNC)); sNC.pParse = pParse; if( pCopy ) sqlite3SelectPrep(sNC.pParse, p, &sNC); if( sNC.pParse->db->mallocFailed ) return; sqlite3WalkSelect(pWalker, p); sqlite3RenameExprlistUnmap(pParse, pWith->a[i].pCols); } if( pCopy && pParse->pWith==pCopy ){ pParse->pWith = pCopy->pOuter; } } } /* ** Unmap all tokens in the IdList object passed as the second argument. */ static void unmapColumnIdlistNames( Parse *pParse, const IdList *pIdList ){ if( pIdList ){ int ii; for(ii=0; ii<pIdList->nId; ii++){ sqlite3RenameTokenRemap(pParse, 0, (const void*)pIdList->a[ii].zName); } } } /* ** Walker callback used by sqlite3RenameExprUnmap(). */ static int renameUnmapSelectCb(Walker *pWalker, Select *p){ Parse *pParse = pWalker->pParse; int i; if( pParse->nErr ) return WRC_Abort; testcase( p->selFlags & SF_View ); testcase( p->selFlags & SF_CopyCte ); if( p->selFlags & (SF_View|SF_CopyCte) ){ return WRC_Prune; } if( ALWAYS(p->pEList) ){ ExprList *pList = p->pEList; for(i=0; i<pList->nExpr; i++){ if( pList->a[i].zEName && pList->a[i].eEName==ENAME_NAME ){ sqlite3RenameTokenRemap(pParse, 0, (void*)pList->a[i].zEName); } } } if( ALWAYS(p->pSrc) ){ /* Every Select as a SrcList, even if it is empty */ SrcList *pSrc = p->pSrc; for(i=0; i<pSrc->nSrc; i++){ sqlite3RenameTokenRemap(pParse, 0, (void*)pSrc->a[i].zName); sqlite3WalkExpr(pWalker, pSrc->a[i].pOn); unmapColumnIdlistNames(pParse, pSrc->a[i].pUsing); } } renameWalkWith(pWalker, p); return WRC_Continue; } /* ** Remove all nodes that are part of expression pExpr from the rename list. */ void sqlite3RenameExprUnmap(Parse *pParse, Expr *pExpr){ u8 eMode = pParse->eParseMode; Walker sWalker; memset(&sWalker, 0, sizeof(Walker)); sWalker.pParse = pParse; sWalker.xExprCallback = renameUnmapExprCb; sWalker.xSelectCallback = renameUnmapSelectCb; pParse->eParseMode = PARSE_MODE_UNMAP; sqlite3WalkExpr(&sWalker, pExpr); pParse->eParseMode = eMode; } /* ** Remove all nodes that are part of expression-list pEList from the ** rename list. */ void sqlite3RenameExprlistUnmap(Parse *pParse, ExprList *pEList){ if( pEList ){ int i; Walker sWalker; memset(&sWalker, 0, sizeof(Walker)); sWalker.pParse = pParse; sWalker.xExprCallback = renameUnmapExprCb; sqlite3WalkExprList(&sWalker, pEList); for(i=0; i<pEList->nExpr; i++){ if( ALWAYS(pEList->a[i].eEName==ENAME_NAME) ){ sqlite3RenameTokenRemap(pParse, 0, (void*)pEList->a[i].zEName); } } } } /* ** Free the list of RenameToken objects given in the second argument */ static void renameTokenFree(sqlite3 *db, RenameToken *pToken){ RenameToken *pNext; RenameToken *p; for(p=pToken; p; p=pNext){ pNext = p->pNext; sqlite3DbFree(db, p); } } /* ** Search the Parse object passed as the first argument for a RenameToken ** object associated with parse tree element pPtr. If found, return a pointer ** to it. Otherwise, return NULL. ** ** If the second argument passed to this function is not NULL and a matching ** RenameToken object is found, remove it from the Parse object and add it to ** the list maintained by the RenameCtx object. */ static RenameToken *renameTokenFind( Parse *pParse, struct RenameCtx *pCtx, const void *pPtr ){ RenameToken **pp; if( NEVER(pPtr==0) ){ return 0; } for(pp=&pParse->pRename; (*pp); pp=&(*pp)->pNext){ if( (*pp)->p==pPtr ){ RenameToken *pToken = *pp; if( pCtx ){ *pp = pToken->pNext; pToken->pNext = pCtx->pList; pCtx->pList = pToken; pCtx->nList++; } return pToken; } } return 0; } /* ** This is a Walker select callback. It does nothing. It is only required ** because without a dummy callback, sqlite3WalkExpr() and similar do not ** descend into sub-select statements. */ static int renameColumnSelectCb(Walker *pWalker, Select *p){ if( p->selFlags & (SF_View|SF_CopyCte) ){ testcase( p->selFlags & SF_View ); testcase( p->selFlags & SF_CopyCte ); return WRC_Prune; } renameWalkWith(pWalker, p); return WRC_Continue; } /* ** This is a Walker expression callback. ** |
︙ | ︙ | |||
821 822 823 824 825 826 827 | RenameCtx *p = pWalker->u.pRename; if( pExpr->op==TK_TRIGGER && pExpr->iColumn==p->iCol && pWalker->pParse->pTriggerTab==p->pTab ){ renameTokenFind(pWalker->pParse, p, (void*)pExpr); }else if( pExpr->op==TK_COLUMN | | > | 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 | RenameCtx *p = pWalker->u.pRename; if( pExpr->op==TK_TRIGGER && pExpr->iColumn==p->iCol && pWalker->pParse->pTriggerTab==p->pTab ){ renameTokenFind(pWalker->pParse, p, (void*)pExpr); }else if( pExpr->op==TK_COLUMN && pExpr->iColumn==p->iCol && ALWAYS(ExprUseYTab(pExpr)) && p->pTab==pExpr->y.pTab ){ renameTokenFind(pWalker->pParse, p, (void*)pExpr); } return WRC_Continue; } |
︙ | ︙ | |||
861 862 863 864 865 866 867 | ** object (either pParse->pNewTable, pNewIndex or pNewTrigger) as part of an ** ALTER TABLE RENAME COLUMN program. The error message emitted by the ** sub-routine is currently stored in pParse->zErrMsg. This function ** adds context to the error message and then stores it in pCtx. */ static void renameColumnParseError( sqlite3_context *pCtx, | | | | | | > > | > | | | | > < | | < | 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 | ** object (either pParse->pNewTable, pNewIndex or pNewTrigger) as part of an ** ALTER TABLE RENAME COLUMN program. The error message emitted by the ** sub-routine is currently stored in pParse->zErrMsg. This function ** adds context to the error message and then stores it in pCtx. */ static void renameColumnParseError( sqlite3_context *pCtx, const char *zWhen, sqlite3_value *pType, sqlite3_value *pObject, Parse *pParse ){ const char *zT = (const char*)sqlite3_value_text(pType); const char *zN = (const char*)sqlite3_value_text(pObject); char *zErr; zErr = sqlite3_mprintf("error in %s %s%s%s: %s", zT, zN, (zWhen[0] ? " " : ""), zWhen, pParse->zErrMsg ); sqlite3_result_error(pCtx, zErr, -1); sqlite3_free(zErr); } /* ** For each name in the the expression-list pEList (i.e. each ** pEList->a[i].zName) that matches the string in zOld, extract the ** corresponding rename-token from Parse object pParse and add it ** to the RenameCtx pCtx. */ static void renameColumnElistNames( Parse *pParse, RenameCtx *pCtx, const ExprList *pEList, const char *zOld ){ if( pEList ){ int i; for(i=0; i<pEList->nExpr; i++){ const char *zName = pEList->a[i].zEName; if( ALWAYS(pEList->a[i].eEName==ENAME_NAME) && ALWAYS(zName!=0) && 0==sqlite3_stricmp(zName, zOld) ){ renameTokenFind(pParse, pCtx, (const void*)zName); } } } } /* ** For each name in the the id-list pIdList (i.e. each pIdList->a[i].zName) ** that matches the string in zOld, extract the corresponding rename-token ** from Parse object pParse and add it to the RenameCtx pCtx. */ static void renameColumnIdlistNames( Parse *pParse, RenameCtx *pCtx, const IdList *pIdList, const char *zOld ){ if( pIdList ){ int i; for(i=0; i<pIdList->nId; i++){ const char *zName = pIdList->a[i].zName; if( 0==sqlite3_stricmp(zName, zOld) ){ renameTokenFind(pParse, pCtx, (const void*)zName); } } } } /* ** Parse the SQL statement zSql using Parse object (*p). The Parse object ** is initialized by this function before it is used. */ static int renameParseSql( Parse *p, /* Memory to use for Parse object */ const char *zDb, /* Name of schema SQL belongs to */ sqlite3 *db, /* Database handle */ const char *zSql, /* SQL to parse */ int bTemp /* True if SQL is from temp schema */ ){ int rc; char *zErr = 0; db->init.iDb = bTemp ? 1 : sqlite3FindDbName(db, zDb); /* Parse the SQL statement passed as the first argument. If no error ** occurs and the parse does not result in a new table, index or ** trigger object, the database must be corrupt. */ memset(p, 0, sizeof(Parse)); p->eParseMode = PARSE_MODE_RENAME; p->db = db; p->nQueryLoop = 1; rc = zSql ? sqlite3RunParser(p, zSql, &zErr) : SQLITE_NOMEM; assert( p->zErrMsg==0 ); assert( rc!=SQLITE_OK || zErr==0 ); p->zErrMsg = zErr; if( db->mallocFailed ) rc = SQLITE_NOMEM; if( rc==SQLITE_OK && p->pNewTable==0 && p->pNewIndex==0 && p->pNewTrigger==0 ){ rc = SQLITE_CORRUPT_BKPT; } |
︙ | ︙ | |||
991 992 993 994 995 996 997 | static int renameEditSql( sqlite3_context *pCtx, /* Return result here */ RenameCtx *pRename, /* Rename context */ const char *zSql, /* SQL statement to edit */ const char *zNew, /* New token text */ int bQuote /* True to always quote token */ ){ | | | | | > > > | | | | | | | | | | | | | > > > > | > > | | < < < < > > > | | | | | | > > > > > > > > > > > > > > > > > | 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 | static int renameEditSql( sqlite3_context *pCtx, /* Return result here */ RenameCtx *pRename, /* Rename context */ const char *zSql, /* SQL statement to edit */ const char *zNew, /* New token text */ int bQuote /* True to always quote token */ ){ i64 nNew = sqlite3Strlen30(zNew); i64 nSql = sqlite3Strlen30(zSql); sqlite3 *db = sqlite3_context_db_handle(pCtx); int rc = SQLITE_OK; char *zQuot = 0; char *zOut; i64 nQuot = 0; char *zBuf1 = 0; char *zBuf2 = 0; if( zNew ){ /* Set zQuot to point to a buffer containing a quoted copy of the ** identifier zNew. If the corresponding identifier in the original ** ALTER TABLE statement was quoted (bQuote==1), then set zNew to ** point to zQuot so that all substitutions are made using the ** quoted version of the new column name. */ zQuot = sqlite3MPrintf(db, "\"%w\" ", zNew); if( zQuot==0 ){ return SQLITE_NOMEM; }else{ nQuot = sqlite3Strlen30(zQuot)-1; } assert( nQuot>=nNew ); zOut = sqlite3DbMallocZero(db, nSql + pRename->nList*nQuot + 1); }else{ zOut = (char*)sqlite3DbMallocZero(db, (nSql*2+1) * 3); if( zOut ){ zBuf1 = &zOut[nSql*2+1]; zBuf2 = &zOut[nSql*4+2]; } } /* At this point pRename->pList contains a list of RenameToken objects ** corresponding to all tokens in the input SQL that must be replaced ** with the new column name, or with single-quoted versions of themselves. ** All that remains is to construct and return the edited SQL string. */ if( zOut ){ int nOut = nSql; memcpy(zOut, zSql, nSql); while( pRename->pList ){ int iOff; /* Offset of token to replace in zOut */ u32 nReplace; const char *zReplace; RenameToken *pBest = renameColumnTokenNext(pRename); if( zNew ){ if( bQuote==0 && sqlite3IsIdChar(*pBest->t.z) ){ nReplace = nNew; zReplace = zNew; }else{ nReplace = nQuot; zReplace = zQuot; if( pBest->t.z[pBest->t.n]=='"' ) nReplace++; } }else{ /* Dequote the double-quoted token. Then requote it again, this time ** using single quotes. If the character immediately following the ** original token within the input SQL was a single quote ('), then ** add another space after the new, single-quoted version of the ** token. This is so that (SELECT "string"'alias') maps to ** (SELECT 'string' 'alias'), and not (SELECT 'string''alias'). */ memcpy(zBuf1, pBest->t.z, pBest->t.n); zBuf1[pBest->t.n] = 0; sqlite3Dequote(zBuf1); sqlite3_snprintf(nSql*2, zBuf2, "%Q%s", zBuf1, pBest->t.z[pBest->t.n]=='\'' ? " " : "" ); zReplace = zBuf2; nReplace = sqlite3Strlen30(zReplace); } iOff = pBest->t.z - zSql; if( pBest->t.n!=nReplace ){ memmove(&zOut[iOff + nReplace], &zOut[iOff + pBest->t.n], nOut - (iOff + pBest->t.n) ); |
︙ | ︙ | |||
1066 1067 1068 1069 1070 1071 1072 | /* ** Resolve all symbols in the trigger at pParse->pNewTrigger, assuming ** it was read from the schema of database zDb. Return SQLITE_OK if ** successful. Otherwise, return an SQLite error code and leave an error ** message in the Parse object. */ | | | 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 | /* ** Resolve all symbols in the trigger at pParse->pNewTrigger, assuming ** it was read from the schema of database zDb. Return SQLITE_OK if ** successful. Otherwise, return an SQLite error code and leave an error ** message in the Parse object. */ static int renameResolveTrigger(Parse *pParse){ sqlite3 *db = pParse->db; Trigger *pNew = pParse->pNewTrigger; TriggerStep *pStep; NameContext sNC; int rc = SQLITE_OK; memset(&sNC, 0, sizeof(sNC)); |
︙ | ︙ | |||
1097 1098 1099 1100 1101 1102 1103 | for(pStep=pNew->step_list; rc==SQLITE_OK && pStep; pStep=pStep->pNext){ if( pStep->pSelect ){ sqlite3SelectPrep(pParse, pStep->pSelect, &sNC); if( pParse->nErr ) rc = pParse->rc; } if( rc==SQLITE_OK && pStep->zTarget ){ | > > > > > > > > > > > > > | | | > > | < < > > > > | < < > | | | < | > > > > | 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 | for(pStep=pNew->step_list; rc==SQLITE_OK && pStep; pStep=pStep->pNext){ if( pStep->pSelect ){ sqlite3SelectPrep(pParse, pStep->pSelect, &sNC); if( pParse->nErr ) rc = pParse->rc; } if( rc==SQLITE_OK && pStep->zTarget ){ SrcList *pSrc = sqlite3TriggerStepSrc(pParse, pStep); if( pSrc ){ int i; for(i=0; i<pSrc->nSrc && rc==SQLITE_OK; i++){ SrcItem *p = &pSrc->a[i]; p->iCursor = pParse->nTab++; if( p->pSelect ){ sqlite3SelectPrep(pParse, p->pSelect, 0); sqlite3ExpandSubquery(pParse, p); assert( i>0 ); assert( pStep->pFrom->a[i-1].pSelect ); sqlite3SelectPrep(pParse, pStep->pFrom->a[i-1].pSelect, 0); }else{ p->pTab = sqlite3LocateTableItem(pParse, 0, p); if( p->pTab==0 ){ rc = SQLITE_ERROR; }else{ p->pTab->nTabRef++; rc = sqlite3ViewGetColumnNames(pParse, p->pTab); } } } if( rc==SQLITE_OK && db->mallocFailed ){ rc = SQLITE_NOMEM; } sNC.pSrcList = pSrc; if( rc==SQLITE_OK && pStep->pWhere ){ rc = sqlite3ResolveExprNames(&sNC, pStep->pWhere); } if( rc==SQLITE_OK ){ rc = sqlite3ResolveExprListNames(&sNC, pStep->pExprList); } assert( !pStep->pUpsert || (!pStep->pWhere && !pStep->pExprList) ); if( pStep->pUpsert && rc==SQLITE_OK ){ Upsert *pUpsert = pStep->pUpsert; pUpsert->pUpsertSrc = pSrc; sNC.uNC.pUpsert = pUpsert; sNC.ncFlags = NC_UUpsert; rc = sqlite3ResolveExprListNames(&sNC, pUpsert->pUpsertTarget); if( rc==SQLITE_OK ){ ExprList *pUpsertSet = pUpsert->pUpsertSet; rc = sqlite3ResolveExprListNames(&sNC, pUpsertSet); } if( rc==SQLITE_OK ){ rc = sqlite3ResolveExprNames(&sNC, pUpsert->pUpsertWhere); } if( rc==SQLITE_OK ){ rc = sqlite3ResolveExprNames(&sNC, pUpsert->pUpsertTargetWhere); } sNC.ncFlags = 0; } sNC.pSrcList = 0; sqlite3SrcListDelete(db, pSrc); }else{ rc = SQLITE_NOMEM; } } } return rc; } /* |
︙ | ︙ | |||
1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 | if( pStep->pUpsert ){ Upsert *pUpsert = pStep->pUpsert; sqlite3WalkExprList(pWalker, pUpsert->pUpsertTarget); sqlite3WalkExprList(pWalker, pUpsert->pUpsertSet); sqlite3WalkExpr(pWalker, pUpsert->pUpsertWhere); sqlite3WalkExpr(pWalker, pUpsert->pUpsertTargetWhere); } } } /* ** Free the contents of Parse object (*pParse). Do not free the memory ** occupied by the Parse object itself. */ static void renameParseCleanup(Parse *pParse){ sqlite3 *db = pParse->db; if( pParse->pVdbe ){ sqlite3VdbeFinalize(pParse->pVdbe); } sqlite3DeleteTable(db, pParse->pNewTable); | > > > > > > > > > | > | 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 | if( pStep->pUpsert ){ Upsert *pUpsert = pStep->pUpsert; sqlite3WalkExprList(pWalker, pUpsert->pUpsertTarget); sqlite3WalkExprList(pWalker, pUpsert->pUpsertSet); sqlite3WalkExpr(pWalker, pUpsert->pUpsertWhere); sqlite3WalkExpr(pWalker, pUpsert->pUpsertTargetWhere); } if( pStep->pFrom ){ int i; for(i=0; i<pStep->pFrom->nSrc; i++){ sqlite3WalkSelect(pWalker, pStep->pFrom->a[i].pSelect); } } } } /* ** Free the contents of Parse object (*pParse). Do not free the memory ** occupied by the Parse object itself. */ static void renameParseCleanup(Parse *pParse){ sqlite3 *db = pParse->db; Index *pIdx; if( pParse->pVdbe ){ sqlite3VdbeFinalize(pParse->pVdbe); } sqlite3DeleteTable(db, pParse->pNewTable); while( (pIdx = pParse->pNewIndex)!=0 ){ pParse->pNewIndex = pIdx->pNext; sqlite3FreeIndex(db, pIdx); } sqlite3DeleteTrigger(db, pParse->pNewTrigger); sqlite3DbFree(db, pParse->zErrMsg); renameTokenFree(db, pParse->pRename); sqlite3ParserReset(pParse); } /* |
︙ | ︙ | |||
1240 1241 1242 1243 1244 1245 1246 | if( iCol<0 ) return; sqlite3BtreeEnterAll(db); pTab = sqlite3FindTable(db, zTable, zDb); if( pTab==0 || iCol>=pTab->nCol ){ sqlite3BtreeLeaveAll(db); return; } | | | > | | | | < > | | | > > > | > > > > > | > > > > | | | 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 | if( iCol<0 ) return; sqlite3BtreeEnterAll(db); pTab = sqlite3FindTable(db, zTable, zDb); if( pTab==0 || iCol>=pTab->nCol ){ sqlite3BtreeLeaveAll(db); return; } zOld = pTab->aCol[iCol].zCnName; memset(&sCtx, 0, sizeof(sCtx)); sCtx.iCol = ((iCol==pTab->iPKey) ? -1 : iCol); #ifndef SQLITE_OMIT_AUTHORIZATION db->xAuth = 0; #endif rc = renameParseSql(&sParse, zDb, db, zSql, bTemp); /* Find tokens that need to be replaced. */ memset(&sWalker, 0, sizeof(Walker)); sWalker.pParse = &sParse; sWalker.xExprCallback = renameColumnExprCb; sWalker.xSelectCallback = renameColumnSelectCb; sWalker.u.pRename = &sCtx; sCtx.pTab = pTab; if( rc!=SQLITE_OK ) goto renameColumnFunc_done; if( sParse.pNewTable ){ if( IsView(sParse.pNewTable) ){ Select *pSelect = sParse.pNewTable->u.view.pSelect; pSelect->selFlags &= ~SF_View; sParse.rc = SQLITE_OK; sqlite3SelectPrep(&sParse, pSelect, 0); rc = (db->mallocFailed ? SQLITE_NOMEM : sParse.rc); if( rc==SQLITE_OK ){ sqlite3WalkSelect(&sWalker, pSelect); } if( rc!=SQLITE_OK ) goto renameColumnFunc_done; }else if( IsOrdinaryTable(sParse.pNewTable) ){ /* A regular table */ int bFKOnly = sqlite3_stricmp(zTable, sParse.pNewTable->zName); FKey *pFKey; sCtx.pTab = sParse.pNewTable; if( bFKOnly==0 ){ if( iCol<sParse.pNewTable->nCol ){ renameTokenFind( &sParse, &sCtx, (void*)sParse.pNewTable->aCol[iCol].zCnName ); } if( sCtx.iCol<0 ){ renameTokenFind(&sParse, &sCtx, (void*)&sParse.pNewTable->iPKey); } sqlite3WalkExprList(&sWalker, sParse.pNewTable->pCheck); for(pIdx=sParse.pNewTable->pIndex; pIdx; pIdx=pIdx->pNext){ sqlite3WalkExprList(&sWalker, pIdx->aColExpr); } for(pIdx=sParse.pNewIndex; pIdx; pIdx=pIdx->pNext){ sqlite3WalkExprList(&sWalker, pIdx->aColExpr); } #ifndef SQLITE_OMIT_GENERATED_COLUMNS for(i=0; i<sParse.pNewTable->nCol; i++){ Expr *pExpr = sqlite3ColumnExpr(sParse.pNewTable, &sParse.pNewTable->aCol[i]); sqlite3WalkExpr(&sWalker, pExpr); } #endif } assert( IsOrdinaryTable(sParse.pNewTable) ); for(pFKey=sParse.pNewTable->u.tab.pFKey; pFKey; pFKey=pFKey->pNextFrom){ for(i=0; i<pFKey->nCol; i++){ if( bFKOnly==0 && pFKey->aCol[i].iFrom==iCol ){ renameTokenFind(&sParse, &sCtx, (void*)&pFKey->aCol[i]); } if( 0==sqlite3_stricmp(pFKey->zTo, zTable) && 0==sqlite3_stricmp(pFKey->aCol[i].zCol, zOld) ){ renameTokenFind(&sParse, &sCtx, (void*)pFKey->aCol[i].zCol); } } } } }else if( sParse.pNewIndex ){ sqlite3WalkExprList(&sWalker, sParse.pNewIndex->aColExpr); sqlite3WalkExpr(&sWalker, sParse.pNewIndex->pPartIdxWhere); }else{ /* A trigger */ TriggerStep *pStep; rc = renameResolveTrigger(&sParse); if( rc!=SQLITE_OK ) goto renameColumnFunc_done; for(pStep=sParse.pNewTrigger->step_list; pStep; pStep=pStep->pNext){ if( pStep->zTarget ){ Table *pTarget = sqlite3LocateTable(&sParse, 0, pStep->zTarget, zDb); if( pTarget==pTab ){ if( pStep->pUpsert ){ |
︙ | ︙ | |||
1339 1340 1341 1342 1343 1344 1345 | assert( rc==SQLITE_OK ); rc = renameEditSql(context, &sCtx, zSql, zNew, bQuote); renameColumnFunc_done: if( rc!=SQLITE_OK ){ if( sParse.zErrMsg ){ | | | > > > > > > > > | | | 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 | assert( rc==SQLITE_OK ); rc = renameEditSql(context, &sCtx, zSql, zNew, bQuote); renameColumnFunc_done: if( rc!=SQLITE_OK ){ if( sParse.zErrMsg ){ renameColumnParseError(context, "", argv[1], argv[2], &sParse); }else{ sqlite3_result_error_code(context, rc); } } renameParseCleanup(&sParse); renameTokenFree(db, sCtx.pList); #ifndef SQLITE_OMIT_AUTHORIZATION db->xAuth = xAuth; #endif sqlite3BtreeLeaveAll(db); } /* ** Walker expression callback used by "RENAME TABLE". */ static int renameTableExprCb(Walker *pWalker, Expr *pExpr){ RenameCtx *p = pWalker->u.pRename; if( pExpr->op==TK_COLUMN && ALWAYS(ExprUseYTab(pExpr)) && p->pTab==pExpr->y.pTab ){ renameTokenFind(pWalker->pParse, p, (void*)&pExpr->y.pTab); } return WRC_Continue; } /* ** Walker select callback used by "RENAME TABLE". */ static int renameTableSelectCb(Walker *pWalker, Select *pSelect){ int i; RenameCtx *p = pWalker->u.pRename; SrcList *pSrc = pSelect->pSrc; if( pSelect->selFlags & (SF_View|SF_CopyCte) ){ testcase( pSelect->selFlags & SF_View ); testcase( pSelect->selFlags & SF_CopyCte ); return WRC_Prune; } if( NEVER(pSrc==0) ){ assert( pWalker->pParse->db->mallocFailed ); return WRC_Abort; } for(i=0; i<pSrc->nSrc; i++){ SrcItem *pItem = &pSrc->a[i]; if( pItem->pTab==p->pTab ){ renameTokenFind(pWalker->pParse, p, pItem->zName); } } renameWalkWith(pWalker, pSelect); return WRC_Continue; |
︙ | ︙ | |||
1441 1442 1443 1444 1445 1446 1447 | sCtx.pTab = sqlite3FindTable(db, zOld, zDb); memset(&sWalker, 0, sizeof(Walker)); sWalker.pParse = &sParse; sWalker.xExprCallback = renameTableExprCb; sWalker.xSelectCallback = renameTableSelectCb; sWalker.u.pRename = &sCtx; | | | > > > | | > > | > | > > > | | 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 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 1744 1745 1746 | sCtx.pTab = sqlite3FindTable(db, zOld, zDb); memset(&sWalker, 0, sizeof(Walker)); sWalker.pParse = &sParse; sWalker.xExprCallback = renameTableExprCb; sWalker.xSelectCallback = renameTableSelectCb; sWalker.u.pRename = &sCtx; rc = renameParseSql(&sParse, zDb, db, zInput, bTemp); if( rc==SQLITE_OK ){ int isLegacy = (db->flags & SQLITE_LegacyAlter); if( sParse.pNewTable ){ Table *pTab = sParse.pNewTable; if( IsView(pTab) ){ if( isLegacy==0 ){ Select *pSelect = pTab->u.view.pSelect; NameContext sNC; memset(&sNC, 0, sizeof(sNC)); sNC.pParse = &sParse; assert( pSelect->selFlags & SF_View ); pSelect->selFlags &= ~SF_View; sqlite3SelectPrep(&sParse, pTab->u.view.pSelect, &sNC); if( sParse.nErr ){ rc = sParse.rc; }else{ sqlite3WalkSelect(&sWalker, pTab->u.view.pSelect); } } }else{ /* Modify any FK definitions to point to the new table. */ #ifndef SQLITE_OMIT_FOREIGN_KEY if( (isLegacy==0 || (db->flags & SQLITE_ForeignKeys)) && !IsVirtual(pTab) ){ FKey *pFKey; assert( IsOrdinaryTable(pTab) ); for(pFKey=pTab->u.tab.pFKey; pFKey; pFKey=pFKey->pNextFrom){ if( sqlite3_stricmp(pFKey->zTo, zOld)==0 ){ renameTokenFind(&sParse, &sCtx, (void*)pFKey->zTo); } } } #endif |
︙ | ︙ | |||
1502 1503 1504 1505 1506 1507 1508 | if( 0==sqlite3_stricmp(sParse.pNewTrigger->table, zOld) && sCtx.pTab->pSchema==pTrigger->pTabSchema ){ renameTokenFind(&sParse, &sCtx, sParse.pNewTrigger->table); } if( isLegacy==0 ){ | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > | | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | > > | 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 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 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 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 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 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 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 | if( 0==sqlite3_stricmp(sParse.pNewTrigger->table, zOld) && sCtx.pTab->pSchema==pTrigger->pTabSchema ){ renameTokenFind(&sParse, &sCtx, sParse.pNewTrigger->table); } if( isLegacy==0 ){ rc = renameResolveTrigger(&sParse); if( rc==SQLITE_OK ){ renameWalkTrigger(&sWalker, pTrigger); for(pStep=pTrigger->step_list; pStep; pStep=pStep->pNext){ if( pStep->zTarget && 0==sqlite3_stricmp(pStep->zTarget, zOld) ){ renameTokenFind(&sParse, &sCtx, pStep->zTarget); } } } } } #endif } if( rc==SQLITE_OK ){ rc = renameEditSql(context, &sCtx, zInput, zNew, bQuote); } if( rc!=SQLITE_OK ){ if( sParse.zErrMsg ){ renameColumnParseError(context, "", argv[1], argv[2], &sParse); }else{ sqlite3_result_error_code(context, rc); } } renameParseCleanup(&sParse); renameTokenFree(db, sCtx.pList); sqlite3BtreeLeaveAll(db); #ifndef SQLITE_OMIT_AUTHORIZATION db->xAuth = xAuth; #endif } return; } static int renameQuotefixExprCb(Walker *pWalker, Expr *pExpr){ if( pExpr->op==TK_STRING && (pExpr->flags & EP_DblQuoted) ){ renameTokenFind(pWalker->pParse, pWalker->u.pRename, (const void*)pExpr); } return WRC_Continue; } /* ** The implementation of an SQL scalar function that rewrites DDL statements ** so that any string literals that use double-quotes are modified so that ** they use single quotes. ** ** Two arguments must be passed: ** ** 0: Database name ("main", "temp" etc.). ** 1: SQL statement to edit. ** ** The returned value is the modified SQL statement. For example, given ** the database schema: ** ** CREATE TABLE t1(a, b, c); ** ** SELECT sqlite_rename_quotefix('main', ** 'CREATE VIEW v1 AS SELECT "a", "string" FROM t1' ** ); ** ** returns the string: ** ** CREATE VIEW v1 AS SELECT "a", 'string' FROM t1 */ static void renameQuotefixFunc( sqlite3_context *context, int NotUsed, sqlite3_value **argv ){ sqlite3 *db = sqlite3_context_db_handle(context); char const *zDb = (const char*)sqlite3_value_text(argv[0]); char const *zInput = (const char*)sqlite3_value_text(argv[1]); #ifndef SQLITE_OMIT_AUTHORIZATION sqlite3_xauth xAuth = db->xAuth; db->xAuth = 0; #endif sqlite3BtreeEnterAll(db); UNUSED_PARAMETER(NotUsed); if( zDb && zInput ){ int rc; Parse sParse; rc = renameParseSql(&sParse, zDb, db, zInput, 0); if( rc==SQLITE_OK ){ RenameCtx sCtx; Walker sWalker; /* Walker to find tokens that need to be replaced. */ memset(&sCtx, 0, sizeof(RenameCtx)); memset(&sWalker, 0, sizeof(Walker)); sWalker.pParse = &sParse; sWalker.xExprCallback = renameQuotefixExprCb; sWalker.xSelectCallback = renameColumnSelectCb; sWalker.u.pRename = &sCtx; if( sParse.pNewTable ){ if( IsView(sParse.pNewTable) ){ Select *pSelect = sParse.pNewTable->u.view.pSelect; pSelect->selFlags &= ~SF_View; sParse.rc = SQLITE_OK; sqlite3SelectPrep(&sParse, pSelect, 0); rc = (db->mallocFailed ? SQLITE_NOMEM : sParse.rc); if( rc==SQLITE_OK ){ sqlite3WalkSelect(&sWalker, pSelect); } }else{ int i; sqlite3WalkExprList(&sWalker, sParse.pNewTable->pCheck); #ifndef SQLITE_OMIT_GENERATED_COLUMNS for(i=0; i<sParse.pNewTable->nCol; i++){ sqlite3WalkExpr(&sWalker, sqlite3ColumnExpr(sParse.pNewTable, &sParse.pNewTable->aCol[i])); } #endif /* SQLITE_OMIT_GENERATED_COLUMNS */ } }else if( sParse.pNewIndex ){ sqlite3WalkExprList(&sWalker, sParse.pNewIndex->aColExpr); sqlite3WalkExpr(&sWalker, sParse.pNewIndex->pPartIdxWhere); }else{ #ifndef SQLITE_OMIT_TRIGGER rc = renameResolveTrigger(&sParse); if( rc==SQLITE_OK ){ renameWalkTrigger(&sWalker, sParse.pNewTrigger); } #endif /* SQLITE_OMIT_TRIGGER */ } if( rc==SQLITE_OK ){ rc = renameEditSql(context, &sCtx, zInput, 0, 0); } renameTokenFree(db, sCtx.pList); } if( rc!=SQLITE_OK ){ sqlite3_result_error_code(context, rc); } renameParseCleanup(&sParse); } #ifndef SQLITE_OMIT_AUTHORIZATION db->xAuth = xAuth; #endif sqlite3BtreeLeaveAll(db); } /* ** An SQL user function that checks that there are no parse or symbol ** resolution problems in a CREATE TRIGGER|TABLE|VIEW|INDEX statement. ** After an ALTER TABLE .. RENAME operation is performed and the schema ** reloaded, this function is called on each SQL statement in the schema ** to ensure that it is still usable. ** ** 0: Database name ("main", "temp" etc.). ** 1: SQL statement. ** 2: Object type ("view", "table", "trigger" or "index"). ** 3: Object name. ** 4: True if object is from temp schema. ** 5: "when" part of error message. ** 6: True to disable the DQS quirk when parsing SQL. ** ** Unless it finds an error, this function normally returns NULL. However, it ** returns integer value 1 if: ** ** * the SQL argument creates a trigger, and ** * the table that the trigger is attached to is in database zDb. */ static void renameTableTest( sqlite3_context *context, int NotUsed, sqlite3_value **argv ){ sqlite3 *db = sqlite3_context_db_handle(context); char const *zDb = (const char*)sqlite3_value_text(argv[0]); char const *zInput = (const char*)sqlite3_value_text(argv[1]); int bTemp = sqlite3_value_int(argv[4]); int isLegacy = (db->flags & SQLITE_LegacyAlter); char const *zWhen = (const char*)sqlite3_value_text(argv[5]); int bNoDQS = sqlite3_value_int(argv[6]); #ifndef SQLITE_OMIT_AUTHORIZATION sqlite3_xauth xAuth = db->xAuth; db->xAuth = 0; #endif UNUSED_PARAMETER(NotUsed); if( zDb && zInput ){ int rc; Parse sParse; int flags = db->flags; if( bNoDQS ) db->flags &= ~(SQLITE_DqsDML|SQLITE_DqsDDL); rc = renameParseSql(&sParse, zDb, db, zInput, bTemp); db->flags |= (flags & (SQLITE_DqsDML|SQLITE_DqsDDL)); if( rc==SQLITE_OK ){ if( isLegacy==0 && sParse.pNewTable && IsView(sParse.pNewTable) ){ NameContext sNC; memset(&sNC, 0, sizeof(sNC)); sNC.pParse = &sParse; sqlite3SelectPrep(&sParse, sParse.pNewTable->u.view.pSelect, &sNC); if( sParse.nErr ) rc = sParse.rc; } else if( sParse.pNewTrigger ){ if( isLegacy==0 ){ rc = renameResolveTrigger(&sParse); } if( rc==SQLITE_OK ){ int i1 = sqlite3SchemaToIndex(db, sParse.pNewTrigger->pTabSchema); int i2 = sqlite3FindDbName(db, zDb); if( i1==i2 ) sqlite3_result_int(context, 1); } } } if( rc!=SQLITE_OK && zWhen ){ renameColumnParseError(context, zWhen, argv[2], argv[3],&sParse); } renameParseCleanup(&sParse); } #ifndef SQLITE_OMIT_AUTHORIZATION db->xAuth = xAuth; #endif } /* ** The implementation of internal UDF sqlite_drop_column(). ** ** Arguments: ** ** argv[0]: An integer - the index of the schema containing the table ** argv[1]: CREATE TABLE statement to modify. ** argv[2]: An integer - the index of the column to remove. ** ** The value returned is a string containing the CREATE TABLE statement ** with column argv[2] removed. */ static void dropColumnFunc( sqlite3_context *context, int NotUsed, sqlite3_value **argv ){ sqlite3 *db = sqlite3_context_db_handle(context); int iSchema = sqlite3_value_int(argv[0]); const char *zSql = (const char*)sqlite3_value_text(argv[1]); int iCol = sqlite3_value_int(argv[2]); const char *zDb = db->aDb[iSchema].zDbSName; int rc; Parse sParse; RenameToken *pCol; Table *pTab; const char *zEnd; char *zNew = 0; #ifndef SQLITE_OMIT_AUTHORIZATION sqlite3_xauth xAuth = db->xAuth; db->xAuth = 0; #endif UNUSED_PARAMETER(NotUsed); rc = renameParseSql(&sParse, zDb, db, zSql, iSchema==1); if( rc!=SQLITE_OK ) goto drop_column_done; pTab = sParse.pNewTable; if( pTab==0 || pTab->nCol==1 || iCol>=pTab->nCol ){ /* This can happen if the sqlite_schema table is corrupt */ rc = SQLITE_CORRUPT_BKPT; goto drop_column_done; } pCol = renameTokenFind(&sParse, 0, (void*)pTab->aCol[iCol].zCnName); if( iCol<pTab->nCol-1 ){ RenameToken *pEnd; pEnd = renameTokenFind(&sParse, 0, (void*)pTab->aCol[iCol+1].zCnName); zEnd = (const char*)pEnd->t.z; }else{ assert( IsOrdinaryTable(pTab) ); zEnd = (const char*)&zSql[pTab->u.tab.addColOffset]; while( ALWAYS(pCol->t.z[0]!=0) && pCol->t.z[0]!=',' ) pCol->t.z--; } zNew = sqlite3MPrintf(db, "%.*s%s", pCol->t.z-zSql, zSql, zEnd); sqlite3_result_text(context, zNew, -1, SQLITE_TRANSIENT); sqlite3_free(zNew); drop_column_done: renameParseCleanup(&sParse); #ifndef SQLITE_OMIT_AUTHORIZATION db->xAuth = xAuth; #endif if( rc!=SQLITE_OK ){ sqlite3_result_error_code(context, rc); } } /* ** This function is called by the parser upon parsing an ** ** ALTER TABLE pSrc DROP COLUMN pName ** ** statement. Argument pSrc contains the possibly qualified name of the ** table being edited, and token pName the name of the column to drop. */ void sqlite3AlterDropColumn(Parse *pParse, SrcList *pSrc, const Token *pName){ sqlite3 *db = pParse->db; /* Database handle */ Table *pTab; /* Table to modify */ int iDb; /* Index of db containing pTab in aDb[] */ const char *zDb; /* Database containing pTab ("main" etc.) */ char *zCol = 0; /* Name of column to drop */ int iCol; /* Index of column zCol in pTab->aCol[] */ /* Look up the table being altered. */ assert( pParse->pNewTable==0 ); assert( sqlite3BtreeHoldsAllMutexes(db) ); if( NEVER(db->mallocFailed) ) goto exit_drop_column; pTab = sqlite3LocateTableItem(pParse, 0, &pSrc->a[0]); if( !pTab ) goto exit_drop_column; /* Make sure this is not an attempt to ALTER a view, virtual table or ** system table. */ if( SQLITE_OK!=isAlterableTable(pParse, pTab) ) goto exit_drop_column; if( SQLITE_OK!=isRealTable(pParse, pTab, 1) ) goto exit_drop_column; /* Find the index of the column being dropped. */ zCol = sqlite3NameFromToken(db, pName); if( zCol==0 ){ assert( db->mallocFailed ); goto exit_drop_column; } iCol = sqlite3ColumnIndex(pTab, zCol); if( iCol<0 ){ sqlite3ErrorMsg(pParse, "no such column: \"%s\"", zCol); goto exit_drop_column; } /* Do not allow the user to drop a PRIMARY KEY column or a column ** constrained by a UNIQUE constraint. */ if( pTab->aCol[iCol].colFlags & (COLFLAG_PRIMKEY|COLFLAG_UNIQUE) ){ sqlite3ErrorMsg(pParse, "cannot drop %s column: \"%s\"", (pTab->aCol[iCol].colFlags&COLFLAG_PRIMKEY) ? "PRIMARY KEY" : "UNIQUE", zCol ); goto exit_drop_column; } /* Do not allow the number of columns to go to zero */ if( pTab->nCol<=1 ){ sqlite3ErrorMsg(pParse, "cannot drop column \"%s\": no other columns exist",zCol); goto exit_drop_column; } /* Edit the sqlite_schema table */ iDb = sqlite3SchemaToIndex(db, pTab->pSchema); assert( iDb>=0 ); zDb = db->aDb[iDb].zDbSName; renameTestSchema(pParse, zDb, iDb==1, "", 0); renameFixQuotes(pParse, zDb, iDb==1); sqlite3NestedParse(pParse, "UPDATE \"%w\"." LEGACY_SCHEMA_TABLE " SET " "sql = sqlite_drop_column(%d, sql, %d) " "WHERE (type=='table' AND tbl_name=%Q COLLATE nocase)" , zDb, iDb, iCol, pTab->zName ); /* Drop and reload the database schema. */ renameReloadSchema(pParse, iDb, INITFLAG_AlterDrop); renameTestSchema(pParse, zDb, iDb==1, "after drop column", 1); /* Edit rows of table on disk */ if( pParse->nErr==0 && (pTab->aCol[iCol].colFlags & COLFLAG_VIRTUAL)==0 ){ int i; int addr; int reg; int regRec; Index *pPk = 0; int nField = 0; /* Number of non-virtual columns after drop */ int iCur; Vdbe *v = sqlite3GetVdbe(pParse); iCur = pParse->nTab++; sqlite3OpenTable(pParse, iCur, iDb, pTab, OP_OpenWrite); addr = sqlite3VdbeAddOp1(v, OP_Rewind, iCur); VdbeCoverage(v); reg = ++pParse->nMem; if( HasRowid(pTab) ){ sqlite3VdbeAddOp2(v, OP_Rowid, iCur, reg); pParse->nMem += pTab->nCol; }else{ pPk = sqlite3PrimaryKeyIndex(pTab); pParse->nMem += pPk->nColumn; for(i=0; i<pPk->nKeyCol; i++){ sqlite3VdbeAddOp3(v, OP_Column, iCur, i, reg+i+1); } nField = pPk->nKeyCol; } regRec = ++pParse->nMem; for(i=0; i<pTab->nCol; i++){ if( i!=iCol && (pTab->aCol[i].colFlags & COLFLAG_VIRTUAL)==0 ){ int regOut; if( pPk ){ int iPos = sqlite3TableColumnToIndex(pPk, i); int iColPos = sqlite3TableColumnToIndex(pPk, iCol); if( iPos<pPk->nKeyCol ) continue; regOut = reg+1+iPos-(iPos>iColPos); }else{ regOut = reg+1+nField; } if( i==pTab->iPKey ){ sqlite3VdbeAddOp2(v, OP_Null, 0, regOut); }else{ sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, i, regOut); } nField++; } } if( nField==0 ){ /* dbsqlfuzz 5f09e7bcc78b4954d06bf9f2400d7715f48d1fef */ pParse->nMem++; sqlite3VdbeAddOp2(v, OP_Null, 0, reg+1); nField = 1; } sqlite3VdbeAddOp3(v, OP_MakeRecord, reg+1, nField, regRec); if( pPk ){ sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iCur, regRec, reg+1, pPk->nKeyCol); }else{ sqlite3VdbeAddOp3(v, OP_Insert, iCur, regRec, reg); } sqlite3VdbeChangeP5(v, OPFLAG_SAVEPOSITION); sqlite3VdbeAddOp2(v, OP_Next, iCur, addr+1); VdbeCoverage(v); sqlite3VdbeJumpHere(v, addr); } exit_drop_column: sqlite3DbFree(db, zCol); sqlite3SrcListDelete(db, pSrc); } /* ** Register built-in functions used to help implement ALTER TABLE */ void sqlite3AlterFunctions(void){ static FuncDef aAlterTableFuncs[] = { INTERNAL_FUNCTION(sqlite_rename_column, 9, renameColumnFunc), INTERNAL_FUNCTION(sqlite_rename_table, 7, renameTableFunc), INTERNAL_FUNCTION(sqlite_rename_test, 7, renameTableTest), INTERNAL_FUNCTION(sqlite_drop_column, 3, dropColumnFunc), INTERNAL_FUNCTION(sqlite_rename_quotefix,2, renameQuotefixFunc), }; sqlite3InsertBuiltinFuncs(aAlterTableFuncs, ArraySize(aAlterTableFuncs)); } #endif /* SQLITE_ALTER_TABLE */ |
Changes to src/analyze.c.
︙ | ︙ | |||
23 24 25 26 27 28 29 | ** CREATE TABLE sqlite_stat4(tbl, idx, nEq, nLt, nDLt, sample); ** ** Additional tables might be added in future releases of SQLite. ** The sqlite_stat2 table is not created or used unless the SQLite version ** is between 3.6.18 and 3.7.8, inclusive, and unless SQLite is compiled ** with SQLITE_ENABLE_STAT2. The sqlite_stat2 table is deprecated. ** The sqlite_stat2 table is superseded by sqlite_stat3, which is only | | | | | | | | 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | ** CREATE TABLE sqlite_stat4(tbl, idx, nEq, nLt, nDLt, sample); ** ** Additional tables might be added in future releases of SQLite. ** The sqlite_stat2 table is not created or used unless the SQLite version ** is between 3.6.18 and 3.7.8, inclusive, and unless SQLite is compiled ** with SQLITE_ENABLE_STAT2. The sqlite_stat2 table is deprecated. ** The sqlite_stat2 table is superseded by sqlite_stat3, which is only ** created and used by SQLite versions 3.7.9 through 3.29.0 when ** SQLITE_ENABLE_STAT3 defined. The functionality of sqlite_stat3 ** is a superset of sqlite_stat2 and is also now deprecated. The ** sqlite_stat4 is an enhanced version of sqlite_stat3 and is only ** available when compiled with SQLITE_ENABLE_STAT4 and in SQLite ** versions 3.8.1 and later. STAT4 is the only variant that is still ** supported. ** ** For most applications, sqlite_stat1 provides all the statistics required ** for the query planner to make good choices. ** ** Format of sqlite_stat1: ** ** There is normally one row per index, with the index identified by the |
︙ | ︙ | |||
140 141 142 143 144 145 146 | ** integer in the equivalent columns in sqlite_stat4. */ #ifndef SQLITE_OMIT_ANALYZE #include "sqliteInt.h" #if defined(SQLITE_ENABLE_STAT4) # define IsStat4 1 | < < < < < < | 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 | ** integer in the equivalent columns in sqlite_stat4. */ #ifndef SQLITE_OMIT_ANALYZE #include "sqliteInt.h" #if defined(SQLITE_ENABLE_STAT4) # define IsStat4 1 #else # define IsStat4 0 # undef SQLITE_STAT4_SAMPLES # define SQLITE_STAT4_SAMPLES 1 #endif /* ** This routine generates code that opens the sqlite_statN tables. ** The sqlite_stat1 table is always relevant. sqlite_stat2 is now ** obsolete. sqlite_stat3 and sqlite_stat4 are only opened when ** appropriate compile-time options are provided. ** |
︙ | ︙ | |||
179 180 181 182 183 184 185 | static const struct { const char *zName; const char *zCols; } aTable[] = { { "sqlite_stat1", "tbl,idx,stat" }, #if defined(SQLITE_ENABLE_STAT4) { "sqlite_stat4", "tbl,idx,neq,nlt,ndlt,sample" }, | < < < < < > | > > > > > > | | < | | | | | | | | > > | | > > > > < | | | | | | | | | | | | | | | | > | | | | > | | > < < | | | | | | > | | | | | > | | | > < < > > > | < > > < | | | | | | 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 | static const struct { const char *zName; const char *zCols; } aTable[] = { { "sqlite_stat1", "tbl,idx,stat" }, #if defined(SQLITE_ENABLE_STAT4) { "sqlite_stat4", "tbl,idx,neq,nlt,ndlt,sample" }, #else { "sqlite_stat4", 0 }, #endif { "sqlite_stat3", 0 }, }; int i; sqlite3 *db = pParse->db; Db *pDb; Vdbe *v = sqlite3GetVdbe(pParse); u32 aRoot[ArraySize(aTable)]; u8 aCreateTbl[ArraySize(aTable)]; #ifdef SQLITE_ENABLE_STAT4 const int nToOpen = OptimizationEnabled(db,SQLITE_Stat4) ? 2 : 1; #else const int nToOpen = 1; #endif if( v==0 ) return; assert( sqlite3BtreeHoldsAllMutexes(db) ); assert( sqlite3VdbeDb(v)==db ); pDb = &db->aDb[iDb]; /* Create new statistic tables if they do not exist, or clear them ** if they do already exist. */ for(i=0; i<ArraySize(aTable); i++){ const char *zTab = aTable[i].zName; Table *pStat; aCreateTbl[i] = 0; if( (pStat = sqlite3FindTable(db, zTab, pDb->zDbSName))==0 ){ if( i<nToOpen ){ /* The sqlite_statN table does not exist. Create it. Note that a ** side-effect of the CREATE TABLE statement is to leave the rootpage ** of the new table in register pParse->regRoot. This is important ** because the OpenWrite opcode below will be needing it. */ sqlite3NestedParse(pParse, "CREATE TABLE %Q.%s(%s)", pDb->zDbSName, zTab, aTable[i].zCols ); aRoot[i] = (u32)pParse->regRoot; aCreateTbl[i] = OPFLAG_P2ISREG; } }else{ /* The table already exists. If zWhere is not NULL, delete all entries ** associated with the table zWhere. If zWhere is NULL, delete the ** entire contents of the table. */ aRoot[i] = pStat->tnum; sqlite3TableLock(pParse, iDb, aRoot[i], 1, zTab); if( zWhere ){ sqlite3NestedParse(pParse, "DELETE FROM %Q.%s WHERE %s=%Q", pDb->zDbSName, zTab, zWhereType, zWhere ); #ifdef SQLITE_ENABLE_PREUPDATE_HOOK }else if( db->xPreUpdateCallback ){ sqlite3NestedParse(pParse, "DELETE FROM %Q.%s", pDb->zDbSName, zTab); #endif }else{ /* The sqlite_stat[134] table already exists. Delete all rows. */ sqlite3VdbeAddOp2(v, OP_Clear, (int)aRoot[i], iDb); } } } /* Open the sqlite_stat[134] tables for writing. */ for(i=0; i<nToOpen; i++){ assert( i<ArraySize(aTable) ); sqlite3VdbeAddOp4Int(v, OP_OpenWrite, iStatCur+i, (int)aRoot[i], iDb, 3); sqlite3VdbeChangeP5(v, aCreateTbl[i]); VdbeComment((v, aTable[i].zName)); } } /* ** Recommended number of samples for sqlite_stat4 */ #ifndef SQLITE_STAT4_SAMPLES # define SQLITE_STAT4_SAMPLES 24 #endif /* ** Three SQL functions - stat_init(), stat_push(), and stat_get() - ** share an instance of the following structure to hold their state ** information. */ typedef struct StatAccum StatAccum; typedef struct StatSample StatSample; struct StatSample { tRowcnt *anEq; /* sqlite_stat4.nEq */ tRowcnt *anDLt; /* sqlite_stat4.nDLt */ #ifdef SQLITE_ENABLE_STAT4 tRowcnt *anLt; /* sqlite_stat4.nLt */ union { i64 iRowid; /* Rowid in main table of the key */ u8 *aRowid; /* Key for WITHOUT ROWID tables */ } u; u32 nRowid; /* Sizeof aRowid[] */ u8 isPSample; /* True if a periodic sample */ int iCol; /* If !isPSample, the reason for inclusion */ u32 iHash; /* Tiebreaker hash */ #endif }; struct StatAccum { sqlite3 *db; /* Database connection, for malloc() */ tRowcnt nEst; /* Estimated number of rows */ tRowcnt nRow; /* Number of rows visited so far */ int nLimit; /* Analysis row-scan limit */ int nCol; /* Number of columns in index + pk/rowid */ int nKeyCol; /* Number of index columns w/o the pk/rowid */ u8 nSkipAhead; /* Number of times of skip-ahead */ StatSample current; /* Current row as a StatSample */ #ifdef SQLITE_ENABLE_STAT4 tRowcnt nPSample; /* How often to do a periodic sample */ int mxSample; /* Maximum number of samples to accumulate */ u32 iPrn; /* Pseudo-random number used for sampling */ StatSample *aBest; /* Array of nCol best samples */ int iMin; /* Index in a[] of entry with minimum score */ int nSample; /* Current number of samples */ int nMaxEqZero; /* Max leading 0 in anEq[] for any a[] entry */ int iGet; /* Index of current sample accessed by stat_get() */ StatSample *a; /* Array of mxSample StatSample objects */ #endif }; /* Reclaim memory used by a StatSample */ #ifdef SQLITE_ENABLE_STAT4 static void sampleClear(sqlite3 *db, StatSample *p){ assert( db!=0 ); if( p->nRowid ){ sqlite3DbFree(db, p->u.aRowid); p->nRowid = 0; } } #endif /* Initialize the BLOB value of a ROWID */ #ifdef SQLITE_ENABLE_STAT4 static void sampleSetRowid(sqlite3 *db, StatSample *p, int n, const u8 *pData){ assert( db!=0 ); if( p->nRowid ) sqlite3DbFree(db, p->u.aRowid); p->u.aRowid = sqlite3DbMallocRawNN(db, n); if( p->u.aRowid ){ p->nRowid = n; memcpy(p->u.aRowid, pData, n); }else{ p->nRowid = 0; } } #endif /* Initialize the INTEGER value of a ROWID. */ #ifdef SQLITE_ENABLE_STAT4 static void sampleSetRowidInt64(sqlite3 *db, StatSample *p, i64 iRowid){ assert( db!=0 ); if( p->nRowid ) sqlite3DbFree(db, p->u.aRowid); p->nRowid = 0; p->u.iRowid = iRowid; } #endif /* ** Copy the contents of object (*pFrom) into (*pTo). */ #ifdef SQLITE_ENABLE_STAT4 static void sampleCopy(StatAccum *p, StatSample *pTo, StatSample *pFrom){ pTo->isPSample = pFrom->isPSample; pTo->iCol = pFrom->iCol; pTo->iHash = pFrom->iHash; memcpy(pTo->anEq, pFrom->anEq, sizeof(tRowcnt)*p->nCol); memcpy(pTo->anLt, pFrom->anLt, sizeof(tRowcnt)*p->nCol); memcpy(pTo->anDLt, pFrom->anDLt, sizeof(tRowcnt)*p->nCol); if( pFrom->nRowid ){ sampleSetRowid(p->db, pTo, pFrom->nRowid, pFrom->u.aRowid); }else{ sampleSetRowidInt64(p->db, pTo, pFrom->u.iRowid); } } #endif /* ** Reclaim all memory of a StatAccum structure. */ static void statAccumDestructor(void *pOld){ StatAccum *p = (StatAccum*)pOld; #ifdef SQLITE_ENABLE_STAT4 if( p->mxSample ){ int i; for(i=0; i<p->nCol; i++) sampleClear(p->db, p->aBest+i); for(i=0; i<p->mxSample; i++) sampleClear(p->db, p->a+i); sampleClear(p->db, &p->current); } #endif sqlite3DbFree(p->db, p); } /* ** Implementation of the stat_init(N,K,C,L) SQL function. The four parameters ** are: ** N: The number of columns in the index including the rowid/pk (note 1) ** K: The number of columns in the index excluding the rowid/pk. ** C: Estimated number of rows in the index ** L: A limit on the number of rows to scan, or 0 for no-limit ** ** Note 1: In the special case of the covering index that implements a ** WITHOUT ROWID table, N is the number of PRIMARY KEY columns, not the ** total number of columns in the table. ** ** For indexes on ordinary rowid tables, N==K+1. But for indexes on ** WITHOUT ROWID tables, N=K+P where P is the number of columns in the ** PRIMARY KEY of the table. The covering index that implements the ** original WITHOUT ROWID table as N==K as a special case. ** ** This routine allocates the StatAccum object in heap memory. The return ** value is a pointer to the StatAccum object. The datatype of the ** return value is BLOB, but it is really just a pointer to the StatAccum ** object. */ static void statInit( sqlite3_context *context, int argc, sqlite3_value **argv ){ StatAccum *p; int nCol; /* Number of columns in index being sampled */ int nKeyCol; /* Number of key columns */ int nColUp; /* nCol rounded up for alignment */ int n; /* Bytes of space to allocate */ sqlite3 *db = sqlite3_context_db_handle(context); /* Database connection */ #ifdef SQLITE_ENABLE_STAT4 /* Maximum number of samples. 0 if STAT4 data is not collected */ int mxSample = OptimizationEnabled(db,SQLITE_Stat4) ?SQLITE_STAT4_SAMPLES :0; #endif /* Decode the three function arguments */ UNUSED_PARAMETER(argc); nCol = sqlite3_value_int(argv[0]); assert( nCol>0 ); nColUp = sizeof(tRowcnt)<8 ? (nCol+1)&~1 : nCol; nKeyCol = sqlite3_value_int(argv[1]); assert( nKeyCol<=nCol ); assert( nKeyCol>0 ); /* Allocate the space required for the StatAccum object */ n = sizeof(*p) + sizeof(tRowcnt)*nColUp /* StatAccum.anEq */ + sizeof(tRowcnt)*nColUp; /* StatAccum.anDLt */ #ifdef SQLITE_ENABLE_STAT4 if( mxSample ){ n += sizeof(tRowcnt)*nColUp /* StatAccum.anLt */ + sizeof(StatSample)*(nCol+mxSample) /* StatAccum.aBest[], a[] */ + sizeof(tRowcnt)*3*nColUp*(nCol+mxSample); } #endif p = sqlite3DbMallocZero(db, n); if( p==0 ){ sqlite3_result_error_nomem(context); return; } p->db = db; p->nEst = sqlite3_value_int64(argv[2]); p->nRow = 0; p->nLimit = sqlite3_value_int64(argv[3]); p->nCol = nCol; p->nKeyCol = nKeyCol; p->nSkipAhead = 0; p->current.anDLt = (tRowcnt*)&p[1]; p->current.anEq = &p->current.anDLt[nColUp]; #ifdef SQLITE_ENABLE_STAT4 p->mxSample = p->nLimit==0 ? mxSample : 0; if( mxSample ){ u8 *pSpace; /* Allocated space not yet assigned */ int i; /* Used to iterate through p->aSample[] */ p->iGet = -1; p->nPSample = (tRowcnt)(p->nEst/(mxSample/3+1) + 1); p->current.anLt = &p->current.anEq[nColUp]; p->iPrn = 0x689e962d*(u32)nCol ^ 0xd0944565*(u32)sqlite3_value_int(argv[2]); /* Set up the StatAccum.a[] and aBest[] arrays */ p->a = (struct StatSample*)&p->current.anLt[nColUp]; p->aBest = &p->a[mxSample]; pSpace = (u8*)(&p->a[mxSample+nCol]); for(i=0; i<(mxSample+nCol); i++){ p->a[i].anEq = (tRowcnt *)pSpace; pSpace += (sizeof(tRowcnt) * nColUp); p->a[i].anLt = (tRowcnt *)pSpace; pSpace += (sizeof(tRowcnt) * nColUp); p->a[i].anDLt = (tRowcnt *)pSpace; pSpace += (sizeof(tRowcnt) * nColUp); } assert( (pSpace - (u8*)p)==n ); for(i=0; i<nCol; i++){ p->aBest[i].iCol = i; } } #endif /* Return a pointer to the allocated object to the caller. Note that ** only the pointer (the 2nd parameter) matters. The size of the object ** (given by the 3rd parameter) is never used and can be any positive ** value. */ sqlite3_result_blob(context, p, sizeof(*p), statAccumDestructor); } static const FuncDef statInitFuncdef = { 4, /* nArg */ SQLITE_UTF8, /* funcFlags */ 0, /* pUserData */ 0, /* pNext */ statInit, /* xSFunc */ 0, /* xFinalize */ 0, 0, /* xValue, xInverse */ "stat_init", /* zName */ |
︙ | ︙ | |||
499 500 501 502 503 504 505 | ** In other words, if we assume that the cardinalities of the selected ** column for pNew and pOld are equal, is pNew to be preferred over pOld. ** ** This function assumes that for each argument sample, the contents of ** the anEq[] array from pSample->anEq[pSample->iCol+1] onwards are valid. */ static int sampleIsBetterPost( | | | | | | | | < < < < | | < | | | | | < | < < < | < | > | < | | 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 | ** In other words, if we assume that the cardinalities of the selected ** column for pNew and pOld are equal, is pNew to be preferred over pOld. ** ** This function assumes that for each argument sample, the contents of ** the anEq[] array from pSample->anEq[pSample->iCol+1] onwards are valid. */ static int sampleIsBetterPost( StatAccum *pAccum, StatSample *pNew, StatSample *pOld ){ int nCol = pAccum->nCol; int i; assert( pNew->iCol==pOld->iCol ); for(i=pNew->iCol+1; i<nCol; i++){ if( pNew->anEq[i]>pOld->anEq[i] ) return 1; if( pNew->anEq[i]<pOld->anEq[i] ) return 0; } if( pNew->iHash>pOld->iHash ) return 1; return 0; } #endif #ifdef SQLITE_ENABLE_STAT4 /* ** Return true if pNew is to be preferred over pOld. ** ** This function assumes that for each argument sample, the contents of ** the anEq[] array from pSample->anEq[pSample->iCol] onwards are valid. */ static int sampleIsBetter( StatAccum *pAccum, StatSample *pNew, StatSample *pOld ){ tRowcnt nEqNew = pNew->anEq[pNew->iCol]; tRowcnt nEqOld = pOld->anEq[pOld->iCol]; assert( pOld->isPSample==0 && pNew->isPSample==0 ); assert( IsStat4 || (pNew->iCol==0 && pOld->iCol==0) ); if( (nEqNew>nEqOld) ) return 1; if( nEqNew==nEqOld ){ if( pNew->iCol<pOld->iCol ) return 1; return (pNew->iCol==pOld->iCol && sampleIsBetterPost(pAccum, pNew, pOld)); } return 0; } /* ** Copy the contents of sample *pNew into the p->a[] array. If necessary, ** remove the least desirable sample from p->a[] to make room. */ static void sampleInsert(StatAccum *p, StatSample *pNew, int nEqZero){ StatSample *pSample = 0; int i; assert( IsStat4 || nEqZero==0 ); /* StatAccum.nMaxEqZero is set to the maximum number of leading 0 ** values in the anEq[] array of any sample in StatAccum.a[]. In ** other words, if nMaxEqZero is n, then it is guaranteed that there ** are no samples with StatSample.anEq[m]==0 for (m>=n). */ if( nEqZero>p->nMaxEqZero ){ p->nMaxEqZero = nEqZero; } if( pNew->isPSample==0 ){ StatSample *pUpgrade = 0; assert( pNew->anEq[pNew->iCol]>0 ); /* This sample is being added because the prefix that ends in column ** iCol occurs many times in the table. However, if we have already ** added a sample that shares this prefix, there is no need to add ** this one. Instead, upgrade the priority of the highest priority ** existing sample that shares this prefix. */ for(i=p->nSample-1; i>=0; i--){ StatSample *pOld = &p->a[i]; if( pOld->anEq[pNew->iCol]==0 ){ if( pOld->isPSample ) return; assert( pOld->iCol>pNew->iCol ); assert( sampleIsBetter(p, pNew, pOld) ); if( pUpgrade==0 || sampleIsBetter(p, pOld, pUpgrade) ){ pUpgrade = pOld; } } } if( pUpgrade ){ pUpgrade->iCol = pNew->iCol; pUpgrade->anEq[pUpgrade->iCol] = pNew->anEq[pUpgrade->iCol]; goto find_new_min; } } /* If necessary, remove sample iMin to make room for the new sample. */ if( p->nSample>=p->mxSample ){ StatSample *pMin = &p->a[p->iMin]; tRowcnt *anEq = pMin->anEq; tRowcnt *anLt = pMin->anLt; tRowcnt *anDLt = pMin->anDLt; sampleClear(p->db, pMin); memmove(pMin, &pMin[1], sizeof(p->a[0])*(p->nSample-p->iMin-1)); pSample = &p->a[p->nSample-1]; pSample->nRowid = 0; pSample->anEq = anEq; pSample->anDLt = anDLt; pSample->anLt = anLt; p->nSample = p->mxSample-1; } /* The "rows less-than" for the rowid column must be greater than that ** for the last sample in the p->a[] array. Otherwise, the samples would ** be out of order. */ assert( p->nSample==0 || pNew->anLt[p->nCol-1] > p->a[p->nSample-1].anLt[p->nCol-1] ); /* Insert the new sample */ pSample = &p->a[p->nSample]; sampleCopy(p, pSample, pNew); p->nSample++; /* Zero the first nEqZero entries in the anEq[] array. */ memset(pSample->anEq, 0, sizeof(tRowcnt)*nEqZero); find_new_min: if( p->nSample>=p->mxSample ){ int iMin = -1; for(i=0; i<p->mxSample; i++){ if( p->a[i].isPSample ) continue; if( iMin<0 || sampleIsBetter(p, &p->a[iMin], &p->a[i]) ){ iMin = i; } } assert( iMin>=0 ); p->iMin = iMin; } } #endif /* SQLITE_ENABLE_STAT4 */ #ifdef SQLITE_ENABLE_STAT4 /* ** Field iChng of the index being scanned has changed. So at this point ** p->current contains a sample that reflects the previous row of the ** index. The value of anEq[iChng] and subsequent anEq[] elements are ** correct at this point. */ static void samplePushPrevious(StatAccum *p, int iChng){ int i; /* Check if any samples from the aBest[] array should be pushed ** into IndexSample.a[] at this point. */ for(i=(p->nCol-2); i>=iChng; i--){ StatSample *pBest = &p->aBest[i]; pBest->anEq[i] = p->current.anEq[i]; if( p->nSample<p->mxSample || sampleIsBetter(p, pBest, &p->a[p->iMin]) ){ sampleInsert(p, pBest, i); } } /* Check that no sample contains an anEq[] entry with an index of |
︙ | ︙ | |||
677 678 679 680 681 682 683 | int j; for(j=iChng; j<p->nCol; j++){ if( p->a[i].anEq[j]==0 ) p->a[i].anEq[j] = p->current.anEq[j]; } } p->nMaxEqZero = iChng; } | < | < < < < < < < < < < < < < < < < < < < < < | < < < < | < | > | | > > > | | > | > | | > | > > | | | | | | | < < < | < | > > > | > > | | | | | | | | > | | | | < | < < | < < | < < | < | | > > | < < < < < < < < < | | < | < < > | | < < | | | < | | > | | > | > > > > > > > > > > > > > > > > > > | > > > > | 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 | int j; for(j=iChng; j<p->nCol; j++){ if( p->a[i].anEq[j]==0 ) p->a[i].anEq[j] = p->current.anEq[j]; } } p->nMaxEqZero = iChng; } } #endif /* SQLITE_ENABLE_STAT4 */ /* ** Implementation of the stat_push SQL function: stat_push(P,C,R) ** Arguments: ** ** P Pointer to the StatAccum object created by stat_init() ** C Index of left-most column to differ from previous row ** R Rowid for the current row. Might be a key record for ** WITHOUT ROWID tables. ** ** The purpose of this routine is to collect statistical data and/or ** samples from the index being analyzed into the StatAccum object. ** The stat_get() SQL function will be used afterwards to ** retrieve the information gathered. ** ** This SQL function usually returns NULL, but might return an integer ** if it wants the byte-code to do special processing. ** ** The R parameter is only used for STAT4 */ static void statPush( sqlite3_context *context, int argc, sqlite3_value **argv ){ int i; /* The three function arguments */ StatAccum *p = (StatAccum*)sqlite3_value_blob(argv[0]); int iChng = sqlite3_value_int(argv[1]); UNUSED_PARAMETER( argc ); UNUSED_PARAMETER( context ); assert( p->nCol>0 ); assert( iChng<p->nCol ); if( p->nRow==0 ){ /* This is the first call to this function. Do initialization. */ for(i=0; i<p->nCol; i++) p->current.anEq[i] = 1; }else{ /* Second and subsequent calls get processed here */ #ifdef SQLITE_ENABLE_STAT4 if( p->mxSample ) samplePushPrevious(p, iChng); #endif /* Update anDLt[], anLt[] and anEq[] to reflect the values that apply ** to the current row of the index. */ for(i=0; i<iChng; i++){ p->current.anEq[i]++; } for(i=iChng; i<p->nCol; i++){ p->current.anDLt[i]++; #ifdef SQLITE_ENABLE_STAT4 if( p->mxSample ) p->current.anLt[i] += p->current.anEq[i]; #endif p->current.anEq[i] = 1; } } p->nRow++; #ifdef SQLITE_ENABLE_STAT4 if( p->mxSample ){ tRowcnt nLt; if( sqlite3_value_type(argv[2])==SQLITE_INTEGER ){ sampleSetRowidInt64(p->db, &p->current, sqlite3_value_int64(argv[2])); }else{ sampleSetRowid(p->db, &p->current, sqlite3_value_bytes(argv[2]), sqlite3_value_blob(argv[2])); } p->current.iHash = p->iPrn = p->iPrn*1103515245 + 12345; nLt = p->current.anLt[p->nCol-1]; /* Check if this is to be a periodic sample. If so, add it. */ if( (nLt/p->nPSample)!=(nLt+1)/p->nPSample ){ p->current.isPSample = 1; p->current.iCol = 0; sampleInsert(p, &p->current, p->nCol-1); p->current.isPSample = 0; } /* Update the aBest[] array. */ for(i=0; i<(p->nCol-1); i++){ p->current.iCol = i; if( i>=iChng || sampleIsBetterPost(p, &p->current, &p->aBest[i]) ){ sampleCopy(p, &p->aBest[i], &p->current); } } }else #endif if( p->nLimit && p->nRow>(tRowcnt)p->nLimit*(p->nSkipAhead+1) ){ p->nSkipAhead++; sqlite3_result_int(context, p->current.anDLt[0]>0); } } static const FuncDef statPushFuncdef = { 2+IsStat4, /* nArg */ SQLITE_UTF8, /* funcFlags */ 0, /* pUserData */ 0, /* pNext */ statPush, /* xSFunc */ 0, /* xFinalize */ 0, 0, /* xValue, xInverse */ "stat_push", /* zName */ {0} }; #define STAT_GET_STAT1 0 /* "stat" column of stat1 table */ #define STAT_GET_ROWID 1 /* "rowid" column of stat[34] entry */ #define STAT_GET_NEQ 2 /* "neq" column of stat[34] entry */ #define STAT_GET_NLT 3 /* "nlt" column of stat[34] entry */ #define STAT_GET_NDLT 4 /* "ndlt" column of stat[34] entry */ /* ** Implementation of the stat_get(P,J) SQL function. This routine is ** used to query statistical information that has been gathered into ** the StatAccum object by prior calls to stat_push(). The P parameter ** has type BLOB but it is really just a pointer to the StatAccum object. ** The content to returned is determined by the parameter J ** which is one of the STAT_GET_xxxx values defined above. ** ** The stat_get(P,J) function is not available to generic SQL. It is ** inserted as part of a manually constructed bytecode program. (See ** the callStatGet() routine below.) It is guaranteed that the P ** parameter will always be a pointer to a StatAccum object, never a ** NULL. ** ** If STAT4 is not enabled, then J is always ** STAT_GET_STAT1 and is hence omitted and this routine becomes ** a one-parameter function, stat_get(P), that always returns the ** stat1 table entry information. */ static void statGet( sqlite3_context *context, int argc, sqlite3_value **argv ){ StatAccum *p = (StatAccum*)sqlite3_value_blob(argv[0]); #ifdef SQLITE_ENABLE_STAT4 /* STAT4 has a parameter on this routine. */ int eCall = sqlite3_value_int(argv[1]); assert( argc==2 ); assert( eCall==STAT_GET_STAT1 || eCall==STAT_GET_NEQ || eCall==STAT_GET_ROWID || eCall==STAT_GET_NLT || eCall==STAT_GET_NDLT ); assert( eCall==STAT_GET_STAT1 || p->mxSample ); if( eCall==STAT_GET_STAT1 ) #else assert( argc==1 ); #endif { /* Return the value to store in the "stat" column of the sqlite_stat1 ** table for this index. ** ** The value is a string composed of a list of integers describing ** the index. The first integer in the list is the total number of ** entries in the index. There is one additional integer in the list ** for each indexed column. This additional integer is an estimate of ** the number of rows matched by a equality query on the index using ** a key with the corresponding number of fields. In other words, ** if the index is on columns (a,b) and the sqlite_stat1 value is ** "100 10 2", then SQLite estimates that: ** ** * the index contains 100 rows, ** * "WHERE a=?" matches 10 rows, and ** * "WHERE a=? AND b=?" matches 2 rows. ** ** If D is the count of distinct values and K is the total number of ** rows, then each estimate is computed as: ** ** I = (K+D-1)/D */ sqlite3_str sStat; /* Text of the constructed "stat" line */ int i; /* Loop counter */ sqlite3StrAccumInit(&sStat, 0, 0, 0, (p->nKeyCol+1)*100); sqlite3_str_appendf(&sStat, "%llu", p->nSkipAhead ? (u64)p->nEst : (u64)p->nRow); for(i=0; i<p->nKeyCol; i++){ u64 nDistinct = p->current.anDLt[i] + 1; u64 iVal = (p->nRow + nDistinct - 1) / nDistinct; sqlite3_str_appendf(&sStat, " %llu", iVal); assert( p->current.anEq[i] ); } sqlite3ResultStrAccum(context, &sStat); } #ifdef SQLITE_ENABLE_STAT4 else if( eCall==STAT_GET_ROWID ){ if( p->iGet<0 ){ samplePushPrevious(p, 0); p->iGet = 0; } if( p->iGet<p->nSample ){ StatSample *pS = p->a + p->iGet; if( pS->nRowid==0 ){ sqlite3_result_int64(context, pS->u.iRowid); }else{ sqlite3_result_blob(context, pS->u.aRowid, pS->nRowid, SQLITE_TRANSIENT); } } }else{ tRowcnt *aCnt = 0; sqlite3_str sStat; int i; assert( p->iGet<p->nSample ); switch( eCall ){ case STAT_GET_NEQ: aCnt = p->a[p->iGet].anEq; break; case STAT_GET_NLT: aCnt = p->a[p->iGet].anLt; break; default: { aCnt = p->a[p->iGet].anDLt; p->iGet++; break; } } sqlite3StrAccumInit(&sStat, 0, 0, 0, p->nCol*100); for(i=0; i<p->nCol; i++){ sqlite3_str_appendf(&sStat, "%llu ", (u64)aCnt[i]); } if( sStat.nChar ) sStat.nChar--; sqlite3ResultStrAccum(context, &sStat); } #endif /* SQLITE_ENABLE_STAT4 */ #ifndef SQLITE_DEBUG UNUSED_PARAMETER( argc ); #endif } static const FuncDef statGetFuncdef = { 1+IsStat4, /* nArg */ SQLITE_UTF8, /* funcFlags */ 0, /* pUserData */ 0, /* pNext */ statGet, /* xSFunc */ 0, /* xFinalize */ 0, 0, /* xValue, xInverse */ "stat_get", /* zName */ {0} }; static void callStatGet(Parse *pParse, int regStat, int iParam, int regOut){ #ifdef SQLITE_ENABLE_STAT4 sqlite3VdbeAddOp2(pParse->pVdbe, OP_Integer, iParam, regStat+1); #elif SQLITE_DEBUG assert( iParam==STAT_GET_STAT1 ); #else UNUSED_PARAMETER( iParam ); #endif assert( regOut!=regStat && regOut!=regStat+1 ); sqlite3VdbeAddFunctionCall(pParse, 0, regStat, regOut, 1+IsStat4, &statGetFuncdef, 0); } #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS /* Add a comment to the most recent VDBE opcode that is the name ** of the k-th column of the pIdx index. */ static void analyzeVdbeCommentIndexWithColumnName( Vdbe *v, /* Prepared statement under construction */ Index *pIdx, /* Index whose column is being loaded */ int k /* Which column index */ ){ int i; /* Index of column in the table */ assert( k>=0 && k<pIdx->nColumn ); i = pIdx->aiColumn[k]; if( NEVER(i==XN_ROWID) ){ VdbeComment((v,"%s.rowid",pIdx->zName)); }else if( i==XN_EXPR ){ VdbeComment((v,"%s.expr(%d)",pIdx->zName, k)); }else{ VdbeComment((v,"%s.%s", pIdx->zName, pIdx->pTable->aCol[i].zCnName)); } } #else # define analyzeVdbeCommentIndexWithColumnName(a,b,c) #endif /* SQLITE_DEBUG */ /* ** Generate code to do an analysis of all indices associated with ** a single table. */ static void analyzeOneTable( Parse *pParse, /* Parser context */ |
︙ | ︙ | |||
991 992 993 994 995 996 997 | int iTabCur; /* Table cursor */ Vdbe *v; /* The virtual machine being built up */ int i; /* Loop counter */ int jZeroRows = -1; /* Jump from here if number of rows is zero */ int iDb; /* Index of database containing pTab */ u8 needTableCnt = 1; /* True to count the table */ int regNewRowid = iMem++; /* Rowid for the inserted record */ | | < < > | | 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 | int iTabCur; /* Table cursor */ Vdbe *v; /* The virtual machine being built up */ int i; /* Loop counter */ int jZeroRows = -1; /* Jump from here if number of rows is zero */ int iDb; /* Index of database containing pTab */ u8 needTableCnt = 1; /* True to count the table */ int regNewRowid = iMem++; /* Rowid for the inserted record */ int regStat = iMem++; /* Register to hold StatAccum object */ int regChng = iMem++; /* Index of changed index field */ int regRowid = iMem++; /* Rowid argument passed to stat_push() */ int regTemp = iMem++; /* Temporary use register */ int regTemp2 = iMem++; /* Second temporary use register */ int regTabname = iMem++; /* Register containing table name */ int regIdxname = iMem++; /* Register containing index name */ int regStat1 = iMem++; /* Value for the stat column of sqlite_stat1 */ int regPrev = iMem; /* MUST BE LAST (see below) */ #ifdef SQLITE_ENABLE_PREUPDATE_HOOK Table *pStat1 = 0; #endif pParse->nMem = MAX(pParse->nMem, iMem); v = sqlite3GetVdbe(pParse); if( v==0 || NEVER(pTab==0) ){ return; } if( !IsOrdinaryTable(pTab) ){ /* Do not gather statistics on views or virtual tables */ return; } if( sqlite3_strlike("sqlite\\_%", pTab->zName, '\\')==0 ){ /* Do not gather statistics on system tables */ return; } |
︙ | ︙ | |||
1124 1125 1126 1127 1128 1129 1130 | VdbeComment((v, "%s", pIdx->zName)); /* Invoke the stat_init() function. The arguments are: ** ** (1) the number of columns in the index including the rowid ** (or for a WITHOUT ROWID table, the number of PK columns), ** (2) the number of columns in the key without the rowid/pk | | < < < > > > | > | > > > > | > > > > | | | < < < | | 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 | VdbeComment((v, "%s", pIdx->zName)); /* Invoke the stat_init() function. The arguments are: ** ** (1) the number of columns in the index including the rowid ** (or for a WITHOUT ROWID table, the number of PK columns), ** (2) the number of columns in the key without the rowid/pk ** (3) estimated number of rows in the index, */ sqlite3VdbeAddOp2(v, OP_Integer, nCol, regStat+1); assert( regRowid==regStat+2 ); sqlite3VdbeAddOp2(v, OP_Integer, pIdx->nKeyCol, regRowid); #ifdef SQLITE_ENABLE_STAT4 if( OptimizationEnabled(db, SQLITE_Stat4) ){ sqlite3VdbeAddOp2(v, OP_Count, iIdxCur, regTemp); addrRewind = sqlite3VdbeAddOp1(v, OP_Rewind, iIdxCur); VdbeCoverage(v); }else #endif { addrRewind = sqlite3VdbeAddOp1(v, OP_Rewind, iIdxCur); VdbeCoverage(v); sqlite3VdbeAddOp3(v, OP_Count, iIdxCur, regTemp, 1); } assert( regTemp2==regStat+4 ); sqlite3VdbeAddOp2(v, OP_Integer, db->nAnalysisLimit, regTemp2); sqlite3VdbeAddFunctionCall(pParse, 0, regStat+1, regStat, 4, &statInitFuncdef, 0); /* Implementation of the following: ** ** Rewind csr ** if eof(csr) goto end_of_scan; ** regChng = 0 ** goto next_push_0; ** */ sqlite3VdbeAddOp2(v, OP_Integer, 0, regChng); addrNextRow = sqlite3VdbeCurrentAddr(v); if( nColTest>0 ){ int endDistinctTest = sqlite3VdbeMakeLabel(pParse); int *aGotoChng; /* Array of jump instruction addresses */ aGotoChng = sqlite3DbMallocRawNN(db, sizeof(int)*nColTest); if( aGotoChng==0 ) continue; /* ** next_row: ** regChng = 0 |
︙ | ︙ | |||
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 | sqlite3VdbeAddOp2(v, OP_NotNull, regPrev, endDistinctTest); VdbeCoverage(v); } for(i=0; i<nColTest; i++){ char *pColl = (char*)sqlite3LocateCollSeq(pParse, pIdx->azColl[i]); sqlite3VdbeAddOp2(v, OP_Integer, i, regChng); sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, i, regTemp); aGotoChng[i] = sqlite3VdbeAddOp4(v, OP_Ne, regTemp, 0, regPrev+i, pColl, P4_COLLSEQ); sqlite3VdbeChangeP5(v, SQLITE_NULLEQ); VdbeCoverage(v); } sqlite3VdbeAddOp2(v, OP_Integer, nColTest, regChng); sqlite3VdbeGoto(v, endDistinctTest); /* ** chng_addr_0: ** regPrev(0) = idx(0) ** chng_addr_1: ** regPrev(1) = idx(1) ** ... */ sqlite3VdbeJumpHere(v, addrNextRow-1); for(i=0; i<nColTest; i++){ sqlite3VdbeJumpHere(v, aGotoChng[i]); sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, i, regPrev+i); } sqlite3VdbeResolveLabel(v, endDistinctTest); sqlite3DbFree(db, aGotoChng); } /* ** chng_addr_N: | > > | | | > | | | | | | | | | | | | | | | | > | > | | > > > > > > | | > > > > > > | | | < > | | | | < < < < | | 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 | sqlite3VdbeAddOp2(v, OP_NotNull, regPrev, endDistinctTest); VdbeCoverage(v); } for(i=0; i<nColTest; i++){ char *pColl = (char*)sqlite3LocateCollSeq(pParse, pIdx->azColl[i]); sqlite3VdbeAddOp2(v, OP_Integer, i, regChng); sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, i, regTemp); analyzeVdbeCommentIndexWithColumnName(v,pIdx,i); aGotoChng[i] = sqlite3VdbeAddOp4(v, OP_Ne, regTemp, 0, regPrev+i, pColl, P4_COLLSEQ); sqlite3VdbeChangeP5(v, SQLITE_NULLEQ); VdbeCoverage(v); } sqlite3VdbeAddOp2(v, OP_Integer, nColTest, regChng); sqlite3VdbeGoto(v, endDistinctTest); /* ** chng_addr_0: ** regPrev(0) = idx(0) ** chng_addr_1: ** regPrev(1) = idx(1) ** ... */ sqlite3VdbeJumpHere(v, addrNextRow-1); for(i=0; i<nColTest; i++){ sqlite3VdbeJumpHere(v, aGotoChng[i]); sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, i, regPrev+i); analyzeVdbeCommentIndexWithColumnName(v,pIdx,i); } sqlite3VdbeResolveLabel(v, endDistinctTest); sqlite3DbFree(db, aGotoChng); } /* ** chng_addr_N: ** regRowid = idx(rowid) // STAT4 only ** stat_push(P, regChng, regRowid) // 3rd parameter STAT4 only ** Next csr ** if !eof(csr) goto next_row; */ #ifdef SQLITE_ENABLE_STAT4 if( OptimizationEnabled(db, SQLITE_Stat4) ){ assert( regRowid==(regStat+2) ); if( HasRowid(pTab) ){ sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdxCur, regRowid); }else{ Index *pPk = sqlite3PrimaryKeyIndex(pIdx->pTable); int j, k, regKey; regKey = sqlite3GetTempRange(pParse, pPk->nKeyCol); for(j=0; j<pPk->nKeyCol; j++){ k = sqlite3TableColumnToIndex(pIdx, pPk->aiColumn[j]); assert( k>=0 && k<pIdx->nColumn ); sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, k, regKey+j); analyzeVdbeCommentIndexWithColumnName(v,pIdx,k); } sqlite3VdbeAddOp3(v, OP_MakeRecord, regKey, pPk->nKeyCol, regRowid); sqlite3ReleaseTempRange(pParse, regKey, pPk->nKeyCol); } } #endif assert( regChng==(regStat+1) ); { sqlite3VdbeAddFunctionCall(pParse, 1, regStat, regTemp, 2+IsStat4, &statPushFuncdef, 0); if( db->nAnalysisLimit ){ int j1, j2, j3; j1 = sqlite3VdbeAddOp1(v, OP_IsNull, regTemp); VdbeCoverage(v); j2 = sqlite3VdbeAddOp1(v, OP_If, regTemp); VdbeCoverage(v); j3 = sqlite3VdbeAddOp4Int(v, OP_SeekGT, iIdxCur, 0, regPrev, 1); VdbeCoverage(v); sqlite3VdbeJumpHere(v, j1); sqlite3VdbeAddOp2(v, OP_Next, iIdxCur, addrNextRow); VdbeCoverage(v); sqlite3VdbeJumpHere(v, j2); sqlite3VdbeJumpHere(v, j3); }else{ sqlite3VdbeAddOp2(v, OP_Next, iIdxCur, addrNextRow); VdbeCoverage(v); } } /* Add the entry to the stat1 table. */ callStatGet(pParse, regStat, STAT_GET_STAT1, regStat1); assert( "BBB"[0]==SQLITE_AFF_TEXT ); sqlite3VdbeAddOp4(v, OP_MakeRecord, regTabname, 3, regTemp, "BBB", 0); sqlite3VdbeAddOp2(v, OP_NewRowid, iStatCur, regNewRowid); sqlite3VdbeAddOp3(v, OP_Insert, iStatCur, regTemp, regNewRowid); #ifdef SQLITE_ENABLE_PREUPDATE_HOOK sqlite3VdbeChangeP4(v, -1, (char*)pStat1, P4_TABLE); #endif sqlite3VdbeChangeP5(v, OPFLAG_APPEND); /* Add the entries to the stat4 table. */ #ifdef SQLITE_ENABLE_STAT4 if( OptimizationEnabled(db, SQLITE_Stat4) && db->nAnalysisLimit==0 ){ int regEq = regStat1; int regLt = regStat1+1; int regDLt = regStat1+2; int regSample = regStat1+3; int regCol = regStat1+4; int regSampleRowid = regCol + nCol; int addrNext; int addrIsNull; u8 seekOp = HasRowid(pTab) ? OP_NotExists : OP_NotFound; pParse->nMem = MAX(pParse->nMem, regCol+nCol); addrNext = sqlite3VdbeCurrentAddr(v); callStatGet(pParse, regStat, STAT_GET_ROWID, regSampleRowid); addrIsNull = sqlite3VdbeAddOp1(v, OP_IsNull, regSampleRowid); VdbeCoverage(v); callStatGet(pParse, regStat, STAT_GET_NEQ, regEq); callStatGet(pParse, regStat, STAT_GET_NLT, regLt); callStatGet(pParse, regStat, STAT_GET_NDLT, regDLt); sqlite3VdbeAddOp4Int(v, seekOp, iTabCur, addrNext, regSampleRowid, 0); VdbeCoverage(v); for(i=0; i<nCol; i++){ sqlite3ExprCodeLoadIndexColumn(pParse, pIdx, iTabCur, i, regCol+i); } sqlite3VdbeAddOp3(v, OP_MakeRecord, regCol, nCol, regSample); sqlite3VdbeAddOp3(v, OP_MakeRecord, regTabname, 6, regTemp); sqlite3VdbeAddOp2(v, OP_NewRowid, iStatCur+1, regNewRowid); sqlite3VdbeAddOp3(v, OP_Insert, iStatCur+1, regTemp, regNewRowid); sqlite3VdbeAddOp2(v, OP_Goto, 1, addrNext); /* P1==1 for end-of-loop */ sqlite3VdbeJumpHere(v, addrIsNull); } #endif /* SQLITE_ENABLE_STAT4 */ /* End of analysis */ sqlite3VdbeJumpHere(v, addrRewind); } /* Create a single sqlite_stat1 entry containing NULL as the index |
︙ | ︙ | |||
1460 1461 1462 1463 1464 1465 1466 | Index *pIndex /* Handle extra flags for this index, if not NULL */ ){ char *z = zIntArray; int c; int i; tRowcnt v; | | | | > > | | 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 | Index *pIndex /* Handle extra flags for this index, if not NULL */ ){ char *z = zIntArray; int c; int i; tRowcnt v; #ifdef SQLITE_ENABLE_STAT4 if( z==0 ) z = ""; #else assert( z!=0 ); #endif for(i=0; *z && i<nOut; i++){ v = 0; while( (c=z[0])>='0' && c<='9' ){ v = v*10 + c - '0'; z++; } #ifdef SQLITE_ENABLE_STAT4 if( aOut ) aOut[i] = v; if( aLog ) aLog[i] = sqlite3LogEst(v); #else assert( aOut==0 ); UNUSED_PARAMETER(aOut); assert( aLog!=0 ); aLog[i] = sqlite3LogEst(v); #endif if( *z==' ' ) z++; } #ifndef SQLITE_ENABLE_STAT4 assert( pIndex!=0 ); { #else if( pIndex ){ #endif pIndex->bUnordered = 0; pIndex->noSkipScan = 0; while( z[0] ){ if( sqlite3_strglob("unordered*", z)==0 ){ pIndex->bUnordered = 1; }else if( sqlite3_strglob("sz=[0-9]*", z)==0 ){ int sz = sqlite3Atoi(z+3); if( sz<2 ) sz = 2; pIndex->szIdxRow = sqlite3LogEst(sz); }else if( sqlite3_strglob("noskipscan*", z)==0 ){ pIndex->noSkipScan = 1; } #ifdef SQLITE_ENABLE_COSTMULT else if( sqlite3_strglob("costmult=[0-9]*",z)==0 ){ pIndex->pTable->costMult = sqlite3LogEst(sqlite3Atoi(z+9)); } |
︙ | ︙ | |||
1547 1548 1549 1550 1551 1552 1553 | pIndex = sqlite3FindIndex(pInfo->db, argv[1], pInfo->zDatabase); } z = argv[2]; if( pIndex ){ tRowcnt *aiRowEst = 0; int nCol = pIndex->nKeyCol+1; | | | 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 | pIndex = sqlite3FindIndex(pInfo->db, argv[1], pInfo->zDatabase); } z = argv[2]; if( pIndex ){ tRowcnt *aiRowEst = 0; int nCol = pIndex->nKeyCol+1; #ifdef SQLITE_ENABLE_STAT4 /* Index.aiRowEst may already be set here if there are duplicate ** sqlite_stat1 entries for this index. In that case just clobber ** the old data with the new instead of allocating a new array. */ if( pIndex->aiRowEst==0 ){ pIndex->aiRowEst = (tRowcnt*)sqlite3MallocZero(sizeof(tRowcnt) * nCol); if( pIndex->aiRowEst==0 ) sqlite3OomFault(pInfo->db); } |
︙ | ︙ | |||
1583 1584 1585 1586 1587 1588 1589 | } /* ** If the Index.aSample variable is not NULL, delete the aSample[] array ** and its contents. */ void sqlite3DeleteIndexSamples(sqlite3 *db, Index *pIdx){ | | | | | 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 | } /* ** If the Index.aSample variable is not NULL, delete the aSample[] array ** and its contents. */ void sqlite3DeleteIndexSamples(sqlite3 *db, Index *pIdx){ #ifdef SQLITE_ENABLE_STAT4 if( pIdx->aSample ){ int j; for(j=0; j<pIdx->nSample; j++){ IndexSample *p = &pIdx->aSample[j]; sqlite3DbFree(db, p->p); } sqlite3DbFree(db, pIdx->aSample); } if( db && db->pnBytesFreed==0 ){ pIdx->nSample = 0; pIdx->aSample = 0; } #else UNUSED_PARAMETER(db); UNUSED_PARAMETER(pIdx); #endif /* SQLITE_ENABLE_STAT4 */ } #ifdef SQLITE_ENABLE_STAT4 /* ** Populate the pIdx->aAvgEq[] array based on the samples currently ** stored in pIdx->aSample[]. */ static void initAvgEq(Index *pIdx){ if( pIdx ){ IndexSample *aSample = pIdx->aSample; |
︙ | ︙ | |||
1680 1681 1682 1683 1684 1685 1686 | Table *pTab = sqlite3FindTable(db, zName, zDb); if( pTab && !HasRowid(pTab) ) pIdx = sqlite3PrimaryKeyIndex(pTab); } return pIdx; } /* | | | < < | 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 | Table *pTab = sqlite3FindTable(db, zName, zDb); if( pTab && !HasRowid(pTab) ) pIdx = sqlite3PrimaryKeyIndex(pTab); } return pIdx; } /* ** Load the content from either the sqlite_stat4 ** into the relevant Index.aSample[] arrays. ** ** Arguments zSql1 and zSql2 must point to SQL statements that return ** data equivalent to the following: ** ** zSql1: SELECT idx,count(*) FROM %Q.sqlite_stat4 GROUP BY idx ** zSql2: SELECT idx,neq,nlt,ndlt,sample FROM %Q.sqlite_stat4 ** ** where %Q is replaced with the database name before the SQL is executed. */ static int loadStatTbl( sqlite3 *db, /* Database handle */ const char *zSql1, /* SQL statement 1 (see above) */ const char *zSql2, /* SQL statement 2 (see above) */ const char *zDb /* Database name (e.g. "main") */ ){ int rc; /* Result codes from subroutines */ sqlite3_stmt *pStmt = 0; /* An SQL statement being run */ char *zSql; /* Text of the SQL statement */ |
︙ | ︙ | |||
1728 1729 1730 1731 1732 1733 1734 | int i; /* Bytes of space required */ tRowcnt *pSpace; zIndex = (char *)sqlite3_column_text(pStmt, 0); if( zIndex==0 ) continue; nSample = sqlite3_column_int(pStmt, 1); pIdx = findIndexOrPrimaryKey(db, zIndex, zDb); | | < < | < | | | | | < > | 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 | int i; /* Bytes of space required */ tRowcnt *pSpace; zIndex = (char *)sqlite3_column_text(pStmt, 0); if( zIndex==0 ) continue; nSample = sqlite3_column_int(pStmt, 1); pIdx = findIndexOrPrimaryKey(db, zIndex, zDb); assert( pIdx==0 || pIdx->nSample==0 ); if( pIdx==0 ) continue; assert( !HasRowid(pIdx->pTable) || pIdx->nColumn==pIdx->nKeyCol+1 ); if( !HasRowid(pIdx->pTable) && IsPrimaryKeyIndex(pIdx) ){ nIdxCol = pIdx->nKeyCol; }else{ nIdxCol = pIdx->nColumn; } pIdx->nSampleCol = nIdxCol; nByte = sizeof(IndexSample) * nSample; nByte += sizeof(tRowcnt) * nIdxCol * 3 * nSample; nByte += nIdxCol * sizeof(tRowcnt); /* Space for Index.aAvgEq[] */ pIdx->aSample = sqlite3DbMallocZero(db, nByte); if( pIdx->aSample==0 ){ sqlite3_finalize(pStmt); return SQLITE_NOMEM_BKPT; } pSpace = (tRowcnt*)&pIdx->aSample[nSample]; pIdx->aAvgEq = pSpace; pSpace += nIdxCol; pIdx->pTable->tabFlags |= TF_HasStat4; for(i=0; i<nSample; i++){ pIdx->aSample[i].anEq = pSpace; pSpace += nIdxCol; pIdx->aSample[i].anLt = pSpace; pSpace += nIdxCol; pIdx->aSample[i].anDLt = pSpace; pSpace += nIdxCol; } assert( ((u8*)pSpace)-nByte==(u8*)(pIdx->aSample) ); } |
︙ | ︙ | |||
1780 1781 1782 1783 1784 1785 1786 | int nCol = 1; /* Number of columns in index */ zIndex = (char *)sqlite3_column_text(pStmt, 0); if( zIndex==0 ) continue; pIdx = findIndexOrPrimaryKey(db, zIndex, zDb); if( pIdx==0 ) continue; /* This next condition is true if data has already been loaded from | | < | 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 | int nCol = 1; /* Number of columns in index */ zIndex = (char *)sqlite3_column_text(pStmt, 0); if( zIndex==0 ) continue; pIdx = findIndexOrPrimaryKey(db, zIndex, zDb); if( pIdx==0 ) continue; /* This next condition is true if data has already been loaded from ** the sqlite_stat4 table. */ nCol = pIdx->nSampleCol; if( pIdx!=pPrevIdx ){ initAvgEq(pPrevIdx); pPrevIdx = pIdx; } pSample = &pIdx->aSample[pIdx->nSample]; decodeIntArray((char*)sqlite3_column_text(pStmt,1),nCol,pSample->anEq,0,0); decodeIntArray((char*)sqlite3_column_text(pStmt,2),nCol,pSample->anLt,0,0); |
︙ | ︙ | |||
1815 1816 1817 1818 1819 1820 1821 | } rc = sqlite3_finalize(pStmt); if( rc==SQLITE_OK ) initAvgEq(pPrevIdx); return rc; } /* | | > | > > | < < < < < < < < < | | | | | | > | | > > | | | | 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 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 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 | } rc = sqlite3_finalize(pStmt); if( rc==SQLITE_OK ) initAvgEq(pPrevIdx); return rc; } /* ** Load content from the sqlite_stat4 table into ** the Index.aSample[] arrays of all indices. */ static int loadStat4(sqlite3 *db, const char *zDb){ int rc = SQLITE_OK; /* Result codes from subroutines */ const Table *pStat4; assert( db->lookaside.bDisable ); if( (pStat4 = sqlite3FindTable(db, "sqlite_stat4", zDb))!=0 && IsOrdinaryTable(pStat4) ){ rc = loadStatTbl(db, "SELECT idx,count(*) FROM %Q.sqlite_stat4 GROUP BY idx", "SELECT idx,neq,nlt,ndlt,sample FROM %Q.sqlite_stat4", zDb ); } return rc; } #endif /* SQLITE_ENABLE_STAT4 */ /* ** Load the content of the sqlite_stat1 and sqlite_stat4 tables. The ** contents of sqlite_stat1 are used to populate the Index.aiRowEst[] ** arrays. The contents of sqlite_stat4 are used to populate the ** Index.aSample[] arrays. ** ** If the sqlite_stat1 table is not present in the database, SQLITE_ERROR ** is returned. In this case, even if SQLITE_ENABLE_STAT4 was defined ** during compilation and the sqlite_stat4 table is present, no data is ** read from it. ** ** If SQLITE_ENABLE_STAT4 was defined during compilation and the ** sqlite_stat4 table is not present in the database, SQLITE_ERROR is ** returned. However, in this case, data is read from the sqlite_stat1 ** table (if it is present) before returning. ** ** If an OOM error occurs, this function always sets db->mallocFailed. ** This means if the caller does not care about other errors, the return ** code may be ignored. */ int sqlite3AnalysisLoad(sqlite3 *db, int iDb){ analysisInfo sInfo; HashElem *i; char *zSql; int rc = SQLITE_OK; Schema *pSchema = db->aDb[iDb].pSchema; const Table *pStat1; assert( iDb>=0 && iDb<db->nDb ); assert( db->aDb[iDb].pBt!=0 ); /* Clear any prior statistics */ assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); for(i=sqliteHashFirst(&pSchema->tblHash); i; i=sqliteHashNext(i)){ Table *pTab = sqliteHashData(i); pTab->tabFlags &= ~TF_HasStat1; } for(i=sqliteHashFirst(&pSchema->idxHash); i; i=sqliteHashNext(i)){ Index *pIdx = sqliteHashData(i); pIdx->hasStat1 = 0; #ifdef SQLITE_ENABLE_STAT4 sqlite3DeleteIndexSamples(db, pIdx); pIdx->aSample = 0; #endif } /* Load new statistics out of the sqlite_stat1 table */ sInfo.db = db; sInfo.zDatabase = db->aDb[iDb].zDbSName; if( (pStat1 = sqlite3FindTable(db, "sqlite_stat1", sInfo.zDatabase)) && IsOrdinaryTable(pStat1) ){ zSql = sqlite3MPrintf(db, "SELECT tbl,idx,stat FROM %Q.sqlite_stat1", sInfo.zDatabase); if( zSql==0 ){ rc = SQLITE_NOMEM_BKPT; }else{ rc = sqlite3_exec(db, zSql, analysisLoader, &sInfo, 0); sqlite3DbFree(db, zSql); } } /* Set appropriate defaults on all indexes not in the sqlite_stat1 table */ assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); for(i=sqliteHashFirst(&pSchema->idxHash); i; i=sqliteHashNext(i)){ Index *pIdx = sqliteHashData(i); if( !pIdx->hasStat1 ) sqlite3DefaultRowEst(pIdx); } /* Load the statistics from the sqlite_stat4 table. */ #ifdef SQLITE_ENABLE_STAT4 if( rc==SQLITE_OK ){ DisableLookaside; rc = loadStat4(db, sInfo.zDatabase); EnableLookaside; } for(i=sqliteHashFirst(&pSchema->idxHash); i; i=sqliteHashNext(i)){ Index *pIdx = sqliteHashData(i); sqlite3_free(pIdx->aiRowEst); pIdx->aiRowEst = 0; } #endif |
︙ | ︙ |
Changes to src/attach.c.
︙ | ︙ | |||
40 41 42 43 44 45 46 47 48 49 50 51 52 53 | rc = sqlite3ResolveExprNames(pName, pExpr); }else{ pExpr->op = TK_STRING; } } return rc; } /* ** An SQL user-function registered to do the work of an ATTACH statement. The ** three arguments to the function come directly from an attach statement: ** ** ATTACH DATABASE x AS y KEY z ** | > > > > > > > > > > > | 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 | rc = sqlite3ResolveExprNames(pName, pExpr); }else{ pExpr->op = TK_STRING; } } return rc; } /* ** Return true if zName points to a name that may be used to refer to ** database iDb attached to handle db. */ int sqlite3DbIsNamed(sqlite3 *db, int iDb, const char *zName){ return ( sqlite3StrICmp(db->aDb[iDb].zDbSName, zName)==0 || (iDb==0 && sqlite3StrICmp("main", zName)==0) ); } /* ** An SQL user-function registered to do the work of an ATTACH statement. The ** three arguments to the function come directly from an attach statement: ** ** ATTACH DATABASE x AS y KEY z ** |
︙ | ︙ | |||
80 81 82 83 84 85 86 | UNUSED_PARAMETER(NotUsed); zFile = (const char *)sqlite3_value_text(argv[0]); zName = (const char *)sqlite3_value_text(argv[1]); if( zFile==0 ) zFile = ""; if( zName==0 ) zName = ""; | | | 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 | UNUSED_PARAMETER(NotUsed); zFile = (const char *)sqlite3_value_text(argv[0]); zName = (const char *)sqlite3_value_text(argv[1]); if( zFile==0 ) zFile = ""; if( zName==0 ) zName = ""; #ifndef SQLITE_OMIT_DESERIALIZE # define REOPEN_AS_MEMDB(db) (db->init.reopenMemdb) #else # define REOPEN_AS_MEMDB(db) (0) #endif if( REOPEN_AS_MEMDB(db) ){ /* This is not a real ATTACH. Instead, this routine is being called |
︙ | ︙ | |||
113 114 115 116 117 118 119 | if( db->nDb>=db->aLimit[SQLITE_LIMIT_ATTACHED]+2 ){ zErrDyn = sqlite3MPrintf(db, "too many attached databases - max %d", db->aLimit[SQLITE_LIMIT_ATTACHED] ); goto attach_error; } for(i=0; i<db->nDb; i++){ | < | | | 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 | if( db->nDb>=db->aLimit[SQLITE_LIMIT_ATTACHED]+2 ){ zErrDyn = sqlite3MPrintf(db, "too many attached databases - max %d", db->aLimit[SQLITE_LIMIT_ATTACHED] ); goto attach_error; } for(i=0; i<db->nDb; i++){ assert( zName ); if( sqlite3DbIsNamed(db, i, zName) ){ 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. |
︙ | ︙ | |||
151 152 153 154 155 156 157 | sqlite3_result_error(context, zErr, -1); sqlite3_free(zErr); return; } assert( pVfs ); flags |= SQLITE_OPEN_MAIN_DB; rc = sqlite3BtreeOpen(pVfs, zPath, db, &pNew->pBt, 0, flags); | < > | 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 | sqlite3_result_error(context, zErr, -1); sqlite3_free(zErr); return; } assert( pVfs ); flags |= SQLITE_OPEN_MAIN_DB; rc = sqlite3BtreeOpen(pVfs, zPath, db, &pNew->pBt, 0, flags); db->nDb++; pNew->zDbSName = sqlite3DbStrDup(db, zName); } db->noSharedCache = 0; if( rc==SQLITE_CONSTRAINT ){ rc = SQLITE_ERROR; zErrDyn = sqlite3MPrintf(db, "database is already attached"); }else if( rc==SQLITE_OK ){ Pager *pPager; |
︙ | ︙ | |||
180 181 182 183 184 185 186 | #ifndef SQLITE_OMIT_PAGER_PRAGMAS sqlite3BtreeSetPagerFlags(pNew->pBt, PAGER_SYNCHRONOUS_FULL | (db->flags & PAGER_FLAGS_MASK)); #endif sqlite3BtreeLeave(pNew->pBt); } pNew->safety_level = SQLITE_DEFAULT_SYNCHRONOUS+1; | < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < > | > | | 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 | #ifndef SQLITE_OMIT_PAGER_PRAGMAS sqlite3BtreeSetPagerFlags(pNew->pBt, PAGER_SYNCHRONOUS_FULL | (db->flags & PAGER_FLAGS_MASK)); #endif sqlite3BtreeLeave(pNew->pBt); } pNew->safety_level = SQLITE_DEFAULT_SYNCHRONOUS+1; if( rc==SQLITE_OK && pNew->zDbSName==0 ){ rc = SQLITE_NOMEM_BKPT; } sqlite3_free_filename( zPath ); /* If the file was opened successfully, read the schema for the new database. ** If this fails, or if opening the file failed, then close the file and ** remove the entry from the db->aDb[] array. i.e. put everything back the ** way we found it. */ if( rc==SQLITE_OK ){ sqlite3BtreeEnterAll(db); db->init.iDb = 0; db->mDbFlags &= ~(DBFLAG_SchemaKnownOk); if( !REOPEN_AS_MEMDB(db) ){ rc = sqlite3Init(db, &zErrDyn); } sqlite3BtreeLeaveAll(db); assert( zErrDyn==0 || rc!=SQLITE_OK ); } #ifdef SQLITE_USER_AUTHENTICATION if( rc==SQLITE_OK && !REOPEN_AS_MEMDB(db) ){ u8 newAuth = 0; rc = sqlite3UserAuthCheckLogin(db, zName, &newAuth); if( newAuth<db->auth.authLevel ){ rc = SQLITE_AUTH_USER; } } #endif |
︙ | ︙ | |||
290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 | int NotUsed, sqlite3_value **argv ){ const char *zName = (const char *)sqlite3_value_text(argv[0]); sqlite3 *db = sqlite3_context_db_handle(context); int i; Db *pDb = 0; char zErr[128]; UNUSED_PARAMETER(NotUsed); if( zName==0 ) zName = ""; for(i=0; i<db->nDb; i++){ pDb = &db->aDb[i]; if( pDb->pBt==0 ) continue; | > | > | > > > > > > > > > > > > > | 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 | int NotUsed, sqlite3_value **argv ){ const char *zName = (const char *)sqlite3_value_text(argv[0]); sqlite3 *db = sqlite3_context_db_handle(context); int i; Db *pDb = 0; HashElem *pEntry; char zErr[128]; UNUSED_PARAMETER(NotUsed); if( zName==0 ) zName = ""; for(i=0; i<db->nDb; i++){ pDb = &db->aDb[i]; if( pDb->pBt==0 ) continue; if( sqlite3DbIsNamed(db, i, zName) ) break; } if( i>=db->nDb ){ sqlite3_snprintf(sizeof(zErr),zErr, "no such database: %s", zName); goto detach_error; } if( i<2 ){ sqlite3_snprintf(sizeof(zErr),zErr, "cannot detach database %s", zName); goto detach_error; } if( sqlite3BtreeTxnState(pDb->pBt)!=SQLITE_TXN_NONE || sqlite3BtreeIsInBackup(pDb->pBt) ){ sqlite3_snprintf(sizeof(zErr),zErr, "database %s is locked", zName); goto detach_error; } /* If any TEMP triggers reference the schema being detached, move those ** triggers to reference the TEMP schema itself. */ assert( db->aDb[1].pSchema ); pEntry = sqliteHashFirst(&db->aDb[1].pSchema->trigHash); while( pEntry ){ Trigger *pTrig = (Trigger*)sqliteHashData(pEntry); if( pTrig->pTabSchema==pDb->pSchema ){ pTrig->pTabSchema = pTrig->pSchema; } pEntry = sqliteHashNext(pEntry); } sqlite3BtreeClose(pDb->pBt); pDb->pBt = 0; pDb->pSchema = 0; sqlite3CollapseDatabaseArray(db); return; |
︙ | ︙ | |||
348 349 350 351 352 353 354 | int regArgs; if( pParse->nErr ) goto attach_end; memset(&sName, 0, sizeof(NameContext)); sName.pParse = pParse; if( | | | | > | < < | < | 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 | int regArgs; if( pParse->nErr ) goto attach_end; memset(&sName, 0, sizeof(NameContext)); sName.pParse = pParse; if( SQLITE_OK!=resolveAttachExpr(&sName, pFilename) || SQLITE_OK!=resolveAttachExpr(&sName, pDbname) || SQLITE_OK!=resolveAttachExpr(&sName, pKey) ){ goto attach_end; } #ifndef SQLITE_OMIT_AUTHORIZATION if( pAuthArg ){ char *zAuthArg; if( pAuthArg->op==TK_STRING ){ assert( !ExprHasProperty(pAuthArg, EP_IntValue) ); zAuthArg = pAuthArg->u.zToken; }else{ zAuthArg = 0; } rc = sqlite3AuthCheck(pParse, type, zAuthArg, 0, 0); if(rc!=SQLITE_OK ){ goto attach_end; } } #endif /* SQLITE_OMIT_AUTHORIZATION */ v = sqlite3GetVdbe(pParse); regArgs = sqlite3GetTempRange(pParse, 4); sqlite3ExprCode(pParse, pFilename, regArgs); sqlite3ExprCode(pParse, pDbname, regArgs+1); sqlite3ExprCode(pParse, pKey, regArgs+2); assert( v || db->mallocFailed ); if( v ){ sqlite3VdbeAddFunctionCall(pParse, 0, regArgs+3-pFunc->nArg, regArgs+3, pFunc->nArg, pFunc, 0); /* Code an OP_Expire. For an ATTACH statement, set P1 to true (expire this ** statement only). For DETACH, set it to false (expire all existing ** statements). */ sqlite3VdbeAddOp1(v, OP_Expire, (type==SQLITE_ATTACH)); } |
︙ | ︙ | |||
437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 | 0, 0, /* xValue, xInverse */ "sqlite_attach", /* zName */ {0} }; codeAttach(pParse, SQLITE_ATTACH, &attach_func, p, p, pDbname, pKey); } #endif /* SQLITE_OMIT_ATTACH */ /* ** Initialize a DbFixer structure. This routine must be called prior ** to passing the structure to one of the sqliteFixAAAA() routines below. */ void sqlite3FixInit( DbFixer *pFix, /* The fixer to be initialized */ Parse *pParse, /* Error messages will be written here */ int iDb, /* This is the database that must be used */ const char *zType, /* "view", "trigger", or "index" */ const Token *pName /* Name of the view, trigger, or index */ ){ | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | < < | > > > > > > > | | | | < | < < < | < < < | < < < < < < < < < | | < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < | < < > | > < > | > | | | | | | > > | 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 | 0, 0, /* xValue, xInverse */ "sqlite_attach", /* zName */ {0} }; codeAttach(pParse, SQLITE_ATTACH, &attach_func, p, p, pDbname, pKey); } #endif /* SQLITE_OMIT_ATTACH */ /* ** Expression callback used by sqlite3FixAAAA() routines. */ static int fixExprCb(Walker *p, Expr *pExpr){ DbFixer *pFix = p->u.pFix; if( !pFix->bTemp ) ExprSetProperty(pExpr, EP_FromDDL); if( pExpr->op==TK_VARIABLE ){ if( pFix->pParse->db->init.busy ){ pExpr->op = TK_NULL; }else{ sqlite3ErrorMsg(pFix->pParse, "%s cannot use variables", pFix->zType); return WRC_Abort; } } return WRC_Continue; } /* ** Select callback used by sqlite3FixAAAA() routines. */ static int fixSelectCb(Walker *p, Select *pSelect){ DbFixer *pFix = p->u.pFix; int i; SrcItem *pItem; sqlite3 *db = pFix->pParse->db; int iDb = sqlite3FindDbName(db, pFix->zDb); SrcList *pList = pSelect->pSrc; if( NEVER(pList==0) ) return WRC_Continue; for(i=0, pItem=pList->a; i<pList->nSrc; i++, pItem++){ if( pFix->bTemp==0 ){ if( pItem->zDatabase ){ if( iDb!=sqlite3FindDbName(db, pItem->zDatabase) ){ sqlite3ErrorMsg(pFix->pParse, "%s %T cannot reference objects in database %s", pFix->zType, pFix->pName, pItem->zDatabase); return WRC_Abort; } sqlite3DbFree(db, pItem->zDatabase); pItem->zDatabase = 0; pItem->fg.notCte = 1; } pItem->pSchema = pFix->pSchema; pItem->fg.fromDDL = 1; } #if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER) if( sqlite3WalkExpr(&pFix->w, pList->a[i].pOn) ) return WRC_Abort; #endif } if( pSelect->pWith ){ for(i=0; i<pSelect->pWith->nCte; i++){ if( sqlite3WalkSelect(p, pSelect->pWith->a[i].pSelect) ){ return WRC_Abort; } } } return WRC_Continue; } /* ** Initialize a DbFixer structure. This routine must be called prior ** to passing the structure to one of the sqliteFixAAAA() routines below. */ void sqlite3FixInit( DbFixer *pFix, /* The fixer to be initialized */ Parse *pParse, /* Error messages will be written here */ int iDb, /* This is the database that must be used */ const char *zType, /* "view", "trigger", or "index" */ const Token *pName /* Name of the view, trigger, or index */ ){ sqlite3 *db = pParse->db; assert( db->nDb>iDb ); pFix->pParse = pParse; pFix->zDb = db->aDb[iDb].zDbSName; pFix->pSchema = db->aDb[iDb].pSchema; pFix->zType = zType; pFix->pName = pName; pFix->bTemp = (iDb==1); pFix->w.pParse = pParse; pFix->w.xExprCallback = fixExprCb; pFix->w.xSelectCallback = fixSelectCb; pFix->w.xSelectCallback2 = sqlite3WalkWinDefnDummyCallback; pFix->w.walkerDepth = 0; pFix->w.eCode = 0; pFix->w.u.pFix = pFix; } /* ** The following set of routines walk through the parse tree and assign ** a specific database to all table references where the database name ** was left unspecified in the original SQL statement. The pFix structure ** must have been initialized by a prior call to sqlite3FixInit(). ** ** These routines are used to make sure that an index, trigger, or ** view in one database does not refer to objects in a different database. ** (Exception: indices, triggers, and views in the TEMP database are ** allowed to refer to anything.) If a reference is explicitly made ** to an object in a different database, an error message is added to ** pParse->zErrMsg and these routines return non-zero. If everything ** checks out, these routines return 0. */ int sqlite3FixSrcList( DbFixer *pFix, /* Context of the fixation */ SrcList *pList /* The Source list to check and modify */ ){ int res = 0; if( pList ){ Select s; memset(&s, 0, sizeof(s)); s.pSrc = pList; res = sqlite3WalkSelect(&pFix->w, &s); } return res; } #if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER) int sqlite3FixSelect( DbFixer *pFix, /* Context of the fixation */ Select *pSelect /* The SELECT statement to be fixed to one database */ ){ return sqlite3WalkSelect(&pFix->w, pSelect); } int sqlite3FixExpr( DbFixer *pFix, /* Context of the fixation */ Expr *pExpr /* The expression to be fixed to one database */ ){ return sqlite3WalkExpr(&pFix->w, pExpr); } #endif #ifndef SQLITE_OMIT_TRIGGER int sqlite3FixTriggerStep( DbFixer *pFix, /* Context of the fixation */ TriggerStep *pStep /* The trigger step be fixed to one database */ ){ while( pStep ){ if( sqlite3WalkSelect(&pFix->w, pStep->pSelect) || sqlite3WalkExpr(&pFix->w, pStep->pWhere) || sqlite3WalkExprList(&pFix->w, pStep->pExprList) || sqlite3FixSrcList(pFix, pStep->pFrom) ){ return 1; } #ifndef SQLITE_OMIT_UPSERT { Upsert *pUp; for(pUp=pStep->pUpsert; pUp; pUp=pUp->pNextUpsert){ if( sqlite3WalkExprList(&pFix->w, pUp->pUpsertTarget) || sqlite3WalkExpr(&pFix->w, pUp->pUpsertTargetWhere) || sqlite3WalkExprList(&pFix->w, pUp->pUpsertSet) || sqlite3WalkExpr(&pFix->w, pUp->pUpsertWhere) ){ return 1; } } } #endif pStep = pStep->pNext; } return 0; } #endif |
Changes to src/auth.c.
︙ | ︙ | |||
74 75 76 77 78 79 80 | ){ #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; #endif sqlite3_mutex_enter(db->mutex); db->xAuth = (sqlite3_xauth)xAuth; db->pAuthArg = pArg; | | | 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 | ){ #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; #endif sqlite3_mutex_enter(db->mutex); db->xAuth = (sqlite3_xauth)xAuth; db->pAuthArg = pArg; if( db->xAuth ) sqlite3ExpirePreparedStatements(db, 1); sqlite3_mutex_leave(db->mutex); return SQLITE_OK; } /* ** Write an error message into pParse->zErrMsg that explains that the ** user-supplied authorization function returned an illegal value. |
︙ | ︙ | |||
139 140 141 142 143 144 145 | */ void sqlite3AuthRead( Parse *pParse, /* The parser context */ Expr *pExpr, /* The expression to check authorization on */ Schema *pSchema, /* The schema of the expression */ SrcList *pTabList /* All table that pExpr might refer to */ ){ | < | | | | | | | | 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 | */ void sqlite3AuthRead( Parse *pParse, /* The parser context */ Expr *pExpr, /* The expression to check authorization on */ Schema *pSchema, /* The schema of the expression */ SrcList *pTabList /* All table that pExpr might refer to */ ){ Table *pTab = 0; /* The table being read */ const char *zCol; /* Name of the column of the table */ int iSrc; /* Index in pTabList->a[] of table being read */ int iDb; /* The index of the database the expression refers to */ int iCol; /* Index of column in table */ assert( pExpr->op==TK_COLUMN || pExpr->op==TK_TRIGGER ); assert( !IN_RENAME_OBJECT ); assert( pParse->db->xAuth!=0 ); iDb = sqlite3SchemaToIndex(pParse->db, pSchema); if( iDb<0 ){ /* An attempt to read a column out of a subquery or other ** temporary table. */ return; } if( pExpr->op==TK_TRIGGER ){ pTab = pParse->pTriggerTab; }else{ assert( pTabList ); for(iSrc=0; iSrc<pTabList->nSrc; iSrc++){ if( pExpr->iTable==pTabList->a[iSrc].iCursor ){ pTab = pTabList->a[iSrc].pTab; break; } } } iCol = pExpr->iColumn; if( pTab==0 ) return; if( iCol>=0 ){ assert( iCol<pTab->nCol ); zCol = pTab->aCol[iCol].zCnName; }else if( pTab->iPKey>=0 ){ assert( pTab->iPKey<pTab->nCol ); zCol = pTab->aCol[pTab->iPKey].zCnName; }else{ zCol = "ROWID"; } assert( iDb>=0 && iDb<pParse->db->nDb ); if( SQLITE_IGNORE==sqlite3AuthReadCol(pParse, pTab->zName, zCol, iDb) ){ pExpr->op = TK_NULL; } } /* ** Do an authorization check using the code and arguments given. Return |
︙ | ︙ | |||
205 206 207 208 209 210 211 | sqlite3 *db = pParse->db; int rc; /* Don't do any authorization checks if the database is initialising ** or if the parser is being invoked from within sqlite3_declare_vtab. */ assert( !IN_RENAME_OBJECT || db->xAuth==0 ); | < < < < | | 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 | sqlite3 *db = pParse->db; int rc; /* Don't do any authorization checks if the database is initialising ** or if the parser is being invoked from within sqlite3_declare_vtab. */ assert( !IN_RENAME_OBJECT || db->xAuth==0 ); if( db->xAuth==0 || db->init.busy || IN_SPECIAL_PARSE ){ return SQLITE_OK; } /* EVIDENCE-OF: R-43249-19882 The third through sixth parameters to the ** callback are either NULL pointers or zero-terminated strings that ** contain additional details about the action to be authorized. ** |
︙ | ︙ |
Changes to src/backup.c.
︙ | ︙ | |||
108 109 110 111 112 113 114 | /* ** Attempt to set the page size of the destination to match the page size ** of the source. */ static int setDestPgsz(sqlite3_backup *p){ int rc; | | | | 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 | /* ** Attempt to set the page size of the destination to match the page size ** of the source. */ static int setDestPgsz(sqlite3_backup *p){ int rc; rc = sqlite3BtreeSetPageSize(p->pDest,sqlite3BtreeGetPageSize(p->pSrc),0,0); return rc; } /* ** Check that there is no open read-transaction on the b-tree passed as the ** second argument. If there is not, return SQLITE_OK. Otherwise, if there ** is an open read-transaction, return SQLITE_ERROR and leave an error ** message in database handle db. */ static int checkReadTransaction(sqlite3 *db, Btree *p){ if( sqlite3BtreeTxnState(p)!=SQLITE_TXN_NONE ){ sqlite3ErrorWithMsg(db, SQLITE_ERROR, "destination database is in use"); return SQLITE_ERROR; } return SQLITE_OK; } /* |
︙ | ︙ | |||
231 232 233 234 235 236 237 | int bUpdate /* True for an update, false otherwise */ ){ Pager * const pDestPager = sqlite3BtreePager(p->pDest); const int nSrcPgsz = sqlite3BtreeGetPageSize(p->pSrc); int nDestPgsz = sqlite3BtreeGetPageSize(p->pDest); const int nCopy = MIN(nSrcPgsz, nDestPgsz); const i64 iEnd = (i64)iSrcPg*(i64)nSrcPgsz; | < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 | int bUpdate /* True for an update, false otherwise */ ){ Pager * const pDestPager = sqlite3BtreePager(p->pDest); const int nSrcPgsz = sqlite3BtreeGetPageSize(p->pSrc); int nDestPgsz = sqlite3BtreeGetPageSize(p->pDest); const int nCopy = MIN(nSrcPgsz, nDestPgsz); const i64 iEnd = (i64)iSrcPg*(i64)nSrcPgsz; int rc = SQLITE_OK; i64 iOff; assert( sqlite3BtreeGetReserveNoMutex(p->pSrc)>=0 ); assert( p->bDestLocked ); assert( !isFatalError(p->rc) ); assert( iSrcPg!=PENDING_BYTE_PAGE(p->pSrc->pBt) ); assert( zSrcData ); /* Catch the case where the destination is an in-memory database and the ** page sizes of the source and destination differ. */ if( nSrcPgsz!=nDestPgsz && sqlite3PagerIsMemdb(pDestPager) ){ rc = SQLITE_READONLY; } /* This loop runs once for each destination page spanned by the source ** page. For each iteration, variable iOff is set to the byte offset ** of the destination page. */ for(iOff=iEnd-(i64)nSrcPgsz; rc==SQLITE_OK && iOff<iEnd; iOff+=nDestPgsz){ DbPage *pDestPg = 0; Pgno iDest = (Pgno)(iOff/nDestPgsz)+1; |
︙ | ︙ | |||
377 378 379 380 381 382 383 | rc = SQLITE_OK; } /* If there is no open read-transaction on the source database, open ** one now. If a transaction is opened here, then it will be closed ** before this function exits. */ | | | 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 | rc = SQLITE_OK; } /* If there is no open read-transaction on the source database, open ** one now. If a transaction is opened here, then it will be closed ** before this function exits. */ if( rc==SQLITE_OK && SQLITE_TXN_NONE==sqlite3BtreeTxnState(p->pSrc) ){ rc = sqlite3BtreeBeginTrans(p->pSrc, 0, 0); bCloseTrans = 1; } /* If the destination database has not yet been locked (i.e. if this ** is the first call to backup_step() for the current backup operation), ** try to set its page size to the same as the source database. This |
︙ | ︙ | |||
615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 | /* Detach this backup from the source pager. */ if( p->pDestDb ){ p->pSrc->nBackup--; } if( p->isAttached ){ pp = sqlite3PagerBackupPtr(sqlite3BtreePager(p->pSrc)); while( *pp!=p ){ pp = &(*pp)->pNext; } *pp = p->pNext; } /* If a transaction is still open on the Btree, roll it back. */ sqlite3BtreeRollback(p->pDest, SQLITE_OK, 0); | > > | 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 | /* Detach this backup from the source pager. */ if( p->pDestDb ){ p->pSrc->nBackup--; } if( p->isAttached ){ pp = sqlite3PagerBackupPtr(sqlite3BtreePager(p->pSrc)); assert( pp!=0 ); while( *pp!=p ){ pp = &(*pp)->pNext; assert( pp!=0 ); } *pp = p->pNext; } /* If a transaction is still open on the Btree, roll it back. */ sqlite3BtreeRollback(p->pDest, SQLITE_OK, 0); |
︙ | ︙ | |||
747 748 749 750 751 752 753 | int sqlite3BtreeCopyFile(Btree *pTo, Btree *pFrom){ int rc; sqlite3_file *pFd; /* File descriptor for database pTo */ sqlite3_backup b; sqlite3BtreeEnter(pTo); sqlite3BtreeEnter(pFrom); | | < < < < | | 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 | int sqlite3BtreeCopyFile(Btree *pTo, Btree *pFrom){ int rc; sqlite3_file *pFd; /* File descriptor for database pTo */ sqlite3_backup b; sqlite3BtreeEnter(pTo); sqlite3BtreeEnter(pFrom); assert( sqlite3BtreeTxnState(pTo)==SQLITE_TXN_WRITE ); pFd = sqlite3PagerFile(sqlite3BtreePager(pTo)); if( pFd->pMethods ){ i64 nByte = sqlite3BtreeGetPageSize(pFrom)*(i64)sqlite3BtreeLastPage(pFrom); rc = sqlite3OsFileControl(pFd, SQLITE_FCNTL_OVERWRITE, &nByte); if( rc==SQLITE_NOTFOUND ) rc = SQLITE_OK; if( rc ) goto copy_finished; } /* Set up an sqlite3_backup object. sqlite3_backup.pDestDb must be set ** to 0. This is used by the implementations of sqlite3_backup_step() ** and sqlite3_backup_finish() to detect that they are being called ** from this function, not directly by the user. */ memset(&b, 0, sizeof(b)); b.pSrcDb = pFrom->db; b.pSrc = pFrom; b.pDest = pTo; b.iNext = 1; /* 0x7FFFFFFF is the hard limit for the number of pages in a database ** file. By passing this as the number of pages to copy to ** sqlite3_backup_step(), we can guarantee that the copy finishes ** within a single call (unless an error occurs). The assert() statement ** checks this assumption - (p->rc) should be set to either SQLITE_DONE ** or an error code. */ sqlite3_backup_step(&b, 0x7FFFFFFF); assert( b.rc!=SQLITE_OK ); rc = sqlite3_backup_finish(&b); if( rc==SQLITE_OK ){ pTo->pBt->btsFlags &= ~BTS_PAGESIZE_FIXED; }else{ sqlite3PagerClearCache(sqlite3BtreePager(b.pDest)); } assert( sqlite3BtreeTxnState(pTo)!=SQLITE_TXN_WRITE ); copy_finished: sqlite3BtreeLeave(pFrom); sqlite3BtreeLeave(pTo); return rc; } #endif /* SQLITE_OMIT_VACUUM */ |
Changes to src/bitvec.c.
︙ | ︙ | |||
355 356 357 358 359 360 361 | if( pBitvec==0 || pV==0 || pTmpSpace==0 ) goto bitvec_end; /* NULL pBitvec tests */ sqlite3BitvecSet(0, 1); sqlite3BitvecClear(0, 1, pTmpSpace); /* Run the program */ | | | 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 | if( pBitvec==0 || pV==0 || pTmpSpace==0 ) goto bitvec_end; /* NULL pBitvec tests */ sqlite3BitvecSet(0, 1); sqlite3BitvecClear(0, 1, pTmpSpace); /* Run the program */ pc = i = 0; while( (op = aOp[pc])!=0 ){ switch( op ){ case 1: case 2: case 5: { nx = 4; i = aOp[pc+2] - 1; |
︙ | ︙ |
Changes to src/btree.c.
︙ | ︙ | |||
65 66 67 68 69 70 71 | #ifndef SQLITE_OMIT_SHARED_CACHE /* ** A list of BtShared objects that are eligible for participation ** in shared cache. This variable has file scope during normal builds, ** but the test harness needs to access it so we make it global for ** test builds. ** | | | 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 | #ifndef SQLITE_OMIT_SHARED_CACHE /* ** A list of BtShared objects that are eligible for participation ** in shared cache. This variable has file scope during normal builds, ** but the test harness needs to access it so we make it global for ** test builds. ** ** Access to this variable is protected by SQLITE_MUTEX_STATIC_MAIN. */ #ifdef SQLITE_TEST BtShared *SQLITE_WSD sqlite3SharedCacheList = 0; #else static BtShared *SQLITE_WSD sqlite3SharedCacheList = 0; #endif #endif /* SQLITE_OMIT_SHARED_CACHE */ |
︙ | ︙ | |||
107 108 109 110 111 112 113 114 115 116 117 118 119 120 | #define querySharedCacheTableLock(a,b,c) SQLITE_OK #define setSharedCacheTableLock(a,b,c) SQLITE_OK #define clearAllSharedCacheTableLocks(a) #define downgradeAllSharedCacheTableLocks(a) #define hasSharedCacheTableLock(a,b,c,d) 1 #define hasReadConflicts(a, b) 0 #endif /* ** Implementation of the SQLITE_CORRUPT_PAGE() macro. Takes a single ** (MemPage*) as an argument. The (MemPage*) must not be NULL. ** ** If SQLITE_DEBUG is not defined, then this macro is equivalent to ** SQLITE_CORRUPT_BKPT. Or, if SQLITE_DEBUG is set, then the log message | > > > > > > > > > > > | 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 | #define querySharedCacheTableLock(a,b,c) SQLITE_OK #define setSharedCacheTableLock(a,b,c) SQLITE_OK #define clearAllSharedCacheTableLocks(a) #define downgradeAllSharedCacheTableLocks(a) #define hasSharedCacheTableLock(a,b,c,d) 1 #define hasReadConflicts(a, b) 0 #endif #ifdef SQLITE_DEBUG /* ** Return and reset the seek counter for a Btree object. */ sqlite3_uint64 sqlite3BtreeSeekCount(Btree *pBt){ u64 n = pBt->nSeek; pBt->nSeek = 0; return n; } #endif /* ** Implementation of the SQLITE_CORRUPT_PAGE() macro. Takes a single ** (MemPage*) as an argument. The (MemPage*) must not be NULL. ** ** If SQLITE_DEBUG is not defined, then this macro is equivalent to ** SQLITE_CORRUPT_BKPT. Or, if SQLITE_DEBUG is set, then the log message |
︙ | ︙ | |||
196 197 198 199 200 201 202 203 204 205 | /* Figure out the root-page that the lock should be held on. For table ** b-trees, this is just the root page of the b-tree being read or ** written. For index b-trees, it is the root page of the associated ** table. */ if( isIndex ){ HashElem *p; for(p=sqliteHashFirst(&pSchema->idxHash); p; p=sqliteHashNext(p)){ Index *pIdx = (Index *)sqliteHashData(p); if( pIdx->tnum==(int)iRoot ){ | > | > | 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 | /* Figure out the root-page that the lock should be held on. For table ** b-trees, this is just the root page of the b-tree being read or ** written. For index b-trees, it is the root page of the associated ** table. */ if( isIndex ){ HashElem *p; int bSeen = 0; for(p=sqliteHashFirst(&pSchema->idxHash); p; p=sqliteHashNext(p)){ Index *pIdx = (Index *)sqliteHashData(p); if( pIdx->tnum==(int)iRoot ){ if( bSeen ){ /* Two or more indexes share the same root page. There must ** be imposter tables. So just return true. The assert is not ** useful in that case. */ return 1; } iTab = pIdx->pTable->tnum; bSeen = 1; } } }else{ iTab = iRoot; } /* Search for the required lock. Either a write-lock on root-page iTab, a |
︙ | ︙ | |||
351 352 353 354 355 356 357 | assert( sqlite3BtreeHoldsMutex(p) ); assert( eLock==READ_LOCK || eLock==WRITE_LOCK ); assert( p->db!=0 ); /* A connection with the read-uncommitted flag set will never try to ** obtain a read-lock using this function. The only read-lock obtained | | | 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 | assert( sqlite3BtreeHoldsMutex(p) ); assert( eLock==READ_LOCK || eLock==WRITE_LOCK ); assert( p->db!=0 ); /* A connection with the read-uncommitted flag set will never try to ** obtain a read-lock using this function. The only read-lock obtained ** by a connection in read-uncommitted mode is on the sqlite_schema ** table, and that lock is obtained in BtreeBeginTrans(). */ assert( 0==(p->db->flags&SQLITE_ReadUncommit) || eLock==WRITE_LOCK ); /* This function should only be called on a sharable b-tree after it ** has been determined that no other b-tree holds a conflicting lock. */ assert( p->sharable ); assert( SQLITE_OK==querySharedCacheTableLock(p, iTable, eLock) ); |
︙ | ︙ | |||
763 764 765 766 767 768 769 | static void invalidateIncrblobCursors( Btree *pBtree, /* The database file to check */ Pgno pgnoRoot, /* The table that might be changing */ i64 iRow, /* The rowid that might be changing */ int isClearTable /* True if all rows are being deleted */ ){ BtCursor *p; | | | 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 | static void invalidateIncrblobCursors( Btree *pBtree, /* The database file to check */ Pgno pgnoRoot, /* The table that might be changing */ i64 iRow, /* The rowid that might be changing */ int isClearTable /* True if all rows are being deleted */ ){ BtCursor *p; assert( pBtree->hasIncrblobCur ); assert( sqlite3BtreeHoldsMutex(pBtree) ); pBtree->hasIncrblobCur = 0; for(p=pBtree->pBt->pCursor; p; p=p->pNext){ if( (p->curFlags & BTCF_Incrblob)!=0 ){ pBtree->hasIncrblobCur = 1; if( p->pgnoRoot==pgnoRoot && (isClearTable || p->info.nKey==iRow) ){ p->eState = CURSOR_INVALID; |
︙ | ︙ | |||
840 841 842 843 844 845 846 | ** ** This function is called when a free-list leaf page is removed from the ** free-list for reuse. It returns false if it is safe to retrieve the ** page from the pager layer with the 'no-content' flag set. True otherwise. */ static int btreeGetHasContent(BtShared *pBt, Pgno pgno){ Bitvec *p = pBt->pHasContent; | | | 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 | ** ** This function is called when a free-list leaf page is removed from the ** free-list for reuse. It returns false if it is safe to retrieve the ** page from the pager layer with the 'no-content' flag set. True otherwise. */ static int btreeGetHasContent(BtShared *pBt, Pgno pgno){ Bitvec *p = pBt->pHasContent; return p && (pgno>sqlite3BitvecSize(p) || sqlite3BitvecTestNotNull(p, pgno)); } /* ** Clear (destroy) the BtShared.pHasContent bitvec. This should be ** invoked at the conclusion of each write-transaction. */ static void btreeClearHasContent(BtShared *pBt){ |
︙ | ︙ | |||
901 902 903 904 905 906 907 908 909 910 911 912 913 914 | ** below. */ void *pKey; pCur->nKey = sqlite3BtreePayloadSize(pCur); pKey = sqlite3Malloc( pCur->nKey + 9 + 8 ); if( pKey ){ rc = sqlite3BtreePayload(pCur, 0, (int)pCur->nKey, pKey); if( rc==SQLITE_OK ){ pCur->pKey = pKey; }else{ sqlite3_free(pKey); } }else{ rc = SQLITE_NOMEM_BKPT; } | > | 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 | ** below. */ void *pKey; pCur->nKey = sqlite3BtreePayloadSize(pCur); pKey = sqlite3Malloc( pCur->nKey + 9 + 8 ); if( pKey ){ rc = sqlite3BtreePayload(pCur, 0, (int)pCur->nKey, pKey); if( rc==SQLITE_OK ){ memset(((u8*)pKey)+pCur->nKey, 0, 9+8); pCur->pKey = pKey; }else{ sqlite3_free(pKey); } }else{ rc = SQLITE_NOMEM_BKPT; } |
︙ | ︙ | |||
927 928 929 930 931 932 933 934 935 936 937 938 939 940 | static int saveCursorPosition(BtCursor *pCur){ int rc; assert( CURSOR_VALID==pCur->eState || CURSOR_SKIPNEXT==pCur->eState ); assert( 0==pCur->pKey ); assert( cursorHoldsMutex(pCur) ); if( pCur->eState==CURSOR_SKIPNEXT ){ pCur->eState = CURSOR_VALID; }else{ pCur->skipNext = 0; } rc = saveCursorKey(pCur); | > > > | 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 | static int saveCursorPosition(BtCursor *pCur){ int rc; assert( CURSOR_VALID==pCur->eState || CURSOR_SKIPNEXT==pCur->eState ); assert( 0==pCur->pKey ); assert( cursorHoldsMutex(pCur) ); if( pCur->curFlags & BTCF_Pinned ){ return SQLITE_CONSTRAINT_PINNED; } if( pCur->eState==CURSOR_SKIPNEXT ){ pCur->eState = CURSOR_VALID; }else{ pCur->skipNext = 0; } rc = saveCursorKey(pCur); |
︙ | ︙ | |||
1032 1033 1034 1035 1036 1037 1038 1039 | int bias, /* Bias search to the high end */ int *pRes /* Write search results here */ ){ int rc; /* Status code */ UnpackedRecord *pIdxKey; /* Unpacked index key */ if( pKey ){ assert( nKey==(i64)(int)nKey ); | > | | | > | > < | < < < | > > > | > | | 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 | int bias, /* Bias search to the high end */ int *pRes /* Write search results here */ ){ int rc; /* Status code */ UnpackedRecord *pIdxKey; /* Unpacked index key */ if( pKey ){ KeyInfo *pKeyInfo = pCur->pKeyInfo; assert( nKey==(i64)(int)nKey ); pIdxKey = sqlite3VdbeAllocUnpackedRecord(pKeyInfo); if( pIdxKey==0 ) return SQLITE_NOMEM_BKPT; sqlite3VdbeRecordUnpack(pKeyInfo, (int)nKey, pKey, pIdxKey); if( pIdxKey->nField==0 || pIdxKey->nField>pKeyInfo->nAllField ){ rc = SQLITE_CORRUPT_BKPT; }else{ rc = sqlite3BtreeIndexMoveto(pCur, pIdxKey, pRes); } sqlite3DbFree(pCur->pKeyInfo->db, pIdxKey); }else{ pIdxKey = 0; rc = sqlite3BtreeTableMoveto(pCur, nKey, bias, pRes); } return rc; } /* ** Restore the cursor to the position it was in (or as close to as possible) ** when saveCursorPosition() was called. Note that this call deletes the ** saved position info stored by saveCursorPosition(), so there can be ** at most one effective restoreCursorPosition() call after each ** saveCursorPosition(). */ static int btreeRestoreCursorPosition(BtCursor *pCur){ int rc; int skipNext = 0; assert( cursorOwnsBtShared(pCur) ); assert( pCur->eState>=CURSOR_REQUIRESEEK ); if( pCur->eState==CURSOR_FAULT ){ return pCur->skipNext; } pCur->eState = CURSOR_INVALID; if( sqlite3FaultSim(410) ){ rc = SQLITE_IOERR; }else{ rc = btreeMoveto(pCur, pCur->pKey, pCur->nKey, 0, &skipNext); } if( rc==SQLITE_OK ){ sqlite3_free(pCur->pKey); pCur->pKey = 0; assert( pCur->eState==CURSOR_VALID || pCur->eState==CURSOR_INVALID ); if( skipNext ) pCur->skipNext = skipNext; if( pCur->skipNext && pCur->eState==CURSOR_VALID ){ pCur->eState = CURSOR_SKIPNEXT; } } return rc; } |
︙ | ︙ | |||
1142 1143 1144 1145 1146 1147 1148 | if( rc ){ *pDifferentRow = 1; return rc; } if( pCur->eState!=CURSOR_VALID ){ *pDifferentRow = 1; }else{ | < | 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 | if( rc ){ *pDifferentRow = 1; return rc; } if( pCur->eState!=CURSOR_VALID ){ *pDifferentRow = 1; }else{ *pDifferentRow = 0; } return SQLITE_OK; } #ifdef SQLITE_ENABLE_CURSOR_HINTS /* |
︙ | ︙ | |||
1212 1213 1214 1215 1216 1217 1218 | Pgno iPtrmap; /* The pointer map page number */ int offset; /* Offset in pointer map page */ int rc; /* Return code from subfunctions */ if( *pRC ) return; assert( sqlite3_mutex_held(pBt->mutex) ); | | | 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 | Pgno iPtrmap; /* The pointer map page number */ int offset; /* Offset in pointer map page */ int rc; /* Return code from subfunctions */ if( *pRC ) return; assert( sqlite3_mutex_held(pBt->mutex) ); /* The super-journal page number must never be used as a pointer map page */ assert( 0==PTRMAP_ISPAGE(pBt, PENDING_BYTE_PAGE(pBt)) ); #ifndef SQLITE_OMIT_CONCURRENT if( pBt->pMap ){ *pRC = btreePtrmapStore(pBt, key, eType, parent); return; } |
︙ | ︙ | |||
1302 1303 1304 1305 1306 1307 1308 | if( *pEType<1 || *pEType>5 ) return SQLITE_CORRUPT_PGNO(iPtrmap); return SQLITE_OK; } #else /* if defined SQLITE_OMIT_AUTOVACUUM */ #define ptrmapPut(w,x,y,z,rc) #define ptrmapGet(w,x,y,z) SQLITE_OK | | | 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 | if( *pEType<1 || *pEType>5 ) return SQLITE_CORRUPT_PGNO(iPtrmap); return SQLITE_OK; } #else /* if defined SQLITE_OMIT_AUTOVACUUM */ #define ptrmapPut(w,x,y,z,rc) #define ptrmapGet(w,x,y,z) SQLITE_OK #define ptrmapPutOvflPtr(x, y, z, rc) #endif /* ** Given a btree page and a cell index (0 means the first cell on ** the page, 1 means the second cell, and so forth) return a pointer ** to the cell content. ** |
︙ | ︙ | |||
1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 | if( surplus <= maxLocal ){ pInfo->nLocal = (u16)surplus; }else{ pInfo->nLocal = (u16)minLocal; } pInfo->nSize = (u16)(&pInfo->pPayload[pInfo->nLocal] - pCell) + 4; } /* ** The following routines are implementations of the MemPage.xParseCell() ** method. ** ** Parse a cell content block and fill in the CellInfo structure. ** | > > > > > > > > > > > > > > > > > > | 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 | if( surplus <= maxLocal ){ pInfo->nLocal = (u16)surplus; }else{ pInfo->nLocal = (u16)minLocal; } pInfo->nSize = (u16)(&pInfo->pPayload[pInfo->nLocal] - pCell) + 4; } /* ** Given a record with nPayload bytes of payload stored within btree ** page pPage, return the number of bytes of payload stored locally. */ static int btreePayloadToLocal(MemPage *pPage, i64 nPayload){ int maxLocal; /* Maximum amount of payload held locally */ maxLocal = pPage->maxLocal; if( nPayload<=maxLocal ){ return nPayload; }else{ int minLocal; /* Minimum amount of payload held locally */ int surplus; /* Overflow payload available for local storage */ minLocal = pPage->minLocal; surplus = minLocal + (nPayload - minLocal)%(pPage->pBt->usableSize-4); return ( surplus <= maxLocal ) ? surplus : minLocal; } } /* ** The following routines are implementations of the MemPage.xParseCell() ** method. ** ** Parse a cell content block and fill in the CellInfo structure. ** |
︙ | ︙ | |||
1595 1596 1597 1598 1599 1600 1601 | static u16 cellSize(MemPage *pPage, int iCell){ return pPage->xCellSize(pPage, findCell(pPage, iCell)); } #endif #ifndef SQLITE_OMIT_AUTOVACUUM /* | | > | | | | > | 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 | static u16 cellSize(MemPage *pPage, int iCell){ return pPage->xCellSize(pPage, findCell(pPage, iCell)); } #endif #ifndef SQLITE_OMIT_AUTOVACUUM /* ** The cell pCell is currently part of page pSrc but will ultimately be part ** of pPage. (pSrc and pPager are often the same.) If pCell contains a ** pointer to an overflow page, insert an entry into the pointer-map for ** the overflow page that will be valid after pCell has been moved to pPage. */ static void ptrmapPutOvflPtr(MemPage *pPage, MemPage *pSrc, u8 *pCell,int *pRC){ CellInfo info; if( *pRC ) return; assert( pCell!=0 ); pPage->xParseCell(pPage, pCell, &info); if( info.nLocal<info.nPayload ){ Pgno ovfl; if( SQLITE_WITHIN(pSrc->aDataEnd, pCell, pCell+info.nLocal) ){ testcase( pSrc!=pPage ); *pRC = SQLITE_CORRUPT_BKPT; return; } ovfl = get4byte(&pCell[info.nSize-4]); ptrmapPut(pPage->pBt, ovfl, PTRMAP_OVERFLOW1, pPage->pgno, pRC); } } |
︙ | ︙ | |||
1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 | int cbrk; /* Offset to the cell content area */ int nCell; /* Number of cells on the page */ unsigned char *data; /* The page data */ unsigned char *temp; /* Temp area for cell content */ unsigned char *src; /* Source of content */ int iCellFirst; /* First allowable cell index */ int iCellLast; /* Last possible cell index */ assert( sqlite3PagerIswriteable(pPage->pDbPage) ); assert( pPage->pBt!=0 ); assert( pPage->pBt->usableSize <= SQLITE_MAX_PAGE_SIZE ); assert( pPage->nOverflow==0 ); assert( sqlite3_mutex_held(pPage->pBt->mutex) ); temp = 0; src = data = pPage->aData; hdr = pPage->hdrOffset; cellOffset = pPage->cellOffset; nCell = pPage->nCell; | > | | < < < < > > > > | | | | < < | > | 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 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 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 | int cbrk; /* Offset to the cell content area */ int nCell; /* Number of cells on the page */ unsigned char *data; /* The page data */ unsigned char *temp; /* Temp area for cell content */ unsigned char *src; /* Source of content */ int iCellFirst; /* First allowable cell index */ int iCellLast; /* Last possible cell index */ int iCellStart; /* First cell offset in input */ assert( sqlite3PagerIswriteable(pPage->pDbPage) ); assert( pPage->pBt!=0 ); assert( pPage->pBt->usableSize <= SQLITE_MAX_PAGE_SIZE ); assert( pPage->nOverflow==0 ); assert( sqlite3_mutex_held(pPage->pBt->mutex) ); temp = 0; src = data = pPage->aData; hdr = pPage->hdrOffset; cellOffset = pPage->cellOffset; nCell = pPage->nCell; assert( nCell==get2byte(&data[hdr+3]) || CORRUPT_DB ); iCellFirst = cellOffset + 2*nCell; usableSize = pPage->pBt->usableSize; /* This block handles pages with two or fewer free blocks and nMaxFrag ** or fewer fragmented bytes. In this case it is faster to move the ** two (or one) blocks of cells using memmove() and add the required ** offsets to each pointer in the cell-pointer array than it is to ** reconstruct the entire page. */ if( (int)data[hdr+7]<=nMaxFrag ){ int iFree = get2byte(&data[hdr+1]); if( iFree>usableSize-4 ) return SQLITE_CORRUPT_PAGE(pPage); if( iFree ){ int iFree2 = get2byte(&data[iFree]); if( iFree2>usableSize-4 ) return SQLITE_CORRUPT_PAGE(pPage); if( 0==iFree2 || (data[iFree2]==0 && data[iFree2+1]==0) ){ u8 *pEnd = &data[cellOffset + nCell*2]; u8 *pAddr; int sz2 = 0; int sz = get2byte(&data[iFree+2]); int top = get2byte(&data[hdr+5]); if( top>=iFree ){ return SQLITE_CORRUPT_PAGE(pPage); } if( iFree2 ){ if( iFree+sz>iFree2 ) return SQLITE_CORRUPT_PAGE(pPage); sz2 = get2byte(&data[iFree2+2]); if( iFree2+sz2 > usableSize ) return SQLITE_CORRUPT_PAGE(pPage); memmove(&data[iFree+sz+sz2], &data[iFree+sz], iFree2-(iFree+sz)); sz += sz2; }else if( NEVER(iFree+sz>usableSize) ){ return SQLITE_CORRUPT_PAGE(pPage); } cbrk = top+sz; assert( cbrk+(iFree-top) <= usableSize ); memmove(&data[cbrk], &data[top], iFree-top); for(pAddr=&data[cellOffset]; pAddr<pEnd; pAddr+=2){ pc = get2byte(pAddr); if( pc<iFree ){ put2byte(pAddr, pc+sz); } else if( pc<iFree2 ){ put2byte(pAddr, pc+sz2); } } goto defragment_out; } } } cbrk = usableSize; iCellLast = usableSize - 4; iCellStart = get2byte(&data[hdr+5]); for(i=0; i<nCell; i++){ u8 *pAddr; /* The i-th cell pointer */ pAddr = &data[cellOffset + i*2]; pc = get2byte(pAddr); testcase( pc==iCellFirst ); testcase( pc==iCellLast ); /* These conditions have already been verified in btreeInitPage() ** if PRAGMA cell_size_check=ON. */ if( pc<iCellStart || pc>iCellLast ){ return SQLITE_CORRUPT_PAGE(pPage); } assert( pc>=iCellStart && pc<=iCellLast ); size = pPage->xCellSize(pPage, &src[pc]); cbrk -= size; if( cbrk<iCellStart || pc+size>usableSize ){ return SQLITE_CORRUPT_PAGE(pPage); } assert( cbrk+size<=usableSize && cbrk>=iCellStart ); testcase( cbrk+size==usableSize ); testcase( pc+size==usableSize ); put2byte(pAddr, cbrk); if( temp==0 ){ if( cbrk==pc ) continue; temp = sqlite3PagerTempSpace(pPage->pBt->pPager); memcpy(&temp[iCellStart], &data[iCellStart], usableSize - iCellStart); src = temp; } memcpy(&data[cbrk], &src[pc], size); } data[hdr+7] = 0; defragment_out: assert( pPage->nFree>=0 ); if( data[hdr+7]+cbrk-iCellFirst!=pPage->nFree ){ return SQLITE_CORRUPT_PAGE(pPage); } assert( cbrk>=iCellFirst ); put2byte(&data[hdr+5], cbrk); data[hdr+1] = 0; data[hdr+2] = 0; |
︙ | ︙ | |||
1766 1767 1768 1769 1770 1771 1772 | ** detected then *pRc is set to SQLITE_CORRUPT and NULL is returned. ** ** Slots on the free list that are between 1 and 3 bytes larger than nByte ** will be ignored if adding the extra space to the fragmentation count ** causes the fragmentation count to exceed 60. */ static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc){ | | | | | | | | | < < < | > > > > | | < | > | | > | > > > > > | 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 | ** detected then *pRc is set to SQLITE_CORRUPT and NULL is returned. ** ** Slots on the free list that are between 1 and 3 bytes larger than nByte ** will be ignored if adding the extra space to the fragmentation count ** causes the fragmentation count to exceed 60. */ static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc){ const int hdr = pPg->hdrOffset; /* Offset to page header */ u8 * const aData = pPg->aData; /* Page data */ int iAddr = hdr + 1; /* Address of ptr to pc */ int pc = get2byte(&aData[iAddr]); /* Address of a free slot */ int x; /* Excess size of the slot */ int maxPC = pPg->pBt->usableSize - nByte; /* Max address for a usable slot */ int size; /* Size of the free slot */ assert( pc>0 ); while( pc<=maxPC ){ /* EVIDENCE-OF: R-22710-53328 The third and fourth bytes of each ** freeblock form a big-endian integer which is the size of the freeblock ** in bytes, including the 4-byte header. */ size = get2byte(&aData[pc+2]); if( (x = size - nByte)>=0 ){ testcase( x==4 ); testcase( x==3 ); if( x<4 ){ /* EVIDENCE-OF: R-11498-58022 In a well-formed b-tree page, the total ** number of bytes in fragments may not exceed 60. */ if( aData[hdr+7]>57 ) return 0; /* Remove the slot from the free-list. Update the number of ** fragmented bytes within the page. */ memcpy(&aData[iAddr], &aData[pc], 2); aData[hdr+7] += (u8)x; }else if( x+pc > maxPC ){ /* This slot extends off the end of the usable part of the page */ *pRc = SQLITE_CORRUPT_PAGE(pPg); return 0; }else{ /* The slot remains on the free-list. Reduce its size to account ** for the portion used by the new allocation. */ put2byte(&aData[pc+2], x); } return &aData[pc + x]; } iAddr = pc; pc = get2byte(&aData[pc]); if( pc<=iAddr+size ){ if( pc ){ /* The next slot in the chain is not past the end of the current slot */ *pRc = SQLITE_CORRUPT_PAGE(pPg); } return 0; } } if( pc>maxPC+nByte-4 ){ /* The free slot chain extends off the end of the page */ *pRc = SQLITE_CORRUPT_PAGE(pPg); } return 0; } /* ** Allocate nByte bytes of space from within the B-Tree page passed ** as the first argument. Write into *pIdx the index into pPage->aData[] ** of the first byte of allocated space. Return either SQLITE_OK or |
︙ | ︙ | |||
1850 1851 1852 1853 1854 1855 1856 | assert( gap<=65536 ); /* EVIDENCE-OF: R-29356-02391 If the database uses a 65536-byte page size ** and the reserved space is zero (the usual value for reserved space) ** then the cell content offset of an empty page wants to be 65536. ** However, that integer is too large to be stored in a 2-byte unsigned ** integer, so a value of 0 is used in its place. */ top = get2byte(&data[hdr+5]); | | | | | > | | > > > | > > | | | 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 | assert( gap<=65536 ); /* EVIDENCE-OF: R-29356-02391 If the database uses a 65536-byte page size ** and the reserved space is zero (the usual value for reserved space) ** then the cell content offset of an empty page wants to be 65536. ** However, that integer is too large to be stored in a 2-byte unsigned ** integer, so a value of 0 is used in its place. */ top = get2byte(&data[hdr+5]); assert( top<=(int)pPage->pBt->usableSize ); /* by btreeComputeFreeSpace() */ if( gap>top ){ if( top==0 && pPage->pBt->usableSize==65536 ){ top = 65536; }else{ return SQLITE_CORRUPT_PAGE(pPage); } } /* If there is enough space between gap and top for one more cell pointer, ** and if the freelist is not empty, then search the ** freelist looking for a slot big enough to satisfy the request. */ testcase( gap+2==top ); testcase( gap+1==top ); testcase( gap==top ); if( (data[hdr+2] || data[hdr+1]) && gap+2<=top ){ u8 *pSpace = pageFindSlot(pPage, nByte, &rc); if( pSpace ){ int g2; assert( pSpace+nByte<=data+pPage->pBt->usableSize ); *pIdx = g2 = (int)(pSpace-data); if( g2<=gap ){ return SQLITE_CORRUPT_PAGE(pPage); }else{ return SQLITE_OK; } }else if( rc ){ return rc; } } /* The request could not be fulfilled using a freelist slot. Check ** to see if defragmentation is necessary. */ testcase( gap+2+nByte==top ); if( gap+2+nByte>top ){ assert( pPage->nCell>0 || CORRUPT_DB ); assert( pPage->nFree>=0 ); rc = defragmentPage(pPage, MIN(4, pPage->nFree - (2+nByte))); if( rc ) return rc; top = get2byteNotZero(&data[hdr+5]); assert( gap+2+nByte<=top ); } /* Allocate memory from the gap in between the cell pointer array ** and the cell content area. The btreeComputeFreeSpace() call has already ** validated the freelist. Given that the freelist is valid, there ** is no way that the allocation can extend off the end of the page. ** The assert() below verifies the previous sentence. */ top -= nByte; put2byte(&data[hdr+5], top); assert( top+nByte <= (int)pPage->pBt->usableSize ); *pIdx = top; return SQLITE_OK; } /* ** Return a section of the pPage->aData to the freelist. ** The first byte of the new free block is pPage->aData[iStart] ** and the size of the block is iSize bytes. ** ** Adjacent freeblocks are coalesced. ** ** Even though the freeblock list was checked by btreeComputeFreeSpace(), ** that routine will not detect overlap between cells or freeblocks. Nor ** does it detect cells or freeblocks that encrouch into the reserved bytes ** at the end of the page. So do additional corruption checks inside this ** routine and return SQLITE_CORRUPT if any problems are found. */ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){ u16 iPtr; /* Address of ptr to next freeblock */ |
︙ | ︙ | |||
1944 1945 1946 1947 1948 1949 1950 | hdr = pPage->hdrOffset; iPtr = hdr + 1; if( data[iPtr+1]==0 && data[iPtr]==0 ){ iFreeBlk = 0; /* Shortcut for the case when the freelist is empty */ }else{ while( (iFreeBlk = get2byte(&data[iPtr]))<iStart ){ if( iFreeBlk<iPtr+4 ){ | | | | 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 | hdr = pPage->hdrOffset; iPtr = hdr + 1; if( data[iPtr+1]==0 && data[iPtr]==0 ){ iFreeBlk = 0; /* Shortcut for the case when the freelist is empty */ }else{ while( (iFreeBlk = get2byte(&data[iPtr]))<iStart ){ if( iFreeBlk<iPtr+4 ){ if( iFreeBlk==0 ) break; /* TH3: corrupt082.100 */ return SQLITE_CORRUPT_PAGE(pPage); } iPtr = iFreeBlk; } if( iFreeBlk>pPage->pBt->usableSize-4 ){ /* TH3: corrupt081.100 */ return SQLITE_CORRUPT_PAGE(pPage); } assert( iFreeBlk>iPtr || iFreeBlk==0 ); /* At this point: ** iFreeBlk: First freeblock after iStart, or zero if none ** iPtr: The address of a pointer to iFreeBlk |
︙ | ︙ | |||
1992 1993 1994 1995 1996 1997 1998 | data[hdr+7] -= nFrag; } x = get2byte(&data[hdr+5]); if( iStart<=x ){ /* The new freeblock is at the beginning of the cell content area, ** so just extend the cell content area rather than create another ** freelist entry */ | > | | 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 | data[hdr+7] -= nFrag; } x = get2byte(&data[hdr+5]); if( iStart<=x ){ /* The new freeblock is at the beginning of the cell content area, ** so just extend the cell content area rather than create another ** freelist entry */ if( iStart<x ) return SQLITE_CORRUPT_PAGE(pPage); if( iPtr!=hdr+1 ) return SQLITE_CORRUPT_PAGE(pPage); put2byte(&data[hdr+1], iFreeBlk); put2byte(&data[hdr+5], iEnd); }else{ /* Insert the new freeblock into the freelist */ put2byte(&data[iPtr], iStart); } if( pPage->pBt->btsFlags & BTS_FAST_SECURE ){ |
︙ | ︙ | |||
2072 2073 2074 2075 2076 2077 2078 | return SQLITE_CORRUPT_PAGE(pPage); } pPage->max1bytePayload = pBt->max1bytePayload; return SQLITE_OK; } /* | | | < < < < < | < < | > | < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 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 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 | return SQLITE_CORRUPT_PAGE(pPage); } pPage->max1bytePayload = pBt->max1bytePayload; return SQLITE_OK; } /* ** Compute the amount of freespace on the page. In other words, fill ** in the pPage->nFree field. */ static int btreeComputeFreeSpace(MemPage *pPage){ int pc; /* Address of a freeblock within pPage->aData[] */ u8 hdr; /* Offset to beginning of page header */ u8 *data; /* Equal to pPage->aData */ int usableSize; /* Amount of usable space on each page */ int nFree; /* Number of unused bytes on the page */ int top; /* First byte of the cell content area */ int iCellFirst; /* First allowable cell or freeblock offset */ int iCellLast; /* Last possible cell or freeblock offset */ assert( pPage->pBt!=0 ); assert( pPage->pBt->db!=0 ); assert( sqlite3_mutex_held(pPage->pBt->mutex) ); assert( pPage->pgno==sqlite3PagerPagenumber(pPage->pDbPage) ); assert( pPage == sqlite3PagerGetExtra(pPage->pDbPage) ); assert( pPage->aData == sqlite3PagerGetData(pPage->pDbPage) ); assert( pPage->isInit==1 ); assert( pPage->nFree<0 ); usableSize = pPage->pBt->usableSize; hdr = pPage->hdrOffset; data = pPage->aData; /* EVIDENCE-OF: R-58015-48175 The two-byte integer at offset 5 designates ** the start of the cell content area. A zero value for this integer is ** interpreted as 65536. */ top = get2byteNotZero(&data[hdr+5]); iCellFirst = hdr + 8 + pPage->childPtrSize + 2*pPage->nCell; iCellLast = usableSize - 4; /* Compute the total free space on the page ** EVIDENCE-OF: R-23588-34450 The two-byte integer at offset 1 gives the ** start of the first freeblock on the page, or is zero if there are no ** freeblocks. */ pc = get2byte(&data[hdr+1]); nFree = data[hdr+7] + top; /* Init nFree to non-freeblock free space */ if( pc>0 ){ u32 next, size; if( pc<top ){ /* EVIDENCE-OF: R-55530-52930 In a well-formed b-tree page, there will ** always be at least one cell before the first freeblock. */ return SQLITE_CORRUPT_PAGE(pPage); } while( 1 ){ if( pc>iCellLast ){ |
︙ | ︙ | |||
2206 2207 2208 2209 2210 2211 2212 | /* At this point, nFree contains the sum of the offset to the start ** of the cell-content area plus the number of free bytes within ** the cell-content area. If this is greater than the usable-size ** of the page, then the page must be corrupted. This check also ** serves to verify that the offset to the start of the cell-content ** area, according to the page header, lies within the page. */ | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 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 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 | /* At this point, nFree contains the sum of the offset to the start ** of the cell-content area plus the number of free bytes within ** the cell-content area. If this is greater than the usable-size ** of the page, then the page must be corrupted. This check also ** serves to verify that the offset to the start of the cell-content ** area, according to the page header, lies within the page. */ if( nFree>usableSize || nFree<iCellFirst ){ return SQLITE_CORRUPT_PAGE(pPage); } pPage->nFree = (u16)(nFree - iCellFirst); return SQLITE_OK; } /* ** Do additional sanity check after btreeInitPage() if ** PRAGMA cell_size_check=ON */ static SQLITE_NOINLINE int btreeCellSizeCheck(MemPage *pPage){ int iCellFirst; /* First allowable cell or freeblock offset */ int iCellLast; /* Last possible cell or freeblock offset */ int i; /* Index into the cell pointer array */ int sz; /* Size of a cell */ int pc; /* Address of a freeblock within pPage->aData[] */ u8 *data; /* Equal to pPage->aData */ int usableSize; /* Maximum usable space on the page */ int cellOffset; /* Start of cell content area */ iCellFirst = pPage->cellOffset + 2*pPage->nCell; usableSize = pPage->pBt->usableSize; iCellLast = usableSize - 4; data = pPage->aData; cellOffset = pPage->cellOffset; if( !pPage->leaf ) iCellLast--; for(i=0; i<pPage->nCell; i++){ pc = get2byteAligned(&data[cellOffset+i*2]); testcase( pc==iCellFirst ); testcase( pc==iCellLast ); if( pc<iCellFirst || pc>iCellLast ){ return SQLITE_CORRUPT_PAGE(pPage); } sz = pPage->xCellSize(pPage, &data[pc]); testcase( pc+sz==usableSize ); if( pc+sz>usableSize ){ return SQLITE_CORRUPT_PAGE(pPage); } } return SQLITE_OK; } /* ** Initialize the auxiliary information for a disk block. ** ** Return SQLITE_OK on success. If we see that the page does ** not contain a well-formed database page, then return ** SQLITE_CORRUPT. Note that a return of SQLITE_OK does not ** guarantee that the page is well-formed. It only shows that ** we failed to detect any corruption. */ static int btreeInitPage(MemPage *pPage){ u8 *data; /* Equal to pPage->aData */ BtShared *pBt; /* The main btree structure */ assert( pPage->pBt!=0 ); assert( pPage->pBt->db!=0 ); assert( sqlite3_mutex_held(pPage->pBt->mutex) ); assert( pPage->pgno==sqlite3PagerPagenumber(pPage->pDbPage) ); assert( pPage == sqlite3PagerGetExtra(pPage->pDbPage) ); assert( pPage->aData == sqlite3PagerGetData(pPage->pDbPage) ); assert( pPage->isInit==0 ); pBt = pPage->pBt; data = pPage->aData + pPage->hdrOffset; /* EVIDENCE-OF: R-28594-02890 The one-byte flag at offset 0 indicating ** the b-tree page type. */ if( decodeFlags(pPage, data[0]) ){ return SQLITE_CORRUPT_PAGE(pPage); } assert( pBt->pageSize>=512 && pBt->pageSize<=65536 ); pPage->maskPage = (u16)(pBt->pageSize - 1); pPage->nOverflow = 0; pPage->cellOffset = pPage->hdrOffset + 8 + pPage->childPtrSize; pPage->aCellIdx = data + pPage->childPtrSize + 8; pPage->aDataEnd = pPage->aData + pBt->usableSize; pPage->aDataOfst = pPage->aData + pPage->childPtrSize; /* EVIDENCE-OF: R-37002-32774 The two-byte integer at offset 3 gives the ** number of cells on the page. */ pPage->nCell = get2byte(&data[3]); if( pPage->nCell>MX_CELL(pBt) ){ /* To many cells for a single page. The page must be corrupt */ return SQLITE_CORRUPT_PAGE(pPage); } testcase( pPage->nCell==MX_CELL(pBt) ); /* EVIDENCE-OF: R-24089-57979 If a page contains no cells (which is only ** possible for a root page of a table that contains no rows) then the ** offset to the cell content area will equal the page size minus the ** bytes of reserved space. */ assert( pPage->nCell>0 || get2byteNotZero(&data[5])==(int)pBt->usableSize || CORRUPT_DB ); pPage->nFree = -1; /* Indicate that this value is yet uncomputed */ pPage->isInit = 1; if( pBt->db->flags & SQLITE_CellSizeCk ){ return btreeCellSizeCheck(pPage); } return SQLITE_OK; } /* ** Set up a raw page so that it looks like a database page holding ** no entries. */ |
︙ | ︙ | |||
2318 2319 2320 2321 2322 2323 2324 | /* ** Return the size of the database file in pages. If there is any kind of ** error, return ((unsigned int)-1). */ static Pgno btreePagecount(BtShared *pBt){ return pBt->nPage; } | | < | 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 | /* ** Return the size of the database file in pages. If there is any kind of ** error, return ((unsigned int)-1). */ static Pgno btreePagecount(BtShared *pBt){ return pBt->nPage; } Pgno sqlite3BtreeLastPage(Btree *p){ assert( sqlite3BtreeHoldsMutex(p) ); return btreePagecount(p->pBt); } /* ** Get a page from the pager and initialize it. ** ** If pCur!=0 then the page is being fetched as part of a moveToChild() |
︙ | ︙ | |||
2353 2354 2355 2356 2357 2358 2359 | assert( sqlite3_mutex_held(pBt->mutex) ); assert( pCur==0 || ppPage==&pCur->pPage ); assert( pCur==0 || bReadOnly==pCur->curPagerFlags ); assert( pCur==0 || pCur->iPage>0 ); if( pgno>btreePagecount(pBt) ){ rc = SQLITE_CORRUPT_BKPT; | | | < | < | | > > | 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 | assert( sqlite3_mutex_held(pBt->mutex) ); assert( pCur==0 || ppPage==&pCur->pPage ); assert( pCur==0 || bReadOnly==pCur->curPagerFlags ); assert( pCur==0 || pCur->iPage>0 ); if( pgno>btreePagecount(pBt) ){ rc = SQLITE_CORRUPT_BKPT; goto getAndInitPage_error1; } rc = sqlite3PagerGet(pBt->pPager, pgno, (DbPage**)&pDbPage, bReadOnly); if( rc ){ goto getAndInitPage_error1; } *ppPage = (MemPage*)sqlite3PagerGetExtra(pDbPage); if( (*ppPage)->isInit==0 ){ btreePageFromDbPage(pDbPage, pgno, pBt); rc = btreeInitPage(*ppPage); if( rc!=SQLITE_OK ){ goto getAndInitPage_error2; } } assert( (*ppPage)->pgno==pgno ); assert( (*ppPage)->aData==sqlite3PagerGetData(pDbPage) ); /* If obtaining a child page for a cursor, we must verify that the page is ** compatible with the root page. */ if( pCur && ((*ppPage)->nCell<1 || (*ppPage)->intKey!=pCur->curIntKey) ){ rc = SQLITE_CORRUPT_PGNO(pgno); goto getAndInitPage_error2; } return SQLITE_OK; getAndInitPage_error2: releasePage(*ppPage); getAndInitPage_error1: if( pCur ){ pCur->iPage--; pCur->pPage = pCur->apPage[pCur->iPage]; } testcase( pgno==0 ); assert( pgno!=0 || rc==SQLITE_CORRUPT ); return rc; |
︙ | ︙ | |||
2494 2495 2496 2497 2498 2499 2500 | /* ** Invoke the busy handler for a btree. */ static int btreeInvokeBusyHandler(void *pArg){ BtShared *pBt = (BtShared*)pArg; assert( pBt->db ); assert( sqlite3_mutex_held(pBt->db->mutex) ); | | < | 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 | /* ** Invoke the busy handler for a btree. */ static int btreeInvokeBusyHandler(void *pArg){ BtShared *pBt = (BtShared*)pArg; assert( pBt->db ); assert( sqlite3_mutex_held(pBt->db->mutex) ); return sqlite3InvokeBusyHandler(&pBt->db->busyHandler); } /* ** Open a database file. ** ** zFilename is the name of the database file. If zFilename is NULL ** then an ephemeral database is created. The ephemeral database might |
︙ | ︙ | |||
2599 2600 2601 2602 2603 2604 2605 | } if( isMemdb ){ memcpy(zFullPathname, zFilename, nFilename); }else{ rc = sqlite3OsFullPathname(pVfs, zFilename, nFullPathname, zFullPathname); if( rc ){ | > > > | | | > | | 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 | } if( isMemdb ){ memcpy(zFullPathname, zFilename, nFilename); }else{ rc = sqlite3OsFullPathname(pVfs, zFilename, nFullPathname, zFullPathname); if( rc ){ if( rc==SQLITE_OK_SYMLINK ){ rc = SQLITE_OK; }else{ sqlite3_free(zFullPathname); sqlite3_free(p); return rc; } } } #if SQLITE_THREADSAFE mutexOpen = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_OPEN); sqlite3_mutex_enter(mutexOpen); mutexShared = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN); sqlite3_mutex_enter(mutexShared); #endif for(pBt=GLOBAL(BtShared*,sqlite3SharedCacheList); pBt; pBt=pBt->pNext){ assert( pBt->nRef>0 ); if( 0==strcmp(zFullPathname, sqlite3PagerFilename(pBt->pPager, 0)) && sqlite3PagerVfs(pBt->pPager)==pVfs ){ int iDb; |
︙ | ︙ | |||
2726 2727 2728 2729 2730 2731 2732 | #if !defined(SQLITE_OMIT_SHARED_CACHE) && !defined(SQLITE_OMIT_DISKIO) /* Add the new BtShared object to the linked list sharable BtShareds. */ pBt->nRef = 1; if( p->sharable ){ MUTEX_LOGIC( sqlite3_mutex *mutexShared; ) | | | 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 | #if !defined(SQLITE_OMIT_SHARED_CACHE) && !defined(SQLITE_OMIT_DISKIO) /* Add the new BtShared object to the linked list sharable BtShareds. */ pBt->nRef = 1; if( p->sharable ){ MUTEX_LOGIC( sqlite3_mutex *mutexShared; ) MUTEX_LOGIC( mutexShared = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN);) if( SQLITE_THREADSAFE && sqlite3GlobalConfig.bCoreMutex ){ pBt->mutex = sqlite3MutexAlloc(SQLITE_MUTEX_FAST); if( pBt->mutex==0 ){ rc = SQLITE_NOMEM_BKPT; goto btree_open_out; } } |
︙ | ︙ | |||
2791 2792 2793 2794 2795 2796 2797 | sqlite3_file *pFile; /* If the B-Tree was successfully opened, set the pager-cache size to the ** default value. Except, when opening on an existing shared pager-cache, ** do not change the pager-cache size. */ if( sqlite3BtreeSchema(p, 0, 0)==0 ){ | | | 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 | sqlite3_file *pFile; /* If the B-Tree was successfully opened, set the pager-cache size to the ** default value. Except, when opening on an existing shared pager-cache, ** do not change the pager-cache size. */ if( sqlite3BtreeSchema(p, 0, 0)==0 ){ sqlite3BtreeSetCacheSize(p, SQLITE_DEFAULT_CACHE_SIZE); } pFile = sqlite3PagerFile(pBt->pPager); if( pFile->pMethods ){ sqlite3OsFileControlHint(pFile, SQLITE_FCNTL_PDB, (void*)&pBt->db); } } |
︙ | ︙ | |||
2815 2816 2817 2818 2819 2820 2821 | ** Decrement the BtShared.nRef counter. When it reaches zero, ** remove the BtShared structure from the sharing list. Return ** true if the BtShared.nRef counter reaches zero and return ** false if it is still positive. */ static int removeFromSharingList(BtShared *pBt){ #ifndef SQLITE_OMIT_SHARED_CACHE | | | | | | 2903 2904 2905 2906 2907 2908 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 | ** Decrement the BtShared.nRef counter. When it reaches zero, ** remove the BtShared structure from the sharing list. Return ** true if the BtShared.nRef counter reaches zero and return ** false if it is still positive. */ static int removeFromSharingList(BtShared *pBt){ #ifndef SQLITE_OMIT_SHARED_CACHE MUTEX_LOGIC( sqlite3_mutex *pMainMtx; ) BtShared *pList; int removed = 0; assert( sqlite3_mutex_notheld(pBt->mutex) ); MUTEX_LOGIC( pMainMtx = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN); ) sqlite3_mutex_enter(pMainMtx); pBt->nRef--; if( pBt->nRef<=0 ){ if( GLOBAL(BtShared*,sqlite3SharedCacheList)==pBt ){ GLOBAL(BtShared*,sqlite3SharedCacheList) = pBt->pNext; }else{ pList = GLOBAL(BtShared*,sqlite3SharedCacheList); while( ALWAYS(pList) && pList->pNext!=pBt ){ pList=pList->pNext; } if( ALWAYS(pList) ){ pList->pNext = pBt->pNext; } } if( SQLITE_THREADSAFE ){ sqlite3_mutex_free(pBt->mutex); } removed = 1; } sqlite3_mutex_leave(pMainMtx); return removed; #else return 1; #endif } /* |
︙ | ︙ | |||
2894 2895 2896 2897 2898 2899 2900 | } /* ** Close an open database and invalidate all cursors. */ int sqlite3BtreeClose(Btree *p){ BtShared *pBt = p->pBt; | < > > > > | | | | | | > | 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 | } /* ** Close an open database and invalidate all cursors. */ int sqlite3BtreeClose(Btree *p){ BtShared *pBt = p->pBt; /* Close all cursors opened via this handle. */ assert( sqlite3_mutex_held(p->db->mutex) ); sqlite3BtreeEnter(p); /* Verify that no other cursors have this Btree open */ #ifdef SQLITE_DEBUG { BtCursor *pCur = pBt->pCursor; while( pCur ){ BtCursor *pTmp = pCur; pCur = pCur->pNext; assert( pTmp->pBtree!=p ); } } #endif /* Rollback any active transaction and free the handle structure. ** The call to sqlite3BtreeRollback() drops any table-locks held by ** this handle. */ sqlite3BtreeRollback(p, SQLITE_OK, 0); sqlite3BtreeLeave(p); |
︙ | ︙ | |||
3042 3043 3044 3045 3046 3047 3048 3049 | ** bytes per page is left unchanged. ** ** If the iFix!=0 then the BTS_PAGESIZE_FIXED flag is set so that the page size ** and autovacuum mode can no longer be changed. */ int sqlite3BtreeSetPageSize(Btree *p, int pageSize, int nReserve, int iFix){ int rc = SQLITE_OK; BtShared *pBt = p->pBt; | > | < | > | < < < > | 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 | ** bytes per page is left unchanged. ** ** If the iFix!=0 then the BTS_PAGESIZE_FIXED flag is set so that the page size ** and autovacuum mode can no longer be changed. */ int sqlite3BtreeSetPageSize(Btree *p, int pageSize, int nReserve, int iFix){ int rc = SQLITE_OK; int x; BtShared *pBt = p->pBt; assert( nReserve>=0 && nReserve<=255 ); sqlite3BtreeEnter(p); pBt->nReserveWanted = nReserve; x = pBt->pageSize - pBt->usableSize; if( nReserve<x ) nReserve = x; if( pBt->btsFlags & BTS_PAGESIZE_FIXED ){ sqlite3BtreeLeave(p); return SQLITE_READONLY; } assert( nReserve>=0 && nReserve<=255 ); if( pageSize>=512 && pageSize<=SQLITE_MAX_PAGE_SIZE && ((pageSize-1)&pageSize)==0 ){ assert( (pageSize & 7)==0 ); assert( !pBt->pCursor ); if( nReserve>32 && pageSize==512 ) pageSize = 1024; pBt->pageSize = (u32)pageSize; freeTempSpace(pBt); } rc = sqlite3PagerSetPagesize(pBt->pPager, &pBt->pageSize, nReserve); pBt->usableSize = pBt->pageSize - (u16)nReserve; if( iFix ) pBt->btsFlags |= BTS_PAGESIZE_FIXED; sqlite3BtreeLeave(p); |
︙ | ︙ | |||
3100 3101 3102 3103 3104 3105 3106 | } /* ** Return the number of bytes of space at the end of every page that ** are intentually left unused. This is the "reserved" space that is ** sometimes used by extensions. ** | < | > | | | > | < < < | | | | 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 | } /* ** Return the number of bytes of space at the end of every page that ** are intentually left unused. This is the "reserved" space that is ** sometimes used by extensions. ** ** The value returned is the larger of the current reserve size and ** the latest reserve size requested by SQLITE_FILECTRL_RESERVE_BYTES. ** The amount of reserve can only grow - never shrink. */ int sqlite3BtreeGetRequestedReserve(Btree *p){ int n1, n2; sqlite3BtreeEnter(p); n1 = (int)p->pBt->nReserveWanted; n2 = sqlite3BtreeGetReserveNoMutex(p); sqlite3BtreeLeave(p); return n1>n2 ? n1 : n2; } /* ** Set the maximum page count for a database if mxPage is positive. ** No changes are made if mxPage is 0 or negative. ** Regardless of the value of mxPage, return the maximum page count. */ Pgno sqlite3BtreeMaxPageCount(Btree *p, Pgno mxPage){ Pgno n; sqlite3BtreeEnter(p); n = sqlite3PagerMaxPageCount(p->pBt->pPager, mxPage); sqlite3BtreeLeave(p); return n; } /* |
︙ | ︙ | |||
3251 3252 3253 3254 3255 3256 3257 | ** well-formed database file, then SQLITE_CORRUPT is returned. ** SQLITE_BUSY is returned if the database is locked. SQLITE_NOMEM ** is returned if we run out of memory. */ static int lockBtree(BtShared *pBt){ int rc; /* Result code from subfunctions */ MemPage *pPage1; /* Page 1 of the database file */ | | | < | | | 3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 3368 | ** well-formed database file, then SQLITE_CORRUPT is returned. ** SQLITE_BUSY is returned if the database is locked. SQLITE_NOMEM ** is returned if we run out of memory. */ static int lockBtree(BtShared *pBt){ int rc; /* Result code from subfunctions */ MemPage *pPage1; /* Page 1 of the database file */ u32 nPage; /* Number of pages in the database */ u32 nPageFile = 0; /* Number of pages in the database file */ 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); if( rc!=SQLITE_OK ) return rc; /* Do some checking to help insure the file we opened really is ** a valid database file. */ nPage = get4byte(28+(u8*)pPage1->aData); sqlite3PagerPagecount(pBt->pPager, (int*)&nPageFile); if( nPage==0 || memcmp(24+(u8*)pPage1->aData, 92+(u8*)pPage1->aData,4)!=0 ){ nPage = nPageFile; } if( (pBt->db->flags & SQLITE_ResetDatabase)!=0 ){ nPage = 0; } if( nPage>0 ){ |
︙ | ︙ | |||
3300 3301 3302 3303 3304 3305 3306 | if( page1[18]>2 ){ pBt->btsFlags |= BTS_READ_ONLY; } if( page1[19]>2 ){ goto page1_init_failed; } | | | 3388 3389 3390 3391 3392 3393 3394 3395 3396 3397 3398 3399 3400 3401 3402 | if( page1[18]>2 ){ pBt->btsFlags |= BTS_READ_ONLY; } if( page1[19]>2 ){ goto page1_init_failed; } /* If the read version is set to 2, this database should be accessed ** in WAL mode. If the log is not already open, open it now. Then ** return SQLITE_OK and return without populating BtShared.pPage1. ** The caller detects this and calls this function again. This is ** required as the version of page 1 currently in the page1 buffer ** may not be the latest version - there may be a newer one in the log ** file. */ |
︙ | ︙ | |||
3347 3348 3349 3350 3351 3352 3353 3354 3355 3356 3357 3358 3359 3360 | ** between 512 and 65536 inclusive. */ if( ((pageSize-1)&pageSize)!=0 || pageSize>SQLITE_MAX_PAGE_SIZE || pageSize<=256 ){ goto page1_init_failed; } assert( (pageSize & 7)==0 ); /* EVIDENCE-OF: R-59310-51205 The "reserved space" size in the 1-byte ** integer at offset 20 is the number of bytes of space at the end of ** each page to reserve for extensions. ** ** EVIDENCE-OF: R-37497-42412 The size of the reserved region is ** determined by the one-byte unsigned integer found at an offset of 20 | > | 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 | ** between 512 and 65536 inclusive. */ if( ((pageSize-1)&pageSize)!=0 || pageSize>SQLITE_MAX_PAGE_SIZE || pageSize<=256 ){ goto page1_init_failed; } pBt->btsFlags |= BTS_PAGESIZE_FIXED; assert( (pageSize & 7)==0 ); /* EVIDENCE-OF: R-59310-51205 The "reserved space" size in the 1-byte ** integer at offset 20 is the number of bytes of space at the end of ** each page to reserve for extensions. ** ** EVIDENCE-OF: R-37497-42412 The size of the reserved region is ** determined by the one-byte unsigned integer found at an offset of 20 |
︙ | ︙ | |||
3561 3562 3563 3564 3565 3566 3567 3568 | ** One or the other of the two processes must give way or there can be ** no progress. By returning SQLITE_BUSY and not invoking the busy callback ** when A already has a read lock, we encourage A to give up and let B ** proceed. */ int sqlite3BtreeBeginTrans(Btree *p, int wrflag, int *pSchemaVersion){ BtShared *pBt = p->pBt; int rc = SQLITE_OK; | > | | | 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 | ** One or the other of the two processes must give way or there can be ** no progress. By returning SQLITE_BUSY and not invoking the busy callback ** when A already has a read lock, we encourage A to give up and let B ** proceed. */ int sqlite3BtreeBeginTrans(Btree *p, int wrflag, int *pSchemaVersion){ BtShared *pBt = p->pBt; Pager *pPager = pBt->pPager; int rc = SQLITE_OK; int bConcurrent = (p->db->eConcurrent && !ISAUTOVACUUM); sqlite3BtreeEnter(p); btreeIntegrity(p); /* If the btree is already in a write-transaction, or it ** is already in a read-transaction and a read-transaction ** is requested, this is a no-op. */ if( p->inTrans==TRANS_WRITE || (p->inTrans==TRANS_READ && !wrflag) ){ goto trans_begun; } assert( pBt->inTransaction==TRANS_WRITE || IfNotOmitAV(pBt->bDoTruncate)==0 ); if( (p->db->flags & SQLITE_ResetDatabase) && sqlite3PagerIsreadonly(pPager)==0 ){ pBt->btsFlags &= ~BTS_READ_ONLY; } /* Write transactions are not possible on a read-only database */ if( (pBt->btsFlags & BTS_READ_ONLY)!=0 && wrflag ){ rc = SQLITE_READONLY; |
︙ | ︙ | |||
3619 3620 3621 3622 3623 3624 3625 | } } #endif /* Any read-only or read-write transaction implies a read-lock on ** page 1. So if some other shared-cache client already has a write-lock ** on page 1, the transaction cannot be opened. */ | | > > > > > > > > > > > > | > | > > > | 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 | } } #endif /* Any read-only or read-write transaction implies a read-lock on ** page 1. So if some other shared-cache client already has a write-lock ** on page 1, the transaction cannot be opened. */ rc = querySharedCacheTableLock(p, SCHEMA_ROOT, READ_LOCK); if( SQLITE_OK!=rc ) goto trans_begun; pBt->btsFlags &= ~BTS_INITIALLY_EMPTY; if( pBt->nPage==0 ) pBt->btsFlags |= BTS_INITIALLY_EMPTY; do { sqlite3PagerWalDb(pPager, p->db); #ifdef SQLITE_ENABLE_SETLK_TIMEOUT /* If transitioning from no transaction directly to a write transaction, ** block for the WRITER lock first if possible. */ if( pBt->pPage1==0 && wrflag ){ assert( pBt->inTransaction==TRANS_NONE ); rc = sqlite3PagerWalWriteLock(pPager, 1); if( rc!=SQLITE_BUSY && rc!=SQLITE_OK ) break; } #endif /* Call lockBtree() until either pBt->pPage1 is populated or ** lockBtree() returns something other than SQLITE_OK. lockBtree() ** may return SQLITE_OK but leave pBt->pPage1 set to 0 if after ** reading page 1 it discovers that the page-size of the database ** file is not pBt->pageSize. In this case lockBtree() will update ** pBt->pageSize to the page-size of the file on disk. */ while( pBt->pPage1==0 && SQLITE_OK==(rc = lockBtree(pBt)) ); if( rc==SQLITE_OK && wrflag ){ if( (pBt->btsFlags & BTS_READ_ONLY)!=0 ){ rc = SQLITE_READONLY; }else{ int exFlag = bConcurrent ? -1 : (wrflag>1); rc = sqlite3PagerBegin(pPager, exFlag, sqlite3TempInMemory(p->db)); if( rc==SQLITE_OK ){ rc = newDatabase(pBt); }else if( rc==SQLITE_BUSY_SNAPSHOT && pBt->inTransaction==TRANS_NONE ){ /* if there was no transaction opened when this function was ** called and SQLITE_BUSY_SNAPSHOT is returned, change the error ** code to SQLITE_BUSY. */ rc = SQLITE_BUSY; } } } if( rc!=SQLITE_OK ){ (void)sqlite3PagerWalWriteLock(pPager, 0); unlockBtreeIfUnused(pBt); } }while( (rc&0xFF)==SQLITE_BUSY && pBt->inTransaction==TRANS_NONE && btreeInvokeBusyHandler(pBt) ); sqlite3PagerWalDb(pPager, 0); #ifdef SQLITE_ENABLE_SETLK_TIMEOUT if( rc==SQLITE_BUSY_TIMEOUT ) rc = SQLITE_BUSY; #endif if( rc==SQLITE_OK ){ if( p->inTrans==TRANS_NONE ){ pBt->nTransaction++; #ifndef SQLITE_OMIT_SHARED_CACHE if( p->sharable ){ assert( p->lock.pBtree==p && p->lock.iTable==1 ); |
︙ | ︙ | |||
3718 3719 3720 3721 3722 3723 3724 | } if( wrflag ){ /* This call makes sure that the pager has the correct number of ** open savepoints. If the second parameter is greater than 0 and ** the sub-journal is not already open, then it will be opened here. */ int nSavepoint = p->db->nSavepoint; | | | 3824 3825 3826 3827 3828 3829 3830 3831 3832 3833 3834 3835 3836 3837 3838 | } if( wrflag ){ /* This call makes sure that the pager has the correct number of ** open savepoints. If the second parameter is greater than 0 and ** the sub-journal is not already open, then it will be opened here. */ int nSavepoint = p->db->nSavepoint; rc = sqlite3PagerOpenSavepoint(pPager, nSavepoint); if( rc==SQLITE_OK && nSavepoint ){ rc = btreePtrmapBegin(pBt, nSavepoint); } } } btreeIntegrity(p); |
︙ | ︙ | |||
3752 3753 3754 3755 3756 3757 3758 | rc = pPage->isInit ? SQLITE_OK : btreeInitPage(pPage); if( rc!=SQLITE_OK ) return rc; nCell = pPage->nCell; for(i=0; i<nCell; i++){ u8 *pCell = findCell(pPage, i); | | | 3858 3859 3860 3861 3862 3863 3864 3865 3866 3867 3868 3869 3870 3871 3872 | rc = pPage->isInit ? SQLITE_OK : btreeInitPage(pPage); if( rc!=SQLITE_OK ) return rc; nCell = pPage->nCell; for(i=0; i<nCell; i++){ u8 *pCell = findCell(pPage, i); ptrmapPutOvflPtr(pPage, pPage, pCell, &rc); if( !pPage->leaf ){ Pgno childPgno = get4byte(pCell); ptrmapPut(pBt, childPgno, PTRMAP_BTREE, pgno, &rc); } } |
︙ | ︙ | |||
4072 4073 4074 4075 4076 4077 4078 | if( !pBt->autoVacuum ){ rc = SQLITE_DONE; }else{ Pgno nOrig = btreePagecount(pBt); Pgno nFree = get4byte(&pBt->pPage1->aData[36]); Pgno nFin = finalDbSize(pBt, nOrig, nFree); | | | 4178 4179 4180 4181 4182 4183 4184 4185 4186 4187 4188 4189 4190 4191 4192 | if( !pBt->autoVacuum ){ rc = SQLITE_DONE; }else{ Pgno nOrig = btreePagecount(pBt); Pgno nFree = get4byte(&pBt->pPage1->aData[36]); Pgno nFin = finalDbSize(pBt, nOrig, nFree); if( nOrig<nFin || nFree>=nOrig ){ 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); } |
︙ | ︙ | |||
4095 4096 4097 4098 4099 4100 4101 | sqlite3BtreeLeave(p); return rc; } /* ** This routine is called prior to sqlite3PagerCommit when a transaction ** is committed for an auto-vacuum database. | < < < < < | | > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > | | > | | > | 4201 4202 4203 4204 4205 4206 4207 4208 4209 4210 4211 4212 4213 4214 4215 4216 4217 4218 4219 4220 4221 4222 4223 4224 4225 4226 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 4258 4259 4260 4261 4262 4263 4264 4265 4266 4267 4268 4269 4270 4271 4272 4273 4274 4275 4276 4277 4278 4279 4280 4281 4282 4283 | sqlite3BtreeLeave(p); return rc; } /* ** This routine is called prior to sqlite3PagerCommit when a transaction ** is committed for an auto-vacuum database. */ static int autoVacuumCommit(Btree *p){ int rc = SQLITE_OK; Pager *pPager; BtShared *pBt; sqlite3 *db; VVA_ONLY( int nRef ); assert( p!=0 ); pBt = p->pBt; pPager = pBt->pPager; VVA_ONLY( nRef = sqlite3PagerRefcount(pPager); ) assert( sqlite3_mutex_held(pBt->mutex) ); invalidateAllOverflowCache(pBt); assert(pBt->autoVacuum); if( !pBt->incrVacuum ){ Pgno nFin; /* Number of pages in database after autovacuuming */ Pgno nFree; /* Number of pages on the freelist initially */ Pgno nVac; /* Number of pages to vacuum */ Pgno iFree; /* The next page to be freed */ Pgno nOrig; /* Database size before freeing */ nOrig = btreePagecount(pBt); if( PTRMAP_ISPAGE(pBt, nOrig) || nOrig==PENDING_BYTE_PAGE(pBt) ){ /* It is not possible to create a database for which the final page ** is either a pointer-map page or the pending-byte page. If one ** is encountered, this indicates corruption. */ return SQLITE_CORRUPT_BKPT; } nFree = get4byte(&pBt->pPage1->aData[36]); db = p->db; if( db->xAutovacPages ){ int iDb; for(iDb=0; ALWAYS(iDb<db->nDb); iDb++){ if( db->aDb[iDb].pBt==p ) break; } nVac = db->xAutovacPages( db->pAutovacPagesArg, db->aDb[iDb].zDbSName, nOrig, nFree, pBt->pageSize ); if( nVac>nFree ){ nVac = nFree; } if( nVac==0 ){ return SQLITE_OK; } }else{ nVac = nFree; } nFin = finalDbSize(pBt, nOrig, nVac); 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, nVac==nFree); } if( (rc==SQLITE_DONE || rc==SQLITE_OK) && nFree>0 ){ rc = sqlite3PagerWrite(pBt->pPage1->pDbPage); if( nVac==nFree ){ 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); } |
︙ | ︙ | |||
4338 4339 4340 4341 4342 4343 4344 | ** At the end of this call, the rollback journal still exists on the ** disk and we are still holding all locks, so the transaction has not ** committed. See sqlite3BtreeCommitPhaseTwo() for the second phase of the ** commit process. ** ** This call is a no-op if no write-transaction is currently active on pBt. ** | | | | | | | | | | 4471 4472 4473 4474 4475 4476 4477 4478 4479 4480 4481 4482 4483 4484 4485 4486 4487 4488 4489 4490 4491 4492 4493 4494 4495 4496 4497 4498 4499 4500 4501 4502 4503 4504 4505 4506 4507 4508 4509 4510 4511 4512 4513 4514 4515 4516 4517 4518 4519 | ** At the end of this call, the rollback journal still exists on the ** disk and we are still holding all locks, so the transaction has not ** committed. See sqlite3BtreeCommitPhaseTwo() for the second phase of the ** commit process. ** ** This call is a no-op if no write-transaction is currently active on pBt. ** ** Otherwise, sync the database file for the btree pBt. zSuperJrnl points to ** the name of a super-journal file that should be written into the ** individual journal file, or is NULL, indicating no super-journal file ** (single database transaction). ** ** When this is called, the super-journal should already have been ** created, populated with this journal pointer and synced to disk. ** ** Once this is routine has returned, the only thing required to commit ** the write-transaction for this database file is to delete the journal. */ int sqlite3BtreeCommitPhaseOne(Btree *p, const char *zSuperJrnl){ int rc = SQLITE_OK; if( p->inTrans==TRANS_WRITE ){ BtShared *pBt = p->pBt; sqlite3BtreeEnter(p); #ifndef SQLITE_OMIT_AUTOVACUUM if( pBt->autoVacuum ){ assert( ISCONCURRENT==0 ); rc = autoVacuumCommit(p); if( rc!=SQLITE_OK ){ sqlite3BtreeLeave(p); return rc; } } if( pBt->bDoTruncate ){ sqlite3PagerTruncateImage(pBt->pPager, pBt->nPage); } #endif if( rc==SQLITE_OK && ISCONCURRENT && p->db->eConcurrent==CONCURRENT_OPEN ){ rc = btreeFixUnlocked(p); } if( rc==SQLITE_OK ){ rc = sqlite3PagerCommitPhaseOne(pBt->pPager, zSuperJrnl, 0); } sqlite3BtreeLeave(p); } return rc; } /* |
︙ | ︙ | |||
4441 4442 4443 4444 4445 4446 4447 | ** drop locks. ** ** Normally, if an error occurs while the pager layer is attempting to ** finalize the underlying journal file, this function returns an error and ** the upper layer will attempt a rollback. However, if the second argument ** is non-zero then this b-tree transaction is part of a multi-file ** transaction. In this case, the transaction has already been committed | | | 4574 4575 4576 4577 4578 4579 4580 4581 4582 4583 4584 4585 4586 4587 4588 | ** drop locks. ** ** Normally, if an error occurs while the pager layer is attempting to ** finalize the underlying journal file, this function returns an error and ** the upper layer will attempt a rollback. However, if the second argument ** is non-zero then this b-tree transaction is part of a multi-file ** transaction. In this case, the transaction has already been committed ** (by deleting a super-journal file) and the caller will ignore this ** functions return code. So, even if an error occurs in the pager layer, ** reset the b-tree objects internal state to indicate that the write ** transaction has been closed. This is quite safe, as the pager will have ** transitioned to the error state. ** ** This will release the write lock on the database file. If there ** are no active cursors, it also releases the read lock. |
︙ | ︙ | |||
4469 4470 4471 4472 4473 4474 4475 | assert( pBt->inTransaction==TRANS_WRITE ); assert( pBt->nTransaction>0 ); rc = sqlite3PagerCommitPhaseTwo(pBt->pPager); if( rc!=SQLITE_OK && bCleanup==0 ){ sqlite3BtreeLeave(p); return rc; } | | | 4602 4603 4604 4605 4606 4607 4608 4609 4610 4611 4612 4613 4614 4615 4616 | assert( pBt->inTransaction==TRANS_WRITE ); assert( pBt->nTransaction>0 ); rc = sqlite3PagerCommitPhaseTwo(pBt->pPager); if( rc!=SQLITE_OK && bCleanup==0 ){ sqlite3BtreeLeave(p); return rc; } p->iBDataVersion--; /* Compensate for pPager->iDataVersion++; */ pBt->inTransaction = TRANS_READ; btreeClearHasContent(pBt); } btreeEndTransaction(p); sqlite3BtreeLeave(p); return SQLITE_OK; |
︙ | ︙ | |||
4546 4547 4548 4549 4550 4551 4552 4553 4554 4555 4556 4557 4558 4559 | } btreeReleaseAllCursorPages(p); } sqlite3BtreeLeave(pBtree); } return rc; } /* ** Rollback the transaction in progress. ** ** If tripCode is not SQLITE_OK then cursors will be invalidated (tripped). ** Only write cursors are tripped if writeOnly is true but all cursors are ** tripped if writeOnly is false. Any attempt to use | > > > > > > > > > > > > | 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 | } btreeReleaseAllCursorPages(p); } sqlite3BtreeLeave(pBtree); } return rc; } /* ** Set the pBt->nPage field correctly, according to the current ** state of the database. Assume pBt->pPage1 is valid. */ static void btreeSetNPage(BtShared *pBt, MemPage *pPage1){ int nPage = get4byte(&pPage1->aData[28]); testcase( nPage==0 ); if( nPage==0 ) sqlite3PagerPagecount(pBt->pPager, &nPage); testcase( pBt->nPage!=nPage ); pBt->nPage = nPage; } /* ** Rollback the transaction in progress. ** ** If tripCode is not SQLITE_OK then cursors will be invalidated (tripped). ** Only write cursors are tripped if writeOnly is true but all cursors are ** tripped if writeOnly is false. Any attempt to use |
︙ | ︙ | |||
4592 4593 4594 4595 4596 4597 4598 | 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)==SQLITE_OK ){ | < < < < | | 4737 4738 4739 4740 4741 4742 4743 4744 4745 4746 4747 4748 4749 4750 4751 | 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)==SQLITE_OK ){ btreeSetNPage(pBt, pPage1); releasePageOne(pPage1); } assert( countValidCursors(pBt, 1)==0 ); pBt->inTransaction = TRANS_READ; btreeClearHasContent(pBt); } |
︙ | ︙ | |||
4680 4681 4682 4683 4684 4685 4686 | rc = sqlite3PagerSavepoint(pBt->pPager, op, iSavepoint); } if( rc==SQLITE_OK ){ if( iSavepoint<0 && (pBt->btsFlags & BTS_INITIALLY_EMPTY)!=0 ){ pBt->nPage = 0; } rc = newDatabase(pBt); | | | | < | | 4821 4822 4823 4824 4825 4826 4827 4828 4829 4830 4831 4832 4833 4834 4835 4836 4837 4838 4839 | rc = sqlite3PagerSavepoint(pBt->pPager, op, iSavepoint); } if( rc==SQLITE_OK ){ if( iSavepoint<0 && (pBt->btsFlags & BTS_INITIALLY_EMPTY)!=0 ){ pBt->nPage = 0; } rc = newDatabase(pBt); btreeSetNPage(pBt, pBt->pPage1); /* pBt->nPage might be zero if the database was corrupt when ** the transaction was started. Otherwise, it must be at least 1. */ assert( CORRUPT_DB || pBt->nPage>0 ); } sqlite3BtreeLeave(p); } return rc; } /* |
︙ | ︙ | |||
4736 4737 4738 4739 4740 4741 4742 | ** will not work correctly. ** ** It is assumed that the sqlite3BtreeCursorZero() has been called ** on pCur to initialize the memory space prior to invoking this routine. */ static int btreeCursor( Btree *p, /* The btree */ | | | | > > > > | | | > | | > > > > > > > > > > > > > | | | < < | < < | 4876 4877 4878 4879 4880 4881 4882 4883 4884 4885 4886 4887 4888 4889 4890 4891 4892 4893 4894 4895 4896 4897 4898 4899 4900 4901 4902 4903 4904 4905 4906 4907 4908 4909 4910 4911 4912 4913 4914 4915 4916 4917 4918 4919 4920 4921 4922 4923 4924 4925 4926 4927 4928 4929 4930 4931 4932 4933 4934 4935 4936 4937 4938 4939 4940 4941 4942 4943 4944 4945 4946 4947 4948 4949 4950 4951 4952 4953 4954 4955 4956 4957 4958 4959 4960 4961 4962 4963 4964 4965 4966 4967 4968 4969 4970 4971 4972 4973 4974 4975 4976 4977 | ** will not work correctly. ** ** It is assumed that the sqlite3BtreeCursorZero() has been called ** on pCur to initialize the memory space prior to invoking this routine. */ static int btreeCursor( Btree *p, /* The btree */ Pgno iTable, /* Root page of table to open */ int wrFlag, /* 1 to write. 0 read-only */ struct KeyInfo *pKeyInfo, /* First arg to comparison function */ BtCursor *pCur /* Space for new cursor */ ){ BtShared *pBt = p->pBt; /* Shared b-tree handle */ BtCursor *pX; /* Looping over other all cursors */ assert( sqlite3BtreeHoldsMutex(p) ); assert( wrFlag==0 || wrFlag==BTREE_WRCSR || wrFlag==(BTREE_WRCSR|BTREE_FORDELETE) ); /* The following assert statements verify that if this is a sharable ** b-tree database, the connection is holding the required table locks, ** and that no other connection has any open cursor that conflicts with ** this lock. The iTable<1 term disables the check for corrupt schemas. */ assert( hasSharedCacheTableLock(p, iTable, pKeyInfo!=0, (wrFlag?2:1)) || iTable<1 ); assert( wrFlag==0 || !hasReadConflicts(p, iTable) ); /* Assert that the caller has opened the required transaction. */ assert( p->inTrans>TRANS_NONE ); assert( wrFlag==0 || p->inTrans==TRANS_WRITE ); assert( pBt->pPage1 && pBt->pPage1->aData ); assert( wrFlag==0 || (pBt->btsFlags & BTS_READ_ONLY)==0 ); if( wrFlag ){ allocateTempSpace(pBt); if( pBt->pTmpSpace==0 ) return SQLITE_NOMEM_BKPT; } if( iTable<=1 ){ if( iTable<1 ){ return SQLITE_CORRUPT_BKPT; }else if( btreePagecount(pBt)==0 ){ assert( wrFlag==0 ); iTable = 0; } } /* Now that no other errors can occur, finish filling in the BtCursor ** variables and link the cursor into the BtShared list. */ pCur->pgnoRoot = iTable; pCur->iPage = -1; pCur->pKeyInfo = pKeyInfo; pCur->pBtree = p; pCur->pBt = pBt; pCur->curFlags = wrFlag ? BTCF_WriteFlag : 0; pCur->curPagerFlags = wrFlag ? 0 : PAGER_GET_READONLY; /* If there are two or more cursors on the same btree, then all such ** cursors *must* have the BTCF_Multiple flag set. */ for(pX=pBt->pCursor; pX; pX=pX->pNext){ if( pX->pgnoRoot==iTable ){ pX->curFlags |= BTCF_Multiple; pCur->curFlags |= BTCF_Multiple; } } pCur->pNext = pBt->pCursor; pBt->pCursor = pCur; pCur->eState = CURSOR_INVALID; return SQLITE_OK; } static int btreeCursorWithLock( Btree *p, /* The btree */ Pgno iTable, /* Root page of table to open */ int wrFlag, /* 1 to write. 0 read-only */ struct KeyInfo *pKeyInfo, /* First arg to comparison function */ BtCursor *pCur /* Space for new cursor */ ){ int rc; sqlite3BtreeEnter(p); rc = btreeCursor(p, iTable, wrFlag, pKeyInfo, pCur); sqlite3BtreeLeave(p); return rc; } int sqlite3BtreeCursor( Btree *p, /* The btree */ Pgno iTable, /* Root page of table to open */ int wrFlag, /* 1 to write. 0 read-only */ struct KeyInfo *pKeyInfo, /* First arg to xCompare() */ BtCursor *pCur /* Write new cursor here */ ){ if( p->sharable ){ return btreeCursorWithLock(p, iTable, wrFlag, pKeyInfo, pCur); }else{ return btreeCursor(p, iTable, wrFlag, pKeyInfo, pCur); } } /* ** Return the size of a BtCursor object in bytes. ** ** This interfaces is needed so that users of cursors can preallocate ** sufficient storage to hold a cursor. The BtCursor object is opaque |
︙ | ︙ | |||
4862 4863 4864 4865 4866 4867 4868 | pPrev = pPrev->pNext; }while( ALWAYS(pPrev) ); } btreeReleaseAllCursorPages(pCur); unlockBtreeIfUnused(pBt); sqlite3_free(pCur->aOverflow); sqlite3_free(pCur->pKey); | > > > > > > | > > | 5016 5017 5018 5019 5020 5021 5022 5023 5024 5025 5026 5027 5028 5029 5030 5031 5032 5033 5034 5035 5036 5037 5038 | pPrev = pPrev->pNext; }while( ALWAYS(pPrev) ); } btreeReleaseAllCursorPages(pCur); unlockBtreeIfUnused(pBt); sqlite3_free(pCur->aOverflow); sqlite3_free(pCur->pKey); if( (pBt->openFlags & BTREE_SINGLE) && pBt->pCursor==0 ){ /* Since the BtShared is not sharable, there is no need to ** worry about the missing sqlite3BtreeLeave() call here. */ assert( pBtree->sharable==0 ); sqlite3BtreeClose(pBtree); }else{ sqlite3BtreeLeave(pBtree); } pCur->pBtree = 0; } return SQLITE_OK; } /* ** Make sure the BtCursor* given in the argument has a valid ** BtCursor.info structure. If it is not already valid, call |
︙ | ︙ | |||
4930 4931 4932 4933 4934 4935 4936 4937 4938 4939 4940 4941 4942 4943 | i64 sqlite3BtreeIntegerKey(BtCursor *pCur){ assert( cursorHoldsMutex(pCur) ); assert( pCur->eState==CURSOR_VALID ); assert( pCur->curIntKey ); getCellInfo(pCur); return pCur->info.nKey; } #ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC /* ** Return the offset into the database file for the start of the ** payload to which the cursor is pointing. */ i64 sqlite3BtreeOffset(BtCursor *pCur){ | > > > > > > > > > > > > | 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 | i64 sqlite3BtreeIntegerKey(BtCursor *pCur){ assert( cursorHoldsMutex(pCur) ); assert( pCur->eState==CURSOR_VALID ); assert( pCur->curIntKey ); getCellInfo(pCur); return pCur->info.nKey; } /* ** Pin or unpin a cursor. */ void sqlite3BtreeCursorPin(BtCursor *pCur){ assert( (pCur->curFlags & BTCF_Pinned)==0 ); pCur->curFlags |= BTCF_Pinned; } void sqlite3BtreeCursorUnpin(BtCursor *pCur){ assert( (pCur->curFlags & BTCF_Pinned)!=0 ); pCur->curFlags &= ~BTCF_Pinned; } #ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC /* ** Return the offset into the database file for the start of the ** payload to which the cursor is pointing. */ i64 sqlite3BtreeOffset(BtCursor *pCur){ |
︙ | ︙ | |||
4960 4961 4962 4963 4964 4965 4966 4967 4968 4969 4970 4971 4972 4973 | */ u32 sqlite3BtreePayloadSize(BtCursor *pCur){ assert( cursorHoldsMutex(pCur) ); assert( pCur->eState==CURSOR_VALID ); getCellInfo(pCur); return pCur->info.nPayload; } /* ** Given the page number of an overflow page in the database (parameter ** ovfl), this function finds the page number of the next page in the ** linked list of overflow pages. If possible, it uses the auto-vacuum ** pointer-map data instead of reading the content of page ovfl to do so. ** | > > > > > > > > > > > > > > > > > > > | 5134 5135 5136 5137 5138 5139 5140 5141 5142 5143 5144 5145 5146 5147 5148 5149 5150 5151 5152 5153 5154 5155 5156 5157 5158 5159 5160 5161 5162 5163 5164 5165 5166 | */ u32 sqlite3BtreePayloadSize(BtCursor *pCur){ assert( cursorHoldsMutex(pCur) ); assert( pCur->eState==CURSOR_VALID ); getCellInfo(pCur); return pCur->info.nPayload; } /* ** Return an upper bound on the size of any record for the table ** that the cursor is pointing into. ** ** This is an optimization. Everything will still work if this ** routine always returns 2147483647 (which is the largest record ** that SQLite can handle) or more. But returning a smaller value might ** prevent large memory allocations when trying to interpret a ** corrupt datrabase. ** ** The current implementation merely returns the size of the underlying ** database file. */ sqlite3_int64 sqlite3BtreeMaxRecordSize(BtCursor *pCur){ assert( cursorHoldsMutex(pCur) ); assert( pCur->eState==CURSOR_VALID ); return pCur->pBt->pageSize * (sqlite3_int64)pCur->pBt->nPage; } /* ** Given the page number of an overflow page in the database (parameter ** ovfl), this function finds the page number of the next page in the ** linked list of overflow pages. If possible, it uses the auto-vacuum ** pointer-map data instead of reading the content of page ovfl to do so. ** |
︙ | ︙ | |||
5117 5118 5119 5120 5121 5122 5123 | #ifdef SQLITE_DIRECT_OVERFLOW_READ unsigned char * const pBufStart = pBuf; /* Start of original out buffer */ #endif assert( pPage ); assert( eOp==0 || eOp==1 ); assert( pCur->eState==CURSOR_VALID ); | | > > | 5310 5311 5312 5313 5314 5315 5316 5317 5318 5319 5320 5321 5322 5323 5324 5325 5326 | #ifdef SQLITE_DIRECT_OVERFLOW_READ unsigned char * const pBufStart = pBuf; /* Start of original out buffer */ #endif assert( pPage ); assert( eOp==0 || eOp==1 ); assert( pCur->eState==CURSOR_VALID ); if( pCur->ix>=pPage->nCell ){ return SQLITE_CORRUPT_PAGE(pPage); } assert( cursorHoldsMutex(pCur) ); getCellInfo(pCur); aPayload = pCur->info.pPayload; assert( offset+amt <= pCur->info.nPayload ); assert( aPayload > pPage->aData ); |
︙ | ︙ | |||
5154 5155 5156 5157 5158 5159 5160 | if( rc==SQLITE_OK && amt>0 ){ const u32 ovflSize = pBt->usableSize - 4; /* Bytes content per ovfl page */ Pgno nextPage; nextPage = get4byte(&aPayload[pCur->info.nLocal]); | | | 5349 5350 5351 5352 5353 5354 5355 5356 5357 5358 5359 5360 5361 5362 5363 | if( rc==SQLITE_OK && amt>0 ){ const u32 ovflSize = pBt->usableSize - 4; /* Bytes content per ovfl page */ Pgno nextPage; nextPage = get4byte(&aPayload[pCur->info.nLocal]); /* If the BtCursor.aOverflow[] has not been allocated, allocate it now. ** ** The aOverflow[] array is sized at one entry for each overflow page ** in the overflow chain. The page number of the first overflow page is ** stored in aOverflow[0], etc. A value of 0 in the aOverflow[] array ** means "not yet known" (the cache is lazily populated). */ |
︙ | ︙ | |||
5193 5194 5195 5196 5197 5198 5199 5200 5201 5202 5203 5204 5205 5206 | offset = (offset%ovflSize); } } assert( rc==SQLITE_OK && amt>0 ); while( nextPage ){ /* If required, populate the overflow page-list cache. */ assert( pCur->aOverflow[iIdx]==0 || pCur->aOverflow[iIdx]==nextPage || CORRUPT_DB ); pCur->aOverflow[iIdx] = nextPage; if( offset>=ovflSize ){ /* The only reason to read this page is to obtain the page | > | 5388 5389 5390 5391 5392 5393 5394 5395 5396 5397 5398 5399 5400 5401 5402 | offset = (offset%ovflSize); } } assert( rc==SQLITE_OK && amt>0 ); while( nextPage ){ /* If required, populate the overflow page-list cache. */ if( nextPage > pBt->nPage ) return SQLITE_CORRUPT_BKPT; assert( pCur->aOverflow[iIdx]==0 || pCur->aOverflow[iIdx]==nextPage || CORRUPT_DB ); pCur->aOverflow[iIdx] = nextPage; if( offset>=ovflSize ){ /* The only reason to read this page is to obtain the page |
︙ | ︙ | |||
5247 5248 5249 5250 5251 5252 5253 5254 5255 5256 5257 5258 5259 5260 | ){ sqlite3_file *fd = sqlite3PagerFile(pBt->pPager); u8 aSave[4]; u8 *aWrite = &pBuf[-4]; assert( aWrite>=pBufStart ); /* due to (6) */ memcpy(aSave, aWrite, 4); rc = sqlite3OsRead(fd, aWrite, a+4, (i64)pBt->pageSize*(nextPage-1)); nextPage = get4byte(aWrite); memcpy(aWrite, aSave, 4); }else #endif { DbPage *pDbPage; | > | 5443 5444 5445 5446 5447 5448 5449 5450 5451 5452 5453 5454 5455 5456 5457 | ){ sqlite3_file *fd = sqlite3PagerFile(pBt->pPager); u8 aSave[4]; u8 *aWrite = &pBuf[-4]; assert( aWrite>=pBufStart ); /* due to (6) */ memcpy(aSave, aWrite, 4); rc = sqlite3OsRead(fd, aWrite, a+4, (i64)pBt->pageSize*(nextPage-1)); if( rc && nextPage>pBt->nPage ) rc = SQLITE_CORRUPT_BKPT; nextPage = get4byte(aWrite); memcpy(aWrite, aSave, 4); }else #endif { DbPage *pDbPage; |
︙ | ︙ | |||
5302 5303 5304 5305 5306 5307 5308 | ** wrong. An error is returned if "offset+amt" is larger than ** the available payload. */ int sqlite3BtreePayload(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){ assert( cursorHoldsMutex(pCur) ); assert( pCur->eState==CURSOR_VALID ); assert( pCur->iPage>=0 && pCur->pPage ); | < | 5499 5500 5501 5502 5503 5504 5505 5506 5507 5508 5509 5510 5511 5512 | ** wrong. An error is returned if "offset+amt" is larger than ** the available payload. */ int sqlite3BtreePayload(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){ assert( cursorHoldsMutex(pCur) ); assert( pCur->eState==CURSOR_VALID ); assert( pCur->iPage>=0 && pCur->pPage ); return accessPayload(pCur, offset, amt, (unsigned char*)pBuf, 0); } /* ** This variant of sqlite3BtreePayload() works even if the cursor has not ** in the CURSOR_VALID state. It is only used by the sqlite3_blob_read() ** interface. |
︙ | ︙ | |||
5364 5365 5366 5367 5368 5369 5370 | u32 *pAmt /* Write the number of available bytes here */ ){ int amt; assert( pCur!=0 && pCur->iPage>=0 && pCur->pPage); assert( pCur->eState==CURSOR_VALID ); assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) ); assert( cursorOwnsBtShared(pCur) ); | | | 5560 5561 5562 5563 5564 5565 5566 5567 5568 5569 5570 5571 5572 5573 5574 | u32 *pAmt /* Write the number of available bytes here */ ){ int amt; assert( pCur!=0 && pCur->iPage>=0 && pCur->pPage); assert( pCur->eState==CURSOR_VALID ); assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) ); assert( cursorOwnsBtShared(pCur) ); assert( pCur->ix<pCur->pPage->nCell || CORRUPT_DB ); assert( pCur->info.nSize>0 ); assert( pCur->info.pPayload>pCur->pPage->aData || CORRUPT_DB ); assert( pCur->info.pPayload<pCur->pPage->aDataEnd ||CORRUPT_DB); amt = pCur->info.nLocal; if( amt>(int)(pCur->pPage->aDataEnd - pCur->info.pPayload) ){ /* There is too little space on the page for the expected amount ** of local content. Database must be corrupt. */ |
︙ | ︙ | |||
5658 5659 5660 5661 5662 5663 5664 | assert( pCur->pgnoRoot==0 || pCur->pPage->nCell==0 ); *pRes = 1; rc = SQLITE_OK; } return rc; } | < < < < < < < < < < < < < < < < < | > > > | 5854 5855 5856 5857 5858 5859 5860 5861 5862 5863 5864 5865 5866 5867 5868 5869 5870 5871 5872 5873 5874 5875 5876 5877 5878 5879 5880 5881 5882 5883 5884 5885 5886 5887 5888 5889 5890 5891 5892 | assert( pCur->pgnoRoot==0 || pCur->pPage->nCell==0 ); *pRes = 1; rc = SQLITE_OK; } return rc; } /* Move the cursor to the last entry in the table. Return SQLITE_OK ** on success. Set *pRes to 0 if the cursor actually points to something ** or set *pRes to 1 if the table is empty. */ int sqlite3BtreeLast(BtCursor *pCur, int *pRes){ int rc; assert( cursorOwnsBtShared(pCur) ); assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) ); /* If the cursor already points to the last entry, this is a no-op. */ if( CURSOR_VALID==pCur->eState && (pCur->curFlags & BTCF_AtLast)!=0 ){ #ifdef SQLITE_DEBUG /* This block serves to assert() that the cursor really does point ** to the last entry in the b-tree. */ int ii; for(ii=0; ii<pCur->iPage; ii++){ assert( pCur->aiIdx[ii]==pCur->apPage[ii]->nCell ); } assert( pCur->ix==pCur->pPage->nCell-1 || CORRUPT_DB ); testcase( pCur->ix!=pCur->pPage->nCell-1 ); /* ^-- dbsqlfuzz b92b72e4de80b5140c30ab71372ca719b8feb618 */ assert( pCur->pPage->leaf ); #endif *pRes = 0; return SQLITE_OK; } rc = moveToRoot(pCur); if( rc==SQLITE_OK ){ assert( pCur->eState==CURSOR_VALID ); *pRes = 0; |
︙ | ︙ | |||
5718 5719 5720 5721 5722 5723 5724 | assert( pCur->pgnoRoot==0 || pCur->pPage->nCell==0 ); *pRes = 1; rc = SQLITE_OK; } return rc; } | | | < < < < | | | < < < | < < | | < | < | | < < > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | | | < < < | 5900 5901 5902 5903 5904 5905 5906 5907 5908 5909 5910 5911 5912 5913 5914 5915 5916 5917 5918 5919 5920 5921 5922 5923 5924 5925 5926 5927 5928 5929 5930 5931 5932 5933 5934 5935 5936 5937 5938 5939 5940 5941 5942 5943 5944 5945 5946 5947 5948 5949 5950 5951 5952 5953 5954 5955 5956 5957 5958 5959 5960 5961 5962 5963 5964 5965 5966 5967 5968 5969 5970 5971 5972 5973 5974 5975 5976 5977 5978 5979 5980 5981 5982 5983 5984 5985 5986 5987 5988 5989 5990 5991 5992 5993 5994 5995 5996 5997 5998 5999 6000 6001 6002 6003 6004 6005 6006 6007 6008 6009 6010 6011 6012 6013 6014 6015 6016 6017 6018 6019 6020 6021 6022 6023 6024 6025 6026 6027 6028 6029 6030 6031 6032 6033 6034 6035 6036 6037 6038 6039 6040 6041 6042 6043 6044 6045 6046 6047 6048 6049 6050 6051 6052 6053 6054 6055 6056 6057 6058 6059 6060 6061 6062 6063 6064 6065 6066 6067 6068 6069 6070 6071 6072 6073 6074 6075 6076 6077 6078 6079 6080 6081 6082 6083 6084 6085 6086 6087 6088 6089 6090 6091 6092 6093 6094 6095 6096 6097 6098 6099 6100 6101 6102 6103 6104 6105 6106 6107 6108 6109 6110 6111 6112 6113 6114 6115 6116 6117 6118 6119 6120 6121 6122 6123 6124 6125 6126 6127 6128 | assert( pCur->pgnoRoot==0 || pCur->pPage->nCell==0 ); *pRes = 1; rc = SQLITE_OK; } return rc; } /* Move the cursor so that it points to an entry in a table (a.k.a INTKEY) ** table near the key intKey. Return a success code. ** ** If an exact match is not found, then the cursor is always ** left pointing at a leaf page which would hold the entry if it ** were present. The cursor might point to an entry that comes ** before or after the key. ** ** An integer is written into *pRes which is the result of ** comparing the key with the entry to which the cursor is ** pointing. The meaning of the integer written into ** *pRes is as follows: ** ** *pRes<0 The cursor is left pointing at an entry that ** is smaller than intKey or if the table is empty ** and the cursor is therefore left point to nothing. ** ** *pRes==0 The cursor is left pointing at an entry that ** exactly matches intKey. ** ** *pRes>0 The cursor is left pointing at an entry that ** is larger than intKey. */ int sqlite3BtreeTableMoveto( BtCursor *pCur, /* The cursor to be moved */ i64 intKey, /* The table key */ int biasRight, /* If true, bias the search to the high end */ int *pRes /* Write search results here */ ){ int rc; assert( cursorOwnsBtShared(pCur) ); assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) ); assert( pRes ); assert( pCur->pKeyInfo==0 ); assert( pCur->eState!=CURSOR_VALID || pCur->curIntKey!=0 ); /* If the cursor is already positioned at the point we are trying ** to move to, then just return without doing any work */ if( pCur->eState==CURSOR_VALID && (pCur->curFlags & BTCF_ValidNKey)!=0 ){ if( pCur->info.nKey==intKey ){ *pRes = 0; return SQLITE_OK; } if( pCur->info.nKey<intKey ){ if( (pCur->curFlags & BTCF_AtLast)!=0 ){ *pRes = -1; return SQLITE_OK; } /* If the requested key is one more than the previous key, then ** try to get there using sqlite3BtreeNext() rather than a full ** binary search. This is an optimization only. The correct answer ** is still obtained without this case, only a little more slowely */ if( pCur->info.nKey+1==intKey ){ *pRes = 0; rc = sqlite3BtreeNext(pCur, 0); if( rc==SQLITE_OK ){ getCellInfo(pCur); if( pCur->info.nKey==intKey ){ return SQLITE_OK; } }else if( rc!=SQLITE_DONE ){ return rc; } } } } #ifdef SQLITE_DEBUG pCur->pBtree->nSeek++; /* Performance measurement during testing */ #endif rc = moveToRoot(pCur); if( rc ){ if( rc==SQLITE_EMPTY ){ assert( pCur->pgnoRoot==0 || pCur->pPage->nCell==0 ); *pRes = -1; return SQLITE_OK; } return rc; } assert( pCur->pPage ); assert( pCur->pPage->isInit ); assert( pCur->eState==CURSOR_VALID ); assert( pCur->pPage->nCell > 0 ); assert( pCur->iPage==0 || pCur->apPage[0]->intKey==pCur->curIntKey ); assert( pCur->curIntKey ); for(;;){ int lwr, upr, idx, c; Pgno chldPg; MemPage *pPage = pCur->pPage; u8 *pCell; /* Pointer to current cell in pPage */ /* pPage->nCell must be greater than zero. If this is the root-page ** the cursor would have been INVALID above and this for(;;) loop ** not run. If this is not the root-page, then the moveToChild() routine ** would have already detected db corruption. Similarly, pPage must ** be the right kind (index or table) of b-tree page. Otherwise ** a moveToChild() or moveToRoot() call would have detected corruption. */ assert( pPage->nCell>0 ); assert( pPage->intKey ); lwr = 0; upr = pPage->nCell-1; assert( biasRight==0 || biasRight==1 ); idx = upr>>(1-biasRight); /* idx = biasRight ? upr : (lwr+upr)/2; */ pCur->ix = (u16)idx; for(;;){ i64 nCellKey; pCell = findCellPastPtr(pPage, idx); if( pPage->intKeyLeaf ){ while( 0x80 <= *(pCell++) ){ if( pCell>=pPage->aDataEnd ){ return SQLITE_CORRUPT_PAGE(pPage); } } } getVarint(pCell, (u64*)&nCellKey); if( nCellKey<intKey ){ lwr = idx+1; if( lwr>upr ){ c = -1; break; } }else if( nCellKey>intKey ){ upr = idx-1; if( lwr>upr ){ c = +1; break; } }else{ assert( nCellKey==intKey ); pCur->ix = (u16)idx; if( !pPage->leaf ){ lwr = idx; goto moveto_table_next_layer; }else{ pCur->curFlags |= BTCF_ValidNKey; pCur->info.nKey = nCellKey; pCur->info.nSize = 0; *pRes = 0; return SQLITE_OK; } } assert( lwr+upr>=0 ); idx = (lwr+upr)>>1; /* idx = (lwr+upr)/2; */ } assert( lwr==upr+1 || !pPage->leaf ); assert( pPage->isInit ); if( pPage->leaf ){ assert( pCur->ix<pCur->pPage->nCell ); pCur->ix = (u16)idx; *pRes = c; rc = SQLITE_OK; goto moveto_table_finish; } moveto_table_next_layer: if( lwr>=pPage->nCell ){ chldPg = get4byte(&pPage->aData[pPage->hdrOffset+8]); }else{ chldPg = get4byte(findCell(pPage, lwr)); } pCur->ix = (u16)lwr; rc = moveToChild(pCur, chldPg); if( rc ) break; } moveto_table_finish: pCur->info.nSize = 0; assert( (pCur->curFlags & BTCF_ValidOvfl)==0 ); return rc; } /* Move the cursor so that it points to an entry in an index table ** near the key pIdxKey. Return a success code. ** ** If an exact match is not found, then the cursor is always ** left pointing at a leaf page which would hold the entry if it ** were present. The cursor might point to an entry that comes ** before or after the key. ** ** An integer is written into *pRes which is the result of ** comparing the key with the entry to which the cursor is ** pointing. The meaning of the integer written into ** *pRes is as follows: ** ** *pRes<0 The cursor is left pointing at an entry that ** is smaller than pIdxKey or if the table is empty ** and the cursor is therefore left point to nothing. ** ** *pRes==0 The cursor is left pointing at an entry that ** exactly matches pIdxKey. ** ** *pRes>0 The cursor is left pointing at an entry that ** is larger than pIdxKey. ** ** The pIdxKey->eqSeen field is set to 1 if there ** exists an entry in the table that exactly matches pIdxKey. */ int sqlite3BtreeIndexMoveto( BtCursor *pCur, /* The cursor to be moved */ UnpackedRecord *pIdxKey, /* Unpacked index key */ int *pRes /* Write search results here */ ){ int rc; RecordCompare xRecordCompare; assert( cursorOwnsBtShared(pCur) ); assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) ); assert( pRes ); assert( pCur->pKeyInfo!=0 ); #ifdef SQLITE_DEBUG pCur->pBtree->nSeek++; /* Performance measurement during testing */ #endif xRecordCompare = sqlite3VdbeFindCompare(pIdxKey); pIdxKey->errCode = 0; assert( pIdxKey->default_rc==1 || pIdxKey->default_rc==0 || pIdxKey->default_rc==-1 ); rc = moveToRoot(pCur); if( rc ){ if( rc==SQLITE_EMPTY ){ assert( pCur->pgnoRoot==0 || pCur->pPage->nCell==0 ); *pRes = -1; return SQLITE_OK; |
︙ | ︙ | |||
5841 5842 5843 5844 5845 5846 5847 | ** would have already detected db corruption. Similarly, pPage must ** be the right kind (index or table) of b-tree page. Otherwise ** a moveToChild() or moveToRoot() call would have detected corruption. */ assert( pPage->nCell>0 ); assert( pPage->intKey==(pIdxKey==0) ); lwr = 0; upr = pPage->nCell-1; | < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | > | | | | | | | | | | | | | | | | | > | | | | | | | | | | | | | | | | | | | | | | | | | | | < | < | | 6147 6148 6149 6150 6151 6152 6153 6154 6155 6156 6157 6158 6159 6160 6161 6162 6163 6164 6165 6166 6167 6168 6169 6170 6171 6172 6173 6174 6175 6176 6177 6178 6179 6180 6181 6182 6183 6184 6185 6186 6187 6188 6189 6190 6191 6192 6193 6194 6195 6196 6197 6198 6199 6200 6201 6202 6203 6204 6205 6206 6207 6208 6209 6210 6211 6212 6213 6214 6215 6216 6217 6218 6219 6220 6221 6222 6223 6224 6225 6226 6227 6228 6229 6230 6231 6232 6233 6234 6235 6236 6237 6238 6239 6240 6241 6242 6243 6244 6245 6246 6247 6248 6249 6250 6251 6252 6253 6254 6255 6256 6257 6258 6259 6260 6261 6262 6263 6264 6265 6266 | ** would have already detected db corruption. Similarly, pPage must ** be the right kind (index or table) of b-tree page. Otherwise ** a moveToChild() or moveToRoot() call would have detected corruption. */ assert( pPage->nCell>0 ); assert( pPage->intKey==(pIdxKey==0) ); lwr = 0; upr = pPage->nCell-1; idx = upr>>1; /* idx = (lwr+upr)/2; */ pCur->ix = (u16)idx; for(;;){ int nCell; /* Size of the pCell cell in bytes */ pCell = findCellPastPtr(pPage, idx); /* The maximum supported page-size is 65536 bytes. This means that ** the maximum number of record bytes stored on an index B-Tree ** page is less than 16384 bytes and may be stored as a 2-byte ** varint. This information is used to attempt to avoid parsing ** the entire cell by checking for the cases where the record is ** stored entirely within the b-tree page by inspecting the first ** 2 bytes of the cell. */ nCell = pCell[0]; if( nCell<=pPage->max1bytePayload ){ /* This branch runs if the record-size field of the cell is a ** single byte varint and the record fits entirely on the main ** b-tree page. */ testcase( pCell+nCell+1==pPage->aDataEnd ); c = xRecordCompare(nCell, (void*)&pCell[1], pIdxKey); }else if( !(pCell[1] & 0x80) && (nCell = ((nCell&0x7f)<<7) + pCell[1])<=pPage->maxLocal ){ /* The record-size field is a 2 byte varint and the record ** fits entirely on the main b-tree page. */ testcase( pCell+nCell+2==pPage->aDataEnd ); c = xRecordCompare(nCell, (void*)&pCell[2], pIdxKey); }else{ /* The record flows over onto one or more overflow pages. In ** this case the whole cell needs to be parsed, a buffer allocated ** and accessPayload() used to retrieve the record into the ** buffer before VdbeRecordCompare() can be called. ** ** If the record is corrupt, the xRecordCompare routine may read ** up to two varints past the end of the buffer. An extra 18 ** bytes of padding is allocated at the end of the buffer in ** case this happens. */ void *pCellKey; u8 * const pCellBody = pCell - pPage->childPtrSize; const int nOverrun = 18; /* Size of the overrun padding */ pPage->xParseCell(pPage, pCellBody, &pCur->info); nCell = (int)pCur->info.nKey; testcase( nCell<0 ); /* True if key size is 2^32 or more */ testcase( nCell==0 ); /* Invalid key size: 0x80 0x80 0x00 */ testcase( nCell==1 ); /* Invalid key size: 0x80 0x80 0x01 */ testcase( nCell==2 ); /* Minimum legal index key size */ if( nCell<2 || nCell/pCur->pBt->usableSize>pCur->pBt->nPage ){ rc = SQLITE_CORRUPT_PAGE(pPage); goto moveto_index_finish; } pCellKey = sqlite3Malloc( nCell+nOverrun ); if( pCellKey==0 ){ rc = SQLITE_NOMEM_BKPT; goto moveto_index_finish; } pCur->ix = (u16)idx; rc = accessPayload(pCur, 0, nCell, (unsigned char*)pCellKey, 0); memset(((u8*)pCellKey)+nCell,0,nOverrun); /* Fix uninit warnings */ pCur->curFlags &= ~BTCF_ValidOvfl; if( rc ){ sqlite3_free(pCellKey); goto moveto_index_finish; } c = sqlite3VdbeRecordCompare(nCell, pCellKey, pIdxKey); sqlite3_free(pCellKey); } assert( (pIdxKey->errCode!=SQLITE_CORRUPT || c==0) && (pIdxKey->errCode!=SQLITE_NOMEM || pCur->pBtree->db->mallocFailed) ); if( c<0 ){ lwr = idx+1; }else if( c>0 ){ upr = idx-1; }else{ assert( c==0 ); *pRes = 0; rc = SQLITE_OK; pCur->ix = (u16)idx; if( pIdxKey->errCode ) rc = SQLITE_CORRUPT_BKPT; goto moveto_index_finish; } if( lwr>upr ) break; assert( lwr+upr>=0 ); idx = (lwr+upr)>>1; /* idx = (lwr+upr)/2 */ } assert( lwr==upr+1 || (pPage->intKey && !pPage->leaf) ); assert( pPage->isInit ); if( pPage->leaf ){ assert( pCur->ix<pCur->pPage->nCell ); pCur->ix = (u16)idx; *pRes = c; rc = SQLITE_OK; goto moveto_index_finish; } if( lwr>=pPage->nCell ){ chldPg = get4byte(&pPage->aData[pPage->hdrOffset+8]); }else{ chldPg = get4byte(findCell(pPage, lwr)); } pCur->ix = (u16)lwr; rc = moveToChild(pCur, chldPg); if( rc ) break; } moveto_index_finish: pCur->info.nSize = 0; assert( (pCur->curFlags & BTCF_ValidOvfl)==0 ); return rc; } /* |
︙ | ︙ | |||
6056 6057 6058 6059 6060 6061 6062 | */ static SQLITE_NOINLINE int btreeNext(BtCursor *pCur){ int rc; int idx; MemPage *pPage; assert( cursorOwnsBtShared(pCur) ); | < < | | < < < < | < < < < < < < | 6325 6326 6327 6328 6329 6330 6331 6332 6333 6334 6335 6336 6337 6338 6339 6340 6341 6342 6343 6344 6345 6346 6347 6348 6349 6350 6351 6352 6353 6354 6355 6356 6357 6358 6359 6360 6361 6362 6363 6364 6365 6366 | */ static SQLITE_NOINLINE int btreeNext(BtCursor *pCur){ int rc; int idx; MemPage *pPage; assert( cursorOwnsBtShared(pCur) ); if( pCur->eState!=CURSOR_VALID ){ assert( (pCur->curFlags & BTCF_ValidOvfl)==0 ); rc = restoreCursorPosition(pCur); if( rc!=SQLITE_OK ){ return rc; } if( CURSOR_INVALID==pCur->eState ){ return SQLITE_DONE; } if( pCur->eState==CURSOR_SKIPNEXT ){ pCur->eState = CURSOR_VALID; if( pCur->skipNext>0 ) return SQLITE_OK; } } pPage = pCur->pPage; idx = ++pCur->ix; if( !pPage->isInit || sqlite3FaultSim(412) ){ /* The only known way for this to happen is for there to be a ** recursive SQL function that does a DELETE operation as part of a ** SELECT which deletes content out from under an active cursor ** in a corrupt database file where the table being DELETE-ed from ** has pages in common with the table being queried. See TH3 ** module cov1/btree78.test testcase 220 (2018-06-08) for an ** example. */ return SQLITE_CORRUPT_BKPT; } if( idx>=pPage->nCell ){ if( !pPage->leaf ){ rc = moveToChild(pCur, get4byte(&pPage->aData[pPage->hdrOffset+8])); if( rc ) return rc; return moveToLeftmost(pCur); } do{ |
︙ | ︙ | |||
6128 6129 6130 6131 6132 6133 6134 | } } int sqlite3BtreeNext(BtCursor *pCur, int flags){ MemPage *pPage; UNUSED_PARAMETER( flags ); /* Used in COMDB2 but not native SQLite */ assert( cursorOwnsBtShared(pCur) ); assert( flags==0 || flags==1 ); | < | 6384 6385 6386 6387 6388 6389 6390 6391 6392 6393 6394 6395 6396 6397 | } } int sqlite3BtreeNext(BtCursor *pCur, int flags){ MemPage *pPage; UNUSED_PARAMETER( flags ); /* Used in COMDB2 but not native SQLite */ assert( cursorOwnsBtShared(pCur) ); assert( flags==0 || flags==1 ); pCur->info.nSize = 0; pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl); if( pCur->eState!=CURSOR_VALID ) return btreeNext(pCur); pPage = pCur->pPage; if( (++pCur->ix)>=pPage->nCell ){ pCur->ix--; return btreeNext(pCur); |
︙ | ︙ | |||
6169 6170 6171 6172 6173 6174 6175 | ** use this hint, but COMDB2 does. */ static SQLITE_NOINLINE int btreePrevious(BtCursor *pCur){ int rc; MemPage *pPage; assert( cursorOwnsBtShared(pCur) ); | < < | | < < < < | 6424 6425 6426 6427 6428 6429 6430 6431 6432 6433 6434 6435 6436 6437 6438 6439 6440 6441 6442 6443 6444 6445 6446 6447 6448 6449 6450 | ** use this hint, but COMDB2 does. */ static SQLITE_NOINLINE int btreePrevious(BtCursor *pCur){ int rc; MemPage *pPage; assert( cursorOwnsBtShared(pCur) ); assert( (pCur->curFlags & (BTCF_AtLast|BTCF_ValidOvfl|BTCF_ValidNKey))==0 ); assert( pCur->info.nSize==0 ); if( pCur->eState!=CURSOR_VALID ){ rc = restoreCursorPosition(pCur); if( rc!=SQLITE_OK ){ return rc; } if( CURSOR_INVALID==pCur->eState ){ return SQLITE_DONE; } if( CURSOR_SKIPNEXT==pCur->eState ){ pCur->eState = CURSOR_VALID; if( pCur->skipNext<0 ) return SQLITE_OK; } } pPage = pCur->pPage; assert( pPage->isInit ); if( !pPage->leaf ){ int idx = pCur->ix; |
︙ | ︙ | |||
6222 6223 6224 6225 6226 6227 6228 | } } return rc; } int sqlite3BtreePrevious(BtCursor *pCur, int flags){ assert( cursorOwnsBtShared(pCur) ); assert( flags==0 || flags==1 ); | < | 6471 6472 6473 6474 6475 6476 6477 6478 6479 6480 6481 6482 6483 6484 | } } return rc; } int sqlite3BtreePrevious(BtCursor *pCur, int flags){ assert( cursorOwnsBtShared(pCur) ); assert( flags==0 || flags==1 ); UNUSED_PARAMETER( flags ); /* Used in COMDB2 but not native SQLite */ pCur->curFlags &= ~(BTCF_AtLast|BTCF_ValidOvfl|BTCF_ValidNKey); pCur->info.nSize = 0; if( pCur->eState!=CURSOR_VALID || pCur->ix==0 || pCur->pPage->leaf==0 ){ |
︙ | ︙ | |||
6475 6476 6477 6478 6479 6480 6481 | } }else{ closest = 0; } iPage = get4byte(&aData[8+closest*4]); testcase( iPage==mxPage ); | | | 6723 6724 6725 6726 6727 6728 6729 6730 6731 6732 6733 6734 6735 6736 6737 | } }else{ closest = 0; } iPage = get4byte(&aData[8+closest*4]); testcase( iPage==mxPage ); if( iPage>mxPage || iPage<2 ){ rc = SQLITE_CORRUPT_PGNO(iTrunk); goto end_allocate_page; } testcase( iPage==mxPage ); if( !searchList || (iPage==nearby || (iPage<nearby && eMode==BTALLOC_LE)) ){ |
︙ | ︙ | |||
6568 6569 6570 6571 6572 6573 6574 | if( rc!=SQLITE_OK ){ releasePage(*ppPage); *ppPage = 0; } TRACE(("ALLOCATE: %d from end of file\n", *pPgno)); } | | | 6816 6817 6818 6819 6820 6821 6822 6823 6824 6825 6826 6827 6828 6829 6830 | if( rc!=SQLITE_OK ){ releasePage(*ppPage); *ppPage = 0; } TRACE(("ALLOCATE: %d from end of file\n", *pPgno)); } assert( CORRUPT_DB || *pPgno!=PENDING_BYTE_PAGE(pBt) ); end_allocate_page: releasePage(pTrunk); releasePage(pPrevTrunk); assert( rc!=SQLITE_OK || sqlite3PagerPageRefcount((*ppPage)->pDbPage)<=1 ); assert( rc!=SQLITE_OK || (*ppPage)->isInit==0 ); return rc; |
︙ | ︙ | |||
6596 6597 6598 6599 6600 6601 6602 | */ static int freePage2(BtShared *pBt, MemPage *pMemPage, Pgno iPage){ MemPage *pTrunk = 0; /* Free-list trunk page */ Pgno iTrunk = 0; /* Page number of free-list trunk page */ MemPage *pPage1 = pBt->pPage1; /* Local reference to page 1 */ MemPage *pPage; /* Page being freed. May be NULL. */ int rc; /* Return Code */ | | > | > | 6844 6845 6846 6847 6848 6849 6850 6851 6852 6853 6854 6855 6856 6857 6858 6859 6860 6861 6862 6863 6864 6865 6866 | */ static int freePage2(BtShared *pBt, MemPage *pMemPage, Pgno iPage){ MemPage *pTrunk = 0; /* Free-list trunk page */ Pgno iTrunk = 0; /* Page number of free-list trunk page */ MemPage *pPage1 = pBt->pPage1; /* Local reference to page 1 */ MemPage *pPage; /* Page being freed. May be NULL. */ int rc; /* Return Code */ u32 nFree; /* Initial number of pages on free-list */ assert( sqlite3_mutex_held(pBt->mutex) ); assert( CORRUPT_DB || iPage>1 ); assert( !pMemPage || pMemPage->pgno==iPage ); if( NEVER(iPage<2) || iPage>pBt->nPage ){ return SQLITE_CORRUPT_BKPT; } if( pMemPage ){ pPage = pMemPage; sqlite3PagerRef(pPage->pDbPage); }else{ pPage = btreePageLookup(pBt, iPage); } |
︙ | ︙ | |||
6647 6648 6649 6650 6651 6652 6653 6654 6655 6656 6657 6658 6659 6660 | ** 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); if( rc!=SQLITE_OK ){ goto freepage_out; } nLeaf = get4byte(&pTrunk->aData[4]); assert( pBt->usableSize>32 ); | > > > > | 6897 6898 6899 6900 6901 6902 6903 6904 6905 6906 6907 6908 6909 6910 6911 6912 6913 6914 | ** 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]); if( iTrunk>btreePagecount(pBt) ){ rc = SQLITE_CORRUPT_BKPT; goto freepage_out; } rc = btreeGetPage(pBt, iTrunk, &pTrunk, 0); if( rc!=SQLITE_OK ){ goto freepage_out; } nLeaf = get4byte(&pTrunk->aData[4]); assert( pBt->usableSize>32 ); |
︙ | ︙ | |||
6725 6726 6727 6728 6729 6730 6731 | static void freePage(MemPage *pPage, int *pRC){ if( (*pRC)==SQLITE_OK ){ *pRC = freePage2(pPage->pBt, pPage, pPage->pgno); } } /* | | < | < | < < | 6979 6980 6981 6982 6983 6984 6985 6986 6987 6988 6989 6990 6991 6992 6993 6994 6995 6996 6997 6998 6999 7000 7001 7002 7003 7004 7005 7006 7007 | static void freePage(MemPage *pPage, int *pRC){ if( (*pRC)==SQLITE_OK ){ *pRC = freePage2(pPage->pBt, pPage, pPage->pgno); } } /* ** Free the overflow pages associated with the given Cell. */ static SQLITE_NOINLINE int clearCellOverflow( MemPage *pPage, /* The page that contains the Cell */ unsigned char *pCell, /* First byte of the Cell */ CellInfo *pInfo /* Size information about the cell */ ){ BtShared *pBt; Pgno ovflPgno; int rc; int nOvfl; u32 ovflPageSize; assert( sqlite3_mutex_held(pPage->pBt->mutex) ); assert( pInfo->nLocal!=pInfo->nPayload ); testcase( pCell + pInfo->nSize == pPage->aDataEnd ); testcase( pCell + (pInfo->nSize-1) == pPage->aDataEnd ); if( pCell + pInfo->nSize > pPage->aDataEnd ){ /* Cell extends past end of page */ return SQLITE_CORRUPT_PAGE(pPage); } ovflPgno = get4byte(pCell + pInfo->nSize - 4); |
︙ | ︙ | |||
6798 6799 6800 6801 6802 6803 6804 6805 6806 6807 6808 6809 6810 6811 | sqlite3PagerUnref(pOvfl->pDbPage); } if( rc ) return rc; ovflPgno = iNext; } return SQLITE_OK; } /* ** Create the byte sequence used to represent a cell on page pPage ** and write that byte sequence into pCell[]. Overflow pages are ** allocated and filled in as necessary. The calling procedure ** is responsible for making sure sufficient space has been allocated ** for pCell[]. | > > > > > > > > > > > > > > > | 7048 7049 7050 7051 7052 7053 7054 7055 7056 7057 7058 7059 7060 7061 7062 7063 7064 7065 7066 7067 7068 7069 7070 7071 7072 7073 7074 7075 7076 | sqlite3PagerUnref(pOvfl->pDbPage); } if( rc ) return rc; ovflPgno = iNext; } return SQLITE_OK; } /* Call xParseCell to compute the size of a cell. If the cell contains ** overflow, then invoke cellClearOverflow to clear out that overflow. ** STore the result code (SQLITE_OK or some error code) in rc. ** ** Implemented as macro to force inlining for performance. */ #define BTREE_CLEAR_CELL(rc, pPage, pCell, sInfo) \ pPage->xParseCell(pPage, pCell, &sInfo); \ if( sInfo.nLocal!=sInfo.nPayload ){ \ rc = clearCellOverflow(pPage, pCell, &sInfo); \ }else{ \ rc = SQLITE_OK; \ } /* ** Create the byte sequence used to represent a cell on page pPage ** and write that byte sequence into pCell[]. Overflow pages are ** allocated and filled in as necessary. The calling procedure ** is responsible for making sure sufficient space has been allocated ** for pCell[]. |
︙ | ︙ | |||
7012 7013 7014 7015 7016 7017 7018 7019 7020 7021 7022 7023 7024 7025 | int hdr; /* Beginning of the header. 0 most pages. 100 page 1 */ if( *pRC ) return; assert( idx>=0 && idx<pPage->nCell ); assert( CORRUPT_DB || sz==cellSize(pPage, idx) ); assert( sqlite3PagerIswriteable(pPage->pDbPage) ); assert( sqlite3_mutex_held(pPage->pBt->mutex) ); data = pPage->aData; ptr = &pPage->aCellIdx[2*idx]; pc = get2byte(ptr); hdr = pPage->hdrOffset; testcase( pc==get2byte(&data[hdr+5]) ); testcase( pc+sz==pPage->pBt->usableSize ); if( pc+sz > pPage->pBt->usableSize ){ | > | 7277 7278 7279 7280 7281 7282 7283 7284 7285 7286 7287 7288 7289 7290 7291 | int hdr; /* Beginning of the header. 0 most pages. 100 page 1 */ if( *pRC ) return; assert( idx>=0 && idx<pPage->nCell ); assert( CORRUPT_DB || sz==cellSize(pPage, idx) ); assert( sqlite3PagerIswriteable(pPage->pDbPage) ); assert( sqlite3_mutex_held(pPage->pBt->mutex) ); assert( pPage->nFree>=0 ); data = pPage->aData; ptr = &pPage->aCellIdx[2*idx]; pc = get2byte(ptr); hdr = pPage->hdrOffset; testcase( pc==get2byte(&data[hdr+5]) ); testcase( pc+sz==pPage->pBt->usableSize ); if( pc+sz > pPage->pBt->usableSize ){ |
︙ | ︙ | |||
7076 7077 7078 7079 7080 7081 7082 | assert( *pRC==SQLITE_OK ); assert( i>=0 && i<=pPage->nCell+pPage->nOverflow ); assert( MX_CELL(pPage->pBt)<=10921 ); assert( pPage->nCell<=MX_CELL(pPage->pBt) || CORRUPT_DB ); assert( pPage->nOverflow<=ArraySize(pPage->apOvfl) ); assert( ArraySize(pPage->apOvfl)==ArraySize(pPage->aiOvfl) ); assert( sqlite3_mutex_held(pPage->pBt->mutex) ); | < < < < < | > | 7342 7343 7344 7345 7346 7347 7348 7349 7350 7351 7352 7353 7354 7355 7356 7357 | assert( *pRC==SQLITE_OK ); assert( i>=0 && i<=pPage->nCell+pPage->nOverflow ); assert( MX_CELL(pPage->pBt)<=10921 ); assert( pPage->nCell<=MX_CELL(pPage->pBt) || CORRUPT_DB ); assert( pPage->nOverflow<=ArraySize(pPage->apOvfl) ); assert( ArraySize(pPage->apOvfl)==ArraySize(pPage->aiOvfl) ); assert( sqlite3_mutex_held(pPage->pBt->mutex) ); assert( sz==pPage->xCellSize(pPage, pCell) || CORRUPT_DB ); assert( pPage->nFree>=0 ); if( pPage->nOverflow || sz+2>pPage->nFree ){ if( pTemp ){ memcpy(pTemp, pCell, sz); pCell = pTemp; } if( iChild ){ put4byte(pCell, iChild); |
︙ | ︙ | |||
7123 7124 7125 7126 7127 7128 7129 | if( rc ){ *pRC = rc; return; } /* The allocateSpace() routine guarantees the following properties ** if it returns successfully */ assert( idx >= 0 ); assert( idx >= pPage->cellOffset+2*pPage->nCell+2 || CORRUPT_DB ); assert( idx+sz <= (int)pBt->usableSize ); pPage->nFree -= (u16)(2 + sz); | < > > > > > > > > | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 7385 7386 7387 7388 7389 7390 7391 7392 7393 7394 7395 7396 7397 7398 7399 7400 7401 7402 7403 7404 7405 7406 7407 7408 7409 7410 7411 7412 7413 7414 7415 7416 7417 7418 7419 7420 7421 7422 7423 7424 7425 7426 7427 7428 7429 7430 7431 7432 7433 7434 7435 7436 7437 7438 7439 7440 7441 7442 7443 7444 7445 7446 7447 7448 7449 7450 7451 7452 7453 7454 7455 7456 7457 7458 7459 7460 7461 7462 7463 7464 7465 7466 7467 7468 7469 7470 7471 7472 7473 7474 7475 7476 7477 7478 7479 7480 7481 7482 7483 7484 7485 7486 7487 7488 7489 7490 7491 7492 7493 7494 7495 7496 7497 7498 7499 7500 7501 7502 7503 7504 7505 7506 7507 7508 7509 7510 7511 7512 7513 7514 7515 7516 | if( rc ){ *pRC = rc; return; } /* The allocateSpace() routine guarantees the following properties ** if it returns successfully */ assert( idx >= 0 ); assert( idx >= pPage->cellOffset+2*pPage->nCell+2 || CORRUPT_DB ); assert( idx+sz <= (int)pBt->usableSize ); pPage->nFree -= (u16)(2 + sz); if( iChild ){ /* In a corrupt database where an entry in the cell index section of ** a btree page has a value of 3 or less, the pCell value might point ** as many as 4 bytes in front of the start of the aData buffer for ** the source page. Make sure this does not cause problems by not ** reading the first 4 bytes */ memcpy(&data[idx+4], pCell+4, sz-4); put4byte(&data[idx], iChild); }else{ memcpy(&data[idx], pCell, sz); } pIns = pPage->aCellIdx + i*2; memmove(pIns+2, pIns, 2*(pPage->nCell - i)); put2byte(pIns, idx); pPage->nCell++; /* increment the cell count */ if( (++data[pPage->hdrOffset+4])==0 ) data[pPage->hdrOffset+3]++; assert( get2byte(&data[pPage->hdrOffset+3])==pPage->nCell || CORRUPT_DB ); if( REQUIRE_PTRMAP ){ /* The cell may contain a pointer to an overflow page. If so, write ** the entry for the overflow page into the pointer map. */ ptrmapPutOvflPtr(pPage, pPage, pCell, pRC); } } } /* ** The following parameters determine how many adjacent pages get involved ** in a balancing operation. NN is the number of neighbors on either side ** of the page that participate in the balancing operation. NB is the ** total number of pages that participate, including the target page and ** NN neighbors on either side. ** ** The minimum value of NN is 1 (of course). Increasing NN above 1 ** (to 2 or 3) gives a modest improvement in SELECT and DELETE performance ** in exchange for a larger degradation in INSERT and UPDATE performance. ** The value of NN appears to give the best results overall. ** ** (Later:) The description above makes it seem as if these values are ** tunable - as if you could change them and recompile and it would all work. ** But that is unlikely. NB has been 3 since the inception of SQLite and ** we have never tested any other value. */ #define NN 1 /* Number of neighbors on either side of pPage */ #define NB 3 /* (NN*2+1): Total pages involved in the balance */ /* ** A CellArray object contains a cache of pointers and sizes for a ** consecutive sequence of cells that might be held on multiple pages. ** ** The cells in this array are the divider cell or cells from the pParent ** page plus up to three child pages. There are a total of nCell cells. ** ** pRef is a pointer to one of the pages that contributes cells. This is ** used to access information such as MemPage.intKey and MemPage.pBt->pageSize ** which should be common to all pages that contribute cells to this array. ** ** apCell[] and szCell[] hold, respectively, pointers to the start of each ** cell and the size of each cell. Some of the apCell[] pointers might refer ** to overflow cells. In other words, some apCel[] pointers might not point ** to content area of the pages. ** ** A szCell[] of zero means the size of that cell has not yet been computed. ** ** The cells come from as many as four different pages: ** ** ----------- ** | Parent | ** ----------- ** / | \ ** / | \ ** --------- --------- --------- ** |Child-1| |Child-2| |Child-3| ** --------- --------- --------- ** ** The order of cells is in the array is for an index btree is: ** ** 1. All cells from Child-1 in order ** 2. The first divider cell from Parent ** 3. All cells from Child-2 in order ** 4. The second divider cell from Parent ** 5. All cells from Child-3 in order ** ** For a table-btree (with rowids) the items 2 and 4 are empty because ** content exists only in leaves and there are no divider cells. ** ** For an index btree, the apEnd[] array holds pointer to the end of page ** for Child-1, the Parent, Child-2, the Parent (again), and Child-3, ** respectively. The ixNx[] array holds the number of cells contained in ** each of these 5 stages, and all stages to the left. Hence: ** ** ixNx[0] = Number of cells in Child-1. ** ixNx[1] = Number of cells in Child-1 plus 1 for first divider. ** ixNx[2] = Number of cells in Child-1 and Child-2 + 1 for 1st divider. ** ixNx[3] = Number of cells in Child-1 and Child-2 + both divider cells ** ixNx[4] = Total number of cells. ** ** For a table-btree, the concept is similar, except only apEnd[0]..apEnd[2] ** are used and they point to the leaf pages only, and the ixNx value are: ** ** ixNx[0] = Number of cells in Child-1. ** ixNx[1] = Number of cells in Child-1 and Child-2. ** ixNx[2] = Total number of cells. ** ** Sometimes when deleting, a child page can have zero cells. In those ** cases, ixNx[] entries with higher indexes, and the corresponding apEnd[] ** entries, shift down. The end result is that each ixNx[] entry should ** be larger than the previous */ typedef struct CellArray CellArray; struct CellArray { int nCell; /* Number of cells in apCell[] */ MemPage *pRef; /* Reference page */ u8 **apCell; /* All cells begin balanced */ u16 *szCell; /* Local size of all cells in apCell[] */ u8 *apEnd[NB*2]; /* MemPage.aDataEnd values */ int ixNx[NB*2]; /* Index of at which we move to the next apEnd[] */ }; /* ** Make sure the cell sizes at idx, idx+1, ..., idx+N-1 have been ** computed. */ static void populateCellCache(CellArray *p, int idx, int N){ |
︙ | ︙ | |||
7203 7204 7205 7206 7207 7208 7209 | ** function works around problems caused by this by making a copy of any ** such cells before overwriting the page data. ** ** The MemPage.nFree field is invalidated by this function. It is the ** responsibility of the caller to set it correctly. */ static int rebuildPage( | > | < | > > | > > > | > > | > > < > | > > | | > > > > > | | | | > > > > > | < | | | | | 7553 7554 7555 7556 7557 7558 7559 7560 7561 7562 7563 7564 7565 7566 7567 7568 7569 7570 7571 7572 7573 7574 7575 7576 7577 7578 7579 7580 7581 7582 7583 7584 7585 7586 7587 7588 7589 7590 7591 7592 7593 7594 7595 7596 7597 7598 7599 7600 7601 7602 7603 7604 7605 7606 7607 7608 7609 7610 7611 7612 7613 7614 7615 7616 7617 7618 7619 7620 7621 7622 7623 7624 7625 7626 7627 7628 7629 7630 7631 7632 7633 7634 7635 7636 7637 | ** function works around problems caused by this by making a copy of any ** such cells before overwriting the page data. ** ** The MemPage.nFree field is invalidated by this function. It is the ** responsibility of the caller to set it correctly. */ static int rebuildPage( CellArray *pCArray, /* Content to be added to page pPg */ int iFirst, /* First cell in pCArray to use */ int nCell, /* Final number of cells on page */ MemPage *pPg /* The page to be reconstructed */ ){ const int hdr = pPg->hdrOffset; /* Offset of header on pPg */ u8 * const aData = pPg->aData; /* Pointer to data for pPg */ const int usableSize = pPg->pBt->usableSize; u8 * const pEnd = &aData[usableSize]; int i = iFirst; /* Which cell to copy from pCArray*/ u32 j; /* Start of cell content area */ int iEnd = i+nCell; /* Loop terminator */ u8 *pCellptr = pPg->aCellIdx; u8 *pTmp = sqlite3PagerTempSpace(pPg->pBt->pPager); u8 *pData; int k; /* Current slot in pCArray->apEnd[] */ u8 *pSrcEnd; /* Current pCArray->apEnd[k] value */ assert( i<iEnd ); j = get2byte(&aData[hdr+5]); if( NEVER(j>(u32)usableSize) ){ j = 0; } memcpy(&pTmp[j], &aData[j], usableSize - j); for(k=0; pCArray->ixNx[k]<=i && ALWAYS(k<NB*2); k++){} pSrcEnd = pCArray->apEnd[k]; pData = pEnd; while( 1/*exit by break*/ ){ u8 *pCell = pCArray->apCell[i]; u16 sz = pCArray->szCell[i]; assert( sz>0 ); if( SQLITE_WITHIN(pCell,aData+j,pEnd) ){ if( ((uptr)(pCell+sz))>(uptr)pEnd ) return SQLITE_CORRUPT_BKPT; pCell = &pTmp[pCell - aData]; }else if( (uptr)(pCell+sz)>(uptr)pSrcEnd && (uptr)(pCell)<(uptr)pSrcEnd ){ return SQLITE_CORRUPT_BKPT; } pData -= sz; put2byte(pCellptr, (pData - aData)); pCellptr += 2; if( pData < pCellptr ) return SQLITE_CORRUPT_BKPT; memmove(pData, pCell, sz); assert( sz==pPg->xCellSize(pPg, pCell) || CORRUPT_DB ); i++; if( i>=iEnd ) break; if( pCArray->ixNx[k]<=i ){ k++; pSrcEnd = pCArray->apEnd[k]; } } /* The pPg->nFree field is now set incorrectly. The caller will fix it. */ pPg->nCell = nCell; pPg->nOverflow = 0; put2byte(&aData[hdr+1], 0); put2byte(&aData[hdr+3], pPg->nCell); put2byte(&aData[hdr+5], pData - aData); aData[hdr+7] = 0x00; return SQLITE_OK; } /* ** The pCArray objects contains pointers to b-tree cells and the cell sizes. ** This function attempts to add the cells stored in the array to page pPg. ** If it cannot (because the page needs to be defragmented before the cells ** will fit), non-zero is returned. Otherwise, if the cells are added ** successfully, zero is returned. ** ** Argument pCellptr points to the first entry in the cell-pointer array ** (part of page pPg) to populate. After cell apCell[0] is written to the ** page body, a 16-bit offset is written to pCellptr. And so on, for each ** cell in the array. It is the responsibility of the caller to ensure ** that it is safe to overwrite this part of the cell-pointer array. ** |
︙ | ︙ | |||
7275 7276 7277 7278 7279 7280 7281 | ** all cells - not just those inserted by the current call). If the content ** area must be extended to before this point in order to accomodate all ** cells in apCell[], then the cells do not fit and non-zero is returned. */ static int pageInsertArray( MemPage *pPg, /* Page to add cells to */ u8 *pBegin, /* End of cell-pointer array */ | | | | | | > > | > > > > | > > > > > > > > > > > > > | | | | | | 7645 7646 7647 7648 7649 7650 7651 7652 7653 7654 7655 7656 7657 7658 7659 7660 7661 7662 7663 7664 7665 7666 7667 7668 7669 7670 7671 7672 7673 7674 7675 7676 7677 7678 7679 7680 7681 7682 7683 7684 7685 7686 7687 7688 7689 7690 7691 7692 7693 7694 7695 7696 7697 7698 7699 7700 7701 7702 7703 7704 7705 7706 7707 7708 7709 7710 7711 7712 7713 7714 7715 7716 7717 | ** all cells - not just those inserted by the current call). If the content ** area must be extended to before this point in order to accomodate all ** cells in apCell[], then the cells do not fit and non-zero is returned. */ static int pageInsertArray( MemPage *pPg, /* Page to add cells to */ u8 *pBegin, /* End of cell-pointer array */ u8 **ppData, /* IN/OUT: Page content-area pointer */ u8 *pCellptr, /* Pointer to cell-pointer area */ int iFirst, /* Index of first cell to add */ int nCell, /* Number of cells to add to pPg */ CellArray *pCArray /* Array of cells */ ){ int i = iFirst; /* Loop counter - cell index to insert */ u8 *aData = pPg->aData; /* Complete page */ u8 *pData = *ppData; /* Content area. A subset of aData[] */ int iEnd = iFirst + nCell; /* End of loop. One past last cell to ins */ int k; /* Current slot in pCArray->apEnd[] */ u8 *pEnd; /* Maximum extent of cell data */ assert( CORRUPT_DB || pPg->hdrOffset==0 ); /* Never called on page 1 */ if( iEnd<=iFirst ) return 0; for(k=0; pCArray->ixNx[k]<=i && ALWAYS(k<NB*2); k++){} pEnd = pCArray->apEnd[k]; while( 1 /*Exit by break*/ ){ int sz, rc; u8 *pSlot; assert( pCArray->szCell[i]!=0 ); sz = pCArray->szCell[i]; if( (aData[1]==0 && aData[2]==0) || (pSlot = pageFindSlot(pPg,sz,&rc))==0 ){ if( (pData - pBegin)<sz ) return 1; pData -= sz; pSlot = pData; } /* pSlot and pCArray->apCell[i] will never overlap on a well-formed ** database. But they might for a corrupt database. Hence use memmove() ** since memcpy() sends SIGABORT with overlapping buffers on OpenBSD */ assert( (pSlot+sz)<=pCArray->apCell[i] || pSlot>=(pCArray->apCell[i]+sz) || CORRUPT_DB ); if( (uptr)(pCArray->apCell[i]+sz)>(uptr)pEnd && (uptr)(pCArray->apCell[i])<(uptr)pEnd ){ assert( CORRUPT_DB ); (void)SQLITE_CORRUPT_BKPT; return 1; } memmove(pSlot, pCArray->apCell[i], sz); put2byte(pCellptr, (pSlot - aData)); pCellptr += 2; i++; if( i>=iEnd ) break; if( pCArray->ixNx[k]<=i ){ k++; pEnd = pCArray->apEnd[k]; } } *ppData = pData; return 0; } /* ** The pCArray object contains pointers to b-tree cells and their sizes. ** ** This function adds the space associated with each cell in the array ** that is currently stored within the body of pPg to the pPg free-list. ** The cell-pointers and other fields of the page are not updated. ** ** This function returns the total number of cells added to the free-list. */ static int pageFreeArray( MemPage *pPg, /* Page to edit */ int iFirst, /* First cell to delete */ int nCell, /* Cells to delete */ |
︙ | ︙ | |||
7348 7349 7350 7351 7352 7353 7354 | if( pFree!=(pCell + sz) ){ if( pFree ){ assert( pFree>aData && (pFree - aData)<65536 ); freeSpace(pPg, (u16)(pFree - aData), szFree); } pFree = pCell; szFree = sz; | | > > | | | | 7737 7738 7739 7740 7741 7742 7743 7744 7745 7746 7747 7748 7749 7750 7751 7752 7753 7754 7755 7756 7757 7758 7759 7760 7761 7762 7763 7764 7765 7766 7767 7768 7769 7770 7771 | if( pFree!=(pCell + sz) ){ if( pFree ){ assert( pFree>aData && (pFree - aData)<65536 ); freeSpace(pPg, (u16)(pFree - aData), szFree); } pFree = pCell; szFree = sz; if( pFree+sz>pEnd ){ return 0; } }else{ pFree = pCell; szFree += sz; } nRet++; } } if( pFree ){ assert( pFree>aData && (pFree - aData)<65536 ); freeSpace(pPg, (u16)(pFree - aData), szFree); } return nRet; } /* ** pCArray contains pointers to and sizes of all cells in the page being ** balanced. The current page, pPg, has pPg->nCell cells starting with ** pCArray->apCell[iOld]. After balancing, this page should hold nNew cells ** starting at apCell[iNew]. ** ** This routine makes the necessary adjustments to pPg so that it contains ** the correct cells after being balanced. ** ** The pPg->nFree field is invalid when this function returns. It is the ** responsibility of the caller to set it correctly. |
︙ | ︙ | |||
7398 7399 7400 7401 7402 7403 7404 7405 7406 7407 7408 7409 7410 | #ifdef SQLITE_DEBUG u8 *pTmp = sqlite3PagerTempSpace(pPg->pBt->pPager); memcpy(pTmp, aData, pPg->pBt->usableSize); #endif /* Remove cells from the start and end of the page */ if( iOld<iNew ){ int nShift = pageFreeArray(pPg, iOld, iNew-iOld, pCArray); memmove(pPg->aCellIdx, &pPg->aCellIdx[nShift*2], nCell*2); nCell -= nShift; } if( iNewEnd < iOldEnd ){ | > > | > > > > > | > > > | 7789 7790 7791 7792 7793 7794 7795 7796 7797 7798 7799 7800 7801 7802 7803 7804 7805 7806 7807 7808 7809 7810 7811 7812 7813 7814 7815 7816 7817 7818 7819 7820 7821 7822 7823 7824 7825 7826 7827 7828 7829 7830 7831 7832 7833 7834 7835 7836 7837 7838 7839 7840 7841 7842 7843 7844 7845 7846 7847 7848 7849 7850 7851 7852 | #ifdef SQLITE_DEBUG u8 *pTmp = sqlite3PagerTempSpace(pPg->pBt->pPager); memcpy(pTmp, aData, pPg->pBt->usableSize); #endif /* Remove cells from the start and end of the page */ assert( nCell>=0 ); if( iOld<iNew ){ int nShift = pageFreeArray(pPg, iOld, iNew-iOld, pCArray); if( NEVER(nShift>nCell) ) return SQLITE_CORRUPT_BKPT; memmove(pPg->aCellIdx, &pPg->aCellIdx[nShift*2], nCell*2); nCell -= nShift; } if( iNewEnd < iOldEnd ){ int nTail = pageFreeArray(pPg, iNewEnd, iOldEnd - iNewEnd, pCArray); assert( nCell>=nTail ); nCell -= nTail; } pData = &aData[get2byteNotZero(&aData[hdr+5])]; if( pData<pBegin ) goto editpage_fail; if( NEVER(pData>pPg->aDataEnd) ) goto editpage_fail; /* Add cells to the start of the page */ if( iNew<iOld ){ int nAdd = MIN(nNew,iOld-iNew); assert( (iOld-iNew)<nNew || nCell==0 || CORRUPT_DB ); assert( nAdd>=0 ); pCellptr = pPg->aCellIdx; memmove(&pCellptr[nAdd*2], pCellptr, nCell*2); if( pageInsertArray( pPg, pBegin, &pData, pCellptr, iNew, nAdd, pCArray ) ) goto editpage_fail; nCell += nAdd; } /* Add any overflow cells */ for(i=0; i<pPg->nOverflow; i++){ int iCell = (iOld + pPg->aiOvfl[i]) - iNew; if( iCell>=0 && iCell<nNew ){ pCellptr = &pPg->aCellIdx[iCell * 2]; if( nCell>iCell ){ memmove(&pCellptr[2], pCellptr, (nCell - iCell) * 2); } nCell++; cachedCellSize(pCArray, iCell+iNew); if( pageInsertArray( pPg, pBegin, &pData, pCellptr, iCell+iNew, 1, pCArray ) ) goto editpage_fail; } } /* Append cells to the end of the page */ assert( nCell>=0 ); pCellptr = &pPg->aCellIdx[nCell*2]; if( pageInsertArray( pPg, pBegin, &pData, pCellptr, iNew+nCell, nNew-nCell, pCArray ) ) goto editpage_fail; pPg->nCell = nNew; |
︙ | ︙ | |||
7466 7467 7468 7469 7470 7471 7472 | } #endif return SQLITE_OK; editpage_fail: /* Unable to edit this page. Rebuild it from scratch instead. */ populateCellCache(pCArray, iNew, nNew); | | < < < < < < < < < < < < < < < | 7867 7868 7869 7870 7871 7872 7873 7874 7875 7876 7877 7878 7879 7880 7881 7882 | } #endif return SQLITE_OK; editpage_fail: /* Unable to edit this page. Rebuild it from scratch instead. */ populateCellCache(pCArray, iNew, nNew); return rebuildPage(pCArray, iNew, nNew, pPg); } #ifndef SQLITE_OMIT_QUICKBALANCE /* ** This version of balance() handles the common special case where ** a new entry is being inserted on the extreme right-end of the ** tree, in other words, when the new entry will become the largest |
︙ | ︙ | |||
7518 7519 7520 7521 7522 7523 7524 | MemPage *pNew; /* Newly allocated page */ int rc; /* Return Code */ Pgno pgnoNew; /* Page number of pNew */ assert( sqlite3_mutex_held(pPage->pBt->mutex) ); assert( sqlite3PagerIswriteable(pParent->pDbPage) ); assert( pPage->nOverflow==1 ); | | > > > | > > > > > > | | > > > | | 7904 7905 7906 7907 7908 7909 7910 7911 7912 7913 7914 7915 7916 7917 7918 7919 7920 7921 7922 7923 7924 7925 7926 7927 7928 7929 7930 7931 7932 7933 7934 7935 7936 7937 7938 7939 7940 7941 7942 7943 7944 7945 7946 7947 7948 7949 7950 7951 7952 7953 7954 7955 7956 7957 7958 7959 7960 7961 7962 7963 7964 7965 | MemPage *pNew; /* Newly allocated page */ int rc; /* Return Code */ Pgno pgnoNew; /* Page number of pNew */ assert( sqlite3_mutex_held(pPage->pBt->mutex) ); assert( sqlite3PagerIswriteable(pParent->pDbPage) ); assert( pPage->nOverflow==1 ); if( pPage->nCell==0 ) return SQLITE_CORRUPT_BKPT; /* dbfuzz001.test */ assert( pPage->nFree>=0 ); assert( pParent->nFree>=0 ); /* Allocate a new page. This page will become the right-sibling of ** pPage. Make the parent page writable, so that the new divider cell ** may be inserted. If both these operations are successful, proceed. */ rc = allocateBtreePage(pBt, &pNew, &pgnoNew, 0, 0); if( rc==SQLITE_OK ){ u8 *pOut = &pSpace[4]; u8 *pCell = pPage->apOvfl[0]; u16 szCell = pPage->xCellSize(pPage, pCell); u8 *pStop; CellArray b; assert( sqlite3PagerIswriteable(pNew->pDbPage) ); assert( CORRUPT_DB || pPage->aData[0]==(PTF_INTKEY|PTF_LEAFDATA|PTF_LEAF) ); zeroPage(pNew, PTF_INTKEY|PTF_LEAFDATA|PTF_LEAF); b.nCell = 1; b.pRef = pPage; b.apCell = &pCell; b.szCell = &szCell; b.apEnd[0] = pPage->aDataEnd; b.ixNx[0] = 2; rc = rebuildPage(&b, 0, 1, pNew); if( NEVER(rc) ){ releasePage(pNew); return rc; } pNew->nFree = pBt->usableSize - pNew->cellOffset - 2 - szCell; /* If this is an auto-vacuum database, update the pointer map ** with entries for the new page, and any pointer from the ** cell on the page to an overflow page. If either of these ** operations fails, the return code is set, but the contents ** of the parent page are still manipulated by thh code below. ** That is Ok, at this point the parent page is guaranteed to ** be marked as dirty. Returning an error code will cause a ** rollback, undoing any changes made to the parent page. */ if( REQUIRE_PTRMAP ){ ptrmapPut(pBt, pgnoNew, PTRMAP_BTREE, pParent->pgno, &rc); if( szCell>pNew->minLocal ){ ptrmapPutOvflPtr(pNew, pNew, pCell, &rc); } } /* Create a divider cell to insert into pParent. The divider cell ** consists of a 4-byte page number (the page number of pPage) and ** a variable length key value (which must be the same value as the ** largest key on pPage). |
︙ | ︙ | |||
7679 7680 7681 7682 7683 7684 7685 7686 7687 7688 7689 7690 7691 7692 | /* Reinitialize page pTo so that the contents of the MemPage structure ** match the new data. The initialization of pTo can actually fail under ** fairly obscure circumstances, even though it is a copy of initialized ** page pFrom. */ pTo->isInit = 0; rc = btreeInitPage(pTo); if( rc!=SQLITE_OK ){ *pRC = rc; return; } /* If this is an auto-vacuum database, update the pointer-map entries ** for any b-tree or overflow pages that pTo now contains the pointers to. | > | 8077 8078 8079 8080 8081 8082 8083 8084 8085 8086 8087 8088 8089 8090 8091 | /* Reinitialize page pTo so that the contents of the MemPage structure ** match the new data. The initialization of pTo can actually fail under ** fairly obscure circumstances, even though it is a copy of initialized ** page pFrom. */ pTo->isInit = 0; rc = btreeInitPage(pTo); if( rc==SQLITE_OK ) rc = btreeComputeFreeSpace(pTo); if( rc!=SQLITE_OK ){ *pRC = rc; return; } /* If this is an auto-vacuum database, update the pointer-map entries ** for any b-tree or overflow pages that pTo now contains the pointers to. |
︙ | ︙ | |||
7768 7769 7770 7771 7772 7773 7774 | int szNew[NB+2]; /* Combined size of cells placed on i-th page */ u8 *aSpace1; /* Space for copies of dividers cells */ Pgno pgno; /* Temp var to store a page number in */ u8 abDone[NB+2]; /* True after i'th new page is populated */ Pgno aPgno[NB+2]; /* Page numbers of new pages before shuffling */ Pgno aPgOrder[NB+2]; /* Copy of aPgno[] used for sorting pages */ u16 aPgFlags[NB+2]; /* flags field of new pages before shuffling */ | | | < < < < < > | 8167 8168 8169 8170 8171 8172 8173 8174 8175 8176 8177 8178 8179 8180 8181 8182 8183 8184 8185 8186 8187 8188 8189 8190 8191 8192 8193 8194 8195 8196 8197 8198 8199 8200 | int szNew[NB+2]; /* Combined size of cells placed on i-th page */ u8 *aSpace1; /* Space for copies of dividers cells */ Pgno pgno; /* Temp var to store a page number in */ u8 abDone[NB+2]; /* True after i'th new page is populated */ Pgno aPgno[NB+2]; /* Page numbers of new pages before shuffling */ Pgno aPgOrder[NB+2]; /* Copy of aPgno[] used for sorting pages */ u16 aPgFlags[NB+2]; /* flags field of new pages before shuffling */ CellArray b; /* Parsed information on cells being balanced */ memset(abDone, 0, sizeof(abDone)); memset(&b, 0, sizeof(b)); pBt = pParent->pBt; assert( sqlite3_mutex_held(pBt->mutex) ); assert( sqlite3PagerIswriteable(pParent->pDbPage) ); /* At this point pParent may have at most one overflow cell. And if ** this overflow cell is present, it must be the cell with ** index iParentIdx. This scenario comes about when this function ** is called (indirectly) from sqlite3BtreeDelete(). */ assert( pParent->nOverflow==0 || pParent->nOverflow==1 ); assert( pParent->nOverflow==0 || pParent->aiOvfl[0]==iParentIdx ); if( !aOvflSpace ){ return SQLITE_NOMEM_BKPT; } assert( pParent->nFree>=0 ); /* Find the sibling pages to balance. Also locate the cells in pParent ** that divide the siblings. An attempt is made to find NN siblings on ** either side of pPage. More siblings are taken from one side, however, ** if there are fewer than NN siblings on the other side. If pParent ** has NB or fewer children then all children of pParent are taken. ** |
︙ | ︙ | |||
7826 7827 7828 7829 7830 7831 7832 | 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 ){ | > | > > > > > > | > | | 8221 8222 8223 8224 8225 8226 8227 8228 8229 8230 8231 8232 8233 8234 8235 8236 8237 8238 8239 8240 8241 8242 8243 8244 8245 8246 8247 8248 8249 8250 | 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 ){ if( rc==SQLITE_OK ){ rc = getAndInitPage(pBt, pgno, &apOld[i], 0, 0); } if( rc ){ memset(apOld, 0, (i+1)*sizeof(MemPage*)); goto balance_cleanup; } setMempageRoot(apOld[i], pgnoRoot); if( apOld[i]->nFree<0 ){ rc = btreeComputeFreeSpace(apOld[i]); if( rc ){ memset(apOld, 0, (i)*sizeof(MemPage*)); goto balance_cleanup; } } nMaxCells += apOld[i]->nCell + ArraySize(pParent->apOvfl); if( (i--)==0 ) break; if( pParent->nOverflow && i+nxDiv==pParent->aiOvfl[0] ){ apDiv[i] = pParent->apOvfl[0]; pgno = get4byte(apDiv[i]); szNew[i] = pParent->xCellSize(pParent, apDiv[i]); pParent->nOverflow = 0; |
︙ | ︙ | |||
7861 7862 7863 7864 7865 7866 7867 7868 | ** the dropCell() routine will overwrite the entire cell with zeroes. ** In this case, temporarily copy the cell into the aOvflSpace[] ** buffer. It will be copied out again as soon as the aSpace[] buffer ** is allocated. */ if( pBt->btsFlags & BTS_FAST_SECURE ){ int iOff; iOff = SQLITE_PTR_TO_INT(apDiv[i]) - SQLITE_PTR_TO_INT(pParent->aData); | > > | < < < < | | 8264 8265 8266 8267 8268 8269 8270 8271 8272 8273 8274 8275 8276 8277 8278 8279 8280 8281 8282 8283 8284 8285 8286 8287 8288 8289 8290 8291 8292 8293 8294 8295 8296 8297 8298 8299 8300 8301 8302 | ** the dropCell() routine will overwrite the entire cell with zeroes. ** In this case, temporarily copy the cell into the aOvflSpace[] ** buffer. It will be copied out again as soon as the aSpace[] buffer ** is allocated. */ if( pBt->btsFlags & BTS_FAST_SECURE ){ int iOff; /* If the following if() condition is not true, the db is corrupted. ** The call to dropCell() below will detect this. */ iOff = SQLITE_PTR_TO_INT(apDiv[i]) - SQLITE_PTR_TO_INT(pParent->aData); if( (iOff+szNew[i])<=(int)pBt->usableSize ){ memcpy(&aOvflSpace[iOff], apDiv[i], szNew[i]); apDiv[i] = &aOvflSpace[apDiv[i]-pParent->aData]; } } dropCell(pParent, i+nxDiv-pParent->nOverflow, szNew[i], &rc); } } /* Make nMaxCells a multiple of 4 in order to preserve 8-byte ** alignment */ nMaxCells = (nMaxCells + 3)&~3; /* ** Allocate space for memory structures */ szScratch = nMaxCells*sizeof(u8*) /* b.apCell */ + nMaxCells*sizeof(u16) /* b.szCell */ + pBt->pageSize; /* aSpace1 */ assert( szScratch<=7*(int)pBt->pageSize ); b.apCell = sqlite3StackAllocRaw(0, szScratch ); if( b.apCell==0 ){ rc = SQLITE_NOMEM_BKPT; goto balance_cleanup; } b.szCell = (u16*)&b.apCell[nMaxCells]; aSpace1 = (u8*)&b.szCell[nMaxCells]; |
︙ | ︙ | |||
7923 7924 7925 7926 7927 7928 7929 7930 7931 7932 7933 7934 7935 7936 | for(i=0; i<nOld; i++){ MemPage *pOld = apOld[i]; int limit = pOld->nCell; u8 *aData = pOld->aData; u16 maskPage = pOld->maskPage; u8 *piCell = aData + pOld->cellOffset; u8 *piEnd; /* Verify that all sibling pages are of the same "type" (table-leaf, ** table-interior, index-leaf, or index-interior). */ if( pOld->aData[0]!=apOld[0]->aData[0] ){ rc = SQLITE_CORRUPT_BKPT; goto balance_cleanup; | > | 8324 8325 8326 8327 8328 8329 8330 8331 8332 8333 8334 8335 8336 8337 8338 | for(i=0; i<nOld; i++){ MemPage *pOld = apOld[i]; int limit = pOld->nCell; u8 *aData = pOld->aData; u16 maskPage = pOld->maskPage; u8 *piCell = aData + pOld->cellOffset; u8 *piEnd; VVA_ONLY( int nCellAtStart = b.nCell; ) /* Verify that all sibling pages are of the same "type" (table-leaf, ** table-interior, index-leaf, or index-interior). */ if( pOld->aData[0]!=apOld[0]->aData[0] ){ rc = SQLITE_CORRUPT_BKPT; goto balance_cleanup; |
︙ | ︙ | |||
7951 7952 7953 7954 7955 7956 7957 7958 7959 7960 7961 7962 7963 7964 7965 7966 7967 7968 7969 7970 7971 7972 7973 7974 7975 7976 7977 7978 7979 7980 7981 7982 7983 7984 7985 7986 7987 7988 7989 7990 7991 7992 7993 | ** This must be done in advance. Once the balance starts, the cell ** offset section of the btree page will be overwritten and we will no ** long be able to find the cells if a pointer to each cell is not saved ** first. */ memset(&b.szCell[b.nCell], 0, sizeof(b.szCell[0])*(limit+pOld->nOverflow)); if( pOld->nOverflow>0 ){ limit = pOld->aiOvfl[0]; for(j=0; j<limit; j++){ b.apCell[b.nCell] = aData + (maskPage & get2byteAligned(piCell)); piCell += 2; b.nCell++; } for(k=0; k<pOld->nOverflow; k++){ assert( k==0 || pOld->aiOvfl[k-1]+1==pOld->aiOvfl[k] );/* NOTE 1 */ b.apCell[b.nCell] = pOld->apOvfl[k]; b.nCell++; } } piEnd = aData + pOld->cellOffset + 2*pOld->nCell; while( piCell<piEnd ){ assert( b.nCell<nMaxCells ); b.apCell[b.nCell] = aData + (maskPage & get2byteAligned(piCell)); piCell += 2; b.nCell++; } cntOld[i] = b.nCell; if( i<nOld-1 && !leafData){ u16 sz = (u16)szNew[i]; u8 *pTemp; assert( b.nCell<nMaxCells ); b.szCell[b.nCell] = sz; pTemp = &aSpace1[iSpace1]; iSpace1 += sz; assert( sz<=pBt->maxLocal+23 ); assert( iSpace1 <= (int)pBt->pageSize ); memcpy(pTemp, apDiv[i], sz); b.apCell[b.nCell] = pTemp+leafCorrection; assert( leafCorrection==0 || leafCorrection==4 ); b.szCell[b.nCell] = b.szCell[b.nCell] - leafCorrection; if( !pOld->leaf ){ assert( leafCorrection==0 ); | > > > > > | | 8353 8354 8355 8356 8357 8358 8359 8360 8361 8362 8363 8364 8365 8366 8367 8368 8369 8370 8371 8372 8373 8374 8375 8376 8377 8378 8379 8380 8381 8382 8383 8384 8385 8386 8387 8388 8389 8390 8391 8392 8393 8394 8395 8396 8397 8398 8399 8400 8401 8402 8403 8404 8405 8406 8407 8408 | ** This must be done in advance. Once the balance starts, the cell ** offset section of the btree page will be overwritten and we will no ** long be able to find the cells if a pointer to each cell is not saved ** first. */ memset(&b.szCell[b.nCell], 0, sizeof(b.szCell[0])*(limit+pOld->nOverflow)); if( pOld->nOverflow>0 ){ if( NEVER(limit<pOld->aiOvfl[0]) ){ rc = SQLITE_CORRUPT_BKPT; goto balance_cleanup; } limit = pOld->aiOvfl[0]; for(j=0; j<limit; j++){ b.apCell[b.nCell] = aData + (maskPage & get2byteAligned(piCell)); piCell += 2; b.nCell++; } for(k=0; k<pOld->nOverflow; k++){ assert( k==0 || pOld->aiOvfl[k-1]+1==pOld->aiOvfl[k] );/* NOTE 1 */ b.apCell[b.nCell] = pOld->apOvfl[k]; b.nCell++; } } piEnd = aData + pOld->cellOffset + 2*pOld->nCell; while( piCell<piEnd ){ assert( b.nCell<nMaxCells ); b.apCell[b.nCell] = aData + (maskPage & get2byteAligned(piCell)); piCell += 2; b.nCell++; } assert( (b.nCell-nCellAtStart)==(pOld->nCell+pOld->nOverflow) ); cntOld[i] = b.nCell; if( i<nOld-1 && !leafData){ u16 sz = (u16)szNew[i]; u8 *pTemp; assert( b.nCell<nMaxCells ); b.szCell[b.nCell] = sz; pTemp = &aSpace1[iSpace1]; iSpace1 += sz; assert( sz<=pBt->maxLocal+23 ); assert( iSpace1 <= (int)pBt->pageSize ); memcpy(pTemp, apDiv[i], sz); b.apCell[b.nCell] = pTemp+leafCorrection; assert( leafCorrection==0 || leafCorrection==4 ); b.szCell[b.nCell] = b.szCell[b.nCell] - leafCorrection; if( !pOld->leaf ){ assert( leafCorrection==0 ); assert( pOld->hdrOffset==0 || CORRUPT_DB ); /* The right pointer of the child page pOld becomes the left ** pointer of the divider cell */ memcpy(b.apCell[b.nCell], &pOld->aData[8], 4); }else{ assert( leafCorrection==4 ); while( b.szCell[b.nCell]<4 ){ /* Do not allow any cells smaller than 4 bytes. If a smaller cell |
︙ | ︙ | |||
8023 8024 8025 8026 8027 8028 8029 | ** szNew[i]: Spaced used on the i-th sibling page. ** cntNew[i]: Index in b.apCell[] and b.szCell[] for the first cell to ** the right of the i-th sibling page. ** usableSpace: Number of bytes of space available on each sibling. ** */ usableSpace = pBt->usableSize - 12 + leafCorrection; | | > > > > > > > > > > > | 8430 8431 8432 8433 8434 8435 8436 8437 8438 8439 8440 8441 8442 8443 8444 8445 8446 8447 8448 8449 8450 8451 8452 8453 8454 8455 8456 | ** szNew[i]: Spaced used on the i-th sibling page. ** cntNew[i]: Index in b.apCell[] and b.szCell[] for the first cell to ** the right of the i-th sibling page. ** usableSpace: Number of bytes of space available on each sibling. ** */ usableSpace = pBt->usableSize - 12 + leafCorrection; for(i=k=0; i<nOld; i++, k++){ MemPage *p = apOld[i]; b.apEnd[k] = p->aDataEnd; b.ixNx[k] = cntOld[i]; if( k && b.ixNx[k]==b.ixNx[k-1] ){ k--; /* Omit b.ixNx[] entry for child pages with no cells */ } if( !leafData ){ k++; b.apEnd[k] = pParent->aDataEnd; b.ixNx[k] = cntOld[i]+1; } assert( p->nFree>=0 ); szNew[i] = usableSpace - p->nFree; for(j=0; j<p->nOverflow; j++){ szNew[i] += 2 + p->xCellSize(p, p->apOvfl[j]); } cntNew[i] = cntOld[i]; } k = nOld; |
︙ | ︙ | |||
8142 8143 8144 8145 8146 8147 8148 8149 8150 8151 8152 8153 8154 8155 | for(i=0; i<k; i++){ MemPage *pNew; if( i<nOld ){ pNew = apNew[i] = apOld[i]; apOld[i] = 0; rc = sqlite3PagerWrite(pNew->pDbPage); nNew++; if( rc ) goto balance_cleanup; }else{ assert( i>0 ); rc = allocateBtreePage(pBt, &pNew, &pgno, (bBulk ? 1 : pgno), 0); if( rc ) goto balance_cleanup; zeroPage(pNew, pageFlags); apNew[i] = pNew; | > > > > > | 8560 8561 8562 8563 8564 8565 8566 8567 8568 8569 8570 8571 8572 8573 8574 8575 8576 8577 8578 | for(i=0; i<k; i++){ MemPage *pNew; if( i<nOld ){ pNew = apNew[i] = apOld[i]; apOld[i] = 0; rc = sqlite3PagerWrite(pNew->pDbPage); nNew++; if( sqlite3PagerPageRefcount(pNew->pDbPage)!=1+(i==(iParentIdx-nxDiv)) && rc==SQLITE_OK ){ rc = SQLITE_CORRUPT_BKPT; } if( rc ) goto balance_cleanup; }else{ assert( i>0 ); rc = allocateBtreePage(pBt, &pNew, &pgno, (bBulk ? 1 : pgno), 0); if( rc ) goto balance_cleanup; zeroPage(pNew, pageFlags); apNew[i] = pNew; |
︙ | ︙ | |||
8178 8179 8180 8181 8182 8183 8184 | ** When NB==3, this one optimization makes the database about 25% faster ** for large insertions and deletions. */ for(i=0; i<nNew; i++){ aPgOrder[i] = aPgno[i] = apNew[i]->pgno; aPgFlags[i] = apNew[i]->pDbPage->flags; for(j=0; j<i; j++){ | | | 8601 8602 8603 8604 8605 8606 8607 8608 8609 8610 8611 8612 8613 8614 8615 | ** When NB==3, this one optimization makes the database about 25% faster ** for large insertions and deletions. */ for(i=0; i<nNew; i++){ aPgOrder[i] = aPgno[i] = apNew[i]->pgno; aPgFlags[i] = apNew[i]->pDbPage->flags; for(j=0; j<i; j++){ if( NEVER(aPgno[j]==aPgno[i]) ){ /* This branch is taken if the set of sibling pages somehow contains ** duplicate entries. This can happen if the database is corrupt. ** It would be simpler to detect this as part of the loop below, but ** we do the detection here in order to avoid populating the pager ** cache with two separate objects associated with the same ** page number. */ assert( CORRUPT_DB ); |
︙ | ︙ | |||
8221 8222 8223 8224 8225 8226 8227 8228 8229 8230 8231 8232 8233 8234 | nNew>=4 ? apNew[3]->pgno : 0, nNew>=4 ? szNew[3] : 0, nNew>=4 ? cntNew[3] - cntNew[2] - !leafData : 0, nNew>=5 ? apNew[4]->pgno : 0, nNew>=5 ? szNew[4] : 0, nNew>=5 ? cntNew[4] - cntNew[3] - !leafData : 0 )); assert( sqlite3PagerIswriteable(pParent->pDbPage) ); put4byte(pRight, apNew[nNew-1]->pgno); /* If the sibling pages are not leaves, ensure that the right-child pointer ** of the right-most new sibling page is set to the value that was ** originally in the same field of the right-most old sibling page. */ if( (pageFlags & PTF_LEAF)==0 && nOld!=nNew ){ MemPage *pOld = (nNew>nOld ? apNew : apOld)[nOld-1]; | > > | 8644 8645 8646 8647 8648 8649 8650 8651 8652 8653 8654 8655 8656 8657 8658 8659 | nNew>=4 ? apNew[3]->pgno : 0, nNew>=4 ? szNew[3] : 0, nNew>=4 ? cntNew[3] - cntNew[2] - !leafData : 0, nNew>=5 ? apNew[4]->pgno : 0, nNew>=5 ? szNew[4] : 0, nNew>=5 ? cntNew[4] - cntNew[3] - !leafData : 0 )); assert( sqlite3PagerIswriteable(pParent->pDbPage) ); assert( nNew>=1 && nNew<=ArraySize(apNew) ); assert( apNew[nNew-1]!=0 ); put4byte(pRight, apNew[nNew-1]->pgno); /* If the sibling pages are not leaves, ensure that the right-child pointer ** of the right-most new sibling page is set to the value that was ** originally in the same field of the right-most old sibling page. */ if( (pageFlags & PTF_LEAF)==0 && nOld!=nNew ){ MemPage *pOld = (nNew>nOld ? apNew : apOld)[nOld-1]; |
︙ | ︙ | |||
8248 8249 8250 8251 8252 8253 8254 | ** ** If the sibling pages are not leaves, then the pointer map entry ** associated with the right-child of each sibling may also need to be ** updated. This happens below, after the sibling pages have been ** populated, not here. */ if( REQUIRE_PTRMAP ){ | | | < | > > > | < | | > | 8673 8674 8675 8676 8677 8678 8679 8680 8681 8682 8683 8684 8685 8686 8687 8688 8689 8690 8691 8692 8693 8694 8695 8696 8697 8698 8699 8700 8701 8702 8703 8704 8705 8706 8707 8708 8709 8710 8711 8712 8713 8714 8715 8716 8717 8718 8719 8720 8721 8722 8723 8724 8725 8726 8727 8728 8729 8730 8731 8732 8733 | ** ** If the sibling pages are not leaves, then the pointer map entry ** associated with the right-child of each sibling may also need to be ** updated. This happens below, after the sibling pages have been ** populated, not here. */ if( REQUIRE_PTRMAP ){ MemPage *pOld; MemPage *pNew = pOld = apNew[0]; int cntOldNext = pNew->nCell + pNew->nOverflow; int iNew = 0; int iOld = 0; for(i=0; i<b.nCell; i++){ u8 *pCell = b.apCell[i]; while( i==cntOldNext ){ iOld++; assert( iOld<nNew || iOld<nOld ); assert( iOld>=0 && iOld<NB ); pOld = iOld<nNew ? apNew[iOld] : apOld[iOld]; cntOldNext += pOld->nCell + pOld->nOverflow + !leafData; } if( i==cntNew[iNew] ){ pNew = apNew[++iNew]; if( !leafData ) continue; } /* Cell pCell is destined for new sibling page pNew. Originally, it ** was either part of sibling page iOld (possibly an overflow cell), ** or else the divider cell to the left of sibling page iOld. So, ** if sibling page iOld had the same page number as pNew, and if ** pCell really was a part of sibling page iOld (not a divider or ** overflow cell), we can skip updating the pointer map entries. */ if( iOld>=nNew || pNew->pgno!=aPgno[iOld] || !SQLITE_WITHIN(pCell,pOld->aData,pOld->aDataEnd) ){ if( !leafCorrection ){ ptrmapPut(pBt, get4byte(pCell), PTRMAP_BTREE, pNew->pgno, &rc); } if( cachedCellSize(&b,i)>pNew->minLocal ){ ptrmapPutOvflPtr(pNew, pOld, pCell, &rc); } if( rc ) goto balance_cleanup; } } } /* Insert new divider cells into pParent. */ for(i=0; i<nNew-1; i++){ u8 *pCell; u8 *pTemp; int sz; u8 *pSrcEnd; MemPage *pNew = apNew[i]; j = cntNew[i]; assert( j<nMaxCells ); assert( b.apCell[j]!=0 ); pCell = b.apCell[j]; sz = b.szCell[j] + leafCorrection; |
︙ | ︙ | |||
8336 8337 8338 8339 8340 8341 8342 8343 8344 8345 8346 8347 8348 8349 | assert(leafCorrection==4); sz = pParent->xCellSize(pParent, pCell); } } iOvflSpace += sz; assert( sz<=pBt->maxLocal+23 ); assert( iOvflSpace <= (int)pBt->pageSize ); insertCell(pParent, nxDiv+i, pCell, sz, pTemp, pNew->pgno, &rc); if( rc!=SQLITE_OK ) goto balance_cleanup; assert( sqlite3PagerIswriteable(pParent->pDbPage) ); } /* Now update the actual sibling pages. The order in which they are updated ** is important, as this code needs to avoid disrupting any page from which | > > > > > > | 8763 8764 8765 8766 8767 8768 8769 8770 8771 8772 8773 8774 8775 8776 8777 8778 8779 8780 8781 8782 | assert(leafCorrection==4); sz = pParent->xCellSize(pParent, pCell); } } iOvflSpace += sz; assert( sz<=pBt->maxLocal+23 ); assert( iOvflSpace <= (int)pBt->pageSize ); for(k=0; b.ixNx[k]<=i && ALWAYS(k<NB*2); k++){} pSrcEnd = b.apEnd[k]; if( SQLITE_WITHIN(pSrcEnd, pCell, pCell+sz) ){ rc = SQLITE_CORRUPT_BKPT; goto balance_cleanup; } insertCell(pParent, nxDiv+i, pCell, sz, pTemp, pNew->pgno, &rc); if( rc!=SQLITE_OK ) goto balance_cleanup; assert( sqlite3PagerIswriteable(pParent->pDbPage) ); } /* Now update the actual sibling pages. The order in which they are updated ** is important, as this code needs to avoid disrupting any page from which |
︙ | ︙ | |||
8426 8427 8428 8429 8430 8431 8432 | ** by smaller than the child due to the database header, and so all the ** free space needs to be up front. */ assert( nNew==1 || CORRUPT_DB ); rc = defragmentPage(apNew[0], -1); testcase( rc!=SQLITE_OK ); assert( apNew[0]->nFree == | > | | 8859 8860 8861 8862 8863 8864 8865 8866 8867 8868 8869 8870 8871 8872 8873 8874 | ** by smaller than the child due to the database header, and so all the ** free space needs to be up front. */ assert( nNew==1 || CORRUPT_DB ); rc = defragmentPage(apNew[0], -1); testcase( rc!=SQLITE_OK ); assert( apNew[0]->nFree == (get2byteNotZero(&apNew[0]->aData[5]) - apNew[0]->cellOffset - apNew[0]->nCell*2) || rc!=SQLITE_OK ); copyNodeContent(apNew[0], pParent, &rc); freePage(apNew[0], &rc); }else if( REQUIRE_PTRMAP && !leafCorrection ){ /* Fix the pointer map entries associated with the right-child of each ** sibling page. All other pointer map entries have already been taken |
︙ | ︙ | |||
8525 8526 8527 8528 8529 8530 8531 | if( rc ){ *ppChild = 0; releasePage(pChild); return rc; } assert( sqlite3PagerIswriteable(pChild->pDbPage) ); assert( sqlite3PagerIswriteable(pRoot->pDbPage) ); | | > > > > > > > > > > > > > > > > > > > > > > > > | 8959 8960 8961 8962 8963 8964 8965 8966 8967 8968 8969 8970 8971 8972 8973 8974 8975 8976 8977 8978 8979 8980 8981 8982 8983 8984 8985 8986 8987 8988 8989 8990 8991 8992 8993 8994 8995 8996 8997 8998 8999 9000 9001 9002 9003 9004 9005 9006 9007 9008 9009 9010 9011 9012 9013 9014 | if( rc ){ *ppChild = 0; releasePage(pChild); return rc; } assert( sqlite3PagerIswriteable(pChild->pDbPage) ); assert( sqlite3PagerIswriteable(pRoot->pDbPage) ); assert( pChild->nCell==pRoot->nCell || CORRUPT_DB ); TRACE(("BALANCE: copy root %d into %d\n", pRoot->pgno, pChild->pgno)); /* Copy the overflow cells from pRoot to pChild */ memcpy(pChild->aiOvfl, pRoot->aiOvfl, pRoot->nOverflow*sizeof(pRoot->aiOvfl[0])); memcpy(pChild->apOvfl, pRoot->apOvfl, pRoot->nOverflow*sizeof(pRoot->apOvfl[0])); pChild->nOverflow = pRoot->nOverflow; /* Zero the contents of pRoot. Then install pChild as the right-child. */ zeroPage(pRoot, pChild->aData[0] & ~PTF_LEAF); put4byte(&pRoot->aData[pRoot->hdrOffset+8], pgnoChild); *ppChild = pChild; return SQLITE_OK; } /* ** Return SQLITE_CORRUPT if any cursor other than pCur is currently valid ** on the same B-tree as pCur. ** ** This can occur if a database is corrupt with two or more SQL tables ** pointing to the same b-tree. If an insert occurs on one SQL table ** and causes a BEFORE TRIGGER to do a secondary insert on the other SQL ** table linked to the same b-tree. If the secondary insert causes a ** rebalance, that can change content out from under the cursor on the ** first SQL table, violating invariants on the first insert. */ static int anotherValidCursor(BtCursor *pCur){ BtCursor *pOther; for(pOther=pCur->pBt->pCursor; pOther; pOther=pOther->pNext){ if( pOther!=pCur && pOther->eState==CURSOR_VALID && pOther->pPage==pCur->pPage ){ return SQLITE_CORRUPT_BKPT; } } return SQLITE_OK; } /* ** The page that pCur currently points to has just been modified in ** some way. This function figures out if this modification means the ** tree needs to be balanced, and if so calls the appropriate balancing ** routine. Balancing routines are: ** |
︙ | ︙ | |||
8564 8565 8566 8567 8568 8569 8570 | u8 aBalanceQuickSpace[13]; u8 *pFree = 0; VVA_ONLY( int balance_quick_called = 0 ); VVA_ONLY( int balance_deeper_called = 0 ); do { | | | | > > > < < > > > | 9022 9023 9024 9025 9026 9027 9028 9029 9030 9031 9032 9033 9034 9035 9036 9037 9038 9039 9040 9041 9042 9043 9044 9045 9046 9047 9048 9049 9050 9051 9052 9053 9054 9055 9056 9057 9058 9059 9060 9061 9062 9063 9064 9065 9066 9067 9068 9069 9070 | u8 aBalanceQuickSpace[13]; u8 *pFree = 0; VVA_ONLY( int balance_quick_called = 0 ); VVA_ONLY( int balance_deeper_called = 0 ); do { int iPage; MemPage *pPage = pCur->pPage; if( NEVER(pPage->nFree<0) && btreeComputeFreeSpace(pPage) ) break; if( pPage->nOverflow==0 && pPage->nFree<=nMin ){ break; }else if( (iPage = pCur->iPage)==0 ){ if( pPage->nOverflow && (rc = anotherValidCursor(pCur))==SQLITE_OK ){ /* The root page of the b-tree is overfull. In this case call the ** balance_deeper() function to create a new child for the root-page ** and copy the current contents of the root-page to it. The ** next iteration of the do-loop will balance the child page. */ assert( balance_deeper_called==0 ); VVA_ONLY( balance_deeper_called++ ); rc = balance_deeper(pPage, &pCur->apPage[1]); if( rc==SQLITE_OK ){ pCur->iPage = 1; pCur->ix = 0; pCur->aiIdx[0] = 0; pCur->apPage[0] = pPage; pCur->pPage = pCur->apPage[1]; assert( pCur->pPage->nOverflow ); } }else{ break; } }else{ MemPage * const pParent = pCur->apPage[iPage-1]; int const iIdx = pCur->aiIdx[iPage-1]; rc = sqlite3PagerWrite(pParent->pDbPage); if( rc==SQLITE_OK && pParent->nFree<0 ){ rc = btreeComputeFreeSpace(pParent); } if( rc==SQLITE_OK ){ #ifndef SQLITE_OMIT_QUICKBALANCE if( pPage->intKeyLeaf && pPage->nOverflow==1 && pPage->aiOvfl[0]==pPage->nCell && pParent->pgno!=1 && pParent->nCell==iIdx |
︙ | ︙ | |||
8705 8706 8707 8708 8709 8710 8711 | iAmt-nData); if( rc ) return rc; iAmt = nData; } if( memcmp(pDest, ((u8*)pX->pData) + iOffset, iAmt)!=0 ){ int rc = sqlite3PagerWrite(pPage->pDbPage); if( rc ) return rc; | > > > > | | > > | | 9167 9168 9169 9170 9171 9172 9173 9174 9175 9176 9177 9178 9179 9180 9181 9182 9183 9184 9185 9186 9187 9188 9189 9190 9191 9192 9193 9194 9195 9196 9197 9198 9199 9200 9201 9202 9203 9204 9205 9206 9207 9208 9209 9210 9211 9212 9213 9214 9215 9216 9217 9218 9219 9220 9221 9222 9223 9224 9225 | iAmt-nData); if( rc ) return rc; iAmt = nData; } if( memcmp(pDest, ((u8*)pX->pData) + iOffset, iAmt)!=0 ){ int rc = sqlite3PagerWrite(pPage->pDbPage); if( rc ) return rc; /* In a corrupt database, it is possible for the source and destination ** buffers to overlap. This is harmless since the database is already ** corrupt but it does cause valgrind and ASAN warnings. So use ** memmove(). */ memmove(pDest, ((u8*)pX->pData) + iOffset, iAmt); } } return SQLITE_OK; } /* ** Overwrite the cell that cursor pCur is pointing to with fresh content ** contained in pX. */ static int btreeOverwriteCell(BtCursor *pCur, const BtreePayload *pX){ int iOffset; /* Next byte of pX->pData to write */ int nTotal = pX->nData + pX->nZero; /* Total bytes of to write */ int rc; /* Return code */ MemPage *pPage = pCur->pPage; /* Page being written */ BtShared *pBt; /* Btree */ Pgno ovflPgno; /* Next overflow page to write */ u32 ovflPageSize; /* Size to write on overflow page */ if( pCur->info.pPayload + pCur->info.nLocal > pPage->aDataEnd || pCur->info.pPayload < pPage->aData + pPage->cellOffset ){ return SQLITE_CORRUPT_BKPT; } /* Overwrite the local portion first */ rc = btreeOverwriteContent(pPage, pCur->info.pPayload, pX, 0, pCur->info.nLocal); if( rc ) return rc; if( pCur->info.nLocal==nTotal ) return SQLITE_OK; /* Now overwrite the overflow pages */ iOffset = pCur->info.nLocal; assert( nTotal>=0 ); assert( iOffset>=0 ); ovflPgno = get4byte(pCur->info.pPayload + iOffset); pBt = pPage->pBt; ovflPageSize = pBt->usableSize - 4; do{ rc = btreeGetPage(pBt, ovflPgno, &pPage, 0); if( rc ) return rc; if( sqlite3PagerPageRefcount(pPage->pDbPage)!=1 || pPage->isInit ){ rc = SQLITE_CORRUPT_BKPT; }else{ if( iOffset+ovflPageSize<(u32)nTotal ){ ovflPgno = get4byte(pPage->aData); }else{ ovflPageSize = nTotal - iOffset; } |
︙ | ︙ | |||
8808 8809 8810 8811 8812 8813 8814 | int idx; MemPage *pPage; Btree *p = pCur->pBtree; BtShared *pBt = p->pBt; unsigned char *oldCell; unsigned char *newCell = 0; | | > | > > > > > > > > > | > < | 9276 9277 9278 9279 9280 9281 9282 9283 9284 9285 9286 9287 9288 9289 9290 9291 9292 9293 9294 9295 9296 9297 9298 9299 9300 9301 9302 9303 9304 9305 9306 9307 9308 9309 9310 9311 9312 9313 9314 9315 9316 9317 9318 9319 9320 9321 9322 9323 9324 9325 9326 9327 9328 9329 9330 9331 9332 9333 9334 9335 9336 9337 9338 9339 9340 9341 9342 9343 9344 9345 9346 9347 9348 9349 | int idx; MemPage *pPage; Btree *p = pCur->pBtree; BtShared *pBt = p->pBt; unsigned char *oldCell; unsigned char *newCell = 0; assert( (flags & (BTREE_SAVEPOSITION|BTREE_APPEND|BTREE_PREFORMAT))==flags ); assert( (flags & BTREE_PREFORMAT)==0 || seekResult || pCur->pKeyInfo==0 ); if( pCur->eState==CURSOR_FAULT ){ assert( pCur->skipNext!=SQLITE_OK ); return pCur->skipNext; } assert( cursorOwnsBtShared(pCur) ); assert( (pCur->curFlags & BTCF_WriteFlag)!=0 && pBt->inTransaction==TRANS_WRITE && (pBt->btsFlags & BTS_READ_ONLY)==0 ); assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) ); /* Assert that the caller has been consistent. If this cursor was opened ** expecting an index b-tree, then the caller should be inserting blob ** keys with no associated data. If the cursor was opened expecting an ** intkey table, the caller should be inserting integer keys with a ** blob of associated data. */ assert( (flags & BTREE_PREFORMAT) || (pX->pKey==0)==(pCur->pKeyInfo==0) ); /* Save the positions of any other cursors open on this table. ** ** In some cases, the call to btreeMoveto() below is a no-op. For ** example, when inserting data into a table with auto-generated integer ** keys, the VDBE layer invokes sqlite3BtreeLast() to figure out the ** integer key to use. It then calls this function to actually insert the ** data into the intkey B-Tree. In this case btreeMoveto() recognizes ** that the cursor is already where it needs to be and returns without ** doing any work. To avoid thwarting these optimizations, it is important ** not to clear the cursor here. */ if( pCur->curFlags & BTCF_Multiple ){ rc = saveAllCursors(pBt, pCur->pgnoRoot, pCur); if( rc ) return rc; if( loc && pCur->iPage<0 ){ /* This can only happen if the schema is corrupt such that there is more ** than one table or index with the same root page as used by the cursor. ** Which can only happen if the SQLITE_NoSchemaError flag was set when ** the schema was loaded. This cannot be asserted though, as a user might ** set the flag, load the schema, and then unset the flag. */ return SQLITE_CORRUPT_BKPT; } } if( pCur->pKeyInfo==0 ){ assert( pX->pKey==0 ); /* If this is an insert into a table b-tree, invalidate any incrblob ** cursors open on the row being replaced */ if( p->hasIncrblobCur ){ invalidateIncrblobCursors(p, pCur->pgnoRoot, pX->nKey, 0); } /* If BTREE_SAVEPOSITION is set, the cursor must already be pointing ** to a row with the same key as the new entry being inserted. */ #ifdef SQLITE_DEBUG if( flags & BTREE_SAVEPOSITION ){ assert( pCur->curFlags & BTCF_ValidNKey ); assert( pX->nKey==pCur->info.nKey ); assert( loc==0 ); } #endif /* On the other hand, BTREE_SAVEPOSITION==0 does not imply ** that the cursor is not pointing to a row to be overwritten. ** So do a complete check. |
︙ | ︙ | |||
8882 8883 8884 8885 8886 8887 8888 | } assert( loc==0 ); }else if( loc==0 ){ /* The cursor is *not* pointing to the cell to be overwritten, nor ** to an adjacent cell. Move the cursor so that it is pointing either ** to the cell to be overwritten or an adjacent cell. */ | | > | 9360 9361 9362 9363 9364 9365 9366 9367 9368 9369 9370 9371 9372 9373 9374 9375 | } assert( loc==0 ); }else if( loc==0 ){ /* The cursor is *not* pointing to the cell to be overwritten, nor ** to an adjacent cell. Move the cursor so that it is pointing either ** to the cell to be overwritten or an adjacent cell. */ rc = sqlite3BtreeTableMoveto(pCur, pX->nKey, (flags & BTREE_APPEND)!=0, &loc); if( rc ) return rc; } }else{ /* This is an index or a WITHOUT ROWID table */ /* If BTREE_SAVEPOSITION is set, the cursor must already be pointing ** to a row with the same key as the new entry being inserted. |
︙ | ︙ | |||
8905 8906 8907 8908 8909 8910 8911 | if( loc==0 && (flags & BTREE_SAVEPOSITION)==0 ){ if( pX->nMem ){ UnpackedRecord r; r.pKeyInfo = pCur->pKeyInfo; r.aMem = pX->aMem; r.nField = pX->nMem; r.default_rc = 0; | < < < | | > | < | > > | > > > > > > > > > > > > > > > > > > > > > | > | > > > | > > > > > | > > | 9384 9385 9386 9387 9388 9389 9390 9391 9392 9393 9394 9395 9396 9397 9398 9399 9400 9401 9402 9403 9404 9405 9406 9407 9408 9409 9410 9411 9412 9413 9414 9415 9416 9417 9418 9419 9420 9421 9422 9423 9424 9425 9426 9427 9428 9429 9430 9431 9432 9433 9434 9435 9436 9437 9438 9439 9440 9441 9442 9443 9444 9445 9446 9447 9448 9449 9450 9451 9452 9453 9454 9455 9456 9457 9458 9459 9460 9461 9462 9463 9464 9465 9466 9467 9468 9469 9470 9471 9472 9473 9474 9475 9476 9477 9478 9479 9480 9481 9482 9483 9484 9485 9486 9487 9488 9489 9490 9491 9492 9493 9494 9495 9496 9497 9498 | if( loc==0 && (flags & BTREE_SAVEPOSITION)==0 ){ if( pX->nMem ){ UnpackedRecord r; r.pKeyInfo = pCur->pKeyInfo; r.aMem = pX->aMem; r.nField = pX->nMem; r.default_rc = 0; r.eqSeen = 0; rc = sqlite3BtreeIndexMoveto(pCur, &r, &loc); }else{ rc = btreeMoveto(pCur, pX->pKey, pX->nKey, (flags & BTREE_APPEND)!=0, &loc); } if( rc ) return rc; } /* If the cursor is currently pointing to an entry to be overwritten ** and the new content is the same as as the old, then use the ** overwrite optimization. */ if( loc==0 ){ getCellInfo(pCur); if( pCur->info.nKey==pX->nKey ){ BtreePayload x2; x2.pData = pX->pKey; x2.nData = pX->nKey; x2.nZero = 0; return btreeOverwriteCell(pCur, &x2); } } } assert( pCur->eState==CURSOR_VALID || (pCur->eState==CURSOR_INVALID && loc) || CORRUPT_DB ); pPage = pCur->pPage; assert( pPage->intKey || pX->nKey>=0 || (flags & BTREE_PREFORMAT) ); assert( pPage->leaf || !pPage->intKey ); if( pPage->nFree<0 ){ if( NEVER(pCur->eState>CURSOR_INVALID) ){ rc = SQLITE_CORRUPT_BKPT; }else{ rc = btreeComputeFreeSpace(pPage); } if( rc ) return rc; } TRACE(("INSERT: table=%d nkey=%lld ndata=%d page=%d %s\n", pCur->pgnoRoot, pX->nKey, pX->nData, pPage->pgno, loc==0 ? "overwrite" : "new entry")); assert( pPage->isInit ); newCell = pBt->pTmpSpace; assert( newCell!=0 ); if( flags & BTREE_PREFORMAT ){ rc = SQLITE_OK; szNew = pBt->nPreformatSize; if( szNew<4 ) szNew = 4; if( ISAUTOVACUUM && szNew>pPage->maxLocal ){ CellInfo info; pPage->xParseCell(pPage, newCell, &info); if( info.nPayload!=info.nLocal ){ Pgno ovfl = get4byte(&newCell[szNew-4]); ptrmapPut(pBt, ovfl, PTRMAP_OVERFLOW1, pPage->pgno, &rc); } } }else{ rc = fillInCell(pPage, newCell, pX, &szNew); } if( rc ) goto end_insert; assert( szNew==pPage->xCellSize(pPage, newCell) ); assert( szNew <= MX_CELL_SIZE(pBt) ); idx = pCur->ix; if( loc==0 ){ CellInfo info; assert( idx>=0 ); if( idx>=pPage->nCell ){ return SQLITE_CORRUPT_BKPT; } rc = sqlite3PagerWrite(pPage->pDbPage); if( rc ){ goto end_insert; } oldCell = findCell(pPage, idx); if( !pPage->leaf ){ memcpy(newCell, oldCell, 4); } BTREE_CLEAR_CELL(rc, pPage, oldCell, info); testcase( pCur->curFlags & BTCF_ValidOvfl ); invalidateOverflowCache(pCur); if( info.nSize==szNew && info.nLocal==info.nPayload && (!REQUIRE_PTRMAP || szNew<pPage->minLocal) ){ /* Overwrite the old cell with the new if they are the same size. ** We could also try to do this if the old cell is smaller, then add ** the leftover space to the free list. But experiments show that ** doing that is no faster then skipping this optimization and just ** calling dropCell() and insertCell(). ** ** This optimization cannot be used on an autovacuum database if the ** new entry uses overflow pages, as the insertCell() call below is ** necessary to add the PTRMAP_OVERFLOW1 pointer-map entry. */ assert( rc==SQLITE_OK ); /* clearCell never fails when nLocal==nPayload */ if( oldCell < pPage->aData+pPage->hdrOffset+10 ){ return SQLITE_CORRUPT_BKPT; } if( oldCell+szNew > pPage->aDataEnd ){ return SQLITE_CORRUPT_BKPT; } memcpy(oldCell, newCell, szNew); return SQLITE_OK; } dropCell(pPage, idx, info.nSize, &rc); if( rc ) goto end_insert; }else if( loc<0 && pPage->nCell>0 ){ assert( pPage->leaf ); |
︙ | ︙ | |||
9043 9044 9045 9046 9047 9048 9049 9050 9051 9052 9053 9054 9055 9056 | } } assert( pCur->iPage<0 || pCur->pPage->nOverflow==0 ); end_insert: return rc; } /* ** Delete the entry that the cursor is pointing to. ** ** If the BTREE_SAVEPOSITION bit of the flags parameter is zero, then ** the cursor is left pointing at an arbitrary location after the delete. ** But if that bit is set, then the cursor is left in a state such that | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 9553 9554 9555 9556 9557 9558 9559 9560 9561 9562 9563 9564 9565 9566 9567 9568 9569 9570 9571 9572 9573 9574 9575 9576 9577 9578 9579 9580 9581 9582 9583 9584 9585 9586 9587 9588 9589 9590 9591 9592 9593 9594 9595 9596 9597 9598 9599 9600 9601 9602 9603 9604 9605 9606 9607 9608 9609 9610 9611 9612 9613 9614 9615 9616 9617 9618 9619 9620 9621 9622 9623 9624 9625 9626 9627 9628 9629 9630 9631 9632 9633 9634 9635 9636 9637 9638 9639 9640 9641 9642 9643 9644 9645 9646 9647 9648 9649 9650 9651 9652 9653 9654 9655 9656 9657 9658 9659 9660 9661 9662 9663 9664 9665 9666 9667 9668 9669 9670 9671 9672 9673 9674 | } } assert( pCur->iPage<0 || pCur->pPage->nOverflow==0 ); end_insert: return rc; } /* ** This function is used as part of copying the current row from cursor ** pSrc into cursor pDest. If the cursors are open on intkey tables, then ** parameter iKey is used as the rowid value when the record is copied ** into pDest. Otherwise, the record is copied verbatim. ** ** This function does not actually write the new value to cursor pDest. ** Instead, it creates and populates any required overflow pages and ** writes the data for the new cell into the BtShared.pTmpSpace buffer ** for the destination database. The size of the cell, in bytes, is left ** in BtShared.nPreformatSize. The caller completes the insertion by ** calling sqlite3BtreeInsert() with the BTREE_PREFORMAT flag specified. ** ** SQLITE_OK is returned if successful, or an SQLite error code otherwise. */ int sqlite3BtreeTransferRow(BtCursor *pDest, BtCursor *pSrc, i64 iKey){ int rc = SQLITE_OK; BtShared *pBt = pDest->pBt; u8 *aOut = pBt->pTmpSpace; /* Pointer to next output buffer */ const u8 *aIn; /* Pointer to next input buffer */ u32 nIn; /* Size of input buffer aIn[] */ u32 nRem; /* Bytes of data still to copy */ getCellInfo(pSrc); aOut += putVarint32(aOut, pSrc->info.nPayload); if( pDest->pKeyInfo==0 ) aOut += putVarint(aOut, iKey); nIn = pSrc->info.nLocal; aIn = pSrc->info.pPayload; if( aIn+nIn>pSrc->pPage->aDataEnd ){ return SQLITE_CORRUPT_BKPT; } nRem = pSrc->info.nPayload; if( nIn==nRem && nIn<pDest->pPage->maxLocal ){ memcpy(aOut, aIn, nIn); pBt->nPreformatSize = nIn + (aOut - pBt->pTmpSpace); }else{ Pager *pSrcPager = pSrc->pBt->pPager; u8 *pPgnoOut = 0; Pgno ovflIn = 0; DbPage *pPageIn = 0; MemPage *pPageOut = 0; u32 nOut; /* Size of output buffer aOut[] */ nOut = btreePayloadToLocal(pDest->pPage, pSrc->info.nPayload); pBt->nPreformatSize = nOut + (aOut - pBt->pTmpSpace); if( nOut<pSrc->info.nPayload ){ pPgnoOut = &aOut[nOut]; pBt->nPreformatSize += 4; } if( nRem>nIn ){ if( aIn+nIn+4>pSrc->pPage->aDataEnd ){ return SQLITE_CORRUPT_BKPT; } ovflIn = get4byte(&pSrc->info.pPayload[nIn]); } do { nRem -= nOut; do{ assert( nOut>0 ); if( nIn>0 ){ int nCopy = MIN(nOut, nIn); memcpy(aOut, aIn, nCopy); nOut -= nCopy; nIn -= nCopy; aOut += nCopy; aIn += nCopy; } if( nOut>0 ){ sqlite3PagerUnref(pPageIn); pPageIn = 0; rc = sqlite3PagerGet(pSrcPager, ovflIn, &pPageIn, PAGER_GET_READONLY); if( rc==SQLITE_OK ){ aIn = (const u8*)sqlite3PagerGetData(pPageIn); ovflIn = get4byte(aIn); aIn += 4; nIn = pSrc->pBt->usableSize - 4; } } }while( rc==SQLITE_OK && nOut>0 ); if( rc==SQLITE_OK && nRem>0 && ALWAYS(pPgnoOut) ){ Pgno pgnoNew; MemPage *pNew = 0; rc = allocateBtreePage(pBt, &pNew, &pgnoNew, 0, 0); put4byte(pPgnoOut, pgnoNew); if( ISAUTOVACUUM && pPageOut ){ ptrmapPut(pBt, pgnoNew, PTRMAP_OVERFLOW2, pPageOut->pgno, &rc); } releasePage(pPageOut); pPageOut = pNew; if( pPageOut ){ pPgnoOut = pPageOut->aData; put4byte(pPgnoOut, 0); aOut = &pPgnoOut[4]; nOut = MIN(pBt->usableSize - 4, nRem); } } }while( nRem>0 && rc==SQLITE_OK ); releasePage(pPageOut); sqlite3PagerUnref(pPageIn); } return rc; } /* ** Delete the entry that the cursor is pointing to. ** ** If the BTREE_SAVEPOSITION bit of the flags parameter is zero, then ** the cursor is left pointing at an arbitrary location after the delete. ** But if that bit is set, then the cursor is left in a state such that |
︙ | ︙ | |||
9079 9080 9081 9082 9083 9084 9085 | assert( cursorOwnsBtShared(pCur) ); assert( pBt->inTransaction==TRANS_WRITE ); assert( (pBt->btsFlags & BTS_READ_ONLY)==0 ); assert( pCur->curFlags & BTCF_WriteFlag ); assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) ); assert( !hasReadConflicts(p, pCur->pgnoRoot) ); | < < > > > > > > > | 9697 9698 9699 9700 9701 9702 9703 9704 9705 9706 9707 9708 9709 9710 9711 9712 9713 9714 9715 9716 9717 9718 9719 9720 9721 9722 9723 | assert( cursorOwnsBtShared(pCur) ); assert( pBt->inTransaction==TRANS_WRITE ); assert( (pBt->btsFlags & BTS_READ_ONLY)==0 ); assert( pCur->curFlags & BTCF_WriteFlag ); assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) ); assert( !hasReadConflicts(p, pCur->pgnoRoot) ); assert( (flags & ~(BTREE_SAVEPOSITION | BTREE_AUXDELETE))==0 ); if( pCur->eState==CURSOR_REQUIRESEEK ){ rc = btreeRestoreCursorPosition(pCur); assert( rc!=SQLITE_OK || CORRUPT_DB || pCur->eState==CURSOR_VALID ); if( rc || pCur->eState!=CURSOR_VALID ) return rc; } assert( CORRUPT_DB || pCur->eState==CURSOR_VALID ); iCellDepth = pCur->iPage; iCellIdx = pCur->ix; pPage = pCur->pPage; pCell = findCell(pPage, iCellIdx); if( pPage->nFree<0 && btreeComputeFreeSpace(pPage) ) return SQLITE_CORRUPT; /* If the bPreserve flag is set to true, then the cursor position must ** be preserved following this delete operation. If the current delete ** will cause a b-tree rebalance, then this is done by saving the cursor ** key and leaving the cursor in CURSOR_REQUIRESEEK state before ** returning. ** |
︙ | ︙ | |||
9133 9134 9135 9136 9137 9138 9139 | if( pCur->curFlags & BTCF_Multiple ){ rc = saveAllCursors(pBt, pCur->pgnoRoot, pCur); if( rc ) return rc; } /* If this is a delete operation to remove a row from a table b-tree, ** invalidate any incrblob cursors open on the row being deleted. */ | | | > > > > | 9756 9757 9758 9759 9760 9761 9762 9763 9764 9765 9766 9767 9768 9769 9770 9771 9772 9773 9774 9775 9776 9777 9778 9779 9780 9781 9782 9783 9784 9785 9786 9787 9788 9789 9790 9791 9792 9793 9794 9795 9796 9797 | if( pCur->curFlags & BTCF_Multiple ){ rc = saveAllCursors(pBt, pCur->pgnoRoot, pCur); if( rc ) return rc; } /* If this is a delete operation to remove a row from a table b-tree, ** invalidate any incrblob cursors open on the row being deleted. */ if( pCur->pKeyInfo==0 && p->hasIncrblobCur ){ invalidateIncrblobCursors(p, pCur->pgnoRoot, pCur->info.nKey, 0); } /* Make the page containing the entry to be deleted writable. Then free any ** overflow pages associated with the entry and finally remove the cell ** itself from within the page. */ rc = sqlite3PagerWrite(pPage->pDbPage); if( rc ) return rc; BTREE_CLEAR_CELL(rc, pPage, pCell, info); dropCell(pPage, iCellIdx, info.nSize, &rc); if( rc ) return rc; /* If the cell deleted was not located on a leaf page, then the cursor ** is currently pointing to the largest entry in the sub-tree headed ** by the child-page of the cell that was just deleted from an internal ** node. The cell from the leaf node needs to be moved to the internal ** node to replace the deleted cell. */ if( !pPage->leaf ){ MemPage *pLeaf = pCur->pPage; int nCell; Pgno n; unsigned char *pTmp; if( pLeaf->nFree<0 ){ rc = btreeComputeFreeSpace(pLeaf); if( rc ) return rc; } if( iCellDepth<pCur->iPage-1 ){ n = pCur->apPage[iCellDepth+1]->pgno; }else{ n = pCur->pPage->pgno; } pCell = findCell(pLeaf, pLeaf->nCell-1); if( pCell<&pLeaf->aData[4] ) return SQLITE_CORRUPT_BKPT; |
︙ | ︙ | |||
9237 9238 9239 9240 9241 9242 9243 | ** The type of type is determined by the flags parameter. Only the ** following values of flags are currently in use. Other values for ** flags might not work: ** ** BTREE_INTKEY|BTREE_LEAFDATA Used for SQL tables with rowid keys ** BTREE_ZERODATA Used for SQL indices */ | | | 9864 9865 9866 9867 9868 9869 9870 9871 9872 9873 9874 9875 9876 9877 9878 | ** The type of type is determined by the flags parameter. Only the ** following values of flags are currently in use. Other values for ** flags might not work: ** ** BTREE_INTKEY|BTREE_LEAFDATA Used for SQL tables with rowid keys ** BTREE_ZERODATA Used for SQL indices */ static int btreeCreateTable(Btree *p, Pgno *piTable, int createTabFlags){ BtShared *pBt = p->pBt; MemPage *pRoot; Pgno pgnoRoot; int rc; int ptfFlags; /* Page-type flage for the root page of new table */ assert( sqlite3BtreeHoldsMutex(p) ); |
︙ | ︙ | |||
9270 9271 9272 9273 9274 9275 9276 9277 9278 9279 9280 9281 9282 9283 9284 9285 | invalidateAllOverflowCache(pBt); /* Read the value of meta[3] from the database to determine where the ** root page of the new table should go. meta[3] is the largest root-page ** created so far, so the new root-page is (meta[3]+1). */ sqlite3BtreeGetMeta(p, BTREE_LARGEST_ROOT_PAGE, &pgnoRoot); pgnoRoot++; /* The new root-page may not be allocated on a pointer-map page, or the ** PENDING_BYTE page. */ while( pgnoRoot==PTRMAP_PAGENO(pBt, pgnoRoot) || pgnoRoot==PENDING_BYTE_PAGE(pBt) ){ pgnoRoot++; } | > > > | < | 9897 9898 9899 9900 9901 9902 9903 9904 9905 9906 9907 9908 9909 9910 9911 9912 9913 9914 9915 9916 9917 9918 9919 9920 9921 9922 9923 | invalidateAllOverflowCache(pBt); /* Read the value of meta[3] from the database to determine where the ** root page of the new table should go. meta[3] is the largest root-page ** created so far, so the new root-page is (meta[3]+1). */ sqlite3BtreeGetMeta(p, BTREE_LARGEST_ROOT_PAGE, &pgnoRoot); if( pgnoRoot>btreePagecount(pBt) ){ return SQLITE_CORRUPT_BKPT; } pgnoRoot++; /* The new root-page may not be allocated on a pointer-map page, or the ** PENDING_BYTE page. */ while( pgnoRoot==PTRMAP_PAGENO(pBt, pgnoRoot) || pgnoRoot==PENDING_BYTE_PAGE(pBt) ){ pgnoRoot++; } assert( pgnoRoot>=3 ); /* Allocate a page. The page that currently resides at pgnoRoot will ** be moved to the allocated page (unless the allocated page happens ** to reside at pgnoRoot). */ rc = allocateBtreePage(pBt, &pPageMove, &pgnoMove, pgnoRoot, BTALLOC_EXACT); if( rc!=SQLITE_OK ){ |
︙ | ︙ | |||
9377 9378 9379 9380 9381 9382 9383 | ptfFlags = PTF_INTKEY | PTF_LEAFDATA | PTF_LEAF; }else{ ptfFlags = PTF_ZERODATA | PTF_LEAF; } zeroPage(pRoot, ptfFlags); sqlite3PagerUnref(pRoot->pDbPage); assert( (pBt->openFlags & BTREE_SINGLE)==0 || pgnoRoot==2 ); | | | | > | > < | > > | < < | | < | > | > | 10006 10007 10008 10009 10010 10011 10012 10013 10014 10015 10016 10017 10018 10019 10020 10021 10022 10023 10024 10025 10026 10027 10028 10029 10030 10031 10032 10033 10034 10035 10036 10037 10038 10039 10040 10041 10042 10043 10044 10045 10046 10047 10048 10049 10050 10051 10052 10053 10054 10055 10056 10057 10058 10059 10060 10061 10062 10063 10064 10065 10066 10067 10068 10069 10070 10071 10072 10073 10074 10075 10076 10077 10078 10079 10080 10081 10082 10083 10084 10085 10086 10087 10088 10089 10090 10091 10092 10093 10094 10095 10096 10097 10098 10099 10100 10101 10102 10103 10104 10105 10106 10107 10108 10109 10110 10111 10112 10113 10114 10115 10116 10117 10118 10119 10120 | ptfFlags = PTF_INTKEY | PTF_LEAFDATA | PTF_LEAF; }else{ ptfFlags = PTF_ZERODATA | PTF_LEAF; } zeroPage(pRoot, ptfFlags); sqlite3PagerUnref(pRoot->pDbPage); assert( (pBt->openFlags & BTREE_SINGLE)==0 || pgnoRoot==2 ); *piTable = pgnoRoot; return SQLITE_OK; } int sqlite3BtreeCreateTable(Btree *p, Pgno *piTable, int flags){ int rc; sqlite3BtreeEnter(p); rc = btreeCreateTable(p, piTable, flags); sqlite3BtreeLeave(p); return rc; } /* ** Erase the given database page and all its children. Return ** the page to the freelist. */ static int clearDatabasePage( BtShared *pBt, /* The BTree that contains the table */ Pgno pgno, /* Page number to clear */ int freePageFlag, /* Deallocate page if true */ i64 *pnChange, /* Add number of Cells freed to this counter */ Pgno pgnoRoot ){ MemPage *pPage; int rc; unsigned char *pCell; int i; int hdr; CellInfo info; assert( sqlite3_mutex_held(pBt->mutex) ); if( pgno>btreePagecount(pBt) ){ return SQLITE_CORRUPT_BKPT; } rc = getAndInitPage(pBt, pgno, &pPage, 0, 0); if( rc ) return rc; setMempageRoot(pPage, pgnoRoot); if( (pBt->openFlags & BTREE_SINGLE)==0 && sqlite3PagerPageRefcount(pPage->pDbPage)!=1 ){ rc = SQLITE_CORRUPT_BKPT; goto cleardatabasepage_out; } hdr = pPage->hdrOffset; for(i=0; i<pPage->nCell; i++){ pCell = findCell(pPage, i); if( !pPage->leaf ){ rc = clearDatabasePage(pBt, get4byte(pCell), 1, pnChange, pgnoRoot); if( rc ) goto cleardatabasepage_out; } BTREE_CLEAR_CELL(rc, pPage, pCell, info); if( rc ) goto cleardatabasepage_out; } if( !pPage->leaf ){ rc = clearDatabasePage( pBt, get4byte(&pPage->aData[hdr+8]), 1, pnChange, pgnoRoot ); if( rc ) goto cleardatabasepage_out; if( pPage->intKey ) pnChange = 0; } if( pnChange ){ testcase( !pPage->intKey ); *pnChange += pPage->nCell; } if( freePageFlag ){ freePage(pPage, &rc); }else if( (rc = sqlite3PagerWrite(pPage->pDbPage))==0 ){ zeroPage(pPage, pPage->aData[hdr] | PTF_LEAF); } cleardatabasepage_out: releasePage(pPage); return rc; } /* ** Delete all information from a single table in the database. iTable is ** the page number of the root of the table. After this routine returns, ** the root page is empty, but still exists. ** ** This routine will fail with SQLITE_LOCKED if there are any open ** read cursors on the table. Open write cursors are moved to the ** root of the table. ** ** If pnChange is not NULL, then the integer value pointed to by pnChange ** is incremented by the number of entries in the table. */ int sqlite3BtreeClearTable(Btree *p, int iTable, i64 *pnChange){ int rc; BtShared *pBt = p->pBt; sqlite3BtreeEnter(p); assert( p->inTrans==TRANS_WRITE ); rc = saveAllCursors(pBt, (Pgno)iTable, 0); if( SQLITE_OK==rc ){ /* Invalidate all incrblob cursors open on table iTable (assuming iTable ** is the root of a table b-tree - if it is not, the following call is ** a no-op). */ if( p->hasIncrblobCur ){ invalidateIncrblobCursors(p, (Pgno)iTable, 0, 1); } rc = clearDatabasePage(pBt, (Pgno)iTable, 0, pnChange, (Pgno)iTable); } sqlite3BtreeLeave(p); return rc; } /* |
︙ | ︙ | |||
9519 9520 9521 9522 9523 9524 9525 | int rc; MemPage *pPage = 0; BtShared *pBt = p->pBt; assert( sqlite3BtreeHoldsMutex(p) ); assert( p->inTrans==TRANS_WRITE ); assert( iTable>=2 ); | > > | | < | > > | 10150 10151 10152 10153 10154 10155 10156 10157 10158 10159 10160 10161 10162 10163 10164 10165 10166 10167 10168 10169 10170 10171 | int rc; MemPage *pPage = 0; BtShared *pBt = p->pBt; assert( sqlite3BtreeHoldsMutex(p) ); assert( p->inTrans==TRANS_WRITE ); assert( iTable>=2 ); if( iTable>btreePagecount(pBt) ){ return SQLITE_CORRUPT_BKPT; } rc = sqlite3BtreeClearTable(p, iTable, 0); if( rc ) return rc; rc = btreeGetPage(pBt, (Pgno)iTable, &pPage, 0); if( NEVER(rc) ){ releasePage(pPage); return rc; } *piMoved = 0; #ifdef SQLITE_OMIT_AUTOVACUUM |
︙ | ︙ | |||
9627 9628 9629 9630 9631 9632 9633 | ** read it from this routine. */ void sqlite3BtreeGetMeta(Btree *p, int idx, u32 *pMeta){ BtShared *pBt = p->pBt; sqlite3BtreeEnter(p); assert( p->inTrans>TRANS_NONE ); | | | | 10261 10262 10263 10264 10265 10266 10267 10268 10269 10270 10271 10272 10273 10274 10275 10276 10277 10278 10279 10280 | ** read it from this routine. */ void sqlite3BtreeGetMeta(Btree *p, int idx, u32 *pMeta){ BtShared *pBt = p->pBt; sqlite3BtreeEnter(p); assert( p->inTrans>TRANS_NONE ); assert( SQLITE_OK==querySharedCacheTableLock(p, SCHEMA_ROOT, READ_LOCK) ); assert( pBt->pPage1 ); assert( idx>=0 && idx<=15 ); if( idx==BTREE_DATA_VERSION ){ *pMeta = sqlite3PagerDataVersion(pBt->pPager) + p->iBDataVersion; }else{ *pMeta = get4byte(&pBt->pPage1->aData[36 + idx*4]); } /* If auto-vacuum is disabled in this build and this is an auto-vacuum ** database, mark the database as read-only. */ #ifdef SQLITE_OMIT_AUTOVACUUM |
︙ | ︙ | |||
9676 9677 9678 9679 9680 9681 9682 | } #endif } sqlite3BtreeLeave(p); return rc; } | < | | | 10310 10311 10312 10313 10314 10315 10316 10317 10318 10319 10320 10321 10322 10323 10324 10325 10326 10327 10328 10329 10330 10331 10332 10333 10334 10335 10336 10337 10338 10339 10340 10341 10342 10343 10344 10345 | } #endif } sqlite3BtreeLeave(p); return rc; } /* ** The first argument, pCur, is a cursor opened on some b-tree. Count the ** number of entries in the b-tree and write the result to *pnEntry. ** ** SQLITE_OK is returned if the operation is successfully executed. ** Otherwise, if an error is encountered (i.e. an IO error or database ** corruption) an SQLite error code is returned. */ int sqlite3BtreeCount(sqlite3 *db, BtCursor *pCur, i64 *pnEntry){ i64 nEntry = 0; /* Value to return in *pnEntry */ int rc; /* Return code */ rc = moveToRoot(pCur); if( rc==SQLITE_EMPTY ){ *pnEntry = 0; return SQLITE_OK; } /* Unless an error occurs, the following loop runs one iteration for each ** page in the B-Tree structure (not including overflow pages). */ while( rc==SQLITE_OK && !AtomicLoad(&db->u1.isInterrupted) ){ int iIdx; /* Index of child node in parent */ MemPage *pPage; /* Current page of the b-tree */ /* If this is a leaf page or the tree is not an int-key tree, then ** this page contains countable entries. Increment the entry counter ** accordingly. */ |
︙ | ︙ | |||
9749 9750 9751 9752 9753 9754 9755 | rc = moveToChild(pCur, get4byte(findCell(pPage, iIdx))); } } /* An error has occurred. Return an error code. */ return rc; } | < | 10382 10383 10384 10385 10386 10387 10388 10389 10390 10391 10392 10393 10394 10395 | rc = moveToChild(pCur, get4byte(findCell(pPage, iIdx))); } } /* An error has occurred. Return an error code. */ return rc; } /* ** Return the pager associated with a BTree. This routine is used for ** testing and debugging only. */ Pager *sqlite3BtreePager(Btree *p){ return p->pBt->pPager; |
︙ | ︙ | |||
9782 9783 9784 9785 9786 9787 9788 | } if( pCheck->zPfx ){ sqlite3_str_appendf(&pCheck->errMsg, pCheck->zPfx, pCheck->v1, pCheck->v2); } sqlite3_str_vappendf(&pCheck->errMsg, zFormat, ap); va_end(ap); if( pCheck->errMsg.accError==SQLITE_NOMEM ){ | | | 10414 10415 10416 10417 10418 10419 10420 10421 10422 10423 10424 10425 10426 10427 10428 | } if( pCheck->zPfx ){ sqlite3_str_appendf(&pCheck->errMsg, pCheck->zPfx, pCheck->v1, pCheck->v2); } sqlite3_str_vappendf(&pCheck->errMsg, zFormat, ap); va_end(ap); if( pCheck->errMsg.accError==SQLITE_NOMEM ){ pCheck->bOomFault = 1; } } #endif /* SQLITE_OMIT_INTEGRITY_CHECK */ #ifndef SQLITE_OMIT_INTEGRITY_CHECK /* |
︙ | ︙ | |||
9824 9825 9826 9827 9828 9829 9830 9831 9832 9833 9834 9835 9836 9837 | checkAppendMsg(pCheck, "invalid page number %d", iPage); return 1; } if( getPageReferenced(pCheck, iPage) ){ checkAppendMsg(pCheck, "2nd reference to page %d", iPage); return 1; } setPageReferenced(pCheck, iPage); return 0; } #ifndef SQLITE_OMIT_AUTOVACUUM /* ** Check that the entry in the pointer-map for page iChild maps to | > | 10456 10457 10458 10459 10460 10461 10462 10463 10464 10465 10466 10467 10468 10469 10470 | checkAppendMsg(pCheck, "invalid page number %d", iPage); return 1; } if( getPageReferenced(pCheck, iPage) ){ checkAppendMsg(pCheck, "2nd reference to page %d", iPage); return 1; } if( AtomicLoad(&pCheck->db->u1.isInterrupted) ) return 1; setPageReferenced(pCheck, iPage); return 0; } #ifndef SQLITE_OMIT_AUTOVACUUM /* ** Check that the entry in the pointer-map for page iChild maps to |
︙ | ︙ | |||
9846 9847 9848 9849 9850 9851 9852 | ){ int rc; u8 ePtrmapType; Pgno iPtrmapParent; rc = ptrmapGet(pCheck->pBt, iChild, &ePtrmapType, &iPtrmapParent); if( rc!=SQLITE_OK ){ | | | | | | 10479 10480 10481 10482 10483 10484 10485 10486 10487 10488 10489 10490 10491 10492 10493 10494 10495 10496 10497 10498 10499 10500 10501 10502 10503 10504 10505 10506 10507 10508 10509 10510 10511 10512 10513 10514 10515 10516 10517 | ){ int rc; u8 ePtrmapType; Pgno iPtrmapParent; rc = ptrmapGet(pCheck->pBt, iChild, &ePtrmapType, &iPtrmapParent); if( rc!=SQLITE_OK ){ if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ) pCheck->bOomFault = 1; checkAppendMsg(pCheck, "Failed to read ptrmap key=%d", iChild); return; } if( ePtrmapType!=eType || iPtrmapParent!=iParent ){ checkAppendMsg(pCheck, "Bad ptr map entry key=%d expected=(%d,%d) got=(%d,%d)", iChild, eType, iParent, ePtrmapType, iPtrmapParent); } } #endif /* ** Check the integrity of the freelist or of an overflow page list. ** Verify that the number of pages on the list is N. */ static void checkList( IntegrityCk *pCheck, /* Integrity checking context */ int isFreeList, /* True for a freelist. False for overflow page list */ Pgno iPage, /* Page number for first page in the list */ u32 N /* Expected number of pages in the list */ ){ int i; u32 expected = N; int nErrAtStart = pCheck->nErr; while( iPage!=0 && pCheck->mxErr ){ DbPage *pOvflPage; unsigned char *pOvflData; if( checkRef(pCheck, iPage) ) break; N--; if( sqlite3PagerGet(pCheck->pPager, (Pgno)iPage, &pOvflPage, 0) ){ |
︙ | ︙ | |||
9998 9999 10000 10001 10002 10003 10004 | ** 2. Make sure integer cell keys are in order. ** 3. Check the integrity of overflow pages. ** 4. Recursively call checkTreePage on all children. ** 5. Verify that the depth of all children is the same. */ static int checkTreePage( IntegrityCk *pCheck, /* Context for the sanity check */ | | | 10631 10632 10633 10634 10635 10636 10637 10638 10639 10640 10641 10642 10643 10644 10645 | ** 2. Make sure integer cell keys are in order. ** 3. Check the integrity of overflow pages. ** 4. Recursively call checkTreePage on all children. ** 5. Verify that the depth of all children is the same. */ static int checkTreePage( IntegrityCk *pCheck, /* Context for the sanity check */ Pgno iPage, /* Page number of the page to check */ i64 *piMinKey, /* Write minimum integer primary key here */ i64 maxKey /* Error if integer primary key greater than this */ ){ MemPage *pPage = 0; /* The page being analyzed */ int i; /* Loop counter */ int rc; /* Result code from subroutine call */ int depth = -1, d2; /* Depth of a subtree */ |
︙ | ︙ | |||
10034 10035 10036 10037 10038 10039 10040 | /* Check that the page exists */ pBt = pCheck->pBt; usableSize = pBt->usableSize; if( iPage==0 ) return 0; if( checkRef(pCheck, iPage) ) return 0; | | | > > > > > | | | 10667 10668 10669 10670 10671 10672 10673 10674 10675 10676 10677 10678 10679 10680 10681 10682 10683 10684 10685 10686 10687 10688 10689 10690 10691 10692 10693 10694 10695 10696 10697 10698 10699 10700 10701 10702 10703 10704 10705 10706 10707 10708 10709 10710 10711 10712 10713 10714 10715 10716 10717 10718 10719 10720 10721 10722 10723 10724 10725 10726 10727 10728 | /* Check that the page exists */ pBt = pCheck->pBt; usableSize = pBt->usableSize; if( iPage==0 ) return 0; if( checkRef(pCheck, iPage) ) return 0; pCheck->zPfx = "Page %u: "; pCheck->v1 = iPage; if( (rc = btreeGetPage(pBt, iPage, &pPage, 0))!=0 ){ checkAppendMsg(pCheck, "unable to get the page. error code=%d", rc); goto end_of_check; } /* Clear MemPage.isInit to make sure the corruption detection code in ** btreeInitPage() is executed. */ savedIsInit = pPage->isInit; pPage->isInit = 0; if( (rc = btreeInitPage(pPage))!=0 ){ assert( rc==SQLITE_CORRUPT ); /* The only possible error from InitPage */ checkAppendMsg(pCheck, "btreeInitPage() returns error code %d", rc); goto end_of_check; } if( (rc = btreeComputeFreeSpace(pPage))!=0 ){ assert( rc==SQLITE_CORRUPT ); checkAppendMsg(pCheck, "free space corruption", rc); goto end_of_check; } data = pPage->aData; hdr = pPage->hdrOffset; /* Set up for cell analysis */ pCheck->zPfx = "On tree page %u cell %d: "; contentOffset = get2byteNotZero(&data[hdr+5]); assert( contentOffset<=usableSize ); /* Enforced by btreeInitPage() */ /* EVIDENCE-OF: R-37002-32774 The two-byte integer at offset 3 gives the ** number of cells on the page. */ nCell = get2byte(&data[hdr+3]); assert( pPage->nCell==nCell ); /* EVIDENCE-OF: R-23882-45353 The cell pointer array of a b-tree page ** immediately follows the b-tree page header. */ cellStart = hdr + 12 - 4*pPage->leaf; assert( pPage->aCellIdx==&data[cellStart] ); pCellIdx = &data[cellStart + 2*(nCell-1)]; if( !pPage->leaf ){ /* Analyze the right-child page of internal pages */ pgno = get4byte(&data[hdr+8]); #ifndef SQLITE_OMIT_AUTOVACUUM if( pBt->autoVacuum ){ pCheck->zPfx = "On page %u at right child: "; checkPtrmap(pCheck, pgno, PTRMAP_BTREE, iPage); } #endif depth = checkTreePage(pCheck, pgno, &maxKey, maxKey); keyCanBeEqual = 0; }else{ /* For leaf pages, the coverage check will occur in the same loop |
︙ | ︙ | |||
10124 10125 10126 10127 10128 10129 10130 | } maxKey = info.nKey; keyCanBeEqual = 0; /* Only the first key on the page may ==maxKey */ } /* Check the content overflow list */ if( info.nPayload>info.nLocal ){ | | | 10762 10763 10764 10765 10766 10767 10768 10769 10770 10771 10772 10773 10774 10775 10776 | } maxKey = info.nKey; keyCanBeEqual = 0; /* Only the first key on the page may ==maxKey */ } /* Check the content overflow list */ if( info.nPayload>info.nLocal ){ u32 nPage; /* Number of pages on the overflow chain */ Pgno pgnoOvfl; /* First page of the overflow chain */ assert( pc + info.nSize - 4 <= usableSize ); nPage = (info.nPayload - info.nLocal + usableSize - 5)/(usableSize - 4); pgnoOvfl = get4byte(&pCell[info.nSize - 4]); #ifndef SQLITE_OMIT_AUTOVACUUM if( pBt->autoVacuum ){ checkPtrmap(pCheck, pgnoOvfl, PTRMAP_OVERFLOW1, iPage); |
︙ | ︙ | |||
10184 10185 10186 10187 10188 10189 10190 | ** EVIDENCE-OF: R-20690-50594 The second field of the b-tree page header ** is the offset of the first freeblock, or zero if there are no ** freeblocks on the page. */ i = get2byte(&data[hdr+1]); while( i>0 ){ int size, j; | | | | | | | | 10822 10823 10824 10825 10826 10827 10828 10829 10830 10831 10832 10833 10834 10835 10836 10837 10838 10839 10840 10841 10842 10843 10844 10845 10846 10847 10848 10849 10850 10851 10852 10853 10854 10855 10856 10857 10858 10859 10860 10861 10862 10863 10864 10865 10866 10867 10868 10869 10870 10871 10872 10873 10874 10875 10876 10877 10878 10879 10880 10881 10882 10883 10884 | ** EVIDENCE-OF: R-20690-50594 The second field of the b-tree page header ** is the offset of the first freeblock, or zero if there are no ** freeblocks on the page. */ i = get2byte(&data[hdr+1]); while( i>0 ){ int size, j; assert( (u32)i<=usableSize-4 ); /* Enforced by btreeComputeFreeSpace() */ size = get2byte(&data[i+2]); assert( (u32)(i+size)<=usableSize ); /* due to btreeComputeFreeSpace() */ btreeHeapInsert(heap, (((u32)i)<<16)|(i+size-1)); /* EVIDENCE-OF: R-58208-19414 The first 2 bytes of a freeblock are a ** big-endian integer which is the offset in the b-tree page of the next ** freeblock in the chain, or zero if the freeblock is the last on the ** chain. */ j = get2byte(&data[i]); /* EVIDENCE-OF: R-06866-39125 Freeblocks are always connected in order of ** increasing offset. */ assert( j==0 || j>i+size ); /* Enforced by btreeComputeFreeSpace() */ assert( (u32)j<=usableSize-4 ); /* Enforced by btreeComputeFreeSpace() */ i = j; } /* Analyze the min-heap looking for overlap between cells and/or ** freeblocks, and counting the number of untracked bytes in nFrag. ** ** Each min-heap entry is of the form: (start_address<<16)|end_address. ** There is an implied first entry the covers the page header, the cell ** pointer index, and the gap between the cell pointer index and the start ** of cell content. ** ** The loop below pulls entries from the min-heap in order and compares ** the start_address against the previous end_address. If there is an ** overlap, that means bytes are used multiple times. If there is a gap, ** that gap is added to the fragmentation count. */ nFrag = 0; prev = contentOffset - 1; /* Implied first min-heap entry */ while( btreeHeapPull(heap,&x) ){ if( (prev&0xffff)>=(x>>16) ){ checkAppendMsg(pCheck, "Multiple uses for byte %u of page %u", x>>16, iPage); break; }else{ nFrag += (x>>16) - (prev&0xffff) - 1; prev = x; } } nFrag += usableSize - (prev&0xffff) - 1; /* EVIDENCE-OF: R-43263-13491 The total number of bytes in all fragments ** is stored in the fifth field of the b-tree page header. ** EVIDENCE-OF: R-07161-27322 The one-byte integer at offset 7 gives the ** number of fragmented free bytes within the cell content area. */ if( heap[0]==0 && nFrag!=data[hdr+7] ){ checkAppendMsg(pCheck, "Fragmentation of %d bytes reported as %d on page %u", nFrag, data[hdr+7], iPage); } } end_of_check: if( !doCoverageCheck ) pPage->isInit = savedIsInit; releasePage(pPage); |
︙ | ︙ | |||
10260 10261 10262 10263 10264 10265 10266 10267 10268 10269 | ** A read-only or read-write transaction must be opened before calling ** this function. ** ** Write the number of error seen in *pnErr. Except for some memory ** allocation errors, an error message held in memory obtained from ** malloc is returned if *pnErr is non-zero. If *pnErr==0 then NULL is ** returned. If a memory allocation error occurs, NULL is returned. */ char *sqlite3BtreeIntegrityCheck( Btree *p, /* The btree to be checked */ | > > > > > > > > > > | | > > > > > > > > > > > | | | > | | | | | > > | | | | | | | | | | | | | | | > | > | | | | | | | | | | | | | | | | | | | > | | 10898 10899 10900 10901 10902 10903 10904 10905 10906 10907 10908 10909 10910 10911 10912 10913 10914 10915 10916 10917 10918 10919 10920 10921 10922 10923 10924 10925 10926 10927 10928 10929 10930 10931 10932 10933 10934 10935 10936 10937 10938 10939 10940 10941 10942 10943 10944 10945 10946 10947 10948 10949 10950 10951 10952 10953 10954 10955 10956 10957 10958 10959 10960 10961 10962 10963 10964 10965 10966 10967 10968 10969 10970 10971 10972 10973 10974 10975 10976 10977 10978 10979 10980 10981 10982 10983 10984 10985 10986 10987 10988 10989 10990 10991 10992 10993 10994 10995 10996 10997 10998 10999 11000 11001 11002 11003 11004 11005 11006 11007 11008 11009 11010 11011 11012 11013 11014 11015 11016 11017 11018 11019 11020 11021 11022 11023 11024 11025 11026 11027 11028 11029 11030 11031 11032 11033 11034 11035 11036 11037 11038 11039 11040 11041 11042 11043 11044 11045 11046 11047 11048 11049 11050 11051 11052 11053 11054 11055 11056 11057 11058 11059 | ** A read-only or read-write transaction must be opened before calling ** this function. ** ** Write the number of error seen in *pnErr. Except for some memory ** allocation errors, an error message held in memory obtained from ** malloc is returned if *pnErr is non-zero. If *pnErr==0 then NULL is ** returned. If a memory allocation error occurs, NULL is returned. ** ** If the first entry in aRoot[] is 0, that indicates that the list of ** root pages is incomplete. This is a "partial integrity-check". This ** happens when performing an integrity check on a single table. The ** zero is skipped, of course. But in addition, the freelist checks ** and the checks to make sure every page is referenced are also skipped, ** since obviously it is not possible to know which pages are covered by ** the unverified btrees. Except, if aRoot[1] is 1, then the freelist ** checks are still performed. */ char *sqlite3BtreeIntegrityCheck( sqlite3 *db, /* Database connection that is running the check */ Btree *p, /* The btree to be checked */ Pgno *aRoot, /* An array of root pages numbers for individual trees */ int nRoot, /* Number of entries in aRoot[] */ int mxErr, /* Stop reporting errors after this many */ int *pnErr /* Write number of errors seen to this variable */ ){ Pgno i; IntegrityCk sCheck; BtShared *pBt = p->pBt; u64 savedDbFlags = pBt->db->flags; char zErr[100]; int bPartial = 0; /* True if not checking all btrees */ int bCkFreelist = 1; /* True to scan the freelist */ VVA_ONLY( int nRef ); assert( nRoot>0 ); /* aRoot[0]==0 means this is a partial check */ if( aRoot[0]==0 ){ assert( nRoot>1 ); bPartial = 1; if( aRoot[1]!=1 ) bCkFreelist = 0; } sqlite3BtreeEnter(p); assert( p->inTrans>TRANS_NONE && pBt->inTransaction>TRANS_NONE ); VVA_ONLY( nRef = sqlite3PagerRefcount(pBt->pPager) ); assert( nRef>=0 ); sCheck.db = db; sCheck.pBt = pBt; sCheck.pPager = pBt->pPager; sCheck.nPage = btreePagecount(sCheck.pBt); sCheck.mxErr = mxErr; sCheck.nErr = 0; sCheck.bOomFault = 0; sCheck.zPfx = 0; sCheck.v1 = 0; sCheck.v2 = 0; sCheck.aPgRef = 0; sCheck.heap = 0; sqlite3StrAccumInit(&sCheck.errMsg, 0, zErr, sizeof(zErr), SQLITE_MAX_LENGTH); sCheck.errMsg.printfFlags = SQLITE_PRINTF_INTERNAL; if( sCheck.nPage==0 ){ goto integrity_ck_cleanup; } sCheck.aPgRef = sqlite3MallocZero((sCheck.nPage / 8)+ 1); if( !sCheck.aPgRef ){ sCheck.bOomFault = 1; goto integrity_ck_cleanup; } sCheck.heap = (u32*)sqlite3PageMalloc( pBt->pageSize ); if( sCheck.heap==0 ){ sCheck.bOomFault = 1; goto integrity_ck_cleanup; } i = PENDING_BYTE_PAGE(pBt); if( i<=sCheck.nPage ) setPageReferenced(&sCheck, i); /* Check the integrity of the freelist */ if( bCkFreelist ){ sCheck.zPfx = "Main freelist: "; checkList(&sCheck, 1, get4byte(&pBt->pPage1->aData[32]), get4byte(&pBt->pPage1->aData[36])); sCheck.zPfx = 0; } /* Check all the tables. */ #ifndef SQLITE_OMIT_AUTOVACUUM if( !bPartial ){ if( pBt->autoVacuum ){ Pgno mx = 0; Pgno mxInHdr; for(i=0; (int)i<nRoot; i++) if( mx<aRoot[i] ) mx = aRoot[i]; mxInHdr = get4byte(&pBt->pPage1->aData[52]); if( mx!=mxInHdr ){ checkAppendMsg(&sCheck, "max rootpage (%d) disagrees with header (%d)", mx, mxInHdr ); } }else if( get4byte(&pBt->pPage1->aData[64])!=0 ){ checkAppendMsg(&sCheck, "incremental_vacuum enabled with a max rootpage of zero" ); } } #endif testcase( pBt->db->flags & SQLITE_CellSizeCk ); pBt->db->flags &= ~(u64)SQLITE_CellSizeCk; for(i=0; (int)i<nRoot && sCheck.mxErr; i++){ i64 notUsed; if( aRoot[i]==0 ) continue; #ifndef SQLITE_OMIT_AUTOVACUUM if( pBt->autoVacuum && aRoot[i]>1 && !bPartial ){ checkPtrmap(&sCheck, aRoot[i], PTRMAP_ROOTPAGE, 0); } #endif checkTreePage(&sCheck, aRoot[i], ¬Used, LARGEST_INT64); } pBt->db->flags = savedDbFlags; if( !bPartial ){ /* Make sure every page in the file is referenced. Skip this if the ** database is currently being written by a CONCURRENT transaction (it ** may fail as pages that were part of the free-list when the transaction ** was opened cannot be counted). */ for(i=1; ISCONCURRENT==0 && i<=sCheck.nPage && sCheck.mxErr; i++){ #ifdef SQLITE_OMIT_AUTOVACUUM if( getPageReferenced(&sCheck, i)==0 ){ checkAppendMsg(&sCheck, "Page %d is never used", i); } #else /* If the database supports auto-vacuum, make sure no tables contain ** references to pointer-map pages. */ if( getPageReferenced(&sCheck, i)==0 && (PTRMAP_PAGENO(pBt, i)!=i || !pBt->autoVacuum) ){ checkAppendMsg(&sCheck, "Page %d is never used", i); } if( getPageReferenced(&sCheck, i)!=0 && (PTRMAP_PAGENO(pBt, i)==i && pBt->autoVacuum) ){ checkAppendMsg(&sCheck, "Pointer map page %d is referenced", i); } #endif } } /* Clean up and report errors. */ integrity_ck_cleanup: sqlite3PageFree(sCheck.heap); sqlite3_free(sCheck.aPgRef); if( sCheck.bOomFault ){ sqlite3_str_reset(&sCheck.errMsg); sCheck.nErr++; } *pnErr = sCheck.nErr; if( sCheck.nErr==0 ) sqlite3_str_reset(&sCheck.errMsg); /* Make sure this analysis did not leave any unref() pages. */ assert( nRef==sqlite3PagerRefcount(pBt->pPager) ); |
︙ | ︙ | |||
10419 10420 10421 10422 10423 10424 10425 | */ const char *sqlite3BtreeGetJournalname(Btree *p){ assert( p->pBt->pPager!=0 ); return sqlite3PagerJournalname(p->pBt->pPager); } /* | > | | | | 11084 11085 11086 11087 11088 11089 11090 11091 11092 11093 11094 11095 11096 11097 11098 11099 11100 11101 11102 11103 | */ const char *sqlite3BtreeGetJournalname(Btree *p){ assert( p->pBt->pPager!=0 ); return sqlite3PagerJournalname(p->pBt->pPager); } /* ** Return one of SQLITE_TXN_NONE, SQLITE_TXN_READ, or SQLITE_TXN_WRITE ** to describe the current transaction state of Btree p. */ int sqlite3BtreeTxnState(Btree *p){ assert( p==0 || sqlite3_mutex_held(p->db->mutex) ); return p ? p->inTrans : 0; } #ifndef SQLITE_OMIT_WAL /* ** Run a checkpoint on the Btree passed as the first argument. ** ** Return SQLITE_LOCKED if this or any other connection has an open |
︙ | ︙ | |||
10452 10453 10454 10455 10456 10457 10458 | sqlite3BtreeLeave(p); } return rc; } #endif /* | | < < < < < < | 11118 11119 11120 11121 11122 11123 11124 11125 11126 11127 11128 11129 11130 11131 11132 11133 | sqlite3BtreeLeave(p); } return rc; } #endif /* ** Return true if there is currently a backup running on Btree p. */ int sqlite3BtreeIsInBackup(Btree *p){ assert( p ); assert( sqlite3_mutex_held(p->db->mutex) ); return p->nBackup!=0; } /* |
︙ | ︙ | |||
10500 10501 10502 10503 10504 10505 10506 | sqlite3BtreeLeave(p); return pBt->pSchema; } /* ** Return SQLITE_LOCKED_SHAREDCACHE if another user of the same shared ** btree as the argument handle holds an exclusive lock on the | | | | 11160 11161 11162 11163 11164 11165 11166 11167 11168 11169 11170 11171 11172 11173 11174 11175 11176 11177 11178 11179 11180 | sqlite3BtreeLeave(p); return pBt->pSchema; } /* ** Return SQLITE_LOCKED_SHAREDCACHE if another user of the same shared ** btree as the argument handle holds an exclusive lock on the ** sqlite_schema table. Otherwise SQLITE_OK. */ int sqlite3BtreeSchemaLocked(Btree *p){ int rc; assert( sqlite3_mutex_held(p->db->mutex) ); sqlite3BtreeEnter(p); rc = querySharedCacheTableLock(p, SCHEMA_ROOT, READ_LOCK); assert( rc==SQLITE_OK || rc==SQLITE_LOCKED_SHAREDCACHE ); sqlite3BtreeLeave(p); return rc; } #ifndef SQLITE_OMIT_SHARED_CACHE |
︙ | ︙ | |||
10682 10683 10684 10685 10686 10687 10688 | */ int sqlite3BtreeExclusiveLock(Btree *p){ int rc; Pgno pgno = 0; BtShared *pBt = p->pBt; assert( p->inTrans==TRANS_WRITE && pBt->pPage1 ); sqlite3BtreeEnter(p); | | > > > | 11342 11343 11344 11345 11346 11347 11348 11349 11350 11351 11352 11353 11354 11355 11356 11357 11358 11359 | */ int sqlite3BtreeExclusiveLock(Btree *p){ int rc; Pgno pgno = 0; BtShared *pBt = p->pBt; assert( p->inTrans==TRANS_WRITE && pBt->pPage1 ); sqlite3BtreeEnter(p); rc = sqlite3PagerExclusiveLock(pBt->pPager, (p->db->eConcurrent==CONCURRENT_SCHEMA) ? 0 : pBt->pPage1->pDbPage, &pgno ); #ifdef SQLITE_OMIT_CONCURRENT assert( pgno==0 ); #else if( rc==SQLITE_BUSY_SNAPSHOT && pgno ){ PgHdr *pPg = 0; int rc2 = sqlite3PagerGet(pBt->pPager, pgno, &pPg, 0); if( rc2==SQLITE_OK ){ |
︙ | ︙ |
Changes to src/btree.h.
︙ | ︙ | |||
67 68 69 70 71 72 73 | int sqlite3BtreeSetSpillSize(Btree*,int); #if SQLITE_MAX_MMAP_SIZE>0 int sqlite3BtreeSetMmapLimit(Btree*,sqlite3_int64); #endif int sqlite3BtreeSetPagerFlags(Btree*,unsigned); int sqlite3BtreeSetPageSize(Btree *p, int nPagesize, int nReserve, int eFix); int sqlite3BtreeGetPageSize(Btree*); | | | | | | | | | > > > > > > > > | 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 | int sqlite3BtreeSetSpillSize(Btree*,int); #if SQLITE_MAX_MMAP_SIZE>0 int sqlite3BtreeSetMmapLimit(Btree*,sqlite3_int64); #endif int sqlite3BtreeSetPagerFlags(Btree*,unsigned); int sqlite3BtreeSetPageSize(Btree *p, int nPagesize, int nReserve, int eFix); int sqlite3BtreeGetPageSize(Btree*); Pgno sqlite3BtreeMaxPageCount(Btree*,Pgno); Pgno sqlite3BtreeLastPage(Btree*); int sqlite3BtreeSecureDelete(Btree*,int); int sqlite3BtreeGetRequestedReserve(Btree*); int sqlite3BtreeGetReserveNoMutex(Btree *p); int sqlite3BtreeSetAutoVacuum(Btree *, int); int sqlite3BtreeGetAutoVacuum(Btree *); int sqlite3BtreeBeginTrans(Btree*,int,int*); int sqlite3BtreeCommitPhaseOne(Btree*, const char*); int sqlite3BtreeCommitPhaseTwo(Btree*, int); int sqlite3BtreeCommit(Btree*); int sqlite3BtreeRollback(Btree*,int,int); int sqlite3BtreeBeginStmt(Btree*,int); int sqlite3BtreeCreateTable(Btree*, Pgno*, int flags); int sqlite3BtreeTxnState(Btree*); int sqlite3BtreeIsInBackup(Btree*); void *sqlite3BtreeSchema(Btree *, int, void(*)(void *)); int sqlite3BtreeSchemaLocked(Btree *pBtree); #ifndef SQLITE_OMIT_SHARED_CACHE int sqlite3BtreeLockTable(Btree *pBtree, int iTab, u8 isWriteLock); #endif /* Savepoints are named, nestable SQL transactions mostly implemented */ /* in vdbe.c and pager.c See https://sqlite.org/lang_savepoint.html */ int sqlite3BtreeSavepoint(Btree *, int, int); /* "Checkpoint" only refers to WAL. See https://sqlite.org/wal.html#ckpt */ #ifndef SQLITE_OMIT_WAL int sqlite3BtreeCheckpoint(Btree*, int, int *, int *); #endif const char *sqlite3BtreeGetFilename(Btree *); const char *sqlite3BtreeGetJournalname(Btree *); int sqlite3BtreeCopyFile(Btree *, Btree *); int sqlite3BtreeIncrVacuum(Btree *); |
︙ | ︙ | |||
111 112 113 114 115 116 117 | ** anywhere - the key is the content. (BTREE_BLOBKEY is used for SQL ** indices.) */ #define BTREE_INTKEY 1 /* Table has only 64-bit signed integer keys */ #define BTREE_BLOBKEY 2 /* Table has keys only - no data */ int sqlite3BtreeDropTable(Btree*, int, int*); | | | 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 | ** anywhere - the key is the content. (BTREE_BLOBKEY is used for SQL ** indices.) */ #define BTREE_INTKEY 1 /* Table has only 64-bit signed integer keys */ #define BTREE_BLOBKEY 2 /* Table has keys only - no data */ int sqlite3BtreeDropTable(Btree*, int, int*); int sqlite3BtreeClearTable(Btree*, int, i64*); int sqlite3BtreeClearTableOfCursor(BtCursor*); int sqlite3BtreeTripAllCursors(Btree*, int, int); void sqlite3BtreeGetMeta(Btree *pBtree, int idx, u32 *pValue); int sqlite3BtreeUpdateMeta(Btree*, int idx, u32 value); int sqlite3BtreeNewDb(Btree *p); |
︙ | ︙ | |||
221 222 223 224 225 226 227 | ** FORDELETE cursor may return a null row: 0x01 0x00. */ #define BTREE_WRCSR 0x00000004 /* read-write cursor */ #define BTREE_FORDELETE 0x00000008 /* Cursor is for seek/delete only */ int sqlite3BtreeCursor( Btree*, /* BTree containing table to open */ | | | < > > > > > > | 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 | ** FORDELETE cursor may return a null row: 0x01 0x00. */ #define BTREE_WRCSR 0x00000004 /* read-write cursor */ #define BTREE_FORDELETE 0x00000008 /* Cursor is for seek/delete only */ int sqlite3BtreeCursor( Btree*, /* BTree containing table to open */ Pgno iTable, /* Index of root page */ int wrFlag, /* 1 for writing. 0 for read-only */ struct KeyInfo*, /* First argument to compare function */ BtCursor *pCursor /* Space to write cursor structure */ ); BtCursor *sqlite3BtreeFakeValidCursor(void); int sqlite3BtreeCursorSize(void); void sqlite3BtreeCursorZero(BtCursor*); void sqlite3BtreeCursorHintFlags(BtCursor*, unsigned); #ifdef SQLITE_ENABLE_CURSOR_HINTS void sqlite3BtreeCursorHint(BtCursor*, int, ...); #endif int sqlite3BtreeCloseCursor(BtCursor*); int sqlite3BtreeTableMoveto( BtCursor*, i64 intKey, int bias, int *pRes ); int sqlite3BtreeIndexMoveto( BtCursor*, UnpackedRecord *pUnKey, int *pRes ); int sqlite3BtreeCursorHasMoved(BtCursor*); int sqlite3BtreeCursorRestore(BtCursor*, int*); int sqlite3BtreeDelete(BtCursor*, u8 flags); /* Allowed flags for sqlite3BtreeDelete() and sqlite3BtreeInsert() */ #define BTREE_SAVEPOSITION 0x02 /* Leave cursor pointing at NEXT or PREV */ #define BTREE_AUXDELETE 0x04 /* not the primary delete operation */ #define BTREE_APPEND 0x08 /* Insert is likely an append */ #define BTREE_PREFORMAT 0x80 /* Inserted data is a preformated cell */ /* An instance of the BtreePayload object describes the content of a single ** entry in either an index or table btree. ** ** Index btrees (used for indexes and also WITHOUT ROWID tables) contain ** an arbitrary key and no data. These btrees have pKey,nKey set to the ** key and the pData,nData,nZero fields are uninitialized. The aMem,nMem |
︙ | ︙ | |||
297 298 299 300 301 302 303 | int nData; /* Size of pData. 0 if none. */ int nZero; /* Extra zero data appended after pData,nData */ }; int sqlite3BtreeInsert(BtCursor*, const BtreePayload *pPayload, int flags, int seekResult); int sqlite3BtreeFirst(BtCursor*, int *pRes); | < < < > > > | > > > > > > < | < > > | 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 | int nData; /* Size of pData. 0 if none. */ int nZero; /* Extra zero data appended after pData,nData */ }; int sqlite3BtreeInsert(BtCursor*, const BtreePayload *pPayload, int flags, int seekResult); int sqlite3BtreeFirst(BtCursor*, int *pRes); int sqlite3BtreeLast(BtCursor*, int *pRes); int sqlite3BtreeNext(BtCursor*, int flags); int sqlite3BtreeEof(BtCursor*); int sqlite3BtreePrevious(BtCursor*, int flags); i64 sqlite3BtreeIntegerKey(BtCursor*); void sqlite3BtreeCursorPin(BtCursor*); void sqlite3BtreeCursorUnpin(BtCursor*); #ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC i64 sqlite3BtreeOffset(BtCursor*); #endif int sqlite3BtreePayload(BtCursor*, u32 offset, u32 amt, void*); const void *sqlite3BtreePayloadFetch(BtCursor*, u32 *pAmt); u32 sqlite3BtreePayloadSize(BtCursor*); sqlite3_int64 sqlite3BtreeMaxRecordSize(BtCursor*); char *sqlite3BtreeIntegrityCheck(sqlite3*,Btree*,Pgno*aRoot,int nRoot,int,int*); struct Pager *sqlite3BtreePager(Btree*); i64 sqlite3BtreeRowCountEst(BtCursor*); #ifndef SQLITE_OMIT_INCRBLOB int sqlite3BtreePayloadChecked(BtCursor*, u32 offset, u32 amt, void*); int sqlite3BtreePutData(BtCursor*, u32 offset, u32 amt, void*); void sqlite3BtreeIncrblobCursor(BtCursor *); #endif void sqlite3BtreeClearCursor(BtCursor *); int sqlite3BtreeSetVersion(Btree *pBt, int iVersion); int sqlite3BtreeCursorHasHint(BtCursor*, unsigned int mask); int sqlite3BtreeIsReadonly(Btree *pBt); int sqlite3HeaderSizeBtree(void); #ifdef SQLITE_DEBUG sqlite3_uint64 sqlite3BtreeSeekCount(Btree*); #else # define sqlite3BtreeSeekCount(X) 0 #endif int sqlite3BtreeExclusiveLock(Btree *pBt); #ifndef NDEBUG int sqlite3BtreeCursorIsValid(BtCursor*); #endif int sqlite3BtreeCursorIsValidNN(BtCursor*); int sqlite3BtreeCount(sqlite3*, BtCursor*, i64*); #ifdef SQLITE_TEST int sqlite3BtreeCursorInfo(BtCursor*, int*, int); void sqlite3BtreeCursorList(Btree*); #endif #ifndef SQLITE_OMIT_WAL int sqlite3BtreeCheckpoint(Btree*, int, int *, int *); #endif int sqlite3BtreeTransferRow(BtCursor*, BtCursor*, i64); /* ** If we are not using shared cache, then there is no need to ** use mutexes to access the BtShared structures. So make the ** Enter and Leave procedures no-ops. */ #ifndef SQLITE_OMIT_SHARED_CACHE |
︙ | ︙ |
Changes to src/btreeInt.h.
︙ | ︙ | |||
269 270 271 272 273 274 275 | ** "extra" information associated with each page of the pager.) ** ** Access to all fields of this structure is controlled by the mutex ** stored in MemPage.pBt->mutex. */ struct MemPage { u8 isInit; /* True if previously initialized. MUST BE FIRST! */ | < | | 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 | ** "extra" information associated with each page of the pager.) ** ** Access to all fields of this structure is controlled by the mutex ** stored in MemPage.pBt->mutex. */ struct MemPage { u8 isInit; /* True if previously initialized. MUST BE FIRST! */ u8 intKey; /* True if table b-trees. False for index b-trees */ u8 intKeyLeaf; /* True if the leaf of an intKey table */ Pgno pgno; /* Page number for this page */ #ifndef SQLITE_OMIT_CONCURRENT Pgno pgnoRoot; /* Root page of b-tree that this page belongs to */ #endif /* Only the first 8 bytes (above) are zeroed by pager.c when a new page ** is allocated. All fields that follow must be initialized before use */ u8 leaf; /* True if a leaf page */ u8 hdrOffset; /* 100 for page 1. 0 otherwise */ u8 childPtrSize; /* 0 if leaf==1. 4 if leaf==0 */ u8 max1bytePayload; /* min(maxLocal,127) */ u8 nOverflow; /* Number of overflow cell bodies in aCell[] */ u16 maxLocal; /* Copy of BtShared.maxLocal or BtShared.maxLeaf */ u16 minLocal; /* Copy of BtShared.minLocal or BtShared.minLeaf */ u16 cellOffset; /* Index in aData of first cell pointer */ int nFree; /* Number of free bytes on the page. -1 for unknown */ u16 nCell; /* Number of cells on this page, local and ovfl */ u16 maskPage; /* Mask for page offset */ u16 aiOvfl[4]; /* Insert the i-th overflow cell before the aiOvfl-th ** non-overflow cell */ u8 *apOvfl[4]; /* Pointers to the body of overflow cells */ BtShared *pBt; /* Pointer to BtShared that this page is part of */ u8 *aData; /* Pointer to disk image of the page data */ |
︙ | ︙ | |||
350 351 352 353 354 355 356 | BtShared *pBt; /* Sharable content of this btree */ u8 inTrans; /* TRANS_NONE, TRANS_READ or TRANS_WRITE */ u8 sharable; /* True if we can share pBt with another db */ u8 locked; /* True if db currently has pBt locked */ u8 hasIncrblobCur; /* True if there are one or more Incrblob cursors */ int wantToLock; /* Number of nested calls to sqlite3BtreeEnter() */ int nBackup; /* Number of backup operations reading this btree */ | | > > > > > > > > > > > > > > > > > | | 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 | BtShared *pBt; /* Sharable content of this btree */ u8 inTrans; /* TRANS_NONE, TRANS_READ or TRANS_WRITE */ u8 sharable; /* True if we can share pBt with another db */ u8 locked; /* True if db currently has pBt locked */ u8 hasIncrblobCur; /* True if there are one or more Incrblob cursors */ int wantToLock; /* Number of nested calls to sqlite3BtreeEnter() */ int nBackup; /* Number of backup operations reading this btree */ u32 iBDataVersion; /* Combines with pBt->pPager->iDataVersion */ Btree *pNext; /* List of other sharable Btrees from the same db */ Btree *pPrev; /* Back pointer of the same list */ #ifdef SQLITE_DEBUG u64 nSeek; /* Calls to sqlite3BtreeMovetoUnpacked() */ #endif #ifndef SQLITE_OMIT_SHARED_CACHE BtLock lock; /* Object used to lock page 1 */ #endif }; /* ** Btree.inTrans may take one of the following values. ** ** If the shared-data extension is enabled, there may be multiple users ** of the Btree structure. At most one of these may open a write transaction, ** but any number may have active read transactions. ** ** These values must match SQLITE_TXN_NONE, SQLITE_TXN_READ, and ** SQLITE_TXN_WRITE */ #define TRANS_NONE 0 #define TRANS_READ 1 #define TRANS_WRITE 2 #if TRANS_NONE!=SQLITE_TXN_NONE # error wrong numeric code for no-transaction #endif #if TRANS_READ!=SQLITE_TXN_READ # error wrong numeric code for read-transaction #endif #if TRANS_WRITE!=SQLITE_TXN_WRITE # error wrong numeric code for write-transaction #endif /* ** An instance of this object represents a single database file. ** ** A single database file can be in use at the same time by two ** or more database connections. When two or more connections are ** sharing the same database file, each connection has it own ** private Btree object for the file and each of those Btrees points ** to this one BtShared object. BtShared.nRef is the number of ** connections currently sharing this database file. ** ** Fields in this structure are accessed under the BtShared.mutex ** mutex, except for nRef and pNext which are accessed under the ** global SQLITE_MUTEX_STATIC_MAIN mutex. The pPager field ** may not be modified once it is initially set as long as nRef>0. ** The pSchema field may be set once under BtShared.mutex and ** thereafter is unchanged as long as nRef>0. ** ** isPending: ** ** If a BtShared client fails to obtain a write-lock on a database |
︙ | ︙ | |||
417 418 419 420 421 422 423 | #ifndef SQLITE_OMIT_AUTOVACUUM u8 autoVacuum; /* True if auto-vacuum is enabled */ u8 incrVacuum; /* True if incr-vacuum is enabled */ u8 bDoTruncate; /* True to truncate db on commit */ #endif u8 inTransaction; /* Transaction state */ u8 max1bytePayload; /* Maximum first byte of cell for a 1-byte payload */ | < | < | 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 | #ifndef SQLITE_OMIT_AUTOVACUUM u8 autoVacuum; /* True if auto-vacuum is enabled */ u8 incrVacuum; /* True if incr-vacuum is enabled */ u8 bDoTruncate; /* True to truncate db on commit */ #endif u8 inTransaction; /* Transaction state */ u8 max1bytePayload; /* Maximum first byte of cell for a 1-byte payload */ u8 nReserveWanted; /* Desired number of extra bytes per page */ u16 btsFlags; /* Boolean parameters. See BTS_* macros below */ u16 maxLocal; /* Maximum local payload in non-LEAFDATA tables */ u16 minLocal; /* Minimum local payload in non-LEAFDATA tables */ u16 maxLeaf; /* Maximum local payload in a LEAFDATA table */ u16 minLeaf; /* Minimum local payload in a LEAFDATA table */ u32 pageSize; /* Total number of bytes on a page */ u32 usableSize; /* Number of usable bytes on each page */ |
︙ | ︙ | |||
443 444 445 446 447 448 449 450 451 452 453 454 455 456 | BtLock *pLock; /* List of locks held on this shared-btree struct */ Btree *pWriter; /* Btree with currently open write transaction */ #endif u8 *pTmpSpace; /* Temp space sufficient to hold a single cell */ #ifndef SQLITE_OMIT_CONCURRENT BtreePtrmap *pMap; #endif }; /* ** Allowed values for BtShared.btsFlags */ #define BTS_READ_ONLY 0x0001 /* Underlying file is readonly */ #define BTS_PAGESIZE_FIXED 0x0002 /* Page size can no longer be changed */ | > | 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 | BtLock *pLock; /* List of locks held on this shared-btree struct */ Btree *pWriter; /* Btree with currently open write transaction */ #endif u8 *pTmpSpace; /* Temp space sufficient to hold a single cell */ #ifndef SQLITE_OMIT_CONCURRENT BtreePtrmap *pMap; #endif int nPreformatSize; /* Size of last cell written by TransferRow() */ }; /* ** Allowed values for BtShared.btsFlags */ #define BTS_READ_ONLY 0x0001 /* Underlying file is readonly */ #define BTS_PAGESIZE_FIXED 0x0002 /* Page size can no longer be changed */ |
︙ | ︙ | |||
497 498 499 500 501 502 503 | ** but cursors cannot be shared. Each cursor is associated with a ** particular database connection identified BtCursor.pBtree.db. ** ** Fields in this structure are accessed under the BtShared.mutex ** found at self->pBt->mutex. ** ** skipNext meaning: | > > > > > | | > | > | 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 | ** but cursors cannot be shared. Each cursor is associated with a ** particular database connection identified BtCursor.pBtree.db. ** ** Fields in this structure are accessed under the BtShared.mutex ** found at self->pBt->mutex. ** ** skipNext meaning: ** The meaning of skipNext depends on the value of eState: ** ** eState Meaning of skipNext ** VALID skipNext is meaningless and is ignored ** INVALID skipNext is meaningless and is ignored ** SKIPNEXT sqlite3BtreeNext() is a no-op if skipNext>0 and ** sqlite3BtreePrevious() is no-op if skipNext<0. ** REQUIRESEEK restoreCursorPosition() restores the cursor to ** eState=SKIPNEXT if skipNext!=0 ** FAULT skipNext holds the cursor fault error code. */ struct BtCursor { u8 eState; /* One of the CURSOR_XXX constants (see below) */ u8 curFlags; /* zero or more BTCF_* flags defined below */ u8 curPagerFlags; /* Flags to send to sqlite3PagerGet() */ u8 hints; /* As configured by CursorSetHints() */ int skipNext; /* Prev() is noop if negative. Next() is noop if positive. |
︙ | ︙ | |||
538 539 540 541 542 543 544 545 546 547 548 549 550 551 | */ #define BTCF_WriteFlag 0x01 /* True if a write cursor */ #define BTCF_ValidNKey 0x02 /* True if info.nKey is valid */ #define BTCF_ValidOvfl 0x04 /* True if aOverflow is valid */ #define BTCF_AtLast 0x08 /* Cursor is pointing ot the last entry */ #define BTCF_Incrblob 0x10 /* True if an incremental I/O handle */ #define BTCF_Multiple 0x20 /* Maybe another cursor on the same btree */ /* ** Potential values for BtCursor.eState. ** ** CURSOR_INVALID: ** Cursor does not point to a valid entry. This can happen (for example) ** because the table is empty or because BtreeCursorFirst() has not been | > | 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 | */ #define BTCF_WriteFlag 0x01 /* True if a write cursor */ #define BTCF_ValidNKey 0x02 /* True if info.nKey is valid */ #define BTCF_ValidOvfl 0x04 /* True if aOverflow is valid */ #define BTCF_AtLast 0x08 /* Cursor is pointing ot the last entry */ #define BTCF_Incrblob 0x10 /* True if an incremental I/O handle */ #define BTCF_Multiple 0x20 /* Maybe another cursor on the same btree */ #define BTCF_Pinned 0x40 /* Cursor is busy and cannot be moved */ /* ** Potential values for BtCursor.eState. ** ** CURSOR_INVALID: ** Cursor does not point to a valid entry. This can happen (for example) ** because the table is empty or because BtreeCursorFirst() has not been |
︙ | ︙ | |||
683 684 685 686 687 688 689 | struct IntegrityCk { BtShared *pBt; /* The tree being checked out */ Pager *pPager; /* The associated pager. Also accessible by pBt->pPager */ u8 *aPgRef; /* 1 bit per page in the db (see above) */ Pgno nPage; /* Number of pages in the database */ int mxErr; /* Stop accumulating errors when this reaches zero */ int nErr; /* Number of messages written to zErrMsg so far */ | | > | > | 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 | struct IntegrityCk { BtShared *pBt; /* The tree being checked out */ Pager *pPager; /* The associated pager. Also accessible by pBt->pPager */ u8 *aPgRef; /* 1 bit per page in the db (see above) */ Pgno nPage; /* Number of pages in the database */ int mxErr; /* Stop accumulating errors when this reaches zero */ int nErr; /* Number of messages written to zErrMsg so far */ int bOomFault; /* A memory allocation error has occurred */ const char *zPfx; /* Error message prefix */ Pgno v1; /* Value for first %u substitution in zPfx */ int v2; /* Value for second %d substitution in zPfx */ StrAccum errMsg; /* Accumulate the error message text here */ u32 *heap; /* Min-heap used for analyzing cell coverage */ sqlite3 *db; /* Database connection running the check */ }; /* ** Routines to read or write a two- and four-byte big-endian integer values. */ #define get2byte(x) ((x)[0]<<8 | (x)[1]) #define put2byte(p,v) ((p)[0] = (u8)((v)>>8), (p)[1] = (u8)(v)) |
︙ | ︙ |
Changes to src/build.c.
︙ | ︙ | |||
27 28 29 30 31 32 33 | #ifndef SQLITE_OMIT_SHARED_CACHE /* ** The TableLock structure is only used by the sqlite3TableLock() and ** codeTableLocks() functions. */ struct TableLock { int iDb; /* The database containing the table to be locked */ | | | | | < < | < | 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 | #ifndef SQLITE_OMIT_SHARED_CACHE /* ** The TableLock structure is only used by the sqlite3TableLock() and ** codeTableLocks() functions. */ struct TableLock { int iDb; /* The database containing the table to be locked */ Pgno iTab; /* The root page of the table to be locked */ u8 isWriteLock; /* True for write lock. False for a read lock */ const char *zLockName; /* Name of the table */ }; /* ** Record the fact that we want to lock a table at run-time. ** ** The table to be locked has root page iTab and is found in database iDb. ** A read or a write lock can be taken depending on isWritelock. ** ** This routine just records the fact that the lock is desired. The ** code to make the lock occur is generated by a later call to ** codeTableLocks() which occurs during sqlite3FinishCoding(). */ static SQLITE_NOINLINE void lockTable( Parse *pParse, /* Parsing context */ int iDb, /* Index of the database containing the table to lock */ Pgno iTab, /* Root page number of the table to be locked */ u8 isWriteLock, /* True for a write lock */ const char *zName /* Name of the table to be locked */ ){ Parse *pToplevel; int i; int nBytes; TableLock *p; assert( iDb>=0 ); pToplevel = sqlite3ParseToplevel(pParse); for(i=0; i<pToplevel->nTableLock; i++){ p = &pToplevel->aTableLock[i]; if( p->iDb==iDb && p->iTab==iTab ){ p->isWriteLock = (p->isWriteLock || isWriteLock); return; } } |
︙ | ︙ | |||
81 82 83 84 85 86 87 88 89 90 91 92 93 94 | p->isWriteLock = isWriteLock; p->zLockName = zName; }else{ pToplevel->nTableLock = 0; sqlite3OomFault(pToplevel->db); } } /* ** Code an OP_TableLock instruction for each table locked by the ** statement (configured by calls to sqlite3TableLock()). */ static void codeTableLocks(Parse *pParse){ int i; | > > > > > > > > > > > > > | < < | | 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 | p->isWriteLock = isWriteLock; p->zLockName = zName; }else{ pToplevel->nTableLock = 0; sqlite3OomFault(pToplevel->db); } } void sqlite3TableLock( Parse *pParse, /* Parsing context */ int iDb, /* Index of the database containing the table to lock */ Pgno iTab, /* Root page number of the table to be locked */ u8 isWriteLock, /* True for a write lock */ const char *zName /* Name of the table to be locked */ ){ #ifdef SQLITE_OMIT_CONCURRENT if( iDb==1 ) return; if( !sqlite3BtreeSharable(pParse->db->aDb[iDb].pBt) ) return; #endif lockTable(pParse, iDb, iTab, isWriteLock, zName); } /* ** Code an OP_TableLock instruction for each table locked by the ** statement (configured by calls to sqlite3TableLock()). */ static void codeTableLocks(Parse *pParse){ int i; Vdbe *pVdbe = pParse->pVdbe; assert( pVdbe!=0 ); for(i=0; i<pParse->nTableLock; i++){ TableLock *p = &pParse->aTableLock[i]; int p1 = p->iDb; sqlite3VdbeAddOp4(pVdbe, OP_TableLock, p1, p->iTab, p->isWriteLock, p->zLockName, P4_STATIC); } |
︙ | ︙ | |||
142 143 144 145 146 147 148 | if( pParse->rc==SQLITE_OK ) pParse->rc = SQLITE_ERROR; return; } /* Begin by generating some termination code at the end of the ** vdbe program */ | > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > | 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 | if( pParse->rc==SQLITE_OK ) pParse->rc = SQLITE_ERROR; return; } /* Begin by generating some termination code at the end of the ** vdbe program */ v = pParse->pVdbe; if( v==0 ){ if( db->init.busy ){ pParse->rc = SQLITE_DONE; return; } v = sqlite3GetVdbe(pParse); if( v==0 ) pParse->rc = SQLITE_ERROR; } assert( !pParse->isMultiWrite || sqlite3VdbeAssertMayAbort(v, pParse->mayAbort)); if( v ){ if( pParse->bReturning ){ Returning *pReturning = pParse->u1.pReturning; int addrRewind; int i; int reg; if( pReturning->nRetCol==0 ){ assert( CORRUPT_DB ); }else{ addrRewind = sqlite3VdbeAddOp1(v, OP_Rewind, pReturning->iRetCur); VdbeCoverage(v); reg = pReturning->iRetReg; for(i=0; i<pReturning->nRetCol; i++){ sqlite3VdbeAddOp3(v, OP_Column, pReturning->iRetCur, i, reg+i); } sqlite3VdbeAddOp2(v, OP_ResultRow, reg, i); sqlite3VdbeAddOp2(v, OP_Next, pReturning->iRetCur, addrRewind+1); VdbeCoverage(v); sqlite3VdbeJumpHere(v, addrRewind); } } sqlite3VdbeAddOp0(v, OP_Halt); #if SQLITE_USER_AUTHENTICATION if( pParse->nTableLock>0 && db->init.busy==0 ){ sqlite3UserAuthInit(db); if( db->auth.authLevel<UAUTH_User ){ sqlite3ErrorMsg(pParse, "user not authenticated"); |
︙ | ︙ | |||
205 206 207 208 209 210 211 | */ codeTableLocks(pParse); /* Initialize any AUTOINCREMENT data structures required. */ sqlite3AutoincrementBegin(pParse); | | > > > > > > > > | > > > > > > > > > > < | > | | | < | | > > > > > > > | > > | 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 | */ codeTableLocks(pParse); /* Initialize any AUTOINCREMENT data structures required. */ sqlite3AutoincrementBegin(pParse); /* Code constant expressions that where factored out of inner loops. ** ** The pConstExpr list might also contain expressions that we simply ** want to keep around until the Parse object is deleted. Such ** expressions have iConstExprReg==0. Do not generate code for ** those expressions, of course. */ if( pParse->pConstExpr ){ ExprList *pEL = pParse->pConstExpr; pParse->okConstFactor = 0; for(i=0; i<pEL->nExpr; i++){ int iReg = pEL->a[i].u.iConstExprReg; if( iReg>0 ){ sqlite3ExprCode(pParse, pEL->a[i].pExpr, iReg); } } } if( pParse->bReturning ){ Returning *pRet = pParse->u1.pReturning; if( pRet->nRetCol==0 ){ assert( CORRUPT_DB ); }else{ sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pRet->iRetCur, pRet->nRetCol); } } /* Finally, jump back to the beginning of the executable code. */ sqlite3VdbeGoto(v, 1); } } /* Get the VDBE program ready for execution */ if( v && pParse->nErr==0 && !db->mallocFailed ){ /* A minimum of one cursor is required if autoincrement is used * See ticket [a696379c1f08866] */ assert( pParse->pAinc==0 || pParse->nTab>0 ); sqlite3VdbeMakeReady(v, pParse); pParse->rc = SQLITE_DONE; }else{ pParse->rc = SQLITE_ERROR; } } /* ** Run the parser and code generator recursively in order to generate ** code for the SQL statement given onto the end of the pParse context ** currently under construction. Notes: ** ** * The final OP_Halt is not appended and other initialization ** and finalization steps are omitted because those are handling by the ** outermost parser. ** ** * Built-in SQL functions always take precedence over application-defined ** SQL functions. In other words, it is not possible to override a ** built-in function. */ void sqlite3NestedParse(Parse *pParse, const char *zFormat, ...){ va_list ap; char *zSql; char *zErrMsg = 0; sqlite3 *db = pParse->db; u32 savedDbFlags = db->mDbFlags; char saveBuf[PARSE_TAIL_SZ]; if( pParse->nErr ) return; assert( pParse->nested<10 ); /* Nesting should only be of limited depth */ va_start(ap, zFormat); zSql = sqlite3VMPrintf(db, zFormat, ap); va_end(ap); if( zSql==0 ){ /* This can result either from an OOM or because the formatted string ** exceeds SQLITE_LIMIT_LENGTH. In the latter case, we need to set ** an error */ if( !db->mallocFailed ) pParse->rc = SQLITE_TOOBIG; pParse->nErr++; return; } pParse->nested++; memcpy(saveBuf, PARSE_TAIL(pParse), PARSE_TAIL_SZ); memset(PARSE_TAIL(pParse), 0, PARSE_TAIL_SZ); db->mDbFlags |= DBFLAG_PreferBuiltin; sqlite3RunParser(pParse, zSql, &zErrMsg); db->mDbFlags = savedDbFlags; sqlite3DbFree(db, zErrMsg); sqlite3DbFree(db, zSql); memcpy(PARSE_TAIL(pParse), saveBuf, PARSE_TAIL_SZ); pParse->nested--; } #if SQLITE_USER_AUTHENTICATION |
︙ | ︙ | |||
305 306 307 308 309 310 311 | #if SQLITE_USER_AUTHENTICATION /* Only the admin user is allowed to know that the sqlite_user table ** exists */ if( db->auth.authLevel<UAUTH_Admin && sqlite3UserAuthTable(zName)!=0 ){ return 0; } #endif | | | < | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | > > > > > > | < < < < < | > | | 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 | #if SQLITE_USER_AUTHENTICATION /* Only the admin user is allowed to know that the sqlite_user table ** exists */ if( db->auth.authLevel<UAUTH_Admin && sqlite3UserAuthTable(zName)!=0 ){ return 0; } #endif if( zDatabase ){ for(i=0; i<db->nDb; i++){ if( sqlite3StrICmp(zDatabase, db->aDb[i].zDbSName)==0 ) break; } if( i>=db->nDb ){ /* No match against the official names. But always match "main" ** to schema 0 as a legacy fallback. */ if( sqlite3StrICmp(zDatabase,"main")==0 ){ i = 0; }else{ return 0; } } p = sqlite3HashFind(&db->aDb[i].pSchema->tblHash, zName); if( p==0 && sqlite3StrNICmp(zName, "sqlite_", 7)==0 ){ if( i==1 ){ if( sqlite3StrICmp(zName+7, &PREFERRED_TEMP_SCHEMA_TABLE[7])==0 || sqlite3StrICmp(zName+7, &PREFERRED_SCHEMA_TABLE[7])==0 || sqlite3StrICmp(zName+7, &LEGACY_SCHEMA_TABLE[7])==0 ){ p = sqlite3HashFind(&db->aDb[1].pSchema->tblHash, LEGACY_TEMP_SCHEMA_TABLE); } }else{ if( sqlite3StrICmp(zName+7, &PREFERRED_SCHEMA_TABLE[7])==0 ){ p = sqlite3HashFind(&db->aDb[i].pSchema->tblHash, LEGACY_SCHEMA_TABLE); } } } }else{ /* Match against TEMP first */ p = sqlite3HashFind(&db->aDb[1].pSchema->tblHash, zName); if( p ) return p; /* The main database is second */ p = sqlite3HashFind(&db->aDb[0].pSchema->tblHash, zName); if( p ) return p; /* Attached databases are in order of attachment */ for(i=2; i<db->nDb; i++){ assert( sqlite3SchemaMutexHeld(db, i, 0) ); p = sqlite3HashFind(&db->aDb[i].pSchema->tblHash, zName); if( p ) break; } if( p==0 && sqlite3StrNICmp(zName, "sqlite_", 7)==0 ){ if( sqlite3StrICmp(zName+7, &PREFERRED_SCHEMA_TABLE[7])==0 ){ p = sqlite3HashFind(&db->aDb[0].pSchema->tblHash, LEGACY_SCHEMA_TABLE); }else if( sqlite3StrICmp(zName+7, &PREFERRED_TEMP_SCHEMA_TABLE[7])==0 ){ p = sqlite3HashFind(&db->aDb[1].pSchema->tblHash, LEGACY_TEMP_SCHEMA_TABLE); } } } return p; } /* ** Locate the in-memory structure that describes a particular database ** table given the name of that table and (optionally) the name of the ** database containing the table. Return NULL if not found. Also leave an ** error message in pParse->zErrMsg. |
︙ | ︙ | |||
352 353 354 355 356 357 358 | && SQLITE_OK!=sqlite3ReadSchema(pParse) ){ return 0; } p = sqlite3FindTable(db, zName, zDbase); if( p==0 ){ | < > | | | | | > | | > | > > > > > > > | | | | | < | > | > > > > > > > > > > > > > > > > | 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 | && SQLITE_OK!=sqlite3ReadSchema(pParse) ){ return 0; } p = sqlite3FindTable(db, zName, zDbase); if( p==0 ){ #ifndef SQLITE_OMIT_VIRTUALTABLE /* If zName is the not the name of a table in the schema created using ** CREATE, then check to see if it is the name of an virtual table that ** can be an eponymous virtual table. */ if( pParse->disableVtab==0 && db->init.busy==0 ){ Module *pMod = (Module*)sqlite3HashFind(&db->aModule, zName); if( pMod==0 && sqlite3_strnicmp(zName, "pragma_", 7)==0 ){ pMod = sqlite3PragmaVtabRegister(db, zName); } if( pMod && sqlite3VtabEponymousTableInit(pParse, pMod) ){ testcase( pMod->pEpoTab==0 ); return pMod->pEpoTab; } } #endif if( flags & LOCATE_NOERR ) return 0; pParse->checkSchema = 1; }else if( IsVirtual(p) && pParse->disableVtab ){ p = 0; } if( p==0 ){ const char *zMsg = flags & LOCATE_VIEW ? "no such view" : "no such table"; if( zDbase ){ sqlite3ErrorMsg(pParse, "%s: %s.%s", zMsg, zDbase, zName); }else{ sqlite3ErrorMsg(pParse, "%s: %s", zMsg, zName); } }else{ assert( HasRowid(p) || p->iPKey<0 ); } return p; } /* ** Locate the table identified by *p. ** ** This is a wrapper around sqlite3LocateTable(). The difference between ** sqlite3LocateTable() and this function is that this function restricts ** the search to schema (p->pSchema) if it is not NULL. p->pSchema may be ** non-NULL if it is part of a view or trigger program definition. See ** sqlite3FixSrcList() for details. */ Table *sqlite3LocateTableItem( Parse *pParse, u32 flags, SrcItem *p ){ const char *zDb; assert( p->pSchema==0 || p->zDatabase==0 ); if( p->pSchema ){ int iDb = sqlite3SchemaToIndex(pParse->db, p->pSchema); zDb = pParse->db->aDb[iDb].zDbSName; }else{ zDb = p->zDatabase; } return sqlite3LocateTable(pParse, flags, p->zName, zDb); } /* ** Return the preferred table name for system tables. Translate legacy ** names into the new preferred names, as appropriate. */ const char *sqlite3PreferredTableName(const char *zName){ if( sqlite3StrNICmp(zName, "sqlite_", 7)==0 ){ if( sqlite3StrICmp(zName+7, &LEGACY_SCHEMA_TABLE[7])==0 ){ return PREFERRED_SCHEMA_TABLE; } if( sqlite3StrICmp(zName+7, &LEGACY_TEMP_SCHEMA_TABLE[7])==0 ){ return PREFERRED_TEMP_SCHEMA_TABLE; } } return zName; } /* ** Locate the in-memory structure that describes ** a particular index given the name of that index ** and the name of the database that contains the index. ** Return NULL if not found. ** |
︙ | ︙ | |||
424 425 426 427 428 429 430 | int i; /* All mutexes are required for schema access. Make sure we hold them. */ assert( zDb!=0 || sqlite3BtreeHoldsAllMutexes(db) ); for(i=OMIT_TEMPDB; i<db->nDb; i++){ int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */ Schema *pSchema = db->aDb[j].pSchema; assert( pSchema ); | | | | 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 | int i; /* All mutexes are required for schema access. Make sure we hold them. */ assert( zDb!=0 || sqlite3BtreeHoldsAllMutexes(db) ); for(i=OMIT_TEMPDB; i<db->nDb; i++){ int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */ Schema *pSchema = db->aDb[j].pSchema; assert( pSchema ); if( zDb && sqlite3DbIsNamed(db, j, zDb)==0 ) continue; assert( sqlite3SchemaMutexHeld(db, j, 0) ); p = sqlite3HashFind(&pSchema->idxHash, zName); if( p ) break; } return p; } /* ** Reclaim the memory used by an index */ void sqlite3FreeIndex(sqlite3 *db, Index *p){ #ifndef SQLITE_OMIT_ANALYZE sqlite3DeleteIndexSamples(db, p); #endif sqlite3ExprDelete(db, p->pPartIdxWhere); sqlite3ExprListDelete(db, p->aColExpr); sqlite3DbFree(db, p->zColAff); if( p->isResized ) sqlite3DbFree(db, (void *)p->azColl); #ifdef SQLITE_ENABLE_STAT4 sqlite3_free(p->aiRowEst); #endif sqlite3DbFree(db, p); } /* ** For the index called zIdxName which is found in the database iDb, |
︙ | ︙ | |||
566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 | /* ** This routine is called when a commit occurs. */ void sqlite3CommitInternalChanges(sqlite3 *db){ db->mDbFlags &= ~DBFLAG_SchemaChange; } /* ** Delete memory allocated for the column names of a table or view (the ** Table.aCol[] array). */ void sqlite3DeleteColumnNames(sqlite3 *db, Table *pTable){ int i; Column *pCol; assert( pTable!=0 ); if( (pCol = pTable->aCol)!=0 ){ for(i=0; i<pTable->nCol; i++, pCol++){ | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | < > | > > > | > > > > > | 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 | /* ** This routine is called when a commit occurs. */ void sqlite3CommitInternalChanges(sqlite3 *db){ db->mDbFlags &= ~DBFLAG_SchemaChange; } /* ** Set the expression associated with a column. This is usually ** the DEFAULT value, but might also be the expression that computes ** the value for a generated column. */ void sqlite3ColumnSetExpr( Parse *pParse, /* Parsing context */ Table *pTab, /* The table containing the column */ Column *pCol, /* The column to receive the new DEFAULT expression */ Expr *pExpr /* The new default expression */ ){ ExprList *pList; assert( IsOrdinaryTable(pTab) ); pList = pTab->u.tab.pDfltList; if( pCol->iDflt==0 || NEVER(pList==0) || NEVER(pList->nExpr<pCol->iDflt) ){ pCol->iDflt = pList==0 ? 1 : pList->nExpr+1; pTab->u.tab.pDfltList = sqlite3ExprListAppend(pParse, pList, pExpr); }else{ sqlite3ExprDelete(pParse->db, pList->a[pCol->iDflt-1].pExpr); pList->a[pCol->iDflt-1].pExpr = pExpr; } } /* ** Return the expression associated with a column. The expression might be ** the DEFAULT clause or the AS clause of a generated column. ** Return NULL if the column has no associated expression. */ Expr *sqlite3ColumnExpr(Table *pTab, Column *pCol){ if( pCol->iDflt==0 ) return 0; if( NEVER(!IsOrdinaryTable(pTab)) ) return 0; if( NEVER(pTab->u.tab.pDfltList==0) ) return 0; if( NEVER(pTab->u.tab.pDfltList->nExpr<pCol->iDflt) ) return 0; return pTab->u.tab.pDfltList->a[pCol->iDflt-1].pExpr; } /* ** Set the collating sequence name for a column. */ void sqlite3ColumnSetColl( sqlite3 *db, Column *pCol, const char *zColl ){ i64 nColl; i64 n; char *zNew; assert( zColl!=0 ); n = sqlite3Strlen30(pCol->zCnName) + 1; if( pCol->colFlags & COLFLAG_HASTYPE ){ n += sqlite3Strlen30(pCol->zCnName+n) + 1; } nColl = sqlite3Strlen30(zColl) + 1; zNew = sqlite3DbRealloc(db, pCol->zCnName, nColl+n); if( zNew ){ pCol->zCnName = zNew; memcpy(pCol->zCnName + n, zColl, nColl); pCol->colFlags |= COLFLAG_HASCOLL; } } /* ** Return the collating squence name for a column */ const char *sqlite3ColumnColl(Column *pCol){ const char *z; if( (pCol->colFlags & COLFLAG_HASCOLL)==0 ) return 0; z = pCol->zCnName; while( *z ){ z++; } if( pCol->colFlags & COLFLAG_HASTYPE ){ do{ z++; }while( *z ); } return z+1; } /* ** Delete memory allocated for the column names of a table or view (the ** Table.aCol[] array). */ void sqlite3DeleteColumnNames(sqlite3 *db, Table *pTable){ int i; Column *pCol; assert( pTable!=0 ); if( (pCol = pTable->aCol)!=0 ){ for(i=0; i<pTable->nCol; i++, pCol++){ assert( pCol->zCnName==0 || pCol->hName==sqlite3StrIHash(pCol->zCnName) ); sqlite3DbFree(db, pCol->zCnName); } sqlite3DbFree(db, pTable->aCol); if( IsOrdinaryTable(pTable) ){ sqlite3ExprListDelete(db, pTable->u.tab.pDfltList); } if( db==0 || db->pnBytesFreed==0 ){ pTable->aCol = 0; pTable->nCol = 0; if( IsOrdinaryTable(pTable) ){ pTable->u.tab.pDfltList = 0; } } } } /* ** Remove the memory data structures associated with the given ** Table. No changes are made to disk by this routine. ** |
︙ | ︙ | |||
605 606 607 608 609 610 611 | ** used by the Table object. */ static void SQLITE_NOINLINE deleteTable(sqlite3 *db, Table *pTable){ Index *pIndex, *pNext; #ifdef SQLITE_DEBUG /* Record the number of outstanding lookaside allocations in schema Tables | | | > > > > | | | > > > > > > > > > > < < < < | 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 | ** used by the Table object. */ static void SQLITE_NOINLINE deleteTable(sqlite3 *db, Table *pTable){ Index *pIndex, *pNext; #ifdef SQLITE_DEBUG /* Record the number of outstanding lookaside allocations in schema Tables ** prior to doing any free() operations. Since schema Tables do not use ** lookaside, this number should not change. ** ** If malloc has already failed, it may be that it failed while allocating ** a Table object that was going to be marked ephemeral. So do not check ** that no lookaside memory is used in this case either. */ int nLookaside = 0; if( db && !db->mallocFailed && (pTable->tabFlags & TF_Ephemeral)==0 ){ nLookaside = sqlite3LookasideUsed(db, 0); } #endif /* Delete all indices associated with this table. */ for(pIndex = pTable->pIndex; pIndex; pIndex=pNext){ pNext = pIndex->pNext; assert( pIndex->pSchema==pTable->pSchema || (IsVirtual(pTable) && pIndex->idxType!=SQLITE_IDXTYPE_APPDEF) ); if( (db==0 || db->pnBytesFreed==0) && !IsVirtual(pTable) ){ char *zName = pIndex->zName; TESTONLY ( Index *pOld = ) sqlite3HashInsert( &pIndex->pSchema->idxHash, zName, 0 ); assert( db==0 || sqlite3SchemaMutexHeld(db, 0, pIndex->pSchema) ); assert( pOld==pIndex || pOld==0 ); } sqlite3FreeIndex(db, pIndex); } if( IsOrdinaryTable(pTable) ){ sqlite3FkDelete(db, pTable); } #ifndef SQLITE_OMIT_VIRTUAL_TABLE else if( IsVirtual(pTable) ){ sqlite3VtabClear(db, pTable); } #endif else{ assert( IsView(pTable) ); sqlite3SelectDelete(db, pTable->u.view.pSelect); } /* Delete the Table structure itself. */ sqlite3DeleteColumnNames(db, pTable); sqlite3DbFree(db, pTable->zName); sqlite3DbFree(db, pTable->zColAff); sqlite3ExprListDelete(db, pTable->pCheck); sqlite3DbFree(db, pTable); /* Verify that no lookaside memory was used by schema tables */ assert( nLookaside==0 || nLookaside==sqlite3LookasideUsed(db,0) ); } void sqlite3DeleteTable(sqlite3 *db, Table *pTable){ /* Do not delete the table until the reference count reaches zero. */ |
︙ | ︙ | |||
687 688 689 690 691 692 693 | ** Any quotation marks (ex: "name", 'name', [name], or `name`) that ** surround the body of the token are removed. ** ** Tokens are often just pointers into the original SQL text and so ** are not \000 terminated and are not persistent. The returned string ** is \000 terminated and is persistent. */ | | | | | | | | 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 | ** Any quotation marks (ex: "name", 'name', [name], or `name`) that ** surround the body of the token are removed. ** ** Tokens are often just pointers into the original SQL text and so ** are not \000 terminated and are not persistent. The returned string ** is \000 terminated and is persistent. */ char *sqlite3NameFromToken(sqlite3 *db, const Token *pName){ char *zName; if( pName ){ zName = sqlite3DbStrNDup(db, (const char*)pName->z, pName->n); sqlite3Dequote(zName); }else{ zName = 0; } return zName; } /* ** Open the sqlite_schema table stored in database number iDb for ** writing. The table is opened using cursor 0. */ void sqlite3OpenSchemaTable(Parse *p, int iDb){ Vdbe *v = sqlite3GetVdbe(p); sqlite3TableLock(p, iDb, SCHEMA_ROOT, 1, LEGACY_SCHEMA_TABLE); sqlite3VdbeAddOp4Int(v, OP_OpenWrite, 0, SCHEMA_ROOT, iDb, 5); if( p->nTab==0 ){ p->nTab = 1; } } /* ** Parameter zName points to a nul-terminated buffer containing the name |
︙ | ︙ | |||
784 785 786 787 788 789 790 | *pUnqual = pName2; iDb = sqlite3FindDb(db, pName1); if( iDb<0 ){ sqlite3ErrorMsg(pParse, "unknown database %T", pName1); return -1; } }else{ | | | 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 | *pUnqual = pName2; iDb = sqlite3FindDb(db, pName1); if( iDb<0 ){ sqlite3ErrorMsg(pParse, "unknown database %T", pName1); return -1; } }else{ assert( db->init.iDb==0 || db->init.busy || IN_SPECIAL_PARSE || (db->mDbFlags & DBFLAG_Vacuum)!=0); iDb = db->init.iDb; *pUnqual = pName1; } return iDb; } |
︙ | ︙ | |||
812 813 814 815 816 817 818 819 | /* ** This routine is used to check if the UTF-8 string zName is a legal ** unqualified name for a new schema object (table, index, view or ** trigger). All names are legal except those that begin with the string ** "sqlite_" (in upper, lower or mixed case). This portion of the namespace ** is reserved for internal use. */ | > > > > | > > > > > | | > > > > > > > > > > > > > > > | > > | > | > > > | > | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* ** This routine is used to check if the UTF-8 string zName is a legal ** unqualified name for a new schema object (table, index, view or ** trigger). All names are legal except those that begin with the string ** "sqlite_" (in upper, lower or mixed case). This portion of the namespace ** is reserved for internal use. ** ** When parsing the sqlite_schema table, this routine also checks to ** make sure the "type", "name", and "tbl_name" columns are consistent ** with the SQL. */ int sqlite3CheckObjectName( Parse *pParse, /* Parsing context */ const char *zName, /* Name of the object to check */ const char *zType, /* Type of this object */ const char *zTblName /* Parent table name for triggers and indexes */ ){ sqlite3 *db = pParse->db; if( sqlite3WritableSchema(db) || db->init.imposterTable || !sqlite3Config.bExtraSchemaChecks ){ /* Skip these error checks for writable_schema=ON */ return SQLITE_OK; } if( db->init.busy ){ if( sqlite3_stricmp(zType, db->init.azInit[0]) || sqlite3_stricmp(zName, db->init.azInit[1]) || sqlite3_stricmp(zTblName, db->init.azInit[2]) ){ sqlite3ErrorMsg(pParse, ""); /* corruptSchema() will supply the error */ return SQLITE_ERROR; } }else{ if( (pParse->nested==0 && 0==sqlite3StrNICmp(zName, "sqlite_", 7)) || (sqlite3ReadOnlyShadowTables(db) && sqlite3ShadowTableName(db, zName)) ){ sqlite3ErrorMsg(pParse, "object name reserved for internal use: %s", zName); return SQLITE_ERROR; } } return SQLITE_OK; } /* ** Return the PRIMARY KEY index of a table */ Index *sqlite3PrimaryKeyIndex(Table *pTab){ Index *p; for(p=pTab->pIndex; p && !IsPrimaryKeyIndex(p); p=p->pNext){} return p; } /* ** Convert an table column number into a index column number. That is, ** for the column iCol in the table (as defined by the CREATE TABLE statement) ** find the (first) offset of that column in index pIdx. Or return -1 ** if column iCol is not used in index pIdx. */ i16 sqlite3TableColumnToIndex(Index *pIdx, i16 iCol){ int i; for(i=0; i<pIdx->nColumn; i++){ if( iCol==pIdx->aiColumn[i] ) return i; } return -1; } #ifndef SQLITE_OMIT_GENERATED_COLUMNS /* Convert a storage column number into a table column number. ** ** The storage column number (0,1,2,....) is the index of the value ** as it appears in the record on disk. The true column number ** is the index (0,1,2,...) of the column in the CREATE TABLE statement. ** ** The storage column number is less than the table column number if ** and only there are VIRTUAL columns to the left. ** ** If SQLITE_OMIT_GENERATED_COLUMNS, this routine is a no-op macro. */ i16 sqlite3StorageColumnToTable(Table *pTab, i16 iCol){ if( pTab->tabFlags & TF_HasVirtual ){ int i; for(i=0; i<=iCol; i++){ if( pTab->aCol[i].colFlags & COLFLAG_VIRTUAL ) iCol++; } } return iCol; } #endif #ifndef SQLITE_OMIT_GENERATED_COLUMNS /* Convert a table column number into a storage column number. ** ** The storage column number (0,1,2,....) is the index of the value ** as it appears in the record on disk. Or, if the input column is ** the N-th virtual column (zero-based) then the storage number is ** the number of non-virtual columns in the table plus N. ** ** The true column number is the index (0,1,2,...) of the column in ** the CREATE TABLE statement. ** ** If the input column is a VIRTUAL column, then it should not appear ** in storage. But the value sometimes is cached in registers that ** follow the range of registers used to construct storage. This ** avoids computing the same VIRTUAL column multiple times, and provides ** values for use by OP_Param opcodes in triggers. Hence, if the ** input column is a VIRTUAL table, put it after all the other columns. ** ** In the following, N means "normal column", S means STORED, and ** V means VIRTUAL. Suppose the CREATE TABLE has columns like this: ** ** CREATE TABLE ex(N,S,V,N,S,V,N,S,V); ** -- 0 1 2 3 4 5 6 7 8 ** ** Then the mapping from this function is as follows: ** ** INPUTS: 0 1 2 3 4 5 6 7 8 ** OUTPUTS: 0 1 6 2 3 7 4 5 8 ** ** So, in other words, this routine shifts all the virtual columns to ** the end. ** ** If SQLITE_OMIT_GENERATED_COLUMNS then there are no virtual columns and ** this routine is a no-op macro. If the pTab does not have any virtual ** columns, then this routine is no-op that always return iCol. If iCol ** is negative (indicating the ROWID column) then this routine return iCol. */ i16 sqlite3TableColumnToStorage(Table *pTab, i16 iCol){ int i; i16 n; assert( iCol<pTab->nCol ); if( (pTab->tabFlags & TF_HasVirtual)==0 || iCol<0 ) return iCol; for(i=0, n=0; i<iCol; i++){ if( (pTab->aCol[i].colFlags & COLFLAG_VIRTUAL)==0 ) n++; } if( pTab->aCol[i].colFlags & COLFLAG_VIRTUAL ){ /* iCol is a virtual column itself */ return pTab->nNVCol + i - n; }else{ /* iCol is a normal or stored column */ return n; } } #endif /* ** Insert a single OP_JournalMode query opcode in order to force the ** prepared statement to return false for sqlite3_stmt_readonly(). This ** is used by CREATE TABLE IF NOT EXISTS and similar if the table already ** exists, so that the prepared statement for CREATE TABLE IF NOT EXISTS ** will return false for sqlite3_stmt_readonly() even if that statement ** is a read-only no-op. */ static void sqlite3ForceNotReadOnly(Parse *pParse){ int iReg = ++pParse->nMem; Vdbe *v = sqlite3GetVdbe(pParse); if( v ){ sqlite3VdbeAddOp3(v, OP_JournalMode, 0, iReg, PAGER_JOURNALMODE_QUERY); sqlite3VdbeUsesBtree(v, 0); } } /* ** Begin constructing a new table representation in memory. This is ** the first of several action routines that get called in response ** to a CREATE TABLE statement. In particular, this routine is called ** after seeing tokens "CREATE" and "TABLE" and the table name. The isTemp ** flag is true if the table should be stored in the auxiliary database |
︙ | ︙ | |||
877 878 879 880 881 882 883 | char *zName = 0; /* The name of the new table */ sqlite3 *db = pParse->db; Vdbe *v; int iDb; /* Database number to create the table in */ Token *pName; /* Unqualified name of the table to create */ if( db->init.busy && db->init.newTnum==1 ){ | | | 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 | char *zName = 0; /* The name of the new table */ sqlite3 *db = pParse->db; Vdbe *v; int iDb; /* Database number to create the table in */ Token *pName; /* Unqualified name of the table to create */ if( db->init.busy && db->init.newTnum==1 ){ /* Special case: Parsing the sqlite_schema or sqlite_temp_schema schema */ iDb = db->init.iDb; zName = sqlite3DbStrDup(db, SCHEMA_TABLE(iDb)); pName = pName1; }else{ /* The common case */ iDb = sqlite3TwoPartName(pParse, pName1, pName2, &pName); if( iDb<0 ) return; |
︙ | ︙ | |||
899 900 901 902 903 904 905 | zName = sqlite3NameFromToken(db, pName); if( IN_RENAME_OBJECT ){ sqlite3RenameTokenMap(pParse, (void*)zName, pName); } } pParse->sNameToken = *pName; if( zName==0 ) return; | | | 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 | zName = sqlite3NameFromToken(db, pName); if( IN_RENAME_OBJECT ){ sqlite3RenameTokenMap(pParse, (void*)zName, pName); } } pParse->sNameToken = *pName; if( zName==0 ) return; if( sqlite3CheckObjectName(pParse, zName, isView?"view":"table", zName) ){ goto begin_table_error; } if( db->init.iDb==1 ) isTemp = 1; #ifndef SQLITE_OMIT_AUTHORIZATION assert( isTemp==0 || isTemp==1 ); assert( isView==0 || isView==1 ); { |
︙ | ︙ | |||
943 944 945 946 947 948 949 950 951 952 953 954 955 956 | pTable = sqlite3FindTable(db, zName, zDb); if( pTable ){ if( !noErr ){ sqlite3ErrorMsg(pParse, "table %T already exists", pName); }else{ assert( !db->init.busy || CORRUPT_DB ); sqlite3CodeVerifySchema(pParse, iDb); } goto begin_table_error; } if( sqlite3FindIndex(db, zName, zDb)!=0 ){ sqlite3ErrorMsg(pParse, "there is already an index named %s", zName); goto begin_table_error; } | > | 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 | pTable = sqlite3FindTable(db, zName, zDb); if( pTable ){ if( !noErr ){ sqlite3ErrorMsg(pParse, "table %T already exists", pName); }else{ assert( !db->init.busy || CORRUPT_DB ); sqlite3CodeVerifySchema(pParse, iDb); sqlite3ForceNotReadOnly(pParse); } goto begin_table_error; } if( sqlite3FindIndex(db, zName, zDb)!=0 ){ sqlite3ErrorMsg(pParse, "there is already an index named %s", zName); goto begin_table_error; } |
︙ | ︙ | |||
971 972 973 974 975 976 977 | pTable->nRowLogEst = sqlite3LogEst(SQLITE_DEFAULT_ROWEST); #else pTable->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) ); #endif assert( pParse->pNewTable==0 ); pParse->pNewTable = pTable; | < < < < < < < < < < < | | 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 | pTable->nRowLogEst = sqlite3LogEst(SQLITE_DEFAULT_ROWEST); #else pTable->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) ); #endif assert( pParse->pNewTable==0 ); pParse->pNewTable = pTable; /* Begin generating the code that will insert the table record into ** the schema table. Note in particular that we must go ahead ** and allocate the record number for the table entry now. Before any ** PRIMARY KEY or UNIQUE keywords are parsed. Those keywords will cause ** indices to be created and the table record must come before the ** indices. Hence, the record number for the table must be allocated ** now. */ if( !db->init.busy && (v = sqlite3GetVdbe(pParse))!=0 ){ |
︙ | ︙ | |||
1019 1020 1021 1022 1023 1024 1025 | addr1 = sqlite3VdbeAddOp1(v, OP_If, reg3); VdbeCoverage(v); fileFormat = (db->flags & SQLITE_LegacyFileFmt)!=0 ? 1 : SQLITE_MAX_FILE_FORMAT; sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_FILE_FORMAT, fileFormat); sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_TEXT_ENCODING, ENC(db)); sqlite3VdbeJumpHere(v, addr1); | | > | | > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | > | < < | | | | | | < | > | | > | > | | > | | > | 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 | addr1 = sqlite3VdbeAddOp1(v, OP_If, reg3); VdbeCoverage(v); fileFormat = (db->flags & SQLITE_LegacyFileFmt)!=0 ? 1 : SQLITE_MAX_FILE_FORMAT; sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_FILE_FORMAT, fileFormat); sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_TEXT_ENCODING, ENC(db)); sqlite3VdbeJumpHere(v, addr1); /* This just creates a place-holder record in the sqlite_schema table. ** The record created does not contain anything yet. It will be replaced ** by the real entry in code generated at sqlite3EndTable(). ** ** The rowid for the new entry is left in register pParse->regRowid. ** The root page number of the new table is left in reg pParse->regRoot. ** The rowid and root page number values are needed by the code that ** sqlite3EndTable will generate. */ #if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE) if( isView || isVirtual ){ sqlite3VdbeAddOp2(v, OP_Integer, 0, reg2); }else #endif { assert( !pParse->bReturning ); pParse->u1.addrCrTab = sqlite3VdbeAddOp3(v, OP_CreateBtree, iDb, reg2, BTREE_INTKEY); } sqlite3OpenSchemaTable(pParse, iDb); sqlite3VdbeAddOp2(v, OP_NewRowid, 0, reg1); sqlite3VdbeAddOp4(v, OP_Blob, 6, reg3, 0, nullRow, P4_STATIC); sqlite3VdbeAddOp3(v, OP_Insert, 0, reg3, reg1); sqlite3VdbeChangeP5(v, OPFLAG_APPEND); sqlite3VdbeAddOp0(v, OP_Close); } /* Normal (non-error) return. */ return; /* If an error occurs, we jump here */ begin_table_error: pParse->checkSchema = 1; sqlite3DbFree(db, zName); return; } /* Set properties of a table column based on the (magical) ** name of the column. */ #if SQLITE_ENABLE_HIDDEN_COLUMNS void sqlite3ColumnPropertiesFromName(Table *pTab, Column *pCol){ if( sqlite3_strnicmp(pCol->zCnName, "__hidden__", 10)==0 ){ pCol->colFlags |= COLFLAG_HIDDEN; if( pTab ) pTab->tabFlags |= TF_HasHidden; }else if( pTab && pCol!=pTab->aCol && (pCol[-1].colFlags & COLFLAG_HIDDEN) ){ pTab->tabFlags |= TF_OOOHidden; } } #endif /* ** Name of the special TEMP trigger used to implement RETURNING. The ** name begins with "sqlite_" so that it is guaranteed not to collide ** with any application-generated triggers. */ #define RETURNING_TRIGGER_NAME "sqlite_returning" /* ** Clean up the data structures associated with the RETURNING clause. */ static void sqlite3DeleteReturning(sqlite3 *db, Returning *pRet){ Hash *pHash; pHash = &(db->aDb[1].pSchema->trigHash); sqlite3HashInsert(pHash, RETURNING_TRIGGER_NAME, 0); sqlite3ExprListDelete(db, pRet->pReturnEL); sqlite3DbFree(db, pRet); } /* ** Add the RETURNING clause to the parse currently underway. ** ** This routine creates a special TEMP trigger that will fire for each row ** of the DML statement. That TEMP trigger contains a single SELECT ** statement with a result set that is the argument of the RETURNING clause. ** The trigger has the Trigger.bReturning flag and an opcode of ** TK_RETURNING instead of TK_SELECT, so that the trigger code generator ** knows to handle it specially. The TEMP trigger is automatically ** removed at the end of the parse. ** ** When this routine is called, we do not yet know if the RETURNING clause ** is attached to a DELETE, INSERT, or UPDATE, so construct it as a ** RETURNING trigger instead. It will then be converted into the appropriate ** type on the first call to sqlite3TriggersExist(). */ void sqlite3AddReturning(Parse *pParse, ExprList *pList){ Returning *pRet; Hash *pHash; sqlite3 *db = pParse->db; if( pParse->pNewTrigger ){ sqlite3ErrorMsg(pParse, "cannot use RETURNING in a trigger"); }else{ assert( pParse->bReturning==0 ); } pParse->bReturning = 1; pRet = sqlite3DbMallocZero(db, sizeof(*pRet)); if( pRet==0 ){ sqlite3ExprListDelete(db, pList); return; } pParse->u1.pReturning = pRet; pRet->pParse = pParse; pRet->pReturnEL = pList; sqlite3ParserAddCleanup(pParse, (void(*)(sqlite3*,void*))sqlite3DeleteReturning, pRet); testcase( pParse->earlyCleanup ); if( db->mallocFailed ) return; pRet->retTrig.zName = RETURNING_TRIGGER_NAME; pRet->retTrig.op = TK_RETURNING; pRet->retTrig.tr_tm = TRIGGER_AFTER; pRet->retTrig.bReturning = 1; pRet->retTrig.pSchema = db->aDb[1].pSchema; pRet->retTrig.pTabSchema = db->aDb[1].pSchema; pRet->retTrig.step_list = &pRet->retTStep; pRet->retTStep.op = TK_RETURNING; pRet->retTStep.pTrig = &pRet->retTrig; pRet->retTStep.pExprList = pList; pHash = &(db->aDb[1].pSchema->trigHash); assert( sqlite3HashFind(pHash, RETURNING_TRIGGER_NAME)==0 || pParse->nErr ); if( sqlite3HashInsert(pHash, RETURNING_TRIGGER_NAME, &pRet->retTrig) ==&pRet->retTrig ){ sqlite3OomFault(db); } } /* ** Add a new column to the table currently being constructed. ** ** The parser calls this routine once for each column declaration ** in a CREATE TABLE statement. sqlite3StartTable() gets called ** first to get things going. Then this routine is called for each ** column. */ void sqlite3AddColumn(Parse *pParse, Token sName, Token sType){ Table *p; int i; char *z; char *zType; Column *pCol; sqlite3 *db = pParse->db; u8 hName; Column *aNew; u8 eType = COLTYPE_CUSTOM; u8 szEst = 1; char affinity = SQLITE_AFF_BLOB; if( (p = pParse->pNewTable)==0 ) return; if( p->nCol+1>db->aLimit[SQLITE_LIMIT_COLUMN] ){ sqlite3ErrorMsg(pParse, "too many columns on %s", p->zName); return; } if( !IN_RENAME_OBJECT ) sqlite3DequoteToken(&sName); /* Because keywords GENERATE ALWAYS can be converted into indentifiers ** by the parser, we can sometimes end up with a typename that ends ** with "generated always". Check for this case and omit the surplus ** text. */ if( sType.n>=16 && sqlite3_strnicmp(sType.z+(sType.n-6),"always",6)==0 ){ sType.n -= 6; while( ALWAYS(sType.n>0) && sqlite3Isspace(sType.z[sType.n-1]) ) sType.n--; if( sType.n>=9 && sqlite3_strnicmp(sType.z+(sType.n-9),"generated",9)==0 ){ sType.n -= 9; while( sType.n>0 && sqlite3Isspace(sType.z[sType.n-1]) ) sType.n--; } } /* Check for standard typenames. For standard typenames we will ** set the Column.eType field rather than storing the typename after ** the column name, in order to save space. */ if( sType.n>=3 ){ sqlite3DequoteToken(&sType); for(i=0; i<SQLITE_N_STDTYPE; i++){ if( sType.n==sqlite3StdTypeLen[i] && sqlite3_strnicmp(sType.z, sqlite3StdType[i], sType.n)==0 ){ sType.n = 0; eType = i+1; affinity = sqlite3StdTypeAffinity[i]; if( affinity<=SQLITE_AFF_TEXT ) szEst = 5; break; } } } z = sqlite3DbMallocRaw(db, (i64)sName.n + 1 + (i64)sType.n + (sType.n>0) ); if( z==0 ) return; if( IN_RENAME_OBJECT ) sqlite3RenameTokenMap(pParse, (void*)z, &sName); memcpy(z, sName.z, sName.n); z[sName.n] = 0; sqlite3Dequote(z); hName = sqlite3StrIHash(z); for(i=0; i<p->nCol; i++){ if( p->aCol[i].hName==hName && sqlite3StrICmp(z, p->aCol[i].zCnName)==0 ){ sqlite3ErrorMsg(pParse, "duplicate column name: %s", z); sqlite3DbFree(db, z); return; } } aNew = sqlite3DbRealloc(db,p->aCol,((i64)p->nCol+1)*sizeof(p->aCol[0])); if( aNew==0 ){ sqlite3DbFree(db, z); return; } p->aCol = aNew; pCol = &p->aCol[p->nCol]; memset(pCol, 0, sizeof(p->aCol[0])); pCol->zCnName = z; pCol->hName = hName; sqlite3ColumnPropertiesFromName(p, pCol); if( sType.n==0 ){ /* If there is no type specified, columns have the default affinity ** 'BLOB' with a default size of 4 bytes. */ pCol->affinity = affinity; pCol->eCType = eType; pCol->szEst = szEst; #ifdef SQLITE_ENABLE_SORTER_REFERENCES if( affinity==SQLITE_AFF_BLOB ){ if( 4>=sqlite3GlobalConfig.szSorterRef ){ pCol->colFlags |= COLFLAG_SORTERREF; } } #endif }else{ zType = z + sqlite3Strlen30(z) + 1; memcpy(zType, sType.z, sType.n); zType[sType.n] = 0; sqlite3Dequote(zType); pCol->affinity = sqlite3AffinityType(zType, pCol); pCol->colFlags |= COLFLAG_HASTYPE; } p->nCol++; p->nNVCol++; pParse->constraintName.n = 0; } /* ** This routine is called by the parser while in the middle of ** parsing a CREATE TABLE statement. A "NOT NULL" constraint has ** been seen on a column. This routine sets the notNull flag on |
︙ | ︙ | |||
1278 1279 1280 1281 1282 1283 1284 1285 | const char *zEnd /* First character past end of defaut value text */ ){ Table *p; Column *pCol; sqlite3 *db = pParse->db; p = pParse->pNewTable; if( p!=0 ){ pCol = &(p->aCol[p->nCol-1]); | > | | > > > > > > | < | > | 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 | const char *zEnd /* First character past end of defaut value text */ ){ Table *p; Column *pCol; sqlite3 *db = pParse->db; p = pParse->pNewTable; if( p!=0 ){ int isInit = db->init.busy && db->init.iDb!=1; pCol = &(p->aCol[p->nCol-1]); if( !sqlite3ExprIsConstantOrFunction(pExpr, isInit) ){ sqlite3ErrorMsg(pParse, "default value of column [%s] is not constant", pCol->zCnName); #ifndef SQLITE_OMIT_GENERATED_COLUMNS }else if( pCol->colFlags & COLFLAG_GENERATED ){ testcase( pCol->colFlags & COLFLAG_VIRTUAL ); testcase( pCol->colFlags & COLFLAG_STORED ); sqlite3ErrorMsg(pParse, "cannot use DEFAULT on a generated column"); #endif }else{ /* A copy of pExpr is used instead of the original, as pExpr contains ** tokens that point to volatile memory. */ Expr x, *pDfltExpr; memset(&x, 0, sizeof(x)); x.op = TK_SPAN; x.u.zToken = sqlite3DbSpanDup(db, zStart, zEnd); x.pLeft = pExpr; x.flags = EP_Skip; pDfltExpr = sqlite3ExprDup(db, &x, EXPRDUP_REDUCE); sqlite3DbFree(db, x.u.zToken); sqlite3ColumnSetExpr(pParse, p, pCol, pDfltExpr); } } if( IN_RENAME_OBJECT ){ sqlite3RenameExprUnmap(pParse, pExpr); } sqlite3ExprDelete(db, pExpr); } |
︙ | ︙ | |||
1316 1317 1318 1319 1320 1321 1322 | ** CREATE TABLE xyz(a,b,c,d,e,PRIMARY KEY('a'),UNIQUE('b','c' COLLATE trim) ** CREATE INDEX abc ON xyz('c','d' DESC,'e' COLLATE nocase DESC); ** ** This is goofy. But to preserve backwards compatibility we continue to ** accept it. This routine does the necessary conversion. It converts ** the expression given in its argument from a TK_STRING into a TK_ID ** if the expression is just a TK_STRING with an optional COLLATE clause. | | > > > > > > > > > > > > > > > | 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 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 | ** CREATE TABLE xyz(a,b,c,d,e,PRIMARY KEY('a'),UNIQUE('b','c' COLLATE trim) ** CREATE INDEX abc ON xyz('c','d' DESC,'e' COLLATE nocase DESC); ** ** This is goofy. But to preserve backwards compatibility we continue to ** accept it. This routine does the necessary conversion. It converts ** the expression given in its argument from a TK_STRING into a TK_ID ** if the expression is just a TK_STRING with an optional COLLATE clause. ** If the expression is anything other than TK_STRING, the expression is ** unchanged. */ static void sqlite3StringToId(Expr *p){ if( p->op==TK_STRING ){ p->op = TK_ID; }else if( p->op==TK_COLLATE && p->pLeft->op==TK_STRING ){ p->pLeft->op = TK_ID; } } /* ** Tag the given column as being part of the PRIMARY KEY */ static void makeColumnPartOfPrimaryKey(Parse *pParse, Column *pCol){ pCol->colFlags |= COLFLAG_PRIMKEY; #ifndef SQLITE_OMIT_GENERATED_COLUMNS if( pCol->colFlags & COLFLAG_GENERATED ){ testcase( pCol->colFlags & COLFLAG_VIRTUAL ); testcase( pCol->colFlags & COLFLAG_STORED ); sqlite3ErrorMsg(pParse, "generated columns cannot be part of the PRIMARY KEY"); } #endif } /* ** Designate the PRIMARY KEY for the table. pList is a list of names ** of columns that form the primary key. If pList is NULL, then the ** most recently added column of the table is the primary key. ** ** A table can have at most one primary key. If the table already has |
︙ | ︙ | |||
1366 1367 1368 1369 1370 1371 1372 | "table \"%s\" has more than one primary key", pTab->zName); goto primary_key_exit; } pTab->tabFlags |= TF_HasPrimaryKey; if( pList==0 ){ iCol = pTab->nCol - 1; pCol = &pTab->aCol[iCol]; | | | > > | | | > | | > | | > > > > > > > > > | < | | < > | | | | < < < | < < < < < < < < < < < < < < < | > > | < < | > > > > > > > > > > > > > > > > > | < < < > > > > > > > | | > > | > > > > > > > > > > > | | 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 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 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 | "table \"%s\" has more than one primary key", pTab->zName); goto primary_key_exit; } pTab->tabFlags |= TF_HasPrimaryKey; if( pList==0 ){ iCol = pTab->nCol - 1; pCol = &pTab->aCol[iCol]; makeColumnPartOfPrimaryKey(pParse, pCol); nTerm = 1; }else{ nTerm = pList->nExpr; for(i=0; i<nTerm; i++){ Expr *pCExpr = sqlite3ExprSkipCollate(pList->a[i].pExpr); assert( pCExpr!=0 ); sqlite3StringToId(pCExpr); if( pCExpr->op==TK_ID ){ const char *zCName; assert( !ExprHasProperty(pCExpr, EP_IntValue) ); zCName = pCExpr->u.zToken; for(iCol=0; iCol<pTab->nCol; iCol++){ if( sqlite3StrICmp(zCName, pTab->aCol[iCol].zCnName)==0 ){ pCol = &pTab->aCol[iCol]; makeColumnPartOfPrimaryKey(pParse, pCol); break; } } } } } if( nTerm==1 && pCol && pCol->eCType==COLTYPE_INTEGER && sortOrder!=SQLITE_SO_DESC ){ if( IN_RENAME_OBJECT && pList ){ Expr *pCExpr = sqlite3ExprSkipCollate(pList->a[0].pExpr); sqlite3RenameTokenRemap(pParse, &pTab->iPKey, pCExpr); } pTab->iPKey = iCol; pTab->keyConf = (u8)onError; assert( autoInc==0 || autoInc==1 ); pTab->tabFlags |= autoInc*TF_Autoincrement; if( pList ) pParse->iPkSortOrder = pList->a[0].sortFlags; (void)sqlite3HasExplicitNulls(pParse, pList); }else if( autoInc ){ #ifndef SQLITE_OMIT_AUTOINCREMENT sqlite3ErrorMsg(pParse, "AUTOINCREMENT is only allowed on an " "INTEGER PRIMARY KEY"); #endif }else{ sqlite3CreateIndex(pParse, 0, 0, 0, pList, onError, 0, 0, sortOrder, 0, SQLITE_IDXTYPE_PRIMARYKEY); pList = 0; } primary_key_exit: sqlite3ExprListDelete(pParse->db, pList); return; } /* ** Add a new CHECK constraint to the table currently under construction. */ void sqlite3AddCheckConstraint( Parse *pParse, /* Parsing context */ Expr *pCheckExpr, /* The check expression */ const char *zStart, /* Opening "(" */ const char *zEnd /* Closing ")" */ ){ #ifndef SQLITE_OMIT_CHECK Table *pTab = pParse->pNewTable; sqlite3 *db = pParse->db; if( pTab && !IN_DECLARE_VTAB && !sqlite3BtreeIsReadonly(db->aDb[db->init.iDb].pBt) ){ pTab->pCheck = sqlite3ExprListAppend(pParse, pTab->pCheck, pCheckExpr); if( pParse->constraintName.n ){ sqlite3ExprListSetName(pParse, pTab->pCheck, &pParse->constraintName, 1); }else{ Token t; for(zStart++; sqlite3Isspace(zStart[0]); zStart++){} while( sqlite3Isspace(zEnd[-1]) ){ zEnd--; } t.z = zStart; t.n = (int)(zEnd - t.z); sqlite3ExprListSetName(pParse, pTab->pCheck, &t, 1); } }else #endif { sqlite3ExprDelete(pParse->db, pCheckExpr); } } /* ** Set the collation function of the most recently parsed table column ** to the CollSeq given. */ void sqlite3AddCollateType(Parse *pParse, Token *pToken){ Table *p; int i; char *zColl; /* Dequoted name of collation sequence */ sqlite3 *db; if( (p = pParse->pNewTable)==0 || IN_RENAME_OBJECT ) return; i = p->nCol-1; db = pParse->db; zColl = sqlite3NameFromToken(db, pToken); if( !zColl ) return; if( sqlite3LocateCollSeq(pParse, zColl) ){ Index *pIdx; sqlite3ColumnSetColl(db, &p->aCol[i], zColl); /* If the column is declared as "<name> PRIMARY KEY COLLATE <type>", ** then an index may have been created on this column before the ** collation type was added. Correct this if it is the case. */ for(pIdx=p->pIndex; pIdx; pIdx=pIdx->pNext){ assert( pIdx->nKeyCol==1 ); if( pIdx->aiColumn[0]==i ){ pIdx->azColl[0] = sqlite3ColumnColl(&p->aCol[i]); } } } sqlite3DbFree(db, zColl); } /* Change the most recently parsed column to be a GENERATED ALWAYS AS ** column. */ void sqlite3AddGenerated(Parse *pParse, Expr *pExpr, Token *pType){ #ifndef SQLITE_OMIT_GENERATED_COLUMNS u8 eType = COLFLAG_VIRTUAL; Table *pTab = pParse->pNewTable; Column *pCol; if( pTab==0 ){ /* generated column in an CREATE TABLE IF NOT EXISTS that already exists */ goto generated_done; } pCol = &(pTab->aCol[pTab->nCol-1]); if( IN_DECLARE_VTAB ){ sqlite3ErrorMsg(pParse, "virtual tables cannot use computed columns"); goto generated_done; } if( pCol->iDflt>0 ) goto generated_error; if( pType ){ if( pType->n==7 && sqlite3StrNICmp("virtual",pType->z,7)==0 ){ /* no-op */ }else if( pType->n==6 && sqlite3StrNICmp("stored",pType->z,6)==0 ){ eType = COLFLAG_STORED; }else{ goto generated_error; } } if( eType==COLFLAG_VIRTUAL ) pTab->nNVCol--; pCol->colFlags |= eType; assert( TF_HasVirtual==COLFLAG_VIRTUAL ); assert( TF_HasStored==COLFLAG_STORED ); pTab->tabFlags |= eType; if( pCol->colFlags & COLFLAG_PRIMKEY ){ makeColumnPartOfPrimaryKey(pParse, pCol); /* For the error message */ } sqlite3ColumnSetExpr(pParse, pTab, pCol, pExpr); pExpr = 0; goto generated_done; generated_error: sqlite3ErrorMsg(pParse, "error in generated column \"%s\"", pCol->zCnName); generated_done: sqlite3ExprDelete(pParse->db, pExpr); #else /* Throw and error for the GENERATED ALWAYS AS clause if the ** SQLITE_OMIT_GENERATED_COLUMNS compile-time option is used. */ sqlite3ErrorMsg(pParse, "generated columns not supported"); sqlite3ExprDelete(pParse->db, pExpr); #endif } /* ** Generate code that will increment the schema cookie. ** ** The schema cookie is used to determine when the schema for the ** database changes. After each schema change, the cookie value ** changes. When a process first reads the schema it records the |
︙ | ︙ | |||
1601 1602 1603 1604 1605 1606 1607 | static char *createTableStmt(sqlite3 *db, Table *p){ int i, k, n; char *zStmt; char *zSep, *zSep2, *zEnd; Column *pCol; n = 0; for(pCol = p->aCol, i=0; i<p->nCol; i++, pCol++){ | | | 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 | static char *createTableStmt(sqlite3 *db, Table *p){ int i, k, n; char *zStmt; char *zSep, *zSep2, *zEnd; Column *pCol; n = 0; for(pCol = p->aCol, i=0; i<p->nCol; i++, pCol++){ n += identLength(pCol->zCnName) + 5; } n += identLength(p->zName); if( n<50 ){ zSep = ""; zSep2 = ","; zEnd = ")"; }else{ |
︙ | ︙ | |||
1637 1638 1639 1640 1641 1642 1643 | }; int len; const char *zType; sqlite3_snprintf(n-k, &zStmt[k], zSep); k += sqlite3Strlen30(&zStmt[k]); zSep = zSep2; | | | 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 | }; int len; const char *zType; sqlite3_snprintf(n-k, &zStmt[k], zSep); k += sqlite3Strlen30(&zStmt[k]); zSep = zSep2; identPut(zStmt, &k, pCol->zCnName); assert( pCol->affinity-SQLITE_AFF_BLOB >= 0 ); assert( pCol->affinity-SQLITE_AFF_BLOB < ArraySize(azType) ); testcase( pCol->affinity==SQLITE_AFF_BLOB ); testcase( pCol->affinity==SQLITE_AFF_TEXT ); testcase( pCol->affinity==SQLITE_AFF_NUMERIC ); testcase( pCol->affinity==SQLITE_AFF_INTEGER ); testcase( pCol->affinity==SQLITE_AFF_REAL ); |
︙ | ︙ | |||
1667 1668 1669 1670 1671 1672 1673 | ** on success and SQLITE_NOMEM on an OOM error. */ static int resizeIndexObject(sqlite3 *db, Index *pIdx, int N){ char *zExtra; int nByte; if( pIdx->nColumn>=N ) return SQLITE_OK; assert( pIdx->isResized==0 ); | | > > > | 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 | ** on success and SQLITE_NOMEM on an OOM error. */ static int resizeIndexObject(sqlite3 *db, Index *pIdx, int N){ char *zExtra; int nByte; if( pIdx->nColumn>=N ) return SQLITE_OK; assert( pIdx->isResized==0 ); nByte = (sizeof(char*) + sizeof(LogEst) + sizeof(i16) + 1)*N; zExtra = sqlite3DbMallocZero(db, nByte); if( zExtra==0 ) return SQLITE_NOMEM_BKPT; memcpy(zExtra, pIdx->azColl, sizeof(char*)*pIdx->nColumn); pIdx->azColl = (const char**)zExtra; zExtra += sizeof(char*)*N; memcpy(zExtra, pIdx->aiRowLogEst, sizeof(LogEst)*(pIdx->nKeyCol+1)); pIdx->aiRowLogEst = (LogEst*)zExtra; zExtra += sizeof(LogEst)*N; memcpy(zExtra, pIdx->aiColumn, sizeof(i16)*pIdx->nColumn); pIdx->aiColumn = (i16*)zExtra; zExtra += sizeof(i16)*N; memcpy(zExtra, pIdx->aSortOrder, pIdx->nColumn); pIdx->aSortOrder = (u8*)zExtra; pIdx->nColumn = N; pIdx->isResized = 1; |
︙ | ︙ | |||
1712 1713 1714 1715 1716 1717 1718 | i16 x = pIdx->aiColumn[i]; assert( x<pIdx->pTable->nCol ); wIndex += x<0 ? 1 : aCol[pIdx->aiColumn[i]].szEst; } pIdx->szIdxRow = sqlite3LogEst(wIndex*4); } | | > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | > | > > > > | | | | > > > > > > | > | > > > | > | > > > | | | > | > > > | > > > > > | > > > | | | > > | | | | | | | | < < < > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | < < < | > > | | > > > > > > > > > | > > > > > > > > > > | > | | | | | | < | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > | | | < < > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | 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 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 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 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 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 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 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 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 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 | i16 x = pIdx->aiColumn[i]; assert( x<pIdx->pTable->nCol ); wIndex += x<0 ? 1 : aCol[pIdx->aiColumn[i]].szEst; } pIdx->szIdxRow = sqlite3LogEst(wIndex*4); } /* Return true if column number x is any of the first nCol entries of aiCol[]. ** This is used to determine if the column number x appears in any of the ** first nCol entries of an index. */ static int hasColumn(const i16 *aiCol, int nCol, int x){ while( nCol-- > 0 ){ if( x==*(aiCol++) ){ return 1; } } return 0; } /* ** Return true if any of the first nKey entries of index pIdx exactly ** match the iCol-th entry of pPk. pPk is always a WITHOUT ROWID ** PRIMARY KEY index. pIdx is an index on the same table. pIdx may ** or may not be the same index as pPk. ** ** The first nKey entries of pIdx are guaranteed to be ordinary columns, ** not a rowid or expression. ** ** This routine differs from hasColumn() in that both the column and the ** collating sequence must match for this routine, but for hasColumn() only ** the column name must match. */ static int isDupColumn(Index *pIdx, int nKey, Index *pPk, int iCol){ int i, j; assert( nKey<=pIdx->nColumn ); assert( iCol<MAX(pPk->nColumn,pPk->nKeyCol) ); assert( pPk->idxType==SQLITE_IDXTYPE_PRIMARYKEY ); assert( pPk->pTable->tabFlags & TF_WithoutRowid ); assert( pPk->pTable==pIdx->pTable ); testcase( pPk==pIdx ); j = pPk->aiColumn[iCol]; assert( j!=XN_ROWID && j!=XN_EXPR ); for(i=0; i<nKey; i++){ assert( pIdx->aiColumn[i]>=0 || j>=0 ); if( pIdx->aiColumn[i]==j && sqlite3StrICmp(pIdx->azColl[i], pPk->azColl[iCol])==0 ){ return 1; } } return 0; } /* Recompute the colNotIdxed field of the Index. ** ** colNotIdxed is a bitmask that has a 0 bit representing each indexed ** columns that are within the first 63 columns of the table. The ** high-order bit of colNotIdxed is always 1. All unindexed columns ** of the table have a 1. ** ** 2019-10-24: For the purpose of this computation, virtual columns are ** not considered to be covered by the index, even if they are in the ** index, because we do not trust the logic in whereIndexExprTrans() to be ** able to find all instances of a reference to the indexed table column ** and convert them into references to the index. Hence we always want ** the actual table at hand in order to recompute the virtual column, if ** necessary. ** ** The colNotIdxed mask is AND-ed with the SrcList.a[].colUsed mask ** to determine if the index is covering index. */ static void recomputeColumnsNotIndexed(Index *pIdx){ Bitmask m = 0; int j; Table *pTab = pIdx->pTable; for(j=pIdx->nColumn-1; j>=0; j--){ int x = pIdx->aiColumn[j]; if( x>=0 && (pTab->aCol[x].colFlags & COLFLAG_VIRTUAL)==0 ){ testcase( x==BMS-1 ); testcase( x==BMS-2 ); if( x<BMS-1 ) m |= MASKBIT(x); } } pIdx->colNotIdxed = ~m; assert( (pIdx->colNotIdxed>>63)==1 ); } /* ** This routine runs at the end of parsing a CREATE TABLE statement that ** has a WITHOUT ROWID clause. The job of this routine is to convert both ** internal schema data structures and the generated VDBE code so that they ** are appropriate for a WITHOUT ROWID table instead of a rowid table. ** Changes include: ** ** (1) Set all columns of the PRIMARY KEY schema object to be NOT NULL. ** (2) Convert P3 parameter of the OP_CreateBtree from BTREE_INTKEY ** into BTREE_BLOBKEY. ** (3) Bypass the creation of the sqlite_schema table entry ** for the PRIMARY KEY as the primary key index is now ** identified by the sqlite_schema table entry of the table itself. ** (4) Set the Index.tnum of the PRIMARY KEY Index object in the ** schema to the rootpage from the main table. ** (5) Add all table columns to the PRIMARY KEY Index object ** so that the PRIMARY KEY is a covering index. The surplus ** columns are part of KeyInfo.nAllField and are not used for ** sorting or lookup or uniqueness checks. ** (6) Replace the rowid tail on all automatically generated UNIQUE ** indices with the PRIMARY KEY columns. ** ** For virtual tables, only (1) is performed. */ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){ Index *pIdx; Index *pPk; int nPk; int nExtra; int i, j; sqlite3 *db = pParse->db; Vdbe *v = pParse->pVdbe; /* Mark every PRIMARY KEY column as NOT NULL (except for imposter tables) */ if( !db->init.imposterTable ){ for(i=0; i<pTab->nCol; i++){ if( (pTab->aCol[i].colFlags & COLFLAG_PRIMKEY)!=0 && (pTab->aCol[i].notNull==OE_None) ){ pTab->aCol[i].notNull = OE_Abort; } } pTab->tabFlags |= TF_HasNotNull; } /* Convert the P3 operand of the OP_CreateBtree opcode from BTREE_INTKEY ** into BTREE_BLOBKEY. */ assert( !pParse->bReturning ); if( pParse->u1.addrCrTab ){ assert( v ); sqlite3VdbeChangeP3(v, pParse->u1.addrCrTab, BTREE_BLOBKEY); } /* Locate the PRIMARY KEY index. Or, if this table was originally ** an INTEGER PRIMARY KEY table, create a new PRIMARY KEY index. */ if( pTab->iPKey>=0 ){ ExprList *pList; Token ipkToken; sqlite3TokenInit(&ipkToken, pTab->aCol[pTab->iPKey].zCnName); pList = sqlite3ExprListAppend(pParse, 0, sqlite3ExprAlloc(db, TK_ID, &ipkToken, 0)); if( pList==0 ){ pTab->tabFlags &= ~TF_WithoutRowid; return; } if( IN_RENAME_OBJECT ){ sqlite3RenameTokenRemap(pParse, pList->a[0].pExpr, &pTab->iPKey); } pList->a[0].sortFlags = pParse->iPkSortOrder; assert( pParse->pNewTable==pTab ); pTab->iPKey = -1; sqlite3CreateIndex(pParse, 0, 0, 0, pList, pTab->keyConf, 0, 0, 0, 0, SQLITE_IDXTYPE_PRIMARYKEY); if( db->mallocFailed || pParse->nErr ){ pTab->tabFlags &= ~TF_WithoutRowid; return; } pPk = sqlite3PrimaryKeyIndex(pTab); assert( pPk->nKeyCol==1 ); }else{ pPk = sqlite3PrimaryKeyIndex(pTab); assert( pPk!=0 ); /* ** Remove all redundant columns from the PRIMARY KEY. For example, change ** "PRIMARY KEY(a,b,a,b,c,b,c,d)" into just "PRIMARY KEY(a,b,c,d)". Later ** code assumes the PRIMARY KEY contains no repeated columns. */ for(i=j=1; i<pPk->nKeyCol; i++){ if( isDupColumn(pPk, j, pPk, i) ){ pPk->nColumn--; }else{ testcase( hasColumn(pPk->aiColumn, j, pPk->aiColumn[i]) ); pPk->azColl[j] = pPk->azColl[i]; pPk->aSortOrder[j] = pPk->aSortOrder[i]; pPk->aiColumn[j++] = pPk->aiColumn[i]; } } pPk->nKeyCol = j; } assert( pPk!=0 ); pPk->isCovering = 1; if( !db->init.imposterTable ) pPk->uniqNotNull = 1; nPk = pPk->nColumn = pPk->nKeyCol; /* Bypass the creation of the PRIMARY KEY btree and the sqlite_schema ** table entry. This is only required if currently generating VDBE ** code for a CREATE TABLE (not when parsing one as part of reading ** a database schema). */ if( v && pPk->tnum>0 ){ assert( db->init.busy==0 ); sqlite3VdbeChangeOpcode(v, (int)pPk->tnum, OP_Goto); } /* The root page of the PRIMARY KEY is the table root page */ pPk->tnum = pTab->tnum; /* Update the in-memory representation of all UNIQUE indices by converting ** the final rowid column into one or more columns of the PRIMARY KEY. */ for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ int n; if( IsPrimaryKeyIndex(pIdx) ) continue; for(i=n=0; i<nPk; i++){ if( !isDupColumn(pIdx, pIdx->nKeyCol, pPk, i) ){ testcase( hasColumn(pIdx->aiColumn, pIdx->nKeyCol, pPk->aiColumn[i]) ); n++; } } if( n==0 ){ /* This index is a superset of the primary key */ pIdx->nColumn = pIdx->nKeyCol; continue; } if( resizeIndexObject(db, pIdx, pIdx->nKeyCol+n) ) return; for(i=0, j=pIdx->nKeyCol; i<nPk; i++){ if( !isDupColumn(pIdx, pIdx->nKeyCol, pPk, i) ){ testcase( hasColumn(pIdx->aiColumn, pIdx->nKeyCol, pPk->aiColumn[i]) ); pIdx->aiColumn[j] = pPk->aiColumn[i]; pIdx->azColl[j] = pPk->azColl[i]; if( pPk->aSortOrder[i] ){ /* See ticket https://www.sqlite.org/src/info/bba7b69f9849b5bf */ pIdx->bAscKeyBug = 1; } j++; } } assert( pIdx->nColumn>=pIdx->nKeyCol+n ); assert( pIdx->nColumn>=j ); } /* Add all table columns to the PRIMARY KEY index */ nExtra = 0; for(i=0; i<pTab->nCol; i++){ if( !hasColumn(pPk->aiColumn, nPk, i) && (pTab->aCol[i].colFlags & COLFLAG_VIRTUAL)==0 ) nExtra++; } if( resizeIndexObject(db, pPk, nPk+nExtra) ) return; for(i=0, j=nPk; i<pTab->nCol; i++){ if( !hasColumn(pPk->aiColumn, j, i) && (pTab->aCol[i].colFlags & COLFLAG_VIRTUAL)==0 ){ assert( j<pPk->nColumn ); pPk->aiColumn[j] = i; pPk->azColl[j] = sqlite3StrBINARY; j++; } } assert( pPk->nColumn==j ); assert( pTab->nNVCol<=j ); recomputeColumnsNotIndexed(pPk); } #ifndef SQLITE_OMIT_VIRTUALTABLE /* ** Return true if pTab is a virtual table and zName is a shadow table name ** for that virtual table. */ int sqlite3IsShadowTableOf(sqlite3 *db, Table *pTab, const char *zName){ int nName; /* Length of zName */ Module *pMod; /* Module for the virtual table */ if( !IsVirtual(pTab) ) return 0; nName = sqlite3Strlen30(pTab->zName); if( sqlite3_strnicmp(zName, pTab->zName, nName)!=0 ) return 0; if( zName[nName]!='_' ) return 0; pMod = (Module*)sqlite3HashFind(&db->aModule, pTab->u.vtab.azArg[0]); if( pMod==0 ) return 0; if( pMod->pModule->iVersion<3 ) return 0; if( pMod->pModule->xShadowName==0 ) return 0; return pMod->pModule->xShadowName(zName+nName+1); } #endif /* ifndef SQLITE_OMIT_VIRTUALTABLE */ #ifndef SQLITE_OMIT_VIRTUALTABLE /* ** Table pTab is a virtual table. If it the virtual table implementation ** exists and has an xShadowName method, then loop over all other ordinary ** tables within the same schema looking for shadow tables of pTab, and mark ** any shadow tables seen using the TF_Shadow flag. */ void sqlite3MarkAllShadowTablesOf(sqlite3 *db, Table *pTab){ int nName; /* Length of pTab->zName */ Module *pMod; /* Module for the virtual table */ HashElem *k; /* For looping through the symbol table */ assert( IsVirtual(pTab) ); pMod = (Module*)sqlite3HashFind(&db->aModule, pTab->u.vtab.azArg[0]); if( pMod==0 ) return; if( NEVER(pMod->pModule==0) ) return; if( pMod->pModule->iVersion<3 ) return; if( pMod->pModule->xShadowName==0 ) return; assert( pTab->zName!=0 ); nName = sqlite3Strlen30(pTab->zName); for(k=sqliteHashFirst(&pTab->pSchema->tblHash); k; k=sqliteHashNext(k)){ Table *pOther = sqliteHashData(k); assert( pOther->zName!=0 ); if( !IsOrdinaryTable(pOther) ) continue; if( pOther->tabFlags & TF_Shadow ) continue; if( sqlite3StrNICmp(pOther->zName, pTab->zName, nName)==0 && pOther->zName[nName]=='_' && pMod->pModule->xShadowName(pOther->zName+nName+1) ){ pOther->tabFlags |= TF_Shadow; } } } #endif /* ifndef SQLITE_OMIT_VIRTUALTABLE */ #ifndef SQLITE_OMIT_VIRTUALTABLE /* ** Return true if zName is a shadow table name in the current database ** connection. ** ** zName is temporarily modified while this routine is running, but is ** restored to its original value prior to this routine returning. */ int sqlite3ShadowTableName(sqlite3 *db, const char *zName){ char *zTail; /* Pointer to the last "_" in zName */ Table *pTab; /* Table that zName is a shadow of */ zTail = strrchr(zName, '_'); if( zTail==0 ) return 0; *zTail = 0; pTab = sqlite3FindTable(db, zName, 0); *zTail = '_'; if( pTab==0 ) return 0; if( !IsVirtual(pTab) ) return 0; return sqlite3IsShadowTableOf(db, pTab, zName); } #endif /* ifndef SQLITE_OMIT_VIRTUALTABLE */ #ifdef SQLITE_DEBUG /* ** Mark all nodes of an expression as EP_Immutable, indicating that ** they should not be changed. Expressions attached to a table or ** index definition are tagged this way to help ensure that we do ** not pass them into code generator routines by mistake. */ static int markImmutableExprStep(Walker *pWalker, Expr *pExpr){ ExprSetVVAProperty(pExpr, EP_Immutable); return WRC_Continue; } static void markExprListImmutable(ExprList *pList){ if( pList ){ Walker w; memset(&w, 0, sizeof(w)); w.xExprCallback = markImmutableExprStep; w.xSelectCallback = sqlite3SelectWalkNoop; w.xSelectCallback2 = 0; sqlite3WalkExprList(&w, pList); } } #else #define markExprListImmutable(X) /* no-op */ #endif /* SQLITE_DEBUG */ /* ** This routine is called to report the final ")" that terminates ** a CREATE TABLE statement. ** ** The table structure that other action routines have been building ** is added to the internal hash tables, assuming no errors have ** occurred. ** ** An entry for the table is made in the schema table on disk, unless ** this is a temporary table or db->init.busy==1. When db->init.busy==1 ** it means we are reading the sqlite_schema table because we just ** connected to the database or because the sqlite_schema table has ** recently changed, so the entry for this table already exists in ** the sqlite_schema table. We do not want to create it again. ** ** If the pSelect argument is not NULL, it means that this routine ** was called to create a table generated from a ** "CREATE TABLE ... AS SELECT ..." statement. The column names of ** the new table will match the result set of the SELECT. */ void sqlite3EndTable( Parse *pParse, /* Parse context */ Token *pCons, /* The ',' token after the last column defn. */ Token *pEnd, /* The ')' before options in the CREATE TABLE */ u32 tabOpts, /* Extra table options. Usually 0. */ Select *pSelect /* Select from a "CREATE ... AS SELECT" */ ){ Table *p; /* The new table */ sqlite3 *db = pParse->db; /* The database connection */ int iDb; /* Database in which the table lives */ Index *pIdx; /* An implied index of the table */ if( pEnd==0 && pSelect==0 ){ return; } p = pParse->pNewTable; if( p==0 ) return; if( pSelect==0 && sqlite3ShadowTableName(db, p->zName) ){ p->tabFlags |= TF_Shadow; } /* If the db->init.busy is 1 it means we are reading the SQL off the ** "sqlite_schema" or "sqlite_temp_schema" table on the disk. ** So do not write to the disk again. Extract the root page number ** for the table from the db->init.newTnum field. (The page number ** should have been put there by the sqliteOpenCb routine.) ** ** If the root page number is 1, that means this is the sqlite_schema ** table itself. So mark it read-only. */ if( db->init.busy ){ if( pSelect || (!IsOrdinaryTable(p) && db->init.newTnum) ){ sqlite3ErrorMsg(pParse, ""); return; } p->tnum = db->init.newTnum; if( p->tnum==1 ) p->tabFlags |= TF_Readonly; } /* Special processing for tables that include the STRICT keyword: ** ** * Do not allow custom column datatypes. Every column must have ** a datatype that is one of INT, INTEGER, REAL, TEXT, or BLOB. ** ** * If a PRIMARY KEY is defined, other than the INTEGER PRIMARY KEY, ** then all columns of the PRIMARY KEY must have a NOT NULL ** constraint. */ if( tabOpts & TF_Strict ){ int ii; p->tabFlags |= TF_Strict; for(ii=0; ii<p->nCol; ii++){ Column *pCol = &p->aCol[ii]; if( pCol->eCType==COLTYPE_CUSTOM ){ if( pCol->colFlags & COLFLAG_HASTYPE ){ sqlite3ErrorMsg(pParse, "unknown datatype for %s.%s: \"%s\"", p->zName, pCol->zCnName, sqlite3ColumnType(pCol, "") ); }else{ sqlite3ErrorMsg(pParse, "missing datatype for %s.%s", p->zName, pCol->zCnName); } return; }else if( pCol->eCType==COLTYPE_ANY ){ pCol->affinity = SQLITE_AFF_BLOB; } if( (pCol->colFlags & COLFLAG_PRIMKEY)!=0 && p->iPKey!=ii && pCol->notNull == OE_None ){ pCol->notNull = OE_Abort; p->tabFlags |= TF_HasNotNull; } } } assert( (p->tabFlags & TF_HasPrimaryKey)==0 || p->iPKey>=0 || sqlite3PrimaryKeyIndex(p)!=0 ); assert( (p->tabFlags & TF_HasPrimaryKey)!=0 || (p->iPKey<0 && sqlite3PrimaryKeyIndex(p)==0) ); /* Special processing for WITHOUT ROWID Tables */ if( tabOpts & TF_WithoutRowid ){ if( (p->tabFlags & TF_Autoincrement) ){ sqlite3ErrorMsg(pParse, "AUTOINCREMENT not allowed on WITHOUT ROWID tables"); return; } if( (p->tabFlags & TF_HasPrimaryKey)==0 ){ sqlite3ErrorMsg(pParse, "PRIMARY KEY missing on table %s", p->zName); return; } p->tabFlags |= TF_WithoutRowid | TF_NoVisibleRowid; convertToWithoutRowidTable(pParse, p); } iDb = sqlite3SchemaToIndex(db, p->pSchema); #ifndef SQLITE_OMIT_CHECK /* Resolve names in all CHECK constraint expressions. */ if( p->pCheck ){ sqlite3ResolveSelfReference(pParse, p, NC_IsCheck, 0, p->pCheck); if( pParse->nErr ){ /* If errors are seen, delete the CHECK constraints now, else they might ** actually be used if PRAGMA writable_schema=ON is set. */ sqlite3ExprListDelete(db, p->pCheck); p->pCheck = 0; }else{ markExprListImmutable(p->pCheck); } } #endif /* !defined(SQLITE_OMIT_CHECK) */ #ifndef SQLITE_OMIT_GENERATED_COLUMNS if( p->tabFlags & TF_HasGenerated ){ int ii, nNG = 0; testcase( p->tabFlags & TF_HasVirtual ); testcase( p->tabFlags & TF_HasStored ); for(ii=0; ii<p->nCol; ii++){ u32 colFlags = p->aCol[ii].colFlags; if( (colFlags & COLFLAG_GENERATED)!=0 ){ Expr *pX = sqlite3ColumnExpr(p, &p->aCol[ii]); testcase( colFlags & COLFLAG_VIRTUAL ); testcase( colFlags & COLFLAG_STORED ); if( sqlite3ResolveSelfReference(pParse, p, NC_GenCol, pX, 0) ){ /* If there are errors in resolving the expression, change the ** expression to a NULL. This prevents code generators that operate ** on the expression from inserting extra parts into the expression ** tree that have been allocated from lookaside memory, which is ** illegal in a schema and will lead to errors or heap corruption ** when the database connection closes. */ sqlite3ColumnSetExpr(pParse, p, &p->aCol[ii], sqlite3ExprAlloc(db, TK_NULL, 0, 0)); } }else{ nNG++; } } if( nNG==0 ){ sqlite3ErrorMsg(pParse, "must have at least one non-generated column"); return; } } #endif /* Estimate the average row size for the table and for all implied indices */ estimateTableWidth(p); for(pIdx=p->pIndex; pIdx; pIdx=pIdx->pNext){ estimateIndexWidth(pIdx); } /* If not initializing, then create a record for the new table ** in the schema table of the database. ** ** If this is a TEMPORARY table, write the entry into the auxiliary ** file instead of into the main database file. */ if( !db->init.busy ){ int n; Vdbe *v; char *zType; /* "view" or "table" */ char *zType2; /* "VIEW" or "TABLE" */ char *zStmt; /* Text of the CREATE TABLE or CREATE VIEW statement */ v = sqlite3GetVdbe(pParse); if( NEVER(v==0) ) return; sqlite3VdbeAddOp1(v, OP_Close, 0); /* ** Initialize zType for the new view or table. */ if( IsOrdinaryTable(p) ){ /* A regular table */ zType = "table"; zType2 = "TABLE"; #ifndef SQLITE_OMIT_VIEW }else{ /* A view */ zType = "view"; |
︙ | ︙ | |||
2079 2080 2081 2082 2083 2084 2085 | sqlite3MayAbort(pParse); sqlite3VdbeAddOp3(v, OP_OpenWrite, 1, pParse->regRoot, iDb); sqlite3VdbeChangeP5(v, OPFLAG_P2ISREG); pParse->nTab = 2; addrTop = sqlite3VdbeCurrentAddr(v) + 1; sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, addrTop); if( pParse->nErr ) return; | | | | 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 | sqlite3MayAbort(pParse); sqlite3VdbeAddOp3(v, OP_OpenWrite, 1, pParse->regRoot, iDb); sqlite3VdbeChangeP5(v, OPFLAG_P2ISREG); pParse->nTab = 2; addrTop = sqlite3VdbeCurrentAddr(v) + 1; sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, addrTop); if( pParse->nErr ) return; pSelTab = sqlite3ResultSetOfSelect(pParse, pSelect, SQLITE_AFF_BLOB); if( pSelTab==0 ) return; assert( p->aCol==0 ); p->nCol = p->nNVCol = pSelTab->nCol; p->aCol = pSelTab->aCol; pSelTab->nCol = 0; pSelTab->aCol = 0; sqlite3DeleteTable(db, pSelTab); sqlite3SelectDestInit(&dest, SRT_Coroutine, regYield); sqlite3Select(pParse, pSelect, &dest); if( pParse->nErr ) return; |
︙ | ︙ | |||
2116 2117 2118 2119 2120 2121 2122 | if( pEnd2->z[0]!=';' ) n += pEnd2->n; zStmt = sqlite3MPrintf(db, "CREATE %s %.*s", zType2, n, pParse->sNameToken.z ); } /* A slot for the record has already been allocated in the | | | | | | | | < > > > > > | > > | > > > | < > > | | | | < | | < | 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 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 | if( pEnd2->z[0]!=';' ) n += pEnd2->n; zStmt = sqlite3MPrintf(db, "CREATE %s %.*s", zType2, n, pParse->sNameToken.z ); } /* A slot for the record has already been allocated in the ** schema table. We just need to update that slot with all ** the information we've collected. */ sqlite3NestedParse(pParse, "UPDATE %Q." LEGACY_SCHEMA_TABLE " SET type='%s', name=%Q, tbl_name=%Q, rootpage=#%d, sql=%Q" " WHERE rowid=#%d", db->aDb[iDb].zDbSName, zType, p->zName, p->zName, pParse->regRoot, zStmt, pParse->regRowid ); sqlite3DbFree(db, zStmt); sqlite3ChangeCookie(pParse, iDb); #ifndef SQLITE_OMIT_AUTOINCREMENT /* Check to see if we need to create an sqlite_sequence table for ** keeping track of autoincrement keys. */ if( (p->tabFlags & TF_Autoincrement)!=0 && !IN_SPECIAL_PARSE ){ Db *pDb = &db->aDb[iDb]; assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); if( pDb->pSchema->pSeqTab==0 ){ sqlite3NestedParse(pParse, "CREATE TABLE %Q.sqlite_sequence(name,seq)", pDb->zDbSName ); } } #endif /* Reparse everything to update our internal data structures */ sqlite3VdbeAddParseSchemaOp(v, iDb, sqlite3MPrintf(db, "tbl_name='%q' AND type!='trigger'", p->zName),0); } /* Add the table to the in-memory representation of the database. */ if( db->init.busy ){ Table *pOld; Schema *pSchema = p->pSchema; assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); assert( HasRowid(p) || p->iPKey<0 ); pOld = sqlite3HashInsert(&pSchema->tblHash, p->zName, p); if( pOld ){ assert( p==pOld ); /* Malloc must have failed inside HashInsert() */ sqlite3OomFault(db); return; } pParse->pNewTable = 0; db->mDbFlags |= DBFLAG_SchemaChange; /* If this is the magic sqlite_sequence table used by autoincrement, ** then record a pointer to this table in the main database structure ** so that INSERT can find the table easily. */ assert( !pParse->nested ); #ifndef SQLITE_OMIT_AUTOINCREMENT if( strcmp(p->zName, "sqlite_sequence")==0 ){ assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); p->pSchema->pSeqTab = p; } #endif } #ifndef SQLITE_OMIT_ALTERTABLE if( !pSelect && IsOrdinaryTable(p) ){ assert( pCons && pEnd ); if( pCons->z==0 ){ pCons = pEnd; } p->u.tab.addColOffset = 13 + (int)(pCons->z - pParse->sNameToken.z); } #endif } #ifndef SQLITE_OMIT_VIEW /* ** The parser calls this routine in order to create a new VIEW */ void sqlite3CreateView( |
︙ | ︙ | |||
2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 | if( pParse->nVar>0 ){ sqlite3ErrorMsg(pParse, "parameters are not allowed in views"); goto create_view_fail; } sqlite3StartTable(pParse, pName1, pName2, isTemp, 1, 0, noErr); p = pParse->pNewTable; if( p==0 || pParse->nErr ) goto create_view_fail; sqlite3TwoPartName(pParse, pName1, pName2, &pName); iDb = sqlite3SchemaToIndex(db, p->pSchema); sqlite3FixInit(&sFix, pParse, iDb, "view", pName); if( sqlite3FixSelect(&sFix, pSelect) ) goto create_view_fail; /* Make a copy of the entire SELECT statement that defines the view. ** This will force all the Expr.token.z values to be dynamically ** allocated rather than point to the input string - which means that ** they will persist after the current sqlite3_exec() call returns. */ if( IN_RENAME_OBJECT ){ | > > > > > > > > > > > | | > | | 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 | if( pParse->nVar>0 ){ sqlite3ErrorMsg(pParse, "parameters are not allowed in views"); goto create_view_fail; } sqlite3StartTable(pParse, pName1, pName2, isTemp, 1, 0, noErr); p = pParse->pNewTable; if( p==0 || pParse->nErr ) goto create_view_fail; /* Legacy versions of SQLite allowed the use of the magic "rowid" column ** on a view, even though views do not have rowids. The following flag ** setting fixes this problem. But the fix can be disabled by compiling ** with -DSQLITE_ALLOW_ROWID_IN_VIEW in case there are legacy apps that ** depend upon the old buggy behavior. */ #ifndef SQLITE_ALLOW_ROWID_IN_VIEW p->tabFlags |= TF_NoVisibleRowid; #endif sqlite3TwoPartName(pParse, pName1, pName2, &pName); iDb = sqlite3SchemaToIndex(db, p->pSchema); sqlite3FixInit(&sFix, pParse, iDb, "view", pName); if( sqlite3FixSelect(&sFix, pSelect) ) goto create_view_fail; /* Make a copy of the entire SELECT statement that defines the view. ** This will force all the Expr.token.z values to be dynamically ** allocated rather than point to the input string - which means that ** they will persist after the current sqlite3_exec() call returns. */ pSelect->selFlags |= SF_View; if( IN_RENAME_OBJECT ){ p->u.view.pSelect = pSelect; pSelect = 0; }else{ p->u.view.pSelect = sqlite3SelectDup(db, pSelect, EXPRDUP_REDUCE); } p->pCheck = sqlite3ExprListDup(db, pCNames, EXPRDUP_REDUCE); p->eTabType = TABTYP_VIEW; if( db->mallocFailed ) goto create_view_fail; /* Locate the end of the CREATE VIEW statement. Make sEnd point to ** the end. */ sEnd = pParse->sLastToken; assert( sEnd.z[0]!=0 || sEnd.n==0 ); if( sEnd.z[0]!=';' ){ sEnd.z += sEnd.n; } sEnd.n = 0; n = (int)(sEnd.z - pBegin->z); assert( n>0 ); z = pBegin->z; while( sqlite3Isspace(z[n-1]) ){ n--; } sEnd.z = &z[n-1]; sEnd.n = 1; /* Use sqlite3EndTable() to add the view to the schema table */ sqlite3EndTable(pParse, 0, &sEnd, 0, 0); create_view_fail: sqlite3SelectDelete(db, pSelect); if( IN_RENAME_OBJECT ){ sqlite3RenameExprlistUnmap(pParse, pCNames); } |
︙ | ︙ | |||
2286 2287 2288 2289 2290 2291 2292 | #ifndef SQLITE_OMIT_AUTHORIZATION sqlite3_xauth xAuth; /* Saved xAuth pointer */ #endif assert( pTable ); #ifndef SQLITE_OMIT_VIRTUALTABLE | > | | | < | < | 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 | #ifndef SQLITE_OMIT_AUTHORIZATION sqlite3_xauth xAuth; /* Saved xAuth pointer */ #endif assert( pTable ); #ifndef SQLITE_OMIT_VIRTUALTABLE if( IsVirtual(pTable) ){ db->nSchemaLock++; rc = sqlite3VtabCallConnect(pParse, pTable); db->nSchemaLock--; return rc; } #endif #ifndef SQLITE_OMIT_VIEW /* A positive nCol means the columns names for this view are ** already known. */ if( pTable->nCol>0 ) return 0; |
︙ | ︙ | |||
2329 2330 2331 2332 2333 2334 2335 | /* If we get this far, it means we need to compute the table names. ** Note that the call to sqlite3ResultSetOfSelect() will expand any ** "*" elements in the results set of the view and will assign cursors ** to the elements of the FROM clause. But we do not want these changes ** to be permanent. So the computation is done on a copy of the SELECT ** statement that defines the view. */ | | | < < | | | > > > | | > | > < < < > | < < < < | < < | 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 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 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 | /* If we get this far, it means we need to compute the table names. ** Note that the call to sqlite3ResultSetOfSelect() will expand any ** "*" elements in the results set of the view and will assign cursors ** to the elements of the FROM clause. But we do not want these changes ** to be permanent. So the computation is done on a copy of the SELECT ** statement that defines the view. */ assert( IsView(pTable) ); pSel = sqlite3SelectDup(db, pTable->u.view.pSelect, 0); if( pSel ){ u8 eParseMode = pParse->eParseMode; pParse->eParseMode = PARSE_MODE_NORMAL; n = pParse->nTab; sqlite3SrcListAssignCursors(pParse, pSel->pSrc); pTable->nCol = -1; DisableLookaside; #ifndef SQLITE_OMIT_AUTHORIZATION xAuth = db->xAuth; db->xAuth = 0; pSelTab = sqlite3ResultSetOfSelect(pParse, pSel, SQLITE_AFF_NONE); db->xAuth = xAuth; #else pSelTab = sqlite3ResultSetOfSelect(pParse, pSel, SQLITE_AFF_NONE); #endif pParse->nTab = n; if( pSelTab==0 ){ pTable->nCol = 0; nErr++; }else if( pTable->pCheck ){ /* CREATE VIEW name(arglist) AS ... ** The names of the columns in the table are taken from ** arglist which is stored in pTable->pCheck. The pCheck field ** normally holds CHECK constraints on an ordinary table, but for ** a VIEW it holds the list of column names. */ sqlite3ColumnsFromExprList(pParse, pTable->pCheck, &pTable->nCol, &pTable->aCol); if( db->mallocFailed==0 && pParse->nErr==0 && pTable->nCol==pSel->pEList->nExpr ){ sqlite3SelectAddColumnTypeAndCollation(pParse, pTable, pSel, SQLITE_AFF_NONE); } }else{ /* CREATE VIEW name AS... without an argument list. Construct ** the column names from the SELECT statement that defines the view. */ assert( pTable->aCol==0 ); pTable->nCol = pSelTab->nCol; pTable->aCol = pSelTab->aCol; pTable->tabFlags |= (pSelTab->tabFlags & COLFLAG_NOINSERT); pSelTab->nCol = 0; pSelTab->aCol = 0; assert( sqlite3SchemaMutexHeld(db, 0, pTable->pSchema) ); } pTable->nNVCol = pTable->nCol; sqlite3DeleteTable(db, pSelTab); sqlite3SelectDelete(db, pSel); EnableLookaside; pParse->eParseMode = eParseMode; } else { nErr++; } pTable->pSchema->schemaFlags |= DB_UnresetViews; if( db->mallocFailed ){ sqlite3DeleteColumnNames(db, pTable); } #endif /* SQLITE_OMIT_VIEW */ return nErr; } #endif /* !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE) */ #ifndef SQLITE_OMIT_VIEW /* ** Clear the column names from every VIEW in database idx. */ static void sqliteViewResetAll(sqlite3 *db, int idx){ HashElem *i; assert( sqlite3SchemaMutexHeld(db, idx, 0) ); if( !DbHasProperty(db, idx, DB_UnresetViews) ) return; for(i=sqliteHashFirst(&db->aDb[idx].pSchema->tblHash); i;i=sqliteHashNext(i)){ Table *pTab = sqliteHashData(i); if( IsView(pTab) ){ sqlite3DeleteColumnNames(db, pTab); } } DbClearProperty(db, idx, DB_UnresetViews); } #else # define sqliteViewResetAll(A,B) #endif /* SQLITE_OMIT_VIEW */ |
︙ | ︙ | |||
2438 2439 2440 2441 2442 2443 2444 | ** because the first match might be for one of the deleted indices ** or tables and not the table/index that is actually being moved. ** We must continue looping until all tables and indices with ** rootpage==iFrom have been converted to have a rootpage of iTo ** in order to be certain that we got the right one. */ #ifndef SQLITE_OMIT_AUTOVACUUM | | | 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 | ** because the first match might be for one of the deleted indices ** or tables and not the table/index that is actually being moved. ** We must continue looping until all tables and indices with ** rootpage==iFrom have been converted to have a rootpage of iTo ** in order to be certain that we got the right one. */ #ifndef SQLITE_OMIT_AUTOVACUUM void sqlite3RootPageMoved(sqlite3 *db, int iDb, Pgno iFrom, Pgno iTo){ HashElem *pElem; Hash *pHash; Db *pDb; assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); pDb = &db->aDb[iDb]; pHash = &pDb->pSchema->tblHash; |
︙ | ︙ | |||
2464 2465 2466 2467 2468 2469 2470 | } } } #endif /* ** Write code to erase the table with root-page iTable from database iDb. | | | > | | | | | | | | 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 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 | } } } #endif /* ** Write code to erase the table with root-page iTable from database iDb. ** Also write code to modify the sqlite_schema table and internal schema ** if a root-page of another table is moved by the btree-layer whilst ** erasing iTable (this can happen with an auto-vacuum database). */ static void destroyRootPage(Parse *pParse, int iTable, int iDb){ Vdbe *v = sqlite3GetVdbe(pParse); int r1 = sqlite3GetTempReg(pParse); if( iTable<2 ) sqlite3ErrorMsg(pParse, "corrupt schema"); sqlite3VdbeAddOp3(v, OP_Destroy, iTable, r1, iDb); sqlite3MayAbort(pParse); #ifndef SQLITE_OMIT_AUTOVACUUM /* OP_Destroy stores an in integer r1. If this integer ** is non-zero, then it is the root page number of a table moved to ** location iTable. The following code modifies the sqlite_schema table to ** reflect this. ** ** The "#NNN" in the SQL is a special constant that means whatever value ** is in register NNN. See grammar rules associated with the TK_REGISTER ** token for additional information. */ sqlite3NestedParse(pParse, "UPDATE %Q." LEGACY_SCHEMA_TABLE " SET rootpage=%d WHERE #%d AND rootpage=#%d", pParse->db->aDb[iDb].zDbSName, iTable, r1, r1); #endif sqlite3ReleaseTempReg(pParse, r1); } /* ** Write VDBE code to erase table pTab and all associated indices on disk. ** Code to update the sqlite_schema tables and internal schema definitions ** in case a root-page belonging to another table is moved by the btree layer ** is also added (this can happen with an auto-vacuum database). */ static void destroyTable(Parse *pParse, Table *pTab){ /* If the database may be auto-vacuum capable (if SQLITE_OMIT_AUTOVACUUM ** is not defined), then it is important to call OP_Destroy on the ** table and index root-pages in order, starting with the numerically ** largest root-page number. This guarantees that none of the root-pages ** to be destroyed is relocated by an earlier OP_Destroy. i.e. if the ** following were coded: ** ** OP_Destroy 4 0 ** ... ** OP_Destroy 5 0 ** ** and root page 5 happened to be the largest root-page number in the ** database, then root page 5 would be moved to page 4 by the ** "OP_Destroy 4 0" opcode. The subsequent "OP_Destroy 5 0" would hit ** a free-list page. */ Pgno iTab = pTab->tnum; Pgno iDestroyed = 0; while( 1 ){ Index *pIdx; Pgno iLargest = 0; if( iDestroyed==0 || iTab<iDestroyed ){ iLargest = iTab; } for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ Pgno iIdx = pIdx->tnum; assert( pIdx->pSchema==pTab->pSchema ); if( (iDestroyed==0 || (iIdx<iDestroyed)) && iIdx>iLargest ){ iLargest = iIdx; } } if( iLargest==0 ){ return; |
︙ | ︙ | |||
2586 2587 2588 2589 2590 2591 2592 | #ifndef SQLITE_OMIT_VIRTUALTABLE if( IsVirtual(pTab) ){ sqlite3VdbeAddOp0(v, OP_VBegin); } #endif /* Drop all triggers associated with the table being dropped. Code | | | | 3350 3351 3352 3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 | #ifndef SQLITE_OMIT_VIRTUALTABLE if( IsVirtual(pTab) ){ sqlite3VdbeAddOp0(v, OP_VBegin); } #endif /* Drop all triggers associated with the table being dropped. Code ** is generated to remove entries from sqlite_schema and/or ** sqlite_temp_schema if required. */ pTrigger = sqlite3TriggerList(pParse, pTab); while( pTrigger ){ assert( pTrigger->pSchema==pTab->pSchema || pTrigger->pSchema==db->aDb[1].pSchema ); sqlite3DropTriggerPtr(pParse, pTrigger); pTrigger = pTrigger->pNext; |
︙ | ︙ | |||
2611 2612 2613 2614 2615 2616 2617 | sqlite3NestedParse(pParse, "DELETE FROM %Q.sqlite_sequence WHERE name=%Q", pDb->zDbSName, pTab->zName ); } #endif | | | > | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 | sqlite3NestedParse(pParse, "DELETE FROM %Q.sqlite_sequence WHERE name=%Q", pDb->zDbSName, pTab->zName ); } #endif /* Drop all entries in the schema table that refer to the ** table. The program name loops through the schema 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." LEGACY_SCHEMA_TABLE " WHERE tbl_name=%Q and type!='trigger'", pDb->zDbSName, pTab->zName); if( !isView && !IsVirtual(pTab) ){ destroyTable(pParse, pTab); } /* Remove the table entry from SQLite's internal schema and modify ** the schema cookie. */ if( IsVirtual(pTab) ){ sqlite3VdbeAddOp4(v, OP_VDestroy, iDb, 0, 0, pTab->zName, 0); sqlite3MayAbort(pParse); } sqlite3VdbeAddOp4(v, OP_DropTable, iDb, 0, 0, pTab->zName, 0); sqlite3ChangeCookie(pParse, iDb); sqliteViewResetAll(db, iDb); } /* ** Return TRUE if shadow tables should be read-only in the current ** context. */ int sqlite3ReadOnlyShadowTables(sqlite3 *db){ #ifndef SQLITE_OMIT_VIRTUALTABLE if( (db->flags & SQLITE_Defensive)!=0 && db->pVtabCtx==0 && db->nVdbeExec==0 && !sqlite3VtabInSync(db) ){ return 1; } #endif return 0; } /* ** Return true if it is not allowed to drop the given table */ static int tableMayNotBeDropped(sqlite3 *db, Table *pTab){ if( sqlite3StrNICmp(pTab->zName, "sqlite_", 7)==0 ){ if( sqlite3StrNICmp(pTab->zName+7, "stat", 4)==0 ) return 0; if( sqlite3StrNICmp(pTab->zName+7, "parameters", 10)==0 ) return 0; return 1; } if( (pTab->tabFlags & TF_Shadow)!=0 && sqlite3ReadOnlyShadowTables(db) ){ return 1; } if( pTab->tabFlags & TF_Eponymous ){ return 1; } return 0; } /* ** This routine is called to do the work of a DROP TABLE statement. ** pName is the name of the table to be dropped. */ void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, int noErr){ Table *pTab; |
︙ | ︙ | |||
2658 2659 2660 2661 2662 2663 2664 | if( sqlite3ReadSchema(pParse) ) goto exit_drop_table; if( noErr ) db->suppressErr++; assert( isView==0 || isView==LOCATE_VIEW ); pTab = sqlite3LocateTableItem(pParse, isView, &pName->a[0]); if( noErr ) db->suppressErr--; if( pTab==0 ){ | > | > > | 3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 | if( sqlite3ReadSchema(pParse) ) goto exit_drop_table; if( noErr ) db->suppressErr++; assert( isView==0 || isView==LOCATE_VIEW ); pTab = sqlite3LocateTableItem(pParse, isView, &pName->a[0]); if( noErr ) db->suppressErr--; if( pTab==0 ){ if( noErr ){ sqlite3CodeVerifyNamedSchema(pParse, pName->a[0].zDatabase); sqlite3ForceNotReadOnly(pParse); } goto exit_drop_table; } iDb = sqlite3SchemaToIndex(db, pTab->pSchema); assert( iDb>=0 && iDb<db->nDb ); /* If pTab is a virtual table, call ViewGetColumnNames() to ensure ** it is initialized. |
︙ | ︙ | |||
2705 2706 2707 2708 2709 2710 2711 | goto exit_drop_table; } if( sqlite3AuthCheck(pParse, SQLITE_DELETE, pTab->zName, 0, zDb) ){ goto exit_drop_table; } } #endif | | < | | | | 3509 3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542 | goto exit_drop_table; } if( sqlite3AuthCheck(pParse, SQLITE_DELETE, pTab->zName, 0, zDb) ){ goto exit_drop_table; } } #endif if( tableMayNotBeDropped(db, pTab) ){ sqlite3ErrorMsg(pParse, "table %s may not be dropped", pTab->zName); goto exit_drop_table; } #ifndef SQLITE_OMIT_VIEW /* Ensure DROP TABLE is not used on a view, and DROP VIEW is not used ** on a table. */ if( isView && !IsView(pTab) ){ sqlite3ErrorMsg(pParse, "use DROP TABLE to delete table %s", pTab->zName); goto exit_drop_table; } if( !isView && IsView(pTab) ){ sqlite3ErrorMsg(pParse, "use DROP VIEW to delete view %s", pTab->zName); goto exit_drop_table; } #endif /* Generate code to remove the table from the schema table ** on disk. */ v = sqlite3GetVdbe(pParse); if( v ){ sqlite3BeginWriteOperation(pParse, 1, iDb); if( !isView ){ sqlite3ClearStatTables(pParse, iDb, "tbl", pTab->zName); |
︙ | ︙ | |||
2770 2771 2772 2773 2774 2775 2776 | int flags /* Conflict resolution algorithms. */ ){ sqlite3 *db = pParse->db; #ifndef SQLITE_OMIT_FOREIGN_KEY FKey *pFKey = 0; FKey *pNextTo; Table *p = pParse->pNewTable; | | | | > | | | | | | | | 3573 3574 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 | int flags /* Conflict resolution algorithms. */ ){ sqlite3 *db = pParse->db; #ifndef SQLITE_OMIT_FOREIGN_KEY FKey *pFKey = 0; FKey *pNextTo; Table *p = pParse->pNewTable; i64 nByte; int i; int nCol; char *z; assert( pTo!=0 ); if( p==0 || IN_DECLARE_VTAB ) goto fk_end; if( pFromCol==0 ){ int iCol = p->nCol-1; if( NEVER(iCol<0) ) goto fk_end; if( pToCol && pToCol->nExpr!=1 ){ sqlite3ErrorMsg(pParse, "foreign key on %s" " should reference only one column of table %T", p->aCol[iCol].zCnName, pTo); goto fk_end; } nCol = 1; }else if( pToCol && pToCol->nExpr!=pFromCol->nExpr ){ sqlite3ErrorMsg(pParse, "number of columns in foreign key does not match the number of " "columns in the referenced table"); goto fk_end; }else{ nCol = pFromCol->nExpr; } nByte = sizeof(*pFKey) + (nCol-1)*sizeof(pFKey->aCol[0]) + pTo->n + 1; if( pToCol ){ for(i=0; i<pToCol->nExpr; i++){ nByte += sqlite3Strlen30(pToCol->a[i].zEName) + 1; } } pFKey = sqlite3DbMallocZero(db, nByte ); if( pFKey==0 ){ goto fk_end; } pFKey->pFrom = p; assert( IsOrdinaryTable(p) ); pFKey->pNextFrom = p->u.tab.pFKey; z = (char*)&pFKey->aCol[nCol]; pFKey->zTo = z; if( IN_RENAME_OBJECT ){ sqlite3RenameTokenMap(pParse, (void*)z, pTo); } memcpy(z, pTo->z, pTo->n); z[pTo->n] = 0; sqlite3Dequote(z); z += pTo->n+1; pFKey->nCol = nCol; if( pFromCol==0 ){ pFKey->aCol[0].iFrom = p->nCol-1; }else{ for(i=0; i<nCol; i++){ int j; for(j=0; j<p->nCol; j++){ if( sqlite3StrICmp(p->aCol[j].zCnName, pFromCol->a[i].zEName)==0 ){ pFKey->aCol[i].iFrom = j; break; } } if( j>=p->nCol ){ sqlite3ErrorMsg(pParse, "unknown column \"%s\" in foreign key definition", pFromCol->a[i].zEName); goto fk_end; } if( IN_RENAME_OBJECT ){ sqlite3RenameTokenRemap(pParse, &pFKey->aCol[i], pFromCol->a[i].zEName); } } } if( pToCol ){ for(i=0; i<nCol; i++){ int n = sqlite3Strlen30(pToCol->a[i].zEName); pFKey->aCol[i].zCol = z; if( IN_RENAME_OBJECT ){ sqlite3RenameTokenRemap(pParse, z, pToCol->a[i].zEName); } memcpy(z, pToCol->a[i].zEName, n); z[n] = 0; z += n+1; } } pFKey->isDeferred = 0; pFKey->aAction[0] = (u8)(flags & 0xff); /* ON DELETE action */ pFKey->aAction[1] = (u8)((flags >> 8 ) & 0xff); /* ON UPDATE action */ |
︙ | ︙ | |||
2871 2872 2873 2874 2875 2876 2877 | assert( pNextTo->pPrevTo==0 ); pFKey->pNextTo = pNextTo; pNextTo->pPrevTo = pFKey; } /* Link the foreign key to the table as the last step. */ | > | | > > | 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 | assert( pNextTo->pPrevTo==0 ); pFKey->pNextTo = pNextTo; pNextTo->pPrevTo = pFKey; } /* Link the foreign key to the table as the last step. */ assert( IsOrdinaryTable(p) ); p->u.tab.pFKey = pFKey; pFKey = 0; fk_end: sqlite3DbFree(db, pFKey); #endif /* !defined(SQLITE_OMIT_FOREIGN_KEY) */ sqlite3ExprListDelete(db, pFromCol); sqlite3ExprListDelete(db, pToCol); } /* ** This routine is called when an INITIALLY IMMEDIATE or INITIALLY DEFERRED ** clause is seen as part of a foreign key definition. The isDeferred ** parameter is 1 for INITIALLY DEFERRED and 0 for INITIALLY IMMEDIATE. ** The behavior of the most recently created foreign key is adjusted ** accordingly. */ void sqlite3DeferForeignKey(Parse *pParse, int isDeferred){ #ifndef SQLITE_OMIT_FOREIGN_KEY Table *pTab; FKey *pFKey; if( (pTab = pParse->pNewTable)==0 ) return; if( NEVER(!IsOrdinaryTable(pTab)) ) return; if( (pFKey = pTab->u.tab.pFKey)==0 ) return; assert( isDeferred==0 || isDeferred==1 ); /* EV: R-30323-21917 */ pFKey->isDeferred = (u8)isDeferred; #endif } /* ** Generate code that will erase and refill index *pIdx. This is |
︙ | ︙ | |||
2916 2917 2918 2919 2920 2921 2922 | static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){ Table *pTab = pIndex->pTable; /* The table that is indexed */ int iTab = pParse->nTab++; /* Btree cursor used for pTab */ 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 */ | | | | 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 | static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){ Table *pTab = pIndex->pTable; /* The table that is indexed */ int iTab = pParse->nTab++; /* Btree cursor used for pTab */ 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 */ Pgno tnum; /* Root page of index */ int iPartIdxLabel; /* Jump to this label to skip a row */ Vdbe *v; /* Generate code into this virtual machine */ KeyInfo *pKey; /* KeyInfo for index */ int regRecord; /* Register holding assembled 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].zDbSName ) ){ return; } #endif /* Require a write-lock on the table to perform this operation */ sqlite3TableLock(pParse, iDb, pTab->tnum, 1, pTab->zName); v = sqlite3GetVdbe(pParse); if( v==0 ) return; if( memRootPage>=0 ){ tnum = (Pgno)memRootPage; }else{ tnum = pIndex->tnum; } pKey = sqlite3KeyInfoOfIndex(pParse, pIndex); assert( pKey!=0 || db->mallocFailed || pParse->nErr ); /* Open the sorter cursor if we are to use one. */ |
︙ | ︙ | |||
2962 2963 2964 2965 2966 2967 2968 | sqlite3GenerateIndexKey(pParse,pIndex,iTab,regRecord,0,&iPartIdxLabel,0,0); sqlite3VdbeAddOp2(v, OP_SorterInsert, iSorter, regRecord); sqlite3ResolvePartIdxLabel(pParse, iPartIdxLabel); sqlite3VdbeAddOp2(v, OP_Next, iTab, addr1+1); VdbeCoverage(v); sqlite3VdbeJumpHere(v, addr1); if( memRootPage<0 ) sqlite3VdbeAddOp2(v, OP_Clear, tnum, iDb); | | > > > > > > > > > > > > > > > > | > | 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 | sqlite3GenerateIndexKey(pParse,pIndex,iTab,regRecord,0,&iPartIdxLabel,0,0); sqlite3VdbeAddOp2(v, OP_SorterInsert, iSorter, regRecord); sqlite3ResolvePartIdxLabel(pParse, iPartIdxLabel); sqlite3VdbeAddOp2(v, OP_Next, iTab, addr1+1); VdbeCoverage(v); sqlite3VdbeJumpHere(v, addr1); if( memRootPage<0 ) sqlite3VdbeAddOp2(v, OP_Clear, tnum, iDb); sqlite3VdbeAddOp4(v, OP_OpenWrite, iIdx, (int)tnum, iDb, (char *)pKey, P4_KEYINFO); sqlite3VdbeChangeP5(v, OPFLAG_BULKCSR|((memRootPage>=0)?OPFLAG_P2ISREG:0)); addr1 = sqlite3VdbeAddOp2(v, OP_SorterSort, iSorter, 0); VdbeCoverage(v); if( IsUniqueIndex(pIndex) ){ int j2 = sqlite3VdbeGoto(v, 1); addr2 = sqlite3VdbeCurrentAddr(v); sqlite3VdbeVerifyAbortable(v, OE_Abort); sqlite3VdbeAddOp4Int(v, OP_SorterCompare, iSorter, j2, regRecord, pIndex->nKeyCol); VdbeCoverage(v); sqlite3UniqueConstraint(pParse, OE_Abort, pIndex); sqlite3VdbeJumpHere(v, j2); }else{ /* Most CREATE INDEX and REINDEX statements that are not UNIQUE can not ** abort. The exception is if one of the indexed expressions contains a ** user function that throws an exception when it is evaluated. But the ** overhead of adding a statement journal to a CREATE INDEX statement is ** very small (since most of the pages written do not contain content that ** needs to be restored if the statement aborts), so we call ** sqlite3MayAbort() for all CREATE INDEX statements. */ sqlite3MayAbort(pParse); addr2 = sqlite3VdbeCurrentAddr(v); } sqlite3VdbeAddOp3(v, OP_SorterData, iSorter, regRecord, iIdx); if( !pIndex->bAscKeyBug ){ /* This OP_SeekEnd opcode makes index insert for a REINDEX go much ** faster by avoiding unnecessary seeks. But the optimization does ** not work for UNIQUE constraint indexes on WITHOUT ROWID tables ** with DESC primary keys, since those indexes have there keys in ** a different order from the main table. ** See ticket: https://www.sqlite.org/src/info/bba7b69f9849b5bf */ sqlite3VdbeAddOp1(v, OP_SeekEnd, iIdx); } sqlite3VdbeAddOp2(v, OP_IdxInsert, iIdx, regRecord); sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT); sqlite3ReleaseTempReg(pParse, regRecord); sqlite3VdbeAddOp2(v, OP_SorterNext, iSorter, addr2); VdbeCoverage(v); sqlite3VdbeJumpHere(v, addr1); sqlite3VdbeAddOp1(v, OP_Close, iTab); |
︙ | ︙ | |||
3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 | p->aSortOrder = (u8*)pExtra; p->nColumn = nCol; p->nKeyCol = nCol - 1; *ppExtra = ((char*)p) + nByte; } return p; } /* ** Create a new index for an SQL table. pName1.pName2 is the name of the index ** and pTblList is the name of the table that is to be indexed. Both will ** be NULL for a primary key or an index that is created to satisfy a ** UNIQUE constraint. If pTable and pIndex are NULL, use pParse->pNewTable ** as the table to be indexed. pParse->pNewTable is a table that is | > > > > > > > > > > > > > > > > > > > > > | 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 3882 3883 | p->aSortOrder = (u8*)pExtra; p->nColumn = nCol; p->nKeyCol = nCol - 1; *ppExtra = ((char*)p) + nByte; } return p; } /* ** If expression list pList contains an expression that was parsed with ** an explicit "NULLS FIRST" or "NULLS LAST" clause, leave an error in ** pParse and return non-zero. Otherwise, return zero. */ int sqlite3HasExplicitNulls(Parse *pParse, ExprList *pList){ if( pList ){ int i; for(i=0; i<pList->nExpr; i++){ if( pList->a[i].bNulls ){ u8 sf = pList->a[i].sortFlags; sqlite3ErrorMsg(pParse, "unsupported use of NULLS %s", (sf==0 || sf==3) ? "FIRST" : "LAST" ); return 1; } } } return 0; } /* ** Create a new index for an SQL table. pName1.pName2 is the name of the index ** and pTblList is the name of the table that is to be indexed. Both will ** be NULL for a primary key or an index that is created to satisfy a ** UNIQUE constraint. If pTable and pIndex are NULL, use pParse->pNewTable ** as the table to be indexed. pParse->pNewTable is a table that is |
︙ | ︙ | |||
3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 | goto exit_create_index; } if( IN_DECLARE_VTAB && idxType!=SQLITE_IDXTYPE_PRIMARYKEY ){ goto exit_create_index; } if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){ goto exit_create_index; } /* ** Find the table that is to be indexed. Return early if not found. */ if( pTblName!=0 ){ | > > > | 3921 3922 3923 3924 3925 3926 3927 3928 3929 3930 3931 3932 3933 3934 3935 3936 3937 | goto exit_create_index; } if( IN_DECLARE_VTAB && idxType!=SQLITE_IDXTYPE_PRIMARYKEY ){ goto exit_create_index; } if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){ goto exit_create_index; } if( sqlite3HasExplicitNulls(pParse, pList) ){ goto exit_create_index; } /* ** Find the table that is to be indexed. Return early if not found. */ if( pTblName!=0 ){ |
︙ | ︙ | |||
3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 | } pDb = &db->aDb[iDb]; assert( pTab!=0 ); assert( pParse->nErr==0 ); if( sqlite3StrNICmp(pTab->zName, "sqlite_", 7)==0 && db->init.busy==0 #if SQLITE_USER_AUTHENTICATION && sqlite3UserAuthTable(pTab->zName)==0 #endif | > < < < < | | | | > | 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994 3995 3996 3997 3998 3999 4000 4001 4002 4003 4004 4005 4006 4007 4008 4009 4010 4011 4012 4013 4014 4015 4016 4017 4018 4019 4020 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 4034 4035 4036 4037 4038 4039 4040 4041 4042 4043 4044 4045 4046 4047 4048 4049 4050 | } pDb = &db->aDb[iDb]; assert( pTab!=0 ); assert( pParse->nErr==0 ); if( sqlite3StrNICmp(pTab->zName, "sqlite_", 7)==0 && db->init.busy==0 && pTblName!=0 #if SQLITE_USER_AUTHENTICATION && sqlite3UserAuthTable(pTab->zName)==0 #endif ){ sqlite3ErrorMsg(pParse, "table %s may not be indexed", pTab->zName); goto exit_create_index; } #ifndef SQLITE_OMIT_VIEW if( IsView(pTab) ){ sqlite3ErrorMsg(pParse, "views may not be indexed"); goto exit_create_index; } #endif #ifndef SQLITE_OMIT_VIRTUALTABLE if( IsVirtual(pTab) ){ sqlite3ErrorMsg(pParse, "virtual tables may not be indexed"); goto exit_create_index; } #endif /* ** Find the name of the index. Make sure there is not already another ** index or table with the same name. ** ** Exception: If we are reading the names of permanent indices from the ** sqlite_schema table (because some other process changed the schema) and ** one of the index names collides with the name of a temporary table or ** index, then we will continue to process this index. ** ** If pName==0 it means that we are ** dealing with a primary key or UNIQUE constraint. We have to invent our ** own name. */ if( pName ){ zName = sqlite3NameFromToken(db, pName); if( zName==0 ) goto exit_create_index; assert( pName->z!=0 ); if( SQLITE_OK!=sqlite3CheckObjectName(pParse, zName,"index",pTab->zName) ){ goto exit_create_index; } if( !IN_RENAME_OBJECT ){ if( !db->init.busy ){ if( sqlite3FindTable(db, zName, 0)!=0 ){ sqlite3ErrorMsg(pParse, "there is already a table named %s", zName); goto exit_create_index; } } if( sqlite3FindIndex(db, zName, pDb->zDbSName)!=0 ){ if( !ifNotExist ){ sqlite3ErrorMsg(pParse, "index %s already exists", zName); }else{ assert( !db->init.busy ); sqlite3CodeVerifySchema(pParse, iDb); sqlite3ForceNotReadOnly(pParse); } goto exit_create_index; } } }else{ int n; Index *pLoop; |
︙ | ︙ | |||
3236 3237 3238 3239 3240 3241 3242 | ** key out of the last column added to the table under construction. ** So create a fake list to simulate this. */ if( pList==0 ){ Token prevCol; Column *pCol = &pTab->aCol[pTab->nCol-1]; pCol->colFlags |= COLFLAG_UNIQUE; | | | > > > | 4082 4083 4084 4085 4086 4087 4088 4089 4090 4091 4092 4093 4094 4095 4096 4097 4098 4099 4100 4101 4102 4103 4104 4105 4106 4107 4108 4109 4110 4111 4112 4113 4114 4115 4116 4117 4118 4119 4120 4121 4122 4123 4124 | ** key out of the last column added to the table under construction. ** So create a fake list to simulate this. */ if( pList==0 ){ Token prevCol; Column *pCol = &pTab->aCol[pTab->nCol-1]; pCol->colFlags |= COLFLAG_UNIQUE; sqlite3TokenInit(&prevCol, pCol->zCnName); pList = sqlite3ExprListAppend(pParse, 0, sqlite3ExprAlloc(db, TK_ID, &prevCol, 0)); if( pList==0 ) goto exit_create_index; assert( pList->nExpr==1 ); sqlite3ExprListSetSortOrder(pList, sortOrder, SQLITE_SO_UNDEFINED); }else{ sqlite3ExprListCheckLength(pParse, pList, "index"); if( pParse->nErr ) goto exit_create_index; } /* Figure out how many bytes of space are required to store explicitly ** specified collation sequence names. */ for(i=0; i<pList->nExpr; i++){ Expr *pExpr = pList->a[i].pExpr; assert( pExpr!=0 ); if( pExpr->op==TK_COLLATE ){ assert( !ExprHasProperty(pExpr, EP_IntValue) ); nExtra += (1 + sqlite3Strlen30(pExpr->u.zToken)); } } /* ** Allocate the index structure. */ nName = sqlite3Strlen30(zName); nExtraCol = pPk ? pPk->nKeyCol : 1; assert( pList->nExpr + nExtraCol <= 32767 /* Fits in i16 */ ); pIndex = sqlite3AllocateIndexObject(db, pList->nExpr + nExtraCol, nName + nExtra + 1, &zExtra); if( db->mallocFailed ){ goto exit_create_index; } assert( EIGHT_BYTE_ALIGNMENT(pIndex->aiRowLogEst) ); assert( EIGHT_BYTE_ALIGNMENT(pIndex->azColl) ); |
︙ | ︙ | |||
3334 3335 3336 3337 3338 3339 3340 | pIndex->aiColumn[i] = XN_EXPR; pIndex->uniqNotNull = 0; }else{ j = pCExpr->iColumn; assert( j<=0x7fff ); if( j<0 ){ j = pTab->iPKey; | > | | > > > > > | | | > | | | 4183 4184 4185 4186 4187 4188 4189 4190 4191 4192 4193 4194 4195 4196 4197 4198 4199 4200 4201 4202 4203 4204 4205 4206 4207 4208 4209 4210 4211 4212 4213 4214 4215 4216 4217 4218 4219 4220 4221 4222 4223 4224 4225 4226 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 4258 4259 4260 4261 4262 4263 4264 4265 | pIndex->aiColumn[i] = XN_EXPR; pIndex->uniqNotNull = 0; }else{ j = pCExpr->iColumn; assert( j<=0x7fff ); if( j<0 ){ j = pTab->iPKey; }else{ if( pTab->aCol[j].notNull==0 ){ pIndex->uniqNotNull = 0; } if( pTab->aCol[j].colFlags & COLFLAG_VIRTUAL ){ pIndex->bHasVCol = 1; } } pIndex->aiColumn[i] = (i16)j; } zColl = 0; if( pListItem->pExpr->op==TK_COLLATE ){ int nColl; assert( !ExprHasProperty(pListItem->pExpr, EP_IntValue) ); zColl = pListItem->pExpr->u.zToken; nColl = sqlite3Strlen30(zColl) + 1; assert( nExtra>=nColl ); memcpy(zExtra, zColl, nColl); zColl = zExtra; zExtra += nColl; nExtra -= nColl; }else if( j>=0 ){ zColl = sqlite3ColumnColl(&pTab->aCol[j]); } if( !zColl ) zColl = sqlite3StrBINARY; if( !db->init.busy && !sqlite3LocateCollSeq(pParse, zColl) ){ goto exit_create_index; } pIndex->azColl[i] = zColl; requestedSortOrder = pListItem->sortFlags & sortOrderMask; pIndex->aSortOrder[i] = (u8)requestedSortOrder; } /* Append the table key to the end of the index. For WITHOUT ROWID ** tables (when pPk!=0) this will be the declared PRIMARY KEY. For ** normal tables (when pPk==0) this will be the rowid. */ if( pPk ){ for(j=0; j<pPk->nKeyCol; j++){ int x = pPk->aiColumn[j]; assert( x>=0 ); if( isDupColumn(pIndex, pIndex->nKeyCol, pPk, j) ){ pIndex->nColumn--; }else{ testcase( hasColumn(pIndex->aiColumn,pIndex->nKeyCol,x) ); pIndex->aiColumn[i] = x; pIndex->azColl[i] = pPk->azColl[j]; pIndex->aSortOrder[i] = pPk->aSortOrder[j]; i++; } } assert( i==pIndex->nColumn ); }else{ pIndex->aiColumn[i] = XN_ROWID; pIndex->azColl[i] = sqlite3StrBINARY; } sqlite3DefaultRowEst(pIndex); if( pParse->pNewTable==0 ) estimateIndexWidth(pIndex); /* If this index contains every column of its table, then mark ** it as a covering index */ assert( HasRowid(pTab) || pTab->iPKey<0 || sqlite3TableColumnToIndex(pIndex, pTab->iPKey)>=0 ); recomputeColumnsNotIndexed(pIndex); if( pTblName!=0 && pIndex->nColumn>=pTab->nCol ){ pIndex->isCovering = 1; for(j=0; j<pTab->nCol; j++){ if( j==pTab->iPKey ) continue; if( sqlite3TableColumnToIndex(pIndex,j)>=0 ) continue; pIndex->isCovering = 0; break; } } if( pTab==pParse->pNewTable ){ /* This routine has been called to create an automatic index as a |
︙ | ︙ | |||
3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 | "conflicting ON CONFLICT clauses specified", 0); } if( pIdx->onError==OE_Default ){ pIdx->onError = pIndex->onError; } } if( idxType==SQLITE_IDXTYPE_PRIMARYKEY ) pIdx->idxType = idxType; goto exit_create_index; } } } if( !IN_RENAME_OBJECT ){ /* Link the new Index structure to its table and to the other ** in-memory database structures. */ assert( pParse->nErr==0 ); if( db->init.busy ){ Index *p; assert( !IN_SPECIAL_PARSE ); assert( sqlite3SchemaMutexHeld(db, 0, pIndex->pSchema) ); p = sqlite3HashInsert(&pIndex->pSchema->idxHash, pIndex->zName, pIndex); if( p ){ assert( p==pIndex ); /* Malloc must have failed */ sqlite3OomFault(db); goto exit_create_index; } db->mDbFlags |= DBFLAG_SchemaChange; | > > > > > > > > > > > > > < < < | | | 4314 4315 4316 4317 4318 4319 4320 4321 4322 4323 4324 4325 4326 4327 4328 4329 4330 4331 4332 4333 4334 4335 4336 4337 4338 4339 4340 4341 4342 4343 4344 4345 4346 4347 4348 4349 4350 4351 4352 4353 4354 4355 4356 4357 4358 4359 4360 4361 4362 4363 4364 4365 4366 4367 4368 4369 4370 | "conflicting ON CONFLICT clauses specified", 0); } if( pIdx->onError==OE_Default ){ pIdx->onError = pIndex->onError; } } if( idxType==SQLITE_IDXTYPE_PRIMARYKEY ) pIdx->idxType = idxType; if( IN_RENAME_OBJECT ){ pIndex->pNext = pParse->pNewIndex; pParse->pNewIndex = pIndex; pIndex = 0; } goto exit_create_index; } } } if( !IN_RENAME_OBJECT ){ /* Link the new Index structure to its table and to the other ** in-memory database structures. */ assert( pParse->nErr==0 ); if( db->init.busy ){ Index *p; assert( !IN_SPECIAL_PARSE ); assert( sqlite3SchemaMutexHeld(db, 0, pIndex->pSchema) ); if( pTblName!=0 ){ pIndex->tnum = db->init.newTnum; if( sqlite3IndexHasDuplicateRootPage(pIndex) ){ sqlite3ErrorMsg(pParse, "invalid rootpage"); pParse->rc = SQLITE_CORRUPT_BKPT; goto exit_create_index; } } p = sqlite3HashInsert(&pIndex->pSchema->idxHash, pIndex->zName, pIndex); if( p ){ assert( p==pIndex ); /* Malloc must have failed */ sqlite3OomFault(db); goto exit_create_index; } db->mDbFlags |= DBFLAG_SchemaChange; } /* If this is the initial CREATE INDEX statement (or CREATE TABLE if the ** index is an implied index for a UNIQUE or PRIMARY KEY constraint) then ** emit code to allocate the index rootpage on disk and make an entry for ** the index in the sqlite_schema table and populate the index with ** content. But, do not do this if we are simply reading the sqlite_schema ** table to parse the schema, or if this index is the PRIMARY KEY index ** of a WITHOUT ROWID table. ** ** If pTblName==0 it means this index is generated as an implied PRIMARY KEY ** or UNIQUE index in a CREATE TABLE statement. Since the table ** has just been created, it contains no data and the index initialization ** step can be skipped. |
︙ | ︙ | |||
3515 3516 3517 3518 3519 3520 3521 | /* Create the rootpage for the index using CreateIndex. But before ** doing so, code a Noop instruction and store its address in ** Index.tnum. This is required in case this index is actually a ** PRIMARY KEY and the table is actually a WITHOUT ROWID table. In ** that case the convertToWithoutRowidTable() routine will replace ** the Noop with a Goto to jump over the VDBE code generated below. */ | | > | | | | | < < < < < < < < < | | < < < < < < < < > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 4381 4382 4383 4384 4385 4386 4387 4388 4389 4390 4391 4392 4393 4394 4395 4396 4397 4398 4399 4400 4401 4402 4403 4404 4405 4406 4407 4408 4409 4410 4411 4412 4413 4414 4415 4416 4417 4418 4419 4420 4421 4422 4423 4424 4425 4426 4427 4428 4429 4430 4431 4432 4433 4434 4435 4436 4437 4438 4439 4440 4441 4442 4443 4444 4445 4446 4447 4448 4449 4450 4451 4452 4453 4454 4455 4456 4457 4458 4459 4460 4461 4462 4463 4464 4465 4466 4467 4468 4469 4470 4471 4472 4473 4474 4475 4476 4477 4478 4479 4480 4481 4482 | /* Create the rootpage for the index using CreateIndex. But before ** doing so, code a Noop instruction and store its address in ** Index.tnum. This is required in case this index is actually a ** PRIMARY KEY and the table is actually a WITHOUT ROWID table. In ** that case the convertToWithoutRowidTable() routine will replace ** the Noop with a Goto to jump over the VDBE code generated below. */ pIndex->tnum = (Pgno)sqlite3VdbeAddOp0(v, OP_Noop); sqlite3VdbeAddOp3(v, OP_CreateBtree, iDb, iMem, BTREE_BLOBKEY); /* Gather the complete text of the CREATE INDEX statement into ** the zStmt variable */ assert( pName!=0 || pStart==0 ); if( pStart ){ int n = (int)(pParse->sLastToken.z - pName->z) + pParse->sLastToken.n; if( pName->z[n-1]==';' ) n--; /* A named index with an explicit CREATE INDEX statement */ zStmt = sqlite3MPrintf(db, "CREATE%s INDEX %.*s", onError==OE_None ? "" : " UNIQUE", n, pName->z); }else{ /* An automatic index created by a PRIMARY KEY or UNIQUE constraint */ /* zStmt = sqlite3MPrintf(""); */ zStmt = 0; } /* Add an entry in sqlite_schema for this index */ sqlite3NestedParse(pParse, "INSERT INTO %Q." LEGACY_SCHEMA_TABLE " VALUES('index',%Q,%Q,#%d,%Q);", db->aDb[iDb].zDbSName, pIndex->zName, pTab->zName, iMem, zStmt ); sqlite3DbFree(db, zStmt); /* Fill the index with data and reparse the schema. Code an OP_Expire ** to invalidate all pre-compiled statements. */ if( pTblName ){ sqlite3RefillIndex(pParse, pIndex, iMem); sqlite3ChangeCookie(pParse, iDb); sqlite3VdbeAddParseSchemaOp(v, iDb, sqlite3MPrintf(db, "name='%q' AND type='index'", pIndex->zName), 0); sqlite3VdbeAddOp2(v, OP_Expire, 0, 1); } sqlite3VdbeJumpHere(v, (int)pIndex->tnum); } } if( db->init.busy || pTblName==0 ){ pIndex->pNext = pTab->pIndex; pTab->pIndex = pIndex; pIndex = 0; } else if( IN_RENAME_OBJECT ){ assert( pParse->pNewIndex==0 ); pParse->pNewIndex = pIndex; pIndex = 0; } /* Clean up before exiting */ exit_create_index: if( pIndex ) sqlite3FreeIndex(db, pIndex); if( pTab ){ /* Ensure all REPLACE indexes on pTab are at the end of the pIndex list. ** The list was already ordered when this routine was entered, so at this ** point at most a single index (the newly added index) will be out of ** order. So we have to reorder at most one index. */ Index **ppFrom; Index *pThis; for(ppFrom=&pTab->pIndex; (pThis = *ppFrom)!=0; ppFrom=&pThis->pNext){ Index *pNext; if( pThis->onError!=OE_Replace ) continue; while( (pNext = pThis->pNext)!=0 && pNext->onError!=OE_Replace ){ *ppFrom = pNext; pThis->pNext = pNext->pNext; pNext->pNext = pThis; ppFrom = &pNext->pNext; } break; } #ifdef SQLITE_DEBUG /* Verify that all REPLACE indexes really are now at the end ** of the index list. In other words, no other index type ever ** comes after a REPLACE index on the list. */ for(pThis = pTab->pIndex; pThis; pThis=pThis->pNext){ assert( pThis->onError!=OE_Replace || pThis->pNext==0 || pThis->pNext->onError==OE_Replace ); } #endif } sqlite3ExprDelete(db, pPIWhere); sqlite3ExprListDelete(db, pList); sqlite3SrcListDelete(db, pTblName); sqlite3DbFree(db, zName); } /* |
︙ | ︙ | |||
3615 3616 3617 3618 3619 3620 3621 | ** aiRowEst[N]>=1 ** ** Apart from that, we have little to go on besides intuition as to ** how aiRowEst[] should be initialized. The numbers generated here ** are based on typical values found in actual indices. */ void sqlite3DefaultRowEst(Index *pIdx){ | | | > | > > > > > > > | > > > > | | | 4494 4495 4496 4497 4498 4499 4500 4501 4502 4503 4504 4505 4506 4507 4508 4509 4510 4511 4512 4513 4514 4515 4516 4517 4518 4519 4520 4521 4522 4523 4524 4525 4526 4527 4528 4529 4530 4531 4532 4533 4534 | ** aiRowEst[N]>=1 ** ** Apart from that, we have little to go on besides intuition as to ** how aiRowEst[] should be initialized. The numbers generated here ** are based on typical values found in actual indices. */ void sqlite3DefaultRowEst(Index *pIdx){ /* 10, 9, 8, 7, 6 */ static const LogEst aVal[] = { 33, 32, 30, 28, 26 }; LogEst *a = pIdx->aiRowLogEst; LogEst x; int nCopy = MIN(ArraySize(aVal), pIdx->nKeyCol); int i; /* Indexes with default row estimates should not have stat1 data */ assert( !pIdx->hasStat1 ); /* Set the first entry (number of rows in the index) to the estimated ** number of rows in the table, or half the number of rows in the table ** for a partial index. ** ** 2020-05-27: If some of the stat data is coming from the sqlite_stat1 ** table but other parts we are having to guess at, then do not let the ** estimated number of rows in the table be less than 1000 (LogEst 99). ** Failure to do this can cause the indexes for which we do not have ** stat1 data to be ignored by the query planner. */ x = pIdx->pTable->nRowLogEst; assert( 99==sqlite3LogEst(1000) ); if( x<99 ){ pIdx->pTable->nRowLogEst = x = 99; } if( pIdx->pPartIdxWhere!=0 ){ x -= 10; assert( 10==sqlite3LogEst(2) ); } a[0] = x; /* Estimate that a[1] is 10, a[2] is 9, a[3] is 8, a[4] is 7, a[5] is ** 6 and each subsequent value (if any) is 5. */ memcpy(&a[1], aVal, nCopy*sizeof(LogEst)); for(i=nCopy+1; i<=pIdx->nKeyCol; i++){ a[i] = 23; assert( 23==sqlite3LogEst(5) ); } |
︙ | ︙ | |||
3663 3664 3665 3666 3667 3668 3669 | assert( pName->nSrc==1 ); if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){ goto exit_drop_index; } pIndex = sqlite3FindIndex(db, pName->a[0].zName, pName->a[0].zDatabase); if( pIndex==0 ){ if( !ifExists ){ | | > | | | | | 4554 4555 4556 4557 4558 4559 4560 4561 4562 4563 4564 4565 4566 4567 4568 4569 4570 4571 4572 4573 4574 4575 4576 4577 4578 4579 4580 4581 4582 4583 4584 4585 4586 4587 4588 4589 4590 4591 4592 4593 4594 4595 4596 4597 4598 4599 4600 4601 4602 4603 4604 | assert( pName->nSrc==1 ); if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){ goto exit_drop_index; } pIndex = sqlite3FindIndex(db, pName->a[0].zName, pName->a[0].zDatabase); if( pIndex==0 ){ if( !ifExists ){ sqlite3ErrorMsg(pParse, "no such index: %S", pName->a); }else{ sqlite3CodeVerifyNamedSchema(pParse, pName->a[0].zDatabase); sqlite3ForceNotReadOnly(pParse); } pParse->checkSchema = 1; goto exit_drop_index; } if( pIndex->idxType!=SQLITE_IDXTYPE_APPDEF ){ sqlite3ErrorMsg(pParse, "index associated with UNIQUE " "or PRIMARY KEY constraint cannot be dropped", 0); goto exit_drop_index; } iDb = sqlite3SchemaToIndex(db, pIndex->pSchema); #ifndef SQLITE_OMIT_AUTHORIZATION { int code = SQLITE_DROP_INDEX; Table *pTab = pIndex->pTable; const char *zDb = db->aDb[iDb].zDbSName; const char *zTab = SCHEMA_TABLE(iDb); if( sqlite3AuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb) ){ goto exit_drop_index; } if( !OMIT_TEMPDB && iDb==1 ) code = SQLITE_DROP_TEMP_INDEX; if( sqlite3AuthCheck(pParse, code, pIndex->zName, pTab->zName, zDb) ){ goto exit_drop_index; } } #endif /* Generate code to remove the index and from the schema table */ v = sqlite3GetVdbe(pParse); if( v ){ sqlite3BeginWriteOperation(pParse, 1, iDb); sqlite3NestedParse(pParse, "DELETE FROM %Q." LEGACY_SCHEMA_TABLE " WHERE name=%Q AND type='index'", db->aDb[iDb].zDbSName, pIndex->zName ); sqlite3ClearStatTables(pParse, iDb, "idx", pIndex->zName); sqlite3ChangeCookie(pParse, iDb); destroyRootPage(pParse, pIndex->tnum, iDb); sqlite3VdbeAddOp4(v, OP_DropIndex, iDb, 0, 0, pIndex->zName, 0); } |
︙ | ︙ | |||
3735 3736 3737 3738 3739 3740 3741 | sqlite3 *db, /* Connection to notify of malloc failures */ void *pArray, /* Array of objects. Might be reallocated */ int szEntry, /* Size of each object in the array */ int *pnEntry, /* Number of objects currently in use */ int *pIdx /* Write the index of a new slot here */ ){ char *z; | | | < | 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 | sqlite3 *db, /* Connection to notify of malloc failures */ void *pArray, /* Array of objects. Might be reallocated */ int szEntry, /* Size of each object in the array */ int *pnEntry, /* Number of objects currently in use */ int *pIdx /* Write the index of a new slot here */ ){ char *z; sqlite3_int64 n = *pIdx = *pnEntry; if( (n & (n-1))==0 ){ sqlite3_int64 sz = (n==0) ? 1 : 2*n; void *pNew = sqlite3DbRealloc(db, pArray, sz*szEntry); if( pNew==0 ){ *pIdx = -1; return pArray; } pArray = pNew; } z = (char*)pArray; memset(&z[n * szEntry], 0, szEntry); ++*pnEntry; return pArray; } /* ** Append a new element to the given IdList. Create a new IdList if ** need be. |
︙ | ︙ | |||
3809 3810 3811 3812 3813 3814 3815 3816 3817 3818 3819 3820 3821 3822 3823 3824 3825 3826 3827 3828 3829 3830 3831 | if( pList==0 ) return -1; for(i=0; i<pList->nId; i++){ if( sqlite3StrICmp(pList->a[i].zName, zName)==0 ) return i; } return -1; } /* ** Expand the space allocated for the given SrcList object by ** creating nExtra new slots beginning at iStart. iStart is zero based. ** New slots are zeroed. ** ** For example, suppose a SrcList initially contains two entries: A,B. ** To append 3 new entries onto the end, do this: ** ** sqlite3SrcListEnlarge(db, pSrclist, 3, 2); ** ** After the call above it would contain: A, B, nil, nil, nil. ** If the iStart argument had been 1 instead of 2, then the result ** would have been: A, nil, nil, nil, B. To prepend the new slots, ** the iStart value would be 0. The result then would ** be: nil, nil, nil, A, B. ** | > > > > > > > > > > > > | > | < > | > | > > > > > > | < | | 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 | if( pList==0 ) return -1; for(i=0; i<pList->nId; i++){ if( sqlite3StrICmp(pList->a[i].zName, zName)==0 ) return i; } return -1; } /* ** Maximum size of a SrcList object. ** The SrcList object is used to represent the FROM clause of a ** SELECT statement, and the query planner cannot deal with more ** than 64 tables in a join. So any value larger than 64 here ** is sufficient for most uses. Smaller values, like say 10, are ** appropriate for small and memory-limited applications. */ #ifndef SQLITE_MAX_SRCLIST # define SQLITE_MAX_SRCLIST 200 #endif /* ** Expand the space allocated for the given SrcList object by ** creating nExtra new slots beginning at iStart. iStart is zero based. ** New slots are zeroed. ** ** For example, suppose a SrcList initially contains two entries: A,B. ** To append 3 new entries onto the end, do this: ** ** sqlite3SrcListEnlarge(db, pSrclist, 3, 2); ** ** After the call above it would contain: A, B, nil, nil, nil. ** If the iStart argument had been 1 instead of 2, then the result ** would have been: A, nil, nil, nil, B. To prepend the new slots, ** the iStart value would be 0. The result then would ** be: nil, nil, nil, A, B. ** ** If a memory allocation fails or the SrcList becomes too large, leave ** the original SrcList unchanged, return NULL, and leave an error message ** in pParse. */ SrcList *sqlite3SrcListEnlarge( Parse *pParse, /* Parsing context into which errors are reported */ SrcList *pSrc, /* The SrcList to be enlarged */ int nExtra, /* Number of new slots to add to pSrc->a[] */ int iStart /* Index in pSrc->a[] of first new slot */ ){ int i; /* Sanity checking on calling parameters */ assert( iStart>=0 ); assert( nExtra>=1 ); assert( pSrc!=0 ); assert( iStart<=pSrc->nSrc ); /* Allocate additional space if needed */ if( (u32)pSrc->nSrc+nExtra>pSrc->nAlloc ){ SrcList *pNew; sqlite3_int64 nAlloc = 2*(sqlite3_int64)pSrc->nSrc+nExtra; sqlite3 *db = pParse->db; if( pSrc->nSrc+nExtra>=SQLITE_MAX_SRCLIST ){ sqlite3ErrorMsg(pParse, "too many FROM clause terms, max: %d", SQLITE_MAX_SRCLIST); return 0; } if( nAlloc>SQLITE_MAX_SRCLIST ) nAlloc = SQLITE_MAX_SRCLIST; pNew = sqlite3DbRealloc(db, pSrc, sizeof(*pSrc) + (nAlloc-1)*sizeof(pSrc->a[0]) ); if( pNew==0 ){ assert( db->mallocFailed ); return 0; } pSrc = pNew; pSrc->nAlloc = nAlloc; } /* Move existing slots that come after the newly inserted slots ** out of the way */ for(i=pSrc->nSrc-1; i>=iStart; i--){ pSrc->a[i+nExtra] = pSrc->a[i]; } |
︙ | ︙ | |||
3880 3881 3882 3883 3884 3885 3886 | } /* ** Append a new table name to the given SrcList. Create a new SrcList if ** need be. A new entry is created in the SrcList even if pTable is NULL. ** | | > | 4790 4791 4792 4793 4794 4795 4796 4797 4798 4799 4800 4801 4802 4803 4804 4805 | } /* ** Append a new table name to the given SrcList. Create a new SrcList if ** need be. A new entry is created in the SrcList even if pTable is NULL. ** ** A SrcList is returned, or NULL if there is an OOM error or if the ** SrcList grows to large. The returned ** SrcList might be the same as the SrcList that was input or it might be ** a new one. If an OOM error does occurs, then the prior value of pList ** that is input to this routine is automatically freed. ** ** If pDatabase is not null, it means that the table has an optional ** database name prefix. Like this: "database.table". The pDatabase ** points to the table name and the pTable points to the database name. |
︙ | ︙ | |||
3911 3912 3913 3914 3915 3916 3917 | ** ** sqlite3SrcListAppend(D,A,0,C); ** ** Both pTable and pDatabase are assumed to be quoted. They are dequoted ** before being added to the SrcList. */ SrcList *sqlite3SrcListAppend( | | | > | > > | | < | | | > > > | | | | | | | | | | | 4822 4823 4824 4825 4826 4827 4828 4829 4830 4831 4832 4833 4834 4835 4836 4837 4838 4839 4840 4841 4842 4843 4844 4845 4846 4847 4848 4849 4850 4851 4852 4853 4854 4855 4856 4857 4858 4859 4860 4861 4862 4863 4864 4865 4866 4867 4868 4869 4870 4871 4872 4873 4874 4875 4876 4877 4878 4879 4880 4881 4882 4883 4884 4885 4886 4887 4888 4889 4890 4891 4892 4893 4894 4895 4896 4897 4898 4899 4900 4901 4902 4903 4904 4905 4906 4907 4908 4909 4910 4911 | ** ** sqlite3SrcListAppend(D,A,0,C); ** ** Both pTable and pDatabase are assumed to be quoted. They are dequoted ** before being added to the SrcList. */ SrcList *sqlite3SrcListAppend( Parse *pParse, /* Parsing context, in which errors are reported */ SrcList *pList, /* Append to this SrcList. NULL creates a new SrcList */ Token *pTable, /* Table to append */ Token *pDatabase /* Database of the table */ ){ SrcItem *pItem; sqlite3 *db; assert( pDatabase==0 || pTable!=0 ); /* Cannot have C without B */ assert( pParse!=0 ); assert( pParse->db!=0 ); db = pParse->db; if( pList==0 ){ pList = sqlite3DbMallocRawNN(pParse->db, sizeof(SrcList) ); if( pList==0 ) return 0; pList->nAlloc = 1; pList->nSrc = 1; memset(&pList->a[0], 0, sizeof(pList->a[0])); pList->a[0].iCursor = -1; }else{ SrcList *pNew = sqlite3SrcListEnlarge(pParse, pList, 1, pList->nSrc); if( pNew==0 ){ sqlite3SrcListDelete(db, pList); return 0; }else{ pList = pNew; } } pItem = &pList->a[pList->nSrc-1]; if( pDatabase && pDatabase->z==0 ){ pDatabase = 0; } if( pDatabase ){ pItem->zName = sqlite3NameFromToken(db, pDatabase); pItem->zDatabase = sqlite3NameFromToken(db, pTable); }else{ pItem->zName = sqlite3NameFromToken(db, pTable); pItem->zDatabase = 0; } return pList; } /* ** Assign VdbeCursor index numbers to all tables in a SrcList */ void sqlite3SrcListAssignCursors(Parse *pParse, SrcList *pList){ int i; SrcItem *pItem; assert( pList || pParse->db->mallocFailed ); if( ALWAYS(pList) ){ for(i=0, pItem=pList->a; i<pList->nSrc; i++, pItem++){ if( pItem->iCursor>=0 ) continue; pItem->iCursor = pParse->nTab++; if( pItem->pSelect ){ sqlite3SrcListAssignCursors(pParse, pItem->pSelect->pSrc); } } } } /* ** Delete an entire SrcList including all its substructure. */ void sqlite3SrcListDelete(sqlite3 *db, SrcList *pList){ int i; SrcItem *pItem; if( pList==0 ) return; for(pItem=pList->a, i=0; i<pList->nSrc; i++, pItem++){ if( pItem->zDatabase ) sqlite3DbFreeNN(db, pItem->zDatabase); sqlite3DbFree(db, pItem->zName); if( pItem->zAlias ) sqlite3DbFreeNN(db, pItem->zAlias); if( pItem->fg.isIndexedBy ) sqlite3DbFree(db, pItem->u1.zIndexedBy); if( pItem->fg.isTabFunc ) sqlite3ExprListDelete(db, pItem->u1.pFuncArg); sqlite3DeleteTable(db, pItem->pTab); if( pItem->pSelect ) sqlite3SelectDelete(db, pItem->pSelect); if( pItem->pOn ) sqlite3ExprDelete(db, pItem->pOn); if( pItem->pUsing ) sqlite3IdListDelete(db, pItem->pUsing); } sqlite3DbFreeNN(db, pList); } /* ** This routine is called by the parser to add a new term to the ** end of a growing FROM clause. The "p" parameter is the part of |
︙ | ︙ | |||
4012 4013 4014 4015 4016 4017 4018 | Token *pTable, /* Name of the table to add to the FROM clause */ Token *pDatabase, /* Name of the database containing pTable */ Token *pAlias, /* The right-hand side of the AS subexpression */ Select *pSubquery, /* A subquery used in place of a table name */ Expr *pOn, /* The ON clause of a join */ IdList *pUsing /* The USING clause of a join */ ){ | | | | 4928 4929 4930 4931 4932 4933 4934 4935 4936 4937 4938 4939 4940 4941 4942 4943 4944 4945 4946 4947 4948 4949 4950 | Token *pTable, /* Name of the table to add to the FROM clause */ Token *pDatabase, /* Name of the database containing pTable */ Token *pAlias, /* The right-hand side of the AS subexpression */ Select *pSubquery, /* A subquery used in place of a table name */ Expr *pOn, /* The ON clause of a join */ IdList *pUsing /* The USING clause of a join */ ){ SrcItem *pItem; sqlite3 *db = pParse->db; if( !p && (pOn || pUsing) ){ sqlite3ErrorMsg(pParse, "a JOIN clause is required before %s", (pOn ? "ON" : "USING") ); goto append_from_error; } p = sqlite3SrcListAppend(pParse, p, pTable, pDatabase); if( p==0 ){ goto append_from_error; } assert( p->nSrc>0 ); pItem = &p->a[p->nSrc-1]; assert( (pTable==0)==(pDatabase==0) ); assert( pItem->zName==0 || pDatabase!=0 ); |
︙ | ︙ | |||
4056 4057 4058 4059 4060 4061 4062 | /* ** Add an INDEXED BY or NOT INDEXED clause to the most recently added ** element of the source-list passed as the second argument. */ void sqlite3SrcListIndexedBy(Parse *pParse, SrcList *p, Token *pIndexedBy){ assert( pIndexedBy!=0 ); if( p && pIndexedBy->n>0 ){ | | > > > > > > > > > > > > > > > > > > > > > | | 4972 4973 4974 4975 4976 4977 4978 4979 4980 4981 4982 4983 4984 4985 4986 4987 4988 4989 4990 4991 4992 4993 4994 4995 4996 4997 4998 4999 5000 5001 5002 5003 5004 5005 5006 5007 5008 5009 5010 5011 5012 5013 5014 5015 5016 5017 5018 5019 5020 5021 5022 5023 5024 5025 5026 5027 5028 5029 5030 | /* ** Add an INDEXED BY or NOT INDEXED clause to the most recently added ** element of the source-list passed as the second argument. */ void sqlite3SrcListIndexedBy(Parse *pParse, SrcList *p, Token *pIndexedBy){ assert( pIndexedBy!=0 ); if( p && pIndexedBy->n>0 ){ SrcItem *pItem; assert( p->nSrc>0 ); pItem = &p->a[p->nSrc-1]; assert( pItem->fg.notIndexed==0 ); assert( pItem->fg.isIndexedBy==0 ); assert( pItem->fg.isTabFunc==0 ); if( pIndexedBy->n==1 && !pIndexedBy->z ){ /* A "NOT INDEXED" clause was supplied. See parse.y ** construct "indexed_opt" for details. */ pItem->fg.notIndexed = 1; }else{ pItem->u1.zIndexedBy = sqlite3NameFromToken(pParse->db, pIndexedBy); pItem->fg.isIndexedBy = 1; assert( pItem->fg.isCte==0 ); /* No collision on union u2 */ } } } /* ** Append the contents of SrcList p2 to SrcList p1 and return the resulting ** SrcList. Or, if an error occurs, return NULL. In all cases, p1 and p2 ** are deleted by this function. */ SrcList *sqlite3SrcListAppendList(Parse *pParse, SrcList *p1, SrcList *p2){ assert( p1 && p1->nSrc==1 ); if( p2 ){ SrcList *pNew = sqlite3SrcListEnlarge(pParse, p1, p2->nSrc, 1); if( pNew==0 ){ sqlite3SrcListDelete(pParse->db, p2); }else{ p1 = pNew; memcpy(&p1->a[1], p2->a, p2->nSrc*sizeof(SrcItem)); sqlite3DbFree(pParse->db, p2); } } return p1; } /* ** Add the list of function arguments to the SrcList entry for a ** table-valued-function. */ void sqlite3SrcListFuncArgs(Parse *pParse, SrcList *p, ExprList *pList){ if( p ){ SrcItem *pItem = &p->a[p->nSrc-1]; assert( pItem->fg.notIndexed==0 ); assert( pItem->fg.isIndexedBy==0 ); assert( pItem->fg.isTabFunc==0 ); pItem->u1.pFuncArg = pList; pItem->fg.isTabFunc = 1; }else{ sqlite3ExprListDelete(pParse->db, pList); |
︙ | ︙ | |||
4133 4134 4135 4136 4137 4138 4139 | if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION, "BEGIN", 0, 0) ){ return; } v = sqlite3GetVdbe(pParse); if( !v ) return; if( type==TK_IMMEDIATE || type==TK_EXCLUSIVE ){ for(i=0; i<db->nDb; i++){ | > > > > > > > > > | | 5070 5071 5072 5073 5074 5075 5076 5077 5078 5079 5080 5081 5082 5083 5084 5085 5086 5087 5088 5089 5090 5091 5092 5093 | if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION, "BEGIN", 0, 0) ){ return; } v = sqlite3GetVdbe(pParse); if( !v ) return; if( type==TK_IMMEDIATE || type==TK_EXCLUSIVE ){ for(i=0; i<db->nDb; i++){ int eTxnType; Btree *pBt = db->aDb[i].pBt; if( pBt && sqlite3BtreeIsReadonly(pBt) ){ eTxnType = 0; /* Read txn */ }else if( type==TK_EXCLUSIVE ){ eTxnType = 2; /* Exclusive txn */ }else{ eTxnType = 1; /* Write txn */ } sqlite3VdbeAddOp2(v, OP_Transaction, i, eTxnType); sqlite3VdbeUsesBtree(v, i); } } sqlite3VdbeAddOp3(v, OP_AutoCommit, 0, 0, (type==TK_CONCURRENT)); } /* |
︙ | ︙ | |||
4208 4209 4210 4211 4212 4213 4214 | sqlite3ErrorMsg(pParse, "unable to open a temporary database " "file for storing temporary tables"); pParse->rc = rc; return 1; } db->aDb[1].pBt = pBt; assert( db->aDb[1].pSchema ); | | | < < | | | | > > > > | 5154 5155 5156 5157 5158 5159 5160 5161 5162 5163 5164 5165 5166 5167 5168 5169 5170 5171 5172 5173 5174 5175 5176 5177 5178 5179 5180 5181 5182 5183 5184 5185 5186 5187 5188 5189 5190 5191 5192 5193 5194 5195 5196 5197 | sqlite3ErrorMsg(pParse, "unable to open a temporary database " "file for storing temporary tables"); pParse->rc = rc; return 1; } db->aDb[1].pBt = pBt; assert( db->aDb[1].pSchema ); if( SQLITE_NOMEM==sqlite3BtreeSetPageSize(pBt, db->nextPagesize, 0, 0) ){ sqlite3OomFault(db); return 1; } } return 0; } /* ** Record the fact that the schema cookie will need to be verified ** for database iDb. The code to actually verify the schema cookie ** will occur at the end of the top-level VDBE and will be generated ** later, by sqlite3FinishCoding(). */ static void sqlite3CodeVerifySchemaAtToplevel(Parse *pToplevel, int iDb){ assert( iDb>=0 && iDb<pToplevel->db->nDb ); assert( pToplevel->db->aDb[iDb].pBt!=0 || iDb==1 ); assert( iDb<SQLITE_MAX_DB ); assert( sqlite3SchemaMutexHeld(pToplevel->db, iDb, 0) ); if( DbMaskTest(pToplevel->cookieMask, iDb)==0 ){ DbMaskSet(pToplevel->cookieMask, iDb); if( !OMIT_TEMPDB && iDb==1 ){ sqlite3OpenTempDatabase(pToplevel); } } } void sqlite3CodeVerifySchema(Parse *pParse, int iDb){ sqlite3CodeVerifySchemaAtToplevel(sqlite3ParseToplevel(pParse), iDb); } /* ** If argument zDb is NULL, then call sqlite3CodeVerifySchema() for each ** attached database. Otherwise, invoke it for the database named zDb only. */ void sqlite3CodeVerifyNamedSchema(Parse *pParse, const char *zDb){ sqlite3 *db = pParse->db; |
︙ | ︙ | |||
4267 4268 4269 4270 4271 4272 4273 | ** the way through and which will need to undo some writes without having to ** rollback the whole transaction. For operations where all constraints ** can be checked before any changes are made to the database, it is never ** necessary to undo a write and the checkpoint should not be set. */ void sqlite3BeginWriteOperation(Parse *pParse, int setStatement, int iDb){ Parse *pToplevel = sqlite3ParseToplevel(pParse); | | | 5215 5216 5217 5218 5219 5220 5221 5222 5223 5224 5225 5226 5227 5228 5229 | ** the way through and which will need to undo some writes without having to ** rollback the whole transaction. For operations where all constraints ** can be checked before any changes are made to the database, it is never ** necessary to undo a write and the checkpoint should not be set. */ void sqlite3BeginWriteOperation(Parse *pParse, int setStatement, int iDb){ Parse *pToplevel = sqlite3ParseToplevel(pParse); sqlite3CodeVerifySchemaAtToplevel(pToplevel, iDb); DbMaskSet(pToplevel->writeMask, iDb); pToplevel->isMultiWrite |= setStatement; } /* ** Indicate that the statement currently under construction might write ** more than one entry (example: deleting one row then inserting another, |
︙ | ︙ | |||
4318 4319 4320 4321 4322 4323 4324 | Parse *pParse, /* Parsing context */ int errCode, /* extended error code */ int onError, /* Constraint type */ char *p4, /* Error message */ i8 p4type, /* P4_STATIC or P4_TRANSIENT */ u8 p5Errmsg /* P5_ErrMsg type */ ){ | > > | | | > | | 5266 5267 5268 5269 5270 5271 5272 5273 5274 5275 5276 5277 5278 5279 5280 5281 5282 5283 5284 5285 5286 5287 5288 5289 5290 5291 5292 5293 5294 5295 5296 5297 5298 5299 5300 5301 5302 5303 5304 5305 5306 5307 5308 5309 5310 5311 5312 | Parse *pParse, /* Parsing context */ int errCode, /* extended error code */ int onError, /* Constraint type */ char *p4, /* Error message */ i8 p4type, /* P4_STATIC or P4_TRANSIENT */ u8 p5Errmsg /* P5_ErrMsg type */ ){ Vdbe *v; assert( pParse->pVdbe!=0 ); v = sqlite3GetVdbe(pParse); assert( (errCode&0xff)==SQLITE_CONSTRAINT || pParse->nested ); if( onError==OE_Abort ){ sqlite3MayAbort(pParse); } sqlite3VdbeAddOp4(v, OP_Halt, errCode, onError, 0, p4, p4type); sqlite3VdbeChangeP5(v, p5Errmsg); } /* ** Code an OP_Halt due to UNIQUE or PRIMARY KEY constraint violation. */ void sqlite3UniqueConstraint( Parse *pParse, /* Parsing context */ int onError, /* Constraint type */ Index *pIdx /* The index that triggers the constraint */ ){ char *zErr; int j; StrAccum errMsg; Table *pTab = pIdx->pTable; sqlite3StrAccumInit(&errMsg, pParse->db, 0, 0, pParse->db->aLimit[SQLITE_LIMIT_LENGTH]); if( pIdx->aColExpr ){ sqlite3_str_appendf(&errMsg, "index '%q'", pIdx->zName); }else{ for(j=0; j<pIdx->nKeyCol; j++){ char *zCol; assert( pIdx->aiColumn[j]>=0 ); zCol = pTab->aCol[pIdx->aiColumn[j]].zCnName; if( j ) sqlite3_str_append(&errMsg, ", ", 2); sqlite3_str_appendall(&errMsg, pTab->zName); sqlite3_str_append(&errMsg, ".", 1); sqlite3_str_appendall(&errMsg, zCol); } } zErr = sqlite3StrAccumFinish(&errMsg); |
︙ | ︙ | |||
4374 4375 4376 4377 4378 4379 4380 | int onError, /* Conflict resolution algorithm */ Table *pTab /* The table with the non-unique rowid */ ){ char *zMsg; int rc; if( pTab->iPKey>=0 ){ zMsg = sqlite3MPrintf(pParse->db, "%s.%s", pTab->zName, | | | 5325 5326 5327 5328 5329 5330 5331 5332 5333 5334 5335 5336 5337 5338 5339 | int onError, /* Conflict resolution algorithm */ Table *pTab /* The table with the non-unique rowid */ ){ char *zMsg; int rc; if( pTab->iPKey>=0 ){ zMsg = sqlite3MPrintf(pParse->db, "%s.%s", pTab->zName, pTab->aCol[pTab->iPKey].zCnName); rc = SQLITE_CONSTRAINT_PRIMARYKEY; }else{ zMsg = sqlite3MPrintf(pParse->db, "%s.rowid", pTab->zName); rc = SQLITE_CONSTRAINT_ROWID; } sqlite3HaltConstraint(pParse, rc, onError, zMsg, P4_DYNAMIC, P5_ConstraintUnique); |
︙ | ︙ | |||
4409 4410 4411 4412 4413 4414 4415 | /* ** Recompute all indices of pTab that use the collating sequence pColl. ** If pColl==0 then recompute all indices of pTab. */ #ifndef SQLITE_OMIT_REINDEX static void reindexTable(Parse *pParse, Table *pTab, char const *zColl){ | > | | | | | | > | 5360 5361 5362 5363 5364 5365 5366 5367 5368 5369 5370 5371 5372 5373 5374 5375 5376 5377 5378 5379 5380 5381 5382 | /* ** Recompute all indices of pTab that use the collating sequence pColl. ** If pColl==0 then recompute all indices of pTab. */ #ifndef SQLITE_OMIT_REINDEX static void reindexTable(Parse *pParse, Table *pTab, char const *zColl){ if( !IsVirtual(pTab) ){ Index *pIndex; /* An index associated with pTab */ for(pIndex=pTab->pIndex; pIndex; pIndex=pIndex->pNext){ if( zColl==0 || collationMatch(zColl, pIndex) ){ int iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); sqlite3BeginWriteOperation(pParse, 0, iDb); sqlite3RefillIndex(pParse, pIndex, -1); } } } } #endif /* ** Recompute all indices of all tables in all databases where the |
︙ | ︙ | |||
4536 4537 4538 4539 4540 4541 4542 | } if( pKey ){ assert( sqlite3KeyInfoIsWriteable(pKey) ); for(i=0; i<nCol; i++){ const char *zColl = pIdx->azColl[i]; pKey->aColl[i] = zColl==sqlite3StrBINARY ? 0 : sqlite3LocateCollSeq(pParse, zColl); | | > | 5489 5490 5491 5492 5493 5494 5495 5496 5497 5498 5499 5500 5501 5502 5503 5504 | } if( pKey ){ assert( sqlite3KeyInfoIsWriteable(pKey) ); for(i=0; i<nCol; i++){ const char *zColl = pIdx->azColl[i]; pKey->aColl[i] = zColl==sqlite3StrBINARY ? 0 : sqlite3LocateCollSeq(pParse, zColl); pKey->aSortFlags[i] = pIdx->aSortOrder[i]; assert( 0==(pKey->aSortFlags[i] & KEYINFO_ORDER_BIGNULL) ); } if( pParse->nErr ){ assert( pParse->rc==SQLITE_ERROR_MISSING_COLLSEQ ); if( pIdx->bNoQuery==0 ){ /* Deactivate the index because it contains an unknown collating ** sequence. The only way to reactive the index is to reload the ** schema. Adding the missing collating sequence later does not |
︙ | ︙ | |||
4559 4560 4561 4562 4563 4564 4565 | pKey = 0; } } return pKey; } #ifndef SQLITE_OMIT_CTE | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > | < < > > > > | | < | < < < < | | | < < < | 5513 5514 5515 5516 5517 5518 5519 5520 5521 5522 5523 5524 5525 5526 5527 5528 5529 5530 5531 5532 5533 5534 5535 5536 5537 5538 5539 5540 5541 5542 5543 5544 5545 5546 5547 5548 5549 5550 5551 5552 5553 5554 5555 5556 5557 5558 5559 5560 5561 5562 5563 5564 5565 5566 5567 5568 5569 5570 5571 5572 5573 5574 5575 5576 5577 5578 5579 5580 5581 5582 5583 5584 5585 5586 5587 5588 5589 5590 5591 5592 5593 5594 5595 5596 5597 5598 5599 5600 5601 5602 5603 5604 5605 5606 5607 5608 5609 5610 5611 5612 5613 5614 5615 5616 5617 5618 5619 5620 5621 5622 5623 5624 5625 5626 5627 5628 5629 5630 | pKey = 0; } } return pKey; } #ifndef SQLITE_OMIT_CTE /* ** Create a new CTE object */ Cte *sqlite3CteNew( Parse *pParse, /* Parsing context */ Token *pName, /* Name of the common-table */ ExprList *pArglist, /* Optional column name list for the table */ Select *pQuery, /* Query used to initialize the table */ u8 eM10d /* The MATERIALIZED flag */ ){ Cte *pNew; sqlite3 *db = pParse->db; pNew = sqlite3DbMallocZero(db, sizeof(*pNew)); assert( pNew!=0 || db->mallocFailed ); if( db->mallocFailed ){ sqlite3ExprListDelete(db, pArglist); sqlite3SelectDelete(db, pQuery); }else{ pNew->pSelect = pQuery; pNew->pCols = pArglist; pNew->zName = sqlite3NameFromToken(pParse->db, pName); pNew->eM10d = eM10d; } return pNew; } /* ** Clear information from a Cte object, but do not deallocate storage ** for the object itself. */ static void cteClear(sqlite3 *db, Cte *pCte){ assert( pCte!=0 ); sqlite3ExprListDelete(db, pCte->pCols); sqlite3SelectDelete(db, pCte->pSelect); sqlite3DbFree(db, pCte->zName); } /* ** Free the contents of the CTE object passed as the second argument. */ void sqlite3CteDelete(sqlite3 *db, Cte *pCte){ assert( pCte!=0 ); cteClear(db, pCte); sqlite3DbFree(db, pCte); } /* ** This routine is invoked once per CTE by the parser while parsing a ** WITH clause. The CTE described by teh third argument is added to ** the WITH clause of the second argument. If the second argument is ** NULL, then a new WITH argument is created. */ With *sqlite3WithAdd( Parse *pParse, /* Parsing context */ With *pWith, /* Existing WITH clause, or NULL */ Cte *pCte /* CTE to add to the WITH clause */ ){ sqlite3 *db = pParse->db; With *pNew; char *zName; if( pCte==0 ){ return pWith; } /* Check that the CTE name is unique within this WITH clause. If ** not, store an error in the Parse structure. */ zName = pCte->zName; if( zName && pWith ){ int i; for(i=0; i<pWith->nCte; i++){ if( sqlite3StrICmp(zName, pWith->a[i].zName)==0 ){ sqlite3ErrorMsg(pParse, "duplicate WITH table name: %s", zName); } } } if( pWith ){ sqlite3_int64 nByte = sizeof(*pWith) + (sizeof(pWith->a[1]) * pWith->nCte); pNew = sqlite3DbRealloc(db, pWith, nByte); }else{ pNew = sqlite3DbMallocZero(db, sizeof(*pWith)); } assert( (pNew!=0 && zName!=0) || db->mallocFailed ); if( db->mallocFailed ){ sqlite3CteDelete(db, pCte); pNew = pWith; }else{ pNew->a[pNew->nCte++] = *pCte; sqlite3DbFree(db, pCte); } return pNew; } /* ** Free the contents of the With object passed as the second argument. */ void sqlite3WithDelete(sqlite3 *db, With *pWith){ if( pWith ){ int i; for(i=0; i<pWith->nCte; i++){ cteClear(db, &pWith->a[i]); } sqlite3DbFree(db, pWith); } } #endif /* !defined(SQLITE_OMIT_CTE) */ |
Changes to src/callback.c.
︙ | ︙ | |||
61 62 63 64 65 66 67 | pColl->xDel = 0; /* Do not copy the destructor */ return SQLITE_OK; } } return SQLITE_ERROR; } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | pColl->xDel = 0; /* Do not copy the destructor */ return SQLITE_OK; } } return SQLITE_ERROR; } /* ** This routine is called on a collation sequence before it is used to ** check that it is defined. An undefined collation sequence exists when ** a database is loaded that contains references to collation sequences ** that have not been defined by sqlite3_create_collation() etc. ** ** If required, this routine calls the 'collation needed' callback to |
︙ | ︙ | |||
198 199 200 201 202 203 204 | ** this routine. sqlite3LocateCollSeq() invokes the collation factory ** if necessary and generates an error message if the collating sequence ** cannot be found. ** ** See also: sqlite3LocateCollSeq(), sqlite3GetCollSeq() */ CollSeq *sqlite3FindCollSeq( | | | | | > > > > > | > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | ** this routine. sqlite3LocateCollSeq() invokes the collation factory ** if necessary and generates an error message if the collating sequence ** cannot be found. ** ** See also: sqlite3LocateCollSeq(), sqlite3GetCollSeq() */ CollSeq *sqlite3FindCollSeq( sqlite3 *db, /* Database connection to search */ u8 enc, /* Desired text encoding */ const char *zName, /* Name of the collating sequence. Might be NULL */ int create /* True to create CollSeq if doesn't already exist */ ){ CollSeq *pColl; assert( SQLITE_UTF8==1 && SQLITE_UTF16LE==2 && SQLITE_UTF16BE==3 ); assert( enc>=SQLITE_UTF8 && enc<=SQLITE_UTF16BE ); if( zName ){ pColl = findCollSeqEntry(db, zName, create); if( pColl ) pColl += enc-1; }else{ pColl = db->pDfltColl; } return pColl; } /* ** Change the text encoding for a database connection. This means that ** the pDfltColl must change as well. */ void sqlite3SetTextEncoding(sqlite3 *db, u8 enc){ assert( enc==SQLITE_UTF8 || enc==SQLITE_UTF16LE || enc==SQLITE_UTF16BE ); db->enc = enc; /* EVIDENCE-OF: R-08308-17224 The default collating function for all ** strings is BINARY. */ db->pDfltColl = sqlite3FindCollSeq(db, enc, sqlite3StrBINARY, 0); } /* ** This function is responsible for invoking the collation factory callback ** or substituting a collation sequence of a different encoding when the ** requested collation sequence is not available in the desired encoding. ** ** If it is not NULL, then pColl must point to the database native encoding ** collation sequence with name zName, length nName. ** ** The return value is either the collation sequence to be used in database ** db for collation type name zName, length nName, or NULL, if no collation ** sequence can be found. If no collation is found, leave an error message. ** ** See also: sqlite3LocateCollSeq(), sqlite3FindCollSeq() */ CollSeq *sqlite3GetCollSeq( Parse *pParse, /* Parsing context */ u8 enc, /* The desired encoding for the collating sequence */ CollSeq *pColl, /* Collating sequence with native encoding, or NULL */ const char *zName /* Collating sequence name */ ){ CollSeq *p; sqlite3 *db = pParse->db; p = pColl; if( !p ){ p = sqlite3FindCollSeq(db, enc, zName, 0); } if( !p || !p->xCmp ){ /* No collation sequence of this type for this encoding is registered. ** Call the collation factory to see if it can supply us with one. */ callCollNeeded(db, enc, zName); p = sqlite3FindCollSeq(db, enc, zName, 0); } if( p && !p->xCmp && synthCollSeq(db, p) ){ p = 0; } assert( !p || p->xCmp ); if( p==0 ){ sqlite3ErrorMsg(pParse, "no such collation sequence: %s", zName); pParse->rc = SQLITE_ERROR_MISSING_COLLSEQ; } return p; } /* ** This function returns the collation sequence for database native text ** encoding identified by the string zName. ** ** If the requested collation sequence is not available, or not available ** in the database native encoding, the collation factory is invoked to ** request it. If the collation factory does not supply such a sequence, ** and the sequence is available in another text encoding, then that is ** returned instead. ** ** If no versions of the requested collations sequence are available, or ** another error occurs, NULL is returned and an error message written into ** pParse. ** ** This routine is a wrapper around sqlite3FindCollSeq(). This routine ** invokes the collation factory if the named collation cannot be found ** and generates an error message. ** ** See also: sqlite3FindCollSeq(), sqlite3GetCollSeq() */ CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char *zName){ sqlite3 *db = pParse->db; u8 enc = ENC(db); u8 initbusy = db->init.busy; CollSeq *pColl; pColl = sqlite3FindCollSeq(db, enc, zName, initbusy); if( !initbusy && (!pColl || !pColl->xCmp) ){ pColl = sqlite3GetCollSeq(pParse, enc, pColl, zName); } return pColl; } /* During the search for the best function definition, this procedure ** is called to test how well the function passed as the first argument ** matches the request for a function with nArg arguments in a system ** that uses encoding enc. The value returned indicates how well the |
︙ | ︙ | |||
250 251 252 253 254 255 256 257 | #define FUNC_PERFECT_MATCH 6 /* The score for a perfect match */ static int matchQuality( FuncDef *p, /* The function we are evaluating for match quality */ int nArg, /* Desired number of arguments. (-1)==any */ u8 enc /* Desired text encoding */ ){ int match; | > > | | > | < < | 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 | #define FUNC_PERFECT_MATCH 6 /* The score for a perfect match */ static int matchQuality( FuncDef *p, /* The function we are evaluating for match quality */ int nArg, /* Desired number of arguments. (-1)==any */ u8 enc /* Desired text encoding */ ){ int match; assert( p->nArg>=-1 ); /* Wrong number of arguments means "no match" */ if( p->nArg!=nArg ){ if( nArg==(-2) ) return (p->xSFunc==0) ? 0 : FUNC_PERFECT_MATCH; if( p->nArg>=0 ) return 0; } /* Give a better score to a function with a specific number of arguments ** than to function that accepts any number of arguments. */ if( p->nArg==nArg ){ match = 4; }else{ match = 1; |
︙ | ︙ | |||
285 286 287 288 289 290 291 292 293 294 295 296 297 298 | */ FuncDef *sqlite3FunctionSearch( int h, /* Hash of the name */ const char *zFunc /* Name of function */ ){ FuncDef *p; for(p=sqlite3BuiltinFunctions.a[h]; p; p=p->u.pHash){ if( sqlite3StrICmp(p->zName, zFunc)==0 ){ return p; } } return 0; } | > | 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 | */ FuncDef *sqlite3FunctionSearch( int h, /* Hash of the name */ const char *zFunc /* Name of function */ ){ FuncDef *p; for(p=sqlite3BuiltinFunctions.a[h]; p; p=p->u.pHash){ assert( p->funcFlags & SQLITE_FUNC_BUILTIN ); if( sqlite3StrICmp(p->zName, zFunc)==0 ){ return p; } } return 0; } |
︙ | ︙ | |||
306 307 308 309 310 311 312 313 314 315 316 317 318 319 | int i; for(i=0; i<nDef; i++){ FuncDef *pOther; const char *zName = aDef[i].zName; int nName = sqlite3Strlen30(zName); int h = SQLITE_FUNC_HASH(zName[0], nName); assert( zName[0]>='a' && zName[0]<='z' ); pOther = sqlite3FunctionSearch(h, zName); if( pOther ){ assert( pOther!=&aDef[i] && pOther->pNext!=&aDef[i] ); aDef[i].pNext = pOther->pNext; pOther->pNext = &aDef[i]; }else{ aDef[i].pNext = 0; | > | 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 | int i; for(i=0; i<nDef; i++){ FuncDef *pOther; const char *zName = aDef[i].zName; int nName = sqlite3Strlen30(zName); int h = SQLITE_FUNC_HASH(zName[0], nName); assert( zName[0]>='a' && zName[0]<='z' ); assert( aDef[i].funcFlags & SQLITE_FUNC_BUILTIN ); pOther = sqlite3FunctionSearch(h, zName); if( pOther ){ assert( pOther!=&aDef[i] && pOther->pNext!=&aDef[i] ); aDef[i].pNext = pOther->pNext; pOther->pNext = &aDef[i]; }else{ aDef[i].pNext = 0; |
︙ | ︙ |
Changes to src/ctime.c.
︙ | ︙ | |||
9 10 11 12 13 14 15 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** ** This file implements routines used to report what compile-time options ** SQLite was built with. */ | < | > | | | > | | > | > > > | | | | | | | | | > | | > | | | | | | | | | | | | > > > | | | | | > > > | | | | < < < | | | | | | | | | | | > > > | | | | | | > > > | | | | | | | | | | | < < | | | | | | | | | | | | | < < < > | | > | | | | | | | | 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 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** ** This file implements routines used to report what compile-time options ** SQLite was built with. */ #ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS /* IMP: R-16824-07538 */ /* ** Include the configuration header output by 'configure' if we're using the ** autoconf-based build */ #if defined(_HAVE_SQLITE_CONFIG_H) && !defined(SQLITECONFIG_H) #include "config.h" #define SQLITECONFIG_H 1 #endif /* These macros are provided to "stringify" the value of the define ** for those options in which the value is meaningful. */ #define CTIMEOPT_VAL_(opt) #opt #define CTIMEOPT_VAL(opt) CTIMEOPT_VAL_(opt) /* Like CTIMEOPT_VAL, but especially for SQLITE_DEFAULT_LOOKASIDE. This ** option requires a separate macro because legal values contain a single ** comma. e.g. (-DSQLITE_DEFAULT_LOOKASIDE="100,100") */ #define CTIMEOPT_VAL2_(opt1,opt2) #opt1 "," #opt2 #define CTIMEOPT_VAL2(opt) CTIMEOPT_VAL2_(opt) #include "sqliteInt.h" /* ** An array of names of all compile-time options. This array should ** be sorted A-Z. ** ** This array looks large, but in a typical installation actually uses ** only a handful of compile-time options, so most times this array is usually ** rather short and uses little memory space. */ static const char * const sqlite3azCompileOpt[] = { /* ** BEGIN CODE GENERATED BY tool/mkctime.tcl */ #ifdef SQLITE_32BIT_ROWID "32BIT_ROWID", #endif #ifdef SQLITE_4_BYTE_ALIGNED_MALLOC "4_BYTE_ALIGNED_MALLOC", #endif #ifdef SQLITE_64BIT_STATS "64BIT_STATS", #endif #ifdef SQLITE_ALLOW_COVERING_INDEX_SCAN # if SQLITE_ALLOW_COVERING_INDEX_SCAN != 1 "ALLOW_COVERING_INDEX_SCAN=" CTIMEOPT_VAL(SQLITE_ALLOW_COVERING_INDEX_SCAN), # endif #endif #ifdef SQLITE_ALLOW_URI_AUTHORITY "ALLOW_URI_AUTHORITY", #endif #ifdef SQLITE_ATOMIC_INTRINSICS "ATOMIC_INTRINSICS=" CTIMEOPT_VAL(SQLITE_ATOMIC_INTRINSICS), #endif #ifdef SQLITE_BITMASK_TYPE "BITMASK_TYPE=" CTIMEOPT_VAL(SQLITE_BITMASK_TYPE), #endif #ifdef SQLITE_BUG_COMPATIBLE_20160819 "BUG_COMPATIBLE_20160819", #endif #ifdef SQLITE_CASE_SENSITIVE_LIKE "CASE_SENSITIVE_LIKE", #endif #ifdef SQLITE_CHECK_PAGES "CHECK_PAGES", #endif #if defined(__clang__) && defined(__clang_major__) "COMPILER=clang-" CTIMEOPT_VAL(__clang_major__) "." CTIMEOPT_VAL(__clang_minor__) "." CTIMEOPT_VAL(__clang_patchlevel__), #elif defined(_MSC_VER) "COMPILER=msvc-" CTIMEOPT_VAL(_MSC_VER), #elif defined(__GNUC__) && defined(__VERSION__) "COMPILER=gcc-" __VERSION__, #endif #ifdef SQLITE_COVERAGE_TEST "COVERAGE_TEST", #endif #ifdef SQLITE_DEBUG "DEBUG", #endif #ifdef SQLITE_DEFAULT_AUTOMATIC_INDEX "DEFAULT_AUTOMATIC_INDEX", #endif #ifdef SQLITE_DEFAULT_AUTOVACUUM "DEFAULT_AUTOVACUUM", #endif #ifdef SQLITE_DEFAULT_CACHE_SIZE "DEFAULT_CACHE_SIZE=" CTIMEOPT_VAL(SQLITE_DEFAULT_CACHE_SIZE), #endif #ifdef SQLITE_DEFAULT_CKPTFULLFSYNC "DEFAULT_CKPTFULLFSYNC", #endif #ifdef SQLITE_DEFAULT_FILE_FORMAT "DEFAULT_FILE_FORMAT=" CTIMEOPT_VAL(SQLITE_DEFAULT_FILE_FORMAT), #endif #ifdef SQLITE_DEFAULT_FILE_PERMISSIONS "DEFAULT_FILE_PERMISSIONS=" CTIMEOPT_VAL(SQLITE_DEFAULT_FILE_PERMISSIONS), #endif #ifdef SQLITE_DEFAULT_FOREIGN_KEYS "DEFAULT_FOREIGN_KEYS", #endif #ifdef SQLITE_DEFAULT_JOURNAL_SIZE_LIMIT "DEFAULT_JOURNAL_SIZE_LIMIT=" CTIMEOPT_VAL(SQLITE_DEFAULT_JOURNAL_SIZE_LIMIT), #endif #ifdef SQLITE_DEFAULT_LOCKING_MODE "DEFAULT_LOCKING_MODE=" CTIMEOPT_VAL(SQLITE_DEFAULT_LOCKING_MODE), #endif #ifdef SQLITE_DEFAULT_LOOKASIDE "DEFAULT_LOOKASIDE=" CTIMEOPT_VAL2(SQLITE_DEFAULT_LOOKASIDE), #endif #ifdef SQLITE_DEFAULT_MEMSTATUS # if SQLITE_DEFAULT_MEMSTATUS != 1 "DEFAULT_MEMSTATUS=" CTIMEOPT_VAL(SQLITE_DEFAULT_MEMSTATUS), # endif #endif #ifdef SQLITE_DEFAULT_MMAP_SIZE "DEFAULT_MMAP_SIZE=" CTIMEOPT_VAL(SQLITE_DEFAULT_MMAP_SIZE), #endif #ifdef SQLITE_DEFAULT_PAGE_SIZE "DEFAULT_PAGE_SIZE=" CTIMEOPT_VAL(SQLITE_DEFAULT_PAGE_SIZE), #endif #ifdef SQLITE_DEFAULT_PCACHE_INITSZ "DEFAULT_PCACHE_INITSZ=" CTIMEOPT_VAL(SQLITE_DEFAULT_PCACHE_INITSZ), #endif #ifdef SQLITE_DEFAULT_PROXYDIR_PERMISSIONS "DEFAULT_PROXYDIR_PERMISSIONS=" CTIMEOPT_VAL(SQLITE_DEFAULT_PROXYDIR_PERMISSIONS), #endif #ifdef SQLITE_DEFAULT_RECURSIVE_TRIGGERS "DEFAULT_RECURSIVE_TRIGGERS", #endif #ifdef SQLITE_DEFAULT_ROWEST "DEFAULT_ROWEST=" CTIMEOPT_VAL(SQLITE_DEFAULT_ROWEST), #endif #ifdef SQLITE_DEFAULT_SECTOR_SIZE "DEFAULT_SECTOR_SIZE=" CTIMEOPT_VAL(SQLITE_DEFAULT_SECTOR_SIZE), #endif #ifdef SQLITE_DEFAULT_SYNCHRONOUS "DEFAULT_SYNCHRONOUS=" CTIMEOPT_VAL(SQLITE_DEFAULT_SYNCHRONOUS), #endif #ifdef SQLITE_DEFAULT_WAL_AUTOCHECKPOINT "DEFAULT_WAL_AUTOCHECKPOINT=" CTIMEOPT_VAL(SQLITE_DEFAULT_WAL_AUTOCHECKPOINT), #endif #ifdef SQLITE_DEFAULT_WAL_SYNCHRONOUS "DEFAULT_WAL_SYNCHRONOUS=" CTIMEOPT_VAL(SQLITE_DEFAULT_WAL_SYNCHRONOUS), #endif #ifdef SQLITE_DEFAULT_WORKER_THREADS "DEFAULT_WORKER_THREADS=" CTIMEOPT_VAL(SQLITE_DEFAULT_WORKER_THREADS), #endif #ifdef SQLITE_DIRECT_OVERFLOW_READ "DIRECT_OVERFLOW_READ", #endif #ifdef SQLITE_DISABLE_DIRSYNC "DISABLE_DIRSYNC", #endif #ifdef SQLITE_DISABLE_FTS3_UNICODE "DISABLE_FTS3_UNICODE", #endif #ifdef SQLITE_DISABLE_FTS4_DEFERRED "DISABLE_FTS4_DEFERRED", #endif #ifdef SQLITE_DISABLE_INTRINSIC "DISABLE_INTRINSIC", #endif #ifdef SQLITE_DISABLE_LFS "DISABLE_LFS", #endif #ifdef SQLITE_DISABLE_PAGECACHE_OVERFLOW_STATS "DISABLE_PAGECACHE_OVERFLOW_STATS", #endif #ifdef SQLITE_DISABLE_SKIPAHEAD_DISTINCT "DISABLE_SKIPAHEAD_DISTINCT", #endif #ifdef SQLITE_ENABLE_8_3_NAMES "ENABLE_8_3_NAMES=" CTIMEOPT_VAL(SQLITE_ENABLE_8_3_NAMES), #endif #ifdef SQLITE_ENABLE_API_ARMOR "ENABLE_API_ARMOR", #endif #ifdef SQLITE_ENABLE_ATOMIC_WRITE "ENABLE_ATOMIC_WRITE", #endif #ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE "ENABLE_BATCH_ATOMIC_WRITE", #endif #ifdef SQLITE_ENABLE_BYTECODE_VTAB "ENABLE_BYTECODE_VTAB", #endif #ifdef SQLITE_ENABLE_CEROD "ENABLE_CEROD=" CTIMEOPT_VAL(SQLITE_ENABLE_CEROD), #endif #ifdef SQLITE_ENABLE_COLUMN_METADATA "ENABLE_COLUMN_METADATA", #endif #ifdef SQLITE_ENABLE_COLUMN_USED_MASK "ENABLE_COLUMN_USED_MASK", #endif #ifdef SQLITE_ENABLE_COSTMULT "ENABLE_COSTMULT", #endif #ifdef SQLITE_ENABLE_CURSOR_HINTS "ENABLE_CURSOR_HINTS", #endif #ifdef SQLITE_ENABLE_DBPAGE_VTAB "ENABLE_DBPAGE_VTAB", #endif #ifdef SQLITE_ENABLE_DBSTAT_VTAB "ENABLE_DBSTAT_VTAB", #endif #ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT "ENABLE_EXPENSIVE_ASSERT", #endif #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS "ENABLE_EXPLAIN_COMMENTS", #endif #ifdef SQLITE_ENABLE_FTS3 "ENABLE_FTS3", #endif #ifdef SQLITE_ENABLE_FTS3_PARENTHESIS "ENABLE_FTS3_PARENTHESIS", #endif #ifdef SQLITE_ENABLE_FTS3_TOKENIZER "ENABLE_FTS3_TOKENIZER", #endif #ifdef SQLITE_ENABLE_FTS4 "ENABLE_FTS4", #endif #ifdef SQLITE_ENABLE_FTS5 "ENABLE_FTS5", #endif #ifdef SQLITE_ENABLE_GEOPOLY "ENABLE_GEOPOLY", #endif #ifdef SQLITE_ENABLE_HIDDEN_COLUMNS "ENABLE_HIDDEN_COLUMNS", #endif #ifdef SQLITE_ENABLE_ICU "ENABLE_ICU", #endif #ifdef SQLITE_ENABLE_IOTRACE "ENABLE_IOTRACE", #endif #ifdef SQLITE_ENABLE_JSON1 "ENABLE_JSON1", #endif #ifdef SQLITE_ENABLE_LOAD_EXTENSION "ENABLE_LOAD_EXTENSION", #endif #ifdef SQLITE_ENABLE_LOCKING_STYLE "ENABLE_LOCKING_STYLE=" CTIMEOPT_VAL(SQLITE_ENABLE_LOCKING_STYLE), #endif #ifdef SQLITE_ENABLE_MATH_FUNCTIONS "ENABLE_MATH_FUNCTIONS", #endif #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT "ENABLE_MEMORY_MANAGEMENT", #endif #ifdef SQLITE_ENABLE_MEMSYS3 "ENABLE_MEMSYS3", #endif #ifdef SQLITE_ENABLE_MEMSYS5 "ENABLE_MEMSYS5", #endif #ifdef SQLITE_ENABLE_MULTIPLEX "ENABLE_MULTIPLEX", #endif #ifdef SQLITE_ENABLE_NORMALIZE "ENABLE_NORMALIZE", #endif #ifdef SQLITE_ENABLE_NULL_TRIM "ENABLE_NULL_TRIM", #endif #ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC "ENABLE_OFFSET_SQL_FUNC", #endif #ifdef SQLITE_ENABLE_OVERSIZE_CELL_CHECK "ENABLE_OVERSIZE_CELL_CHECK", #endif #ifdef SQLITE_ENABLE_PREUPDATE_HOOK "ENABLE_PREUPDATE_HOOK", #endif #ifdef SQLITE_ENABLE_QPSG "ENABLE_QPSG", #endif #ifdef SQLITE_ENABLE_RBU "ENABLE_RBU", #endif #ifdef SQLITE_ENABLE_RTREE "ENABLE_RTREE", #endif #ifdef SQLITE_ENABLE_SELECTTRACE "ENABLE_SELECTTRACE", #endif #ifdef SQLITE_ENABLE_SESSION "ENABLE_SESSION", #endif #ifdef SQLITE_ENABLE_SNAPSHOT "ENABLE_SNAPSHOT", #endif #ifdef SQLITE_ENABLE_SORTER_REFERENCES "ENABLE_SORTER_REFERENCES", #endif #ifdef SQLITE_ENABLE_SQLLOG "ENABLE_SQLLOG", #endif #ifdef SQLITE_ENABLE_STAT4 "ENABLE_STAT4", #endif #ifdef SQLITE_ENABLE_STMTVTAB "ENABLE_STMTVTAB", #endif #ifdef SQLITE_ENABLE_STMT_SCANSTATUS "ENABLE_STMT_SCANSTATUS", #endif #ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION "ENABLE_UNKNOWN_SQL_FUNCTION", #endif #ifdef SQLITE_ENABLE_UNLOCK_NOTIFY "ENABLE_UNLOCK_NOTIFY", #endif #ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT "ENABLE_UPDATE_DELETE_LIMIT", #endif #ifdef SQLITE_ENABLE_URI_00_ERROR "ENABLE_URI_00_ERROR", #endif #ifdef SQLITE_ENABLE_VFSTRACE "ENABLE_VFSTRACE", #endif #ifdef SQLITE_ENABLE_WHERETRACE "ENABLE_WHERETRACE", #endif #ifdef SQLITE_ENABLE_ZIPVFS "ENABLE_ZIPVFS", #endif #ifdef SQLITE_EXPLAIN_ESTIMATED_ROWS "EXPLAIN_ESTIMATED_ROWS", #endif #ifdef SQLITE_EXTRA_IFNULLROW "EXTRA_IFNULLROW", #endif #ifdef SQLITE_EXTRA_INIT "EXTRA_INIT=" CTIMEOPT_VAL(SQLITE_EXTRA_INIT), #endif #ifdef SQLITE_EXTRA_SHUTDOWN "EXTRA_SHUTDOWN=" CTIMEOPT_VAL(SQLITE_EXTRA_SHUTDOWN), #endif #ifdef SQLITE_FTS3_MAX_EXPR_DEPTH "FTS3_MAX_EXPR_DEPTH=" CTIMEOPT_VAL(SQLITE_FTS3_MAX_EXPR_DEPTH), #endif #ifdef SQLITE_FTS5_ENABLE_TEST_MI "FTS5_ENABLE_TEST_MI", #endif #ifdef SQLITE_FTS5_NO_WITHOUT_ROWID "FTS5_NO_WITHOUT_ROWID", #endif #if HAVE_ISNAN || SQLITE_HAVE_ISNAN "HAVE_ISNAN", #endif #ifdef SQLITE_HOMEGROWN_RECURSIVE_MUTEX # if SQLITE_HOMEGROWN_RECURSIVE_MUTEX != 1 "HOMEGROWN_RECURSIVE_MUTEX=" CTIMEOPT_VAL(SQLITE_HOMEGROWN_RECURSIVE_MUTEX), # endif #endif #ifdef SQLITE_IGNORE_AFP_LOCK_ERRORS "IGNORE_AFP_LOCK_ERRORS", #endif #ifdef SQLITE_IGNORE_FLOCK_LOCK_ERRORS "IGNORE_FLOCK_LOCK_ERRORS", #endif #ifdef SQLITE_INLINE_MEMCPY "INLINE_MEMCPY", #endif #ifdef SQLITE_INT64_TYPE "INT64_TYPE", #endif #ifdef SQLITE_INTEGRITY_CHECK_ERROR_MAX "INTEGRITY_CHECK_ERROR_MAX=" CTIMEOPT_VAL(SQLITE_INTEGRITY_CHECK_ERROR_MAX), #endif #ifdef SQLITE_LIKE_DOESNT_MATCH_BLOBS "LIKE_DOESNT_MATCH_BLOBS", #endif #ifdef SQLITE_LOCK_TRACE "LOCK_TRACE", #endif #ifdef SQLITE_LOG_CACHE_SPILL "LOG_CACHE_SPILL", #endif #ifdef SQLITE_MALLOC_SOFT_LIMIT "MALLOC_SOFT_LIMIT=" CTIMEOPT_VAL(SQLITE_MALLOC_SOFT_LIMIT), #endif #ifdef SQLITE_MAX_ATTACHED "MAX_ATTACHED=" CTIMEOPT_VAL(SQLITE_MAX_ATTACHED), |
︙ | ︙ | |||
446 447 448 449 450 451 452 | #endif #ifdef SQLITE_MAX_VDBE_OP "MAX_VDBE_OP=" CTIMEOPT_VAL(SQLITE_MAX_VDBE_OP), #endif #ifdef SQLITE_MAX_WORKER_THREADS "MAX_WORKER_THREADS=" CTIMEOPT_VAL(SQLITE_MAX_WORKER_THREADS), #endif | | | | | < < < | | | | < < < | | | | | | | | | | | | < < < | | | | | | | | | > > > | | | | | | | | | > > > | | | | | | | | | | | | | | | | | | | | | > | | > | | | | | | | | | | | > | | > | | | | | | | | > > > | | | | | | | | | | | | | 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 | #endif #ifdef SQLITE_MAX_VDBE_OP "MAX_VDBE_OP=" CTIMEOPT_VAL(SQLITE_MAX_VDBE_OP), #endif #ifdef SQLITE_MAX_WORKER_THREADS "MAX_WORKER_THREADS=" CTIMEOPT_VAL(SQLITE_MAX_WORKER_THREADS), #endif #ifdef SQLITE_MEMDEBUG "MEMDEBUG", #endif #ifdef SQLITE_MIXED_ENDIAN_64BIT_FLOAT "MIXED_ENDIAN_64BIT_FLOAT", #endif #ifdef SQLITE_MMAP_READWRITE "MMAP_READWRITE", #endif #ifdef SQLITE_MUTEX_NOOP "MUTEX_NOOP", #endif #ifdef SQLITE_MUTEX_OMIT "MUTEX_OMIT", #endif #ifdef SQLITE_MUTEX_PTHREADS "MUTEX_PTHREADS", #endif #ifdef SQLITE_MUTEX_W32 "MUTEX_W32", #endif #ifdef SQLITE_NEED_ERR_NAME "NEED_ERR_NAME", #endif #ifdef SQLITE_NO_SYNC "NO_SYNC", #endif #ifdef SQLITE_OMIT_ALTERTABLE "OMIT_ALTERTABLE", #endif #ifdef SQLITE_OMIT_ANALYZE "OMIT_ANALYZE", #endif #ifdef SQLITE_OMIT_ATTACH "OMIT_ATTACH", #endif #ifdef SQLITE_OMIT_AUTHORIZATION "OMIT_AUTHORIZATION", #endif #ifdef SQLITE_OMIT_AUTOINCREMENT "OMIT_AUTOINCREMENT", #endif #ifdef SQLITE_OMIT_AUTOINIT "OMIT_AUTOINIT", #endif #ifdef SQLITE_OMIT_AUTOMATIC_INDEX "OMIT_AUTOMATIC_INDEX", #endif #ifdef SQLITE_OMIT_AUTORESET "OMIT_AUTORESET", #endif #ifdef SQLITE_OMIT_AUTOVACUUM "OMIT_AUTOVACUUM", #endif #ifdef SQLITE_OMIT_BETWEEN_OPTIMIZATION "OMIT_BETWEEN_OPTIMIZATION", #endif #ifdef SQLITE_OMIT_BLOB_LITERAL "OMIT_BLOB_LITERAL", #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_CONFLICT_CLAUSE "OMIT_CONFLICT_CLAUSE", #endif #ifdef SQLITE_OMIT_CTE "OMIT_CTE", #endif #if defined(SQLITE_OMIT_DATETIME_FUNCS) || defined(SQLITE_OMIT_FLOATING_POINT) "OMIT_DATETIME_FUNCS", #endif #ifdef SQLITE_OMIT_DECLTYPE "OMIT_DECLTYPE", #endif #ifdef SQLITE_OMIT_DEPRECATED "OMIT_DEPRECATED", #endif #ifdef SQLITE_OMIT_DESERIALIZE "OMIT_DESERIALIZE", #endif #ifdef SQLITE_OMIT_DISKIO "OMIT_DISKIO", #endif #ifdef SQLITE_OMIT_EXPLAIN "OMIT_EXPLAIN", #endif #ifdef SQLITE_OMIT_FLAG_PRAGMAS "OMIT_FLAG_PRAGMAS", #endif #ifdef SQLITE_OMIT_FLOATING_POINT "OMIT_FLOATING_POINT", #endif #ifdef SQLITE_OMIT_FOREIGN_KEY "OMIT_FOREIGN_KEY", #endif #ifdef SQLITE_OMIT_GET_TABLE "OMIT_GET_TABLE", #endif #ifdef SQLITE_OMIT_HEX_INTEGER "OMIT_HEX_INTEGER", #endif #ifdef SQLITE_OMIT_INCRBLOB "OMIT_INCRBLOB", #endif #ifdef SQLITE_OMIT_INTEGRITY_CHECK "OMIT_INTEGRITY_CHECK", #endif #ifdef SQLITE_OMIT_INTROSPECTION_PRAGMAS "OMIT_INTROSPECTION_PRAGMAS", #endif #ifdef SQLITE_OMIT_LIKE_OPTIMIZATION "OMIT_LIKE_OPTIMIZATION", #endif #ifdef SQLITE_OMIT_LOAD_EXTENSION "OMIT_LOAD_EXTENSION", #endif #ifdef SQLITE_OMIT_LOCALTIME "OMIT_LOCALTIME", #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_PARSER_TRACE "OMIT_PARSER_TRACE", #endif #ifdef SQLITE_OMIT_POPEN "OMIT_POPEN", #endif #ifdef SQLITE_OMIT_PRAGMA "OMIT_PRAGMA", #endif #ifdef SQLITE_OMIT_PROGRESS_CALLBACK "OMIT_PROGRESS_CALLBACK", #endif #ifdef SQLITE_OMIT_QUICKBALANCE "OMIT_QUICKBALANCE", #endif #ifdef SQLITE_OMIT_REINDEX "OMIT_REINDEX", #endif #ifdef SQLITE_OMIT_SCHEMA_PRAGMAS "OMIT_SCHEMA_PRAGMAS", #endif #ifdef SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS "OMIT_SCHEMA_VERSION_PRAGMAS", #endif #ifdef SQLITE_OMIT_SHARED_CACHE "OMIT_SHARED_CACHE", #endif #ifdef SQLITE_OMIT_SHUTDOWN_DIRECTORIES "OMIT_SHUTDOWN_DIRECTORIES", #endif #ifdef SQLITE_OMIT_SUBQUERY "OMIT_SUBQUERY", #endif #ifdef SQLITE_OMIT_TCL_VARIABLE "OMIT_TCL_VARIABLE", #endif #ifdef SQLITE_OMIT_TEMPDB "OMIT_TEMPDB", #endif #ifdef SQLITE_OMIT_TEST_CONTROL "OMIT_TEST_CONTROL", #endif #ifdef SQLITE_OMIT_TRACE # if SQLITE_OMIT_TRACE != 1 "OMIT_TRACE=" CTIMEOPT_VAL(SQLITE_OMIT_TRACE), # endif #endif #ifdef SQLITE_OMIT_TRIGGER "OMIT_TRIGGER", #endif #ifdef SQLITE_OMIT_TRUNCATE_OPTIMIZATION "OMIT_TRUNCATE_OPTIMIZATION", #endif #ifdef SQLITE_OMIT_UTF16 "OMIT_UTF16", #endif #ifdef SQLITE_OMIT_VACUUM "OMIT_VACUUM", #endif #ifdef SQLITE_OMIT_VIEW "OMIT_VIEW", #endif #ifdef SQLITE_OMIT_VIRTUALTABLE "OMIT_VIRTUALTABLE", #endif #ifdef SQLITE_OMIT_WAL "OMIT_WAL", #endif #ifdef SQLITE_OMIT_WSD "OMIT_WSD", #endif #ifdef SQLITE_OMIT_XFER_OPT "OMIT_XFER_OPT", #endif #ifdef SQLITE_PCACHE_SEPARATE_HEADER "PCACHE_SEPARATE_HEADER", #endif #ifdef SQLITE_PERFORMANCE_TRACE "PERFORMANCE_TRACE", #endif #ifdef SQLITE_POWERSAFE_OVERWRITE # if SQLITE_POWERSAFE_OVERWRITE != 1 "POWERSAFE_OVERWRITE=" CTIMEOPT_VAL(SQLITE_POWERSAFE_OVERWRITE), # endif #endif #ifdef SQLITE_PREFER_PROXY_LOCKING "PREFER_PROXY_LOCKING", #endif #ifdef SQLITE_PROXY_DEBUG "PROXY_DEBUG", #endif #ifdef SQLITE_REVERSE_UNORDERED_SELECTS "REVERSE_UNORDERED_SELECTS", #endif #ifdef SQLITE_RTREE_INT_ONLY "RTREE_INT_ONLY", #endif #ifdef SQLITE_SECURE_DELETE "SECURE_DELETE", #endif #ifdef SQLITE_SMALL_STACK "SMALL_STACK", #endif #ifdef SQLITE_SORTER_PMASZ "SORTER_PMASZ=" CTIMEOPT_VAL(SQLITE_SORTER_PMASZ), #endif #ifdef SQLITE_SOUNDEX "SOUNDEX", #endif #ifdef SQLITE_STAT4_SAMPLES "STAT4_SAMPLES=" CTIMEOPT_VAL(SQLITE_STAT4_SAMPLES), #endif #ifdef SQLITE_STMTJRNL_SPILL "STMTJRNL_SPILL=" CTIMEOPT_VAL(SQLITE_STMTJRNL_SPILL), #endif #ifdef SQLITE_SUBSTR_COMPATIBILITY "SUBSTR_COMPATIBILITY", #endif #if (!defined(SQLITE_WIN32_MALLOC) \ && !defined(SQLITE_ZERO_MALLOC) \ && !defined(SQLITE_MEMDEBUG) \ ) || defined(SQLITE_SYSTEM_MALLOC) "SYSTEM_MALLOC", #endif #ifdef SQLITE_TCL "TCL", #endif #ifdef SQLITE_TEMP_STORE "TEMP_STORE=" CTIMEOPT_VAL(SQLITE_TEMP_STORE), #endif #ifdef SQLITE_TEST "TEST", #endif #if defined(SQLITE_THREADSAFE) "THREADSAFE=" CTIMEOPT_VAL(SQLITE_THREADSAFE), #elif defined(THREADSAFE) "THREADSAFE=" CTIMEOPT_VAL(THREADSAFE), #else "THREADSAFE=1", #endif #ifdef SQLITE_UNLINK_AFTER_CLOSE "UNLINK_AFTER_CLOSE", #endif #ifdef SQLITE_UNTESTABLE "UNTESTABLE", #endif #ifdef SQLITE_USER_AUTHENTICATION "USER_AUTHENTICATION", #endif #ifdef SQLITE_USE_ALLOCA "USE_ALLOCA", #endif #ifdef SQLITE_USE_FCNTL_TRACE "USE_FCNTL_TRACE", #endif #ifdef SQLITE_USE_URI "USE_URI", #endif #ifdef SQLITE_VDBE_COVERAGE "VDBE_COVERAGE", #endif #ifdef SQLITE_WIN32_MALLOC "WIN32_MALLOC", #endif #ifdef SQLITE_ZERO_MALLOC "ZERO_MALLOC", #endif /* ** END CODE GENERATED BY tool/mkctime.tcl */ }; const char **sqlite3CompileOptions(int *pnOpt){ *pnOpt = sizeof(sqlite3azCompileOpt) / sizeof(sqlite3azCompileOpt[0]); return (const char**)sqlite3azCompileOpt; } #endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */ |
Changes to src/date.c.
︙ | ︙ | |||
384 385 386 387 388 389 390 | double r; if( parseYyyyMmDd(zDate,p)==0 ){ return 0; }else if( parseHhMmSs(zDate, p)==0 ){ return 0; }else if( sqlite3StrICmp(zDate,"now")==0 && sqlite3NotPureFunc(context) ){ return setDateTimeToCurrent(context, p); | | | 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 | double r; if( parseYyyyMmDd(zDate,p)==0 ){ return 0; }else if( parseHhMmSs(zDate, p)==0 ){ return 0; }else if( sqlite3StrICmp(zDate,"now")==0 && sqlite3NotPureFunc(context) ){ return setDateTimeToCurrent(context, p); }else if( sqlite3AtoF(zDate, &r, sqlite3Strlen30(zDate), SQLITE_UTF8)>0 ){ setRawDateNumber(p, r); return 0; } return 1; } /* The julian day number for 9999-12-31 23:59:59.999 is 5373484.4999999. |
︙ | ︙ | |||
511 512 513 514 515 516 517 | ** local time. */ static int osLocaltime(time_t *t, struct tm *pTm){ int rc; #if !HAVE_LOCALTIME_R && !HAVE_LOCALTIME_S struct tm *pX; #if SQLITE_THREADSAFE>0 | | | 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 | ** local time. */ static int osLocaltime(time_t *t, struct tm *pTm){ int rc; #if !HAVE_LOCALTIME_R && !HAVE_LOCALTIME_S struct tm *pX; #if SQLITE_THREADSAFE>0 sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN); #endif sqlite3_mutex_enter(mutex); pX = localtime(t); #ifndef SQLITE_UNTESTABLE if( sqlite3GlobalConfig.bLocaltimeFault ) pX = 0; #endif if( pX ) *pTm = *pX; |
︙ | ︙ | |||
617 618 619 620 621 622 623 | static const struct { u8 eType; /* Transformation type code */ u8 nName; /* Length of th name */ char *zName; /* Name of the transformation */ double rLimit; /* Maximum NNN value for this transform */ double rXform; /* Constant used for this transform */ } aXformType[] = { | | | | | | | | 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 | static const struct { u8 eType; /* Transformation type code */ u8 nName; /* Length of th name */ char *zName; /* Name of the transformation */ double rLimit; /* Maximum NNN value for this transform */ double rXform; /* Constant used for this transform */ } aXformType[] = { { 0, 6, "second", 464269060800.0, 1000.0 }, { 0, 6, "minute", 7737817680.0, 60000.0 }, { 0, 4, "hour", 128963628.0, 3600000.0 }, { 0, 3, "day", 5373485.0, 86400000.0 }, { 1, 5, "month", 176546.0, 2592000000.0 }, { 2, 4, "year", 14713.0, 31536000000.0 }, }; /* ** Process a modifier to a date-time stamp. The modifiers are ** as follows: ** ** NNN days |
︙ | ︙ | |||
684 685 686 687 688 689 690 | ** Treat the current value of p->s as the number of ** seconds since 1970. Convert to a real julian day number. */ if( sqlite3_stricmp(z, "unixepoch")==0 && p->rawS ){ r = p->s*1000.0 + 210866760000000.0; if( r>=0.0 && r<464269060800000.0 ){ clearYMD_HMS_TZ(p); | | | 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 | ** Treat the current value of p->s as the number of ** seconds since 1970. Convert to a real julian day number. */ if( sqlite3_stricmp(z, "unixepoch")==0 && p->rawS ){ r = p->s*1000.0 + 210866760000000.0; if( r>=0.0 && r<464269060800000.0 ){ clearYMD_HMS_TZ(p); p->iJD = (sqlite3_int64)(r + 0.5); p->validJD = 1; p->rawS = 0; rc = 0; } } #ifndef SQLITE_OMIT_LOCALTIME else if( sqlite3_stricmp(z, "utc")==0 && sqlite3NotPureFunc(pCtx) ){ |
︙ | ︙ | |||
718 719 720 721 722 723 724 | ** weekday N ** ** Move the date to the same time on the next occurrence of ** weekday N where 0==Sunday, 1==Monday, and so forth. If the ** date is already on the appropriate weekday, this is a no-op. */ if( sqlite3_strnicmp(z, "weekday ", 8)==0 | | | 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 | ** weekday N ** ** Move the date to the same time on the next occurrence of ** weekday N where 0==Sunday, 1==Monday, and so forth. If the ** date is already on the appropriate weekday, this is a no-op. */ if( sqlite3_strnicmp(z, "weekday ", 8)==0 && sqlite3AtoF(&z[8], &r, sqlite3Strlen30(&z[8]), SQLITE_UTF8)>0 && (n=(int)r)==r && n>=0 && r<7 ){ sqlite3_int64 Z; computeYMD_HMS(p); p->validTZ = 0; p->validJD = 0; computeJD(p); Z = ((p->iJD + 129600000)/86400000) % 7; |
︙ | ︙ | |||
777 778 779 780 781 782 783 | case '6': case '7': case '8': case '9': { double rRounder; int i; for(n=1; z[n] && z[n]!=':' && !sqlite3Isspace(z[n]); n++){} | | | 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 | case '6': case '7': case '8': case '9': { double rRounder; int i; for(n=1; z[n] && z[n]!=':' && !sqlite3Isspace(z[n]); n++){} if( sqlite3AtoF(z, &r, n, SQLITE_UTF8)<=0 ){ rc = 1; break; } if( z[n]==':' ){ /* A modifier of the form (+|-)HH:MM:SS.FFF adds (or subtracts) the ** specified number of hours, minutes, seconds, and fractional seconds ** to the time. The ".FFF" may be omitted. The ":SS.FFF" may be |
︙ | ︙ | |||
877 878 879 880 881 882 883 884 885 886 887 888 889 890 | DateTime *p ){ int i, n; const unsigned char *z; int eType; memset(p, 0, sizeof(*p)); if( argc==0 ){ return setDateTimeToCurrent(context, p); } if( (eType = sqlite3_value_type(argv[0]))==SQLITE_FLOAT || eType==SQLITE_INTEGER ){ setRawDateNumber(p, sqlite3_value_double(argv[0])); }else{ z = sqlite3_value_text(argv[0]); | > | 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 | DateTime *p ){ int i, n; const unsigned char *z; int eType; memset(p, 0, sizeof(*p)); if( argc==0 ){ if( !sqlite3NotPureFunc(context) ) return 1; return setDateTimeToCurrent(context, p); } if( (eType = sqlite3_value_type(argv[0]))==SQLITE_FLOAT || eType==SQLITE_INTEGER ){ setRawDateNumber(p, sqlite3_value_double(argv[0])); }else{ z = sqlite3_value_text(argv[0]); |
︙ | ︙ | |||
1004 1005 1006 1007 1008 1009 1010 | */ static void strftimeFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ DateTime x; | < < > | > < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < | < | | < | > | | > > > | | | | < | | | > > > | | | | | | | | | | | | | < | | < | | | | | < | | | > > > | > > > | < | | | | > | > > | > | | | | | | | > > > > | > > < > | < | 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 | */ static void strftimeFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ DateTime x; size_t i,j; sqlite3 *db; const char *zFmt; sqlite3_str sRes; if( argc==0 ) return; zFmt = (const char*)sqlite3_value_text(argv[0]); if( zFmt==0 || isDate(context, argc-1, argv+1, &x) ) return; db = sqlite3_context_db_handle(context); sqlite3StrAccumInit(&sRes, 0, 0, 0, db->aLimit[SQLITE_LIMIT_LENGTH]); computeJD(&x); computeYMD_HMS(&x); for(i=j=0; zFmt[i]; i++){ if( zFmt[i]!='%' ) continue; if( j<i ) sqlite3_str_append(&sRes, zFmt+j, (int)(i-j)); i++; j = i + 1; switch( zFmt[i] ){ case 'd': { sqlite3_str_appendf(&sRes, "%02d", x.D); break; } case 'f': { double s = x.s; if( s>59.999 ) s = 59.999; sqlite3_str_appendf(&sRes, "%06.3f", s); break; } case 'H': { sqlite3_str_appendf(&sRes, "%02d", x.h); break; } case 'W': /* Fall thru */ case 'j': { int nDay; /* Number of days since 1st day of year */ DateTime y = x; y.validJD = 0; y.M = 1; y.D = 1; computeJD(&y); nDay = (int)((x.iJD-y.iJD+43200000)/86400000); if( zFmt[i]=='W' ){ int wd; /* 0=Monday, 1=Tuesday, ... 6=Sunday */ wd = (int)(((x.iJD+43200000)/86400000)%7); sqlite3_str_appendf(&sRes,"%02d",(nDay+7-wd)/7); }else{ sqlite3_str_appendf(&sRes,"%03d",nDay+1); } break; } case 'J': { sqlite3_str_appendf(&sRes,"%.16g",x.iJD/86400000.0); break; } case 'm': { sqlite3_str_appendf(&sRes,"%02d",x.M); break; } case 'M': { sqlite3_str_appendf(&sRes,"%02d",x.m); break; } case 's': { i64 iS = (i64)(x.iJD/1000 - 21086676*(i64)10000); sqlite3_str_appendf(&sRes,"%lld",iS); break; } case 'S': { sqlite3_str_appendf(&sRes,"%02d",(int)x.s); break; } case 'w': { sqlite3_str_appendchar(&sRes, 1, (char)(((x.iJD+129600000)/86400000) % 7) + '0'); break; } case 'Y': { sqlite3_str_appendf(&sRes,"%04d",x.Y); break; } case '%': { sqlite3_str_appendchar(&sRes, 1, '%'); break; } default: { sqlite3_str_reset(&sRes); return; } } } if( j<i ) sqlite3_str_append(&sRes, zFmt+j, (int)(i-j)); sqlite3ResultStrAccum(context, &sRes); } /* ** current_time() ** ** This function returns the same value as time('now'). */ |
︙ | ︙ | |||
1207 1208 1209 1210 1211 1212 1213 | iT = sqlite3StmtCurrentTime(context); if( iT<=0 ) return; t = iT/1000 - 10000*(sqlite3_int64)21086676; #if HAVE_GMTIME_R pTm = gmtime_r(&t, &sNow); #else | | | | 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 | iT = sqlite3StmtCurrentTime(context); if( iT<=0 ) return; t = iT/1000 - 10000*(sqlite3_int64)21086676; #if HAVE_GMTIME_R pTm = gmtime_r(&t, &sNow); #else sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN)); pTm = gmtime(&t); if( pTm ) memcpy(&sNow, pTm, sizeof(sNow)); sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN)); #endif if( pTm ){ strftime(zBuf, 20, zFormat, &sNow); sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT); } } #endif |
︙ | ︙ |
Changes to src/dbpage.c.
︙ | ︙ | |||
69 70 71 72 73 74 75 76 77 78 79 80 81 82 | int argc, const char *const*argv, sqlite3_vtab **ppVtab, char **pzErr ){ DbpageTable *pTab = 0; int rc = SQLITE_OK; rc = sqlite3_declare_vtab(db, "CREATE TABLE x(pgno INTEGER PRIMARY KEY, data BLOB, schema HIDDEN)"); if( rc==SQLITE_OK ){ pTab = (DbpageTable *)sqlite3_malloc64(sizeof(DbpageTable)); if( pTab==0 ) rc = SQLITE_NOMEM_BKPT; } | > | 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | int argc, const char *const*argv, sqlite3_vtab **ppVtab, char **pzErr ){ DbpageTable *pTab = 0; int rc = SQLITE_OK; sqlite3_vtab_config(db, SQLITE_VTAB_DIRECTONLY); rc = sqlite3_declare_vtab(db, "CREATE TABLE x(pgno INTEGER PRIMARY KEY, data BLOB, schema HIDDEN)"); if( rc==SQLITE_OK ){ pTab = (DbpageTable *)sqlite3_malloc64(sizeof(DbpageTable)); if( pTab==0 ) rc = SQLITE_NOMEM_BKPT; } |
︙ | ︙ |
Changes to src/dbstat.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 file contains an implementation of the "dbstat" virtual table. ** | | > > > > > > > > > | 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 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ****************************************************************************** ** ** This file contains an implementation of the "dbstat" virtual table. ** ** The dbstat virtual table is used to extract low-level storage ** information from an SQLite database in order to implement the ** "sqlite3_analyzer" utility. See the ../tool/spaceanal.tcl script ** for an example implementation. ** ** Additional information is available on the "dbstat.html" page of the ** official SQLite documentation. */ #include "sqliteInt.h" /* Requires access to internal data structures */ #if (defined(SQLITE_ENABLE_DBSTAT_VTAB) || defined(SQLITE_TEST)) \ && !defined(SQLITE_OMIT_VIRTUALTABLE) /* ** The pager and btree modules arrange objects in memory so that there are ** always approximately 200 bytes of addressable memory following each page ** buffer. This way small buffer overreads caused by corrupt database pages ** do not cause undefined behaviour. This module pads each page buffer ** by the following number of bytes for the same purpose. */ #define DBSTAT_PAGE_PADDING_BYTES 256 /* ** Page paths: ** ** The value of the 'path' column describes the path taken from the ** root-node of the b-tree structure to each page. The value of the ** root-node path is '/'. ** |
︙ | ︙ | |||
52 53 54 55 56 57 58 | ** ** If the paths are sorted using the BINARY collation sequence, then ** the overflow pages associated with a cell will appear earlier in the ** sort-order than its child page: ** ** '/1c2/000/' // Left-most child of 451st child of root */ | | | | | | | | | | | | | | > | | > > > | | | < | > | | > | > < > | | | | > | | | | 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 | ** ** If the paths are sorted using the BINARY collation sequence, then ** the overflow pages associated with a cell will appear earlier in the ** sort-order than its child page: ** ** '/1c2/000/' // Left-most child of 451st child of root */ static const char zDbstatSchema[] = "CREATE TABLE x(" " name TEXT," /* 0 Name of table or index */ " path TEXT," /* 1 Path to page from root (NULL for agg) */ " pageno INTEGER," /* 2 Page number (page count for aggregates) */ " pagetype TEXT," /* 3 'internal', 'leaf', 'overflow', or NULL */ " ncell INTEGER," /* 4 Cells on page (0 for overflow) */ " payload INTEGER," /* 5 Bytes of payload on this page */ " unused INTEGER," /* 6 Bytes of unused space on this page */ " mx_payload INTEGER," /* 7 Largest payload size of all cells */ " pgoffset INTEGER," /* 8 Offset of page in file (NULL for agg) */ " pgsize INTEGER," /* 9 Size of the page (sum for aggregate) */ " schema TEXT HIDDEN," /* 10 Database schema being analyzed */ " aggregate BOOLEAN HIDDEN" /* 11 aggregate info for each table */ ")" ; /* Forward reference to data structured used in this module */ typedef struct StatTable StatTable; typedef struct StatCursor StatCursor; typedef struct StatPage StatPage; typedef struct StatCell StatCell; /* Size information for a single cell within a btree page */ struct StatCell { int nLocal; /* Bytes of local payload */ u32 iChildPg; /* Child node (or 0 if this is a leaf) */ int nOvfl; /* Entries in aOvfl[] */ u32 *aOvfl; /* Array of overflow page numbers */ int nLastOvfl; /* Bytes of payload on final overflow page */ int iOvfl; /* Iterates through aOvfl[] */ }; /* Size information for a single btree page */ struct StatPage { u32 iPgno; /* Page number */ u8 *aPg; /* Page buffer from sqlite3_malloc() */ int iCell; /* Current cell */ char *zPath; /* Path to this page */ /* Variables populated by statDecodePage(): */ u8 flags; /* Copy of flags byte */ int nCell; /* Number of cells on page */ int nUnused; /* Number of unused bytes on page */ StatCell *aCell; /* Array of parsed cells */ u32 iRightChildPg; /* Right-child page number (or 0) */ int nMxPayload; /* Largest payload of any cell on the page */ }; /* The cursor for scanning the dbstat virtual table */ struct StatCursor { sqlite3_vtab_cursor base; /* base class. MUST BE FIRST! */ sqlite3_stmt *pStmt; /* Iterates through set of root pages */ u8 isEof; /* After pStmt has returned SQLITE_DONE */ u8 isAgg; /* Aggregate results for each table */ int iDb; /* Schema used for this query */ StatPage aPage[32]; /* Pages in path to current page */ int iPage; /* Current entry in aPage[] */ /* Values to return. */ u32 iPageno; /* Value of 'pageno' column */ char *zName; /* Value of 'name' column */ char *zPath; /* Value of 'path' column */ char *zPagetype; /* Value of 'pagetype' column */ int nPage; /* Number of pages in current btree */ int nCell; /* Value of 'ncell' column */ int nMxPayload; /* Value of 'mx_payload' column */ i64 nUnused; /* Value of 'unused' column */ i64 nPayload; /* Value of 'payload' column */ i64 iOffset; /* Value of 'pgOffset' column */ i64 szPage; /* Value of 'pgSize' column */ }; /* An instance of the DBSTAT virtual table */ struct StatTable { sqlite3_vtab base; /* base class. MUST BE FIRST! */ sqlite3 *db; /* Database connection that owns this vtab */ int iDb; /* Index of database to analyze */ }; #ifndef get2byte # define get2byte(x) ((x)[0]<<8 | (x)[1]) #endif /* ** Connect to or create a new DBSTAT virtual table. */ static int statConnect( sqlite3 *db, void *pAux, int argc, const char *const*argv, sqlite3_vtab **ppVtab, char **pzErr |
︙ | ︙ | |||
155 156 157 158 159 160 161 | if( iDb<0 ){ *pzErr = sqlite3_mprintf("no such database: %s", argv[3]); return SQLITE_ERROR; } }else{ iDb = 0; } | > | | | < < > > | > > > > > > | | > > > | > > > > > > > > > > > > > > | > | | > > > | < > > > > | > > | | 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 | if( iDb<0 ){ *pzErr = sqlite3_mprintf("no such database: %s", argv[3]); return SQLITE_ERROR; } }else{ iDb = 0; } sqlite3_vtab_config(db, SQLITE_VTAB_DIRECTONLY); rc = sqlite3_declare_vtab(db, zDbstatSchema); if( rc==SQLITE_OK ){ pTab = (StatTable *)sqlite3_malloc64(sizeof(StatTable)); if( pTab==0 ) rc = SQLITE_NOMEM_BKPT; } assert( rc==SQLITE_OK || pTab==0 ); if( rc==SQLITE_OK ){ memset(pTab, 0, sizeof(StatTable)); pTab->db = db; pTab->iDb = iDb; } *ppVtab = (sqlite3_vtab*)pTab; return rc; } /* ** Disconnect from or destroy the DBSTAT virtual table. */ static int statDisconnect(sqlite3_vtab *pVtab){ sqlite3_free(pVtab); return SQLITE_OK; } /* ** Compute the best query strategy and return the result in idxNum. ** ** idxNum-Bit Meaning ** ---------- ---------------------------------------------- ** 0x01 There is a schema=? term in the WHERE clause ** 0x02 There is a name=? term in the WHERE clause ** 0x04 There is an aggregate=? term in the WHERE clause ** 0x08 Output should be ordered by name and path */ static int statBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ int i; int iSchema = -1; int iName = -1; int iAgg = -1; /* Look for a valid schema=? constraint. If found, change the idxNum to ** 1 and request the value of that constraint be sent to xFilter. And ** lower the cost estimate to encourage the constrained version to be ** used. */ for(i=0; i<pIdxInfo->nConstraint; i++){ if( pIdxInfo->aConstraint[i].op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue; if( pIdxInfo->aConstraint[i].usable==0 ){ /* Force DBSTAT table should always be the right-most table in a join */ return SQLITE_CONSTRAINT; } switch( pIdxInfo->aConstraint[i].iColumn ){ case 0: { /* name */ iName = i; break; } case 10: { /* schema */ iSchema = i; break; } case 11: { /* aggregate */ iAgg = i; break; } } } i = 0; if( iSchema>=0 ){ pIdxInfo->aConstraintUsage[iSchema].argvIndex = ++i; pIdxInfo->aConstraintUsage[iSchema].omit = 1; pIdxInfo->idxNum |= 0x01; } if( iName>=0 ){ pIdxInfo->aConstraintUsage[iName].argvIndex = ++i; pIdxInfo->idxNum |= 0x02; } if( iAgg>=0 ){ pIdxInfo->aConstraintUsage[iAgg].argvIndex = ++i; pIdxInfo->idxNum |= 0x04; } pIdxInfo->estimatedCost = 1.0; /* Records are always returned in ascending order of (name, path). ** If this will satisfy the client, set the orderByConsumed flag so that ** SQLite does not do an external sort. */ if( ( pIdxInfo->nOrderBy==1 && pIdxInfo->aOrderBy[0].iColumn==0 && pIdxInfo->aOrderBy[0].desc==0 ) || ( pIdxInfo->nOrderBy==2 && pIdxInfo->aOrderBy[0].iColumn==0 && pIdxInfo->aOrderBy[0].desc==0 && pIdxInfo->aOrderBy[1].iColumn==1 && pIdxInfo->aOrderBy[1].desc==0 ) ){ pIdxInfo->orderByConsumed = 1; pIdxInfo->idxNum |= 0x08; } return SQLITE_OK; } /* ** Open a new DBSTAT cursor. */ static int statOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){ StatTable *pTab = (StatTable *)pVTab; StatCursor *pCsr; pCsr = (StatCursor *)sqlite3_malloc64(sizeof(StatCursor)); if( pCsr==0 ){ |
︙ | ︙ | |||
261 262 263 264 265 266 267 268 | sqlite3_free(p->aCell); } p->nCell = 0; p->aCell = 0; } static void statClearPage(StatPage *p){ statClearCells(p); | > < > > | > > > > > > > > > > > > > > > | > > > > > | | < | > > > | | 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 | sqlite3_free(p->aCell); } p->nCell = 0; p->aCell = 0; } static void statClearPage(StatPage *p){ u8 *aPg = p->aPg; statClearCells(p); sqlite3_free(p->zPath); memset(p, 0, sizeof(StatPage)); p->aPg = aPg; } static void statResetCsr(StatCursor *pCsr){ int i; /* In some circumstances, specifically if an OOM has occurred, the call ** to sqlite3_reset() may cause the pager to be reset (emptied). It is ** important that statClearPage() is called to free any page refs before ** this happens. dbsqlfuzz 9ed3e4e3816219d3509d711636c38542bf3f40b1. */ for(i=0; i<ArraySize(pCsr->aPage); i++){ statClearPage(&pCsr->aPage[i]); sqlite3_free(pCsr->aPage[i].aPg); pCsr->aPage[i].aPg = 0; } sqlite3_reset(pCsr->pStmt); pCsr->iPage = 0; sqlite3_free(pCsr->zPath); pCsr->zPath = 0; pCsr->isEof = 0; } /* Resize the space-used counters inside of the cursor */ static void statResetCounts(StatCursor *pCsr){ pCsr->nCell = 0; pCsr->nMxPayload = 0; pCsr->nUnused = 0; pCsr->nPayload = 0; pCsr->szPage = 0; pCsr->nPage = 0; } /* ** Close a DBSTAT cursor. */ static int statClose(sqlite3_vtab_cursor *pCursor){ StatCursor *pCsr = (StatCursor *)pCursor; statResetCsr(pCsr); sqlite3_finalize(pCsr->pStmt); sqlite3_free(pCsr); return SQLITE_OK; } /* ** For a single cell on a btree page, compute the number of bytes of ** content (payload) stored on that page. That is to say, compute the ** number of bytes of content not found on overflow pages. */ static int getLocalPayload( int nUsable, /* Usable bytes per page */ u8 flags, /* Page flags */ int nTotal /* Total record (payload) size */ ){ int nLocal; int nMinLocal; int nMaxLocal; if( flags==0x0D ){ /* Table leaf node */ nMinLocal = (nUsable - 12) * 32 / 255 - 23; nMaxLocal = nUsable - 35; }else{ /* Index interior and leaf nodes */ nMinLocal = (nUsable - 12) * 32 / 255 - 23; nMaxLocal = (nUsable - 12) * 64 / 255 - 23; } nLocal = nMinLocal + (nTotal - nMinLocal) % (nUsable - 4); if( nLocal>nMaxLocal ) nLocal = nMinLocal; return nLocal; } /* Populate the StatPage object with information about the all ** cells found on the page currently under analysis. */ static int statDecodePage(Btree *pBt, StatPage *p){ int nUnused; int iOff; int nHdr; int isLeaf; int szPage; u8 *aData = p->aPg; u8 *aHdr = &aData[p->iPgno==1 ? 100 : 0]; p->flags = aHdr[0]; if( p->flags==0x0A || p->flags==0x0D ){ isLeaf = 1; nHdr = 8; }else if( p->flags==0x05 || p->flags==0x02 ){ |
︙ | ︙ | |||
383 384 385 386 387 388 389 | int nLocal; /* Bytes of payload stored locally */ iOff += getVarint32(&aData[iOff], nPayload); if( p->flags==0x0D ){ u64 dummy; iOff += sqlite3GetVarint(&aData[iOff], &dummy); } if( nPayload>(u32)p->nMxPayload ) p->nMxPayload = nPayload; | | > | > | 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 | int nLocal; /* Bytes of payload stored locally */ iOff += getVarint32(&aData[iOff], nPayload); if( p->flags==0x0D ){ u64 dummy; iOff += sqlite3GetVarint(&aData[iOff], &dummy); } if( nPayload>(u32)p->nMxPayload ) p->nMxPayload = nPayload; nLocal = getLocalPayload(nUsable, p->flags, nPayload); if( nLocal<0 ) goto statPageIsCorrupt; pCell->nLocal = nLocal; assert( nPayload>=(u32)nLocal ); assert( nLocal<=(nUsable-35) ); if( nPayload>(u32)nLocal ){ int j; int nOvfl = ((nPayload - nLocal) + nUsable-4 - 1) / (nUsable - 4); if( iOff+nLocal+4>nUsable || nPayload>0x7fffffff ){ goto statPageIsCorrupt; } pCell->nLastOvfl = (nPayload-nLocal) - (nOvfl-1) * (nUsable-4); pCell->nOvfl = nOvfl; pCell->aOvfl = sqlite3_malloc64(sizeof(u32)*nOvfl); if( pCell->aOvfl==0 ) return SQLITE_NOMEM_BKPT; pCell->aOvfl[0] = sqlite3Get4byte(&aData[iOff+nLocal]); for(j=1; j<nOvfl; j++){ int rc; |
︙ | ︙ | |||
433 434 435 436 437 438 439 | static void statSizeAndOffset(StatCursor *pCsr){ StatTable *pTab = (StatTable *)((sqlite3_vtab_cursor *)pCsr)->pVtab; Btree *pBt = pTab->db->aDb[pTab->iDb].pBt; Pager *pPager = sqlite3BtreePager(pBt); sqlite3_file *fd; sqlite3_int64 x[2]; | < < < < | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > | > > | > | > > | | < | | | < < < | | < < < < | | | > | > > > > > > | > < > > > > > > > > > | > > | < | > > | 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 | static void statSizeAndOffset(StatCursor *pCsr){ StatTable *pTab = (StatTable *)((sqlite3_vtab_cursor *)pCsr)->pVtab; Btree *pBt = pTab->db->aDb[pTab->iDb].pBt; Pager *pPager = sqlite3BtreePager(pBt); sqlite3_file *fd; sqlite3_int64 x[2]; /* If connected to a ZIPVFS backend, find the page size and ** offset from ZIPVFS. */ fd = sqlite3PagerFile(pPager); x[0] = pCsr->iPageno; if( sqlite3OsFileControl(fd, 230440, &x)==SQLITE_OK ){ pCsr->iOffset = x[0]; pCsr->szPage += x[1]; }else{ /* Not ZIPVFS: The default page size and offset */ pCsr->szPage += sqlite3BtreeGetPageSize(pBt); pCsr->iOffset = (i64)pCsr->szPage * (pCsr->iPageno - 1); } } /* ** Load a copy of the page data for page iPg into the buffer belonging ** to page object pPg. Allocate the buffer if necessary. Return SQLITE_OK ** if successful, or an SQLite error code otherwise. */ static int statGetPage( Btree *pBt, /* Load page from this b-tree */ u32 iPg, /* Page number to load */ StatPage *pPg /* Load page into this object */ ){ int pgsz = sqlite3BtreeGetPageSize(pBt); DbPage *pDbPage = 0; int rc; if( pPg->aPg==0 ){ pPg->aPg = (u8*)sqlite3_malloc(pgsz + DBSTAT_PAGE_PADDING_BYTES); if( pPg->aPg==0 ){ return SQLITE_NOMEM_BKPT; } memset(&pPg->aPg[pgsz], 0, DBSTAT_PAGE_PADDING_BYTES); } rc = sqlite3PagerGet(sqlite3BtreePager(pBt), iPg, &pDbPage, 0); if( rc==SQLITE_OK ){ const u8 *a = sqlite3PagerGetData(pDbPage); memcpy(pPg->aPg, a, pgsz); sqlite3PagerUnref(pDbPage); } return rc; } /* ** Move a DBSTAT cursor to the next entry. Normally, the next ** entry will be the next page, but in aggregated mode (pCsr->isAgg!=0), ** the next entry is the next btree. */ static int statNext(sqlite3_vtab_cursor *pCursor){ int rc; int nPayload; char *z; StatCursor *pCsr = (StatCursor *)pCursor; StatTable *pTab = (StatTable *)pCursor->pVtab; Btree *pBt = pTab->db->aDb[pCsr->iDb].pBt; Pager *pPager = sqlite3BtreePager(pBt); sqlite3_free(pCsr->zPath); pCsr->zPath = 0; statNextRestart: if( pCsr->iPage<0 ){ /* Start measuring space on the next btree */ statResetCounts(pCsr); rc = sqlite3_step(pCsr->pStmt); if( rc==SQLITE_ROW ){ int nPage; u32 iRoot = (u32)sqlite3_column_int64(pCsr->pStmt, 1); sqlite3PagerPagecount(pPager, &nPage); if( nPage==0 ){ pCsr->isEof = 1; return sqlite3_reset(pCsr->pStmt); } rc = statGetPage(pBt, iRoot, &pCsr->aPage[0]); pCsr->aPage[0].iPgno = iRoot; pCsr->aPage[0].iCell = 0; if( !pCsr->isAgg ){ pCsr->aPage[0].zPath = z = sqlite3_mprintf("/"); if( z==0 ) rc = SQLITE_NOMEM_BKPT; } pCsr->iPage = 0; pCsr->nPage = 1; }else{ pCsr->isEof = 1; return sqlite3_reset(pCsr->pStmt); } }else{ /* Continue analyzing the btree previously started */ StatPage *p = &pCsr->aPage[pCsr->iPage]; if( !pCsr->isAgg ) statResetCounts(pCsr); while( p->iCell<p->nCell ){ StatCell *pCell = &p->aCell[p->iCell]; while( pCell->iOvfl<pCell->nOvfl ){ int nUsable, iOvfl; sqlite3BtreeEnter(pBt); nUsable = sqlite3BtreeGetPageSize(pBt) - sqlite3BtreeGetReserveNoMutex(pBt); sqlite3BtreeLeave(pBt); pCsr->nPage++; statSizeAndOffset(pCsr); if( pCell->iOvfl<pCell->nOvfl-1 ){ pCsr->nPayload += nUsable - 4; }else{ pCsr->nPayload += pCell->nLastOvfl; pCsr->nUnused += nUsable - 4 - pCell->nLastOvfl; } iOvfl = pCell->iOvfl; pCell->iOvfl++; if( !pCsr->isAgg ){ pCsr->zName = (char *)sqlite3_column_text(pCsr->pStmt, 0); pCsr->iPageno = pCell->aOvfl[iOvfl]; pCsr->zPagetype = "overflow"; pCsr->zPath = z = sqlite3_mprintf( "%s%.3x+%.6x", p->zPath, p->iCell, iOvfl ); return z==0 ? SQLITE_NOMEM_BKPT : SQLITE_OK; } } if( p->iRightChildPg ) break; p->iCell++; } if( !p->iRightChildPg || p->iCell>p->nCell ){ statClearPage(p); pCsr->iPage--; if( pCsr->isAgg && pCsr->iPage<0 ){ /* label-statNext-done: When computing aggregate space usage over ** an entire btree, this is the exit point from this function */ return SQLITE_OK; } goto statNextRestart; /* Tail recursion */ } pCsr->iPage++; if( pCsr->iPage>=ArraySize(pCsr->aPage) ){ statResetCsr(pCsr); return SQLITE_CORRUPT_BKPT; } assert( p==&pCsr->aPage[pCsr->iPage-1] ); if( p->iCell==p->nCell ){ p[1].iPgno = p->iRightChildPg; }else{ p[1].iPgno = p->aCell[p->iCell].iChildPg; } rc = statGetPage(pBt, p[1].iPgno, &p[1]); pCsr->nPage++; p[1].iCell = 0; if( !pCsr->isAgg ){ p[1].zPath = z = sqlite3_mprintf("%s%.3x/", p->zPath, p->iCell); if( z==0 ) rc = SQLITE_NOMEM_BKPT; } p->iCell++; } /* Populate the StatCursor fields with the values to be returned ** by the xColumn() and xRowid() methods. */ if( rc==SQLITE_OK ){ |
︙ | ︙ | |||
568 569 570 571 572 573 574 | case 0x0A: /* index leaf */ pCsr->zPagetype = "leaf"; break; default: pCsr->zPagetype = "corrupted"; break; } | | | | > | | > | > > > > > > > > > > | > | | > > > | > | | < > | < > > | > > > > > | < > | > > | | | | | > > > > > > > > > | > > > > | > > | > > | > | > > > > | 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 | case 0x0A: /* index leaf */ pCsr->zPagetype = "leaf"; break; default: pCsr->zPagetype = "corrupted"; break; } pCsr->nCell += p->nCell; pCsr->nUnused += p->nUnused; if( p->nMxPayload>pCsr->nMxPayload ) pCsr->nMxPayload = p->nMxPayload; if( !pCsr->isAgg ){ pCsr->zPath = z = sqlite3_mprintf("%s", p->zPath); if( z==0 ) rc = SQLITE_NOMEM_BKPT; } nPayload = 0; for(i=0; i<p->nCell; i++){ nPayload += p->aCell[i].nLocal; } pCsr->nPayload += nPayload; /* If computing aggregate space usage by btree, continue with the ** next page. The loop will exit via the return at label-statNext-done */ if( pCsr->isAgg ) goto statNextRestart; } } return rc; } static int statEof(sqlite3_vtab_cursor *pCursor){ StatCursor *pCsr = (StatCursor *)pCursor; return pCsr->isEof; } /* Initialize a cursor according to the query plan idxNum using the ** arguments in argv[0]. See statBestIndex() for a description of the ** meaning of the bits in idxNum. */ static int statFilter( sqlite3_vtab_cursor *pCursor, int idxNum, const char *idxStr, int argc, sqlite3_value **argv ){ StatCursor *pCsr = (StatCursor *)pCursor; StatTable *pTab = (StatTable*)(pCursor->pVtab); sqlite3_str *pSql; /* Query of btrees to analyze */ char *zSql; /* String value of pSql */ int iArg = 0; /* Count of argv[] parameters used so far */ int rc = SQLITE_OK; /* Result of this operation */ const char *zName = 0; /* Only provide analysis of this table */ statResetCsr(pCsr); sqlite3_finalize(pCsr->pStmt); pCsr->pStmt = 0; if( idxNum & 0x01 ){ /* schema=? constraint is present. Get its value */ const char *zDbase = (const char*)sqlite3_value_text(argv[iArg++]); pCsr->iDb = sqlite3FindDbName(pTab->db, zDbase); if( pCsr->iDb<0 ){ pCsr->iDb = 0; pCsr->isEof = 1; return SQLITE_OK; } }else{ pCsr->iDb = pTab->iDb; } if( idxNum & 0x02 ){ /* name=? constraint is present */ zName = (const char*)sqlite3_value_text(argv[iArg++]); } if( idxNum & 0x04 ){ /* aggregate=? constraint is present */ pCsr->isAgg = sqlite3_value_double(argv[iArg++])!=0.0; }else{ pCsr->isAgg = 0; } pSql = sqlite3_str_new(pTab->db); sqlite3_str_appendf(pSql, "SELECT * FROM (" "SELECT 'sqlite_schema' AS name,1 AS rootpage,'table' AS type" " UNION ALL " "SELECT name,rootpage,type" " FROM \"%w\".sqlite_schema WHERE rootpage!=0)", pTab->db->aDb[pCsr->iDb].zDbSName); if( zName ){ sqlite3_str_appendf(pSql, "WHERE name=%Q", zName); } if( idxNum & 0x08 ){ sqlite3_str_appendf(pSql, " ORDER BY name"); } zSql = sqlite3_str_finish(pSql); if( zSql==0 ){ return SQLITE_NOMEM_BKPT; }else{ rc = sqlite3_prepare_v2(pTab->db, zSql, -1, &pCsr->pStmt, 0); sqlite3_free(zSql); } if( rc==SQLITE_OK ){ pCsr->iPage = -1; rc = statNext(pCursor); } return rc; } static int statColumn( sqlite3_vtab_cursor *pCursor, sqlite3_context *ctx, int i ){ StatCursor *pCsr = (StatCursor *)pCursor; switch( i ){ case 0: /* name */ sqlite3_result_text(ctx, pCsr->zName, -1, SQLITE_TRANSIENT); break; case 1: /* path */ if( !pCsr->isAgg ){ sqlite3_result_text(ctx, pCsr->zPath, -1, SQLITE_TRANSIENT); } break; case 2: /* pageno */ if( pCsr->isAgg ){ sqlite3_result_int64(ctx, pCsr->nPage); }else{ sqlite3_result_int64(ctx, pCsr->iPageno); } break; case 3: /* pagetype */ if( !pCsr->isAgg ){ sqlite3_result_text(ctx, pCsr->zPagetype, -1, SQLITE_STATIC); } break; case 4: /* ncell */ sqlite3_result_int(ctx, pCsr->nCell); break; case 5: /* payload */ sqlite3_result_int(ctx, pCsr->nPayload); break; case 6: /* unused */ sqlite3_result_int(ctx, pCsr->nUnused); break; case 7: /* mx_payload */ sqlite3_result_int(ctx, pCsr->nMxPayload); break; case 8: /* pgoffset */ if( !pCsr->isAgg ){ sqlite3_result_int64(ctx, pCsr->iOffset); } break; case 9: /* pgsize */ sqlite3_result_int(ctx, pCsr->szPage); break; case 10: { /* schema */ sqlite3 *db = sqlite3_context_db_handle(ctx); int iDb = pCsr->iDb; sqlite3_result_text(ctx, db->aDb[iDb].zDbSName, -1, SQLITE_STATIC); break; } default: { /* aggregate */ sqlite3_result_int(ctx, pCsr->isAgg); break; } } return SQLITE_OK; } static int statRowid(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){ StatCursor *pCsr = (StatCursor *)pCursor; |
︙ | ︙ |
Changes to src/delete.c.
︙ | ︙ | |||
25 26 27 28 29 30 31 | ** The following fields are initialized appropriate in pSrc: ** ** pSrc->a[0].pTab Pointer to the Table object ** pSrc->a[0].pIndex Pointer to the INDEXED BY index, if there is one ** */ Table *sqlite3SrcListLookup(Parse *pParse, SrcList *pSrc){ | | | < | | > | | < < < < | | 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 | ** The following fields are initialized appropriate in pSrc: ** ** pSrc->a[0].pTab Pointer to the Table object ** pSrc->a[0].pIndex Pointer to the INDEXED BY index, if there is one ** */ Table *sqlite3SrcListLookup(Parse *pParse, SrcList *pSrc){ SrcItem *pItem = pSrc->a; Table *pTab; assert( pItem && pSrc->nSrc>=1 ); pTab = sqlite3LocateTableItem(pParse, 0, pItem); sqlite3DeleteTable(pParse->db, pItem->pTab); pItem->pTab = pTab; if( pTab ){ pTab->nTabRef++; if( pItem->fg.isIndexedBy && sqlite3IndexedByLookup(pParse, pItem) ){ pTab = 0; } } return pTab; } /* Return true if table pTab is read-only. ** ** A table is read-only if any of the following are true: ** ** 1) It is a virtual table and no implementation of the xUpdate method ** has been provided ** ** 2) It is a system table (i.e. sqlite_schema), this call is not ** part of a nested parse and writable_schema pragma has not ** been specified ** ** 3) The table is a shadow table, the database connection is in ** defensive mode, and the current sqlite3_prepare() ** is for a top-level SQL statement. */ static int tabIsReadOnly(Parse *pParse, Table *pTab){ sqlite3 *db; if( IsVirtual(pTab) ){ return sqlite3GetVTable(pParse->db, pTab)->pMod->pModule->xUpdate==0; } if( (pTab->tabFlags & (TF_Readonly|TF_Shadow))==0 ) return 0; db = pParse->db; if( (pTab->tabFlags & TF_Readonly)!=0 ){ return sqlite3WritableSchema(db)==0 && pParse->nested==0; } assert( pTab->tabFlags & TF_Shadow ); return sqlite3ReadOnlyShadowTables(db); } /* ** Check to make sure the given table is writable. If it is not ** writable, generate an error message and return 1. If it is ** writable return 0; */ int sqlite3IsReadOnly(Parse *pParse, Table *pTab, int viewOk){ if( tabIsReadOnly(pParse, pTab) ){ sqlite3ErrorMsg(pParse, "table %s may not be modified", pTab->zName); return 1; } #ifndef SQLITE_OMIT_VIEW if( !viewOk && IsView(pTab) ){ sqlite3ErrorMsg(pParse,"cannot modify %s because it is a view",pTab->zName); return 1; } #endif return 0; } |
︙ | ︙ | |||
113 114 115 116 117 118 119 | ){ SelectDest dest; Select *pSel; SrcList *pFrom; sqlite3 *db = pParse->db; int iDb = sqlite3SchemaToIndex(db, pView->pSchema); pWhere = sqlite3ExprDup(db, pWhere, 0); | | | 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 | ){ SelectDest dest; Select *pSel; SrcList *pFrom; sqlite3 *db = pParse->db; int iDb = sqlite3SchemaToIndex(db, pView->pSchema); pWhere = sqlite3ExprDup(db, pWhere, 0); pFrom = sqlite3SrcListAppend(pParse, 0, 0, 0); if( pFrom ){ assert( pFrom->nSrc==1 ); pFrom->a[0].zName = sqlite3DbStrDup(db, pView->zName); pFrom->a[0].zDatabase = sqlite3DbStrDup(db, db->aDb[iDb].zDbSName); assert( pFrom->a[0].pOn==0 ); assert( pFrom->a[0].pUsing==0 ); } |
︙ | ︙ | |||
188 189 190 191 192 193 194 | pLhs = sqlite3PExpr(pParse, TK_ROW, 0, 0); pEList = sqlite3ExprListAppend( pParse, 0, sqlite3PExpr(pParse, TK_ROW, 0, 0) ); }else{ Index *pPk = sqlite3PrimaryKeyIndex(pTab); if( pPk->nKeyCol==1 ){ | | | | > > | > > > > > | 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 | pLhs = sqlite3PExpr(pParse, TK_ROW, 0, 0); pEList = sqlite3ExprListAppend( pParse, 0, sqlite3PExpr(pParse, TK_ROW, 0, 0) ); }else{ Index *pPk = sqlite3PrimaryKeyIndex(pTab); if( pPk->nKeyCol==1 ){ const char *zName = pTab->aCol[pPk->aiColumn[0]].zCnName; pLhs = sqlite3Expr(db, TK_ID, zName); pEList = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(db, TK_ID, zName)); }else{ int i; for(i=0; i<pPk->nKeyCol; i++){ Expr *p = sqlite3Expr(db, TK_ID, pTab->aCol[pPk->aiColumn[i]].zCnName); pEList = sqlite3ExprListAppend(pParse, pEList, p); } pLhs = sqlite3PExpr(pParse, TK_VECTOR, 0, 0); if( pLhs ){ pLhs->x.pList = sqlite3ExprListDup(db, pEList, 0); } } } /* duplicate the FROM clause as it is needed by both the DELETE/UPDATE tree ** and the SELECT subtree. */ pSrc->a[0].pTab = 0; pSelectSrc = sqlite3SrcListDup(db, pSrc, 0); pSrc->a[0].pTab = pTab; if( pSrc->a[0].fg.isIndexedBy ){ assert( pSrc->a[0].fg.isCte==0 ); pSrc->a[0].u2.pIBIndex = 0; pSrc->a[0].fg.isIndexedBy = 0; sqlite3DbFree(db, pSrc->a[0].u1.zIndexedBy); }else if( pSrc->a[0].fg.isCte ){ pSrc->a[0].u2.pCteUse->nUse++; } /* generate the SELECT expression tree. */ pSelect = sqlite3SelectNew(pParse, pEList, pSelectSrc, pWhere, 0 ,0, pOrderBy,0,pLimit ); /* now generate the new WHERE rowid IN clause for the DELETE/UDPATE */ |
︙ | ︙ | |||
295 296 297 298 299 300 301 | if( pTab==0 ) goto delete_from_cleanup; /* Figure out if we have any triggers and if the table being ** deleted from is a view */ #ifndef SQLITE_OMIT_TRIGGER pTrigger = sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0, 0); | | | 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 | if( pTab==0 ) goto delete_from_cleanup; /* Figure out if we have any triggers and if the table being ** deleted from is a view */ #ifndef SQLITE_OMIT_TRIGGER pTrigger = sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0, 0); isView = IsView(pTab); #else # define pTrigger 0 # define isView 0 #endif bComplex = pTrigger || sqlite3FkRequired(pParse, pTab, 0, 0); #ifdef SQLITE_OMIT_VIEW # undef isView |
︙ | ︙ | |||
387 388 389 390 391 392 393 394 395 396 397 398 399 400 | /* Initialize the counter of the number of rows deleted, if ** we are counting rows. */ if( (db->flags & SQLITE_CountRows)!=0 && !pParse->nested && !pParse->pTriggerTab ){ memCnt = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_Integer, 0, memCnt); } #ifndef SQLITE_OMIT_TRUNCATE_OPTIMIZATION /* Special case: A DELETE without a WHERE clause deletes everything. | > | 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 | /* Initialize the counter of the number of rows deleted, if ** we are counting rows. */ if( (db->flags & SQLITE_CountRows)!=0 && !pParse->nested && !pParse->pTriggerTab && !pParse->bReturning ){ memCnt = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_Integer, 0, memCnt); } #ifndef SQLITE_OMIT_TRUNCATE_OPTIMIZATION /* Special case: A DELETE without a WHERE clause deletes everything. |
︙ | ︙ | |||
421 422 423 424 425 426 427 428 429 430 431 | if( HasRowid(pTab) ){ sqlite3VdbeAddOp4(v, OP_Clear, pTab->tnum, iDb, memCnt ? memCnt : -1, pTab->zName, P4_STATIC); } for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ assert( pIdx->pSchema==pTab->pSchema ); sqlite3VdbeAddOp2(v, OP_Clear, pIdx->tnum, iDb); } }else #endif /* SQLITE_OMIT_TRUNCATE_OPTIMIZATION */ { | > > > | | 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 | if( HasRowid(pTab) ){ sqlite3VdbeAddOp4(v, OP_Clear, pTab->tnum, iDb, memCnt ? memCnt : -1, pTab->zName, P4_STATIC); } for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ assert( pIdx->pSchema==pTab->pSchema ); sqlite3VdbeAddOp2(v, OP_Clear, pIdx->tnum, iDb); if( IsPrimaryKeyIndex(pIdx) && !HasRowid(pTab) ){ sqlite3VdbeChangeP3(v, -1, memCnt ? memCnt : -1); } } }else #endif /* SQLITE_OMIT_TRUNCATE_OPTIMIZATION */ { u16 wcf = WHERE_ONEPASS_DESIRED|WHERE_DUPLICATES_OK; if( sNC.ncFlags & NC_VarSelect ) bComplex = 1; wcf |= (bComplex ? 0 : WHERE_ONEPASS_MULTIROW); if( HasRowid(pTab) ){ /* For a rowid table, initialize the RowSet to an empty set */ pPk = 0; nPk = 1; iRowSet = ++pParse->nMem; |
︙ | ︙ | |||
461 462 463 464 465 466 467 468 469 470 471 472 473 474 | */ pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0, 0, wcf, iTabCur+1); if( pWInfo==0 ) goto delete_from_cleanup; eOnePass = sqlite3WhereOkOnePass(pWInfo, aiCurOnePass); assert( IsVirtual(pTab)==0 || eOnePass!=ONEPASS_MULTI ); assert( IsVirtual(pTab) || bComplex || eOnePass!=ONEPASS_OFF ); if( eOnePass!=ONEPASS_SINGLE ) sqlite3MultiWrite(pParse); /* Keep track of the number of rows to be deleted */ if( memCnt ){ sqlite3VdbeAddOp2(v, OP_AddImm, memCnt, 1); } /* Extract the rowid or primary key for the current row */ | > > > | 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 | */ pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0, 0, wcf, iTabCur+1); if( pWInfo==0 ) goto delete_from_cleanup; eOnePass = sqlite3WhereOkOnePass(pWInfo, aiCurOnePass); assert( IsVirtual(pTab)==0 || eOnePass!=ONEPASS_MULTI ); assert( IsVirtual(pTab) || bComplex || eOnePass!=ONEPASS_OFF ); if( eOnePass!=ONEPASS_SINGLE ) sqlite3MultiWrite(pParse); if( sqlite3WhereUsesDeferredSeek(pWInfo) ){ sqlite3VdbeAddOp1(v, OP_FinishSeek, iTabCur); } /* Keep track of the number of rows to be deleted */ if( memCnt ){ sqlite3VdbeAddOp2(v, OP_AddImm, memCnt, 1); } /* Extract the rowid or primary key for the current row */ |
︙ | ︙ | |||
495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 | goto delete_from_cleanup; } memset(aToOpen, 1, nIdx+1); aToOpen[nIdx+1] = 0; if( aiCurOnePass[0]>=0 ) aToOpen[aiCurOnePass[0]-iTabCur] = 0; if( aiCurOnePass[1]>=0 ) aToOpen[aiCurOnePass[1]-iTabCur] = 0; if( addrEphOpen ) sqlite3VdbeChangeToNoop(v, addrEphOpen); }else{ if( pPk ){ /* Add the PK key for this row to the temporary table */ iKey = ++pParse->nMem; nKey = 0; /* Zero tells OP_Found to use a composite key */ sqlite3VdbeAddOp4(v, OP_MakeRecord, iPk, nPk, iKey, sqlite3IndexAffinityStr(pParse->db, pPk), nPk); sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iEphCur, iKey, iPk, nPk); }else{ /* Add the rowid of the row to be deleted to the RowSet */ nKey = 1; /* OP_DeferredSeek always uses a single rowid */ sqlite3VdbeAddOp2(v, OP_RowSetAdd, iRowSet, iKey); } | > < < < < < < < | > > | | 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 | goto delete_from_cleanup; } memset(aToOpen, 1, nIdx+1); aToOpen[nIdx+1] = 0; if( aiCurOnePass[0]>=0 ) aToOpen[aiCurOnePass[0]-iTabCur] = 0; if( aiCurOnePass[1]>=0 ) aToOpen[aiCurOnePass[1]-iTabCur] = 0; if( addrEphOpen ) sqlite3VdbeChangeToNoop(v, addrEphOpen); addrBypass = sqlite3VdbeMakeLabel(pParse); }else{ if( pPk ){ /* Add the PK key for this row to the temporary table */ iKey = ++pParse->nMem; nKey = 0; /* Zero tells OP_Found to use a composite key */ sqlite3VdbeAddOp4(v, OP_MakeRecord, iPk, nPk, iKey, sqlite3IndexAffinityStr(pParse->db, pPk), nPk); sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iEphCur, iKey, iPk, nPk); }else{ /* Add the rowid of the row to be deleted to the RowSet */ nKey = 1; /* OP_DeferredSeek always uses a single rowid */ sqlite3VdbeAddOp2(v, OP_RowSetAdd, iRowSet, iKey); } sqlite3WhereEnd(pWInfo); } /* Unless this is a view, open cursors for the table we are ** deleting from and all its indices. If this is a view, then the ** only effect this statement has is to fire the INSTEAD OF ** triggers. */ if( !isView ){ int iAddrOnce = 0; if( eOnePass==ONEPASS_MULTI ){ iAddrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v); } testcase( IsVirtual(pTab) ); sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, OPFLAG_FORDELETE, iTabCur, aToOpen, &iDataCur, &iIdxCur); assert( pPk || IsVirtual(pTab) || iDataCur==iTabCur ); assert( pPk || IsVirtual(pTab) || iIdxCur==iDataCur+1 ); if( eOnePass==ONEPASS_MULTI ){ sqlite3VdbeJumpHereOrPopInst(v, iAddrOnce); } } /* Set up a loop over the rowids/primary-keys that were found in the ** where-clause loop above. */ if( eOnePass!=ONEPASS_OFF ){ assert( nKey==nPk ); /* OP_Found will use an unpacked key */ if( !IsVirtual(pTab) && aToOpen[iDataCur-iTabCur] ){ assert( pPk!=0 || IsView(pTab) ); sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, addrBypass, iKey, nKey); VdbeCoverage(v); } }else if( pPk ){ addrLoop = sqlite3VdbeAddOp1(v, OP_Rewind, iEphCur); VdbeCoverage(v); if( IsVirtual(pTab) ){ sqlite3VdbeAddOp3(v, OP_Column, iEphCur, 0, iKey); |
︙ | ︙ | |||
609 610 611 612 613 614 615 | } /* Return the number of rows that were deleted. If this routine is ** generating code because of a call to sqlite3NestedParse(), do not ** invoke the callback function. */ if( memCnt ){ | | | 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 | } /* Return the number of rows that were deleted. If this routine is ** generating code because of a call to sqlite3NestedParse(), do not ** invoke the callback function. */ if( memCnt ){ sqlite3VdbeAddOp2(v, OP_ChngCntRow, memCnt, 1); sqlite3VdbeSetNumCols(v, 1); sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows deleted", SQLITE_STATIC); } delete_from_cleanup: sqlite3AuthContextPop(&sContext); sqlite3SrcListDelete(db, pTabList); |
︙ | ︙ | |||
702 703 704 705 706 707 708 | assert( v ); VdbeModuleComment((v, "BEGIN: GenRowDel(%d,%d,%d,%d)", iDataCur, iIdxCur, iPk, (int)nPk)); /* Seek cursor iCur to the row to delete. If this row no longer exists ** (this can happen if a trigger program has already deleted it), do ** not attempt to delete it or fire any DELETE triggers. */ | | | 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 | assert( v ); VdbeModuleComment((v, "BEGIN: GenRowDel(%d,%d,%d,%d)", iDataCur, iIdxCur, iPk, (int)nPk)); /* Seek cursor iCur to the row to delete. If this row no longer exists ** (this can happen if a trigger program has already deleted it), do ** not attempt to delete it or fire any DELETE triggers. */ iLabel = sqlite3VdbeMakeLabel(pParse); opSeek = HasRowid(pTab) ? OP_NotExists : OP_NotFound; if( eMode==ONEPASS_OFF ){ sqlite3VdbeAddOp4Int(v, opSeek, iDataCur, iLabel, iPk, nPk); VdbeCoverageIf(v, opSeek==OP_NotExists); VdbeCoverageIf(v, opSeek==OP_NotFound); } |
︙ | ︙ | |||
733 734 735 736 737 738 739 | /* Populate the OLD.* pseudo-table register array. These values will be ** used by any BEFORE and AFTER triggers that exist. */ sqlite3VdbeAddOp2(v, OP_Copy, iPk, iOld); for(iCol=0; iCol<pTab->nCol; iCol++){ testcase( mask!=0xffffffff && iCol==31 ); testcase( mask!=0xffffffff && iCol==32 ); if( mask==0xffffffff || (iCol<=31 && (mask & MASKBIT32(iCol))!=0) ){ | > | | 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 | /* Populate the OLD.* pseudo-table register array. These values will be ** used by any BEFORE and AFTER triggers that exist. */ sqlite3VdbeAddOp2(v, OP_Copy, iPk, iOld); for(iCol=0; iCol<pTab->nCol; iCol++){ testcase( mask!=0xffffffff && iCol==31 ); testcase( mask!=0xffffffff && iCol==32 ); if( mask==0xffffffff || (iCol<=31 && (mask & MASKBIT32(iCol))!=0) ){ int kk = sqlite3TableColumnToStorage(pTab, iCol); sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, iCol, iOld+kk+1); } } /* Invoke BEFORE DELETE trigger programs. */ addrStart = sqlite3VdbeCurrentAddr(v); sqlite3CodeRowTrigger(pParse, pTrigger, TK_DELETE, 0, TRIGGER_BEFORE, pTab, iOld, onconf, iLabel |
︙ | ︙ | |||
775 776 777 778 779 780 781 | ** ** If variable 'count' is non-zero, then this OP_Delete instruction should ** invoke the update-hook. The pre-update-hook, on the other hand should ** be invoked unless table pTab is a system table. The difference is that ** the update-hook is not invoked for rows removed by REPLACE, but the ** pre-update-hook is. */ | | | 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 | ** ** If variable 'count' is non-zero, then this OP_Delete instruction should ** invoke the update-hook. The pre-update-hook, on the other hand should ** be invoked unless table pTab is a system table. The difference is that ** the update-hook is not invoked for rows removed by REPLACE, but the ** pre-update-hook is. */ if( !IsView(pTab) ){ u8 p5 = 0; sqlite3GenerateRowIndexDelete(pParse, pTab, iDataCur, iIdxCur,0,iIdxNoSeek); sqlite3VdbeAddOp2(v, OP_Delete, iDataCur, (count?OPFLAG_NCHANGE:0)); if( pParse->nested==0 || 0==sqlite3_stricmp(pTab->zName, "sqlite_stat1") ){ sqlite3VdbeAppendP4(v, (char*)pTab, P4_TABLE); } if( eMode!=ONEPASS_OFF ){ |
︙ | ︙ | |||
855 856 857 858 859 860 861 862 863 864 865 866 867 868 | if( pIdx==pPk ) continue; if( iIdxCur+i==iIdxNoSeek ) continue; VdbeModuleComment((v, "GenRowIdxDel for %s", pIdx->zName)); r1 = sqlite3GenerateIndexKey(pParse, pIdx, iDataCur, 0, 1, &iPartIdxLabel, pPrior, r1); sqlite3VdbeAddOp3(v, OP_IdxDelete, iIdxCur+i, r1, pIdx->uniqNotNull ? pIdx->nKeyCol : pIdx->nColumn); sqlite3ResolvePartIdxLabel(pParse, iPartIdxLabel); pPrior = pIdx; } } /* ** Generate code that will assemble an index key and stores it in register | > | 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 | if( pIdx==pPk ) continue; if( iIdxCur+i==iIdxNoSeek ) continue; VdbeModuleComment((v, "GenRowIdxDel for %s", pIdx->zName)); r1 = sqlite3GenerateIndexKey(pParse, pIdx, iDataCur, 0, 1, &iPartIdxLabel, pPrior, r1); sqlite3VdbeAddOp3(v, OP_IdxDelete, iIdxCur+i, r1, pIdx->uniqNotNull ? pIdx->nKeyCol : pIdx->nColumn); sqlite3VdbeChangeP5(v, 1); /* Cause IdxDelete to error if no entry found */ sqlite3ResolvePartIdxLabel(pParse, iPartIdxLabel); pPrior = pIdx; } } /* ** Generate code that will assemble an index key and stores it in register |
︙ | ︙ | |||
908 909 910 911 912 913 914 | Vdbe *v = pParse->pVdbe; int j; int regBase; int nCol; if( piPartIdxLabel ){ if( pIdx->pPartIdxWhere ){ | | > > > | | | | | | | > < < < < | 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 | Vdbe *v = pParse->pVdbe; int j; int regBase; int nCol; if( piPartIdxLabel ){ if( pIdx->pPartIdxWhere ){ *piPartIdxLabel = sqlite3VdbeMakeLabel(pParse); pParse->iSelfTab = iDataCur + 1; sqlite3ExprIfFalseDup(pParse, pIdx->pPartIdxWhere, *piPartIdxLabel, SQLITE_JUMPIFNULL); pParse->iSelfTab = 0; pPrior = 0; /* Ticket a9efb42811fa41ee 2019-11-02; ** pPartIdxWhere may have corrupted regPrior registers */ }else{ *piPartIdxLabel = 0; } } nCol = (prefixOnly && pIdx->uniqNotNull) ? pIdx->nKeyCol : pIdx->nColumn; regBase = sqlite3GetTempRange(pParse, nCol); if( pPrior && (regBase!=regPrior || pPrior->pPartIdxWhere) ) pPrior = 0; for(j=0; j<nCol; j++){ if( pPrior && pPrior->aiColumn[j]==pIdx->aiColumn[j] && pPrior->aiColumn[j]!=XN_EXPR ){ /* This column was already computed by the previous index */ continue; } sqlite3ExprCodeLoadIndexColumn(pParse, pIdx, iDataCur, j, regBase+j); if( pIdx->aiColumn[j]>=0 ){ /* If the column affinity is REAL but the number is an integer, then it ** might be stored in the table as an integer (using a compact ** representation) then converted to REAL by an OP_RealAffinity opcode. ** But we are getting ready to store this value back into an index, where ** it should be converted by to INTEGER again. So omit the ** OP_RealAffinity opcode if it is present */ sqlite3VdbeDeletePriorOpcode(v, OP_RealAffinity); } } if( regOut ){ sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase, nCol, regOut); } sqlite3ReleaseTempRange(pParse, regBase, nCol); return regBase; } /* ** If a prior call to sqlite3GenerateIndexKey() generated a jump-over label |
︙ | ︙ |
Changes to src/expr.c.
︙ | ︙ | |||
17 18 19 20 21 22 23 | /* Forward declarations */ static void exprCodeBetween(Parse*,Expr*,int,void(*)(Parse*,Expr*,int,int),int); static int exprCodeVector(Parse *pParse, Expr *p, int *piToFree); /* ** Return the affinity character for a single column of a table. */ | | | | | > > > > | | > > > > > > > > > | > > < < < < | > > > > > > | | | > > > > | < > > > > > > > > > > > > > | | 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 | /* Forward declarations */ static void exprCodeBetween(Parse*,Expr*,int,void(*)(Parse*,Expr*,int,int),int); static int exprCodeVector(Parse *pParse, Expr *p, int *piToFree); /* ** Return the affinity character for a single column of a table. */ char sqlite3TableColumnAffinity(const Table *pTab, int iCol){ if( iCol<0 || NEVER(iCol>=pTab->nCol) ) return SQLITE_AFF_INTEGER; return pTab->aCol[iCol].affinity; } /* ** Return the 'affinity' of the expression pExpr if any. ** ** If pExpr is a column, a reference to a column via an 'AS' alias, ** or a sub-select with a column as the return value, then the ** affinity of that column is returned. Otherwise, 0x00 is returned, ** indicating no affinity for the expression. ** ** i.e. the WHERE clause expressions in the following statements all ** have an affinity: ** ** CREATE TABLE t1(a); ** SELECT * FROM t1 WHERE a; ** SELECT a AS b FROM t1 WHERE b; ** SELECT * FROM t1 WHERE (select a from t1); */ char sqlite3ExprAffinity(const Expr *pExpr){ int op; while( ExprHasProperty(pExpr, EP_Skip|EP_IfNullRow) ){ assert( pExpr->op==TK_COLLATE || pExpr->op==TK_IF_NULL_ROW || (pExpr->op==TK_REGISTER && pExpr->op2==TK_IF_NULL_ROW) ); pExpr = pExpr->pLeft; assert( pExpr!=0 ); } op = pExpr->op; if( op==TK_REGISTER ) op = pExpr->op2; if( op==TK_COLUMN || op==TK_AGG_COLUMN ){ assert( ExprUseYTab(pExpr) ); if( pExpr->y.pTab ){ return sqlite3TableColumnAffinity(pExpr->y.pTab, pExpr->iColumn); } } if( op==TK_SELECT ){ assert( ExprUseXSelect(pExpr) ); assert( pExpr->x.pSelect!=0 ); assert( pExpr->x.pSelect->pEList!=0 ); assert( pExpr->x.pSelect->pEList->a[0].pExpr!=0 ); return sqlite3ExprAffinity(pExpr->x.pSelect->pEList->a[0].pExpr); } #ifndef SQLITE_OMIT_CAST if( op==TK_CAST ){ assert( !ExprHasProperty(pExpr, EP_IntValue) ); return sqlite3AffinityType(pExpr->u.zToken, 0); } #endif if( op==TK_SELECT_COLUMN ){ assert( pExpr->pLeft!=0 && ExprUseXSelect(pExpr->pLeft) ); assert( pExpr->iColumn < pExpr->iTable ); assert( pExpr->iTable==pExpr->pLeft->x.pSelect->pEList->nExpr ); return sqlite3ExprAffinity( pExpr->pLeft->x.pSelect->pEList->a[pExpr->iColumn].pExpr ); } if( op==TK_VECTOR ){ assert( ExprUseXList(pExpr) ); return sqlite3ExprAffinity(pExpr->x.pList->a[0].pExpr); } return pExpr->affExpr; } /* ** Set the collating sequence for expression pExpr to be the collating ** sequence named by pToken. Return a pointer to a new Expr node that ** implements the COLLATE operator. ** ** If a memory allocation error occurs, that fact is recorded in pParse->db ** and the pExpr parameter is returned unchanged. */ Expr *sqlite3ExprAddCollateToken( const Parse *pParse, /* Parsing context */ Expr *pExpr, /* Add the "COLLATE" clause to this expression */ const Token *pCollName, /* Name of collating sequence */ int dequote /* True to dequote pCollName */ ){ if( pCollName->n>0 ){ Expr *pNew = sqlite3ExprAlloc(pParse->db, TK_COLLATE, pCollName, dequote); if( pNew ){ pNew->pLeft = pExpr; pNew->flags |= EP_Collate|EP_Skip; pExpr = pNew; } } return pExpr; } Expr *sqlite3ExprAddCollateString( const Parse *pParse, /* Parsing context */ Expr *pExpr, /* Add the "COLLATE" clause to this expression */ const char *zC /* The collating sequence name */ ){ Token s; assert( zC!=0 ); sqlite3TokenInit(&s, (char*)zC); return sqlite3ExprAddCollateToken(pParse, pExpr, &s, 0); } /* ** Skip over any TK_COLLATE operators. */ Expr *sqlite3ExprSkipCollate(Expr *pExpr){ while( pExpr && ExprHasProperty(pExpr, EP_Skip) ){ assert( pExpr->op==TK_COLLATE ); pExpr = pExpr->pLeft; } return pExpr; } /* ** Skip over any TK_COLLATE operators and/or any unlikely() ** or likelihood() or likely() functions at the root of an ** expression. */ Expr *sqlite3ExprSkipCollateAndLikely(Expr *pExpr){ while( pExpr && ExprHasProperty(pExpr, EP_Skip|EP_Unlikely) ){ if( ExprHasProperty(pExpr, EP_Unlikely) ){ assert( ExprUseXList(pExpr) ); assert( pExpr->x.pList->nExpr>0 ); assert( pExpr->op==TK_FUNCTION ); pExpr = pExpr->x.pList->a[0].pExpr; }else{ assert( pExpr->op==TK_COLLATE ); pExpr = pExpr->pLeft; } |
︙ | ︙ | |||
130 131 132 133 134 135 136 | ** default collation if pExpr has no defined collation. ** ** The collating sequence might be determined by a COLLATE operator ** or by the presence of a column with a defined collating sequence. ** COLLATE operators take first precedence. Left operands take ** precedence over right operands. */ | | | < | > | < | | | | | | | | > > > > > > > > < < < | | 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 | ** default collation if pExpr has no defined collation. ** ** The collating sequence might be determined by a COLLATE operator ** or by the presence of a column with a defined collating sequence. ** COLLATE operators take first precedence. Left operands take ** precedence over right operands. */ CollSeq *sqlite3ExprCollSeq(Parse *pParse, const Expr *pExpr){ sqlite3 *db = pParse->db; CollSeq *pColl = 0; const Expr *p = pExpr; while( p ){ int op = p->op; if( op==TK_REGISTER ) op = p->op2; if( op==TK_AGG_COLUMN || op==TK_COLUMN || op==TK_TRIGGER ){ assert( ExprUseYTab(p) ); if( p->y.pTab!=0 ){ /* op==TK_REGISTER && p->y.pTab!=0 happens when pExpr was originally ** a TK_COLUMN but was previously evaluated and cached in a register */ int j = p->iColumn; if( j>=0 ){ const char *zColl = sqlite3ColumnColl(&p->y.pTab->aCol[j]); pColl = sqlite3FindCollSeq(db, ENC(db), zColl, 0); } break; } } if( op==TK_CAST || op==TK_UPLUS ){ p = p->pLeft; continue; } if( op==TK_VECTOR ){ assert( ExprUseXList(p) ); p = p->x.pList->a[0].pExpr; continue; } if( op==TK_COLLATE ){ assert( !ExprHasProperty(p, EP_IntValue) ); pColl = sqlite3GetCollSeq(pParse, ENC(db), 0, p->u.zToken); break; } if( p->flags & EP_Collate ){ if( p->pLeft && (p->pLeft->flags & EP_Collate)!=0 ){ p = p->pLeft; }else{ Expr *pNext = p->pRight; /* The Expr.x union is never used at the same time as Expr.pRight */ assert( ExprUseXList(p) ); assert( p->x.pList==0 || p->pRight==0 ); if( p->x.pList!=0 && !db->mallocFailed ){ int i; for(i=0; ALWAYS(i<p->x.pList->nExpr); i++){ if( ExprHasProperty(p->x.pList->a[i].pExpr, EP_Collate) ){ pNext = p->x.pList->a[i].pExpr; break; } } |
︙ | ︙ | |||
199 200 201 202 203 204 205 | ** defautl collation sequence. ** ** See also: sqlite3ExprCollSeq() ** ** The sqlite3ExprCollSeq() routine works the same except that it ** returns NULL if there is no defined collation. */ | | | | | < < < < < | | | | | < | | > | | < < > | > > > > | | > > > > > > > > > > > > > > > > | > > > > > | > | | > > | 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 | ** defautl collation sequence. ** ** See also: sqlite3ExprCollSeq() ** ** The sqlite3ExprCollSeq() routine works the same except that it ** returns NULL if there is no defined collation. */ CollSeq *sqlite3ExprNNCollSeq(Parse *pParse, const Expr *pExpr){ CollSeq *p = sqlite3ExprCollSeq(pParse, pExpr); if( p==0 ) p = pParse->db->pDfltColl; assert( p!=0 ); return p; } /* ** Return TRUE if the two expressions have equivalent collating sequences. */ int sqlite3ExprCollSeqMatch(Parse *pParse, const Expr *pE1, const Expr *pE2){ CollSeq *pColl1 = sqlite3ExprNNCollSeq(pParse, pE1); CollSeq *pColl2 = sqlite3ExprNNCollSeq(pParse, pE2); return sqlite3StrICmp(pColl1->zName, pColl2->zName)==0; } /* ** pExpr is an operand of a comparison operator. aff2 is the ** type affinity of the other operand. This routine returns the ** type affinity that should be used for the comparison operator. */ char sqlite3CompareAffinity(const Expr *pExpr, char aff2){ char aff1 = sqlite3ExprAffinity(pExpr); if( aff1>SQLITE_AFF_NONE && aff2>SQLITE_AFF_NONE ){ /* Both sides of the comparison are columns. If one has numeric ** affinity, use that. Otherwise use no affinity. */ if( sqlite3IsNumericAffinity(aff1) || sqlite3IsNumericAffinity(aff2) ){ return SQLITE_AFF_NUMERIC; }else{ return SQLITE_AFF_BLOB; } }else{ /* One side is a column, the other is not. Use the columns affinity. */ assert( aff1<=SQLITE_AFF_NONE || aff2<=SQLITE_AFF_NONE ); return (aff1<=SQLITE_AFF_NONE ? aff2 : aff1) | SQLITE_AFF_NONE; } } /* ** pExpr is a comparison operator. Return the type affinity that should ** be applied to both operands prior to doing the comparison. */ static char comparisonAffinity(const Expr *pExpr){ char aff; assert( pExpr->op==TK_EQ || pExpr->op==TK_IN || pExpr->op==TK_LT || pExpr->op==TK_GT || pExpr->op==TK_GE || pExpr->op==TK_LE || pExpr->op==TK_NE || pExpr->op==TK_IS || pExpr->op==TK_ISNOT ); assert( pExpr->pLeft ); aff = sqlite3ExprAffinity(pExpr->pLeft); if( pExpr->pRight ){ aff = sqlite3CompareAffinity(pExpr->pRight, aff); }else if( ExprUseXSelect(pExpr) ){ aff = sqlite3CompareAffinity(pExpr->x.pSelect->pEList->a[0].pExpr, aff); }else if( aff==0 ){ aff = SQLITE_AFF_BLOB; } return aff; } /* ** pExpr is a comparison expression, eg. '=', '<', IN(...) etc. ** idx_affinity is the affinity of an indexed column. Return true ** if the index with affinity idx_affinity may be used to implement ** the comparison in pExpr. */ int sqlite3IndexAffinityOk(const Expr *pExpr, char idx_affinity){ char aff = comparisonAffinity(pExpr); if( aff<SQLITE_AFF_TEXT ){ return 1; } if( aff==SQLITE_AFF_TEXT ){ return idx_affinity==SQLITE_AFF_TEXT; } return sqlite3IsNumericAffinity(idx_affinity); } /* ** Return the P5 value that should be used for a binary comparison ** opcode (OP_Eq, OP_Ge etc.) used to compare pExpr1 and pExpr2. */ static u8 binaryCompareP5( const Expr *pExpr1, /* Left operand */ const Expr *pExpr2, /* Right operand */ int jumpIfNull /* Extra flags added to P5 */ ){ u8 aff = (char)sqlite3ExprAffinity(pExpr2); aff = (u8)sqlite3CompareAffinity(pExpr1, aff) | (u8)jumpIfNull; return aff; } /* ** Return a pointer to the collation sequence that should be used by ** a binary comparison operator comparing pLeft and pRight. ** ** If the left hand expression has a collating sequence type, then it is ** used. Otherwise the collation sequence for the right hand expression ** is used, or the default (BINARY) if neither expression has a collating ** type. ** ** Argument pRight (but not pLeft) may be a null pointer. In this case, ** it is not considered. */ CollSeq *sqlite3BinaryCompareCollSeq( Parse *pParse, const Expr *pLeft, const Expr *pRight ){ CollSeq *pColl; assert( pLeft ); if( pLeft->flags & EP_Collate ){ pColl = sqlite3ExprCollSeq(pParse, pLeft); }else if( pRight && (pRight->flags & EP_Collate)!=0 ){ pColl = sqlite3ExprCollSeq(pParse, pRight); }else{ pColl = sqlite3ExprCollSeq(pParse, pLeft); if( !pColl ){ pColl = sqlite3ExprCollSeq(pParse, pRight); } } return pColl; } /* Expresssion p is a comparison operator. Return a collation sequence ** appropriate for the comparison operator. ** ** This is normally just a wrapper around sqlite3BinaryCompareCollSeq(). ** However, if the OP_Commuted flag is set, then the order of the operands ** is reversed in the sqlite3BinaryCompareCollSeq() call so that the ** correct collating sequence is found. */ CollSeq *sqlite3ExprCompareCollSeq(Parse *pParse, const Expr *p){ if( ExprHasProperty(p, EP_Commuted) ){ return sqlite3BinaryCompareCollSeq(pParse, p->pRight, p->pLeft); }else{ return sqlite3BinaryCompareCollSeq(pParse, p->pLeft, p->pRight); } } /* ** Generate code for a comparison operator. */ static int codeCompare( Parse *pParse, /* The parsing (and code generating) context */ Expr *pLeft, /* The left operand */ Expr *pRight, /* The right operand */ int opcode, /* The comparison opcode */ int in1, int in2, /* Register holding operands */ int dest, /* Jump here if true. */ int jumpIfNull, /* If true, jump if either operand is NULL */ int isCommuted /* The comparison has been commuted */ ){ int p5; int addr; CollSeq *p4; if( pParse->nErr ) return 0; if( isCommuted ){ p4 = sqlite3BinaryCompareCollSeq(pParse, pRight, pLeft); }else{ p4 = sqlite3BinaryCompareCollSeq(pParse, pLeft, pRight); } p5 = binaryCompareP5(pLeft, pRight, jumpIfNull); addr = sqlite3VdbeAddOp4(pParse->pVdbe, opcode, in2, dest, in1, (void*)p4, P4_COLLSEQ); sqlite3VdbeChangeP5(pParse->pVdbe, (u8)p5); return addr; } /* ** Return true if expression pExpr is a vector, or false otherwise. ** ** A vector is defined as any expression that results in two or more ** columns of result. Every TK_VECTOR node is an vector because the ** parser will not generate a TK_VECTOR with fewer than two entries. ** But a TK_SELECT might be either a vector or a scalar. It is only ** considered a vector if it has two or more result columns. */ int sqlite3ExprIsVector(const Expr *pExpr){ return sqlite3ExprVectorSize(pExpr)>1; } /* ** If the expression passed as the only argument is of type TK_VECTOR ** return the number of expressions in the vector. Or, if the expression ** is a sub-select, return the number of columns in the sub-select. For ** any other type of expression, return 1. */ int sqlite3ExprVectorSize(const Expr *pExpr){ u8 op = pExpr->op; if( op==TK_REGISTER ) op = pExpr->op2; if( op==TK_VECTOR ){ assert( ExprUseXList(pExpr) ); return pExpr->x.pList->nExpr; }else if( op==TK_SELECT ){ assert( ExprUseXSelect(pExpr) ); return pExpr->x.pSelect->pEList->nExpr; }else{ return 1; } } /* |
︙ | ︙ | |||
395 396 397 398 399 400 401 | ** ** If the vector is a (SELECT ...) then the expression returned is ** just the expression for the i-th term of the result set, and may ** not be ready for evaluation because the table cursor has not yet ** been positioned. */ Expr *sqlite3VectorFieldSubexpr(Expr *pVector, int i){ | | > > | 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 | ** ** If the vector is a (SELECT ...) then the expression returned is ** just the expression for the i-th term of the result set, and may ** not be ready for evaluation because the table cursor has not yet ** been positioned. */ Expr *sqlite3VectorFieldSubexpr(Expr *pVector, int i){ assert( i<sqlite3ExprVectorSize(pVector) || pVector->op==TK_ERROR ); if( sqlite3ExprIsVector(pVector) ){ assert( pVector->op2==0 || pVector->op==TK_REGISTER ); if( pVector->op==TK_SELECT || pVector->op2==TK_SELECT ){ assert( ExprUseXSelect(pVector) ); return pVector->x.pSelect->pEList->a[i].pExpr; }else{ assert( ExprUseXList(pVector) ); return pVector->x.pList->a[i].pExpr; } } return pVector; } /* |
︙ | ︙ | |||
431 432 433 434 435 436 437 | ** A trick to cause a TK_SELECT pVector to be deleted together with ** the returned Expr object is to attach the pVector to the pRight field ** of the returned TK_SELECT_COLUMN Expr object. */ Expr *sqlite3ExprForVectorField( Parse *pParse, /* Parsing context */ Expr *pVector, /* The vector. List of expressions or a sub-SELECT */ | | > | > < | > > > > > > > > > > | | 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 | ** A trick to cause a TK_SELECT pVector to be deleted together with ** the returned Expr object is to attach the pVector to the pRight field ** of the returned TK_SELECT_COLUMN Expr object. */ Expr *sqlite3ExprForVectorField( Parse *pParse, /* Parsing context */ Expr *pVector, /* The vector. List of expressions or a sub-SELECT */ int iField, /* Which column of the vector to return */ int nField /* Total number of columns in the vector */ ){ Expr *pRet; if( pVector->op==TK_SELECT ){ assert( ExprUseXSelect(pVector) ); /* The TK_SELECT_COLUMN Expr node: ** ** pLeft: pVector containing TK_SELECT. Not deleted. ** pRight: not used. But recursively deleted. ** iColumn: Index of a column in pVector ** iTable: 0 or the number of columns on the LHS of an assignment ** pLeft->iTable: First in an array of register holding result, or 0 ** if the result is not yet computed. ** ** sqlite3ExprDelete() specifically skips the recursive delete of ** pLeft on TK_SELECT_COLUMN nodes. But pRight is followed, so pVector ** can be attached to pRight to cause this node to take ownership of ** pVector. Typically there will be multiple TK_SELECT_COLUMN nodes ** with the same pLeft pointer to the pVector, but only one of them ** will own the pVector. */ pRet = sqlite3PExpr(pParse, TK_SELECT_COLUMN, 0, 0); if( pRet ){ pRet->iTable = nField; pRet->iColumn = iField; pRet->pLeft = pVector; } }else{ if( pVector->op==TK_VECTOR ){ Expr **ppVector; assert( ExprUseXList(pVector) ); ppVector = &pVector->x.pList->a[iField].pExpr; pVector = *ppVector; if( IN_RENAME_OBJECT ){ /* This must be a vector UPDATE inside a trigger */ *ppVector = 0; return pVector; } } pRet = sqlite3ExprDup(pParse->db, pVector, 0); } return pRet; } /* ** If expression pExpr is of type TK_SELECT, generate code to evaluate ** it. Return the register in which the result is stored (or, if the ** sub-select returns more than one column, the first in an array ** of registers in which the result is stored). ** ** If pExpr is not a TK_SELECT expression, return 0. */ static int exprCodeSubselect(Parse *pParse, Expr *pExpr){ int reg = 0; #ifndef SQLITE_OMIT_SUBQUERY if( pExpr->op==TK_SELECT ){ reg = sqlite3CodeSubselect(pParse, pExpr); } #endif return reg; } /* ** Argument pVector points to a vector expression - either a TK_VECTOR |
︙ | ︙ | |||
510 511 512 513 514 515 516 | Expr *pVector, /* Vector to extract element from */ int iField, /* Field to extract from pVector */ int regSelect, /* First in array of registers */ Expr **ppExpr, /* OUT: Expression element */ int *pRegFree /* OUT: Temp register to free */ ){ u8 op = pVector->op; | | > > > | | > > | 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 | Expr *pVector, /* Vector to extract element from */ int iField, /* Field to extract from pVector */ int regSelect, /* First in array of registers */ Expr **ppExpr, /* OUT: Expression element */ int *pRegFree /* OUT: Temp register to free */ ){ u8 op = pVector->op; assert( op==TK_VECTOR || op==TK_REGISTER || op==TK_SELECT || op==TK_ERROR ); if( op==TK_REGISTER ){ *ppExpr = sqlite3VectorFieldSubexpr(pVector, iField); return pVector->iTable+iField; } if( op==TK_SELECT ){ assert( ExprUseXSelect(pVector) ); *ppExpr = pVector->x.pSelect->pEList->a[iField].pExpr; return regSelect+iField; } if( op==TK_VECTOR ){ assert( ExprUseXList(pVector) ); *ppExpr = pVector->x.pList->a[iField].pExpr; return sqlite3ExprCodeTemp(pParse, *ppExpr, pRegFree); } return 0; } /* ** Expression pExpr is a comparison between two vector values. Compute ** the result of the comparison (1, 0, or NULL) and write that ** result into register dest. ** |
︙ | ︙ | |||
549 550 551 552 553 554 555 | Expr *pLeft = pExpr->pLeft; Expr *pRight = pExpr->pRight; int nLeft = sqlite3ExprVectorSize(pLeft); int i; int regLeft = 0; int regRight = 0; u8 opx = op; | > | > > > < | | > > | > > | > > > > > > > > > > < < < | < | < < < < > > > > | 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 | Expr *pLeft = pExpr->pLeft; Expr *pRight = pExpr->pRight; int nLeft = sqlite3ExprVectorSize(pLeft); int i; int regLeft = 0; int regRight = 0; u8 opx = op; int addrCmp = 0; int addrDone = sqlite3VdbeMakeLabel(pParse); int isCommuted = ExprHasProperty(pExpr,EP_Commuted); assert( !ExprHasVVAProperty(pExpr,EP_Immutable) ); if( pParse->nErr ) return; if( nLeft!=sqlite3ExprVectorSize(pRight) ){ sqlite3ErrorMsg(pParse, "row value misused"); return; } assert( pExpr->op==TK_EQ || pExpr->op==TK_NE || pExpr->op==TK_IS || pExpr->op==TK_ISNOT || pExpr->op==TK_LT || pExpr->op==TK_GT || pExpr->op==TK_LE || pExpr->op==TK_GE ); assert( pExpr->op==op || (pExpr->op==TK_IS && op==TK_EQ) || (pExpr->op==TK_ISNOT && op==TK_NE) ); assert( p5==0 || pExpr->op!=op ); assert( p5==SQLITE_NULLEQ || pExpr->op==op ); if( op==TK_LE ) opx = TK_LT; if( op==TK_GE ) opx = TK_GT; if( op==TK_NE ) opx = TK_EQ; regLeft = exprCodeSubselect(pParse, pLeft); regRight = exprCodeSubselect(pParse, pRight); sqlite3VdbeAddOp2(v, OP_Integer, 1, dest); for(i=0; 1 /*Loop exits by "break"*/; i++){ int regFree1 = 0, regFree2 = 0; Expr *pL = 0, *pR = 0; int r1, r2; assert( i>=0 && i<nLeft ); if( addrCmp ) sqlite3VdbeJumpHere(v, addrCmp); r1 = exprVectorRegister(pParse, pLeft, i, regLeft, &pL, ®Free1); r2 = exprVectorRegister(pParse, pRight, i, regRight, &pR, ®Free2); addrCmp = sqlite3VdbeCurrentAddr(v); codeCompare(pParse, pL, pR, opx, r1, r2, addrDone, p5, isCommuted); testcase(op==OP_Lt); VdbeCoverageIf(v,op==OP_Lt); testcase(op==OP_Le); VdbeCoverageIf(v,op==OP_Le); testcase(op==OP_Gt); VdbeCoverageIf(v,op==OP_Gt); testcase(op==OP_Ge); VdbeCoverageIf(v,op==OP_Ge); testcase(op==OP_Eq); VdbeCoverageIf(v,op==OP_Eq); testcase(op==OP_Ne); VdbeCoverageIf(v,op==OP_Ne); sqlite3ReleaseTempReg(pParse, regFree1); sqlite3ReleaseTempReg(pParse, regFree2); if( (opx==TK_LT || opx==TK_GT) && i<nLeft-1 ){ addrCmp = sqlite3VdbeAddOp0(v, OP_ElseEq); testcase(opx==TK_LT); VdbeCoverageIf(v,opx==TK_LT); testcase(opx==TK_GT); VdbeCoverageIf(v,opx==TK_GT); } if( p5==SQLITE_NULLEQ ){ sqlite3VdbeAddOp2(v, OP_Integer, 0, dest); }else{ sqlite3VdbeAddOp3(v, OP_ZeroOrNull, r1, dest, r2); } if( i==nLeft-1 ){ break; } if( opx==TK_EQ ){ sqlite3VdbeAddOp2(v, OP_NotNull, dest, addrDone); VdbeCoverage(v); }else{ assert( op==TK_LT || op==TK_GT || op==TK_LE || op==TK_GE ); sqlite3VdbeAddOp2(v, OP_Goto, 0, addrDone); if( i==nLeft-2 ) opx = op; } } sqlite3VdbeJumpHere(v, addrCmp); sqlite3VdbeResolveLabel(v, addrDone); if( op==TK_NE ){ sqlite3VdbeAddOp2(v, OP_Not, dest, dest); } } #if SQLITE_MAX_EXPR_DEPTH>0 /* ** Check that argument nHeight is less than or equal to the maximum ** expression depth allowed. If it is not, leave an error message in ** pParse. |
︙ | ︙ | |||
637 638 639 640 641 642 643 | ** of any expression tree referenced by the structure passed as the ** first argument. ** ** If this maximum height is greater than the current value pointed ** to by pnHeight, the second parameter, then set *pnHeight to that ** value. */ | | | | | | 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 | ** of any expression tree referenced by the structure passed as the ** first argument. ** ** If this maximum height is greater than the current value pointed ** to by pnHeight, the second parameter, then set *pnHeight to that ** value. */ static void heightOfExpr(const Expr *p, int *pnHeight){ if( p ){ if( p->nHeight>*pnHeight ){ *pnHeight = p->nHeight; } } } static void heightOfExprList(const ExprList *p, int *pnHeight){ if( p ){ int i; for(i=0; i<p->nExpr; i++){ heightOfExpr(p->a[i].pExpr, pnHeight); } } } static void heightOfSelect(const Select *pSelect, int *pnHeight){ const Select *p; for(p=pSelect; p; p=p->pPrior){ heightOfExpr(p->pWhere, pnHeight); heightOfExpr(p->pHaving, pnHeight); heightOfExpr(p->pLimit, pnHeight); heightOfExprList(p->pEList, pnHeight); heightOfExprList(p->pGroupBy, pnHeight); heightOfExprList(p->pOrderBy, pnHeight); |
︙ | ︙ | |||
678 679 680 681 682 683 684 | ** Also propagate EP_Propagate flags up from Expr.x.pList to Expr.flags, ** if appropriate. */ static void exprSetHeight(Expr *p){ int nHeight = 0; heightOfExpr(p->pLeft, &nHeight); heightOfExpr(p->pRight, &nHeight); | | | 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 | ** Also propagate EP_Propagate flags up from Expr.x.pList to Expr.flags, ** if appropriate. */ static void exprSetHeight(Expr *p){ int nHeight = 0; heightOfExpr(p->pLeft, &nHeight); heightOfExpr(p->pRight, &nHeight); if( ExprUseXSelect(p) ){ heightOfSelect(p->x.pSelect, &nHeight); }else if( p->x.pList ){ heightOfExprList(p->x.pList, &nHeight); p->flags |= EP_Propagate & sqlite3ExprListFlags(p->x.pList); } p->nHeight = nHeight + 1; } |
︙ | ︙ | |||
705 706 707 708 709 710 711 | sqlite3ExprCheckHeight(pParse, p->nHeight); } /* ** Return the maximum height of any expression tree referenced ** by the select statement passed as an argument. */ | | > | | 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 | sqlite3ExprCheckHeight(pParse, p->nHeight); } /* ** Return the maximum height of any expression tree referenced ** by the select statement passed as an argument. */ int sqlite3SelectExprHeight(const Select *p){ int nHeight = 0; heightOfSelect(p, &nHeight); return nHeight; } #else /* ABOVE: Height enforcement enabled. BELOW: Height enforcement off */ /* ** Propagate all EP_Propagate flags from the Expr.x.pList into ** Expr.flags. */ void sqlite3ExprSetHeightAndFlags(Parse *pParse, Expr *p){ if( pParse->nErr ) return; if( p && ExprUseXList(p) && p->x.pList ){ p->flags |= EP_Propagate & sqlite3ExprListFlags(p->x.pList); } } #define exprSetHeight(y) #endif /* SQLITE_MAX_EXPR_DEPTH>0 */ /* |
︙ | ︙ | |||
768 769 770 771 772 773 774 | pNew = sqlite3DbMallocRawNN(db, sizeof(Expr)+nExtra); if( pNew ){ memset(pNew, 0, sizeof(Expr)); pNew->op = (u8)op; pNew->iAgg = -1; if( pToken ){ if( nExtra==0 ){ | | < | | 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 | pNew = sqlite3DbMallocRawNN(db, sizeof(Expr)+nExtra); if( pNew ){ memset(pNew, 0, sizeof(Expr)); pNew->op = (u8)op; pNew->iAgg = -1; if( pToken ){ if( nExtra==0 ){ pNew->flags |= EP_IntValue|EP_Leaf|(iValue?EP_IsTrue:EP_IsFalse); pNew->u.iValue = iValue; }else{ pNew->u.zToken = (char*)&pNew[1]; assert( pToken->z!=0 || pToken->n==0 ); if( pToken->n ) memcpy(pNew->u.zToken, pToken->z, pToken->n); pNew->u.zToken[pToken->n] = 0; if( dequote && sqlite3Isquote(pNew->u.zToken[0]) ){ sqlite3DequoteExpr(pNew); } } } #if SQLITE_MAX_EXPR_DEPTH>0 pNew->nHeight = 1; #endif } |
︙ | ︙ | |||
846 847 848 849 850 851 852 | Expr *sqlite3PExpr( Parse *pParse, /* Parsing context */ int op, /* Expression opcode */ Expr *pLeft, /* Left operand */ Expr *pRight /* Right operand */ ){ Expr *p; | < < < < | | | | | < < < > > > < | > | | | | | > > > | > > | < < > > > > > > > > > > | > > | > | | > > | | | > | > > > > > > > > | > > > | | | > | | > > | | | < < | | > | > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | Expr *sqlite3PExpr( Parse *pParse, /* Parsing context */ int op, /* Expression opcode */ Expr *pLeft, /* Left operand */ Expr *pRight /* Right operand */ ){ Expr *p; p = sqlite3DbMallocRawNN(pParse->db, sizeof(Expr)); if( p ){ memset(p, 0, sizeof(Expr)); p->op = op & 0xff; p->iAgg = -1; sqlite3ExprAttachSubtrees(pParse->db, p, pLeft, pRight); sqlite3ExprCheckHeight(pParse, p->nHeight); }else{ sqlite3ExprDelete(pParse->db, pLeft); sqlite3ExprDelete(pParse->db, pRight); } return p; } /* ** Add pSelect to the Expr.x.pSelect field. Or, if pExpr is NULL (due ** do a memory allocation failure) then delete the pSelect object. */ void sqlite3PExprAddSelect(Parse *pParse, Expr *pExpr, Select *pSelect){ if( pExpr ){ pExpr->x.pSelect = pSelect; ExprSetProperty(pExpr, EP_xIsSelect|EP_Subquery); sqlite3ExprSetHeightAndFlags(pParse, pExpr); }else{ assert( pParse->db->mallocFailed ); sqlite3SelectDelete(pParse->db, pSelect); } } /* ** Expression list pEList is a list of vector values. This function ** converts the contents of pEList to a VALUES(...) Select statement ** returning 1 row for each element of the list. For example, the ** expression list: ** ** ( (1,2), (3,4) (5,6) ) ** ** is translated to the equivalent of: ** ** VALUES(1,2), (3,4), (5,6) ** ** Each of the vector values in pEList must contain exactly nElem terms. ** If a list element that is not a vector or does not contain nElem terms, ** an error message is left in pParse. ** ** This is used as part of processing IN(...) expressions with a list ** of vectors on the RHS. e.g. "... IN ((1,2), (3,4), (5,6))". */ Select *sqlite3ExprListToValues(Parse *pParse, int nElem, ExprList *pEList){ int ii; Select *pRet = 0; assert( nElem>1 ); for(ii=0; ii<pEList->nExpr; ii++){ Select *pSel; Expr *pExpr = pEList->a[ii].pExpr; int nExprElem; if( pExpr->op==TK_VECTOR ){ assert( ExprUseXList(pExpr) ); nExprElem = pExpr->x.pList->nExpr; }else{ nExprElem = 1; } if( nExprElem!=nElem ){ sqlite3ErrorMsg(pParse, "IN(...) element has %d term%s - expected %d", nExprElem, nExprElem>1?"s":"", nElem ); break; } assert( ExprUseXList(pExpr) ); pSel = sqlite3SelectNew(pParse, pExpr->x.pList, 0, 0, 0, 0, 0, SF_Values,0); pExpr->x.pList = 0; if( pSel ){ if( pRet ){ pSel->op = TK_ALL; pSel->pPrior = pRet; } pRet = pSel; } } if( pRet && pRet->pPrior ){ pRet->selFlags |= SF_MultiValue; } sqlite3ExprListDelete(pParse->db, pEList); return pRet; } /* ** Join two expressions using an AND operator. If either expression is ** NULL, then just return the other expression. ** ** If one side or the other of the AND is known to be false, then instead ** of returning an AND expression, just return a constant expression with ** a value of false. */ Expr *sqlite3ExprAnd(Parse *pParse, Expr *pLeft, Expr *pRight){ sqlite3 *db = pParse->db; if( pLeft==0 ){ return pRight; }else if( pRight==0 ){ return pLeft; }else if( (ExprAlwaysFalse(pLeft) || ExprAlwaysFalse(pRight)) && !IN_RENAME_OBJECT ){ sqlite3ExprDeferredDelete(pParse, pLeft); sqlite3ExprDeferredDelete(pParse, pRight); return sqlite3Expr(db, TK_INTEGER, "0"); }else{ return sqlite3PExpr(pParse, TK_AND, pLeft, pRight); } } /* ** Construct a new expression node for a function with multiple ** arguments. */ Expr *sqlite3ExprFunction( Parse *pParse, /* Parsing context */ ExprList *pList, /* Argument list */ const Token *pToken, /* Name of the function */ int eDistinct /* SF_Distinct or SF_ALL or 0 */ ){ Expr *pNew; sqlite3 *db = pParse->db; assert( pToken ); pNew = sqlite3ExprAlloc(db, TK_FUNCTION, pToken, 1); if( pNew==0 ){ sqlite3ExprListDelete(db, pList); /* Avoid memory leak when malloc fails */ return 0; } if( pList && pList->nExpr > pParse->db->aLimit[SQLITE_LIMIT_FUNCTION_ARG] && !pParse->nested ){ sqlite3ErrorMsg(pParse, "too many arguments on function %T", pToken); } pNew->x.pList = pList; ExprSetProperty(pNew, EP_HasFunc); assert( ExprUseXList(pNew) ); sqlite3ExprSetHeightAndFlags(pParse, pNew); if( eDistinct==SF_Distinct ) ExprSetProperty(pNew, EP_Distinct); return pNew; } /* ** Check to see if a function is usable according to current access ** rules: ** ** SQLITE_FUNC_DIRECT - Only usable from top-level SQL ** ** SQLITE_FUNC_UNSAFE - Usable if TRUSTED_SCHEMA or from ** top-level SQL ** ** If the function is not usable, create an error. */ void sqlite3ExprFunctionUsable( Parse *pParse, /* Parsing and code generating context */ const Expr *pExpr, /* The function invocation */ const FuncDef *pDef /* The function being invoked */ ){ assert( !IN_RENAME_OBJECT ); assert( (pDef->funcFlags & (SQLITE_FUNC_DIRECT|SQLITE_FUNC_UNSAFE))!=0 ); if( ExprHasProperty(pExpr, EP_FromDDL) ){ if( (pDef->funcFlags & SQLITE_FUNC_DIRECT)!=0 || (pParse->db->flags & SQLITE_TrustedSchema)==0 ){ /* Functions prohibited in triggers and views if: ** (1) tagged with SQLITE_DIRECTONLY ** (2) not tagged with SQLITE_INNOCUOUS (which means it ** is tagged with SQLITE_FUNC_UNSAFE) and ** SQLITE_DBCONFIG_TRUSTED_SCHEMA is off (meaning ** that the schema is possibly tainted). */ sqlite3ErrorMsg(pParse, "unsafe use of %s()", pDef->zName); } } } /* ** Assign a variable number to an expression that encodes a wildcard ** in the original SQL statement. ** ** Wildcards consisting of a single "?" are assigned the next sequential ** variable number. |
︙ | ︙ | |||
1046 1047 1048 1049 1050 1051 1052 | } /* ** Recursively delete an expression tree. */ static SQLITE_NOINLINE void sqlite3ExprDeleteNN(sqlite3 *db, Expr *p){ assert( p!=0 ); | < | | | | < | > | > > | < > | < | | > | > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | 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 | } /* ** Recursively delete an expression tree. */ static SQLITE_NOINLINE void sqlite3ExprDeleteNN(sqlite3 *db, Expr *p){ assert( p!=0 ); assert( !ExprUseUValue(p) || p->u.iValue>=0 ); assert( !ExprUseYWin(p) || !ExprUseYSub(p) ); assert( !ExprUseYWin(p) || p->y.pWin!=0 || db->mallocFailed ); assert( p->op!=TK_FUNCTION || !ExprUseYSub(p) ); #ifdef SQLITE_DEBUG if( ExprHasProperty(p, EP_Leaf) && !ExprHasProperty(p, EP_TokenOnly) ){ assert( p->pLeft==0 ); assert( p->pRight==0 ); assert( !ExprUseXSelect(p) || p->x.pSelect==0 ); assert( !ExprUseXList(p) || p->x.pList==0 ); } #endif if( !ExprHasProperty(p, (EP_TokenOnly|EP_Leaf)) ){ /* The Expr.x union is never used at the same time as Expr.pRight */ assert( (ExprUseXList(p) && p->x.pList==0) || p->pRight==0 ); if( p->pLeft && p->op!=TK_SELECT_COLUMN ) sqlite3ExprDeleteNN(db, p->pLeft); if( p->pRight ){ assert( !ExprHasProperty(p, EP_WinFunc) ); sqlite3ExprDeleteNN(db, p->pRight); }else if( ExprUseXSelect(p) ){ assert( !ExprHasProperty(p, EP_WinFunc) ); sqlite3SelectDelete(db, p->x.pSelect); }else{ sqlite3ExprListDelete(db, p->x.pList); #ifndef SQLITE_OMIT_WINDOWFUNC if( ExprHasProperty(p, EP_WinFunc) ){ sqlite3WindowDelete(db, p->y.pWin); } #endif } } if( ExprHasProperty(p, EP_MemToken) ){ assert( !ExprHasProperty(p, EP_IntValue) ); sqlite3DbFree(db, p->u.zToken); } if( !ExprHasProperty(p, EP_Static) ){ sqlite3DbFreeNN(db, p); } } void sqlite3ExprDelete(sqlite3 *db, Expr *p){ if( p ) sqlite3ExprDeleteNN(db, p); } /* ** Arrange to cause pExpr to be deleted when the pParse is deleted. ** This is similar to sqlite3ExprDelete() except that the delete is ** deferred untilthe pParse is deleted. ** ** The pExpr might be deleted immediately on an OOM error. ** ** The deferred delete is (currently) implemented by adding the ** pExpr to the pParse->pConstExpr list with a register number of 0. */ void sqlite3ExprDeferredDelete(Parse *pParse, Expr *pExpr){ pParse->pConstExpr = sqlite3ExprListAppend(pParse, pParse->pConstExpr, pExpr); } /* Invoke sqlite3RenameExprUnmap() and sqlite3ExprDelete() on the ** expression. */ void sqlite3ExprUnmapAndDelete(Parse *pParse, Expr *p){ if( p ){ if( IN_RENAME_OBJECT ){ sqlite3RenameExprUnmap(pParse, p); } sqlite3ExprDeleteNN(pParse->db, p); } } /* ** Return the number of bytes allocated for the expression structure ** passed as the first argument. This is always one of EXPR_FULLSIZE, ** EXPR_REDUCEDSIZE or EXPR_TOKENONLYSIZE. */ static int exprStructSize(const Expr *p){ if( ExprHasProperty(p, EP_TokenOnly) ) return EXPR_TOKENONLYSIZE; if( ExprHasProperty(p, EP_Reduced) ) return EXPR_REDUCEDSIZE; return EXPR_FULLSIZE; } /* ** The dupedExpr*Size() routines each return the number of bytes required |
︙ | ︙ | |||
1129 1130 1131 1132 1133 1134 1135 | ** later parts of the Expr object and that extra information might get chopped ** off if the expression is reduced. Note also that it does not work to ** make an EXPRDUP_REDUCE copy of a reduced expression. It is only legal ** to reduce a pristine expression tree from the parser. The implementation ** of dupedExprStructSize() contain multiple assert() statements that attempt ** to enforce this constraint. */ | | | | | | > | 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 | ** later parts of the Expr object and that extra information might get chopped ** off if the expression is reduced. Note also that it does not work to ** make an EXPRDUP_REDUCE copy of a reduced expression. It is only legal ** to reduce a pristine expression tree from the parser. The implementation ** of dupedExprStructSize() contain multiple assert() statements that attempt ** to enforce this constraint. */ static int dupedExprStructSize(const Expr *p, int flags){ int nSize; assert( flags==EXPRDUP_REDUCE || flags==0 ); /* Only one flag value allowed */ assert( EXPR_FULLSIZE<=0xfff ); assert( (0xfff & (EP_Reduced|EP_TokenOnly))==0 ); if( 0==flags || p->op==TK_SELECT_COLUMN #ifndef SQLITE_OMIT_WINDOWFUNC || ExprHasProperty(p, EP_WinFunc) #endif ){ nSize = EXPR_FULLSIZE; }else{ assert( !ExprHasProperty(p, EP_TokenOnly|EP_Reduced) ); assert( !ExprHasProperty(p, EP_FromJoin) ); assert( !ExprHasProperty(p, EP_MemToken) ); assert( !ExprHasVVAProperty(p, EP_NoReduce) ); if( p->pLeft || p->x.pList ){ nSize = EXPR_REDUCEDSIZE | EP_Reduced; }else{ assert( p->pRight==0 ); nSize = EXPR_TOKENONLYSIZE | EP_TokenOnly; } } return nSize; } /* ** This function returns the space in bytes required to store the copy ** of the Expr structure and a copy of the Expr.u.zToken string (if that ** string is defined.) */ static int dupedExprNodeSize(const Expr *p, int flags){ int nByte = dupedExprStructSize(p, flags) & 0xfff; if( !ExprHasProperty(p, EP_IntValue) && p->u.zToken ){ nByte += sqlite3Strlen30NN(p->u.zToken)+1; } return ROUND8(nByte); } /* ** Return the number of bytes required to create a duplicate of the ** expression passed as the first argument. The second argument is a ** mask containing EXPRDUP_XXX flags. ** ** The value returned includes space to create a copy of the Expr struct ** itself and the buffer referred to by Expr.u.zToken, if any. ** ** If the EXPRDUP_REDUCE flag is set, then the return value includes ** space to duplicate all Expr nodes in the tree formed by Expr.pLeft ** and Expr.pRight variables (but not for any structures pointed to or ** descended from the Expr.x.pList or Expr.x.pSelect variables). */ static int dupedExprSize(const Expr *p, int flags){ int nByte = 0; if( p ){ nByte = dupedExprNodeSize(p, flags); if( flags&EXPRDUP_REDUCE ){ nByte += dupedExprSize(p->pLeft, flags) + dupedExprSize(p->pRight, flags); } } return nByte; } /* ** This function is similar to sqlite3ExprDup(), except that if pzBuffer ** is not NULL then *pzBuffer is assumed to point to a buffer large enough ** to store the copy of expression p, the copies of p->u.zToken ** (if applicable), and the copies of the p->pLeft and p->pRight expressions, ** if any. Before returning, *pzBuffer is set to the first byte past the ** portion of the buffer copied into by this function. */ static Expr *exprDup(sqlite3 *db, const Expr *p, int dupFlags, u8 **pzBuffer){ Expr *pNew; /* Value to return */ u8 *zAlloc; /* Memory space from which to build Expr object */ u32 staticFlag; /* EP_Static if space not obtained from malloc */ assert( db!=0 ); assert( p ); assert( dupFlags==0 || dupFlags==EXPRDUP_REDUCE ); assert( pzBuffer==0 || dupFlags==EXPRDUP_REDUCE ); /* Figure out where to write the new Expr structure. */ if( pzBuffer ){ zAlloc = *pzBuffer; staticFlag = EP_Static; assert( zAlloc!=0 ); }else{ zAlloc = sqlite3DbMallocRawNN(db, dupedExprSize(p, dupFlags)); staticFlag = 0; } pNew = (Expr *)zAlloc; if( pNew ){ |
︙ | ︙ | |||
1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 | } } /* Set the EP_Reduced, EP_TokenOnly, and EP_Static flags appropriately. */ pNew->flags &= ~(EP_Reduced|EP_TokenOnly|EP_Static|EP_MemToken); pNew->flags |= nStructSize & (EP_Reduced|EP_TokenOnly); pNew->flags |= staticFlag; /* Copy the p->u.zToken string, if any. */ if( nToken ){ char *zToken = pNew->u.zToken = (char*)&zAlloc[nNewSize]; memcpy(zToken, p->u.zToken, nToken); } if( 0==((p->flags|pNew->flags) & (EP_TokenOnly|EP_Leaf)) ){ /* Fill in the pNew->x.pSelect or pNew->x.pList member. */ | > > > > | | 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 | } } /* Set the EP_Reduced, EP_TokenOnly, and EP_Static flags appropriately. */ pNew->flags &= ~(EP_Reduced|EP_TokenOnly|EP_Static|EP_MemToken); pNew->flags |= nStructSize & (EP_Reduced|EP_TokenOnly); pNew->flags |= staticFlag; ExprClearVVAProperties(pNew); if( dupFlags ){ ExprSetVVAProperty(pNew, EP_Immutable); } /* Copy the p->u.zToken string, if any. */ if( nToken ){ char *zToken = pNew->u.zToken = (char*)&zAlloc[nNewSize]; memcpy(zToken, p->u.zToken, nToken); } if( 0==((p->flags|pNew->flags) & (EP_TokenOnly|EP_Leaf)) ){ /* Fill in the pNew->x.pSelect or pNew->x.pList member. */ if( ExprUseXSelect(p) ){ pNew->x.pSelect = sqlite3SelectDup(db, p->x.pSelect, dupFlags); }else{ pNew->x.pList = sqlite3ExprListDup(db, p->x.pList, dupFlags); } } /* Fill in pNew->pLeft and pNew->pRight. */ |
︙ | ︙ | |||
1287 1288 1289 1290 1291 1292 1293 | if( pzBuffer ){ *pzBuffer = zAlloc; } }else{ if( !ExprHasProperty(p, EP_TokenOnly|EP_Leaf) ){ if( pNew->op==TK_SELECT_COLUMN ){ pNew->pLeft = p->pLeft; | < | > | | | | < | | > > > > > | 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 | if( pzBuffer ){ *pzBuffer = zAlloc; } }else{ if( !ExprHasProperty(p, EP_TokenOnly|EP_Leaf) ){ if( pNew->op==TK_SELECT_COLUMN ){ pNew->pLeft = p->pLeft; assert( p->pRight==0 || p->pRight==p->pLeft || ExprHasProperty(p->pLeft, EP_Subquery) ); }else{ pNew->pLeft = sqlite3ExprDup(db, p->pLeft, 0); } pNew->pRight = sqlite3ExprDup(db, p->pRight, 0); } } } return pNew; } /* ** Create and return a deep copy of the object passed as the second ** argument. If an OOM condition is encountered, NULL is returned ** and the db->mallocFailed flag set. */ #ifndef SQLITE_OMIT_CTE With *sqlite3WithDup(sqlite3 *db, With *p){ With *pRet = 0; if( p ){ sqlite3_int64 nByte = sizeof(*p) + sizeof(p->a[0]) * (p->nCte-1); pRet = sqlite3DbMallocZero(db, nByte); if( pRet ){ int i; pRet->nCte = p->nCte; for(i=0; i<p->nCte; i++){ pRet->a[i].pSelect = sqlite3SelectDup(db, p->a[i].pSelect, 0); pRet->a[i].pCols = sqlite3ExprListDup(db, p->a[i].pCols, 0); pRet->a[i].zName = sqlite3DbStrDup(db, p->a[i].zName); } } } return pRet; } #else # define sqlite3WithDup(x,y) 0 #endif #ifndef SQLITE_OMIT_WINDOWFUNC /* ** The gatherSelectWindows() procedure and its helper routine ** gatherSelectWindowsCallback() are used to scan all the expressions ** an a newly duplicated SELECT statement and gather all of the Window ** objects found there, assembling them onto the linked list at Select->pWin. */ static int gatherSelectWindowsCallback(Walker *pWalker, Expr *pExpr){ if( pExpr->op==TK_FUNCTION && ExprHasProperty(pExpr, EP_WinFunc) ){ Select *pSelect = pWalker->u.pSelect; Window *pWin = pExpr->y.pWin; assert( pWin ); assert( IsWindowFunc(pExpr) ); assert( pWin->ppThis==0 ); sqlite3WindowLink(pSelect, pWin); } return WRC_Continue; } static int gatherSelectWindowsSelectCallback(Walker *pWalker, Select *p){ return p==pWalker->u.pSelect ? WRC_Continue : WRC_Prune; } static void gatherSelectWindows(Select *p){ Walker w; w.xExprCallback = gatherSelectWindowsCallback; w.xSelectCallback = gatherSelectWindowsSelectCallback; w.xSelectCallback2 = 0; w.pParse = 0; w.u.pSelect = p; sqlite3WalkSelect(&w, p); } #endif /* |
︙ | ︙ | |||
1372 1373 1374 1375 1376 1377 1378 | ** Any tables that the SrcList might point to are not duplicated. ** ** The flags parameter contains a combination of the EXPRDUP_XXX flags. ** If the EXPRDUP_REDUCE flag is set, then the structure returned is a ** truncated version of the usual Expr structure that will be stored as ** part of the in-memory representation of the database schema. */ | | | | > | > > < | | > | | | | | > | | | | | | | | | > > > | | 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 | ** Any tables that the SrcList might point to are not duplicated. ** ** The flags parameter contains a combination of the EXPRDUP_XXX flags. ** If the EXPRDUP_REDUCE flag is set, then the structure returned is a ** truncated version of the usual Expr structure that will be stored as ** part of the in-memory representation of the database schema. */ Expr *sqlite3ExprDup(sqlite3 *db, const Expr *p, int flags){ assert( flags==0 || flags==EXPRDUP_REDUCE ); return p ? exprDup(db, p, flags, 0) : 0; } ExprList *sqlite3ExprListDup(sqlite3 *db, const ExprList *p, int flags){ ExprList *pNew; struct ExprList_item *pItem; const struct ExprList_item *pOldItem; int i; Expr *pPriorSelectColOld = 0; Expr *pPriorSelectColNew = 0; assert( db!=0 ); if( p==0 ) return 0; pNew = sqlite3DbMallocRawNN(db, sqlite3DbMallocSize(db, p)); if( pNew==0 ) return 0; pNew->nExpr = p->nExpr; pNew->nAlloc = p->nAlloc; pItem = pNew->a; pOldItem = p->a; for(i=0; i<p->nExpr; i++, pItem++, pOldItem++){ Expr *pOldExpr = pOldItem->pExpr; Expr *pNewExpr; pItem->pExpr = sqlite3ExprDup(db, pOldExpr, flags); if( pOldExpr && pOldExpr->op==TK_SELECT_COLUMN && (pNewExpr = pItem->pExpr)!=0 ){ if( pNewExpr->pRight ){ pPriorSelectColOld = pOldExpr->pRight; pPriorSelectColNew = pNewExpr->pRight; pNewExpr->pLeft = pNewExpr->pRight; }else{ if( pOldExpr->pLeft!=pPriorSelectColOld ){ pPriorSelectColOld = pOldExpr->pLeft; pPriorSelectColNew = sqlite3ExprDup(db, pPriorSelectColOld, flags); pNewExpr->pRight = pPriorSelectColNew; } pNewExpr->pLeft = pPriorSelectColNew; } } pItem->zEName = sqlite3DbStrDup(db, pOldItem->zEName); pItem->sortFlags = pOldItem->sortFlags; pItem->eEName = pOldItem->eEName; pItem->done = 0; pItem->bNulls = pOldItem->bNulls; pItem->bSorterRef = pOldItem->bSorterRef; pItem->u = pOldItem->u; } return pNew; } /* ** If cursors, triggers, views and subqueries are all omitted from ** the build, then none of the following routines, except for ** sqlite3SelectDup(), can be called. sqlite3SelectDup() is sometimes ** called with a NULL argument. */ #if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER) \ || !defined(SQLITE_OMIT_SUBQUERY) SrcList *sqlite3SrcListDup(sqlite3 *db, const SrcList *p, int flags){ SrcList *pNew; int i; int nByte; assert( db!=0 ); if( p==0 ) return 0; nByte = sizeof(*p) + (p->nSrc>0 ? sizeof(p->a[0]) * (p->nSrc-1) : 0); pNew = sqlite3DbMallocRawNN(db, nByte ); if( pNew==0 ) return 0; pNew->nSrc = pNew->nAlloc = p->nSrc; for(i=0; i<p->nSrc; i++){ SrcItem *pNewItem = &pNew->a[i]; const SrcItem *pOldItem = &p->a[i]; Table *pTab; pNewItem->pSchema = pOldItem->pSchema; pNewItem->zDatabase = sqlite3DbStrDup(db, pOldItem->zDatabase); pNewItem->zName = sqlite3DbStrDup(db, pOldItem->zName); pNewItem->zAlias = sqlite3DbStrDup(db, pOldItem->zAlias); pNewItem->fg = pOldItem->fg; pNewItem->iCursor = pOldItem->iCursor; pNewItem->addrFillSub = pOldItem->addrFillSub; pNewItem->regReturn = pOldItem->regReturn; if( pNewItem->fg.isIndexedBy ){ pNewItem->u1.zIndexedBy = sqlite3DbStrDup(db, pOldItem->u1.zIndexedBy); } pNewItem->u2 = pOldItem->u2; if( pNewItem->fg.isCte ){ pNewItem->u2.pCteUse->nUse++; } if( pNewItem->fg.isTabFunc ){ pNewItem->u1.pFuncArg = sqlite3ExprListDup(db, pOldItem->u1.pFuncArg, flags); } pTab = pNewItem->pTab = pOldItem->pTab; if( pTab ){ pTab->nTabRef++; } pNewItem->pSelect = sqlite3SelectDup(db, pOldItem->pSelect, flags); pNewItem->pOn = sqlite3ExprDup(db, pOldItem->pOn, flags); pNewItem->pUsing = sqlite3IdListDup(db, pOldItem->pUsing); pNewItem->colUsed = pOldItem->colUsed; } return pNew; } IdList *sqlite3IdListDup(sqlite3 *db, const IdList *p){ IdList *pNew; int i; assert( db!=0 ); if( p==0 ) return 0; pNew = sqlite3DbMallocRawNN(db, sizeof(*pNew) ); if( pNew==0 ) return 0; pNew->nId = p->nId; |
︙ | ︙ | |||
1492 1493 1494 1495 1496 1497 1498 | struct IdList_item *pNewItem = &pNew->a[i]; struct IdList_item *pOldItem = &p->a[i]; pNewItem->zName = sqlite3DbStrDup(db, pOldItem->zName); pNewItem->idx = pOldItem->idx; } return pNew; } | | | | 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 | struct IdList_item *pNewItem = &pNew->a[i]; struct IdList_item *pOldItem = &p->a[i]; pNewItem->zName = sqlite3DbStrDup(db, pOldItem->zName); pNewItem->idx = pOldItem->idx; } return pNew; } Select *sqlite3SelectDup(sqlite3 *db, const Select *pDup, int flags){ Select *pRet = 0; Select *pNext = 0; Select **pp = &pRet; const Select *p; assert( db!=0 ); for(p=pDup; p; p=p->pPrior){ Select *pNew = sqlite3DbMallocRawNN(db, sizeof(*p) ); if( pNew==0 ) break; pNew->pEList = sqlite3ExprListDup(db, p->pEList, flags); pNew->pSrc = sqlite3SrcListDup(db, p->pSrc, flags); |
︙ | ︙ | |||
1518 1519 1520 1521 1522 1523 1524 | pNew->pLimit = sqlite3ExprDup(db, p->pLimit, flags); pNew->iLimit = 0; pNew->iOffset = 0; pNew->selFlags = p->selFlags & ~SF_UsesEphemeral; pNew->addrOpenEphm[0] = -1; pNew->addrOpenEphm[1] = -1; pNew->nSelectRow = p->nSelectRow; | | | > > > > > > > > | | 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 | pNew->pLimit = sqlite3ExprDup(db, p->pLimit, flags); pNew->iLimit = 0; pNew->iOffset = 0; pNew->selFlags = p->selFlags & ~SF_UsesEphemeral; pNew->addrOpenEphm[0] = -1; pNew->addrOpenEphm[1] = -1; pNew->nSelectRow = p->nSelectRow; pNew->pWith = sqlite3WithDup(db, p->pWith); #ifndef SQLITE_OMIT_WINDOWFUNC pNew->pWin = 0; pNew->pWinDefn = sqlite3WindowListDup(db, p->pWinDefn); if( p->pWin && db->mallocFailed==0 ) gatherSelectWindows(pNew); #endif pNew->selId = p->selId; if( db->mallocFailed ){ /* Any prior OOM might have left the Select object incomplete. ** Delete the whole thing rather than allow an incomplete Select ** to be used by the code generator. */ pNew->pNext = 0; sqlite3SelectDelete(db, pNew); break; } *pp = pNew; pp = &pNew->pPrior; pNext = pNew; } return pRet; } #else Select *sqlite3SelectDup(sqlite3 *db, const Select *p, int flags){ assert( p==0 ); return 0; } #endif /* |
︙ | ︙ | |||
1555 1556 1557 1558 1559 1560 1561 | ** is a power of two. That is true for sqlite3ExprListAppend() returns ** but is not necessarily true from the return value of sqlite3ExprListDup(). ** ** If a memory allocation error occurs, the entire list is freed and ** NULL is returned. If non-NULL is returned, then it is guaranteed ** that the new entry was successfully appended. */ | > | | < | | < | | > | | > | | > > > > > > > > > > | > | | | > > > | > | > > > | > > > > > > > > > > > > < < | < < < < < < | 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 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 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 | ** is a power of two. That is true for sqlite3ExprListAppend() returns ** but is not necessarily true from the return value of sqlite3ExprListDup(). ** ** If a memory allocation error occurs, the entire list is freed and ** NULL is returned. If non-NULL is returned, then it is guaranteed ** that the new entry was successfully appended. */ static const struct ExprList_item zeroItem = {0}; SQLITE_NOINLINE ExprList *sqlite3ExprListAppendNew( sqlite3 *db, /* Database handle. Used for memory allocation */ Expr *pExpr /* Expression to be appended. Might be NULL */ ){ struct ExprList_item *pItem; ExprList *pList; pList = sqlite3DbMallocRawNN(db, sizeof(ExprList)+sizeof(pList->a[0])*4 ); if( pList==0 ){ sqlite3ExprDelete(db, pExpr); return 0; } pList->nAlloc = 4; pList->nExpr = 1; pItem = &pList->a[0]; *pItem = zeroItem; pItem->pExpr = pExpr; return pList; } SQLITE_NOINLINE ExprList *sqlite3ExprListAppendGrow( sqlite3 *db, /* Database handle. Used for memory allocation */ ExprList *pList, /* List to which to append. Might be NULL */ Expr *pExpr /* Expression to be appended. Might be NULL */ ){ struct ExprList_item *pItem; ExprList *pNew; pList->nAlloc *= 2; pNew = sqlite3DbRealloc(db, pList, sizeof(*pList)+(pList->nAlloc-1)*sizeof(pList->a[0])); if( pNew==0 ){ sqlite3ExprListDelete(db, pList); sqlite3ExprDelete(db, pExpr); return 0; }else{ pList = pNew; } pItem = &pList->a[pList->nExpr++]; *pItem = zeroItem; pItem->pExpr = pExpr; return pList; } ExprList *sqlite3ExprListAppend( Parse *pParse, /* Parsing context */ ExprList *pList, /* List to which to append. Might be NULL */ Expr *pExpr /* Expression to be appended. Might be NULL */ ){ struct ExprList_item *pItem; if( pList==0 ){ return sqlite3ExprListAppendNew(pParse->db,pExpr); } if( pList->nAlloc<pList->nExpr+1 ){ return sqlite3ExprListAppendGrow(pParse->db,pList,pExpr); } pItem = &pList->a[pList->nExpr++]; *pItem = zeroItem; pItem->pExpr = pExpr; return pList; } /* ** pColumns and pExpr form a vector assignment which is part of the SET ** clause of an UPDATE statement. Like this: ** ** (a,b,c) = (expr1,expr2,expr3) |
︙ | ︙ | |||
1630 1631 1632 1633 1634 1635 1636 | if( pExpr->op!=TK_SELECT && pColumns->nId!=(n=sqlite3ExprVectorSize(pExpr)) ){ sqlite3ErrorMsg(pParse, "%d columns assigned %d values", pColumns->nId, n); goto vector_append_error; } for(i=0; i<pColumns->nId; i++){ | | > > | | | > > > | | | | > > > > > | > > > > | > > > > > > > | | > | > | | > > > > | | > | 1864 1865 1866 1867 1868 1869 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 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 | if( pExpr->op!=TK_SELECT && pColumns->nId!=(n=sqlite3ExprVectorSize(pExpr)) ){ sqlite3ErrorMsg(pParse, "%d columns assigned %d values", pColumns->nId, n); goto vector_append_error; } for(i=0; i<pColumns->nId; i++){ Expr *pSubExpr = sqlite3ExprForVectorField(pParse, pExpr, i, pColumns->nId); assert( pSubExpr!=0 || db->mallocFailed ); if( pSubExpr==0 ) continue; pList = sqlite3ExprListAppend(pParse, pList, pSubExpr); if( pList ){ assert( pList->nExpr==iFirst+i+1 ); pList->a[pList->nExpr-1].zEName = pColumns->a[i].zName; pColumns->a[i].zName = 0; } } if( !db->mallocFailed && pExpr->op==TK_SELECT && ALWAYS(pList!=0) ){ Expr *pFirst = pList->a[iFirst].pExpr; assert( pFirst!=0 ); assert( pFirst->op==TK_SELECT_COLUMN ); /* Store the SELECT statement in pRight so it will be deleted when ** sqlite3ExprListDelete() is called */ pFirst->pRight = pExpr; pExpr = 0; /* Remember the size of the LHS in iTable so that we can check that ** the RHS and LHS sizes match during code generation. */ pFirst->iTable = pColumns->nId; } vector_append_error: sqlite3ExprUnmapAndDelete(pParse, pExpr); sqlite3IdListDelete(db, pColumns); return pList; } /* ** Set the sort order for the last element on the given ExprList. */ void sqlite3ExprListSetSortOrder(ExprList *p, int iSortOrder, int eNulls){ struct ExprList_item *pItem; if( p==0 ) return; assert( p->nExpr>0 ); assert( SQLITE_SO_UNDEFINED<0 && SQLITE_SO_ASC==0 && SQLITE_SO_DESC>0 ); assert( iSortOrder==SQLITE_SO_UNDEFINED || iSortOrder==SQLITE_SO_ASC || iSortOrder==SQLITE_SO_DESC ); assert( eNulls==SQLITE_SO_UNDEFINED || eNulls==SQLITE_SO_ASC || eNulls==SQLITE_SO_DESC ); pItem = &p->a[p->nExpr-1]; assert( pItem->bNulls==0 ); if( iSortOrder==SQLITE_SO_UNDEFINED ){ iSortOrder = SQLITE_SO_ASC; } pItem->sortFlags = (u8)iSortOrder; if( eNulls!=SQLITE_SO_UNDEFINED ){ pItem->bNulls = 1; if( iSortOrder!=eNulls ){ pItem->sortFlags |= KEYINFO_ORDER_BIGNULL; } } } /* ** Set the ExprList.a[].zEName element of the most recently added item ** on the expression list. ** ** pList might be NULL following an OOM error. But pName should never be ** NULL. If a memory allocation fails, the pParse->db->mallocFailed flag ** is set. */ void sqlite3ExprListSetName( Parse *pParse, /* Parsing context */ ExprList *pList, /* List to which to add the span. */ const Token *pName, /* Name to be added */ int dequote /* True to cause the name to be dequoted */ ){ assert( pList!=0 || pParse->db->mallocFailed!=0 ); assert( pParse->eParseMode!=PARSE_MODE_UNMAP || dequote==0 ); if( pList ){ struct ExprList_item *pItem; assert( pList->nExpr>0 ); pItem = &pList->a[pList->nExpr-1]; assert( pItem->zEName==0 ); assert( pItem->eEName==ENAME_NAME ); pItem->zEName = sqlite3DbStrNDup(pParse->db, pName->z, pName->n); if( dequote ){ /* If dequote==0, then pName->z does not point to part of a DDL ** statement handled by the parser. And so no token need be added ** to the token-map. */ sqlite3Dequote(pItem->zEName); if( IN_RENAME_OBJECT ){ sqlite3RenameTokenMap(pParse, (const void*)pItem->zEName, pName); } } } } /* ** Set the ExprList.a[].zSpan element of the most recently added item ** on the expression list. |
︙ | ︙ | |||
1721 1722 1723 1724 1725 1726 1727 | const char *zEnd /* End of the span */ ){ sqlite3 *db = pParse->db; assert( pList!=0 || db->mallocFailed!=0 ); if( pList ){ struct ExprList_item *pItem = &pList->a[pList->nExpr-1]; assert( pList->nExpr>0 ); | | | > > | 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 | const char *zEnd /* End of the span */ ){ sqlite3 *db = pParse->db; assert( pList!=0 || db->mallocFailed!=0 ); if( pList ){ struct ExprList_item *pItem = &pList->a[pList->nExpr-1]; assert( pList->nExpr>0 ); if( pItem->zEName==0 ){ pItem->zEName = sqlite3DbSpanDup(db, zStart, zEnd); pItem->eEName = ENAME_SPAN; } } } /* ** If the expression list pEList contains more than iLimit elements, ** leave an error message in pParse. */ |
︙ | ︙ | |||
1752 1753 1754 1755 1756 1757 1758 | */ static SQLITE_NOINLINE void exprListDeleteNN(sqlite3 *db, ExprList *pList){ int i = pList->nExpr; struct ExprList_item *pItem = pList->a; assert( pList->nExpr>0 ); do{ sqlite3ExprDelete(db, pItem->pExpr); | | < | 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 | */ static SQLITE_NOINLINE void exprListDeleteNN(sqlite3 *db, ExprList *pList){ int i = pList->nExpr; struct ExprList_item *pItem = pList->a; assert( pList->nExpr>0 ); do{ sqlite3ExprDelete(db, pItem->pExpr); sqlite3DbFree(db, pItem->zEName); pItem++; }while( --i>0 ); sqlite3DbFreeNN(db, pList); } void sqlite3ExprListDelete(sqlite3 *db, ExprList *pList){ if( pList ) exprListDeleteNN(db, pList); } |
︙ | ︙ | |||
1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 | ** This callback is used by multiple expression walkers. */ int sqlite3SelectWalkFail(Walker *pWalker, Select *NotUsed){ UNUSED_PARAMETER(NotUsed); pWalker->eCode = 0; return WRC_Abort; } /* ** If the input expression is an ID with the name "true" or "false" ** then convert it into an TK_TRUEFALSE term. Return non-zero if ** the conversion happened, and zero if the expression is unaltered. */ int sqlite3ExprIdToTrueFalse(Expr *pExpr){ assert( pExpr->op==TK_ID || pExpr->op==TK_STRING ); | > > > > > > > > > > > > > > > > > | < > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | > | | | | > > > | | > > | | | 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 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 | ** This callback is used by multiple expression walkers. */ int sqlite3SelectWalkFail(Walker *pWalker, Select *NotUsed){ UNUSED_PARAMETER(NotUsed); pWalker->eCode = 0; return WRC_Abort; } /* ** Check the input string to see if it is "true" or "false" (in any case). ** ** If the string is.... Return ** "true" EP_IsTrue ** "false" EP_IsFalse ** anything else 0 */ u32 sqlite3IsTrueOrFalse(const char *zIn){ if( sqlite3StrICmp(zIn, "true")==0 ) return EP_IsTrue; if( sqlite3StrICmp(zIn, "false")==0 ) return EP_IsFalse; return 0; } /* ** If the input expression is an ID with the name "true" or "false" ** then convert it into an TK_TRUEFALSE term. Return non-zero if ** the conversion happened, and zero if the expression is unaltered. */ int sqlite3ExprIdToTrueFalse(Expr *pExpr){ u32 v; assert( pExpr->op==TK_ID || pExpr->op==TK_STRING ); if( !ExprHasProperty(pExpr, EP_Quoted|EP_IntValue) && (v = sqlite3IsTrueOrFalse(pExpr->u.zToken))!=0 ){ pExpr->op = TK_TRUEFALSE; ExprSetProperty(pExpr, v); return 1; } return 0; } /* ** The argument must be a TK_TRUEFALSE Expr node. Return 1 if it is TRUE ** and 0 if it is FALSE. */ int sqlite3ExprTruthValue(const Expr *pExpr){ pExpr = sqlite3ExprSkipCollate((Expr*)pExpr); assert( pExpr->op==TK_TRUEFALSE ); assert( !ExprHasProperty(pExpr, EP_IntValue) ); assert( sqlite3StrICmp(pExpr->u.zToken,"true")==0 || sqlite3StrICmp(pExpr->u.zToken,"false")==0 ); return pExpr->u.zToken[4]==0; } /* ** If pExpr is an AND or OR expression, try to simplify it by eliminating ** terms that are always true or false. Return the simplified expression. ** Or return the original expression if no simplification is possible. ** ** Examples: ** ** (x<10) AND true => (x<10) ** (x<10) AND false => false ** (x<10) AND (y=22 OR false) => (x<10) AND (y=22) ** (x<10) AND (y=22 OR true) => (x<10) ** (y=22) OR true => true */ Expr *sqlite3ExprSimplifiedAndOr(Expr *pExpr){ assert( pExpr!=0 ); if( pExpr->op==TK_AND || pExpr->op==TK_OR ){ Expr *pRight = sqlite3ExprSimplifiedAndOr(pExpr->pRight); Expr *pLeft = sqlite3ExprSimplifiedAndOr(pExpr->pLeft); if( ExprAlwaysTrue(pLeft) || ExprAlwaysFalse(pRight) ){ pExpr = pExpr->op==TK_AND ? pRight : pLeft; }else if( ExprAlwaysTrue(pRight) || ExprAlwaysFalse(pLeft) ){ pExpr = pExpr->op==TK_AND ? pLeft : pRight; } } return pExpr; } /* ** These routines are Walker callbacks used to check expressions to ** see if they are "constant" for some definition of constant. The ** Walker.eCode value determines the type of "constant" we are looking ** for. ** ** These callback routines are used to implement the following: ** ** sqlite3ExprIsConstant() pWalker->eCode==1 ** sqlite3ExprIsConstantNotJoin() pWalker->eCode==2 ** sqlite3ExprIsTableConstant() pWalker->eCode==3 ** sqlite3ExprIsConstantOrFunction() pWalker->eCode==4 or 5 ** ** In all cases, the callbacks set Walker.eCode=0 and abort if the expression ** is found to not be a constant. ** ** The sqlite3ExprIsConstantOrFunction() is used for evaluating DEFAULT ** expressions in a CREATE TABLE statement. The Walker.eCode value is 5 ** when parsing an existing schema out of the sqlite_schema table and 4 ** when processing a new CREATE TABLE statement. A bound parameter raises ** an error for new statements, but is silently converted ** to NULL for existing schemas. This allows sqlite_schema tables that ** contain a bound parameter because they were generated by older versions ** of SQLite to be parsed by newer versions of SQLite without raising a ** malformed schema error. */ static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){ /* If pWalker->eCode is 2 then any term of the expression that comes from ** the ON or USING clauses of a left join disqualifies the expression ** from being considered constant. */ if( pWalker->eCode==2 && ExprHasProperty(pExpr, EP_FromJoin) ){ pWalker->eCode = 0; return WRC_Abort; } switch( pExpr->op ){ /* Consider functions to be constant if all their arguments are constant ** and either pWalker->eCode==4 or 5 or the function has the ** SQLITE_FUNC_CONST flag. */ case TK_FUNCTION: if( (pWalker->eCode>=4 || ExprHasProperty(pExpr,EP_ConstFunc)) && !ExprHasProperty(pExpr, EP_WinFunc) ){ if( pWalker->eCode==5 ) ExprSetProperty(pExpr, EP_FromDDL); return WRC_Continue; }else{ pWalker->eCode = 0; return WRC_Abort; } case TK_ID: /* Convert "true" or "false" in a DEFAULT clause into the ** appropriate TK_TRUEFALSE operator */ if( sqlite3ExprIdToTrueFalse(pExpr) ){ return WRC_Prune; } /* no break */ deliberate_fall_through case TK_COLUMN: case TK_AGG_FUNCTION: case TK_AGG_COLUMN: testcase( pExpr->op==TK_ID ); testcase( pExpr->op==TK_COLUMN ); testcase( pExpr->op==TK_AGG_FUNCTION ); testcase( pExpr->op==TK_AGG_COLUMN ); if( ExprHasProperty(pExpr, EP_FixedCol) && pWalker->eCode!=2 ){ return WRC_Continue; } if( pWalker->eCode==3 && pExpr->iTable==pWalker->u.iCur ){ return WRC_Continue; } /* no break */ deliberate_fall_through case TK_IF_NULL_ROW: case TK_REGISTER: case TK_DOT: testcase( pExpr->op==TK_REGISTER ); testcase( pExpr->op==TK_IF_NULL_ROW ); testcase( pExpr->op==TK_DOT ); pWalker->eCode = 0; return WRC_Abort; case TK_VARIABLE: if( pWalker->eCode==5 ){ /* Silently convert bound parameters that appear inside of CREATE ** statements into a NULL when parsing the CREATE statement text out ** of the sqlite_schema table */ pExpr->op = TK_NULL; }else if( pWalker->eCode==4 ){ /* A bound parameter in a CREATE statement that originates from ** sqlite3_prepare() causes an error */ pWalker->eCode = 0; return WRC_Abort; } /* no break */ deliberate_fall_through default: testcase( pExpr->op==TK_SELECT ); /* sqlite3SelectWalkFail() disallows */ testcase( pExpr->op==TK_EXISTS ); /* sqlite3SelectWalkFail() disallows */ return WRC_Continue; } } static int exprIsConst(Expr *p, int initFlag, int iCur){ |
︙ | ︙ | |||
1947 1948 1949 1950 1951 1952 1953 | ** (2) the expression does originate in the ON or USING clause ** of a LEFT JOIN, and ** (3) the expression does not contain any EP_FixedCol TK_COLUMN ** operands created by the constant propagation optimization. ** ** When this routine returns true, it indicates that the expression ** can be added to the pParse->pConstExpr list and evaluated once when | | | 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 | ** (2) the expression does originate in the ON or USING clause ** of a LEFT JOIN, and ** (3) the expression does not contain any EP_FixedCol TK_COLUMN ** operands created by the constant propagation optimization. ** ** When this routine returns true, it indicates that the expression ** can be added to the pParse->pConstExpr list and evaluated once when ** the prepared statement starts up. See sqlite3ExprCodeRunJustOnce(). */ int sqlite3ExprIsConstantNotJoin(Expr *p){ return exprIsConst(p, 2, 0); } /* ** Walk an expression tree. Return non-zero if the expression is constant |
︙ | ︙ | |||
1984 1985 1986 1987 1988 1989 1990 | if( sqlite3IsBinary(pColl) ){ return WRC_Prune; } } } /* Check if pExpr is a sub-select. If so, consider it variable. */ | | | 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 | if( sqlite3IsBinary(pColl) ){ return WRC_Prune; } } } /* Check if pExpr is a sub-select. If so, consider it variable. */ if( ExprUseXSelect(pExpr) ){ pWalker->eCode = 0; return WRC_Abort; } return exprNodeIsConstant(pWalker, pExpr); } |
︙ | ︙ | |||
2023 2024 2025 2026 2027 2028 2029 | w.u.pGroupBy = pGroupBy; w.pParse = pParse; sqlite3WalkExpr(&w, p); return w.eCode; } /* | > | > | | > > > > > > > > > > | 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 | w.u.pGroupBy = pGroupBy; w.pParse = pParse; sqlite3WalkExpr(&w, p); return w.eCode; } /* ** Walk an expression tree for the DEFAULT field of a column definition ** in a CREATE TABLE statement. Return non-zero if the expression is ** acceptable for use as a DEFAULT. That is to say, return non-zero if ** the expression is constant or a function call with constant arguments. ** Return and 0 if there are any variables. ** ** isInit is true when parsing from sqlite_schema. isInit is false when ** processing a new CREATE TABLE statement. When isInit is true, parameters ** (such as ? or $abc) in the expression are converted into NULL. When ** isInit is false, parameters raise an error. Parameters should not be ** allowed in a CREATE TABLE statement, but some legacy versions of SQLite ** allowed it, so we need to support it when reading sqlite_schema for ** backwards compatibility. ** ** If isInit is true, set EP_FromDDL on every TK_FUNCTION node. ** ** For the purposes of this function, a double-quoted string (ex: "abc") ** is considered a variable but a single-quoted string (ex: 'abc') is ** a constant. */ int sqlite3ExprIsConstantOrFunction(Expr *p, u8 isInit){ assert( isInit==0 || isInit==1 ); |
︙ | ︙ | |||
2060 2061 2062 2063 2064 2065 2066 | /* ** If the expression p codes a constant integer that is small enough ** to fit in a 32-bit integer, return 1 and put the value of the integer ** in *pValue. If the expression is not an integer or if it is too big ** to fit in a signed 32-bit integer, return 0 and leave *pValue unchanged. */ | | | | | | 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 2421 2422 | /* ** If the expression p codes a constant integer that is small enough ** to fit in a 32-bit integer, return 1 and put the value of the integer ** in *pValue. If the expression is not an integer or if it is too big ** to fit in a signed 32-bit integer, return 0 and leave *pValue unchanged. */ int sqlite3ExprIsInteger(const Expr *p, int *pValue){ int rc = 0; if( NEVER(p==0) ) return 0; /* Used to only happen following on OOM */ /* If an expression is an integer literal that fits in a signed 32-bit ** integer, then the EP_IntValue flag will have already been set */ assert( p->op!=TK_INTEGER || (p->flags & EP_IntValue)!=0 || sqlite3GetInt32(p->u.zToken, &rc)==0 ); if( p->flags & EP_IntValue ){ *pValue = p->u.iValue; return 1; } switch( p->op ){ case TK_UPLUS: { rc = sqlite3ExprIsInteger(p->pLeft, pValue); break; } case TK_UMINUS: { int v = 0; if( sqlite3ExprIsInteger(p->pLeft, &v) ){ assert( ((unsigned int)v)!=0x80000000 ); *pValue = -v; rc = 1; } break; } default: break; } |
︙ | ︙ | |||
2108 2109 2110 2111 2112 2113 2114 | ** be a small performance hit but is otherwise harmless. On the other ** hand, a false negative (returning FALSE when the result could be NULL) ** will likely result in an incorrect answer. So when in doubt, return ** TRUE. */ int sqlite3ExprCanBeNull(const Expr *p){ u8 op; | > | > > > > > > | > | > > > | | | | < | | 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 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 | ** be a small performance hit but is otherwise harmless. On the other ** hand, a false negative (returning FALSE when the result could be NULL) ** will likely result in an incorrect answer. So when in doubt, return ** TRUE. */ int sqlite3ExprCanBeNull(const Expr *p){ u8 op; assert( p!=0 ); while( p->op==TK_UPLUS || p->op==TK_UMINUS ){ p = p->pLeft; assert( p!=0 ); } op = p->op; if( op==TK_REGISTER ) op = p->op2; switch( op ){ case TK_INTEGER: case TK_STRING: case TK_FLOAT: case TK_BLOB: return 0; case TK_COLUMN: assert( ExprUseYTab(p) ); return ExprHasProperty(p, EP_CanBeNull) || p->y.pTab==0 || /* Reference to column of index on expression */ (p->iColumn>=0 && ALWAYS(p->y.pTab->aCol!=0) /* Defense against OOM problems */ && p->y.pTab->aCol[p->iColumn].notNull==0); default: return 1; } } /* ** Return TRUE if the given expression is a constant which would be ** unchanged by OP_Affinity with the affinity given in the second ** argument. ** ** This routine is used to determine if the OP_Affinity operation ** can be omitted. When in doubt return FALSE. A false negative ** is harmless. A false positive, however, can result in the wrong ** answer. */ int sqlite3ExprNeedsNoAffinityChange(const Expr *p, char aff){ u8 op; int unaryMinus = 0; if( aff==SQLITE_AFF_BLOB ) return 1; while( p->op==TK_UPLUS || p->op==TK_UMINUS ){ if( p->op==TK_UMINUS ) unaryMinus = 1; p = p->pLeft; } op = p->op; if( op==TK_REGISTER ) op = p->op2; switch( op ){ case TK_INTEGER: { return aff>=SQLITE_AFF_NUMERIC; } case TK_FLOAT: { return aff>=SQLITE_AFF_NUMERIC; } case TK_STRING: { return !unaryMinus && aff==SQLITE_AFF_TEXT; } case TK_BLOB: { return !unaryMinus; } case TK_COLUMN: { assert( p->iTable>=0 ); /* p cannot be part of a CHECK constraint */ return aff>=SQLITE_AFF_NUMERIC && p->iColumn<0; } default: { return 0; } } } |
︙ | ︙ | |||
2184 2185 2186 2187 2188 2189 2190 | ** pX is the RHS of an IN operator. If pX is a SELECT statement ** that can be simplified to a direct table access, then return ** a pointer to the SELECT statement. If pX is not a SELECT statement, ** or if the SELECT statement needs to be manifested into a transient ** table, then return NULL. */ #ifndef SQLITE_OMIT_SUBQUERY | | | | | 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 | ** pX is the RHS of an IN operator. If pX is a SELECT statement ** that can be simplified to a direct table access, then return ** a pointer to the SELECT statement. If pX is not a SELECT statement, ** or if the SELECT statement needs to be manifested into a transient ** table, then return NULL. */ #ifndef SQLITE_OMIT_SUBQUERY static Select *isCandidateForInOpt(const Expr *pX){ Select *p; SrcList *pSrc; ExprList *pEList; Table *pTab; int i; if( !ExprUseXSelect(pX) ) return 0; /* Not a subquery */ if( ExprHasProperty(pX, EP_VarSelect) ) return 0; /* Correlated subq */ p = pX->x.pSelect; if( p->pPrior ) return 0; /* Not a compound SELECT */ if( p->selFlags & (SF_Distinct|SF_Aggregate) ){ testcase( (p->selFlags & (SF_Distinct|SF_Aggregate))==SF_Distinct ); testcase( (p->selFlags & (SF_Distinct|SF_Aggregate))==SF_Aggregate ); return 0; /* No DISTINCT keyword and no aggregate functions */ } assert( p->pGroupBy==0 ); /* Has no GROUP BY clause */ if( p->pLimit ) return 0; /* Has no LIMIT clause */ if( p->pWhere ) return 0; /* Has no WHERE clause */ pSrc = p->pSrc; assert( pSrc!=0 ); if( pSrc->nSrc!=1 ) return 0; /* Single term in FROM clause */ if( pSrc->a[0].pSelect ) return 0; /* FROM is not a subquery or view */ pTab = pSrc->a[0].pTab; assert( pTab!=0 ); assert( !IsView(pTab) ); /* FROM clause is not a view */ if( IsVirtual(pTab) ) return 0; /* FROM clause not a virtual table */ pEList = p->pEList; assert( pEList!=0 ); /* All SELECT results must be columns. */ for(i=0; i<pEList->nExpr; i++){ Expr *pRes = pEList->a[i].pExpr; if( pRes->op!=TK_COLUMN ) return 0; |
︙ | ︙ | |||
2341 2342 2343 2344 2345 2346 2347 | ** CREATE INDEX i1 ON t1(b, c, a); ** ** then aiMap[] is populated with {2, 0, 1}. */ #ifndef SQLITE_OMIT_SUBQUERY int sqlite3FindInIndex( Parse *pParse, /* Parsing context */ | | | > | | > | 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 | ** CREATE INDEX i1 ON t1(b, c, a); ** ** then aiMap[] is populated with {2, 0, 1}. */ #ifndef SQLITE_OMIT_SUBQUERY int sqlite3FindInIndex( Parse *pParse, /* Parsing context */ Expr *pX, /* The IN expression */ u32 inFlags, /* IN_INDEX_LOOP, _MEMBERSHIP, and/or _NOOP_OK */ int *prRhsHasNull, /* Register holding NULL status. See notes */ int *aiMap, /* Mapping from Index fields to RHS fields */ int *piTab /* OUT: index to use */ ){ Select *p; /* SELECT to the right of IN operator */ int eType = 0; /* Type of RHS table. IN_INDEX_* */ int iTab = pParse->nTab++; /* Cursor of the RHS table */ int mustBeUnique; /* True if RHS must be unique */ Vdbe *v = sqlite3GetVdbe(pParse); /* Virtual machine being coded */ assert( pX->op==TK_IN ); mustBeUnique = (inFlags & IN_INDEX_LOOP)!=0; /* If the RHS of this IN(...) operator is a SELECT, and if it matters ** whether or not the SELECT result contains NULL values, check whether ** or not NULL is actually possible (it may not be, for example, due ** to NOT NULL constraints in the schema). If no NULL values are possible, ** set prRhsHasNull to 0 before continuing. */ if( prRhsHasNull && ExprUseXSelect(pX) ){ int i; ExprList *pEList = pX->x.pSelect->pEList; for(i=0; i<pEList->nExpr; i++){ if( sqlite3ExprCanBeNull(pEList->a[i].pExpr) ) break; } if( i==pEList->nExpr ){ prRhsHasNull = 0; } } /* Check to see if an existing table or index can be used to ** satisfy the query. This is preferable to generating a new ** ephemeral table. */ if( pParse->nErr==0 && (p = isCandidateForInOpt(pX))!=0 ){ sqlite3 *db = pParse->db; /* Database connection */ Table *pTab; /* Table <table>. */ int iDb; /* Database idx for pTab */ ExprList *pEList = p->pEList; int nExpr = pEList->nExpr; assert( p->pEList!=0 ); /* Because of isCandidateForInOpt(p) */ assert( p->pEList->a[0].pExpr!=0 ); /* Because of isCandidateForInOpt(p) */ assert( p->pSrc!=0 ); /* Because of isCandidateForInOpt(p) */ pTab = p->pSrc->a[0].pTab; /* Code an OP_Transaction and OP_TableLock for <table>. */ iDb = sqlite3SchemaToIndex(db, pTab->pSchema); assert( iDb>=0 && iDb<SQLITE_MAX_DB ); sqlite3CodeVerifySchema(pParse, iDb); sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName); assert(v); /* sqlite3GetVdbe() has always been previously called */ if( nExpr==1 && pEList->a[0].pExpr->iColumn<0 ){ /* The "x IN (SELECT rowid FROM table)" case */ int iAddr = sqlite3VdbeAddOp0(v, OP_Once); |
︙ | ︙ | |||
2460 2461 2462 2463 2464 2465 2466 | colUsed = 0; /* Columns of index used so far */ for(i=0; i<nExpr; i++){ Expr *pLhs = sqlite3VectorFieldSubexpr(pX->pLeft, i); Expr *pRhs = pEList->a[i].pExpr; CollSeq *pReq = sqlite3BinaryCompareCollSeq(pParse, pLhs, pRhs); int j; | | > | 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 | colUsed = 0; /* Columns of index used so far */ for(i=0; i<nExpr; i++){ Expr *pLhs = sqlite3VectorFieldSubexpr(pX->pLeft, i); Expr *pRhs = pEList->a[i].pExpr; CollSeq *pReq = sqlite3BinaryCompareCollSeq(pParse, pLhs, pRhs); int j; assert( pReq!=0 || pRhs->iColumn==XN_ROWID || pParse->nErr || db->mallocFailed ); for(j=0; j<nExpr; j++){ if( pIdx->aiColumn[j]!=pRhs->iColumn ) continue; assert( pIdx->azColl[j] ); if( pReq!=0 && sqlite3StrICmp(pReq->zName, pIdx->azColl[j])!=0 ){ continue; } break; |
︙ | ︙ | |||
2515 2516 2517 2518 2519 2520 2521 | ** and the RHS of the IN operator is a list, not a subquery ** and the RHS is not constant or has two or fewer terms, ** then it is not worth creating an ephemeral table to evaluate ** the IN operator so return IN_INDEX_NOOP. */ if( eType==0 && (inFlags & IN_INDEX_NOOP_OK) | | < < < > > | > > < < > | | | 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 | ** and the RHS of the IN operator is a list, not a subquery ** and the RHS is not constant or has two or fewer terms, ** then it is not worth creating an ephemeral table to evaluate ** the IN operator so return IN_INDEX_NOOP. */ if( eType==0 && (inFlags & IN_INDEX_NOOP_OK) && ExprUseXList(pX) && (!sqlite3InRhsIsConstant(pX) || pX->x.pList->nExpr<=2) ){ eType = IN_INDEX_NOOP; } if( eType==0 ){ /* Could not find an existing table or index to use as the RHS b-tree. ** We will have to generate an ephemeral table to do the job. */ u32 savedNQueryLoop = pParse->nQueryLoop; int rMayHaveNull = 0; eType = IN_INDEX_EPH; if( inFlags & IN_INDEX_LOOP ){ pParse->nQueryLoop = 0; }else if( prRhsHasNull ){ *prRhsHasNull = rMayHaveNull = ++pParse->nMem; } assert( pX->op==TK_IN ); sqlite3CodeRhsOfIN(pParse, pX, iTab); if( rMayHaveNull ){ sqlite3SetHasNullFlag(v, iTab, rMayHaveNull); } pParse->nQueryLoop = savedNQueryLoop; } if( aiMap && eType!=IN_INDEX_INDEX_ASC && eType!=IN_INDEX_INDEX_DESC ){ int i, n; n = sqlite3ExprVectorSize(pX->pLeft); for(i=0; i<n; i++) aiMap[i] = i; } *piTab = iTab; return eType; } #endif #ifndef SQLITE_OMIT_SUBQUERY /* ** Argument pExpr is an (?, ?...) IN(...) expression. This ** function allocates and returns a nul-terminated string containing ** the affinities to be used for each column of the comparison. ** ** It is the responsibility of the caller to ensure that the returned ** string is eventually freed using sqlite3DbFree(). */ static char *exprINAffinity(Parse *pParse, const Expr *pExpr){ Expr *pLeft = pExpr->pLeft; int nVal = sqlite3ExprVectorSize(pLeft); Select *pSelect = ExprUseXSelect(pExpr) ? pExpr->x.pSelect : 0; char *zRet; assert( pExpr->op==TK_IN ); zRet = sqlite3DbMallocRaw(pParse->db, nVal+1); if( zRet ){ int i; for(i=0; i<nVal; i++){ |
︙ | ︙ | |||
2593 2594 2595 2596 2597 2598 2599 | /* ** Load the Parse object passed as the first argument with an error ** message of the form: ** ** "sub-select returns N columns - expected M" */ void sqlite3SubselectError(Parse *pParse, int nActual, int nExpect){ | > | | > | > | | > < < | > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > | > > | > > > | > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > | > > > > > | > > > > > > > > > > | > > > > > > > > > > > > > | > > > > > > > | > > > > > > > > | | | | | | | > > | > | > | > > > > > > | > > > > > > > > > | > > > > | > > > | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | | | | | | | < < < < < < < < < < < | | | | | | | | | | | | | | | | < | > > > > > > > > > | | | > > | | | | > > > > | | | | | > | | | < | < | < | < | | | 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 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 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 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 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 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 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 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 | /* ** Load the Parse object passed as the first argument with an error ** message of the form: ** ** "sub-select returns N columns - expected M" */ void sqlite3SubselectError(Parse *pParse, int nActual, int nExpect){ if( pParse->nErr==0 ){ const char *zFmt = "sub-select returns %d columns - expected %d"; sqlite3ErrorMsg(pParse, zFmt, nActual, nExpect); } } #endif /* ** Expression pExpr is a vector that has been used in a context where ** it is not permitted. If pExpr is a sub-select vector, this routine ** loads the Parse object with a message of the form: ** ** "sub-select returns N columns - expected 1" ** ** Or, if it is a regular scalar vector: ** ** "row value misused" */ void sqlite3VectorErrorMsg(Parse *pParse, Expr *pExpr){ #ifndef SQLITE_OMIT_SUBQUERY if( ExprUseXSelect(pExpr) ){ sqlite3SubselectError(pParse, pExpr->x.pSelect->pEList->nExpr, 1); }else #endif { sqlite3ErrorMsg(pParse, "row value misused"); } } #ifndef SQLITE_OMIT_SUBQUERY /* ** Generate code that will construct an ephemeral table containing all terms ** in the RHS of an IN operator. The IN operator can be in either of two ** forms: ** ** x IN (4,5,11) -- IN operator with list on right-hand side ** x IN (SELECT a FROM b) -- IN operator with subquery on the right ** ** The pExpr parameter is the IN operator. The cursor number for the ** constructed ephermeral table is returned. The first time the ephemeral ** table is computed, the cursor number is also stored in pExpr->iTable, ** however the cursor number returned might not be the same, as it might ** have been duplicated using OP_OpenDup. ** ** If the LHS expression ("x" in the examples) is a column value, or ** the SELECT statement returns a column value, then the affinity of that ** column is used to build the index keys. If both 'x' and the ** SELECT... statement are columns, then numeric affinity is used ** if either column has NUMERIC or INTEGER affinity. If neither ** 'x' nor the SELECT... statement are columns, then numeric affinity ** is used. */ void sqlite3CodeRhsOfIN( Parse *pParse, /* Parsing context */ Expr *pExpr, /* The IN operator */ int iTab /* Use this cursor number */ ){ int addrOnce = 0; /* Address of the OP_Once instruction at top */ int addr; /* Address of OP_OpenEphemeral instruction */ Expr *pLeft; /* the LHS of the IN operator */ KeyInfo *pKeyInfo = 0; /* Key information */ int nVal; /* Size of vector pLeft */ Vdbe *v; /* The prepared statement under construction */ v = pParse->pVdbe; assert( v!=0 ); /* The evaluation of the IN must be repeated every time it ** is encountered if any of the following is true: ** ** * The right-hand side is a correlated subquery ** * The right-hand side is an expression list containing variables ** * We are inside a trigger ** ** If all of the above are false, then we can compute the RHS just once ** and reuse it many names. */ if( !ExprHasProperty(pExpr, EP_VarSelect) && pParse->iSelfTab==0 ){ /* Reuse of the RHS is allowed */ /* If this routine has already been coded, but the previous code ** might not have been invoked yet, so invoke it now as a subroutine. */ if( ExprHasProperty(pExpr, EP_Subrtn) ){ addrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v); if( ExprUseXSelect(pExpr) ){ ExplainQueryPlan((pParse, 0, "REUSE LIST SUBQUERY %d", pExpr->x.pSelect->selId)); } assert( ExprUseYSub(pExpr) ); sqlite3VdbeAddOp2(v, OP_Gosub, pExpr->y.sub.regReturn, pExpr->y.sub.iAddr); sqlite3VdbeAddOp2(v, OP_OpenDup, iTab, pExpr->iTable); sqlite3VdbeJumpHere(v, addrOnce); return; } /* Begin coding the subroutine */ assert( !ExprUseYWin(pExpr) ); ExprSetProperty(pExpr, EP_Subrtn); assert( !ExprHasProperty(pExpr, EP_TokenOnly|EP_Reduced) ); pExpr->y.sub.regReturn = ++pParse->nMem; pExpr->y.sub.iAddr = sqlite3VdbeAddOp2(v, OP_Integer, 0, pExpr->y.sub.regReturn) + 1; VdbeComment((v, "return address")); addrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v); } /* Check to see if this is a vector IN operator */ pLeft = pExpr->pLeft; nVal = sqlite3ExprVectorSize(pLeft); /* Construct the ephemeral table that will contain the content of ** RHS of the IN operator. */ pExpr->iTable = iTab; addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pExpr->iTable, nVal); #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS if( ExprUseXSelect(pExpr) ){ VdbeComment((v, "Result of SELECT %u", pExpr->x.pSelect->selId)); }else{ VdbeComment((v, "RHS of IN operator")); } #endif pKeyInfo = sqlite3KeyInfoAlloc(pParse->db, nVal, 1); if( ExprUseXSelect(pExpr) ){ /* Case 1: expr IN (SELECT ...) ** ** Generate code to write the results of the select into the temporary ** table allocated and opened above. */ Select *pSelect = pExpr->x.pSelect; ExprList *pEList = pSelect->pEList; ExplainQueryPlan((pParse, 1, "%sLIST SUBQUERY %d", addrOnce?"":"CORRELATED ", pSelect->selId )); /* If the LHS and RHS of the IN operator do not match, that ** error will have been caught long before we reach this point. */ if( ALWAYS(pEList->nExpr==nVal) ){ Select *pCopy; SelectDest dest; int i; int rc; sqlite3SelectDestInit(&dest, SRT_Set, iTab); dest.zAffSdst = exprINAffinity(pParse, pExpr); pSelect->iLimit = 0; testcase( pSelect->selFlags & SF_Distinct ); testcase( pKeyInfo==0 ); /* Caused by OOM in sqlite3KeyInfoAlloc() */ pCopy = sqlite3SelectDup(pParse->db, pSelect, 0); rc = pParse->db->mallocFailed ? 1 :sqlite3Select(pParse, pCopy, &dest); sqlite3SelectDelete(pParse->db, pCopy); sqlite3DbFree(pParse->db, dest.zAffSdst); if( rc ){ sqlite3KeyInfoUnref(pKeyInfo); return; } assert( pKeyInfo!=0 ); /* OOM will cause exit after sqlite3Select() */ assert( pEList!=0 ); assert( pEList->nExpr>0 ); assert( sqlite3KeyInfoIsWriteable(pKeyInfo) ); for(i=0; i<nVal; i++){ Expr *p = sqlite3VectorFieldSubexpr(pLeft, i); pKeyInfo->aColl[i] = sqlite3BinaryCompareCollSeq( pParse, p, pEList->a[i].pExpr ); } } }else if( ALWAYS(pExpr->x.pList!=0) ){ /* Case 2: expr IN (exprlist) ** ** For each expression, build an index key from the evaluation and ** store it in the temporary table. If <expr> is a column, then use ** that columns affinity when building index keys. If <expr> is not ** a column, use numeric affinity. */ char affinity; /* Affinity of the LHS of the IN */ int i; ExprList *pList = pExpr->x.pList; struct ExprList_item *pItem; int r1, r2; affinity = sqlite3ExprAffinity(pLeft); if( affinity<=SQLITE_AFF_NONE ){ affinity = SQLITE_AFF_BLOB; }else if( affinity==SQLITE_AFF_REAL ){ affinity = SQLITE_AFF_NUMERIC; } if( pKeyInfo ){ assert( sqlite3KeyInfoIsWriteable(pKeyInfo) ); pKeyInfo->aColl[0] = sqlite3ExprCollSeq(pParse, pExpr->pLeft); } /* Loop through each expression in <exprlist>. */ r1 = sqlite3GetTempReg(pParse); r2 = sqlite3GetTempReg(pParse); for(i=pList->nExpr, pItem=pList->a; i>0; i--, pItem++){ Expr *pE2 = pItem->pExpr; /* If the expression is not constant then we will need to ** disable the test that was generated above that makes sure ** this code only executes once. Because for a non-constant ** expression we need to rerun this code each time. */ if( addrOnce && !sqlite3ExprIsConstant(pE2) ){ sqlite3VdbeChangeToNoop(v, addrOnce); ExprClearProperty(pExpr, EP_Subrtn); addrOnce = 0; } /* Evaluate the expression and insert it into the temp table */ sqlite3ExprCode(pParse, pE2, r1); sqlite3VdbeAddOp4(v, OP_MakeRecord, r1, 1, r2, &affinity, 1); sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iTab, r2, r1, 1); } sqlite3ReleaseTempReg(pParse, r1); sqlite3ReleaseTempReg(pParse, r2); } if( pKeyInfo ){ sqlite3VdbeChangeP4(v, addr, (void *)pKeyInfo, P4_KEYINFO); } if( addrOnce ){ sqlite3VdbeJumpHere(v, addrOnce); /* Subroutine return */ assert( ExprUseYSub(pExpr) ); sqlite3VdbeAddOp1(v, OP_Return, pExpr->y.sub.regReturn); sqlite3VdbeChangeP1(v, pExpr->y.sub.iAddr-1, sqlite3VdbeCurrentAddr(v)-1); sqlite3ClearTempRegCache(pParse); } } #endif /* SQLITE_OMIT_SUBQUERY */ /* ** Generate code for scalar subqueries used as a subquery expression ** or EXISTS operator: ** ** (SELECT a FROM b) -- subquery ** EXISTS (SELECT a FROM b) -- EXISTS subquery ** ** The pExpr parameter is the SELECT or EXISTS operator to be coded. ** ** Return the register that holds the result. For a multi-column SELECT, ** the result is stored in a contiguous array of registers and the ** return value is the register of the left-most result column. ** Return 0 if an error occurs. */ #ifndef SQLITE_OMIT_SUBQUERY int sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){ int addrOnce = 0; /* Address of OP_Once at top of subroutine */ int rReg = 0; /* Register storing resulting */ Select *pSel; /* SELECT statement to encode */ SelectDest dest; /* How to deal with SELECT result */ int nReg; /* Registers to allocate */ Expr *pLimit; /* New limit expression */ Vdbe *v = pParse->pVdbe; assert( v!=0 ); if( pParse->nErr ) return 0; testcase( pExpr->op==TK_EXISTS ); testcase( pExpr->op==TK_SELECT ); assert( pExpr->op==TK_EXISTS || pExpr->op==TK_SELECT ); assert( ExprUseXSelect(pExpr) ); pSel = pExpr->x.pSelect; /* If this routine has already been coded, then invoke it as a ** subroutine. */ if( ExprHasProperty(pExpr, EP_Subrtn) ){ ExplainQueryPlan((pParse, 0, "REUSE SUBQUERY %d", pSel->selId)); assert( ExprUseYSub(pExpr) ); sqlite3VdbeAddOp2(v, OP_Gosub, pExpr->y.sub.regReturn, pExpr->y.sub.iAddr); return pExpr->iTable; } /* Begin coding the subroutine */ assert( !ExprUseYWin(pExpr) ); assert( !ExprHasProperty(pExpr, EP_Reduced|EP_TokenOnly) ); ExprSetProperty(pExpr, EP_Subrtn); pExpr->y.sub.regReturn = ++pParse->nMem; pExpr->y.sub.iAddr = sqlite3VdbeAddOp2(v, OP_Integer, 0, pExpr->y.sub.regReturn) + 1; VdbeComment((v, "return address")); /* The evaluation of the EXISTS/SELECT must be repeated every time it ** is encountered if any of the following is true: ** ** * The right-hand side is a correlated subquery ** * The right-hand side is an expression list containing variables ** * We are inside a trigger ** ** If all of the above are false, then we can run this code just once ** save the results, and reuse the same result on subsequent invocations. */ if( !ExprHasProperty(pExpr, EP_VarSelect) ){ addrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v); } /* For a SELECT, generate code to put the values for all columns of ** the first row into an array of registers and return the index of ** the first register. ** ** If this is an EXISTS, write an integer 0 (not exists) or 1 (exists) ** into a register and return that register number. ** ** In both cases, the query is augmented with "LIMIT 1". Any ** preexisting limit is discarded in place of the new LIMIT 1. */ ExplainQueryPlan((pParse, 1, "%sSCALAR SUBQUERY %d", addrOnce?"":"CORRELATED ", pSel->selId)); nReg = pExpr->op==TK_SELECT ? pSel->pEList->nExpr : 1; sqlite3SelectDestInit(&dest, 0, pParse->nMem+1); pParse->nMem += nReg; if( pExpr->op==TK_SELECT ){ dest.eDest = SRT_Mem; dest.iSdst = dest.iSDParm; dest.nSdst = nReg; sqlite3VdbeAddOp3(v, OP_Null, 0, dest.iSDParm, dest.iSDParm+nReg-1); VdbeComment((v, "Init subquery result")); }else{ dest.eDest = SRT_Exists; sqlite3VdbeAddOp2(v, OP_Integer, 0, dest.iSDParm); VdbeComment((v, "Init EXISTS result")); } if( pSel->pLimit ){ /* The subquery already has a limit. If the pre-existing limit is X ** then make the new limit X<>0 so that the new limit is either 1 or 0 */ sqlite3 *db = pParse->db; pLimit = sqlite3Expr(db, TK_INTEGER, "0"); if( pLimit ){ pLimit->affExpr = SQLITE_AFF_NUMERIC; pLimit = sqlite3PExpr(pParse, TK_NE, sqlite3ExprDup(db, pSel->pLimit->pLeft, 0), pLimit); } sqlite3ExprDelete(db, pSel->pLimit->pLeft); pSel->pLimit->pLeft = pLimit; }else{ /* If there is no pre-existing limit add a limit of 1 */ pLimit = sqlite3Expr(pParse->db, TK_INTEGER, "1"); pSel->pLimit = sqlite3PExpr(pParse, TK_LIMIT, pLimit, 0); } pSel->iLimit = 0; if( sqlite3Select(pParse, pSel, &dest) ){ if( pParse->nErr ){ pExpr->op2 = pExpr->op; pExpr->op = TK_ERROR; } return 0; } pExpr->iTable = rReg = dest.iSDParm; ExprSetVVAProperty(pExpr, EP_NoReduce); if( addrOnce ){ sqlite3VdbeJumpHere(v, addrOnce); } /* Subroutine return */ assert( ExprUseYSub(pExpr) ); sqlite3VdbeAddOp1(v, OP_Return, pExpr->y.sub.regReturn); sqlite3VdbeChangeP1(v, pExpr->y.sub.iAddr-1, sqlite3VdbeCurrentAddr(v)-1); sqlite3ClearTempRegCache(pParse); return rReg; } #endif /* SQLITE_OMIT_SUBQUERY */ #ifndef SQLITE_OMIT_SUBQUERY /* ** Expr pIn is an IN(...) expression. This function checks that the ** sub-select on the RHS of the IN() operator has the same number of ** columns as the vector on the LHS. Or, if the RHS of the IN() is not ** a sub-query, that the LHS is a vector of size 1. */ int sqlite3ExprCheckIN(Parse *pParse, Expr *pIn){ int nVector = sqlite3ExprVectorSize(pIn->pLeft); if( ExprUseXSelect(pIn) && !pParse->db->mallocFailed ){ if( nVector!=pIn->x.pSelect->pEList->nExpr ){ sqlite3SubselectError(pParse, pIn->x.pSelect->pEList->nExpr, nVector); return 1; } }else if( nVector!=1 ){ sqlite3VectorErrorMsg(pParse, pIn->pLeft); return 1; |
︙ | ︙ | |||
2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 | Expr *pLeft; /* The LHS of the IN operator */ int i; /* loop counter */ int destStep2; /* Where to jump when NULLs seen in step 2 */ int destStep6 = 0; /* Start of code for Step 6 */ int addrTruthOp; /* Address of opcode that determines the IN is true */ int destNotNull; /* Jump here if a comparison is not true in step 6 */ int addrTop; /* Top of the step-6 loop */ pLeft = pExpr->pLeft; if( sqlite3ExprCheckIN(pParse, pExpr) ) return; zAff = exprINAffinity(pParse, pExpr); nVector = sqlite3ExprVectorSize(pExpr->pLeft); aiMap = (int*)sqlite3DbMallocZero( pParse->db, nVector*(sizeof(int) + sizeof(char)) + 1 ); if( pParse->db->mallocFailed ) goto sqlite3ExprCodeIN_oom_error; /* Attempt to compute the RHS. After this step, if anything other than | > > > | | > | 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 3404 | Expr *pLeft; /* The LHS of the IN operator */ int i; /* loop counter */ int destStep2; /* Where to jump when NULLs seen in step 2 */ int destStep6 = 0; /* Start of code for Step 6 */ int addrTruthOp; /* Address of opcode that determines the IN is true */ int destNotNull; /* Jump here if a comparison is not true in step 6 */ int addrTop; /* Top of the step-6 loop */ int iTab = 0; /* Index to use */ u8 okConstFactor = pParse->okConstFactor; assert( !ExprHasVVAProperty(pExpr,EP_Immutable) ); pLeft = pExpr->pLeft; if( sqlite3ExprCheckIN(pParse, pExpr) ) return; zAff = exprINAffinity(pParse, pExpr); nVector = sqlite3ExprVectorSize(pExpr->pLeft); aiMap = (int*)sqlite3DbMallocZero( pParse->db, nVector*(sizeof(int) + sizeof(char)) + 1 ); if( pParse->db->mallocFailed ) goto sqlite3ExprCodeIN_oom_error; /* Attempt to compute the RHS. After this step, if anything other than ** IN_INDEX_NOOP is returned, the table opened with cursor iTab ** contains the values that make up the RHS. If IN_INDEX_NOOP is returned, ** the RHS has not yet been coded. */ v = pParse->pVdbe; assert( v!=0 ); /* OOM detected prior to this routine */ VdbeNoopComment((v, "begin IN expr")); eType = sqlite3FindInIndex(pParse, pExpr, IN_INDEX_MEMBERSHIP | IN_INDEX_NOOP_OK, destIfFalse==destIfNull ? 0 : &rRhsHasNull, aiMap, &iTab); assert( pParse->nErr || nVector==1 || eType==IN_INDEX_EPH || eType==IN_INDEX_INDEX_ASC || eType==IN_INDEX_INDEX_DESC ); #ifdef SQLITE_DEBUG /* Confirm that aiMap[] contains nVector integer values between 0 and ** nVector-1. */ |
︙ | ︙ | |||
2992 2993 2994 2995 2996 2997 2998 | ** vector, then it is stored in an array of nVector registers starting ** at r1. ** ** sqlite3FindInIndex() might have reordered the fields of the LHS vector ** so that the fields are in the same order as an existing index. The ** aiMap[] array contains a mapping from the original LHS field order to ** the field order that matches the RHS index. | | > > > > > > | | | | > > > > | | | > > > | | > > < | > > | | | | 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 | ** vector, then it is stored in an array of nVector registers starting ** at r1. ** ** sqlite3FindInIndex() might have reordered the fields of the LHS vector ** so that the fields are in the same order as an existing index. The ** aiMap[] array contains a mapping from the original LHS field order to ** the field order that matches the RHS index. ** ** Avoid factoring the LHS of the IN(...) expression out of the loop, ** even if it is constant, as OP_Affinity may be used on the register ** by code generated below. */ assert( pParse->okConstFactor==okConstFactor ); pParse->okConstFactor = 0; rLhsOrig = exprCodeVector(pParse, pLeft, &iDummy); pParse->okConstFactor = okConstFactor; for(i=0; i<nVector && aiMap[i]==i; i++){} /* Are LHS fields reordered? */ if( i==nVector ){ /* LHS fields are not reordered */ rLhs = rLhsOrig; }else{ /* Need to reorder the LHS fields according to aiMap */ rLhs = sqlite3GetTempRange(pParse, nVector); for(i=0; i<nVector; i++){ sqlite3VdbeAddOp3(v, OP_Copy, rLhsOrig+i, rLhs+aiMap[i], 0); } } /* If sqlite3FindInIndex() did not find or create an index that is ** suitable for evaluating the IN operator, then evaluate using a ** sequence of comparisons. ** ** This is step (1) in the in-operator.md optimized algorithm. */ if( eType==IN_INDEX_NOOP ){ ExprList *pList; CollSeq *pColl; int labelOk = sqlite3VdbeMakeLabel(pParse); int r2, regToFree; int regCkNull = 0; int ii; assert( ExprUseXList(pExpr) ); pList = pExpr->x.pList; pColl = sqlite3ExprCollSeq(pParse, pExpr->pLeft); if( destIfNull!=destIfFalse ){ regCkNull = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp3(v, OP_BitAnd, rLhs, rLhs, regCkNull); } for(ii=0; ii<pList->nExpr; ii++){ r2 = sqlite3ExprCodeTemp(pParse, pList->a[ii].pExpr, ®ToFree); if( regCkNull && sqlite3ExprCanBeNull(pList->a[ii].pExpr) ){ sqlite3VdbeAddOp3(v, OP_BitAnd, regCkNull, r2, regCkNull); } sqlite3ReleaseTempReg(pParse, regToFree); if( ii<pList->nExpr-1 || destIfNull!=destIfFalse ){ int op = rLhs!=r2 ? OP_Eq : OP_NotNull; sqlite3VdbeAddOp4(v, op, rLhs, labelOk, r2, (void*)pColl, P4_COLLSEQ); VdbeCoverageIf(v, ii<pList->nExpr-1 && op==OP_Eq); VdbeCoverageIf(v, ii==pList->nExpr-1 && op==OP_Eq); VdbeCoverageIf(v, ii<pList->nExpr-1 && op==OP_NotNull); VdbeCoverageIf(v, ii==pList->nExpr-1 && op==OP_NotNull); sqlite3VdbeChangeP5(v, zAff[0]); }else{ int op = rLhs!=r2 ? OP_Ne : OP_IsNull; assert( destIfNull==destIfFalse ); sqlite3VdbeAddOp4(v, op, rLhs, destIfFalse, r2, (void*)pColl, P4_COLLSEQ); VdbeCoverageIf(v, op==OP_Ne); VdbeCoverageIf(v, op==OP_IsNull); sqlite3VdbeChangeP5(v, zAff[0] | SQLITE_JUMPIFNULL); } } if( regCkNull ){ sqlite3VdbeAddOp2(v, OP_IsNull, regCkNull, destIfNull); VdbeCoverage(v); sqlite3VdbeGoto(v, destIfFalse); } sqlite3VdbeResolveLabel(v, labelOk); sqlite3ReleaseTempReg(pParse, regCkNull); goto sqlite3ExprCodeIN_finished; } /* Step 2: Check to see if the LHS contains any NULL columns. If the ** LHS does contain NULLs then the result must be either FALSE or NULL. ** We will then skip the binary search of the RHS. */ if( destIfNull==destIfFalse ){ destStep2 = destIfFalse; }else{ destStep2 = destStep6 = sqlite3VdbeMakeLabel(pParse); } if( pParse->nErr ) goto sqlite3ExprCodeIN_finished; for(i=0; i<nVector; i++){ Expr *p = sqlite3VectorFieldSubexpr(pExpr->pLeft, i); if( pParse->db->mallocFailed ) goto sqlite3ExprCodeIN_oom_error; if( sqlite3ExprCanBeNull(p) ){ sqlite3VdbeAddOp2(v, OP_IsNull, rLhs+i, destStep2); VdbeCoverage(v); } } /* Step 3. The LHS is now known to be non-NULL. Do the binary search ** of the RHS using the LHS as a probe. If found, the result is ** true. */ if( eType==IN_INDEX_ROWID ){ /* In this case, the RHS is the ROWID of table b-tree and so we also ** know that the RHS is non-NULL. Hence, we combine steps 3 and 4 ** into a single opcode. */ sqlite3VdbeAddOp3(v, OP_SeekRowid, iTab, destIfFalse, rLhs); VdbeCoverage(v); addrTruthOp = sqlite3VdbeAddOp0(v, OP_Goto); /* Return True */ }else{ sqlite3VdbeAddOp4(v, OP_Affinity, rLhs, nVector, 0, zAff, nVector); if( destIfFalse==destIfNull ){ /* Combine Step 3 and Step 5 into a single opcode */ sqlite3VdbeAddOp4Int(v, OP_NotFound, iTab, destIfFalse, rLhs, nVector); VdbeCoverage(v); goto sqlite3ExprCodeIN_finished; } /* Ordinary Step 3, for the case where FALSE and NULL are distinct */ addrTruthOp = sqlite3VdbeAddOp4Int(v, OP_Found, iTab, 0, rLhs, nVector); VdbeCoverage(v); } /* Step 4. If the RHS is known to be non-NULL and we did not find ** an match on the search above, then the result must be FALSE. */ if( rRhsHasNull && nVector==1 ){ |
︙ | ︙ | |||
3114 3115 3116 3117 3118 3119 3120 | ** If any comparison is NULL, then the result is NULL. If all ** comparisons are FALSE then the final result is FALSE. ** ** For a scalar LHS, it is sufficient to check just the first row ** of the RHS. */ if( destStep6 ) sqlite3VdbeResolveLabel(v, destStep6); | | | | | | 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 3587 3588 3589 | ** If any comparison is NULL, then the result is NULL. If all ** comparisons are FALSE then the final result is FALSE. ** ** For a scalar LHS, it is sufficient to check just the first row ** of the RHS. */ if( destStep6 ) sqlite3VdbeResolveLabel(v, destStep6); addrTop = sqlite3VdbeAddOp2(v, OP_Rewind, iTab, destIfFalse); VdbeCoverage(v); if( nVector>1 ){ destNotNull = sqlite3VdbeMakeLabel(pParse); }else{ /* For nVector==1, combine steps 6 and 7 by immediately returning ** FALSE if the first comparison is not NULL */ destNotNull = destIfFalse; } for(i=0; i<nVector; i++){ Expr *p; CollSeq *pColl; int r3 = sqlite3GetTempReg(pParse); p = sqlite3VectorFieldSubexpr(pLeft, i); pColl = sqlite3ExprCollSeq(pParse, p); sqlite3VdbeAddOp3(v, OP_Column, iTab, i, r3); sqlite3VdbeAddOp4(v, OP_Ne, rLhs+i, destNotNull, r3, (void*)pColl, P4_COLLSEQ); VdbeCoverage(v); sqlite3ReleaseTempReg(pParse, r3); } sqlite3VdbeAddOp2(v, OP_Goto, 0, destIfNull); if( nVector>1 ){ sqlite3VdbeResolveLabel(v, destNotNull); sqlite3VdbeAddOp2(v, OP_Next, iTab, addrTop+1); VdbeCoverage(v); /* Step 7: If we reach this point, we know that the result must ** be false. */ sqlite3VdbeAddOp2(v, OP_Goto, 0, destIfFalse); } |
︙ | ︙ | |||
3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 | pParse->iSelfTab = 0; }else{ sqlite3ExprCodeGetColumnOfTable(pParse->pVdbe, pIdx->pTable, iTabCur, iTabCol, regOut); } } /* ** Generate code to extract the value of the iCol-th column of a table. */ void sqlite3ExprCodeGetColumnOfTable( | > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > | > | > > > > > > > > > > > > > > > > | > | > > > > > < < < | | | > < | > > | 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 | pParse->iSelfTab = 0; }else{ sqlite3ExprCodeGetColumnOfTable(pParse->pVdbe, pIdx->pTable, iTabCur, iTabCol, regOut); } } #ifndef SQLITE_OMIT_GENERATED_COLUMNS /* ** Generate code that will compute the value of generated column pCol ** and store the result in register regOut */ void sqlite3ExprCodeGeneratedColumn( Parse *pParse, /* Parsing context */ Table *pTab, /* Table containing the generated column */ Column *pCol, /* The generated column */ int regOut /* Put the result in this register */ ){ int iAddr; Vdbe *v = pParse->pVdbe; assert( v!=0 ); assert( pParse->iSelfTab!=0 ); if( pParse->iSelfTab>0 ){ iAddr = sqlite3VdbeAddOp3(v, OP_IfNullRow, pParse->iSelfTab-1, 0, regOut); }else{ iAddr = 0; } sqlite3ExprCodeCopy(pParse, sqlite3ColumnExpr(pTab,pCol), regOut); if( pCol->affinity>=SQLITE_AFF_TEXT ){ sqlite3VdbeAddOp4(v, OP_Affinity, regOut, 1, 0, &pCol->affinity, 1); } if( iAddr ) sqlite3VdbeJumpHere(v, iAddr); } #endif /* SQLITE_OMIT_GENERATED_COLUMNS */ /* ** Generate code to extract the value of the iCol-th column of a table. */ void sqlite3ExprCodeGetColumnOfTable( Vdbe *v, /* Parsing context */ Table *pTab, /* The table containing the value */ int iTabCur, /* The table cursor. Or the PK cursor for WITHOUT ROWID */ int iCol, /* Index of the column to extract */ int regOut /* Extract the value into this register */ ){ Column *pCol; assert( v!=0 ); if( pTab==0 ){ sqlite3VdbeAddOp3(v, OP_Column, iTabCur, iCol, regOut); return; } if( iCol<0 || iCol==pTab->iPKey ){ sqlite3VdbeAddOp2(v, OP_Rowid, iTabCur, regOut); }else{ int op; int x; if( IsVirtual(pTab) ){ op = OP_VColumn; x = iCol; #ifndef SQLITE_OMIT_GENERATED_COLUMNS }else if( (pCol = &pTab->aCol[iCol])->colFlags & COLFLAG_VIRTUAL ){ Parse *pParse = sqlite3VdbeParser(v); if( pCol->colFlags & COLFLAG_BUSY ){ sqlite3ErrorMsg(pParse, "generated column loop on \"%s\"", pCol->zCnName); }else{ int savedSelfTab = pParse->iSelfTab; pCol->colFlags |= COLFLAG_BUSY; pParse->iSelfTab = iTabCur+1; sqlite3ExprCodeGeneratedColumn(pParse, pTab, pCol, regOut); pParse->iSelfTab = savedSelfTab; pCol->colFlags &= ~COLFLAG_BUSY; } return; #endif }else if( !HasRowid(pTab) ){ testcase( iCol!=sqlite3TableColumnToStorage(pTab, iCol) ); x = sqlite3TableColumnToIndex(sqlite3PrimaryKeyIndex(pTab), iCol); op = OP_Column; }else{ x = sqlite3TableColumnToStorage(pTab,iCol); testcase( x!=iCol ); op = OP_Column; } sqlite3VdbeAddOp3(v, op, iTabCur, x, regOut); sqlite3ColumnDefault(v, pTab, iCol, regOut); } } /* ** Generate code that will extract the iColumn-th column from ** table pTab and store the column value in register iReg. ** ** There must be an open cursor to pTab in iTable when this routine ** is called. If iColumn<0 then code is generated that extracts the rowid. */ int sqlite3ExprCodeGetColumn( Parse *pParse, /* Parsing and code generating context */ Table *pTab, /* Description of the table we are reading from */ int iColumn, /* Index of the table column */ int iTable, /* The cursor pointing to the table */ int iReg, /* Store results here */ u8 p5 /* P5 value for OP_Column + FLAGS */ ){ assert( pParse->pVdbe!=0 ); sqlite3ExprCodeGetColumnOfTable(pParse->pVdbe, pTab, iTable, iColumn, iReg); if( p5 ){ VdbeOp *pOp = sqlite3VdbeGetOp(pParse->pVdbe,-1); if( pOp->opcode==OP_Column ) pOp->p5 = p5; } return iReg; } /* ** Generate code to move content from registers iFrom...iFrom+nReg-1 ** over to iTo..iTo+nReg-1. */ void sqlite3ExprCodeMove(Parse *pParse, int iFrom, int iTo, int nReg){ sqlite3VdbeAddOp3(pParse->pVdbe, OP_Move, iFrom, iTo, nReg); } /* ** Convert a scalar expression node to a TK_REGISTER referencing ** register iReg. The caller must ensure that iReg already contains ** the correct value for the expression. */ static void exprToRegister(Expr *pExpr, int iReg){ Expr *p = sqlite3ExprSkipCollateAndLikely(pExpr); if( NEVER(p==0) ) return; p->op2 = p->op; p->op = TK_REGISTER; p->iTable = iReg; ExprClearProperty(p, EP_Skip); } /* |
︙ | ︙ | |||
3337 3338 3339 3340 3341 3342 3343 | iResult = sqlite3ExprCodeTemp(pParse, p, piFreeable); }else{ *piFreeable = 0; if( p->op==TK_SELECT ){ #if SQLITE_OMIT_SUBQUERY iResult = 0; #else | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 3828 3829 3830 3831 3832 3833 3834 3835 3836 3837 3838 3839 3840 3841 3842 3843 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 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 3940 3941 3942 3943 3944 3945 3946 3947 3948 3949 3950 3951 3952 3953 3954 3955 3956 3957 3958 3959 3960 3961 3962 3963 3964 3965 3966 3967 3968 3969 3970 3971 3972 3973 | iResult = sqlite3ExprCodeTemp(pParse, p, piFreeable); }else{ *piFreeable = 0; if( p->op==TK_SELECT ){ #if SQLITE_OMIT_SUBQUERY iResult = 0; #else iResult = sqlite3CodeSubselect(pParse, p); #endif }else{ int i; iResult = pParse->nMem+1; pParse->nMem += nResult; assert( ExprUseXList(p) ); for(i=0; i<nResult; i++){ sqlite3ExprCodeFactorable(pParse, p->x.pList->a[i].pExpr, i+iResult); } } } return iResult; } /* ** If the last opcode is a OP_Copy, then set the do-not-merge flag (p5) ** so that a subsequent copy will not be merged into this one. */ static void setDoNotMergeFlagOnCopy(Vdbe *v){ if( sqlite3VdbeGetOp(v, -1)->opcode==OP_Copy ){ sqlite3VdbeChangeP5(v, 1); /* Tag trailing OP_Copy as not mergable */ } } /* ** Generate code to implement special SQL functions that are implemented ** in-line rather than by using the usual callbacks. */ static int exprCodeInlineFunction( Parse *pParse, /* Parsing context */ ExprList *pFarg, /* List of function arguments */ int iFuncId, /* Function ID. One of the INTFUNC_... values */ int target /* Store function result in this register */ ){ int nFarg; Vdbe *v = pParse->pVdbe; assert( v!=0 ); assert( pFarg!=0 ); nFarg = pFarg->nExpr; assert( nFarg>0 ); /* All in-line functions have at least one argument */ switch( iFuncId ){ case INLINEFUNC_coalesce: { /* Attempt a direct implementation of the built-in COALESCE() and ** IFNULL() functions. This avoids unnecessary evaluation of ** arguments past the first non-NULL argument. */ int endCoalesce = sqlite3VdbeMakeLabel(pParse); int i; assert( nFarg>=2 ); sqlite3ExprCode(pParse, pFarg->a[0].pExpr, target); for(i=1; i<nFarg; i++){ sqlite3VdbeAddOp2(v, OP_NotNull, target, endCoalesce); VdbeCoverage(v); sqlite3ExprCode(pParse, pFarg->a[i].pExpr, target); } setDoNotMergeFlagOnCopy(v); sqlite3VdbeResolveLabel(v, endCoalesce); break; } case INLINEFUNC_iif: { Expr caseExpr; memset(&caseExpr, 0, sizeof(caseExpr)); caseExpr.op = TK_CASE; caseExpr.x.pList = pFarg; return sqlite3ExprCodeTarget(pParse, &caseExpr, target); } default: { /* The UNLIKELY() function is a no-op. The result is the value ** of the first argument. */ assert( nFarg==1 || nFarg==2 ); target = sqlite3ExprCodeTarget(pParse, pFarg->a[0].pExpr, target); break; } /*********************************************************************** ** Test-only SQL functions that are only usable if enabled ** via SQLITE_TESTCTRL_INTERNAL_FUNCTIONS */ #if !defined(SQLITE_UNTESTABLE) case INLINEFUNC_expr_compare: { /* Compare two expressions using sqlite3ExprCompare() */ assert( nFarg==2 ); sqlite3VdbeAddOp2(v, OP_Integer, sqlite3ExprCompare(0,pFarg->a[0].pExpr, pFarg->a[1].pExpr,-1), target); break; } case INLINEFUNC_expr_implies_expr: { /* Compare two expressions using sqlite3ExprImpliesExpr() */ assert( nFarg==2 ); sqlite3VdbeAddOp2(v, OP_Integer, sqlite3ExprImpliesExpr(pParse,pFarg->a[0].pExpr, pFarg->a[1].pExpr,-1), target); break; } case INLINEFUNC_implies_nonnull_row: { /* REsult of sqlite3ExprImpliesNonNullRow() */ Expr *pA1; assert( nFarg==2 ); pA1 = pFarg->a[1].pExpr; if( pA1->op==TK_COLUMN ){ sqlite3VdbeAddOp2(v, OP_Integer, sqlite3ExprImpliesNonNullRow(pFarg->a[0].pExpr,pA1->iTable), target); }else{ sqlite3VdbeAddOp2(v, OP_Null, 0, target); } break; } case INLINEFUNC_affinity: { /* The AFFINITY() function evaluates to a string that describes ** the type affinity of the argument. This is used for testing of ** the SQLite type logic. */ const char *azAff[] = { "blob", "text", "numeric", "integer", "real" }; char aff; assert( nFarg==1 ); aff = sqlite3ExprAffinity(pFarg->a[0].pExpr); sqlite3VdbeLoadString(v, target, (aff<=SQLITE_AFF_NONE) ? "none" : azAff[aff-SQLITE_AFF_BLOB]); break; } #endif /* !defined(SQLITE_UNTESTABLE) */ } return target; } /* ** Generate code into the current Vdbe to evaluate the given ** expression. Attempt to store the results in register "target". ** Return the register where results are stored. ** |
︙ | ︙ | |||
3374 3375 3376 3377 3378 3379 3380 | int regFree1 = 0; /* If non-zero free this temporary register */ int regFree2 = 0; /* If non-zero free this temporary register */ int r1, r2; /* Various register numbers */ Expr tempX; /* Temporary expression node */ int p5 = 0; assert( target>0 && target<=pParse->nMem ); | < | < < > | > > > > > > > > > > > > > > > > | > > | > > > | < < < < > | > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > | > > > > | > > > > | 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994 3995 3996 3997 3998 3999 4000 4001 4002 4003 4004 4005 4006 4007 4008 4009 4010 4011 4012 4013 4014 4015 4016 4017 4018 4019 4020 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 4034 4035 4036 4037 4038 4039 4040 4041 4042 4043 4044 4045 4046 4047 4048 4049 4050 4051 4052 4053 4054 4055 4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075 4076 4077 4078 4079 4080 4081 4082 4083 4084 4085 4086 4087 4088 4089 4090 4091 4092 4093 4094 4095 4096 4097 4098 4099 4100 4101 4102 4103 4104 4105 4106 4107 4108 4109 4110 4111 4112 4113 4114 4115 4116 4117 4118 4119 4120 | int regFree1 = 0; /* If non-zero free this temporary register */ int regFree2 = 0; /* If non-zero free this temporary register */ int r1, r2; /* Various register numbers */ Expr tempX; /* Temporary expression node */ int p5 = 0; assert( target>0 && target<=pParse->nMem ); assert( v!=0 ); expr_code_doover: if( pExpr==0 ){ op = TK_NULL; }else{ assert( !ExprHasVVAProperty(pExpr,EP_Immutable) ); op = pExpr->op; } switch( op ){ case TK_AGG_COLUMN: { AggInfo *pAggInfo = pExpr->pAggInfo; struct AggInfo_col *pCol; assert( pAggInfo!=0 ); assert( pExpr->iAgg>=0 && pExpr->iAgg<pAggInfo->nColumn ); pCol = &pAggInfo->aCol[pExpr->iAgg]; if( !pAggInfo->directMode ){ assert( pCol->iMem>0 ); return pCol->iMem; }else if( pAggInfo->useSortingIdx ){ Table *pTab = pCol->pTab; sqlite3VdbeAddOp3(v, OP_Column, pAggInfo->sortingIdxPTab, pCol->iSorterColumn, target); if( pCol->iColumn<0 ){ VdbeComment((v,"%s.rowid",pTab->zName)); }else{ VdbeComment((v,"%s.%s", pTab->zName, pTab->aCol[pCol->iColumn].zCnName)); if( pTab->aCol[pCol->iColumn].affinity==SQLITE_AFF_REAL ){ sqlite3VdbeAddOp1(v, OP_RealAffinity, target); } } return target; } /* Otherwise, fall thru into the TK_COLUMN case */ /* no break */ deliberate_fall_through } case TK_COLUMN: { int iTab = pExpr->iTable; int iReg; if( ExprHasProperty(pExpr, EP_FixedCol) ){ /* This COLUMN expression is really a constant due to WHERE clause ** constraints, and that constant is coded by the pExpr->pLeft ** expresssion. However, make sure the constant has the correct ** datatype by applying the Affinity of the table column to the ** constant. */ int aff; iReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft,target); assert( ExprUseYTab(pExpr) ); if( pExpr->y.pTab ){ aff = sqlite3TableColumnAffinity(pExpr->y.pTab, pExpr->iColumn); }else{ aff = pExpr->affExpr; } if( aff>SQLITE_AFF_BLOB ){ static const char zAff[] = "B\000C\000D\000E"; assert( SQLITE_AFF_BLOB=='A' ); assert( SQLITE_AFF_TEXT=='B' ); sqlite3VdbeAddOp4(v, OP_Affinity, iReg, 1, 0, &zAff[(aff-'B')*2], P4_STATIC); } return iReg; } if( iTab<0 ){ if( pParse->iSelfTab<0 ){ /* Other columns in the same row for CHECK constraints or ** generated columns or for inserting into partial index. ** The row is unpacked into registers beginning at ** 0-(pParse->iSelfTab). The rowid (if any) is in a register ** immediately prior to the first column. */ Column *pCol; Table *pTab; int iSrc; int iCol = pExpr->iColumn; assert( ExprUseYTab(pExpr) ); pTab = pExpr->y.pTab; assert( pTab!=0 ); assert( iCol>=XN_ROWID ); assert( iCol<pTab->nCol ); if( iCol<0 ){ return -1-pParse->iSelfTab; } pCol = pTab->aCol + iCol; testcase( iCol!=sqlite3TableColumnToStorage(pTab,iCol) ); iSrc = sqlite3TableColumnToStorage(pTab, iCol) - pParse->iSelfTab; #ifndef SQLITE_OMIT_GENERATED_COLUMNS if( pCol->colFlags & COLFLAG_GENERATED ){ if( pCol->colFlags & COLFLAG_BUSY ){ sqlite3ErrorMsg(pParse, "generated column loop on \"%s\"", pCol->zCnName); return 0; } pCol->colFlags |= COLFLAG_BUSY; if( pCol->colFlags & COLFLAG_NOTAVAIL ){ sqlite3ExprCodeGeneratedColumn(pParse, pTab, pCol, iSrc); } pCol->colFlags &= ~(COLFLAG_BUSY|COLFLAG_NOTAVAIL); return iSrc; }else #endif /* SQLITE_OMIT_GENERATED_COLUMNS */ if( pCol->affinity==SQLITE_AFF_REAL ){ sqlite3VdbeAddOp2(v, OP_SCopy, iSrc, target); sqlite3VdbeAddOp1(v, OP_RealAffinity, target); return target; }else{ return iSrc; } }else{ /* Coding an expression that is part of an index where column names ** in the index refer to the table to which the index belongs */ iTab = pParse->iSelfTab - 1; } } assert( ExprUseYTab(pExpr) ); iReg = sqlite3ExprCodeGetColumn(pParse, pExpr->y.pTab, pExpr->iColumn, iTab, target, pExpr->op2); if( pExpr->y.pTab==0 && pExpr->affExpr==SQLITE_AFF_REAL ){ sqlite3VdbeAddOp1(v, OP_RealAffinity, iReg); } return iReg; } case TK_INTEGER: { codeInteger(pParse, pExpr, 0, target); return target; } case TK_TRUEFALSE: { sqlite3VdbeAddOp2(v, OP_Integer, sqlite3ExprTruthValue(pExpr), target); |
︙ | ︙ | |||
3457 3458 3459 3460 3461 3462 3463 | } #endif case TK_STRING: { assert( !ExprHasProperty(pExpr, EP_IntValue) ); sqlite3VdbeLoadString(v, target, pExpr->u.zToken); return target; } | | > > > > > | 4128 4129 4130 4131 4132 4133 4134 4135 4136 4137 4138 4139 4140 4141 4142 4143 4144 4145 4146 4147 | } #endif case TK_STRING: { assert( !ExprHasProperty(pExpr, EP_IntValue) ); sqlite3VdbeLoadString(v, target, pExpr->u.zToken); return target; } default: { /* Make NULL the default case so that if a bug causes an illegal ** Expr node to be passed into this function, it will be handled ** sanely and not crash. But keep the assert() to bring the problem ** to the attention of the developers. */ assert( op==TK_NULL || op==TK_ERROR || pParse->db->mallocFailed ); sqlite3VdbeAddOp2(v, OP_Null, 0, target); return target; } #ifndef SQLITE_OMIT_BLOB_LITERAL case TK_BLOB: { int n; const char *z; |
︙ | ︙ | |||
3484 3485 3486 3487 3488 3489 3490 | case TK_VARIABLE: { assert( !ExprHasProperty(pExpr, EP_IntValue) ); assert( pExpr->u.zToken!=0 ); assert( pExpr->u.zToken[0]!=0 ); sqlite3VdbeAddOp2(v, OP_Variable, pExpr->iColumn, target); if( pExpr->u.zToken[1]!=0 ){ const char *z = sqlite3VListNumToName(pParse->pVList, pExpr->iColumn); | | > | 4160 4161 4162 4163 4164 4165 4166 4167 4168 4169 4170 4171 4172 4173 4174 4175 4176 4177 4178 4179 4180 4181 4182 4183 4184 4185 4186 4187 4188 4189 4190 4191 | case TK_VARIABLE: { assert( !ExprHasProperty(pExpr, EP_IntValue) ); assert( pExpr->u.zToken!=0 ); assert( pExpr->u.zToken[0]!=0 ); sqlite3VdbeAddOp2(v, OP_Variable, pExpr->iColumn, target); if( pExpr->u.zToken[1]!=0 ){ const char *z = sqlite3VListNumToName(pParse->pVList, pExpr->iColumn); assert( pExpr->u.zToken[0]=='?' || (z && !strcmp(pExpr->u.zToken, z)) ); pParse->pVList[0] = 0; /* Indicate VList may no longer be enlarged */ sqlite3VdbeAppendP4(v, (char*)z, P4_STATIC); } return target; } case TK_REGISTER: { return pExpr->iTable; } #ifndef SQLITE_OMIT_CAST case TK_CAST: { /* Expressions of the form: CAST(pLeft AS token) */ inReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target); if( inReg!=target ){ sqlite3VdbeAddOp2(v, OP_SCopy, inReg, target); inReg = target; } assert( !ExprHasProperty(pExpr, EP_IntValue) ); sqlite3VdbeAddOp2(v, OP_Cast, target, sqlite3AffinityType(pExpr->u.zToken, 0)); return inReg; } #endif /* SQLITE_OMIT_CAST */ case TK_IS: case TK_ISNOT: |
︙ | ︙ | |||
3523 3524 3525 3526 3527 3528 3529 | case TK_EQ: { Expr *pLeft = pExpr->pLeft; if( sqlite3ExprIsVector(pLeft) ){ codeVectorCompare(pParse, pExpr, target, op, p5); }else{ r1 = sqlite3ExprCodeTemp(pParse, pLeft, ®Free1); r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, ®Free2); | > | < > > > > > > > | 4200 4201 4202 4203 4204 4205 4206 4207 4208 4209 4210 4211 4212 4213 4214 4215 4216 4217 4218 4219 4220 4221 4222 4223 4224 4225 4226 4227 4228 | case TK_EQ: { Expr *pLeft = pExpr->pLeft; if( sqlite3ExprIsVector(pLeft) ){ codeVectorCompare(pParse, pExpr, target, op, p5); }else{ r1 = sqlite3ExprCodeTemp(pParse, pLeft, ®Free1); r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, ®Free2); sqlite3VdbeAddOp2(v, OP_Integer, 1, inReg); codeCompare(pParse, pLeft, pExpr->pRight, op, r1, r2, sqlite3VdbeCurrentAddr(v)+2, p5, ExprHasProperty(pExpr,EP_Commuted)); assert(TK_LT==OP_Lt); testcase(op==OP_Lt); VdbeCoverageIf(v,op==OP_Lt); assert(TK_LE==OP_Le); testcase(op==OP_Le); VdbeCoverageIf(v,op==OP_Le); assert(TK_GT==OP_Gt); testcase(op==OP_Gt); VdbeCoverageIf(v,op==OP_Gt); assert(TK_GE==OP_Ge); testcase(op==OP_Ge); VdbeCoverageIf(v,op==OP_Ge); assert(TK_EQ==OP_Eq); testcase(op==OP_Eq); VdbeCoverageIf(v,op==OP_Eq); assert(TK_NE==OP_Ne); testcase(op==OP_Ne); VdbeCoverageIf(v,op==OP_Ne); if( p5==SQLITE_NULLEQ ){ sqlite3VdbeAddOp2(v, OP_Integer, 0, inReg); }else{ sqlite3VdbeAddOp3(v, OP_ZeroOrNull, r1, inReg, r2); } testcase( regFree1==0 ); testcase( regFree2==0 ); } break; } case TK_AND: case TK_OR: |
︙ | ︙ | |||
3582 3583 3584 3585 3586 3587 3588 3589 3590 3591 3592 3593 3594 3595 | codeReal(v, pLeft->u.zToken, 1, target); return target; #endif }else{ tempX.op = TK_INTEGER; tempX.flags = EP_IntValue|EP_TokenOnly; tempX.u.iValue = 0; r1 = sqlite3ExprCodeTemp(pParse, &tempX, ®Free1); r2 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free2); sqlite3VdbeAddOp3(v, OP_Subtract, r2, r1, target); testcase( regFree2==0 ); } break; } | > | 4266 4267 4268 4269 4270 4271 4272 4273 4274 4275 4276 4277 4278 4279 4280 | codeReal(v, pLeft->u.zToken, 1, target); return target; #endif }else{ tempX.op = TK_INTEGER; tempX.flags = EP_IntValue|EP_TokenOnly; tempX.u.iValue = 0; ExprClearVVAProperties(&tempX); r1 = sqlite3ExprCodeTemp(pParse, &tempX, ®Free1); r2 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free2); sqlite3VdbeAddOp3(v, OP_Subtract, r2, r1, target); testcase( regFree2==0 ); } break; } |
︙ | ︙ | |||
3627 3628 3629 3630 3631 3632 3633 | VdbeCoverageIf(v, op==TK_NOTNULL); sqlite3VdbeAddOp2(v, OP_Integer, 0, target); sqlite3VdbeJumpHere(v, addr); break; } case TK_AGG_FUNCTION: { AggInfo *pInfo = pExpr->pAggInfo; | | > > > | 4312 4313 4314 4315 4316 4317 4318 4319 4320 4321 4322 4323 4324 4325 4326 4327 4328 4329 | VdbeCoverageIf(v, op==TK_NOTNULL); sqlite3VdbeAddOp2(v, OP_Integer, 0, target); sqlite3VdbeJumpHere(v, addr); break; } case TK_AGG_FUNCTION: { AggInfo *pInfo = pExpr->pAggInfo; if( pInfo==0 || NEVER(pExpr->iAgg<0) || NEVER(pExpr->iAgg>=pInfo->nFunc) ){ assert( !ExprHasProperty(pExpr, EP_IntValue) ); sqlite3ErrorMsg(pParse, "misuse of aggregate: %s()", pExpr->u.zToken); }else{ return pInfo->aFunc[pExpr->iAgg].iMem; } break; } |
︙ | ︙ | |||
3653 3654 3655 3656 3657 3658 3659 | #ifndef SQLITE_OMIT_WINDOWFUNC if( ExprHasProperty(pExpr, EP_WinFunc) ){ return pExpr->y.pWin->regResult; } #endif if( ConstFactorOk(pParse) && sqlite3ExprIsConstantNotJoin(pExpr) ){ | | | | | | < < | < < < < < < | < < < < < < < < < < < | < < < | < | < | < < < < < | < < < | < < < < | 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 | #ifndef SQLITE_OMIT_WINDOWFUNC if( ExprHasProperty(pExpr, EP_WinFunc) ){ return pExpr->y.pWin->regResult; } #endif if( ConstFactorOk(pParse) && sqlite3ExprIsConstantNotJoin(pExpr) ){ /* SQL functions can be expensive. So try to avoid running them ** multiple times if we know they always give the same result */ return sqlite3ExprCodeRunJustOnce(pParse, pExpr, -1); } assert( !ExprHasProperty(pExpr, EP_TokenOnly) ); assert( ExprUseXList(pExpr) ); pFarg = pExpr->x.pList; nFarg = pFarg ? pFarg->nExpr : 0; assert( !ExprHasProperty(pExpr, EP_IntValue) ); zId = pExpr->u.zToken; pDef = sqlite3FindFunction(db, zId, nFarg, enc, 0); #ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION if( pDef==0 && pParse->explain ){ pDef = sqlite3FindFunction(db, "unknown", nFarg, enc, 0); } #endif if( pDef==0 || pDef->xFinalize!=0 ){ sqlite3ErrorMsg(pParse, "unknown function: %s()", zId); break; } if( pDef->funcFlags & SQLITE_FUNC_INLINE ){ assert( (pDef->funcFlags & SQLITE_FUNC_UNSAFE)==0 ); assert( (pDef->funcFlags & SQLITE_FUNC_DIRECT)==0 ); return exprCodeInlineFunction(pParse, pFarg, SQLITE_PTR_TO_INT(pDef->pUserData), target); }else if( pDef->funcFlags & (SQLITE_FUNC_DIRECT|SQLITE_FUNC_UNSAFE) ){ sqlite3ExprFunctionUsable(pParse, pExpr, pDef); } for(i=0; i<nFarg; i++){ if( i<32 && sqlite3ExprIsConstant(pFarg->a[i].pExpr) ){ testcase( i==31 ); constMask |= MASKBIT32(i); } if( (pDef->funcFlags & SQLITE_FUNC_NEEDCOLL)!=0 && !pColl ){ |
︙ | ︙ | |||
3783 3784 3785 3786 3787 3788 3789 | } #endif if( pDef->funcFlags & SQLITE_FUNC_NEEDCOLL ){ if( !pColl ) pColl = db->pDfltColl; sqlite3VdbeAddOp4(v, OP_CollSeq, 0, 0, 0, (char *)pColl, P4_COLLSEQ); } #ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC | | < | < > | > | > > > > > > > | > | | | < | | | | | 4435 4436 4437 4438 4439 4440 4441 4442 4443 4444 4445 4446 4447 4448 4449 4450 4451 4452 4453 4454 4455 4456 4457 4458 4459 4460 4461 4462 4463 4464 4465 4466 4467 4468 4469 4470 4471 4472 4473 4474 4475 4476 4477 4478 4479 4480 4481 4482 4483 4484 4485 4486 4487 4488 4489 4490 4491 4492 4493 4494 4495 4496 4497 4498 4499 4500 4501 4502 4503 4504 | } #endif if( pDef->funcFlags & SQLITE_FUNC_NEEDCOLL ){ if( !pColl ) pColl = db->pDfltColl; sqlite3VdbeAddOp4(v, OP_CollSeq, 0, 0, 0, (char *)pColl, P4_COLLSEQ); } #ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC if( (pDef->funcFlags & SQLITE_FUNC_OFFSET)!=0 && ALWAYS(pFarg!=0) ){ Expr *pArg = pFarg->a[0].pExpr; if( pArg->op==TK_COLUMN ){ sqlite3VdbeAddOp3(v, OP_Offset, pArg->iTable, pArg->iColumn, target); }else{ sqlite3VdbeAddOp2(v, OP_Null, 0, target); } }else #endif { sqlite3VdbeAddFunctionCall(pParse, constMask, r1, target, nFarg, pDef, pExpr->op2); } if( nFarg ){ if( constMask==0 ){ sqlite3ReleaseTempRange(pParse, r1, nFarg); }else{ sqlite3VdbeReleaseRegisters(pParse, r1, nFarg, constMask, 1); } } return target; } #ifndef SQLITE_OMIT_SUBQUERY case TK_EXISTS: case TK_SELECT: { int nCol; testcase( op==TK_EXISTS ); testcase( op==TK_SELECT ); if( pParse->db->mallocFailed ){ return 0; }else if( op==TK_SELECT && ALWAYS( ExprUseXSelect(pExpr) ) && (nCol = pExpr->x.pSelect->pEList->nExpr)!=1 ){ sqlite3SubselectError(pParse, nCol, 1); }else{ return sqlite3CodeSubselect(pParse, pExpr); } break; } case TK_SELECT_COLUMN: { int n; if( pExpr->pLeft->iTable==0 ){ pExpr->pLeft->iTable = sqlite3CodeSubselect(pParse, pExpr->pLeft); } assert( pExpr->pLeft->op==TK_SELECT || pExpr->pLeft->op==TK_ERROR ); n = sqlite3ExprVectorSize(pExpr->pLeft); if( pExpr->iTable!=n ){ sqlite3ErrorMsg(pParse, "%d columns assigned %d values", pExpr->iTable, n); } return pExpr->pLeft->iTable + pExpr->iColumn; } case TK_IN: { int destIfFalse = sqlite3VdbeMakeLabel(pParse); int destIfNull = sqlite3VdbeMakeLabel(pParse); sqlite3VdbeAddOp2(v, OP_Null, 0, target); sqlite3ExprCodeIN(pParse, pExpr, destIfFalse, destIfNull); sqlite3VdbeAddOp2(v, OP_Integer, 1, target); sqlite3VdbeResolveLabel(v, destIfFalse); sqlite3VdbeAddOp2(v, OP_AddImm, target, 0); sqlite3VdbeResolveLabel(v, destIfNull); return target; |
︙ | ︙ | |||
3891 3892 3893 3894 3895 3896 3897 | ** ** Then p1 is interpreted as follows: ** ** p1==0 -> old.rowid p1==3 -> new.rowid ** p1==1 -> old.a p1==4 -> new.a ** p1==2 -> old.b p1==5 -> new.b */ | > > > > > | > | > | | | < | < > > > > > > > > > > > > > | 4550 4551 4552 4553 4554 4555 4556 4557 4558 4559 4560 4561 4562 4563 4564 4565 4566 4567 4568 4569 4570 4571 4572 4573 4574 4575 4576 4577 4578 4579 4580 4581 4582 4583 4584 4585 4586 4587 4588 4589 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 | ** ** Then p1 is interpreted as follows: ** ** p1==0 -> old.rowid p1==3 -> new.rowid ** p1==1 -> old.a p1==4 -> new.a ** p1==2 -> old.b p1==5 -> new.b */ Table *pTab; int iCol; int p1; assert( ExprUseYTab(pExpr) ); pTab = pExpr->y.pTab; iCol = pExpr->iColumn; p1 = pExpr->iTable * (pTab->nCol+1) + 1 + sqlite3TableColumnToStorage(pTab, iCol); assert( pExpr->iTable==0 || pExpr->iTable==1 ); assert( iCol>=-1 && iCol<pTab->nCol ); assert( pTab->iPKey<0 || iCol!=pTab->iPKey ); assert( p1>=0 && p1<(pTab->nCol*2+2) ); sqlite3VdbeAddOp2(v, OP_Param, p1, target); VdbeComment((v, "r[%d]=%s.%s", target, (pExpr->iTable ? "new" : "old"), (pExpr->iColumn<0 ? "rowid" : pExpr->y.pTab->aCol[iCol].zCnName) )); #ifndef SQLITE_OMIT_FLOATING_POINT /* If the column has REAL affinity, it may currently be stored as an ** integer. Use OP_RealAffinity to make sure it is really real. ** ** EVIDENCE-OF: R-60985-57662 SQLite will convert the value back to ** floating point when extracting it from the record. */ if( iCol>=0 && pTab->aCol[iCol].affinity==SQLITE_AFF_REAL ){ sqlite3VdbeAddOp1(v, OP_RealAffinity, target); } #endif break; } case TK_VECTOR: { sqlite3ErrorMsg(pParse, "row value misused"); break; } /* TK_IF_NULL_ROW Expr nodes are inserted ahead of expressions ** that derive from the right-hand table of a LEFT JOIN. The ** Expr.iTable value is the table number for the right-hand table. ** The expression is only evaluated if that table is not currently ** on a LEFT JOIN NULL row. */ case TK_IF_NULL_ROW: { int addrINR; u8 okConstFactor = pParse->okConstFactor; addrINR = sqlite3VdbeAddOp1(v, OP_IfNullRow, pExpr->iTable); /* Temporarily disable factoring of constant expressions, since ** even though expressions may appear to be constant, they are not ** really constant because they originate from the right-hand side ** of a LEFT JOIN. */ pParse->okConstFactor = 0; inReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target); pParse->okConstFactor = okConstFactor; sqlite3VdbeJumpHere(v, addrINR); sqlite3VdbeChangeP3(v, addrINR, inReg); break; } /* ** Form A: |
︙ | ︙ | |||
3955 3956 3957 3958 3959 3960 3961 | ** is even, then Y is omitted and the "otherwise" result is NULL. ** Ei is in pExpr->pList->a[i*2] and Ri is pExpr->pList->a[i*2+1]. ** ** The result of the expression is the Ri for the first matching Ei, ** or if there is no matching Ei, the ELSE term Y, or if there is ** no ELSE term, NULL. */ | | > > | | | > > > > | | | > > | | | | | | | | > | | > > > > > > | | > > | > > > > > > > > > > > > > > | | | | | | | | > | > | | 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 | ** is even, then Y is omitted and the "otherwise" result is NULL. ** Ei is in pExpr->pList->a[i*2] and Ri is pExpr->pList->a[i*2+1]. ** ** The result of the expression is the Ri for the first matching Ei, ** or if there is no matching Ei, the ELSE term Y, or if there is ** no ELSE term, NULL. */ case TK_CASE: { int endLabel; /* GOTO label for end of CASE stmt */ int nextCase; /* GOTO label for next WHEN clause */ int nExpr; /* 2x number of WHEN terms */ int i; /* Loop counter */ ExprList *pEList; /* List of WHEN terms */ struct ExprList_item *aListelem; /* Array of WHEN terms */ Expr opCompare; /* The X==Ei expression */ Expr *pX; /* The X expression */ Expr *pTest = 0; /* X==Ei (form A) or just Ei (form B) */ Expr *pDel = 0; sqlite3 *db = pParse->db; assert( ExprUseXList(pExpr) && pExpr->x.pList!=0 ); assert(pExpr->x.pList->nExpr > 0); pEList = pExpr->x.pList; aListelem = pEList->a; nExpr = pEList->nExpr; endLabel = sqlite3VdbeMakeLabel(pParse); if( (pX = pExpr->pLeft)!=0 ){ pDel = sqlite3ExprDup(db, pX, 0); if( db->mallocFailed ){ sqlite3ExprDelete(db, pDel); break; } testcase( pX->op==TK_COLUMN ); exprToRegister(pDel, exprCodeVector(pParse, pDel, ®Free1)); testcase( regFree1==0 ); memset(&opCompare, 0, sizeof(opCompare)); opCompare.op = TK_EQ; opCompare.pLeft = pDel; pTest = &opCompare; /* Ticket b351d95f9cd5ef17e9d9dbae18f5ca8611190001: ** The value in regFree1 might get SCopy-ed into the file result. ** So make sure that the regFree1 register is not reused for other ** purposes and possibly overwritten. */ regFree1 = 0; } for(i=0; i<nExpr-1; i=i+2){ if( pX ){ assert( pTest!=0 ); opCompare.pRight = aListelem[i].pExpr; }else{ pTest = aListelem[i].pExpr; } nextCase = sqlite3VdbeMakeLabel(pParse); testcase( pTest->op==TK_COLUMN ); sqlite3ExprIfFalse(pParse, pTest, nextCase, SQLITE_JUMPIFNULL); testcase( aListelem[i+1].pExpr->op==TK_COLUMN ); sqlite3ExprCode(pParse, aListelem[i+1].pExpr, target); sqlite3VdbeGoto(v, endLabel); sqlite3VdbeResolveLabel(v, nextCase); } if( (nExpr&1)!=0 ){ sqlite3ExprCode(pParse, pEList->a[nExpr-1].pExpr, target); }else{ sqlite3VdbeAddOp2(v, OP_Null, 0, target); } sqlite3ExprDelete(db, pDel); setDoNotMergeFlagOnCopy(v); sqlite3VdbeResolveLabel(v, endLabel); break; } #ifndef SQLITE_OMIT_TRIGGER case TK_RAISE: { assert( pExpr->affExpr==OE_Rollback || pExpr->affExpr==OE_Abort || pExpr->affExpr==OE_Fail || pExpr->affExpr==OE_Ignore ); if( !pParse->pTriggerTab && !pParse->nested ){ sqlite3ErrorMsg(pParse, "RAISE() may only be used within a trigger-program"); return 0; } if( pExpr->affExpr==OE_Abort ){ sqlite3MayAbort(pParse); } assert( !ExprHasProperty(pExpr, EP_IntValue) ); if( pExpr->affExpr==OE_Ignore ){ sqlite3VdbeAddOp4( v, OP_Halt, SQLITE_OK, OE_Ignore, 0, pExpr->u.zToken,0); VdbeCoverage(v); }else{ sqlite3HaltConstraint(pParse, pParse->pTriggerTab ? SQLITE_CONSTRAINT_TRIGGER : SQLITE_ERROR, pExpr->affExpr, pExpr->u.zToken, 0, 0); } break; } #endif } sqlite3ReleaseTempReg(pParse, regFree1); sqlite3ReleaseTempReg(pParse, regFree2); return inReg; } /* ** Generate code that will evaluate expression pExpr just one time ** per prepared statement execution. ** ** If the expression uses functions (that might throw an exception) then ** guard them with an OP_Once opcode to ensure that the code is only executed ** once. If no functions are involved, then factor the code out and put it at ** the end of the prepared statement in the initialization section. ** ** If regDest>=0 then the result is always stored in that register and the ** result is not reusable. If regDest<0 then this routine is free to ** store the value whereever it wants. The register where the expression ** is stored is returned. When regDest<0, two identical expressions might ** code to the same register, if they do not contain function calls and hence ** are factored out into the initialization section at the end of the ** prepared statement. */ int sqlite3ExprCodeRunJustOnce( Parse *pParse, /* Parsing context */ Expr *pExpr, /* The expression to code when the VDBE initializes */ int regDest /* Store the value in this register */ ){ ExprList *p; assert( ConstFactorOk(pParse) ); p = pParse->pConstExpr; if( regDest<0 && p ){ struct ExprList_item *pItem; int i; for(pItem=p->a, i=p->nExpr; i>0; pItem++, i--){ if( pItem->reusable && sqlite3ExprCompare(0,pItem->pExpr,pExpr,-1)==0 ){ return pItem->u.iConstExprReg; } } } pExpr = sqlite3ExprDup(pParse->db, pExpr, 0); if( pExpr!=0 && ExprHasProperty(pExpr, EP_HasFunc) ){ Vdbe *v = pParse->pVdbe; int addr; assert( v ); addr = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v); pParse->okConstFactor = 0; if( !pParse->db->mallocFailed ){ if( regDest<0 ) regDest = ++pParse->nMem; sqlite3ExprCode(pParse, pExpr, regDest); } pParse->okConstFactor = 1; sqlite3ExprDelete(pParse->db, pExpr); sqlite3VdbeJumpHere(v, addr); }else{ p = sqlite3ExprListAppend(pParse, p, pExpr); if( p ){ struct ExprList_item *pItem = &p->a[p->nExpr-1]; pItem->reusable = regDest<0; if( regDest<0 ) regDest = ++pParse->nMem; pItem->u.iConstExprReg = regDest; } pParse->pConstExpr = p; } return regDest; } /* ** Generate code to evaluate an expression and store the results ** into a register. Return the register number where the results ** are stored. ** ** If the register is a temporary register that can be deallocated, ** then write its number into *pReg. If the result register is not ** a temporary, then set *pReg to zero. ** ** If pExpr is a constant, then this routine might generate this ** code to fill the register in the initialization section of the ** VDBE program, in order to factor it out of the evaluation loop. */ int sqlite3ExprCodeTemp(Parse *pParse, Expr *pExpr, int *pReg){ int r2; pExpr = sqlite3ExprSkipCollateAndLikely(pExpr); if( ConstFactorOk(pParse) && ALWAYS(pExpr!=0) && pExpr->op!=TK_REGISTER && sqlite3ExprIsConstantNotJoin(pExpr) ){ *pReg = 0; r2 = sqlite3ExprCodeRunJustOnce(pParse, pExpr, -1); }else{ int r1 = sqlite3GetTempReg(pParse); r2 = sqlite3ExprCodeTarget(pParse, pExpr, r1); if( r2==r1 ){ *pReg = r1; }else{ sqlite3ReleaseTempReg(pParse, r1); |
︙ | ︙ | |||
4125 4126 4127 4128 4129 4130 4131 4132 | ** Generate code that will evaluate expression pExpr and store the ** results in register target. The results are guaranteed to appear ** in register target. */ void sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){ int inReg; assert( target>0 && target<=pParse->nMem ); | > < | | | < | > > > > | > | 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 | ** Generate code that will evaluate expression pExpr and store the ** results in register target. The results are guaranteed to appear ** in register target. */ void sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){ int inReg; assert( pExpr==0 || !ExprHasVVAProperty(pExpr,EP_Immutable) ); assert( target>0 && target<=pParse->nMem ); assert( pParse->pVdbe!=0 || pParse->db->mallocFailed ); if( pParse->pVdbe==0 ) return; inReg = sqlite3ExprCodeTarget(pParse, pExpr, target); if( inReg!=target ){ u8 op; if( ALWAYS(pExpr) && ExprHasProperty(pExpr,EP_Subquery) ){ op = OP_Copy; }else{ op = OP_SCopy; } sqlite3VdbeAddOp2(pParse->pVdbe, op, inReg, target); } } /* ** Make a transient copy of expression pExpr and then code it using ** sqlite3ExprCode(). This routine works just like sqlite3ExprCode() ** except that the input expression is guaranteed to be unchanged. |
︙ | ︙ | |||
4157 4158 4159 4160 4161 4162 4163 | ** Generate code that will evaluate expression pExpr and store the ** results in register target. The results are guaranteed to appear ** in register target. If the expression is constant, then this routine ** might choose to code the expression at initialization time. */ void sqlite3ExprCodeFactorable(Parse *pParse, Expr *pExpr, int target){ if( pParse->okConstFactor && sqlite3ExprIsConstantNotJoin(pExpr) ){ | | | < < < < < < < < < < < < < < < < < < < < < < < < | 4871 4872 4873 4874 4875 4876 4877 4878 4879 4880 4881 4882 4883 4884 4885 4886 4887 4888 | ** Generate code that will evaluate expression pExpr and store the ** results in register target. The results are guaranteed to appear ** in register target. If the expression is constant, then this routine ** might choose to code the expression at initialization time. */ void sqlite3ExprCodeFactorable(Parse *pParse, Expr *pExpr, int target){ if( pParse->okConstFactor && sqlite3ExprIsConstantNotJoin(pExpr) ){ sqlite3ExprCodeRunJustOnce(pParse, pExpr, target); }else{ sqlite3ExprCodeCopy(pParse, pExpr, target); } } /* ** Generate code that pushes the value of every element of the given ** expression list into a sequence of registers beginning at target. ** ** Return the number of elements evaluated. The number returned will |
︙ | ︙ | |||
4241 4242 4243 4244 4245 4246 4247 | n--; }else{ sqlite3VdbeAddOp2(v, copyOp, j+srcReg-1, target+i); } }else if( (flags & SQLITE_ECEL_FACTOR)!=0 && sqlite3ExprIsConstantNotJoin(pExpr) ){ | | > | 4931 4932 4933 4934 4935 4936 4937 4938 4939 4940 4941 4942 4943 4944 4945 4946 4947 4948 4949 4950 4951 4952 4953 4954 | n--; }else{ sqlite3VdbeAddOp2(v, copyOp, j+srcReg-1, target+i); } }else if( (flags & SQLITE_ECEL_FACTOR)!=0 && sqlite3ExprIsConstantNotJoin(pExpr) ){ sqlite3ExprCodeRunJustOnce(pParse, pExpr, target+i); }else{ int inReg = sqlite3ExprCodeTarget(pParse, pExpr, target+i); if( inReg!=target+i ){ VdbeOp *pOp; if( copyOp==OP_Copy && (pOp=sqlite3VdbeGetOp(v, -1))->opcode==OP_Copy && pOp->p1+pOp->p3+1==inReg && pOp->p2+pOp->p3+1==target+i && pOp->p5==0 /* The do-not-merge flag must be clear */ ){ pOp->p3++; }else{ sqlite3VdbeAddOp2(v, copyOp, inReg, target+i); } } } |
︙ | ︙ | |||
4288 4289 4290 4291 4292 4293 4294 | static void exprCodeBetween( Parse *pParse, /* Parsing and code generating context */ Expr *pExpr, /* The BETWEEN expression */ int dest, /* Jump destination or storage location */ void (*xJump)(Parse*,Expr*,int,int), /* Action to take */ int jumpIfNull /* Take the jump if the BETWEEN is NULL */ ){ | | < | > | | > | | | | | | | | | | | | | | | | | | | | | | > > | 4979 4980 4981 4982 4983 4984 4985 4986 4987 4988 4989 4990 4991 4992 4993 4994 4995 4996 4997 4998 4999 5000 5001 5002 5003 5004 5005 5006 5007 5008 5009 5010 5011 5012 5013 5014 5015 5016 5017 5018 5019 5020 5021 5022 5023 5024 5025 5026 5027 5028 5029 5030 | static void exprCodeBetween( Parse *pParse, /* Parsing and code generating context */ Expr *pExpr, /* The BETWEEN expression */ int dest, /* Jump destination or storage location */ void (*xJump)(Parse*,Expr*,int,int), /* Action to take */ int jumpIfNull /* Take the jump if the BETWEEN is NULL */ ){ Expr exprAnd; /* The AND operator in x>=y AND x<=z */ Expr compLeft; /* The x>=y term */ Expr compRight; /* The x<=z term */ int regFree1 = 0; /* Temporary use register */ Expr *pDel = 0; sqlite3 *db = pParse->db; memset(&compLeft, 0, sizeof(Expr)); memset(&compRight, 0, sizeof(Expr)); memset(&exprAnd, 0, sizeof(Expr)); assert( ExprUseXList(pExpr) ); pDel = sqlite3ExprDup(db, pExpr->pLeft, 0); if( db->mallocFailed==0 ){ exprAnd.op = TK_AND; exprAnd.pLeft = &compLeft; exprAnd.pRight = &compRight; compLeft.op = TK_GE; compLeft.pLeft = pDel; compLeft.pRight = pExpr->x.pList->a[0].pExpr; compRight.op = TK_LE; compRight.pLeft = pDel; compRight.pRight = pExpr->x.pList->a[1].pExpr; exprToRegister(pDel, exprCodeVector(pParse, pDel, ®Free1)); if( xJump ){ xJump(pParse, &exprAnd, dest, jumpIfNull); }else{ /* Mark the expression is being from the ON or USING clause of a join ** so that the sqlite3ExprCodeTarget() routine will not attempt to move ** it into the Parse.pConstExpr list. We should use a new bit for this, ** for clarity, but we are out of bits in the Expr.flags field so we ** have to reuse the EP_FromJoin bit. Bummer. */ pDel->flags |= EP_FromJoin; sqlite3ExprCodeTarget(pParse, &exprAnd, dest); } sqlite3ReleaseTempReg(pParse, regFree1); } sqlite3ExprDelete(db, pDel); /* Ensure adequate test coverage */ testcase( xJump==sqlite3ExprIfTrue && jumpIfNull==0 && regFree1==0 ); testcase( xJump==sqlite3ExprIfTrue && jumpIfNull==0 && regFree1!=0 ); testcase( xJump==sqlite3ExprIfTrue && jumpIfNull!=0 && regFree1==0 ); testcase( xJump==sqlite3ExprIfTrue && jumpIfNull!=0 && regFree1!=0 ); testcase( xJump==sqlite3ExprIfFalse && jumpIfNull==0 && regFree1==0 ); |
︙ | ︙ | |||
4360 4361 4362 4363 4364 4365 4366 4367 4368 | 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 ){ | > | > > > > > | | | > | | < | < | | | > | 5054 5055 5056 5057 5058 5059 5060 5061 5062 5063 5064 5065 5066 5067 5068 5069 5070 5071 5072 5073 5074 5075 5076 5077 5078 5079 5080 5081 5082 5083 5084 5085 5086 5087 | 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 */ assert( !ExprHasVVAProperty(pExpr, EP_Immutable) ); op = pExpr->op; switch( op ){ case TK_AND: case TK_OR: { Expr *pAlt = sqlite3ExprSimplifiedAndOr(pExpr); if( pAlt!=pExpr ){ sqlite3ExprIfTrue(pParse, pAlt, dest, jumpIfNull); }else if( op==TK_AND ){ int d2 = sqlite3VdbeMakeLabel(pParse); testcase( jumpIfNull==0 ); sqlite3ExprIfFalse(pParse, pExpr->pLeft, d2, jumpIfNull^SQLITE_JUMPIFNULL); sqlite3ExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull); sqlite3VdbeResolveLabel(v, d2); }else{ testcase( jumpIfNull==0 ); sqlite3ExprIfTrue(pParse, pExpr->pLeft, dest, jumpIfNull); sqlite3ExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull); } break; } case TK_NOT: { testcase( jumpIfNull==0 ); sqlite3ExprIfFalse(pParse, pExpr->pLeft, dest, jumpIfNull); break; } |
︙ | ︙ | |||
4404 4405 4406 4407 4408 4409 4410 | } case TK_IS: case TK_ISNOT: testcase( op==TK_IS ); testcase( op==TK_ISNOT ); op = (op==TK_IS) ? TK_EQ : TK_NE; jumpIfNull = SQLITE_NULLEQ; | | | | 5104 5105 5106 5107 5108 5109 5110 5111 5112 5113 5114 5115 5116 5117 5118 5119 5120 5121 5122 5123 5124 5125 5126 5127 5128 5129 5130 | } case TK_IS: case TK_ISNOT: testcase( op==TK_IS ); testcase( op==TK_ISNOT ); op = (op==TK_IS) ? TK_EQ : TK_NE; jumpIfNull = SQLITE_NULLEQ; /* no break */ deliberate_fall_through case TK_LT: case TK_LE: case TK_GT: case TK_GE: case TK_NE: case TK_EQ: { if( sqlite3ExprIsVector(pExpr->pLeft) ) goto default_expr; testcase( jumpIfNull==0 ); r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1); r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, ®Free2); codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op, r1, r2, dest, jumpIfNull, ExprHasProperty(pExpr,EP_Commuted)); assert(TK_LT==OP_Lt); testcase(op==OP_Lt); VdbeCoverageIf(v,op==OP_Lt); assert(TK_LE==OP_Le); testcase(op==OP_Le); VdbeCoverageIf(v,op==OP_Le); assert(TK_GT==OP_Gt); testcase(op==OP_Gt); VdbeCoverageIf(v,op==OP_Gt); assert(TK_GE==OP_Ge); testcase(op==OP_Ge); VdbeCoverageIf(v,op==OP_Ge); assert(TK_EQ==OP_Eq); testcase(op==OP_Eq); VdbeCoverageIf(v, op==OP_Eq && jumpIfNull==SQLITE_NULLEQ); VdbeCoverageIf(v, op==OP_Eq && jumpIfNull!=SQLITE_NULLEQ); |
︙ | ︙ | |||
4449 4450 4451 4452 4453 4454 4455 | case TK_BETWEEN: { testcase( jumpIfNull==0 ); exprCodeBetween(pParse, pExpr, dest, sqlite3ExprIfTrue, jumpIfNull); break; } #ifndef SQLITE_OMIT_SUBQUERY case TK_IN: { | | | | | 5149 5150 5151 5152 5153 5154 5155 5156 5157 5158 5159 5160 5161 5162 5163 5164 5165 5166 5167 5168 5169 5170 5171 5172 5173 5174 5175 | case TK_BETWEEN: { testcase( jumpIfNull==0 ); exprCodeBetween(pParse, pExpr, dest, sqlite3ExprIfTrue, jumpIfNull); break; } #ifndef SQLITE_OMIT_SUBQUERY case TK_IN: { int destIfFalse = sqlite3VdbeMakeLabel(pParse); int destIfNull = jumpIfNull ? dest : destIfFalse; sqlite3ExprCodeIN(pParse, pExpr, destIfFalse, destIfNull); sqlite3VdbeGoto(v, dest); sqlite3VdbeResolveLabel(v, destIfFalse); break; } #endif default: { default_expr: if( ExprAlwaysTrue(pExpr) ){ sqlite3VdbeGoto(v, dest); }else if( ExprAlwaysFalse(pExpr) ){ /* No-op */ }else{ r1 = sqlite3ExprCodeTemp(pParse, pExpr, ®Free1); sqlite3VdbeAddOp3(v, OP_If, r1, dest, jumpIfNull!=0); VdbeCoverage(v); testcase( regFree1==0 ); testcase( jumpIfNull==0 ); |
︙ | ︙ | |||
4496 4497 4498 4499 4500 4501 4502 4503 4504 4505 4506 4507 4508 4509 | 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 ** TK_NOTNULL OP_IsNull | > | 5196 5197 5198 5199 5200 5201 5202 5203 5204 5205 5206 5207 5208 5209 5210 | 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; assert( !ExprHasVVAProperty(pExpr,EP_Immutable) ); /* The value of pExpr->op and op are related as follows: ** ** pExpr->op op ** --------- ---------- ** TK_ISNULL OP_NotNull ** TK_NOTNULL OP_IsNull |
︙ | ︙ | |||
4529 4530 4531 4532 4533 4534 4535 | assert( pExpr->op!=TK_EQ || op==OP_Ne ); assert( pExpr->op!=TK_LT || op==OP_Ge ); assert( pExpr->op!=TK_LE || op==OP_Gt ); assert( pExpr->op!=TK_GT || op==OP_Le ); assert( pExpr->op!=TK_GE || op==OP_Lt ); switch( pExpr->op ){ | | > > > > > | | | < | < | | | > | | > | 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 | assert( pExpr->op!=TK_EQ || op==OP_Ne ); assert( pExpr->op!=TK_LT || op==OP_Ge ); assert( pExpr->op!=TK_LE || op==OP_Gt ); assert( pExpr->op!=TK_GT || op==OP_Le ); assert( pExpr->op!=TK_GE || op==OP_Lt ); switch( pExpr->op ){ case TK_AND: case TK_OR: { Expr *pAlt = sqlite3ExprSimplifiedAndOr(pExpr); if( pAlt!=pExpr ){ sqlite3ExprIfFalse(pParse, pAlt, dest, jumpIfNull); }else if( pExpr->op==TK_AND ){ testcase( jumpIfNull==0 ); sqlite3ExprIfFalse(pParse, pExpr->pLeft, dest, jumpIfNull); sqlite3ExprIfFalse(pParse, pExpr->pRight, dest, jumpIfNull); }else{ int d2 = sqlite3VdbeMakeLabel(pParse); testcase( jumpIfNull==0 ); sqlite3ExprIfTrue(pParse, pExpr->pLeft, d2, jumpIfNull^SQLITE_JUMPIFNULL); sqlite3ExprIfFalse(pParse, pExpr->pRight, dest, jumpIfNull); sqlite3VdbeResolveLabel(v, d2); } break; } case TK_NOT: { testcase( jumpIfNull==0 ); sqlite3ExprIfTrue(pParse, pExpr->pLeft, dest, jumpIfNull); break; } |
︙ | ︙ | |||
4574 4575 4576 4577 4578 4579 4580 | } case TK_IS: case TK_ISNOT: testcase( pExpr->op==TK_IS ); testcase( pExpr->op==TK_ISNOT ); op = (pExpr->op==TK_IS) ? TK_NE : TK_EQ; jumpIfNull = SQLITE_NULLEQ; | | | | 5280 5281 5282 5283 5284 5285 5286 5287 5288 5289 5290 5291 5292 5293 5294 5295 5296 5297 5298 5299 5300 5301 5302 5303 5304 5305 5306 | } case TK_IS: case TK_ISNOT: testcase( pExpr->op==TK_IS ); testcase( pExpr->op==TK_ISNOT ); op = (pExpr->op==TK_IS) ? TK_NE : TK_EQ; jumpIfNull = SQLITE_NULLEQ; /* no break */ deliberate_fall_through case TK_LT: case TK_LE: case TK_GT: case TK_GE: case TK_NE: case TK_EQ: { if( sqlite3ExprIsVector(pExpr->pLeft) ) goto default_expr; testcase( jumpIfNull==0 ); r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1); r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, ®Free2); codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op, r1, r2, dest, jumpIfNull,ExprHasProperty(pExpr,EP_Commuted)); assert(TK_LT==OP_Lt); testcase(op==OP_Lt); VdbeCoverageIf(v,op==OP_Lt); assert(TK_LE==OP_Le); testcase(op==OP_Le); VdbeCoverageIf(v,op==OP_Le); assert(TK_GT==OP_Gt); testcase(op==OP_Gt); VdbeCoverageIf(v,op==OP_Gt); assert(TK_GE==OP_Ge); testcase(op==OP_Ge); VdbeCoverageIf(v,op==OP_Ge); assert(TK_EQ==OP_Eq); testcase(op==OP_Eq); VdbeCoverageIf(v, op==OP_Eq && jumpIfNull!=SQLITE_NULLEQ); VdbeCoverageIf(v, op==OP_Eq && jumpIfNull==SQLITE_NULLEQ); |
︙ | ︙ | |||
4620 4621 4622 4623 4624 4625 4626 | break; } #ifndef SQLITE_OMIT_SUBQUERY case TK_IN: { if( jumpIfNull ){ sqlite3ExprCodeIN(pParse, pExpr, dest, dest); }else{ | | | | | 5326 5327 5328 5329 5330 5331 5332 5333 5334 5335 5336 5337 5338 5339 5340 5341 5342 5343 5344 5345 5346 5347 5348 5349 5350 5351 | break; } #ifndef SQLITE_OMIT_SUBQUERY case TK_IN: { if( jumpIfNull ){ sqlite3ExprCodeIN(pParse, pExpr, dest, dest); }else{ int destIfNull = sqlite3VdbeMakeLabel(pParse); sqlite3ExprCodeIN(pParse, pExpr, dest, destIfNull); sqlite3VdbeResolveLabel(v, destIfNull); } break; } #endif default: { default_expr: if( ExprAlwaysFalse(pExpr) ){ sqlite3VdbeGoto(v, dest); }else if( ExprAlwaysTrue(pExpr) ){ /* no-op */ }else{ r1 = sqlite3ExprCodeTemp(pParse, pExpr, ®Free1); sqlite3VdbeAddOp3(v, OP_IfNot, r1, dest, jumpIfNull!=0); VdbeCoverage(v); testcase( regFree1==0 ); testcase( jumpIfNull==0 ); |
︙ | ︙ | |||
4674 4675 4676 4677 4678 4679 4680 | ** to re-prepare each time a new value is bound to variable pVar. ** ** Additionally, if pExpr is a simple SQL value and the value is the ** same as that currently bound to variable pVar, non-zero is returned. ** Otherwise, if the values are not the same or if pExpr is not a simple ** SQL value, zero is returned. */ | | > > > > | 5380 5381 5382 5383 5384 5385 5386 5387 5388 5389 5390 5391 5392 5393 5394 5395 5396 5397 5398 | ** to re-prepare each time a new value is bound to variable pVar. ** ** Additionally, if pExpr is a simple SQL value and the value is the ** same as that currently bound to variable pVar, non-zero is returned. ** Otherwise, if the values are not the same or if pExpr is not a simple ** SQL value, zero is returned. */ static int exprCompareVariable( const Parse *pParse, const Expr *pVar, const Expr *pExpr ){ int res = 0; int iVar; sqlite3_value *pL, *pR = 0; sqlite3ValueFromExpr(pParse->db, pExpr, SQLITE_UTF8, SQLITE_AFF_BLOB, &pR); if( pR ){ iVar = pVar->iColumn; |
︙ | ︙ | |||
4726 4727 4728 4729 4730 4731 4732 | ** If pParse is not NULL then TK_VARIABLE terms in pA with bindings in ** pParse->pReprepare can be matched against literals in pB. The ** pParse->pVdbe->expmask bitmask is updated for each variable referenced. ** If pParse is NULL (the normal case) then any TK_VARIABLE term in ** Argument pParse should normally be NULL. If it is not NULL and pA or ** pB causes a return value of 2. */ | | > > > > > | > > | | | < < < < < < < | > > | > | > > > > > > > | > | > | | > | | > | | > | > | | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 5436 5437 5438 5439 5440 5441 5442 5443 5444 5445 5446 5447 5448 5449 5450 5451 5452 5453 5454 5455 5456 5457 5458 5459 5460 5461 5462 5463 5464 5465 5466 5467 5468 5469 5470 5471 5472 5473 5474 5475 5476 5477 5478 5479 5480 5481 5482 5483 5484 5485 5486 5487 5488 5489 5490 5491 5492 5493 5494 5495 5496 5497 5498 5499 5500 5501 5502 5503 5504 5505 5506 5507 5508 5509 5510 5511 5512 5513 5514 5515 5516 5517 5518 5519 5520 5521 5522 5523 5524 5525 5526 5527 5528 5529 5530 5531 5532 5533 5534 5535 5536 5537 5538 5539 5540 5541 5542 5543 5544 5545 5546 5547 5548 5549 5550 5551 5552 5553 5554 5555 5556 5557 5558 5559 5560 5561 5562 5563 5564 5565 5566 5567 5568 5569 5570 5571 5572 5573 5574 5575 5576 5577 5578 5579 5580 5581 5582 5583 5584 5585 5586 5587 5588 5589 5590 5591 5592 5593 5594 5595 5596 5597 5598 5599 5600 5601 5602 5603 5604 5605 5606 5607 5608 5609 5610 5611 5612 5613 5614 5615 5616 5617 5618 5619 5620 5621 5622 5623 5624 5625 5626 5627 5628 5629 5630 5631 5632 5633 5634 5635 5636 5637 5638 5639 5640 5641 5642 5643 5644 5645 5646 5647 5648 | ** If pParse is not NULL then TK_VARIABLE terms in pA with bindings in ** pParse->pReprepare can be matched against literals in pB. The ** pParse->pVdbe->expmask bitmask is updated for each variable referenced. ** If pParse is NULL (the normal case) then any TK_VARIABLE term in ** Argument pParse should normally be NULL. If it is not NULL and pA or ** pB causes a return value of 2. */ int sqlite3ExprCompare( const Parse *pParse, const Expr *pA, const Expr *pB, int iTab ){ u32 combinedFlags; if( pA==0 || pB==0 ){ return pB==pA ? 0 : 2; } if( pParse && pA->op==TK_VARIABLE && exprCompareVariable(pParse, pA, pB) ){ return 0; } combinedFlags = pA->flags | pB->flags; if( combinedFlags & EP_IntValue ){ if( (pA->flags&pB->flags&EP_IntValue)!=0 && pA->u.iValue==pB->u.iValue ){ return 0; } return 2; } if( pA->op!=pB->op || pA->op==TK_RAISE ){ if( pA->op==TK_COLLATE && sqlite3ExprCompare(pParse, pA->pLeft,pB,iTab)<2 ){ return 1; } if( pB->op==TK_COLLATE && sqlite3ExprCompare(pParse, pA,pB->pLeft,iTab)<2 ){ return 1; } return 2; } assert( !ExprHasProperty(pA, EP_IntValue) ); assert( !ExprHasProperty(pB, EP_IntValue) ); if( pA->u.zToken ){ if( pA->op==TK_FUNCTION || pA->op==TK_AGG_FUNCTION ){ if( sqlite3StrICmp(pA->u.zToken,pB->u.zToken)!=0 ) return 2; #ifndef SQLITE_OMIT_WINDOWFUNC assert( pA->op==pB->op ); if( ExprHasProperty(pA,EP_WinFunc)!=ExprHasProperty(pB,EP_WinFunc) ){ return 2; } if( ExprHasProperty(pA,EP_WinFunc) ){ if( sqlite3WindowCompare(pParse, pA->y.pWin, pB->y.pWin, 1)!=0 ){ return 2; } } #endif }else if( pA->op==TK_NULL ){ return 0; }else if( pA->op==TK_COLLATE ){ if( sqlite3_stricmp(pA->u.zToken,pB->u.zToken)!=0 ) return 2; }else if( pB->u.zToken!=0 && pA->op!=TK_COLUMN && pA->op!=TK_AGG_COLUMN && strcmp(pA->u.zToken,pB->u.zToken)!=0 ){ return 2; } } if( (pA->flags & (EP_Distinct|EP_Commuted)) != (pB->flags & (EP_Distinct|EP_Commuted)) ) return 2; if( ALWAYS((combinedFlags & EP_TokenOnly)==0) ){ if( combinedFlags & EP_xIsSelect ) return 2; if( (combinedFlags & EP_FixedCol)==0 && sqlite3ExprCompare(pParse, pA->pLeft, pB->pLeft, iTab) ) return 2; if( sqlite3ExprCompare(pParse, pA->pRight, pB->pRight, iTab) ) return 2; if( sqlite3ExprListCompare(pA->x.pList, pB->x.pList, iTab) ) return 2; if( pA->op!=TK_STRING && pA->op!=TK_TRUEFALSE && ALWAYS((combinedFlags & EP_Reduced)==0) ){ if( pA->iColumn!=pB->iColumn ) return 2; if( pA->op2!=pB->op2 && pA->op==TK_TRUTH ) return 2; if( pA->op!=TK_IN && pA->iTable!=pB->iTable && pA->iTable!=iTab ){ return 2; } } } return 0; } /* ** Compare two ExprList objects. Return 0 if they are identical, 1 ** if they are certainly different, or 2 if it is not possible to ** determine if they are identical or not. ** ** If any subelement of pB has Expr.iTable==(-1) then it is allowed ** to compare equal to an equivalent element in pA with Expr.iTable==iTab. ** ** This routine might return non-zero for equivalent ExprLists. The ** only consequence will be disabled optimizations. But this routine ** must never return 0 if the two ExprList objects are different, or ** a malfunction will result. ** ** Two NULL pointers are considered to be the same. But a NULL pointer ** always differs from a non-NULL pointer. */ int sqlite3ExprListCompare(const ExprList *pA, const ExprList *pB, int iTab){ int i; if( pA==0 && pB==0 ) return 0; if( pA==0 || pB==0 ) return 1; if( pA->nExpr!=pB->nExpr ) return 1; for(i=0; i<pA->nExpr; i++){ int res; Expr *pExprA = pA->a[i].pExpr; Expr *pExprB = pB->a[i].pExpr; if( pA->a[i].sortFlags!=pB->a[i].sortFlags ) return 1; if( (res = sqlite3ExprCompare(0, pExprA, pExprB, iTab)) ) return res; } return 0; } /* ** Like sqlite3ExprCompare() except COLLATE operators at the top-level ** are ignored. */ int sqlite3ExprCompareSkip(Expr *pA,Expr *pB, int iTab){ return sqlite3ExprCompare(0, sqlite3ExprSkipCollateAndLikely(pA), sqlite3ExprSkipCollateAndLikely(pB), iTab); } /* ** Return non-zero if Expr p can only be true if pNN is not NULL. ** ** Or if seenNot is true, return non-zero if Expr p can only be ** non-NULL if pNN is not NULL */ static int exprImpliesNotNull( const Parse *pParse,/* Parsing context */ const Expr *p, /* The expression to be checked */ const Expr *pNN, /* The expression that is NOT NULL */ int iTab, /* Table being evaluated */ int seenNot /* Return true only if p can be any non-NULL value */ ){ assert( p ); assert( pNN ); if( sqlite3ExprCompare(pParse, p, pNN, iTab)==0 ){ return pNN->op!=TK_NULL; } switch( p->op ){ case TK_IN: { if( seenNot && ExprHasProperty(p, EP_xIsSelect) ) return 0; assert( ExprUseXSelect(p) || (p->x.pList!=0 && p->x.pList->nExpr>0) ); return exprImpliesNotNull(pParse, p->pLeft, pNN, iTab, 1); } case TK_BETWEEN: { ExprList *pList; assert( ExprUseXList(p) ); pList = p->x.pList; assert( pList!=0 ); assert( pList->nExpr==2 ); if( seenNot ) return 0; if( exprImpliesNotNull(pParse, pList->a[0].pExpr, pNN, iTab, 1) || exprImpliesNotNull(pParse, pList->a[1].pExpr, pNN, iTab, 1) ){ return 1; } return exprImpliesNotNull(pParse, p->pLeft, pNN, iTab, 1); } case TK_EQ: case TK_NE: case TK_LT: case TK_LE: case TK_GT: case TK_GE: case TK_PLUS: case TK_MINUS: case TK_BITOR: case TK_LSHIFT: case TK_RSHIFT: case TK_CONCAT: seenNot = 1; /* no break */ deliberate_fall_through case TK_STAR: case TK_REM: case TK_BITAND: case TK_SLASH: { if( exprImpliesNotNull(pParse, p->pRight, pNN, iTab, seenNot) ) return 1; /* no break */ deliberate_fall_through } case TK_SPAN: case TK_COLLATE: case TK_UPLUS: case TK_UMINUS: { return exprImpliesNotNull(pParse, p->pLeft, pNN, iTab, seenNot); } case TK_TRUTH: { if( seenNot ) return 0; if( p->op2!=TK_IS ) return 0; return exprImpliesNotNull(pParse, p->pLeft, pNN, iTab, 1); } case TK_BITNOT: case TK_NOT: { return exprImpliesNotNull(pParse, p->pLeft, pNN, iTab, 1); } } return 0; } /* ** Return true if we can prove the pE2 will always be true if pE1 is ** true. Return false if we cannot complete the proof or if pE2 might ** be false. Examples: ** ** pE1: x==5 pE2: x==5 Result: true |
︙ | ︙ | |||
4857 4858 4859 4860 4861 4862 4863 | ** modified to record which bound variables are referenced. If pParse ** is NULL, then false will be returned if pE1 contains any bound variables. ** ** When in doubt, return false. Returning true might give a performance ** improvement. Returning false might cause a performance reduction, but ** it will always give the correct answer and is hence always safe. */ | | > > > > > | | | | | | | > > | | > > > > > > > > > > > > > > > > > > > | > > > > > > | > > | > > | > > | 5661 5662 5663 5664 5665 5666 5667 5668 5669 5670 5671 5672 5673 5674 5675 5676 5677 5678 5679 5680 5681 5682 5683 5684 5685 5686 5687 5688 5689 5690 5691 5692 5693 5694 5695 5696 5697 5698 5699 5700 5701 5702 5703 5704 5705 5706 5707 5708 5709 5710 5711 5712 5713 5714 5715 5716 5717 5718 5719 5720 5721 5722 5723 5724 5725 5726 5727 5728 5729 5730 5731 5732 5733 5734 5735 5736 5737 5738 5739 5740 5741 5742 5743 5744 5745 5746 5747 5748 5749 5750 5751 5752 5753 5754 5755 5756 5757 5758 5759 5760 5761 5762 5763 5764 5765 5766 5767 5768 5769 5770 5771 5772 5773 5774 5775 5776 5777 5778 5779 5780 5781 5782 5783 5784 5785 5786 5787 5788 | ** modified to record which bound variables are referenced. If pParse ** is NULL, then false will be returned if pE1 contains any bound variables. ** ** When in doubt, return false. Returning true might give a performance ** improvement. Returning false might cause a performance reduction, but ** it will always give the correct answer and is hence always safe. */ int sqlite3ExprImpliesExpr( const Parse *pParse, const Expr *pE1, const Expr *pE2, int iTab ){ if( sqlite3ExprCompare(pParse, pE1, pE2, iTab)==0 ){ return 1; } if( pE2->op==TK_OR && (sqlite3ExprImpliesExpr(pParse, pE1, pE2->pLeft, iTab) || sqlite3ExprImpliesExpr(pParse, pE1, pE2->pRight, iTab) ) ){ return 1; } if( pE2->op==TK_NOTNULL && exprImpliesNotNull(pParse, pE1, pE2->pLeft, iTab, 0) ){ return 1; } return 0; } /* ** This is the Expr node callback for sqlite3ExprImpliesNonNullRow(). ** If the expression node requires that the table at pWalker->iCur ** have one or more non-NULL column, then set pWalker->eCode to 1 and abort. ** ** This routine controls an optimization. False positives (setting ** pWalker->eCode to 1 when it should not be) are deadly, but false-negatives ** (never setting pWalker->eCode) is a harmless missed optimization. */ static int impliesNotNullRow(Walker *pWalker, Expr *pExpr){ testcase( pExpr->op==TK_AGG_COLUMN ); testcase( pExpr->op==TK_AGG_FUNCTION ); if( ExprHasProperty(pExpr, EP_FromJoin) ) return WRC_Prune; switch( pExpr->op ){ case TK_ISNOT: case TK_ISNULL: case TK_NOTNULL: case TK_IS: case TK_OR: case TK_VECTOR: case TK_CASE: case TK_IN: case TK_FUNCTION: case TK_TRUTH: testcase( pExpr->op==TK_ISNOT ); testcase( pExpr->op==TK_ISNULL ); testcase( pExpr->op==TK_NOTNULL ); testcase( pExpr->op==TK_IS ); testcase( pExpr->op==TK_OR ); testcase( pExpr->op==TK_VECTOR ); testcase( pExpr->op==TK_CASE ); testcase( pExpr->op==TK_IN ); testcase( pExpr->op==TK_FUNCTION ); testcase( pExpr->op==TK_TRUTH ); return WRC_Prune; case TK_COLUMN: if( pWalker->u.iCur==pExpr->iTable ){ pWalker->eCode = 1; return WRC_Abort; } return WRC_Prune; case TK_AND: if( pWalker->eCode==0 ){ sqlite3WalkExpr(pWalker, pExpr->pLeft); if( pWalker->eCode ){ pWalker->eCode = 0; sqlite3WalkExpr(pWalker, pExpr->pRight); } } return WRC_Prune; case TK_BETWEEN: if( sqlite3WalkExpr(pWalker, pExpr->pLeft)==WRC_Abort ){ assert( pWalker->eCode ); return WRC_Abort; } return WRC_Prune; /* Virtual tables are allowed to use constraints like x=NULL. So ** a term of the form x=y does not prove that y is not null if x ** is the column of a virtual table */ case TK_EQ: case TK_NE: case TK_LT: case TK_LE: case TK_GT: case TK_GE: { Expr *pLeft = pExpr->pLeft; Expr *pRight = pExpr->pRight; testcase( pExpr->op==TK_EQ ); testcase( pExpr->op==TK_NE ); testcase( pExpr->op==TK_LT ); testcase( pExpr->op==TK_LE ); testcase( pExpr->op==TK_GT ); testcase( pExpr->op==TK_GE ); /* The y.pTab=0 assignment in wherecode.c always happens after the ** impliesNotNullRow() test */ assert( pLeft->op!=TK_COLUMN || ExprUseYTab(pLeft) ); assert( pRight->op!=TK_COLUMN || ExprUseYTab(pRight) ); if( (pLeft->op==TK_COLUMN && pLeft->y.pTab!=0 && IsVirtual(pLeft->y.pTab)) || (pRight->op==TK_COLUMN && pRight->y.pTab!=0 && IsVirtual(pRight->y.pTab)) ){ return WRC_Prune; } /* no break */ deliberate_fall_through } default: return WRC_Continue; } } /* ** Return true (non-zero) if expression p can only be true if at least |
︙ | ︙ | |||
4962 4963 4964 4965 4966 4967 4968 4969 4970 4971 4972 4973 4974 4975 | ** an ordinary JOIN. The p argument is the WHERE clause. If the WHERE ** clause requires that some column of the right table of the LEFT JOIN ** be non-NULL, then the LEFT JOIN can be safely converted into an ** ordinary join. */ int sqlite3ExprImpliesNonNullRow(Expr *p, int iTab){ Walker w; w.xExprCallback = impliesNotNullRow; w.xSelectCallback = 0; w.xSelectCallback2 = 0; w.eCode = 0; w.u.iCur = iTab; sqlite3WalkExpr(&w, p); return w.eCode; | > > > > > > > > > > | 5804 5805 5806 5807 5808 5809 5810 5811 5812 5813 5814 5815 5816 5817 5818 5819 5820 5821 5822 5823 5824 5825 5826 5827 | ** an ordinary JOIN. The p argument is the WHERE clause. If the WHERE ** clause requires that some column of the right table of the LEFT JOIN ** be non-NULL, then the LEFT JOIN can be safely converted into an ** ordinary join. */ int sqlite3ExprImpliesNonNullRow(Expr *p, int iTab){ Walker w; p = sqlite3ExprSkipCollateAndLikely(p); if( p==0 ) return 0; if( p->op==TK_NOTNULL ){ p = p->pLeft; }else{ while( p->op==TK_AND ){ if( sqlite3ExprImpliesNonNullRow(p->pLeft, iTab) ) return 1; p = p->pRight; } } w.xExprCallback = impliesNotNullRow; w.xSelectCallback = 0; w.xSelectCallback2 = 0; w.eCode = 0; w.u.iCur = iTab; sqlite3WalkExpr(&w, p); return w.eCode; |
︙ | ︙ | |||
4991 4992 4993 4994 4995 4996 4997 | ** Check to see if there are references to columns in table ** pWalker->u.pIdxCover->iCur can be satisfied using the index ** pWalker->u.pIdxCover->pIdx. */ static int exprIdxCover(Walker *pWalker, Expr *pExpr){ if( pExpr->op==TK_COLUMN && pExpr->iTable==pWalker->u.pIdxCover->iCur | | | 5843 5844 5845 5846 5847 5848 5849 5850 5851 5852 5853 5854 5855 5856 5857 | ** Check to see if there are references to columns in table ** pWalker->u.pIdxCover->iCur can be satisfied using the index ** pWalker->u.pIdxCover->pIdx. */ static int exprIdxCover(Walker *pWalker, Expr *pExpr){ if( pExpr->op==TK_COLUMN && pExpr->iTable==pWalker->u.pIdxCover->iCur && sqlite3TableColumnToIndex(pWalker->u.pIdxCover->pIdx, pExpr->iColumn)<0 ){ pWalker->eCode = 1; return WRC_Abort; } return WRC_Continue; } |
︙ | ︙ | |||
5026 5027 5028 5029 5030 5031 5032 | w.xExprCallback = exprIdxCover; w.u.pIdxCover = &xcov; sqlite3WalkExpr(&w, pExpr); return !w.eCode; } | < | < | < | > | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > | < < < < < | > > | | | > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > | > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | < < | | < | | | < < < < < < | 5878 5879 5880 5881 5882 5883 5884 5885 5886 5887 5888 5889 5890 5891 5892 5893 5894 5895 5896 5897 5898 5899 5900 5901 5902 5903 5904 5905 5906 5907 5908 5909 5910 5911 5912 5913 5914 5915 5916 5917 5918 5919 5920 5921 5922 5923 5924 5925 5926 5927 5928 5929 5930 5931 5932 5933 5934 5935 5936 5937 5938 5939 5940 5941 5942 5943 5944 5945 5946 5947 5948 5949 5950 5951 5952 5953 5954 5955 5956 5957 5958 5959 5960 5961 5962 5963 5964 5965 5966 5967 5968 5969 5970 5971 5972 5973 5974 5975 5976 5977 5978 5979 5980 5981 5982 5983 5984 5985 5986 5987 5988 5989 5990 5991 5992 5993 5994 5995 5996 5997 5998 5999 6000 6001 6002 6003 6004 6005 6006 6007 6008 6009 6010 6011 6012 6013 6014 6015 6016 6017 6018 6019 6020 6021 6022 6023 6024 6025 6026 6027 6028 6029 6030 6031 6032 6033 6034 6035 6036 6037 6038 6039 6040 6041 6042 6043 6044 6045 6046 6047 6048 6049 6050 6051 6052 6053 6054 6055 6056 6057 6058 6059 6060 6061 6062 6063 6064 6065 6066 | w.xExprCallback = exprIdxCover; w.u.pIdxCover = &xcov; sqlite3WalkExpr(&w, pExpr); return !w.eCode; } /* Structure used to pass information throught the Walker in order to ** implement sqlite3ReferencesSrcList(). */ struct RefSrcList { sqlite3 *db; /* Database connection used for sqlite3DbRealloc() */ SrcList *pRef; /* Looking for references to these tables */ i64 nExclude; /* Number of tables to exclude from the search */ int *aiExclude; /* Cursor IDs for tables to exclude from the search */ }; /* ** Walker SELECT callbacks for sqlite3ReferencesSrcList(). ** ** When entering a new subquery on the pExpr argument, add all FROM clause ** entries for that subquery to the exclude list. ** ** When leaving the subquery, remove those entries from the exclude list. */ static int selectRefEnter(Walker *pWalker, Select *pSelect){ struct RefSrcList *p = pWalker->u.pRefSrcList; SrcList *pSrc = pSelect->pSrc; i64 i, j; int *piNew; if( pSrc->nSrc==0 ) return WRC_Continue; j = p->nExclude; p->nExclude += pSrc->nSrc; piNew = sqlite3DbRealloc(p->db, p->aiExclude, p->nExclude*sizeof(int)); if( piNew==0 ){ p->nExclude = 0; return WRC_Abort; }else{ p->aiExclude = piNew; } for(i=0; i<pSrc->nSrc; i++, j++){ p->aiExclude[j] = pSrc->a[i].iCursor; } return WRC_Continue; } static void selectRefLeave(Walker *pWalker, Select *pSelect){ struct RefSrcList *p = pWalker->u.pRefSrcList; SrcList *pSrc = pSelect->pSrc; if( p->nExclude ){ assert( p->nExclude>=pSrc->nSrc ); p->nExclude -= pSrc->nSrc; } } /* This is the Walker EXPR callback for sqlite3ReferencesSrcList(). ** ** Set the 0x01 bit of pWalker->eCode if there is a reference to any ** of the tables shown in RefSrcList.pRef. ** ** Set the 0x02 bit of pWalker->eCode if there is a reference to a ** table is in neither RefSrcList.pRef nor RefSrcList.aiExclude. */ static int exprRefToSrcList(Walker *pWalker, Expr *pExpr){ if( pExpr->op==TK_COLUMN || pExpr->op==TK_AGG_COLUMN ){ int i; struct RefSrcList *p = pWalker->u.pRefSrcList; SrcList *pSrc = p->pRef; int nSrc = pSrc ? pSrc->nSrc : 0; for(i=0; i<nSrc; i++){ if( pExpr->iTable==pSrc->a[i].iCursor ){ pWalker->eCode |= 1; return WRC_Continue; } } for(i=0; i<p->nExclude && p->aiExclude[i]!=pExpr->iTable; i++){} if( i>=p->nExclude ){ pWalker->eCode |= 2; } } return WRC_Continue; } /* ** Check to see if pExpr references any tables in pSrcList. ** Possible return values: ** ** 1 pExpr does references a table in pSrcList. ** ** 0 pExpr references some table that is not defined in either ** pSrcList or in subqueries of pExpr itself. ** ** -1 pExpr only references no tables at all, or it only ** references tables defined in subqueries of pExpr itself. ** ** As currently used, pExpr is always an aggregate function call. That ** fact is exploited for efficiency. */ int sqlite3ReferencesSrcList(Parse *pParse, Expr *pExpr, SrcList *pSrcList){ Walker w; struct RefSrcList x; memset(&w, 0, sizeof(w)); memset(&x, 0, sizeof(x)); w.xExprCallback = exprRefToSrcList; w.xSelectCallback = selectRefEnter; w.xSelectCallback2 = selectRefLeave; w.u.pRefSrcList = &x; x.db = pParse->db; x.pRef = pSrcList; assert( pExpr->op==TK_AGG_FUNCTION ); assert( ExprUseXList(pExpr) ); sqlite3WalkExprList(&w, pExpr->x.pList); #ifndef SQLITE_OMIT_WINDOWFUNC if( ExprHasProperty(pExpr, EP_WinFunc) ){ sqlite3WalkExpr(&w, pExpr->y.pWin->pFilter); } #endif sqlite3DbFree(pParse->db, x.aiExclude); if( w.eCode & 0x01 ){ return 1; }else if( w.eCode ){ return 0; }else{ return -1; } } /* ** This is a Walker expression node callback. ** ** For Expr nodes that contain pAggInfo pointers, make sure the AggInfo ** object that is referenced does not refer directly to the Expr. If ** it does, make a copy. This is done because the pExpr argument is ** subject to change. ** ** The copy is stored on pParse->pConstExpr with a register number of 0. ** This will cause the expression to be deleted automatically when the ** Parse object is destroyed, but the zero register number means that it ** will not generate any code in the preamble. */ static int agginfoPersistExprCb(Walker *pWalker, Expr *pExpr){ if( ALWAYS(!ExprHasProperty(pExpr, EP_TokenOnly|EP_Reduced)) && pExpr->pAggInfo!=0 ){ AggInfo *pAggInfo = pExpr->pAggInfo; int iAgg = pExpr->iAgg; Parse *pParse = pWalker->pParse; sqlite3 *db = pParse->db; assert( pExpr->op==TK_AGG_COLUMN || pExpr->op==TK_AGG_FUNCTION ); if( pExpr->op==TK_AGG_COLUMN ){ assert( iAgg>=0 && iAgg<pAggInfo->nColumn ); if( pAggInfo->aCol[iAgg].pCExpr==pExpr ){ pExpr = sqlite3ExprDup(db, pExpr, 0); if( pExpr ){ pAggInfo->aCol[iAgg].pCExpr = pExpr; sqlite3ExprDeferredDelete(pParse, pExpr); } } }else{ assert( iAgg>=0 && iAgg<pAggInfo->nFunc ); if( pAggInfo->aFunc[iAgg].pFExpr==pExpr ){ pExpr = sqlite3ExprDup(db, pExpr, 0); if( pExpr ){ pAggInfo->aFunc[iAgg].pFExpr = pExpr; sqlite3ExprDeferredDelete(pParse, pExpr); } } } } return WRC_Continue; } /* ** Initialize a Walker object so that will persist AggInfo entries referenced ** by the tree that is walked. */ void sqlite3AggInfoPersistWalkerInit(Walker *pWalker, Parse *pParse){ memset(pWalker, 0, sizeof(*pWalker)); pWalker->pParse = pParse; pWalker->xExprCallback = agginfoPersistExprCb; pWalker->xSelectCallback = sqlite3SelectWalkNoop; } /* ** Add a new element to the pAggInfo->aCol[] array. Return the index of ** the new element. Return a negative number if malloc fails. */ static int addAggInfoColumn(sqlite3 *db, AggInfo *pInfo){ |
︙ | ︙ | |||
5114 5115 5116 5117 5118 5119 5120 | db, pInfo->aFunc, sizeof(pInfo->aFunc[0]), &pInfo->nFunc, &i ); return i; | | | 6085 6086 6087 6088 6089 6090 6091 6092 6093 6094 6095 6096 6097 6098 6099 | db, pInfo->aFunc, sizeof(pInfo->aFunc[0]), &pInfo->nFunc, &i ); return i; } /* ** This is the xExprCallback for a tree walker. It is used to ** implement sqlite3ExprAnalyzeAggregates(). See sqlite3ExprAnalyzeAggregates ** for additional information. */ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){ |
︙ | ︙ | |||
5137 5138 5139 5140 5141 5142 5143 | case TK_AGG_COLUMN: case TK_COLUMN: { testcase( pExpr->op==TK_AGG_COLUMN ); testcase( pExpr->op==TK_COLUMN ); /* Check to see if the column is in one of the tables in the FROM ** clause of the aggregate query */ if( ALWAYS(pSrcList!=0) ){ | | | 6108 6109 6110 6111 6112 6113 6114 6115 6116 6117 6118 6119 6120 6121 6122 | case TK_AGG_COLUMN: case TK_COLUMN: { testcase( pExpr->op==TK_AGG_COLUMN ); testcase( pExpr->op==TK_COLUMN ); /* Check to see if the column is in one of the tables in the FROM ** clause of the aggregate query */ if( ALWAYS(pSrcList!=0) ){ SrcItem *pItem = pSrcList->a; for(i=0; i<pSrcList->nSrc; i++, pItem++){ struct AggInfo_col *pCol; assert( !ExprHasProperty(pExpr, EP_TokenOnly|EP_Reduced) ); if( pExpr->iTable==pItem->iCursor ){ /* If we reach this point, it means that pExpr refers to a table ** that is in the FROM clause of the aggregate query. ** |
︙ | ︙ | |||
5160 5161 5162 5163 5164 5165 5166 5167 5168 5169 5170 5171 | break; } } if( (k>=pAggInfo->nColumn) && (k = addAggInfoColumn(pParse->db, pAggInfo))>=0 ){ pCol = &pAggInfo->aCol[k]; pCol->pTab = pExpr->y.pTab; pCol->iTable = pExpr->iTable; pCol->iColumn = pExpr->iColumn; pCol->iMem = ++pParse->nMem; pCol->iSorterColumn = -1; | > | | 6131 6132 6133 6134 6135 6136 6137 6138 6139 6140 6141 6142 6143 6144 6145 6146 6147 6148 6149 6150 6151 | break; } } if( (k>=pAggInfo->nColumn) && (k = addAggInfoColumn(pParse->db, pAggInfo))>=0 ){ pCol = &pAggInfo->aCol[k]; assert( ExprUseYTab(pExpr) ); pCol->pTab = pExpr->y.pTab; pCol->iTable = pExpr->iTable; pCol->iColumn = pExpr->iColumn; pCol->iMem = ++pParse->nMem; pCol->iSorterColumn = -1; pCol->pCExpr = pExpr; if( pAggInfo->pGroupBy ){ int j, n; ExprList *pGB = pAggInfo->pGroupBy; struct ExprList_item *pTerm = pGB->a; n = pGB->nExpr; for(j=0; j<n; j++, pTerm++){ Expr *pE = pTerm->pExpr; |
︙ | ︙ | |||
5208 5209 5210 5211 5212 5213 5214 | && pWalker->walkerDepth==pExpr->op2 ){ /* Check to see if pExpr is a duplicate of another aggregate ** function that is already in the pAggInfo structure */ struct AggInfo_func *pItem = pAggInfo->aFunc; for(i=0; i<pAggInfo->nFunc; i++, pItem++){ | > | | | | 6180 6181 6182 6183 6184 6185 6186 6187 6188 6189 6190 6191 6192 6193 6194 6195 6196 6197 6198 6199 6200 6201 6202 6203 6204 6205 6206 6207 6208 6209 | && pWalker->walkerDepth==pExpr->op2 ){ /* Check to see if pExpr is a duplicate of another aggregate ** function that is already in the pAggInfo structure */ struct AggInfo_func *pItem = pAggInfo->aFunc; for(i=0; i<pAggInfo->nFunc; i++, pItem++){ if( pItem->pFExpr==pExpr ) break; if( sqlite3ExprCompare(0, pItem->pFExpr, pExpr, -1)==0 ){ break; } } if( i>=pAggInfo->nFunc ){ /* pExpr is original. Make a new entry in pAggInfo->aFunc[] */ u8 enc = ENC(pParse->db); i = addAggInfoFunc(pParse->db, pAggInfo); if( i>=0 ){ assert( !ExprHasProperty(pExpr, EP_xIsSelect) ); pItem = &pAggInfo->aFunc[i]; pItem->pFExpr = pExpr; pItem->iMem = ++pParse->nMem; assert( ExprUseUToken(pExpr) ); pItem->pFunc = sqlite3FindFunction(pParse->db, pExpr->u.zToken, pExpr->x.pList ? pExpr->x.pList->nExpr : 0, enc, 0); if( pExpr->flags & EP_Distinct ){ pItem->iDistinct = pParse->nTab++; }else{ pItem->iDistinct = -1; |
︙ | ︙ | |||
5247 5248 5249 5250 5251 5252 5253 | }else{ return WRC_Continue; } } } return WRC_Continue; } | < < < < < < < < < | | > | 6220 6221 6222 6223 6224 6225 6226 6227 6228 6229 6230 6231 6232 6233 6234 6235 6236 6237 6238 6239 6240 6241 6242 6243 6244 6245 6246 6247 6248 6249 6250 6251 | }else{ return WRC_Continue; } } } return WRC_Continue; } /* ** Analyze the pExpr expression looking for aggregate functions and ** for variables that need to be added to AggInfo object that pNC->pAggInfo ** points to. Additional entries are made on the AggInfo object as ** necessary. ** ** This routine should only be called after the expression has been ** analyzed by sqlite3ResolveExprNames(). */ void sqlite3ExprAnalyzeAggregates(NameContext *pNC, Expr *pExpr){ Walker w; w.xExprCallback = analyzeAggregate; w.xSelectCallback = sqlite3WalkerDepthIncrease; w.xSelectCallback2 = sqlite3WalkerDepthDecrease; w.walkerDepth = 0; w.u.pNC = pNC; w.pParse = 0; assert( pNC->pSrcList!=0 ); sqlite3WalkExpr(&w, pExpr); } /* ** Call sqlite3ExprAnalyzeAggregates() for every expression in an ** expression list. Return the number of errors. |
︙ | ︙ | |||
5308 5309 5310 5311 5312 5313 5314 | } /* ** Deallocate a register, making available for reuse for some other ** purpose. */ void sqlite3ReleaseTempReg(Parse *pParse, int iReg){ | > > | | > | 6273 6274 6275 6276 6277 6278 6279 6280 6281 6282 6283 6284 6285 6286 6287 6288 6289 6290 6291 | } /* ** Deallocate a register, making available for reuse for some other ** purpose. */ void sqlite3ReleaseTempReg(Parse *pParse, int iReg){ if( iReg ){ sqlite3VdbeReleaseRegisters(pParse, iReg, 1, 0, 0); if( pParse->nTempReg<ArraySize(pParse->aTempReg) ){ pParse->aTempReg[pParse->nTempReg++] = iReg; } } } /* ** Allocate or deallocate a block of nReg consecutive registers. */ int sqlite3GetTempRange(Parse *pParse, int nReg){ |
︙ | ︙ | |||
5335 5336 5337 5338 5339 5340 5341 5342 5343 5344 5345 5346 5347 5348 5349 5350 5351 5352 5353 5354 5355 5356 | return i; } void sqlite3ReleaseTempRange(Parse *pParse, int iReg, int nReg){ if( nReg==1 ){ sqlite3ReleaseTempReg(pParse, iReg); return; } if( nReg>pParse->nRangeReg ){ pParse->nRangeReg = nReg; pParse->iRangeReg = iReg; } } /* ** Mark all temporary registers as being unavailable for reuse. */ void sqlite3ClearTempRegCache(Parse *pParse){ pParse->nTempReg = 0; pParse->nRangeReg = 0; } /* | > > > > > > | 6303 6304 6305 6306 6307 6308 6309 6310 6311 6312 6313 6314 6315 6316 6317 6318 6319 6320 6321 6322 6323 6324 6325 6326 6327 6328 6329 6330 | return i; } void sqlite3ReleaseTempRange(Parse *pParse, int iReg, int nReg){ if( nReg==1 ){ sqlite3ReleaseTempReg(pParse, iReg); return; } sqlite3VdbeReleaseRegisters(pParse, iReg, nReg, 0, 0); if( nReg>pParse->nRangeReg ){ pParse->nRangeReg = nReg; pParse->iRangeReg = iReg; } } /* ** Mark all temporary registers as being unavailable for reuse. ** ** Always invoke this procedure after coding a subroutine or co-routine ** that might be invoked from other parts of the code, to ensure that ** the sub/co-routine does not use registers in common with the code that ** invokes the sub/co-routine. */ void sqlite3ClearTempRegCache(Parse *pParse){ pParse->nTempReg = 0; pParse->nRangeReg = 0; } /* |
︙ | ︙ |
Changes to src/fkey.c.
︙ | ︙ | |||
211 212 213 214 215 216 217 | ** 1) There is an INTEGER PRIMARY KEY column and the FK is implicitly ** mapped to the primary key of table pParent, or ** 2) The FK is explicitly mapped to a column declared as INTEGER ** PRIMARY KEY. */ if( pParent->iPKey>=0 ){ if( !zKey ) return 0; | | > > | 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 | ** 1) There is an INTEGER PRIMARY KEY column and the FK is implicitly ** mapped to the primary key of table pParent, or ** 2) The FK is explicitly mapped to a column declared as INTEGER ** PRIMARY KEY. */ if( pParent->iPKey>=0 ){ if( !zKey ) return 0; if( !sqlite3StrICmp(pParent->aCol[pParent->iPKey].zCnName, zKey) ){ return 0; } } }else if( paiCol ){ assert( nCol>1 ); aiCol = (int *)sqlite3DbMallocRawNN(pParse->db, nCol*sizeof(int)); if( !aiCol ) return 1; *paiCol = aiCol; } |
︙ | ︙ | |||
253 254 255 256 257 258 259 | char *zIdxCol; /* Name of indexed column */ if( iCol<0 ) break; /* No foreign keys against expression indexes */ /* If the index uses a collation sequence that is different from ** the default collation sequence for the column, this index is ** unusable. Bail out early in this case. */ | | | | 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 | char *zIdxCol; /* Name of indexed column */ if( iCol<0 ) break; /* No foreign keys against expression indexes */ /* If the index uses a collation sequence that is different from ** the default collation sequence for the column, this index is ** unusable. Bail out early in this case. */ zDfltColl = sqlite3ColumnColl(&pParent->aCol[iCol]); if( !zDfltColl ) zDfltColl = sqlite3StrBINARY; if( sqlite3StrICmp(pIdx->azColl[i], zDfltColl) ) break; zIdxCol = pParent->aCol[iCol].zCnName; for(j=0; j<nCol; j++){ if( sqlite3StrICmp(pFKey->aCol[j].zCol, zIdxCol)==0 ){ if( aiCol ) aiCol[i] = pFKey->aCol[j].iFrom; break; } } if( j==nCol ) break; |
︙ | ︙ | |||
325 326 327 328 329 330 331 | int regData, /* Address of array containing child table row */ int nIncr, /* Increment constraint counter by this */ int isIgnore /* If true, pretend pTab contains all NULL values */ ){ int i; /* Iterator variable */ Vdbe *v = sqlite3GetVdbe(pParse); /* Vdbe to add code to */ int iCur = pParse->nTab - 1; /* Cursor number to use */ | | | | > | 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 | int regData, /* Address of array containing child table row */ int nIncr, /* Increment constraint counter by this */ int isIgnore /* If true, pretend pTab contains all NULL values */ ){ int i; /* Iterator variable */ Vdbe *v = sqlite3GetVdbe(pParse); /* Vdbe to add code to */ int iCur = pParse->nTab - 1; /* Cursor number to use */ int iOk = sqlite3VdbeMakeLabel(pParse); /* jump here if parent key found */ sqlite3VdbeVerifyAbortable(v, (!pFKey->isDeferred && !(pParse->db->flags & SQLITE_DeferFKs) && !pParse->pToplevel && !pParse->isMultiWrite) ? OE_Abort : OE_Ignore); /* If nIncr is less than zero, then check at runtime if there are any ** outstanding constraints to resolve. If there are not, there is no need ** to check if deleting this row resolves any outstanding violations. ** ** Check if any of the key columns in the child table row are NULL. If ** any are, then the constraint is considered satisfied. No need to ** search for a matching row in the parent table. */ if( nIncr<0 ){ sqlite3VdbeAddOp2(v, OP_FkIfZero, pFKey->isDeferred, iOk); VdbeCoverage(v); } for(i=0; i<pFKey->nCol; i++){ int iReg = sqlite3TableColumnToStorage(pFKey->pFrom,aiCol[i]) + regData + 1; sqlite3VdbeAddOp2(v, OP_IsNull, iReg, iOk); VdbeCoverage(v); } if( isIgnore==0 ){ if( pIdx==0 ){ /* If pIdx is NULL, then the parent key is the INTEGER PRIMARY KEY ** column of the parent table (table pTab). */ int iMustBeInt; /* Address of MustBeInt instruction */ int regTemp = sqlite3GetTempReg(pParse); /* Invoke MustBeInt to coerce the child key value to an integer (i.e. ** apply the affinity of the parent key). If this fails, then there ** is no matching parent key. Before using MustBeInt, make a copy of ** the value. Otherwise, the value inserted into the child key column ** will have INTEGER affinity applied to it, which may not be correct. */ sqlite3VdbeAddOp2(v, OP_SCopy, sqlite3TableColumnToStorage(pFKey->pFrom,aiCol[0])+1+regData, regTemp); iMustBeInt = sqlite3VdbeAddOp2(v, OP_MustBeInt, regTemp, 0); VdbeCoverage(v); /* If the parent table is the same as the child table, and we are about ** to increment the constraint-counter (i.e. this is an INSERT operation), ** then check if the row being inserted matches itself. If so, do not ** increment the constraint-counter. */ |
︙ | ︙ | |||
388 389 390 391 392 393 394 | int nCol = pFKey->nCol; int regTemp = sqlite3GetTempRange(pParse, nCol); int regRec = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp3(v, OP_OpenRead, iCur, pIdx->tnum, iDb); sqlite3VdbeSetP4KeyInfo(pParse, pIdx); for(i=0; i<nCol; i++){ | | > > > | | > > | 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 | int nCol = pFKey->nCol; int regTemp = sqlite3GetTempRange(pParse, nCol); int regRec = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp3(v, OP_OpenRead, iCur, pIdx->tnum, iDb); sqlite3VdbeSetP4KeyInfo(pParse, pIdx); for(i=0; i<nCol; i++){ sqlite3VdbeAddOp2(v, OP_Copy, sqlite3TableColumnToStorage(pFKey->pFrom, aiCol[i])+1+regData, regTemp+i); } /* If the parent table is the same as the child table, and we are about ** to increment the constraint-counter (i.e. this is an INSERT operation), ** then check if the row being inserted matches itself. If so, do not ** increment the constraint-counter. ** ** If any of the parent-key values are NULL, then the row cannot match ** itself. So set JUMPIFNULL to make sure we do the OP_Found if any ** of the parent-key values are NULL (at this point it is known that ** none of the child key values are). */ if( pTab==pFKey->pFrom && nIncr==1 ){ int iJump = sqlite3VdbeCurrentAddr(v) + nCol + 1; for(i=0; i<nCol; i++){ int iChild = sqlite3TableColumnToStorage(pFKey->pFrom,aiCol[i]) +1+regData; int iParent = 1+regData; iParent += sqlite3TableColumnToStorage(pIdx->pTable, pIdx->aiColumn[i]); assert( pIdx->aiColumn[i]>=0 ); assert( aiCol[i]!=pTab->iPKey ); if( pIdx->aiColumn[i]==pTab->iPKey ){ /* The parent key is a composite key that includes the IPK column */ iParent = regData; } sqlite3VdbeAddOp3(v, OP_Ne, iChild, iJump, iParent); VdbeCoverage(v); |
︙ | ︙ | |||
473 474 475 476 477 478 479 | const char *zColl; sqlite3 *db = pParse->db; pExpr = sqlite3Expr(db, TK_REGISTER, 0); if( pExpr ){ if( iCol>=0 && iCol!=pTab->iPKey ){ pCol = &pTab->aCol[iCol]; | | | | | > | 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 | const char *zColl; sqlite3 *db = pParse->db; pExpr = sqlite3Expr(db, TK_REGISTER, 0); if( pExpr ){ if( iCol>=0 && iCol!=pTab->iPKey ){ pCol = &pTab->aCol[iCol]; pExpr->iTable = regBase + sqlite3TableColumnToStorage(pTab,iCol) + 1; pExpr->affExpr = pCol->affinity; zColl = sqlite3ColumnColl(pCol); if( zColl==0 ) zColl = db->pDfltColl->zName; pExpr = sqlite3ExprAddCollateString(pParse, pExpr, zColl); }else{ pExpr->iTable = regBase; pExpr->affExpr = SQLITE_AFF_INTEGER; } } return pExpr; } /* ** Return an Expr object that refers to column iCol of table pTab which ** has cursor iCur. */ static Expr *exprTableColumn( sqlite3 *db, /* The database connection */ Table *pTab, /* The table whose column is desired */ int iCursor, /* The open cursor on the table */ i16 iCol /* The column that is wanted */ ){ Expr *pExpr = sqlite3Expr(db, TK_COLUMN, 0); if( pExpr ){ assert( ExprUseYTab(pExpr) ); pExpr->y.pTab = pTab; pExpr->iTable = iCursor; pExpr->iColumn = iCol; } return pExpr; } |
︙ | ︙ | |||
584 585 586 587 588 589 590 | i16 iCol; /* Index of column in child table */ const char *zCol; /* Name of column in child table */ iCol = pIdx ? pIdx->aiColumn[i] : -1; pLeft = exprTableRegister(pParse, pTab, regData, iCol); iCol = aiCol ? aiCol[i] : pFKey->aCol[0].iFrom; assert( iCol>=0 ); | | | | | > > > < | | | | | | 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 | i16 iCol; /* Index of column in child table */ const char *zCol; /* Name of column in child table */ iCol = pIdx ? pIdx->aiColumn[i] : -1; pLeft = exprTableRegister(pParse, pTab, regData, iCol); iCol = aiCol ? aiCol[i] : pFKey->aCol[0].iFrom; assert( iCol>=0 ); zCol = pFKey->pFrom->aCol[iCol].zCnName; pRight = sqlite3Expr(db, TK_ID, zCol); pEq = sqlite3PExpr(pParse, TK_EQ, pLeft, pRight); pWhere = sqlite3ExprAnd(pParse, pWhere, pEq); } /* If the child table is the same as the parent table, then add terms ** to the WHERE clause that prevent this entry from being scanned. ** The added WHERE clause terms are like this: ** ** $current_rowid!=rowid ** NOT( $current_a==a AND $current_b==b AND ... ) ** ** The first form is used for rowid tables. The second form is used ** for WITHOUT ROWID tables. In the second form, the *parent* key is ** (a,b,...). Either the parent or primary key could be used to ** uniquely identify the current row, but the parent key is more convenient ** as the required values have already been loaded into registers ** by the caller. */ if( pTab==pFKey->pFrom && nIncr>0 ){ Expr *pNe; /* Expression (pLeft != pRight) */ Expr *pLeft; /* Value from parent table row */ Expr *pRight; /* Column ref to child table */ if( HasRowid(pTab) ){ pLeft = exprTableRegister(pParse, pTab, regData, -1); pRight = exprTableColumn(db, pTab, pSrc->a[0].iCursor, -1); pNe = sqlite3PExpr(pParse, TK_NE, pLeft, pRight); }else{ Expr *pEq, *pAll = 0; assert( pIdx!=0 ); for(i=0; i<pIdx->nKeyCol; i++){ i16 iCol = pIdx->aiColumn[i]; assert( iCol>=0 ); pLeft = exprTableRegister(pParse, pTab, regData, iCol); pRight = sqlite3Expr(db, TK_ID, pTab->aCol[iCol].zCnName); pEq = sqlite3PExpr(pParse, TK_IS, pLeft, pRight); pAll = sqlite3ExprAnd(pParse, pAll, pEq); } pNe = sqlite3PExpr(pParse, TK_NOT, pAll, 0); } pWhere = sqlite3ExprAnd(pParse, pWhere, pNe); } /* Resolve the references in the WHERE clause. */ memset(&sNameContext, 0, sizeof(NameContext)); sNameContext.pSrcList = pSrc; sNameContext.pParse = pParse; sqlite3ResolveExprNames(&sNameContext, pWhere); |
︙ | ︙ | |||
646 647 648 649 650 651 652 | sqlite3WhereEnd(pWInfo); } } /* Clean up the WHERE clause constructed above. */ sqlite3ExprDelete(db, pWhere); if( iFkIfZero ){ | | | 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 | sqlite3WhereEnd(pWInfo); } } /* Clean up the WHERE clause constructed above. */ sqlite3ExprDelete(db, pWhere); if( iFkIfZero ){ sqlite3VdbeJumpHereOrPopInst(v, iFkIfZero); } } /* ** This function returns a linked list of FKey objects (connected by ** FKey.pNextTo) holding all children of table pTab. For example, ** given the following schema: |
︙ | ︙ | |||
706 707 708 709 710 711 712 | ** ** then the equivalent of "DELETE FROM <tbl>" is executed before dropping ** the table from the database. Triggers are disabled while running this ** DELETE, but foreign key actions are not. */ void sqlite3FkDropTable(Parse *pParse, SrcList *pName, Table *pTab){ sqlite3 *db = pParse->db; | | | | | | 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 | ** ** then the equivalent of "DELETE FROM <tbl>" is executed before dropping ** the table from the database. Triggers are disabled while running this ** DELETE, but foreign key actions are not. */ void sqlite3FkDropTable(Parse *pParse, SrcList *pName, Table *pTab){ sqlite3 *db = pParse->db; if( (db->flags&SQLITE_ForeignKeys) && IsOrdinaryTable(pTab) ){ int iSkip = 0; Vdbe *v = sqlite3GetVdbe(pParse); assert( v ); /* VDBE has already been allocated */ assert( IsOrdinaryTable(pTab) ); if( sqlite3FkReferences(pTab)==0 ){ /* Search for a deferred foreign key constraint for which this table ** is the child table. If one cannot be found, return without ** generating any VDBE code. If one can be found, then jump over ** the entire DELETE if there are no outstanding deferred constraints ** when this statement is run. */ FKey *p; for(p=pTab->u.tab.pFKey; p; p=p->pNextFrom){ if( p->isDeferred || (db->flags & SQLITE_DeferFKs) ) break; } if( !p ) return; iSkip = sqlite3VdbeMakeLabel(pParse); sqlite3VdbeAddOp2(v, OP_FkIfZero, 1, iSkip); VdbeCoverage(v); } pParse->disableTriggers = 1; sqlite3DeleteFrom(pParse, sqlite3SrcListDup(db, pName, 0), 0, 0, 0); pParse->disableTriggers = 0; |
︙ | ︙ | |||
808 809 810 811 812 813 814 | for(i=0; i<p->nCol; i++){ char *zKey = p->aCol[i].zCol; int iKey; for(iKey=0; iKey<pTab->nCol; iKey++){ if( aChange[iKey]>=0 || (iKey==pTab->iPKey && bChngRowid) ){ Column *pCol = &pTab->aCol[iKey]; if( zKey ){ | | | 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 | for(i=0; i<p->nCol; i++){ char *zKey = p->aCol[i].zCol; int iKey; for(iKey=0; iKey<pTab->nCol; iKey++){ if( aChange[iKey]>=0 || (iKey==pTab->iPKey && bChngRowid) ){ Column *pCol = &pTab->aCol[iKey]; if( zKey ){ if( 0==sqlite3StrICmp(pCol->zCnName, zKey) ) return 1; }else if( pCol->colFlags & COLFLAG_PRIMKEY ){ return 1; } } } } return 0; |
︙ | ︙ | |||
875 876 877 878 879 880 881 882 883 884 885 886 887 | int isIgnoreErrors = pParse->disableTriggers; /* Exactly one of regOld and regNew should be non-zero. */ assert( (regOld==0)!=(regNew==0) ); /* If foreign-keys are disabled, this function is a no-op. */ if( (db->flags&SQLITE_ForeignKeys)==0 ) return; iDb = sqlite3SchemaToIndex(db, pTab->pSchema); zDb = db->aDb[iDb].zDbSName; /* Loop through all the foreign key constraints for which pTab is the ** child table (the table that the foreign key definition is part of). */ | > | | 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 | int isIgnoreErrors = pParse->disableTriggers; /* Exactly one of regOld and regNew should be non-zero. */ assert( (regOld==0)!=(regNew==0) ); /* If foreign-keys are disabled, this function is a no-op. */ if( (db->flags&SQLITE_ForeignKeys)==0 ) return; if( !IsOrdinaryTable(pTab) ) return; iDb = sqlite3SchemaToIndex(db, pTab->pSchema); zDb = db->aDb[iDb].zDbSName; /* Loop through all the foreign key constraints for which pTab is the ** child table (the table that the foreign key definition is part of). */ for(pFKey=pTab->u.tab.pFKey; pFKey; pFKey=pFKey->pNextFrom){ Table *pTo; /* Parent table of foreign key pFKey */ Index *pIdx = 0; /* Index on key columns in pTo */ int *aiFree = 0; int *aiCol; int iCol; int i; int bIgnore = 0; |
︙ | ︙ | |||
920 921 922 923 924 925 926 | ** If the parent table of an FK constraint on the current table is ** missing, behave as if it is empty. i.e. decrement the relevant ** FK counter for each row of the current table with non-NULL keys. */ Vdbe *v = sqlite3GetVdbe(pParse); int iJump = sqlite3VdbeCurrentAddr(v) + pFKey->nCol + 1; for(i=0; i<pFKey->nCol; i++){ | > | > | 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 | ** If the parent table of an FK constraint on the current table is ** missing, behave as if it is empty. i.e. decrement the relevant ** FK counter for each row of the current table with non-NULL keys. */ Vdbe *v = sqlite3GetVdbe(pParse); int iJump = sqlite3VdbeCurrentAddr(v) + pFKey->nCol + 1; for(i=0; i<pFKey->nCol; i++){ int iFromCol, iReg; iFromCol = pFKey->aCol[i].iFrom; iReg = sqlite3TableColumnToStorage(pFKey->pFrom,iFromCol) + regOld+1; sqlite3VdbeAddOp2(v, OP_IsNull, iReg, iJump); VdbeCoverage(v); } sqlite3VdbeAddOp2(v, OP_FkCounter, pFKey->isDeferred, -1); } continue; } assert( pFKey->nCol==1 || (aiFree && pIdx) ); |
︙ | ︙ | |||
946 947 948 949 950 951 952 | assert( pIdx==0 || pIdx->aiColumn[i]>=0 ); #ifndef SQLITE_OMIT_AUTHORIZATION /* Request permission to read the parent key columns. If the ** authorization callback returns SQLITE_IGNORE, behave as if any ** values read from the parent table are NULL. */ if( db->xAuth ){ int rcauth; | | | 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 | assert( pIdx==0 || pIdx->aiColumn[i]>=0 ); #ifndef SQLITE_OMIT_AUTHORIZATION /* Request permission to read the parent key columns. If the ** authorization callback returns SQLITE_IGNORE, behave as if any ** values read from the parent table are NULL. */ if( db->xAuth ){ int rcauth; char *zCol = pTo->aCol[pIdx ? pIdx->aiColumn[i] : pTo->iPKey].zCnName; rcauth = sqlite3AuthReadCol(pParse, pTo->zName, zCol, iDb); bIgnore = (rcauth==SQLITE_IGNORE); } #endif } /* Take a shared-cache advisory read-lock on the parent table. Allocate |
︙ | ︙ | |||
1008 1009 1010 1011 1012 1013 1014 | if( !isIgnoreErrors || db->mallocFailed ) return; continue; } assert( aiCol || pFKey->nCol==1 ); /* Create a SrcList structure containing the child table. We need the ** child table as a SrcList for sqlite3WhereBegin() */ | | | | 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 | if( !isIgnoreErrors || db->mallocFailed ) return; continue; } assert( aiCol || pFKey->nCol==1 ); /* Create a SrcList structure containing the child table. We need the ** child table as a SrcList for sqlite3WhereBegin() */ pSrc = sqlite3SrcListAppend(pParse, 0, 0, 0); if( pSrc ){ SrcItem *pItem = pSrc->a; pItem->pTab = pFKey->pFrom; pItem->zName = pFKey->pFrom->zName; pItem->pTab->nTabRef++; pItem->iCursor = pParse->nTab++; if( regNew!=0 ){ fkScanChildren(pParse, pSrc, pTab, pIdx, pFKey, aiCol, regNew, -1); |
︙ | ︙ | |||
1061 1062 1063 1064 1065 1066 1067 | ** row contained in table pTab. */ u32 sqlite3FkOldmask( Parse *pParse, /* Parse context */ Table *pTab /* Table being modified */ ){ u32 mask = 0; | | | | 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 | ** row contained in table pTab. */ u32 sqlite3FkOldmask( Parse *pParse, /* Parse context */ Table *pTab /* Table being modified */ ){ u32 mask = 0; if( pParse->db->flags&SQLITE_ForeignKeys && IsOrdinaryTable(pTab) ){ FKey *p; int i; for(p=pTab->u.tab.pFKey; p; p=p->pNextFrom){ for(i=0; i<p->nCol; i++) mask |= COLUMN_MASK(p->aCol[i].iFrom); } for(p=sqlite3FkReferences(pTab); p; p=p->pNextTo){ Index *pIdx = 0; sqlite3FkLocateIndex(pParse, pTab, p, &pIdx, 0); if( pIdx ){ for(i=0; i<pIdx->nKeyCol; i++){ |
︙ | ︙ | |||
1098 1099 1100 1101 1102 1103 1104 | ** ** If any foreign key processing will be required, this function returns ** non-zero. If there is no foreign key related processing, this function ** returns zero. ** ** For an UPDATE, this function returns 2 if: ** | | > > | > | | | < > | | | | 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 | ** ** If any foreign key processing will be required, this function returns ** non-zero. If there is no foreign key related processing, this function ** returns zero. ** ** For an UPDATE, this function returns 2 if: ** ** * There are any FKs for which pTab is the child and the parent table ** and any FK processing at all is required (even of a different FK), or ** ** * the UPDATE modifies one or more parent keys for which the action is ** not "NO ACTION" (i.e. is CASCADE, SET DEFAULT or SET NULL). ** ** Or, assuming some other foreign key processing is required, 1. */ int sqlite3FkRequired( Parse *pParse, /* Parse context */ Table *pTab, /* Table being modified */ int *aChange, /* Non-NULL for UPDATE operations */ int chngRowid /* True for UPDATE that affects rowid */ ){ int eRet = 1; /* Value to return if bHaveFK is true */ int bHaveFK = 0; /* If FK processing is required */ if( pParse->db->flags&SQLITE_ForeignKeys && IsOrdinaryTable(pTab) ){ if( !aChange ){ /* A DELETE operation. Foreign key processing is required if the ** table in question is either the child or parent table for any ** foreign key constraint. */ bHaveFK = (sqlite3FkReferences(pTab) || pTab->u.tab.pFKey); }else{ /* This is an UPDATE. Foreign key processing is only required if the ** operation modifies one or more child or parent key columns. */ FKey *p; /* Check if any child key columns are being modified. */ for(p=pTab->u.tab.pFKey; p; p=p->pNextFrom){ if( fkChildIsModified(pTab, p, aChange, chngRowid) ){ if( 0==sqlite3_stricmp(pTab->zName, p->zTo) ) eRet = 2; bHaveFK = 1; } } /* Check if any parent key columns are being modified. */ for(p=sqlite3FkReferences(pTab); p; p=p->pNextTo){ if( fkParentIsModified(pTab, p, aChange, chngRowid) ){ if( p->aAction[1]!=OE_None ) return 2; bHaveFK = 1; } } } } return bHaveFK ? eRet : 0; } /* ** This function is called when an UPDATE or DELETE operation is being ** compiled on table pTab, which is the parent table of foreign-key pFKey. ** If the current operation is an UPDATE, then the pChanges parameter is ** passed a pointer to the list of columns being modified. If it is a |
︙ | ︙ | |||
1216 1217 1218 1219 1220 1221 1222 | Expr *pEq; /* tFromCol = OLD.tToCol */ iFromCol = aiCol ? aiCol[i] : pFKey->aCol[0].iFrom; assert( iFromCol>=0 ); assert( pIdx!=0 || (pTab->iPKey>=0 && pTab->iPKey<pTab->nCol) ); assert( pIdx==0 || pIdx->aiColumn[i]>=0 ); sqlite3TokenInit(&tToCol, | | | | | > | > > > > > > > | 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 | Expr *pEq; /* tFromCol = OLD.tToCol */ iFromCol = aiCol ? aiCol[i] : pFKey->aCol[0].iFrom; assert( iFromCol>=0 ); assert( pIdx!=0 || (pTab->iPKey>=0 && pTab->iPKey<pTab->nCol) ); assert( pIdx==0 || pIdx->aiColumn[i]>=0 ); sqlite3TokenInit(&tToCol, pTab->aCol[pIdx ? pIdx->aiColumn[i] : pTab->iPKey].zCnName); sqlite3TokenInit(&tFromCol, pFKey->pFrom->aCol[iFromCol].zCnName); /* Create the expression "OLD.zToCol = zFromCol". It is important ** that the "OLD.zToCol" term is on the LHS of the = operator, so ** that the affinity and collation sequence associated with the ** parent table are used for the comparison. */ pEq = sqlite3PExpr(pParse, TK_EQ, sqlite3PExpr(pParse, TK_DOT, sqlite3ExprAlloc(db, TK_ID, &tOld, 0), sqlite3ExprAlloc(db, TK_ID, &tToCol, 0)), sqlite3ExprAlloc(db, TK_ID, &tFromCol, 0) ); pWhere = sqlite3ExprAnd(pParse, pWhere, pEq); /* For ON UPDATE, construct the next term of the WHEN clause. ** The final WHEN clause will be like this: ** ** WHEN NOT(old.col1 IS new.col1 AND ... AND old.colN IS new.colN) */ if( pChanges ){ pEq = sqlite3PExpr(pParse, TK_IS, sqlite3PExpr(pParse, TK_DOT, sqlite3ExprAlloc(db, TK_ID, &tOld, 0), sqlite3ExprAlloc(db, TK_ID, &tToCol, 0)), sqlite3PExpr(pParse, TK_DOT, sqlite3ExprAlloc(db, TK_ID, &tNew, 0), sqlite3ExprAlloc(db, TK_ID, &tToCol, 0)) ); pWhen = sqlite3ExprAnd(pParse, pWhen, pEq); } if( action!=OE_Restrict && (action!=OE_Cascade || pChanges) ){ Expr *pNew; if( action==OE_Cascade ){ pNew = sqlite3PExpr(pParse, TK_DOT, sqlite3ExprAlloc(db, TK_ID, &tNew, 0), sqlite3ExprAlloc(db, TK_ID, &tToCol, 0)); }else if( action==OE_SetDflt ){ Column *pCol = pFKey->pFrom->aCol + iFromCol; Expr *pDflt; if( pCol->colFlags & COLFLAG_GENERATED ){ testcase( pCol->colFlags & COLFLAG_VIRTUAL ); testcase( pCol->colFlags & COLFLAG_STORED ); pDflt = 0; }else{ pDflt = sqlite3ColumnExpr(pFKey->pFrom, pCol); } if( pDflt ){ pNew = sqlite3ExprDup(db, pDflt, 0); }else{ pNew = sqlite3ExprAlloc(db, TK_NULL, 0, 0); } }else{ pNew = sqlite3ExprAlloc(db, TK_NULL, 0, 0); |
︙ | ︙ | |||
1281 1282 1283 1284 1285 1286 1287 | Token tFrom; Expr *pRaise; tFrom.z = zFrom; tFrom.n = nFrom; pRaise = sqlite3Expr(db, TK_RAISE, "FOREIGN KEY constraint failed"); if( pRaise ){ | | | | | 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 | Token tFrom; Expr *pRaise; tFrom.z = zFrom; tFrom.n = nFrom; pRaise = sqlite3Expr(db, TK_RAISE, "FOREIGN KEY constraint failed"); if( pRaise ){ pRaise->affExpr = OE_Abort; } pSelect = sqlite3SelectNew(pParse, sqlite3ExprListAppend(pParse, 0, pRaise), sqlite3SrcListAppend(pParse, 0, &tFrom, 0), pWhere, 0, 0, 0, 0, 0 ); pWhere = 0; } /* Disable lookaside memory allocation */ DisableLookaside; pTrigger = (Trigger *)sqlite3DbMallocZero(db, sizeof(Trigger) + /* struct Trigger */ sizeof(TriggerStep) + /* Single step in trigger program */ nFrom + 1 /* Space for pStep->zTarget */ ); if( pTrigger ){ |
︙ | ︙ | |||
1315 1316 1317 1318 1319 1320 1321 | if( pWhen ){ pWhen = sqlite3PExpr(pParse, TK_NOT, pWhen, 0); pTrigger->pWhen = sqlite3ExprDup(db, pWhen, EXPRDUP_REDUCE); } } /* Re-enable the lookaside buffer, if it was disabled earlier. */ | | > | > | 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 | if( pWhen ){ pWhen = sqlite3PExpr(pParse, TK_NOT, pWhen, 0); pTrigger->pWhen = sqlite3ExprDup(db, pWhen, EXPRDUP_REDUCE); } } /* Re-enable the lookaside buffer, if it was disabled earlier. */ EnableLookaside; sqlite3ExprDelete(db, pWhere); sqlite3ExprDelete(db, pWhen); sqlite3ExprListDelete(db, pList); sqlite3SelectDelete(db, pSelect); if( db->mallocFailed==1 ){ fkTriggerDelete(db, pTrigger); return 0; } assert( pStep!=0 ); assert( pTrigger!=0 ); switch( action ){ case OE_Restrict: pStep->op = TK_SELECT; break; case OE_Cascade: if( !pChanges ){ pStep->op = TK_DELETE; break; } /* no break */ deliberate_fall_through default: pStep->op = TK_UPDATE; } pStep->pTrig = pTrigger; pTrigger->pSchema = pTab->pSchema; pTrigger->pTabSchema = pTab->pSchema; pFKey->apTrigger[iAction] = pTrigger; |
︙ | ︙ | |||
1389 1390 1391 1392 1393 1394 1395 | ** table pTab. Remove the deleted foreign keys from the Schema.fkeyHash ** hash table. */ void sqlite3FkDelete(sqlite3 *db, Table *pTab){ FKey *pFKey; /* Iterator variable */ FKey *pNext; /* Copy of pFKey->pNextFrom */ | | > | < | 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 | ** table pTab. Remove the deleted foreign keys from the Schema.fkeyHash ** hash table. */ void sqlite3FkDelete(sqlite3 *db, Table *pTab){ FKey *pFKey; /* Iterator variable */ FKey *pNext; /* Copy of pFKey->pNextFrom */ assert( IsOrdinaryTable(pTab) ); for(pFKey=pTab->u.tab.pFKey; pFKey; pFKey=pNext){ assert( db==0 || sqlite3SchemaMutexHeld(db, 0, pTab->pSchema) ); /* Remove the FK from the fkeyHash hash table. */ if( !db || db->pnBytesFreed==0 ){ if( pFKey->pPrevTo ){ pFKey->pPrevTo->pNextTo = pFKey->pNextTo; }else{ void *p = (void *)pFKey->pNextTo; |
︙ | ︙ |
Changes to src/func.c.
︙ | ︙ | |||
12 13 14 15 16 17 18 19 20 21 22 23 24 25 | ** This file contains the C-language implementations for many of the SQL ** functions of SQLite. (Some function, and in particular the date and ** time functions, are implemented separately.) */ #include "sqliteInt.h" #include <stdlib.h> #include <assert.h> #include "vdbeInt.h" /* ** Return the collating function associated with a function. */ static CollSeq *sqlite3GetFuncCollSeq(sqlite3_context *context){ VdbeOp *pOp; | > > > | 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | ** This file contains the C-language implementations for many of the SQL ** functions of SQLite. (Some function, and in particular the date and ** time functions, are implemented separately.) */ #include "sqliteInt.h" #include <stdlib.h> #include <assert.h> #ifndef SQLITE_OMIT_FLOATING_POINT #include <math.h> #endif #include "vdbeInt.h" /* ** Return the collating function associated with a function. */ static CollSeq *sqlite3GetFuncCollSeq(sqlite3_context *context){ VdbeOp *pOp; |
︙ | ︙ | |||
197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 | const unsigned char *zHaystack; const unsigned char *zNeedle; int nHaystack; int nNeedle; int typeHaystack, typeNeedle; int N = 1; int isText; UNUSED_PARAMETER(argc); typeHaystack = sqlite3_value_type(argv[0]); typeNeedle = sqlite3_value_type(argv[1]); if( typeHaystack==SQLITE_NULL || typeNeedle==SQLITE_NULL ) return; nHaystack = sqlite3_value_bytes(argv[0]); nNeedle = sqlite3_value_bytes(argv[1]); if( nNeedle>0 ){ if( typeHaystack==SQLITE_BLOB && typeNeedle==SQLITE_BLOB ){ zHaystack = sqlite3_value_blob(argv[0]); zNeedle = sqlite3_value_blob(argv[1]); isText = 0; | > > > | > > > > > > > > > > | > | > > > > > > > > > | 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 | const unsigned char *zHaystack; const unsigned char *zNeedle; int nHaystack; int nNeedle; int typeHaystack, typeNeedle; int N = 1; int isText; unsigned char firstChar; sqlite3_value *pC1 = 0; sqlite3_value *pC2 = 0; UNUSED_PARAMETER(argc); typeHaystack = sqlite3_value_type(argv[0]); typeNeedle = sqlite3_value_type(argv[1]); if( typeHaystack==SQLITE_NULL || typeNeedle==SQLITE_NULL ) return; nHaystack = sqlite3_value_bytes(argv[0]); nNeedle = sqlite3_value_bytes(argv[1]); if( nNeedle>0 ){ if( typeHaystack==SQLITE_BLOB && typeNeedle==SQLITE_BLOB ){ zHaystack = sqlite3_value_blob(argv[0]); zNeedle = sqlite3_value_blob(argv[1]); isText = 0; }else if( typeHaystack!=SQLITE_BLOB && typeNeedle!=SQLITE_BLOB ){ zHaystack = sqlite3_value_text(argv[0]); zNeedle = sqlite3_value_text(argv[1]); isText = 1; }else{ pC1 = sqlite3_value_dup(argv[0]); zHaystack = sqlite3_value_text(pC1); if( zHaystack==0 ) goto endInstrOOM; nHaystack = sqlite3_value_bytes(pC1); pC2 = sqlite3_value_dup(argv[1]); zNeedle = sqlite3_value_text(pC2); if( zNeedle==0 ) goto endInstrOOM; nNeedle = sqlite3_value_bytes(pC2); isText = 1; } if( zNeedle==0 || (nHaystack && zHaystack==0) ) goto endInstrOOM; firstChar = zNeedle[0]; while( nNeedle<=nHaystack && (zHaystack[0]!=firstChar || memcmp(zHaystack, zNeedle, nNeedle)!=0) ){ N++; do{ nHaystack--; zHaystack++; }while( isText && (zHaystack[0]&0xc0)==0x80 ); } if( nNeedle>nHaystack ) N = 0; } sqlite3_result_int(context, N); endInstr: sqlite3_value_free(pC1); sqlite3_value_free(pC2); return; endInstrOOM: sqlite3_result_error_nomem(context); goto endInstr; } /* ** Implementation of the printf() function. */ static void printfFunc( sqlite3_context *context, |
︙ | ︙ | |||
378 379 380 381 382 383 384 | } if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return; r = sqlite3_value_double(argv[0]); /* If Y==0 and X will fit in a 64-bit int, ** handle the rounding directly, ** otherwise use printf. */ | | | | | | 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 | } if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return; r = sqlite3_value_double(argv[0]); /* If Y==0 and X will fit in a 64-bit int, ** handle the rounding directly, ** otherwise use printf. */ if( r<-4503599627370496.0 || r>+4503599627370496.0 ){ /* The value has no fractional part so there is nothing to round */ }else if( n==0 ){ r = (double)((sqlite_int64)(r+(r<0?-0.5:+0.5))); }else{ zBuf = sqlite3_mprintf("%.*f",n,r); if( zBuf==0 ){ sqlite3_result_error_nomem(context); return; } sqlite3AtoF(zBuf, &r, sqlite3Strlen30(zBuf), SQLITE_UTF8); |
︙ | ︙ | |||
481 482 483 484 485 486 487 488 | */ static void randomFunc( sqlite3_context *context, int NotUsed, sqlite3_value **NotUsed2 ){ sqlite_int64 r; UNUSED_PARAMETER2(NotUsed, NotUsed2); | > | | 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 | */ static void randomFunc( sqlite3_context *context, int NotUsed, sqlite3_value **NotUsed2 ){ sqlite_int64 r; sqlite3 *db = sqlite3_context_db_handle(context); UNUSED_PARAMETER2(NotUsed, NotUsed2); sqlite3FastRandomness(&db->sPrng, sizeof(r), &r); if( r<0 ){ /* We need to prevent a random number of 0x8000000000000000 ** (or -9223372036854775808) since when you do abs() of that ** number of you get the same value back again. To do this ** in a way that is testable, mask the sign bit off of negative ** values, resulting in a positive value. Then take the ** 2s complement of that positive value. The end result can |
︙ | ︙ | |||
506 507 508 509 510 511 512 | ** that is N bytes long. */ static void randomBlob( sqlite3_context *context, int argc, sqlite3_value **argv ){ | | > | | | 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 | ** that is N bytes long. */ static void randomBlob( sqlite3_context *context, int argc, sqlite3_value **argv ){ sqlite3_int64 n; unsigned char *p; sqlite3 *db = sqlite3_context_db_handle(context); assert( argc==1 ); UNUSED_PARAMETER(argc); n = sqlite3_value_int64(argv[0]); if( n<1 ){ n = 1; } p = contextMalloc(context, n); if( p ){ sqlite3FastRandomness(&db->sPrng, n, p); sqlite3_result_blob(context, (char*)p, n, sqlite3_free); } } /* ** Implementation of the last_insert_rowid() SQL function. The return ** value is the same as the sqlite3_last_insert_rowid() API function. |
︙ | ︙ | |||
541 542 543 544 545 546 547 | ** function. */ sqlite3_result_int64(context, sqlite3_last_insert_rowid(db)); } /* ** Implementation of the changes() SQL function. ** | | | | | | | | | | 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 | ** function. */ sqlite3_result_int64(context, sqlite3_last_insert_rowid(db)); } /* ** Implementation of the changes() SQL function. ** ** IMP: R-32760-32347 The changes() SQL function is a wrapper ** around the sqlite3_changes64() C/C++ function and hence follows the ** same rules for counting changes. */ static void changes( sqlite3_context *context, int NotUsed, sqlite3_value **NotUsed2 ){ sqlite3 *db = sqlite3_context_db_handle(context); UNUSED_PARAMETER2(NotUsed, NotUsed2); sqlite3_result_int64(context, sqlite3_changes64(db)); } /* ** Implementation of the total_changes() SQL function. The return value is ** the same as the sqlite3_total_changes64() API function. */ static void total_changes( sqlite3_context *context, int NotUsed, sqlite3_value **NotUsed2 ){ sqlite3 *db = sqlite3_context_db_handle(context); UNUSED_PARAMETER2(NotUsed, NotUsed2); /* IMP: R-11217-42568 This function is a wrapper around the ** sqlite3_total_changes64() C/C++ interface. */ sqlite3_result_int64(context, sqlite3_total_changes64(db)); } /* ** A structure defining how to do GLOB-style comparisons. */ struct compareInfo { u8 matchAll; /* "*" or "%" */ |
︙ | ︙ | |||
664 665 666 667 668 669 670 | const u8 *zEscaped = 0; /* One past the last escaped input char */ while( (c = Utf8Read(zPattern))!=0 ){ if( c==matchAll ){ /* Match "*" */ /* Skip over multiple "*" characters in the pattern. If there ** are also "?" characters, skip those as well, but consume a ** single character of the input string for each "?" skipped */ | | > | 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 | const u8 *zEscaped = 0; /* One past the last escaped input char */ while( (c = Utf8Read(zPattern))!=0 ){ if( c==matchAll ){ /* Match "*" */ /* Skip over multiple "*" characters in the pattern. If there ** are also "?" characters, skip those as well, but consume a ** single character of the input string for each "?" skipped */ while( (c=Utf8Read(zPattern)) == matchAll || (c == matchOne && matchOne!=0) ){ if( c==matchOne && sqlite3Utf8Read(&zString)==0 ){ return SQLITE_NOWILDCARDMATCH; } } if( c==0 ){ return SQLITE_MATCH; /* "*" at the end of the pattern matches */ }else if( c==matchOther ){ |
︙ | ︙ | |||
823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 | sqlite3_value **argv ){ const unsigned char *zA, *zB; u32 escape; int nPat; sqlite3 *db = sqlite3_context_db_handle(context); struct compareInfo *pInfo = sqlite3_user_data(context); #ifdef SQLITE_LIKE_DOESNT_MATCH_BLOBS if( sqlite3_value_type(argv[0])==SQLITE_BLOB || sqlite3_value_type(argv[1])==SQLITE_BLOB ){ #ifdef SQLITE_TEST sqlite3_like_count++; #endif sqlite3_result_int(context, 0); return; } #endif | > < < < < > > > > > > > > | 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 | sqlite3_value **argv ){ const unsigned char *zA, *zB; u32 escape; int nPat; sqlite3 *db = sqlite3_context_db_handle(context); struct compareInfo *pInfo = sqlite3_user_data(context); struct compareInfo backupInfo; #ifdef SQLITE_LIKE_DOESNT_MATCH_BLOBS if( sqlite3_value_type(argv[0])==SQLITE_BLOB || sqlite3_value_type(argv[1])==SQLITE_BLOB ){ #ifdef SQLITE_TEST sqlite3_like_count++; #endif sqlite3_result_int(context, 0); return; } #endif /* Limit the length of the LIKE or GLOB pattern to avoid problems ** of deep recursion and N*N behavior in patternCompare(). */ nPat = sqlite3_value_bytes(argv[0]); testcase( nPat==db->aLimit[SQLITE_LIMIT_LIKE_PATTERN_LENGTH] ); testcase( nPat==db->aLimit[SQLITE_LIMIT_LIKE_PATTERN_LENGTH]+1 ); if( nPat > db->aLimit[SQLITE_LIMIT_LIKE_PATTERN_LENGTH] ){ sqlite3_result_error(context, "LIKE or GLOB pattern too complex", -1); return; } if( argc==3 ){ /* The escape character string must consist of a single UTF-8 character. ** Otherwise, return an error. */ const unsigned char *zEsc = sqlite3_value_text(argv[2]); if( zEsc==0 ) return; if( sqlite3Utf8CharLen((char*)zEsc, -1)!=1 ){ sqlite3_result_error(context, "ESCAPE expression must be a single character", -1); return; } escape = sqlite3Utf8Read(&zEsc); if( escape==pInfo->matchAll || escape==pInfo->matchOne ){ memcpy(&backupInfo, pInfo, sizeof(backupInfo)); pInfo = &backupInfo; if( escape==pInfo->matchAll ) pInfo->matchAll = 0; if( escape==pInfo->matchOne ) pInfo->matchOne = 0; } }else{ escape = pInfo->matchSet; } zB = sqlite3_value_text(argv[0]); zA = sqlite3_value_text(argv[1]); if( zA && zB ){ #ifdef SQLITE_TEST sqlite3_like_count++; #endif sqlite3_result_int(context, patternCompare(zB, zA, pInfo, escape)==SQLITE_MATCH); } |
︙ | ︙ | |||
1248 1249 1250 1251 1252 1253 1254 | } cntExpand++; if( (cntExpand&(cntExpand-1))==0 ){ /* Grow the size of the output buffer only on substitutions ** whose index is a power of two: 1, 2, 4, 8, 16, 32, ... */ u8 *zOld; zOld = zOut; | | | 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 | } cntExpand++; if( (cntExpand&(cntExpand-1))==0 ){ /* Grow the size of the output buffer only on substitutions ** whose index is a power of two: 1, 2, 4, 8, 16, 32, ... */ u8 *zOld; zOld = zOut; zOut = sqlite3Realloc(zOut, (int)nOut + (nOut - nStr - 1)); if( zOut==0 ){ sqlite3_result_error_nomem(context); sqlite3_free(zOld); return; } } } |
︙ | ︙ | |||
1280 1281 1282 1283 1284 1285 1286 | static void trimFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ const unsigned char *zIn; /* Input string */ const unsigned char *zCharSet; /* Set of characters to trim */ | | | | | | | > | | | | | 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 | static void trimFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ const unsigned char *zIn; /* Input string */ const unsigned char *zCharSet; /* Set of characters to trim */ unsigned int nIn; /* Number of bytes in input */ int flags; /* 1: trimleft 2: trimright 3: trim */ int i; /* Loop counter */ unsigned int *aLen = 0; /* Length of each character in zCharSet */ unsigned char **azChar = 0; /* Individual characters in zCharSet */ int nChar; /* Number of characters in zCharSet */ if( sqlite3_value_type(argv[0])==SQLITE_NULL ){ return; } zIn = sqlite3_value_text(argv[0]); if( zIn==0 ) return; nIn = (unsigned)sqlite3_value_bytes(argv[0]); assert( zIn==sqlite3_value_text(argv[0]) ); if( argc==1 ){ static const unsigned lenOne[] = { 1 }; static unsigned char * const azOne[] = { (u8*)" " }; nChar = 1; aLen = (unsigned*)lenOne; azChar = (unsigned char **)azOne; zCharSet = 0; }else if( (zCharSet = sqlite3_value_text(argv[1]))==0 ){ return; }else{ const unsigned char *z; for(z=zCharSet, nChar=0; *z; nChar++){ SQLITE_SKIP_UTF8(z); } if( nChar>0 ){ azChar = contextMalloc(context, ((i64)nChar)*(sizeof(char*)+sizeof(unsigned))); if( azChar==0 ){ return; } aLen = (unsigned*)&azChar[nChar]; for(z=zCharSet, nChar=0; *z; nChar++){ azChar[nChar] = (unsigned char *)z; SQLITE_SKIP_UTF8(z); aLen[nChar] = (unsigned)(z - azChar[nChar]); } } } if( nChar>0 ){ flags = SQLITE_PTR_TO_INT(sqlite3_user_data(context)); if( flags & 1 ){ while( nIn>0 ){ unsigned int len = 0; for(i=0; i<nChar; i++){ len = aLen[i]; if( len<=nIn && memcmp(zIn, azChar[i], len)==0 ) break; } if( i>=nChar ) break; zIn += len; nIn -= len; } } if( flags & 2 ){ while( nIn>0 ){ unsigned int len = 0; for(i=0; i<nChar; i++){ len = aLen[i]; if( len<=nIn && memcmp(&zIn[nIn-len],azChar[i],len)==0 ) break; } if( i>=nChar ) break; nIn -= len; } |
︙ | ︙ | |||
1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 | #endif /* SQLITE_OMIT_WINDOWFUNC */ static void minMaxFinalize(sqlite3_context *context){ minMaxValueFinalize(context, 0); } /* ** group_concat(EXPR, ?SEPARATOR?) */ static void groupConcatStep( sqlite3_context *context, int argc, sqlite3_value **argv ){ const char *zVal; | > > > > > > > > > > > > > > > > > > > > | | < | | | > | > > > > > > > | | | > > > > | | > > > > > > > > > > > > > > > > > | > > | > > > > > | > > | > < | > | | | > > > > | > > > | | > > > < > > | | | | > | > > > | | | < | | < < < | < > | | | > | | 1713 1714 1715 1716 1717 1718 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 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 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 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 | #endif /* SQLITE_OMIT_WINDOWFUNC */ static void minMaxFinalize(sqlite3_context *context){ minMaxValueFinalize(context, 0); } /* ** group_concat(EXPR, ?SEPARATOR?) ** ** The SEPARATOR goes before the EXPR string. This is tragic. The ** groupConcatInverse() implementation would have been easier if the ** SEPARATOR were appended after EXPR. And the order is undocumented, ** so we could change it, in theory. But the old behavior has been ** around for so long that we dare not, for fear of breaking something. */ typedef struct { StrAccum str; /* The accumulated concatenation */ #ifndef SQLITE_OMIT_WINDOWFUNC int nAccum; /* Number of strings presently concatenated */ int nFirstSepLength; /* Used to detect separator length change */ /* If pnSepLengths!=0, refs an array of inter-string separator lengths, ** stored as actually incorporated into presently accumulated result. ** (Hence, its slots in use number nAccum-1 between method calls.) ** If pnSepLengths==0, nFirstSepLength is the length used throughout. */ int *pnSepLengths; #endif } GroupConcatCtx; static void groupConcatStep( sqlite3_context *context, int argc, sqlite3_value **argv ){ const char *zVal; GroupConcatCtx *pGCC; const char *zSep; int nVal, nSep; assert( argc==1 || argc==2 ); if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return; pGCC = (GroupConcatCtx*)sqlite3_aggregate_context(context, sizeof(*pGCC)); if( pGCC ){ sqlite3 *db = sqlite3_context_db_handle(context); int firstTerm = pGCC->str.mxAlloc==0; pGCC->str.mxAlloc = db->aLimit[SQLITE_LIMIT_LENGTH]; if( argc==1 ){ if( !firstTerm ){ sqlite3_str_appendchar(&pGCC->str, 1, ','); } #ifndef SQLITE_OMIT_WINDOWFUNC else{ pGCC->nFirstSepLength = 1; } #endif }else if( !firstTerm ){ zSep = (char*)sqlite3_value_text(argv[1]); nSep = sqlite3_value_bytes(argv[1]); if( zSep ){ sqlite3_str_append(&pGCC->str, zSep, nSep); } #ifndef SQLITE_OMIT_WINDOWFUNC else{ nSep = 0; } if( nSep != pGCC->nFirstSepLength || pGCC->pnSepLengths != 0 ){ int *pnsl = pGCC->pnSepLengths; if( pnsl == 0 ){ /* First separator length variation seen, start tracking them. */ pnsl = (int*)sqlite3_malloc64((pGCC->nAccum+1) * sizeof(int)); if( pnsl!=0 ){ int i = 0, nA = pGCC->nAccum-1; while( i<nA ) pnsl[i++] = pGCC->nFirstSepLength; } }else{ pnsl = (int*)sqlite3_realloc64(pnsl, pGCC->nAccum * sizeof(int)); } if( pnsl!=0 ){ if( ALWAYS(pGCC->nAccum>0) ){ pnsl[pGCC->nAccum-1] = nSep; } pGCC->pnSepLengths = pnsl; }else{ sqlite3StrAccumSetError(&pGCC->str, SQLITE_NOMEM); } } #endif } #ifndef SQLITE_OMIT_WINDOWFUNC else{ pGCC->nFirstSepLength = sqlite3_value_bytes(argv[1]); } pGCC->nAccum += 1; #endif zVal = (char*)sqlite3_value_text(argv[0]); nVal = sqlite3_value_bytes(argv[0]); if( zVal ) sqlite3_str_append(&pGCC->str, zVal, nVal); } } #ifndef SQLITE_OMIT_WINDOWFUNC static void groupConcatInverse( sqlite3_context *context, int argc, sqlite3_value **argv ){ GroupConcatCtx *pGCC; assert( argc==1 || argc==2 ); (void)argc; /* Suppress unused parameter warning */ if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return; pGCC = (GroupConcatCtx*)sqlite3_aggregate_context(context, sizeof(*pGCC)); /* pGCC is always non-NULL since groupConcatStep() will have always ** run frist to initialize it */ if( ALWAYS(pGCC) ){ int nVS; /* Must call sqlite3_value_text() to convert the argument into text prior ** to invoking sqlite3_value_bytes(), in case the text encoding is UTF16 */ (void)sqlite3_value_text(argv[0]); nVS = sqlite3_value_bytes(argv[0]); pGCC->nAccum -= 1; if( pGCC->pnSepLengths!=0 ){ assert(pGCC->nAccum >= 0); if( pGCC->nAccum>0 ){ nVS += *pGCC->pnSepLengths; memmove(pGCC->pnSepLengths, pGCC->pnSepLengths+1, (pGCC->nAccum-1)*sizeof(int)); } }else{ /* If removing single accumulated string, harmlessly over-do. */ nVS += pGCC->nFirstSepLength; } if( nVS>=(int)pGCC->str.nChar ){ pGCC->str.nChar = 0; }else{ pGCC->str.nChar -= nVS; memmove(pGCC->str.zText, &pGCC->str.zText[nVS], pGCC->str.nChar); } if( pGCC->str.nChar==0 ){ pGCC->str.mxAlloc = 0; sqlite3_free(pGCC->pnSepLengths); pGCC->pnSepLengths = 0; } } } #else # define groupConcatInverse 0 #endif /* SQLITE_OMIT_WINDOWFUNC */ static void groupConcatFinalize(sqlite3_context *context){ GroupConcatCtx *pGCC = (GroupConcatCtx*)sqlite3_aggregate_context(context, 0); if( pGCC ){ sqlite3ResultStrAccum(context, &pGCC->str); #ifndef SQLITE_OMIT_WINDOWFUNC sqlite3_free(pGCC->pnSepLengths); #endif } } #ifndef SQLITE_OMIT_WINDOWFUNC static void groupConcatValue(sqlite3_context *context){ GroupConcatCtx *pGCC = (GroupConcatCtx*)sqlite3_aggregate_context(context, 0); if( pGCC ){ StrAccum *pAccum = &pGCC->str; if( pAccum->accError==SQLITE_TOOBIG ){ sqlite3_result_error_toobig(context); }else if( pAccum->accError==SQLITE_NOMEM ){ sqlite3_result_error_nomem(context); }else{ const char *zText = sqlite3_str_value(pAccum); sqlite3_result_text(context, zText, pAccum->nChar, SQLITE_TRANSIENT); } } } #else # define groupConcatValue 0 #endif /* SQLITE_OMIT_WINDOWFUNC */ |
︙ | ︙ | |||
1790 1791 1792 1793 1794 1795 1796 | assert( rc==SQLITE_NOMEM || rc==SQLITE_OK ); if( rc==SQLITE_NOMEM ){ sqlite3OomFault(db); } } /* | < < < < < < < < < < < | | > > > | < < | < | 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 | assert( rc==SQLITE_NOMEM || rc==SQLITE_OK ); if( rc==SQLITE_NOMEM ){ sqlite3OomFault(db); } } /* ** Re-register the built-in LIKE functions. The caseSensitive ** parameter determines whether or not the LIKE operator is case ** sensitive. */ void sqlite3RegisterLikeFunctions(sqlite3 *db, int caseSensitive){ struct compareInfo *pInfo; int flags; if( caseSensitive ){ pInfo = (struct compareInfo*)&likeInfoAlt; flags = SQLITE_FUNC_LIKE | SQLITE_FUNC_CASE; }else{ pInfo = (struct compareInfo*)&likeInfoNorm; flags = SQLITE_FUNC_LIKE; } sqlite3CreateFunc(db, "like", 2, SQLITE_UTF8, pInfo, likeFunc, 0, 0, 0, 0, 0); sqlite3CreateFunc(db, "like", 3, SQLITE_UTF8, pInfo, likeFunc, 0, 0, 0, 0, 0); sqlite3FindFunction(db, "like", 2, SQLITE_UTF8, 0)->funcFlags |= flags; sqlite3FindFunction(db, "like", 3, SQLITE_UTF8, 0)->funcFlags |= flags; } /* ** pExpr points to an expression which implements a function. If ** it is appropriate to apply the LIKE optimization to that function ** then set aWc[0] through aWc[2] to the wildcard characters and the ** escape character and then return TRUE. If the function is not a |
︙ | ︙ | |||
1841 1842 1843 1844 1845 1846 1847 | ** the function (default for LIKE). If the function makes the distinction ** between uppercase and lowercase (as does GLOB) then *pIsNocase is set to ** false. */ int sqlite3IsLikeFunction(sqlite3 *db, Expr *pExpr, int *pIsNocase, char *aWc){ FuncDef *pDef; int nExpr; | > > > | < > > > > < < < < < < < < < < > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | | < < < | | | > > | > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > < < < > | 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 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 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 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 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 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 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 | ** the function (default for LIKE). If the function makes the distinction ** between uppercase and lowercase (as does GLOB) then *pIsNocase is set to ** false. */ int sqlite3IsLikeFunction(sqlite3 *db, Expr *pExpr, int *pIsNocase, char *aWc){ FuncDef *pDef; int nExpr; assert( pExpr!=0 ); assert( pExpr->op==TK_FUNCTION ); assert( ExprUseXList(pExpr) ); if( !pExpr->x.pList ){ return 0; } nExpr = pExpr->x.pList->nExpr; assert( !ExprHasProperty(pExpr, EP_IntValue) ); pDef = sqlite3FindFunction(db, pExpr->u.zToken, nExpr, SQLITE_UTF8, 0); #ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION if( pDef==0 ) return 0; #endif if( NEVER(pDef==0) || (pDef->funcFlags & SQLITE_FUNC_LIKE)==0 ){ return 0; } /* The memcpy() statement assumes that the wildcard characters are ** the first three statements in the compareInfo structure. The ** asserts() that follow verify that assumption */ memcpy(aWc, pDef->pUserData, 3); assert( (char*)&likeInfoAlt == (char*)&likeInfoAlt.matchAll ); assert( &((char*)&likeInfoAlt)[1] == (char*)&likeInfoAlt.matchOne ); assert( &((char*)&likeInfoAlt)[2] == (char*)&likeInfoAlt.matchSet ); if( nExpr<3 ){ aWc[3] = 0; }else{ Expr *pEscape = pExpr->x.pList->a[2].pExpr; char *zEscape; if( pEscape->op!=TK_STRING ) return 0; assert( !ExprHasProperty(pEscape, EP_IntValue) ); zEscape = pEscape->u.zToken; if( zEscape[0]==0 || zEscape[1]!=0 ) return 0; if( zEscape[0]==aWc[0] ) return 0; if( zEscape[0]==aWc[1] ) return 0; aWc[3] = zEscape[0]; } *pIsNocase = (pDef->funcFlags & SQLITE_FUNC_CASE)==0; return 1; } /* Mathematical Constants */ #ifndef M_PI # define M_PI 3.141592653589793238462643383279502884 #endif #ifndef M_LN10 # define M_LN10 2.302585092994045684017991454684364208 #endif #ifndef M_LN2 # define M_LN2 0.693147180559945309417232121458176568 #endif /* Extra math functions that require linking with -lm */ #ifdef SQLITE_ENABLE_MATH_FUNCTIONS /* ** Implementation SQL functions: ** ** ceil(X) ** ceiling(X) ** floor(X) ** ** The sqlite3_user_data() pointer is a pointer to the libm implementation ** of the underlying C function. */ static void ceilingFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ assert( argc==1 ); switch( sqlite3_value_numeric_type(argv[0]) ){ case SQLITE_INTEGER: { sqlite3_result_int64(context, sqlite3_value_int64(argv[0])); break; } case SQLITE_FLOAT: { double (*x)(double) = (double(*)(double))sqlite3_user_data(context); sqlite3_result_double(context, x(sqlite3_value_double(argv[0]))); break; } default: { break; } } } /* ** On some systems, ceil() and floor() are intrinsic function. You are ** unable to take a pointer to these functions. Hence, we here wrap them ** in our own actual functions. */ static double xCeil(double x){ return ceil(x); } static double xFloor(double x){ return floor(x); } /* ** Implementation of SQL functions: ** ** ln(X) - natural logarithm ** log(X) - log X base 10 ** log10(X) - log X base 10 ** log(B,X) - log X base B */ static void logFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ double x, b, ans; assert( argc==1 || argc==2 ); switch( sqlite3_value_numeric_type(argv[0]) ){ case SQLITE_INTEGER: case SQLITE_FLOAT: x = sqlite3_value_double(argv[0]); if( x<=0.0 ) return; break; default: return; } if( argc==2 ){ switch( sqlite3_value_numeric_type(argv[0]) ){ case SQLITE_INTEGER: case SQLITE_FLOAT: b = log(x); if( b<=0.0 ) return; x = sqlite3_value_double(argv[1]); if( x<=0.0 ) return; break; default: return; } ans = log(x)/b; }else{ ans = log(x); switch( SQLITE_PTR_TO_INT(sqlite3_user_data(context)) ){ case 1: /* Convert from natural logarithm to log base 10 */ ans *= 1.0/M_LN10; break; case 2: /* Convert from natural logarithm to log base 2 */ ans *= 1.0/M_LN2; break; default: break; } } sqlite3_result_double(context, ans); } /* ** Functions to converts degrees to radians and radians to degrees. */ static double degToRad(double x){ return x*(M_PI/180.0); } static double radToDeg(double x){ return x*(180.0/M_PI); } /* ** Implementation of 1-argument SQL math functions: ** ** exp(X) - Compute e to the X-th power */ static void math1Func( sqlite3_context *context, int argc, sqlite3_value **argv ){ int type0; double v0, ans; double (*x)(double); assert( argc==1 ); type0 = sqlite3_value_numeric_type(argv[0]); if( type0!=SQLITE_INTEGER && type0!=SQLITE_FLOAT ) return; v0 = sqlite3_value_double(argv[0]); x = (double(*)(double))sqlite3_user_data(context); ans = x(v0); sqlite3_result_double(context, ans); } /* ** Implementation of 2-argument SQL math functions: ** ** power(X,Y) - Compute X to the Y-th power */ static void math2Func( sqlite3_context *context, int argc, sqlite3_value **argv ){ int type0, type1; double v0, v1, ans; double (*x)(double,double); assert( argc==2 ); type0 = sqlite3_value_numeric_type(argv[0]); if( type0!=SQLITE_INTEGER && type0!=SQLITE_FLOAT ) return; type1 = sqlite3_value_numeric_type(argv[1]); if( type1!=SQLITE_INTEGER && type1!=SQLITE_FLOAT ) return; v0 = sqlite3_value_double(argv[0]); v1 = sqlite3_value_double(argv[1]); x = (double(*)(double,double))sqlite3_user_data(context); ans = x(v0, v1); sqlite3_result_double(context, ans); } /* ** Implementation of 0-argument pi() function. */ static void piFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ assert( argc==0 ); sqlite3_result_double(context, M_PI); } #endif /* SQLITE_ENABLE_MATH_FUNCTIONS */ /* ** Implementation of sign(X) function. */ static void signFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ int type0; double x; UNUSED_PARAMETER(argc); assert( argc==1 ); type0 = sqlite3_value_numeric_type(argv[0]); if( type0!=SQLITE_INTEGER && type0!=SQLITE_FLOAT ) return; x = sqlite3_value_double(argv[0]); sqlite3_result_int(context, x<0.0 ? -1 : x>0.0 ? +1 : 0); } /* ** All of the FuncDef structures in the aBuiltinFunc[] array above ** to the global function hash table. This occurs at start-time (as ** a consequence of calling sqlite3_initialize()). ** ** After this routine runs */ void sqlite3RegisterBuiltinFunctions(void){ /* ** The following array holds FuncDef structures for all of the functions ** defined in this file. ** ** The array cannot be constant since changes are made to the ** FuncDef.pHash elements at start-time. The elements of this array ** are read-only after initialization is complete. ** ** For peak efficiency, put the most frequently used function last. */ static FuncDef aBuiltinFunc[] = { /***** Functions only available with SQLITE_TESTCTRL_INTERNAL_FUNCTIONS *****/ #if !defined(SQLITE_UNTESTABLE) TEST_FUNC(implies_nonnull_row, 2, INLINEFUNC_implies_nonnull_row, 0), TEST_FUNC(expr_compare, 2, INLINEFUNC_expr_compare, 0), TEST_FUNC(expr_implies_expr, 2, INLINEFUNC_expr_implies_expr, 0), TEST_FUNC(affinity, 1, INLINEFUNC_affinity, 0), #endif /* !defined(SQLITE_UNTESTABLE) */ /***** Regular functions *****/ #ifdef SQLITE_SOUNDEX FUNCTION(soundex, 1, 0, 0, soundexFunc ), #endif #ifndef SQLITE_OMIT_LOAD_EXTENSION SFUNCTION(load_extension, 1, 0, 0, loadExt ), SFUNCTION(load_extension, 2, 0, 0, loadExt ), #endif #if SQLITE_USER_AUTHENTICATION FUNCTION(sqlite_crypt, 2, 0, 0, sqlite3CryptFunc ), #endif #ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS DFUNCTION(sqlite_compileoption_used,1, 0, 0, compileoptionusedFunc ), DFUNCTION(sqlite_compileoption_get, 1, 0, 0, compileoptiongetFunc ), #endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */ INLINE_FUNC(unlikely, 1, INLINEFUNC_unlikely, SQLITE_FUNC_UNLIKELY), INLINE_FUNC(likelihood, 2, INLINEFUNC_unlikely, SQLITE_FUNC_UNLIKELY), INLINE_FUNC(likely, 1, INLINEFUNC_unlikely, SQLITE_FUNC_UNLIKELY), #ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC FUNCTION2(sqlite_offset, 1, 0, 0, noopFunc, SQLITE_FUNC_OFFSET| SQLITE_FUNC_TYPEOF), #endif FUNCTION(ltrim, 1, 1, 0, trimFunc ), FUNCTION(ltrim, 2, 1, 0, trimFunc ), FUNCTION(rtrim, 1, 2, 0, trimFunc ), FUNCTION(rtrim, 2, 2, 0, trimFunc ), FUNCTION(trim, 1, 3, 0, trimFunc ), FUNCTION(trim, 2, 3, 0, trimFunc ), FUNCTION(min, -1, 0, 1, minmaxFunc ), FUNCTION(min, 0, 0, 1, 0 ), WAGGREGATE(min, 1, 0, 1, minmaxStep, minMaxFinalize, minMaxValue, 0, SQLITE_FUNC_MINMAX|SQLITE_FUNC_ANYORDER ), FUNCTION(max, -1, 1, 1, minmaxFunc ), FUNCTION(max, 0, 1, 1, 0 ), WAGGREGATE(max, 1, 1, 1, minmaxStep, minMaxFinalize, minMaxValue, 0, SQLITE_FUNC_MINMAX|SQLITE_FUNC_ANYORDER ), FUNCTION2(typeof, 1, 0, 0, typeofFunc, SQLITE_FUNC_TYPEOF), FUNCTION2(length, 1, 0, 0, lengthFunc, SQLITE_FUNC_LENGTH), FUNCTION(instr, 2, 0, 0, instrFunc ), FUNCTION(printf, -1, 0, 0, printfFunc ), FUNCTION(unicode, 1, 0, 0, unicodeFunc ), FUNCTION(char, -1, 0, 0, charFunc ), FUNCTION(abs, 1, 0, 0, absFunc ), #ifndef SQLITE_OMIT_FLOATING_POINT FUNCTION(round, 1, 0, 0, roundFunc ), FUNCTION(round, 2, 0, 0, roundFunc ), #endif FUNCTION(upper, 1, 0, 0, upperFunc ), FUNCTION(lower, 1, 0, 0, lowerFunc ), FUNCTION(hex, 1, 0, 0, hexFunc ), INLINE_FUNC(ifnull, 2, INLINEFUNC_coalesce, 0 ), VFUNCTION(random, 0, 0, 0, randomFunc ), VFUNCTION(randomblob, 1, 0, 0, randomBlob ), FUNCTION(nullif, 2, 0, 1, nullifFunc ), DFUNCTION(sqlite_version, 0, 0, 0, versionFunc ), DFUNCTION(sqlite_source_id, 0, 0, 0, sourceidFunc ), FUNCTION(sqlite_log, 2, 0, 0, errlogFunc ), FUNCTION(quote, 1, 0, 0, quoteFunc ), VFUNCTION(last_insert_rowid, 0, 0, 0, last_insert_rowid), VFUNCTION(changes, 0, 0, 0, changes ), VFUNCTION(total_changes, 0, 0, 0, total_changes ), FUNCTION(replace, 3, 0, 0, replaceFunc ), FUNCTION(zeroblob, 1, 0, 0, zeroblobFunc ), FUNCTION(substr, 2, 0, 0, substrFunc ), FUNCTION(substr, 3, 0, 0, substrFunc ), FUNCTION(substring, 2, 0, 0, substrFunc ), FUNCTION(substring, 3, 0, 0, substrFunc ), WAGGREGATE(sum, 1,0,0, sumStep, sumFinalize, sumFinalize, sumInverse, 0), WAGGREGATE(total, 1,0,0, sumStep,totalFinalize,totalFinalize,sumInverse, 0), WAGGREGATE(avg, 1,0,0, sumStep, avgFinalize, avgFinalize, sumInverse, 0), WAGGREGATE(count, 0,0,0, countStep, countFinalize, countFinalize, countInverse, SQLITE_FUNC_COUNT|SQLITE_FUNC_ANYORDER ), WAGGREGATE(count, 1,0,0, countStep, countFinalize, countFinalize, countInverse, SQLITE_FUNC_ANYORDER ), WAGGREGATE(group_concat, 1, 0, 0, groupConcatStep, groupConcatFinalize, groupConcatValue, groupConcatInverse, 0), WAGGREGATE(group_concat, 2, 0, 0, groupConcatStep, groupConcatFinalize, groupConcatValue, groupConcatInverse, 0), LIKEFUNC(glob, 2, &globInfo, SQLITE_FUNC_LIKE|SQLITE_FUNC_CASE), #ifdef SQLITE_CASE_SENSITIVE_LIKE LIKEFUNC(like, 2, &likeInfoAlt, SQLITE_FUNC_LIKE|SQLITE_FUNC_CASE), LIKEFUNC(like, 3, &likeInfoAlt, SQLITE_FUNC_LIKE|SQLITE_FUNC_CASE), #else LIKEFUNC(like, 2, &likeInfoNorm, SQLITE_FUNC_LIKE), LIKEFUNC(like, 3, &likeInfoNorm, SQLITE_FUNC_LIKE), #endif #ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION FUNCTION(unknown, -1, 0, 0, unknownFunc ), #endif FUNCTION(coalesce, 1, 0, 0, 0 ), FUNCTION(coalesce, 0, 0, 0, 0 ), #ifdef SQLITE_ENABLE_MATH_FUNCTIONS MFUNCTION(ceil, 1, xCeil, ceilingFunc ), MFUNCTION(ceiling, 1, xCeil, ceilingFunc ), MFUNCTION(floor, 1, xFloor, ceilingFunc ), #if SQLITE_HAVE_C99_MATH_FUNCS MFUNCTION(trunc, 1, trunc, ceilingFunc ), #endif FUNCTION(ln, 1, 0, 0, logFunc ), FUNCTION(log, 1, 1, 0, logFunc ), FUNCTION(log10, 1, 1, 0, logFunc ), FUNCTION(log2, 1, 2, 0, logFunc ), FUNCTION(log, 2, 0, 0, logFunc ), MFUNCTION(exp, 1, exp, math1Func ), MFUNCTION(pow, 2, pow, math2Func ), MFUNCTION(power, 2, pow, math2Func ), MFUNCTION(mod, 2, fmod, math2Func ), MFUNCTION(acos, 1, acos, math1Func ), MFUNCTION(asin, 1, asin, math1Func ), MFUNCTION(atan, 1, atan, math1Func ), MFUNCTION(atan2, 2, atan2, math2Func ), MFUNCTION(cos, 1, cos, math1Func ), MFUNCTION(sin, 1, sin, math1Func ), MFUNCTION(tan, 1, tan, math1Func ), MFUNCTION(cosh, 1, cosh, math1Func ), MFUNCTION(sinh, 1, sinh, math1Func ), MFUNCTION(tanh, 1, tanh, math1Func ), #if SQLITE_HAVE_C99_MATH_FUNCS MFUNCTION(acosh, 1, acosh, math1Func ), MFUNCTION(asinh, 1, asinh, math1Func ), MFUNCTION(atanh, 1, atanh, math1Func ), #endif MFUNCTION(sqrt, 1, sqrt, math1Func ), MFUNCTION(radians, 1, degToRad, math1Func ), MFUNCTION(degrees, 1, radToDeg, math1Func ), FUNCTION(pi, 0, 0, 0, piFunc ), #endif /* SQLITE_ENABLE_MATH_FUNCTIONS */ FUNCTION(sign, 1, 0, 0, signFunc ), INLINE_FUNC(coalesce, -1, INLINEFUNC_coalesce, 0 ), INLINE_FUNC(iif, 3, INLINEFUNC_iif, 0 ), }; #ifndef SQLITE_OMIT_ALTERTABLE sqlite3AlterFunctions(); #endif sqlite3WindowFunctions(); sqlite3RegisterDateTimeFunctions(); sqlite3InsertBuiltinFuncs(aBuiltinFunc, ArraySize(aBuiltinFunc)); #if 0 /* Enable to print out how the built-in functions are hashed */ { int i; FuncDef *p; for(i=0; i<SQLITE_FUNC_HASH_SZ; i++){ printf("FUNC-HASH %02d:", i); for(p=sqlite3BuiltinFunctions.a[i]; p; p=p->u.pHash){ int n = sqlite3Strlen30(p->zName); int h = p->zName[0] + n; assert( p->funcFlags & SQLITE_FUNC_BUILTIN ); printf(" %s(%d)", p->zName, h); } printf("\n"); } } #endif } |
Changes to src/global.c.
︙ | ︙ | |||
33 34 35 36 37 38 39 | 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, | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | 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, #endif #ifdef SQLITE_EBCDIC 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, /* 0x */ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, /* 1x */ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, /* 2x */ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, /* 3x */ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, /* 4x */ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, /* 5x */ 96, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111, /* 6x */ 112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127, /* 7x */ 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, /* 8x */ 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159, /* 9x */ 160,161,162,163,164,165,166,167,168,169,170,171,140,141,142,175, /* Ax */ 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191, /* Bx */ 192,129,130,131,132,133,134,135,136,137,202,203,204,205,206,207, /* Cx */ 208,145,146,147,148,149,150,151,152,153,218,219,220,221,222,223, /* Dx */ 224,225,162,163,164,165,166,167,168,169,234,235,236,237,238,239, /* Ex */ 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255, /* Fx */ #endif /* All of the upper-to-lower conversion data is above. The following ** 18 integers are completely unrelated. They are appended to the ** sqlite3UpperToLower[] array to avoid UBSAN warnings. Here's what is ** going on: ** ** The SQL comparison operators (<>, =, >, <=, <, and >=) are implemented ** by invoking sqlite3MemCompare(A,B) which compares values A and B and ** returns negative, zero, or positive if A is less then, equal to, or ** greater than B, respectively. Then the true false results is found by ** consulting sqlite3aLTb[opcode], sqlite3aEQb[opcode], or ** sqlite3aGTb[opcode] depending on whether the result of compare(A,B) ** is negative, zero, or positive, where opcode is the specific opcode. ** The only works because the comparison opcodes are consecutive and in ** this order: NE EQ GT LE LT GE. Various assert()s throughout the code ** ensure that is the case. ** ** These elements must be appended to another array. Otherwise the ** index (here shown as [256-OP_Ne]) would be out-of-bounds and thus ** be undefined behavior. That's goofy, but the C-standards people thought ** it was a good idea, so here we are. */ /* NE EQ GT LE LT GE */ 1, 0, 0, 1, 1, 0, /* aLTb[]: Use when compare(A,B) less than zero */ 0, 1, 0, 1, 0, 1, /* aEQb[]: Use when compare(A,B) equals zero */ 1, 0, 1, 0, 0, 1 /* aGTb[]: Use when compare(A,B) greater than zero*/ }; const unsigned char *sqlite3aLTb = &sqlite3UpperToLower[256-OP_Ne]; const unsigned char *sqlite3aEQb = &sqlite3UpperToLower[256+6-OP_Ne]; const unsigned char *sqlite3aGTb = &sqlite3UpperToLower[256+12-OP_Ne]; /* ** The following 256 byte lookup table is used to support SQLites built-in ** equivalents to the following standard library functions: ** ** isspace() 0x01 ** isalpha() 0x02 |
︙ | ︙ | |||
83 84 85 86 87 88 89 | ** array. tolower() is used more often than toupper() by SQLite. ** ** Bit 0x40 is set if the character is non-alphanumeric and can be used in an ** SQLite identifier. Identifiers are alphanumerics, "_", "$", and any ** non-ASCII UTF character. Hence the test for whether or not a character is ** part of an identifier is 0x46. */ | < | 111 112 113 114 115 116 117 118 119 120 121 122 123 124 | ** array. tolower() is used more often than toupper() by SQLite. ** ** Bit 0x40 is set if the character is non-alphanumeric and can be used in an ** SQLite identifier. Identifiers are alphanumerics, "_", "$", and any ** non-ASCII UTF character. Hence the test for whether or not a character is ** part of an identifier is 0x46. */ const unsigned char sqlite3CtypeMap[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 00..07 ........ */ 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, /* 08..0f ........ */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 10..17 ........ */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 18..1f ........ */ 0x01, 0x00, 0x80, 0x00, 0x40, 0x00, 0x00, 0x80, /* 20..27 !"#$%&' */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 28..2f ()*+,-./ */ |
︙ | ︙ | |||
121 122 123 124 125 126 127 | 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* d0..d7 ........ */ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* d8..df ........ */ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* e0..e7 ........ */ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* e8..ef ........ */ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* f0..f7 ........ */ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40 /* f8..ff ........ */ }; | < < < < < < < | < | > > > > > > > | 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 | 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* d0..d7 ........ */ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* d8..df ........ */ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* e0..e7 ........ */ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* e8..ef ........ */ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* f0..f7 ........ */ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40 /* f8..ff ........ */ }; /* EVIDENCE-OF: R-02982-34736 In order to maintain full backwards ** compatibility for legacy applications, the URI filename capability is ** disabled by default. ** ** EVIDENCE-OF: R-38799-08373 URI filenames can be enabled or disabled ** using the SQLITE_USE_URI=1 or SQLITE_USE_URI=0 compile-time options. ** ** EVIDENCE-OF: R-43642-56306 By default, URI handling is globally ** disabled. The default value may be changed by compiling with the ** SQLITE_USE_URI symbol defined. */ #ifndef SQLITE_USE_URI # define SQLITE_USE_URI 0 #endif /* EVIDENCE-OF: R-38720-18127 The default setting is determined by the ** SQLITE_ALLOW_COVERING_INDEX_SCAN compile-time option, or is "on" if ** that compile-time option is omitted. */ #if !defined(SQLITE_ALLOW_COVERING_INDEX_SCAN) # define SQLITE_ALLOW_COVERING_INDEX_SCAN 1 #else # if !SQLITE_ALLOW_COVERING_INDEX_SCAN # error "Compile-time disabling of covering index scan using the\ -DSQLITE_ALLOW_COVERING_INDEX_SCAN=0 option is deprecated.\ Contact SQLite developers if this is a problem for you, and\ delete this #error macro to continue with your build." # endif #endif /* The minimum PMA size is set to this value multiplied by the database ** page size in bytes. */ #ifndef SQLITE_SORTER_PMASZ # define SQLITE_SORTER_PMASZ 250 |
︙ | ︙ | |||
179 180 181 182 183 184 185 186 187 | /* ** The default lookaside-configuration, the format "SZ,N". SZ is the ** number of bytes in each lookaside slot (should be a multiple of 8) ** and N is the number of slots. The lookaside-configuration can be ** changed as start-time using sqlite3_config(SQLITE_CONFIG_LOOKASIDE) ** or at run-time for an individual database connection using ** sqlite3_db_config(db, SQLITE_DBCONFIG_LOOKASIDE); */ #ifndef SQLITE_DEFAULT_LOOKASIDE | > > > > > > | > > > > > > > > > > > | 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 | /* ** The default lookaside-configuration, the format "SZ,N". SZ is the ** number of bytes in each lookaside slot (should be a multiple of 8) ** and N is the number of slots. The lookaside-configuration can be ** changed as start-time using sqlite3_config(SQLITE_CONFIG_LOOKASIDE) ** or at run-time for an individual database connection using ** sqlite3_db_config(db, SQLITE_DBCONFIG_LOOKASIDE); ** ** With the two-size-lookaside enhancement, less lookaside is required. ** The default configuration of 1200,40 actually provides 30 1200-byte slots ** and 93 128-byte slots, which is more lookaside than is available ** using the older 1200,100 configuration without two-size-lookaside. */ #ifndef SQLITE_DEFAULT_LOOKASIDE # ifdef SQLITE_OMIT_TWOSIZE_LOOKASIDE # define SQLITE_DEFAULT_LOOKASIDE 1200,100 /* 120KB of memory */ # else # define SQLITE_DEFAULT_LOOKASIDE 1200,40 /* 48KB of memory */ # endif #endif /* The default maximum size of an in-memory database created using ** sqlite3_deserialize() */ #ifndef SQLITE_MEMDB_DEFAULT_MAXSIZE # define SQLITE_MEMDB_DEFAULT_MAXSIZE 1073741824 #endif /* ** The following singleton contains the global configuration for ** the SQLite library. */ SQLITE_WSD struct Sqlite3Config sqlite3Config = { SQLITE_DEFAULT_MEMSTATUS, /* bMemstat */ 1, /* bCoreMutex */ SQLITE_THREADSAFE==1, /* bFullMutex */ SQLITE_USE_URI, /* bOpenUri */ SQLITE_ALLOW_COVERING_INDEX_SCAN, /* bUseCis */ 0, /* bSmallMalloc */ 1, /* bExtraSchemaChecks */ 0x7ffffffe, /* mxStrlen */ 0, /* neverCorrupt */ SQLITE_DEFAULT_LOOKASIDE, /* szLookaside, nLookaside */ SQLITE_STMTJRNL_SPILL, /* nStmtSpill */ {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 */ |
︙ | ︙ | |||
232 233 234 235 236 237 238 239 240 241 242 | 0, /* xSqllog */ 0, /* pSqllogArg */ #endif #ifdef SQLITE_VDBE_COVERAGE 0, /* xVdbeBranch */ 0, /* pVbeBranchArg */ #endif #ifndef SQLITE_UNTESTABLE 0, /* xTestCallback */ #endif 0, /* bLocaltimeFault */ | > > > < | > > > | > > > > | < < < > | 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 | 0, /* xSqllog */ 0, /* pSqllogArg */ #endif #ifdef SQLITE_VDBE_COVERAGE 0, /* xVdbeBranch */ 0, /* pVbeBranchArg */ #endif #ifndef SQLITE_OMIT_DESERIALIZE SQLITE_MEMDB_DEFAULT_MAXSIZE, /* mxMemdbSize */ #endif #ifndef SQLITE_UNTESTABLE 0, /* xTestCallback */ #endif 0, /* bLocaltimeFault */ 0x7ffffffe, /* iOnceResetThreshold */ SQLITE_DEFAULT_SORTERREF_SIZE, /* szSorterRef */ 0, /* iPrngSeed */ }; /* ** Hash table for global functions - functions common to all ** database connections. After initialization, this table is ** read-only. */ FuncDefHash sqlite3BuiltinFunctions; #if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_DEBUG) /* ** Counter used for coverage testing. Does not come into play for ** release builds. ** ** Access to this global variable is not mutex protected. This might ** result in TSAN warnings. But as the variable does not exist in ** release builds, that should not be a concern. */ unsigned int sqlite3CoverageCounter; #endif /* SQLITE_COVERAGE_TEST || SQLITE_DEBUG */ #ifdef VDBE_PROFILE /* ** The following performance counter can be used in place of ** sqlite3Hwtime() for profiling. This is a no-op on standard builds. */ sqlite3_uint64 sqlite3NProfileCnt = 0; |
︙ | ︙ | |||
286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 | ** Changing the pending byte during operation will result in undefined ** and incorrect behavior. */ #ifndef SQLITE_OMIT_WSD int sqlite3PendingByte = 0x40000000; #endif #include "opcodes.h" /* ** Properties of opcodes. The OPFLG_INITIALIZER macro is ** created by mkopcodeh.awk during compilation. Data is obtained ** from the comments following the "case OP_xxxx:" statements in ** the vdbe.c file. */ const unsigned char sqlite3OpcodeProperty[] = OPFLG_INITIALIZER; /* ** Name of the default collating sequence */ const char sqlite3StrBINARY[] = "BINARY"; | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | ** Changing the pending byte during operation will result in undefined ** and incorrect behavior. */ #ifndef SQLITE_OMIT_WSD int sqlite3PendingByte = 0x40000000; #endif /* ** Tracing flags set by SQLITE_TESTCTRL_TRACEFLAGS. */ u32 sqlite3SelectTrace = 0; u32 sqlite3WhereTrace = 0; #include "opcodes.h" /* ** Properties of opcodes. The OPFLG_INITIALIZER macro is ** created by mkopcodeh.awk during compilation. Data is obtained ** from the comments following the "case OP_xxxx:" statements in ** the vdbe.c file. */ const unsigned char sqlite3OpcodeProperty[] = OPFLG_INITIALIZER; /* ** Name of the default collating sequence */ const char sqlite3StrBINARY[] = "BINARY"; /* ** Standard typenames. These names must match the COLTYPE_* definitions. ** Adjust the SQLITE_N_STDTYPE value if adding or removing entries. ** ** sqlite3StdType[] The actual names of the datatypes. ** ** sqlite3StdTypeLen[] The length (in bytes) of each entry ** in sqlite3StdType[]. ** ** sqlite3StdTypeAffinity[] The affinity associated with each entry ** in sqlite3StdType[]. ** ** sqlite3StdTypeMap[] The type value (as returned from ** sqlite3_column_type() or sqlite3_value_type()) ** for each entry in sqlite3StdType[]. */ const unsigned char sqlite3StdTypeLen[] = { 3, 4, 3, 7, 4, 4 }; const char sqlite3StdTypeAffinity[] = { SQLITE_AFF_NUMERIC, SQLITE_AFF_BLOB, SQLITE_AFF_INTEGER, SQLITE_AFF_INTEGER, SQLITE_AFF_REAL, SQLITE_AFF_TEXT }; const char sqlite3StdTypeMap[] = { 0, SQLITE_BLOB, SQLITE_INTEGER, SQLITE_INTEGER, SQLITE_FLOAT, SQLITE_TEXT }; const char *sqlite3StdType[] = { "ANY", "BLOB", "INT", "INTEGER", "REAL", "TEXT" }; |
Changes to src/hash.c.
︙ | ︙ | |||
146 147 148 149 150 151 152 | */ static HashElem *findElementWithHash( const Hash *pH, /* The pH to be searched */ const char *pKey, /* The key we are searching for */ unsigned int *pHash /* Write the hash value here */ ){ HashElem *elem; /* Used to loop thru the element list */ | | | 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 | */ static HashElem *findElementWithHash( const Hash *pH, /* The pH to be searched */ const char *pKey, /* The key we are searching for */ unsigned int *pHash /* Write the hash value here */ ){ HashElem *elem; /* Used to loop thru the element list */ unsigned int count; /* Number of elements left to test */ unsigned int h; /* The computed hash */ static HashElem nullElement = { 0, 0, 0, 0 }; if( pH->ht ){ /*OPTIMIZATION-IF-TRUE*/ struct _ht *pEntry; h = strHash(pKey) % pH->htsize; pEntry = &pH->ht[h]; |
︙ | ︙ | |||
194 195 196 197 198 199 200 | elem->next->prev = elem->prev; } if( pH->ht ){ pEntry = &pH->ht[h]; if( pEntry->chain==elem ){ pEntry->chain = elem->next; } | | | | 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 | elem->next->prev = elem->prev; } if( pH->ht ){ pEntry = &pH->ht[h]; if( pEntry->chain==elem ){ pEntry->chain = elem->next; } assert( pEntry->count>0 ); pEntry->count--; } sqlite3_free( elem ); pH->count--; if( pH->count==0 ){ assert( pH->first==0 ); assert( pH->count==0 ); sqlite3HashClear(pH); |
︙ | ︙ |
Changes to src/hash.h.
︙ | ︙ | |||
41 42 43 44 45 46 47 | ** the hash table. */ struct Hash { unsigned int htsize; /* Number of buckets in the hash table */ unsigned int count; /* Number of entries in this table */ HashElem *first; /* The first element of the array */ struct _ht { /* the hash table */ | | | 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | ** the hash table. */ struct Hash { unsigned int htsize; /* Number of buckets in the hash table */ unsigned int count; /* Number of entries in this table */ HashElem *first; /* The first element of the array */ struct _ht { /* the hash table */ unsigned int count; /* Number of entries with this hash */ HashElem *chain; /* Pointer to first entry with this hash */ } *ht; }; /* Each element in the hash table is an instance of the following ** structure. All elements are stored on a single doubly-linked list. ** |
︙ | ︙ | |||
87 88 89 90 91 92 93 | #define sqliteHashData(E) ((E)->data) /* #define sqliteHashKey(E) ((E)->pKey) // NOT USED */ /* #define sqliteHashKeysize(E) ((E)->nKey) // NOT USED */ /* ** Number of entries in a hash table */ | | | 87 88 89 90 91 92 93 94 95 96 | #define sqliteHashData(E) ((E)->data) /* #define sqliteHashKey(E) ((E)->pKey) // NOT USED */ /* #define sqliteHashKeysize(E) ((E)->nKey) // NOT USED */ /* ** Number of entries in a hash table */ #define sqliteHashCount(H) ((H)->count) #endif /* SQLITE_HASH_H */ |
Changes to src/hwtime.h.
1 2 3 4 5 6 7 8 9 10 11 12 13 | /* ** 2008 May 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 contains inline asm code for retrieving "high-performance" | | > | | | | < < > | > | | | < | 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 | /* ** 2008 May 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 contains inline asm code for retrieving "high-performance" ** counters for x86 and x86_64 class CPUs. */ #ifndef SQLITE_HWTIME_H #define SQLITE_HWTIME_H /* ** The following routine only works on pentium-class (or newer) processors. ** It uses the RDTSC opcode to read the cycle count value out of the ** processor and returns that value. This can be used for high-res ** profiling. */ #if !defined(__STRICT_ANSI__) && \ (defined(__GNUC__) || defined(_MSC_VER)) && \ (defined(i386) || defined(__i386__) || defined(_M_IX86)) #if defined(__GNUC__) __inline__ sqlite_uint64 sqlite3Hwtime(void){ unsigned int lo, hi; __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi)); return (sqlite_uint64)hi << 32 | lo; } #elif defined(_MSC_VER) __declspec(naked) __inline sqlite_uint64 __cdecl sqlite3Hwtime(void){ __asm { rdtsc ret ; return value at EDX:EAX } } #endif #elif !defined(__STRICT_ANSI__) && (defined(__GNUC__) && defined(__x86_64__)) __inline__ sqlite_uint64 sqlite3Hwtime(void){ unsigned long val; __asm__ __volatile__ ("rdtsc" : "=A" (val)); return val; } #elif !defined(__STRICT_ANSI__) && (defined(__GNUC__) && defined(__ppc__)) __inline__ sqlite_uint64 sqlite3Hwtime(void){ unsigned long long retval; unsigned long junk; __asm__ __volatile__ ("\n\ 1: mftbu %1\n\ mftb %L0\n\ mftbu %0\n\ cmpw %0,%1\n\ bne 1b" : "=r" (retval), "=r" (junk)); return retval; } #else /* ** asm() is needed for hardware timing support. Without asm(), ** disable the sqlite3Hwtime() routine. ** ** sqlite3Hwtime() is only used for some obscure debugging ** and analysis configurations, not in any deliverable, so this ** should not be a great loss. */ sqlite_uint64 sqlite3Hwtime(void){ return ((sqlite_uint64)0); } #endif #endif /* !defined(SQLITE_HWTIME_H) */ |
Changes to src/insert.c.
︙ | ︙ | |||
28 29 30 31 32 33 34 | int iCur, /* The cursor number of the table */ int iDb, /* The database index in sqlite3.aDb[] */ Table *pTab, /* The table to be opened */ int opcode /* OP_OpenRead or OP_OpenWrite */ ){ Vdbe *v; assert( !IsVirtual(pTab) ); | > | | | 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | int iCur, /* The cursor number of the table */ int iDb, /* The database index in sqlite3.aDb[] */ Table *pTab, /* The table to be opened */ int opcode /* OP_OpenRead or OP_OpenWrite */ ){ Vdbe *v; assert( !IsVirtual(pTab) ); assert( pParse->pVdbe!=0 ); v = pParse->pVdbe; assert( opcode==OP_OpenWrite || opcode==OP_OpenRead ); sqlite3TableLock(pParse, iDb, pTab->tnum, (opcode==OP_OpenWrite)?1:0, pTab->zName); if( HasRowid(pTab) ){ sqlite3VdbeAddOp4Int(v, opcode, iCur, pTab->tnum, iDb, pTab->nNVCol); VdbeComment((v, "%s", pTab->zName)); }else{ Index *pPk = sqlite3PrimaryKeyIndex(pTab); assert( pPk!=0 ); assert( pPk->tnum==pTab->tnum ); sqlite3VdbeAddOp3(v, opcode, iCur, pPk->tnum, iDb); sqlite3VdbeSetP4KeyInfo(pParse, pPk); |
︙ | ︙ | |||
84 85 86 87 88 89 90 91 | pIdx->zColAff = (char *)sqlite3DbMallocRaw(0, pIdx->nColumn+1); if( !pIdx->zColAff ){ sqlite3OomFault(db); return 0; } for(n=0; n<pIdx->nColumn; n++){ i16 x = pIdx->aiColumn[n]; if( x>=0 ){ | > | | < > | > | < > > > > > > | > > | | | | | | | | | > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > | | > > | | > | | > > | 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 | pIdx->zColAff = (char *)sqlite3DbMallocRaw(0, pIdx->nColumn+1); if( !pIdx->zColAff ){ sqlite3OomFault(db); return 0; } for(n=0; n<pIdx->nColumn; n++){ i16 x = pIdx->aiColumn[n]; char aff; if( x>=0 ){ aff = pTab->aCol[x].affinity; }else if( x==XN_ROWID ){ aff = SQLITE_AFF_INTEGER; }else{ assert( x==XN_EXPR ); assert( pIdx->aColExpr!=0 ); aff = sqlite3ExprAffinity(pIdx->aColExpr->a[n].pExpr); } if( aff<SQLITE_AFF_BLOB ) aff = SQLITE_AFF_BLOB; if( aff>SQLITE_AFF_NUMERIC) aff = SQLITE_AFF_NUMERIC; pIdx->zColAff[n] = aff; } pIdx->zColAff[n] = 0; } return pIdx->zColAff; } /* ** Make changes to the evolving bytecode to do affinity transformations ** of values that are about to be gathered into a row for table pTab. ** ** For ordinary (legacy, non-strict) tables: ** ----------------------------------------- ** ** Compute the affinity string for table pTab, if it has not already been ** computed. As an optimization, omit trailing SQLITE_AFF_BLOB affinities. ** ** If the affinity string is empty (because it was all SQLITE_AFF_BLOB entries ** which were then optimized out) then this routine becomes a no-op. ** ** Otherwise if iReg>0 then code an OP_Affinity opcode that will set the ** affinities for register iReg and following. Or if iReg==0, ** then just set the P4 operand of the previous opcode (which should be ** an OP_MakeRecord) to the affinity string. ** ** A column affinity string has one character per column: ** ** Character Column affinity ** --------- --------------- ** 'A' BLOB ** 'B' TEXT ** 'C' NUMERIC ** 'D' INTEGER ** 'E' REAL ** ** For STRICT tables: ** ------------------ ** ** Generate an appropropriate OP_TypeCheck opcode that will verify the ** datatypes against the column definitions in pTab. If iReg==0, that ** means an OP_MakeRecord opcode has already been generated and should be ** the last opcode generated. The new OP_TypeCheck needs to be inserted ** before the OP_MakeRecord. The new OP_TypeCheck should use the same ** register set as the OP_MakeRecord. If iReg>0 then register iReg is ** the first of a series of registers that will form the new record. ** Apply the type checking to that array of registers. */ void sqlite3TableAffinity(Vdbe *v, Table *pTab, int iReg){ int i, j; char *zColAff; if( pTab->tabFlags & TF_Strict ){ if( iReg==0 ){ /* Move the previous opcode (which should be OP_MakeRecord) forward ** by one slot and insert a new OP_TypeCheck where the current ** OP_MakeRecord is found */ VdbeOp *pPrev; sqlite3VdbeAppendP4(v, pTab, P4_TABLE); pPrev = sqlite3VdbeGetOp(v, -1); assert( pPrev!=0 ); assert( pPrev->opcode==OP_MakeRecord || sqlite3VdbeDb(v)->mallocFailed ); pPrev->opcode = OP_TypeCheck; sqlite3VdbeAddOp3(v, OP_MakeRecord, pPrev->p1, pPrev->p2, pPrev->p3); }else{ /* Insert an isolated OP_Typecheck */ sqlite3VdbeAddOp2(v, OP_TypeCheck, iReg, pTab->nNVCol); sqlite3VdbeAppendP4(v, pTab, P4_TABLE); } return; } zColAff = pTab->zColAff; if( zColAff==0 ){ sqlite3 *db = sqlite3VdbeDb(v); zColAff = (char *)sqlite3DbMallocRaw(0, pTab->nCol+1); if( !zColAff ){ sqlite3OomFault(db); return; } for(i=j=0; i<pTab->nCol; i++){ assert( pTab->aCol[i].affinity!=0 ); if( (pTab->aCol[i].colFlags & COLFLAG_VIRTUAL)==0 ){ zColAff[j++] = pTab->aCol[i].affinity; } } do{ zColAff[j--] = 0; }while( j>=0 && zColAff[j]<=SQLITE_AFF_BLOB ); pTab->zColAff = zColAff; } assert( zColAff!=0 ); i = sqlite3Strlen30NN(zColAff); if( i ){ if( iReg ){ sqlite3VdbeAddOp4(v, OP_Affinity, iReg, i, 0, zColAff, i); }else{ assert( sqlite3VdbeGetOp(v, -1)->opcode==OP_MakeRecord || sqlite3VdbeDb(v)->mallocFailed ); sqlite3VdbeChangeP4(v, -1, zColAff, i); } } } /* ** Return non-zero if the table pTab in database iDb or any of its indices |
︙ | ︙ | |||
172 173 174 175 176 177 178 | #endif for(i=1; i<iEnd; i++){ VdbeOp *pOp = sqlite3VdbeGetOp(v, i); assert( pOp!=0 ); if( pOp->opcode==OP_OpenRead && pOp->p3==iDb ){ Index *pIndex; | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | #endif for(i=1; i<iEnd; i++){ VdbeOp *pOp = sqlite3VdbeGetOp(v, i); assert( pOp!=0 ); if( pOp->opcode==OP_OpenRead && pOp->p3==iDb ){ Index *pIndex; Pgno tnum = pOp->p2; if( tnum==pTab->tnum ){ return 1; } for(pIndex=pTab->pIndex; pIndex; pIndex=pIndex->pNext){ if( tnum==pIndex->tnum ){ return 1; } } } #ifndef SQLITE_OMIT_VIRTUALTABLE if( pOp->opcode==OP_VOpen && pOp->p4.pVtab==pVTab ){ assert( pOp->p4.pVtab!=0 ); assert( pOp->p4type==P4_VTAB ); return 1; } #endif } return 0; } /* This walker callback will compute the union of colFlags flags for all ** referenced columns in a CHECK constraint or generated column expression. */ static int exprColumnFlagUnion(Walker *pWalker, Expr *pExpr){ if( pExpr->op==TK_COLUMN && pExpr->iColumn>=0 ){ assert( pExpr->iColumn < pWalker->u.pTab->nCol ); pWalker->eCode |= pWalker->u.pTab->aCol[pExpr->iColumn].colFlags; } return WRC_Continue; } #ifndef SQLITE_OMIT_GENERATED_COLUMNS /* ** All regular columns for table pTab have been puts into registers ** starting with iRegStore. The registers that correspond to STORED ** or VIRTUAL columns have not yet been initialized. This routine goes ** back and computes the values for those columns based on the previously ** computed normal columns. */ void sqlite3ComputeGeneratedColumns( Parse *pParse, /* Parsing context */ int iRegStore, /* Register holding the first column */ Table *pTab /* The table */ ){ int i; Walker w; Column *pRedo; int eProgress; VdbeOp *pOp; assert( pTab->tabFlags & TF_HasGenerated ); testcase( pTab->tabFlags & TF_HasVirtual ); testcase( pTab->tabFlags & TF_HasStored ); /* Before computing generated columns, first go through and make sure ** that appropriate affinity has been applied to the regular columns */ sqlite3TableAffinity(pParse->pVdbe, pTab, iRegStore); if( (pTab->tabFlags & TF_HasStored)!=0 ){ pOp = sqlite3VdbeGetOp(pParse->pVdbe,-1); if( pOp->opcode==OP_Affinity ){ /* Change the OP_Affinity argument to '@' (NONE) for all stored ** columns. '@' is the no-op affinity and those columns have not ** yet been computed. */ int ii, jj; char *zP4 = pOp->p4.z; assert( zP4!=0 ); assert( pOp->p4type==P4_DYNAMIC ); for(ii=jj=0; zP4[jj]; ii++){ if( pTab->aCol[ii].colFlags & COLFLAG_VIRTUAL ){ continue; } if( pTab->aCol[ii].colFlags & COLFLAG_STORED ){ zP4[jj] = SQLITE_AFF_NONE; } jj++; } }else if( pOp->opcode==OP_TypeCheck ){ /* If an OP_TypeCheck was generated because the table is STRICT, ** then set the P3 operand to indicate that generated columns should ** not be checked */ pOp->p3 = 1; } } /* Because there can be multiple generated columns that refer to one another, ** this is a two-pass algorithm. On the first pass, mark all generated ** columns as "not available". */ for(i=0; i<pTab->nCol; i++){ if( pTab->aCol[i].colFlags & COLFLAG_GENERATED ){ testcase( pTab->aCol[i].colFlags & COLFLAG_VIRTUAL ); testcase( pTab->aCol[i].colFlags & COLFLAG_STORED ); pTab->aCol[i].colFlags |= COLFLAG_NOTAVAIL; } } w.u.pTab = pTab; w.xExprCallback = exprColumnFlagUnion; w.xSelectCallback = 0; w.xSelectCallback2 = 0; /* On the second pass, compute the value of each NOT-AVAILABLE column. ** Companion code in the TK_COLUMN case of sqlite3ExprCodeTarget() will ** compute dependencies and mark remove the COLSPAN_NOTAVAIL mark, as ** they are needed. */ pParse->iSelfTab = -iRegStore; do{ eProgress = 0; pRedo = 0; for(i=0; i<pTab->nCol; i++){ Column *pCol = pTab->aCol + i; if( (pCol->colFlags & COLFLAG_NOTAVAIL)!=0 ){ int x; pCol->colFlags |= COLFLAG_BUSY; w.eCode = 0; sqlite3WalkExpr(&w, sqlite3ColumnExpr(pTab, pCol)); pCol->colFlags &= ~COLFLAG_BUSY; if( w.eCode & COLFLAG_NOTAVAIL ){ pRedo = pCol; continue; } eProgress = 1; assert( pCol->colFlags & COLFLAG_GENERATED ); x = sqlite3TableColumnToStorage(pTab, i) + iRegStore; sqlite3ExprCodeGeneratedColumn(pParse, pTab, pCol, x); pCol->colFlags &= ~COLFLAG_NOTAVAIL; } } }while( pRedo && eProgress ); if( pRedo ){ sqlite3ErrorMsg(pParse, "generated column loop on \"%s\"", pRedo->zCnName); } pParse->iSelfTab = 0; } #endif /* SQLITE_OMIT_GENERATED_COLUMNS */ #ifndef SQLITE_OMIT_AUTOINCREMENT /* ** Locate or create an AutoincInfo structure associated with table pTab ** which is in database iDb. Return the register number for the register ** that holds the maximum rowid. Return zero if pTab is not an AUTOINCREMENT ** table. (Also return zero when doing a VACUUM since we do not want to |
︙ | ︙ | |||
236 237 238 239 240 241 242 | Table *pSeqTab = pParse->db->aDb[iDb].pSchema->pSeqTab; /* Verify that the sqlite_sequence table exists and is an ordinary ** rowid table with exactly two columns. ** Ticket d8dc2b3a58cd5dc2918a1d4acb 2018-05-23 */ if( pSeqTab==0 || !HasRowid(pSeqTab) | | > > | | 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 | Table *pSeqTab = pParse->db->aDb[iDb].pSchema->pSeqTab; /* Verify that the sqlite_sequence table exists and is an ordinary ** rowid table with exactly two columns. ** Ticket d8dc2b3a58cd5dc2918a1d4acb 2018-05-23 */ if( pSeqTab==0 || !HasRowid(pSeqTab) || NEVER(IsVirtual(pSeqTab)) || pSeqTab->nCol!=2 ){ pParse->nErr++; pParse->rc = SQLITE_CORRUPT_SEQUENCE; return 0; } pInfo = pToplevel->pAinc; while( pInfo && pInfo->pTab!=pTab ){ pInfo = pInfo->pNext; } if( pInfo==0 ){ pInfo = sqlite3DbMallocRawNN(pParse->db, sizeof(*pInfo)); sqlite3ParserAddCleanup(pToplevel, sqlite3DbFree, pInfo); testcase( pParse->earlyCleanup ); if( pParse->db->mallocFailed ) return 0; pInfo->pNext = pToplevel->pAinc; pToplevel->pAinc = pInfo; pInfo->pTab = pTab; pInfo->iDb = iDb; pToplevel->nMem++; /* Register to hold name of table */ pInfo->regCtr = ++pToplevel->nMem; /* Max rowid register */ pToplevel->nMem +=2; /* Rowid in sqlite_sequence + orig max val */ |
︙ | ︙ | |||
500 501 502 503 504 505 506 | ** end loop ** D: cleanup */ void sqlite3Insert( Parse *pParse, /* Parser context */ SrcList *pTabList, /* Name of table into which we are inserting */ Select *pSelect, /* A SELECT statement to use as the data source */ | | | 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 | ** end loop ** D: cleanup */ void sqlite3Insert( Parse *pParse, /* Parser context */ SrcList *pTabList, /* Name of table into which we are inserting */ Select *pSelect, /* A SELECT statement to use as the data source */ IdList *pColumn, /* Column names corresponding to IDLIST, or NULL. */ int onError, /* How to handle constraint errors */ Upsert *pUpsert /* ON CONFLICT clauses for upsert, or NULL */ ){ sqlite3 *db; /* The main database structure */ Table *pTab; /* The table to insert into. aka TABLE */ int i, j; /* Loop counters */ Vdbe *v; /* Generate code into this virtual machine */ |
︙ | ︙ | |||
525 526 527 528 529 530 531 532 533 534 535 536 537 538 | SelectDest dest; /* Destination for SELECT on rhs of INSERT */ int iDb; /* Index of database holding TABLE */ u8 useTempTable = 0; /* Store SELECT results in intermediate table */ u8 appendFlag = 0; /* True if the insert is likely to be an append */ u8 withoutRowid; /* 0 for normal table. 1 for WITHOUT ROWID table */ u8 bIdListInOrder; /* True if IDLIST is in table order */ ExprList *pList = 0; /* List of VALUES() to be inserted */ /* Register allocations */ int regFromSelect = 0;/* Base register for data coming from SELECT */ int regAutoinc = 0; /* Register holding the AUTOINCREMENT counter */ int regRowCount = 0; /* Memory cell used for the row counter */ int regIns; /* Block of regs holding rowid+data being inserted */ int regRowid; /* registers holding insert rowid */ | > | 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 | SelectDest dest; /* Destination for SELECT on rhs of INSERT */ int iDb; /* Index of database holding TABLE */ u8 useTempTable = 0; /* Store SELECT results in intermediate table */ u8 appendFlag = 0; /* True if the insert is likely to be an append */ u8 withoutRowid; /* 0 for normal table. 1 for WITHOUT ROWID table */ u8 bIdListInOrder; /* True if IDLIST is in table order */ ExprList *pList = 0; /* List of VALUES() to be inserted */ int iRegStore; /* Register in which to store next column */ /* Register allocations */ int regFromSelect = 0;/* Base register for data coming from SELECT */ int regAutoinc = 0; /* Register holding the AUTOINCREMENT counter */ int regRowCount = 0; /* Memory cell used for the row counter */ int regIns; /* Block of regs holding rowid+data being inserted */ int regRowid; /* registers holding insert rowid */ |
︙ | ︙ | |||
578 579 580 581 582 583 584 | withoutRowid = !HasRowid(pTab); /* Figure out if we have any triggers and if the table being ** inserted into is a view */ #ifndef SQLITE_OMIT_TRIGGER pTrigger = sqlite3TriggersExist(pParse, pTab, TK_INSERT, 0, &tmask); | | | 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 | withoutRowid = !HasRowid(pTab); /* Figure out if we have any triggers and if the table being ** inserted into is a view */ #ifndef SQLITE_OMIT_TRIGGER pTrigger = sqlite3TriggersExist(pParse, pTab, TK_INSERT, 0, &tmask); isView = IsView(pTab); #else # define pTrigger 0 # define tmask 0 # define isView 0 #endif #ifdef SQLITE_OMIT_VIEW # undef isView |
︙ | ︙ | |||
632 633 634 635 636 637 638 | #endif /* SQLITE_OMIT_XFER_OPT */ /* If this is an AUTOINCREMENT table, look up the sequence number in the ** sqlite_sequence table and store it in memory cell regAutoinc. */ regAutoinc = autoIncBegin(pParse, iDb, pTab); | | | | > > > > > > > > | | > > > > > > > > | | 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 | #endif /* SQLITE_OMIT_XFER_OPT */ /* If this is an AUTOINCREMENT table, look up the sequence number in the ** sqlite_sequence table and store it in memory cell regAutoinc. */ regAutoinc = autoIncBegin(pParse, iDb, pTab); /* Allocate a block registers to hold the rowid and the values ** for all columns of the new row. */ regRowid = regIns = pParse->nMem+1; pParse->nMem += pTab->nCol + 1; if( IsVirtual(pTab) ){ regRowid++; pParse->nMem++; } regData = regRowid+1; /* If the INSERT statement included an IDLIST term, then make sure ** all elements of the IDLIST really are columns of the table and ** remember the column indices. ** ** If the table has an INTEGER PRIMARY KEY column and that column ** is named in the IDLIST, then record in the ipkColumn variable ** the index into IDLIST of the primary key column. ipkColumn is ** the index of the primary key as it appears in IDLIST, not as ** is appears in the original table. (The index of the INTEGER ** PRIMARY KEY in the original table is pTab->iPKey.) After this ** loop, if ipkColumn==(-1), that means that integer primary key ** is unspecified, and hence the table is either WITHOUT ROWID or ** it will automatically generated an integer primary key. ** ** bIdListInOrder is true if the columns in IDLIST are in storage ** order. This enables an optimization that avoids shuffling the ** columns into storage order. False negatives are harmless, ** but false positives will cause database corruption. */ bIdListInOrder = (pTab->tabFlags & (TF_OOOHidden|TF_HasStored))==0; if( pColumn ){ for(i=0; i<pColumn->nId; i++){ pColumn->a[i].idx = -1; } for(i=0; i<pColumn->nId; i++){ for(j=0; j<pTab->nCol; j++){ if( sqlite3StrICmp(pColumn->a[i].zName, pTab->aCol[j].zCnName)==0 ){ pColumn->a[i].idx = j; if( i!=j ) bIdListInOrder = 0; if( j==pTab->iPKey ){ ipkColumn = i; assert( !withoutRowid ); } #ifndef SQLITE_OMIT_GENERATED_COLUMNS if( pTab->aCol[j].colFlags & (COLFLAG_STORED|COLFLAG_VIRTUAL) ){ sqlite3ErrorMsg(pParse, "cannot INSERT into generated column \"%s\"", pTab->aCol[j].zCnName); goto insert_cleanup; } #endif break; } } if( j>=pTab->nCol ){ if( sqlite3IsRowid(pColumn->a[i].zName) && !withoutRowid ){ ipkColumn = i; bIdListInOrder = 0; }else{ sqlite3ErrorMsg(pParse, "table %S has no column named %s", pTabList->a, pColumn->a[i].zName); pParse->checkSchema = 1; goto insert_cleanup; } } } } |
︙ | ︙ | |||
776 777 778 779 780 781 782 | /* If there is no IDLIST term but the table has an integer primary ** key, the set the ipkColumn variable to the integer primary key ** column index in the original table definition. */ if( pColumn==0 && nColumn>0 ){ ipkColumn = pTab->iPKey; | > > > > > > > > > | | > > > | | | > > > > | | | > | | | | | > > | > > > > > > > > > > > > > > > > | | | | | | > | > > > | 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 | /* If there is no IDLIST term but the table has an integer primary ** key, the set the ipkColumn variable to the integer primary key ** column index in the original table definition. */ if( pColumn==0 && nColumn>0 ){ ipkColumn = pTab->iPKey; #ifndef SQLITE_OMIT_GENERATED_COLUMNS if( ipkColumn>=0 && (pTab->tabFlags & TF_HasGenerated)!=0 ){ testcase( pTab->tabFlags & TF_HasVirtual ); testcase( pTab->tabFlags & TF_HasStored ); for(i=ipkColumn-1; i>=0; i--){ if( pTab->aCol[i].colFlags & COLFLAG_GENERATED ){ testcase( pTab->aCol[i].colFlags & COLFLAG_VIRTUAL ); testcase( pTab->aCol[i].colFlags & COLFLAG_STORED ); ipkColumn--; } } } #endif /* Make sure the number of columns in the source data matches the number ** of columns to be inserted into the table. */ assert( TF_HasHidden==COLFLAG_HIDDEN ); assert( TF_HasGenerated==COLFLAG_GENERATED ); assert( COLFLAG_NOINSERT==(COLFLAG_GENERATED|COLFLAG_HIDDEN) ); if( (pTab->tabFlags & (TF_HasGenerated|TF_HasHidden))!=0 ){ for(i=0; i<pTab->nCol; i++){ if( pTab->aCol[i].colFlags & COLFLAG_NOINSERT ) nHidden++; } } if( nColumn!=(pTab->nCol-nHidden) ){ sqlite3ErrorMsg(pParse, "table %S has %d columns but %d values were supplied", pTabList->a, pTab->nCol-nHidden, nColumn); goto insert_cleanup; } } if( pColumn!=0 && nColumn!=pColumn->nId ){ sqlite3ErrorMsg(pParse, "%d values for %d columns", nColumn, pColumn->nId); goto insert_cleanup; } /* Initialize the count of rows to be inserted */ if( (db->flags & SQLITE_CountRows)!=0 && !pParse->nested && !pParse->pTriggerTab && !pParse->bReturning ){ regRowCount = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_Integer, 0, regRowCount); } /* If this is not a view, open the table and and all indices */ if( !isView ){ int nIdx; nIdx = sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, 0, -1, 0, &iDataCur, &iIdxCur); aRegIdx = sqlite3DbMallocRawNN(db, sizeof(int)*(nIdx+2)); if( aRegIdx==0 ){ goto insert_cleanup; } for(i=0, pIdx=pTab->pIndex; i<nIdx; pIdx=pIdx->pNext, i++){ assert( pIdx ); aRegIdx[i] = ++pParse->nMem; pParse->nMem += pIdx->nColumn; } aRegIdx[i] = ++pParse->nMem; /* Register to store the table record */ } #ifndef SQLITE_OMIT_UPSERT if( pUpsert ){ Upsert *pNx; if( IsVirtual(pTab) ){ sqlite3ErrorMsg(pParse, "UPSERT not implemented for virtual table \"%s\"", pTab->zName); goto insert_cleanup; } if( IsView(pTab) ){ sqlite3ErrorMsg(pParse, "cannot UPSERT a view"); goto insert_cleanup; } if( sqlite3HasExplicitNulls(pParse, pUpsert->pUpsertTarget) ){ goto insert_cleanup; } pTabList->a[0].iCursor = iDataCur; pNx = pUpsert; do{ pNx->pUpsertSrc = pTabList; pNx->regData = regData; pNx->iDataCur = iDataCur; pNx->iIdxCur = iIdxCur; if( pNx->pUpsertTarget ){ if( sqlite3UpsertAnalyzeTarget(pParse, pTabList, pNx) ){ goto insert_cleanup; } } pNx = pNx->pNextUpsert; }while( pNx!=0 ); } #endif /* This is the top of the main insertion loop */ if( useTempTable ){ /* This block codes the top of loop only. The complete loop is the |
︙ | ︙ | |||
856 857 858 859 860 861 862 863 864 | ** following pseudocode (template 3): ** ** C: yield X, at EOF goto D ** insert the select result into <table> from R..R+n ** goto C ** D: ... */ addrInsTop = addrCont = sqlite3VdbeAddOp1(v, OP_Yield, dest.iSDParm); VdbeCoverage(v); | > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | 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 | ** following pseudocode (template 3): ** ** C: yield X, at EOF goto D ** insert the select result into <table> from R..R+n ** goto C ** D: ... */ sqlite3VdbeReleaseRegisters(pParse, regData, pTab->nCol, 0, 0); addrInsTop = addrCont = sqlite3VdbeAddOp1(v, OP_Yield, dest.iSDParm); VdbeCoverage(v); if( ipkColumn>=0 ){ /* tag-20191021-001: If the INTEGER PRIMARY KEY is being generated by the ** SELECT, go ahead and copy the value into the rowid slot now, so that ** the value does not get overwritten by a NULL at tag-20191021-002. */ sqlite3VdbeAddOp2(v, OP_Copy, regFromSelect+ipkColumn, regRowid); } } /* Compute data for ordinary columns of the new entry. Values ** are written in storage order into registers starting with regData. ** Only ordinary columns are computed in this loop. The rowid ** (if there is one) is computed later and generated columns are ** computed after the rowid since they might depend on the value ** of the rowid. */ nHidden = 0; iRegStore = regData; assert( regData==regRowid+1 ); for(i=0; i<pTab->nCol; i++, iRegStore++){ int k; u32 colFlags; assert( i>=nHidden ); if( i==pTab->iPKey ){ /* tag-20191021-002: References to the INTEGER PRIMARY KEY are filled ** using the rowid. So put a NULL in the IPK slot of the record to avoid ** using excess space. The file format definition requires this extra ** NULL - we cannot optimize further by skipping the column completely */ sqlite3VdbeAddOp1(v, OP_SoftNull, iRegStore); continue; } if( ((colFlags = pTab->aCol[i].colFlags) & COLFLAG_NOINSERT)!=0 ){ nHidden++; if( (colFlags & COLFLAG_VIRTUAL)!=0 ){ /* Virtual columns do not participate in OP_MakeRecord. So back up ** iRegStore by one slot to compensate for the iRegStore++ in the ** outer for() loop */ iRegStore--; continue; }else if( (colFlags & COLFLAG_STORED)!=0 ){ /* Stored columns are computed later. But if there are BEFORE ** triggers, the slots used for stored columns will be OP_Copy-ed ** to a second block of registers, so the register needs to be ** initialized to NULL to avoid an uninitialized register read */ if( tmask & TRIGGER_BEFORE ){ sqlite3VdbeAddOp1(v, OP_SoftNull, iRegStore); } continue; }else if( pColumn==0 ){ /* Hidden columns that are not explicitly named in the INSERT ** get there default value */ sqlite3ExprCodeFactorable(pParse, sqlite3ColumnExpr(pTab, &pTab->aCol[i]), iRegStore); continue; } } if( pColumn ){ for(j=0; j<pColumn->nId && pColumn->a[j].idx!=i; j++){} if( j>=pColumn->nId ){ /* A column not named in the insert column list gets its ** default value */ sqlite3ExprCodeFactorable(pParse, sqlite3ColumnExpr(pTab, &pTab->aCol[i]), iRegStore); continue; } k = j; }else if( nColumn==0 ){ /* This is INSERT INTO ... DEFAULT VALUES. Load the default value. */ sqlite3ExprCodeFactorable(pParse, sqlite3ColumnExpr(pTab, &pTab->aCol[i]), iRegStore); continue; }else{ k = i - nHidden; } if( useTempTable ){ sqlite3VdbeAddOp3(v, OP_Column, srcTab, k, iRegStore); }else if( pSelect ){ if( regFromSelect!=regData ){ sqlite3VdbeAddOp2(v, OP_SCopy, regFromSelect+k, iRegStore); } }else{ sqlite3ExprCode(pParse, pList->a[k].pExpr, iRegStore); } } /* Run the BEFORE and INSTEAD OF triggers, if there are any */ endOfLoop = sqlite3VdbeMakeLabel(pParse); if( tmask & TRIGGER_BEFORE ){ int regCols = sqlite3GetTempRange(pParse, pTab->nCol+1); /* build the NEW.* reference row. Note that if there is an INTEGER ** PRIMARY KEY into which a NULL is being inserted, that NULL will be ** translated into a unique ID for the row. But on a BEFORE trigger, ** we do not know what the unique ID will be (because the insert has |
︙ | ︙ | |||
889 890 891 892 893 894 895 | } addr1 = sqlite3VdbeAddOp1(v, OP_NotNull, regCols); VdbeCoverage(v); sqlite3VdbeAddOp2(v, OP_Integer, -1, regCols); sqlite3VdbeJumpHere(v, addr1); sqlite3VdbeAddOp1(v, OP_MustBeInt, regCols); VdbeCoverage(v); } | | < < | > > | < < | | > | < < < | | < | < < < | < < > < < < > | < | < < | > < < > | < | 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 | } addr1 = sqlite3VdbeAddOp1(v, OP_NotNull, regCols); VdbeCoverage(v); sqlite3VdbeAddOp2(v, OP_Integer, -1, regCols); sqlite3VdbeJumpHere(v, addr1); sqlite3VdbeAddOp1(v, OP_MustBeInt, regCols); VdbeCoverage(v); } /* Copy the new data already generated. */ assert( pTab->nNVCol>0 ); sqlite3VdbeAddOp3(v, OP_Copy, regRowid+1, regCols+1, pTab->nNVCol-1); #ifndef SQLITE_OMIT_GENERATED_COLUMNS /* Compute the new value for generated columns after all other ** columns have already been computed. This must be done after ** computing the ROWID in case one of the generated columns ** refers to the ROWID. */ if( pTab->tabFlags & TF_HasGenerated ){ testcase( pTab->tabFlags & TF_HasVirtual ); testcase( pTab->tabFlags & TF_HasStored ); sqlite3ComputeGeneratedColumns(pParse, regCols+1, pTab); } #endif /* If this is an INSERT on a view with an INSTEAD OF INSERT trigger, ** do not attempt any conversions before assembling the record. ** If this is a real table, attempt conversions as required by the ** table column affinities. */ if( !isView ){ sqlite3TableAffinity(v, pTab, regCols+1); } /* Fire BEFORE or INSTEAD OF triggers */ sqlite3CodeRowTrigger(pParse, pTrigger, TK_INSERT, 0, TRIGGER_BEFORE, pTab, regCols-pTab->nCol-1, onError, endOfLoop); sqlite3ReleaseTempRange(pParse, regCols, pTab->nCol+1); } if( !isView ){ if( IsVirtual(pTab) ){ /* The row that the VUpdate opcode will delete: none */ sqlite3VdbeAddOp2(v, OP_Null, 0, regIns); } if( ipkColumn>=0 ){ /* Compute the new rowid */ if( useTempTable ){ sqlite3VdbeAddOp3(v, OP_Column, srcTab, ipkColumn, regRowid); }else if( pSelect ){ /* Rowid already initialized at tag-20191021-001 */ }else{ Expr *pIpk = pList->a[ipkColumn].pExpr; if( pIpk->op==TK_NULL && !IsVirtual(pTab) ){ sqlite3VdbeAddOp3(v, OP_NewRowid, iDataCur, regRowid, regAutoinc); appendFlag = 1; }else{ sqlite3ExprCode(pParse, pList->a[ipkColumn].pExpr, regRowid); } } /* If the PRIMARY KEY expression is NULL, then use OP_NewRowid ** to generate a unique primary key value. */ if( !appendFlag ){ int addr1; |
︙ | ︙ | |||
979 980 981 982 983 984 985 | sqlite3VdbeAddOp2(v, OP_Null, 0, regRowid); }else{ sqlite3VdbeAddOp3(v, OP_NewRowid, iDataCur, regRowid, regAutoinc); appendFlag = 1; } autoIncStep(pParse, regAutoinc, regRowid); | > | | < | < < < | < < < < < < < | < < < < < < < < < < < < | < < < < < | | < < < | | < < > > > > > > > | 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 | sqlite3VdbeAddOp2(v, OP_Null, 0, regRowid); }else{ sqlite3VdbeAddOp3(v, OP_NewRowid, iDataCur, regRowid, regAutoinc); appendFlag = 1; } autoIncStep(pParse, regAutoinc, regRowid); #ifndef SQLITE_OMIT_GENERATED_COLUMNS /* Compute the new value for generated columns after all other ** columns have already been computed. This must be done after ** computing the ROWID in case one of the generated columns ** is derived from the INTEGER PRIMARY KEY. */ if( pTab->tabFlags & TF_HasGenerated ){ sqlite3ComputeGeneratedColumns(pParse, regRowid+1, pTab); } #endif /* Generate code to check constraints and generate index keys and ** do the insertion. */ #ifndef SQLITE_OMIT_VIRTUALTABLE if( IsVirtual(pTab) ){ const char *pVTab = (const char *)sqlite3GetVTable(db, pTab); sqlite3VtabMakeWritable(pParse, pTab); sqlite3VdbeAddOp4(v, OP_VUpdate, 1, pTab->nCol+2, regIns, pVTab, P4_VTAB); sqlite3VdbeChangeP5(v, onError==OE_Default ? OE_Abort : onError); sqlite3MayAbort(pParse); }else #endif { int isReplace = 0;/* Set to true if constraints may cause a replace */ int bUseSeek; /* True to use OPFLAG_SEEKRESULT */ sqlite3GenerateConstraintChecks(pParse, pTab, aRegIdx, iDataCur, iIdxCur, regIns, 0, ipkColumn>=0, onError, endOfLoop, &isReplace, 0, pUpsert ); sqlite3FkCheck(pParse, pTab, 0, regIns, 0, 0); /* Set the OPFLAG_USESEEKRESULT flag if either (a) there are no REPLACE ** constraints or (b) there are no triggers and this table is not a ** parent table in a foreign key constraint. It is safe to set the ** flag in the second case as if any REPLACE constraint is hit, an ** OP_Delete or OP_IdxDelete instruction will be executed on each ** cursor that is disturbed. And these instructions both clear the ** VdbeCursor.seekResult variable, disabling the OPFLAG_USESEEKRESULT ** functionality. */ bUseSeek = (isReplace==0 || !sqlite3VdbeHasSubProgram(v)); sqlite3CompleteInsertion(pParse, pTab, iDataCur, iIdxCur, regIns, aRegIdx, 0, appendFlag, bUseSeek ); } #ifdef SQLITE_ALLOW_ROWID_IN_VIEW }else if( pParse->bReturning ){ /* If there is a RETURNING clause, populate the rowid register with ** constant value -1, in case one or more of the returned expressions ** refer to the "rowid" of the view. */ sqlite3VdbeAddOp2(v, OP_Integer, -1, regRowid); #endif } /* Update the count of rows that are inserted */ if( regRowCount ){ sqlite3VdbeAddOp2(v, OP_AddImm, regRowCount, 1); } |
︙ | ︙ | |||
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 | sqlite3VdbeResolveLabel(v, endOfLoop); if( useTempTable ){ sqlite3VdbeAddOp2(v, OP_Next, srcTab, addrCont); VdbeCoverage(v); sqlite3VdbeJumpHere(v, addrInsTop); sqlite3VdbeAddOp1(v, OP_Close, srcTab); }else if( pSelect ){ sqlite3VdbeGoto(v, addrCont); sqlite3VdbeJumpHere(v, addrInsTop); } insert_end: /* Update the sqlite_sequence table by storing the content of the ** maximum rowid counter values recorded while inserting into ** autoincrement tables. */ if( pParse->nested==0 && pParse->pTriggerTab==0 ){ sqlite3AutoincrementEnd(pParse); } /* ** Return the number of rows inserted. If this routine is ** generating code because of a call to sqlite3NestedParse(), do not ** invoke the callback function. */ if( regRowCount ){ | > > > > > > > > > > > | | 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 | sqlite3VdbeResolveLabel(v, endOfLoop); if( useTempTable ){ sqlite3VdbeAddOp2(v, OP_Next, srcTab, addrCont); VdbeCoverage(v); sqlite3VdbeJumpHere(v, addrInsTop); sqlite3VdbeAddOp1(v, OP_Close, srcTab); }else if( pSelect ){ sqlite3VdbeGoto(v, addrCont); #ifdef SQLITE_DEBUG /* If we are jumping back to an OP_Yield that is preceded by an ** OP_ReleaseReg, set the p5 flag on the OP_Goto so that the ** OP_ReleaseReg will be included in the loop. */ if( sqlite3VdbeGetOp(v, addrCont-1)->opcode==OP_ReleaseReg ){ assert( sqlite3VdbeGetOp(v, addrCont)->opcode==OP_Yield ); sqlite3VdbeChangeP5(v, 1); } #endif sqlite3VdbeJumpHere(v, addrInsTop); } #ifndef SQLITE_OMIT_XFER_OPT insert_end: #endif /* SQLITE_OMIT_XFER_OPT */ /* Update the sqlite_sequence table by storing the content of the ** maximum rowid counter values recorded while inserting into ** autoincrement tables. */ if( pParse->nested==0 && pParse->pTriggerTab==0 ){ sqlite3AutoincrementEnd(pParse); } /* ** Return the number of rows inserted. If this routine is ** generating code because of a call to sqlite3NestedParse(), do not ** invoke the callback function. */ if( regRowCount ){ sqlite3VdbeAddOp2(v, OP_ChngCntRow, regRowCount, 1); sqlite3VdbeSetNumCols(v, 1); sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows inserted", SQLITE_STATIC); } insert_cleanup: sqlite3SrcListDelete(db, pTabList); sqlite3ExprListDelete(db, pList); |
︙ | ︙ | |||
1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 | testcase( w.eCode==0 ); testcase( w.eCode==CKCNSTRNT_COLUMN ); testcase( w.eCode==CKCNSTRNT_ROWID ); testcase( w.eCode==(CKCNSTRNT_ROWID|CKCNSTRNT_COLUMN) ); return w.eCode!=0; } /* ** Generate code to do constraint checks prior to an INSERT or an UPDATE ** on table pTab. ** ** The regNewData parameter is the first register in a range that contains ** the data to be inserted or the data after the update. There will be ** pTab->nCol+1 registers in this range. The first register (the one | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | testcase( w.eCode==0 ); testcase( w.eCode==CKCNSTRNT_COLUMN ); testcase( w.eCode==CKCNSTRNT_ROWID ); testcase( w.eCode==(CKCNSTRNT_ROWID|CKCNSTRNT_COLUMN) ); return w.eCode!=0; } /* ** The sqlite3GenerateConstraintChecks() routine usually wants to visit ** the indexes of a table in the order provided in the Table->pIndex list. ** However, sometimes (rarely - when there is an upsert) it wants to visit ** the indexes in a different order. The following data structures accomplish ** this. ** ** The IndexIterator object is used to walk through all of the indexes ** of a table in either Index.pNext order, or in some other order established ** by an array of IndexListTerm objects. */ typedef struct IndexListTerm IndexListTerm; typedef struct IndexIterator IndexIterator; struct IndexIterator { int eType; /* 0 for Index.pNext list. 1 for an array of IndexListTerm */ int i; /* Index of the current item from the list */ union { struct { /* Use this object for eType==0: A Index.pNext list */ Index *pIdx; /* The current Index */ } lx; struct { /* Use this object for eType==1; Array of IndexListTerm */ int nIdx; /* Size of the array */ IndexListTerm *aIdx; /* Array of IndexListTerms */ } ax; } u; }; /* When IndexIterator.eType==1, then each index is an array of instances ** of the following object */ struct IndexListTerm { Index *p; /* The index */ int ix; /* Which entry in the original Table.pIndex list is this index*/ }; /* Return the first index on the list */ static Index *indexIteratorFirst(IndexIterator *pIter, int *pIx){ assert( pIter->i==0 ); if( pIter->eType ){ *pIx = pIter->u.ax.aIdx[0].ix; return pIter->u.ax.aIdx[0].p; }else{ *pIx = 0; return pIter->u.lx.pIdx; } } /* Return the next index from the list. Return NULL when out of indexes */ static Index *indexIteratorNext(IndexIterator *pIter, int *pIx){ if( pIter->eType ){ int i = ++pIter->i; if( i>=pIter->u.ax.nIdx ){ *pIx = i; return 0; } *pIx = pIter->u.ax.aIdx[i].ix; return pIter->u.ax.aIdx[i].p; }else{ ++(*pIx); pIter->u.lx.pIdx = pIter->u.lx.pIdx->pNext; return pIter->u.lx.pIdx; } } /* ** Generate code to do constraint checks prior to an INSERT or an UPDATE ** on table pTab. ** ** The regNewData parameter is the first register in a range that contains ** the data to be inserted or the data after the update. There will be ** pTab->nCol+1 registers in this range. The first register (the one |
︙ | ︙ | |||
1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 | ** value for either the rowid column or its INTEGER PRIMARY KEY alias. ** ** The code generated by this routine will store new index entries into ** registers identified by aRegIdx[]. No index entry is created for ** indices where aRegIdx[i]==0. The order of indices in aRegIdx[] is ** the same as the order of indices on the linked list of indices ** at pTab->pIndex. ** ** The caller must have already opened writeable cursors on the main ** table and all applicable indices (that is to say, all indices for which ** aRegIdx[] is not zero). iDataCur is the cursor for the main table when ** inserting or updating a rowid table, or the cursor for the PRIMARY KEY ** index when operating on a WITHOUT ROWID table. iIdxCur is the cursor ** for the first index in the pTab->pIndex list. Cursors for other indices | > > > > > > > > | 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 | ** value for either the rowid column or its INTEGER PRIMARY KEY alias. ** ** The code generated by this routine will store new index entries into ** registers identified by aRegIdx[]. No index entry is created for ** indices where aRegIdx[i]==0. The order of indices in aRegIdx[] is ** the same as the order of indices on the linked list of indices ** at pTab->pIndex. ** ** (2019-05-07) The generated code also creates a new record for the ** main table, if pTab is a rowid table, and stores that record in the ** register identified by aRegIdx[nIdx] - in other words in the first ** entry of aRegIdx[] past the last index. It is important that the ** record be generated during constraint checks to avoid affinity changes ** to the register content that occur after constraint checks but before ** the new record is inserted. ** ** The caller must have already opened writeable cursors on the main ** table and all applicable indices (that is to say, all indices for which ** aRegIdx[] is not zero). iDataCur is the cursor for the main table when ** inserting or updating a rowid table, or the cursor for the PRIMARY KEY ** index when operating on a WITHOUT ROWID table. iIdxCur is the cursor ** for the first index in the pTab->pIndex list. Cursors for other indices |
︙ | ︙ | |||
1286 1287 1288 1289 1290 1291 1292 | int ignoreDest, /* Jump to this label on an OE_Ignore resolution */ int *pbMayReplace, /* OUT: Set to true if constraint may cause a replace */ int *aiChng, /* column i is unchanged if aiChng[i]<0 */ Upsert *pUpsert /* ON CONFLICT clauses, if any. NULL otherwise */ ){ Vdbe *v; /* VDBE under constrution */ Index *pIdx; /* Pointer to one of the indices */ | | < | | | | > > > > > > > > | | > > > > > | > > > > > | | | > > > > > | | | | < < | | | | | | > > > > > > | > > | > > > | | > > | > > > > > > > > > > | | | | | | | | | | | | | | > | | | | | < | < | > | | > > > > > > > > > > | < > > > > > > > > | > > | > > | | | | 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 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 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 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 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 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 | int ignoreDest, /* Jump to this label on an OE_Ignore resolution */ int *pbMayReplace, /* OUT: Set to true if constraint may cause a replace */ int *aiChng, /* column i is unchanged if aiChng[i]<0 */ Upsert *pUpsert /* ON CONFLICT clauses, if any. NULL otherwise */ ){ Vdbe *v; /* VDBE under constrution */ Index *pIdx; /* Pointer to one of the indices */ Index *pPk = 0; /* The PRIMARY KEY index for WITHOUT ROWID tables */ sqlite3 *db; /* Database connection */ int i; /* loop counter */ int ix; /* Index loop counter */ int nCol; /* Number of columns */ int onError; /* Conflict resolution strategy */ int seenReplace = 0; /* True if REPLACE is used to resolve INT PK conflict */ int nPkField; /* Number of fields in PRIMARY KEY. 1 for ROWID tables */ Upsert *pUpsertClause = 0; /* The specific ON CONFLICT clause for pIdx */ u8 isUpdate; /* True if this is an UPDATE operation */ u8 bAffinityDone = 0; /* True if the OP_Affinity operation has been run */ int upsertIpkReturn = 0; /* Address of Goto at end of IPK uniqueness check */ int upsertIpkDelay = 0; /* Address of Goto to bypass initial IPK check */ int ipkTop = 0; /* Top of the IPK uniqueness check */ int ipkBottom = 0; /* OP_Goto at the end of the IPK uniqueness check */ /* Variables associated with retesting uniqueness constraints after ** replace triggers fire have run */ int regTrigCnt; /* Register used to count replace trigger invocations */ int addrRecheck = 0; /* Jump here to recheck all uniqueness constraints */ int lblRecheckOk = 0; /* Each recheck jumps to this label if it passes */ Trigger *pTrigger; /* List of DELETE triggers on the table pTab */ int nReplaceTrig = 0; /* Number of replace triggers coded */ IndexIterator sIdxIter; /* Index iterator */ isUpdate = regOldData!=0; db = pParse->db; v = pParse->pVdbe; assert( v!=0 ); assert( !IsView(pTab) ); /* This table is not a VIEW */ nCol = pTab->nCol; /* pPk is the PRIMARY KEY index for WITHOUT ROWID tables and NULL for ** normal rowid tables. nPkField is the number of key fields in the ** pPk index or 1 for a rowid table. In other words, nPkField is the ** number of fields in the true primary key of the table. */ if( HasRowid(pTab) ){ pPk = 0; nPkField = 1; }else{ pPk = sqlite3PrimaryKeyIndex(pTab); nPkField = pPk->nKeyCol; } /* Record that this module has started */ VdbeModuleComment((v, "BEGIN: GenCnstCks(%d,%d,%d,%d,%d)", iDataCur, iIdxCur, regNewData, regOldData, pkChng)); /* Test all NOT NULL constraints. */ if( pTab->tabFlags & TF_HasNotNull ){ int b2ndPass = 0; /* True if currently running 2nd pass */ int nSeenReplace = 0; /* Number of ON CONFLICT REPLACE operations */ int nGenerated = 0; /* Number of generated columns with NOT NULL */ while(1){ /* Make 2 passes over columns. Exit loop via "break" */ for(i=0; i<nCol; i++){ int iReg; /* Register holding column value */ Column *pCol = &pTab->aCol[i]; /* The column to check for NOT NULL */ int isGenerated; /* non-zero if column is generated */ onError = pCol->notNull; if( onError==OE_None ) continue; /* No NOT NULL on this column */ if( i==pTab->iPKey ){ continue; /* ROWID is never NULL */ } isGenerated = pCol->colFlags & COLFLAG_GENERATED; if( isGenerated && !b2ndPass ){ nGenerated++; continue; /* Generated columns processed on 2nd pass */ } if( aiChng && aiChng[i]<0 && !isGenerated ){ /* Do not check NOT NULL on columns that do not change */ continue; } if( overrideError!=OE_Default ){ onError = overrideError; }else if( onError==OE_Default ){ onError = OE_Abort; } if( onError==OE_Replace ){ if( b2ndPass /* REPLACE becomes ABORT on the 2nd pass */ || pCol->iDflt==0 /* REPLACE is ABORT if no DEFAULT value */ ){ testcase( pCol->colFlags & COLFLAG_VIRTUAL ); testcase( pCol->colFlags & COLFLAG_STORED ); testcase( pCol->colFlags & COLFLAG_GENERATED ); onError = OE_Abort; }else{ assert( !isGenerated ); } }else if( b2ndPass && !isGenerated ){ continue; } assert( onError==OE_Rollback || onError==OE_Abort || onError==OE_Fail || onError==OE_Ignore || onError==OE_Replace ); testcase( i!=sqlite3TableColumnToStorage(pTab, i) ); iReg = sqlite3TableColumnToStorage(pTab, i) + regNewData + 1; switch( onError ){ case OE_Replace: { int addr1 = sqlite3VdbeAddOp1(v, OP_NotNull, iReg); VdbeCoverage(v); assert( (pCol->colFlags & COLFLAG_GENERATED)==0 ); nSeenReplace++; sqlite3ExprCodeCopy(pParse, sqlite3ColumnExpr(pTab, pCol), iReg); sqlite3VdbeJumpHere(v, addr1); break; } case OE_Abort: sqlite3MayAbort(pParse); /* no break */ deliberate_fall_through case OE_Rollback: case OE_Fail: { char *zMsg = sqlite3MPrintf(db, "%s.%s", pTab->zName, pCol->zCnName); sqlite3VdbeAddOp3(v, OP_HaltIfNull, SQLITE_CONSTRAINT_NOTNULL, onError, iReg); sqlite3VdbeAppendP4(v, zMsg, P4_DYNAMIC); sqlite3VdbeChangeP5(v, P5_ConstraintNotNull); VdbeCoverage(v); break; } default: { assert( onError==OE_Ignore ); sqlite3VdbeAddOp2(v, OP_IsNull, iReg, ignoreDest); VdbeCoverage(v); break; } } /* end switch(onError) */ } /* end loop i over columns */ if( nGenerated==0 && nSeenReplace==0 ){ /* If there are no generated columns with NOT NULL constraints ** and no NOT NULL ON CONFLICT REPLACE constraints, then a single ** pass is sufficient */ break; } if( b2ndPass ) break; /* Never need more than 2 passes */ b2ndPass = 1; #ifndef SQLITE_OMIT_GENERATED_COLUMNS if( nSeenReplace>0 && (pTab->tabFlags & TF_HasGenerated)!=0 ){ /* If any NOT NULL ON CONFLICT REPLACE constraints fired on the ** first pass, recomputed values for all generated columns, as ** those values might depend on columns affected by the REPLACE. */ sqlite3ComputeGeneratedColumns(pParse, regNewData+1, pTab); } #endif } /* end of 2-pass loop */ } /* end if( has-not-null-constraints ) */ /* Test all CHECK constraints */ #ifndef SQLITE_OMIT_CHECK if( pTab->pCheck && (db->flags & SQLITE_IgnoreChecks)==0 ){ ExprList *pCheck = pTab->pCheck; pParse->iSelfTab = -(regNewData+1); onError = overrideError!=OE_Default ? overrideError : OE_Abort; for(i=0; i<pCheck->nExpr; i++){ int allOk; Expr *pCopy; Expr *pExpr = pCheck->a[i].pExpr; if( aiChng && !sqlite3ExprReferencesUpdatedColumn(pExpr, aiChng, pkChng) ){ /* The check constraints do not reference any of the columns being ** updated so there is no point it verifying the check constraint */ continue; } if( bAffinityDone==0 ){ sqlite3TableAffinity(v, pTab, regNewData+1); bAffinityDone = 1; } allOk = sqlite3VdbeMakeLabel(pParse); sqlite3VdbeVerifyAbortable(v, onError); pCopy = sqlite3ExprDup(db, pExpr, 0); if( !db->mallocFailed ){ sqlite3ExprIfTrue(pParse, pCopy, allOk, SQLITE_JUMPIFNULL); } sqlite3ExprDelete(db, pCopy); if( onError==OE_Ignore ){ sqlite3VdbeGoto(v, ignoreDest); }else{ char *zName = pCheck->a[i].zEName; assert( zName!=0 || pParse->db->mallocFailed ); if( onError==OE_Replace ) onError = OE_Abort; /* IMP: R-26383-51744 */ sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_CHECK, onError, zName, P4_TRANSIENT, P5_ConstraintCheck); } sqlite3VdbeResolveLabel(v, allOk); } pParse->iSelfTab = 0; |
︙ | ︙ | |||
1443 1444 1445 1446 1447 1448 1449 | ** default conflict resolution strategy ** (C) Unique index that do use OE_Replace by default. ** ** The ordering of (2) and (3) is accomplished by making sure the linked ** list of indexes attached to a table puts all OE_Replace indexes last ** in the list. See sqlite3CreateIndex() for where that happens. */ | | > > > > > > | | < | | > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | > > | | > | > | | | > > > > > > > | | 1861 1862 1863 1864 1865 1866 1867 1868 1869 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 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 | ** default conflict resolution strategy ** (C) Unique index that do use OE_Replace by default. ** ** The ordering of (2) and (3) is accomplished by making sure the linked ** list of indexes attached to a table puts all OE_Replace indexes last ** in the list. See sqlite3CreateIndex() for where that happens. */ sIdxIter.eType = 0; sIdxIter.i = 0; sIdxIter.u.ax.aIdx = 0; /* Silence harmless compiler warning */ sIdxIter.u.lx.pIdx = pTab->pIndex; if( pUpsert ){ if( pUpsert->pUpsertTarget==0 ){ /* There is just on ON CONFLICT clause and it has no constraint-target */ assert( pUpsert->pNextUpsert==0 ); if( pUpsert->isDoUpdate==0 ){ /* A single ON CONFLICT DO NOTHING clause, without a constraint-target. ** Make all unique constraint resolution be OE_Ignore */ overrideError = OE_Ignore; pUpsert = 0; }else{ /* A single ON CONFLICT DO UPDATE. Make all resolutions OE_Update */ overrideError = OE_Update; } }else if( pTab->pIndex!=0 ){ /* Otherwise, we'll need to run the IndexListTerm array version of the ** iterator to ensure that all of the ON CONFLICT conditions are ** checked first and in order. */ int nIdx, jj; u64 nByte; Upsert *pTerm; u8 *bUsed; for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdx++){ assert( aRegIdx[nIdx]>0 ); } sIdxIter.eType = 1; sIdxIter.u.ax.nIdx = nIdx; nByte = (sizeof(IndexListTerm)+1)*nIdx + nIdx; sIdxIter.u.ax.aIdx = sqlite3DbMallocZero(db, nByte); if( sIdxIter.u.ax.aIdx==0 ) return; /* OOM */ bUsed = (u8*)&sIdxIter.u.ax.aIdx[nIdx]; pUpsert->pToFree = sIdxIter.u.ax.aIdx; for(i=0, pTerm=pUpsert; pTerm; pTerm=pTerm->pNextUpsert){ if( pTerm->pUpsertTarget==0 ) break; if( pTerm->pUpsertIdx==0 ) continue; /* Skip ON CONFLICT for the IPK */ jj = 0; pIdx = pTab->pIndex; while( ALWAYS(pIdx!=0) && pIdx!=pTerm->pUpsertIdx ){ pIdx = pIdx->pNext; jj++; } if( bUsed[jj] ) continue; /* Duplicate ON CONFLICT clause ignored */ bUsed[jj] = 1; sIdxIter.u.ax.aIdx[i].p = pIdx; sIdxIter.u.ax.aIdx[i].ix = jj; i++; } for(jj=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, jj++){ if( bUsed[jj] ) continue; sIdxIter.u.ax.aIdx[i].p = pIdx; sIdxIter.u.ax.aIdx[i].ix = jj; i++; } assert( i==nIdx ); } } /* Determine if it is possible that triggers (either explicitly coded ** triggers or FK resolution actions) might run as a result of deletes ** that happen when OE_Replace conflict resolution occurs. (Call these ** "replace triggers".) If any replace triggers run, we will need to ** recheck all of the uniqueness constraints after they have all run. ** But on the recheck, the resolution is OE_Abort instead of OE_Replace. ** ** If replace triggers are a possibility, then ** ** (1) Allocate register regTrigCnt and initialize it to zero. ** That register will count the number of replace triggers that ** fire. Constraint recheck only occurs if the number is positive. ** (2) Initialize pTrigger to the list of all DELETE triggers on pTab. ** (3) Initialize addrRecheck and lblRecheckOk ** ** The uniqueness rechecking code will create a series of tests to run ** in a second pass. The addrRecheck and lblRecheckOk variables are ** used to link together these tests which are separated from each other ** in the generate bytecode. */ if( (db->flags & (SQLITE_RecTriggers|SQLITE_ForeignKeys))==0 ){ /* There are not DELETE triggers nor FK constraints. No constraint ** rechecks are needed. */ pTrigger = 0; regTrigCnt = 0; }else{ if( db->flags&SQLITE_RecTriggers ){ pTrigger = sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0, 0); regTrigCnt = pTrigger!=0 || sqlite3FkRequired(pParse, pTab, 0, 0); }else{ pTrigger = 0; regTrigCnt = sqlite3FkRequired(pParse, pTab, 0, 0); } if( regTrigCnt ){ /* Replace triggers might exist. Allocate the counter and ** initialize it to zero. */ regTrigCnt = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_Integer, 0, regTrigCnt); VdbeComment((v, "trigger count")); lblRecheckOk = sqlite3VdbeMakeLabel(pParse); addrRecheck = lblRecheckOk; } } /* If rowid is changing, make sure the new rowid does not previously ** exist in the table. */ if( pkChng && pPk==0 ){ int addrRowidOk = sqlite3VdbeMakeLabel(pParse); /* Figure out what action to take in case of a rowid collision */ onError = pTab->keyConf; if( overrideError!=OE_Default ){ onError = overrideError; }else if( onError==OE_Default ){ onError = OE_Abort; } /* figure out whether or not upsert applies in this case */ if( pUpsert ){ pUpsertClause = sqlite3UpsertOfIndex(pUpsert,0); if( pUpsertClause!=0 ){ if( pUpsertClause->isDoUpdate==0 ){ onError = OE_Ignore; /* DO NOTHING is the same as INSERT OR IGNORE */ }else{ onError = OE_Update; /* DO UPDATE */ } } if( pUpsertClause!=pUpsert ){ /* The first ON CONFLICT clause has a conflict target other than ** the IPK. We have to jump ahead to that first ON CONFLICT clause ** and then come back here and deal with the IPK afterwards */ upsertIpkDelay = sqlite3VdbeAddOp0(v, OP_Goto); } } /* If the response to a rowid conflict is REPLACE but the response ** to some other UNIQUE constraint is FAIL or IGNORE, then we need ** to defer the running of the rowid conflict checking until after ** the UNIQUE constraints have run. */ if( onError==OE_Replace /* IPK rule is REPLACE */ && onError!=overrideError /* Rules for other constraints are different */ && pTab->pIndex /* There exist other constraints */ ){ ipkTop = sqlite3VdbeAddOp0(v, OP_Goto)+1; VdbeComment((v, "defer IPK REPLACE until last")); } if( isUpdate ){ |
︙ | ︙ | |||
1514 1515 1516 1517 1518 1519 1520 | sqlite3VdbeVerifyAbortable(v, onError); sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, addrRowidOk, regNewData); VdbeCoverage(v); switch( onError ){ default: { onError = OE_Abort; | | | 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 | sqlite3VdbeVerifyAbortable(v, onError); sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, addrRowidOk, regNewData); VdbeCoverage(v); switch( onError ){ default: { onError = OE_Abort; /* no break */ deliberate_fall_through } case OE_Rollback: case OE_Abort: case OE_Fail: { testcase( onError==OE_Rollback ); testcase( onError==OE_Abort ); testcase( onError==OE_Fail ); |
︙ | ︙ | |||
1548 1549 1550 1551 1552 1553 1554 | ** but being more selective here allows statements like: ** ** REPLACE INTO t(rowid) VALUES($newrowid) ** ** to run without a statement journal if there are no indexes on the ** table. */ | | < < < < > > | 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 | ** but being more selective here allows statements like: ** ** REPLACE INTO t(rowid) VALUES($newrowid) ** ** to run without a statement journal if there are no indexes on the ** table. */ if( regTrigCnt ){ sqlite3MultiWrite(pParse); sqlite3GenerateRowDelete(pParse, pTab, pTrigger, iDataCur, iIdxCur, regNewData, 1, 0, OE_Replace, 1, -1); sqlite3VdbeAddOp2(v, OP_AddImm, regTrigCnt, 1); /* incr trigger cnt */ nReplaceTrig++; }else{ #ifdef SQLITE_ENABLE_PREUPDATE_HOOK assert( HasRowid(pTab) ); /* This OP_Delete opcode fires the pre-update-hook only. It does ** not modify the b-tree. It is more efficient to let the coming ** OP_Insert replace the existing entry than it is to delete the ** existing entry and then insert a new one. */ |
︙ | ︙ | |||
1577 1578 1579 1580 1581 1582 1583 | } seenReplace = 1; break; } #ifndef SQLITE_OMIT_UPSERT case OE_Update: { sqlite3UpsertDoUpdate(pParse, pUpsert, pTab, 0, iDataCur); | | > > | > | > > > | < | | | < < | > > | | | 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 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 | } seenReplace = 1; break; } #ifndef SQLITE_OMIT_UPSERT case OE_Update: { sqlite3UpsertDoUpdate(pParse, pUpsert, pTab, 0, iDataCur); /* no break */ deliberate_fall_through } #endif case OE_Ignore: { testcase( onError==OE_Ignore ); sqlite3VdbeGoto(v, ignoreDest); break; } } sqlite3VdbeResolveLabel(v, addrRowidOk); if( pUpsert && pUpsertClause!=pUpsert ){ upsertIpkReturn = sqlite3VdbeAddOp0(v, OP_Goto); }else if( ipkTop ){ ipkBottom = sqlite3VdbeAddOp0(v, OP_Goto); sqlite3VdbeJumpHere(v, ipkTop-1); } } /* Test all UNIQUE constraints by creating entries for each UNIQUE ** index and making sure that duplicate entries do not already exist. ** Compute the revised record entries for indices as we go. ** ** This loop also handles the case of the PRIMARY KEY index for a ** WITHOUT ROWID table. */ for(pIdx = indexIteratorFirst(&sIdxIter, &ix); pIdx; pIdx = indexIteratorNext(&sIdxIter, &ix) ){ int regIdx; /* Range of registers hold conent for pIdx */ int regR; /* Range of registers holding conflicting PK */ int iThisCur; /* Cursor for this UNIQUE index */ int addrUniqueOk; /* Jump here if the UNIQUE constraint is satisfied */ int addrConflictCk; /* First opcode in the conflict check logic */ if( aRegIdx[ix]==0 ) continue; /* Skip indices that do not change */ if( pUpsert ){ pUpsertClause = sqlite3UpsertOfIndex(pUpsert, pIdx); if( upsertIpkDelay && pUpsertClause==pUpsert ){ sqlite3VdbeJumpHere(v, upsertIpkDelay); } } addrUniqueOk = sqlite3VdbeMakeLabel(pParse); if( bAffinityDone==0 ){ sqlite3TableAffinity(v, pTab, regNewData+1); bAffinityDone = 1; } VdbeNoopComment((v, "prep index %s", pIdx->zName)); iThisCur = iIdxCur+ix; /* Skip partial indices for which the WHERE clause is not true */ if( pIdx->pPartIdxWhere ){ sqlite3VdbeAddOp2(v, OP_Null, 0, aRegIdx[ix]); pParse->iSelfTab = -(regNewData+1); |
︙ | ︙ | |||
1644 1645 1646 1647 1648 1649 1650 | int iField = pIdx->aiColumn[i]; int x; if( iField==XN_EXPR ){ pParse->iSelfTab = -(regNewData+1); sqlite3ExprCodeCopy(pParse, pIdx->aColExpr->a[i].pExpr, regIdx+i); pParse->iSelfTab = 0; VdbeComment((v, "%s column %d", pIdx->zName, i)); | < | | > > | > | < | | > | > > | 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 | int iField = pIdx->aiColumn[i]; int x; if( iField==XN_EXPR ){ pParse->iSelfTab = -(regNewData+1); sqlite3ExprCodeCopy(pParse, pIdx->aColExpr->a[i].pExpr, regIdx+i); pParse->iSelfTab = 0; VdbeComment((v, "%s column %d", pIdx->zName, i)); }else if( iField==XN_ROWID || iField==pTab->iPKey ){ x = regNewData; sqlite3VdbeAddOp2(v, OP_IntCopy, x, regIdx+i); VdbeComment((v, "rowid")); }else{ testcase( sqlite3TableColumnToStorage(pTab, iField)!=iField ); x = sqlite3TableColumnToStorage(pTab, iField) + regNewData + 1; sqlite3VdbeAddOp2(v, OP_SCopy, x, regIdx+i); VdbeComment((v, "%s", pTab->aCol[iField].zCnName)); } } sqlite3VdbeAddOp3(v, OP_MakeRecord, regIdx, pIdx->nColumn, aRegIdx[ix]); VdbeComment((v, "for %s", pIdx->zName)); #ifdef SQLITE_ENABLE_NULL_TRIM if( pIdx->idxType==SQLITE_IDXTYPE_PRIMARYKEY ){ sqlite3SetMakeRecordP5(v, pIdx->pTable); } #endif sqlite3VdbeReleaseRegisters(pParse, regIdx, pIdx->nColumn, 0, 0); /* In an UPDATE operation, if this index is the PRIMARY KEY index ** of a WITHOUT ROWID table and there has been no change the ** primary key, then no collision is possible. The collision detection ** logic below can all be skipped. */ if( isUpdate && pPk==pIdx && pkChng==0 ){ sqlite3VdbeResolveLabel(v, addrUniqueOk); |
︙ | ︙ | |||
1682 1683 1684 1685 1686 1687 1688 | if( overrideError!=OE_Default ){ onError = overrideError; }else if( onError==OE_Default ){ onError = OE_Abort; } /* Figure out if the upsert clause applies to this index */ | | | | > > > > > | > > | | | | | | 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 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 | if( overrideError!=OE_Default ){ onError = overrideError; }else if( onError==OE_Default ){ onError = OE_Abort; } /* Figure out if the upsert clause applies to this index */ if( pUpsertClause ){ if( pUpsertClause->isDoUpdate==0 ){ onError = OE_Ignore; /* DO NOTHING is the same as INSERT OR IGNORE */ }else{ onError = OE_Update; /* DO UPDATE */ } } /* Collision detection may be omitted if all of the following are true: ** (1) The conflict resolution algorithm is REPLACE ** (2) The table is a WITHOUT ROWID table ** (3) There are no secondary indexes on the table ** (4) No delete triggers need to be fired if there is a conflict ** (5) No FK constraint counters need to be updated if a conflict occurs. ** ** This is not possible for ENABLE_PREUPDATE_HOOK builds, as the row ** must be explicitly deleted in order to ensure any pre-update hook ** is invoked. */ assert( IsOrdinaryTable(pTab) ); #ifndef SQLITE_ENABLE_PREUPDATE_HOOK if( (ix==0 && pIdx->pNext==0) /* Condition 3 */ && pPk==pIdx /* Condition 2 */ && onError==OE_Replace /* Condition 1 */ && ( 0==(db->flags&SQLITE_RecTriggers) || /* Condition 4 */ 0==sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0, 0)) && ( 0==(db->flags&SQLITE_ForeignKeys) || /* Condition 5 */ (0==pTab->u.tab.pFKey && 0==sqlite3FkReferences(pTab))) ){ sqlite3VdbeResolveLabel(v, addrUniqueOk); continue; } #endif /* ifndef SQLITE_ENABLE_PREUPDATE_HOOK */ /* Check to see if the new index entry will be unique */ sqlite3VdbeVerifyAbortable(v, onError); addrConflictCk = sqlite3VdbeAddOp4Int(v, OP_NoConflict, iThisCur, addrUniqueOk, regIdx, pIdx->nKeyCol); VdbeCoverage(v); /* Generate code to handle collisions */ regR = pIdx==pPk ? regIdx : sqlite3GetTempRange(pParse, nPkField); if( isUpdate || onError==OE_Replace ){ if( HasRowid(pTab) ){ sqlite3VdbeAddOp2(v, OP_IdxRowid, iThisCur, regR); /* Conflict only if the rowid of the existing index entry ** is different from old-rowid */ if( isUpdate ){ sqlite3VdbeAddOp3(v, OP_Eq, regR, addrUniqueOk, regOldData); sqlite3VdbeChangeP5(v, SQLITE_NOTNULL); VdbeCoverage(v); } }else{ int x; /* Extract the PRIMARY KEY from the end of the index entry and ** store it in registers regR..regR+nPk-1 */ if( pIdx!=pPk ){ for(i=0; i<pPk->nKeyCol; i++){ assert( pPk->aiColumn[i]>=0 ); x = sqlite3TableColumnToIndex(pIdx, pPk->aiColumn[i]); sqlite3VdbeAddOp3(v, OP_Column, iThisCur, x, regR+i); VdbeComment((v, "%s.%s", pTab->zName, pTab->aCol[pPk->aiColumn[i]].zCnName)); } } if( isUpdate ){ /* If currently processing the PRIMARY KEY of a WITHOUT ROWID ** table, only conflict if the new PRIMARY KEY values are actually ** different from the old. ** |
︙ | ︙ | |||
1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 | char *p4 = (char*)sqlite3LocateCollSeq(pParse, pPk->azColl[i]); x = pPk->aiColumn[i]; assert( x>=0 ); if( i==(pPk->nKeyCol-1) ){ addrJump = addrUniqueOk; op = OP_Eq; } sqlite3VdbeAddOp4(v, op, regOldData+1+x, addrJump, regCmp+i, p4, P4_COLLSEQ ); sqlite3VdbeChangeP5(v, SQLITE_NOTNULL); VdbeCoverageIf(v, op==OP_Eq); VdbeCoverageIf(v, op==OP_Ne); } | > | 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 | char *p4 = (char*)sqlite3LocateCollSeq(pParse, pPk->azColl[i]); x = pPk->aiColumn[i]; assert( x>=0 ); if( i==(pPk->nKeyCol-1) ){ addrJump = addrUniqueOk; op = OP_Eq; } x = sqlite3TableColumnToStorage(pTab, x); sqlite3VdbeAddOp4(v, op, regOldData+1+x, addrJump, regCmp+i, p4, P4_COLLSEQ ); sqlite3VdbeChangeP5(v, SQLITE_NOTNULL); VdbeCoverageIf(v, op==OP_Eq); VdbeCoverageIf(v, op==OP_Ne); } |
︙ | ︙ | |||
1786 1787 1788 1789 1790 1791 1792 | testcase( onError==OE_Fail ); sqlite3UniqueConstraint(pParse, onError, pIdx); break; } #ifndef SQLITE_OMIT_UPSERT case OE_Update: { sqlite3UpsertDoUpdate(pParse, pUpsert, pTab, pIdx, iIdxCur+ix); | | > | > > > > | | > | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > | | | < < | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 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 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 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 | testcase( onError==OE_Fail ); sqlite3UniqueConstraint(pParse, onError, pIdx); break; } #ifndef SQLITE_OMIT_UPSERT case OE_Update: { sqlite3UpsertDoUpdate(pParse, pUpsert, pTab, pIdx, iIdxCur+ix); /* no break */ deliberate_fall_through } #endif case OE_Ignore: { testcase( onError==OE_Ignore ); sqlite3VdbeGoto(v, ignoreDest); break; } default: { int nConflictCk; /* Number of opcodes in conflict check logic */ assert( onError==OE_Replace ); nConflictCk = sqlite3VdbeCurrentAddr(v) - addrConflictCk; assert( nConflictCk>0 || db->mallocFailed ); testcase( nConflictCk<=0 ); testcase( nConflictCk>1 ); if( regTrigCnt ){ sqlite3MultiWrite(pParse); nReplaceTrig++; } if( pTrigger && isUpdate ){ sqlite3VdbeAddOp1(v, OP_CursorLock, iDataCur); } sqlite3GenerateRowDelete(pParse, pTab, pTrigger, iDataCur, iIdxCur, regR, nPkField, 0, OE_Replace, (pIdx==pPk ? ONEPASS_SINGLE : ONEPASS_OFF), iThisCur); if( pTrigger && isUpdate ){ sqlite3VdbeAddOp1(v, OP_CursorUnlock, iDataCur); } if( regTrigCnt ){ int addrBypass; /* Jump destination to bypass recheck logic */ sqlite3VdbeAddOp2(v, OP_AddImm, regTrigCnt, 1); /* incr trigger cnt */ addrBypass = sqlite3VdbeAddOp0(v, OP_Goto); /* Bypass recheck */ VdbeComment((v, "bypass recheck")); /* Here we insert code that will be invoked after all constraint ** checks have run, if and only if one or more replace triggers ** fired. */ sqlite3VdbeResolveLabel(v, lblRecheckOk); lblRecheckOk = sqlite3VdbeMakeLabel(pParse); if( pIdx->pPartIdxWhere ){ /* Bypass the recheck if this partial index is not defined ** for the current row */ sqlite3VdbeAddOp2(v, OP_IsNull, regIdx-1, lblRecheckOk); VdbeCoverage(v); } /* Copy the constraint check code from above, except change ** the constraint-ok jump destination to be the address of ** the next retest block */ while( nConflictCk>0 ){ VdbeOp x; /* Conflict check opcode to copy */ /* The sqlite3VdbeAddOp4() call might reallocate the opcode array. ** Hence, make a complete copy of the opcode, rather than using ** a pointer to the opcode. */ x = *sqlite3VdbeGetOp(v, addrConflictCk); if( x.opcode!=OP_IdxRowid ){ int p2; /* New P2 value for copied conflict check opcode */ const char *zP4; if( sqlite3OpcodeProperty[x.opcode]&OPFLG_JUMP ){ p2 = lblRecheckOk; }else{ p2 = x.p2; } zP4 = x.p4type==P4_INT32 ? SQLITE_INT_TO_PTR(x.p4.i) : x.p4.z; sqlite3VdbeAddOp4(v, x.opcode, x.p1, p2, x.p3, zP4, x.p4type); sqlite3VdbeChangeP5(v, x.p5); VdbeCoverageIf(v, p2!=x.p2); } nConflictCk--; addrConflictCk++; } /* If the retest fails, issue an abort */ sqlite3UniqueConstraint(pParse, OE_Abort, pIdx); sqlite3VdbeJumpHere(v, addrBypass); /* Terminate the recheck bypass */ } seenReplace = 1; break; } } sqlite3VdbeResolveLabel(v, addrUniqueOk); if( regR!=regIdx ) sqlite3ReleaseTempRange(pParse, regR, nPkField); if( pUpsertClause && upsertIpkReturn && sqlite3UpsertNextIsIPK(pUpsertClause) ){ sqlite3VdbeGoto(v, upsertIpkDelay+1); sqlite3VdbeJumpHere(v, upsertIpkReturn); upsertIpkReturn = 0; } } /* If the IPK constraint is a REPLACE, run it last */ if( ipkTop ){ sqlite3VdbeGoto(v, ipkTop); VdbeComment((v, "Do IPK REPLACE")); sqlite3VdbeJumpHere(v, ipkBottom); } /* Recheck all uniqueness constraints after replace triggers have run */ testcase( regTrigCnt!=0 && nReplaceTrig==0 ); assert( regTrigCnt!=0 || nReplaceTrig==0 ); if( nReplaceTrig ){ sqlite3VdbeAddOp2(v, OP_IfNot, regTrigCnt, lblRecheckOk);VdbeCoverage(v); if( !pPk ){ if( isUpdate ){ sqlite3VdbeAddOp3(v, OP_Eq, regNewData, addrRecheck, regOldData); sqlite3VdbeChangeP5(v, SQLITE_NOTNULL); VdbeCoverage(v); } sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, addrRecheck, regNewData); VdbeCoverage(v); sqlite3RowidConstraint(pParse, OE_Abort, pTab); }else{ sqlite3VdbeGoto(v, addrRecheck); } sqlite3VdbeResolveLabel(v, lblRecheckOk); } /* Generate the table record */ if( HasRowid(pTab) ){ int regRec = aRegIdx[ix]; sqlite3VdbeAddOp3(v, OP_MakeRecord, regNewData+1, pTab->nNVCol, regRec); sqlite3SetMakeRecordP5(v, pTab); if( !bAffinityDone ){ sqlite3TableAffinity(v, pTab, 0); } } *pbMayReplace = seenReplace; VdbeModuleComment((v, "END: GenCnstCks(%d)", seenReplace)); } #ifdef SQLITE_ENABLE_NULL_TRIM /* ** Change the P5 operand on the last opcode (which should be an OP_MakeRecord) ** to be the number of columns in table pTab that must not be NULL-trimmed. ** ** Or if no columns of pTab may be NULL-trimmed, leave P5 at zero. */ void sqlite3SetMakeRecordP5(Vdbe *v, Table *pTab){ u16 i; /* Records with omitted columns are only allowed for schema format ** version 2 and later (SQLite version 3.1.4, 2005-02-20). */ if( pTab->pSchema->file_format<2 ) return; for(i=pTab->nCol-1; i>0; i--){ if( pTab->aCol[i].iDflt!=0 ) break; if( pTab->aCol[i].colFlags & COLFLAG_PRIMKEY ) break; } sqlite3VdbeChangeP5(v, i+1); } #endif /* ** Table pTab is a WITHOUT ROWID table that is being written to. The cursor ** number is iCur, and register regData contains the new record for the ** PK index. This function adds code to invoke the pre-update hook, ** if one is registered. */ #ifdef SQLITE_ENABLE_PREUPDATE_HOOK static void codeWithoutRowidPreupdate( Parse *pParse, /* Parse context */ Table *pTab, /* Table being updated */ int iCur, /* Cursor number for table */ int regData /* Data containing new record */ ){ Vdbe *v = pParse->pVdbe; int r = sqlite3GetTempReg(pParse); assert( !HasRowid(pTab) ); assert( 0==(pParse->db->mDbFlags & DBFLAG_Vacuum) || CORRUPT_DB ); sqlite3VdbeAddOp2(v, OP_Integer, 0, r); sqlite3VdbeAddOp4(v, OP_Insert, iCur, regData, r, (char*)pTab, P4_TABLE); sqlite3VdbeChangeP5(v, OPFLAG_ISNOOP); sqlite3ReleaseTempReg(pParse, r); } #else # define codeWithoutRowidPreupdate(a,b,c,d) #endif /* ** This routine generates code to finish the INSERT or UPDATE operation ** that was started by a prior call to sqlite3GenerateConstraintChecks. ** A consecutive range of registers starting at regNewData contains the ** rowid and the content to be inserted. ** ** The arguments to this routine should be the same as the first six |
︙ | ︙ | |||
1875 1876 1877 1878 1879 1880 1881 | int update_flags, /* True for UPDATE, False for INSERT */ int appendBias, /* True if this is likely to be an append */ int useSeekResult /* True to set the USESEEKRESULT flag on OP_[Idx]Insert */ ){ Vdbe *v; /* Prepared statements under construction */ Index *pIdx; /* An index being inserted or updated */ u8 pik_flags; /* flag values passed to the btree insert */ | < < < | | > > > > < < < | < < < < < < < < < < | | 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 | int update_flags, /* True for UPDATE, False for INSERT */ int appendBias, /* True if this is likely to be an append */ int useSeekResult /* True to set the USESEEKRESULT flag on OP_[Idx]Insert */ ){ Vdbe *v; /* Prepared statements under construction */ Index *pIdx; /* An index being inserted or updated */ u8 pik_flags; /* flag values passed to the btree insert */ int i; /* Loop counter */ assert( update_flags==0 || update_flags==OPFLAG_ISUPDATE || update_flags==(OPFLAG_ISUPDATE|OPFLAG_SAVEPOSITION) ); v = pParse->pVdbe; assert( v!=0 ); assert( !IsView(pTab) ); /* This table is not a VIEW */ for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){ /* All REPLACE indexes are at the end of the list */ assert( pIdx->onError!=OE_Replace || pIdx->pNext==0 || pIdx->pNext->onError==OE_Replace ); if( aRegIdx[i]==0 ) continue; if( pIdx->pPartIdxWhere ){ sqlite3VdbeAddOp2(v, OP_IsNull, aRegIdx[i], sqlite3VdbeCurrentAddr(v)+2); VdbeCoverage(v); } pik_flags = (useSeekResult ? OPFLAG_USESEEKRESULT : 0); if( IsPrimaryKeyIndex(pIdx) && !HasRowid(pTab) ){ assert( pParse->nested==0 ); pik_flags |= OPFLAG_NCHANGE; pik_flags |= (update_flags & OPFLAG_SAVEPOSITION); if( update_flags==0 ){ codeWithoutRowidPreupdate(pParse, pTab, iIdxCur+i, aRegIdx[i]); } } sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iIdxCur+i, aRegIdx[i], aRegIdx[i]+1, pIdx->uniqNotNull ? pIdx->nKeyCol: pIdx->nColumn); sqlite3VdbeChangeP5(v, pik_flags); } if( !HasRowid(pTab) ) return; if( pParse->nested ){ pik_flags = 0; }else{ pik_flags = OPFLAG_NCHANGE; pik_flags |= (update_flags?update_flags:OPFLAG_LASTROWID); } if( appendBias ){ pik_flags |= OPFLAG_APPEND; } if( useSeekResult ){ pik_flags |= OPFLAG_USESEEKRESULT; } sqlite3VdbeAddOp3(v, OP_Insert, iDataCur, aRegIdx[i], regNewData); if( !pParse->nested ){ sqlite3VdbeAppendP4(v, pTab, P4_TABLE); } sqlite3VdbeChangeP5(v, pik_flags); } /* |
︙ | ︙ | |||
1982 1983 1984 1985 1986 1987 1988 | Index *pIdx; Vdbe *v; assert( op==OP_OpenRead || op==OP_OpenWrite ); assert( op==OP_OpenWrite || p5==0 ); if( IsVirtual(pTab) ){ /* This routine is a no-op for virtual tables. Leave the output | | | > | | 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 | Index *pIdx; Vdbe *v; assert( op==OP_OpenRead || op==OP_OpenWrite ); assert( op==OP_OpenWrite || p5==0 ); if( IsVirtual(pTab) ){ /* This routine is a no-op for virtual tables. Leave the output ** variables *piDataCur and *piIdxCur set to illegal cursor numbers ** for improved error detection. */ *piDataCur = *piIdxCur = -999; return 0; } iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); v = pParse->pVdbe; assert( v!=0 ); if( iBase<0 ) iBase = pParse->nTab; iDataCur = iBase++; if( piDataCur ) *piDataCur = iDataCur; if( HasRowid(pTab) && (aToOpen==0 || aToOpen[0]) ){ sqlite3OpenTable(pParse, iDataCur, iDb, pTab, op); }else{ |
︙ | ︙ | |||
2044 2045 2046 2047 2048 2049 2050 | ** * The same collating sequence on each column ** * The index has the exact same WHERE clause */ static int xferCompatibleIndex(Index *pDest, Index *pSrc){ int i; assert( pDest && pSrc ); assert( pDest->pTable!=pSrc->pTable ); | | | 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 | ** * The same collating sequence on each column ** * The index has the exact same WHERE clause */ static int xferCompatibleIndex(Index *pDest, Index *pSrc){ int i; assert( pDest && pSrc ); assert( pDest->pTable!=pSrc->pTable ); if( pDest->nKeyCol!=pSrc->nKeyCol || pDest->nColumn!=pSrc->nColumn ){ return 0; /* Different number of columns */ } if( pDest->onError!=pSrc->onError ){ return 0; /* Different conflict resolution strategies */ } for(i=0; i<pSrc->nKeyCol; i++){ if( pSrc->aiColumn[i]!=pDest->aiColumn[i] ){ |
︙ | ︙ | |||
2112 2113 2114 2115 2116 2117 2118 | int onError, /* How to handle constraint errors */ int iDbDest /* The database of pDest */ ){ sqlite3 *db = pParse->db; ExprList *pEList; /* The result set of the SELECT */ Table *pSrc; /* The table in the FROM clause of SELECT */ Index *pSrcIdx, *pDestIdx; /* Source and destination indices */ | | | 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 | int onError, /* How to handle constraint errors */ int iDbDest /* The database of pDest */ ){ sqlite3 *db = pParse->db; ExprList *pEList; /* The result set of the SELECT */ Table *pSrc; /* The table in the FROM clause of SELECT */ Index *pSrcIdx, *pDestIdx; /* Source and destination indices */ SrcItem *pItem; /* An element of pSelect->pSrc */ int i; /* Loop counter */ int iDbSrc; /* The database of pSrc */ int iSrc, iDest; /* Cursors from source and destination */ int addr1, addr2; /* Loop addresses */ int emptyDestTest = 0; /* Address of test for empty pDest */ int emptySrcTest = 0; /* Address of test for empty pSrc */ Vdbe *v; /* The VDBE we are building */ |
︙ | ︙ | |||
2191 2192 2193 2194 2195 2196 2197 | ** we have to check the semantics. */ pItem = pSelect->pSrc->a; pSrc = sqlite3LocateTableItem(pParse, 0, pItem); if( pSrc==0 ){ return 0; /* FROM clause does not contain a real table */ } | | > < | < < < < | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > | > > | > | > | | | > > > > > > > > | | 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 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 2960 2961 2962 | ** we have to check the semantics. */ pItem = pSelect->pSrc->a; pSrc = sqlite3LocateTableItem(pParse, 0, pItem); if( pSrc==0 ){ return 0; /* FROM clause does not contain a real table */ } if( pSrc->tnum==pDest->tnum && pSrc->pSchema==pDest->pSchema ){ testcase( pSrc!=pDest ); /* Possible due to bad sqlite_schema.rootpage */ return 0; /* tab1 and tab2 may not be the same table */ } if( HasRowid(pDest)!=HasRowid(pSrc) ){ return 0; /* source and destination must both be WITHOUT ROWID or not */ } if( !IsOrdinaryTable(pSrc) ){ return 0; /* tab2 may not be a view or virtual table */ } if( pDest->nCol!=pSrc->nCol ){ return 0; /* Number of columns must be the same in tab1 and tab2 */ } if( pDest->iPKey!=pSrc->iPKey ){ return 0; /* Both tables must have the same INTEGER PRIMARY KEY */ } if( (pDest->tabFlags & TF_Strict)!=0 && (pSrc->tabFlags & TF_Strict)==0 ){ return 0; /* Cannot feed from a non-strict into a strict table */ } for(i=0; i<pDest->nCol; i++){ Column *pDestCol = &pDest->aCol[i]; Column *pSrcCol = &pSrc->aCol[i]; #ifdef SQLITE_ENABLE_HIDDEN_COLUMNS if( (db->mDbFlags & DBFLAG_Vacuum)==0 && (pDestCol->colFlags | pSrcCol->colFlags) & COLFLAG_HIDDEN ){ return 0; /* Neither table may have __hidden__ columns */ } #endif #ifndef SQLITE_OMIT_GENERATED_COLUMNS /* Even if tables t1 and t2 have identical schemas, if they contain ** generated columns, then this statement is semantically incorrect: ** ** INSERT INTO t2 SELECT * FROM t1; ** ** The reason is that generated column values are returned by the ** the SELECT statement on the right but the INSERT statement on the ** left wants them to be omitted. ** ** Nevertheless, this is a useful notational shorthand to tell SQLite ** to do a bulk transfer all of the content from t1 over to t2. ** ** We could, in theory, disable this (except for internal use by the ** VACUUM command where it is actually needed). But why do that? It ** seems harmless enough, and provides a useful service. */ if( (pDestCol->colFlags & COLFLAG_GENERATED) != (pSrcCol->colFlags & COLFLAG_GENERATED) ){ return 0; /* Both columns have the same generated-column type */ } /* But the transfer is only allowed if both the source and destination ** tables have the exact same expressions for generated columns. ** This requirement could be relaxed for VIRTUAL columns, I suppose. */ if( (pDestCol->colFlags & COLFLAG_GENERATED)!=0 ){ if( sqlite3ExprCompare(0, sqlite3ColumnExpr(pSrc, pSrcCol), sqlite3ColumnExpr(pDest, pDestCol), -1)!=0 ){ testcase( pDestCol->colFlags & COLFLAG_VIRTUAL ); testcase( pDestCol->colFlags & COLFLAG_STORED ); return 0; /* Different generator expressions */ } } #endif if( pDestCol->affinity!=pSrcCol->affinity ){ return 0; /* Affinity must be the same on all columns */ } if( sqlite3_stricmp(sqlite3ColumnColl(pDestCol), sqlite3ColumnColl(pSrcCol))!=0 ){ return 0; /* Collating sequence must be the same on all columns */ } if( pDestCol->notNull && !pSrcCol->notNull ){ return 0; /* tab2 must be NOT NULL if tab1 is */ } /* Default values for second and subsequent columns need to match. */ if( (pDestCol->colFlags & COLFLAG_GENERATED)==0 && i>0 ){ Expr *pDestExpr = sqlite3ColumnExpr(pDest, pDestCol); Expr *pSrcExpr = sqlite3ColumnExpr(pSrc, pSrcCol); assert( pDestExpr==0 || pDestExpr->op==TK_SPAN ); assert( pDestExpr==0 || !ExprHasProperty(pDestExpr, EP_IntValue) ); assert( pSrcExpr==0 || pSrcExpr->op==TK_SPAN ); assert( pSrcExpr==0 || !ExprHasProperty(pSrcExpr, EP_IntValue) ); if( (pDestExpr==0)!=(pSrcExpr==0) || (pDestExpr!=0 && strcmp(pDestExpr->u.zToken, pSrcExpr->u.zToken)!=0) ){ return 0; /* Default values must be the same for all columns */ } } } for(pDestIdx=pDest->pIndex; pDestIdx; pDestIdx=pDestIdx->pNext){ if( IsUniqueIndex(pDestIdx) ){ destHasUniqueIdx = 1; } for(pSrcIdx=pSrc->pIndex; pSrcIdx; pSrcIdx=pSrcIdx->pNext){ if( xferCompatibleIndex(pDestIdx, pSrcIdx) ) break; } if( pSrcIdx==0 ){ return 0; /* pDestIdx has no corresponding index in pSrc */ } if( pSrcIdx->tnum==pDestIdx->tnum && pSrc->pSchema==pDest->pSchema && sqlite3FaultSim(411)==SQLITE_OK ){ /* The sqlite3FaultSim() call allows this corruption test to be ** bypassed during testing, in order to exercise other corruption tests ** further downstream. */ return 0; /* Corrupt schema - two indexes on the same btree */ } } #ifndef SQLITE_OMIT_CHECK if( pDest->pCheck && sqlite3ExprListCompare(pSrc->pCheck,pDest->pCheck,-1) ){ return 0; /* Tables have different CHECK constraints. Ticket #2252 */ } #endif #ifndef SQLITE_OMIT_FOREIGN_KEY /* Disallow the transfer optimization if the destination table constains ** any foreign key constraints. This is more restrictive than necessary. ** But the main beneficiary of the transfer optimization is the VACUUM ** command, and the VACUUM command disables foreign key constraints. So ** the extra complication to make this rule less restrictive is probably ** not worth the effort. Ticket [6284df89debdfa61db8073e062908af0c9b6118e] */ assert( IsOrdinaryTable(pDest) ); if( (db->flags & SQLITE_ForeignKeys)!=0 && pDest->u.tab.pFKey!=0 ){ return 0; } #endif if( (db->flags & SQLITE_CountRows)!=0 ){ return 0; /* xfer opt does not play well with PRAGMA count_changes */ } |
︙ | ︙ | |||
2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 | iDbSrc = sqlite3SchemaToIndex(db, pSrc->pSchema); v = sqlite3GetVdbe(pParse); sqlite3CodeVerifySchema(pParse, iDbSrc); iSrc = pParse->nTab++; iDest = pParse->nTab++; regAutoinc = autoIncBegin(pParse, iDbDest, pDest); regData = sqlite3GetTempReg(pParse); regRowid = sqlite3GetTempReg(pParse); sqlite3OpenTable(pParse, iDest, iDbDest, pDest, OP_OpenWrite); assert( HasRowid(pDest) || destHasUniqueIdx ); if( (db->mDbFlags & DBFLAG_Vacuum)==0 && ( (pDest->iPKey<0 && pDest->pIndex!=0) /* (1) */ || destHasUniqueIdx /* (2) */ || (onError!=OE_Abort && onError!=OE_Rollback) /* (3) */ | > | 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 | iDbSrc = sqlite3SchemaToIndex(db, pSrc->pSchema); v = sqlite3GetVdbe(pParse); sqlite3CodeVerifySchema(pParse, iDbSrc); iSrc = pParse->nTab++; iDest = pParse->nTab++; regAutoinc = autoIncBegin(pParse, iDbDest, pDest); regData = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp2(v, OP_Null, 0, regData); regRowid = sqlite3GetTempReg(pParse); sqlite3OpenTable(pParse, iDest, iDbDest, pDest, OP_OpenWrite); assert( HasRowid(pDest) || destHasUniqueIdx ); if( (db->mDbFlags & DBFLAG_Vacuum)==0 && ( (pDest->iPKey<0 && pDest->pIndex!=0) /* (1) */ || destHasUniqueIdx /* (2) */ || (onError!=OE_Abort && onError!=OE_Rollback) /* (3) */ |
︙ | ︙ | |||
2323 2324 2325 2326 2327 2328 2329 | } if( HasRowid(pSrc) ){ u8 insFlags; sqlite3OpenTable(pParse, iSrc, iDbSrc, pSrc, OP_OpenRead); emptySrcTest = sqlite3VdbeAddOp2(v, OP_Rewind, iSrc, 0); VdbeCoverage(v); if( pDest->iPKey>=0 ){ addr1 = sqlite3VdbeAddOp2(v, OP_Rowid, iSrc, regRowid); | > | | | | | > | | < | | > > > > > > > > > | > | > > | 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 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 | } if( HasRowid(pSrc) ){ u8 insFlags; sqlite3OpenTable(pParse, iSrc, iDbSrc, pSrc, OP_OpenRead); emptySrcTest = sqlite3VdbeAddOp2(v, OP_Rewind, iSrc, 0); VdbeCoverage(v); if( pDest->iPKey>=0 ){ addr1 = sqlite3VdbeAddOp2(v, OP_Rowid, iSrc, regRowid); if( (db->mDbFlags & DBFLAG_Vacuum)==0 ){ sqlite3VdbeVerifyAbortable(v, onError); addr2 = sqlite3VdbeAddOp3(v, OP_NotExists, iDest, 0, regRowid); VdbeCoverage(v); sqlite3RowidConstraint(pParse, onError, pDest); sqlite3VdbeJumpHere(v, addr2); } autoIncStep(pParse, regAutoinc, regRowid); }else if( pDest->pIndex==0 && !(db->mDbFlags & DBFLAG_VacuumInto) ){ addr1 = sqlite3VdbeAddOp2(v, OP_NewRowid, iDest, regRowid); }else{ addr1 = sqlite3VdbeAddOp2(v, OP_Rowid, iSrc, regRowid); assert( (pDest->tabFlags & TF_Autoincrement)==0 ); } if( db->mDbFlags & DBFLAG_Vacuum ){ sqlite3VdbeAddOp1(v, OP_SeekEnd, iDest); insFlags = OPFLAG_APPEND|OPFLAG_USESEEKRESULT|OPFLAG_PREFORMAT; }else{ insFlags = OPFLAG_NCHANGE|OPFLAG_LASTROWID|OPFLAG_APPEND|OPFLAG_PREFORMAT; } #ifdef SQLITE_ENABLE_PREUPDATE_HOOK if( (db->mDbFlags & DBFLAG_Vacuum)==0 ){ sqlite3VdbeAddOp3(v, OP_RowData, iSrc, regData, 1); insFlags &= ~OPFLAG_PREFORMAT; }else #endif { sqlite3VdbeAddOp3(v, OP_RowCell, iDest, iSrc, regRowid); } sqlite3VdbeAddOp3(v, OP_Insert, iDest, regData, regRowid); if( (db->mDbFlags & DBFLAG_Vacuum)==0 ){ sqlite3VdbeChangeP4(v, -1, (char*)pDest, P4_TABLE); } sqlite3VdbeChangeP5(v, insFlags); sqlite3VdbeAddOp2(v, OP_Next, iSrc, addr1); VdbeCoverage(v); sqlite3VdbeAddOp2(v, OP_Close, iSrc, 0); sqlite3VdbeAddOp2(v, OP_Close, iDest, 0); }else{ sqlite3TableLock(pParse, iDbDest, pDest->tnum, 1, pDest->zName); sqlite3TableLock(pParse, iDbSrc, pSrc->tnum, 0, pSrc->zName); } |
︙ | ︙ | |||
2367 2368 2369 2370 2371 2372 2373 | sqlite3VdbeSetP4KeyInfo(pParse, pSrcIdx); VdbeComment((v, "%s", pSrcIdx->zName)); sqlite3VdbeAddOp3(v, OP_OpenWrite, iDest, pDestIdx->tnum, iDbDest); sqlite3VdbeSetP4KeyInfo(pParse, pDestIdx); sqlite3VdbeChangeP5(v, OPFLAG_BULKCSR); VdbeComment((v, "%s", pDestIdx->zName)); addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iSrc, 0); VdbeCoverage(v); | < | > < | > > > > > > > > > | 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 | sqlite3VdbeSetP4KeyInfo(pParse, pSrcIdx); VdbeComment((v, "%s", pSrcIdx->zName)); sqlite3VdbeAddOp3(v, OP_OpenWrite, iDest, pDestIdx->tnum, iDbDest); sqlite3VdbeSetP4KeyInfo(pParse, pDestIdx); sqlite3VdbeChangeP5(v, OPFLAG_BULKCSR); VdbeComment((v, "%s", pDestIdx->zName)); addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iSrc, 0); VdbeCoverage(v); if( db->mDbFlags & DBFLAG_Vacuum ){ /* This INSERT command is part of a VACUUM operation, which guarantees ** that the destination table is empty. If all indexed columns use ** collation sequence BINARY, then it can also be assumed that the ** index will be populated by inserting keys in strictly sorted ** order. In this case, instead of seeking within the b-tree as part ** of every OP_IdxInsert opcode, an OP_SeekEnd is added before the ** OP_IdxInsert to seek to the point within the b-tree where each key ** should be inserted. This is faster. ** ** If any of the indexed columns use a collation sequence other than ** BINARY, this optimization is disabled. This is because the user ** might change the definition of a collation sequence and then run ** a VACUUM command. In that case keys may not be written in strictly ** sorted order. */ for(i=0; i<pSrcIdx->nColumn; i++){ const char *zColl = pSrcIdx->azColl[i]; if( sqlite3_stricmp(sqlite3StrBINARY, zColl) ) break; } if( i==pSrcIdx->nColumn ){ idxInsFlags = OPFLAG_USESEEKRESULT|OPFLAG_PREFORMAT; sqlite3VdbeAddOp1(v, OP_SeekEnd, iDest); sqlite3VdbeAddOp2(v, OP_RowCell, iDest, iSrc); } }else if( !HasRowid(pSrc) && pDestIdx->idxType==SQLITE_IDXTYPE_PRIMARYKEY ){ idxInsFlags |= OPFLAG_NCHANGE; } if( idxInsFlags!=(OPFLAG_USESEEKRESULT|OPFLAG_PREFORMAT) ){ sqlite3VdbeAddOp3(v, OP_RowData, iSrc, regData, 1); if( (db->mDbFlags & DBFLAG_Vacuum)==0 && !HasRowid(pDest) && IsPrimaryKeyIndex(pDestIdx) ){ codeWithoutRowidPreupdate(pParse, pDest, iDest, regData); } } sqlite3VdbeAddOp2(v, OP_IdxInsert, iDest, regData); sqlite3VdbeChangeP5(v, idxInsFlags|OPFLAG_APPEND); sqlite3VdbeAddOp2(v, OP_Next, iSrc, addr1+1); VdbeCoverage(v); sqlite3VdbeJumpHere(v, addr1); sqlite3VdbeAddOp2(v, OP_Close, iSrc, 0); sqlite3VdbeAddOp2(v, OP_Close, iDest, 0); |
︙ | ︙ |
Changes to src/legacy.c.
︙ | ︙ | |||
42 43 44 45 46 47 48 | if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; if( zSql==0 ) zSql = ""; sqlite3_mutex_enter(db->mutex); sqlite3Error(db, SQLITE_OK); while( rc==SQLITE_OK && zSql[0] ){ | | < < > | 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 | if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; if( zSql==0 ) zSql = ""; sqlite3_mutex_enter(db->mutex); sqlite3Error(db, SQLITE_OK); while( rc==SQLITE_OK && zSql[0] ){ int nCol = 0; 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; continue; } callbackIsInit = 0; while( 1 ){ int i; rc = sqlite3_step(pStmt); /* Invoke the callback function if required */ if( xCallback && (SQLITE_ROW==rc || (SQLITE_DONE==rc && !callbackIsInit && db->flags&SQLITE_NullCallback)) ){ if( !callbackIsInit ){ nCol = sqlite3_column_count(pStmt); azCols = sqlite3DbMallocRaw(db, (2*nCol+1)*sizeof(const char*)); if( azCols==0 ){ goto exec_out; } for(i=0; i<nCol; i++){ azCols[i] = (char *)sqlite3_column_name(pStmt, i); /* sqlite3VdbeSetColName() installs column names as UTF8 |
︙ | ︙ |
Changes to src/loadext.c.
︙ | ︙ | |||
451 452 453 454 455 456 457 | sqlite3_str_errcode, sqlite3_str_length, sqlite3_str_value, /* Version 3.25.0 and later */ sqlite3_create_window_function, /* Version 3.26.0 and later */ #ifdef SQLITE_ENABLE_NORMALIZE | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | sqlite3_str_errcode, sqlite3_str_length, sqlite3_str_value, /* Version 3.25.0 and later */ sqlite3_create_window_function, /* Version 3.26.0 and later */ #ifdef SQLITE_ENABLE_NORMALIZE sqlite3_normalized_sql, #else 0, #endif /* Version 3.28.0 and later */ sqlite3_stmt_isexplain, sqlite3_value_frombind, /* Version 3.30.0 and later */ #ifndef SQLITE_OMIT_VIRTUALTABLE sqlite3_drop_modules, #else 0, #endif /* Version 3.31.0 and later */ sqlite3_hard_heap_limit64, sqlite3_uri_key, sqlite3_filename_database, sqlite3_filename_journal, sqlite3_filename_wal, /* Version 3.32.0 and later */ sqlite3_create_filename, sqlite3_free_filename, sqlite3_database_file_object, /* Version 3.34.0 and later */ sqlite3_txn_state, /* Version 3.36.1 and later */ sqlite3_changes64, sqlite3_total_changes64, /* Version 3.37.0 and later */ sqlite3_autovacuum_pages, }; /* True if x is the directory separator character */ #if SQLITE_OS_WIN # define DirSep(X) ((X)=='/'||(X)=='\\') #else # define DirSep(X) ((X)=='/') #endif /* ** Attempt to load an SQLite extension library contained in the file ** zFile. The entry point is zProc. zProc may be 0 in which case a ** default entry point name (sqlite3_extension_init) is used. Use ** of the default name is recommended. ** |
︙ | ︙ | |||
482 483 484 485 486 487 488 | sqlite3_vfs *pVfs = db->pVfs; void *handle; sqlite3_loadext_entry xInit; char *zErrmsg = 0; const char *zEntry; char *zAltEntry = 0; void **aHandle; | | | 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 | sqlite3_vfs *pVfs = db->pVfs; void *handle; sqlite3_loadext_entry xInit; char *zErrmsg = 0; const char *zEntry; char *zAltEntry = 0; void **aHandle; u64 nMsg = strlen(zFile); int ii; int rc; /* Shared library endings to try if zFile cannot be loaded as written */ static const char *azEndings[] = { #if SQLITE_OS_WIN "dll" |
︙ | ︙ | |||
516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 | *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_BKPT; handle = sqlite3OsDlOpen(pVfs, zAltFile); sqlite3_free(zAltFile); } #endif | > > > > > > | < < < < < < < < < < | 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 | *pzErrMsg = sqlite3_mprintf("not authorized"); } return SQLITE_ERROR; } zEntry = zProc ? zProc : "sqlite3_extension_init"; /* tag-20210611-1. Some dlopen() implementations will segfault if given ** an oversize filename. Most filesystems have a pathname limit of 4K, ** so limit the extension filename length to about twice that. ** https://sqlite.org/forum/forumpost/08a0d6d9bf */ if( nMsg>SQLITE_MAX_PATHLEN ) goto extension_not_found; 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_BKPT; handle = sqlite3OsDlOpen(pVfs, zAltFile); sqlite3_free(zAltFile); } #endif if( handle==0 ) goto extension_not_found; xInit = (sqlite3_loadext_entry)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 ".", |
︙ | ︙ | |||
558 559 560 561 562 563 564 | int ncFile = sqlite3Strlen30(zFile); zAltEntry = sqlite3_malloc64(ncFile+30); if( zAltEntry==0 ){ sqlite3OsDlClose(pVfs, handle); return SQLITE_NOMEM_BKPT; } memcpy(zAltEntry, "sqlite3_", 8); | | | > | | 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 | int ncFile = sqlite3Strlen30(zFile); zAltEntry = sqlite3_malloc64(ncFile+30); if( zAltEntry==0 ){ sqlite3OsDlClose(pVfs, handle); return SQLITE_NOMEM_BKPT; } memcpy(zAltEntry, "sqlite3_", 8); for(iFile=ncFile-1; iFile>=0 && !DirSep(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 = (sqlite3_loadext_entry)sqlite3OsDlSym(pVfs, handle, zEntry); } if( xInit==0 ){ if( pzErrMsg ){ nMsg += strlen(zEntry) + 300; *pzErrMsg = zErrmsg = sqlite3_malloc64(nMsg); if( zErrmsg ){ assert( nMsg<0x7fffffff ); /* zErrmsg would be NULL if not so */ sqlite3_snprintf((int)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; |
︙ | ︙ | |||
609 610 611 612 613 614 615 616 617 618 619 620 621 622 | memcpy(aHandle, db->aExtension, sizeof(handle)*db->nExtension); } sqlite3DbFree(db, db->aExtension); db->aExtension = aHandle; db->aExtension[db->nExtension++] = handle; return SQLITE_OK; } int sqlite3_load_extension( sqlite3 *db, /* Load the extension into this database connection */ const char *zFile, /* Name of the shared library containing extension */ const char *zProc, /* Entry point. Use "sqlite3_extension_init" if 0 */ char **pzErrMsg /* Put error message here if not 0 */ ){ | > > > > > > > > > > > > > | 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 | memcpy(aHandle, db->aExtension, sizeof(handle)*db->nExtension); } sqlite3DbFree(db, db->aExtension); db->aExtension = aHandle; db->aExtension[db->nExtension++] = handle; return SQLITE_OK; extension_not_found: if( pzErrMsg ){ nMsg += 300; *pzErrMsg = zErrmsg = sqlite3_malloc64(nMsg); if( zErrmsg ){ assert( nMsg<0x7fffffff ); /* zErrmsg would be NULL if not so */ sqlite3_snprintf((int)nMsg, zErrmsg, "unable to open shared library [%.*s]", SQLITE_MAX_PATHLEN, zFile); sqlite3OsDlError(pVfs, nMsg-1, zErrmsg); } } return SQLITE_ERROR; } int sqlite3_load_extension( sqlite3 *db, /* Load the extension into this database connection */ const char *zFile, /* Name of the shared library containing extension */ const char *zProc, /* Entry point. Use "sqlite3_extension_init" if 0 */ char **pzErrMsg /* Put error message here if not 0 */ ){ |
︙ | ︙ | |||
658 659 660 661 662 663 664 | #endif /* !defined(SQLITE_OMIT_LOAD_EXTENSION) */ /* ** The following object holds the list of automatically loaded ** extensions. ** | | | 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 | #endif /* !defined(SQLITE_OMIT_LOAD_EXTENSION) */ /* ** The following object holds the list of automatically loaded ** extensions. ** ** This list is shared across threads. The SQLITE_MUTEX_STATIC_MAIN ** mutex must be held while accessing this list. */ typedef struct sqlite3AutoExtList sqlite3AutoExtList; static SQLITE_WSD struct sqlite3AutoExtList { u32 nExt; /* Number of entries in aExt[] */ void (**aExt)(void); /* Pointers to the extension init functions */ } sqlite3Autoext = { 0, 0 }; |
︙ | ︙ | |||
700 701 702 703 704 705 706 | if( rc ){ return rc; }else #endif { u32 i; #if SQLITE_THREADSAFE | | | 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 | if( rc ){ return rc; }else #endif { u32 i; #if SQLITE_THREADSAFE sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN); #endif wsdAutoextInit; sqlite3_mutex_enter(mutex); for(i=0; i<wsdAutoext.nExt; i++){ if( wsdAutoext.aExt[i]==xInit ) break; } if( i==wsdAutoext.nExt ){ |
︙ | ︙ | |||
738 739 740 741 742 743 744 | ** Return 1 if xInit was found on the list and removed. Return 0 if xInit ** was not on the list. */ int sqlite3_cancel_auto_extension( void (*xInit)(void) ){ #if SQLITE_THREADSAFE | | | 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 | ** Return 1 if xInit was found on the list and removed. Return 0 if xInit ** was not on the list. */ int sqlite3_cancel_auto_extension( void (*xInit)(void) ){ #if SQLITE_THREADSAFE sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN); #endif int i; int n = 0; wsdAutoextInit; sqlite3_mutex_enter(mutex); for(i=(int)wsdAutoext.nExt-1; i>=0; i--){ if( wsdAutoext.aExt[i]==xInit ){ |
︙ | ︙ | |||
765 766 767 768 769 770 771 | */ void sqlite3_reset_auto_extension(void){ #ifndef SQLITE_OMIT_AUTOINIT if( sqlite3_initialize()==SQLITE_OK ) #endif { #if SQLITE_THREADSAFE | | | 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 | */ void sqlite3_reset_auto_extension(void){ #ifndef SQLITE_OMIT_AUTOINIT if( sqlite3_initialize()==SQLITE_OK ) #endif { #if SQLITE_THREADSAFE sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN); #endif wsdAutoextInit; sqlite3_mutex_enter(mutex); sqlite3_free(wsdAutoext.aExt); wsdAutoext.aExt = 0; wsdAutoext.nExt = 0; sqlite3_mutex_leave(mutex); |
︙ | ︙ | |||
795 796 797 798 799 800 801 | if( wsdAutoext.nExt==0 ){ /* Common case: early out without every having to acquire a mutex */ return; } for(i=0; go; i++){ char *zErrmsg; #if SQLITE_THREADSAFE | | | 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 | if( wsdAutoext.nExt==0 ){ /* Common case: early out without every having to acquire a mutex */ return; } for(i=0; go; i++){ char *zErrmsg; #if SQLITE_THREADSAFE sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN); #endif #ifdef SQLITE_OMIT_LOAD_EXTENSION const sqlite3_api_routines *pThunk = 0; #else const sqlite3_api_routines *pThunk = &sqlite3Apis; #endif sqlite3_mutex_enter(mutex); |
︙ | ︙ |
Changes to src/main.c.
︙ | ︙ | |||
21 22 23 24 25 26 27 28 29 30 31 32 33 34 | #endif #ifdef SQLITE_ENABLE_RTREE # include "rtree.h" #endif #if defined(SQLITE_ENABLE_ICU) || defined(SQLITE_ENABLE_ICU_COLLATIONS) # include "sqliteicu.h" #endif #ifdef SQLITE_ENABLE_JSON1 int sqlite3Json1Init(sqlite3*); #endif #ifdef SQLITE_ENABLE_STMTVTAB int sqlite3StmtVtabInit(sqlite3*); #endif #ifdef SQLITE_ENABLE_FTS5 | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > | | 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 | #endif #ifdef SQLITE_ENABLE_RTREE # include "rtree.h" #endif #if defined(SQLITE_ENABLE_ICU) || defined(SQLITE_ENABLE_ICU_COLLATIONS) # include "sqliteicu.h" #endif /* ** This is an extension initializer that is a no-op and always ** succeeds, except that it fails if the fault-simulation is set ** to 500. */ static int sqlite3TestExtInit(sqlite3 *db){ (void)db; return sqlite3FaultSim(500); } /* ** Forward declarations of external module initializer functions ** for modules that need them. */ #ifdef SQLITE_ENABLE_FTS1 int sqlite3Fts1Init(sqlite3*); #endif #ifdef SQLITE_ENABLE_FTS2 int sqlite3Fts2Init(sqlite3*); #endif #ifdef SQLITE_ENABLE_FTS5 int sqlite3Fts5Init(sqlite3*); #endif #ifdef SQLITE_ENABLE_JSON1 int sqlite3Json1Init(sqlite3*); #endif #ifdef SQLITE_ENABLE_STMTVTAB int sqlite3StmtVtabInit(sqlite3*); #endif /* ** An array of pointers to extension initializer functions for ** built-in extensions. */ static int (*const sqlite3BuiltinExtensions[])(sqlite3*) = { #ifdef SQLITE_ENABLE_FTS1 sqlite3Fts1Init, #endif #ifdef SQLITE_ENABLE_FTS2 sqlite3Fts2Init, #endif #ifdef SQLITE_ENABLE_FTS3 sqlite3Fts3Init, #endif #ifdef SQLITE_ENABLE_FTS5 sqlite3Fts5Init, #endif #if defined(SQLITE_ENABLE_ICU) || defined(SQLITE_ENABLE_ICU_COLLATIONS) sqlite3IcuInit, #endif #ifdef SQLITE_ENABLE_RTREE sqlite3RtreeInit, #endif #ifdef SQLITE_ENABLE_DBPAGE_VTAB sqlite3DbpageRegister, #endif #ifdef SQLITE_ENABLE_DBSTAT_VTAB sqlite3DbstatRegister, #endif sqlite3TestExtInit, #ifdef SQLITE_ENABLE_JSON1 sqlite3Json1Init, #endif #ifdef SQLITE_ENABLE_STMTVTAB sqlite3StmtVtabInit, #endif #ifdef SQLITE_ENABLE_BYTECODE_VTAB sqlite3VdbeBytecodeVtabInit, #endif }; #ifndef SQLITE_AMALGAMATION /* IMPLEMENTATION-OF: R-46656-45156 The sqlite3_version[] string constant ** contains the text of SQLITE_VERSION macro. */ const char sqlite3_version[] = SQLITE_VERSION; #endif /* IMPLEMENTATION-OF: R-53536-42575 The sqlite3_libversion() function returns ** a pointer to the to the sqlite3_version[] string constant. */ |
︙ | ︙ | |||
134 135 136 137 138 139 140 | ** * Calls to this routine from Y must block until the outer-most ** call by X completes. ** ** * Recursive calls to this routine from thread X return immediately ** without blocking. */ int sqlite3_initialize(void){ | | | 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 | ** * Calls to this routine from Y must block until the outer-most ** call by X completes. ** ** * Recursive calls to this routine from thread X return immediately ** without blocking. */ int sqlite3_initialize(void){ MUTEX_LOGIC( sqlite3_mutex *pMainMtx; ) /* The main static mutex */ int rc; /* Result code */ #ifdef SQLITE_EXTRA_INIT int bRunExtraInit = 0; /* Extra initialization needed */ #endif #ifdef SQLITE_OMIT_WSD rc = sqlite3_wsd_init(4096, 24); |
︙ | ︙ | |||
157 158 159 160 161 162 163 | assert( SQLITE_PTRSIZE==sizeof(char*) ); /* If SQLite is already completely initialized, then this call ** to sqlite3_initialize() should be a no-op. But the initialization ** must be complete. So isInit must not be set until the very end ** of this routine. */ | | > > > | | | | | 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 | assert( SQLITE_PTRSIZE==sizeof(char*) ); /* If SQLite is already completely initialized, then this call ** to sqlite3_initialize() should be a no-op. But the initialization ** must be complete. So isInit must not be set until the very end ** of this routine. */ if( sqlite3GlobalConfig.isInit ){ sqlite3MemoryBarrier(); return SQLITE_OK; } /* Make sure the mutex subsystem is initialized. If unable to ** initialize the mutex subsystem, return early with the error. ** If the system is so sick that we are unable to allocate a mutex, ** there is not much SQLite is going to be able to do. ** ** The mutex subsystem must take care of serializing its own ** initialization. */ rc = sqlite3MutexInit(); if( rc ) return rc; /* Initialize the malloc() system and the recursive pInitMutex mutex. ** This operation is protected by the STATIC_MAIN mutex. Note that ** MutexAlloc() is called for a static mutex prior to initializing the ** malloc subsystem - this implies that the allocation of a static ** mutex must not require support from the malloc subsystem. */ MUTEX_LOGIC( pMainMtx = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN); ) sqlite3_mutex_enter(pMainMtx); sqlite3GlobalConfig.isMutexInit = 1; if( !sqlite3GlobalConfig.isMallocInit ){ rc = sqlite3MallocInit(); } if( rc==SQLITE_OK ){ sqlite3GlobalConfig.isMallocInit = 1; if( !sqlite3GlobalConfig.pInitMutex ){ sqlite3GlobalConfig.pInitMutex = sqlite3MutexAlloc(SQLITE_MUTEX_RECURSIVE); if( sqlite3GlobalConfig.bCoreMutex && !sqlite3GlobalConfig.pInitMutex ){ rc = SQLITE_NOMEM_BKPT; } } } if( rc==SQLITE_OK ){ sqlite3GlobalConfig.nRefInitMutex++; } sqlite3_mutex_leave(pMainMtx); /* If rc is not SQLITE_OK at this point, then either the malloc ** subsystem could not be initialized or the system failed to allocate ** the pInitMutex mutex. Return an error in either case. */ if( rc!=SQLITE_OK ){ return rc; } |
︙ | ︙ | |||
235 236 237 238 239 240 241 | if( sqlite3GlobalConfig.isPCacheInit==0 ){ rc = sqlite3PcacheInitialize(); } if( rc==SQLITE_OK ){ sqlite3GlobalConfig.isPCacheInit = 1; rc = sqlite3OsInit(); } | | > | | | 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 | if( sqlite3GlobalConfig.isPCacheInit==0 ){ rc = sqlite3PcacheInitialize(); } if( rc==SQLITE_OK ){ sqlite3GlobalConfig.isPCacheInit = 1; rc = sqlite3OsInit(); } #ifndef SQLITE_OMIT_DESERIALIZE if( rc==SQLITE_OK ){ rc = sqlite3MemdbInit(); } #endif if( rc==SQLITE_OK ){ sqlite3PCacheBufferSetup( sqlite3GlobalConfig.pPage, sqlite3GlobalConfig.szPage, sqlite3GlobalConfig.nPage); sqlite3MemoryBarrier(); sqlite3GlobalConfig.isInit = 1; #ifdef SQLITE_EXTRA_INIT bRunExtraInit = 1; #endif } sqlite3GlobalConfig.inProgress = 0; } sqlite3_mutex_leave(sqlite3GlobalConfig.pInitMutex); /* Go back under the static mutex and clean up the recursive ** mutex to prevent a resource leak. */ sqlite3_mutex_enter(pMainMtx); sqlite3GlobalConfig.nRefInitMutex--; if( sqlite3GlobalConfig.nRefInitMutex<=0 ){ assert( sqlite3GlobalConfig.nRefInitMutex==0 ); sqlite3_mutex_free(sqlite3GlobalConfig.pInitMutex); sqlite3GlobalConfig.pInitMutex = 0; } sqlite3_mutex_leave(pMainMtx); /* The following is just a sanity check to make sure SQLite has ** been compiled correctly. It is important to run this code, but ** we don't want to run it too often and soak up CPU cycles for no ** reason. So we run it once during initialization. */ #ifndef NDEBUG |
︙ | ︙ | |||
649 650 651 652 653 654 655 656 657 658 659 660 661 662 | iVal = SQLITE_DEFAULT_SORTERREF_SIZE; } sqlite3GlobalConfig.szSorterRef = (u32)iVal; break; } #endif /* SQLITE_ENABLE_SORTER_REFERENCES */ default: { rc = SQLITE_ERROR; break; } } va_end(ap); return rc; | > > > > > > > | 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 | iVal = SQLITE_DEFAULT_SORTERREF_SIZE; } sqlite3GlobalConfig.szSorterRef = (u32)iVal; break; } #endif /* SQLITE_ENABLE_SORTER_REFERENCES */ #ifndef SQLITE_OMIT_DESERIALIZE case SQLITE_CONFIG_MEMDB_MAXSIZE: { sqlite3GlobalConfig.mxMemdbSize = va_arg(ap, sqlite3_int64); break; } #endif /* SQLITE_OMIT_DESERIALIZE */ default: { rc = SQLITE_ERROR; break; } } va_end(ap); return rc; |
︙ | ︙ | |||
672 673 674 675 676 677 678 679 680 681 682 683 684 685 | ** space for the lookaside memory is obtained from sqlite3_malloc(). ** If pStart is not NULL then it is sz*cnt bytes of memory to use for ** the lookaside memory. */ static int setupLookaside(sqlite3 *db, void *pBuf, int sz, int cnt){ #ifndef SQLITE_OMIT_LOOKASIDE void *pStart; if( sqlite3LookasideUsed(db,0)>0 ){ return SQLITE_BUSY; } /* Free any existing lookaside buffer for this handle before ** allocating a new one so we don't have to have space for ** both at the same time. | > > > | 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 | ** space for the lookaside memory is obtained from sqlite3_malloc(). ** If pStart is not NULL then it is sz*cnt bytes of memory to use for ** the lookaside memory. */ static int setupLookaside(sqlite3 *db, void *pBuf, int sz, int cnt){ #ifndef SQLITE_OMIT_LOOKASIDE void *pStart; sqlite3_int64 szAlloc = sz*(sqlite3_int64)cnt; int nBig; /* Number of full-size slots */ int nSm; /* Number smaller LOOKASIDE_SMALL-byte slots */ if( sqlite3LookasideUsed(db,0)>0 ){ return SQLITE_BUSY; } /* Free any existing lookaside buffer for this handle before ** allocating a new one so we don't have to have space for ** both at the same time. |
︙ | ︙ | |||
694 695 696 697 698 699 700 | if( sz<=(int)sizeof(LookasideSlot*) ) sz = 0; if( cnt<0 ) cnt = 0; if( sz==0 || cnt==0 ){ sz = 0; pStart = 0; }else if( pBuf==0 ){ sqlite3BeginBenignMalloc(); | | | > > > > > > > > > > > > > > > > < | > > > > > > > > > > > > > > > > > > > | 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 | if( sz<=(int)sizeof(LookasideSlot*) ) sz = 0; if( cnt<0 ) cnt = 0; if( sz==0 || cnt==0 ){ sz = 0; pStart = 0; }else if( pBuf==0 ){ sqlite3BeginBenignMalloc(); pStart = sqlite3Malloc( szAlloc ); /* IMP: R-61949-35727 */ sqlite3EndBenignMalloc(); if( pStart ) szAlloc = sqlite3MallocSize(pStart); }else{ pStart = pBuf; } #ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE if( sz>=LOOKASIDE_SMALL*3 ){ nBig = szAlloc/(3*LOOKASIDE_SMALL+sz); nSm = (szAlloc - sz*nBig)/LOOKASIDE_SMALL; }else if( sz>=LOOKASIDE_SMALL*2 ){ nBig = szAlloc/(LOOKASIDE_SMALL+sz); nSm = (szAlloc - sz*nBig)/LOOKASIDE_SMALL; }else #endif /* SQLITE_OMIT_TWOSIZE_LOOKASIDE */ if( sz>0 ){ nBig = szAlloc/sz; nSm = 0; }else{ nBig = nSm = 0; } db->lookaside.pStart = pStart; db->lookaside.pInit = 0; db->lookaside.pFree = 0; db->lookaside.sz = (u16)sz; db->lookaside.szTrue = (u16)sz; if( pStart ){ int i; LookasideSlot *p; assert( sz > (int)sizeof(LookasideSlot*) ); p = (LookasideSlot*)pStart; for(i=0; i<nBig; i++){ p->pNext = db->lookaside.pInit; db->lookaside.pInit = p; p = (LookasideSlot*)&((u8*)p)[sz]; } #ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE db->lookaside.pSmallInit = 0; db->lookaside.pSmallFree = 0; db->lookaside.pMiddle = p; for(i=0; i<nSm; i++){ p->pNext = db->lookaside.pSmallInit; db->lookaside.pSmallInit = p; p = (LookasideSlot*)&((u8*)p)[LOOKASIDE_SMALL]; } #endif /* SQLITE_OMIT_TWOSIZE_LOOKASIDE */ assert( ((uptr)p)<=szAlloc + (uptr)pStart ); db->lookaside.pEnd = p; db->lookaside.bDisable = 0; db->lookaside.bMalloced = pBuf==0 ?1:0; db->lookaside.nSlot = nBig+nSm; }else{ db->lookaside.pStart = db; #ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE db->lookaside.pSmallInit = 0; db->lookaside.pSmallFree = 0; db->lookaside.pMiddle = db; #endif /* SQLITE_OMIT_TWOSIZE_LOOKASIDE */ db->lookaside.pEnd = db; db->lookaside.bDisable = 1; db->lookaside.sz = 0; db->lookaside.bMalloced = 0; db->lookaside.nSlot = 0; } assert( sqlite3LookasideUsed(db,0)==0 ); #endif /* SQLITE_OMIT_LOOKASIDE */ return SQLITE_OK; } /* ** Return the mutex associated with a database connection. */ |
︙ | ︙ | |||
782 783 784 785 786 787 788 | #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; #endif sqlite3_mutex_enter(db->mutex); sqlite3BtreeEnterAll(db); for(i=0; rc==SQLITE_OK && i<db->nDb; i++){ Btree *pBt = db->aDb[i].pBt; | | | 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 | #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; #endif sqlite3_mutex_enter(db->mutex); sqlite3BtreeEnterAll(db); for(i=0; rc==SQLITE_OK && i<db->nDb; i++){ Btree *pBt = db->aDb[i].pBt; if( pBt && sqlite3BtreeTxnState(pBt)==SQLITE_TXN_WRITE ){ Pager *pPager = sqlite3BtreePager(pBt); rc = sqlite3PagerFlush(pPager); if( rc==SQLITE_BUSY ){ bSeenBusy = 1; rc = SQLITE_OK; } } |
︙ | ︙ | |||
825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 | default: { static const struct { int op; /* The opcode */ u32 mask; /* Mask of the bit in sqlite3.flags to set/clear */ } aFlagOp[] = { { SQLITE_DBCONFIG_ENABLE_FKEY, SQLITE_ForeignKeys }, { SQLITE_DBCONFIG_ENABLE_TRIGGER, SQLITE_EnableTrigger }, { SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER, SQLITE_Fts3Tokenizer }, { SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION, SQLITE_LoadExtension }, { SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE, SQLITE_NoCkptOnClose }, { SQLITE_DBCONFIG_ENABLE_QPSG, SQLITE_EnableQPSG }, { SQLITE_DBCONFIG_TRIGGER_EQP, SQLITE_TriggerEQP }, { SQLITE_DBCONFIG_RESET_DATABASE, SQLITE_ResetDatabase }, { SQLITE_DBCONFIG_DEFENSIVE, SQLITE_Defensive }, }; unsigned int i; rc = SQLITE_ERROR; /* IMP: R-42790-23372 */ for(i=0; i<ArraySize(aFlagOp); i++){ if( aFlagOp[i].op==op ){ int onoff = va_arg(ap, int); int *pRes = va_arg(ap, int*); | > > > > > > > > | 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 | default: { static const struct { int op; /* The opcode */ u32 mask; /* Mask of the bit in sqlite3.flags to set/clear */ } aFlagOp[] = { { SQLITE_DBCONFIG_ENABLE_FKEY, SQLITE_ForeignKeys }, { SQLITE_DBCONFIG_ENABLE_TRIGGER, SQLITE_EnableTrigger }, { SQLITE_DBCONFIG_ENABLE_VIEW, SQLITE_EnableView }, { SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER, SQLITE_Fts3Tokenizer }, { SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION, SQLITE_LoadExtension }, { SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE, SQLITE_NoCkptOnClose }, { SQLITE_DBCONFIG_ENABLE_QPSG, SQLITE_EnableQPSG }, { SQLITE_DBCONFIG_TRIGGER_EQP, SQLITE_TriggerEQP }, { SQLITE_DBCONFIG_RESET_DATABASE, SQLITE_ResetDatabase }, { SQLITE_DBCONFIG_DEFENSIVE, SQLITE_Defensive }, { SQLITE_DBCONFIG_WRITABLE_SCHEMA, SQLITE_WriteSchema| SQLITE_NoSchemaError }, { SQLITE_DBCONFIG_LEGACY_ALTER_TABLE, SQLITE_LegacyAlter }, { SQLITE_DBCONFIG_DQS_DDL, SQLITE_DqsDDL }, { SQLITE_DBCONFIG_DQS_DML, SQLITE_DqsDML }, { SQLITE_DBCONFIG_LEGACY_FILE_FORMAT, SQLITE_LegacyFileFmt }, { SQLITE_DBCONFIG_TRUSTED_SCHEMA, SQLITE_TrustedSchema }, }; unsigned int i; rc = SQLITE_ERROR; /* IMP: R-42790-23372 */ for(i=0; i<ArraySize(aFlagOp); i++){ if( aFlagOp[i].op==op ){ int onoff = va_arg(ap, int); int *pRes = va_arg(ap, int*); |
︙ | ︙ | |||
862 863 864 865 866 867 868 | break; } } va_end(ap); return rc; } | < < < < < < < < < < < < | > < < < < < < < < < < | | > | | > > > > > > > > > > > > > > | < | | 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 | break; } } va_end(ap); return rc; } /* ** This is the default collating function named "BINARY" which is always ** available. */ static int binCollFunc( void *NotUsed, int nKey1, const void *pKey1, int nKey2, const void *pKey2 ){ int rc, n; UNUSED_PARAMETER(NotUsed); n = nKey1<nKey2 ? nKey1 : nKey2; /* EVIDENCE-OF: R-65033-28449 The built-in BINARY collation compares ** strings byte by byte using the memcmp() function from the standard C ** library. */ assert( pKey1 && pKey2 ); rc = memcmp(pKey1, pKey2, n); if( rc==0 ){ rc = nKey1 - nKey2; } return rc; } /* ** This is the collating function named "RTRIM" which is always ** available. Ignore trailing spaces. */ static int rtrimCollFunc( void *pUser, int nKey1, const void *pKey1, int nKey2, const void *pKey2 ){ const u8 *pK1 = (const u8*)pKey1; const u8 *pK2 = (const u8*)pKey2; while( nKey1 && pK1[nKey1-1]==' ' ) nKey1--; while( nKey2 && pK2[nKey2-1]==' ' ) nKey2--; return binCollFunc(pUser, nKey1, pKey1, nKey2, pKey2); } /* ** Return true if CollSeq is the default built-in BINARY. */ int sqlite3IsBinary(const CollSeq *p){ assert( p==0 || p->xCmp!=binCollFunc || strcmp(p->zName,"BINARY")==0 ); return p==0 || p->xCmp==binCollFunc; } /* ** Another built-in collating sequence: NOCASE. ** ** This collating sequence is intended to be used for "case independent ** comparison". SQLite's knowledge of upper and lower case equivalents |
︙ | ︙ | |||
970 971 972 973 974 975 976 | db->lastRowid = iRowid; sqlite3_mutex_leave(db->mutex); } /* ** Return the number of changes in the most recent call to sqlite3_exec(). */ | | > > > | > > > | 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 | db->lastRowid = iRowid; sqlite3_mutex_leave(db->mutex); } /* ** Return the number of changes in the most recent call to sqlite3_exec(). */ sqlite3_int64 sqlite3_changes64(sqlite3 *db){ #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ){ (void)SQLITE_MISUSE_BKPT; return 0; } #endif return db->nChange; } int sqlite3_changes(sqlite3 *db){ return (int)sqlite3_changes64(db); } /* ** Return the number of changes since the database handle was opened. */ sqlite3_int64 sqlite3_total_changes64(sqlite3 *db){ #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ){ (void)SQLITE_MISUSE_BKPT; return 0; } #endif return db->nTotalChange; } int sqlite3_total_changes(sqlite3 *db){ return (int)sqlite3_total_changes64(db); } /* ** Close all open savepoints. This function only manipulates fields of the ** database handle object, it does not close any savepoints that may be open ** at the b-tree/pager level. */ void sqlite3CloseSavepoints(sqlite3 *db){ |
︙ | ︙ | |||
1016 1017 1018 1019 1020 1021 1022 | /* ** Invoke the destructor function associated with FuncDef p, if any. Except, ** if this is not the last copy of the function, do not invoke it. Multiple ** copies of a single function are created when create_function() is called ** with SQLITE_ANY as the encoding. */ static void functionDestroy(sqlite3 *db, FuncDef *p){ | | > > | 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 | /* ** Invoke the destructor function associated with FuncDef p, if any. Except, ** if this is not the last copy of the function, do not invoke it. Multiple ** copies of a single function are created when create_function() is called ** with SQLITE_ANY as the encoding. */ static void functionDestroy(sqlite3 *db, FuncDef *p){ FuncDestructor *pDestructor; assert( (p->funcFlags & SQLITE_FUNC_BUILTIN)==0 ); pDestructor = p->u.pDestructor; if( pDestructor ){ pDestructor->nRef--; if( pDestructor->nRef==0 ){ pDestructor->xDestroy(pDestructor->pUserData); sqlite3DbFree(db, pDestructor); } } |
︙ | ︙ | |||
1086 1087 1088 1089 1090 1091 1092 | return SQLITE_OK; } if( !sqlite3SafetyCheckSickOrOk(db) ){ return SQLITE_MISUSE_BKPT; } sqlite3_mutex_enter(db->mutex); if( db->mTrace & SQLITE_TRACE_CLOSE ){ | | | 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 | return SQLITE_OK; } if( !sqlite3SafetyCheckSickOrOk(db) ){ return SQLITE_MISUSE_BKPT; } sqlite3_mutex_enter(db->mutex); if( db->mTrace & SQLITE_TRACE_CLOSE ){ db->trace.xV2(SQLITE_TRACE_CLOSE, db->pTraceArg, db, 0); } /* Force xDisconnect calls on all virtual tables */ disconnectAllVtab(db); /* If a transaction is open, the disconnectAllVtab() call above ** will not have called the xDisconnect() method on any virtual |
︙ | ︙ | |||
1120 1121 1122 1123 1124 1125 1126 | /* Closing the handle. Fourth parameter is passed the value 2. */ sqlite3GlobalConfig.xSqllog(sqlite3GlobalConfig.pSqllogArg, db, 0, 2); } #endif /* Convert the connection into a zombie and then close it. */ | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | 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 | /* Closing the handle. Fourth parameter is passed the value 2. */ sqlite3GlobalConfig.xSqllog(sqlite3GlobalConfig.pSqllogArg, db, 0, 2); } #endif /* Convert the connection into a zombie and then close it. */ db->eOpenState = SQLITE_STATE_ZOMBIE; sqlite3LeaveMutexAndCloseZombie(db); return SQLITE_OK; } /* ** Return the transaction state for a single databse, or the maximum ** transaction state over all attached databases if zSchema is null. */ int sqlite3_txn_state(sqlite3 *db, const char *zSchema){ int iDb, nDb; int iTxn = -1; #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ){ (void)SQLITE_MISUSE_BKPT; return -1; } #endif sqlite3_mutex_enter(db->mutex); if( zSchema ){ nDb = iDb = sqlite3FindDbName(db, zSchema); if( iDb<0 ) nDb--; }else{ iDb = 0; nDb = db->nDb-1; } for(; iDb<=nDb; iDb++){ Btree *pBt = db->aDb[iDb].pBt; int x = pBt!=0 ? sqlite3BtreeTxnState(pBt) : SQLITE_TXN_NONE; if( x>iTxn ) iTxn = x; } sqlite3_mutex_leave(db->mutex); return iTxn; } /* ** Two variations on the public interface for closing a database ** connection. The sqlite3_close() version returns SQLITE_BUSY and ** leaves the connection open if there are unfinalized prepared ** statements or unfinished sqlite3_backups. The sqlite3_close_v2() ** version forces the connection to become a zombie if there are ** unclosed resources, and arranges for deallocation when the last ** prepare statement or sqlite3_backup closes. */ int sqlite3_close(sqlite3 *db){ return sqlite3Close(db,0); } int sqlite3_close_v2(sqlite3 *db){ return sqlite3Close(db,1); } |
︙ | ︙ | |||
1154 1155 1156 1157 1158 1159 1160 | HashElem *i; /* Hash table iterator */ int j; /* If there are outstanding sqlite3_stmt or sqlite3_backup objects ** or if the connection has not yet been closed by sqlite3_close_v2(), ** then just leave the mutex and return. */ | | | 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 | HashElem *i; /* Hash table iterator */ int j; /* If there are outstanding sqlite3_stmt or sqlite3_backup objects ** or if the connection has not yet been closed by sqlite3_close_v2(), ** then just leave the mutex and return. */ if( db->eOpenState!=SQLITE_STATE_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, |
︙ | ︙ | |||
1226 1227 1228 1229 1230 1231 1232 | } sqlite3DbFree(db, pColl); } sqlite3HashClear(&db->aCollSeq); #ifndef SQLITE_OMIT_VIRTUALTABLE for(i=sqliteHashFirst(&db->aModule); i; i=sqliteHashNext(i)){ Module *pMod = (Module *)sqliteHashData(i); | < < < | | > > > | | 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 | } sqlite3DbFree(db, pColl); } sqlite3HashClear(&db->aCollSeq); #ifndef SQLITE_OMIT_VIRTUALTABLE for(i=sqliteHashFirst(&db->aModule); i; i=sqliteHashNext(i)){ Module *pMod = (Module *)sqliteHashData(i); sqlite3VtabEponymousTableClear(db, pMod); sqlite3VtabModuleUnref(db, pMod); } sqlite3HashClear(&db->aModule); #endif sqlite3Error(db, SQLITE_OK); /* Deallocates any cached error strings. */ sqlite3ValueFree(db->pErr); sqlite3CloseExtensions(db); #if SQLITE_USER_AUTHENTICATION sqlite3_free(db->auth.zAuthUser); sqlite3_free(db->auth.zAuthPW); #endif db->eOpenState = SQLITE_STATE_ERROR; /* The temp-database schema is allocated differently from the other schema ** objects (using sqliteMalloc() directly, instead of sqlite3BtreeSchema()). ** So it needs to be freed here. Todo: Why not roll the temp schema into ** the same sqliteMalloc() as the one that allocates the database ** structure? */ sqlite3DbFree(db, db->aDb[1].pSchema); if( db->xAutovacDestr ){ db->xAutovacDestr(db->pAutovacPagesArg); } sqlite3_mutex_leave(db->mutex); db->eOpenState = SQLITE_STATE_CLOSED; sqlite3_mutex_free(db->mutex); assert( sqlite3LookasideUsed(db,0)==0 ); if( db->lookaside.bMalloced ){ sqlite3_free(db->lookaside.pStart); } sqlite3_free(db); } |
︙ | ︙ | |||
1288 1289 1290 1291 1292 1293 1294 | ** corruption reports in some cases. */ sqlite3BtreeEnterAll(db); schemaChange = (db->mDbFlags & DBFLAG_SchemaChange)!=0 && db->init.busy==0; for(i=0; i<db->nDb; i++){ Btree *p = db->aDb[i].pBt; if( p ){ | | | | 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 | ** corruption reports in some cases. */ sqlite3BtreeEnterAll(db); schemaChange = (db->mDbFlags & DBFLAG_SchemaChange)!=0 && db->init.busy==0; for(i=0; i<db->nDb; i++){ Btree *p = db->aDb[i].pBt; if( p ){ if( sqlite3BtreeTxnState(p)==SQLITE_TXN_WRITE ){ inTrans = 1; } sqlite3BtreeRollback(p, tripCode, !schemaChange); } } sqlite3VtabRollback(db); sqlite3EndBenignMalloc(); if( schemaChange ){ sqlite3ExpirePreparedStatements(db, 0); sqlite3ResetAllSchemasOfConnection(db); } sqlite3BtreeLeaveAll(db); /* Any deferred constraint violations have now been resolved. */ db->nDeferredCons = 0; db->nDeferredImmCons = 0; db->flags &= ~(u64)(SQLITE_DeferFKs|SQLITE_CorruptRdOnly); /* If one has been configured, invoke the rollback-hook callback */ if( db->xRollbackCallback && (inTrans || !db->autoCommit) ){ db->xRollbackCallback(db->pRollbackArg); } } |
︙ | ︙ | |||
1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 | 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_CANTOPEN_CONVPATH: zName = "SQLITE_CANTOPEN_CONVPATH"; 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; | > | 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 | 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_CANTOPEN_CONVPATH: zName = "SQLITE_CANTOPEN_CONVPATH"; break; case SQLITE_CANTOPEN_SYMLINK: zName = "SQLITE_CANTOPEN_SYMLINK"; 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; |
︙ | ︙ | |||
1501 1502 1503 1504 1505 1506 1507 | ** argument. ** ** Return non-zero to retry the lock. Return zero to stop trying ** and cause SQLite to return SQLITE_BUSY. */ static int sqliteDefaultBusyCallback( void *ptr, /* Database connection */ | | < < < < < < < < < < < < < < < | < < < < < < < < | < | 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 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 | ** argument. ** ** Return non-zero to retry the lock. Return zero to stop trying ** and cause SQLite to return SQLITE_BUSY. */ static int sqliteDefaultBusyCallback( void *ptr, /* Database connection */ int count /* Number of times table has been busy */ ){ #if SQLITE_OS_WIN || HAVE_USLEEP /* This case is for systems that have support for sleeping for fractions of ** a second. Examples: All windows systems, unix systems with usleep() */ static const u8 delays[] = { 1, 2, 5, 10, 15, 20, 25, 25, 25, 50, 50, 100 }; static const u8 totals[] = { 0, 1, 3, 8, 18, 33, 53, 78, 103, 128, 178, 228 }; # define NDELAY ArraySize(delays) sqlite3 *db = (sqlite3 *)ptr; int tmout = db->busyTimeout; int delay, prior; assert( count>=0 ); if( count < NDELAY ){ delay = delays[count]; prior = totals[count]; }else{ delay = delays[NDELAY-1]; prior = totals[NDELAY-1] + delay*(count-(NDELAY-1)); } if( prior + delay > tmout ){ delay = tmout - prior; if( delay<=0 ) return 0; } sqlite3OsSleep(db->pVfs, delay*1000); return 1; #else /* This case for unix systems that lack usleep() support. Sleeping ** must be done in increments of whole seconds */ sqlite3 *db = (sqlite3 *)ptr; int tmout = ((sqlite3 *)ptr)->busyTimeout; if( (count+1)*1000 > tmout ){ return 0; } sqlite3OsSleep(db->pVfs, 1000000); return 1; #endif } /* ** Invoke the given busy handler. ** ** This routine is called when an operation failed to acquire a ** lock on VFS file pFile. ** ** If this routine returns non-zero, the lock is retried. If it ** returns 0, the operation aborts with an SQLITE_BUSY error. */ int sqlite3InvokeBusyHandler(BusyHandler *p){ int rc; if( p->xBusyHandler==0 || p->nBusy<0 ) return 0; rc = p->xBusyHandler(p->pBusyArg, p->nBusy); if( rc==0 ){ p->nBusy = -1; }else{ p->nBusy++; } return rc; } |
︙ | ︙ | |||
1603 1604 1605 1606 1607 1608 1609 | #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; #endif sqlite3_mutex_enter(db->mutex); db->busyHandler.xBusyHandler = xBusy; db->busyHandler.pBusyArg = pArg; db->busyHandler.nBusy = 0; | < | 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 | #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; #endif sqlite3_mutex_enter(db->mutex); db->busyHandler.xBusyHandler = xBusy; db->busyHandler.pBusyArg = pArg; db->busyHandler.nBusy = 0; db->busyTimeout = 0; sqlite3_mutex_leave(db->mutex); return SQLITE_OK; } #ifndef SQLITE_OMIT_PROGRESS_CALLBACK /* |
︙ | ︙ | |||
1654 1655 1656 1657 1658 1659 1660 | #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; #endif if( ms>0 ){ sqlite3_busy_handler(db, (int(*)(void*,int))sqliteDefaultBusyCallback, (void*)db); db->busyTimeout = ms; | < | | | 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 | #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; #endif if( ms>0 ){ sqlite3_busy_handler(db, (int(*)(void*,int))sqliteDefaultBusyCallback, (void*)db); db->busyTimeout = ms; }else{ sqlite3_busy_handler(db, 0, 0); } return SQLITE_OK; } /* ** Cause any pending operation to stop at its earliest opportunity. */ void sqlite3_interrupt(sqlite3 *db){ #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) && (db==0 || db->eOpenState!=SQLITE_STATE_ZOMBIE) ){ (void)SQLITE_MISUSE_BKPT; return; } #endif AtomicStore(&db->u1.isInterrupted, 1); } /* ** This function is exactly the same as sqlite3_create_function(), except ** that it is designed to be called by internal code. The difference is ** that if a malloc() fails in sqlite3_create_function(), an error code |
︙ | ︙ | |||
1695 1696 1697 1698 1699 1700 1701 | void (*xStep)(sqlite3_context*,int,sqlite3_value **), void (*xFinal)(sqlite3_context*), void (*xValue)(sqlite3_context*), void (*xInverse)(sqlite3_context*,int,sqlite3_value **), FuncDestructor *pDestructor ){ FuncDef *p; | < | > | > > > > > > > > | | > | | | > | | | > | | | | | | > > > > > > > > > > > > > > | 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 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 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 | void (*xStep)(sqlite3_context*,int,sqlite3_value **), void (*xFinal)(sqlite3_context*), void (*xValue)(sqlite3_context*), void (*xInverse)(sqlite3_context*,int,sqlite3_value **), FuncDestructor *pDestructor ){ FuncDef *p; int extraFlags; assert( sqlite3_mutex_held(db->mutex) ); assert( xValue==0 || xSFunc==0 ); if( zFunctionName==0 /* Must have a valid name */ || (xSFunc!=0 && xFinal!=0) /* Not both xSFunc and xFinal */ || ((xFinal==0)!=(xStep==0)) /* Both or neither of xFinal and xStep */ || ((xValue==0)!=(xInverse==0)) /* Both or neither of xValue, xInverse */ || (nArg<-1 || nArg>SQLITE_MAX_FUNCTION_ARG) || (255<sqlite3Strlen30(zFunctionName)) ){ return SQLITE_MISUSE_BKPT; } assert( SQLITE_FUNC_CONSTANT==SQLITE_DETERMINISTIC ); assert( SQLITE_FUNC_DIRECT==SQLITE_DIRECTONLY ); extraFlags = enc & (SQLITE_DETERMINISTIC|SQLITE_DIRECTONLY| SQLITE_SUBTYPE|SQLITE_INNOCUOUS); enc &= (SQLITE_FUNC_ENCMASK|SQLITE_ANY); /* The SQLITE_INNOCUOUS flag is the same bit as SQLITE_FUNC_UNSAFE. But ** the meaning is inverted. So flip the bit. */ assert( SQLITE_FUNC_UNSAFE==SQLITE_INNOCUOUS ); extraFlags ^= SQLITE_FUNC_UNSAFE; #ifndef SQLITE_OMIT_UTF16 /* If SQLITE_UTF16 is specified as the encoding type, transform this ** to one of SQLITE_UTF16LE or SQLITE_UTF16BE using the ** SQLITE_UTF16NATIVE macro. SQLITE_UTF16 is not used internally. ** ** If SQLITE_ANY is specified, add three versions of the function ** to the hash table. */ switch( enc ){ case SQLITE_UTF16: enc = SQLITE_UTF16NATIVE; break; case SQLITE_ANY: { int rc; rc = sqlite3CreateFunc(db, zFunctionName, nArg, (SQLITE_UTF8|extraFlags)^SQLITE_FUNC_UNSAFE, pUserData, xSFunc, xStep, xFinal, xValue, xInverse, pDestructor); if( rc==SQLITE_OK ){ rc = sqlite3CreateFunc(db, zFunctionName, nArg, (SQLITE_UTF16LE|extraFlags)^SQLITE_FUNC_UNSAFE, pUserData, xSFunc, xStep, xFinal, xValue, xInverse, pDestructor); } if( rc!=SQLITE_OK ){ return rc; } enc = SQLITE_UTF16BE; break; } case SQLITE_UTF8: case SQLITE_UTF16LE: case SQLITE_UTF16BE: break; default: enc = SQLITE_UTF8; break; } #else enc = SQLITE_UTF8; #endif /* Check if an existing function is being overridden or deleted. If so, ** and there are active VMs, then return SQLITE_BUSY. If a function ** is being overridden/deleted but there are no active VMs, allow the ** operation to continue but invalidate all precompiled statements. */ p = sqlite3FindFunction(db, zFunctionName, nArg, (u8)enc, 0); if( p && (p->funcFlags & SQLITE_FUNC_ENCMASK)==(u32)enc && p->nArg==nArg ){ if( db->nVdbeActive ){ sqlite3ErrorWithMsg(db, SQLITE_BUSY, "unable to delete/modify user-function due to active statements"); assert( !db->mallocFailed ); return SQLITE_BUSY; }else{ sqlite3ExpirePreparedStatements(db, 0); } }else if( xSFunc==0 && xFinal==0 ){ /* Trying to delete a function that does not exist. This is a no-op. ** https://sqlite.org/forum/forumpost/726219164b */ return SQLITE_OK; } p = sqlite3FindFunction(db, zFunctionName, nArg, (u8)enc, 1); assert(p || db->mallocFailed); if( !p ){ return SQLITE_NOMEM_BKPT; } /* If an older version of the function with a configured destructor is ** being replaced invoke the destructor function here. */ functionDestroy(db, p); if( pDestructor ){ pDestructor->nRef++; } p->u.pDestructor = pDestructor; p->funcFlags = (p->funcFlags & SQLITE_FUNC_ENCMASK) | extraFlags; testcase( p->funcFlags & SQLITE_DETERMINISTIC ); testcase( p->funcFlags & SQLITE_DIRECTONLY ); p->xSFunc = xSFunc ? xSFunc : xStep; p->xFinalize = xFinal; p->xValue = xValue; p->xInverse = xInverse; p->pUserData = pUserData; p->nArg = (u16)nArg; return SQLITE_OK; |
︙ | ︙ | |||
1827 1828 1829 1830 1831 1832 1833 | pArg->xDestroy = xDestroy; pArg->pUserData = p; } rc = sqlite3CreateFunc(db, zFunc, nArg, enc, p, xSFunc, xStep, xFinal, xValue, xInverse, pArg ); if( pArg && pArg->nRef==0 ){ | | | 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 | pArg->xDestroy = xDestroy; pArg->pUserData = p; } rc = sqlite3CreateFunc(db, zFunc, nArg, enc, p, xSFunc, xStep, xFinal, xValue, xInverse, pArg ); if( pArg && pArg->nRef==0 ){ assert( rc!=SQLITE_OK || (xStep==0 && xFinal==0) ); xDestroy(p); sqlite3_free(pArg); } out: rc = sqlite3ApiExit(db, rc); sqlite3_mutex_leave(db->mutex); |
︙ | ︙ | |||
1992 1993 1994 1995 1996 1997 1998 | (void)SQLITE_MISUSE_BKPT; return 0; } #endif sqlite3_mutex_enter(db->mutex); pOld = db->pTraceArg; db->mTrace = xTrace ? SQLITE_TRACE_LEGACY : 0; | | | 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 | (void)SQLITE_MISUSE_BKPT; return 0; } #endif sqlite3_mutex_enter(db->mutex); pOld = db->pTraceArg; db->mTrace = xTrace ? SQLITE_TRACE_LEGACY : 0; db->trace.xLegacy = xTrace; db->pTraceArg = pArg; sqlite3_mutex_leave(db->mutex); return pOld; } #endif /* SQLITE_OMIT_DEPRECATED */ /* Register a trace callback using the version-2 interface. |
︙ | ︙ | |||
2016 2017 2018 2019 2020 2021 2022 | return SQLITE_MISUSE_BKPT; } #endif sqlite3_mutex_enter(db->mutex); if( mTrace==0 ) xTrace = 0; if( xTrace==0 ) mTrace = 0; db->mTrace = mTrace; | | | 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 | return SQLITE_MISUSE_BKPT; } #endif sqlite3_mutex_enter(db->mutex); if( mTrace==0 ) xTrace = 0; if( xTrace==0 ) mTrace = 0; db->mTrace = mTrace; db->trace.xV2 = xTrace; db->pTraceArg = pArg; sqlite3_mutex_leave(db->mutex); return SQLITE_OK; } #ifndef SQLITE_OMIT_DEPRECATED /* |
︙ | ︙ | |||
2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 | pRet = db->pPreUpdateArg; db->xPreUpdateCallback = xCallback; db->pPreUpdateArg = pArg; sqlite3_mutex_leave(db->mutex); return pRet; } #endif /* SQLITE_ENABLE_PREUPDATE_HOOK */ #ifndef SQLITE_OMIT_WAL /* ** The sqlite3_wal_hook() callback registered by sqlite3_wal_autocheckpoint(). ** Invoke sqlite3_wal_checkpoint if the number of frames in the log file ** is greater than sqlite3.pWalArg cast to an integer (the value configured by ** wal_autocheckpoint()). | > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | pRet = db->pPreUpdateArg; db->xPreUpdateCallback = xCallback; db->pPreUpdateArg = pArg; sqlite3_mutex_leave(db->mutex); return pRet; } #endif /* SQLITE_ENABLE_PREUPDATE_HOOK */ /* ** Register a function to be invoked prior to each autovacuum that ** determines the number of pages to vacuum. */ int sqlite3_autovacuum_pages( sqlite3 *db, /* Attach the hook to this database */ unsigned int (*xCallback)(void*,const char*,u32,u32,u32), void *pArg, /* Argument to the function */ void (*xDestructor)(void*) /* Destructor for pArg */ ){ #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ){ if( xDestructor ) xDestructor(pArg); return SQLITE_MISUSE_BKPT; } #endif sqlite3_mutex_enter(db->mutex); if( db->xAutovacDestr ){ db->xAutovacDestr(db->pAutovacPagesArg); } db->xAutovacPages = xCallback; db->pAutovacPagesArg = pArg; db->xAutovacDestr = xDestructor; sqlite3_mutex_leave(db->mutex); return SQLITE_OK; } #ifndef SQLITE_OMIT_WAL /* ** The sqlite3_wal_hook() callback registered by sqlite3_wal_autocheckpoint(). ** Invoke sqlite3_wal_checkpoint if the number of frames in the log file ** is greater than sqlite3.pWalArg cast to an integer (the value configured by ** wal_autocheckpoint()). |
︙ | ︙ | |||
2245 2246 2247 2248 2249 2250 2251 | int *pnLog, /* OUT: Size of WAL log in frames */ int *pnCkpt /* OUT: Total number of frames checkpointed */ ){ #ifdef SQLITE_OMIT_WAL return SQLITE_OK; #else int rc; /* Return code */ | | | 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 | int *pnLog, /* OUT: Size of WAL log in frames */ int *pnCkpt /* OUT: Total number of frames checkpointed */ ){ #ifdef SQLITE_OMIT_WAL return SQLITE_OK; #else int rc; /* Return code */ int iDb; /* Schema to checkpoint */ #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; #endif /* Initialize the output variables to -1 in case an error occurs. */ if( pnLog ) *pnLog = -1; |
︙ | ︙ | |||
2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 | ** mode: */ return SQLITE_MISUSE; } sqlite3_mutex_enter(db->mutex); if( zDb && zDb[0] ){ iDb = sqlite3FindDbName(db, zDb); } if( iDb<0 ){ rc = SQLITE_ERROR; sqlite3ErrorWithMsg(db, SQLITE_ERROR, "unknown database: %s", zDb); }else{ db->busyHandler.nBusy = 0; rc = sqlite3Checkpoint(db, iDb, eMode, pnLog, pnCkpt); sqlite3Error(db, rc); } rc = sqlite3ApiExit(db, rc); /* If there are no active statements, clear the interrupt flag at this ** point. */ if( db->nVdbeActive==0 ){ | > > | | 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 | ** mode: */ return SQLITE_MISUSE; } sqlite3_mutex_enter(db->mutex); if( zDb && zDb[0] ){ iDb = sqlite3FindDbName(db, zDb); }else{ iDb = SQLITE_MAX_DB; /* This means process all schemas */ } if( iDb<0 ){ rc = SQLITE_ERROR; sqlite3ErrorWithMsg(db, SQLITE_ERROR, "unknown database: %s", zDb); }else{ db->busyHandler.nBusy = 0; rc = sqlite3Checkpoint(db, iDb, eMode, pnLog, pnCkpt); sqlite3Error(db, rc); } rc = sqlite3ApiExit(db, rc); /* If there are no active statements, clear the interrupt flag at this ** point. */ if( db->nVdbeActive==0 ){ AtomicStore(&db->u1.isInterrupted, 0); } sqlite3_mutex_leave(db->mutex); return rc; #endif } |
︙ | ︙ | |||
2316 2317 2318 2319 2320 2321 2322 | ** an error occurs while running the checkpoint, an SQLite error code is ** returned (i.e. SQLITE_IOERR). Otherwise, SQLITE_OK. ** ** The mutex on database handle db should be held by the caller. The mutex ** associated with the specific b-tree being checkpointed is taken by ** this function while the checkpoint is running. ** | | > > | | 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 | ** an error occurs while running the checkpoint, an SQLite error code is ** returned (i.e. SQLITE_IOERR). Otherwise, SQLITE_OK. ** ** The mutex on database handle db should be held by the caller. The mutex ** associated with the specific b-tree being checkpointed is taken by ** this function while the checkpoint is running. ** ** If iDb is passed SQLITE_MAX_DB then all attached databases are ** checkpointed. If an error is encountered it is returned immediately - ** no attempt is made to checkpoint any remaining databases. ** ** Parameter eMode is one of SQLITE_CHECKPOINT_PASSIVE, FULL, RESTART ** or TRUNCATE. */ int sqlite3Checkpoint(sqlite3 *db, int iDb, int eMode, int *pnLog, int *pnCkpt){ int rc = SQLITE_OK; /* Return code */ int i; /* Used to iterate through attached dbs */ int bBusy = 0; /* True if SQLITE_BUSY has been encountered */ assert( sqlite3_mutex_held(db->mutex) ); assert( !pnLog || *pnLog==-1 ); assert( !pnCkpt || *pnCkpt==-1 ); testcase( iDb==SQLITE_MAX_ATTACHED ); /* See forum post a006d86f72 */ testcase( iDb==SQLITE_MAX_DB ); for(i=0; i<db->nDb && rc==SQLITE_OK; i++){ if( i==iDb || iDb==SQLITE_MAX_DB ){ rc = sqlite3BtreeCheckpoint(db->aDb[i].pBt, eMode, pnLog, pnCkpt); pnLog = 0; pnCkpt = 0; if( rc==SQLITE_BUSY ){ bBusy = 1; rc = SQLITE_OK; } |
︙ | ︙ | |||
2692 2693 2694 2695 2696 2697 2698 | ** itself. When this function is called the *pFlags variable should contain ** the default flags to open the database handle with. The value stored in ** *pFlags may be updated before returning if the URI filename contains ** "cache=xxx" or "mode=xxx" query parameters. ** ** If successful, SQLITE_OK is returned. In this case *ppVfs is set to point to ** the VFS that should be used to open the database file. *pzFile is set to | | > > | | | 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 | ** itself. When this function is called the *pFlags variable should contain ** the default flags to open the database handle with. The value stored in ** *pFlags may be updated before returning if the URI filename contains ** "cache=xxx" or "mode=xxx" query parameters. ** ** If successful, SQLITE_OK is returned. In this case *ppVfs is set to point to ** the VFS that should be used to open the database file. *pzFile is set to ** point to a buffer containing the name of the file to open. The value ** stored in *pzFile is a database name acceptable to sqlite3_uri_parameter() ** and is in the same format as names created using sqlite3_create_filename(). ** The caller must invoke sqlite3_free_filename() (not sqlite3_free()!) on ** the value returned in *pzFile to avoid a memory leak. ** ** If an error occurs, then an SQLite error code is returned and *pzErrMsg ** may be set to point to a buffer containing an English language error ** message. It is the responsibility of the caller to eventually release ** this buffer by calling sqlite3_free(). */ int sqlite3ParseUri( |
︙ | ︙ | |||
2726 2727 2728 2729 2730 2731 2732 | || sqlite3GlobalConfig.bOpenUri) /* IMP: R-51689-46548 */ && nUri>=5 && memcmp(zUri, "file:", 5)==0 /* IMP: R-57884-37496 */ ){ char *zOpt; int eState; /* Parser state when parsing URI */ int iIn; /* Input character index */ int iOut = 0; /* Output character index */ | | > > > | 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 | || sqlite3GlobalConfig.bOpenUri) /* IMP: R-51689-46548 */ && nUri>=5 && memcmp(zUri, "file:", 5)==0 /* IMP: R-57884-37496 */ ){ char *zOpt; int eState; /* Parser state when parsing URI */ int iIn; /* Input character index */ int iOut = 0; /* Output character index */ u64 nByte = nUri+8; /* Bytes of space to allocate */ /* Make sure the SQLITE_OPEN_URI flag is set to indicate to the VFS xOpen ** method that there may be extra parameters following the file-name. */ flags |= SQLITE_OPEN_URI; for(iIn=0; iIn<nUri; iIn++) nByte += (zUri[iIn]=='&'); zFile = sqlite3_malloc64(nByte); if( !zFile ) return SQLITE_NOMEM_BKPT; memset(zFile, 0, 4); /* 4-byte of 0x00 is the start of DB name marker */ zFile += 4; iIn = 5; #ifdef SQLITE_ALLOW_URI_AUTHORITY if( strncmp(zUri+5, "///", 3)==0 ){ iIn = 7; /* The following condition causes URIs with five leading / characters ** like file://///host/path to be converted into UNCs like //host/path. |
︙ | ︙ | |||
2825 2826 2827 2828 2829 2830 2831 | }else if( (eState==0 && c=='?') || (eState==2 && c=='&') ){ c = 0; eState = 1; } zFile[iOut++] = c; } if( eState==1 ) zFile[iOut++] = '\0'; | | < | 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 | }else if( (eState==0 && c=='?') || (eState==2 && c=='&') ){ c = 0; eState = 1; } zFile[iOut++] = c; } if( eState==1 ) zFile[iOut++] = '\0'; memset(zFile+iOut, 0, 4); /* end-of-options + empty journal filenames */ /* Check if there were any options specified that should be interpreted ** here. Options that are interpreted here include "vfs" and those that ** correspond to flags that may be passed to the sqlite3_open_v2() ** method. */ zOpt = &zFile[sqlite3Strlen30(zFile)+1]; while( zOpt[0] ){ |
︙ | ︙ | |||
2906 2907 2908 2909 2910 2911 2912 | } } zOpt = &zVal[nVal+1]; } }else{ | | > > | < | > > > > > > > > > > > > > > > > > | 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 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 | } } zOpt = &zVal[nVal+1]; } }else{ zFile = sqlite3_malloc64(nUri+8); if( !zFile ) return SQLITE_NOMEM_BKPT; memset(zFile, 0, 4); zFile += 4; if( nUri ){ memcpy(zFile, zUri, nUri); } memset(zFile+nUri, 0, 4); flags &= ~SQLITE_OPEN_URI; } *ppVfs = sqlite3_vfs_find(zVfs); if( *ppVfs==0 ){ *pzErrMsg = sqlite3_mprintf("no such vfs: %s", zVfs); rc = SQLITE_ERROR; } parse_uri_out: if( rc!=SQLITE_OK ){ sqlite3_free_filename(zFile); zFile = 0; } *pFlags = flags; *pzFile = zFile; return rc; } /* ** This routine does the core work of extracting URI parameters from a ** database filename for the sqlite3_uri_parameter() interface. */ static const char *uriParameter(const char *zFilename, const char *zParam){ zFilename += sqlite3Strlen30(zFilename) + 1; while( ALWAYS(zFilename!=0) && zFilename[0] ){ int x = strcmp(zFilename, zParam); zFilename += sqlite3Strlen30(zFilename) + 1; if( x==0 ) return zFilename; zFilename += sqlite3Strlen30(zFilename) + 1; } return 0; } /* ** This routine does the work of opening a database on behalf of ** sqlite3_open() and sqlite3_open16(). The database filename "zFilename" ** is UTF-8 encoded. */ static int openDatabase( const char *zFilename, /* Database filename UTF-8 encoded */ sqlite3 **ppDb, /* OUT: Returned database handle */ unsigned int flags, /* Operational flags */ const char *zVfs /* Name of the VFS to use */ ){ sqlite3 *db; /* Store allocated handle here */ int rc; /* Return code */ int isThreadsafe; /* True for threadsafe connections */ char *zOpen = 0; /* Filename argument to pass to BtreeOpen() */ char *zErrMsg = 0; /* Error message from sqlite3ParseUri() */ int i; /* Loop counter */ #ifdef SQLITE_ENABLE_API_ARMOR if( ppDb==0 ) return SQLITE_MISUSE_BKPT; #endif *ppDb = 0; #ifndef SQLITE_OMIT_AUTOINIT rc = sqlite3_initialize(); |
︙ | ︙ | |||
2980 2981 2982 2983 2984 2985 2986 | /* Remove harmful bits from the flags parameter ** ** The SQLITE_OPEN_NOMUTEX and SQLITE_OPEN_FULLMUTEX flags were ** dealt with in the previous code block. Besides these, the only ** valid input flags for sqlite3_open_v2() are SQLITE_OPEN_READONLY, ** SQLITE_OPEN_READWRITE, SQLITE_OPEN_CREATE, SQLITE_OPEN_SHAREDCACHE, | | | | | 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 | /* Remove harmful bits from the flags parameter ** ** The SQLITE_OPEN_NOMUTEX and SQLITE_OPEN_FULLMUTEX flags were ** dealt with in the previous code block. Besides these, the only ** valid input flags for sqlite3_open_v2() are SQLITE_OPEN_READONLY, ** SQLITE_OPEN_READWRITE, SQLITE_OPEN_CREATE, SQLITE_OPEN_SHAREDCACHE, ** SQLITE_OPEN_PRIVATECACHE, SQLITE_OPEN_EXRESCODE, and some reserved ** bits. Silently mask off all other flags. */ flags &= ~( SQLITE_OPEN_DELETEONCLOSE | SQLITE_OPEN_EXCLUSIVE | SQLITE_OPEN_MAIN_DB | SQLITE_OPEN_TEMP_DB | SQLITE_OPEN_TRANSIENT_DB | SQLITE_OPEN_MAIN_JOURNAL | SQLITE_OPEN_TEMP_JOURNAL | SQLITE_OPEN_SUBJOURNAL | SQLITE_OPEN_SUPER_JOURNAL | SQLITE_OPEN_NOMUTEX | SQLITE_OPEN_FULLMUTEX | SQLITE_OPEN_WAL ); /* Allocate the sqlite data structure */ db = sqlite3MallocZero( sizeof(sqlite3) ); |
︙ | ︙ | |||
3016 3017 3018 3019 3020 3021 3022 | goto opendb_out; } if( isThreadsafe==0 ){ sqlite3MutexWarnOnContention(db->mutex); } } sqlite3_mutex_enter(db->mutex); | | | | > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 | goto opendb_out; } if( isThreadsafe==0 ){ sqlite3MutexWarnOnContention(db->mutex); } } sqlite3_mutex_enter(db->mutex); db->errMask = (flags & SQLITE_OPEN_EXRESCODE)!=0 ? 0xffffffff : 0xff; db->nDb = 2; db->eOpenState = SQLITE_STATE_BUSY; db->aDb = db->aDbStatic; db->lookaside.bDisable = 1; db->lookaside.sz = 0; sqlite3FastPrngInit(&db->sPrng); assert( sizeof(db->aLimit)==sizeof(aHardLimit) ); memcpy(db->aLimit, aHardLimit, sizeof(db->aLimit)); db->aLimit[SQLITE_LIMIT_WORKER_THREADS] = SQLITE_DEFAULT_WORKER_THREADS; db->autoCommit = 1; db->nextAutovac = -1; db->szMmap = sqlite3GlobalConfig.szMmap; db->nextPagesize = 0; db->init.azInit = sqlite3StdType; /* Any array of string ptrs will do */ #ifdef SQLITE_ENABLE_SORTER_MMAP /* Beginning with version 3.37.0, using the VFS xFetch() API to memory-map ** the temporary files used to do external sorts (see code in vdbesort.c) ** is disabled. It can still be used either by defining ** SQLITE_ENABLE_SORTER_MMAP at compile time or by using the ** SQLITE_TESTCTRL_SORTER_MMAP test-control at runtime. */ db->nMaxSorterMmap = 0x7FFFFFFF; #endif db->flags |= SQLITE_ShortColNames | SQLITE_EnableTrigger | SQLITE_EnableView | SQLITE_CacheSpill #if !defined(SQLITE_TRUSTED_SCHEMA) || SQLITE_TRUSTED_SCHEMA+0!=0 | SQLITE_TrustedSchema #endif /* The SQLITE_DQS compile-time option determines the default settings ** for SQLITE_DBCONFIG_DQS_DDL and SQLITE_DBCONFIG_DQS_DML. ** ** SQLITE_DQS SQLITE_DBCONFIG_DQS_DDL SQLITE_DBCONFIG_DQS_DML ** ---------- ----------------------- ----------------------- ** undefined on on ** 3 on on ** 2 on off ** 1 off on ** 0 off off ** ** Legacy behavior is 3 (double-quoted string literals are allowed anywhere) ** and so that is the default. But developers are encouranged to use ** -DSQLITE_DQS=0 (best) or -DSQLITE_DQS=1 (second choice) if possible. */ #if !defined(SQLITE_DQS) # define SQLITE_DQS 3 #endif #if (SQLITE_DQS&1)==1 | SQLITE_DqsDML #endif #if (SQLITE_DQS&2)==2 | SQLITE_DqsDDL #endif #if !defined(SQLITE_DEFAULT_AUTOMATIC_INDEX) || SQLITE_DEFAULT_AUTOMATIC_INDEX | SQLITE_AutoIndex #endif #if SQLITE_DEFAULT_CKPTFULLFSYNC | SQLITE_CkptFullFSync #endif #if SQLITE_DEFAULT_FILE_FORMAT<4 |
︙ | ︙ | |||
3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 | #endif #if defined(SQLITE_ENABLE_QPSG) | SQLITE_EnableQPSG #endif #if defined(SQLITE_DEFAULT_DEFENSIVE) | SQLITE_Defensive #endif ; sqlite3HashInit(&db->aCollSeq); #ifndef SQLITE_OMIT_VIRTUALTABLE sqlite3HashInit(&db->aModule); #endif /* Add the default collation sequence BINARY. BINARY works for both UTF-8 ** and UTF-16, so add a version for each to avoid any unnecessary ** conversions. The only error that can occur here is a malloc() failure. ** ** EVIDENCE-OF: R-52786-44878 SQLite defines three built-in collating ** functions: */ createCollation(db, sqlite3StrBINARY, SQLITE_UTF8, 0, binCollFunc, 0); createCollation(db, sqlite3StrBINARY, SQLITE_UTF16BE, 0, binCollFunc, 0); createCollation(db, sqlite3StrBINARY, SQLITE_UTF16LE, 0, binCollFunc, 0); createCollation(db, "NOCASE", SQLITE_UTF8, 0, nocaseCollatingFunc, 0); | > > > | < < < < < | 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 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 3344 3345 | #endif #if defined(SQLITE_ENABLE_QPSG) | SQLITE_EnableQPSG #endif #if defined(SQLITE_DEFAULT_DEFENSIVE) | SQLITE_Defensive #endif #if defined(SQLITE_DEFAULT_LEGACY_ALTER_TABLE) | SQLITE_LegacyAlter #endif ; sqlite3HashInit(&db->aCollSeq); #ifndef SQLITE_OMIT_VIRTUALTABLE sqlite3HashInit(&db->aModule); #endif /* Add the default collation sequence BINARY. BINARY works for both UTF-8 ** and UTF-16, so add a version for each to avoid any unnecessary ** conversions. The only error that can occur here is a malloc() failure. ** ** EVIDENCE-OF: R-52786-44878 SQLite defines three built-in collating ** functions: */ createCollation(db, sqlite3StrBINARY, SQLITE_UTF8, 0, binCollFunc, 0); createCollation(db, sqlite3StrBINARY, SQLITE_UTF16BE, 0, binCollFunc, 0); createCollation(db, sqlite3StrBINARY, SQLITE_UTF16LE, 0, binCollFunc, 0); createCollation(db, "NOCASE", SQLITE_UTF8, 0, nocaseCollatingFunc, 0); createCollation(db, "RTRIM", SQLITE_UTF8, 0, rtrimCollFunc, 0); if( db->mallocFailed ){ goto opendb_out; } /* Parse the filename/URI argument ** ** Only allow sensible combinations of bits in the flags argument. ** Throw an error if any non-sense combination is used. If we ** do not block illegal combinations here, it could trigger ** assert() statements in deeper layers. Sensible combinations |
︙ | ︙ | |||
3111 3112 3113 3114 3115 3116 3117 | assert( SQLITE_OPEN_READONLY == 0x01 ); assert( SQLITE_OPEN_READWRITE == 0x02 ); assert( SQLITE_OPEN_CREATE == 0x04 ); testcase( (1<<(flags&7))==0x02 ); /* READONLY */ testcase( (1<<(flags&7))==0x04 ); /* READWRITE */ testcase( (1<<(flags&7))==0x40 ); /* READWRITE | CREATE */ if( ((1<<(flags&7)) & 0x46)==0 ){ | | | 3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 | assert( SQLITE_OPEN_READONLY == 0x01 ); assert( SQLITE_OPEN_READWRITE == 0x02 ); assert( SQLITE_OPEN_CREATE == 0x04 ); testcase( (1<<(flags&7))==0x02 ); /* READONLY */ testcase( (1<<(flags&7))==0x04 ); /* READWRITE */ testcase( (1<<(flags&7))==0x40 ); /* READWRITE | CREATE */ if( ((1<<(flags&7)) & 0x46)==0 ){ rc = SQLITE_MISUSE_BKPT; /* IMP: R-18321-05872 */ }else{ rc = sqlite3ParseUri(zVfs, zFilename, &flags, &db->pVfs, &zOpen, &zErrMsg); } if( rc!=SQLITE_OK ){ if( rc==SQLITE_NOMEM ) sqlite3OomFault(db); sqlite3ErrorWithMsg(db, rc, zErrMsg ? "%s" : 0, zErrMsg); sqlite3_free(zErrMsg); |
︙ | ︙ | |||
3134 3135 3136 3137 3138 3139 3140 | rc = SQLITE_NOMEM_BKPT; } sqlite3Error(db, rc); goto opendb_out; } sqlite3BtreeEnter(db->aDb[0].pBt); db->aDb[0].pSchema = sqlite3SchemaGet(db, db->aDb[0].pBt); | | > > | | < | < | | < | < < < < < | < < < < < < | < < < < < | < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 | rc = SQLITE_NOMEM_BKPT; } sqlite3Error(db, rc); goto opendb_out; } sqlite3BtreeEnter(db->aDb[0].pBt); db->aDb[0].pSchema = sqlite3SchemaGet(db, db->aDb[0].pBt); if( !db->mallocFailed ){ sqlite3SetTextEncoding(db, SCHEMA_ENC(db)); } sqlite3BtreeLeave(db->aDb[0].pBt); db->aDb[1].pSchema = sqlite3SchemaGet(db, 0); /* The default safety_level for the main database is FULL; for the temp ** database it is OFF. This matches the pager layer defaults. */ db->aDb[0].zDbSName = "main"; db->aDb[0].safety_level = SQLITE_DEFAULT_SYNCHRONOUS+1; db->aDb[1].zDbSName = "temp"; db->aDb[1].safety_level = PAGER_SYNCHRONOUS_OFF; db->eOpenState = SQLITE_STATE_OPEN; if( db->mallocFailed ){ goto opendb_out; } /* Register all built-in functions, but do not attempt to read the ** database schema yet. This is delayed until the first time the database ** is accessed. */ sqlite3Error(db, SQLITE_OK); sqlite3RegisterPerConnectionBuiltinFunctions(db); rc = sqlite3_errcode(db); /* Load compiled-in extensions */ for(i=0; rc==SQLITE_OK && i<ArraySize(sqlite3BuiltinExtensions); i++){ rc = sqlite3BuiltinExtensions[i](db); } /* Load automatic extensions - extensions that have been registered ** using the sqlite3_automatic_extension() API. */ if( rc==SQLITE_OK ){ sqlite3AutoLoadExtensions(db); rc = sqlite3_errcode(db); if( rc!=SQLITE_OK ){ goto opendb_out; } } #ifdef SQLITE_ENABLE_INTERNAL_FUNCTIONS /* Testing use only!!! The -DSQLITE_ENABLE_INTERNAL_FUNCTIONS=1 compile-time ** option gives access to internal functions by default. ** Testing use only!!! */ db->mDbFlags |= DBFLAG_InternalFunc; #endif /* -DSQLITE_DEFAULT_LOCKING_MODE=1 makes EXCLUSIVE the default locking ** mode. -DSQLITE_DEFAULT_LOCKING_MODE=0 make NORMAL the default locking ** mode. Doing nothing at all also makes NORMAL the default. */ #ifdef SQLITE_DEFAULT_LOCKING_MODE |
︙ | ︙ | |||
3260 3261 3262 3263 3264 3265 3266 | opendb_out: if( db ){ assert( db->mutex!=0 || isThreadsafe==0 || sqlite3GlobalConfig.bFullMutex==0 ); sqlite3_mutex_leave(db->mutex); } rc = sqlite3_errcode(db); | | | | < < < < < < < < < < < < < < < < < | | > | 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 | opendb_out: if( db ){ assert( db->mutex!=0 || isThreadsafe==0 || sqlite3GlobalConfig.bFullMutex==0 ); sqlite3_mutex_leave(db->mutex); } rc = sqlite3_errcode(db); assert( db!=0 || (rc&0xff)==SQLITE_NOMEM ); if( (rc&0xff)==SQLITE_NOMEM ){ sqlite3_close(db); db = 0; }else if( rc!=SQLITE_OK ){ db->eOpenState = SQLITE_STATE_SICK; } *ppDb = db; #ifdef SQLITE_ENABLE_SQLLOG if( sqlite3GlobalConfig.xSqllog ){ /* Opening a db handle. Fourth parameter is passed 0. */ void *pArg = sqlite3GlobalConfig.pSqllogArg; sqlite3GlobalConfig.xSqllog(pArg, db, zFilename, 0); } #endif sqlite3_free_filename(zOpen); return rc; } /* ** Open a new database handle. */ int sqlite3_open( const char *zFilename, sqlite3 **ppDb |
︙ | ︙ | |||
3518 3519 3520 3521 3522 3523 3524 | testcase( sqlite3GlobalConfig.xLog!=0 ); return sqlite3ReportError(SQLITE_MISUSE, lineno, "misuse"); } int sqlite3CantopenError(int lineno){ testcase( sqlite3GlobalConfig.xLog!=0 ); return sqlite3ReportError(SQLITE_CANTOPEN, lineno, "cannot open file"); } | | > > | 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 3716 | testcase( sqlite3GlobalConfig.xLog!=0 ); return sqlite3ReportError(SQLITE_MISUSE, lineno, "misuse"); } int sqlite3CantopenError(int lineno){ testcase( sqlite3GlobalConfig.xLog!=0 ); return sqlite3ReportError(SQLITE_CANTOPEN, lineno, "cannot open file"); } #if defined(SQLITE_DEBUG) || defined(SQLITE_ENABLE_CORRUPT_PGNO) int sqlite3CorruptPgnoError(int lineno, Pgno pgno){ char zMsg[100]; sqlite3_snprintf(sizeof(zMsg), zMsg, "database corruption page %d", pgno); testcase( sqlite3GlobalConfig.xLog!=0 ); return sqlite3ReportError(SQLITE_CORRUPT, lineno, zMsg); } #endif #ifdef SQLITE_DEBUG int sqlite3NomemError(int lineno){ testcase( sqlite3GlobalConfig.xLog!=0 ); return sqlite3ReportError(SQLITE_NOMEM, lineno, "OOM"); } int sqlite3IoerrnomemError(int lineno){ testcase( sqlite3GlobalConfig.xLog!=0 ); return sqlite3ReportError(SQLITE_IOERR_NOMEM, lineno, "I/O OOM error"); |
︙ | ︙ | |||
3590 3591 3592 3593 3594 3595 3596 | rc = sqlite3Init(db, &zErrMsg); if( SQLITE_OK!=rc ){ goto error_out; } /* Locate the table in question */ pTab = sqlite3FindTable(db, zTableName, zDbName); | | | | 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 | rc = sqlite3Init(db, &zErrMsg); if( SQLITE_OK!=rc ){ goto error_out; } /* Locate the table in question */ pTab = sqlite3FindTable(db, zTableName, zDbName); if( !pTab || IsView(pTab) ){ pTab = 0; goto error_out; } /* Find the column for which info is requested */ if( zColumnName==0 ){ /* Query for existance of table only */ }else{ for(iCol=0; iCol<pTab->nCol; iCol++){ pCol = &pTab->aCol[iCol]; if( 0==sqlite3StrICmp(pCol->zCnName, zColumnName) ){ break; } } if( iCol==pTab->nCol ){ if( HasRowid(pTab) && sqlite3IsRowid(zColumnName) ){ iCol = pTab->iPKey; pCol = iCol>=0 ? &pTab->aCol[iCol] : 0; |
︙ | ︙ | |||
3628 3629 3630 3631 3632 3633 3634 | ** and there is no explicitly declared IPK column. ** ** 2. The table is not a view and the column name identified an ** explicitly declared column. Copy meta information from *pCol. */ if( pCol ){ zDataType = sqlite3ColumnType(pCol,0); | | | 3806 3807 3808 3809 3810 3811 3812 3813 3814 3815 3816 3817 3818 3819 3820 | ** and there is no explicitly declared IPK column. ** ** 2. The table is not a view and the column name identified an ** explicitly declared column. Copy meta information from *pCol. */ if( pCol ){ zDataType = sqlite3ColumnType(pCol,0); zCollSeq = sqlite3ColumnColl(pCol); notnull = pCol->notNull!=0; primarykey = (pCol->colFlags & COLFLAG_PRIMKEY)!=0; autoinc = pTab->iPKey==iCol && (pTab->tabFlags & TF_Autoincrement)!=0; }else{ zDataType = "INTEGER"; primarykey = 1; } |
︙ | ︙ | |||
3726 3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 3737 3738 3739 3740 3741 3742 | *(sqlite3_vfs**)pArg = sqlite3PagerVfs(pPager); rc = SQLITE_OK; }else if( op==SQLITE_FCNTL_JOURNAL_POINTER ){ *(sqlite3_file**)pArg = sqlite3PagerJrnlFile(pPager); rc = SQLITE_OK; }else if( op==SQLITE_FCNTL_DATA_VERSION ){ *(unsigned int*)pArg = sqlite3PagerDataVersion(pPager); rc = SQLITE_OK; }else{ rc = sqlite3OsFileControl(fd, op, pArg); } sqlite3BtreeLeave(pBtree); } sqlite3_mutex_leave(db->mutex); return rc; } | > > > > > > > > > | 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 | *(sqlite3_vfs**)pArg = sqlite3PagerVfs(pPager); rc = SQLITE_OK; }else if( op==SQLITE_FCNTL_JOURNAL_POINTER ){ *(sqlite3_file**)pArg = sqlite3PagerJrnlFile(pPager); rc = SQLITE_OK; }else if( op==SQLITE_FCNTL_DATA_VERSION ){ *(unsigned int*)pArg = sqlite3PagerDataVersion(pPager); rc = SQLITE_OK; }else if( op==SQLITE_FCNTL_RESERVE_BYTES ){ int iNew = *(int*)pArg; *(int*)pArg = sqlite3BtreeGetRequestedReserve(pBtree); if( iNew>=0 && iNew<=255 ){ sqlite3BtreeSetPageSize(pBtree, 0, iNew, 0); } rc = SQLITE_OK; }else{ int nSave = db->busyHandler.nBusy; rc = sqlite3OsFileControl(fd, op, pArg); db->busyHandler.nBusy = nSave; } sqlite3BtreeLeave(pBtree); } sqlite3_mutex_leave(db->mutex); return rc; } |
︙ | ︙ | |||
3766 3767 3768 3769 3770 3771 3772 | ** this verb acts like PRNG_RESET. */ case SQLITE_TESTCTRL_PRNG_RESTORE: { sqlite3PrngRestoreState(); break; } | > | > > > > > > > > | > | > > | > > > > | > > > > > > > | 3953 3954 3955 3956 3957 3958 3959 3960 3961 3962 3963 3964 3965 3966 3967 3968 3969 3970 3971 3972 3973 3974 3975 3976 3977 3978 3979 3980 3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994 3995 3996 3997 3998 | ** this verb acts like PRNG_RESET. */ case SQLITE_TESTCTRL_PRNG_RESTORE: { sqlite3PrngRestoreState(); break; } /* sqlite3_test_control(SQLITE_TESTCTRL_PRNG_SEED, int x, sqlite3 *db); ** ** Control the seed for the pseudo-random number generator (PRNG) that ** is built into SQLite. Cases: ** ** x!=0 && db!=0 Seed the PRNG to the current value of the ** schema cookie in the main database for db, or ** x if the schema cookie is zero. This case ** is convenient to use with database fuzzers ** as it allows the fuzzer some control over the ** the PRNG seed. ** ** x!=0 && db==0 Seed the PRNG to the value of x. ** ** x==0 && db==0 Revert to default behavior of using the ** xRandomness method on the primary VFS. ** ** This test-control also resets the PRNG so that the new seed will ** be used for the next call to sqlite3_randomness(). */ #ifndef SQLITE_OMIT_WSD case SQLITE_TESTCTRL_PRNG_SEED: { int x = va_arg(ap, int); int y; sqlite3 *db = va_arg(ap, sqlite3*); assert( db==0 || db->aDb[0].pSchema!=0 ); if( db && (y = db->aDb[0].pSchema->schema_cookie)!=0 ){ x = y; } sqlite3Config.iPrngSeed = x; sqlite3_randomness(0,0); break; } #endif /* ** sqlite3_test_control(BITVEC_TEST, size, program) ** ** Run a test against a Bitvec object of size. The program argument ** is an array of integers that defines the test. Return -1 on a ** memory allocation error, 0 on success, or non-zero for an error. |
︙ | ︙ | |||
3920 3921 3922 3923 3924 3925 3926 | ** 123410 little-endian, determined at compile-time */ case SQLITE_TESTCTRL_BYTEORDER: { rc = SQLITE_BYTEORDER*100 + SQLITE_LITTLEENDIAN*10 + SQLITE_BIGENDIAN; break; } | < < < < < < < < < < < < < < | | | | < < | > > > > > > > > > > > > > > > > > > | 4130 4131 4132 4133 4134 4135 4136 4137 4138 4139 4140 4141 4142 4143 4144 4145 4146 4147 4148 4149 4150 4151 4152 4153 4154 4155 4156 4157 4158 4159 4160 4161 4162 4163 4164 4165 4166 4167 4168 4169 4170 4171 4172 4173 4174 4175 4176 4177 4178 4179 4180 4181 4182 4183 4184 4185 4186 4187 4188 4189 4190 4191 4192 4193 4194 4195 4196 4197 4198 4199 4200 4201 4202 4203 4204 4205 4206 4207 4208 | ** 123410 little-endian, determined at compile-time */ case SQLITE_TESTCTRL_BYTEORDER: { rc = SQLITE_BYTEORDER*100 + SQLITE_LITTLEENDIAN*10 + SQLITE_BIGENDIAN; break; } /* sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS, sqlite3 *db, int N) ** ** Enable or disable various optimizations for testing purposes. The ** argument N is a bitmask of optimizations to be disabled. For normal ** operation N should be 0. The idea is that a test program (like the ** SQL Logic Test or SLT test module) can run the same SQL multiple times ** with various optimizations disabled to verify that the same answer ** is obtained in every case. */ case SQLITE_TESTCTRL_OPTIMIZATIONS: { sqlite3 *db = va_arg(ap, sqlite3*); db->dbOptFlags = va_arg(ap, u32); break; } /* sqlite3_test_control(SQLITE_TESTCTRL_LOCALTIME_FAULT, int onoff); ** ** If parameter onoff is non-zero, subsequent calls to localtime() ** and its variants fail. If onoff is zero, undo this setting. */ case SQLITE_TESTCTRL_LOCALTIME_FAULT: { sqlite3GlobalConfig.bLocaltimeFault = va_arg(ap, int); break; } /* sqlite3_test_control(SQLITE_TESTCTRL_INTERNAL_FUNCTIONS, sqlite3*); ** ** Toggle the ability to use internal functions on or off for ** the database connection given in the argument. */ case SQLITE_TESTCTRL_INTERNAL_FUNCTIONS: { sqlite3 *db = va_arg(ap, sqlite3*); db->mDbFlags ^= DBFLAG_InternalFunc; break; } /* sqlite3_test_control(SQLITE_TESTCTRL_NEVER_CORRUPT, int); ** ** Set or clear a flag that indicates that the database file is always well- ** formed and never corrupt. This flag is clear by default, indicating that ** database files might have arbitrary corruption. Setting the flag during ** testing causes certain assert() statements in the code to be activated ** that demonstrat invariants on well-formed database files. */ case SQLITE_TESTCTRL_NEVER_CORRUPT: { sqlite3GlobalConfig.neverCorrupt = va_arg(ap, int); break; } /* sqlite3_test_control(SQLITE_TESTCTRL_EXTRA_SCHEMA_CHECKS, int); ** ** Set or clear a flag that causes SQLite to verify that type, name, ** and tbl_name fields of the sqlite_schema table. This is normally ** on, but it is sometimes useful to turn it off for testing. ** ** 2020-07-22: Disabling EXTRA_SCHEMA_CHECKS also disables the ** verification of rootpage numbers when parsing the schema. This ** is useful to make it easier to reach strange internal error states ** during testing. The EXTRA_SCHEMA_CHECKS setting is always enabled ** in production. */ case SQLITE_TESTCTRL_EXTRA_SCHEMA_CHECKS: { sqlite3GlobalConfig.bExtraSchemaChecks = va_arg(ap, int); break; } /* Set the threshold at which OP_Once counters reset back to zero. ** By default this is 0x7ffffffe (over 2 billion), but that value is ** too big to test in a reasonable amount of time, so this control is ** provided to set a small and easily reachable reset value. */ case SQLITE_TESTCTRL_ONCE_RESET_THRESHOLD: { |
︙ | ︙ | |||
4070 4071 4072 4073 4074 4075 4076 | */ case SQLITE_TESTCTRL_PARSER_COVERAGE: { FILE *out = va_arg(ap, FILE*); if( sqlite3ParserCoverage(out) ) rc = SQLITE_ERROR; break; } #endif /* defined(YYCOVERAGE) */ | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | < < | | 4282 4283 4284 4285 4286 4287 4288 4289 4290 4291 4292 4293 4294 4295 4296 4297 4298 4299 4300 4301 4302 4303 4304 4305 4306 4307 4308 4309 4310 4311 4312 4313 4314 4315 4316 4317 4318 4319 4320 4321 4322 4323 4324 4325 4326 4327 4328 4329 4330 4331 4332 4333 4334 4335 4336 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 4389 4390 4391 4392 4393 4394 4395 4396 4397 4398 4399 4400 4401 4402 4403 4404 4405 4406 4407 4408 4409 4410 4411 4412 4413 4414 4415 4416 4417 4418 4419 4420 4421 4422 4423 4424 4425 4426 4427 4428 4429 4430 4431 4432 4433 4434 4435 4436 4437 4438 4439 4440 4441 4442 4443 4444 4445 4446 4447 4448 4449 4450 4451 4452 4453 4454 4455 4456 4457 4458 4459 4460 4461 4462 4463 4464 4465 4466 4467 4468 4469 4470 4471 4472 4473 4474 4475 4476 4477 4478 4479 4480 4481 4482 4483 4484 4485 4486 4487 4488 4489 4490 4491 | */ case SQLITE_TESTCTRL_PARSER_COVERAGE: { FILE *out = va_arg(ap, FILE*); if( sqlite3ParserCoverage(out) ) rc = SQLITE_ERROR; break; } #endif /* defined(YYCOVERAGE) */ /* sqlite3_test_control(SQLITE_TESTCTRL_RESULT_INTREAL, sqlite3_context*); ** ** This test-control causes the most recent sqlite3_result_int64() value ** to be interpreted as a MEM_IntReal instead of as an MEM_Int. Normally, ** MEM_IntReal values only arise during an INSERT operation of integer ** values into a REAL column, so they can be challenging to test. This ** test-control enables us to write an intreal() SQL function that can ** inject an intreal() value at arbitrary places in an SQL statement, ** for testing purposes. */ case SQLITE_TESTCTRL_RESULT_INTREAL: { sqlite3_context *pCtx = va_arg(ap, sqlite3_context*); sqlite3ResultIntReal(pCtx); break; } /* sqlite3_test_control(SQLITE_TESTCTRL_SEEK_COUNT, ** sqlite3 *db, // Database connection ** u64 *pnSeek // Write seek count here ** ); ** ** This test-control queries the seek-counter on the "main" database ** file. The seek-counter is written into *pnSeek and is then reset. ** The seek-count is only available if compiled with SQLITE_DEBUG. */ case SQLITE_TESTCTRL_SEEK_COUNT: { sqlite3 *db = va_arg(ap, sqlite3*); u64 *pn = va_arg(ap, sqlite3_uint64*); *pn = sqlite3BtreeSeekCount(db->aDb->pBt); (void)db; /* Silence harmless unused variable warning */ break; } /* sqlite3_test_control(SQLITE_TESTCTRL_TRACEFLAGS, op, ptr) ** ** "ptr" is a pointer to a u32. ** ** op==0 Store the current sqlite3SelectTrace in *ptr ** op==1 Set sqlite3SelectTrace to the value *ptr ** op==3 Store the current sqlite3WhereTrace in *ptr ** op==3 Set sqlite3WhereTrace to the value *ptr */ case SQLITE_TESTCTRL_TRACEFLAGS: { int opTrace = va_arg(ap, int); u32 *ptr = va_arg(ap, u32*); switch( opTrace ){ case 0: *ptr = sqlite3SelectTrace; break; case 1: sqlite3SelectTrace = *ptr; break; case 2: *ptr = sqlite3WhereTrace; break; case 3: sqlite3WhereTrace = *ptr; break; } break; } #if defined(SQLITE_DEBUG) && !defined(SQLITE_OMIT_WSD) /* sqlite3_test_control(SQLITE_TESTCTRL_TUNE, id, *piValue) ** ** If "id" is an integer between 1 and SQLITE_NTUNE then set the value ** of the id-th tuning parameter to *piValue. If "id" is between -1 ** and -SQLITE_NTUNE, then write the current value of the (-id)-th ** tuning parameter into *piValue. ** ** Tuning parameters are for use during transient development builds, ** to help find the best values for constants in the query planner. ** Access tuning parameters using the Tuning(ID) macro. Set the ** parameters in the CLI using ".testctrl tune ID VALUE". ** ** Transient use only. Tuning parameters should not be used in ** checked-in code. */ case SQLITE_TESTCTRL_TUNE: { int id = va_arg(ap, int); int *piValue = va_arg(ap, int*); if( id>0 && id<=SQLITE_NTUNE ){ Tuning(id) = *piValue; }else if( id<0 && id>=-SQLITE_NTUNE ){ *piValue = Tuning(-id); }else{ rc = SQLITE_NOTFOUND; } break; } #endif } va_end(ap); #endif /* SQLITE_UNTESTABLE */ return rc; } /* ** The Pager stores the Database filename, Journal filename, and WAL filename ** consecutively in memory, in that order. The database filename is prefixed ** by four zero bytes. Locate the start of the database filename by searching ** backwards for the first byte following four consecutive zero bytes. ** ** This only works if the filename passed in was obtained from the Pager. */ static const char *databaseName(const char *zName){ while( zName[-1]!=0 || zName[-2]!=0 || zName[-3]!=0 || zName[-4]!=0 ){ zName--; } return zName; } /* ** Append text z[] to the end of p[]. Return a pointer to the first ** character after then zero terminator on the new text in p[]. */ static char *appendText(char *p, const char *z){ size_t n = strlen(z); memcpy(p, z, n+1); return p+n+1; } /* ** Allocate memory to hold names for a database, journal file, WAL file, ** and query parameters. The pointer returned is valid for use by ** sqlite3_filename_database() and sqlite3_uri_parameter() and related ** functions. ** ** Memory layout must be compatible with that generated by the pager ** and expected by sqlite3_uri_parameter() and databaseName(). */ char *sqlite3_create_filename( const char *zDatabase, const char *zJournal, const char *zWal, int nParam, const char **azParam ){ sqlite3_int64 nByte; int i; char *pResult, *p; nByte = strlen(zDatabase) + strlen(zJournal) + strlen(zWal) + 10; for(i=0; i<nParam*2; i++){ nByte += strlen(azParam[i])+1; } pResult = p = sqlite3_malloc64( nByte ); if( p==0 ) return 0; memset(p, 0, 4); p += 4; p = appendText(p, zDatabase); for(i=0; i<nParam*2; i++){ p = appendText(p, azParam[i]); } *(p++) = 0; p = appendText(p, zJournal); p = appendText(p, zWal); *(p++) = 0; *(p++) = 0; assert( (sqlite3_int64)(p - pResult)==nByte ); return pResult + 4; } /* ** Free memory obtained from sqlite3_create_filename(). It is a severe ** error to call this routine with any parameter other than a pointer ** previously obtained from sqlite3_create_filename() or a NULL pointer. */ void sqlite3_free_filename(char *p){ if( p==0 ) return; p = (char*)databaseName(p); sqlite3_free(p - 4); } /* ** This is a utility routine, useful to VFS implementations, that checks ** to see if a database file was a URI that contained a specific query ** parameter, and if so obtains the value of the query parameter. ** ** The zFilename argument is the filename pointer passed into the xOpen() ** method of a VFS implementation. The zParam argument is the name of the ** query parameter we seek. This routine returns the value of the zParam ** parameter if it exists. If the parameter does not exist, this routine ** returns a NULL pointer. */ const char *sqlite3_uri_parameter(const char *zFilename, const char *zParam){ if( zFilename==0 || zParam==0 ) return 0; zFilename = databaseName(zFilename); return uriParameter(zFilename, zParam); } /* ** Return a pointer to the name of Nth query parameter of the filename. */ const char *sqlite3_uri_key(const char *zFilename, int N){ if( zFilename==0 || N<0 ) return 0; zFilename = databaseName(zFilename); zFilename += sqlite3Strlen30(zFilename) + 1; while( ALWAYS(zFilename) && zFilename[0] && (N--)>0 ){ zFilename += sqlite3Strlen30(zFilename) + 1; zFilename += sqlite3Strlen30(zFilename) + 1; } return zFilename[0] ? zFilename : 0; } /* ** Return a boolean value for a query parameter. */ int sqlite3_uri_boolean(const char *zFilename, const char *zParam, int bDflt){ const char *z = sqlite3_uri_parameter(zFilename, zParam); |
︙ | ︙ | |||
4123 4124 4125 4126 4127 4128 4129 4130 4131 4132 4133 4134 4135 4136 | const char *z = sqlite3_uri_parameter(zFilename, zParam); sqlite3_int64 v; if( z && sqlite3DecOrHexToI64(z, &v)==0 ){ bDflt = v; } return bDflt; } /* ** Return the Btree pointer identified by zDbName. Return NULL if not found. */ Btree *sqlite3DbNameToBtree(sqlite3 *db, const char *zDbName){ int iDb = zDbName ? sqlite3FindDbName(db, zDbName) : 0; return iDb<0 ? 0 : db->aDb[iDb].pBt; | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 4504 4505 4506 4507 4508 4509 4510 4511 4512 4513 4514 4515 4516 4517 4518 4519 4520 4521 4522 4523 4524 4525 4526 4527 4528 4529 4530 4531 4532 4533 4534 4535 4536 4537 4538 4539 4540 4541 4542 4543 4544 4545 4546 4547 4548 4549 4550 4551 | const char *z = sqlite3_uri_parameter(zFilename, zParam); sqlite3_int64 v; if( z && sqlite3DecOrHexToI64(z, &v)==0 ){ bDflt = v; } return bDflt; } /* ** Translate a filename that was handed to a VFS routine into the corresponding ** database, journal, or WAL file. ** ** It is an error to pass this routine a filename string that was not ** passed into the VFS from the SQLite core. Doing so is similar to ** passing free() a pointer that was not obtained from malloc() - it is ** an error that we cannot easily detect but that will likely cause memory ** corruption. */ const char *sqlite3_filename_database(const char *zFilename){ if( zFilename==0 ) return 0; return databaseName(zFilename); } const char *sqlite3_filename_journal(const char *zFilename){ if( zFilename==0 ) return 0; zFilename = databaseName(zFilename); zFilename += sqlite3Strlen30(zFilename) + 1; while( ALWAYS(zFilename) && zFilename[0] ){ zFilename += sqlite3Strlen30(zFilename) + 1; zFilename += sqlite3Strlen30(zFilename) + 1; } return zFilename + 1; } const char *sqlite3_filename_wal(const char *zFilename){ #ifdef SQLITE_OMIT_WAL return 0; #else zFilename = sqlite3_filename_journal(zFilename); if( zFilename ) zFilename += sqlite3Strlen30(zFilename) + 1; return zFilename; #endif } /* ** Return the Btree pointer identified by zDbName. Return NULL if not found. */ Btree *sqlite3DbNameToBtree(sqlite3 *db, const char *zDbName){ int iDb = zDbName ? sqlite3FindDbName(db, zDbName) : 0; return iDb<0 ? 0 : db->aDb[iDb].pBt; |
︙ | ︙ | |||
4188 4189 4190 4191 4192 4193 4194 | #endif sqlite3_mutex_enter(db->mutex); if( db->autoCommit==0 ){ int iDb = sqlite3FindDbName(db, zDb); if( iDb==0 || iDb>1 ){ Btree *pBt = db->aDb[iDb].pBt; | | | 4603 4604 4605 4606 4607 4608 4609 4610 4611 4612 4613 4614 4615 4616 4617 | #endif sqlite3_mutex_enter(db->mutex); if( db->autoCommit==0 ){ int iDb = sqlite3FindDbName(db, zDb); if( iDb==0 || iDb>1 ){ Btree *pBt = db->aDb[iDb].pBt; if( SQLITE_TXN_WRITE!=sqlite3BtreeTxnState(pBt) ){ rc = sqlite3BtreeBeginTrans(pBt, 0, 0); if( rc==SQLITE_OK ){ rc = sqlite3PagerSnapshotGet(sqlite3BtreePager(pBt), ppSnapshot); } } } } |
︙ | ︙ | |||
4224 4225 4226 4227 4228 4229 4230 | #endif sqlite3_mutex_enter(db->mutex); if( db->autoCommit==0 ){ int iDb; iDb = sqlite3FindDbName(db, zDb); if( iDb==0 || iDb>1 ){ Btree *pBt = db->aDb[iDb].pBt; | | | | 4639 4640 4641 4642 4643 4644 4645 4646 4647 4648 4649 4650 4651 4652 4653 4654 4655 4656 | #endif sqlite3_mutex_enter(db->mutex); if( db->autoCommit==0 ){ int iDb; iDb = sqlite3FindDbName(db, zDb); if( iDb==0 || iDb>1 ){ Btree *pBt = db->aDb[iDb].pBt; if( sqlite3BtreeTxnState(pBt)!=SQLITE_TXN_WRITE ){ Pager *pPager = sqlite3BtreePager(pBt); int bUnlock = 0; if( sqlite3BtreeTxnState(pBt)!=SQLITE_TXN_NONE ){ if( db->nVdbeActive==0 ){ rc = sqlite3PagerSnapshotCheck(pPager, pSnapshot); if( rc==SQLITE_OK ){ bUnlock = 1; rc = sqlite3BtreeCommit(pBt); } } |
︙ | ︙ | |||
4276 4277 4278 4279 4280 4281 4282 | } #endif sqlite3_mutex_enter(db->mutex); iDb = sqlite3FindDbName(db, zDb); if( iDb==0 || iDb>1 ){ Btree *pBt = db->aDb[iDb].pBt; | | | 4691 4692 4693 4694 4695 4696 4697 4698 4699 4700 4701 4702 4703 4704 4705 | } #endif sqlite3_mutex_enter(db->mutex); iDb = sqlite3FindDbName(db, zDb); if( iDb==0 || iDb>1 ){ Btree *pBt = db->aDb[iDb].pBt; if( SQLITE_TXN_NONE==sqlite3BtreeTxnState(pBt) ){ rc = sqlite3BtreeBeginTrans(pBt, 0, 0); if( rc==SQLITE_OK ){ rc = sqlite3PagerSnapshotRecover(sqlite3BtreePager(pBt)); sqlite3BtreeCommit(pBt); } } } |
︙ | ︙ |
Changes to src/malloc.c.
︙ | ︙ | |||
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | ** is a no-op returning zero if SQLite is not compiled with ** SQLITE_ENABLE_MEMORY_MANAGEMENT. */ UNUSED_PARAMETER(n); return 0; #endif } /* ** State information local to the memory allocation subsystem. */ static SQLITE_WSD struct Mem0Global { sqlite3_mutex *mutex; /* Mutex to serialize access */ sqlite3_int64 alarmThreshold; /* The soft heap limit */ /* ** True if heap is nearly "full" where "full" is defined by the ** sqlite3_soft_heap_limit() setting. */ int nearlyFull; | > > > > > > > > | | 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 | ** is a no-op returning zero if SQLite is not compiled with ** SQLITE_ENABLE_MEMORY_MANAGEMENT. */ UNUSED_PARAMETER(n); return 0; #endif } /* ** Default value of the hard heap limit. 0 means "no limit". */ #ifndef SQLITE_MAX_MEMORY # define SQLITE_MAX_MEMORY 0 #endif /* ** State information local to the memory allocation subsystem. */ static SQLITE_WSD struct Mem0Global { sqlite3_mutex *mutex; /* Mutex to serialize access */ sqlite3_int64 alarmThreshold; /* The soft heap limit */ sqlite3_int64 hardLimit; /* The hard upper bound on memory */ /* ** True if heap is nearly "full" where "full" is defined by the ** sqlite3_soft_heap_limit() setting. */ int nearlyFull; } mem0 = { 0, SQLITE_MAX_MEMORY, SQLITE_MAX_MEMORY, 0 }; #define mem0 GLOBAL(struct Mem0Global, mem0) /* ** Return the memory allocator mutex. sqlite3_status() needs it. */ sqlite3_mutex *sqlite3MallocMutex(void){ |
︙ | ︙ | |||
70 71 72 73 74 75 76 | (void)pArg; (void)iThreshold; return SQLITE_OK; } #endif /* | | | > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > < | | 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 | (void)pArg; (void)iThreshold; return SQLITE_OK; } #endif /* ** Set the soft heap-size limit for the library. An argument of ** zero disables the limit. A negative argument is a no-op used to ** obtain the return value. ** ** The return value is the value of the heap limit just before this ** interface was called. ** ** If the hard heap limit is enabled, then the soft heap limit cannot ** be disabled nor raised above the hard heap limit. */ sqlite3_int64 sqlite3_soft_heap_limit64(sqlite3_int64 n){ sqlite3_int64 priorLimit; sqlite3_int64 excess; sqlite3_int64 nUsed; #ifndef SQLITE_OMIT_AUTOINIT int rc = sqlite3_initialize(); if( rc ) return -1; #endif sqlite3_mutex_enter(mem0.mutex); priorLimit = mem0.alarmThreshold; if( n<0 ){ sqlite3_mutex_leave(mem0.mutex); return priorLimit; } if( mem0.hardLimit>0 && (n>mem0.hardLimit || n==0) ){ n = mem0.hardLimit; } mem0.alarmThreshold = n; nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED); AtomicStore(&mem0.nearlyFull, n>0 && n<=nUsed); sqlite3_mutex_leave(mem0.mutex); excess = sqlite3_memory_used() - n; if( excess>0 ) sqlite3_release_memory((int)(excess & 0x7fffffff)); return priorLimit; } void sqlite3_soft_heap_limit(int n){ if( n<0 ) n = 0; sqlite3_soft_heap_limit64(n); } /* ** Set the hard heap-size limit for the library. An argument of zero ** disables the hard heap limit. A negative argument is a no-op used ** to obtain the return value without affecting the hard heap limit. ** ** The return value is the value of the hard heap limit just prior to ** calling this interface. ** ** Setting the hard heap limit will also activate the soft heap limit ** and constrain the soft heap limit to be no more than the hard heap ** limit. */ sqlite3_int64 sqlite3_hard_heap_limit64(sqlite3_int64 n){ sqlite3_int64 priorLimit; #ifndef SQLITE_OMIT_AUTOINIT int rc = sqlite3_initialize(); if( rc ) return -1; #endif sqlite3_mutex_enter(mem0.mutex); priorLimit = mem0.hardLimit; if( n>=0 ){ mem0.hardLimit = n; if( n<mem0.alarmThreshold || mem0.alarmThreshold==0 ){ mem0.alarmThreshold = n; } } sqlite3_mutex_leave(mem0.mutex); return priorLimit; } /* ** Initialize the memory allocation subsystem. */ int sqlite3MallocInit(void){ int rc; if( sqlite3GlobalConfig.m.xMalloc==0 ){ sqlite3MemSetDefault(); } mem0.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MEM); if( sqlite3GlobalConfig.pPage==0 || sqlite3GlobalConfig.szPage<512 || sqlite3GlobalConfig.nPage<=0 ){ sqlite3GlobalConfig.pPage = 0; sqlite3GlobalConfig.szPage = 0; } rc = sqlite3GlobalConfig.m.xInit(sqlite3GlobalConfig.m.pAppData); if( rc!=SQLITE_OK ) memset(&mem0, 0, sizeof(mem0)); return rc; } /* ** Return true if the heap is currently under memory pressure - in other ** words if the amount of heap used is close to the limit set by ** sqlite3_soft_heap_limit(). */ int sqlite3HeapNearlyFull(void){ return AtomicLoad(&mem0.nearlyFull); } /* ** Deinitialize the memory allocation subsystem. */ void sqlite3MallocEnd(void){ if( sqlite3GlobalConfig.m.xShutdown ){ |
︙ | ︙ | |||
186 187 188 189 190 191 192 | /* In Firefox (circa 2017-02-08), xRoundup() is remapped to an internal ** implementation of malloc_good_size(), which must be called in debug ** mode and specifically when the DMD "Dark Matter Detector" is enabled ** or else a crash results. Hence, do not attempt to optimize out the ** following xRoundup() call. */ nFull = sqlite3GlobalConfig.m.xRoundup(n); | < < < < < < < | > > > > > > > | | 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 | /* In Firefox (circa 2017-02-08), xRoundup() is remapped to an internal ** implementation of malloc_good_size(), which must be called in debug ** mode and specifically when the DMD "Dark Matter Detector" is enabled ** or else a crash results. Hence, do not attempt to optimize out the ** following xRoundup() call. */ nFull = sqlite3GlobalConfig.m.xRoundup(n); sqlite3StatusHighwater(SQLITE_STATUS_MALLOC_SIZE, n); if( mem0.alarmThreshold>0 ){ sqlite3_int64 nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED); if( nUsed >= mem0.alarmThreshold - nFull ){ AtomicStore(&mem0.nearlyFull, 1); sqlite3MallocAlarm(nFull); if( mem0.hardLimit ){ nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED); if( nUsed >= mem0.hardLimit - nFull ){ *pp = 0; return; } } }else{ AtomicStore(&mem0.nearlyFull, 0); } } p = sqlite3GlobalConfig.m.xMalloc(nFull); #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT if( p==0 && mem0.alarmThreshold>0 ){ sqlite3MallocAlarm(nFull); p = sqlite3GlobalConfig.m.xMalloc(nFull); |
︙ | ︙ | |||
264 265 266 267 268 269 270 | return sqlite3Malloc(n); } /* ** TRUE if p is a lookaside memory allocation from db */ #ifndef SQLITE_OMIT_LOOKASIDE | | | | > > > > > > > | < > > > > > > > | > | > | | | > > > | 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 | return sqlite3Malloc(n); } /* ** TRUE if p is a lookaside memory allocation from db */ #ifndef SQLITE_OMIT_LOOKASIDE static int isLookaside(sqlite3 *db, const void *p){ return SQLITE_WITHIN(p, db->lookaside.pStart, db->lookaside.pEnd); } #else #define isLookaside(A,B) 0 #endif /* ** Return the size of a memory allocation previously obtained from ** sqlite3Malloc() or sqlite3_malloc(). */ int sqlite3MallocSize(const void *p){ assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) ); return sqlite3GlobalConfig.m.xSize((void*)p); } static int lookasideMallocSize(sqlite3 *db, const void *p){ #ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE return p<db->lookaside.pMiddle ? db->lookaside.szTrue : LOOKASIDE_SMALL; #else return db->lookaside.szTrue; #endif } int sqlite3DbMallocSize(sqlite3 *db, const void *p){ assert( p!=0 ); #ifdef SQLITE_DEBUG if( db==0 || !isLookaside(db,p) ){ if( db==0 ){ assert( sqlite3MemdebugNoType(p, (u8)~MEMTYPE_HEAP) ); assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) ); }else{ assert( sqlite3MemdebugHasType(p, (MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) ); assert( sqlite3MemdebugNoType(p, (u8)~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) ); } } #endif if( db ){ if( ((uptr)p)<(uptr)(db->lookaside.pEnd) ){ #ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE if( ((uptr)p)>=(uptr)(db->lookaside.pMiddle) ){ assert( sqlite3_mutex_held(db->mutex) ); return LOOKASIDE_SMALL; } #endif if( ((uptr)p)>=(uptr)(db->lookaside.pStart) ){ assert( sqlite3_mutex_held(db->mutex) ); return db->lookaside.szTrue; } } } return sqlite3GlobalConfig.m.xSize((void*)p); } sqlite3_uint64 sqlite3_msize(void *p){ assert( sqlite3MemdebugNoType(p, (u8)~MEMTYPE_HEAP) ); assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) ); return p ? sqlite3GlobalConfig.m.xSize(p) : 0; } |
︙ | ︙ | |||
342 343 344 345 346 347 348 | assert( db==0 || sqlite3_mutex_held(db->mutex) ); assert( p!=0 ); if( db ){ if( db->pnBytesFreed ){ measureAllocationSize(db, p); return; } | | > > | | > > > > > > > > > | | | | > | 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 | assert( db==0 || sqlite3_mutex_held(db->mutex) ); assert( p!=0 ); if( db ){ if( db->pnBytesFreed ){ measureAllocationSize(db, p); return; } if( ((uptr)p)<(uptr)(db->lookaside.pEnd) ){ #ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE if( ((uptr)p)>=(uptr)(db->lookaside.pMiddle) ){ LookasideSlot *pBuf = (LookasideSlot*)p; #ifdef SQLITE_DEBUG memset(p, 0xaa, LOOKASIDE_SMALL); /* Trash freed content */ #endif pBuf->pNext = db->lookaside.pSmallFree; db->lookaside.pSmallFree = pBuf; return; } #endif /* SQLITE_OMIT_TWOSIZE_LOOKASIDE */ if( ((uptr)p)>=(uptr)(db->lookaside.pStart) ){ LookasideSlot *pBuf = (LookasideSlot*)p; #ifdef SQLITE_DEBUG memset(p, 0xaa, db->lookaside.szTrue); /* Trash freed content */ #endif pBuf->pNext = db->lookaside.pFree; db->lookaside.pFree = pBuf; return; } } } assert( sqlite3MemdebugHasType(p, (MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) ); assert( sqlite3MemdebugNoType(p, (u8)~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) ); assert( db!=0 || sqlite3MemdebugNoType(p, MEMTYPE_LOOKASIDE) ); sqlite3MemdebugSetType(p, MEMTYPE_HEAP); sqlite3_free(p); |
︙ | ︙ | |||
391 392 393 394 395 396 397 398 399 400 | /* IMPLEMENTATION-OF: R-46199-30249 SQLite guarantees that the second ** argument to xRealloc is always a value returned by a prior call to ** xRoundup. */ nNew = sqlite3GlobalConfig.m.xRoundup((int)nBytes); if( nOld==nNew ){ pNew = pOld; }else if( sqlite3GlobalConfig.bMemstat ){ sqlite3_mutex_enter(mem0.mutex); sqlite3StatusHighwater(SQLITE_STATUS_MALLOC_SIZE, (int)nBytes); nDiff = nNew - nOld; | > | > > > | > > > | 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 | /* IMPLEMENTATION-OF: R-46199-30249 SQLite guarantees that the second ** argument to xRealloc is always a value returned by a prior call to ** xRoundup. */ nNew = sqlite3GlobalConfig.m.xRoundup((int)nBytes); if( nOld==nNew ){ pNew = pOld; }else if( sqlite3GlobalConfig.bMemstat ){ sqlite3_int64 nUsed; sqlite3_mutex_enter(mem0.mutex); sqlite3StatusHighwater(SQLITE_STATUS_MALLOC_SIZE, (int)nBytes); nDiff = nNew - nOld; if( nDiff>0 && (nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED)) >= mem0.alarmThreshold-nDiff ){ sqlite3MallocAlarm(nDiff); if( mem0.hardLimit>0 && nUsed >= mem0.hardLimit - nDiff ){ sqlite3_mutex_leave(mem0.mutex); return 0; } } pNew = sqlite3GlobalConfig.m.xRealloc(pOld, nNew); #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT if( pNew==0 && mem0.alarmThreshold>0 ){ sqlite3MallocAlarm((int)nBytes); pNew = sqlite3GlobalConfig.m.xRealloc(pOld, nNew); } #endif if( pNew ){ nNew = sqlite3MallocSize(pNew); sqlite3StatusUp(SQLITE_STATUS_MEMORY_USED, nNew-nOld); } sqlite3_mutex_leave(mem0.mutex); }else{ pNew = sqlite3GlobalConfig.m.xRealloc(pOld, nNew); |
︙ | ︙ | |||
506 507 508 509 510 511 512 | } void *sqlite3DbMallocRawNN(sqlite3 *db, u64 n){ #ifndef SQLITE_OMIT_LOOKASIDE LookasideSlot *pBuf; assert( db!=0 ); assert( sqlite3_mutex_held(db->mutex) ); assert( db->pnBytesFreed==0 ); | > | > | > > > > > > > > | > > > | > > > > | | | | | | | | | | < < < | 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 | } void *sqlite3DbMallocRawNN(sqlite3 *db, u64 n){ #ifndef SQLITE_OMIT_LOOKASIDE LookasideSlot *pBuf; assert( db!=0 ); assert( sqlite3_mutex_held(db->mutex) ); assert( db->pnBytesFreed==0 ); if( n>db->lookaside.sz ){ if( !db->lookaside.bDisable ){ db->lookaside.anStat[1]++; }else if( db->mallocFailed ){ return 0; } return dbMallocRawFinish(db, n); } #ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE if( n<=LOOKASIDE_SMALL ){ if( (pBuf = db->lookaside.pSmallFree)!=0 ){ db->lookaside.pSmallFree = pBuf->pNext; db->lookaside.anStat[0]++; return (void*)pBuf; }else if( (pBuf = db->lookaside.pSmallInit)!=0 ){ db->lookaside.pSmallInit = pBuf->pNext; db->lookaside.anStat[0]++; return (void*)pBuf; } } #endif if( (pBuf = db->lookaside.pFree)!=0 ){ db->lookaside.pFree = pBuf->pNext; db->lookaside.anStat[0]++; return (void*)pBuf; }else if( (pBuf = db->lookaside.pInit)!=0 ){ db->lookaside.pInit = pBuf->pNext; db->lookaside.anStat[0]++; return (void*)pBuf; }else{ db->lookaside.anStat[2]++; } #else assert( db!=0 ); assert( sqlite3_mutex_held(db->mutex) ); assert( db->pnBytesFreed==0 ); if( db->mallocFailed ){ return 0; |
︙ | ︙ | |||
546 547 548 549 550 551 552 | ** Resize the block of memory pointed to by p to n bytes. If the ** resize fails, set the mallocFailed flag in the connection object. */ void *sqlite3DbRealloc(sqlite3 *db, void *p, u64 n){ assert( db!=0 ); if( p==0 ) return sqlite3DbMallocRawNN(db, n); assert( sqlite3_mutex_held(db->mutex) ); | > > > > > > > | > > | | | 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 | ** Resize the block of memory pointed to by p to n bytes. If the ** resize fails, set the mallocFailed flag in the connection object. */ void *sqlite3DbRealloc(sqlite3 *db, void *p, u64 n){ assert( db!=0 ); if( p==0 ) return sqlite3DbMallocRawNN(db, n); assert( sqlite3_mutex_held(db->mutex) ); if( ((uptr)p)<(uptr)db->lookaside.pEnd ){ #ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE if( ((uptr)p)>=(uptr)db->lookaside.pMiddle ){ if( n<=LOOKASIDE_SMALL ) return p; }else #endif if( ((uptr)p)>=(uptr)db->lookaside.pStart ){ if( n<=db->lookaside.szTrue ) return p; } } return dbReallocFinish(db, p, n); } static SQLITE_NOINLINE void *dbReallocFinish(sqlite3 *db, void *p, u64 n){ void *pNew = 0; assert( db!=0 ); assert( p!=0 ); if( db->mallocFailed==0 ){ if( isLookaside(db, p) ){ pNew = sqlite3DbMallocRawNN(db, n); if( pNew ){ memcpy(pNew, p, lookasideMallocSize(db, p)); sqlite3DbFree(db, p); } }else{ assert( sqlite3MemdebugHasType(p, (MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) ); assert( sqlite3MemdebugNoType(p, (u8)~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) ); sqlite3MemdebugSetType(p, MEMTYPE_HEAP); pNew = sqlite3Realloc(p, n); if( !pNew ){ sqlite3OomFault(db); } sqlite3MemdebugSetType(pNew, (db->lookaside.bDisable==0 ? MEMTYPE_LOOKASIDE : MEMTYPE_HEAP)); } } |
︙ | ︙ | |||
611 612 613 614 615 616 617 | memcpy(zNew, z, n); } return zNew; } char *sqlite3DbStrNDup(sqlite3 *db, const char *z, u64 n){ char *zNew; assert( db!=0 ); | | < < | | 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 | memcpy(zNew, z, n); } return zNew; } char *sqlite3DbStrNDup(sqlite3 *db, const char *z, u64 n){ char *zNew; assert( db!=0 ); assert( z!=0 || n==0 ); assert( (n&0x7fffffff)==n ); zNew = z ? sqlite3DbMallocRawNN(db, n+1) : 0; if( zNew ){ memcpy(zNew, z, (size_t)n); zNew[n] = 0; } return zNew; } |
︙ | ︙ | |||
654 655 656 657 658 659 660 | ** temporarily disable the lookaside memory allocator and interrupt ** any running VDBEs. */ void sqlite3OomFault(sqlite3 *db){ if( db->mallocFailed==0 && db->bBenignMalloc==0 ){ db->mallocFailed = 1; if( db->nVdbeExec>0 ){ | | | > > > | | | | > | | | > > | 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 | ** temporarily disable the lookaside memory allocator and interrupt ** any running VDBEs. */ void sqlite3OomFault(sqlite3 *db){ if( db->mallocFailed==0 && db->bBenignMalloc==0 ){ db->mallocFailed = 1; if( db->nVdbeExec>0 ){ AtomicStore(&db->u1.isInterrupted, 1); } DisableLookaside; if( db->pParse ){ db->pParse->rc = SQLITE_NOMEM_BKPT; } } } /* ** This routine reactivates the memory allocator and clears the ** db->mallocFailed flag as necessary. ** ** The memory allocator is not restarted if there are running ** VDBEs. */ void sqlite3OomClear(sqlite3 *db){ if( db->mallocFailed && db->nVdbeExec==0 ){ db->mallocFailed = 0; AtomicStore(&db->u1.isInterrupted, 0); assert( db->lookaside.bDisable>0 ); EnableLookaside; } } /* ** Take actions at the end of an API call to deal with error codes. */ static SQLITE_NOINLINE int apiHandleError(sqlite3 *db, int rc){ if( db->mallocFailed || rc==SQLITE_IOERR_NOMEM ){ sqlite3OomClear(db); sqlite3Error(db, SQLITE_NOMEM); return SQLITE_NOMEM_BKPT; } return rc & db->errMask; } /* ** This function must be called before exiting any API function (i.e. ** returning control to the user) that has called sqlite3_malloc or ** sqlite3_realloc. ** |
︙ | ︙ | |||
704 705 706 707 708 709 710 | int sqlite3ApiExit(sqlite3* db, int rc){ /* If the db handle must hold the connection handle mutex here. ** Otherwise the read (and possible write) of db->mallocFailed ** is unsafe, as is the call to sqlite3Error(). */ assert( db!=0 ); assert( sqlite3_mutex_held(db->mutex) ); | | | | 816 817 818 819 820 821 822 823 824 825 826 827 | int sqlite3ApiExit(sqlite3* db, int rc){ /* If the db handle must hold the connection handle mutex here. ** Otherwise the read (and possible write) of db->mallocFailed ** is unsafe, as is the call to sqlite3Error(). */ assert( db!=0 ); assert( sqlite3_mutex_held(db->mutex) ); if( db->mallocFailed || rc ){ return apiHandleError(db, rc); } return rc & db->errMask; } |
Changes to src/mem2.c.
︙ | ︙ | |||
145 146 147 148 149 150 151 | /* ** Given an allocation, find the MemBlockHdr for that allocation. ** ** This routine checks the guards at either end of the allocation and ** if they are incorrect it asserts. */ | | | 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 | /* ** Given an allocation, find the MemBlockHdr for that allocation. ** ** This routine checks the guards at either end of the allocation and ** if they are incorrect it asserts. */ static struct MemBlockHdr *sqlite3MemsysGetHeader(const void *pAllocation){ struct MemBlockHdr *p; int *pInt; u8 *pU8; int nReserve; p = (struct MemBlockHdr*)pAllocation; p--; |
︙ | ︙ | |||
375 376 377 378 379 380 381 | sqlite3_config(SQLITE_CONFIG_MALLOC, &defaultMethods); } /* ** Set the "type" of an allocation. */ void sqlite3MemdebugSetType(void *p, u8 eType){ | | | | | | | 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 | sqlite3_config(SQLITE_CONFIG_MALLOC, &defaultMethods); } /* ** Set the "type" of an allocation. */ void sqlite3MemdebugSetType(void *p, u8 eType){ if( p && sqlite3GlobalConfig.m.xFree==sqlite3MemFree ){ struct MemBlockHdr *pHdr; pHdr = sqlite3MemsysGetHeader(p); assert( pHdr->iForeGuard==FOREGUARD ); pHdr->eType = eType; } } /* ** Return TRUE if the mask of type in eType matches the type of the ** allocation p. Also return true if p==NULL. ** ** This routine is designed for use within an assert() statement, to ** verify the type of an allocation. For example: ** ** assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) ); */ int sqlite3MemdebugHasType(const void *p, u8 eType){ int rc = 1; if( p && sqlite3GlobalConfig.m.xFree==sqlite3MemFree ){ struct MemBlockHdr *pHdr; pHdr = sqlite3MemsysGetHeader(p); assert( pHdr->iForeGuard==FOREGUARD ); /* Allocation is valid */ if( (pHdr->eType&eType)==0 ){ rc = 0; } } return rc; } /* ** Return TRUE if the mask of type in eType matches no bits of the type of the ** allocation p. Also return true if p==NULL. ** ** This routine is designed for use within an assert() statement, to ** verify the type of an allocation. For example: ** ** assert( sqlite3MemdebugNoType(p, MEMTYPE_LOOKASIDE) ); */ int sqlite3MemdebugNoType(const void *p, u8 eType){ int rc = 1; if( p && sqlite3GlobalConfig.m.xFree==sqlite3MemFree ){ struct MemBlockHdr *pHdr; pHdr = sqlite3MemsysGetHeader(p); assert( pHdr->iForeGuard==FOREGUARD ); /* Allocation is valid */ if( (pHdr->eType&eType)!=0 ){ rc = 0; } } |
︙ | ︙ |
Changes to src/mem3.c.
︙ | ︙ | |||
114 115 116 117 118 119 120 | ** Mutex to control access to the memory allocation subsystem. */ sqlite3_mutex *mutex; /* ** The minimum amount of free space that we have seen. */ | | | | | | | | | 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 | ** Mutex to control access to the memory allocation subsystem. */ sqlite3_mutex *mutex; /* ** The minimum amount of free space that we have seen. */ u32 mnKeyBlk; /* ** iKeyBlk is the index of the key chunk. Most new allocations ** occur off of this chunk. szKeyBlk is the size (in Mem3Blocks) ** of the current key chunk. iKeyBlk is 0 if there is no key chunk. ** The key chunk is not in either the aiHash[] or aiSmall[]. */ u32 iKeyBlk; u32 szKeyBlk; /* ** Array of lists of free blocks according to the block size ** for smaller chunks, or a hash on the block size for larger ** chunks. */ u32 aiSmall[MX_SMALL-1]; /* For sizes 2 through MX_SMALL, inclusive */ |
︙ | ︙ | |||
259 260 261 262 263 264 265 | mem3.aPool[i-1].u.hdr.size4x = nBlock*4 | 1 | (x&2); mem3.aPool[i+nBlock-1].u.hdr.prevSize = nBlock; mem3.aPool[i+nBlock-1].u.hdr.size4x |= 2; return &mem3.aPool[i]; } /* | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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 | mem3.aPool[i-1].u.hdr.size4x = nBlock*4 | 1 | (x&2); mem3.aPool[i+nBlock-1].u.hdr.prevSize = nBlock; mem3.aPool[i+nBlock-1].u.hdr.size4x |= 2; return &mem3.aPool[i]; } /* ** Carve a piece off of the end of the mem3.iKeyBlk free chunk. ** Return a pointer to the new allocation. Or, if the key chunk ** is not large enough, return 0. */ static void *memsys3FromKeyBlk(u32 nBlock){ assert( sqlite3_mutex_held(mem3.mutex) ); assert( mem3.szKeyBlk>=nBlock ); if( nBlock>=mem3.szKeyBlk-1 ){ /* Use the entire key chunk */ void *p = memsys3Checkout(mem3.iKeyBlk, mem3.szKeyBlk); mem3.iKeyBlk = 0; mem3.szKeyBlk = 0; mem3.mnKeyBlk = 0; return p; }else{ /* Split the key block. Return the tail. */ u32 newi, x; newi = mem3.iKeyBlk + mem3.szKeyBlk - nBlock; assert( newi > mem3.iKeyBlk+1 ); mem3.aPool[mem3.iKeyBlk+mem3.szKeyBlk-1].u.hdr.prevSize = nBlock; mem3.aPool[mem3.iKeyBlk+mem3.szKeyBlk-1].u.hdr.size4x |= 2; mem3.aPool[newi-1].u.hdr.size4x = nBlock*4 + 1; mem3.szKeyBlk -= nBlock; mem3.aPool[newi-1].u.hdr.prevSize = mem3.szKeyBlk; x = mem3.aPool[mem3.iKeyBlk-1].u.hdr.size4x & 2; mem3.aPool[mem3.iKeyBlk-1].u.hdr.size4x = mem3.szKeyBlk*4 | x; if( mem3.szKeyBlk < mem3.mnKeyBlk ){ mem3.mnKeyBlk = mem3.szKeyBlk; } return (void*)&mem3.aPool[newi]; } } /* ** *pRoot is the head of a list of free chunks of the same size ** or same size hash. In other words, *pRoot is an entry in either ** mem3.aiSmall[] or mem3.aiHash[]. ** ** This routine examines all entries on the given list and tries ** to coalesce each entries with adjacent free chunks. ** ** If it sees a chunk that is larger than mem3.iKeyBlk, it replaces ** the current mem3.iKeyBlk with the new larger chunk. In order for ** this mem3.iKeyBlk replacement to work, the key chunk must be ** linked into the hash tables. That is not the normal state of ** affairs, of course. The calling routine must link the key ** chunk before invoking this routine, then must unlink the (possibly ** changed) key chunk once this routine has finished. */ static void memsys3Merge(u32 *pRoot){ u32 iNext, prev, size, i, x; assert( sqlite3_mutex_held(mem3.mutex) ); for(i=*pRoot; i>0; i=iNext){ iNext = mem3.aPool[i].u.list.next; |
︙ | ︙ | |||
333 334 335 336 337 338 339 | mem3.aPool[prev-1].u.hdr.size4x = size*4 | x; mem3.aPool[prev+size-1].u.hdr.prevSize = size; memsys3Link(prev); i = prev; }else{ size /= 4; } | | | | | 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 | mem3.aPool[prev-1].u.hdr.size4x = size*4 | x; mem3.aPool[prev+size-1].u.hdr.prevSize = size; memsys3Link(prev); i = prev; }else{ size /= 4; } if( size>mem3.szKeyBlk ){ mem3.iKeyBlk = i; mem3.szKeyBlk = size; } } } /* ** Return a block of memory of at least nBytes in size. ** Return NULL if unable. |
︙ | ︙ | |||
384 385 386 387 388 389 390 | return memsys3Checkout(i, nBlock); } } } /* STEP 2: ** Try to satisfy the allocation by carving a piece off of the end | | | | | | | | | | | | | | | 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 | return memsys3Checkout(i, nBlock); } } } /* STEP 2: ** Try to satisfy the allocation by carving a piece off of the end ** of the key chunk. This step usually works if step 1 fails. */ if( mem3.szKeyBlk>=nBlock ){ return memsys3FromKeyBlk(nBlock); } /* STEP 3: ** Loop through the entire memory pool. Coalesce adjacent free ** chunks. Recompute the key chunk as the largest free chunk. ** Then try again to satisfy the allocation by carving a piece off ** of the end of the key chunk. This step happens very ** rarely (we hope!) */ for(toFree=nBlock*16; toFree<(mem3.nPool*16); toFree *= 2){ memsys3OutOfMemory(toFree); if( mem3.iKeyBlk ){ memsys3Link(mem3.iKeyBlk); mem3.iKeyBlk = 0; mem3.szKeyBlk = 0; } for(i=0; i<N_HASH; i++){ memsys3Merge(&mem3.aiHash[i]); } for(i=0; i<MX_SMALL-1; i++){ memsys3Merge(&mem3.aiSmall[i]); } if( mem3.szKeyBlk ){ memsys3Unlink(mem3.iKeyBlk); if( mem3.szKeyBlk>=nBlock ){ return memsys3FromKeyBlk(nBlock); } } } /* If none of the above worked, then we fail. */ return 0; } |
︙ | ︙ | |||
444 445 446 447 448 449 450 | size = mem3.aPool[i-1].u.hdr.size4x/4; assert( i+size<=mem3.nPool+1 ); mem3.aPool[i-1].u.hdr.size4x &= ~1; mem3.aPool[i+size-1].u.hdr.prevSize = size; mem3.aPool[i+size-1].u.hdr.size4x &= ~2; memsys3Link(i); | | | | | | | | | | | | | | | | | | 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 | size = mem3.aPool[i-1].u.hdr.size4x/4; assert( i+size<=mem3.nPool+1 ); mem3.aPool[i-1].u.hdr.size4x &= ~1; mem3.aPool[i+size-1].u.hdr.prevSize = size; mem3.aPool[i+size-1].u.hdr.size4x &= ~2; memsys3Link(i); /* Try to expand the key using the newly freed chunk */ if( mem3.iKeyBlk ){ while( (mem3.aPool[mem3.iKeyBlk-1].u.hdr.size4x&2)==0 ){ size = mem3.aPool[mem3.iKeyBlk-1].u.hdr.prevSize; mem3.iKeyBlk -= size; mem3.szKeyBlk += size; memsys3Unlink(mem3.iKeyBlk); x = mem3.aPool[mem3.iKeyBlk-1].u.hdr.size4x & 2; mem3.aPool[mem3.iKeyBlk-1].u.hdr.size4x = mem3.szKeyBlk*4 | x; mem3.aPool[mem3.iKeyBlk+mem3.szKeyBlk-1].u.hdr.prevSize = mem3.szKeyBlk; } x = mem3.aPool[mem3.iKeyBlk-1].u.hdr.size4x & 2; while( (mem3.aPool[mem3.iKeyBlk+mem3.szKeyBlk-1].u.hdr.size4x&1)==0 ){ memsys3Unlink(mem3.iKeyBlk+mem3.szKeyBlk); mem3.szKeyBlk += mem3.aPool[mem3.iKeyBlk+mem3.szKeyBlk-1].u.hdr.size4x/4; mem3.aPool[mem3.iKeyBlk-1].u.hdr.size4x = mem3.szKeyBlk*4 | x; mem3.aPool[mem3.iKeyBlk+mem3.szKeyBlk-1].u.hdr.prevSize = mem3.szKeyBlk; } } } /* ** Return the size of an outstanding allocation, in bytes. The ** size returned omits the 8-byte header overhead. This only |
︙ | ︙ | |||
556 557 558 559 560 561 562 | } /* Store a pointer to the memory block in global structure mem3. */ assert( sizeof(Mem3Block)==8 ); mem3.aPool = (Mem3Block *)sqlite3GlobalConfig.pHeap; mem3.nPool = (sqlite3GlobalConfig.nHeap / sizeof(Mem3Block)) - 2; | | | | | | | 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 | } /* Store a pointer to the memory block in global structure mem3. */ assert( sizeof(Mem3Block)==8 ); mem3.aPool = (Mem3Block *)sqlite3GlobalConfig.pHeap; mem3.nPool = (sqlite3GlobalConfig.nHeap / sizeof(Mem3Block)) - 2; /* Initialize the key block. */ mem3.szKeyBlk = mem3.nPool; mem3.mnKeyBlk = mem3.szKeyBlk; mem3.iKeyBlk = 1; mem3.aPool[0].u.hdr.size4x = (mem3.szKeyBlk<<2) + 2; mem3.aPool[mem3.nPool].u.hdr.prevSize = mem3.nPool; mem3.aPool[mem3.nPool].u.hdr.size4x = 1; return SQLITE_OK; } /* |
︙ | ︙ | |||
620 621 622 623 624 625 626 | assert( 0 ); break; } if( size&1 ){ fprintf(out, "%p %6d bytes checked out\n", &mem3.aPool[i], (size/4)*8-8); }else{ fprintf(out, "%p %6d bytes free%s\n", &mem3.aPool[i], (size/4)*8-8, | | | | | | 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 | assert( 0 ); break; } if( size&1 ){ fprintf(out, "%p %6d bytes checked out\n", &mem3.aPool[i], (size/4)*8-8); }else{ fprintf(out, "%p %6d bytes free%s\n", &mem3.aPool[i], (size/4)*8-8, i==mem3.iKeyBlk ? " **key**" : ""); } } for(i=0; i<MX_SMALL-1; i++){ if( mem3.aiSmall[i]==0 ) continue; fprintf(out, "small(%2d):", i); for(j = mem3.aiSmall[i]; j>0; j=mem3.aPool[j].u.list.next){ fprintf(out, " %p(%d)", &mem3.aPool[j], (mem3.aPool[j-1].u.hdr.size4x/4)*8-8); } fprintf(out, "\n"); } for(i=0; i<N_HASH; i++){ if( mem3.aiHash[i]==0 ) continue; fprintf(out, "hash(%2d):", i); for(j = mem3.aiHash[i]; j>0; j=mem3.aPool[j].u.list.next){ fprintf(out, " %p(%d)", &mem3.aPool[j], (mem3.aPool[j-1].u.hdr.size4x/4)*8-8); } fprintf(out, "\n"); } fprintf(out, "key=%d\n", mem3.iKeyBlk); fprintf(out, "nowUsed=%d\n", mem3.nPool*8 - mem3.szKeyBlk*8); fprintf(out, "mxUsed=%d\n", mem3.nPool*8 - mem3.mnKeyBlk*8); sqlite3_mutex_leave(mem3.mutex); if( out==stdout ){ fflush(stdout); }else{ fclose(out); } #else |
︙ | ︙ |
Changes to src/memdb.c.
︙ | ︙ | |||
13 14 15 16 17 18 19 | ** This file implements an in-memory VFS. A database is held as a contiguous ** block of memory. ** ** This file also implements interface sqlite3_serialize() and ** sqlite3_deserialize(). */ #include "sqliteInt.h" | | > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | < > | > > > > > > > > > > > > > > > > > > > > > > | 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 | ** This file implements an in-memory VFS. A database is held as a contiguous ** block of memory. ** ** This file also implements interface sqlite3_serialize() and ** sqlite3_deserialize(). */ #include "sqliteInt.h" #ifndef SQLITE_OMIT_DESERIALIZE /* ** Forward declaration of objects used by this utility */ typedef struct sqlite3_vfs MemVfs; typedef struct MemFile MemFile; typedef struct MemStore MemStore; /* Access to a lower-level VFS that (might) implement dynamic loading, ** access to randomness, etc. */ #define ORIGVFS(p) ((sqlite3_vfs*)((p)->pAppData)) /* Storage for a memdb file. ** ** An memdb object can be shared or separate. Shared memdb objects can be ** used by more than one database connection. Mutexes are used by shared ** memdb objects to coordinate access. Separate memdb objects are only ** connected to a single database connection and do not require additional ** mutexes. ** ** Shared memdb objects have .zFName!=0 and .pMutex!=0. They are created ** using "file:/name?vfs=memdb". The first character of the name must be ** "/" or else the object will be a separate memdb object. All shared ** memdb objects are stored in memdb_g.apMemStore[] in an arbitrary order. ** ** Separate memdb objects are created using a name that does not begin ** with "/" or using sqlite3_deserialize(). ** ** Access rules for shared MemStore objects: ** ** * .zFName is initialized when the object is created and afterwards ** is unchanged until the object is destroyed. So it can be accessed ** at any time as long as we know the object is not being destroyed, ** which means while either the SQLITE_MUTEX_STATIC_VFS1 or ** .pMutex is held or the object is not part of memdb_g.apMemStore[]. ** ** * Can .pMutex can only be changed while holding the ** SQLITE_MUTEX_STATIC_VFS1 mutex or while the object is not part ** of memdb_g.apMemStore[]. ** ** * Other fields can only be changed while holding the .pMutex mutex ** or when the .nRef is less than zero and the object is not part of ** memdb_g.apMemStore[]. ** ** * The .aData pointer has the added requirement that it can can only ** be changed (for resizing) when nMmap is zero. ** */ struct MemStore { sqlite3_int64 sz; /* Size of the file */ sqlite3_int64 szAlloc; /* Space allocated to aData */ sqlite3_int64 szMax; /* Maximum allowed size of the file */ unsigned char *aData; /* content of the file */ sqlite3_mutex *pMutex; /* Used by shared stores only */ int nMmap; /* Number of memory mapped pages */ unsigned mFlags; /* Flags */ int nRdLock; /* Number of readers */ int nWrLock; /* Number of writers. (Always 0 or 1) */ int nRef; /* Number of users of this MemStore */ char *zFName; /* The filename for shared stores */ }; /* An open file */ struct MemFile { sqlite3_file base; /* IO methods */ MemStore *pStore; /* The storage */ int eLock; /* Most recent lock against this file */ }; /* ** File-scope variables for holding the memdb files that are accessible ** to multiple database connections in separate threads. ** ** Must hold SQLITE_MUTEX_STATIC_VFS1 to access any part of this object. */ static struct MemFS { int nMemStore; /* Number of shared MemStore objects */ MemStore **apMemStore; /* Array of all shared MemStore objects */ } memdb_g; /* ** Methods for MemFile */ static int memdbClose(sqlite3_file*); static int memdbRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst); static int memdbWrite(sqlite3_file*,const void*,int iAmt, sqlite3_int64 iOfst); static int memdbTruncate(sqlite3_file*, sqlite3_int64 size); |
︙ | ︙ | |||
90 91 92 93 94 95 96 | memdbDlError, /* xDlError */ memdbDlSym, /* xDlSym */ memdbDlClose, /* xDlClose */ memdbRandomness, /* xRandomness */ memdbSleep, /* xSleep */ 0, /* memdbCurrentTime, */ /* xCurrentTime */ memdbGetLastError, /* xGetLastError */ | | > > > | 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 | memdbDlError, /* xDlError */ memdbDlSym, /* xDlSym */ memdbDlClose, /* xDlClose */ memdbRandomness, /* xRandomness */ memdbSleep, /* xSleep */ 0, /* memdbCurrentTime, */ /* xCurrentTime */ memdbGetLastError, /* xGetLastError */ memdbCurrentTimeInt64, /* xCurrentTimeInt64 */ 0, /* xSetSystemCall */ 0, /* xGetSystemCall */ 0, /* xNextSystemCall */ }; static const sqlite3_io_methods memdb_io_methods = { 3, /* iVersion */ memdbClose, /* xClose */ memdbRead, /* xRead */ memdbWrite, /* xWrite */ |
︙ | ︙ | |||
115 116 117 118 119 120 121 122 123 124 125 | 0, /* xShmLock */ 0, /* xShmBarrier */ 0, /* xShmUnmap */ memdbFetch, /* xFetch */ memdbUnfetch /* xUnfetch */ }; /* ** Close an memdb-file. | > > > > > > > > > > > > > > > > > > > > | < < | > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > | > > > | | > > > > > | | | | > > > > > > > | | > > | > > | > > > | > > | > > | > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > | | > | > | > > > > > > > > > > > > > > > > | > > > > | | > > | > > > > | | > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > | > > > > > > > > > > > > | | > > > | | > | > | | 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 | 0, /* xShmLock */ 0, /* xShmBarrier */ 0, /* xShmUnmap */ memdbFetch, /* xFetch */ memdbUnfetch /* xUnfetch */ }; /* ** Enter/leave the mutex on a MemStore */ #if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE==0 static void memdbEnter(MemStore *p){ UNUSED_PARAMETER(p); } static void memdbLeave(MemStore *p){ UNUSED_PARAMETER(p); } #else static void memdbEnter(MemStore *p){ sqlite3_mutex_enter(p->pMutex); } static void memdbLeave(MemStore *p){ sqlite3_mutex_leave(p->pMutex); } #endif /* ** Close an memdb-file. ** Free the underlying MemStore object when its refcount drops to zero ** or less. */ static int memdbClose(sqlite3_file *pFile){ MemStore *p = ((MemFile*)pFile)->pStore; if( p->zFName ){ int i; #ifndef SQLITE_MUTEX_OMIT sqlite3_mutex *pVfsMutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1); #endif sqlite3_mutex_enter(pVfsMutex); for(i=0; ALWAYS(i<memdb_g.nMemStore); i++){ if( memdb_g.apMemStore[i]==p ){ memdbEnter(p); if( p->nRef==1 ){ memdb_g.apMemStore[i] = memdb_g.apMemStore[--memdb_g.nMemStore]; if( memdb_g.nMemStore==0 ){ sqlite3_free(memdb_g.apMemStore); memdb_g.apMemStore = 0; } } break; } } sqlite3_mutex_leave(pVfsMutex); }else{ memdbEnter(p); } p->nRef--; if( p->nRef<=0 ){ if( p->mFlags & SQLITE_DESERIALIZE_FREEONCLOSE ){ sqlite3_free(p->aData); } memdbLeave(p); sqlite3_mutex_free(p->pMutex); sqlite3_free(p); }else{ memdbLeave(p); } return SQLITE_OK; } /* ** Read data from an memdb-file. */ static int memdbRead( sqlite3_file *pFile, void *zBuf, int iAmt, sqlite_int64 iOfst ){ MemStore *p = ((MemFile*)pFile)->pStore; memdbEnter(p); if( iOfst+iAmt>p->sz ){ memset(zBuf, 0, iAmt); if( iOfst<p->sz ) memcpy(zBuf, p->aData+iOfst, p->sz - iOfst); memdbLeave(p); return SQLITE_IOERR_SHORT_READ; } memcpy(zBuf, p->aData+iOfst, iAmt); memdbLeave(p); return SQLITE_OK; } /* ** Try to enlarge the memory allocation to hold at least sz bytes */ static int memdbEnlarge(MemStore *p, sqlite3_int64 newSz){ unsigned char *pNew; if( (p->mFlags & SQLITE_DESERIALIZE_RESIZEABLE)==0 || NEVER(p->nMmap>0) ){ return SQLITE_FULL; } if( newSz>p->szMax ){ return SQLITE_FULL; } newSz *= 2; if( newSz>p->szMax ) newSz = p->szMax; pNew = sqlite3Realloc(p->aData, newSz); if( pNew==0 ) return SQLITE_IOERR_NOMEM; p->aData = pNew; p->szAlloc = newSz; return SQLITE_OK; } /* ** Write data to an memdb-file. */ static int memdbWrite( sqlite3_file *pFile, const void *z, int iAmt, sqlite_int64 iOfst ){ MemStore *p = ((MemFile*)pFile)->pStore; memdbEnter(p); if( NEVER(p->mFlags & SQLITE_DESERIALIZE_READONLY) ){ /* Can't happen: memdbLock() will return SQLITE_READONLY before ** reaching this point */ memdbLeave(p); return SQLITE_IOERR_WRITE; } if( iOfst+iAmt>p->sz ){ int rc; if( iOfst+iAmt>p->szAlloc && (rc = memdbEnlarge(p, iOfst+iAmt))!=SQLITE_OK ){ memdbLeave(p); return rc; } if( iOfst>p->sz ) memset(p->aData+p->sz, 0, iOfst-p->sz); p->sz = iOfst+iAmt; } memcpy(p->aData+iOfst, z, iAmt); memdbLeave(p); return SQLITE_OK; } /* ** Truncate an memdb-file. ** ** In rollback mode (which is always the case for memdb, as it does not ** support WAL mode) the truncate() method is only used to reduce ** the size of a file, never to increase the size. */ static int memdbTruncate(sqlite3_file *pFile, sqlite_int64 size){ MemStore *p = ((MemFile*)pFile)->pStore; int rc = SQLITE_OK; memdbEnter(p); if( size>p->sz ){ /* This can only happen with a corrupt wal mode db */ rc = SQLITE_CORRUPT; }else{ p->sz = size; } memdbLeave(p); return rc; } /* ** Sync an memdb-file. */ static int memdbSync(sqlite3_file *pFile, int flags){ UNUSED_PARAMETER(pFile); UNUSED_PARAMETER(flags); return SQLITE_OK; } /* ** Return the current file-size of an memdb-file. */ static int memdbFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){ MemStore *p = ((MemFile*)pFile)->pStore; memdbEnter(p); *pSize = p->sz; memdbLeave(p); return SQLITE_OK; } /* ** Lock an memdb-file. */ static int memdbLock(sqlite3_file *pFile, int eLock){ MemFile *pThis = (MemFile*)pFile; MemStore *p = pThis->pStore; int rc = SQLITE_OK; if( eLock==pThis->eLock ) return SQLITE_OK; memdbEnter(p); if( eLock>SQLITE_LOCK_SHARED ){ if( p->mFlags & SQLITE_DESERIALIZE_READONLY ){ rc = SQLITE_READONLY; }else if( pThis->eLock<=SQLITE_LOCK_SHARED ){ if( p->nWrLock ){ rc = SQLITE_BUSY; }else{ p->nWrLock = 1; } } }else if( eLock==SQLITE_LOCK_SHARED ){ if( pThis->eLock > SQLITE_LOCK_SHARED ){ assert( p->nWrLock==1 ); p->nWrLock = 0; }else if( p->nWrLock ){ rc = SQLITE_BUSY; }else{ p->nRdLock++; } }else{ assert( eLock==SQLITE_LOCK_NONE ); if( pThis->eLock>SQLITE_LOCK_SHARED ){ assert( p->nWrLock==1 ); p->nWrLock = 0; } assert( p->nRdLock>0 ); p->nRdLock--; } if( rc==SQLITE_OK ) pThis->eLock = eLock; memdbLeave(p); return rc; } #if 0 /* ** This interface is only used for crash recovery, which does not ** occur on an in-memory database. */ static int memdbCheckReservedLock(sqlite3_file *pFile, int *pResOut){ *pResOut = 0; return SQLITE_OK; } #endif /* ** File control method. For custom operations on an memdb-file. */ static int memdbFileControl(sqlite3_file *pFile, int op, void *pArg){ MemStore *p = ((MemFile*)pFile)->pStore; int rc = SQLITE_NOTFOUND; memdbEnter(p); if( op==SQLITE_FCNTL_VFSNAME ){ *(char**)pArg = sqlite3_mprintf("memdb(%p,%lld)", p->aData, p->sz); rc = SQLITE_OK; } if( op==SQLITE_FCNTL_SIZE_LIMIT ){ sqlite3_int64 iLimit = *(sqlite3_int64*)pArg; if( iLimit<p->sz ){ if( iLimit<0 ){ iLimit = p->szMax; }else{ iLimit = p->sz; } } p->szMax = iLimit; *(sqlite3_int64*)pArg = iLimit; rc = SQLITE_OK; } memdbLeave(p); return rc; } #if 0 /* Not used because of SQLITE_IOCAP_POWERSAFE_OVERWRITE */ /* ** Return the sector-size in bytes for an memdb-file. */ static int memdbSectorSize(sqlite3_file *pFile){ return 1024; } #endif /* ** Return the device characteristic flags supported by an memdb-file. */ static int memdbDeviceCharacteristics(sqlite3_file *pFile){ UNUSED_PARAMETER(pFile); return SQLITE_IOCAP_ATOMIC | SQLITE_IOCAP_POWERSAFE_OVERWRITE | SQLITE_IOCAP_SAFE_APPEND | SQLITE_IOCAP_SEQUENTIAL; } /* Fetch a page of a memory-mapped file */ static int memdbFetch( sqlite3_file *pFile, sqlite3_int64 iOfst, int iAmt, void **pp ){ MemStore *p = ((MemFile*)pFile)->pStore; memdbEnter(p); if( iOfst+iAmt>p->sz || (p->mFlags & SQLITE_DESERIALIZE_RESIZEABLE)!=0 ){ *pp = 0; }else{ p->nMmap++; *pp = (void*)(p->aData + iOfst); } memdbLeave(p); return SQLITE_OK; } /* Release a memory-mapped page */ static int memdbUnfetch(sqlite3_file *pFile, sqlite3_int64 iOfst, void *pPage){ MemStore *p = ((MemFile*)pFile)->pStore; UNUSED_PARAMETER(iOfst); UNUSED_PARAMETER(pPage); memdbEnter(p); p->nMmap--; memdbLeave(p); return SQLITE_OK; } /* ** Open an mem file handle. */ static int memdbOpen( sqlite3_vfs *pVfs, const char *zName, sqlite3_file *pFd, int flags, int *pOutFlags ){ MemFile *pFile = (MemFile*)pFd; MemStore *p = 0; int szName; UNUSED_PARAMETER(pVfs); memset(pFile, 0, sizeof(*pFile)); szName = sqlite3Strlen30(zName); if( szName>1 && zName[0]=='/' ){ int i; #ifndef SQLITE_MUTEX_OMIT sqlite3_mutex *pVfsMutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1); #endif sqlite3_mutex_enter(pVfsMutex); for(i=0; i<memdb_g.nMemStore; i++){ if( strcmp(memdb_g.apMemStore[i]->zFName,zName)==0 ){ p = memdb_g.apMemStore[i]; break; } } if( p==0 ){ MemStore **apNew; p = sqlite3Malloc( sizeof(*p) + szName + 3 ); if( p==0 ){ sqlite3_mutex_leave(pVfsMutex); return SQLITE_NOMEM; } apNew = sqlite3Realloc(memdb_g.apMemStore, sizeof(apNew[0])*(memdb_g.nMemStore+1) ); if( apNew==0 ){ sqlite3_free(p); sqlite3_mutex_leave(pVfsMutex); return SQLITE_NOMEM; } apNew[memdb_g.nMemStore++] = p; memdb_g.apMemStore = apNew; memset(p, 0, sizeof(*p)); p->mFlags = SQLITE_DESERIALIZE_RESIZEABLE|SQLITE_DESERIALIZE_FREEONCLOSE; p->szMax = sqlite3GlobalConfig.mxMemdbSize; p->zFName = (char*)&p[1]; memcpy(p->zFName, zName, szName+1); p->pMutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST); if( p->pMutex==0 ){ memdb_g.nMemStore--; sqlite3_free(p); sqlite3_mutex_leave(pVfsMutex); return SQLITE_NOMEM; } p->nRef = 1; memdbEnter(p); }else{ memdbEnter(p); p->nRef++; } sqlite3_mutex_leave(pVfsMutex); }else{ p = sqlite3Malloc( sizeof(*p) ); if( p==0 ){ return SQLITE_NOMEM; } memset(p, 0, sizeof(*p)); p->mFlags = SQLITE_DESERIALIZE_RESIZEABLE | SQLITE_DESERIALIZE_FREEONCLOSE; p->szMax = sqlite3GlobalConfig.mxMemdbSize; } pFile->pStore = p; if( pOutFlags!=0 ){ *pOutFlags = flags | SQLITE_OPEN_MEMORY; } pFd->pMethods = &memdb_io_methods; memdbLeave(p); return SQLITE_OK; } #if 0 /* Only used to delete rollback journals, super-journals, and WAL ** files, none of which exist in memdb. So this routine is never used */ /* ** Delete the file located at zPath. If the dirSync argument is true, ** ensure the file-system modifications are synced to disk before ** returning. */ static int memdbDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){ |
︙ | ︙ | |||
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 | */ static int memdbAccess( sqlite3_vfs *pVfs, const char *zPath, int flags, int *pResOut ){ *pResOut = 0; return SQLITE_OK; } /* ** Populate buffer zOut with the full canonical pathname corresponding ** to the pathname in zPath. zOut is guaranteed to point to a buffer ** of at least (INST_MAX_PATHNAME+1) bytes. */ static int memdbFullPathname( sqlite3_vfs *pVfs, const char *zPath, int nOut, char *zOut ){ sqlite3_snprintf(nOut, zOut, "%s", zPath); return SQLITE_OK; } /* ** Open the dynamic library located at zPath and return a handle. */ | > > > > | 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 | */ static int memdbAccess( sqlite3_vfs *pVfs, const char *zPath, int flags, int *pResOut ){ UNUSED_PARAMETER(pVfs); UNUSED_PARAMETER(zPath); UNUSED_PARAMETER(flags); *pResOut = 0; return SQLITE_OK; } /* ** Populate buffer zOut with the full canonical pathname corresponding ** to the pathname in zPath. zOut is guaranteed to point to a buffer ** of at least (INST_MAX_PATHNAME+1) bytes. */ static int memdbFullPathname( sqlite3_vfs *pVfs, const char *zPath, int nOut, char *zOut ){ UNUSED_PARAMETER(pVfs); sqlite3_snprintf(nOut, zOut, "%s", zPath); return SQLITE_OK; } /* ** Open the dynamic library located at zPath and return a handle. */ |
︙ | ︙ | |||
421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 | /* ** Translate a database connection pointer and schema name into a ** MemFile pointer. */ static MemFile *memdbFromDbSchema(sqlite3 *db, const char *zSchema){ MemFile *p = 0; int rc = sqlite3_file_control(db, zSchema, SQLITE_FCNTL_FILE_POINTER, &p); if( rc ) return 0; if( p->base.pMethods!=&memdb_io_methods ) return 0; return p; } /* ** Return the serialization of a database */ unsigned char *sqlite3_serialize( | > > > > > | 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 | /* ** Translate a database connection pointer and schema name into a ** MemFile pointer. */ static MemFile *memdbFromDbSchema(sqlite3 *db, const char *zSchema){ MemFile *p = 0; MemStore *pStore; int rc = sqlite3_file_control(db, zSchema, SQLITE_FCNTL_FILE_POINTER, &p); if( rc ) return 0; if( p->base.pMethods!=&memdb_io_methods ) return 0; pStore = p->pStore; memdbEnter(pStore); if( pStore->zFName!=0 ) p = 0; memdbLeave(pStore); return p; } /* ** Return the serialization of a database */ unsigned char *sqlite3_serialize( |
︙ | ︙ | |||
459 460 461 462 463 464 465 | if( zSchema==0 ) zSchema = db->aDb[0].zDbSName; p = memdbFromDbSchema(db, zSchema); iDb = sqlite3FindDbName(db, zSchema); if( piSize ) *piSize = -1; if( iDb<0 ) return 0; if( p ){ | > > | | | | | 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 | if( zSchema==0 ) zSchema = db->aDb[0].zDbSName; p = memdbFromDbSchema(db, zSchema); iDb = sqlite3FindDbName(db, zSchema); if( piSize ) *piSize = -1; if( iDb<0 ) return 0; if( p ){ MemStore *pStore = p->pStore; assert( pStore->pMutex==0 ); if( piSize ) *piSize = pStore->sz; if( mFlags & SQLITE_SERIALIZE_NOCOPY ){ pOut = pStore->aData; }else{ pOut = sqlite3_malloc64( pStore->sz ); if( pOut ) memcpy(pOut, pStore->aData, pStore->sz); } return pOut; } pBt = db->aDb[iDb].pBt; if( pBt==0 ) return 0; szPage = sqlite3BtreeGetPageSize(pBt); zSql = sqlite3_mprintf("PRAGMA \"%w\".page_count", zSchema); |
︙ | ︙ | |||
534 535 536 537 538 539 540 | if( szDb<0 ) return SQLITE_MISUSE_BKPT; if( szBuf<0 ) return SQLITE_MISUSE_BKPT; #endif sqlite3_mutex_enter(db->mutex); if( zSchema==0 ) zSchema = db->aDb[0].zDbSName; iDb = sqlite3FindDbName(db, zSchema); | > | | > > > | | > > | > | > | > > > | > > > > > | < < | > > > | | | 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 | if( szDb<0 ) return SQLITE_MISUSE_BKPT; if( szBuf<0 ) return SQLITE_MISUSE_BKPT; #endif sqlite3_mutex_enter(db->mutex); if( zSchema==0 ) zSchema = db->aDb[0].zDbSName; iDb = sqlite3FindDbName(db, zSchema); testcase( iDb==1 ); if( iDb<2 && iDb!=0 ){ rc = SQLITE_ERROR; goto end_deserialize; } zSql = sqlite3_mprintf("ATTACH x AS %Q", zSchema); if( zSql==0 ){ rc = SQLITE_NOMEM; }else{ rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0); sqlite3_free(zSql); } if( rc ) goto end_deserialize; db->init.iDb = (u8)iDb; db->init.reopenMemdb = 1; rc = sqlite3_step(pStmt); db->init.reopenMemdb = 0; if( rc!=SQLITE_DONE ){ rc = SQLITE_ERROR; goto end_deserialize; } p = memdbFromDbSchema(db, zSchema); if( p==0 ){ rc = SQLITE_ERROR; }else{ MemStore *pStore = p->pStore; pStore->aData = pData; pData = 0; pStore->sz = szDb; pStore->szAlloc = szBuf; pStore->szMax = szBuf; if( pStore->szMax<sqlite3GlobalConfig.mxMemdbSize ){ pStore->szMax = sqlite3GlobalConfig.mxMemdbSize; } pStore->mFlags = mFlags; rc = SQLITE_OK; } end_deserialize: sqlite3_finalize(pStmt); if( pData && (mFlags & SQLITE_DESERIALIZE_FREEONCLOSE)!=0 ){ sqlite3_free(pData); } sqlite3_mutex_leave(db->mutex); return rc; } /* ** This routine is called when the extension is loaded. ** Register the new VFS. */ int sqlite3MemdbInit(void){ sqlite3_vfs *pLower = sqlite3_vfs_find(0); unsigned int sz; if( NEVER(pLower==0) ) return SQLITE_ERROR; sz = pLower->szOsFile; memdb_vfs.pAppData = pLower; /* The following conditional can only be true when compiled for ** Windows x86 and SQLITE_MAX_MMAP_SIZE=0. We always leave ** it in, to be safe, but it is marked as NO_TEST since there ** is no way to reach it under most builds. */ if( sz<sizeof(MemFile) ) sz = sizeof(MemFile); /*NO_TEST*/ memdb_vfs.szOsFile = sz; return sqlite3_vfs_register(&memdb_vfs, 0); } #endif /* SQLITE_OMIT_DESERIALIZE */ |
Changes to src/memjournal.c.
︙ | ︙ | |||
66 67 68 69 70 71 72 | ** is an instance of this class. */ struct MemJournal { const sqlite3_io_methods *pMethod; /* Parent class. MUST BE FIRST */ int nChunkSize; /* In-memory chunk-size */ int nSpill; /* Bytes of data before flushing */ | < | 66 67 68 69 70 71 72 73 74 75 76 77 78 79 | ** is an instance of this class. */ struct MemJournal { const sqlite3_io_methods *pMethod; /* Parent class. MUST BE FIRST */ int nChunkSize; /* In-memory chunk-size */ int nSpill; /* Bytes of data before flushing */ FileChunk *pFirst; /* Head of in-memory chunk-list */ FilePoint endpoint; /* Pointer to the end of the file */ FilePoint readpoint; /* Pointer to the end of the last xRead() */ int flags; /* xOpen flags */ sqlite3_vfs *pVfs; /* The "real" underlying VFS */ const char *zJournal; /* Name of the journal file */ |
︙ | ︙ | |||
92 93 94 95 96 97 98 | ){ MemJournal *p = (MemJournal *)pJfd; u8 *zOut = zBuf; int nRead = iAmt; int iChunkOffset; FileChunk *pChunk; | < < < < < | 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 | ){ MemJournal *p = (MemJournal *)pJfd; u8 *zOut = zBuf; int nRead = iAmt; int iChunkOffset; FileChunk *pChunk; if( (iAmt+iOfst)>p->endpoint.iOffset ){ return SQLITE_IOERR_SHORT_READ; } assert( p->readpoint.iOffset==0 || p->readpoint.pChunk!=0 ); if( p->readpoint.iOffset!=iOfst || iOfst==0 ){ sqlite3_int64 iOff = 0; for(pChunk=p->pFirst; ALWAYS(pChunk) && (iOff+p->nChunkSize)<=iOfst; pChunk=pChunk->pNext ){ |
︙ | ︙ | |||
132 133 134 135 136 137 138 | return SQLITE_OK; } /* ** Free the list of FileChunk structures headed at MemJournal.pFirst. */ | | | < | 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 | return SQLITE_OK; } /* ** Free the list of FileChunk structures headed at MemJournal.pFirst. */ static void memjrnlFreeChunks(FileChunk *pFirst){ FileChunk *pIter; FileChunk *pNext; for(pIter=pFirst; pIter; pIter=pNext){ pNext = pIter->pNext; sqlite3_free(pIter); } } /* ** Flush the contents of memory to a real file on disk. */ static int memjrnlCreateFile(MemJournal *p){ int rc; |
︙ | ︙ | |||
166 167 168 169 170 171 172 | } rc = sqlite3OsWrite(pReal, (u8*)pIter->zChunk, nChunk, iOff); if( rc ) break; iOff += nChunk; } if( rc==SQLITE_OK ){ /* No error has occurred. Free the in-memory buffers. */ | | | 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 | } rc = sqlite3OsWrite(pReal, (u8*)pIter->zChunk, nChunk, iOff); if( rc ) break; iOff += nChunk; } if( rc==SQLITE_OK ){ /* No error has occurred. Free the in-memory buffers. */ memjrnlFreeChunks(copy.pFirst); } } if( rc!=SQLITE_OK ){ /* If an error occurred while creating or writing to the file, restore ** the original before returning. This way, SQLite uses the in-memory ** journal data to roll back changes made to the internal page-cache ** before this function was called. */ |
︙ | ︙ | |||
249 250 251 252 253 254 255 | } memcpy((u8*)p->endpoint.pChunk->zChunk + iChunkOffset, zWrite, iSpace); zWrite += iSpace; nWrite -= iSpace; p->endpoint.iOffset += iSpace; } | < | < < < < > > > > > > > > > > > | | | > > > | | | | 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 | } memcpy((u8*)p->endpoint.pChunk->zChunk + iChunkOffset, zWrite, iSpace); zWrite += iSpace; nWrite -= iSpace; p->endpoint.iOffset += iSpace; } } } return SQLITE_OK; } /* ** Truncate the in-memory file. */ static int memjrnlTruncate(sqlite3_file *pJfd, sqlite_int64 size){ MemJournal *p = (MemJournal *)pJfd; assert( p->endpoint.pChunk==0 || p->endpoint.pChunk->pNext==0 ); if( size<p->endpoint.iOffset ){ FileChunk *pIter = 0; if( size==0 ){ memjrnlFreeChunks(p->pFirst); p->pFirst = 0; }else{ i64 iOff = p->nChunkSize; for(pIter=p->pFirst; ALWAYS(pIter) && iOff<=size; pIter=pIter->pNext){ iOff += p->nChunkSize; } if( ALWAYS(pIter) ){ memjrnlFreeChunks(pIter->pNext); pIter->pNext = 0; } } p->endpoint.pChunk = pIter; p->endpoint.iOffset = size; p->readpoint.pChunk = 0; p->readpoint.iOffset = 0; } return SQLITE_OK; } /* ** Close the file. */ static int memjrnlClose(sqlite3_file *pJfd){ MemJournal *p = (MemJournal *)pJfd; memjrnlFreeChunks(p->pFirst); return SQLITE_OK; } /* ** Sync the file. ** ** If the real file has been created, call its xSync method. Otherwise, |
︙ | ︙ | |||
367 368 369 370 371 372 373 | if( nSpill>0 ){ p->nChunkSize = nSpill; }else{ p->nChunkSize = 8 + MEMJOURNAL_DFLT_FILECHUNKSIZE - sizeof(FileChunk); assert( MEMJOURNAL_DFLT_FILECHUNKSIZE==fileChunkSize(p->nChunkSize) ); } | | | 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 | if( nSpill>0 ){ p->nChunkSize = nSpill; }else{ p->nChunkSize = 8 + MEMJOURNAL_DFLT_FILECHUNKSIZE - sizeof(FileChunk); assert( MEMJOURNAL_DFLT_FILECHUNKSIZE==fileChunkSize(p->nChunkSize) ); } pJfd->pMethods = (const sqlite3_io_methods*)&MemJournalMethods; p->nSpill = nSpill; p->flags = flags; p->zJournal = zName; p->pVfs = pVfs; return SQLITE_OK; } |
︙ | ︙ | |||
393 394 395 396 397 398 399 | ** in-memory-only journal file (i.e. is one that was opened with a +ve ** nSpill parameter or as SQLITE_OPEN_MAIN_JOURNAL), and the underlying ** file has not yet been created, create it now. */ int sqlite3JournalCreate(sqlite3_file *pJfd){ int rc = SQLITE_OK; MemJournal *p = (MemJournal*)pJfd; | | | 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 | ** in-memory-only journal file (i.e. is one that was opened with a +ve ** nSpill parameter or as SQLITE_OPEN_MAIN_JOURNAL), and the underlying ** file has not yet been created, create it now. */ int sqlite3JournalCreate(sqlite3_file *pJfd){ int rc = SQLITE_OK; MemJournal *p = (MemJournal*)pJfd; if( pJfd->pMethods==&MemJournalMethods && ( #ifdef SQLITE_ENABLE_ATOMIC_WRITE p->nSpill>0 #else /* While this appears to not be possible without ATOMIC_WRITE, the ** paths are complex, so it seems prudent to leave the test in as ** a NEVER(), in case our analysis is subtly flawed. */ NEVER(p->nSpill>0) |
︙ | ︙ |
Changes to src/msvc.h.
︙ | ︙ | |||
29 30 31 32 33 34 35 36 | #pragma warning(disable : 4244) #pragma warning(disable : 4305) #pragma warning(disable : 4306) #pragma warning(disable : 4702) #pragma warning(disable : 4706) #endif /* defined(_MSC_VER) */ #endif /* SQLITE_MSVC_H */ | > > > > > | 29 30 31 32 33 34 35 36 37 38 39 40 41 | #pragma warning(disable : 4244) #pragma warning(disable : 4305) #pragma warning(disable : 4306) #pragma warning(disable : 4702) #pragma warning(disable : 4706) #endif /* defined(_MSC_VER) */ #if defined(_MSC_VER) && !defined(_WIN64) #undef SQLITE_4_BYTE_ALIGNED_MALLOC #define SQLITE_4_BYTE_ALIGNED_MALLOC #endif /* defined(_MSC_VER) && !defined(_WIN64) */ #endif /* SQLITE_MSVC_H */ |
Changes to src/mutex.c.
︙ | ︙ | |||
250 251 252 253 254 255 256 257 258 259 260 261 262 263 | assert( sqlite3GlobalConfig.mutex.xMutexInit ); rc = sqlite3GlobalConfig.mutex.xMutexInit(); #ifdef SQLITE_DEBUG GLOBAL(int, mutexIsInit) = 1; #endif return rc; } /* ** Shutdown the mutex system. This call frees resources allocated by ** sqlite3MutexInit(). */ | > | 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 | assert( sqlite3GlobalConfig.mutex.xMutexInit ); rc = sqlite3GlobalConfig.mutex.xMutexInit(); #ifdef SQLITE_DEBUG GLOBAL(int, mutexIsInit) = 1; #endif sqlite3MemoryBarrier(); return rc; } /* ** Shutdown the mutex system. This call frees resources allocated by ** sqlite3MutexInit(). */ |
︙ | ︙ |
Changes to src/mutex.h.
︙ | ︙ | |||
63 64 65 66 67 68 69 70 | #define sqlite3_mutex_notheld(X) ((void)(X),1) #define sqlite3MutexAlloc(X) ((sqlite3_mutex*)8) #define sqlite3MutexInit() SQLITE_OK #define sqlite3MutexEnd() #define MUTEX_LOGIC(X) #else #define MUTEX_LOGIC(X) X #endif /* defined(SQLITE_MUTEX_OMIT) */ | > | 63 64 65 66 67 68 69 70 71 | #define sqlite3_mutex_notheld(X) ((void)(X),1) #define sqlite3MutexAlloc(X) ((sqlite3_mutex*)8) #define sqlite3MutexInit() SQLITE_OK #define sqlite3MutexEnd() #define MUTEX_LOGIC(X) #else #define MUTEX_LOGIC(X) X int sqlite3_mutex_held(sqlite3_mutex*); #endif /* defined(SQLITE_MUTEX_OMIT) */ |
Changes to src/mutex_unix.c.
︙ | ︙ | |||
108 109 110 111 112 113 114 | ** that means that a mutex could not be allocated. SQLite ** will unwind its stack and return an error. The argument ** to sqlite3_mutex_alloc() is one of these integer constants: ** ** <ul> ** <li> SQLITE_MUTEX_FAST ** <li> SQLITE_MUTEX_RECURSIVE | | | 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 | ** that means that a mutex could not be allocated. SQLite ** will unwind its stack and return an error. The argument ** to sqlite3_mutex_alloc() is one of these integer constants: ** ** <ul> ** <li> SQLITE_MUTEX_FAST ** <li> SQLITE_MUTEX_RECURSIVE ** <li> SQLITE_MUTEX_STATIC_MAIN ** <li> SQLITE_MUTEX_STATIC_MEM ** <li> SQLITE_MUTEX_STATIC_OPEN ** <li> SQLITE_MUTEX_STATIC_PRNG ** <li> SQLITE_MUTEX_STATIC_LRU ** <li> SQLITE_MUTEX_STATIC_PMEM ** <li> SQLITE_MUTEX_STATIC_APP1 ** <li> SQLITE_MUTEX_STATIC_APP2 |
︙ | ︙ |
Changes to src/mutex_w32.c.
︙ | ︙ | |||
167 168 169 170 171 172 173 | ** that means that a mutex could not be allocated. SQLite ** will unwind its stack and return an error. The argument ** to sqlite3_mutex_alloc() is one of these integer constants: ** ** <ul> ** <li> SQLITE_MUTEX_FAST ** <li> SQLITE_MUTEX_RECURSIVE | | | 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 | ** that means that a mutex could not be allocated. SQLite ** will unwind its stack and return an error. The argument ** to sqlite3_mutex_alloc() is one of these integer constants: ** ** <ul> ** <li> SQLITE_MUTEX_FAST ** <li> SQLITE_MUTEX_RECURSIVE ** <li> SQLITE_MUTEX_STATIC_MAIN ** <li> SQLITE_MUTEX_STATIC_MEM ** <li> SQLITE_MUTEX_STATIC_OPEN ** <li> SQLITE_MUTEX_STATIC_PRNG ** <li> SQLITE_MUTEX_STATIC_LRU ** <li> SQLITE_MUTEX_STATIC_PMEM ** <li> SQLITE_MUTEX_STATIC_APP1 ** <li> SQLITE_MUTEX_STATIC_APP2 |
︙ | ︙ |
Changes to src/notify.c.
︙ | ︙ | |||
25 26 27 28 29 30 31 | ** sqlite3ConnectionBlocked() ** sqlite3ConnectionUnlocked() ** sqlite3ConnectionClosed() ** sqlite3_unlock_notify() */ #define assertMutexHeld() \ | | | | 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | ** sqlite3ConnectionBlocked() ** sqlite3ConnectionUnlocked() ** sqlite3ConnectionClosed() ** sqlite3_unlock_notify() */ #define assertMutexHeld() \ assert( sqlite3_mutex_held(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN)) ) /* ** Head of a linked list of all sqlite3 objects created by this process ** for which either sqlite3.pBlockingConnection or sqlite3.pUnlockConnection ** is not NULL. This variable may only accessed while the STATIC_MAIN ** mutex is held. */ static sqlite3 *SQLITE_WSD sqlite3BlockedList = 0; #ifndef NDEBUG /* ** This function is a complex assert() that verifies the following |
︙ | ︙ | |||
104 105 106 107 108 109 110 | pp=&(*pp)->pNextBlocked ); db->pNextBlocked = *pp; *pp = db; } /* | | | | | | 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 | pp=&(*pp)->pNextBlocked ); db->pNextBlocked = *pp; *pp = db; } /* ** Obtain the STATIC_MAIN mutex. */ static void enterMutex(void){ sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN)); checkListProperties(0); } /* ** Release the STATIC_MAIN mutex. */ static void leaveMutex(void){ assertMutexHeld(); checkListProperties(0); sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN)); } /* ** Register an unlock-notify callback. ** ** This is called after connection "db" has attempted some operation ** but has received an SQLITE_LOCKED error because another connection |
︙ | ︙ | |||
228 229 230 231 232 233 234 | int nArg = 0; /* Number of entries in aArg[] */ sqlite3 **pp; /* Iterator variable */ void **aArg; /* Arguments to the unlock callback */ void **aDyn = 0; /* Dynamically allocated space for aArg[] */ void *aStatic[16]; /* Starter space for aArg[]. No malloc required */ aArg = aStatic; | | | 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 | int nArg = 0; /* Number of entries in aArg[] */ sqlite3 **pp; /* Iterator variable */ void **aArg; /* Arguments to the unlock callback */ void **aDyn = 0; /* Dynamically allocated space for aArg[] */ void *aStatic[16]; /* Starter space for aArg[]. No malloc required */ aArg = aStatic; enterMutex(); /* Enter STATIC_MAIN mutex */ /* This loop runs once for each entry in the blocked-connections list. */ for(pp=&sqlite3BlockedList; *pp; /* no-op */ ){ sqlite3 *p = *pp; /* Step 1. */ if( p->pBlockingConnection==db ){ |
︙ | ︙ | |||
311 312 313 314 315 316 317 | } } if( nArg!=0 ){ xUnlockNotify(aArg, nArg); } sqlite3_free(aDyn); | | | 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 | } } if( nArg!=0 ){ xUnlockNotify(aArg, nArg); } sqlite3_free(aDyn); leaveMutex(); /* Leave STATIC_MAIN mutex */ } /* ** This is called when the database connection passed as an argument is ** being closed. The connection is removed from the blocked list. */ void sqlite3ConnectionClosed(sqlite3 *db){ |
︙ | ︙ |
Changes to src/os.c.
︙ | ︙ | |||
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 | ** routine has no return value since the return value would be meaningless. */ int sqlite3OsFileControl(sqlite3_file *id, int op, void *pArg){ if( id->pMethods==0 ) return SQLITE_NOTFOUND; #ifdef SQLITE_TEST if( op!=SQLITE_FCNTL_COMMIT_PHASETWO && op!=SQLITE_FCNTL_LOCK_TIMEOUT ){ /* Faults are not injected into COMMIT_PHASETWO because, assuming SQLite ** is using a regular VFS, it is called after the corresponding ** transaction has been committed. Injecting a fault at this point ** confuses the test scripts - the COMMIT comand returns SQLITE_NOMEM ** but the transaction is committed anyway. ** ** The core must call OsFileControl() though, not OsFileControlHint(), ** as if a custom VFS (e.g. zipvfs) returns an error here, it probably ** means the commit really has failed and an error should be returned | > > | > > > > > > | 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 | ** routine has no return value since the return value would be meaningless. */ int sqlite3OsFileControl(sqlite3_file *id, int op, void *pArg){ if( id->pMethods==0 ) return SQLITE_NOTFOUND; #ifdef SQLITE_TEST if( op!=SQLITE_FCNTL_COMMIT_PHASETWO && op!=SQLITE_FCNTL_LOCK_TIMEOUT && op!=SQLITE_FCNTL_CKPT_DONE && op!=SQLITE_FCNTL_CKPT_START ){ /* Faults are not injected into COMMIT_PHASETWO because, assuming SQLite ** is using a regular VFS, it is called after the corresponding ** transaction has been committed. Injecting a fault at this point ** confuses the test scripts - the COMMIT comand returns SQLITE_NOMEM ** but the transaction is committed anyway. ** ** The core must call OsFileControl() though, not OsFileControlHint(), ** as if a custom VFS (e.g. zipvfs) returns an error here, it probably ** means the commit really has failed and an error should be returned ** to the user. ** ** The CKPT_DONE and CKPT_START file-controls are write-only signals ** to the cksumvfs. Their return code is meaningless and is ignored ** by the SQLite core, so there is no point in simulating OOMs for them. */ DO_OS_MALLOC_TEST(id); } #endif return id->pMethods->xFileControl(id, op, pArg); } void sqlite3OsFileControlHint(sqlite3_file *id, int op, void *pArg){ if( id->pMethods ) (void)id->pMethods->xFileControl(id, op, pArg); } int sqlite3OsSectorSize(sqlite3_file *id){ int (*xSectorSize)(sqlite3_file*) = id->pMethods->xSectorSize; return (xSectorSize ? xSectorSize(id) : SQLITE_DEFAULT_SECTOR_SIZE); } int sqlite3OsDeviceCharacteristics(sqlite3_file *id){ if( NEVER(id->pMethods==0) ) return 0; return id->pMethods->xDeviceCharacteristics(id); } #ifndef SQLITE_OMIT_WAL int sqlite3OsShmLock(sqlite3_file *id, int offset, int n, int flags){ return id->pMethods->xShmLock(id, offset, n, flags); } void sqlite3OsShmBarrier(sqlite3_file *id){ |
︙ | ︙ | |||
211 212 213 214 215 216 217 | ){ int rc; DO_OS_MALLOC_TEST(0); /* 0x87f7f is a mask of SQLITE_OPEN_ flags that are valid to be passed ** down into the VFS layer. Some SQLITE_OPEN_ flags (for example, ** SQLITE_OPEN_FULLMUTEX or SQLITE_OPEN_SHAREDCACHE) are blocked before ** reaching the VFS. */ | | | | 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 | ){ int rc; DO_OS_MALLOC_TEST(0); /* 0x87f7f is a mask of SQLITE_OPEN_ flags that are valid to be passed ** down into the VFS layer. Some SQLITE_OPEN_ flags (for example, ** SQLITE_OPEN_FULLMUTEX or SQLITE_OPEN_SHAREDCACHE) are blocked before ** reaching the VFS. */ rc = pVfs->xOpen(pVfs, zPath, pFile, flags & 0x1087f7f, pFlagsOut); assert( rc==SQLITE_OK || pFile->pMethods==0 ); return rc; } int sqlite3OsDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){ DO_OS_MALLOC_TEST(0); assert( dirSync==0 || dirSync==1 ); return pVfs->xDelete!=0 ? pVfs->xDelete(pVfs, zPath, dirSync) : SQLITE_OK; } int sqlite3OsAccess( sqlite3_vfs *pVfs, const char *zPath, int flags, int *pResOut ){ |
︙ | ︙ | |||
241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 | ){ DO_OS_MALLOC_TEST(0); zPathOut[0] = 0; return pVfs->xFullPathname(pVfs, zPath, nPathOut, zPathOut); } #ifndef SQLITE_OMIT_LOAD_EXTENSION void *sqlite3OsDlOpen(sqlite3_vfs *pVfs, const char *zPath){ return pVfs->xDlOpen(pVfs, zPath); } void sqlite3OsDlError(sqlite3_vfs *pVfs, int nByte, char *zBufOut){ pVfs->xDlError(pVfs, nByte, zBufOut); } void (*sqlite3OsDlSym(sqlite3_vfs *pVfs, void *pHdle, const char *zSym))(void){ return pVfs->xDlSym(pVfs, pHdle, zSym); } void sqlite3OsDlClose(sqlite3_vfs *pVfs, void *pHandle){ pVfs->xDlClose(pVfs, pHandle); } #endif /* SQLITE_OMIT_LOAD_EXTENSION */ int sqlite3OsRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){ | > > > > > > > > | > > | 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 | ){ DO_OS_MALLOC_TEST(0); zPathOut[0] = 0; return pVfs->xFullPathname(pVfs, zPath, nPathOut, zPathOut); } #ifndef SQLITE_OMIT_LOAD_EXTENSION void *sqlite3OsDlOpen(sqlite3_vfs *pVfs, const char *zPath){ assert( zPath!=0 ); assert( strlen(zPath)<=SQLITE_MAX_PATHLEN ); /* tag-20210611-1 */ return pVfs->xDlOpen(pVfs, zPath); } void sqlite3OsDlError(sqlite3_vfs *pVfs, int nByte, char *zBufOut){ pVfs->xDlError(pVfs, nByte, zBufOut); } void (*sqlite3OsDlSym(sqlite3_vfs *pVfs, void *pHdle, const char *zSym))(void){ return pVfs->xDlSym(pVfs, pHdle, zSym); } void sqlite3OsDlClose(sqlite3_vfs *pVfs, void *pHandle){ pVfs->xDlClose(pVfs, pHandle); } #endif /* SQLITE_OMIT_LOAD_EXTENSION */ int sqlite3OsRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){ if( sqlite3Config.iPrngSeed ){ memset(zBufOut, 0, nByte); if( ALWAYS(nByte>(signed)sizeof(unsigned)) ) nByte = sizeof(unsigned int); memcpy(zBufOut, &sqlite3Config.iPrngSeed, nByte); return SQLITE_OK; }else{ return pVfs->xRandomness(pVfs, nByte, zBufOut); } } int sqlite3OsSleep(sqlite3_vfs *pVfs, int nMicro){ return pVfs->xSleep(pVfs, nMicro); } int sqlite3OsGetLastError(sqlite3_vfs *pVfs){ return pVfs->xGetLastError ? pVfs->xGetLastError(pVfs, 0, 0) : 0; } |
︙ | ︙ | |||
294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 | int rc; sqlite3_file *pFile; pFile = (sqlite3_file *)sqlite3MallocZero(pVfs->szOsFile); if( pFile ){ rc = sqlite3OsOpen(pVfs, zFile, pFile, flags, pOutFlags); if( rc!=SQLITE_OK ){ sqlite3_free(pFile); }else{ *ppFile = pFile; } }else{ rc = SQLITE_NOMEM_BKPT; } return rc; } void sqlite3OsCloseFree(sqlite3_file *pFile){ assert( pFile ); sqlite3OsClose(pFile); sqlite3_free(pFile); } | > > > | 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 | int rc; sqlite3_file *pFile; pFile = (sqlite3_file *)sqlite3MallocZero(pVfs->szOsFile); if( pFile ){ rc = sqlite3OsOpen(pVfs, zFile, pFile, flags, pOutFlags); if( rc!=SQLITE_OK ){ sqlite3_free(pFile); *ppFile = 0; }else{ *ppFile = pFile; } }else{ *ppFile = 0; rc = SQLITE_NOMEM_BKPT; } assert( *ppFile!=0 || rc!=SQLITE_OK ); return rc; } void sqlite3OsCloseFree(sqlite3_file *pFile){ assert( pFile ); sqlite3OsClose(pFile); sqlite3_free(pFile); } |
︙ | ︙ | |||
341 342 343 344 345 346 347 | sqlite3_mutex *mutex; #endif #ifndef SQLITE_OMIT_AUTOINIT int rc = sqlite3_initialize(); if( rc ) return 0; #endif #if SQLITE_THREADSAFE | | | | 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 | sqlite3_mutex *mutex; #endif #ifndef SQLITE_OMIT_AUTOINIT int rc = sqlite3_initialize(); if( rc ) return 0; #endif #if SQLITE_THREADSAFE mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN); #endif sqlite3_mutex_enter(mutex); for(pVfs = vfsList; pVfs; pVfs=pVfs->pNext){ if( zVfs==0 ) break; if( strcmp(zVfs, pVfs->zName)==0 ) break; } sqlite3_mutex_leave(mutex); return pVfs; } /* ** Unlink a VFS from the linked list */ static void vfsUnlink(sqlite3_vfs *pVfs){ assert( sqlite3_mutex_held(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN)) ); if( pVfs==0 ){ /* No-op */ }else if( vfsList==pVfs ){ vfsList = pVfs->pNext; }else if( vfsList ){ sqlite3_vfs *p = vfsList; while( p->pNext && p->pNext!=pVfs ){ |
︙ | ︙ | |||
387 388 389 390 391 392 393 | int rc = sqlite3_initialize(); if( rc ) return rc; #endif #ifdef SQLITE_ENABLE_API_ARMOR if( pVfs==0 ) return SQLITE_MISUSE_BKPT; #endif | | | 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 | int rc = sqlite3_initialize(); if( rc ) return rc; #endif #ifdef SQLITE_ENABLE_API_ARMOR if( pVfs==0 ) return SQLITE_MISUSE_BKPT; #endif MUTEX_LOGIC( mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN); ) sqlite3_mutex_enter(mutex); vfsUnlink(pVfs); if( makeDflt || vfsList==0 ){ pVfs->pNext = vfsList; vfsList = pVfs; }else{ pVfs->pNext = vfsList->pNext; |
︙ | ︙ | |||
411 412 413 414 415 416 417 | */ int sqlite3_vfs_unregister(sqlite3_vfs *pVfs){ MUTEX_LOGIC(sqlite3_mutex *mutex;) #ifndef SQLITE_OMIT_AUTOINIT int rc = sqlite3_initialize(); if( rc ) return rc; #endif | | | 432 433 434 435 436 437 438 439 440 441 442 443 444 | */ int sqlite3_vfs_unregister(sqlite3_vfs *pVfs){ MUTEX_LOGIC(sqlite3_mutex *mutex;) #ifndef SQLITE_OMIT_AUTOINIT int rc = sqlite3_initialize(); if( rc ) return rc; #endif MUTEX_LOGIC( mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN); ) sqlite3_mutex_enter(mutex); vfsUnlink(pVfs); sqlite3_mutex_leave(mutex); return SQLITE_OK; } |
Changes to src/os.h.
︙ | ︙ | |||
28 29 30 31 32 33 34 35 36 37 38 39 40 41 | /* If the SET_FULLSYNC macro is not defined above, then make it ** a no-op */ #ifndef SET_FULLSYNC # define SET_FULLSYNC(x,y) #endif /* ** The default size of a disk sector */ #ifndef SQLITE_DEFAULT_SECTOR_SIZE # define SQLITE_DEFAULT_SECTOR_SIZE 4096 #endif | > > > > > > | 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | /* If the SET_FULLSYNC macro is not defined above, then make it ** a no-op */ #ifndef SET_FULLSYNC # define SET_FULLSYNC(x,y) #endif /* Maximum pathname length. Note: FILENAME_MAX defined by stdio.h */ #ifndef SQLITE_MAX_PATHLEN # define SQLITE_MAX_PATHLEN FILENAME_MAX #endif /* ** The default size of a disk sector */ #ifndef SQLITE_DEFAULT_SECTOR_SIZE # define SQLITE_DEFAULT_SECTOR_SIZE 4096 #endif |
︙ | ︙ |
Changes to src/os_unix.c.
︙ | ︙ | |||
101 102 103 104 105 106 107 | #if SQLITE_ENABLE_LOCKING_STYLE # include <sys/ioctl.h> # include <sys/file.h> # include <sys/param.h> #endif /* SQLITE_ENABLE_LOCKING_STYLE */ | > > > > > > > > > > > > > > | | | | > > | | | > | 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 | #if SQLITE_ENABLE_LOCKING_STYLE # include <sys/ioctl.h> # include <sys/file.h> # include <sys/param.h> #endif /* SQLITE_ENABLE_LOCKING_STYLE */ /* ** Try to determine if gethostuuid() is available based on standard ** macros. This might sometimes compute the wrong value for some ** obscure platforms. For those cases, simply compile with one of ** the following: ** ** -DHAVE_GETHOSTUUID=0 ** -DHAVE_GETHOSTUUID=1 ** ** None if this matters except when building on Apple products with ** -DSQLITE_ENABLE_LOCKING_STYLE. */ #ifndef HAVE_GETHOSTUUID # define HAVE_GETHOSTUUID 0 # if defined(__APPLE__) && ((__MAC_OS_X_VERSION_MIN_REQUIRED > 1050) || \ (__IPHONE_OS_VERSION_MIN_REQUIRED > 2000)) # if (!defined(TARGET_OS_EMBEDDED) || (TARGET_OS_EMBEDDED==0)) \ && (!defined(TARGET_IPHONE_SIMULATOR) || (TARGET_IPHONE_SIMULATOR==0))\ && (!defined(TARGET_OS_MACCATALYST) || (TARGET_OS_MACCATALYST==0)) # undef HAVE_GETHOSTUUID # define HAVE_GETHOSTUUID 1 # else # warning "gethostuuid() is disabled." # endif # endif #endif #if OS_VXWORKS # include <sys/ioctl.h> # include <semaphore.h> |
︙ | ︙ | |||
517 518 519 520 521 522 523 524 525 526 527 528 529 | { "lstat", (sqlite3_syscall_ptr)0, 0 }, #endif #define osLstat ((int(*)(const char*,struct stat*))aSyscall[27].pCurrent) #if defined(__linux__) && defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE) # ifdef __ANDROID__ { "ioctl", (sqlite3_syscall_ptr)(int(*)(int, int, ...))ioctl, 0 }, # else { "ioctl", (sqlite3_syscall_ptr)ioctl, 0 }, # endif #else { "ioctl", (sqlite3_syscall_ptr)0, 0 }, #endif | > > < | 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 | { "lstat", (sqlite3_syscall_ptr)0, 0 }, #endif #define osLstat ((int(*)(const char*,struct stat*))aSyscall[27].pCurrent) #if defined(__linux__) && defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE) # ifdef __ANDROID__ { "ioctl", (sqlite3_syscall_ptr)(int(*)(int, int, ...))ioctl, 0 }, #define osIoctl ((int(*)(int,int,...))aSyscall[28].pCurrent) # else { "ioctl", (sqlite3_syscall_ptr)ioctl, 0 }, #define osIoctl ((int(*)(int,unsigned long,...))aSyscall[28].pCurrent) # endif #else { "ioctl", (sqlite3_syscall_ptr)0, 0 }, #endif }; /* End of the overrideable system calls */ /* ** On some systems, calls to fchown() will trigger a message in a security ** log if they come from non-root processes. So avoid calling fchown() if |
︙ | ︙ | |||
668 669 670 671 672 673 674 | break; } if( fd>=SQLITE_MINIMUM_FILE_DESCRIPTOR ) break; osClose(fd); sqlite3_log(SQLITE_WARNING, "attempt to open \"%s\" as file descriptor %d", z, fd); fd = -1; | | | 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 | break; } if( fd>=SQLITE_MINIMUM_FILE_DESCRIPTOR ) break; osClose(fd); sqlite3_log(SQLITE_WARNING, "attempt to open \"%s\" as file descriptor %d", z, fd); fd = -1; if( osOpen("/dev/null", O_RDONLY, m)<0 ) break; } if( fd>=0 ){ if( m!=0 ){ struct stat statbuf; if( osFstat(fd, &statbuf)==0 && statbuf.st_size==0 && (statbuf.st_mode&0777)!=m |
︙ | ︙ | |||
1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 | sqlite3_mutex_leave(pFile->pInode->pLockMutex); OSTRACE(("TEST WR-LOCK %d %d %d (unix)\n", pFile->h, rc, reserved)); *pResOut = reserved; return rc; } /* ** Set a posix-advisory-lock. ** ** There are two versions of this routine. If compiled with ** SQLITE_ENABLE_SETLK_TIMEOUT then the routine has an extra parameter ** which is a pointer to a unixFile. If the unixFile->iBusyTimeout ** value is set, then it is the number of milliseconds to wait before | > > > | 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 | sqlite3_mutex_leave(pFile->pInode->pLockMutex); OSTRACE(("TEST WR-LOCK %d %d %d (unix)\n", pFile->h, rc, reserved)); *pResOut = reserved; return rc; } /* Forward declaration*/ static int unixSleep(sqlite3_vfs*,int); /* ** Set a posix-advisory-lock. ** ** There are two versions of this routine. If compiled with ** SQLITE_ENABLE_SETLK_TIMEOUT then the routine has an extra parameter ** which is a pointer to a unixFile. If the unixFile->iBusyTimeout ** value is set, then it is the number of milliseconds to wait before |
︙ | ︙ | |||
1555 1556 1557 1558 1559 1560 1561 1562 | # define osSetPosixAdvisoryLock(h,x,t) osFcntl(h,F_SETLK,x) #else static int osSetPosixAdvisoryLock( int h, /* The file descriptor on which to take the lock */ struct flock *pLock, /* The description of the lock */ unixFile *pFile /* Structure holding timeout value */ ){ int rc = osFcntl(h,F_SETLK,pLock); | > | | | | 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 | # define osSetPosixAdvisoryLock(h,x,t) osFcntl(h,F_SETLK,x) #else static int osSetPosixAdvisoryLock( int h, /* The file descriptor on which to take the lock */ struct flock *pLock, /* The description of the lock */ unixFile *pFile /* Structure holding timeout value */ ){ int tm = pFile->iBusyTimeout; int rc = osFcntl(h,F_SETLK,pLock); while( rc<0 && tm>0 ){ /* On systems that support some kind of blocking file lock with a timeout, ** make appropriate changes here to invoke that blocking file lock. On ** generic posix, however, there is no such API. So we simply try the ** lock once every millisecond until either the timeout expires, or until ** the lock is obtained. */ unixSleep(0,1000); rc = osFcntl(h,F_SETLK,pLock); tm--; } return rc; } #endif /* SQLITE_ENABLE_SETLK_TIMEOUT */ /* |
︙ | ︙ | |||
2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 | ** descriptor to pInode->pUnused list. It will be automatically closed ** when the last lock is cleared. */ setPendingFd(pFile); } sqlite3_mutex_leave(pInode->pLockMutex); releaseInodeInfo(pFile); rc = closeUnixFile(id); unixLeaveMutex(); return rc; } /************** End of the posix advisory lock implementation ***************** ******************************************************************************/ | > | 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 | ** descriptor to pInode->pUnused list. It will be automatically closed ** when the last lock is cleared. */ setPendingFd(pFile); } sqlite3_mutex_leave(pInode->pLockMutex); releaseInodeInfo(pFile); assert( pFile->pShm==0 ); rc = closeUnixFile(id); unixLeaveMutex(); return rc; } /************** End of the posix advisory lock implementation ***************** ******************************************************************************/ |
︙ | ︙ | |||
3337 3338 3339 3340 3341 3342 3343 | ){ unixFile *pFile = (unixFile *)id; int got; assert( id ); assert( offset>=0 ); assert( amt>0 ); | | | 3360 3361 3362 3363 3364 3365 3366 3367 3368 3369 3370 3371 3372 3373 3374 | ){ unixFile *pFile = (unixFile *)id; int got; assert( id ); assert( offset>=0 ); assert( amt>0 ); /* If this is a database file (not a journal, super-journal or temp ** file), the bytes in the locking range should never be read or written. */ #if 0 assert( pFile->pPreallocatedUnused==0 || offset>=PENDING_BYTE+512 || offset+amt<=PENDING_BYTE ); #endif |
︙ | ︙ | |||
3367 3368 3369 3370 3371 3372 3373 | } #endif got = seekAndRead(pFile, offset, pBuf, amt); if( got==amt ){ return SQLITE_OK; }else if( got<0 ){ | > > > > > > > | > > > > > > > > > > | 3390 3391 3392 3393 3394 3395 3396 3397 3398 3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 | } #endif got = seekAndRead(pFile, offset, pBuf, amt); if( got==amt ){ return SQLITE_OK; }else if( got<0 ){ /* pFile->lastErrno has been set by seekAndRead(). ** Usually we return SQLITE_IOERR_READ here, though for some ** kinds of errors we return SQLITE_IOERR_CORRUPTFS. The ** SQLITE_IOERR_CORRUPTFS will be converted into SQLITE_CORRUPT ** prior to returning to the application by the sqlite3ApiExit() ** routine. */ switch( pFile->lastErrno ){ case ERANGE: case EIO: #ifdef ENXIO case ENXIO: #endif #ifdef EDEVERR case EDEVERR: #endif return SQLITE_IOERR_CORRUPTFS; } return SQLITE_IOERR_READ; }else{ storeLastErrno(pFile, 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; } |
︙ | ︙ | |||
3450 3451 3452 3453 3454 3455 3456 | sqlite3_int64 offset ){ unixFile *pFile = (unixFile*)id; int wrote = 0; assert( id ); assert( amt>0 ); | | | 3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 3504 | sqlite3_int64 offset ){ unixFile *pFile = (unixFile*)id; int wrote = 0; assert( id ); assert( amt>0 ); /* If this is a database file (not a journal, super-journal or temp ** file), the bytes in the locking range should never be read or written. */ #if 0 assert( pFile->pPreallocatedUnused==0 || offset>=PENDING_BYTE+512 || offset+amt<=PENDING_BYTE ); #endif |
︙ | ︙ | |||
3926 3927 3928 3929 3930 3931 3932 3933 3934 3935 3936 3937 3938 3939 | }else{ pFile->ctrlFlags |= mask; } } /* Forward declaration */ static int unixGetTempname(int nBuf, char *zBuf); /* ** Information and control of an open file handle. */ static int unixFileControl(sqlite3_file *id, int op, void *pArg){ unixFile *pFile = (unixFile*)id; switch( op ){ | > > > | 3966 3967 3968 3969 3970 3971 3972 3973 3974 3975 3976 3977 3978 3979 3980 3981 3982 | }else{ pFile->ctrlFlags |= mask; } } /* Forward declaration */ static int unixGetTempname(int nBuf, char *zBuf); #ifndef SQLITE_OMIT_WAL static int unixFcntlExternalReader(unixFile*, int*); #endif /* ** Information and control of an open file handle. */ static int unixFileControl(sqlite3_file *id, int op, void *pArg){ unixFile *pFile = (unixFile*)id; switch( op ){ |
︙ | ︙ | |||
3993 3994 3995 3996 3997 3998 3999 4000 4001 4002 4003 4004 4005 4006 4007 | } case SQLITE_FCNTL_HAS_MOVED: { *(int*)pArg = fileHasMoved(pFile); return SQLITE_OK; } #ifdef SQLITE_ENABLE_SETLK_TIMEOUT case SQLITE_FCNTL_LOCK_TIMEOUT: { pFile->iBusyTimeout = *(int*)pArg; return SQLITE_OK; } #endif #if SQLITE_MAX_MMAP_SIZE>0 case SQLITE_FCNTL_MMAP_SIZE: { i64 newLimit = *(i64*)pArg; int rc = SQLITE_OK; | > > | 4036 4037 4038 4039 4040 4041 4042 4043 4044 4045 4046 4047 4048 4049 4050 4051 4052 | } case SQLITE_FCNTL_HAS_MOVED: { *(int*)pArg = fileHasMoved(pFile); return SQLITE_OK; } #ifdef SQLITE_ENABLE_SETLK_TIMEOUT case SQLITE_FCNTL_LOCK_TIMEOUT: { int iOld = pFile->iBusyTimeout; pFile->iBusyTimeout = *(int*)pArg; *(int*)pArg = iOld; return SQLITE_OK; } #endif #if SQLITE_MAX_MMAP_SIZE>0 case SQLITE_FCNTL_MMAP_SIZE: { i64 newLimit = *(i64*)pArg; int rc = SQLITE_OK; |
︙ | ︙ | |||
4043 4044 4045 4046 4047 4048 4049 4050 4051 4052 4053 4054 4055 4056 | #endif #if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__) case SQLITE_FCNTL_SET_LOCKPROXYFILE: case SQLITE_FCNTL_GET_LOCKPROXYFILE: { return proxyFileControl(id,op,pArg); } #endif /* SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__) */ } return SQLITE_NOTFOUND; } /* ** If pFd->sectorSize is non-zero when this function is called, it is a ** no-op. Otherwise, the values of pFd->sectorSize and | > > > > > > > > > | 4088 4089 4090 4091 4092 4093 4094 4095 4096 4097 4098 4099 4100 4101 4102 4103 4104 4105 4106 4107 4108 4109 4110 | #endif #if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__) case SQLITE_FCNTL_SET_LOCKPROXYFILE: case SQLITE_FCNTL_GET_LOCKPROXYFILE: { return proxyFileControl(id,op,pArg); } #endif /* SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__) */ case SQLITE_FCNTL_EXTERNAL_READER: { #ifndef SQLITE_OMIT_WAL return unixFcntlExternalReader((unixFile*)id, (int*)pArg); #else *(int*)pArg = 0; return SQLITE_OK; #endif } } return SQLITE_NOTFOUND; } /* ** If pFd->sectorSize is non-zero when this function is called, it is a ** no-op. Otherwise, the values of pFd->sectorSize and |
︙ | ︙ | |||
4252 4253 4254 4255 4256 4257 4258 4259 4260 4261 4262 4263 4264 4265 | int szRegion; /* Size of shared-memory regions */ u16 nRegion; /* Size of array apRegion */ u8 isReadonly; /* True if read-only */ u8 isUnlocked; /* True if no DMS lock held */ char **apRegion; /* Array of mapped shared-memory regions */ int nRef; /* Number of unixShm objects pointing to this */ unixShm *pFirst; /* All unixShm objects pointing to this */ #ifdef SQLITE_DEBUG u8 exclMask; /* Mask of exclusive locks held */ u8 sharedMask; /* Mask of shared locks held */ u8 nextShmId; /* Next available unixShm.id value */ #endif }; | > | 4306 4307 4308 4309 4310 4311 4312 4313 4314 4315 4316 4317 4318 4319 4320 | int szRegion; /* Size of shared-memory regions */ u16 nRegion; /* Size of array apRegion */ u8 isReadonly; /* True if read-only */ u8 isUnlocked; /* True if no DMS lock held */ char **apRegion; /* Array of mapped shared-memory regions */ int nRef; /* Number of unixShm objects pointing to this */ unixShm *pFirst; /* All unixShm objects pointing to this */ int aLock[SQLITE_SHM_NLOCK]; /* # shared locks on slot, -1==excl lock */ #ifdef SQLITE_DEBUG u8 exclMask; /* Mask of exclusive locks held */ u8 sharedMask; /* Mask of shared locks held */ u8 nextShmId; /* Next available unixShm.id value */ #endif }; |
︙ | ︙ | |||
4286 4287 4288 4289 4290 4291 4292 4293 4294 4295 4296 4297 4298 4299 | }; /* ** Constants used for locking */ #define UNIX_SHM_BASE ((22+SQLITE_SHM_NLOCK)*4) /* first lock byte */ #define UNIX_SHM_DMS (UNIX_SHM_BASE+SQLITE_SHM_NLOCK) /* deadman switch */ /* ** Apply posix advisory locks for all bytes from ofst through ofst+n-1. ** ** Locks block if the mask is exactly UNIX_SHM_C and are non-blocking ** otherwise. */ | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | }; /* ** Constants used for locking */ #define UNIX_SHM_BASE ((22+SQLITE_SHM_NLOCK)*4) /* first lock byte */ #define UNIX_SHM_DMS (UNIX_SHM_BASE+SQLITE_SHM_NLOCK) /* deadman switch */ /* ** Use F_GETLK to check whether or not there are any readers with open ** wal-mode transactions in other processes on database file pFile. If ** no error occurs, return SQLITE_OK and set (*piOut) to 1 if there are ** such transactions, or 0 otherwise. If an error occurs, return an ** SQLite error code. The final value of *piOut is undefined in this ** case. */ static int unixFcntlExternalReader(unixFile *pFile, int *piOut){ int rc = SQLITE_OK; *piOut = 0; if( pFile->pShm){ unixShmNode *pShmNode = pFile->pShm->pShmNode; struct flock f; memset(&f, 0, sizeof(f)); f.l_type = F_WRLCK; f.l_whence = SEEK_SET; f.l_start = UNIX_SHM_BASE + 3; f.l_len = SQLITE_SHM_NLOCK - 3; sqlite3_mutex_enter(pShmNode->pShmMutex); if( osFcntl(pShmNode->hShm, F_GETLK, &f)<0 ){ rc = SQLITE_IOERR_LOCK; }else{ *piOut = (f.l_type!=F_UNLCK); } sqlite3_mutex_leave(pShmNode->pShmMutex); } return rc; } /* ** Apply posix advisory locks for all bytes from ofst through ofst+n-1. ** ** Locks block if the mask is exactly UNIX_SHM_C and are non-blocking ** otherwise. */ |
︙ | ︙ | |||
4315 4316 4317 4318 4319 4320 4321 4322 4323 4324 4325 4326 | /* Shared locks never span more than one byte */ assert( n==1 || lockType!=F_RDLCK ); /* Locks are within range */ assert( n>=1 && n<=SQLITE_SHM_NLOCK ); if( pShmNode->hShm>=0 ){ /* Initialize the locking parameters */ f.l_type = lockType; f.l_whence = SEEK_SET; f.l_start = ofst; f.l_len = n; | > | > > > > | > > | 4404 4405 4406 4407 4408 4409 4410 4411 4412 4413 4414 4415 4416 4417 4418 4419 4420 4421 4422 4423 4424 4425 4426 4427 4428 4429 4430 4431 | /* Shared locks never span more than one byte */ assert( n==1 || lockType!=F_RDLCK ); /* Locks are within range */ assert( n>=1 && n<=SQLITE_SHM_NLOCK ); if( pShmNode->hShm>=0 ){ int res; /* Initialize the locking parameters */ f.l_type = lockType; f.l_whence = SEEK_SET; f.l_start = ofst; f.l_len = n; res = osSetPosixAdvisoryLock(pShmNode->hShm, &f, pFile); if( res==-1 ){ #ifdef SQLITE_ENABLE_SETLK_TIMEOUT rc = (pFile->iBusyTimeout ? SQLITE_BUSY_TIMEOUT : SQLITE_BUSY); #else rc = SQLITE_BUSY; #endif } } /* Update the global lock state and do debug tracing */ #ifdef SQLITE_DEBUG { u16 mask; OSTRACE(("SHM-LOCK ")); mask = ofst>31 ? 0xffff : (1<<(ofst+n)) - (1<<ofst); |
︙ | ︙ | |||
4577 4578 4579 4580 4581 4582 4583 | rc = SQLITE_NOMEM_BKPT; goto shm_open_err; } } if( pInode->bProcessLock==0 ){ if( 0==sqlite3_uri_boolean(pDbFd->zPath, "readonly_shm", 0) ){ | | > | > | 4673 4674 4675 4676 4677 4678 4679 4680 4681 4682 4683 4684 4685 4686 4687 4688 4689 4690 4691 4692 | rc = SQLITE_NOMEM_BKPT; goto shm_open_err; } } if( pInode->bProcessLock==0 ){ if( 0==sqlite3_uri_boolean(pDbFd->zPath, "readonly_shm", 0) ){ pShmNode->hShm = robust_open(zShm, O_RDWR|O_CREAT|O_NOFOLLOW, (sStat.st_mode&0777)); } if( pShmNode->hShm<0 ){ pShmNode->hShm = robust_open(zShm, O_RDONLY|O_NOFOLLOW, (sStat.st_mode&0777)); if( pShmNode->hShm<0 ){ rc = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zShm); goto shm_open_err; } pShmNode->isReadonly = 1; } |
︙ | ︙ | |||
4783 4784 4785 4786 4787 4788 4789 4790 4791 4792 4793 4794 4795 4796 4797 4798 4799 4800 4801 4802 4803 4804 4805 | *pp = 0; } if( pShmNode->isReadonly && rc==SQLITE_OK ) rc = SQLITE_READONLY; sqlite3_mutex_leave(pShmNode->pShmMutex); return rc; } /* ** Change the lock state for a shared-memory segment. ** ** Note that the relationship between SHAREd and EXCLUSIVE locks is a little ** different here than in posix. In xShmLock(), one can go from unlocked ** to shared and back or from unlocked to exclusive and back. But one may ** not go from shared to exclusive or from exclusive to shared. */ static int unixShmLock( sqlite3_file *fd, /* Database file holding the shared memory */ int ofst, /* First lock to acquire or release */ int n, /* Number of locks to acquire or release */ int flags /* What to do with the lock */ ){ unixFile *pDbFd = (unixFile*)fd; /* Connection holding shared memory */ unixShm *p = pDbFd->pShm; /* The shared memory being locked */ | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > < > > > > > > > > > > > > > > > > > > > > > > > > > > | < | < | | | | | | | < | > > > > > | | | | | | > < | | < < < < | > < < < < | < < < < < < | | | | > | > | < > | | > | | | < > > > > | 4881 4882 4883 4884 4885 4886 4887 4888 4889 4890 4891 4892 4893 4894 4895 4896 4897 4898 4899 4900 4901 4902 4903 4904 4905 4906 4907 4908 4909 4910 4911 4912 4913 4914 4915 4916 4917 4918 4919 4920 4921 4922 4923 4924 4925 4926 4927 4928 4929 4930 4931 4932 4933 4934 4935 4936 4937 4938 4939 4940 4941 4942 4943 4944 4945 4946 4947 4948 4949 4950 4951 4952 4953 4954 4955 4956 4957 4958 4959 4960 4961 4962 4963 4964 4965 4966 4967 4968 4969 4970 4971 4972 4973 4974 4975 4976 4977 4978 4979 4980 4981 4982 4983 4984 4985 4986 4987 4988 4989 4990 4991 4992 4993 4994 4995 4996 4997 4998 4999 5000 5001 5002 5003 5004 5005 5006 5007 5008 5009 5010 5011 5012 5013 5014 5015 5016 5017 5018 5019 5020 5021 5022 5023 5024 5025 5026 5027 5028 5029 5030 5031 5032 5033 5034 5035 5036 5037 5038 5039 5040 5041 5042 5043 5044 5045 5046 5047 5048 5049 5050 5051 5052 5053 5054 | *pp = 0; } if( pShmNode->isReadonly && rc==SQLITE_OK ) rc = SQLITE_READONLY; sqlite3_mutex_leave(pShmNode->pShmMutex); return rc; } /* ** Check that the pShmNode->aLock[] array comports with the locking bitmasks ** held by each client. Return true if it does, or false otherwise. This ** is to be used in an assert(). e.g. ** ** assert( assertLockingArrayOk(pShmNode) ); */ #ifdef SQLITE_DEBUG static int assertLockingArrayOk(unixShmNode *pShmNode){ unixShm *pX; int aLock[SQLITE_SHM_NLOCK]; assert( sqlite3_mutex_held(pShmNode->pShmMutex) ); memset(aLock, 0, sizeof(aLock)); for(pX=pShmNode->pFirst; pX; pX=pX->pNext){ int i; for(i=0; i<SQLITE_SHM_NLOCK; i++){ if( pX->exclMask & (1<<i) ){ assert( aLock[i]==0 ); aLock[i] = -1; }else if( pX->sharedMask & (1<<i) ){ assert( aLock[i]>=0 ); aLock[i]++; } } } assert( 0==memcmp(pShmNode->aLock, aLock, sizeof(aLock)) ); return (memcmp(pShmNode->aLock, aLock, sizeof(aLock))==0); } #endif /* ** Change the lock state for a shared-memory segment. ** ** Note that the relationship between SHAREd and EXCLUSIVE locks is a little ** different here than in posix. In xShmLock(), one can go from unlocked ** to shared and back or from unlocked to exclusive and back. But one may ** not go from shared to exclusive or from exclusive to shared. */ static int unixShmLock( sqlite3_file *fd, /* Database file holding the shared memory */ int ofst, /* First lock to acquire or release */ int n, /* Number of locks to acquire or release */ int flags /* What to do with the lock */ ){ unixFile *pDbFd = (unixFile*)fd; /* Connection holding shared memory */ unixShm *p = pDbFd->pShm; /* The shared memory being locked */ unixShmNode *pShmNode = p->pShmNode; /* The underlying file iNode */ int rc = SQLITE_OK; /* Result code */ u16 mask; /* Mask of locks to take or release */ int *aLock = pShmNode->aLock; assert( pShmNode==pDbFd->pInode->pShmNode ); assert( pShmNode->pInode==pDbFd->pInode ); assert( ofst>=0 && ofst+n<=SQLITE_SHM_NLOCK ); assert( n>=1 ); assert( flags==(SQLITE_SHM_LOCK | SQLITE_SHM_SHARED) || flags==(SQLITE_SHM_LOCK | SQLITE_SHM_EXCLUSIVE) || flags==(SQLITE_SHM_UNLOCK | SQLITE_SHM_SHARED) || flags==(SQLITE_SHM_UNLOCK | SQLITE_SHM_EXCLUSIVE) ); assert( n==1 || (flags & SQLITE_SHM_EXCLUSIVE)!=0 ); assert( pShmNode->hShm>=0 || pDbFd->pInode->bProcessLock==1 ); assert( pShmNode->hShm<0 || pDbFd->pInode->bProcessLock==0 ); /* Check that, if this to be a blocking lock, no locks that occur later ** in the following list than the lock being obtained are already held: ** ** 1. Checkpointer lock (ofst==1). ** 2. Write lock (ofst==0). ** 3. Read locks (ofst>=3 && ofst<SQLITE_SHM_NLOCK). ** ** In other words, if this is a blocking lock, none of the locks that ** occur later in the above list than the lock being obtained may be ** held. ** ** It is not permitted to block on the RECOVER lock. */ #ifdef SQLITE_ENABLE_SETLK_TIMEOUT assert( (flags & SQLITE_SHM_UNLOCK) || pDbFd->iBusyTimeout==0 || ( (ofst!=2) /* not RECOVER */ && (ofst!=1 || (p->exclMask|p->sharedMask)==0) && (ofst!=0 || (p->exclMask|p->sharedMask)<3) && (ofst<3 || (p->exclMask|p->sharedMask)<(1<<ofst)) )); #endif mask = (1<<(ofst+n)) - (1<<ofst); assert( n>1 || mask==(1<<ofst) ); sqlite3_mutex_enter(pShmNode->pShmMutex); assert( assertLockingArrayOk(pShmNode) ); if( flags & SQLITE_SHM_UNLOCK ){ if( (p->exclMask|p->sharedMask) & mask ){ int ii; int bUnlock = 1; for(ii=ofst; ii<ofst+n; ii++){ if( aLock[ii]>((p->sharedMask & (1<<ii)) ? 1 : 0) ){ bUnlock = 0; } } if( bUnlock ){ rc = unixShmSystemLock(pDbFd, F_UNLCK, ofst+UNIX_SHM_BASE, n); if( rc==SQLITE_OK ){ memset(&aLock[ofst], 0, sizeof(int)*n); } }else if( ALWAYS(p->sharedMask & (1<<ofst)) ){ assert( n==1 && aLock[ofst]>1 ); aLock[ofst]--; } /* Undo the local locks */ if( rc==SQLITE_OK ){ p->exclMask &= ~mask; p->sharedMask &= ~mask; } } }else if( flags & SQLITE_SHM_SHARED ){ assert( n==1 ); assert( (p->exclMask & (1<<ofst))==0 ); if( (p->sharedMask & mask)==0 ){ if( aLock[ofst]<0 ){ rc = SQLITE_BUSY; }else if( aLock[ofst]==0 ){ rc = unixShmSystemLock(pDbFd, F_RDLCK, ofst+UNIX_SHM_BASE, n); } /* Get the local shared locks */ if( rc==SQLITE_OK ){ p->sharedMask |= mask; aLock[ofst]++; } } }else{ /* Make sure no sibling connections hold locks that will block this ** lock. If any do, return SQLITE_BUSY right away. */ int ii; for(ii=ofst; ii<ofst+n; ii++){ assert( (p->sharedMask & mask)==0 ); if( ALWAYS((p->exclMask & (1<<ii))==0) && aLock[ii] ){ rc = SQLITE_BUSY; break; } } /* Get the exclusive locks at the system level. Then if successful ** also update the in-memory values. */ if( rc==SQLITE_OK ){ rc = unixShmSystemLock(pDbFd, F_WRLCK, ofst+UNIX_SHM_BASE, n); if( rc==SQLITE_OK ){ assert( (p->sharedMask & mask)==0 ); p->exclMask |= mask; for(ii=ofst; ii<ofst+n; ii++){ aLock[ii] = -1; } } } } assert( assertLockingArrayOk(pShmNode) ); sqlite3_mutex_leave(pShmNode->pShmMutex); OSTRACE(("SHM-LOCK shmid-%d, pid-%d got %03x,%03x\n", p->id, osGetpid(0), p->sharedMask, p->exclMask)); return rc; } /* |
︙ | ︙ | |||
5687 5688 5689 5690 5691 5692 5693 | osUnlink(zFilename); pNew->ctrlFlags |= UNIXFILE_DELETE; } #endif if( rc!=SQLITE_OK ){ if( h>=0 ) robust_close(pNew, h, __LINE__); }else{ | | > > > > > > > > > > > > > > > > > > > > < < < < < < < < < < | | | 5837 5838 5839 5840 5841 5842 5843 5844 5845 5846 5847 5848 5849 5850 5851 5852 5853 5854 5855 5856 5857 5858 5859 5860 5861 5862 5863 5864 5865 5866 5867 5868 5869 5870 5871 5872 5873 5874 5875 5876 5877 5878 5879 5880 5881 5882 5883 5884 5885 5886 5887 5888 5889 5890 5891 5892 5893 5894 5895 5896 | osUnlink(zFilename); pNew->ctrlFlags |= UNIXFILE_DELETE; } #endif if( rc!=SQLITE_OK ){ if( h>=0 ) robust_close(pNew, h, __LINE__); }else{ pId->pMethods = pLockingStyle; OpenCounter(+1); verifyDbFile(pNew); } return rc; } /* ** Directories to consider for temp files. */ static const char *azTempDirs[] = { 0, 0, "/var/tmp", "/usr/tmp", "/tmp", "." }; /* ** Initialize first two members of azTempDirs[] array. */ static void unixTempFileInit(void){ azTempDirs[0] = getenv("SQLITE_TMPDIR"); azTempDirs[1] = getenv("TMPDIR"); } /* ** Return the name of a directory in which to put temporary files. ** If no suitable temporary file directory can be found, return NULL. */ static const char *unixTempFileDir(void){ unsigned int i = 0; struct stat buf; const char *zDir = sqlite3_temp_directory; while(1){ if( zDir!=0 && osStat(zDir, &buf)==0 && S_ISDIR(buf.st_mode) && osAccess(zDir, 03)==0 ){ return zDir; } if( i>=sizeof(azTempDirs)/sizeof(azTempDirs[0]) ) break; zDir = azTempDirs[i++]; } return 0; } /* ** Create a temporary file name in zBuf. zBuf must be allocated ** by the calling process and must be big enough to hold at least |
︙ | ︙ | |||
5768 5769 5770 5771 5772 5773 5774 | ** if SQLITE_PREFER_PROXY_LOCKING is defined. */ static int proxyTransformUnixFile(unixFile*, const char*); #endif /* ** Search for an unused file descriptor that was opened on the database | | | 5928 5929 5930 5931 5932 5933 5934 5935 5936 5937 5938 5939 5940 5941 5942 | ** if SQLITE_PREFER_PROXY_LOCKING is defined. */ static int proxyTransformUnixFile(unixFile*, const char*); #endif /* ** Search for an unused file descriptor that was opened on the database ** file (not a journal or super-journal file) identified by pathname ** zPath with SQLITE_OPEN_XXX flags matching those passed as the second ** argument to this function. ** ** Such a file descriptor may exist if a database connection was closed ** but the associated file descriptor could not be closed because some ** other file descriptor open on the same file is holding a file-lock. ** Refer to comments in the unixClose() function and the lengthy comment |
︙ | ︙ | |||
5815 5816 5817 5818 5819 5820 5821 5822 5823 5824 5825 5826 5827 5828 | || pInode->fileId.ino!=(u64)sStat.st_ino) ){ pInode = pInode->pNext; } if( pInode ){ UnixUnusedFd **pp; assert( sqlite3_mutex_notheld(pInode->pLockMutex) ); sqlite3_mutex_enter(pInode->pLockMutex); for(pp=&pInode->pUnused; *pp && (*pp)->flags!=flags; pp=&((*pp)->pNext)); pUnused = *pp; if( pUnused ){ *pp = pUnused->pNext; } sqlite3_mutex_leave(pInode->pLockMutex); } | > | 5975 5976 5977 5978 5979 5980 5981 5982 5983 5984 5985 5986 5987 5988 5989 | || pInode->fileId.ino!=(u64)sStat.st_ino) ){ pInode = pInode->pNext; } if( pInode ){ UnixUnusedFd **pp; assert( sqlite3_mutex_notheld(pInode->pLockMutex) ); sqlite3_mutex_enter(pInode->pLockMutex); flags &= (SQLITE_OPEN_READONLY|SQLITE_OPEN_READWRITE); for(pp=&pInode->pUnused; *pp && (*pp)->flags!=flags; pp=&((*pp)->pNext)); pUnused = *pp; if( pUnused ){ *pp = pUnused->pNext; } sqlite3_mutex_leave(pInode->pLockMutex); } |
︙ | ︙ | |||
5868 5869 5870 5871 5872 5873 5874 | ** corresponding database file and sets *pMode to this value. Whenever ** possible, WAL and journal files are created using the same permissions ** as the associated database file. ** ** If the SQLITE_ENABLE_8_3_NAMES option is enabled, then the ** original filename is unavailable. But 8_3_NAMES is only used for ** FAT filesystems and permissions do not matter there, so just use | | | 6029 6030 6031 6032 6033 6034 6035 6036 6037 6038 6039 6040 6041 6042 6043 | ** corresponding database file and sets *pMode to this value. Whenever ** possible, WAL and journal files are created using the same permissions ** as the associated database file. ** ** If the SQLITE_ENABLE_8_3_NAMES option is enabled, then the ** original filename is unavailable. But 8_3_NAMES is only used for ** FAT filesystems and permissions do not matter there, so just use ** the default permissions. In 8_3_NAMES mode, leave *pMode set to zero. */ static int findCreateFileMode( const char *zPath, /* Path of file (possibly) being created */ int flags, /* Flags passed as 4th argument to xOpen() */ mode_t *pMode, /* OUT: Permissions to open file with */ uid_t *pUid, /* OUT: uid to set on the file */ gid_t *pGid /* OUT: gid to set on the file */ |
︙ | ︙ | |||
5901 5902 5903 5904 5905 5906 5907 | ** where NN is a decimal number. The NN naming schemes are ** used by the test_multiplex.c module. */ nDb = sqlite3Strlen30(zPath) - 1; while( zPath[nDb]!='-' ){ /* In normal operation, the journal file name will always contain ** a '-' character. However in 8+3 filename mode, or if a corrupt | | | 6062 6063 6064 6065 6066 6067 6068 6069 6070 6071 6072 6073 6074 6075 6076 | ** where NN is a decimal number. The NN naming schemes are ** used by the test_multiplex.c module. */ nDb = sqlite3Strlen30(zPath) - 1; while( zPath[nDb]!='-' ){ /* In normal operation, the journal file name will always contain ** a '-' character. However in 8+3 filename mode, or if a corrupt ** rollback journal specifies a super-journal with a goofy name, then ** the '-' might be missing. */ if( nDb==0 || zPath[nDb]=='.' ) return SQLITE_OK; nDb--; } memcpy(zDb, zPath, nDb); zDb[nDb] = '\0'; |
︙ | ︙ | |||
5957 5958 5959 5960 5961 5962 5963 | sqlite3_file *pFile, /* The file descriptor to be filled in */ int flags, /* Input flags to control the opening */ int *pOutFlags /* Output flags returned to SQLite core */ ){ unixFile *p = (unixFile *)pFile; int fd = -1; /* File descriptor returned by open() */ int openFlags = 0; /* Flags to pass to open() */ | | | | | 6118 6119 6120 6121 6122 6123 6124 6125 6126 6127 6128 6129 6130 6131 6132 6133 6134 6135 6136 6137 6138 6139 6140 6141 6142 6143 6144 6145 6146 6147 6148 6149 6150 6151 6152 6153 6154 | sqlite3_file *pFile, /* The file descriptor to be filled in */ int flags, /* Input flags to control the opening */ int *pOutFlags /* Output flags returned to SQLite core */ ){ unixFile *p = (unixFile *)pFile; int fd = -1; /* File descriptor returned by open() */ int openFlags = 0; /* Flags to pass to open() */ int eType = flags&0x0FFF00; /* Type of file to open */ int noLock; /* True to omit locking primitives */ int rc = SQLITE_OK; /* Function Return Code */ int ctrlFlags = 0; /* UNIXFILE_* flags */ 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); #if SQLITE_ENABLE_LOCKING_STYLE int isAutoProxy = (flags & SQLITE_OPEN_AUTOPROXY); #endif #if defined(__APPLE__) || SQLITE_ENABLE_LOCKING_STYLE struct statfs fsInfo; #endif /* If creating a super- or main-file journal, this function will open ** a file-descriptor on the directory too. The first time unixSync() ** is called the directory file descriptor will be fsync()ed and close()d. */ int isNewJrnl = (isCreate && ( eType==SQLITE_OPEN_SUPER_JOURNAL || eType==SQLITE_OPEN_MAIN_JOURNAL || eType==SQLITE_OPEN_WAL )); /* If argument zPath is a NULL pointer, this function is required to open ** a temporary file. Use this buffer to store the file name in. */ |
︙ | ︙ | |||
6002 6003 6004 6005 6006 6007 6008 | ** (d) if DELETEONCLOSE is set, then CREATE must also be set. */ assert((isReadonly==0 || isReadWrite==0) && (isReadWrite || isReadonly)); assert(isCreate==0 || isReadWrite); assert(isExclusive==0 || isCreate); assert(isDelete==0 || isCreate); | | | | > > > > > | 6163 6164 6165 6166 6167 6168 6169 6170 6171 6172 6173 6174 6175 6176 6177 6178 6179 6180 6181 6182 6183 6184 6185 6186 6187 6188 6189 6190 6191 6192 6193 6194 6195 6196 6197 6198 6199 6200 6201 6202 6203 6204 6205 | ** (d) if DELETEONCLOSE is set, then CREATE must also be set. */ assert((isReadonly==0 || isReadWrite==0) && (isReadWrite || isReadonly)); assert(isCreate==0 || isReadWrite); assert(isExclusive==0 || isCreate); assert(isDelete==0 || isCreate); /* The main DB, main journal, WAL file and super-journal are never ** automatically deleted. Nor are they ever temporary files. */ assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MAIN_DB ); assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MAIN_JOURNAL ); assert( (!isDelete && zName) || eType!=SQLITE_OPEN_SUPER_JOURNAL ); assert( (!isDelete && zName) || eType!=SQLITE_OPEN_WAL ); /* Assert that the upper layer has set one of the "file-type" flags. */ assert( eType==SQLITE_OPEN_MAIN_DB || eType==SQLITE_OPEN_TEMP_DB || eType==SQLITE_OPEN_MAIN_JOURNAL || eType==SQLITE_OPEN_TEMP_JOURNAL || eType==SQLITE_OPEN_SUBJOURNAL || eType==SQLITE_OPEN_SUPER_JOURNAL || eType==SQLITE_OPEN_TRANSIENT_DB || eType==SQLITE_OPEN_WAL ); /* Detect a pid change and reset the PRNG. There is a race condition ** here such that two or more threads all trying to open databases at ** the same instant might all reset the PRNG. But multiple resets ** are harmless. */ if( randomnessPid!=osGetpid(0) ){ randomnessPid = osGetpid(0); sqlite3_randomness(0,0); } memset(p, 0, sizeof(unixFile)); #ifdef SQLITE_ASSERT_NO_FILES /* Applications that never read or write a persistent disk files */ assert( zName==0 ); #endif if( eType==SQLITE_OPEN_MAIN_DB ){ UnixUnusedFd *pUnused; pUnused = findReusableFd(zName, flags); if( pUnused ){ fd = pUnused->fd; }else{ |
︙ | ︙ | |||
6067 6068 6069 6070 6071 6072 6073 | ** open(). These must be calculated even if open() is not called, as ** they may be stored as part of the file handle and used by the ** 'conch file' locking functions later on. */ if( isReadonly ) openFlags |= O_RDONLY; if( isReadWrite ) openFlags |= O_RDWR; if( isCreate ) openFlags |= O_CREAT; if( isExclusive ) openFlags |= (O_EXCL|O_NOFOLLOW); | | | 6233 6234 6235 6236 6237 6238 6239 6240 6241 6242 6243 6244 6245 6246 6247 | ** open(). These must be calculated even if open() is not called, as ** they may be stored as part of the file handle and used by the ** 'conch file' locking functions later on. */ if( isReadonly ) openFlags |= O_RDONLY; if( isReadWrite ) openFlags |= O_RDWR; if( isCreate ) openFlags |= O_CREAT; if( isExclusive ) openFlags |= (O_EXCL|O_NOFOLLOW); openFlags |= (O_LARGEFILE|O_BINARY|O_NOFOLLOW); if( fd<0 ){ mode_t openMode; /* Permissions to create file with */ uid_t uid; /* Userid for the file */ gid_t gid; /* Groupid for the file */ rc = findCreateFileMode(zName, flags, &openMode, &uid, &gid); if( rc!=SQLITE_OK ){ |
︙ | ︙ | |||
6103 6104 6105 6106 6107 6108 6109 | } if( fd<0 ){ int rc2 = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zName); if( rc==SQLITE_OK ) rc = rc2; goto open_finished; } | < | | > > > > > > > > > | | > | 6269 6270 6271 6272 6273 6274 6275 6276 6277 6278 6279 6280 6281 6282 6283 6284 6285 6286 6287 6288 6289 6290 6291 6292 6293 6294 6295 6296 6297 6298 6299 6300 6301 6302 6303 6304 6305 6306 6307 | } if( fd<0 ){ int rc2 = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zName); if( rc==SQLITE_OK ) rc = rc2; goto open_finished; } /* The owner of the rollback journal or WAL file should always be the ** same as the owner of the database file. Try to ensure that this is ** the case. The chown() system call will be a no-op if the current ** process lacks root privileges, be we should at least try. Without ** this step, if a root process opens a database file, it can leave ** behinds a journal/WAL that is owned by root and hence make the ** database inaccessible to unprivileged processes. ** ** If openMode==0, then that means uid and gid are not set correctly ** (probably because SQLite is configured to use 8+3 filename mode) and ** in that case we do not want to attempt the chown(). */ if( openMode && (flags & (SQLITE_OPEN_WAL|SQLITE_OPEN_MAIN_JOURNAL))!=0 ){ robustFchown(fd, uid, gid); } } assert( fd>=0 ); if( pOutFlags ){ *pOutFlags = flags; } if( p->pPreallocatedUnused ){ p->pPreallocatedUnused->fd = fd; p->pPreallocatedUnused->flags = flags & (SQLITE_OPEN_READONLY|SQLITE_OPEN_READWRITE); } if( isDelete ){ #if OS_VXWORKS zPath = zName; #elif defined(SQLITE_UNLINK_AFTER_CLOSE) zPath = sqlite3_mprintf("%s", zName); |
︙ | ︙ | |||
6196 6197 6198 6199 6200 6201 6202 | } goto open_finished; } } #endif assert( zPath==0 || zPath[0]=='/' | | | 6371 6372 6373 6374 6375 6376 6377 6378 6379 6380 6381 6382 6383 6384 6385 | } goto open_finished; } } #endif assert( zPath==0 || zPath[0]=='/' || eType==SQLITE_OPEN_SUPER_JOURNAL || eType==SQLITE_OPEN_MAIN_JOURNAL ); rc = fillInUnixFile(pVfs, fd, pFile, zPath, ctrlFlags); open_finished: if( rc!=SQLITE_OK ){ sqlite3_free(p->pPreallocatedUnused); } |
︙ | ︙ | |||
6276 6277 6278 6279 6280 6281 6282 | /* The spec says there are three possible values for flags. But only ** two of them are actually used */ assert( flags==SQLITE_ACCESS_EXISTS || flags==SQLITE_ACCESS_READWRITE ); if( flags==SQLITE_ACCESS_EXISTS ){ struct stat buf; | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 6451 6452 6453 6454 6455 6456 6457 6458 6459 6460 6461 6462 6463 6464 6465 6466 6467 6468 6469 6470 6471 6472 6473 6474 6475 6476 6477 6478 6479 6480 6481 6482 6483 6484 6485 6486 6487 6488 6489 6490 6491 6492 6493 6494 6495 6496 6497 6498 6499 6500 6501 6502 6503 6504 6505 6506 6507 6508 6509 6510 6511 6512 6513 6514 6515 6516 6517 6518 6519 6520 6521 6522 6523 6524 6525 6526 6527 6528 6529 6530 6531 6532 6533 6534 6535 6536 6537 6538 6539 6540 6541 6542 6543 6544 6545 6546 6547 6548 6549 6550 6551 6552 | /* The spec says there are three possible values for flags. But only ** two of them are actually used */ assert( flags==SQLITE_ACCESS_EXISTS || flags==SQLITE_ACCESS_READWRITE ); if( flags==SQLITE_ACCESS_EXISTS ){ struct stat buf; *pResOut = 0==osStat(zPath, &buf) && (!S_ISREG(buf.st_mode) || buf.st_size>0); }else{ *pResOut = osAccess(zPath, W_OK|R_OK)==0; } return SQLITE_OK; } /* ** If the last component of the pathname in z[0]..z[j-1] is something ** other than ".." then back it out and return true. If the last ** component is empty or if it is ".." then return false. */ static int unixBackupDir(const char *z, int *pJ){ int j = *pJ; int i; if( j<=0 ) return 0; for(i=j-1; i>0 && z[i-1]!='/'; i--){} if( i==0 ) return 0; if( z[i]=='.' && i==j-2 && z[i+1]=='.' ) return 0; *pJ = i-1; return 1; } /* ** Convert a relative pathname into a full pathname. Also ** simplify the pathname as follows: ** ** Remove all instances of /./ ** Remove all isntances of /X/../ for any X */ static int mkFullPathname( const char *zPath, /* Input path */ char *zOut, /* Output buffer */ int nOut /* Allocated size of buffer zOut */ ){ int nPath = sqlite3Strlen30(zPath); int iOff = 0; int i, j; if( zPath[0]!='/' ){ if( osGetcwd(zOut, nOut-2)==0 ){ return unixLogError(SQLITE_CANTOPEN_BKPT, "getcwd", zPath); } iOff = sqlite3Strlen30(zOut); zOut[iOff++] = '/'; } if( (iOff+nPath+1)>nOut ){ /* SQLite assumes that xFullPathname() nul-terminates the output buffer ** even if it returns an error. */ zOut[iOff] = '\0'; return SQLITE_CANTOPEN_BKPT; } sqlite3_snprintf(nOut-iOff, &zOut[iOff], "%s", zPath); /* Remove duplicate '/' characters. Except, two // at the beginning ** of a pathname is allowed since this is important on windows. */ for(i=j=1; zOut[i]; i++){ zOut[j++] = zOut[i]; while( zOut[i]=='/' && zOut[i+1]=='/' ) i++; } zOut[j] = 0; assert( zOut[0]=='/' ); for(i=j=0; zOut[i]; i++){ if( zOut[i]=='/' ){ /* Skip over internal "/." directory components */ if( zOut[i+1]=='.' && zOut[i+2]=='/' ){ i += 1; continue; } /* If this is a "/.." directory component then back out the ** previous term of the directory if it is something other than "..". */ if( zOut[i+1]=='.' && zOut[i+2]=='.' && zOut[i+3]=='/' && unixBackupDir(zOut, &j) ){ i += 2; continue; } } if( ALWAYS(j>=0) ) zOut[j] = zOut[i]; j++; } if( NEVER(j==0) ) zOut[j++] = '/'; zOut[j] = 0; return SQLITE_OK; } /* ** Turn a relative pathname into a full pathname. The relative path ** is stored as a nul-terminated string in the buffer pointed to by ** zPath. |
︙ | ︙ | |||
6330 6331 6332 6333 6334 6335 6336 | char *zOut /* Output buffer */ ){ #if !defined(HAVE_READLINK) || !defined(HAVE_LSTAT) return mkFullPathname(zPath, zOut, nOut); #else int rc = SQLITE_OK; int nByte; | | | 6562 6563 6564 6565 6566 6567 6568 6569 6570 6571 6572 6573 6574 6575 6576 | char *zOut /* Output buffer */ ){ #if !defined(HAVE_READLINK) || !defined(HAVE_LSTAT) return mkFullPathname(zPath, zOut, nOut); #else int rc = SQLITE_OK; int nByte; int nLink = 0; /* Number of symbolic links followed so far */ const char *zIn = zPath; /* Input path for each iteration of loop */ char *zDel = 0; assert( pVfs->mxPathname==MAX_PATHNAME ); UNUSED_PARAMETER(pVfs); /* It's odd to simulate an io-error here, but really this is just |
︙ | ︙ | |||
6359 6360 6361 6362 6363 6364 6365 6366 6367 6368 | rc = unixLogError(SQLITE_CANTOPEN_BKPT, "lstat", zIn); } }else{ bLink = S_ISLNK(buf.st_mode); } if( bLink ){ if( zDel==0 ){ zDel = sqlite3_malloc(nOut); if( zDel==0 ) rc = SQLITE_NOMEM_BKPT; | > | | 6591 6592 6593 6594 6595 6596 6597 6598 6599 6600 6601 6602 6603 6604 6605 6606 6607 6608 6609 | rc = unixLogError(SQLITE_CANTOPEN_BKPT, "lstat", zIn); } }else{ bLink = S_ISLNK(buf.st_mode); } if( bLink ){ nLink++; if( zDel==0 ){ zDel = sqlite3_malloc(nOut); if( zDel==0 ) rc = SQLITE_NOMEM_BKPT; }else if( nLink>=SQLITE_MAX_SYMLINKS ){ rc = SQLITE_CANTOPEN_BKPT; } if( rc==SQLITE_OK ){ nByte = osReadlink(zIn, zDel, nOut-1); if( nByte<0 ){ rc = unixLogError(SQLITE_CANTOPEN_BKPT, "readlink", zIn); |
︙ | ︙ | |||
6398 6399 6400 6401 6402 6403 6404 6405 6406 6407 6408 6409 6410 6411 | rc = mkFullPathname(zIn, zOut, nOut); } if( bLink==0 ) break; zIn = zOut; }while( rc==SQLITE_OK ); sqlite3_free(zDel); return rc; #endif /* HAVE_READLINK && HAVE_LSTAT */ } #ifndef SQLITE_OMIT_LOAD_EXTENSION /* | > | 6631 6632 6633 6634 6635 6636 6637 6638 6639 6640 6641 6642 6643 6644 6645 | rc = mkFullPathname(zIn, zOut, nOut); } if( bLink==0 ) break; zIn = zOut; }while( rc==SQLITE_OK ); sqlite3_free(zDel); if( rc==SQLITE_OK && nLink ) rc = SQLITE_OK_SYMLINK; return rc; #endif /* HAVE_READLINK && HAVE_LSTAT */ } #ifndef SQLITE_OMIT_LOAD_EXTENSION /* |
︙ | ︙ | |||
6525 6526 6527 6528 6529 6530 6531 | sp.tv_sec = microseconds / 1000000; sp.tv_nsec = (microseconds % 1000000) * 1000; nanosleep(&sp, NULL); UNUSED_PARAMETER(NotUsed); return microseconds; #elif defined(HAVE_USLEEP) && HAVE_USLEEP | > | | 6759 6760 6761 6762 6763 6764 6765 6766 6767 6768 6769 6770 6771 6772 6773 6774 | sp.tv_sec = microseconds / 1000000; sp.tv_nsec = (microseconds % 1000000) * 1000; nanosleep(&sp, NULL); UNUSED_PARAMETER(NotUsed); return microseconds; #elif defined(HAVE_USLEEP) && HAVE_USLEEP if( microseconds>=1000000 ) sleep(microseconds/1000000); if( microseconds%1000000 ) usleep(microseconds%1000000); UNUSED_PARAMETER(NotUsed); return microseconds; #else int seconds = (microseconds+999999)/1000000; sleep(seconds); UNUSED_PARAMETER(NotUsed); return seconds*1000000; |
︙ | ︙ | |||
6883 6884 6885 6886 6887 6888 6889 | const char *path, /* path for the new unixFile */ unixFile **ppFile, /* unixFile created and returned by ref */ int islockfile /* if non zero missing dirs will be created */ ) { int fd = -1; unixFile *pNew; int rc = SQLITE_OK; | | | 7118 7119 7120 7121 7122 7123 7124 7125 7126 7127 7128 7129 7130 7131 7132 | const char *path, /* path for the new unixFile */ unixFile **ppFile, /* unixFile created and returned by ref */ int islockfile /* if non zero missing dirs will be created */ ) { int fd = -1; unixFile *pNew; int rc = SQLITE_OK; int openFlags = O_RDWR | O_CREAT | O_NOFOLLOW; sqlite3_vfs dummyVfs; int terrno = 0; UnixUnusedFd *pUnused = NULL; /* 1. first try to open/create the file ** 2. if that fails, and this is a lock file (not-conch), try creating ** the parent directories and then try again. |
︙ | ︙ | |||
6913 6914 6915 6916 6917 6918 6919 | if( fd<0 && errno==ENOENT && islockfile ){ if( proxyCreateLockPath(path) == SQLITE_OK ){ fd = robust_open(path, openFlags, 0); } } } if( fd<0 ){ | | | 7148 7149 7150 7151 7152 7153 7154 7155 7156 7157 7158 7159 7160 7161 7162 | if( fd<0 && errno==ENOENT && islockfile ){ if( proxyCreateLockPath(path) == SQLITE_OK ){ fd = robust_open(path, openFlags, 0); } } } if( fd<0 ){ openFlags = O_RDONLY | O_NOFOLLOW; fd = robust_open(path, openFlags, 0); terrno = errno; } if( fd<0 ){ if( islockfile ){ return SQLITE_BUSY; } |
︙ | ︙ | |||
6964 6965 6966 6967 6968 6969 6970 | #ifdef SQLITE_TEST /* simulate multiple hosts by creating unique hostid file paths */ int sqlite3_hostid_num = 0; #endif #define PROXY_HOSTIDLEN 16 /* conch file host id length */ | | | | 7199 7200 7201 7202 7203 7204 7205 7206 7207 7208 7209 7210 7211 7212 7213 7214 7215 7216 7217 7218 7219 7220 7221 7222 7223 7224 | #ifdef SQLITE_TEST /* simulate multiple hosts by creating unique hostid file paths */ int sqlite3_hostid_num = 0; #endif #define PROXY_HOSTIDLEN 16 /* conch file host id length */ #if HAVE_GETHOSTUUID /* Not always defined in the headers as it ought to be */ extern int gethostuuid(uuid_t id, const struct timespec *wait); #endif /* get the host ID via gethostuuid(), pHostID must point to PROXY_HOSTIDLEN ** bytes of writable memory. */ static int proxyGetHostID(unsigned char *pHostID, int *pError){ assert(PROXY_HOSTIDLEN == sizeof(uuid_t)); memset(pHostID, 0, PROXY_HOSTIDLEN); #if HAVE_GETHOSTUUID { struct timespec timeout = {1, 0}; /* 1 sec timeout */ if( gethostuuid(pHostID, &timeout) ){ int err = errno; if( pError ){ *pError = err; } |
︙ | ︙ | |||
7039 7040 7041 7042 7043 7044 7045 | /* read the conch content */ readLen = osPread(conchFile->h, buf, PROXY_MAXCONCHLEN, 0); if( readLen<PROXY_PATHINDEX ){ sqlite3_snprintf(sizeof(errmsg),errmsg,"read error (len %d)",(int)readLen); goto end_breaklock; } /* write it out to the temporary break file */ | | | 7274 7275 7276 7277 7278 7279 7280 7281 7282 7283 7284 7285 7286 7287 7288 | /* read the conch content */ readLen = osPread(conchFile->h, buf, PROXY_MAXCONCHLEN, 0); if( readLen<PROXY_PATHINDEX ){ sqlite3_snprintf(sizeof(errmsg),errmsg,"read error (len %d)",(int)readLen); goto end_breaklock; } /* write it out to the temporary break file */ fd = robust_open(tPath, (O_RDWR|O_CREAT|O_EXCL|O_NOFOLLOW), 0); if( fd<0 ){ sqlite3_snprintf(sizeof(errmsg), errmsg, "create failed (%d)", errno); goto end_breaklock; } if( osPwrite(fd, buf, readLen, 0) != (ssize_t)readLen ){ sqlite3_snprintf(sizeof(errmsg), errmsg, "write failed (%d)", errno); goto end_breaklock; |
︙ | ︙ | |||
7098 7099 7100 7101 7102 7103 7104 | if( osFstat(conchFile->h, &buf) ){ storeLastErrno(pFile, errno); return SQLITE_IOERR_LOCK; } if( nTries==1 ){ conchModTime = buf.st_mtimespec; | | | 7333 7334 7335 7336 7337 7338 7339 7340 7341 7342 7343 7344 7345 7346 7347 | if( osFstat(conchFile->h, &buf) ){ storeLastErrno(pFile, errno); return SQLITE_IOERR_LOCK; } if( nTries==1 ){ conchModTime = buf.st_mtimespec; unixSleep(0,500000); /* wait 0.5 sec and try the lock again*/ continue; } assert( nTries>1 ); if( conchModTime.tv_sec != buf.st_mtimespec.tv_sec || conchModTime.tv_nsec != buf.st_mtimespec.tv_nsec ){ return SQLITE_BUSY; |
︙ | ︙ | |||
7124 7125 7126 7127 7128 7129 7130 | if( 0!=memcmp(&tBuf[PROXY_HEADERLEN], myHostID, PROXY_HOSTIDLEN) ){ return SQLITE_BUSY; } }else{ /* don't break the lock on short read or a version mismatch */ return SQLITE_BUSY; } | | | 7359 7360 7361 7362 7363 7364 7365 7366 7367 7368 7369 7370 7371 7372 7373 | if( 0!=memcmp(&tBuf[PROXY_HEADERLEN], myHostID, PROXY_HOSTIDLEN) ){ return SQLITE_BUSY; } }else{ /* don't break the lock on short read or a version mismatch */ return SQLITE_BUSY; } unixSleep(0,10000000); /* wait 10 sec and try the lock again */ continue; } assert( nTries==3 ); if( 0==proxyBreakConchLock(pFile, myHostID) ){ rc = SQLITE_OK; if( lockType==EXCLUSIVE_LOCK ){ |
︙ | ︙ | |||
7649 7650 7651 7652 7653 7654 7655 | } return rc; } default: { assert( 0 ); /* The call assures that only valid opcodes are sent */ } } | | | 7884 7885 7886 7887 7888 7889 7890 7891 7892 7893 7894 7895 7896 7897 7898 | } return rc; } default: { assert( 0 ); /* The call assures that only valid opcodes are sent */ } } /*NOTREACHED*/ assert(0); return SQLITE_ERROR; } /* ** Within this division (the proxying locking implementation) the procedures ** above this point are all utilities. The lock-related methods of the ** proxy-locking sqlite3_io_method object follow. |
︙ | ︙ | |||
7900 7901 7902 7903 7904 7905 7906 7907 7908 7909 7910 7911 7912 7913 | assert( ArraySize(aSyscall)==29 ); /* 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); } unixBigLock = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1); return SQLITE_OK; } /* ** Shutdown the operating system interface. ** ** Some operating systems might need to do some cleanup in this routine, | > > > > > > > > > > > > > > > > > > > > > > | 8135 8136 8137 8138 8139 8140 8141 8142 8143 8144 8145 8146 8147 8148 8149 8150 8151 8152 8153 8154 8155 8156 8157 8158 8159 8160 8161 8162 8163 8164 8165 8166 8167 8168 8169 8170 | assert( ArraySize(aSyscall)==29 ); /* 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); } unixBigLock = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1); #ifndef SQLITE_OMIT_WAL /* Validate lock assumptions */ assert( SQLITE_SHM_NLOCK==8 ); /* Number of available locks */ assert( UNIX_SHM_BASE==120 ); /* Start of locking area */ /* Locks: ** WRITE UNIX_SHM_BASE 120 ** CKPT UNIX_SHM_BASE+1 121 ** RECOVER UNIX_SHM_BASE+2 122 ** READ-0 UNIX_SHM_BASE+3 123 ** READ-1 UNIX_SHM_BASE+4 124 ** READ-2 UNIX_SHM_BASE+5 125 ** READ-3 UNIX_SHM_BASE+6 126 ** READ-4 UNIX_SHM_BASE+7 127 ** DMS UNIX_SHM_BASE+8 128 */ assert( UNIX_SHM_DMS==128 ); /* Byte offset of the deadman-switch */ #endif /* Initialize temp file dir array. */ unixTempFileInit(); return SQLITE_OK; } /* ** Shutdown the operating system interface. ** ** Some operating systems might need to do some cleanup in this routine, |
︙ | ︙ |
Changes to src/os_win.c.
︙ | ︙ | |||
1286 1287 1288 1289 1290 1291 1292 | ** If a Win32 native heap has been configured, this function will attempt to ** destroy and recreate it. If the Win32 native heap is not isolated and/or ** the sqlite3_memory_used() function does not return zero, SQLITE_BUSY will ** be returned and no changes will be made to the Win32 native heap. */ int sqlite3_win32_reset_heap(){ int rc; | | | | | | 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 | ** If a Win32 native heap has been configured, this function will attempt to ** destroy and recreate it. If the Win32 native heap is not isolated and/or ** the sqlite3_memory_used() function does not return zero, SQLITE_BUSY will ** be returned and no changes will be made to the Win32 native heap. */ int sqlite3_win32_reset_heap(){ int rc; MUTEX_LOGIC( sqlite3_mutex *pMainMtx; ) /* The main static mutex */ MUTEX_LOGIC( sqlite3_mutex *pMem; ) /* The memsys static mutex */ MUTEX_LOGIC( pMainMtx = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN); ) MUTEX_LOGIC( pMem = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MEM); ) sqlite3_mutex_enter(pMainMtx); sqlite3_mutex_enter(pMem); winMemAssertMagic(); if( winMemGetHeap()!=NULL && winMemGetOwned() && sqlite3_memory_used()==0 ){ /* ** At this point, there should be no outstanding memory allocations on ** the heap. Also, since both the main and memsys locks are currently ** being held by us, no other function (i.e. from another thread) should ** be able to even access the heap. Attempt to destroy and recreate our ** isolated Win32 native heap now. */ assert( winMemGetHeap()!=NULL ); assert( winMemGetOwned() ); assert( sqlite3_memory_used()==0 ); |
︙ | ︙ | |||
1319 1320 1321 1322 1323 1324 1325 | }else{ /* ** The Win32 native heap cannot be modified because it may be in use. */ rc = SQLITE_BUSY; } sqlite3_mutex_leave(pMem); | | | 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 | }else{ /* ** The Win32 native heap cannot be modified because it may be in use. */ rc = SQLITE_BUSY; } sqlite3_mutex_leave(pMem); sqlite3_mutex_leave(pMainMtx); return rc; } #endif /* SQLITE_WIN32_MALLOC */ /* ** This function outputs the specified (ANSI) string to the Win32 debugger ** (if available). |
︙ | ︙ | |||
3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 | pFile->ctrlFlags |= mask; } } /* Forward references to VFS helper methods used for temporary files */ static int winGetTempname(sqlite3_vfs *, char **); static int winIsDir(const void *); static BOOL winIsDriveLetterAndColon(const char *); /* ** Control and query of the open file handle. */ static int winFileControl(sqlite3_file *id, int op, void *pArg){ winFile *pFile = (winFile*)id; | > | 3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 | pFile->ctrlFlags |= mask; } } /* Forward references to VFS helper methods used for temporary files */ static int winGetTempname(sqlite3_vfs *, char **); static int winIsDir(const void *); static BOOL winIsLongPathPrefix(const char *); static BOOL winIsDriveLetterAndColon(const char *); /* ** Control and query of the open file handle. */ static int winFileControl(sqlite3_file *id, int op, void *pArg){ winFile *pFile = (winFile*)id; |
︙ | ︙ | |||
4211 4212 4213 4214 4215 4216 4217 4218 4219 4220 4221 4222 4223 4224 | DWORD flags = FILE_MAP_WRITE | FILE_MAP_READ; int rc = SQLITE_OK; if( !pShm ){ rc = winOpenSharedMemory(pDbFd); if( rc!=SQLITE_OK ) return rc; pShm = pDbFd->pShm; } pShmNode = pShm->pShmNode; sqlite3_mutex_enter(pShmNode->mutex); if( pShmNode->isUnlocked ){ rc = winLockSharedMemory(pShmNode); if( rc!=SQLITE_OK ) goto shmpage_out; | > | 4212 4213 4214 4215 4216 4217 4218 4219 4220 4221 4222 4223 4224 4225 4226 | DWORD flags = FILE_MAP_WRITE | FILE_MAP_READ; int rc = SQLITE_OK; if( !pShm ){ rc = winOpenSharedMemory(pDbFd); if( rc!=SQLITE_OK ) return rc; pShm = pDbFd->pShm; assert( pShm!=0 ); } pShmNode = pShm->pShmNode; sqlite3_mutex_enter(pShmNode->mutex); if( pShmNode->isUnlocked ){ rc = winLockSharedMemory(pShmNode); if( rc!=SQLITE_OK ) goto shmpage_out; |
︙ | ︙ | |||
4513 4514 4515 4516 4517 4518 4519 4520 4521 4522 4523 4524 4525 4526 | 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", | > | 4515 4516 4517 4518 4519 4520 4521 4522 4523 4524 4525 4526 4527 4528 4529 | if( rc!=SQLITE_OK ){ OSTRACE(("FETCH pid=%lu, pFile=%p, rc=%s\n", osGetCurrentProcessId(), pFd, sqlite3ErrName(rc))); return rc; } } if( pFd->mmapSize >= iOff+nAmt ){ assert( pFd->pMapRegion!=0 ); *pp = &((u8 *)pFd->pMapRegion)[iOff]; pFd->nFetchOut++; } } #endif OSTRACE(("FETCH pid=%lu, pFile=%p, pp=%p, *pp=%p, rc=SQLITE_OK\n", |
︙ | ︙ | |||
5016 5017 5018 5019 5020 5021 5022 | 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 && ( | | | | | | 5019 5020 5021 5022 5023 5024 5025 5026 5027 5028 5029 5030 5031 5032 5033 5034 5035 5036 5037 5038 5039 5040 5041 5042 5043 5044 5045 5046 5047 5048 5049 5050 5051 5052 5053 5054 5055 5056 5057 5058 5059 5060 5061 5062 5063 5064 | 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_SUPER_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. */ assert((isReadonly==0 || isReadWrite==0) && (isReadWrite || isReadonly)); assert(isCreate==0 || isReadWrite); assert(isExclusive==0 || isCreate); assert(isDelete==0 || isCreate); /* The main DB, main journal, WAL file and super-journal are never ** automatically deleted. Nor are they ever temporary files. */ assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MAIN_DB ); assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MAIN_JOURNAL ); assert( (!isDelete && zName) || eType!=SQLITE_OPEN_SUPER_JOURNAL ); assert( (!isDelete && zName) || eType!=SQLITE_OPEN_WAL ); /* Assert that the upper layer has set one of the "file-type" flags. */ assert( eType==SQLITE_OPEN_MAIN_DB || eType==SQLITE_OPEN_TEMP_DB || eType==SQLITE_OPEN_MAIN_JOURNAL || eType==SQLITE_OPEN_TEMP_JOURNAL || eType==SQLITE_OPEN_SUBJOURNAL || eType==SQLITE_OPEN_SUPER_JOURNAL || eType==SQLITE_OPEN_TRANSIENT_DB || eType==SQLITE_OPEN_WAL ); assert( pFile!=0 ); memset(pFile, 0, sizeof(winFile)); pFile->h = INVALID_HANDLE_VALUE; |
︙ | ︙ | |||
5119 5120 5121 5122 5123 5124 5125 | /* Open existing file, or create if it doesn't exist */ dwCreationDisposition = OPEN_ALWAYS; }else{ /* Opens a file, only if it exists. */ dwCreationDisposition = OPEN_EXISTING; } | > | > > > | 5122 5123 5124 5125 5126 5127 5128 5129 5130 5131 5132 5133 5134 5135 5136 5137 5138 5139 5140 | /* Open existing file, or create if it doesn't exist */ dwCreationDisposition = OPEN_ALWAYS; }else{ /* Opens a file, only if it exists. */ dwCreationDisposition = OPEN_EXISTING; } if( 0==sqlite3_uri_boolean(zName, "exclusive", 0) ){ dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE; }else{ dwShareMode = 0; } if( isDelete ){ #if SQLITE_OS_WINCE dwFlagsAndAttributes = FILE_ATTRIBUTE_HIDDEN; isTemp = 1; #else dwFlagsAndAttributes = FILE_ATTRIBUTE_TEMPORARY |
︙ | ︙ | |||
5259 5260 5261 5262 5263 5264 5265 | }else #endif { sqlite3_free(zConverted); } sqlite3_free(zTmpname); | | > | > | 5266 5267 5268 5269 5270 5271 5272 5273 5274 5275 5276 5277 5278 5279 5280 5281 5282 5283 5284 5285 5286 5287 5288 | }else #endif { sqlite3_free(zConverted); } sqlite3_free(zTmpname); id->pMethods = pAppData ? pAppData->pMethod : &winIoMethod; pFile->pVfs = pVfs; pFile->h = h; if( isReadonly ){ pFile->ctrlFlags |= WINFILE_RDONLY; } if( (flags & SQLITE_OPEN_MAIN_DB) && 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; |
︙ | ︙ | |||
5474 5475 5476 5477 5478 5479 5480 5481 5482 5483 5484 5485 5486 5487 | 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 starts with a drive letter ** followed by a colon character. */ static BOOL winIsDriveLetterAndColon( const char *zPathname | > > > > > > > > > > > | 5483 5484 5485 5486 5487 5488 5489 5490 5491 5492 5493 5494 5495 5496 5497 5498 5499 5500 5501 5502 5503 5504 5505 5506 5507 | 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 starts with the "long path" ** prefix. */ static BOOL winIsLongPathPrefix( const char *zPathname ){ return ( zPathname[0]=='\\' && zPathname[1]=='\\' && zPathname[2]=='?' && zPathname[3]=='\\' ); } /* ** Returns non-zero if the specified path name starts with a drive letter ** followed by a colon character. */ static BOOL winIsDriveLetterAndColon( const char *zPathname |
︙ | ︙ | |||
5539 5540 5541 5542 5543 5544 5545 | ){ #if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && !defined(__CYGWIN__) DWORD nByte; void *zConverted; char *zOut; #endif | | | | > | 5559 5560 5561 5562 5563 5564 5565 5566 5567 5568 5569 5570 5571 5572 5573 5574 5575 5576 5577 | ){ #if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && !defined(__CYGWIN__) DWORD nByte; void *zConverted; char *zOut; #endif /* If this path name begins with "/X:" or "\\?\", where "X" is any ** alphabetic character, discard the initial "/" from the pathname. */ if( zRelative[0]=='/' && (winIsDriveLetterAndColon(zRelative+1) || winIsLongPathPrefix(zRelative+1)) ){ zRelative++; } #if defined(__CYGWIN__) SimulateIOError( return SQLITE_ERROR ); UNUSED_PARAMETER(nFull); assert( nFull>=pVfs->mxPathname ); |
︙ | ︙ |
Changes to src/pager.c.
︙ | ︙ | |||
66 67 68 69 70 71 72 | ** (4) Reads from the database file are either aligned on a page boundary and ** an integer multiple of the page size in length or are taken from the ** first 100 bytes of the database file. ** ** (5) All writes to the database file are synced prior to the rollback journal ** being deleted, truncated, or zeroed. ** | | | | 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 | ** (4) Reads from the database file are either aligned on a page boundary and ** an integer multiple of the page size in length or are taken from the ** first 100 bytes of the database file. ** ** (5) All writes to the database file are synced prior to the rollback journal ** being deleted, truncated, or zeroed. ** ** (6) If a super-journal file is used, then all writes to the database file ** are synced prior to the super-journal being deleted. ** ** Definition: Two databases (or the same database at two points it time) ** are said to be "logically equivalent" if they give the same answer to ** all queries. Note in particular the content of freelist leaf ** pages can be changed arbitrarily without affecting the logical equivalence ** of the database. ** |
︙ | ︙ | |||
402 403 404 405 406 407 408 | ** PagerSharedLock() for more detail. ** ** Pager.eLock may only be set to UNKNOWN_LOCK when the pager is in ** PAGER_OPEN state. */ #define UNKNOWN_LOCK (EXCLUSIVE_LOCK+1) | < < < < < < < < < < < < < < | 402 403 404 405 406 407 408 409 410 411 412 413 414 415 | ** PagerSharedLock() for more detail. ** ** Pager.eLock may only be set to UNKNOWN_LOCK when the pager is in ** PAGER_OPEN state. */ #define UNKNOWN_LOCK (EXCLUSIVE_LOCK+1) /* ** The maximum allowed sector size. 64KiB. If the xSectorsize() method ** returns a value larger than this, then MAX_SECTOR_SIZE is used instead. ** This could conceivably cause corruption following a power failure on ** such a system. This is currently an undocumented limit. */ #define MAX_SECTOR_SIZE 0x10000 |
︙ | ︙ | |||
445 446 447 448 449 450 451 452 453 454 455 456 457 458 | typedef struct PagerSavepoint PagerSavepoint; struct PagerSavepoint { i64 iOffset; /* Starting offset in main journal */ i64 iHdrOffset; /* See above */ Bitvec *pInSavepoint; /* Set of pages in this savepoint */ Pgno nOrig; /* Original number of pages in file */ Pgno iSubRec; /* Index of first record in sub-journal */ #ifndef SQLITE_OMIT_WAL u32 aWalData[WAL_SAVEPOINT_NDATA]; /* WAL savepoint context */ #endif }; /* ** Bits of the Pager.doNotSpill flag. See further description below. | > | 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 | typedef struct PagerSavepoint PagerSavepoint; struct PagerSavepoint { i64 iOffset; /* Starting offset in main journal */ i64 iHdrOffset; /* See above */ Bitvec *pInSavepoint; /* Set of pages in this savepoint */ Pgno nOrig; /* Original number of pages in file */ Pgno iSubRec; /* Index of first record in sub-journal */ int bTruncateOnRelease; /* If stmt journal may be truncated on RELEASE */ #ifndef SQLITE_OMIT_WAL u32 aWalData[WAL_SAVEPOINT_NDATA]; /* WAL savepoint context */ #endif }; /* ** Bits of the Pager.doNotSpill flag. See further description below. |
︙ | ︙ | |||
498 499 500 501 502 503 504 | ** The changeCountDone flag is inspected. If it is true, the work of ** updating the change-counter is omitted for the current transaction. ** ** This mechanism means that when running in exclusive mode, a connection ** need only update the change-counter once, for the first transaction ** committed. ** | | | | | | | | | | 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 | ** The changeCountDone flag is inspected. If it is true, the work of ** updating the change-counter is omitted for the current transaction. ** ** This mechanism means that when running in exclusive mode, a connection ** need only update the change-counter once, for the first transaction ** committed. ** ** setSuper ** ** When PagerCommitPhaseOne() is called to commit a transaction, it may ** (or may not) specify a super-journal name to be written into the ** journal file before it is synced to disk. ** ** Whether or not a journal file contains a super-journal pointer affects ** the way in which the journal file is finalized after the transaction is ** committed or rolled back when running in "journal_mode=PERSIST" mode. ** If a journal file does not contain a super-journal pointer, it is ** finalized by overwriting the first journal header with zeroes. If ** it does contain a super-journal pointer the journal file is finalized ** by truncating it to zero bytes, just as if the connection were ** running in "journal_mode=truncate" mode. ** ** Journal files that contain super-journal pointers cannot be finalized ** simply by overwriting the first journal-header with zeroes, as the ** super-journal pointer could interfere with hot-journal rollback of any ** subsequently interrupted transaction that reuses the journal file. ** ** 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 setSuper flag ** is cleared anyway (and the pager will move to ERROR state). ** ** doNotSpill ** ** This 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). |
︙ | ︙ | |||
639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 | u8 extraSync; /* sync directory after journal delete */ u8 syncFlags; /* SYNC_NORMAL or SYNC_FULL otherwise */ u8 walSyncFlags; /* See description above */ u8 tempFile; /* zFilename is a temporary or immutable file */ u8 noLock; /* Do not lock (except in WAL mode) */ u8 readOnly; /* True for a read-only database */ u8 memDb; /* True to inhibit all file I/O */ /************************************************************************** ** The following block contains those class members that change during ** routine operation. Class members not in this block are either fixed ** when the pager is first created or else only change when there is a ** significant mode change (such as changing the page_size, locking_mode, ** or the journal_mode). From another view, these class members describe ** the "state" of the pager, while other class members describe the ** "configuration" of the pager. */ u8 eState; /* Pager state (OPEN, READER, WRITER_LOCKED..) */ u8 eLock; /* Current lock held on database file */ u8 changeCountDone; /* Set after incrementing the change-counter */ | > | | 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 | u8 extraSync; /* sync directory after journal delete */ u8 syncFlags; /* SYNC_NORMAL or SYNC_FULL otherwise */ u8 walSyncFlags; /* See description above */ u8 tempFile; /* zFilename is a temporary or immutable file */ u8 noLock; /* Do not lock (except in WAL mode) */ u8 readOnly; /* True for a read-only database */ u8 memDb; /* True to inhibit all file I/O */ u8 memVfs; /* VFS-implemented memory database */ /************************************************************************** ** The following block contains those class members that change during ** routine operation. Class members not in this block are either fixed ** when the pager is first created or else only change when there is a ** significant mode change (such as changing the page_size, locking_mode, ** or the journal_mode). From another view, these class members describe ** the "state" of the pager, while other class members describe the ** "configuration" of the pager. */ u8 eState; /* Pager state (OPEN, READER, WRITER_LOCKED..) */ u8 eLock; /* Current lock held on database file */ u8 changeCountDone; /* Set after incrementing the change-counter */ u8 setSuper; /* Super-jrnl name is written into jrnl */ u8 doNotSpill; /* Do not spill the cache when non-zero */ u8 subjInMemory; /* True to use in-memory sub-journals */ u8 bUseFetch; /* True to use xFetch() */ u8 hasHeldSharedLock; /* True if a shared lock has ever been held */ Pgno dbSize; /* Number of pages in the database */ Pgno dbOrigSize; /* dbSize before the current transaction */ Pgno dbFileSize; /* Number of pages in the database file */ |
︙ | ︙ | |||
691 692 693 694 695 696 697 | ** 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() */ u32 sectorSize; /* Assumed sector size during rollback */ | < > < < < < < < | 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 | ** 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() */ u32 sectorSize; /* Assumed sector size during rollback */ Pgno mxPgno; /* Maximum allowed size of the database */ i64 pageSize; /* Number of bytes in a page */ i64 journalSizeLimit; /* Size limit for persistent journal files */ char *zFilename; /* Name of the database file */ char *zJournal; /* Name of the journal file */ int (*xBusyHandler)(void*); /* Function to call when busy */ void *pBusyHandlerArg; /* Context argument for xBusyHandler */ int aStat[4]; /* Total cache hits, misses, writes, spills */ #ifdef SQLITE_TEST int nRead; /* Database pages read */ #endif void (*xReiniter)(DbPage*); /* Call this routine when reloading pages */ int (*xGet)(Pager*,Pgno,DbPage**,int); /* Routine to fetch a patch */ char *pTmpSpace; /* Pager.pageSize bytes of space for tmp use */ PCache *pPCache; /* Pointer to page cache object */ #ifndef SQLITE_OMIT_WAL Wal *pWal; /* Write-ahead log used by "journal_mode=wal" */ char *zWal; /* File name for write-ahead log */ #endif }; |
︙ | ︙ | |||
805 806 807 808 809 810 811 | */ #if SQLITE_MAX_MMAP_SIZE>0 # define USEFETCH(x) ((x)->bUseFetch) #else # define USEFETCH(x) 0 #endif | < < < < < | 787 788 789 790 791 792 793 794 795 796 797 798 799 800 | */ #if SQLITE_MAX_MMAP_SIZE>0 # define USEFETCH(x) ((x)->bUseFetch) #else # define USEFETCH(x) 0 #endif /* ** The argument to this macro is a file descriptor (type sqlite3_file*). ** Return 0 if it is not open, or non-zero (but not 1) if it is. ** ** This is so that expressions can be written as: ** ** if( isOpen(pPager->jfd) ){ ... |
︙ | ︙ | |||
941 942 943 944 945 946 947 | assert( p->eLock>=RESERVED_LOCK ); } #ifndef SQLITE_OMIT_CONCURRENT assert( pPager->dbSize==pPager->dbOrigSize || pPager->pAllRead ); #endif assert( pPager->dbOrigSize==pPager->dbFileSize ); assert( pPager->dbOrigSize==pPager->dbHintSize ); | | | 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 | assert( p->eLock>=RESERVED_LOCK ); } #ifndef SQLITE_OMIT_CONCURRENT assert( pPager->dbSize==pPager->dbOrigSize || pPager->pAllRead ); #endif assert( pPager->dbOrigSize==pPager->dbFileSize ); assert( pPager->dbOrigSize==pPager->dbHintSize ); assert( pPager->setSuper==0 ); break; case PAGER_WRITER_CACHEMOD: assert( p->eLock!=UNKNOWN_LOCK ); assert( pPager->errCode==SQLITE_OK ); if( !pagerUseWal(pPager) ){ /* It is possible that if journal_mode=wal here that neither the |
︙ | ︙ | |||
1071 1072 1073 1074 1075 1076 1077 | ** Set the Pager.xGet method for the appropriate routine used to fetch ** content from the pager. */ static void setGetterMethod(Pager *pPager){ if( pPager->errCode ){ pPager->xGet = getPageError; #if SQLITE_MAX_MMAP_SIZE>0 | | < < < < | 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 | ** Set the Pager.xGet method for the appropriate routine used to fetch ** content from the pager. */ static void setGetterMethod(Pager *pPager){ if( pPager->errCode ){ pPager->xGet = getPageError; #if SQLITE_MAX_MMAP_SIZE>0 }else if( USEFETCH(pPager) ){ pPager->xGet = getPageMMap; #endif /* SQLITE_MAX_MMAP_SIZE>0 */ }else{ pPager->xGet = getPageNormal; } } |
︙ | ︙ | |||
1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 | Pager *pPager = pPg->pPager; PagerSavepoint *p; Pgno pgno = pPg->pgno; int i; for(i=0; i<pPager->nSavepoint; i++){ p = &pPager->aSavepoint[i]; if( p->nOrig>=pgno && 0==sqlite3BitvecTestNotNull(p->pInSavepoint, pgno) ){ return 1; } } return 0; } #ifdef SQLITE_DEBUG | > > > | 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 | Pager *pPager = pPg->pPager; PagerSavepoint *p; Pgno pgno = pPg->pgno; int i; for(i=0; i<pPager->nSavepoint; i++){ p = &pPager->aSavepoint[i]; if( p->nOrig>=pgno && 0==sqlite3BitvecTestNotNull(p->pInSavepoint, pgno) ){ for(i=i+1; i<pPager->nSavepoint; i++){ pPager->aSavepoint[i].bTruncateOnRelease = 0; } return 1; } } return 0; } #ifdef SQLITE_DEBUG |
︙ | ︙ | |||
1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 | assert( pPager->eLock>=eLock ); rc = pPager->noLock ? SQLITE_OK : sqlite3OsUnlock(pPager->fd, eLock); if( pPager->eLock!=UNKNOWN_LOCK ){ pPager->eLock = (u8)eLock; } IOTRACE(("UNLOCK %p %d\n", pPager, eLock)) } return rc; } /* ** Lock the database file to level eLock, which must be either SHARED_LOCK, ** RESERVED_LOCK or EXCLUSIVE_LOCK. If the caller is successful, set the ** Pager.eLock variable to the new locking state. | > | 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 | assert( pPager->eLock>=eLock ); rc = pPager->noLock ? SQLITE_OK : sqlite3OsUnlock(pPager->fd, eLock); if( pPager->eLock!=UNKNOWN_LOCK ){ pPager->eLock = (u8)eLock; } IOTRACE(("UNLOCK %p %d\n", pPager, eLock)) } pPager->changeCountDone = pPager->tempFile; /* ticket fb3b3024ea238d5c */ return rc; } /* ** Lock the database file to level eLock, which must be either SHARED_LOCK, ** RESERVED_LOCK or EXCLUSIVE_LOCK. If the caller is successful, set the ** Pager.eLock variable to the new locking state. |
︙ | ︙ | |||
1298 1299 1300 1301 1302 1303 1304 | #define pager_pagehash(X) 0 #define pager_set_pagehash(X) #define CHECK_PAGE(x) #endif /* SQLITE_CHECK_PAGES */ /* ** When this is called the journal file for pager pPager must be open. | | | | | | | | | | | | | | | | | | | | | | | | > | 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 | #define pager_pagehash(X) 0 #define pager_set_pagehash(X) #define CHECK_PAGE(x) #endif /* SQLITE_CHECK_PAGES */ /* ** When this is called the journal file for pager pPager must be open. ** This function attempts to read a super-journal file name from the ** end of the file and, if successful, copies it into memory supplied ** by the caller. See comments above writeSuperJournal() for the format ** used to store a super-journal file name at the end of a journal file. ** ** zSuper must point to a buffer of at least nSuper bytes allocated by ** the caller. This should be sqlite3_vfs.mxPathname+1 (to ensure there is ** enough space to write the super-journal name). If the super-journal ** name in the journal is longer than nSuper bytes (including a ** nul-terminator), then this is handled as if no super-journal name ** were present in the journal. ** ** If a super-journal file name is present at the end of the journal ** file, then it is copied into the buffer pointed to by zSuper. A ** nul-terminator byte is appended to the buffer following the ** super-journal file name. ** ** If it is determined that no super-journal file name is present ** zSuper[0] is set to 0 and SQLITE_OK returned. ** ** If an error occurs while reading from the journal file, an SQLite ** error code is returned. */ static int readSuperJournal(sqlite3_file *pJrnl, char *zSuper, u32 nSuper){ int rc; /* Return code */ u32 len; /* Length in bytes of super-journal name */ i64 szJ; /* Total size in bytes of journal file pJrnl */ u32 cksum; /* MJ checksum value read from journal */ u32 u; /* Unsigned loop counter */ unsigned char aMagic[8]; /* A buffer to hold the magic header */ zSuper[0] = '\0'; if( SQLITE_OK!=(rc = sqlite3OsFileSize(pJrnl, &szJ)) || szJ<16 || SQLITE_OK!=(rc = read32bits(pJrnl, szJ-16, &len)) || len>=nSuper || len>szJ-16 || len==0 || SQLITE_OK!=(rc = read32bits(pJrnl, szJ-12, &cksum)) || SQLITE_OK!=(rc = sqlite3OsRead(pJrnl, aMagic, 8, szJ-8)) || memcmp(aMagic, aJournalMagic, 8) || SQLITE_OK!=(rc = sqlite3OsRead(pJrnl, zSuper, len, szJ-16-len)) ){ return rc; } /* See if the checksum matches the super-journal name */ for(u=0; u<len; u++){ cksum -= zSuper[u]; } if( cksum ){ /* If the checksum doesn't add up, then one or more of the disk sectors ** containing the super-journal filename is corrupted. This means ** definitely roll back, so just return SQLITE_OK and report a (nul) ** super-journal filename. */ len = 0; } zSuper[len] = '\0'; zSuper[len+1] = '\0'; return SQLITE_OK; } /* ** Return the offset of the sector boundary at or immediately ** following the value in pPager->journalOff, assuming a sector |
︙ | ︙ | |||
1684 1685 1686 1687 1688 1689 1690 | pPager->journalOff += JOURNAL_HDR_SZ(pPager); return rc; } /* | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 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 1744 1745 | pPager->journalOff += JOURNAL_HDR_SZ(pPager); return rc; } /* ** Write the supplied super-journal name into the journal file for pager ** pPager at the current location. The super-journal name must be the last ** thing written to a journal file. If the pager is in full-sync mode, the ** journal file descriptor is advanced to the next sector boundary before ** anything is written. The format is: ** ** + 4 bytes: PAGER_MJ_PGNO. ** + N bytes: super-journal filename in utf-8. ** + 4 bytes: N (length of super-journal name in bytes, no nul-terminator). ** + 4 bytes: super-journal name checksum. ** + 8 bytes: aJournalMagic[]. ** ** The super-journal page checksum is the sum of the bytes in thesuper-journal ** name, where each byte is interpreted as a signed 8-bit integer. ** ** If zSuper is a NULL pointer (occurs for a single database transaction), ** this call is a no-op. */ static int writeSuperJournal(Pager *pPager, const char *zSuper){ int rc; /* Return code */ int nSuper; /* Length of string zSuper */ i64 iHdrOff; /* Offset of header in journal file */ i64 jrnlSize; /* Size of journal file on disk */ u32 cksum = 0; /* Checksum of string zSuper */ assert( pPager->setSuper==0 ); assert( !pagerUseWal(pPager) ); if( !zSuper || pPager->journalMode==PAGER_JOURNALMODE_MEMORY || !isOpen(pPager->jfd) ){ return SQLITE_OK; } pPager->setSuper = 1; assert( pPager->journalHdr <= pPager->journalOff ); /* Calculate the length in bytes and the checksum of zSuper */ for(nSuper=0; zSuper[nSuper]; nSuper++){ cksum += zSuper[nSuper]; } /* If in full-sync mode, advance to the next disk sector before writing ** the super-journal name. This is in case the previous page written to ** the journal has already been synced. */ if( pPager->fullSync ){ pPager->journalOff = journalHdrOffset(pPager); } iHdrOff = pPager->journalOff; /* Write the super-journal data to the end of the journal file. If ** an error occurs, return the error code to the caller. */ if( (0 != (rc = write32bits(pPager->jfd, iHdrOff, PAGER_MJ_PGNO(pPager)))) || (0 != (rc = sqlite3OsWrite(pPager->jfd, zSuper, nSuper, iHdrOff+4))) || (0 != (rc = write32bits(pPager->jfd, iHdrOff+4+nSuper, nSuper))) || (0 != (rc = write32bits(pPager->jfd, iHdrOff+4+nSuper+4, cksum))) || (0 != (rc = sqlite3OsWrite(pPager->jfd, aJournalMagic, 8, iHdrOff+4+nSuper+8))) ){ return rc; } pPager->journalOff += (nSuper+20); /* If the pager is in peristent-journal mode, then the physical ** journal-file may extend past the end of the super-journal name ** and 8 bytes of magic data just written to the file. This is ** dangerous because the code to rollback a hot-journal file ** will not be able to find the super-journal name to determine ** whether or not the journal is hot. ** ** Easiest thing to do in this scenario is to truncate the journal ** file to the required size. */ if( SQLITE_OK==(rc = sqlite3OsFileSize(pPager->jfd, &jrnlSize)) && jrnlSize>pPager->journalOff |
︙ | ︙ | |||
1936 1937 1938 1939 1940 1941 1942 | } /* The pager state may be changed from PAGER_ERROR to PAGER_OPEN here ** without clearing the error code. This is intentional - the error ** code is cleared and the cache reset in the block below. */ assert( pPager->errCode || pPager->eState!=PAGER_ERROR ); | < | 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 | } /* The pager state may be changed from PAGER_ERROR to PAGER_OPEN here ** without clearing the error code. This is intentional - the error ** code is cleared and the cache reset in the block below. */ assert( pPager->errCode || pPager->eState!=PAGER_ERROR ); pPager->eState = PAGER_OPEN; } /* If Pager.errCode is set, the contents of the pager cache cannot be ** trusted. Now that there are no outstanding references to the pager, ** it can safely move back to PAGER_OPEN state. This happens in both ** normal and exclusive-locking mode. |
︙ | ︙ | |||
1961 1962 1963 1964 1965 1966 1967 | if( USEFETCH(pPager) ) sqlite3OsUnfetch(pPager->fd, 0, 0); pPager->errCode = SQLITE_OK; setGetterMethod(pPager); } pPager->journalOff = 0; pPager->journalHdr = 0; | | | 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 | if( USEFETCH(pPager) ) sqlite3OsUnfetch(pPager->fd, 0, 0); pPager->errCode = SQLITE_OK; setGetterMethod(pPager); } pPager->journalOff = 0; pPager->journalHdr = 0; pPager->setSuper = 0; } /* ** This function is called whenever an IOERR or FULL error that requires ** the pager to transition into the ERROR state may ahve occurred. ** The first argument is a pointer to the pager structure, the second ** the error-code about to be returned by a pager API function. The |
︙ | ︙ | |||
2077 2078 2079 2080 2081 2082 2083 | ** database then the IO error code is returned to the user. If the ** operation to finalize the journal file fails, then the code still ** tries to unlock the database file if not in exclusive mode. If the ** unlock operation fails as well, then the first error code related ** to the first error encountered (the journal finalization one) is ** returned. */ | | | 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 | ** database then the IO error code is returned to the user. If the ** operation to finalize the journal file fails, then the code still ** tries to unlock the database file if not in exclusive mode. If the ** unlock operation fails as well, then the first error code related ** to the first error encountered (the journal finalization one) is ** returned. */ static int pager_end_transaction(Pager *pPager, int hasSuper, int bCommit){ int rc = SQLITE_OK; /* Error code from journal finalization operation */ int rc2 = SQLITE_OK; /* Error code from db file unlock operation */ /* Do nothing if the pager does not have an open write transaction ** or at least a RESERVED lock. This function may be called when there ** is no write-transaction active but a RESERVED or greater lock is ** held under two circumstances: |
︙ | ︙ | |||
2129 2130 2131 2132 2133 2134 2135 | rc = sqlite3OsSync(pPager->jfd, pPager->syncFlags); } } pPager->journalOff = 0; }else if( pPager->journalMode==PAGER_JOURNALMODE_PERSIST || (pPager->exclusiveMode && pPager->journalMode!=PAGER_JOURNALMODE_WAL) ){ | | | 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 | rc = sqlite3OsSync(pPager->jfd, pPager->syncFlags); } } pPager->journalOff = 0; }else if( pPager->journalMode==PAGER_JOURNALMODE_PERSIST || (pPager->exclusiveMode && pPager->journalMode!=PAGER_JOURNALMODE_WAL) ){ rc = zeroJournalHdr(pPager, hasSuper||pPager->tempFile); pPager->journalOff = 0; }else{ /* This branch may be executed with Pager.journalMode==MEMORY if ** a hot-journal was just rolled back. In this case the journal ** file should be closed and deleted. If this connection writes to ** the database file, it will do so using an in-memory journal. */ |
︙ | ︙ | |||
2199 2200 2201 2202 2203 2204 2205 | if( rc==SQLITE_NOTFOUND ) rc = SQLITE_OK; } if( !pPager->exclusiveMode && (!pagerUseWal(pPager) || sqlite3WalExclusiveMode(pPager->pWal, 0)) ){ rc2 = pagerUnlockDb(pPager, SHARED_LOCK); | < | | 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 | if( rc==SQLITE_NOTFOUND ) rc = SQLITE_OK; } if( !pPager->exclusiveMode && (!pagerUseWal(pPager) || sqlite3WalExclusiveMode(pPager->pWal, 0)) ){ rc2 = pagerUnlockDb(pPager, SHARED_LOCK); } pPager->eState = PAGER_READER; pPager->setSuper = 0; return (rc==SQLITE_OK?rc2:rc); } /* ** Execute a rollback if a transaction is active and unlock the ** database file. |
︙ | ︙ | |||
2268 2269 2270 2271 2272 2273 2274 | while( i>0 ){ cksum += aData[i]; i -= 200; } return cksum; } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 | while( i>0 ){ cksum += aData[i]; i -= 200; } return cksum; } /* ** Read a single page from either the journal file (if isMainJrnl==1) or ** from the sub-journal (if isMainJrnl==0) and playback that page. ** The page begins at offset *pOffset into the file. The *pOffset ** value is increased to the start of the next page in the journal. ** ** The main rollback journal uses checksums - the statement journal does |
︙ | ︙ | |||
2348 2349 2350 2351 2352 2353 2354 | int rc; PgHdr *pPg; /* An existing page in the cache */ Pgno pgno; /* The page number of a page in journal */ u32 cksum; /* Checksum used for sanity checking */ char *aData; /* Temporary storage for the page */ sqlite3_file *jfd; /* The file descriptor for the journal file */ int isSynced; /* True if journal page is synced */ | < < < < < | 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 | int rc; PgHdr *pPg; /* An existing page in the cache */ Pgno pgno; /* The page number of a page in journal */ u32 cksum; /* Checksum used for sanity checking */ char *aData; /* Temporary storage for the page */ sqlite3_file *jfd; /* The file descriptor for the journal file */ int isSynced; /* True if journal page is synced */ assert( (isMainJrnl&~1)==0 ); /* isMainJrnl is 0 or 1 */ assert( (isSavepnt&~1)==0 ); /* isSavepnt is 0 or 1 */ assert( isMainJrnl || pDone ); /* pDone always used on sub-journals */ assert( isSavepnt || pDone==0 ); /* pDone never used on non-savepoint */ aData = pPager->pTmpSpace; |
︙ | ︙ | |||
2415 2416 2417 2418 2419 2420 2421 | return rc; } /* When playing back page 1, restore the nReserve setting */ if( pgno==1 && pPager->nReserve!=((u8*)aData)[20] ){ pPager->nReserve = ((u8*)aData)[20]; | < | 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 | return rc; } /* When playing back page 1, restore the nReserve setting */ if( pgno==1 && pPager->nReserve!=((u8*)aData)[20] ){ pPager->nReserve = ((u8*)aData)[20]; } /* If the pager is in CACHEMOD state, then there must be a copy of this ** page in the pager cache. In this case just update the pager cache, ** not the database file. The page is left marked dirty in this case. ** ** An exception to the above rule: If the database is in no-sync mode |
︙ | ︙ | |||
2483 2484 2485 2486 2487 2488 2489 | /* Write the data read from the journal back into the database file. ** This is usually safe even for an encrypted database - as the data ** was encrypted before it was written to the journal file. The exception ** is if the data was just read from an in-memory sub-journal. In that ** case it must be encrypted here before it is copied into the database ** file. */ | < < < < < < < < < < < < < < | 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 | /* Write the data read from the journal back into the database file. ** This is usually safe even for an encrypted database - as the data ** was encrypted before it was written to the journal file. The exception ** is if the data was just read from an in-memory sub-journal. In that ** case it must be encrypted here before it is copied into the database ** file. */ rc = sqlite3OsWrite(pPager->fd, (u8 *)aData, pPager->pageSize, ofst); if( pgno>pPager->dbFileSize ){ pPager->dbFileSize = pgno; } if( pPager->pBackup ){ sqlite3BackupUpdate(pPager->pBackup, pgno, (u8*)aData); } }else if( !isMainJrnl && pPg==0 ){ /* If this is a rollback of a savepoint and data was not written to ** the database and the page is not in-memory, there is a potential ** problem. When the page is next fetched by the b-tree layer, it ** will be read from the database file, which may or may not be |
︙ | ︙ | |||
2553 2554 2555 2556 2557 2558 2559 | pager_set_pagehash(pPg); /* If this was page 1, then restore the value of Pager.dbFileVers. ** Do this before any decoding. */ if( pgno==1 ){ memcpy(&pPager->dbFileVers, &((u8*)pData)[24],sizeof(pPager->dbFileVers)); } | < < < < < | | | | | | | | | | | | | | | | | > | | | | < | > | | > | | | | | | | | | | | > | > | | | > | | | | | | > > > | | | | | | | | | | | | | | | 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 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 | pager_set_pagehash(pPg); /* If this was page 1, then restore the value of Pager.dbFileVers. ** Do this before any decoding. */ if( pgno==1 ){ memcpy(&pPager->dbFileVers, &((u8*)pData)[24],sizeof(pPager->dbFileVers)); } sqlite3PcacheRelease(pPg); } return rc; } /* ** Parameter zSuper is the name of a super-journal file. A single journal ** file that referred to the super-journal file has just been rolled back. ** This routine checks if it is possible to delete the super-journal file, ** and does so if it is. ** ** Argument zSuper may point to Pager.pTmpSpace. So that buffer is not ** available for use within this function. ** ** When a super-journal file is created, it is populated with the names ** of all of its child journals, one after another, formatted as utf-8 ** encoded text. The end of each child journal file is marked with a ** nul-terminator byte (0x00). i.e. the entire contents of a super-journal ** file for a transaction involving two databases might be: ** ** "/home/bill/a.db-journal\x00/home/bill/b.db-journal\x00" ** ** A super-journal file may only be deleted once all of its child ** journals have been rolled back. ** ** This function reads the contents of the super-journal file into ** memory and loops through each of the child journal names. For ** each child journal, it checks if: ** ** * if the child journal exists, and if so ** * if the child journal contains a reference to super-journal ** file zSuper ** ** If a child journal can be found that matches both of the criteria ** above, this function returns without doing anything. Otherwise, if ** no such child journal can be found, file zSuper is deleted from ** the file-system using sqlite3OsDelete(). ** ** If an IO error within this function, an error code is returned. This ** function allocates memory by calling sqlite3Malloc(). If an allocation ** fails, SQLITE_NOMEM is returned. Otherwise, if no IO or malloc errors ** occur, SQLITE_OK is returned. ** ** TODO: This function allocates a single block of memory to load ** the entire contents of the super-journal file. This could be ** a couple of kilobytes or so - potentially larger than the page ** size. */ static int pager_delsuper(Pager *pPager, const char *zSuper){ sqlite3_vfs *pVfs = pPager->pVfs; int rc; /* Return code */ sqlite3_file *pSuper; /* Malloc'd super-journal file descriptor */ sqlite3_file *pJournal; /* Malloc'd child-journal file descriptor */ char *zSuperJournal = 0; /* Contents of super-journal file */ i64 nSuperJournal; /* Size of super-journal file */ char *zJournal; /* Pointer to one journal within MJ file */ char *zSuperPtr; /* Space to hold super-journal filename */ char *zFree = 0; /* Free this buffer */ int nSuperPtr; /* Amount of space allocated to zSuperPtr[] */ /* Allocate space for both the pJournal and pSuper file descriptors. ** If successful, open the super-journal file for reading. */ pSuper = (sqlite3_file *)sqlite3MallocZero(pVfs->szOsFile * 2); if( !pSuper ){ rc = SQLITE_NOMEM_BKPT; pJournal = 0; }else{ const int flags = (SQLITE_OPEN_READONLY|SQLITE_OPEN_SUPER_JOURNAL); rc = sqlite3OsOpen(pVfs, zSuper, pSuper, flags, 0); pJournal = (sqlite3_file *)(((u8 *)pSuper) + pVfs->szOsFile); } if( rc!=SQLITE_OK ) goto delsuper_out; /* Load the entire super-journal file into space obtained from ** sqlite3_malloc() and pointed to by zSuperJournal. Also obtain ** sufficient space (in zSuperPtr) to hold the names of super-journal ** files extracted from regular rollback-journals. */ rc = sqlite3OsFileSize(pSuper, &nSuperJournal); if( rc!=SQLITE_OK ) goto delsuper_out; nSuperPtr = pVfs->mxPathname+1; zFree = sqlite3Malloc(4 + nSuperJournal + nSuperPtr + 2); if( !zFree ){ rc = SQLITE_NOMEM_BKPT; goto delsuper_out; } zFree[0] = zFree[1] = zFree[2] = zFree[3] = 0; zSuperJournal = &zFree[4]; zSuperPtr = &zSuperJournal[nSuperJournal+2]; rc = sqlite3OsRead(pSuper, zSuperJournal, (int)nSuperJournal, 0); if( rc!=SQLITE_OK ) goto delsuper_out; zSuperJournal[nSuperJournal] = 0; zSuperJournal[nSuperJournal+1] = 0; zJournal = zSuperJournal; while( (zJournal-zSuperJournal)<nSuperJournal ){ int exists; rc = sqlite3OsAccess(pVfs, zJournal, SQLITE_ACCESS_EXISTS, &exists); if( rc!=SQLITE_OK ){ goto delsuper_out; } if( exists ){ /* One of the journals pointed to by the super-journal exists. ** Open it and check if it points at the super-journal. If ** so, return without deleting the super-journal file. ** NB: zJournal is really a MAIN_JOURNAL. But call it a ** SUPER_JOURNAL here so that the VFS will not send the zJournal ** name into sqlite3_database_file_object(). */ int c; int flags = (SQLITE_OPEN_READONLY|SQLITE_OPEN_SUPER_JOURNAL); rc = sqlite3OsOpen(pVfs, zJournal, pJournal, flags, 0); if( rc!=SQLITE_OK ){ goto delsuper_out; } rc = readSuperJournal(pJournal, zSuperPtr, nSuperPtr); sqlite3OsClose(pJournal); if( rc!=SQLITE_OK ){ goto delsuper_out; } c = zSuperPtr[0]!=0 && strcmp(zSuperPtr, zSuper)==0; if( c ){ /* We have a match. Do not delete the super-journal file. */ goto delsuper_out; } } zJournal += (sqlite3Strlen30(zJournal)+1); } sqlite3OsClose(pSuper); rc = sqlite3OsDelete(pVfs, zSuper, 0); delsuper_out: sqlite3_free(zFree); if( pSuper ){ sqlite3OsClose(pSuper); assert( !isOpen(pJournal) ); sqlite3_free(pSuper); } return rc; } /* ** This function is used to change the actual size of the database |
︙ | ︙ | |||
2768 2769 2770 2771 2772 2773 2774 | } /* ** Set the value of the Pager.sectorSize variable for the given ** pager based on the value returned by the xSectorSize method ** of the open database file. The sector size will be used ** to determine the size and alignment of journal header and | | | 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 | } /* ** Set the value of the Pager.sectorSize variable for the given ** pager based on the value returned by the xSectorSize method ** of the open database file. The sector size will be used ** to determine the size and alignment of journal header and ** super-journal pointers within created journal files. ** ** For temporary files the effective sector size is always 512 bytes. ** ** Otherwise, for non-temporary files, the effective sector size is ** the value returned by the xSectorSize() method rounded up to 32 if ** it is less than 32, or rounded down to MAX_SECTOR_SIZE if it ** is greater than MAX_SECTOR_SIZE. |
︙ | ︙ | |||
2867 2868 2869 2870 2871 2872 2873 | sqlite3_vfs *pVfs = pPager->pVfs; i64 szJ; /* Size of the journal file in bytes */ 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() */ | | | | | | | | | | 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 | sqlite3_vfs *pVfs = pPager->pVfs; i64 szJ; /* Size of the journal file in bytes */ 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 *zSuper = 0; /* Name of super-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 */ u32 savedPageSize = pPager->pageSize; /* 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 ){ goto end_playback; } /* Read the super-journal name from the journal, if it is present. ** If a super-journal file name is specified, but the file is not ** present on disk, then the journal is not hot and does not need to be ** played back. ** ** TODO: Technically the following is an error because it assumes that ** buffer Pager.pTmpSpace is (mxPathname+1) bytes or larger. i.e. that ** (pPager->pageSize >= pPager->pVfs->mxPathname+1). Using os_unix.c, ** mxPathname is 512, which is the same as the minimum allowable value ** for pageSize. */ zSuper = pPager->pTmpSpace; rc = readSuperJournal(pPager->jfd, zSuper, pPager->pVfs->mxPathname+1); if( rc==SQLITE_OK && zSuper[0] ){ rc = sqlite3OsAccess(pVfs, zSuper, SQLITE_ACCESS_EXISTS, &res); } zSuper = 0; if( rc!=SQLITE_OK || !res ){ goto end_playback; } pPager->journalOff = 0; needPagerReset = isHot; /* This loop terminates either when a readJournalHdr() or |
︙ | ︙ | |||
3024 3025 3026 3027 3028 3029 3030 | ** update the change-counter at all. This may lead to cache inconsistency ** problems for other processes at some point in the future. So, just ** in case this has happened, clear the changeCountDone flag now. */ pPager->changeCountDone = pPager->tempFile; if( rc==SQLITE_OK ){ | > > > > | | | | | | > > | | 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 | ** update the change-counter at all. This may lead to cache inconsistency ** problems for other processes at some point in the future. So, just ** in case this has happened, clear the changeCountDone flag now. */ pPager->changeCountDone = pPager->tempFile; if( rc==SQLITE_OK ){ /* Leave 4 bytes of space before the super-journal filename in memory. ** This is because it may end up being passed to sqlite3OsOpen(), in ** which case it requires 4 0x00 bytes in memory immediately before ** the filename. */ zSuper = &pPager->pTmpSpace[4]; rc = readSuperJournal(pPager->jfd, zSuper, pPager->pVfs->mxPathname+1); testcase( rc!=SQLITE_OK ); } if( rc==SQLITE_OK && (pPager->eState>=PAGER_WRITER_DBMOD || pPager->eState==PAGER_OPEN) ){ rc = sqlite3PagerSync(pPager, 0); } if( rc==SQLITE_OK ){ rc = pager_end_transaction(pPager, zSuper[0]!='\0', 0); testcase( rc!=SQLITE_OK ); } if( rc==SQLITE_OK && zSuper[0] && res ){ /* If there was a super-journal and this routine will return success, ** see if it is possible to delete the super-journal. */ assert( zSuper==&pPager->pTmpSpace[4] ); memset(&zSuper[-4], 0, 4); rc = pager_delsuper(pPager, zSuper); testcase( rc!=SQLITE_OK ); } if( isHot && nPlayback ){ sqlite3_log(SQLITE_NOTICE_RECOVER_ROLLBACK, "recovered %d pages from %s", nPlayback, pPager->zJournal); } |
︙ | ︙ | |||
3116 3117 3118 3119 3120 3121 3122 | */ memset(pPager->dbFileVers, 0xff, sizeof(pPager->dbFileVers)); }else{ u8 *dbFileVers = &((u8*)pPg->pData)[24]; memcpy(&pPager->dbFileVers, dbFileVers, sizeof(pPager->dbFileVers)); } } | < < > | 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 | */ memset(pPager->dbFileVers, 0xff, sizeof(pPager->dbFileVers)); }else{ u8 *dbFileVers = &((u8*)pPg->pData)[24]; memcpy(&pPager->dbFileVers, dbFileVers, sizeof(pPager->dbFileVers)); } } PAGER_INCR(sqlite3_pager_readdb_count); PAGER_INCR(pPager->nRead); IOTRACE(("PGIN %p %d\n", pPager, pPg->pgno)); PAGERTRACE(("FETCH %d page %d hash(%08x)\n", PAGERID(pPager), pPg->pgno, pager_pagehash(pPg))); return rc; } /* ** Update the value of the change-counter at offsets 24 and 92 in ** the header and the sqlite version number at offset 96. ** ** This is an unconditional update. See also the pager_incr_changecounter() ** routine which only updates the change-counter if the update is actually ** needed, as determined by the pPager->changeCountDone state variable. */ static void pager_write_changecounter(PgHdr *pPg){ u32 change_counter; if( NEVER(pPg==0) ) return; /* Increment the value just read and write it back to byte 24. */ change_counter = sqlite3Get4byte((u8*)pPg->pPager->dbFileVers)+1; put32bits(((char*)pPg->pData)+24, change_counter); /* Also store the SQLite version number in bytes 96..99 and in ** bytes 92..95 store the change counter for which the version number |
︙ | ︙ | |||
3209 3210 3211 3212 3213 3214 3215 | ** been written (but not committed) to the log file, do one of the ** following: ** ** + Discard the cached page (if refcount==0), or ** + Reload page content from the database (if refcount>0). */ pPager->dbSize = pPager->dbOrigSize; | | > > > > > > | 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 | ** been written (but not committed) to the log file, do one of the ** following: ** ** + Discard the cached page (if refcount==0), or ** + Reload page content from the database (if refcount>0). */ pPager->dbSize = pPager->dbOrigSize; rc = sqlite3WalUndo(pPager->pWal, pagerUndoCallback, (void *)pPager, #ifdef SQLITE_OMIT_CONCURRENT 0 #else pPager->pAllRead!=0 #endif ); pList = sqlite3PcacheDirtyList(pPager->pPCache); #ifndef SQLITE_OMIT_CONCURRENT /* If this is an CONCURRENT transaction, then page 1 must be reread from ** the db file, even if it is not dirty. This is because the b-tree layer ** may have already zeroed the nFree and iTrunk header fields. */ if( rc==SQLITE_OK && (pList==0 || pList->pgno!=1) && pPager->pAllRead ){ |
︙ | ︙ | |||
3434 3435 3436 3437 3438 3439 3440 | } return rc; } #endif /* ** Playback savepoint pSavepoint. Or, if pSavepoint==NULL, then playback | | | 3375 3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 | } return rc; } #endif /* ** Playback savepoint pSavepoint. Or, if pSavepoint==NULL, then playback ** the entire super-journal file. The case pSavepoint==NULL occurs when ** a ROLLBACK TO command is invoked on a SAVEPOINT that is a transaction ** savepoint. ** ** When pSavepoint is not NULL (meaning a non-transaction savepoint is ** being rolled back), then the rollback consists of up to three stages, ** performed in the order specified: ** |
︙ | ︙ | |||
3844 3845 3846 3847 3848 3849 3850 | char *pNew = NULL; /* New temp space */ i64 nByte = 0; if( pPager->eState>PAGER_OPEN && isOpen(pPager->fd) ){ rc = sqlite3OsFileSize(pPager->fd, &nByte); } if( rc==SQLITE_OK ){ | > > | > | > > > | 3785 3786 3787 3788 3789 3790 3791 3792 3793 3794 3795 3796 3797 3798 3799 3800 3801 3802 3803 3804 3805 3806 | char *pNew = NULL; /* New temp space */ i64 nByte = 0; if( pPager->eState>PAGER_OPEN && isOpen(pPager->fd) ){ rc = sqlite3OsFileSize(pPager->fd, &nByte); } if( rc==SQLITE_OK ){ /* 8 bytes of zeroed overrun space is sufficient so that the b-tree * cell header parser will never run off the end of the allocation */ pNew = (char *)sqlite3PageMalloc(pageSize+8); if( !pNew ){ rc = SQLITE_NOMEM_BKPT; }else{ memset(pNew+pageSize, 0, 8); } } if( rc==SQLITE_OK ){ pager_reset(pPager); rc = sqlite3PcacheSetPageSize(pPager->pPCache, pageSize); } if( rc==SQLITE_OK ){ |
︙ | ︙ | |||
3867 3868 3869 3870 3871 3872 3873 | } *pPageSize = pPager->pageSize; if( rc==SQLITE_OK ){ if( nReserve<0 ) nReserve = pPager->nReserve; assert( nReserve>=0 && nReserve<1000 ); pPager->nReserve = (i16)nReserve; | < | 3814 3815 3816 3817 3818 3819 3820 3821 3822 3823 3824 3825 3826 3827 | } *pPageSize = pPager->pageSize; if( rc==SQLITE_OK ){ if( nReserve<0 ) nReserve = pPager->nReserve; assert( nReserve>=0 && nReserve<1000 ); pPager->nReserve = (i16)nReserve; pagerFixMaplimit(pPager); } return rc; } /* ** Return a pointer to the "temporary page" buffer held internally |
︙ | ︙ | |||
3892 3893 3894 3895 3896 3897 3898 | /* ** Attempt to set the maximum database page count if mxPage is positive. ** Make no changes if mxPage is zero or negative. And never reduce the ** maximum page count below the current size of the database. ** ** Regardless of mxPage, return the current maximum page count. */ | | | > > > | 3838 3839 3840 3841 3842 3843 3844 3845 3846 3847 3848 3849 3850 3851 3852 3853 3854 3855 3856 3857 3858 3859 3860 | /* ** Attempt to set the maximum database page count if mxPage is positive. ** Make no changes if mxPage is zero or negative. And never reduce the ** maximum page count below the current size of the database. ** ** Regardless of mxPage, return the current maximum page count. */ Pgno sqlite3PagerMaxPageCount(Pager *pPager, Pgno mxPage){ if( mxPage>0 ){ pPager->mxPgno = mxPage; } assert( pPager->eState!=PAGER_OPEN ); /* Called only by OP_MaxPgcnt */ /* assert( pPager->mxPgno>=pPager->dbSize ); */ /* OP_MaxPgcnt ensures that the parameter passed to this function is not ** less than the total number of valid pages in the database. But this ** may be less than Pager.dbSize, and so the assert() above is not valid */ return pPager->mxPgno; } /* ** The following set of routines are used to disable the simulated ** I/O error mechanism. These routines are used to avoid simulated ** errors in places where we do not care about errors. |
︙ | ︙ | |||
4053 4054 4055 4056 4057 4058 4059 | ** ** This function is only called right before committing a transaction. ** Once this function has been called, the transaction must either be ** rolled back or committed. It is not safe to call this function and ** then continue writing to the database. */ void sqlite3PagerTruncateImage(Pager *pPager, Pgno nPage){ | | > | 4002 4003 4004 4005 4006 4007 4008 4009 4010 4011 4012 4013 4014 4015 4016 4017 | ** ** This function is only called right before committing a transaction. ** Once this function has been called, the transaction must either be ** rolled back or committed. It is not safe to call this function and ** then continue writing to the database. */ void sqlite3PagerTruncateImage(Pager *pPager, Pgno nPage){ assert( pPager->dbSize>=nPage || CORRUPT_DB ); testcase( pPager->dbSize<nPage ); assert( pPager->eState>=PAGER_WRITER_CACHEMOD ); pPager->dbSize = nPage; /* At one point the code here called assertTruncateConstraint() to ** ensure that all pages being truncated away by this operation are, ** if one or more savepoints are open, present in the savepoint ** journal so that they can be restored if the savepoint is rolled |
︙ | ︙ | |||
4260 4261 4262 4263 4264 4265 4266 | enable_simulated_io_errors(); PAGERTRACE(("CLOSE %d\n", PAGERID(pPager))); IOTRACE(("CLOSE %p\n", pPager)) sqlite3OsClose(pPager->jfd); sqlite3OsClose(pPager->fd); sqlite3PageFree(pTmp); sqlite3PcacheClose(pPager->pPCache); | < < < < < | 4210 4211 4212 4213 4214 4215 4216 4217 4218 4219 4220 4221 4222 4223 | enable_simulated_io_errors(); PAGERTRACE(("CLOSE %d\n", PAGERID(pPager))); IOTRACE(("CLOSE %p\n", pPager)) sqlite3OsClose(pPager->jfd); sqlite3OsClose(pPager->fd); sqlite3PageFree(pTmp); sqlite3PcacheClose(pPager->pPCache); assert( !pPager->aSavepoint && !pPager->pInJournal ); assert( !isOpen(pPager->jfd) && !isOpen(pPager->sjfd) ); sqlite3_free(pPager); return SQLITE_OK; } |
︙ | ︙ | |||
4515 4516 4517 4518 4519 4520 4521 | if( pgno<=pPager->dbSize && 0==(pList->flags&PGHDR_DONT_WRITE) ){ i64 offset = (pgno-1)*(i64)pPager->pageSize; /* Offset to write */ char *pData; /* Data to write */ assert( (pList->flags&PGHDR_NEED_SYNC)==0 ); if( pList->pgno==1 ) pager_write_changecounter(pList); | < | | 4460 4461 4462 4463 4464 4465 4466 4467 4468 4469 4470 4471 4472 4473 4474 | if( pgno<=pPager->dbSize && 0==(pList->flags&PGHDR_DONT_WRITE) ){ i64 offset = (pgno-1)*(i64)pPager->pageSize; /* Offset to write */ char *pData; /* Data to write */ assert( (pList->flags&PGHDR_NEED_SYNC)==0 ); if( pList->pgno==1 ) pager_write_changecounter(pList); pData = pList->pData; /* Write out the page data. */ rc = sqlite3OsWrite(pPager->fd, pData, pPager->pageSize, offset); /* If page 1 was just written, update Pager.dbFileVers to match ** the value now stored in the database file. If writing this ** page caused the database file to grow, update dbFileSize. |
︙ | ︙ | |||
4605 4606 4607 4608 4609 4610 4611 | /* If the sub-journal was opened successfully (or was already open), ** write the journal record into the file. */ if( rc==SQLITE_OK ){ void *pData = pPg->pData; i64 offset = (i64)pPager->nSubRec*(4+pPager->pageSize); char *pData2; | < < < < < < | 4549 4550 4551 4552 4553 4554 4555 4556 4557 4558 4559 4560 4561 4562 | /* If the sub-journal was opened successfully (or was already open), ** write the journal record into the file. */ if( rc==SQLITE_OK ){ void *pData = pPg->pData; i64 offset = (i64)pPager->nSubRec*(4+pPager->pageSize); char *pData2; pData2 = pData; PAGERTRACE(("STMT-JOURNAL %d page %d\n", PAGERID(pPager), pPg->pgno)); rc = write32bits(pPager->sjfd, offset, pPg->pgno); if( rc==SQLITE_OK ){ rc = sqlite3OsWrite(pPager->sjfd, pData2, pPager->pageSize, offset+4); } } |
︙ | ︙ | |||
4799 4800 4801 4802 4803 4804 4805 | void (*xReinit)(DbPage*) /* Function to reinitialize pages */ ){ u8 *pPtr; Pager *pPager = 0; /* Pager object to allocate and return */ int rc = SQLITE_OK; /* Return code */ int tempFile = 0; /* True for temp files (incl. in-memory files) */ int memDb = 0; /* True if this is an in-memory file */ | | > | | 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 | void (*xReinit)(DbPage*) /* Function to reinitialize pages */ ){ u8 *pPtr; Pager *pPager = 0; /* Pager object to allocate and return */ int rc = SQLITE_OK; /* Return code */ int tempFile = 0; /* True for temp files (incl. in-memory files) */ int memDb = 0; /* True if this is an in-memory file */ #ifndef SQLITE_OMIT_DESERIALIZE int memJM = 0; /* Memory journal mode */ #else # define memJM 0 #endif int readOnly = 0; /* True if this is a read-only file */ int journalFileSize; /* Bytes to allocate for each journal fd */ char *zPathname = 0; /* Full path to database file */ int nPathname = 0; /* Number of bytes in zPathname */ int useJournal = (flags & PAGER_OMIT_JOURNAL)==0; /* False to omit journal */ int pcacheSize = sqlite3PcacheSize(); /* Bytes to allocate for PCache */ u32 szPageDflt = SQLITE_DEFAULT_PAGE_SIZE; /* Default page size */ const char *zUri = 0; /* URI args to copy */ int nUriByte = 1; /* Number of bytes of URI args at *zUri */ int nUri = 0; /* Number of URI parameters */ /* Figure out how much space is required for each journal file-handle ** (there are two of them, the main journal and the sub-journal). */ journalFileSize = ROUND8(sqlite3JournalSize(pVfs)); /* Set the output variable to NULL in case an error occurs. */ *ppPager = 0; |
︙ | ︙ | |||
4846 4847 4848 4849 4850 4851 4852 4853 4854 4855 | nPathname = pVfs->mxPathname+1; zPathname = sqlite3DbMallocRaw(0, nPathname*2); if( zPathname==0 ){ return SQLITE_NOMEM_BKPT; } zPathname[0] = 0; /* Make sure initialized even if FullPathname() fails */ rc = sqlite3OsFullPathname(pVfs, zFilename, nPathname, zPathname); nPathname = sqlite3Strlen30(zPathname); z = zUri = &zFilename[sqlite3Strlen30(zFilename)+1]; while( *z ){ | > > > > > > > > > | | > | | | 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 | nPathname = pVfs->mxPathname+1; zPathname = sqlite3DbMallocRaw(0, nPathname*2); if( zPathname==0 ){ return SQLITE_NOMEM_BKPT; } zPathname[0] = 0; /* Make sure initialized even if FullPathname() fails */ rc = sqlite3OsFullPathname(pVfs, zFilename, nPathname, zPathname); if( rc!=SQLITE_OK ){ if( rc==SQLITE_OK_SYMLINK ){ if( vfsFlags & SQLITE_OPEN_NOFOLLOW ){ rc = SQLITE_CANTOPEN_SYMLINK; }else{ rc = SQLITE_OK; } } } nPathname = sqlite3Strlen30(zPathname); z = zUri = &zFilename[sqlite3Strlen30(zFilename)+1]; while( *z ){ z += strlen(z)+1; z += strlen(z)+1; nUri++; } nUriByte = (int)(&z[1] - zUri); assert( nUriByte>=1 ); if( rc==SQLITE_OK && nPathname+8>pVfs->mxPathname ){ /* This branch is taken when the journal path required by ** the database being opened will be more than pVfs->mxPathname ** bytes in length. This means the database cannot be opened, ** as it will not be possible to open the journal file or even ** check for a hot-journal before reading. */ |
︙ | ︙ | |||
4878 4879 4880 4881 4882 4883 4884 4885 | ** file name. The layout in memory is as follows: ** ** Pager object (sizeof(Pager) bytes) ** PCache object (sqlite3PcacheSize() bytes) ** Database file handle (pVfs->szOsFile bytes) ** Sub-journal file handle (journalFileSize bytes) ** Main journal file handle (journalFileSize bytes) ** Database file name (nPathname+1 bytes) | > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | > > | > | | > < | | > | | < > | > > | > > > > > > > > > > | | | | > | > > > | > | > > | | | > | > > > > > | | > | | | 4827 4828 4829 4830 4831 4832 4833 4834 4835 4836 4837 4838 4839 4840 4841 4842 4843 4844 4845 4846 4847 4848 4849 4850 4851 4852 4853 4854 4855 4856 4857 4858 4859 4860 4861 4862 4863 4864 4865 4866 4867 4868 4869 4870 4871 4872 4873 4874 4875 4876 4877 4878 4879 4880 4881 4882 4883 4884 4885 4886 4887 4888 4889 4890 4891 4892 4893 4894 4895 4896 4897 4898 4899 4900 4901 4902 4903 4904 4905 4906 4907 4908 4909 4910 4911 4912 4913 4914 4915 4916 4917 4918 4919 4920 4921 4922 4923 4924 4925 4926 4927 4928 4929 4930 4931 4932 4933 4934 4935 4936 4937 4938 4939 4940 4941 4942 4943 4944 4945 4946 4947 4948 4949 4950 4951 4952 4953 4954 4955 4956 4957 | ** file name. The layout in memory is as follows: ** ** Pager object (sizeof(Pager) bytes) ** PCache object (sqlite3PcacheSize() bytes) ** Database file handle (pVfs->szOsFile bytes) ** Sub-journal file handle (journalFileSize bytes) ** Main journal file handle (journalFileSize bytes) ** Ptr back to the Pager (sizeof(Pager*) bytes) ** \0\0\0\0 database prefix (4 bytes) ** Database file name (nPathname+1 bytes) ** URI query parameters (nUriByte bytes) ** Journal filename (nPathname+8+1 bytes) ** WAL filename (nPathname+4+1 bytes) ** \0\0\0 terminator (3 bytes) ** ** Some 3rd-party software, over which we have no control, depends on ** the specific order of the filenames and the \0 separators between them ** so that it can (for example) find the database filename given the WAL ** filename without using the sqlite3_filename_database() API. This is a ** misuse of SQLite and a bug in the 3rd-party software, but the 3rd-party ** software is in widespread use, so we try to avoid changing the filename ** order and formatting if possible. In particular, the details of the ** filename format expected by 3rd-party software should be as follows: ** ** - Main Database Path ** - \0 ** - Multiple URI components consisting of: ** - Key ** - \0 ** - Value ** - \0 ** - \0 ** - Journal Path ** - \0 ** - WAL Path (zWALName) ** - \0 ** ** The sqlite3_create_filename() interface and the databaseFilename() utility ** that is used by sqlite3_filename_database() and kin also depend on the ** specific formatting and order of the various filenames, so if the format ** changes here, be sure to change it there as well. */ pPtr = (u8 *)sqlite3MallocZero( ROUND8(sizeof(*pPager)) + /* Pager structure */ ROUND8(pcacheSize) + /* PCache object */ ROUND8(pVfs->szOsFile) + /* The main db file */ journalFileSize * 2 + /* The two journal files */ sizeof(pPager) + /* Space to hold a pointer */ 4 + /* Database prefix */ nPathname + 1 + /* database filename */ nUriByte + /* query parameters */ nPathname + 8 + 1 + /* Journal filename */ #ifndef SQLITE_OMIT_WAL nPathname + 4 + 1 + /* WAL filename */ #endif 3 /* Terminator */ ); assert( EIGHT_BYTE_ALIGNMENT(SQLITE_INT_TO_PTR(journalFileSize)) ); if( !pPtr ){ sqlite3DbFree(0, zPathname); return SQLITE_NOMEM_BKPT; } pPager = (Pager*)pPtr; pPtr += ROUND8(sizeof(*pPager)); pPager->pPCache = (PCache*)pPtr; pPtr += ROUND8(pcacheSize); pPager->fd = (sqlite3_file*)pPtr; pPtr += ROUND8(pVfs->szOsFile); pPager->sjfd = (sqlite3_file*)pPtr; pPtr += journalFileSize; pPager->jfd = (sqlite3_file*)pPtr; pPtr += journalFileSize; assert( EIGHT_BYTE_ALIGNMENT(pPager->jfd) ); memcpy(pPtr, &pPager, sizeof(pPager)); pPtr += sizeof(pPager); /* Fill in the Pager.zFilename and pPager.zQueryParam fields */ pPtr += 4; /* Skip zero prefix */ pPager->zFilename = (char*)pPtr; if( nPathname>0 ){ memcpy(pPtr, zPathname, nPathname); pPtr += nPathname + 1; if( zUri ){ memcpy(pPtr, zUri, nUriByte); pPtr += nUriByte; }else{ pPtr++; } } /* Fill in Pager.zJournal */ if( nPathname>0 ){ pPager->zJournal = (char*)pPtr; memcpy(pPtr, zPathname, nPathname); pPtr += nPathname; memcpy(pPtr, "-journal",8); pPtr += 8 + 1; #ifdef SQLITE_ENABLE_8_3_NAMES sqlite3FileSuffix3(zFilename,pPager->zJournal); pPtr = (u8*)(pPager->zJournal + sqlite3Strlen30(pPager->zJournal)+1); #endif }else{ pPager->zJournal = 0; } #ifndef SQLITE_OMIT_WAL /* Fill in Pager.zWal */ if( nPathname>0 ){ pPager->zWal = (char*)pPtr; memcpy(pPtr, zPathname, nPathname); pPtr += nPathname; memcpy(pPtr, "-wal", 4); pPtr += 4 + 1; #ifdef SQLITE_ENABLE_8_3_NAMES sqlite3FileSuffix3(zFilename, pPager->zWal); pPtr = (u8*)(pPager->zWal + sqlite3Strlen30(pPager->zWal)+1); #endif }else{ pPager->zWal = 0; } #endif (void)pPtr; /* Suppress warning about unused pPtr value */ if( nPathname ) sqlite3DbFree(0, zPathname); pPager->pVfs = pVfs; pPager->vfsFlags = vfsFlags; /* Open the pager file. */ if( zFilename && zFilename[0] ){ int fout = 0; /* VFS flags returned by xOpen() */ rc = sqlite3OsOpen(pVfs, pPager->zFilename, pPager->fd, vfsFlags, &fout); assert( !memDb ); #ifndef SQLITE_OMIT_DESERIALIZE pPager->memVfs = memJM = (fout&SQLITE_OPEN_MEMORY)!=0; #endif readOnly = (fout&SQLITE_OPEN_READONLY)!=0; /* If the file was successfully opened for read/write access, ** choose a default page size in case we have to create the ** database file. The default page size is the maximum of: ** |
︙ | ︙ | |||
4970 4971 4972 4973 4974 4975 4976 | if( iDc&(SQLITE_IOCAP_ATOMIC|(ii>>8)) ){ szPageDflt = ii; } } } #endif } | | | | 4981 4982 4983 4984 4985 4986 4987 4988 4989 4990 4991 4992 4993 4994 4995 4996 4997 | if( iDc&(SQLITE_IOCAP_ATOMIC|(ii>>8)) ){ szPageDflt = ii; } } } #endif } pPager->noLock = sqlite3_uri_boolean(pPager->zFilename, "nolock", 0); if( (iDc & SQLITE_IOCAP_IMMUTABLE)!=0 || sqlite3_uri_boolean(pPager->zFilename, "immutable", 0) ){ vfsFlags |= SQLITE_OPEN_READONLY; goto act_like_temp_file; } } }else{ /* If a temporary file is requested, it is not opened immediately. ** In this case we accept the default page size and delay actually |
︙ | ︙ | |||
5079 5080 5081 5082 5083 5084 5085 5086 5087 5088 5089 5090 5091 5092 5093 5094 5095 5096 5097 5098 5099 5100 5101 5102 5103 5104 5105 | /* memset(pPager->aHash, 0, sizeof(pPager->aHash)); */ /* pPager->szMmap = SQLITE_DEFAULT_MMAP_SIZE // will be set by btree.c */ *ppPager = pPager; return SQLITE_OK; } /* ** This function is called after transitioning from PAGER_UNLOCK to ** PAGER_SHARED state. It tests if there is a hot journal present in ** the file-system for the given pager. A hot journal is one that ** needs to be played back. According to this function, a hot-journal ** file exists if the following criteria are met: ** ** * The journal file exists in the file system, and ** * No process holds a RESERVED or greater lock on the database file, and ** * The database file itself is greater than 0 bytes in size, and ** * The first byte of the journal file exists and is not 0x00. ** ** If the current size of the database file is 0 but a journal file ** exists, that is probably an old journal left over from a prior ** database with the same name. In this case the journal file is ** just deleted using OsDelete, *pExists is set to 0 and SQLITE_OK ** is returned. ** | > > > > > > > > > > > > > | | | 5090 5091 5092 5093 5094 5095 5096 5097 5098 5099 5100 5101 5102 5103 5104 5105 5106 5107 5108 5109 5110 5111 5112 5113 5114 5115 5116 5117 5118 5119 5120 5121 5122 5123 5124 5125 5126 5127 5128 5129 5130 5131 5132 5133 5134 5135 5136 5137 5138 | /* memset(pPager->aHash, 0, sizeof(pPager->aHash)); */ /* pPager->szMmap = SQLITE_DEFAULT_MMAP_SIZE // will be set by btree.c */ *ppPager = pPager; return SQLITE_OK; } /* ** Return the sqlite3_file for the main database given the name ** of the corresonding WAL or Journal name as passed into ** xOpen. */ sqlite3_file *sqlite3_database_file_object(const char *zName){ Pager *pPager; while( zName[-1]!=0 || zName[-2]!=0 || zName[-3]!=0 || zName[-4]!=0 ){ zName--; } pPager = *(Pager**)(zName - 4 - sizeof(Pager*)); return pPager->fd; } /* ** This function is called after transitioning from PAGER_UNLOCK to ** PAGER_SHARED state. It tests if there is a hot journal present in ** the file-system for the given pager. A hot journal is one that ** needs to be played back. According to this function, a hot-journal ** file exists if the following criteria are met: ** ** * The journal file exists in the file system, and ** * No process holds a RESERVED or greater lock on the database file, and ** * The database file itself is greater than 0 bytes in size, and ** * The first byte of the journal file exists and is not 0x00. ** ** If the current size of the database file is 0 but a journal file ** exists, that is probably an old journal left over from a prior ** database with the same name. In this case the journal file is ** just deleted using OsDelete, *pExists is set to 0 and SQLITE_OK ** is returned. ** ** This routine does not check if there is a super-journal filename ** at the end of the file. If there is, and that super-journal file ** does not exist, then the journal file is not really hot. In this ** case this routine will return a false-positive. The pager_playback() ** routine will discover that the journal file is not really hot and ** will not roll it back. ** ** If a hot-journal file is found to exist, *pExists is set to 1 and ** SQLITE_OK returned. If no hot-journal file is present, *pExists is |
︙ | ︙ | |||
5561 5562 5563 5564 5565 5566 5567 | assert( pPg->pgno==pgno ); assert( pPg->pPager==pPager || pPg->pPager==0 ); noContent = (flags & PAGER_GET_NOCONTENT)!=0; if( pPg->pPager && !noContent ){ /* In this case the pcache already contains an initialized copy of ** the page. Return without further ado. */ | | | | | 5585 5586 5587 5588 5589 5590 5591 5592 5593 5594 5595 5596 5597 5598 5599 5600 5601 5602 5603 5604 5605 5606 5607 5608 5609 5610 | assert( pPg->pgno==pgno ); assert( pPg->pPager==pPager || pPg->pPager==0 ); noContent = (flags & PAGER_GET_NOCONTENT)!=0; if( pPg->pPager && !noContent ){ /* In this case the pcache already contains an initialized copy of ** the page. Return without further ado. */ assert( pgno!=PAGER_MJ_PGNO(pPager) ); pPager->aStat[PAGER_STAT_HIT]++; return SQLITE_OK; }else{ /* The pager cache has created a new page. Its content needs to ** be initialized. But first some error checks: ** ** (*) obsolete. Was: maximum page number is 2^31 ** (2) Never try to fetch the locking page */ if( pgno==PAGER_MJ_PGNO(pPager) ){ rc = SQLITE_CORRUPT_BKPT; goto pager_acquire_err; } pPg->pPager = pPager; assert( !isOpen(pPager->fd) || !MEMDB ); |
︙ | ︙ | |||
5646 5647 5648 5649 5650 5651 5652 | ** 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 && (pPager->eState==PAGER_READER || (flags & PAGER_GET_READONLY)) ); assert( USEFETCH(pPager) ); | < < < | 5670 5671 5672 5673 5674 5675 5676 5677 5678 5679 5680 5681 5682 5683 | ** 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 && (pPager->eState==PAGER_READER || (flags & PAGER_GET_READONLY)) ); assert( USEFETCH(pPager) ); /* Optimization note: Adding the "pgno<=1" term before "pgno==0" here ** allows the compiler optimizer to reuse the results of the "pgno>1" ** test in the previous statement, and avoid testing pgno==0 in the ** common case where pgno is large. */ if( pgno<=1 && pgno==0 ){ return SQLITE_CORRUPT_BKPT; |
︙ | ︙ | |||
5779 5780 5781 5782 5783 5784 5785 | } void sqlite3PagerUnrefPageOne(DbPage *pPg){ Pager *pPager; assert( pPg!=0 ); assert( pPg->pgno==1 ); assert( (pPg->flags & PGHDR_MMAP)==0 ); /* Page1 is never memory mapped */ pPager = pPg->pPager; | < | 5800 5801 5802 5803 5804 5805 5806 5807 5808 5809 5810 5811 5812 5813 | } void sqlite3PagerUnrefPageOne(DbPage *pPg){ Pager *pPager; assert( pPg!=0 ); assert( pPg->pgno==1 ); assert( (pPg->flags & PGHDR_MMAP)==0 ); /* Page1 is never memory mapped */ 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 |
︙ | ︙ | |||
5861 5862 5863 5864 5865 5866 5867 | /* Write the first journal header to the journal file and open ** the sub-journal if necessary. */ if( rc==SQLITE_OK ){ /* TODO: Check if all of these are really required. */ pPager->nRec = 0; pPager->journalOff = 0; | | | 5881 5882 5883 5884 5885 5886 5887 5888 5889 5890 5891 5892 5893 5894 5895 | /* Write the first journal header to the journal file and open ** the sub-journal if necessary. */ if( rc==SQLITE_OK ){ /* TODO: Check if all of these are really required. */ pPager->nRec = 0; pPager->journalOff = 0; pPager->setSuper = 0; pPager->journalHdr = 0; rc = writeJournalHdr(pPager); } } if( rc!=SQLITE_OK ){ sqlite3BitvecDestroy(pPager->pInJournal); |
︙ | ︙ | |||
5905 5906 5907 5908 5909 5910 5911 | int sqlite3PagerBegin(Pager *pPager, int exFlag, int subjInMemory){ int rc = SQLITE_OK; if( pPager->errCode ) return pPager->errCode; assert( pPager->eState>=PAGER_READER && pPager->eState<PAGER_ERROR ); pPager->subjInMemory = (u8)subjInMemory; | | | 5925 5926 5927 5928 5929 5930 5931 5932 5933 5934 5935 5936 5937 5938 5939 | int sqlite3PagerBegin(Pager *pPager, int exFlag, int subjInMemory){ int rc = SQLITE_OK; if( pPager->errCode ) return pPager->errCode; assert( pPager->eState>=PAGER_READER && pPager->eState<PAGER_ERROR ); pPager->subjInMemory = (u8)subjInMemory; if( pPager->eState==PAGER_READER ){ assert( pPager->pInJournal==0 ); if( pagerUseWal(pPager) ){ /* If the pager is configured to use locking_mode=exclusive, and an ** exclusive lock on the database is not already held, obtain it now. */ if( pPager->exclusiveMode && sqlite3WalExclusiveMode(pPager->pWal, -1) ){ rc = pagerLockDb(pPager, EXCLUSIVE_LOCK); |
︙ | ︙ | |||
5980 5981 5982 5983 5984 5985 5986 | /* We should never write to the journal file the page that ** contains the database locks. The following assert verifies ** that we do not. */ assert( pPg->pgno!=PAGER_MJ_PGNO(pPager) ); assert( pPager->journalHdr<=pPager->journalOff ); | | | 6000 6001 6002 6003 6004 6005 6006 6007 6008 6009 6010 6011 6012 6013 6014 | /* We should never write to the journal file the page that ** contains the database locks. The following assert verifies ** that we do not. */ assert( pPg->pgno!=PAGER_MJ_PGNO(pPager) ); assert( pPager->journalHdr<=pPager->journalOff ); pData2 = pPg->pData; cksum = pager_cksum(pPager, (u8*)pData2); /* Even if an IO or diskfull error occurs while journalling the ** page in the block above, set the need-sync flag for the page. ** Otherwise, when the transaction is rolled back, the logic in ** playback_one_page() will think that the page needs to be restored ** in the database file. And if an IO error occurs while doing so, |
︙ | ︙ | |||
6345 6346 6347 6348 6349 6350 6351 | /* Actually do the update of the change counter */ pager_write_changecounter(pPgHdr); /* If running in direct mode, write the contents of page 1 to the file. */ if( DIRECT_MODE ){ const void *zBuf; assert( pPager->dbFileSize>0 ); | | | 6365 6366 6367 6368 6369 6370 6371 6372 6373 6374 6375 6376 6377 6378 6379 | /* Actually do the update of the change counter */ pager_write_changecounter(pPgHdr); /* If running in direct mode, write the contents of page 1 to the file. */ if( DIRECT_MODE ){ const void *zBuf; assert( pPager->dbFileSize>0 ); zBuf = pPgHdr->pData; 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 |
︙ | ︙ | |||
6376 6377 6378 6379 6380 6381 6382 | /* ** Sync the database file to disk. This is a no-op for in-memory databases ** or pages with the Pager.noSync flag set. ** ** If successful, or if called on a pager for which it is a no-op, this ** function returns SQLITE_OK. Otherwise, an IO error code is returned. */ | | | | 6396 6397 6398 6399 6400 6401 6402 6403 6404 6405 6406 6407 6408 6409 6410 6411 6412 | /* ** Sync the database file to disk. This is a no-op for in-memory databases ** or pages with the Pager.noSync flag set. ** ** If successful, or if called on a pager for which it is a no-op, this ** function returns SQLITE_OK. Otherwise, an IO error code is returned. */ int sqlite3PagerSync(Pager *pPager, const char *zSuper){ int rc = SQLITE_OK; void *pArg = (void*)zSuper; rc = sqlite3OsFileControl(pPager->fd, SQLITE_FCNTL_SYNC, pArg); if( rc==SQLITE_NOTFOUND ) rc = SQLITE_OK; if( rc==SQLITE_OK && !pPager->noSync ){ assert( !MEMDB ); rc = sqlite3OsSync(pPager->fd, pPager->syncFlags); } return rc; |
︙ | ︙ | |||
6488 6489 6490 6491 6492 6493 6494 | sqlite3WalEndWriteTransaction(pPager->pWal); } } #endif /* SQLITE_OMIT_CONCURRENT */ /* | | | | | | | | | | | 6508 6509 6510 6511 6512 6513 6514 6515 6516 6517 6518 6519 6520 6521 6522 6523 6524 6525 6526 6527 6528 6529 6530 6531 6532 6533 6534 6535 6536 6537 6538 6539 6540 6541 6542 6543 6544 6545 6546 6547 6548 6549 6550 6551 6552 6553 6554 6555 6556 6557 6558 6559 6560 6561 6562 6563 6564 6565 6566 6567 6568 | sqlite3WalEndWriteTransaction(pPager->pWal); } } #endif /* SQLITE_OMIT_CONCURRENT */ /* ** Sync the database file for the pager pPager. zSuper points to the name ** of a super-journal file that should be written into the individual ** journal file. zSuper may be NULL, which is interpreted as no ** super-journal (a single database transaction). ** ** This routine ensures that: ** ** * The database file change-counter is updated, ** * the journal is synced (unless the atomic-write optimization is used), ** * all dirty pages are written to the database file, ** * the database file is truncated (if required), and ** * the database file synced. ** ** The only thing that remains to commit the transaction is to finalize ** (delete, truncate or zero the first part of) the journal file (or ** delete the super-journal file if specified). ** ** Note that if zSuper==NULL, this does not overwrite a previous value ** passed to an sqlite3PagerCommitPhaseOne() call. ** ** If the final parameter - noSync - is true, then the database file itself ** is not synced. The caller must call sqlite3PagerSync() directly to ** sync the database file before calling CommitPhaseTwo() to delete the ** journal file in this case. */ int sqlite3PagerCommitPhaseOne( Pager *pPager, /* Pager object */ const char *zSuper, /* If not NULL, the super-journal name */ int noSync /* True to omit the xSync on the db file */ ){ int rc = SQLITE_OK; /* Return code */ assert( pPager->eState==PAGER_WRITER_LOCKED || pPager->eState==PAGER_WRITER_CACHEMOD || pPager->eState==PAGER_WRITER_DBMOD || pPager->eState==PAGER_ERROR ); assert( assert_pager_state(pPager) ); /* If a prior error occurred, report that error again. */ if( NEVER(pPager->errCode) ) return pPager->errCode; /* Provide the ability to easily simulate an I/O error during testing */ if( sqlite3FaultSim(400) ) return SQLITE_IOERR; PAGERTRACE(("DATABASE SYNC: File=%s zSuper=%s nSize=%d\n", pPager->zFilename, zSuper, pPager->dbSize)); /* If no database changes have been made, return early. */ if( pPager->eState<PAGER_WRITER_CACHEMOD ) return SQLITE_OK; assert( MEMDB==0 || pPager->tempFile ); assert( isOpen(pPager->fd) || pPager->tempFile ); if( 0==pagerFlushOnCommit(pPager, 1) ){ |
︙ | ︙ | |||
6573 6574 6575 6576 6577 6578 6579 | }else{ /* The bBatch boolean is true if the batch-atomic-write commit method ** should be used. No rollback journal is created if batch-atomic-write ** is enabled. */ #ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE sqlite3_file *fd = pPager->fd; | | | 6593 6594 6595 6596 6597 6598 6599 6600 6601 6602 6603 6604 6605 6606 6607 | }else{ /* The bBatch boolean is true if the batch-atomic-write commit method ** should be used. No rollback journal is created if batch-atomic-write ** is enabled. */ #ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE sqlite3_file *fd = pPager->fd; int bBatch = zSuper==0 /* An SQLITE_IOCAP_BATCH_ATOMIC commit */ && (sqlite3OsDeviceCharacteristics(fd) & SQLITE_IOCAP_BATCH_ATOMIC) && !pPager->noSync && sqlite3JournalIsInMemory(pPager->jfd); #else # define bBatch 0 #endif |
︙ | ︙ | |||
6611 6612 6613 6614 6615 6616 6617 | */ if( bBatch==0 ){ PgHdr *pPg; assert( isOpen(pPager->jfd) || pPager->journalMode==PAGER_JOURNALMODE_OFF || pPager->journalMode==PAGER_JOURNALMODE_WAL ); | | | | | | | | 6631 6632 6633 6634 6635 6636 6637 6638 6639 6640 6641 6642 6643 6644 6645 6646 6647 6648 6649 6650 6651 6652 6653 6654 6655 6656 6657 6658 6659 6660 6661 6662 6663 6664 6665 6666 6667 6668 6669 6670 6671 6672 6673 6674 6675 6676 6677 6678 6679 6680 | */ if( bBatch==0 ){ PgHdr *pPg; assert( isOpen(pPager->jfd) || pPager->journalMode==PAGER_JOURNALMODE_OFF || pPager->journalMode==PAGER_JOURNALMODE_WAL ); if( !zSuper && isOpen(pPager->jfd) && pPager->journalOff==jrnlBufferSize(pPager) && pPager->dbSize>=pPager->dbOrigSize && (!(pPg = sqlite3PcacheDirtyList(pPager->pPCache)) || 0==pPg->pDirty) ){ /* Update the db file change counter via the direct-write method. The ** following call will modify the in-memory representation of page 1 ** to include the updated change counter and then write page 1 ** directly to the database file. Because of the atomic-write ** property of the host file-system, this is safe. */ rc = pager_incr_changecounter(pPager, 1); }else{ rc = sqlite3JournalCreate(pPager->jfd); if( rc==SQLITE_OK ){ rc = pager_incr_changecounter(pPager, 0); } } } #else /* SQLITE_ENABLE_ATOMIC_WRITE */ #ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE if( zSuper ){ rc = sqlite3JournalCreate(pPager->jfd); if( rc!=SQLITE_OK ) goto commit_phase_one_exit; assert( bBatch==0 ); } #endif rc = pager_incr_changecounter(pPager, 0); #endif /* !SQLITE_ENABLE_ATOMIC_WRITE */ if( rc!=SQLITE_OK ) goto commit_phase_one_exit; /* Write the super-journal name into the journal file. If a ** super-journal file name has already been written to the journal file, ** or if zSuper is NULL (no super-journal), then this call is a no-op. */ rc = writeSuperJournal(pPager, zSuper); if( rc!=SQLITE_OK ) goto commit_phase_one_exit; /* Sync the journal file and write all dirty pages to the database. ** If the atomic-update optimization is being used, this sync will not ** create the journal file or perform any real IO. ** ** Because the change-counter page was just modified, unless the |
︙ | ︙ | |||
6714 6715 6716 6717 6718 6719 6720 | assert( pPager->eState==PAGER_WRITER_DBMOD ); rc = pager_truncate(pPager, nNew); if( rc!=SQLITE_OK ) goto commit_phase_one_exit; } /* Finally, sync the database file. */ if( !noSync ){ | | | 6734 6735 6736 6737 6738 6739 6740 6741 6742 6743 6744 6745 6746 6747 6748 | assert( pPager->eState==PAGER_WRITER_DBMOD ); rc = pager_truncate(pPager, nNew); if( rc!=SQLITE_OK ) goto commit_phase_one_exit; } /* Finally, sync the database file. */ if( !noSync ){ rc = sqlite3PagerSync(pPager, zSuper); } IOTRACE(("DBSYNC %p\n", pPager)) } } commit_phase_one_exit: if( rc==SQLITE_OK && !pagerUseWal(pPager) ){ |
︙ | ︙ | |||
6750 6751 6752 6753 6754 6755 6756 6757 6758 6759 6760 6761 6762 6763 | int sqlite3PagerCommitPhaseTwo(Pager *pPager){ int rc = SQLITE_OK; /* Return code */ /* This routine should not be called if a prior error has occurred. ** But if (due to a coding error elsewhere in the system) it does get ** called, just return the same error code without doing anything. */ if( NEVER(pPager->errCode) ) return pPager->errCode; assert( pPager->eState==PAGER_WRITER_LOCKED || pPager->eState==PAGER_WRITER_FINISHED || (pagerUseWal(pPager) && pPager->eState==PAGER_WRITER_CACHEMOD) ); assert( assert_pager_state(pPager) ); | > | 6770 6771 6772 6773 6774 6775 6776 6777 6778 6779 6780 6781 6782 6783 6784 | int sqlite3PagerCommitPhaseTwo(Pager *pPager){ int rc = SQLITE_OK; /* Return code */ /* This routine should not be called if a prior error has occurred. ** But if (due to a coding error elsewhere in the system) it does get ** called, just return the same error code without doing anything. */ if( NEVER(pPager->errCode) ) return pPager->errCode; pPager->iDataVersion++; assert( pPager->eState==PAGER_WRITER_LOCKED || pPager->eState==PAGER_WRITER_FINISHED || (pagerUseWal(pPager) && pPager->eState==PAGER_WRITER_CACHEMOD) ); assert( assert_pager_state(pPager) ); |
︙ | ︙ | |||
6778 6779 6780 6781 6782 6783 6784 | ){ assert( pPager->journalOff==JOURNAL_HDR_SZ(pPager) || !pPager->journalOff ); pPager->eState = PAGER_READER; return SQLITE_OK; } PAGERTRACE(("COMMIT %d\n", PAGERID(pPager))); | < | | 6799 6800 6801 6802 6803 6804 6805 6806 6807 6808 6809 6810 6811 6812 6813 | ){ assert( pPager->journalOff==JOURNAL_HDR_SZ(pPager) || !pPager->journalOff ); pPager->eState = PAGER_READER; return SQLITE_OK; } PAGERTRACE(("COMMIT %d\n", PAGERID(pPager))); rc = pager_end_transaction(pPager, pPager->setSuper, 1); return pager_error(pPager, rc); } /* ** If a write transaction is open, then all changes made within the ** transaction are reverted and the current write-transaction is closed. ** The pager falls back to PAGER_READER state if successful, or PAGER_ERROR |
︙ | ︙ | |||
6824 6825 6826 6827 6828 6829 6830 | assert( assert_pager_state(pPager) ); if( pPager->eState==PAGER_ERROR ) return pPager->errCode; if( pPager->eState<=PAGER_READER ) return SQLITE_OK; if( pagerUseWal(pPager) ){ int rc2; rc = sqlite3PagerSavepoint(pPager, SAVEPOINT_ROLLBACK, -1); | | | 6844 6845 6846 6847 6848 6849 6850 6851 6852 6853 6854 6855 6856 6857 6858 | assert( assert_pager_state(pPager) ); if( pPager->eState==PAGER_ERROR ) return pPager->errCode; if( pPager->eState<=PAGER_READER ) return SQLITE_OK; if( pagerUseWal(pPager) ){ int rc2; rc = sqlite3PagerSavepoint(pPager, SAVEPOINT_ROLLBACK, -1); rc2 = pager_end_transaction(pPager, pPager->setSuper, 0); if( rc==SQLITE_OK ) rc = rc2; }else if( !isOpen(pPager->jfd) || pPager->eState==PAGER_WRITER_LOCKED ){ int eState = pPager->eState; rc = pager_end_transaction(pPager, 0, 0); if( !MEMDB && eState>PAGER_WRITER_LOCKED ){ /* This can happen using journal_mode=off. Move the pager to the error ** state to indicate that the contents of the cache may not be trusted. |
︙ | ︙ | |||
6877 6878 6879 6880 6881 6882 6883 | #endif /* ** Return the approximate number of bytes of memory currently ** used by the pager and its associated cache. */ int sqlite3PagerMemUsed(Pager *pPager){ | | | | 6897 6898 6899 6900 6901 6902 6903 6904 6905 6906 6907 6908 6909 6910 6911 6912 | #endif /* ** Return the approximate number of bytes of memory currently ** used by the pager and its associated cache. */ int sqlite3PagerMemUsed(Pager *pPager){ int perPageSize = pPager->pageSize + pPager->nExtra + (int)(sizeof(PgHdr) + 5*sizeof(void*)); return perPageSize*sqlite3PcachePagecount(pPager->pPCache) + sqlite3MallocSize(pPager) + pPager->pageSize; } /* ** Return the number of references to the specified page. |
︙ | ︙ | |||
6947 6948 6949 6950 6951 6952 6953 | } } /* ** Return true if this is an in-memory or temp-file backed pager. */ int sqlite3PagerIsMemdb(Pager *pPager){ | | | 6967 6968 6969 6970 6971 6972 6973 6974 6975 6976 6977 6978 6979 6980 6981 | } } /* ** Return true if this is an in-memory or temp-file backed pager. */ int sqlite3PagerIsMemdb(Pager *pPager){ return pPager->tempFile || pPager->memVfs; } /* ** Check that there are at least nSavepoint savepoints open. If there are ** currently less than nSavepoints open, then open one or more savepoints ** to make up the difference. If the number of savepoints is already ** equal to nSavepoint, then this function is a no-op. |
︙ | ︙ | |||
6993 6994 6995 6996 6997 6998 6999 7000 7001 7002 7003 7004 7005 7006 | if( isOpen(pPager->jfd) && pPager->journalOff>0 ){ aNew[ii].iOffset = pPager->journalOff; }else{ aNew[ii].iOffset = JOURNAL_HDR_SZ(pPager); } aNew[ii].iSubRec = pPager->nSubRec; aNew[ii].pInSavepoint = sqlite3BitvecCreate(pPager->dbSize); if( !aNew[ii].pInSavepoint ){ return SQLITE_NOMEM_BKPT; } if( pagerUseWal(pPager) ){ sqlite3WalSavepoint(pPager->pWal, aNew[ii].aWalData); } pPager->nSavepoint = ii+1; | > | 7013 7014 7015 7016 7017 7018 7019 7020 7021 7022 7023 7024 7025 7026 7027 | if( isOpen(pPager->jfd) && pPager->journalOff>0 ){ aNew[ii].iOffset = pPager->journalOff; }else{ aNew[ii].iOffset = JOURNAL_HDR_SZ(pPager); } aNew[ii].iSubRec = pPager->nSubRec; aNew[ii].pInSavepoint = sqlite3BitvecCreate(pPager->dbSize); aNew[ii].bTruncateOnRelease = 1; if( !aNew[ii].pInSavepoint ){ return SQLITE_NOMEM_BKPT; } if( pagerUseWal(pPager) ){ sqlite3WalSavepoint(pPager->pWal, aNew[ii].aWalData); } pPager->nSavepoint = ii+1; |
︙ | ︙ | |||
7071 7072 7073 7074 7075 7076 7077 | */ nNew = iSavepoint + (( op==SAVEPOINT_RELEASE ) ? 0 : 1); for(ii=nNew; ii<pPager->nSavepoint; ii++){ sqlite3BitvecDestroy(pPager->aSavepoint[ii].pInSavepoint); } pPager->nSavepoint = nNew; | < | > > | > | | | 7092 7093 7094 7095 7096 7097 7098 7099 7100 7101 7102 7103 7104 7105 7106 7107 7108 7109 7110 7111 7112 7113 7114 7115 7116 7117 | */ nNew = iSavepoint + (( op==SAVEPOINT_RELEASE ) ? 0 : 1); for(ii=nNew; ii<pPager->nSavepoint; ii++){ sqlite3BitvecDestroy(pPager->aSavepoint[ii].pInSavepoint); } pPager->nSavepoint = nNew; /* Truncate the sub-journal so that it only includes the parts ** that are still in use. */ if( op==SAVEPOINT_RELEASE ){ PagerSavepoint *pRel = &pPager->aSavepoint[nNew]; if( pRel->bTruncateOnRelease && isOpen(pPager->sjfd) ){ /* Only truncate if it is an in-memory sub-journal. */ if( sqlite3JournalIsInMemory(pPager->sjfd) ){ i64 sz = (pPager->pageSize+4)*(i64)pRel->iSubRec; rc = sqlite3OsTruncate(pPager->sjfd, sz); assert( rc==SQLITE_OK ); } pPager->nSubRec = pRel->iSubRec; } } /* Else this is a rollback operation, playback the specified savepoint. ** If this is a temp-file, it is possible that the journal file has ** not yet been opened. In this case there have been no changes to ** the database file, so the playback operation can be skipped. */ |
︙ | ︙ | |||
7122 7123 7124 7125 7126 7127 7128 7129 | ** ** Except, if the pager is in-memory only, then return an empty string if ** nullIfMemDb is true. This routine is called with nullIfMemDb==1 when ** used to report the filename to the user, for compatibility with legacy ** behavior. But when the Btree needs to know the filename for matching to ** shared cache, it uses nullIfMemDb==0 so that in-memory databases can ** participate in shared-cache. */ | > > > | > | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 7145 7146 7147 7148 7149 7150 7151 7152 7153 7154 7155 7156 7157 7158 7159 7160 7161 7162 7163 7164 7165 7166 7167 7168 7169 7170 7171 7172 7173 7174 7175 7176 7177 7178 7179 7180 7181 7182 7183 7184 7185 7186 7187 7188 7189 7190 7191 7192 7193 7194 7195 7196 7197 7198 7199 7200 7201 7202 | ** ** Except, if the pager is in-memory only, then return an empty string if ** nullIfMemDb is true. This routine is called with nullIfMemDb==1 when ** used to report the filename to the user, for compatibility with legacy ** behavior. But when the Btree needs to know the filename for matching to ** shared cache, it uses nullIfMemDb==0 so that in-memory databases can ** participate in shared-cache. ** ** The return value to this routine is always safe to use with ** sqlite3_uri_parameter() and sqlite3_filename_database() and friends. */ const char *sqlite3PagerFilename(const Pager *pPager, int nullIfMemDb){ static const char zFake[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; return (nullIfMemDb && pPager->memDb) ? &zFake[4] : pPager->zFilename; } /* ** Return the VFS structure for the pager. */ sqlite3_vfs *sqlite3PagerVfs(Pager *pPager){ return pPager->pVfs; } /* ** Return the file handle for the database file associated ** with the pager. This might return NULL if the file has ** not yet been opened. */ sqlite3_file *sqlite3PagerFile(Pager *pPager){ return pPager->fd; } /* ** Return the file handle for the journal file (if it exists). ** This will be either the rollback journal or the WAL file. */ sqlite3_file *sqlite3PagerJrnlFile(Pager *pPager){ #if SQLITE_OMIT_WAL return pPager->jfd; #else return pPager->pWal ? sqlite3WalFile(pPager->pWal) : pPager->jfd; #endif } /* ** Return the full pathname of the journal file. */ const char *sqlite3PagerJournalname(Pager *pPager){ return pPager->zJournal; } #ifndef SQLITE_OMIT_AUTOVACUUM /* ** Move the page pPg to location pgno in the file. ** ** There must be no references to the page previously located at ** pgno (which we call pPgOld) though that page is allowed to be ** in cache. If the page previously located at pgno is not already |
︙ | ︙ | |||
7316 7317 7318 7319 7320 7321 7322 | /* If the cache contains a page with page-number pgno, remove it ** from its hash chain. Also, if the PGHDR_NEED_SYNC flag was set for ** page pgno before the 'move' operation, it needs to be retained ** for the page moved there. */ pPg->flags &= ~PGHDR_NEED_SYNC; pPgOld = sqlite3PagerLookup(pPager, pgno); | | > > > > | 7285 7286 7287 7288 7289 7290 7291 7292 7293 7294 7295 7296 7297 7298 7299 7300 7301 7302 7303 7304 | /* If the cache contains a page with page-number pgno, remove it ** from its hash chain. Also, if the PGHDR_NEED_SYNC flag was set for ** page pgno before the 'move' operation, it needs to be retained ** for the page moved there. */ pPg->flags &= ~PGHDR_NEED_SYNC; pPgOld = sqlite3PagerLookup(pPager, pgno); assert( !pPgOld || pPgOld->nRef==1 || CORRUPT_DB ); if( pPgOld ){ if( NEVER(pPgOld->nRef>1) ){ sqlite3PagerUnrefNotNull(pPgOld); return SQLITE_CORRUPT_BKPT; } pPg->flags |= (pPgOld->flags&PGHDR_NEED_SYNC); if( pPager->tempFile ){ /* Do not discard pages from an in-memory database since we might ** need to rollback later. Just move the page out of the way. */ sqlite3PcacheMove(pPgOld, pPager->dbSize+1); }else{ sqlite3PcacheDrop(pPgOld); |
︙ | ︙ | |||
7610 7611 7612 7613 7614 7615 7616 | if( pPager->pWal ){ rc = sqlite3WalCheckpoint(pPager->pWal, db, eMode, (eMode==SQLITE_CHECKPOINT_PASSIVE ? 0 : pPager->xBusyHandler), pPager->pBusyHandlerArg, pPager->walSyncFlags, pPager->pageSize, (u8 *)pPager->pTmpSpace, pnLog, pnCkpt ); | < | 7583 7584 7585 7586 7587 7588 7589 7590 7591 7592 7593 7594 7595 7596 | if( pPager->pWal ){ rc = sqlite3WalCheckpoint(pPager->pWal, db, eMode, (eMode==SQLITE_CHECKPOINT_PASSIVE ? 0 : pPager->xBusyHandler), pPager->pBusyHandlerArg, pPager->walSyncFlags, pPager->pageSize, (u8 *)pPager->pTmpSpace, pnLog, pnCkpt ); } return rc; } int sqlite3PagerWalCallback(Pager *pPager){ return sqlite3WalCallback(pPager->pWal); } |
︙ | ︙ | |||
7774 7775 7776 7777 7778 7779 7780 7781 7782 7783 7784 7785 7786 7787 7788 7789 7790 7791 7792 7793 7794 7795 7796 7797 7798 7799 | pPager->pWal = 0; pagerFixMaplimit(pPager); if( rc && !pPager->exclusiveMode ) pagerUnlockDb(pPager, SHARED_LOCK); } } return rc; } #ifdef SQLITE_ENABLE_SNAPSHOT /* ** If this is a WAL database, obtain a snapshot handle for the snapshot ** currently open. Otherwise, return an error. */ int sqlite3PagerSnapshotGet(Pager *pPager, sqlite3_snapshot **ppSnapshot){ int rc = SQLITE_ERROR; if( pPager->pWal ){ rc = sqlite3WalSnapshotGet(pPager->pWal, ppSnapshot); } return rc; } /* ** If this is a WAL database, store a pointer to pSnapshot. Next time a ** read transaction is opened, attempt to read from the snapshot it ** identifies. If this is not a WAL database, return an error. */ | > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > | 7746 7747 7748 7749 7750 7751 7752 7753 7754 7755 7756 7757 7758 7759 7760 7761 7762 7763 7764 7765 7766 7767 7768 7769 7770 7771 7772 7773 7774 7775 7776 7777 7778 7779 7780 7781 7782 7783 7784 7785 7786 7787 7788 7789 7790 7791 7792 7793 7794 7795 7796 7797 7798 7799 7800 7801 7802 7803 7804 7805 7806 7807 7808 | pPager->pWal = 0; pagerFixMaplimit(pPager); if( rc && !pPager->exclusiveMode ) pagerUnlockDb(pPager, SHARED_LOCK); } } return rc; } #ifdef SQLITE_ENABLE_SETLK_TIMEOUT /* ** If pager pPager is a wal-mode database not in exclusive locking mode, ** invoke the sqlite3WalWriteLock() function on the associated Wal object ** with the same db and bLock parameters as were passed to this function. ** Return an SQLite error code if an error occurs, or SQLITE_OK otherwise. */ int sqlite3PagerWalWriteLock(Pager *pPager, int bLock){ int rc = SQLITE_OK; if( pagerUseWal(pPager) && pPager->exclusiveMode==0 ){ rc = sqlite3WalWriteLock(pPager->pWal, bLock); } return rc; } /* ** Set the database handle used by the wal layer to determine if ** blocking locks are required. */ void sqlite3PagerWalDb(Pager *pPager, sqlite3 *db){ if( pagerUseWal(pPager) ){ sqlite3WalDb(pPager->pWal, db); } } #endif #ifdef SQLITE_ENABLE_SNAPSHOT /* ** If this is a WAL database, obtain a snapshot handle for the snapshot ** currently open. Otherwise, return an error. */ int sqlite3PagerSnapshotGet(Pager *pPager, sqlite3_snapshot **ppSnapshot){ int rc = SQLITE_ERROR; if( pPager->pWal ){ rc = sqlite3WalSnapshotGet(pPager->pWal, ppSnapshot); } return rc; } /* ** If this is a WAL database, store a pointer to pSnapshot. Next time a ** read transaction is opened, attempt to read from the snapshot it ** identifies. If this is not a WAL database, return an error. */ int sqlite3PagerSnapshotOpen( Pager *pPager, sqlite3_snapshot *pSnapshot ){ int rc = SQLITE_OK; if( pPager->pWal ){ sqlite3WalSnapshotOpen(pPager->pWal, pSnapshot); }else{ rc = SQLITE_ERROR; } return rc; |
︙ | ︙ | |||
7845 7846 7847 7848 7849 7850 7851 | /* ** Release a lock obtained by an earlier successful call to ** sqlite3PagerSnapshotCheck(). */ void sqlite3PagerSnapshotUnlock(Pager *pPager){ assert( pPager->pWal ); | | | 7846 7847 7848 7849 7850 7851 7852 7853 7854 7855 7856 7857 7858 7859 7860 | /* ** Release a lock obtained by an earlier successful call to ** sqlite3PagerSnapshotCheck(). */ void sqlite3PagerSnapshotUnlock(Pager *pPager){ assert( pPager->pWal ); sqlite3WalSnapshotUnlock(pPager->pWal); } #endif /* SQLITE_ENABLE_SNAPSHOT */ int sqlite3PagerWalInfo(Pager *pPager, u32 *pnPrior, u32 *pnFrame){ return sqlite3WalInfo(pPager->pWal, pnPrior, pnFrame); } |
︙ | ︙ |
Changes to src/pager.h.
︙ | ︙ | |||
42 43 44 45 46 47 48 | */ typedef struct PgHdr DbPage; /* ** Page number PAGER_MJ_PGNO is never used in an SQLite database (it is ** reserved for working around a windows/posix incompatibility). It is ** used in the journal to signify that the remainder of the journal file | | | | 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | */ typedef struct PgHdr DbPage; /* ** Page number PAGER_MJ_PGNO is never used in an SQLite database (it is ** reserved for working around a windows/posix incompatibility). It is ** used in the journal to signify that the remainder of the journal file ** is devoted to storing a super-journal name - there are no more pages to ** roll back. See comments for function writeSuperJournal() in pager.c ** for details. */ #define PAGER_MJ_PGNO(x) ((Pgno)((PENDING_BYTE/((x)->pageSize))+1)) /* ** Allowed values for the flags parameter to sqlite3PagerOpen(). ** |
︙ | ︙ | |||
124 125 126 127 128 129 130 | ); int sqlite3PagerClose(Pager *pPager, sqlite3*); int sqlite3PagerReadFileheader(Pager*, int, unsigned char*); /* Functions used to configure a Pager object. */ void sqlite3PagerSetBusyHandler(Pager*, int(*)(void *), void *); int sqlite3PagerSetPagesize(Pager*, u32*, int); | < < < | | 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 | ); int sqlite3PagerClose(Pager *pPager, sqlite3*); int sqlite3PagerReadFileheader(Pager*, int, unsigned char*); /* Functions used to configure a Pager object. */ void sqlite3PagerSetBusyHandler(Pager*, int(*)(void *), void *); int sqlite3PagerSetPagesize(Pager*, u32*, int); Pgno sqlite3PagerMaxPageCount(Pager*, Pgno); void sqlite3PagerSetCachesize(Pager*, int); int sqlite3PagerSetSpillsize(Pager*, int); void sqlite3PagerSetMmapLimit(Pager *, sqlite3_int64); void sqlite3PagerShrink(Pager*); void sqlite3PagerSetFlags(Pager*,unsigned); int sqlite3PagerLockingMode(Pager *, int); int sqlite3PagerSetJournalMode(Pager *, int); |
︙ | ︙ | |||
160 161 162 163 164 165 166 | int sqlite3PagerPageRefcount(DbPage*); void *sqlite3PagerGetData(DbPage *); void *sqlite3PagerGetExtra(DbPage *); /* Functions used to manage pager transactions and savepoints. */ void sqlite3PagerPagecount(Pager*, int*); int sqlite3PagerBegin(Pager*, int exFlag, int); | | | | | > > > > > > > > | < < < < < | 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 | int sqlite3PagerPageRefcount(DbPage*); void *sqlite3PagerGetData(DbPage *); void *sqlite3PagerGetExtra(DbPage *); /* Functions used to manage pager transactions and savepoints. */ void sqlite3PagerPagecount(Pager*, int*); int sqlite3PagerBegin(Pager*, int exFlag, int); int sqlite3PagerCommitPhaseOne(Pager*,const char *zSuper, int); int sqlite3PagerExclusiveLock(Pager*, DbPage *pPage1, Pgno*); int sqlite3PagerSync(Pager *pPager, const char *zSuper); int sqlite3PagerCommitPhaseTwo(Pager*); int sqlite3PagerRollback(Pager*); int sqlite3PagerOpenSavepoint(Pager *pPager, int n); int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint); int sqlite3PagerSharedLock(Pager *pPager); #ifndef SQLITE_OMIT_WAL int sqlite3PagerCheckpoint(Pager *pPager, sqlite3*, int, int*, int*); int sqlite3PagerWalSupported(Pager *pPager); int sqlite3PagerWalCallback(Pager *pPager); int sqlite3PagerOpenWal(Pager *pPager, int *pisOpen); int sqlite3PagerCloseWal(Pager *pPager, sqlite3*); # ifdef SQLITE_ENABLE_SNAPSHOT int sqlite3PagerSnapshotGet(Pager*, sqlite3_snapshot **ppSnapshot); int sqlite3PagerSnapshotOpen(Pager*, sqlite3_snapshot *pSnapshot); int sqlite3PagerSnapshotRecover(Pager *pPager); int sqlite3PagerSnapshotCheck(Pager *pPager, sqlite3_snapshot *pSnapshot); void sqlite3PagerSnapshotUnlock(Pager *pPager); # endif #endif #if !defined(SQLITE_OMIT_WAL) && defined(SQLITE_ENABLE_SETLK_TIMEOUT) int sqlite3PagerWalWriteLock(Pager*, int); void sqlite3PagerWalDb(Pager*, sqlite3*); #else # define sqlite3PagerWalWriteLock(y,z) SQLITE_OK # define sqlite3PagerWalDb(x,y) #endif #ifdef SQLITE_DIRECT_OVERFLOW_READ int sqlite3PagerDirectReadOk(Pager *pPager, Pgno pgno); #endif #ifdef SQLITE_ENABLE_ZIPVFS int sqlite3PagerWalFramesize(Pager *pPager); #endif /* Functions used to query pager state and configuration. */ u8 sqlite3PagerIsreadonly(Pager*); u32 sqlite3PagerDataVersion(Pager*); #ifdef SQLITE_DEBUG int sqlite3PagerRefcount(Pager*); #endif int sqlite3PagerMemUsed(Pager*); const char *sqlite3PagerFilename(const Pager*, int); sqlite3_vfs *sqlite3PagerVfs(Pager*); sqlite3_file *sqlite3PagerFile(Pager*); sqlite3_file *sqlite3PagerJrnlFile(Pager*); const char *sqlite3PagerJournalname(Pager*); void *sqlite3PagerTempSpace(Pager*); int sqlite3PagerIsMemdb(Pager*); void sqlite3PagerCacheStat(Pager *, int, int, int *); void sqlite3PagerClearCache(Pager*); int sqlite3SectorSize(sqlite3_file *); /* Functions used to truncate the database file. */ void sqlite3PagerTruncateImage(Pager*,Pgno); void sqlite3PagerRekey(DbPage*, Pgno, u16); #ifndef SQLITE_OMIT_CONCURRENT |
︙ | ︙ | |||
238 239 240 241 242 243 244 | #if defined(SQLITE_DEBUG) || !defined(SQLITE_OMIT_CONCURRENT) int sqlite3PagerIswriteable(DbPage*); #endif int sqlite3PagerWalInfo(Pager*, u32 *pnPrior, u32 *pnFrame); | < < < < | 238 239 240 241 242 243 244 245 246 247 248 249 250 251 | #if defined(SQLITE_DEBUG) || !defined(SQLITE_OMIT_CONCURRENT) int sqlite3PagerIswriteable(DbPage*); #endif int sqlite3PagerWalInfo(Pager*, u32 *pnPrior, u32 *pnFrame); /* Functions to support testing and debugging. */ #if !defined(NDEBUG) || defined(SQLITE_TEST) Pgno sqlite3PagerPagenumber(DbPage*); #endif #ifdef SQLITE_TEST int *sqlite3PagerStats(Pager*); void sqlite3PagerRefdump(Pager*); |
︙ | ︙ |
Changes to src/parse.y.
1 | /* | > | | > > | | > | > > | 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 | %include { /* ** 2001-09-15 ** ** 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 SQLite's SQL parser. ** ** The canonical source code to this file ("parse.y") is a Lemon grammar ** file that specifies the input grammar and actions to take while parsing. ** That input file is processed by Lemon to generate a C-language ** implementation of a parser for the given grammer. You might be reading ** this comment as part of the translated C-code. Edits should be made ** to the original parse.y sources. */ } // All token codes are small integers with #defines that begin with "TK_" %token_prefix TK_ // The type of the data attached to each token is Token. This is also the // default type for non-terminals. // |
︙ | ︙ | |||
109 110 111 112 113 114 115 116 | struct FrameBound { int eType; Expr *pExpr; }; /* ** Disable lookaside memory allocation for objects that might be ** shared across database connections. */ static void disableLookaside(Parse *pParse){ pParse->disableLookaside++; | > > > | > > > > > > > > > > > > > > > | > > > > | | 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 | struct FrameBound { int eType; Expr *pExpr; }; /* ** Disable lookaside memory allocation for objects that might be ** shared across database connections. */ static void disableLookaside(Parse *pParse){ sqlite3 *db = pParse->db; pParse->disableLookaside++; DisableLookaside; } #if !defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) \ && defined(SQLITE_UDL_CAPABLE_PARSER) /* ** Issue an error message if an ORDER BY or LIMIT clause occurs on an ** UPDATE or DELETE statement. */ static void updateDeleteLimitError( Parse *pParse, ExprList *pOrderBy, Expr *pLimit ){ if( pOrderBy ){ sqlite3ErrorMsg(pParse, "syntax error near \"ORDER BY\""); }else{ sqlite3ErrorMsg(pParse, "syntax error near \"LIMIT\""); } sqlite3ExprListDelete(pParse->db, pOrderBy); sqlite3ExprDelete(pParse->db, pLimit); } #endif /* SQLITE_ENABLE_UPDATE_DELETE_LIMIT */ } // end %include // Input is a single SQL command input ::= cmdlist. cmdlist ::= cmdlist ecmd. cmdlist ::= ecmd. ecmd ::= SEMI. ecmd ::= cmdx SEMI. %ifndef SQLITE_OMIT_EXPLAIN ecmd ::= explain cmdx SEMI. {NEVER-REDUCE} explain ::= EXPLAIN. { pParse->explain = 1; } explain ::= EXPLAIN QUERY PLAN. { pParse->explain = 2; } %endif SQLITE_OMIT_EXPLAIN cmdx ::= cmd. { sqlite3FinishCoding(pParse); } ///////////////////// Begin and end transactions. //////////////////////////// // |
︙ | ︙ | |||
177 178 179 180 181 182 183 | createkw(A) ::= CREATE(A). {disableLookaside(pParse);} %type ifnotexists {int} ifnotexists(A) ::= . {A = 0;} ifnotexists(A) ::= IF NOT EXISTS. {A = 1;} %type temp {int} %ifndef SQLITE_OMIT_TEMPDB | | | | > | > > | > > > > > > > > | | < < > > > > > > | 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 | createkw(A) ::= CREATE(A). {disableLookaside(pParse);} %type ifnotexists {int} ifnotexists(A) ::= . {A = 0;} ifnotexists(A) ::= IF NOT EXISTS. {A = 1;} %type temp {int} %ifndef SQLITE_OMIT_TEMPDB temp(A) ::= TEMP. {A = pParse->db->init.busy==0;} %endif SQLITE_OMIT_TEMPDB temp(A) ::= . {A = 0;} create_table_args ::= LP columnlist conslist_opt(X) RP(E) table_option_set(F). { sqlite3EndTable(pParse,&X,&E,F,0); } create_table_args ::= AS select(S). { sqlite3EndTable(pParse,0,0,0,S); sqlite3SelectDelete(pParse->db, S); } %type table_option_set {u32} %type table_option {u32} table_option_set(A) ::= . {A = 0;} table_option_set(A) ::= table_option(A). table_option_set(A) ::= table_option_set(X) COMMA table_option(Y). {A = X|Y;} table_option(A) ::= WITHOUT nm(X). { if( X.n==5 && sqlite3_strnicmp(X.z,"rowid",5)==0 ){ A = TF_WithoutRowid | TF_NoVisibleRowid; }else{ A = 0; sqlite3ErrorMsg(pParse, "unknown table option: %.*s", X.n, X.z); } } table_option(A) ::= nm(X). { if( X.n==6 && sqlite3_strnicmp(X.z,"strict",6)==0 ){ A = TF_Strict; }else{ A = 0; sqlite3ErrorMsg(pParse, "unknown table option: %.*s", X.n, X.z); } } columnlist ::= columnlist COMMA columnname carglist. columnlist ::= columnname carglist. columnname(A) ::= nm(A) typetoken(Y). {sqlite3AddColumn(pParse,A,Y);} // Declare some tokens early in order to influence their values, to // improve performance and reduce the executable size. The goal here is // to get the "jump" operations in ISNULL through ESCAPE to have numeric // values that are early enough so that all jump operations are clustered // at the beginning. // %token ABORT ACTION AFTER ANALYZE ASC ATTACH BEFORE BEGIN BY CASCADE CAST. %token CONFLICT DATABASE DEFERRED DESC DETACH EACH END EXCLUSIVE EXPLAIN FAIL. %token OR AND NOT IS MATCH LIKE_KW BETWEEN IN ISNULL NOTNULL NE EQ. %token GT LE LT GE ESCAPE. // The following directive causes tokens ABORT, AFTER, ASC, etc. to // fallback to ID if they will not parse as their original value. // This obviates the need for the "id" nonterminal. // %fallback ID ABORT ACTION AFTER ANALYZE ASC ATTACH BEFORE BEGIN BY CASCADE CAST COLUMNKW CONFLICT DATABASE DEFERRED DESC DETACH DO EACH END EXCLUSIVE EXPLAIN FAIL FOR IGNORE IMMEDIATE INITIALLY INSTEAD LIKE_KW MATCH NO PLAN QUERY KEY OF OFFSET PRAGMA RAISE RECURSIVE RELEASE REPLACE RESTRICT ROW ROWS ROLLBACK SAVEPOINT TEMP TRIGGER VACUUM VIEW VIRTUAL WITH WITHOUT NULLS FIRST LAST %ifdef SQLITE_OMIT_COMPOUND_SELECT EXCEPT INTERSECT UNION %endif SQLITE_OMIT_COMPOUND_SELECT %ifndef SQLITE_OMIT_WINDOWFUNC CURRENT FOLLOWING PARTITION PRECEDING RANGE UNBOUNDED EXCLUDE GROUPS OTHERS TIES %endif SQLITE_OMIT_WINDOWFUNC %ifndef SQLITE_OMIT_GENERATED_COLUMNS GENERATED ALWAYS %endif MATERIALIZED REINDEX RENAME CTIME_KW IF . %wildcard ANY. // Define operator precedence early so that this is the first occurrence // of the operator tokens in the grammer. Keeping the operators together // causes them to be assigned integer values that are close together, |
︙ | ︙ | |||
313 314 315 316 317 318 319 320 321 322 323 324 325 326 | // post-processing, if needed. // %type scanpt {const char*} scanpt(A) ::= . { assert( yyLookahead!=YYNOCODE ); A = yyLookaheadToken.z; } // "carglist" is a list of additional constraints that come after the // column name and column type in a CREATE TABLE statement. // carglist ::= carglist ccons. carglist ::= . ccons ::= CONSTRAINT nm(X). {pParse->constraintName = X;} | > > > > | | | | | | | | > > > > | 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 | // post-processing, if needed. // %type scanpt {const char*} scanpt(A) ::= . { assert( yyLookahead!=YYNOCODE ); A = yyLookaheadToken.z; } scantok(A) ::= . { assert( yyLookahead!=YYNOCODE ); A = yyLookaheadToken; } // "carglist" is a list of additional constraints that come after the // column name and column type in a CREATE TABLE statement. // carglist ::= carglist ccons. carglist ::= . ccons ::= CONSTRAINT nm(X). {pParse->constraintName = X;} ccons ::= DEFAULT scantok(A) term(X). {sqlite3AddDefaultValue(pParse,X,A.z,&A.z[A.n]);} ccons ::= DEFAULT LP(A) expr(X) RP(Z). {sqlite3AddDefaultValue(pParse,X,A.z+1,Z.z);} ccons ::= DEFAULT PLUS(A) scantok(Z) term(X). {sqlite3AddDefaultValue(pParse,X,A.z,&Z.z[Z.n]);} ccons ::= DEFAULT MINUS(A) scantok(Z) term(X). { Expr *p = sqlite3PExpr(pParse, TK_UMINUS, X, 0); sqlite3AddDefaultValue(pParse,p,A.z,&Z.z[Z.n]); } ccons ::= DEFAULT scantok id(X). { Expr *p = tokenExpr(pParse, TK_STRING, X); if( p ){ sqlite3ExprIdToTrueFalse(p); testcase( p->op==TK_TRUEFALSE && sqlite3ExprTruthValue(p) ); } sqlite3AddDefaultValue(pParse,p,X.z,X.z+X.n); } // In addition to the type name, we also care about the primary key and // UNIQUE constraints. // ccons ::= NULL onconf. ccons ::= NOT NULL onconf(R). {sqlite3AddNotNull(pParse, R);} ccons ::= PRIMARY KEY sortorder(Z) onconf(R) autoinc(I). {sqlite3AddPrimaryKey(pParse,0,R,I,Z);} ccons ::= UNIQUE onconf(R). {sqlite3CreateIndex(pParse,0,0,0,0,R,0,0,0,0, SQLITE_IDXTYPE_UNIQUE);} ccons ::= CHECK LP(A) expr(X) RP(B). {sqlite3AddCheckConstraint(pParse,X,A.z,B.z);} ccons ::= REFERENCES nm(T) eidlist_opt(TA) refargs(R). {sqlite3CreateForeignKey(pParse,0,&T,TA,R);} ccons ::= defer_subclause(D). {sqlite3DeferForeignKey(pParse,D);} ccons ::= COLLATE ids(C). {sqlite3AddCollateType(pParse, &C);} ccons ::= GENERATED ALWAYS AS generated. ccons ::= AS generated. generated ::= LP expr(E) RP. {sqlite3AddGenerated(pParse,E,0);} generated ::= LP expr(E) RP ID(TYPE). {sqlite3AddGenerated(pParse,E,&TYPE);} // The optional AUTOINCREMENT keyword %type autoinc {int} autoinc(X) ::= . {X = 0;} autoinc(X) ::= AUTOINCR. {X = 1;} // The next group of rules parses the arguments to a REFERENCES clause |
︙ | ︙ | |||
398 399 400 401 402 403 404 | tconscomma ::= . tcons ::= CONSTRAINT nm(X). {pParse->constraintName = X;} tcons ::= PRIMARY KEY LP sortlist(X) autoinc(I) RP onconf(R). {sqlite3AddPrimaryKey(pParse,X,R,I,0);} tcons ::= UNIQUE LP sortlist(X) RP onconf(R). {sqlite3CreateIndex(pParse,0,0,0,X,R,0,0,0,0, SQLITE_IDXTYPE_UNIQUE);} | | | | 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 | tconscomma ::= . tcons ::= CONSTRAINT nm(X). {pParse->constraintName = X;} tcons ::= PRIMARY KEY LP sortlist(X) autoinc(I) RP onconf(R). {sqlite3AddPrimaryKey(pParse,X,R,I,0);} tcons ::= UNIQUE LP sortlist(X) RP onconf(R). {sqlite3CreateIndex(pParse,0,0,0,X,R,0,0,0,0, SQLITE_IDXTYPE_UNIQUE);} tcons ::= CHECK LP(A) expr(E) RP(B) onconf. {sqlite3AddCheckConstraint(pParse,E,A.z,B.z);} tcons ::= FOREIGN KEY LP eidlist(FA) RP REFERENCES nm(T) eidlist_opt(TA) refargs(R) defer_subclause_opt(D). { sqlite3CreateForeignKey(pParse, FA, &T, TA, R); sqlite3DeferForeignKey(pParse, D); } %type defer_subclause_opt {int} defer_subclause_opt(A) ::= . {A = 0;} |
︙ | ︙ | |||
447 448 449 450 451 452 453 | sqlite3DropTable(pParse, X, 1, E); } %endif SQLITE_OMIT_VIEW //////////////////////// The SELECT statement ///////////////////////////////// // cmd ::= select(X). { | | > | | < > > > > > > > > > > > | | | < > | | | | | | | | | < < < < < < < | < | > > > > | 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 | sqlite3DropTable(pParse, X, 1, E); } %endif SQLITE_OMIT_VIEW //////////////////////// The SELECT statement ///////////////////////////////// // cmd ::= select(X). { SelectDest dest = {SRT_Output, 0, 0, 0, 0, 0, 0}; sqlite3Select(pParse, X, &dest); sqlite3SelectDelete(pParse->db, X); } %type select {Select*} %destructor select {sqlite3SelectDelete(pParse->db, $$);} %type selectnowith {Select*} %destructor selectnowith {sqlite3SelectDelete(pParse->db, $$);} %type oneselect {Select*} %destructor oneselect {sqlite3SelectDelete(pParse->db, $$);} %include { /* ** For a compound SELECT statement, make sure p->pPrior->pNext==p for ** all elements in the list. And make sure list length does not exceed ** SQLITE_LIMIT_COMPOUND_SELECT. */ static void parserDoubleLinkSelect(Parse *pParse, Select *p){ assert( p!=0 ); if( p->pPrior ){ Select *pNext = 0, *pLoop = p; int mxSelect, cnt = 1; while(1){ pLoop->pNext = pNext; pLoop->selFlags |= SF_Compound; pNext = pLoop; pLoop = pLoop->pPrior; if( pLoop==0 ) break; cnt++; if( pLoop->pOrderBy || pLoop->pLimit ){ sqlite3ErrorMsg(pParse,"%s clause should come after %s not before", pLoop->pOrderBy!=0 ? "ORDER BY" : "LIMIT", sqlite3SelectOpName(pNext->op)); break; } } if( (p->selFlags & SF_MultiValue)==0 && (mxSelect = pParse->db->aLimit[SQLITE_LIMIT_COMPOUND_SELECT])>0 && cnt>mxSelect ){ sqlite3ErrorMsg(pParse, "too many terms in compound SELECT"); } } } /* Attach a With object describing the WITH clause to a Select ** object describing the query for which the WITH clause is a prefix. */ static Select *attachWithToSelect(Parse *pParse, Select *pSelect, With *pWith){ if( pSelect ){ pSelect->pWith = pWith; parserDoubleLinkSelect(pParse, pSelect); }else{ sqlite3WithDelete(pParse->db, pWith); } return pSelect; } } %ifndef SQLITE_OMIT_CTE select(A) ::= WITH wqlist(W) selectnowith(X). {A = attachWithToSelect(pParse,X,W);} select(A) ::= WITH RECURSIVE wqlist(W) selectnowith(X). {A = attachWithToSelect(pParse,X,W);} %endif /* SQLITE_OMIT_CTE */ select(A) ::= selectnowith(X). { Select *p = X; if( p ){ parserDoubleLinkSelect(pParse, p); } A = p; /*A-overwrites-X*/ |
︙ | ︙ | |||
635 636 637 638 639 640 641 | %type stl_prefix {SrcList*} %destructor stl_prefix {sqlite3SrcListDelete(pParse->db, $$);} %type from {SrcList*} %destructor from {sqlite3SrcListDelete(pParse->db, $$);} // A complete FROM clause. // | | | 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 | %type stl_prefix {SrcList*} %destructor stl_prefix {sqlite3SrcListDelete(pParse->db, $$);} %type from {SrcList*} %destructor from {sqlite3SrcListDelete(pParse->db, $$);} // A complete FROM clause. // from(A) ::= . {A = 0;} from(A) ::= FROM seltablist(X). { A = X; sqlite3SrcListShiftJoinType(A); } // "seltablist" is a "Select Table List" - the content of the FROM clause // in a SELECT statement. "stl_prefix" is a prefix of this list. |
︙ | ︙ | |||
670 671 672 673 674 675 676 | seltablist(A) ::= stl_prefix(A) LP seltablist(F) RP as(Z) on_opt(N) using_opt(U). { if( A==0 && Z.n==0 && N==0 && U==0 ){ A = F; }else if( F->nSrc==1 ){ A = sqlite3SrcListAppendFromTerm(pParse,A,0,0,&Z,0,N,U); if( A ){ | | | | 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 | seltablist(A) ::= stl_prefix(A) LP seltablist(F) RP as(Z) on_opt(N) using_opt(U). { if( A==0 && Z.n==0 && N==0 && U==0 ){ A = F; }else if( F->nSrc==1 ){ A = sqlite3SrcListAppendFromTerm(pParse,A,0,0,&Z,0,N,U); if( A ){ SrcItem *pNew = &A->a[A->nSrc-1]; SrcItem *pOld = F->a; pNew->zName = pOld->zName; pNew->zDatabase = pOld->zDatabase; pNew->pSelect = pOld->pSelect; if( pOld->fg.isTabFunc ){ pNew->u1.pFuncArg = pOld->u1.pFuncArg; pOld->u1.pFuncArg = 0; pOld->fg.isTabFunc = 0; |
︙ | ︙ | |||
701 702 703 704 705 706 707 | %type dbnm {Token} dbnm(A) ::= . {A.z=0; A.n=0;} dbnm(A) ::= DOT nm(X). {A = X;} %type fullname {SrcList*} %destructor fullname {sqlite3SrcListDelete(pParse->db, $$);} fullname(A) ::= nm(X). { | | | | | | | | 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 | %type dbnm {Token} dbnm(A) ::= . {A.z=0; A.n=0;} dbnm(A) ::= DOT nm(X). {A = X;} %type fullname {SrcList*} %destructor fullname {sqlite3SrcListDelete(pParse->db, $$);} fullname(A) ::= nm(X). { A = sqlite3SrcListAppend(pParse,0,&X,0); if( IN_RENAME_OBJECT && A ) sqlite3RenameTokenMap(pParse, A->a[0].zName, &X); } fullname(A) ::= nm(X) DOT nm(Y). { A = sqlite3SrcListAppend(pParse,0,&X,&Y); if( IN_RENAME_OBJECT && A ) sqlite3RenameTokenMap(pParse, A->a[0].zName, &Y); } %type xfullname {SrcList*} %destructor xfullname {sqlite3SrcListDelete(pParse->db, $$);} xfullname(A) ::= nm(X). {A = sqlite3SrcListAppend(pParse,0,&X,0); /*A-overwrites-X*/} xfullname(A) ::= nm(X) DOT nm(Y). {A = sqlite3SrcListAppend(pParse,0,&X,&Y); /*A-overwrites-X*/} xfullname(A) ::= nm(X) DOT nm(Y) AS nm(Z). { A = sqlite3SrcListAppend(pParse,0,&X,&Y); /*A-overwrites-X*/ if( A ) A->a[0].zAlias = sqlite3NameFromToken(pParse->db, &Z); } xfullname(A) ::= nm(X) AS nm(Z). { A = sqlite3SrcListAppend(pParse,0,&X,0); /*A-overwrites-X*/ if( A ) A->a[0].zAlias = sqlite3NameFromToken(pParse->db, &Z); } %type joinop {int} joinop(X) ::= COMMA|JOIN. { X = JT_INNER; } joinop(X) ::= JOIN_KW(A) JOIN. {X = sqlite3JoinType(pParse,&A,0,0); /*X-overwrites-A*/} |
︙ | ︙ | |||
788 789 790 791 792 793 794 | // sort order. // %type sortlist {ExprList*} %destructor sortlist {sqlite3ExprListDelete(pParse->db, $$);} orderby_opt(A) ::= . {A = 0;} orderby_opt(A) ::= ORDER BY sortlist(X). {A = X;} | | | | | > > > > > | 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 | // sort order. // %type sortlist {ExprList*} %destructor sortlist {sqlite3ExprListDelete(pParse->db, $$);} orderby_opt(A) ::= . {A = 0;} orderby_opt(A) ::= ORDER BY sortlist(X). {A = X;} sortlist(A) ::= sortlist(A) COMMA expr(Y) sortorder(Z) nulls(X). { A = sqlite3ExprListAppend(pParse,A,Y); sqlite3ExprListSetSortOrder(A,Z,X); } sortlist(A) ::= expr(Y) sortorder(Z) nulls(X). { A = sqlite3ExprListAppend(pParse,0,Y); /*A-overwrites-Y*/ sqlite3ExprListSetSortOrder(A,Z,X); } %type sortorder {int} sortorder(A) ::= ASC. {A = SQLITE_SO_ASC;} sortorder(A) ::= DESC. {A = SQLITE_SO_DESC;} sortorder(A) ::= . {A = SQLITE_SO_UNDEFINED;} %type nulls {int} nulls(A) ::= NULLS FIRST. {A = SQLITE_SO_ASC;} nulls(A) ::= NULLS LAST. {A = SQLITE_SO_DESC;} nulls(A) ::= . {A = SQLITE_SO_UNDEFINED;} %type groupby_opt {ExprList*} %destructor groupby_opt {sqlite3ExprListDelete(pParse->db, $$);} groupby_opt(A) ::= . {A = 0;} groupby_opt(A) ::= GROUP BY nexprlist(X). {A = X;} %type having_opt {Expr*} %destructor having_opt {sqlite3ExprDelete(pParse->db, $$);} |
︙ | ︙ | |||
833 834 835 836 837 838 839 | limit_opt(A) ::= LIMIT expr(X) OFFSET expr(Y). {A = sqlite3PExpr(pParse,TK_LIMIT,X,Y);} limit_opt(A) ::= LIMIT expr(X) COMMA expr(Y). {A = sqlite3PExpr(pParse,TK_LIMIT,Y,X);} /////////////////////////// The DELETE statement ///////////////////////////// // | | | > > > > > > > | < | > > > > > > > > | | | > > > > > > > > | < | | > > > | 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 | limit_opt(A) ::= LIMIT expr(X) OFFSET expr(Y). {A = sqlite3PExpr(pParse,TK_LIMIT,X,Y);} limit_opt(A) ::= LIMIT expr(X) COMMA expr(Y). {A = sqlite3PExpr(pParse,TK_LIMIT,Y,X);} /////////////////////////// The DELETE statement ///////////////////////////// // %if SQLITE_ENABLE_UPDATE_DELETE_LIMIT || SQLITE_UDL_CAPABLE_PARSER cmd ::= with DELETE FROM xfullname(X) indexed_opt(I) where_opt_ret(W) orderby_opt(O) limit_opt(L). { sqlite3SrcListIndexedBy(pParse, X, &I); #ifndef SQLITE_ENABLE_UPDATE_DELETE_LIMIT if( O || L ){ updateDeleteLimitError(pParse,O,L); O = 0; L = 0; } #endif sqlite3DeleteFrom(pParse,X,W,O,L); } %else cmd ::= with DELETE FROM xfullname(X) indexed_opt(I) where_opt_ret(W). { sqlite3SrcListIndexedBy(pParse, X, &I); sqlite3DeleteFrom(pParse,X,W,0,0); } %endif %type where_opt {Expr*} %destructor where_opt {sqlite3ExprDelete(pParse->db, $$);} %type where_opt_ret {Expr*} %destructor where_opt_ret {sqlite3ExprDelete(pParse->db, $$);} where_opt(A) ::= . {A = 0;} where_opt(A) ::= WHERE expr(X). {A = X;} where_opt_ret(A) ::= . {A = 0;} where_opt_ret(A) ::= WHERE expr(X). {A = X;} where_opt_ret(A) ::= RETURNING selcollist(X). {sqlite3AddReturning(pParse,X); A = 0;} where_opt_ret(A) ::= WHERE expr(X) RETURNING selcollist(Y). {sqlite3AddReturning(pParse,Y); A = X;} ////////////////////////// The UPDATE command //////////////////////////////// // %if SQLITE_ENABLE_UPDATE_DELETE_LIMIT || SQLITE_UDL_CAPABLE_PARSER cmd ::= with UPDATE orconf(R) xfullname(X) indexed_opt(I) SET setlist(Y) from(F) where_opt_ret(W) orderby_opt(O) limit_opt(L). { sqlite3SrcListIndexedBy(pParse, X, &I); X = sqlite3SrcListAppendList(pParse, X, F); sqlite3ExprListCheckLength(pParse,Y,"set list"); #ifndef SQLITE_ENABLE_UPDATE_DELETE_LIMIT if( O || L ){ updateDeleteLimitError(pParse,O,L); O = 0; L = 0; } #endif sqlite3Update(pParse,X,Y,W,R,O,L,0); } %else cmd ::= with UPDATE orconf(R) xfullname(X) indexed_opt(I) SET setlist(Y) from(F) where_opt_ret(W). { sqlite3SrcListIndexedBy(pParse, X, &I); sqlite3ExprListCheckLength(pParse,Y,"set list"); X = sqlite3SrcListAppendList(pParse, X, F); sqlite3Update(pParse,X,Y,W,R,0,0,0); } %endif %type setlist {ExprList*} %destructor setlist {sqlite3ExprListDelete(pParse->db, $$);} setlist(A) ::= setlist(A) COMMA nm(X) EQ expr(Y). { A = sqlite3ExprListAppend(pParse, A, Y); sqlite3ExprListSetName(pParse, A, &X, 1); |
︙ | ︙ | |||
896 897 898 899 900 901 902 | ////////////////////////// The INSERT command ///////////////////////////////// // cmd ::= with insert_cmd(R) INTO xfullname(X) idlist_opt(F) select(S) upsert(U). { sqlite3Insert(pParse, X, S, F, R, U); } | | > | | | | | | > > > > > | 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 | ////////////////////////// The INSERT command ///////////////////////////////// // cmd ::= with insert_cmd(R) INTO xfullname(X) idlist_opt(F) select(S) upsert(U). { sqlite3Insert(pParse, X, S, F, R, U); } cmd ::= with insert_cmd(R) INTO xfullname(X) idlist_opt(F) DEFAULT VALUES returning. { sqlite3Insert(pParse, X, 0, F, R, 0); } %type upsert {Upsert*} // Because upsert only occurs at the tip end of the INSERT rule for cmd, // there is never a case where the value of the upsert pointer will not // be destroyed by the cmd action. So comment-out the destructor to // avoid unreachable code. //%destructor upsert {sqlite3UpsertDelete(pParse->db,$$);} upsert(A) ::= . { A = 0; } upsert(A) ::= RETURNING selcollist(X). { A = 0; sqlite3AddReturning(pParse,X); } upsert(A) ::= ON CONFLICT LP sortlist(T) RP where_opt(TW) DO UPDATE SET setlist(Z) where_opt(W) upsert(N). { A = sqlite3UpsertNew(pParse->db,T,TW,Z,W,N);} upsert(A) ::= ON CONFLICT LP sortlist(T) RP where_opt(TW) DO NOTHING upsert(N). { A = sqlite3UpsertNew(pParse->db,T,TW,0,0,N); } upsert(A) ::= ON CONFLICT DO NOTHING returning. { A = sqlite3UpsertNew(pParse->db,0,0,0,0,0); } upsert(A) ::= ON CONFLICT DO UPDATE SET setlist(Z) where_opt(W) returning. { A = sqlite3UpsertNew(pParse->db,0,0,Z,W,0);} returning ::= RETURNING selcollist(X). {sqlite3AddReturning(pParse,X);} returning ::= . %type insert_cmd {int} insert_cmd(A) ::= INSERT orconf(R). {A = R;} insert_cmd(A) ::= REPLACE. {A = OE_Replace;} %type idlist_opt {IdList*} %destructor idlist_opt {sqlite3IdListDelete(pParse->db, $$);} |
︙ | ︙ | |||
952 953 954 955 956 957 958 | ** that created the expression. */ static Expr *tokenExpr(Parse *pParse, int op, Token t){ Expr *p = sqlite3DbMallocRawNN(pParse->db, sizeof(Expr)+t.n+1); if( p ){ /* memset(p, 0, sizeof(Expr)); */ p->op = (u8)op; | | > < > | < | | 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 | ** that created the expression. */ static Expr *tokenExpr(Parse *pParse, int op, Token t){ Expr *p = sqlite3DbMallocRawNN(pParse->db, sizeof(Expr)+t.n+1); if( p ){ /* memset(p, 0, sizeof(Expr)); */ p->op = (u8)op; p->affExpr = 0; p->flags = EP_Leaf; ExprClearVVAProperties(p); p->iAgg = -1; p->pLeft = p->pRight = 0; p->pAggInfo = 0; memset(&p->x, 0, sizeof(p->x)); memset(&p->y, 0, sizeof(p->y)); p->op2 = 0; p->iTable = 0; p->iColumn = 0; p->u.zToken = (char*)&p[1]; memcpy(p->u.zToken, t.z, t.n); p->u.zToken[t.n] = 0; if( sqlite3Isquote(p->u.zToken[0]) ){ sqlite3DequoteExpr(p); } #if SQLITE_MAX_EXPR_DEPTH>0 p->nHeight = 1; #endif if( IN_RENAME_OBJECT ){ return (Expr*)sqlite3RenameTokenMap(pParse, (void*)p, &t); } |
︙ | ︙ | |||
1049 1050 1051 1052 1053 1054 1055 | A = sqlite3ExprFunction(pParse, Y, &X, D); } expr(A) ::= id(X) LP STAR RP. { A = sqlite3ExprFunction(pParse, 0, &X, 0); } %ifndef SQLITE_OMIT_WINDOWFUNC | | | > > > | | 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 | A = sqlite3ExprFunction(pParse, Y, &X, D); } expr(A) ::= id(X) LP STAR RP. { A = sqlite3ExprFunction(pParse, 0, &X, 0); } %ifndef SQLITE_OMIT_WINDOWFUNC expr(A) ::= id(X) LP distinct(D) exprlist(Y) RP filter_over(Z). { A = sqlite3ExprFunction(pParse, Y, &X, D); sqlite3WindowAttach(pParse, A, Z); } expr(A) ::= id(X) LP STAR RP filter_over(Z). { A = sqlite3ExprFunction(pParse, 0, &X, 0); sqlite3WindowAttach(pParse, A, Z); } %endif term(A) ::= CTIME_KW(OP). { A = sqlite3ExprFunction(pParse, 0, &OP, 0); } expr(A) ::= LP nexprlist(X) COMMA expr(Y) RP. { ExprList *pList = sqlite3ExprListAppend(pParse, X, Y); A = sqlite3PExpr(pParse, TK_VECTOR, 0, 0); if( A ){ A->x.pList = pList; if( ALWAYS(pList->nExpr) ){ A->flags |= pList->a[0].pExpr->flags & EP_Propagate; } }else{ sqlite3ExprListDelete(pParse->db, pList); } } expr(A) ::= expr(A) AND expr(Y). {A=sqlite3ExprAnd(pParse,A,Y);} expr(A) ::= expr(A) OR(OP) expr(Y). {A=sqlite3PExpr(pParse,@OP,A,Y);} expr(A) ::= expr(A) LT|GT|GE|LE(OP) expr(Y). {A=sqlite3PExpr(pParse,@OP,A,Y);} expr(A) ::= expr(A) EQ|NE(OP) expr(Y). {A=sqlite3PExpr(pParse,@OP,A,Y);} expr(A) ::= expr(A) BITAND|BITOR|LSHIFT|RSHIFT(OP) expr(Y). {A=sqlite3PExpr(pParse,@OP,A,Y);} expr(A) ::= expr(A) PLUS|MINUS(OP) expr(Y). |
︙ | ︙ | |||
1178 1179 1180 1181 1182 1183 1184 | ** ** expr1 IN () ** expr1 NOT IN () ** ** simplify to constants 0 (false) and 1 (true), respectively, ** regardless of the value of expr1. */ | | | | < < < < < < < < < < < < < < < < > | | < < | < < < | | | | > > > > > > > > > | | < < > | | 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 | ** ** expr1 IN () ** expr1 NOT IN () ** ** simplify to constants 0 (false) and 1 (true), respectively, ** regardless of the value of expr1. */ sqlite3ExprUnmapAndDelete(pParse, A); A = sqlite3Expr(pParse->db, TK_INTEGER, N ? "1" : "0"); }else{ Expr *pRHS = Y->a[0].pExpr; if( Y->nExpr==1 && sqlite3ExprIsConstant(pRHS) && A->op!=TK_VECTOR ){ Y->a[0].pExpr = 0; sqlite3ExprListDelete(pParse->db, Y); pRHS = sqlite3PExpr(pParse, TK_UPLUS, pRHS, 0); A = sqlite3PExpr(pParse, TK_EQ, A, pRHS); }else{ A = sqlite3PExpr(pParse, TK_IN, A, 0); if( A==0 ){ sqlite3ExprListDelete(pParse->db, Y); }else if( A->pLeft->op==TK_VECTOR ){ int nExpr = A->pLeft->x.pList->nExpr; Select *pSelectRHS = sqlite3ExprListToValues(pParse, nExpr, Y); if( pSelectRHS ){ parserDoubleLinkSelect(pParse, pSelectRHS); sqlite3PExprAddSelect(pParse, A, pSelectRHS); } }else{ A->x.pList = Y; sqlite3ExprSetHeightAndFlags(pParse, A); } } if( N ) A = sqlite3PExpr(pParse, TK_NOT, A, 0); } } expr(A) ::= LP select(X) RP. { A = sqlite3PExpr(pParse, TK_SELECT, 0, 0); sqlite3PExprAddSelect(pParse, A, X); } expr(A) ::= expr(A) in_op(N) LP select(Y) RP. [IN] { A = sqlite3PExpr(pParse, TK_IN, A, 0); sqlite3PExprAddSelect(pParse, A, Y); if( N ) A = sqlite3PExpr(pParse, TK_NOT, A, 0); } expr(A) ::= expr(A) in_op(N) nm(Y) dbnm(Z) paren_exprlist(E). [IN] { SrcList *pSrc = sqlite3SrcListAppend(pParse, 0,&Y,&Z); Select *pSelect = sqlite3SelectNew(pParse, 0,pSrc,0,0,0,0,0,0); if( E ) sqlite3SrcListFuncArgs(pParse, pSelect ? pSrc : 0, E); A = sqlite3PExpr(pParse, TK_IN, A, 0); sqlite3PExprAddSelect(pParse, A, pSelect); if( N ) A = sqlite3PExpr(pParse, TK_NOT, A, 0); } expr(A) ::= EXISTS LP select(Y) RP. { |
︙ | ︙ | |||
1299 1300 1301 1302 1303 1304 1305 | ///////////////////////////// The CREATE INDEX command /////////////////////// // cmd ::= createkw(S) uniqueflag(U) INDEX ifnotexists(NE) nm(X) dbnm(D) ON nm(Y) LP sortlist(Z) RP where_opt(W). { sqlite3CreateIndex(pParse, &X, &D, | | | 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 | ///////////////////////////// The CREATE INDEX command /////////////////////// // cmd ::= createkw(S) uniqueflag(U) INDEX ifnotexists(NE) nm(X) dbnm(D) ON nm(Y) LP sortlist(Z) RP where_opt(W). { sqlite3CreateIndex(pParse, &X, &D, sqlite3SrcListAppend(pParse,0,&Y,0), Z, U, &S, W, SQLITE_SO_ASC, NE, SQLITE_IDXTYPE_APPDEF); if( IN_RENAME_OBJECT && pParse->pNewIndex ){ sqlite3RenameTokenMap(pParse, pParse->pNewIndex->zName, &Y); } } %type uniqueflag {int} |
︙ | ︙ | |||
1321 1322 1323 1324 1325 1326 1327 | // can be easily sent to sqlite3ColumnsExprList(). // // eidlist is grouped with CREATE INDEX because it used to be the non-terminal // used for the arguments to an index. That is just an historical accident. // // IMPORTANT COMPATIBILITY NOTE: Some prior versions of SQLite accepted // COLLATE clauses and ASC or DESC keywords on ID lists in inappropriate | | | 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 | // can be easily sent to sqlite3ColumnsExprList(). // // eidlist is grouped with CREATE INDEX because it used to be the non-terminal // used for the arguments to an index. That is just an historical accident. // // IMPORTANT COMPATIBILITY NOTE: Some prior versions of SQLite accepted // COLLATE clauses and ASC or DESC keywords on ID lists in inappropriate // places - places that might have been stored in the sqlite_schema table. // Those extra features were ignored. But because they might be in some // (busted) old databases, we need to continue parsing them when loading // historical schemas. // %type eidlist {ExprList*} %destructor eidlist {sqlite3ExprListDelete(pParse->db, $$);} %type eidlist_opt {ExprList*} |
︙ | ︙ | |||
1376 1377 1378 1379 1380 1381 1382 | ///////////////////////////// The DROP INDEX command ///////////////////////// // cmd ::= DROP INDEX ifexists(E) fullname(X). {sqlite3DropIndex(pParse, X, E);} ///////////////////////////// The VACUUM command ///////////////////////////// // | | < | < | 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 | ///////////////////////////// The DROP INDEX command ///////////////////////// // cmd ::= DROP INDEX ifexists(E) fullname(X). {sqlite3DropIndex(pParse, X, E);} ///////////////////////////// The VACUUM command ///////////////////////////// // %if !SQLITE_OMIT_VACUUM && !SQLITE_OMIT_ATTACH %type vinto {Expr*} %destructor vinto {sqlite3ExprDelete(pParse->db, $$);} cmd ::= VACUUM vinto(Y). {sqlite3Vacuum(pParse,0,Y);} cmd ::= VACUUM nm(X) vinto(Y). {sqlite3Vacuum(pParse,&X,Y);} vinto(A) ::= INTO expr(X). {A = X;} vinto(A) ::= . {A = 0;} %endif ///////////////////////////// The PRAGMA command ///////////////////////////// // %ifndef SQLITE_OMIT_PRAGMA cmd ::= PRAGMA nm(X) dbnm(Z). {sqlite3Pragma(pParse,&X,&Z,0,0);} cmd ::= PRAGMA nm(X) dbnm(Z) EQ nmnum(Y). {sqlite3Pragma(pParse,&X,&Z,&Y,0);} cmd ::= PRAGMA nm(X) dbnm(Z) LP nmnum(Y) RP. {sqlite3Pragma(pParse,&X,&Z,&Y,0);} |
︙ | ︙ | |||
1492 1493 1494 1495 1496 1497 1498 | %type trigger_cmd {TriggerStep*} %destructor trigger_cmd {sqlite3DeleteTriggerStep(pParse->db, $$);} // UPDATE trigger_cmd(A) ::= | | | | | | 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 | %type trigger_cmd {TriggerStep*} %destructor trigger_cmd {sqlite3DeleteTriggerStep(pParse->db, $$);} // UPDATE trigger_cmd(A) ::= UPDATE(B) orconf(R) trnm(X) tridxby SET setlist(Y) from(F) where_opt(Z) scanpt(E). {A = sqlite3TriggerUpdateStep(pParse, &X, F, Y, Z, R, B.z, E);} // INSERT trigger_cmd(A) ::= scanpt(B) insert_cmd(R) INTO trnm(X) idlist_opt(F) select(S) upsert(U) scanpt(Z). { A = sqlite3TriggerInsertStep(pParse,&X,F,S,R,U,B,Z);/*A-overwrites-R*/ } // DELETE trigger_cmd(A) ::= DELETE(B) FROM trnm(X) tridxby where_opt(Y) scanpt(E). {A = sqlite3TriggerDeleteStep(pParse, &X, Y, B.z, E);} // SELECT trigger_cmd(A) ::= scanpt(B) select(X) scanpt(E). {A = sqlite3TriggerSelectStep(pParse->db, X, B, E); /*A-overwrites-X*/} // The special RAISE expression that may occur in trigger programs expr(A) ::= RAISE LP IGNORE RP. { A = sqlite3PExpr(pParse, TK_RAISE, 0, 0); if( A ){ A->affExpr = OE_Ignore; } } expr(A) ::= RAISE LP raisetype(T) COMMA nm(Z) RP. { A = sqlite3ExprAlloc(pParse->db, TK_RAISE, &Z, 1); if( A ) { A->affExpr = (char)T; } } %endif !SQLITE_OMIT_TRIGGER %type raisetype {int} raisetype(A) ::= ROLLBACK. {A = OE_Rollback;} raisetype(A) ::= ABORT. {A = OE_Abort;} |
︙ | ︙ | |||
1567 1568 1569 1570 1571 1572 1573 | /////////////////////////////////// ANALYZE /////////////////////////////////// %ifndef SQLITE_OMIT_ANALYZE cmd ::= ANALYZE. {sqlite3Analyze(pParse, 0, 0);} cmd ::= ANALYZE nm(X) dbnm(Y). {sqlite3Analyze(pParse, &X, &Y);} %endif //////////////////////// ALTER TABLE table ... //////////////////////////////// | | > > > > > > | | 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 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 | /////////////////////////////////// ANALYZE /////////////////////////////////// %ifndef SQLITE_OMIT_ANALYZE cmd ::= ANALYZE. {sqlite3Analyze(pParse, 0, 0);} cmd ::= ANALYZE nm(X) dbnm(Y). {sqlite3Analyze(pParse, &X, &Y);} %endif //////////////////////// ALTER TABLE table ... //////////////////////////////// %ifndef SQLITE_OMIT_ALTERTABLE %ifndef SQLITE_OMIT_VIRTUALTABLE cmd ::= ALTER TABLE fullname(X) RENAME TO nm(Z). { sqlite3AlterRenameTable(pParse,X,&Z); } cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname(Y) carglist. { Y.n = (int)(pParse->sLastToken.z-Y.z) + pParse->sLastToken.n; sqlite3AlterFinishAddColumn(pParse, &Y); } cmd ::= ALTER TABLE fullname(X) DROP kwcolumn_opt nm(Y). { sqlite3AlterDropColumn(pParse, X, &Y); } add_column_fullname ::= fullname(X). { disableLookaside(pParse); sqlite3AlterBeginAddColumn(pParse, X); } cmd ::= ALTER TABLE fullname(X) RENAME kwcolumn_opt nm(Y) TO nm(Z). { sqlite3AlterRenameColumn(pParse, X, &Y, &Z); } kwcolumn_opt ::= . kwcolumn_opt ::= COLUMNKW. %endif SQLITE_OMIT_VIRTUALTABLE %endif SQLITE_OMIT_ALTERTABLE //////////////////////// CREATE VIRTUAL TABLE ... ///////////////////////////// %ifndef SQLITE_OMIT_VIRTUALTABLE cmd ::= create_vtab. {sqlite3VtabFinishParse(pParse,0);} cmd ::= create_vtab LP vtabarglist RP(X). {sqlite3VtabFinishParse(pParse,&X);} create_vtab ::= createkw VIRTUAL TABLE ifnotexists(E) nm(X) dbnm(Y) USING nm(Z). { |
︙ | ︙ | |||
1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 | anylist ::= anylist ANY. %endif SQLITE_OMIT_VIRTUALTABLE //////////////////////// COMMON TABLE EXPRESSIONS //////////////////////////// %type wqlist {With*} %destructor wqlist {sqlite3WithDelete(pParse->db, $$);} with ::= . %ifndef SQLITE_OMIT_CTE with ::= WITH wqlist(W). { sqlite3WithPush(pParse, W, 1); } with ::= WITH RECURSIVE wqlist(W). { sqlite3WithPush(pParse, W, 1); } | > > > > > > > > > | | | | > | | | > > > > > > | | < > | | | > > > > | | > > | > > | | | | > | | < < | | | | | > | | > > > > > > > > > > > > > > > > > | > > > > > > > > | > > > | < | < < < < | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 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 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 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 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 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 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 | anylist ::= anylist ANY. %endif SQLITE_OMIT_VIRTUALTABLE //////////////////////// COMMON TABLE EXPRESSIONS //////////////////////////// %type wqlist {With*} %destructor wqlist {sqlite3WithDelete(pParse->db, $$);} %type wqitem {Cte*} // %destructor wqitem {sqlite3CteDelete(pParse->db, $$);} // not reachable with ::= . %ifndef SQLITE_OMIT_CTE with ::= WITH wqlist(W). { sqlite3WithPush(pParse, W, 1); } with ::= WITH RECURSIVE wqlist(W). { sqlite3WithPush(pParse, W, 1); } %type wqas {u8} wqas(A) ::= AS. {A = M10d_Any;} wqas(A) ::= AS MATERIALIZED. {A = M10d_Yes;} wqas(A) ::= AS NOT MATERIALIZED. {A = M10d_No;} wqitem(A) ::= nm(X) eidlist_opt(Y) wqas(M) LP select(Z) RP. { A = sqlite3CteNew(pParse, &X, Y, Z, M); /*A-overwrites-X*/ } wqlist(A) ::= wqitem(X). { A = sqlite3WithAdd(pParse, 0, X); /*A-overwrites-X*/ } wqlist(A) ::= wqlist(A) COMMA wqitem(X). { A = sqlite3WithAdd(pParse, A, X); } %endif SQLITE_OMIT_CTE //////////////////////// WINDOW FUNCTION EXPRESSIONS ///////////////////////// // These must be at the end of this file. Specifically, the rules that // introduce tokens WINDOW, OVER and FILTER must appear last. This causes // the integer values assigned to these tokens to be larger than all other // tokens that may be output by the tokenizer except TK_SPACE and TK_ILLEGAL. // %ifndef SQLITE_OMIT_WINDOWFUNC %type windowdefn_list {Window*} %destructor windowdefn_list {sqlite3WindowListDelete(pParse->db, $$);} windowdefn_list(A) ::= windowdefn(Z). { A = Z; } windowdefn_list(A) ::= windowdefn_list(Y) COMMA windowdefn(Z). { assert( Z!=0 ); sqlite3WindowChain(pParse, Z, Y); Z->pNextWin = Y; A = Z; } %type windowdefn {Window*} %destructor windowdefn {sqlite3WindowDelete(pParse->db, $$);} windowdefn(A) ::= nm(X) AS LP window(Y) RP. { if( ALWAYS(Y) ){ Y->zName = sqlite3DbStrNDup(pParse->db, X.z, X.n); } A = Y; } %type window {Window*} %destructor window {sqlite3WindowDelete(pParse->db, $$);} %type frame_opt {Window*} %destructor frame_opt {sqlite3WindowDelete(pParse->db, $$);} %type part_opt {ExprList*} %destructor part_opt {sqlite3ExprListDelete(pParse->db, $$);} %type filter_clause {Expr*} %destructor filter_clause {sqlite3ExprDelete(pParse->db, $$);} %type over_clause {Window*} %destructor over_clause {sqlite3WindowDelete(pParse->db, $$);} %type filter_over {Window*} %destructor filter_over {sqlite3WindowDelete(pParse->db, $$);} %type range_or_rows {int} %type frame_bound {struct FrameBound} %destructor frame_bound {sqlite3ExprDelete(pParse->db, $$.pExpr);} %type frame_bound_s {struct FrameBound} %destructor frame_bound_s {sqlite3ExprDelete(pParse->db, $$.pExpr);} %type frame_bound_e {struct FrameBound} %destructor frame_bound_e {sqlite3ExprDelete(pParse->db, $$.pExpr);} window(A) ::= PARTITION BY nexprlist(X) orderby_opt(Y) frame_opt(Z). { A = sqlite3WindowAssemble(pParse, Z, X, Y, 0); } window(A) ::= nm(W) PARTITION BY nexprlist(X) orderby_opt(Y) frame_opt(Z). { A = sqlite3WindowAssemble(pParse, Z, X, Y, &W); } window(A) ::= ORDER BY sortlist(Y) frame_opt(Z). { A = sqlite3WindowAssemble(pParse, Z, 0, Y, 0); } window(A) ::= nm(W) ORDER BY sortlist(Y) frame_opt(Z). { A = sqlite3WindowAssemble(pParse, Z, 0, Y, &W); } window(A) ::= frame_opt(Z). { A = Z; } window(A) ::= nm(W) frame_opt(Z). { A = sqlite3WindowAssemble(pParse, Z, 0, 0, &W); } frame_opt(A) ::= . { A = sqlite3WindowAlloc(pParse, 0, TK_UNBOUNDED, 0, TK_CURRENT, 0, 0); } frame_opt(A) ::= range_or_rows(X) frame_bound_s(Y) frame_exclude_opt(Z). { A = sqlite3WindowAlloc(pParse, X, Y.eType, Y.pExpr, TK_CURRENT, 0, Z); } frame_opt(A) ::= range_or_rows(X) BETWEEN frame_bound_s(Y) AND frame_bound_e(Z) frame_exclude_opt(W). { A = sqlite3WindowAlloc(pParse, X, Y.eType, Y.pExpr, Z.eType, Z.pExpr, W); } range_or_rows(A) ::= RANGE|ROWS|GROUPS(X). {A = @X; /*A-overwrites-X*/} frame_bound_s(A) ::= frame_bound(X). {A = X;} frame_bound_s(A) ::= UNBOUNDED(X) PRECEDING. {A.eType = @X; A.pExpr = 0;} frame_bound_e(A) ::= frame_bound(X). {A = X;} frame_bound_e(A) ::= UNBOUNDED(X) FOLLOWING. {A.eType = @X; A.pExpr = 0;} frame_bound(A) ::= expr(X) PRECEDING|FOLLOWING(Y). {A.eType = @Y; A.pExpr = X;} frame_bound(A) ::= CURRENT(X) ROW. {A.eType = @X; A.pExpr = 0;} %type frame_exclude_opt {u8} frame_exclude_opt(A) ::= . {A = 0;} frame_exclude_opt(A) ::= EXCLUDE frame_exclude(X). {A = X;} %type frame_exclude {u8} frame_exclude(A) ::= NO(X) OTHERS. {A = @X; /*A-overwrites-X*/} frame_exclude(A) ::= CURRENT(X) ROW. {A = @X; /*A-overwrites-X*/} frame_exclude(A) ::= GROUP|TIES(X). {A = @X; /*A-overwrites-X*/} %type window_clause {Window*} %destructor window_clause {sqlite3WindowListDelete(pParse->db, $$);} window_clause(A) ::= WINDOW windowdefn_list(B). { A = B; } filter_over(A) ::= filter_clause(F) over_clause(O). { if( O ){ O->pFilter = F; }else{ sqlite3ExprDelete(pParse->db, F); } A = O; } filter_over(A) ::= over_clause(O). { A = O; } filter_over(A) ::= filter_clause(F). { A = (Window*)sqlite3DbMallocZero(pParse->db, sizeof(Window)); if( A ){ A->eFrmType = TK_FILTER; A->pFilter = F; }else{ sqlite3ExprDelete(pParse->db, F); } } over_clause(A) ::= OVER LP window(Z) RP. { A = Z; assert( A!=0 ); } over_clause(A) ::= OVER nm(Z). { A = (Window*)sqlite3DbMallocZero(pParse->db, sizeof(Window)); if( A ){ A->zName = sqlite3DbStrNDup(pParse->db, Z.z, Z.n); } } filter_clause(A) ::= FILTER LP WHERE expr(X) RP. { A = X; } %endif /* SQLITE_OMIT_WINDOWFUNC */ /* ** The code generator needs some extra TK_ token values for tokens that ** are synthesized and do not actually appear in the grammar: */ %token COLUMN /* Reference to a table column */ AGG_FUNCTION /* An aggregate function */ AGG_COLUMN /* An aggregated column */ TRUEFALSE /* True or false keyword */ ISNOT /* Combination of IS and NOT */ FUNCTION /* A function invocation */ UMINUS /* Unary minus */ UPLUS /* Unary plus */ TRUTH /* IS TRUE or IS FALSE or IS NOT TRUE or IS NOT FALSE */ REGISTER /* Reference to a VDBE register */ CONCURRENT /* BEGIN CONCURRENT */ VECTOR /* Vector */ SELECT_COLUMN /* Choose a single column from a multi-column SELECT */ IF_NULL_ROW /* the if-null-row operator */ ASTERISK /* The "*" in count(*) and similar */ SPAN /* The span operator */ ERROR /* An expression containing an error */ . /* There must be no more than 255 tokens defined above. If this grammar ** is extended with new rules and tokens, they must either be so few in ** number that TK_SPAN is no more than 255, or else the new tokens must ** appear after this line. */ %include { #if TK_SPAN>255 # error too many tokens in the grammar #endif } /* ** The TK_SPACE and TK_ILLEGAL tokens must be the last two tokens. The ** parser depends on this. Those tokens are not used in any grammar rule. ** They are only used by the tokenizer. Declare them last so that they ** are guaranteed to be the last two tokens */ %token SPACE ILLEGAL. |
Changes to src/pcache.c.
︙ | ︙ | |||
239 240 241 242 243 244 245 | */ static int numberOfCachePages(PCache *p){ if( p->szCache>=0 ){ /* IMPLEMENTATION-OF: R-42059-47211 If the argument N is positive then the ** suggested cache size is set to N. */ return p->szCache; }else{ | > | | | > | > > > | 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 | */ static int numberOfCachePages(PCache *p){ if( p->szCache>=0 ){ /* IMPLEMENTATION-OF: R-42059-47211 If the argument N is positive then the ** suggested cache size is set to N. */ return p->szCache; }else{ i64 n; /* IMPLEMANTATION-OF: R-59858-46238 If the argument N is negative, then the ** number of cache pages is adjusted to be a number of pages that would ** use approximately abs(N*1024) bytes of memory based on the current ** page size. */ n = ((-1024*(i64)p->szCache)/(p->szPage+p->szExtra)); if( n>1000000000 ) n = 1000000000; return (int)n; } } /*************************************************** General Interfaces ****** ** ** Initialize and shutdown the page cache subsystem. Neither of these ** functions are threadsafe. */ int sqlite3PcacheInitialize(void){ if( sqlite3GlobalConfig.pcache2.xInit==0 ){ /* IMPLEMENTATION-OF: R-26801-64137 If the xInit() method is NULL, then the ** built-in default page cache is used instead of the application defined ** page cache. */ sqlite3PCacheSetDefault(); assert( sqlite3GlobalConfig.pcache2.xInit!=0 ); } return sqlite3GlobalConfig.pcache2.xInit(sqlite3GlobalConfig.pcache2.pArg); } void sqlite3PcacheShutdown(void){ if( sqlite3GlobalConfig.pcache2.xShutdown ){ /* IMPLEMENTATION-OF: R-26000-56589 The xShutdown() method may be NULL. */ sqlite3GlobalConfig.pcache2.xShutdown(sqlite3GlobalConfig.pcache2.pArg); |
︙ | ︙ |
Changes to src/pcache1.c.
︙ | ︙ | |||
88 89 90 91 92 93 94 95 96 97 98 | typedef struct PGroup PGroup; /* ** Each cache entry is represented by an instance of the following ** structure. Unless SQLITE_PCACHE_SEPARATE_HEADER is defined, a buffer of ** PgHdr1.pCache->szPage bytes is allocated directly before this structure ** in memory. */ struct PgHdr1 { sqlite3_pcache_page page; /* Base class. Must be first. pBuf & pExtra */ unsigned int iKey; /* Key value (page number) */ | > > > > > > > > > > | | | 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 | typedef struct PGroup PGroup; /* ** Each cache entry is represented by an instance of the following ** structure. Unless SQLITE_PCACHE_SEPARATE_HEADER is defined, a buffer of ** PgHdr1.pCache->szPage bytes is allocated directly before this structure ** in memory. ** ** Note: Variables isBulkLocal and isAnchor were once type "u8". That works, ** but causes a 2-byte gap in the structure for most architectures (since ** pointers must be either 4 or 8-byte aligned). As this structure is located ** in memory directly after the associated page data, if the database is ** corrupt, code at the b-tree layer may overread the page buffer and ** read part of this structure before the corruption is detected. This ** can cause a valgrind error if the unitialized gap is accessed. Using u16 ** ensures there is no such gap, and therefore no bytes of unitialized memory ** in the structure. */ struct PgHdr1 { sqlite3_pcache_page page; /* Base class. Must be first. pBuf & pExtra */ unsigned int iKey; /* Key value (page number) */ u16 isBulkLocal; /* This page from bulk local storage */ u16 isAnchor; /* This is the PGroup.lru element */ PgHdr1 *pNext; /* Next in hash table chain */ PCache1 *pCache; /* Cache that currently owns this page */ PgHdr1 *pLruNext; /* Next in LRU list of unpinned pages */ PgHdr1 *pLruPrev; /* Previous in LRU list of unpinned pages */ /* NB: pLruPrev is only valid if pLruNext!=0 */ }; |
︙ | ︙ | |||
164 165 166 167 168 169 170 171 172 173 174 175 176 177 | int szExtra; /* sizeof(MemPage)+sizeof(PgHdr) */ int szAlloc; /* Total size of one pcache line */ int bPurgeable; /* True if cache is purgeable */ unsigned int nMin; /* Minimum number of pages reserved */ unsigned int nMax; /* Configured "cache_size" value */ unsigned int n90pct; /* nMax*9/10 */ unsigned int iMaxKey; /* Largest key seen since xTruncate() */ /* Hash table of all pages. The following variables may only be accessed ** when the accessor is holding the PGroup mutex. */ unsigned int nRecyclable; /* Number of pages in the LRU list */ unsigned int nPage; /* Total number of pages in apHash */ unsigned int nHash; /* Number of slots in apHash[] */ | > | 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 | int szExtra; /* sizeof(MemPage)+sizeof(PgHdr) */ int szAlloc; /* Total size of one pcache line */ int bPurgeable; /* True if cache is purgeable */ unsigned int nMin; /* Minimum number of pages reserved */ unsigned int nMax; /* Configured "cache_size" value */ unsigned int n90pct; /* nMax*9/10 */ unsigned int iMaxKey; /* Largest key seen since xTruncate() */ unsigned int nPurgeableDummy; /* pnPurgeable points here when not used*/ /* Hash table of all pages. The following variables may only be accessed ** when the accessor is holding the PGroup mutex. */ unsigned int nRecyclable; /* Number of pages in the LRU list */ unsigned int nPage; /* Total number of pages in apHash */ unsigned int nHash; /* Number of slots in apHash[] */ |
︙ | ︙ | |||
298 299 300 301 302 303 304 305 306 307 308 309 310 311 | do{ PgHdr1 *pX = (PgHdr1*)&zBulk[pCache->szPage]; pX->page.pBuf = zBulk; pX->page.pExtra = &pX[1]; pX->isBulkLocal = 1; pX->isAnchor = 0; pX->pNext = pCache->pFree; pCache->pFree = pX; zBulk += pCache->szAlloc; }while( --nBulk ); } return pCache->pFree!=0; } | > | 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 | do{ PgHdr1 *pX = (PgHdr1*)&zBulk[pCache->szPage]; pX->page.pBuf = zBulk; pX->page.pExtra = &pX[1]; pX->isBulkLocal = 1; pX->isAnchor = 0; pX->pNext = pCache->pFree; pX->pLruPrev = 0; /* Initializing this saves a valgrind error */ pCache->pFree = pX; zBulk += pCache->szAlloc; }while( --nBulk ); } return pCache->pFree!=0; } |
︙ | ︙ | |||
408 409 410 411 412 413 414 415 416 417 418 419 420 421 | */ static PgHdr1 *pcache1AllocPage(PCache1 *pCache, int benignMalloc){ PgHdr1 *p = 0; void *pPg; assert( sqlite3_mutex_held(pCache->pGroup->mutex) ); if( pCache->pFree || (pCache->nPage==0 && pcache1InitBulk(pCache)) ){ p = pCache->pFree; pCache->pFree = p->pNext; p->pNext = 0; }else{ #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT /* The group mutex must be released before pcache1Alloc() is called. This ** is because it might call sqlite3_release_memory(), which assumes that | > | 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 | */ static PgHdr1 *pcache1AllocPage(PCache1 *pCache, int benignMalloc){ PgHdr1 *p = 0; void *pPg; assert( sqlite3_mutex_held(pCache->pGroup->mutex) ); if( pCache->pFree || (pCache->nPage==0 && pcache1InitBulk(pCache)) ){ assert( pCache->pFree!=0 ); p = pCache->pFree; pCache->pFree = p->pNext; p->pNext = 0; }else{ #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT /* The group mutex must be released before pcache1Alloc() is called. This ** is because it might call sqlite3_release_memory(), which assumes that |
︙ | ︙ | |||
431 432 433 434 435 436 437 | if( !pPg || !p ){ pcache1Free(pPg); sqlite3_free(p); pPg = 0; } #else pPg = pcache1Alloc(pCache->szAlloc); | < > > > > | 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 | if( !pPg || !p ){ pcache1Free(pPg); sqlite3_free(p); pPg = 0; } #else pPg = pcache1Alloc(pCache->szAlloc); #endif if( benignMalloc ){ sqlite3EndBenignMalloc(); } #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT pcache1EnterMutex(pCache->pGroup); #endif if( pPg==0 ) return 0; #ifndef SQLITE_PCACHE_SEPARATE_HEADER p = (PgHdr1 *)&((u8 *)pPg)[pCache->szPage]; #endif p->page.pBuf = pPg; p->page.pExtra = &p[1]; p->isBulkLocal = 0; p->isAnchor = 0; p->pLruPrev = 0; /* Initializing this saves a valgrind error */ } (*pCache->pnPurgeable)++; return p; } /* ** Free a page object allocated by pcache1AllocPage(). |
︙ | ︙ | |||
473 474 475 476 477 478 479 | /* ** Malloc function used by SQLite to obtain space from the buffer configured ** using sqlite3_config(SQLITE_CONFIG_PAGECACHE) option. If no such buffer ** exists, this function falls back to sqlite3Malloc(). */ void *sqlite3PageMalloc(int sz){ | < < | | 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 | /* ** Malloc function used by SQLite to obtain space from the buffer configured ** using sqlite3_config(SQLITE_CONFIG_PAGECACHE) option. If no such buffer ** exists, this function falls back to sqlite3Malloc(). */ void *sqlite3PageMalloc(int sz){ assert( sz<=65536+8 ); /* These allocations are never very large */ return pcache1Alloc(sz); } /* ** Free an allocated buffer obtained from sqlite3PageMalloc(). */ void sqlite3PageFree(void *p){ |
︙ | ︙ | |||
764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 | if( pCache ){ if( pcache1.separateCache ){ pGroup = (PGroup*)&pCache[1]; pGroup->mxPinned = 10; }else{ pGroup = &pcache1.grp; } if( pGroup->lru.isAnchor==0 ){ pGroup->lru.isAnchor = 1; pGroup->lru.pLruPrev = pGroup->lru.pLruNext = &pGroup->lru; } pCache->pGroup = pGroup; pCache->szPage = szPage; pCache->szExtra = szExtra; pCache->szAlloc = szPage + szExtra + ROUND8(sizeof(PgHdr1)); pCache->bPurgeable = (bPurgeable ? 1 : 0); | > < < | > > > > > > | | | | 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 | if( pCache ){ if( pcache1.separateCache ){ pGroup = (PGroup*)&pCache[1]; pGroup->mxPinned = 10; }else{ pGroup = &pcache1.grp; } pcache1EnterMutex(pGroup); if( pGroup->lru.isAnchor==0 ){ pGroup->lru.isAnchor = 1; pGroup->lru.pLruPrev = pGroup->lru.pLruNext = &pGroup->lru; } pCache->pGroup = pGroup; pCache->szPage = szPage; pCache->szExtra = szExtra; pCache->szAlloc = szPage + szExtra + ROUND8(sizeof(PgHdr1)); pCache->bPurgeable = (bPurgeable ? 1 : 0); pcache1ResizeHash(pCache); if( bPurgeable ){ pCache->nMin = 10; pGroup->nMinPage += pCache->nMin; pGroup->mxPinned = pGroup->nMaxPage + 10 - pGroup->nMinPage; pCache->pnPurgeable = &pGroup->nPurgeable; }else{ pCache->pnPurgeable = &pCache->nPurgeableDummy; } pcache1LeaveMutex(pGroup); if( pCache->nHash==0 ){ pcache1Destroy((sqlite3_pcache*)pCache); pCache = 0; } } return (sqlite3_pcache *)pCache; } /* ** Implementation of the sqlite3_pcache.xCachesize method. ** ** Configure the cache_size limit for a cache. */ static void pcache1Cachesize(sqlite3_pcache *p, int nMax){ PCache1 *pCache = (PCache1 *)p; u32 n; assert( nMax>=0 ); if( pCache->bPurgeable ){ PGroup *pGroup = pCache->pGroup; pcache1EnterMutex(pGroup); n = (u32)nMax; if( n > 0x7fff0000 - pGroup->nMaxPage + pCache->nMax ){ n = 0x7fff0000 - pGroup->nMaxPage + pCache->nMax; } pGroup->nMaxPage += (n - pCache->nMax); pGroup->mxPinned = pGroup->nMaxPage + 10 - pGroup->nMinPage; pCache->nMax = n; pCache->n90pct = pCache->nMax*9/10; pcache1EnforceMaxPage(pCache); pcache1LeaveMutex(pGroup); } } /* ** Implementation of the sqlite3_pcache.xShrink method. ** ** Free up as much memory as possible. */ static void pcache1Shrink(sqlite3_pcache *p){ PCache1 *pCache = (PCache1*)p; if( pCache->bPurgeable ){ PGroup *pGroup = pCache->pGroup; unsigned int savedMaxPage; pcache1EnterMutex(pGroup); savedMaxPage = pGroup->nMaxPage; pGroup->nMaxPage = 0; pcache1EnforceMaxPage(pCache); pGroup->nMaxPage = savedMaxPage; pcache1LeaveMutex(pGroup); } |
︙ | ︙ |
Changes to src/pragma.c.
︙ | ︙ | |||
127 128 129 130 131 132 133 | /* ** Invalidate temp storage, either when the temp storage is changed ** from default, or when 'file' and the temp_store_directory has changed */ static int invalidateTempStorage(Parse *pParse){ sqlite3 *db = pParse->db; if( db->aDb[1].pBt!=0 ){ | | > > | 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 | /* ** Invalidate temp storage, either when the temp storage is changed ** from default, or when 'file' and the temp_store_directory has changed */ static int invalidateTempStorage(Parse *pParse){ sqlite3 *db = pParse->db; if( db->aDb[1].pBt!=0 ){ if( !db->autoCommit || sqlite3BtreeTxnState(db->aDb[1].pBt)!=SQLITE_TXN_NONE ){ sqlite3ErrorMsg(pParse, "temporary storage cannot be changed " "from within a transaction"); return SQLITE_ERROR; } sqlite3BtreeClose(db->aDb[1].pBt); db->aDb[1].pBt = 0; sqlite3ResetAllSchemasOfConnection(db); |
︙ | ︙ | |||
290 291 292 293 294 295 296 297 298 299 300 301 302 303 | upr = mid - 1; }else{ lwr = mid + 1; } } return lwr>upr ? 0 : &aPragmaName[mid]; } /* ** Helper subroutine for PRAGMA integrity_check: ** ** Generate code to output a single-column result row with a value of the ** string held in register 3. Decrement the result count in register 1 ** and halt if the maximum number of result rows have been issued. | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | upr = mid - 1; }else{ lwr = mid + 1; } } return lwr>upr ? 0 : &aPragmaName[mid]; } /* ** Create zero or more entries in the output for the SQL functions ** defined by FuncDef p. */ static void pragmaFunclistLine( Vdbe *v, /* The prepared statement being created */ FuncDef *p, /* A particular function definition */ int isBuiltin, /* True if this is a built-in function */ int showInternFuncs /* True if showing internal functions */ ){ for(; p; p=p->pNext){ const char *zType; static const u32 mask = SQLITE_DETERMINISTIC | SQLITE_DIRECTONLY | SQLITE_SUBTYPE | SQLITE_INNOCUOUS | SQLITE_FUNC_INTERNAL ; static const char *azEnc[] = { 0, "utf8", "utf16le", "utf16be" }; assert( SQLITE_FUNC_ENCMASK==0x3 ); assert( strcmp(azEnc[SQLITE_UTF8],"utf8")==0 ); assert( strcmp(azEnc[SQLITE_UTF16LE],"utf16le")==0 ); assert( strcmp(azEnc[SQLITE_UTF16BE],"utf16be")==0 ); if( p->xSFunc==0 ) continue; if( (p->funcFlags & SQLITE_FUNC_INTERNAL)!=0 && showInternFuncs==0 ){ continue; } if( p->xValue!=0 ){ zType = "w"; }else if( p->xFinalize!=0 ){ zType = "a"; }else{ zType = "s"; } sqlite3VdbeMultiLoad(v, 1, "sissii", p->zName, isBuiltin, zType, azEnc[p->funcFlags&SQLITE_FUNC_ENCMASK], p->nArg, (p->funcFlags & mask) ^ SQLITE_INNOCUOUS ); } } /* ** Helper subroutine for PRAGMA integrity_check: ** ** Generate code to output a single-column result row with a value of the ** string held in register 3. Decrement the result count in register 1 ** and halt if the maximum number of result rows have been issued. |
︙ | ︙ | |||
412 413 414 415 416 417 418 | pParse->nErr++; pParse->rc = rc; goto pragma_out; } /* Locate the pragma in the lookup table */ pPragma = pragmaLocate(zLeft); | | > > > > | 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 | pParse->nErr++; pParse->rc = rc; goto pragma_out; } /* Locate the pragma in the lookup table */ pPragma = pragmaLocate(zLeft); if( pPragma==0 ){ /* IMP: R-43042-22504 No error messages are generated if an ** unknown pragma is issued. */ goto pragma_out; } /* Make sure the database schema is loaded if the pragma requires that */ if( (pPragma->mPragFlg & PragFlg_NeedSchema)!=0 ){ if( sqlite3ReadSchema(pParse) ) goto pragma_out; } /* Register the result column names for pragmas that return results */ |
︙ | ︙ | |||
502 503 504 505 506 507 508 | int size = ALWAYS(pBt) ? sqlite3BtreeGetPageSize(pBt) : 0; returnSingleInt(v, size); }else{ /* Malloc may fail when setting the page-size, as there is an internal ** buffer that the pager module resizes using sqlite3_realloc(). */ db->nextPagesize = sqlite3Atoi(zRight); | | | 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 | int size = ALWAYS(pBt) ? sqlite3BtreeGetPageSize(pBt) : 0; returnSingleInt(v, size); }else{ /* Malloc may fail when setting the page-size, as there is an internal ** buffer that the pager module resizes using sqlite3_realloc(). */ db->nextPagesize = sqlite3Atoi(zRight); if( SQLITE_NOMEM==sqlite3BtreeSetPageSize(pBt, db->nextPagesize,0,0) ){ sqlite3OomFault(db); } } break; } /* |
︙ | ︙ | |||
558 559 560 561 562 563 564 565 566 567 568 569 | ** ** PRAGMA [schema.]page_count ** ** Return the number of pages in the specified database. */ case PragTyp_PAGE_COUNT: { int iReg; sqlite3CodeVerifySchema(pParse, iDb); iReg = ++pParse->nMem; if( sqlite3Tolower(zLeft[0])=='p' ){ sqlite3VdbeAddOp2(v, OP_Pagecount, iDb, iReg); }else{ | > > > > > > > | < | 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 | ** ** PRAGMA [schema.]page_count ** ** Return the number of pages in the specified database. */ case PragTyp_PAGE_COUNT: { int iReg; i64 x = 0; sqlite3CodeVerifySchema(pParse, iDb); iReg = ++pParse->nMem; if( sqlite3Tolower(zLeft[0])=='p' ){ sqlite3VdbeAddOp2(v, OP_Pagecount, iDb, iReg); }else{ if( zRight && sqlite3DecOrHexToI64(zRight,&x)==0 ){ if( x<0 ) x = 0; else if( x>0xfffffffe ) x = 0xfffffffe; }else{ x = 0; } sqlite3VdbeAddOp3(v, OP_MaxPgcnt, iDb, iReg, (int)x); } sqlite3VdbeAddOp2(v, OP_ResultRow, iReg, 1); break; } /* ** PRAGMA [schema.]locking_mode |
︙ | ︙ | |||
639 640 641 642 643 644 645 646 647 648 649 650 651 652 | for(eMode=0; (zMode = sqlite3JournalModename(eMode))!=0; eMode++){ if( sqlite3StrNICmp(zRight, zMode, n)==0 ) break; } if( !zMode ){ /* If the "=MODE" part does not match any known journal mode, ** then do a query */ eMode = PAGER_JOURNALMODE_QUERY; } } if( eMode==PAGER_JOURNALMODE_QUERY && pId2->n==0 ){ /* Convert "PRAGMA journal_mode" into "PRAGMA main.journal_mode" */ iDb = 0; pId2->n = 1; } | > > > > > | 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 | for(eMode=0; (zMode = sqlite3JournalModename(eMode))!=0; eMode++){ if( sqlite3StrNICmp(zRight, zMode, n)==0 ) break; } if( !zMode ){ /* If the "=MODE" part does not match any known journal mode, ** then do a query */ eMode = PAGER_JOURNALMODE_QUERY; } if( eMode==PAGER_JOURNALMODE_OFF && (db->flags & SQLITE_Defensive)!=0 ){ /* Do not allow journal-mode "OFF" in defensive since the database ** can become corrupted using ordinary SQL when the journal is off */ eMode = PAGER_JOURNALMODE_QUERY; } } if( eMode==PAGER_JOURNALMODE_QUERY && pId2->n==0 ){ /* Convert "PRAGMA journal_mode" into "PRAGMA main.journal_mode" */ iDb = 0; pId2->n = 1; } |
︙ | ︙ | |||
1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 | #endif if( sqlite3GetBoolean(zRight, 0) ){ db->flags |= mask; }else{ db->flags &= ~mask; if( mask==SQLITE_DeferFKs ) db->nDeferredImmCons = 0; } /* Many of the flag-pragmas modify the code generated by the SQL ** compiler (eg. count_changes). So add an opcode to expire all ** compiled SQL statements after modifying a pragma value. */ sqlite3VdbeAddOp0(v, OP_Expire); | > > > > > > > > | 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 | #endif if( sqlite3GetBoolean(zRight, 0) ){ db->flags |= mask; }else{ db->flags &= ~mask; if( mask==SQLITE_DeferFKs ) db->nDeferredImmCons = 0; if( (mask & SQLITE_WriteSchema)!=0 && sqlite3_stricmp(zRight, "reset")==0 ){ /* IMP: R-60817-01178 If the argument is "RESET" then schema ** writing is disabled (as with "PRAGMA writable_schema=OFF") and, ** in addition, the schema is reloaded. */ sqlite3ResetAllSchemasOfConnection(db); } } /* Many of the flag-pragmas modify the code generated by the SQL ** compiler (eg. count_changes). So add an opcode to expire all ** compiled SQL statements after modifying a pragma value. */ sqlite3VdbeAddOp0(v, OP_Expire); |
︙ | ︙ | |||
1080 1081 1082 1083 1084 1085 1086 1087 1088 | ** type: Column declaration type. ** notnull: True if 'NOT NULL' is part of column declaration ** dflt_value: The default value for the column, if any. ** pk: Non-zero for PK fields. */ case PragTyp_TABLE_INFO: if( zRight ){ Table *pTab; pTab = sqlite3LocateTable(pParse, LOCATE_NOERR, zRight, zDb); if( pTab ){ | > < < | > > | | | > > > > > > > > > | > > | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | 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 | ** type: Column declaration type. ** notnull: True if 'NOT NULL' is part of column declaration ** dflt_value: The default value for the column, if any. ** pk: Non-zero for PK fields. */ case PragTyp_TABLE_INFO: if( zRight ){ Table *pTab; sqlite3CodeVerifyNamedSchema(pParse, zDb); pTab = sqlite3LocateTable(pParse, LOCATE_NOERR, zRight, zDb); if( pTab ){ int i, k; int nHidden = 0; Column *pCol; Index *pPk = sqlite3PrimaryKeyIndex(pTab); pParse->nMem = 7; sqlite3ViewGetColumnNames(pParse, pTab); for(i=0, pCol=pTab->aCol; i<pTab->nCol; i++, pCol++){ int isHidden = 0; const Expr *pColExpr; if( pCol->colFlags & COLFLAG_NOINSERT ){ if( pPragma->iArg==0 ){ nHidden++; continue; } if( pCol->colFlags & COLFLAG_VIRTUAL ){ isHidden = 2; /* GENERATED ALWAYS AS ... VIRTUAL */ }else if( pCol->colFlags & COLFLAG_STORED ){ isHidden = 3; /* GENERATED ALWAYS AS ... STORED */ }else{ assert( pCol->colFlags & COLFLAG_HIDDEN ); isHidden = 1; /* HIDDEN */ } } if( (pCol->colFlags & COLFLAG_PRIMKEY)==0 ){ k = 0; }else if( pPk==0 ){ k = 1; }else{ for(k=1; k<=pTab->nCol && pPk->aiColumn[k-1]!=i; k++){} } pColExpr = sqlite3ColumnExpr(pTab,pCol); assert( pColExpr==0 || pColExpr->op==TK_SPAN || isHidden>=2 ); assert( pColExpr==0 || !ExprHasProperty(pColExpr, EP_IntValue) || isHidden>=2 ); sqlite3VdbeMultiLoad(v, 1, pPragma->iArg ? "issisii" : "issisi", i-nHidden, pCol->zCnName, sqlite3ColumnType(pCol,""), pCol->notNull ? 1 : 0, (isHidden>=2 || pColExpr==0) ? 0 : pColExpr->u.zToken, k, isHidden); } } } break; /* ** PRAGMA table_list ** ** Return a single row for each table, virtual table, or view in the ** entire schema. ** ** schema: Name of attached database hold this table ** name: Name of the table itself ** type: "table", "view", "virtual", "shadow" ** ncol: Number of columns ** wr: True for a WITHOUT ROWID table ** strict: True for a STRICT table */ case PragTyp_TABLE_LIST: { int ii; pParse->nMem = 6; sqlite3CodeVerifyNamedSchema(pParse, zDb); for(ii=0; ii<db->nDb; ii++){ HashElem *k; Hash *pHash; int initNCol; if( zDb && sqlite3_stricmp(zDb, db->aDb[ii].zDbSName)!=0 ) continue; /* Ensure that the Table.nCol field is initialized for all views ** and virtual tables. Each time we initialize a Table.nCol value ** for a table, that can potentially disrupt the hash table, so restart ** the initialization scan. */ pHash = &db->aDb[ii].pSchema->tblHash; initNCol = sqliteHashCount(pHash); while( initNCol-- ){ for(k=sqliteHashFirst(pHash); 1; k=sqliteHashNext(k) ){ Table *pTab; if( k==0 ){ initNCol = 0; break; } pTab = sqliteHashData(k); if( pTab->nCol==0 ){ char *zSql = sqlite3MPrintf(db, "SELECT*FROM\"%w\"", pTab->zName); if( zSql ){ sqlite3_stmt *pDummy = 0; (void)sqlite3_prepare(db, zSql, -1, &pDummy, 0); (void)sqlite3_finalize(pDummy); sqlite3DbFree(db, zSql); } pHash = &db->aDb[ii].pSchema->tblHash; break; } } } for(k=sqliteHashFirst(pHash); k; k=sqliteHashNext(k) ){ Table *pTab = sqliteHashData(k); const char *zType; if( zRight && sqlite3_stricmp(zRight, pTab->zName)!=0 ) continue; if( IsView(pTab) ){ zType = "view"; }else if( IsVirtual(pTab) ){ zType = "virtual"; }else if( pTab->tabFlags & TF_Shadow ){ zType = "shadow"; }else{ zType = "table"; } sqlite3VdbeMultiLoad(v, 1, "sssiii", db->aDb[ii].zDbSName, sqlite3PreferredTableName(pTab->zName), zType, pTab->nCol, (pTab->tabFlags & TF_WithoutRowid)!=0, (pTab->tabFlags & TF_Strict)!=0 ); } } } break; #ifdef SQLITE_DEBUG case PragTyp_STATS: { Index *pIdx; HashElem *i; pParse->nMem = 5; sqlite3CodeVerifySchema(pParse, iDb); for(i=sqliteHashFirst(&pDb->pSchema->tblHash); i; i=sqliteHashNext(i)){ Table *pTab = sqliteHashData(i); sqlite3VdbeMultiLoad(v, 1, "ssiii", sqlite3PreferredTableName(pTab->zName), 0, pTab->szTabRow, pTab->nRowLogEst, pTab->tabFlags); for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ sqlite3VdbeMultiLoad(v, 2, "siiiX", pIdx->zName, |
︙ | ︙ | |||
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 | break; #endif case PragTyp_INDEX_INFO: if( zRight ){ Index *pIdx; Table *pTab; pIdx = sqlite3FindIndex(db, zRight, zDb); if( pIdx ){ int iIdxDb = sqlite3SchemaToIndex(db, pIdx->pSchema); int i; int mx; if( pPragma->iArg ){ /* PRAGMA index_xinfo (newer version with more rows and columns) */ mx = pIdx->nColumn; pParse->nMem = 6; }else{ /* PRAGMA index_info (legacy version) */ mx = pIdx->nKeyCol; pParse->nMem = 3; } pTab = pIdx->pTable; sqlite3CodeVerifySchema(pParse, iIdxDb); assert( pParse->nMem<=pPragma->nPragCName ); for(i=0; i<mx; i++){ i16 cnum = pIdx->aiColumn[i]; sqlite3VdbeMultiLoad(v, 1, "iisX", i, cnum, | > > > > > > > > > | | 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 | break; #endif case PragTyp_INDEX_INFO: if( zRight ){ Index *pIdx; Table *pTab; pIdx = sqlite3FindIndex(db, zRight, zDb); if( pIdx==0 ){ /* If there is no index named zRight, check to see if there is a ** WITHOUT ROWID table named zRight, and if there is, show the ** structure of the PRIMARY KEY index for that table. */ pTab = sqlite3LocateTable(pParse, LOCATE_NOERR, zRight, zDb); if( pTab && !HasRowid(pTab) ){ pIdx = sqlite3PrimaryKeyIndex(pTab); } } if( pIdx ){ int iIdxDb = sqlite3SchemaToIndex(db, pIdx->pSchema); int i; int mx; if( pPragma->iArg ){ /* PRAGMA index_xinfo (newer version with more rows and columns) */ mx = pIdx->nColumn; pParse->nMem = 6; }else{ /* PRAGMA index_info (legacy version) */ mx = pIdx->nKeyCol; pParse->nMem = 3; } pTab = pIdx->pTable; sqlite3CodeVerifySchema(pParse, iIdxDb); assert( pParse->nMem<=pPragma->nPragCName ); for(i=0; i<mx; i++){ i16 cnum = pIdx->aiColumn[i]; sqlite3VdbeMultiLoad(v, 1, "iisX", i, cnum, cnum<0 ? 0 : pTab->aCol[cnum].zCnName); if( pPragma->iArg ){ sqlite3VdbeMultiLoad(v, 4, "isiX", pIdx->aSortOrder[i], pIdx->azColl[i], i<pIdx->nKeyCol); } sqlite3VdbeAddOp2(v, OP_ResultRow, 1, pParse->nMem); |
︙ | ︙ | |||
1227 1228 1229 1230 1231 1232 1233 | for(p=sqliteHashFirst(&db->aCollSeq); p; p=sqliteHashNext(p)){ CollSeq *pColl = (CollSeq *)sqliteHashData(p); sqlite3VdbeMultiLoad(v, 1, "is", i++, pColl->zName); } } break; | | > | | < > | > | 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 | for(p=sqliteHashFirst(&db->aCollSeq); p; p=sqliteHashNext(p)){ CollSeq *pColl = (CollSeq *)sqliteHashData(p); sqlite3VdbeMultiLoad(v, 1, "is", i++, pColl->zName); } } break; #ifndef SQLITE_OMIT_INTROSPECTION_PRAGMAS case PragTyp_FUNCTION_LIST: { int i; HashElem *j; FuncDef *p; int showInternFunc = (db->mDbFlags & DBFLAG_InternalFunc)!=0; pParse->nMem = 6; for(i=0; i<SQLITE_FUNC_HASH_SZ; i++){ for(p=sqlite3BuiltinFunctions.a[i]; p; p=p->u.pHash ){ assert( p->funcFlags & SQLITE_FUNC_BUILTIN ); pragmaFunclistLine(v, p, 1, showInternFunc); } } for(j=sqliteHashFirst(&db->aFunc); j; j=sqliteHashNext(j)){ p = (FuncDef*)sqliteHashData(j); assert( (p->funcFlags & SQLITE_FUNC_BUILTIN)==0 ); pragmaFunclistLine(v, p, 0, showInternFunc); } } break; #ifndef SQLITE_OMIT_VIRTUALTABLE case PragTyp_MODULE_LIST: { HashElem *j; |
︙ | ︙ | |||
1274 1275 1276 1277 1278 1279 1280 | #endif /* SQLITE_OMIT_SCHEMA_PRAGMAS */ #ifndef SQLITE_OMIT_FOREIGN_KEY case PragTyp_FOREIGN_KEY_LIST: if( zRight ){ FKey *pFK; Table *pTab; pTab = sqlite3FindTable(db, zRight, zDb); | | | | | 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 | #endif /* SQLITE_OMIT_SCHEMA_PRAGMAS */ #ifndef SQLITE_OMIT_FOREIGN_KEY case PragTyp_FOREIGN_KEY_LIST: if( zRight ){ FKey *pFK; Table *pTab; pTab = sqlite3FindTable(db, zRight, zDb); if( pTab && IsOrdinaryTable(pTab) ){ pFK = pTab->u.tab.pFKey; if( pFK ){ int iTabDb = sqlite3SchemaToIndex(db, pTab->pSchema); int i = 0; pParse->nMem = 8; sqlite3CodeVerifySchema(pParse, iTabDb); while(pFK){ int j; for(j=0; j<pFK->nCol; j++){ sqlite3VdbeMultiLoad(v, 1, "iissssss", i, j, pFK->zTo, pTab->aCol[pFK->aCol[j].iFrom].zCnName, pFK->aCol[j].zCol, actionName(pFK->aAction[1]), /* ON UPDATE */ actionName(pFK->aAction[0]), /* ON DELETE */ "NONE"); } ++i; pFK = pFK->pNextFrom; |
︙ | ︙ | |||
1327 1328 1329 1330 1331 1332 1333 | regResult = pParse->nMem+1; pParse->nMem += 4; regKey = ++pParse->nMem; regRow = ++pParse->nMem; k = sqliteHashFirst(&db->aDb[iDb].pSchema->tblHash); while( k ){ | < | | > | | | > | | | | > | | | > | | 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 | regResult = pParse->nMem+1; pParse->nMem += 4; regKey = ++pParse->nMem; regRow = ++pParse->nMem; k = sqliteHashFirst(&db->aDb[iDb].pSchema->tblHash); while( k ){ if( zRight ){ pTab = sqlite3LocateTable(pParse, 0, zRight, zDb); k = 0; }else{ pTab = (Table*)sqliteHashData(k); k = sqliteHashNext(k); } if( pTab==0 || !IsOrdinaryTable(pTab) || pTab->u.tab.pFKey==0 ) continue; iDb = sqlite3SchemaToIndex(db, pTab->pSchema); zDb = db->aDb[iDb].zDbSName; sqlite3CodeVerifySchema(pParse, iDb); sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName); if( pTab->nCol+regRow>pParse->nMem ) pParse->nMem = pTab->nCol + regRow; sqlite3OpenTable(pParse, 0, iDb, pTab, OP_OpenRead); sqlite3VdbeLoadString(v, regResult, pTab->zName); assert( IsOrdinaryTable(pTab) ); for(i=1, pFK=pTab->u.tab.pFKey; pFK; i++, pFK=pFK->pNextFrom){ pParent = sqlite3FindTable(db, pFK->zTo, zDb); if( pParent==0 ) continue; pIdx = 0; sqlite3TableLock(pParse, iDb, pParent->tnum, 0, pParent->zName); x = sqlite3FkLocateIndex(pParse, pParent, pFK, &pIdx, 0); if( x==0 ){ if( pIdx==0 ){ sqlite3OpenTable(pParse, i, iDb, pParent, OP_OpenRead); }else{ sqlite3VdbeAddOp3(v, OP_OpenRead, i, pIdx->tnum, iDb); sqlite3VdbeSetP4KeyInfo(pParse, pIdx); } }else{ k = 0; break; } } assert( pParse->nErr>0 || pFK==0 ); if( pFK ) break; if( pParse->nTab<i ) pParse->nTab = i; addrTop = sqlite3VdbeAddOp1(v, OP_Rewind, 0); VdbeCoverage(v); assert( IsOrdinaryTable(pTab) ); for(i=1, pFK=pTab->u.tab.pFKey; pFK; i++, pFK=pFK->pNextFrom){ pParent = sqlite3FindTable(db, pFK->zTo, zDb); pIdx = 0; aiCols = 0; if( pParent ){ x = sqlite3FkLocateIndex(pParse, pParent, pFK, &pIdx, &aiCols); assert( x==0 || db->mallocFailed ); } addrOk = sqlite3VdbeMakeLabel(pParse); /* Generate code to read the child key values into registers ** regRow..regRow+n. If any of the child key values are NULL, this ** row cannot cause an FK violation. Jump directly to addrOk in ** this case. */ if( regRow+pFK->nCol>pParse->nMem ) pParse->nMem = regRow+pFK->nCol; for(j=0; j<pFK->nCol; j++){ int iCol = aiCols ? aiCols[j] : pFK->aCol[j].iFrom; sqlite3ExprCodeGetColumnOfTable(v, pTab, 0, iCol, regRow+j); sqlite3VdbeAddOp2(v, OP_IsNull, regRow+j, addrOk); VdbeCoverage(v); } /* Generate code to query the parent index for a matching parent ** key. If a match is found, jump to addrOk. */ if( pIdx ){ sqlite3VdbeAddOp4(v, OP_MakeRecord, regRow, pFK->nCol, regKey, sqlite3IndexAffinityStr(db,pIdx), pFK->nCol); sqlite3VdbeAddOp4Int(v, OP_Found, i, addrOk, regKey, 0); VdbeCoverage(v); }else if( pParent ){ int jmp = sqlite3VdbeCurrentAddr(v)+2; sqlite3VdbeAddOp3(v, OP_SeekRowid, i, jmp, regRow); VdbeCoverage(v); sqlite3VdbeGoto(v, addrOk); assert( pFK->nCol==1 || db->mallocFailed ); } /* Generate code to report an FK violation to the caller. */ if( HasRowid(pTab) ){ sqlite3VdbeAddOp2(v, OP_Rowid, 0, regResult+1); }else{ sqlite3VdbeAddOp2(v, OP_Null, 0, regResult+1); |
︙ | ︙ | |||
1417 1418 1419 1420 1421 1422 1423 | sqlite3VdbeJumpHere(v, addrTop); } } break; #endif /* !defined(SQLITE_OMIT_TRIGGER) */ #endif /* !defined(SQLITE_OMIT_FOREIGN_KEY) */ | | < < < < < < < < < < < < > > > > > > > > > > > > > > | 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 | sqlite3VdbeJumpHere(v, addrTop); } } break; #endif /* !defined(SQLITE_OMIT_TRIGGER) */ #endif /* !defined(SQLITE_OMIT_FOREIGN_KEY) */ #ifndef SQLITE_OMIT_CASE_SENSITIVE_LIKE_PRAGMA /* Reinstall the LIKE and GLOB functions. The variant of LIKE ** used will be case sensitive or not depending on the RHS. */ case PragTyp_CASE_SENSITIVE_LIKE: { if( zRight ){ sqlite3RegisterLikeFunctions(db, sqlite3GetBoolean(zRight, 0)); } } break; #endif /* SQLITE_OMIT_CASE_SENSITIVE_LIKE_PRAGMA */ #ifndef SQLITE_INTEGRITY_CHECK_ERROR_MAX # define SQLITE_INTEGRITY_CHECK_ERROR_MAX 100 #endif #ifndef SQLITE_OMIT_INTEGRITY_CHECK /* PRAGMA integrity_check ** PRAGMA integrity_check(N) ** PRAGMA quick_check ** PRAGMA quick_check(N) ** ** Verify the integrity of the database. ** ** The "quick_check" is reduced version of ** integrity_check designed to detect most database corruption ** without the overhead of cross-checking indexes. Quick_check ** is linear time wherease integrity_check is O(NlogN). ** ** The maximum nubmer of errors is 100 by default. A different default ** can be specified using a numeric parameter N. ** ** Or, the parameter N can be the name of a table. In that case, only ** the one table named is verified. The freelist is only verified if ** the named table is "sqlite_schema" (or one of its aliases). ** ** All schemas are checked by default. To check just a single ** schema, use the form: ** ** PRAGMA schema.integrity_check; */ case PragTyp_INTEGRITY_CHECK: { int i, j, addr, mxErr; Table *pObjTab = 0; /* Check only this one table, if not NULL */ int isQuick = (sqlite3Tolower(zLeft[0])=='q'); /* If the PRAGMA command was of the form "PRAGMA <db>.integrity_check", ** then iDb is set to the index of the database identified by <db>. ** In this case, the integrity of database iDb only is verified by ** the VDBE created below. |
︙ | ︙ | |||
1481 1482 1483 1484 1485 1486 1487 | /* Initialize the VDBE program */ pParse->nMem = 6; /* Set the maximum error count */ mxErr = SQLITE_INTEGRITY_CHECK_ERROR_MAX; if( zRight ){ | | | | > > > > | 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 | /* Initialize the VDBE program */ pParse->nMem = 6; /* Set the maximum error count */ mxErr = SQLITE_INTEGRITY_CHECK_ERROR_MAX; if( zRight ){ if( sqlite3GetInt32(zRight, &mxErr) ){ if( mxErr<=0 ){ mxErr = SQLITE_INTEGRITY_CHECK_ERROR_MAX; } }else{ pObjTab = sqlite3LocateTable(pParse, 0, zRight, iDb>=0 ? db->aDb[iDb].zDbSName : 0); } } sqlite3VdbeAddOp2(v, OP_Integer, mxErr-1, 1); /* reg[1] holds errors left */ /* Do an integrity check on each database file */ for(i=0; i<db->nDb; i++){ HashElem *x; /* For looping over tables in the schema */ |
︙ | ︙ | |||
1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 | */ assert( sqlite3SchemaMutexHeld(db, i, 0) ); pTbls = &db->aDb[i].pSchema->tblHash; for(cnt=0, x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){ Table *pTab = sqliteHashData(x); /* Current table */ Index *pIdx; /* An index on pTab */ int nIdx; /* Number of indexes on pTab */ if( HasRowid(pTab) ) cnt++; for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdx++){ cnt++; } if( nIdx>mxIdx ) mxIdx = nIdx; } aRoot = sqlite3DbMallocRawNN(db, sizeof(int)*(cnt+1)); if( aRoot==0 ) break; | > > > > > | > | 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 | */ assert( sqlite3SchemaMutexHeld(db, i, 0) ); pTbls = &db->aDb[i].pSchema->tblHash; for(cnt=0, x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){ Table *pTab = sqliteHashData(x); /* Current table */ Index *pIdx; /* An index on pTab */ int nIdx; /* Number of indexes on pTab */ if( pObjTab && pObjTab!=pTab ) continue; if( HasRowid(pTab) ) cnt++; for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdx++){ cnt++; } if( nIdx>mxIdx ) mxIdx = nIdx; } if( cnt==0 ) continue; if( pObjTab ) cnt++; aRoot = sqlite3DbMallocRawNN(db, sizeof(int)*(cnt+1)); if( aRoot==0 ) break; cnt = 0; if( pObjTab ) aRoot[++cnt] = 0; for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){ Table *pTab = sqliteHashData(x); Index *pIdx; if( pObjTab && pObjTab!=pTab ) continue; if( HasRowid(pTab) ) aRoot[++cnt] = pTab->tnum; for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ aRoot[++cnt] = pIdx->tnum; } } aRoot[0] = cnt; |
︙ | ︙ | |||
1552 1553 1554 1555 1556 1557 1558 1559 | for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){ Table *pTab = sqliteHashData(x); Index *pIdx, *pPk; Index *pPrior = 0; int loopTop; int iDataCur, iIdxCur; int r1 = -1; | > > | | > | > > > | | > > | > > | | > > > > > > > > > > > > > > > > > | | > | | | > | | | 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 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 | for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){ Table *pTab = sqliteHashData(x); Index *pIdx, *pPk; Index *pPrior = 0; int loopTop; int iDataCur, iIdxCur; int r1 = -1; int bStrict; if( !IsOrdinaryTable(pTab) ) continue; if( pObjTab && pObjTab!=pTab ) continue; pPk = HasRowid(pTab) ? 0 : sqlite3PrimaryKeyIndex(pTab); sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenRead, 0, 1, 0, &iDataCur, &iIdxCur); /* reg[7] counts the number of entries in the table. ** reg[8+i] counts the number of entries in the i-th index */ sqlite3VdbeAddOp2(v, OP_Integer, 0, 7); for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){ sqlite3VdbeAddOp2(v, OP_Integer, 0, 8+j); /* index entries counter */ } assert( pParse->nMem>=8+j ); assert( sqlite3NoTempsInRange(pParse,1,7+j) ); sqlite3VdbeAddOp2(v, OP_Rewind, iDataCur, 0); VdbeCoverage(v); loopTop = sqlite3VdbeAddOp2(v, OP_AddImm, 7, 1); if( !isQuick ){ /* Sanity check on record header decoding */ sqlite3VdbeAddOp3(v, OP_Column, iDataCur, pTab->nNVCol-1,3); sqlite3VdbeChangeP5(v, OPFLAG_TYPEOFARG); VdbeComment((v, "(right-most column)")); } /* Verify that all NOT NULL columns really are NOT NULL. At the ** same time verify the type of the content of STRICT tables */ bStrict = (pTab->tabFlags & TF_Strict)!=0; for(j=0; j<pTab->nCol; j++){ char *zErr; Column *pCol = pTab->aCol + j; int doError, jmp2; if( j==pTab->iPKey ) continue; if( pCol->notNull==0 && !bStrict ) continue; doError = bStrict ? sqlite3VdbeMakeLabel(pParse) : 0; sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, j, 3); if( sqlite3VdbeGetOp(v,-1)->opcode==OP_Column ){ sqlite3VdbeChangeP5(v, OPFLAG_TYPEOFARG); } if( pCol->notNull ){ jmp2 = sqlite3VdbeAddOp1(v, OP_NotNull, 3); VdbeCoverage(v); zErr = sqlite3MPrintf(db, "NULL value in %s.%s", pTab->zName, pCol->zCnName); sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC); if( bStrict && pCol->eCType!=COLTYPE_ANY ){ sqlite3VdbeGoto(v, doError); }else{ integrityCheckResultRow(v); } sqlite3VdbeJumpHere(v, jmp2); } if( (pTab->tabFlags & TF_Strict)!=0 && pCol->eCType!=COLTYPE_ANY ){ jmp2 = sqlite3VdbeAddOp3(v, OP_IsNullOrType, 3, 0, sqlite3StdTypeMap[pCol->eCType-1]); VdbeCoverage(v); zErr = sqlite3MPrintf(db, "non-%s value in %s.%s", sqlite3StdType[pCol->eCType-1], pTab->zName, pTab->aCol[j].zCnName); sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC); sqlite3VdbeResolveLabel(v, doError); integrityCheckResultRow(v); sqlite3VdbeJumpHere(v, jmp2); } } /* Verify CHECK constraints */ if( pTab->pCheck && (db->flags & SQLITE_IgnoreChecks)==0 ){ ExprList *pCheck = sqlite3ExprListDup(db, pTab->pCheck, 0); if( db->mallocFailed==0 ){ int addrCkFault = sqlite3VdbeMakeLabel(pParse); int addrCkOk = sqlite3VdbeMakeLabel(pParse); char *zErr; int k; pParse->iSelfTab = iDataCur + 1; for(k=pCheck->nExpr-1; k>0; k--){ sqlite3ExprIfFalse(pParse, pCheck->a[k].pExpr, addrCkFault, 0); } sqlite3ExprIfTrue(pParse, pCheck->a[0].pExpr, addrCkOk, |
︙ | ︙ | |||
1616 1617 1618 1619 1620 1621 1622 | } sqlite3ExprListDelete(db, pCheck); } if( !isQuick ){ /* Omit the remaining tests for quick_check */ /* Validate index entries for the current row */ for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){ int jmp2, jmp3, jmp4, jmp5; | | | | 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 | } sqlite3ExprListDelete(db, pCheck); } if( !isQuick ){ /* Omit the remaining tests for quick_check */ /* Validate index entries for the current row */ for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){ int jmp2, jmp3, jmp4, jmp5; int ckUniq = sqlite3VdbeMakeLabel(pParse); if( pPk==pIdx ) continue; r1 = sqlite3GenerateIndexKey(pParse, pIdx, iDataCur, 0, 0, &jmp3, pPrior, r1); pPrior = pIdx; sqlite3VdbeAddOp2(v, OP_AddImm, 8+j, 1);/* increment entry count */ /* Verify that an index entry exists for the current table row */ jmp2 = sqlite3VdbeAddOp4Int(v, OP_Found, iIdxCur+j, ckUniq, r1, pIdx->nColumn); VdbeCoverage(v); sqlite3VdbeLoadString(v, 3, "row "); sqlite3VdbeAddOp3(v, OP_Concat, 7, 3, 3); sqlite3VdbeLoadString(v, 4, " missing from index "); sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 3); jmp5 = sqlite3VdbeLoadString(v, 4, pIdx->zName); sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 3); jmp4 = integrityCheckResultRow(v); sqlite3VdbeJumpHere(v, jmp2); /* For UNIQUE indexes, verify that only one entry exists with the ** current key. The entry is unique if (1) any column is NULL ** or (2) the next entry has a different key */ if( IsUniqueIndex(pIdx) ){ int uniqOk = sqlite3VdbeMakeLabel(pParse); int jmp6; int kk; for(kk=0; kk<pIdx->nKeyCol; kk++){ int iCol = pIdx->aiColumn[kk]; assert( iCol!=XN_ROWID && iCol<pTab->nCol ); if( iCol>=0 && pTab->aCol[iCol].notNull ) continue; sqlite3VdbeAddOp2(v, OP_IsNull, r1+kk, uniqOk); |
︙ | ︙ | |||
1662 1663 1664 1665 1666 1667 1668 | } sqlite3VdbeJumpHere(v, jmp4); sqlite3ResolvePartIdxLabel(pParse, jmp3); } } sqlite3VdbeAddOp2(v, OP_Next, iDataCur, loopTop); VdbeCoverage(v); sqlite3VdbeJumpHere(v, loopTop-1); | < < | 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 1904 | } sqlite3VdbeJumpHere(v, jmp4); sqlite3ResolvePartIdxLabel(pParse, jmp3); } } sqlite3VdbeAddOp2(v, OP_Next, iDataCur, loopTop); VdbeCoverage(v); sqlite3VdbeJumpHere(v, loopTop-1); if( !isQuick ){ sqlite3VdbeLoadString(v, 2, "wrong # of entries in index "); for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){ if( pPk==pIdx ) continue; sqlite3VdbeAddOp2(v, OP_Count, iIdxCur+j, 3); addr = sqlite3VdbeAddOp3(v, OP_Eq, 8+j, 0, 3); VdbeCoverage(v); sqlite3VdbeChangeP5(v, SQLITE_NOTNULL); sqlite3VdbeLoadString(v, 4, pIdx->zName); sqlite3VdbeAddOp3(v, OP_Concat, 4, 2, 3); integrityCheckResultRow(v); sqlite3VdbeJumpHere(v, addr); } } } } { static const int iLn = VDBE_OFFSET_LINENO(2); static const VdbeOpList endCode[] = { { OP_AddImm, 1, 0, 0}, /* 0 */ { OP_IfNotZero, 1, 4, 0}, /* 1 */ |
︙ | ︙ | |||
1757 1758 1759 1760 1761 1762 1763 | returnSingleText(v, encnames[ENC(pParse->db)].zName); }else{ /* "PRAGMA encoding = XXX" */ /* Only change the value of sqlite.enc if the database handle is not ** initialized. If the main database exists, the new sqlite.enc value ** will be overwritten when the schema is next loaded. If it does not ** already exists, it will be created to use the new encoding value. */ | | < < < < | > > | 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 | returnSingleText(v, encnames[ENC(pParse->db)].zName); }else{ /* "PRAGMA encoding = XXX" */ /* Only change the value of sqlite.enc if the database handle is not ** initialized. If the main database exists, the new sqlite.enc value ** will be overwritten when the schema is next loaded. If it does not ** already exists, it will be created to use the new encoding value. */ if( (db->mDbFlags & DBFLAG_EncodingFixed)==0 ){ for(pEnc=&encnames[0]; pEnc->zName; pEnc++){ if( 0==sqlite3StrICmp(zRight, pEnc->zName) ){ u8 enc = pEnc->enc ? pEnc->enc : SQLITE_UTF16NATIVE; SCHEMA_ENC(db) = enc; sqlite3SetTextEncoding(db, enc); break; } } if( !pEnc->zName ){ sqlite3ErrorMsg(pParse, "unsupported encoding: %s", zRight); } } |
︙ | ︙ | |||
1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 | sqlite3VdbeVerifyNoMallocRequired(v, ArraySize(setCookie)); aOp = sqlite3VdbeAddOpList(v, ArraySize(setCookie), setCookie, 0); if( ONLY_IF_REALLOC_STRESS(aOp==0) ) break; aOp[0].p1 = iDb; aOp[1].p1 = iDb; aOp[1].p2 = iCookie; aOp[1].p3 = sqlite3Atoi(zRight); }else{ /* Read the specified cookie value */ static const VdbeOpList readCookie[] = { { OP_Transaction, 0, 0, 0}, /* 0 */ { OP_ReadCookie, 0, 1, 0}, /* 1 */ { OP_ResultRow, 1, 1, 0} }; | > | 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 | sqlite3VdbeVerifyNoMallocRequired(v, ArraySize(setCookie)); aOp = sqlite3VdbeAddOpList(v, ArraySize(setCookie), setCookie, 0); if( ONLY_IF_REALLOC_STRESS(aOp==0) ) break; aOp[0].p1 = iDb; aOp[1].p1 = iDb; aOp[1].p2 = iCookie; aOp[1].p3 = sqlite3Atoi(zRight); aOp[1].p5 = 1; }else{ /* Read the specified cookie value */ static const VdbeOpList readCookie[] = { { OP_Transaction, 0, 0, 0}, /* 0 */ { OP_ReadCookie, 0, 1, 0}, /* 1 */ { OP_ResultRow, 1, 1, 0} }; |
︙ | ︙ | |||
1874 1875 1876 1877 1878 1879 1880 | #ifndef SQLITE_OMIT_WAL /* ** PRAGMA [schema.]wal_checkpoint = passive|full|restart|truncate ** ** Checkpoint the database. */ case PragTyp_WAL_CHECKPOINT: { | | | 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 | #ifndef SQLITE_OMIT_WAL /* ** PRAGMA [schema.]wal_checkpoint = passive|full|restart|truncate ** ** Checkpoint the database. */ case PragTyp_WAL_CHECKPOINT: { int iBt = (pId2->z?iDb:SQLITE_MAX_DB); int eMode = SQLITE_CHECKPOINT_PASSIVE; if( zRight ){ if( sqlite3StrICmp(zRight, "full")==0 ){ eMode = SQLITE_CHECKPOINT_FULL; }else if( sqlite3StrICmp(zRight, "restart")==0 ){ eMode = SQLITE_CHECKPOINT_RESTART; }else if( sqlite3StrICmp(zRight, "truncate")==0 ){ |
︙ | ︙ | |||
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 | sqlite3_int64 N; if( zRight && sqlite3DecOrHexToI64(zRight, &N)==SQLITE_OK ){ sqlite3_soft_heap_limit64(N); } returnSingleInt(v, sqlite3_soft_heap_limit64(-1)); break; } /* ** PRAGMA threads ** PRAGMA threads = N ** ** Configure the maximum number of worker threads. Return the new ** maximum, which might be less than requested. */ case PragTyp_THREADS: { sqlite3_int64 N; if( zRight && sqlite3DecOrHexToI64(zRight, &N)==SQLITE_OK && N>=0 ){ sqlite3_limit(db, SQLITE_LIMIT_WORKER_THREADS, (int)(N&0x7fffffff)); } returnSingleInt(v, sqlite3_limit(db, SQLITE_LIMIT_WORKER_THREADS, -1)); break; } #if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) /* ** Report the current state of file logs for all databases */ case PragTyp_LOCK_STATUS: { static const char *const azLockName[] = { | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 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 | sqlite3_int64 N; if( zRight && sqlite3DecOrHexToI64(zRight, &N)==SQLITE_OK ){ sqlite3_soft_heap_limit64(N); } returnSingleInt(v, sqlite3_soft_heap_limit64(-1)); break; } /* ** PRAGMA hard_heap_limit ** PRAGMA hard_heap_limit = N ** ** Invoke sqlite3_hard_heap_limit64() to query or set the hard heap ** limit. The hard heap limit can be activated or lowered by this ** pragma, but not raised or deactivated. Only the ** sqlite3_hard_heap_limit64() C-language API can raise or deactivate ** the hard heap limit. This allows an application to set a heap limit ** constraint that cannot be relaxed by an untrusted SQL script. */ case PragTyp_HARD_HEAP_LIMIT: { sqlite3_int64 N; if( zRight && sqlite3DecOrHexToI64(zRight, &N)==SQLITE_OK ){ sqlite3_int64 iPrior = sqlite3_hard_heap_limit64(-1); if( N>0 && (iPrior==0 || iPrior>N) ) sqlite3_hard_heap_limit64(N); } returnSingleInt(v, sqlite3_hard_heap_limit64(-1)); break; } /* ** PRAGMA threads ** PRAGMA threads = N ** ** Configure the maximum number of worker threads. Return the new ** maximum, which might be less than requested. */ case PragTyp_THREADS: { sqlite3_int64 N; if( zRight && sqlite3DecOrHexToI64(zRight, &N)==SQLITE_OK && N>=0 ){ sqlite3_limit(db, SQLITE_LIMIT_WORKER_THREADS, (int)(N&0x7fffffff)); } returnSingleInt(v, sqlite3_limit(db, SQLITE_LIMIT_WORKER_THREADS, -1)); break; } /* ** PRAGMA analysis_limit ** PRAGMA analysis_limit = N ** ** Configure the maximum number of rows that ANALYZE will examine ** in each index that it looks at. Return the new limit. */ case PragTyp_ANALYSIS_LIMIT: { sqlite3_int64 N; if( zRight && sqlite3DecOrHexToI64(zRight, &N)==SQLITE_OK /* IMP: R-40975-20399 */ && N>=0 ){ db->nAnalysisLimit = (int)(N&0x7fffffff); } returnSingleInt(v, db->nAnalysisLimit); /* IMP: R-57594-65522 */ break; } #if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) /* ** Report the current state of file logs for all databases */ case PragTyp_LOCK_STATUS: { static const char *const azLockName[] = { |
︙ | ︙ | |||
2120 2121 2122 2123 2124 2125 2126 | } sqlite3VdbeMultiLoad(v, 1, "ss", db->aDb[i].zDbSName, zState); } break; } #endif | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < | 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 | } sqlite3VdbeMultiLoad(v, 1, "ss", db->aDb[i].zDbSName, zState); } break; } #endif #if defined(SQLITE_ENABLE_CEROD) case PragTyp_ACTIVATE_EXTENSIONS: if( zRight ){ if( sqlite3StrNICmp(zRight, "cerod-", 6)==0 ){ sqlite3_activate_cerod(&zRight[6]); } } break; #endif } /* End of the PRAGMA switch */ /* The following block is a no-op unless SQLITE_DEBUG is defined. Its only |
︙ | ︙ |
Changes to src/pragma.h.
1 2 3 4 5 6 7 | /* DO NOT EDIT! ** This file is automatically generated by the script at ** ../tool/mkpragmatab.tcl. To update the set of pragmas, edit ** that script and rerun it. */ /* The various pragma types */ | > > | | | | | | | | | | | | | | | | > | | | | | | | | | | | | | | | | | | | > | | | | | < < < | < | 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 | /* DO NOT EDIT! ** This file is automatically generated by the script at ** ../tool/mkpragmatab.tcl. To update the set of pragmas, edit ** that script and rerun it. */ /* The various pragma types */ #define PragTyp_ACTIVATE_EXTENSIONS 0 #define PragTyp_ANALYSIS_LIMIT 1 #define PragTyp_HEADER_VALUE 2 #define PragTyp_AUTO_VACUUM 3 #define PragTyp_FLAG 4 #define PragTyp_BUSY_TIMEOUT 5 #define PragTyp_CACHE_SIZE 6 #define PragTyp_CACHE_SPILL 7 #define PragTyp_CASE_SENSITIVE_LIKE 8 #define PragTyp_COLLATION_LIST 9 #define PragTyp_COMPILE_OPTIONS 10 #define PragTyp_DATA_STORE_DIRECTORY 11 #define PragTyp_DATABASE_LIST 12 #define PragTyp_DEFAULT_CACHE_SIZE 13 #define PragTyp_ENCODING 14 #define PragTyp_FOREIGN_KEY_CHECK 15 #define PragTyp_FOREIGN_KEY_LIST 16 #define PragTyp_FUNCTION_LIST 17 #define PragTyp_HARD_HEAP_LIMIT 18 #define PragTyp_INCREMENTAL_VACUUM 19 #define PragTyp_INDEX_INFO 20 #define PragTyp_INDEX_LIST 21 #define PragTyp_INTEGRITY_CHECK 22 #define PragTyp_JOURNAL_MODE 23 #define PragTyp_JOURNAL_SIZE_LIMIT 24 #define PragTyp_LOCK_PROXY_FILE 25 #define PragTyp_LOCKING_MODE 26 #define PragTyp_PAGE_COUNT 27 #define PragTyp_MMAP_SIZE 28 #define PragTyp_MODULE_LIST 29 #define PragTyp_OPTIMIZE 30 #define PragTyp_PAGE_SIZE 31 #define PragTyp_PRAGMA_LIST 32 #define PragTyp_SECURE_DELETE 33 #define PragTyp_SHRINK_MEMORY 34 #define PragTyp_SOFT_HEAP_LIMIT 35 #define PragTyp_SYNCHRONOUS 36 #define PragTyp_TABLE_INFO 37 #define PragTyp_TABLE_LIST 38 #define PragTyp_TEMP_STORE 39 #define PragTyp_TEMP_STORE_DIRECTORY 40 #define PragTyp_THREADS 41 #define PragTyp_WAL_AUTOCHECKPOINT 42 #define PragTyp_WAL_CHECKPOINT 43 #define PragTyp_LOCK_STATUS 44 #define PragTyp_STATS 45 /* Property flags associated with various pragma. */ #define PragFlg_NeedSchema 0x01 /* Force schema load before running */ #define PragFlg_NoColumns 0x02 /* OP_ResultRow called with zero columns */ #define PragFlg_NoColumns1 0x04 /* zero columns if RHS argument is present */ #define PragFlg_ReadOnly 0x08 /* Read-only HEADER_VALUE */ |
︙ | ︙ | |||
79 80 81 82 83 84 85 | /* 9 */ "name", /* 10 */ "type", /* 11 */ "notnull", /* 12 */ "dflt_value", /* 13 */ "pk", /* 14 */ "hidden", /* table_info reuses 8 */ | | | | | | | | | | | | | | | | | | | | | < | | | | | | | | > > > > > > > > > > > | | | | | | > > > > > | 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 | /* 9 */ "name", /* 10 */ "type", /* 11 */ "notnull", /* 12 */ "dflt_value", /* 13 */ "pk", /* 14 */ "hidden", /* table_info reuses 8 */ /* 15 */ "schema", /* Used by: table_list */ /* 16 */ "name", /* 17 */ "type", /* 18 */ "ncol", /* 19 */ "wr", /* 20 */ "strict", /* 21 */ "seqno", /* Used by: index_xinfo */ /* 22 */ "cid", /* 23 */ "name", /* 24 */ "desc", /* 25 */ "coll", /* 26 */ "key", /* 27 */ "name", /* Used by: function_list */ /* 28 */ "builtin", /* 29 */ "type", /* 30 */ "enc", /* 31 */ "narg", /* 32 */ "flags", /* 33 */ "tbl", /* Used by: stats */ /* 34 */ "idx", /* 35 */ "wdth", /* 36 */ "hght", /* 37 */ "flgs", /* 38 */ "seq", /* Used by: index_list */ /* 39 */ "name", /* 40 */ "unique", /* 41 */ "origin", /* 42 */ "partial", /* 43 */ "table", /* Used by: foreign_key_check */ /* 44 */ "rowid", /* 45 */ "parent", /* 46 */ "fkid", /* index_info reuses 21 */ /* 47 */ "seq", /* Used by: database_list */ /* 48 */ "name", /* 49 */ "file", /* 50 */ "busy", /* Used by: wal_checkpoint */ /* 51 */ "log", /* 52 */ "checkpointed", /* collation_list reuses 38 */ /* 53 */ "database", /* Used by: lock_status */ /* 54 */ "status", /* 55 */ "cache_size", /* Used by: default_cache_size */ /* module_list pragma_list reuses 9 */ /* 56 */ "timeout", /* Used by: busy_timeout */ }; /* Definitions of all built-in pragmas */ typedef struct PragmaName { const char *const zName; /* Name of pragma */ u8 ePragTyp; /* PragTyp_XXX value */ u8 mPragFlg; /* Zero or more PragFlg_XXX values */ u8 iPragCName; /* Start of column names in pragCName[] */ u8 nPragCName; /* Num of col names. 0 means use pragma name */ u64 iArg; /* Extra argument */ } PragmaName; static const PragmaName aPragmaName[] = { #if defined(SQLITE_ENABLE_CEROD) {/* zName: */ "activate_extensions", /* ePragTyp: */ PragTyp_ACTIVATE_EXTENSIONS, /* ePragFlg: */ 0, /* ColNames: */ 0, 0, /* iArg: */ 0 }, #endif {/* zName: */ "analysis_limit", /* ePragTyp: */ PragTyp_ANALYSIS_LIMIT, /* ePragFlg: */ PragFlg_Result0, /* ColNames: */ 0, 0, /* iArg: */ 0 }, #if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS) {/* zName: */ "application_id", /* ePragTyp: */ PragTyp_HEADER_VALUE, /* ePragFlg: */ PragFlg_NoColumns1|PragFlg_Result0, /* ColNames: */ 0, 0, /* iArg: */ BTREE_APPLICATION_ID }, #endif |
︙ | ︙ | |||
159 160 161 162 163 164 165 | /* ColNames: */ 0, 0, /* iArg: */ SQLITE_AutoIndex }, #endif #endif {/* zName: */ "busy_timeout", /* ePragTyp: */ PragTyp_BUSY_TIMEOUT, /* ePragFlg: */ PragFlg_Result0, | | > > | | 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 | /* ColNames: */ 0, 0, /* iArg: */ SQLITE_AutoIndex }, #endif #endif {/* zName: */ "busy_timeout", /* ePragTyp: */ PragTyp_BUSY_TIMEOUT, /* ePragFlg: */ PragFlg_Result0, /* ColNames: */ 56, 1, /* iArg: */ 0 }, #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) {/* zName: */ "cache_size", /* ePragTyp: */ PragTyp_CACHE_SIZE, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1, /* ColNames: */ 0, 0, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) {/* zName: */ "cache_spill", /* ePragTyp: */ PragTyp_CACHE_SPILL, /* ePragFlg: */ PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1, /* ColNames: */ 0, 0, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_CASE_SENSITIVE_LIKE_PRAGMA) {/* zName: */ "case_sensitive_like", /* ePragTyp: */ PragTyp_CASE_SENSITIVE_LIKE, /* ePragFlg: */ PragFlg_NoColumns, /* ColNames: */ 0, 0, /* iArg: */ 0 }, #endif {/* zName: */ "cell_size_check", /* ePragTyp: */ PragTyp_FLAG, /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, /* ColNames: */ 0, 0, /* iArg: */ SQLITE_CellSizeCk }, #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) {/* zName: */ "checkpoint_fullfsync", /* ePragTyp: */ PragTyp_FLAG, /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, /* ColNames: */ 0, 0, /* iArg: */ SQLITE_CkptFullFSync }, #endif #if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) {/* zName: */ "collation_list", /* ePragTyp: */ PragTyp_COLLATION_LIST, /* ePragFlg: */ PragFlg_Result0, /* ColNames: */ 38, 2, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_COMPILEOPTION_DIAGS) {/* zName: */ "compile_options", /* ePragTyp: */ PragTyp_COMPILE_OPTIONS, /* ePragFlg: */ PragFlg_Result0, /* ColNames: */ 0, 0, |
︙ | ︙ | |||
231 232 233 234 235 236 237 | /* ColNames: */ 0, 0, /* iArg: */ BTREE_DATA_VERSION }, #endif #if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) {/* zName: */ "database_list", /* ePragTyp: */ PragTyp_DATABASE_LIST, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0, | | | | 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 | /* ColNames: */ 0, 0, /* iArg: */ BTREE_DATA_VERSION }, #endif #if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) {/* zName: */ "database_list", /* ePragTyp: */ PragTyp_DATABASE_LIST, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0, /* ColNames: */ 47, 3, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && !defined(SQLITE_OMIT_DEPRECATED) {/* zName: */ "default_cache_size", /* ePragTyp: */ PragTyp_DEFAULT_CACHE_SIZE, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1, /* ColNames: */ 55, 1, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) #if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER) {/* zName: */ "defer_foreign_keys", /* ePragTyp: */ PragTyp_FLAG, /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, |
︙ | ︙ | |||
267 268 269 270 271 272 273 | /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, /* ColNames: */ 0, 0, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER) {/* zName: */ "foreign_key_check", /* ePragTyp: */ PragTyp_FOREIGN_KEY_CHECK, | | | | 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 | /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, /* ColNames: */ 0, 0, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER) {/* zName: */ "foreign_key_check", /* ePragTyp: */ PragTyp_FOREIGN_KEY_CHECK, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_Result1|PragFlg_SchemaOpt, /* ColNames: */ 43, 4, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_FOREIGN_KEY) {/* zName: */ "foreign_key_list", /* ePragTyp: */ PragTyp_FOREIGN_KEY_LIST, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt, /* ColNames: */ 0, 8, |
︙ | ︙ | |||
307 308 309 310 311 312 313 | {/* zName: */ "fullfsync", /* ePragTyp: */ PragTyp_FLAG, /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, /* ColNames: */ 0, 0, /* iArg: */ SQLITE_FullFSync }, #endif #if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) | | | < < < < < < | | | | < | | | | < < < < < < < < < < < < | | 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 | {/* zName: */ "fullfsync", /* ePragTyp: */ PragTyp_FLAG, /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, /* ColNames: */ 0, 0, /* iArg: */ SQLITE_FullFSync }, #endif #if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) #if !defined(SQLITE_OMIT_INTROSPECTION_PRAGMAS) {/* zName: */ "function_list", /* ePragTyp: */ PragTyp_FUNCTION_LIST, /* ePragFlg: */ PragFlg_Result0, /* ColNames: */ 27, 6, /* iArg: */ 0 }, #endif #endif {/* zName: */ "hard_heap_limit", /* ePragTyp: */ PragTyp_HARD_HEAP_LIMIT, /* ePragFlg: */ PragFlg_Result0, /* ColNames: */ 0, 0, /* iArg: */ 0 }, #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) #if !defined(SQLITE_OMIT_CHECK) {/* zName: */ "ignore_check_constraints", /* ePragTyp: */ PragTyp_FLAG, /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, /* ColNames: */ 0, 0, /* iArg: */ SQLITE_IgnoreChecks }, #endif #endif #if !defined(SQLITE_OMIT_AUTOVACUUM) {/* zName: */ "incremental_vacuum", /* ePragTyp: */ PragTyp_INCREMENTAL_VACUUM, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_NoColumns, /* ColNames: */ 0, 0, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) {/* zName: */ "index_info", /* ePragTyp: */ PragTyp_INDEX_INFO, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt, /* ColNames: */ 21, 3, /* iArg: */ 0 }, {/* zName: */ "index_list", /* ePragTyp: */ PragTyp_INDEX_LIST, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt, /* ColNames: */ 38, 5, /* iArg: */ 0 }, {/* zName: */ "index_xinfo", /* ePragTyp: */ PragTyp_INDEX_INFO, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt, /* ColNames: */ 21, 6, /* iArg: */ 1 }, #endif #if !defined(SQLITE_OMIT_INTEGRITY_CHECK) {/* zName: */ "integrity_check", /* ePragTyp: */ PragTyp_INTEGRITY_CHECK, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_Result1|PragFlg_SchemaOpt, /* ColNames: */ 0, 0, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) {/* zName: */ "journal_mode", /* ePragTyp: */ PragTyp_JOURNAL_MODE, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq, /* ColNames: */ 0, 0, /* iArg: */ 0 }, {/* zName: */ "journal_size_limit", /* ePragTyp: */ PragTyp_JOURNAL_SIZE_LIMIT, /* ePragFlg: */ PragFlg_Result0|PragFlg_SchemaReq, /* ColNames: */ 0, 0, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) {/* zName: */ "legacy_alter_table", /* ePragTyp: */ PragTyp_FLAG, /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, /* ColNames: */ 0, 0, /* iArg: */ SQLITE_LegacyAlter }, #endif #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && SQLITE_ENABLE_LOCKING_STYLE {/* zName: */ "lock_proxy_file", /* ePragTyp: */ PragTyp_LOCK_PROXY_FILE, /* ePragFlg: */ PragFlg_NoColumns1, /* ColNames: */ 0, 0, /* iArg: */ 0 }, #endif #if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) {/* zName: */ "lock_status", /* ePragTyp: */ PragTyp_LOCK_STATUS, /* ePragFlg: */ PragFlg_Result0, /* ColNames: */ 53, 2, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) {/* zName: */ "locking_mode", /* ePragTyp: */ PragTyp_LOCKING_MODE, /* ePragFlg: */ PragFlg_Result0|PragFlg_SchemaReq, /* ColNames: */ 0, 0, |
︙ | ︙ | |||
431 432 433 434 435 436 437 | /* ePragTyp: */ PragTyp_MMAP_SIZE, /* ePragFlg: */ 0, /* ColNames: */ 0, 0, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) #if !defined(SQLITE_OMIT_VIRTUALTABLE) | | > > > > > > > > > > | | | | > | | < < < < < < < < < | 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 | /* ePragTyp: */ PragTyp_MMAP_SIZE, /* ePragFlg: */ 0, /* ColNames: */ 0, 0, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) #if !defined(SQLITE_OMIT_VIRTUALTABLE) #if !defined(SQLITE_OMIT_INTROSPECTION_PRAGMAS) {/* zName: */ "module_list", /* ePragTyp: */ PragTyp_MODULE_LIST, /* ePragFlg: */ PragFlg_Result0, /* ColNames: */ 9, 1, /* iArg: */ 0 }, #endif #endif #endif #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) #if defined(SQLITE_ENABLE_NOOP_UPDATE) {/* zName: */ "noop_update", /* ePragTyp: */ PragTyp_FLAG, /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, /* ColNames: */ 0, 0, /* iArg: */ SQLITE_NoopUpdate }, #endif #endif {/* zName: */ "optimize", /* ePragTyp: */ PragTyp_OPTIMIZE, /* ePragFlg: */ PragFlg_Result1|PragFlg_NeedSchema, /* ColNames: */ 0, 0, /* iArg: */ 0 }, #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) {/* zName: */ "page_count", /* ePragTyp: */ PragTyp_PAGE_COUNT, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq, /* ColNames: */ 0, 0, /* iArg: */ 0 }, {/* zName: */ "page_size", /* ePragTyp: */ PragTyp_PAGE_SIZE, /* ePragFlg: */ PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1, /* ColNames: */ 0, 0, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) #if defined(SQLITE_DEBUG) {/* zName: */ "parser_trace", /* ePragTyp: */ PragTyp_FLAG, /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, /* ColNames: */ 0, 0, /* iArg: */ SQLITE_ParserTrace }, #endif #endif #if !defined(SQLITE_OMIT_INTROSPECTION_PRAGMAS) {/* zName: */ "pragma_list", /* ePragTyp: */ PragTyp_PRAGMA_LIST, /* ePragFlg: */ PragFlg_Result0, /* ColNames: */ 9, 1, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) {/* zName: */ "query_only", /* ePragTyp: */ PragTyp_FLAG, /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, /* ColNames: */ 0, 0, /* iArg: */ SQLITE_QueryOnly }, #endif #if !defined(SQLITE_OMIT_INTEGRITY_CHECK) {/* zName: */ "quick_check", /* ePragTyp: */ PragTyp_INTEGRITY_CHECK, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_Result1|PragFlg_SchemaOpt, /* ColNames: */ 0, 0, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) {/* zName: */ "read_uncommitted", /* ePragTyp: */ PragTyp_FLAG, /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, /* ColNames: */ 0, 0, /* iArg: */ SQLITE_ReadUncommit }, {/* zName: */ "recursive_triggers", /* ePragTyp: */ PragTyp_FLAG, /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, /* ColNames: */ 0, 0, /* iArg: */ SQLITE_RecTriggers }, {/* zName: */ "reverse_unordered_selects", /* ePragTyp: */ PragTyp_FLAG, /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, /* ColNames: */ 0, 0, /* iArg: */ SQLITE_ReverseOrder }, #endif #if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS) |
︙ | ︙ | |||
555 556 557 558 559 560 561 | /* iArg: */ SQLITE_SqlTrace }, #endif #endif #if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) && defined(SQLITE_DEBUG) {/* zName: */ "stats", /* ePragTyp: */ PragTyp_STATS, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq, | | > > > > > < < < < < < < < < < < < > > > > > > > | 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 | /* iArg: */ SQLITE_SqlTrace }, #endif #endif #if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) && defined(SQLITE_DEBUG) {/* zName: */ "stats", /* ePragTyp: */ PragTyp_STATS, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq, /* ColNames: */ 33, 5, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) {/* zName: */ "synchronous", /* ePragTyp: */ PragTyp_SYNCHRONOUS, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1, /* ColNames: */ 0, 0, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) {/* zName: */ "table_info", /* ePragTyp: */ PragTyp_TABLE_INFO, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt, /* ColNames: */ 8, 6, /* iArg: */ 0 }, {/* zName: */ "table_list", /* ePragTyp: */ PragTyp_TABLE_LIST, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1, /* ColNames: */ 15, 6, /* iArg: */ 0 }, {/* zName: */ "table_xinfo", /* ePragTyp: */ PragTyp_TABLE_INFO, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt, /* ColNames: */ 8, 7, /* iArg: */ 1 }, #endif #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) {/* zName: */ "temp_store", /* ePragTyp: */ PragTyp_TEMP_STORE, /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, /* ColNames: */ 0, 0, /* iArg: */ 0 }, {/* zName: */ "temp_store_directory", /* ePragTyp: */ PragTyp_TEMP_STORE_DIRECTORY, /* ePragFlg: */ PragFlg_NoColumns1, /* ColNames: */ 0, 0, /* iArg: */ 0 }, #endif {/* zName: */ "threads", /* ePragTyp: */ PragTyp_THREADS, /* ePragFlg: */ PragFlg_Result0, /* ColNames: */ 0, 0, /* iArg: */ 0 }, #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) {/* zName: */ "trusted_schema", /* ePragTyp: */ PragTyp_FLAG, /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, /* ColNames: */ 0, 0, /* iArg: */ SQLITE_TrustedSchema }, #endif #if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS) {/* zName: */ "user_version", /* ePragTyp: */ PragTyp_HEADER_VALUE, /* ePragFlg: */ PragFlg_NoColumns1|PragFlg_Result0, /* ColNames: */ 0, 0, /* iArg: */ BTREE_USER_VERSION }, #endif |
︙ | ︙ | |||
651 652 653 654 655 656 657 | /* ePragTyp: */ PragTyp_WAL_AUTOCHECKPOINT, /* ePragFlg: */ 0, /* ColNames: */ 0, 0, /* iArg: */ 0 }, {/* zName: */ "wal_checkpoint", /* ePragTyp: */ PragTyp_WAL_CHECKPOINT, /* ePragFlg: */ PragFlg_NeedSchema, | | | | 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 | /* ePragTyp: */ PragTyp_WAL_AUTOCHECKPOINT, /* ePragFlg: */ 0, /* ColNames: */ 0, 0, /* iArg: */ 0 }, {/* zName: */ "wal_checkpoint", /* ePragTyp: */ PragTyp_WAL_CHECKPOINT, /* ePragFlg: */ PragFlg_NeedSchema, /* ColNames: */ 50, 3, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) {/* zName: */ "writable_schema", /* ePragTyp: */ PragTyp_FLAG, /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, /* ColNames: */ 0, 0, /* iArg: */ SQLITE_WriteSchema|SQLITE_NoSchemaError }, #endif }; /* Number of pragmas: 68 on by default, 78 total. */ |
Changes to src/prepare.c.
︙ | ︙ | |||
17 18 19 20 21 22 23 | /* ** Fill the InitData structure with an error message that indicates ** that the database is corrupt. */ static void corruptSchema( InitData *pData, /* Initialization context */ | | | > > > > > | > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > | > | | | | > > | < | | | > > > > > > > | > > > > > > > > | | | > | | | | > > | < | < | > | | > | | > | | > | > | | | > > | > | | 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 | /* ** Fill the InitData structure with an error message that indicates ** that the database is corrupt. */ static void corruptSchema( InitData *pData, /* Initialization context */ char **azObj, /* Type and name of object being parsed */ const char *zExtra /* Error information */ ){ sqlite3 *db = pData->db; if( db->mallocFailed ){ pData->rc = SQLITE_NOMEM_BKPT; }else if( pData->pzErrMsg[0]!=0 ){ /* A error message has already been generated. Do not overwrite it */ }else if( pData->mInitFlags & (INITFLAG_AlterMask) ){ static const char *azAlterType[] = { "rename", "drop column", "add column" }; *pData->pzErrMsg = sqlite3MPrintf(db, "error in %s %s after %s: %s", azObj[0], azObj[1], azAlterType[(pData->mInitFlags&INITFLAG_AlterMask)-1], zExtra ); pData->rc = SQLITE_ERROR; }else if( db->flags & SQLITE_WriteSchema ){ pData->rc = SQLITE_CORRUPT_BKPT; }else{ char *z; const char *zObj = azObj[1] ? azObj[1] : "?"; z = sqlite3MPrintf(db, "malformed database schema (%s)", zObj); if( zExtra && zExtra[0] ) z = sqlite3MPrintf(db, "%z - %s", z, zExtra); *pData->pzErrMsg = z; pData->rc = SQLITE_CORRUPT_BKPT; } } /* ** Check to see if any sibling index (another index on the same table) ** of pIndex has the same root page number, and if it does, return true. ** This would indicate a corrupt schema. */ int sqlite3IndexHasDuplicateRootPage(Index *pIndex){ Index *p; for(p=pIndex->pTable->pIndex; p; p=p->pNext){ if( p->tnum==pIndex->tnum && p!=pIndex ) return 1; } return 0; } /* forward declaration */ static int sqlite3Prepare( sqlite3 *db, /* Database handle. */ const char *zSql, /* UTF-8 encoded SQL statement. */ int nBytes, /* Length of zSql in bytes. */ u32 prepFlags, /* Zero or more SQLITE_PREPARE_* flags */ Vdbe *pReprepare, /* VM being reprepared */ sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */ const char **pzTail /* OUT: End of parsed string */ ); /* ** This is the callback routine for the code that initializes the ** database. See sqlite3Init() below for additional information. ** This routine is also called from the OP_ParseSchema opcode of the VDBE. ** ** Each callback contains the following information: ** ** argv[0] = type of object: "table", "index", "trigger", or "view". ** argv[1] = name of thing being created ** argv[2] = associated table if an index or trigger ** argv[3] = root page number for table or index. 0 for trigger or view. ** argv[4] = SQL text for the CREATE statement. ** */ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){ InitData *pData = (InitData*)pInit; sqlite3 *db = pData->db; int iDb = pData->iDb; assert( argc==5 ); UNUSED_PARAMETER2(NotUsed, argc); assert( sqlite3_mutex_held(db->mutex) ); db->mDbFlags |= DBFLAG_EncodingFixed; if( argv==0 ) return 0; /* Might happen if EMPTY_RESULT_CALLBACKS are on */ pData->nInitRow++; if( db->mallocFailed ){ corruptSchema(pData, argv, 0); return 1; } assert( iDb>=0 && iDb<db->nDb ); if( argv[3]==0 ){ corruptSchema(pData, argv, 0); }else if( argv[4] && 'c'==sqlite3UpperToLower[(unsigned char)argv[4][0]] && 'r'==sqlite3UpperToLower[(unsigned char)argv[4][1]] ){ /* Call the parser to process a CREATE TABLE, INDEX or VIEW. ** But because db->init.busy is set to 1, no VDBE code is generated ** or executed. All the parser does is build the internal data ** structures that describe the table, index, or view. ** ** No other valid SQL statement, other than the variable CREATE statements, ** can begin with the letters "C" and "R". Thus, it is not possible run ** any other kind of statement while parsing the schema, even a corrupt ** schema. */ int rc; u8 saved_iDb = db->init.iDb; sqlite3_stmt *pStmt; TESTONLY(int rcp); /* Return code from sqlite3_prepare() */ assert( db->init.busy ); db->init.iDb = iDb; if( sqlite3GetUInt32(argv[3], &db->init.newTnum)==0 || (db->init.newTnum>pData->mxPage && pData->mxPage>0) ){ if( sqlite3Config.bExtraSchemaChecks ){ corruptSchema(pData, argv, "invalid rootpage"); } } db->init.orphanTrigger = 0; db->init.azInit = (const char**)argv; pStmt = 0; TESTONLY(rcp = ) sqlite3Prepare(db, argv[4], -1, 0, 0, &pStmt, 0); rc = db->errCode; assert( (rc&0xFF)==(rcp&0xFF) ); db->init.iDb = saved_iDb; /* assert( saved_iDb==0 || (db->mDbFlags & DBFLAG_Vacuum)!=0 ); */ if( SQLITE_OK!=rc ){ if( db->init.orphanTrigger ){ assert( iDb==1 ); }else{ if( rc > pData->rc ) pData->rc = rc; if( rc==SQLITE_NOMEM ){ sqlite3OomFault(db); }else if( rc!=SQLITE_INTERRUPT && (rc&0xFF)!=SQLITE_LOCKED ){ corruptSchema(pData, argv, sqlite3_errmsg(db)); } } } db->init.azInit = sqlite3StdType; /* Any array of string ptrs will do */ sqlite3_finalize(pStmt); }else if( argv[1]==0 || (argv[4]!=0 && argv[4][0]!=0) ){ corruptSchema(pData, argv, 0); }else{ /* If the SQL column is blank it means this is an index that ** was created to be the PRIMARY KEY or to fulfill a UNIQUE ** constraint for a CREATE TABLE. The index should have already ** been created when we processed the CREATE TABLE. All we have ** to do here is record the root page number for that index. */ Index *pIndex; pIndex = sqlite3FindIndex(db, argv[1], db->aDb[iDb].zDbSName); if( pIndex==0 ){ corruptSchema(pData, argv, "orphan index"); }else if( sqlite3GetUInt32(argv[3],&pIndex->tnum)==0 || pIndex->tnum<2 || pIndex->tnum>pData->mxPage || sqlite3IndexHasDuplicateRootPage(pIndex) ){ if( sqlite3Config.bExtraSchemaChecks ){ corruptSchema(pData, argv, "invalid rootpage"); } } } return 0; } /* ** Attempt to read the database schema and initialize internal ** data structures for a single database file. The index of the ** database file is given by iDb. iDb==0 is used for the main ** database. iDb==1 should never be used. iDb>=2 is used for ** auxiliary databases. Return one of the SQLITE_ error codes to ** indicate success or failure. */ int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg, u32 mFlags){ int rc; int i; #ifndef SQLITE_OMIT_DEPRECATED int size; #endif Db *pDb; char const *azArg[6]; int meta[5]; InitData initData; const char *zSchemaTabName; int openedTransaction = 0; int mask = ((db->mDbFlags & DBFLAG_EncodingFixed) | ~DBFLAG_EncodingFixed); assert( (db->mDbFlags & DBFLAG_SchemaKnownOk)==0 ); 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) ); db->init.busy = 1; /* Construct the in-memory representation schema tables (sqlite_schema or ** sqlite_temp_schema) by invoking the parser directly. The appropriate ** table name will be inserted automatically by the parser so we can just ** use the abbreviation "x" here. The parser will also automatically tag ** the schema table as read-only. */ azArg[0] = "table"; azArg[1] = zSchemaTabName = SCHEMA_TABLE(iDb); azArg[2] = azArg[1]; azArg[3] = "1"; azArg[4] = "CREATE TABLE x(type text,name text,tbl_name text," "rootpage int,sql text)"; azArg[5] = 0; initData.db = db; initData.iDb = iDb; initData.rc = SQLITE_OK; initData.pzErrMsg = pzErrMsg; initData.mInitFlags = mFlags; initData.nInitRow = 0; initData.mxPage = 0; sqlite3InitCallback(&initData, 5, (char **)azArg, 0); db->mDbFlags &= mask; if( initData.rc ){ rc = initData.rc; goto error_out; } /* Create a cursor to hold the database open */ pDb = &db->aDb[iDb]; if( pDb->pBt==0 ){ assert( iDb==1 ); DbSetProperty(db, 1, DB_SchemaLoaded); rc = SQLITE_OK; goto error_out; } /* If there is not already a read-only (or read-write) transaction opened ** on the b-tree database, open one now. If a transaction is opened, it ** will be closed before this function returns. */ sqlite3BtreeEnter(pDb->pBt); if( sqlite3BtreeTxnState(pDb->pBt)==SQLITE_TXN_NONE ){ rc = sqlite3BtreeBeginTrans(pDb->pBt, 0, 0); if( rc!=SQLITE_OK ){ sqlite3SetString(pzErrMsg, db, sqlite3ErrStr(rc)); goto initone_error_out; } openedTransaction = 1; } |
︙ | ︙ | |||
232 233 234 235 236 237 238 | /* If opening a non-empty database, check the text encoding. For the ** main database, set sqlite3.enc to the encoding of the main database. ** For an attached db, it is an error if the encoding is not the same ** as sqlite3.enc. */ if( meta[BTREE_TEXT_ENCODING-1] ){ /* text encoding */ | | < > < | > | < < | 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 | /* If opening a non-empty database, check the text encoding. For the ** main database, set sqlite3.enc to the encoding of the main database. ** For an attached db, it is an error if the encoding is not the same ** as sqlite3.enc. */ if( meta[BTREE_TEXT_ENCODING-1] ){ /* text encoding */ if( iDb==0 && (db->mDbFlags & DBFLAG_EncodingFixed)==0 ){ u8 encoding; #ifndef SQLITE_OMIT_UTF16 /* If opening the main database, set ENC(db). */ encoding = (u8)meta[BTREE_TEXT_ENCODING-1] & 3; if( encoding==0 ) encoding = SQLITE_UTF8; #else encoding = SQLITE_UTF8; #endif sqlite3SetTextEncoding(db, encoding); }else{ /* If opening an attached database, the encoding much match ENC(db) */ if( (meta[BTREE_TEXT_ENCODING-1] & 3)!=ENC(db) ){ sqlite3SetString(pzErrMsg, db, "attached databases must use the same" " text encoding as main database"); rc = SQLITE_ERROR; goto initone_error_out; } } } pDb->pSchema->enc = ENC(db); if( pDb->pSchema->cache_size==0 ){ #ifndef SQLITE_OMIT_DEPRECATED size = sqlite3AbsInt32(meta[BTREE_DEFAULT_CACHE_SIZE-1]); if( size==0 ){ size = SQLITE_DEFAULT_CACHE_SIZE; } |
︙ | ︙ | |||
295 296 297 298 299 300 301 302 303 304 | if( iDb==0 && meta[BTREE_FILE_FORMAT-1]>=4 ){ db->flags &= ~(u64)SQLITE_LegacyFileFmt; } /* Read the schema information out of the schema tables */ assert( db->init.busy ); { char *zSql; zSql = sqlite3MPrintf(db, | > | | > > | | | | | | > > | | | 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 | if( iDb==0 && meta[BTREE_FILE_FORMAT-1]>=4 ){ db->flags &= ~(u64)SQLITE_LegacyFileFmt; } /* Read the schema information out of the schema tables */ assert( db->init.busy ); initData.mxPage = sqlite3BtreeLastPage(pDb->pBt); { char *zSql; zSql = sqlite3MPrintf(db, "SELECT*FROM\"%w\".%s ORDER BY rowid", db->aDb[iDb].zDbSName, zSchemaTabName); #ifndef SQLITE_OMIT_AUTHORIZATION { sqlite3_xauth xAuth; xAuth = db->xAuth; db->xAuth = 0; #endif rc = sqlite3_exec(db, zSql, sqlite3InitCallback, &initData, 0); #ifndef SQLITE_OMIT_AUTHORIZATION db->xAuth = xAuth; } #endif if( rc==SQLITE_OK ) rc = initData.rc; sqlite3DbFree(db, zSql); #ifndef SQLITE_OMIT_ANALYZE if( rc==SQLITE_OK ){ sqlite3AnalysisLoad(db, iDb); } #endif } assert( pDb == &(db->aDb[iDb]) ); if( db->mallocFailed ){ rc = SQLITE_NOMEM_BKPT; sqlite3ResetAllSchemasOfConnection(db); pDb = &db->aDb[iDb]; }else if( rc==SQLITE_OK || (db->flags&SQLITE_NoSchemaError)){ /* Hack: If the SQLITE_NoSchemaError flag is set, then consider ** the schema loaded, even if errors (other than OOM) occurred. In ** this situation the current sqlite3_prepare() operation will fail, ** but the following one will attempt to compile the supplied statement ** against whatever subset of the schema was loaded before the error ** occurred. ** ** The primary purpose of this is to allow access to the sqlite_schema ** table even when its contents have been corrupted. */ DbSetProperty(db, iDb, DB_SchemaLoaded); rc = SQLITE_OK; } /* Jump here for an error that occurs after successfully allocating ** curMain and calling sqlite3BtreeEnter(). For an error that occurs |
︙ | ︙ | |||
364 365 366 367 368 369 370 | /* ** Initialize all database files - the main database file, the file ** used to store temporary tables, and any additional database files ** created using ATTACH statements. Return a success code. If an ** error occurs, write an error message into *pzErrMsg. ** ** After a database is initialized, the DB_SchemaLoaded bit is set | | < | 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 | /* ** Initialize all database files - the main database file, the file ** used to store temporary tables, and any additional database files ** created using ATTACH statements. Return a success code. If an ** error occurs, write an error message into *pzErrMsg. ** ** After a database is initialized, the DB_SchemaLoaded bit is set ** bit is set in the flags field of the Db structure. */ int sqlite3Init(sqlite3 *db, char **pzErrMsg){ int i, rc; int commit_internal = !(db->mDbFlags&DBFLAG_SchemaChange); assert( sqlite3_mutex_held(db->mutex) ); assert( sqlite3BtreeHoldsMutex(db->aDb[0].pBt) ); |
︙ | ︙ | |||
437 438 439 440 441 442 443 | int openedTransaction = 0; /* True if a transaction is opened */ Btree *pBt = db->aDb[iDb].pBt; /* Btree database to read cookie from */ if( pBt==0 ) continue; /* If there is not already a read-only (or read-write) transaction opened ** on the b-tree database, open one now. If a transaction is opened, it ** will be closed immediately after reading the meta-value. */ | | > | 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 | int openedTransaction = 0; /* True if a transaction is opened */ Btree *pBt = db->aDb[iDb].pBt; /* Btree database to read cookie from */ if( pBt==0 ) continue; /* If there is not already a read-only (or read-write) transaction opened ** on the b-tree database, open one now. If a transaction is opened, it ** will be closed immediately after reading the meta-value. */ if( sqlite3BtreeTxnState(pBt)==SQLITE_TXN_NONE ){ rc = sqlite3BtreeBeginTrans(pBt, 0, 0); if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){ sqlite3OomFault(db); pParse->rc = SQLITE_NOMEM; } if( rc!=SQLITE_OK ) return; openedTransaction = 1; } /* Read the schema cookie from the database. If it does not match the ** value stored as part of the in-memory schema representation, |
︙ | ︙ | |||
471 472 473 474 475 476 477 | ** Convert a schema pointer into the iDb index that indicates ** which database file in db->aDb[] the schema refers to. ** ** If the same database is attached more than once, the first ** attached database is returned. */ int sqlite3SchemaToIndex(sqlite3 *db, Schema *pSchema){ | | | | | | > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | ** Convert a schema pointer into the iDb index that indicates ** which database file in db->aDb[] the schema refers to. ** ** If the same database is attached more than once, the first ** attached database is returned. */ int sqlite3SchemaToIndex(sqlite3 *db, Schema *pSchema){ int i = -32768; /* If pSchema is NULL, then return -32768. This happens when code in ** expr.c is trying to resolve a reference to a transient table (i.e. one ** created by a sub-select). In this case the return value of this ** function should never be used. ** ** We return -32768 instead of the more usual -1 simply because using ** -32768 as the incorrect index into db->aDb[] is much ** more likely to cause a segfault than -1 (of course there are assert() ** statements too, but it never hurts to play the odds) and ** -32768 will still fit into a 16-bit signed integer. */ assert( sqlite3_mutex_held(db->mutex) ); if( pSchema ){ for(i=0; 1; i++){ assert( i<db->nDb ); if( db->aDb[i].pSchema==pSchema ){ break; } } assert( i>=0 && i<db->nDb ); } return i; } /* ** Free all memory allocations in the pParse object */ void sqlite3ParserReset(Parse *pParse){ sqlite3 *db = pParse->db; while( pParse->pCleanup ){ ParseCleanup *pCleanup = pParse->pCleanup; pParse->pCleanup = pCleanup->pNext; pCleanup->xCleanup(db, pCleanup->pPtr); sqlite3DbFreeNN(db, pCleanup); } sqlite3DbFree(db, pParse->aLabel); if( pParse->pConstExpr ){ sqlite3ExprListDelete(db, pParse->pConstExpr); } if( db ){ assert( db->lookaside.bDisable >= pParse->disableLookaside ); db->lookaside.bDisable -= pParse->disableLookaside; db->lookaside.sz = db->lookaside.bDisable ? 0 : db->lookaside.szTrue; } pParse->disableLookaside = 0; } /* ** Add a new cleanup operation to a Parser. The cleanup should happen when ** the parser object is destroyed. But, beware: the cleanup might happen ** immediately. ** ** Use this mechanism for uncommon cleanups. There is a higher setup ** cost for this mechansim (an extra malloc), so it should not be used ** for common cleanups that happen on most calls. But for less ** common cleanups, we save a single NULL-pointer comparison in ** sqlite3ParserReset(), which reduces the total CPU cycle count. ** ** If a memory allocation error occurs, then the cleanup happens immediately. ** When either SQLITE_DEBUG or SQLITE_COVERAGE_TEST are defined, the ** pParse->earlyCleanup flag is set in that case. Calling code show verify ** that test cases exist for which this happens, to guard against possible ** use-after-free errors following an OOM. The preferred way to do this is ** to immediately follow the call to this routine with: ** ** testcase( pParse->earlyCleanup ); ** ** This routine returns a copy of its pPtr input (the third parameter) ** except if an early cleanup occurs, in which case it returns NULL. So ** another way to check for early cleanup is to check the return value. ** Or, stop using the pPtr parameter with this call and use only its ** return value thereafter. Something like this: ** ** pObj = sqlite3ParserAddCleanup(pParse, destructor, pObj); */ void *sqlite3ParserAddCleanup( Parse *pParse, /* Destroy when this Parser finishes */ void (*xCleanup)(sqlite3*,void*), /* The cleanup routine */ void *pPtr /* Pointer to object to be cleaned up */ ){ ParseCleanup *pCleanup = sqlite3DbMallocRaw(pParse->db, sizeof(*pCleanup)); if( pCleanup ){ pCleanup->pNext = pParse->pCleanup; pParse->pCleanup = pCleanup; pCleanup->pPtr = pPtr; pCleanup->xCleanup = xCleanup; }else{ xCleanup(pParse->db, pPtr); pPtr = 0; #if defined(SQLITE_DEBUG) || defined(SQLITE_COVERAGE_TEST) pParse->earlyCleanup = 1; #endif } return pPtr; } /* ** Compile the UTF-8 encoded SQL statement zSql into a statement handle. */ static int sqlite3Prepare( sqlite3 *db, /* Database handle. */ const char *zSql, /* UTF-8 encoded SQL statement. */ |
︙ | ︙ | |||
539 540 541 542 543 544 545 | assert( sqlite3_mutex_held(db->mutex) ); /* For a long-term use prepared statement avoid the use of ** lookaside memory. */ if( prepFlags & SQLITE_PREPARE_PERSISTENT ){ sParse.disableLookaside++; | | > | 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 | assert( sqlite3_mutex_held(db->mutex) ); /* For a long-term use prepared statement avoid the use of ** lookaside memory. */ if( prepFlags & SQLITE_PREPARE_PERSISTENT ){ sParse.disableLookaside++; DisableLookaside; } sParse.disableVtab = (prepFlags & SQLITE_PREPARE_NO_VTAB)!=0; /* Check to verify that it is possible to get a read lock on all ** database schemas. The inability to get a read lock indicates that ** some other database connection is holding a write-lock, which in ** turn means that the other connection has made uncommitted changes ** to the schema. ** |
︙ | ︙ | |||
565 566 567 568 569 570 571 | ** locks on the schema, we just need to make sure nobody else is ** holding them. ** ** Note that setting READ_UNCOMMITTED overrides most lock detection, ** but it does *not* override schema lock detection, so this all still ** works even if READ_UNCOMMITTED is set. */ | > | | | | | | | | | | > | 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 | ** locks on the schema, we just need to make sure nobody else is ** holding them. ** ** Note that setting READ_UNCOMMITTED overrides most lock detection, ** but it does *not* override schema lock detection, so this all still ** works even if READ_UNCOMMITTED is set. */ if( !db->noSharedCache ){ for(i=0; i<db->nDb; i++) { Btree *pBt = db->aDb[i].pBt; if( pBt ){ assert( sqlite3BtreeHoldsMutex(pBt) ); rc = sqlite3BtreeSchemaLocked(pBt); if( rc ){ const char *zDb = db->aDb[i].zDbSName; sqlite3ErrorWithMsg(db, rc, "database schema is locked: %s", zDb); testcase( db->flags & SQLITE_ReadUncommit ); goto end_prepare; } } } } sqlite3VtabUnlockList(db); sParse.db = db; |
︙ | ︙ | |||
605 606 607 608 609 610 611 | sParse.zTail = &zSql[nBytes]; } }else{ sqlite3RunParser(&sParse, zSql, &zErrMsg); } assert( 0==sParse.nQueryLoop ); | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | > > | | | > > | > > | | | | | | > > > > > > > | 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 | sParse.zTail = &zSql[nBytes]; } }else{ sqlite3RunParser(&sParse, zSql, &zErrMsg); } assert( 0==sParse.nQueryLoop ); if( pzTail ){ *pzTail = sParse.zTail; } if( db->init.busy==0 ){ sqlite3VdbeSetSql(sParse.pVdbe, zSql, (int)(sParse.zTail-zSql), prepFlags); } if( db->mallocFailed ){ sParse.rc = SQLITE_NOMEM_BKPT; sParse.checkSchema = 0; } if( sParse.rc!=SQLITE_OK && sParse.rc!=SQLITE_DONE ){ if( sParse.checkSchema ){ schemaIsValid(&sParse); } if( sParse.pVdbe ){ sqlite3VdbeFinalize(sParse.pVdbe); } assert( 0==(*ppStmt) ); rc = sParse.rc; if( zErrMsg ){ sqlite3ErrorWithMsg(db, rc, "%s", zErrMsg); sqlite3DbFree(db, zErrMsg); }else{ sqlite3Error(db, rc); } }else{ assert( zErrMsg==0 ); *ppStmt = (sqlite3_stmt*)sParse.pVdbe; rc = SQLITE_OK; sqlite3ErrorClear(db); } /* Delete any TriggerPrg structures allocated while parsing this statement. */ while( sParse.pTriggerPrg ){ TriggerPrg *pT = sParse.pTriggerPrg; sParse.pTriggerPrg = pT->pNext; sqlite3DbFree(db, pT); } |
︙ | ︙ | |||
701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 | rc = sqlite3Prepare(db, zSql, nBytes, prepFlags, pOld, ppStmt, pzTail); assert( rc==SQLITE_OK || *ppStmt==0 ); }while( rc==SQLITE_ERROR_RETRY || (rc==SQLITE_SCHEMA && (sqlite3ResetOneSchema(db,-1), cnt++)==0) ); sqlite3BtreeLeaveAll(db); rc = sqlite3ApiExit(db, rc); assert( (rc&db->errMask)==rc ); sqlite3_mutex_leave(db->mutex); return rc; } /* ** Rerun the compilation of a statement after a schema change. ** ** If the statement is successfully recompiled, return SQLITE_OK. Otherwise, ** if the statement cannot be recompiled because another connection has | > | | 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 | rc = sqlite3Prepare(db, zSql, nBytes, prepFlags, pOld, ppStmt, pzTail); assert( rc==SQLITE_OK || *ppStmt==0 ); }while( rc==SQLITE_ERROR_RETRY || (rc==SQLITE_SCHEMA && (sqlite3ResetOneSchema(db,-1), cnt++)==0) ); sqlite3BtreeLeaveAll(db); rc = sqlite3ApiExit(db, rc); assert( (rc&db->errMask)==rc ); db->busyHandler.nBusy = 0; sqlite3_mutex_leave(db->mutex); return rc; } /* ** Rerun the compilation of a statement after a schema change. ** ** If the statement is successfully recompiled, return SQLITE_OK. Otherwise, ** if the statement cannot be recompiled because another connection has ** locked the sqlite3_schema table, return SQLITE_LOCKED. If any other error ** occurs, return SQLITE_SCHEMA. */ int sqlite3Reprepare(Vdbe *p){ int rc; sqlite3_stmt *pNew; const char *zSql; sqlite3 *db; |
︙ | ︙ |
Changes to src/printf.c.
︙ | ︙ | |||
25 26 27 28 29 30 31 | #define etPERCENT 7 /* Percent symbol. %% */ #define etCHARX 8 /* Characters. %c */ /* The rest are extensions, not normally found in printf() */ #define etSQLESCAPE 9 /* Strings with '\'' doubled. %q */ #define etSQLESCAPE2 10 /* Strings with '\'' doubled and enclosed in '', NULL pointers replaced by SQL NULL. %Q */ #define etTOKEN 11 /* a pointer to a Token structure */ | | | 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | #define etPERCENT 7 /* Percent symbol. %% */ #define etCHARX 8 /* Characters. %c */ /* The rest are extensions, not normally found in printf() */ #define etSQLESCAPE 9 /* Strings with '\'' doubled. %q */ #define etSQLESCAPE2 10 /* Strings with '\'' doubled and enclosed in '', NULL pointers replaced by SQL NULL. %Q */ #define etTOKEN 11 /* a pointer to a Token structure */ #define etSRCITEM 12 /* a pointer to a SrcItem */ #define etPOINTER 13 /* The %p conversion */ #define etSQLESCAPE3 14 /* %w -> Strings with '\"' doubled */ #define etORDINAL 15 /* %r -> 1st, 2nd, 3rd, 4th, etc. English only */ #define etDECIMAL 16 /* %d or %u, but not %x, %o */ #define etINVALID 17 /* Any unrecognized conversion type */ |
︙ | ︙ | |||
91 92 93 94 95 96 97 | { 'i', 10, 1, etDECIMAL, 0, 0 }, { 'n', 0, 0, etSIZE, 0, 0 }, { '%', 0, 0, etPERCENT, 0, 0 }, { 'p', 16, 0, etPOINTER, 0, 1 }, /* All the rest are undocumented and are for internal use only */ { 'T', 0, 0, etTOKEN, 0, 0 }, | | > > > > > > > > > > > > | 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 | { 'i', 10, 1, etDECIMAL, 0, 0 }, { 'n', 0, 0, etSIZE, 0, 0 }, { '%', 0, 0, etPERCENT, 0, 0 }, { 'p', 16, 0, etPOINTER, 0, 1 }, /* All the rest are undocumented and are for internal use only */ { 'T', 0, 0, etTOKEN, 0, 0 }, { 'S', 0, 0, etSRCITEM, 0, 0 }, { 'r', 10, 1, etORDINAL, 0, 0 }, }; /* Notes: ** ** %S Takes a pointer to SrcItem. Shows name or database.name ** %!S Like %S but prefer the zName over the zAlias */ /* Floating point constants used for rounding */ static const double arRound[] = { 5.0e-01, 5.0e-02, 5.0e-03, 5.0e-04, 5.0e-05, 5.0e-06, 5.0e-07, 5.0e-08, 5.0e-09, 5.0e-10, }; /* ** If SQLITE_OMIT_FLOATING_POINT is defined, then none of the floating point ** conversions will work. */ #ifndef SQLITE_OMIT_FLOATING_POINT /* |
︙ | ︙ | |||
129 130 131 132 133 134 135 | return (char)digit; } #endif /* SQLITE_OMIT_FLOATING_POINT */ /* ** Set the StrAccum object to an error mode. */ | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | return (char)digit; } #endif /* SQLITE_OMIT_FLOATING_POINT */ /* ** Set the StrAccum object to an error mode. */ void sqlite3StrAccumSetError(StrAccum *p, u8 eError){ assert( eError==SQLITE_NOMEM || eError==SQLITE_TOOBIG ); p->accError = eError; if( p->mxAlloc ) sqlite3_str_reset(p); if( eError==SQLITE_TOOBIG ) sqlite3ErrorToParser(p->db, eError); } /* ** Extra argument values from a PrintfArguments object */ static sqlite3_int64 getIntArg(PrintfArguments *p){ if( p->nArg<=p->nUsed ) return 0; return sqlite3_value_int64(p->apArg[p->nUsed++]); } static double getDoubleArg(PrintfArguments *p){ if( p->nArg<=p->nUsed ) return 0.0; return sqlite3_value_double(p->apArg[p->nUsed++]); } static char *getTextArg(PrintfArguments *p){ if( p->nArg<=p->nUsed ) return 0; return (char*)sqlite3_value_text(p->apArg[p->nUsed++]); } /* ** Allocate memory for a temporary buffer needed for printf rendering. ** ** If the requested size of the temp buffer is larger than the size ** of the output buffer in pAccum, then cause an SQLITE_TOOBIG error. ** Do the size check before the memory allocation to prevent rogue ** SQL from requesting large allocations using the precision or width ** field of the printf() function. */ static char *printfTempBuf(sqlite3_str *pAccum, sqlite3_int64 n){ char *z; if( pAccum->accError ) return 0; if( n>pAccum->nAlloc && n>pAccum->mxAlloc ){ sqlite3StrAccumSetError(pAccum, SQLITE_TOOBIG); return 0; } z = sqlite3DbMallocRaw(pAccum->db, n); if( z==0 ){ sqlite3StrAccumSetError(pAccum, SQLITE_NOMEM); } return z; } /* ** On machines with a small stack size, you can redefine the ** SQLITE_PRINT_BUF_SIZE to be something smaller, if desired. */ #ifndef SQLITE_PRINT_BUF_SIZE # define SQLITE_PRINT_BUF_SIZE 70 #endif #define etBUFSIZE SQLITE_PRINT_BUF_SIZE /* Size of the output buffer */ /* ** Hard limit on the precision of floating-point conversions. */ #ifndef SQLITE_PRINTF_PRECISION_LIMIT # define SQLITE_FP_PRECISION_LIMIT 100000000 #endif /* ** Render a string given by "fmt" into the StrAccum object. */ void sqlite3_str_vappendf( sqlite3_str *pAccum, /* Accumulate results here */ const char *fmt, /* Format string */ va_list ap /* arguments */ |
︙ | ︙ | |||
233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 | sqlite3_str_append(pAccum, "%", 1); break; } /* Find out what flags are present */ flag_leftjustify = flag_prefix = cThousand = flag_alternateform = flag_altform2 = flag_zeropad = 0; done = 0; do{ switch( c ){ case '-': flag_leftjustify = 1; break; case '+': flag_prefix = '+'; break; case ' ': flag_prefix = ' '; break; case '#': flag_alternateform = 1; break; case '!': flag_altform2 = 1; break; case '0': flag_zeropad = 1; break; case ',': cThousand = ','; break; default: done = 1; break; } }while( !done && (c=(*++fmt))!=0 ); | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 | sqlite3_str_append(pAccum, "%", 1); break; } /* Find out what flags are present */ flag_leftjustify = flag_prefix = cThousand = flag_alternateform = flag_altform2 = flag_zeropad = 0; done = 0; width = 0; flag_long = 0; precision = -1; do{ switch( c ){ case '-': flag_leftjustify = 1; break; case '+': flag_prefix = '+'; break; case ' ': flag_prefix = ' '; break; case '#': flag_alternateform = 1; break; case '!': flag_altform2 = 1; break; case '0': flag_zeropad = 1; break; case ',': cThousand = ','; break; default: done = 1; break; case 'l': { flag_long = 1; c = *++fmt; if( c=='l' ){ c = *++fmt; flag_long = 2; } done = 1; break; } case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { unsigned wx = c - '0'; while( (c = *++fmt)>='0' && c<='9' ){ wx = wx*10 + c - '0'; } testcase( wx>0x7fffffff ); width = wx & 0x7fffffff; #ifdef SQLITE_PRINTF_PRECISION_LIMIT if( width>SQLITE_PRINTF_PRECISION_LIMIT ){ width = SQLITE_PRINTF_PRECISION_LIMIT; } #endif if( c!='.' && c!='l' ){ done = 1; }else{ fmt--; } break; } case '*': { if( bArgList ){ width = (int)getIntArg(pArgList); }else{ width = va_arg(ap,int); } if( width<0 ){ flag_leftjustify = 1; width = width >= -2147483647 ? -width : 0; } #ifdef SQLITE_PRINTF_PRECISION_LIMIT if( width>SQLITE_PRINTF_PRECISION_LIMIT ){ width = SQLITE_PRINTF_PRECISION_LIMIT; } #endif if( (c = fmt[1])!='.' && c!='l' ){ c = *++fmt; done = 1; } break; } case '.': { c = *++fmt; if( c=='*' ){ if( bArgList ){ precision = (int)getIntArg(pArgList); }else{ precision = va_arg(ap,int); } if( precision<0 ){ precision = precision >= -2147483647 ? -precision : -1; } c = *++fmt; }else{ unsigned px = 0; while( c>='0' && c<='9' ){ px = px*10 + c - '0'; c = *++fmt; } testcase( px>0x7fffffff ); precision = px & 0x7fffffff; } #ifdef SQLITE_PRINTF_PRECISION_LIMIT if( precision>SQLITE_PRINTF_PRECISION_LIMIT ){ precision = SQLITE_PRINTF_PRECISION_LIMIT; } #endif if( c=='l' ){ --fmt; }else{ done = 1; } break; } } }while( !done && (c=(*++fmt))!=0 ); /* Fetch the info entry for the field */ infop = &fmtinfo[0]; xtype = etINVALID; for(idx=0; idx<ArraySize(fmtinfo); idx++){ if( c==fmtinfo[idx].fmttype ){ infop = &fmtinfo[idx]; xtype = infop->type; |
︙ | ︙ | |||
345 346 347 348 349 350 351 352 353 354 355 | ** width The specified field width. This is ** always non-negative. Zero is the default. ** precision The specified precision. The default ** is -1. ** xtype The class of the conversion. ** infop Pointer to the appropriate info struct. */ switch( xtype ){ case etPOINTER: flag_long = sizeof(char*)==sizeof(i64) ? 2 : sizeof(char*)==sizeof(long int) ? 1 : 0; | > > | | | > | < | < | 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 | ** width The specified field width. This is ** always non-negative. Zero is the default. ** precision The specified precision. The default ** is -1. ** xtype The class of the conversion. ** infop Pointer to the appropriate info struct. */ assert( width>=0 ); assert( precision>=(-1) ); switch( xtype ){ case etPOINTER: flag_long = sizeof(char*)==sizeof(i64) ? 2 : sizeof(char*)==sizeof(long int) ? 1 : 0; /* no break */ deliberate_fall_through case etORDINAL: case etRADIX: cThousand = 0; /* no break */ deliberate_fall_through case etDECIMAL: if( infop->flags & FLAG_SIGNED ){ i64 v; if( bArgList ){ v = getIntArg(pArgList); }else if( flag_long ){ if( flag_long==2 ){ v = va_arg(ap,i64) ; }else{ v = va_arg(ap,long int); } }else{ v = va_arg(ap,int); } if( v<0 ){ testcase( v==SMALLEST_INT64 ); testcase( v==(-1) ); longvalue = ~v; longvalue++; prefix = '-'; }else{ longvalue = v; prefix = flag_prefix; } }else{ if( bArgList ){ |
︙ | ︙ | |||
401 402 403 404 405 406 407 | if( flag_zeropad && precision<width-(prefix!=0) ){ precision = width-(prefix!=0); } if( precision<etBUFSIZE-10-etBUFSIZE/3 ){ nOut = etBUFSIZE; zOut = buf; }else{ | > | > | | < < < | 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 | if( flag_zeropad && precision<width-(prefix!=0) ){ precision = width-(prefix!=0); } if( precision<etBUFSIZE-10-etBUFSIZE/3 ){ nOut = etBUFSIZE; zOut = buf; }else{ u64 n; n = (u64)precision + 10; if( cThousand ) n += precision/3; zOut = zExtra = printfTempBuf(pAccum, n); if( zOut==0 ) return; nOut = (int)n; } bufpt = &zOut[nOut-1]; if( xtype==etORDINAL ){ static const char zOrd[] = "thstndrd"; int x = (int)(longvalue % 10); if( x>=4 || (longvalue/10)%10==1 ){ |
︙ | ︙ | |||
467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 | }else{ realvalue = va_arg(ap,double); } #ifdef SQLITE_OMIT_FLOATING_POINT length = 0; #else if( precision<0 ) precision = 6; /* Set default precision */ if( realvalue<0.0 ){ realvalue = -realvalue; prefix = '-'; }else{ prefix = flag_prefix; } if( xtype==etGENERIC && precision>0 ) precision--; testcase( precision>0xfff ); | > > > > > | > > | > > > > > > > > | 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 | }else{ realvalue = va_arg(ap,double); } #ifdef SQLITE_OMIT_FLOATING_POINT length = 0; #else if( precision<0 ) precision = 6; /* Set default precision */ #ifdef SQLITE_FP_PRECISION_LIMIT if( precision>SQLITE_FP_PRECISION_LIMIT ){ precision = SQLITE_FP_PRECISION_LIMIT; } #endif if( realvalue<0.0 ){ realvalue = -realvalue; prefix = '-'; }else{ prefix = flag_prefix; } if( xtype==etGENERIC && precision>0 ) precision--; testcase( precision>0xfff ); idx = precision & 0xfff; rounder = arRound[idx%10]; while( idx>=10 ){ rounder *= 1.0e-10; idx -= 10; } if( xtype==etFLOAT ){ double rx = (double)realvalue; sqlite3_uint64 u; int ex; memcpy(&u, &rx, sizeof(u)); ex = -1023 + (int)((u>>52)&0x7ff); if( precision+(ex/3) < 15 ) rounder += realvalue*3e-16; realvalue += rounder; } /* Normalize realvalue to within 10.0 > realvalue >= 1.0 */ exp = 0; if( sqlite3IsNaN((double)realvalue) ){ bufpt = "NaN"; length = 3; break; } |
︙ | ︙ | |||
525 526 527 528 529 530 531 | flag_rtz = flag_altform2; } if( xtype==etEXP ){ e2 = 0; }else{ e2 = exp; } | > > | > | < | < < | 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 | flag_rtz = flag_altform2; } if( xtype==etEXP ){ e2 = 0; }else{ e2 = exp; } { i64 szBufNeeded; /* Size of a temporary buffer needed */ szBufNeeded = MAX(e2,0)+(i64)precision+(i64)width+15; if( szBufNeeded > etBUFSIZE ){ bufpt = zExtra = printfTempBuf(pAccum, szBufNeeded); if( bufpt==0 ) return; } } zOut = bufpt; nsd = 16 + flag_altform2*10; flag_dp = (precision>0 ?1:0) | flag_alternateform | flag_altform2; /* The sign in front of the number */ if( prefix ){ |
︙ | ︙ | |||
739 740 741 742 743 744 745 | if( bArgList ){ escarg = getTextArg(pArgList); }else{ escarg = va_arg(ap,char*); } isnull = escarg==0; if( isnull ) escarg = (xtype==etSQLESCAPE2 ? "NULL" : "(NULL)"); | | | | < < < | 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 | if( bArgList ){ escarg = getTextArg(pArgList); }else{ escarg = va_arg(ap,char*); } isnull = escarg==0; if( isnull ) escarg = (xtype==etSQLESCAPE2 ? "NULL" : "(NULL)"); /* For %q, %Q, and %w, the precision is the number of bytes (or ** characters if the ! flags is present) to use from the input. ** Because of the extra quoting characters inserted, the number ** of output characters may be larger than the precision. */ k = precision; for(i=n=0; k!=0 && (ch=escarg[i])!=0; i++, k--){ if( ch==q ) n++; if( flag_altform2 && (ch&0xc0)==0xc0 ){ while( (escarg[i+1]&0xc0)==0x80 ){ i++; } } } needQuote = !isnull && xtype==etSQLESCAPE2; n += i + 3; if( n>etBUFSIZE ){ bufpt = zExtra = printfTempBuf(pAccum, n); if( bufpt==0 ) return; }else{ bufpt = buf; } j = 0; if( needQuote ) bufpt[j++] = q; k = i; for(i=0; i<k; i++){ |
︙ | ︙ | |||
785 786 787 788 789 790 791 | assert( bArgList==0 ); if( pToken && pToken->n ){ sqlite3_str_append(pAccum, (const char*)pToken->z, pToken->n); } length = width = 0; break; } | | < < | | < < < > > > | | | | | > > > > > | 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 | assert( bArgList==0 ); if( pToken && pToken->n ){ sqlite3_str_append(pAccum, (const char*)pToken->z, pToken->n); } length = width = 0; break; } case etSRCITEM: { SrcItem *pItem; if( (pAccum->printfFlags & SQLITE_PRINTF_INTERNAL)==0 ) return; pItem = va_arg(ap, SrcItem*); assert( bArgList==0 ); if( pItem->zAlias && !flag_altform2 ){ sqlite3_str_appendall(pAccum, pItem->zAlias); }else if( pItem->zName ){ if( pItem->zDatabase ){ sqlite3_str_appendall(pAccum, pItem->zDatabase); sqlite3_str_append(pAccum, ".", 1); } sqlite3_str_appendall(pAccum, pItem->zName); }else if( pItem->zAlias ){ sqlite3_str_appendall(pAccum, pItem->zAlias); }else if( ALWAYS(pItem->pSelect) ){ sqlite3_str_appendf(pAccum, "SUBQUERY %u", pItem->pSelect->selId); } length = width = 0; break; } default: { assert( xtype==etINVALID ); return; } |
︙ | ︙ | |||
848 849 850 851 852 853 854 | assert( p->nChar+(i64)N >= p->nAlloc ); /* Only called if really needed */ if( p->accError ){ testcase(p->accError==SQLITE_TOOBIG); testcase(p->accError==SQLITE_NOMEM); return 0; } if( p->mxAlloc==0 ){ | < | | | | | | | 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 | assert( p->nChar+(i64)N >= p->nAlloc ); /* Only called if really needed */ if( p->accError ){ testcase(p->accError==SQLITE_TOOBIG); testcase(p->accError==SQLITE_NOMEM); return 0; } if( p->mxAlloc==0 ){ sqlite3StrAccumSetError(p, SQLITE_TOOBIG); return p->nAlloc - p->nChar - 1; }else{ char *zOld = isMalloced(p) ? p->zText : 0; i64 szNew = p->nChar; szNew += (sqlite3_int64)N + 1; if( szNew+p->nChar<=p->mxAlloc ){ /* Force exponential buffer size growth as long as it does not overflow, ** to avoid having to call this routine too often */ szNew += p->nChar; } if( szNew > p->mxAlloc ){ sqlite3_str_reset(p); sqlite3StrAccumSetError(p, SQLITE_TOOBIG); return 0; }else{ p->nAlloc = (int)szNew; } if( p->db ){ zNew = sqlite3DbRealloc(p->db, zOld, p->nAlloc); }else{ zNew = sqlite3Realloc(zOld, p->nAlloc); } if( zNew ){ assert( p->zText!=0 || p->nChar==0 ); if( !isMalloced(p) && p->nChar>0 ) memcpy(zNew, p->zText, p->nChar); p->zText = zNew; p->nAlloc = sqlite3DbMallocSize(p->db, zNew); p->printfFlags |= SQLITE_PRINTF_MALLOCED; }else{ sqlite3_str_reset(p); sqlite3StrAccumSetError(p, SQLITE_NOMEM); return 0; } } return N; } /* |
︙ | ︙ | |||
922 923 924 925 926 927 928 | ** Append N bytes of text from z to the StrAccum object. Increase the ** size of the memory allocation for StrAccum if necessary. */ void sqlite3_str_append(sqlite3_str *p, const char *z, int N){ assert( z!=0 || N==0 ); assert( p->zText!=0 || p->nChar==0 || p->accError ); assert( N>=0 ); | | | 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 | ** Append N bytes of text from z to the StrAccum object. Increase the ** size of the memory allocation for StrAccum if necessary. */ void sqlite3_str_append(sqlite3_str *p, const char *z, int N){ assert( z!=0 || N==0 ); assert( p->zText!=0 || p->nChar==0 || p->accError ); assert( N>=0 ); assert( p->accError==0 || p->nAlloc==0 || p->mxAlloc==0 ); if( p->nChar+N >= p->nAlloc ){ enlargeAndAppend(p,z,N); }else if( N ){ assert( p->zText ); p->nChar += N; memcpy(&p->zText[p->nChar-N], z, N); } |
︙ | ︙ | |||
953 954 955 956 957 958 959 | char *zText; assert( p->mxAlloc>0 && !isMalloced(p) ); zText = sqlite3DbMallocRaw(p->db, p->nChar+1 ); if( zText ){ memcpy(zText, p->zText, p->nChar+1); p->printfFlags |= SQLITE_PRINTF_MALLOCED; }else{ | | > > > > > > > > > > > > > > > > | 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 | char *zText; assert( p->mxAlloc>0 && !isMalloced(p) ); zText = sqlite3DbMallocRaw(p->db, p->nChar+1 ); if( zText ){ memcpy(zText, p->zText, p->nChar+1); p->printfFlags |= SQLITE_PRINTF_MALLOCED; }else{ sqlite3StrAccumSetError(p, SQLITE_NOMEM); } p->zText = zText; return zText; } char *sqlite3StrAccumFinish(StrAccum *p){ if( p->zText ){ p->zText[p->nChar] = 0; if( p->mxAlloc>0 && !isMalloced(p) ){ return strAccumFinishRealloc(p); } } return p->zText; } /* ** Use the content of the StrAccum passed as the second argument ** as the result of an SQL function. */ void sqlite3ResultStrAccum(sqlite3_context *pCtx, StrAccum *p){ if( p->accError ){ sqlite3_result_error_code(pCtx, p->accError); sqlite3_str_reset(p); }else if( isMalloced(p) ){ sqlite3_result_text(pCtx, p->zText, p->nChar, SQLITE_DYNAMIC); }else{ sqlite3_result_text(pCtx, "", 0, SQLITE_STATIC); sqlite3_str_reset(p); } } /* ** This singleton is an sqlite3_str object that is returned if ** sqlite3_malloc() fails to provide space for a real one. This ** sqlite3_str object accepts no new text and always returns ** an SQLITE_NOMEM error. */ |
︙ | ︙ | |||
1212 1213 1214 1215 1216 1217 1218 | ** A version of printf() that understands %lld. Used for debugging. ** The printf() built into some versions of windows does not understand %lld ** and segfaults if you give it a long long int. */ void sqlite3DebugPrintf(const char *zFormat, ...){ va_list ap; StrAccum acc; | | | 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 | ** A version of printf() that understands %lld. Used for debugging. ** The printf() built into some versions of windows does not understand %lld ** and segfaults if you give it a long long int. */ void sqlite3DebugPrintf(const char *zFormat, ...){ va_list ap; StrAccum acc; char zBuf[SQLITE_PRINT_BUF_SIZE*10]; sqlite3StrAccumInit(&acc, 0, zBuf, sizeof(zBuf), 0); va_start(ap,zFormat); sqlite3_str_vappendf(&acc, zFormat, ap); va_end(ap); sqlite3StrAccumFinish(&acc); #ifdef SQLITE_OS_TRACE_PROC { |
︙ | ︙ |
Changes to src/random.c.
︙ | ︙ | |||
72 73 74 75 76 77 78 79 80 81 82 | ** trying to do secure encryption or anything like that... ** ** Nothing in this file or anywhere else in SQLite does any kind of ** encryption. The RC4 algorithm is being used as a PRNG (pseudo-random ** number generator) not as an encryption device. */ if( !wsdPrng.isInit ){ int i; char k[256]; wsdPrng.j = 0; wsdPrng.i = 0; | > > > > | > | 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 | ** trying to do secure encryption or anything like that... ** ** Nothing in this file or anywhere else in SQLite does any kind of ** encryption. The RC4 algorithm is being used as a PRNG (pseudo-random ** number generator) not as an encryption device. */ if( !wsdPrng.isInit ){ sqlite3_vfs *pVfs = sqlite3_vfs_find(0); int i; char k[256]; wsdPrng.j = 0; wsdPrng.i = 0; if( NEVER(pVfs==0) ){ memset(k, 0, sizeof(k)); }else{ sqlite3OsRandomness(pVfs, 256, k); } for(i=0; i<256; i++){ wsdPrng.s[i] = (u8)i; } for(i=0; i<256; i++){ wsdPrng.j += wsdPrng.s[i] + k[i]; t = wsdPrng.s[wsdPrng.j]; wsdPrng.s[wsdPrng.j] = wsdPrng.s[i]; |
︙ | ︙ | |||
101 102 103 104 105 106 107 108 109 110 111 112 113 114 | wsdPrng.s[wsdPrng.i] = wsdPrng.s[wsdPrng.j]; wsdPrng.s[wsdPrng.j] = t; t += wsdPrng.s[wsdPrng.i]; *(zBuf++) = wsdPrng.s[t]; }while( --N ); sqlite3_mutex_leave(mutex); } #ifndef SQLITE_UNTESTABLE /* ** For testing purposes, we sometimes want to preserve the state of ** PRNG and restore the PRNG to its saved state at a later time, or ** to reset the PRNG to its initial state. These routines accomplish ** those tasks. | > > > > > > > > > > > > > > > > > > > > > > | 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 | wsdPrng.s[wsdPrng.i] = wsdPrng.s[wsdPrng.j]; wsdPrng.s[wsdPrng.j] = t; t += wsdPrng.s[wsdPrng.i]; *(zBuf++) = wsdPrng.s[t]; }while( --N ); sqlite3_mutex_leave(mutex); } /* ** Initialize a fast PRNG. A Fast PRNG is called "fast" because it does ** not need a mutex to operate, though it does use a mutex to initialize. ** The quality of the randomness is not as good as the global PRNG. */ void sqlite3FastPrngInit(FastPrng *pPrng){ sqlite3_randomness(sizeof(*pPrng), pPrng); pPrng->x |= 1; } /* ** Generate N bytes of pseudo-randomness using a FastPrng */ void sqlite3FastRandomness(FastPrng *pPrng, int N, void *P){ unsigned char *pOut = (unsigned char*)P; while( N-->0 ){ pPrng->x = ((pPrng->x)>>1) ^ ((1+~((pPrng->x)&1)) & 0xd0000001); pPrng->y = (pPrng->y)*1103515245 + 12345; *(pOut++) = (pPrng->x ^ pPrng->y) & 0xff; } } #ifndef SQLITE_UNTESTABLE /* ** For testing purposes, we sometimes want to preserve the state of ** PRNG and restore the PRNG to its saved state at a later time, or ** to reset the PRNG to its initial state. These routines accomplish ** those tasks. |
︙ | ︙ |
Changes to src/resolve.c.
︙ | ︙ | |||
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | ** ** This file contains routines used for walking the parser tree and ** resolve all identifiers by associating them with a particular ** table and column. */ #include "sqliteInt.h" /* ** Walk the expression tree pExpr and increase the aggregate function ** depth (the Expr.op2 field) by N on every TK_AGG_FUNCTION node. ** This needs to occur when copying a TK_AGG_FUNCTION node from an ** outer query into an inner subquery. ** ** incrAggFunctionDepth(pExpr,n) is the main routine. incrAggDepth(..) ** is a helper function - a callback for the tree walker. */ static int incrAggDepth(Walker *pWalker, Expr *pExpr){ if( pExpr->op==TK_AGG_FUNCTION ) pExpr->op2 += pWalker->u.n; return WRC_Continue; } static void incrAggFunctionDepth(Expr *pExpr, int N){ if( N>0 ){ | > > > > > > > | 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 | ** ** This file contains routines used for walking the parser tree and ** resolve all identifiers by associating them with a particular ** table and column. */ #include "sqliteInt.h" /* ** Magic table number to mean the EXCLUDED table in an UPSERT statement. */ #define EXCLUDED_TABLE_NUMBER 2 /* ** Walk the expression tree pExpr and increase the aggregate function ** depth (the Expr.op2 field) by N on every TK_AGG_FUNCTION node. ** This needs to occur when copying a TK_AGG_FUNCTION node from an ** outer query into an inner subquery. ** ** incrAggFunctionDepth(pExpr,n) is the main routine. incrAggDepth(..) ** is a helper function - a callback for the tree walker. ** ** See also the sqlite3WindowExtraAggFuncDepth() routine in window.c */ static int incrAggDepth(Walker *pWalker, Expr *pExpr){ if( pExpr->op==TK_AGG_FUNCTION ) pExpr->op2 += pWalker->u.n; return WRC_Continue; } static void incrAggFunctionDepth(Expr *pExpr, int N){ if( N>0 ){ |
︙ | ︙ | |||
59 60 61 62 63 64 65 | ** structures must be increased by the nSubquery amount. */ static void resolveAlias( Parse *pParse, /* Parsing context */ ExprList *pEList, /* A result set */ int iCol, /* A column in the result set. 0..pEList->nExpr-1 */ Expr *pExpr, /* Transform this into an alias to the result set */ | < > > | > | > > > > > > < | 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 | ** structures must be increased by the nSubquery amount. */ static void resolveAlias( Parse *pParse, /* Parsing context */ ExprList *pEList, /* A result set */ int iCol, /* A column in the result set. 0..pEList->nExpr-1 */ Expr *pExpr, /* Transform this into an alias to the result set */ int nSubquery /* Number of subqueries that the label is moving */ ){ Expr *pOrig; /* The iCol-th column of the result set */ Expr *pDup; /* Copy of pOrig */ sqlite3 *db; /* The database connection */ assert( iCol>=0 && iCol<pEList->nExpr ); pOrig = pEList->a[iCol].pExpr; assert( pOrig!=0 ); db = pParse->db; pDup = sqlite3ExprDup(db, pOrig, 0); if( db->mallocFailed ){ sqlite3ExprDelete(db, pDup); pDup = 0; }else{ incrAggFunctionDepth(pDup, nSubquery); if( pExpr->op==TK_COLLATE ){ assert( !ExprHasProperty(pExpr, EP_IntValue) ); pDup = sqlite3ExprAddCollateString(pParse, pDup, pExpr->u.zToken); } /* Before calling sqlite3ExprDelete(), set the EP_Static flag. This ** prevents ExprDelete() from deleting the Expr structure itself, ** allowing it to be repopulated by the memcpy() on the following line. ** The pExpr->u.zToken might point into memory that will be freed by the ** sqlite3DbFree(db, pDup) on the last line of this block, so be sure to ** make a copy of the token before doing the sqlite3DbFree(). */ ExprSetProperty(pExpr, EP_Static); sqlite3ExprDelete(db, pExpr); memcpy(pExpr, pDup, sizeof(*pExpr)); if( !ExprHasProperty(pExpr, EP_IntValue) && pExpr->u.zToken!=0 ){ assert( (pExpr->flags & (EP_Reduced|EP_TokenOnly))==0 ); pExpr->u.zToken = sqlite3DbStrDup(db, pExpr->u.zToken); pExpr->flags |= EP_MemToken; } if( ExprHasProperty(pExpr, EP_WinFunc) ){ if( ALWAYS(pExpr->y.pWin!=0) ){ pExpr->y.pWin->pOwner = pExpr; } } sqlite3DbFree(db, pDup); } } /* ** Return TRUE if the name zCol occurs anywhere in the USING clause. ** ** Return FALSE if the USING clause is NULL or if it does not contain |
︙ | ︙ | |||
121 122 123 124 125 126 127 | /* ** Subqueries stores the original database, table and column names for their ** result sets in ExprList.a[].zSpan, in the form "DATABASE.TABLE.COLUMN". ** Check to see if the zSpan given to this routine matches the zDb, zTab, ** and zCol. If any of zDb, zTab, and zCol are NULL then those fields will ** match anything. */ | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* ** Subqueries stores the original database, table and column names for their ** result sets in ExprList.a[].zSpan, in the form "DATABASE.TABLE.COLUMN". ** Check to see if the zSpan given to this routine matches the zDb, zTab, ** and zCol. If any of zDb, zTab, and zCol are NULL then those fields will ** match anything. */ int sqlite3MatchEName( const struct ExprList_item *pItem, const char *zCol, const char *zTab, const char *zDb ){ int n; const char *zSpan; if( pItem->eEName!=ENAME_TAB ) return 0; zSpan = pItem->zEName; for(n=0; ALWAYS(zSpan[n]) && zSpan[n]!='.'; n++){} if( zDb && (sqlite3StrNICmp(zSpan, zDb, n)!=0 || zDb[n]!=0) ){ return 0; } zSpan += n+1; for(n=0; ALWAYS(zSpan[n]) && zSpan[n]!='.'; n++){} if( zTab && (sqlite3StrNICmp(zSpan, zTab, n)!=0 || zTab[n]!=0) ){ return 0; } zSpan += n+1; if( zCol && sqlite3StrICmp(zSpan, zCol)!=0 ){ return 0; } return 1; } /* ** Return TRUE if the double-quoted string mis-feature should be supported. */ static int areDoubleQuotedStringsEnabled(sqlite3 *db, NameContext *pTopNC){ if( db->init.busy ) return 1; /* Always support for legacy schemas */ if( pTopNC->ncFlags & NC_IsDDL ){ /* Currently parsing a DDL statement */ if( sqlite3WritableSchema(db) && (db->flags & SQLITE_DqsDML)!=0 ){ return 1; } return (db->flags & SQLITE_DqsDDL)!=0; }else{ /* Currently parsing a DML statement */ return (db->flags & SQLITE_DqsDML)!=0; } } /* ** The argument is guaranteed to be a non-NULL Expr node of type TK_COLUMN. ** return the appropriate colUsed mask. */ Bitmask sqlite3ExprColUsed(Expr *pExpr){ int n; Table *pExTab; n = pExpr->iColumn; assert( ExprUseYTab(pExpr) ); pExTab = pExpr->y.pTab; assert( pExTab!=0 ); if( (pExTab->tabFlags & TF_HasGenerated)!=0 && (pExTab->aCol[n].colFlags & COLFLAG_GENERATED)!=0 ){ testcase( pExTab->nCol==BMS-1 ); testcase( pExTab->nCol==BMS ); return pExTab->nCol>=BMS ? ALLBITS : MASKBIT(pExTab->nCol)-1; }else{ testcase( n==BMS-1 ); testcase( n==BMS ); if( n>=BMS ) n = BMS-1; return ((Bitmask)1)<<n; } } /* ** Given the name of a column of the form X.Y.Z or Y.Z or just Z, look up ** that name in the set of source tables in pSrcList and make the pExpr ** expression node refer back to that source column. The following changes ** are made to pExpr: ** |
︙ | ︙ | |||
184 185 186 187 188 189 190 | Expr *pExpr /* Make this EXPR node point to the selected column */ ){ int i, j; /* Loop counters */ int cnt = 0; /* Number of matching column names */ int cntTab = 0; /* Number of matching table names */ int nSubquery = 0; /* How many levels of subquery */ sqlite3 *db = pParse->db; /* The database connection */ | | | | 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 | Expr *pExpr /* Make this EXPR node point to the selected column */ ){ int i, j; /* Loop counters */ int cnt = 0; /* Number of matching column names */ int cntTab = 0; /* Number of matching table names */ int nSubquery = 0; /* How many levels of subquery */ sqlite3 *db = pParse->db; /* The database connection */ SrcItem *pItem; /* Use for looping over pSrcList items */ SrcItem *pMatch = 0; /* The matching pSrcList item */ NameContext *pTopNC = pNC; /* First namecontext in the list */ Schema *pSchema = 0; /* Schema of the expression */ int eNewExprOp = TK_COLUMN; /* New value for pExpr->op on success */ Table *pTab = 0; /* Table hold the row */ Column *pCol; /* A column of pTab */ assert( pNC ); /* the name context cannot be NULL. */ |
︙ | ︙ | |||
221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 | for(i=0; i<db->nDb; i++){ assert( db->aDb[i].zDbSName ); if( sqlite3StrICmp(db->aDb[i].zDbSName,zDb)==0 ){ pSchema = db->aDb[i].pSchema; break; } } } } /* Start at the inner-most context and move outward until a match is found */ assert( pNC && cnt==0 ); do{ ExprList *pEList; SrcList *pSrcList = pNC->pSrcList; if( pSrcList ){ for(i=0, pItem=pSrcList->a; i<pSrcList->nSrc; i++, pItem++){ pTab = pItem->pTab; assert( pTab!=0 && pTab->zName!=0 ); | > > > > > > > | | > < | < > | > > > > > > | > | > > > > > > > | | | | > > | > > | > | > < > > > > > > > > > | | | | | | | | | | | < < < > | | | > | < | > | > | | > > > > > > | | 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 | for(i=0; i<db->nDb; i++){ assert( db->aDb[i].zDbSName ); if( sqlite3StrICmp(db->aDb[i].zDbSName,zDb)==0 ){ pSchema = db->aDb[i].pSchema; break; } } if( i==db->nDb && sqlite3StrICmp("main", zDb)==0 ){ /* This branch is taken when the main database has been renamed ** using SQLITE_DBCONFIG_MAINDBNAME. */ pSchema = db->aDb[0].pSchema; zDb = db->aDb[0].zDbSName; } } } /* Start at the inner-most context and move outward until a match is found */ assert( pNC && cnt==0 ); do{ ExprList *pEList; SrcList *pSrcList = pNC->pSrcList; if( pSrcList ){ for(i=0, pItem=pSrcList->a; i<pSrcList->nSrc; i++, pItem++){ u8 hCol; pTab = pItem->pTab; assert( pTab!=0 && pTab->zName!=0 ); assert( pTab->nCol>0 || pParse->nErr ); if( pItem->pSelect && (pItem->pSelect->selFlags & SF_NestedFrom)!=0 ){ int hit = 0; pEList = pItem->pSelect->pEList; for(j=0; j<pEList->nExpr; j++){ if( sqlite3MatchEName(&pEList->a[j], zCol, zTab, zDb) ){ cnt++; cntTab = 2; pMatch = pItem; pExpr->iColumn = j; hit = 1; } } if( hit || zTab==0 ) continue; } if( zDb && pTab->pSchema!=pSchema ){ continue; } if( zTab ){ const char *zTabName = pItem->zAlias ? pItem->zAlias : pTab->zName; assert( zTabName!=0 ); if( sqlite3StrICmp(zTabName, zTab)!=0 ){ continue; } assert( ExprUseYTab(pExpr) ); if( IN_RENAME_OBJECT && pItem->zAlias ){ sqlite3RenameTokenRemap(pParse, 0, (void*)&pExpr->y.pTab); } } hCol = sqlite3StrIHash(zCol); for(j=0, pCol=pTab->aCol; j<pTab->nCol; j++, pCol++){ if( pCol->hName==hCol && sqlite3StrICmp(pCol->zCnName, zCol)==0 ){ /* If there has been exactly one prior match and this match ** is for the right-hand table of a NATURAL JOIN or is in a ** USING clause, then skip this match. */ if( cnt==1 ){ if( pItem->fg.jointype & JT_NATURAL ) continue; if( nameInUsingClause(pItem->pUsing, zCol) ) continue; } cnt++; pMatch = pItem; /* Substitute the rowid (column -1) for the INTEGER PRIMARY KEY */ pExpr->iColumn = j==pTab->iPKey ? -1 : (i16)j; break; } } if( 0==cnt && VisibleRowid(pTab) ){ cntTab++; pMatch = pItem; } } if( pMatch ){ pExpr->iTable = pMatch->iCursor; assert( ExprUseYTab(pExpr) ); pExpr->y.pTab = pMatch->pTab; /* RIGHT JOIN not (yet) supported */ assert( (pMatch->fg.jointype & JT_RIGHT)==0 ); if( (pMatch->fg.jointype & JT_LEFT)!=0 ){ ExprSetProperty(pExpr, EP_CanBeNull); } pSchema = pExpr->y.pTab->pSchema; } } /* if( pSrcList ) */ #if !defined(SQLITE_OMIT_TRIGGER) || !defined(SQLITE_OMIT_UPSERT) /* If we have not already resolved the name, then maybe ** it is a new.* or old.* trigger argument reference. Or ** maybe it is an excluded.* from an upsert. Or maybe it is ** a reference in the RETURNING clause to a table being modified. */ if( cnt==0 && zDb==0 ){ pTab = 0; #ifndef SQLITE_OMIT_TRIGGER if( pParse->pTriggerTab!=0 ){ int op = pParse->eTriggerOp; assert( op==TK_DELETE || op==TK_UPDATE || op==TK_INSERT ); if( pParse->bReturning ){ if( (pNC->ncFlags & NC_UBaseReg)!=0 && (zTab==0 || sqlite3StrICmp(zTab,pParse->pTriggerTab->zName)==0) ){ pExpr->iTable = op!=TK_DELETE; pTab = pParse->pTriggerTab; } }else if( op!=TK_DELETE && zTab && sqlite3StrICmp("new",zTab) == 0 ){ pExpr->iTable = 1; pTab = pParse->pTriggerTab; }else if( op!=TK_INSERT && zTab && sqlite3StrICmp("old",zTab)==0 ){ pExpr->iTable = 0; pTab = pParse->pTriggerTab; } } #endif /* SQLITE_OMIT_TRIGGER */ #ifndef SQLITE_OMIT_UPSERT if( (pNC->ncFlags & NC_UUpsert)!=0 && zTab!=0 ){ Upsert *pUpsert = pNC->uNC.pUpsert; if( pUpsert && sqlite3StrICmp("excluded",zTab)==0 ){ pTab = pUpsert->pUpsertSrc->a[0].pTab; pExpr->iTable = EXCLUDED_TABLE_NUMBER; } } #endif /* SQLITE_OMIT_UPSERT */ if( pTab ){ int iCol; u8 hCol = sqlite3StrIHash(zCol); pSchema = pTab->pSchema; cntTab++; for(iCol=0, pCol=pTab->aCol; iCol<pTab->nCol; iCol++, pCol++){ if( pCol->hName==hCol && sqlite3StrICmp(pCol->zCnName, zCol)==0 ){ if( iCol==pTab->iPKey ){ iCol = -1; } break; } } if( iCol>=pTab->nCol && sqlite3IsRowid(zCol) && VisibleRowid(pTab) ){ /* IMP: R-51414-32910 */ iCol = -1; } if( iCol<pTab->nCol ){ cnt++; pMatch = 0; #ifndef SQLITE_OMIT_UPSERT if( pExpr->iTable==EXCLUDED_TABLE_NUMBER ){ testcase( iCol==(-1) ); assert( ExprUseYTab(pExpr) ); if( IN_RENAME_OBJECT ){ pExpr->iColumn = iCol; pExpr->y.pTab = pTab; eNewExprOp = TK_COLUMN; }else{ pExpr->iTable = pNC->uNC.pUpsert->regData + sqlite3TableColumnToStorage(pTab, iCol); eNewExprOp = TK_REGISTER; } }else #endif /* SQLITE_OMIT_UPSERT */ { assert( ExprUseYTab(pExpr) ); pExpr->y.pTab = pTab; if( pParse->bReturning ){ eNewExprOp = TK_REGISTER; pExpr->iTable = pNC->uNC.iBaseReg + (pTab->nCol+1)*pExpr->iTable + sqlite3TableColumnToStorage(pTab, iCol) + 1; }else{ pExpr->iColumn = (i16)iCol; eNewExprOp = TK_TRIGGER; #ifndef SQLITE_OMIT_TRIGGER if( iCol<0 ){ pExpr->affExpr = SQLITE_AFF_INTEGER; }else if( pExpr->iTable==0 ){ testcase( iCol==31 ); testcase( iCol==32 ); pParse->oldmask |= (iCol>=32 ? 0xffffffff : (((u32)1)<<iCol)); }else{ testcase( iCol==31 ); testcase( iCol==32 ); pParse->newmask |= (iCol>=32 ? 0xffffffff : (((u32)1)<<iCol)); } #endif /* SQLITE_OMIT_TRIGGER */ } } } } } #endif /* !defined(SQLITE_OMIT_TRIGGER) || !defined(SQLITE_OMIT_UPSERT) */ /* ** Perhaps the name is a reference to the ROWID */ if( cnt==0 && cntTab==1 && pMatch && (pNC->ncFlags & (NC_IdxExpr|NC_GenCol))==0 && sqlite3IsRowid(zCol) && ALWAYS(VisibleRowid(pMatch->pTab)) ){ cnt = 1; pExpr->iColumn = -1; pExpr->affExpr = SQLITE_AFF_INTEGER; } /* ** If the input is of the form Z (not Y.Z or X.Y.Z) then the name Z ** might refer to an result-set alias. This happens, for example, when ** we are resolving names in the WHERE clause of the following command: ** ** 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. ** ** The ability to use an output result-set column in the WHERE, GROUP BY, ** or HAVING clauses, or as part of a larger expression in the ORDER BY ** clause is not standard SQL. This is a (goofy) SQLite extension, that ** is supported for backwards compatibility only. Hence, we issue a warning ** on sqlite3_log() whenever the capability is used. */ if( cnt==0 && (pNC->ncFlags & NC_UEList)!=0 && zTab==0 ){ pEList = pNC->uNC.pEList; assert( pEList!=0 ); for(j=0; j<pEList->nExpr; j++){ char *zAs = pEList->a[j].zEName; if( pEList->a[j].eEName==ENAME_NAME && sqlite3_stricmp(zAs, zCol)==0 ){ Expr *pOrig; assert( pExpr->pLeft==0 && pExpr->pRight==0 ); assert( ExprUseXList(pExpr)==0 || pExpr->x.pList==0 ); assert( ExprUseXSelect(pExpr)==0 || pExpr->x.pSelect==0 ); pOrig = pEList->a[j].pExpr; if( (pNC->ncFlags&NC_AllowAgg)==0 && ExprHasProperty(pOrig, EP_Agg) ){ sqlite3ErrorMsg(pParse, "misuse of aliased aggregate %s", zAs); return WRC_Abort; } if( ExprHasProperty(pOrig, EP_Win) && ((pNC->ncFlags&NC_AllowWin)==0 || pNC!=pTopNC ) ){ sqlite3ErrorMsg(pParse, "misuse of aliased window function %s",zAs); return WRC_Abort; } if( sqlite3ExprVectorSize(pOrig)!=1 ){ sqlite3ErrorMsg(pParse, "row value misused"); return WRC_Abort; } resolveAlias(pParse, pEList, j, pExpr, nSubquery); cnt = 1; pMatch = 0; assert( zTab==0 && zDb==0 ); if( IN_RENAME_OBJECT ){ sqlite3RenameTokenRemap(pParse, 0, (void*)pExpr); } goto lookupname_end; |
︙ | ︙ | |||
468 469 470 471 472 473 474 | ** pExpr. ** ** Because no reference was made to outer contexts, the pNC->nRef ** fields are not changed in any context. */ if( cnt==0 && zTab==0 ){ assert( pExpr->op==TK_ID ); | | > > | | 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 | ** pExpr. ** ** Because no reference was made to outer contexts, the pNC->nRef ** fields are not changed in any context. */ if( cnt==0 && zTab==0 ){ assert( pExpr->op==TK_ID ); if( ExprHasProperty(pExpr,EP_DblQuoted) && areDoubleQuotedStringsEnabled(db, pTopNC) ){ /* If a double-quoted identifier does not match any known column name, ** then treat it as a string. ** ** This hack was added in the early days of SQLite in a misguided attempt ** to be compatible with MySQL 3.x, which used double-quotes for strings. ** I now sorely regret putting in this hack. The effect of this hack is ** that misspelled identifier names are silently converted into strings ** rather than causing an error, to the frustration of countless ** programmers. To all those frustrated programmers, my apologies. ** ** Someday, I hope to get rid of this hack. Unfortunately there is ** a huge amount of legacy SQL that uses it. So for now, we just ** issue a warning. */ sqlite3_log(SQLITE_WARNING, "double-quoted string literal: \"%w\"", zCol); #ifdef SQLITE_ENABLE_NORMALIZE sqlite3VdbeAddDblquoteStr(db, pParse->pVdbe, zCol); #endif pExpr->op = TK_STRING; memset(&pExpr->y, 0, sizeof(pExpr->y)); return WRC_Prune; } if( sqlite3ExprIdToTrueFalse(pExpr) ){ return WRC_Prune; } } |
︙ | ︙ | |||
512 513 514 515 516 517 518 | sqlite3ErrorMsg(pParse, "%s: %s.%s.%s", zErr, zDb, zTab, zCol); }else if( zTab ){ sqlite3ErrorMsg(pParse, "%s: %s.%s", zErr, zTab, zCol); }else{ sqlite3ErrorMsg(pParse, "%s: %s", zErr, zCol); } pParse->checkSchema = 1; | | | > > > > > | > > > | < < < < < < | > | | | | > > | > > > | 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 | sqlite3ErrorMsg(pParse, "%s: %s.%s.%s", zErr, zDb, zTab, zCol); }else if( zTab ){ sqlite3ErrorMsg(pParse, "%s: %s.%s", zErr, zTab, zCol); }else{ sqlite3ErrorMsg(pParse, "%s: %s", zErr, zCol); } pParse->checkSchema = 1; pTopNC->nNcErr++; } /* If a column from a table in pSrcList is referenced, then record ** this fact in the pSrcList.a[].colUsed bitmask. Column 0 causes ** bit 0 to be set. Column 1 sets bit 1. And so forth. Bit 63 is ** set if the 63rd or any subsequent column is used. ** ** The colUsed mask is an optimization used to help determine if an ** index is a covering index. The correct answer is still obtained ** if the mask contains extra set bits. However, it is important to ** avoid setting bits beyond the maximum column number of the table. ** (See ticket [b92e5e8ec2cdbaa1]). ** ** If a generated column is referenced, set bits for every column ** of the table. */ if( pExpr->iColumn>=0 && pMatch!=0 ){ pMatch->colUsed |= sqlite3ExprColUsed(pExpr); } /* Clean up and return */ if( !ExprHasProperty(pExpr,(EP_TokenOnly|EP_Leaf)) ){ sqlite3ExprDelete(db, pExpr->pLeft); pExpr->pLeft = 0; sqlite3ExprDelete(db, pExpr->pRight); pExpr->pRight = 0; } pExpr->op = eNewExprOp; ExprSetProperty(pExpr, EP_Leaf); lookupname_end: if( cnt==1 ){ assert( pNC!=0 ); #ifndef SQLITE_OMIT_AUTHORIZATION if( pParse->db->xAuth && (pExpr->op==TK_COLUMN || pExpr->op==TK_TRIGGER) ){ sqlite3AuthRead(pParse, pExpr, pSchema, pNC->pSrcList); } #endif /* 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; |
︙ | ︙ | |||
566 567 568 569 570 571 572 | /* ** Allocate and return a pointer to an expression to load the column iCol ** from datasource iSrc in SrcList pSrc. */ Expr *sqlite3CreateColumnExpr(sqlite3 *db, SrcList *pSrc, int iSrc, int iCol){ Expr *p = sqlite3ExprAlloc(db, TK_COLUMN, 0, 0); if( p ){ | | > > | > > > > > > > | | | > > > > > > > > > > > > > | | | | < > < < | | | > > > | > | < > > > > | 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 | /* ** Allocate and return a pointer to an expression to load the column iCol ** from datasource iSrc in SrcList pSrc. */ Expr *sqlite3CreateColumnExpr(sqlite3 *db, SrcList *pSrc, int iSrc, int iCol){ Expr *p = sqlite3ExprAlloc(db, TK_COLUMN, 0, 0); if( p ){ SrcItem *pItem = &pSrc->a[iSrc]; Table *pTab; assert( ExprUseYTab(p) ); pTab = p->y.pTab = pItem->pTab; p->iTable = pItem->iCursor; if( p->y.pTab->iPKey==iCol ){ p->iColumn = -1; }else{ p->iColumn = (ynVar)iCol; if( (pTab->tabFlags & TF_HasGenerated)!=0 && (pTab->aCol[iCol].colFlags & COLFLAG_GENERATED)!=0 ){ testcase( pTab->nCol==63 ); testcase( pTab->nCol==64 ); pItem->colUsed = pTab->nCol>=64 ? ALLBITS : MASKBIT(pTab->nCol)-1; }else{ testcase( iCol==BMS ); testcase( iCol==BMS-1 ); pItem->colUsed |= ((Bitmask)1)<<(iCol>=BMS ? BMS-1 : iCol); } } } return p; } /* ** Report an error that an expression is not valid for some set of ** pNC->ncFlags values determined by validMask. ** ** static void notValid( ** Parse *pParse, // Leave error message here ** NameContext *pNC, // The name context ** const char *zMsg, // Type of error ** int validMask, // Set of contexts for which prohibited ** Expr *pExpr // Invalidate this expression on error ** ){...} ** ** As an optimization, since the conditional is almost always false ** (because errors are rare), the conditional is moved outside of the ** function call using a macro. */ static void notValidImpl( Parse *pParse, /* Leave error message here */ NameContext *pNC, /* The name context */ const char *zMsg, /* Type of error */ Expr *pExpr /* Invalidate this expression on error */ ){ const char *zIn = "partial index WHERE clauses"; if( pNC->ncFlags & NC_IdxExpr ) zIn = "index expressions"; #ifndef SQLITE_OMIT_CHECK else if( pNC->ncFlags & NC_IsCheck ) zIn = "CHECK constraints"; #endif #ifndef SQLITE_OMIT_GENERATED_COLUMNS else if( pNC->ncFlags & NC_GenCol ) zIn = "generated columns"; #endif sqlite3ErrorMsg(pParse, "%s prohibited in %s", zMsg, zIn); if( pExpr ) pExpr->op = TK_NULL; } #define sqlite3ResolveNotValid(P,N,M,X,E) \ assert( ((X)&~(NC_IsCheck|NC_PartIdx|NC_IdxExpr|NC_GenCol))==0 ); \ if( ((N)->ncFlags & (X))!=0 ) notValidImpl(P,N,M,E); /* ** Expression p should encode a floating point value between 1.0 and 0.0. ** Return 1024 times this value. Or return -1 if p is not a floating point ** value between 1.0 and 0.0. */ static int exprProbability(Expr *p){ double r = -1.0; if( p->op!=TK_FLOAT ) return -1; assert( !ExprHasProperty(p, EP_IntValue) ); sqlite3AtoF(p->u.zToken, &r, sqlite3Strlen30(p->u.zToken), SQLITE_UTF8); assert( r>=0.0 ); if( r>1.0 ) return -1; return (int)(r*134217728.0); } /* |
︙ | ︙ | |||
647 648 649 650 651 652 653 | for(i=0; i<pNC->pSrcList->nSrc; i++){ assert( pSrcList->a[i].iCursor>=0 && pSrcList->a[i].iCursor<pParse->nTab); } } #endif switch( pExpr->op ){ | < | > | | < > | | | > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > | > > > | | | | 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 | for(i=0; i<pNC->pSrcList->nSrc; i++){ assert( pSrcList->a[i].iCursor>=0 && pSrcList->a[i].iCursor<pParse->nTab); } } #endif switch( pExpr->op ){ /* The special operator TK_ROW means use the rowid for the first ** column in the FROM clause. This is used by the LIMIT and ORDER BY ** clause processing on UPDATE and DELETE statements, and by ** UPDATE ... FROM statement processing. */ case TK_ROW: { SrcList *pSrcList = pNC->pSrcList; SrcItem *pItem; assert( pSrcList && pSrcList->nSrc>=1 ); pItem = pSrcList->a; pExpr->op = TK_COLUMN; assert( ExprUseYTab(pExpr) ); pExpr->y.pTab = pItem->pTab; pExpr->iTable = pItem->iCursor; pExpr->iColumn--; pExpr->affExpr = SQLITE_AFF_INTEGER; break; } /* An optimization: Attempt to convert ** ** "expr IS NOT NULL" --> "TRUE" ** "expr IS NULL" --> "FALSE" ** ** if we can prove that "expr" is never NULL. Call this the ** "NOT NULL strength reduction optimization". ** ** If this optimization occurs, also restore the NameContext ref-counts ** to the state they where in before the "column" LHS expression was ** resolved. This prevents "column" from being counted as having been ** referenced, which might prevent a SELECT from being erroneously ** marked as correlated. */ case TK_NOTNULL: case TK_ISNULL: { int anRef[8]; NameContext *p; int i; for(i=0, p=pNC; p && i<ArraySize(anRef); p=p->pNext, i++){ anRef[i] = p->nRef; } sqlite3WalkExpr(pWalker, pExpr->pLeft); if( 0==sqlite3ExprCanBeNull(pExpr->pLeft) && !IN_RENAME_OBJECT ){ testcase( ExprHasProperty(pExpr, EP_FromJoin) ); assert( !ExprHasProperty(pExpr, EP_IntValue) ); if( pExpr->op==TK_NOTNULL ){ pExpr->u.zToken = "true"; ExprSetProperty(pExpr, EP_IsTrue); }else{ pExpr->u.zToken = "false"; ExprSetProperty(pExpr, EP_IsFalse); } pExpr->op = TK_TRUEFALSE; for(i=0, p=pNC; p && i<ArraySize(anRef); p=p->pNext, i++){ p->nRef = anRef[i]; } sqlite3ExprDelete(pParse->db, pExpr->pLeft); pExpr->pLeft = 0; } return WRC_Prune; } /* A column name: ID ** Or table name and column name: ID.ID ** Or a database, table and column: ID.ID.ID ** ** The TK_ID and TK_OUT cases are combined so that there will only ** be one call to lookupName(). Then the compiler will in-line ** lookupName() for a size reduction and performance increase. */ case TK_ID: case TK_DOT: { const char *zColumn; const char *zTable; const char *zDb; Expr *pRight; if( pExpr->op==TK_ID ){ zDb = 0; zTable = 0; assert( !ExprHasProperty(pExpr, EP_IntValue) ); zColumn = pExpr->u.zToken; }else{ Expr *pLeft = pExpr->pLeft; testcase( pNC->ncFlags & NC_IdxExpr ); testcase( pNC->ncFlags & NC_GenCol ); sqlite3ResolveNotValid(pParse, pNC, "the \".\" operator", NC_IdxExpr|NC_GenCol, 0); pRight = pExpr->pRight; if( pRight->op==TK_ID ){ zDb = 0; }else{ assert( pRight->op==TK_DOT ); assert( !ExprHasProperty(pRight, EP_IntValue) ); zDb = pLeft->u.zToken; pLeft = pRight->pLeft; pRight = pRight->pRight; } assert( ExprUseUToken(pLeft) && ExprUseUToken(pRight) ); zTable = pLeft->u.zToken; zColumn = pRight->u.zToken; assert( ExprUseYTab(pExpr) ); if( IN_RENAME_OBJECT ){ sqlite3RenameTokenRemap(pParse, (void*)pExpr, (void*)pRight); sqlite3RenameTokenRemap(pParse, (void*)&pExpr->y.pTab, (void*)pLeft); } } return lookupName(pParse, zDb, zTable, zColumn, pNC, pExpr); } /* Resolve function names */ case TK_FUNCTION: { ExprList *pList = pExpr->x.pList; /* The argument list */ int n = pList ? pList->nExpr : 0; /* Number of arguments */ int no_such_func = 0; /* True if no such function exists */ int wrong_num_args = 0; /* True if wrong number of arguments */ int is_agg = 0; /* True if is an aggregate function */ int nId; /* Number of characters in function name */ const char *zId; /* The function name. */ FuncDef *pDef; /* Information about the function */ u8 enc = ENC(pParse->db); /* The database encoding */ int savedAllowFlags = (pNC->ncFlags & (NC_AllowAgg | NC_AllowWin)); #ifndef SQLITE_OMIT_WINDOWFUNC Window *pWin = (IsWindowFunc(pExpr) ? pExpr->y.pWin : 0); #endif assert( !ExprHasProperty(pExpr, EP_xIsSelect|EP_IntValue) ); zId = pExpr->u.zToken; nId = sqlite3Strlen30(zId); pDef = sqlite3FindFunction(pParse->db, zId, n, enc, 0); if( pDef==0 ){ pDef = sqlite3FindFunction(pParse->db, zId, -2, enc, 0); if( pDef==0 ){ no_such_func = 1; }else{ wrong_num_args = 1; } }else{ is_agg = pDef->xFinalize!=0; if( pDef->funcFlags & SQLITE_FUNC_UNLIKELY ){ ExprSetProperty(pExpr, EP_Unlikely); if( n==2 ){ pExpr->iTable = exprProbability(pList->a[1].pExpr); if( pExpr->iTable<0 ){ sqlite3ErrorMsg(pParse, "second argument to likelihood() must be a " "constant between 0.0 and 1.0"); pNC->nNcErr++; } }else{ /* EVIDENCE-OF: R-61304-29449 The unlikely(X) function is ** equivalent to likelihood(X, 0.0625). ** EVIDENCE-OF: R-01283-11636 The unlikely(X) function is ** short-hand for likelihood(X,0.0625). ** EVIDENCE-OF: R-36850-34127 The likely(X) function is short-hand |
︙ | ︙ | |||
765 766 767 768 769 770 771 | #ifndef SQLITE_OMIT_AUTHORIZATION { int auth = sqlite3AuthCheck(pParse, SQLITE_FUNCTION, 0,pDef->zName,0); if( auth!=SQLITE_OK ){ if( auth==SQLITE_DENY ){ sqlite3ErrorMsg(pParse, "not authorized to use function: %s", pDef->zName); | | | > > | | > > | | > > > > | | > > > > > > > | | | | | | | | | > > > > > > > > > > > > | > > > > > | > > > > > | | | < < | < < < < | | > > > > > > | > > | | > > | > > | | | < | > > > > > | > | > > > > > | > | | | > | 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 | #ifndef SQLITE_OMIT_AUTHORIZATION { int auth = sqlite3AuthCheck(pParse, SQLITE_FUNCTION, 0,pDef->zName,0); if( auth!=SQLITE_OK ){ if( auth==SQLITE_DENY ){ sqlite3ErrorMsg(pParse, "not authorized to use function: %s", pDef->zName); pNC->nNcErr++; } pExpr->op = TK_NULL; return WRC_Prune; } } #endif if( pDef->funcFlags & (SQLITE_FUNC_CONSTANT|SQLITE_FUNC_SLOCHNG) ){ /* For the purposes of the EP_ConstFunc flag, date and time ** functions and other functions that change slowly are considered ** constant because they are constant for the duration of one query. ** This allows them to be factored out of inner loops. */ ExprSetProperty(pExpr,EP_ConstFunc); } if( (pDef->funcFlags & SQLITE_FUNC_CONSTANT)==0 ){ /* Clearly non-deterministic functions like random(), but also ** date/time functions that use 'now', and other functions like ** sqlite_version() that might change over time cannot be used ** in an index or generated column. Curiously, they can be used ** in a CHECK constraint. SQLServer, MySQL, and PostgreSQL all ** all this. */ sqlite3ResolveNotValid(pParse, pNC, "non-deterministic functions", NC_IdxExpr|NC_PartIdx|NC_GenCol, 0); }else{ assert( (NC_SelfRef & 0xff)==NC_SelfRef ); /* Must fit in 8 bits */ pExpr->op2 = pNC->ncFlags & NC_SelfRef; if( pNC->ncFlags & NC_FromDDL ) ExprSetProperty(pExpr, EP_FromDDL); } if( (pDef->funcFlags & SQLITE_FUNC_INTERNAL)!=0 && pParse->nested==0 && (pParse->db->mDbFlags & DBFLAG_InternalFunc)==0 ){ /* Internal-use-only functions are disallowed unless the ** SQL is being compiled using sqlite3NestedParse() or ** the SQLITE_TESTCTRL_INTERNAL_FUNCTIONS test-control has be ** used to activate internal functionsn for testing purposes */ no_such_func = 1; pDef = 0; }else if( (pDef->funcFlags & (SQLITE_FUNC_DIRECT|SQLITE_FUNC_UNSAFE))!=0 && !IN_RENAME_OBJECT ){ sqlite3ExprFunctionUsable(pParse, pExpr, pDef); } } if( 0==IN_RENAME_OBJECT ){ #ifndef SQLITE_OMIT_WINDOWFUNC assert( is_agg==0 || (pDef->funcFlags & SQLITE_FUNC_MINMAX) || (pDef->xValue==0 && pDef->xInverse==0) || (pDef->xValue && pDef->xInverse && pDef->xSFunc && pDef->xFinalize) ); if( pDef && pDef->xValue==0 && pWin ){ sqlite3ErrorMsg(pParse, "%.*s() may not be used as a window function", nId, zId ); pNC->nNcErr++; }else if( (is_agg && (pNC->ncFlags & NC_AllowAgg)==0) || (is_agg && (pDef->funcFlags&SQLITE_FUNC_WINDOW) && !pWin) || (is_agg && pWin && (pNC->ncFlags & NC_AllowWin)==0) ){ const char *zType; if( (pDef->funcFlags & SQLITE_FUNC_WINDOW) || pWin ){ zType = "window"; }else{ zType = "aggregate"; } sqlite3ErrorMsg(pParse, "misuse of %s function %.*s()",zType,nId,zId); pNC->nNcErr++; is_agg = 0; } #else if( (is_agg && (pNC->ncFlags & NC_AllowAgg)==0) ){ sqlite3ErrorMsg(pParse,"misuse of aggregate function %.*s()",nId,zId); pNC->nNcErr++; is_agg = 0; } #endif else if( no_such_func && pParse->db->init.busy==0 #ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION && pParse->explain==0 #endif ){ sqlite3ErrorMsg(pParse, "no such function: %.*s", nId, zId); pNC->nNcErr++; }else if( wrong_num_args ){ sqlite3ErrorMsg(pParse,"wrong number of arguments to function %.*s()", nId, zId); pNC->nNcErr++; } #ifndef SQLITE_OMIT_WINDOWFUNC else if( is_agg==0 && ExprHasProperty(pExpr, EP_WinFunc) ){ sqlite3ErrorMsg(pParse, "FILTER may not be used with non-aggregate %.*s()", nId, zId ); pNC->nNcErr++; } #endif if( is_agg ){ /* Window functions may not be arguments of aggregate functions. ** Or arguments of other window functions. But aggregate functions ** may be arguments for window functions. */ #ifndef SQLITE_OMIT_WINDOWFUNC pNC->ncFlags &= ~(NC_AllowWin | (!pWin ? NC_AllowAgg : 0)); #else pNC->ncFlags &= ~NC_AllowAgg; #endif } } #ifndef SQLITE_OMIT_WINDOWFUNC else if( ExprHasProperty(pExpr, EP_WinFunc) ){ is_agg = 1; } #endif sqlite3WalkExprList(pWalker, pList); if( is_agg ){ #ifndef SQLITE_OMIT_WINDOWFUNC if( pWin ){ Select *pSel = pNC->pWinSelect; assert( pWin==0 || (ExprUseYWin(pExpr) && pWin==pExpr->y.pWin) ); if( IN_RENAME_OBJECT==0 ){ sqlite3WindowUpdate(pParse, pSel ? pSel->pWinDefn : 0, pWin, pDef); if( pParse->db->mallocFailed ) break; } sqlite3WalkExprList(pWalker, pWin->pPartition); sqlite3WalkExprList(pWalker, pWin->pOrderBy); sqlite3WalkExpr(pWalker, pWin->pFilter); sqlite3WindowLink(pSel, pWin); pNC->ncFlags |= NC_HasWin; }else #endif /* SQLITE_OMIT_WINDOWFUNC */ { NameContext *pNC2; /* For looping up thru outer contexts */ pExpr->op = TK_AGG_FUNCTION; pExpr->op2 = 0; #ifndef SQLITE_OMIT_WINDOWFUNC if( ExprHasProperty(pExpr, EP_WinFunc) ){ sqlite3WalkExpr(pWalker, pExpr->y.pWin->pFilter); } #endif pNC2 = pNC; while( pNC2 && sqlite3ReferencesSrcList(pParse, pExpr, pNC2->pSrcList)==0 ){ pExpr->op2++; pNC2 = pNC2->pNext; } assert( pDef!=0 || IN_RENAME_OBJECT ); if( pNC2 && pDef ){ assert( SQLITE_FUNC_MINMAX==NC_MinMaxAgg ); assert( SQLITE_FUNC_ANYORDER==NC_OrderAgg ); testcase( (pDef->funcFlags & SQLITE_FUNC_MINMAX)!=0 ); testcase( (pDef->funcFlags & SQLITE_FUNC_ANYORDER)!=0 ); pNC2->ncFlags |= NC_HasAgg | ((pDef->funcFlags^SQLITE_FUNC_ANYORDER) & (SQLITE_FUNC_MINMAX|SQLITE_FUNC_ANYORDER)); } } pNC->ncFlags |= savedAllowFlags; } /* FIX ME: Compute pExpr->affinity based on the expected return ** type of the function */ return WRC_Prune; } #ifndef SQLITE_OMIT_SUBQUERY case TK_SELECT: case TK_EXISTS: testcase( pExpr->op==TK_EXISTS ); #endif case TK_IN: { testcase( pExpr->op==TK_IN ); if( ExprUseXSelect(pExpr) ){ int nRef = pNC->nRef; testcase( pNC->ncFlags & NC_IsCheck ); testcase( pNC->ncFlags & NC_PartIdx ); testcase( pNC->ncFlags & NC_IdxExpr ); testcase( pNC->ncFlags & NC_GenCol ); if( pNC->ncFlags & NC_SelfRef ){ notValidImpl(pParse, pNC, "subqueries", pExpr); }else{ sqlite3WalkSelect(pWalker, pExpr->x.pSelect); } assert( pNC->nRef>=nRef ); if( nRef!=pNC->nRef ){ ExprSetProperty(pExpr, EP_VarSelect); pNC->ncFlags |= NC_VarSelect; } } break; } case TK_VARIABLE: { testcase( pNC->ncFlags & NC_IsCheck ); testcase( pNC->ncFlags & NC_PartIdx ); testcase( pNC->ncFlags & NC_IdxExpr ); testcase( pNC->ncFlags & NC_GenCol ); sqlite3ResolveNotValid(pParse, pNC, "parameters", NC_IsCheck|NC_PartIdx|NC_IdxExpr|NC_GenCol, pExpr); break; } case TK_IS: case TK_ISNOT: { Expr *pRight = sqlite3ExprSkipCollateAndLikely(pExpr->pRight); assert( !ExprHasProperty(pExpr, EP_Reduced) ); /* Handle special cases of "x IS TRUE", "x IS FALSE", "x IS NOT TRUE", ** and "x IS NOT FALSE". */ if( ALWAYS(pRight) && (pRight->op==TK_ID || pRight->op==TK_TRUEFALSE) ){ int rc = resolveExprStep(pWalker, pRight); if( rc==WRC_Abort ) return WRC_Abort; if( pRight->op==TK_TRUEFALSE ){ pExpr->op2 = pExpr->op; pExpr->op = TK_TRUTH; return WRC_Continue; } } /* no break */ deliberate_fall_through } case TK_BETWEEN: case TK_EQ: case TK_NE: case TK_LT: case TK_LE: case TK_GT: case TK_GE: { int nLeft, nRight; if( pParse->db->mallocFailed ) break; assert( pExpr->pLeft!=0 ); nLeft = sqlite3ExprVectorSize(pExpr->pLeft); if( pExpr->op==TK_BETWEEN ){ assert( ExprUseXList(pExpr) ); nRight = sqlite3ExprVectorSize(pExpr->x.pList->a[0].pExpr); if( nRight==nLeft ){ nRight = sqlite3ExprVectorSize(pExpr->x.pList->a[1].pExpr); } }else{ assert( pExpr->pRight!=0 ); nRight = sqlite3ExprVectorSize(pExpr->pRight); |
︙ | ︙ | |||
989 990 991 992 993 994 995 | Expr *pE /* Expression we are trying to match */ ){ int i; /* Loop counter */ UNUSED_PARAMETER(pParse); if( pE->op==TK_ID ){ | > > | | | > | 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 | Expr *pE /* Expression we are trying to match */ ){ int i; /* Loop counter */ UNUSED_PARAMETER(pParse); if( pE->op==TK_ID ){ const char *zCol; assert( !ExprHasProperty(pE, EP_IntValue) ); zCol = pE->u.zToken; for(i=0; i<pEList->nExpr; i++){ if( pEList->a[i].eEName==ENAME_NAME && sqlite3_stricmp(pEList->a[i].zEName, zCol)==0 ){ return i+1; } } } return 0; } |
︙ | ︙ | |||
1039 1040 1041 1042 1043 1044 1045 | /* Resolve all names in the ORDER BY term expression */ memset(&nc, 0, sizeof(nc)); nc.pParse = pParse; nc.pSrcList = pSelect->pSrc; nc.uNC.pEList = pEList; | | | | 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 | /* Resolve all names in the ORDER BY term expression */ memset(&nc, 0, sizeof(nc)); nc.pParse = pParse; nc.pSrcList = pSelect->pSrc; nc.uNC.pEList = pEList; nc.ncFlags = NC_AllowAgg|NC_UEList|NC_NoSelect; nc.nNcErr = 0; db = pParse->db; savedSuppErr = db->suppressErr; db->suppressErr = 1; rc = sqlite3ResolveExprNames(&nc, pE); db->suppressErr = savedSuppErr; if( rc ) return 0; |
︙ | ︙ | |||
1125 1126 1127 1128 1129 1130 1131 | moreToDo = 0; pEList = pSelect->pEList; assert( pEList!=0 ); for(i=0, pItem=pOrderBy->a; i<pOrderBy->nExpr; i++, pItem++){ int iCol = -1; Expr *pE, *pDup; if( pItem->done ) continue; | | > > > > > > > > > > > > > > > | > | | | | | | | | | | | | | | | > | 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 | moreToDo = 0; pEList = pSelect->pEList; assert( pEList!=0 ); for(i=0, pItem=pOrderBy->a; i<pOrderBy->nExpr; i++, pItem++){ int iCol = -1; Expr *pE, *pDup; if( pItem->done ) continue; pE = sqlite3ExprSkipCollateAndLikely(pItem->pExpr); if( NEVER(pE==0) ) continue; if( sqlite3ExprIsInteger(pE, &iCol) ){ if( iCol<=0 || iCol>pEList->nExpr ){ resolveOutOfRangeError(pParse, "ORDER", i+1, pEList->nExpr); return 1; } }else{ iCol = resolveAsName(pParse, pEList, pE); if( iCol==0 ){ /* Now test if expression pE matches one of the values returned ** by pSelect. In the usual case this is done by duplicating the ** expression, resolving any symbols in it, and then comparing ** it against each expression returned by the SELECT statement. ** Once the comparisons are finished, the duplicate expression ** is deleted. ** ** If this is running as part of an ALTER TABLE operation and ** the symbols resolve successfully, also resolve the symbols in the ** actual expression. This allows the code in alter.c to modify ** column references within the ORDER BY expression as required. */ pDup = sqlite3ExprDup(db, pE, 0); if( !db->mallocFailed ){ assert(pDup); iCol = resolveOrderByTermToExprList(pParse, pSelect, pDup); if( IN_RENAME_OBJECT && iCol>0 ){ resolveOrderByTermToExprList(pParse, pSelect, pE); } } sqlite3ExprDelete(db, pDup); } } if( iCol>0 ){ /* Convert the ORDER BY term into an integer column number iCol, ** taking care to preserve the COLLATE clause if it exists. */ if( !IN_RENAME_OBJECT ){ Expr *pNew = sqlite3Expr(db, TK_INTEGER, 0); if( pNew==0 ) return 1; pNew->flags |= EP_IntValue; pNew->u.iValue = iCol; if( pItem->pExpr==pE ){ pItem->pExpr = pNew; }else{ Expr *pParent = pItem->pExpr; assert( pParent->op==TK_COLLATE ); while( pParent->pLeft->op==TK_COLLATE ) pParent = pParent->pLeft; assert( pParent->pLeft==pE ); pParent->pLeft = pNew; } sqlite3ExprDelete(db, pE); pItem->u.x.iOrderByCol = (u16)iCol; } pItem->done = 1; }else{ moreToDo = 1; } } pSelect = pSelect->pNext; } |
︙ | ︙ | |||
1198 1199 1200 1201 1202 1203 1204 | const char *zType /* "ORDER" or "GROUP" */ ){ int i; sqlite3 *db = pParse->db; ExprList *pEList; struct ExprList_item *pItem; | | | < > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | const char *zType /* "ORDER" or "GROUP" */ ){ int i; sqlite3 *db = pParse->db; ExprList *pEList; struct ExprList_item *pItem; if( pOrderBy==0 || pParse->db->mallocFailed || IN_RENAME_OBJECT ) return 0; if( pOrderBy->nExpr>db->aLimit[SQLITE_LIMIT_COLUMN] ){ sqlite3ErrorMsg(pParse, "too many terms in %s BY clause", zType); return 1; } pEList = pSelect->pEList; assert( pEList!=0 ); /* sqlite3SelectNew() guarantees this */ for(i=0, pItem=pOrderBy->a; i<pOrderBy->nExpr; i++, pItem++){ if( pItem->u.x.iOrderByCol ){ if( pItem->u.x.iOrderByCol>pEList->nExpr ){ resolveOutOfRangeError(pParse, zType, i+1, pEList->nExpr); return 1; } resolveAlias(pParse, pEList, pItem->u.x.iOrderByCol-1, pItem->pExpr,0); } } return 0; } #ifndef SQLITE_OMIT_WINDOWFUNC /* ** Walker callback for windowRemoveExprFromSelect(). */ static int resolveRemoveWindowsCb(Walker *pWalker, Expr *pExpr){ UNUSED_PARAMETER(pWalker); if( ExprHasProperty(pExpr, EP_WinFunc) ){ Window *pWin = pExpr->y.pWin; sqlite3WindowUnlinkFromSelect(pWin); } return WRC_Continue; } /* ** Remove any Window objects owned by the expression pExpr from the ** Select.pWin list of Select object pSelect. */ static void windowRemoveExprFromSelect(Select *pSelect, Expr *pExpr){ if( pSelect->pWin ){ Walker sWalker; memset(&sWalker, 0, sizeof(Walker)); sWalker.xExprCallback = resolveRemoveWindowsCb; sWalker.u.pSelect = pSelect; sqlite3WalkExpr(&sWalker, pExpr); } } #else # define windowRemoveExprFromSelect(a, b) #endif /* SQLITE_OMIT_WINDOWFUNC */ /* ** pOrderBy is an ORDER BY or GROUP BY clause in SELECT statement pSelect. ** The Name context of the SELECT statement is pNC. zType is either ** "ORDER" or "GROUP" depending on which type of clause pOrderBy is. ** ** This routine resolves each term of the clause into an expression. ** If the order-by term is an integer I between 1 and N (where N is the |
︙ | ︙ | |||
1248 1249 1250 1251 1252 1253 1254 | ){ int i, j; /* Loop counters */ int iCol; /* Column number */ struct ExprList_item *pItem; /* A term of the ORDER BY clause */ Parse *pParse; /* Parsing context */ int nResult; /* Number of terms in the result set */ | | | > | 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 | ){ int i, j; /* Loop counters */ int iCol; /* Column number */ struct ExprList_item *pItem; /* A term of the ORDER BY clause */ Parse *pParse; /* Parsing context */ int nResult; /* Number of terms in the result set */ assert( pOrderBy!=0 ); nResult = pSelect->pEList->nExpr; pParse = pNC->pParse; for(i=0, pItem=pOrderBy->a; i<pOrderBy->nExpr; i++, pItem++){ Expr *pE = pItem->pExpr; Expr *pE2 = sqlite3ExprSkipCollateAndLikely(pE); if( NEVER(pE2==0) ) continue; if( zType[0]!='G' ){ iCol = resolveAsName(pParse, pSelect->pEList, pE2); if( iCol>0 ){ /* If an AS-name match is found, mark this ORDER BY column as being ** a copy of the iCol-th result-set column. The subsequent call to ** sqlite3ResolveOrderGroupBy() will convert the expression to a ** copy of the iCol-th result-set expression. */ |
︙ | ︙ | |||
1284 1285 1286 1287 1288 1289 1290 | /* Otherwise, treat the ORDER BY term as an ordinary expression */ pItem->u.x.iOrderByCol = 0; if( sqlite3ResolveExprNames(pNC, pE) ){ return 1; } for(j=0; j<pSelect->pEList->nExpr; j++){ if( sqlite3ExprCompare(0, pE, pSelect->pEList->a[j].pExpr, -1)==0 ){ | < < | | | | < < < < < < < | 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 | /* Otherwise, treat the ORDER BY term as an ordinary expression */ pItem->u.x.iOrderByCol = 0; if( sqlite3ResolveExprNames(pNC, pE) ){ return 1; } for(j=0; j<pSelect->pEList->nExpr; j++){ if( sqlite3ExprCompare(0, pE, pSelect->pEList->a[j].pExpr, -1)==0 ){ /* Since this expresion is being changed into a reference ** to an identical expression in the result set, remove all Window ** objects belonging to the expression from the Select.pWin list. */ windowRemoveExprFromSelect(pSelect, pE); pItem->u.x.iOrderByCol = j+1; } } } return sqlite3ResolveOrderGroupBy(pParse, pSelect, pOrderBy, zType); } |
︙ | ︙ | |||
1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 | isCompound = p->pPrior!=0; nCompound = 0; pLeftmost = p; while( p ){ assert( (p->selFlags & SF_Expanded)!=0 ); assert( (p->selFlags & SF_Resolved)==0 ); p->selFlags |= SF_Resolved; /* Resolve the expressions in the LIMIT and OFFSET clauses. These ** are not allowed to refer to any names, so pass an empty NameContext. */ memset(&sNC, 0, sizeof(sNC)); sNC.pParse = pParse; sNC.pWinSelect = p; | > > | 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 | isCompound = p->pPrior!=0; nCompound = 0; pLeftmost = p; while( p ){ assert( (p->selFlags & SF_Expanded)!=0 ); assert( (p->selFlags & SF_Resolved)==0 ); assert( db->suppressErr==0 ); /* SF_Resolved not set if errors suppressed */ p->selFlags |= SF_Resolved; /* Resolve the expressions in the LIMIT and OFFSET clauses. These ** are not allowed to refer to any names, so pass an empty NameContext. */ memset(&sNC, 0, sizeof(sNC)); sNC.pParse = pParse; sNC.pWinSelect = p; |
︙ | ︙ | |||
1372 1373 1374 1375 1376 1377 1378 | Select *pSub = p->pSrc->a[0].pSelect; assert( p->pSrc->nSrc==1 && p->pOrderBy ); assert( pSub->pPrior && pSub->pOrderBy==0 ); pSub->pOrderBy = p->pOrderBy; p->pOrderBy = 0; } | | | | < | < < < < < < < > > > > > > | | | > | 1659 1660 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 1690 1691 1692 1693 1694 1695 | Select *pSub = p->pSrc->a[0].pSelect; assert( p->pSrc->nSrc==1 && p->pOrderBy ); assert( pSub->pPrior && pSub->pOrderBy==0 ); pSub->pOrderBy = p->pOrderBy; p->pOrderBy = 0; } /* Recursively resolve names in all subqueries in the FROM clause */ for(i=0; i<p->pSrc->nSrc; i++){ SrcItem *pItem = &p->pSrc->a[i]; if( pItem->pSelect && (pItem->pSelect->selFlags & SF_Resolved)==0 ){ int nRef = pOuterNC ? pOuterNC->nRef : 0; const char *zSavedContext = pParse->zAuthContext; if( pItem->zName ) pParse->zAuthContext = pItem->zName; sqlite3ResolveSelectNames(pParse, pItem->pSelect, pOuterNC); pParse->zAuthContext = zSavedContext; if( pParse->nErr || db->mallocFailed ) return WRC_Abort; /* If the number of references to the outer context changed when ** expressions in the sub-select were resolved, the sub-select ** is correlated. It is not required to check the refcount on any ** but the innermost outer context object, as lookupName() increments ** the refcount on all contexts between the current one and the ** context containing the column when it resolves a name. */ if( pOuterNC ){ assert( pItem->fg.isCorrelated==0 && pOuterNC->nRef>=nRef ); pItem->fg.isCorrelated = (pOuterNC->nRef>nRef); } } } /* Set up the local name-context to pass to sqlite3ResolveExprNames() to ** resolve the result-set expression list. */ sNC.ncFlags = NC_AllowAgg|NC_AllowWin; |
︙ | ︙ | |||
1417 1418 1419 1420 1421 1422 1423 | /* If there are no aggregate functions in the result-set, and no GROUP BY ** expression, do not allow aggregates in any of the other expressions. */ assert( (p->selFlags & SF_Aggregate)==0 ); pGroupBy = p->pGroupBy; if( pGroupBy || (sNC.ncFlags & NC_HasAgg)!=0 ){ assert( NC_MinMaxAgg==SF_MinMaxAgg ); | > | < < < < < < < | > > > > > | > | > > > > > > > > > > > > > | 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 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 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 | /* If there are no aggregate functions in the result-set, and no GROUP BY ** expression, do not allow aggregates in any of the other expressions. */ assert( (p->selFlags & SF_Aggregate)==0 ); pGroupBy = p->pGroupBy; if( pGroupBy || (sNC.ncFlags & NC_HasAgg)!=0 ){ assert( NC_MinMaxAgg==SF_MinMaxAgg ); assert( NC_OrderAgg==SF_OrderByReqd ); p->selFlags |= SF_Aggregate | (sNC.ncFlags&(NC_MinMaxAgg|NC_OrderAgg)); }else{ sNC.ncFlags &= ~NC_AllowAgg; } /* Add the output column list to the name-context before parsing the ** other expressions in the SELECT statement. This is so that ** 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. */ assert( (sNC.ncFlags & (NC_UAggInfo|NC_UUpsert|NC_UBaseReg))==0 ); sNC.uNC.pEList = p->pEList; sNC.ncFlags |= NC_UEList; if( p->pHaving ){ if( !pGroupBy ){ sqlite3ErrorMsg(pParse, "a GROUP BY clause is required before HAVING"); return WRC_Abort; } if( sqlite3ResolveExprNames(&sNC, p->pHaving) ) return WRC_Abort; } if( sqlite3ResolveExprNames(&sNC, p->pWhere) ) return WRC_Abort; /* Resolve names in table-valued-function arguments */ for(i=0; i<p->pSrc->nSrc; i++){ SrcItem *pItem = &p->pSrc->a[i]; if( pItem->fg.isTabFunc && sqlite3ResolveExprListNames(&sNC, pItem->u1.pFuncArg) ){ return WRC_Abort; } } #ifndef SQLITE_OMIT_WINDOWFUNC if( IN_RENAME_OBJECT ){ Window *pWin; for(pWin=p->pWinDefn; pWin; pWin=pWin->pNextWin){ if( sqlite3ResolveExprListNames(&sNC, pWin->pOrderBy) || sqlite3ResolveExprListNames(&sNC, pWin->pPartition) ){ return WRC_Abort; } } } #endif /* The ORDER BY and GROUP BY clauses may not refer to terms in ** outer queries */ sNC.pNext = 0; sNC.ncFlags |= NC_AllowAgg|NC_AllowWin; |
︙ | ︙ | |||
1480 1481 1482 1483 1484 1485 1486 | ** the compound have been resolved. ** ** If there is an ORDER BY clause on a term of a compound-select other ** than the right-most term, then that is a syntax error. But the error ** is not detected until much later, and so we need to go ahead and ** resolve those symbols on the incorrect ORDER BY for consistency. */ | > | | 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 | ** the compound have been resolved. ** ** If there is an ORDER BY clause on a term of a compound-select other ** than the right-most term, then that is a syntax error. But the error ** is not detected until much later, and so we need to go ahead and ** resolve those symbols on the incorrect ORDER BY for consistency. */ if( p->pOrderBy!=0 && isCompound<=nCompound /* Defer right-most ORDER BY of a compound */ && resolveOrderGroupBy(&sNC, p, p->pOrderBy, "ORDER") ){ return WRC_Abort; } if( db->mallocFailed ){ return WRC_Abort; } |
︙ | ︙ | |||
1583 1584 1585 1586 1587 1588 1589 | ** An error message is left in pParse if anything is amiss. The number ** if errors is returned. */ int sqlite3ResolveExprNames( NameContext *pNC, /* Namespace to resolve expressions in. */ Expr *pExpr /* The expression to be analyzed. */ ){ | | | | | > > | > | < | > > | > > > > > > > | > > > > > | > > > > > > > > > > > > > > | > > > | 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 | ** An error message is left in pParse if anything is amiss. The number ** if errors is returned. */ int sqlite3ResolveExprNames( NameContext *pNC, /* Namespace to resolve expressions in. */ Expr *pExpr /* The expression to be analyzed. */ ){ int savedHasAgg; Walker w; if( pExpr==0 ) return SQLITE_OK; savedHasAgg = pNC->ncFlags & (NC_HasAgg|NC_MinMaxAgg|NC_HasWin|NC_OrderAgg); pNC->ncFlags &= ~(NC_HasAgg|NC_MinMaxAgg|NC_HasWin|NC_OrderAgg); w.pParse = pNC->pParse; w.xExprCallback = resolveExprStep; w.xSelectCallback = (pNC->ncFlags & NC_NoSelect) ? 0 : resolveSelectStep; w.xSelectCallback2 = 0; w.u.pNC = pNC; #if SQLITE_MAX_EXPR_DEPTH>0 w.pParse->nHeight += pExpr->nHeight; if( sqlite3ExprCheckHeight(w.pParse, w.pParse->nHeight) ){ return SQLITE_ERROR; } #endif sqlite3WalkExpr(&w, pExpr); #if SQLITE_MAX_EXPR_DEPTH>0 w.pParse->nHeight -= pExpr->nHeight; #endif assert( EP_Agg==NC_HasAgg ); assert( EP_Win==NC_HasWin ); testcase( pNC->ncFlags & NC_HasAgg ); testcase( pNC->ncFlags & NC_HasWin ); ExprSetProperty(pExpr, pNC->ncFlags & (NC_HasAgg|NC_HasWin) ); pNC->ncFlags |= savedHasAgg; return pNC->nNcErr>0 || w.pParse->nErr>0; } /* ** Resolve all names for all expression in an expression list. This is ** just like sqlite3ResolveExprNames() except that it works for an expression ** list rather than a single expression. */ int sqlite3ResolveExprListNames( NameContext *pNC, /* Namespace to resolve expressions in. */ ExprList *pList /* The expression list to be analyzed. */ ){ int i; int savedHasAgg = 0; Walker w; if( pList==0 ) return WRC_Continue; w.pParse = pNC->pParse; w.xExprCallback = resolveExprStep; w.xSelectCallback = resolveSelectStep; w.xSelectCallback2 = 0; w.u.pNC = pNC; savedHasAgg = pNC->ncFlags & (NC_HasAgg|NC_MinMaxAgg|NC_HasWin|NC_OrderAgg); pNC->ncFlags &= ~(NC_HasAgg|NC_MinMaxAgg|NC_HasWin|NC_OrderAgg); for(i=0; i<pList->nExpr; i++){ Expr *pExpr = pList->a[i].pExpr; if( pExpr==0 ) continue; #if SQLITE_MAX_EXPR_DEPTH>0 w.pParse->nHeight += pExpr->nHeight; if( sqlite3ExprCheckHeight(w.pParse, w.pParse->nHeight) ){ return WRC_Abort; } #endif sqlite3WalkExpr(&w, pExpr); #if SQLITE_MAX_EXPR_DEPTH>0 w.pParse->nHeight -= pExpr->nHeight; #endif assert( EP_Agg==NC_HasAgg ); assert( EP_Win==NC_HasWin ); testcase( pNC->ncFlags & NC_HasAgg ); testcase( pNC->ncFlags & NC_HasWin ); if( pNC->ncFlags & (NC_HasAgg|NC_MinMaxAgg|NC_HasWin|NC_OrderAgg) ){ ExprSetProperty(pExpr, pNC->ncFlags & (NC_HasAgg|NC_HasWin) ); savedHasAgg |= pNC->ncFlags & (NC_HasAgg|NC_MinMaxAgg|NC_HasWin|NC_OrderAgg); pNC->ncFlags &= ~(NC_HasAgg|NC_MinMaxAgg|NC_HasWin|NC_OrderAgg); } if( w.pParse->nErr>0 ) return WRC_Abort; } pNC->ncFlags |= savedHasAgg; return WRC_Continue; } /* ** Resolve all names in all expressions of a SELECT and in all ** decendents of the SELECT, including compounds off of p->pPrior, ** subqueries in expressions, and subqueries used as FROM clause |
︙ | ︙ | |||
1658 1659 1660 1661 1662 1663 1664 | w.xSelectCallback2 = 0; w.pParse = pParse; w.u.pNC = pOuterNC; sqlite3WalkSelect(&w, p); } /* | | > > > | | > > > | | > | | | | | | > > | > > | | | | > > > > > > | | | > | 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 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 | w.xSelectCallback2 = 0; w.pParse = pParse; w.u.pNC = pOuterNC; sqlite3WalkSelect(&w, p); } /* ** Resolve names in expressions that can only reference a single table ** or which cannot reference any tables at all. Examples: ** ** "type" flag ** ------------ ** (1) CHECK constraints NC_IsCheck ** (2) WHERE clauses on partial indices NC_PartIdx ** (3) Expressions in indexes on expressions NC_IdxExpr ** (4) Expression arguments to VACUUM INTO. 0 ** (5) GENERATED ALWAYS as expressions NC_GenCol ** ** In all cases except (4), the Expr.iTable value for Expr.op==TK_COLUMN ** nodes of the expression is set to -1 and the Expr.iColumn value is ** set to the column number. In case (4), TK_COLUMN nodes cause an error. ** ** Any errors cause an error message to be set in pParse. */ int sqlite3ResolveSelfReference( Parse *pParse, /* Parsing context */ Table *pTab, /* The table being referenced, or NULL */ int type, /* NC_IsCheck, NC_PartIdx, NC_IdxExpr, NC_GenCol, or 0 */ Expr *pExpr, /* Expression to resolve. May be NULL. */ ExprList *pList /* Expression list to resolve. May be NULL. */ ){ SrcList sSrc; /* Fake SrcList for pParse->pNewTable */ NameContext sNC; /* Name context for pParse->pNewTable */ int rc; assert( type==0 || pTab!=0 ); assert( type==NC_IsCheck || type==NC_PartIdx || type==NC_IdxExpr || type==NC_GenCol || pTab==0 ); memset(&sNC, 0, sizeof(sNC)); memset(&sSrc, 0, sizeof(sSrc)); if( pTab ){ sSrc.nSrc = 1; sSrc.a[0].zName = pTab->zName; sSrc.a[0].pTab = pTab; sSrc.a[0].iCursor = -1; if( pTab->pSchema!=pParse->db->aDb[1].pSchema ){ /* Cause EP_FromDDL to be set on TK_FUNCTION nodes of non-TEMP ** schema elements */ type |= NC_FromDDL; } } sNC.pParse = pParse; sNC.pSrcList = &sSrc; sNC.ncFlags = type | NC_IsDDL; if( (rc = sqlite3ResolveExprNames(&sNC, pExpr))!=SQLITE_OK ) return rc; if( pList ) rc = sqlite3ResolveExprListNames(&sNC, pList); return rc; } |
Changes to src/rowset.c.
︙ | ︙ | |||
173 174 175 176 177 178 179 | sqlite3RowSetClear(pArg); sqlite3DbFree(((RowSet*)pArg)->db, pArg); } /* ** Allocate a new RowSetEntry object that is associated with the ** given RowSet. Return a pointer to the new and completely uninitialized | | | 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 | sqlite3RowSetClear(pArg); sqlite3DbFree(((RowSet*)pArg)->db, pArg); } /* ** Allocate a new RowSetEntry object that is associated with the ** given RowSet. Return a pointer to the new and completely uninitialized ** object. ** ** In an OOM situation, the RowSet.db->mallocFailed flag is set and this ** routine returns NULL. */ static struct RowSetEntry *rowSetEntryAlloc(RowSet *p){ assert( p!=0 ); if( p->nFresh==0 ){ /*OPTIMIZATION-IF-FALSE*/ |
︙ | ︙ | |||
449 450 451 452 453 454 455 | ** To save unnecessary work, only do this when the batch number changes. */ if( iBatch!=pRowSet->iBatch ){ /*OPTIMIZATION-IF-FALSE*/ p = pRowSet->pEntry; if( p ){ struct RowSetEntry **ppPrevTree = &pRowSet->pForest; if( (pRowSet->rsFlags & ROWSET_SORTED)==0 ){ /*OPTIMIZATION-IF-FALSE*/ | | | 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 | ** To save unnecessary work, only do this when the batch number changes. */ if( iBatch!=pRowSet->iBatch ){ /*OPTIMIZATION-IF-FALSE*/ p = pRowSet->pEntry; if( p ){ struct RowSetEntry **ppPrevTree = &pRowSet->pForest; if( (pRowSet->rsFlags & ROWSET_SORTED)==0 ){ /*OPTIMIZATION-IF-FALSE*/ /* Only sort the current set of entries if they need it */ p = rowSetEntrySort(p); } for(pTree = pRowSet->pForest; pTree; pTree=pTree->pRight){ ppPrevTree = &pTree->pRight; if( pTree->pLeft==0 ){ pTree->pLeft = rowSetListToTree(p); break; |
︙ | ︙ |
Changes to src/select.c.
︙ | ︙ | |||
9 10 11 12 13 14 15 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle SELECT statements in SQLite. */ #include "sqliteInt.h" | < < < < < < < < < < < < < < | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle SELECT statements in SQLite. */ #include "sqliteInt.h" /* ** An instance of the following object is used to record information about ** how to process the DISTINCT keyword, to simplify passing that information ** into the selectInnerLoop() routine. */ typedef struct DistinctCtx DistinctCtx; |
︙ | ︙ | |||
80 81 82 83 84 85 86 | #endif struct RowLoadInfo *pDeferredRowLoad; /* Deferred row loading info or NULL */ }; #define SORTFLAG_UseSorter 0x01 /* Use SorterOpen instead of OpenEphemeral */ /* ** Delete all the content of a Select structure. Deallocate the structure | | > > > > > > > > < > | 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 | #endif struct RowLoadInfo *pDeferredRowLoad; /* Deferred row loading info or NULL */ }; #define SORTFLAG_UseSorter 0x01 /* Use SorterOpen instead of OpenEphemeral */ /* ** Delete all the content of a Select structure. Deallocate the structure ** itself depending on the value of bFree ** ** If bFree==1, call sqlite3DbFree() on the p object. ** If bFree==0, Leave the first Select object unfreed */ static void clearSelect(sqlite3 *db, Select *p, int bFree){ while( p ){ Select *pPrior = p->pPrior; sqlite3ExprListDelete(db, p->pEList); sqlite3SrcListDelete(db, p->pSrc); sqlite3ExprDelete(db, p->pWhere); sqlite3ExprListDelete(db, p->pGroupBy); sqlite3ExprDelete(db, p->pHaving); sqlite3ExprListDelete(db, p->pOrderBy); sqlite3ExprDelete(db, p->pLimit); if( OK_IF_ALWAYS_TRUE(p->pWith) ) sqlite3WithDelete(db, p->pWith); #ifndef SQLITE_OMIT_WINDOWFUNC if( OK_IF_ALWAYS_TRUE(p->pWinDefn) ){ sqlite3WindowListDelete(db, p->pWinDefn); } while( p->pWin ){ assert( p->pWin->ppThis==&p->pWin ); sqlite3WindowUnlinkFromSelect(p->pWin); } #endif if( bFree ) sqlite3DbFreeNN(db, p); p = pPrior; bFree = 1; } } /* ** Initialize a SelectDest structure. */ void sqlite3SelectDestInit(SelectDest *pDest, int eDest, int iParm){ pDest->eDest = (u8)eDest; pDest->iSDParm = iParm; pDest->iSDParm2 = 0; pDest->zAffSdst = 0; pDest->iSdst = 0; pDest->nSdst = 0; } /* |
︙ | ︙ | |||
131 132 133 134 135 136 137 | Expr *pWhere, /* the WHERE clause */ ExprList *pGroupBy, /* the GROUP BY clause */ Expr *pHaving, /* the HAVING clause */ ExprList *pOrderBy, /* the ORDER BY clause */ u32 selFlags, /* Flag parameters, such as SF_Distinct */ Expr *pLimit /* LIMIT value. NULL means not used */ ){ | | | | 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 | Expr *pWhere, /* the WHERE clause */ ExprList *pGroupBy, /* the GROUP BY clause */ Expr *pHaving, /* the HAVING clause */ ExprList *pOrderBy, /* the ORDER BY clause */ u32 selFlags, /* Flag parameters, such as SF_Distinct */ Expr *pLimit /* LIMIT value. NULL means not used */ ){ Select *pNew, *pAllocated; Select standin; pAllocated = pNew = sqlite3DbMallocRawNN(pParse->db, sizeof(*pNew) ); if( pNew==0 ){ assert( pParse->db->mallocFailed ); pNew = &standin; } if( pEList==0 ){ pEList = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(pParse->db,TK_ASTERISK,0)); |
︙ | ︙ | |||
167 168 169 170 171 172 173 | pNew->pWith = 0; #ifndef SQLITE_OMIT_WINDOWFUNC pNew->pWin = 0; pNew->pWinDefn = 0; #endif if( pParse->db->mallocFailed ) { clearSelect(pParse->db, pNew, pNew!=&standin); | | < | | 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 | pNew->pWith = 0; #ifndef SQLITE_OMIT_WINDOWFUNC pNew->pWin = 0; pNew->pWinDefn = 0; #endif if( pParse->db->mallocFailed ) { clearSelect(pParse->db, pNew, pNew!=&standin); pAllocated = 0; }else{ assert( pNew->pSrc!=0 || pParse->nErr>0 ); } return pAllocated; } /* ** Delete the given Select structure and all of its substructures. */ void sqlite3SelectDelete(sqlite3 *db, Select *p){ |
︙ | ︙ | |||
269 270 271 272 273 274 275 | return jointype; } /* ** Return the index of a column in a table. Return -1 if the column ** is not contained in the table. */ | | > > | | | > | | > > | 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 | return jointype; } /* ** Return the index of a column in a table. Return -1 if the column ** is not contained in the table. */ int sqlite3ColumnIndex(Table *pTab, const char *zCol){ int i; u8 h = sqlite3StrIHash(zCol); Column *pCol; for(pCol=pTab->aCol, i=0; i<pTab->nCol; pCol++, i++){ if( pCol->hName==h && sqlite3StrICmp(pCol->zCnName, zCol)==0 ) return i; } return -1; } /* ** Search the first N tables in pSrc, from left to right, looking for a ** table that has a column named zCol. ** ** When found, set *piTab and *piCol to the table index and column index ** of the matching column and return TRUE. ** ** If not found, return FALSE. */ static int tableAndColumnIndex( SrcList *pSrc, /* Array of tables to search */ int N, /* Number of tables in pSrc->a[] to search */ const char *zCol, /* Name of the column we are looking for */ int *piTab, /* Write index of pSrc->a[] here */ int *piCol, /* Write index of pSrc->a[*piTab].pTab->aCol[] here */ int bIgnoreHidden /* True to ignore hidden columns */ ){ int i; /* For looping over tables in pSrc */ int iCol; /* Index of column matching zCol */ assert( (piTab==0)==(piCol==0) ); /* Both or neither are NULL */ for(i=0; i<N; i++){ iCol = sqlite3ColumnIndex(pSrc->a[i].pTab, zCol); if( iCol>=0 && (bIgnoreHidden==0 || IsHiddenColumn(&pSrc->a[i].pTab->aCol[iCol])==0) ){ if( piTab ){ *piTab = i; *piCol = iCol; } return 1; } } |
︙ | ︙ | |||
345 346 347 348 349 350 351 352 353 354 355 | assert( pSrc->a[iLeft].pTab ); assert( pSrc->a[iRight].pTab ); pE1 = sqlite3CreateColumnExpr(db, pSrc, iLeft, iColLeft); pE2 = sqlite3CreateColumnExpr(db, pSrc, iRight, iColRight); pEq = sqlite3PExpr(pParse, TK_EQ, pE1, pE2); if( pEq && isOuterJoin ){ ExprSetProperty(pEq, EP_FromJoin); assert( !ExprHasProperty(pEq, EP_TokenOnly|EP_Reduced) ); ExprSetVVAProperty(pEq, EP_NoReduce); | > > > | | | 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 | assert( pSrc->a[iLeft].pTab ); assert( pSrc->a[iRight].pTab ); pE1 = sqlite3CreateColumnExpr(db, pSrc, iLeft, iColLeft); pE2 = sqlite3CreateColumnExpr(db, pSrc, iRight, iColRight); pEq = sqlite3PExpr(pParse, TK_EQ, pE1, pE2); assert( pE2!=0 || pEq==0 ); /* Due to db->mallocFailed test ** in sqlite3DbMallocRawNN() called from ** sqlite3PExpr(). */ if( pEq && isOuterJoin ){ ExprSetProperty(pEq, EP_FromJoin); assert( !ExprHasProperty(pEq, EP_TokenOnly|EP_Reduced) ); ExprSetVVAProperty(pEq, EP_NoReduce); pEq->iRightJoinTable = pE2->iTable; } *ppWhere = sqlite3ExprAnd(pParse, *ppWhere, pEq); } /* ** Set the EP_FromJoin property on all terms of the given expression. ** And set the Expr.iRightJoinTable to iTable for every term in the ** expression. ** |
︙ | ︙ | |||
380 381 382 383 384 385 386 | ** The where clause needs to defer the handling of the t1.x=5 ** term until after the t2 loop of the join. In that way, a ** NULL t2 row will be inserted whenever t1.x!=5. If we do not ** defer the handling of t1.x=5, it will be processed immediately ** after the t1 loop and rows with t1.x!=5 will never appear in ** the output, which is incorrect. */ | | | | > > | | | | | > | | > > > | > > | | | > | 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 | ** The where clause needs to defer the handling of the t1.x=5 ** term until after the t2 loop of the join. In that way, a ** NULL t2 row will be inserted whenever t1.x!=5. If we do not ** defer the handling of t1.x=5, it will be processed immediately ** after the t1 loop and rows with t1.x!=5 will never appear in ** the output, which is incorrect. */ void sqlite3SetJoinExpr(Expr *p, int iTable){ while( p ){ ExprSetProperty(p, EP_FromJoin); assert( !ExprHasProperty(p, EP_TokenOnly|EP_Reduced) ); ExprSetVVAProperty(p, EP_NoReduce); p->iRightJoinTable = iTable; if( p->op==TK_FUNCTION ){ assert( ExprUseXList(p) ); if( p->x.pList ){ int i; for(i=0; i<p->x.pList->nExpr; i++){ sqlite3SetJoinExpr(p->x.pList->a[i].pExpr, iTable); } } } sqlite3SetJoinExpr(p->pLeft, iTable); p = p->pRight; } } /* Undo the work of sqlite3SetJoinExpr(). In the expression p, convert every ** term that is marked with EP_FromJoin and iRightJoinTable==iTable into ** an ordinary term that omits the EP_FromJoin mark. ** ** This happens when a LEFT JOIN is simplified into an ordinary JOIN. */ static void unsetJoinExpr(Expr *p, int iTable){ while( p ){ if( ExprHasProperty(p, EP_FromJoin) && (iTable<0 || p->iRightJoinTable==iTable) ){ ExprClearProperty(p, EP_FromJoin); } if( p->op==TK_COLUMN && p->iTable==iTable ){ ExprClearProperty(p, EP_CanBeNull); } if( p->op==TK_FUNCTION ){ assert( ExprUseXList(p) ); if( p->x.pList ){ int i; for(i=0; i<p->x.pList->nExpr; i++){ unsetJoinExpr(p->x.pList->a[i].pExpr, iTable); } } } unsetJoinExpr(p->pLeft, iTable); p = p->pRight; } } |
︙ | ︙ | |||
437 438 439 440 441 442 443 | ** also attached to the left entry. ** ** This routine returns the number of errors encountered. */ static int sqliteProcessJoin(Parse *pParse, Select *p){ SrcList *pSrc; /* All tables in the FROM clause */ int i, j; /* Loop counters */ | | | | 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 | ** also attached to the left entry. ** ** This routine returns the number of errors encountered. */ static int sqliteProcessJoin(Parse *pParse, Select *p){ SrcList *pSrc; /* All tables in the FROM clause */ int i, j; /* Loop counters */ SrcItem *pLeft; /* Left table being joined */ SrcItem *pRight; /* Right table being joined */ pSrc = p->pSrc; pLeft = &pSrc->a[0]; pRight = &pLeft[1]; for(i=0; i<pSrc->nSrc-1; i++, pRight++, pLeft++){ Table *pRightTab = pRight->pTab; int isOuter; |
︙ | ︙ | |||
464 465 466 467 468 469 470 | return 1; } for(j=0; j<pRightTab->nCol; j++){ char *zName; /* Name of column in the right table */ int iLeft; /* Matching left table */ int iLeftCol; /* Matching column in the left table */ | > | | | | | | | | 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 | return 1; } for(j=0; j<pRightTab->nCol; j++){ char *zName; /* Name of column in the right table */ int iLeft; /* Matching left table */ int iLeftCol; /* Matching column in the left table */ if( IsHiddenColumn(&pRightTab->aCol[j]) ) continue; zName = pRightTab->aCol[j].zCnName; if( tableAndColumnIndex(pSrc, i+1, zName, &iLeft, &iLeftCol, 1) ){ addWhereTerm(pParse, pSrc, iLeft, iLeftCol, i+1, j, isOuter, &p->pWhere); } } } /* Disallow both ON and USING clauses in the same join */ if( pRight->pOn && pRight->pUsing ){ sqlite3ErrorMsg(pParse, "cannot have both ON and USING " "clauses in the same join"); return 1; } /* Add the ON clause to the end of the WHERE clause, connected by ** an AND operator. */ if( pRight->pOn ){ if( isOuter ) sqlite3SetJoinExpr(pRight->pOn, pRight->iCursor); p->pWhere = sqlite3ExprAnd(pParse, p->pWhere, pRight->pOn); pRight->pOn = 0; } /* Create extra terms on the WHERE clause for each column named ** in the USING clause. Example: If the two tables to be joined are ** A and B and the USING clause names X, Y, and Z, then add this ** to the WHERE clause: A.X=B.X AND A.Y=B.Y AND A.Z=B.Z ** Report an error if any column mentioned in the USING clause is ** not contained in both tables to be joined. */ if( pRight->pUsing ){ IdList *pList = pRight->pUsing; for(j=0; j<pList->nId; j++){ char *zName; /* Name of the term in the USING clause */ int iLeft; /* Table on the left with matching column name */ int iLeftCol; /* Column number of matching column on the left */ int iRightCol; /* Column number of matching column on the right */ zName = pList->a[j].zName; iRightCol = sqlite3ColumnIndex(pRightTab, zName); if( iRightCol<0 || !tableAndColumnIndex(pSrc, i+1, zName, &iLeft, &iLeftCol, 0) ){ sqlite3ErrorMsg(pParse, "cannot join using column %s - column " "not present in both tables", zName); return 1; } addWhereTerm(pParse, pSrc, iLeft, iLeftCol, i+1, iRightCol, isOuter, &p->pWhere); |
︙ | ︙ | |||
627 628 629 630 631 632 633 | regBase = regData - nPrefixReg; }else{ regBase = pParse->nMem + 1; pParse->nMem += nBase; } assert( pSelect->iOffset==0 || pSelect->iLimit!=0 ); iLimit = pSelect->iOffset ? pSelect->iOffset+1 : pSelect->iLimit; | | | 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 | regBase = regData - nPrefixReg; }else{ regBase = pParse->nMem + 1; pParse->nMem += nBase; } assert( pSelect->iOffset==0 || pSelect->iLimit!=0 ); iLimit = pSelect->iOffset ? pSelect->iOffset+1 : pSelect->iLimit; pSort->labelDone = sqlite3VdbeMakeLabel(pParse); sqlite3ExprCodeExprList(pParse, pSort->pOrderBy, regBase, regOrigData, SQLITE_ECEL_DUP | (regOrigData? SQLITE_ECEL_REF : 0)); if( bSeq ){ sqlite3VdbeAddOp2(v, OP_Sequence, pSort->iECursor, regBase+nExpr); } if( nPrefixReg==0 && nData>0 ){ sqlite3ExprCodeMove(pParse, regData, regBase+nExpr+bSeq, nData); |
︙ | ︙ | |||
659 660 661 662 663 664 665 | } VdbeCoverage(v); sqlite3VdbeAddOp3(v, OP_Compare, regPrevKey, regBase, pSort->nOBSat); pOp = sqlite3VdbeGetOp(v, pSort->addrSortIndex); if( pParse->db->mallocFailed ) return; pOp->p2 = nKey + nData; pKI = pOp->p4.pKeyInfo; | | > | | 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 | } VdbeCoverage(v); sqlite3VdbeAddOp3(v, OP_Compare, regPrevKey, regBase, pSort->nOBSat); pOp = sqlite3VdbeGetOp(v, pSort->addrSortIndex); if( pParse->db->mallocFailed ) return; pOp->p2 = nKey + nData; pKI = pOp->p4.pKeyInfo; memset(pKI->aSortFlags, 0, pKI->nKeyField); /* Makes OP_Jump testable */ sqlite3VdbeChangeP4(v, -1, (char*)pKI, P4_KEYINFO); testcase( pKI->nAllField > pKI->nKeyField+2 ); pOp->p4.pKeyInfo = sqlite3KeyInfoFromExprList(pParse,pSort->pOrderBy,nOBSat, pKI->nAllField-pKI->nKeyField-1); pOp = 0; /* Ensure pOp not used after sqltie3VdbeAddOp3() */ addrJmp = sqlite3VdbeCurrentAddr(v); sqlite3VdbeAddOp3(v, OP_Jump, addrJmp+1, 0, addrJmp+1); VdbeCoverage(v); pSort->labelBkOut = sqlite3VdbeMakeLabel(pParse); pSort->regReturn = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_Gosub, pSort->regReturn, pSort->labelBkOut); sqlite3VdbeAddOp1(v, OP_ResetSorter, pSort->iECursor); if( iLimit ){ sqlite3VdbeAddOp2(v, OP_IfNot, iLimit, pSort->labelDone); VdbeCoverage(v); } |
︙ | ︙ | |||
734 735 736 737 738 739 740 | if( iOffset>0 ){ sqlite3VdbeAddOp3(v, OP_IfPos, iOffset, iContinue, 1); VdbeCoverage(v); VdbeComment((v, "OFFSET")); } } /* | | | | > | > > > > > > > > | > > > > > > > > | > > > > > > > > > > > > > > > > > | > > > > > > > | > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | < < | | | > > > > > > | > > > > > | 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 | if( iOffset>0 ){ sqlite3VdbeAddOp3(v, OP_IfPos, iOffset, iContinue, 1); VdbeCoverage(v); VdbeComment((v, "OFFSET")); } } /* ** Add code that will check to make sure the array of registers starting at ** iMem form a distinct entry. This is used by both "SELECT DISTINCT ..." and ** distinct aggregates ("SELECT count(DISTINCT <expr>) ..."). Three strategies ** are available. Which is used depends on the value of parameter eTnctType, ** as follows: ** ** WHERE_DISTINCT_UNORDERED/WHERE_DISTINCT_NOOP: ** Build an ephemeral table that contains all entries seen before and ** skip entries which have been seen before. ** ** Parameter iTab is the cursor number of an ephemeral table that must ** be opened before the VM code generated by this routine is executed. ** The ephemeral cursor table is queried for a record identical to the ** record formed by the current array of registers. If one is found, ** jump to VM address addrRepeat. Otherwise, insert a new record into ** the ephemeral cursor and proceed. ** ** The returned value in this case is a copy of parameter iTab. ** ** WHERE_DISTINCT_ORDERED: ** In this case rows are being delivered sorted order. The ephermal ** table is not required. Instead, the current set of values ** is compared against previous row. If they match, the new row ** is not distinct and control jumps to VM address addrRepeat. Otherwise, ** the VM program proceeds with processing the new row. ** ** The returned value in this case is the register number of the first ** in an array of registers used to store the previous result row so that ** it can be compared to the next. The caller must ensure that this ** register is initialized to NULL. (The fixDistinctOpenEph() routine ** will take care of this initialization.) ** ** WHERE_DISTINCT_UNIQUE: ** In this case it has already been determined that the rows are distinct. ** No special action is required. The return value is zero. ** ** Parameter pEList is the list of expressions used to generated the ** contents of each row. It is used by this routine to determine (a) ** how many elements there are in the array of registers and (b) the ** collation sequences that should be used for the comparisons if ** eTnctType is WHERE_DISTINCT_ORDERED. */ static int codeDistinct( Parse *pParse, /* Parsing and code generating context */ int eTnctType, /* WHERE_DISTINCT_* value */ int iTab, /* A sorting index used to test for distinctness */ int addrRepeat, /* Jump to here if not distinct */ ExprList *pEList, /* Expression for each element */ int regElem /* First element */ ){ int iRet = 0; int nResultCol = pEList->nExpr; Vdbe *v = pParse->pVdbe; switch( eTnctType ){ case WHERE_DISTINCT_ORDERED: { int i; int iJump; /* Jump destination */ int regPrev; /* Previous row content */ /* Allocate space for the previous row */ iRet = regPrev = pParse->nMem+1; pParse->nMem += nResultCol; iJump = sqlite3VdbeCurrentAddr(v) + nResultCol; for(i=0; i<nResultCol; i++){ CollSeq *pColl = sqlite3ExprCollSeq(pParse, pEList->a[i].pExpr); if( i<nResultCol-1 ){ sqlite3VdbeAddOp3(v, OP_Ne, regElem+i, iJump, regPrev+i); VdbeCoverage(v); }else{ sqlite3VdbeAddOp3(v, OP_Eq, regElem+i, addrRepeat, regPrev+i); VdbeCoverage(v); } sqlite3VdbeChangeP4(v, -1, (const char *)pColl, P4_COLLSEQ); sqlite3VdbeChangeP5(v, SQLITE_NULLEQ); } assert( sqlite3VdbeCurrentAddr(v)==iJump || pParse->db->mallocFailed ); sqlite3VdbeAddOp3(v, OP_Copy, regElem, regPrev, nResultCol-1); break; } case WHERE_DISTINCT_UNIQUE: { /* nothing to do */ break; } default: { int r1 = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp4Int(v, OP_Found, iTab, addrRepeat, regElem, nResultCol); VdbeCoverage(v); sqlite3VdbeAddOp3(v, OP_MakeRecord, regElem, nResultCol, r1); sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iTab, r1, regElem, nResultCol); sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT); sqlite3ReleaseTempReg(pParse, r1); iRet = iTab; break; } } return iRet; } /* ** This routine runs after codeDistinct(). It makes necessary ** adjustments to the OP_OpenEphemeral opcode that the codeDistinct() ** routine made use of. This processing must be done separately since ** sometimes codeDistinct is called before the OP_OpenEphemeral is actually ** laid down. ** ** WHERE_DISTINCT_NOOP: ** WHERE_DISTINCT_UNORDERED: ** ** No adjustments necessary. This function is a no-op. ** ** WHERE_DISTINCT_UNIQUE: ** ** The ephemeral table is not needed. So change the ** OP_OpenEphemeral opcode into an OP_Noop. ** ** WHERE_DISTINCT_ORDERED: ** ** The ephemeral table is not needed. But we do need register ** iVal to be initialized to NULL. So change the OP_OpenEphemeral ** into an OP_Null on the iVal register. */ static void fixDistinctOpenEph( Parse *pParse, /* Parsing and code generating context */ int eTnctType, /* WHERE_DISTINCT_* value */ int iVal, /* Value returned by codeDistinct() */ int iOpenEphAddr /* Address of OP_OpenEphemeral instruction for iTab */ ){ if( pParse->nErr==0 && (eTnctType==WHERE_DISTINCT_UNIQUE || eTnctType==WHERE_DISTINCT_ORDERED) ){ Vdbe *v = pParse->pVdbe; sqlite3VdbeChangeToNoop(v, iOpenEphAddr); if( sqlite3VdbeGetOp(v, iOpenEphAddr+1)->opcode==OP_Explain ){ sqlite3VdbeChangeToNoop(v, iOpenEphAddr+1); } if( eTnctType==WHERE_DISTINCT_ORDERED ){ /* Change the OP_OpenEphemeral to an OP_Null that sets the MEM_Cleared ** bit on the first register of the previous value. This will cause the ** OP_Ne added in codeDistinct() to always fail on the first iteration of ** the loop even if the first row is all NULLs. */ VdbeOp *pOp = sqlite3VdbeGetOp(v, iOpenEphAddr); pOp->opcode = OP_Null; pOp->p1 = 1; pOp->p2 = iVal; } } } #ifdef SQLITE_ENABLE_SORTER_REFERENCES /* ** This function is called as part of inner-loop generation for a SELECT ** statement with an ORDER BY that is not optimized by an index. It ** determines the expressions, if any, that the sorter-reference |
︙ | ︙ | |||
799 800 801 802 803 804 805 | int i; int nDefer = 0; ExprList *pExtra = 0; for(i=0; i<pEList->nExpr; i++){ struct ExprList_item *pItem = &pEList->a[i]; if( pItem->u.x.iOrderByCol==0 ){ Expr *pExpr = pItem->pExpr; | | | > > > > | > | 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 | int i; int nDefer = 0; ExprList *pExtra = 0; for(i=0; i<pEList->nExpr; i++){ struct ExprList_item *pItem = &pEList->a[i]; if( pItem->u.x.iOrderByCol==0 ){ Expr *pExpr = pItem->pExpr; Table *pTab; if( pExpr->op==TK_COLUMN && pExpr->iColumn>=0 && ALWAYS( ExprUseYTab(pExpr) ) && (pTab = pExpr->y.pTab)!=0 && IsOrdinaryTable(pTab) && (pTab->aCol[pExpr->iColumn].colFlags & COLFLAG_SORTERREF)!=0 ){ int j; for(j=0; j<nDefer; j++){ if( pSort->aDefer[j].iCsr==pExpr->iTable ) break; } if( j==nDefer ){ if( nDefer==ArraySize(pSort->aDefer) ){ continue; }else{ int nKey = 1; int k; Index *pPk = 0; if( !HasRowid(pTab) ){ pPk = sqlite3PrimaryKeyIndex(pTab); nKey = pPk->nKeyCol; } for(k=0; k<nKey; k++){ Expr *pNew = sqlite3PExpr(pParse, TK_COLUMN, 0, 0); if( pNew ){ pNew->iTable = pExpr->iTable; assert( ExprUseYTab(pNew) ); pNew->y.pTab = pExpr->y.pTab; pNew->iColumn = pPk ? pPk->aiColumn[k] : -1; pExtra = sqlite3ExprListAppend(pParse, pExtra, pNew); } } pSort->aDefer[nDefer].pTab = pExpr->y.pTab; pSort->aDefer[nDefer].iCsr = pExpr->iTable; |
︙ | ︙ | |||
912 913 914 915 916 917 918 | pParse->nMem += nResultCol; } pDest->nSdst = nResultCol; regOrig = regResult = pDest->iSdst; if( srcTab>=0 ){ for(i=0; i<nResultCol; i++){ sqlite3VdbeAddOp3(v, OP_Column, srcTab, i, regResult+i); | | | 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 | pParse->nMem += nResultCol; } pDest->nSdst = nResultCol; regOrig = regResult = pDest->iSdst; if( srcTab>=0 ){ for(i=0; i<nResultCol; i++){ sqlite3VdbeAddOp3(v, OP_Column, srcTab, i, regResult+i); VdbeComment((v, "%s", p->pEList->a[i].zEName)); } }else if( eDest!=SRT_Exists ){ #ifdef SQLITE_ENABLE_SORTER_REFERENCES ExprList *pExtra = 0; #endif /* If the destination is an EXISTS(...) expression, the actual ** values returned by the SELECT are not required. |
︙ | ︙ | |||
978 979 980 981 982 983 984 | testcase( regOrig ); testcase( eDest==SRT_Set ); testcase( eDest==SRT_Mem ); testcase( eDest==SRT_Coroutine ); testcase( eDest==SRT_Output ); assert( eDest==SRT_Set || eDest==SRT_Mem | | > | 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 | testcase( regOrig ); testcase( eDest==SRT_Set ); testcase( eDest==SRT_Mem ); testcase( eDest==SRT_Coroutine ); testcase( eDest==SRT_Output ); assert( eDest==SRT_Set || eDest==SRT_Mem || eDest==SRT_Coroutine || eDest==SRT_Output || eDest==SRT_Upfrom ); } sRowLoadInfo.regResult = regResult; sRowLoadInfo.ecelFlags = ecelFlags; #ifdef SQLITE_ENABLE_SORTER_REFERENCES sRowLoadInfo.pExtra = pExtra; sRowLoadInfo.regExtraResult = regResult + nResultCol; if( pExtra ) nResultCol += pExtra->nExpr; |
︙ | ︙ | |||
1005 1006 1007 1008 1009 1010 1011 | } /* If the DISTINCT keyword was present on the SELECT statement ** and this row has been seen before, then do not make this row ** part of the result. */ if( hasDistinct ){ | | < < < < | < < | | < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 | } /* If the DISTINCT keyword was present on the SELECT statement ** and this row has been seen before, then do not make this row ** part of the result. */ if( hasDistinct ){ int eType = pDistinct->eTnctType; int iTab = pDistinct->tabTnct; assert( nResultCol==p->pEList->nExpr ); iTab = codeDistinct(pParse, eType, iTab, iContinue, p->pEList, regResult); fixDistinctOpenEph(pParse, eType, iTab, pDistinct->addrTnct); if( pSort==0 ){ codeOffset(v, p->iOffset, iContinue); } } switch( eDest ){ /* In this mode, write each query result to the key of the temporary |
︙ | ︙ | |||
1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 | sqlite3VdbeAddOp3(v, OP_Insert, iParm, r1, r2); sqlite3VdbeChangeP5(v, OPFLAG_APPEND); sqlite3ReleaseTempReg(pParse, r2); } sqlite3ReleaseTempRange(pParse, r1, nPrefixReg+1); break; } #ifndef SQLITE_OMIT_SUBQUERY /* If we are creating a set for an "expr IN (SELECT ...)" construct, ** then there should be a single item on the stack. Write this ** item into the set table with bogus data. */ case SRT_Set: { | > > > > > > > > > > > > > > > > > > > > > > > > | 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 | sqlite3VdbeAddOp3(v, OP_Insert, iParm, r1, r2); sqlite3VdbeChangeP5(v, OPFLAG_APPEND); sqlite3ReleaseTempReg(pParse, r2); } sqlite3ReleaseTempRange(pParse, r1, nPrefixReg+1); break; } case SRT_Upfrom: { if( pSort ){ pushOntoSorter( pParse, pSort, p, regResult, regOrig, nResultCol, nPrefixReg); }else{ int i2 = pDest->iSDParm2; int r1 = sqlite3GetTempReg(pParse); /* If the UPDATE FROM join is an aggregate that matches no rows, it ** might still be trying to return one row, because that is what ** aggregates do. Don't record that empty row in the output table. */ sqlite3VdbeAddOp2(v, OP_IsNull, regResult, iBreak); VdbeCoverage(v); sqlite3VdbeAddOp3(v, OP_MakeRecord, regResult+(i2<0), nResultCol-(i2<0), r1); if( i2<0 ){ sqlite3VdbeAddOp3(v, OP_Insert, iParm, r1, regResult); }else{ sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iParm, r1, regResult, i2); } } break; } #ifndef SQLITE_OMIT_SUBQUERY /* If we are creating a set for an "expr IN (SELECT ...)" construct, ** then there should be a single item on the stack. Write this ** item into the set table with bogus data. */ case SRT_Set: { |
︙ | ︙ | |||
1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 | sqlite3VdbeAddOp4(v, OP_MakeRecord, regResult, nResultCol, r1, pDest->zAffSdst, nResultCol); sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iParm, r1, regResult, nResultCol); sqlite3ReleaseTempReg(pParse, r1); } break; } /* If any row exist in the result set, record that fact and abort. */ case SRT_Exists: { sqlite3VdbeAddOp2(v, OP_Integer, 1, iParm); /* The LIMIT clause will terminate the loop for us */ break; | > | 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 | sqlite3VdbeAddOp4(v, OP_MakeRecord, regResult, nResultCol, r1, pDest->zAffSdst, nResultCol); sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iParm, r1, regResult, nResultCol); sqlite3ReleaseTempReg(pParse, r1); } break; } /* If any row exist in the result set, record that fact and abort. */ case SRT_Exists: { sqlite3VdbeAddOp2(v, OP_Integer, 1, iParm); /* The LIMIT clause will terminate the loop for us */ break; |
︙ | ︙ | |||
1270 1271 1272 1273 1274 1275 1276 | ** Allocate a KeyInfo object sufficient for an index of N key columns and ** X extra columns. */ KeyInfo *sqlite3KeyInfoAlloc(sqlite3 *db, int N, int X){ int nExtra = (N+X)*(sizeof(CollSeq*)+1) - sizeof(CollSeq*); KeyInfo *p = sqlite3DbMallocRawNN(db, sizeof(KeyInfo) + nExtra); if( p ){ | | | 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 | ** Allocate a KeyInfo object sufficient for an index of N key columns and ** X extra columns. */ KeyInfo *sqlite3KeyInfoAlloc(sqlite3 *db, int N, int X){ int nExtra = (N+X)*(sizeof(CollSeq*)+1) - sizeof(CollSeq*); KeyInfo *p = sqlite3DbMallocRawNN(db, sizeof(KeyInfo) + nExtra); if( p ){ p->aSortFlags = (u8*)&p->aColl[N+X]; p->nKeyField = (u16)N; p->nAllField = (u16)(N+X); p->enc = ENC(db); p->db = db; p->nRef = 1; memset(&p[1], 0, nExtra); }else{ |
︙ | ︙ | |||
1347 1348 1349 1350 1351 1352 1353 | nExpr = pList->nExpr; pInfo = sqlite3KeyInfoAlloc(db, nExpr-iStart, nExtra+1); if( pInfo ){ assert( sqlite3KeyInfoIsWriteable(pInfo) ); for(i=iStart, pItem=pList->a+iStart; i<nExpr; i++, pItem++){ pInfo->aColl[i-iStart] = sqlite3ExprNNCollSeq(pParse, pItem->pExpr); | | | | 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 | nExpr = pList->nExpr; pInfo = sqlite3KeyInfoAlloc(db, nExpr-iStart, nExtra+1); if( pInfo ){ assert( sqlite3KeyInfoIsWriteable(pInfo) ); for(i=iStart, pItem=pList->a+iStart; i<nExpr; i++, pItem++){ pInfo->aColl[i-iStart] = sqlite3ExprNNCollSeq(pParse, pItem->pExpr); pInfo->aSortFlags[i-iStart] = pItem->sortFlags; } } return pInfo; } /* ** Name of the connection operator, used for error messages. */ const char *sqlite3SelectOpName(int id){ char *z; switch( id ){ case TK_ALL: z = "UNION ALL"; break; case TK_INTERSECT: z = "INTERSECT"; break; case TK_EXCEPT: z = "EXCEPT"; break; default: z = "UNION"; break; } |
︙ | ︙ | |||
1413 1414 1415 1416 1417 1418 1419 | Select *p, /* The SELECT statement */ SortCtx *pSort, /* Information on the ORDER BY clause */ int nColumn, /* Number of columns of data */ SelectDest *pDest /* Write the sorted results here */ ){ Vdbe *v = pParse->pVdbe; /* The prepared statement */ int addrBreak = pSort->labelDone; /* Jump here to exit loop */ | | | 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 | Select *p, /* The SELECT statement */ SortCtx *pSort, /* Information on the ORDER BY clause */ int nColumn, /* Number of columns of data */ SelectDest *pDest /* Write the sorted results here */ ){ Vdbe *v = pParse->pVdbe; /* The prepared statement */ int addrBreak = pSort->labelDone; /* Jump here to exit loop */ int addrContinue = sqlite3VdbeMakeLabel(pParse);/* Jump here for next cycle */ int addr; /* Top of output loop. Jump for Next. */ int addrOnce = 0; int iTab; ExprList *pOrderBy = pSort->pOrderBy; int eDest = pDest->eDest; int iParm = pDest->iSDParm; int regRow; |
︙ | ︙ | |||
1453 1454 1455 1456 1457 1458 1459 | iTab = pSort->iECursor; if( eDest==SRT_Output || eDest==SRT_Coroutine || eDest==SRT_Mem ){ regRowid = 0; regRow = pDest->iSdst; }else{ regRowid = sqlite3GetTempReg(pParse); | > > > > | > | 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 | iTab = pSort->iECursor; if( eDest==SRT_Output || eDest==SRT_Coroutine || eDest==SRT_Mem ){ regRowid = 0; regRow = pDest->iSdst; }else{ regRowid = sqlite3GetTempReg(pParse); if( eDest==SRT_EphemTab || eDest==SRT_Table ){ regRow = sqlite3GetTempReg(pParse); nColumn = 0; }else{ regRow = sqlite3GetTempRange(pParse, nColumn); } } nKey = pOrderBy->nExpr - pSort->nOBSat; if( pSort->sortFlags & SORTFLAG_UseSorter ){ int regSortOut = ++pParse->nMem; iSortTab = pParse->nTab++; if( pSort->labelBkOut ){ addrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v); |
︙ | ︙ | |||
1527 1528 1529 1530 1531 1532 1533 | int iRead; if( aOutEx[i].u.x.iOrderByCol ){ iRead = aOutEx[i].u.x.iOrderByCol-1; }else{ iRead = iCol--; } sqlite3VdbeAddOp3(v, OP_Column, iSortTab, iRead, regRow+i); | | > > > > > > > > > > > > | 1654 1655 1656 1657 1658 1659 1660 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 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 | int iRead; if( aOutEx[i].u.x.iOrderByCol ){ iRead = aOutEx[i].u.x.iOrderByCol-1; }else{ iRead = iCol--; } sqlite3VdbeAddOp3(v, OP_Column, iSortTab, iRead, regRow+i); VdbeComment((v, "%s", aOutEx[i].zEName)); } } switch( eDest ){ case SRT_Table: case SRT_EphemTab: { sqlite3VdbeAddOp3(v, OP_Column, iSortTab, nKey+bSeq, regRow); sqlite3VdbeAddOp2(v, OP_NewRowid, iParm, regRowid); sqlite3VdbeAddOp3(v, OP_Insert, iParm, regRow, regRowid); sqlite3VdbeChangeP5(v, OPFLAG_APPEND); break; } #ifndef SQLITE_OMIT_SUBQUERY case SRT_Set: { assert( nColumn==sqlite3Strlen30(pDest->zAffSdst) ); sqlite3VdbeAddOp4(v, OP_MakeRecord, regRow, nColumn, regRowid, pDest->zAffSdst, nColumn); sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iParm, regRowid, regRow, nColumn); break; } case SRT_Mem: { /* The LIMIT clause will terminate the loop for us */ break; } #endif case SRT_Upfrom: { int i2 = pDest->iSDParm2; int r1 = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp3(v, OP_MakeRecord,regRow+(i2<0),nColumn-(i2<0),r1); if( i2<0 ){ sqlite3VdbeAddOp3(v, OP_Insert, iParm, r1, regRow); }else{ sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iParm, r1, regRow, i2); } break; } default: { assert( eDest==SRT_Output || eDest==SRT_Coroutine ); testcase( eDest==SRT_Output ); testcase( eDest==SRT_Coroutine ); if( eDest==SRT_Output ){ sqlite3VdbeAddOp2(v, OP_ResultRow, pDest->iSdst, nColumn); }else{ |
︙ | ︙ | |||
1633 1634 1635 1636 1637 1638 1639 | char const *zOrigDb = 0; char const *zOrigTab = 0; char const *zOrigCol = 0; #endif assert( pExpr!=0 ); assert( pNC->pSrcList!=0 ); | < < | 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 | char const *zOrigDb = 0; char const *zOrigTab = 0; char const *zOrigCol = 0; #endif assert( pExpr!=0 ); assert( pNC->pSrcList!=0 ); switch( pExpr->op ){ case TK_COLUMN: { /* The expression is a column. Locate the table the column is being ** extracted from in NameContext.pSrcList. This table may be real ** database table or a subquery. */ Table *pTab = 0; /* Table structure column is extracted from */ |
︙ | ︙ | |||
1676 1677 1678 1679 1680 1681 1682 | ** This is not a problem, as the column type of "t1.col" is never ** used. When columnType() is called on the expression ** "(SELECT t1.col)", the correct type is returned (see the TK_SELECT ** branch below. */ break; } | | | > > > > > > | 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 | ** This is not a problem, as the column type of "t1.col" is never ** used. When columnType() is called on the expression ** "(SELECT t1.col)", the correct type is returned (see the TK_SELECT ** branch below. */ break; } assert( pTab && ExprUseYTab(pExpr) && pExpr->y.pTab==pTab ); if( pS ){ /* The "table" is actually a sub-select or a view in the FROM clause ** of the SELECT statement. Return the declaration type and origin ** data for the result-set column of the sub-select. */ if( iCol<pS->pEList->nExpr #ifdef SQLITE_ALLOW_ROWID_IN_VIEW && iCol>=0 #else && ALWAYS(iCol>=0) #endif ){ /* If iCol is less than zero, then the expression requests the ** rowid of the sub-select or view. This expression is legal (see ** test case misc2.2.2) - it always evaluates to NULL. */ NameContext sNC; Expr *p = pS->pEList->a[iCol].pExpr; sNC.pSrcList = pS->pSrc; |
︙ | ︙ | |||
1704 1705 1706 1707 1708 1709 1710 | #ifdef SQLITE_ENABLE_COLUMN_METADATA if( iCol<0 ) iCol = pTab->iPKey; assert( iCol==XN_ROWID || (iCol>=0 && iCol<pTab->nCol) ); if( iCol<0 ){ zType = "INTEGER"; zOrigCol = "rowid"; }else{ | | | 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 | #ifdef SQLITE_ENABLE_COLUMN_METADATA if( iCol<0 ) iCol = pTab->iPKey; assert( iCol==XN_ROWID || (iCol>=0 && iCol<pTab->nCol) ); if( iCol<0 ){ zType = "INTEGER"; zOrigCol = "rowid"; }else{ zOrigCol = pTab->aCol[iCol].zCnName; zType = sqlite3ColumnType(&pTab->aCol[iCol],0); } zOrigTab = pTab->zName; if( pNC->pParse && pTab->pSchema ){ int iDb = sqlite3SchemaToIndex(pNC->pParse->db, pTab->pSchema); zOrigDb = pNC->pParse->db->aDb[iDb].zDbSName; } |
︙ | ︙ | |||
1730 1731 1732 1733 1734 1735 1736 | #ifndef SQLITE_OMIT_SUBQUERY case TK_SELECT: { /* The expression is a sub-select. Return the declaration type and ** origin info for the single column in the result set of the SELECT ** statement. */ NameContext sNC; | > > > | | < | 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 | #ifndef SQLITE_OMIT_SUBQUERY case TK_SELECT: { /* The expression is a sub-select. Return the declaration type and ** origin info for the single column in the result set of the SELECT ** statement. */ NameContext sNC; Select *pS; Expr *p; assert( ExprUseXSelect(pExpr) ); pS = pExpr->x.pSelect; p = pS->pEList->a[0].pExpr; sNC.pSrcList = pS->pSrc; sNC.pNext = pNC; sNC.pParse = pNC->pParse; zType = columnType(&sNC, p, &zOrigDb, &zOrigTab, &zOrigCol); break; } #endif |
︙ | ︙ | |||
1824 1825 1826 1827 1828 1829 1830 | ** result column name is just the table column ** name: COLUMN. Otherwise use zSpan. ** ** full=ON, short=ANY: If the result refers directly to a table column, ** then the result column name with the table name ** prefix, ex: TABLE.COLUMN. Otherwise use zSpan. */ | | | 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 | ** result column name is just the table column ** name: COLUMN. Otherwise use zSpan. ** ** full=ON, short=ANY: If the result refers directly to a table column, ** then the result column name with the table name ** prefix, ex: TABLE.COLUMN. Otherwise use zSpan. */ void sqlite3GenerateColumnNames( Parse *pParse, /* Parser context */ Select *pSelect /* Generate column names for this SELECT statement */ ){ Vdbe *v = pParse->pVdbe; int i; Table *pTab; SrcList *pTabList; |
︙ | ︙ | |||
1861 1862 1863 1864 1865 1866 1867 | srcName = (db->flags & SQLITE_ShortColNames)!=0 || fullName; sqlite3VdbeSetNumCols(v, pEList->nExpr); for(i=0; i<pEList->nExpr; i++){ Expr *p = pEList->a[i].pExpr; assert( p!=0 ); assert( p->op!=TK_AGG_COLUMN ); /* Agg processing has not run yet */ | | > | | | | | 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 | srcName = (db->flags & SQLITE_ShortColNames)!=0 || fullName; sqlite3VdbeSetNumCols(v, pEList->nExpr); for(i=0; i<pEList->nExpr; i++){ Expr *p = pEList->a[i].pExpr; assert( p!=0 ); assert( p->op!=TK_AGG_COLUMN ); /* Agg processing has not run yet */ assert( p->op!=TK_COLUMN || (ExprUseYTab(p) && p->y.pTab!=0) ); /* Covering idx not yet coded */ if( pEList->a[i].zEName && pEList->a[i].eEName==ENAME_NAME ){ /* An AS clause always takes first priority */ char *zName = pEList->a[i].zEName; sqlite3VdbeSetColName(v, i, COLNAME_NAME, zName, SQLITE_TRANSIENT); }else if( srcName && p->op==TK_COLUMN ){ char *zCol; int iCol = p->iColumn; pTab = p->y.pTab; assert( pTab!=0 ); if( iCol<0 ) iCol = pTab->iPKey; assert( iCol==-1 || (iCol>=0 && iCol<pTab->nCol) ); if( iCol<0 ){ zCol = "rowid"; }else{ zCol = pTab->aCol[iCol].zCnName; } if( fullName ){ char *zName = 0; zName = sqlite3MPrintf(db, "%s.%s", pTab->zName, zCol); sqlite3VdbeSetColName(v, i, COLNAME_NAME, zName, SQLITE_DYNAMIC); }else{ sqlite3VdbeSetColName(v, i, COLNAME_NAME, zCol, SQLITE_TRANSIENT); } }else{ const char *z = pEList->a[i].zEName; z = z==0 ? sqlite3MPrintf(db, "column%d", i+1) : sqlite3DbStrDup(db, z); sqlite3VdbeSetColName(v, i, COLNAME_NAME, z, SQLITE_DYNAMIC); } } generateColumnTypes(pParse, pTabList, pEList); } |
︙ | ︙ | |||
1914 1915 1916 1917 1918 1919 1920 | ** The only guarantee that SQLite makes about column names is that if the ** column has an AS clause assigning it a name, that will be the name used. ** That is the only documented guarantee. However, countless applications ** developed over the years have made baseless assumptions about column names ** and will break if those assumptions changes. Hence, use extreme caution ** when modifying this routine to avoid breaking legacy. ** | | > | | | | < | > > > < < | | | | | > | | 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 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 | ** The only guarantee that SQLite makes about column names is that if the ** column has an AS clause assigning it a name, that will be the name used. ** That is the only documented guarantee. However, countless applications ** developed over the years have made baseless assumptions about column names ** and will break if those assumptions changes. Hence, use extreme caution ** when modifying this routine to avoid breaking legacy. ** ** See Also: sqlite3GenerateColumnNames() */ int sqlite3ColumnsFromExprList( Parse *pParse, /* Parsing context */ ExprList *pEList, /* Expr list from which to derive column names */ i16 *pnCol, /* Write the number of columns here */ Column **paCol /* Write the new column list here */ ){ sqlite3 *db = pParse->db; /* Database connection */ int i, j; /* Loop counters */ u32 cnt; /* Index added to make the name unique */ Column *aCol, *pCol; /* For looping over result columns */ int nCol; /* Number of columns in the result set */ char *zName; /* Column name */ int nName; /* Size of name in zName[] */ Hash ht; /* Hash table of column names */ Table *pTab; sqlite3HashInit(&ht); if( pEList ){ nCol = pEList->nExpr; aCol = sqlite3DbMallocZero(db, sizeof(aCol[0])*nCol); testcase( aCol==0 ); if( NEVER(nCol>32767) ) nCol = 32767; }else{ nCol = 0; aCol = 0; } assert( nCol==(i16)nCol ); *pnCol = nCol; *paCol = aCol; for(i=0, pCol=aCol; i<nCol && !db->mallocFailed; i++, pCol++){ /* Get an appropriate name for the column */ if( (zName = pEList->a[i].zEName)!=0 && pEList->a[i].eEName==ENAME_NAME ){ /* If the column contains an "AS <name>" phrase, use <name> as the name */ }else{ Expr *pColExpr = sqlite3ExprSkipCollateAndLikely(pEList->a[i].pExpr); while( ALWAYS(pColExpr!=0) && pColExpr->op==TK_DOT ){ pColExpr = pColExpr->pRight; assert( pColExpr!=0 ); } if( pColExpr->op==TK_COLUMN && ALWAYS( ExprUseYTab(pColExpr) ) && (pTab = pColExpr->y.pTab)!=0 ){ /* For columns use the column name name */ int iCol = pColExpr->iColumn; if( iCol<0 ) iCol = pTab->iPKey; zName = iCol>=0 ? pTab->aCol[iCol].zCnName : "rowid"; }else if( pColExpr->op==TK_ID ){ assert( !ExprHasProperty(pColExpr, EP_IntValue) ); zName = pColExpr->u.zToken; }else{ /* Use the original text of the column expression as its name */ zName = pEList->a[i].zEName; } } if( zName && !sqlite3IsTrueOrFalse(zName) ){ zName = sqlite3DbStrDup(db, zName); }else{ zName = sqlite3MPrintf(db,"column%d",i+1); } /* Make sure the column name is unique. If the name is not unique, ** append an integer to the name so that it becomes unique. */ cnt = 0; while( zName && sqlite3HashFind(&ht, zName)!=0 ){ nName = sqlite3Strlen30(zName); if( nName>0 ){ for(j=nName-1; j>0 && sqlite3Isdigit(zName[j]); j--){} if( zName[j]==':' ) nName = j; } zName = sqlite3MPrintf(db, "%.*z:%u", nName, zName, ++cnt); if( cnt>3 ) sqlite3FastRandomness(&db->sPrng, sizeof(cnt), &cnt); } pCol->zCnName = zName; pCol->hName = sqlite3StrIHash(zName); sqlite3ColumnPropertiesFromName(0, pCol); if( zName && sqlite3HashInsert(&ht, zName, pCol)==pCol ){ sqlite3OomFault(db); } } sqlite3HashClear(&ht); if( db->mallocFailed ){ for(j=0; j<i; j++){ sqlite3DbFree(db, aCol[j].zCnName); } sqlite3DbFree(db, aCol); *paCol = 0; *pnCol = 0; return SQLITE_NOMEM_BKPT; } return SQLITE_OK; |
︙ | ︙ | |||
2024 2025 2026 2027 2028 2029 2030 | ** ** This routine requires that all identifiers in the SELECT ** statement be resolved. */ void sqlite3SelectAddColumnTypeAndCollation( Parse *pParse, /* Parsing contexts */ Table *pTab, /* Add column type information to this table */ | | > | > | | | | > > > | | > | | > < < < < | | 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 | ** ** This routine requires that all identifiers in the SELECT ** statement be resolved. */ void sqlite3SelectAddColumnTypeAndCollation( Parse *pParse, /* Parsing contexts */ Table *pTab, /* Add column type information to this table */ Select *pSelect, /* SELECT used to determine types and collations */ char aff /* Default affinity for columns */ ){ sqlite3 *db = pParse->db; NameContext sNC; Column *pCol; CollSeq *pColl; int i; Expr *p; struct ExprList_item *a; assert( pSelect!=0 ); assert( (pSelect->selFlags & SF_Resolved)!=0 ); assert( pTab->nCol==pSelect->pEList->nExpr || db->mallocFailed ); if( db->mallocFailed ) return; memset(&sNC, 0, sizeof(sNC)); sNC.pSrcList = pSelect->pSrc; a = pSelect->pEList->a; for(i=0, pCol=pTab->aCol; i<pTab->nCol; i++, pCol++){ const char *zType; i64 n, m; pTab->tabFlags |= (pCol->colFlags & COLFLAG_NOINSERT); p = a[i].pExpr; zType = columnType(&sNC, p, 0, 0, 0); /* pCol->szEst = ... // Column size est for SELECT tables never used */ pCol->affinity = sqlite3ExprAffinity(p); if( zType ){ m = sqlite3Strlen30(zType); n = sqlite3Strlen30(pCol->zCnName); pCol->zCnName = sqlite3DbReallocOrFree(db, pCol->zCnName, n+m+2); if( pCol->zCnName ){ memcpy(&pCol->zCnName[n+1], zType, m+1); pCol->colFlags |= COLFLAG_HASTYPE; }else{ testcase( pCol->colFlags & COLFLAG_HASTYPE ); pCol->colFlags &= ~(COLFLAG_HASTYPE|COLFLAG_HASCOLL); } } if( pCol->affinity<=SQLITE_AFF_NONE ) pCol->affinity = aff; pColl = sqlite3ExprCollSeq(pParse, p); if( pColl ){ assert( pTab->pIndex==0 ); sqlite3ColumnSetColl(db, pCol, pColl->zName); } } pTab->szTabRow = 1; /* Any non-zero value works */ } /* ** Given a SELECT statement, generate a Table structure that describes ** the result set of that SELECT. */ Table *sqlite3ResultSetOfSelect(Parse *pParse, Select *pSelect, char aff){ Table *pTab; sqlite3 *db = pParse->db; u64 savedFlags; savedFlags = db->flags; db->flags &= ~(u64)SQLITE_FullColNames; db->flags |= SQLITE_ShortColNames; sqlite3SelectPrep(pParse, pSelect, 0); db->flags = savedFlags; if( pParse->nErr ) return 0; while( pSelect->pPrior ) pSelect = pSelect->pPrior; pTab = sqlite3DbMallocZero(db, sizeof(Table) ); if( pTab==0 ){ return 0; } pTab->nTabRef = 1; pTab->zName = 0; pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) ); sqlite3ColumnsFromExprList(pParse, pSelect->pEList, &pTab->nCol, &pTab->aCol); sqlite3SelectAddColumnTypeAndCollation(pParse, pTab, pSelect, aff); pTab->iPKey = -1; if( db->mallocFailed ){ sqlite3DeleteTable(db, pTab); return 0; } return pTab; } |
︙ | ︙ | |||
2227 2228 2229 2230 2231 2232 2233 | ** ** Space to hold the KeyInfo structure is obtained from malloc. The calling ** function is responsible for ensuring that this structure is eventually ** freed. */ static KeyInfo *multiSelectOrderByKeyInfo(Parse *pParse, Select *p, int nExtra){ ExprList *pOrderBy = p->pOrderBy; | | | | 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 | ** ** Space to hold the KeyInfo structure is obtained from malloc. The calling ** function is responsible for ensuring that this structure is eventually ** freed. */ static KeyInfo *multiSelectOrderByKeyInfo(Parse *pParse, Select *p, int nExtra){ ExprList *pOrderBy = p->pOrderBy; int nOrderBy = ALWAYS(pOrderBy!=0) ? pOrderBy->nExpr : 0; sqlite3 *db = pParse->db; KeyInfo *pRet = sqlite3KeyInfoAlloc(db, nOrderBy+nExtra, 1); if( pRet ){ int i; for(i=0; i<nOrderBy; i++){ struct ExprList_item *pItem = &pOrderBy->a[i]; Expr *pTerm = pItem->pExpr; CollSeq *pColl; if( pTerm->flags & EP_Collate ){ pColl = sqlite3ExprCollSeq(pParse, pTerm); }else{ pColl = multiSelectCollSeq(pParse, p, pItem->u.x.iOrderByCol-1); if( pColl==0 ) pColl = db->pDfltColl; pOrderBy->a[i].pExpr = sqlite3ExprAddCollateString(pParse, pTerm, pColl->zName); } assert( sqlite3KeyInfoIsWriteable(pRet) ); pRet->aColl[i] = pColl; pRet->aSortFlags[i] = pOrderBy->a[i].sortFlags; } } return pRet; } #ifndef SQLITE_OMIT_CTE |
︙ | ︙ | |||
2299 2300 2301 2302 2303 2304 2305 | Parse *pParse, /* Parsing context */ Select *p, /* The recursive SELECT to be coded */ SelectDest *pDest /* What to do with query results */ ){ SrcList *pSrc = p->pSrc; /* The FROM clause of the recursive query */ int nCol = p->pEList->nExpr; /* Number of columns in the recursive table */ Vdbe *v = pParse->pVdbe; /* The prepared statement under construction */ | | > | 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 | Parse *pParse, /* Parsing context */ Select *p, /* The recursive SELECT to be coded */ SelectDest *pDest /* What to do with query results */ ){ SrcList *pSrc = p->pSrc; /* The FROM clause of the recursive query */ int nCol = p->pEList->nExpr; /* Number of columns in the recursive table */ Vdbe *v = pParse->pVdbe; /* The prepared statement under construction */ Select *pSetup; /* The setup query */ Select *pFirstRec; /* Left-most recursive term */ int addrTop; /* Top of the loop */ int addrCont, addrBreak; /* CONTINUE and BREAK addresses */ int iCurrent = 0; /* The Current table */ int regCurrent; /* Register holding Current table */ int iQueue; /* The Queue table */ int iDistinct = 0; /* To ensure unique results if UNION */ int eDest = SRT_Fifo; /* How to write to Queue */ |
︙ | ︙ | |||
2325 2326 2327 2328 2329 2330 2331 | } #endif /* Obtain authorization to do a recursive query */ if( sqlite3AuthCheck(pParse, SQLITE_RECURSIVE, 0, 0, 0) ) return; /* Process the LIMIT and OFFSET clauses, if they exist */ | | | 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 | } #endif /* Obtain authorization to do a recursive query */ if( sqlite3AuthCheck(pParse, SQLITE_RECURSIVE, 0, 0, 0) ) return; /* Process the LIMIT and OFFSET clauses, if they exist */ addrBreak = sqlite3VdbeMakeLabel(pParse); p->nSelectRow = 320; /* 4 billion rows */ computeLimitRegisters(pParse, p, addrBreak); pLimit = p->pLimit; regLimit = p->iLimit; regOffset = p->iOffset; p->pLimit = 0; p->iLimit = p->iOffset = 0; |
︙ | ︙ | |||
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 | if( iDistinct ){ p->addrOpenEphm[0] = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, iDistinct, 0); p->selFlags |= SF_UsesEphemeral; } /* Detach the ORDER BY clause from the compound SELECT */ p->pOrderBy = 0; /* Store the results of the setup-query in Queue. */ pSetup->pNext = 0; ExplainQueryPlan((pParse, 1, "SETUP")); rc = sqlite3Select(pParse, pSetup, &destQueue); pSetup->pNext = p; if( rc ) goto end_of_recursive_query; /* Find the next row in the Queue and output that row */ addrTop = sqlite3VdbeAddOp2(v, OP_Rewind, iQueue, addrBreak); VdbeCoverage(v); /* Transfer the next row in Queue over to Current */ sqlite3VdbeAddOp1(v, OP_NullRow, iCurrent); /* To reset column cache */ if( pOrderBy ){ sqlite3VdbeAddOp3(v, OP_Column, iQueue, pOrderBy->nExpr+1, regCurrent); }else{ sqlite3VdbeAddOp2(v, OP_RowData, iQueue, regCurrent); } sqlite3VdbeAddOp1(v, OP_Delete, iQueue); /* Output the single row in Current */ | > > > > > > > > > > > > > > > > > | < < < | | | | | < | 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 | if( iDistinct ){ p->addrOpenEphm[0] = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, iDistinct, 0); p->selFlags |= SF_UsesEphemeral; } /* Detach the ORDER BY clause from the compound SELECT */ p->pOrderBy = 0; /* Figure out how many elements of the compound SELECT are part of the ** recursive query. Make sure no recursive elements use aggregate ** functions. Mark the recursive elements as UNION ALL even if they ** are really UNION because the distinctness will be enforced by the ** iDistinct table. pFirstRec is left pointing to the left-most ** recursive term of the CTE. */ for(pFirstRec=p; ALWAYS(pFirstRec!=0); pFirstRec=pFirstRec->pPrior){ if( pFirstRec->selFlags & SF_Aggregate ){ sqlite3ErrorMsg(pParse, "recursive aggregate queries not supported"); goto end_of_recursive_query; } pFirstRec->op = TK_ALL; if( (pFirstRec->pPrior->selFlags & SF_Recursive)==0 ) break; } /* Store the results of the setup-query in Queue. */ pSetup = pFirstRec->pPrior; pSetup->pNext = 0; ExplainQueryPlan((pParse, 1, "SETUP")); rc = sqlite3Select(pParse, pSetup, &destQueue); pSetup->pNext = p; if( rc ) goto end_of_recursive_query; /* Find the next row in the Queue and output that row */ addrTop = sqlite3VdbeAddOp2(v, OP_Rewind, iQueue, addrBreak); VdbeCoverage(v); /* Transfer the next row in Queue over to Current */ sqlite3VdbeAddOp1(v, OP_NullRow, iCurrent); /* To reset column cache */ if( pOrderBy ){ sqlite3VdbeAddOp3(v, OP_Column, iQueue, pOrderBy->nExpr+1, regCurrent); }else{ sqlite3VdbeAddOp2(v, OP_RowData, iQueue, regCurrent); } sqlite3VdbeAddOp1(v, OP_Delete, iQueue); /* Output the single row in Current */ addrCont = sqlite3VdbeMakeLabel(pParse); codeOffset(v, regOffset, addrCont); selectInnerLoop(pParse, p, iCurrent, 0, 0, pDest, addrCont, addrBreak); if( regLimit ){ sqlite3VdbeAddOp2(v, OP_DecrJumpZero, regLimit, addrBreak); VdbeCoverage(v); } sqlite3VdbeResolveLabel(v, addrCont); /* Execute the recursive SELECT taking the single row in Current as ** the value for the recursive-table. Store the results in the Queue. */ pFirstRec->pPrior = 0; ExplainQueryPlan((pParse, 1, "RECURSIVE STEP")); sqlite3Select(pParse, p, &destQueue); assert( pFirstRec->pPrior==0 ); pFirstRec->pPrior = pSetup; /* Keep running the loop until the Queue is empty */ sqlite3VdbeGoto(v, addrTop); sqlite3VdbeResolveLabel(v, addrBreak); end_of_recursive_query: sqlite3ExprListDelete(pParse->db, p->pOrderBy); |
︙ | ︙ | |||
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 | int rc = 0; int bShowAll = p->pLimit==0; assert( p->selFlags & SF_MultiValue ); do{ assert( p->selFlags & SF_Values ); assert( p->op==TK_ALL || (p->op==TK_SELECT && p->pPrior==0) ); assert( p->pNext==0 || p->pEList->nExpr==p->pNext->pEList->nExpr ); if( p->pPrior==0 ) break; assert( p->pPrior->pNext==p ); p = p->pPrior; nRow += bShowAll; }while(1); ExplainQueryPlan((pParse, 0, "SCAN %d CONSTANT ROW%s", nRow, nRow==1 ? "" : "S")); while( p ){ selectInnerLoop(pParse, p, -1, 0, 0, pDest, 1, 1); if( !bShowAll ) break; p->nSelectRow = nRow; p = p->pNext; } return rc; } /* ** This routine is called to process a compound query form from ** two or more separate queries using UNION, UNION ALL, EXCEPT, or ** INTERSECT ** ** "p" points to the right-most of the two queries. the query on the | > > > > > > > > > > > > > | 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 | int rc = 0; int bShowAll = p->pLimit==0; assert( p->selFlags & SF_MultiValue ); do{ assert( p->selFlags & SF_Values ); assert( p->op==TK_ALL || (p->op==TK_SELECT && p->pPrior==0) ); assert( p->pNext==0 || p->pEList->nExpr==p->pNext->pEList->nExpr ); #ifndef SQLITE_OMIT_WINDOWFUNC if( p->pWin ) return -1; #endif if( p->pPrior==0 ) break; assert( p->pPrior->pNext==p ); p = p->pPrior; nRow += bShowAll; }while(1); ExplainQueryPlan((pParse, 0, "SCAN %d CONSTANT ROW%s", nRow, nRow==1 ? "" : "S")); while( p ){ selectInnerLoop(pParse, p, -1, 0, 0, pDest, 1, 1); if( !bShowAll ) break; p->nSelectRow = nRow; p = p->pNext; } return rc; } /* ** Return true if the SELECT statement which is known to be the recursive ** part of a recursive CTE still has its anchor terms attached. If the ** anchor terms have already been removed, then return false. */ static int hasAnchor(Select *p){ while( p && (p->selFlags & SF_Recursive)!=0 ){ p = p->pPrior; } return p!=0; } /* ** This routine is called to process a compound query form from ** two or more separate queries using UNION, UNION ALL, EXCEPT, or ** INTERSECT ** ** "p" points to the right-most of the two queries. the query on the |
︙ | ︙ | |||
2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 | sqlite3 *db; /* Database connection */ /* Make sure there is no ORDER BY or LIMIT clause on prior SELECTs. Only ** the last (right-most) SELECT in the series may have an ORDER BY or LIMIT. */ assert( p && p->pPrior ); /* Calling function guarantees this much */ assert( (p->selFlags & SF_Recursive)==0 || p->op==TK_ALL || p->op==TK_UNION ); db = pParse->db; pPrior = p->pPrior; dest = *pDest; | > | < | < < < | > | | 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 | sqlite3 *db; /* Database connection */ /* Make sure there is no ORDER BY or LIMIT clause on prior SELECTs. Only ** the last (right-most) SELECT in the series may have an ORDER BY or LIMIT. */ assert( p && p->pPrior ); /* Calling function guarantees this much */ assert( (p->selFlags & SF_Recursive)==0 || p->op==TK_ALL || p->op==TK_UNION ); assert( p->selFlags & SF_Compound ); db = pParse->db; pPrior = p->pPrior; dest = *pDest; assert( pPrior->pOrderBy==0 ); assert( pPrior->pLimit==0 ); v = sqlite3GetVdbe(pParse); assert( v!=0 ); /* The VDBE already created by calling function */ /* Create the destination temporary table if necessary */ if( dest.eDest==SRT_EphemTab ){ assert( p->pEList ); sqlite3VdbeAddOp2(v, OP_OpenEphemeral, dest.iSDParm, p->pEList->nExpr); dest.eDest = SRT_Table; } /* Special handling for a compound-select that originates as a VALUES clause. */ if( p->selFlags & SF_MultiValue ){ rc = multiSelectValues(pParse, p, &dest); if( rc>=0 ) goto multi_select_end; rc = SQLITE_OK; } /* Make sure all SELECTs in the statement have the same number of elements ** in their result sets. */ assert( p->pEList && pPrior->pEList ); assert( p->pEList->nExpr==pPrior->pEList->nExpr ); #ifndef SQLITE_OMIT_CTE if( (p->selFlags & SF_Recursive)!=0 && hasAnchor(p) ){ generateWithRecursiveQuery(pParse, p, &dest); }else #endif /* Compound SELECTs that have an ORDER BY clause are handled separately. */ if( p->pOrderBy ){ |
︙ | ︙ | |||
2588 2589 2590 2591 2592 2593 2594 | #endif /* Generate code for the left and right SELECT statements. */ switch( p->op ){ case TK_ALL: { int addr = 0; | | > | > | | | 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 | #endif /* Generate code for the left and right SELECT statements. */ switch( p->op ){ case TK_ALL: { int addr = 0; int nLimit = 0; /* Initialize to suppress harmless compiler warning */ assert( !pPrior->pLimit ); pPrior->iLimit = p->iLimit; pPrior->iOffset = p->iOffset; pPrior->pLimit = p->pLimit; SELECTTRACE(1, pParse, p, ("multiSelect UNION ALL left...\n")); rc = sqlite3Select(pParse, pPrior, &dest); pPrior->pLimit = 0; if( rc ){ goto multi_select_end; } p->pPrior = 0; p->iLimit = pPrior->iLimit; p->iOffset = pPrior->iOffset; if( p->iLimit ){ addr = sqlite3VdbeAddOp1(v, OP_IfNot, p->iLimit); VdbeCoverage(v); VdbeComment((v, "Jump ahead if LIMIT reached")); if( p->iOffset ){ sqlite3VdbeAddOp3(v, OP_OffsetLimit, p->iLimit, p->iOffset+1, p->iOffset); } } ExplainQueryPlan((pParse, 1, "UNION ALL")); SELECTTRACE(1, pParse, p, ("multiSelect UNION ALL right...\n")); rc = sqlite3Select(pParse, p, &dest); testcase( rc!=SQLITE_OK ); pDelete = p->pPrior; p->pPrior = pPrior; p->nSelectRow = sqlite3LogEstAdd(p->nSelectRow, pPrior->nSelectRow); if( p->pLimit && sqlite3ExprIsInteger(p->pLimit->pLeft, &nLimit) && nLimit>0 && p->nSelectRow > sqlite3LogEst((u64)nLimit) ){ p->nSelectRow = sqlite3LogEst((u64)nLimit); } if( addr ){ sqlite3VdbeJumpHere(v, addr); } |
︙ | ︙ | |||
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 | assert( p->pOrderBy==0 ); addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, unionTab, 0); assert( p->addrOpenEphm[0] == -1 ); p->addrOpenEphm[0] = addr; findRightmost(p)->selFlags |= SF_UsesEphemeral; assert( p->pEList ); } /* Code the SELECT statements to our left */ assert( !pPrior->pOrderBy ); sqlite3SelectDestInit(&uniondest, priorOp, unionTab); rc = sqlite3Select(pParse, pPrior, &uniondest); if( rc ){ goto multi_select_end; } /* Code the current SELECT statement */ if( p->op==TK_EXCEPT ){ op = SRT_Except; }else{ assert( p->op==TK_UNION ); op = SRT_Union; } p->pPrior = 0; pLimit = p->pLimit; p->pLimit = 0; uniondest.eDest = op; ExplainQueryPlan((pParse, 1, "%s USING TEMP B-TREE", | > > | > < < | > | < | | | 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 | assert( p->pOrderBy==0 ); addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, unionTab, 0); assert( p->addrOpenEphm[0] == -1 ); p->addrOpenEphm[0] = addr; findRightmost(p)->selFlags |= SF_UsesEphemeral; assert( p->pEList ); } /* Code the SELECT statements to our left */ assert( !pPrior->pOrderBy ); sqlite3SelectDestInit(&uniondest, priorOp, unionTab); SELECTTRACE(1, pParse, p, ("multiSelect EXCEPT/UNION left...\n")); rc = sqlite3Select(pParse, pPrior, &uniondest); if( rc ){ goto multi_select_end; } /* Code the current SELECT statement */ if( p->op==TK_EXCEPT ){ op = SRT_Except; }else{ assert( p->op==TK_UNION ); op = SRT_Union; } p->pPrior = 0; pLimit = p->pLimit; p->pLimit = 0; uniondest.eDest = op; ExplainQueryPlan((pParse, 1, "%s USING TEMP B-TREE", sqlite3SelectOpName(p->op))); SELECTTRACE(1, pParse, p, ("multiSelect EXCEPT/UNION right...\n")); rc = sqlite3Select(pParse, p, &uniondest); testcase( rc!=SQLITE_OK ); assert( p->pOrderBy==0 ); pDelete = p->pPrior; p->pPrior = pPrior; p->pOrderBy = 0; if( p->op==TK_UNION ){ p->nSelectRow = sqlite3LogEstAdd(p->nSelectRow, pPrior->nSelectRow); } sqlite3ExprDelete(db, p->pLimit); p->pLimit = pLimit; p->iLimit = 0; p->iOffset = 0; /* Convert the data in the temporary table into whatever form ** it is that we currently need. */ assert( unionTab==dest.iSDParm || dest.eDest!=priorOp ); assert( p->pEList || db->mallocFailed ); if( dest.eDest!=priorOp && db->mallocFailed==0 ){ int iCont, iBreak, iStart; iBreak = sqlite3VdbeMakeLabel(pParse); iCont = sqlite3VdbeMakeLabel(pParse); computeLimitRegisters(pParse, p, iBreak); sqlite3VdbeAddOp2(v, OP_Rewind, unionTab, iBreak); VdbeCoverage(v); iStart = sqlite3VdbeCurrentAddr(v); selectInnerLoop(pParse, p, unionTab, 0, 0, &dest, iCont, iBreak); sqlite3VdbeResolveLabel(v, iCont); sqlite3VdbeAddOp2(v, OP_Next, unionTab, iStart); VdbeCoverage(v); |
︙ | ︙ | |||
2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 | p->addrOpenEphm[0] = addr; findRightmost(p)->selFlags |= SF_UsesEphemeral; assert( p->pEList ); /* Code the SELECTs to our left into temporary table "tab1". */ sqlite3SelectDestInit(&intersectdest, SRT_Union, tab1); rc = sqlite3Select(pParse, pPrior, &intersectdest); if( rc ){ goto multi_select_end; } /* Code the current SELECT into temporary table "tab2" */ addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, tab2, 0); assert( p->addrOpenEphm[1] == -1 ); p->addrOpenEphm[1] = addr; p->pPrior = 0; pLimit = p->pLimit; p->pLimit = 0; intersectdest.iSDParm = tab2; ExplainQueryPlan((pParse, 1, "%s USING TEMP B-TREE", | > | > > | | | 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 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 | p->addrOpenEphm[0] = addr; findRightmost(p)->selFlags |= SF_UsesEphemeral; assert( p->pEList ); /* Code the SELECTs to our left into temporary table "tab1". */ sqlite3SelectDestInit(&intersectdest, SRT_Union, tab1); SELECTTRACE(1, pParse, p, ("multiSelect INTERSECT left...\n")); rc = sqlite3Select(pParse, pPrior, &intersectdest); if( rc ){ goto multi_select_end; } /* Code the current SELECT into temporary table "tab2" */ addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, tab2, 0); assert( p->addrOpenEphm[1] == -1 ); p->addrOpenEphm[1] = addr; p->pPrior = 0; pLimit = p->pLimit; p->pLimit = 0; intersectdest.iSDParm = tab2; ExplainQueryPlan((pParse, 1, "%s USING TEMP B-TREE", sqlite3SelectOpName(p->op))); SELECTTRACE(1, pParse, p, ("multiSelect INTERSECT right...\n")); rc = sqlite3Select(pParse, p, &intersectdest); testcase( rc!=SQLITE_OK ); pDelete = p->pPrior; p->pPrior = pPrior; if( p->nSelectRow>pPrior->nSelectRow ){ p->nSelectRow = pPrior->nSelectRow; } sqlite3ExprDelete(db, p->pLimit); p->pLimit = pLimit; /* Generate code to take the intersection of the two temporary ** tables. */ if( rc ) break; assert( p->pEList ); iBreak = sqlite3VdbeMakeLabel(pParse); iCont = sqlite3VdbeMakeLabel(pParse); computeLimitRegisters(pParse, p, iBreak); sqlite3VdbeAddOp2(v, OP_Rewind, tab1, iBreak); VdbeCoverage(v); r1 = sqlite3GetTempReg(pParse); iStart = sqlite3VdbeAddOp2(v, OP_RowData, tab1, r1); sqlite3VdbeAddOp4Int(v, OP_NotFound, tab2, iCont, r1, 0); VdbeCoverage(v); sqlite3ReleaseTempReg(pParse, r1); |
︙ | ︙ | |||
2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 | #ifndef SQLITE_OMIT_EXPLAIN if( p->pNext==0 ){ ExplainQueryPlanPop(pParse); } #endif } /* Compute collating sequences used by ** temporary tables needed to implement the compound select. ** Attach the KeyInfo structure to all temporary tables. ** ** This section is run by the right-most SELECT statement only. ** SELECT statements to the left always skip this part. The right-most ** SELECT might also skip this part if it has no ORDER BY clause and ** no temp tables are required. */ if( p->selFlags & SF_UsesEphemeral ){ int i; /* Loop counter */ KeyInfo *pKeyInfo; /* Collating sequence for the result set */ Select *pLoop; /* For looping through SELECT statements */ CollSeq **apColl; /* For looping through pKeyInfo->aColl[] */ int nCol; /* Number of columns in result set */ assert( p->pNext==0 ); nCol = p->pEList->nExpr; pKeyInfo = sqlite3KeyInfoAlloc(db, nCol, 1); if( !pKeyInfo ){ rc = SQLITE_NOMEM_BKPT; goto multi_select_end; } for(i=0, apColl=pKeyInfo->aColl; i<nCol; i++, apColl++){ | > > | 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 | #ifndef SQLITE_OMIT_EXPLAIN if( p->pNext==0 ){ ExplainQueryPlanPop(pParse); } #endif } if( pParse->nErr ) goto multi_select_end; /* Compute collating sequences used by ** temporary tables needed to implement the compound select. ** Attach the KeyInfo structure to all temporary tables. ** ** This section is run by the right-most SELECT statement only. ** SELECT statements to the left always skip this part. The right-most ** SELECT might also skip this part if it has no ORDER BY clause and ** no temp tables are required. */ if( p->selFlags & SF_UsesEphemeral ){ int i; /* Loop counter */ KeyInfo *pKeyInfo; /* Collating sequence for the result set */ Select *pLoop; /* For looping through SELECT statements */ CollSeq **apColl; /* For looping through pKeyInfo->aColl[] */ int nCol; /* Number of columns in result set */ assert( p->pNext==0 ); assert( p->pEList!=0 ); nCol = p->pEList->nExpr; pKeyInfo = sqlite3KeyInfoAlloc(db, nCol, 1); if( !pKeyInfo ){ rc = SQLITE_NOMEM_BKPT; goto multi_select_end; } for(i=0, apColl=pKeyInfo->aColl; i<nCol; i++, apColl++){ |
︙ | ︙ | |||
2850 2851 2852 2853 2854 2855 2856 | } sqlite3KeyInfoUnref(pKeyInfo); } multi_select_end: pDest->iSdst = dest.iSdst; pDest->nSdst = dest.nSdst; | > > | > > | > | 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 3062 3063 3064 3065 3066 3067 | } sqlite3KeyInfoUnref(pKeyInfo); } multi_select_end: pDest->iSdst = dest.iSdst; pDest->nSdst = dest.nSdst; if( pDelete ){ sqlite3ParserAddCleanup(pParse, (void(*)(sqlite3*,void*))sqlite3SelectDelete, pDelete); } return rc; } #endif /* SQLITE_OMIT_COMPOUND_SELECT */ /* ** Error message for when two or more terms of a compound select have different ** size result sets. */ void sqlite3SelectWrongNumTermsError(Parse *pParse, Select *p){ if( p->selFlags & SF_Values ){ sqlite3ErrorMsg(pParse, "all VALUES must have the same number of terms"); }else{ sqlite3ErrorMsg(pParse, "SELECTs to the left and right of %s" " do not have the same number of result columns", sqlite3SelectOpName(p->op)); } } /* ** Code an output subroutine for a coroutine implementation of a ** SELECT statment. ** |
︙ | ︙ | |||
2903 2904 2905 2906 2907 2908 2909 | int iBreak /* Jump here if we hit the LIMIT */ ){ Vdbe *v = pParse->pVdbe; int iContinue; int addr; addr = sqlite3VdbeCurrentAddr(v); | | | 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 | int iBreak /* Jump here if we hit the LIMIT */ ){ Vdbe *v = pParse->pVdbe; int iContinue; int addr; addr = sqlite3VdbeCurrentAddr(v); iContinue = sqlite3VdbeMakeLabel(pParse); /* Suppress duplicates for UNION, EXCEPT, and INTERSECT */ if( regPrev ){ int addr1, addr2; addr1 = sqlite3VdbeAddOp1(v, OP_IfNot, regPrev); VdbeCoverage(v); addr2 = sqlite3VdbeAddOp4(v, OP_Compare, pIn->iSdst, regPrev+1, pIn->nSdst, |
︙ | ︙ | |||
2957 2958 2959 2960 2961 2962 2963 | pIn->iSdst, pIn->nSdst); sqlite3ReleaseTempReg(pParse, r1); break; } /* If this is a scalar select that is part of an expression, then ** store the results in the appropriate memory cell and break out | | > | | | 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 | pIn->iSdst, pIn->nSdst); sqlite3ReleaseTempReg(pParse, r1); break; } /* If this is a scalar select that is part of an expression, then ** store the results in the appropriate memory cell and break out ** of the scan loop. Note that the select might return multiple columns ** if it is the RHS of a row-value IN operator. */ case SRT_Mem: { testcase( pIn->nSdst>1 ); sqlite3ExprCodeMove(pParse, pIn->iSdst, pDest->iSDParm, pIn->nSdst); /* The LIMIT clause will jump out of the loop for us */ break; } #endif /* #ifndef SQLITE_OMIT_SUBQUERY */ /* The results are stored in a sequence of registers ** starting at pDest->iSdst. Then the co-routine yields. |
︙ | ︙ | |||
3133 3134 3135 3136 3137 3138 3139 | int addr1; /* Jump instructions that get retargetted */ int op; /* One of TK_ALL, TK_UNION, TK_EXCEPT, TK_INTERSECT */ KeyInfo *pKeyDup = 0; /* Comparison information for duplicate removal */ KeyInfo *pKeyMerge; /* Comparison information for merging rows */ sqlite3 *db; /* Database connection */ ExprList *pOrderBy; /* The ORDER BY clause */ int nOrderBy; /* Number of terms in the ORDER BY clause */ | | | | > | 3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 | int addr1; /* Jump instructions that get retargetted */ int op; /* One of TK_ALL, TK_UNION, TK_EXCEPT, TK_INTERSECT */ KeyInfo *pKeyDup = 0; /* Comparison information for duplicate removal */ KeyInfo *pKeyMerge; /* Comparison information for merging rows */ sqlite3 *db; /* Database connection */ ExprList *pOrderBy; /* The ORDER BY clause */ int nOrderBy; /* Number of terms in the ORDER BY clause */ u32 *aPermute; /* Mapping from ORDER BY terms to result set columns */ assert( p->pOrderBy!=0 ); assert( pKeyDup==0 ); /* "Managed" code needs this. Ticket #3382. */ db = pParse->db; v = pParse->pVdbe; assert( v!=0 ); /* Already thrown the error if VDBE alloc failed */ labelEnd = sqlite3VdbeMakeLabel(pParse); labelCmpr = sqlite3VdbeMakeLabel(pParse); /* Patch up the ORDER BY clause */ op = p->op; pPrior = p->pPrior; assert( pPrior->pOrderBy==0 ); pOrderBy = p->pOrderBy; assert( pOrderBy ); nOrderBy = pOrderBy->nExpr; /* For operators other than UNION ALL we have to make sure that ** the ORDER BY clause covers every term of the result set. Add ** terms to the ORDER BY clause as necessary. */ if( op!=TK_ALL ){ for(i=1; db->mallocFailed==0 && i<=p->pEList->nExpr; i++){ struct ExprList_item *pItem; for(j=0, pItem=pOrderBy->a; j<nOrderBy; j++, pItem++){ assert( pItem!=0 ); assert( pItem->u.x.iOrderByCol>0 ); if( pItem->u.x.iOrderByCol==i ) break; } if( j==nOrderBy ){ Expr *pNew = sqlite3Expr(db, TK_INTEGER, 0); if( pNew==0 ) return SQLITE_NOMEM_BKPT; pNew->flags |= EP_IntValue; |
︙ | ︙ | |||
3182 3183 3184 3185 3186 3187 3188 | /* Compute the comparison permutation and keyinfo that is used with ** the permutation used to determine if the next ** row of results comes from selectA or selectB. Also add explicit ** collations to the ORDER BY clause terms so that when the subqueries ** to the right and the left are evaluated, they use the correct ** collation. */ | | > | 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 3392 | /* Compute the comparison permutation and keyinfo that is used with ** the permutation used to determine if the next ** row of results comes from selectA or selectB. Also add explicit ** collations to the ORDER BY clause terms so that when the subqueries ** to the right and the left are evaluated, they use the correct ** collation. */ aPermute = sqlite3DbMallocRawNN(db, sizeof(u32)*(nOrderBy + 1)); if( aPermute ){ struct ExprList_item *pItem; aPermute[0] = nOrderBy; for(i=1, pItem=pOrderBy->a; i<=nOrderBy; i++, pItem++){ assert( pItem!=0 ); assert( pItem->u.x.iOrderByCol>0 ); assert( pItem->u.x.iOrderByCol<=p->pEList->nExpr ); aPermute[i] = pItem->u.x.iOrderByCol - 1; } pKeyMerge = multiSelectOrderByKeyInfo(pParse, p, 1); }else{ pKeyMerge = 0; |
︙ | ︙ | |||
3218 3219 3220 3221 3222 3223 3224 | pParse->nMem += nExpr+1; sqlite3VdbeAddOp2(v, OP_Integer, 0, regPrev); pKeyDup = sqlite3KeyInfoAlloc(db, nExpr, 1); if( pKeyDup ){ assert( sqlite3KeyInfoIsWriteable(pKeyDup) ); for(i=0; i<nExpr; i++){ pKeyDup->aColl[i] = multiSelectCollSeq(pParse, p, i); | | | 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 3424 | pParse->nMem += nExpr+1; sqlite3VdbeAddOp2(v, OP_Integer, 0, regPrev); pKeyDup = sqlite3KeyInfoAlloc(db, nExpr, 1); if( pKeyDup ){ assert( sqlite3KeyInfoIsWriteable(pKeyDup) ); for(i=0; i<nExpr; i++){ pKeyDup->aColl[i] = multiSelectCollSeq(pParse, p, i); pKeyDup->aSortFlags[i] = 0; } } } /* Separate the left and the right query from one another */ p->pPrior = 0; |
︙ | ︙ | |||
3253 3254 3255 3256 3257 3258 3259 | regAddrA = ++pParse->nMem; regAddrB = ++pParse->nMem; regOutA = ++pParse->nMem; regOutB = ++pParse->nMem; sqlite3SelectDestInit(&destA, SRT_Coroutine, regAddrA); sqlite3SelectDestInit(&destB, SRT_Coroutine, regAddrB); | | | 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458 3459 | regAddrA = ++pParse->nMem; regAddrB = ++pParse->nMem; regOutA = ++pParse->nMem; regOutB = ++pParse->nMem; sqlite3SelectDestInit(&destA, SRT_Coroutine, regAddrA); sqlite3SelectDestInit(&destB, SRT_Coroutine, regAddrB); ExplainQueryPlan((pParse, 1, "MERGE (%s)", sqlite3SelectOpName(p->op))); /* Generate a coroutine to evaluate the SELECT statement to the ** left of the compound operator - the "A" select. */ addrSelectA = sqlite3VdbeCurrentAddr(v) + 1; addr1 = sqlite3VdbeAddOp3(v, OP_InitCoroutine, regAddrA, 0, addrSelectA); VdbeComment((v, "left SELECT")); |
︙ | ︙ | |||
3386 3387 3388 3389 3390 3391 3392 3393 3394 3395 3396 3397 3398 3399 | /* Reassembly the compound query so that it will be freed correctly ** by the calling function */ if( p->pPrior ){ sqlite3SelectDelete(db, p->pPrior); } p->pPrior = pPrior; pPrior->pNext = p; /*** TBD: Insert subroutine calls to close cursors on incomplete **** subqueries ****/ ExplainQueryPlanPop(pParse); return pParse->nErr!=0; } #endif | > > > | 3578 3579 3580 3581 3582 3583 3584 3585 3586 3587 3588 3589 3590 3591 3592 3593 3594 | /* Reassembly the compound query so that it will be freed correctly ** by the calling function */ if( p->pPrior ){ sqlite3SelectDelete(db, p->pPrior); } p->pPrior = pPrior; pPrior->pNext = p; sqlite3ExprListDelete(db, pPrior->pOrderBy); pPrior->pOrderBy = 0; /*** TBD: Insert subroutine calls to close cursors on incomplete **** subqueries ****/ ExplainQueryPlanPop(pParse); return pParse->nErr!=0; } #endif |
︙ | ︙ | |||
3437 3438 3439 3440 3441 3442 3443 | ){ if( pExpr==0 ) return 0; if( ExprHasProperty(pExpr, EP_FromJoin) && pExpr->iRightJoinTable==pSubst->iTable ){ pExpr->iRightJoinTable = pSubst->iNewTable; } | | > > > > | > > > > > > > | | | < > > > > > > > > > > | > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 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 3882 3883 | ){ if( pExpr==0 ) return 0; if( ExprHasProperty(pExpr, EP_FromJoin) && pExpr->iRightJoinTable==pSubst->iTable ){ pExpr->iRightJoinTable = pSubst->iNewTable; } if( pExpr->op==TK_COLUMN && pExpr->iTable==pSubst->iTable && !ExprHasProperty(pExpr, EP_FixedCol) ){ #ifdef SQLITE_ALLOW_ROWID_IN_VIEW if( pExpr->iColumn<0 ){ pExpr->op = TK_NULL; }else #endif { Expr *pNew; Expr *pCopy = pSubst->pEList->a[pExpr->iColumn].pExpr; Expr ifNullRow; assert( pSubst->pEList!=0 && pExpr->iColumn<pSubst->pEList->nExpr ); assert( pExpr->pRight==0 ); if( sqlite3ExprIsVector(pCopy) ){ sqlite3VectorErrorMsg(pSubst->pParse, pCopy); }else{ sqlite3 *db = pSubst->pParse->db; if( pSubst->isLeftJoin && pCopy->op!=TK_COLUMN ){ memset(&ifNullRow, 0, sizeof(ifNullRow)); ifNullRow.op = TK_IF_NULL_ROW; ifNullRow.pLeft = pCopy; ifNullRow.iTable = pSubst->iNewTable; ifNullRow.flags = EP_IfNullRow; pCopy = &ifNullRow; } testcase( ExprHasProperty(pCopy, EP_Subquery) ); pNew = sqlite3ExprDup(db, pCopy, 0); if( db->mallocFailed ){ sqlite3ExprDelete(db, pNew); return pExpr; } if( pSubst->isLeftJoin ){ ExprSetProperty(pNew, EP_CanBeNull); } if( ExprHasProperty(pExpr,EP_FromJoin) ){ sqlite3SetJoinExpr(pNew, pExpr->iRightJoinTable); } sqlite3ExprDelete(db, pExpr); pExpr = pNew; /* Ensure that the expression now has an implicit collation sequence, ** just as it did when it was a column of a view or sub-query. */ if( pExpr->op!=TK_COLUMN && pExpr->op!=TK_COLLATE ){ CollSeq *pColl = sqlite3ExprCollSeq(pSubst->pParse, pExpr); pExpr = sqlite3ExprAddCollateString(pSubst->pParse, pExpr, (pColl ? pColl->zName : "BINARY") ); } ExprClearProperty(pExpr, EP_Collate); } } }else{ if( pExpr->op==TK_IF_NULL_ROW && pExpr->iTable==pSubst->iTable ){ pExpr->iTable = pSubst->iNewTable; } pExpr->pLeft = substExpr(pSubst, pExpr->pLeft); pExpr->pRight = substExpr(pSubst, pExpr->pRight); if( ExprUseXSelect(pExpr) ){ substSelect(pSubst, pExpr->x.pSelect, 1); }else{ substExprList(pSubst, pExpr->x.pList); } #ifndef SQLITE_OMIT_WINDOWFUNC if( ExprHasProperty(pExpr, EP_WinFunc) ){ Window *pWin = pExpr->y.pWin; pWin->pFilter = substExpr(pSubst, pWin->pFilter); substExprList(pSubst, pWin->pPartition); substExprList(pSubst, pWin->pOrderBy); } #endif } return pExpr; } static void substExprList( SubstContext *pSubst, /* Description of the substitution */ ExprList *pList /* List to scan and in which to make substitutes */ ){ int i; if( pList==0 ) return; for(i=0; i<pList->nExpr; i++){ pList->a[i].pExpr = substExpr(pSubst, pList->a[i].pExpr); } } static void substSelect( SubstContext *pSubst, /* Description of the substitution */ Select *p, /* SELECT statement in which to make substitutions */ int doPrior /* Do substitutes on p->pPrior too */ ){ SrcList *pSrc; SrcItem *pItem; int i; if( !p ) return; do{ substExprList(pSubst, p->pEList); substExprList(pSubst, p->pGroupBy); substExprList(pSubst, p->pOrderBy); p->pHaving = substExpr(pSubst, p->pHaving); p->pWhere = substExpr(pSubst, p->pWhere); pSrc = p->pSrc; assert( pSrc!=0 ); for(i=pSrc->nSrc, pItem=pSrc->a; i>0; i--, pItem++){ substSelect(pSubst, pItem->pSelect, 1); if( pItem->fg.isTabFunc ){ substExprList(pSubst, pItem->u1.pFuncArg); } } }while( doPrior && (p = p->pPrior)!=0 ); } #endif /* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */ #if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) /* ** pSelect is a SELECT statement and pSrcItem is one item in the FROM ** clause of that SELECT. ** ** This routine scans the entire SELECT statement and recomputes the ** pSrcItem->colUsed mask. */ static int recomputeColumnsUsedExpr(Walker *pWalker, Expr *pExpr){ SrcItem *pItem; if( pExpr->op!=TK_COLUMN ) return WRC_Continue; pItem = pWalker->u.pSrcItem; if( pItem->iCursor!=pExpr->iTable ) return WRC_Continue; if( pExpr->iColumn<0 ) return WRC_Continue; pItem->colUsed |= sqlite3ExprColUsed(pExpr); return WRC_Continue; } static void recomputeColumnsUsed( Select *pSelect, /* The complete SELECT statement */ SrcItem *pSrcItem /* Which FROM clause item to recompute */ ){ Walker w; if( NEVER(pSrcItem->pTab==0) ) return; memset(&w, 0, sizeof(w)); w.xExprCallback = recomputeColumnsUsedExpr; w.xSelectCallback = sqlite3SelectWalkNoop; w.u.pSrcItem = pSrcItem; pSrcItem->colUsed = 0; sqlite3WalkSelect(&w, pSelect); } #endif /* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */ #if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) /* ** Assign new cursor numbers to each of the items in pSrc. For each ** new cursor number assigned, set an entry in the aCsrMap[] array ** to map the old cursor number to the new: ** ** aCsrMap[iOld+1] = iNew; ** ** The array is guaranteed by the caller to be large enough for all ** existing cursor numbers in pSrc. aCsrMap[0] is the array size. ** ** If pSrc contains any sub-selects, call this routine recursively ** on the FROM clause of each such sub-select, with iExcept set to -1. */ static void srclistRenumberCursors( Parse *pParse, /* Parse context */ int *aCsrMap, /* Array to store cursor mappings in */ SrcList *pSrc, /* FROM clause to renumber */ int iExcept /* FROM clause item to skip */ ){ int i; SrcItem *pItem; for(i=0, pItem=pSrc->a; i<pSrc->nSrc; i++, pItem++){ if( i!=iExcept ){ Select *p; assert( pItem->iCursor < aCsrMap[0] ); if( !pItem->fg.isRecursive || aCsrMap[pItem->iCursor+1]==0 ){ aCsrMap[pItem->iCursor+1] = pParse->nTab++; } pItem->iCursor = aCsrMap[pItem->iCursor+1]; for(p=pItem->pSelect; p; p=p->pPrior){ srclistRenumberCursors(pParse, aCsrMap, p->pSrc, -1); } } } } /* ** *piCursor is a cursor number. Change it if it needs to be mapped. */ static void renumberCursorDoMapping(Walker *pWalker, int *piCursor){ int *aCsrMap = pWalker->u.aiCol; int iCsr = *piCursor; if( iCsr < aCsrMap[0] && aCsrMap[iCsr+1]>0 ){ *piCursor = aCsrMap[iCsr+1]; } } /* ** Expression walker callback used by renumberCursors() to update ** Expr objects to match newly assigned cursor numbers. */ static int renumberCursorsCb(Walker *pWalker, Expr *pExpr){ int op = pExpr->op; if( op==TK_COLUMN || op==TK_IF_NULL_ROW ){ renumberCursorDoMapping(pWalker, &pExpr->iTable); } if( ExprHasProperty(pExpr, EP_FromJoin) ){ renumberCursorDoMapping(pWalker, &pExpr->iRightJoinTable); } return WRC_Continue; } /* ** Assign a new cursor number to each cursor in the FROM clause (Select.pSrc) ** of the SELECT statement passed as the second argument, and to each ** cursor in the FROM clause of any FROM clause sub-selects, recursively. ** Except, do not assign a new cursor number to the iExcept'th element in ** the FROM clause of (*p). Update all expressions and other references ** to refer to the new cursor numbers. ** ** Argument aCsrMap is an array that may be used for temporary working ** space. Two guarantees are made by the caller: ** ** * the array is larger than the largest cursor number used within the ** select statement passed as an argument, and ** ** * the array entries for all cursor numbers that do *not* appear in ** FROM clauses of the select statement as described above are ** initialized to zero. */ static void renumberCursors( Parse *pParse, /* Parse context */ Select *p, /* Select to renumber cursors within */ int iExcept, /* FROM clause item to skip */ int *aCsrMap /* Working space */ ){ Walker w; srclistRenumberCursors(pParse, aCsrMap, p->pSrc, iExcept); memset(&w, 0, sizeof(w)); w.u.aiCol = aCsrMap; w.xExprCallback = renumberCursorsCb; w.xSelectCallback = sqlite3SelectWalkNoop; sqlite3WalkSelect(&w, p); } #endif /* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */ #if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) /* ** This routine attempts to flatten subqueries as a performance optimization. ** This routine returns 1 if it makes changes and 0 if no flattening occurs. |
︙ | ︙ | |||
3566 3567 3568 3569 3570 3571 3572 3573 3574 3575 3576 3577 3578 3579 | ** from 2015-02-09.) ** ** (3) If the subquery is the right operand of a LEFT JOIN then ** (3a) the subquery may not be a join and ** (3b) the FROM clause of the subquery may not contain a virtual ** table and ** (3c) the outer query may not be an aggregate. ** ** (4) The subquery can not be DISTINCT. ** ** (**) At one point restrictions (4) and (5) defined a subset of DISTINCT ** sub-queries that were excluded from this optimization. Restriction ** (4) has since been expanded to exclude all DISTINCT subqueries. ** | > | 3918 3919 3920 3921 3922 3923 3924 3925 3926 3927 3928 3929 3930 3931 3932 | ** from 2015-02-09.) ** ** (3) If the subquery is the right operand of a LEFT JOIN then ** (3a) the subquery may not be a join and ** (3b) the FROM clause of the subquery may not contain a virtual ** table and ** (3c) the outer query may not be an aggregate. ** (3d) the outer query may not be DISTINCT. ** ** (4) The subquery can not be DISTINCT. ** ** (**) At one point restrictions (4) and (5) defined a subset of DISTINCT ** sub-queries that were excluded from this optimization. Restriction ** (4) has since been expanded to exclude all DISTINCT subqueries. ** |
︙ | ︙ | |||
3614 3615 3616 3617 3618 3619 3620 | ** (17) If the subquery is a compound select, then ** (17a) all compound operators must be a UNION ALL, and ** (17b) no terms within the subquery compound may be aggregate ** or DISTINCT, and ** (17c) every term within the subquery compound must have a FROM clause ** (17d) the outer query may not be ** (17d1) aggregate, or | | > | | | < | | | 3967 3968 3969 3970 3971 3972 3973 3974 3975 3976 3977 3978 3979 3980 3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994 3995 3996 3997 3998 3999 4000 4001 4002 4003 4004 4005 4006 4007 4008 4009 4010 4011 4012 4013 4014 4015 4016 4017 | ** (17) If the subquery is a compound select, then ** (17a) all compound operators must be a UNION ALL, and ** (17b) no terms within the subquery compound may be aggregate ** or DISTINCT, and ** (17c) every term within the subquery compound must have a FROM clause ** (17d) the outer query may not be ** (17d1) aggregate, or ** (17d2) DISTINCT ** (17e) the subquery may not contain window functions, and ** (17f) the subquery must not be the RHS of a LEFT JOIN. ** ** The parent and sub-query may contain WHERE clauses. Subject to ** rules (11), (13) and (14), they may also contain ORDER BY, ** LIMIT and OFFSET clauses. The subquery cannot use any compound ** operator other than UNION ALL because all the other compound ** operators have an implied DISTINCT which is disallowed by ** restriction (4). ** ** Also, each component of the sub-query must return the same number ** of result columns. This is actually a requirement for any compound ** SELECT statement, but all the code here does is make sure that no ** such (illegal) sub-query is flattened. The caller will detect the ** syntax error and return a detailed message. ** ** (18) If the sub-query is a compound select, then all terms of the ** ORDER BY clause of the parent must be copies of a term returned ** by the parent query. ** ** (19) If the subquery uses LIMIT then the outer query may not ** have a WHERE clause. ** ** (20) If the sub-query is a compound select, then it must not use ** an ORDER BY clause. Ticket #3773. We could relax this constraint ** somewhat by saying that the terms of the ORDER BY clause must ** appear as unmodified result columns in the outer query. But we ** have other optimizations in mind to deal with that case. ** ** (21) If the subquery uses LIMIT then the outer query may not be ** DISTINCT. (See ticket [752e1646fc]). ** ** (22) The subquery may not be a recursive CTE. ** ** (23) If the outer query is a recursive CTE, then the sub-query may not be ** a compound query. This restriction is because transforming the ** parent to a compound query confuses the code that handles ** recursive queries in multiSelect(). ** ** (**) We no longer attempt to flatten aggregate subqueries. Was: ** The subquery may not be an aggregate that uses the built-in min() or ** or max() functions. (Without this restriction, a query like: ** "SELECT x FROM (SELECT max(y), x FROM t1)" would not necessarily |
︙ | ︙ | |||
3692 3693 3694 3695 3696 3697 3698 | SrcList *pSrc; /* The FROM clause of the outer query */ SrcList *pSubSrc; /* The FROM clause of the subquery */ int iParent; /* VDBE cursor number of the pSub result set temp table */ int iNewParent = -1;/* Replacement table for iParent */ int isLeftJoin = 0; /* True if pSub is the right side of a LEFT JOIN */ int i; /* Loop counter */ Expr *pWhere; /* The WHERE clause */ | | > > | 4045 4046 4047 4048 4049 4050 4051 4052 4053 4054 4055 4056 4057 4058 4059 4060 4061 4062 | SrcList *pSrc; /* The FROM clause of the outer query */ SrcList *pSubSrc; /* The FROM clause of the subquery */ int iParent; /* VDBE cursor number of the pSub result set temp table */ int iNewParent = -1;/* Replacement table for iParent */ int isLeftJoin = 0; /* True if pSub is the right side of a LEFT JOIN */ int i; /* Loop counter */ Expr *pWhere; /* The WHERE clause */ SrcItem *pSubitem; /* The subquery */ sqlite3 *db = pParse->db; Walker w; /* Walker to persist agginfo data */ int *aCsrMap = 0; /* Check to see if flattening is permitted. Return 0 if not. */ assert( p!=0 ); assert( p->pPrior==0 ); if( OptimizationDisabled(db, SQLITE_QueryFlattener) ) return 0; pSrc = p->pSrc; |
︙ | ︙ | |||
3762 3763 3764 3765 3766 3767 3768 | ** aggregates are processed - there is no mechanism to determine if ** the LEFT JOIN table should be all-NULL. ** ** See also tickets #306, #350, and #3300. */ if( (pSubitem->fg.jointype & JT_OUTER)!=0 ){ isLeftJoin = 1; | > > | < > > | 4117 4118 4119 4120 4121 4122 4123 4124 4125 4126 4127 4128 4129 4130 4131 4132 4133 4134 4135 | ** aggregates are processed - there is no mechanism to determine if ** the LEFT JOIN table should be all-NULL. ** ** See also tickets #306, #350, and #3300. */ if( (pSubitem->fg.jointype & JT_OUTER)!=0 ){ isLeftJoin = 1; if( pSubSrc->nSrc>1 /* (3a) */ || isAgg /* (3b) */ || IsVirtual(pSubSrc->a[0].pTab) /* (3c) */ || (p->selFlags & SF_Distinct)!=0 /* (3d) */ ){ return 0; } } #ifdef SQLITE_EXTRA_IFNULLROW else if( iFrom>0 && !isAgg ){ /* Setting isLeftJoin to -1 causes OP_IfNullRow opcodes to be generated for ** every reference to any result column from subquery in a join, even |
︙ | ︙ | |||
3786 3787 3788 3789 3790 3791 3792 | ** that make up the compound SELECT are allowed to be aggregate or distinct ** queries. */ if( pSub->pPrior ){ if( pSub->pOrderBy ){ return 0; /* Restriction (20) */ } | | | > > > > | < | < < < < < | > > > > > > > > > > > > > > > > > > | 4144 4145 4146 4147 4148 4149 4150 4151 4152 4153 4154 4155 4156 4157 4158 4159 4160 4161 4162 4163 4164 4165 4166 4167 4168 4169 4170 4171 4172 4173 4174 4175 4176 4177 4178 4179 4180 4181 4182 4183 4184 4185 4186 4187 4188 4189 4190 4191 4192 4193 4194 4195 4196 4197 4198 4199 4200 4201 4202 4203 4204 4205 4206 4207 4208 4209 4210 4211 4212 4213 4214 4215 4216 | ** that make up the compound SELECT are allowed to be aggregate or distinct ** queries. */ if( pSub->pPrior ){ if( pSub->pOrderBy ){ return 0; /* Restriction (20) */ } if( isAgg || (p->selFlags & SF_Distinct)!=0 || isLeftJoin>0 ){ return 0; /* (17d1), (17d2), or (17f) */ } for(pSub1=pSub; pSub1; pSub1=pSub1->pPrior){ testcase( (pSub1->selFlags & (SF_Distinct|SF_Aggregate))==SF_Distinct ); testcase( (pSub1->selFlags & (SF_Distinct|SF_Aggregate))==SF_Aggregate ); assert( pSub->pSrc!=0 ); assert( (pSub->selFlags & SF_Recursive)==0 ); assert( pSub->pEList->nExpr==pSub1->pEList->nExpr ); if( (pSub1->selFlags & (SF_Distinct|SF_Aggregate))!=0 /* (17b) */ || (pSub1->pPrior && pSub1->op!=TK_ALL) /* (17a) */ || pSub1->pSrc->nSrc<1 /* (17c) */ #ifndef SQLITE_OMIT_WINDOWFUNC || pSub1->pWin /* (17e) */ #endif ){ return 0; } testcase( pSub1->pSrc->nSrc>1 ); } /* Restriction (18). */ if( p->pOrderBy ){ int ii; for(ii=0; ii<p->pOrderBy->nExpr; ii++){ if( p->pOrderBy->a[ii].u.x.iOrderByCol==0 ) return 0; } } /* Restriction (23) */ if( (p->selFlags & SF_Recursive) ) return 0; if( pSrc->nSrc>1 ){ if( pParse->nSelect>500 ) return 0; aCsrMap = sqlite3DbMallocZero(db, ((i64)pParse->nTab+1)*sizeof(int)); if( aCsrMap ) aCsrMap[0] = pParse->nTab; } } /***** If we reach this point, flattening is permitted. *****/ SELECTTRACE(1,pParse,p,("flatten %u.%p from term %d\n", pSub->selId, pSub, iFrom)); /* Authorize the subquery */ pParse->zAuthContext = pSubitem->zName; TESTONLY(i =) sqlite3AuthCheck(pParse, SQLITE_SELECT, 0, 0, 0); testcase( i==SQLITE_DENY ); pParse->zAuthContext = zSavedAuthContext; /* Delete the transient structures associated with thesubquery */ pSub1 = pSubitem->pSelect; sqlite3DbFree(db, pSubitem->zDatabase); sqlite3DbFree(db, pSubitem->zName); sqlite3DbFree(db, pSubitem->zAlias); pSubitem->zDatabase = 0; pSubitem->zName = 0; pSubitem->zAlias = 0; pSubitem->pSelect = 0; assert( pSubitem->pOn==0 ); /* If the sub-query is a compound SELECT statement, then (by restrictions ** 17 and 18 above) it must be a UNION ALL and the parent query must ** be of the form: ** ** SELECT <expr-list> FROM (<sub-query>) <where-clause> ** |
︙ | ︙ | |||
3868 3869 3870 3871 3872 3873 3874 3875 | ** We call this the "compound-subquery flattening". */ for(pSub=pSub->pPrior; pSub; pSub=pSub->pPrior){ Select *pNew; ExprList *pOrderBy = p->pOrderBy; Expr *pLimit = p->pLimit; Select *pPrior = p->pPrior; p->pOrderBy = 0; | > > < < > > > > > < < < < < < | | < < < < | < < | < | > > > > | | > > < | | < < < < < < | | < | < | < > | 4242 4243 4244 4245 4246 4247 4248 4249 4250 4251 4252 4253 4254 4255 4256 4257 4258 4259 4260 4261 4262 4263 4264 4265 4266 4267 4268 4269 4270 4271 4272 4273 4274 4275 4276 4277 4278 4279 4280 4281 4282 4283 4284 4285 4286 4287 4288 4289 4290 4291 4292 4293 4294 4295 4296 4297 4298 4299 4300 4301 4302 4303 4304 4305 4306 4307 4308 4309 4310 4311 4312 4313 4314 4315 4316 4317 4318 4319 4320 4321 4322 4323 4324 4325 4326 4327 4328 4329 4330 4331 4332 4333 4334 4335 4336 4337 4338 4339 4340 4341 4342 4343 4344 4345 4346 4347 4348 4349 4350 4351 4352 4353 | ** We call this the "compound-subquery flattening". */ for(pSub=pSub->pPrior; pSub; pSub=pSub->pPrior){ Select *pNew; ExprList *pOrderBy = p->pOrderBy; Expr *pLimit = p->pLimit; Select *pPrior = p->pPrior; Table *pItemTab = pSubitem->pTab; pSubitem->pTab = 0; p->pOrderBy = 0; p->pPrior = 0; p->pLimit = 0; pNew = sqlite3SelectDup(db, p, 0); p->pLimit = pLimit; p->pOrderBy = pOrderBy; p->op = TK_ALL; pSubitem->pTab = pItemTab; if( pNew==0 ){ p->pPrior = pPrior; }else{ pNew->selId = ++pParse->nSelect; if( aCsrMap && ALWAYS(db->mallocFailed==0) ){ renumberCursors(pParse, pNew, iFrom, aCsrMap); } pNew->pPrior = pPrior; if( pPrior ) pPrior->pNext = pNew; pNew->pNext = p; p->pPrior = pNew; SELECTTRACE(2,pParse,p,("compound-subquery flattener" " creates %u as peer\n",pNew->selId)); } assert( pSubitem->pSelect==0 ); } sqlite3DbFree(db, aCsrMap); if( db->mallocFailed ){ pSubitem->pSelect = pSub1; return 1; } /* Defer deleting the Table object associated with the ** subquery until code generation is ** complete, since there may still exist Expr.pTab entries that ** refer to the subquery even after flattening. Ticket #3346. ** ** pSubitem->pTab is always non-NULL by test restrictions and tests above. */ if( ALWAYS(pSubitem->pTab!=0) ){ Table *pTabToDel = pSubitem->pTab; if( pTabToDel->nTabRef==1 ){ Parse *pToplevel = sqlite3ParseToplevel(pParse); sqlite3ParserAddCleanup(pToplevel, (void(*)(sqlite3*,void*))sqlite3DeleteTable, pTabToDel); testcase( pToplevel->earlyCleanup ); }else{ pTabToDel->nTabRef--; } pSubitem->pTab = 0; } /* The following loop runs once for each term in a compound-subquery ** flattening (as described above). If we are doing a different kind ** of flattening - a flattening other than a compound-subquery flattening - ** then this loop only runs once. ** ** This loop moves all of the FROM elements of the subquery into the ** the FROM clause of the outer query. Before doing this, remember ** the cursor number for the original outer query FROM element in ** iParent. The iParent cursor will never be used. Subsequent code ** will scan expressions looking for iParent references and replace ** those references with expressions that resolve to the subquery FROM ** elements we are now copying in. */ pSub = pSub1; for(pParent=p; pParent; pParent=pParent->pPrior, pSub=pSub->pPrior){ int nSubSrc; u8 jointype = 0; assert( pSub!=0 ); pSubSrc = pSub->pSrc; /* FROM clause of subquery */ nSubSrc = pSubSrc->nSrc; /* Number of terms in subquery FROM clause */ pSrc = pParent->pSrc; /* FROM clause of the outer query */ if( pParent==p ){ jointype = pSubitem->fg.jointype; /* First time through the loop */ } /* The subquery uses a single slot of the FROM clause of the outer ** query. If the subquery has more than one element in its FROM clause, ** then expand the outer query to make space for it to hold all elements ** of the subquery. ** ** Example: ** ** SELECT * FROM tabA, (SELECT * FROM sub1, sub2), tabB; ** ** The outer query has 3 slots in its FROM clause. One slot of the ** outer query (the middle slot) is used by the subquery. The next ** block of code will expand the outer query FROM clause to 4 slots. ** The middle slot is expanded to two slots in order to make space ** for the two elements in the FROM clause of the subquery. */ if( nSubSrc>1 ){ pSrc = sqlite3SrcListEnlarge(pParse, pSrc, nSubSrc-1,iFrom+1); if( pSrc==0 ) break; pParent->pSrc = pSrc; } /* Transfer the FROM clause terms from the subquery into the ** outer query. */ for(i=0; i<nSubSrc; i++){ sqlite3IdListDelete(db, pSrc->a[i+iFrom].pUsing); |
︙ | ︙ | |||
4003 4004 4005 4006 4007 4008 4009 | ** SELECT a+5, b*10 FROM (SELECT x*3 AS a, y+10 AS b FROM t1) WHERE a>b; ** \ \_____________ subquery __________/ / ** \_____________________ outer query ______________________________/ ** ** We look at every expression in the outer query and every place we see ** "a" we substitute "x*3" and every place we see "b" we substitute "y+10". */ | | | 4366 4367 4368 4369 4370 4371 4372 4373 4374 4375 4376 4377 4378 4379 4380 | ** SELECT a+5, b*10 FROM (SELECT x*3 AS a, y+10 AS b FROM t1) WHERE a>b; ** \ \_____________ subquery __________/ / ** \_____________________ outer query ______________________________/ ** ** We look at every expression in the outer query and every place we see ** "a" we substitute "x*3" and every place we see "b" we substitute "y+10". */ if( pSub->pOrderBy && (pParent->selFlags & SF_NoopOrderBy)==0 ){ /* At this point, any non-zero iOrderByCol values indicate that the ** ORDER BY column expression is identical to the iOrderByCol'th ** expression returned by SELECT statement pSub. Since these values ** do not necessarily correspond to columns in SELECT statement pParent, ** zero them before transfering the ORDER BY clause. ** ** Not doing this may cause an error if a subsequent call to this |
︙ | ︙ | |||
4025 4026 4027 4028 4029 4030 4031 | assert( pParent->pOrderBy==0 ); pParent->pOrderBy = pOrderBy; pSub->pOrderBy = 0; } pWhere = pSub->pWhere; pSub->pWhere = 0; if( isLeftJoin>0 ){ | | > > > > | > > | | < | > > > > > > > > > > > | > > > > | | | > > > > > > > > | | | | > > > < | | < < < < | < > | < < < < | | > | | | > > | > > > > | | > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | < | 4388 4389 4390 4391 4392 4393 4394 4395 4396 4397 4398 4399 4400 4401 4402 4403 4404 4405 4406 4407 4408 4409 4410 4411 4412 4413 4414 4415 4416 4417 4418 4419 4420 4421 4422 4423 4424 4425 4426 4427 4428 4429 4430 4431 4432 4433 4434 4435 4436 4437 4438 4439 4440 4441 4442 4443 4444 4445 4446 4447 4448 4449 4450 4451 4452 4453 4454 4455 4456 4457 4458 4459 4460 4461 4462 4463 4464 4465 4466 4467 4468 4469 4470 4471 4472 4473 4474 4475 4476 4477 4478 4479 4480 4481 4482 4483 4484 4485 4486 4487 4488 4489 4490 4491 4492 4493 4494 4495 4496 4497 4498 4499 4500 4501 4502 4503 4504 4505 4506 4507 4508 4509 4510 4511 4512 4513 4514 4515 4516 4517 4518 4519 4520 4521 4522 4523 4524 4525 4526 4527 4528 4529 4530 4531 4532 4533 4534 4535 4536 4537 4538 4539 4540 4541 4542 4543 4544 4545 4546 4547 4548 4549 4550 4551 4552 4553 4554 4555 4556 4557 4558 4559 4560 4561 4562 4563 4564 4565 4566 4567 4568 4569 4570 4571 4572 4573 4574 4575 4576 4577 4578 4579 4580 4581 4582 4583 4584 4585 4586 4587 4588 4589 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 | assert( pParent->pOrderBy==0 ); pParent->pOrderBy = pOrderBy; pSub->pOrderBy = 0; } pWhere = pSub->pWhere; pSub->pWhere = 0; if( isLeftJoin>0 ){ sqlite3SetJoinExpr(pWhere, iNewParent); } if( pWhere ){ if( pParent->pWhere ){ pParent->pWhere = sqlite3PExpr(pParse, TK_AND, pWhere, pParent->pWhere); }else{ pParent->pWhere = pWhere; } } if( db->mallocFailed==0 ){ SubstContext x; x.pParse = pParse; x.iTable = iParent; x.iNewTable = iNewParent; x.isLeftJoin = isLeftJoin; x.pEList = pSub->pEList; substSelect(&x, pParent, 0); } /* The flattened query is a compound if either the inner or the ** outer query is a compound. */ pParent->selFlags |= pSub->selFlags & SF_Compound; assert( (pSub->selFlags & SF_Distinct)==0 ); /* restriction (17b) */ /* ** SELECT ... FROM (SELECT ... LIMIT a OFFSET b) LIMIT x OFFSET y; ** ** One is tempted to try to add a and b to combine the limits. But this ** does not work if either limit is negative. */ if( pSub->pLimit ){ pParent->pLimit = pSub->pLimit; pSub->pLimit = 0; } /* Recompute the SrcList_item.colUsed masks for the flattened ** tables. */ for(i=0; i<nSubSrc; i++){ recomputeColumnsUsed(pParent, &pSrc->a[i+iFrom]); } } /* Finially, delete what is left of the subquery and return ** success. */ sqlite3AggInfoPersistWalkerInit(&w, pParse); sqlite3WalkSelect(&w,pSub1); sqlite3SelectDelete(db, pSub1); #if SELECTTRACE_ENABLED if( sqlite3SelectTrace & 0x100 ){ SELECTTRACE(0x100,pParse,p,("After flattening:\n")); sqlite3TreeViewSelect(0, p, 0); } #endif return 1; } #endif /* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */ /* ** A structure to keep track of all of the column values that are fixed to ** a known value due to WHERE clause constraints of the form COLUMN=VALUE. */ typedef struct WhereConst WhereConst; struct WhereConst { Parse *pParse; /* Parsing context */ u8 *pOomFault; /* Pointer to pParse->db->mallocFailed */ int nConst; /* Number for COLUMN=CONSTANT terms */ int nChng; /* Number of times a constant is propagated */ int bHasAffBlob; /* At least one column in apExpr[] as affinity BLOB */ Expr **apExpr; /* [i*2] is COLUMN and [i*2+1] is VALUE */ }; /* ** Add a new entry to the pConst object. Except, do not add duplicate ** pColumn entires. Also, do not add if doing so would not be appropriate. ** ** The caller guarantees the pColumn is a column and pValue is a constant. ** This routine has to do some additional checks before completing the ** insert. */ static void constInsert( WhereConst *pConst, /* The WhereConst into which we are inserting */ Expr *pColumn, /* The COLUMN part of the constraint */ Expr *pValue, /* The VALUE part of the constraint */ Expr *pExpr /* Overall expression: COLUMN=VALUE or VALUE=COLUMN */ ){ int i; assert( pColumn->op==TK_COLUMN ); assert( sqlite3ExprIsConstant(pValue) ); if( ExprHasProperty(pColumn, EP_FixedCol) ) return; if( sqlite3ExprAffinity(pValue)!=0 ) return; if( !sqlite3IsBinary(sqlite3ExprCompareCollSeq(pConst->pParse,pExpr)) ){ return; } /* 2018-10-25 ticket [cf5ed20f] ** Make sure the same pColumn is not inserted more than once */ for(i=0; i<pConst->nConst; i++){ const Expr *pE2 = pConst->apExpr[i*2]; assert( pE2->op==TK_COLUMN ); if( pE2->iTable==pColumn->iTable && pE2->iColumn==pColumn->iColumn ){ return; /* Already present. Return without doing anything. */ } } if( sqlite3ExprAffinity(pColumn)==SQLITE_AFF_BLOB ){ pConst->bHasAffBlob = 1; } pConst->nConst++; pConst->apExpr = sqlite3DbReallocOrFree(pConst->pParse->db, pConst->apExpr, pConst->nConst*2*sizeof(Expr*)); if( pConst->apExpr==0 ){ pConst->nConst = 0; }else{ pConst->apExpr[pConst->nConst*2-2] = pColumn; pConst->apExpr[pConst->nConst*2-1] = pValue; } } /* ** Find all terms of COLUMN=VALUE or VALUE=COLUMN in pExpr where VALUE ** is a constant expression and where the term must be true because it ** is part of the AND-connected terms of the expression. For each term ** found, add it to the pConst structure. */ static void findConstInWhere(WhereConst *pConst, Expr *pExpr){ Expr *pRight, *pLeft; if( NEVER(pExpr==0) ) return; if( ExprHasProperty(pExpr, EP_FromJoin) ) return; if( pExpr->op==TK_AND ){ findConstInWhere(pConst, pExpr->pRight); findConstInWhere(pConst, pExpr->pLeft); return; } if( pExpr->op!=TK_EQ ) return; pRight = pExpr->pRight; pLeft = pExpr->pLeft; assert( pRight!=0 ); assert( pLeft!=0 ); if( pRight->op==TK_COLUMN && sqlite3ExprIsConstant(pLeft) ){ constInsert(pConst,pRight,pLeft,pExpr); } if( pLeft->op==TK_COLUMN && sqlite3ExprIsConstant(pRight) ){ constInsert(pConst,pLeft,pRight,pExpr); } } /* ** This is a helper function for Walker callback propagateConstantExprRewrite(). ** ** Argument pExpr is a candidate expression to be replaced by a value. If ** pExpr is equivalent to one of the columns named in pWalker->u.pConst, ** then overwrite it with the corresponding value. Except, do not do so ** if argument bIgnoreAffBlob is non-zero and the affinity of pExpr ** is SQLITE_AFF_BLOB. */ static int propagateConstantExprRewriteOne( WhereConst *pConst, Expr *pExpr, int bIgnoreAffBlob ){ int i; if( pConst->pOomFault[0] ) return WRC_Prune; if( pExpr->op!=TK_COLUMN ) return WRC_Continue; if( ExprHasProperty(pExpr, EP_FixedCol|EP_FromJoin) ){ testcase( ExprHasProperty(pExpr, EP_FixedCol) ); testcase( ExprHasProperty(pExpr, EP_FromJoin) ); return WRC_Continue; } for(i=0; i<pConst->nConst; i++){ Expr *pColumn = pConst->apExpr[i*2]; if( pColumn==pExpr ) continue; if( pColumn->iTable!=pExpr->iTable ) continue; if( pColumn->iColumn!=pExpr->iColumn ) continue; if( bIgnoreAffBlob && sqlite3ExprAffinity(pColumn)==SQLITE_AFF_BLOB ){ break; } /* A match is found. Add the EP_FixedCol property */ pConst->nChng++; ExprClearProperty(pExpr, EP_Leaf); ExprSetProperty(pExpr, EP_FixedCol); assert( pExpr->pLeft==0 ); pExpr->pLeft = sqlite3ExprDup(pConst->pParse->db, pConst->apExpr[i*2+1], 0); if( pConst->pParse->db->mallocFailed ) return WRC_Prune; break; } return WRC_Prune; } /* ** This is a Walker expression callback. pExpr is a node from the WHERE ** clause of a SELECT statement. This function examines pExpr to see if ** any substitutions based on the contents of pWalker->u.pConst should ** be made to pExpr or its immediate children. ** ** A substitution is made if: ** ** + pExpr is a column with an affinity other than BLOB that matches ** one of the columns in pWalker->u.pConst, or ** ** + pExpr is a binary comparison operator (=, <=, >=, <, >) that ** uses an affinity other than TEXT and one of its immediate ** children is a column that matches one of the columns in ** pWalker->u.pConst. */ static int propagateConstantExprRewrite(Walker *pWalker, Expr *pExpr){ WhereConst *pConst = pWalker->u.pConst; assert( TK_GT==TK_EQ+1 ); assert( TK_LE==TK_EQ+2 ); assert( TK_LT==TK_EQ+3 ); assert( TK_GE==TK_EQ+4 ); if( pConst->bHasAffBlob ){ if( (pExpr->op>=TK_EQ && pExpr->op<=TK_GE) || pExpr->op==TK_IS ){ propagateConstantExprRewriteOne(pConst, pExpr->pLeft, 0); if( pConst->pOomFault[0] ) return WRC_Prune; if( sqlite3ExprAffinity(pExpr->pLeft)!=SQLITE_AFF_TEXT ){ propagateConstantExprRewriteOne(pConst, pExpr->pRight, 0); } } } return propagateConstantExprRewriteOne(pConst, pExpr, pConst->bHasAffBlob); } /* ** The WHERE-clause constant propagation optimization. ** ** If the WHERE clause contains terms of the form COLUMN=CONSTANT or ** CONSTANT=COLUMN that are top-level AND-connected terms that are not ** part of a ON clause from a LEFT JOIN, then throughout the query ** replace all other occurrences of COLUMN with CONSTANT. ** ** For example, the query: ** ** SELECT * FROM t1, t2, t3 WHERE t1.a=39 AND t2.b=t1.a AND t3.c=t2.b ** ** Is transformed into ** |
︙ | ︙ | |||
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 4258 4259 4260 4261 4262 | ** is false because it uses text affinity and '0123' is not the same as '123'. ** To work around this, the expression tree is not actually changed from ** "b=a" to "b=123" but rather the "a" in "b=a" is tagged with EP_FixedCol ** and the "123" value is hung off of the pLeft pointer. Code generator ** routines know to generate the constant "123" instead of looking up the ** column value. Also, to avoid collation problems, this optimization is ** only attempted if the "a=123" term uses the default BINARY collation. */ static int propagateConstants( Parse *pParse, /* The parsing context */ Select *p /* The query in which to propagate constants */ ){ WhereConst x; Walker w; int nChng = 0; x.pParse = pParse; do{ x.nConst = 0; x.nChng = 0; x.apExpr = 0; findConstInWhere(&x, p->pWhere); if( x.nConst ){ memset(&w, 0, sizeof(w)); w.pParse = pParse; w.xExprCallback = propagateConstantExprRewrite; w.xSelectCallback = sqlite3SelectWalkNoop; w.xSelectCallback2 = 0; w.walkerDepth = 0; w.u.pConst = &x; sqlite3WalkExpr(&w, p->pWhere); sqlite3DbFree(x.pParse->db, x.apExpr); nChng += x.nChng; } }while( x.nChng ); return nChng; } #if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) /* ** Make copies of relevant WHERE clause terms of the outer query into ** the WHERE clause of subquery. Example: ** ** SELECT * FROM (SELECT a AS x, c-d AS y FROM t1) WHERE x=5 AND y=10; ** | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | ** is false because it uses text affinity and '0123' is not the same as '123'. ** To work around this, the expression tree is not actually changed from ** "b=a" to "b=123" but rather the "a" in "b=a" is tagged with EP_FixedCol ** and the "123" value is hung off of the pLeft pointer. Code generator ** routines know to generate the constant "123" instead of looking up the ** column value. Also, to avoid collation problems, this optimization is ** only attempted if the "a=123" term uses the default BINARY collation. ** ** 2021-05-25 forum post 6a06202608: Another troublesome case is... ** ** CREATE TABLE t1(x); ** INSERT INTO t1 VALUES(10.0); ** SELECT 1 FROM t1 WHERE x=10 AND x LIKE 10; ** ** The query should return no rows, because the t1.x value is '10.0' not '10' ** and '10.0' is not LIKE '10'. But if we are not careful, the first WHERE ** term "x=10" will cause the second WHERE term to become "10 LIKE 10", ** resulting in a false positive. To avoid this, constant propagation for ** columns with BLOB affinity is only allowed if the constant is used with ** operators ==, <=, <, >=, >, or IS in a way that will cause the correct ** type conversions to occur. See logic associated with the bHasAffBlob flag ** for details. */ static int propagateConstants( Parse *pParse, /* The parsing context */ Select *p /* The query in which to propagate constants */ ){ WhereConst x; Walker w; int nChng = 0; x.pParse = pParse; x.pOomFault = &pParse->db->mallocFailed; do{ x.nConst = 0; x.nChng = 0; x.apExpr = 0; x.bHasAffBlob = 0; findConstInWhere(&x, p->pWhere); if( x.nConst ){ memset(&w, 0, sizeof(w)); w.pParse = pParse; w.xExprCallback = propagateConstantExprRewrite; w.xSelectCallback = sqlite3SelectWalkNoop; w.xSelectCallback2 = 0; w.walkerDepth = 0; w.u.pConst = &x; sqlite3WalkExpr(&w, p->pWhere); sqlite3DbFree(x.pParse->db, x.apExpr); nChng += x.nChng; } }while( x.nChng ); return nChng; } #if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) # if !defined(SQLITE_OMIT_WINDOWFUNC) /* ** This function is called to determine whether or not it is safe to ** push WHERE clause expression pExpr down to FROM clause sub-query ** pSubq, which contains at least one window function. Return 1 ** if it is safe and the expression should be pushed down, or 0 ** otherwise. ** ** It is only safe to push the expression down if it consists only ** of constants and copies of expressions that appear in the PARTITION ** BY clause of all window function used by the sub-query. It is safe ** to filter out entire partitions, but not rows within partitions, as ** this may change the results of the window functions. ** ** At the time this function is called it is guaranteed that ** ** * the sub-query uses only one distinct window frame, and ** * that the window frame has a PARTITION BY clase. */ static int pushDownWindowCheck(Parse *pParse, Select *pSubq, Expr *pExpr){ assert( pSubq->pWin->pPartition ); assert( (pSubq->selFlags & SF_MultiPart)==0 ); assert( pSubq->pPrior==0 ); return sqlite3ExprIsConstantOrGroupBy(pParse, pExpr, pSubq->pWin->pPartition); } # endif /* SQLITE_OMIT_WINDOWFUNC */ #endif /* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */ #if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) /* ** Make copies of relevant WHERE clause terms of the outer query into ** the WHERE clause of subquery. Example: ** ** SELECT * FROM (SELECT a AS x, c-d AS y FROM t1) WHERE x=5 AND y=10; ** |
︙ | ︙ | |||
4296 4297 4298 4299 4300 4301 4302 | ** JOIN (SELECT 1 AS b2 UNION ALL SELECT 2) AS bb ON (a1=b2) ** LEFT JOIN (SELECT 8 AS c3 UNION ALL SELECT 9) AS cc ON (b2=2); ** ** The correct answer is three rows: (1,1,NULL),(2,2,8),(2,2,9). ** But if the (b2=2) term were to be pushed down into the bb subquery, ** then the (1,1,NULL) row would be suppressed. ** | | | > | > > > > > > > > > > > > > > | > > > | > > > > | 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 | ** JOIN (SELECT 1 AS b2 UNION ALL SELECT 2) AS bb ON (a1=b2) ** LEFT JOIN (SELECT 8 AS c3 UNION ALL SELECT 9) AS cc ON (b2=2); ** ** The correct answer is three rows: (1,1,NULL),(2,2,8),(2,2,9). ** But if the (b2=2) term were to be pushed down into the bb subquery, ** then the (1,1,NULL) row would be suppressed. ** ** (6) Window functions make things tricky as changes to the WHERE clause ** of the inner query could change the window over which window ** functions are calculated. Therefore, do not attempt the optimization ** if: ** ** (6a) The inner query uses multiple incompatible window partitions. ** ** (6b) The inner query is a compound and uses window-functions. ** ** (6c) The WHERE clause does not consist entirely of constants and ** copies of expressions found in the PARTITION BY clause of ** all window-functions used by the sub-query. It is safe to ** filter out entire partitions, as this does not change the ** window over which any window-function is calculated. ** ** (7) The inner query is a Common Table Expression (CTE) that should ** be materialized. (This restriction is implemented in the calling ** routine.) ** ** Return 0 if no changes are made and non-zero if one or more WHERE clause ** terms are duplicated into the subquery. */ static int pushDownWhereTerms( Parse *pParse, /* Parse context (for malloc() and error reporting) */ Select *pSubq, /* The subquery whose WHERE clause is to be augmented */ Expr *pWhere, /* The WHERE clause of the outer query */ int iCursor, /* Cursor number of the subquery */ int isLeftJoin /* True if pSubq is the right term of a LEFT JOIN */ ){ Expr *pNew; int nChng = 0; if( pWhere==0 ) return 0; if( pSubq->selFlags & (SF_Recursive|SF_MultiPart) ) return 0; #ifndef SQLITE_OMIT_WINDOWFUNC if( pSubq->pPrior ){ Select *pSel; for(pSel=pSubq; pSel; pSel=pSel->pPrior){ if( pSel->pWin ) return 0; /* restriction (6b) */ } }else{ if( pSubq->pWin && pSubq->pWin->pPartition==0 ) return 0; } #endif #ifdef SQLITE_DEBUG /* Only the first term of a compound can have a WITH clause. But make ** sure no other terms are marked SF_Recursive in case something changes ** in the future. */ |
︙ | ︙ | |||
4351 4352 4353 4354 4355 4356 4357 4358 4359 4360 4361 4362 4363 4364 4365 4366 4367 4368 | return 0; /* restriction (4) */ } if( ExprHasProperty(pWhere,EP_FromJoin) && pWhere->iRightJoinTable!=iCursor ){ return 0; /* restriction (5) */ } if( sqlite3ExprIsTableConstant(pWhere, iCursor) ){ nChng++; while( pSubq ){ SubstContext x; pNew = sqlite3ExprDup(pParse->db, pWhere, 0); unsetJoinExpr(pNew, -1); x.pParse = pParse; x.iTable = iCursor; x.iNewTable = iCursor; x.isLeftJoin = 0; x.pEList = pSubq->pEList; pNew = substExpr(&x, pNew); if( pSubq->selFlags & SF_Aggregate ){ | > > > > > > > > > | | | 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 | return 0; /* restriction (4) */ } if( ExprHasProperty(pWhere,EP_FromJoin) && pWhere->iRightJoinTable!=iCursor ){ return 0; /* restriction (5) */ } if( sqlite3ExprIsTableConstant(pWhere, iCursor) ){ nChng++; pSubq->selFlags |= SF_PushDown; while( pSubq ){ SubstContext x; pNew = sqlite3ExprDup(pParse->db, pWhere, 0); unsetJoinExpr(pNew, -1); x.pParse = pParse; x.iTable = iCursor; x.iNewTable = iCursor; x.isLeftJoin = 0; x.pEList = pSubq->pEList; pNew = substExpr(&x, pNew); #ifndef SQLITE_OMIT_WINDOWFUNC if( pSubq->pWin && 0==pushDownWindowCheck(pParse, pSubq, pNew) ){ /* Restriction 6c has prevented push-down in this case */ sqlite3ExprDelete(pParse->db, pNew); nChng--; break; } #endif if( pSubq->selFlags & SF_Aggregate ){ pSubq->pHaving = sqlite3ExprAnd(pParse, pSubq->pHaving, pNew); }else{ pSubq->pWhere = sqlite3ExprAnd(pParse, pSubq->pWhere, pNew); } pSubq = pSubq->pPrior; } } return nChng; } #endif /* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */ |
︙ | ︙ | |||
4391 4392 4393 4394 4395 4396 4397 | ** ** This routine must be called after aggregate functions have been ** located but before their arguments have been subjected to aggregate ** analysis. */ static u8 minMaxQuery(sqlite3 *db, Expr *pFunc, ExprList **ppMinMax){ int eRet = WHERE_ORDERBY_NORMAL; /* Return value */ | | | > > > | > > > > > > > > | > | | | > > > > > > | > | > > < | | | > > | > | > > | < | | | > > > | | | | | | | | | > | < > | 4902 4903 4904 4905 4906 4907 4908 4909 4910 4911 4912 4913 4914 4915 4916 4917 4918 4919 4920 4921 4922 4923 4924 4925 4926 4927 4928 4929 4930 4931 4932 4933 4934 4935 4936 4937 4938 4939 4940 4941 4942 4943 4944 4945 4946 4947 4948 4949 4950 4951 4952 4953 4954 4955 4956 4957 4958 4959 4960 4961 4962 4963 4964 4965 4966 4967 4968 4969 4970 4971 4972 4973 4974 4975 4976 4977 4978 4979 4980 4981 4982 4983 4984 4985 4986 4987 4988 4989 4990 4991 4992 4993 4994 4995 4996 4997 4998 4999 5000 5001 5002 5003 5004 5005 5006 5007 5008 5009 5010 5011 5012 5013 5014 5015 5016 5017 5018 5019 5020 5021 5022 5023 5024 5025 5026 5027 | ** ** This routine must be called after aggregate functions have been ** located but before their arguments have been subjected to aggregate ** analysis. */ static u8 minMaxQuery(sqlite3 *db, Expr *pFunc, ExprList **ppMinMax){ int eRet = WHERE_ORDERBY_NORMAL; /* Return value */ ExprList *pEList; /* Arguments to agg function */ const char *zFunc; /* Name of aggregate function pFunc */ ExprList *pOrderBy; u8 sortFlags = 0; assert( *ppMinMax==0 ); assert( pFunc->op==TK_AGG_FUNCTION ); assert( !IsWindowFunc(pFunc) ); assert( ExprUseXList(pFunc) ); pEList = pFunc->x.pList; if( pEList==0 || pEList->nExpr!=1 || ExprHasProperty(pFunc, EP_WinFunc) || OptimizationDisabled(db, SQLITE_MinMaxOpt) ){ return eRet; } assert( !ExprHasProperty(pFunc, EP_IntValue) ); zFunc = pFunc->u.zToken; if( sqlite3StrICmp(zFunc, "min")==0 ){ eRet = WHERE_ORDERBY_MIN; if( sqlite3ExprCanBeNull(pEList->a[0].pExpr) ){ sortFlags = KEYINFO_ORDER_BIGNULL; } }else if( sqlite3StrICmp(zFunc, "max")==0 ){ eRet = WHERE_ORDERBY_MAX; sortFlags = KEYINFO_ORDER_DESC; }else{ return eRet; } *ppMinMax = pOrderBy = sqlite3ExprListDup(db, pEList, 0); assert( pOrderBy!=0 || db->mallocFailed ); if( pOrderBy ) pOrderBy->a[0].sortFlags = sortFlags; return eRet; } /* ** The select statement passed as the first argument is an aggregate query. ** The second argument is the associated aggregate-info object. This ** function tests if the SELECT is of the form: ** ** SELECT count(*) FROM <tbl> ** ** where table is a database table, not a sub-select or view. If the query ** does match this pattern, then a pointer to the Table object representing ** <tbl> is returned. Otherwise, NULL is returned. ** ** This routine checks to see if it is safe to use the count optimization. ** A correct answer is still obtained (though perhaps more slowly) if ** this routine returns NULL when it could have returned a table pointer. ** But returning the pointer when NULL should have been returned can ** result in incorrect answers and/or crashes. So, when in doubt, return NULL. */ static Table *isSimpleCount(Select *p, AggInfo *pAggInfo){ Table *pTab; Expr *pExpr; assert( !p->pGroupBy ); if( p->pWhere || p->pEList->nExpr!=1 || p->pSrc->nSrc!=1 || p->pSrc->a[0].pSelect || pAggInfo->nFunc!=1 ){ return 0; } pTab = p->pSrc->a[0].pTab; assert( pTab!=0 ); assert( !IsView(pTab) ); if( !IsOrdinaryTable(pTab) ) return 0; pExpr = p->pEList->a[0].pExpr; assert( pExpr!=0 ); if( pExpr->op!=TK_AGG_FUNCTION ) return 0; if( pExpr->pAggInfo!=pAggInfo ) return 0; if( (pAggInfo->aFunc[0].pFunc->funcFlags&SQLITE_FUNC_COUNT)==0 ) return 0; assert( pAggInfo->aFunc[0].pFExpr==pExpr ); testcase( ExprHasProperty(pExpr, EP_Distinct) ); testcase( ExprHasProperty(pExpr, EP_WinFunc) ); if( ExprHasProperty(pExpr, EP_Distinct|EP_WinFunc) ) return 0; return pTab; } /* ** If the source-list item passed as an argument was augmented with an ** INDEXED BY clause, then try to locate the specified index. If there ** was such a clause and the named index cannot be found, return ** SQLITE_ERROR and leave an error in pParse. Otherwise, populate ** pFrom->pIndex and return SQLITE_OK. */ int sqlite3IndexedByLookup(Parse *pParse, SrcItem *pFrom){ Table *pTab = pFrom->pTab; char *zIndexedBy = pFrom->u1.zIndexedBy; Index *pIdx; assert( pTab!=0 ); assert( pFrom->fg.isIndexedBy!=0 ); for(pIdx=pTab->pIndex; pIdx && sqlite3StrICmp(pIdx->zName, zIndexedBy); pIdx=pIdx->pNext ); if( !pIdx ){ sqlite3ErrorMsg(pParse, "no such index: %s", zIndexedBy, 0); pParse->checkSchema = 1; return SQLITE_ERROR; } assert( pFrom->fg.isCte==0 ); pFrom->u2.pIBIndex = 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: |
︙ | ︙ | |||
4511 4512 4513 4514 4515 4516 4517 4518 4519 4520 4521 4522 4523 4524 | 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. */ | > > > > > > > > | 5050 5051 5052 5053 5054 5055 5056 5057 5058 5059 5060 5061 5062 5063 5064 5065 5066 5067 5068 5069 5070 5071 | 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; #ifndef SQLITE_OMIT_WINDOWFUNC /* If iOrderByCol is already non-zero, then it has already been matched ** to a result column of the SELECT statement. This occurs when the ** SELECT is rewritten for window-functions processing and then passed ** to sqlite3SelectPrep() and similar a second time. The rewriting done ** by this function is not required in this case. */ if( a[0].u.x.iOrderByCol ) return WRC_Continue; #endif 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. */ |
︙ | ︙ | |||
4536 4537 4538 4539 4540 4541 4542 4543 4544 4545 4546 4547 4548 4549 4550 4551 4552 4553 4554 4555 4556 | p->pWhere = 0; pNew->pGroupBy = 0; pNew->pHaving = 0; pNew->pOrderBy = 0; p->pPrior = 0; p->pNext = 0; p->pWith = 0; p->selFlags &= ~SF_Compound; assert( (p->selFlags & SF_Converted)==0 ); p->selFlags |= SF_Converted; assert( pNew->pPrior!=0 ); pNew->pPrior->pNext = pNew; pNew->pLimit = 0; return WRC_Continue; } /* ** Check to see if the FROM clause term pFrom has table-valued function ** arguments. If it does, leave an error message in pParse and return ** non-zero, since pFrom is not allowed to be a table-valued function. */ | > > > | | | < | > > | | | | | | | | < > | | > > > > > > > | < > > > > > > > | | | < | > > | | > | | | < < > | | < | > | | < < | | > > > | > > > > > > > > > > > > > > > > > > > > > > | | | | > > > > > > > > > > > > | > > > > | > > > > > > > | | | > | | < | < < < | < < | | | | | > | > > > | > | > | | > > > > | | | | > > > > | > > > | > | < | | < < | > > | > > > | > | 5083 5084 5085 5086 5087 5088 5089 5090 5091 5092 5093 5094 5095 5096 5097 5098 5099 5100 5101 5102 5103 5104 5105 5106 5107 5108 5109 5110 5111 5112 5113 5114 5115 5116 5117 5118 5119 5120 5121 5122 5123 5124 5125 5126 5127 5128 5129 5130 5131 5132 5133 5134 5135 5136 5137 5138 5139 5140 5141 5142 5143 5144 5145 5146 5147 5148 5149 5150 5151 5152 5153 5154 5155 5156 5157 5158 5159 5160 5161 5162 5163 5164 5165 5166 5167 5168 5169 5170 5171 5172 5173 5174 5175 5176 5177 5178 5179 5180 5181 5182 5183 5184 5185 5186 5187 5188 5189 5190 5191 5192 5193 5194 5195 5196 5197 5198 5199 5200 5201 5202 5203 5204 5205 5206 5207 5208 5209 5210 5211 5212 5213 5214 5215 5216 5217 5218 5219 5220 5221 5222 5223 5224 5225 5226 5227 5228 5229 5230 5231 5232 5233 5234 5235 5236 5237 5238 5239 5240 5241 5242 5243 5244 5245 5246 5247 5248 5249 5250 5251 5252 5253 5254 5255 5256 5257 5258 5259 5260 5261 5262 5263 5264 5265 5266 5267 5268 5269 5270 5271 5272 5273 5274 5275 5276 5277 5278 5279 5280 5281 5282 5283 5284 5285 5286 5287 5288 5289 5290 5291 5292 5293 5294 5295 5296 5297 5298 5299 5300 5301 5302 5303 5304 5305 5306 5307 5308 5309 5310 5311 5312 5313 5314 5315 5316 5317 5318 5319 5320 5321 5322 5323 5324 5325 5326 5327 5328 5329 5330 5331 5332 5333 5334 5335 5336 5337 5338 5339 5340 5341 5342 5343 5344 5345 5346 5347 5348 5349 5350 5351 5352 5353 5354 5355 5356 5357 5358 5359 5360 5361 5362 5363 5364 5365 5366 5367 5368 5369 5370 5371 5372 5373 5374 5375 5376 5377 5378 5379 5380 5381 5382 5383 5384 5385 5386 5387 5388 5389 5390 5391 5392 5393 5394 5395 5396 5397 5398 5399 5400 5401 5402 5403 5404 5405 5406 5407 5408 5409 5410 5411 5412 5413 5414 5415 5416 5417 5418 5419 5420 5421 5422 5423 5424 5425 5426 5427 5428 5429 5430 5431 | p->pWhere = 0; pNew->pGroupBy = 0; pNew->pHaving = 0; pNew->pOrderBy = 0; p->pPrior = 0; p->pNext = 0; p->pWith = 0; #ifndef SQLITE_OMIT_WINDOWFUNC p->pWinDefn = 0; #endif p->selFlags &= ~SF_Compound; assert( (p->selFlags & SF_Converted)==0 ); p->selFlags |= SF_Converted; assert( pNew->pPrior!=0 ); pNew->pPrior->pNext = pNew; pNew->pLimit = 0; return WRC_Continue; } /* ** Check to see if the FROM clause term pFrom has table-valued function ** arguments. If it does, leave an error message in pParse and return ** non-zero, since pFrom is not allowed to be a table-valued function. */ static int cannotBeFunction(Parse *pParse, SrcItem *pFrom){ if( pFrom->fg.isTabFunc ){ sqlite3ErrorMsg(pParse, "'%s' is not a function", pFrom->zName); return 1; } return 0; } #ifndef SQLITE_OMIT_CTE /* ** Argument pWith (which may be NULL) points to a linked list of nested ** WITH contexts, from inner to outermost. If the table identified by ** FROM clause element pItem is really a common-table-expression (CTE) ** then return a pointer to the CTE definition for that table. Otherwise ** return NULL. ** ** If a non-NULL value is returned, set *ppContext to point to the With ** object that the returned CTE belongs to. */ static struct Cte *searchWith( With *pWith, /* Current innermost WITH clause */ SrcItem *pItem, /* FROM clause element to resolve */ With **ppContext /* OUT: WITH clause return value belongs to */ ){ const char *zName = pItem->zName; With *p; assert( pItem->zDatabase==0 ); assert( zName!=0 ); for(p=pWith; p; p=p->pOuter){ int i; for(i=0; i<p->nCte; i++){ if( sqlite3StrICmp(zName, p->a[i].zName)==0 ){ *ppContext = p; return &p->a[i]; } } if( p->bView ) break; } return 0; } /* The code generator maintains a stack of active WITH clauses ** with the inner-most WITH clause being at the top of the stack. ** ** This routine pushes the WITH clause passed as the second argument ** onto the top of the stack. If argument bFree is true, then this ** WITH clause will never be popped from the stack but should instead ** be freed along with the Parse object. In other cases, when ** bFree==0, the With object will be freed along with the SELECT ** statement with which it is associated. ** ** This routine returns a copy of pWith. Or, if bFree is true and ** the pWith object is destroyed immediately due to an OOM condition, ** then this routine return NULL. ** ** If bFree is true, do not continue to use the pWith pointer after ** calling this routine, Instead, use only the return value. */ With *sqlite3WithPush(Parse *pParse, With *pWith, u8 bFree){ if( pWith ){ if( bFree ){ pWith = (With*)sqlite3ParserAddCleanup(pParse, (void(*)(sqlite3*,void*))sqlite3WithDelete, pWith); if( pWith==0 ) return 0; } if( pParse->nErr==0 ){ assert( pParse->pWith!=pWith ); pWith->pOuter = pParse->pWith; pParse->pWith = pWith; } } return pWith; } /* ** This function checks if argument pFrom refers to a CTE declared by ** a WITH clause on the stack currently maintained by the parser (on the ** pParse->pWith linked list). And if currently processing a CTE ** CTE expression, through routine checks to see if the reference is ** a recursive reference to the CTE. ** ** If pFrom matches a CTE according to either of these two above, pFrom->pTab ** and other fields are populated accordingly. ** ** Return 0 if no match is found. ** Return 1 if a match is found. ** Return 2 if an error condition is detected. */ static int resolveFromTermToCte( Parse *pParse, /* The parsing context */ Walker *pWalker, /* Current tree walker */ SrcItem *pFrom /* The FROM clause term to check */ ){ Cte *pCte; /* Matched CTE (or NULL if no match) */ With *pWith; /* The matching WITH */ assert( pFrom->pTab==0 ); if( pParse->pWith==0 ){ /* There are no WITH clauses in the stack. No match is possible */ return 0; } if( pParse->nErr ){ /* Prior errors might have left pParse->pWith in a goofy state, so ** go no further. */ return 0; } if( pFrom->zDatabase!=0 ){ /* The FROM term contains a schema qualifier (ex: main.t1) and so ** it cannot possibly be a CTE reference. */ return 0; } if( pFrom->fg.notCte ){ /* The FROM term is specifically excluded from matching a CTE. ** (1) It is part of a trigger that used to have zDatabase but had ** zDatabase removed by sqlite3FixTriggerStep(). ** (2) This is the first term in the FROM clause of an UPDATE. */ return 0; } pCte = searchWith(pParse->pWith, pFrom, &pWith); if( pCte ){ sqlite3 *db = pParse->db; Table *pTab; ExprList *pEList; Select *pSel; Select *pLeft; /* Left-most SELECT statement */ Select *pRecTerm; /* Left-most recursive term */ int bMayRecursive; /* True if compound joined by UNION [ALL] */ With *pSavedWith; /* Initial value of pParse->pWith */ int iRecTab = -1; /* Cursor for recursive table */ CteUse *pCteUse; /* If pCte->zCteErr is non-NULL at this point, then this is an illegal ** recursive reference to CTE pCte. Leave an error in pParse and return ** early. If pCte->zCteErr is NULL, then this is not a recursive reference. ** In this case, proceed. */ if( pCte->zCteErr ){ sqlite3ErrorMsg(pParse, pCte->zCteErr, pCte->zName); return 2; } if( cannotBeFunction(pParse, pFrom) ) return 2; assert( pFrom->pTab==0 ); pTab = sqlite3DbMallocZero(db, sizeof(Table)); if( pTab==0 ) return 2; pCteUse = pCte->pUse; if( pCteUse==0 ){ pCte->pUse = pCteUse = sqlite3DbMallocZero(db, sizeof(pCteUse[0])); if( pCteUse==0 || sqlite3ParserAddCleanup(pParse,sqlite3DbFree,pCteUse)==0 ){ sqlite3DbFree(db, pTab); return 2; } pCteUse->eM10d = pCte->eM10d; } pFrom->pTab = pTab; pTab->nTabRef = 1; pTab->zName = sqlite3DbStrDup(db, pCte->zName); pTab->iPKey = -1; pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) ); pTab->tabFlags |= TF_Ephemeral | TF_NoVisibleRowid; pFrom->pSelect = sqlite3SelectDup(db, pCte->pSelect, 0); if( db->mallocFailed ) return 2; pFrom->pSelect->selFlags |= SF_CopyCte; assert( pFrom->pSelect ); if( pFrom->fg.isIndexedBy ){ sqlite3ErrorMsg(pParse, "no such index: \"%s\"", pFrom->u1.zIndexedBy); return 2; } pFrom->fg.isCte = 1; pFrom->u2.pCteUse = pCteUse; pCteUse->nUse++; if( pCteUse->nUse>=2 && pCteUse->eM10d==M10d_Any ){ pCteUse->eM10d = M10d_Yes; } /* Check if this is a recursive CTE. */ pRecTerm = pSel = pFrom->pSelect; bMayRecursive = ( pSel->op==TK_ALL || pSel->op==TK_UNION ); while( bMayRecursive && pRecTerm->op==pSel->op ){ int i; SrcList *pSrc = pRecTerm->pSrc; assert( pRecTerm->pPrior!=0 ); for(i=0; i<pSrc->nSrc; i++){ SrcItem *pItem = &pSrc->a[i]; if( pItem->zDatabase==0 && pItem->zName!=0 && 0==sqlite3StrICmp(pItem->zName, pCte->zName) ){ pItem->pTab = pTab; pTab->nTabRef++; pItem->fg.isRecursive = 1; if( pRecTerm->selFlags & SF_Recursive ){ sqlite3ErrorMsg(pParse, "multiple references to recursive table: %s", pCte->zName ); return 2; } pRecTerm->selFlags |= SF_Recursive; if( iRecTab<0 ) iRecTab = pParse->nTab++; pItem->iCursor = iRecTab; } } if( (pRecTerm->selFlags & SF_Recursive)==0 ) break; pRecTerm = pRecTerm->pPrior; } pCte->zCteErr = "circular reference: %s"; pSavedWith = pParse->pWith; pParse->pWith = pWith; if( pSel->selFlags & SF_Recursive ){ int rc; assert( pRecTerm!=0 ); assert( (pRecTerm->selFlags & SF_Recursive)==0 ); assert( pRecTerm->pNext!=0 ); assert( (pRecTerm->pNext->selFlags & SF_Recursive)!=0 ); assert( pRecTerm->pWith==0 ); pRecTerm->pWith = pSel->pWith; rc = sqlite3WalkSelect(pWalker, pRecTerm); pRecTerm->pWith = 0; if( rc ){ pParse->pWith = pSavedWith; return 2; } }else{ if( sqlite3WalkSelect(pWalker, pSel) ){ pParse->pWith = pSavedWith; return 2; } } pParse->pWith = pWith; for(pLeft=pSel; pLeft->pPrior; pLeft=pLeft->pPrior); pEList = pLeft->pEList; if( pCte->pCols ){ if( pEList && pEList->nExpr!=pCte->pCols->nExpr ){ sqlite3ErrorMsg(pParse, "table %s has %d values for %d columns", pCte->zName, pEList->nExpr, pCte->pCols->nExpr ); pParse->pWith = pSavedWith; return 2; } pEList = pCte->pCols; } sqlite3ColumnsFromExprList(pParse, pEList, &pTab->nCol, &pTab->aCol); if( bMayRecursive ){ if( pSel->selFlags & SF_Recursive ){ pCte->zCteErr = "multiple recursive references: %s"; }else{ pCte->zCteErr = "recursive reference in a subquery: %s"; } sqlite3WalkSelect(pWalker, pSel); } pCte->zCteErr = 0; pParse->pWith = pSavedWith; return 1; /* Success */ } return 0; /* No match */ } #endif #ifndef SQLITE_OMIT_CTE /* ** If the SELECT passed as the second argument has an associated WITH ** clause, pop it from the stack stored as part of the Parse object. ** ** This function is used as the xSelectCallback2() callback by ** sqlite3SelectExpand() when walking a SELECT tree to resolve table ** names and other FROM clause elements. */ void sqlite3SelectPopWith(Walker *pWalker, Select *p){ Parse *pParse = pWalker->pParse; if( OK_IF_ALWAYS_TRUE(pParse->pWith) && p->pPrior==0 ){ With *pWith = findRightmost(p)->pWith; if( pWith!=0 ){ assert( pParse->pWith==pWith || pParse->nErr ); pParse->pWith = pWith->pOuter; } } } #endif /* ** The SrcList_item structure passed as the second argument represents a ** sub-query in the FROM clause of a SELECT statement. This function ** allocates and populates the SrcList_item.pTab object. If successful, ** SQLITE_OK is returned. Otherwise, if an OOM error is encountered, ** SQLITE_NOMEM. */ int sqlite3ExpandSubquery(Parse *pParse, SrcItem *pFrom){ Select *pSel = pFrom->pSelect; Table *pTab; assert( pSel ); pFrom->pTab = pTab = sqlite3DbMallocZero(pParse->db, sizeof(Table)); if( pTab==0 ) return SQLITE_NOMEM; pTab->nTabRef = 1; if( pFrom->zAlias ){ pTab->zName = sqlite3DbStrDup(pParse->db, pFrom->zAlias); }else{ pTab->zName = sqlite3MPrintf(pParse->db, "subquery_%u", pSel->selId); } while( pSel->pPrior ){ pSel = pSel->pPrior; } sqlite3ColumnsFromExprList(pParse, pSel->pEList,&pTab->nCol,&pTab->aCol); pTab->iPKey = -1; pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) ); #ifndef SQLITE_ALLOW_ROWID_IN_VIEW /* The usual case - do not allow ROWID on a subquery */ pTab->tabFlags |= TF_Ephemeral | TF_NoVisibleRowid; #else pTab->tabFlags |= TF_Ephemeral; /* Legacy compatibility mode */ #endif return pParse->nErr ? SQLITE_ERROR : 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 |
︙ | ︙ | |||
4819 4820 4821 4822 4823 4824 4825 | ** for instances of the "*" operator or the TABLE.* operator. ** If found, expand each "*" to be every column in every table ** and TABLE.* to be every column in TABLE. ** */ static int selectExpander(Walker *pWalker, Select *p){ Parse *pParse = pWalker->pParse; | | | > > > > > > > > > > > > > | | < < < < > > > > > > | | > > > > > > > > | > > > > > > > > > > > > > > | | | 5446 5447 5448 5449 5450 5451 5452 5453 5454 5455 5456 5457 5458 5459 5460 5461 5462 5463 5464 5465 5466 5467 5468 5469 5470 5471 5472 5473 5474 5475 5476 5477 5478 5479 5480 5481 5482 5483 5484 5485 5486 5487 5488 5489 5490 5491 5492 5493 5494 5495 5496 5497 5498 5499 5500 5501 5502 5503 5504 5505 5506 5507 5508 5509 5510 5511 5512 5513 5514 5515 5516 5517 5518 5519 5520 5521 5522 5523 5524 5525 5526 5527 5528 5529 5530 5531 5532 5533 5534 5535 5536 5537 5538 5539 5540 5541 5542 5543 5544 5545 5546 5547 5548 5549 5550 5551 5552 5553 5554 5555 5556 5557 5558 5559 5560 5561 5562 5563 5564 5565 5566 5567 5568 5569 5570 5571 5572 5573 5574 5575 5576 5577 5578 5579 5580 5581 5582 | ** for instances of the "*" operator or the TABLE.* operator. ** If found, expand each "*" to be every column in every table ** and TABLE.* to be every column in TABLE. ** */ static int selectExpander(Walker *pWalker, Select *p){ Parse *pParse = pWalker->pParse; int i, j, k, rc; SrcList *pTabList; ExprList *pEList; SrcItem *pFrom; sqlite3 *db = pParse->db; Expr *pE, *pRight, *pExpr; u16 selFlags = p->selFlags; u32 elistFlags = 0; p->selFlags |= SF_Expanded; if( db->mallocFailed ){ return WRC_Abort; } assert( p->pSrc!=0 ); if( (selFlags & SF_Expanded)!=0 ){ return WRC_Prune; } if( pWalker->eCode ){ /* Renumber selId because it has been copied from a view */ p->selId = ++pParse->nSelect; } pTabList = p->pSrc; pEList = p->pEList; if( pParse->pWith && (p->selFlags & SF_View) ){ if( p->pWith==0 ){ p->pWith = (With*)sqlite3DbMallocZero(db, sizeof(With)); if( p->pWith==0 ){ return WRC_Abort; } } p->pWith->bView = 1; } sqlite3WithPush(pParse, p->pWith, 0); /* Make sure cursor numbers have been assigned to all entries in ** the FROM clause of the SELECT statement. */ sqlite3SrcListAssignCursors(pParse, pTabList); /* Look up every table named in the FROM clause of the select. If ** an entry of the FROM clause is a subquery instead of a table or view, ** then create a transient table structure to describe the subquery. */ for(i=0, pFrom=pTabList->a; i<pTabList->nSrc; i++, pFrom++){ Table *pTab; assert( pFrom->fg.isRecursive==0 || pFrom->pTab!=0 ); if( pFrom->pTab ) continue; assert( pFrom->fg.isRecursive==0 ); if( pFrom->zName==0 ){ #ifndef SQLITE_OMIT_SUBQUERY Select *pSel = pFrom->pSelect; /* A sub-query in the FROM clause of a SELECT */ assert( pSel!=0 ); assert( pFrom->pTab==0 ); if( sqlite3WalkSelect(pWalker, pSel) ) return WRC_Abort; if( sqlite3ExpandSubquery(pParse, pFrom) ) return WRC_Abort; #endif #ifndef SQLITE_OMIT_CTE }else if( (rc = resolveFromTermToCte(pParse, pWalker, pFrom))!=0 ){ if( rc>1 ) return WRC_Abort; pTab = pFrom->pTab; assert( pTab!=0 ); #endif }else{ /* An ordinary table or view name in the FROM clause */ assert( pFrom->pTab==0 ); pFrom->pTab = pTab = sqlite3LocateTableItem(pParse, 0, pFrom); if( pTab==0 ) return WRC_Abort; if( pTab->nTabRef>=0xffff ){ sqlite3ErrorMsg(pParse, "too many references to \"%s\": max 65535", pTab->zName); pFrom->pTab = 0; return WRC_Abort; } pTab->nTabRef++; if( !IsVirtual(pTab) && cannotBeFunction(pParse, pFrom) ){ return WRC_Abort; } #if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE) if( !IsOrdinaryTable(pTab) ){ i16 nCol; u8 eCodeOrig = pWalker->eCode; if( sqlite3ViewGetColumnNames(pParse, pTab) ) return WRC_Abort; assert( pFrom->pSelect==0 ); if( IsView(pTab) ){ if( (db->flags & SQLITE_EnableView)==0 && pTab->pSchema!=db->aDb[1].pSchema ){ sqlite3ErrorMsg(pParse, "access to view \"%s\" prohibited", pTab->zName); } pFrom->pSelect = sqlite3SelectDup(db, pTab->u.view.pSelect, 0); } #ifndef SQLITE_OMIT_VIRTUALTABLE else if( ALWAYS(IsVirtual(pTab)) && pFrom->fg.fromDDL && ALWAYS(pTab->u.vtab.p!=0) && pTab->u.vtab.p->eVtabRisk > ((db->flags & SQLITE_TrustedSchema)!=0) ){ sqlite3ErrorMsg(pParse, "unsafe use of virtual table \"%s\"", pTab->zName); } assert( SQLITE_VTABRISK_Normal==1 && SQLITE_VTABRISK_High==2 ); #endif nCol = pTab->nCol; pTab->nCol = -1; pWalker->eCode = 1; /* Turn on Select.selId renumbering */ sqlite3WalkSelect(pWalker, pFrom->pSelect); pWalker->eCode = eCodeOrig; pTab->nCol = nCol; } #endif } /* Locate the index named by the INDEXED BY clause, if any. */ if( pFrom->fg.isIndexedBy && sqlite3IndexedByLookup(pParse, pFrom) ){ return WRC_Abort; } } /* Process NATURAL keywords, and ON and USING clauses of joins. */ if( pParse->nErr || db->mallocFailed || sqliteProcessJoin(pParse, p) ){ return WRC_Abort; } /* For every "*" that occurs in the column list, insert the names of ** all columns in all tables. And for every TABLE.* insert the names ** of all columns in TABLE. The parser inserted a special expression ** with the TK_ASTERISK operator for each "*" that it found in the column |
︙ | ︙ | |||
4951 4952 4953 4954 4955 4956 4957 | if( pE->op!=TK_ASTERISK && (pE->op!=TK_DOT || pRight->op!=TK_ASTERISK) ){ /* This particular expression does not need to be expanded. */ pNew = sqlite3ExprListAppend(pParse, pNew, a[k].pExpr); if( pNew ){ | | | | < | 5615 5616 5617 5618 5619 5620 5621 5622 5623 5624 5625 5626 5627 5628 5629 5630 5631 | if( pE->op!=TK_ASTERISK && (pE->op!=TK_DOT || pRight->op!=TK_ASTERISK) ){ /* This particular expression does not need to be expanded. */ pNew = sqlite3ExprListAppend(pParse, pNew, a[k].pExpr); if( pNew ){ pNew->a[pNew->nExpr-1].zEName = a[k].zEName; pNew->a[pNew->nExpr-1].eEName = a[k].eEName; a[k].zEName = 0; } a[k].pExpr = 0; }else{ /* This expression is a "*" or a "TABLE.*" and needs to be ** expanded. */ int tableSeen = 0; /* Set to 1 when TABLE matches */ char *zTName = 0; /* text of name of TABLE */ |
︙ | ︙ | |||
4986 4987 4988 4989 4990 4991 4992 | if( zTName && sqlite3StrICmp(zTName, zTabName)!=0 ){ continue; } iDb = sqlite3SchemaToIndex(db, pTab->pSchema); zSchemaName = iDb>=0 ? db->aDb[iDb].zDbSName : "*"; } for(j=0; j<pTab->nCol; j++){ | | | | | 5649 5650 5651 5652 5653 5654 5655 5656 5657 5658 5659 5660 5661 5662 5663 5664 5665 5666 5667 5668 5669 5670 5671 5672 5673 5674 5675 5676 5677 5678 5679 5680 5681 5682 5683 5684 5685 5686 5687 5688 | if( zTName && sqlite3StrICmp(zTName, zTabName)!=0 ){ continue; } iDb = sqlite3SchemaToIndex(db, pTab->pSchema); zSchemaName = iDb>=0 ? db->aDb[iDb].zDbSName : "*"; } for(j=0; j<pTab->nCol; j++){ char *zName = pTab->aCol[j].zCnName; char *zColname; /* The computed column name */ char *zToFree; /* Malloced string that needs to be freed */ Token sColname; /* Computed column name as a token */ assert( zName ); if( zTName && pSub && sqlite3MatchEName(&pSub->pEList->a[j], 0, zTName, 0)==0 ){ continue; } /* If a column is marked as 'hidden', omit it from the expanded ** result-set list unless the SELECT has the SF_IncludeHidden ** bit set. */ if( (p->selFlags & SF_IncludeHidden)==0 && IsHiddenColumn(&pTab->aCol[j]) ){ continue; } tableSeen = 1; if( i>0 && zTName==0 ){ if( (pFrom->fg.jointype & JT_NATURAL)!=0 && tableAndColumnIndex(pTabList, i, zName, 0, 0, 1) ){ /* In a NATURAL join, omit the join columns from the ** table to the right of the join */ continue; } if( sqlite3IdListIndex(pFrom->pUsing, zName)>=0 ){ /* In a join with a USING clause, omit columns in the |
︙ | ︙ | |||
5044 5045 5046 5047 5048 5049 5050 | } }else{ pExpr = pRight; } pNew = sqlite3ExprListAppend(pParse, pNew, pExpr); sqlite3TokenInit(&sColname, zColname); sqlite3ExprListSetName(pParse, pNew, &sColname, 0); | | > | | | | | | 5707 5708 5709 5710 5711 5712 5713 5714 5715 5716 5717 5718 5719 5720 5721 5722 5723 5724 5725 5726 5727 5728 5729 5730 5731 5732 | } }else{ pExpr = pRight; } pNew = sqlite3ExprListAppend(pParse, pNew, pExpr); sqlite3TokenInit(&sColname, zColname); sqlite3ExprListSetName(pParse, pNew, &sColname, 0); if( pNew && (p->selFlags & SF_NestedFrom)!=0 && !IN_RENAME_OBJECT ){ struct ExprList_item *pX = &pNew->a[pNew->nExpr-1]; sqlite3DbFree(db, pX->zEName); if( pSub ){ pX->zEName = sqlite3DbStrDup(db, pSub->pEList->a[j].zEName); testcase( pX->zEName==0 ); }else{ pX->zEName = sqlite3MPrintf(db, "%s.%s.%s", zSchemaName, zTabName, zColname); testcase( pX->zEName==0 ); } pX->eEName = ENAME_TAB; } sqlite3DbFree(db, zToFree); } } if( !tableSeen ){ if( zTName ){ sqlite3ErrorMsg(pParse, "no such table: %s", zTName); |
︙ | ︙ | |||
5083 5084 5085 5086 5087 5088 5089 | if( (elistFlags & (EP_HasFunc|EP_Subquery))!=0 ){ p->selFlags |= SF_ComplexResult; } } return WRC_Continue; } | < < < < < < < < < < < < < < < < < < < < < < < | 5747 5748 5749 5750 5751 5752 5753 5754 5755 5756 5757 5758 5759 5760 | if( (elistFlags & (EP_HasFunc|EP_Subquery))!=0 ){ p->selFlags |= SF_ComplexResult; } } return WRC_Continue; } #if SQLITE_DEBUG /* ** Always assert. This xSelectCallback2 implementation proves that the ** xSelectCallback2 is never invoked. */ void sqlite3SelectWalkAssert2(Walker *NotUsed, Select *NotUsed2){ UNUSED_PARAMETER2(NotUsed, NotUsed2); |
︙ | ︙ | |||
5139 5140 5141 5142 5143 5144 5145 | w.pParse = pParse; if( OK_IF_ALWAYS_TRUE(pParse->hasCompound) ){ w.xSelectCallback = convertCompoundSelectToSubquery; w.xSelectCallback2 = 0; sqlite3WalkSelect(&w, pSelect); } w.xSelectCallback = selectExpander; | | > | 5780 5781 5782 5783 5784 5785 5786 5787 5788 5789 5790 5791 5792 5793 5794 5795 | w.pParse = pParse; if( OK_IF_ALWAYS_TRUE(pParse->hasCompound) ){ w.xSelectCallback = convertCompoundSelectToSubquery; w.xSelectCallback2 = 0; sqlite3WalkSelect(&w, pSelect); } w.xSelectCallback = selectExpander; w.xSelectCallback2 = sqlite3SelectPopWith; w.eCode = 0; sqlite3WalkSelect(&w, pSelect); } #ifndef SQLITE_OMIT_SUBQUERY /* ** This is a Walker.xSelectCallback callback for the sqlite3SelectTypeInfo() |
︙ | ︙ | |||
5162 5163 5164 5165 5166 5167 5168 | ** at that point because identifiers had not yet been resolved. This ** routine is called after identifier resolution. */ static void selectAddSubqueryTypeInfo(Walker *pWalker, Select *p){ Parse *pParse; int i; SrcList *pTabList; | | | > | 5804 5805 5806 5807 5808 5809 5810 5811 5812 5813 5814 5815 5816 5817 5818 5819 5820 5821 5822 5823 5824 5825 5826 5827 5828 5829 5830 5831 5832 5833 5834 | ** at that point because identifiers had not yet been resolved. This ** routine is called after identifier resolution. */ static void selectAddSubqueryTypeInfo(Walker *pWalker, Select *p){ Parse *pParse; int i; SrcList *pTabList; SrcItem *pFrom; assert( p->selFlags & SF_Resolved ); if( p->selFlags & SF_HasTypeInfo ) return; p->selFlags |= SF_HasTypeInfo; pParse = pWalker->pParse; pTabList = p->pSrc; for(i=0, pFrom=pTabList->a; i<pTabList->nSrc; i++, pFrom++){ Table *pTab = pFrom->pTab; assert( pTab!=0 ); if( (pTab->tabFlags & TF_Ephemeral)!=0 ){ /* A sub-query in the FROM clause of a SELECT */ Select *pSel = pFrom->pSelect; if( pSel ){ while( pSel->pPrior ) pSel = pSel->pPrior; sqlite3SelectAddColumnTypeAndCollation(pParse, pTab, pSel, SQLITE_AFF_NONE); } } } } #endif |
︙ | ︙ | |||
5245 5246 5247 5248 5249 5250 5251 5252 5253 5254 5255 5256 5257 5258 5259 5260 5261 5262 5263 5264 5265 5266 5267 | */ static void resetAccumulator(Parse *pParse, AggInfo *pAggInfo){ Vdbe *v = pParse->pVdbe; int i; struct AggInfo_func *pFunc; int nReg = pAggInfo->nFunc + pAggInfo->nColumn; if( nReg==0 ) return; #ifdef SQLITE_DEBUG /* Verify that all AggInfo registers are within the range specified by ** AggInfo.mnReg..AggInfo.mxReg */ assert( nReg==pAggInfo->mxReg-pAggInfo->mnReg+1 ); for(i=0; i<pAggInfo->nColumn; i++){ assert( pAggInfo->aCol[i].iMem>=pAggInfo->mnReg && pAggInfo->aCol[i].iMem<=pAggInfo->mxReg ); } for(i=0; i<pAggInfo->nFunc; i++){ assert( pAggInfo->aFunc[i].iMem>=pAggInfo->mnReg && pAggInfo->aFunc[i].iMem<=pAggInfo->mxReg ); } #endif sqlite3VdbeAddOp3(v, OP_Null, 0, pAggInfo->mnReg, pAggInfo->mxReg); for(pFunc=pAggInfo->aFunc, i=0; i<pAggInfo->nFunc; i++, pFunc++){ if( pFunc->iDistinct>=0 ){ | > | | | | > > | | > | | > > > > > | > > > | > > > > > > > > > > > > > > > > > > > > > | > | < < > > | | 5888 5889 5890 5891 5892 5893 5894 5895 5896 5897 5898 5899 5900 5901 5902 5903 5904 5905 5906 5907 5908 5909 5910 5911 5912 5913 5914 5915 5916 5917 5918 5919 5920 5921 5922 5923 5924 5925 5926 5927 5928 5929 5930 5931 5932 5933 5934 5935 5936 5937 5938 5939 5940 5941 5942 5943 5944 5945 5946 5947 5948 5949 5950 5951 5952 5953 5954 5955 5956 5957 5958 5959 5960 5961 5962 5963 5964 5965 5966 5967 5968 5969 5970 5971 5972 5973 5974 5975 5976 5977 5978 5979 5980 5981 5982 5983 5984 5985 5986 5987 5988 5989 5990 5991 5992 5993 5994 5995 5996 5997 5998 5999 6000 6001 6002 6003 6004 6005 6006 6007 6008 6009 6010 6011 6012 6013 6014 6015 6016 6017 6018 6019 6020 | */ static void resetAccumulator(Parse *pParse, AggInfo *pAggInfo){ Vdbe *v = pParse->pVdbe; int i; struct AggInfo_func *pFunc; int nReg = pAggInfo->nFunc + pAggInfo->nColumn; if( nReg==0 ) return; if( pParse->nErr || pParse->db->mallocFailed ) return; #ifdef SQLITE_DEBUG /* Verify that all AggInfo registers are within the range specified by ** AggInfo.mnReg..AggInfo.mxReg */ assert( nReg==pAggInfo->mxReg-pAggInfo->mnReg+1 ); for(i=0; i<pAggInfo->nColumn; i++){ assert( pAggInfo->aCol[i].iMem>=pAggInfo->mnReg && pAggInfo->aCol[i].iMem<=pAggInfo->mxReg ); } for(i=0; i<pAggInfo->nFunc; i++){ assert( pAggInfo->aFunc[i].iMem>=pAggInfo->mnReg && pAggInfo->aFunc[i].iMem<=pAggInfo->mxReg ); } #endif sqlite3VdbeAddOp3(v, OP_Null, 0, pAggInfo->mnReg, pAggInfo->mxReg); for(pFunc=pAggInfo->aFunc, i=0; i<pAggInfo->nFunc; i++, pFunc++){ if( pFunc->iDistinct>=0 ){ Expr *pE = pFunc->pFExpr; assert( ExprUseXList(pE) ); if( pE->x.pList==0 || pE->x.pList->nExpr!=1 ){ sqlite3ErrorMsg(pParse, "DISTINCT aggregates must have exactly one " "argument"); pFunc->iDistinct = -1; }else{ KeyInfo *pKeyInfo = sqlite3KeyInfoFromExprList(pParse, pE->x.pList,0,0); pFunc->iDistAddr = sqlite3VdbeAddOp4(v, OP_OpenEphemeral, pFunc->iDistinct, 0, 0, (char*)pKeyInfo, P4_KEYINFO); ExplainQueryPlan((pParse, 0, "USE TEMP B-TREE FOR %s(DISTINCT)", pFunc->pFunc->zName)); } } } } /* ** Invoke the OP_AggFinalize opcode for every aggregate function ** in the AggInfo structure. */ static void finalizeAggFunctions(Parse *pParse, AggInfo *pAggInfo){ Vdbe *v = pParse->pVdbe; int i; struct AggInfo_func *pF; for(i=0, pF=pAggInfo->aFunc; i<pAggInfo->nFunc; i++, pF++){ ExprList *pList; assert( ExprUseXList(pF->pFExpr) ); pList = pF->pFExpr->x.pList; sqlite3VdbeAddOp2(v, OP_AggFinal, pF->iMem, pList ? pList->nExpr : 0); sqlite3VdbeAppendP4(v, pF->pFunc, P4_FUNCDEF); } } /* ** Update the accumulator memory cells for an aggregate based on ** the current cursor position. ** ** If regAcc is non-zero and there are no min() or max() aggregates ** in pAggInfo, then only populate the pAggInfo->nAccumulator accumulator ** registers if register regAcc contains 0. The caller will take care ** of setting and clearing regAcc. */ static void updateAccumulator( Parse *pParse, int regAcc, AggInfo *pAggInfo, int eDistinctType ){ Vdbe *v = pParse->pVdbe; int i; int regHit = 0; int addrHitTest = 0; struct AggInfo_func *pF; struct AggInfo_col *pC; pAggInfo->directMode = 1; for(i=0, pF=pAggInfo->aFunc; i<pAggInfo->nFunc; i++, pF++){ int nArg; int addrNext = 0; int regAgg; ExprList *pList; assert( ExprUseXList(pF->pFExpr) ); assert( !IsWindowFunc(pF->pFExpr) ); pList = pF->pFExpr->x.pList; if( ExprHasProperty(pF->pFExpr, EP_WinFunc) ){ Expr *pFilter = pF->pFExpr->y.pWin->pFilter; if( pAggInfo->nAccumulator && (pF->pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL) && regAcc ){ /* If regAcc==0, there there exists some min() or max() function ** without a FILTER clause that will ensure the magnet registers ** are populated. */ if( regHit==0 ) regHit = ++pParse->nMem; /* If this is the first row of the group (regAcc contains 0), clear the ** "magnet" register regHit so that the accumulator registers ** are populated if the FILTER clause jumps over the the ** invocation of min() or max() altogether. Or, if this is not ** the first row (regAcc contains 1), set the magnet register so that ** the accumulators are not populated unless the min()/max() is invoked ** and indicates that they should be. */ sqlite3VdbeAddOp2(v, OP_Copy, regAcc, regHit); } addrNext = sqlite3VdbeMakeLabel(pParse); sqlite3ExprIfFalse(pParse, pFilter, addrNext, SQLITE_JUMPIFNULL); } if( pList ){ nArg = pList->nExpr; regAgg = sqlite3GetTempRange(pParse, nArg); sqlite3ExprCodeExprList(pParse, pList, regAgg, 0, SQLITE_ECEL_DUP); }else{ nArg = 0; regAgg = 0; } if( pF->iDistinct>=0 && pList ){ if( addrNext==0 ){ addrNext = sqlite3VdbeMakeLabel(pParse); } pF->iDistinct = codeDistinct(pParse, eDistinctType, pF->iDistinct, addrNext, pList, regAgg); } if( pF->pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL ){ CollSeq *pColl = 0; struct ExprList_item *pItem; int j; assert( pList!=0 ); /* pList!=0 if pF->pFunc has NEEDCOLL */ for(j=0, pItem=pList->a; !pColl && j<nArg; j++, pItem++){ |
︙ | ︙ | |||
5360 5361 5362 5363 5364 5365 5366 | if( regHit==0 && pAggInfo->nAccumulator ){ regHit = regAcc; } if( regHit ){ addrHitTest = sqlite3VdbeAddOp1(v, OP_If, regHit); VdbeCoverage(v); } for(i=0, pC=pAggInfo->aCol; i<pAggInfo->nAccumulator; i++, pC++){ | | > | | | 6037 6038 6039 6040 6041 6042 6043 6044 6045 6046 6047 6048 6049 6050 6051 6052 6053 6054 6055 6056 6057 6058 6059 6060 6061 6062 6063 6064 6065 6066 6067 6068 6069 6070 6071 6072 | if( regHit==0 && pAggInfo->nAccumulator ){ regHit = regAcc; } if( regHit ){ addrHitTest = sqlite3VdbeAddOp1(v, OP_If, regHit); VdbeCoverage(v); } for(i=0, pC=pAggInfo->aCol; i<pAggInfo->nAccumulator; i++, pC++){ sqlite3ExprCode(pParse, pC->pCExpr, pC->iMem); } pAggInfo->directMode = 0; if( addrHitTest ){ sqlite3VdbeJumpHereOrPopInst(v, addrHitTest); } } /* ** Add a single OP_Explain instruction to the VDBE to explain a simple ** count(*) query ("SELECT count(*) FROM pTab"). */ #ifndef SQLITE_OMIT_EXPLAIN static void explainSimpleCount( Parse *pParse, /* Parse context */ Table *pTab, /* Table being queried */ Index *pIdx /* Index used to optimize scan, or NULL */ ){ if( pParse->explain==2 ){ int bCover = (pIdx!=0 && (HasRowid(pTab) || !IsPrimaryKeyIndex(pIdx))); sqlite3VdbeExplain(pParse, 0, "SCAN %s%s%s", pTab->zName, bCover ? " USING COVERING INDEX " : "", bCover ? pIdx->zName : "" ); } } #else |
︙ | ︙ | |||
5405 5406 5407 5408 5409 5410 5411 | ** sub-expression matches the criteria for being moved to the WHERE ** clause. If so, add it to the WHERE clause and replace the sub-expression ** within the HAVING expression with a constant "1". */ static int havingToWhereExprCb(Walker *pWalker, Expr *pExpr){ if( pExpr->op!=TK_AND ){ Select *pS = pWalker->u.pSelect; | > > > > > > > | > > > | | | 6083 6084 6085 6086 6087 6088 6089 6090 6091 6092 6093 6094 6095 6096 6097 6098 6099 6100 6101 6102 6103 6104 6105 6106 6107 6108 6109 6110 6111 6112 6113 | ** sub-expression matches the criteria for being moved to the WHERE ** clause. If so, add it to the WHERE clause and replace the sub-expression ** within the HAVING expression with a constant "1". */ static int havingToWhereExprCb(Walker *pWalker, Expr *pExpr){ if( pExpr->op!=TK_AND ){ Select *pS = pWalker->u.pSelect; /* This routine is called before the HAVING clause of the current ** SELECT is analyzed for aggregates. So if pExpr->pAggInfo is set ** here, it indicates that the expression is a correlated reference to a ** column from an outer aggregate query, or an aggregate function that ** belongs to an outer query. Do not move the expression to the WHERE ** clause in this obscure case, as doing so may corrupt the outer Select ** statements AggInfo structure. */ if( sqlite3ExprIsConstantOrGroupBy(pWalker->pParse, pExpr, pS->pGroupBy) && ExprAlwaysFalse(pExpr)==0 && pExpr->pAggInfo==0 ){ sqlite3 *db = pWalker->pParse->db; Expr *pNew = sqlite3Expr(db, TK_INTEGER, "1"); if( pNew ){ Expr *pWhere = pS->pWhere; SWAP(Expr, *pNew, *pExpr); pNew = sqlite3ExprAnd(pWalker->pParse, pWhere, pNew); pS->pWhere = pNew; pWalker->eCode = 1; } } return WRC_Prune; } return WRC_Continue; |
︙ | ︙ | |||
5456 5457 5458 5459 5460 5461 5462 | } /* ** Check to see if the pThis entry of pTabList is a self-join of a prior view. ** If it is, then return the SrcList_item for the prior view. If it is not, ** then return 0. */ | | | | > > > > | > < | < > > > > > > > > > > > > > > > | > > > > > | 6144 6145 6146 6147 6148 6149 6150 6151 6152 6153 6154 6155 6156 6157 6158 6159 6160 6161 6162 6163 6164 6165 6166 6167 6168 6169 6170 6171 6172 6173 6174 6175 6176 6177 6178 6179 6180 6181 6182 6183 6184 6185 6186 6187 6188 6189 6190 6191 6192 6193 6194 6195 6196 6197 6198 6199 6200 6201 6202 6203 6204 6205 6206 6207 6208 6209 6210 6211 6212 6213 6214 6215 6216 6217 6218 6219 6220 6221 6222 6223 6224 6225 6226 6227 6228 6229 6230 6231 6232 | } /* ** Check to see if the pThis entry of pTabList is a self-join of a prior view. ** If it is, then return the SrcList_item for the prior view. If it is not, ** then return 0. */ static SrcItem *isSelfJoinView( SrcList *pTabList, /* Search for self-joins in this FROM clause */ SrcItem *pThis /* Search for prior reference to this subquery */ ){ SrcItem *pItem; assert( pThis->pSelect!=0 ); if( pThis->pSelect->selFlags & SF_PushDown ) return 0; for(pItem = pTabList->a; pItem<pThis; pItem++){ Select *pS1; if( pItem->pSelect==0 ) continue; if( pItem->fg.viaCoroutine ) continue; if( pItem->zName==0 ) continue; assert( pItem->pTab!=0 ); assert( pThis->pTab!=0 ); if( pItem->pTab->pSchema!=pThis->pTab->pSchema ) continue; if( sqlite3_stricmp(pItem->zName, pThis->zName)!=0 ) continue; pS1 = pItem->pSelect; if( pItem->pTab->pSchema==0 && pThis->pSelect->selId!=pS1->selId ){ /* The query flattener left two different CTE tables with identical ** names in the same FROM clause. */ continue; } if( pItem->pSelect->selFlags & SF_PushDown ){ /* The view was modified by some other optimization such as ** pushDownWhereTerms() */ continue; } return pItem; } return 0; } /* ** Deallocate a single AggInfo object */ static void agginfoFree(sqlite3 *db, AggInfo *p){ sqlite3DbFree(db, p->aCol); sqlite3DbFree(db, p->aFunc); sqlite3DbFreeNN(db, p); } #ifdef SQLITE_COUNTOFVIEW_OPTIMIZATION /* ** Attempt to transform a query of the form ** ** SELECT count(*) FROM (SELECT x FROM t1 UNION ALL SELECT y FROM t2) ** ** Into this: ** ** SELECT (SELECT count(*) FROM t1)+(SELECT count(*) FROM t2) ** ** The transformation only works if all of the following are true: ** ** * The subquery is a UNION ALL of two or more terms ** * The subquery does not have a LIMIT clause ** * There is no WHERE or GROUP BY or HAVING clauses on the subqueries ** * The outer query is a simple count(*) with no WHERE clause or other ** extraneous syntax. ** ** Return TRUE if the optimization is undertaken. */ static int countOfViewOptimization(Parse *pParse, Select *p){ Select *pSub, *pPrior; Expr *pExpr; Expr *pCount; sqlite3 *db; if( (p->selFlags & SF_Aggregate)==0 ) return 0; /* This is an aggregate */ if( p->pEList->nExpr!=1 ) return 0; /* Single result column */ if( p->pWhere ) return 0; if( p->pGroupBy ) return 0; pExpr = p->pEList->a[0].pExpr; if( pExpr->op!=TK_AGG_FUNCTION ) return 0; /* Result is an aggregate */ assert( ExprUseUToken(pExpr) ); if( sqlite3_stricmp(pExpr->u.zToken,"count") ) return 0; /* Is count() */ assert( ExprUseXList(pExpr) ); if( pExpr->x.pList!=0 ) return 0; /* Must be count(*) */ if( p->pSrc->nSrc!=1 ) return 0; /* One table in FROM */ pSub = p->pSrc->a[0].pSelect; if( pSub==0 ) return 0; /* The FROM is a subquery */ if( pSub->pPrior==0 ) return 0; /* Must be a compound ry */ do{ if( pSub->op!=TK_ALL && pSub->pPrior ) return 0; /* Must be UNION ALL */ |
︙ | ︙ | |||
5590 5591 5592 5593 5594 5595 5596 5597 5598 5599 | Vdbe *v; /* The virtual machine under construction */ int isAgg; /* True for select lists like "count(*)" */ ExprList *pEList = 0; /* List of columns to extract. */ SrcList *pTabList; /* List of tables to select from */ Expr *pWhere; /* The WHERE clause. May be NULL */ ExprList *pGroupBy; /* The GROUP BY clause. May be NULL */ Expr *pHaving; /* The HAVING clause. May be NULL */ int rc = 1; /* Value to return from this function */ DistinctCtx sDistinct; /* Info on how to code the DISTINCT keyword */ SortCtx sSort; /* Info on how to code the ORDER BY clause */ | > < < | | | < | | > | > > > > > > > | > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > | | | > > > > > | 6301 6302 6303 6304 6305 6306 6307 6308 6309 6310 6311 6312 6313 6314 6315 6316 6317 6318 6319 6320 6321 6322 6323 6324 6325 6326 6327 6328 6329 6330 6331 6332 6333 6334 6335 6336 6337 6338 6339 6340 6341 6342 6343 6344 6345 6346 6347 6348 6349 6350 6351 6352 6353 6354 6355 6356 6357 6358 6359 6360 6361 6362 6363 6364 6365 6366 6367 6368 6369 6370 6371 6372 6373 6374 6375 6376 6377 6378 6379 6380 6381 6382 6383 6384 6385 6386 6387 6388 6389 6390 6391 6392 6393 6394 6395 6396 6397 6398 6399 6400 6401 6402 6403 6404 6405 6406 6407 6408 6409 6410 6411 6412 6413 6414 6415 6416 6417 6418 6419 6420 6421 6422 6423 6424 6425 6426 6427 6428 6429 6430 6431 6432 6433 6434 6435 6436 | Vdbe *v; /* The virtual machine under construction */ int isAgg; /* True for select lists like "count(*)" */ ExprList *pEList = 0; /* List of columns to extract. */ SrcList *pTabList; /* List of tables to select from */ Expr *pWhere; /* The WHERE clause. May be NULL */ ExprList *pGroupBy; /* The GROUP BY clause. May be NULL */ Expr *pHaving; /* The HAVING clause. May be NULL */ AggInfo *pAggInfo = 0; /* Aggregate information */ int rc = 1; /* Value to return from this function */ DistinctCtx sDistinct; /* Info on how to code the DISTINCT keyword */ SortCtx sSort; /* Info on how to code the ORDER BY clause */ int iEnd; /* Address of the end of the query */ sqlite3 *db; /* The database connection */ ExprList *pMinMaxOrderBy = 0; /* Added ORDER BY for min/max queries */ u8 minMaxFlag; /* Flag for min/max queries */ db = pParse->db; v = sqlite3GetVdbe(pParse); if( p==0 || db->mallocFailed || pParse->nErr ){ return 1; } if( sqlite3AuthCheck(pParse, SQLITE_SELECT, 0, 0, 0) ) return 1; #if SELECTTRACE_ENABLED SELECTTRACE(1,pParse,p, ("begin processing:\n", pParse->addrExplain)); if( sqlite3SelectTrace & 0x100 ){ sqlite3TreeViewSelect(0, p, 0); } #endif assert( p->pOrderBy==0 || pDest->eDest!=SRT_DistFifo ); assert( p->pOrderBy==0 || pDest->eDest!=SRT_Fifo ); assert( p->pOrderBy==0 || pDest->eDest!=SRT_DistQueue ); assert( p->pOrderBy==0 || pDest->eDest!=SRT_Queue ); if( IgnorableDistinct(pDest) ){ assert(pDest->eDest==SRT_Exists || pDest->eDest==SRT_Union || pDest->eDest==SRT_Except || pDest->eDest==SRT_Discard || pDest->eDest==SRT_DistQueue || pDest->eDest==SRT_DistFifo ); /* All of these destinations are also able to ignore the ORDER BY clause */ if( p->pOrderBy ){ #if SELECTTRACE_ENABLED SELECTTRACE(1,pParse,p, ("dropping superfluous ORDER BY:\n")); if( sqlite3SelectTrace & 0x100 ){ sqlite3TreeViewExprList(0, p->pOrderBy, 0, "ORDERBY"); } #endif sqlite3ParserAddCleanup(pParse, (void(*)(sqlite3*,void*))sqlite3ExprListDelete, p->pOrderBy); testcase( pParse->earlyCleanup ); p->pOrderBy = 0; } p->selFlags &= ~SF_Distinct; p->selFlags |= SF_NoopOrderBy; } sqlite3SelectPrep(pParse, p, 0); if( pParse->nErr || db->mallocFailed ){ goto select_end; } assert( p->pEList!=0 ); #if SELECTTRACE_ENABLED if( sqlite3SelectTrace & 0x104 ){ SELECTTRACE(0x104,pParse,p, ("after name resolution:\n")); sqlite3TreeViewSelect(0, p, 0); } #endif /* If the SF_UFSrcCheck flag is set, then this function is being called ** as part of populating the temp table for an UPDATE...FROM statement. ** In this case, it is an error if the target object (pSrc->a[0]) name ** or alias is duplicated within FROM clause (pSrc->a[1..n]). ** ** Postgres disallows this case too. The reason is that some other ** systems handle this case differently, and not all the same way, ** which is just confusing. To avoid this, we follow PG's lead and ** disallow it altogether. */ if( p->selFlags & SF_UFSrcCheck ){ SrcItem *p0 = &p->pSrc->a[0]; for(i=1; i<p->pSrc->nSrc; i++){ SrcItem *p1 = &p->pSrc->a[i]; if( p0->pTab==p1->pTab && 0==sqlite3_stricmp(p0->zAlias, p1->zAlias) ){ sqlite3ErrorMsg(pParse, "target object/alias may not appear in FROM clause: %s", p0->zAlias ? p0->zAlias : p0->pTab->zName ); goto select_end; } } /* Clear the SF_UFSrcCheck flag. The check has already been performed, ** and leaving this flag set can cause errors if a compound sub-query ** in p->pSrc is flattened into this query and this function called ** again as part of compound SELECT processing. */ p->selFlags &= ~SF_UFSrcCheck; } if( pDest->eDest==SRT_Output ){ sqlite3GenerateColumnNames(pParse, p); } #ifndef SQLITE_OMIT_WINDOWFUNC if( sqlite3WindowRewrite(pParse, p) ){ assert( db->mallocFailed || pParse->nErr>0 ); goto select_end; } #if SELECTTRACE_ENABLED if( p->pWin && (sqlite3SelectTrace & 0x108)!=0 ){ SELECTTRACE(0x104,pParse,p, ("after window rewrite:\n")); sqlite3TreeViewSelect(0, p, 0); } #endif #endif /* SQLITE_OMIT_WINDOWFUNC */ pTabList = p->pSrc; isAgg = (p->selFlags & SF_Aggregate)!=0; memset(&sSort, 0, sizeof(sSort)); sSort.pOrderBy = p->pOrderBy; /* Try to do various optimizations (flattening subqueries, and strength ** reduction of join operators) in the FROM clause up into the main query */ #if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) for(i=0; !p->pPrior && i<pTabList->nSrc; i++){ SrcItem *pItem = &pTabList->a[i]; Select *pSub = pItem->pSelect; Table *pTab = pItem->pTab; /* The expander should have already created transient Table objects ** even for FROM clause elements such as subqueries that do not correspond ** to a real table */ assert( pTab!=0 ); /* Convert LEFT JOIN into JOIN if there are terms of the right table ** of the LEFT JOIN used in the WHERE clause. */ if( (pItem->fg.jointype & JT_LEFT)!=0 && sqlite3ExprImpliesNonNullRow(p->pWhere, pItem->iCursor) && OptimizationEnabled(db, SQLITE_SimplifyJoin) |
︙ | ︙ | |||
5702 5703 5704 5705 5706 5707 5708 5709 5710 5711 5712 5713 5714 5715 | ** Flattening an aggregate subquery is only possible if the outer query ** is not a join. But if the outer query is not a join, then the subquery ** will be implemented as a co-routine and there is no advantage to ** flattening in that case. */ if( (pSub->selFlags & SF_Aggregate)!=0 ) continue; assert( pSub->pGroupBy==0 ); /* If the outer query contains a "complex" result set (that is, ** if the result set of the outer query uses functions or subqueries) ** and if the subquery contains an ORDER BY clause and if ** it will be implemented as a co-routine, then do not flatten. This ** restriction allows SQL constructs like this: ** | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 6457 6458 6459 6460 6461 6462 6463 6464 6465 6466 6467 6468 6469 6470 6471 6472 6473 6474 6475 6476 6477 6478 6479 6480 6481 6482 6483 6484 6485 6486 6487 6488 6489 6490 6491 6492 6493 6494 6495 6496 6497 6498 6499 6500 6501 6502 6503 | ** Flattening an aggregate subquery is only possible if the outer query ** is not a join. But if the outer query is not a join, then the subquery ** will be implemented as a co-routine and there is no advantage to ** flattening in that case. */ if( (pSub->selFlags & SF_Aggregate)!=0 ) continue; assert( pSub->pGroupBy==0 ); /* If a FROM-clause subquery has an ORDER BY clause that is not ** really doing anything, then delete it now so that it does not ** interfere with query flattening. See the discussion at ** https://sqlite.org/forum/forumpost/2d76f2bcf65d256a ** ** Beware of these cases where the ORDER BY clause may not be safely ** omitted: ** ** (1) There is also a LIMIT clause ** (2) The subquery was added to help with window-function ** processing ** (3) The subquery is in the FROM clause of an UPDATE ** (4) The outer query uses an aggregate function other than ** the built-in count(), min(), or max(). ** (5) The ORDER BY isn't going to accomplish anything because ** one of: ** (a) The outer query has a different ORDER BY clause ** (b) The subquery is part of a join ** See forum post 062d576715d277c8 */ if( pSub->pOrderBy!=0 && (p->pOrderBy!=0 || pTabList->nSrc>1) /* Condition (5) */ && pSub->pLimit==0 /* Condition (1) */ && (pSub->selFlags & SF_OrderByReqd)==0 /* Condition (2) */ && (p->selFlags & SF_OrderByReqd)==0 /* Condition (3) and (4) */ && OptimizationEnabled(db, SQLITE_OmitOrderBy) ){ SELECTTRACE(0x100,pParse,p, ("omit superfluous ORDER BY on %r FROM-clause subquery\n",i+1)); sqlite3ExprListDelete(db, pSub->pOrderBy); pSub->pOrderBy = 0; } /* If the outer query contains a "complex" result set (that is, ** if the result set of the outer query uses functions or subqueries) ** and if the subquery contains an ORDER BY clause and if ** it will be implemented as a co-routine, then do not flatten. This ** restriction allows SQL constructs like this: ** |
︙ | ︙ | |||
5731 5732 5733 5734 5735 5736 5737 5738 5739 5740 5741 5742 5743 5744 | && (pTabList->nSrc==1 || (pTabList->a[1].fg.jointype&(JT_LEFT|JT_CROSS))!=0) ){ continue; } if( flattenSubquery(pParse, p, i, isAgg) ){ /* This subquery can be absorbed into its parent. */ i = -1; } pTabList = p->pSrc; if( db->mallocFailed ) goto select_end; if( !IgnorableOrderby(pDest) ){ sSort.pOrderBy = p->pOrderBy; | > | 6519 6520 6521 6522 6523 6524 6525 6526 6527 6528 6529 6530 6531 6532 6533 | && (pTabList->nSrc==1 || (pTabList->a[1].fg.jointype&(JT_LEFT|JT_CROSS))!=0) ){ continue; } if( flattenSubquery(pParse, p, i, isAgg) ){ if( pParse->nErr ) goto select_end; /* This subquery can be absorbed into its parent. */ i = -1; } pTabList = p->pSrc; if( db->mallocFailed ) goto select_end; if( !IgnorableOrderby(pDest) ){ sSort.pOrderBy = p->pOrderBy; |
︙ | ︙ | |||
5764 5765 5766 5767 5768 5769 5770 | #endif /* Do the WHERE-clause constant propagation optimization if this is ** a join. No need to speed time on this operation for non-join queries ** as the equivalent optimization will be handled by query planner in ** sqlite3WhereBegin(). */ | | > | 6553 6554 6555 6556 6557 6558 6559 6560 6561 6562 6563 6564 6565 6566 6567 6568 | #endif /* Do the WHERE-clause constant propagation optimization if this is ** a join. No need to speed time on this operation for non-join queries ** as the equivalent optimization will be handled by query planner in ** sqlite3WhereBegin(). */ if( p->pWhere!=0 && p->pWhere->op==TK_AND && OptimizationEnabled(db, SQLITE_PropagateConst) && propagateConstants(pParse, p) ){ #if SELECTTRACE_ENABLED if( sqlite3SelectTrace & 0x100 ){ SELECTTRACE(0x100,pParse,p,("After constant propagation:\n")); sqlite3TreeViewSelect(0, p, 0); |
︙ | ︙ | |||
5793 5794 5795 5796 5797 5798 5799 | #endif /* For each term in the FROM clause, do two things: ** (1) Authorized unreferenced tables ** (2) Generate code for all sub-queries */ for(i=0; i<pTabList->nSrc; i++){ | | > | 6583 6584 6585 6586 6587 6588 6589 6590 6591 6592 6593 6594 6595 6596 6597 6598 | #endif /* For each term in the FROM clause, do two things: ** (1) Authorized unreferenced tables ** (2) Generate code for all sub-queries */ for(i=0; i<pTabList->nSrc; i++){ SrcItem *pItem = &pTabList->a[i]; SrcItem *pPrior; SelectDest dest; Select *pSub; #if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) const char *zSavedAuthContext; #endif /* Issue SQLITE_READ authorizations with a fake column name for any |
︙ | ︙ | |||
5816 5817 5818 5819 5820 5821 5822 | ** have a column named by the empty string, in which case there is no way to ** distinguish between an unreferenced table and an actual reference to the ** "" column. The original design was for the fake column name to be a NULL, ** which would be unambiguous. But legacy authorization callbacks might ** assume the column name is non-NULL and segfault. The use of an empty ** string for the fake column name seems safer. */ | | | < < < < < | < < < < < < < < < > > > | | | > | > | | > > > > > > > > > > > > > > > > > > > > > | | < < < < < | | < < < < < < | | | < | > > > > > > > | 6607 6608 6609 6610 6611 6612 6613 6614 6615 6616 6617 6618 6619 6620 6621 6622 6623 6624 6625 6626 6627 6628 6629 6630 6631 6632 6633 6634 6635 6636 6637 6638 6639 6640 6641 6642 6643 6644 6645 6646 6647 6648 6649 6650 6651 6652 6653 6654 6655 6656 6657 6658 6659 6660 6661 6662 6663 6664 6665 6666 6667 6668 6669 6670 6671 6672 6673 6674 6675 6676 6677 6678 6679 6680 6681 6682 6683 6684 6685 6686 6687 6688 6689 6690 6691 6692 6693 6694 6695 6696 6697 6698 6699 6700 6701 6702 6703 6704 6705 6706 6707 6708 6709 6710 6711 6712 6713 6714 6715 6716 6717 6718 6719 6720 6721 6722 6723 6724 6725 6726 6727 6728 6729 6730 6731 6732 6733 6734 6735 6736 6737 6738 6739 6740 6741 6742 6743 6744 6745 6746 6747 6748 6749 6750 6751 6752 6753 6754 6755 | ** have a column named by the empty string, in which case there is no way to ** distinguish between an unreferenced table and an actual reference to the ** "" column. The original design was for the fake column name to be a NULL, ** which would be unambiguous. But legacy authorization callbacks might ** assume the column name is non-NULL and segfault. The use of an empty ** string for the fake column name seems safer. */ if( pItem->colUsed==0 && pItem->zName!=0 ){ sqlite3AuthCheck(pParse, SQLITE_READ, pItem->zName, "", pItem->zDatabase); } #if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) /* Generate code for all sub-queries in the FROM clause */ pSub = pItem->pSelect; if( pSub==0 ) continue; /* The code for a subquery should only be generated once. */ assert( pItem->addrFillSub==0 ); /* Increment Parse.nHeight by the height of the largest expression ** tree referred to by this, the parent select. The child select ** may contain expression trees of at most ** (SQLITE_MAX_EXPR_DEPTH-Parse.nHeight) height. This is a bit ** more conservative than necessary, but much easier than enforcing ** an exact limit. */ pParse->nHeight += sqlite3SelectExprHeight(p); /* Make copies of constant WHERE-clause terms in the outer query down ** inside the subquery. This can help the subquery to run more efficiently. */ if( OptimizationEnabled(db, SQLITE_PushDown) && (pItem->fg.isCte==0 || (pItem->u2.pCteUse->eM10d!=M10d_Yes && pItem->u2.pCteUse->nUse<2)) && pushDownWhereTerms(pParse, pSub, p->pWhere, pItem->iCursor, (pItem->fg.jointype & JT_OUTER)!=0) ){ #if SELECTTRACE_ENABLED if( sqlite3SelectTrace & 0x100 ){ SELECTTRACE(0x100,pParse,p, ("After WHERE-clause push-down into subquery %d:\n", pSub->selId)); sqlite3TreeViewSelect(0, p, 0); } #endif assert( pItem->pSelect && (pItem->pSelect->selFlags & SF_PushDown)!=0 ); }else{ SELECTTRACE(0x100,pParse,p,("Push-down not possible\n")); } zSavedAuthContext = pParse->zAuthContext; pParse->zAuthContext = pItem->zName; /* Generate code to implement the subquery ** ** The subquery is implemented as a co-routine if: ** (1) the subquery is guaranteed to be the outer loop (so that ** it does not need to be computed more than once), and ** (2) the subquery is not a CTE that should be materialized ** ** TODO: Are there other reasons beside (1) and (2) to use a co-routine ** implementation? */ if( i==0 && (pTabList->nSrc==1 || (pTabList->a[1].fg.jointype&(JT_LEFT|JT_CROSS))!=0) /* (1) */ && (pItem->fg.isCte==0 || pItem->u2.pCteUse->eM10d!=M10d_Yes) /* (2) */ ){ /* Implement a co-routine that will return a single row of the result ** set on each invocation. */ int addrTop = sqlite3VdbeCurrentAddr(v)+1; pItem->regReturn = ++pParse->nMem; sqlite3VdbeAddOp3(v, OP_InitCoroutine, pItem->regReturn, 0, addrTop); VdbeComment((v, "%!S", pItem)); pItem->addrFillSub = addrTop; sqlite3SelectDestInit(&dest, SRT_Coroutine, pItem->regReturn); ExplainQueryPlan((pParse, 1, "CO-ROUTINE %!S", pItem)); sqlite3Select(pParse, pSub, &dest); pItem->pTab->nRowLogEst = pSub->nSelectRow; pItem->fg.viaCoroutine = 1; pItem->regResult = dest.iSdst; sqlite3VdbeEndCoroutine(v, pItem->regReturn); sqlite3VdbeJumpHere(v, addrTop-1); sqlite3ClearTempRegCache(pParse); }else if( pItem->fg.isCte && pItem->u2.pCteUse->addrM9e>0 ){ /* This is a CTE for which materialization code has already been ** generated. Invoke the subroutine to compute the materialization, ** the make the pItem->iCursor be a copy of the ephemerial table that ** holds the result of the materialization. */ CteUse *pCteUse = pItem->u2.pCteUse; sqlite3VdbeAddOp2(v, OP_Gosub, pCteUse->regRtn, pCteUse->addrM9e); if( pItem->iCursor!=pCteUse->iCur ){ sqlite3VdbeAddOp2(v, OP_OpenDup, pItem->iCursor, pCteUse->iCur); VdbeComment((v, "%!S", pItem)); } pSub->nSelectRow = pCteUse->nRowEst; }else if( (pPrior = isSelfJoinView(pTabList, pItem))!=0 ){ /* This view has already been materialized by a prior entry in ** this same FROM clause. Reuse it. */ if( pPrior->addrFillSub ){ sqlite3VdbeAddOp2(v, OP_Gosub, pPrior->regReturn, pPrior->addrFillSub); } sqlite3VdbeAddOp2(v, OP_OpenDup, pItem->iCursor, pPrior->iCursor); pSub->nSelectRow = pPrior->pSelect->nSelectRow; }else{ /* Materialize the view. If the view is not correlated, generate a ** subroutine to do the materialization so that subsequent uses of ** the same view can reuse the materialization. */ int topAddr; int onceAddr = 0; int retAddr; pItem->regReturn = ++pParse->nMem; topAddr = sqlite3VdbeAddOp2(v, OP_Integer, 0, pItem->regReturn); pItem->addrFillSub = topAddr+1; if( pItem->fg.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 = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v); VdbeComment((v, "materialize %!S", pItem)); }else{ VdbeNoopComment((v, "materialize %!S", pItem)); } sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor); ExplainQueryPlan((pParse, 1, "MATERIALIZE %!S", pItem)); sqlite3Select(pParse, pSub, &dest); pItem->pTab->nRowLogEst = pSub->nSelectRow; if( onceAddr ) sqlite3VdbeJumpHere(v, onceAddr); retAddr = sqlite3VdbeAddOp1(v, OP_Return, pItem->regReturn); VdbeComment((v, "end %!S", pItem)); sqlite3VdbeChangeP1(v, topAddr, retAddr); sqlite3ClearTempRegCache(pParse); if( pItem->fg.isCte && pItem->fg.isCorrelated==0 ){ CteUse *pCteUse = pItem->u2.pCteUse; pCteUse->addrM9e = pItem->addrFillSub; pCteUse->regRtn = pItem->regReturn; pCteUse->iCur = pItem->iCursor; pCteUse->nRowEst = pSub->nSelectRow; } } if( db->mallocFailed ) goto select_end; pParse->nHeight -= sqlite3SelectExprHeight(p); pParse->zAuthContext = zSavedAuthContext; #endif } |
︙ | ︙ | |||
5983 5984 5985 5986 5987 5988 5989 5990 5991 5992 5993 5994 5995 5996 5997 5998 5999 | ** The second form is preferred as a single index (or temp-table) may be ** used for both the ORDER BY and DISTINCT processing. As originally ** written the query must use a temp-table for at least one of the ORDER ** BY and DISTINCT, and an index or separate temp-table for the other. */ if( (p->selFlags & (SF_Distinct|SF_Aggregate))==SF_Distinct && sqlite3ExprListCompare(sSort.pOrderBy, pEList, -1)==0 ){ p->selFlags &= ~SF_Distinct; pGroupBy = p->pGroupBy = sqlite3ExprListDup(db, pEList, 0); /* Notice that even thought SF_Distinct has been cleared from p->selFlags, ** the sDistinct.isTnct is still set. Hence, isTnct represents the ** original setting of the SF_Distinct flag, not the current setting */ assert( sDistinct.isTnct ); #if SELECTTRACE_ENABLED if( sqlite3SelectTrace & 0x400 ){ | > > > > | 6781 6782 6783 6784 6785 6786 6787 6788 6789 6790 6791 6792 6793 6794 6795 6796 6797 6798 6799 6800 6801 | ** The second form is preferred as a single index (or temp-table) may be ** used for both the ORDER BY and DISTINCT processing. As originally ** written the query must use a temp-table for at least one of the ORDER ** BY and DISTINCT, and an index or separate temp-table for the other. */ if( (p->selFlags & (SF_Distinct|SF_Aggregate))==SF_Distinct && sqlite3ExprListCompare(sSort.pOrderBy, pEList, -1)==0 #ifndef SQLITE_OMIT_WINDOWFUNC && p->pWin==0 #endif ){ p->selFlags &= ~SF_Distinct; pGroupBy = p->pGroupBy = sqlite3ExprListDup(db, pEList, 0); p->selFlags |= SF_Aggregate; /* Notice that even thought SF_Distinct has been cleared from p->selFlags, ** the sDistinct.isTnct is still set. Hence, isTnct represents the ** original setting of the SF_Distinct flag, not the current setting */ assert( sDistinct.isTnct ); #if SELECTTRACE_ENABLED if( sqlite3SelectTrace & 0x400 ){ |
︙ | ︙ | |||
6029 6030 6031 6032 6033 6034 6035 | */ if( pDest->eDest==SRT_EphemTab ){ sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pDest->iSDParm, pEList->nExpr); } /* Set the limiter. */ | | | 6831 6832 6833 6834 6835 6836 6837 6838 6839 6840 6841 6842 6843 6844 6845 | */ if( pDest->eDest==SRT_EphemTab ){ sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pDest->iSDParm, pEList->nExpr); } /* Set the limiter. */ iEnd = sqlite3VdbeMakeLabel(pParse); if( (p->selFlags & SF_FixedLimit)==0 ){ p->nSelectRow = 320; /* 4 billion rows */ } computeLimitRegisters(pParse, p, iEnd); if( p->iLimit==0 && sSort.addrSortIndex>=0 ){ sqlite3VdbeChangeOpcode(v, sSort.addrSortIndex, OP_SorterOpen); sSort.sortFlags |= SORTFLAG_UseSorter; |
︙ | ︙ | |||
6058 6059 6060 6061 6062 6063 6064 | } if( !isAgg && pGroupBy==0 ){ /* No aggregate functions and no GROUP BY clause */ u16 wctrlFlags = (sDistinct.isTnct ? WHERE_WANT_DISTINCT : 0) | (p->selFlags & SF_FixedLimit); #ifndef SQLITE_OMIT_WINDOWFUNC | | | | 6860 6861 6862 6863 6864 6865 6866 6867 6868 6869 6870 6871 6872 6873 6874 6875 6876 | } if( !isAgg && pGroupBy==0 ){ /* No aggregate functions and no GROUP BY clause */ u16 wctrlFlags = (sDistinct.isTnct ? WHERE_WANT_DISTINCT : 0) | (p->selFlags & SF_FixedLimit); #ifndef SQLITE_OMIT_WINDOWFUNC Window *pWin = p->pWin; /* Main window object (or NULL) */ if( pWin ){ sqlite3WindowCodeInit(pParse, p); } #endif assert( WHERE_USE_LIMIT==SF_FixedLimit ); /* Begin the database scan. */ SELECTTRACE(1,pParse,p,("WhereBegin\n")); |
︙ | ︙ | |||
6084 6085 6086 6087 6088 6089 6090 6091 6092 6093 6094 6095 6096 6097 6098 6099 6100 6101 6102 | if( sSort.pOrderBy ){ sSort.nOBSat = sqlite3WhereIsOrdered(pWInfo); sSort.labelOBLopt = sqlite3WhereOrderByLimitOptLabel(pWInfo); if( sSort.nOBSat==sSort.pOrderBy->nExpr ){ sSort.pOrderBy = 0; } } /* If sorting index that was created by a prior OP_OpenEphemeral ** instruction ended up not being needed, then change the OP_OpenEphemeral ** into an OP_Noop. */ if( sSort.addrSortIndex>=0 && sSort.pOrderBy==0 ){ sqlite3VdbeChangeToNoop(v, sSort.addrSortIndex); } assert( p->pEList==pEList ); #ifndef SQLITE_OMIT_WINDOWFUNC if( pWin ){ | > | | | | 6886 6887 6888 6889 6890 6891 6892 6893 6894 6895 6896 6897 6898 6899 6900 6901 6902 6903 6904 6905 6906 6907 6908 6909 6910 6911 6912 6913 6914 6915 | if( sSort.pOrderBy ){ sSort.nOBSat = sqlite3WhereIsOrdered(pWInfo); sSort.labelOBLopt = sqlite3WhereOrderByLimitOptLabel(pWInfo); if( sSort.nOBSat==sSort.pOrderBy->nExpr ){ sSort.pOrderBy = 0; } } SELECTTRACE(1,pParse,p,("WhereBegin returns\n")); /* If sorting index that was created by a prior OP_OpenEphemeral ** instruction ended up not being needed, then change the OP_OpenEphemeral ** into an OP_Noop. */ if( sSort.addrSortIndex>=0 && sSort.pOrderBy==0 ){ sqlite3VdbeChangeToNoop(v, sSort.addrSortIndex); } assert( p->pEList==pEList ); #ifndef SQLITE_OMIT_WINDOWFUNC if( pWin ){ int addrGosub = sqlite3VdbeMakeLabel(pParse); int iCont = sqlite3VdbeMakeLabel(pParse); int iBreak = sqlite3VdbeMakeLabel(pParse); int regGosub = ++pParse->nMem; sqlite3WindowCodeStep(pParse, p, pWInfo, regGosub, addrGosub); sqlite3VdbeAddOp2(v, OP_Goto, 0, iBreak); sqlite3VdbeResolveLabel(v, addrGosub); VdbeNoopComment((v, "inner-loop subroutine")); |
︙ | ︙ | |||
6122 6123 6124 6125 6126 6127 6128 6129 6130 6131 6132 6133 6134 6135 | /* Use the standard inner loop. */ selectInnerLoop(pParse, p, -1, &sSort, &sDistinct, pDest, sqlite3WhereContinueLabel(pWInfo), sqlite3WhereBreakLabel(pWInfo)); /* End the database scan loop. */ sqlite3WhereEnd(pWInfo); } }else{ /* This case when there exist aggregate functions or a GROUP BY clause ** or both */ NameContext sNC; /* Name context for processing aggregate information */ int iAMem; /* First Mem address for storing current GROUP BY */ | > | 6925 6926 6927 6928 6929 6930 6931 6932 6933 6934 6935 6936 6937 6938 6939 | /* Use the standard inner loop. */ selectInnerLoop(pParse, p, -1, &sSort, &sDistinct, pDest, sqlite3WhereContinueLabel(pWInfo), sqlite3WhereBreakLabel(pWInfo)); /* End the database scan loop. */ SELECTTRACE(1,pParse,p,("WhereEnd\n")); sqlite3WhereEnd(pWInfo); } }else{ /* This case when there exist aggregate functions or a GROUP BY clause ** or both */ NameContext sNC; /* Name context for processing aggregate information */ int iAMem; /* First Mem address for storing current GROUP BY */ |
︙ | ︙ | |||
6155 6156 6157 6158 6159 6160 6161 6162 6163 6164 6165 6166 | pItem->u.x.iAlias = 0; } for(k=pGroupBy->nExpr, pItem=pGroupBy->a; k>0; k--, pItem++){ pItem->u.x.iAlias = 0; } assert( 66==sqlite3LogEst(100) ); if( p->nSelectRow>66 ) p->nSelectRow = 66; }else{ assert( 0==sqlite3LogEst(1) ); p->nSelectRow = 0; } | > > > > > > > > > > > > > > > > > > > > > > > > < < < < < < < < < < < < | > > > > > > > > > > | | | | | | | | | > | > > > > > > | | > > > > | | | | | | > > > > > > > > > > > > > > > > | | > | | | | | | > > > > > | 6959 6960 6961 6962 6963 6964 6965 6966 6967 6968 6969 6970 6971 6972 6973 6974 6975 6976 6977 6978 6979 6980 6981 6982 6983 6984 6985 6986 6987 6988 6989 6990 6991 6992 6993 6994 6995 6996 6997 6998 6999 7000 7001 7002 7003 7004 7005 7006 7007 7008 7009 7010 7011 7012 7013 7014 7015 7016 7017 7018 7019 7020 7021 7022 7023 7024 7025 7026 7027 7028 7029 7030 7031 7032 7033 7034 7035 7036 7037 7038 7039 7040 7041 7042 7043 7044 7045 7046 7047 7048 7049 7050 7051 7052 7053 7054 7055 7056 7057 7058 7059 7060 7061 7062 7063 7064 7065 7066 7067 7068 7069 7070 7071 7072 7073 7074 7075 7076 7077 7078 7079 7080 7081 7082 7083 7084 7085 7086 7087 7088 7089 7090 7091 7092 7093 7094 7095 7096 7097 7098 7099 7100 7101 7102 7103 7104 7105 7106 7107 7108 7109 7110 7111 7112 7113 7114 7115 7116 7117 7118 7119 7120 7121 7122 7123 7124 7125 7126 7127 7128 7129 7130 7131 7132 7133 7134 7135 7136 7137 7138 7139 7140 7141 7142 7143 7144 7145 7146 7147 7148 7149 7150 7151 7152 7153 7154 7155 7156 | pItem->u.x.iAlias = 0; } for(k=pGroupBy->nExpr, pItem=pGroupBy->a; k>0; k--, pItem++){ pItem->u.x.iAlias = 0; } assert( 66==sqlite3LogEst(100) ); if( p->nSelectRow>66 ) p->nSelectRow = 66; /* If there is both a GROUP BY and an ORDER BY clause and they are ** identical, then it may be possible to disable the ORDER BY clause ** on the grounds that the GROUP BY will cause elements to come out ** in the correct order. It also may not - the GROUP BY might use a ** database index that causes rows to be grouped together as required ** but not actually sorted. Either way, record the fact that the ** ORDER BY and GROUP BY clauses are the same by setting the orderByGrp ** variable. */ if( sSort.pOrderBy && pGroupBy->nExpr==sSort.pOrderBy->nExpr ){ int ii; /* The GROUP BY processing doesn't care whether rows are delivered in ** ASC or DESC order - only that each group is returned contiguously. ** So set the ASC/DESC flags in the GROUP BY to match those in the ** ORDER BY to maximize the chances of rows being delivered in an ** order that makes the ORDER BY redundant. */ for(ii=0; ii<pGroupBy->nExpr; ii++){ u8 sortFlags = sSort.pOrderBy->a[ii].sortFlags & KEYINFO_ORDER_DESC; pGroupBy->a[ii].sortFlags = sortFlags; } if( sqlite3ExprListCompare(pGroupBy, sSort.pOrderBy, -1)==0 ){ orderByGrp = 1; } } }else{ assert( 0==sqlite3LogEst(1) ); p->nSelectRow = 0; } /* Create a label to jump to when we want to abort the query */ addrEnd = sqlite3VdbeMakeLabel(pParse); /* Convert TK_COLUMN nodes into TK_AGG_COLUMN and make entries in ** sAggInfo for all TK_AGG_FUNCTION nodes in expressions of the ** SELECT statement. */ pAggInfo = sqlite3DbMallocZero(db, sizeof(*pAggInfo) ); if( pAggInfo ){ sqlite3ParserAddCleanup(pParse, (void(*)(sqlite3*,void*))agginfoFree, pAggInfo); testcase( pParse->earlyCleanup ); } if( db->mallocFailed ){ goto select_end; } pAggInfo->selId = p->selId; memset(&sNC, 0, sizeof(sNC)); sNC.pParse = pParse; sNC.pSrcList = pTabList; sNC.uNC.pAggInfo = pAggInfo; VVA_ONLY( sNC.ncFlags = NC_UAggInfo; ) pAggInfo->mnReg = pParse->nMem+1; pAggInfo->nSortingColumn = pGroupBy ? pGroupBy->nExpr : 0; pAggInfo->pGroupBy = pGroupBy; sqlite3ExprAnalyzeAggList(&sNC, pEList); sqlite3ExprAnalyzeAggList(&sNC, sSort.pOrderBy); if( pHaving ){ if( pGroupBy ){ assert( pWhere==p->pWhere ); assert( pHaving==p->pHaving ); assert( pGroupBy==p->pGroupBy ); havingToWhere(pParse, p); pWhere = p->pWhere; } sqlite3ExprAnalyzeAggregates(&sNC, pHaving); } pAggInfo->nAccumulator = pAggInfo->nColumn; if( p->pGroupBy==0 && p->pHaving==0 && pAggInfo->nFunc==1 ){ minMaxFlag = minMaxQuery(db, pAggInfo->aFunc[0].pFExpr, &pMinMaxOrderBy); }else{ minMaxFlag = WHERE_ORDERBY_NORMAL; } for(i=0; i<pAggInfo->nFunc; i++){ Expr *pExpr = pAggInfo->aFunc[i].pFExpr; assert( ExprUseXList(pExpr) ); sNC.ncFlags |= NC_InAggFunc; sqlite3ExprAnalyzeAggList(&sNC, pExpr->x.pList); #ifndef SQLITE_OMIT_WINDOWFUNC assert( !IsWindowFunc(pExpr) ); if( ExprHasProperty(pExpr, EP_WinFunc) ){ sqlite3ExprAnalyzeAggregates(&sNC, pExpr->y.pWin->pFilter); } #endif sNC.ncFlags &= ~NC_InAggFunc; } pAggInfo->mxReg = pParse->nMem; if( db->mallocFailed ) goto select_end; #if SELECTTRACE_ENABLED if( sqlite3SelectTrace & 0x400 ){ int ii; SELECTTRACE(0x400,pParse,p,("After aggregate analysis %p:\n", pAggInfo)); sqlite3TreeViewSelect(0, p, 0); if( minMaxFlag ){ sqlite3DebugPrintf("MIN/MAX Optimization (0x%02x) adds:\n", minMaxFlag); sqlite3TreeViewExprList(0, pMinMaxOrderBy, 0, "ORDERBY"); } for(ii=0; ii<pAggInfo->nColumn; ii++){ sqlite3DebugPrintf("agg-column[%d] iMem=%d\n", ii, pAggInfo->aCol[ii].iMem); sqlite3TreeViewExpr(0, pAggInfo->aCol[ii].pCExpr, 0); } for(ii=0; ii<pAggInfo->nFunc; ii++){ sqlite3DebugPrintf("agg-func[%d]: iMem=%d\n", ii, pAggInfo->aFunc[ii].iMem); sqlite3TreeViewExpr(0, pAggInfo->aFunc[ii].pFExpr, 0); } } #endif /* Processing for aggregates with GROUP BY is very different and ** much more complex than aggregates without a GROUP BY. */ if( pGroupBy ){ KeyInfo *pKeyInfo; /* Keying information for the group by clause */ int addr1; /* A-vs-B comparision jump */ int addrOutputRow; /* Start of subroutine that outputs a result row */ int regOutputRow; /* Return address register for output subroutine */ int addrSetAbort; /* Set the abort flag and return */ int addrTopOfLoop; /* Top of the input loop */ int addrSortingIdx; /* The OP_OpenEphemeral for the sorting index */ int addrReset; /* Subroutine for resetting the accumulator */ int regReset; /* Return address register for reset subroutine */ ExprList *pDistinct = 0; u16 distFlag = 0; int eDist = WHERE_DISTINCT_NOOP; if( pAggInfo->nFunc==1 && pAggInfo->aFunc[0].iDistinct>=0 && ALWAYS(pAggInfo->aFunc[0].pFExpr!=0) && ALWAYS(ExprUseXList(pAggInfo->aFunc[0].pFExpr)) && pAggInfo->aFunc[0].pFExpr->x.pList!=0 ){ Expr *pExpr = pAggInfo->aFunc[0].pFExpr->x.pList->a[0].pExpr; pExpr = sqlite3ExprDup(db, pExpr, 0); pDistinct = sqlite3ExprListDup(db, pGroupBy, 0); pDistinct = sqlite3ExprListAppend(pParse, pDistinct, pExpr); distFlag = pDistinct ? (WHERE_WANT_DISTINCT|WHERE_AGG_DISTINCT) : 0; } /* If there is a GROUP BY clause we might need a sorting index to ** implement it. Allocate that sorting index now. If it turns out ** that we do not need it after all, the OP_SorterOpen instruction ** will be converted into a Noop. */ pAggInfo->sortingIdx = pParse->nTab++; pKeyInfo = sqlite3KeyInfoFromExprList(pParse, pGroupBy, 0, pAggInfo->nColumn); addrSortingIdx = sqlite3VdbeAddOp4(v, OP_SorterOpen, pAggInfo->sortingIdx, pAggInfo->nSortingColumn, 0, (char*)pKeyInfo, P4_KEYINFO); /* Initialize memory locations used by GROUP BY aggregate processing */ iUseFlag = ++pParse->nMem; iAbortFlag = ++pParse->nMem; regOutputRow = ++pParse->nMem; addrOutputRow = sqlite3VdbeMakeLabel(pParse); regReset = ++pParse->nMem; addrReset = sqlite3VdbeMakeLabel(pParse); iAMem = pParse->nMem + 1; pParse->nMem += pGroupBy->nExpr; iBMem = pParse->nMem + 1; pParse->nMem += pGroupBy->nExpr; sqlite3VdbeAddOp2(v, OP_Integer, 0, iAbortFlag); VdbeComment((v, "clear abort flag")); sqlite3VdbeAddOp3(v, OP_Null, 0, iAMem, iAMem+pGroupBy->nExpr-1); /* Begin a loop that will extract all source rows in GROUP BY order. ** This might involve two separate loops with an OP_Sort in between, or ** it might be a single loop that uses an index to extract information ** in the right order to begin with. */ sqlite3VdbeAddOp2(v, OP_Gosub, regReset, addrReset); SELECTTRACE(1,pParse,p,("WhereBegin\n")); pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pGroupBy, pDistinct, WHERE_GROUPBY | (orderByGrp ? WHERE_SORTBYGROUP : 0) | distFlag, 0 ); if( pWInfo==0 ){ sqlite3ExprListDelete(db, pDistinct); goto select_end; } eDist = sqlite3WhereIsDistinct(pWInfo); SELECTTRACE(1,pParse,p,("WhereBegin returns\n")); if( sqlite3WhereIsOrdered(pWInfo)==pGroupBy->nExpr ){ /* The optimizer is able to deliver rows in group by order so ** we do not have to sort. The OP_OpenEphemeral table will be ** cancelled later because we still need to use the pKeyInfo */ groupBySort = 0; }else{ |
︙ | ︙ | |||
6309 6310 6311 6312 6313 6314 6315 | (sDistinct.isTnct && (p->selFlags&SF_Distinct)==0) ? "DISTINCT" : "GROUP BY"); groupBySort = 1; nGroupBy = pGroupBy->nExpr; nCol = nGroupBy; j = nGroupBy; | | | | | | > | | | | 7168 7169 7170 7171 7172 7173 7174 7175 7176 7177 7178 7179 7180 7181 7182 7183 7184 7185 7186 7187 7188 7189 7190 7191 7192 7193 7194 7195 7196 7197 7198 7199 7200 7201 7202 7203 7204 7205 7206 7207 7208 7209 7210 7211 7212 | (sDistinct.isTnct && (p->selFlags&SF_Distinct)==0) ? "DISTINCT" : "GROUP BY"); groupBySort = 1; nGroupBy = pGroupBy->nExpr; nCol = nGroupBy; j = nGroupBy; for(i=0; i<pAggInfo->nColumn; i++){ if( pAggInfo->aCol[i].iSorterColumn>=j ){ nCol++; j++; } } regBase = sqlite3GetTempRange(pParse, nCol); sqlite3ExprCodeExprList(pParse, pGroupBy, regBase, 0, 0); j = nGroupBy; for(i=0; i<pAggInfo->nColumn; i++){ struct AggInfo_col *pCol = &pAggInfo->aCol[i]; if( pCol->iSorterColumn>=j ){ int r1 = j + regBase; sqlite3ExprCodeGetColumnOfTable(v, pCol->pTab, pCol->iTable, pCol->iColumn, r1); j++; } } regRecord = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase, nCol, regRecord); sqlite3VdbeAddOp2(v, OP_SorterInsert, pAggInfo->sortingIdx, regRecord); sqlite3ReleaseTempReg(pParse, regRecord); sqlite3ReleaseTempRange(pParse, regBase, nCol); SELECTTRACE(1,pParse,p,("WhereEnd\n")); sqlite3WhereEnd(pWInfo); pAggInfo->sortingIdxPTab = sortPTab = pParse->nTab++; sortOut = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp3(v, OP_OpenPseudo, sortPTab, sortOut, nCol); sqlite3VdbeAddOp2(v, OP_SorterSort, pAggInfo->sortingIdx, addrEnd); VdbeComment((v, "GROUP BY sort")); VdbeCoverage(v); pAggInfo->useSortingIdx = 1; } /* If the index or temporary table used by the GROUP BY sort ** will naturally deliver rows in the order required by the ORDER BY ** clause, cancel the ephemeral table open coded earlier. ** ** This is an optimization - the correct answer should result regardless. |
︙ | ︙ | |||
6362 6363 6364 6365 6366 6367 6368 | /* Evaluate the current GROUP BY terms and store in b0, b1, b2... ** (b0 is memory location iBMem+0, b1 is iBMem+1, and so forth) ** Then compare the current GROUP BY terms against the GROUP BY terms ** from the previous row currently stored in a0, a1, a2... */ addrTopOfLoop = sqlite3VdbeCurrentAddr(v); if( groupBySort ){ | | | | 7222 7223 7224 7225 7226 7227 7228 7229 7230 7231 7232 7233 7234 7235 7236 7237 7238 7239 7240 7241 7242 7243 | /* Evaluate the current GROUP BY terms and store in b0, b1, b2... ** (b0 is memory location iBMem+0, b1 is iBMem+1, and so forth) ** Then compare the current GROUP BY terms against the GROUP BY terms ** from the previous row currently stored in a0, a1, a2... */ addrTopOfLoop = sqlite3VdbeCurrentAddr(v); if( groupBySort ){ sqlite3VdbeAddOp3(v, OP_SorterData, pAggInfo->sortingIdx, sortOut, sortPTab); } for(j=0; j<pGroupBy->nExpr; j++){ if( groupBySort ){ sqlite3VdbeAddOp3(v, OP_Column, sortPTab, j, iBMem+j); }else{ pAggInfo->directMode = 1; sqlite3ExprCode(pParse, pGroupBy->a[j].pExpr, iBMem+j); } } sqlite3VdbeAddOp4(v, OP_Compare, iAMem, iBMem, pGroupBy->nExpr, (char*)sqlite3KeyInfoRef(pKeyInfo), P4_KEYINFO); addr1 = sqlite3VdbeCurrentAddr(v); sqlite3VdbeAddOp3(v, OP_Jump, addr1+1, 0, addr1+1); VdbeCoverage(v); |
︙ | ︙ | |||
6399 6400 6401 6402 6403 6404 6405 | sqlite3VdbeAddOp2(v, OP_Gosub, regReset, addrReset); VdbeComment((v, "reset accumulator")); /* Update the aggregate accumulators based on the content of ** the current row */ sqlite3VdbeJumpHere(v, addr1); | | | > > | 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 | sqlite3VdbeAddOp2(v, OP_Gosub, regReset, addrReset); VdbeComment((v, "reset accumulator")); /* Update the aggregate accumulators based on the content of ** the current row */ sqlite3VdbeJumpHere(v, addr1); updateAccumulator(pParse, iUseFlag, pAggInfo, eDist); sqlite3VdbeAddOp2(v, OP_Integer, 1, iUseFlag); VdbeComment((v, "indicate data in accumulator")); /* End of the loop */ if( groupBySort ){ sqlite3VdbeAddOp2(v, OP_SorterNext, pAggInfo->sortingIdx,addrTopOfLoop); VdbeCoverage(v); }else{ SELECTTRACE(1,pParse,p,("WhereEnd\n")); sqlite3WhereEnd(pWInfo); sqlite3VdbeChangeToNoop(v, addrSortingIdx); } sqlite3ExprListDelete(db, pDistinct); /* Output the final row of result */ sqlite3VdbeAddOp2(v, OP_Gosub, regOutputRow, addrOutputRow); VdbeComment((v, "output final row")); /* Jump over the subroutines |
︙ | ︙ | |||
6439 6440 6441 6442 6443 6444 6445 | sqlite3VdbeAddOp1(v, OP_Return, regOutputRow); sqlite3VdbeResolveLabel(v, addrOutputRow); addrOutputRow = sqlite3VdbeCurrentAddr(v); sqlite3VdbeAddOp2(v, OP_IfPos, iUseFlag, addrOutputRow+2); VdbeCoverage(v); VdbeComment((v, "Groupby result generator entry point")); sqlite3VdbeAddOp1(v, OP_Return, regOutputRow); | | | | > > > > < | | > | | | | | | | > | | | < < > > > | | | > | > > > | | | > > > | > | > | > > > > | | > > | > > > > > | | < < > | | 7301 7302 7303 7304 7305 7306 7307 7308 7309 7310 7311 7312 7313 7314 7315 7316 7317 7318 7319 7320 7321 7322 7323 7324 7325 7326 7327 7328 7329 7330 7331 7332 7333 7334 7335 7336 7337 7338 7339 7340 7341 7342 7343 7344 7345 7346 7347 7348 7349 7350 7351 7352 7353 7354 7355 7356 7357 7358 7359 7360 7361 7362 7363 7364 7365 7366 7367 7368 7369 7370 7371 7372 7373 7374 7375 7376 7377 7378 7379 7380 7381 7382 7383 7384 7385 7386 7387 7388 7389 7390 7391 7392 7393 7394 7395 7396 7397 7398 7399 7400 7401 7402 7403 7404 7405 7406 7407 7408 7409 7410 7411 7412 7413 7414 7415 7416 7417 7418 7419 7420 7421 7422 7423 7424 7425 7426 7427 7428 7429 7430 7431 7432 7433 7434 7435 7436 7437 7438 7439 7440 7441 7442 7443 7444 7445 7446 7447 7448 7449 7450 7451 7452 7453 7454 7455 7456 7457 7458 7459 7460 7461 7462 7463 7464 7465 | sqlite3VdbeAddOp1(v, OP_Return, regOutputRow); sqlite3VdbeResolveLabel(v, addrOutputRow); addrOutputRow = sqlite3VdbeCurrentAddr(v); sqlite3VdbeAddOp2(v, OP_IfPos, iUseFlag, addrOutputRow+2); VdbeCoverage(v); VdbeComment((v, "Groupby result generator entry point")); sqlite3VdbeAddOp1(v, OP_Return, regOutputRow); finalizeAggFunctions(pParse, pAggInfo); sqlite3ExprIfFalse(pParse, pHaving, addrOutputRow+1, SQLITE_JUMPIFNULL); selectInnerLoop(pParse, p, -1, &sSort, &sDistinct, pDest, addrOutputRow+1, addrSetAbort); sqlite3VdbeAddOp1(v, OP_Return, regOutputRow); VdbeComment((v, "end groupby result generator")); /* Generate a subroutine that will reset the group-by accumulator */ sqlite3VdbeResolveLabel(v, addrReset); resetAccumulator(pParse, pAggInfo); sqlite3VdbeAddOp2(v, OP_Integer, 0, iUseFlag); VdbeComment((v, "indicate accumulator empty")); sqlite3VdbeAddOp1(v, OP_Return, regReset); if( eDist!=WHERE_DISTINCT_NOOP ){ struct AggInfo_func *pF = &pAggInfo->aFunc[0]; fixDistinctOpenEph(pParse, eDist, pF->iDistinct, pF->iDistAddr); } } /* endif pGroupBy. Begin aggregate queries without GROUP BY: */ else { Table *pTab; if( (pTab = isSimpleCount(p, pAggInfo))!=0 ){ /* If isSimpleCount() returns a pointer to a Table structure, then ** the SQL statement is of the form: ** ** SELECT count(*) FROM <tbl> ** ** where the Table structure returned represents table <tbl>. ** ** This statement is so common that it is optimized specially. The ** OP_Count instruction is executed either on the intkey table that ** contains the data for table <tbl> or on one of its indexes. It ** is better to execute the op on an index, as indexes are almost ** always spread across less pages than their corresponding tables. */ const int iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); const int iCsr = pParse->nTab++; /* Cursor to scan b-tree */ Index *pIdx; /* Iterator variable */ KeyInfo *pKeyInfo = 0; /* Keyinfo for scanned index */ Index *pBest = 0; /* Best index found so far */ Pgno iRoot = pTab->tnum; /* Root page of scanned b-tree */ sqlite3CodeVerifySchema(pParse, iDb); sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName); /* Search for the index that has the lowest scan cost. ** ** (2011-04-15) Do not do a full scan of an unordered index. ** ** (2013-10-03) Do not count the entries in a partial index. ** ** In practice the KeyInfo structure will not be used. It is only ** passed to keep OP_OpenRead happy. */ if( !HasRowid(pTab) ) pBest = sqlite3PrimaryKeyIndex(pTab); if( !p->pSrc->a[0].fg.notIndexed ){ for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ if( pIdx->bUnordered==0 && pIdx->szIdxRow<pTab->szTabRow && pIdx->pPartIdxWhere==0 && (!pBest || pIdx->szIdxRow<pBest->szIdxRow) ){ pBest = pIdx; } } } if( pBest ){ iRoot = pBest->tnum; pKeyInfo = sqlite3KeyInfoOfIndex(pParse, pBest); } /* Open a read-only cursor, execute the OP_Count, close the cursor. */ sqlite3VdbeAddOp4Int(v, OP_OpenRead, iCsr, (int)iRoot, iDb, 1); if( pKeyInfo ){ sqlite3VdbeChangeP4(v, -1, (char *)pKeyInfo, P4_KEYINFO); } sqlite3VdbeAddOp2(v, OP_Count, iCsr, pAggInfo->aFunc[0].iMem); sqlite3VdbeAddOp1(v, OP_Close, iCsr); explainSimpleCount(pParse, pTab, pBest); }else{ int regAcc = 0; /* "populate accumulators" flag */ ExprList *pDistinct = 0; u16 distFlag = 0; int eDist; /* If there are accumulator registers but no min() or max() functions ** without FILTER clauses, allocate register regAcc. Register regAcc ** will contain 0 the first time the inner loop runs, and 1 thereafter. ** The code generated by updateAccumulator() uses this to ensure ** that the accumulator registers are (a) updated only once if ** there are no min() or max functions or (b) always updated for the ** first row visited by the aggregate, so that they are updated at ** least once even if the FILTER clause means the min() or max() ** function visits zero rows. */ if( pAggInfo->nAccumulator ){ for(i=0; i<pAggInfo->nFunc; i++){ if( ExprHasProperty(pAggInfo->aFunc[i].pFExpr, EP_WinFunc) ){ continue; } if( pAggInfo->aFunc[i].pFunc->funcFlags&SQLITE_FUNC_NEEDCOLL ){ break; } } if( i==pAggInfo->nFunc ){ regAcc = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_Integer, 0, regAcc); } }else if( pAggInfo->nFunc==1 && pAggInfo->aFunc[0].iDistinct>=0 ){ assert( ExprUseXList(pAggInfo->aFunc[0].pFExpr) ); pDistinct = pAggInfo->aFunc[0].pFExpr->x.pList; distFlag = pDistinct ? (WHERE_WANT_DISTINCT|WHERE_AGG_DISTINCT) : 0; } /* This case runs if the aggregate has no GROUP BY clause. The ** processing is much simpler since there is only a single row ** of output. */ assert( p->pGroupBy==0 ); resetAccumulator(pParse, pAggInfo); /* If this query is a candidate for the min/max optimization, then ** minMaxFlag will have been previously set to either ** WHERE_ORDERBY_MIN or WHERE_ORDERBY_MAX and pMinMaxOrderBy will ** be an appropriate ORDER BY expression for the optimization. */ assert( minMaxFlag==WHERE_ORDERBY_NORMAL || pMinMaxOrderBy!=0 ); assert( pMinMaxOrderBy==0 || pMinMaxOrderBy->nExpr==1 ); SELECTTRACE(1,pParse,p,("WhereBegin\n")); pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pMinMaxOrderBy, pDistinct, minMaxFlag|distFlag, 0); if( pWInfo==0 ){ goto select_end; } SELECTTRACE(1,pParse,p,("WhereBegin returns\n")); eDist = sqlite3WhereIsDistinct(pWInfo); updateAccumulator(pParse, regAcc, pAggInfo, eDist); if( eDist!=WHERE_DISTINCT_NOOP ){ struct AggInfo_func *pF = &pAggInfo->aFunc[0]; fixDistinctOpenEph(pParse, eDist, pF->iDistinct, pF->iDistAddr); } if( regAcc ) sqlite3VdbeAddOp2(v, OP_Integer, 1, regAcc); if( minMaxFlag ){ sqlite3WhereMinMaxOptEarlyOut(v, pWInfo); } SELECTTRACE(1,pParse,p,("WhereEnd\n")); sqlite3WhereEnd(pWInfo); finalizeAggFunctions(pParse, pAggInfo); } sSort.pOrderBy = 0; sqlite3ExprIfFalse(pParse, pHaving, addrEnd, SQLITE_JUMPIFNULL); selectInnerLoop(pParse, p, -1, 0, 0, pDest, addrEnd, addrEnd); } |
︙ | ︙ | |||
6602 6603 6604 6605 6606 6607 6608 6609 | ** set the return code to 1. Otherwise 0. */ rc = (pParse->nErr>0); /* Control jumps to here if an error is encountered above, or upon ** successful coding of the SELECT. */ select_end: sqlite3ExprListDelete(db, pMinMaxOrderBy); | > > > > > > > > > > | > > > > > > > | | 7489 7490 7491 7492 7493 7494 7495 7496 7497 7498 7499 7500 7501 7502 7503 7504 7505 7506 7507 7508 7509 7510 7511 7512 7513 7514 7515 7516 7517 7518 7519 7520 7521 7522 7523 7524 | ** set the return code to 1. Otherwise 0. */ rc = (pParse->nErr>0); /* Control jumps to here if an error is encountered above, or upon ** successful coding of the SELECT. */ select_end: assert( db->mallocFailed==0 || db->mallocFailed==1 ); pParse->nErr += db->mallocFailed; sqlite3ExprListDelete(db, pMinMaxOrderBy); #ifdef SQLITE_DEBUG if( pAggInfo && !db->mallocFailed ){ for(i=0; i<pAggInfo->nColumn; i++){ Expr *pExpr = pAggInfo->aCol[i].pCExpr; assert( pExpr!=0 ); assert( pExpr->pAggInfo==pAggInfo ); assert( pExpr->iAgg==i ); } for(i=0; i<pAggInfo->nFunc; i++){ Expr *pExpr = pAggInfo->aFunc[i].pFExpr; assert( pExpr!=0 ); assert( pExpr->pAggInfo==pAggInfo ); assert( pExpr->iAgg==i ); } } #endif #if SELECTTRACE_ENABLED SELECTTRACE(0x1,pParse,p,("end processing\n")); if( (sqlite3SelectTrace & 0x2000)!=0 && ExplainQueryPlanParent(pParse)==0 ){ sqlite3TreeViewSelect(0, p, 0); } #endif ExplainQueryPlanPop(pParse); return rc; } |
Changes to src/shell.c.in.
︙ | ︙ | |||
13 14 15 16 17 18 19 20 21 22 23 24 25 26 | ** utility for accessing SQLite databases. */ #if (defined(_WIN32) || defined(WIN32)) && !defined(_CRT_SECURE_NO_WARNINGS) /* This needs to come before any includes for MSVC compiler */ #define _CRT_SECURE_NO_WARNINGS #endif /* ** Warning pragmas copied from msvc.h in the core. */ #if defined(_MSC_VER) #pragma warning(disable : 4054) #pragma warning(disable : 4055) #pragma warning(disable : 4100) | > > > > > > > > > > > > > > > > > > > > | 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 | ** utility for accessing SQLite databases. */ #if (defined(_WIN32) || defined(WIN32)) && !defined(_CRT_SECURE_NO_WARNINGS) /* This needs to come before any includes for MSVC compiler */ #define _CRT_SECURE_NO_WARNINGS #endif /* ** Optionally #include a user-defined header, whereby compilation options ** may be set prior to where they take effect, but after platform setup. ** If SQLITE_CUSTOM_INCLUDE=? is defined, its value names the #include ** file. Note that this macro has a like effect on sqlite3.c compilation. */ #ifdef SQLITE_CUSTOM_INCLUDE # define INC_STRINGIFY_(f) #f # define INC_STRINGIFY(f) INC_STRINGIFY_(f) # include INC_STRINGIFY(SQLITE_CUSTOM_INCLUDE) #endif /* ** 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 /* ** Warning pragmas copied from msvc.h in the core. */ #if defined(_MSC_VER) #pragma warning(disable : 4054) #pragma warning(disable : 4055) #pragma warning(disable : 4100) |
︙ | ︙ | |||
125 126 127 128 129 130 131 | # define shell_stifle_history(X) # define SHELL_USE_LOCAL_GETLINE 1 #endif #if defined(_WIN32) || defined(WIN32) | > > > | | | | | | | | | > > > | | | | > | 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 | # define shell_stifle_history(X) # define SHELL_USE_LOCAL_GETLINE 1 #endif #if defined(_WIN32) || defined(WIN32) # if SQLITE_OS_WINRT # define SQLITE_OMIT_POPEN 1 # else # include <io.h> # include <fcntl.h> # define isatty(h) _isatty(h) # ifndef access # define access(f,m) _access((f),(m)) # endif # ifndef unlink # define unlink _unlink # endif # ifndef strdup # define strdup _strdup # endif # undef popen # define popen _popen # undef pclose # define pclose _pclose # endif #else /* Make sure isatty() has a prototype. */ extern int isatty(int); # if !defined(__RTP__) && !defined(_WRS_KERNEL) /* popen and pclose are not C89 functions and so are ** sometimes omitted from the <stdio.h> header */ |
︙ | ︙ | |||
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 | /* ctype macros that work with signed characters */ #define IsSpace(X) isspace((unsigned char)X) #define IsDigit(X) isdigit((unsigned char)X) #define ToLower(X) (char)tolower((unsigned char)X) #if defined(_WIN32) || defined(WIN32) #include <windows.h> /* string conversion routines only needed on Win32 */ extern char *sqlite3_win32_unicode_to_utf8(LPCWSTR); extern char *sqlite3_win32_mbcs_to_utf8_v2(const char *, int); extern char *sqlite3_win32_utf8_to_mbcs_v2(const char *, int); extern LPWSTR sqlite3_win32_utf8_to_unicode(const char *zText); #endif /* On Windows, we normally run with output mode of TEXT so that \n characters ** are automatically translated into \r\n. However, this behavior needs ** to be disabled in some cases (ex: when generating CSV output and when ** rendering quoted strings that contain \n characters). The following ** routines take care of that. */ | > > > | | 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 | /* ctype macros that work with signed characters */ #define IsSpace(X) isspace((unsigned char)X) #define IsDigit(X) isdigit((unsigned char)X) #define ToLower(X) (char)tolower((unsigned char)X) #if defined(_WIN32) || defined(WIN32) #if SQLITE_OS_WINRT #include <intrin.h> #endif #include <windows.h> /* string conversion routines only needed on Win32 */ extern char *sqlite3_win32_unicode_to_utf8(LPCWSTR); extern char *sqlite3_win32_mbcs_to_utf8_v2(const char *, int); extern char *sqlite3_win32_utf8_to_mbcs_v2(const char *, int); extern LPWSTR sqlite3_win32_utf8_to_unicode(const char *zText); #endif /* On Windows, we normally run with output mode of TEXT so that \n characters ** are automatically translated into \r\n. However, this behavior needs ** to be disabled in some cases (ex: when generating CSV output and when ** rendering quoted strings that contain \n characters). The following ** routines take care of that. */ #if (defined(_WIN32) || defined(WIN32)) && !SQLITE_OS_WINRT static void setBinaryMode(FILE *file, int isOutput){ if( isOutput ) fflush(file); _setmode(_fileno(file), _O_BINARY); } static void setTextMode(FILE *file, int isOutput){ if( isOutput ) fflush(file); _setmode(_fileno(file), _O_TEXT); |
︙ | ︙ | |||
204 205 206 207 208 209 210 211 212 213 214 215 216 217 | static int enableTimer = 0; /* Return the current wall-clock time */ static sqlite3_int64 timeOfDay(void){ static sqlite3_vfs *clockVfs = 0; sqlite3_int64 t; if( clockVfs==0 ) clockVfs = sqlite3_vfs_find(0); if( clockVfs->iVersion>=2 && clockVfs->xCurrentTimeInt64!=0 ){ clockVfs->xCurrentTimeInt64(clockVfs, &t); }else{ double r; clockVfs->xCurrentTime(clockVfs, &r); t = (sqlite3_int64)(r*86400000.0); } | > | 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 | static int enableTimer = 0; /* Return the current wall-clock time */ static sqlite3_int64 timeOfDay(void){ static sqlite3_vfs *clockVfs = 0; sqlite3_int64 t; if( clockVfs==0 ) clockVfs = sqlite3_vfs_find(0); if( clockVfs==0 ) return 0; /* Never actually happens */ if( clockVfs->iVersion>=2 && clockVfs->xCurrentTimeInt64!=0 ){ clockVfs->xCurrentTimeInt64(clockVfs, &t); }else{ double r; clockVfs->xCurrentTime(clockVfs, &r); t = (sqlite3_int64)(r*86400000.0); } |
︙ | ︙ | |||
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 | ** Check to see if we have timer support. Return 1 if necessary ** support found (or found previously). */ static int hasTimer(void){ if( getProcessTimesAddr ){ return 1; } else { /* GetProcessTimes() isn't supported in WIN95 and some other Windows ** versions. See if the version we are running on has it, and if it ** does, save off a pointer to it and the current process handle. */ hProcess = GetCurrentProcess(); if( hProcess ){ HINSTANCE hinstLib = LoadLibrary(TEXT("Kernel32.dll")); if( NULL != hinstLib ){ getProcessTimesAddr = (GETPROCTIMES) GetProcAddress(hinstLib, "GetProcessTimes"); if( NULL != getProcessTimesAddr ){ return 1; } FreeLibrary(hinstLib); } } } return 0; } /* ** Begin timing an operation */ | > > | 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 | ** Check to see if we have timer support. Return 1 if necessary ** support found (or found previously). */ static int hasTimer(void){ if( getProcessTimesAddr ){ return 1; } else { #if !SQLITE_OS_WINRT /* GetProcessTimes() isn't supported in WIN95 and some other Windows ** versions. See if the version we are running on has it, and if it ** does, save off a pointer to it and the current process handle. */ hProcess = GetCurrentProcess(); if( hProcess ){ HINSTANCE hinstLib = LoadLibrary(TEXT("Kernel32.dll")); if( NULL != hinstLib ){ getProcessTimesAddr = (GETPROCTIMES) GetProcAddress(hinstLib, "GetProcessTimes"); if( NULL != getProcessTimesAddr ){ return 1; } FreeLibrary(hinstLib); } } #endif } return 0; } /* ** Begin timing an operation */ |
︙ | ︙ | |||
390 391 392 393 394 395 396 397 398 399 400 401 402 403 | static sqlite3 *globalDb = 0; /* ** True if an interrupt (Control-C) has been received. */ static volatile int seenInterrupt = 0; /* ** This is the name of our program. It is set in main(), used ** in a number of other places, mostly for error messages. */ static char *Argv0; /* | > > > > > > > > > | 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 | static sqlite3 *globalDb = 0; /* ** True if an interrupt (Control-C) has been received. */ static volatile int seenInterrupt = 0; #ifdef SQLITE_DEBUG /* ** Out-of-memory simulator variables */ static unsigned int oomCounter = 0; /* Simulate OOM when equals 1 */ static unsigned int oomRepeat = 0; /* Number of OOMs in a row */ static void*(*defaultMalloc)(int) = 0; /* The low-level malloc routine */ #endif /* SQLITE_DEBUG */ /* ** This is the name of our program. It is set in main(), used ** in a number of other places, mostly for error messages. */ static char *Argv0; /* |
︙ | ︙ | |||
441 442 443 444 445 446 447 448 449 450 451 452 453 454 | /* Indicate out-of-memory and exit. */ static void shell_out_of_memory(void){ raw_printf(stderr,"Error: out of memory\n"); exit(1); } /* ** Write I/O traces to the following stream. */ #ifdef SQLITE_ENABLE_IOTRACE static FILE *iotrace = 0; #endif | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* Indicate out-of-memory and exit. */ static void shell_out_of_memory(void){ raw_printf(stderr,"Error: out of memory\n"); exit(1); } #ifdef SQLITE_DEBUG /* This routine is called when a simulated OOM occurs. It is broken ** out as a separate routine to make it easy to set a breakpoint on ** the OOM */ void shellOomFault(void){ if( oomRepeat>0 ){ oomRepeat--; }else{ oomCounter--; } } #endif /* SQLITE_DEBUG */ #ifdef SQLITE_DEBUG /* This routine is a replacement malloc() that is used to simulate ** Out-Of-Memory (OOM) errors for testing purposes. */ static void *oomMalloc(int nByte){ if( oomCounter ){ if( oomCounter==1 ){ shellOomFault(); return 0; }else{ oomCounter--; } } return defaultMalloc(nByte); } #endif /* SQLITE_DEBUG */ #ifdef SQLITE_DEBUG /* Register the OOM simulator. This must occur before any memory ** allocations */ static void registerOomSimulator(void){ sqlite3_mem_methods mem; sqlite3_config(SQLITE_CONFIG_GETMALLOC, &mem); defaultMalloc = mem.xMalloc; mem.xMalloc = oomMalloc; sqlite3_config(SQLITE_CONFIG_MALLOC, &mem); } #endif /* ** Write I/O traces to the following stream. */ #ifdef SQLITE_ENABLE_IOTRACE static FILE *iotrace = 0; #endif |
︙ | ︙ | |||
477 478 479 480 481 482 483 | ** in bytes. This is different from the %*.*s specification in printf ** since with %*.*s the width is measured in bytes, not characters. */ static void utf8_width_print(FILE *pOut, int w, const char *zUtf){ int i; int n; int aw = w<0 ? -w : w; | < < | 562 563 564 565 566 567 568 569 570 571 572 573 574 575 | ** in bytes. This is different from the %*.*s specification in printf ** since with %*.*s the width is measured in bytes, not characters. */ static void utf8_width_print(FILE *pOut, int w, const char *zUtf){ int i; int n; int aw = w<0 ? -w : w; for(i=n=0; zUtf[i]; i++){ if( (zUtf[i]&0xc0)!=0x80 ){ n++; if( n==aw ){ do{ i++; }while( (zUtf[i]&0xc0)==0x80 ); break; } |
︙ | ︙ | |||
546 547 548 549 550 551 552 553 554 555 556 557 558 559 | static int strlenChar(const char *z){ int n = 0; while( *z ){ if( (0xc0&*(z++))!=0x80 ) n++; } return n; } /* ** This routine reads a line of text from FILE in, stores ** the text in memory obtained from malloc() and returns a pointer ** to the text. NULL is returned at end of file, or if malloc() ** fails. ** | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | static int strlenChar(const char *z){ int n = 0; while( *z ){ if( (0xc0&*(z++))!=0x80 ) n++; } return n; } /* ** Return open FILE * if zFile exists, can be opened for read ** and is an ordinary file or a character stream source. ** Otherwise return 0. */ static FILE * openChrSource(const char *zFile){ #ifdef _WIN32 struct _stat x = {0}; # define STAT_CHR_SRC(mode) ((mode & (_S_IFCHR|_S_IFIFO|_S_IFREG))!=0) /* On Windows, open first, then check the stream nature. This order ** is necessary because _stat() and sibs, when checking a named pipe, ** effectively break the pipe as its supplier sees it. */ FILE *rv = fopen(zFile, "rb"); if( rv==0 ) return 0; if( _fstat(_fileno(rv), &x) != 0 || !STAT_CHR_SRC(x.st_mode)){ fclose(rv); rv = 0; } return rv; #else struct stat x = {0}; int rc = stat(zFile, &x); # define STAT_CHR_SRC(mode) (S_ISREG(mode)||S_ISFIFO(mode)||S_ISCHR(mode)) if( rc!=0 ) return 0; if( STAT_CHR_SRC(x.st_mode) ){ return fopen(zFile, "rb"); }else{ return 0; } #endif #undef STAT_CHR_SRC } /* ** This routine reads a line of text from FILE in, stores ** the text in memory obtained from malloc() and returns a pointer ** to the text. NULL is returned at end of file, or if malloc() ** fails. ** |
︙ | ︙ | |||
735 736 737 738 739 740 741 | if( quote ){ len += 2; for(i=0; i<nAppend; i++){ if( zAppend[i]==quote ) len++; } } | | | 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 | if( quote ){ len += 2; for(i=0; i<nAppend; i++){ if( zAppend[i]==quote ) len++; } } if( p->z==0 || p->n+len>=p->nAlloc ){ p->nAlloc = p->nAlloc*2 + len + 20; p->z = realloc(p->z, p->nAlloc); if( p->z==0 ) shell_out_of_memory(); } if( quote ){ char *zCsr = p->z+p->n; |
︙ | ︙ | |||
859 860 861 862 863 864 865 | ** CREATE INDEX ** CREATE UNIQUE INDEX ** CREATE VIEW ** CREATE TRIGGER ** CREATE VIRTUAL TABLE ** ** This UDF is used by the .schema command to insert the schema name of | | | 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 | ** CREATE INDEX ** CREATE UNIQUE INDEX ** CREATE VIEW ** CREATE TRIGGER ** CREATE VIRTUAL TABLE ** ** This UDF is used by the .schema command to insert the schema name of ** attached databases into the middle of the sqlite_schema.sql field. */ static void shellAddSchemaName( sqlite3_context *pCtx, int nVal, sqlite3_value **apVal ){ static const char *aPrefix[] = { |
︙ | ︙ | |||
881 882 883 884 885 886 887 | int i = 0; const char *zIn = (const char*)sqlite3_value_text(apVal[0]); const char *zSchema = (const char*)sqlite3_value_text(apVal[1]); const char *zName = (const char*)sqlite3_value_text(apVal[2]); sqlite3 *db = sqlite3_context_db_handle(pCtx); UNUSED_PARAMETER(nVal); if( zIn!=0 && strncmp(zIn, "CREATE ", 7)==0 ){ | | | 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 | int i = 0; const char *zIn = (const char*)sqlite3_value_text(apVal[0]); const char *zSchema = (const char*)sqlite3_value_text(apVal[1]); const char *zName = (const char*)sqlite3_value_text(apVal[2]); sqlite3 *db = sqlite3_context_db_handle(pCtx); UNUSED_PARAMETER(nVal); if( zIn!=0 && strncmp(zIn, "CREATE ", 7)==0 ){ for(i=0; i<ArraySize(aPrefix); i++){ int n = strlen30(aPrefix[i]); if( strncmp(zIn+7, aPrefix[i], n)==0 && zIn[n+7]==' ' ){ char *z = 0; char *zFake = 0; if( zSchema ){ char cQuote = quoteChar(zSchema); if( cQuote && sqlite3_stricmp(zSchema,"temp")!=0 ){ |
︙ | ︙ | |||
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 | INCLUDE test_windirent.c #define dirent DIRENT #endif INCLUDE ../ext/misc/shathree.c INCLUDE ../ext/misc/fileio.c INCLUDE ../ext/misc/completion.c INCLUDE ../ext/misc/appendvfs.c #ifdef SQLITE_HAVE_ZLIB INCLUDE ../ext/misc/zipfile.c INCLUDE ../ext/misc/sqlar.c #endif INCLUDE ../ext/expert/sqlite3expert.h INCLUDE ../ext/expert/sqlite3expert.c #if defined(SQLITE_ENABLE_SESSION) /* ** State information for a single open session */ typedef struct OpenSession OpenSession; struct OpenSession { char *zName; /* Symbolic name for this session */ int nFilter; /* Number of xFilter rejection GLOB patterns */ char **azFilter; /* Array of xFilter rejection GLOB patterns */ sqlite3_session *p; /* The open session */ }; #endif | > > > > > > > > > > < < < < < < < < < < < < | 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 | INCLUDE test_windirent.c #define dirent DIRENT #endif INCLUDE ../ext/misc/shathree.c INCLUDE ../ext/misc/fileio.c INCLUDE ../ext/misc/completion.c INCLUDE ../ext/misc/appendvfs.c INCLUDE ../ext/misc/memtrace.c INCLUDE ../ext/misc/uint.c INCLUDE ../ext/misc/decimal.c INCLUDE ../ext/misc/ieee754.c INCLUDE ../ext/misc/series.c INCLUDE ../ext/misc/regexp.c #ifdef SQLITE_HAVE_ZLIB INCLUDE ../ext/misc/zipfile.c INCLUDE ../ext/misc/sqlar.c #endif INCLUDE ../ext/expert/sqlite3expert.h INCLUDE ../ext/expert/sqlite3expert.c #if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB) INCLUDE ../ext/misc/dbdata.c #endif #if defined(SQLITE_ENABLE_SESSION) /* ** State information for a single open session */ typedef struct OpenSession OpenSession; struct OpenSession { char *zName; /* Symbolic name for this session */ int nFilter; /* Number of xFilter rejection GLOB patterns */ char **azFilter; /* Array of xFilter rejection GLOB patterns */ sqlite3_session *p; /* The open session */ }; #endif typedef struct ExpertInfo ExpertInfo; struct ExpertInfo { sqlite3expert *pExpert; int bVerbose; }; /* A single line in the EQP output */ |
︙ | ︙ | |||
998 999 1000 1001 1002 1003 1004 | */ typedef struct ShellState ShellState; struct ShellState { sqlite3 *db; /* The database */ u8 autoExplain; /* Automatically turn on .explain mode */ u8 autoEQP; /* Run EXPLAIN QUERY PLAN prior to seach SQL stmt */ u8 autoEQPtest; /* autoEQP is in test mode */ | | > > > > > > > > > | | > < < < > > > > > > > > > > > < < < < | | 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 | */ typedef struct ShellState ShellState; struct ShellState { sqlite3 *db; /* The database */ u8 autoExplain; /* Automatically turn on .explain mode */ u8 autoEQP; /* Run EXPLAIN QUERY PLAN prior to seach SQL stmt */ u8 autoEQPtest; /* autoEQP is in test mode */ u8 autoEQPtrace; /* autoEQP is in trace mode */ u8 scanstatsOn; /* True to display scan stats before each finalize */ u8 openMode; /* SHELL_OPEN_NORMAL, _APPENDVFS, or _ZIPFILE */ u8 doXdgOpen; /* Invoke start/open/xdg-open in output_reset() */ u8 nEqpLevel; /* Depth of the EQP output graph */ u8 eTraceType; /* SHELL_TRACE_* value for type of trace */ u8 bSafeMode; /* True to prohibit unsafe operations */ u8 bSafeModePersist; /* The long-term value of bSafeMode */ unsigned statsOn; /* True to display memory stats before each finalize */ unsigned mEqpLines; /* Mask of veritical lines in the EQP output graph */ int outCount; /* Revert to stdout when reaching zero */ int cnt; /* Number of records displayed so far */ int lineno; /* Line number of last line read from in */ int openFlags; /* Additional flags to open. (SQLITE_OPEN_NOFOLLOW) */ FILE *in; /* Read commands from this stream */ FILE *out; /* Write results here */ FILE *traceOut; /* Output for sqlite3_trace() */ int nErr; /* Number of errors seen */ int mode; /* An output mode setting */ int modePrior; /* Saved mode */ int cMode; /* temporary output mode for the current query */ int normalMode; /* Output mode before ".explain on" */ int writableSchema; /* True if PRAGMA writable_schema=ON */ int showHeader; /* True to show column names in List or Column mode */ int nCheck; /* Number of ".check" commands run */ unsigned nProgress; /* Number of progress callbacks encountered */ unsigned mxProgress; /* Maximum progress callbacks before failing */ unsigned flgProgress; /* Flags for the progress callback */ unsigned shellFlgs; /* Various flags */ unsigned priorShFlgs; /* Saved copy of flags */ sqlite3_int64 szMax; /* --maxsize argument to .open */ char *zDestTable; /* Name of destination table when MODE_Insert */ char *zTempFile; /* Temporary file that might need deleting */ char zTestcase[30]; /* Name of current test case */ char colSeparator[20]; /* Column separator character for several modes */ char rowSeparator[20]; /* Row separator character for MODE_Ascii */ char colSepPrior[20]; /* Saved column separator */ char rowSepPrior[20]; /* Saved row separator */ int *colWidth; /* Requested width of each column in columnar modes */ int *actualWidth; /* Actual width of each column */ int nWidth; /* Number of slots in colWidth[] and actualWidth[] */ char nullValue[20]; /* The text to print when a NULL comes back from ** the database */ char outfile[FILENAME_MAX]; /* Filename for *out */ sqlite3_stmt *pStmt; /* Current statement if any. */ FILE *pLog; /* Write log output here */ struct AuxDb { /* Storage space for auxiliary database connections */ sqlite3 *db; /* Connection pointer */ const char *zDbFilename; /* Filename used to open the connection */ char *zFreeOnClose; /* Free this memory allocation on close */ #if defined(SQLITE_ENABLE_SESSION) int nSession; /* Number of active sessions */ OpenSession aSession[4]; /* Array of sessions. [0] is in focus. */ #endif } aAuxDb[5], /* Array of all database connections */ *pAuxDb; /* Currently active database connection */ int *aiIndent; /* Array of indents used in MODE_Explain */ int nIndent; /* Size of array aiIndent[] */ int iIndent; /* Index of current op in aiIndent[] */ char *zNonce; /* Nonce for temporary safe-mode excapes */ EQPGraph sGraph; /* Information for the graphical EXPLAIN QUERY PLAN */ ExpertInfo expert; /* Valid if previous command was ".expert OPT..." */ }; /* Allowed values for ShellState.autoEQP */ #define AUTOEQP_off 0 /* Automatic EXPLAIN QUERY PLAN is off */ #define AUTOEQP_on 1 /* Automatic EQP is on */ |
︙ | ︙ | |||
1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 | /* Allowed values for ShellState.eTraceType */ #define SHELL_TRACE_PLAIN 0 /* Show input SQL text */ #define SHELL_TRACE_EXPANDED 1 /* Show expanded SQL text */ #define SHELL_TRACE_NORMALIZED 2 /* Show normalized SQL text */ /* ** These are the allowed shellFlgs values */ #define SHFLG_Pagecache 0x00000001 /* The --pagecache option is used */ #define SHFLG_Lookaside 0x00000002 /* Lookaside memory is used */ #define SHFLG_Backslash 0x00000004 /* The --backslash option is used */ #define SHFLG_PreserveRowid 0x00000008 /* .dump preserves rowid values */ #define SHFLG_Newlines 0x00000010 /* .dump --newline flag */ #define SHFLG_CountChanges 0x00000020 /* .changes setting */ #define SHFLG_Echo 0x00000040 /* .echo or --echo setting */ /* ** Macros for testing and setting shellFlgs */ #define ShellHasFlag(P,X) (((P)->shellFlgs & (X))!=0) #define ShellSetFlag(P,X) ((P)->shellFlgs|=(X)) #define ShellClearFlag(P,X) ((P)->shellFlgs&=(~(X))) | > > > > > > > > > > | 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 | /* Allowed values for ShellState.eTraceType */ #define SHELL_TRACE_PLAIN 0 /* Show input SQL text */ #define SHELL_TRACE_EXPANDED 1 /* Show expanded SQL text */ #define SHELL_TRACE_NORMALIZED 2 /* Show normalized SQL text */ /* Bits in the ShellState.flgProgress variable */ #define SHELL_PROGRESS_QUIET 0x01 /* Omit announcing every progress callback */ #define SHELL_PROGRESS_RESET 0x02 /* Reset the count when the progres ** callback limit is reached, and for each ** top-level SQL statement */ #define SHELL_PROGRESS_ONCE 0x04 /* Cancel the --limit after firing once */ /* ** These are the allowed shellFlgs values */ #define SHFLG_Pagecache 0x00000001 /* The --pagecache option is used */ #define SHFLG_Lookaside 0x00000002 /* Lookaside memory is used */ #define SHFLG_Backslash 0x00000004 /* The --backslash option is used */ #define SHFLG_PreserveRowid 0x00000008 /* .dump preserves rowid values */ #define SHFLG_Newlines 0x00000010 /* .dump --newline flag */ #define SHFLG_CountChanges 0x00000020 /* .changes setting */ #define SHFLG_Echo 0x00000040 /* .echo or --echo setting */ #define SHFLG_HeaderSet 0x00000080 /* showHeader has been specified */ #define SHFLG_DumpDataOnly 0x00000100 /* .dump show data only */ #define SHFLG_DumpNoSys 0x00000200 /* .dump omits system tables */ /* ** Macros for testing and setting shellFlgs */ #define ShellHasFlag(P,X) (((P)->shellFlgs & (X))!=0) #define ShellSetFlag(P,X) ((P)->shellFlgs|=(X)) #define ShellClearFlag(P,X) ((P)->shellFlgs&=(~(X))) |
︙ | ︙ | |||
1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 | #define MODE_Quote 6 /* Quote values as for SQL */ #define MODE_Tcl 7 /* Generate ANSI-C or TCL quoted elements */ #define MODE_Csv 8 /* Quote strings, numbers are plain */ #define MODE_Explain 9 /* Like MODE_Column, but do not truncate data */ #define MODE_Ascii 10 /* Use ASCII unit and record separators (0x1F/0x1E) */ #define MODE_Pretty 11 /* Pretty-print schemas */ #define MODE_EQP 12 /* Converts EXPLAIN QUERY PLAN output into a graph */ static const char *modeDescr[] = { "line", "column", "list", "semi", "html", "insert", "quote", "tcl", "csv", "explain", "ascii", "prettyprint", | > > > > | > > > > | 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 | #define MODE_Quote 6 /* Quote values as for SQL */ #define MODE_Tcl 7 /* Generate ANSI-C or TCL quoted elements */ #define MODE_Csv 8 /* Quote strings, numbers are plain */ #define MODE_Explain 9 /* Like MODE_Column, but do not truncate data */ #define MODE_Ascii 10 /* Use ASCII unit and record separators (0x1F/0x1E) */ #define MODE_Pretty 11 /* Pretty-print schemas */ #define MODE_EQP 12 /* Converts EXPLAIN QUERY PLAN output into a graph */ #define MODE_Json 13 /* Output JSON */ #define MODE_Markdown 14 /* Markdown formatting */ #define MODE_Table 15 /* MySQL-style table formatting */ #define MODE_Box 16 /* Unicode box-drawing characters */ static const char *modeDescr[] = { "line", "column", "list", "semi", "html", "insert", "quote", "tcl", "csv", "explain", "ascii", "prettyprint", "eqp", "json", "markdown", "table", "box" }; /* ** These are the column/row/line separators used by the various ** import/export modes. */ #define SEP_Column "|" |
︙ | ︙ | |||
1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 | sqlite3_value **apVal ){ ShellState *p = (ShellState*)sqlite3_user_data(pCtx); (void)nVal; utf8_printf(p->out, "%s\n", sqlite3_value_text(apVal[0])); sqlite3_result_value(pCtx, apVal[0]); } /* ** SQL function: edit(VALUE) ** edit(VALUE,EDITOR) ** ** These steps: ** | > > > > > > > > > > > > > > > > > > > > > | 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 | sqlite3_value **apVal ){ ShellState *p = (ShellState*)sqlite3_user_data(pCtx); (void)nVal; utf8_printf(p->out, "%s\n", sqlite3_value_text(apVal[0])); sqlite3_result_value(pCtx, apVal[0]); } /* ** If in safe mode, print an error message described by the arguments ** and exit immediately. */ static void failIfSafeMode( ShellState *p, const char *zErrMsg, ... ){ if( p->bSafeMode ){ va_list ap; char *zMsg; va_start(ap, zErrMsg); zMsg = sqlite3_vmprintf(zErrMsg, ap); va_end(ap); raw_printf(stderr, "line %d: ", p->lineno); utf8_printf(stderr, "%s\n", zMsg); exit(1); } } /* ** SQL function: edit(VALUE) ** edit(VALUE,EDITOR) ** ** These steps: ** |
︙ | ︙ | |||
1232 1233 1234 1235 1236 1237 1238 | f = fopen(zTempFile, bBin ? "wb" : "w"); if( f==0 ){ sqlite3_result_error(context, "edit() cannot open temp file", -1); goto edit_func_end; } sz = sqlite3_value_bytes(argv[0]); if( bBin ){ | | | | 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 | f = fopen(zTempFile, bBin ? "wb" : "w"); if( f==0 ){ sqlite3_result_error(context, "edit() cannot open temp file", -1); goto edit_func_end; } sz = sqlite3_value_bytes(argv[0]); if( bBin ){ x = fwrite(sqlite3_value_blob(argv[0]), 1, (size_t)sz, f); }else{ const char *z = (const char*)sqlite3_value_text(argv[0]); /* Remember whether or not the value originally contained \r\n */ if( z && strstr(z,"\r\n")!=0 ) hasCRNL = 1; x = fwrite(sqlite3_value_text(argv[0]), 1, (size_t)sz, f); } fclose(f); f = 0; if( x!=sz ){ sqlite3_result_error(context, "edit() could not write the whole file", -1); goto edit_func_end; } |
︙ | ︙ | |||
1265 1266 1267 1268 1269 1270 1271 | sqlite3_result_error(context, "edit() cannot reopen temp file after edit", -1); goto edit_func_end; } fseek(f, 0, SEEK_END); sz = ftell(f); rewind(f); | | | < | 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 | sqlite3_result_error(context, "edit() cannot reopen temp file after edit", -1); goto edit_func_end; } fseek(f, 0, SEEK_END); sz = ftell(f); rewind(f); p = sqlite3_malloc64( sz+1 ); if( p==0 ){ sqlite3_result_error_nomem(context); goto edit_func_end; } x = fread(p, 1, (size_t)sz, f); fclose(f); f = 0; if( x!=sz ){ sqlite3_result_error(context, "could not read back the whole file", -1); goto edit_func_end; } if( bBin ){ sqlite3_result_blob64(context, p, sz, sqlite3_free); }else{ sqlite3_int64 i, j; if( hasCRNL ){ /* If the original contains \r\n then do no conversions back to \n */ }else{ /* If the file did not originally contain \r\n then convert any new ** \r\n back into \n */ for(i=j=0; i<sz; i++){ if( p[i]=='\r' && p[i+1]=='\n' ) i++; p[j++] = p[i]; } |
︙ | ︙ | |||
1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 | #endif /* SQLITE_NOHAVE_SYSTEM */ /* ** Save or restore the current output mode */ static void outputModePush(ShellState *p){ p->modePrior = p->mode; memcpy(p->colSepPrior, p->colSeparator, sizeof(p->colSeparator)); memcpy(p->rowSepPrior, p->rowSeparator, sizeof(p->rowSeparator)); } static void outputModePop(ShellState *p){ p->mode = p->modePrior; memcpy(p->colSeparator, p->colSepPrior, sizeof(p->colSeparator)); memcpy(p->rowSeparator, p->rowSepPrior, sizeof(p->rowSeparator)); } /* ** Output the given string as a hex-encoded blob (eg. X'1234' ) */ | > > | 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 | #endif /* SQLITE_NOHAVE_SYSTEM */ /* ** Save or restore the current output mode */ static void outputModePush(ShellState *p){ p->modePrior = p->mode; p->priorShFlgs = p->shellFlgs; memcpy(p->colSepPrior, p->colSeparator, sizeof(p->colSeparator)); memcpy(p->rowSepPrior, p->rowSeparator, sizeof(p->rowSeparator)); } static void outputModePop(ShellState *p){ p->mode = p->modePrior; p->shellFlgs = p->priorShFlgs; memcpy(p->colSeparator, p->colSepPrior, sizeof(p->colSeparator)); memcpy(p->rowSeparator, p->rowSepPrior, sizeof(p->rowSeparator)); } /* ** Output the given string as a hex-encoded blob (eg. X'1234' ) */ |
︙ | ︙ | |||
1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 | raw_printf(out, "\\%03o", c&0xff); }else{ fputc(c, out); } } fputc('"', out); } /* ** Output the given string with characters that are special to ** HTML escaped. */ static void output_html_string(FILE *out, const char *z){ int i; | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1654 1655 1656 1657 1658 1659 1660 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 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 | raw_printf(out, "\\%03o", c&0xff); }else{ fputc(c, out); } } fputc('"', out); } /* ** Output the given string as a quoted according to JSON quoting rules. */ static void output_json_string(FILE *out, const char *z, int n){ unsigned int c; if( n<0 ) n = (int)strlen(z); fputc('"', out); while( n-- ){ c = *(z++); if( c=='\\' || c=='"' ){ fputc('\\', out); fputc(c, out); }else if( c<=0x1f ){ fputc('\\', out); if( c=='\b' ){ fputc('b', out); }else if( c=='\f' ){ fputc('f', out); }else if( c=='\n' ){ fputc('n', out); }else if( c=='\r' ){ fputc('r', out); }else if( c=='\t' ){ fputc('t', out); }else{ raw_printf(out, "u%04x",c); } }else{ fputc(c, out); } } fputc('"', out); } /* ** Output the given string with characters that are special to ** HTML escaped. */ static void output_html_string(FILE *out, const char *z){ int i; |
︙ | ︙ | |||
1555 1556 1557 1558 1559 1560 1561 | ** is only issued if bSep is true. */ static void output_csv(ShellState *p, const char *z, int bSep){ FILE *out = p->out; if( z==0 ){ utf8_printf(out,"%s",p->nullValue); }else{ | | < | < < | | 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 | ** is only issued if bSep is true. */ static void output_csv(ShellState *p, const char *z, int bSep){ FILE *out = p->out; if( z==0 ){ utf8_printf(out,"%s",p->nullValue); }else{ unsigned i; for(i=0; z[i]; i++){ if( needCsvQuote[((unsigned char*)z)[i]] ){ i = 0; break; } } if( i==0 || strstr(z, p->colSeparator)!=0 ){ char *zQuoted = sqlite3_mprintf("\"%w\"", z); utf8_printf(out, "%s", zQuoted); sqlite3_free(zQuoted); }else{ utf8_printf(out, "%s", z); } } |
︙ | ︙ | |||
1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 | return TRUE; } return FALSE; } #endif #ifndef SQLITE_OMIT_AUTHORIZATION /* ** When the ".auth ON" is set, the following authorizer callback is ** invoked. It always returns SQLITE_OK. */ static int shellAuth( void *pClientData, int op, | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 | return TRUE; } return FALSE; } #endif #ifndef SQLITE_OMIT_AUTHORIZATION /* ** This authorizer runs in safe mode. */ static int safeModeAuth( void *pClientData, int op, const char *zA1, const char *zA2, const char *zA3, const char *zA4 ){ ShellState *p = (ShellState*)pClientData; static const char *azProhibitedFunctions[] = { "edit", "fts3_tokenizer", "load_extension", "readfile", "writefile", "zipfile", "zipfile_cds", }; UNUSED_PARAMETER(zA2); UNUSED_PARAMETER(zA3); UNUSED_PARAMETER(zA4); switch( op ){ case SQLITE_ATTACH: { failIfSafeMode(p, "cannot run ATTACH in safe mode"); break; } case SQLITE_FUNCTION: { int i; for(i=0; i<ArraySize(azProhibitedFunctions); i++){ if( sqlite3_stricmp(zA1, azProhibitedFunctions[i])==0 ){ failIfSafeMode(p, "cannot use the %s() function in safe mode", azProhibitedFunctions[i]); } } break; } } return SQLITE_OK; } /* ** When the ".auth ON" is set, the following authorizer callback is ** invoked. It always returns SQLITE_OK. */ static int shellAuth( void *pClientData, int op, |
︙ | ︙ | |||
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 | if( az[i] ){ output_c_string(p->out, az[i]); }else{ raw_printf(p->out, "NULL"); } } raw_printf(p->out, "\n"); return SQLITE_OK; } #endif /* ** Print a schema statement. Part of MODE_Semi and MODE_Pretty output. ** ** This routine converts some CREATE TABLE statements for shadow tables ** in FTS3/4/5 into CREATE TABLE IF NOT EXISTS statements. */ static void printSchemaLine(FILE *out, const char *z, const char *zTail){ if( sqlite3_strglob("CREATE TABLE ['\"]*", z)==0 ){ utf8_printf(out, "CREATE TABLE IF NOT EXISTS %s%s", z+13, zTail); }else{ utf8_printf(out, "%s%s", z, zTail); } } static void printSchemaLineN(FILE *out, char *z, int n, const char *zTail){ | > > > | 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 | if( az[i] ){ output_c_string(p->out, az[i]); }else{ raw_printf(p->out, "NULL"); } } raw_printf(p->out, "\n"); if( p->bSafeMode ) (void)safeModeAuth(pClientData, op, zA1, zA2, zA3, zA4); return SQLITE_OK; } #endif /* ** Print a schema statement. Part of MODE_Semi and MODE_Pretty output. ** ** This routine converts some CREATE TABLE statements for shadow tables ** in FTS3/4/5 into CREATE TABLE IF NOT EXISTS statements. */ static void printSchemaLine(FILE *out, const char *z, const char *zTail){ if( z==0 ) return; if( zTail==0 ) return; if( sqlite3_strglob("CREATE TABLE ['\"]*", z)==0 ){ utf8_printf(out, "CREATE TABLE IF NOT EXISTS %s%s", z+13, zTail); }else{ utf8_printf(out, "%s%s", z, zTail); } } static void printSchemaLineN(FILE *out, char *z, int n, const char *zTail){ |
︙ | ︙ | |||
1740 1741 1742 1743 1744 1745 1746 | static void eqp_render_level(ShellState *p, int iEqpId){ EQPGraphRow *pRow, *pNext; int n = strlen30(p->sGraph.zPrefix); char *z; for(pRow = eqp_next_row(p, iEqpId, 0); pRow; pRow = pNext){ pNext = eqp_next_row(p, iEqpId, pRow); z = pRow->zText; | | > | 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 | static void eqp_render_level(ShellState *p, int iEqpId){ EQPGraphRow *pRow, *pNext; int n = strlen30(p->sGraph.zPrefix); char *z; for(pRow = eqp_next_row(p, iEqpId, 0); pRow; pRow = pNext){ pNext = eqp_next_row(p, iEqpId, pRow); z = pRow->zText; utf8_printf(p->out, "%s%s%s\n", p->sGraph.zPrefix, pNext ? "|--" : "`--", z); if( n<(int)sizeof(p->sGraph.zPrefix)-7 ){ memcpy(&p->sGraph.zPrefix[n], pNext ? "| " : " ", 4); eqp_render_level(p, pRow->iEqpId); p->sGraph.zPrefix[n] = 0; } } } |
︙ | ︙ | |||
1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 | utf8_printf(p->out, "QUERY PLAN\n"); } p->sGraph.zPrefix[0] = 0; eqp_render_level(p, 0); eqp_reset(p); } } /* ** This is the callback routine that the shell ** invokes for each row of a query result. */ static int shell_callback( void *pArg, int nArg, /* Number of result columns */ char **azArg, /* Text of each result column */ char **azCol, /* Column names */ | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | < | | < < < < < < < | < < < < | < < < < < < < < < < < < < | | | < < | < < | < < < < | < < | < < < | < | < | | | 2018 2019 2020 2021 2022 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 2142 2143 2144 2145 2146 2147 2148 | utf8_printf(p->out, "QUERY PLAN\n"); } p->sGraph.zPrefix[0] = 0; eqp_render_level(p, 0); eqp_reset(p); } } #ifndef SQLITE_OMIT_PROGRESS_CALLBACK /* ** Progress handler callback. */ static int progress_handler(void *pClientData) { ShellState *p = (ShellState*)pClientData; p->nProgress++; if( p->nProgress>=p->mxProgress && p->mxProgress>0 ){ raw_printf(p->out, "Progress limit reached (%u)\n", p->nProgress); if( p->flgProgress & SHELL_PROGRESS_RESET ) p->nProgress = 0; if( p->flgProgress & SHELL_PROGRESS_ONCE ) p->mxProgress = 0; return 1; } if( (p->flgProgress & SHELL_PROGRESS_QUIET)==0 ){ raw_printf(p->out, "Progress %u\n", p->nProgress); } return 0; } #endif /* SQLITE_OMIT_PROGRESS_CALLBACK */ /* ** Print N dashes */ static void print_dashes(FILE *out, int N){ const char zDash[] = "--------------------------------------------------"; const int nDash = sizeof(zDash) - 1; while( N>nDash ){ fputs(zDash, out); N -= nDash; } raw_printf(out, "%.*s", N, zDash); } /* ** Print a markdown or table-style row separator using ascii-art */ static void print_row_separator( ShellState *p, int nArg, const char *zSep ){ int i; if( nArg>0 ){ fputs(zSep, p->out); print_dashes(p->out, p->actualWidth[0]+2); for(i=1; i<nArg; i++){ fputs(zSep, p->out); print_dashes(p->out, p->actualWidth[i]+2); } fputs(zSep, p->out); } fputs("\n", p->out); } /* ** This is the callback routine that the shell ** invokes for each row of a query result. */ static int shell_callback( void *pArg, int nArg, /* Number of result columns */ char **azArg, /* Text of each result column */ char **azCol, /* Column names */ int *aiType /* Column types. Might be NULL */ ){ int i; ShellState *p = (ShellState*)pArg; if( azArg==0 ) return 0; switch( p->cMode ){ case MODE_Line: { int w = 5; if( azArg==0 ) break; for(i=0; i<nArg; i++){ int len = strlen30(azCol[i] ? azCol[i] : ""); if( len>w ) w = len; } if( p->cnt++>0 ) utf8_printf(p->out, "%s", p->rowSeparator); for(i=0; i<nArg; i++){ utf8_printf(p->out,"%*s = %s%s", w, azCol[i], azArg[i] ? azArg[i] : p->nullValue, p->rowSeparator); } break; } case MODE_Explain: { static const int aExplainWidth[] = {4, 13, 4, 4, 4, 13, 2, 13}; if( nArg>ArraySize(aExplainWidth) ){ nArg = ArraySize(aExplainWidth); } if( p->cnt++==0 ){ for(i=0; i<nArg; i++){ int w = aExplainWidth[i]; utf8_width_print(p->out, w, azCol[i]); fputs(i==nArg-1 ? "\n" : " ", p->out); } for(i=0; i<nArg; i++){ int w = aExplainWidth[i]; print_dashes(p->out, w); fputs(i==nArg-1 ? "\n" : " ", p->out); } } if( azArg==0 ) break; for(i=0; i<nArg; i++){ int w = aExplainWidth[i]; if( i==nArg-1 ) w = 0; if( azArg[i] && strlenChar(azArg[i])>w ){ w = strlenChar(azArg[i]); } if( i==1 && p->aiIndent && p->pStmt ){ if( p->iIndent<p->nIndent ){ utf8_printf(p->out, "%*.s", p->aiIndent[p->iIndent], ""); } p->iIndent++; } utf8_width_print(p->out, w, azArg[i] ? azArg[i] : p->nullValue); fputs(i==nArg-1 ? "\n" : " ", p->out); } break; } case MODE_Semi: { /* .schema and .fullschema output */ printSchemaLine(p->out, azArg[0], ";\n"); break; } |
︙ | ︙ | |||
1911 1912 1913 1914 1915 1916 1917 | j--; } z[j++] = c; } while( j>0 && IsSpace(z[j-1]) ){ j--; } z[j] = 0; if( strlen30(z)>=79 ){ | | | 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 | j--; } z[j++] = c; } while( j>0 && IsSpace(z[j-1]) ){ j--; } z[j] = 0; if( strlen30(z)>=79 ){ for(i=j=0; (c = z[i])!=0; i++){ /* Copy from z[i] back to z[j] */ if( c==cEnd ){ cEnd = 0; }else if( c=='"' || c=='\'' || c=='`' ){ cEnd = c; }else if( c=='[' ){ cEnd = ']'; }else if( c=='-' && z[i+1]=='-' ){ |
︙ | ︙ | |||
2076 2077 2078 2079 2080 2081 2082 2083 | output_quoted_string(p->out, azArg[i]); }else{ output_quoted_escaped_string(p->out, azArg[i]); } } raw_printf(p->out,");\n"); break; } | | | > > > > > | > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 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 | output_quoted_string(p->out, azArg[i]); }else{ output_quoted_escaped_string(p->out, azArg[i]); } } raw_printf(p->out,");\n"); break; } case MODE_Json: { if( azArg==0 ) break; if( p->cnt==0 ){ fputs("[{", p->out); }else{ fputs(",\n{", p->out); } p->cnt++; for(i=0; i<nArg; i++){ output_json_string(p->out, azCol[i], -1); putc(':', p->out); if( (azArg[i]==0) || (aiType && aiType[i]==SQLITE_NULL) ){ fputs("null",p->out); }else if( aiType && aiType[i]==SQLITE_FLOAT ){ char z[50]; double r = sqlite3_column_double(p->pStmt, i); sqlite3_uint64 ur; memcpy(&ur,&r,sizeof(r)); if( ur==0x7ff0000000000000LL ){ raw_printf(p->out, "1e999"); }else if( ur==0xfff0000000000000LL ){ raw_printf(p->out, "-1e999"); }else{ sqlite3_snprintf(50,z,"%!.20g", r); raw_printf(p->out, "%s", z); } }else if( aiType && aiType[i]==SQLITE_BLOB && p->pStmt ){ const void *pBlob = sqlite3_column_blob(p->pStmt, i); int nBlob = sqlite3_column_bytes(p->pStmt, i); output_json_string(p->out, pBlob, nBlob); }else if( aiType && aiType[i]==SQLITE_TEXT ){ output_json_string(p->out, azArg[i], -1); }else{ utf8_printf(p->out,"%s", azArg[i]); } if( i<nArg-1 ){ putc(',', p->out); } } putc('}', p->out); break; } case MODE_Quote: { if( azArg==0 ) break; if( p->cnt==0 && p->showHeader ){ for(i=0; i<nArg; i++){ if( i>0 ) fputs(p->colSeparator, p->out); output_quoted_string(p->out, azCol[i]); } fputs(p->rowSeparator, p->out); } p->cnt++; for(i=0; i<nArg; i++){ if( i>0 ) fputs(p->colSeparator, p->out); if( (azArg[i]==0) || (aiType && aiType[i]==SQLITE_NULL) ){ utf8_printf(p->out,"NULL"); }else if( aiType && aiType[i]==SQLITE_TEXT ){ output_quoted_string(p->out, azArg[i]); }else if( aiType && aiType[i]==SQLITE_INTEGER ){ utf8_printf(p->out,"%s", azArg[i]); }else if( aiType && aiType[i]==SQLITE_FLOAT ){ |
︙ | ︙ | |||
2110 2111 2112 2113 2114 2115 2116 | output_hex_blob(p->out, pBlob, nBlob); }else if( isNumber(azArg[i], 0) ){ utf8_printf(p->out,"%s", azArg[i]); }else{ output_quoted_string(p->out, azArg[i]); } } | | | 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 | output_hex_blob(p->out, pBlob, nBlob); }else if( isNumber(azArg[i], 0) ){ utf8_printf(p->out,"%s", azArg[i]); }else{ output_quoted_string(p->out, azArg[i]); } } fputs(p->rowSeparator, p->out); break; } case MODE_Ascii: { if( p->cnt++==0 && p->showHeader ){ for(i=0; i<nArg; i++){ if( i>0 ) utf8_printf(p->out, "%s", p->colSeparator); utf8_printf(p->out,"%s",azCol[i] ? azCol[i] : ""); |
︙ | ︙ | |||
2183 2184 2185 2186 2187 2188 2189 | "CREATE TEMP TABLE [_shell$self](op,cmd,ans);\n" "INSERT INTO [_shell$self](rowid,op,cmd)\n" " VALUES(coalesce((SELECT (max(tno)+100)/10 FROM selftest),10),\n" " 'memo','Tests generated by --init');\n" "INSERT INTO [_shell$self]\n" " SELECT 'run',\n" " 'SELECT hex(sha3_query(''SELECT type,name,tbl_name,sql " | | | | | 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 | "CREATE TEMP TABLE [_shell$self](op,cmd,ans);\n" "INSERT INTO [_shell$self](rowid,op,cmd)\n" " VALUES(coalesce((SELECT (max(tno)+100)/10 FROM selftest),10),\n" " 'memo','Tests generated by --init');\n" "INSERT INTO [_shell$self]\n" " SELECT 'run',\n" " 'SELECT hex(sha3_query(''SELECT type,name,tbl_name,sql " "FROM sqlite_schema ORDER BY 2'',224))',\n" " hex(sha3_query('SELECT type,name,tbl_name,sql " "FROM sqlite_schema ORDER BY 2',224));\n" "INSERT INTO [_shell$self]\n" " SELECT 'run'," " 'SELECT hex(sha3_query(''SELECT * FROM \"' ||" " printf('%w',name) || '\" NOT INDEXED'',224))',\n" " hex(sha3_query(printf('SELECT * FROM \"%w\" NOT INDEXED',name),224))\n" " FROM (\n" " SELECT name FROM sqlite_schema\n" " WHERE type='table'\n" " AND name<>'selftest'\n" " AND coalesce(rootpage,0)>0\n" " )\n" " ORDER BY name;\n" "INSERT INTO [_shell$self]\n" " VALUES('run','PRAGMA integrity_check','ok');\n" |
︙ | ︙ | |||
2255 2256 2257 2258 2259 2260 2261 | ** If the number of columns is 1 and that column contains text "--" ** then write the semicolon on a separate line. That way, if a ** "--" comment occurs at the end of the statement, the comment ** won't consume the semicolon terminator. */ static int run_table_dump_query( ShellState *p, /* Query context */ | | < < < < < | 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 | ** If the number of columns is 1 and that column contains text "--" ** then write the semicolon on a separate line. That way, if a ** "--" comment occurs at the end of the statement, the comment ** won't consume the semicolon terminator. */ static int run_table_dump_query( ShellState *p, /* Query context */ const char *zSelect /* SELECT statement to extract content */ ){ sqlite3_stmt *pSelect; int rc; int nResult; int i; const char *z; rc = sqlite3_prepare_v2(p->db, zSelect, -1, &pSelect, 0); if( rc!=SQLITE_OK || !pSelect ){ utf8_printf(p->out, "/**** ERROR: (%d) %s *****/\n", rc, sqlite3_errmsg(p->db)); if( (rc&0xff)!=SQLITE_CORRUPT ) p->nErr++; return rc; } rc = sqlite3_step(pSelect); nResult = sqlite3_column_count(pSelect); while( rc==SQLITE_ROW ){ z = (const char*)sqlite3_column_text(pSelect, 0); utf8_printf(p->out, "%s", z); for(i=1; i<nResult; i++){ utf8_printf(p->out, ",%s", sqlite3_column_text(pSelect, i)); } if( z==0 ) z = ""; while( z[0] && (z[0]!='-' || z[1]!='-') ) z++; |
︙ | ︙ | |||
2301 2302 2303 2304 2305 2306 2307 | sqlite3_errmsg(p->db)); if( (rc&0xff)!=SQLITE_CORRUPT ) p->nErr++; } return rc; } /* | | | > > < < | > | < < | 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 | sqlite3_errmsg(p->db)); if( (rc&0xff)!=SQLITE_CORRUPT ) p->nErr++; } return rc; } /* ** Allocate space and save off string indicating current error. */ static char *save_err_msg( sqlite3 *db, /* Database to query */ const char *zWhen, /* Qualifier (format) wrapper */ int rc /* Error code returned from API */ ){ if( zWhen==0 ) zWhen = "%s (%d)"; return sqlite3_mprintf(zWhen, sqlite3_errmsg(db), rc); } #ifdef __linux__ /* ** Attempt to display I/O stats on Linux using /proc/PID/io */ static void displayLinuxIoStats(FILE *out){ |
︙ | ︙ | |||
2390 2391 2392 2393 2394 2395 2396 | ){ int iCur; int iHiwtr; FILE *out; if( pArg==0 || pArg->out==0 ) return 0; out = pArg->out; | | | 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 | ){ int iCur; int iHiwtr; FILE *out; if( pArg==0 || pArg->out==0 ) return 0; out = pArg->out; if( pArg->pStmt && pArg->statsOn==2 ){ int nCol, i, x; sqlite3_stmt *pStmt = pArg->pStmt; char z[100]; nCol = sqlite3_column_count(pStmt); raw_printf(out, "%-36s %d\n", "Number of output columns:", nCol); for(i=0; i<nCol; i++){ sqlite3_snprintf(sizeof(z),z,"Column %d %nname:", i, &x); |
︙ | ︙ | |||
2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 | sqlite3_snprintf(30, z+x, "table name:"); utf8_printf(out, "%-36s %s\n", z, sqlite3_column_table_name(pStmt,i)); sqlite3_snprintf(30, z+x, "origin name:"); utf8_printf(out, "%-36s %s\n", z, sqlite3_column_origin_name(pStmt,i)); #endif } } displayStatLine(pArg, "Memory Used:", "%lld (max %lld) bytes", SQLITE_STATUS_MEMORY_USED, bReset); displayStatLine(pArg, "Number of Outstanding Allocations:", "%lld (max %lld)", SQLITE_STATUS_MALLOC_COUNT, bReset); if( pArg->shellFlgs & SHFLG_Pagecache ){ displayStatLine(pArg, "Number of Pcache Pages Used:", | > > > > > > > > | 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 | sqlite3_snprintf(30, z+x, "table name:"); utf8_printf(out, "%-36s %s\n", z, sqlite3_column_table_name(pStmt,i)); sqlite3_snprintf(30, z+x, "origin name:"); utf8_printf(out, "%-36s %s\n", z, sqlite3_column_origin_name(pStmt,i)); #endif } } if( pArg->statsOn==3 ){ if( pArg->pStmt ){ iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_VM_STEP, bReset); raw_printf(pArg->out, "VM-steps: %d\n", iCur); } return 0; } displayStatLine(pArg, "Memory Used:", "%lld (max %lld) bytes", SQLITE_STATUS_MEMORY_USED, bReset); displayStatLine(pArg, "Number of Outstanding Allocations:", "%lld (max %lld)", SQLITE_STATUS_MALLOC_COUNT, bReset); if( pArg->shellFlgs & SHFLG_Pagecache ){ displayStatLine(pArg, "Number of Pcache Pages Used:", |
︙ | ︙ | |||
2490 2491 2492 2493 2494 2495 2496 | raw_printf(pArg->out, "Fullscan Steps: %d\n", iCur); iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_SORT, bReset); raw_printf(pArg->out, "Sort Operations: %d\n", iCur); iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_AUTOINDEX,bReset); raw_printf(pArg->out, "Autoindex Inserts: %d\n", iCur); iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_VM_STEP, bReset); raw_printf(pArg->out, "Virtual Machine Steps: %d\n", iCur); | | | 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 | raw_printf(pArg->out, "Fullscan Steps: %d\n", iCur); iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_SORT, bReset); raw_printf(pArg->out, "Sort Operations: %d\n", iCur); iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_AUTOINDEX,bReset); raw_printf(pArg->out, "Autoindex Inserts: %d\n", iCur); iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_VM_STEP, bReset); raw_printf(pArg->out, "Virtual Machine Steps: %d\n", iCur); iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_REPREPARE,bReset); raw_printf(pArg->out, "Reprepare operations: %d\n", iCur); iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_RUN, bReset); raw_printf(pArg->out, "Number of times run: %d\n", iCur); iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_MEMUSED, bReset); raw_printf(pArg->out, "Memory used by prepared stmt: %d\n", iCur); } |
︙ | ︙ | |||
2680 2681 2682 2683 2684 2685 2686 | p->nIndent = 0; p->iIndent = 0; } /* ** Disable and restore .wheretrace and .selecttrace settings. */ | < < | < < < | < < > | | < < | | < > > > | > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > | | 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 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 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 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 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 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 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 3333 | p->nIndent = 0; p->iIndent = 0; } /* ** Disable and restore .wheretrace and .selecttrace settings. */ static unsigned int savedSelectTrace; static unsigned int savedWhereTrace; static void disable_debug_trace_modes(void){ unsigned int zero = 0; sqlite3_test_control(SQLITE_TESTCTRL_TRACEFLAGS, 0, &savedSelectTrace); sqlite3_test_control(SQLITE_TESTCTRL_TRACEFLAGS, 1, &zero); sqlite3_test_control(SQLITE_TESTCTRL_TRACEFLAGS, 2, &savedWhereTrace); sqlite3_test_control(SQLITE_TESTCTRL_TRACEFLAGS, 3, &zero); } static void restore_debug_trace_modes(void){ sqlite3_test_control(SQLITE_TESTCTRL_TRACEFLAGS, 1, &savedSelectTrace); sqlite3_test_control(SQLITE_TESTCTRL_TRACEFLAGS, 3, &savedWhereTrace); } /* Create the TEMP table used to store parameter bindings */ static void bind_table_init(ShellState *p){ int wrSchema = 0; int defensiveMode = 0; sqlite3_db_config(p->db, SQLITE_DBCONFIG_DEFENSIVE, -1, &defensiveMode); sqlite3_db_config(p->db, SQLITE_DBCONFIG_DEFENSIVE, 0, 0); sqlite3_db_config(p->db, SQLITE_DBCONFIG_WRITABLE_SCHEMA, -1, &wrSchema); sqlite3_db_config(p->db, SQLITE_DBCONFIG_WRITABLE_SCHEMA, 1, 0); sqlite3_exec(p->db, "CREATE TABLE IF NOT EXISTS temp.sqlite_parameters(\n" " key TEXT PRIMARY KEY,\n" " value\n" ") WITHOUT ROWID;", 0, 0, 0); sqlite3_db_config(p->db, SQLITE_DBCONFIG_WRITABLE_SCHEMA, wrSchema, 0); sqlite3_db_config(p->db, SQLITE_DBCONFIG_DEFENSIVE, defensiveMode, 0); } /* ** Bind parameters on a prepared statement. ** ** Parameter bindings are taken from a TEMP table of the form: ** ** CREATE TEMP TABLE sqlite_parameters(key TEXT PRIMARY KEY, value) ** WITHOUT ROWID; ** ** No bindings occur if this table does not exist. The name of the table ** begins with "sqlite_" so that it will not collide with ordinary application ** tables. The table must be in the TEMP schema. */ static void bind_prepared_stmt(ShellState *pArg, sqlite3_stmt *pStmt){ int nVar; int i; int rc; sqlite3_stmt *pQ = 0; nVar = sqlite3_bind_parameter_count(pStmt); if( nVar==0 ) return; /* Nothing to do */ if( sqlite3_table_column_metadata(pArg->db, "TEMP", "sqlite_parameters", "key", 0, 0, 0, 0, 0)!=SQLITE_OK ){ return; /* Parameter table does not exist */ } rc = sqlite3_prepare_v2(pArg->db, "SELECT value FROM temp.sqlite_parameters" " WHERE key=?1", -1, &pQ, 0); if( rc || pQ==0 ) return; for(i=1; i<=nVar; i++){ char zNum[30]; const char *zVar = sqlite3_bind_parameter_name(pStmt, i); if( zVar==0 ){ sqlite3_snprintf(sizeof(zNum),zNum,"?%d",i); zVar = zNum; } sqlite3_bind_text(pQ, 1, zVar, -1, SQLITE_STATIC); if( sqlite3_step(pQ)==SQLITE_ROW ){ sqlite3_bind_value(pStmt, i, sqlite3_column_value(pQ, 0)); }else{ sqlite3_bind_null(pStmt, i); } sqlite3_reset(pQ); } sqlite3_finalize(pQ); } /* ** UTF8 box-drawing characters. Imagine box lines like this: ** ** 1 ** | ** 4 --+-- 2 ** | ** 3 ** ** Each box characters has between 2 and 4 of the lines leading from ** the center. The characters are here identified by the numbers of ** their corresponding lines. */ #define BOX_24 "\342\224\200" /* U+2500 --- */ #define BOX_13 "\342\224\202" /* U+2502 | */ #define BOX_23 "\342\224\214" /* U+250c ,- */ #define BOX_34 "\342\224\220" /* U+2510 -, */ #define BOX_12 "\342\224\224" /* U+2514 '- */ #define BOX_14 "\342\224\230" /* U+2518 -' */ #define BOX_123 "\342\224\234" /* U+251c |- */ #define BOX_134 "\342\224\244" /* U+2524 -| */ #define BOX_234 "\342\224\254" /* U+252c -,- */ #define BOX_124 "\342\224\264" /* U+2534 -'- */ #define BOX_1234 "\342\224\274" /* U+253c -|- */ /* Draw horizontal line N characters long using unicode box ** characters */ static void print_box_line(FILE *out, int N){ const char zDash[] = BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24; const int nDash = sizeof(zDash) - 1; N *= 3; while( N>nDash ){ utf8_printf(out, zDash); N -= nDash; } utf8_printf(out, "%.*s", N, zDash); } /* ** Draw a horizontal separator for a MODE_Box table. */ static void print_box_row_separator( ShellState *p, int nArg, const char *zSep1, const char *zSep2, const char *zSep3 ){ int i; if( nArg>0 ){ utf8_printf(p->out, "%s", zSep1); print_box_line(p->out, p->actualWidth[0]+2); for(i=1; i<nArg; i++){ utf8_printf(p->out, "%s", zSep2); print_box_line(p->out, p->actualWidth[i]+2); } utf8_printf(p->out, "%s", zSep3); } fputs("\n", p->out); } /* ** Run a prepared statement and output the result in one of the ** table-oriented formats: MODE_Column, MODE_Markdown, MODE_Table, ** or MODE_Box. ** ** This is different from ordinary exec_prepared_stmt() in that ** it has to run the entire query and gather the results into memory ** first, in order to determine column widths, before providing ** any output. */ static void exec_prepared_stmt_columnar( ShellState *p, /* Pointer to ShellState */ sqlite3_stmt *pStmt /* Statment to run */ ){ sqlite3_int64 nRow = 0; int nColumn = 0; char **azData = 0; sqlite3_int64 nAlloc = 0; const char *z; int rc; sqlite3_int64 i, nData; int j, nTotal, w, n; const char *colSep = 0; const char *rowSep = 0; rc = sqlite3_step(pStmt); if( rc!=SQLITE_ROW ) return; nColumn = sqlite3_column_count(pStmt); nAlloc = nColumn*4; if( nAlloc<=0 ) nAlloc = 1; azData = sqlite3_malloc64( nAlloc*sizeof(char*) ); if( azData==0 ) shell_out_of_memory(); for(i=0; i<nColumn; i++){ azData[i] = strdup(sqlite3_column_name(pStmt,i)); } do{ if( (nRow+2)*nColumn >= nAlloc ){ nAlloc *= 2; azData = sqlite3_realloc64(azData, nAlloc*sizeof(char*)); if( azData==0 ) shell_out_of_memory(); } nRow++; for(i=0; i<nColumn; i++){ z = (const char*)sqlite3_column_text(pStmt,i); azData[nRow*nColumn + i] = z ? strdup(z) : 0; } }while( sqlite3_step(pStmt)==SQLITE_ROW ); if( nColumn>p->nWidth ){ p->colWidth = realloc(p->colWidth, (nColumn+1)*2*sizeof(int)); if( p->colWidth==0 ) shell_out_of_memory(); for(i=p->nWidth; i<nColumn; i++) p->colWidth[i] = 0; p->nWidth = nColumn; p->actualWidth = &p->colWidth[nColumn]; } memset(p->actualWidth, 0, nColumn*sizeof(int)); for(i=0; i<nColumn; i++){ w = p->colWidth[i]; if( w<0 ) w = -w; p->actualWidth[i] = w; } nTotal = nColumn*(nRow+1); for(i=0; i<nTotal; i++){ z = azData[i]; if( z==0 ) z = p->nullValue; n = strlenChar(z); j = i%nColumn; if( n>p->actualWidth[j] ) p->actualWidth[j] = n; } if( seenInterrupt ) goto columnar_end; if( nColumn==0 ) goto columnar_end; switch( p->cMode ){ case MODE_Column: { colSep = " "; rowSep = "\n"; if( p->showHeader ){ for(i=0; i<nColumn; i++){ w = p->actualWidth[i]; if( p->colWidth[i]<0 ) w = -w; utf8_width_print(p->out, w, azData[i]); fputs(i==nColumn-1?"\n":" ", p->out); } for(i=0; i<nColumn; i++){ print_dashes(p->out, p->actualWidth[i]); fputs(i==nColumn-1?"\n":" ", p->out); } } break; } case MODE_Table: { colSep = " | "; rowSep = " |\n"; print_row_separator(p, nColumn, "+"); fputs("| ", p->out); for(i=0; i<nColumn; i++){ w = p->actualWidth[i]; n = strlenChar(azData[i]); utf8_printf(p->out, "%*s%s%*s", (w-n)/2, "", azData[i], (w-n+1)/2, ""); fputs(i==nColumn-1?" |\n":" | ", p->out); } print_row_separator(p, nColumn, "+"); break; } case MODE_Markdown: { colSep = " | "; rowSep = " |\n"; fputs("| ", p->out); for(i=0; i<nColumn; i++){ w = p->actualWidth[i]; n = strlenChar(azData[i]); utf8_printf(p->out, "%*s%s%*s", (w-n)/2, "", azData[i], (w-n+1)/2, ""); fputs(i==nColumn-1?" |\n":" | ", p->out); } print_row_separator(p, nColumn, "|"); break; } case MODE_Box: { colSep = " " BOX_13 " "; rowSep = " " BOX_13 "\n"; print_box_row_separator(p, nColumn, BOX_23, BOX_234, BOX_34); utf8_printf(p->out, BOX_13 " "); for(i=0; i<nColumn; i++){ w = p->actualWidth[i]; n = strlenChar(azData[i]); utf8_printf(p->out, "%*s%s%*s%s", (w-n)/2, "", azData[i], (w-n+1)/2, "", i==nColumn-1?" "BOX_13"\n":" "BOX_13" "); } print_box_row_separator(p, nColumn, BOX_123, BOX_1234, BOX_134); break; } } for(i=nColumn, j=0; i<nTotal; i++, j++){ if( j==0 && p->cMode!=MODE_Column ){ utf8_printf(p->out, "%s", p->cMode==MODE_Box?BOX_13" ":"| "); } z = azData[i]; if( z==0 ) z = p->nullValue; w = p->actualWidth[j]; if( p->colWidth[j]<0 ) w = -w; utf8_width_print(p->out, w, z); if( j==nColumn-1 ){ utf8_printf(p->out, "%s", rowSep); j = -1; if( seenInterrupt ) goto columnar_end; }else{ utf8_printf(p->out, "%s", colSep); } } if( p->cMode==MODE_Table ){ print_row_separator(p, nColumn, "+"); }else if( p->cMode==MODE_Box ){ print_box_row_separator(p, nColumn, BOX_12, BOX_124, BOX_14); } columnar_end: if( seenInterrupt ){ utf8_printf(p->out, "Interrupt\n"); } nData = (nRow+1)*nColumn; for(i=0; i<nData; i++) free(azData[i]); sqlite3_free(azData); } /* ** Run a prepared statement */ static void exec_prepared_stmt( ShellState *pArg, /* Pointer to ShellState */ sqlite3_stmt *pStmt /* Statment to run */ ){ int rc; if( pArg->cMode==MODE_Column || pArg->cMode==MODE_Table || pArg->cMode==MODE_Box || pArg->cMode==MODE_Markdown ){ exec_prepared_stmt_columnar(pArg, pStmt); return; } /* perform the first step. this will tell us if we ** have a result set or not and how wide it is. */ rc = sqlite3_step(pStmt); /* if we have a result set... */ if( SQLITE_ROW == rc ){ /* allocate space for col name ptr, value ptr, and type */ int nCol = sqlite3_column_count(pStmt); void *pData = sqlite3_malloc64(3*nCol*sizeof(const char*) + 1); if( !pData ){ shell_out_of_memory(); }else{ char **azCols = (char **)pData; /* Names of result columns */ char **azVals = &azCols[nCol]; /* Results */ int *aiTypes = (int *)&azVals[nCol]; /* Result types */ int i, x; assert(sizeof(int) <= sizeof(char *)); /* save off ptrs to column names */ |
︙ | ︙ | |||
2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 | rc = SQLITE_ABORT; }else{ rc = sqlite3_step(pStmt); } } } while( SQLITE_ROW == rc ); sqlite3_free(pData); } } } #ifndef SQLITE_OMIT_VIRTUALTABLE /* ** This function is called to process SQL if the previous shell command | > > > | 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 3368 3369 3370 3371 3372 | rc = SQLITE_ABORT; }else{ rc = sqlite3_step(pStmt); } } } while( SQLITE_ROW == rc ); sqlite3_free(pData); if( pArg->cMode==MODE_Json ){ fputs("]\n", pArg->out); } } } } #ifndef SQLITE_OMIT_VIRTUALTABLE /* ** This function is called to process SQL if the previous shell command |
︙ | ︙ | |||
2934 2935 2936 2937 2938 2939 2940 | #endif while( zSql[0] && (SQLITE_OK == rc) ){ static const char *zStmtSql; rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zLeftover); if( SQLITE_OK != rc ){ if( pzErrMsg ){ | | | 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 | #endif while( zSql[0] && (SQLITE_OK == rc) ){ static const char *zStmtSql; rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zLeftover); if( SQLITE_OK != rc ){ if( pzErrMsg ){ *pzErrMsg = save_err_msg(db, "in prepare, %s (%d)", rc); } }else{ if( !pStmt ){ /* this happens for a comment or white-space */ zSql = zLeftover; while( IsSpace(zSql[0]) ) zSql++; continue; |
︙ | ︙ | |||
2959 2960 2961 2962 2963 2964 2965 | /* echo the sql statement if echo on */ if( pArg && ShellHasFlag(pArg, SHFLG_Echo) ){ utf8_printf(pArg->out, "%s\n", zStmtSql ? zStmtSql : zSql); } /* Show the EXPLAIN QUERY PLAN if .eqp is on */ | | > | 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 | /* echo the sql statement if echo on */ if( pArg && ShellHasFlag(pArg, SHFLG_Echo) ){ utf8_printf(pArg->out, "%s\n", zStmtSql ? zStmtSql : zSql); } /* Show the EXPLAIN QUERY PLAN if .eqp is on */ if( pArg && pArg->autoEQP && sqlite3_stmt_isexplain(pStmt)==0 ){ sqlite3_stmt *pExplain; char *zEQP; int triggerEQP = 0; disable_debug_trace_modes(); sqlite3_db_config(db, SQLITE_DBCONFIG_TRIGGER_EQP, -1, &triggerEQP); if( pArg->autoEQP>=AUTOEQP_trigger ){ sqlite3_db_config(db, SQLITE_DBCONFIG_TRIGGER_EQP, 1, 0); } zEQP = sqlite3_mprintf("EXPLAIN QUERY PLAN %s", zStmtSql); rc = sqlite3_prepare_v2(db, zEQP, -1, &pExplain, 0); if( rc==SQLITE_OK ){ while( sqlite3_step(pExplain)==SQLITE_ROW ){ const char *zEQPLine = (const char*)sqlite3_column_text(pExplain,3); int iEqpId = sqlite3_column_int(pExplain, 0); int iParentId = sqlite3_column_int(pExplain, 1); if( zEQPLine==0 ) zEQPLine = ""; if( zEQPLine[0]=='-' ) eqp_render(pArg); eqp_append(pArg, iEqpId, iParentId, zEQPLine); } eqp_render(pArg); } sqlite3_finalize(pExplain); sqlite3_free(zEQP); |
︙ | ︙ | |||
3008 3009 3010 3011 3012 3013 3014 | } restore_debug_trace_modes(); } if( pArg ){ pArg->cMode = pArg->mode; if( pArg->autoExplain ){ | | < < | < > | 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 | } restore_debug_trace_modes(); } if( pArg ){ pArg->cMode = pArg->mode; if( pArg->autoExplain ){ if( sqlite3_stmt_isexplain(pStmt)==1 ){ pArg->cMode = MODE_Explain; } if( sqlite3_stmt_isexplain(pStmt)==2 ){ pArg->cMode = MODE_EQP; } } /* If the shell is currently in ".explain" mode, gather the extra ** data required to add indents to the output.*/ if( pArg->cMode==MODE_Explain ){ explain_data_prepare(pArg, pStmt); } } bind_prepared_stmt(pArg, pStmt); exec_prepared_stmt(pArg, pStmt); explain_data_delete(pArg); eqp_render(pArg); /* print usage stats if stats on */ if( pArg && pArg->statsOn ){ display_stats(db, pArg, 0); |
︙ | ︙ | |||
3049 3050 3051 3052 3053 3054 3055 | ** next statement to execute. */ rc2 = sqlite3_finalize(pStmt); if( rc!=SQLITE_NOMEM ) rc = rc2; if( rc==SQLITE_OK ){ zSql = zLeftover; while( IsSpace(zSql[0]) ) zSql++; }else if( pzErrMsg ){ | | | 3644 3645 3646 3647 3648 3649 3650 3651 3652 3653 3654 3655 3656 3657 3658 | ** next statement to execute. */ rc2 = sqlite3_finalize(pStmt); if( rc!=SQLITE_NOMEM ) rc = rc2; if( rc==SQLITE_OK ){ zSql = zLeftover; while( IsSpace(zSql[0]) ) zSql++; }else if( pzErrMsg ){ *pzErrMsg = save_err_msg(db, "stepping, %s (%d)", rc); } /* clear saved stmt handle */ if( pArg ){ pArg->pStmt = NULL; } } |
︙ | ︙ | |||
3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 | */ static int dump_callback(void *pArg, int nArg, char **azArg, char **azNotUsed){ int rc; const char *zTable; const char *zType; const char *zSql; ShellState *p = (ShellState *)pArg; UNUSED_PARAMETER(azNotUsed); if( nArg!=3 || azArg==0 ) return 0; zTable = azArg[0]; zType = azArg[1]; zSql = azArg[2]; | > > > > | | | | > > | | 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 | */ static int dump_callback(void *pArg, int nArg, char **azArg, char **azNotUsed){ int rc; const char *zTable; const char *zType; const char *zSql; ShellState *p = (ShellState *)pArg; int dataOnly; int noSys; UNUSED_PARAMETER(azNotUsed); if( nArg!=3 || azArg==0 ) return 0; zTable = azArg[0]; zType = azArg[1]; zSql = azArg[2]; dataOnly = (p->shellFlgs & SHFLG_DumpDataOnly)!=0; noSys = (p->shellFlgs & SHFLG_DumpNoSys)!=0; if( strcmp(zTable, "sqlite_sequence")==0 && !noSys ){ if( !dataOnly ) raw_printf(p->out, "DELETE FROM sqlite_sequence;\n"); }else if( sqlite3_strglob("sqlite_stat?", zTable)==0 && !noSys ){ if( !dataOnly ) raw_printf(p->out, "ANALYZE sqlite_schema;\n"); }else if( strncmp(zTable, "sqlite_", 7)==0 ){ return 0; }else if( dataOnly ){ /* no-op */ }else if( strncmp(zSql, "CREATE VIRTUAL TABLE", 20)==0 ){ char *zIns; if( !p->writableSchema ){ raw_printf(p->out, "PRAGMA writable_schema=ON;\n"); p->writableSchema = 1; } zIns = sqlite3_mprintf( "INSERT INTO sqlite_schema(type,name,tbl_name,rootpage,sql)" "VALUES('table','%q','%q',0,'%q');", zTable, zTable, zSql); utf8_printf(p->out, "%s\n", zIns); sqlite3_free(zIns); return 0; }else{ printSchemaLine(p->out, zSql, ";\n"); |
︙ | ︙ | |||
3355 3356 3357 3358 3359 3360 3361 | ** start of the description of what that command does. */ static const char *(azHelp[]) = { #if defined(SQLITE_HAVE_ZLIB) && !defined(SQLITE_OMIT_VIRTUALTABLE) ".archive ... Manage SQL archives", " Each command must have exactly one of the following options:", " -c, --create Create a new archive", | | > > | | | > | | | | | > | | > > | > | > > > > > > | > | < < | > > > > > > > > > > > > > > > | > | | | | > | | > | > | | > | | | | > > > | | | > > | > > > > > > > > > > > > > > > > > > > > > > > > > > | | > | 3956 3957 3958 3959 3960 3961 3962 3963 3964 3965 3966 3967 3968 3969 3970 3971 3972 3973 3974 3975 3976 3977 3978 3979 3980 3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994 3995 3996 3997 3998 3999 4000 4001 4002 4003 4004 4005 4006 4007 4008 4009 4010 4011 4012 4013 4014 4015 4016 4017 4018 4019 4020 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 4034 4035 4036 4037 4038 4039 4040 4041 4042 4043 4044 4045 4046 4047 4048 4049 4050 4051 4052 4053 4054 4055 4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075 4076 4077 4078 4079 4080 4081 4082 4083 4084 4085 4086 4087 4088 4089 4090 4091 4092 4093 4094 4095 4096 4097 4098 4099 4100 4101 4102 4103 4104 4105 4106 4107 4108 4109 4110 4111 4112 4113 4114 4115 4116 4117 4118 4119 4120 4121 4122 4123 4124 4125 4126 4127 4128 4129 4130 4131 4132 4133 4134 4135 4136 4137 4138 | ** start of the description of what that command does. */ static const char *(azHelp[]) = { #if defined(SQLITE_HAVE_ZLIB) && !defined(SQLITE_OMIT_VIRTUALTABLE) ".archive ... Manage SQL archives", " Each command must have exactly one of the following options:", " -c, --create Create a new archive", " -u, --update Add or update files with changed mtime", " -i, --insert Like -u but always add even if unchanged", " -r, --remove Remove files from archive", " -t, --list List contents of archive", " -x, --extract Extract files from archive", " Optional arguments:", " -v, --verbose Print each filename as it is processed", " -f FILE, --file FILE Use archive FILE (default is current db)", " -a FILE, --append FILE Open FILE using the apndvfs VFS", " -C DIR, --directory DIR Read/extract files from directory DIR", " -g, --glob Use glob matching for names in archive", " -n, --dryrun Show the SQL that would have occurred", " Examples:", " .ar -cf ARCHIVE foo bar # Create ARCHIVE from files foo and bar", " .ar -tf ARCHIVE # List members of ARCHIVE", " .ar -xvf ARCHIVE # Verbosely extract files from ARCHIVE", " See also:", " http://sqlite.org/cli.html#sqlite_archive_support", #endif #ifndef SQLITE_OMIT_AUTHORIZATION ".auth ON|OFF Show authorizer callbacks", #endif ".backup ?DB? FILE Backup DB (default \"main\") to FILE", " --append Use the appendvfs", " --async Write to FILE without journal and fsync()", ".bail on|off Stop after hitting an error. Default OFF", ".binary on|off Turn binary output on or off. Default OFF", ".cd DIRECTORY Change the working directory to DIRECTORY", ".changes on|off Show number of rows changed by SQL", ".check GLOB Fail if output since .testcase does not match", ".clone NEWDB Clone data into NEWDB from the existing database", ".connection [close] [#] Open or close an auxiliary database connection", ".databases List names and files of attached databases", ".dbconfig ?op? ?val? List or change sqlite3_db_config() options", ".dbinfo ?DB? Show status information about the database", ".dump ?OBJECTS? Render database content as SQL", " Options:", " --data-only Output only INSERT statements", " --newlines Allow unescaped newline characters in output", " --nosys Omit system tables (ex: \"sqlite_stat1\")", " --preserve-rowids Include ROWID values in the output", " OBJECTS is a LIKE pattern for tables, indexes, triggers or views to dump", " Additional LIKE patterns can be given in subsequent arguments", ".echo on|off Turn command echo on or off", ".eqp on|off|full|... Enable or disable automatic EXPLAIN QUERY PLAN", " Other Modes:", #ifdef SQLITE_DEBUG " test Show raw EXPLAIN QUERY PLAN output", " trace Like \"full\" but enable \"PRAGMA vdbe_trace\"", #endif " trigger Like \"full\" but also show trigger bytecode", ".excel Display the output of next command in spreadsheet", " --bom Put a UTF8 byte-order mark on intermediate file", ".exit ?CODE? Exit this program with return-code CODE", ".expert EXPERIMENTAL. Suggest indexes for queries", ".explain ?on|off|auto? Change the EXPLAIN formatting mode. Default: auto", ".filectrl CMD ... Run various sqlite3_file_control() operations", " --schema SCHEMA Use SCHEMA instead of \"main\"", " --help Show CMD details", ".fullschema ?--indent? Show schema and the content of sqlite_stat tables", ".headers on|off Turn display of headers on or off", ".help ?-all? ?PATTERN? Show help text for PATTERN", ".import FILE TABLE Import data from FILE into TABLE", " Options:", " --ascii Use \\037 and \\036 as column and row separators", " --csv Use , and \\n as column and row separators", " --skip N Skip the first N rows of input", " -v \"Verbose\" - increase auxiliary output", " Notes:", " * If TABLE does not exist, it is created. The first row of input", " determines the column names.", " * If neither --csv or --ascii are used, the input mode is derived", " from the \".mode\" output mode", " * If FILE begins with \"|\" then it is a command that generates the", " input text.", #ifndef SQLITE_OMIT_TEST_CONTROL ".imposter INDEX TABLE Create imposter table TABLE on index INDEX", #endif ".indexes ?TABLE? Show names of indexes", " If TABLE is specified, only show indexes for", " tables matching TABLE using the LIKE operator.", #ifdef SQLITE_ENABLE_IOTRACE ".iotrace FILE Enable I/O diagnostic logging to FILE", #endif ".limit ?LIMIT? ?VAL? Display or change the value of an SQLITE_LIMIT", ".lint OPTIONS Report potential schema issues.", " Options:", " fkey-indexes Find missing foreign key indexes", #ifndef SQLITE_OMIT_LOAD_EXTENSION ".load FILE ?ENTRY? Load an extension library", #endif ".log FILE|off Turn logging on or off. FILE can be stderr/stdout", ".mode MODE ?TABLE? Set output mode", " MODE is one of:", " ascii Columns/rows delimited by 0x1F and 0x1E", " box Tables using unicode box-drawing characters", " csv Comma-separated values", " column Output in columns. (See .width)", " html HTML <table> code", " insert SQL insert statements for TABLE", " json Results in a JSON array", " line One value per line", " list Values delimited by \"|\"", " markdown Markdown table format", " quote Escape answers as for SQL", " table ASCII-art table", " tabs Tab-separated values", " tcl TCL list elements", ".nonce STRING Disable safe mode for one command if the nonce matches", ".nullvalue STRING Use STRING in place of NULL values", ".once ?OPTIONS? ?FILE? Output for the next SQL command only to FILE", " If FILE begins with '|' then open as a pipe", " --bom Put a UTF8 byte-order mark at the beginning", " -e Send output to the system text editor", " -x Send output as CSV to a spreadsheet (same as \".excel\")", #ifdef SQLITE_DEBUG ".oom ?--repeat M? ?N? Simulate an OOM error on the N-th allocation", #endif ".open ?OPTIONS? ?FILE? Close existing database and reopen FILE", " Options:", " --append Use appendvfs to append database to the end of FILE", #ifndef SQLITE_OMIT_DESERIALIZE " --deserialize Load into memory using sqlite3_deserialize()", " --hexdb Load the output of \"dbtotxt\" as an in-memory db", " --maxsize N Maximum size for --hexdb or --deserialized database", #endif " --new Initialize FILE to an empty database", " --nofollow Do not follow symbolic links", " --readonly Open FILE readonly", " --zip FILE is a ZIP archive", ".output ?FILE? Send output to FILE or stdout if FILE is omitted", " If FILE begins with '|' then open it as a pipe.", " Options:", " --bom Prefix output with a UTF8 byte-order mark", " -e Send output to the system text editor", " -x Send output as CSV to a spreadsheet", ".parameter CMD ... Manage SQL parameter bindings", " clear Erase all bindings", " init Initialize the TEMP table that holds bindings", " list List the current parameter bindings", " set PARAMETER VALUE Given SQL parameter PARAMETER a value of VALUE", " PARAMETER should start with one of: $ : @ ?", " unset PARAMETER Remove PARAMETER from the binding table", ".print STRING... Print literal STRING", #ifndef SQLITE_OMIT_PROGRESS_CALLBACK ".progress N Invoke progress handler after every N opcodes", " --limit N Interrupt after N progress callbacks", " --once Do no more than one progress interrupt", " --quiet|-q No output except at interrupts", " --reset Reset the count for each input and interrupt", #endif ".prompt MAIN CONTINUE Replace the standard prompts", ".quit Exit this program", ".read FILE Read input from FILE", #if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB) ".recover Recover as much data as possible from corrupt db.", " --freelist-corrupt Assume the freelist is corrupt", " --recovery-db NAME Store recovery metadata in database file NAME", " --lost-and-found TABLE Alternative name for the lost-and-found table", " --no-rowids Do not attempt to recover rowid values", " that are not also INTEGER PRIMARY KEYs", #endif ".restore ?DB? FILE Restore content of DB (default \"main\") from FILE", ".save FILE Write in-memory database into FILE", ".scanstats on|off Turn sqlite3_stmt_scanstatus() metrics on or off", ".schema ?PATTERN? Show the CREATE statements matching PATTERN", " Options:", " --indent Try to pretty-print the schema", " --nosys Omit objects whose names start with \"sqlite_\"", ".selftest ?OPTIONS? Run tests defined in the SELFTEST table", " Options:", " --init Create a new SELFTEST table", " -v Verbose output", ".separator COL ?ROW? Change the column and row separators", #if defined(SQLITE_ENABLE_SESSION) ".session ?NAME? CMD ... Create or control sessions", |
︙ | ︙ | |||
3482 3483 3484 3485 3486 3487 3488 | " list List currently open session names", " open DB NAME Open a new session on DB", " patchset FILE Write a patchset into FILE", " If ?NAME? is omitted, the first defined session is used.", #endif ".sha3sum ... Compute a SHA3 hash of database content", " Options:", | | | | > > > > > > > > > > | | 4147 4148 4149 4150 4151 4152 4153 4154 4155 4156 4157 4158 4159 4160 4161 4162 4163 4164 4165 4166 4167 4168 4169 4170 4171 4172 4173 4174 4175 4176 4177 4178 4179 4180 4181 4182 4183 4184 4185 4186 4187 4188 4189 4190 4191 4192 4193 4194 4195 4196 4197 4198 4199 4200 4201 4202 4203 4204 4205 4206 4207 4208 | " list List currently open session names", " open DB NAME Open a new session on DB", " patchset FILE Write a patchset into FILE", " If ?NAME? is omitted, the first defined session is used.", #endif ".sha3sum ... Compute a SHA3 hash of database content", " Options:", " --schema Also hash the sqlite_schema table", " --sha3-224 Use the sha3-224 algorithm", " --sha3-256 Use the sha3-256 algorithm (default)", " --sha3-384 Use the sha3-384 algorithm", " --sha3-512 Use the sha3-512 algorithm", " Any other argument is a LIKE pattern for tables to hash", #ifndef SQLITE_NOHAVE_SYSTEM ".shell CMD ARGS... Run CMD ARGS... in a system shell", #endif ".show Show the current values for various settings", ".stats ?ARG? Show stats or turn stats on or off", " off Turn off automatic stat display", " on Turn on automatic stat display", " stmt Show statement stats", " vmstep Show the virtual machine step count only", #ifndef SQLITE_NOHAVE_SYSTEM ".system CMD ARGS... Run CMD ARGS... in a system shell", #endif ".tables ?TABLE? List names of tables matching LIKE pattern TABLE", ".testcase NAME Begin redirecting output to 'testcase-out.txt'", ".testctrl CMD ... Run various sqlite3_test_control() operations", " Run \".testctrl\" with no arguments for details", ".timeout MS Try opening locked tables for MS milliseconds", ".timer on|off Turn SQL timer on or off", #ifndef SQLITE_OMIT_TRACE ".trace ?OPTIONS? Output each SQL statement as it is run", " FILE Send output to FILE", " stdout Send output to stdout", " stderr Send output to stderr", " off Disable tracing", " --expanded Expand query parameters", #ifdef SQLITE_ENABLE_NORMALIZE " --normalized Normal the SQL statements", #endif " --plain Show SQL as it is input", " --stmt Trace statement execution (SQLITE_TRACE_STMT)", " --profile Profile statements (SQLITE_TRACE_PROFILE)", " --row Trace each row (SQLITE_TRACE_ROW)", " --close Trace connection close (SQLITE_TRACE_CLOSE)", #endif /* SQLITE_OMIT_TRACE */ #ifdef SQLITE_DEBUG ".unmodule NAME ... Unregister virtual table modules", " --allexcept Unregister everything except those named", #endif ".vfsinfo ?AUX? Information about the top-level VFS", ".vfslist List all available VFSes", ".vfsname ?AUX? Print the name of the VFS stack", ".width NUM1 NUM2 ... Set minimum column widths for columnar output", " Negative values right-justify", }; /* ** Output help text. ** ** zPattern describes the set of commands for which help text is provided. |
︙ | ︙ | |||
3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 3551 3552 3553 3554 | int j = 0; int n = 0; char *zPat; if( zPattern==0 || zPattern[0]=='0' || strcmp(zPattern,"-a")==0 || strcmp(zPattern,"-all")==0 ){ /* Show all commands, but only one line per command */ if( zPattern==0 ) zPattern = ""; for(i=0; i<ArraySize(azHelp); i++){ if( azHelp[i][0]=='.' || zPattern[0] ){ utf8_printf(out, "%s\n", azHelp[i]); n++; | > | 4216 4217 4218 4219 4220 4221 4222 4223 4224 4225 4226 4227 4228 4229 4230 | int j = 0; int n = 0; char *zPat; if( zPattern==0 || zPattern[0]=='0' || strcmp(zPattern,"-a")==0 || strcmp(zPattern,"-all")==0 || strcmp(zPattern,"--all")==0 ){ /* Show all commands, but only one line per command */ if( zPattern==0 ) zPattern = ""; for(i=0; i<ArraySize(azHelp); i++){ if( azHelp[i][0]=='.' || zPattern[0] ){ utf8_printf(out, "%s\n", azHelp[i]); n++; |
︙ | ︙ | |||
3653 3654 3655 3656 3657 3658 3659 | } #endif /* ** Close all OpenSession objects and release all associated resources. */ #if defined(SQLITE_ENABLE_SESSION) | | | > | | | | | 4329 4330 4331 4332 4333 4334 4335 4336 4337 4338 4339 4340 4341 4342 4343 4344 4345 4346 4347 4348 4349 4350 4351 4352 | } #endif /* ** Close all OpenSession objects and release all associated resources. */ #if defined(SQLITE_ENABLE_SESSION) static void session_close_all(ShellState *p, int i){ int j; struct AuxDb *pAuxDb = i<0 ? p->pAuxDb : &p->aAuxDb[i]; for(j=0; j<pAuxDb->nSession; j++){ session_close(&pAuxDb->aSession[j]); } pAuxDb->nSession = 0; } #else # define session_close_all(X,Y) #endif /* ** Implementation of the xFilter function for an open session. Omit ** any tables named by ".session filter" but let all other table through. */ #if defined(SQLITE_ENABLE_SESSION) |
︙ | ︙ | |||
3723 3724 3725 3726 3727 3728 3729 | rc = SHELL_OPEN_ZIPFILE; } } fclose(f); return rc; } | | | | > | | | | > | > > | | < | | > | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | | > | > | | > > > > > > > > > > > > > > > > > > > | | | < > > > > > > | 4400 4401 4402 4403 4404 4405 4406 4407 4408 4409 4410 4411 4412 4413 4414 4415 4416 4417 4418 4419 4420 4421 4422 4423 4424 4425 4426 4427 4428 4429 4430 4431 4432 4433 4434 4435 4436 4437 4438 4439 4440 4441 4442 4443 4444 4445 4446 4447 4448 4449 4450 4451 4452 4453 4454 4455 4456 4457 4458 4459 4460 4461 4462 4463 4464 4465 4466 4467 4468 4469 4470 4471 4472 4473 4474 4475 4476 4477 4478 4479 4480 4481 4482 4483 4484 4485 4486 4487 4488 4489 4490 4491 4492 4493 4494 4495 4496 4497 4498 4499 4500 4501 4502 4503 4504 4505 4506 4507 4508 4509 4510 4511 4512 4513 4514 4515 4516 4517 4518 4519 4520 4521 4522 4523 4524 4525 4526 4527 4528 4529 4530 4531 4532 4533 4534 4535 4536 4537 4538 4539 4540 4541 4542 4543 4544 4545 4546 4547 4548 4549 4550 4551 4552 4553 4554 4555 4556 4557 4558 4559 4560 4561 4562 4563 4564 4565 4566 4567 4568 4569 4570 4571 4572 4573 4574 4575 4576 4577 4578 4579 4580 4581 4582 4583 4584 4585 4586 4587 4588 4589 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 | rc = SHELL_OPEN_ZIPFILE; } } fclose(f); return rc; } #ifndef SQLITE_OMIT_DESERIALIZE /* ** Reconstruct an in-memory database using the output from the "dbtotxt" ** program. Read content from the file in p->aAuxDb[].zDbFilename. ** If p->aAuxDb[].zDbFilename is 0, then read from standard input. */ static unsigned char *readHexDb(ShellState *p, int *pnData){ unsigned char *a = 0; int nLine; int n = 0; int pgsz = 0; int iOffset = 0; int j, k; int rc; FILE *in; const char *zDbFilename = p->pAuxDb->zDbFilename; unsigned int x[16]; char zLine[1000]; if( zDbFilename ){ in = fopen(zDbFilename, "r"); if( in==0 ){ utf8_printf(stderr, "cannot open \"%s\" for reading\n", zDbFilename); return 0; } nLine = 0; }else{ in = p->in; nLine = p->lineno; if( in==0 ) in = stdin; } *pnData = 0; nLine++; if( fgets(zLine, sizeof(zLine), in)==0 ) goto readHexDb_error; rc = sscanf(zLine, "| size %d pagesize %d", &n, &pgsz); if( rc!=2 ) goto readHexDb_error; if( n<0 ) goto readHexDb_error; if( pgsz<512 || pgsz>65536 || (pgsz&(pgsz-1))!=0 ) goto readHexDb_error; n = (n+pgsz-1)&~(pgsz-1); /* Round n up to the next multiple of pgsz */ a = sqlite3_malloc( n ? n : 1 ); if( a==0 ){ utf8_printf(stderr, "Out of memory!\n"); goto readHexDb_error; } memset(a, 0, n); if( pgsz<512 || pgsz>65536 || (pgsz & (pgsz-1))!=0 ){ utf8_printf(stderr, "invalid pagesize\n"); goto readHexDb_error; } for(nLine++; fgets(zLine, sizeof(zLine), in)!=0; nLine++){ rc = sscanf(zLine, "| page %d offset %d", &j, &k); if( rc==2 ){ iOffset = k; continue; } if( strncmp(zLine, "| end ", 6)==0 ){ break; } rc = sscanf(zLine,"| %d: %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x", &j, &x[0], &x[1], &x[2], &x[3], &x[4], &x[5], &x[6], &x[7], &x[8], &x[9], &x[10], &x[11], &x[12], &x[13], &x[14], &x[15]); if( rc==17 ){ k = iOffset+j; if( k+16<=n && k>=0 ){ int ii; for(ii=0; ii<16; ii++) a[k+ii] = x[ii]&0xff; } } } *pnData = n; if( in!=p->in ){ fclose(in); }else{ p->lineno = nLine; } return a; readHexDb_error: if( in!=p->in ){ fclose(in); }else{ while( fgets(zLine, sizeof(zLine), p->in)!=0 ){ nLine++; if(strncmp(zLine, "| end ", 6)==0 ) break; } p->lineno = nLine; } sqlite3_free(a); utf8_printf(stderr,"Error on line %d of --hexdb input\n", nLine); return 0; } #endif /* SQLITE_OMIT_DESERIALIZE */ /* ** Scalar function "shell_int32". The first argument to this function ** must be a blob. The second a non-negative integer. This function ** reads and returns a 32-bit big-endian integer from byte ** offset (4*<arg2>) of the blob. */ static void shellInt32( sqlite3_context *context, int argc, sqlite3_value **argv ){ const unsigned char *pBlob; int nBlob; int iInt; UNUSED_PARAMETER(argc); nBlob = sqlite3_value_bytes(argv[0]); pBlob = (const unsigned char*)sqlite3_value_blob(argv[0]); iInt = sqlite3_value_int(argv[1]); if( iInt>=0 && (iInt+1)*4<=nBlob ){ const unsigned char *a = &pBlob[iInt*4]; sqlite3_int64 iVal = ((sqlite3_int64)a[0]<<24) + ((sqlite3_int64)a[1]<<16) + ((sqlite3_int64)a[2]<< 8) + ((sqlite3_int64)a[3]<< 0); sqlite3_result_int64(context, iVal); } } /* ** Scalar function "shell_idquote(X)" returns string X quoted as an identifier, ** using "..." with internal double-quote characters doubled. */ static void shellIdQuote( sqlite3_context *context, int argc, sqlite3_value **argv ){ const char *zName = (const char*)sqlite3_value_text(argv[0]); UNUSED_PARAMETER(argc); if( zName ){ char *z = sqlite3_mprintf("\"%w\"", zName); sqlite3_result_text(context, z, -1, sqlite3_free); } } /* ** Scalar function "usleep(X)" invokes sqlite3_sleep(X) and returns X. */ static void shellUSleepFunc( sqlite3_context *context, int argcUnused, sqlite3_value **argv ){ int sleep = sqlite3_value_int(argv[0]); (void)argcUnused; sqlite3_sleep(sleep/1000); sqlite3_result_int(context, sleep); } /* ** Scalar function "shell_escape_crnl" used by the .recover command. ** The argument passed to this function is the output of built-in ** function quote(). If the first character of the input is "'", ** indicating that the value passed to quote() was a text value, ** then this function searches the input for "\n" and "\r" characters ** and adds a wrapper similar to the following: ** ** replace(replace(<input>, '\n', char(10), '\r', char(13)); ** ** Or, if the first character of the input is not "'", then a copy ** of the input is returned. */ static void shellEscapeCrnl( sqlite3_context *context, int argc, sqlite3_value **argv ){ const char *zText = (const char*)sqlite3_value_text(argv[0]); UNUSED_PARAMETER(argc); if( zText[0]=='\'' ){ int nText = sqlite3_value_bytes(argv[0]); int i; char zBuf1[20]; char zBuf2[20]; const char *zNL = 0; const char *zCR = 0; int nCR = 0; int nNL = 0; for(i=0; zText[i]; i++){ if( zNL==0 && zText[i]=='\n' ){ zNL = unused_string(zText, "\\n", "\\012", zBuf1); nNL = (int)strlen(zNL); } if( zCR==0 && zText[i]=='\r' ){ zCR = unused_string(zText, "\\r", "\\015", zBuf2); nCR = (int)strlen(zCR); } } if( zNL || zCR ){ int iOut = 0; i64 nMax = (nNL > nCR) ? nNL : nCR; i64 nAlloc = nMax * nText + (nMax+64)*2; char *zOut = (char*)sqlite3_malloc64(nAlloc); if( zOut==0 ){ sqlite3_result_error_nomem(context); return; } if( zNL && zCR ){ memcpy(&zOut[iOut], "replace(replace(", 16); iOut += 16; }else{ memcpy(&zOut[iOut], "replace(", 8); iOut += 8; } for(i=0; zText[i]; i++){ if( zText[i]=='\n' ){ memcpy(&zOut[iOut], zNL, nNL); iOut += nNL; }else if( zText[i]=='\r' ){ memcpy(&zOut[iOut], zCR, nCR); iOut += nCR; }else{ zOut[iOut] = zText[i]; iOut++; } } if( zNL ){ memcpy(&zOut[iOut], ",'", 2); iOut += 2; memcpy(&zOut[iOut], zNL, nNL); iOut += nNL; memcpy(&zOut[iOut], "', char(10))", 12); iOut += 12; } if( zCR ){ memcpy(&zOut[iOut], ",'", 2); iOut += 2; memcpy(&zOut[iOut], zCR, nCR); iOut += nCR; memcpy(&zOut[iOut], "', char(13))", 12); iOut += 12; } sqlite3_result_text(context, zOut, iOut, SQLITE_TRANSIENT); sqlite3_free(zOut); return; } } sqlite3_result_value(context, argv[0]); } /* Flags for open_db(). ** ** The default behavior of open_db() is to exit(1) if the database fails to ** open. The OPEN_DB_KEEPALIVE flag changes that so that it prints an error ** but still returns without calling exit. ** ** The OPEN_DB_ZIPFILE flag causes open_db() to prefer to open files as a ** ZIP archive if the file does not exist or is empty and its name matches ** the *.zip pattern. */ #define OPEN_DB_KEEPALIVE 0x001 /* Return after error if true */ #define OPEN_DB_ZIPFILE 0x002 /* Open as ZIP if name matches *.zip */ /* ** Make sure the database is open. If it is not, then open it. If ** the database fails to open, print an error message and exit. */ static void open_db(ShellState *p, int openFlags){ if( p->db==0 ){ const char *zDbFilename = p->pAuxDb->zDbFilename; if( p->openMode==SHELL_OPEN_UNSPEC ){ if( zDbFilename==0 || zDbFilename[0]==0 ){ p->openMode = SHELL_OPEN_NORMAL; }else{ p->openMode = (u8)deduceDatabaseType(zDbFilename, (openFlags & OPEN_DB_ZIPFILE)!=0); } } switch( p->openMode ){ case SHELL_OPEN_APPENDVFS: { sqlite3_open_v2(zDbFilename, &p->db, SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|p->openFlags, "apndvfs"); break; } case SHELL_OPEN_HEXDB: case SHELL_OPEN_DESERIALIZE: { sqlite3_open(0, &p->db); break; } case SHELL_OPEN_ZIPFILE: { sqlite3_open(":memory:", &p->db); break; } case SHELL_OPEN_READONLY: { sqlite3_open_v2(zDbFilename, &p->db, SQLITE_OPEN_READONLY|p->openFlags, 0); break; } case SHELL_OPEN_UNSPEC: case SHELL_OPEN_NORMAL: { sqlite3_open_v2(zDbFilename, &p->db, SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|p->openFlags, 0); break; } } globalDb = p->db; if( p->db==0 || SQLITE_OK!=sqlite3_errcode(p->db) ){ utf8_printf(stderr,"Error: unable to open database \"%s\": %s\n", zDbFilename, sqlite3_errmsg(p->db)); if( openFlags & OPEN_DB_KEEPALIVE ){ sqlite3_open(":memory:", &p->db); return; } exit(1); } #ifndef SQLITE_OMIT_LOAD_EXTENSION sqlite3_enable_load_extension(p->db, 1); #endif sqlite3_fileio_init(p->db, 0, 0); sqlite3_shathree_init(p->db, 0, 0); sqlite3_completion_init(p->db, 0, 0); sqlite3_uint_init(p->db, 0, 0); sqlite3_decimal_init(p->db, 0, 0); sqlite3_regexp_init(p->db, 0, 0); sqlite3_ieee_init(p->db, 0, 0); sqlite3_series_init(p->db, 0, 0); #if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB) sqlite3_dbdata_init(p->db, 0, 0); #endif #ifdef SQLITE_HAVE_ZLIB sqlite3_zipfile_init(p->db, 0, 0); sqlite3_sqlar_init(p->db, 0, 0); #endif sqlite3_create_function(p->db, "shell_add_schema", 3, SQLITE_UTF8, 0, shellAddSchemaName, 0, 0); sqlite3_create_function(p->db, "shell_module_schema", 1, SQLITE_UTF8, 0, shellModuleSchema, 0, 0); sqlite3_create_function(p->db, "shell_putsnl", 1, SQLITE_UTF8, p, shellPutsFunc, 0, 0); sqlite3_create_function(p->db, "shell_escape_crnl", 1, SQLITE_UTF8, 0, shellEscapeCrnl, 0, 0); sqlite3_create_function(p->db, "shell_int32", 2, SQLITE_UTF8, 0, shellInt32, 0, 0); sqlite3_create_function(p->db, "shell_idquote", 1, SQLITE_UTF8, 0, shellIdQuote, 0, 0); sqlite3_create_function(p->db, "usleep",1,SQLITE_UTF8,0, shellUSleepFunc, 0, 0); #ifndef SQLITE_NOHAVE_SYSTEM sqlite3_create_function(p->db, "edit", 1, SQLITE_UTF8, 0, editFunc, 0, 0); sqlite3_create_function(p->db, "edit", 2, SQLITE_UTF8, 0, editFunc, 0, 0); #endif if( p->openMode==SHELL_OPEN_ZIPFILE ){ char *zSql = sqlite3_mprintf( "CREATE VIRTUAL TABLE zip USING zipfile(%Q);", zDbFilename); sqlite3_exec(p->db, zSql, 0, 0, 0); sqlite3_free(zSql); } #ifndef SQLITE_OMIT_DESERIALIZE else if( p->openMode==SHELL_OPEN_DESERIALIZE || p->openMode==SHELL_OPEN_HEXDB ){ int rc; int nData = 0; unsigned char *aData; if( p->openMode==SHELL_OPEN_DESERIALIZE ){ aData = (unsigned char*)readFile(zDbFilename, &nData); }else{ aData = readHexDb(p, &nData); if( aData==0 ){ return; } } rc = sqlite3_deserialize(p->db, "main", aData, nData, nData, SQLITE_DESERIALIZE_RESIZEABLE | SQLITE_DESERIALIZE_FREEONCLOSE); if( rc ){ utf8_printf(stderr, "Error: sqlite3_deserialize() returns %d\n", rc); } if( p->szMax>0 ){ sqlite3_file_control(p->db, "main", SQLITE_FCNTL_SIZE_LIMIT, &p->szMax); } } #endif } if( p->bSafeModePersist && p->db!=0 ){ sqlite3_set_authorizer(p->db, safeModeAuth, p); } } /* ** Attempt to close the databaes connection. Report errors. */ void close_db(sqlite3 *db){ int rc = sqlite3_close(db); |
︙ | ︙ | |||
4197 4198 4199 4200 4201 4202 4203 4204 4205 4206 4207 4208 4209 4210 4211 4212 4213 4214 4215 4216 4217 4218 4219 | /* ** An object used to read a CSV and other files for import. */ typedef struct ImportCtx ImportCtx; struct ImportCtx { const char *zFile; /* Name of the input file */ FILE *in; /* Read the CSV text from this input stream */ char *z; /* Accumulated text for a field */ int n; /* Number of bytes in z */ int nAlloc; /* Space allocated for z[] */ int nLine; /* Current line number */ int bNotFirst; /* True if one or more bytes already read */ int cTerm; /* Character that terminated the most recent field */ int cColSep; /* The column separator character. (Usually ",") */ int cRowSep; /* The row separator character. (Usually "\n") */ }; /* Append a single byte to z[] */ static void import_append_char(ImportCtx *p, int c){ if( p->n+1>=p->nAlloc ){ p->nAlloc += p->nAlloc + 100; p->z = sqlite3_realloc64(p->z, p->nAlloc); if( p->z==0 ) shell_out_of_memory(); | > > > > > > > > > > > > > | 5057 5058 5059 5060 5061 5062 5063 5064 5065 5066 5067 5068 5069 5070 5071 5072 5073 5074 5075 5076 5077 5078 5079 5080 5081 5082 5083 5084 5085 5086 5087 5088 5089 5090 5091 5092 | /* ** An object used to read a CSV and other files for import. */ typedef struct ImportCtx ImportCtx; struct ImportCtx { const char *zFile; /* Name of the input file */ FILE *in; /* Read the CSV text from this input stream */ int (SQLITE_CDECL *xCloser)(FILE*); /* Func to close in */ char *z; /* Accumulated text for a field */ int n; /* Number of bytes in z */ int nAlloc; /* Space allocated for z[] */ int nLine; /* Current line number */ int nRow; /* Number of rows imported */ int nErr; /* Number of errors encountered */ int bNotFirst; /* True if one or more bytes already read */ int cTerm; /* Character that terminated the most recent field */ int cColSep; /* The column separator character. (Usually ",") */ int cRowSep; /* The row separator character. (Usually "\n") */ }; /* Clean up resourced used by an ImportCtx */ static void import_cleanup(ImportCtx *p){ if( p->in!=0 && p->xCloser!=0 ){ p->xCloser(p->in); p->in = 0; } sqlite3_free(p->z); p->z = 0; } /* Append a single byte to z[] */ static void import_append_char(ImportCtx *p, int c){ if( p->n+1>=p->nAlloc ){ p->nAlloc += p->nAlloc + 100; p->z = sqlite3_realloc64(p->z, p->nAlloc); if( p->z==0 ) shell_out_of_memory(); |
︙ | ︙ | |||
4455 4456 4457 4458 4459 4460 4461 | } /* ** Try to transfer all rows of the schema that match zWhere. For ** each row, invoke xForEach() on the object defined by that row. ** If an error is encountered while moving forward through the | | | | 5328 5329 5330 5331 5332 5333 5334 5335 5336 5337 5338 5339 5340 5341 5342 5343 5344 5345 5346 5347 5348 5349 5350 5351 5352 5353 5354 5355 5356 5357 | } /* ** Try to transfer all rows of the schema that match zWhere. For ** each row, invoke xForEach() on the object defined by that row. ** If an error is encountered while moving forward through the ** sqlite_schema table, try again moving backwards. */ static void tryToCloneSchema( ShellState *p, sqlite3 *newDb, const char *zWhere, void (*xForEach)(ShellState*,sqlite3*,const char*) ){ sqlite3_stmt *pQuery = 0; char *zQuery = 0; int rc; const unsigned char *zName; const unsigned char *zSql; char *zErrMsg = 0; zQuery = sqlite3_mprintf("SELECT name, sql FROM sqlite_schema" " WHERE %s", zWhere); rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0); if( rc ){ utf8_printf(stderr, "Error: (%d) %s on [%s]\n", sqlite3_extended_errcode(p->db), sqlite3_errmsg(p->db), zQuery); goto end_schema_xfer; |
︙ | ︙ | |||
4497 4498 4499 4500 4501 4502 4503 | xForEach(p, newDb, (const char*)zName); } printf("done\n"); } if( rc!=SQLITE_DONE ){ sqlite3_finalize(pQuery); sqlite3_free(zQuery); | | | | 5370 5371 5372 5373 5374 5375 5376 5377 5378 5379 5380 5381 5382 5383 5384 5385 5386 5387 5388 5389 5390 5391 5392 5393 | xForEach(p, newDb, (const char*)zName); } printf("done\n"); } if( rc!=SQLITE_DONE ){ sqlite3_finalize(pQuery); sqlite3_free(zQuery); zQuery = sqlite3_mprintf("SELECT name, sql FROM sqlite_schema" " WHERE %s ORDER BY rowid DESC", zWhere); rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0); if( rc ){ utf8_printf(stderr, "Error: (%d) %s on [%s]\n", sqlite3_extended_errcode(p->db), sqlite3_errmsg(p->db), zQuery); goto end_schema_xfer; } while( sqlite3_step(pQuery)==SQLITE_ROW ){ zName = sqlite3_column_text(pQuery, 0); zSql = sqlite3_column_text(pQuery, 1); printf("%s... ", zName); fflush(stdout); sqlite3_exec(newDb, (const char*)zSql, 0, 0, &zErrMsg); if( zErrMsg ){ utf8_printf(stderr, "Error: %s\nSQL: [%s]\n", zErrMsg, zSql); sqlite3_free(zErrMsg); |
︙ | ︙ | |||
4582 4583 4584 4585 4586 4587 4588 4589 4590 4591 4592 4593 4594 4595 | #else "xdg-open"; #endif char *zCmd; zCmd = sqlite3_mprintf("%s %s", zXdgOpenCmd, p->zTempFile); if( system(zCmd) ){ utf8_printf(stderr, "Failed: [%s]\n", zCmd); } sqlite3_free(zCmd); outputModePop(p); p->doXdgOpen = 0; } #endif /* !defined(SQLITE_NOHAVE_SYSTEM) */ } | > > > > > | 5455 5456 5457 5458 5459 5460 5461 5462 5463 5464 5465 5466 5467 5468 5469 5470 5471 5472 5473 | #else "xdg-open"; #endif char *zCmd; zCmd = sqlite3_mprintf("%s %s", zXdgOpenCmd, p->zTempFile); if( system(zCmd) ){ utf8_printf(stderr, "Failed: [%s]\n", zCmd); }else{ /* Give the start/open/xdg-open command some time to get ** going before we continue, and potential delete the ** p->zTempFile data file out from under it */ sqlite3_sleep(2000); } sqlite3_free(zCmd); outputModePop(p); p->doXdgOpen = 0; } #endif /* !defined(SQLITE_NOHAVE_SYSTEM) */ } |
︙ | ︙ | |||
4618 4619 4620 4621 4622 4623 4624 | return (a[0]<<8) + a[1]; } static unsigned int get4byteInt(unsigned char *a){ return (a[0]<<24) + (a[1]<<16) + (a[2]<<8) + a[3]; } /* | | | 5496 5497 5498 5499 5500 5501 5502 5503 5504 5505 5506 5507 5508 5509 5510 | return (a[0]<<8) + a[1]; } static unsigned int get4byteInt(unsigned char *a){ return (a[0]<<24) + (a[1]<<16) + (a[2]<<8) + a[3]; } /* ** Implementation of the ".dbinfo" command. ** ** Return 1 on error, 2 to exit, and 0 otherwise. */ static int shell_dbinfo_command(ShellState *p, int nArg, char **azArg){ static const struct { const char *zName; int ofst; } aField[] = { { "file change counter:", 24 }, { "database page count:", 28 }, |
︙ | ︙ | |||
4649 4650 4651 4652 4653 4654 4655 | { "number of triggers:", "SELECT count(*) FROM %s WHERE type='trigger'" }, { "number of views:", "SELECT count(*) FROM %s WHERE type='view'" }, { "schema size:", "SELECT total(length(sql)) FROM %s" }, }; | | > | | > > > > > | 5527 5528 5529 5530 5531 5532 5533 5534 5535 5536 5537 5538 5539 5540 5541 5542 5543 5544 5545 5546 5547 5548 5549 5550 5551 5552 5553 5554 5555 5556 | { "number of triggers:", "SELECT count(*) FROM %s WHERE type='trigger'" }, { "number of views:", "SELECT count(*) FROM %s WHERE type='view'" }, { "schema size:", "SELECT total(length(sql)) FROM %s" }, }; int i, rc; unsigned iDataVersion; char *zSchemaTab; char *zDb = nArg>=2 ? azArg[1] : "main"; sqlite3_stmt *pStmt = 0; unsigned char aHdr[100]; open_db(p, 0); if( p->db==0 ) return 1; rc = sqlite3_prepare_v2(p->db, "SELECT data FROM sqlite_dbpage(?1) WHERE pgno=1", -1, &pStmt, 0); if( rc ){ utf8_printf(stderr, "error: %s\n", sqlite3_errmsg(p->db)); sqlite3_finalize(pStmt); return 1; } sqlite3_bind_text(pStmt, 1, zDb, -1, SQLITE_STATIC); if( sqlite3_step(pStmt)==SQLITE_ROW && sqlite3_column_bytes(pStmt,0)>100 ){ memcpy(aHdr, sqlite3_column_blob(pStmt,0), 100); sqlite3_finalize(pStmt); }else{ |
︙ | ︙ | |||
4690 4691 4692 4693 4694 4695 4696 | if( val==2 ) raw_printf(p->out, " (utf16le)"); if( val==3 ) raw_printf(p->out, " (utf16be)"); } } raw_printf(p->out, "\n"); } if( zDb==0 ){ | | | | | 5574 5575 5576 5577 5578 5579 5580 5581 5582 5583 5584 5585 5586 5587 5588 5589 5590 5591 5592 | if( val==2 ) raw_printf(p->out, " (utf16le)"); if( val==3 ) raw_printf(p->out, " (utf16be)"); } } raw_printf(p->out, "\n"); } if( zDb==0 ){ zSchemaTab = sqlite3_mprintf("main.sqlite_schema"); }else if( strcmp(zDb,"temp")==0 ){ zSchemaTab = sqlite3_mprintf("%s", "sqlite_temp_schema"); }else{ zSchemaTab = sqlite3_mprintf("\"%w\".sqlite_schema", zDb); } for(i=0; i<ArraySize(aQuery); i++){ char *zSql = sqlite3_mprintf(aQuery[i].zSql, zSchemaTab); int val = db_int(p, zSql); sqlite3_free(zSql); utf8_printf(p->out, "%-20s %d\n", aQuery[i].zName, val); } |
︙ | ︙ | |||
4864 4865 4866 4867 4868 4869 4870 4871 4872 | clearTempFile(p); sqlite3_free(p->zTempFile); p->zTempFile = 0; if( p->db ){ sqlite3_file_control(p->db, 0, SQLITE_FCNTL_TEMPFILENAME, &p->zTempFile); } if( p->zTempFile==0 ){ sqlite3_uint64 r; sqlite3_randomness(sizeof(r), &r); | > > > > > > > > > > > > | | < | 5748 5749 5750 5751 5752 5753 5754 5755 5756 5757 5758 5759 5760 5761 5762 5763 5764 5765 5766 5767 5768 5769 5770 5771 5772 5773 5774 5775 5776 5777 5778 5779 5780 5781 | clearTempFile(p); sqlite3_free(p->zTempFile); p->zTempFile = 0; if( p->db ){ sqlite3_file_control(p->db, 0, SQLITE_FCNTL_TEMPFILENAME, &p->zTempFile); } if( p->zTempFile==0 ){ /* If p->db is an in-memory database then the TEMPFILENAME file-control ** will not work and we will need to fallback to guessing */ char *zTemp; sqlite3_uint64 r; sqlite3_randomness(sizeof(r), &r); zTemp = getenv("TEMP"); if( zTemp==0 ) zTemp = getenv("TMP"); if( zTemp==0 ){ #ifdef _WIN32 zTemp = "\\tmp"; #else zTemp = "/tmp"; #endif } p->zTempFile = sqlite3_mprintf("%s/temp%llx.%s", zTemp, r, zSuffix); }else{ p->zTempFile = sqlite3_mprintf("%z.%s", p->zTempFile, zSuffix); } if( p->zTempFile==0 ){ shell_out_of_memory(); } } /* ** The implementation of SQL scalar function fkey_collate_clause(), used ** by the ".lint fkey-indexes" command. This scalar function is always |
︙ | ︙ | |||
4989 4990 4991 4992 4993 4994 4995 | const char *zSql = "SELECT " " 'EXPLAIN QUERY PLAN SELECT 1 FROM ' || quote(s.name) || ' WHERE '" " || group_concat(quote(s.name) || '.' || quote(f.[from]) || '=?' " " || fkey_collate_clause(" " f.[table], COALESCE(f.[to], p.[name]), s.name, f.[from]),' AND ')" ", " | | | | | 5884 5885 5886 5887 5888 5889 5890 5891 5892 5893 5894 5895 5896 5897 5898 5899 5900 5901 5902 5903 5904 5905 5906 5907 5908 5909 5910 5911 5912 5913 5914 5915 5916 5917 5918 | const char *zSql = "SELECT " " 'EXPLAIN QUERY PLAN SELECT 1 FROM ' || quote(s.name) || ' WHERE '" " || group_concat(quote(s.name) || '.' || quote(f.[from]) || '=?' " " || fkey_collate_clause(" " f.[table], COALESCE(f.[to], p.[name]), s.name, f.[from]),' AND ')" ", " " 'SEARCH ' || s.name || ' USING COVERING INDEX*('" " || group_concat('*=?', ' AND ') || ')'" ", " " s.name || '(' || group_concat(f.[from], ', ') || ')'" ", " " f.[table] || '(' || group_concat(COALESCE(f.[to], p.[name])) || ')'" ", " " 'CREATE INDEX ' || quote(s.name ||'_'|| group_concat(f.[from], '_'))" " || ' ON ' || quote(s.name) || '('" " || group_concat(quote(f.[from]) ||" " fkey_collate_clause(" " f.[table], COALESCE(f.[to], p.[name]), s.name, f.[from]), ', ')" " || ');'" ", " " f.[table] " "FROM sqlite_schema AS s, pragma_foreign_key_list(s.name) AS f " "LEFT JOIN pragma_table_info AS p ON (pk-1=seq AND p.arg=f.[table]) " "GROUP BY s.name, f.id " "ORDER BY (CASE WHEN ? THEN f.[table] ELSE s.name END)" ; const char *zGlobIPK = "SEARCH * USING INTEGER PRIMARY KEY (rowid=?)"; for(i=2; i<nArg; i++){ int n = strlen30(azArg[i]); if( n>1 && sqlite3_strnicmp("-verbose", azArg[i], n)==0 ){ bVerbose = 1; } else if( n>1 && sqlite3_strnicmp("-groupbyparent", azArg[i], n)==0 ){ |
︙ | ︙ | |||
5126 5127 5128 5129 5130 5131 5132 | usage: raw_printf(stderr, "Usage %s sub-command ?switches...?\n", azArg[0]); raw_printf(stderr, "Where sub-commands are:\n"); raw_printf(stderr, " fkey-indexes\n"); return SQLITE_ERROR; } | | < < < > > > > > > > | | 6021 6022 6023 6024 6025 6026 6027 6028 6029 6030 6031 6032 6033 6034 6035 6036 6037 6038 6039 6040 6041 6042 6043 6044 6045 6046 6047 6048 6049 6050 6051 6052 6053 6054 6055 6056 6057 6058 6059 6060 6061 | usage: raw_printf(stderr, "Usage %s sub-command ?switches...?\n", azArg[0]); raw_printf(stderr, "Where sub-commands are:\n"); raw_printf(stderr, " fkey-indexes\n"); return SQLITE_ERROR; } #if !defined SQLITE_OMIT_VIRTUALTABLE static void shellPrepare( sqlite3 *db, int *pRc, const char *zSql, sqlite3_stmt **ppStmt ){ *ppStmt = 0; if( *pRc==SQLITE_OK ){ int rc = sqlite3_prepare_v2(db, zSql, -1, ppStmt, 0); if( rc!=SQLITE_OK ){ raw_printf(stderr, "sql error: %s (%d)\n", sqlite3_errmsg(db), sqlite3_errcode(db) ); *pRc = rc; } } } /* ** Create a prepared statement using printf-style arguments for the SQL. ** ** This routine is could be marked "static". But it is not always used, ** depending on compile-time options. By omitting the "static", we avoid ** nuisance compiler warnings about "defined but not used". */ void shellPreparePrintf( sqlite3 *db, int *pRc, sqlite3_stmt **ppStmt, const char *zFmt, ... ){ *ppStmt = 0; |
︙ | ︙ | |||
5171 5172 5173 5174 5175 5176 5177 | }else{ shellPrepare(db, pRc, z, ppStmt); sqlite3_free(z); } } } | > > > > > > | > > > > > > | > > > > > > > | 6070 6071 6072 6073 6074 6075 6076 6077 6078 6079 6080 6081 6082 6083 6084 6085 6086 6087 6088 6089 6090 6091 6092 6093 6094 6095 6096 6097 6098 6099 6100 6101 6102 6103 6104 6105 6106 6107 6108 6109 6110 6111 6112 6113 6114 6115 6116 6117 6118 6119 6120 6121 6122 6123 6124 6125 6126 6127 6128 6129 6130 6131 6132 6133 6134 6135 6136 6137 6138 6139 6140 6141 | }else{ shellPrepare(db, pRc, z, ppStmt); sqlite3_free(z); } } } /* Finalize the prepared statement created using shellPreparePrintf(). ** ** This routine is could be marked "static". But it is not always used, ** depending on compile-time options. By omitting the "static", we avoid ** nuisance compiler warnings about "defined but not used". */ void shellFinalize( int *pRc, sqlite3_stmt *pStmt ){ if( pStmt ){ sqlite3 *db = sqlite3_db_handle(pStmt); int rc = sqlite3_finalize(pStmt); if( *pRc==SQLITE_OK ){ if( rc!=SQLITE_OK ){ raw_printf(stderr, "SQL error: %s\n", sqlite3_errmsg(db)); } *pRc = rc; } } } /* Reset the prepared statement created using shellPreparePrintf(). ** ** This routine is could be marked "static". But it is not always used, ** depending on compile-time options. By omitting the "static", we avoid ** nuisance compiler warnings about "defined but not used". */ void shellReset( int *pRc, sqlite3_stmt *pStmt ){ int rc = sqlite3_reset(pStmt); if( *pRc==SQLITE_OK ){ if( rc!=SQLITE_OK ){ sqlite3 *db = sqlite3_db_handle(pStmt); raw_printf(stderr, "SQL error: %s\n", sqlite3_errmsg(db)); } *pRc = rc; } } #endif /* !defined SQLITE_OMIT_VIRTUALTABLE */ #if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB) /****************************************************************************** ** The ".archive" or ".ar" command. */ /* ** Structure representing a single ".ar" command. */ typedef struct ArCommand ArCommand; struct ArCommand { u8 eCmd; /* An AR_CMD_* value */ u8 bVerbose; /* True if --verbose */ u8 bZip; /* True if the archive is a ZIP */ u8 bDryRun; /* True if --dry-run */ u8 bAppend; /* True if --append */ u8 bGlob; /* True if --glob */ u8 fromCmdLine; /* Run from -A instead of .archive */ int nArg; /* Number of command arguments */ char *zSrcTable; /* "sqlar", "zipfile($file)" or "zip" */ const char *zFile; /* --file argument, or NULL */ const char *zDir; /* --directory argument, or NULL */ char **azArg; /* Array of command arguments */ ShellState *p; /* Shell state */ |
︙ | ︙ | |||
5252 5253 5254 5255 5256 5257 5258 | return SQLITE_ERROR; } /* ** Values for ArCommand.eCmd. */ #define AR_CMD_CREATE 1 | > > | | | | | | | | | > > > > > > | 6170 6171 6172 6173 6174 6175 6176 6177 6178 6179 6180 6181 6182 6183 6184 6185 6186 6187 6188 6189 6190 6191 6192 6193 6194 6195 6196 6197 6198 6199 6200 6201 6202 6203 6204 6205 6206 6207 6208 6209 6210 6211 6212 6213 6214 6215 6216 6217 6218 6219 6220 | return SQLITE_ERROR; } /* ** Values for ArCommand.eCmd. */ #define AR_CMD_CREATE 1 #define AR_CMD_UPDATE 2 #define AR_CMD_INSERT 3 #define AR_CMD_EXTRACT 4 #define AR_CMD_LIST 5 #define AR_CMD_HELP 6 #define AR_CMD_REMOVE 7 /* ** Other (non-command) switches. */ #define AR_SWITCH_VERBOSE 8 #define AR_SWITCH_FILE 9 #define AR_SWITCH_DIRECTORY 10 #define AR_SWITCH_APPEND 11 #define AR_SWITCH_DRYRUN 12 #define AR_SWITCH_GLOB 13 static int arProcessSwitch(ArCommand *pAr, int eSwitch, const char *zArg){ switch( eSwitch ){ case AR_CMD_CREATE: case AR_CMD_EXTRACT: case AR_CMD_LIST: case AR_CMD_REMOVE: case AR_CMD_UPDATE: case AR_CMD_INSERT: case AR_CMD_HELP: if( pAr->eCmd ){ return arErrorMsg(pAr, "multiple command options"); } pAr->eCmd = eSwitch; break; case AR_SWITCH_DRYRUN: pAr->bDryRun = 1; break; case AR_SWITCH_GLOB: pAr->bGlob = 1; break; case AR_SWITCH_VERBOSE: pAr->bVerbose = 1; break; case AR_SWITCH_APPEND: pAr->bAppend = 1; /* Fall thru into --file */ |
︙ | ︙ | |||
5318 5319 5320 5321 5322 5323 5324 5325 5326 5327 5328 5329 5330 5331 5332 5333 5334 5335 5336 5337 5338 5339 | const char *zLong; char cShort; u8 eSwitch; u8 bArg; } aSwitch[] = { { "create", 'c', AR_CMD_CREATE, 0 }, { "extract", 'x', AR_CMD_EXTRACT, 0 }, { "list", 't', AR_CMD_LIST, 0 }, { "update", 'u', AR_CMD_UPDATE, 0 }, { "help", 'h', AR_CMD_HELP, 0 }, { "verbose", 'v', AR_SWITCH_VERBOSE, 0 }, { "file", 'f', AR_SWITCH_FILE, 1 }, { "append", 'a', AR_SWITCH_APPEND, 1 }, { "directory", 'C', AR_SWITCH_DIRECTORY, 1 }, { "dryrun", 'n', AR_SWITCH_DRYRUN, 0 }, }; int nSwitch = sizeof(aSwitch) / sizeof(struct ArSwitch); struct ArSwitch *pEnd = &aSwitch[nSwitch]; if( nArg<=1 ){ utf8_printf(stderr, "Wrong number of arguments. Usage:\n"); return arUsage(stderr); | > > > | 6244 6245 6246 6247 6248 6249 6250 6251 6252 6253 6254 6255 6256 6257 6258 6259 6260 6261 6262 6263 6264 6265 6266 6267 6268 | const char *zLong; char cShort; u8 eSwitch; u8 bArg; } aSwitch[] = { { "create", 'c', AR_CMD_CREATE, 0 }, { "extract", 'x', AR_CMD_EXTRACT, 0 }, { "insert", 'i', AR_CMD_INSERT, 0 }, { "list", 't', AR_CMD_LIST, 0 }, { "remove", 'r', AR_CMD_REMOVE, 0 }, { "update", 'u', AR_CMD_UPDATE, 0 }, { "help", 'h', AR_CMD_HELP, 0 }, { "verbose", 'v', AR_SWITCH_VERBOSE, 0 }, { "file", 'f', AR_SWITCH_FILE, 1 }, { "append", 'a', AR_SWITCH_APPEND, 1 }, { "directory", 'C', AR_SWITCH_DIRECTORY, 1 }, { "dryrun", 'n', AR_SWITCH_DRYRUN, 0 }, { "glob", 'g', AR_SWITCH_GLOB, 0 }, }; int nSwitch = sizeof(aSwitch) / sizeof(struct ArSwitch); struct ArSwitch *pEnd = &aSwitch[nSwitch]; if( nArg<=1 ){ utf8_printf(stderr, "Wrong number of arguments. Usage:\n"); return arUsage(stderr); |
︙ | ︙ | |||
5392 5393 5394 5395 5396 5397 5398 | } if( pOpt->bArg ){ if( i<(n-1) ){ zArg = &z[i+1]; i = n; }else{ if( iArg>=(nArg-1) ){ | | > | 6321 6322 6323 6324 6325 6326 6327 6328 6329 6330 6331 6332 6333 6334 6335 6336 | } if( pOpt->bArg ){ if( i<(n-1) ){ zArg = &z[i+1]; i = n; }else{ if( iArg>=(nArg-1) ){ return arErrorMsg(pAr, "option requires an argument: %c", z[i]); } zArg = azArg[++iArg]; } } if( arProcessSwitch(pAr, pOpt->eSwitch, zArg) ) return SQLITE_ERROR; } }else if( z[2]=='\0' ){ |
︙ | ︙ | |||
5441 5442 5443 5444 5445 5446 5447 | } return SQLITE_OK; } /* ** This function assumes that all arguments within the ArCommand.azArg[] | | | | | | > > > > > | < < < | 6371 6372 6373 6374 6375 6376 6377 6378 6379 6380 6381 6382 6383 6384 6385 6386 6387 6388 6389 6390 6391 6392 6393 6394 6395 6396 6397 6398 6399 6400 6401 6402 6403 6404 6405 6406 | } return SQLITE_OK; } /* ** This function assumes that all arguments within the ArCommand.azArg[] ** array refer to archive members, as for the --extract, --list or --remove ** commands. It checks that each of them are "present". If any specified ** file is not present in the archive, an error is printed to stderr and an ** error code returned. Otherwise, if all specified arguments are present ** in the archive, SQLITE_OK is returned. Here, "present" means either an ** exact equality when pAr->bGlob is false or a "name GLOB pattern" match ** when pAr->bGlob is true. ** ** This function strips any trailing '/' characters from each argument. ** This is consistent with the way the [tar] command seems to work on ** Linux. */ static int arCheckEntries(ArCommand *pAr){ int rc = SQLITE_OK; if( pAr->nArg ){ int i, j; sqlite3_stmt *pTest = 0; const char *zSel = (pAr->bGlob) ? "SELECT name FROM %s WHERE glob($name,name)" : "SELECT name FROM %s WHERE name=$name"; shellPreparePrintf(pAr->db, &rc, &pTest, zSel, pAr->zSrcTable); j = sqlite3_bind_parameter_index(pTest, "$name"); for(i=0; i<pAr->nArg && rc==SQLITE_OK; i++){ char *z = pAr->azArg[i]; int n = strlen30(z); int bOk = 0; while( n>0 && z[n-1]=='/' ) n--; z[n] = '\0'; |
︙ | ︙ | |||
5488 5489 5490 5491 5492 5493 5494 | } /* ** Format a WHERE clause that can be used against the "sqlar" table to ** identify all archive members that match the command arguments held ** in (*pAr). Leave this WHERE clause in (*pzWhere) before returning. ** The caller is responsible for eventually calling sqlite3_free() on | | > | > | | | 6420 6421 6422 6423 6424 6425 6426 6427 6428 6429 6430 6431 6432 6433 6434 6435 6436 6437 6438 6439 6440 6441 6442 6443 6444 6445 6446 6447 6448 6449 6450 6451 6452 6453 6454 | } /* ** Format a WHERE clause that can be used against the "sqlar" table to ** identify all archive members that match the command arguments held ** in (*pAr). Leave this WHERE clause in (*pzWhere) before returning. ** The caller is responsible for eventually calling sqlite3_free() on ** any non-NULL (*pzWhere) value. Here, "match" means strict equality ** when pAr->bGlob is false and GLOB match when pAr->bGlob is true. */ static void arWhereClause( int *pRc, ArCommand *pAr, char **pzWhere /* OUT: New WHERE clause */ ){ char *zWhere = 0; const char *zSameOp = (pAr->bGlob)? "GLOB" : "="; if( *pRc==SQLITE_OK ){ if( pAr->nArg==0 ){ zWhere = sqlite3_mprintf("1"); }else{ int i; const char *zSep = ""; for(i=0; i<pAr->nArg; i++){ const char *z = pAr->azArg[i]; zWhere = sqlite3_mprintf( "%z%s name %s '%q' OR substr(name,1,%d) %s '%q/'", zWhere, zSep, zSameOp, z, strlen30(z)+1, zSameOp, z ); if( zWhere==0 ){ *pRc = SQLITE_NOMEM; break; } zSep = " OR "; } |
︙ | ︙ | |||
5559 5560 5561 5562 5563 5564 5565 5566 5567 5568 5569 5570 5571 5572 | } } shellFinalize(&rc, pSql); sqlite3_free(zWhere); return rc; } /* ** Implementation of .ar "eXtract" command. */ static int arExtractCommand(ArCommand *pAr){ const char *zSql1 = "SELECT " | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 6493 6494 6495 6496 6497 6498 6499 6500 6501 6502 6503 6504 6505 6506 6507 6508 6509 6510 6511 6512 6513 6514 6515 6516 6517 6518 6519 6520 6521 6522 6523 6524 6525 6526 6527 6528 6529 6530 6531 6532 6533 6534 6535 6536 6537 6538 6539 6540 6541 6542 6543 6544 6545 6546 6547 | } } shellFinalize(&rc, pSql); sqlite3_free(zWhere); return rc; } /* ** Implementation of .ar "Remove" command. */ static int arRemoveCommand(ArCommand *pAr){ int rc = 0; char *zSql = 0; char *zWhere = 0; if( pAr->nArg ){ /* Verify that args actually exist within the archive before proceeding. ** And formulate a WHERE clause to match them. */ rc = arCheckEntries(pAr); arWhereClause(&rc, pAr, &zWhere); } if( rc==SQLITE_OK ){ zSql = sqlite3_mprintf("DELETE FROM %s WHERE %s;", pAr->zSrcTable, zWhere); if( pAr->bDryRun ){ utf8_printf(pAr->p->out, "%s\n", zSql); }else{ char *zErr = 0; rc = sqlite3_exec(pAr->db, "SAVEPOINT ar;", 0, 0, 0); if( rc==SQLITE_OK ){ rc = sqlite3_exec(pAr->db, zSql, 0, 0, &zErr); if( rc!=SQLITE_OK ){ sqlite3_exec(pAr->db, "ROLLBACK TO ar; RELEASE ar;", 0, 0, 0); }else{ rc = sqlite3_exec(pAr->db, "RELEASE ar;", 0, 0, 0); } } if( zErr ){ utf8_printf(stdout, "ERROR: %s\n", zErr); sqlite3_free(zErr); } } } sqlite3_free(zWhere); sqlite3_free(zSql); return rc; } /* ** Implementation of .ar "eXtract" command. */ static int arExtractCommand(ArCommand *pAr){ const char *zSql1 = "SELECT " |
︙ | ︙ | |||
5653 5654 5655 5656 5657 5658 5659 | } } return rc; } /* | | > > > > > | > > | > | 6628 6629 6630 6631 6632 6633 6634 6635 6636 6637 6638 6639 6640 6641 6642 6643 6644 6645 6646 6647 6648 6649 6650 6651 6652 6653 6654 6655 6656 6657 6658 6659 6660 6661 6662 | } } return rc; } /* ** Implementation of .ar "create", "insert", and "update" commands. ** ** create -> Create a new SQL archive ** insert -> Insert or reinsert all files listed ** update -> Insert files that have changed or that were not ** previously in the archive ** ** Create the "sqlar" table in the database if it does not already exist. ** Then add each file in the azFile[] array to the archive. Directories ** are added recursively. If argument bVerbose is non-zero, a message is ** printed on stdout for each file archived. ** ** The create command is the same as update, except that it drops ** any existing "sqlar" table before beginning. The "insert" command ** always overwrites every file named on the command-line, where as ** "update" only overwrites if the size or mtime or mode has changed. */ static int arCreateOrUpdateCommand( ArCommand *pAr, /* Command arguments and options */ int bUpdate, /* true for a --create. */ int bOnlyIfChanged /* Only update if file has changed */ ){ const char *zCreate = "CREATE TABLE IF NOT EXISTS sqlar(\n" " name TEXT PRIMARY KEY, -- name of the file\n" " mode INT, -- access permissions\n" " mtime INT, -- last modification time\n" " sz INT, -- original file size\n" |
︙ | ︙ | |||
5687 5688 5689 5690 5691 5692 5693 | " mode,\n" " mtime,\n" " CASE substr(lsmode(mode),1,1)\n" " WHEN '-' THEN length(data)\n" " WHEN 'd' THEN 0\n" " ELSE -1 END,\n" " sqlar_compress(data)\n" | | | > | | > | 6670 6671 6672 6673 6674 6675 6676 6677 6678 6679 6680 6681 6682 6683 6684 6685 6686 6687 6688 6689 6690 6691 6692 6693 6694 6695 6696 6697 6698 6699 6700 6701 | " mode,\n" " mtime,\n" " CASE substr(lsmode(mode),1,1)\n" " WHEN '-' THEN length(data)\n" " WHEN 'd' THEN 0\n" " ELSE -1 END,\n" " sqlar_compress(data)\n" " FROM fsdir(%Q,%Q) AS disk\n" " WHERE lsmode(mode) NOT LIKE '?%%'%s;" , "REPLACE INTO %s(name,mode,mtime,data)\n" " SELECT\n" " %s,\n" " mode,\n" " mtime,\n" " data\n" " FROM fsdir(%Q,%Q) AS disk\n" " WHERE lsmode(mode) NOT LIKE '?%%'%s;" }; int i; /* For iterating through azFile[] */ int rc; /* Return code */ const char *zTab = 0; /* SQL table into which to insert */ char *zSql; char zTemp[50]; char *zExists = 0; arExecSql(pAr, "PRAGMA page_size=512"); rc = arExecSql(pAr, "SAVEPOINT ar;"); if( rc!=SQLITE_OK ) return rc; zTemp[0] = 0; if( pAr->bZip ){ /* Initialize the zipfile virtual table, if necessary */ |
︙ | ︙ | |||
5733 5734 5735 5736 5737 5738 5739 5740 5741 5742 | zTab = "sqlar"; if( bUpdate==0 ){ rc = arExecSql(pAr, zDrop); if( rc!=SQLITE_OK ) goto end_ar_transaction; } rc = arExecSql(pAr, zCreate); } for(i=0; i<pAr->nArg && rc==SQLITE_OK; i++){ char *zSql2 = sqlite3_mprintf(zInsertFmt[pAr->bZip], zTab, pAr->bVerbose ? "shell_putsnl(name)" : "name", | > > > > > > > > > > > | | > | | | | | 6718 6719 6720 6721 6722 6723 6724 6725 6726 6727 6728 6729 6730 6731 6732 6733 6734 6735 6736 6737 6738 6739 6740 6741 6742 6743 6744 6745 6746 6747 6748 6749 6750 6751 6752 6753 6754 6755 6756 6757 6758 6759 6760 6761 6762 6763 6764 6765 6766 6767 6768 6769 6770 6771 6772 | zTab = "sqlar"; if( bUpdate==0 ){ rc = arExecSql(pAr, zDrop); if( rc!=SQLITE_OK ) goto end_ar_transaction; } rc = arExecSql(pAr, zCreate); } if( bOnlyIfChanged ){ zExists = sqlite3_mprintf( " AND NOT EXISTS(" "SELECT 1 FROM %s AS mem" " WHERE mem.name=disk.name" " AND mem.mtime=disk.mtime" " AND mem.mode=disk.mode)", zTab); }else{ zExists = sqlite3_mprintf(""); } if( zExists==0 ) rc = SQLITE_NOMEM; for(i=0; i<pAr->nArg && rc==SQLITE_OK; i++){ char *zSql2 = sqlite3_mprintf(zInsertFmt[pAr->bZip], zTab, pAr->bVerbose ? "shell_putsnl(name)" : "name", pAr->azArg[i], pAr->zDir, zExists); rc = arExecSql(pAr, zSql2); sqlite3_free(zSql2); } end_ar_transaction: if( rc!=SQLITE_OK ){ sqlite3_exec(pAr->db, "ROLLBACK TO ar; RELEASE ar;", 0, 0, 0); }else{ rc = arExecSql(pAr, "RELEASE ar;"); if( pAr->bZip && pAr->zFile ){ zSql = sqlite3_mprintf("DROP TABLE %s", zTemp); arExecSql(pAr, zSql); sqlite3_free(zSql); } } sqlite3_free(zExists); return rc; } /* ** Implementation of ".ar" dot command. */ static int arDotCommand( ShellState *pState, /* Current shell tool state */ int fromCmdLine, /* True if -A command-line option, not .ar cmd */ char **azArg, /* Array of arguments passed to dot command */ int nArg /* Number of entries in azArg[] */ ){ ArCommand cmd; int rc; memset(&cmd, 0, sizeof(cmd)); cmd.fromCmdLine = fromCmdLine; rc = arParseCommand(azArg, nArg, &cmd); if( rc==SQLITE_OK ){ |
︙ | ︙ | |||
5789 5790 5791 5792 5793 5794 5795 | cmd.zSrcTable = sqlite3_mprintf("zipfile(%Q)", cmd.zFile); } } cmd.bZip = 1; }else if( cmd.zFile ){ int flags; if( cmd.bAppend ) eDbType = SHELL_OPEN_APPENDVFS; | | > | 6786 6787 6788 6789 6790 6791 6792 6793 6794 6795 6796 6797 6798 6799 6800 6801 | cmd.zSrcTable = sqlite3_mprintf("zipfile(%Q)", cmd.zFile); } } cmd.bZip = 1; }else if( cmd.zFile ){ int flags; if( cmd.bAppend ) eDbType = SHELL_OPEN_APPENDVFS; if( cmd.eCmd==AR_CMD_CREATE || cmd.eCmd==AR_CMD_INSERT || cmd.eCmd==AR_CMD_REMOVE || cmd.eCmd==AR_CMD_UPDATE ){ flags = SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE; }else{ flags = SQLITE_OPEN_READONLY; } cmd.db = 0; if( cmd.bDryRun ){ utf8_printf(pState->out, "-- open database '%s'%s\n", cmd.zFile, |
︙ | ︙ | |||
5826 5827 5828 5829 5830 5831 5832 | goto end_ar_command; } cmd.zSrcTable = sqlite3_mprintf("sqlar"); } switch( cmd.eCmd ){ case AR_CMD_CREATE: | | > > > > > > > > | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | > > > > > | 6824 6825 6826 6827 6828 6829 6830 6831 6832 6833 6834 6835 6836 6837 6838 6839 6840 6841 6842 6843 6844 6845 6846 6847 6848 6849 6850 6851 6852 6853 6854 6855 6856 6857 6858 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 6892 6893 6894 6895 6896 6897 6898 6899 6900 6901 6902 6903 6904 6905 6906 6907 6908 6909 6910 6911 6912 6913 6914 6915 6916 6917 6918 6919 6920 6921 6922 6923 6924 6925 6926 6927 6928 6929 6930 6931 6932 6933 6934 6935 6936 6937 6938 6939 6940 6941 6942 6943 6944 6945 6946 6947 6948 6949 6950 6951 6952 6953 6954 6955 6956 6957 6958 6959 6960 6961 6962 6963 6964 6965 6966 6967 6968 6969 6970 6971 6972 6973 6974 6975 6976 6977 6978 6979 6980 6981 6982 6983 6984 6985 6986 6987 6988 6989 6990 6991 6992 6993 6994 6995 6996 6997 6998 6999 7000 7001 7002 7003 7004 7005 7006 7007 7008 7009 7010 7011 7012 7013 7014 7015 7016 7017 7018 7019 7020 7021 7022 7023 7024 7025 7026 7027 7028 7029 7030 7031 7032 7033 7034 7035 7036 7037 7038 7039 7040 7041 7042 7043 7044 7045 7046 7047 7048 7049 7050 7051 7052 7053 7054 7055 7056 7057 7058 7059 7060 7061 7062 7063 7064 7065 7066 7067 7068 7069 7070 7071 7072 7073 7074 7075 7076 7077 7078 7079 7080 7081 7082 7083 7084 7085 7086 7087 7088 7089 7090 7091 7092 7093 7094 7095 7096 7097 7098 7099 7100 7101 7102 7103 7104 7105 7106 7107 7108 7109 7110 7111 7112 7113 7114 7115 7116 7117 7118 7119 7120 7121 7122 7123 7124 7125 7126 7127 7128 7129 7130 7131 7132 7133 7134 7135 7136 7137 7138 7139 7140 7141 7142 7143 7144 7145 7146 7147 7148 7149 7150 7151 7152 7153 7154 7155 7156 7157 7158 7159 7160 7161 7162 7163 7164 7165 7166 7167 7168 7169 7170 7171 7172 7173 7174 7175 7176 7177 7178 7179 7180 7181 7182 7183 7184 7185 7186 7187 7188 7189 7190 7191 7192 7193 7194 7195 7196 7197 7198 7199 7200 7201 7202 7203 7204 7205 7206 7207 7208 7209 7210 7211 7212 7213 7214 7215 7216 7217 7218 7219 7220 7221 7222 7223 7224 7225 7226 7227 7228 7229 7230 7231 7232 7233 7234 7235 7236 7237 7238 7239 7240 7241 7242 7243 7244 7245 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 7292 7293 7294 7295 7296 7297 7298 7299 7300 7301 7302 7303 7304 7305 7306 7307 7308 7309 7310 7311 7312 7313 7314 7315 7316 7317 7318 7319 7320 7321 7322 7323 7324 7325 7326 7327 7328 7329 7330 7331 7332 7333 7334 7335 7336 7337 7338 7339 7340 7341 7342 7343 7344 7345 7346 7347 7348 7349 7350 7351 7352 7353 7354 7355 7356 7357 7358 7359 7360 7361 7362 7363 7364 7365 7366 7367 7368 7369 7370 7371 7372 7373 7374 7375 7376 7377 7378 7379 7380 7381 7382 7383 7384 7385 7386 7387 7388 7389 7390 7391 7392 7393 7394 7395 7396 7397 7398 7399 7400 7401 7402 7403 7404 7405 7406 7407 7408 7409 7410 7411 7412 7413 7414 7415 7416 7417 7418 7419 7420 7421 7422 7423 7424 7425 7426 7427 7428 7429 7430 7431 7432 7433 7434 7435 7436 7437 7438 7439 7440 7441 7442 7443 7444 7445 7446 7447 7448 7449 7450 7451 7452 7453 7454 7455 7456 7457 7458 7459 7460 7461 7462 7463 7464 7465 7466 7467 7468 7469 7470 7471 7472 7473 7474 7475 7476 7477 7478 7479 7480 7481 7482 7483 7484 7485 7486 7487 7488 7489 7490 7491 7492 7493 7494 7495 7496 7497 7498 7499 7500 7501 7502 7503 7504 7505 7506 7507 7508 7509 7510 7511 7512 7513 7514 7515 7516 7517 7518 7519 7520 7521 7522 7523 7524 7525 7526 7527 7528 7529 7530 7531 7532 7533 7534 7535 7536 7537 7538 7539 7540 7541 7542 7543 7544 7545 7546 7547 7548 7549 7550 7551 7552 7553 7554 7555 7556 7557 7558 7559 7560 7561 7562 7563 7564 7565 7566 7567 7568 7569 7570 7571 7572 7573 7574 7575 7576 7577 7578 7579 7580 7581 7582 7583 7584 7585 7586 7587 7588 7589 7590 7591 7592 7593 7594 7595 7596 7597 7598 7599 7600 7601 7602 7603 7604 7605 7606 7607 7608 7609 7610 7611 7612 7613 7614 7615 7616 7617 7618 7619 7620 7621 7622 7623 7624 7625 7626 7627 7628 7629 7630 7631 7632 7633 7634 7635 7636 7637 7638 7639 7640 7641 7642 | goto end_ar_command; } cmd.zSrcTable = sqlite3_mprintf("sqlar"); } switch( cmd.eCmd ){ case AR_CMD_CREATE: rc = arCreateOrUpdateCommand(&cmd, 0, 0); break; case AR_CMD_EXTRACT: rc = arExtractCommand(&cmd); break; case AR_CMD_LIST: rc = arListCommand(&cmd); break; case AR_CMD_HELP: arUsage(pState->out); break; case AR_CMD_INSERT: rc = arCreateOrUpdateCommand(&cmd, 1, 0); break; case AR_CMD_REMOVE: rc = arRemoveCommand(&cmd); break; default: assert( cmd.eCmd==AR_CMD_UPDATE ); rc = arCreateOrUpdateCommand(&cmd, 1, 1); break; } } end_ar_command: if( cmd.db!=pState->db ){ close_db(cmd.db); } sqlite3_free(cmd.zSrcTable); return rc; } /* End of the ".archive" or ".ar" command logic *******************************************************************************/ #endif /* !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB) */ #if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB) /* ** If (*pRc) is not SQLITE_OK when this function is called, it is a no-op. ** Otherwise, the SQL statement or statements in zSql are executed using ** database connection db and the error code written to *pRc before ** this function returns. */ static void shellExec(sqlite3 *db, int *pRc, const char *zSql){ int rc = *pRc; if( rc==SQLITE_OK ){ char *zErr = 0; rc = sqlite3_exec(db, zSql, 0, 0, &zErr); if( rc!=SQLITE_OK ){ raw_printf(stderr, "SQL error: %s\n", zErr); } sqlite3_free(zErr); *pRc = rc; } } /* ** Like shellExec(), except that zFmt is a printf() style format string. */ static void shellExecPrintf(sqlite3 *db, int *pRc, const char *zFmt, ...){ char *z = 0; if( *pRc==SQLITE_OK ){ va_list ap; va_start(ap, zFmt); z = sqlite3_vmprintf(zFmt, ap); va_end(ap); if( z==0 ){ *pRc = SQLITE_NOMEM; }else{ shellExec(db, pRc, z); } sqlite3_free(z); } } /* ** If *pRc is not SQLITE_OK when this function is called, it is a no-op. ** Otherwise, an attempt is made to allocate, zero and return a pointer ** to a buffer nByte bytes in size. If an OOM error occurs, *pRc is set ** to SQLITE_NOMEM and NULL returned. */ static void *shellMalloc(int *pRc, sqlite3_int64 nByte){ void *pRet = 0; if( *pRc==SQLITE_OK ){ pRet = sqlite3_malloc64(nByte); if( pRet==0 ){ *pRc = SQLITE_NOMEM; }else{ memset(pRet, 0, nByte); } } return pRet; } /* ** If *pRc is not SQLITE_OK when this function is called, it is a no-op. ** Otherwise, zFmt is treated as a printf() style string. The result of ** formatting it along with any trailing arguments is written into a ** buffer obtained from sqlite3_malloc(), and pointer to which is returned. ** It is the responsibility of the caller to eventually free this buffer ** using a call to sqlite3_free(). ** ** If an OOM error occurs, (*pRc) is set to SQLITE_NOMEM and a NULL ** pointer returned. */ static char *shellMPrintf(int *pRc, const char *zFmt, ...){ char *z = 0; if( *pRc==SQLITE_OK ){ va_list ap; va_start(ap, zFmt); z = sqlite3_vmprintf(zFmt, ap); va_end(ap); if( z==0 ){ *pRc = SQLITE_NOMEM; } } return z; } /* ** When running the ".recover" command, each output table, and the special ** orphaned row table if it is required, is represented by an instance ** of the following struct. */ typedef struct RecoverTable RecoverTable; struct RecoverTable { char *zQuoted; /* Quoted version of table name */ int nCol; /* Number of columns in table */ char **azlCol; /* Array of column lists */ int iPk; /* Index of IPK column */ }; /* ** Free a RecoverTable object allocated by recoverFindTable() or ** recoverOrphanTable(). */ static void recoverFreeTable(RecoverTable *pTab){ if( pTab ){ sqlite3_free(pTab->zQuoted); if( pTab->azlCol ){ int i; for(i=0; i<=pTab->nCol; i++){ sqlite3_free(pTab->azlCol[i]); } sqlite3_free(pTab->azlCol); } sqlite3_free(pTab); } } /* ** This function is a no-op if (*pRc) is not SQLITE_OK when it is called. ** Otherwise, it allocates and returns a RecoverTable object based on the ** final four arguments passed to this function. It is the responsibility ** of the caller to eventually free the returned object using ** recoverFreeTable(). */ static RecoverTable *recoverNewTable( int *pRc, /* IN/OUT: Error code */ const char *zName, /* Name of table */ const char *zSql, /* CREATE TABLE statement */ int bIntkey, int nCol ){ sqlite3 *dbtmp = 0; /* sqlite3 handle for testing CREATE TABLE */ int rc = *pRc; RecoverTable *pTab = 0; pTab = (RecoverTable*)shellMalloc(&rc, sizeof(RecoverTable)); if( rc==SQLITE_OK ){ int nSqlCol = 0; int bSqlIntkey = 0; sqlite3_stmt *pStmt = 0; rc = sqlite3_open("", &dbtmp); if( rc==SQLITE_OK ){ sqlite3_create_function(dbtmp, "shell_idquote", 1, SQLITE_UTF8, 0, shellIdQuote, 0, 0); } if( rc==SQLITE_OK ){ rc = sqlite3_exec(dbtmp, "PRAGMA writable_schema = on", 0, 0, 0); } if( rc==SQLITE_OK ){ rc = sqlite3_exec(dbtmp, zSql, 0, 0, 0); if( rc==SQLITE_ERROR ){ rc = SQLITE_OK; goto finished; } } shellPreparePrintf(dbtmp, &rc, &pStmt, "SELECT count(*) FROM pragma_table_info(%Q)", zName ); if( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){ nSqlCol = sqlite3_column_int(pStmt, 0); } shellFinalize(&rc, pStmt); if( rc!=SQLITE_OK || nSqlCol<nCol ){ goto finished; } shellPreparePrintf(dbtmp, &rc, &pStmt, "SELECT (" " SELECT substr(data,1,1)==X'0D' FROM sqlite_dbpage WHERE pgno=rootpage" ") FROM sqlite_schema WHERE name = %Q", zName ); if( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){ bSqlIntkey = sqlite3_column_int(pStmt, 0); } shellFinalize(&rc, pStmt); if( bIntkey==bSqlIntkey ){ int i; const char *zPk = "_rowid_"; sqlite3_stmt *pPkFinder = 0; /* If this is an intkey table and there is an INTEGER PRIMARY KEY, ** set zPk to the name of the PK column, and pTab->iPk to the index ** of the column, where columns are 0-numbered from left to right. ** Or, if this is a WITHOUT ROWID table or if there is no IPK column, ** leave zPk as "_rowid_" and pTab->iPk at -2. */ pTab->iPk = -2; if( bIntkey ){ shellPreparePrintf(dbtmp, &rc, &pPkFinder, "SELECT cid, name FROM pragma_table_info(%Q) " " WHERE pk=1 AND type='integer' COLLATE nocase" " AND NOT EXISTS (SELECT cid FROM pragma_table_info(%Q) WHERE pk=2)" , zName, zName ); if( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pPkFinder) ){ pTab->iPk = sqlite3_column_int(pPkFinder, 0); zPk = (const char*)sqlite3_column_text(pPkFinder, 1); } } pTab->zQuoted = shellMPrintf(&rc, "\"%w\"", zName); pTab->azlCol = (char**)shellMalloc(&rc, sizeof(char*) * (nSqlCol+1)); pTab->nCol = nSqlCol; if( bIntkey ){ pTab->azlCol[0] = shellMPrintf(&rc, "\"%w\"", zPk); }else{ pTab->azlCol[0] = shellMPrintf(&rc, ""); } i = 1; shellPreparePrintf(dbtmp, &rc, &pStmt, "SELECT %Q || group_concat(shell_idquote(name), ', ') " " FILTER (WHERE cid!=%d) OVER (ORDER BY %s cid) " "FROM pragma_table_info(%Q)", bIntkey ? ", " : "", pTab->iPk, bIntkey ? "" : "(CASE WHEN pk=0 THEN 1000000 ELSE pk END), ", zName ); while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){ const char *zText = (const char*)sqlite3_column_text(pStmt, 0); pTab->azlCol[i] = shellMPrintf(&rc, "%s%s", pTab->azlCol[0], zText); i++; } shellFinalize(&rc, pStmt); shellFinalize(&rc, pPkFinder); } } finished: sqlite3_close(dbtmp); *pRc = rc; if( rc!=SQLITE_OK || (pTab && pTab->zQuoted==0) ){ recoverFreeTable(pTab); pTab = 0; } return pTab; } /* ** This function is called to search the schema recovered from the ** sqlite_schema table of the (possibly) corrupt database as part ** of a ".recover" command. Specifically, for a table with root page ** iRoot and at least nCol columns. Additionally, if bIntkey is 0, the ** table must be a WITHOUT ROWID table, or if non-zero, not one of ** those. ** ** If a table is found, a (RecoverTable*) object is returned. Or, if ** no such table is found, but bIntkey is false and iRoot is the ** root page of an index in the recovered schema, then (*pbNoop) is ** set to true and NULL returned. Or, if there is no such table or ** index, NULL is returned and (*pbNoop) set to 0, indicating that ** the caller should write data to the orphans table. */ static RecoverTable *recoverFindTable( ShellState *pState, /* Shell state object */ int *pRc, /* IN/OUT: Error code */ int iRoot, /* Root page of table */ int bIntkey, /* True for an intkey table */ int nCol, /* Number of columns in table */ int *pbNoop /* OUT: True if iRoot is root of index */ ){ sqlite3_stmt *pStmt = 0; RecoverTable *pRet = 0; int bNoop = 0; const char *zSql = 0; const char *zName = 0; /* Search the recovered schema for an object with root page iRoot. */ shellPreparePrintf(pState->db, pRc, &pStmt, "SELECT type, name, sql FROM recovery.schema WHERE rootpage=%d", iRoot ); while( *pRc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){ const char *zType = (const char*)sqlite3_column_text(pStmt, 0); if( bIntkey==0 && sqlite3_stricmp(zType, "index")==0 ){ bNoop = 1; break; } if( sqlite3_stricmp(zType, "table")==0 ){ zName = (const char*)sqlite3_column_text(pStmt, 1); zSql = (const char*)sqlite3_column_text(pStmt, 2); pRet = recoverNewTable(pRc, zName, zSql, bIntkey, nCol); break; } } shellFinalize(pRc, pStmt); *pbNoop = bNoop; return pRet; } /* ** Return a RecoverTable object representing the orphans table. */ static RecoverTable *recoverOrphanTable( ShellState *pState, /* Shell state object */ int *pRc, /* IN/OUT: Error code */ const char *zLostAndFound, /* Base name for orphans table */ int nCol /* Number of user data columns */ ){ RecoverTable *pTab = 0; if( nCol>=0 && *pRc==SQLITE_OK ){ int i; /* This block determines the name of the orphan table. The prefered ** name is zLostAndFound. But if that clashes with another name ** in the recovered schema, try zLostAndFound_0, zLostAndFound_1 ** and so on until a non-clashing name is found. */ int iTab = 0; char *zTab = shellMPrintf(pRc, "%s", zLostAndFound); sqlite3_stmt *pTest = 0; shellPrepare(pState->db, pRc, "SELECT 1 FROM recovery.schema WHERE name=?", &pTest ); if( pTest ) sqlite3_bind_text(pTest, 1, zTab, -1, SQLITE_TRANSIENT); while( *pRc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pTest) ){ shellReset(pRc, pTest); sqlite3_free(zTab); zTab = shellMPrintf(pRc, "%s_%d", zLostAndFound, iTab++); sqlite3_bind_text(pTest, 1, zTab, -1, SQLITE_TRANSIENT); } shellFinalize(pRc, pTest); pTab = (RecoverTable*)shellMalloc(pRc, sizeof(RecoverTable)); if( pTab ){ pTab->zQuoted = shellMPrintf(pRc, "\"%w\"", zTab); pTab->nCol = nCol; pTab->iPk = -2; if( nCol>0 ){ pTab->azlCol = (char**)shellMalloc(pRc, sizeof(char*) * (nCol+1)); if( pTab->azlCol ){ pTab->azlCol[nCol] = shellMPrintf(pRc, ""); for(i=nCol-1; i>=0; i--){ pTab->azlCol[i] = shellMPrintf(pRc, "%s, NULL", pTab->azlCol[i+1]); } } } if( *pRc!=SQLITE_OK ){ recoverFreeTable(pTab); pTab = 0; }else{ raw_printf(pState->out, "CREATE TABLE %s(rootpgno INTEGER, " "pgno INTEGER, nfield INTEGER, id INTEGER", pTab->zQuoted ); for(i=0; i<nCol; i++){ raw_printf(pState->out, ", c%d", i); } raw_printf(pState->out, ");\n"); } } sqlite3_free(zTab); } return pTab; } /* ** This function is called to recover data from the database. A script ** to construct a new database containing all recovered data is output ** on stream pState->out. */ static int recoverDatabaseCmd(ShellState *pState, int nArg, char **azArg){ int rc = SQLITE_OK; sqlite3_stmt *pLoop = 0; /* Loop through all root pages */ sqlite3_stmt *pPages = 0; /* Loop through all pages in a group */ sqlite3_stmt *pCells = 0; /* Loop through all cells in a page */ const char *zRecoveryDb = ""; /* Name of "recovery" database */ const char *zLostAndFound = "lost_and_found"; int i; int nOrphan = -1; RecoverTable *pOrphan = 0; int bFreelist = 1; /* 0 if --freelist-corrupt is specified */ int bRowids = 1; /* 0 if --no-rowids */ for(i=1; i<nArg; i++){ char *z = azArg[i]; int n; if( z[0]=='-' && z[1]=='-' ) z++; n = strlen30(z); if( n<=17 && memcmp("-freelist-corrupt", z, n)==0 ){ bFreelist = 0; }else if( n<=12 && memcmp("-recovery-db", z, n)==0 && i<(nArg-1) ){ i++; zRecoveryDb = azArg[i]; }else if( n<=15 && memcmp("-lost-and-found", z, n)==0 && i<(nArg-1) ){ i++; zLostAndFound = azArg[i]; }else if( n<=10 && memcmp("-no-rowids", z, n)==0 ){ bRowids = 0; } else{ utf8_printf(stderr, "unexpected option: %s\n", azArg[i]); showHelp(pState->out, azArg[0]); return 1; } } shellExecPrintf(pState->db, &rc, /* Attach an in-memory database named 'recovery'. Create an indexed ** cache of the sqlite_dbptr virtual table. */ "PRAGMA writable_schema = on;" "ATTACH %Q AS recovery;" "DROP TABLE IF EXISTS recovery.dbptr;" "DROP TABLE IF EXISTS recovery.freelist;" "DROP TABLE IF EXISTS recovery.map;" "DROP TABLE IF EXISTS recovery.schema;" "CREATE TABLE recovery.freelist(pgno INTEGER PRIMARY KEY);", zRecoveryDb ); if( bFreelist ){ shellExec(pState->db, &rc, "WITH trunk(pgno) AS (" " SELECT shell_int32(" " (SELECT data FROM sqlite_dbpage WHERE pgno=1), 8) AS x " " WHERE x>0" " UNION" " SELECT shell_int32(" " (SELECT data FROM sqlite_dbpage WHERE pgno=trunk.pgno), 0) AS x " " FROM trunk WHERE x>0" ")," "freelist(data, n, freepgno) AS (" " SELECT data, min(16384, shell_int32(data, 1)-1), t.pgno " " FROM trunk t, sqlite_dbpage s WHERE s.pgno=t.pgno" " UNION ALL" " SELECT data, n-1, shell_int32(data, 2+n) " " FROM freelist WHERE n>=0" ")" "REPLACE INTO recovery.freelist SELECT freepgno FROM freelist;" ); } /* If this is an auto-vacuum database, add all pointer-map pages to ** the freelist table. Do this regardless of whether or not ** --freelist-corrupt was specified. */ shellExec(pState->db, &rc, "WITH ptrmap(pgno) AS (" " SELECT 2 WHERE shell_int32(" " (SELECT data FROM sqlite_dbpage WHERE pgno=1), 13" " )" " UNION ALL " " SELECT pgno+1+(SELECT page_size FROM pragma_page_size)/5 AS pp " " FROM ptrmap WHERE pp<=(SELECT page_count FROM pragma_page_count)" ")" "REPLACE INTO recovery.freelist SELECT pgno FROM ptrmap" ); shellExec(pState->db, &rc, "CREATE TABLE recovery.dbptr(" " pgno, child, PRIMARY KEY(child, pgno)" ") WITHOUT ROWID;" "INSERT OR IGNORE INTO recovery.dbptr(pgno, child) " " SELECT * FROM sqlite_dbptr" " WHERE pgno NOT IN freelist AND child NOT IN freelist;" /* Delete any pointer to page 1. This ensures that page 1 is considered ** a root page, regardless of how corrupt the db is. */ "DELETE FROM recovery.dbptr WHERE child = 1;" /* Delete all pointers to any pages that have more than one pointer ** to them. Such pages will be treated as root pages when recovering ** data. */ "DELETE FROM recovery.dbptr WHERE child IN (" " SELECT child FROM recovery.dbptr GROUP BY child HAVING count(*)>1" ");" /* Create the "map" table that will (eventually) contain instructions ** for dealing with each page in the db that contains one or more ** records. */ "CREATE TABLE recovery.map(" "pgno INTEGER PRIMARY KEY, maxlen INT, intkey, root INT" ");" /* Populate table [map]. If there are circular loops of pages in the ** database, the following adds all pages in such a loop to the map ** as individual root pages. This could be handled better. */ "WITH pages(i, maxlen) AS (" " SELECT page_count, (" " SELECT max(field+1) FROM sqlite_dbdata WHERE pgno=page_count" " ) FROM pragma_page_count WHERE page_count>0" " UNION ALL" " SELECT i-1, (" " SELECT max(field+1) FROM sqlite_dbdata WHERE pgno=i-1" " ) FROM pages WHERE i>=2" ")" "INSERT INTO recovery.map(pgno, maxlen, intkey, root) " " SELECT i, maxlen, NULL, (" " WITH p(orig, pgno, parent) AS (" " SELECT 0, i, (SELECT pgno FROM recovery.dbptr WHERE child=i)" " UNION " " SELECT i, p.parent, " " (SELECT pgno FROM recovery.dbptr WHERE child=p.parent) FROM p" " )" " SELECT pgno FROM p WHERE (parent IS NULL OR pgno = orig)" ") " "FROM pages WHERE maxlen IS NOT NULL AND i NOT IN freelist;" "UPDATE recovery.map AS o SET intkey = (" " SELECT substr(data, 1, 1)==X'0D' FROM sqlite_dbpage WHERE pgno=o.pgno" ");" /* Extract data from page 1 and any linked pages into table ** recovery.schema. With the same schema as an sqlite_schema table. */ "CREATE TABLE recovery.schema(type, name, tbl_name, rootpage, sql);" "INSERT INTO recovery.schema SELECT " " max(CASE WHEN field=0 THEN value ELSE NULL END)," " max(CASE WHEN field=1 THEN value ELSE NULL END)," " max(CASE WHEN field=2 THEN value ELSE NULL END)," " max(CASE WHEN field=3 THEN value ELSE NULL END)," " max(CASE WHEN field=4 THEN value ELSE NULL END)" "FROM sqlite_dbdata WHERE pgno IN (" " SELECT pgno FROM recovery.map WHERE root=1" ")" "GROUP BY pgno, cell;" "CREATE INDEX recovery.schema_rootpage ON schema(rootpage);" ); /* Open a transaction, then print out all non-virtual, non-"sqlite_%" ** CREATE TABLE statements that extracted from the existing schema. */ if( rc==SQLITE_OK ){ sqlite3_stmt *pStmt = 0; /* ".recover" might output content in an order which causes immediate ** foreign key constraints to be violated. So disable foreign-key ** constraint enforcement to prevent problems when running the output ** script. */ raw_printf(pState->out, "PRAGMA foreign_keys=OFF;\n"); raw_printf(pState->out, "BEGIN;\n"); raw_printf(pState->out, "PRAGMA writable_schema = on;\n"); shellPrepare(pState->db, &rc, "SELECT sql FROM recovery.schema " "WHERE type='table' AND sql LIKE 'create table%'", &pStmt ); while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){ const char *zCreateTable = (const char*)sqlite3_column_text(pStmt, 0); raw_printf(pState->out, "CREATE TABLE IF NOT EXISTS %s;\n", &zCreateTable[12] ); } shellFinalize(&rc, pStmt); } /* Figure out if an orphan table will be required. And if so, how many ** user columns it should contain */ shellPrepare(pState->db, &rc, "SELECT coalesce(max(maxlen), -2) FROM recovery.map WHERE root>1" , &pLoop ); if( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pLoop) ){ nOrphan = sqlite3_column_int(pLoop, 0); } shellFinalize(&rc, pLoop); pLoop = 0; shellPrepare(pState->db, &rc, "SELECT pgno FROM recovery.map WHERE root=?", &pPages ); shellPrepare(pState->db, &rc, "SELECT max(field), group_concat(shell_escape_crnl(quote" "(case when (? AND field<0) then NULL else value end)" "), ', ')" ", min(field) " "FROM sqlite_dbdata WHERE pgno = ? AND field != ?" "GROUP BY cell", &pCells ); /* Loop through each root page. */ shellPrepare(pState->db, &rc, "SELECT root, intkey, max(maxlen) FROM recovery.map" " WHERE root>1 GROUP BY root, intkey ORDER BY root=(" " SELECT rootpage FROM recovery.schema WHERE name='sqlite_sequence'" ")", &pLoop ); while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pLoop) ){ int iRoot = sqlite3_column_int(pLoop, 0); int bIntkey = sqlite3_column_int(pLoop, 1); int nCol = sqlite3_column_int(pLoop, 2); int bNoop = 0; RecoverTable *pTab; assert( bIntkey==0 || bIntkey==1 ); pTab = recoverFindTable(pState, &rc, iRoot, bIntkey, nCol, &bNoop); if( bNoop || rc ) continue; if( pTab==0 ){ if( pOrphan==0 ){ pOrphan = recoverOrphanTable(pState, &rc, zLostAndFound, nOrphan); } pTab = pOrphan; if( pTab==0 ) break; } if( 0==sqlite3_stricmp(pTab->zQuoted, "\"sqlite_sequence\"") ){ raw_printf(pState->out, "DELETE FROM sqlite_sequence;\n"); } sqlite3_bind_int(pPages, 1, iRoot); if( bRowids==0 && pTab->iPk<0 ){ sqlite3_bind_int(pCells, 1, 1); }else{ sqlite3_bind_int(pCells, 1, 0); } sqlite3_bind_int(pCells, 3, pTab->iPk); while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pPages) ){ int iPgno = sqlite3_column_int(pPages, 0); sqlite3_bind_int(pCells, 2, iPgno); while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pCells) ){ int nField = sqlite3_column_int(pCells, 0); int iMin = sqlite3_column_int(pCells, 2); const char *zVal = (const char*)sqlite3_column_text(pCells, 1); RecoverTable *pTab2 = pTab; if( pTab!=pOrphan && (iMin<0)!=bIntkey ){ if( pOrphan==0 ){ pOrphan = recoverOrphanTable(pState, &rc, zLostAndFound, nOrphan); } pTab2 = pOrphan; if( pTab2==0 ) break; } nField = nField+1; if( pTab2==pOrphan ){ raw_printf(pState->out, "INSERT INTO %s VALUES(%d, %d, %d, %s%s%s);\n", pTab2->zQuoted, iRoot, iPgno, nField, iMin<0 ? "" : "NULL, ", zVal, pTab2->azlCol[nField] ); }else{ raw_printf(pState->out, "INSERT INTO %s(%s) VALUES( %s );\n", pTab2->zQuoted, pTab2->azlCol[nField], zVal ); } } shellReset(&rc, pCells); } shellReset(&rc, pPages); if( pTab!=pOrphan ) recoverFreeTable(pTab); } shellFinalize(&rc, pLoop); shellFinalize(&rc, pPages); shellFinalize(&rc, pCells); recoverFreeTable(pOrphan); /* The rest of the schema */ if( rc==SQLITE_OK ){ sqlite3_stmt *pStmt = 0; shellPrepare(pState->db, &rc, "SELECT sql, name FROM recovery.schema " "WHERE sql NOT LIKE 'create table%'", &pStmt ); while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){ const char *zSql = (const char*)sqlite3_column_text(pStmt, 0); if( sqlite3_strnicmp(zSql, "create virt", 11)==0 ){ const char *zName = (const char*)sqlite3_column_text(pStmt, 1); char *zPrint = shellMPrintf(&rc, "INSERT INTO sqlite_schema VALUES('table', %Q, %Q, 0, %Q)", zName, zName, zSql ); raw_printf(pState->out, "%s;\n", zPrint); sqlite3_free(zPrint); }else{ raw_printf(pState->out, "%s;\n", zSql); } } shellFinalize(&rc, pStmt); } if( rc==SQLITE_OK ){ raw_printf(pState->out, "PRAGMA writable_schema = off;\n"); raw_printf(pState->out, "COMMIT;\n"); } sqlite3_exec(pState->db, "DETACH recovery", 0, 0, 0); return rc; } #endif /* !(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB) */ /* ** If an input line begins with "." then invoke this routine to ** process that line. ** ** Return 1 on error, 2 to exit, and 0 otherwise. */ static int do_meta_command(char *zLine, ShellState *p){ int h = 1; int nArg = 0; int n, c; int rc = 0; char *azArg[52]; #ifndef SQLITE_OMIT_VIRTUALTABLE if( p->expert.pExpert ){ expertFinish(p, 1, 0); } #endif /* Parse the input line into tokens. */ while( zLine[h] && nArg<ArraySize(azArg)-1 ){ while( IsSpace(zLine[h]) ){ h++; } if( zLine[h]==0 ) break; if( zLine[h]=='\'' || zLine[h]=='"' ){ int delim = zLine[h++]; azArg[nArg++] = &zLine[h]; while( zLine[h] && zLine[h]!=delim ){ if( zLine[h]=='\\' && delim=='"' && zLine[h+1]!=0 ) h++; h++; } if( zLine[h]==delim ){ zLine[h++] = 0; } if( delim=='"' ) resolve_backslashes(azArg[nArg-1]); }else{ azArg[nArg++] = &zLine[h]; while( zLine[h] && !IsSpace(zLine[h]) ){ h++; } if( zLine[h] ) zLine[h++] = 0; resolve_backslashes(azArg[nArg-1]); } } azArg[nArg] = 0; /* Process the input line. */ if( nArg==0 ) return 0; /* no tokens, no error */ n = strlen30(azArg[0]); c = azArg[0][0]; clearTempFile(p); #ifndef SQLITE_OMIT_AUTHORIZATION if( c=='a' && strncmp(azArg[0], "auth", n)==0 ){ if( nArg!=2 ){ raw_printf(stderr, "Usage: .auth ON|OFF\n"); rc = 1; goto meta_command_exit; } open_db(p, 0); if( booleanValue(azArg[1]) ){ sqlite3_set_authorizer(p->db, shellAuth, p); }else if( p->bSafeModePersist ){ sqlite3_set_authorizer(p->db, safeModeAuth, p); }else{ sqlite3_set_authorizer(p->db, 0, 0); } }else #endif #if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB) if( c=='a' && strncmp(azArg[0], "archive", n)==0 ){ open_db(p, 0); failIfSafeMode(p, "cannot run .archive in safe mode"); rc = arDotCommand(p, 0, azArg, nArg); }else #endif if( (c=='b' && n>=3 && strncmp(azArg[0], "backup", n)==0) || (c=='s' && n>=3 && strncmp(azArg[0], "save", n)==0) ){ const char *zDestFile = 0; const char *zDb = 0; sqlite3 *pDest; sqlite3_backup *pBackup; int j; int bAsync = 0; const char *zVfs = 0; failIfSafeMode(p, "cannot run .%s in safe mode", azArg[0]); for(j=1; j<nArg; j++){ const char *z = azArg[j]; if( z[0]=='-' ){ if( z[1]=='-' ) z++; if( strcmp(z, "-append")==0 ){ zVfs = "apndvfs"; }else |
︙ | ︙ | |||
6022 6023 6024 6025 6026 6027 6028 6029 6030 6031 6032 6033 6034 6035 6036 6037 6038 6039 6040 6041 6042 6043 6044 6045 6046 6047 6048 | setTextMode(p->out, 1); } }else{ raw_printf(stderr, "Usage: .binary on|off\n"); rc = 1; } }else if( c=='c' && strcmp(azArg[0],"cd")==0 ){ if( nArg==2 ){ #if defined(_WIN32) || defined(WIN32) wchar_t *z = sqlite3_win32_utf8_to_unicode(azArg[1]); rc = !SetCurrentDirectoryW(z); sqlite3_free(z); #else rc = chdir(azArg[1]); #endif if( rc ){ utf8_printf(stderr, "Cannot change to directory \"%s\"\n", azArg[1]); rc = 1; } }else{ raw_printf(stderr, "Usage: .cd DIRECTORY\n"); rc = 1; } }else | > > > > > > > > < < < < < < < | 7708 7709 7710 7711 7712 7713 7714 7715 7716 7717 7718 7719 7720 7721 7722 7723 7724 7725 7726 7727 7728 7729 7730 7731 7732 7733 7734 7735 7736 7737 7738 7739 7740 7741 7742 7743 7744 7745 7746 7747 7748 7749 | setTextMode(p->out, 1); } }else{ raw_printf(stderr, "Usage: .binary on|off\n"); rc = 1; } }else /* The undocumented ".breakpoint" command causes a call to the no-op ** routine named test_breakpoint(). */ if( c=='b' && n>=3 && strncmp(azArg[0], "breakpoint", n)==0 ){ test_breakpoint(); }else if( c=='c' && strcmp(azArg[0],"cd")==0 ){ failIfSafeMode(p, "cannot run .cd in safe mode"); if( nArg==2 ){ #if defined(_WIN32) || defined(WIN32) wchar_t *z = sqlite3_win32_utf8_to_unicode(azArg[1]); rc = !SetCurrentDirectoryW(z); sqlite3_free(z); #else rc = chdir(azArg[1]); #endif if( rc ){ utf8_printf(stderr, "Cannot change to directory \"%s\"\n", azArg[1]); rc = 1; } }else{ raw_printf(stderr, "Usage: .cd DIRECTORY\n"); rc = 1; } }else if( c=='c' && n>=3 && strncmp(azArg[0], "changes", n)==0 ){ if( nArg==2 ){ setOrClearFlag(p, SHFLG_CountChanges, azArg[1]); }else{ raw_printf(stderr, "Usage: .changes on|off\n"); rc = 1; } |
︙ | ︙ | |||
6084 6085 6086 6087 6088 6089 6090 6091 6092 6093 6094 6095 6096 6097 6098 6099 | utf8_printf(stdout, "testcase-%s ok\n", p->zTestcase); p->nCheck++; } sqlite3_free(zRes); }else if( c=='c' && strncmp(azArg[0], "clone", n)==0 ){ if( nArg==2 ){ tryToClone(p, azArg[1]); }else{ raw_printf(stderr, "Usage: .clone FILENAME\n"); rc = 1; } }else if( c=='d' && n>1 && strncmp(azArg[0], "databases", n)==0 ){ | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | > > < < < < < | < | | < > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > | > | > > | | | | | | | > > > > > > > | > > | > > > > > > > > > | > > > > > | > > | > > > > | < > > | | | | > > > > | | | | | > | | < < < < < < < < < < < < < < | | | | > > > | | > | | | | > | > > | > > > > > > > > > > > > > | | 7771 7772 7773 7774 7775 7776 7777 7778 7779 7780 7781 7782 7783 7784 7785 7786 7787 7788 7789 7790 7791 7792 7793 7794 7795 7796 7797 7798 7799 7800 7801 7802 7803 7804 7805 7806 7807 7808 7809 7810 7811 7812 7813 7814 7815 7816 7817 7818 7819 7820 7821 7822 7823 7824 7825 7826 7827 7828 7829 7830 7831 7832 7833 7834 7835 7836 7837 7838 7839 7840 7841 7842 7843 7844 7845 7846 7847 7848 7849 7850 7851 7852 7853 7854 7855 7856 7857 7858 7859 7860 7861 7862 7863 7864 7865 7866 7867 7868 7869 7870 7871 7872 7873 7874 7875 7876 7877 7878 7879 7880 7881 7882 7883 7884 7885 7886 7887 7888 7889 7890 7891 7892 7893 7894 7895 7896 7897 7898 7899 7900 7901 7902 7903 7904 7905 7906 7907 7908 7909 7910 7911 7912 7913 7914 7915 7916 7917 7918 7919 7920 7921 7922 7923 7924 7925 7926 7927 7928 7929 7930 7931 7932 7933 7934 7935 7936 7937 7938 7939 7940 7941 7942 7943 7944 7945 7946 7947 7948 7949 7950 7951 7952 7953 7954 7955 7956 7957 7958 7959 7960 7961 7962 7963 7964 7965 7966 7967 7968 7969 7970 7971 7972 7973 7974 7975 7976 7977 7978 7979 7980 7981 7982 7983 7984 7985 7986 7987 7988 7989 7990 7991 7992 7993 7994 7995 7996 7997 7998 7999 8000 8001 8002 8003 8004 8005 8006 8007 8008 8009 8010 8011 8012 8013 8014 8015 8016 8017 8018 8019 8020 8021 8022 8023 8024 8025 8026 8027 8028 8029 8030 8031 8032 8033 8034 8035 8036 8037 8038 8039 8040 8041 8042 8043 8044 8045 8046 8047 8048 8049 8050 8051 8052 8053 8054 8055 8056 8057 8058 8059 8060 8061 8062 8063 8064 8065 8066 8067 8068 8069 8070 8071 8072 8073 8074 8075 | utf8_printf(stdout, "testcase-%s ok\n", p->zTestcase); p->nCheck++; } sqlite3_free(zRes); }else if( c=='c' && strncmp(azArg[0], "clone", n)==0 ){ failIfSafeMode(p, "cannot run .clone in safe mode"); if( nArg==2 ){ tryToClone(p, azArg[1]); }else{ raw_printf(stderr, "Usage: .clone FILENAME\n"); rc = 1; } }else if( c=='c' && strncmp(azArg[0], "connection", n)==0 ){ if( nArg==1 ){ /* List available connections */ int i; for(i=0; i<ArraySize(p->aAuxDb); i++){ const char *zFile = p->aAuxDb[i].zDbFilename; if( p->aAuxDb[i].db==0 && p->pAuxDb!=&p->aAuxDb[i] ){ zFile = "(not open)"; }else if( zFile==0 ){ zFile = "(memory)"; }else if( zFile[0]==0 ){ zFile = "(temporary-file)"; } if( p->pAuxDb == &p->aAuxDb[i] ){ utf8_printf(stdout, "ACTIVE %d: %s\n", i, zFile); }else if( p->aAuxDb[i].db!=0 ){ utf8_printf(stdout, " %d: %s\n", i, zFile); } } }else if( nArg==2 && IsDigit(azArg[1][0]) && azArg[1][1]==0 ){ int i = azArg[1][0] - '0'; if( p->pAuxDb != &p->aAuxDb[i] && i>=0 && i<ArraySize(p->aAuxDb) ){ p->pAuxDb->db = p->db; p->pAuxDb = &p->aAuxDb[i]; globalDb = p->db = p->pAuxDb->db; p->pAuxDb->db = 0; } }else if( nArg==3 && strcmp(azArg[1], "close")==0 && IsDigit(azArg[2][0]) && azArg[2][1]==0 ){ int i = azArg[2][0] - '0'; if( i<0 || i>=ArraySize(p->aAuxDb) ){ /* No-op */ }else if( p->pAuxDb == &p->aAuxDb[i] ){ raw_printf(stderr, "cannot close the active database connection\n"); rc = 1; }else if( p->aAuxDb[i].db ){ session_close_all(p, i); close_db(p->aAuxDb[i].db); p->aAuxDb[i].db = 0; } }else{ raw_printf(stderr, "Usage: .connection [close] [CONNECTION-NUMBER]\n"); rc = 1; } }else if( c=='d' && n>1 && strncmp(azArg[0], "databases", n)==0 ){ char **azName = 0; int nName = 0; sqlite3_stmt *pStmt; int i; open_db(p, 0); rc = sqlite3_prepare_v2(p->db, "PRAGMA database_list", -1, &pStmt, 0); if( rc ){ utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(p->db)); rc = 1; }else{ while( sqlite3_step(pStmt)==SQLITE_ROW ){ const char *zSchema = (const char *)sqlite3_column_text(pStmt,1); const char *zFile = (const char*)sqlite3_column_text(pStmt,2); azName = sqlite3_realloc(azName, (nName+1)*2*sizeof(char*)); if( azName==0 ){ shell_out_of_memory(); /* Does not return */ } azName[nName*2] = strdup(zSchema); azName[nName*2+1] = strdup(zFile); nName++; } } sqlite3_finalize(pStmt); for(i=0; i<nName; i++){ int eTxn = sqlite3_txn_state(p->db, azName[i*2]); int bRdonly = sqlite3_db_readonly(p->db, azName[i*2]); const char *z = azName[i*2+1]; utf8_printf(p->out, "%s: %s %s%s\n", azName[i*2], z && z[0] ? z : "\"\"", bRdonly ? "r/o" : "r/w", eTxn==SQLITE_TXN_NONE ? "" : eTxn==SQLITE_TXN_READ ? " read-txn" : " write-txn"); free(azName[i*2]); free(azName[i*2+1]); } sqlite3_free(azName); }else if( c=='d' && n>=3 && strncmp(azArg[0], "dbconfig", n)==0 ){ static const struct DbConfigChoices { const char *zName; int op; } aDbConfig[] = { { "defensive", SQLITE_DBCONFIG_DEFENSIVE }, { "dqs_ddl", SQLITE_DBCONFIG_DQS_DDL }, { "dqs_dml", SQLITE_DBCONFIG_DQS_DML }, { "enable_fkey", SQLITE_DBCONFIG_ENABLE_FKEY }, { "enable_qpsg", SQLITE_DBCONFIG_ENABLE_QPSG }, { "enable_trigger", SQLITE_DBCONFIG_ENABLE_TRIGGER }, { "enable_view", SQLITE_DBCONFIG_ENABLE_VIEW }, { "fts3_tokenizer", SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER }, { "legacy_alter_table", SQLITE_DBCONFIG_LEGACY_ALTER_TABLE }, { "legacy_file_format", SQLITE_DBCONFIG_LEGACY_FILE_FORMAT }, { "load_extension", SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION }, { "no_ckpt_on_close", SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE }, { "reset_database", SQLITE_DBCONFIG_RESET_DATABASE }, { "trigger_eqp", SQLITE_DBCONFIG_TRIGGER_EQP }, { "trusted_schema", SQLITE_DBCONFIG_TRUSTED_SCHEMA }, { "writable_schema", SQLITE_DBCONFIG_WRITABLE_SCHEMA }, }; int ii, v; open_db(p, 0); for(ii=0; ii<ArraySize(aDbConfig); ii++){ if( nArg>1 && strcmp(azArg[1], aDbConfig[ii].zName)!=0 ) continue; if( nArg>=3 ){ sqlite3_db_config(p->db, aDbConfig[ii].op, booleanValue(azArg[2]), 0); } sqlite3_db_config(p->db, aDbConfig[ii].op, -1, &v); utf8_printf(p->out, "%19s %s\n", aDbConfig[ii].zName, v ? "on" : "off"); if( nArg>1 ) break; } if( nArg>1 && ii==ArraySize(aDbConfig) ){ utf8_printf(stderr, "Error: unknown dbconfig \"%s\"\n", azArg[1]); utf8_printf(stderr, "Enter \".dbconfig\" with no arguments for a list\n"); } }else if( c=='d' && n>=3 && strncmp(azArg[0], "dbinfo", n)==0 ){ rc = shell_dbinfo_command(p, nArg, azArg); }else #if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB) if( c=='r' && strncmp(azArg[0], "recover", n)==0 ){ open_db(p, 0); rc = recoverDatabaseCmd(p, nArg, azArg); }else #endif /* !(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB) */ if( c=='d' && strncmp(azArg[0], "dump", n)==0 ){ char *zLike = 0; char *zSql; int i; int savedShowHeader = p->showHeader; int savedShellFlags = p->shellFlgs; ShellClearFlag(p, SHFLG_PreserveRowid|SHFLG_Newlines|SHFLG_Echo |SHFLG_DumpDataOnly|SHFLG_DumpNoSys); for(i=1; i<nArg; i++){ if( azArg[i][0]=='-' ){ const char *z = azArg[i]+1; if( z[0]=='-' ) z++; if( strcmp(z,"preserve-rowids")==0 ){ #ifdef SQLITE_OMIT_VIRTUALTABLE raw_printf(stderr, "The --preserve-rowids option is not compatible" " with SQLITE_OMIT_VIRTUALTABLE\n"); rc = 1; sqlite3_free(zLike); goto meta_command_exit; #else ShellSetFlag(p, SHFLG_PreserveRowid); #endif }else if( strcmp(z,"newlines")==0 ){ ShellSetFlag(p, SHFLG_Newlines); }else if( strcmp(z,"data-only")==0 ){ ShellSetFlag(p, SHFLG_DumpDataOnly); }else if( strcmp(z,"nosys")==0 ){ ShellSetFlag(p, SHFLG_DumpNoSys); }else { raw_printf(stderr, "Unknown option \"%s\" on \".dump\"\n", azArg[i]); rc = 1; sqlite3_free(zLike); goto meta_command_exit; } }else{ /* azArg[i] contains a LIKE pattern. This ".dump" request should ** only dump data for tables for which either the table name matches ** the LIKE pattern, or the table appears to be a shadow table of ** a virtual table for which the name matches the LIKE pattern. */ char *zExpr = sqlite3_mprintf( "name LIKE %Q ESCAPE '\\' OR EXISTS (" " SELECT 1 FROM sqlite_schema WHERE " " name LIKE %Q ESCAPE '\\' AND" " sql LIKE 'CREATE VIRTUAL TABLE%%' AND" " substr(o.name, 1, length(name)+1) == (name||'_')" ")", azArg[i], azArg[i] ); if( zLike ){ zLike = sqlite3_mprintf("%z OR %z", zLike, zExpr); }else{ zLike = zExpr; } } } open_db(p, 0); if( (p->shellFlgs & SHFLG_DumpDataOnly)==0 ){ /* When playing back a "dump", the content might appear in an order ** which causes immediate foreign key constraints to be violated. ** So disable foreign-key constraint enforcement to prevent problems. */ raw_printf(p->out, "PRAGMA foreign_keys=OFF;\n"); raw_printf(p->out, "BEGIN TRANSACTION;\n"); } p->writableSchema = 0; p->showHeader = 0; /* Set writable_schema=ON since doing so forces SQLite to initialize ** as much of the schema as it can even if the sqlite_schema table is ** corrupt. */ sqlite3_exec(p->db, "SAVEPOINT dump; PRAGMA writable_schema=ON", 0, 0, 0); p->nErr = 0; if( zLike==0 ) zLike = sqlite3_mprintf("true"); zSql = sqlite3_mprintf( "SELECT name, type, sql FROM sqlite_schema AS o " "WHERE (%s) AND type=='table'" " AND sql NOT NULL" " ORDER BY tbl_name='sqlite_sequence', rowid", zLike ); run_schema_dump_query(p,zSql); sqlite3_free(zSql); if( (p->shellFlgs & SHFLG_DumpDataOnly)==0 ){ zSql = sqlite3_mprintf( "SELECT sql FROM sqlite_schema AS o " "WHERE (%s) AND sql NOT NULL" " AND type IN ('index','trigger','view')", zLike ); run_table_dump_query(p, zSql); sqlite3_free(zSql); } sqlite3_free(zLike); if( p->writableSchema ){ raw_printf(p->out, "PRAGMA writable_schema=OFF;\n"); p->writableSchema = 0; } sqlite3_exec(p->db, "PRAGMA writable_schema=OFF;", 0, 0, 0); sqlite3_exec(p->db, "RELEASE dump;", 0, 0, 0); if( (p->shellFlgs & SHFLG_DumpDataOnly)==0 ){ raw_printf(p->out, p->nErr?"ROLLBACK; -- due to errors\n":"COMMIT;\n"); } p->showHeader = savedShowHeader; p->shellFlgs = savedShellFlags; }else if( c=='e' && strncmp(azArg[0], "echo", n)==0 ){ if( nArg==2 ){ setOrClearFlag(p, SHFLG_Echo, azArg[1]); }else{ raw_printf(stderr, "Usage: .echo on|off\n"); rc = 1; } }else if( c=='e' && strncmp(azArg[0], "eqp", n)==0 ){ if( nArg==2 ){ p->autoEQPtest = 0; if( p->autoEQPtrace ){ if( p->db ) sqlite3_exec(p->db, "PRAGMA vdbe_trace=OFF;", 0, 0, 0); p->autoEQPtrace = 0; } if( strcmp(azArg[1],"full")==0 ){ p->autoEQP = AUTOEQP_full; }else if( strcmp(azArg[1],"trigger")==0 ){ p->autoEQP = AUTOEQP_trigger; #ifdef SQLITE_DEBUG }else if( strcmp(azArg[1],"test")==0 ){ p->autoEQP = AUTOEQP_on; p->autoEQPtest = 1; }else if( strcmp(azArg[1],"trace")==0 ){ p->autoEQP = AUTOEQP_full; p->autoEQPtrace = 1; open_db(p, 0); sqlite3_exec(p->db, "SELECT name FROM sqlite_schema LIMIT 1", 0, 0, 0); sqlite3_exec(p->db, "PRAGMA vdbe_trace=ON;", 0, 0, 0); #endif }else{ p->autoEQP = (u8)booleanValue(azArg[1]); } }else{ raw_printf(stderr, "Usage: .eqp off|on|trace|trigger|full\n"); rc = 1; } }else if( c=='e' && strncmp(azArg[0], "exit", n)==0 ){ if( nArg>1 && (rc = (int)integerValue(azArg[1]))!=0 ) exit(rc); rc = 2; |
︙ | ︙ | |||
6299 6300 6301 6302 6303 6304 6305 6306 6307 6308 | #ifndef SQLITE_OMIT_VIRTUALTABLE if( c=='e' && strncmp(azArg[0], "expert", n)==0 ){ open_db(p, 0); expertDotCommand(p, azArg, nArg); }else #endif if( c=='f' && strncmp(azArg[0], "fullschema", n)==0 ){ ShellState data; | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > < | | | | | | < < | < < | | > | | | | | < < | < < < > < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < | < < < < < | < < | < < > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > | > > > | > > > > > > | | | < | | > > > > | < | | > | | > | > > > | | > | 8101 8102 8103 8104 8105 8106 8107 8108 8109 8110 8111 8112 8113 8114 8115 8116 8117 8118 8119 8120 8121 8122 8123 8124 8125 8126 8127 8128 8129 8130 8131 8132 8133 8134 8135 8136 8137 8138 8139 8140 8141 8142 8143 8144 8145 8146 8147 8148 8149 8150 8151 8152 8153 8154 8155 8156 8157 8158 8159 8160 8161 8162 8163 8164 8165 8166 8167 8168 8169 8170 8171 8172 8173 8174 8175 8176 8177 8178 8179 8180 8181 8182 8183 8184 8185 8186 8187 8188 8189 8190 8191 8192 8193 8194 8195 8196 8197 8198 8199 8200 8201 8202 8203 8204 8205 8206 8207 8208 8209 8210 8211 8212 8213 8214 8215 8216 8217 8218 8219 8220 8221 8222 8223 8224 8225 8226 8227 8228 8229 8230 8231 8232 8233 8234 8235 8236 8237 8238 8239 8240 8241 8242 8243 8244 8245 8246 8247 8248 8249 8250 8251 8252 8253 8254 8255 8256 8257 8258 8259 8260 8261 8262 8263 8264 8265 8266 8267 8268 8269 8270 8271 8272 8273 8274 8275 8276 8277 8278 8279 8280 8281 8282 8283 8284 8285 8286 8287 8288 8289 8290 8291 8292 8293 8294 8295 8296 8297 8298 8299 8300 8301 8302 8303 8304 8305 8306 8307 8308 8309 8310 8311 8312 8313 8314 8315 8316 8317 8318 8319 8320 8321 8322 8323 8324 8325 8326 8327 8328 8329 8330 8331 8332 8333 8334 8335 8336 8337 8338 8339 8340 8341 8342 8343 8344 8345 8346 8347 8348 8349 8350 8351 8352 8353 8354 8355 8356 8357 8358 8359 8360 8361 8362 8363 8364 8365 8366 8367 8368 8369 8370 8371 8372 8373 8374 8375 8376 8377 8378 8379 8380 8381 8382 8383 8384 8385 8386 8387 8388 8389 8390 8391 8392 8393 8394 8395 8396 8397 8398 8399 8400 8401 8402 8403 8404 8405 8406 8407 8408 8409 8410 8411 8412 8413 8414 8415 8416 8417 8418 8419 8420 8421 8422 8423 8424 8425 8426 8427 8428 8429 8430 8431 8432 8433 8434 8435 8436 8437 8438 8439 8440 8441 8442 8443 8444 8445 8446 8447 8448 8449 8450 8451 8452 8453 8454 8455 8456 8457 8458 8459 8460 8461 8462 8463 8464 8465 8466 8467 8468 8469 8470 8471 8472 8473 8474 8475 8476 8477 8478 8479 8480 8481 8482 8483 8484 8485 8486 8487 8488 8489 8490 8491 8492 8493 8494 8495 8496 8497 8498 8499 8500 8501 8502 8503 8504 8505 8506 8507 8508 8509 8510 8511 8512 8513 8514 8515 8516 8517 8518 8519 8520 8521 8522 8523 8524 8525 8526 8527 8528 8529 8530 8531 8532 8533 8534 8535 8536 8537 8538 8539 8540 8541 8542 8543 8544 8545 8546 8547 8548 8549 8550 8551 8552 8553 | #ifndef SQLITE_OMIT_VIRTUALTABLE if( c=='e' && strncmp(azArg[0], "expert", n)==0 ){ open_db(p, 0); expertDotCommand(p, azArg, nArg); }else #endif if( c=='f' && strncmp(azArg[0], "filectrl", n)==0 ){ static const struct { const char *zCtrlName; /* Name of a test-control option */ int ctrlCode; /* Integer code for that option */ const char *zUsage; /* Usage notes */ } aCtrl[] = { { "chunk_size", SQLITE_FCNTL_CHUNK_SIZE, "SIZE" }, { "data_version", SQLITE_FCNTL_DATA_VERSION, "" }, { "has_moved", SQLITE_FCNTL_HAS_MOVED, "" }, { "lock_timeout", SQLITE_FCNTL_LOCK_TIMEOUT, "MILLISEC" }, { "persist_wal", SQLITE_FCNTL_PERSIST_WAL, "[BOOLEAN]" }, /* { "pragma", SQLITE_FCNTL_PRAGMA, "NAME ARG" },*/ { "psow", SQLITE_FCNTL_POWERSAFE_OVERWRITE, "[BOOLEAN]" }, { "reserve_bytes", SQLITE_FCNTL_RESERVE_BYTES, "[N]" }, { "size_limit", SQLITE_FCNTL_SIZE_LIMIT, "[LIMIT]" }, { "tempfilename", SQLITE_FCNTL_TEMPFILENAME, "" }, /* { "win32_av_retry", SQLITE_FCNTL_WIN32_AV_RETRY, "COUNT DELAY" },*/ }; int filectrl = -1; int iCtrl = -1; sqlite3_int64 iRes = 0; /* Integer result to display if rc2==1 */ int isOk = 0; /* 0: usage 1: %lld 2: no-result */ int n2, i; const char *zCmd = 0; const char *zSchema = 0; open_db(p, 0); zCmd = nArg>=2 ? azArg[1] : "help"; if( zCmd[0]=='-' && (strcmp(zCmd,"--schema")==0 || strcmp(zCmd,"-schema")==0) && nArg>=4 ){ zSchema = azArg[2]; for(i=3; i<nArg; i++) azArg[i-2] = azArg[i]; nArg -= 2; zCmd = azArg[1]; } /* The argument can optionally begin with "-" or "--" */ if( zCmd[0]=='-' && zCmd[1] ){ zCmd++; if( zCmd[0]=='-' && zCmd[1] ) zCmd++; } /* --help lists all file-controls */ if( strcmp(zCmd,"help")==0 ){ utf8_printf(p->out, "Available file-controls:\n"); for(i=0; i<ArraySize(aCtrl); i++){ utf8_printf(p->out, " .filectrl %s %s\n", aCtrl[i].zCtrlName, aCtrl[i].zUsage); } rc = 1; goto meta_command_exit; } /* convert filectrl text option to value. allow any unique prefix ** of the option name, or a numerical value. */ n2 = strlen30(zCmd); for(i=0; i<ArraySize(aCtrl); i++){ if( strncmp(zCmd, aCtrl[i].zCtrlName, n2)==0 ){ if( filectrl<0 ){ filectrl = aCtrl[i].ctrlCode; iCtrl = i; }else{ utf8_printf(stderr, "Error: ambiguous file-control: \"%s\"\n" "Use \".filectrl --help\" for help\n", zCmd); rc = 1; goto meta_command_exit; } } } if( filectrl<0 ){ utf8_printf(stderr,"Error: unknown file-control: %s\n" "Use \".filectrl --help\" for help\n", zCmd); }else{ switch(filectrl){ case SQLITE_FCNTL_SIZE_LIMIT: { if( nArg!=2 && nArg!=3 ) break; iRes = nArg==3 ? integerValue(azArg[2]) : -1; sqlite3_file_control(p->db, zSchema, SQLITE_FCNTL_SIZE_LIMIT, &iRes); isOk = 1; break; } case SQLITE_FCNTL_LOCK_TIMEOUT: case SQLITE_FCNTL_CHUNK_SIZE: { int x; if( nArg!=3 ) break; x = (int)integerValue(azArg[2]); sqlite3_file_control(p->db, zSchema, filectrl, &x); isOk = 2; break; } case SQLITE_FCNTL_PERSIST_WAL: case SQLITE_FCNTL_POWERSAFE_OVERWRITE: { int x; if( nArg!=2 && nArg!=3 ) break; x = nArg==3 ? booleanValue(azArg[2]) : -1; sqlite3_file_control(p->db, zSchema, filectrl, &x); iRes = x; isOk = 1; break; } case SQLITE_FCNTL_DATA_VERSION: case SQLITE_FCNTL_HAS_MOVED: { int x; if( nArg!=2 ) break; sqlite3_file_control(p->db, zSchema, filectrl, &x); iRes = x; isOk = 1; break; } case SQLITE_FCNTL_TEMPFILENAME: { char *z = 0; if( nArg!=2 ) break; sqlite3_file_control(p->db, zSchema, filectrl, &z); if( z ){ utf8_printf(p->out, "%s\n", z); sqlite3_free(z); } isOk = 2; break; } case SQLITE_FCNTL_RESERVE_BYTES: { int x; if( nArg>=3 ){ x = atoi(azArg[2]); sqlite3_file_control(p->db, zSchema, filectrl, &x); } x = -1; sqlite3_file_control(p->db, zSchema, filectrl, &x); utf8_printf(p->out,"%d\n", x); isOk = 2; break; } } } if( isOk==0 && iCtrl>=0 ){ utf8_printf(p->out, "Usage: .filectrl %s %s\n", zCmd,aCtrl[iCtrl].zUsage); rc = 1; }else if( isOk==1 ){ char zBuf[100]; sqlite3_snprintf(sizeof(zBuf), zBuf, "%lld", iRes); raw_printf(p->out, "%s\n", zBuf); } }else if( c=='f' && strncmp(azArg[0], "fullschema", n)==0 ){ ShellState data; int doStats = 0; memcpy(&data, p, sizeof(data)); data.showHeader = 0; data.cMode = data.mode = MODE_Semi; if( nArg==2 && optionMatch(azArg[1], "indent") ){ data.cMode = data.mode = MODE_Pretty; nArg = 1; } if( nArg!=1 ){ raw_printf(stderr, "Usage: .fullschema ?--indent?\n"); rc = 1; goto meta_command_exit; } open_db(p, 0); rc = sqlite3_exec(p->db, "SELECT sql FROM" " (SELECT sql sql, type type, tbl_name tbl_name, name name, rowid x" " FROM sqlite_schema UNION ALL" " SELECT sql, type, tbl_name, name, rowid FROM sqlite_temp_schema) " "WHERE type!='meta' AND sql NOTNULL AND name NOT LIKE 'sqlite_%' " "ORDER BY x", callback, &data, 0 ); if( rc==SQLITE_OK ){ sqlite3_stmt *pStmt; rc = sqlite3_prepare_v2(p->db, "SELECT rowid FROM sqlite_schema" " WHERE name GLOB 'sqlite_stat[134]'", -1, &pStmt, 0); doStats = sqlite3_step(pStmt)==SQLITE_ROW; sqlite3_finalize(pStmt); } if( doStats==0 ){ raw_printf(p->out, "/* No STAT tables available */\n"); }else{ raw_printf(p->out, "ANALYZE sqlite_schema;\n"); data.cMode = data.mode = MODE_Insert; data.zDestTable = "sqlite_stat1"; shell_exec(&data, "SELECT * FROM sqlite_stat1", 0); data.zDestTable = "sqlite_stat4"; shell_exec(&data, "SELECT * FROM sqlite_stat4", 0); raw_printf(p->out, "ANALYZE sqlite_schema;\n"); } }else if( c=='h' && strncmp(azArg[0], "headers", n)==0 ){ if( nArg==2 ){ p->showHeader = booleanValue(azArg[1]); p->shellFlgs |= SHFLG_HeaderSet; }else{ raw_printf(stderr, "Usage: .headers on|off\n"); rc = 1; } }else if( c=='h' && strncmp(azArg[0], "help", n)==0 ){ if( nArg>=2 ){ n = showHelp(p->out, azArg[1]); if( n==0 ){ utf8_printf(p->out, "Nothing matches '%s'\n", azArg[1]); } }else{ showHelp(p->out, 0); } }else if( c=='i' && strncmp(azArg[0], "import", n)==0 ){ char *zTable = 0; /* Insert data into this table */ char *zFile = 0; /* Name of file to extra content from */ sqlite3_stmt *pStmt = NULL; /* A statement */ int nCol; /* Number of columns in the table */ int nByte; /* Number of bytes in an SQL string */ int i, j; /* Loop counters */ int needCommit; /* True to COMMIT or ROLLBACK at end */ int nSep; /* Number of bytes in p->colSeparator[] */ char *zSql; /* An SQL statement */ ImportCtx sCtx; /* Reader context */ char *(SQLITE_CDECL *xRead)(ImportCtx*); /* Func to read one value */ int eVerbose = 0; /* Larger for more console output */ int nSkip = 0; /* Initial lines to skip */ int useOutputMode = 1; /* Use output mode to determine separators */ failIfSafeMode(p, "cannot run .import in safe mode"); memset(&sCtx, 0, sizeof(sCtx)); sCtx.z = sqlite3_malloc64(120); if( sCtx.z==0 ){ import_cleanup(&sCtx); shell_out_of_memory(); } if( p->mode==MODE_Ascii ){ xRead = ascii_read_one_field; }else{ xRead = csv_read_one_field; } for(i=1; i<nArg; i++){ char *z = azArg[i]; if( z[0]=='-' && z[1]=='-' ) z++; if( z[0]!='-' ){ if( zFile==0 ){ zFile = z; }else if( zTable==0 ){ zTable = z; }else{ utf8_printf(p->out, "ERROR: extra argument: \"%s\". Usage:\n", z); showHelp(p->out, "import"); rc = 1; goto meta_command_exit; } }else if( strcmp(z,"-v")==0 ){ eVerbose++; }else if( strcmp(z,"-skip")==0 && i<nArg-1 ){ nSkip = integerValue(azArg[++i]); }else if( strcmp(z,"-ascii")==0 ){ sCtx.cColSep = SEP_Unit[0]; sCtx.cRowSep = SEP_Record[0]; xRead = ascii_read_one_field; useOutputMode = 0; }else if( strcmp(z,"-csv")==0 ){ sCtx.cColSep = ','; sCtx.cRowSep = '\n'; xRead = csv_read_one_field; useOutputMode = 0; }else{ utf8_printf(p->out, "ERROR: unknown option: \"%s\". Usage:\n", z); showHelp(p->out, "import"); rc = 1; goto meta_command_exit; } } if( zTable==0 ){ utf8_printf(p->out, "ERROR: missing %s argument. Usage:\n", zFile==0 ? "FILE" : "TABLE"); showHelp(p->out, "import"); rc = 1; goto meta_command_exit; } seenInterrupt = 0; open_db(p, 0); if( useOutputMode ){ /* If neither the --csv or --ascii options are specified, then set ** the column and row separator characters from the output mode. */ nSep = strlen30(p->colSeparator); if( nSep==0 ){ raw_printf(stderr, "Error: non-null column separator required for import\n"); rc = 1; goto meta_command_exit; } if( nSep>1 ){ raw_printf(stderr, "Error: multi-character column separators not allowed" " for import\n"); rc = 1; goto meta_command_exit; } nSep = strlen30(p->rowSeparator); if( nSep==0 ){ raw_printf(stderr, "Error: non-null row separator required for import\n"); rc = 1; goto meta_command_exit; } if( nSep==2 && p->mode==MODE_Csv && strcmp(p->rowSeparator,SEP_CrLf)==0 ){ /* When importing CSV (only), if the row separator is set to the ** default output row separator, change it to the default input ** row separator. This avoids having to maintain different input ** and output row separators. */ sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row); nSep = strlen30(p->rowSeparator); } if( nSep>1 ){ raw_printf(stderr, "Error: multi-character row separators not allowed" " for import\n"); rc = 1; goto meta_command_exit; } sCtx.cColSep = p->colSeparator[0]; sCtx.cRowSep = p->rowSeparator[0]; } sCtx.zFile = zFile; sCtx.nLine = 1; if( sCtx.zFile[0]=='|' ){ #ifdef SQLITE_OMIT_POPEN raw_printf(stderr, "Error: pipes are not supported in this OS\n"); rc = 1; goto meta_command_exit; #else sCtx.in = popen(sCtx.zFile+1, "r"); sCtx.zFile = "<pipe>"; sCtx.xCloser = pclose; #endif }else{ sCtx.in = fopen(sCtx.zFile, "rb"); sCtx.xCloser = fclose; } if( sCtx.in==0 ){ utf8_printf(stderr, "Error: cannot open \"%s\"\n", zFile); rc = 1; import_cleanup(&sCtx); goto meta_command_exit; } if( eVerbose>=2 || (eVerbose>=1 && useOutputMode) ){ char zSep[2]; zSep[1] = 0; zSep[0] = sCtx.cColSep; utf8_printf(p->out, "Column separator "); output_c_string(p->out, zSep); utf8_printf(p->out, ", row separator "); zSep[0] = sCtx.cRowSep; output_c_string(p->out, zSep); utf8_printf(p->out, "\n"); } while( (nSkip--)>0 ){ while( xRead(&sCtx) && sCtx.cTerm==sCtx.cColSep ){} } zSql = sqlite3_mprintf("SELECT * FROM \"%w\"", zTable); if( zSql==0 ){ import_cleanup(&sCtx); shell_out_of_memory(); } nByte = strlen30(zSql); rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); import_append_char(&sCtx, 0); /* To ensure sCtx.z is allocated */ if( rc && sqlite3_strglob("no such table: *", sqlite3_errmsg(p->db))==0 ){ char *zCreate = sqlite3_mprintf("CREATE TABLE \"%w\"", zTable); char cSep = '('; while( xRead(&sCtx) ){ zCreate = sqlite3_mprintf("%z%c\n \"%w\" TEXT", zCreate, cSep, sCtx.z); cSep = ','; if( sCtx.cTerm!=sCtx.cColSep ) break; } if( cSep=='(' ){ sqlite3_free(zCreate); import_cleanup(&sCtx); utf8_printf(stderr,"%s: empty file\n", sCtx.zFile); rc = 1; goto meta_command_exit; } zCreate = sqlite3_mprintf("%z\n)", zCreate); if( eVerbose>=1 ){ utf8_printf(p->out, "%s\n", zCreate); } rc = sqlite3_exec(p->db, zCreate, 0, 0, 0); sqlite3_free(zCreate); if( rc ){ utf8_printf(stderr, "CREATE TABLE \"%s\"(...) failed: %s\n", zTable, sqlite3_errmsg(p->db)); import_cleanup(&sCtx); rc = 1; goto meta_command_exit; } rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); } sqlite3_free(zSql); if( rc ){ if (pStmt) sqlite3_finalize(pStmt); utf8_printf(stderr,"Error: %s\n", sqlite3_errmsg(p->db)); import_cleanup(&sCtx); rc = 1; goto meta_command_exit; } nCol = sqlite3_column_count(pStmt); sqlite3_finalize(pStmt); pStmt = 0; if( nCol==0 ) return 0; /* no columns, no error */ zSql = sqlite3_malloc64( nByte*2 + 20 + nCol*2 ); if( zSql==0 ){ import_cleanup(&sCtx); shell_out_of_memory(); } sqlite3_snprintf(nByte+20, zSql, "INSERT INTO \"%w\" VALUES(?", zTable); j = strlen30(zSql); for(i=1; i<nCol; i++){ zSql[j++] = ','; zSql[j++] = '?'; } zSql[j++] = ')'; zSql[j] = 0; if( eVerbose>=2 ){ utf8_printf(p->out, "Insert using: %s\n", zSql); } rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); sqlite3_free(zSql); if( rc ){ utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(p->db)); if (pStmt) sqlite3_finalize(pStmt); import_cleanup(&sCtx); rc = 1; goto meta_command_exit; } needCommit = sqlite3_get_autocommit(p->db); if( needCommit ) sqlite3_exec(p->db, "BEGIN", 0, 0, 0); do{ int startLine = sCtx.nLine; for(i=0; i<nCol; i++){ char *z = xRead(&sCtx); |
︙ | ︙ | |||
6558 6559 6560 6561 6562 6563 6564 6565 6566 6567 6568 | } if( i>=nCol ){ sqlite3_step(pStmt); rc = sqlite3_reset(pStmt); if( rc!=SQLITE_OK ){ utf8_printf(stderr, "%s:%d: INSERT failed: %s\n", sCtx.zFile, startLine, sqlite3_errmsg(p->db)); } } }while( sCtx.cTerm!=EOF ); | > > > | < > > > > > > > > > > > > > > | > | > > > > > > > < < < < < | > > > > > > > > > > | | | > | 8582 8583 8584 8585 8586 8587 8588 8589 8590 8591 8592 8593 8594 8595 8596 8597 8598 8599 8600 8601 8602 8603 8604 8605 8606 8607 8608 8609 8610 8611 8612 8613 8614 8615 8616 8617 8618 8619 8620 8621 8622 8623 8624 8625 8626 8627 8628 8629 8630 8631 8632 8633 8634 8635 8636 8637 8638 8639 8640 8641 8642 8643 8644 8645 8646 8647 8648 8649 8650 8651 8652 8653 8654 8655 8656 8657 8658 8659 8660 8661 8662 8663 8664 8665 8666 8667 8668 8669 8670 8671 8672 8673 8674 8675 8676 8677 8678 8679 8680 8681 8682 8683 8684 8685 8686 8687 8688 8689 8690 8691 8692 8693 8694 8695 8696 8697 8698 8699 8700 8701 8702 8703 | } if( i>=nCol ){ sqlite3_step(pStmt); rc = sqlite3_reset(pStmt); if( rc!=SQLITE_OK ){ utf8_printf(stderr, "%s:%d: INSERT failed: %s\n", sCtx.zFile, startLine, sqlite3_errmsg(p->db)); sCtx.nErr++; }else{ sCtx.nRow++; } } }while( sCtx.cTerm!=EOF ); import_cleanup(&sCtx); sqlite3_finalize(pStmt); if( needCommit ) sqlite3_exec(p->db, "COMMIT", 0, 0, 0); if( eVerbose>0 ){ utf8_printf(p->out, "Added %d rows with %d errors using %d lines of input\n", sCtx.nRow, sCtx.nErr, sCtx.nLine-1); } }else #ifndef SQLITE_UNTESTABLE if( c=='i' && strncmp(azArg[0], "imposter", n)==0 ){ char *zSql; char *zCollist = 0; sqlite3_stmt *pStmt; int tnum = 0; int isWO = 0; /* True if making an imposter of a WITHOUT ROWID table */ int lenPK = 0; /* Length of the PRIMARY KEY string for isWO tables */ int i; if( !(nArg==3 || (nArg==2 && sqlite3_stricmp(azArg[1],"off")==0)) ){ utf8_printf(stderr, "Usage: .imposter INDEX IMPOSTER\n" " .imposter off\n"); /* Also allowed, but not documented: ** ** .imposter TABLE IMPOSTER ** ** where TABLE is a WITHOUT ROWID table. In that case, the ** imposter is another WITHOUT ROWID table with the columns in ** storage order. */ rc = 1; goto meta_command_exit; } open_db(p, 0); if( nArg==2 ){ sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->db, "main", 0, 1); goto meta_command_exit; } zSql = sqlite3_mprintf( "SELECT rootpage, 0 FROM sqlite_schema" " WHERE name='%q' AND type='index'" "UNION ALL " "SELECT rootpage, 1 FROM sqlite_schema" " WHERE name='%q' AND type='table'" " AND sql LIKE '%%without%%rowid%%'", azArg[1], azArg[1] ); sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); sqlite3_free(zSql); if( sqlite3_step(pStmt)==SQLITE_ROW ){ tnum = sqlite3_column_int(pStmt, 0); isWO = sqlite3_column_int(pStmt, 1); } sqlite3_finalize(pStmt); zSql = sqlite3_mprintf("PRAGMA index_xinfo='%q'", azArg[1]); rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); sqlite3_free(zSql); i = 0; while( rc==SQLITE_OK && sqlite3_step(pStmt)==SQLITE_ROW ){ char zLabel[20]; const char *zCol = (const char*)sqlite3_column_text(pStmt,2); i++; if( zCol==0 ){ if( sqlite3_column_int(pStmt,1)==-1 ){ zCol = "_ROWID_"; }else{ sqlite3_snprintf(sizeof(zLabel),zLabel,"expr%d",i); zCol = zLabel; } } if( isWO && lenPK==0 && sqlite3_column_int(pStmt,5)==0 && zCollist ){ lenPK = (int)strlen(zCollist); } if( zCollist==0 ){ zCollist = sqlite3_mprintf("\"%w\"", zCol); }else{ zCollist = sqlite3_mprintf("%z,\"%w\"", zCollist, zCol); } } sqlite3_finalize(pStmt); if( i==0 || tnum==0 ){ utf8_printf(stderr, "no such index: \"%s\"\n", azArg[1]); rc = 1; sqlite3_free(zCollist); goto meta_command_exit; } if( lenPK==0 ) lenPK = 100000; zSql = sqlite3_mprintf( "CREATE TABLE \"%w\"(%s,PRIMARY KEY(%.*s))WITHOUT ROWID", azArg[2], zCollist, lenPK, zCollist); sqlite3_free(zCollist); rc = sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->db, "main", 1, tnum); if( rc==SQLITE_OK ){ rc = sqlite3_exec(p->db, zSql, 0, 0, 0); sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->db, "main", 0, 0); if( rc ){ utf8_printf(stderr, "Error in [%s]: %s\n", zSql, sqlite3_errmsg(p->db)); }else{ utf8_printf(stdout, "%s;\n", zSql); raw_printf(stdout, "WARNING: writing to an imposter table will corrupt the \"%s\" %s!\n", azArg[1], isWO ? "table" : "index" ); } }else{ raw_printf(stderr, "SQLITE_TESTCTRL_IMPOSTER returns %d\n", rc); rc = 1; } sqlite3_free(zSql); |
︙ | ︙ | |||
6737 6738 6739 6740 6741 6742 6743 6744 6745 6746 6747 6748 6749 6750 6751 6752 6753 6754 6755 6756 6757 6758 6759 6760 6761 6762 6763 6764 6765 6766 6767 6768 6769 6770 6771 6772 6773 6774 6775 6776 6777 6778 6779 6780 6781 6782 6783 6784 6785 6786 6787 | lintDotCommand(p, azArg, nArg); }else #ifndef SQLITE_OMIT_LOAD_EXTENSION if( c=='l' && strncmp(azArg[0], "load", n)==0 ){ const char *zFile, *zProc; char *zErrMsg = 0; if( nArg<2 ){ raw_printf(stderr, "Usage: .load FILE ?ENTRYPOINT?\n"); rc = 1; goto meta_command_exit; } zFile = azArg[1]; zProc = nArg>=3 ? azArg[2] : 0; open_db(p, 0); rc = sqlite3_load_extension(p->db, zFile, zProc, &zErrMsg); if( rc!=SQLITE_OK ){ utf8_printf(stderr, "Error: %s\n", zErrMsg); sqlite3_free(zErrMsg); rc = 1; } }else #endif if( c=='l' && strncmp(azArg[0], "log", n)==0 ){ if( nArg!=2 ){ raw_printf(stderr, "Usage: .log FILENAME\n"); rc = 1; }else{ const char *zFile = azArg[1]; output_file_close(p->pLog); p->pLog = output_file_open(zFile, 0); } }else if( c=='m' && strncmp(azArg[0], "mode", n)==0 ){ const char *zMode = nArg>=2 ? azArg[1] : ""; int n2 = strlen30(zMode); int c2 = zMode[0]; if( c2=='l' && n2>2 && strncmp(azArg[1],"lines",n2)==0 ){ p->mode = MODE_Line; sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row); }else if( c2=='c' && strncmp(azArg[1],"columns",n2)==0 ){ p->mode = MODE_Column; sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row); }else if( c2=='l' && n2>2 && strncmp(azArg[1],"list",n2)==0 ){ p->mode = MODE_List; sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Column); sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row); }else if( c2=='h' && strncmp(azArg[1],"html",n2)==0 ){ p->mode = MODE_Html; | > > > > > | 8791 8792 8793 8794 8795 8796 8797 8798 8799 8800 8801 8802 8803 8804 8805 8806 8807 8808 8809 8810 8811 8812 8813 8814 8815 8816 8817 8818 8819 8820 8821 8822 8823 8824 8825 8826 8827 8828 8829 8830 8831 8832 8833 8834 8835 8836 8837 8838 8839 8840 8841 8842 8843 8844 8845 8846 | lintDotCommand(p, azArg, nArg); }else #ifndef SQLITE_OMIT_LOAD_EXTENSION if( c=='l' && strncmp(azArg[0], "load", n)==0 ){ const char *zFile, *zProc; char *zErrMsg = 0; failIfSafeMode(p, "cannot run .load in safe mode"); if( nArg<2 ){ raw_printf(stderr, "Usage: .load FILE ?ENTRYPOINT?\n"); rc = 1; goto meta_command_exit; } zFile = azArg[1]; zProc = nArg>=3 ? azArg[2] : 0; open_db(p, 0); rc = sqlite3_load_extension(p->db, zFile, zProc, &zErrMsg); if( rc!=SQLITE_OK ){ utf8_printf(stderr, "Error: %s\n", zErrMsg); sqlite3_free(zErrMsg); rc = 1; } }else #endif if( c=='l' && strncmp(azArg[0], "log", n)==0 ){ failIfSafeMode(p, "cannot run .log in safe mode"); if( nArg!=2 ){ raw_printf(stderr, "Usage: .log FILENAME\n"); rc = 1; }else{ const char *zFile = azArg[1]; output_file_close(p->pLog); p->pLog = output_file_open(zFile, 0); } }else if( c=='m' && strncmp(azArg[0], "mode", n)==0 ){ const char *zMode = nArg>=2 ? azArg[1] : ""; int n2 = strlen30(zMode); int c2 = zMode[0]; if( c2=='l' && n2>2 && strncmp(azArg[1],"lines",n2)==0 ){ p->mode = MODE_Line; sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row); }else if( c2=='c' && strncmp(azArg[1],"columns",n2)==0 ){ p->mode = MODE_Column; if( (p->shellFlgs & SHFLG_HeaderSet)==0 ){ p->showHeader = 1; } sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row); }else if( c2=='l' && n2>2 && strncmp(azArg[1],"list",n2)==0 ){ p->mode = MODE_List; sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Column); sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row); }else if( c2=='h' && strncmp(azArg[1],"html",n2)==0 ){ p->mode = MODE_Html; |
︙ | ︙ | |||
6797 6798 6799 6800 6801 6802 6803 6804 6805 6806 6807 6808 6809 6810 6811 | p->mode = MODE_List; sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Tab); }else if( c2=='i' && strncmp(azArg[1],"insert",n2)==0 ){ p->mode = MODE_Insert; set_table_name(p, nArg>=3 ? azArg[2] : "table"); }else if( c2=='q' && strncmp(azArg[1],"quote",n2)==0 ){ p->mode = MODE_Quote; }else if( c2=='a' && strncmp(azArg[1],"ascii",n2)==0 ){ p->mode = MODE_Ascii; sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Unit); sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Record); }else if( nArg==1 ){ raw_printf(p->out, "current output mode: %s\n", modeDescr[p->mode]); }else{ raw_printf(stderr, "Error: mode should be one of: " | > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | | | | > > | > > | > > | > > > > > > < | > > > > > > > | | | | > > > > > > | < > | | < | > > | > > > > > > > > > > | | | | < > > | > > > > | > > > > > > < < > | > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | > > > > > > > > > | 8856 8857 8858 8859 8860 8861 8862 8863 8864 8865 8866 8867 8868 8869 8870 8871 8872 8873 8874 8875 8876 8877 8878 8879 8880 8881 8882 8883 8884 8885 8886 8887 8888 8889 8890 8891 8892 8893 8894 8895 8896 8897 8898 8899 8900 8901 8902 8903 8904 8905 8906 8907 8908 8909 8910 8911 8912 8913 8914 8915 8916 8917 8918 8919 8920 8921 8922 8923 8924 8925 8926 8927 8928 8929 8930 8931 8932 8933 8934 8935 8936 8937 8938 8939 8940 8941 8942 8943 8944 8945 8946 8947 8948 8949 8950 8951 8952 8953 8954 8955 8956 8957 8958 8959 8960 8961 8962 8963 8964 8965 8966 8967 8968 8969 8970 8971 8972 8973 8974 8975 8976 8977 8978 8979 8980 8981 8982 8983 8984 8985 8986 8987 8988 8989 8990 8991 8992 8993 8994 8995 8996 8997 8998 8999 9000 9001 9002 9003 9004 9005 9006 9007 9008 9009 9010 9011 9012 9013 9014 9015 9016 9017 9018 9019 9020 9021 9022 9023 9024 9025 9026 9027 9028 9029 9030 9031 9032 9033 9034 9035 9036 9037 9038 9039 9040 9041 9042 9043 9044 9045 9046 9047 9048 9049 9050 9051 9052 9053 9054 9055 9056 9057 9058 9059 9060 9061 9062 9063 9064 9065 9066 9067 9068 9069 9070 9071 9072 9073 9074 9075 9076 9077 9078 9079 9080 9081 9082 9083 9084 9085 9086 9087 9088 9089 9090 9091 9092 9093 9094 9095 9096 9097 9098 9099 9100 9101 9102 9103 9104 9105 9106 9107 9108 9109 9110 9111 9112 9113 9114 9115 9116 9117 9118 9119 9120 9121 9122 9123 9124 9125 9126 9127 9128 9129 9130 9131 9132 9133 9134 9135 9136 9137 9138 9139 9140 9141 9142 9143 9144 9145 9146 9147 9148 9149 9150 9151 9152 9153 9154 9155 9156 9157 9158 9159 9160 9161 9162 9163 9164 9165 9166 9167 9168 9169 9170 9171 9172 9173 9174 9175 9176 9177 9178 9179 9180 9181 9182 9183 9184 9185 9186 9187 9188 9189 9190 9191 9192 9193 9194 9195 9196 9197 9198 9199 9200 9201 9202 9203 9204 9205 9206 9207 9208 9209 9210 9211 9212 9213 9214 9215 9216 9217 9218 9219 9220 9221 9222 9223 9224 9225 9226 9227 9228 9229 9230 9231 9232 9233 9234 9235 9236 9237 9238 9239 9240 9241 9242 9243 9244 9245 9246 9247 9248 9249 9250 9251 9252 9253 9254 9255 9256 9257 9258 9259 9260 9261 9262 9263 9264 9265 9266 9267 9268 9269 9270 9271 9272 9273 9274 9275 9276 9277 9278 9279 9280 9281 9282 9283 9284 9285 9286 9287 9288 9289 9290 9291 9292 9293 9294 9295 9296 9297 9298 9299 9300 9301 9302 9303 9304 9305 9306 9307 9308 9309 9310 9311 9312 9313 9314 9315 9316 9317 9318 9319 9320 9321 9322 9323 9324 9325 9326 9327 9328 9329 9330 9331 9332 9333 9334 9335 9336 9337 9338 9339 9340 9341 9342 9343 9344 9345 | p->mode = MODE_List; sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Tab); }else if( c2=='i' && strncmp(azArg[1],"insert",n2)==0 ){ p->mode = MODE_Insert; set_table_name(p, nArg>=3 ? azArg[2] : "table"); }else if( c2=='q' && strncmp(azArg[1],"quote",n2)==0 ){ p->mode = MODE_Quote; sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Comma); sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row); }else if( c2=='a' && strncmp(azArg[1],"ascii",n2)==0 ){ p->mode = MODE_Ascii; sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Unit); sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Record); }else if( c2=='m' && strncmp(azArg[1],"markdown",n2)==0 ){ p->mode = MODE_Markdown; }else if( c2=='t' && strncmp(azArg[1],"table",n2)==0 ){ p->mode = MODE_Table; }else if( c2=='b' && strncmp(azArg[1],"box",n2)==0 ){ p->mode = MODE_Box; }else if( c2=='j' && strncmp(azArg[1],"json",n2)==0 ){ p->mode = MODE_Json; }else if( nArg==1 ){ raw_printf(p->out, "current output mode: %s\n", modeDescr[p->mode]); }else{ raw_printf(stderr, "Error: mode should be one of: " "ascii box column csv html insert json line list markdown " "quote table tabs tcl\n"); rc = 1; } p->cMode = p->mode; }else if( c=='n' && strcmp(azArg[0], "nonce")==0 ){ if( nArg!=2 ){ raw_printf(stderr, "Usage: .nonce NONCE\n"); rc = 1; }else if( p->zNonce==0 || strcmp(azArg[1],p->zNonce)!=0 ){ raw_printf(stderr, "line %d: incorrect nonce: \"%s\"\n", p->lineno, azArg[1]); exit(1); }else{ p->bSafeMode = 0; return 0; /* Return immediately to bypass the safe mode reset ** at the end of this procedure */ } }else if( c=='n' && strncmp(azArg[0], "nullvalue", n)==0 ){ if( nArg==2 ){ sqlite3_snprintf(sizeof(p->nullValue), p->nullValue, "%.*s", (int)ArraySize(p->nullValue)-1, azArg[1]); }else{ raw_printf(stderr, "Usage: .nullvalue STRING\n"); rc = 1; } }else #ifdef SQLITE_DEBUG if( c=='o' && strcmp(azArg[0],"oom")==0 ){ int i; for(i=1; i<nArg; i++){ const char *z = azArg[i]; if( z[0]=='-' && z[1]=='-' ) z++; if( strcmp(z,"-repeat")==0 ){ if( i==nArg-1 ){ raw_printf(p->out, "missing argument on \"%s\"\n", azArg[i]); rc = 1; }else{ oomRepeat = (int)integerValue(azArg[++i]); } }else if( IsDigit(z[0]) ){ oomCounter = (int)integerValue(azArg[i]); }else{ raw_printf(p->out, "unknown argument: \"%s\"\n", azArg[i]); raw_printf(p->out, "Usage: .oom [--repeat N] [M]\n"); rc = 1; } } if( rc==0 ){ raw_printf(p->out, "oomCounter = %d\n", oomCounter); raw_printf(p->out, "oomRepeat = %d\n", oomRepeat); } }else #endif /* SQLITE_DEBUG */ if( c=='o' && strncmp(azArg[0], "open", n)==0 && n>=2 ){ char *zNewFilename = 0; /* Name of the database file to open */ int iName = 1; /* Index in azArg[] of the filename */ int newFlag = 0; /* True to delete file before opening */ /* Close the existing database */ session_close_all(p, -1); close_db(p->db); p->db = 0; p->pAuxDb->zDbFilename = 0; sqlite3_free(p->pAuxDb->zFreeOnClose); p->pAuxDb->zFreeOnClose = 0; p->openMode = SHELL_OPEN_UNSPEC; p->openFlags = 0; p->szMax = 0; /* Check for command-line arguments */ for(iName=1; iName<nArg; iName++){ const char *z = azArg[iName]; if( optionMatch(z,"new") ){ newFlag = 1; #ifdef SQLITE_HAVE_ZLIB }else if( optionMatch(z, "zip") ){ p->openMode = SHELL_OPEN_ZIPFILE; #endif }else if( optionMatch(z, "append") ){ p->openMode = SHELL_OPEN_APPENDVFS; }else if( optionMatch(z, "readonly") ){ p->openMode = SHELL_OPEN_READONLY; }else if( optionMatch(z, "nofollow") ){ p->openFlags |= SQLITE_OPEN_NOFOLLOW; #ifndef SQLITE_OMIT_DESERIALIZE }else if( optionMatch(z, "deserialize") ){ p->openMode = SHELL_OPEN_DESERIALIZE; }else if( optionMatch(z, "hexdb") ){ p->openMode = SHELL_OPEN_HEXDB; }else if( optionMatch(z, "maxsize") && iName+1<nArg ){ p->szMax = integerValue(azArg[++iName]); #endif /* SQLITE_OMIT_DESERIALIZE */ }else if( z[0]=='-' ){ utf8_printf(stderr, "unknown option: %s\n", z); rc = 1; goto meta_command_exit; }else if( zNewFilename ){ utf8_printf(stderr, "extra argument: \"%s\"\n", z); rc = 1; goto meta_command_exit; }else{ zNewFilename = sqlite3_mprintf("%s", z); } } /* If a filename is specified, try to open it first */ if( zNewFilename || p->openMode==SHELL_OPEN_HEXDB ){ if( newFlag && !p->bSafeMode ) shellDeleteFile(zNewFilename); if( p->bSafeMode && p->openMode!=SHELL_OPEN_HEXDB && zNewFilename && strcmp(zNewFilename,":memory:")!=0 ){ failIfSafeMode(p, "cannot open disk-based database files in safe mode"); } p->pAuxDb->zDbFilename = zNewFilename; open_db(p, OPEN_DB_KEEPALIVE); if( p->db==0 ){ utf8_printf(stderr, "Error: cannot open '%s'\n", zNewFilename); sqlite3_free(zNewFilename); }else{ p->pAuxDb->zFreeOnClose = zNewFilename; } } if( p->db==0 ){ /* As a fall-back open a TEMP database */ p->pAuxDb->zDbFilename = 0; open_db(p, 0); } }else if( (c=='o' && (strncmp(azArg[0], "output", n)==0||strncmp(azArg[0], "once", n)==0)) || (c=='e' && n==5 && strcmp(azArg[0],"excel")==0) ){ char *zFile = 0; int bTxtMode = 0; int i; int eMode = 0; int bBOM = 0; int bOnce = 0; /* 0: .output, 1: .once, 2: .excel */ failIfSafeMode(p, "cannot run .%s in safe mode", azArg[0]); if( c=='e' ){ eMode = 'x'; bOnce = 2; }else if( strncmp(azArg[0],"once",n)==0 ){ bOnce = 1; } for(i=1; i<nArg; i++){ char *z = azArg[i]; if( z[0]=='-' ){ if( z[1]=='-' ) z++; if( strcmp(z,"-bom")==0 ){ bBOM = 1; }else if( c!='e' && strcmp(z,"-x")==0 ){ eMode = 'x'; /* spreadsheet */ }else if( c!='e' && strcmp(z,"-e")==0 ){ eMode = 'e'; /* text editor */ }else{ utf8_printf(p->out, "ERROR: unknown option: \"%s\". Usage:\n", azArg[i]); showHelp(p->out, azArg[0]); rc = 1; goto meta_command_exit; } }else if( zFile==0 && eMode!='e' && eMode!='x' ){ zFile = sqlite3_mprintf("%s", z); if( zFile[0]=='|' ){ while( i+1<nArg ) zFile = sqlite3_mprintf("%z %s", zFile, azArg[++i]); break; } }else{ utf8_printf(p->out,"ERROR: extra parameter: \"%s\". Usage:\n", azArg[i]); showHelp(p->out, azArg[0]); rc = 1; sqlite3_free(zFile); goto meta_command_exit; } } if( zFile==0 ) zFile = sqlite3_mprintf("stdout"); if( bOnce ){ p->outCount = 2; }else{ p->outCount = 0; } output_reset(p); #ifndef SQLITE_NOHAVE_SYSTEM if( eMode=='e' || eMode=='x' ){ p->doXdgOpen = 1; outputModePush(p); if( eMode=='x' ){ /* spreadsheet mode. Output as CSV. */ newTempFile(p, "csv"); ShellClearFlag(p, SHFLG_Echo); p->mode = MODE_Csv; sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Comma); sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_CrLf); }else{ /* text editor mode */ newTempFile(p, "txt"); bTxtMode = 1; } sqlite3_free(zFile); zFile = sqlite3_mprintf("%s", p->zTempFile); } #endif /* SQLITE_NOHAVE_SYSTEM */ if( zFile[0]=='|' ){ #ifdef SQLITE_OMIT_POPEN raw_printf(stderr, "Error: pipes are not supported in this OS\n"); rc = 1; p->out = stdout; #else p->out = popen(zFile + 1, "w"); if( p->out==0 ){ utf8_printf(stderr,"Error: cannot open pipe \"%s\"\n", zFile + 1); p->out = stdout; rc = 1; }else{ if( bBOM ) fprintf(p->out,"\357\273\277"); sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", zFile); } #endif }else{ p->out = output_file_open(zFile, bTxtMode); if( p->out==0 ){ if( strcmp(zFile,"off")!=0 ){ utf8_printf(stderr,"Error: cannot write to \"%s\"\n", zFile); } p->out = stdout; rc = 1; } else { if( bBOM ) fprintf(p->out,"\357\273\277"); sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", zFile); } } sqlite3_free(zFile); }else if( c=='p' && n>=3 && strncmp(azArg[0], "parameter", n)==0 ){ open_db(p,0); if( nArg<=1 ) goto parameter_syntax_error; /* .parameter clear ** Clear all bind parameters by dropping the TEMP table that holds them. */ if( nArg==2 && strcmp(azArg[1],"clear")==0 ){ sqlite3_exec(p->db, "DROP TABLE IF EXISTS temp.sqlite_parameters;", 0, 0, 0); }else /* .parameter list ** List all bind parameters. */ if( nArg==2 && strcmp(azArg[1],"list")==0 ){ sqlite3_stmt *pStmt = 0; int rx; int len = 0; rx = sqlite3_prepare_v2(p->db, "SELECT max(length(key)) " "FROM temp.sqlite_parameters;", -1, &pStmt, 0); if( rx==SQLITE_OK && sqlite3_step(pStmt)==SQLITE_ROW ){ len = sqlite3_column_int(pStmt, 0); if( len>40 ) len = 40; } sqlite3_finalize(pStmt); pStmt = 0; if( len ){ rx = sqlite3_prepare_v2(p->db, "SELECT key, quote(value) " "FROM temp.sqlite_parameters;", -1, &pStmt, 0); while( rx==SQLITE_OK && sqlite3_step(pStmt)==SQLITE_ROW ){ utf8_printf(p->out, "%-*s %s\n", len, sqlite3_column_text(pStmt,0), sqlite3_column_text(pStmt,1)); } sqlite3_finalize(pStmt); } }else /* .parameter init ** Make sure the TEMP table used to hold bind parameters exists. ** Create it if necessary. */ if( nArg==2 && strcmp(azArg[1],"init")==0 ){ bind_table_init(p); }else /* .parameter set NAME VALUE ** Set or reset a bind parameter. NAME should be the full parameter ** name exactly as it appears in the query. (ex: $abc, @def). The ** VALUE can be in either SQL literal notation, or if not it will be ** understood to be a text string. */ if( nArg==4 && strcmp(azArg[1],"set")==0 ){ int rx; char *zSql; sqlite3_stmt *pStmt; const char *zKey = azArg[2]; const char *zValue = azArg[3]; bind_table_init(p); zSql = sqlite3_mprintf( "REPLACE INTO temp.sqlite_parameters(key,value)" "VALUES(%Q,%s);", zKey, zValue); if( zSql==0 ) shell_out_of_memory(); pStmt = 0; rx = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); sqlite3_free(zSql); if( rx!=SQLITE_OK ){ sqlite3_finalize(pStmt); pStmt = 0; zSql = sqlite3_mprintf( "REPLACE INTO temp.sqlite_parameters(key,value)" "VALUES(%Q,%Q);", zKey, zValue); if( zSql==0 ) shell_out_of_memory(); rx = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); sqlite3_free(zSql); if( rx!=SQLITE_OK ){ utf8_printf(p->out, "Error: %s\n", sqlite3_errmsg(p->db)); sqlite3_finalize(pStmt); pStmt = 0; rc = 1; } } sqlite3_step(pStmt); sqlite3_finalize(pStmt); }else /* .parameter unset NAME ** Remove the NAME binding from the parameter binding table, if it ** exists. */ if( nArg==3 && strcmp(azArg[1],"unset")==0 ){ char *zSql = sqlite3_mprintf( "DELETE FROM temp.sqlite_parameters WHERE key=%Q", azArg[2]); if( zSql==0 ) shell_out_of_memory(); sqlite3_exec(p->db, zSql, 0, 0, 0); sqlite3_free(zSql); }else /* If no command name matches, show a syntax error */ parameter_syntax_error: showHelp(p->out, "parameter"); }else if( c=='p' && n>=3 && strncmp(azArg[0], "print", n)==0 ){ int i; for(i=1; i<nArg; i++){ if( i>1 ) raw_printf(p->out, " "); utf8_printf(p->out, "%s", azArg[i]); } raw_printf(p->out, "\n"); }else #ifndef SQLITE_OMIT_PROGRESS_CALLBACK if( c=='p' && n>=3 && strncmp(azArg[0], "progress", n)==0 ){ int i; int nn = 0; p->flgProgress = 0; p->mxProgress = 0; p->nProgress = 0; for(i=1; i<nArg; i++){ const char *z = azArg[i]; if( z[0]=='-' ){ z++; if( z[0]=='-' ) z++; if( strcmp(z,"quiet")==0 || strcmp(z,"q")==0 ){ p->flgProgress |= SHELL_PROGRESS_QUIET; continue; } if( strcmp(z,"reset")==0 ){ p->flgProgress |= SHELL_PROGRESS_RESET; continue; } if( strcmp(z,"once")==0 ){ p->flgProgress |= SHELL_PROGRESS_ONCE; continue; } if( strcmp(z,"limit")==0 ){ if( i+1>=nArg ){ utf8_printf(stderr, "Error: missing argument on --limit\n"); rc = 1; goto meta_command_exit; }else{ p->mxProgress = (int)integerValue(azArg[++i]); } continue; } utf8_printf(stderr, "Error: unknown option: \"%s\"\n", azArg[i]); rc = 1; goto meta_command_exit; }else{ nn = (int)integerValue(z); } } open_db(p, 0); sqlite3_progress_handler(p->db, nn, progress_handler, p); }else #endif /* SQLITE_OMIT_PROGRESS_CALLBACK */ if( c=='p' && strncmp(azArg[0], "prompt", n)==0 ){ if( nArg >= 2) { strncpy(mainPrompt,azArg[1],(int)ArraySize(mainPrompt)-1); } if( nArg >= 3) { strncpy(continuePrompt,azArg[2],(int)ArraySize(continuePrompt)-1); } }else if( c=='q' && strncmp(azArg[0], "quit", n)==0 ){ rc = 2; }else if( c=='r' && n>=3 && strncmp(azArg[0], "read", n)==0 ){ FILE *inSaved = p->in; int savedLineno = p->lineno; failIfSafeMode(p, "cannot run .read in safe mode"); if( nArg!=2 ){ raw_printf(stderr, "Usage: .read FILE\n"); rc = 1; goto meta_command_exit; } if( azArg[1][0]=='|' ){ #ifdef SQLITE_OMIT_POPEN raw_printf(stderr, "Error: pipes are not supported in this OS\n"); rc = 1; p->out = stdout; #else p->in = popen(azArg[1]+1, "r"); if( p->in==0 ){ utf8_printf(stderr, "Error: cannot open \"%s\"\n", azArg[1]); rc = 1; }else{ rc = process_input(p); pclose(p->in); } #endif }else if( (p->in = openChrSource(azArg[1]))==0 ){ utf8_printf(stderr,"Error: cannot open \"%s\"\n", azArg[1]); rc = 1; }else{ rc = process_input(p); fclose(p->in); } p->in = inSaved; p->lineno = savedLineno; }else if( c=='r' && n>=3 && strncmp(azArg[0], "restore", n)==0 ){ const char *zSrcFile; const char *zDb; sqlite3 *pSrc; sqlite3_backup *pBackup; int nTimeout = 0; failIfSafeMode(p, "cannot run .restore in safe mode"); if( nArg==2 ){ zSrcFile = azArg[1]; zDb = "main"; }else if( nArg==3 ){ zSrcFile = azArg[2]; zDb = azArg[1]; }else{ |
︙ | ︙ | |||
7066 7067 7068 7069 7070 7071 7072 7073 7074 7075 7076 7077 7078 7079 7080 7081 7082 7083 7084 7085 7086 7087 | ShellText sSelect; ShellState data; char *zErrMsg = 0; const char *zDiv = "("; const char *zName = 0; int iSchema = 0; int bDebug = 0; int ii; open_db(p, 0); memcpy(&data, p, sizeof(data)); data.showHeader = 0; data.cMode = data.mode = MODE_Semi; initText(&sSelect); for(ii=1; ii<nArg; ii++){ if( optionMatch(azArg[ii],"indent") ){ data.cMode = data.mode = MODE_Pretty; }else if( optionMatch(azArg[ii],"debug") ){ bDebug = 1; }else if( zName==0 ){ zName = azArg[ii]; }else{ | > > > > > > > | | > | > > | | 9396 9397 9398 9399 9400 9401 9402 9403 9404 9405 9406 9407 9408 9409 9410 9411 9412 9413 9414 9415 9416 9417 9418 9419 9420 9421 9422 9423 9424 9425 9426 9427 9428 9429 9430 9431 9432 9433 9434 9435 9436 9437 9438 9439 9440 9441 9442 9443 9444 9445 9446 9447 9448 9449 9450 9451 | ShellText sSelect; ShellState data; char *zErrMsg = 0; const char *zDiv = "("; const char *zName = 0; int iSchema = 0; int bDebug = 0; int bNoSystemTabs = 0; int ii; open_db(p, 0); memcpy(&data, p, sizeof(data)); data.showHeader = 0; data.cMode = data.mode = MODE_Semi; initText(&sSelect); for(ii=1; ii<nArg; ii++){ if( optionMatch(azArg[ii],"indent") ){ data.cMode = data.mode = MODE_Pretty; }else if( optionMatch(azArg[ii],"debug") ){ bDebug = 1; }else if( optionMatch(azArg[ii],"nosys") ){ bNoSystemTabs = 1; }else if( azArg[ii][0]=='-' ){ utf8_printf(stderr, "Unknown option: \"%s\"\n", azArg[ii]); rc = 1; goto meta_command_exit; }else if( zName==0 ){ zName = azArg[ii]; }else{ raw_printf(stderr, "Usage: .schema ?--indent? ?--nosys? ?LIKE-PATTERN?\n"); rc = 1; goto meta_command_exit; } } if( zName!=0 ){ int isSchema = sqlite3_strlike(zName, "sqlite_master", '\\')==0 || sqlite3_strlike(zName, "sqlite_schema", '\\')==0 || sqlite3_strlike(zName,"sqlite_temp_master", '\\')==0 || sqlite3_strlike(zName,"sqlite_temp_schema", '\\')==0; if( isSchema ){ char *new_argv[2], *new_colv[2]; new_argv[0] = sqlite3_mprintf( "CREATE TABLE %s (\n" " type text,\n" " name text,\n" " tbl_name text,\n" " rootpage integer,\n" " sql text\n" ")", zName); new_argv[1] = 0; new_colv[0] = "sql"; new_colv[1] = 0; callback(&data, 1, new_argv, new_colv); sqlite3_free(new_argv[0]); } } |
︙ | ︙ | |||
7125 7126 7127 7128 7129 7130 7131 | const char *zDb = (const char*)sqlite3_column_text(pStmt, 0); char zScNum[30]; sqlite3_snprintf(sizeof(zScNum), zScNum, "%d", ++iSchema); appendText(&sSelect, zDiv, 0); zDiv = " UNION ALL "; appendText(&sSelect, "SELECT shell_add_schema(sql,", 0); if( sqlite3_stricmp(zDb, "main")!=0 ){ | | | | | | > > > > | < | > < > | | | | | | | 9465 9466 9467 9468 9469 9470 9471 9472 9473 9474 9475 9476 9477 9478 9479 9480 9481 9482 9483 9484 9485 9486 9487 9488 9489 9490 9491 9492 9493 9494 9495 9496 9497 9498 9499 9500 9501 9502 9503 9504 9505 9506 9507 9508 9509 9510 9511 9512 9513 9514 9515 9516 9517 9518 9519 9520 9521 9522 9523 9524 9525 9526 9527 9528 9529 9530 9531 9532 9533 9534 9535 9536 9537 9538 9539 9540 9541 9542 9543 9544 9545 9546 9547 9548 9549 9550 9551 9552 9553 9554 9555 9556 9557 9558 9559 9560 9561 9562 9563 9564 9565 9566 | const char *zDb = (const char*)sqlite3_column_text(pStmt, 0); char zScNum[30]; sqlite3_snprintf(sizeof(zScNum), zScNum, "%d", ++iSchema); appendText(&sSelect, zDiv, 0); zDiv = " UNION ALL "; appendText(&sSelect, "SELECT shell_add_schema(sql,", 0); if( sqlite3_stricmp(zDb, "main")!=0 ){ appendText(&sSelect, zDb, '\''); }else{ appendText(&sSelect, "NULL", 0); } appendText(&sSelect, ",name) AS sql, type, tbl_name, name, rowid,", 0); appendText(&sSelect, zScNum, 0); appendText(&sSelect, " AS snum, ", 0); appendText(&sSelect, zDb, '\''); appendText(&sSelect, " AS sname FROM ", 0); appendText(&sSelect, zDb, quoteChar(zDb)); appendText(&sSelect, ".sqlite_schema", 0); } sqlite3_finalize(pStmt); #ifndef SQLITE_OMIT_INTROSPECTION_PRAGMAS if( zName ){ appendText(&sSelect, " UNION ALL SELECT shell_module_schema(name)," " 'table', name, name, name, 9e+99, 'main' FROM pragma_module_list", 0); } #endif appendText(&sSelect, ") WHERE ", 0); if( zName ){ char *zQarg = sqlite3_mprintf("%Q", zName); int bGlob = strchr(zName, '*') != 0 || strchr(zName, '?') != 0 || strchr(zName, '[') != 0; if( strchr(zName, '.') ){ appendText(&sSelect, "lower(printf('%s.%s',sname,tbl_name))", 0); }else{ appendText(&sSelect, "lower(tbl_name)", 0); } appendText(&sSelect, bGlob ? " GLOB " : " LIKE ", 0); appendText(&sSelect, zQarg, 0); if( !bGlob ){ appendText(&sSelect, " ESCAPE '\\' ", 0); } appendText(&sSelect, " AND ", 0); sqlite3_free(zQarg); } if( bNoSystemTabs ){ appendText(&sSelect, "name NOT LIKE 'sqlite_%%' AND ", 0); } appendText(&sSelect, "sql IS NOT NULL" " ORDER BY snum, rowid", 0); if( bDebug ){ utf8_printf(p->out, "SQL: %s;\n", sSelect.z); }else{ rc = sqlite3_exec(p->db, sSelect.z, callback, &data, &zErrMsg); } freeText(&sSelect); } if( zErrMsg ){ utf8_printf(stderr,"Error: %s\n", zErrMsg); sqlite3_free(zErrMsg); rc = 1; }else if( rc != SQLITE_OK ){ raw_printf(stderr,"Error: querying schema information\n"); rc = 1; }else{ rc = 0; } }else if( c=='s' && n==11 && strncmp(azArg[0], "selecttrace", n)==0 ){ unsigned int x = nArg>=2 ? (unsigned int)integerValue(azArg[1]) : 0xffffffff; sqlite3_test_control(SQLITE_TESTCTRL_TRACEFLAGS, 1, &x); }else #if defined(SQLITE_ENABLE_SESSION) if( c=='s' && strncmp(azArg[0],"session",n)==0 && n>=3 ){ struct AuxDb *pAuxDb = p->pAuxDb; OpenSession *pSession = &pAuxDb->aSession[0]; char **azCmd = &azArg[1]; int iSes = 0; int nCmd = nArg - 1; int i; if( nArg<=1 ) goto session_syntax_error; open_db(p, 0); if( nArg>=3 ){ for(iSes=0; iSes<pAuxDb->nSession; iSes++){ if( strcmp(pAuxDb->aSession[iSes].zName, azArg[1])==0 ) break; } if( iSes<pAuxDb->nSession ){ pSession = &pAuxDb->aSession[iSes]; azCmd++; nCmd--; }else{ pSession = &pAuxDb->aSession[0]; iSes = 0; } } /* .session attach TABLE ** Invoke the sqlite3session_attach() interface to attach a particular ** table so that it is never filtered. |
︙ | ︙ | |||
7237 7238 7239 7240 7241 7242 7243 7244 7245 7246 7247 | /* .session changeset FILE ** .session patchset FILE ** Write a changeset or patchset into a file. The file is overwritten. */ if( strcmp(azCmd[0],"changeset")==0 || strcmp(azCmd[0],"patchset")==0 ){ FILE *out = 0; if( nCmd!=2 ) goto session_syntax_error; if( pSession->p==0 ) goto session_not_open; out = fopen(azCmd[1], "wb"); if( out==0 ){ | > | > | 9581 9582 9583 9584 9585 9586 9587 9588 9589 9590 9591 9592 9593 9594 9595 9596 9597 9598 9599 9600 9601 | /* .session changeset FILE ** .session patchset FILE ** Write a changeset or patchset into a file. The file is overwritten. */ if( strcmp(azCmd[0],"changeset")==0 || strcmp(azCmd[0],"patchset")==0 ){ FILE *out = 0; failIfSafeMode(p, "cannot run \".session %s\" in safe mode", azCmd[0]); if( nCmd!=2 ) goto session_syntax_error; if( pSession->p==0 ) goto session_not_open; out = fopen(azCmd[1], "wb"); if( out==0 ){ utf8_printf(stderr, "ERROR: cannot open \"%s\" for writing\n", azCmd[1]); }else{ int szChng; void *pChng; if( azCmd[0][0]=='c' ){ rc = sqlite3session_changeset(pSession->p, &szChng, &pChng); }else{ rc = sqlite3session_patchset(pSession->p, &szChng, &pChng); |
︙ | ︙ | |||
7269 7270 7271 7272 7273 7274 7275 | }else /* .session close ** Close the identified session */ if( strcmp(azCmd[0], "close")==0 ){ if( nCmd!=1 ) goto session_syntax_error; | | | | | | 9615 9616 9617 9618 9619 9620 9621 9622 9623 9624 9625 9626 9627 9628 9629 9630 9631 9632 9633 9634 9635 9636 9637 9638 9639 9640 9641 9642 9643 9644 9645 9646 9647 9648 9649 9650 9651 9652 9653 9654 9655 | }else /* .session close ** Close the identified session */ if( strcmp(azCmd[0], "close")==0 ){ if( nCmd!=1 ) goto session_syntax_error; if( pAuxDb->nSession ){ session_close(pSession); pAuxDb->aSession[iSes] = pAuxDb->aSession[--pAuxDb->nSession]; } }else /* .session enable ?BOOLEAN? ** Query or set the enable flag */ if( strcmp(azCmd[0], "enable")==0 ){ int ii; if( nCmd>2 ) goto session_syntax_error; ii = nCmd==1 ? -1 : booleanValue(azCmd[1]); if( pAuxDb->nSession ){ ii = sqlite3session_enable(pSession->p, ii); utf8_printf(p->out, "session %s enable flag = %d\n", pSession->zName, ii); } }else /* .session filter GLOB .... ** Set a list of GLOB patterns of table names to be excluded. */ if( strcmp(azCmd[0], "filter")==0 ){ int ii, nByte; if( nCmd<2 ) goto session_syntax_error; if( pAuxDb->nSession ){ for(ii=0; ii<pSession->nFilter; ii++){ sqlite3_free(pSession->azFilter[ii]); } sqlite3_free(pSession->azFilter); nByte = sizeof(pSession->azFilter[0])*(nCmd-1); pSession->azFilter = sqlite3_malloc( nByte ); if( pSession->azFilter==0 ){ |
︙ | ︙ | |||
7320 7321 7322 7323 7324 7325 7326 | /* .session indirect ?BOOLEAN? ** Query or set the indirect flag */ if( strcmp(azCmd[0], "indirect")==0 ){ int ii; if( nCmd>2 ) goto session_syntax_error; ii = nCmd==1 ? -1 : booleanValue(azCmd[1]); | | | | | | | | | | | | 9666 9667 9668 9669 9670 9671 9672 9673 9674 9675 9676 9677 9678 9679 9680 9681 9682 9683 9684 9685 9686 9687 9688 9689 9690 9691 9692 9693 9694 9695 9696 9697 9698 9699 9700 9701 9702 9703 9704 9705 9706 9707 9708 9709 9710 9711 9712 9713 9714 9715 9716 9717 9718 9719 9720 9721 9722 9723 9724 9725 9726 9727 9728 9729 9730 9731 9732 9733 9734 9735 9736 9737 | /* .session indirect ?BOOLEAN? ** Query or set the indirect flag */ if( strcmp(azCmd[0], "indirect")==0 ){ int ii; if( nCmd>2 ) goto session_syntax_error; ii = nCmd==1 ? -1 : booleanValue(azCmd[1]); if( pAuxDb->nSession ){ ii = sqlite3session_indirect(pSession->p, ii); utf8_printf(p->out, "session %s indirect flag = %d\n", pSession->zName, ii); } }else /* .session isempty ** Determine if the session is empty */ if( strcmp(azCmd[0], "isempty")==0 ){ int ii; if( nCmd!=1 ) goto session_syntax_error; if( pAuxDb->nSession ){ ii = sqlite3session_isempty(pSession->p); utf8_printf(p->out, "session %s isempty flag = %d\n", pSession->zName, ii); } }else /* .session list ** List all currently open sessions */ if( strcmp(azCmd[0],"list")==0 ){ for(i=0; i<pAuxDb->nSession; i++){ utf8_printf(p->out, "%d %s\n", i, pAuxDb->aSession[i].zName); } }else /* .session open DB NAME ** Open a new session called NAME on the attached database DB. ** DB is normally "main". */ if( strcmp(azCmd[0],"open")==0 ){ char *zName; if( nCmd!=3 ) goto session_syntax_error; zName = azCmd[2]; if( zName[0]==0 ) goto session_syntax_error; for(i=0; i<pAuxDb->nSession; i++){ if( strcmp(pAuxDb->aSession[i].zName,zName)==0 ){ utf8_printf(stderr, "Session \"%s\" already exists\n", zName); goto meta_command_exit; } } if( pAuxDb->nSession>=ArraySize(pAuxDb->aSession) ){ raw_printf(stderr, "Maximum of %d sessions\n", ArraySize(pAuxDb->aSession)); goto meta_command_exit; } pSession = &pAuxDb->aSession[pAuxDb->nSession]; rc = sqlite3session_create(p->db, azCmd[1], &pSession->p); if( rc ){ raw_printf(stderr, "Cannot open session: error code=%d\n", rc); rc = 0; goto meta_command_exit; } pSession->nFilter = 0; sqlite3session_table_filter(pSession->p, session_filter, pSession); pAuxDb->nSession++; pSession->zName = sqlite3_mprintf("%s", zName); }else /* If no command name matches, show a syntax error */ session_syntax_error: showHelp(p->out, "session"); }else #endif |
︙ | ︙ | |||
7562 7563 7564 7565 7566 7567 7568 | }else if( strcmp(z,"debug")==0 ){ bDebug = 1; }else { utf8_printf(stderr, "Unknown option \"%s\" on \"%s\"\n", azArg[i], azArg[0]); | | < | | | | | | < | 9908 9909 9910 9911 9912 9913 9914 9915 9916 9917 9918 9919 9920 9921 9922 9923 9924 9925 9926 9927 9928 9929 9930 9931 9932 9933 9934 9935 9936 9937 9938 9939 9940 9941 9942 9943 9944 9945 9946 9947 9948 9949 9950 9951 9952 9953 9954 9955 9956 9957 9958 9959 9960 9961 9962 9963 9964 9965 9966 9967 9968 | }else if( strcmp(z,"debug")==0 ){ bDebug = 1; }else { utf8_printf(stderr, "Unknown option \"%s\" on \"%s\"\n", azArg[i], azArg[0]); showHelp(p->out, azArg[0]); rc = 1; goto meta_command_exit; } }else if( zLike ){ raw_printf(stderr, "Usage: .sha3sum ?OPTIONS? ?LIKE-PATTERN?\n"); rc = 1; goto meta_command_exit; }else{ zLike = z; bSeparate = 1; if( sqlite3_strlike("sqlite\\_%", zLike, '\\')==0 ) bSchema = 1; } } if( bSchema ){ zSql = "SELECT lower(name) FROM sqlite_schema" " WHERE type='table' AND coalesce(rootpage,0)>1" " UNION ALL SELECT 'sqlite_schema'" " ORDER BY 1 collate nocase"; }else{ zSql = "SELECT lower(name) FROM sqlite_schema" " WHERE type='table' AND coalesce(rootpage,0)>1" " AND name NOT LIKE 'sqlite_%'" " ORDER BY 1 collate nocase"; } sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); initText(&sQuery); initText(&sSql); appendText(&sSql, "WITH [sha3sum$query](a,b) AS(",0); zSep = "VALUES("; while( SQLITE_ROW==sqlite3_step(pStmt) ){ const char *zTab = (const char*)sqlite3_column_text(pStmt,0); if( zLike && sqlite3_strlike(zLike, zTab, 0)!=0 ) continue; if( strncmp(zTab, "sqlite_",7)!=0 ){ appendText(&sQuery,"SELECT * FROM ", 0); appendText(&sQuery,zTab,'"'); appendText(&sQuery," NOT INDEXED;", 0); }else if( strcmp(zTab, "sqlite_schema")==0 ){ appendText(&sQuery,"SELECT type,name,tbl_name,sql FROM sqlite_schema" " ORDER BY name;", 0); }else if( strcmp(zTab, "sqlite_sequence")==0 ){ appendText(&sQuery,"SELECT name,seq FROM sqlite_sequence" " ORDER BY name;", 0); }else if( strcmp(zTab, "sqlite_stat1")==0 ){ appendText(&sQuery,"SELECT tbl,idx,stat FROM sqlite_stat1" " ORDER BY tbl,idx;", 0); }else if( strcmp(zTab, "sqlite_stat4")==0 ){ appendText(&sQuery, "SELECT * FROM ", 0); appendText(&sQuery, zTab, 0); appendText(&sQuery, " ORDER BY tbl, idx, rowid;\n", 0); } appendText(&sSql, zSep, 0); appendText(&sSql, sQuery.z, '\''); sQuery.n = 0; |
︙ | ︙ | |||
7652 7653 7654 7655 7656 7657 7658 7659 7660 7661 7662 7663 7664 7665 7666 7667 7668 7669 7670 7671 7672 7673 7674 7675 7676 7677 7678 7679 7680 7681 7682 7683 | #ifndef SQLITE_NOHAVE_SYSTEM if( c=='s' && (strncmp(azArg[0], "shell", n)==0 || strncmp(azArg[0],"system",n)==0) ){ char *zCmd; int i, x; if( nArg<2 ){ raw_printf(stderr, "Usage: .system COMMAND\n"); rc = 1; goto meta_command_exit; } zCmd = sqlite3_mprintf(strchr(azArg[1],' ')==0?"%s":"\"%s\"", azArg[1]); for(i=2; i<nArg; i++){ zCmd = sqlite3_mprintf(strchr(azArg[i],' ')==0?"%z %s":"%z \"%s\"", zCmd, azArg[i]); } x = system(zCmd); sqlite3_free(zCmd); if( x ) raw_printf(stderr, "System command returns %d\n", x); }else #endif /* !defined(SQLITE_NOHAVE_SYSTEM) */ if( c=='s' && strncmp(azArg[0], "show", n)==0 ){ static const char *azBool[] = { "off", "on", "trigger", "full"}; int i; if( nArg!=1 ){ raw_printf(stderr, "Usage: .show\n"); rc = 1; goto meta_command_exit; } utf8_printf(p->out, "%12.12s: %s\n","echo", | > > | 9996 9997 9998 9999 10000 10001 10002 10003 10004 10005 10006 10007 10008 10009 10010 10011 10012 10013 10014 10015 10016 10017 10018 10019 10020 10021 10022 10023 10024 10025 10026 10027 10028 10029 | #ifndef SQLITE_NOHAVE_SYSTEM if( c=='s' && (strncmp(azArg[0], "shell", n)==0 || strncmp(azArg[0],"system",n)==0) ){ char *zCmd; int i, x; failIfSafeMode(p, "cannot run .%s in safe mode", azArg[0]); if( nArg<2 ){ raw_printf(stderr, "Usage: .system COMMAND\n"); rc = 1; goto meta_command_exit; } zCmd = sqlite3_mprintf(strchr(azArg[1],' ')==0?"%s":"\"%s\"", azArg[1]); for(i=2; i<nArg; i++){ zCmd = sqlite3_mprintf(strchr(azArg[i],' ')==0?"%z %s":"%z \"%s\"", zCmd, azArg[i]); } x = system(zCmd); sqlite3_free(zCmd); if( x ) raw_printf(stderr, "System command returns %d\n", x); }else #endif /* !defined(SQLITE_NOHAVE_SYSTEM) */ if( c=='s' && strncmp(azArg[0], "show", n)==0 ){ static const char *azBool[] = { "off", "on", "trigger", "full"}; const char *zOut; int i; if( nArg!=1 ){ raw_printf(stderr, "Usage: .show\n"); rc = 1; goto meta_command_exit; } utf8_printf(p->out, "%12.12s: %s\n","echo", |
︙ | ︙ | |||
7694 7695 7696 7697 7698 7699 7700 | strlen30(p->outfile) ? p->outfile : "stdout"); utf8_printf(p->out,"%12.12s: ", "colseparator"); output_c_string(p->out, p->colSeparator); raw_printf(p->out, "\n"); utf8_printf(p->out,"%12.12s: ", "rowseparator"); output_c_string(p->out, p->rowSeparator); raw_printf(p->out, "\n"); | > > > > > > | | | > > > > > | > | | 10040 10041 10042 10043 10044 10045 10046 10047 10048 10049 10050 10051 10052 10053 10054 10055 10056 10057 10058 10059 10060 10061 10062 10063 10064 10065 10066 10067 10068 10069 10070 10071 10072 10073 10074 10075 10076 10077 10078 10079 10080 10081 10082 | strlen30(p->outfile) ? p->outfile : "stdout"); utf8_printf(p->out,"%12.12s: ", "colseparator"); output_c_string(p->out, p->colSeparator); raw_printf(p->out, "\n"); utf8_printf(p->out,"%12.12s: ", "rowseparator"); output_c_string(p->out, p->rowSeparator); raw_printf(p->out, "\n"); switch( p->statsOn ){ case 0: zOut = "off"; break; default: zOut = "on"; break; case 2: zOut = "stmt"; break; case 3: zOut = "vmstep"; break; } utf8_printf(p->out, "%12.12s: %s\n","stats", zOut); utf8_printf(p->out, "%12.12s: ", "width"); for (i=0;i<p->nWidth;i++) { raw_printf(p->out, "%d ", p->colWidth[i]); } raw_printf(p->out, "\n"); utf8_printf(p->out, "%12.12s: %s\n", "filename", p->pAuxDb->zDbFilename ? p->pAuxDb->zDbFilename : ""); }else if( c=='s' && strncmp(azArg[0], "stats", n)==0 ){ if( nArg==2 ){ if( strcmp(azArg[1],"stmt")==0 ){ p->statsOn = 2; }else if( strcmp(azArg[1],"vmstep")==0 ){ p->statsOn = 3; }else{ p->statsOn = (u8)booleanValue(azArg[1]); } }else if( nArg==1 ){ display_stats(p->db, p, 0); }else{ raw_printf(stderr, "Usage: .stats ?on|off|stmt|vmstep?\n"); rc = 1; } }else if( (c=='t' && n>1 && strncmp(azArg[0], "tables", n)==0) || (c=='i' && (strncmp(azArg[0], "indices", n)==0 || strncmp(azArg[0], "indexes", n)==0) ) |
︙ | ︙ | |||
7753 7754 7755 7756 7757 7758 7759 | appendText(&s, "SELECT name FROM ", 0); }else{ appendText(&s, "SELECT ", 0); appendText(&s, zDbName, '\''); appendText(&s, "||'.'||name FROM ", 0); } appendText(&s, zDbName, '"'); | | > | | > | 10111 10112 10113 10114 10115 10116 10117 10118 10119 10120 10121 10122 10123 10124 10125 10126 10127 10128 10129 10130 10131 10132 10133 10134 10135 10136 10137 10138 10139 | appendText(&s, "SELECT name FROM ", 0); }else{ appendText(&s, "SELECT ", 0); appendText(&s, zDbName, '\''); appendText(&s, "||'.'||name FROM ", 0); } appendText(&s, zDbName, '"'); appendText(&s, ".sqlite_schema ", 0); if( c=='t' ){ appendText(&s," WHERE type IN ('table','view')" " AND name NOT LIKE 'sqlite_%'" " AND name LIKE ?1", 0); }else{ appendText(&s," WHERE type='index'" " AND tbl_name LIKE ?1", 0); } } rc = sqlite3_finalize(pStmt); if( rc==SQLITE_OK ){ appendText(&s, " ORDER BY 1", 0); rc = sqlite3_prepare_v2(p->db, s.z, -1, &pStmt, 0); } freeText(&s); if( rc ) return shellDatabaseError(p->db); /* Run the SQL statement prepared by the above block. Store the results ** as an array of nul-terminated strings in azResult[]. */ nRow = nAlloc = 0; azResult = 0; |
︙ | ︙ | |||
7842 7843 7844 7845 7846 7847 7848 | #ifndef SQLITE_UNTESTABLE if( c=='t' && n>=8 && strncmp(azArg[0], "testctrl", n)==0 ){ static const struct { const char *zCtrlName; /* Name of a test-control option */ int ctrlCode; /* Integer code for that option */ const char *zUsage; /* Usage notes */ } aCtrl[] = { | | | | | | > | | | | | | | | < | | | > > > | 10202 10203 10204 10205 10206 10207 10208 10209 10210 10211 10212 10213 10214 10215 10216 10217 10218 10219 10220 10221 10222 10223 10224 10225 10226 10227 10228 10229 10230 10231 10232 10233 10234 10235 10236 10237 | #ifndef SQLITE_UNTESTABLE if( c=='t' && n>=8 && strncmp(azArg[0], "testctrl", n)==0 ){ static const struct { const char *zCtrlName; /* Name of a test-control option */ int ctrlCode; /* Integer code for that option */ const char *zUsage; /* Usage notes */ } aCtrl[] = { { "always", SQLITE_TESTCTRL_ALWAYS, "BOOLEAN" }, { "assert", SQLITE_TESTCTRL_ASSERT, "BOOLEAN" }, /*{ "benign_malloc_hooks",SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS, "" },*/ /*{ "bitvec_test", SQLITE_TESTCTRL_BITVEC_TEST, "" },*/ { "byteorder", SQLITE_TESTCTRL_BYTEORDER, "" }, { "extra_schema_checks",SQLITE_TESTCTRL_EXTRA_SCHEMA_CHECKS,"BOOLEAN" }, /*{ "fault_install", SQLITE_TESTCTRL_FAULT_INSTALL, "" },*/ { "imposter", SQLITE_TESTCTRL_IMPOSTER, "SCHEMA ON/OFF ROOTPAGE"}, { "internal_functions", SQLITE_TESTCTRL_INTERNAL_FUNCTIONS, "" }, { "localtime_fault", SQLITE_TESTCTRL_LOCALTIME_FAULT,"BOOLEAN" }, { "never_corrupt", SQLITE_TESTCTRL_NEVER_CORRUPT, "BOOLEAN" }, { "optimizations", SQLITE_TESTCTRL_OPTIMIZATIONS, "DISABLE-MASK" }, #ifdef YYCOVERAGE { "parser_coverage", SQLITE_TESTCTRL_PARSER_COVERAGE, "" }, #endif { "pending_byte", SQLITE_TESTCTRL_PENDING_BYTE, "OFFSET " }, { "prng_restore", SQLITE_TESTCTRL_PRNG_RESTORE, "" }, { "prng_save", SQLITE_TESTCTRL_PRNG_SAVE, "" }, { "prng_seed", SQLITE_TESTCTRL_PRNG_SEED, "SEED ?db?" }, { "seek_count", SQLITE_TESTCTRL_SEEK_COUNT, "" }, { "sorter_mmap", SQLITE_TESTCTRL_SORTER_MMAP, "NMAX" }, { "tune", SQLITE_TESTCTRL_TUNE, "ID VALUE" }, }; int testctrl = -1; int iCtrl = -1; int rc2 = 0; /* 0: usage. 1: %d 2: %x 3: no-output */ int isOk = 0; int i, n2; const char *zCmd = 0; |
︙ | ︙ | |||
7913 7914 7915 7916 7917 7918 7919 | utf8_printf(stderr,"Error: unknown test-control: %s\n" "Use \".testctrl --help\" for help\n", zCmd); }else{ switch(testctrl){ /* sqlite3_test_control(int, db, int) */ case SQLITE_TESTCTRL_OPTIMIZATIONS: | < | < > > > > > > > > > > > > > > > > > > > > > < > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | 10276 10277 10278 10279 10280 10281 10282 10283 10284 10285 10286 10287 10288 10289 10290 10291 10292 10293 10294 10295 10296 10297 10298 10299 10300 10301 10302 10303 10304 10305 10306 10307 10308 10309 10310 10311 10312 10313 10314 10315 10316 10317 10318 10319 10320 10321 10322 10323 10324 10325 10326 10327 10328 10329 10330 10331 10332 10333 10334 10335 10336 10337 10338 10339 10340 10341 10342 10343 10344 10345 10346 10347 10348 10349 10350 10351 10352 10353 10354 10355 10356 10357 10358 10359 10360 10361 10362 10363 10364 10365 10366 10367 10368 10369 10370 10371 10372 10373 10374 10375 10376 10377 10378 10379 10380 10381 10382 10383 10384 10385 10386 10387 10388 10389 10390 10391 10392 10393 10394 10395 10396 10397 10398 10399 10400 10401 10402 10403 10404 10405 10406 10407 10408 10409 10410 10411 10412 10413 10414 10415 10416 10417 10418 10419 10420 10421 10422 10423 10424 10425 10426 10427 | utf8_printf(stderr,"Error: unknown test-control: %s\n" "Use \".testctrl --help\" for help\n", zCmd); }else{ switch(testctrl){ /* sqlite3_test_control(int, db, int) */ case SQLITE_TESTCTRL_OPTIMIZATIONS: if( nArg==3 ){ unsigned int opt = (unsigned int)strtol(azArg[2], 0, 0); rc2 = sqlite3_test_control(testctrl, p->db, opt); isOk = 3; } break; /* sqlite3_test_control(int) */ case SQLITE_TESTCTRL_PRNG_SAVE: case SQLITE_TESTCTRL_PRNG_RESTORE: case SQLITE_TESTCTRL_BYTEORDER: if( nArg==2 ){ rc2 = sqlite3_test_control(testctrl); isOk = testctrl==SQLITE_TESTCTRL_BYTEORDER ? 1 : 3; } break; /* sqlite3_test_control(int, uint) */ case SQLITE_TESTCTRL_PENDING_BYTE: if( nArg==3 ){ unsigned int opt = (unsigned int)integerValue(azArg[2]); rc2 = sqlite3_test_control(testctrl, opt); isOk = 3; } break; /* sqlite3_test_control(int, int, sqlite3*) */ case SQLITE_TESTCTRL_PRNG_SEED: if( nArg==3 || nArg==4 ){ int ii = (int)integerValue(azArg[2]); sqlite3 *db; if( ii==0 && strcmp(azArg[2],"random")==0 ){ sqlite3_randomness(sizeof(ii),&ii); printf("-- random seed: %d\n", ii); } if( nArg==3 ){ db = 0; }else{ db = p->db; /* Make sure the schema has been loaded */ sqlite3_table_column_metadata(db, 0, "x", 0, 0, 0, 0, 0, 0); } rc2 = sqlite3_test_control(testctrl, ii, db); isOk = 3; } break; /* sqlite3_test_control(int, int) */ case SQLITE_TESTCTRL_ASSERT: case SQLITE_TESTCTRL_ALWAYS: if( nArg==3 ){ int opt = booleanValue(azArg[2]); rc2 = sqlite3_test_control(testctrl, opt); isOk = 1; } break; /* sqlite3_test_control(int, int) */ case SQLITE_TESTCTRL_LOCALTIME_FAULT: case SQLITE_TESTCTRL_NEVER_CORRUPT: if( nArg==3 ){ int opt = booleanValue(azArg[2]); rc2 = sqlite3_test_control(testctrl, opt); isOk = 3; } break; /* sqlite3_test_control(sqlite3*) */ case SQLITE_TESTCTRL_INTERNAL_FUNCTIONS: rc2 = sqlite3_test_control(testctrl, p->db); isOk = 3; break; case SQLITE_TESTCTRL_IMPOSTER: if( nArg==5 ){ rc2 = sqlite3_test_control(testctrl, p->db, azArg[2], integerValue(azArg[3]), integerValue(azArg[4])); isOk = 3; } break; case SQLITE_TESTCTRL_SEEK_COUNT: { u64 x = 0; rc2 = sqlite3_test_control(testctrl, p->db, &x); utf8_printf(p->out, "%llu\n", x); isOk = 3; break; } #ifdef YYCOVERAGE case SQLITE_TESTCTRL_PARSER_COVERAGE: { if( nArg==2 ){ sqlite3_test_control(testctrl, p->out); isOk = 3; } break; } #endif #ifdef SQLITE_DEBUG case SQLITE_TESTCTRL_TUNE: { if( nArg==4 ){ int id = (int)integerValue(azArg[2]); int val = (int)integerValue(azArg[3]); sqlite3_test_control(testctrl, id, &val); isOk = 3; }else if( nArg==3 ){ int id = (int)integerValue(azArg[2]); sqlite3_test_control(testctrl, -id, &rc2); isOk = 1; }else if( nArg==2 ){ int id = 1; while(1){ int val = 0; rc2 = sqlite3_test_control(testctrl, -id, &val); if( rc2!=SQLITE_OK ) break; if( id>1 ) utf8_printf(p->out, " "); utf8_printf(p->out, "%d: %d", id, val); id++; } if( id>1 ) utf8_printf(p->out, "\n"); isOk = 3; } break; } #endif case SQLITE_TESTCTRL_SORTER_MMAP: if( nArg==3 ){ int opt = (unsigned int)integerValue(azArg[2]); rc2 = sqlite3_test_control(testctrl, p->db, opt); isOk = 3; } break; } } if( isOk==0 && iCtrl>=0 ){ utf8_printf(p->out, "Usage: .testctrl %s %s\n", zCmd,aCtrl[iCtrl].zUsage); rc = 1; }else if( isOk==1 ){ raw_printf(p->out, "%d\n", rc2); }else if( isOk==2 ){ raw_printf(p->out, "0x%08x\n", rc2); } }else |
︙ | ︙ | |||
8059 8060 8061 8062 8063 8064 8065 8066 8067 8068 8069 8070 8071 8072 8073 8074 8075 8076 8077 8078 8079 8080 | sqlite3_trace_v2(p->db, 0, 0, 0); }else{ if( mType==0 ) mType = SQLITE_TRACE_STMT; sqlite3_trace_v2(p->db, mType, sql_trace_callback, p); } }else #endif /* !defined(SQLITE_OMIT_TRACE) */ #if SQLITE_USER_AUTHENTICATION if( c=='u' && strncmp(azArg[0], "user", n)==0 ){ if( nArg<2 ){ raw_printf(stderr, "Usage: .user SUBCOMMAND ...\n"); rc = 1; goto meta_command_exit; } open_db(p, 0); if( strcmp(azArg[1],"login")==0 ){ if( nArg!=4 ){ raw_printf(stderr, "Usage: .user login USER PASSWORD\n"); rc = 1; goto meta_command_exit; } | > > > > > > > > > > > > > > > > > > > > > > > > > | > | 10490 10491 10492 10493 10494 10495 10496 10497 10498 10499 10500 10501 10502 10503 10504 10505 10506 10507 10508 10509 10510 10511 10512 10513 10514 10515 10516 10517 10518 10519 10520 10521 10522 10523 10524 10525 10526 10527 10528 10529 10530 10531 10532 10533 10534 10535 10536 10537 10538 10539 10540 10541 10542 10543 10544 10545 | sqlite3_trace_v2(p->db, 0, 0, 0); }else{ if( mType==0 ) mType = SQLITE_TRACE_STMT; sqlite3_trace_v2(p->db, mType, sql_trace_callback, p); } }else #endif /* !defined(SQLITE_OMIT_TRACE) */ #if defined(SQLITE_DEBUG) && !defined(SQLITE_OMIT_VIRTUALTABLE) if( c=='u' && strncmp(azArg[0], "unmodule", n)==0 ){ int ii; int lenOpt; char *zOpt; if( nArg<2 ){ raw_printf(stderr, "Usage: .unmodule [--allexcept] NAME ...\n"); rc = 1; goto meta_command_exit; } open_db(p, 0); zOpt = azArg[1]; if( zOpt[0]=='-' && zOpt[1]=='-' && zOpt[2]!=0 ) zOpt++; lenOpt = (int)strlen(zOpt); if( lenOpt>=3 && strncmp(zOpt, "-allexcept",lenOpt)==0 ){ assert( azArg[nArg]==0 ); sqlite3_drop_modules(p->db, nArg>2 ? (const char**)(azArg+2) : 0); }else{ for(ii=1; ii<nArg; ii++){ sqlite3_create_module(p->db, azArg[ii], 0, 0); } } }else #endif #if SQLITE_USER_AUTHENTICATION if( c=='u' && strncmp(azArg[0], "user", n)==0 ){ if( nArg<2 ){ raw_printf(stderr, "Usage: .user SUBCOMMAND ...\n"); rc = 1; goto meta_command_exit; } open_db(p, 0); if( strcmp(azArg[1],"login")==0 ){ if( nArg!=4 ){ raw_printf(stderr, "Usage: .user login USER PASSWORD\n"); rc = 1; goto meta_command_exit; } rc = sqlite3_user_authenticate(p->db, azArg[2], azArg[3], strlen30(azArg[3])); if( rc ){ utf8_printf(stderr, "Authentication failed for user %s\n", azArg[2]); rc = 1; } }else if( strcmp(azArg[1],"add")==0 ){ if( nArg!=5 ){ raw_printf(stderr, "Usage: .user add USER PASSWORD ISADMIN\n"); |
︙ | ︙ | |||
8185 8186 8187 8188 8189 8190 8191 | if( zVfsName ){ utf8_printf(p->out, "%s\n", zVfsName); sqlite3_free(zVfsName); } } }else | < | > < > > > > | > | < < < > | < | > > > > | > > > > > < > > > > | > > > > | | > > > > > > > > > > > > > | > | | > > | < > | > > > > > > > | > > > > > > > > | > > | < > > > | > | | > > | > > > | > > > | | | | < | < | < > | > | 10642 10643 10644 10645 10646 10647 10648 10649 10650 10651 10652 10653 10654 10655 10656 10657 10658 10659 10660 10661 10662 10663 10664 10665 10666 10667 10668 10669 10670 10671 10672 10673 10674 10675 10676 10677 10678 10679 10680 10681 10682 10683 10684 10685 10686 10687 10688 10689 10690 10691 10692 10693 10694 10695 10696 10697 10698 10699 10700 10701 10702 10703 10704 10705 10706 10707 10708 10709 10710 10711 10712 10713 10714 10715 10716 10717 10718 10719 10720 10721 10722 10723 10724 10725 10726 10727 10728 10729 10730 10731 10732 10733 10734 10735 10736 10737 10738 10739 10740 10741 10742 10743 10744 10745 10746 10747 10748 10749 10750 10751 10752 10753 10754 10755 10756 10757 10758 10759 10760 10761 10762 10763 10764 10765 10766 10767 10768 10769 10770 10771 10772 10773 10774 10775 10776 10777 10778 10779 10780 10781 10782 10783 10784 10785 10786 10787 10788 10789 10790 10791 10792 | if( zVfsName ){ utf8_printf(p->out, "%s\n", zVfsName); sqlite3_free(zVfsName); } } }else if( c=='w' && strncmp(azArg[0], "wheretrace", n)==0 ){ unsigned int x = nArg>=2 ? (unsigned int)integerValue(azArg[1]) : 0xffffffff; sqlite3_test_control(SQLITE_TESTCTRL_TRACEFLAGS, 3, &x); }else if( c=='w' && strncmp(azArg[0], "width", n)==0 ){ int j; assert( nArg<=ArraySize(azArg) ); p->nWidth = nArg-1; p->colWidth = realloc(p->colWidth, (p->nWidth+1)*sizeof(int)*2); if( p->colWidth==0 && p->nWidth>0 ) shell_out_of_memory(); if( p->nWidth ) p->actualWidth = &p->colWidth[p->nWidth]; for(j=1; j<nArg; j++){ p->colWidth[j-1] = (int)integerValue(azArg[j]); } }else { utf8_printf(stderr, "Error: unknown command or invalid arguments: " " \"%s\". Enter \".help\" for help\n", azArg[0]); rc = 1; } meta_command_exit: if( p->outCount ){ p->outCount--; if( p->outCount==0 ) output_reset(p); } p->bSafeMode = p->bSafeModePersist; return rc; } /* Line scan result and intermediate states (supporting scan resumption) */ #ifndef CHAR_BIT # define CHAR_BIT 8 #endif typedef enum { QSS_HasDark = 1<<CHAR_BIT, QSS_EndingSemi = 2<<CHAR_BIT, QSS_CharMask = (1<<CHAR_BIT)-1, QSS_ScanMask = 3<<CHAR_BIT, QSS_Start = 0 } QuickScanState; #define QSS_SETV(qss, newst) ((newst) | ((qss) & QSS_ScanMask)) #define QSS_INPLAIN(qss) (((qss)&QSS_CharMask)==QSS_Start) #define QSS_PLAINWHITE(qss) (((qss)&~QSS_EndingSemi)==QSS_Start) #define QSS_PLAINDARK(qss) (((qss)&~QSS_EndingSemi)==QSS_HasDark) #define QSS_SEMITERM(qss) (((qss)&~QSS_HasDark)==QSS_EndingSemi) /* ** Scan line for classification to guide shell's handling. ** The scan is resumable for subsequent lines when prior ** return values are passed as the 2nd argument. */ static QuickScanState quickscan(char *zLine, QuickScanState qss){ char cin; char cWait = (char)qss; /* intentional narrowing loss */ if( cWait==0 ){ PlainScan: assert( cWait==0 ); while( (cin = *zLine++)!=0 ){ if( IsSpace(cin) ) continue; switch (cin){ case '-': if( *zLine!='-' ) break; while((cin = *++zLine)!=0 ) if( cin=='\n') goto PlainScan; return qss; case ';': qss |= QSS_EndingSemi; continue; case '/': if( *zLine=='*' ){ ++zLine; cWait = '*'; qss = QSS_SETV(qss, cWait); goto TermScan; } break; case '[': cin = ']'; /* fall thru */ case '`': case '\'': case '"': cWait = cin; qss = QSS_HasDark | cWait; goto TermScan; default: break; } qss = (qss & ~QSS_EndingSemi) | QSS_HasDark; } }else{ TermScan: while( (cin = *zLine++)!=0 ){ if( cin==cWait ){ switch( cWait ){ case '*': if( *zLine != '/' ) continue; ++zLine; cWait = 0; qss = QSS_SETV(qss, 0); goto PlainScan; case '`': case '\'': case '"': if(*zLine==cWait){ ++zLine; continue; } /* fall thru */ case ']': cWait = 0; qss = QSS_SETV(qss, 0); goto PlainScan; default: assert(0); } } } } return qss; } /* ** Return TRUE if the line typed in is an SQL command terminator other ** than a semi-colon. The SQL Server style "go" command is understood ** as is the Oracle "/". */ static int line_is_command_terminator(char *zLine){ while( IsSpace(zLine[0]) ){ zLine++; }; if( zLine[0]=='/' ) zLine += 1; /* Oracle */ else if ( ToLower(zLine[0])=='g' && ToLower(zLine[1])=='o' ) zLine += 2; /* SQL Server */ else return 0; return quickscan(zLine,QSS_Start)==QSS_Start; } /* ** We need a default sqlite3_complete() implementation to use in case ** the shell is compiled with SQLITE_OMIT_COMPLETE. The default assumes ** any arbitrary text is a complete SQL statement. This is not very ** user-friendly, but it does seem to work. |
︙ | ︙ | |||
8297 8298 8299 8300 8301 8302 8303 8304 8305 8306 8307 8308 8309 8310 8311 8312 8313 8314 8315 8316 8317 8318 8319 8320 8321 8322 8323 | */ static int runOneSqlLine(ShellState *p, char *zSql, FILE *in, int startline){ int rc; char *zErrMsg = 0; open_db(p, 0); if( ShellHasFlag(p,SHFLG_Backslash) ) resolve_backslashes(zSql); BEGIN_TIMER; rc = shell_exec(p, zSql, &zErrMsg); END_TIMER; if( rc || zErrMsg ){ char zPrefix[100]; if( in!=0 || !stdin_is_interactive ){ sqlite3_snprintf(sizeof(zPrefix), zPrefix, "Error: near line %d:", startline); }else{ sqlite3_snprintf(sizeof(zPrefix), zPrefix, "Error:"); } if( zErrMsg!=0 ){ utf8_printf(stderr, "%s %s\n", zPrefix, zErrMsg); sqlite3_free(zErrMsg); zErrMsg = 0; }else{ utf8_printf(stderr, "%s %s\n", zPrefix, sqlite3_errmsg(p->db)); } return 1; }else if( ShellHasFlag(p, SHFLG_CountChanges) ){ | > > > | | > < > > > > > > > | | > > > > < | < > | < < | > > | > | | 10814 10815 10816 10817 10818 10819 10820 10821 10822 10823 10824 10825 10826 10827 10828 10829 10830 10831 10832 10833 10834 10835 10836 10837 10838 10839 10840 10841 10842 10843 10844 10845 10846 10847 10848 10849 10850 10851 10852 10853 10854 10855 10856 10857 10858 10859 10860 10861 10862 10863 10864 10865 10866 10867 10868 10869 10870 10871 10872 10873 10874 10875 10876 10877 10878 10879 10880 10881 10882 10883 10884 10885 10886 10887 10888 10889 10890 10891 10892 10893 10894 10895 10896 10897 10898 10899 10900 10901 10902 10903 10904 10905 10906 10907 10908 10909 10910 10911 10912 10913 10914 10915 10916 10917 10918 10919 10920 10921 10922 10923 10924 10925 10926 10927 10928 10929 10930 10931 10932 10933 10934 10935 10936 10937 10938 10939 10940 10941 10942 10943 10944 10945 10946 10947 10948 10949 10950 10951 10952 10953 10954 10955 10956 | */ static int runOneSqlLine(ShellState *p, char *zSql, FILE *in, int startline){ int rc; char *zErrMsg = 0; open_db(p, 0); if( ShellHasFlag(p,SHFLG_Backslash) ) resolve_backslashes(zSql); if( p->flgProgress & SHELL_PROGRESS_RESET ) p->nProgress = 0; BEGIN_TIMER; rc = shell_exec(p, zSql, &zErrMsg); END_TIMER; if( rc || zErrMsg ){ char zPrefix[100]; if( in!=0 || !stdin_is_interactive ){ sqlite3_snprintf(sizeof(zPrefix), zPrefix, "Error: near line %d:", startline); }else{ sqlite3_snprintf(sizeof(zPrefix), zPrefix, "Error:"); } if( zErrMsg!=0 ){ utf8_printf(stderr, "%s %s\n", zPrefix, zErrMsg); sqlite3_free(zErrMsg); zErrMsg = 0; }else{ utf8_printf(stderr, "%s %s\n", zPrefix, sqlite3_errmsg(p->db)); } return 1; }else if( ShellHasFlag(p, SHFLG_CountChanges) ){ char zLineBuf[2000]; sqlite3_snprintf(sizeof(zLineBuf), zLineBuf, "changes: %lld total_changes: %lld", sqlite3_changes64(p->db), sqlite3_total_changes64(p->db)); raw_printf(p->out, "%s\n", zLineBuf); } return 0; } /* ** Read input from *in and process it. If *in==0 then input ** is interactive - the user is typing it it. Otherwise, input ** is coming from a file or device. A prompt is issued and history ** is saved only if input is interactive. An interrupt signal will ** cause this routine to exit immediately, unless input is interactive. ** ** Return the number of errors. */ static int process_input(ShellState *p){ char *zLine = 0; /* A single input line */ char *zSql = 0; /* Accumulated SQL text */ int nLine; /* Length of current line */ int nSql = 0; /* Bytes of zSql[] used */ int nAlloc = 0; /* Allocated zSql[] space */ int rc; /* Error code */ int errCnt = 0; /* Number of errors seen */ int startline = 0; /* Line number for start of current input */ QuickScanState qss = QSS_Start; /* Accumulated line status (so far) */ p->lineno = 0; while( errCnt==0 || !bail_on_error || (p->in==0 && stdin_is_interactive) ){ fflush(p->out); zLine = one_input_line(p->in, zLine, nSql>0); if( zLine==0 ){ /* End of input */ if( p->in==0 && stdin_is_interactive ) printf("\n"); break; } if( seenInterrupt ){ if( p->in!=0 ) break; seenInterrupt = 0; } p->lineno++; if( QSS_INPLAIN(qss) && line_is_command_terminator(zLine) && line_is_complete(zSql, nSql) ){ memcpy(zLine,";",2); } qss = quickscan(zLine, qss); if( QSS_PLAINWHITE(qss) && nSql==0 ){ if( ShellHasFlag(p, SHFLG_Echo) ) printf("%s\n", zLine); /* Just swallow single-line whitespace */ qss = QSS_Start; continue; } if( zLine && (zLine[0]=='.' || zLine[0]=='#') && nSql==0 ){ if( ShellHasFlag(p, SHFLG_Echo) ) printf("%s\n", zLine); if( zLine[0]=='.' ){ rc = do_meta_command(zLine, p); if( rc==2 ){ /* exit requested */ break; }else if( rc ){ errCnt++; } } qss = QSS_Start; continue; } /* No single-line dispositions remain; accumulate line(s). */ nLine = strlen30(zLine); if( nSql+nLine+2>=nAlloc ){ /* Grow buffer by half-again increments when big. */ nAlloc = nSql+(nSql>>1)+nLine+100; zSql = realloc(zSql, nAlloc); if( zSql==0 ) shell_out_of_memory(); } if( nSql==0 ){ int i; for(i=0; zLine[i] && IsSpace(zLine[i]); i++){} assert( nAlloc>0 && zSql!=0 ); memcpy(zSql, zLine+i, nLine+1-i); startline = p->lineno; nSql = nLine-i; }else{ zSql[nSql++] = '\n'; memcpy(zSql+nSql, zLine, nLine+1); nSql += nLine; } if( nSql && QSS_SEMITERM(qss) && sqlite3_complete(zSql) ){ errCnt += runOneSqlLine(p, zSql, p->in, startline); nSql = 0; if( p->outCount ){ output_reset(p); p->outCount = 0; }else{ clearTempFile(p); } p->bSafeMode = p->bSafeModePersist; qss = QSS_Start; }else if( nSql && QSS_PLAINWHITE(qss) ){ if( ShellHasFlag(p, SHFLG_Echo) ) printf("%s\n", zSql); nSql = 0; qss = QSS_Start; } } if( nSql && QSS_PLAINDARK(qss) ){ errCnt += runOneSqlLine(p, zSql, p->in, startline); } free(zSql); free(zLine); return errCnt>0; } |
︙ | ︙ | |||
8519 8520 8521 8522 8523 8524 8525 | sqliterc = zBuf; } p->in = fopen(sqliterc,"rb"); if( p->in ){ if( stdin_is_interactive ){ utf8_printf(stderr,"-- Loading resources from %s\n",sqliterc); } | | > > > > > > > > > > > > > > > > > > | 11050 11051 11052 11053 11054 11055 11056 11057 11058 11059 11060 11061 11062 11063 11064 11065 11066 11067 11068 11069 11070 11071 11072 11073 11074 11075 11076 11077 11078 11079 11080 11081 11082 11083 11084 11085 11086 11087 11088 11089 11090 11091 11092 11093 11094 11095 11096 11097 11098 11099 11100 11101 11102 11103 11104 11105 11106 11107 11108 11109 11110 11111 11112 11113 11114 11115 11116 11117 11118 11119 11120 11121 11122 11123 11124 11125 11126 11127 11128 11129 | sqliterc = zBuf; } p->in = fopen(sqliterc,"rb"); if( p->in ){ if( stdin_is_interactive ){ utf8_printf(stderr,"-- Loading resources from %s\n",sqliterc); } if( process_input(p) && bail_on_error ) exit(1); fclose(p->in); }else if( sqliterc_override!=0 ){ utf8_printf(stderr,"cannot open: \"%s\"\n", sqliterc); if( bail_on_error ) exit(1); } p->in = inSaved; p->lineno = savedLineno; sqlite3_free(zBuf); } /* ** Show available command line options */ static const char zOptions[] = #if defined(SQLITE_HAVE_ZLIB) && !defined(SQLITE_OMIT_VIRTUALTABLE) " -A ARGS... run \".archive ARGS\" and exit\n" #endif " -append append the database to the end of the file\n" " -ascii set output mode to 'ascii'\n" " -bail stop after hitting an error\n" " -batch force batch I/O\n" " -box set output mode to 'box'\n" " -column set output mode to 'column'\n" " -cmd COMMAND run \"COMMAND\" before reading stdin\n" " -csv set output mode to 'csv'\n" #if !defined(SQLITE_OMIT_DESERIALIZE) " -deserialize open the database using sqlite3_deserialize()\n" #endif " -echo print commands before execution\n" " -init FILENAME read/process named file\n" " -[no]header turn headers on or off\n" #if defined(SQLITE_ENABLE_MEMSYS3) || defined(SQLITE_ENABLE_MEMSYS5) " -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" " -json set output mode to 'json'\n" " -line set output mode to 'line'\n" " -list set output mode to 'list'\n" " -lookaside SIZE N use N entries of SZ bytes for lookaside memory\n" " -markdown set output mode to 'markdown'\n" #if !defined(SQLITE_OMIT_DESERIALIZE) " -maxsize N maximum size for a --deserialize database\n" #endif " -memtrace trace all memory allocations and deallocations\n" " -mmap N default mmap size set to N\n" #ifdef SQLITE_ENABLE_MULTIPLEX " -multiplex enable the multiplexor VFS\n" #endif " -newline SEP set output row separator. Default: '\\n'\n" " -nofollow refuse to open symbolic links to database files\n" " -nonce STRING set the safe-mode escape nonce\n" " -nullvalue TEXT set text string for NULL values. Default ''\n" " -pagecache SIZE N use N slots of SZ bytes each for page cache memory\n" " -quote set output mode to 'quote'\n" " -readonly open the database read-only\n" " -safe enable safe-mode\n" " -separator SEP set output column separator. Default: '|'\n" #ifdef SQLITE_ENABLE_SORTER_REFERENCES " -sorterref SIZE sorter references threshold size\n" #endif " -stats print memory stats before each finalize\n" " -table set output mode to 'table'\n" " -tabs set output mode to 'tabs'\n" " -version show SQLite version\n" " -vfs NAME use NAME as the default VFS\n" #ifdef SQLITE_ENABLE_VFSTRACE " -vfstrace enable tracing of all VFS calls\n" #endif #ifdef SQLITE_HAVE_ZLIB " -zip open the file as a ZIP Archive\n" |
︙ | ︙ | |||
8607 8608 8609 8610 8611 8612 8613 8614 8615 8616 8617 8618 8619 8620 8621 8622 8623 8624 8625 8626 8627 8628 8629 8630 8631 8632 8633 8634 8635 8636 8637 8638 8639 8640 8641 8642 8643 8644 8645 | /* ** Initialize the state information in data */ static void main_init(ShellState *data) { memset(data, 0, sizeof(*data)); data->normalMode = data->cMode = data->mode = MODE_List; data->autoExplain = 1; memcpy(data->colSeparator,SEP_Column, 2); memcpy(data->rowSeparator,SEP_Row, 2); data->showHeader = 0; data->shellFlgs = SHFLG_Lookaside; verify_uninitialized(); sqlite3_config(SQLITE_CONFIG_URI, 1); sqlite3_config(SQLITE_CONFIG_LOG, shellLog, data); sqlite3_config(SQLITE_CONFIG_MULTITHREAD); sqlite3_snprintf(sizeof(mainPrompt), mainPrompt,"sqlite> "); sqlite3_snprintf(sizeof(continuePrompt), continuePrompt," ...> "); } /* ** Output text to the console in a font that attracts extra attention. */ #ifdef _WIN32 static void printBold(const char *zText){ HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE); CONSOLE_SCREEN_BUFFER_INFO defaultScreenInfo; GetConsoleScreenBufferInfo(out, &defaultScreenInfo); SetConsoleTextAttribute(out, FOREGROUND_RED|FOREGROUND_INTENSITY ); printf("%s", zText); SetConsoleTextAttribute(out, defaultScreenInfo.wAttributes); } #else static void printBold(const char *zText){ printf("\033[1m%s\033[0m", zText); } #endif | > > > > > | 11156 11157 11158 11159 11160 11161 11162 11163 11164 11165 11166 11167 11168 11169 11170 11171 11172 11173 11174 11175 11176 11177 11178 11179 11180 11181 11182 11183 11184 11185 11186 11187 11188 11189 11190 11191 11192 11193 11194 11195 11196 11197 11198 11199 | /* ** Initialize the state information in data */ static void main_init(ShellState *data) { memset(data, 0, sizeof(*data)); data->normalMode = data->cMode = data->mode = MODE_List; data->autoExplain = 1; data->pAuxDb = &data->aAuxDb[0]; memcpy(data->colSeparator,SEP_Column, 2); memcpy(data->rowSeparator,SEP_Row, 2); data->showHeader = 0; data->shellFlgs = SHFLG_Lookaside; verify_uninitialized(); sqlite3_config(SQLITE_CONFIG_URI, 1); sqlite3_config(SQLITE_CONFIG_LOG, shellLog, data); sqlite3_config(SQLITE_CONFIG_MULTITHREAD); sqlite3_snprintf(sizeof(mainPrompt), mainPrompt,"sqlite> "); sqlite3_snprintf(sizeof(continuePrompt), continuePrompt," ...> "); } /* ** Output text to the console in a font that attracts extra attention. */ #ifdef _WIN32 static void printBold(const char *zText){ #if !SQLITE_OS_WINRT HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE); CONSOLE_SCREEN_BUFFER_INFO defaultScreenInfo; GetConsoleScreenBufferInfo(out, &defaultScreenInfo); SetConsoleTextAttribute(out, FOREGROUND_RED|FOREGROUND_INTENSITY ); #endif printf("%s", zText); #if !SQLITE_OS_WINRT SetConsoleTextAttribute(out, defaultScreenInfo.wAttributes); #endif } #else static void printBold(const char *zText){ printf("\033[1m%s\033[0m", zText); } #endif |
︙ | ︙ | |||
8653 8654 8655 8656 8657 8658 8659 | argv[0], argv[argc-1]); exit(1); } return argv[i]; } #ifndef SQLITE_SHELL_IS_UTF8 | | > | 11207 11208 11209 11210 11211 11212 11213 11214 11215 11216 11217 11218 11219 11220 11221 11222 | argv[0], argv[argc-1]); exit(1); } return argv[i]; } #ifndef SQLITE_SHELL_IS_UTF8 # if (defined(_WIN32) || defined(WIN32)) \ && (defined(_MSC_VER) || (defined(UNICODE) && defined(__GNUC__))) # define SQLITE_SHELL_IS_UTF8 (0) # else # define SQLITE_SHELL_IS_UTF8 (1) # endif #endif #if SQLITE_SHELL_IS_UTF8 |
︙ | ︙ | |||
8685 8686 8687 8688 8689 8690 8691 8692 8693 8694 8695 8696 8697 8698 8699 8700 8701 8702 8703 8704 8705 8706 8707 8708 8709 | int argcToFree = 0; #endif setBinaryMode(stdin, 0); setvbuf(stderr, 0, _IONBF, 0); /* Make sure stderr is unbuffered */ stdin_is_interactive = isatty(0); stdout_is_console = isatty(1); #if !defined(_WIN32_WCE) if( getenv("SQLITE_DEBUG_BREAK") ){ if( isatty(0) && isatty(2) ){ fprintf(stderr, "attach debugger to process %d and press any key to continue.\n", GETPID()); fgetc(stdin); }else{ #if defined(_WIN32) || defined(WIN32) DebugBreak(); #elif defined(SIGTRAP) raise(SIGTRAP); #endif } } #endif | > > > > > > > > | 11240 11241 11242 11243 11244 11245 11246 11247 11248 11249 11250 11251 11252 11253 11254 11255 11256 11257 11258 11259 11260 11261 11262 11263 11264 11265 11266 11267 11268 11269 11270 11271 11272 | int argcToFree = 0; #endif setBinaryMode(stdin, 0); setvbuf(stderr, 0, _IONBF, 0); /* Make sure stderr is unbuffered */ stdin_is_interactive = isatty(0); stdout_is_console = isatty(1); #ifdef SQLITE_DEBUG registerOomSimulator(); #endif #if !defined(_WIN32_WCE) if( getenv("SQLITE_DEBUG_BREAK") ){ if( isatty(0) && isatty(2) ){ fprintf(stderr, "attach debugger to process %d and press any key to continue.\n", GETPID()); fgetc(stdin); }else{ #if defined(_WIN32) || defined(WIN32) #if SQLITE_OS_WINRT __debugbreak(); #else DebugBreak(); #endif #elif defined(SIGTRAP) raise(SIGTRAP); #endif } } #endif |
︙ | ︙ | |||
8757 8758 8759 8760 8761 8762 8763 | #ifdef SQLITE_SHELL_DBNAME_PROC { /* If the SQLITE_SHELL_DBNAME_PROC macro is defined, then it is the name ** of a C-function that will provide the name of the database file. Use ** this compile-time option to embed this shell program in larger ** applications. */ extern void SQLITE_SHELL_DBNAME_PROC(const char**); | | | | | 11320 11321 11322 11323 11324 11325 11326 11327 11328 11329 11330 11331 11332 11333 11334 11335 11336 11337 11338 11339 11340 11341 11342 11343 11344 11345 11346 11347 11348 11349 11350 | #ifdef SQLITE_SHELL_DBNAME_PROC { /* If the SQLITE_SHELL_DBNAME_PROC macro is defined, then it is the name ** of a C-function that will provide the name of the database file. Use ** this compile-time option to embed this shell program in larger ** applications. */ extern void SQLITE_SHELL_DBNAME_PROC(const char**); SQLITE_SHELL_DBNAME_PROC(&data.pAuxDb->zDbFilename); warnInmemoryDb = 0; } #endif /* Do an initial pass through the command-line argument to locate ** the name of the database file, the name of the initialization file, ** the size of the alternative malloc heap, ** and the first command to execute. */ verify_uninitialized(); for(i=1; i<argc; i++){ char *z; z = argv[i]; if( z[0]!='-' ){ if( data.aAuxDb->zDbFilename==0 ){ data.aAuxDb->zDbFilename = z; }else{ /* Excesss arguments are interpreted as SQL (or dot-commands) and ** mean that nothing is read from stdin */ readStdin = 0; nCmd++; azCmd = realloc(azCmd, sizeof(azCmd[0])*nCmd); if( azCmd==0 ) shell_out_of_memory(); |
︙ | ︙ | |||
8812 8813 8814 8815 8816 8817 8818 | szHeap = integerValue(zSize); if( szHeap>0x7fff0000 ) szHeap = 0x7fff0000; sqlite3_config(SQLITE_CONFIG_HEAP, malloc((int)szHeap), (int)szHeap, 64); #else (void)cmdline_option_value(argc, argv, ++i); #endif }else if( strcmp(z,"-pagecache")==0 ){ | | | | > > > > > > > > > > > | 11375 11376 11377 11378 11379 11380 11381 11382 11383 11384 11385 11386 11387 11388 11389 11390 11391 11392 11393 11394 11395 11396 11397 11398 11399 11400 11401 11402 11403 11404 11405 11406 11407 11408 11409 11410 11411 11412 11413 11414 11415 | szHeap = integerValue(zSize); if( szHeap>0x7fff0000 ) szHeap = 0x7fff0000; sqlite3_config(SQLITE_CONFIG_HEAP, malloc((int)szHeap), (int)szHeap, 64); #else (void)cmdline_option_value(argc, argv, ++i); #endif }else if( strcmp(z,"-pagecache")==0 ){ sqlite3_int64 n, sz; sz = integerValue(cmdline_option_value(argc,argv,++i)); if( sz>70000 ) sz = 70000; if( sz<0 ) sz = 0; n = integerValue(cmdline_option_value(argc,argv,++i)); if( sz>0 && n>0 && 0xffffffffffffLL/sz<n ){ n = 0xffffffffffffLL/sz; } sqlite3_config(SQLITE_CONFIG_PAGECACHE, (n>0 && sz>0) ? malloc(n*sz) : 0, sz, n); data.shellFlgs |= SHFLG_Pagecache; }else if( strcmp(z,"-lookaside")==0 ){ int n, sz; sz = (int)integerValue(cmdline_option_value(argc,argv,++i)); if( sz<0 ) sz = 0; n = (int)integerValue(cmdline_option_value(argc,argv,++i)); if( n<0 ) n = 0; sqlite3_config(SQLITE_CONFIG_LOOKASIDE, sz, n); if( sz*n==0 ) data.shellFlgs &= ~SHFLG_Lookaside; }else if( strcmp(z,"-threadsafe")==0 ){ int n; n = (int)integerValue(cmdline_option_value(argc,argv,++i)); switch( n ){ case 0: sqlite3_config(SQLITE_CONFIG_SINGLETHREAD); break; case 2: sqlite3_config(SQLITE_CONFIG_MULTITHREAD); break; default: sqlite3_config(SQLITE_CONFIG_SERIALIZED); break; } #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, |
︙ | ︙ | |||
8860 8861 8862 8863 8864 8865 8866 | zVfs = cmdline_option_value(argc, argv, ++i); #ifdef SQLITE_HAVE_ZLIB }else if( strcmp(z,"-zip")==0 ){ data.openMode = SHELL_OPEN_ZIPFILE; #endif }else if( strcmp(z,"-append")==0 ){ data.openMode = SHELL_OPEN_APPENDVFS; | | > > > > > > > > > > > > > | 11434 11435 11436 11437 11438 11439 11440 11441 11442 11443 11444 11445 11446 11447 11448 11449 11450 11451 11452 11453 11454 11455 11456 11457 11458 11459 11460 11461 11462 11463 11464 11465 11466 11467 11468 11469 11470 11471 11472 | zVfs = cmdline_option_value(argc, argv, ++i); #ifdef SQLITE_HAVE_ZLIB }else if( strcmp(z,"-zip")==0 ){ data.openMode = SHELL_OPEN_ZIPFILE; #endif }else if( strcmp(z,"-append")==0 ){ data.openMode = SHELL_OPEN_APPENDVFS; #ifndef SQLITE_OMIT_DESERIALIZE }else if( strcmp(z,"-deserialize")==0 ){ data.openMode = SHELL_OPEN_DESERIALIZE; }else if( strcmp(z,"-maxsize")==0 && i+1<argc ){ data.szMax = integerValue(argv[++i]); #endif }else if( strcmp(z,"-readonly")==0 ){ data.openMode = SHELL_OPEN_READONLY; }else if( strcmp(z,"-nofollow")==0 ){ data.openFlags = SQLITE_OPEN_NOFOLLOW; #if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB) }else if( strncmp(z, "-A",2)==0 ){ /* All remaining command-line arguments are passed to the ".archive" ** command, so ignore them */ break; #endif }else if( strcmp(z, "-memtrace")==0 ){ sqlite3MemTraceActivate(stderr); }else if( strcmp(z,"-bail")==0 ){ bail_on_error = 1; }else if( strcmp(z,"-nonce")==0 ){ free(data.zNonce); data.zNonce = strdup(argv[++i]); }else if( strcmp(z,"-safe")==0 ){ /* no-op - catch this on the second pass */ } } verify_uninitialized(); #ifdef SQLITE_SHELL_INIT_PROC { |
︙ | ︙ | |||
8902 8903 8904 8905 8906 8907 8908 | sqlite3_vfs_register(pVfs, 1); }else{ utf8_printf(stderr, "no such VFS: \"%s\"\n", argv[i]); exit(1); } } | | | | | 11489 11490 11491 11492 11493 11494 11495 11496 11497 11498 11499 11500 11501 11502 11503 11504 11505 11506 11507 11508 11509 11510 11511 11512 11513 11514 11515 11516 11517 11518 11519 11520 | sqlite3_vfs_register(pVfs, 1); }else{ utf8_printf(stderr, "no such VFS: \"%s\"\n", argv[i]); exit(1); } } if( data.pAuxDb->zDbFilename==0 ){ #ifndef SQLITE_OMIT_MEMORYDB data.pAuxDb->zDbFilename = ":memory:"; warnInmemoryDb = argc==1; #else utf8_printf(stderr,"%s: Error: no database filename specified\n", Argv0); return 1; #endif } data.out = stdout; sqlite3_appendvfs_init(0,0,0); /* Go ahead and open the database file if it already exists. If the ** file does not exist, delay opening it. This prevents empty database ** files from being created if a user mistypes the database name argument ** to the sqlite command-line tool. */ if( access(data.pAuxDb->zDbFilename, 0)==0 ){ open_db(&data, 0); } /* Process the initialization file if there is one. If no -init option ** is given on the command line, look for a file named ~/.sqliterc and ** try to process it. */ |
︙ | ︙ | |||
8946 8947 8948 8949 8950 8951 8952 8953 8954 8955 8956 8957 8958 8959 8960 8961 8962 8963 8964 8965 | i++; }else if( strcmp(z,"-html")==0 ){ data.mode = MODE_Html; }else if( strcmp(z,"-list")==0 ){ data.mode = MODE_List; }else if( strcmp(z,"-quote")==0 ){ data.mode = MODE_Quote; }else if( strcmp(z,"-line")==0 ){ data.mode = MODE_Line; }else if( strcmp(z,"-column")==0 ){ data.mode = MODE_Column; }else if( strcmp(z,"-csv")==0 ){ data.mode = MODE_Csv; memcpy(data.colSeparator,",",2); #ifdef SQLITE_HAVE_ZLIB }else if( strcmp(z,"-zip")==0 ){ data.openMode = SHELL_OPEN_ZIPFILE; #endif }else if( strcmp(z,"-append")==0 ){ data.openMode = SHELL_OPEN_APPENDVFS; | > > > > > > > > > > | > > > > | < | > > > | > | > | > > > > > > | 11533 11534 11535 11536 11537 11538 11539 11540 11541 11542 11543 11544 11545 11546 11547 11548 11549 11550 11551 11552 11553 11554 11555 11556 11557 11558 11559 11560 11561 11562 11563 11564 11565 11566 11567 11568 11569 11570 11571 11572 11573 11574 11575 11576 11577 11578 11579 11580 11581 11582 11583 11584 11585 11586 11587 11588 11589 11590 11591 11592 11593 11594 11595 11596 11597 11598 11599 11600 11601 11602 11603 11604 11605 11606 11607 11608 11609 11610 11611 11612 11613 11614 11615 11616 11617 11618 11619 11620 11621 11622 11623 11624 11625 11626 11627 11628 11629 11630 11631 11632 11633 11634 11635 11636 11637 11638 11639 11640 11641 | i++; }else if( strcmp(z,"-html")==0 ){ data.mode = MODE_Html; }else if( strcmp(z,"-list")==0 ){ data.mode = MODE_List; }else if( strcmp(z,"-quote")==0 ){ data.mode = MODE_Quote; sqlite3_snprintf(sizeof(data.colSeparator), data.colSeparator, SEP_Comma); sqlite3_snprintf(sizeof(data.rowSeparator), data.rowSeparator, SEP_Row); }else if( strcmp(z,"-line")==0 ){ data.mode = MODE_Line; }else if( strcmp(z,"-column")==0 ){ data.mode = MODE_Column; }else if( strcmp(z,"-json")==0 ){ data.mode = MODE_Json; }else if( strcmp(z,"-markdown")==0 ){ data.mode = MODE_Markdown; }else if( strcmp(z,"-table")==0 ){ data.mode = MODE_Table; }else if( strcmp(z,"-box")==0 ){ data.mode = MODE_Box; }else if( strcmp(z,"-csv")==0 ){ data.mode = MODE_Csv; memcpy(data.colSeparator,",",2); #ifdef SQLITE_HAVE_ZLIB }else if( strcmp(z,"-zip")==0 ){ data.openMode = SHELL_OPEN_ZIPFILE; #endif }else if( strcmp(z,"-append")==0 ){ data.openMode = SHELL_OPEN_APPENDVFS; #ifndef SQLITE_OMIT_DESERIALIZE }else if( strcmp(z,"-deserialize")==0 ){ data.openMode = SHELL_OPEN_DESERIALIZE; }else if( strcmp(z,"-maxsize")==0 && i+1<argc ){ data.szMax = integerValue(argv[++i]); #endif }else if( strcmp(z,"-readonly")==0 ){ data.openMode = SHELL_OPEN_READONLY; }else if( strcmp(z,"-nofollow")==0 ){ data.openFlags |= SQLITE_OPEN_NOFOLLOW; }else if( strcmp(z,"-ascii")==0 ){ data.mode = MODE_Ascii; sqlite3_snprintf(sizeof(data.colSeparator), data.colSeparator, SEP_Unit); sqlite3_snprintf(sizeof(data.rowSeparator), data.rowSeparator, SEP_Record); }else if( strcmp(z,"-tabs")==0 ){ data.mode = MODE_List; sqlite3_snprintf(sizeof(data.colSeparator), data.colSeparator, SEP_Tab); sqlite3_snprintf(sizeof(data.rowSeparator), data.rowSeparator, SEP_Row); }else if( strcmp(z,"-separator")==0 ){ sqlite3_snprintf(sizeof(data.colSeparator), data.colSeparator, "%s",cmdline_option_value(argc,argv,++i)); }else if( strcmp(z,"-newline")==0 ){ sqlite3_snprintf(sizeof(data.rowSeparator), data.rowSeparator, "%s",cmdline_option_value(argc,argv,++i)); }else if( strcmp(z,"-nullvalue")==0 ){ sqlite3_snprintf(sizeof(data.nullValue), data.nullValue, "%s",cmdline_option_value(argc,argv,++i)); }else if( strcmp(z,"-header")==0 ){ data.showHeader = 1; ShellSetFlag(&data, SHFLG_HeaderSet); }else if( strcmp(z,"-noheader")==0 ){ data.showHeader = 0; ShellSetFlag(&data, SHFLG_HeaderSet); }else if( strcmp(z,"-echo")==0 ){ ShellSetFlag(&data, SHFLG_Echo); }else if( strcmp(z,"-eqp")==0 ){ data.autoEQP = AUTOEQP_on; }else if( strcmp(z,"-eqpfull")==0 ){ data.autoEQP = AUTOEQP_full; }else if( strcmp(z,"-stats")==0 ){ data.statsOn = 1; }else if( strcmp(z,"-scanstats")==0 ){ data.scanstatsOn = 1; }else if( strcmp(z,"-backslash")==0 ){ /* Undocumented command-line option: -backslash ** Causes C-style backslash escapes to be evaluated in SQL statements ** prior to sending the SQL into SQLite. Useful for injecting ** crazy bytes in the middle of SQL statements for testing and debugging. */ ShellSetFlag(&data, SHFLG_Backslash); }else if( strcmp(z,"-bail")==0 ){ /* No-op. The bail_on_error flag should already be set. */ }else if( strcmp(z,"-version")==0 ){ printf("%s %s\n", sqlite3_libversion(), sqlite3_sourceid()); 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,"-pagecache")==0 ){ i+=2; }else if( strcmp(z,"-lookaside")==0 ){ i+=2; }else if( strcmp(z,"-threadsafe")==0 ){ i+=2; }else if( strcmp(z,"-nonce")==0 ){ i += 2; }else if( strcmp(z,"-mmap")==0 ){ i++; }else if( strcmp(z,"-memtrace")==0 ){ i++; #ifdef SQLITE_ENABLE_SORTER_REFERENCES }else if( strcmp(z,"-sorterref")==0 ){ i++; #endif }else if( strcmp(z,"-vfs")==0 ){ i++; |
︙ | ︙ | |||
9072 9073 9074 9075 9076 9077 9078 9079 9080 9081 9082 9083 9084 9085 9086 9087 9088 9089 9090 9091 9092 9093 9094 | arDotCommand(&data, 1, argv+(i-1), argc-(i-1)); }else{ arDotCommand(&data, 1, argv+i, argc-i); } readStdin = 0; break; #endif }else{ utf8_printf(stderr,"%s: Error: unknown option: %s\n", Argv0, z); raw_printf(stderr,"Use -help for a list of options.\n"); return 1; } data.cMode = data.mode; } if( !readStdin ){ /* Run all arguments that do not begin with '-' as if they were separate ** command-line inputs, except for the argToSkip argument which contains ** the database filename. */ for(i=0; i<nCmd; i++){ if( azCmd[i][0]=='.' ){ rc = do_meta_command(azCmd[i], &data); | > > > > | > > | | < | | > > > | < | 11683 11684 11685 11686 11687 11688 11689 11690 11691 11692 11693 11694 11695 11696 11697 11698 11699 11700 11701 11702 11703 11704 11705 11706 11707 11708 11709 11710 11711 11712 11713 11714 11715 11716 11717 11718 11719 11720 11721 11722 11723 11724 11725 11726 11727 11728 11729 11730 11731 11732 11733 | arDotCommand(&data, 1, argv+(i-1), argc-(i-1)); }else{ arDotCommand(&data, 1, argv+i, argc-i); } readStdin = 0; break; #endif }else if( strcmp(z,"-safe")==0 ){ data.bSafeMode = data.bSafeModePersist = 1; }else{ utf8_printf(stderr,"%s: Error: unknown option: %s\n", Argv0, z); raw_printf(stderr,"Use -help for a list of options.\n"); return 1; } data.cMode = data.mode; } if( !readStdin ){ /* Run all arguments that do not begin with '-' as if they were separate ** command-line inputs, except for the argToSkip argument which contains ** the database filename. */ for(i=0; i<nCmd; i++){ if( azCmd[i][0]=='.' ){ rc = do_meta_command(azCmd[i], &data); if( rc ){ free(azCmd); return rc==2 ? 0 : rc; } }else{ open_db(&data, 0); rc = shell_exec(&data, azCmd[i], &zErrMsg); if( zErrMsg || rc ){ if( zErrMsg!=0 ){ utf8_printf(stderr,"Error: %s\n", zErrMsg); }else{ utf8_printf(stderr,"Error: unable to process SQL: %s\n", azCmd[i]); } sqlite3_free(zErrMsg); free(azCmd); return rc!=0 ? rc : 1; } } } }else{ /* Run commands received from standard input */ if( stdin_is_interactive ){ char *zHome; char *zHistory; int nHistory; |
︙ | ︙ | |||
9147 9148 9149 9150 9151 9152 9153 9154 9155 | free(zHistory); } }else{ data.in = stdin; rc = process_input(&data); } } set_table_name(&data, 0); if( data.db ){ | > | > | > > > > > > > | 11765 11766 11767 11768 11769 11770 11771 11772 11773 11774 11775 11776 11777 11778 11779 11780 11781 11782 11783 11784 11785 11786 11787 11788 11789 11790 11791 11792 11793 11794 11795 11796 11797 11798 11799 | free(zHistory); } }else{ data.in = stdin; rc = process_input(&data); } } free(azCmd); set_table_name(&data, 0); if( data.db ){ session_close_all(&data, -1); close_db(data.db); } for(i=0; i<ArraySize(data.aAuxDb); i++){ sqlite3_free(data.aAuxDb[i].zFreeOnClose); if( data.aAuxDb[i].db ){ session_close_all(&data, i); close_db(data.aAuxDb[i].db); } } find_home_dir(1); output_reset(&data); data.doXdgOpen = 0; clearTempFile(&data); #if !SQLITE_SHELL_IS_UTF8 for(i=0; i<argcToFree; i++) free(argvToFree[i]); free(argvToFree); #endif free(data.colWidth); free(data.zNonce); /* Clear the global data structure so that valgrind will detect memory ** leaks */ memset(&data, 0, sizeof(data)); return rc; } |
Changes to src/sqlite.h.in.
︙ | ︙ | |||
39 40 41 42 43 44 45 | */ #ifdef __cplusplus extern "C" { #endif /* | | > > > > > > > > > > > > > > > > > > > > > > > | 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 | */ #ifdef __cplusplus extern "C" { #endif /* ** Facilitate override of interface linkage and calling conventions. ** Be aware that these macros may not be used within this particular ** translation of the amalgamation and its associated header file. ** ** The SQLITE_EXTERN and SQLITE_API macros are used to instruct the ** compiler that the target identifier should have external linkage. ** ** The SQLITE_CDECL macro is used to set the calling convention for ** public functions that accept a variable number of arguments. ** ** The SQLITE_APICALL macro is used to set the calling convention for ** public functions that accept a fixed number of arguments. ** ** The SQLITE_STDCALL macro is no longer used and is now deprecated. ** ** The SQLITE_CALLBACK macro is used to set the calling convention for ** function pointers. ** ** The SQLITE_SYSAPI macro is used to set the calling convention for ** functions provided by the operating system. ** ** Currently, the SQLITE_CDECL, SQLITE_APICALL, SQLITE_CALLBACK, and ** SQLITE_SYSAPI macros are used only when building for environments ** that require non-default calling conventions. */ #ifndef SQLITE_EXTERN # define SQLITE_EXTERN extern #endif #ifndef SQLITE_API # define SQLITE_API #endif |
︙ | ︙ | |||
185 186 187 188 189 190 191 192 193 194 195 196 197 198 | ** ** See also: SQL functions [sqlite_compileoption_used()] and ** [sqlite_compileoption_get()] and the [compile_options pragma]. */ #ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS int sqlite3_compileoption_used(const char *zOptName); const char *sqlite3_compileoption_get(int N); #endif /* ** CAPI3REF: Test To See If The Library Is Threadsafe ** ** ^The sqlite3_threadsafe() function returns zero if and only if ** SQLite was compiled with mutexing code omitted due to the | > > > | 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 | ** ** See also: SQL functions [sqlite_compileoption_used()] and ** [sqlite_compileoption_get()] and the [compile_options pragma]. */ #ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS int sqlite3_compileoption_used(const char *zOptName); const char *sqlite3_compileoption_get(int N); #else # define sqlite3_compileoption_used(X) 0 # define sqlite3_compileoption_get(X) ((void*)0) #endif /* ** CAPI3REF: Test To See If The Library Is Threadsafe ** ** ^The sqlite3_threadsafe() function returns zero if and only if ** SQLite was compiled with mutexing code omitted due to the |
︙ | ︙ | |||
292 293 294 295 296 297 298 299 | ** ** ^The sqlite3_close() and sqlite3_close_v2() routines are destructors ** for the [sqlite3] object. ** ^Calls to sqlite3_close() and sqlite3_close_v2() return [SQLITE_OK] if ** the [sqlite3] object is successfully destroyed and all associated ** resources are deallocated. ** ** ^If the database connection is associated with unfinalized prepared | > > > > | | | | > > | | | | | < < < < < < < < < < | 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 | ** ** ^The sqlite3_close() and sqlite3_close_v2() routines are destructors ** for the [sqlite3] object. ** ^Calls to sqlite3_close() and sqlite3_close_v2() return [SQLITE_OK] if ** the [sqlite3] object is successfully destroyed and all associated ** resources are deallocated. ** ** Ideally, applications should [sqlite3_finalize | finalize] all ** [prepared statements], [sqlite3_blob_close | close] all [BLOB handles], and ** [sqlite3_backup_finish | finish] all [sqlite3_backup] objects associated ** with the [sqlite3] object prior to attempting to close the object. ** ^If the database connection is associated with unfinalized prepared ** statements, BLOB handlers, and/or unfinished sqlite3_backup objects then ** sqlite3_close() will leave the database connection open and return ** [SQLITE_BUSY]. ^If sqlite3_close_v2() is called with unfinalized prepared ** statements, unclosed BLOB handlers, and/or unfinished sqlite3_backups, ** it returns [SQLITE_OK] regardless, but instead of deallocating the database ** connection immediately, it marks the database connection as an unusable ** "zombie" and makes arrangements to automatically deallocate the database ** connection after all prepared statements are finalized, all BLOB handles ** are closed, and all backups have finished. The sqlite3_close_v2() interface ** is intended for use with host languages that are garbage collected, and ** where the order in which destructors are called is arbitrary. ** ** ^If an [sqlite3] object is destroyed while a transaction is open, ** the transaction is automatically rolled back. ** ** The C parameter to [sqlite3_close(C)] and [sqlite3_close_v2(C)] ** must be either a NULL ** pointer or an [sqlite3] object pointer obtained |
︙ | ︙ | |||
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 | #define SQLITE_IOERR_GETTEMPPATH (SQLITE_IOERR | (25<<8)) #define SQLITE_IOERR_CONVPATH (SQLITE_IOERR | (26<<8)) #define SQLITE_IOERR_VNODE (SQLITE_IOERR | (27<<8)) #define SQLITE_IOERR_AUTH (SQLITE_IOERR | (28<<8)) #define SQLITE_IOERR_BEGIN_ATOMIC (SQLITE_IOERR | (29<<8)) #define SQLITE_IOERR_COMMIT_ATOMIC (SQLITE_IOERR | (30<<8)) #define SQLITE_IOERR_ROLLBACK_ATOMIC (SQLITE_IOERR | (31<<8)) #define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8)) #define SQLITE_LOCKED_VTAB (SQLITE_LOCKED | (2<<8)) #define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8)) #define SQLITE_BUSY_SNAPSHOT (SQLITE_BUSY | (2<<8)) #define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1<<8)) #define SQLITE_CANTOPEN_ISDIR (SQLITE_CANTOPEN | (2<<8)) #define SQLITE_CANTOPEN_FULLPATH (SQLITE_CANTOPEN | (3<<8)) #define SQLITE_CANTOPEN_CONVPATH (SQLITE_CANTOPEN | (4<<8)) #define SQLITE_CANTOPEN_DIRTYWAL (SQLITE_CANTOPEN | (5<<8)) /* Not Used */ #define SQLITE_CORRUPT_VTAB (SQLITE_CORRUPT | (1<<8)) #define SQLITE_CORRUPT_SEQUENCE (SQLITE_CORRUPT | (2<<8)) #define SQLITE_READONLY_RECOVERY (SQLITE_READONLY | (1<<8)) #define SQLITE_READONLY_CANTLOCK (SQLITE_READONLY | (2<<8)) #define SQLITE_READONLY_ROLLBACK (SQLITE_READONLY | (3<<8)) #define SQLITE_READONLY_DBMOVED (SQLITE_READONLY | (4<<8)) #define SQLITE_READONLY_CANTINIT (SQLITE_READONLY | (5<<8)) #define SQLITE_READONLY_DIRECTORY (SQLITE_READONLY | (6<<8)) #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_CONSTRAINT_ROWID (SQLITE_CONSTRAINT |(10<<8)) #define SQLITE_NOTICE_RECOVER_WAL (SQLITE_NOTICE | (1<<8)) #define SQLITE_NOTICE_RECOVER_ROLLBACK (SQLITE_NOTICE | (2<<8)) #define SQLITE_WARNING_AUTOINDEX (SQLITE_WARNING | (1<<8)) #define SQLITE_AUTH_USER (SQLITE_AUTH | (1<<8)) #define SQLITE_OK_LOAD_PERMANENTLY (SQLITE_OK | (1<<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. */ #define SQLITE_OPEN_READONLY 0x00000001 /* Ok for sqlite3_open_v2() */ #define SQLITE_OPEN_READWRITE 0x00000002 /* Ok for sqlite3_open_v2() */ #define SQLITE_OPEN_CREATE 0x00000004 /* Ok for sqlite3_open_v2() */ #define SQLITE_OPEN_DELETEONCLOSE 0x00000008 /* VFS only */ #define SQLITE_OPEN_EXCLUSIVE 0x00000010 /* VFS only */ #define SQLITE_OPEN_AUTOPROXY 0x00000020 /* VFS only */ #define SQLITE_OPEN_URI 0x00000040 /* Ok for sqlite3_open_v2() */ #define SQLITE_OPEN_MEMORY 0x00000080 /* Ok for sqlite3_open_v2() */ #define SQLITE_OPEN_MAIN_DB 0x00000100 /* VFS only */ #define SQLITE_OPEN_TEMP_DB 0x00000200 /* VFS only */ #define SQLITE_OPEN_TRANSIENT_DB 0x00000400 /* VFS only */ #define SQLITE_OPEN_MAIN_JOURNAL 0x00000800 /* VFS only */ #define SQLITE_OPEN_TEMP_JOURNAL 0x00001000 /* VFS only */ #define SQLITE_OPEN_SUBJOURNAL 0x00002000 /* VFS only */ | > > > > > > > > > > > > > > > > > > > > > | > > > > > | 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 | #define SQLITE_IOERR_GETTEMPPATH (SQLITE_IOERR | (25<<8)) #define SQLITE_IOERR_CONVPATH (SQLITE_IOERR | (26<<8)) #define SQLITE_IOERR_VNODE (SQLITE_IOERR | (27<<8)) #define SQLITE_IOERR_AUTH (SQLITE_IOERR | (28<<8)) #define SQLITE_IOERR_BEGIN_ATOMIC (SQLITE_IOERR | (29<<8)) #define SQLITE_IOERR_COMMIT_ATOMIC (SQLITE_IOERR | (30<<8)) #define SQLITE_IOERR_ROLLBACK_ATOMIC (SQLITE_IOERR | (31<<8)) #define SQLITE_IOERR_DATA (SQLITE_IOERR | (32<<8)) #define SQLITE_IOERR_CORRUPTFS (SQLITE_IOERR | (33<<8)) #define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8)) #define SQLITE_LOCKED_VTAB (SQLITE_LOCKED | (2<<8)) #define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8)) #define SQLITE_BUSY_SNAPSHOT (SQLITE_BUSY | (2<<8)) #define SQLITE_BUSY_TIMEOUT (SQLITE_BUSY | (3<<8)) #define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1<<8)) #define SQLITE_CANTOPEN_ISDIR (SQLITE_CANTOPEN | (2<<8)) #define SQLITE_CANTOPEN_FULLPATH (SQLITE_CANTOPEN | (3<<8)) #define SQLITE_CANTOPEN_CONVPATH (SQLITE_CANTOPEN | (4<<8)) #define SQLITE_CANTOPEN_DIRTYWAL (SQLITE_CANTOPEN | (5<<8)) /* Not Used */ #define SQLITE_CANTOPEN_SYMLINK (SQLITE_CANTOPEN | (6<<8)) #define SQLITE_CORRUPT_VTAB (SQLITE_CORRUPT | (1<<8)) #define SQLITE_CORRUPT_SEQUENCE (SQLITE_CORRUPT | (2<<8)) #define SQLITE_CORRUPT_INDEX (SQLITE_CORRUPT | (3<<8)) #define SQLITE_READONLY_RECOVERY (SQLITE_READONLY | (1<<8)) #define SQLITE_READONLY_CANTLOCK (SQLITE_READONLY | (2<<8)) #define SQLITE_READONLY_ROLLBACK (SQLITE_READONLY | (3<<8)) #define SQLITE_READONLY_DBMOVED (SQLITE_READONLY | (4<<8)) #define SQLITE_READONLY_CANTINIT (SQLITE_READONLY | (5<<8)) #define SQLITE_READONLY_DIRECTORY (SQLITE_READONLY | (6<<8)) #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_CONSTRAINT_ROWID (SQLITE_CONSTRAINT |(10<<8)) #define SQLITE_CONSTRAINT_PINNED (SQLITE_CONSTRAINT |(11<<8)) #define SQLITE_CONSTRAINT_DATATYPE (SQLITE_CONSTRAINT |(12<<8)) #define SQLITE_NOTICE_RECOVER_WAL (SQLITE_NOTICE | (1<<8)) #define SQLITE_NOTICE_RECOVER_ROLLBACK (SQLITE_NOTICE | (2<<8)) #define SQLITE_WARNING_AUTOINDEX (SQLITE_WARNING | (1<<8)) #define SQLITE_AUTH_USER (SQLITE_AUTH | (1<<8)) #define SQLITE_OK_LOAD_PERMANENTLY (SQLITE_OK | (1<<8)) #define SQLITE_OK_SYMLINK (SQLITE_OK | (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. ** ** Only those flags marked as "Ok for sqlite3_open_v2()" may be ** used as the third argument to the [sqlite3_open_v2()] interface. ** The other flags have historically been ignored by sqlite3_open_v2(), ** though future versions of SQLite might change so that an error is ** raised if any of the disallowed bits are passed into sqlite3_open_v2(). ** Applications should not depend on the historical behavior. ** ** Note in particular that passing the SQLITE_OPEN_EXCLUSIVE flag into ** [sqlite3_open_v2()] does *not* cause the underlying database file ** to be opened using O_EXCL. Passing SQLITE_OPEN_EXCLUSIVE into ** [sqlite3_open_v2()] has historically be a no-op and might become an ** error in future versions of SQLite. */ #define SQLITE_OPEN_READONLY 0x00000001 /* Ok for sqlite3_open_v2() */ #define SQLITE_OPEN_READWRITE 0x00000002 /* Ok for sqlite3_open_v2() */ #define SQLITE_OPEN_CREATE 0x00000004 /* Ok for sqlite3_open_v2() */ #define SQLITE_OPEN_DELETEONCLOSE 0x00000008 /* VFS only */ #define SQLITE_OPEN_EXCLUSIVE 0x00000010 /* VFS only */ #define SQLITE_OPEN_AUTOPROXY 0x00000020 /* VFS only */ #define SQLITE_OPEN_URI 0x00000040 /* Ok for sqlite3_open_v2() */ #define SQLITE_OPEN_MEMORY 0x00000080 /* Ok for sqlite3_open_v2() */ #define SQLITE_OPEN_MAIN_DB 0x00000100 /* VFS only */ #define SQLITE_OPEN_TEMP_DB 0x00000200 /* VFS only */ #define SQLITE_OPEN_TRANSIENT_DB 0x00000400 /* VFS only */ #define SQLITE_OPEN_MAIN_JOURNAL 0x00000800 /* VFS only */ #define SQLITE_OPEN_TEMP_JOURNAL 0x00001000 /* VFS only */ #define SQLITE_OPEN_SUBJOURNAL 0x00002000 /* VFS only */ #define SQLITE_OPEN_SUPER_JOURNAL 0x00004000 /* VFS only */ #define SQLITE_OPEN_NOMUTEX 0x00008000 /* Ok for sqlite3_open_v2() */ #define SQLITE_OPEN_FULLMUTEX 0x00010000 /* Ok for sqlite3_open_v2() */ #define SQLITE_OPEN_SHAREDCACHE 0x00020000 /* Ok for sqlite3_open_v2() */ #define SQLITE_OPEN_PRIVATECACHE 0x00040000 /* Ok for sqlite3_open_v2() */ #define SQLITE_OPEN_WAL 0x00080000 /* VFS only */ #define SQLITE_OPEN_NOFOLLOW 0x01000000 /* Ok for sqlite3_open_v2() */ #define SQLITE_OPEN_EXRESCODE 0x02000000 /* Extended result codes */ /* Reserved: 0x00F00000 */ /* Legacy compatibility: */ #define SQLITE_OPEN_MASTER_JOURNAL 0x00004000 /* VFS only */ /* ** CAPI3REF: Device Characteristics ** ** The xDeviceCharacteristics method of the [sqlite3_io_methods] ** object returns an integer which is a vector of these ** bit values expressing I/O characteristics of the mass storage |
︙ | ︙ | |||
819 820 821 822 823 824 825 826 827 828 829 830 831 832 | ** The [SQLITE_FCNTL_SIZE_HINT] opcode is used by SQLite to give the VFS ** layer a hint of how large the database file will grow to be during the ** current transaction. This hint is not guaranteed to be accurate but it ** is often close. The underlying VFS might choose to preallocate database ** file space based on this hint in order to help writes to the database ** file run faster. ** ** <li>[[SQLITE_FCNTL_CHUNK_SIZE]] ** The [SQLITE_FCNTL_CHUNK_SIZE] opcode is used to request that the VFS ** extends and truncates the database file in chunks of a size specified ** by the user. The fourth argument to [sqlite3_file_control()] should ** point to an integer (type int) containing the new chunk-size to use ** for the nominated database. Allocating database file space in large ** chunks (say 1MB at a time), may reduce file-system fragmentation and | > > > > > > > > > | 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 | ** The [SQLITE_FCNTL_SIZE_HINT] opcode is used by SQLite to give the VFS ** layer a hint of how large the database file will grow to be during the ** current transaction. This hint is not guaranteed to be accurate but it ** is often close. The underlying VFS might choose to preallocate database ** file space based on this hint in order to help writes to the database ** file run faster. ** ** <li>[[SQLITE_FCNTL_SIZE_LIMIT]] ** The [SQLITE_FCNTL_SIZE_LIMIT] opcode is used by in-memory VFS that ** implements [sqlite3_deserialize()] to set an upper bound on the size ** of the in-memory database. The argument is a pointer to a [sqlite3_int64]. ** If the integer pointed to is negative, then it is filled in with the ** current limit. Otherwise the limit is set to the larger of the value ** of the integer pointed to and the current database size. The integer ** pointed to is set to the new limit. ** ** <li>[[SQLITE_FCNTL_CHUNK_SIZE]] ** The [SQLITE_FCNTL_CHUNK_SIZE] opcode is used to request that the VFS ** extends and truncates the database file in chunks of a size specified ** by the user. The fourth argument to [sqlite3_file_control()] should ** point to an integer (type int) containing the new chunk-size to use ** for the nominated database. Allocating database file space in large ** chunks (say 1MB at a time), may reduce file-system fragmentation and |
︙ | ︙ | |||
851 852 853 854 855 856 857 | ** sent to the VFS immediately before the xSync method is invoked on a ** database file descriptor. Or, if the xSync method is not invoked ** because the user has configured SQLite with ** [PRAGMA synchronous | PRAGMA synchronous=OFF] it is invoked in place ** of the xSync method. In most cases, the pointer argument passed with ** this file-control is NULL. However, if the database file is being synced ** as part of a multi-database commit, the argument points to a nul-terminated | | | 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 | ** sent to the VFS immediately before the xSync method is invoked on a ** database file descriptor. Or, if the xSync method is not invoked ** because the user has configured SQLite with ** [PRAGMA synchronous | PRAGMA synchronous=OFF] it is invoked in place ** of the xSync method. In most cases, the pointer argument passed with ** this file-control is NULL. However, if the database file is being synced ** as part of a multi-database commit, the argument points to a nul-terminated ** string containing the transactions super-journal file name. VFSes that ** do not need this signal should silently ignore this opcode. Applications ** should not call [sqlite3_file_control()] with this opcode as doing so may ** disrupt the operation of the specialized VFSes that do require it. ** ** <li>[[SQLITE_FCNTL_COMMIT_PHASETWO]] ** The [SQLITE_FCNTL_COMMIT_PHASETWO] opcode is generated internally by SQLite ** and sent to the VFS after a transaction has been committed immediately |
︙ | ︙ | |||
963 964 965 966 967 968 969 | ** 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 | | | | | 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 | ** 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 connection's 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 connection's ** 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]] ** ^Applications 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. ** |
︙ | ︙ | |||
1067 1068 1069 1070 1071 1072 1073 | ** [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] to be rolled back. ** ^This file control takes the file descriptor out of batch write mode ** so that all subsequent write operations are independent. ** ^SQLite will never invoke SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE without ** a prior successful call to [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE]. ** ** <li>[[SQLITE_FCNTL_LOCK_TIMEOUT]] | | > | < | > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | ** [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] to be rolled back. ** ^This file control takes the file descriptor out of batch write mode ** so that all subsequent write operations are independent. ** ^SQLite will never invoke SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE without ** a prior successful call to [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE]. ** ** <li>[[SQLITE_FCNTL_LOCK_TIMEOUT]] ** The [SQLITE_FCNTL_LOCK_TIMEOUT] opcode is used to configure a VFS ** to block for up to M milliseconds before failing when attempting to ** obtain a file lock using the xLock or xShmLock methods of the VFS. ** The parameter is a pointer to a 32-bit signed integer that contains ** the value that M is to be set to. Before returning, the 32-bit signed ** integer is overwritten with the previous value of M. ** ** <li>[[SQLITE_FCNTL_DATA_VERSION]] ** The [SQLITE_FCNTL_DATA_VERSION] opcode is used to detect changes to ** a database file. The argument is a pointer to a 32-bit unsigned integer. ** The "data version" for the pager is written into the pointer. The ** "data version" changes whenever any change occurs to the corresponding ** database file, either through SQL statements on the same database ** connection or through transactions committed by separate database ** connections possibly in other processes. The [sqlite3_total_changes()] ** interface can be used to find if any database on the connection has changed, ** but that interface responds to changes on TEMP as well as MAIN and does ** not provide a mechanism to detect changes to MAIN only. Also, the ** [sqlite3_total_changes()] interface responds to internal changes only and ** omits changes made by other database connections. The ** [PRAGMA data_version] command provides a mechanism to detect changes to ** a single attached database that occur due to other database connections, ** but omits changes implemented by the database connection on which it is ** called. This file control is the only mechanism to detect changes that ** happen either internally or externally and that are associated with ** a particular attached database. ** ** <li>[[SQLITE_FCNTL_CKPT_START]] ** The [SQLITE_FCNTL_CKPT_START] opcode is invoked from within a checkpoint ** in wal mode before the client starts to copy pages from the wal ** file to the database file. ** ** <li>[[SQLITE_FCNTL_CKPT_DONE]] ** The [SQLITE_FCNTL_CKPT_DONE] opcode is invoked from within a checkpoint ** in wal mode after the client has finished copying pages from the wal ** file to the database file, but before the *-shm file is updated to ** record the fact that the pages have been checkpointed. ** </ul> ** ** <li>[[SQLITE_FCNTL_EXTERNAL_READER]] ** The EXPERIMENTAL [SQLITE_FCNTL_EXTERNAL_READER] opcode is used to detect ** whether or not there is a database client in another process with a wal-mode ** transaction open on the database or not. It is only available on unix.The ** (void*) argument passed with this file-control should be a pointer to a ** value of type (int). The integer value is set to 1 if the database is a wal ** mode database and there exists at least one client in another process that ** currently has an SQL transaction open on the database. It is set to 0 if ** the database is not a wal-mode db, or if there is no such connection in any ** other process. This opcode cannot be used to detect transactions opened ** by clients within the current process, only within other processes. ** </ul> ** ** <li>[[SQLITE_FCNTL_CKSM_FILE]] ** Used by the cksmvfs VFS module only. ** </ul> */ #define SQLITE_FCNTL_LOCKSTATE 1 #define SQLITE_FCNTL_GET_LOCKPROXYFILE 2 #define SQLITE_FCNTL_SET_LOCKPROXYFILE 3 #define SQLITE_FCNTL_LAST_ERRNO 4 #define SQLITE_FCNTL_SIZE_HINT 5 |
︙ | ︙ | |||
1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 | #define SQLITE_FCNTL_WIN32_GET_HANDLE 29 #define SQLITE_FCNTL_PDB 30 #define SQLITE_FCNTL_BEGIN_ATOMIC_WRITE 31 #define SQLITE_FCNTL_COMMIT_ATOMIC_WRITE 32 #define SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE 33 #define SQLITE_FCNTL_LOCK_TIMEOUT 34 #define SQLITE_FCNTL_DATA_VERSION 35 /* deprecated names */ #define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE #define SQLITE_SET_LOCKPROXYFILE SQLITE_FCNTL_SET_LOCKPROXYFILE #define SQLITE_LAST_ERRNO SQLITE_FCNTL_LAST_ERRNO | > > > > > > | 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 | #define SQLITE_FCNTL_WIN32_GET_HANDLE 29 #define SQLITE_FCNTL_PDB 30 #define SQLITE_FCNTL_BEGIN_ATOMIC_WRITE 31 #define SQLITE_FCNTL_COMMIT_ATOMIC_WRITE 32 #define SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE 33 #define SQLITE_FCNTL_LOCK_TIMEOUT 34 #define SQLITE_FCNTL_DATA_VERSION 35 #define SQLITE_FCNTL_SIZE_LIMIT 36 #define SQLITE_FCNTL_CKPT_DONE 37 #define SQLITE_FCNTL_RESERVE_BYTES 38 #define SQLITE_FCNTL_CKPT_START 39 #define SQLITE_FCNTL_EXTERNAL_READER 40 #define SQLITE_FCNTL_CKSM_FILE 41 /* deprecated names */ #define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE #define SQLITE_SET_LOCKPROXYFILE SQLITE_FCNTL_SET_LOCKPROXYFILE #define SQLITE_LAST_ERRNO SQLITE_FCNTL_LAST_ERRNO |
︙ | ︙ | |||
1172 1173 1174 1175 1176 1177 1178 | ** the end. Each time such an extension occurs, the iVersion field ** is incremented. The iVersion value started out as 1 in ** SQLite [version 3.5.0] on [dateof:3.5.0], then increased to 2 ** with SQLite [version 3.7.0] on [dateof:3.7.0], and then increased ** to 3 with SQLite [version 3.7.6] on [dateof:3.7.6]. Additional fields ** may be appended to the sqlite3_vfs object and the iVersion value ** may increase again in future versions of SQLite. | | | | | 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 | ** the end. Each time such an extension occurs, the iVersion field ** is incremented. The iVersion value started out as 1 in ** SQLite [version 3.5.0] on [dateof:3.5.0], then increased to 2 ** with SQLite [version 3.7.0] on [dateof:3.7.0], and then increased ** to 3 with SQLite [version 3.7.6] on [dateof:3.7.6]. Additional fields ** may be appended to the sqlite3_vfs object and the iVersion value ** may increase again in future versions of SQLite. ** Note that due to an oversight, the structure ** of the sqlite3_vfs object changed in the transition from ** SQLite [version 3.5.9] to [version 3.6.0] on [dateof:3.6.0] ** and yet the iVersion field was not increased. ** ** The szOsFile field is the size of the subclassed [sqlite3_file] ** structure used by this VFS. mxPathname is the maximum length of ** a pathname in this VFS. ** ** Registered sqlite3_vfs objects are kept on a linked list formed by ** the pNext pointer. The [sqlite3_vfs_register()] |
︙ | ︙ | |||
1231 1232 1233 1234 1235 1236 1237 | ** <ul> ** <li> [SQLITE_OPEN_MAIN_DB] ** <li> [SQLITE_OPEN_MAIN_JOURNAL] ** <li> [SQLITE_OPEN_TEMP_DB] ** <li> [SQLITE_OPEN_TEMP_JOURNAL] ** <li> [SQLITE_OPEN_TRANSIENT_DB] ** <li> [SQLITE_OPEN_SUBJOURNAL] | | | 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 | ** <ul> ** <li> [SQLITE_OPEN_MAIN_DB] ** <li> [SQLITE_OPEN_MAIN_JOURNAL] ** <li> [SQLITE_OPEN_TEMP_DB] ** <li> [SQLITE_OPEN_TEMP_JOURNAL] ** <li> [SQLITE_OPEN_TRANSIENT_DB] ** <li> [SQLITE_OPEN_SUBJOURNAL] ** <li> [SQLITE_OPEN_SUPER_JOURNAL] ** <li> [SQLITE_OPEN_WAL] ** </ul>)^ ** ** The file I/O implementation can use the object type flags to ** change the way it deals with files. For example, an application ** that does not care about crash recovery or rollback might make ** the open of a journal file a no-op. Writes to this journal would |
︙ | ︙ | |||
1266 1267 1268 1269 1270 1271 1272 | ** API. The SQLITE_OPEN_EXCLUSIVE flag, when paired with the ** SQLITE_OPEN_CREATE, is used to indicate that file should always ** be created, and that it is an error if it already exists. ** It is <i>not</i> used to indicate the file should be opened ** for exclusive access. ** ** ^At least szOsFile bytes of memory are allocated by SQLite | | | > > | > > > > | 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 | ** API. The SQLITE_OPEN_EXCLUSIVE flag, when paired with the ** SQLITE_OPEN_CREATE, is used to indicate that file should always ** be created, and that it is an error if it already exists. ** It is <i>not</i> used to indicate the file should be opened ** for exclusive access. ** ** ^At least szOsFile bytes of memory are allocated by SQLite ** to hold the [sqlite3_file] structure passed as the third ** argument to xOpen. The xOpen method does not have to ** allocate the structure; it should just fill it in. Note that ** the xOpen method must set the sqlite3_file.pMethods to either ** a valid [sqlite3_io_methods] object or to NULL. xOpen must do ** this even if the open fails. SQLite expects that the sqlite3_file.pMethods ** element will be valid after xOpen returns regardless of the success ** or failure of the xOpen call. ** ** [[sqlite3_vfs.xAccess]] ** ^The flags argument to xAccess() may be [SQLITE_ACCESS_EXISTS] ** to test for the existence of a file, or [SQLITE_ACCESS_READWRITE] to ** test whether a file is readable and writable, or [SQLITE_ACCESS_READ] ** to test whether a file is at least readable. The SQLITE_ACCESS_READ ** flag is never actually used and is not implemented in the built-in ** VFSes of SQLite. The file is named by the second argument and can be a ** directory. The xAccess method returns [SQLITE_OK] on success or some ** non-zero error code if there is an I/O error or if the name of ** the file given in the second argument is illegal. If SQLITE_OK ** is returned, then non-zero or zero is written into *pResOut to indicate ** whether or not the file is accessible. ** ** ^SQLite will always allocate at least mxPathname+1 bytes for the ** output buffer xFullPathname. The exact size of the output buffer ** is also passed as a parameter to both methods. If the output buffer ** is not large enough, [SQLITE_CANTOPEN] should be returned. Since this is ** handled as a fatal error by SQLite, vfs implementations should endeavor ** to prevent this by setting mxPathname to a sufficiently large value. |
︙ | ︙ | |||
1597 1598 1599 1600 1601 1602 1603 | ** allocators round up memory allocations at least to the next multiple ** of 8. Some allocators round up to a larger multiple or to a power of 2. ** Every memory allocation request coming in through [sqlite3_malloc()] ** or [sqlite3_realloc()] first calls xRoundup. If xRoundup returns 0, ** that causes the corresponding memory allocation to fail. ** ** The xInit method initializes the memory allocator. For example, | | | | 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 | ** allocators round up memory allocations at least to the next multiple ** of 8. Some allocators round up to a larger multiple or to a power of 2. ** Every memory allocation request coming in through [sqlite3_malloc()] ** or [sqlite3_realloc()] first calls xRoundup. If xRoundup returns 0, ** that causes the corresponding memory allocation to fail. ** ** The xInit method initializes the memory allocator. For example, ** it might allocate any required mutexes or initialize internal data ** structures. The xShutdown method is invoked (indirectly) by ** [sqlite3_shutdown()] and should deallocate any resources acquired ** by xInit. The pAppData pointer is used as the only parameter to ** xInit and xShutdown. ** ** SQLite holds the [SQLITE_MUTEX_STATIC_MAIN] mutex when it invokes ** the xInit method, so the xInit method need not be threadsafe. The ** xShutdown method is only called from [sqlite3_shutdown()] so it does ** not need to be threadsafe either. For all other methods, SQLite ** holds the [SQLITE_MUTEX_STATIC_MEM] mutex as long as the ** [SQLITE_CONFIG_MEMSTATUS] configuration option is turned on (which ** it is by default) and so the methods are automatically serialized. ** However, if [SQLITE_CONFIG_MEMSTATUS] is disabled, then the other |
︙ | ︙ | |||
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 | ** ** [[SQLITE_CONFIG_MEMSTATUS]] <dt>SQLITE_CONFIG_MEMSTATUS</dt> ** <dd> ^The SQLITE_CONFIG_MEMSTATUS option takes single argument of type int, ** interpreted as a boolean, which enables or disables the collection of ** memory allocation statistics. ^(When memory allocation statistics are ** disabled, the following SQLite interfaces become non-operational: ** <ul> ** <li> [sqlite3_memory_used()] ** <li> [sqlite3_memory_highwater()] ** <li> [sqlite3_soft_heap_limit64()] ** <li> [sqlite3_status64()] ** </ul>)^ ** ^Memory allocation statistics are enabled by default unless SQLite is ** compiled with [SQLITE_DEFAULT_MEMSTATUS]=0 in which case memory ** allocation statistics are disabled by default. ** </dd> ** ** [[SQLITE_CONFIG_SCRATCH]] <dt>SQLITE_CONFIG_SCRATCH</dt> ** <dd> The SQLITE_CONFIG_SCRATCH option is no longer used. ** </dd> ** ** [[SQLITE_CONFIG_PAGECACHE]] <dt>SQLITE_CONFIG_PAGECACHE</dt> ** <dd> ^The SQLITE_CONFIG_PAGECACHE option specifies a memory pool ** that SQLite can use for the database page cache with the default page ** cache implementation. | > | | 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 | ** ** [[SQLITE_CONFIG_MEMSTATUS]] <dt>SQLITE_CONFIG_MEMSTATUS</dt> ** <dd> ^The SQLITE_CONFIG_MEMSTATUS option takes single argument of type int, ** interpreted as a boolean, which enables or disables the collection of ** memory allocation statistics. ^(When memory allocation statistics are ** disabled, the following SQLite interfaces become non-operational: ** <ul> ** <li> [sqlite3_hard_heap_limit64()] ** <li> [sqlite3_memory_used()] ** <li> [sqlite3_memory_highwater()] ** <li> [sqlite3_soft_heap_limit64()] ** <li> [sqlite3_status64()] ** </ul>)^ ** ^Memory allocation statistics are enabled by default unless SQLite is ** compiled with [SQLITE_DEFAULT_MEMSTATUS]=0 in which case memory ** allocation statistics are disabled by default. ** </dd> ** ** [[SQLITE_CONFIG_SCRATCH]] <dt>SQLITE_CONFIG_SCRATCH</dt> ** <dd> The SQLITE_CONFIG_SCRATCH option is no longer used. ** </dd> ** ** [[SQLITE_CONFIG_PAGECACHE]] <dt>SQLITE_CONFIG_PAGECACHE</dt> ** <dd> ^The SQLITE_CONFIG_PAGECACHE option specifies a memory pool ** that SQLite can use for the database page cache with the default page ** cache implementation. ** This configuration option is a no-op if an application-defined page ** cache implementation is loaded using the [SQLITE_CONFIG_PCACHE2]. ** ^There are three arguments to SQLITE_CONFIG_PAGECACHE: A pointer to ** 8-byte aligned memory (pMem), the size of each page cache line (sz), ** and the number of cache lines (N). ** The sz argument should be the size of the largest database page ** (a power of two between 512 and 65536) plus some extra bytes for each ** page header. ^The number of extra bytes needed by the page header |
︙ | ︙ | |||
1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 | ** than the configured sorter-reference size threshold - then a reference ** is stored in each sorted record and the required column values loaded ** from the database as records are returned in sorted order. The default ** value for this option is to never use this optimization. Specifying a ** negative value for this option restores the default behaviour. ** This option is only available if SQLite is compiled with the ** [SQLITE_ENABLE_SORTER_REFERENCES] compile-time option. ** </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* */ | > > > > > > > > > > > | 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 | ** than the configured sorter-reference size threshold - then a reference ** is stored in each sorted record and the required column values loaded ** from the database as records are returned in sorted order. The default ** value for this option is to never use this optimization. Specifying a ** negative value for this option restores the default behaviour. ** This option is only available if SQLite is compiled with the ** [SQLITE_ENABLE_SORTER_REFERENCES] compile-time option. ** ** [[SQLITE_CONFIG_MEMDB_MAXSIZE]] ** <dt>SQLITE_CONFIG_MEMDB_MAXSIZE ** <dd>The SQLITE_CONFIG_MEMDB_MAXSIZE option accepts a single parameter ** [sqlite3_int64] parameter which is the default maximum size for an in-memory ** database created using [sqlite3_deserialize()]. This default maximum ** size can be adjusted up or down for individual databases using the ** [SQLITE_FCNTL_SIZE_LIMIT] [sqlite3_file_control|file-control]. If this ** configuration setting is never used, then the default maximum is determined ** by the [SQLITE_MEMDB_DEFAULT_MAXSIZE] compile-time option. If that ** compile-time option is not set, then the default maximum is 1073741824. ** </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* */ |
︙ | ︙ | |||
1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 | #define SQLITE_CONFIG_MMAP_SIZE 22 /* sqlite3_int64, sqlite3_int64 */ #define SQLITE_CONFIG_WIN32_HEAPSIZE 23 /* int nByte */ #define SQLITE_CONFIG_PCACHE_HDRSZ 24 /* int *psz */ #define SQLITE_CONFIG_PMASZ 25 /* unsigned int szPma */ #define SQLITE_CONFIG_STMTJRNL_SPILL 26 /* int nByte */ #define SQLITE_CONFIG_SMALL_MALLOC 27 /* boolean */ #define SQLITE_CONFIG_SORTERREF_SIZE 28 /* int nByte */ /* ** 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. ** | > | 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 | #define SQLITE_CONFIG_MMAP_SIZE 22 /* sqlite3_int64, sqlite3_int64 */ #define SQLITE_CONFIG_WIN32_HEAPSIZE 23 /* int nByte */ #define SQLITE_CONFIG_PCACHE_HDRSZ 24 /* int *psz */ #define SQLITE_CONFIG_PMASZ 25 /* unsigned int szPma */ #define SQLITE_CONFIG_STMTJRNL_SPILL 26 /* int nByte */ #define SQLITE_CONFIG_SMALL_MALLOC 27 /* boolean */ #define SQLITE_CONFIG_SORTERREF_SIZE 28 /* int nByte */ #define SQLITE_CONFIG_MEMDB_MAXSIZE 29 /* 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. ** |
︙ | ︙ | |||
2056 2057 2058 2059 2060 2061 2062 | ** <dd> ^This option is used to enable or disable [CREATE TRIGGER | triggers]. ** There should be two additional arguments. ** The first argument is an integer which is 0 to disable triggers, ** positive to enable triggers or negative to leave the setting unchanged. ** The second parameter is a pointer to an integer into which ** is written 0 or 1 to indicate whether triggers are disabled or enabled ** following this call. The second parameter may be a NULL pointer, in | | > > > > > > > > > > > > > > > > > > > > > > > | | | 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 | ** <dd> ^This option is used to enable or disable [CREATE TRIGGER | triggers]. ** There should be two additional arguments. ** The first argument is an integer which is 0 to disable triggers, ** positive to enable triggers or negative to leave the setting unchanged. ** The second parameter is a pointer to an integer into which ** is written 0 or 1 to indicate whether triggers are disabled or enabled ** following this call. The second parameter may be a NULL pointer, in ** which case the trigger setting is not reported back. ** ** <p>Originally this option disabled all triggers. ^(However, since ** SQLite version 3.35.0, TEMP triggers are still allowed even if ** this option is off. So, in other words, this option now only disables ** triggers in the main database schema or in the schemas of ATTACH-ed ** databases.)^ </dd> ** ** [[SQLITE_DBCONFIG_ENABLE_VIEW]] ** <dt>SQLITE_DBCONFIG_ENABLE_VIEW</dt> ** <dd> ^This option is used to enable or disable [CREATE VIEW | views]. ** There should be two additional arguments. ** The first argument is an integer which is 0 to disable views, ** positive to enable views or negative to leave the setting unchanged. ** The second parameter is a pointer to an integer into which ** is written 0 or 1 to indicate whether views are disabled or enabled ** following this call. The second parameter may be a NULL pointer, in ** which case the view setting is not reported back. ** ** <p>Originally this option disabled all views. ^(However, since ** SQLite version 3.35.0, TEMP views are still allowed even if ** this option is off. So, in other words, this option now only disables ** views in the main database schema or in the schemas of ATTACH-ed ** databases.)^ </dd> ** ** [[SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER]] ** <dt>SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER</dt> ** <dd> ^This option is used to enable or disable the ** [fts3_tokenizer()] function which is part of the ** [FTS3] full-text search engine extension. ** There should be two additional arguments. ** The first argument is an integer which is 0 to disable fts3_tokenizer() or ** positive to enable fts3_tokenizer() or negative to leave the setting ** unchanged. ** The second parameter is a pointer to an integer into which ** is written 0 or 1 to indicate whether fts3_tokenizer is disabled or enabled |
︙ | ︙ | |||
2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 | ** <dd>The SQLITE_DBCONFIG_DEFENSIVE option activates or deactivates the ** "defensive" flag for a database connection. When the defensive ** flag is enabled, language features that allow ordinary SQL to ** deliberately corrupt the database file are disabled. The disabled ** features include but are not limited to the following: ** <ul> ** <li> The [PRAGMA writable_schema=ON] statement. ** <li> Writes to the [sqlite_dbpage] virtual table. ** <li> Direct writes to [shadow tables]. ** </ul> ** </dd> ** </dl> */ #define SQLITE_DBCONFIG_MAINDBNAME 1000 /* const char* */ #define SQLITE_DBCONFIG_LOOKASIDE 1001 /* void* int int */ #define SQLITE_DBCONFIG_ENABLE_FKEY 1002 /* int int* */ #define SQLITE_DBCONFIG_ENABLE_TRIGGER 1003 /* int int* */ #define SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER 1004 /* int int* */ #define SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION 1005 /* int int* */ #define SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE 1006 /* int int* */ #define SQLITE_DBCONFIG_ENABLE_QPSG 1007 /* int int* */ #define SQLITE_DBCONFIG_TRIGGER_EQP 1008 /* int int* */ #define SQLITE_DBCONFIG_RESET_DATABASE 1009 /* int int* */ #define SQLITE_DBCONFIG_DEFENSIVE 1010 /* int int* */ | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | 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 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 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 | ** <dd>The SQLITE_DBCONFIG_DEFENSIVE option activates or deactivates the ** "defensive" flag for a database connection. When the defensive ** flag is enabled, language features that allow ordinary SQL to ** deliberately corrupt the database file are disabled. The disabled ** features include but are not limited to the following: ** <ul> ** <li> The [PRAGMA writable_schema=ON] statement. ** <li> The [PRAGMA journal_mode=OFF] statement. ** <li> Writes to the [sqlite_dbpage] virtual table. ** <li> Direct writes to [shadow tables]. ** </ul> ** </dd> ** ** [[SQLITE_DBCONFIG_WRITABLE_SCHEMA]] <dt>SQLITE_DBCONFIG_WRITABLE_SCHEMA</dt> ** <dd>The SQLITE_DBCONFIG_WRITABLE_SCHEMA option activates or deactivates the ** "writable_schema" flag. This has the same effect and is logically equivalent ** to setting [PRAGMA writable_schema=ON] or [PRAGMA writable_schema=OFF]. ** The first argument to this setting is an integer which is 0 to disable ** the writable_schema, positive to enable writable_schema, or negative to ** leave the setting unchanged. The second parameter is a pointer to an ** integer into which is written 0 or 1 to indicate whether the writable_schema ** is enabled or disabled following this call. ** </dd> ** ** [[SQLITE_DBCONFIG_LEGACY_ALTER_TABLE]] ** <dt>SQLITE_DBCONFIG_LEGACY_ALTER_TABLE</dt> ** <dd>The SQLITE_DBCONFIG_LEGACY_ALTER_TABLE option activates or deactivates ** the legacy behavior of the [ALTER TABLE RENAME] command such it ** behaves as it did prior to [version 3.24.0] (2018-06-04). See the ** "Compatibility Notice" on the [ALTER TABLE RENAME documentation] for ** additional information. This feature can also be turned on and off ** using the [PRAGMA legacy_alter_table] statement. ** </dd> ** ** [[SQLITE_DBCONFIG_DQS_DML]] ** <dt>SQLITE_DBCONFIG_DQS_DML</td> ** <dd>The SQLITE_DBCONFIG_DQS_DML option activates or deactivates ** the legacy [double-quoted string literal] misfeature for DML statements ** only, that is DELETE, INSERT, SELECT, and UPDATE statements. The ** default value of this setting is determined by the [-DSQLITE_DQS] ** compile-time option. ** </dd> ** ** [[SQLITE_DBCONFIG_DQS_DDL]] ** <dt>SQLITE_DBCONFIG_DQS_DDL</td> ** <dd>The SQLITE_DBCONFIG_DQS option activates or deactivates ** the legacy [double-quoted string literal] misfeature for DDL statements, ** such as CREATE TABLE and CREATE INDEX. The ** default value of this setting is determined by the [-DSQLITE_DQS] ** compile-time option. ** </dd> ** ** [[SQLITE_DBCONFIG_TRUSTED_SCHEMA]] ** <dt>SQLITE_DBCONFIG_TRUSTED_SCHEMA</td> ** <dd>The SQLITE_DBCONFIG_TRUSTED_SCHEMA option tells SQLite to ** assume that database schemas are untainted by malicious content. ** When the SQLITE_DBCONFIG_TRUSTED_SCHEMA option is disabled, SQLite ** takes additional defensive steps to protect the application from harm ** including: ** <ul> ** <li> Prohibit the use of SQL functions inside triggers, views, ** CHECK constraints, DEFAULT clauses, expression indexes, ** partial indexes, or generated columns ** unless those functions are tagged with [SQLITE_INNOCUOUS]. ** <li> Prohibit the use of virtual tables inside of triggers or views ** unless those virtual tables are tagged with [SQLITE_VTAB_INNOCUOUS]. ** </ul> ** This setting defaults to "on" for legacy compatibility, however ** all applications are advised to turn it off if possible. This setting ** can also be controlled using the [PRAGMA trusted_schema] statement. ** </dd> ** ** [[SQLITE_DBCONFIG_LEGACY_FILE_FORMAT]] ** <dt>SQLITE_DBCONFIG_LEGACY_FILE_FORMAT</td> ** <dd>The SQLITE_DBCONFIG_LEGACY_FILE_FORMAT option activates or deactivates ** the legacy file format flag. When activated, this flag causes all newly ** created database file to have a schema format version number (the 4-byte ** integer found at offset 44 into the database header) of 1. This in turn ** means that the resulting database file will be readable and writable by ** any SQLite version back to 3.0.0 ([dateof:3.0.0]). Without this setting, ** newly created databases are generally not understandable by SQLite versions ** prior to 3.3.0 ([dateof:3.3.0]). As these words are written, there ** is now scarcely any need to generated database files that are compatible ** all the way back to version 3.0.0, and so this setting is of little ** practical use, but is provided so that SQLite can continue to claim the ** ability to generate new database files that are compatible with version ** 3.0.0. ** <p>Note that when the SQLITE_DBCONFIG_LEGACY_FILE_FORMAT setting is on, ** the [VACUUM] command will fail with an obscure error when attempting to ** process a table with generated columns and a descending index. This is ** not considered a bug since SQLite versions 3.3.0 and earlier do not support ** either generated columns or decending indexes. ** </dd> ** </dl> */ #define SQLITE_DBCONFIG_MAINDBNAME 1000 /* const char* */ #define SQLITE_DBCONFIG_LOOKASIDE 1001 /* void* int int */ #define SQLITE_DBCONFIG_ENABLE_FKEY 1002 /* int int* */ #define SQLITE_DBCONFIG_ENABLE_TRIGGER 1003 /* int int* */ #define SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER 1004 /* int int* */ #define SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION 1005 /* int int* */ #define SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE 1006 /* int int* */ #define SQLITE_DBCONFIG_ENABLE_QPSG 1007 /* int int* */ #define SQLITE_DBCONFIG_TRIGGER_EQP 1008 /* int int* */ #define SQLITE_DBCONFIG_RESET_DATABASE 1009 /* int int* */ #define SQLITE_DBCONFIG_DEFENSIVE 1010 /* int int* */ #define SQLITE_DBCONFIG_WRITABLE_SCHEMA 1011 /* int int* */ #define SQLITE_DBCONFIG_LEGACY_ALTER_TABLE 1012 /* int int* */ #define SQLITE_DBCONFIG_DQS_DML 1013 /* int int* */ #define SQLITE_DBCONFIG_DQS_DDL 1014 /* int int* */ #define SQLITE_DBCONFIG_ENABLE_VIEW 1015 /* int int* */ #define SQLITE_DBCONFIG_LEGACY_FILE_FORMAT 1016 /* int int* */ #define SQLITE_DBCONFIG_TRUSTED_SCHEMA 1017 /* int int* */ #define SQLITE_DBCONFIG_MAX 1017 /* Largest DBCONFIG */ /* ** CAPI3REF: Enable Or Disable Extended Result Codes ** METHOD: sqlite3 ** ** ^The sqlite3_extended_result_codes() routine enables or disables the ** [extended result codes] feature of SQLite. ^The extended result |
︙ | ︙ | |||
2274 2275 2276 2277 2278 2279 2280 | */ void sqlite3_set_last_insert_rowid(sqlite3*,sqlite3_int64); /* ** CAPI3REF: Count The Number Of Rows Modified ** METHOD: sqlite3 ** | | > > > > | < | 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 | */ void sqlite3_set_last_insert_rowid(sqlite3*,sqlite3_int64); /* ** CAPI3REF: Count The Number Of Rows Modified ** METHOD: sqlite3 ** ** ^These functions return the number of rows modified, inserted or ** deleted by the most recently completed INSERT, UPDATE or DELETE ** statement on the database connection specified by the only parameter. ** The two functions are identical except for the type of the return value ** and that if the number of rows modified by the most recent INSERT, UPDATE ** or DELETE is greater than the maximum value supported by type "int", then ** the return value of sqlite3_changes() is undefined. ^Executing any other ** type of SQL statement does not modify the value returned by these functions. ** ** ^Only changes made directly by the INSERT, UPDATE or DELETE statement are ** considered - auxiliary changes caused by [CREATE TRIGGER | triggers], ** [foreign key actions] or [REPLACE] constraint resolution are not counted. ** ** Changes to a view that are intercepted by ** [INSTEAD OF trigger | INSTEAD OF triggers] are not counted. ^The value |
︙ | ︙ | |||
2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 | ** <li> the [sqlite3_total_changes()] interface ** <li> the [count_changes pragma] ** <li> the [changes() SQL function] ** <li> the [data_version pragma] ** </ul> */ int sqlite3_changes(sqlite3*); /* ** CAPI3REF: Total Number Of Rows Modified ** METHOD: sqlite3 ** | > | > > > > | | | > | 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 | ** <li> the [sqlite3_total_changes()] interface ** <li> the [count_changes pragma] ** <li> the [changes() SQL function] ** <li> the [data_version pragma] ** </ul> */ int sqlite3_changes(sqlite3*); sqlite3_int64 sqlite3_changes64(sqlite3*); /* ** CAPI3REF: Total Number Of Rows Modified ** METHOD: sqlite3 ** ** ^These functions return the total number of rows inserted, modified or ** deleted by all [INSERT], [UPDATE] or [DELETE] statements completed ** since the database connection was opened, including those executed as ** part of trigger programs. The two functions are identical except for the ** type of the return value and that if the number of rows modified by the ** connection exceeds the maximum value supported by type "int", then ** the return value of sqlite3_total_changes() is undefined. ^Executing ** any other type of SQL statement does not affect the value returned by ** sqlite3_total_changes(). ** ** ^Changes made as part of [foreign key actions] are included in the ** count, but those made as part of REPLACE constraint resolution are ** not. ^Changes to a view that are intercepted by INSTEAD OF triggers ** are not counted. ** ** The [sqlite3_total_changes(D)] interface only reports the number ** of rows that changed due to SQL statement run against database ** connection D. Any changes by other database connections are ignored. ** To detect changes against a database file from other database ** connections use the [PRAGMA data_version] command or the ** [SQLITE_FCNTL_DATA_VERSION] [file control]. ** ** If a separate thread makes changes on the same database connection ** while [sqlite3_total_changes()] is running then the value ** returned is unpredictable and not meaningful. ** ** See also: ** <ul> ** <li> the [sqlite3_changes()] interface ** <li> the [count_changes pragma] ** <li> the [changes() SQL function] ** <li> the [data_version pragma] ** <li> the [SQLITE_FCNTL_DATA_VERSION] [file control] ** </ul> */ int sqlite3_total_changes(sqlite3*); sqlite3_int64 sqlite3_total_changes64(sqlite3*); /* ** CAPI3REF: Interrupt A Long-Running Query ** METHOD: sqlite3 ** ** ^This function causes any pending database operation to abort and ** return at its earliest opportunity. This routine is typically |
︙ | ︙ | |||
2392 2393 2394 2395 2396 2397 2398 | ** ^If the interrupted SQL operation is an INSERT, UPDATE, or DELETE ** that is inside an explicit transaction, then the entire transaction ** will be rolled back automatically. ** ** ^The sqlite3_interrupt(D) call is in effect until all currently running ** SQL statements on [database connection] D complete. ^Any new SQL statements ** that are started after the sqlite3_interrupt() call and before the | | | 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 | ** ^If the interrupted SQL operation is an INSERT, UPDATE, or DELETE ** that is inside an explicit transaction, then the entire transaction ** will be rolled back automatically. ** ** ^The sqlite3_interrupt(D) call is in effect until all currently running ** SQL statements on [database connection] D complete. ^Any new SQL statements ** that are started after the sqlite3_interrupt() call and before the ** running statement count reaches zero are interrupted as if they had been ** running prior to the sqlite3_interrupt() call. ^New SQL statements ** that are started after the running statement count reaches zero are ** not effected by the sqlite3_interrupt(). ** ^A call to sqlite3_interrupt(D) that occurs when there are no running ** SQL statements is a no-op and has no effect on SQL statements ** that are started after the sqlite3_interrupt() call returns. */ |
︙ | ︙ | |||
2560 2561 2562 2563 2564 2565 2566 | ** Name | Age ** ----------------------- ** Alice | 43 ** Bob | 28 ** Cindy | 21 ** </pre></blockquote> ** | | | | 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 | ** Name | Age ** ----------------------- ** Alice | 43 ** Bob | 28 ** Cindy | 21 ** </pre></blockquote> ** ** There are two columns (M==2) and three rows (N==3). Thus the ** result table has 8 entries. Suppose the result table is stored ** in an array named azResult. Then azResult holds this content: ** ** <blockquote><pre> ** azResult[0] = "Name"; ** azResult[1] = "Age"; ** azResult[2] = "Alice"; ** azResult[3] = "43"; ** azResult[4] = "Bob"; |
︙ | ︙ | |||
2655 2656 2657 2658 2659 2660 2661 | char *sqlite3_vsnprintf(int,char*,const char*, va_list); /* ** CAPI3REF: Memory Allocation Subsystem ** ** The SQLite core uses these three routines for all of its own ** internal memory allocation needs. "Core" in the previous sentence | | | 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 | char *sqlite3_vsnprintf(int,char*,const char*, va_list); /* ** CAPI3REF: Memory Allocation Subsystem ** ** The SQLite core uses these three routines for all of its own ** internal memory allocation needs. "Core" in the previous sentence ** does not include operating-system specific [VFS] implementation. The ** Windows VFS uses native malloc() and free() for some operations. ** ** ^The sqlite3_malloc() routine returns a pointer to a block ** of memory at least N bytes in length, where N is the parameter. ** ^If sqlite3_malloc() is unable to obtain sufficient free ** memory, it returns a NULL pointer. ^If the parameter N to ** sqlite3_malloc() is zero or negative then sqlite3_malloc() returns |
︙ | ︙ | |||
2716 2717 2718 2719 2720 2721 2722 | ** ** ^The memory returned by sqlite3_malloc(), sqlite3_realloc(), ** sqlite3_malloc64(), and sqlite3_realloc64() ** is always aligned to at least an 8 byte boundary, or to a ** 4 byte boundary if the [SQLITE_4_BYTE_ALIGNED_MALLOC] compile-time ** option is used. ** | < < < < < < < < < < < < < | 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 | ** ** ^The memory returned by sqlite3_malloc(), sqlite3_realloc(), ** sqlite3_malloc64(), and sqlite3_realloc64() ** is always aligned to at least an 8 byte boundary, or to a ** 4 byte boundary if the [SQLITE_4_BYTE_ALIGNED_MALLOC] compile-time ** option is used. ** ** The pointer arguments to [sqlite3_free()] and [sqlite3_realloc()] ** must be either NULL or else pointers obtained from a prior ** invocation of [sqlite3_malloc()] or [sqlite3_realloc()] that have ** not yet been released. ** ** The application must not read or write any part of ** a block of memory after it has been released using |
︙ | ︙ | |||
2777 2778 2779 2780 2781 2782 2783 | /* ** CAPI3REF: Pseudo-Random Number Generator ** ** SQLite contains a high-quality pseudo-random number generator (PRNG) used to ** select random [ROWID | ROWIDs] when inserting new records into a table that ** already uses the largest possible [ROWID]. The PRNG is also used for | | | 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 | /* ** CAPI3REF: Pseudo-Random Number Generator ** ** SQLite contains a high-quality pseudo-random number generator (PRNG) used to ** select random [ROWID | ROWIDs] when inserting new records into a table that ** already uses the largest possible [ROWID]. The PRNG is also used for ** the built-in random() and randomblob() SQL functions. This interface allows ** applications to access the same PRNG for other purposes. ** ** ^A call to this routine stores N bytes of randomness into buffer P. ** ^The P parameter can be a NULL pointer. ** ** ^If this routine has not been previously called or if the previous ** call had N less than one or a NULL pointer for P, then the PRNG is |
︙ | ︙ | |||
3151 3152 3153 3154 3155 3156 3157 | ** Whether or not an error occurs when it is opened, resources ** associated with the [database connection] handle should be released by ** passing it to [sqlite3_close()] when it is no longer required. ** ** The sqlite3_open_v2() interface works like sqlite3_open() ** except that it accepts two additional parameters for additional control ** over the new database connection. ^(The flags parameter to | | | < < | | > > | > > > > > > | | > | < > > > | > | < > > > > | > | | > | > | > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 | ** Whether or not an error occurs when it is opened, resources ** associated with the [database connection] handle should be released by ** passing it to [sqlite3_close()] when it is no longer required. ** ** The sqlite3_open_v2() interface works like sqlite3_open() ** except that it accepts two additional parameters for additional control ** over the new database connection. ^(The flags parameter to ** sqlite3_open_v2() must include, at a minimum, one of the following ** three flag combinations:)^ ** ** <dl> ** ^(<dt>[SQLITE_OPEN_READONLY]</dt> ** <dd>The database is opened in read-only mode. If the database does not ** already exist, an error is returned.</dd>)^ ** ** ^(<dt>[SQLITE_OPEN_READWRITE]</dt> ** <dd>The database is opened for reading and writing if possible, or reading ** only if the file is write protected by the operating system. In either ** case the database must already exist, otherwise an error is returned.</dd>)^ ** ** ^(<dt>[SQLITE_OPEN_READWRITE] | [SQLITE_OPEN_CREATE]</dt> ** <dd>The database is opened for reading and writing, and is created if ** it does not already exist. This is the behavior that is always used for ** sqlite3_open() and sqlite3_open16().</dd>)^ ** </dl> ** ** In addition to the required flags, the following optional flags are ** also supported: ** ** <dl> ** ^(<dt>[SQLITE_OPEN_URI]</dt> ** <dd>The filename can be interpreted as a URI if this flag is set.</dd>)^ ** ** ^(<dt>[SQLITE_OPEN_MEMORY]</dt> ** <dd>The database will be opened as an in-memory database. The database ** is named by the "filename" argument for the purposes of cache-sharing, ** if shared cache mode is enabled, but the "filename" is otherwise ignored. ** </dd>)^ ** ** ^(<dt>[SQLITE_OPEN_NOMUTEX]</dt> ** <dd>The new database connection will use the "multi-thread" ** [threading mode].)^ This means that separate threads are allowed ** to use SQLite at the same time, as long as each thread is using ** a different [database connection]. ** ** ^(<dt>[SQLITE_OPEN_FULLMUTEX]</dt> ** <dd>The new database connection will use the "serialized" ** [threading mode].)^ This means the multiple threads can safely ** attempt to use the same database connection at the same time. ** (Mutexes will block any actual concurrency, but in this mode ** there is no harm in trying.) ** ** ^(<dt>[SQLITE_OPEN_SHAREDCACHE]</dt> ** <dd>The database is opened [shared cache] enabled, overriding ** the default shared cache setting provided by ** [sqlite3_enable_shared_cache()].)^ ** ** ^(<dt>[SQLITE_OPEN_PRIVATECACHE]</dt> ** <dd>The database is opened [shared cache] disabled, overriding ** the default shared cache setting provided by ** [sqlite3_enable_shared_cache()].)^ ** ** [[OPEN_EXRESCODE]] ^(<dt>[SQLITE_OPEN_EXRESCODE]</dt> ** <dd>The database connection comes up in "extended result code mode". ** In other words, the database behaves has if ** [sqlite3_extended_result_codes(db,1)] where called on the database ** connection as soon as the connection is created. In addition to setting ** the extended result code mode, this flag also causes [sqlite3_open_v2()] ** to return an extended result code.</dd> ** ** [[OPEN_NOFOLLOW]] ^(<dt>[SQLITE_OPEN_NOFOLLOW]</dt> ** <dd>The database filename is not allowed to be a symbolic link</dd> ** </dl>)^ ** ** If the 3rd parameter to sqlite3_open_v2() is not one of the ** required combinations shown above optionally combined with other ** [SQLITE_OPEN_READONLY | SQLITE_OPEN_* bits] ** then the behavior is undefined. Historic versions of SQLite ** have silently ignored surplus bits in the flags parameter to ** sqlite3_open_v2(), however that behavior might not be carried through ** into future versions of SQLite and so applications should not rely ** upon it. Note in particular that the SQLITE_OPEN_EXCLUSIVE flag is a no-op ** for sqlite3_open_v2(). The SQLITE_OPEN_EXCLUSIVE does *not* cause ** the open to fail if the database already exists. The SQLITE_OPEN_EXCLUSIVE ** flag is intended for use by the [sqlite3_vfs|VFS interface] only, and not ** by sqlite3_open_v2(). ** ** ^The fourth parameter to sqlite3_open_v2() is the name of the ** [sqlite3_vfs] object that defines the operating system interface that ** the new database connection should use. ^If the fourth parameter is ** a NULL pointer then the default [sqlite3_vfs] object is used. ** ** ^If the filename is ":memory:", then a private, temporary in-memory database |
︙ | ︙ | |||
3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 | ** Regardless of whether or not shared-cache mode is enabled by ** default, use a private cache. ** <tr><td> file:/home/fred/data.db?vfs=unix-dotfile <td> ** Open file "/home/fred/data.db". Use the special VFS "unix-dotfile" ** that uses dot-files in place of posix advisory locking. ** <tr><td> file:data.db?mode=readonly <td> ** An error. "readonly" is not a valid option for the "mode" parameter. ** </table> ** ** ^URI hexadecimal escape sequences (%HH) are supported within the path and ** query components of a URI. A hexadecimal escape sequence consists of a ** percent sign - "%" - followed by exactly two hexadecimal digits ** specifying an octet value. ^Before the path or query components of a ** URI filename are interpreted, they are encoded using UTF-8 and all | > | 3589 3590 3591 3592 3593 3594 3595 3596 3597 3598 3599 3600 3601 3602 3603 | ** Regardless of whether or not shared-cache mode is enabled by ** default, use a private cache. ** <tr><td> file:/home/fred/data.db?vfs=unix-dotfile <td> ** Open file "/home/fred/data.db". Use the special VFS "unix-dotfile" ** that uses dot-files in place of posix advisory locking. ** <tr><td> file:data.db?mode=readonly <td> ** An error. "readonly" is not a valid option for the "mode" parameter. ** Use "ro" instead: "file:data.db?mode=ro". ** </table> ** ** ^URI hexadecimal escape sequences (%HH) are supported within the path and ** query components of a URI. A hexadecimal escape sequence consists of a ** percent sign - "%" - followed by exactly two hexadecimal digits ** specifying an octet value. ^Before the path or query components of a ** URI filename are interpreted, they are encoded using UTF-8 and all |
︙ | ︙ | |||
3368 3369 3370 3371 3372 3373 3374 | int flags, /* Flags */ const char *zVfs /* Name of VFS module to use */ ); /* ** CAPI3REF: Obtain Values For URI Parameters ** | | | > > > > | > > > | > | > > | | | > > > > > > > | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | int flags, /* Flags */ const char *zVfs /* Name of VFS module to use */ ); /* ** CAPI3REF: Obtain Values For URI Parameters ** ** These are utility routines, useful to [VFS|custom VFS implementations], ** that check if a database file was a URI that contained a specific query ** parameter, and if so obtains the value of that query parameter. ** ** The first parameter to these interfaces (hereafter referred to ** as F) must be one of: ** <ul> ** <li> A database filename pointer created by the SQLite core and ** passed into the xOpen() method of a VFS implemention, or ** <li> A filename obtained from [sqlite3_db_filename()], or ** <li> A new filename constructed using [sqlite3_create_filename()]. ** </ul> ** If the F parameter is not one of the above, then the behavior is ** undefined and probably undesirable. Older versions of SQLite were ** more tolerant of invalid F parameters than newer versions. ** ** If F is a suitable filename (as described in the previous paragraph) ** and if P is the name of the query parameter, then ** sqlite3_uri_parameter(F,P) returns the value of the P ** parameter if it exists or a NULL pointer if P does not appear as a ** query parameter on F. If P is a query parameter of F and it ** has no explicit value, then sqlite3_uri_parameter(F,P) returns ** a pointer to an empty string. ** ** The sqlite3_uri_boolean(F,P,B) routine assumes that P is a boolean ** parameter and returns true (1) or false (0) according to the value ** of P. The sqlite3_uri_boolean(F,P,B) routine returns true (1) if the ** value of query parameter P is one of "yes", "true", or "on" in any ** case or if the value begins with a non-zero number. The ** sqlite3_uri_boolean(F,P,B) routines returns false (0) if the value of ** query parameter P is one of "no", "false", or "off" in any case or ** if the value begins with a numeric zero. If P is not a query ** parameter on F or if the value of P does not match any of the ** above, then sqlite3_uri_boolean(F,P,B) returns (B!=0). ** ** The sqlite3_uri_int64(F,P,D) routine converts the value of P into a ** 64-bit signed integer and returns that integer, or D if P does not ** exist. If the value of P is something other than an integer, then ** zero is returned. ** ** The sqlite3_uri_key(F,N) returns a pointer to the name (not ** the value) of the N-th query parameter for filename F, or a NULL ** pointer if N is less than zero or greater than the number of query ** parameters minus 1. The N value is zero-based so N should be 0 to obtain ** the name of the first query parameter, 1 for the second parameter, and ** so forth. ** ** If F is a NULL pointer, then sqlite3_uri_parameter(F,P) returns NULL and ** sqlite3_uri_boolean(F,P,B) returns B. If F is not a NULL pointer and ** is not a database file pathname pointer that the SQLite core passed ** into the xOpen VFS method, then the behavior of this routine is undefined ** and probably undesirable. ** ** Beginning with SQLite [version 3.31.0] ([dateof:3.31.0]) the input F ** parameter can also be the name of a rollback journal file or WAL file ** in addition to the main database file. Prior to version 3.31.0, these ** routines would only work if F was the name of the main database file. ** When the F parameter is the name of the rollback journal or WAL file, ** it has access to all the same query parameters as were found on the ** main database file. ** ** See the [URI filename] documentation for additional information. */ const char *sqlite3_uri_parameter(const char *zFilename, const char *zParam); int sqlite3_uri_boolean(const char *zFile, const char *zParam, int bDefault); sqlite3_int64 sqlite3_uri_int64(const char*, const char*, sqlite3_int64); const char *sqlite3_uri_key(const char *zFilename, int N); /* ** CAPI3REF: Translate filenames ** ** These routines are available to [VFS|custom VFS implementations] for ** translating filenames between the main database file, the journal file, ** and the WAL file. ** ** If F is the name of an sqlite database file, journal file, or WAL file ** passed by the SQLite core into the VFS, then sqlite3_filename_database(F) ** returns the name of the corresponding database file. ** ** If F is the name of an sqlite database file, journal file, or WAL file ** passed by the SQLite core into the VFS, or if F is a database filename ** obtained from [sqlite3_db_filename()], then sqlite3_filename_journal(F) ** returns the name of the corresponding rollback journal file. ** ** If F is the name of an sqlite database file, journal file, or WAL file ** that was passed by the SQLite core into the VFS, or if F is a database ** filename obtained from [sqlite3_db_filename()], then ** sqlite3_filename_wal(F) returns the name of the corresponding ** WAL file. ** ** In all of the above, if F is not the name of a database, journal or WAL ** filename passed into the VFS from the SQLite core and F is not the ** return value from [sqlite3_db_filename()], then the result is ** undefined and is likely a memory access violation. */ const char *sqlite3_filename_database(const char*); const char *sqlite3_filename_journal(const char*); const char *sqlite3_filename_wal(const char*); /* ** CAPI3REF: Database File Corresponding To A Journal ** ** ^If X is the name of a rollback or WAL-mode journal file that is ** passed into the xOpen method of [sqlite3_vfs], then ** sqlite3_database_file_object(X) returns a pointer to the [sqlite3_file] ** object that represents the main database file. ** ** This routine is intended for use in custom [VFS] implementations ** only. It is not a general-purpose interface. ** The argument sqlite3_file_object(X) must be a filename pointer that ** has been passed into [sqlite3_vfs].xOpen method where the ** flags parameter to xOpen contains one of the bits ** [SQLITE_OPEN_MAIN_JOURNAL] or [SQLITE_OPEN_WAL]. Any other use ** of this routine results in undefined and probably undesirable ** behavior. */ sqlite3_file *sqlite3_database_file_object(const char*); /* ** CAPI3REF: Create and Destroy VFS Filenames ** ** These interfces are provided for use by [VFS shim] implementations and ** are not useful outside of that context. ** ** The sqlite3_create_filename(D,J,W,N,P) allocates memory to hold a version of ** database filename D with corresponding journal file J and WAL file W and ** with N URI parameters key/values pairs in the array P. The result from ** sqlite3_create_filename(D,J,W,N,P) is a pointer to a database filename that ** is safe to pass to routines like: ** <ul> ** <li> [sqlite3_uri_parameter()], ** <li> [sqlite3_uri_boolean()], ** <li> [sqlite3_uri_int64()], ** <li> [sqlite3_uri_key()], ** <li> [sqlite3_filename_database()], ** <li> [sqlite3_filename_journal()], or ** <li> [sqlite3_filename_wal()]. ** </ul> ** If a memory allocation error occurs, sqlite3_create_filename() might ** return a NULL pointer. The memory obtained from sqlite3_create_filename(X) ** must be released by a corresponding call to sqlite3_free_filename(Y). ** ** The P parameter in sqlite3_create_filename(D,J,W,N,P) should be an array ** of 2*N pointers to strings. Each pair of pointers in this array corresponds ** to a key and value for a query parameter. The P parameter may be a NULL ** pointer if N is zero. None of the 2*N pointers in the P array may be ** NULL pointers and key pointers should not be empty strings. ** None of the D, J, or W parameters to sqlite3_create_filename(D,J,W,N,P) may ** be NULL pointers, though they can be empty strings. ** ** The sqlite3_free_filename(Y) routine releases a memory allocation ** previously obtained from sqlite3_create_filename(). Invoking ** sqlite3_free_filename(Y) where Y is a NULL pointer is a harmless no-op. ** ** If the Y parameter to sqlite3_free_filename(Y) is anything other ** than a NULL pointer or a pointer previously acquired from ** sqlite3_create_filename(), then bad things such as heap ** corruption or segfaults may occur. The value Y should not be ** used again after sqlite3_free_filename(Y) has been called. This means ** that if the [sqlite3_vfs.xOpen()] method of a VFS has been called using Y, ** then the corresponding [sqlite3_module.xClose() method should also be ** invoked prior to calling sqlite3_free_filename(Y). */ char *sqlite3_create_filename( const char *zDatabase, const char *zJournal, const char *zWal, int nParam, const char **azParam ); void sqlite3_free_filename(char*); /* ** CAPI3REF: Error Codes And Messages ** METHOD: sqlite3 ** ** ^If the most recent sqlite3_* API call associated with ** [database connection] D failed, then the sqlite3_errcode(D) interface |
︙ | ︙ | |||
3632 3633 3634 3635 3636 3637 3638 3639 3640 3641 3642 3643 3644 3645 3646 3647 3648 3649 | ** [[SQLITE_PREPARE_NORMALIZE]] <dt>SQLITE_PREPARE_NORMALIZE</dt> ** <dd>The SQLITE_PREPARE_NORMALIZE flag is a no-op. This flag used ** to be required for any prepared statement that wanted to use the ** [sqlite3_normalized_sql()] interface. However, the ** [sqlite3_normalized_sql()] interface is now available to all ** prepared statements, regardless of whether or not they use this ** flag. ** </dl> */ #define SQLITE_PREPARE_PERSISTENT 0x01 #define SQLITE_PREPARE_NORMALIZE 0x02 /* ** CAPI3REF: Compiling An SQL Statement ** KEYWORDS: {SQL statement compiler} ** METHOD: sqlite3 ** CONSTRUCTOR: sqlite3_stmt ** | > > > > > > | 4026 4027 4028 4029 4030 4031 4032 4033 4034 4035 4036 4037 4038 4039 4040 4041 4042 4043 4044 4045 4046 4047 4048 4049 | ** [[SQLITE_PREPARE_NORMALIZE]] <dt>SQLITE_PREPARE_NORMALIZE</dt> ** <dd>The SQLITE_PREPARE_NORMALIZE flag is a no-op. This flag used ** to be required for any prepared statement that wanted to use the ** [sqlite3_normalized_sql()] interface. However, the ** [sqlite3_normalized_sql()] interface is now available to all ** prepared statements, regardless of whether or not they use this ** flag. ** ** [[SQLITE_PREPARE_NO_VTAB]] <dt>SQLITE_PREPARE_NO_VTAB</dt> ** <dd>The SQLITE_PREPARE_NO_VTAB flag causes the SQL compiler ** to return an error (error code SQLITE_ERROR) if the statement uses ** any virtual tables. ** </dl> */ #define SQLITE_PREPARE_PERSISTENT 0x01 #define SQLITE_PREPARE_NORMALIZE 0x02 #define SQLITE_PREPARE_NO_VTAB 0x04 /* ** CAPI3REF: Compiling An SQL Statement ** KEYWORDS: {SQL statement compiler} ** METHOD: sqlite3 ** CONSTRUCTOR: sqlite3_stmt ** |
︙ | ︙ | |||
3719 3720 3721 3722 3723 3724 3725 | ** [sqlite3_step()] would only return a generic [SQLITE_ERROR] result code ** and the application would have to make a second call to [sqlite3_reset()] ** in order to find the underlying cause of the problem. With the "v2" prepare ** interfaces, the underlying reason for the error is returned immediately. ** </li> ** ** <li> | | | | | | 4119 4120 4121 4122 4123 4124 4125 4126 4127 4128 4129 4130 4131 4132 4133 4134 4135 4136 4137 4138 4139 4140 4141 | ** [sqlite3_step()] would only return a generic [SQLITE_ERROR] result code ** and the application would have to make a second call to [sqlite3_reset()] ** in order to find the underlying cause of the problem. With the "v2" prepare ** interfaces, the underlying reason for the error is returned immediately. ** </li> ** ** <li> ** ^If the specific value bound to a [parameter | host parameter] in the ** WHERE clause might influence the choice of query plan for a statement, ** then the statement will be automatically recompiled, as if there had been ** a schema change, on the first [sqlite3_step()] call following any change ** to the [sqlite3_bind_text | bindings] of that [parameter]. ** ^The specific value of a WHERE-clause [parameter] might influence the ** choice of query plan if the parameter is the left-hand side of a [LIKE] ** or [GLOB] operator or if the parameter is compared to an indexed column ** and the [SQLITE_ENABLE_STAT4] compile-time option is enabled. ** </li> ** </ol> ** ** <p>^sqlite3_prepare_v3() differs from sqlite3_prepare_v2() only in having ** the extra prepFlags parameter, which is a bit array consisting of zero or ** more of the [SQLITE_PREPARE_PERSISTENT|SQLITE_PREPARE_*] flags. ^The ** sqlite3_prepare_v2() interface works exactly the same as |
︙ | ︙ | |||
3817 3818 3819 3820 3821 3822 3823 | ** bound parameter expansions. ^The [SQLITE_OMIT_TRACE] compile-time ** option causes sqlite3_expanded_sql() to always return NULL. ** ** ^The strings returned by sqlite3_sql(P) and sqlite3_normalized_sql(P) ** are managed by SQLite and are automatically freed when the prepared ** statement is finalized. ** ^The string returned by sqlite3_expanded_sql(P), on the other hand, | | > > > > > | 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 | ** bound parameter expansions. ^The [SQLITE_OMIT_TRACE] compile-time ** option causes sqlite3_expanded_sql() to always return NULL. ** ** ^The strings returned by sqlite3_sql(P) and sqlite3_normalized_sql(P) ** are managed by SQLite and are automatically freed when the prepared ** statement is finalized. ** ^The string returned by sqlite3_expanded_sql(P), on the other hand, ** is obtained from [sqlite3_malloc()] and must be freed by the application ** by passing it to [sqlite3_free()]. ** ** ^The sqlite3_normalized_sql() interface is only available if ** the [SQLITE_ENABLE_NORMALIZE] compile-time option is defined. */ const char *sqlite3_sql(sqlite3_stmt *pStmt); char *sqlite3_expanded_sql(sqlite3_stmt *pStmt); #ifdef SQLITE_ENABLE_NORMALIZE const char *sqlite3_normalized_sql(sqlite3_stmt *pStmt); #endif /* ** CAPI3REF: Determine If An SQL Statement Writes The Database ** METHOD: sqlite3_stmt ** ** ^The sqlite3_stmt_readonly(X) interface returns true (non-zero) if ** and only if the [prepared statement] X makes no direct changes to |
︙ | ︙ | |||
3857 3858 3859 3860 3861 3862 3863 3864 3865 3866 3867 3868 3869 3870 3871 3872 3873 | ** sqlite3_stmt_readonly() to return true since, while those statements ** change the configuration of a database connection, they do not make ** changes to the content of the database files on disk. ** ^The sqlite3_stmt_readonly() interface returns true for [BEGIN] since ** [BEGIN] merely sets internal flags, but the [BEGIN|BEGIN IMMEDIATE] and ** [BEGIN|BEGIN EXCLUSIVE] commands do touch the database and so ** sqlite3_stmt_readonly() returns false for those commands. */ int sqlite3_stmt_readonly(sqlite3_stmt *pStmt); /* ** CAPI3REF: Determine If A Prepared Statement Has Been Reset ** METHOD: sqlite3_stmt ** ** ^The sqlite3_stmt_busy(S) interface returns true (non-zero) if the ** [prepared statement] S has been stepped at least once using ** [sqlite3_step(S)] but has neither run to completion (returned | > > > > > > > > > > > > > > > > > > > > > | 4262 4263 4264 4265 4266 4267 4268 4269 4270 4271 4272 4273 4274 4275 4276 4277 4278 4279 4280 4281 4282 4283 4284 4285 4286 4287 4288 4289 4290 4291 4292 4293 4294 4295 4296 4297 4298 4299 | ** sqlite3_stmt_readonly() to return true since, while those statements ** change the configuration of a database connection, they do not make ** changes to the content of the database files on disk. ** ^The sqlite3_stmt_readonly() interface returns true for [BEGIN] since ** [BEGIN] merely sets internal flags, but the [BEGIN|BEGIN IMMEDIATE] and ** [BEGIN|BEGIN EXCLUSIVE] commands do touch the database and so ** sqlite3_stmt_readonly() returns false for those commands. ** ** ^This routine returns false if there is any possibility that the ** statement might change the database file. ^A false return does ** not guarantee that the statement will change the database file. ** ^For example, an UPDATE statement might have a WHERE clause that ** makes it a no-op, but the sqlite3_stmt_readonly() result would still ** be false. ^Similarly, a CREATE TABLE IF NOT EXISTS statement is a ** read-only no-op if the table already exists, but ** sqlite3_stmt_readonly() still returns false for such a statement. */ int sqlite3_stmt_readonly(sqlite3_stmt *pStmt); /* ** CAPI3REF: Query The EXPLAIN Setting For A Prepared Statement ** METHOD: sqlite3_stmt ** ** ^The sqlite3_stmt_isexplain(S) interface returns 1 if the ** prepared statement S is an EXPLAIN statement, or 2 if the ** statement S is an EXPLAIN QUERY PLAN. ** ^The sqlite3_stmt_isexplain(S) interface returns 0 if S is ** an ordinary statement or a NULL pointer. */ int sqlite3_stmt_isexplain(sqlite3_stmt *pStmt); /* ** CAPI3REF: Determine If A Prepared Statement Has Been Reset ** METHOD: sqlite3_stmt ** ** ^The sqlite3_stmt_busy(S) interface returns true (non-zero) if the ** [prepared statement] S has been stepped at least once using ** [sqlite3_step(S)] but has neither run to completion (returned |
︙ | ︙ | |||
3972 3973 3974 3975 3976 3977 3978 | ** ^The leftmost SQL parameter has an index of 1. ^When the same named ** SQL parameter is used more than once, second and subsequent ** occurrences have the same index as the first occurrence. ** ^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()] | | > > > > > > > > > > > > > > > > > > | | | > | | | > | < > > > > | < | > > | 4398 4399 4400 4401 4402 4403 4404 4405 4406 4407 4408 4409 4410 4411 4412 4413 4414 4415 4416 4417 4418 4419 4420 4421 4422 4423 4424 4425 4426 4427 4428 4429 4430 4431 4432 4433 4434 4435 4436 4437 4438 4439 4440 4441 4442 4443 4444 4445 4446 4447 4448 4449 4450 4451 4452 4453 4454 4455 4456 4457 4458 4459 4460 4461 4462 4463 4464 4465 4466 4467 4468 4469 | ** ^The leftmost SQL parameter has an index of 1. ^When the same named ** SQL parameter is used more than once, second and subsequent ** occurrences have the same index as the first occurrence. ** ^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: 32766). ** ** ^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(). ** ^If the third parameter to sqlite3_bind_text() is not NULL, then ** it should be a pointer to well-formed UTF8 text. ** ^If the third parameter to sqlite3_bind_text16() is not NULL, then ** it should be a pointer to well-formed UTF16 text. ** ^If the third parameter to sqlite3_bind_text64() is not NULL, then ** it should be a pointer to a well-formed unicode string that is ** either UTF8 if the sixth parameter is SQLITE_UTF8, or UTF16 ** otherwise. ** ** [[byte-order determination rules]] ^The byte-order of ** UTF16 input text is determined by the byte-order mark (BOM, U+FEFF) ** found in first character, which is removed, or in the absence of a BOM ** the byte order is the native byte order of the host ** machine for sqlite3_bind_text16() or the byte order specified in ** the 6th parameter for sqlite3_bind_text64().)^ ** ^If UTF16 input text contains invalid unicode ** characters, then SQLite might change those invalid characters ** into the unicode replacement character: U+FFFD. ** ** ^(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. ** If the fourth parameter to sqlite3_bind_blob() is negative, then ** the behavior is undefined. ** If a non-negative fourth parameter is provided to sqlite3_bind_text() ** or sqlite3_bind_text16() or sqlite3_bind_text64() then ** that parameter must be the byte offset ** where the NUL terminator would occur assuming the string were NUL ** terminated. If any NUL characters occurs at byte offsets less than ** the value of the fourth parameter then the resulting string value will ** contain embedded NULs. The result of expressions involving strings ** with embedded NULs is undefined. ** ** ^The fifth argument to the BLOB and string binding interfaces controls ** or indicates the lifetime of the object referenced by the third parameter. ** These three options exist: ** ^ (1) A destructor to dispose of the BLOB or string after SQLite has finished ** with it may be passed. ^It is called to dispose of the BLOB or string even ** if the call to the bind API fails, except the destructor is not called if ** the third parameter is a NULL pointer or the fourth parameter is negative. ** ^ (2) The special constant, [SQLITE_STATIC], may be passsed to indicate that ** the application remains responsible for disposing of the object. ^In this ** case, the object and the provided pointer to it must remain valid until ** either the prepared statement is finalized or the same SQL parameter is ** bound to something else, whichever occurs sooner. ** ^ (3) The constant, [SQLITE_TRANSIENT], may be passed to indicate that the ** object is to be copied prior to the return from sqlite3_bind_*(). ^The ** object and pointer to it must remain valid until then. ^SQLite will then ** manage the lifetime of its private copy. ** ** ^The sixth argument to sqlite3_bind_text64() must be one of ** [SQLITE_UTF8], [SQLITE_UTF16], [SQLITE_UTF16BE], or [SQLITE_UTF16LE] ** to specify the encoding of the text in the third parameter. If ** the sixth argument to sqlite3_bind_text64() is not one of the ** allowed values shown above, or if the text encoding is different ** from the encoding specified by the sixth parameter, then the behavior |
︙ | ︙ | |||
4219 4220 4221 4222 4223 4224 4225 | ** ^The first argument to these interfaces is a [prepared statement]. ** ^These functions return information about the Nth result column returned by ** the statement, where N is the second function argument. ** ^The left-most column is column 0 for these routines. ** ** ^If the Nth column returned by the statement is an expression or ** subquery and is not a column value, then all of these functions return | | < < < < | 4669 4670 4671 4672 4673 4674 4675 4676 4677 4678 4679 4680 4681 4682 4683 4684 4685 4686 4687 4688 4689 4690 4691 4692 | ** ^The first argument to these interfaces is a [prepared statement]. ** ^These functions return information about the Nth result column returned by ** the statement, where N is the second function argument. ** ^The left-most column is column 0 for these routines. ** ** ^If the Nth column returned by the statement is an expression or ** subquery and is not a column value, then all of these functions return ** NULL. ^These routines might also return NULL if a memory allocation error ** occurs. ^Otherwise, they return the name of the attached database, table, ** or column that query result column was extracted from. ** ** ^As with all other SQLite APIs, those whose names end with "16" return ** UTF-16 encoded strings and the other functions return UTF-8. ** ** ^These APIs are only available if the library was compiled with the ** [SQLITE_ENABLE_COLUMN_METADATA] C-preprocessor symbol. ** ** If two or more threads call one or more ** [sqlite3_column_database_name | column metadata interfaces] ** for the same [prepared statement] and result column ** at the same time then the results are undefined. */ const char *sqlite3_column_database_name(sqlite3_stmt*,int); const void *sqlite3_column_database_name16(sqlite3_stmt*,int); |
︙ | ︙ | |||
4369 4370 4371 4372 4373 4374 4375 | /* ** CAPI3REF: Number of columns in a result set ** METHOD: sqlite3_stmt ** ** ^The sqlite3_data_count(P) interface returns the number of columns in the ** current row of the result set of [prepared statement] P. ** ^If prepared statement P does not have results ready to return | | | 4815 4816 4817 4818 4819 4820 4821 4822 4823 4824 4825 4826 4827 4828 4829 | /* ** CAPI3REF: Number of columns in a result set ** METHOD: sqlite3_stmt ** ** ^The sqlite3_data_count(P) interface returns the number of columns in the ** current row of the result set of [prepared statement] P. ** ^If prepared statement P does not have results ready to return ** (via calls to the [sqlite3_column_int | sqlite3_column()] family of ** interfaces) then sqlite3_data_count(P) returns 0. ** ^The sqlite3_data_count(P) routine also returns 0 if P is a NULL pointer. ** ^The sqlite3_data_count(P) routine returns 0 if the previous call to ** [sqlite3_step](P) returned [SQLITE_DONE]. ^The sqlite3_data_count(P) ** will return non-zero if previous call to [sqlite3_step](P) returned ** [SQLITE_ROW], except in the case of the [PRAGMA incremental_vacuum] ** where it always returns zero since each step of that multi-step |
︙ | ︙ | |||
4693 4694 4695 4696 4697 4698 4699 | ** of any [sqlite3_bind_blob|bindings] on the [prepared statement] S. */ int sqlite3_reset(sqlite3_stmt *pStmt); /* ** CAPI3REF: Create Or Redefine SQL Functions ** KEYWORDS: {function creation routines} | < < | 5139 5140 5141 5142 5143 5144 5145 5146 5147 5148 5149 5150 5151 5152 | ** of any [sqlite3_bind_blob|bindings] on the [prepared statement] S. */ int sqlite3_reset(sqlite3_stmt *pStmt); /* ** CAPI3REF: Create Or Redefine SQL Functions ** KEYWORDS: {function creation routines} ** METHOD: sqlite3 ** ** ^These functions (collectively known as "function creation routines") ** are used to add SQL functions or aggregates or to redefine the behavior ** of existing SQL functions or aggregates. The only differences between ** the three "sqlite3_create_function*" routines are the text encoding ** expected for the second parameter (the name of the function being |
︙ | ︙ | |||
4747 4748 4749 4750 4751 4752 4753 4754 4755 4756 4757 4758 4759 4760 | ** ^The fourth parameter may optionally be ORed with [SQLITE_DETERMINISTIC] ** to signal that the function will always return the same result given ** the same inputs within a single SQL statement. Most SQL functions are ** deterministic. The built-in [random()] SQL function is an example of a ** function that is not deterministic. The SQLite query planner is able to ** perform additional optimizations on deterministic functions, so use ** of the [SQLITE_DETERMINISTIC] flag is recommended where possible. ** ** ^(The fifth parameter is an arbitrary pointer. The implementation of the ** function can gain access to this pointer using [sqlite3_user_data()].)^ ** ** ^The sixth, seventh and eighth parameters passed to the three ** "sqlite3_create_function*" functions, xFunc, xStep and xFinal, are ** pointers to C-language functions that implement the SQL function or | > > > > > > > > > > > > > > > | 5191 5192 5193 5194 5195 5196 5197 5198 5199 5200 5201 5202 5203 5204 5205 5206 5207 5208 5209 5210 5211 5212 5213 5214 5215 5216 5217 5218 5219 | ** ^The fourth parameter may optionally be ORed with [SQLITE_DETERMINISTIC] ** to signal that the function will always return the same result given ** the same inputs within a single SQL statement. Most SQL functions are ** deterministic. The built-in [random()] SQL function is an example of a ** function that is not deterministic. The SQLite query planner is able to ** perform additional optimizations on deterministic functions, so use ** of the [SQLITE_DETERMINISTIC] flag is recommended where possible. ** ** ^The fourth parameter may also optionally include the [SQLITE_DIRECTONLY] ** flag, which if present prevents the function from being invoked from ** within VIEWs, TRIGGERs, CHECK constraints, generated column expressions, ** index expressions, or the WHERE clause of partial indexes. ** ** For best security, the [SQLITE_DIRECTONLY] flag is recommended for ** all application-defined SQL functions that do not need to be ** used inside of triggers, view, CHECK constraints, or other elements of ** the database schema. This flags is especially recommended for SQL ** functions that have side effects or reveal internal application state. ** Without this flag, an attacker might be able to modify the schema of ** a database file to include invocations of the function with parameters ** chosen by the attacker, which the application will then execute when ** the database file is opened and read. ** ** ^(The fifth parameter is an arbitrary pointer. The implementation of the ** function can gain access to this pointer using [sqlite3_user_data()].)^ ** ** ^The sixth, seventh and eighth parameters passed to the three ** "sqlite3_create_function*" functions, xFunc, xStep and xFinal, are ** pointers to C-language functions that implement the SQL function or |
︙ | ︙ | |||
4864 4865 4866 4867 4868 4869 4870 4871 | /* ** CAPI3REF: Function Flags ** ** These constants may be ORed together with the ** [SQLITE_UTF8 | preferred text encoding] as the fourth argument ** to [sqlite3_create_function()], [sqlite3_create_function16()], or ** [sqlite3_create_function_v2()]. */ | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > | 5323 5324 5325 5326 5327 5328 5329 5330 5331 5332 5333 5334 5335 5336 5337 5338 5339 5340 5341 5342 5343 5344 5345 5346 5347 5348 5349 5350 5351 5352 5353 5354 5355 5356 5357 5358 5359 5360 5361 5362 5363 5364 5365 5366 5367 5368 5369 5370 5371 5372 5373 5374 5375 5376 5377 5378 5379 5380 5381 5382 5383 5384 5385 5386 5387 5388 5389 5390 5391 5392 5393 5394 5395 5396 5397 5398 | /* ** CAPI3REF: Function Flags ** ** These constants may be ORed together with the ** [SQLITE_UTF8 | preferred text encoding] as the fourth argument ** to [sqlite3_create_function()], [sqlite3_create_function16()], or ** [sqlite3_create_function_v2()]. ** ** <dl> ** [[SQLITE_DETERMINISTIC]] <dt>SQLITE_DETERMINISTIC</dt><dd> ** The SQLITE_DETERMINISTIC flag means that the new function always gives ** the same output when the input parameters are the same. ** The [abs|abs() function] is deterministic, for example, but ** [randomblob|randomblob()] is not. Functions must ** be deterministic in order to be used in certain contexts such as ** with the WHERE clause of [partial indexes] or in [generated columns]. ** SQLite might also optimize deterministic functions by factoring them ** out of inner loops. ** </dd> ** ** [[SQLITE_DIRECTONLY]] <dt>SQLITE_DIRECTONLY</dt><dd> ** The SQLITE_DIRECTONLY flag means that the function may only be invoked ** from top-level SQL, and cannot be used in VIEWs or TRIGGERs nor in ** schema structures such as [CHECK constraints], [DEFAULT clauses], ** [expression indexes], [partial indexes], or [generated columns]. ** The SQLITE_DIRECTONLY flags is a security feature which is recommended ** for all [application-defined SQL functions], and especially for functions ** that have side-effects or that could potentially leak sensitive ** information. ** </dd> ** ** [[SQLITE_INNOCUOUS]] <dt>SQLITE_INNOCUOUS</dt><dd> ** The SQLITE_INNOCUOUS flag means that the function is unlikely ** to cause problems even if misused. An innocuous function should have ** no side effects and should not depend on any values other than its ** input parameters. The [abs|abs() function] is an example of an ** innocuous function. ** The [load_extension() SQL function] is not innocuous because of its ** side effects. ** <p> SQLITE_INNOCUOUS is similar to SQLITE_DETERMINISTIC, but is not ** exactly the same. The [random|random() function] is an example of a ** function that is innocuous but not deterministic. ** <p>Some heightened security settings ** ([SQLITE_DBCONFIG_TRUSTED_SCHEMA] and [PRAGMA trusted_schema=OFF]) ** disable the use of SQL functions inside views and triggers and in ** schema structures such as [CHECK constraints], [DEFAULT clauses], ** [expression indexes], [partial indexes], and [generated columns] unless ** the function is tagged with SQLITE_INNOCUOUS. Most built-in functions ** are innocuous. Developers are advised to avoid using the ** SQLITE_INNOCUOUS flag for application-defined functions unless the ** function has been carefully audited and found to be free of potentially ** security-adverse side-effects and information-leaks. ** </dd> ** ** [[SQLITE_SUBTYPE]] <dt>SQLITE_SUBTYPE</dt><dd> ** The SQLITE_SUBTYPE flag indicates to SQLite that a function may call ** [sqlite3_value_subtype()] to inspect the sub-types of its arguments. ** Specifying this flag makes no difference for scalar or aggregate user ** functions. However, if it is not specified for a user-defined window ** function, then any sub-types belonging to arguments passed to the window ** function may be discarded before the window function is called (i.e. ** sqlite3_value_subtype() will always return 0). ** </dd> ** </dl> */ #define SQLITE_DETERMINISTIC 0x000000800 #define SQLITE_DIRECTONLY 0x000080000 #define SQLITE_SUBTYPE 0x000100000 #define SQLITE_INNOCUOUS 0x000200000 /* ** CAPI3REF: Deprecated Functions ** DEPRECATED ** ** These functions are [deprecated]. In order to maintain ** backwards compatibility with older code, these functions continue |
︙ | ︙ | |||
4916 4917 4918 4919 4920 4921 4922 4923 4924 4925 4926 4927 4928 | ** <tr><td><b>sqlite3_value_type</b><td>→<td>Default ** datatype of the value ** <tr><td><b>sqlite3_value_numeric_type </b> ** <td>→ <td>Best numeric datatype of the value ** <tr><td><b>sqlite3_value_nochange </b> ** <td>→ <td>True if the column is unchanged in an UPDATE ** against a virtual table. ** </table></blockquote> ** ** <b>Details:</b> ** ** These routines extract type, size, and content information from ** [protected sqlite3_value] objects. Protected sqlite3_value objects | > > | | | 5435 5436 5437 5438 5439 5440 5441 5442 5443 5444 5445 5446 5447 5448 5449 5450 5451 5452 5453 5454 5455 5456 5457 5458 | ** <tr><td><b>sqlite3_value_type</b><td>→<td>Default ** datatype of the value ** <tr><td><b>sqlite3_value_numeric_type </b> ** <td>→ <td>Best numeric datatype of the value ** <tr><td><b>sqlite3_value_nochange </b> ** <td>→ <td>True if the column is unchanged in an UPDATE ** against a virtual table. ** <tr><td><b>sqlite3_value_frombind </b> ** <td>→ <td>True if value originated from a [bound parameter] ** </table></blockquote> ** ** <b>Details:</b> ** ** These routines extract type, size, and content information from ** [protected sqlite3_value] objects. Protected sqlite3_value objects ** are used to pass parameter information into the functions that ** implement [application-defined SQL functions] and [virtual tables]. ** ** These routines work only with [protected sqlite3_value] objects. ** Any attempt to use these routines on an [unprotected sqlite3_value] ** is not threadsafe. ** ** ^These routines work just like the corresponding [column access functions] ** except that these routines take a single [protected sqlite3_value] object |
︙ | ︙ | |||
4976 4977 4978 4979 4980 4981 4982 4983 4984 4985 4986 4987 4988 4989 | ** the value for that column returned without setting a result (probably ** because it queried [sqlite3_vtab_nochange()] and found that the column ** was unchanging). ^Within an [xUpdate] method, any value for which ** sqlite3_value_nochange(X) is true will in all other respects appear ** to be a NULL value. If sqlite3_value_nochange(X) is invoked anywhere other ** than within an [xUpdate] method call for an UPDATE statement, then ** the return value is arbitrary and meaningless. ** ** Please pay particular attention to the fact that the pointer returned ** from [sqlite3_value_blob()], [sqlite3_value_text()], or ** [sqlite3_value_text16()] can be invalidated by a subsequent call to ** [sqlite3_value_bytes()], [sqlite3_value_bytes16()], [sqlite3_value_text()], ** or [sqlite3_value_text16()]. ** | > > > > > | 5497 5498 5499 5500 5501 5502 5503 5504 5505 5506 5507 5508 5509 5510 5511 5512 5513 5514 5515 | ** the value for that column returned without setting a result (probably ** because it queried [sqlite3_vtab_nochange()] and found that the column ** was unchanging). ^Within an [xUpdate] method, any value for which ** sqlite3_value_nochange(X) is true will in all other respects appear ** to be a NULL value. If sqlite3_value_nochange(X) is invoked anywhere other ** than within an [xUpdate] method call for an UPDATE statement, then ** the return value is arbitrary and meaningless. ** ** ^The sqlite3_value_frombind(X) interface returns non-zero if the ** value X originated from one of the [sqlite3_bind_int|sqlite3_bind()] ** interfaces. ^If X comes from an SQL literal value, or a table column, ** or an expression, then sqlite3_value_frombind(X) returns zero. ** ** Please pay particular attention to the fact that the pointer returned ** from [sqlite3_value_blob()], [sqlite3_value_text()], or ** [sqlite3_value_text16()] can be invalidated by a subsequent call to ** [sqlite3_value_bytes()], [sqlite3_value_bytes16()], [sqlite3_value_text()], ** or [sqlite3_value_text16()]. ** |
︙ | ︙ | |||
5022 5023 5024 5025 5026 5027 5028 5029 5030 5031 5032 5033 5034 5035 | const void *sqlite3_value_text16le(sqlite3_value*); const void *sqlite3_value_text16be(sqlite3_value*); int sqlite3_value_bytes(sqlite3_value*); int sqlite3_value_bytes16(sqlite3_value*); int sqlite3_value_type(sqlite3_value*); int sqlite3_value_numeric_type(sqlite3_value*); int sqlite3_value_nochange(sqlite3_value*); /* ** CAPI3REF: Finding The Subtype Of SQL Values ** METHOD: sqlite3_value ** ** The sqlite3_value_subtype(V) function returns the subtype for ** an [application-defined SQL function] argument V. The subtype | > | 5548 5549 5550 5551 5552 5553 5554 5555 5556 5557 5558 5559 5560 5561 5562 | const void *sqlite3_value_text16le(sqlite3_value*); const void *sqlite3_value_text16be(sqlite3_value*); int sqlite3_value_bytes(sqlite3_value*); int sqlite3_value_bytes16(sqlite3_value*); int sqlite3_value_type(sqlite3_value*); int sqlite3_value_numeric_type(sqlite3_value*); int sqlite3_value_nochange(sqlite3_value*); int sqlite3_value_frombind(sqlite3_value*); /* ** CAPI3REF: Finding The Subtype Of SQL Values ** METHOD: sqlite3_value ** ** The sqlite3_value_subtype(V) function returns the subtype for ** an [application-defined SQL function] argument V. The subtype |
︙ | ︙ | |||
5060 5061 5062 5063 5064 5065 5066 | ** CAPI3REF: Obtain Aggregate Function Context ** METHOD: sqlite3_context ** ** Implementations of aggregate SQL functions use this ** routine to allocate memory for storing their state. ** ** ^The first time the sqlite3_aggregate_context(C,N) routine is called | | | | | 5587 5588 5589 5590 5591 5592 5593 5594 5595 5596 5597 5598 5599 5600 5601 5602 5603 5604 5605 5606 5607 5608 5609 5610 5611 5612 5613 5614 5615 5616 5617 5618 5619 | ** CAPI3REF: Obtain Aggregate Function Context ** METHOD: sqlite3_context ** ** Implementations of aggregate SQL functions use this ** routine to allocate memory for storing their state. ** ** ^The first time the sqlite3_aggregate_context(C,N) routine is called ** for a particular aggregate function, SQLite allocates ** N bytes of memory, zeroes out that memory, and returns a pointer ** to the new memory. ^On second and subsequent calls to ** sqlite3_aggregate_context() for the same aggregate function instance, ** the same buffer is returned. Sqlite3_aggregate_context() is normally ** 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 any 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. |
︙ | ︙ | |||
5235 5236 5237 5238 5239 5240 5241 | ** ** ^The sqlite3_result_error() and sqlite3_result_error16() functions ** cause the implemented SQL function to throw an exception. ** ^SQLite uses the string pointed to by the ** 2nd parameter of sqlite3_result_error() or sqlite3_result_error16() ** as the text of an error message. ^SQLite interprets the error ** message string from sqlite3_result_error() as UTF-8. ^SQLite | | > | | 5762 5763 5764 5765 5766 5767 5768 5769 5770 5771 5772 5773 5774 5775 5776 5777 5778 | ** ** ^The sqlite3_result_error() and sqlite3_result_error16() functions ** cause the implemented SQL function to throw an exception. ** ^SQLite uses the string pointed to by the ** 2nd parameter of sqlite3_result_error() or sqlite3_result_error16() ** as the text of an error message. ^SQLite interprets the error ** message string from sqlite3_result_error() as UTF-8. ^SQLite ** interprets the string from sqlite3_result_error16() as UTF-16 using ** the same [byte-order determination rules] as [sqlite3_bind_text16()]. ** ^If the third parameter to sqlite3_result_error() ** or sqlite3_result_error16() is negative then SQLite takes as the error ** message all text up through the first zero character. ** ^If the third parameter to sqlite3_result_error() or ** sqlite3_result_error16() is non-negative then SQLite takes that many ** bytes (not characters) from the 2nd parameter as the error message. ** ^The sqlite3_result_error() and sqlite3_result_error16() ** routines make a private copy of the error message text before |
︙ | ︙ | |||
5303 5304 5305 5306 5307 5308 5309 5310 5311 5312 5313 5314 5315 5316 | ** assumes that the text or BLOB result is in constant space and does not ** copy the content of the parameter nor call a destructor on the content ** when it has finished using that result. ** ^If the 4th parameter to the sqlite3_result_text* interfaces ** or sqlite3_result_blob is the special constant SQLITE_TRANSIENT ** then SQLite makes a copy of the result into space obtained ** from [sqlite3_malloc()] before it returns. ** ** ^The sqlite3_result_value() interface sets the result of ** the application-defined function to be a copy of the ** [unprotected sqlite3_value] object specified by the 2nd parameter. ^The ** sqlite3_result_value() interface makes a copy of the [sqlite3_value] ** so that the [sqlite3_value] specified in the parameter may change or ** be deallocated after sqlite3_result_value() returns without harm. | > > > > > > > > > > > > > > > > > > > | 5831 5832 5833 5834 5835 5836 5837 5838 5839 5840 5841 5842 5843 5844 5845 5846 5847 5848 5849 5850 5851 5852 5853 5854 5855 5856 5857 5858 5859 5860 5861 5862 5863 | ** assumes that the text or BLOB result is in constant space and does not ** copy the content of the parameter nor call a destructor on the content ** when it has finished using that result. ** ^If the 4th parameter to the sqlite3_result_text* interfaces ** or sqlite3_result_blob is the special constant SQLITE_TRANSIENT ** then SQLite makes a copy of the result into space obtained ** from [sqlite3_malloc()] before it returns. ** ** ^For the sqlite3_result_text16(), sqlite3_result_text16le(), and ** sqlite3_result_text16be() routines, and for sqlite3_result_text64() ** when the encoding is not UTF8, if the input UTF16 begins with a ** byte-order mark (BOM, U+FEFF) then the BOM is removed from the ** string and the rest of the string is interpreted according to the ** byte-order specified by the BOM. ^The byte-order specified by ** the BOM at the beginning of the text overrides the byte-order ** specified by the interface procedure. ^So, for example, if ** sqlite3_result_text16le() is invoked with text that begins ** with bytes 0xfe, 0xff (a big-endian byte-order mark) then the ** first two bytes of input are skipped and the remaining input ** is interpreted as UTF16BE text. ** ** ^For UTF16 input text to the sqlite3_result_text16(), ** sqlite3_result_text16be(), sqlite3_result_text16le(), and ** sqlite3_result_text64() routines, if the text contains invalid ** UTF16 characters, the invalid characters might be converted ** into the unicode replacement character, U+FFFD. ** ** ^The sqlite3_result_value() interface sets the result of ** the application-defined function to be a copy of the ** [unprotected sqlite3_value] object specified by the 2nd parameter. ^The ** sqlite3_result_value() interface makes a copy of the [sqlite3_value] ** so that the [sqlite3_value] specified in the parameter may change or ** be deallocated after sqlite3_result_value() returns without harm. |
︙ | ︙ | |||
5389 5390 5391 5392 5393 5394 5395 | ** <li> [SQLITE_UTF8], ** <li> [SQLITE_UTF16LE], ** <li> [SQLITE_UTF16BE], ** <li> [SQLITE_UTF16], or ** <li> [SQLITE_UTF16_ALIGNED]. ** </ul>)^ ** ^The eTextRep argument determines the encoding of strings passed | | | | | > | | | 5936 5937 5938 5939 5940 5941 5942 5943 5944 5945 5946 5947 5948 5949 5950 5951 5952 5953 5954 5955 5956 5957 5958 5959 5960 5961 5962 5963 5964 5965 5966 5967 5968 5969 5970 5971 5972 5973 5974 5975 5976 5977 5978 5979 5980 5981 5982 5983 5984 5985 5986 5987 5988 | ** <li> [SQLITE_UTF8], ** <li> [SQLITE_UTF16LE], ** <li> [SQLITE_UTF16BE], ** <li> [SQLITE_UTF16], or ** <li> [SQLITE_UTF16_ALIGNED]. ** </ul>)^ ** ^The eTextRep argument determines the encoding of strings passed ** to the collating function callback, xCompare. ** ^The [SQLITE_UTF16] and [SQLITE_UTF16_ALIGNED] values for eTextRep ** force strings to be UTF16 with native byte order. ** ^The [SQLITE_UTF16_ALIGNED] value for eTextRep forces strings to begin ** on an even byte address. ** ** ^The fourth argument, pArg, is an application data pointer that is passed ** through as the first argument to the collating function callback. ** ** ^The fifth argument, xCompare, is a pointer to the collating function. ** ^Multiple collating functions can be registered using the same name but ** with different eTextRep parameters and SQLite will use whichever ** function requires the least amount of data transformation. ** ^If the xCompare argument is NULL then the collating function is ** deleted. ^When all collating functions having the same name are deleted, ** that collation is no longer usable. ** ** ^The collating function callback is invoked with a copy of the pArg ** application data pointer and with two strings in the encoding specified ** by the eTextRep argument. The two integer parameters to the collating ** function callback are the length of the two strings, in bytes. The collating ** function must return an integer that is negative, zero, or positive ** if the first string is less than, equal to, or greater than the second, ** respectively. A collating function must always return the same answer ** given the same inputs. If two or more collating functions are registered ** to the same collation name (using different eTextRep values) then all ** must give an equivalent answer when invoked with equivalent strings. ** The collating function must obey the following properties for all ** strings A, B, and C: ** ** <ol> ** <li> If A==B then B==A. ** <li> If A==B and B==C then A==C. ** <li> If A<B THEN B>A. ** <li> If A<B and B<C then A<C. ** </ol> ** ** If a collating function fails any of the above constraints and that ** collating function is registered and used, then the behavior of SQLite ** is undefined. ** ** ^The sqlite3_create_collation_v2() works like sqlite3_create_collation() ** with the addition that the xDestroy callback is invoked on pArg when ** the collating function is deleted. ** ^Collating functions are deleted when they are overridden by later ** calls to the collation creation functions or when the |
︙ | ︙ | |||
5508 5509 5510 5511 5512 5513 5514 | ); int sqlite3_collation_needed16( sqlite3*, void*, void(*)(void*,sqlite3*,int eTextRep,const void*) ); | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 6056 6057 6058 6059 6060 6061 6062 6063 6064 6065 6066 6067 6068 6069 | ); int sqlite3_collation_needed16( sqlite3*, void*, void(*)(void*,sqlite3*,int eTextRep,const void*) ); #ifdef SQLITE_ENABLE_CEROD /* ** Specify the activation key for a CEROD database. Unless ** activated, none of the CEROD routines will work. */ void sqlite3_activate_cerod( const char *zPassPhrase /* Activation phrase */ |
︙ | ︙ | |||
5753 5754 5755 5756 5757 5758 5759 | */ sqlite3 *sqlite3_db_handle(sqlite3_stmt*); /* ** CAPI3REF: Return The Filename For A Database Connection ** METHOD: sqlite3 ** | | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 6256 6257 6258 6259 6260 6261 6262 6263 6264 6265 6266 6267 6268 6269 6270 6271 6272 6273 6274 6275 6276 6277 6278 6279 6280 6281 6282 6283 6284 6285 6286 6287 6288 6289 6290 6291 6292 6293 6294 6295 6296 6297 6298 6299 6300 6301 6302 6303 6304 6305 6306 6307 6308 6309 6310 6311 6312 6313 6314 6315 6316 6317 6318 6319 6320 6321 6322 6323 6324 6325 6326 6327 6328 6329 6330 6331 6332 6333 6334 6335 6336 6337 6338 6339 6340 6341 6342 6343 6344 6345 6346 6347 6348 6349 6350 6351 6352 6353 6354 6355 6356 6357 6358 | */ sqlite3 *sqlite3_db_handle(sqlite3_stmt*); /* ** CAPI3REF: Return The Filename For A Database Connection ** METHOD: sqlite3 ** ** ^The sqlite3_db_filename(D,N) interface returns a pointer to the filename ** associated with database N of connection D. ** ^If there is no attached database N on the database ** connection D, or if database N is a temporary or in-memory database, then ** this function will return either a NULL pointer or an empty string. ** ** ^The string value returned by this routine is owned and managed by ** the database connection. ^The value will be valid until the database N ** is [DETACH]-ed or until the database connection closes. ** ** ^The filename returned by this function is the output of the ** xFullPathname method of the [VFS]. ^In other words, the filename ** will be an absolute pathname, even if the filename used ** to open the database originally was a URI or relative pathname. ** ** If the filename pointer returned by this routine is not NULL, then it ** can be used as the filename input parameter to these routines: ** <ul> ** <li> [sqlite3_uri_parameter()] ** <li> [sqlite3_uri_boolean()] ** <li> [sqlite3_uri_int64()] ** <li> [sqlite3_filename_database()] ** <li> [sqlite3_filename_journal()] ** <li> [sqlite3_filename_wal()] ** </ul> */ const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName); /* ** CAPI3REF: Determine if a database is read-only ** METHOD: sqlite3 ** ** ^The sqlite3_db_readonly(D,N) interface returns 1 if the database N ** of connection D is read-only, 0 if it is read/write, or -1 if N is not ** the name of a database on connection D. */ int sqlite3_db_readonly(sqlite3 *db, const char *zDbName); /* ** CAPI3REF: Determine the transaction state of a database ** METHOD: sqlite3 ** ** ^The sqlite3_txn_state(D,S) interface returns the current ** [transaction state] of schema S in database connection D. ^If S is NULL, ** then the highest transaction state of any schema on database connection D ** is returned. Transaction states are (in order of lowest to highest): ** <ol> ** <li value="0"> SQLITE_TXN_NONE ** <li value="1"> SQLITE_TXN_READ ** <li value="2"> SQLITE_TXN_WRITE ** </ol> ** ^If the S argument to sqlite3_txn_state(D,S) is not the name of ** a valid schema, then -1 is returned. */ int sqlite3_txn_state(sqlite3*,const char *zSchema); /* ** CAPI3REF: Allowed return values from [sqlite3_txn_state()] ** KEYWORDS: {transaction state} ** ** These constants define the current transaction state of a database file. ** ^The [sqlite3_txn_state(D,S)] interface returns one of these ** constants in order to describe the transaction state of schema S ** in [database connection] D. ** ** <dl> ** [[SQLITE_TXN_NONE]] <dt>SQLITE_TXN_NONE</dt> ** <dd>The SQLITE_TXN_NONE state means that no transaction is currently ** pending.</dd> ** ** [[SQLITE_TXN_READ]] <dt>SQLITE_TXN_READ</dt> ** <dd>The SQLITE_TXN_READ state means that the database is currently ** in a read transaction. Content has been read from the database file ** but nothing in the database file has changed. The transaction state ** will advanced to SQLITE_TXN_WRITE if any changes occur and there are ** no other conflicting concurrent write transactions. The transaction ** state will revert to SQLITE_TXN_NONE following a [ROLLBACK] or ** [COMMIT].</dd> ** ** [[SQLITE_TXN_WRITE]] <dt>SQLITE_TXN_WRITE</dt> ** <dd>The SQLITE_TXN_WRITE state means that the database is currently ** in a write transaction. Content has been written to the database file ** but has not yet committed. The transaction state will change to ** to SQLITE_TXN_NONE at the next [ROLLBACK] or [COMMIT].</dd> */ #define SQLITE_TXN_NONE 0 #define SQLITE_TXN_READ 1 #define SQLITE_TXN_WRITE 2 /* ** CAPI3REF: Find the next prepared statement ** METHOD: sqlite3 ** ** ^This interface returns a pointer to the next [prepared statement] after ** pStmt associated with the [database connection] pDb. ^If pStmt is NULL ** then this interface returns a pointer to the first prepared statement |
︙ | ︙ | |||
5841 5842 5843 5844 5845 5846 5847 5848 5849 5850 5851 5852 5853 5854 | ** ^The rollback callback is not invoked if a transaction is ** automatically rolled back because the database connection is closed. ** ** See also the [sqlite3_update_hook()] interface. */ void *sqlite3_commit_hook(sqlite3*, int(*)(void*), void*); void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*); /* ** CAPI3REF: Data Change Notification Callbacks ** METHOD: sqlite3 ** ** ^The sqlite3_update_hook() interface registers a callback function ** with the [database connection] identified by the first argument | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 6410 6411 6412 6413 6414 6415 6416 6417 6418 6419 6420 6421 6422 6423 6424 6425 6426 6427 6428 6429 6430 6431 6432 6433 6434 6435 6436 6437 6438 6439 6440 6441 6442 6443 6444 6445 6446 6447 6448 6449 6450 6451 6452 6453 6454 6455 6456 6457 6458 6459 6460 6461 6462 6463 6464 6465 6466 6467 6468 6469 6470 6471 6472 6473 6474 6475 6476 6477 6478 6479 6480 6481 6482 6483 6484 6485 6486 6487 6488 6489 | ** ^The rollback callback is not invoked if a transaction is ** automatically rolled back because the database connection is closed. ** ** See also the [sqlite3_update_hook()] interface. */ void *sqlite3_commit_hook(sqlite3*, int(*)(void*), void*); void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*); /* ** CAPI3REF: Autovacuum Compaction Amount Callback ** METHOD: sqlite3 ** ** ^The sqlite3_autovacuum_pages(D,C,P,X) interface registers a callback ** function C that is invoked prior to each autovacuum of the database ** file. ^The callback is passed a copy of the generic data pointer (P), ** the schema-name of the attached database that is being autovacuumed, ** the the size of the database file in pages, the number of free pages, ** and the number of bytes per page, respectively. The callback should ** return the number of free pages that should be removed by the ** autovacuum. ^If the callback returns zero, then no autovacuum happens. ** ^If the value returned is greater than or equal to the number of ** free pages, then a complete autovacuum happens. ** ** <p>^If there are multiple ATTACH-ed database files that are being ** modified as part of a transaction commit, then the autovacuum pages ** callback is invoked separately for each file. ** ** <p><b>The callback is not reentrant.</b> The callback function should ** not attempt to invoke any other SQLite interface. If it does, bad ** things may happen, including segmentation faults and corrupt database ** files. The callback function should be a simple function that ** does some arithmetic on its input parameters and returns a result. ** ** ^The X parameter to sqlite3_autovacuum_pages(D,C,P,X) is an optional ** destructor for the P parameter. ^If X is not NULL, then X(P) is ** invoked whenever the database connection closes or when the callback ** is overwritten by another invocation of sqlite3_autovacuum_pages(). ** ** <p>^There is only one autovacuum pages callback per database connection. ** ^Each call to the sqlite3_autovacuum_pages() interface overrides all ** previous invocations for that database connection. ^If the callback ** argument (C) to sqlite3_autovacuum_pages(D,C,P,X) is a NULL pointer, ** then the autovacuum steps callback is cancelled. The return value ** from sqlite3_autovacuum_pages() is normally SQLITE_OK, but might ** be some other error code if something goes wrong. The current ** implementation will only return SQLITE_OK or SQLITE_MISUSE, but other ** return codes might be added in future releases. ** ** <p>If no autovacuum pages callback is specified (the usual case) or ** a NULL pointer is provided for the callback, ** then the default behavior is to vacuum all free pages. So, in other ** words, the default behavior is the same as if the callback function ** were something like this: ** ** <blockquote><pre> ** unsigned int demonstration_autovac_pages_callback( ** void *pClientData, ** const char *zSchema, ** unsigned int nDbPage, ** unsigned int nFreePage, ** unsigned int nBytePerPage ** ){ ** return nFreePage; ** } ** </pre></blockquote> */ int sqlite3_autovacuum_pages( sqlite3 *db, unsigned int(*)(void*,const char*,unsigned int,unsigned int,unsigned int), void*, void(*)(void*) ); /* ** CAPI3REF: Data Change Notification Callbacks ** METHOD: sqlite3 ** ** ^The sqlite3_update_hook() interface registers a callback function ** with the [database connection] identified by the first argument |
︙ | ︙ | |||
5866 5867 5868 5869 5870 5871 5872 | ** to be invoked. ** ^The third and fourth arguments to the callback contain pointers to the ** database and table name containing the affected row. ** ^The final callback parameter is the [rowid] of the row. ** ^In the case of an update, this is the [rowid] after the update takes place. ** ** ^(The update hook is not invoked when internal system tables are | | | 6501 6502 6503 6504 6505 6506 6507 6508 6509 6510 6511 6512 6513 6514 6515 | ** to be invoked. ** ^The third and fourth arguments to the callback contain pointers to the ** database and table name containing the affected row. ** ^The final callback parameter is the [rowid] of the row. ** ^In the case of an update, this is the [rowid] after the update takes place. ** ** ^(The update hook is not invoked when internal system tables are ** modified (i.e. sqlite_sequence).)^ ** ^The update hook is not invoked when [WITHOUT ROWID] tables are modified. ** ** ^In the current implementation, the update hook ** is not invoked when conflicting rows are deleted because of an ** [ON CONFLICT | ON CONFLICT REPLACE] clause. ^Nor is the update hook ** invoked when rows are deleted using the [truncate optimization]. ** The exceptions defined in this paragraph might change in a future |
︙ | ︙ | |||
5912 5913 5914 5915 5916 5917 5918 | ** ^Cache sharing is enabled and disabled for an entire process. ** This is a change as of SQLite [version 3.5.0] ([dateof:3.5.0]). ** In prior versions of SQLite, ** sharing was enabled or disabled for each thread separately. ** ** ^(The cache sharing mode set by this interface effects all subsequent ** calls to [sqlite3_open()], [sqlite3_open_v2()], and [sqlite3_open16()]. | | | | | > > > > | 6547 6548 6549 6550 6551 6552 6553 6554 6555 6556 6557 6558 6559 6560 6561 6562 6563 6564 6565 6566 6567 6568 6569 6570 6571 6572 6573 | ** ^Cache sharing is enabled and disabled for an entire process. ** This is a change as of SQLite [version 3.5.0] ([dateof:3.5.0]). ** In prior versions of SQLite, ** sharing was enabled or disabled for each thread separately. ** ** ^(The cache sharing mode set by this interface effects all subsequent ** calls to [sqlite3_open()], [sqlite3_open_v2()], and [sqlite3_open16()]. ** Existing database connections continue to use the sharing mode ** that was in effect at the time they were opened.)^ ** ** ^(This routine returns [SQLITE_OK] if shared cache was enabled or disabled ** successfully. An [error code] is returned otherwise.)^ ** ** ^Shared cache is disabled by default. It is recommended that it stay ** that way. In other words, do not use this routine. This interface ** continues to be provided for historical compatibility, but its use is ** discouraged. Any use of shared cache is discouraged. If shared cache ** must be used, it is recommended that shared cache only be enabled for ** individual database connections using the [sqlite3_open_v2()] interface ** with the [SQLITE_OPEN_SHAREDCACHE] flag. ** ** Note: This method is disabled on MacOS X 10.7 and iOS version 5.0 ** and will always return SQLITE_MISUSE. On those systems, ** shared cache mode should be enabled per-database connection via ** [sqlite3_open_v2()] with [SQLITE_OPEN_SHAREDCACHE]. ** ** This interface is threadsafe on processors where writing a |
︙ | ︙ | |||
5966 5967 5968 5969 5970 5971 5972 5973 5974 5975 5976 5977 5978 5979 5980 5981 5982 5983 | ** ** See also: [sqlite3_release_memory()] */ int sqlite3_db_release_memory(sqlite3*); /* ** CAPI3REF: Impose A Limit On Heap Size ** ** ^The sqlite3_soft_heap_limit64() interface sets and/or queries the ** soft limit on the amount of heap memory that may be allocated by SQLite. ** ^SQLite strives to keep heap memory utilization below the soft heap ** limit by reducing the number of pages held in the page cache ** as heap memory usages approaches the limit. ** ^The soft heap limit is "soft" because even though SQLite strives to stay ** below the limit, it will exceed the limit rather than generate ** an [SQLITE_NOMEM] error. In other words, the soft heap limit ** is advisory only. ** | > > > > > > > > > > | | | | | > > > > > | > > > > > > > > > | | < < < < < < < < < < < | > | 6605 6606 6607 6608 6609 6610 6611 6612 6613 6614 6615 6616 6617 6618 6619 6620 6621 6622 6623 6624 6625 6626 6627 6628 6629 6630 6631 6632 6633 6634 6635 6636 6637 6638 6639 6640 6641 6642 6643 6644 6645 6646 6647 6648 6649 6650 6651 6652 6653 6654 6655 6656 6657 6658 6659 6660 6661 6662 6663 6664 6665 6666 6667 6668 6669 6670 6671 6672 6673 6674 6675 6676 6677 6678 6679 6680 6681 6682 | ** ** See also: [sqlite3_release_memory()] */ int sqlite3_db_release_memory(sqlite3*); /* ** CAPI3REF: Impose A Limit On Heap Size ** ** These interfaces impose limits on the amount of heap memory that will be ** by all database connections within a single process. ** ** ^The sqlite3_soft_heap_limit64() interface sets and/or queries the ** soft limit on the amount of heap memory that may be allocated by SQLite. ** ^SQLite strives to keep heap memory utilization below the soft heap ** limit by reducing the number of pages held in the page cache ** as heap memory usages approaches the limit. ** ^The soft heap limit is "soft" because even though SQLite strives to stay ** below the limit, it will exceed the limit rather than generate ** an [SQLITE_NOMEM] error. In other words, the soft heap limit ** is advisory only. ** ** ^The sqlite3_hard_heap_limit64(N) interface sets a hard upper bound of ** N bytes on the amount of memory that will be allocated. ^The ** sqlite3_hard_heap_limit64(N) interface is similar to ** sqlite3_soft_heap_limit64(N) except that memory allocations will fail ** when the hard heap limit is reached. ** ** ^The return value from both sqlite3_soft_heap_limit64() and ** sqlite3_hard_heap_limit64() is the size of ** the heap limit prior to the call, or negative in the case of an ** error. ^If the argument N is negative ** then no change is made to the heap limit. Hence, the current ** size of heap limits can be determined by invoking ** sqlite3_soft_heap_limit64(-1) or sqlite3_hard_heap_limit(-1). ** ** ^Setting the heap limits to zero disables the heap limiter mechanism. ** ** ^The soft heap limit may not be greater than the hard heap limit. ** ^If the hard heap limit is enabled and if sqlite3_soft_heap_limit(N) ** is invoked with a value of N that is greater than the hard heap limit, ** the the soft heap limit is set to the value of the hard heap limit. ** ^The soft heap limit is automatically enabled whenever the hard heap ** limit is enabled. ^When sqlite3_hard_heap_limit64(N) is invoked and ** the soft heap limit is outside the range of 1..N, then the soft heap ** limit is set to N. ^Invoking sqlite3_soft_heap_limit64(0) when the ** hard heap limit is enabled makes the soft heap limit equal to the ** hard heap limit. ** ** The memory allocation limits can also be adjusted using ** [PRAGMA soft_heap_limit] and [PRAGMA hard_heap_limit]. ** ** ^(The heap limits are not enforced in the current implementation ** if one or more of following conditions are true: ** ** <ul> ** <li> The limit value is set to zero. ** <li> Memory accounting is disabled using a combination of the ** [sqlite3_config]([SQLITE_CONFIG_MEMSTATUS],...) start-time option and ** the [SQLITE_DEFAULT_MEMSTATUS] compile-time option. ** <li> An alternative page cache implementation is specified using ** [sqlite3_config]([SQLITE_CONFIG_PCACHE2],...). ** <li> The page cache allocates from its own memory pool supplied ** by [sqlite3_config]([SQLITE_CONFIG_PAGECACHE],...) rather than ** from the heap. ** </ul>)^ ** ** The circumstances under which SQLite will enforce the heap limits may ** changes in future releases of SQLite. */ sqlite3_int64 sqlite3_soft_heap_limit64(sqlite3_int64 N); sqlite3_int64 sqlite3_hard_heap_limit64(sqlite3_int64 N); /* ** CAPI3REF: Deprecated Soft Heap Limit Interface ** DEPRECATED ** ** This is a deprecated version of the [sqlite3_soft_heap_limit64()] ** interface. This routine is provided for historical compatibility |
︙ | ︙ | |||
6039 6040 6041 6042 6043 6044 6045 | ** ** ^(The sqlite3_table_column_metadata(X,D,T,C,....) routine returns ** information about column C of table T in database D ** on [database connection] X.)^ ^The sqlite3_table_column_metadata() ** interface returns SQLITE_OK and fills in the non-NULL pointers in ** the final five arguments with appropriate values if the specified ** column exists. ^The sqlite3_table_column_metadata() interface returns | | | 6692 6693 6694 6695 6696 6697 6698 6699 6700 6701 6702 6703 6704 6705 6706 | ** ** ^(The sqlite3_table_column_metadata(X,D,T,C,....) routine returns ** information about column C of table T in database D ** on [database connection] X.)^ ^The sqlite3_table_column_metadata() ** interface returns SQLITE_OK and fills in the non-NULL pointers in ** the final five arguments with appropriate values if the specified ** column exists. ^The sqlite3_table_column_metadata() interface returns ** SQLITE_ERROR if the specified column does not exist. ** ^If the column-name parameter to sqlite3_table_column_metadata() is a ** NULL pointer, then this routine simply checks for the existence of the ** table and returns SQLITE_OK if the table exists and SQLITE_ERROR if it ** does not. If the table name parameter T in a call to ** sqlite3_table_column_metadata(X,D,T,C,...) is NULL then the result is ** undefined behavior. ** |
︙ | ︙ | |||
6181 6182 6183 6184 6185 6186 6187 | ** ** ^This interface enables or disables both the C-API ** [sqlite3_load_extension()] and the SQL function [load_extension()]. ** ^(Use [sqlite3_db_config](db,[SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION],..) ** to enable or disable only the C-API.)^ ** ** <b>Security warning:</b> It is recommended that extension loading | | | 6834 6835 6836 6837 6838 6839 6840 6841 6842 6843 6844 6845 6846 6847 6848 | ** ** ^This interface enables or disables both the C-API ** [sqlite3_load_extension()] and the SQL function [load_extension()]. ** ^(Use [sqlite3_db_config](db,[SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION],..) ** to enable or disable only the C-API.)^ ** ** <b>Security warning:</b> It is recommended that extension loading ** be enabled using the [SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION] method ** rather than this interface, so the [load_extension()] SQL function ** remains disabled. This will prevent SQL injections from giving attackers ** access to extension loading capabilities. */ int sqlite3_enable_load_extension(sqlite3 *db, int onoff); /* |
︙ | ︙ | |||
6268 6269 6270 6271 6272 6273 6274 | typedef struct sqlite3_module sqlite3_module; /* ** CAPI3REF: Virtual Table Object ** KEYWORDS: sqlite3_module {virtual table module} ** ** This structure, sometimes called a "virtual table module", | | | 6921 6922 6923 6924 6925 6926 6927 6928 6929 6930 6931 6932 6933 6934 6935 | typedef struct sqlite3_module sqlite3_module; /* ** CAPI3REF: Virtual Table Object ** KEYWORDS: sqlite3_module {virtual table module} ** ** This structure, sometimes called a "virtual table module", ** defines the implementation of a [virtual table]. ** This structure consists mostly of methods for the module. ** ** ^A virtual table module is created by filling in a persistent ** instance of this structure and passing a pointer to that instance ** to [sqlite3_create_module()] or [sqlite3_create_module_v2()]. ** ^The registration remains valid until it is replaced by a different ** module or until the [database connection] closes. The content |
︙ | ︙ | |||
6365 6366 6367 6368 6369 6370 6371 | ** non-zero. ** ** The [xBestIndex] method must fill aConstraintUsage[] with information ** about what parameters to pass to xFilter. ^If argvIndex>0 then ** the right-hand side of the corresponding aConstraint[] is evaluated ** and becomes the argvIndex-th entry in argv. ^(If aConstraintUsage[].omit ** is true, then the constraint is assumed to be fully handled by the | | > > > > > > | 7018 7019 7020 7021 7022 7023 7024 7025 7026 7027 7028 7029 7030 7031 7032 7033 7034 7035 7036 7037 7038 | ** non-zero. ** ** The [xBestIndex] method must fill aConstraintUsage[] with information ** about what parameters to pass to xFilter. ^If argvIndex>0 then ** the right-hand side of the corresponding aConstraint[] is evaluated ** and becomes the argvIndex-th entry in argv. ^(If aConstraintUsage[].omit ** is true, then the constraint is assumed to be fully handled by the ** virtual table and might not be checked again by the byte code.)^ ^(The ** aConstraintUsage[].omit flag is an optimization hint. When the omit flag ** is left in its default setting of false, the constraint will always be ** checked separately in byte code. If the omit flag is change to true, then ** the constraint may or may not be checked in byte code. In other words, ** when the omit flag is true there is no guarantee that the constraint will ** not be checked again using byte code.)^ ** ** ^The idxNum and idxPtr values are recorded and passed into the ** [xFilter] method. ** ^[sqlite3_free()] is used to free idxPtr if and only if ** needToFreeIdxPtr is true. ** ** ^The orderByConsumed means that output from [xFilter]/[xNext] will occur in |
︙ | ︙ | |||
6405 6406 6407 6408 6409 6410 6411 | ** the xUpdate method are automatically rolled back by SQLite. ** ** IMPORTANT: The estimatedRows field was added to the sqlite3_index_info ** structure for SQLite [version 3.8.2] ([dateof:3.8.2]). ** If a virtual table extension is ** used with an SQLite version earlier than 3.8.2, the results of attempting ** to read or write the estimatedRows field are undefined (but are likely | | | 7064 7065 7066 7067 7068 7069 7070 7071 7072 7073 7074 7075 7076 7077 7078 | ** the xUpdate method are automatically rolled back by SQLite. ** ** IMPORTANT: The estimatedRows field was added to the sqlite3_index_info ** structure for SQLite [version 3.8.2] ([dateof:3.8.2]). ** If a virtual table extension is ** used with an SQLite version earlier than 3.8.2, the results of attempting ** to read or write the estimatedRows field are undefined (but are likely ** to include crashing the application). The estimatedRows field should ** therefore only be used if [sqlite3_libversion_number()] returns a ** value greater than or equal to 3008002. Similarly, the idxFlags field ** was added for [version 3.9.0] ([dateof:3.9.0]). ** It may therefore only be used if ** sqlite3_libversion_number() returns a value greater than or equal to ** 3009000. */ |
︙ | ︙ | |||
6457 6458 6459 6460 6461 6462 6463 | ** these bits. */ #define SQLITE_INDEX_SCAN_UNIQUE 1 /* Scan visits at most 1 row */ /* ** CAPI3REF: Virtual Table Constraint Operator Codes ** | | | 7116 7117 7118 7119 7120 7121 7122 7123 7124 7125 7126 7127 7128 7129 7130 | ** these bits. */ #define SQLITE_INDEX_SCAN_UNIQUE 1 /* Scan visits at most 1 row */ /* ** CAPI3REF: Virtual Table Constraint Operator Codes ** ** These macros define the allowed values for the ** [sqlite3_index_info].aConstraint[].op field. Each value represents ** an operator that is part of a constraint term in the wHERE clause of ** a query that uses a [virtual table]. */ #define SQLITE_INDEX_CONSTRAINT_EQ 2 #define SQLITE_INDEX_CONSTRAINT_GT 4 #define SQLITE_INDEX_CONSTRAINT_LE 8 |
︙ | ︙ | |||
6503 6504 6505 6506 6507 6508 6509 6510 6511 6512 6513 6514 6515 6516 6517 6518 6519 6520 6521 6522 6523 6524 6525 6526 6527 6528 6529 6530 | ** is a pointer to a destructor for the pClientData. ^SQLite will ** invoke the destructor function (if it is not NULL) when SQLite ** no longer needs the pClientData pointer. ^The destructor will also ** be invoked if the call to sqlite3_create_module_v2() fails. ** ^The sqlite3_create_module() ** interface is equivalent to sqlite3_create_module_v2() with a NULL ** destructor. */ int sqlite3_create_module( sqlite3 *db, /* SQLite connection to register module with */ const char *zName, /* Name of the module */ const sqlite3_module *p, /* Methods for the module */ void *pClientData /* Client data for xCreate/xConnect */ ); int sqlite3_create_module_v2( sqlite3 *db, /* SQLite connection to register module with */ const char *zName, /* Name of the module */ const sqlite3_module *p, /* Methods for the module */ void *pClientData, /* Client data for xCreate/xConnect */ void(*xDestroy)(void*) /* Module destructor function */ ); /* ** CAPI3REF: Virtual Table Instance Object ** KEYWORDS: sqlite3_vtab ** ** Every [virtual table module] implementation uses a subclass ** of this object to describe a particular instance | > > > > > > > > > > > > > > > > > > > > > > > | 7162 7163 7164 7165 7166 7167 7168 7169 7170 7171 7172 7173 7174 7175 7176 7177 7178 7179 7180 7181 7182 7183 7184 7185 7186 7187 7188 7189 7190 7191 7192 7193 7194 7195 7196 7197 7198 7199 7200 7201 7202 7203 7204 7205 7206 7207 7208 7209 7210 7211 7212 | ** is a pointer to a destructor for the pClientData. ^SQLite will ** invoke the destructor function (if it is not NULL) when SQLite ** no longer needs the pClientData pointer. ^The destructor will also ** be invoked if the call to sqlite3_create_module_v2() fails. ** ^The sqlite3_create_module() ** interface is equivalent to sqlite3_create_module_v2() with a NULL ** destructor. ** ** ^If the third parameter (the pointer to the sqlite3_module object) is ** NULL then no new module is create and any existing modules with the ** same name are dropped. ** ** See also: [sqlite3_drop_modules()] */ int sqlite3_create_module( sqlite3 *db, /* SQLite connection to register module with */ const char *zName, /* Name of the module */ const sqlite3_module *p, /* Methods for the module */ void *pClientData /* Client data for xCreate/xConnect */ ); int sqlite3_create_module_v2( sqlite3 *db, /* SQLite connection to register module with */ const char *zName, /* Name of the module */ const sqlite3_module *p, /* Methods for the module */ void *pClientData, /* Client data for xCreate/xConnect */ void(*xDestroy)(void*) /* Module destructor function */ ); /* ** CAPI3REF: Remove Unnecessary Virtual Table Implementations ** METHOD: sqlite3 ** ** ^The sqlite3_drop_modules(D,L) interface removes all virtual ** table modules from database connection D except those named on list L. ** The L parameter must be either NULL or a pointer to an array of pointers ** to strings where the array is terminated by a single NULL pointer. ** ^If the L parameter is NULL, then all virtual table modules are removed. ** ** See also: [sqlite3_create_module()] */ int sqlite3_drop_modules( sqlite3 *db, /* Remove modules from this connection */ const char **azKeep /* Except, do not remove the ones named here */ ); /* ** CAPI3REF: Virtual Table Instance Object ** KEYWORDS: sqlite3_vtab ** ** Every [virtual table module] implementation uses a subclass ** of this object to describe a particular instance |
︙ | ︙ | |||
6921 6922 6923 6924 6925 6926 6927 | ** routine returns NULL if it is unable to allocate the requested ** mutex. The argument to sqlite3_mutex_alloc() must one of these ** integer constants: ** ** <ul> ** <li> SQLITE_MUTEX_FAST ** <li> SQLITE_MUTEX_RECURSIVE | | | 7603 7604 7605 7606 7607 7608 7609 7610 7611 7612 7613 7614 7615 7616 7617 | ** routine returns NULL if it is unable to allocate the requested ** mutex. The argument to sqlite3_mutex_alloc() must one of these ** integer constants: ** ** <ul> ** <li> SQLITE_MUTEX_FAST ** <li> SQLITE_MUTEX_RECURSIVE ** <li> SQLITE_MUTEX_STATIC_MAIN ** <li> SQLITE_MUTEX_STATIC_MEM ** <li> SQLITE_MUTEX_STATIC_OPEN ** <li> SQLITE_MUTEX_STATIC_PRNG ** <li> SQLITE_MUTEX_STATIC_LRU ** <li> SQLITE_MUTEX_STATIC_PMEM ** <li> SQLITE_MUTEX_STATIC_APP1 ** <li> SQLITE_MUTEX_STATIC_APP2 |
︙ | ︙ | |||
7044 7045 7046 7047 7048 7049 7050 | ** <li> [sqlite3_mutex_held()] </li> ** <li> [sqlite3_mutex_notheld()] </li> ** </ul>)^ ** ** The only difference is that the public sqlite3_XXX functions enumerated ** above silently ignore any invocations that pass a NULL pointer instead ** of a valid mutex handle. The implementations of the methods defined | | | 7726 7727 7728 7729 7730 7731 7732 7733 7734 7735 7736 7737 7738 7739 7740 | ** <li> [sqlite3_mutex_held()] </li> ** <li> [sqlite3_mutex_notheld()] </li> ** </ul>)^ ** ** The only difference is that the public sqlite3_XXX functions enumerated ** above silently ignore any invocations that pass a NULL pointer instead ** of a valid mutex handle. The implementations of the methods defined ** by this structure are not required to handle this case. The results ** of passing a NULL pointer instead of a valid mutex handle are undefined ** (i.e. it is acceptable to provide an implementation that segfaults if ** it is passed a NULL pointer). ** ** The xMutexInit() method must be threadsafe. It must be harmless to ** invoke xMutexInit() multiple times within the same process and without ** intervening calls to xMutexEnd(). Second and subsequent calls to |
︙ | ︙ | |||
7123 7124 7125 7126 7127 7128 7129 | ** ** The set of static mutexes may change from one SQLite release to the ** next. Applications that override the built-in mutex logic must be ** prepared to accommodate additional static mutexes. */ #define SQLITE_MUTEX_FAST 0 #define SQLITE_MUTEX_RECURSIVE 1 | | > > > > | 7805 7806 7807 7808 7809 7810 7811 7812 7813 7814 7815 7816 7817 7818 7819 7820 7821 7822 7823 7824 7825 7826 7827 7828 7829 7830 7831 7832 7833 7834 7835 7836 | ** ** The set of static mutexes may change from one SQLite release to the ** next. Applications that override the built-in mutex logic must be ** prepared to accommodate additional static mutexes. */ #define SQLITE_MUTEX_FAST 0 #define SQLITE_MUTEX_RECURSIVE 1 #define SQLITE_MUTEX_STATIC_MAIN 2 #define SQLITE_MUTEX_STATIC_MEM 3 /* sqlite3_malloc() */ #define SQLITE_MUTEX_STATIC_MEM2 4 /* NOT USED */ #define SQLITE_MUTEX_STATIC_OPEN 4 /* sqlite3BtreeOpen() */ #define SQLITE_MUTEX_STATIC_PRNG 5 /* sqlite3_randomness() */ #define SQLITE_MUTEX_STATIC_LRU 6 /* lru page list */ #define SQLITE_MUTEX_STATIC_LRU2 7 /* NOT USED */ #define SQLITE_MUTEX_STATIC_PMEM 7 /* sqlite3PageMalloc() */ #define SQLITE_MUTEX_STATIC_APP1 8 /* For use by application */ #define SQLITE_MUTEX_STATIC_APP2 9 /* For use by application */ #define SQLITE_MUTEX_STATIC_APP3 10 /* For use by application */ #define SQLITE_MUTEX_STATIC_VFS1 11 /* For use by built-in VFS */ #define SQLITE_MUTEX_STATIC_VFS2 12 /* For use by extension VFS */ #define SQLITE_MUTEX_STATIC_VFS3 13 /* For use by application VFS */ /* Legacy compatibility: */ #define SQLITE_MUTEX_STATIC_MASTER 2 /* ** CAPI3REF: Retrieve the mutex for a database connection ** METHOD: sqlite3 ** ** ^This interface returns a pointer the [sqlite3_mutex] object that ** serializes access to the [database connection] given in the argument |
︙ | ︙ | |||
7226 7227 7228 7229 7230 7231 7232 | ** without notice. These values are for testing purposes only. ** Applications should not use any of these parameters or the ** [sqlite3_test_control()] interface. */ #define SQLITE_TESTCTRL_FIRST 5 #define SQLITE_TESTCTRL_PRNG_SAVE 5 #define SQLITE_TESTCTRL_PRNG_RESTORE 6 | | | > > > > > > | | 7912 7913 7914 7915 7916 7917 7918 7919 7920 7921 7922 7923 7924 7925 7926 7927 7928 7929 7930 7931 7932 7933 7934 7935 7936 7937 7938 7939 7940 7941 7942 7943 7944 7945 7946 7947 7948 7949 7950 7951 7952 7953 7954 | ** without notice. These values are for testing purposes only. ** Applications should not use any of these parameters or the ** [sqlite3_test_control()] interface. */ #define SQLITE_TESTCTRL_FIRST 5 #define SQLITE_TESTCTRL_PRNG_SAVE 5 #define SQLITE_TESTCTRL_PRNG_RESTORE 6 #define SQLITE_TESTCTRL_PRNG_RESET 7 /* NOT USED */ #define SQLITE_TESTCTRL_BITVEC_TEST 8 #define SQLITE_TESTCTRL_FAULT_INSTALL 9 #define SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS 10 #define SQLITE_TESTCTRL_PENDING_BYTE 11 #define SQLITE_TESTCTRL_ASSERT 12 #define SQLITE_TESTCTRL_ALWAYS 13 #define SQLITE_TESTCTRL_RESERVE 14 /* NOT USED */ #define SQLITE_TESTCTRL_OPTIMIZATIONS 15 #define SQLITE_TESTCTRL_ISKEYWORD 16 /* NOT USED */ #define SQLITE_TESTCTRL_SCRATCHMALLOC 17 /* NOT USED */ #define SQLITE_TESTCTRL_INTERNAL_FUNCTIONS 17 #define SQLITE_TESTCTRL_LOCALTIME_FAULT 18 #define SQLITE_TESTCTRL_EXPLAIN_STMT 19 /* NOT USED */ #define SQLITE_TESTCTRL_ONCE_RESET_THRESHOLD 19 #define SQLITE_TESTCTRL_NEVER_CORRUPT 20 #define SQLITE_TESTCTRL_VDBE_COVERAGE 21 #define SQLITE_TESTCTRL_BYTEORDER 22 #define SQLITE_TESTCTRL_ISINIT 23 #define SQLITE_TESTCTRL_SORTER_MMAP 24 #define SQLITE_TESTCTRL_IMPOSTER 25 #define SQLITE_TESTCTRL_PARSER_COVERAGE 26 #define SQLITE_TESTCTRL_RESULT_INTREAL 27 #define SQLITE_TESTCTRL_PRNG_SEED 28 #define SQLITE_TESTCTRL_EXTRA_SCHEMA_CHECKS 29 #define SQLITE_TESTCTRL_SEEK_COUNT 30 #define SQLITE_TESTCTRL_TRACEFLAGS 31 #define SQLITE_TESTCTRL_TUNE 32 #define SQLITE_TESTCTRL_LAST 32 /* Largest TESTCTRL */ /* ** CAPI3REF: SQL Keyword Checking ** ** These routines provide access to the set of SQL language keywords ** recognized by SQLite. Applications can uses these routines to determine ** whether or not a specific identifier needs to be escaped (for example, |
︙ | ︙ | |||
7514 7515 7516 7517 7518 7519 7520 | ** returned value includes allocations that overflowed because they ** where too large (they were larger than the "sz" parameter to ** [SQLITE_CONFIG_PAGECACHE]) and allocations that overflowed because ** no space was left in the page cache.</dd>)^ ** ** [[SQLITE_STATUS_PAGECACHE_SIZE]] ^(<dt>SQLITE_STATUS_PAGECACHE_SIZE</dt> ** <dd>This parameter records the largest memory allocation request | | | 8206 8207 8208 8209 8210 8211 8212 8213 8214 8215 8216 8217 8218 8219 8220 | ** returned value includes allocations that overflowed because they ** where too large (they were larger than the "sz" parameter to ** [SQLITE_CONFIG_PAGECACHE]) and allocations that overflowed because ** no space was left in the page cache.</dd>)^ ** ** [[SQLITE_STATUS_PAGECACHE_SIZE]] ^(<dt>SQLITE_STATUS_PAGECACHE_SIZE</dt> ** <dd>This parameter records the largest memory allocation request ** handed to the [pagecache memory allocator]. Only the value returned in the ** *pHighwater parameter to [sqlite3_status()] is of interest. ** The value written into the *pCurrent parameter is undefined.</dd>)^ ** ** [[SQLITE_STATUS_SCRATCH_USED]] <dt>SQLITE_STATUS_SCRATCH_USED</dt> ** <dd>No longer used.</dd> ** ** [[SQLITE_STATUS_SCRATCH_OVERFLOW]] ^(<dt>SQLITE_STATUS_SCRATCH_OVERFLOW</dt> |
︙ | ︙ | |||
7590 7591 7592 7593 7594 7595 7596 | ** ** <dl> ** [[SQLITE_DBSTATUS_LOOKASIDE_USED]] ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_USED</dt> ** <dd>This parameter returns the number of lookaside memory slots currently ** checked out.</dd>)^ ** ** [[SQLITE_DBSTATUS_LOOKASIDE_HIT]] ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_HIT</dt> | | | 8282 8283 8284 8285 8286 8287 8288 8289 8290 8291 8292 8293 8294 8295 8296 | ** ** <dl> ** [[SQLITE_DBSTATUS_LOOKASIDE_USED]] ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_USED</dt> ** <dd>This parameter returns the number of lookaside memory slots currently ** checked out.</dd>)^ ** ** [[SQLITE_DBSTATUS_LOOKASIDE_HIT]] ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_HIT</dt> ** <dd>This parameter returns the number of malloc attempts that were ** satisfied using lookaside memory. Only the high-water value is meaningful; ** the current value is always zero.)^ ** ** [[SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE]] ** ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE</dt> ** <dd>This parameter returns the number malloc attempts that might have ** been satisfied using lookaside memory but failed due to the amount of |
︙ | ︙ | |||
7672 7673 7674 7675 7676 7677 7678 | ** ** [[SQLITE_DBSTATUS_CACHE_SPILL]] ^(<dt>SQLITE_DBSTATUS_CACHE_SPILL</dt> ** <dd>This parameter returns the number of dirty cache entries that have ** been written to disk in the middle of a transaction due to the page ** cache overflowing. Transactions are more efficient if they are written ** to disk all at once. When pages spill mid-transaction, that introduces ** additional overhead. This parameter can be used help identify | | | 8364 8365 8366 8367 8368 8369 8370 8371 8372 8373 8374 8375 8376 8377 8378 | ** ** [[SQLITE_DBSTATUS_CACHE_SPILL]] ^(<dt>SQLITE_DBSTATUS_CACHE_SPILL</dt> ** <dd>This parameter returns the number of dirty cache entries that have ** been written to disk in the middle of a transaction due to the page ** cache overflowing. Transactions are more efficient if they are written ** to disk all at once. When pages spill mid-transaction, that introduces ** additional overhead. This parameter can be used help identify ** inefficiencies that can be resolved by increasing the cache size. ** </dd> ** ** [[SQLITE_DBSTATUS_DEFERRED_FKS]] ^(<dt>SQLITE_DBSTATUS_DEFERRED_FKS</dt> ** <dd>This parameter returns zero for the current value if and only if ** all foreign key constraints (deferred or immediate) have been ** resolved.)^ ^The highwater mark is always 0. ** </dd> |
︙ | ︙ | |||
7761 7762 7763 7764 7765 7766 7767 | ** to 2147483647. The number of virtual machine operations can be ** used as a proxy for the total work done by the prepared statement. ** If the number of virtual machine operations exceeds 2147483647 ** then the value returned by this statement status code is undefined. ** ** [[SQLITE_STMTSTATUS_REPREPARE]] <dt>SQLITE_STMTSTATUS_REPREPARE</dt> ** <dd>^This is the number of times that the prepare statement has been | | | 8453 8454 8455 8456 8457 8458 8459 8460 8461 8462 8463 8464 8465 8466 8467 | ** to 2147483647. The number of virtual machine operations can be ** used as a proxy for the total work done by the prepared statement. ** If the number of virtual machine operations exceeds 2147483647 ** then the value returned by this statement status code is undefined. ** ** [[SQLITE_STMTSTATUS_REPREPARE]] <dt>SQLITE_STMTSTATUS_REPREPARE</dt> ** <dd>^This is the number of times that the prepare statement has been ** automatically regenerated due to schema changes or changes to ** [bound parameters] that might affect the query plan. ** ** [[SQLITE_STMTSTATUS_RUN]] <dt>SQLITE_STMTSTATUS_RUN</dt> ** <dd>^This is the number of times that the prepared statement has ** been run. A single "run" for the purposes of this counter is one ** or more calls to [sqlite3_step()] followed by a call to [sqlite3_reset()]. ** The counter is incremented on the first [sqlite3_step()] call of each |
︙ | ︙ | |||
7932 7933 7934 7935 7936 7937 7938 | ** 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> ** ** ^(SQLite will normally invoke xFetch() with a createFlag of 0 or 1. SQLite ** will only use a createFlag of 2 after a prior call with a createFlag of 1 | | | 8624 8625 8626 8627 8628 8629 8630 8631 8632 8633 8634 8635 8636 8637 8638 | ** 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> ** ** ^(SQLite will normally invoke xFetch() with a createFlag of 0 or 1. SQLite ** will only use a createFlag of 2 after a prior call with a createFlag of 1 ** failed.)^ In between the xFetch() calls, SQLite may ** attempt to unpin one or more cache pages by spilling the content of ** pinned pages to disk and synching the operating system disk cache. ** ** [[the xUnpin() page cache method]] ** ^xUnpin() is called by SQLite with a pointer to a currently pinned page ** as its second argument. If the third parameter, discard, is non-zero, ** then the page must be evicted from the cache. |
︙ | ︙ | |||
8250 8251 8252 8253 8254 8255 8256 | ** identity of the database connection (the blocking connection) that ** has locked the required resource is stored internally. ^After an ** application receives an SQLITE_LOCKED error, it may call the ** sqlite3_unlock_notify() method with the blocked connection handle as ** the first argument to register for a callback that will be invoked ** when the blocking connections current transaction is concluded. ^The ** callback is invoked from within the [sqlite3_step] or [sqlite3_close] | | | 8942 8943 8944 8945 8946 8947 8948 8949 8950 8951 8952 8953 8954 8955 8956 | ** identity of the database connection (the blocking connection) that ** has locked the required resource is stored internally. ^After an ** application receives an SQLITE_LOCKED error, it may call the ** sqlite3_unlock_notify() method with the blocked connection handle as ** the first argument to register for a callback that will be invoked ** when the blocking connections current transaction is concluded. ^The ** callback is invoked from within the [sqlite3_step] or [sqlite3_close] ** call that concludes the blocking connection's transaction. ** ** ^(If sqlite3_unlock_notify() is called in a multi-threaded application, ** there is a chance that the blocking connection will have already ** concluded its transaction by the time sqlite3_unlock_notify() is invoked. ** If this happens, then the specified callback is invoked immediately, ** from within the call to sqlite3_unlock_notify().)^ ** |
︙ | ︙ | |||
8288 8289 8290 8291 8292 8293 8294 | ** When an unlock-notify callback is registered, the application provides a ** single void* pointer that is passed to the callback when it is invoked. ** However, the signature of the callback function allows SQLite to pass ** it an array of void* context pointers. The first argument passed to ** an unlock-notify callback is a pointer to an array of void* pointers, ** and the second is the number of entries in the array. ** | | | 8980 8981 8982 8983 8984 8985 8986 8987 8988 8989 8990 8991 8992 8993 8994 | ** When an unlock-notify callback is registered, the application provides a ** single void* pointer that is passed to the callback when it is invoked. ** However, the signature of the callback function allows SQLite to pass ** it an array of void* context pointers. The first argument passed to ** an unlock-notify callback is a pointer to an array of void* pointers, ** and the second is the number of entries in the array. ** ** When a blocking connection's transaction is concluded, there may be ** more than one blocked connection that has registered for an unlock-notify ** callback. ^If two or more such blocked connections have specified the ** same callback function, then instead of invoking the callback function ** multiple times, it is invoked once with the set of void* context pointers ** specified by the blocked connections bundled together into an array. ** This gives the application an opportunity to prioritize any actions ** related to the set of unblocked database connections. |
︙ | ︙ | |||
8448 8449 8450 8451 8452 8453 8454 | ** to report an error, though the commit will have still occurred. If the ** callback returns [SQLITE_ROW] or [SQLITE_DONE], or if it returns a value ** that does not correspond to any valid SQLite error code, the results ** are undefined. ** ** A single database handle may have at most a single write-ahead log callback ** registered at one time. ^Calling [sqlite3_wal_hook()] replaces any | | > | | 9140 9141 9142 9143 9144 9145 9146 9147 9148 9149 9150 9151 9152 9153 9154 9155 9156 | ** to report an error, though the commit will have still occurred. If the ** callback returns [SQLITE_ROW] or [SQLITE_DONE], or if it returns a value ** that does not correspond to any valid SQLite error code, the results ** are undefined. ** ** A single database handle may have at most a single write-ahead log callback ** registered at one time. ^Calling [sqlite3_wal_hook()] replaces any ** previously registered write-ahead log callback. ^The return value is ** a copy of the third parameter from the previous call, if any, or 0. ** ^Note that the [sqlite3_wal_autocheckpoint()] interface and the ** [wal_autocheckpoint pragma] both invoke [sqlite3_wal_hook()] and will ** overwrite any prior [sqlite3_wal_hook()] settings. */ void *sqlite3_wal_hook( sqlite3*, int(*)(void *,sqlite3*,const char*,int), void* |
︙ | ︙ | |||
8636 8637 8638 8639 8640 8641 8642 | ** This function may be called by either the [xConnect] or [xCreate] method ** of a [virtual table] implementation to configure ** various facets of the virtual table interface. ** ** If this interface is invoked outside the context of an xConnect or ** xCreate virtual table method then the behavior is undefined. ** | | | > > > > | > > | | 9329 9330 9331 9332 9333 9334 9335 9336 9337 9338 9339 9340 9341 9342 9343 9344 9345 9346 9347 9348 9349 9350 9351 9352 9353 9354 9355 9356 9357 9358 9359 9360 9361 9362 9363 9364 | ** This function may be called by either the [xConnect] or [xCreate] method ** of a [virtual table] implementation to configure ** various facets of the virtual table interface. ** ** If this interface is invoked outside the context of an xConnect or ** xCreate virtual table method then the behavior is undefined. ** ** In the call sqlite3_vtab_config(D,C,...) the D parameter is the ** [database connection] in which the virtual table is being created and ** which is passed in as the first argument to the [xConnect] or [xCreate] ** method that is invoking sqlite3_vtab_config(). The C parameter is one ** of the [virtual table configuration options]. The presence and meaning ** of parameters after C depend on which [virtual table configuration option] ** is used. */ int sqlite3_vtab_config(sqlite3*, int op, ...); /* ** CAPI3REF: Virtual Table Configuration Options ** KEYWORDS: {virtual table configuration options} ** KEYWORDS: {virtual table configuration option} ** ** These macros define the various options to the ** [sqlite3_vtab_config()] interface that [virtual table] implementations ** can use to customize and optimize their behavior. ** ** <dl> ** [[SQLITE_VTAB_CONSTRAINT_SUPPORT]] ** <dt>SQLITE_VTAB_CONSTRAINT_SUPPORT</dt> ** <dd>Calls of the form ** [sqlite3_vtab_config](db,SQLITE_VTAB_CONSTRAINT_SUPPORT,X) are supported, ** where X is an integer. If X is zero, then the [virtual table] whose ** [xCreate] or [xConnect] method invoked [sqlite3_vtab_config()] does not ** support constraints. In this configuration (which is the default) if ** a call to the [xUpdate] method returns [SQLITE_CONSTRAINT], then the entire ** statement is rolled back as if [ON CONFLICT | OR ABORT] had been |
︙ | ︙ | |||
8680 8681 8682 8683 8684 8685 8686 8687 8688 8689 8690 8691 8692 8693 8694 8695 8696 8697 8698 8699 8700 8701 8702 8703 8704 8705 8706 | ** must do so within the [xUpdate] method. If a call to the ** [sqlite3_vtab_on_conflict()] function indicates that the current ON ** CONFLICT policy is REPLACE, the virtual table implementation should ** silently replace the appropriate rows within the xUpdate callback and ** return SQLITE_OK. Or, if this is not possible, it may return ** SQLITE_CONSTRAINT, in which case SQLite falls back to OR ABORT ** constraint handling. ** </dl> */ #define SQLITE_VTAB_CONSTRAINT_SUPPORT 1 /* ** CAPI3REF: Determine The Virtual Table Conflict Policy ** ** This function may only be called from within a call to the [xUpdate] method ** of a [virtual table] implementation for an INSERT or UPDATE operation. ^The ** value returned is one of [SQLITE_ROLLBACK], [SQLITE_IGNORE], [SQLITE_FAIL], ** [SQLITE_ABORT], or [SQLITE_REPLACE], according to the [ON CONFLICT] mode ** of the SQL statement that triggered the call to the [xUpdate] method of the ** [virtual table]. */ int sqlite3_vtab_on_conflict(sqlite3 *); /* ** CAPI3REF: Determine If Virtual Table Column Access Is For UPDATE ** ** If the sqlite3_vtab_nochange(X) routine is called within the [xColumn] | > > > > > > > > > > > > > > > > > > > > > > | | > | > > > > > > | 9379 9380 9381 9382 9383 9384 9385 9386 9387 9388 9389 9390 9391 9392 9393 9394 9395 9396 9397 9398 9399 9400 9401 9402 9403 9404 9405 9406 9407 9408 9409 9410 9411 9412 9413 9414 9415 9416 9417 9418 9419 9420 9421 9422 9423 9424 9425 9426 9427 9428 9429 9430 9431 9432 9433 9434 9435 9436 9437 9438 9439 9440 9441 9442 9443 9444 9445 9446 9447 9448 9449 9450 9451 9452 9453 | ** must do so within the [xUpdate] method. If a call to the ** [sqlite3_vtab_on_conflict()] function indicates that the current ON ** CONFLICT policy is REPLACE, the virtual table implementation should ** silently replace the appropriate rows within the xUpdate callback and ** return SQLITE_OK. Or, if this is not possible, it may return ** SQLITE_CONSTRAINT, in which case SQLite falls back to OR ABORT ** constraint handling. ** </dd> ** ** [[SQLITE_VTAB_DIRECTONLY]]<dt>SQLITE_VTAB_DIRECTONLY</dt> ** <dd>Calls of the form ** [sqlite3_vtab_config](db,SQLITE_VTAB_DIRECTONLY) from within the ** the [xConnect] or [xCreate] methods of a [virtual table] implmentation ** prohibits that virtual table from being used from within triggers and ** views. ** </dd> ** ** [[SQLITE_VTAB_INNOCUOUS]]<dt>SQLITE_VTAB_INNOCUOUS</dt> ** <dd>Calls of the form ** [sqlite3_vtab_config](db,SQLITE_VTAB_INNOCUOUS) from within the ** the [xConnect] or [xCreate] methods of a [virtual table] implmentation ** identify that virtual table as being safe to use from within triggers ** and views. Conceptually, the SQLITE_VTAB_INNOCUOUS tag means that the ** virtual table can do no serious harm even if it is controlled by a ** malicious hacker. Developers should avoid setting the SQLITE_VTAB_INNOCUOUS ** flag unless absolutely necessary. ** </dd> ** </dl> */ #define SQLITE_VTAB_CONSTRAINT_SUPPORT 1 #define SQLITE_VTAB_INNOCUOUS 2 #define SQLITE_VTAB_DIRECTONLY 3 /* ** CAPI3REF: Determine The Virtual Table Conflict Policy ** ** This function may only be called from within a call to the [xUpdate] method ** of a [virtual table] implementation for an INSERT or UPDATE operation. ^The ** value returned is one of [SQLITE_ROLLBACK], [SQLITE_IGNORE], [SQLITE_FAIL], ** [SQLITE_ABORT], or [SQLITE_REPLACE], according to the [ON CONFLICT] mode ** of the SQL statement that triggered the call to the [xUpdate] method of the ** [virtual table]. */ int sqlite3_vtab_on_conflict(sqlite3 *); /* ** CAPI3REF: Determine If Virtual Table Column Access Is For UPDATE ** ** If the sqlite3_vtab_nochange(X) routine is called within the [xColumn] ** method of a [virtual table], then it might return true if the ** column is being fetched as part of an UPDATE operation during which the ** column value will not change. The virtual table implementation can use ** this hint as permission to substitute a return value that is less ** expensive to compute and that the corresponding ** [xUpdate] method understands as a "no-change" value. ** ** If the [xColumn] method calls sqlite3_vtab_nochange() and finds that ** the column is not changed by the UPDATE statement, then the xColumn ** method can optionally return without setting a result, without calling ** any of the [sqlite3_result_int|sqlite3_result_xxxxx() interfaces]. ** In that case, [sqlite3_value_nochange(X)] will return true for the ** same column in the [xUpdate] method. ** ** The sqlite3_vtab_nochange() routine is an optimization. Virtual table ** implementations should continue to give a correct answer even if the ** sqlite3_vtab_nochange() interface were to always return false. In the ** current implementation, the sqlite3_vtab_nochange() interface does always ** returns false for the enhanced [UPDATE FROM] statement. */ int sqlite3_vtab_nochange(sqlite3_context*); /* ** CAPI3REF: Determine The Collation For a Virtual Table Constraint ** ** This function may only be called from within a call to the [xBestIndex] |
︙ | ︙ | |||
8762 8763 8764 8765 8766 8767 8768 | ** ** When the value returned to V is a string, space to hold that string is ** managed by the prepared statement S and will be automatically freed when ** S is finalized. ** ** <dl> ** [[SQLITE_SCANSTAT_NLOOP]] <dt>SQLITE_SCANSTAT_NLOOP</dt> | | | | | | | | 9490 9491 9492 9493 9494 9495 9496 9497 9498 9499 9500 9501 9502 9503 9504 9505 9506 9507 9508 9509 9510 9511 9512 9513 9514 9515 9516 9517 9518 9519 9520 9521 9522 9523 9524 9525 9526 9527 9528 9529 9530 | ** ** When the value returned to V is a string, space to hold that string is ** managed by the prepared statement S and will be automatically freed when ** S is finalized. ** ** <dl> ** [[SQLITE_SCANSTAT_NLOOP]] <dt>SQLITE_SCANSTAT_NLOOP</dt> ** <dd>^The [sqlite3_int64] variable pointed to by the V parameter will be ** set to the total number of times that the X-th loop has run.</dd> ** ** [[SQLITE_SCANSTAT_NVISIT]] <dt>SQLITE_SCANSTAT_NVISIT</dt> ** <dd>^The [sqlite3_int64] variable pointed to by the V parameter will be set ** to the total number of rows examined by all iterations of the X-th loop.</dd> ** ** [[SQLITE_SCANSTAT_EST]] <dt>SQLITE_SCANSTAT_EST</dt> ** <dd>^The "double" variable pointed to by the V parameter will be set to the ** query planner's estimate for the average number of rows output from each ** iteration of the X-th loop. If the query planner's estimates was accurate, ** then this value will approximate the quotient NVISIT/NLOOP and the ** product of this value for all prior loops with the same SELECTID will ** be the NLOOP value for the current loop. ** ** [[SQLITE_SCANSTAT_NAME]] <dt>SQLITE_SCANSTAT_NAME</dt> ** <dd>^The "const char *" variable pointed to by the V parameter will be set ** to a zero-terminated UTF-8 string containing the name of the index or table ** used for the X-th loop. ** ** [[SQLITE_SCANSTAT_EXPLAIN]] <dt>SQLITE_SCANSTAT_EXPLAIN</dt> ** <dd>^The "const char *" variable pointed to by the V parameter will be set ** to a zero-terminated UTF-8 string containing the [EXPLAIN QUERY PLAN] ** description for the X-th loop. ** ** [[SQLITE_SCANSTAT_SELECTID]] <dt>SQLITE_SCANSTAT_SELECT</dt> ** <dd>^The "int" variable pointed to by the V parameter will be set to the ** "select-id" for the X-th loop. The select-id identifies which query or ** subquery the loop is part of. The main query has a select-id of zero. ** The select-id is the same value as is output in the first column ** of an [EXPLAIN QUERY PLAN] query. ** </dl> */ #define SQLITE_SCANSTAT_NLOOP 0 |
︙ | ︙ | |||
8853 8854 8855 8856 8857 8858 8859 8860 8861 8862 8863 8864 8865 8866 | ** This API is only available if the library is built with pre-processor ** symbol [SQLITE_ENABLE_STMT_SCANSTATUS] defined. */ void sqlite3_stmt_scanstatus_reset(sqlite3_stmt*); /* ** CAPI3REF: Flush caches to disk mid-transaction ** ** ^If a write-transaction is open on [database connection] D when the ** [sqlite3_db_cacheflush(D)] interface invoked, any dirty ** pages in the pager-cache that are not currently in use are written out ** to disk. A dirty page may be in use if a database cursor created by an ** active SQL statement is reading from it, or if it is page 1 of a database ** file (page 1 is always "in use"). ^The [sqlite3_db_cacheflush(D)] | > | 9581 9582 9583 9584 9585 9586 9587 9588 9589 9590 9591 9592 9593 9594 9595 | ** This API is only available if the library is built with pre-processor ** symbol [SQLITE_ENABLE_STMT_SCANSTATUS] defined. */ void sqlite3_stmt_scanstatus_reset(sqlite3_stmt*); /* ** CAPI3REF: Flush caches to disk mid-transaction ** METHOD: sqlite3 ** ** ^If a write-transaction is open on [database connection] D when the ** [sqlite3_db_cacheflush(D)] interface invoked, any dirty ** pages in the pager-cache that are not currently in use are written out ** to disk. A dirty page may be in use if a database cursor created by an ** active SQL statement is reading from it, or if it is page 1 of a database ** file (page 1 is always "in use"). ^The [sqlite3_db_cacheflush(D)] |
︙ | ︙ | |||
8885 8886 8887 8888 8889 8890 8891 8892 8893 8894 8895 8896 8897 8898 8899 8900 8901 8902 8903 8904 8905 8906 8907 8908 | ** ^This function does not set the database handle error code or message ** returned by the [sqlite3_errcode()] and [sqlite3_errmsg()] functions. */ int sqlite3_db_cacheflush(sqlite3*); /* ** CAPI3REF: The pre-update hook. ** ** ^These interfaces are only available if SQLite is compiled using the ** [SQLITE_ENABLE_PREUPDATE_HOOK] compile-time option. ** ** ^The [sqlite3_preupdate_hook()] interface registers a callback function ** that is invoked prior to each [INSERT], [UPDATE], and [DELETE] operation ** on a database table. ** ^At most one preupdate hook may be registered at a time on a single ** [database connection]; each call to [sqlite3_preupdate_hook()] overrides ** the previous setting. ** ^The preupdate hook is disabled by invoking [sqlite3_preupdate_hook()] ** with a NULL pointer as the second parameter. ** ^The third parameter to [sqlite3_preupdate_hook()] is passed through as ** the first parameter to callbacks. ** ** ^The preupdate hook only fires for changes to real database tables; the ** preupdate hook is not invoked for changes to [virtual tables] or to | > | | 9614 9615 9616 9617 9618 9619 9620 9621 9622 9623 9624 9625 9626 9627 9628 9629 9630 9631 9632 9633 9634 9635 9636 9637 9638 9639 9640 9641 9642 9643 9644 9645 9646 | ** ^This function does not set the database handle error code or message ** returned by the [sqlite3_errcode()] and [sqlite3_errmsg()] functions. */ int sqlite3_db_cacheflush(sqlite3*); /* ** CAPI3REF: The pre-update hook. ** METHOD: sqlite3 ** ** ^These interfaces are only available if SQLite is compiled using the ** [SQLITE_ENABLE_PREUPDATE_HOOK] compile-time option. ** ** ^The [sqlite3_preupdate_hook()] interface registers a callback function ** that is invoked prior to each [INSERT], [UPDATE], and [DELETE] operation ** on a database table. ** ^At most one preupdate hook may be registered at a time on a single ** [database connection]; each call to [sqlite3_preupdate_hook()] overrides ** the previous setting. ** ^The preupdate hook is disabled by invoking [sqlite3_preupdate_hook()] ** with a NULL pointer as the second parameter. ** ^The third parameter to [sqlite3_preupdate_hook()] is passed through as ** the first parameter to callbacks. ** ** ^The preupdate hook only fires for changes to real database tables; the ** preupdate hook is not invoked for changes to [virtual tables] or to ** system tables like sqlite_sequence or sqlite_stat1. ** ** ^The second parameter to the preupdate callback is a pointer to ** the [database connection] that registered the preupdate hook. ** ^The third parameter to the preupdate callback is one of the constants ** [SQLITE_INSERT], [SQLITE_DELETE], or [SQLITE_UPDATE] to identify the ** kind of update operation that is about to occur. ** ^(The fourth parameter to the preupdate callback is the name of the |
︙ | ︙ | |||
8925 8926 8927 8928 8929 8930 8931 | ** parameter passed to the preupdate callback is the initial [rowid] of the ** row being modified or deleted. For an INSERT operation on a rowid table, ** or any operation on a WITHOUT ROWID table, the value of the sixth ** parameter is undefined. For an INSERT or UPDATE on a rowid table the ** seventh parameter is the final rowid value of the row being inserted ** or updated. The value of the seventh parameter passed to the callback ** function is not defined for operations on WITHOUT ROWID tables, or for | | | 9655 9656 9657 9658 9659 9660 9661 9662 9663 9664 9665 9666 9667 9668 9669 | ** parameter passed to the preupdate callback is the initial [rowid] of the ** row being modified or deleted. For an INSERT operation on a rowid table, ** or any operation on a WITHOUT ROWID table, the value of the sixth ** parameter is undefined. For an INSERT or UPDATE on a rowid table the ** seventh parameter is the final rowid value of the row being inserted ** or updated. The value of the seventh parameter passed to the callback ** function is not defined for operations on WITHOUT ROWID tables, or for ** DELETE operations on rowid tables. ** ** The [sqlite3_preupdate_old()], [sqlite3_preupdate_new()], ** [sqlite3_preupdate_count()], and [sqlite3_preupdate_depth()] interfaces ** provide additional information about a preupdate event. These routines ** may only be called from within a preupdate callback. Invoking any of ** these routines from outside of a preupdate callback or with a ** [database connection] pointer that is different from the one supplied |
︙ | ︙ | |||
8963 8964 8965 8966 8967 8968 8969 8970 8971 8972 8973 8974 8975 8976 8977 8978 8979 8980 8981 8982 8983 8984 8985 8986 8987 8988 8989 8990 8991 8992 8993 8994 8995 8996 8997 8998 8999 9000 | ** ** ^The [sqlite3_preupdate_depth(D)] interface returns 0 if the preupdate ** callback was invoked as a result of a direct insert, update, or delete ** operation; or 1 for inserts, updates, or deletes invoked by top-level ** triggers; or 2 for changes resulting from triggers called by top-level ** triggers; and so forth. ** ** See also: [sqlite3_update_hook()] */ #if defined(SQLITE_ENABLE_PREUPDATE_HOOK) void *sqlite3_preupdate_hook( sqlite3 *db, void(*xPreUpdate)( void *pCtx, /* Copy of third arg to preupdate_hook() */ sqlite3 *db, /* Database handle */ int op, /* SQLITE_UPDATE, DELETE or INSERT */ char const *zDb, /* Database name */ char const *zName, /* Table name */ sqlite3_int64 iKey1, /* Rowid of row about to be deleted/updated */ sqlite3_int64 iKey2 /* New rowid value (for a rowid UPDATE) */ ), void* ); int sqlite3_preupdate_old(sqlite3 *, int, sqlite3_value **); int sqlite3_preupdate_count(sqlite3 *); int sqlite3_preupdate_depth(sqlite3 *); int sqlite3_preupdate_new(sqlite3 *, int, sqlite3_value **); #endif /* ** CAPI3REF: Low-level system error code ** ** ^Attempt to return the underlying operating system error code or error ** number that caused the most recent I/O error or failure to open a file. ** The return value is OS-dependent. For example, on unix systems, after ** [sqlite3_open_v2()] returns [SQLITE_CANTOPEN], this interface could be ** called to get back the underlying "errno" that caused the problem, such ** as ENOSPC, EAUTH, EISDIR, and so forth. | > > > > > > > > > > > | 9693 9694 9695 9696 9697 9698 9699 9700 9701 9702 9703 9704 9705 9706 9707 9708 9709 9710 9711 9712 9713 9714 9715 9716 9717 9718 9719 9720 9721 9722 9723 9724 9725 9726 9727 9728 9729 9730 9731 9732 9733 9734 9735 9736 9737 9738 9739 9740 9741 | ** ** ^The [sqlite3_preupdate_depth(D)] interface returns 0 if the preupdate ** callback was invoked as a result of a direct insert, update, or delete ** operation; or 1 for inserts, updates, or deletes invoked by top-level ** triggers; or 2 for changes resulting from triggers called by top-level ** triggers; and so forth. ** ** When the [sqlite3_blob_write()] API is used to update a blob column, ** the pre-update hook is invoked with SQLITE_DELETE. This is because the ** in this case the new values are not available. In this case, when a ** callback made with op==SQLITE_DELETE is actuall a write using the ** sqlite3_blob_write() API, the [sqlite3_preupdate_blobwrite()] returns ** the index of the column being written. In other cases, where the ** pre-update hook is being invoked for some other reason, including a ** regular DELETE, sqlite3_preupdate_blobwrite() returns -1. ** ** See also: [sqlite3_update_hook()] */ #if defined(SQLITE_ENABLE_PREUPDATE_HOOK) void *sqlite3_preupdate_hook( sqlite3 *db, void(*xPreUpdate)( void *pCtx, /* Copy of third arg to preupdate_hook() */ sqlite3 *db, /* Database handle */ int op, /* SQLITE_UPDATE, DELETE or INSERT */ char const *zDb, /* Database name */ char const *zName, /* Table name */ sqlite3_int64 iKey1, /* Rowid of row about to be deleted/updated */ sqlite3_int64 iKey2 /* New rowid value (for a rowid UPDATE) */ ), void* ); int sqlite3_preupdate_old(sqlite3 *, int, sqlite3_value **); int sqlite3_preupdate_count(sqlite3 *); int sqlite3_preupdate_depth(sqlite3 *); int sqlite3_preupdate_new(sqlite3 *, int, sqlite3_value **); int sqlite3_preupdate_blobwrite(sqlite3 *); #endif /* ** CAPI3REF: Low-level system error code ** METHOD: sqlite3 ** ** ^Attempt to return the underlying operating system error code or error ** number that caused the most recent I/O error or failure to open a file. ** The return value is OS-dependent. For example, on unix systems, after ** [sqlite3_open_v2()] returns [SQLITE_CANTOPEN], this interface could be ** called to get back the underlying "errno" that caused the problem, such ** as ENOSPC, EAUTH, EISDIR, and so forth. |
︙ | ︙ | |||
9245 9246 9247 9248 9249 9250 9251 | ** SQLITE_SERIALIZE_NOCOPY bit is set but no contiguous copy ** of the database exists. ** ** A call to sqlite3_serialize(D,S,P,F) might return NULL even if the ** SQLITE_SERIALIZE_NOCOPY bit is omitted from argument F if a memory ** allocation error occurs. ** | | | | 9986 9987 9988 9989 9990 9991 9992 9993 9994 9995 9996 9997 9998 9999 10000 10001 | ** SQLITE_SERIALIZE_NOCOPY bit is set but no contiguous copy ** of the database exists. ** ** A call to sqlite3_serialize(D,S,P,F) might return NULL even if the ** SQLITE_SERIALIZE_NOCOPY bit is omitted from argument F if a memory ** allocation error occurs. ** ** This interface is omitted if SQLite is compiled with the ** [SQLITE_OMIT_DESERIALIZE] option. */ unsigned char *sqlite3_serialize( sqlite3 *db, /* The database connection */ const char *zSchema, /* Which DB to serialize. ex: "main", "temp", ... */ sqlite3_int64 *piSize, /* Write size of the DB here, if not NULL */ unsigned int mFlags /* Zero or more SQLITE_SERIALIZE_* flags */ ); |
︙ | ︙ | |||
9292 9293 9294 9295 9296 9297 9298 9299 9300 9301 9302 9303 | ** connection closes. If the SQLITE_DESERIALIZE_RESIZEABLE bit is set, then ** SQLite will try to increase the buffer size using sqlite3_realloc64() ** if writes on the database cause it to grow larger than M bytes. ** ** The sqlite3_deserialize() interface will fail with SQLITE_BUSY if the ** database is currently in a read transaction or is involved in a backup ** operation. ** ** If sqlite3_deserialize(D,S,P,N,M,F) fails for any reason and if the ** SQLITE_DESERIALIZE_FREEONCLOSE bit is set in argument F, then ** [sqlite3_free()] is invoked on argument P prior to returning. ** | > > > > | | | 10033 10034 10035 10036 10037 10038 10039 10040 10041 10042 10043 10044 10045 10046 10047 10048 10049 10050 10051 10052 10053 10054 10055 10056 10057 | ** connection closes. If the SQLITE_DESERIALIZE_RESIZEABLE bit is set, then ** SQLite will try to increase the buffer size using sqlite3_realloc64() ** if writes on the database cause it to grow larger than M bytes. ** ** The sqlite3_deserialize() interface will fail with SQLITE_BUSY if the ** database is currently in a read transaction or is involved in a backup ** operation. ** ** It is not possible to deserialized into the TEMP database. If the ** S argument to sqlite3_deserialize(D,S,P,N,M,F) is "temp" then the ** function returns SQLITE_ERROR. ** ** If sqlite3_deserialize(D,S,P,N,M,F) fails for any reason and if the ** SQLITE_DESERIALIZE_FREEONCLOSE bit is set in argument F, then ** [sqlite3_free()] is invoked on argument P prior to returning. ** ** This interface is omitted if SQLite is compiled with the ** [SQLITE_OMIT_DESERIALIZE] option. */ int sqlite3_deserialize( sqlite3 *db, /* The database connection */ const char *zSchema, /* Which DB to reopen with the deserialization */ unsigned char *pData, /* The serialized database content */ sqlite3_int64 szDb, /* Number bytes in the deserialization */ sqlite3_int64 szBuf, /* Total size of buffer pData[] */ |
︙ | ︙ |
Changes to src/sqlite3ext.h.
︙ | ︙ | |||
315 316 317 318 319 320 321 322 323 324 325 326 327 328 | void (*xStep)(sqlite3_context*,int,sqlite3_value**), void (*xFinal)(sqlite3_context*), void (*xValue)(sqlite3_context*), void (*xInv)(sqlite3_context*,int,sqlite3_value**), void(*xDestroy)(void*)); /* Version 3.26.0 and later */ const char *(*normalized_sql)(sqlite3_stmt*); }; /* ** This is the function signature used for all extension entry points. It ** is also defined in the file "loadext.c". */ typedef int (*sqlite3_loadext_entry)( | > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | void (*xStep)(sqlite3_context*,int,sqlite3_value**), void (*xFinal)(sqlite3_context*), void (*xValue)(sqlite3_context*), void (*xInv)(sqlite3_context*,int,sqlite3_value**), void(*xDestroy)(void*)); /* Version 3.26.0 and later */ const char *(*normalized_sql)(sqlite3_stmt*); /* Version 3.28.0 and later */ int (*stmt_isexplain)(sqlite3_stmt*); int (*value_frombind)(sqlite3_value*); /* Version 3.30.0 and later */ int (*drop_modules)(sqlite3*,const char**); /* Version 3.31.0 and later */ sqlite3_int64 (*hard_heap_limit64)(sqlite3_int64); const char *(*uri_key)(const char*,int); const char *(*filename_database)(const char*); const char *(*filename_journal)(const char*); const char *(*filename_wal)(const char*); /* Version 3.32.0 and later */ char *(*create_filename)(const char*,const char*,const char*, int,const char**); void (*free_filename)(char*); sqlite3_file *(*database_file_object)(const char*); /* Version 3.34.0 and later */ int (*txn_state)(sqlite3*,const char*); /* Version 3.36.1 and later */ sqlite3_int64 (*changes64)(sqlite3*); sqlite3_int64 (*total_changes64)(sqlite3*); /* Version 3.37.0 and later */ int (*autovacuum_pages)(sqlite3*, unsigned int(*)(void*,const char*,unsigned int,unsigned int,unsigned int), void*, void(*)(void*)); }; /* ** This is the function signature used for all extension entry points. It ** is also defined in the file "loadext.c". */ typedef int (*sqlite3_loadext_entry)( |
︙ | ︙ | |||
604 605 606 607 608 609 610 611 612 613 614 615 616 617 | #define sqlite3_str_errcode sqlite3_api->str_errcode #define sqlite3_str_length sqlite3_api->str_length #define sqlite3_str_value sqlite3_api->str_value /* Version 3.25.0 and later */ #define sqlite3_create_window_function sqlite3_api->create_window_function /* Version 3.26.0 and later */ #define sqlite3_normalized_sql sqlite3_api->normalized_sql #endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */ #if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) /* This case when the file really is being compiled as a loadable ** extension */ # define SQLITE_EXTENSION_INIT1 const sqlite3_api_routines *sqlite3_api=0; # define SQLITE_EXTENSION_INIT2(v) sqlite3_api=v; | > > > > > > > > > > > > > > > > > > > > > > | 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 | #define sqlite3_str_errcode sqlite3_api->str_errcode #define sqlite3_str_length sqlite3_api->str_length #define sqlite3_str_value sqlite3_api->str_value /* Version 3.25.0 and later */ #define sqlite3_create_window_function sqlite3_api->create_window_function /* Version 3.26.0 and later */ #define sqlite3_normalized_sql sqlite3_api->normalized_sql /* Version 3.28.0 and later */ #define sqlite3_stmt_isexplain sqlite3_api->stmt_isexplain #define sqlite3_value_frombind sqlite3_api->value_frombind /* Version 3.30.0 and later */ #define sqlite3_drop_modules sqlite3_api->drop_modules /* Version 3.31.0 and later */ #define sqlite3_hard_heap_limit64 sqlite3_api->hard_heap_limit64 #define sqlite3_uri_key sqlite3_api->uri_key #define sqlite3_filename_database sqlite3_api->filename_database #define sqlite3_filename_journal sqlite3_api->filename_journal #define sqlite3_filename_wal sqlite3_api->filename_wal /* Version 3.32.0 and later */ #define sqlite3_create_filename sqlite3_api->create_filename #define sqlite3_free_filename sqlite3_api->free_filename #define sqlite3_database_file_object sqlite3_api->database_file_object /* Version 3.34.0 and later */ #define sqlite3_txn_state sqlite3_api->txn_state /* Version 3.36.1 and later */ #define sqlite3_changes64 sqlite3_api->changes64 #define sqlite3_total_changes64 sqlite3_api->total_changes64 /* Version 3.37.0 and later */ #define sqlite3_autovacuum_pages sqlite3_api->autovacuum_pages #endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */ #if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) /* This case when the file really is being compiled as a loadable ** extension */ # define SQLITE_EXTENSION_INIT1 const sqlite3_api_routines *sqlite3_api=0; # define SQLITE_EXTENSION_INIT2(v) sqlite3_api=v; |
︙ | ︙ |
Changes to src/sqliteInt.h.
︙ | ︙ | |||
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 | #endif #if defined(_MSC_VER) && !defined(SQLITE_DISABLE_INTRINSIC) # define MSVC_VERSION _MSC_VER #else # define MSVC_VERSION 0 #endif /* Needed for various definitions... */ #if defined(__GNUC__) && !defined(_GNU_SOURCE) # define _GNU_SOURCE #endif #if defined(__OpenBSD__) && !defined(_BSD_SOURCE) # define _BSD_SOURCE #endif /* ** For MinGW, check to see if we can include the header file containing its ** version information, among other things. Normally, this internal MinGW ** header file would [only] be included automatically by other MinGW header ** files; however, the contained version information is now required by this ** header file to work around binary compatibility issues (see below) and ** this is the only known way to reliably obtain it. This entire #if block | > > > > > > > > > > > > > > > > > > > > > | 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 | #endif #if defined(_MSC_VER) && !defined(SQLITE_DISABLE_INTRINSIC) # define MSVC_VERSION _MSC_VER #else # define MSVC_VERSION 0 #endif /* ** Some C99 functions in "math.h" are only present for MSVC when its version ** is associated with Visual Studio 2013 or higher. */ #ifndef SQLITE_HAVE_C99_MATH_FUNCS # if MSVC_VERSION==0 || MSVC_VERSION>=1800 # define SQLITE_HAVE_C99_MATH_FUNCS (1) # else # define SQLITE_HAVE_C99_MATH_FUNCS (0) # endif #endif /* Needed for various definitions... */ #if defined(__GNUC__) && !defined(_GNU_SOURCE) # define _GNU_SOURCE #endif #if defined(__OpenBSD__) && !defined(_BSD_SOURCE) # define _BSD_SOURCE #endif /* ** Macro to disable warnings about missing "break" at the end of a "case". */ #if GCC_VERSION>=7000000 # define deliberate_fall_through __attribute__((fallthrough)); #else # define deliberate_fall_through #endif /* ** For MinGW, check to see if we can include the header file containing its ** version information, among other things. Normally, this internal MinGW ** header file would [only] be included automatically by other MinGW header ** files; however, the contained version information is now required by this ** header file to work around binary compatibility issues (see below) and ** this is the only known way to reliably obtain it. This entire #if block |
︙ | ︙ | |||
155 156 157 158 159 160 161 162 163 164 165 166 167 168 | */ #if !defined(_USE_32BIT_TIME_T) && !defined(_USE_64BIT_TIME_T) && \ defined(_WIN32) && !defined(_WIN64) && \ defined(__MINGW_MAJOR_VERSION) && __MINGW_MAJOR_VERSION >= 4 && \ defined(__MSVCRT__) # define _USE_32BIT_TIME_T #endif /* The public SQLite interface. The _FILE_OFFSET_BITS macro must appear ** first in QNX. Also, the _USE_32BIT_TIME_T macro must appear first for ** MinGW. */ #include "sqlite3.h" | > > > > > > > > > > > | 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 | */ #if !defined(_USE_32BIT_TIME_T) && !defined(_USE_64BIT_TIME_T) && \ defined(_WIN32) && !defined(_WIN64) && \ defined(__MINGW_MAJOR_VERSION) && __MINGW_MAJOR_VERSION >= 4 && \ defined(__MSVCRT__) # define _USE_32BIT_TIME_T #endif /* Optionally #include a user-defined header, whereby compilation options ** may be set prior to where they take effect, but after platform setup. ** If SQLITE_CUSTOM_INCLUDE=? is defined, its value names the #include ** file. */ #ifdef SQLITE_CUSTOM_INCLUDE # define INC_STRINGIFY_(f) #f # define INC_STRINGIFY(f) INC_STRINGIFY_(f) # include INC_STRINGIFY(SQLITE_CUSTOM_INCLUDE) #endif /* The public SQLite interface. The _FILE_OFFSET_BITS macro must appear ** first in QNX. Also, the _USE_32BIT_TIME_T macro must appear first for ** MinGW. */ #include "sqlite3.h" |
︙ | ︙ | |||
182 183 184 185 186 187 188 189 190 191 192 193 194 195 | #pragma warn -rch /* unreachable code */ #pragma warn -ccc /* Condition is always true or false */ #pragma warn -aus /* Assigned value is never used */ #pragma warn -csu /* Comparing signed and unsigned */ #pragma warn -spa /* Suspicious pointer arithmetic */ #endif /* ** Include standard header files as necessary */ #ifdef HAVE_STDINT_H #include <stdint.h> #endif #ifdef HAVE_INTTYPES_H | > > > > > > > > > > > > > > > > > | 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 | #pragma warn -rch /* unreachable code */ #pragma warn -ccc /* Condition is always true or false */ #pragma warn -aus /* Assigned value is never used */ #pragma warn -csu /* Comparing signed and unsigned */ #pragma warn -spa /* Suspicious pointer arithmetic */ #endif /* ** WAL mode depends on atomic aligned 32-bit loads and stores in a few ** places. The following macros try to make this explicit. */ #ifndef __has_extension # define __has_extension(x) 0 /* compatibility with non-clang compilers */ #endif #if GCC_VERSION>=4007000 || __has_extension(c_atomic) # define SQLITE_ATOMIC_INTRINSICS 1 # define AtomicLoad(PTR) __atomic_load_n((PTR),__ATOMIC_RELAXED) # define AtomicStore(PTR,VAL) __atomic_store_n((PTR),(VAL),__ATOMIC_RELAXED) #else # define SQLITE_ATOMIC_INTRINSICS 0 # define AtomicLoad(PTR) (*(PTR)) # define AtomicStore(PTR,VAL) (*(PTR) = (VAL)) #endif /* ** Include standard header files as necessary */ #ifdef HAVE_STDINT_H #include <stdint.h> #endif #ifdef HAVE_INTTYPES_H |
︙ | ︙ | |||
208 209 210 211 212 213 214 | ** that vary from one machine to the next. ** ** Ticket #3860: The llvm-gcc-4.2 compiler from Apple chokes on ** the ((void*)&((char*)0)[X]) construct. But MSVC chokes on ((void*)(X)). ** So we have to define the macros in different ways depending on the ** compiler. */ | > > > | < < < | 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 | ** that vary from one machine to the next. ** ** Ticket #3860: The llvm-gcc-4.2 compiler from Apple chokes on ** the ((void*)&((char*)0)[X]) construct. But MSVC chokes on ((void*)(X)). ** So we have to define the macros in different ways depending on the ** compiler. */ #if defined(HAVE_STDINT_H) /* Use this case if we have ANSI headers */ # define SQLITE_INT_TO_PTR(X) ((void*)(intptr_t)(X)) # define SQLITE_PTR_TO_INT(X) ((int)(intptr_t)(X)) #elif defined(__PTRDIFF_TYPE__) /* This case should work for GCC */ # define SQLITE_INT_TO_PTR(X) ((void*)(__PTRDIFF_TYPE__)(X)) # define SQLITE_PTR_TO_INT(X) ((int)(__PTRDIFF_TYPE__)(X)) #elif !defined(__GNUC__) /* Works for compilers other than LLVM */ # define SQLITE_INT_TO_PTR(X) ((void*)&((char*)0)[X]) # define SQLITE_PTR_TO_INT(X) ((int)(((char*)X)-(char*)0)) #else /* Generates a warning - but it always works */ # define SQLITE_INT_TO_PTR(X) ((void*)(X)) # define SQLITE_PTR_TO_INT(X) ((int)(X)) #endif /* ** A macro to hint to the compiler that a function should not be |
︙ | ︙ | |||
382 383 384 385 386 387 388 | ** to help ensure adequate test coverage in places where simple ** condition/decision coverage is inadequate. For example, testcase() ** can be used to make sure boundary values are tested. For ** bitmask tests, testcase() can be used to make sure each bit ** is significant and used at least once. On switch statements ** where multiple cases go to the same block of code, testcase() ** can insure that all cases are evaluated. | < | > | > | | 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 | ** to help ensure adequate test coverage in places where simple ** condition/decision coverage is inadequate. For example, testcase() ** can be used to make sure boundary values are tested. For ** bitmask tests, testcase() can be used to make sure each bit ** is significant and used at least once. On switch statements ** where multiple cases go to the same block of code, testcase() ** can insure that all cases are evaluated. */ #if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_DEBUG) # ifndef SQLITE_AMALGAMATION extern unsigned int sqlite3CoverageCounter; # endif # define testcase(X) if( X ){ sqlite3CoverageCounter += (unsigned)__LINE__; } #else # define testcase(X) #endif /* ** The TESTONLY macro is used to enclose variable declarations or ** other bits of code that are needed to support the arguments |
︙ | ︙ | |||
416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 | */ #ifndef NDEBUG # define VVA_ONLY(X) X #else # define VVA_ONLY(X) #endif /* ** The ALWAYS and NEVER macros surround boolean expressions which ** are intended to always be true or false, respectively. Such ** expressions could be omitted from the code completely. But they ** are included in a few cases in order to enhance the resilience ** of SQLite to unexpected behavior - to make the code "self-healing" ** or "ductile" rather than being "brittle" and crashing at the first ** hint of unplanned behavior. ** ** In other words, ALWAYS and NEVER are added for defensive code. ** ** When doing coverage testing ALWAYS and NEVER are hard-coded to ** be true and false so that the unreachable code they specify will ** not be counted as untested code. */ | > > > > > > > > | | 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 | */ #ifndef NDEBUG # define VVA_ONLY(X) X #else # define VVA_ONLY(X) #endif /* ** Disable ALWAYS() and NEVER() (make them pass-throughs) for coverage ** and mutation testing */ #if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_MUTATION_TEST) # define SQLITE_OMIT_AUXILIARY_SAFETY_CHECKS 1 #endif /* ** The ALWAYS and NEVER macros surround boolean expressions which ** are intended to always be true or false, respectively. Such ** expressions could be omitted from the code completely. But they ** are included in a few cases in order to enhance the resilience ** of SQLite to unexpected behavior - to make the code "self-healing" ** or "ductile" rather than being "brittle" and crashing at the first ** hint of unplanned behavior. ** ** In other words, ALWAYS and NEVER are added for defensive code. ** ** When doing coverage testing ALWAYS and NEVER are hard-coded to ** be true and false so that the unreachable code they specify will ** not be counted as untested code. */ #if defined(SQLITE_OMIT_AUXILIARY_SAFETY_CHECKS) # define ALWAYS(X) (1) # define NEVER(X) (0) #elif !defined(NDEBUG) # define ALWAYS(X) ((X)?1:(assert(0),0)) # define NEVER(X) ((X)?(assert(0),1):0) #else # define ALWAYS(X) (X) |
︙ | ︙ | |||
505 506 507 508 509 510 511 512 513 514 515 516 517 518 | /* ** SQLITE_ENABLE_EXPLAIN_COMMENTS is incompatible with SQLITE_OMIT_EXPLAIN */ #ifdef SQLITE_OMIT_EXPLAIN # undef SQLITE_ENABLE_EXPLAIN_COMMENTS #endif /* ** Return true (non-zero) if the input is an integer that is too large ** to fit in 32-bits. This macro is used inside of various testcase() ** macros to verify that we have tested SQLite for large-file support. */ #define IS_BIG_INT(X) (((X)&~(i64)0xffffffff)!=0) | > > > > > > > | 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 | /* ** SQLITE_ENABLE_EXPLAIN_COMMENTS is incompatible with SQLITE_OMIT_EXPLAIN */ #ifdef SQLITE_OMIT_EXPLAIN # undef SQLITE_ENABLE_EXPLAIN_COMMENTS #endif /* ** SQLITE_OMIT_VIRTUALTABLE implies SQLITE_OMIT_ALTERTABLE */ #if defined(SQLITE_OMIT_VIRTUALTABLE) && !defined(SQLITE_OMIT_ALTERTABLE) # define SQLITE_OMIT_ALTERTABLE #endif /* ** Return true (non-zero) if the input is an integer that is too large ** to fit in 32-bits. This macro is used inside of various testcase() ** macros to verify that we have tested SQLite for large-file support. */ #define IS_BIG_INT(X) (((X)&~(i64)0xffffffff)!=0) |
︙ | ︙ | |||
626 627 628 629 630 631 632 | /* ** The default initial allocation for the pagecache when using separate ** pagecaches for each database connection. A positive number is the ** number of pages. A negative number N translations means that a buffer ** of -1024*N bytes is allocated and used for as many pages as it will hold. ** | | | 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 | /* ** The default initial allocation for the pagecache when using separate ** pagecaches for each database connection. A positive number is the ** number of pages. A negative number N translations means that a buffer ** of -1024*N bytes is allocated and used for as many pages as it will hold. ** ** The default value of "20" was chosen to minimize the run-time of the ** speedtest1 test program with options: --shrink-memory --reprepare */ #ifndef SQLITE_DEFAULT_PCACHE_INITSZ # define SQLITE_DEFAULT_PCACHE_INITSZ 20 #endif /* |
︙ | ︙ | |||
788 789 790 791 792 793 794 795 796 797 798 799 800 801 | ** Set the SQLITE_PTRSIZE macro to the number of bytes in a pointer */ #ifndef SQLITE_PTRSIZE # if defined(__SIZEOF_POINTER__) # define SQLITE_PTRSIZE __SIZEOF_POINTER__ # elif defined(i386) || defined(__i386__) || defined(_M_IX86) || \ defined(_M_ARM) || defined(__arm__) || defined(__x86) || \ (defined(__TOS_AIX__) && !defined(__64BIT__)) # define SQLITE_PTRSIZE 4 # else # define SQLITE_PTRSIZE 8 # endif #endif | > | 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 | ** Set the SQLITE_PTRSIZE macro to the number of bytes in a pointer */ #ifndef SQLITE_PTRSIZE # if defined(__SIZEOF_POINTER__) # define SQLITE_PTRSIZE __SIZEOF_POINTER__ # elif defined(i386) || defined(__i386__) || defined(_M_IX86) || \ defined(_M_ARM) || defined(__arm__) || defined(__x86) || \ (defined(__APPLE__) && defined(__POWERPC__)) || \ (defined(__TOS_AIX__) && !defined(__64BIT__)) # define SQLITE_PTRSIZE 4 # else # define SQLITE_PTRSIZE 8 # endif #endif |
︙ | ︙ | |||
826 827 828 829 830 831 832 | ** ** For best performance, an attempt is made to guess at the byte-order ** using C-preprocessor macros. If that is unsuccessful, or if ** -DSQLITE_BYTEORDER=0 is set, then byte-order is determined ** at run-time. */ #ifndef SQLITE_BYTEORDER | | | | | | > | 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 | ** ** For best performance, an attempt is made to guess at the byte-order ** using C-preprocessor macros. If that is unsuccessful, or if ** -DSQLITE_BYTEORDER=0 is set, then byte-order is determined ** at run-time. */ #ifndef SQLITE_BYTEORDER # if defined(i386) || defined(__i386__) || defined(_M_IX86) || \ defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || \ defined(_M_AMD64) || defined(_M_ARM) || defined(__x86) || \ defined(__ARMEL__) || defined(__AARCH64EL__) || defined(_M_ARM64) # define SQLITE_BYTEORDER 1234 # elif defined(sparc) || defined(__ppc__) || \ defined(__ARMEB__) || defined(__AARCH64EB__) # define SQLITE_BYTEORDER 4321 # else # define SQLITE_BYTEORDER 0 # endif #endif #if SQLITE_BYTEORDER==4321 # define SQLITE_BIGENDIAN 1 |
︙ | ︙ | |||
862 863 864 865 866 867 868 869 870 871 872 873 874 875 | /* ** Constants for the largest and smallest possible 64-bit signed integers. ** These macros are designed to work correctly on both 32-bit and 64-bit ** compilers. */ #define LARGEST_INT64 (0xffffffff|(((i64)0x7fffffff)<<32)) #define SMALLEST_INT64 (((i64)-1) - LARGEST_INT64) /* ** Round up a number to the next larger multiple of 8. This is used ** to force 8-byte alignment on 64-bit architectures. */ #define ROUND8(x) (((x)+7)&~7) | > | 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 | /* ** Constants for the largest and smallest possible 64-bit signed integers. ** These macros are designed to work correctly on both 32-bit and 64-bit ** compilers. */ #define LARGEST_INT64 (0xffffffff|(((i64)0x7fffffff)<<32)) #define LARGEST_UINT64 (0xffffffff|(((u64)0xffffffff)<<32)) #define SMALLEST_INT64 (((i64)-1) - LARGEST_INT64) /* ** Round up a number to the next larger multiple of 8. This is used ** to force 8-byte alignment on 64-bit architectures. */ #define ROUND8(x) (((x)+7)&~7) |
︙ | ︙ | |||
930 931 932 933 934 935 936 | # define SQLITE_DEFAULT_MMAP_SIZE 0 #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 | < < < < < < < < < < < < < < > > > | > > > > > > > > > > > > > > > > > > > < < | > > | > > > > > > > > > > > | | > > > | | | | > | | 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 | # define SQLITE_DEFAULT_MMAP_SIZE 0 #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 /* ** SELECTTRACE_ENABLED will be either 1 or 0 depending on whether or not ** the Select query generator tracing logic is turned on. */ #if !defined(SQLITE_AMALGAMATION) extern u32 sqlite3SelectTrace; #endif #if defined(SQLITE_DEBUG) \ && (defined(SQLITE_TEST) || defined(SQLITE_ENABLE_SELECTTRACE)) # define SELECTTRACE_ENABLED 1 # define SELECTTRACE(K,P,S,X) \ if(sqlite3SelectTrace&(K)) \ sqlite3DebugPrintf("%u/%d/%p: ",(S)->selId,(P)->addrExplain,(S)),\ sqlite3DebugPrintf X #else # define SELECTTRACE(K,P,S,X) # define SELECTTRACE_ENABLED 0 #endif /* ** Macros for "wheretrace" */ extern u32 sqlite3WhereTrace; #if defined(SQLITE_DEBUG) \ && (defined(SQLITE_TEST) || defined(SQLITE_ENABLE_WHERETRACE)) # define WHERETRACE(K,X) if(sqlite3WhereTrace&(K)) sqlite3DebugPrintf X # define WHERETRACE_ENABLED 1 #else # define WHERETRACE(K,X) #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 ** handle is passed a pointer to sqlite.busyHandler. The busy-handler ** callback is currently invoked only from within pager.c. */ typedef struct BusyHandler BusyHandler; struct BusyHandler { int (*xBusyHandler)(void *,int); /* The busy callback */ void *pBusyArg; /* First arg to busy callback */ int nBusy; /* Incremented with each busy call */ }; /* ** Name of table that holds the database schema. ** ** The PREFERRED names are used whereever possible. But LEGACY is also ** used for backwards compatibility. ** ** 1. Queries can use either the PREFERRED or the LEGACY names ** 2. The sqlite3_set_authorizer() callback uses the LEGACY name ** 3. The PRAGMA table_list statement uses the PREFERRED name ** ** The LEGACY names are stored in the internal symbol hash table ** in support of (2). Names are translated using sqlite3PreferredTableName() ** for (3). The sqlite3FindTable() function takes care of translating ** names for (1). ** ** Note that "sqlite_temp_schema" can also be called "temp.sqlite_schema". */ #define LEGACY_SCHEMA_TABLE "sqlite_master" #define LEGACY_TEMP_SCHEMA_TABLE "sqlite_temp_master" #define PREFERRED_SCHEMA_TABLE "sqlite_schema" #define PREFERRED_TEMP_SCHEMA_TABLE "sqlite_temp_schema" /* ** The root-page of the schema table. */ #define SCHEMA_ROOT 1 /* ** The name of the schema table. The name is different for TEMP. */ #define SCHEMA_TABLE(x) \ ((!OMIT_TEMPDB)&&(x==1)?LEGACY_TEMP_SCHEMA_TABLE:LEGACY_SCHEMA_TABLE) /* ** A convenience macro that returns the number of elements in ** an array. */ #define ArraySize(X) ((int)(sizeof(X)/sizeof(X[0]))) /* ** Determine if the argument is a power of two */ #define IsPowerOfTwo(X) (((X)&((X)-1))==0) /* ** The following value as a destructor means to use sqlite3DbFree(). ** The sqlite3DbFree() routine requires two parameters instead of the ** one parameter that destructors normally want. So we have to introduce ** this magic value that the code knows to handle differently. Any ** pointer will work here as long as it is distinct from SQLITE_STATIC ** and SQLITE_TRANSIENT. */ #define SQLITE_DYNAMIC ((sqlite3_destructor_type)sqlite3OomFault) /* ** When SQLITE_OMIT_WSD is defined, it means that the target platform does ** not support Writable Static Data (WSD) such as global and static variables. ** All variables must either be on the stack or dynamically allocated from ** the heap. When WSD is unsupported, the variable declarations scattered ** throughout the SQLite code must become constants instead. The SQLITE_WSD |
︙ | ︙ | |||
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 | */ typedef struct AggInfo AggInfo; typedef struct AuthContext AuthContext; typedef struct AutoincInfo AutoincInfo; typedef struct Bitvec Bitvec; typedef struct CollSeq CollSeq; typedef struct Column Column; typedef struct Db Db; typedef struct Schema Schema; typedef struct Expr Expr; typedef struct ExprList ExprList; typedef struct FKey FKey; typedef struct FuncDestructor FuncDestructor; typedef struct FuncDef FuncDef; typedef struct FuncDefHash FuncDefHash; typedef struct IdList IdList; typedef struct Index Index; typedef struct IndexSample IndexSample; typedef struct KeyClass KeyClass; typedef struct KeyInfo KeyInfo; typedef struct Lookaside Lookaside; typedef struct LookasideSlot LookasideSlot; typedef struct Module Module; typedef struct NameContext NameContext; typedef struct Parse Parse; typedef struct PreUpdate PreUpdate; typedef struct PrintfArguments PrintfArguments; typedef struct RenameToken RenameToken; typedef struct RowSet RowSet; typedef struct Savepoint Savepoint; typedef struct Select Select; typedef struct SQLiteThread SQLiteThread; typedef struct SelectDest SelectDest; typedef struct SrcList SrcList; typedef struct sqlite3_str StrAccum; /* Internal alias for sqlite3_str */ typedef struct Table Table; typedef struct TableLock TableLock; typedef struct Token Token; typedef struct TreeView TreeView; typedef struct Trigger Trigger; | > > > > > > > | 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 | */ typedef struct AggInfo AggInfo; typedef struct AuthContext AuthContext; typedef struct AutoincInfo AutoincInfo; typedef struct Bitvec Bitvec; typedef struct CollSeq CollSeq; typedef struct Column Column; typedef struct Cte Cte; typedef struct CteUse CteUse; typedef struct Db Db; typedef struct DbFixer DbFixer; typedef struct Schema Schema; typedef struct Expr Expr; typedef struct ExprList ExprList; typedef struct FastPrng FastPrng; typedef struct FKey FKey; typedef struct FuncDestructor FuncDestructor; typedef struct FuncDef FuncDef; typedef struct FuncDefHash FuncDefHash; typedef struct IdList IdList; typedef struct Index Index; typedef struct IndexSample IndexSample; typedef struct KeyClass KeyClass; typedef struct KeyInfo KeyInfo; typedef struct Lookaside Lookaside; typedef struct LookasideSlot LookasideSlot; typedef struct Module Module; typedef struct NameContext NameContext; typedef struct Parse Parse; typedef struct ParseCleanup ParseCleanup; typedef struct PreUpdate PreUpdate; typedef struct PrintfArguments PrintfArguments; typedef struct RenameToken RenameToken; typedef struct Returning Returning; typedef struct RowSet RowSet; typedef struct Savepoint Savepoint; typedef struct Select Select; typedef struct SQLiteThread SQLiteThread; typedef struct SelectDest SelectDest; typedef struct SrcItem SrcItem; typedef struct SrcList SrcList; typedef struct sqlite3_str StrAccum; /* Internal alias for sqlite3_str */ typedef struct Table Table; typedef struct TableLock TableLock; typedef struct Token Token; typedef struct TreeView TreeView; typedef struct Trigger Trigger; |
︙ | ︙ | |||
1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 | */ #define BMS ((int)(sizeof(Bitmask)*8)) /* ** A bit in a Bitmask */ #define MASKBIT(n) (((Bitmask)1)<<(n)) #define MASKBIT32(n) (((unsigned int)1)<<(n)) #define ALLBITS ((Bitmask)-1) /* A VList object records a mapping between parameters/variables/wildcards ** in the SQL statement (such as $abc, @pqr, or :xyz) and the integer ** variable number associated with that parameter. See the format description ** on the sqlite3VListAdd() routine for more information. A VList is really ** just an array of integers. */ typedef int VList; /* ** Defer sourcing vdbe.h and btree.h until after the "u8" and ** "BusyHandler" typedefs. vdbe.h also requires a few of the opaque ** pointer types (i.e. FuncDef) defined above. */ | > | | | | 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 | */ #define BMS ((int)(sizeof(Bitmask)*8)) /* ** A bit in a Bitmask */ #define MASKBIT(n) (((Bitmask)1)<<(n)) #define MASKBIT64(n) (((u64)1)<<(n)) #define MASKBIT32(n) (((unsigned int)1)<<(n)) #define ALLBITS ((Bitmask)-1) /* A VList object records a mapping between parameters/variables/wildcards ** in the SQL statement (such as $abc, @pqr, or :xyz) and the integer ** variable number associated with that parameter. See the format description ** on the sqlite3VListAdd() routine for more information. A VList is really ** just an array of integers. */ typedef int VList; /* ** Defer sourcing vdbe.h and btree.h until after the "u8" and ** "BusyHandler" typedefs. vdbe.h also requires a few of the opaque ** pointer types (i.e. FuncDef) defined above. */ #include "pager.h" #include "btree.h" #include "vdbe.h" #include "pcache.h" #include "os.h" #include "mutex.h" /* The SQLITE_EXTRA_DURABLE compile-time option used to set the default ** synchronous setting to EXTRA. It is no longer supported. */ |
︙ | ︙ | |||
1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 | */ #ifndef SQLITE_DEFAULT_SYNCHRONOUS # define SQLITE_DEFAULT_SYNCHRONOUS 2 #endif #ifndef SQLITE_DEFAULT_WAL_SYNCHRONOUS # define SQLITE_DEFAULT_WAL_SYNCHRONOUS SQLITE_DEFAULT_SYNCHRONOUS #endif /* ** Each database file to be accessed by the system is an instance ** of the following structure. There are normally two of these structures ** in the sqlite.aDb[] array. aDb[0] is the main database file and ** aDb[1] is the database file used to hold temporary tables. Additional ** databases may be attached. | > > > > > > > > | 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 | */ #ifndef SQLITE_DEFAULT_SYNCHRONOUS # define SQLITE_DEFAULT_SYNCHRONOUS 2 #endif #ifndef SQLITE_DEFAULT_WAL_SYNCHRONOUS # define SQLITE_DEFAULT_WAL_SYNCHRONOUS SQLITE_DEFAULT_SYNCHRONOUS #endif /* ** State of a simple PRNG used for the per-connection and per-pager ** pseudo-random number generators. */ struct FastPrng { unsigned int x, y; }; /* ** Each database file to be accessed by the system is an instance ** of the following structure. There are normally two of these structures ** in the sqlite.aDb[] array. aDb[0] is the main database file and ** aDb[1] is the database file used to hold temporary tables. Additional ** databases may be attached. |
︙ | ︙ | |||
1252 1253 1254 1255 1256 1257 1258 | ** ** DB_UnresetViews means that one or more views have column names that ** have been filled out. If the schema changes, these column names might ** changes and so the view will need to be reset. */ #define DB_SchemaLoaded 0x0001 /* The schema has been loaded */ #define DB_UnresetViews 0x0002 /* Some views have defined column names */ | < | 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 | ** ** DB_UnresetViews means that one or more views have column names that ** have been filled out. If the schema changes, these column names might ** changes and so the view will need to be reset. */ #define DB_SchemaLoaded 0x0001 /* The schema has been loaded */ #define DB_UnresetViews 0x0002 /* Some views have defined column names */ #define DB_ResetWanted 0x0008 /* Reset the schema when nSchemaLock==0 */ /* ** The number of different kinds of things that can be limited ** using the sqlite3_limit() interface. */ #define SQLITE_N_LIMIT (SQLITE_LIMIT_WORKER_THREADS+1) |
︙ | ︙ | |||
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 | ** ** Lookaside allocations are only allowed for objects that are associated ** with a particular database connection. Hence, schema information cannot ** be stored in lookaside because in shared cache mode the schema information ** is shared by multiple database connections. Therefore, while parsing ** schema information, the Lookaside.bEnabled flag is cleared so that ** lookaside allocations are not used to construct the schema objects. */ struct Lookaside { u32 bDisable; /* Only operate the lookaside when zero */ u16 sz; /* Size of each buffer in bytes */ u8 bMalloced; /* True if pStart obtained from sqlite3_malloc() */ u32 nSlot; /* Number of lookaside slots allocated */ u32 anStat[3]; /* 0: hits. 1: size misses. 2: full misses */ LookasideSlot *pInit; /* List of buffers not previously used */ LookasideSlot *pFree; /* List of available buffers */ void *pStart; /* First byte of available memory space */ void *pEnd; /* First byte past end of available space */ }; struct LookasideSlot { LookasideSlot *pNext; /* Next buffer in the list of free buffers */ }; /* ** A hash table for built-in function definitions. (Application-defined ** functions use a regular table table from hash.h.) ** ** Hash each FuncDef structure into one of the FuncDefHash.a[] slots. ** Collisions are on the FuncDef.u.pHash chain. Use the SQLITE_FUNC_HASH() | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | ** ** Lookaside allocations are only allowed for objects that are associated ** with a particular database connection. Hence, schema information cannot ** be stored in lookaside because in shared cache mode the schema information ** is shared by multiple database connections. Therefore, while parsing ** schema information, the Lookaside.bEnabled flag is cleared so that ** lookaside allocations are not used to construct the schema objects. ** ** New lookaside allocations are only allowed if bDisable==0. When ** bDisable is greater than zero, sz is set to zero which effectively ** disables lookaside without adding a new test for the bDisable flag ** in a performance-critical path. sz should be set by to szTrue whenever ** bDisable changes back to zero. ** ** Lookaside buffers are initially held on the pInit list. As they are ** used and freed, they are added back to the pFree list. New allocations ** come off of pFree first, then pInit as a fallback. This dual-list ** allows use to compute a high-water mark - the maximum number of allocations ** outstanding at any point in the past - by subtracting the number of ** allocations on the pInit list from the total number of allocations. ** ** Enhancement on 2019-12-12: Two-size-lookaside ** The default lookaside configuration is 100 slots of 1200 bytes each. ** The larger slot sizes are important for performance, but they waste ** a lot of space, as most lookaside allocations are less than 128 bytes. ** The two-size-lookaside enhancement breaks up the lookaside allocation ** into two pools: One of 128-byte slots and the other of the default size ** (1200-byte) slots. Allocations are filled from the small-pool first, ** failing over to the full-size pool if that does not work. Thus more ** lookaside slots are available while also using less memory. ** This enhancement can be omitted by compiling with ** SQLITE_OMIT_TWOSIZE_LOOKASIDE. */ struct Lookaside { u32 bDisable; /* Only operate the lookaside when zero */ u16 sz; /* Size of each buffer in bytes */ u16 szTrue; /* True value of sz, even if disabled */ u8 bMalloced; /* True if pStart obtained from sqlite3_malloc() */ u32 nSlot; /* Number of lookaside slots allocated */ u32 anStat[3]; /* 0: hits. 1: size misses. 2: full misses */ LookasideSlot *pInit; /* List of buffers not previously used */ LookasideSlot *pFree; /* List of available buffers */ #ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE LookasideSlot *pSmallInit; /* List of small buffers not prediously used */ LookasideSlot *pSmallFree; /* List of available small buffers */ void *pMiddle; /* First byte past end of full-size buffers and ** the first byte of LOOKASIDE_SMALL buffers */ #endif /* SQLITE_OMIT_TWOSIZE_LOOKASIDE */ void *pStart; /* First byte of available memory space */ void *pEnd; /* First byte past end of available space */ }; struct LookasideSlot { LookasideSlot *pNext; /* Next buffer in the list of free buffers */ }; #define DisableLookaside db->lookaside.bDisable++;db->lookaside.sz=0 #define EnableLookaside db->lookaside.bDisable--;\ db->lookaside.sz=db->lookaside.bDisable?0:db->lookaside.szTrue /* Size of the smaller allocations in two-size lookside */ #ifdef SQLITE_OMIT_TWOSIZE_LOOKASIDE # define LOOKASIDE_SMALL 0 #else # define LOOKASIDE_SMALL 128 #endif /* ** A hash table for built-in function definitions. (Application-defined ** functions use a regular table table from hash.h.) ** ** Hash each FuncDef structure into one of the FuncDefHash.a[] slots. ** Collisions are on the FuncDef.u.pHash chain. Use the SQLITE_FUNC_HASH() |
︙ | ︙ | |||
1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 | #define SQLITE_TRACE_XPROFILE 0x80 /* Use the legacy xProfile */ #else #define SQLITE_TRACE_LEGACY 0 #define SQLITE_TRACE_XPROFILE 0 #endif /* SQLITE_OMIT_DEPRECATED */ #define SQLITE_TRACE_NONLEGACY_MASK 0x0f /* Normal flags */ /* ** Each database connection is an instance of the following structure. */ struct sqlite3 { sqlite3_vfs *pVfs; /* OS Interface */ struct Vdbe *pVdbe; /* List of active virtual machines */ | > > > > > | | | > | | | | > > > | > | > > > > | 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 | #define SQLITE_TRACE_XPROFILE 0x80 /* Use the legacy xProfile */ #else #define SQLITE_TRACE_LEGACY 0 #define SQLITE_TRACE_XPROFILE 0 #endif /* SQLITE_OMIT_DEPRECATED */ #define SQLITE_TRACE_NONLEGACY_MASK 0x0f /* Normal flags */ /* ** Maximum number of sqlite3.aDb[] entries. This is the number of attached ** databases plus 2 for "main" and "temp". */ #define SQLITE_MAX_DB (SQLITE_MAX_ATTACHED+2) /* ** Each database connection is an instance of the following structure. */ struct sqlite3 { sqlite3_vfs *pVfs; /* OS Interface */ struct Vdbe *pVdbe; /* List of active virtual machines */ CollSeq *pDfltColl; /* BINARY collseq for the database encoding */ sqlite3_mutex *mutex; /* Connection mutex */ Db *aDb; /* All backends */ int nDb; /* Number of backends currently in use */ u32 mDbFlags; /* flags recording internal state */ u64 flags; /* flags settable by pragmas. See below */ i64 lastRowid; /* ROWID of most recent insert (see above) */ i64 szMmap; /* Default mmap_size setting */ u32 nSchemaLock; /* Do not reset the schema when non-zero */ unsigned int openFlags; /* Flags passed to sqlite3_vfs.xOpen() */ int errCode; /* Most recent error code (SQLITE_*) */ int errMask; /* & result codes with this before returning */ int iSysErrno; /* Errno value from last system error */ u32 dbOptFlags; /* Flags to enable/disable optimizations */ u8 enc; /* Text encoding */ u8 autoCommit; /* The auto-commit flag. */ u8 eConcurrent; /* CONCURRENT_* value */ u8 temp_store; /* 1: file 2: memory 0: default */ u8 mallocFailed; /* True if we have seen a malloc failure */ u8 bBenignMalloc; /* Do not require OOMs if true */ u8 dfltLockMode; /* Default locking-mode for attached dbs */ signed char nextAutovac; /* Autovac setting after VACUUM if >=0 */ u8 suppressErr; /* Do not issue error messages if true */ u8 vtabOnConflict; /* Value to return for s3_vtab_on_conflict() */ u8 isTransactionSavepoint; /* True if the outermost savepoint is a TS */ u8 mTrace; /* zero or more SQLITE_TRACE flags */ u8 noSharedCache; /* True if no shared-cache backends */ u8 nSqlExec; /* Number of pending OP_SqlExec opcodes */ u8 eOpenState; /* Current condition of the connection */ int nextPagesize; /* Pagesize after VACUUM if >0 */ FastPrng sPrng; /* State of the per-connection PRNG */ i64 nChange; /* Value returned by sqlite3_changes() */ i64 nTotalChange; /* Value returned by sqlite3_total_changes() */ int aLimit[SQLITE_N_LIMIT]; /* Limits */ int nMaxSorterMmap; /* Maximum size of regions mapped by sorter */ struct sqlite3InitInfo { /* Information used during initialization */ Pgno newTnum; /* Rootpage of table being initialized */ u8 iDb; /* Which db file is being initialized */ u8 busy; /* TRUE if currently initializing */ unsigned orphanTrigger : 1; /* Last statement is orphaned TEMP trigger */ unsigned imposterTable : 1; /* Building an imposter table */ unsigned reopenMemdb : 1; /* ATTACH is really a reopen using MemDB */ const char **azInit; /* "type", "name", and "tbl_name" columns */ } init; int nVdbeActive; /* Number of VDBEs currently running */ int nVdbeRead; /* Number of active VDBEs that read or write */ int nVdbeWrite; /* Number of active VDBEs that read and write */ int nVdbeExec; /* Number of nested calls to VdbeExec() */ int nVDestroy; /* Number of active OP_VDestroy operations */ int nExtension; /* Number of loaded extensions */ void **aExtension; /* Array of shared library handles */ union { void (*xLegacy)(void*,const char*); /* mTrace==SQLITE_TRACE_LEGACY */ int (*xV2)(u32,void*,void*,void*); /* All other mTrace values */ } trace; void *pTraceArg; /* Argument to the trace function */ #ifndef SQLITE_OMIT_DEPRECATED void (*xProfile)(void*,const char*,u64); /* Profiling function */ void *pProfileArg; /* Argument to profile function */ #endif void *pCommitArg; /* Argument to xCommitCallback() */ int (*xCommitCallback)(void*); /* Invoked at every commit. */ void *pRollbackArg; /* Argument to xRollbackCallback() */ void (*xRollbackCallback)(void*); /* Invoked at every commit. */ void *pUpdateArg; void (*xUpdateCallback)(void*,int, const char*,const char*,sqlite_int64); void *pAutovacPagesArg; /* Client argument to autovac_pages */ void (*xAutovacDestr)(void*); /* Destructor for pAutovacPAgesArg */ unsigned int (*xAutovacPages)(void*,const char*,u32,u32,u32); Parse *pParse; /* Current parse */ #ifdef SQLITE_ENABLE_PREUPDATE_HOOK void *pPreUpdateArg; /* First argument to xPreUpdateCallback */ void (*xPreUpdateCallback)( /* Registered using sqlite3_preupdate_hook() */ void*,sqlite3*,int,char const*,char const*,sqlite3_int64,sqlite3_int64 ); PreUpdate *pPreUpdate; /* Context for active pre-update callback */ #endif /* SQLITE_ENABLE_PREUPDATE_HOOK */ |
︙ | ︙ | |||
1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 | VTable *pDisconnect; /* Disconnect these in next sqlite3_prepare() */ #endif Hash aFunc; /* Hash table of connection functions */ Hash aCollSeq; /* All collating sequences */ BusyHandler busyHandler; /* Busy callback */ Db aDbStatic[2]; /* Static space for the 2 default backends */ Savepoint *pSavepoint; /* List of active savepoints */ int busyTimeout; /* Busy handler timeout, in msec */ int nSavepoint; /* Number of non-transaction savepoints */ int nStatement; /* Number of nested statement-transactions */ i64 nDeferredCons; /* Net deferred constraints this transaction. */ i64 nDeferredImmCons; /* Net deferred immediate constraints */ int *pnBytesFreed; /* If not NULL, increment this in DbFree() */ #ifdef SQLITE_ENABLE_UNLOCK_NOTIFY | > | > > > > > > > > > > > > > > | | | < | 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 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 | VTable *pDisconnect; /* Disconnect these in next sqlite3_prepare() */ #endif Hash aFunc; /* Hash table of connection functions */ Hash aCollSeq; /* All collating sequences */ BusyHandler busyHandler; /* Busy callback */ Db aDbStatic[2]; /* Static space for the 2 default backends */ Savepoint *pSavepoint; /* List of active savepoints */ int nAnalysisLimit; /* Number of index rows to ANALYZE */ int busyTimeout; /* Busy handler timeout, in msec */ int nSavepoint; /* Number of non-transaction savepoints */ int nStatement; /* Number of nested statement-transactions */ i64 nDeferredCons; /* Net deferred constraints this transaction. */ i64 nDeferredImmCons; /* Net deferred immediate constraints */ int *pnBytesFreed; /* If not NULL, increment this in DbFree() */ #ifdef SQLITE_ENABLE_UNLOCK_NOTIFY /* The following variables are all protected by the STATIC_MAIN ** mutex, not by sqlite3.mutex. They are used by code in notify.c. ** ** When X.pUnlockConnection==Y, that means that X is waiting for Y to ** unlock so that it can proceed. ** ** When X.pBlockingConnection==Y, that means that something that X tried ** tried to do recently failed with an SQLITE_LOCKED error due to locks ** held by Y. */ sqlite3 *pBlockingConnection; /* Connection that caused SQLITE_LOCKED */ sqlite3 *pUnlockConnection; /* Connection to watch for unlock */ void *pUnlockArg; /* Argument to xUnlockNotify */ void (*xUnlockNotify)(void **, int); /* Unlock notify callback */ sqlite3 *pNextBlocked; /* Next in list of all blocked connections */ #endif #ifdef SQLITE_USER_AUTHENTICATION sqlite3_userauth auth; /* User authentication information */ #endif }; /* ** Candidate values for sqlite3.eConcurrent */ #define CONCURRENT_NONE 0 #define CONCURRENT_OPEN 1 #define CONCURRENT_SCHEMA 2 /* ** A macro to discover the encoding of a database. */ #define SCHEMA_ENC(db) ((db)->aDb[0].pSchema->enc) #define ENC(db) ((db)->enc) /* ** A u64 constant where the lower 32 bits are all zeros. Only the ** upper 32 bits are included in the argument. Necessary because some ** C-compilers still do not accept LL integer literals. */ #define HI(X) ((u64)(X)<<32) /* ** Possible values for the sqlite3.flags. ** ** Value constraints (enforced via assert()): ** SQLITE_FullFSync == PAGER_FULLFSYNC ** SQLITE_CkptFullFSync == PAGER_CKPT_FULLFSYNC ** SQLITE_CacheSpill == PAGER_CACHE_SPILL */ #define SQLITE_WriteSchema 0x00000001 /* OK to update SQLITE_SCHEMA */ #define SQLITE_LegacyFileFmt 0x00000002 /* Create new databases in format 1 */ #define SQLITE_FullColNames 0x00000004 /* Show full column names on SELECT */ #define SQLITE_FullFSync 0x00000008 /* Use full fsync on the backend */ #define SQLITE_CkptFullFSync 0x00000010 /* Use full fsync for checkpoint */ #define SQLITE_CacheSpill 0x00000020 /* OK to spill pager cache */ #define SQLITE_ShortColNames 0x00000040 /* Show short columns names */ #define SQLITE_TrustedSchema 0x00000080 /* Allow unsafe functions and ** vtabs in the schema definition */ #define SQLITE_NullCallback 0x00000100 /* Invoke the callback once if the */ /* result set is empty */ #define SQLITE_IgnoreChecks 0x00000200 /* Do not enforce check constraints */ #define SQLITE_ReadUncommit 0x00000400 /* READ UNCOMMITTED in shared-cache */ #define SQLITE_NoCkptOnClose 0x00000800 /* No checkpoint on close()/DETACH */ #define SQLITE_ReverseOrder 0x00001000 /* Reverse unordered SELECTs */ #define SQLITE_RecTriggers 0x00002000 /* Enable recursive triggers */ |
︙ | ︙ | |||
1543 1544 1545 1546 1547 1548 1549 1550 1551 | #define SQLITE_Fts3Tokenizer 0x00400000 /* Enable fts3_tokenizer(2) */ #define SQLITE_EnableQPSG 0x00800000 /* Query Planner Stability Guarantee*/ #define SQLITE_TriggerEQP 0x01000000 /* Show trigger EXPLAIN QUERY PLAN */ #define SQLITE_ResetDatabase 0x02000000 /* Reset the database */ #define SQLITE_LegacyAlter 0x04000000 /* Legacy ALTER TABLE behaviour */ #define SQLITE_NoSchemaError 0x08000000 /* Do not report schema parse errors*/ #define SQLITE_Defensive 0x10000000 /* Input SQL is likely hostile */ /* Flags used only if debugging */ | > > > > > > > > > > < | | | | | > > | > > | | | | | | | | | | | | | | | | | > > > > | < | | < > | | | | | | | 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 | #define SQLITE_Fts3Tokenizer 0x00400000 /* Enable fts3_tokenizer(2) */ #define SQLITE_EnableQPSG 0x00800000 /* Query Planner Stability Guarantee*/ #define SQLITE_TriggerEQP 0x01000000 /* Show trigger EXPLAIN QUERY PLAN */ #define SQLITE_ResetDatabase 0x02000000 /* Reset the database */ #define SQLITE_LegacyAlter 0x04000000 /* Legacy ALTER TABLE behaviour */ #define SQLITE_NoSchemaError 0x08000000 /* Do not report schema parse errors*/ #define SQLITE_Defensive 0x10000000 /* Input SQL is likely hostile */ #define SQLITE_DqsDDL 0x20000000 /* dbl-quoted strings allowed in DDL*/ #define SQLITE_DqsDML 0x40000000 /* dbl-quoted strings allowed in DML*/ #define SQLITE_EnableView 0x80000000 /* Enable the use of views */ #define SQLITE_CountRows HI(0x00001) /* Count rows changed by INSERT, */ /* DELETE, or UPDATE and return */ /* the count using a callback. */ #define SQLITE_CorruptRdOnly HI(0x00002) /* Prohibit writes due to error */ /* Flags used by the Pragma noop_update enhancement */ #define SQLITE_NoopUpdate HI(0x0001000) /* UPDATE operations are no-ops */ /* Flags used only if debugging */ #ifdef SQLITE_DEBUG #define SQLITE_SqlTrace HI(0x0100000) /* Debug print SQL as it executes */ #define SQLITE_VdbeListing HI(0x0200000) /* Debug listings of VDBE progs */ #define SQLITE_VdbeTrace HI(0x0400000) /* True to trace VDBE execution */ #define SQLITE_VdbeAddopTrace HI(0x0800000) /* Trace sqlite3VdbeAddOp() calls */ #define SQLITE_VdbeEQP HI(0x1000000) /* Debug EXPLAIN QUERY PLAN */ #define SQLITE_ParserTrace HI(0x2000000) /* PRAGMA parser_trace=ON */ #endif /* ** Allowed values for sqlite3.mDbFlags */ #define DBFLAG_SchemaChange 0x0001 /* Uncommitted Hash table changes */ #define DBFLAG_PreferBuiltin 0x0002 /* Preference to built-in funcs */ #define DBFLAG_Vacuum 0x0004 /* Currently in a VACUUM */ #define DBFLAG_VacuumInto 0x0008 /* Currently running VACUUM INTO */ #define DBFLAG_SchemaKnownOk 0x0010 /* Schema is known to be valid */ #define DBFLAG_InternalFunc 0x0020 /* Allow use of internal functions */ #define DBFLAG_EncodingFixed 0x0040 /* No longer possible to change enc. */ /* ** Bits of the sqlite3.dbOptFlags field that are used by the ** sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS,...) interface to ** selectively disable various optimizations. */ #define SQLITE_QueryFlattener 0x00000001 /* Query flattening */ #define SQLITE_WindowFunc 0x00000002 /* Use xInverse for window functions */ #define SQLITE_GroupByOrder 0x00000004 /* GROUPBY cover of ORDERBY */ #define SQLITE_FactorOutConst 0x00000008 /* Constant factoring */ #define SQLITE_DistinctOpt 0x00000010 /* DISTINCT using indexes */ #define SQLITE_CoverIdxScan 0x00000020 /* Covering index scans */ #define SQLITE_OrderByIdxJoin 0x00000040 /* ORDER BY of joins via index */ #define SQLITE_Transitive 0x00000080 /* Transitive constraints */ #define SQLITE_OmitNoopJoin 0x00000100 /* Omit unused tables in joins */ #define SQLITE_CountOfView 0x00000200 /* The count-of-view optimization */ #define SQLITE_CursorHints 0x00000400 /* Add OP_CursorHint opcodes */ #define SQLITE_Stat4 0x00000800 /* Use STAT4 data */ /* TH3 expects this value ^^^^^^^^^^ to be 0x0000800. Don't change it */ #define SQLITE_PushDown 0x00001000 /* The push-down optimization */ #define SQLITE_SimplifyJoin 0x00002000 /* Convert LEFT JOIN to JOIN */ #define SQLITE_SkipScan 0x00004000 /* Skip-scans */ #define SQLITE_PropagateConst 0x00008000 /* The constant propagation opt */ #define SQLITE_MinMaxOpt 0x00010000 /* The min/max optimization */ #define SQLITE_SeekScan 0x00020000 /* The OP_SeekScan optimization */ #define SQLITE_OmitOrderBy 0x00040000 /* Omit pointless ORDER BY */ /* TH3 expects this value ^^^^^^^^^^ to be 0x40000. Coordinate any change */ #define SQLITE_AllOpts 0xffffffff /* All optimizations */ /* ** Macros for testing whether or not optimizations are enabled or disabled. */ #define OptimizationDisabled(db, mask) (((db)->dbOptFlags&(mask))!=0) #define OptimizationEnabled(db, mask) (((db)->dbOptFlags&(mask))==0) /* ** Return true if it OK to factor constant expressions into the initialization ** code. The argument is a Parse object for the code generator. */ #define ConstFactorOk(P) ((P)->okConstFactor) /* Possible values for the sqlite3.eOpenState field. ** The numbers are randomly selected such that a minimum of three bits must ** change to convert any number to another or to zero */ #define SQLITE_STATE_OPEN 0x76 /* Database is open */ #define SQLITE_STATE_CLOSED 0xce /* Database is closed */ #define SQLITE_STATE_SICK 0xba /* Error and awaiting close */ #define SQLITE_STATE_BUSY 0x6d /* Database currently in use */ #define SQLITE_STATE_ERROR 0xd5 /* An SQLITE_MISUSE error occurred */ #define SQLITE_STATE_ZOMBIE 0xa7 /* Close with last statement close */ /* ** Each SQL function is defined by an instance of the following ** structure. For global built-in functions (ex: substr(), max(), count()) ** a pointer to this structure is held in the sqlite3BuiltinFunctions object. ** For per-connection application-defined functions, a pointer to this ** structure is held in the db->aHash hash table. |
︙ | ︙ | |||
1633 1634 1635 1636 1637 1638 1639 | void (*xFinalize)(sqlite3_context*); /* Agg finalizer */ void (*xValue)(sqlite3_context*); /* Current agg value */ void (*xInverse)(sqlite3_context*,int,sqlite3_value**); /* inverse agg-step */ const char *zName; /* SQL name of the function. */ union { FuncDef *pHash; /* Next with a different name but the same hash */ FuncDestructor *pDestructor; /* Reference counted destructor function */ | | | 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 | void (*xFinalize)(sqlite3_context*); /* Agg finalizer */ void (*xValue)(sqlite3_context*); /* Current agg value */ void (*xInverse)(sqlite3_context*,int,sqlite3_value**); /* inverse agg-step */ const char *zName; /* SQL name of the function. */ union { FuncDef *pHash; /* Next with a different name but the same hash */ FuncDestructor *pDestructor; /* Reference counted destructor function */ } u; /* pHash if SQLITE_FUNC_BUILTIN, pDestructor otherwise */ }; /* ** This structure encapsulates a user-function destructor callback (as ** configured using create_function_v2()) and a reference counter. When ** create_function_v2() is called to create a function with a destructor, ** a single object of this type is allocated. FuncDestructor.nRef is set to |
︙ | ︙ | |||
1663 1664 1665 1666 1667 1668 1669 | /* ** Possible values for FuncDef.flags. Note that the _LENGTH and _TYPEOF ** values must correspond to OPFLAG_LENGTHARG and OPFLAG_TYPEOFARG. And ** SQLITE_FUNC_CONSTANT must be the same as SQLITE_DETERMINISTIC. There ** are assert() statements in the code to verify this. ** ** Value constraints (enforced via assert()): | | > | | | > > | | < > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 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 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 | /* ** Possible values for FuncDef.flags. Note that the _LENGTH and _TYPEOF ** values must correspond to OPFLAG_LENGTHARG and OPFLAG_TYPEOFARG. And ** SQLITE_FUNC_CONSTANT must be the same as SQLITE_DETERMINISTIC. There ** are assert() statements in the code to verify this. ** ** Value constraints (enforced via assert()): ** SQLITE_FUNC_MINMAX == NC_MinMaxAgg == SF_MinMaxAgg ** SQLITE_FUNC_ANYORDER == NC_OrderAgg == SF_OrderByReqd ** SQLITE_FUNC_LENGTH == OPFLAG_LENGTHARG ** SQLITE_FUNC_TYPEOF == OPFLAG_TYPEOFARG ** SQLITE_FUNC_CONSTANT == SQLITE_DETERMINISTIC from the API ** SQLITE_FUNC_DIRECT == SQLITE_DIRECTONLY from the API ** SQLITE_FUNC_UNSAFE == SQLITE_INNOCUOUS ** SQLITE_FUNC_ENCMASK depends on SQLITE_UTF* macros in the API */ #define SQLITE_FUNC_ENCMASK 0x0003 /* SQLITE_UTF8, SQLITE_UTF16BE or UTF16LE */ #define SQLITE_FUNC_LIKE 0x0004 /* Candidate for the LIKE optimization */ #define SQLITE_FUNC_CASE 0x0008 /* Case-sensitive LIKE-type function */ #define SQLITE_FUNC_EPHEM 0x0010 /* Ephemeral. Delete with VDBE */ #define SQLITE_FUNC_NEEDCOLL 0x0020 /* sqlite3GetFuncCollSeq() might be called*/ #define SQLITE_FUNC_LENGTH 0x0040 /* Built-in length() function */ #define SQLITE_FUNC_TYPEOF 0x0080 /* Built-in typeof() function */ #define SQLITE_FUNC_COUNT 0x0100 /* Built-in count(*) aggregate */ /* 0x0200 -- available for reuse */ #define SQLITE_FUNC_UNLIKELY 0x0400 /* Built-in unlikely() function */ #define SQLITE_FUNC_CONSTANT 0x0800 /* Constant inputs give a constant output */ #define SQLITE_FUNC_MINMAX 0x1000 /* True for min() and max() aggregates */ #define SQLITE_FUNC_SLOCHNG 0x2000 /* "Slow Change". Value constant during a ** single query - might change over time */ #define SQLITE_FUNC_TEST 0x4000 /* Built-in testing functions */ #define SQLITE_FUNC_OFFSET 0x8000 /* Built-in sqlite_offset() function */ #define SQLITE_FUNC_WINDOW 0x00010000 /* Built-in window-only function */ #define SQLITE_FUNC_INTERNAL 0x00040000 /* For use by NestedParse() only */ #define SQLITE_FUNC_DIRECT 0x00080000 /* Not for use in TRIGGERs or VIEWs */ #define SQLITE_FUNC_SUBTYPE 0x00100000 /* Result likely to have sub-type */ #define SQLITE_FUNC_UNSAFE 0x00200000 /* Function has side effects */ #define SQLITE_FUNC_INLINE 0x00400000 /* Functions implemented in-line */ #define SQLITE_FUNC_BUILTIN 0x00800000 /* This is a built-in function */ #define SQLITE_FUNC_ANYORDER 0x08000000 /* count/min/max aggregate */ /* Identifier numbers for each in-line function */ #define INLINEFUNC_coalesce 0 #define INLINEFUNC_implies_nonnull_row 1 #define INLINEFUNC_expr_implies_expr 2 #define INLINEFUNC_expr_compare 3 #define INLINEFUNC_affinity 4 #define INLINEFUNC_iif 5 #define INLINEFUNC_unlikely 99 /* Default case */ /* ** The following three macros, FUNCTION(), LIKEFUNC() and AGGREGATE() are ** used to create the initializers for the FuncDef structures. ** ** FUNCTION(zName, nArg, iArg, bNC, xFunc) ** Used to create a scalar function definition of a function zName ** implemented by C function xFunc that accepts nArg arguments. The ** value passed as iArg is cast to a (void*) and made available ** as the user-data (sqlite3_user_data()) for the function. If ** argument bNC is true, then the SQLITE_FUNC_NEEDCOLL flag is set. ** ** VFUNCTION(zName, nArg, iArg, bNC, xFunc) ** Like FUNCTION except it omits the SQLITE_FUNC_CONSTANT flag. ** ** SFUNCTION(zName, nArg, iArg, bNC, xFunc) ** Like FUNCTION except it omits the SQLITE_FUNC_CONSTANT flag and ** adds the SQLITE_DIRECTONLY flag. ** ** INLINE_FUNC(zName, nArg, iFuncId, mFlags) ** zName is the name of a function that is implemented by in-line ** byte code rather than by the usual callbacks. The iFuncId ** parameter determines the function id. The mFlags parameter is ** optional SQLITE_FUNC_ flags for this function. ** ** TEST_FUNC(zName, nArg, iFuncId, mFlags) ** zName is the name of a test-only function implemented by in-line ** byte code rather than by the usual callbacks. The iFuncId ** parameter determines the function id. The mFlags parameter is ** optional SQLITE_FUNC_ flags for this function. ** ** DFUNCTION(zName, nArg, iArg, bNC, xFunc) ** Like FUNCTION except it omits the SQLITE_FUNC_CONSTANT flag and ** adds the SQLITE_FUNC_SLOCHNG flag. Used for date & time functions ** and functions like sqlite_version() that can change, but not during ** a single query. The iArg is ignored. The user-data is always set ** to a NULL pointer. The bNC parameter is not used. ** ** MFUNCTION(zName, nArg, xPtr, xFunc) ** For math-library functions. xPtr is an arbitrary pointer. ** ** PURE_DATE(zName, nArg, iArg, bNC, xFunc) ** Used for "pure" date/time functions, this macro is like DFUNCTION ** except that it does set the SQLITE_FUNC_CONSTANT flags. iArg is ** ignored and the user-data for these functions is set to an ** arbitrary non-NULL pointer. The bNC parameter is not used. ** ** AGGREGATE(zName, nArg, iArg, bNC, xStep, xFinal) |
︙ | ︙ | |||
1737 1738 1739 1740 1741 1742 1743 | ** that accepts nArg arguments and is implemented by a call to C ** function likeFunc. Argument pArg is cast to a (void *) and made ** available as the function user-data (sqlite3_user_data()). The ** FuncDef.flags variable is set to the value passed as the flags ** parameter. */ #define FUNCTION(zName, nArg, iArg, bNC, xFunc) \ | > | | | > > > > > > | > > > > > > > > > > | > | > | | < < < < < < | > | | 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 | ** that accepts nArg arguments and is implemented by a call to C ** function likeFunc. Argument pArg is cast to a (void *) and made ** available as the function user-data (sqlite3_user_data()). The ** FuncDef.flags variable is set to the value passed as the flags ** parameter. */ #define FUNCTION(zName, nArg, iArg, bNC, xFunc) \ {nArg, SQLITE_FUNC_BUILTIN|\ SQLITE_FUNC_CONSTANT|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \ SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, 0, #zName, {0} } #define VFUNCTION(zName, nArg, iArg, bNC, xFunc) \ {nArg, SQLITE_FUNC_BUILTIN|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \ SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, 0, #zName, {0} } #define SFUNCTION(zName, nArg, iArg, bNC, xFunc) \ {nArg, SQLITE_FUNC_BUILTIN|SQLITE_UTF8|SQLITE_DIRECTONLY|SQLITE_FUNC_UNSAFE, \ SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, 0, #zName, {0} } #define MFUNCTION(zName, nArg, xPtr, xFunc) \ {nArg, SQLITE_FUNC_BUILTIN|SQLITE_FUNC_CONSTANT|SQLITE_UTF8, \ xPtr, 0, xFunc, 0, 0, 0, #zName, {0} } #define INLINE_FUNC(zName, nArg, iArg, mFlags) \ {nArg, SQLITE_FUNC_BUILTIN|\ SQLITE_UTF8|SQLITE_FUNC_INLINE|SQLITE_FUNC_CONSTANT|(mFlags), \ SQLITE_INT_TO_PTR(iArg), 0, noopFunc, 0, 0, 0, #zName, {0} } #define TEST_FUNC(zName, nArg, iArg, mFlags) \ {nArg, SQLITE_FUNC_BUILTIN|\ SQLITE_UTF8|SQLITE_FUNC_INTERNAL|SQLITE_FUNC_TEST| \ SQLITE_FUNC_INLINE|SQLITE_FUNC_CONSTANT|(mFlags), \ SQLITE_INT_TO_PTR(iArg), 0, noopFunc, 0, 0, 0, #zName, {0} } #define DFUNCTION(zName, nArg, iArg, bNC, xFunc) \ {nArg, SQLITE_FUNC_BUILTIN|SQLITE_FUNC_SLOCHNG|SQLITE_UTF8, \ 0, 0, xFunc, 0, 0, 0, #zName, {0} } #define PURE_DATE(zName, nArg, iArg, bNC, xFunc) \ {nArg, SQLITE_FUNC_BUILTIN|\ SQLITE_FUNC_SLOCHNG|SQLITE_UTF8|SQLITE_FUNC_CONSTANT, \ (void*)&sqlite3Config, 0, xFunc, 0, 0, 0, #zName, {0} } #define FUNCTION2(zName, nArg, iArg, bNC, xFunc, extraFlags) \ {nArg, SQLITE_FUNC_BUILTIN|\ SQLITE_FUNC_CONSTANT|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL)|extraFlags,\ SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, 0, #zName, {0} } #define STR_FUNCTION(zName, nArg, pArg, bNC, xFunc) \ {nArg, SQLITE_FUNC_BUILTIN|\ SQLITE_FUNC_SLOCHNG|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \ pArg, 0, xFunc, 0, 0, 0, #zName, } #define LIKEFUNC(zName, nArg, arg, flags) \ {nArg, SQLITE_FUNC_BUILTIN|SQLITE_FUNC_CONSTANT|SQLITE_UTF8|flags, \ (void *)arg, 0, likeFunc, 0, 0, 0, #zName, {0} } #define WAGGREGATE(zName, nArg, arg, nc, xStep, xFinal, xValue, xInverse, f) \ {nArg, SQLITE_FUNC_BUILTIN|SQLITE_UTF8|(nc*SQLITE_FUNC_NEEDCOLL)|f, \ SQLITE_INT_TO_PTR(arg), 0, xStep,xFinal,xValue,xInverse,#zName, {0}} #define INTERNAL_FUNCTION(zName, nArg, xFunc) \ {nArg, SQLITE_FUNC_BUILTIN|\ SQLITE_FUNC_INTERNAL|SQLITE_UTF8|SQLITE_FUNC_CONSTANT, \ 0, 0, xFunc, 0, 0, 0, #zName, {0} } /* ** All current savepoints are stored in a linked list starting at ** sqlite3.pSavepoint. The first element in the list is the most recently ** opened savepoint. Savepoints are added to the list by the vdbe |
︙ | ︙ | |||
1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 | ** Each SQLite module (virtual table definition) is defined by an ** instance of the following structure, stored in the sqlite3.aModule ** hash table. */ struct Module { const sqlite3_module *pModule; /* Callback pointers */ const char *zName; /* Name passed to create_module() */ void *pAux; /* pAux passed to create_module() */ void (*xDestroy)(void *); /* Module destructor function */ Table *pEpoTab; /* Eponymous table for this module */ }; /* | > | | > > > > > > > > > > > > > > > > > > > > > | < < | > | | > > | > > > > > > > > > > > > > > > > | > > > > > | | | | > > > > > > > | 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 | ** Each SQLite module (virtual table definition) is defined by an ** instance of the following structure, stored in the sqlite3.aModule ** hash table. */ struct Module { const sqlite3_module *pModule; /* Callback pointers */ const char *zName; /* Name passed to create_module() */ int nRefModule; /* Number of pointers to this object */ void *pAux; /* pAux passed to create_module() */ void (*xDestroy)(void *); /* Module destructor function */ Table *pEpoTab; /* Eponymous table for this module */ }; /* ** Information about each column of an SQL table is held in an instance ** of the Column structure, in the Table.aCol[] array. ** ** Definitions: ** ** "table column index" This is the index of the column in the ** Table.aCol[] array, and also the index of ** the column in the original CREATE TABLE stmt. ** ** "storage column index" This is the index of the column in the ** record BLOB generated by the OP_MakeRecord ** opcode. The storage column index is less than ** or equal to the table column index. It is ** equal if and only if there are no VIRTUAL ** columns to the left. ** ** Notes on zCnName: ** The zCnName field stores the name of the column, the datatype of the ** column, and the collating sequence for the column, in that order, all in ** a single allocation. Each string is 0x00 terminated. The datatype ** is only included if the COLFLAG_HASTYPE bit of colFlags is set and the ** collating sequence name is only included if the COLFLAG_HASCOLL bit is ** set. */ struct Column { char *zCnName; /* Name of this column */ unsigned notNull :4; /* An OE_ code for handling a NOT NULL constraint */ unsigned eCType :4; /* One of the standard types */ char affinity; /* One of the SQLITE_AFF_... values */ u8 szEst; /* Est size of value in this column. sizeof(INT)==1 */ u8 hName; /* Column name hash for faster lookup */ u16 iDflt; /* 1-based index of DEFAULT. 0 means "none" */ u16 colFlags; /* Boolean properties. See COLFLAG_ defines below */ }; /* Allowed values for Column.eCType. ** ** Values must match entries in the global constant arrays ** sqlite3StdTypeLen[] and sqlite3StdType[]. Each value is one more ** than the offset into these arrays for the corresponding name. ** Adjust the SQLITE_N_STDTYPE value if adding or removing entries. */ #define COLTYPE_CUSTOM 0 /* Type appended to zName */ #define COLTYPE_ANY 1 #define COLTYPE_BLOB 2 #define COLTYPE_INT 3 #define COLTYPE_INTEGER 4 #define COLTYPE_REAL 5 #define COLTYPE_TEXT 6 #define SQLITE_N_STDTYPE 6 /* Number of standard types */ /* Allowed values for Column.colFlags. ** ** Constraints: ** TF_HasVirtual == COLFLAG_VIRTUAL ** TF_HasStored == COLFLAG_STORED ** TF_HasHidden == COLFLAG_HIDDEN */ #define COLFLAG_PRIMKEY 0x0001 /* Column is part of the primary key */ #define COLFLAG_HIDDEN 0x0002 /* A hidden column in a virtual table */ #define COLFLAG_HASTYPE 0x0004 /* Type name follows column name */ #define COLFLAG_UNIQUE 0x0008 /* Column def contains "UNIQUE" or "PK" */ #define COLFLAG_SORTERREF 0x0010 /* Use sorter-refs with this column */ #define COLFLAG_VIRTUAL 0x0020 /* GENERATED ALWAYS AS ... VIRTUAL */ #define COLFLAG_STORED 0x0040 /* GENERATED ALWAYS AS ... STORED */ #define COLFLAG_NOTAVAIL 0x0080 /* STORED column not yet calculated */ #define COLFLAG_BUSY 0x0100 /* Blocks recursion on GENERATED columns */ #define COLFLAG_HASCOLL 0x0200 /* Has collating sequence name in zCnName */ #define COLFLAG_GENERATED 0x0060 /* Combo: _STORED, _VIRTUAL */ #define COLFLAG_NOINSERT 0x0062 /* Combo: _HIDDEN, _STORED, _VIRTUAL */ /* ** A "Collating Sequence" is defined by an instance of the following ** structure. Conceptually, a collating sequence consists of a name and ** a comparison routine that defines the order of that sequence. ** ** If CollSeq.xCmp is NULL, it means that the |
︙ | ︙ | |||
1866 1867 1868 1869 1870 1871 1872 | ** But rather than start with 0 or 1, we begin with 'A'. That way, ** when multiple affinity types are concatenated into a string and ** used as the P4 operand, they will be more readable. ** ** Note also that the numeric types are grouped together so that testing ** for a numeric type is a single comparison. And the BLOB type is first. */ | > | | | | | < < | 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 | ** But rather than start with 0 or 1, we begin with 'A'. That way, ** when multiple affinity types are concatenated into a string and ** used as the P4 operand, they will be more readable. ** ** Note also that the numeric types are grouped together so that testing ** for a numeric type is a single comparison. And the BLOB type is first. */ #define SQLITE_AFF_NONE 0x40 /* '@' */ #define SQLITE_AFF_BLOB 0x41 /* 'A' */ #define SQLITE_AFF_TEXT 0x42 /* 'B' */ #define SQLITE_AFF_NUMERIC 0x43 /* 'C' */ #define SQLITE_AFF_INTEGER 0x44 /* 'D' */ #define SQLITE_AFF_REAL 0x45 /* 'E' */ #define sqlite3IsNumericAffinity(X) ((X)>=SQLITE_AFF_NUMERIC) /* ** The SQLITE_AFF_MASK values masks off the significant bits of an ** affinity value. */ #define SQLITE_AFF_MASK 0x47 /* ** Additional bit values that can be ORed with an affinity without ** changing the affinity. ** ** The SQLITE_NOTNULL flag is a combination of NULLEQ and JUMPIFNULL. ** It causes an assert() to fire if either operand to a comparison ** operator is NULL. It is added to certain comparison operators to ** prove that the operands are always NOT NULL. */ #define SQLITE_JUMPIFNULL 0x10 /* jumps if either operand is NULL */ #define SQLITE_NULLEQ 0x80 /* NULL=NULL */ #define SQLITE_NOTNULL 0x90 /* Assert that operands are never NULL */ /* ** An object of this type is created for each virtual table present in ** the database schema. ** |
︙ | ︙ | |||
1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 | */ struct VTable { sqlite3 *db; /* Database connection associated with this table */ Module *pMod; /* Pointer to module implementation */ sqlite3_vtab *pVtab; /* Pointer to vtab instance */ int nRef; /* Number of pointers to this structure */ u8 bConstraint; /* True if constraints are supported */ int iSavepoint; /* Depth of the SAVEPOINT stack */ VTable *pNext; /* Next in linked list (see above) */ }; /* | > > > > > > > | | < < | > | > > | > > > > > > | < > | | | < > > | < | > > > > > > | | | | | > > > | < < | > > | | > > > > > > > > > > > > > > | > > > | 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 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 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 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 | */ struct VTable { sqlite3 *db; /* Database connection associated with this table */ Module *pMod; /* Pointer to module implementation */ sqlite3_vtab *pVtab; /* Pointer to vtab instance */ int nRef; /* Number of pointers to this structure */ u8 bConstraint; /* True if constraints are supported */ u8 eVtabRisk; /* Riskiness of allowing hacker access */ int iSavepoint; /* Depth of the SAVEPOINT stack */ VTable *pNext; /* Next in linked list (see above) */ }; /* Allowed values for VTable.eVtabRisk */ #define SQLITE_VTABRISK_Low 0 #define SQLITE_VTABRISK_Normal 1 #define SQLITE_VTABRISK_High 2 /* ** The schema for each SQL table, virtual table, and view is represented ** in memory by an instance of the following structure. */ struct Table { char *zName; /* Name of the table or view */ Column *aCol; /* Information about each column */ Index *pIndex; /* List of SQL indexes on this table. */ char *zColAff; /* String defining the affinity of each column */ ExprList *pCheck; /* All CHECK constraints */ /* ... also used as column name list in a VIEW */ Pgno tnum; /* Root BTree page for this table */ u32 nTabRef; /* Number of pointers to this Table */ u32 tabFlags; /* Mask of TF_* values */ i16 iPKey; /* If not negative, use aCol[iPKey] as the rowid */ i16 nCol; /* Number of columns in this table */ i16 nNVCol; /* Number of columns that are not VIRTUAL */ LogEst nRowLogEst; /* Estimated rows in table - from sqlite_stat1 table */ LogEst szTabRow; /* Estimated size of each table row in bytes */ #ifdef SQLITE_ENABLE_COSTMULT LogEst costMult; /* Cost multiplier for using this table */ #endif u8 keyConf; /* What to do in case of uniqueness conflict on iPKey */ u8 eTabType; /* 0: normal, 1: virtual, 2: view */ union { struct { /* Used by ordinary tables: */ int addColOffset; /* Offset in CREATE TABLE stmt to add a new column */ FKey *pFKey; /* Linked list of all foreign keys in this table */ ExprList *pDfltList; /* DEFAULT clauses on various columns. ** Or the AS clause for generated columns. */ } tab; struct { /* Used by views: */ Select *pSelect; /* View definition */ } view; struct { /* Used by virtual tables only: */ int nArg; /* Number of arguments to the module */ char **azArg; /* 0: module 1: schema 2: vtab name 3...: args */ VTable *p; /* List of VTable objects. */ } vtab; } u; Trigger *pTrigger; /* List of triggers on this object */ Schema *pSchema; /* Schema that contains this table */ }; /* ** Allowed values for Table.tabFlags. ** ** TF_OOOHidden applies to tables or view that have hidden columns that are ** followed by non-hidden columns. Example: "CREATE VIRTUAL TABLE x USING ** vtab1(a HIDDEN, b);". Since "b" is a non-hidden column but "a" is hidden, ** the TF_OOOHidden attribute would apply in this case. Such tables require ** special handling during INSERT processing. The "OOO" means "Out Of Order". ** ** Constraints: ** ** TF_HasVirtual == COLFLAG_VIRTUAL ** TF_HasStored == COLFLAG_STORED ** TF_HasHidden == COLFLAG_HIDDEN */ #define TF_Readonly 0x00000001 /* Read-only system table */ #define TF_HasHidden 0x00000002 /* Has one or more hidden columns */ #define TF_HasPrimaryKey 0x00000004 /* Table has a primary key */ #define TF_Autoincrement 0x00000008 /* Integer primary key is autoincrement */ #define TF_HasStat1 0x00000010 /* nRowLogEst set from sqlite_stat1 */ #define TF_HasVirtual 0x00000020 /* Has one or more VIRTUAL columns */ #define TF_HasStored 0x00000040 /* Has one or more STORED columns */ #define TF_HasGenerated 0x00000060 /* Combo: HasVirtual + HasStored */ #define TF_WithoutRowid 0x00000080 /* No rowid. PRIMARY KEY is the key */ #define TF_StatsUsed 0x00000100 /* Query planner decisions affected by ** Index.aiRowLogEst[] values */ #define TF_NoVisibleRowid 0x00000200 /* No user-visible "rowid" column */ #define TF_OOOHidden 0x00000400 /* Out-of-Order hidden columns */ #define TF_HasNotNull 0x00000800 /* Contains NOT NULL constraints */ #define TF_Shadow 0x00001000 /* True for a shadow table */ #define TF_HasStat4 0x00002000 /* STAT4 info available for this table */ #define TF_Ephemeral 0x00004000 /* An ephemeral table */ #define TF_Eponymous 0x00008000 /* An eponymous virtual table */ #define TF_Strict 0x00010000 /* STRICT mode */ /* ** Allowed values for Table.eTabType */ #define TABTYP_NORM 0 /* Ordinary table */ #define TABTYP_VTAB 1 /* Virtual table */ #define TABTYP_VIEW 2 /* A view */ #define IsView(X) ((X)->eTabType==TABTYP_VIEW) #define IsOrdinaryTable(X) ((X)->eTabType==TABTYP_NORM) /* ** Test to see whether or not a table is a virtual table. This is ** done as a macro so that it will be optimized out when virtual ** table support is omitted from the build. */ #ifndef SQLITE_OMIT_VIRTUALTABLE # define IsVirtual(X) ((X)->eTabType==TABTYP_VTAB) # define ExprIsVtab(X) \ ((X)->op==TK_COLUMN && (X)->y.pTab!=0 && (X)->y.pTab->eTabType==TABTYP_VTAB) #else # define IsVirtual(X) 0 # define ExprIsVtab(X) 0 #endif /* ** Macros to determine if a column is hidden. IsOrdinaryHiddenColumn() ** only works for non-virtual tables (ordinary tables and views) and is ** always false unless SQLITE_ENABLE_HIDDEN_COLUMNS is defined. The ** IsHiddenColumn() macro is general purpose. |
︙ | ︙ | |||
2098 2099 2100 2101 2102 2103 2104 2105 | ** the operation in progress stops and returns an error code. But prior ** changes due to the same operation are not backed out and no rollback ** occurs. IGNORE means that the particular row that caused the constraint ** error is not inserted or updated. Processing continues and no error ** is returned. REPLACE means that preexisting database rows that caused ** a UNIQUE constraint violation are removed so that the new insert or ** update can proceed. Processing continues and no error is reported. ** | > > | > | > > > | | 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 2458 2459 2460 | ** the operation in progress stops and returns an error code. But prior ** changes due to the same operation are not backed out and no rollback ** occurs. IGNORE means that the particular row that caused the constraint ** error is not inserted or updated. Processing continues and no error ** is returned. REPLACE means that preexisting database rows that caused ** a UNIQUE constraint violation are removed so that the new insert or ** update can proceed. Processing continues and no error is reported. ** UPDATE applies to insert operations only and means that the insert ** is omitted and the DO UPDATE clause of an upsert is run instead. ** ** RESTRICT, SETNULL, SETDFLT, and CASCADE actions apply only to foreign keys. ** RESTRICT is the same as ABORT for IMMEDIATE foreign keys and the ** same as ROLLBACK for DEFERRED keys. SETNULL means that the foreign ** key is set to NULL. SETDFLT means that the foreign key is set ** to its default value. CASCADE means that a DELETE or UPDATE of the ** referenced table row is propagated into the row that holds the ** foreign key. ** ** The OE_Default value is a place holder that means to use whatever ** conflict resolution algorthm is required from context. ** ** The following symbolic values are used to record which type ** of conflict resolution action to take. */ #define OE_None 0 /* There is no constraint to check */ #define OE_Rollback 1 /* Fail the operation and rollback the transaction */ #define OE_Abort 2 /* Back out changes but do no rollback transaction */ #define OE_Fail 3 /* Stop the operation but leave all prior changes */ #define OE_Ignore 4 /* Ignore the error. Do not do the INSERT or UPDATE */ #define OE_Replace 5 /* Delete existing record, then do INSERT or UPDATE */ |
︙ | ︙ | |||
2138 2139 2140 2141 2142 2143 2144 | */ struct KeyInfo { u32 nRef; /* Number of references to this KeyInfo object */ u8 enc; /* Text encoding - one of the SQLITE_UTF* values */ u16 nKeyField; /* Number of key columns in the index */ u16 nAllField; /* Total columns, including key plus others */ sqlite3 *db; /* The database connection */ | | > > > > > > | 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 | */ struct KeyInfo { u32 nRef; /* Number of references to this KeyInfo object */ u8 enc; /* Text encoding - one of the SQLITE_UTF* values */ u16 nKeyField; /* Number of key columns in the index */ u16 nAllField; /* Total columns, including key plus others */ sqlite3 *db; /* The database connection */ u8 *aSortFlags; /* Sort order for each column. */ CollSeq *aColl[1]; /* Collating sequence for each term of the key */ }; /* ** Allowed bit values for entries in the KeyInfo.aSortFlags[] array. */ #define KEYINFO_ORDER_DESC 0x01 /* DESC sort order */ #define KEYINFO_ORDER_BIGNULL 0x02 /* NULL is larger than any other value */ /* ** This object holds a record which has been parsed out into individual ** fields, for the purposes of doing a comparison. ** ** A record is an object that contains one or more fields of data. ** Records are used to store the content of a table row and to store ** the key of an index. A blob encoding of a record is created by |
︙ | ︙ | |||
2216 2217 2218 2219 2220 2221 2222 | ** must be unique and what to do if they are not. When Index.onError=OE_None, ** it means this is not a unique index. Otherwise it is a unique index ** and the value of Index.onError indicate the which conflict resolution ** algorithm to employ whenever an attempt is made to insert a non-unique ** element. ** ** While parsing a CREATE TABLE or CREATE INDEX statement in order to | | | | > > | > | | 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 | ** must be unique and what to do if they are not. When Index.onError=OE_None, ** it means this is not a unique index. Otherwise it is a unique index ** and the value of Index.onError indicate the which conflict resolution ** algorithm to employ whenever an attempt is made to insert a non-unique ** element. ** ** While parsing a CREATE TABLE or CREATE INDEX statement in order to ** generate VDBE code (as opposed to parsing one read from an sqlite_schema ** table as part of parsing an existing database schema), transient instances ** of this structure may be created. In this case the Index.tnum variable is ** used to store the address of a VDBE instruction, not a database page ** number (it cannot - the database page is not allocated until the VDBE ** program is executed). See convertToWithoutRowidTable() for details. */ struct Index { char *zName; /* Name of this index */ i16 *aiColumn; /* Which columns are used by this index. 1st is 0 */ LogEst *aiRowLogEst; /* From ANALYZE: Est. rows selected by each column */ Table *pTable; /* The SQL table being indexed */ char *zColAff; /* String defining the affinity of each column */ Index *pNext; /* The next index associated with the same table */ Schema *pSchema; /* Schema containing this index */ u8 *aSortOrder; /* for each column: True==DESC, False==ASC */ const char **azColl; /* Array of collation sequence names for index */ Expr *pPartIdxWhere; /* WHERE clause for partial indices */ ExprList *aColExpr; /* Column expressions */ Pgno tnum; /* DB Page containing root of this index */ LogEst szIdxRow; /* Estimated average row size in bytes */ u16 nKeyCol; /* Number of columns forming the key */ u16 nColumn; /* Number of columns stored in the index */ u8 onError; /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */ unsigned idxType:2; /* 0:Normal 1:UNIQUE, 2:PRIMARY KEY, 3:IPK */ unsigned bUnordered:1; /* Use this index for == or IN queries only */ unsigned uniqNotNull:1; /* True if UNIQUE and NOT NULL for all columns */ unsigned isResized:1; /* True if resizeIndexObject() has been called */ unsigned isCovering:1; /* True if this is a covering index */ unsigned noSkipScan:1; /* Do not try to use skip-scan if true */ unsigned hasStat1:1; /* aiRowLogEst values come from sqlite_stat1 */ unsigned bNoQuery:1; /* Do not use this index to optimize queries */ unsigned bAscKeyBug:1; /* True if the bba7b69f9849b5bf bug applies */ unsigned bHasVCol:1; /* Index references one or more VIRTUAL columns */ #ifdef SQLITE_ENABLE_STAT4 int nSample; /* Number of elements in aSample[] */ int nSampleCol; /* Size of IndexSample.anEq[] and so on */ tRowcnt *aAvgEq; /* Average nEq values for keys not in aSample */ IndexSample *aSample; /* Samples of the left-most key */ tRowcnt *aiRowEst; /* Non-logarithmic stat1 data for this index */ tRowcnt nRowEst0; /* Non-logarithmic number of rows in the index */ #endif Bitmask colNotIdxed; /* 0 for unindexed columns in pTab */ }; /* ** Allowed values for Index.idxType */ #define SQLITE_IDXTYPE_APPDEF 0 /* Created using CREATE INDEX */ #define SQLITE_IDXTYPE_UNIQUE 1 /* Implements a UNIQUE constraint */ #define SQLITE_IDXTYPE_PRIMARYKEY 2 /* Is the PRIMARY KEY for the table */ #define SQLITE_IDXTYPE_IPK 3 /* INTEGER PRIMARY KEY index */ /* Return true if index X is a PRIMARY KEY index */ #define IsPrimaryKeyIndex(X) ((X)->idxType==SQLITE_IDXTYPE_PRIMARYKEY) /* Return true if index X is a UNIQUE index */ #define IsUniqueIndex(X) ((X)->onError!=OE_None) /* The Index.aiColumn[] values are normally positive integer. But ** there are some negative values that have special meaning: */ #define XN_ROWID (-1) /* Indexed column is the rowid */ #define XN_EXPR (-2) /* Indexed column is an expression */ /* ** Each sample stored in the sqlite_stat4 table is represented in memory ** using a structure of this type. See documentation at the top of the ** analyze.c source file for additional information. */ struct IndexSample { void *p; /* Pointer to sampled record */ int n; /* Size of record in bytes */ tRowcnt *anEq; /* Est. number of rows where the key equals this sample */ |
︙ | ︙ | |||
2317 2318 2319 2320 2321 2322 2323 | }; /* ** An instance of this structure contains information needed to generate ** code for a SELECT that contains aggregate functions. ** ** If Expr.op==TK_AGG_COLUMN or TK_AGG_FUNCTION then Expr.pAggInfo is a | | > > | | < < | > > | | | | | | 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 | }; /* ** An instance of this structure contains information needed to generate ** code for a SELECT that contains aggregate functions. ** ** If Expr.op==TK_AGG_COLUMN or TK_AGG_FUNCTION then Expr.pAggInfo is a ** pointer to this structure. The Expr.iAgg field is the index in ** AggInfo.aCol[] or AggInfo.aFunc[] of information needed to generate ** code for that node. ** ** AggInfo.pGroupBy and AggInfo.aFunc.pExpr point to fields within the ** original Select structure that describes the SELECT statement. These ** fields do not need to be freed when deallocating the AggInfo structure. */ struct AggInfo { u8 directMode; /* Direct rendering mode means take data directly ** from source tables rather than from accumulators */ u8 useSortingIdx; /* In direct mode, reference the sorting index rather ** than the source table */ int sortingIdx; /* Cursor number of the sorting index */ int sortingIdxPTab; /* Cursor number of pseudo-table */ int nSortingColumn; /* Number of columns in the sorting index */ int mnReg, mxReg; /* Range of registers allocated for aCol and aFunc */ ExprList *pGroupBy; /* The group by clause */ struct AggInfo_col { /* For each column used in source tables */ Table *pTab; /* Source table */ Expr *pCExpr; /* The original expression */ int iTable; /* Cursor number of the source table */ int iMem; /* Memory location that acts as accumulator */ i16 iColumn; /* Column number within the source table */ i16 iSorterColumn; /* Column number in the sorting index */ } *aCol; int nColumn; /* Number of used entries in aCol[] */ int nAccumulator; /* Number of columns that show through to the output. ** Additional columns are used only as parameters to ** aggregate functions */ struct AggInfo_func { /* For each aggregate function */ Expr *pFExpr; /* Expression encoding the function */ FuncDef *pFunc; /* The aggregate function implementation */ int iMem; /* Memory location that acts as accumulator */ int iDistinct; /* Ephemeral table used to enforce DISTINCT */ int iDistAddr; /* Address of OP_OpenEphemeral */ } *aFunc; int nFunc; /* Number of entries in aFunc[] */ u32 selId; /* Select to which this AggInfo belongs */ }; /* ** The datatype ynVar is a signed integer, either 16-bit or 32-bit. ** Usually it is 16-bits. But if SQLITE_MAX_VARIABLE_NUMBER is greater ** than 32767 we have to make it 32-bit. 16-bit is preferred because ** it uses less memory in the Expr object, which is a big memory user ** in systems with lots of prepared statements. And few applications ** need more than about 10 or 20 variables. But some extreme users want ** to have prepared statements with over 32766 variables, and for them ** the option is available (at compile-time). */ #if SQLITE_MAX_VARIABLE_NUMBER<32767 typedef i16 ynVar; #else typedef int ynVar; #endif /* ** Each node of an expression in the parse tree is an instance ** of this structure. ** ** Expr.op is the opcode. The integer parser token codes are reused ** as opcodes here. For example, the parser defines TK_GE to be an integer ** code representing the ">=" operator. This same integer code is reused ** to represent the greater-than-or-equal-to operator in the expression ** tree. ** ** If the expression is an SQL literal (TK_INTEGER, TK_FLOAT, TK_BLOB, ** or TK_STRING), then Expr.u.zToken contains the text of the SQL literal. If ** the expression is a variable (TK_VARIABLE), then Expr.u.zToken contains the ** variable name. Finally, if the expression is an SQL function (TK_FUNCTION), ** then Expr.u.zToken contains the name of the function. ** ** Expr.pRight and Expr.pLeft are the left and right subexpressions of a ** binary operator. Either or both may be NULL. ** ** Expr.x.pList is a list of arguments if the expression is an SQL function, ** a CASE expression or an IN expression of the form "<lhs> IN (<y>, <z>...)". ** Expr.x.pSelect is used if the expression is a sub-select or an expression of |
︙ | ︙ | |||
2426 2427 2428 2429 2430 2431 2432 | ** ** ALLOCATION NOTES: ** ** Expr objects can use a lot of memory space in database schema. To ** help reduce memory requirements, sometimes an Expr object will be ** truncated. And to reduce the number of memory allocations, sometimes ** two or more Expr objects will be stored in a single memory allocation, | | > > > > > > | > | 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 | ** ** ALLOCATION NOTES: ** ** Expr objects can use a lot of memory space in database schema. To ** help reduce memory requirements, sometimes an Expr object will be ** truncated. And to reduce the number of memory allocations, sometimes ** two or more Expr objects will be stored in a single memory allocation, ** together with Expr.u.zToken strings. ** ** If the EP_Reduced and EP_TokenOnly flags are set when ** an Expr object is truncated. When EP_Reduced is set, then all ** the child Expr objects in the Expr.pLeft and Expr.pRight subtrees ** are contained within the same memory allocation. Note, however, that ** the subtrees in Expr.x.pList or Expr.x.pSelect are always separately ** allocated, regardless of whether or not EP_Reduced is set. */ struct Expr { u8 op; /* Operation performed by this node */ char affExpr; /* affinity, or RAISE type */ u8 op2; /* TK_REGISTER/TK_TRUTH: original value of Expr.op ** TK_COLUMN: the value of p5 for OP_Column ** TK_AGG_FUNCTION: nesting depth ** TK_FUNCTION: NC_SelfRef flag if needs OP_PureFunc */ #ifdef SQLITE_DEBUG u8 vvaFlags; /* Verification flags. */ #endif u32 flags; /* Various flags. EP_* See below */ union { char *zToken; /* Token value. Zero terminated and dequoted */ int iValue; /* Non-negative integer value if EP_IntValue */ } u; /* If the EP_TokenOnly flag is set in the Expr.flags mask, then no |
︙ | ︙ | |||
2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 | #if SQLITE_MAX_EXPR_DEPTH>0 int nHeight; /* Height of the tree headed by this node */ #endif int iTable; /* TK_COLUMN: cursor number of table holding column ** TK_REGISTER: register number ** TK_TRIGGER: 1 -> new, 0 -> old ** EP_Unlikely: 134217728 times likelihood ** TK_SELECT: 1st register of result vector */ ynVar iColumn; /* TK_COLUMN: column index. -1 for rowid. ** TK_VARIABLE: variable number (always >= 1). ** TK_SELECT_COLUMN: column of the result vector */ i16 iAgg; /* Which entry in pAggInfo->aCol[] or ->aFunc[] */ | > > | < < < | > > > > < | > > > > | | | | | | | | | | | | | | | | | | | | | | | | | > > > > > > > < | < | > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > | | | | | | | > > > > > > > | | | < > | | > > > > > > > > | 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 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 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 | #if SQLITE_MAX_EXPR_DEPTH>0 int nHeight; /* Height of the tree headed by this node */ #endif int iTable; /* TK_COLUMN: cursor number of table holding column ** TK_REGISTER: register number ** TK_TRIGGER: 1 -> new, 0 -> old ** EP_Unlikely: 134217728 times likelihood ** TK_IN: ephemerial table holding RHS ** TK_SELECT_COLUMN: Number of columns on the LHS ** TK_SELECT: 1st register of result vector */ ynVar iColumn; /* TK_COLUMN: column index. -1 for rowid. ** TK_VARIABLE: variable number (always >= 1). ** TK_SELECT_COLUMN: column of the result vector */ i16 iAgg; /* Which entry in pAggInfo->aCol[] or ->aFunc[] */ int iRightJoinTable; /* If EP_FromJoin, the right table of the join */ AggInfo *pAggInfo; /* Used by TK_AGG_COLUMN and TK_AGG_FUNCTION */ union { Table *pTab; /* TK_COLUMN: Table containing column. Can be NULL ** for a column of an index on an expression */ Window *pWin; /* EP_WinFunc: Window/Filter defn for a function */ struct { /* TK_IN, TK_SELECT, and TK_EXISTS */ int iAddr; /* Subroutine entry address */ int regReturn; /* Register used to hold return address */ } sub; } y; }; /* The following are the meanings of bits in the Expr.flags field. ** Value restrictions: ** ** EP_Agg == NC_HasAgg == SF_HasAgg ** EP_Win == NC_HasWin */ #define EP_FromJoin 0x000001 /* Originates in ON/USING clause of outer join */ #define EP_Distinct 0x000002 /* Aggregate function with DISTINCT keyword */ #define EP_HasFunc 0x000004 /* Contains one or more functions of any kind */ #define EP_FixedCol 0x000008 /* TK_Column with a known fixed value */ #define EP_Agg 0x000010 /* Contains one or more aggregate functions */ #define EP_VarSelect 0x000020 /* pSelect is correlated, not constant */ #define EP_DblQuoted 0x000040 /* token.z was originally in "..." */ #define EP_InfixFunc 0x000080 /* True for an infix function: LIKE, GLOB, etc */ #define EP_Collate 0x000100 /* Tree contains a TK_COLLATE operator */ #define EP_Commuted 0x000200 /* Comparison operator has been commuted */ #define EP_IntValue 0x000400 /* Integer value contained in u.iValue */ #define EP_xIsSelect 0x000800 /* x.pSelect is valid (otherwise x.pList is) */ #define EP_Skip 0x001000 /* Operator does not contribute to affinity */ #define EP_Reduced 0x002000 /* Expr struct EXPR_REDUCEDSIZE bytes only */ #define EP_TokenOnly 0x004000 /* Expr struct EXPR_TOKENONLYSIZE bytes only */ #define EP_Win 0x008000 /* Contains window functions */ #define EP_MemToken 0x010000 /* Need to sqlite3DbFree() Expr.zToken */ #define EP_IfNullRow 0x020000 /* The TK_IF_NULL_ROW opcode */ #define EP_Unlikely 0x040000 /* unlikely() or likelihood() function */ #define EP_ConstFunc 0x080000 /* A SQLITE_FUNC_CONSTANT or _SLOCHNG function */ #define EP_CanBeNull 0x100000 /* Can be null despite NOT NULL constraint */ #define EP_Subquery 0x200000 /* Tree contains a TK_SELECT operator */ /* 0x400000 // Available */ #define EP_Leaf 0x800000 /* Expr.pLeft, .pRight, .u.pSelect all NULL */ #define EP_WinFunc 0x1000000 /* TK_FUNCTION with Expr.y.pWin set */ #define EP_Subrtn 0x2000000 /* Uses Expr.y.sub. TK_IN, _SELECT, or _EXISTS */ #define EP_Quoted 0x4000000 /* TK_ID was originally quoted */ #define EP_Static 0x8000000 /* Held in memory not obtained from malloc() */ #define EP_IsTrue 0x10000000 /* Always has boolean value of TRUE */ #define EP_IsFalse 0x20000000 /* Always has boolean value of FALSE */ #define EP_FromDDL 0x40000000 /* Originates from sqlite_schema */ /* 0x80000000 // Available */ /* The EP_Propagate mask is a set of properties that automatically propagate ** upwards into parent nodes. */ #define EP_Propagate (EP_Collate|EP_Subquery|EP_HasFunc) /* Macros can be used to test, set, or clear bits in the ** Expr.flags field. */ #define ExprHasProperty(E,P) (((E)->flags&(P))!=0) #define ExprHasAllProperty(E,P) (((E)->flags&(P))==(P)) #define ExprSetProperty(E,P) (E)->flags|=(P) #define ExprClearProperty(E,P) (E)->flags&=~(P) #define ExprAlwaysTrue(E) (((E)->flags&(EP_FromJoin|EP_IsTrue))==EP_IsTrue) #define ExprAlwaysFalse(E) (((E)->flags&(EP_FromJoin|EP_IsFalse))==EP_IsFalse) /* Macros used to ensure that the correct members of unions are accessed ** in Expr. */ #define ExprUseUToken(E) (((E)->flags&EP_IntValue)==0) #define ExprUseUValue(E) (((E)->flags&EP_IntValue)!=0) #define ExprUseXList(E) (((E)->flags&EP_xIsSelect)==0) #define ExprUseXSelect(E) (((E)->flags&EP_xIsSelect)!=0) #define ExprUseYTab(E) (((E)->flags&(EP_WinFunc|EP_Subrtn))==0) #define ExprUseYWin(E) (((E)->flags&EP_WinFunc)!=0) #define ExprUseYSub(E) (((E)->flags&EP_Subrtn)!=0) /* Flags for use with Expr.vvaFlags */ #define EP_NoReduce 0x01 /* Cannot EXPRDUP_REDUCE this Expr */ #define EP_Immutable 0x02 /* Do not change this Expr node */ /* The ExprSetVVAProperty() macro is used for Verification, Validation, ** and Accreditation only. It works like ExprSetProperty() during VVA ** processes but is a no-op for delivery. */ #ifdef SQLITE_DEBUG # define ExprSetVVAProperty(E,P) (E)->vvaFlags|=(P) # define ExprHasVVAProperty(E,P) (((E)->vvaFlags&(P))!=0) # define ExprClearVVAProperties(E) (E)->vvaFlags = 0 #else # define ExprSetVVAProperty(E,P) # define ExprHasVVAProperty(E,P) 0 # define ExprClearVVAProperties(E) #endif /* ** Macros to determine the number of bytes required by a normal Expr ** struct, an Expr struct with the EP_Reduced flag set in Expr.flags ** and an Expr struct with the EP_TokenOnly flag set. */ #define EXPR_FULLSIZE sizeof(Expr) /* Full size */ #define EXPR_REDUCEDSIZE offsetof(Expr,iTable) /* Common features */ #define EXPR_TOKENONLYSIZE offsetof(Expr,pLeft) /* Fewer features */ /* ** Flags passed to the sqlite3ExprDup() function. See the header comment ** above sqlite3ExprDup() for details. */ #define EXPRDUP_REDUCE 0x0001 /* Used reduced-size Expr nodes */ /* ** True if the expression passed as an argument was a function with ** an OVER() clause (a window function). */ #ifdef SQLITE_OMIT_WINDOWFUNC # define IsWindowFunc(p) 0 #else # define IsWindowFunc(p) ( \ ExprHasProperty((p), EP_WinFunc) && p->y.pWin->eFrmType!=TK_FILTER \ ) #endif /* ** A list of expressions. Each expression may optionally have a ** name. An expr/name combination can be used in several ways, such ** as the list of "expr AS ID" fields following a "SELECT" or in the ** list of "ID = expr" items in an UPDATE. A list of expressions can ** also be used as the argument to a function, in which case the a.zName ** field is not used. ** ** In order to try to keep memory usage down, the Expr.a.zEName field ** is used for multiple purposes: ** ** eEName Usage ** ---------- ------------------------- ** ENAME_NAME (1) the AS of result set column ** (2) COLUMN= of an UPDATE ** ** ENAME_TAB DB.TABLE.NAME used to resolve names ** of subqueries ** ** ENAME_SPAN Text of the original result set ** expression. */ struct ExprList { int nExpr; /* Number of expressions on the list */ int nAlloc; /* Number of a[] slots allocated */ struct ExprList_item { /* For each expression in the list */ Expr *pExpr; /* The parse tree for this expression */ char *zEName; /* Token associated with this expression */ u8 sortFlags; /* Mask of KEYINFO_ORDER_* flags */ unsigned eEName :2; /* Meaning of zEName */ unsigned done :1; /* A flag to indicate when processing is finished */ unsigned reusable :1; /* Constant expression is reusable */ unsigned bSorterRef :1; /* Defer evaluation until after sorting */ unsigned bNulls: 1; /* True if explicit "NULLS FIRST/LAST" */ union { struct { /* Used by any ExprList other than Parse.pConsExpr */ u16 iOrderByCol; /* For ORDER BY, column number in result set */ u16 iAlias; /* Index into Parse.aAlias[] for zName */ } x; int iConstExprReg; /* Register in which Expr value is cached. Used only ** by Parse.pConstExpr */ } u; } a[1]; /* One slot for each expression in the list */ }; /* ** Allowed values for Expr.a.eEName */ #define ENAME_NAME 0 /* The AS clause of a result set */ #define ENAME_SPAN 1 /* Complete text of the result set expression */ #define ENAME_TAB 2 /* "DB.TABLE.NAME" for the result set */ /* ** An instance of this structure can hold a simple list of identifiers, ** such as the list "a,b,c" in the following statements: ** ** INSERT INTO t(a,b,c) VALUES ...; ** CREATE INDEX idx ON t(a,b,c); ** CREATE TRIGGER trig BEFORE UPDATE ON t(a,b,c) ...; |
︙ | ︙ | |||
2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 | struct IdList_item { char *zName; /* Name of the identifier */ int idx; /* Index in some Table.aCol[] of a column named zName */ } *a; int nId; /* Number of identifiers on the list */ }; /* ** The following structure describes the FROM clause of a SELECT statement. ** Each table or subquery in the FROM clause is a separate element of ** the SrcList.a[] array. ** ** With the addition of multiple database support, the following structure ** can also be used to describe a particular table such as the table that | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 | struct IdList_item { char *zName; /* Name of the identifier */ int idx; /* Index in some Table.aCol[] of a column named zName */ } *a; int nId; /* Number of identifiers on the list */ }; /* ** The SrcItem object represents a single term in the FROM clause of a query. ** The SrcList object is mostly an array of SrcItems. ** ** Union member validity: ** ** u1.zIndexedBy fg.isIndexedBy && !fg.isTabFunc ** u1.pFuncArg fg.isTabFunc && !fg.isIndexedBy ** u2.pIBIndex fg.isIndexedBy && !fg.isCte ** u2.pCteUse fg.isCte && !fg.isIndexedBy */ struct SrcItem { Schema *pSchema; /* Schema to which this item is fixed */ char *zDatabase; /* Name of database holding this table */ char *zName; /* Name of the table */ char *zAlias; /* The "B" part of a "A AS B" phrase. zName is the "A" */ Table *pTab; /* An SQL table corresponding to zName */ Select *pSelect; /* A SELECT statement used in place of a table name */ int addrFillSub; /* Address of subroutine to manifest a subquery */ int regReturn; /* Register holding return address of addrFillSub */ int regResult; /* Registers holding results of a co-routine */ struct { u8 jointype; /* Type of join between this table and the previous */ unsigned notIndexed :1; /* True if there is a NOT INDEXED clause */ unsigned isIndexedBy :1; /* True if there is an INDEXED BY clause */ unsigned isTabFunc :1; /* True if table-valued-function syntax */ unsigned isCorrelated :1; /* True if sub-query is correlated */ unsigned viaCoroutine :1; /* Implemented as a co-routine */ unsigned isRecursive :1; /* True for recursive reference in WITH */ unsigned fromDDL :1; /* Comes from sqlite_schema */ unsigned isCte :1; /* This is a CTE */ unsigned notCte :1; /* This item may not match a CTE */ } fg; int iCursor; /* The VDBE cursor number used to access this table */ Expr *pOn; /* The ON clause of a join */ IdList *pUsing; /* The USING clause of a join */ Bitmask colUsed; /* Bit N (1<<N) set if column N of pTab is used */ union { char *zIndexedBy; /* Identifier from "INDEXED BY <zIndex>" clause */ ExprList *pFuncArg; /* Arguments to table-valued-function */ } u1; union { Index *pIBIndex; /* Index structure corresponding to u1.zIndexedBy */ CteUse *pCteUse; /* CTE Usage info info fg.isCte is true */ } u2; }; /* ** The following structure describes the FROM clause of a SELECT statement. ** Each table or subquery in the FROM clause is a separate element of ** the SrcList.a[] array. ** ** With the addition of multiple database support, the following structure ** can also be used to describe a particular table such as the table that |
︙ | ︙ | |||
2636 2637 2638 2639 2640 2641 2642 | ** ** In the colUsed field, the high-order bit (bit 63) is set if the table ** contains more than 63 columns and the 64-th or later column is used. */ struct SrcList { int nSrc; /* Number of tables or subqueries in the FROM clause */ u32 nAlloc; /* Number of entries allocated in a[] below */ | < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 | ** ** In the colUsed field, the high-order bit (bit 63) is set if the table ** contains more than 63 columns and the 64-th or later column is used. */ struct SrcList { int nSrc; /* Number of tables or subqueries in the FROM clause */ u32 nAlloc; /* Number of entries allocated in a[] below */ SrcItem a[1]; /* One entry for each identifier on the list */ }; /* ** Permitted values of the SrcList.a.jointype field */ #define JT_INNER 0x0001 /* Any kind of inner or cross join */ #define JT_CROSS 0x0002 /* Explicit use of the CROSS keyword */ |
︙ | ︙ | |||
2698 2699 2700 2701 2702 2703 2704 | #define WHERE_DUPLICATES_OK 0x0010 /* Ok to return a row more than once */ #define WHERE_OR_SUBCLAUSE 0x0020 /* Processing a sub-WHERE as part of ** the OR optimization */ #define WHERE_GROUPBY 0x0040 /* pOrderBy is really a GROUP BY */ #define WHERE_DISTINCTBY 0x0080 /* pOrderby is really a DISTINCT clause */ #define WHERE_WANT_DISTINCT 0x0100 /* All output needs to be distinct */ #define WHERE_SORTBYGROUP 0x0200 /* Support sqlite3WhereIsSorted() */ | | | | 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 | #define WHERE_DUPLICATES_OK 0x0010 /* Ok to return a row more than once */ #define WHERE_OR_SUBCLAUSE 0x0020 /* Processing a sub-WHERE as part of ** the OR optimization */ #define WHERE_GROUPBY 0x0040 /* pOrderBy is really a GROUP BY */ #define WHERE_DISTINCTBY 0x0080 /* pOrderby is really a DISTINCT clause */ #define WHERE_WANT_DISTINCT 0x0100 /* All output needs to be distinct */ #define WHERE_SORTBYGROUP 0x0200 /* Support sqlite3WhereIsSorted() */ #define WHERE_AGG_DISTINCT 0x0400 /* Query is "SELECT agg(DISTINCT ...)" */ #define WHERE_ORDERBY_LIMIT 0x0800 /* ORDERBY+LIMIT on the inner loop */ /* 0x1000 not currently used */ /* 0x2000 not currently used */ #define WHERE_USE_LIMIT 0x4000 /* Use the LIMIT in cost estimates */ /* 0x8000 not currently used */ /* Allowed return values from sqlite3WhereIsDistinct() */ #define WHERE_DISTINCT_NOOP 0 /* DISTINCT keyword not used */ |
︙ | ︙ | |||
2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 | struct NameContext { Parse *pParse; /* The parser */ SrcList *pSrcList; /* One or more tables used to resolve names */ union { ExprList *pEList; /* Optional list of result-set columns */ AggInfo *pAggInfo; /* Information about aggregates at this level */ Upsert *pUpsert; /* ON CONFLICT clause information from an upsert */ } uNC; NameContext *pNext; /* Next outer name context. NULL for outermost */ int nRef; /* Number of names resolved by this context */ | > | | | | > > | | | | | | > | | | | > | | | > > > > > > | > > | > > > | | < > > | | 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 3259 3260 | struct NameContext { Parse *pParse; /* The parser */ SrcList *pSrcList; /* One or more tables used to resolve names */ union { ExprList *pEList; /* Optional list of result-set columns */ AggInfo *pAggInfo; /* Information about aggregates at this level */ Upsert *pUpsert; /* ON CONFLICT clause information from an upsert */ int iBaseReg; /* For TK_REGISTER when parsing RETURNING */ } uNC; NameContext *pNext; /* Next outer name context. NULL for outermost */ int nRef; /* Number of names resolved by this context */ int nNcErr; /* Number of errors encountered while resolving names */ int ncFlags; /* Zero or more NC_* flags defined below */ Select *pWinSelect; /* SELECT statement for any window functions */ }; /* ** Allowed values for the NameContext, ncFlags field. ** ** Value constraints (all checked via assert()): ** NC_HasAgg == SF_HasAgg == EP_Agg ** NC_MinMaxAgg == SF_MinMaxAgg == SQLITE_FUNC_MINMAX ** NC_OrderAgg == SF_OrderByReqd == SQLITE_FUNC_ANYORDER ** NC_HasWin == EP_Win ** */ #define NC_AllowAgg 0x000001 /* Aggregate functions are allowed here */ #define NC_PartIdx 0x000002 /* True if resolving a partial index WHERE */ #define NC_IsCheck 0x000004 /* True if resolving a CHECK constraint */ #define NC_GenCol 0x000008 /* True for a GENERATED ALWAYS AS clause */ #define NC_HasAgg 0x000010 /* One or more aggregate functions seen */ #define NC_IdxExpr 0x000020 /* True if resolving columns of CREATE INDEX */ #define NC_SelfRef 0x00002e /* Combo: PartIdx, isCheck, GenCol, and IdxExpr */ #define NC_VarSelect 0x000040 /* A correlated subquery has been seen */ #define NC_UEList 0x000080 /* True if uNC.pEList is used */ #define NC_UAggInfo 0x000100 /* True if uNC.pAggInfo is used */ #define NC_UUpsert 0x000200 /* True if uNC.pUpsert is used */ #define NC_UBaseReg 0x000400 /* True if uNC.iBaseReg is used */ #define NC_MinMaxAgg 0x001000 /* min/max aggregates seen. See note above */ #define NC_Complex 0x002000 /* True if a function or subquery seen */ #define NC_AllowWin 0x004000 /* Window functions are allowed here */ #define NC_HasWin 0x008000 /* One or more window functions seen */ #define NC_IsDDL 0x010000 /* Resolving names in a CREATE statement */ #define NC_InAggFunc 0x020000 /* True if analyzing arguments to an agg func */ #define NC_FromDDL 0x040000 /* SQL text comes from sqlite_schema */ #define NC_NoSelect 0x080000 /* Do not descend into sub-selects */ #define NC_OrderAgg 0x8000000 /* Has an aggregate other than count/min/max */ /* ** An instance of the following object describes a single ON CONFLICT ** clause in an upsert. ** ** The pUpsertTarget field is only set if the ON CONFLICT clause includes ** conflict-target clause. (In "ON CONFLICT(a,b)" the "(a,b)" is the ** conflict-target clause.) The pUpsertTargetWhere is the optional ** WHERE clause used to identify partial unique indexes. ** ** pUpsertSet is the list of column=expr terms of the UPDATE statement. ** The pUpsertSet field is NULL for a ON CONFLICT DO NOTHING. The ** pUpsertWhere is the WHERE clause for the UPDATE and is NULL if the ** WHERE clause is omitted. */ struct Upsert { ExprList *pUpsertTarget; /* Optional description of conflict target */ Expr *pUpsertTargetWhere; /* WHERE clause for partial index targets */ ExprList *pUpsertSet; /* The SET clause from an ON CONFLICT UPDATE */ Expr *pUpsertWhere; /* WHERE clause for the ON CONFLICT UPDATE */ Upsert *pNextUpsert; /* Next ON CONFLICT clause in the list */ u8 isDoUpdate; /* True for DO UPDATE. False for DO NOTHING */ /* Above this point is the parse tree for the ON CONFLICT clauses. ** The next group of fields stores intermediate data. */ void *pToFree; /* Free memory when deleting the Upsert object */ /* All fields above are owned by the Upsert object and must be freed ** when the Upsert is destroyed. The fields below are used to transfer ** information from the INSERT processing down into the UPDATE processing ** while generating code. The fields below are owned by the INSERT ** statement and will be freed by INSERT processing. */ Index *pUpsertIdx; /* UNIQUE constraint specified by pUpsertTarget */ SrcList *pUpsertSrc; /* Table to be updated */ int regData; /* First register holding array of VALUES */ int iDataCur; /* Index of the data cursor */ int iIdxCur; /* Index of the first index cursor */ }; /* |
︙ | ︙ | |||
2818 2819 2820 2821 2822 2823 2824 | ** as the OP_OpenEphm instruction is coded because not ** enough information about the compound query is known at that point. ** The KeyInfo for addrOpenTran[0] and [1] contains collating sequences ** for the result set. The KeyInfo for addrOpenEphm[2] contains collating ** sequences for the ORDER BY clause. */ struct Select { | < > | | > | | | | | | | | | | | | | | | | | | | | > > > > > > > > > < < < | 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 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 | ** as the OP_OpenEphm instruction is coded because not ** enough information about the compound query is known at that point. ** The KeyInfo for addrOpenTran[0] and [1] contains collating sequences ** for the result set. The KeyInfo for addrOpenEphm[2] contains collating ** sequences for the ORDER BY clause. */ struct Select { u8 op; /* One of: TK_UNION TK_ALL TK_INTERSECT TK_EXCEPT */ LogEst nSelectRow; /* Estimated number of result rows */ u32 selFlags; /* Various SF_* values */ int iLimit, iOffset; /* Memory registers holding LIMIT & OFFSET counters */ u32 selId; /* Unique identifier number for this SELECT */ int addrOpenEphm[2]; /* OP_OpenEphem opcodes related to this select */ ExprList *pEList; /* The fields of the result */ SrcList *pSrc; /* The FROM clause */ Expr *pWhere; /* The WHERE clause */ ExprList *pGroupBy; /* The GROUP BY clause */ Expr *pHaving; /* The HAVING clause */ ExprList *pOrderBy; /* The ORDER BY clause */ Select *pPrior; /* Prior select in a compound select statement */ Select *pNext; /* Next select to the left in a compound */ Expr *pLimit; /* LIMIT expression. NULL means not used. */ With *pWith; /* WITH clause attached to this select. Or NULL. */ #ifndef SQLITE_OMIT_WINDOWFUNC Window *pWin; /* List of window functions */ Window *pWinDefn; /* List of named window definitions */ #endif }; /* ** Allowed values for Select.selFlags. The "SF" prefix stands for ** "Select Flag". ** ** Value constraints (all checked via assert()) ** SF_HasAgg == NC_HasAgg ** SF_MinMaxAgg == NC_MinMaxAgg == SQLITE_FUNC_MINMAX ** SF_OrderByReqd == NC_OrderAgg == SQLITE_FUNC_ANYORDER ** SF_FixedLimit == WHERE_USE_LIMIT */ #define SF_Distinct 0x0000001 /* Output should be DISTINCT */ #define SF_All 0x0000002 /* Includes the ALL keyword */ #define SF_Resolved 0x0000004 /* Identifiers have been resolved */ #define SF_Aggregate 0x0000008 /* Contains agg functions or a GROUP BY */ #define SF_HasAgg 0x0000010 /* Contains aggregate functions */ #define SF_UsesEphemeral 0x0000020 /* Uses the OpenEphemeral opcode */ #define SF_Expanded 0x0000040 /* sqlite3SelectExpand() called on this */ #define SF_HasTypeInfo 0x0000080 /* FROM subqueries have Table metadata */ #define SF_Compound 0x0000100 /* Part of a compound query */ #define SF_Values 0x0000200 /* Synthesized from VALUES clause */ #define SF_MultiValue 0x0000400 /* Single VALUES term with multiple rows */ #define SF_NestedFrom 0x0000800 /* Part of a parenthesized FROM clause */ #define SF_MinMaxAgg 0x0001000 /* Aggregate containing min() or max() */ #define SF_Recursive 0x0002000 /* The recursive part of a recursive CTE */ #define SF_FixedLimit 0x0004000 /* nSelectRow set by a constant LIMIT */ #define SF_MaybeConvert 0x0008000 /* Need convertCompoundSelectToSubquery() */ #define SF_Converted 0x0010000 /* By convertCompoundSelectToSubquery() */ #define SF_IncludeHidden 0x0020000 /* Include hidden columns in output */ #define SF_ComplexResult 0x0040000 /* Result contains subquery or function */ #define SF_WhereBegin 0x0080000 /* Really a WhereBegin() call. Debug Only */ #define SF_WinRewrite 0x0100000 /* Window function rewrite accomplished */ #define SF_View 0x0200000 /* SELECT statement is a view */ #define SF_NoopOrderBy 0x0400000 /* ORDER BY is ignored for this query */ #define SF_UFSrcCheck 0x0800000 /* Check pSrc as required by UPDATE...FROM */ #define SF_PushDown 0x1000000 /* SELECT has be modified by push-down opt */ #define SF_MultiPart 0x2000000 /* Has multiple incompatible PARTITIONs */ #define SF_CopyCte 0x4000000 /* SELECT statement is a copy of a CTE */ #define SF_OrderByReqd 0x8000000 /* The ORDER BY clause may not be omitted */ /* ** The results of a SELECT can be distributed in several ways, as defined ** by one of the following macros. The "SRT" prefix means "SELECT Result ** Type". ** ** SRT_Union Store results as a key in a temporary index ** identified by pDest->iSDParm. ** ** SRT_Except Remove results from the temporary index pDest->iSDParm. ** ** SRT_Exists Store a 1 in memory cell pDest->iSDParm if the result ** set is not empty. ** ** SRT_Discard Throw the results away. This is used by SELECT ** statements within triggers whose only purpose is ** the side-effects of functions. ** ** SRT_Output Generate a row of output (using the OP_ResultRow ** opcode) for each row in the result set. ** ** SRT_Mem Only valid if the result is a single column. ** Store the first column of the first result row ** in register pDest->iSDParm then abandon the rest ** of the query. This destination implies "LIMIT 1". |
︙ | ︙ | |||
2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 | ** SRT_Queue Store results in priority queue pDest->iSDParm (really ** an index). Append a sequence number so that all entries ** are distinct. ** ** SRT_DistQueue Store results in priority queue pDest->iSDParm only if ** the same record has never been stored before. The ** index at pDest->iSDParm+1 hold all prior stores. */ #define SRT_Union 1 /* Store result as keys in an index */ #define SRT_Except 2 /* Remove result from a UNION index */ #define SRT_Exists 3 /* Store 1 if the result is not empty */ #define SRT_Discard 4 /* Do not save the results anywhere */ | > > > > > > > > > > | > > > | | | > | > | 3392 3393 3394 3395 3396 3397 3398 3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 | ** SRT_Queue Store results in priority queue pDest->iSDParm (really ** an index). Append a sequence number so that all entries ** are distinct. ** ** SRT_DistQueue Store results in priority queue pDest->iSDParm only if ** the same record has never been stored before. The ** index at pDest->iSDParm+1 hold all prior stores. ** ** SRT_Upfrom Store results in the temporary table already opened by ** pDest->iSDParm. If (pDest->iSDParm<0), then the temp ** table is an intkey table - in this case the first ** column returned by the SELECT is used as the integer ** key. If (pDest->iSDParm>0), then the table is an index ** table. (pDest->iSDParm) is the number of key columns in ** each index record in this case. */ #define SRT_Union 1 /* Store result as keys in an index */ #define SRT_Except 2 /* Remove result from a UNION index */ #define SRT_Exists 3 /* Store 1 if the result is not empty */ #define SRT_Discard 4 /* Do not save the results anywhere */ #define SRT_DistFifo 5 /* Like SRT_Fifo, but unique results only */ #define SRT_DistQueue 6 /* Like SRT_Queue, but unique results only */ /* The DISTINCT clause is ignored for all of the above. Not that ** IgnorableDistinct() implies IgnorableOrderby() */ #define IgnorableDistinct(X) ((X->eDest)<=SRT_DistQueue) #define SRT_Queue 7 /* Store result in an queue */ #define SRT_Fifo 8 /* Store result as data with an automatic rowid */ /* The ORDER BY clause is ignored for all of the above */ #define IgnorableOrderby(X) ((X->eDest)<=SRT_Fifo) #define SRT_Output 9 /* Output each row of result */ #define SRT_Mem 10 /* Store result in a memory cell */ #define SRT_Set 11 /* Store results as keys in an index */ #define SRT_EphemTab 12 /* Create transient tab and store like SRT_Table */ #define SRT_Coroutine 13 /* Generate a single row of result */ #define SRT_Table 14 /* Store result as data with an automatic rowid */ #define SRT_Upfrom 15 /* Store result as data with rowid */ /* ** An instance of this object describes where to put of the results of ** a SELECT statement. */ struct SelectDest { u8 eDest; /* How to dispose of the results. One of SRT_* above. */ int iSDParm; /* A parameter used by the eDest disposal method */ int iSDParm2; /* A second parameter for the eDest disposal method */ int iSdst; /* Base register where results are written */ int nSdst; /* Number of registers allocated */ char *zAffSdst; /* Affinity used when eDest==SRT_Set */ ExprList *pOrderBy; /* Key columns for SRT_Queue and SRT_DistQueue */ }; /* |
︙ | ︙ | |||
3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 | # define DbMaskTest(M,I) (((M)&(((yDbMask)1)<<(I)))!=0) # define DbMaskZero(M) (M)=0 # define DbMaskSet(M,I) (M)|=(((yDbMask)1)<<(I)) # define DbMaskAllZero(M) (M)==0 # define DbMaskNonZero(M) (M)!=0 #endif /* ** An SQL parser context. A copy of this structure is passed through ** the parser and down into all the parser action routine in order to ** carry around information that is global to the entire parse. ** ** The structure is divided into two parts. When the parser and code ** generate call themselves recursively, the first part of the structure | > > > > > > > > > > > | 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 | # define DbMaskTest(M,I) (((M)&(((yDbMask)1)<<(I)))!=0) # define DbMaskZero(M) (M)=0 # define DbMaskSet(M,I) (M)|=(((yDbMask)1)<<(I)) # define DbMaskAllZero(M) (M)==0 # define DbMaskNonZero(M) (M)!=0 #endif /* ** An instance of the ParseCleanup object specifies an operation that ** should be performed after parsing to deallocation resources obtained ** during the parse and which are no longer needed. */ struct ParseCleanup { ParseCleanup *pNext; /* Next cleanup task */ void *pPtr; /* Pointer to object to deallocate */ void (*xCleanup)(sqlite3*,void*); /* Deallocation routine */ }; /* ** An SQL parser context. A copy of this structure is passed through ** the parser and down into all the parser action routine in order to ** carry around information that is global to the entire parse. ** ** The structure is divided into two parts. When the parser and code ** generate call themselves recursively, the first part of the structure |
︙ | ︙ | |||
3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 | u8 nested; /* Number of nested calls to the parser/code generator */ u8 nTempReg; /* Number of temporary registers in aTempReg[] */ u8 isMultiWrite; /* True if statement may modify/insert multiple rows */ u8 mayAbort; /* True if statement may throw an ABORT exception */ u8 hasCompound; /* Need to invoke convertCompoundSelectToSubquery() */ u8 okConstFactor; /* OK to factor out constants */ u8 disableLookaside; /* Number of times lookaside has been disabled */ int nRangeReg; /* Size of the temporary register block */ int iRangeReg; /* First register in temporary register block */ int nErr; /* Number of errors seen */ int nTab; /* Number of previously allocated VDBE cursors */ int nMem; /* Number of memory cells used so far */ | > > > > < | > > | > > > | 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 3587 3588 3589 3590 3591 3592 3593 3594 | u8 nested; /* Number of nested calls to the parser/code generator */ u8 nTempReg; /* Number of temporary registers in aTempReg[] */ u8 isMultiWrite; /* True if statement may modify/insert multiple rows */ u8 mayAbort; /* True if statement may throw an ABORT exception */ u8 hasCompound; /* Need to invoke convertCompoundSelectToSubquery() */ u8 okConstFactor; /* OK to factor out constants */ u8 disableLookaside; /* Number of times lookaside has been disabled */ u8 disableVtab; /* Disable all virtual tables for this parse */ #if defined(SQLITE_DEBUG) || defined(SQLITE_COVERAGE_TEST) u8 earlyCleanup; /* OOM inside sqlite3ParserAddCleanup() */ #endif int nRangeReg; /* Size of the temporary register block */ int iRangeReg; /* First register in temporary register block */ int nErr; /* Number of errors seen */ int nTab; /* Number of previously allocated VDBE cursors */ int nMem; /* Number of memory cells used so far */ int szOpAlloc; /* Bytes of memory space allocated for Vdbe.aOp[] */ int iSelfTab; /* Table associated with an index on expr, or negative ** of the base register during check-constraint eval */ int nLabel; /* The *negative* of the number of labels used */ int nLabelAlloc; /* Number of slots in aLabel */ int *aLabel; /* Space to hold the labels */ ExprList *pConstExpr;/* Constant expressions */ Token constraintName;/* Name of the constraint currently being parsed */ yDbMask writeMask; /* Start a write transaction on these databases */ yDbMask cookieMask; /* Bitmask of schema verified databases */ int regRowid; /* Register holding rowid of CREATE TABLE entry */ int regRoot; /* Register holding root page number for new objects */ int nMaxArg; /* Max args passed to user function by sub-program */ int nSelect; /* Number of SELECT stmts. Counter for Select.selId */ #ifndef SQLITE_OMIT_SHARED_CACHE int nTableLock; /* Number of locks in aTableLock */ TableLock *aTableLock; /* Required table locks for shared-cache mode */ #endif AutoincInfo *pAinc; /* Information about AUTOINCREMENT counters */ Parse *pToplevel; /* Parse structure for main program (or NULL) */ Table *pTriggerTab; /* Table triggers are being coded for */ union { int addrCrTab; /* Address of OP_CreateBtree on CREATE TABLE */ Returning *pReturning; /* The RETURNING clause */ } u1; u32 nQueryLoop; /* Est number of iterations of a query (10*log2(N)) */ u32 oldmask; /* Mask of old.* columns referenced */ u32 newmask; /* Mask of new.* columns referenced */ u8 eTriggerOp; /* TK_UPDATE, TK_INSERT or TK_DELETE */ u8 bReturning; /* Coding a RETURNING trigger */ u8 eOrconf; /* Default ON CONFLICT policy for trigger steps */ u8 disableTriggers; /* True to disable triggers */ /************************************************************************** ** Fields above must be initialized to zero. The fields that follow, ** down to the beginning of the recursive section, do not need to be ** initialized as they will be set before being used. The boundary is |
︙ | ︙ | |||
3111 3112 3113 3114 3115 3116 3117 | ** first field in the recursive region. ************************************************************************/ Token sLastToken; /* The last token parsed */ ynVar nVar; /* Number of '?' variables seen in the SQL so far */ u8 iPkSortOrder; /* ASC or DESC for INTEGER PRIMARY KEY */ u8 explain; /* True if the EXPLAIN flag is found on the query */ | < < | > > < < > > > | | | 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 | ** first field in the recursive region. ************************************************************************/ Token sLastToken; /* The last token parsed */ ynVar nVar; /* Number of '?' variables seen in the SQL so far */ u8 iPkSortOrder; /* ASC or DESC for INTEGER PRIMARY KEY */ u8 explain; /* True if the EXPLAIN flag is found on the query */ u8 eParseMode; /* PARSE_MODE_XXX constant */ #ifndef SQLITE_OMIT_VIRTUALTABLE int nVtabLock; /* Number of virtual tables to lock */ #endif int nHeight; /* Expression tree height of current sub-select */ #ifndef SQLITE_OMIT_EXPLAIN int addrExplain; /* Address of current OP_Explain opcode */ #endif VList *pVList; /* Mapping between variable names and numbers */ Vdbe *pReprepare; /* VM being reprepared (sqlite3Reprepare()) */ const char *zTail; /* All SQL text past the last semicolon parsed */ Table *pNewTable; /* A table being constructed by CREATE TABLE */ Index *pNewIndex; /* An index being constructed by CREATE INDEX. ** Also used to hold redundant UNIQUE constraints ** during a RENAME COLUMN */ Trigger *pNewTrigger; /* Trigger under construct by a CREATE TRIGGER */ const char *zAuthContext; /* The 6th parameter to db->xAuth callbacks */ #ifndef SQLITE_OMIT_VIRTUALTABLE Token sArg; /* Complete text of a module argument */ Table **apVtabLock; /* Pointer to virtual tables needing locking */ #endif TriggerPrg *pTriggerPrg; /* Linked list of coded triggers */ With *pWith; /* Current WITH clause, or NULL */ ParseCleanup *pCleanup; /* List of cleanup operations to run after parse */ #ifndef SQLITE_OMIT_ALTERTABLE RenameToken *pRename; /* Tokens subject to renaming by ALTER TABLE */ #endif }; /* Allowed values for Parse.eParseMode */ #define PARSE_MODE_NORMAL 0 #define PARSE_MODE_DECLARE_VTAB 1 #define PARSE_MODE_RENAME 2 #define PARSE_MODE_UNMAP 3 /* ** Sizes and pointers of various parts of the Parse object. */ #define PARSE_HDR_SZ offsetof(Parse,aTempReg) /* Recursive part w/o aColCache*/ #define PARSE_RECURSE_SZ offsetof(Parse,sLastToken) /* Recursive part */ #define PARSE_TAIL_SZ (sizeof(Parse)-PARSE_RECURSE_SZ) /* Non-recursive part */ |
︙ | ︙ | |||
3166 3167 3168 3169 3170 3171 3172 | #else #define IN_DECLARE_VTAB (pParse->eParseMode==PARSE_MODE_DECLARE_VTAB) #endif #if defined(SQLITE_OMIT_ALTERTABLE) #define IN_RENAME_OBJECT 0 #else | | | 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 | #else #define IN_DECLARE_VTAB (pParse->eParseMode==PARSE_MODE_DECLARE_VTAB) #endif #if defined(SQLITE_OMIT_ALTERTABLE) #define IN_RENAME_OBJECT 0 #else #define IN_RENAME_OBJECT (pParse->eParseMode>=PARSE_MODE_RENAME) #endif #if defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_OMIT_ALTERTABLE) #define IN_SPECIAL_PARSE 0 #else #define IN_SPECIAL_PARSE (pParse->eParseMode!=PARSE_MODE_NORMAL) #endif |
︙ | ︙ | |||
3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 | #define OPFLAG_SEEKEQ 0x02 /* OP_Open** cursor uses EQ seek only */ #define OPFLAG_FORDELETE 0x08 /* OP_Open should use BTREE_FORDELETE */ #define OPFLAG_P2ISREG 0x10 /* P2 to OP_Open** is a register number */ #define OPFLAG_PERMUTE 0x01 /* OP_Compare: use the permutation */ #define OPFLAG_SAVEPOSITION 0x02 /* OP_Delete/Insert: save cursor pos */ #define OPFLAG_AUXDELETE 0x04 /* OP_Delete: index in a DELETE op */ #define OPFLAG_NOCHNG_MAGIC 0x6d /* OP_MakeRecord: serialtype 10 is ok */ /* * Each trigger present in the database schema is stored as an instance of * struct Trigger. * * Pointers to instances of struct Trigger are stored in two ways. * 1. In the "trigHash" hash table (part of the sqlite3* that represents the | > | 3710 3711 3712 3713 3714 3715 3716 3717 3718 3719 3720 3721 3722 3723 3724 | #define OPFLAG_SEEKEQ 0x02 /* OP_Open** cursor uses EQ seek only */ #define OPFLAG_FORDELETE 0x08 /* OP_Open should use BTREE_FORDELETE */ #define OPFLAG_P2ISREG 0x10 /* P2 to OP_Open** is a register number */ #define OPFLAG_PERMUTE 0x01 /* OP_Compare: use the permutation */ #define OPFLAG_SAVEPOSITION 0x02 /* OP_Delete/Insert: save cursor pos */ #define OPFLAG_AUXDELETE 0x04 /* OP_Delete: index in a DELETE op */ #define OPFLAG_NOCHNG_MAGIC 0x6d /* OP_MakeRecord: serialtype 10 is ok */ #define OPFLAG_PREFORMAT 0x80 /* OP_Insert uses preformatted cell */ /* * Each trigger present in the database schema is stored as an instance of * struct Trigger. * * Pointers to instances of struct Trigger are stored in two ways. * 1. In the "trigHash" hash table (part of the sqlite3* that represents the |
︙ | ︙ | |||
3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 | * containing the SQL statements specified as the trigger program. */ struct Trigger { char *zName; /* The name of the trigger */ char *table; /* The table or view to which the trigger applies */ u8 op; /* One of TK_DELETE, TK_UPDATE, TK_INSERT */ u8 tr_tm; /* One of TRIGGER_BEFORE, TRIGGER_AFTER */ Expr *pWhen; /* The WHEN clause of the expression (may be NULL) */ IdList *pColumns; /* If this is an UPDATE OF <column-list> trigger, the <column-list> is stored here */ Schema *pSchema; /* Schema containing the trigger */ Schema *pTabSchema; /* Schema containing the table */ TriggerStep *step_list; /* Link list of trigger program steps */ Trigger *pNext; /* Next trigger associated with the table */ | > | 3732 3733 3734 3735 3736 3737 3738 3739 3740 3741 3742 3743 3744 3745 3746 | * containing the SQL statements specified as the trigger program. */ struct Trigger { char *zName; /* The name of the trigger */ char *table; /* The table or view to which the trigger applies */ u8 op; /* One of TK_DELETE, TK_UPDATE, TK_INSERT */ u8 tr_tm; /* One of TRIGGER_BEFORE, TRIGGER_AFTER */ u8 bReturning; /* This trigger implements a RETURNING clause */ Expr *pWhen; /* The WHEN clause of the expression (may be NULL) */ IdList *pColumns; /* If this is an UPDATE OF <column-list> trigger, the <column-list> is stored here */ Schema *pSchema; /* Schema containing the trigger */ Schema *pTabSchema; /* Schema containing the table */ TriggerStep *step_list; /* Link list of trigger program steps */ Trigger *pNext; /* Next trigger associated with the table */ |
︙ | ︙ | |||
3294 3295 3296 3297 3298 3299 3300 | * Otherwise NULL. * pExprList -> A list of the columns to update and the expressions to update * them to. See sqlite3Update() documentation of "pChanges" * argument. * */ struct TriggerStep { | | > > | | < < < | | > > > | | | < < | 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 | * Otherwise NULL. * pExprList -> A list of the columns to update and the expressions to update * them to. See sqlite3Update() documentation of "pChanges" * argument. * */ struct TriggerStep { u8 op; /* One of TK_DELETE, TK_UPDATE, TK_INSERT, TK_SELECT, ** or TK_RETURNING */ u8 orconf; /* OE_Rollback etc. */ Trigger *pTrig; /* The trigger that this step is a part of */ Select *pSelect; /* SELECT statement or RHS of INSERT INTO SELECT ... */ char *zTarget; /* Target table for DELETE, UPDATE, INSERT */ SrcList *pFrom; /* FROM clause for UPDATE statement (if any) */ Expr *pWhere; /* The WHERE clause for DELETE or UPDATE steps */ ExprList *pExprList; /* SET clause for UPDATE, or RETURNING clause */ IdList *pIdList; /* Column names for INSERT */ Upsert *pUpsert; /* Upsert clauses on an INSERT */ char *zSpan; /* Original SQL text of this command */ TriggerStep *pNext; /* Next in the link-list */ TriggerStep *pLast; /* Last element in link-list. Valid for 1st elem only */ }; /* ** Information about a RETURNING clause */ struct Returning { Parse *pParse; /* The parse that includes the RETURNING clause */ ExprList *pReturnEL; /* List of expressions to return */ Trigger retTrig; /* The transient trigger that implements RETURNING */ TriggerStep retTStep; /* The trigger step */ int iRetCur; /* Transient table holding RETURNING results */ int nRetCol; /* Number of in pReturnEL after expansion */ int iRetReg; /* Register array for holding a row of RETURNING */ }; /* ** An objected used to accumulate the text of a string where we ** do not necessarily know how big the string will be in the end. */ struct sqlite3_str { |
︙ | ︙ | |||
3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 | */ typedef struct { sqlite3 *db; /* The database being initialized */ char **pzErrMsg; /* Error message stored here */ int iDb; /* 0 for main database. 1 for TEMP, 2.. for ATTACHed */ int rc; /* Result code stored here */ u32 mInitFlags; /* Flags controlling error messages */ } InitData; /* ** Allowed values for mInitFlags */ | > > > > > > | > > > > > > > > > > > > > > > | | | | | > | 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 3882 3883 3884 3885 3886 3887 3888 3889 3890 3891 3892 3893 3894 3895 3896 3897 3898 3899 3900 3901 3902 3903 3904 | */ typedef struct { sqlite3 *db; /* The database being initialized */ char **pzErrMsg; /* Error message stored here */ int iDb; /* 0 for main database. 1 for TEMP, 2.. for ATTACHed */ int rc; /* Result code stored here */ u32 mInitFlags; /* Flags controlling error messages */ u32 nInitRow; /* Number of rows processed */ Pgno mxPage; /* Maximum page number. 0 for no limit. */ } InitData; /* ** Allowed values for mInitFlags */ #define INITFLAG_AlterMask 0x0003 /* Types of ALTER */ #define INITFLAG_AlterRename 0x0001 /* Reparse after a RENAME */ #define INITFLAG_AlterDrop 0x0002 /* Reparse after a DROP COLUMN */ #define INITFLAG_AlterAdd 0x0003 /* Reparse after an ADD COLUMN */ /* Tuning parameters are set using SQLITE_TESTCTRL_TUNE and are controlled ** on debug-builds of the CLI using ".testctrl tune ID VALUE". Tuning ** parameters are for temporary use during development, to help find ** optimial values for parameters in the query planner. The should not ** be used on trunk check-ins. They are a temporary mechanism available ** for transient development builds only. ** ** Tuning parameters are numbered starting with 1. */ #define SQLITE_NTUNE 6 /* Should be zero for all trunk check-ins */ #ifdef SQLITE_DEBUG # define Tuning(X) (sqlite3Config.aTune[(X)-1]) #else # define Tuning(X) 0 #endif /* ** Structure containing global configuration data for the SQLite library. ** ** This structure also contains some state information. */ struct Sqlite3Config { int bMemstat; /* True to enable memory status */ u8 bCoreMutex; /* True to enable core mutexing */ u8 bFullMutex; /* True to enable full mutexing */ u8 bOpenUri; /* True to interpret filenames as URIs */ u8 bUseCis; /* Use covering indices for full-scans */ u8 bSmallMalloc; /* Avoid large memory allocations if true */ u8 bExtraSchemaChecks; /* Verify type,name,tbl_name in schema */ int mxStrlen; /* Maximum string length */ int neverCorrupt; /* Database is always well-formed */ int szLookaside; /* Default lookaside buffer size */ int nLookaside; /* Default lookaside buffer count */ int nStmtSpill; /* Stmt-journal spill-to-disk threshold */ sqlite3_mem_methods m; /* Low-level memory allocation interface */ sqlite3_mutex_methods mutex; /* Low-level mutex interface */ |
︙ | ︙ | |||
3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 | #ifdef SQLITE_VDBE_COVERAGE /* The following callback (if not NULL) is invoked on every VDBE branch ** operation. Set the callback using SQLITE_TESTCTRL_VDBE_COVERAGE. */ void (*xVdbeBranch)(void*,unsigned iSrcLine,u8 eThis,u8 eMx); /* Callback */ void *pVdbeBranchArg; /* 1st argument */ #endif #ifndef SQLITE_UNTESTABLE int (*xTestCallback)(int); /* Invoked by sqlite3FaultSim() */ #endif int bLocaltimeFault; /* True to fail localtime() calls */ | > > > < > > > > > | 3932 3933 3934 3935 3936 3937 3938 3939 3940 3941 3942 3943 3944 3945 3946 3947 3948 3949 3950 3951 3952 3953 3954 3955 3956 3957 3958 3959 | #ifdef SQLITE_VDBE_COVERAGE /* The following callback (if not NULL) is invoked on every VDBE branch ** operation. Set the callback using SQLITE_TESTCTRL_VDBE_COVERAGE. */ void (*xVdbeBranch)(void*,unsigned iSrcLine,u8 eThis,u8 eMx); /* Callback */ void *pVdbeBranchArg; /* 1st argument */ #endif #ifndef SQLITE_OMIT_DESERIALIZE sqlite3_int64 mxMemdbSize; /* Default max memdb size */ #endif #ifndef SQLITE_UNTESTABLE int (*xTestCallback)(int); /* Invoked by sqlite3FaultSim() */ #endif int bLocaltimeFault; /* True to fail localtime() calls */ int iOnceResetThreshold; /* When to reset OP_Once counters */ u32 szSorterRef; /* Min size in bytes to use sorter-refs */ unsigned int iPrngSeed; /* Alternative fixed seed for the PRNG */ /* vvvv--- must be last ---vvv */ #ifdef SQLITE_DEBUG sqlite3_int64 aTune[SQLITE_NTUNE]; /* Tuning parameters */ #endif }; /* ** This macro is used inside of assert() statements to indicate that ** the assert is only valid on a well-formed database. Instead of: ** ** assert( X ); |
︙ | ︙ | |||
3449 3450 3451 3452 3453 3454 3455 | */ struct Walker { Parse *pParse; /* Parser context. */ int (*xExprCallback)(Walker*, Expr*); /* Callback for expressions */ int (*xSelectCallback)(Walker*,Select*); /* Callback for SELECTs */ void (*xSelectCallback2)(Walker*,Select*);/* Second callback for SELECTs */ int walkerDepth; /* Number of subqueries */ | | < > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > | | > | | > | > > > > > > > > > > > > | > > | > | < > | > | > > > > | > | > > > | | | < > > > > > > | > | | < > > | 3975 3976 3977 3978 3979 3980 3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994 3995 3996 3997 3998 3999 4000 4001 4002 4003 4004 4005 4006 4007 4008 4009 4010 4011 4012 4013 4014 4015 4016 4017 4018 4019 4020 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 4034 4035 4036 4037 4038 4039 4040 4041 4042 4043 4044 4045 4046 4047 4048 4049 4050 4051 4052 4053 4054 4055 4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075 4076 4077 4078 4079 4080 4081 4082 4083 4084 4085 4086 4087 4088 4089 4090 4091 4092 4093 4094 4095 4096 4097 4098 4099 4100 4101 4102 4103 4104 4105 4106 4107 4108 4109 4110 4111 4112 4113 4114 4115 4116 4117 4118 4119 4120 4121 4122 4123 4124 4125 4126 4127 4128 4129 4130 4131 4132 4133 4134 4135 4136 4137 4138 4139 4140 4141 4142 4143 4144 4145 4146 4147 4148 4149 4150 4151 4152 4153 4154 4155 4156 4157 4158 4159 4160 4161 4162 4163 4164 4165 4166 4167 4168 4169 4170 4171 4172 4173 4174 4175 4176 4177 4178 4179 4180 4181 4182 4183 4184 4185 4186 4187 4188 4189 4190 | */ struct Walker { Parse *pParse; /* Parser context. */ int (*xExprCallback)(Walker*, Expr*); /* Callback for expressions */ int (*xSelectCallback)(Walker*,Select*); /* Callback for SELECTs */ void (*xSelectCallback2)(Walker*,Select*);/* Second callback for SELECTs */ int walkerDepth; /* Number of subqueries */ u16 eCode; /* A small processing code */ union { /* Extra data for callback */ NameContext *pNC; /* Naming context */ int n; /* A counter */ int iCur; /* A cursor number */ SrcList *pSrcList; /* FROM clause */ struct CCurHint *pCCurHint; /* Used by codeCursorHint() */ struct RefSrcList *pRefSrcList; /* sqlite3ReferencesSrcList() */ int *aiCol; /* array of column indexes */ struct IdxCover *pIdxCover; /* Check for index coverage */ struct IdxExprTrans *pIdxTrans; /* Convert idxed expr to column */ ExprList *pGroupBy; /* GROUP BY clause */ Select *pSelect; /* HAVING to WHERE clause ctx */ struct WindowRewrite *pRewrite; /* Window rewrite context */ struct WhereConst *pConst; /* WHERE clause constants */ struct RenameCtx *pRename; /* RENAME COLUMN context */ struct Table *pTab; /* Table of generated column */ SrcItem *pSrcItem; /* A single FROM clause item */ DbFixer *pFix; } u; }; /* ** The following structure contains information used by the sqliteFix... ** routines as they walk the parse tree to make database references ** explicit. */ struct DbFixer { Parse *pParse; /* The parsing context. Error messages written here */ Walker w; /* Walker object */ Schema *pSchema; /* Fix items to this schema */ u8 bTemp; /* True for TEMP schema entries */ const char *zDb; /* Make sure all objects are contained in this database */ const char *zType; /* Type of the container - used for error messages */ const Token *pName; /* Name of the container - used for error messages */ }; /* Forward declarations */ int sqlite3WalkExpr(Walker*, Expr*); int sqlite3WalkExprList(Walker*, ExprList*); int sqlite3WalkSelect(Walker*, Select*); int sqlite3WalkSelectExpr(Walker*, Select*); int sqlite3WalkSelectFrom(Walker*, Select*); int sqlite3ExprWalkNoop(Walker*, Expr*); int sqlite3SelectWalkNoop(Walker*, Select*); int sqlite3SelectWalkFail(Walker*, Select*); int sqlite3WalkerDepthIncrease(Walker*,Select*); void sqlite3WalkerDepthDecrease(Walker*,Select*); void sqlite3WalkWinDefnDummyCallback(Walker*,Select*); #ifdef SQLITE_DEBUG void sqlite3SelectWalkAssert2(Walker*, Select*); #endif #ifndef SQLITE_OMIT_CTE void sqlite3SelectPopWith(Walker*, Select*); #else # define sqlite3SelectPopWith 0 #endif /* ** Return code from the parse-tree walking primitives and their ** callbacks. */ #define WRC_Continue 0 /* Continue down into children */ #define WRC_Prune 1 /* Omit children but continue walking siblings */ #define WRC_Abort 2 /* Abandon the tree walk */ /* ** A single common table expression */ struct Cte { char *zName; /* Name of this CTE */ ExprList *pCols; /* List of explicit column names, or NULL */ Select *pSelect; /* The definition of this CTE */ const char *zCteErr; /* Error message for circular references */ CteUse *pUse; /* Usage information for this CTE */ u8 eM10d; /* The MATERIALIZED flag */ }; /* ** Allowed values for the materialized flag (eM10d): */ #define M10d_Yes 0 /* AS MATERIALIZED */ #define M10d_Any 1 /* Not specified. Query planner's choice */ #define M10d_No 2 /* AS NOT MATERIALIZED */ /* ** An instance of the With object represents a WITH clause containing ** one or more CTEs (common table expressions). */ struct With { int nCte; /* Number of CTEs in the WITH clause */ int bView; /* Belongs to the outermost Select of a view */ With *pOuter; /* Containing WITH clause, or NULL */ Cte a[1]; /* For each CTE in the WITH clause.... */ }; /* ** The Cte object is not guaranteed to persist for the entire duration ** of code generation. (The query flattener or other parser tree ** edits might delete it.) The following object records information ** about each Common Table Expression that must be preserved for the ** duration of the parse. ** ** The CteUse objects are freed using sqlite3ParserAddCleanup() rather ** than sqlite3SelectDelete(), which is what enables them to persist ** until the end of code generation. */ struct CteUse { int nUse; /* Number of users of this CTE */ int addrM9e; /* Start of subroutine to compute materialization */ int regRtn; /* Return address register for addrM9e subroutine */ int iCur; /* Ephemeral table holding the materialization */ LogEst nRowEst; /* Estimated number of rows in the table */ u8 eM10d; /* The MATERIALIZED flag */ }; #ifdef SQLITE_DEBUG /* ** An instance of the TreeView object is used for printing the content of ** data structures on sqlite3DebugPrintf() using a tree-like view. */ struct TreeView { int iLevel; /* Which level of the tree we are on */ u8 bLine[100]; /* Draw vertical in column i if bLine[i] is true */ }; #endif /* SQLITE_DEBUG */ /* ** This object is used in various ways, most (but not all) related to window ** functions. ** ** (1) A single instance of this structure is attached to the ** the Expr.y.pWin field for each window function in an expression tree. ** This object holds the information contained in the OVER clause, ** plus additional fields used during code generation. ** ** (2) All window functions in a single SELECT form a linked-list ** attached to Select.pWin. The Window.pFunc and Window.pExpr ** fields point back to the expression that is the window function. ** ** (3) The terms of the WINDOW clause of a SELECT are instances of this ** object on a linked list attached to Select.pWinDefn. ** ** (4) For an aggregate function with a FILTER clause, an instance ** of this object is stored in Expr.y.pWin with eFrmType set to ** TK_FILTER. In this case the only field used is Window.pFilter. ** ** The uses (1) and (2) are really the same Window object that just happens ** to be accessible in two different ways. Use case (3) are separate objects. */ struct Window { char *zName; /* Name of window (may be NULL) */ char *zBase; /* Name of base window for chaining (may be NULL) */ ExprList *pPartition; /* PARTITION BY clause */ ExprList *pOrderBy; /* ORDER BY clause */ u8 eFrmType; /* TK_RANGE, TK_GROUPS, TK_ROWS, or 0 */ u8 eStart; /* UNBOUNDED, CURRENT, PRECEDING or FOLLOWING */ u8 eEnd; /* UNBOUNDED, CURRENT, PRECEDING or FOLLOWING */ u8 bImplicitFrame; /* True if frame was implicitly specified */ u8 eExclude; /* TK_NO, TK_CURRENT, TK_TIES, TK_GROUP, or 0 */ Expr *pStart; /* Expression for "<expr> PRECEDING" */ Expr *pEnd; /* Expression for "<expr> FOLLOWING" */ Window **ppThis; /* Pointer to this object in Select.pWin list */ Window *pNextWin; /* Next window function belonging to this SELECT */ Expr *pFilter; /* The FILTER expression */ FuncDef *pFunc; /* The function */ int iEphCsr; /* Partition buffer or Peer buffer */ int regAccum; /* Accumulator */ int regResult; /* Interim result */ int csrApp; /* Function cursor (used by min/max) */ int regApp; /* Function register (also used by min/max) */ int regPart; /* Array of registers for PARTITION BY values */ Expr *pOwner; /* Expression object this window is attached to */ int nBufferCol; /* Number of columns in buffer table */ int iArgCol; /* Offset of first argument for this function */ int regOne; /* Register containing constant value 1 */ int regStartRowid; int regEndRowid; u8 bExprArgs; /* Defer evaluation of window function arguments ** due to the SQLITE_SUBTYPE flag */ }; #ifndef SQLITE_OMIT_WINDOWFUNC void sqlite3WindowDelete(sqlite3*, Window*); void sqlite3WindowUnlinkFromSelect(Window*); void sqlite3WindowListDelete(sqlite3 *db, Window *p); Window *sqlite3WindowAlloc(Parse*, int, int, Expr*, int , Expr*, u8); void sqlite3WindowAttach(Parse*, Expr*, Window*); void sqlite3WindowLink(Select *pSel, Window *pWin); int sqlite3WindowCompare(const Parse*, const Window*, const Window*, int); void sqlite3WindowCodeInit(Parse*, Select*); void sqlite3WindowCodeStep(Parse*, Select*, WhereInfo*, int, int); int sqlite3WindowRewrite(Parse*, Select*); void sqlite3WindowUpdate(Parse*, Window*, Window*, FuncDef*); Window *sqlite3WindowDup(sqlite3 *db, Expr *pOwner, Window *p); Window *sqlite3WindowListDup(sqlite3 *db, Window *p); void sqlite3WindowFunctions(void); void sqlite3WindowChain(Parse*, Window*, Window*); Window *sqlite3WindowAssemble(Parse*, Window*, ExprList*, ExprList*, Token*); #else # define sqlite3WindowDelete(a,b) # define sqlite3WindowFunctions() # define sqlite3WindowAttach(a,b,c) #endif /* |
︙ | ︙ | |||
3604 3605 3606 3607 3608 3609 3610 | int sqlite3CantopenError(int); #define SQLITE_CORRUPT_BKPT sqlite3CorruptError(__LINE__) #define SQLITE_MISUSE_BKPT sqlite3MisuseError(__LINE__) #define SQLITE_CANTOPEN_BKPT sqlite3CantopenError(__LINE__) #ifdef SQLITE_DEBUG int sqlite3NomemError(int); int sqlite3IoerrnomemError(int); | < < > > > > > | 4210 4211 4212 4213 4214 4215 4216 4217 4218 4219 4220 4221 4222 4223 4224 4225 4226 4227 4228 4229 4230 4231 4232 4233 | int sqlite3CantopenError(int); #define SQLITE_CORRUPT_BKPT sqlite3CorruptError(__LINE__) #define SQLITE_MISUSE_BKPT sqlite3MisuseError(__LINE__) #define SQLITE_CANTOPEN_BKPT sqlite3CantopenError(__LINE__) #ifdef SQLITE_DEBUG int sqlite3NomemError(int); int sqlite3IoerrnomemError(int); # define SQLITE_NOMEM_BKPT sqlite3NomemError(__LINE__) # define SQLITE_IOERR_NOMEM_BKPT sqlite3IoerrnomemError(__LINE__) #else # define SQLITE_NOMEM_BKPT SQLITE_NOMEM # define SQLITE_IOERR_NOMEM_BKPT SQLITE_IOERR_NOMEM #endif #if defined(SQLITE_DEBUG) || defined(SQLITE_ENABLE_CORRUPT_PGNO) int sqlite3CorruptPgnoError(int,Pgno); # define SQLITE_CORRUPT_PGNO(P) sqlite3CorruptPgnoError(__LINE__,(P)) #else # define SQLITE_CORRUPT_PGNO(P) sqlite3CorruptError(__LINE__) #endif /* ** FTS3 and FTS4 both require virtual table support */ #if defined(SQLITE_OMIT_VIRTUALTABLE) |
︙ | ︙ | |||
3690 3691 3692 3693 3694 3695 3696 | char *sqlite3DbStrNDup(sqlite3*,const char*, u64); char *sqlite3DbSpanDup(sqlite3*,const char*,const char*); void *sqlite3Realloc(void*, u64); void *sqlite3DbReallocOrFree(sqlite3 *, void *, u64); void *sqlite3DbRealloc(sqlite3 *, void *, u64); void sqlite3DbFree(sqlite3*, void*); void sqlite3DbFreeNN(sqlite3*, void*); | | | | 4299 4300 4301 4302 4303 4304 4305 4306 4307 4308 4309 4310 4311 4312 4313 4314 | char *sqlite3DbStrNDup(sqlite3*,const char*, u64); char *sqlite3DbSpanDup(sqlite3*,const char*,const char*); void *sqlite3Realloc(void*, u64); void *sqlite3DbReallocOrFree(sqlite3 *, void *, u64); void *sqlite3DbRealloc(sqlite3 *, void *, u64); void sqlite3DbFree(sqlite3*, void*); void sqlite3DbFreeNN(sqlite3*, void*); int sqlite3MallocSize(const void*); int sqlite3DbMallocSize(sqlite3*, const void*); void *sqlite3PageMalloc(int); void sqlite3PageFree(void*); void sqlite3MemSetDefault(void); #ifndef SQLITE_UNTESTABLE void sqlite3BenignMallocHooks(void (*)(void), void (*)(void)); #endif int sqlite3HeapNearlyFull(void); |
︙ | ︙ | |||
3760 3761 3762 3763 3764 3765 3766 3767 3768 3769 3770 3771 3772 3773 3774 3775 | #if defined(SQLITE_ENABLE_MULTITHREADED_CHECKS) && !defined(SQLITE_MUTEX_OMIT) void sqlite3MutexWarnOnContention(sqlite3_mutex*); #else # define sqlite3MutexWarnOnContention(x) #endif #ifndef SQLITE_OMIT_FLOATING_POINT int sqlite3IsNaN(double); #else # define sqlite3IsNaN(X) 0 #endif /* ** An instance of the following structure holds information about SQL ** functions arguments that are the parameters to the printf() function. */ | > > > > | 4369 4370 4371 4372 4373 4374 4375 4376 4377 4378 4379 4380 4381 4382 4383 4384 4385 4386 4387 4388 | #if defined(SQLITE_ENABLE_MULTITHREADED_CHECKS) && !defined(SQLITE_MUTEX_OMIT) void sqlite3MutexWarnOnContention(sqlite3_mutex*); #else # define sqlite3MutexWarnOnContention(x) #endif #ifndef SQLITE_OMIT_FLOATING_POINT # define EXP754 (((u64)0x7ff)<<52) # define MAN754 ((((u64)1)<<52)-1) # define IsNaN(X) (((X)&EXP754)==EXP754 && ((X)&MAN754)!=0) int sqlite3IsNaN(double); #else # define IsNaN(X) 0 # define sqlite3IsNaN(X) 0 #endif /* ** An instance of the following structure holds information about SQL ** functions arguments that are the parameters to the printf() function. */ |
︙ | ︙ | |||
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 | void sqlite3TreeViewWinFunc(TreeView*, const Window*, u8); #endif #endif void sqlite3SetString(char **, sqlite3*, const char*); void sqlite3ErrorMsg(Parse*, const char*, ...); void sqlite3Dequote(char*); void sqlite3TokenInit(Token*,char*); int sqlite3KeywordCode(const unsigned char*, int); int sqlite3RunParser(Parse*, const char*, char **); void sqlite3FinishCoding(Parse*); int sqlite3GetTempReg(Parse*); void sqlite3ReleaseTempReg(Parse*,int); int sqlite3GetTempRange(Parse*,int); void sqlite3ReleaseTempRange(Parse*,int,int); void sqlite3ClearTempRegCache(Parse*); #ifdef SQLITE_DEBUG int sqlite3NoTempsInRange(Parse*,int,int); #endif Expr *sqlite3ExprAlloc(sqlite3*,int,const Token*,int); Expr *sqlite3Expr(sqlite3*,int,const char*); void sqlite3ExprAttachSubtrees(sqlite3*,Expr*,Expr*,Expr*); Expr *sqlite3PExpr(Parse*, int, Expr*, Expr*); void sqlite3PExprAddSelect(Parse*, Expr*, Select*); | > > > | > | > > > > | | > > > > > > | | | | > > > > > > > | | > | > > | 4413 4414 4415 4416 4417 4418 4419 4420 4421 4422 4423 4424 4425 4426 4427 4428 4429 4430 4431 4432 4433 4434 4435 4436 4437 4438 4439 4440 4441 4442 4443 4444 4445 4446 4447 4448 4449 4450 4451 4452 4453 4454 4455 4456 4457 4458 4459 4460 4461 4462 4463 4464 4465 4466 4467 4468 4469 4470 4471 4472 4473 4474 4475 4476 4477 4478 4479 4480 4481 4482 4483 4484 4485 4486 4487 4488 4489 4490 4491 4492 4493 4494 4495 4496 4497 4498 4499 4500 4501 4502 4503 4504 4505 4506 4507 4508 4509 4510 4511 4512 | void sqlite3TreeViewWinFunc(TreeView*, const Window*, u8); #endif #endif void sqlite3SetString(char **, sqlite3*, const char*); void sqlite3ErrorMsg(Parse*, const char*, ...); int sqlite3ErrorToParser(sqlite3*,int); void sqlite3Dequote(char*); void sqlite3DequoteExpr(Expr*); void sqlite3DequoteToken(Token*); void sqlite3TokenInit(Token*,char*); int sqlite3KeywordCode(const unsigned char*, int); int sqlite3RunParser(Parse*, const char*, char **); void sqlite3FinishCoding(Parse*); int sqlite3GetTempReg(Parse*); void sqlite3ReleaseTempReg(Parse*,int); int sqlite3GetTempRange(Parse*,int); void sqlite3ReleaseTempRange(Parse*,int,int); void sqlite3ClearTempRegCache(Parse*); #ifdef SQLITE_DEBUG int sqlite3NoTempsInRange(Parse*,int,int); #endif Expr *sqlite3ExprAlloc(sqlite3*,int,const Token*,int); Expr *sqlite3Expr(sqlite3*,int,const char*); void sqlite3ExprAttachSubtrees(sqlite3*,Expr*,Expr*,Expr*); Expr *sqlite3PExpr(Parse*, int, Expr*, Expr*); void sqlite3PExprAddSelect(Parse*, Expr*, Select*); Expr *sqlite3ExprAnd(Parse*,Expr*, Expr*); Expr *sqlite3ExprSimplifiedAndOr(Expr*); Expr *sqlite3ExprFunction(Parse*,ExprList*, const Token*, int); void sqlite3ExprFunctionUsable(Parse*,const Expr*,const FuncDef*); void sqlite3ExprAssignVarNumber(Parse*, Expr*, u32); void sqlite3ExprDelete(sqlite3*, Expr*); void sqlite3ExprDeferredDelete(Parse*, Expr*); void sqlite3ExprUnmapAndDelete(Parse*, Expr*); ExprList *sqlite3ExprListAppend(Parse*,ExprList*,Expr*); ExprList *sqlite3ExprListAppendVector(Parse*,ExprList*,IdList*,Expr*); Select *sqlite3ExprListToValues(Parse*, int, ExprList*); void sqlite3ExprListSetSortOrder(ExprList*,int,int); void sqlite3ExprListSetName(Parse*,ExprList*,const Token*,int); void sqlite3ExprListSetSpan(Parse*,ExprList*,const char*,const char*); void sqlite3ExprListDelete(sqlite3*, ExprList*); u32 sqlite3ExprListFlags(const ExprList*); int sqlite3IndexHasDuplicateRootPage(Index*); int sqlite3Init(sqlite3*, char**); int sqlite3InitCallback(void*, int, char**, char**); int sqlite3InitOne(sqlite3*, int, char**, u32); void sqlite3Pragma(Parse*,Token*,Token*,Token*,int); #ifndef SQLITE_OMIT_VIRTUALTABLE Module *sqlite3PragmaVtabRegister(sqlite3*,const char *zName); #endif void sqlite3ResetAllSchemasOfConnection(sqlite3*); void sqlite3ResetOneSchema(sqlite3*,int); void sqlite3CollapseDatabaseArray(sqlite3*); void sqlite3CommitInternalChanges(sqlite3*); void sqlite3ColumnSetExpr(Parse*,Table*,Column*,Expr*); Expr *sqlite3ColumnExpr(Table*,Column*); void sqlite3ColumnSetColl(sqlite3*,Column*,const char*zColl); const char *sqlite3ColumnColl(Column*); void sqlite3DeleteColumnNames(sqlite3*,Table*); void sqlite3GenerateColumnNames(Parse *pParse, Select *pSelect); int sqlite3ColumnsFromExprList(Parse*,ExprList*,i16*,Column**); void sqlite3SelectAddColumnTypeAndCollation(Parse*,Table*,Select*,char); Table *sqlite3ResultSetOfSelect(Parse*,Select*,char); void sqlite3OpenSchemaTable(Parse *, int); Index *sqlite3PrimaryKeyIndex(Table*); i16 sqlite3TableColumnToIndex(Index*, i16); #ifdef SQLITE_OMIT_GENERATED_COLUMNS # define sqlite3TableColumnToStorage(T,X) (X) /* No-op pass-through */ # define sqlite3StorageColumnToTable(T,X) (X) /* No-op pass-through */ #else i16 sqlite3TableColumnToStorage(Table*, i16); i16 sqlite3StorageColumnToTable(Table*, i16); #endif void sqlite3StartTable(Parse*,Token*,Token*,int,int,int,int); #if SQLITE_ENABLE_HIDDEN_COLUMNS void sqlite3ColumnPropertiesFromName(Table*, Column*); #else # define sqlite3ColumnPropertiesFromName(T,C) /* no-op */ #endif void sqlite3AddColumn(Parse*,Token,Token); void sqlite3AddNotNull(Parse*, int); void sqlite3AddPrimaryKey(Parse*, ExprList*, int, int, int); void sqlite3AddCheckConstraint(Parse*, Expr*, const char*, const char*); void sqlite3AddDefaultValue(Parse*,Expr*,const char*,const char*); void sqlite3AddCollateType(Parse*, Token*); void sqlite3AddGenerated(Parse*,Expr*,Token*); void sqlite3EndTable(Parse*,Token*,Token*,u32,Select*); void sqlite3AddReturning(Parse*,ExprList*); int sqlite3ParseUri(const char*,const char*,unsigned int*, sqlite3_vfs**,char**,char **); #define sqlite3CodecQueryParameters(A,B,C) 0 Btree *sqlite3DbNameToBtree(sqlite3*,const char*); #ifdef SQLITE_UNTESTABLE # define sqlite3FaultSim(X) SQLITE_OK #else int sqlite3FaultSim(int); #endif |
︙ | ︙ | |||
3911 3912 3913 3914 3915 3916 3917 3918 3919 3920 | void sqlite3AutoincrementBegin(Parse *pParse); void sqlite3AutoincrementEnd(Parse *pParse); #else # define sqlite3AutoincrementBegin(X) # define sqlite3AutoincrementEnd(X) #endif void sqlite3Insert(Parse*, SrcList*, Select*, IdList*, int, Upsert*); void *sqlite3ArrayAllocate(sqlite3*,void*,int,int*,int*); IdList *sqlite3IdListAppend(Parse*, IdList*, Token*); int sqlite3IdListIndex(IdList*,const char*); | > > > | > | | | 4548 4549 4550 4551 4552 4553 4554 4555 4556 4557 4558 4559 4560 4561 4562 4563 4564 4565 4566 4567 4568 4569 4570 4571 4572 4573 4574 4575 | void sqlite3AutoincrementBegin(Parse *pParse); void sqlite3AutoincrementEnd(Parse *pParse); #else # define sqlite3AutoincrementBegin(X) # define sqlite3AutoincrementEnd(X) #endif void sqlite3Insert(Parse*, SrcList*, Select*, IdList*, int, Upsert*); #ifndef SQLITE_OMIT_GENERATED_COLUMNS void sqlite3ComputeGeneratedColumns(Parse*, int, Table*); #endif void *sqlite3ArrayAllocate(sqlite3*,void*,int,int*,int*); IdList *sqlite3IdListAppend(Parse*, IdList*, Token*); int sqlite3IdListIndex(IdList*,const char*); SrcList *sqlite3SrcListEnlarge(Parse*, SrcList*, int, int); SrcList *sqlite3SrcListAppendList(Parse *pParse, SrcList *p1, SrcList *p2); SrcList *sqlite3SrcListAppend(Parse*, SrcList*, Token*, Token*); SrcList *sqlite3SrcListAppendFromTerm(Parse*, SrcList*, Token*, Token*, Token*, Select*, Expr*, IdList*); void sqlite3SrcListIndexedBy(Parse *, SrcList *, Token *); void sqlite3SrcListFuncArgs(Parse*, SrcList*, ExprList*); int sqlite3IndexedByLookup(Parse *, SrcItem *); void sqlite3SrcListShiftJoinType(SrcList*); void sqlite3SrcListAssignCursors(Parse*, SrcList*); void sqlite3IdListDelete(sqlite3*, IdList*); void sqlite3SrcListDelete(sqlite3*, SrcList*); Index *sqlite3AllocateIndexObject(sqlite3*,i16,int,char**); void sqlite3CreateIndex(Parse*,Token*,Token*,SrcList*,ExprList*,int,Token*, Expr*, int, int, u8); |
︙ | ︙ | |||
3948 3949 3950 3951 3952 3953 3954 3955 3956 3957 3958 3959 3960 3961 3962 3963 3964 3965 3966 3967 3968 | Upsert*); WhereInfo *sqlite3WhereBegin(Parse*,SrcList*,Expr*,ExprList*,ExprList*,u16,int); void sqlite3WhereEnd(WhereInfo*); LogEst sqlite3WhereOutputRowCount(WhereInfo*); int sqlite3WhereIsDistinct(WhereInfo*); int sqlite3WhereIsOrdered(WhereInfo*); int sqlite3WhereOrderByLimitOptLabel(WhereInfo*); int sqlite3WhereIsSorted(WhereInfo*); int sqlite3WhereContinueLabel(WhereInfo*); int sqlite3WhereBreakLabel(WhereInfo*); int sqlite3WhereOkOnePass(WhereInfo*, int*); #define ONEPASS_OFF 0 /* Use of ONEPASS not allowed */ #define ONEPASS_SINGLE 1 /* ONEPASS valid for a single row update */ #define ONEPASS_MULTI 2 /* ONEPASS is valid for multiple rows */ void sqlite3ExprCodeLoadIndexColumn(Parse*, Index*, int, int, int); int sqlite3ExprCodeGetColumn(Parse*, Table*, int, int, int, u8); void sqlite3ExprCodeGetColumnOfTable(Vdbe*, Table*, int, int, int); void sqlite3ExprCodeMove(Parse*, int, int, int); void sqlite3ExprCode(Parse*, Expr*, int); void sqlite3ExprCodeCopy(Parse*, Expr*, int); void sqlite3ExprCodeFactorable(Parse*, Expr*, int); | > > > > > | < > | | | | | | > | > > > | | 4589 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 | Upsert*); WhereInfo *sqlite3WhereBegin(Parse*,SrcList*,Expr*,ExprList*,ExprList*,u16,int); void sqlite3WhereEnd(WhereInfo*); LogEst sqlite3WhereOutputRowCount(WhereInfo*); int sqlite3WhereIsDistinct(WhereInfo*); int sqlite3WhereIsOrdered(WhereInfo*); int sqlite3WhereOrderByLimitOptLabel(WhereInfo*); void sqlite3WhereMinMaxOptEarlyOut(Vdbe*,WhereInfo*); int sqlite3WhereIsSorted(WhereInfo*); int sqlite3WhereContinueLabel(WhereInfo*); int sqlite3WhereBreakLabel(WhereInfo*); int sqlite3WhereOkOnePass(WhereInfo*, int*); #define ONEPASS_OFF 0 /* Use of ONEPASS not allowed */ #define ONEPASS_SINGLE 1 /* ONEPASS valid for a single row update */ #define ONEPASS_MULTI 2 /* ONEPASS is valid for multiple rows */ int sqlite3WhereUsesDeferredSeek(WhereInfo*); void sqlite3ExprCodeLoadIndexColumn(Parse*, Index*, int, int, int); int sqlite3ExprCodeGetColumn(Parse*, Table*, int, int, int, u8); void sqlite3ExprCodeGetColumnOfTable(Vdbe*, Table*, int, int, int); void sqlite3ExprCodeMove(Parse*, int, int, int); void sqlite3ExprCode(Parse*, Expr*, int); #ifndef SQLITE_OMIT_GENERATED_COLUMNS void sqlite3ExprCodeGeneratedColumn(Parse*, Table*, Column*, int); #endif void sqlite3ExprCodeCopy(Parse*, Expr*, int); void sqlite3ExprCodeFactorable(Parse*, Expr*, int); int sqlite3ExprCodeRunJustOnce(Parse*, Expr*, int); int sqlite3ExprCodeTemp(Parse*, Expr*, int*); int sqlite3ExprCodeTarget(Parse*, Expr*, int); int sqlite3ExprCodeExprList(Parse*, ExprList*, int, int, u8); #define SQLITE_ECEL_DUP 0x01 /* Deep, not shallow copies */ #define SQLITE_ECEL_FACTOR 0x02 /* Factor out constant terms */ #define SQLITE_ECEL_REF 0x04 /* Use ExprList.u.x.iOrderByCol */ #define SQLITE_ECEL_OMITREF 0x08 /* Omit if ExprList.u.x.iOrderByCol */ void sqlite3ExprIfTrue(Parse*, Expr*, int, int); void sqlite3ExprIfFalse(Parse*, Expr*, int, int); void sqlite3ExprIfFalseDup(Parse*, Expr*, int, int); Table *sqlite3FindTable(sqlite3*,const char*, const char*); #define LOCATE_VIEW 0x01 #define LOCATE_NOERR 0x02 Table *sqlite3LocateTable(Parse*,u32 flags,const char*, const char*); const char *sqlite3PreferredTableName(const char*); Table *sqlite3LocateTableItem(Parse*,u32 flags,SrcItem *); Index *sqlite3FindIndex(sqlite3*,const char*, const char*); void sqlite3UnlinkAndDeleteTable(sqlite3*,int,const char*); void sqlite3UnlinkAndDeleteIndex(sqlite3*,int,const char*); void sqlite3Vacuum(Parse*,Token*,Expr*); int sqlite3RunVacuum(char**, sqlite3*, int, sqlite3_value*); char *sqlite3NameFromToken(sqlite3*, const Token*); int sqlite3ExprCompare(const Parse*,const Expr*,const Expr*, int); int sqlite3ExprCompareSkip(Expr*,Expr*,int); int sqlite3ExprListCompare(const ExprList*,const ExprList*, int); int sqlite3ExprImpliesExpr(const Parse*,const Expr*,const Expr*, int); int sqlite3ExprImpliesNonNullRow(Expr*,int); void sqlite3AggInfoPersistWalkerInit(Walker*,Parse*); void sqlite3ExprAnalyzeAggregates(NameContext*, Expr*); void sqlite3ExprAnalyzeAggList(NameContext*,ExprList*); int sqlite3ExprCoveredByIndex(Expr*, int iCur, Index *pIdx); int sqlite3ReferencesSrcList(Parse*, Expr*, SrcList*); Vdbe *sqlite3GetVdbe(Parse*); #ifndef SQLITE_UNTESTABLE void sqlite3PrngSaveState(void); void sqlite3PrngRestoreState(void); #endif void sqlite3FastPrngInit(FastPrng*); void sqlite3FastRandomness(FastPrng*, int N, void *P); void sqlite3RollbackAll(sqlite3*,int); void sqlite3CodeVerifySchema(Parse*, int); void sqlite3CodeVerifyNamedSchema(Parse*, const char *zDb); void sqlite3BeginTransaction(Parse*, int); void sqlite3EndTransaction(Parse*,int); void sqlite3Savepoint(Parse*, int, Token*); void sqlite3CloseSavepoints(sqlite3 *); void sqlite3LeaveMutexAndCloseZombie(sqlite3*); u32 sqlite3IsTrueOrFalse(const char*); int sqlite3ExprIdToTrueFalse(Expr*); int sqlite3ExprTruthValue(const Expr*); int sqlite3ExprIsConstant(Expr*); int sqlite3ExprIsConstantNotJoin(Expr*); int sqlite3ExprIsConstantOrFunction(Expr*, u8); int sqlite3ExprIsConstantOrGroupBy(Parse*, Expr*, ExprList*); int sqlite3ExprIsTableConstant(Expr*,int); #ifdef SQLITE_ENABLE_CURSOR_HINTS int sqlite3ExprContainsSubquery(Expr*); #endif int sqlite3ExprIsInteger(const Expr*, int*); int sqlite3ExprCanBeNull(const Expr*); int sqlite3ExprNeedsNoAffinityChange(const Expr*, char); int sqlite3IsRowid(const char*); void sqlite3GenerateRowDelete( Parse*,Table*,Trigger*,int,int,int,i16,u8,u8,u8,int); void sqlite3GenerateRowIndexDelete(Parse*, Table*, int, int, int*, int); int sqlite3GenerateIndexKey(Parse*, Index*, int, int, int, int*,Index*,int); |
︙ | ︙ | |||
4042 4043 4044 4045 4046 4047 4048 | int sqlite3OpenTableAndIndices(Parse*, Table*, int, u8, int, u8*, int*, int*); void sqlite3BeginWriteOperation(Parse*, int, int); void sqlite3MultiWrite(Parse*); void sqlite3MayAbort(Parse*); void sqlite3HaltConstraint(Parse*, int, int, char*, i8, u8); void sqlite3UniqueConstraint(Parse*, int, Index*); void sqlite3RowidConstraint(Parse*, int, Table*); | | | | | | > | 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 | int sqlite3OpenTableAndIndices(Parse*, Table*, int, u8, int, u8*, int*, int*); void sqlite3BeginWriteOperation(Parse*, int, int); void sqlite3MultiWrite(Parse*); void sqlite3MayAbort(Parse*); void sqlite3HaltConstraint(Parse*, int, int, char*, i8, u8); void sqlite3UniqueConstraint(Parse*, int, Index*); void sqlite3RowidConstraint(Parse*, int, Table*); Expr *sqlite3ExprDup(sqlite3*,const Expr*,int); ExprList *sqlite3ExprListDup(sqlite3*,const ExprList*,int); SrcList *sqlite3SrcListDup(sqlite3*,const SrcList*,int); IdList *sqlite3IdListDup(sqlite3*,const IdList*); Select *sqlite3SelectDup(sqlite3*,const Select*,int); FuncDef *sqlite3FunctionSearch(int,const char*); void sqlite3InsertBuiltinFuncs(FuncDef*,int); FuncDef *sqlite3FindFunction(sqlite3*,const char*,int,u8,u8); void sqlite3RegisterBuiltinFunctions(void); void sqlite3RegisterDateTimeFunctions(void); void sqlite3RegisterPerConnectionBuiltinFunctions(sqlite3*); int sqlite3SafetyCheckOk(sqlite3*); int sqlite3SafetyCheckSickOrOk(sqlite3*); void sqlite3ChangeCookie(Parse*, int); With *sqlite3WithDup(sqlite3 *db, With *p); #if !defined(SQLITE_OMIT_VIEW) && !defined(SQLITE_OMIT_TRIGGER) void sqlite3MaterializeView(Parse*, Table*, Expr*, ExprList*,Expr*,int); #endif #ifndef SQLITE_OMIT_TRIGGER void sqlite3BeginTrigger(Parse*, Token*,Token*,int,int,IdList*,SrcList*, |
︙ | ︙ | |||
4079 4080 4081 4082 4083 4084 4085 | void sqliteViewTriggers(Parse*, Table*, Expr*, int, ExprList*); void sqlite3DeleteTriggerStep(sqlite3*, TriggerStep*); TriggerStep *sqlite3TriggerSelectStep(sqlite3*,Select*, const char*,const char*); TriggerStep *sqlite3TriggerInsertStep(Parse*,Token*, IdList*, Select*,u8,Upsert*, const char*,const char*); | | | > > > > > < > > > | | 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 | void sqliteViewTriggers(Parse*, Table*, Expr*, int, ExprList*); void sqlite3DeleteTriggerStep(sqlite3*, TriggerStep*); TriggerStep *sqlite3TriggerSelectStep(sqlite3*,Select*, const char*,const char*); TriggerStep *sqlite3TriggerInsertStep(Parse*,Token*, IdList*, Select*,u8,Upsert*, const char*,const char*); TriggerStep *sqlite3TriggerUpdateStep(Parse*,Token*,SrcList*,ExprList*, Expr*, u8, const char*,const char*); TriggerStep *sqlite3TriggerDeleteStep(Parse*,Token*, Expr*, const char*,const char*); void sqlite3DeleteTrigger(sqlite3*, Trigger*); void sqlite3UnlinkAndDeleteTrigger(sqlite3*,int,const char*); u32 sqlite3TriggerColmask(Parse*,Trigger*,ExprList*,int,int,Table*,int); SrcList *sqlite3TriggerStepSrc(Parse*, TriggerStep*); # define sqlite3ParseToplevel(p) ((p)->pToplevel ? (p)->pToplevel : (p)) # define sqlite3IsToplevel(p) ((p)->pToplevel==0) #else # define sqlite3TriggersExist(B,C,D,E,F) 0 # define sqlite3DeleteTrigger(A,B) # define sqlite3DropTriggerPtr(A,B) # define sqlite3UnlinkAndDeleteTrigger(A,B,C) # define sqlite3CodeRowTrigger(A,B,C,D,E,F,G,H,I) # define sqlite3CodeRowTriggerDirect(A,B,C,D,E,F) # define sqlite3TriggerList(X, Y) 0 # define sqlite3ParseToplevel(p) p # define sqlite3IsToplevel(p) 1 # define sqlite3TriggerColmask(A,B,C,D,E,F,G) 0 # define sqlite3TriggerStepSrc(A,B) 0 #endif int sqlite3JoinType(Parse*, Token*, Token*, Token*); int sqlite3ColumnIndex(Table *pTab, const char *zCol); void sqlite3SetJoinExpr(Expr*,int); void sqlite3CreateForeignKey(Parse*, ExprList*, Token*, ExprList*, int); void sqlite3DeferForeignKey(Parse*, int); #ifndef SQLITE_OMIT_AUTHORIZATION void sqlite3AuthRead(Parse*,Expr*,Schema*,SrcList*); int sqlite3AuthCheck(Parse*,int, const char*, const char*, const char*); void sqlite3AuthContextPush(Parse*, AuthContext*, const char*); void sqlite3AuthContextPop(AuthContext*); int sqlite3AuthReadCol(Parse*, const char *, const char *, int); #else # define sqlite3AuthRead(a,b,c,d) # define sqlite3AuthCheck(a,b,c,d,e) SQLITE_OK # define sqlite3AuthContextPush(a,b,c) # define sqlite3AuthContextPop(a) ((void)(a)) #endif int sqlite3DbIsNamed(sqlite3 *db, int iDb, const char *zName); void sqlite3Attach(Parse*, Expr*, Expr*, Expr*); void sqlite3Detach(Parse*, Expr*); void sqlite3FixInit(DbFixer*, Parse*, int, const char*, const Token*); int sqlite3FixSrcList(DbFixer*, SrcList*); int sqlite3FixSelect(DbFixer*, Select*); int sqlite3FixExpr(DbFixer*, Expr*); int sqlite3FixTriggerStep(DbFixer*, TriggerStep*); int sqlite3RealSameAsInt(double,sqlite3_int64); void sqlite3Int64ToText(i64,char*); int sqlite3AtoF(const char *z, double*, int, u8); int sqlite3GetInt32(const char *, int*); int sqlite3GetUInt32(const char*, u32*); int sqlite3Atoi(const char*); #ifndef SQLITE_OMIT_UTF16 int sqlite3Utf16ByteLen(const void *pData, int nChar); #endif int sqlite3Utf8CharLen(const char *pData, int nByte); u32 sqlite3Utf8Read(const u8**); LogEst sqlite3LogEst(u64); LogEst sqlite3LogEstAdd(LogEst,LogEst); #ifndef SQLITE_OMIT_VIRTUALTABLE LogEst sqlite3LogEstFromDouble(double); #endif #if defined(SQLITE_ENABLE_STMT_SCANSTATUS) || \ defined(SQLITE_ENABLE_STAT4) || \ defined(SQLITE_EXPLAIN_ESTIMATED_ROWS) u64 sqlite3LogEstToInt(LogEst); #endif VList *sqlite3VListAdd(sqlite3*,VList*,const char*,int,int); const char *sqlite3VListNumToName(VList*,int); int sqlite3VListNameToNum(VList*,const char*,int); |
︙ | ︙ | |||
4163 4164 4165 4166 4167 4168 4169 4170 4171 4172 4173 4174 4175 4176 4177 4178 | /* ** The common case is for a varint to be a single byte. They following ** macros handle the common case without a procedure call, but then call ** the procedure for larger varints. */ #define getVarint32(A,B) \ (u8)((*(A)<(u8)0x80)?((B)=(u32)*(A)),1:sqlite3GetVarint32((A),(u32 *)&(B))) #define putVarint32(A,B) \ (u8)(((u32)(B)<(u32)0x80)?(*(A)=(unsigned char)(B)),1:\ sqlite3PutVarint((A),(B))) #define getVarint sqlite3GetVarint #define putVarint sqlite3PutVarint const char *sqlite3IndexAffinityStr(sqlite3*, Index*); void sqlite3TableAffinity(Vdbe*, Table*, int); | > > | | | | > | > | | | | | > | | > > > | > > > > | | > > | | > | > | > > > > > > > | > | | | > > > > | < | 4821 4822 4823 4824 4825 4826 4827 4828 4829 4830 4831 4832 4833 4834 4835 4836 4837 4838 4839 4840 4841 4842 4843 4844 4845 4846 4847 4848 4849 4850 4851 4852 4853 4854 4855 4856 4857 4858 4859 4860 4861 4862 4863 4864 4865 4866 4867 4868 4869 4870 4871 4872 4873 4874 4875 4876 4877 4878 4879 4880 4881 4882 4883 4884 4885 4886 4887 4888 4889 4890 4891 4892 4893 4894 4895 4896 4897 4898 4899 4900 4901 4902 4903 4904 4905 4906 4907 4908 4909 4910 4911 4912 4913 4914 4915 4916 4917 4918 4919 4920 4921 4922 4923 4924 4925 4926 4927 4928 4929 4930 4931 4932 4933 4934 4935 4936 4937 4938 4939 4940 4941 4942 4943 4944 4945 4946 4947 4948 4949 4950 4951 4952 4953 4954 4955 4956 4957 4958 4959 4960 4961 4962 4963 4964 4965 4966 4967 4968 4969 4970 4971 4972 4973 4974 4975 4976 4977 4978 4979 4980 4981 4982 4983 4984 4985 4986 4987 4988 4989 4990 4991 4992 4993 4994 4995 4996 4997 4998 4999 5000 5001 5002 5003 5004 5005 5006 5007 5008 5009 5010 5011 5012 5013 5014 5015 5016 5017 5018 5019 5020 5021 | /* ** The common case is for a varint to be a single byte. They following ** macros handle the common case without a procedure call, but then call ** the procedure for larger varints. */ #define getVarint32(A,B) \ (u8)((*(A)<(u8)0x80)?((B)=(u32)*(A)),1:sqlite3GetVarint32((A),(u32 *)&(B))) #define getVarint32NR(A,B) \ B=(u32)*(A);if(B>=0x80)sqlite3GetVarint32((A),(u32*)&(B)) #define putVarint32(A,B) \ (u8)(((u32)(B)<(u32)0x80)?(*(A)=(unsigned char)(B)),1:\ sqlite3PutVarint((A),(B))) #define getVarint sqlite3GetVarint #define putVarint sqlite3PutVarint const char *sqlite3IndexAffinityStr(sqlite3*, Index*); void sqlite3TableAffinity(Vdbe*, Table*, int); char sqlite3CompareAffinity(const Expr *pExpr, char aff2); int sqlite3IndexAffinityOk(const Expr *pExpr, char idx_affinity); char sqlite3TableColumnAffinity(const Table*,int); char sqlite3ExprAffinity(const Expr *pExpr); int sqlite3Atoi64(const char*, i64*, int, u8); int sqlite3DecOrHexToI64(const char*, i64*); void sqlite3ErrorWithMsg(sqlite3*, int, const char*,...); void sqlite3Error(sqlite3*,int); void sqlite3ErrorClear(sqlite3*); void sqlite3SystemError(sqlite3*,int); void *sqlite3HexToBlob(sqlite3*, const char *z, int n); u8 sqlite3HexToInt(int h); int sqlite3TwoPartName(Parse *, Token *, Token *, Token **); #if defined(SQLITE_NEED_ERR_NAME) const char *sqlite3ErrName(int); #endif #ifndef SQLITE_OMIT_DESERIALIZE int sqlite3MemdbInit(void); #endif const char *sqlite3ErrStr(int); int sqlite3ReadSchema(Parse *pParse); CollSeq *sqlite3FindCollSeq(sqlite3*,u8 enc, const char*,int); int sqlite3IsBinary(const CollSeq*); CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char*zName); void sqlite3SetTextEncoding(sqlite3 *db, u8); CollSeq *sqlite3ExprCollSeq(Parse *pParse, const Expr *pExpr); CollSeq *sqlite3ExprNNCollSeq(Parse *pParse, const Expr *pExpr); int sqlite3ExprCollSeqMatch(Parse*,const Expr*,const Expr*); Expr *sqlite3ExprAddCollateToken(const Parse *pParse, Expr*, const Token*, int); Expr *sqlite3ExprAddCollateString(const Parse*,Expr*,const char*); Expr *sqlite3ExprSkipCollate(Expr*); Expr *sqlite3ExprSkipCollateAndLikely(Expr*); int sqlite3CheckCollSeq(Parse *, CollSeq *); int sqlite3WritableSchema(sqlite3*); int sqlite3CheckObjectName(Parse*, const char*,const char*,const char*); void sqlite3VdbeSetChanges(sqlite3 *, i64); int sqlite3AddInt64(i64*,i64); int sqlite3SubInt64(i64*,i64); int sqlite3MulInt64(i64*,i64); int sqlite3AbsInt32(int); #ifdef SQLITE_ENABLE_8_3_NAMES void sqlite3FileSuffix3(const char*, char*); #else # define sqlite3FileSuffix3(X,Y) #endif u8 sqlite3GetBoolean(const char *z,u8); const void *sqlite3ValueText(sqlite3_value*, u8); int sqlite3ValueBytes(sqlite3_value*, u8); void sqlite3ValueSetStr(sqlite3_value*, int, const void *,u8, void(*)(void*)); void sqlite3ValueSetNull(sqlite3_value*); void sqlite3ValueFree(sqlite3_value*); #ifndef SQLITE_UNTESTABLE void sqlite3ResultIntReal(sqlite3_context*); #endif sqlite3_value *sqlite3ValueNew(sqlite3 *); #ifndef SQLITE_OMIT_UTF16 char *sqlite3Utf16to8(sqlite3 *, const void*, int, u8); #endif int sqlite3ValueFromExpr(sqlite3 *, const Expr *, u8, u8, sqlite3_value **); void sqlite3ValueApplyAffinity(sqlite3_value *, u8, u8); #ifndef SQLITE_AMALGAMATION extern const unsigned char sqlite3OpcodeProperty[]; extern const char sqlite3StrBINARY[]; extern const unsigned char sqlite3StdTypeLen[]; extern const char sqlite3StdTypeAffinity[]; extern const char sqlite3StdTypeMap[]; extern const char *sqlite3StdType[]; extern const unsigned char sqlite3UpperToLower[]; extern const unsigned char *sqlite3aLTb; extern const unsigned char *sqlite3aEQb; extern const unsigned char *sqlite3aGTb; extern const unsigned char sqlite3CtypeMap[]; extern SQLITE_WSD struct Sqlite3Config sqlite3Config; extern FuncDefHash sqlite3BuiltinFunctions; #ifndef SQLITE_OMIT_WSD extern int sqlite3PendingByte; #endif #endif /* SQLITE_AMALGAMATION */ #ifdef VDBE_PROFILE extern sqlite3_uint64 sqlite3NProfileCnt; #endif void sqlite3RootPageMoved(sqlite3*, int, Pgno, Pgno); void sqlite3Reindex(Parse*, Token*, Token*); void sqlite3AlterFunctions(void); void sqlite3AlterRenameTable(Parse*, SrcList*, Token*); void sqlite3AlterRenameColumn(Parse*, SrcList*, Token*, Token*); int sqlite3GetToken(const unsigned char *, int *); void sqlite3NestedParse(Parse*, const char*, ...); void sqlite3ExpirePreparedStatements(sqlite3*, int); void sqlite3CodeRhsOfIN(Parse*, Expr*, int); int sqlite3CodeSubselect(Parse*, Expr*); void sqlite3SelectPrep(Parse*, Select*, NameContext*); int sqlite3ExpandSubquery(Parse*, SrcItem*); void sqlite3SelectWrongNumTermsError(Parse *pParse, Select *p); int sqlite3MatchEName( const struct ExprList_item*, const char*, const char*, const char* ); Bitmask sqlite3ExprColUsed(Expr*); u8 sqlite3StrIHash(const char*); int sqlite3ResolveExprNames(NameContext*, Expr*); int sqlite3ResolveExprListNames(NameContext*, ExprList*); void sqlite3ResolveSelectNames(Parse*, Select*, NameContext*); int sqlite3ResolveSelfReference(Parse*,Table*,int,Expr*,ExprList*); int sqlite3ResolveOrderGroupBy(Parse*, Select*, ExprList*, const char*); void sqlite3ColumnDefault(Vdbe *, Table *, int, int); void sqlite3AlterFinishAddColumn(Parse *, Token *); void sqlite3AlterBeginAddColumn(Parse *, SrcList *); void sqlite3AlterDropColumn(Parse*, SrcList*, const Token*); const void *sqlite3RenameTokenMap(Parse*, const void*, const Token*); void sqlite3RenameTokenRemap(Parse*, const void *pTo, const void *pFrom); void sqlite3RenameExprUnmap(Parse*, Expr*); void sqlite3RenameExprlistUnmap(Parse*, ExprList*); CollSeq *sqlite3GetCollSeq(Parse*, u8, CollSeq *, const char*); char sqlite3AffinityType(const char*, Column*); void sqlite3Analyze(Parse*, Token*, Token*); int sqlite3InvokeBusyHandler(BusyHandler*); int sqlite3FindDb(sqlite3*, Token*); int sqlite3FindDbName(sqlite3 *, const char *); int sqlite3AnalysisLoad(sqlite3*,int iDB); void sqlite3DeleteIndexSamples(sqlite3*,Index*); void sqlite3DefaultRowEst(Index*); void sqlite3RegisterLikeFunctions(sqlite3*, int); int sqlite3IsLikeFunction(sqlite3*,Expr*,int*,char*); void sqlite3SchemaClear(void *); Schema *sqlite3SchemaGet(sqlite3 *, Btree *); int sqlite3SchemaToIndex(sqlite3 *db, Schema *); KeyInfo *sqlite3KeyInfoAlloc(sqlite3*,int,int); void sqlite3KeyInfoUnref(KeyInfo*); KeyInfo *sqlite3KeyInfoRef(KeyInfo*); KeyInfo *sqlite3KeyInfoOfIndex(Parse*, Index*); KeyInfo *sqlite3KeyInfoFromExprList(Parse*, ExprList*, int, int); const char *sqlite3SelectOpName(int); int sqlite3HasExplicitNulls(Parse*, ExprList*); #ifdef SQLITE_DEBUG int sqlite3KeyInfoIsWriteable(KeyInfo*); #endif int sqlite3CreateFunc(sqlite3 *, const char *, int, int, void *, void (*)(sqlite3_context*,int,sqlite3_value **), void (*)(sqlite3_context*,int,sqlite3_value **), void (*)(sqlite3_context*), void (*)(sqlite3_context*), void (*)(sqlite3_context*,int,sqlite3_value **), FuncDestructor *pDestructor ); void sqlite3NoopDestructor(void*); void sqlite3OomFault(sqlite3*); void sqlite3OomClear(sqlite3*); int sqlite3ApiExit(sqlite3 *db, int); int sqlite3OpenTempDatabase(Parse *); void sqlite3StrAccumInit(StrAccum*, sqlite3*, char*, int, int); char *sqlite3StrAccumFinish(StrAccum*); void sqlite3StrAccumSetError(StrAccum*, u8); void sqlite3ResultStrAccum(sqlite3_context*,StrAccum*); void sqlite3SelectDestInit(SelectDest*,int,int); Expr *sqlite3CreateColumnExpr(sqlite3 *, SrcList *, int, int); void sqlite3BackupRestart(sqlite3_backup *); void sqlite3BackupUpdate(sqlite3_backup *, Pgno, const u8 *); #ifndef SQLITE_OMIT_SUBQUERY int sqlite3ExprCheckIN(Parse*, Expr*); #else # define sqlite3ExprCheckIN(x,y) SQLITE_OK #endif #ifdef SQLITE_ENABLE_STAT4 int sqlite3Stat4ProbeSetValue( Parse*,Index*,UnpackedRecord**,Expr*,int,int,int*); int sqlite3Stat4ValueFromExpr(Parse*, Expr*, u8, sqlite3_value**); void sqlite3Stat4ProbeFree(UnpackedRecord*); int sqlite3Stat4Column(sqlite3*, const void*, int, int, sqlite3_value**); char sqlite3IndexColumnAffinity(sqlite3*, Index*, int); #endif |
︙ | ︙ | |||
4352 4353 4354 4355 4356 4357 4358 | #ifndef SQLITE_OMIT_LOAD_EXTENSION void sqlite3CloseExtensions(sqlite3*); #else # define sqlite3CloseExtensions(X) #endif #ifndef SQLITE_OMIT_SHARED_CACHE | | | > > > > > > > > > > > > > > | > > | | > | > | > | > > | | > > | 5037 5038 5039 5040 5041 5042 5043 5044 5045 5046 5047 5048 5049 5050 5051 5052 5053 5054 5055 5056 5057 5058 5059 5060 5061 5062 5063 5064 5065 5066 5067 5068 5069 5070 5071 5072 5073 5074 5075 5076 5077 5078 5079 5080 5081 5082 5083 5084 5085 5086 5087 5088 5089 5090 5091 5092 5093 5094 5095 5096 5097 5098 5099 5100 5101 5102 5103 5104 5105 5106 5107 5108 5109 5110 5111 5112 5113 5114 5115 5116 5117 5118 5119 5120 5121 5122 5123 5124 5125 5126 5127 5128 5129 5130 5131 5132 5133 5134 5135 5136 5137 5138 5139 5140 5141 5142 5143 5144 5145 5146 5147 5148 5149 5150 5151 5152 5153 5154 5155 5156 5157 5158 5159 5160 | #ifndef SQLITE_OMIT_LOAD_EXTENSION void sqlite3CloseExtensions(sqlite3*); #else # define sqlite3CloseExtensions(X) #endif #ifndef SQLITE_OMIT_SHARED_CACHE void sqlite3TableLock(Parse *, int, Pgno, u8, const char *); #else #define sqlite3TableLock(v,w,x,y,z) #endif #ifdef SQLITE_TEST int sqlite3Utf8To8(unsigned char*); #endif #ifdef SQLITE_OMIT_VIRTUALTABLE # define sqlite3VtabClear(D,T) # define sqlite3VtabSync(X,Y) SQLITE_OK # define sqlite3VtabRollback(X) # define sqlite3VtabCommit(X) # define sqlite3VtabInSync(db) 0 # define sqlite3VtabLock(X) # define sqlite3VtabUnlock(X) # define sqlite3VtabModuleUnref(D,X) # define sqlite3VtabUnlockList(X) # define sqlite3VtabSavepoint(X, Y, Z) SQLITE_OK # define sqlite3GetVTable(X,Y) ((VTable*)0) #else void sqlite3VtabClear(sqlite3 *db, Table*); void sqlite3VtabDisconnect(sqlite3 *db, Table *p); int sqlite3VtabSync(sqlite3 *db, Vdbe*); int sqlite3VtabRollback(sqlite3 *db); int sqlite3VtabCommit(sqlite3 *db); void sqlite3VtabLock(VTable *); void sqlite3VtabUnlock(VTable *); void sqlite3VtabModuleUnref(sqlite3*,Module*); void sqlite3VtabUnlockList(sqlite3*); int sqlite3VtabSavepoint(sqlite3 *, int, int); void sqlite3VtabImportErrmsg(Vdbe*, sqlite3_vtab*); VTable *sqlite3GetVTable(sqlite3*, Table*); Module *sqlite3VtabCreateModule( sqlite3*, const char*, const sqlite3_module*, void*, void(*)(void*) ); # define sqlite3VtabInSync(db) ((db)->nVTrans>0 && (db)->aVTrans==0) #endif int sqlite3ReadOnlyShadowTables(sqlite3 *db); #ifndef SQLITE_OMIT_VIRTUALTABLE int sqlite3ShadowTableName(sqlite3 *db, const char *zName); int sqlite3IsShadowTableOf(sqlite3*,Table*,const char*); void sqlite3MarkAllShadowTablesOf(sqlite3*, Table*); #else # define sqlite3ShadowTableName(A,B) 0 # define sqlite3IsShadowTableOf(A,B,C) 0 # define sqlite3MarkAllShadowTablesOf(A,B) #endif int sqlite3VtabEponymousTableInit(Parse*,Module*); void sqlite3VtabEponymousTableClear(sqlite3*,Module*); void sqlite3VtabMakeWritable(Parse*,Table*); void sqlite3VtabBeginParse(Parse*, Token*, Token*, Token*, int); void sqlite3VtabFinishParse(Parse*, Token*); void sqlite3VtabArgInit(Parse*); void sqlite3VtabArgExtend(Parse*, Token*); int sqlite3VtabCallCreate(sqlite3*, int, const char *, char **); int sqlite3VtabCallConnect(Parse*, Table*); int sqlite3VtabCallDestroy(sqlite3*, int, const char *); int sqlite3VtabBegin(sqlite3 *, VTable *); FuncDef *sqlite3VtabOverloadFunction(sqlite3 *,FuncDef*, int nArg, Expr*); sqlite3_int64 sqlite3StmtCurrentTime(sqlite3_context*); int sqlite3VdbeParameterIndex(Vdbe*, const char*, int); int sqlite3TransferBindings(sqlite3_stmt *, sqlite3_stmt *); void sqlite3ParserReset(Parse*); void *sqlite3ParserAddCleanup(Parse*,void(*)(sqlite3*,void*),void*); #ifdef SQLITE_ENABLE_NORMALIZE char *sqlite3Normalize(Vdbe*, const char*); #endif int sqlite3Reprepare(Vdbe*); void sqlite3ExprListCheckLength(Parse*, ExprList*, const char*); CollSeq *sqlite3ExprCompareCollSeq(Parse*,const Expr*); CollSeq *sqlite3BinaryCompareCollSeq(Parse *, const Expr*, const Expr*); int sqlite3TempInMemory(const sqlite3*); const char *sqlite3JournalModename(int); #ifndef SQLITE_OMIT_WAL int sqlite3Checkpoint(sqlite3*, int, int, int*, int*); int sqlite3WalDefaultHook(void*,sqlite3*,const char*,int); #endif #ifndef SQLITE_OMIT_CTE Cte *sqlite3CteNew(Parse*,Token*,ExprList*,Select*,u8); void sqlite3CteDelete(sqlite3*,Cte*); With *sqlite3WithAdd(Parse*,With*,Cte*); void sqlite3WithDelete(sqlite3*,With*); With *sqlite3WithPush(Parse*, With*, u8); #else # define sqlite3CteNew(P,T,E,S) ((void*)0) # define sqlite3CteDelete(D,C) # define sqlite3CteWithAdd(P,W,C) ((void*)0) # define sqlite3WithDelete(x,y) # define sqlite3WithPush(x,y,z) ((void*)0) #endif #ifndef SQLITE_OMIT_UPSERT Upsert *sqlite3UpsertNew(sqlite3*,ExprList*,Expr*,ExprList*,Expr*,Upsert*); void sqlite3UpsertDelete(sqlite3*,Upsert*); Upsert *sqlite3UpsertDup(sqlite3*,Upsert*); int sqlite3UpsertAnalyzeTarget(Parse*,SrcList*,Upsert*); void sqlite3UpsertDoUpdate(Parse*,Upsert*,Table*,Index*,int); Upsert *sqlite3UpsertOfIndex(Upsert*,Index*); int sqlite3UpsertNextIsIPK(Upsert*); #else #define sqlite3UpsertNew(u,v,w,x,y,z) ((Upsert*)0) #define sqlite3UpsertDelete(x,y) #define sqlite3UpsertDup(x,y) ((Upsert*)0) #define sqlite3UpsertOfIndex(x,y) ((Upsert*)0) #define sqlite3UpsertNextIsIPK(x) 0 #endif /* Declarations for functions in fkey.c. All of these are replaced by ** no-op macros if OMIT_FOREIGN_KEY is defined. In this case no foreign ** key functionality is available. If OMIT_TRIGGER is defined but ** OMIT_FOREIGN_KEY is not, only some of the functions are no-oped. In |
︙ | ︙ | |||
4506 4507 4508 4509 4510 4511 4512 | #define IN_INDEX_NOOP 5 /* No table available. Use comparisons */ /* ** Allowed flags for the 3rd parameter to sqlite3FindInIndex(). */ #define IN_INDEX_NOOP_OK 0x0001 /* OK to return IN_INDEX_NOOP */ #define IN_INDEX_MEMBERSHIP 0x0002 /* IN operator used for membership test */ #define IN_INDEX_LOOP 0x0004 /* IN operator used as a loop */ | | | | 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 | #define IN_INDEX_NOOP 5 /* No table available. Use comparisons */ /* ** Allowed flags for the 3rd parameter to sqlite3FindInIndex(). */ #define IN_INDEX_NOOP_OK 0x0001 /* OK to return IN_INDEX_NOOP */ #define IN_INDEX_MEMBERSHIP 0x0002 /* IN operator used for membership test */ #define IN_INDEX_LOOP 0x0004 /* IN operator used as a loop */ int sqlite3FindInIndex(Parse *, Expr *, u32, int*, int*, int*); int sqlite3JournalOpen(sqlite3_vfs *, const char *, sqlite3_file *, int, int); int sqlite3JournalSize(sqlite3_vfs *); #if defined(SQLITE_ENABLE_ATOMIC_WRITE) \ || defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE) int sqlite3JournalCreate(sqlite3_file *); #endif int sqlite3JournalIsInMemory(sqlite3_file *p); void sqlite3MemJournalOpen(sqlite3_file *); void sqlite3ExprSetHeightAndFlags(Parse *pParse, Expr *p); #if SQLITE_MAX_EXPR_DEPTH>0 int sqlite3SelectExprHeight(const Select *); int sqlite3ExprCheckHeight(Parse*, int); #else #define sqlite3SelectExprHeight(x) 0 #define sqlite3ExprCheckHeight(x,y) #endif u32 sqlite3Get4byte(const u8*); |
︙ | ︙ | |||
4591 4592 4593 4594 4595 4596 4597 | ** this constraint. ** ** All of this is no-op for a production build. It only comes into ** play when the SQLITE_MEMDEBUG compile-time option is used. */ #ifdef SQLITE_MEMDEBUG void sqlite3MemdebugSetType(void*,u8); | | | | 5299 5300 5301 5302 5303 5304 5305 5306 5307 5308 5309 5310 5311 5312 5313 5314 | ** this constraint. ** ** All of this is no-op for a production build. It only comes into ** play when the SQLITE_MEMDEBUG compile-time option is used. */ #ifdef SQLITE_MEMDEBUG void sqlite3MemdebugSetType(void*,u8); int sqlite3MemdebugHasType(const void*,u8); int sqlite3MemdebugNoType(const void*,u8); #else # define sqlite3MemdebugSetType(X,Y) /* no-op */ # define sqlite3MemdebugHasType(X,Y) 1 # define sqlite3MemdebugNoType(X,Y) 1 #endif #define MEMTYPE_HEAP 0x01 /* General heap allocations */ #define MEMTYPE_LOOKASIDE 0x02 /* Heap that might have been lookaside */ |
︙ | ︙ | |||
4617 4618 4619 4620 4621 4622 4623 | #if defined(SQLITE_ENABLE_DBPAGE_VTAB) || defined(SQLITE_TEST) int sqlite3DbpageRegister(sqlite3*); #endif #if defined(SQLITE_ENABLE_DBSTAT_VTAB) || defined(SQLITE_TEST) int sqlite3DbstatRegister(sqlite3*); #endif | | | | | 5325 5326 5327 5328 5329 5330 5331 5332 5333 5334 5335 5336 5337 5338 5339 5340 5341 5342 | #if defined(SQLITE_ENABLE_DBPAGE_VTAB) || defined(SQLITE_TEST) int sqlite3DbpageRegister(sqlite3*); #endif #if defined(SQLITE_ENABLE_DBSTAT_VTAB) || defined(SQLITE_TEST) int sqlite3DbstatRegister(sqlite3*); #endif int sqlite3ExprVectorSize(const Expr *pExpr); int sqlite3ExprIsVector(const Expr *pExpr); Expr *sqlite3VectorFieldSubexpr(Expr*, int); Expr *sqlite3ExprForVectorField(Parse*,Expr*,int,int); void sqlite3VectorErrorMsg(Parse*, Expr*); #ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS const char **sqlite3CompileOptions(int *pnOpt); #endif #endif /* SQLITEINT_H */ |
Changes to src/sqliteLimit.h.
︙ | ︙ | |||
56 57 58 59 60 61 62 | # define SQLITE_MAX_SQL_LENGTH 1000000000 #endif /* ** The maximum depth of an expression tree. This is limited to ** some extent by SQLITE_MAX_SQL_LENGTH. But sometime you might ** want to place more severe limits on the complexity of an | | < < < < | 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | # define SQLITE_MAX_SQL_LENGTH 1000000000 #endif /* ** The maximum depth of an expression tree. This is limited to ** some extent by SQLITE_MAX_SQL_LENGTH. But sometime you might ** want to place more severe limits on the complexity of an ** expression. A value of 0 means that there is no limit. */ #ifndef SQLITE_MAX_EXPR_DEPTH # define SQLITE_MAX_EXPR_DEPTH 1000 #endif /* ** The maximum number of terms in a compound SELECT statement. |
︙ | ︙ | |||
127 128 129 130 131 132 133 134 135 | #ifndef SQLITE_MAX_ATTACHED # define SQLITE_MAX_ATTACHED 10 #endif /* ** The maximum value of a ?nnn wildcard that the parser will accept. */ #ifndef SQLITE_MAX_VARIABLE_NUMBER | > > > | | 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 | #ifndef SQLITE_MAX_ATTACHED # define SQLITE_MAX_ATTACHED 10 #endif /* ** The maximum value of a ?nnn wildcard that the parser will accept. ** If the value exceeds 32767 then extra space is required for the Expr ** structure. But otherwise, we believe that the number can be as large ** as a signed 32-bit integer can hold. */ #ifndef SQLITE_MAX_VARIABLE_NUMBER # define SQLITE_MAX_VARIABLE_NUMBER 32766 #endif /* Maximum page size. The upper bound on this value is 65536. This a limit ** imposed by the use of 16-bit offsets within each page. ** ** Earlier versions of SQLite allowed the user to change this value at ** compile time. This is no longer permitted, on the grounds that it creates |
︙ | ︙ |
Changes to src/status.c.
︙ | ︙ | |||
184 185 186 187 188 189 190 191 192 193 194 195 196 197 | /* ** Count the number of slots of lookaside memory that are outstanding */ int sqlite3LookasideUsed(sqlite3 *db, int *pHighwater){ u32 nInit = countLookasideSlots(db->lookaside.pInit); u32 nFree = countLookasideSlots(db->lookaside.pFree); if( pHighwater ) *pHighwater = db->lookaside.nSlot - nInit; return db->lookaside.nSlot - (nInit+nFree); } /* ** Query status information for a single database connection */ | > > > > | 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 | /* ** Count the number of slots of lookaside memory that are outstanding */ int sqlite3LookasideUsed(sqlite3 *db, int *pHighwater){ u32 nInit = countLookasideSlots(db->lookaside.pInit); u32 nFree = countLookasideSlots(db->lookaside.pFree); #ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE nInit += countLookasideSlots(db->lookaside.pSmallInit); nFree += countLookasideSlots(db->lookaside.pSmallFree); #endif /* SQLITE_OMIT_TWOSIZE_LOOKASIDE */ if( pHighwater ) *pHighwater = db->lookaside.nSlot - nInit; return db->lookaside.nSlot - (nInit+nFree); } /* ** Query status information for a single database connection */ |
︙ | ︙ | |||
216 217 218 219 220 221 222 223 224 225 226 227 228 229 | LookasideSlot *p = db->lookaside.pFree; if( p ){ while( p->pNext ) p = p->pNext; p->pNext = db->lookaside.pInit; db->lookaside.pInit = db->lookaside.pFree; db->lookaside.pFree = 0; } } break; } case SQLITE_DBSTATUS_LOOKASIDE_HIT: case SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE: case SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL: { | > > > > > > > > > | 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 | LookasideSlot *p = db->lookaside.pFree; if( p ){ while( p->pNext ) p = p->pNext; p->pNext = db->lookaside.pInit; db->lookaside.pInit = db->lookaside.pFree; db->lookaside.pFree = 0; } #ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE p = db->lookaside.pSmallFree; if( p ){ while( p->pNext ) p = p->pNext; p->pNext = db->lookaside.pSmallInit; db->lookaside.pSmallInit = db->lookaside.pSmallFree; db->lookaside.pSmallFree = 0; } #endif } break; } case SQLITE_DBSTATUS_LOOKASIDE_HIT: case SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE: case SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL: { |
︙ | ︙ | |||
335 336 337 338 339 340 341 | /* ** Set *pCurrent to the total cache hits or misses encountered by all ** pagers the database handle is connected to. *pHighwater is always set ** to zero. */ case SQLITE_DBSTATUS_CACHE_SPILL: op = SQLITE_DBSTATUS_CACHE_WRITE+1; | | | 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 | /* ** Set *pCurrent to the total cache hits or misses encountered by all ** pagers the database handle is connected to. *pHighwater is always set ** to zero. */ case SQLITE_DBSTATUS_CACHE_SPILL: op = SQLITE_DBSTATUS_CACHE_WRITE+1; /* no break */ deliberate_fall_through case SQLITE_DBSTATUS_CACHE_HIT: case SQLITE_DBSTATUS_CACHE_MISS: case SQLITE_DBSTATUS_CACHE_WRITE:{ int i; int nRet = 0; assert( SQLITE_DBSTATUS_CACHE_MISS==SQLITE_DBSTATUS_CACHE_HIT+1 ); assert( SQLITE_DBSTATUS_CACHE_WRITE==SQLITE_DBSTATUS_CACHE_HIT+2 ); |
︙ | ︙ |
Changes to src/table.c.
︙ | ︙ | |||
52 53 54 55 56 57 58 | need = nCol*2; }else{ need = nCol; } if( p->nData + need > p->nAlloc ){ char **azNew; p->nAlloc = p->nAlloc*2 + need; | | | 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | need = nCol*2; }else{ need = nCol; } if( p->nData + need > p->nAlloc ){ char **azNew; p->nAlloc = p->nAlloc*2 + need; azNew = sqlite3Realloc( p->azResult, sizeof(char*)*p->nAlloc ); if( azNew==0 ) goto malloc_failed; p->azResult = azNew; } /* If this is the first row, then generate an extra row containing ** the names of all columns. */ |
︙ | ︙ | |||
161 162 163 164 165 166 167 | sqlite3_free(res.zErrMsg); if( rc!=SQLITE_OK ){ sqlite3_free_table(&res.azResult[1]); return rc; } if( res.nAlloc>res.nData ){ char **azNew; | | | 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 | sqlite3_free(res.zErrMsg); if( rc!=SQLITE_OK ){ sqlite3_free_table(&res.azResult[1]); return rc; } if( res.nAlloc>res.nData ){ char **azNew; azNew = sqlite3Realloc( res.azResult, sizeof(char*)*res.nData ); if( azNew==0 ){ sqlite3_free_table(&res.azResult[1]); db->errCode = SQLITE_NOMEM; return SQLITE_NOMEM_BKPT; } res.azResult = azNew; } |
︙ | ︙ |
Changes to src/tclsqlite.c.
︙ | ︙ | |||
89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 | /* Forward declaration */ typedef struct SqliteDb SqliteDb; /* ** New SQL functions can be created as TCL scripts. Each such function ** is described by an instance of the following structure. */ typedef struct SqlFunc SqlFunc; struct SqlFunc { Tcl_Interp *interp; /* The TCL interpret to execute the function */ Tcl_Obj *pScript; /* The Tcl_Obj representation of the script */ SqliteDb *pDb; /* Database connection that owns this function */ int useEvalObjv; /* True if it is safe to use Tcl_EvalObjv */ char *zName; /* Name of this function */ SqlFunc *pNext; /* Next function on the list of them all */ }; /* ** New collation sequences function can be created as TCL scripts. Each such ** function is described by an instance of the following structure. | > > > > > > > > > | 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 | /* Forward declaration */ typedef struct SqliteDb SqliteDb; /* ** New SQL functions can be created as TCL scripts. Each such function ** is described by an instance of the following structure. ** ** Variable eType may be set to SQLITE_INTEGER, SQLITE_FLOAT, SQLITE_TEXT, ** SQLITE_BLOB or SQLITE_NULL. If it is SQLITE_NULL, then the implementation ** attempts to determine the type of the result based on the Tcl object. ** If it is SQLITE_TEXT or SQLITE_BLOB, then a text (sqlite3_result_text()) ** or blob (sqlite3_result_blob()) is returned. If it is SQLITE_INTEGER ** or SQLITE_FLOAT, then an attempt is made to return an integer or float ** value, falling back to float and then text if this is not possible. */ typedef struct SqlFunc SqlFunc; struct SqlFunc { Tcl_Interp *interp; /* The TCL interpret to execute the function */ Tcl_Obj *pScript; /* The Tcl_Obj representation of the script */ SqliteDb *pDb; /* Database connection that owns this function */ int useEvalObjv; /* True if it is safe to use Tcl_EvalObjv */ int eType; /* Type of value to return */ char *zName; /* Name of this function */ SqlFunc *pNext; /* Next function on the list of them all */ }; /* ** New collation sequences function can be created as TCL scripts. Each such ** function is described by an instance of the following structure. |
︙ | ︙ | |||
146 147 148 149 150 151 152 153 154 155 156 157 158 159 | Tcl_Interp *interp; /* The interpreter used for this database */ char *zBusy; /* The busy callback routine */ char *zCommit; /* The commit hook callback routine */ char *zTrace; /* The trace callback routine */ char *zTraceV2; /* The trace_v2 callback routine */ char *zProfile; /* The profile callback routine */ char *zProgress; /* The progress callback routine */ char *zAuth; /* The authorization callback routine */ int disableAuth; /* Disable the authorizer if it exists */ char *zNull; /* Text to substitute for an SQL NULL value */ SqlFunc *pFunc; /* List of SQL functions */ Tcl_Obj *pUpdateHook; /* Update hook script (if any) */ Tcl_Obj *pPreUpdateHook; /* Pre-update hook script (if any) */ Tcl_Obj *pRollbackHook; /* Rollback hook script (if any) */ | > | 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 | Tcl_Interp *interp; /* The interpreter used for this database */ char *zBusy; /* The busy callback routine */ char *zCommit; /* The commit hook callback routine */ char *zTrace; /* The trace callback routine */ char *zTraceV2; /* The trace_v2 callback routine */ char *zProfile; /* The profile callback routine */ char *zProgress; /* The progress callback routine */ char *zBindFallback; /* Callback to invoke on a binding miss */ char *zAuth; /* The authorization callback routine */ int disableAuth; /* Disable the authorizer if it exists */ char *zNull; /* Text to substitute for an SQL NULL value */ SqlFunc *pFunc; /* List of SQL functions */ Tcl_Obj *pUpdateHook; /* Update hook script (if any) */ Tcl_Obj *pPreUpdateHook; /* Pre-update hook script (if any) */ Tcl_Obj *pRollbackHook; /* Rollback hook script (if any) */ |
︙ | ︙ | |||
167 168 169 170 171 172 173 174 175 176 177 178 179 180 | int maxStmt; /* The next maximum number of stmtList */ int nStmt; /* Number of statements in stmtList */ IncrblobChannel *pIncrblob;/* Linked list of open incrblob channels */ int nStep, nSort, nIndex; /* Statistics for most recent operation */ int nVMStep; /* Another statistic for most recent operation */ int nTransaction; /* Number of nested [transaction] methods */ int openFlags; /* Flags used to open. (SQLITE_OPEN_URI) */ #ifdef SQLITE_TEST int bLegacyPrepare; /* True to use sqlite3_prepare() */ #endif }; struct IncrblobChannel { sqlite3_blob *pBlob; /* sqlite3 blob handle */ | > | 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 | int maxStmt; /* The next maximum number of stmtList */ int nStmt; /* Number of statements in stmtList */ IncrblobChannel *pIncrblob;/* Linked list of open incrblob channels */ int nStep, nSort, nIndex; /* Statistics for most recent operation */ int nVMStep; /* Another statistic for most recent operation */ int nTransaction; /* Number of nested [transaction] methods */ int openFlags; /* Flags used to open. (SQLITE_OPEN_URI) */ int nRef; /* Delete object when this reaches 0 */ #ifdef SQLITE_TEST int bLegacyPrepare; /* True to use sqlite3_prepare() */ #endif }; struct IncrblobChannel { sqlite3_blob *pBlob; /* sqlite3 blob handle */ |
︙ | ︙ | |||
502 503 504 505 506 507 508 509 510 511 512 513 514 515 | pNext = pPreStmt->pNext; dbFreeStmt(pPreStmt); } pDb->nStmt = 0; pDb->stmtLast = 0; pDb->stmtList = 0; } /* ** TCL calls this procedure when an sqlite3 database command is ** deleted. */ static void SQLITE_TCLAPI DbDeleteCmd(void *db){ SqliteDb *pDb = (SqliteDb*)db; | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 | pNext = pPreStmt->pNext; dbFreeStmt(pPreStmt); } pDb->nStmt = 0; pDb->stmtLast = 0; pDb->stmtList = 0; } /* ** Increment the reference counter on the SqliteDb object. The reference ** should be released by calling delDatabaseRef(). */ static void addDatabaseRef(SqliteDb *pDb){ pDb->nRef++; } /* ** Decrement the reference counter associated with the SqliteDb object. ** If it reaches zero, delete the object. */ static void delDatabaseRef(SqliteDb *pDb){ assert( pDb->nRef>0 ); pDb->nRef--; if( pDb->nRef==0 ){ flushStmtCache(pDb); closeIncrblobChannels(pDb); sqlite3_close(pDb->db); while( pDb->pFunc ){ SqlFunc *pFunc = pDb->pFunc; pDb->pFunc = pFunc->pNext; assert( pFunc->pDb==pDb ); Tcl_DecrRefCount(pFunc->pScript); Tcl_Free((char*)pFunc); } while( pDb->pCollate ){ SqlCollate *pCollate = pDb->pCollate; pDb->pCollate = pCollate->pNext; Tcl_Free((char*)pCollate); } if( pDb->zBusy ){ Tcl_Free(pDb->zBusy); } if( pDb->zTrace ){ Tcl_Free(pDb->zTrace); } if( pDb->zTraceV2 ){ Tcl_Free(pDb->zTraceV2); } if( pDb->zProfile ){ Tcl_Free(pDb->zProfile); } if( pDb->zBindFallback ){ Tcl_Free(pDb->zBindFallback); } if( pDb->zAuth ){ Tcl_Free(pDb->zAuth); } if( pDb->zNull ){ Tcl_Free(pDb->zNull); } if( pDb->pUpdateHook ){ Tcl_DecrRefCount(pDb->pUpdateHook); } if( pDb->pPreUpdateHook ){ Tcl_DecrRefCount(pDb->pPreUpdateHook); } if( pDb->pRollbackHook ){ Tcl_DecrRefCount(pDb->pRollbackHook); } if( pDb->pWalHook ){ Tcl_DecrRefCount(pDb->pWalHook); } if( pDb->pCollateNeeded ){ Tcl_DecrRefCount(pDb->pCollateNeeded); } Tcl_Free((char*)pDb); } } /* ** TCL calls this procedure when an sqlite3 database command is ** deleted. */ static void SQLITE_TCLAPI DbDeleteCmd(void *db){ SqliteDb *pDb = (SqliteDb*)db; delDatabaseRef(pDb); } /* ** This routine is called when a database file is locked while trying ** to execute SQL. */ static int DbBusyHandler(void *cd, int nTries){ |
︙ | ︙ | |||
991 992 993 994 995 996 997 | sqlite3_result_error(context, Tcl_GetStringResult(p->interp), -1); }else{ Tcl_Obj *pVar = Tcl_GetObjResult(p->interp); int n; u8 *data; const char *zType = (pVar->typePtr ? pVar->typePtr->name : ""); char c = zType[0]; | > > > | | | > > > > > > > > > > > > > > > | | < > > > > | | < > > > > > | | | < < | < > > > | < | | > | > > | 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 | sqlite3_result_error(context, Tcl_GetStringResult(p->interp), -1); }else{ Tcl_Obj *pVar = Tcl_GetObjResult(p->interp); int n; u8 *data; const char *zType = (pVar->typePtr ? pVar->typePtr->name : ""); char c = zType[0]; int eType = p->eType; if( eType==SQLITE_NULL ){ if( c=='b' && strcmp(zType,"bytearray")==0 && pVar->bytes==0 ){ /* Only return a BLOB type if the Tcl variable is a bytearray and ** has no string representation. */ eType = SQLITE_BLOB; }else if( (c=='b' && strcmp(zType,"boolean")==0) || (c=='w' && strcmp(zType,"wideInt")==0) || (c=='i' && strcmp(zType,"int")==0) ){ eType = SQLITE_INTEGER; }else if( c=='d' && strcmp(zType,"double")==0 ){ eType = SQLITE_FLOAT; }else{ eType = SQLITE_TEXT; } } switch( eType ){ case SQLITE_BLOB: { data = Tcl_GetByteArrayFromObj(pVar, &n); sqlite3_result_blob(context, data, n, SQLITE_TRANSIENT); break; } case SQLITE_INTEGER: { Tcl_WideInt v; if( TCL_OK==Tcl_GetWideIntFromObj(0, pVar, &v) ){ sqlite3_result_int64(context, v); break; } /* fall-through */ } case SQLITE_FLOAT: { double r; if( TCL_OK==Tcl_GetDoubleFromObj(0, pVar, &r) ){ sqlite3_result_double(context, r); break; } /* fall-through */ } default: { data = (unsigned char *)Tcl_GetStringFromObj(pVar, &n); sqlite3_result_text(context, (char *)data, n, SQLITE_TRANSIENT); break; } } } } #ifndef SQLITE_OMIT_AUTHORIZATION /* ** This is the authentication function. It appends the authentication ** type code and the two arguments to zCmd[] then invokes the result |
︙ | ︙ | |||
1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 | Tcl_AppendResult(interp, sqlite3_errmsg(pDb->db), (char*)0); rc = TCL_ERROR; } sqlite3_exec(pDb->db, "ROLLBACK", 0, 0, 0); } pDb->disableAuth--; return rc; } /* ** Unless SQLITE_TEST is defined, this function is a simple wrapper around ** sqlite3_prepare_v2(). If SQLITE_TEST is defined, then it uses either ** sqlite3_prepare_v2() or legacy interface sqlite3_prepare(), depending | > | 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 | Tcl_AppendResult(interp, sqlite3_errmsg(pDb->db), (char*)0); rc = TCL_ERROR; } sqlite3_exec(pDb->db, "ROLLBACK", 0, 0, 0); } pDb->disableAuth--; delDatabaseRef(pDb); return rc; } /* ** Unless SQLITE_TEST is defined, this function is a simple wrapper around ** sqlite3_prepare_v2(). If SQLITE_TEST is defined, then it uses either ** sqlite3_prepare_v2() or legacy interface sqlite3_prepare(), depending |
︙ | ︙ | |||
1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 | sqlite3_stmt *pStmt = 0; /* Prepared statement object */ SqlPreparedStmt *pPreStmt; /* Pointer to cached statement */ int nSql; /* Length of zSql in bytes */ int nVar = 0; /* Number of variables in statement */ int iParm = 0; /* Next free entry in apParm */ char c; int i; Tcl_Interp *interp = pDb->interp; *ppPreStmt = 0; /* Trim spaces from the start of zSql and calculate the remaining length. */ while( (c = zSql[0])==' ' || c=='\t' || c=='\r' || c=='\n' ){ zSql++; } nSql = strlen30(zSql); | > > | 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 | sqlite3_stmt *pStmt = 0; /* Prepared statement object */ SqlPreparedStmt *pPreStmt; /* Pointer to cached statement */ int nSql; /* Length of zSql in bytes */ int nVar = 0; /* Number of variables in statement */ int iParm = 0; /* Next free entry in apParm */ char c; int i; int needResultReset = 0; /* Need to invoke Tcl_ResetResult() */ int rc = SQLITE_OK; /* Value to return */ Tcl_Interp *interp = pDb->interp; *ppPreStmt = 0; /* Trim spaces from the start of zSql and calculate the remaining length. */ while( (c = zSql[0])==' ' || c=='\t' || c=='\r' || c=='\n' ){ zSql++; } nSql = strlen30(zSql); |
︙ | ︙ | |||
1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 | assert( 0==memcmp(pPreStmt->zSql, zSql, pPreStmt->nSql) ); /* Bind values to parameters that begin with $ or : */ for(i=1; i<=nVar; i++){ const char *zVar = sqlite3_bind_parameter_name(pStmt, i); if( zVar!=0 && (zVar[0]=='$' || zVar[0]==':' || zVar[0]=='@') ){ Tcl_Obj *pVar = Tcl_GetVar2Ex(interp, &zVar[1], 0, 0); if( pVar ){ int n; u8 *data; const char *zType = (pVar->typePtr ? pVar->typePtr->name : ""); c = zType[0]; if( zVar[0]=='@' || (c=='b' && strcmp(zType,"bytearray")==0 && pVar->bytes==0) ){ | > > > > > > > > > > > > > > > > > > > | 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 | assert( 0==memcmp(pPreStmt->zSql, zSql, pPreStmt->nSql) ); /* Bind values to parameters that begin with $ or : */ for(i=1; i<=nVar; i++){ const char *zVar = sqlite3_bind_parameter_name(pStmt, i); if( zVar!=0 && (zVar[0]=='$' || zVar[0]==':' || zVar[0]=='@') ){ Tcl_Obj *pVar = Tcl_GetVar2Ex(interp, &zVar[1], 0, 0); if( pVar==0 && pDb->zBindFallback!=0 ){ Tcl_Obj *pCmd; int rx; pCmd = Tcl_NewStringObj(pDb->zBindFallback, -1); Tcl_IncrRefCount(pCmd); Tcl_ListObjAppendElement(interp, pCmd, Tcl_NewStringObj(zVar,-1)); if( needResultReset ) Tcl_ResetResult(interp); needResultReset = 1; rx = Tcl_EvalObjEx(interp, pCmd, TCL_EVAL_DIRECT); Tcl_DecrRefCount(pCmd); if( rx==TCL_OK ){ pVar = Tcl_GetObjResult(interp); }else if( rx==TCL_ERROR ){ rc = TCL_ERROR; break; }else{ pVar = 0; } } if( pVar ){ int n; u8 *data; const char *zType = (pVar->typePtr ? pVar->typePtr->name : ""); c = zType[0]; if( zVar[0]=='@' || (c=='b' && strcmp(zType,"bytearray")==0 && pVar->bytes==0) ){ |
︙ | ︙ | |||
1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 | sqlite3_bind_text(pStmt, i, (char *)data, n, SQLITE_STATIC); Tcl_IncrRefCount(pVar); pPreStmt->apParm[iParm++] = pVar; } }else{ sqlite3_bind_null(pStmt, i); } } } pPreStmt->nParm = iParm; *ppPreStmt = pPreStmt; | > > | | 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 | sqlite3_bind_text(pStmt, i, (char *)data, n, SQLITE_STATIC); Tcl_IncrRefCount(pVar); pPreStmt->apParm[iParm++] = pVar; } }else{ sqlite3_bind_null(pStmt, i); } if( needResultReset ) Tcl_ResetResult(pDb->interp); } } pPreStmt->nParm = iParm; *ppPreStmt = pPreStmt; if( needResultReset && rc==TCL_OK ) Tcl_ResetResult(pDb->interp); return rc; } /* ** Release a statement reference obtained by calling dbPrepareAndBind(). ** There should be exactly one call to this function for each call to ** dbPrepareAndBind(). ** |
︙ | ︙ | |||
1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 | p->pSql = pSql; Tcl_IncrRefCount(pSql); if( pArray ){ p->pArray = pArray; Tcl_IncrRefCount(pArray); } p->evalFlags = evalFlags; } /* ** Obtain information about the row that the DbEvalContext passed as the ** first argument currently points to. */ static void dbEvalRowInfo( | > | 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 | p->pSql = pSql; Tcl_IncrRefCount(pSql); if( pArray ){ p->pArray = pArray; Tcl_IncrRefCount(pArray); } p->evalFlags = evalFlags; addDatabaseRef(p->pDb); } /* ** Obtain information about the row that the DbEvalContext passed as the ** first argument currently points to. */ static void dbEvalRowInfo( |
︙ | ︙ | |||
1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 | } if( p->pArray ){ Tcl_DecrRefCount(p->pArray); p->pArray = 0; } Tcl_DecrRefCount(p->pSql); dbReleaseColumnNames(p); } /* ** Return a pointer to a Tcl_Obj structure with ref-count 0 that contains ** the value for the iCol'th column of the row currently pointed to by ** the DbEvalContext structure passed as the first argument. */ | > | 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 | } if( p->pArray ){ Tcl_DecrRefCount(p->pArray); p->pArray = 0; } Tcl_DecrRefCount(p->pSql); dbReleaseColumnNames(p); delDatabaseRef(p->pDb); } /* ** Return a pointer to a Tcl_Obj structure with ref-count 0 that contains ** the value for the iCol'th column of the row currently pointed to by ** the DbEvalContext structure passed as the first argument. */ |
︙ | ︙ | |||
1847 1848 1849 1850 1851 1852 1853 | int objc, Tcl_Obj *const*objv ){ SqliteDb *pDb = (SqliteDb*)cd; int choice; int rc = TCL_OK; static const char *DB_strs[] = { | | | | > | | | | | | | | | | < | | | | > | | | | | | | | | | 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 | int objc, Tcl_Obj *const*objv ){ SqliteDb *pDb = (SqliteDb*)cd; int choice; int rc = TCL_OK; static const char *DB_strs[] = { "authorizer", "backup", "bind_fallback", "busy", "cache", "changes", "close", "collate", "collation_needed", "commit_hook", "complete", "config", "copy", "deserialize", "enable_load_extension", "errorcode", "eval", "exists", "function", "incrblob", "interrupt", "last_insert_rowid", "nullvalue", "onecolumn", "preupdate", "profile", "progress", "rekey", "restore", "rollback_hook", "serialize", "status", "timeout", "total_changes", "trace", "trace_v2", "transaction", "unlock_notify", "update_hook", "version", "wal_hook", 0 }; enum DB_enum { DB_AUTHORIZER, DB_BACKUP, DB_BIND_FALLBACK, DB_BUSY, DB_CACHE, DB_CHANGES, DB_CLOSE, DB_COLLATE, DB_COLLATION_NEEDED, DB_COMMIT_HOOK, DB_COMPLETE, DB_CONFIG, DB_COPY, DB_DESERIALIZE, DB_ENABLE_LOAD_EXTENSION, DB_ERRORCODE, DB_EVAL, DB_EXISTS, DB_FUNCTION, DB_INCRBLOB, DB_INTERRUPT, DB_LAST_INSERT_ROWID, DB_NULLVALUE, DB_ONECOLUMN, DB_PREUPDATE, DB_PROFILE, DB_PROGRESS, DB_REKEY, DB_RESTORE, DB_ROLLBACK_HOOK, DB_SERIALIZE, DB_STATUS, DB_TIMEOUT, DB_TOTAL_CHANGES, DB_TRACE, DB_TRACE_V2, DB_TRANSACTION, DB_UNLOCK_NOTIFY, DB_UPDATE_HOOK, DB_VERSION, DB_WAL_HOOK }; /* don't leave trailing commas on DB_enum, it confuses the AIX xlc compiler */ if( objc<2 ){ Tcl_WrongNumArgs(interp, 1, objv, "SUBCOMMAND ..."); return TCL_ERROR; } |
︙ | ︙ | |||
1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 | Tcl_AppendResult(interp, "backup failed: ", sqlite3_errmsg(pDest), (char*)0); rc = TCL_ERROR; } sqlite3_close(pDest); break; } /* $db busy ?CALLBACK? ** ** Invoke the given callback if an SQL statement attempts to open ** a locked database file. */ case DB_BUSY: { | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | Tcl_AppendResult(interp, "backup failed: ", sqlite3_errmsg(pDest), (char*)0); rc = TCL_ERROR; } sqlite3_close(pDest); break; } /* $db bind_fallback ?CALLBACK? ** ** When resolving bind parameters in an SQL statement, if the parameter ** cannot be associated with a TCL variable then invoke CALLBACK with a ** single argument that is the name of the parameter and use the return ** value of the CALLBACK as the binding. If CALLBACK returns something ** other than TCL_OK or TCL_ERROR then bind a NULL. ** ** If CALLBACK is an empty string, then revert to the default behavior ** which is to set the binding to NULL. ** ** If CALLBACK returns an error, that causes the statement execution to ** abort. Hence, to configure a connection so that it throws an error ** on an attempt to bind an unknown variable, do something like this: ** ** proc bind_error {name} {error "no such variable: $name"} ** db bind_fallback bind_error */ case DB_BIND_FALLBACK: { if( objc>3 ){ Tcl_WrongNumArgs(interp, 2, objv, "?CALLBACK?"); return TCL_ERROR; }else if( objc==2 ){ if( pDb->zBindFallback ){ Tcl_AppendResult(interp, pDb->zBindFallback, (char*)0); } }else{ char *zCallback; int len; if( pDb->zBindFallback ){ Tcl_Free(pDb->zBindFallback); } zCallback = Tcl_GetStringFromObj(objv[2], &len); if( zCallback && len>0 ){ pDb->zBindFallback = Tcl_Alloc( len + 1 ); memcpy(pDb->zBindFallback, zCallback, len+1); }else{ pDb->zBindFallback = 0; } } break; } /* $db busy ?CALLBACK? ** ** Invoke the given callback if an SQL statement attempts to open ** a locked database file. */ case DB_BUSY: { |
︙ | ︙ | |||
2096 2097 2098 2099 2100 2101 2102 | case DB_CHANGES: { Tcl_Obj *pResult; if( objc!=2 ){ Tcl_WrongNumArgs(interp, 2, objv, ""); return TCL_ERROR; } pResult = Tcl_GetObjResult(interp); | | | 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 | case DB_CHANGES: { Tcl_Obj *pResult; if( objc!=2 ){ Tcl_WrongNumArgs(interp, 2, objv, ""); return TCL_ERROR; } pResult = Tcl_GetObjResult(interp); Tcl_SetWideIntObj(pResult, sqlite3_changes64(pDb->db)); break; } /* $db close ** ** Shutdown the database */ |
︙ | ︙ | |||
2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 | } isComplete = sqlite3_complete( Tcl_GetStringFromObj(objv[2], 0) ); pResult = Tcl_GetObjResult(interp); Tcl_SetBooleanObj(pResult, isComplete); #endif break; } /* $db copy conflict-algorithm table filename ?SEPARATOR? ?NULLINDICATOR? ** ** Copy data into table from filename, optionally using SEPARATOR ** as column separators. If a column contains a null string, or the ** value of NULLINDICATOR, a NULL is inserted for the column. ** conflict-algorithm is one of the sqlite conflict algorithms: | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 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 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 | } isComplete = sqlite3_complete( Tcl_GetStringFromObj(objv[2], 0) ); pResult = Tcl_GetObjResult(interp); Tcl_SetBooleanObj(pResult, isComplete); #endif break; } /* $db config ?OPTION? ?BOOLEAN? ** ** Configure the database connection using the sqlite3_db_config() ** interface. */ case DB_CONFIG: { static const struct DbConfigChoices { const char *zName; int op; } aDbConfig[] = { { "defensive", SQLITE_DBCONFIG_DEFENSIVE }, { "dqs_ddl", SQLITE_DBCONFIG_DQS_DDL }, { "dqs_dml", SQLITE_DBCONFIG_DQS_DML }, { "enable_fkey", SQLITE_DBCONFIG_ENABLE_FKEY }, { "enable_qpsg", SQLITE_DBCONFIG_ENABLE_QPSG }, { "enable_trigger", SQLITE_DBCONFIG_ENABLE_TRIGGER }, { "enable_view", SQLITE_DBCONFIG_ENABLE_VIEW }, { "fts3_tokenizer", SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER }, { "legacy_alter_table", SQLITE_DBCONFIG_LEGACY_ALTER_TABLE }, { "legacy_file_format", SQLITE_DBCONFIG_LEGACY_FILE_FORMAT }, { "load_extension", SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION }, { "no_ckpt_on_close", SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE }, { "reset_database", SQLITE_DBCONFIG_RESET_DATABASE }, { "trigger_eqp", SQLITE_DBCONFIG_TRIGGER_EQP }, { "trusted_schema", SQLITE_DBCONFIG_TRUSTED_SCHEMA }, { "writable_schema", SQLITE_DBCONFIG_WRITABLE_SCHEMA }, }; Tcl_Obj *pResult; int ii; if( objc>4 ){ Tcl_WrongNumArgs(interp, 2, objv, "?OPTION? ?BOOLEAN?"); return TCL_ERROR; } if( objc==2 ){ /* With no arguments, list all configuration options and with the ** current value */ pResult = Tcl_NewListObj(0,0); for(ii=0; ii<sizeof(aDbConfig)/sizeof(aDbConfig[0]); ii++){ int v = 0; sqlite3_db_config(pDb->db, aDbConfig[ii].op, -1, &v); Tcl_ListObjAppendElement(interp, pResult, Tcl_NewStringObj(aDbConfig[ii].zName,-1)); Tcl_ListObjAppendElement(interp, pResult, Tcl_NewIntObj(v)); } }else{ const char *zOpt = Tcl_GetString(objv[2]); int onoff = -1; int v = 0; if( zOpt[0]=='-' ) zOpt++; for(ii=0; ii<sizeof(aDbConfig)/sizeof(aDbConfig[0]); ii++){ if( strcmp(aDbConfig[ii].zName, zOpt)==0 ) break; } if( ii>=sizeof(aDbConfig)/sizeof(aDbConfig[0]) ){ Tcl_AppendResult(interp, "unknown config option: \"", zOpt, "\"", (void*)0); return TCL_ERROR; } if( objc==4 ){ if( Tcl_GetBooleanFromObj(interp, objv[3], &onoff) ){ return TCL_ERROR; } } sqlite3_db_config(pDb->db, aDbConfig[ii].op, onoff, &v); pResult = Tcl_NewIntObj(v); } Tcl_SetObjResult(interp, pResult); break; } /* $db copy conflict-algorithm table filename ?SEPARATOR? ?NULLINDICATOR? ** ** Copy data into table from filename, optionally using SEPARATOR ** as column separators. If a column contains a null string, or the ** value of NULLINDICATOR, a NULL is inserted for the column. ** conflict-algorithm is one of the sqlite conflict algorithms: |
︙ | ︙ | |||
2414 2415 2416 2417 2418 2419 2420 | (char*)0); rc = TCL_ERROR; } break; } /* | | | | | > > > | > | < < < < < < > > > > > > > > > > > > > > > > > > > > > > > > < > | > | > > > > | > > | 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 | (char*)0); rc = TCL_ERROR; } break; } /* ** $db deserialize ?-maxsize N? ?-readonly BOOL? ?DATABASE? VALUE ** ** Reopen DATABASE (default "main") using the content in $VALUE */ case DB_DESERIALIZE: { #ifdef SQLITE_OMIT_DESERIALIZE Tcl_AppendResult(interp, "MEMDB not available in this build", (char*)0); rc = TCL_ERROR; #else const char *zSchema = 0; Tcl_Obj *pValue = 0; unsigned char *pBA; unsigned char *pData; int len, xrc; sqlite3_int64 mxSize = 0; int i; int isReadonly = 0; if( objc<3 ){ Tcl_WrongNumArgs(interp, 2, objv, "?DATABASE? VALUE"); rc = TCL_ERROR; break; } for(i=2; i<objc-1; i++){ const char *z = Tcl_GetString(objv[i]); if( strcmp(z,"-maxsize")==0 && i<objc-2 ){ Tcl_WideInt x; rc = Tcl_GetWideIntFromObj(interp, objv[++i], &x); if( rc ) goto deserialize_error; mxSize = x; continue; } if( strcmp(z,"-readonly")==0 && i<objc-2 ){ rc = Tcl_GetBooleanFromObj(interp, objv[++i], &isReadonly); if( rc ) goto deserialize_error; continue; } if( zSchema==0 && i==objc-2 && z[0]!='-' ){ zSchema = z; continue; } Tcl_AppendResult(interp, "unknown option: ", z, (char*)0); rc = TCL_ERROR; goto deserialize_error; } pValue = objv[objc-1]; pBA = Tcl_GetByteArrayFromObj(pValue, &len); pData = sqlite3_malloc64( len ); if( pData==0 && len>0 ){ Tcl_AppendResult(interp, "out of memory", (char*)0); rc = TCL_ERROR; }else{ int flags; if( len>0 ) memcpy(pData, pBA, len); if( isReadonly ){ flags = SQLITE_DESERIALIZE_FREEONCLOSE | SQLITE_DESERIALIZE_READONLY; }else{ flags = SQLITE_DESERIALIZE_FREEONCLOSE | SQLITE_DESERIALIZE_RESIZEABLE; } xrc = sqlite3_deserialize(pDb->db, zSchema, pData, len, len, flags); if( xrc ){ Tcl_AppendResult(interp, "unable to set MEMDB content", (char*)0); rc = TCL_ERROR; } if( mxSize>0 ){ sqlite3_file_control(pDb->db, zSchema,SQLITE_FCNTL_SIZE_LIMIT,&mxSize); } } deserialize_error: #endif break; } /* ** $db enable_load_extension BOOLEAN ** |
︙ | ︙ | |||
2603 2604 2605 2606 2607 2608 2609 | cd2[1] = (void *)pScript; rc = DbEvalNextCmd(cd2, interp, TCL_OK); } break; } /* | | > > > > > > > > | | > > > > > > > > > > > > > > > > > > > > | > > | 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 2920 2921 2922 2923 2924 2925 2926 2927 2928 | cd2[1] = (void *)pScript; rc = DbEvalNextCmd(cd2, interp, TCL_OK); } break; } /* ** $db function NAME [OPTIONS] SCRIPT ** ** Create a new SQL function called NAME. Whenever that function is ** called, invoke SCRIPT to evaluate the function. ** ** Options: ** --argcount N Function has exactly N arguments ** --deterministic The function is pure ** --directonly Prohibit use inside triggers and views ** --innocuous Has no side effects or information leaks ** --returntype TYPE Specify the return type of the function */ case DB_FUNCTION: { int flags = SQLITE_UTF8; SqlFunc *pFunc; Tcl_Obj *pScript; char *zName; int nArg = -1; int i; int eType = SQLITE_NULL; if( objc<4 ){ Tcl_WrongNumArgs(interp, 2, objv, "NAME ?SWITCHES? SCRIPT"); return TCL_ERROR; } for(i=3; i<(objc-1); i++){ const char *z = Tcl_GetString(objv[i]); int n = strlen30(z); if( n>1 && strncmp(z, "-argcount",n)==0 ){ if( i==(objc-2) ){ Tcl_AppendResult(interp, "option requires an argument: ", z,(char*)0); return TCL_ERROR; } if( Tcl_GetIntFromObj(interp, objv[i+1], &nArg) ) return TCL_ERROR; if( nArg<0 ){ Tcl_AppendResult(interp, "number of arguments must be non-negative", (char*)0); return TCL_ERROR; } i++; }else if( n>1 && strncmp(z, "-deterministic",n)==0 ){ flags |= SQLITE_DETERMINISTIC; }else if( n>1 && strncmp(z, "-directonly",n)==0 ){ flags |= SQLITE_DIRECTONLY; }else if( n>1 && strncmp(z, "-innocuous",n)==0 ){ flags |= SQLITE_INNOCUOUS; }else if( n>1 && strncmp(z, "-returntype", n)==0 ){ const char *azType[] = {"integer", "real", "text", "blob", "any", 0}; assert( SQLITE_INTEGER==1 && SQLITE_FLOAT==2 && SQLITE_TEXT==3 ); assert( SQLITE_BLOB==4 && SQLITE_NULL==5 ); if( i==(objc-2) ){ Tcl_AppendResult(interp, "option requires an argument: ", z,(char*)0); return TCL_ERROR; } i++; if( Tcl_GetIndexFromObj(interp, objv[i], azType, "type", 0, &eType) ){ return TCL_ERROR; } eType++; }else{ Tcl_AppendResult(interp, "bad option \"", z, "\": must be -argcount, -deterministic, -directonly," " -innocuous, or -returntype", (char*)0 ); return TCL_ERROR; } } pScript = objv[objc-1]; zName = Tcl_GetStringFromObj(objv[2], 0); pFunc = findSqlFunc(pDb, zName); if( pFunc==0 ) return TCL_ERROR; if( pFunc->pScript ){ Tcl_DecrRefCount(pFunc->pScript); } pFunc->pScript = pScript; Tcl_IncrRefCount(pScript); pFunc->useEvalObjv = safeToUseEvalObjv(interp, pScript); pFunc->eType = eType; rc = sqlite3_create_function(pDb->db, zName, nArg, flags, pFunc, tclSqlFunc, 0, 0); if( rc!=SQLITE_OK ){ rc = TCL_ERROR; Tcl_SetResult(interp, (char *)sqlite3_errmsg(pDb->db), TCL_VOLATILE); } break; |
︙ | ︙ | |||
2856 2857 2858 2859 2860 2861 2862 | /* ** $db rekey KEY ** ** Change the encryption key on the currently open database. */ case DB_REKEY: { | < < < < < < < < < < < < | 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130 3131 3132 3133 | /* ** $db rekey KEY ** ** Change the encryption key on the currently open database. */ case DB_REKEY: { if( objc!=3 ){ Tcl_WrongNumArgs(interp, 2, objv, "KEY"); return TCL_ERROR; } break; } /* $db restore ?DATABASE? FILENAME ** ** Open a database file named FILENAME. Transfer the content ** of FILENAME into the local database DATABASE (default: "main"). |
︙ | ︙ | |||
2941 2942 2943 2944 2945 2946 2947 | /* ** $db serialize ?DATABASE? ** ** Return a serialization of a database. */ case DB_SERIALIZE: { | | | 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202 3203 | /* ** $db serialize ?DATABASE? ** ** Return a serialization of a database. */ case DB_SERIALIZE: { #ifdef SQLITE_OMIT_DESERIALIZE Tcl_AppendResult(interp, "MEMDB not available in this build", (char*)0); rc = TCL_ERROR; #else const char *zSchema = objc>=3 ? Tcl_GetString(objv[2]) : "main"; sqlite3_int64 sz = 0; unsigned char *pData; |
︙ | ︙ | |||
3029 3030 3031 3032 3033 3034 3035 | case DB_TOTAL_CHANGES: { Tcl_Obj *pResult; if( objc!=2 ){ Tcl_WrongNumArgs(interp, 2, objv, ""); return TCL_ERROR; } pResult = Tcl_GetObjResult(interp); | | | 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 | case DB_TOTAL_CHANGES: { Tcl_Obj *pResult; if( objc!=2 ){ Tcl_WrongNumArgs(interp, 2, objv, ""); return TCL_ERROR; } pResult = Tcl_GetObjResult(interp); Tcl_SetWideIntObj(pResult, sqlite3_total_changes64(pDb->db)); break; } /* $db trace ?CALLBACK? ** ** Make arrangements to invoke the CALLBACK routine for each SQL statement ** that is executed. The text of the SQL is appended to CALLBACK before |
︙ | ︙ | |||
3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 | pDb->nTransaction++; /* If using NRE, schedule a callback to invoke the script pScript, then ** a second callback to commit (or rollback) the transaction or savepoint ** opened above. If not using NRE, evaluate the script directly, then ** call function DbTransPostCmd() to commit (or rollback) the transaction ** or savepoint. */ if( DbUseNre() ){ Tcl_NRAddCallback(interp, DbTransPostCmd, cd, 0, 0, 0); (void)Tcl_NREvalObj(interp, pScript, 0); }else{ rc = DbTransPostCmd(&cd, interp, Tcl_EvalObjEx(interp, pScript, 0)); } break; | > | 3457 3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 | pDb->nTransaction++; /* If using NRE, schedule a callback to invoke the script pScript, then ** a second callback to commit (or rollback) the transaction or savepoint ** opened above. If not using NRE, evaluate the script directly, then ** call function DbTransPostCmd() to commit (or rollback) the transaction ** or savepoint. */ addDatabaseRef(pDb); /* DbTransPostCmd() calls delDatabaseRef() */ if( DbUseNre() ){ Tcl_NRAddCallback(interp, DbTransPostCmd, cd, 0, 0, 0); (void)Tcl_NREvalObj(interp, pScript, 0); }else{ rc = DbTransPostCmd(&cd, interp, Tcl_EvalObjEx(interp, pScript, 0)); } break; |
︙ | ︙ | |||
3438 3439 3440 3441 3442 3443 3444 3445 | */ static int sqliteCmdUsage( Tcl_Interp *interp, Tcl_Obj *const*objv ){ Tcl_WrongNumArgs(interp, 1, objv, "HANDLE ?FILENAME? ?-vfs VFSNAME? ?-readonly BOOLEAN? ?-create BOOLEAN?" " ?-nomutex BOOLEAN? ?-fullmutex BOOLEAN? ?-uri BOOLEAN?" | > < < < > | 3687 3688 3689 3690 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709 3710 | */ static int sqliteCmdUsage( Tcl_Interp *interp, Tcl_Obj *const*objv ){ Tcl_WrongNumArgs(interp, 1, objv, "HANDLE ?FILENAME? ?-vfs VFSNAME? ?-readonly BOOLEAN? ?-create BOOLEAN?" " ?-nofollow BOOLEAN?" " ?-nomutex BOOLEAN? ?-fullmutex BOOLEAN? ?-uri BOOLEAN?" ); return TCL_ERROR; } /* ** sqlite3 DBNAME FILENAME ?-vfs VFSNAME? ?-key KEY? ?-readonly BOOLEAN? ** ?-create BOOLEAN? ?-nomutex BOOLEAN? ** ?-nofollow BOOLEAN? ** ** This is the main Tcl command. When the "sqlite" Tcl command is ** invoked, this routine runs to process that command. ** ** The first argument, DBNAME, is an arbitrary name for a new ** database connection. This command creates a new command named ** DBNAME that is used to control that connection. The database |
︙ | ︙ | |||
3474 3475 3476 3477 3478 3479 3480 3481 | SqliteDb *p; const char *zArg; char *zErrMsg; int i; const char *zFile = 0; const char *zVfs = 0; int flags; Tcl_DString translatedFilename; | > < < < < | 3722 3723 3724 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 3737 | SqliteDb *p; const char *zArg; char *zErrMsg; int i; const char *zFile = 0; const char *zVfs = 0; int flags; int bTranslateFileName = 1; Tcl_DString translatedFilename; int rc; /* In normal use, each TCL interpreter runs in a single thread. So ** by default, we can turn off mutexing on SQLite database connections. ** However, for testing purposes it is useful to have mutexes turned ** on. So, by default, mutexes default off. But if compiled with ** SQLITE_TCL_DEFAULT_FULLMUTEX then mutexes default on. |
︙ | ︙ | |||
3505 3506 3507 3508 3509 3510 3511 | return TCL_OK; } if( strcmp(zArg,"-sourceid")==0 ){ Tcl_AppendResult(interp,sqlite3_sourceid(), (char*)0); return TCL_OK; } if( strcmp(zArg,"-has-codec")==0 ){ | < < < < < < | > > > > > > > > | 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 | return TCL_OK; } if( strcmp(zArg,"-sourceid")==0 ){ Tcl_AppendResult(interp,sqlite3_sourceid(), (char*)0); return TCL_OK; } if( strcmp(zArg,"-has-codec")==0 ){ Tcl_AppendResult(interp,"0",(char*)0); return TCL_OK; } if( zArg[0]=='-' ) return sqliteCmdUsage(interp, objv); } for(i=2; i<objc; i++){ zArg = Tcl_GetString(objv[i]); if( zArg[0]!='-' ){ if( zFile!=0 ) return sqliteCmdUsage(interp, objv); zFile = zArg; continue; } if( i==objc-1 ) return sqliteCmdUsage(interp, objv); i++; if( strcmp(zArg,"-key")==0 ){ /* no-op */ }else if( strcmp(zArg, "-vfs")==0 ){ zVfs = Tcl_GetString(objv[i]); }else if( strcmp(zArg, "-readonly")==0 ){ int b; if( Tcl_GetBooleanFromObj(interp, objv[i], &b) ) return TCL_ERROR; if( b ){ flags &= ~(SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE); flags |= SQLITE_OPEN_READONLY; }else{ flags &= ~SQLITE_OPEN_READONLY; flags |= SQLITE_OPEN_READWRITE; } }else if( strcmp(zArg, "-create")==0 ){ int b; if( Tcl_GetBooleanFromObj(interp, objv[i], &b) ) return TCL_ERROR; if( b && (flags & SQLITE_OPEN_READONLY)==0 ){ flags |= SQLITE_OPEN_CREATE; }else{ flags &= ~SQLITE_OPEN_CREATE; } }else if( strcmp(zArg, "-nofollow")==0 ){ int b; if( Tcl_GetBooleanFromObj(interp, objv[i], &b) ) return TCL_ERROR; if( b ){ flags |= SQLITE_OPEN_NOFOLLOW; }else{ flags &= ~SQLITE_OPEN_NOFOLLOW; } }else if( strcmp(zArg, "-nomutex")==0 ){ int b; if( Tcl_GetBooleanFromObj(interp, objv[i], &b) ) return TCL_ERROR; if( b ){ flags |= SQLITE_OPEN_NOMUTEX; flags &= ~SQLITE_OPEN_FULLMUTEX; |
︙ | ︙ | |||
3573 3574 3575 3576 3577 3578 3579 3580 3581 3582 3583 3584 3585 3586 3587 3588 | int b; if( Tcl_GetBooleanFromObj(interp, objv[i], &b) ) return TCL_ERROR; if( b ){ flags |= SQLITE_OPEN_URI; }else{ flags &= ~SQLITE_OPEN_URI; } }else{ Tcl_AppendResult(interp, "unknown option: ", zArg, (char*)0); return TCL_ERROR; } } zErrMsg = 0; p = (SqliteDb*)Tcl_Alloc( sizeof(*p) ); memset(p, 0, sizeof(*p)); if( zFile==0 ) zFile = ""; | > > > > > | > > | > < < < < < > | 3820 3821 3822 3823 3824 3825 3826 3827 3828 3829 3830 3831 3832 3833 3834 3835 3836 3837 3838 3839 3840 3841 3842 3843 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 | int b; if( Tcl_GetBooleanFromObj(interp, objv[i], &b) ) return TCL_ERROR; if( b ){ flags |= SQLITE_OPEN_URI; }else{ flags &= ~SQLITE_OPEN_URI; } }else if( strcmp(zArg, "-translatefilename")==0 ){ if( Tcl_GetBooleanFromObj(interp, objv[i], &bTranslateFileName) ){ return TCL_ERROR; } }else{ Tcl_AppendResult(interp, "unknown option: ", zArg, (char*)0); return TCL_ERROR; } } zErrMsg = 0; p = (SqliteDb*)Tcl_Alloc( sizeof(*p) ); memset(p, 0, sizeof(*p)); if( zFile==0 ) zFile = ""; if( bTranslateFileName ){ zFile = Tcl_TranslateFileName(interp, zFile, &translatedFilename); } rc = sqlite3_open_v2(zFile, &p->db, flags, zVfs); if( bTranslateFileName ){ Tcl_DStringFree(&translatedFilename); } if( p->db ){ if( SQLITE_OK!=sqlite3_errcode(p->db) ){ zErrMsg = sqlite3_mprintf("%s", sqlite3_errmsg(p->db)); sqlite3_close(p->db); p->db = 0; } }else{ zErrMsg = sqlite3_mprintf("%s", sqlite3_errstr(rc)); } if( p->db==0 ){ Tcl_SetResult(interp, zErrMsg, TCL_VOLATILE); Tcl_Free((char*)p); sqlite3_free(zErrMsg); return TCL_ERROR; } p->maxStmt = NUM_PREPARED_STMTS; p->openFlags = flags & SQLITE_OPEN_URI; p->interp = interp; zArg = Tcl_GetStringFromObj(objv[1], 0); if( DbUseNre() ){ Tcl_NRCreateCommand(interp, zArg, DbObjCmdAdaptor, DbObjCmd, (char*)p, DbDeleteCmd); }else{ Tcl_CreateObjCommand(interp, zArg, DbObjCmd, (char*)p, DbDeleteCmd); } p->nRef = 1; return TCL_OK; } /* ** Provide a dummy Tcl_InitStubs if we are using this as a static ** library. */ |
︙ | ︙ | |||
3722 3723 3724 3725 3726 3727 3728 | "}\n" "}\n" "}\n" ; return zMainloop; } | > | > | 3973 3974 3975 3976 3977 3978 3979 3980 3981 3982 3983 3984 3985 3986 3987 3988 3989 | "}\n" "}\n" "}\n" ; return zMainloop; } #ifndef TCLSH_MAIN # define TCLSH_MAIN main #endif int SQLITE_CDECL TCLSH_MAIN(int argc, char **argv){ Tcl_Interp *interp; int i; const char *zScript = 0; char zArgc[32]; #if defined(TCLSH_INIT_PROC) extern const char *TCLSH_INIT_PROC(Tcl_Interp*); |
︙ | ︙ |
Changes to src/test1.c.
︙ | ︙ | |||
651 652 653 654 655 656 657 | */ static int SQLITE_TCLAPI test_key( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ char **argv /* Text of each argument */ ){ | < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 | */ static int SQLITE_TCLAPI test_key( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ char **argv /* Text of each argument */ ){ return TCL_OK; } /* ** Usage: sqlite3_rekey DB KEY ** ** Change the codec key. */ static int SQLITE_TCLAPI test_rekey( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ char **argv /* Text of each argument */ ){ return TCL_OK; } /* ** Usage: sqlite3_close DB ** ** Closes the database opened by sqlite3_open. |
︙ | ︙ | |||
993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 | sqlite3_context *context, int argc, sqlite3_value **argv ){ static int cnt = 0; sqlite3_result_int(context, cnt++); } /* ** Usage: sqlite3_create_function DB ** ** Call the sqlite3_create_function API on the given database in order ** to create a function named "x_coalesce". This function does the same thing ** as the "coalesce" function. This function also registers an SQL function | > > > > > > > > > > > > > > | 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 | sqlite3_context *context, int argc, sqlite3_value **argv ){ static int cnt = 0; sqlite3_result_int(context, cnt++); } /* ** This SQL function returns the integer value of its argument as a MEM_IntReal ** value. */ static void intrealFunction( sqlite3_context *context, int argc, sqlite3_value **argv ){ sqlite3_int64 v = sqlite3_value_int64(argv[0]); sqlite3_result_int64(context, v); sqlite3_test_control(SQLITE_TESTCTRL_RESULT_INTREAL, context); } /* ** Usage: sqlite3_create_function DB ** ** Call the sqlite3_create_function API on the given database in order ** to create a function named "x_coalesce". This function does the same thing ** as the "coalesce" function. This function also registers an SQL function |
︙ | ︙ | |||
1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 | rc = sqlite3_create_function(db, "counter1", -1, SQLITE_UTF8, 0, nondeterministicFunction, 0, 0); } if( rc==SQLITE_OK ){ rc = sqlite3_create_function(db, "counter2", -1, SQLITE_UTF8|SQLITE_DETERMINISTIC, 0, nondeterministicFunction, 0, 0); } #ifndef SQLITE_OMIT_UTF16 /* Use the sqlite3_create_function16() API here. Mainly for fun, but also ** because it is not tested anywhere else. */ if( rc==SQLITE_OK ){ const void *zUtf16; sqlite3_value *pVal; | > > > > > > > > | 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 | rc = sqlite3_create_function(db, "counter1", -1, SQLITE_UTF8, 0, nondeterministicFunction, 0, 0); } if( rc==SQLITE_OK ){ rc = sqlite3_create_function(db, "counter2", -1, SQLITE_UTF8|SQLITE_DETERMINISTIC, 0, nondeterministicFunction, 0, 0); } /* The intreal() function converts its argument to an integer and returns ** it as a MEM_IntReal. */ if( rc==SQLITE_OK ){ rc = sqlite3_create_function(db, "intreal", 1, SQLITE_UTF8, 0, intrealFunction, 0, 0); } #ifndef SQLITE_OMIT_UTF16 /* Use the sqlite3_create_function16() API here. Mainly for fun, but also ** because it is not tested anywhere else. */ if( rc==SQLITE_OK ){ const void *zUtf16; sqlite3_value *pVal; |
︙ | ︙ | |||
1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 | } #endif if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR; Tcl_SetResult(interp, (char *)t1ErrorName(rc), 0); return TCL_OK; } /* ** Routines to implement the x_count() aggregate function. ** ** x_count() counts the number of non-null arguments. But there are ** some twists for testing purposes. ** | > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | } #endif if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR; Tcl_SetResult(interp, (char *)t1ErrorName(rc), 0); return TCL_OK; } /* ** Usage: sqlite3_drop_modules DB ?NAME ...? ** ** Invoke the sqlite3_drop_modules(D,L) interface on database ** connection DB, in order to drop all modules except those named in ** the argument. */ static int SQLITE_TCLAPI test_drop_modules( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ char **argv /* Text of each argument */ ){ sqlite3 *db; if( argc!=2 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " DB\"", 0); return TCL_ERROR; } if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; #ifndef SQLITE_OMIT_VIRTUALTABLE sqlite3_drop_modules(db, argc>2 ? (const char**)(argv+2) : 0); #endif return TCL_OK; } /* ** Routines to implement the x_count() aggregate function. ** ** x_count() counts the number of non-null arguments. But there are ** some twists for testing purposes. ** |
︙ | ︙ | |||
2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 | } if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; rc = sqlite3_stmt_readonly(pStmt); Tcl_SetObjResult(interp, Tcl_NewBooleanObj(rc)); return TCL_OK; } /* ** Usage: sqlite3_stmt_busy STMT ** ** Return true if STMT is a non-NULL pointer to a statement ** that has been stepped but not to completion. */ | > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | } if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; rc = sqlite3_stmt_readonly(pStmt); Tcl_SetObjResult(interp, Tcl_NewBooleanObj(rc)); return TCL_OK; } /* ** Usage: sqlite3_stmt_isexplain STMT ** ** Return 1, 2, or 0 respectively if STMT is an EXPLAIN statement, an ** EXPLAIN QUERY PLAN statement or an ordinary statement or NULL pointer. */ static int SQLITE_TCLAPI test_stmt_isexplain( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3_stmt *pStmt; int rc; if( objc!=2 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", Tcl_GetStringFromObj(objv[0], 0), " STMT", 0); return TCL_ERROR; } if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; rc = sqlite3_stmt_isexplain(pStmt); Tcl_SetObjResult(interp, Tcl_NewIntObj(rc)); return TCL_OK; } /* ** Usage: sqlite3_stmt_busy STMT ** ** Return true if STMT is a non-NULL pointer to a statement ** that has been stepped but not to completion. */ |
︙ | ︙ | |||
3773 3774 3775 3776 3777 3778 3779 3780 3781 3782 3783 3784 3785 3786 3787 3788 3789 3790 3791 | void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3_stmt *pStmt; int idx; int bytes; char *value; int rc; if( objc!=5 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", Tcl_GetStringFromObj(objv[0], 0), " STMT N VALUE BYTES", 0); return TCL_ERROR; } if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR; | > > | > > > > > | > > > > > | | 3821 3822 3823 3824 3825 3826 3827 3828 3829 3830 3831 3832 3833 3834 3835 3836 3837 3838 3839 3840 3841 3842 3843 3844 3845 3846 3847 3848 3849 3850 3851 3852 3853 3854 3855 3856 3857 3858 3859 3860 3861 3862 3863 3864 3865 | void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3_stmt *pStmt; int idx; int trueLength = 0; int bytes; char *value; int rc; char *toFree = 0; if( objc!=5 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", Tcl_GetStringFromObj(objv[0], 0), " STMT N VALUE BYTES", 0); return TCL_ERROR; } if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR; value = (char*)Tcl_GetByteArrayFromObj(objv[3], &trueLength); if( Tcl_GetIntFromObj(interp, objv[4], &bytes) ) return TCL_ERROR; if( bytes<0 ){ toFree = malloc( trueLength + 1 ); if( toFree==0 ){ Tcl_AppendResult(interp, "out of memory", (void*)0); return TCL_ERROR; } memcpy(toFree, value, trueLength); toFree[trueLength] = 0; value = toFree; } rc = sqlite3_bind_text(pStmt, idx, value, bytes, SQLITE_TRANSIENT); free(toFree); if( sqlite3TestErrCode(interp, StmtToDb(pStmt), rc) ) return TCL_ERROR; if( rc!=SQLITE_OK ){ Tcl_AppendResult(interp, sqlite3ErrName(rc), (void*)0); return TCL_ERROR; } return TCL_OK; } /* |
︙ | ︙ | |||
3817 3818 3819 3820 3821 3822 3823 3824 3825 3826 3827 3828 3829 3830 3831 3832 3833 3834 3835 3836 3837 3838 3839 | Tcl_Obj *CONST objv[] ){ #ifndef SQLITE_OMIT_UTF16 sqlite3_stmt *pStmt; int idx; int bytes; char *value; int rc; void (*xDel)(void*) = (objc==6?SQLITE_STATIC:SQLITE_TRANSIENT); Tcl_Obj *oStmt = objv[objc-4]; Tcl_Obj *oN = objv[objc-3]; Tcl_Obj *oString = objv[objc-2]; Tcl_Obj *oBytes = objv[objc-1]; if( objc!=5 && objc!=6){ Tcl_AppendResult(interp, "wrong # args: should be \"", Tcl_GetStringFromObj(objv[0], 0), " STMT N VALUE BYTES", 0); return TCL_ERROR; } if( getStmtPointer(interp, Tcl_GetString(oStmt), &pStmt) ) return TCL_ERROR; if( Tcl_GetIntFromObj(interp, oN, &idx) ) return TCL_ERROR; | > > | > > > > > | > > > > > | 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 | Tcl_Obj *CONST objv[] ){ #ifndef SQLITE_OMIT_UTF16 sqlite3_stmt *pStmt; int idx; int bytes; char *value; char *toFree = 0; int rc; int trueLength = 0; void (*xDel)(void*) = (objc==6?SQLITE_STATIC:SQLITE_TRANSIENT); Tcl_Obj *oStmt = objv[objc-4]; Tcl_Obj *oN = objv[objc-3]; Tcl_Obj *oString = objv[objc-2]; Tcl_Obj *oBytes = objv[objc-1]; if( objc!=5 && objc!=6){ Tcl_AppendResult(interp, "wrong # args: should be \"", Tcl_GetStringFromObj(objv[0], 0), " STMT N VALUE BYTES", 0); return TCL_ERROR; } if( getStmtPointer(interp, Tcl_GetString(oStmt), &pStmt) ) return TCL_ERROR; if( Tcl_GetIntFromObj(interp, oN, &idx) ) return TCL_ERROR; value = (char*)Tcl_GetByteArrayFromObj(oString, &trueLength); if( Tcl_GetIntFromObj(interp, oBytes, &bytes) ) return TCL_ERROR; if( bytes<0 && xDel==SQLITE_TRANSIENT ){ toFree = malloc( trueLength + 3 ); if( toFree==0 ){ Tcl_AppendResult(interp, "out of memory", (void*)0); return TCL_ERROR; } memcpy(toFree, value, trueLength); memset(toFree+trueLength, 0, 3); value = toFree; } rc = sqlite3_bind_text16(pStmt, idx, (void *)value, bytes, xDel); free(toFree); 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 */ |
︙ | ︙ | |||
3888 3889 3890 3891 3892 3893 3894 | value = (char*)Tcl_GetByteArrayFromObj(objv[3], &len); if( Tcl_GetIntFromObj(interp, objv[4], &bytes) ) return TCL_ERROR; if( bytes>len ){ char zBuf[200]; sqlite3_snprintf(sizeof(zBuf), zBuf, "cannot use %d blob bytes, have %d", bytes, len); | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 3960 3961 3962 3963 3964 3965 3966 3967 3968 3969 3970 3971 3972 3973 3974 3975 3976 3977 3978 3979 3980 3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994 3995 3996 3997 3998 3999 4000 4001 4002 4003 4004 4005 4006 4007 4008 4009 4010 4011 4012 4013 4014 4015 4016 4017 4018 4019 4020 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 4034 4035 4036 4037 4038 4039 4040 4041 4042 4043 4044 4045 4046 4047 4048 4049 4050 4051 4052 4053 4054 4055 4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075 4076 4077 4078 4079 4080 4081 4082 4083 4084 4085 4086 4087 4088 4089 4090 4091 4092 4093 4094 4095 4096 4097 4098 4099 4100 4101 4102 4103 4104 4105 4106 4107 4108 4109 4110 4111 4112 4113 4114 4115 4116 4117 4118 4119 4120 4121 4122 4123 4124 4125 4126 4127 4128 4129 4130 4131 4132 4133 4134 4135 4136 4137 4138 4139 4140 4141 4142 4143 4144 4145 4146 4147 4148 4149 4150 4151 4152 4153 4154 4155 4156 4157 4158 4159 4160 4161 4162 4163 4164 4165 4166 4167 4168 4169 4170 4171 4172 4173 4174 4175 | value = (char*)Tcl_GetByteArrayFromObj(objv[3], &len); if( Tcl_GetIntFromObj(interp, objv[4], &bytes) ) return TCL_ERROR; if( bytes>len ){ char zBuf[200]; sqlite3_snprintf(sizeof(zBuf), zBuf, "cannot use %d blob bytes, have %d", bytes, len); Tcl_AppendResult(interp, zBuf, (char*)0); return TCL_ERROR; } rc = sqlite3_bind_blob(pStmt, idx, value, bytes, xDestructor); if( sqlite3TestErrCode(interp, StmtToDb(pStmt), rc) ) return TCL_ERROR; if( rc!=SQLITE_OK ){ return TCL_ERROR; } return TCL_OK; } #ifndef SQLITE_OMIT_VIRTUALTABLE /* ** sqlite3_carray_bind [options...] STMT NAME VALUE ... ** ** Options: ** -transient ** -static ** -int32 ** -int64 ** -double ** -text ** ** Each call clears static data. Called with no options does nothing ** but clear static data. */ static int SQLITE_TCLAPI test_carray_bind( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3_stmt *pStmt; int eType = 0; /* CARRAY_INT32 */ int nData = 0; void *aData = 0; int isTransient = 0; int isStatic = 0; int idx; int i, j; int rc; void (*xDel)(void*) = sqlite3_free; static void *aStaticData = 0; static int nStaticData = 0; static int eStaticType = 0; extern int sqlite3_carray_bind( sqlite3_stmt *pStmt, int i, void *aData, int nData, int mFlags, void (*xDestroy)(void*) ); if( aStaticData ){ /* Always clear preexisting static data on every call */ if( eStaticType==3 ){ for(i=0; i<nStaticData; i++){ sqlite3_free(((char**)aStaticData)[i]); } } sqlite3_free(aStaticData); aStaticData = 0; nStaticData = 0; eStaticType = 0; } if( objc==1 ) return TCL_OK; for(i=1; i<objc && Tcl_GetString(objv[i])[0]=='-'; i++){ const char *z = Tcl_GetString(objv[i]); if( strcmp(z, "-transient")==0 ){ isTransient = 1; xDel = SQLITE_TRANSIENT; }else if( strcmp(z, "-static")==0 ){ isStatic = 1; xDel = SQLITE_STATIC; }else if( strcmp(z, "-int32")==0 ){ eType = 0; /* CARRAY_INT32 */ }else if( strcmp(z, "-int64")==0 ){ eType = 1; /* CARRAY_INT64 */ }else if( strcmp(z, "-double")==0 ){ eType = 2; /* CARRAY_DOUBLE */ }else if( strcmp(z, "-text")==0 ){ eType = 3; /* CARRAY_TEXT */ }else if( strcmp(z, "--")==0 ){ break; }else { Tcl_AppendResult(interp, "unknown option: ", z, (char*)0); return TCL_ERROR; } } if( eType==3 && !isStatic && !isTransient ){ Tcl_AppendResult(interp, "text data must be either -static or -transient", (char*)0); return TCL_ERROR; } if( isStatic && isTransient ){ Tcl_AppendResult(interp, "cannot be both -static and -transient", (char*)0); return TCL_ERROR; } if( objc-i < 2 ){ Tcl_WrongNumArgs(interp, 1, objv, "[OPTIONS] STMT IDX VALUE ..."); return TCL_ERROR; } if( getStmtPointer(interp, Tcl_GetString(objv[i]), &pStmt) ) return TCL_ERROR; i++; if( Tcl_GetIntFromObj(interp, objv[i], &idx) ) return TCL_ERROR; i++; nData = objc - i; switch( eType + 4*(nData<=0) ){ case 0: { /* INT32 */ int *a = sqlite3_malloc( sizeof(int)*nData ); if( a==0 ){ rc = SQLITE_NOMEM; goto carray_bind_done; } for(j=0; j<nData; j++){ int v; if( Tcl_GetIntFromObj(interp, objv[i+j], &v) ){ sqlite3_free(a); return TCL_ERROR; } a[j] = v; } aData = a; break; } case 1: { /* INT64 */ sqlite3_int64 *a = sqlite3_malloc( sizeof(sqlite3_int64)*nData ); if( a==0 ){ rc = SQLITE_NOMEM; goto carray_bind_done; } for(j=0; j<nData; j++){ Tcl_WideInt v; if( Tcl_GetWideIntFromObj(interp, objv[i+j], &v) ){ sqlite3_free(a); return TCL_ERROR; } a[j] = v; } aData = a; break; } case 2: { /* DOUBLE */ double *a = sqlite3_malloc( sizeof(double)*nData ); if( a==0 ){ rc = SQLITE_NOMEM; goto carray_bind_done; } for(j=0; j<nData; j++){ double v; if( Tcl_GetDoubleFromObj(interp, objv[i+j], &v) ){ sqlite3_free(a); return TCL_ERROR; } a[j] = v; } aData = a; break; } case 3: { /* TEXT */ char **a = sqlite3_malloc( sizeof(char*)*nData ); if( a==0 ){ rc = SQLITE_NOMEM; goto carray_bind_done; } for(j=0; j<nData; j++){ const char *v = Tcl_GetString(objv[i+j]); a[j] = sqlite3_mprintf("%s", v); } aData = a; break; } case 4: { /* nData==0 */ aData = ""; xDel = SQLITE_STATIC; isTransient = 0; isStatic = 0; break; } } if( isStatic ){ aStaticData = aData; nStaticData = nData; eStaticType = eType; } rc = sqlite3_carray_bind(pStmt, idx, aData, nData, eType, xDel); if( isTransient ){ if( eType==3 ){ for(i=0; i<nData; i++) sqlite3_free(((char**)aData)[i]); } sqlite3_free(aData); } carray_bind_done: if( rc ){ Tcl_AppendResult(interp, sqlite3_errstr(rc), (char*)0); return TCL_ERROR; } return TCL_OK; } #endif /* SQLITE_OMIT_VIRTUALTABLE */ /* ** Usage: sqlite3_bind_parameter_count STMT ** ** Return the number of wildcards in the given statement. */ static int SQLITE_TCLAPI test_bind_parameter_count( void * clientData, |
︙ | ︙ | |||
4241 4242 4243 4244 4245 4246 4247 | }else{ int n = (int)strlen(zSql) + 1; zCopy = malloc(n); memcpy(zCopy, zSql, n); } pzTail = objc>=5 ? &zTail : 0; rc = sqlite3_prepare_v2(db, zCopy, bytes, &pStmt, pzTail); | | | > > | | 4502 4503 4504 4505 4506 4507 4508 4509 4510 4511 4512 4513 4514 4515 4516 4517 4518 4519 4520 4521 4522 4523 4524 | }else{ int n = (int)strlen(zSql) + 1; zCopy = malloc(n); memcpy(zCopy, zSql, n); } pzTail = objc>=5 ? &zTail : 0; rc = sqlite3_prepare_v2(db, zCopy, bytes, &pStmt, pzTail); if( objc>=5 ){ zTail = &zSql[(zTail - zCopy)]; } free(zCopy); assert(rc==SQLITE_OK || pStmt==0); Tcl_ResetResult(interp); if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR; if( rc==SQLITE_OK && objc>=5 && zTail ){ if( bytes>=0 ){ bytes = bytes - (int)(zTail-zSql); } Tcl_ObjSetVar2(interp, objv[4], 0, Tcl_NewStringObj(zTail, bytes), 0); } if( rc!=SQLITE_OK ){ assert( pStmt==0 ); |
︙ | ︙ | |||
4576 4577 4578 4579 4580 4581 4582 | { "SQLITE_OPEN_AUTOPROXY", SQLITE_OPEN_AUTOPROXY }, { "SQLITE_OPEN_MAIN_DB", SQLITE_OPEN_MAIN_DB }, { "SQLITE_OPEN_TEMP_DB", SQLITE_OPEN_TEMP_DB }, { "SQLITE_OPEN_TRANSIENT_DB", SQLITE_OPEN_TRANSIENT_DB }, { "SQLITE_OPEN_MAIN_JOURNAL", SQLITE_OPEN_MAIN_JOURNAL }, { "SQLITE_OPEN_TEMP_JOURNAL", SQLITE_OPEN_TEMP_JOURNAL }, { "SQLITE_OPEN_SUBJOURNAL", SQLITE_OPEN_SUBJOURNAL }, | | > | 4839 4840 4841 4842 4843 4844 4845 4846 4847 4848 4849 4850 4851 4852 4853 4854 4855 4856 4857 4858 4859 4860 | { "SQLITE_OPEN_AUTOPROXY", SQLITE_OPEN_AUTOPROXY }, { "SQLITE_OPEN_MAIN_DB", SQLITE_OPEN_MAIN_DB }, { "SQLITE_OPEN_TEMP_DB", SQLITE_OPEN_TEMP_DB }, { "SQLITE_OPEN_TRANSIENT_DB", SQLITE_OPEN_TRANSIENT_DB }, { "SQLITE_OPEN_MAIN_JOURNAL", SQLITE_OPEN_MAIN_JOURNAL }, { "SQLITE_OPEN_TEMP_JOURNAL", SQLITE_OPEN_TEMP_JOURNAL }, { "SQLITE_OPEN_SUBJOURNAL", SQLITE_OPEN_SUBJOURNAL }, { "SQLITE_OPEN_SUPER_JOURNAL", SQLITE_OPEN_SUPER_JOURNAL }, { "SQLITE_OPEN_NOMUTEX", SQLITE_OPEN_NOMUTEX }, { "SQLITE_OPEN_FULLMUTEX", SQLITE_OPEN_FULLMUTEX }, { "SQLITE_OPEN_SHAREDCACHE", SQLITE_OPEN_SHAREDCACHE }, { "SQLITE_OPEN_PRIVATECACHE", SQLITE_OPEN_PRIVATECACHE }, { "SQLITE_OPEN_WAL", SQLITE_OPEN_WAL }, { "SQLITE_OPEN_URI", SQLITE_OPEN_URI }, { "SQLITE_OPEN_EXRESCODE", SQLITE_OPEN_EXRESCODE }, { 0, 0 } }; rc = Tcl_GetIndexFromObjStruct(interp, apFlag[i], aFlag, sizeof(aFlag[0]), "flag", 0, &iFlag ); if( rc!=TCL_OK ) return rc; flags |= aFlag[iFlag].flag; |
︙ | ︙ | |||
5081 5082 5083 5084 5085 5086 5087 | if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; if( Tcl_GetIntFromObj(interp, objv[2], &col) ) return TCL_ERROR; Tcl_SetObjResult(interp, Tcl_NewIntObj(xFunc(pStmt, col))); return TCL_OK; } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 5345 5346 5347 5348 5349 5350 5351 5352 5353 5354 5355 5356 5357 5358 | if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; if( Tcl_GetIntFromObj(interp, objv[2], &col) ) return TCL_ERROR; Tcl_SetObjResult(interp, Tcl_NewIntObj(xFunc(pStmt, col))); return TCL_OK; } /* ** Usage: sqlite3_interrupt DB ** ** Trigger an interrupt on DB */ static int SQLITE_TCLAPI test_interrupt( |
︙ | ︙ | |||
5443 5444 5445 5446 5447 5448 5449 5450 5451 5452 5453 5454 5455 5456 | if( objc==2 ){ if( Tcl_GetWideIntFromObj(interp, objv[1], &N) ) return TCL_ERROR; } amt = sqlite3_soft_heap_limit64(N); Tcl_SetObjResult(interp, Tcl_NewWideIntObj(amt)); return TCL_OK; } /* ** Usage: sqlite3_thread_cleanup ** ** Call the sqlite3_thread_cleanup API. */ static int SQLITE_TCLAPI test_thread_cleanup( | > > > > > > > > > > > > > > > > > > > > > > > > > > > | 5676 5677 5678 5679 5680 5681 5682 5683 5684 5685 5686 5687 5688 5689 5690 5691 5692 5693 5694 5695 5696 5697 5698 5699 5700 5701 5702 5703 5704 5705 5706 5707 5708 5709 5710 5711 5712 5713 5714 5715 5716 | if( objc==2 ){ if( Tcl_GetWideIntFromObj(interp, objv[1], &N) ) return TCL_ERROR; } amt = sqlite3_soft_heap_limit64(N); Tcl_SetObjResult(interp, Tcl_NewWideIntObj(amt)); return TCL_OK; } /* ** Usage: sqlite3_hard_heap_limit ?N? ** ** Query or set the hard heap limit for the current thread. The ** limit is only changed if the N is present. The previous limit ** is returned. */ static int SQLITE_TCLAPI test_hard_heap_limit( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3_int64 amt; Tcl_WideInt N = -1; if( objc!=1 && objc!=2 ){ Tcl_WrongNumArgs(interp, 1, objv, "?N?"); return TCL_ERROR; } if( objc==2 ){ if( Tcl_GetWideIntFromObj(interp, objv[1], &N) ) return TCL_ERROR; } amt = sqlite3_hard_heap_limit64(N); Tcl_SetObjResult(interp, Tcl_NewWideIntObj(amt)); return TCL_OK; } /* ** Usage: sqlite3_thread_cleanup ** ** Call the sqlite3_thread_cleanup API. */ static int SQLITE_TCLAPI test_thread_cleanup( |
︙ | ︙ | |||
6157 6158 6159 6160 6161 6162 6163 6164 6165 6166 6167 6168 6169 6170 | zDbName = Tcl_GetString(objv[2]); } sqlite3_file_control(db, zDbName, SQLITE_FCNTL_VFSNAME,(void*)&zVfsName); Tcl_AppendResult(interp, zVfsName, (char*)0); sqlite3_free(zVfsName); return TCL_OK; } /* ** tclcmd: file_control_tempfilename DB ?AUXDB? ** ** Return a string that is a temporary filename */ static int SQLITE_TCLAPI file_control_tempfilename( | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 6417 6418 6419 6420 6421 6422 6423 6424 6425 6426 6427 6428 6429 6430 6431 6432 6433 6434 6435 6436 6437 6438 6439 6440 6441 6442 6443 6444 6445 6446 6447 6448 6449 6450 6451 6452 6453 6454 6455 6456 6457 6458 6459 6460 | zDbName = Tcl_GetString(objv[2]); } sqlite3_file_control(db, zDbName, SQLITE_FCNTL_VFSNAME,(void*)&zVfsName); Tcl_AppendResult(interp, zVfsName, (char*)0); sqlite3_free(zVfsName); return TCL_OK; } /* ** tclcmd: file_control_reservebytes DB N */ static int SQLITE_TCLAPI file_control_reservebytes( ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */ ){ sqlite3 *db; const char *zDbName = "main"; int n = 0; int rc; if( objc!=3 ){ Tcl_WrongNumArgs(interp, 1, objv, "DB N"); return TCL_ERROR; } if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) || Tcl_GetIntFromObj(interp, objv[2], &n) ){ return TCL_ERROR; } rc = sqlite3_file_control(db, zDbName, SQLITE_FCNTL_RESERVE_BYTES, (void*)&n); Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1)); return TCL_OK; } /* ** tclcmd: file_control_tempfilename DB ?AUXDB? ** ** Return a string that is a temporary filename */ static int SQLITE_TCLAPI file_control_tempfilename( |
︙ | ︙ | |||
6189 6190 6191 6192 6193 6194 6195 6196 6197 6198 6199 6200 6201 6202 | zDbName = Tcl_GetString(objv[2]); } sqlite3_file_control(db, zDbName, SQLITE_FCNTL_TEMPFILENAME, (void*)&zTName); Tcl_AppendResult(interp, zTName, (char*)0); sqlite3_free(zTName); return TCL_OK; } /* ** tclcmd: sqlite3_vfs_list ** ** Return a tcl list containing the names of all registered vfs's. */ | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 6479 6480 6481 6482 6483 6484 6485 6486 6487 6488 6489 6490 6491 6492 6493 6494 6495 6496 6497 6498 6499 6500 6501 6502 6503 6504 6505 6506 6507 6508 6509 6510 6511 6512 6513 6514 6515 6516 6517 6518 6519 6520 6521 6522 6523 6524 6525 6526 6527 6528 | zDbName = Tcl_GetString(objv[2]); } sqlite3_file_control(db, zDbName, SQLITE_FCNTL_TEMPFILENAME, (void*)&zTName); Tcl_AppendResult(interp, zTName, (char*)0); sqlite3_free(zTName); return TCL_OK; } /* ** tclcmd: file_control_external_reader DB ?AUXDB? ** ** Return a string that is a temporary filename */ static int SQLITE_TCLAPI file_control_external_reader( ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */ ){ sqlite3 *db; const char *zName = "main"; int iRes = 0; int rc = SQLITE_OK; if( objc!=2 && objc!=3 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", Tcl_GetStringFromObj(objv[0], 0), " DB ?AUXDB?", 0); return TCL_ERROR; } if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){ return TCL_ERROR; } if( objc==3 ){ zName = Tcl_GetString(objv[2]); } rc = sqlite3_file_control(db, zName, SQLITE_FCNTL_EXTERNAL_READER, &iRes); if( rc!=SQLITE_OK ){ Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC); return TCL_ERROR; } Tcl_SetObjResult(interp, Tcl_NewIntObj(iRes)); return TCL_OK; } /* ** tclcmd: sqlite3_vfs_list ** ** Return a tcl list containing the names of all registered vfs's. */ |
︙ | ︙ | |||
6318 6319 6320 6321 6322 6323 6324 | */ static int SQLITE_TCLAPI reset_prng_state( ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */ ){ | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > | 6644 6645 6646 6647 6648 6649 6650 6651 6652 6653 6654 6655 6656 6657 6658 6659 6660 6661 6662 6663 6664 6665 6666 6667 6668 6669 6670 6671 6672 6673 6674 6675 6676 6677 6678 6679 6680 6681 6682 6683 6684 6685 6686 6687 6688 6689 6690 6691 6692 6693 6694 6695 6696 6697 6698 6699 6700 6701 6702 6703 6704 6705 6706 6707 6708 6709 6710 6711 6712 6713 6714 6715 6716 | */ static int SQLITE_TCLAPI reset_prng_state( ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */ ){ sqlite3_randomness(0,0); return TCL_OK; } /* ** tclcmd: prng_seed INT ?DB? ** ** Set up the SQLITE_TESTCTRL_PRNG_SEED pragma with parameter INT and DB. ** INT is an integer. DB is a database connection, or a NULL pointer if ** omitted. ** ** When INT!=0 and DB!=0, set the PRNG seed to the value of the schema ** cookie for DB, or to INT if the schema cookie happens to be zero. ** ** When INT!=0 and DB==0, set the PRNG seed to just INT. ** ** If INT==0 and DB==0 then use the default procedure of calling the ** xRandomness method on the default VFS to get the PRNG seed. */ static int SQLITE_TCLAPI prng_seed( ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */ ){ int i = 0; sqlite3 *db = 0; if( objc!=2 && objc!=3 ){ Tcl_WrongNumArgs(interp, 1, objv, "SEED ?DB?"); return TCL_ERROR; } if( Tcl_GetIntFromObj(interp,objv[1],&i) ) return TCL_ERROR; if( objc==3 && getDbPointer(interp, Tcl_GetString(objv[2]), &db) ){ return TCL_ERROR; } sqlite3_test_control(SQLITE_TESTCTRL_PRNG_SEED, i, db); return TCL_OK; } /* ** tclcmd: extra_schema_checks BOOLEAN ** ** Enable or disable schema checks when parsing the sqlite_schema file. ** This is always enabled in production, but it is sometimes useful to ** disable the checks in order to make some internal error states reachable ** for testing. */ static int SQLITE_TCLAPI extra_schema_checks( ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */ ){ int i = 0; if( objc!=2 ){ Tcl_WrongNumArgs(interp, 1, objv, "BOOLEAN"); return TCL_ERROR; } if( Tcl_GetBooleanFromObj(interp,objv[1],&i) ) return TCL_ERROR; sqlite3_test_control(SQLITE_TESTCTRL_EXTRA_SCHEMA_CHECKS, i); return TCL_OK; } /* ** tclcmd: database_may_be_corrupt ** ** Indicate that database files might be corrupt. In other words, set the normal |
︙ | ︙ | |||
6729 6730 6731 6732 6733 6734 6735 | rc = Tcl_GetIndexFromObjStruct( interp, objv[1], aVerb, sizeof(aVerb[0]), "VERB", 0, &iVerb ); if( rc!=TCL_OK ) return rc; iFlag = aVerb[iVerb].i; switch( iFlag ){ | | > > > > > > > > > | 7113 7114 7115 7116 7117 7118 7119 7120 7121 7122 7123 7124 7125 7126 7127 7128 7129 7130 7131 7132 7133 7134 7135 7136 | rc = Tcl_GetIndexFromObjStruct( interp, objv[1], aVerb, sizeof(aVerb[0]), "VERB", 0, &iVerb ); if( rc!=TCL_OK ) return rc; iFlag = aVerb[iVerb].i; switch( iFlag ){ case SQLITE_TESTCTRL_INTERNAL_FUNCTIONS: { sqlite3 *db = 0; if( objc!=3 ){ Tcl_WrongNumArgs(interp, 2, objv, "DB"); return TCL_ERROR; } if( getDbPointer(interp, Tcl_GetString(objv[2]), &db) ) return TCL_ERROR; sqlite3_test_control(SQLITE_TESTCTRL_INTERNAL_FUNCTIONS, db); break; } case SQLITE_TESTCTRL_LOCALTIME_FAULT: { int val; if( objc!=3 ){ Tcl_WrongNumArgs(interp, 2, objv, "ONOFF"); return TCL_ERROR; } if( Tcl_GetBooleanFromObj(interp, objv[2], &val) ) return TCL_ERROR; |
︙ | ︙ | |||
7084 7085 7086 7087 7088 7089 7090 | { "groupby-order", SQLITE_GroupByOrder }, { "factor-constants", SQLITE_FactorOutConst }, { "distinct-opt", SQLITE_DistinctOpt }, { "cover-idx-scan", SQLITE_CoverIdxScan }, { "order-by-idx-join", SQLITE_OrderByIdxJoin }, { "transitive", SQLITE_Transitive }, { "omit-noop-join", SQLITE_OmitNoopJoin }, | < | > | 7477 7478 7479 7480 7481 7482 7483 7484 7485 7486 7487 7488 7489 7490 7491 7492 7493 | { "groupby-order", SQLITE_GroupByOrder }, { "factor-constants", SQLITE_FactorOutConst }, { "distinct-opt", SQLITE_DistinctOpt }, { "cover-idx-scan", SQLITE_CoverIdxScan }, { "order-by-idx-join", SQLITE_OrderByIdxJoin }, { "transitive", SQLITE_Transitive }, { "omit-noop-join", SQLITE_OmitNoopJoin }, { "stat4", SQLITE_Stat4 }, { "skip-scan", SQLITE_SkipScan }, { "push-down", SQLITE_PushDown }, }; if( objc!=4 ){ Tcl_WrongNumArgs(interp, 1, objv, "DB OPT BOOLEAN"); return TCL_ERROR; } if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; |
︙ | ︙ | |||
7127 7128 7129 7130 7131 7132 7133 7134 7135 7136 7137 7138 7139 7140 7141 7142 7143 7144 7145 7146 7147 7148 7149 7150 7151 7152 7153 7154 7155 7156 7157 7158 7159 7160 7161 7162 7163 7164 7165 7166 7167 7168 7169 7170 7171 7172 7173 7174 7175 | static int SQLITE_TCLAPI 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_carray_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_closure_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_csv_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_eval_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_explain_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_fileio_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_fuzzer_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_ieee_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_nextchar_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_percentile_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_regexp_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_remember_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_series_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_spellfix_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_totype_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_wholenumber_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_unionvtab_init(sqlite3*,char**,const sqlite3_api_routines*); #ifdef SQLITE_HAVE_ZLIB extern int sqlite3_zipfile_init(sqlite3*,char**,const sqlite3_api_routines*); #endif static const struct { const char *zExtName; int (*pInit)(sqlite3*,char**,const sqlite3_api_routines*); } aExtension[] = { { "amatch", sqlite3_amatch_init }, { "carray", sqlite3_carray_init }, { "closure", sqlite3_closure_init }, { "csv", sqlite3_csv_init }, { "eval", sqlite3_eval_init }, { "explain", sqlite3_explain_init }, { "fileio", sqlite3_fileio_init }, { "fuzzer", sqlite3_fuzzer_init }, { "ieee754", sqlite3_ieee_init }, { "nextchar", sqlite3_nextchar_init }, { "percentile", sqlite3_percentile_init }, { "regexp", sqlite3_regexp_init }, { "remember", sqlite3_remember_init }, { "series", sqlite3_series_init }, { "spellfix", sqlite3_spellfix_init }, { "totype", sqlite3_totype_init }, { "unionvtab", sqlite3_unionvtab_init }, { "wholenumber", sqlite3_wholenumber_init }, | > > > > > > > > > > | 7520 7521 7522 7523 7524 7525 7526 7527 7528 7529 7530 7531 7532 7533 7534 7535 7536 7537 7538 7539 7540 7541 7542 7543 7544 7545 7546 7547 7548 7549 7550 7551 7552 7553 7554 7555 7556 7557 7558 7559 7560 7561 7562 7563 7564 7565 7566 7567 7568 7569 7570 7571 7572 7573 7574 7575 7576 7577 7578 | static int SQLITE_TCLAPI 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_appendvfs_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_carray_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_closure_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_csv_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_eval_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_explain_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_fileio_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_decimal_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_fuzzer_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_ieee_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_nextchar_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_percentile_init(sqlite3*,char**,const sqlite3_api_routines*); #ifndef SQLITE_OMIT_VIRTUALTABLE extern int sqlite3_prefixes_init(sqlite3*,char**,const sqlite3_api_routines*); #endif extern int sqlite3_regexp_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_remember_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_series_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_spellfix_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_totype_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_wholenumber_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_unionvtab_init(sqlite3*,char**,const sqlite3_api_routines*); #ifdef SQLITE_HAVE_ZLIB extern int sqlite3_zipfile_init(sqlite3*,char**,const sqlite3_api_routines*); #endif static const struct { const char *zExtName; int (*pInit)(sqlite3*,char**,const sqlite3_api_routines*); } aExtension[] = { { "amatch", sqlite3_amatch_init }, { "appendvfs", sqlite3_appendvfs_init }, { "carray", sqlite3_carray_init }, { "closure", sqlite3_closure_init }, { "csv", sqlite3_csv_init }, { "decimal", sqlite3_decimal_init }, { "eval", sqlite3_eval_init }, { "explain", sqlite3_explain_init }, { "fileio", sqlite3_fileio_init }, { "fuzzer", sqlite3_fuzzer_init }, { "ieee754", sqlite3_ieee_init }, { "nextchar", sqlite3_nextchar_init }, { "percentile", sqlite3_percentile_init }, #ifndef SQLITE_OMIT_VIRTUALTABLE { "prefixes", sqlite3_prefixes_init }, #endif { "regexp", sqlite3_regexp_init }, { "remember", sqlite3_remember_init }, { "series", sqlite3_series_init }, { "spellfix", sqlite3_spellfix_init }, { "totype", sqlite3_totype_init }, { "unionvtab", sqlite3_unionvtab_init }, { "wholenumber", sqlite3_wholenumber_init }, |
︙ | ︙ | |||
7196 7197 7198 7199 7200 7201 7202 | return TCL_ERROR; } if( aExtension[i].pInit ){ rc = aExtension[i].pInit(db, &zErrMsg, 0); }else{ rc = SQLITE_OK; } | | | 7599 7600 7601 7602 7603 7604 7605 7606 7607 7608 7609 7610 7611 7612 7613 | return TCL_ERROR; } if( aExtension[i].pInit ){ rc = aExtension[i].pInit(db, &zErrMsg, 0); }else{ rc = SQLITE_OK; } if( (rc!=SQLITE_OK && rc!=SQLITE_OK_LOAD_PERMANENTLY) || zErrMsg ){ Tcl_AppendResult(interp, "initialization of ", zName, " failed: ", zErrMsg, (char*)0); sqlite3_free(zErrMsg); return TCL_ERROR; } } return TCL_OK; |
︙ | ︙ | |||
7547 7548 7549 7550 7551 7552 7553 | int objc, Tcl_Obj *CONST objv[] ){ static const struct { const char *zName; int eVal; } aSetting[] = { | | | | | | | | | | > > > > > | | | > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 7950 7951 7952 7953 7954 7955 7956 7957 7958 7959 7960 7961 7962 7963 7964 7965 7966 7967 7968 7969 7970 7971 7972 7973 7974 7975 7976 7977 7978 7979 7980 7981 7982 7983 7984 7985 7986 7987 7988 7989 7990 7991 7992 7993 7994 7995 7996 7997 7998 7999 8000 8001 8002 8003 8004 8005 8006 8007 8008 8009 8010 8011 8012 8013 8014 8015 8016 8017 8018 8019 8020 8021 8022 8023 8024 8025 8026 8027 8028 8029 8030 8031 8032 8033 8034 8035 8036 | int objc, Tcl_Obj *CONST objv[] ){ static const struct { const char *zName; int eVal; } aSetting[] = { { "FKEY", SQLITE_DBCONFIG_ENABLE_FKEY }, { "TRIGGER", SQLITE_DBCONFIG_ENABLE_TRIGGER }, { "FTS3_TOKENIZER", SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER }, { "LOAD_EXTENSION", SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION }, { "NO_CKPT_ON_CLOSE", SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE }, { "QPSG", SQLITE_DBCONFIG_ENABLE_QPSG }, { "TRIGGER_EQP", SQLITE_DBCONFIG_TRIGGER_EQP }, { "RESET_DB", SQLITE_DBCONFIG_RESET_DATABASE }, { "DEFENSIVE", SQLITE_DBCONFIG_DEFENSIVE }, { "WRITABLE_SCHEMA", SQLITE_DBCONFIG_WRITABLE_SCHEMA }, { "LEGACY_ALTER_TABLE", SQLITE_DBCONFIG_LEGACY_ALTER_TABLE }, { "DQS_DML", SQLITE_DBCONFIG_DQS_DML }, { "DQS_DDL", SQLITE_DBCONFIG_DQS_DDL }, { "LEGACY_FILE_FORMAT", SQLITE_DBCONFIG_LEGACY_FILE_FORMAT }, }; int i; int v = 0; const char *zSetting; sqlite3 *db; if( objc!=4 && objc!=3 ){ Tcl_WrongNumArgs(interp, 1, objv, "DB SETTING [VALUE]"); return TCL_ERROR; } if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; zSetting = Tcl_GetString(objv[2]); if( sqlite3_strglob("SQLITE_*", zSetting)==0 ) zSetting += 7; if( sqlite3_strglob("DBCONFIG_*", zSetting)==0 ) zSetting += 9; if( sqlite3_strglob("ENABLE_*", zSetting)==0 ) zSetting += 7; for(i=0; i<ArraySize(aSetting); i++){ if( strcmp(zSetting, aSetting[i].zName)==0 ) break; } if( i>=ArraySize(aSetting) ){ Tcl_SetObjResult(interp, Tcl_NewStringObj("unknown sqlite3_db_config setting", -1)); return TCL_ERROR; } if( objc==4 ){ if( Tcl_GetIntFromObj(interp, objv[3], &v) ) return TCL_ERROR; }else{ v = -1; } sqlite3_db_config(db, aSetting[i].eVal, v, &v); Tcl_SetObjResult(interp, Tcl_NewIntObj(v)); return TCL_OK; } /* ** tclcmd: sqlite3_txn_state DB ?SCHEMA? ** ** Invoke sqlite3_txn_state(DB,SCHEMA) and return the ** numeric value that results. Use NULL for SCHEMA if the 3 argument ** is omitted. */ static int SQLITE_TCLAPI test_sqlite3_txn_state( void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3 *db; const char *zSchema; int iTxn; if( objc!=2 && objc!=3 ){ Tcl_WrongNumArgs(interp, 1, objv, "DB ?SCHEMA?"); return TCL_ERROR; } if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; zSchema = objc==3 ? Tcl_GetString(objv[2]) : 0; iTxn = sqlite3_txn_state(db, zSchema); Tcl_SetObjResult(interp, Tcl_NewIntObj(iTxn)); return TCL_OK; } /* ** Change the name of the main database schema from "main" to "icecube". */ static int SQLITE_TCLAPI test_dbconfig_maindbname_icecube( void * clientData, Tcl_Interp *interp, |
︙ | ︙ | |||
7671 7672 7673 7674 7675 7676 7677 7678 7679 7680 7681 7682 7683 7684 | zDb = Tcl_GetString(objv[2]); } rc = sqlite3_mmap_warm(db, zDb); Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1)); return TCL_OK; } } /* ** Usage: decode_hexdb TEXT ** ** Example: db deserialize [decode_hexdb $output_of_dbtotxt] ** ** This routine returns a byte-array for an SQLite database file that | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 8110 8111 8112 8113 8114 8115 8116 8117 8118 8119 8120 8121 8122 8123 8124 8125 8126 8127 8128 8129 8130 8131 8132 8133 8134 8135 8136 8137 8138 8139 8140 8141 8142 8143 8144 8145 8146 8147 8148 8149 8150 8151 8152 8153 8154 8155 8156 8157 8158 8159 8160 8161 8162 8163 8164 8165 8166 8167 8168 8169 8170 8171 8172 8173 8174 8175 8176 8177 8178 8179 8180 8181 8182 8183 8184 8185 8186 8187 8188 8189 8190 8191 8192 8193 8194 8195 8196 8197 8198 8199 8200 | zDb = Tcl_GetString(objv[2]); } rc = sqlite3_mmap_warm(db, zDb); Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1)); return TCL_OK; } } /* ** Usage: test_write_db DB OFFSET DATA ** ** Obtain the sqlite3_file* object for the database file for the "main" db ** of handle DB. Then invoke its xWrite method to write data DATA to offset ** OFFSET. */ static int SQLITE_TCLAPI test_write_db( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3 *db = 0; Tcl_WideInt iOff = 0; const unsigned char *aData = 0; int nData = 0; sqlite3_file *pFile = 0; int rc; if( objc!=4 ){ Tcl_WrongNumArgs(interp, 1, objv, "DB OFFSET DATA"); return TCL_ERROR; } if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; if( Tcl_GetWideIntFromObj(interp, objv[2], &iOff) ) return TCL_ERROR; aData = Tcl_GetByteArrayFromObj(objv[3], &nData); sqlite3_file_control(db, "main", SQLITE_FCNTL_FILE_POINTER, (void*)&pFile); rc = pFile->pMethods->xWrite(pFile, aData, nData, iOff); Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE); return TCL_OK; } /* ** Usage: sqlite3_register_cksumvfs ** */ static int SQLITE_TCLAPI test_register_cksumvfs( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ if( objc!=1 ){ Tcl_WrongNumArgs(interp, 1, objv, ""); return TCL_ERROR; }else{ extern int sqlite3_register_cksumvfs(const char*); int rc = sqlite3_register_cksumvfs(0); Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE); } return TCL_OK; } /* ** Usage: sqlite3_unregister_cksumvfs ** */ static int SQLITE_TCLAPI test_unregister_cksumvfs( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ if( objc!=1 ){ Tcl_WrongNumArgs(interp, 1, objv, ""); return TCL_ERROR; }else{ extern int sqlite3_unregister_cksumvfs(void); int rc = sqlite3_unregister_cksumvfs(); Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE); } return TCL_OK; } /* ** Usage: decode_hexdb TEXT ** ** Example: db deserialize [decode_hexdb $output_of_dbtotxt] ** ** This routine returns a byte-array for an SQLite database file that |
︙ | ︙ | |||
7695 7696 7697 7698 7699 7700 7701 | unsigned char *a = 0; int n = 0; int lineno = 0; int i, iNext; int iOffset = 0; int j, k; int rc; | | > > > > > | < | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 8211 8212 8213 8214 8215 8216 8217 8218 8219 8220 8221 8222 8223 8224 8225 8226 8227 8228 8229 8230 8231 8232 8233 8234 8235 8236 8237 8238 8239 8240 8241 8242 8243 8244 8245 8246 8247 8248 8249 8250 8251 8252 8253 8254 8255 8256 8257 8258 8259 8260 8261 8262 8263 8264 8265 8266 8267 8268 8269 8270 8271 8272 8273 8274 8275 8276 8277 8278 8279 8280 8281 8282 8283 8284 8285 8286 8287 8288 8289 8290 8291 8292 8293 8294 8295 8296 8297 8298 8299 8300 8301 8302 8303 8304 8305 8306 8307 8308 8309 8310 8311 8312 8313 8314 8315 8316 8317 8318 8319 8320 8321 8322 8323 8324 8325 8326 8327 8328 8329 8330 8331 8332 8333 8334 8335 8336 8337 8338 8339 8340 8341 8342 8343 8344 8345 8346 8347 8348 8349 8350 8351 8352 8353 8354 8355 8356 8357 8358 8359 8360 8361 8362 8363 8364 8365 8366 8367 | unsigned char *a = 0; int n = 0; int lineno = 0; int i, iNext; int iOffset = 0; int j, k; int rc; unsigned int x[16]; if( objc!=2 ){ Tcl_WrongNumArgs(interp, 1, objv, "HEXDB"); return TCL_ERROR; } zIn = Tcl_GetString(objv[1]); for(i=0; zIn[i]; i=iNext){ lineno++; for(iNext=i; zIn[iNext] && zIn[iNext]!='\n'; iNext++){} if( zIn[iNext]=='\n' ) iNext++; while( zIn[i]==' ' || zIn[i]=='\t' ){ i++; } if( a==0 ){ int pgsz; rc = sscanf(zIn+i, "| size %d pagesize %d", &n, &pgsz); if( rc!=2 ) continue; if( pgsz<512 || pgsz>65536 || (pgsz&(pgsz-1))!=0 ){ Tcl_AppendResult(interp, "bad 'pagesize' field", (void*)0); return TCL_ERROR; } n = (n+pgsz-1)&~(pgsz-1); /* Round n up to the next multiple of pgsz */ if( n<512 ){ Tcl_AppendResult(interp, "bad 'size' field", (void*)0); return TCL_ERROR; } a = malloc( n ); if( a==0 ){ Tcl_AppendResult(interp, "out of memory", (void*)0); return TCL_ERROR; } memset(a, 0, n); continue; } rc = sscanf(zIn+i, "| page %d offset %d", &j, &k); if( rc==2 ){ iOffset = k; continue; } rc = sscanf(zIn+i,"| %d: %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x", &j, &x[0], &x[1], &x[2], &x[3], &x[4], &x[5], &x[6], &x[7], &x[8], &x[9], &x[10], &x[11], &x[12], &x[13], &x[14], &x[15]); if( rc==17 ){ k = iOffset+j; if( k+16<=n ){ int ii; for(ii=0; ii<16; ii++) a[k+ii] = x[ii]&0xff; } continue; } } Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(a, n)); free(a); return TCL_OK; } /* ** Client data for the autovacuum_pages callback. */ struct AutovacPageData { Tcl_Interp *interp; char *zScript; }; typedef struct AutovacPageData AutovacPageData; /* ** Callback functions for sqlite3_autovacuum_pages */ static unsigned int test_autovacuum_pages_callback( void *pClientData, const char *zSchema, unsigned int nFilePages, unsigned int nFreePages, unsigned int nBytePerPage ){ AutovacPageData *pData = (AutovacPageData*)pClientData; Tcl_DString str; unsigned int x; char zBuf[100]; Tcl_DStringInit(&str); Tcl_DStringAppend(&str, pData->zScript, -1); Tcl_DStringAppendElement(&str, zSchema); sqlite3_snprintf(sizeof(zBuf), zBuf, "%u", nFilePages); Tcl_DStringAppendElement(&str, zBuf); sqlite3_snprintf(sizeof(zBuf), zBuf, "%u", nFreePages); Tcl_DStringAppendElement(&str, zBuf); sqlite3_snprintf(sizeof(zBuf), zBuf, "%u", nBytePerPage); Tcl_DStringAppendElement(&str, zBuf); Tcl_ResetResult(pData->interp); Tcl_Eval(pData->interp, Tcl_DStringValue(&str)); Tcl_DStringFree(&str); x = nFreePages; (void)Tcl_GetIntFromObj(0, Tcl_GetObjResult(pData->interp), (int*)&x); return x; } /* ** Usage: sqlite3_autovacuum_pages DB SCRIPT ** ** Add an autovacuum-pages callback to database connection DB. The callback ** will invoke SCRIPT, after appending parameters. ** ** If SCRIPT is an empty string or is omitted, then the callback is ** cancelled. */ static int SQLITE_TCLAPI test_autovacuum_pages( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ AutovacPageData *pData; sqlite3 *db; int rc; const char *zScript; if( objc!=2 && objc!=3 ){ Tcl_WrongNumArgs(interp, 1, objv, "DB ?SCRIPT?"); return TCL_ERROR; } if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; zScript = objc==3 ? Tcl_GetString(objv[2]) : 0; if( zScript ){ size_t nScript = strlen(zScript); pData = sqlite3_malloc64( sizeof(*pData) + nScript + 1 ); if( pData==0 ){ Tcl_AppendResult(interp, "out of memory", (void*)0); return TCL_ERROR; } pData->interp = interp; pData->zScript = (char*)&pData[1]; memcpy(pData->zScript, zScript, nScript+1); rc = sqlite3_autovacuum_pages(db,test_autovacuum_pages_callback, pData, sqlite3_free); }else{ rc = sqlite3_autovacuum_pages(db, 0, 0, 0); } if( rc ){ char zBuf[1000]; sqlite3_snprintf(sizeof(zBuf), zBuf, "sqlite3_autovacuum_pages() returns %d", rc); Tcl_AppendResult(interp, zBuf, (void*)0); return TCL_ERROR; } return TCL_OK; } /* ** Register commands with the TCL interpreter. */ int Sqlitetest1_Init(Tcl_Interp *interp){ extern int sqlite3_search_count; |
︙ | ︙ | |||
7792 7793 7794 7795 7796 7797 7798 7799 7800 7801 7802 7803 7804 | #ifndef SQLITE_OMIT_GET_TABLE { "sqlite3_get_table_printf", (Tcl_CmdProc*)test_get_table_printf }, #endif { "sqlite3_close", (Tcl_CmdProc*)sqlite_test_close }, { "sqlite3_close_v2", (Tcl_CmdProc*)sqlite_test_close_v2 }, { "sqlite3_create_function", (Tcl_CmdProc*)test_create_function }, { "sqlite3_create_aggregate", (Tcl_CmdProc*)test_create_aggregate }, { "sqlite_register_test_function", (Tcl_CmdProc*)test_register_func }, { "sqlite_abort", (Tcl_CmdProc*)sqlite_abort }, { "sqlite_bind", (Tcl_CmdProc*)test_bind }, { "breakpoint", (Tcl_CmdProc*)test_breakpoint }, { "sqlite3_key", (Tcl_CmdProc*)test_key }, { "sqlite3_rekey", (Tcl_CmdProc*)test_rekey }, | > < > > > > | 8403 8404 8405 8406 8407 8408 8409 8410 8411 8412 8413 8414 8415 8416 8417 8418 8419 8420 8421 8422 8423 8424 8425 8426 8427 8428 8429 8430 8431 8432 8433 8434 8435 8436 8437 8438 8439 8440 8441 8442 8443 8444 8445 8446 8447 8448 8449 8450 8451 8452 8453 8454 8455 8456 8457 8458 | #ifndef SQLITE_OMIT_GET_TABLE { "sqlite3_get_table_printf", (Tcl_CmdProc*)test_get_table_printf }, #endif { "sqlite3_close", (Tcl_CmdProc*)sqlite_test_close }, { "sqlite3_close_v2", (Tcl_CmdProc*)sqlite_test_close_v2 }, { "sqlite3_create_function", (Tcl_CmdProc*)test_create_function }, { "sqlite3_create_aggregate", (Tcl_CmdProc*)test_create_aggregate }, { "sqlite3_drop_modules", (Tcl_CmdProc*)test_drop_modules }, { "sqlite_register_test_function", (Tcl_CmdProc*)test_register_func }, { "sqlite_abort", (Tcl_CmdProc*)sqlite_abort }, { "sqlite_bind", (Tcl_CmdProc*)test_bind }, { "breakpoint", (Tcl_CmdProc*)test_breakpoint }, { "sqlite3_key", (Tcl_CmdProc*)test_key }, { "sqlite3_rekey", (Tcl_CmdProc*)test_rekey }, { "sqlite3_interrupt", (Tcl_CmdProc*)test_interrupt }, { "sqlite_delete_function", (Tcl_CmdProc*)delete_function }, { "sqlite_delete_collation", (Tcl_CmdProc*)delete_collation }, { "sqlite3_get_autocommit", (Tcl_CmdProc*)get_autocommit }, { "sqlite3_busy_timeout", (Tcl_CmdProc*)test_busy_timeout }, { "printf", (Tcl_CmdProc*)test_printf }, { "sqlite3IoTrace", (Tcl_CmdProc*)test_io_trace }, { "clang_sanitize_address", (Tcl_CmdProc*)clang_sanitize_address }, }; static struct { char *zName; Tcl_ObjCmdProc *xProc; void *clientData; } aObjCmd[] = { { "sqlite3_db_config", test_sqlite3_db_config, 0 }, { "sqlite3_txn_state", test_sqlite3_txn_state, 0 }, { "bad_behavior", test_bad_behavior, (void*)&iZero }, { "register_dbstat_vtab", test_register_dbstat_vtab }, { "sqlite3_connection_pointer", get_sqlite_pointer, 0 }, { "intarray_addr", test_intarray_addr, 0 }, { "int64array_addr", test_int64array_addr, 0 }, { "doublearray_addr", test_doublearray_addr, 0 }, { "textarray_addr", test_textarray_addr, 0 }, { "sqlite3_bind_int", test_bind_int, 0 }, { "sqlite3_bind_zeroblob", test_bind_zeroblob, 0 }, { "sqlite3_bind_zeroblob64", test_bind_zeroblob64, 0 }, { "sqlite3_bind_int64", test_bind_int64, 0 }, { "sqlite3_bind_double", test_bind_double, 0 }, { "sqlite3_bind_null", test_bind_null ,0 }, { "sqlite3_bind_text", test_bind_text ,0 }, { "sqlite3_bind_text16", test_bind_text16 ,0 }, { "sqlite3_bind_blob", test_bind_blob ,0 }, #ifndef SQLITE_OMIT_VIRTUALTABLE { "sqlite3_carray_bind", test_carray_bind ,0 }, #endif { "sqlite3_bind_parameter_count", test_bind_parameter_count, 0}, { "sqlite3_bind_parameter_name", test_bind_parameter_name, 0}, { "sqlite3_bind_parameter_index", test_bind_parameter_index, 0}, { "sqlite3_clear_bindings", test_clear_bindings, 0}, { "sqlite3_sleep", test_sleep, 0}, { "sqlite3_errcode", test_errcode ,0 }, { "sqlite3_extended_errcode", test_ex_errcode ,0 }, |
︙ | ︙ | |||
7865 7866 7867 7868 7869 7870 7871 7872 7873 7874 7875 7876 7877 7878 7879 7880 7881 7882 7883 7884 7885 7886 7887 7888 7889 7890 7891 7892 7893 7894 7895 7896 7897 7898 7899 7900 | { "sqlite3_sql", test_sql ,0 }, { "sqlite3_expanded_sql", test_ex_sql ,0 }, #ifdef SQLITE_ENABLE_NORMALIZE { "sqlite3_normalized_sql", test_norm_sql ,0 }, #endif { "sqlite3_next_stmt", test_next_stmt ,0 }, { "sqlite3_stmt_readonly", test_stmt_readonly ,0 }, { "sqlite3_stmt_busy", test_stmt_busy ,0 }, { "uses_stmt_journal", uses_stmt_journal ,0 }, { "sqlite3_release_memory", test_release_memory, 0}, { "sqlite3_db_release_memory", test_db_release_memory, 0}, { "sqlite3_db_cacheflush", test_db_cacheflush, 0}, { "sqlite3_system_errno", test_system_errno, 0}, { "sqlite3_db_filename", test_db_filename, 0}, { "sqlite3_db_readonly", test_db_readonly, 0}, { "sqlite3_soft_heap_limit", test_soft_heap_limit, 0}, { "sqlite3_thread_cleanup", test_thread_cleanup, 0}, { "sqlite3_pager_refcounts", test_pager_refcounts, 0}, { "sqlite3_load_extension", test_load_extension, 0}, { "sqlite3_enable_load_extension", test_enable_load, 0}, { "sqlite3_extended_result_codes", test_extended_result_codes, 0}, { "sqlite3_limit", test_limit, 0}, { "dbconfig_maindbname_icecube", test_dbconfig_maindbname_icecube }, { "save_prng_state", save_prng_state, 0 }, { "restore_prng_state", restore_prng_state, 0 }, { "reset_prng_state", reset_prng_state, 0 }, { "database_never_corrupt", database_never_corrupt, 0}, { "database_may_be_corrupt", database_may_be_corrupt, 0}, { "optimization_control", optimization_control,0}, #if SQLITE_OS_WIN { "lock_win32_file", win32_file_lock, 0 }, { "exists_win32_path", win32_exists_path, 0 }, { "find_win32_file", win32_find_file, 0 }, | > > > > > | 8480 8481 8482 8483 8484 8485 8486 8487 8488 8489 8490 8491 8492 8493 8494 8495 8496 8497 8498 8499 8500 8501 8502 8503 8504 8505 8506 8507 8508 8509 8510 8511 8512 8513 8514 8515 8516 8517 8518 8519 8520 | { "sqlite3_sql", test_sql ,0 }, { "sqlite3_expanded_sql", test_ex_sql ,0 }, #ifdef SQLITE_ENABLE_NORMALIZE { "sqlite3_normalized_sql", test_norm_sql ,0 }, #endif { "sqlite3_next_stmt", test_next_stmt ,0 }, { "sqlite3_stmt_readonly", test_stmt_readonly ,0 }, { "sqlite3_stmt_isexplain", test_stmt_isexplain,0 }, { "sqlite3_stmt_busy", test_stmt_busy ,0 }, { "uses_stmt_journal", uses_stmt_journal ,0 }, { "sqlite3_release_memory", test_release_memory, 0}, { "sqlite3_db_release_memory", test_db_release_memory, 0}, { "sqlite3_db_cacheflush", test_db_cacheflush, 0}, { "sqlite3_system_errno", test_system_errno, 0}, { "sqlite3_db_filename", test_db_filename, 0}, { "sqlite3_db_readonly", test_db_readonly, 0}, { "sqlite3_soft_heap_limit", test_soft_heap_limit, 0}, { "sqlite3_soft_heap_limit64", test_soft_heap_limit, 0}, { "sqlite3_hard_heap_limit64", test_hard_heap_limit, 0}, { "sqlite3_thread_cleanup", test_thread_cleanup, 0}, { "sqlite3_pager_refcounts", test_pager_refcounts, 0}, { "sqlite3_load_extension", test_load_extension, 0}, { "sqlite3_enable_load_extension", test_enable_load, 0}, { "sqlite3_extended_result_codes", test_extended_result_codes, 0}, { "sqlite3_limit", test_limit, 0}, { "dbconfig_maindbname_icecube", test_dbconfig_maindbname_icecube }, { "save_prng_state", save_prng_state, 0 }, { "restore_prng_state", restore_prng_state, 0 }, { "reset_prng_state", reset_prng_state, 0 }, { "prng_seed", prng_seed, 0 }, { "extra_schema_checks", extra_schema_checks, 0}, { "database_never_corrupt", database_never_corrupt, 0}, { "database_may_be_corrupt", database_may_be_corrupt, 0}, { "optimization_control", optimization_control,0}, #if SQLITE_OS_WIN { "lock_win32_file", win32_file_lock, 0 }, { "exists_win32_path", win32_exists_path, 0 }, { "find_win32_file", win32_find_file, 0 }, |
︙ | ︙ | |||
7956 7957 7958 7959 7960 7961 7962 7963 7964 7965 7966 7967 7968 7969 7970 | { "file_control_win32_av_retry", file_control_win32_av_retry, 0 }, { "file_control_win32_get_handle", file_control_win32_get_handle, 0 }, { "file_control_win32_set_handle", file_control_win32_set_handle, 0 }, #endif { "file_control_persist_wal", file_control_persist_wal, 0 }, { "file_control_powersafe_overwrite",file_control_powersafe_overwrite,0}, { "file_control_vfsname", file_control_vfsname, 0 }, { "file_control_tempfilename", file_control_tempfilename, 0 }, { "sqlite3_vfs_list", vfs_list, 0 }, { "sqlite3_create_function_v2", test_create_function_v2, 0 }, /* Functions from os.h */ #ifndef SQLITE_OMIT_UTF16 { "add_test_collate", test_collate, 0 }, { "add_test_collate_needed", test_collate_needed, 0 }, | > > | 8576 8577 8578 8579 8580 8581 8582 8583 8584 8585 8586 8587 8588 8589 8590 8591 8592 | { "file_control_win32_av_retry", file_control_win32_av_retry, 0 }, { "file_control_win32_get_handle", file_control_win32_get_handle, 0 }, { "file_control_win32_set_handle", file_control_win32_set_handle, 0 }, #endif { "file_control_persist_wal", file_control_persist_wal, 0 }, { "file_control_powersafe_overwrite",file_control_powersafe_overwrite,0}, { "file_control_vfsname", file_control_vfsname, 0 }, { "file_control_reservebytes", file_control_reservebytes, 0 }, { "file_control_tempfilename", file_control_tempfilename, 0 }, { "file_control_external_reader", file_control_external_reader, 0 }, { "sqlite3_vfs_list", vfs_list, 0 }, { "sqlite3_create_function_v2", test_create_function_v2, 0 }, /* Functions from os.h */ #ifndef SQLITE_OMIT_UTF16 { "add_test_collate", test_collate, 0 }, { "add_test_collate_needed", test_collate_needed, 0 }, |
︙ | ︙ | |||
8025 8026 8027 8028 8029 8030 8031 8032 8033 8034 8035 8036 8037 8038 8039 8040 8041 8042 8043 8044 8045 8046 8047 | { "sqlite3_snapshot_cmp_blob", test_snapshot_cmp_blob, 0 }, #endif { "sqlite3_delete_database", test_delete_database, 0 }, { "sqlite3_wal_info", test_wal_info, 0 }, { "atomic_batch_write", test_atomic_batch_write, 0 }, { "sqlite3_mmap_warm", test_mmap_warm, 0 }, { "sqlite3_config_sorterref", test_config_sorterref, 0 }, { "decode_hexdb", test_decode_hexdb, 0 }, }; static int bitmask_size = sizeof(Bitmask)*8; static int longdouble_size = sizeof(LONGDOUBLE_TYPE); 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; extern int sqlite3_pager_readdb_count; extern int sqlite3_pager_writedb_count; extern int sqlite3_pager_writej_count; #if SQLITE_OS_WIN extern LONG volatile sqlite3_os_type; #endif #ifdef SQLITE_DEBUG | > > > > | < < < | 8647 8648 8649 8650 8651 8652 8653 8654 8655 8656 8657 8658 8659 8660 8661 8662 8663 8664 8665 8666 8667 8668 8669 8670 8671 8672 8673 8674 8675 8676 8677 8678 8679 8680 8681 8682 8683 8684 8685 8686 8687 8688 8689 | { "sqlite3_snapshot_cmp_blob", test_snapshot_cmp_blob, 0 }, #endif { "sqlite3_delete_database", test_delete_database, 0 }, { "sqlite3_wal_info", test_wal_info, 0 }, { "atomic_batch_write", test_atomic_batch_write, 0 }, { "sqlite3_mmap_warm", test_mmap_warm, 0 }, { "sqlite3_config_sorterref", test_config_sorterref, 0 }, { "sqlite3_autovacuum_pages", test_autovacuum_pages, 0 }, { "decode_hexdb", test_decode_hexdb, 0 }, { "test_write_db", test_write_db, 0 }, { "sqlite3_register_cksumvfs", test_register_cksumvfs, 0 }, { "sqlite3_unregister_cksumvfs", test_unregister_cksumvfs, 0 }, }; static int bitmask_size = sizeof(Bitmask)*8; static int longdouble_size = sizeof(LONGDOUBLE_TYPE); 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; extern int sqlite3_pager_readdb_count; extern int sqlite3_pager_writedb_count; extern int sqlite3_pager_writej_count; #if SQLITE_OS_WIN extern LONG volatile sqlite3_os_type; #endif #ifdef SQLITE_DEBUG extern u32 sqlite3WhereTrace; extern int sqlite3OSTrace; extern int sqlite3WalTrace; #endif #ifdef SQLITE_TEST #ifdef SQLITE_ENABLE_FTS3 extern int sqlite3_fts3_enable_parentheses; #endif #endif for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){ Tcl_CreateCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0); } for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){ Tcl_CreateObjCommand(interp, aObjCmd[i].zName, aObjCmd[i].xProc, aObjCmd[i].clientData, 0); |
︙ | ︙ | |||
8139 8140 8141 8142 8143 8144 8145 | Tcl_LinkVar(interp, "longdouble_size", (char*)&longdouble_size, TCL_LINK_INT|TCL_LINK_READ_ONLY); Tcl_LinkVar(interp, "sqlite_sync_count", (char*)&sqlite3_sync_count, TCL_LINK_INT); Tcl_LinkVar(interp, "sqlite_fullsync_count", (char*)&sqlite3_fullsync_count, TCL_LINK_INT); #if defined(SQLITE_ENABLE_SELECTTRACE) | | | 8762 8763 8764 8765 8766 8767 8768 8769 8770 8771 8772 8773 8774 8775 8776 8777 | Tcl_LinkVar(interp, "longdouble_size", (char*)&longdouble_size, TCL_LINK_INT|TCL_LINK_READ_ONLY); Tcl_LinkVar(interp, "sqlite_sync_count", (char*)&sqlite3_sync_count, TCL_LINK_INT); Tcl_LinkVar(interp, "sqlite_fullsync_count", (char*)&sqlite3_fullsync_count, TCL_LINK_INT); #if defined(SQLITE_ENABLE_SELECTTRACE) Tcl_LinkVar(interp, "sqlite3_unsupported_selecttrace", (char*)&sqlite3SelectTrace, TCL_LINK_INT); #endif #if defined(SQLITE_ENABLE_FTS3) && defined(SQLITE_TEST) Tcl_LinkVar(interp, "sqlite_fts3_enable_parentheses", (char*)&sqlite3_fts3_enable_parentheses, TCL_LINK_INT); #endif return TCL_OK; } |
Changes to src/test4.c.
︙ | ︙ | |||
28 29 30 31 32 33 34 | /* ** Each thread is controlled by an instance of the following ** structure. */ typedef struct Thread Thread; struct Thread { | | | | 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | /* ** 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 leader and read-only ** to the thread. */ char *zFilename; /* Name of database file */ void (*xOp)(Thread*); /* next operation to do */ char *zArg; /* argument usable by xOp */ int opnum; /* Operation number */ int busy; /* True if this thread is in use */ /* The next group of fields are writable by the thread but read-only to the ** leader. */ int completed; /* Number of operations completed */ sqlite3 *db; /* Open database */ sqlite3_stmt *pStmt; /* Pending operation */ char *zErr; /* operation error */ char *zStaticErr; /* Static error message */ int rc; /* operation return code */ int argc; /* number of columns in result */ |
︙ | ︙ | |||
60 61 62 63 64 65 66 | #define N_THREAD 26 static Thread threadset[N_THREAD]; /* ** The main loop for a thread. Threads use busy waiting. */ | | | 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | #define N_THREAD 26 static Thread threadset[N_THREAD]; /* ** The main loop for a thread. Threads use busy waiting. */ static void *test_thread_main(void *pArg){ Thread *p = (Thread*)pArg; if( p->db ){ sqlite3_close(p->db); } sqlite3_open(p->zFilename, &p->db); if( SQLITE_OK!=sqlite3_errcode(p->db) ){ p->zErr = strdup(sqlite3_errmsg(p->db)); |
︙ | ︙ | |||
147 148 149 150 151 152 153 | return TCL_ERROR; } threadset[i].busy = 1; sqlite3_free(threadset[i].zFilename); threadset[i].zFilename = sqlite3_mprintf("%s", argv[2]); threadset[i].opnum = 1; threadset[i].completed = 0; | | | | 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 | return TCL_ERROR; } threadset[i].busy = 1; sqlite3_free(threadset[i].zFilename); threadset[i].zFilename = sqlite3_mprintf("%s", argv[2]); threadset[i].opnum = 1; threadset[i].completed = 0; rc = pthread_create(&x, 0, test_thread_main, &threadset[i]); if( rc ){ Tcl_AppendResult(interp, "failed to create the thread", 0); sqlite3_free(threadset[i].zFilename); threadset[i].busy = 0; return TCL_ERROR; } pthread_detach(x); return TCL_OK; } /* ** Wait for a thread to reach its idle state. */ static void test_thread_wait(Thread *p){ while( p->opnum>p->completed ) sched_yield(); } /* ** Usage: thread_wait ID ** ** Wait on thread ID to reach its idle state. |
︙ | ︙ | |||
189 190 191 192 193 194 195 | } 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; } | | | | | | 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 | } 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; } test_thread_wait(&threadset[i]); return TCL_OK; } /* ** Stop a thread. */ static void test_stop_thread(Thread *p){ test_thread_wait(p); p->xOp = 0; p->opnum++; test_thread_wait(p); sqlite3_free(p->zArg); p->zArg = 0; sqlite3_free(p->zFilename); p->zFilename = 0; p->busy = 0; } |
︙ | ︙ | |||
229 230 231 232 233 234 235 | if( argc!=2 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " ID", 0); return TCL_ERROR; } if( argv[1][0]=='*' && argv[1][1]==0 ){ for(i=0; i<N_THREAD; i++){ | | | | 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 | if( argc!=2 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " ID", 0); return TCL_ERROR; } if( argv[1][0]=='*' && argv[1][1]==0 ){ for(i=0; i<N_THREAD; i++){ if( threadset[i].busy ) test_stop_thread(&threadset[i]); } }else{ 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; } test_stop_thread(&threadset[i]); } return TCL_OK; } /* ** Usage: thread_argc ID ** |
︙ | ︙ | |||
269 270 271 272 273 274 275 | } 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; } | | | 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 | } 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; } test_thread_wait(&threadset[i]); sqlite3_snprintf(sizeof(zBuf), zBuf, "%d", threadset[i].argc); Tcl_AppendResult(interp, zBuf, 0); return TCL_OK; } /* ** Usage: thread_argv ID N |
︙ | ︙ | |||
302 303 304 305 306 307 308 | 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; } if( Tcl_GetInt(interp, argv[2], &n) ) return TCL_ERROR; | | | 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 | 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; } if( Tcl_GetInt(interp, argv[2], &n) ) return TCL_ERROR; test_thread_wait(&threadset[i]); if( n<0 || n>=threadset[i].argc ){ Tcl_AppendResult(interp, "column number out of range", 0); return TCL_ERROR; } Tcl_AppendResult(interp, threadset[i].argv[n], 0); return TCL_OK; } |
︙ | ︙ | |||
338 339 340 341 342 343 344 | 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; } if( Tcl_GetInt(interp, argv[2], &n) ) return TCL_ERROR; | | | 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 | 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; } if( Tcl_GetInt(interp, argv[2], &n) ) return TCL_ERROR; test_thread_wait(&threadset[i]); if( n<0 || n>=threadset[i].argc ){ Tcl_AppendResult(interp, "column number out of range", 0); return TCL_ERROR; } Tcl_AppendResult(interp, threadset[i].colv[n], 0); return TCL_OK; } |
︙ | ︙ | |||
373 374 375 376 377 378 379 | } 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; } | | | 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 | } 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; } test_thread_wait(&threadset[i]); zName = sqlite3ErrName(threadset[i].rc); Tcl_AppendResult(interp, zName, 0); return TCL_OK; } /* ** Usage: thread_error ID |
︙ | ︙ | |||
404 405 406 407 408 409 410 | } 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; } | | | 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 | } 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; } test_thread_wait(&threadset[i]); Tcl_AppendResult(interp, threadset[i].zErr, 0); return TCL_OK; } /* ** This procedure runs in the thread to compile an SQL statement. */ |
︙ | ︙ | |||
448 449 450 451 452 453 454 | } 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; } | | | 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 | } 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; } test_thread_wait(&threadset[i]); threadset[i].xOp = do_compile; sqlite3_free(threadset[i].zArg); threadset[i].zArg = sqlite3_mprintf("%s", argv[2]); threadset[i].opnum++; return TCL_OK; } |
︙ | ︙ | |||
501 502 503 504 505 506 507 | } 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; } | | | 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 | } 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; } test_thread_wait(&threadset[i]); threadset[i].xOp = do_step; threadset[i].opnum++; return TCL_OK; } /* ** This procedure runs in the thread to finalize a virtual machine. |
︙ | ︙ | |||
543 544 545 546 547 548 549 | } 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; } | | | 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 | } 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; } test_thread_wait(&threadset[i]); threadset[i].xOp = do_finalize; sqlite3_free(threadset[i].zArg); threadset[i].zArg = 0; threadset[i].opnum++; return TCL_OK; } |
︙ | ︙ | |||
575 576 577 578 579 580 581 | } 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; } | | | | 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 | } 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; } test_thread_wait(&threadset[i]); j = parse_thread_id(interp, argv[2]); if( j<0 ) return TCL_ERROR; if( !threadset[j].busy ){ Tcl_AppendResult(interp, "no such thread", 0); return TCL_ERROR; } test_thread_wait(&threadset[j]); temp = threadset[i].db; threadset[i].db = threadset[j].db; threadset[j].db = temp; return TCL_OK; } /* |
︙ | ︙ | |||
616 617 618 619 620 621 622 | } 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; } | | | 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 | } 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; } test_thread_wait(&threadset[i]); sqlite3TestMakePointerStr(interp, zBuf, threadset[i].db); threadset[i].db = 0; Tcl_AppendResult(interp, zBuf, (char*)0); return TCL_OK; } /* |
︙ | ︙ | |||
647 648 649 650 651 652 653 | } 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; } | | | 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 | } 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; } test_thread_wait(&threadset[i]); assert( !threadset[i].db ); threadset[i].db = (sqlite3*)sqlite3TestTextToPtr(argv[2]); return TCL_OK; } /* ** Usage: thread_stmt_get ID |
︙ | ︙ | |||
679 680 681 682 683 684 685 | } 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; } | | | 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 | } 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; } test_thread_wait(&threadset[i]); sqlite3TestMakePointerStr(interp, zBuf, threadset[i].pStmt); threadset[i].pStmt = 0; Tcl_AppendResult(interp, zBuf, (char*)0); return TCL_OK; } /* |
︙ | ︙ |
Changes to src/test6.c.
︙ | ︙ | |||
546 547 548 549 550 551 552 | return g.iDeviceCharacteristics; } /* ** Pass-throughs for WAL support. */ static int cfShmLock(sqlite3_file *pFile, int ofst, int n, int flags){ | | > | > | > | > | 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 | return g.iDeviceCharacteristics; } /* ** Pass-throughs for WAL support. */ static int cfShmLock(sqlite3_file *pFile, int ofst, int n, int flags){ sqlite3_file *pReal = ((CrashFile*)pFile)->pRealFile; return pReal->pMethods->xShmLock(pReal, ofst, n, flags); } static void cfShmBarrier(sqlite3_file *pFile){ sqlite3_file *pReal = ((CrashFile*)pFile)->pRealFile; pReal->pMethods->xShmBarrier(pReal); } static int cfShmUnmap(sqlite3_file *pFile, int delFlag){ sqlite3_file *pReal = ((CrashFile*)pFile)->pRealFile; return pReal->pMethods->xShmUnmap(pReal, delFlag); } static int cfShmMap( sqlite3_file *pFile, /* Handle open on database file */ int iRegion, /* Region to retrieve */ int sz, /* Size of regions */ int w, /* True to extend file if necessary */ void volatile **pp /* OUT: Mapped memory */ ){ sqlite3_file *pReal = ((CrashFile*)pFile)->pRealFile; return pReal->pMethods->xShmMap(pReal, iRegion, sz, w, pp); } static const sqlite3_io_methods CrashFileVtab = { 2, /* iVersion */ cfClose, /* xClose */ cfRead, /* xRead */ cfWrite, /* xWrite */ |
︙ | ︙ |
Changes to src/test8.c.
︙ | ︙ | |||
337 338 339 340 341 342 343 | sqlite3 *db ){ int rc = SQLITE_OK; if( pVtab->zTableName ){ sqlite3_stmt *pStmt = 0; rc = sqlite3_prepare(db, | | | 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 | sqlite3 *db ){ int rc = SQLITE_OK; if( pVtab->zTableName ){ sqlite3_stmt *pStmt = 0; rc = sqlite3_prepare(db, "SELECT sql FROM sqlite_schema WHERE type = 'table' AND name = ?", -1, &pStmt, 0); if( rc==SQLITE_OK ){ sqlite3_bind_text(pStmt, 1, pVtab->zTableName, -1, 0); if( sqlite3_step(pStmt)==SQLITE_ROW ){ int rc2; const char *zCreateTable = (const char *)sqlite3_column_text(pStmt, 0); rc = sqlite3_declare_vtab(db, zCreateTable); |
︙ | ︙ | |||
385 386 387 388 389 390 391 392 393 394 395 396 397 398 | sqlite3_free(p); return 0; } typedef struct EchoModule EchoModule; struct EchoModule { Tcl_Interp *interp; }; /* ** This function is called to do the work of the xConnect() method - ** to allocate the required in-memory structures for a newly connected ** virtual table. */ | > | 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 | sqlite3_free(p); return 0; } typedef struct EchoModule EchoModule; struct EchoModule { Tcl_Interp *interp; sqlite3 *db; }; /* ** This function is called to do the work of the xConnect() method - ** to allocate the required in-memory structures for a newly connected ** virtual table. */ |
︙ | ︙ | |||
1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 | /* ** 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. */ static int SQLITE_TCLAPI register_echo_module( | > > > | 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 | /* ** 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){ EchoModule *pMod = (EchoModule*)p; sqlite3_create_function(pMod->db, "function_that_does_not_exist_0982ma98", SQLITE_ANY, 1, 0, 0, 0, 0); sqlite3_free(p); } /* ** Register the echo virtual table module. */ static int SQLITE_TCLAPI register_echo_module( |
︙ | ︙ | |||
1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 | return TCL_ERROR; } if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; /* Virtual table module "echo" */ pMod = sqlite3_malloc(sizeof(EchoModule)); pMod->interp = interp; rc = sqlite3_create_module_v2( db, "echo", &echoModule, (void*)pMod, moduleDestroy ); /* Virtual table module "echo_v2" */ if( rc==SQLITE_OK ){ 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; | > > | 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 | return TCL_ERROR; } if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; /* Virtual table module "echo" */ pMod = sqlite3_malloc(sizeof(EchoModule)); pMod->interp = interp; pMod->db = db; rc = sqlite3_create_module_v2( db, "echo", &echoModule, (void*)pMod, moduleDestroy ); /* Virtual table module "echo_v2" */ if( rc==SQLITE_OK ){ pMod = sqlite3_malloc(sizeof(EchoModule)); pMod->interp = interp; pMod->db = db; rc = sqlite3_create_module_v2(db, "echo_v2", &echoModuleV2, (void*)pMod, moduleDestroy ); } Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_STATIC); return TCL_OK; |
︙ | ︙ |
Changes to src/test_config.c.
︙ | ︙ | |||
60 61 62 63 64 65 66 67 68 69 70 71 72 73 | #endif #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 | > > > > > > > | 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 | #endif #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 #ifdef CONFIG_SLOWDOWN_FACTOR Tcl_SetVar2(interp, "sqlite_options","configslower", STRINGVALUE(CONFIG_SLOWDOWN_FACTOR),TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options","configslower","1.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 |
︙ | ︙ | |||
144 145 146 147 148 149 150 | #ifdef SQLITE_ENABLE_HIDDEN_COLUMNS Tcl_SetVar2(interp, "sqlite_options", "hiddencolumns", "1", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "hiddencolumns", "0", TCL_GLOBAL_ONLY); #endif | | > > > > > > | 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 | #ifdef SQLITE_ENABLE_HIDDEN_COLUMNS Tcl_SetVar2(interp, "sqlite_options", "hiddencolumns", "1", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "hiddencolumns", "0", TCL_GLOBAL_ONLY); #endif #ifndef SQLITE_OMIT_DESERIALIZE Tcl_SetVar2(interp, "sqlite_options", "deserialize", "1", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "deserialize", "0", TCL_GLOBAL_ONLY); #endif #ifdef SQLITE_ENABLE_MATH_FUNCTIONS Tcl_SetVar2(interp, "sqlite_options", "mathlib", "1", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "mathlib", "0", TCL_GLOBAL_ONLY); #endif #ifdef SQLITE_ENABLE_MEMSYS3 Tcl_SetVar2(interp, "sqlite_options", "mem3", "1", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "mem3", "0", TCL_GLOBAL_ONLY); #endif |
︙ | ︙ | |||
215 216 217 218 219 220 221 222 223 224 225 226 227 228 | #endif #ifdef SQLITE_ENABLE_ATOMIC_WRITE Tcl_SetVar2(interp, "sqlite_options", "atomicwrite", "1", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "atomicwrite", "0", TCL_GLOBAL_ONLY); #endif #ifdef SQLITE_ENABLE_JSON1 Tcl_SetVar2(interp, "sqlite_options", "json1", "1", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "json1", "0", TCL_GLOBAL_ONLY); #endif | > > > > > > < < < < | 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 | #endif #ifdef SQLITE_ENABLE_ATOMIC_WRITE Tcl_SetVar2(interp, "sqlite_options", "atomicwrite", "1", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "atomicwrite", "0", TCL_GLOBAL_ONLY); #endif #ifdef SQLITE_ENABLE_GEOPOLY Tcl_SetVar2(interp, "sqlite_options", "geopoly", "1", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "geopoly", "0", TCL_GLOBAL_ONLY); #endif #ifdef SQLITE_ENABLE_JSON1 Tcl_SetVar2(interp, "sqlite_options", "json1", "1", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "json1", "0", TCL_GLOBAL_ONLY); #endif Tcl_SetVar2(interp, "sqlite_options", "has_codec", "0", TCL_GLOBAL_ONLY); #ifdef SQLITE_LIKE_DOESNT_MATCH_BLOBS Tcl_SetVar2(interp, "sqlite_options", "like_match_blobs", "0", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "like_match_blobs", "1", TCL_GLOBAL_ONLY); #endif |
︙ | ︙ | |||
570 571 572 573 574 575 576 | #ifdef SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS Tcl_SetVar2(interp, "sqlite_options", "schema_version", "0", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "schema_version", "1", TCL_GLOBAL_ONLY); #endif | | < < < < < < | 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 | #ifdef SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS Tcl_SetVar2(interp, "sqlite_options", "schema_version", "0", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "schema_version", "1", TCL_GLOBAL_ONLY); #endif #if defined(SQLITE_ENABLE_SESSION) && defined(SQLITE_ENABLE_PREUPDATE_HOOK) Tcl_SetVar2(interp, "sqlite_options", "session", "1", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "session", "0", TCL_GLOBAL_ONLY); #endif #ifdef SQLITE_ENABLE_STAT4 Tcl_SetVar2(interp, "sqlite_options", "stat4", "1", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "stat4", "0", TCL_GLOBAL_ONLY); #endif #if defined(SQLITE_ENABLE_STMTVTAB) && !defined(SQLITE_OMIT_VIRTUALTABLE) Tcl_SetVar2(interp, "sqlite_options", "stmtvtab", "1", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "stmtvtab", "0", TCL_GLOBAL_ONLY); #endif #ifdef SQLITE_ENABLE_STMT_SCANSTATUS |
︙ | ︙ |
Changes to src/test_demovfs.c.
︙ | ︙ | |||
236 237 238 239 240 241 242 243 244 245 246 247 248 249 | return SQLITE_IOERR_READ; } nRead = read(p->fd, zBuf, iAmt); if( nRead==iAmt ){ return SQLITE_OK; }else if( nRead>=0 ){ return SQLITE_IOERR_SHORT_READ; } return SQLITE_IOERR_READ; } /* | > > > | 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 | return SQLITE_IOERR_READ; } nRead = read(p->fd, zBuf, iAmt); if( nRead==iAmt ){ return SQLITE_OK; }else if( nRead>=0 ){ if( nRead<iAmt ){ memset(&((char*)zBuf)[nRead], 0, iAmt-nRead); } return SQLITE_IOERR_SHORT_READ; } return SQLITE_IOERR_READ; } /* |
︙ | ︙ | |||
365 366 367 368 369 370 371 | return SQLITE_OK; } /* ** No xFileControl() verbs are implemented by this VFS. */ static int demoFileControl(sqlite3_file *pFile, int op, void *pArg){ | | | 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 | return SQLITE_OK; } /* ** No xFileControl() verbs are implemented by this VFS. */ static int demoFileControl(sqlite3_file *pFile, int op, void *pArg){ return SQLITE_NOTFOUND; } /* ** The xSectorSize() and xDeviceCharacteristics() methods. These two ** may return special values allowing SQLite to optimize file-system ** access to some extent. But it is also safe to simply return 0. */ |
︙ | ︙ |
Changes to src/test_devsym.c.
︙ | ︙ | |||
187 188 189 190 191 192 193 | } /* ** Shared-memory methods are all pass-thrus. */ static int devsymShmLock(sqlite3_file *pFile, int ofst, int n, int flags){ devsym_file *p = (devsym_file *)pFile; | | | | | | 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 | } /* ** Shared-memory methods are all pass-thrus. */ static int devsymShmLock(sqlite3_file *pFile, int ofst, int n, int flags){ devsym_file *p = (devsym_file *)pFile; return p->pReal->pMethods->xShmLock(p->pReal, ofst, n, flags); } static int devsymShmMap( sqlite3_file *pFile, int iRegion, int szRegion, int isWrite, void volatile **pp ){ devsym_file *p = (devsym_file *)pFile; return p->pReal->pMethods->xShmMap(p->pReal, iRegion, szRegion, isWrite, pp); } static void devsymShmBarrier(sqlite3_file *pFile){ devsym_file *p = (devsym_file *)pFile; p->pReal->pMethods->xShmBarrier(p->pReal); } static int devsymShmUnmap(sqlite3_file *pFile, int delFlag){ devsym_file *p = (devsym_file *)pFile; return p->pReal->pMethods->xShmUnmap(p->pReal, delFlag); } /* ** Open an devsym file handle. */ |
︙ | ︙ | |||
501 502 503 504 505 506 507 508 509 510 511 512 513 514 | }else{ g.iSectorSize = 512; } } void devsym_unregister(){ sqlite3_vfs_unregister(&devsym_vfs); g.pVfs = 0; g.iDeviceChar = 0; g.iSectorSize = 0; } void devsym_crash_on_write(int nWrite){ if( g.pVfs==0 ){ | > | 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 | }else{ g.iSectorSize = 512; } } void devsym_unregister(){ sqlite3_vfs_unregister(&devsym_vfs); sqlite3_vfs_unregister(&writecrash_vfs); g.pVfs = 0; g.iDeviceChar = 0; g.iSectorSize = 0; } void devsym_crash_on_write(int nWrite){ if( g.pVfs==0 ){ |
︙ | ︙ |
Changes to src/test_fs.c.
︙ | ︙ | |||
125 126 127 128 129 130 131 | }; struct FsdirCsr { sqlite3_vtab_cursor base; char *zDir; /* Buffer containing directory scanned */ DIR *pDir; /* Open directory */ sqlite3_int64 iRowid; | | | 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 | }; struct FsdirCsr { sqlite3_vtab_cursor base; char *zDir; /* Buffer containing directory scanned */ DIR *pDir; /* Open directory */ sqlite3_int64 iRowid; struct DIRENT *pEntry; }; /* ** This function is the implementation of both the xConnect and xCreate ** methods of the fsdir virtual table. ** ** The argv[] array contains the following: |
︙ | ︙ | |||
232 233 234 235 236 237 238 | /* ** Skip the cursor to the next entry. */ static int fsdirNext(sqlite3_vtab_cursor *cur){ FsdirCsr *pCsr = (FsdirCsr*)cur; if( pCsr->pDir ){ | < < | | < < < < < < | 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 | /* ** Skip the cursor to the next entry. */ static int fsdirNext(sqlite3_vtab_cursor *cur){ FsdirCsr *pCsr = (FsdirCsr*)cur; if( pCsr->pDir ){ pCsr->pEntry = readdir(pCsr->pDir); if( pCsr->pEntry==0 ){ closedir(pCsr->pDir); pCsr->pDir = 0; } pCsr->iRowid++; } return SQLITE_OK; |
︙ | ︙ | |||
304 305 306 307 308 309 310 | FsdirCsr *pCsr = (FsdirCsr*)cur; switch( i ){ case 0: /* dir */ sqlite3_result_text(ctx, pCsr->zDir, -1, SQLITE_STATIC); break; case 1: /* name */ | | | 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 | FsdirCsr *pCsr = (FsdirCsr*)cur; switch( i ){ case 0: /* dir */ sqlite3_result_text(ctx, pCsr->zDir, -1, SQLITE_STATIC); break; case 1: /* name */ sqlite3_result_text(ctx, pCsr->pEntry->d_name, -1, SQLITE_TRANSIENT); break; default: assert( 0 ); } return SQLITE_OK; |
︙ | ︙ | |||
740 741 742 743 744 745 746 | int n; fd = open(zFile, O_RDONLY); if( fd<0 ) return SQLITE_IOERR; fstat(fd, &sbuf); if( sbuf.st_size>=pCur->nAlloc ){ | | | 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 | int n; fd = open(zFile, O_RDONLY); if( fd<0 ) return SQLITE_IOERR; fstat(fd, &sbuf); if( sbuf.st_size>=pCur->nAlloc ){ sqlite3_int64 nNew = sbuf.st_size*2; char *zNew; if( nNew<1024 ) nNew = 1024; zNew = sqlite3Realloc(pCur->zBuf, nNew); if( zNew==0 ){ close(fd); return SQLITE_NOMEM; |
︙ | ︙ |
Changes to src/test_func.c.
︙ | ︙ | |||
625 626 627 628 629 630 631 632 633 634 635 636 637 638 | static void test_getsubtype( sqlite3_context *context, int argc, sqlite3_value **argv ){ sqlite3_result_int(context, (int)sqlite3_value_subtype(argv[0])); } /* test_setsubtype(V, T) ** ** Return the value V with its subtype changed to T */ static void test_setsubtype( sqlite3_context *context, | > > > > > > > > > > > > > > > > > > | 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 | static void test_getsubtype( sqlite3_context *context, int argc, sqlite3_value **argv ){ sqlite3_result_int(context, (int)sqlite3_value_subtype(argv[0])); } /* test_frombind(A,B,C,...) ** ** Return an integer bitmask that has a bit set for every argument ** (up to the first 63 arguments) that originates from a bind a parameter. */ static void test_frombind( sqlite3_context *context, int argc, sqlite3_value **argv ){ sqlite3_uint64 m = 0; int i; for(i=0; i<argc && i<63; i++){ if( sqlite3_value_frombind(argv[i]) ) m |= ((sqlite3_uint64)1)<<i; } sqlite3_result_int64(context, (sqlite3_int64)m); } /* test_setsubtype(V, T) ** ** Return the value V with its subtype changed to T */ static void test_setsubtype( sqlite3_context *context, |
︙ | ︙ | |||
671 672 673 674 675 676 677 678 679 680 681 682 683 684 | { "test_counter", 1, SQLITE_UTF8, counterFunc}, { "real2hex", 1, SQLITE_UTF8, real2hex}, { "test_decode", 1, SQLITE_UTF8, test_decode}, { "test_extract", 2, SQLITE_UTF8, test_extract}, { "test_zeroblob", 1, SQLITE_UTF8|SQLITE_DETERMINISTIC, test_zeroblob}, { "test_getsubtype", 1, SQLITE_UTF8, test_getsubtype}, { "test_setsubtype", 2, SQLITE_UTF8, test_setsubtype}, }; int i; for(i=0; i<sizeof(aFuncs)/sizeof(aFuncs[0]); i++){ sqlite3_create_function(db, aFuncs[i].zName, aFuncs[i].nArg, aFuncs[i].eTextRep, 0, aFuncs[i].xFunc, 0, 0); } | > | 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 | { "test_counter", 1, SQLITE_UTF8, counterFunc}, { "real2hex", 1, SQLITE_UTF8, real2hex}, { "test_decode", 1, SQLITE_UTF8, test_decode}, { "test_extract", 2, SQLITE_UTF8, test_extract}, { "test_zeroblob", 1, SQLITE_UTF8|SQLITE_DETERMINISTIC, test_zeroblob}, { "test_getsubtype", 1, SQLITE_UTF8, test_getsubtype}, { "test_setsubtype", 2, SQLITE_UTF8, test_setsubtype}, { "test_frombind", -1, SQLITE_UTF8, test_frombind}, }; int i; for(i=0; i<sizeof(aFuncs)/sizeof(aFuncs[0]); i++){ sqlite3_create_function(db, aFuncs[i].zName, aFuncs[i].nArg, aFuncs[i].eTextRep, 0, aFuncs[i].xFunc, 0, 0); } |
︙ | ︙ |
Changes to src/test_hexio.c.
︙ | ︙ | |||
164 165 166 167 168 169 170 | if( objc!=4 ){ Tcl_WrongNumArgs(interp, 1, objv, "FILENAME OFFSET HEXDATA"); return TCL_ERROR; } if( Tcl_GetIntFromObj(interp, objv[2], &offset) ) return TCL_ERROR; zFile = Tcl_GetString(objv[1]); zIn = (const unsigned char *)Tcl_GetStringFromObj(objv[3], &nIn); | | | 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 | if( objc!=4 ){ Tcl_WrongNumArgs(interp, 1, objv, "FILENAME OFFSET HEXDATA"); return TCL_ERROR; } if( Tcl_GetIntFromObj(interp, objv[2], &offset) ) return TCL_ERROR; zFile = Tcl_GetString(objv[1]); zIn = (const unsigned char *)Tcl_GetStringFromObj(objv[3], &nIn); aOut = sqlite3_malloc( 1 + nIn/2 ); if( aOut==0 ){ return TCL_ERROR; } nOut = sqlite3TestHexToBin(zIn, nIn, aOut); out = fopen(zFile, "r+b"); if( out==0 ){ out = fopen(zFile, "r+"); |
︙ | ︙ | |||
209 210 211 212 213 214 215 | unsigned char aNum[4]; if( objc!=2 ){ Tcl_WrongNumArgs(interp, 1, objv, "HEXDATA"); return TCL_ERROR; } zIn = (const unsigned char *)Tcl_GetStringFromObj(objv[1], &nIn); | | | 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 | unsigned char aNum[4]; if( objc!=2 ){ Tcl_WrongNumArgs(interp, 1, objv, "HEXDATA"); return TCL_ERROR; } zIn = (const unsigned char *)Tcl_GetStringFromObj(objv[1], &nIn); aOut = sqlite3_malloc( 1 + nIn/2 ); if( aOut==0 ){ return TCL_ERROR; } nOut = sqlite3TestHexToBin(zIn, nIn, aOut); if( nOut>=4 ){ memcpy(aNum, aOut, 4); }else{ |
︙ | ︙ | |||
305 306 307 308 309 310 311 | const unsigned char *zOrig; unsigned char *z; if( objc!=2 ){ Tcl_WrongNumArgs(interp, 1, objv, "HEX"); return TCL_ERROR; } zOrig = (unsigned char *)Tcl_GetStringFromObj(objv[1], &n); | | | 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 | const unsigned char *zOrig; unsigned char *z; if( objc!=2 ){ Tcl_WrongNumArgs(interp, 1, objv, "HEX"); return TCL_ERROR; } zOrig = (unsigned char *)Tcl_GetStringFromObj(objv[1], &n); z = sqlite3_malloc( n+4 ); n = sqlite3TestHexToBin(zOrig, n, z); z[n] = 0; nOut = sqlite3Utf8To8(z); sqlite3TestBinToHex(z,nOut); Tcl_AppendResult(interp, (char*)z, 0); sqlite3_free(z); return TCL_OK; |
︙ | ︙ | |||
333 334 335 336 337 338 339 340 341 342 343 344 345 346 | y <<= 7; } x += y * (*q++); *v = (sqlite_int64) x; return (int) (q - (unsigned char *)p); } /* ** USAGE: read_fts3varint BLOB VARNAME ** ** Read a varint from the start of BLOB. Set variable VARNAME to contain ** the interpreted value. Return the number of bytes of BLOB consumed. */ | > > > > > > > > > > > | 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 | y <<= 7; } x += y * (*q++); *v = (sqlite_int64) x; return (int) (q - (unsigned char *)p); } static int putFts3Varint(char *p, sqlite_int64 v){ unsigned char *q = (unsigned char *) p; sqlite_uint64 vu = v; do{ *q++ = (unsigned char) ((vu & 0x7f) | 0x80); vu >>= 7; }while( vu!=0 ); q[-1] &= 0x7f; /* turn off high bit in final byte */ assert( q - (unsigned char *)p <= 10 ); return (int) (q - (unsigned char *)p); } /* ** USAGE: read_fts3varint BLOB VARNAME ** ** Read a varint from the start of BLOB. Set variable VARNAME to contain ** the interpreted value. Return the number of bytes of BLOB consumed. */ |
︙ | ︙ | |||
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 | nVal = getFts3Varint((char*)zBlob, (sqlite3_int64 *)(&iVal)); Tcl_ObjSetVar2(interp, objv[2], 0, Tcl_NewWideIntObj(iVal), 0); Tcl_SetObjResult(interp, Tcl_NewIntObj(nVal)); return TCL_OK; } /* ** Register commands with the TCL interpreter. */ int Sqlitetest_hexio_Init(Tcl_Interp *interp){ static struct { char *zName; Tcl_ObjCmdProc *xProc; } aObjCmd[] = { { "hexio_read", hexio_read }, { "hexio_write", hexio_write }, { "hexio_get_int", hexio_get_int }, { "hexio_render_int16", hexio_render_int16 }, { "hexio_render_int32", hexio_render_int32 }, { "utf8_to_utf8", utf8_to_utf8 }, { "read_fts3varint", read_fts3varint }, }; int i; for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){ Tcl_CreateObjCommand(interp, aObjCmd[i].zName, aObjCmd[i].xProc, 0, 0); } return TCL_OK; } | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | nVal = getFts3Varint((char*)zBlob, (sqlite3_int64 *)(&iVal)); Tcl_ObjSetVar2(interp, objv[2], 0, Tcl_NewWideIntObj(iVal), 0); Tcl_SetObjResult(interp, Tcl_NewIntObj(nVal)); return TCL_OK; } /* ** USAGE: make_fts3record ARGLIST */ static int SQLITE_TCLAPI make_fts3record( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ Tcl_Obj **aArg = 0; int nArg = 0; unsigned char *aOut = 0; int nOut = 0; int nAlloc = 0; int i; if( objc!=2 ){ Tcl_WrongNumArgs(interp, 1, objv, "LIST"); return TCL_ERROR; } if( Tcl_ListObjGetElements(interp, objv[1], &nArg, &aArg) ){ return TCL_ERROR; } for(i=0; i<nArg; i++){ sqlite3_int64 iVal; if( TCL_OK==Tcl_GetWideIntFromObj(0, aArg[i], &iVal) ){ if( nOut+10>nAlloc ){ int nNew = nAlloc?nAlloc*2:128; unsigned char *aNew = sqlite3_realloc(aOut, nNew); if( aNew==0 ){ sqlite3_free(aOut); return TCL_ERROR; } aOut = aNew; nAlloc = nNew; } nOut += putFts3Varint((char*)&aOut[nOut], iVal); }else{ int nVal = 0; char *zVal = Tcl_GetStringFromObj(aArg[i], &nVal); while( (nOut + nVal)>nAlloc ){ int nNew = nAlloc?nAlloc*2:128; unsigned char *aNew = sqlite3_realloc(aOut, nNew); if( aNew==0 ){ sqlite3_free(aOut); return TCL_ERROR; } aOut = aNew; nAlloc = nNew; } memcpy(&aOut[nOut], zVal, nVal); nOut += nVal; } } Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(aOut, nOut)); sqlite3_free(aOut); return TCL_OK; } /* ** Register commands with the TCL interpreter. */ int Sqlitetest_hexio_Init(Tcl_Interp *interp){ static struct { char *zName; Tcl_ObjCmdProc *xProc; } aObjCmd[] = { { "hexio_read", hexio_read }, { "hexio_write", hexio_write }, { "hexio_get_int", hexio_get_int }, { "hexio_render_int16", hexio_render_int16 }, { "hexio_render_int32", hexio_render_int32 }, { "utf8_to_utf8", utf8_to_utf8 }, { "read_fts3varint", read_fts3varint }, { "make_fts3record", make_fts3record }, }; int i; for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){ Tcl_CreateObjCommand(interp, aObjCmd[i].zName, aObjCmd[i].xProc, 0, 0); } return TCL_OK; } |
Changes to src/test_journal.c.
︙ | ︙ | |||
556 557 558 559 560 561 562 | }else{ u32 pgno = (u32)(iOfst/p->nPagesize + 1); assert( (iAmt==1||iAmt==(int)p->nPagesize) && ((iOfst+iAmt)%p->nPagesize)==0 ); /* The following assert() statements may fail if this layer is used ** with a connection in "PRAGMA synchronous=off" mode. If they ** fail with sync=normal or sync=full, this may indicate problem. */ | | | 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 | }else{ u32 pgno = (u32)(iOfst/p->nPagesize + 1); assert( (iAmt==1||iAmt==(int)p->nPagesize) && ((iOfst+iAmt)%p->nPagesize)==0 ); /* The following assert() statements may fail if this layer is used ** with a connection in "PRAGMA synchronous=off" mode. If they ** fail with sync=normal or sync=full, this may indicate problem. */ assert( p->nPage==0 || pgno<=p->nPage || p->nSync>0 ); assert( pgno>p->nPage || sqlite3BitvecTest(p->pWritable, pgno) ); } } rc = sqlite3OsWrite(p->pReal, zBuf, iAmt, iOfst); if( (p->flags&SQLITE_OPEN_MAIN_JOURNAL) && iAmt==12 ){ jt_file *pMain = locateDatabaseHandle(p->zName, 0); |
︙ | ︙ |
Changes to src/test_malloc.c.
︙ | ︙ | |||
108 109 110 111 112 113 114 | void *p = 0; if( !faultsimStep() ){ p = memfault.m.xRealloc(pOld, n); } return p; } | < < < < < < < < < < < < < < < < < < < < < < < < < < | 108 109 110 111 112 113 114 115 116 117 118 119 120 121 | void *p = 0; if( !faultsimStep() ){ p = memfault.m.xRealloc(pOld, n); } return p; } /* ** This routine configures the malloc failure simulation. After ** calling this routine, the next nDelay mallocs will succeed, followed ** by a block of nRepeat failures, after which malloc() calls will begin ** to succeed again. */ static void faultsimConfig(int nDelay, int nRepeat){ |
︙ | ︙ | |||
200 201 202 203 204 205 206 | } /* ** Add or remove the fault-simulation layer using sqlite3_config(). If ** the argument is non-zero, the */ static int faultsimInstall(int install){ | < < < < < < < < < < > > > | 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 | } /* ** Add or remove the fault-simulation layer using sqlite3_config(). If ** the argument is non-zero, the */ static int faultsimInstall(int install){ int rc; install = (install ? 1 : 0); assert(memfault.isInstalled==1 || memfault.isInstalled==0); if( install==memfault.isInstalled ){ return SQLITE_ERROR; } if( install ){ rc = sqlite3_config(SQLITE_CONFIG_GETMALLOC, &memfault.m); assert(memfault.m.xMalloc); if( rc==SQLITE_OK ){ sqlite3_mem_methods m = memfault.m; m.xMalloc = faultsimMalloc; m.xRealloc = faultsimRealloc; rc = sqlite3_config(SQLITE_CONFIG_MALLOC, &m); } sqlite3_test_control(SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS, faultsimBeginBenign, faultsimEndBenign ); }else{ sqlite3_mem_methods m2; |
︙ | ︙ |
Changes to src/test_multiplex.c.
︙ | ︙ | |||
263 264 265 266 267 268 269 | memset(&p[pGroup->nReal], 0, sizeof(p[0])*(iChunk+1-pGroup->nReal)); pGroup->aReal = p; pGroup->nReal = iChunk+1; } if( pGroup->zName && pGroup->aReal[iChunk].z==0 ){ char *z; int n = pGroup->nName; | | > > > | 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 | memset(&p[pGroup->nReal], 0, sizeof(p[0])*(iChunk+1-pGroup->nReal)); pGroup->aReal = p; pGroup->nReal = iChunk+1; } if( pGroup->zName && pGroup->aReal[iChunk].z==0 ){ char *z; int n = pGroup->nName; z = sqlite3_malloc64( n+5 ); if( z==0 ){ return SQLITE_NOMEM; } multiplexFilename(pGroup->zName, pGroup->nName, pGroup->flags, iChunk, z); pGroup->aReal[iChunk].z = sqlite3_create_filename(z,"","",0,0); sqlite3_free(z); if( pGroup->aReal[iChunk].z==0 ) return SQLITE_NOMEM; } return SQLITE_OK; } /* Translate an sqlite3_file* that is really a multiplexGroup* into ** the sqlite3_file* for the underlying original VFS. ** |
︙ | ︙ | |||
434 435 436 437 438 439 440 | if( pSubOpen ){ pSubOpen->pMethods->xClose(pSubOpen); if( pOrigVfs && pGroup->aReal[iChunk].z ){ pOrigVfs->xDelete(pOrigVfs, pGroup->aReal[iChunk].z, 0); } sqlite3_free(pGroup->aReal[iChunk].p); } | | | 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 | if( pSubOpen ){ pSubOpen->pMethods->xClose(pSubOpen); if( pOrigVfs && pGroup->aReal[iChunk].z ){ pOrigVfs->xDelete(pOrigVfs, pGroup->aReal[iChunk].z, 0); } sqlite3_free(pGroup->aReal[iChunk].p); } sqlite3_free_filename(pGroup->aReal[iChunk].z); memset(&pGroup->aReal[iChunk], 0, sizeof(pGroup->aReal[iChunk])); } /* ** Deallocate memory held by a multiplexGroup */ static void multiplexFreeComponents(multiplexGroup *pGroup){ |
︙ | ︙ | |||
526 527 528 529 530 531 532 | #else int sqlite3PendingByte = 0x40000000; #endif while( (sqlite3PendingByte % pGroup->szChunk)>=(pGroup->szChunk-65536) ){ pGroup->szChunk += 65536; } } | | | | 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 | #else int sqlite3PendingByte = 0x40000000; #endif while( (sqlite3PendingByte % pGroup->szChunk)>=(pGroup->szChunk-65536) ){ pGroup->szChunk += 65536; } } pGroup->flags = (flags & ~SQLITE_OPEN_URI); rc = multiplexSubFilename(pGroup, 1); if( rc==SQLITE_OK ){ pSubOpen = multiplexSubOpen(pGroup, 0, &rc, pOutFlags, 0); if( pSubOpen==0 && rc==SQLITE_OK ) rc = SQLITE_CANTOPEN; } if( rc==SQLITE_OK ){ sqlite3_int64 sz64; rc = pSubOpen->pMethods->xFileSize(pSubOpen, &sz64); if( rc==SQLITE_OK && zName ){ int bExists; if( flags & SQLITE_OPEN_SUPER_JOURNAL ){ pGroup->bEnabled = 0; }else if( sz64==0 ){ if( flags & SQLITE_OPEN_MAIN_JOURNAL ){ /* If opening a main journal file and the first chunk is zero ** bytes in size, delete any subsequent chunks from the ** file-system. */ |
︙ | ︙ | |||
584 585 586 587 588 589 590 | } } } } if( rc==SQLITE_OK ){ if( pSubOpen->pMethods->iVersion==1 ){ | | | | 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 | } } } } if( rc==SQLITE_OK ){ if( pSubOpen->pMethods->iVersion==1 ){ pConn->pMethods = &gMultiplex.sIoMethodsV1; }else{ pConn->pMethods = &gMultiplex.sIoMethodsV2; } }else{ multiplexFreeComponents(pGroup); sqlite3_free(pGroup); } } sqlite3_free(zToFree); |
︙ | ︙ | |||
955 956 957 958 959 960 961 | /* ** EVIDENCE-OF: R-29875-31678 The argument to the SQLITE_FCNTL_PRAGMA ** file control is an array of pointers to strings (char**) in which the ** second element of the array is the name of the pragma and the third ** element is the argument to the pragma or NULL if the pragma has no ** argument. */ | > > > > > > > > > > > | | | | | | | | | | | | | | | | | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* ** EVIDENCE-OF: R-29875-31678 The argument to the SQLITE_FCNTL_PRAGMA ** file control is an array of pointers to strings (char**) in which the ** second element of the array is the name of the pragma and the third ** element is the argument to the pragma or NULL if the pragma has no ** argument. */ if( aFcntl[1] && sqlite3_strnicmp(aFcntl[1],"multiplex_",10)==0 ){ sqlite3_int64 sz = 0; (void)multiplexFileSize(pConn, &sz); /* ** PRAGMA multiplex_truncate=BOOLEAN; ** PRAGMA multiplex_truncate; ** ** Turn the multiplexor truncate feature on or off. Return either ** "on" or "off" to indicate the new setting. If the BOOLEAN argument ** is omitted, just return the current value for the truncate setting. */ if( sqlite3_stricmp(aFcntl[1],"multiplex_truncate")==0 ){ if( aFcntl[2] && aFcntl[2][0] ){ if( sqlite3_stricmp(aFcntl[2], "on")==0 || sqlite3_stricmp(aFcntl[2], "1")==0 ){ pGroup->bTruncate = 1; }else if( sqlite3_stricmp(aFcntl[2], "off")==0 || sqlite3_stricmp(aFcntl[2], "0")==0 ){ pGroup->bTruncate = 0; } } /* EVIDENCE-OF: R-27806-26076 The handler for an SQLITE_FCNTL_PRAGMA ** file control can optionally make the first element of the char** ** argument point to a string obtained from sqlite3_mprintf() or the ** equivalent and that string will become the result of the pragma ** or the error message if the pragma fails. */ aFcntl[0] = sqlite3_mprintf(pGroup->bTruncate ? "on" : "off"); rc = SQLITE_OK; break; } /* ** PRAGMA multiplex_enabled; ** ** Return 0 or 1 depending on whether the multiplexor is enabled or ** disabled, respectively. */ if( sqlite3_stricmp(aFcntl[1],"multiplex_enabled")==0 ){ aFcntl[0] = sqlite3_mprintf("%d", pGroup->bEnabled!=0); rc = SQLITE_OK; break; } /* ** PRAGMA multiplex_chunksize; ** ** Return the chunksize for the multiplexor, or no-op if the ** multiplexor is not active. */ if( sqlite3_stricmp(aFcntl[1],"multiplex_chunksize")==0 && pGroup->bEnabled ){ aFcntl[0] = sqlite3_mprintf("%u", pGroup->szChunk); rc = SQLITE_OK; break; } /* ** PRAGMA multiplex_filecount; ** ** Return the number of disk files currently in use by the ** multiplexor. This should be the total database size size ** divided by the chunksize and rounded up. */ if( sqlite3_stricmp(aFcntl[1],"multiplex_filecount")==0 ){ int n = 0; int ii; for(ii=0; ii<pGroup->nReal; ii++){ if( pGroup->aReal[ii].p!=0 ) n++; } aFcntl[0] = sqlite3_mprintf("%d", n); rc = SQLITE_OK; break; } } /* If the multiplexor does not handle the pragma, pass it through ** into the default case. */ } default: pSubOpen = multiplexSubOpen(pGroup, 0, &rc, NULL, 0); if( pSubOpen ){ |
︙ | ︙ |
Changes to src/test_mutex.c.
︙ | ︙ | |||
26 27 28 29 30 31 32 | #define MAX_MUTEXES (SQLITE_MUTEX_STATIC_VFS3+1) #define STATIC_MUTEXES (MAX_MUTEXES-(SQLITE_MUTEX_RECURSIVE+1)) /* defined in main.c */ extern const char *sqlite3ErrName(int); static const char *aName[MAX_MUTEXES+1] = { | | | 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | #define MAX_MUTEXES (SQLITE_MUTEX_STATIC_VFS3+1) #define STATIC_MUTEXES (MAX_MUTEXES-(SQLITE_MUTEX_RECURSIVE+1)) /* defined in main.c */ extern const char *sqlite3ErrName(int); static const char *aName[MAX_MUTEXES+1] = { "fast", "recursive", "static_main", "static_mem", "static_open", "static_prng", "static_lru", "static_pmem", "static_app1", "static_app2", "static_app3", "static_vfs1", "static_vfs2", "static_vfs3", 0 }; /* A countable mutex */ struct sqlite3_mutex { |
︙ | ︙ |
Changes to src/test_osinst.c.
︙ | ︙ | |||
736 737 738 739 740 741 742 | p->base.zName = &((char *)p->pLog)[pParent->szOsFile]; p->base.szOsFile += pParent->szOsFile; memcpy((char *)p->base.zName, zVfs, nVfs); zFile = (char *)&p->base.zName[nVfs+1]; pParent->xFullPathname(pParent, zLog, pParent->mxPathname, zFile); | | | 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 | p->base.zName = &((char *)p->pLog)[pParent->szOsFile]; p->base.szOsFile += pParent->szOsFile; memcpy((char *)p->base.zName, zVfs, nVfs); zFile = (char *)&p->base.zName[nVfs+1]; pParent->xFullPathname(pParent, zLog, pParent->mxPathname, zFile); flags = SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|SQLITE_OPEN_SUPER_JOURNAL; pParent->xDelete(pParent, zFile, 0); rc = pParent->xOpen(pParent, zFile, p->pLog, flags, &flags); if( rc==SQLITE_OK ){ memcpy(p->aBuf, "sqlite_ostrace1.....", 20); p->iOffset = 0; p->nBuf = 20; rc = sqlite3_vfs_register((sqlite3_vfs *)p, 1); |
︙ | ︙ | |||
889 890 891 892 893 894 895 | sqlite3_free(p); return SQLITE_NOMEM; } dequote(zFile); pVfs->xFullPathname(pVfs, zFile, pVfs->mxPathname, p->zFile); sqlite3_free(zFile); | | | 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 | sqlite3_free(p); return SQLITE_NOMEM; } dequote(zFile); pVfs->xFullPathname(pVfs, zFile, pVfs->mxPathname, p->zFile); sqlite3_free(zFile); flags = SQLITE_OPEN_READWRITE|SQLITE_OPEN_SUPER_JOURNAL; rc = pVfs->xOpen(pVfs, p->zFile, p->pFd, flags, &flags); if( rc==SQLITE_OK ){ p->pFd->pMethods->xFileSize(p->pFd, &p->nByte); sqlite3_declare_vtab(db, "CREATE TABLE xxx(event, file, click, rc, size, offset)" ); |
︙ | ︙ |
Changes to src/test_schema.c.
︙ | ︙ | |||
188 189 190 191 192 193 194 | assert(pCur->pDbList); while( SQLITE_ROW!=sqlite3_step(pCur->pDbList) ){ rc = finalize(&pCur->pDbList); goto next_exit; } /* Set zSql to the SQL to pull the list of tables from the | | | | | 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 | assert(pCur->pDbList); while( SQLITE_ROW!=sqlite3_step(pCur->pDbList) ){ rc = finalize(&pCur->pDbList); goto next_exit; } /* Set zSql to the SQL to pull the list of tables from the ** sqlite_schema (or sqlite_temp_schema) table of the database ** identified by the row pointed to by the SQL statement pCur->pDbList ** (iterating through a "PRAGMA database_list;" statement). */ if( sqlite3_column_int(pCur->pDbList, 0)==1 ){ zSql = sqlite3_mprintf( "SELECT name FROM sqlite_temp_schema WHERE type='table'" ); }else{ sqlite3_stmt *pDbList = pCur->pDbList; zSql = sqlite3_mprintf( "SELECT name FROM %Q.sqlite_schema WHERE type='table'", sqlite3_column_text(pDbList, 1) ); } if( !zSql ){ rc = SQLITE_NOMEM; goto next_exit; } |
︙ | ︙ |
Changes to src/test_sqllog.c.
︙ | ︙ | |||
114 115 116 117 118 119 120 | 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 { | | | 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 | 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_MAIN */ sqlite3_mutex *mutex; /* Recursive mutex */ int nConn; /* Size of aConn[] array */ /* Protected by SLGlobal.mutex */ int bConditional; /* Only trace if *-sqllog file is present */ int bReuse; /* True to avoid extra copies of db files */ char zPrefix[SQLLOG_NAMESZ]; /* Prefix for all created files */ |
︙ | ︙ | |||
463 464 465 466 467 468 469 | ** 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; | | | | | | | | | 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 | ** 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 *mainmtx = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MAIN); assert( eType==0 || eType==1 || eType==2 ); assert( (eType==2)==(zSql==0) ); /* This is a database open command. */ if( eType==0 ){ sqlite3_mutex_enter(mainmtx); if( sqllogglobal.mutex==0 ){ sqllogglobal.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_RECURSIVE); } sqlite3_mutex_leave(mainmtx); sqlite3_mutex_enter(sqllogglobal.mutex); if( sqllogglobal.bRec==0 && sqllogTraceDb(db) ){ sqlite3_mutex_enter(mainmtx); p = &sqllogglobal.aConn[sqllogglobal.nConn++]; p->fd = 0; p->db = db; p->iLog = sqllogglobal.iNextLog++; sqlite3_mutex_leave(mainmtx); /* Open the log and take a copy of the main database file */ sqllogOpenlog(p); if( p->fd ) sqllogCopydb(p, "main", 0); } sqlite3_mutex_leave(sqllogglobal.mutex); } else{ int i; for(i=0; i<sqllogglobal.nConn; i++){ p = &sqllogglobal.aConn[i]; if( p->db==db ) break; } /* A database handle close command */ if( eType==2 ){ sqlite3_mutex_enter(mainmtx); if( i<sqllogglobal.nConn ){ if( p->fd ) fclose(p->fd); p->db = 0; p->fd = 0; sqllogglobal.nConn--; } if( sqllogglobal.nConn==0 ){ sqlite3_mutex_free(sqllogglobal.mutex); sqllogglobal.mutex = 0; }else if( i<sqllogglobal.nConn ){ int nShift = &sqllogglobal.aConn[sqllogglobal.nConn] - p; if( nShift>0 ){ memmove(p, &p[1], nShift*sizeof(struct SLConn)); } } sqlite3_mutex_leave(mainmtx); /* An ordinary SQL command. */ }else if( i<sqllogglobal.nConn && p->fd ){ sqlite3_mutex_enter(sqllogglobal.mutex); if( sqllogglobal.bRec==0 ){ testSqllogStmt(p, zSql); } |
︙ | ︙ |
Changes to src/test_tclsh.c.
︙ | ︙ | |||
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 | extern int SqlitetestThread_Init(Tcl_Interp*); extern int SqlitetestOnefile_Init(); extern int SqlitetestOsinst_Init(Tcl_Interp*); extern int Sqlitetestbackup_Init(Tcl_Interp*); 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_SESSION) && defined(SQLITE_ENABLE_PREUPDATE_HOOK) extern int TestSession_Init(Tcl_Interp*); #endif extern int Md5_Init(Tcl_Interp*); extern int Fts5tcl_Init(Tcl_Interp *); extern int SqliteRbu_Init(Tcl_Interp*); extern int Sqlitetesttcl_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*); #endif extern int TestExpert_Init(Tcl_Interp*); extern int Sqlitetest_window_Init(Tcl_Interp *); Tcl_CmdInfo cmdInfo; /* Since the primary use case for this binary is testing of SQLite, ** be sure to generate core files if we crash */ #if defined(unix) { struct rlimit x; | > > | 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 | extern int SqlitetestThread_Init(Tcl_Interp*); extern int SqlitetestOnefile_Init(); extern int SqlitetestOsinst_Init(Tcl_Interp*); extern int Sqlitetestbackup_Init(Tcl_Interp*); extern int Sqlitetestintarray_Init(Tcl_Interp*); extern int Sqlitetestvfs_Init(Tcl_Interp *); extern int Sqlitetestrtree_Init(Tcl_Interp*); extern int Sqlitetestrtreedoc_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_SESSION) && defined(SQLITE_ENABLE_PREUPDATE_HOOK) extern int TestSession_Init(Tcl_Interp*); #endif extern int Md5_Init(Tcl_Interp*); extern int Fts5tcl_Init(Tcl_Interp *); extern int SqliteRbu_Init(Tcl_Interp*); extern int Sqlitetesttcl_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*); #endif extern int TestExpert_Init(Tcl_Interp*); extern int Sqlitetest_window_Init(Tcl_Interp *); extern int Sqlitetestvdbecov_Init(Tcl_Interp *); Tcl_CmdInfo cmdInfo; /* Since the primary use case for this binary is testing of SQLite, ** be sure to generate core files if we crash */ #if defined(unix) { struct rlimit x; |
︙ | ︙ | |||
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 | SqlitetestThread_Init(interp); SqlitetestOnefile_Init(); SqlitetestOsinst_Init(interp); Sqlitetestbackup_Init(interp); 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_SESSION) && defined(SQLITE_ENABLE_PREUPDATE_HOOK) TestSession_Init(interp); #endif Fts5tcl_Init(interp); SqliteRbu_Init(interp); Sqlitetesttcl_Init(interp); #if defined(SQLITE_ENABLE_FTS3) || defined(SQLITE_ENABLE_FTS4) Sqlitetestfts3_Init(interp); #endif TestExpert_Init(interp); Sqlitetest_window_Init(interp); Tcl_CreateObjCommand( interp, "load_testfixture_extensions", load_testfixture_extensions,0,0 ); return 0; } | > > | 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 | SqlitetestThread_Init(interp); SqlitetestOnefile_Init(); SqlitetestOsinst_Init(interp); Sqlitetestbackup_Init(interp); Sqlitetestintarray_Init(interp); Sqlitetestvfs_Init(interp); Sqlitetestrtree_Init(interp); Sqlitetestrtreedoc_Init(interp); Sqlitequota_Init(interp); Sqlitemultiplex_Init(interp); SqliteSuperlock_Init(interp); SqlitetestSyscall_Init(interp); #if defined(SQLITE_ENABLE_SESSION) && defined(SQLITE_ENABLE_PREUPDATE_HOOK) TestSession_Init(interp); #endif Fts5tcl_Init(interp); SqliteRbu_Init(interp); Sqlitetesttcl_Init(interp); #if defined(SQLITE_ENABLE_FTS3) || defined(SQLITE_ENABLE_FTS4) Sqlitetestfts3_Init(interp); #endif TestExpert_Init(interp); Sqlitetest_window_Init(interp); Sqlitetestvdbecov_Init(interp); Tcl_CreateObjCommand( interp, "load_testfixture_extensions", load_testfixture_extensions,0,0 ); return 0; } |
︙ | ︙ |
Changes to src/test_thread.c.
︙ | ︙ | |||
283 284 285 286 287 288 289 | extern int Md5_Register(sqlite3*,char**,const sqlite3_api_routines*); UNUSED_PARAMETER(clientData); UNUSED_PARAMETER(objc); zFilename = Tcl_GetString(objv[2]); sqlite3_open(zFilename, &db); | < < < < < < < < < < < < < < < < | 283 284 285 286 287 288 289 290 291 292 293 294 295 296 | extern int Md5_Register(sqlite3*,char**,const sqlite3_api_routines*); UNUSED_PARAMETER(clientData); UNUSED_PARAMETER(objc); zFilename = Tcl_GetString(objv[2]); sqlite3_open(zFilename, &db); Md5_Register(db, 0, 0); sqlite3_busy_handler(db, xBusy, 0); if( sqlite3TestMakePointerStr(interp, zBuf, db) ) return TCL_ERROR; Tcl_AppendResult(interp, zBuf, 0); return TCL_OK; |
︙ | ︙ |
Added src/test_vdbecov.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 | /* ** 2019 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. ** ****************************************************************************** ** */ #if SQLITE_TEST /* This file is used for testing only */ #include "sqlite3.h" #include "sqliteInt.h" #if defined(INCLUDE_SQLITE_TCL_H) # include "sqlite_tcl.h" #else # include "tcl.h" #endif #ifdef SQLITE_VDBE_COVERAGE static u8 aBranchArray[200000]; static void test_vdbe_branch( void *pCtx, unsigned int iSrc, unsigned char iBranch, unsigned char iType ){ if( iSrc<sizeof(aBranchArray) ){ aBranchArray[iSrc] |= iBranch; } } static void appendToList( Tcl_Obj *pList, int iLine, int iPath, const char *zNever ){ Tcl_Obj *pNew = Tcl_NewObj(); Tcl_IncrRefCount(pNew); Tcl_ListObjAppendElement(0, pNew, Tcl_NewIntObj(iLine)); Tcl_ListObjAppendElement(0, pNew, Tcl_NewIntObj(iPath)); Tcl_ListObjAppendElement(0, pNew, Tcl_NewStringObj(zNever, -1)); Tcl_ListObjAppendElement(0, pList, pNew); Tcl_DecrRefCount(pNew); } static int SQLITE_TCLAPI test_vdbe_coverage( ClientData cd, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ const char *aSub[] = { "start", "report", "stop", 0 }; int iSub = -1; if( objc!=2 ){ Tcl_WrongNumArgs(interp, 1, objv, "sub-command"); return TCL_ERROR; } if( Tcl_GetIndexFromObj(interp, objv[1], aSub, "sub-command", 0, &iSub) ){ return TCL_ERROR; } Tcl_ResetResult(interp); assert( iSub==0 || iSub==1 || iSub==2 ); switch( iSub ){ case 0: /* start */ memset(aBranchArray, 0, sizeof(aBranchArray)); sqlite3_test_control(SQLITE_TESTCTRL_VDBE_COVERAGE, test_vdbe_branch, 0); break; case 1: { /* report */ int i; Tcl_Obj *pRes = Tcl_NewObj(); Tcl_IncrRefCount(pRes); for(i=0; i<sizeof(aBranchArray); i++){ u8 b = aBranchArray[i]; int bFlag = ((b >> 4)==4); if( b ){ if( (b & 0x01)==0 ){ appendToList(pRes, i, 0, bFlag ? "less than" : "falls through"); } if( (b & 0x02)==0 ){ appendToList(pRes, i, 1, bFlag ? "equal" : "taken"); } if( (b & 0x04)==0 ){ appendToList(pRes, i, 2, bFlag ? "greater-than" : "NULL"); } } } Tcl_SetObjResult(interp, pRes); Tcl_DecrRefCount(pRes); break; }; default: /* stop */ sqlite3_test_control(SQLITE_TESTCTRL_VDBE_COVERAGE, 0, 0); break; } return TCL_OK; } #endif /* SQLITE_VDBE_COVERAGE */ int Sqlitetestvdbecov_Init(Tcl_Interp *interp){ #ifdef SQLITE_VDBE_COVERAGE Tcl_CreateObjCommand(interp, "vdbe_coverage", test_vdbe_coverage, 0, 0); #endif return TCL_OK; } #endif |
Changes to src/test_vfs.c.
︙ | ︙ | |||
224 225 226 227 228 229 230 | }; static int tvfsResultCode(Testvfs *p, int *pRc){ struct errcode { int eCode; const char *zCode; } aCode[] = { | | | | | | > > > > | 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 | }; static int tvfsResultCode(Testvfs *p, int *pRc){ struct errcode { int eCode; const char *zCode; } aCode[] = { { SQLITE_OK, "SQLITE_OK" }, { SQLITE_ERROR, "SQLITE_ERROR" }, { SQLITE_IOERR, "SQLITE_IOERR" }, { SQLITE_LOCKED, "SQLITE_LOCKED" }, { SQLITE_BUSY, "SQLITE_BUSY" }, { SQLITE_READONLY, "SQLITE_READONLY" }, { SQLITE_READONLY_CANTINIT, "SQLITE_READONLY_CANTINIT" }, { SQLITE_NOTFOUND, "SQLITE_NOTFOUND" }, { -1, "SQLITE_OMIT" }, }; const char *z; int i; z = Tcl_GetStringResult(p->interp); for(i=0; i<ArraySize(aCode); i++){ |
︙ | ︙ | |||
376 377 378 379 380 381 382 383 384 385 386 387 388 389 | if( p->pScript && p->mask&TESTVFS_WRITE_MASK ){ tvfsExecTcl(p, "xWrite", Tcl_NewStringObj(pFd->zFilename, -1), pFd->pShmId, Tcl_NewWideIntObj(iOfst), Tcl_NewIntObj(iAmt) ); tvfsResultCode(p, &rc); } if( rc==SQLITE_OK && tvfsInjectFullerr(p) ){ rc = SQLITE_FULL; } if( rc==SQLITE_OK && p->mask&TESTVFS_WRITE_MASK && tvfsInjectIoerr(p) ){ rc = SQLITE_IOERR; | > | 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 | if( p->pScript && p->mask&TESTVFS_WRITE_MASK ){ tvfsExecTcl(p, "xWrite", Tcl_NewStringObj(pFd->zFilename, -1), pFd->pShmId, Tcl_NewWideIntObj(iOfst), Tcl_NewIntObj(iAmt) ); tvfsResultCode(p, &rc); if( rc<0 ) return SQLITE_OK; } if( rc==SQLITE_OK && tvfsInjectFullerr(p) ){ rc = SQLITE_FULL; } if( rc==SQLITE_OK && p->mask&TESTVFS_WRITE_MASK && tvfsInjectIoerr(p) ){ rc = SQLITE_IOERR; |
︙ | ︙ | |||
544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 | if( p->pScript && (p->mask&TESTVFS_FCNTL_MASK) ){ struct Fcntl { int iFnctl; const char *zFnctl; } aF[] = { { SQLITE_FCNTL_BEGIN_ATOMIC_WRITE, "BEGIN_ATOMIC_WRITE" }, { SQLITE_FCNTL_COMMIT_ATOMIC_WRITE, "COMMIT_ATOMIC_WRITE" }, }; int i; for(i=0; i<sizeof(aF)/sizeof(aF[0]); i++){ if( op==aF[i].iFnctl ) break; } if( i<sizeof(aF)/sizeof(aF[0]) ){ int rc = 0; tvfsExecTcl(p, "xFileControl", Tcl_NewStringObj(pFd->zFilename, -1), Tcl_NewStringObj(aF[i].zFnctl, -1), 0, 0 ); tvfsResultCode(p, &rc); | > | | 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 | if( p->pScript && (p->mask&TESTVFS_FCNTL_MASK) ){ struct Fcntl { int iFnctl; const char *zFnctl; } aF[] = { { SQLITE_FCNTL_BEGIN_ATOMIC_WRITE, "BEGIN_ATOMIC_WRITE" }, { SQLITE_FCNTL_COMMIT_ATOMIC_WRITE, "COMMIT_ATOMIC_WRITE" }, { SQLITE_FCNTL_ZIPVFS, "ZIPVFS" }, }; int i; for(i=0; i<sizeof(aF)/sizeof(aF[0]); i++){ if( op==aF[i].iFnctl ) break; } if( i<sizeof(aF)/sizeof(aF[0]) ){ int rc = 0; tvfsExecTcl(p, "xFileControl", Tcl_NewStringObj(pFd->zFilename, -1), Tcl_NewStringObj(aF[i].zFnctl, -1), 0, 0 ); tvfsResultCode(p, &rc); if( rc ) return (rc<0 ? SQLITE_OK : rc); } } return sqlite3OsFileControl(pFd->pReal, op, pArg); } /* ** Return the sector-size in bytes for an tvfs-file. |
︙ | ︙ | |||
861 862 863 864 865 866 867 | p->pBuffer = pBuffer; } /* Connect the TestvfsBuffer to the new TestvfsShm handle and return. */ pFd->pNext = pBuffer->pFile; pBuffer->pFile = pFd; pFd->pShm = pBuffer; | | | 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 | p->pBuffer = pBuffer; } /* Connect the TestvfsBuffer to the new TestvfsShm handle and return. */ pFd->pNext = pBuffer->pFile; pBuffer->pFile = pFd; pFd->pShm = pBuffer; return rc; } static void tvfsAllocPage(TestvfsBuffer *p, int iPage, int pgsz){ assert( iPage<TESTVFS_MAX_PAGES ); if( p->aPage[iPage]==0 ){ p->aPage[iPage] = (u8 *)ckalloc(pgsz); memset(p->aPage[iPage], 0, pgsz); |
︙ | ︙ | |||
885 886 887 888 889 890 891 | void volatile **pp /* OUT: Mapped memory */ ){ int rc = SQLITE_OK; TestvfsFd *pFd = tvfsGetFd(pFile); Testvfs *p = (Testvfs *)(pFd->pVfs->pAppData); if( p->isFullshm ){ | > | | 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 | void volatile **pp /* OUT: Mapped memory */ ){ int rc = SQLITE_OK; TestvfsFd *pFd = tvfsGetFd(pFile); Testvfs *p = (Testvfs *)(pFd->pVfs->pAppData); if( p->isFullshm ){ sqlite3_file *pReal = pFd->pReal; return pReal->pMethods->xShmMap(pReal, iPage, pgsz, isWrite, pp); } if( 0==pFd->pShm ){ rc = tvfsShmOpen(pFile); if( rc!=SQLITE_OK ){ return rc; } |
︙ | ︙ | |||
914 915 916 917 918 919 920 | if( rc==SQLITE_OK && p->mask&TESTVFS_SHMMAP_MASK && tvfsInjectIoerr(p) ){ rc = SQLITE_IOERR; } if( rc==SQLITE_OK && isWrite && !pFd->pShm->aPage[iPage] ){ tvfsAllocPage(pFd->pShm, iPage, pgsz); } | > | > > | | 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 | if( rc==SQLITE_OK && p->mask&TESTVFS_SHMMAP_MASK && tvfsInjectIoerr(p) ){ rc = SQLITE_IOERR; } if( rc==SQLITE_OK && isWrite && !pFd->pShm->aPage[iPage] ){ tvfsAllocPage(pFd->pShm, iPage, pgsz); } if( rc==SQLITE_OK || rc==SQLITE_READONLY ){ *pp = (void volatile *)pFd->pShm->aPage[iPage]; } return rc; } static int tvfsShmLock( sqlite3_file *pFile, int ofst, int n, int flags ){ int rc = SQLITE_OK; TestvfsFd *pFd = tvfsGetFd(pFile); Testvfs *p = (Testvfs *)(pFd->pVfs->pAppData); int nLock; char zLock[80]; if( p->isFullshm ){ sqlite3_file *pReal = pFd->pReal; return pReal->pMethods->xShmLock(pReal, ofst, n, flags); } if( p->pScript && p->mask&TESTVFS_SHMLOCK_MASK ){ sqlite3_snprintf(sizeof(zLock), zLock, "%d %d", ofst, n); nLock = (int)strlen(zLock); if( flags & SQLITE_SHM_LOCK ){ strcpy(&zLock[nLock], " lock"); |
︙ | ︙ | |||
997 998 999 1000 1001 1002 1003 | if( p->pScript && p->mask&TESTVFS_SHMBARRIER_MASK ){ const char *z = pFd->pShm ? pFd->pShm->zFile : ""; tvfsExecTcl(p, "xShmBarrier", Tcl_NewStringObj(z, -1), pFd->pShmId, 0, 0); } if( p->isFullshm ){ | > | > | | 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 | if( p->pScript && p->mask&TESTVFS_SHMBARRIER_MASK ){ const char *z = pFd->pShm ? pFd->pShm->zFile : ""; tvfsExecTcl(p, "xShmBarrier", Tcl_NewStringObj(z, -1), pFd->pShmId, 0, 0); } if( p->isFullshm ){ sqlite3_file *pReal = pFd->pReal; pReal->pMethods->xShmBarrier(pReal); return; } } static int tvfsShmUnmap( sqlite3_file *pFile, int deleteFlag ){ int rc = SQLITE_OK; TestvfsFd *pFd = tvfsGetFd(pFile); Testvfs *p = (Testvfs *)(pFd->pVfs->pAppData); TestvfsBuffer *pBuffer = pFd->pShm; TestvfsFd **ppFd; if( p->isFullshm ){ sqlite3_file *pReal = pFd->pReal; return pReal->pMethods->xShmUnmap(pReal, deleteFlag); } if( !pBuffer ) return SQLITE_OK; assert( pFd->pShmId && pFd->pShm ); if( p->pScript && p->mask&TESTVFS_SHMCLOSE_MASK ){ tvfsExecTcl(p, "xShmUnmap", |
︙ | ︙ | |||
1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 | return TCL_OK; } static void SQLITE_TCLAPI testvfs_obj_del(ClientData cd){ Testvfs *p = (Testvfs *)cd; if( p->pScript ) Tcl_DecrRefCount(p->pScript); sqlite3_vfs_unregister(p->pVfs); ckfree((char *)p->pVfs); ckfree((char *)p); } /* ** Usage: testvfs VFSNAME ?SWITCHES? ** ** Switches are: | > > | 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 | return TCL_OK; } static void SQLITE_TCLAPI testvfs_obj_del(ClientData cd){ Testvfs *p = (Testvfs *)cd; if( p->pScript ) Tcl_DecrRefCount(p->pScript); sqlite3_vfs_unregister(p->pVfs); memset(p->pVfs, 0, sizeof(sqlite3_vfs)); ckfree((char *)p->pVfs); memset(p, 0, sizeof(Testvfs)); ckfree((char *)p); } /* ** Usage: testvfs VFSNAME ?SWITCHES? ** ** Switches are: |
︙ | ︙ | |||
1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 | return TCL_OK; bad_args: Tcl_WrongNumArgs(interp, 1, objv, "VFSNAME ?-noshm BOOL? ?-fullshm BOOL? ?-default BOOL? ?-mxpathname INT? ?-szosfile INT? ?-iversion INT?"); return TCL_ERROR; } int Sqlitetestvfs_Init(Tcl_Interp *interp){ Tcl_CreateObjCommand(interp, "testvfs", testvfs_cmd, 0, 0); return TCL_OK; } #endif | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 | return TCL_OK; bad_args: Tcl_WrongNumArgs(interp, 1, objv, "VFSNAME ?-noshm BOOL? ?-fullshm BOOL? ?-default BOOL? ?-mxpathname INT? ?-szosfile INT? ?-iversion INT?"); return TCL_ERROR; } extern int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb); extern const char *sqlite3ErrName(int); /* ** tclcmd: vfs_shmlock DB DBNAME (shared|exclusive) (lock|unlock) OFFSET N */ static int SQLITE_TCLAPI test_vfs_shmlock( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ const char *azArg1[] = {"shared", "exclusive", 0}; const char *azArg2[] = {"lock", "unlock", 0}; sqlite3 *db = 0; int rc = SQLITE_OK; const char *zDbname = 0; int iArg1 = 0; int iArg2 = 0; int iOffset = 0; int n = 0; sqlite3_file *pFd; if( objc!=7 ){ Tcl_WrongNumArgs(interp, 1, objv, "DB DBNAME (shared|exclusive) (lock|unlock) OFFSET N" ); return TCL_ERROR; } zDbname = Tcl_GetString(objv[2]); if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) || Tcl_GetIndexFromObj(interp, objv[3], azArg1, "ARG", 0, &iArg1) || Tcl_GetIndexFromObj(interp, objv[4], azArg2, "ARG", 0, &iArg2) || Tcl_GetIntFromObj(interp, objv[5], &iOffset) || Tcl_GetIntFromObj(interp, objv[6], &n) ){ return TCL_ERROR; } sqlite3_file_control(db, zDbname, SQLITE_FCNTL_FILE_POINTER, (void*)&pFd); if( pFd==0 ){ return TCL_ERROR; } rc = pFd->pMethods->xShmLock(pFd, iOffset, n, (iArg1==0 ? SQLITE_SHM_SHARED : SQLITE_SHM_EXCLUSIVE) | (iArg2==0 ? SQLITE_SHM_LOCK : SQLITE_SHM_UNLOCK) ); Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1)); return TCL_OK; } static int SQLITE_TCLAPI test_vfs_set_readmark( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3 *db = 0; int rc = SQLITE_OK; const char *zDbname = 0; int iSlot = 0; int iVal = -1; sqlite3_file *pFd; void volatile *pShm = 0; u32 *aShm; int iOff; if( objc!=4 && objc!=5 ){ Tcl_WrongNumArgs(interp, 1, objv, "DB DBNAME SLOT ?VALUE?"); return TCL_ERROR; } zDbname = Tcl_GetString(objv[2]); if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) || Tcl_GetIntFromObj(interp, objv[3], &iSlot) || (objc==5 && Tcl_GetIntFromObj(interp, objv[4], &iVal)) ){ return TCL_ERROR; } sqlite3_file_control(db, zDbname, SQLITE_FCNTL_FILE_POINTER, (void*)&pFd); if( pFd==0 ){ return TCL_ERROR; } rc = pFd->pMethods->xShmMap(pFd, 0, 32*1024, 0, &pShm); if( rc!=SQLITE_OK ){ Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1)); return TCL_ERROR; } if( pShm==0 ){ Tcl_AppendResult(interp, "*-shm is not yet mapped", 0); return TCL_ERROR; } aShm = (u32*)pShm; iOff = 12*2+1+iSlot; if( objc==5 ){ aShm[iOff] = iVal; } Tcl_SetObjResult(interp, Tcl_NewIntObj(aShm[iOff])); return TCL_OK; } int Sqlitetestvfs_Init(Tcl_Interp *interp){ Tcl_CreateObjCommand(interp, "testvfs", testvfs_cmd, 0, 0); Tcl_CreateObjCommand(interp, "vfs_shmlock", test_vfs_shmlock, 0, 0); Tcl_CreateObjCommand(interp, "vfs_set_readmark", test_vfs_set_readmark, 0, 0); return TCL_OK; } #endif |
Changes to src/tokenize.c.
︙ | ︙ | |||
23 24 25 26 27 28 29 | ** In the sqlite3GetToken() function, a switch() on aiClass[c] is implemented ** using a lookup table, whereas a switch() directly on c uses a binary search. ** The lookup table is much faster. To maximize speed, and to ensure that ** a lookup table is used, all of the classes need to be small integers and ** all of them need to be used within the switch. */ #define CC_X 0 /* The letter 'x', or start of BLOB literal */ | > | < | 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | ** In the sqlite3GetToken() function, a switch() on aiClass[c] is implemented ** using a lookup table, whereas a switch() directly on c uses a binary search. ** The lookup table is much faster. To maximize speed, and to ensure that ** a lookup table is used, all of the classes need to be small integers and ** all of them need to be used within the switch. */ #define CC_X 0 /* The letter 'x', or start of BLOB literal */ #define CC_KYWD0 1 /* First letter of a keyword */ #define CC_KYWD 2 /* Alphabetics or '_'. Usable in a keyword */ #define CC_DIGIT 3 /* Digits */ #define CC_DOLLAR 4 /* '$' */ #define CC_VARALPHA 5 /* '@', '#', ':'. Alphabetic SQL variables */ #define CC_VARNUM 6 /* '?'. Numeric SQL variables */ #define CC_SPACE 7 /* Space characters */ #define CC_QUOTE 8 /* '"', '\'', or '`'. String literals, quoted ids */ #define CC_QUOTE2 9 /* '['. [...] style quoted ids */ |
︙ | ︙ | |||
49 50 51 52 53 54 55 | #define CC_PLUS 20 /* '+' */ #define CC_STAR 21 /* '*' */ #define CC_PERCENT 22 /* '%' */ #define CC_COMMA 23 /* ',' */ #define CC_AND 24 /* '&' */ #define CC_TILDA 25 /* '~' */ #define CC_DOT 26 /* '.' */ | > | | > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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 | #define CC_PLUS 20 /* '+' */ #define CC_STAR 21 /* '*' */ #define CC_PERCENT 22 /* '%' */ #define CC_COMMA 23 /* ',' */ #define CC_AND 24 /* '&' */ #define CC_TILDA 25 /* '~' */ #define CC_DOT 26 /* '.' */ #define CC_ID 27 /* unicode characters usable in IDs */ #define CC_ILLEGAL 28 /* Illegal character */ #define CC_NUL 29 /* 0x00 */ #define CC_BOM 30 /* First byte of UTF8 BOM: 0xEF 0xBB 0xBF */ static const unsigned char aiClass[] = { #ifdef SQLITE_ASCII /* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xa xb xc xd xe xf */ /* 0x */ 29, 28, 28, 28, 28, 28, 28, 28, 28, 7, 7, 28, 7, 7, 28, 28, /* 1x */ 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, /* 2x */ 7, 15, 8, 5, 4, 22, 24, 8, 17, 18, 21, 20, 23, 11, 26, 16, /* 3x */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 19, 12, 14, 13, 6, /* 4x */ 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 5x */ 1, 1, 1, 1, 1, 1, 1, 1, 0, 2, 2, 9, 28, 28, 28, 2, /* 6x */ 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 7x */ 1, 1, 1, 1, 1, 1, 1, 1, 0, 2, 2, 28, 10, 28, 25, 28, /* 8x */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, /* 9x */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, /* Ax */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, /* Bx */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, /* Cx */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, /* Dx */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, /* Ex */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 30, /* Fx */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27 #endif #ifdef SQLITE_EBCDIC /* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xa xb xc xd xe xf */ /* 0x */ 29, 28, 28, 28, 28, 7, 28, 28, 28, 28, 28, 28, 7, 7, 28, 28, /* 1x */ 28, 28, 28, 28, 28, 7, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, /* 2x */ 28, 28, 28, 28, 28, 7, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, /* 3x */ 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, /* 4x */ 7, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 26, 12, 17, 20, 10, /* 5x */ 24, 28, 28, 28, 28, 28, 28, 28, 28, 28, 15, 4, 21, 18, 19, 28, /* 6x */ 11, 16, 28, 28, 28, 28, 28, 28, 28, 28, 28, 23, 22, 2, 13, 6, /* 7x */ 28, 28, 28, 28, 28, 28, 28, 28, 28, 8, 5, 5, 5, 8, 14, 8, /* 8x */ 28, 1, 1, 1, 1, 1, 1, 1, 1, 1, 28, 28, 28, 28, 28, 28, /* 9x */ 28, 1, 1, 1, 1, 1, 1, 1, 1, 1, 28, 28, 28, 28, 28, 28, /* Ax */ 28, 25, 1, 1, 1, 1, 1, 0, 2, 2, 28, 28, 28, 28, 28, 28, /* Bx */ 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 9, 28, 28, 28, 28, 28, /* Cx */ 28, 1, 1, 1, 1, 1, 1, 1, 1, 1, 28, 28, 28, 28, 28, 28, /* Dx */ 28, 1, 1, 1, 1, 1, 1, 1, 1, 1, 28, 28, 28, 28, 28, 28, /* Ex */ 28, 28, 1, 1, 1, 1, 1, 0, 2, 2, 28, 28, 28, 28, 28, 28, /* Fx */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 28, 28, 28, 28, 28, 28, #endif }; /* ** The charMap() macro maps alphabetic characters (only) into their ** lower-case ASCII equivalent. On ASCII machines, this is just ** an upper-to-lower case map. On EBCDIC machines we also need |
︙ | ︙ | |||
418 419 420 421 422 423 424 425 426 427 428 429 430 431 | #endif { *tokenType = TK_DOT; return 1; } /* If the next character is a digit, this is a floating point ** number that begins with ".". Fall thru into the next case */ } case CC_DIGIT: { testcase( z[0]=='0' ); testcase( z[0]=='1' ); testcase( z[0]=='2' ); testcase( z[0]=='3' ); testcase( z[0]=='4' ); testcase( z[0]=='5' ); testcase( z[0]=='6' ); testcase( z[0]=='7' ); testcase( z[0]=='8' ); testcase( z[0]=='9' ); *tokenType = TK_INTEGER; | > | 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 | #endif { *tokenType = TK_DOT; return 1; } /* If the next character is a digit, this is a floating point ** number that begins with ".". Fall thru into the next case */ /* no break */ deliberate_fall_through } case CC_DIGIT: { testcase( z[0]=='0' ); testcase( z[0]=='1' ); testcase( z[0]=='2' ); testcase( z[0]=='3' ); testcase( z[0]=='4' ); testcase( z[0]=='5' ); testcase( z[0]=='6' ); testcase( z[0]=='7' ); testcase( z[0]=='8' ); testcase( z[0]=='9' ); *tokenType = TK_INTEGER; |
︙ | ︙ | |||
494 495 496 497 498 499 500 | }else{ break; } } if( n==0 ) *tokenType = TK_ILLEGAL; return i; } | | | 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 | }else{ break; } } if( n==0 ) *tokenType = TK_ILLEGAL; return i; } case CC_KYWD0: { for(i=1; aiClass[z[i]]<=CC_KYWD; i++){} if( IdChar(z[i]) ){ /* This token started out using characters that can appear in keywords, ** but z[i] is a character not allowed within keywords, so this must ** be an identifier instead */ i++; break; |
︙ | ︙ | |||
522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 | } if( z[i] ) i++; return i; } #endif /* If it is not a BLOB literal, then it must be an ID, since no ** SQL keywords start with the letter 'x'. Fall through */ } case CC_ID: { i = 1; break; } case CC_NUL: { *tokenType = TK_ILLEGAL; return 0; } | > > > > > > > > > > | 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 | } if( z[i] ) i++; return i; } #endif /* If it is not a BLOB literal, then it must be an ID, since no ** SQL keywords start with the letter 'x'. Fall through */ /* no break */ deliberate_fall_through } case CC_KYWD: case CC_ID: { i = 1; break; } case CC_BOM: { if( z[1]==0xbb && z[2]==0xbf ){ *tokenType = TK_SPACE; return 3; } i = 1; break; } case CC_NUL: { *tokenType = TK_ILLEGAL; return 0; } |
︙ | ︙ | |||
556 557 558 559 560 561 562 563 564 565 566 567 568 569 | int nErr = 0; /* Number of errors encountered */ void *pEngine; /* The LEMON-generated LALR(1) parser */ int n = 0; /* Length of the next token token */ int tokenType; /* type of the next token */ int lastTokenParsed = -1; /* type of the previous token */ sqlite3 *db = pParse->db; /* The database connection */ int mxSqlLen; /* Max length of an SQL string */ #ifdef sqlite3Parser_ENGINEALWAYSONSTACK yyParser sEngine; /* Space to hold the Lemon-generated Parser object */ #endif assert( zSql!=0 ); mxSqlLen = db->aLimit[SQLITE_LIMIT_SQL_LENGTH]; if( db->nVdbeActive==0 ){ | > > | > > > | > > > > > > | | 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 | int nErr = 0; /* Number of errors encountered */ void *pEngine; /* The LEMON-generated LALR(1) parser */ int n = 0; /* Length of the next token token */ int tokenType; /* type of the next token */ int lastTokenParsed = -1; /* type of the previous token */ sqlite3 *db = pParse->db; /* The database connection */ int mxSqlLen; /* Max length of an SQL string */ Parse *pParentParse = 0; /* Outer parse context, if any */ #ifdef sqlite3Parser_ENGINEALWAYSONSTACK yyParser sEngine; /* Space to hold the Lemon-generated Parser object */ #endif VVA_ONLY( u8 startedWithOom = db->mallocFailed ); assert( zSql!=0 ); mxSqlLen = db->aLimit[SQLITE_LIMIT_SQL_LENGTH]; if( db->nVdbeActive==0 ){ AtomicStore(&db->u1.isInterrupted, 0); } pParse->rc = SQLITE_OK; pParse->zTail = zSql; assert( pzErrMsg!=0 ); #ifdef SQLITE_DEBUG if( db->flags & SQLITE_ParserTrace ){ printf("parser: [[[%s]]]\n", zSql); sqlite3ParserTrace(stdout, "parser: "); }else{ sqlite3ParserTrace(0, 0); } #endif #ifdef sqlite3Parser_ENGINEALWAYSONSTACK pEngine = &sEngine; sqlite3ParserInit(pEngine, pParse); #else pEngine = sqlite3ParserAlloc(sqlite3Malloc, pParse); if( pEngine==0 ){ sqlite3OomFault(db); return SQLITE_NOMEM_BKPT; } #endif assert( pParse->pNewTable==0 ); assert( pParse->pNewTrigger==0 ); assert( pParse->nVar==0 ); assert( pParse->pVList==0 ); pParentParse = db->pParse; db->pParse = pParse; while( 1 ){ n = sqlite3GetToken((u8*)zSql, &tokenType); mxSqlLen -= n; if( mxSqlLen<0 ){ pParse->rc = SQLITE_TOOBIG; break; } #ifndef SQLITE_OMIT_WINDOWFUNC if( tokenType>=TK_WINDOW ){ assert( tokenType==TK_SPACE || tokenType==TK_OVER || tokenType==TK_FILTER || tokenType==TK_ILLEGAL || tokenType==TK_WINDOW ); #else if( tokenType>=TK_SPACE ){ assert( tokenType==TK_SPACE || tokenType==TK_ILLEGAL ); #endif /* SQLITE_OMIT_WINDOWFUNC */ if( AtomicLoad(&db->u1.isInterrupted) ){ pParse->rc = SQLITE_INTERRUPT; break; } if( tokenType==TK_SPACE ){ zSql += n; continue; } |
︙ | ︙ | |||
639 640 641 642 643 644 645 | } } pParse->sLastToken.z = zSql; pParse->sLastToken.n = n; sqlite3Parser(pEngine, tokenType, pParse->sLastToken); lastTokenParsed = tokenType; zSql += n; | > | | 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 | } } pParse->sLastToken.z = zSql; pParse->sLastToken.n = n; sqlite3Parser(pEngine, tokenType, pParse->sLastToken); lastTokenParsed = tokenType; zSql += n; assert( db->mallocFailed==0 || pParse->rc!=SQLITE_OK || startedWithOom ); if( pParse->rc!=SQLITE_OK ) break; } assert( nErr==0 ); #ifdef YYTRACKMAXSTACKDEPTH sqlite3_mutex_enter(sqlite3MallocMutex()); sqlite3StatusHighwater(SQLITE_STATUS_PARSER_STACK, sqlite3ParserStackPeak(pEngine) ); |
︙ | ︙ | |||
694 695 696 697 698 699 700 | ** will take responsibility for freeing the Table structure. */ sqlite3DeleteTable(db, pParse->pNewTable); } if( !IN_RENAME_OBJECT ){ sqlite3DeleteTrigger(db, pParse->pNewTrigger); } | < < | < < < < < < < < < | 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 | ** will take responsibility for freeing the Table structure. */ sqlite3DeleteTable(db, pParse->pNewTable); } if( !IN_RENAME_OBJECT ){ sqlite3DeleteTrigger(db, pParse->pNewTrigger); } sqlite3DbFree(db, pParse->pVList); db->pParse = pParentParse; assert( nErr==0 || pParse->rc!=SQLITE_OK ); return nErr; } #ifdef SQLITE_ENABLE_NORMALIZE /* |
︙ | ︙ | |||
736 737 738 739 740 741 742 | Vdbe *pVdbe, /* VM being reprepared */ const char *zSql /* The original SQL string */ ){ sqlite3 *db; /* The database connection */ int i; /* Next unread byte of zSql[] */ int n; /* length of current token */ int tokenType; /* type of current token */ | | | | 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 | Vdbe *pVdbe, /* VM being reprepared */ const char *zSql /* The original SQL string */ ){ sqlite3 *db; /* The database connection */ int i; /* Next unread byte of zSql[] */ int n; /* length of current token */ int tokenType; /* type of current token */ int prevType = 0; /* Previous non-whitespace token */ int nParen; /* Number of nested levels of parentheses */ int iStartIN; /* Start of RHS of IN operator in z[] */ int nParenAtIN; /* Value of nParent at start of RHS of IN operator */ u32 j; /* Bytes of normalized SQL generated so far */ sqlite3_str *pStr; /* The normalized SQL string under construction */ db = sqlite3VdbeDb(pVdbe); tokenType = -1; nParen = iStartIN = nParenAtIN = 0; pStr = sqlite3_str_new(db); assert( pStr!=0 ); /* sqlite3_str_new() never returns NULL */ |
︙ | ︙ | |||
784 785 786 787 788 789 790 | nParenAtIN = nParen; } sqlite3_str_append(pStr, "(", 1); break; } case TK_RP: { if( iStartIN>0 && nParen==nParenAtIN ){ | | | 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 | nParenAtIN = nParen; } sqlite3_str_append(pStr, "(", 1); break; } case TK_RP: { if( iStartIN>0 && nParen==nParenAtIN ){ assert( pStr->nChar>=(u32)iStartIN ); pStr->nChar = iStartIN+1; sqlite3_str_append(pStr, "?,?,?", 5); iStartIN = 0; } nParen--; sqlite3_str_append(pStr, ")", 1); break; |
︙ | ︙ |
Changes to src/treeview.c.
︙ | ︙ | |||
62 63 64 65 66 67 68 | } sqlite3_str_append(&acc, p->bLine[i] ? "|-- " : "'-- ", 4); } if( zFormat!=0 ){ va_start(ap, zFormat); sqlite3_str_vappendf(&acc, zFormat, ap); va_end(ap); | | | 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 | } sqlite3_str_append(&acc, p->bLine[i] ? "|-- " : "'-- ", 4); } if( zFormat!=0 ){ va_start(ap, zFormat); sqlite3_str_vappendf(&acc, zFormat, ap); va_end(ap); assert( acc.nChar>0 || acc.accError ); sqlite3_str_append(&acc, "\n", 1); } sqlite3StrAccumFinish(&acc); fprintf(stdout,"%s", zBuf); fflush(stdout); } |
︙ | ︙ | |||
102 103 104 105 106 107 108 | const struct Cte *pCte = &pWith->a[i]; sqlite3StrAccumInit(&x, 0, zLine, sizeof(zLine), 0); sqlite3_str_appendf(&x, "%s", pCte->zName); if( pCte->pCols && pCte->pCols->nExpr>0 ){ char cSep = '('; int j; for(j=0; j<pCte->pCols->nExpr; j++){ | | > | > > | > | | < < | < < | < < < > > > > > > > > | 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 | const struct Cte *pCte = &pWith->a[i]; sqlite3StrAccumInit(&x, 0, zLine, sizeof(zLine), 0); sqlite3_str_appendf(&x, "%s", pCte->zName); if( pCte->pCols && pCte->pCols->nExpr>0 ){ char cSep = '('; int j; for(j=0; j<pCte->pCols->nExpr; j++){ sqlite3_str_appendf(&x, "%c%s", cSep, pCte->pCols->a[j].zEName); cSep = ','; } sqlite3_str_appendf(&x, ")"); } if( pCte->pUse ){ sqlite3_str_appendf(&x, " (pUse=0x%p, nUse=%d)", pCte->pUse, pCte->pUse->nUse); } sqlite3StrAccumFinish(&x); sqlite3TreeViewItem(pView, zLine, i<pWith->nCte-1); sqlite3TreeViewSelect(pView, pCte->pSelect, 0); sqlite3TreeViewPop(pView); } sqlite3TreeViewPop(pView); } } /* ** Generate a human-readable description of a SrcList object. */ void sqlite3TreeViewSrcList(TreeView *pView, const SrcList *pSrc){ int i; for(i=0; i<pSrc->nSrc; i++){ const SrcItem *pItem = &pSrc->a[i]; StrAccum x; char zLine[100]; sqlite3StrAccumInit(&x, 0, zLine, sizeof(zLine), 0); x.printfFlags |= SQLITE_PRINTF_INTERNAL; sqlite3_str_appendf(&x, "{%d:*} %!S", pItem->iCursor, pItem); if( pItem->pTab ){ sqlite3_str_appendf(&x, " tab=%Q nCol=%d ptr=%p used=%llx", pItem->pTab->zName, pItem->pTab->nCol, pItem->pTab, pItem->colUsed); } if( pItem->fg.jointype & JT_LEFT ){ sqlite3_str_appendf(&x, " LEFT-JOIN"); }else if( pItem->fg.jointype & JT_CROSS ){ sqlite3_str_appendf(&x, " CROSS-JOIN"); } if( pItem->fg.fromDDL ){ sqlite3_str_appendf(&x, " DDL"); } if( pItem->fg.isCte ){ sqlite3_str_appendf(&x, " CteUse=0x%p", pItem->u2.pCteUse); } sqlite3StrAccumFinish(&x); sqlite3TreeViewItem(pView, zLine, i<pSrc->nSrc-1); if( pItem->pSelect ){ sqlite3TreeViewSelect(pView, pItem->pSelect, 0); } if( pItem->fg.isTabFunc ){ |
︙ | ︙ | |||
171 172 173 174 175 176 177 | pView = sqlite3TreeViewPush(pView, moreToFollow); if( p->pWith ){ sqlite3TreeViewWith(pView, p->pWith, 1); cnt = 1; sqlite3TreeViewPush(pView, 1); } do{ | > > > | | | | | | | > > | > > | 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 | pView = sqlite3TreeViewPush(pView, moreToFollow); if( p->pWith ){ sqlite3TreeViewWith(pView, p->pWith, 1); cnt = 1; sqlite3TreeViewPush(pView, 1); } do{ if( p->selFlags & SF_WhereBegin ){ sqlite3TreeViewLine(pView, "sqlite3WhereBegin()"); }else{ sqlite3TreeViewLine(pView, "SELECT%s%s (%u/%p) selFlags=0x%x nSelectRow=%d", ((p->selFlags & SF_Distinct) ? " DISTINCT" : ""), ((p->selFlags & SF_Aggregate) ? " agg_flag" : ""), p->selId, p, p->selFlags, (int)p->nSelectRow ); } if( cnt++ ) sqlite3TreeViewPop(pView); if( p->pPrior ){ n = 1000; }else{ n = 0; if( p->pSrc && p->pSrc->nSrc ) n++; if( p->pWhere ) n++; if( p->pGroupBy ) n++; if( p->pHaving ) n++; if( p->pOrderBy ) n++; if( p->pLimit ) n++; #ifndef SQLITE_OMIT_WINDOWFUNC if( p->pWin ) n++; if( p->pWinDefn ) n++; #endif } if( p->pEList ){ sqlite3TreeViewExprList(pView, p->pEList, n>0, "result-set"); } n--; #ifndef SQLITE_OMIT_WINDOWFUNC if( p->pWin ){ Window *pX; pView = sqlite3TreeViewPush(pView, (n--)>0); sqlite3TreeViewLine(pView, "window-functions"); for(pX=p->pWin; pX; pX=pX->pNextWin){ sqlite3TreeViewWinFunc(pView, pX, pX->pNextWin!=0); |
︙ | ︙ | |||
304 305 306 307 308 309 310 311 312 | #endif /* SQLITE_OMIT_WINDOWFUNC */ #ifndef SQLITE_OMIT_WINDOWFUNC /* ** Generate a human-readable explanation for a Window object */ void sqlite3TreeViewWindow(TreeView *pView, const Window *pWin, u8 more){ pView = sqlite3TreeViewPush(pView, more); if( pWin->zName ){ | > > > > > > | | > > > > > > > > > | | | > > > > > > | > > > > > > > > > > > > > > > > > | 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 | #endif /* SQLITE_OMIT_WINDOWFUNC */ #ifndef SQLITE_OMIT_WINDOWFUNC /* ** Generate a human-readable explanation for a Window object */ void sqlite3TreeViewWindow(TreeView *pView, const Window *pWin, u8 more){ int nElement = 0; if( pWin->pFilter ){ sqlite3TreeViewItem(pView, "FILTER", 1); sqlite3TreeViewExpr(pView, pWin->pFilter, 0); sqlite3TreeViewPop(pView); } pView = sqlite3TreeViewPush(pView, more); if( pWin->zName ){ sqlite3TreeViewLine(pView, "OVER %s (%p)", pWin->zName, pWin); }else{ sqlite3TreeViewLine(pView, "OVER (%p)", pWin); } if( pWin->zBase ) nElement++; if( pWin->pOrderBy ) nElement++; if( pWin->eFrmType ) nElement++; if( pWin->eExclude ) nElement++; if( pWin->zBase ){ sqlite3TreeViewPush(pView, (--nElement)>0); sqlite3TreeViewLine(pView, "window: %s", pWin->zBase); sqlite3TreeViewPop(pView); } if( pWin->pPartition ){ sqlite3TreeViewExprList(pView, pWin->pPartition, nElement>0,"PARTITION-BY"); } if( pWin->pOrderBy ){ sqlite3TreeViewExprList(pView, pWin->pOrderBy, (--nElement)>0, "ORDER-BY"); } if( pWin->eFrmType ){ char zBuf[30]; const char *zFrmType = "ROWS"; if( pWin->eFrmType==TK_RANGE ) zFrmType = "RANGE"; if( pWin->eFrmType==TK_GROUPS ) zFrmType = "GROUPS"; sqlite3_snprintf(sizeof(zBuf),zBuf,"%s%s",zFrmType, pWin->bImplicitFrame ? " (implied)" : ""); sqlite3TreeViewItem(pView, zBuf, (--nElement)>0); sqlite3TreeViewBound(pView, pWin->eStart, pWin->pStart, 1); sqlite3TreeViewBound(pView, pWin->eEnd, pWin->pEnd, 0); sqlite3TreeViewPop(pView); } if( pWin->eExclude ){ char zBuf[30]; const char *zExclude; switch( pWin->eExclude ){ case TK_NO: zExclude = "NO OTHERS"; break; case TK_CURRENT: zExclude = "CURRENT ROW"; break; case TK_GROUP: zExclude = "GROUP"; break; case TK_TIES: zExclude = "TIES"; break; default: sqlite3_snprintf(sizeof(zBuf),zBuf,"invalid(%d)", pWin->eExclude); zExclude = zBuf; break; } sqlite3TreeViewPush(pView, 0); sqlite3TreeViewLine(pView, "EXCLUDE %s", zExclude); sqlite3TreeViewPop(pView); } sqlite3TreeViewPop(pView); } #endif /* SQLITE_OMIT_WINDOWFUNC */ #ifndef SQLITE_OMIT_WINDOWFUNC /* ** Generate a human-readable explanation for a Window Function object |
︙ | ︙ | |||
345 346 347 348 349 350 351 | /* ** Generate a human-readable explanation of an expression tree. */ void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){ const char *zBinOp = 0; /* Binary operator */ const char *zUniOp = 0; /* Unary operator */ | | | > > > > < | < > > | > > > > > > > > > > | > > | | > > > | | > > > > | 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 | /* ** Generate a human-readable explanation of an expression tree. */ void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){ const char *zBinOp = 0; /* Binary operator */ const char *zUniOp = 0; /* Unary operator */ char zFlgs[200]; pView = sqlite3TreeViewPush(pView, moreToFollow); if( pExpr==0 ){ sqlite3TreeViewLine(pView, "nil"); sqlite3TreeViewPop(pView); return; } if( pExpr->flags || pExpr->affExpr || pExpr->vvaFlags ){ StrAccum x; sqlite3StrAccumInit(&x, 0, zFlgs, sizeof(zFlgs), 0); sqlite3_str_appendf(&x, " fg.af=%x.%c", pExpr->flags, pExpr->affExpr ? pExpr->affExpr : 'n'); if( ExprHasProperty(pExpr, EP_FromJoin) ){ sqlite3_str_appendf(&x, " iRJT=%d", pExpr->iRightJoinTable); } if( ExprHasProperty(pExpr, EP_FromDDL) ){ sqlite3_str_appendf(&x, " DDL"); } if( ExprHasVVAProperty(pExpr, EP_Immutable) ){ sqlite3_str_appendf(&x, " IMMUTABLE"); } sqlite3StrAccumFinish(&x); }else{ zFlgs[0] = 0; } switch( pExpr->op ){ case TK_AGG_COLUMN: { sqlite3TreeViewLine(pView, "AGG{%d:%d}%s", pExpr->iTable, pExpr->iColumn, zFlgs); break; } case TK_COLUMN: { if( pExpr->iTable<0 ){ /* This only happens when coding check constraints */ char zOp2[16]; if( pExpr->op2 ){ sqlite3_snprintf(sizeof(zOp2),zOp2," op2=0x%02x",pExpr->op2); }else{ zOp2[0] = 0; } sqlite3TreeViewLine(pView, "COLUMN(%d)%s%s", pExpr->iColumn, zFlgs, zOp2); }else{ assert( ExprUseYTab(pExpr) ); sqlite3TreeViewLine(pView, "{%d:%d} pTab=%p%s", pExpr->iTable, pExpr->iColumn, pExpr->y.pTab, zFlgs); } if( ExprHasProperty(pExpr, EP_FixedCol) ){ sqlite3TreeViewExpr(pView, pExpr->pLeft, 0); } break; } case TK_INTEGER: { if( pExpr->flags & EP_IntValue ){ sqlite3TreeViewLine(pView, "%d", pExpr->u.iValue); }else{ sqlite3TreeViewLine(pView, "%s", pExpr->u.zToken); } break; } #ifndef SQLITE_OMIT_FLOATING_POINT case TK_FLOAT: { assert( !ExprHasProperty(pExpr, EP_IntValue) ); sqlite3TreeViewLine(pView,"%s", pExpr->u.zToken); break; } #endif case TK_STRING: { assert( !ExprHasProperty(pExpr, EP_IntValue) ); sqlite3TreeViewLine(pView,"%Q", pExpr->u.zToken); break; } case TK_NULL: { sqlite3TreeViewLine(pView,"NULL"); break; } case TK_TRUEFALSE: { sqlite3TreeViewLine(pView,"%s%s", sqlite3ExprTruthValue(pExpr) ? "TRUE" : "FALSE", zFlgs); break; } #ifndef SQLITE_OMIT_BLOB_LITERAL case TK_BLOB: { assert( !ExprHasProperty(pExpr, EP_IntValue) ); sqlite3TreeViewLine(pView,"%s", pExpr->u.zToken); break; } #endif case TK_VARIABLE: { assert( !ExprHasProperty(pExpr, EP_IntValue) ); sqlite3TreeViewLine(pView,"VARIABLE(%s,%d)", pExpr->u.zToken, pExpr->iColumn); break; } case TK_REGISTER: { sqlite3TreeViewLine(pView,"REGISTER(%d)", pExpr->iTable); break; } case TK_ID: { assert( !ExprHasProperty(pExpr, EP_IntValue) ); sqlite3TreeViewLine(pView,"ID \"%w\"", pExpr->u.zToken); break; } #ifndef SQLITE_OMIT_CAST case TK_CAST: { /* Expressions of the form: CAST(pLeft AS token) */ assert( !ExprHasProperty(pExpr, EP_IntValue) ); sqlite3TreeViewLine(pView,"CAST %Q", pExpr->u.zToken); sqlite3TreeViewExpr(pView, pExpr->pLeft, 0); break; } #endif /* SQLITE_OMIT_CAST */ case TK_LT: zBinOp = "LT"; break; case TK_LE: zBinOp = "LE"; break; |
︙ | ︙ | |||
456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 | case TK_BITAND: zBinOp = "BITAND"; break; case TK_BITOR: zBinOp = "BITOR"; break; case TK_SLASH: zBinOp = "DIV"; break; case TK_LSHIFT: zBinOp = "LSHIFT"; break; case TK_RSHIFT: zBinOp = "RSHIFT"; break; case TK_CONCAT: zBinOp = "CONCAT"; break; case TK_DOT: zBinOp = "DOT"; break; case TK_UMINUS: zUniOp = "UMINUS"; break; case TK_UPLUS: zUniOp = "UPLUS"; break; case TK_BITNOT: zUniOp = "BITNOT"; break; case TK_NOT: zUniOp = "NOT"; break; case TK_ISNULL: zUniOp = "ISNULL"; break; case TK_NOTNULL: zUniOp = "NOTNULL"; break; case TK_TRUTH: { int x; const char *azOp[] = { "IS-FALSE", "IS-TRUE", "IS-NOT-FALSE", "IS-NOT-TRUE" }; assert( pExpr->op2==TK_IS || pExpr->op2==TK_ISNOT ); assert( pExpr->pRight ); | > | > > > > > > > | > > > | > | | > > > > > > > > > > > > > | > > | | > | > > | | | 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 | case TK_BITAND: zBinOp = "BITAND"; break; case TK_BITOR: zBinOp = "BITOR"; break; case TK_SLASH: zBinOp = "DIV"; break; case TK_LSHIFT: zBinOp = "LSHIFT"; break; case TK_RSHIFT: zBinOp = "RSHIFT"; break; case TK_CONCAT: zBinOp = "CONCAT"; break; case TK_DOT: zBinOp = "DOT"; break; case TK_LIMIT: zBinOp = "LIMIT"; break; case TK_UMINUS: zUniOp = "UMINUS"; break; case TK_UPLUS: zUniOp = "UPLUS"; break; case TK_BITNOT: zUniOp = "BITNOT"; break; case TK_NOT: zUniOp = "NOT"; break; case TK_ISNULL: zUniOp = "ISNULL"; break; case TK_NOTNULL: zUniOp = "NOTNULL"; break; case TK_TRUTH: { int x; const char *azOp[] = { "IS-FALSE", "IS-TRUE", "IS-NOT-FALSE", "IS-NOT-TRUE" }; assert( pExpr->op2==TK_IS || pExpr->op2==TK_ISNOT ); assert( pExpr->pRight ); assert( sqlite3ExprSkipCollate(pExpr->pRight)->op==TK_TRUEFALSE ); x = (pExpr->op2==TK_ISNOT)*2 + sqlite3ExprTruthValue(pExpr->pRight); zUniOp = azOp[x]; break; } case TK_SPAN: { assert( !ExprHasProperty(pExpr, EP_IntValue) ); sqlite3TreeViewLine(pView, "SPAN %Q", pExpr->u.zToken); sqlite3TreeViewExpr(pView, pExpr->pLeft, 0); break; } case TK_COLLATE: { /* COLLATE operators without the EP_Collate flag are intended to ** emulate collation associated with a table column. These show ** up in the treeview output as "SOFT-COLLATE". Explicit COLLATE ** operators that appear in the original SQL always have the ** EP_Collate bit set and appear in treeview output as just "COLLATE" */ assert( !ExprHasProperty(pExpr, EP_IntValue) ); sqlite3TreeViewLine(pView, "%sCOLLATE %Q%s", !ExprHasProperty(pExpr, EP_Collate) ? "SOFT-" : "", pExpr->u.zToken, zFlgs); sqlite3TreeViewExpr(pView, pExpr->pLeft, 0); break; } case TK_AGG_FUNCTION: case TK_FUNCTION: { ExprList *pFarg; /* List of function arguments */ Window *pWin; if( ExprHasProperty(pExpr, EP_TokenOnly) ){ pFarg = 0; pWin = 0; }else{ assert( ExprUseXList(pExpr) ); pFarg = pExpr->x.pList; #ifndef SQLITE_OMIT_WINDOWFUNC pWin = ExprHasProperty(pExpr, EP_WinFunc) ? pExpr->y.pWin : 0; #else pWin = 0; #endif } assert( !ExprHasProperty(pExpr, EP_IntValue) ); if( pExpr->op==TK_AGG_FUNCTION ){ sqlite3TreeViewLine(pView, "AGG_FUNCTION%d %Q%s agg=%d[%d]/%p", pExpr->op2, pExpr->u.zToken, zFlgs, pExpr->pAggInfo ? pExpr->pAggInfo->selId : 0, pExpr->iAgg, pExpr->pAggInfo); }else if( pExpr->op2!=0 ){ const char *zOp2; char zBuf[8]; sqlite3_snprintf(sizeof(zBuf),zBuf,"0x%02x",pExpr->op2); zOp2 = zBuf; if( pExpr->op2==NC_IsCheck ) zOp2 = "NC_IsCheck"; if( pExpr->op2==NC_IdxExpr ) zOp2 = "NC_IdxExpr"; if( pExpr->op2==NC_PartIdx ) zOp2 = "NC_PartIdx"; if( pExpr->op2==NC_GenCol ) zOp2 = "NC_GenCol"; sqlite3TreeViewLine(pView, "FUNCTION %Q%s op2=%s", pExpr->u.zToken, zFlgs, zOp2); }else{ sqlite3TreeViewLine(pView, "FUNCTION %Q%s", pExpr->u.zToken, zFlgs); } if( pFarg ){ sqlite3TreeViewExprList(pView, pFarg, pWin!=0, 0); } #ifndef SQLITE_OMIT_WINDOWFUNC if( pWin ){ sqlite3TreeViewWindow(pView, pWin, 0); } #endif break; } #ifndef SQLITE_OMIT_SUBQUERY case TK_EXISTS: { assert( ExprUseXSelect(pExpr) ); sqlite3TreeViewLine(pView, "EXISTS-expr flags=0x%x", pExpr->flags); sqlite3TreeViewSelect(pView, pExpr->x.pSelect, 0); break; } case TK_SELECT: { assert( ExprUseXSelect(pExpr) ); sqlite3TreeViewLine(pView, "subquery-expr flags=0x%x", pExpr->flags); sqlite3TreeViewSelect(pView, pExpr->x.pSelect, 0); break; } case TK_IN: { sqlite3TreeViewLine(pView, "IN flags=0x%x", pExpr->flags); sqlite3TreeViewExpr(pView, pExpr->pLeft, 1); if( ExprUseXSelect(pExpr) ){ sqlite3TreeViewSelect(pView, pExpr->x.pSelect, 0); }else{ sqlite3TreeViewExprList(pView, pExpr->x.pList, 0, 0); } break; } #endif /* SQLITE_OMIT_SUBQUERY */ /* ** x BETWEEN y AND z ** ** This is equivalent to ** ** x>=y AND x<=z ** ** X is stored in pExpr->pLeft. ** Y is stored in pExpr->pList->a[0].pExpr. ** Z is stored in pExpr->pList->a[1].pExpr. */ case TK_BETWEEN: { const Expr *pX, *pY, *pZ; pX = pExpr->pLeft; assert( ExprUseXList(pExpr) ); assert( pExpr->x.pList->nExpr==2 ); pY = pExpr->x.pList->a[0].pExpr; pZ = pExpr->x.pList->a[1].pExpr; sqlite3TreeViewLine(pView, "BETWEEN"); sqlite3TreeViewExpr(pView, pX, 1); sqlite3TreeViewExpr(pView, pY, 1); sqlite3TreeViewExpr(pView, pZ, 0); break; } case TK_TRIGGER: { |
︙ | ︙ | |||
579 580 581 582 583 584 585 586 587 588 589 590 591 | sqlite3TreeViewLine(pView, "%s(%d)", pExpr->iTable ? "NEW" : "OLD", pExpr->iColumn); break; } case TK_CASE: { sqlite3TreeViewLine(pView, "CASE"); sqlite3TreeViewExpr(pView, pExpr->pLeft, 1); sqlite3TreeViewExprList(pView, pExpr->x.pList, 0, 0); break; } #ifndef SQLITE_OMIT_TRIGGER case TK_RAISE: { const char *zType = "unk"; | > | > > > | > | > > > > > > > > > > > > > > > > > > > > | | 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 | sqlite3TreeViewLine(pView, "%s(%d)", pExpr->iTable ? "NEW" : "OLD", pExpr->iColumn); break; } case TK_CASE: { sqlite3TreeViewLine(pView, "CASE"); sqlite3TreeViewExpr(pView, pExpr->pLeft, 1); assert( ExprUseXList(pExpr) ); sqlite3TreeViewExprList(pView, pExpr->x.pList, 0, 0); break; } #ifndef SQLITE_OMIT_TRIGGER case TK_RAISE: { const char *zType = "unk"; switch( pExpr->affExpr ){ case OE_Rollback: zType = "rollback"; break; case OE_Abort: zType = "abort"; break; case OE_Fail: zType = "fail"; break; case OE_Ignore: zType = "ignore"; break; } assert( !ExprHasProperty(pExpr, EP_IntValue) ); sqlite3TreeViewLine(pView, "RAISE %s(%Q)", zType, pExpr->u.zToken); break; } #endif case TK_MATCH: { sqlite3TreeViewLine(pView, "MATCH {%d:%d}%s", pExpr->iTable, pExpr->iColumn, zFlgs); sqlite3TreeViewExpr(pView, pExpr->pRight, 0); break; } case TK_VECTOR: { char *z = sqlite3_mprintf("VECTOR%s",zFlgs); assert( ExprUseXList(pExpr) ); sqlite3TreeViewBareExprList(pView, pExpr->x.pList, z); sqlite3_free(z); break; } case TK_SELECT_COLUMN: { sqlite3TreeViewLine(pView, "SELECT-COLUMN %d of [0..%d]%s", pExpr->iColumn, pExpr->iTable-1, pExpr->pRight==pExpr->pLeft ? " (SELECT-owner)" : ""); assert( ExprUseXSelect(pExpr->pLeft) ); sqlite3TreeViewSelect(pView, pExpr->pLeft->x.pSelect, 0); break; } case TK_IF_NULL_ROW: { sqlite3TreeViewLine(pView, "IF-NULL-ROW %d", pExpr->iTable); sqlite3TreeViewExpr(pView, pExpr->pLeft, 0); break; } case TK_ERROR: { Expr tmp; sqlite3TreeViewLine(pView, "ERROR"); tmp = *pExpr; tmp.op = pExpr->op2; sqlite3TreeViewExpr(pView, &tmp, 0); break; } case TK_ROW: { if( pExpr->iColumn<=0 ){ sqlite3TreeViewLine(pView, "First FROM table rowid"); }else{ sqlite3TreeViewLine(pView, "First FROM table column %d", pExpr->iColumn-1); } break; } default: { sqlite3TreeViewLine(pView, "op=%d", pExpr->op); break; } } if( zBinOp ){ sqlite3TreeViewLine(pView, "%s%s", zBinOp, zFlgs); sqlite3TreeViewExpr(pView, pExpr->pLeft, 1); sqlite3TreeViewExpr(pView, pExpr->pRight, 0); }else if( zUniOp ){ sqlite3TreeViewLine(pView, "%s%s", zUniOp, zFlgs); sqlite3TreeViewExpr(pView, pExpr->pLeft, 0); } sqlite3TreeViewPop(pView); } /* ** Generate a human-readable explanation of an expression list. |
︙ | ︙ | |||
648 649 650 651 652 653 654 | if( pList==0 ){ sqlite3TreeViewLine(pView, "%s (empty)", zLabel); }else{ int i; sqlite3TreeViewLine(pView, "%s", zLabel); for(i=0; i<pList->nExpr; i++){ int j = pList->a[i].u.x.iOrderByCol; | | > | 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 | if( pList==0 ){ sqlite3TreeViewLine(pView, "%s (empty)", zLabel); }else{ int i; sqlite3TreeViewLine(pView, "%s", zLabel); for(i=0; i<pList->nExpr; i++){ int j = pList->a[i].u.x.iOrderByCol; char *zName = pList->a[i].zEName; int moreToFollow = i<pList->nExpr - 1; if( pList->a[i].eEName!=ENAME_NAME ) zName = 0; if( j || zName ){ sqlite3TreeViewPush(pView, moreToFollow); moreToFollow = 0; sqlite3TreeViewLine(pView, 0); if( zName ){ fprintf(stdout, "AS %s ", zName); } |
︙ | ︙ |
Changes to src/trigger.c.
︙ | ︙ | |||
22 23 24 25 26 27 28 29 30 31 32 33 34 35 | pTriggerStep = pTriggerStep->pNext; sqlite3ExprDelete(db, pTmp->pWhere); sqlite3ExprListDelete(db, pTmp->pExprList); sqlite3SelectDelete(db, pTmp->pSelect); sqlite3IdListDelete(db, pTmp->pIdList); sqlite3UpsertDelete(db, pTmp->pUpsert); sqlite3DbFree(db, pTmp->zSpan); sqlite3DbFree(db, pTmp); } } /* | > | 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | pTriggerStep = pTriggerStep->pNext; sqlite3ExprDelete(db, pTmp->pWhere); sqlite3ExprListDelete(db, pTmp->pExprList); sqlite3SelectDelete(db, pTmp->pSelect); sqlite3IdListDelete(db, pTmp->pIdList); sqlite3UpsertDelete(db, pTmp->pUpsert); sqlite3SrcListDelete(db, pTmp->pFrom); sqlite3DbFree(db, pTmp->zSpan); sqlite3DbFree(db, pTmp); } } /* |
︙ | ︙ | |||
43 44 45 46 47 48 49 | ** and returns the combined list. ** ** To state it another way: This routine returns a list of all triggers ** that fire off of pTab. The list will include any TEMP triggers on ** pTab as well as the triggers lised in pTab->pTrigger. */ Trigger *sqlite3TriggerList(Parse *pParse, Table *pTab){ | | | > | < < < | > > | | > | > | | | > > > > > > > > > > > | > | > > > > > > | > > | > | | 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 | ** and returns the combined list. ** ** To state it another way: This routine returns a list of all triggers ** that fire off of pTab. The list will include any TEMP triggers on ** pTab as well as the triggers lised in pTab->pTrigger. */ Trigger *sqlite3TriggerList(Parse *pParse, Table *pTab){ Schema *pTmpSchema; /* Schema of the pTab table */ Trigger *pList; /* List of triggers to return */ HashElem *p; /* Loop variable for TEMP triggers */ if( pParse->disableTriggers ){ return 0; } pTmpSchema = pParse->db->aDb[1].pSchema; p = sqliteHashFirst(&pTmpSchema->trigHash); pList = pTab->pTrigger; while( p ){ Trigger *pTrig = (Trigger *)sqliteHashData(p); if( pTrig->pTabSchema==pTab->pSchema && pTrig->table && 0==sqlite3StrICmp(pTrig->table, pTab->zName) && pTrig->pTabSchema!=pTmpSchema ){ pTrig->pNext = pList; pList = pTrig; }else if( pTrig->op==TK_RETURNING #ifndef SQLITE_OMIT_VIRTUALTABLE && pParse->db->pVtabCtx==0 #endif ){ assert( pParse->bReturning ); assert( &(pParse->u1.pReturning->retTrig) == pTrig ); pTrig->table = pTab->zName; pTrig->pTabSchema = pTab->pSchema; pTrig->pNext = pList; pList = pTrig; } p = sqliteHashNext(p); } #if 0 if( pList ){ Trigger *pX; printf("Triggers for %s:", pTab->zName); for(pX=pList; pX; pX=pX->pNext){ printf(" %s", pX->zName); } printf("\n"); fflush(stdout); } #endif return pList; } /* ** This is called by the parser when it sees a CREATE TRIGGER statement ** up to the point of the BEGIN before the trigger actions. A Trigger ** structure is generated based on the information available and stored ** in pParse->pNewTrigger. After the trigger actions have been parsed, the |
︙ | ︙ | |||
124 125 126 127 128 129 130 | /* A long-standing parser bug is that this syntax was allowed: ** ** CREATE TRIGGER attached.demo AFTER INSERT ON attached.tab .... ** ^^^^^^^^ ** ** To maintain backwards compatibility, ignore the database | | | 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 | /* A long-standing parser bug is that this syntax was allowed: ** ** CREATE TRIGGER attached.demo AFTER INSERT ON attached.tab .... ** ^^^^^^^^ ** ** To maintain backwards compatibility, ignore the database ** name on pTableName if we are reparsing out of the schema table */ if( db->init.busy && iDb!=1 ){ sqlite3DbFree(db, pTableName->a[0].zDatabase); pTableName->a[0].zDatabase = 0; } /* If the trigger name was unqualified, and the table is a temp table, |
︙ | ︙ | |||
152 153 154 155 156 157 158 | sqlite3FixInit(&sFix, pParse, iDb, "trigger", pName); if( sqlite3FixSrcList(&sFix, pTableName) ){ goto trigger_cleanup; } pTab = sqlite3SrcListLookup(pParse, pTableName); if( !pTab ){ /* The table does not exist. */ | < < < < < < < < < < < | | > > > > | | 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 | sqlite3FixInit(&sFix, pParse, iDb, "trigger", pName); if( sqlite3FixSrcList(&sFix, pTableName) ){ goto trigger_cleanup; } pTab = sqlite3SrcListLookup(pParse, pTableName); if( !pTab ){ /* The table does not exist. */ goto trigger_orphan_error; } if( IsVirtual(pTab) ){ sqlite3ErrorMsg(pParse, "cannot create triggers on virtual tables"); goto trigger_orphan_error; } /* Check that the trigger name is not reserved and that no trigger of the ** specified name exists */ zName = sqlite3NameFromToken(db, pName); if( zName==0 ){ assert( db->mallocFailed ); goto trigger_cleanup; } if( sqlite3CheckObjectName(pParse, zName, "trigger", pTab->zName) ){ goto trigger_cleanup; } assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); if( !IN_RENAME_OBJECT ){ if( sqlite3HashFind(&(db->aDb[iDb].pSchema->trigHash),zName) ){ if( !noErr ){ sqlite3ErrorMsg(pParse, "trigger %T already exists", pName); |
︙ | ︙ | |||
198 199 200 201 202 203 204 | sqlite3ErrorMsg(pParse, "cannot create trigger on system table"); goto trigger_cleanup; } /* INSTEAD of triggers are only for views and views only support INSTEAD ** of triggers. */ | | | | | | | | 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 | sqlite3ErrorMsg(pParse, "cannot create trigger on system table"); goto trigger_cleanup; } /* INSTEAD of triggers are only for views and views only support INSTEAD ** of triggers. */ if( IsView(pTab) && tr_tm!=TK_INSTEAD ){ sqlite3ErrorMsg(pParse, "cannot create %s trigger on view: %S", (tr_tm == TK_BEFORE)?"BEFORE":"AFTER", pTableName->a); goto trigger_orphan_error; } if( !IsView(pTab) && tr_tm==TK_INSTEAD ){ sqlite3ErrorMsg(pParse, "cannot create INSTEAD OF" " trigger on table: %S", pTableName->a); goto trigger_orphan_error; } #ifndef SQLITE_OMIT_AUTHORIZATION if( !IN_RENAME_OBJECT ){ int iTabDb = sqlite3SchemaToIndex(db, pTab->pSchema); int code = SQLITE_CREATE_TRIGGER; const char *zDb = db->aDb[iTabDb].zDbSName; |
︙ | ︙ | |||
266 267 268 269 270 271 272 273 274 275 276 277 278 279 | sqlite3IdListDelete(db, pColumns); sqlite3ExprDelete(db, pWhen); if( !pParse->pNewTrigger ){ sqlite3DeleteTrigger(db, pTrigger); }else{ assert( pParse->pNewTrigger==pTrigger ); } } /* ** This routine is called after all of the trigger actions have been parsed ** in order to complete the process of building the trigger. */ void sqlite3FinishTrigger( | > > > > > > > > > > > > > > > > > | 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 | sqlite3IdListDelete(db, pColumns); sqlite3ExprDelete(db, pWhen); if( !pParse->pNewTrigger ){ sqlite3DeleteTrigger(db, pTrigger); }else{ assert( pParse->pNewTrigger==pTrigger ); } return; trigger_orphan_error: if( db->init.iDb==1 ){ /* Ticket #3810. ** Normally, whenever a table is dropped, all associated triggers are ** dropped too. But if a TEMP trigger is created on a non-TEMP table ** and the table is dropped by a different database connection, the ** trigger is not visible to the database connection that does the ** drop so the trigger cannot be dropped. This results in an ** "orphaned trigger" - a trigger whose associated table is missing. ** ** 2020-11-05 see also https://sqlite.org/forum/forumpost/157dc791df */ db->init.orphanTrigger = 1; } goto trigger_cleanup; } /* ** This routine is called after all of the trigger actions have been parsed ** in order to complete the process of building the trigger. */ void sqlite3FinishTrigger( |
︙ | ︙ | |||
310 311 312 313 314 315 316 | assert( !db->init.busy ); pParse->pNewTrigger = pTrig; pTrig = 0; }else #endif /* if we are not initializing, | | | > | | | > | 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 | assert( !db->init.busy ); pParse->pNewTrigger = pTrig; pTrig = 0; }else #endif /* if we are not initializing, ** build the sqlite_schema entry */ if( !db->init.busy ){ Vdbe *v; char *z; /* Make an entry in the sqlite_schema table */ v = sqlite3GetVdbe(pParse); if( v==0 ) goto triggerfinish_cleanup; sqlite3BeginWriteOperation(pParse, 0, iDb); z = sqlite3DbStrNDup(db, (char*)pAll->z, pAll->n); testcase( z==0 ); sqlite3NestedParse(pParse, "INSERT INTO %Q." LEGACY_SCHEMA_TABLE " VALUES('trigger',%Q,%Q,0,'CREATE TRIGGER %q')", db->aDb[iDb].zDbSName, zName, pTrig->table, z); sqlite3DbFree(db, z); sqlite3ChangeCookie(pParse, iDb); sqlite3VdbeAddParseSchemaOp(v, iDb, sqlite3MPrintf(db, "type='trigger' AND name='%q'", zName), 0); } if( db->init.busy ){ Trigger *pLink = pTrig; Hash *pHash = &db->aDb[iDb].pSchema->trigHash; assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); assert( pLink!=0 ); pTrig = sqlite3HashInsert(pHash, zName, pTrig); if( pTrig ){ sqlite3OomFault(db); }else if( pLink->pSchema==pLink->pTabSchema ){ Table *pTab; pTab = sqlite3HashFind(&pLink->pTabSchema->tblHash, pLink->table); assert( pTab!=0 ); |
︙ | ︙ | |||
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 | pSelect = 0; }else{ pTriggerStep->pSelect = sqlite3SelectDup(db, pSelect, EXPRDUP_REDUCE); } pTriggerStep->pIdList = pColumn; pTriggerStep->pUpsert = pUpsert; pTriggerStep->orconf = orconf; }else{ testcase( pColumn ); sqlite3IdListDelete(db, pColumn); testcase( pUpsert ); sqlite3UpsertDelete(db, pUpsert); } sqlite3SelectDelete(db, pSelect); return pTriggerStep; } /* ** Construct a trigger step that implements an UPDATE statement and return ** a pointer to that trigger step. The parser calls this routine when it ** sees an UPDATE statement inside the body of a CREATE TRIGGER. */ TriggerStep *sqlite3TriggerUpdateStep( Parse *pParse, /* Parser */ Token *pTableName, /* Name of the table to be updated */ ExprList *pEList, /* The SET clause: list of column and new values */ Expr *pWhere, /* The WHERE clause */ u8 orconf, /* The conflict algorithm. (OE_Abort, OE_Ignore, etc) */ const char *zStart, /* Start of SQL text */ const char *zEnd /* End of SQL text */ ){ sqlite3 *db = pParse->db; TriggerStep *pTriggerStep; pTriggerStep = triggerStepAllocate(pParse, TK_UPDATE, pTableName,zStart,zEnd); if( pTriggerStep ){ if( IN_RENAME_OBJECT ){ pTriggerStep->pExprList = pEList; pTriggerStep->pWhere = pWhere; pEList = 0; pWhere = 0; }else{ pTriggerStep->pExprList = sqlite3ExprListDup(db, pEList, EXPRDUP_REDUCE); pTriggerStep->pWhere = sqlite3ExprDup(db, pWhere, EXPRDUP_REDUCE); } pTriggerStep->orconf = orconf; } sqlite3ExprListDelete(db, pEList); sqlite3ExprDelete(db, pWhere); return pTriggerStep; } /* ** Construct a trigger step that implements a DELETE statement and return ** a pointer to that trigger step. The parser calls this routine when it ** sees a DELETE statement inside the body of a CREATE TRIGGER. | > > > > > > > > | 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 | pSelect = 0; }else{ pTriggerStep->pSelect = sqlite3SelectDup(db, pSelect, EXPRDUP_REDUCE); } pTriggerStep->pIdList = pColumn; pTriggerStep->pUpsert = pUpsert; pTriggerStep->orconf = orconf; if( pUpsert ){ sqlite3HasExplicitNulls(pParse, pUpsert->pUpsertTarget); } }else{ testcase( pColumn ); sqlite3IdListDelete(db, pColumn); testcase( pUpsert ); sqlite3UpsertDelete(db, pUpsert); } sqlite3SelectDelete(db, pSelect); return pTriggerStep; } /* ** Construct a trigger step that implements an UPDATE statement and return ** a pointer to that trigger step. The parser calls this routine when it ** sees an UPDATE statement inside the body of a CREATE TRIGGER. */ TriggerStep *sqlite3TriggerUpdateStep( Parse *pParse, /* Parser */ Token *pTableName, /* Name of the table to be updated */ SrcList *pFrom, ExprList *pEList, /* The SET clause: list of column and new values */ Expr *pWhere, /* The WHERE clause */ u8 orconf, /* The conflict algorithm. (OE_Abort, OE_Ignore, etc) */ const char *zStart, /* Start of SQL text */ const char *zEnd /* End of SQL text */ ){ sqlite3 *db = pParse->db; TriggerStep *pTriggerStep; pTriggerStep = triggerStepAllocate(pParse, TK_UPDATE, pTableName,zStart,zEnd); if( pTriggerStep ){ if( IN_RENAME_OBJECT ){ pTriggerStep->pExprList = pEList; pTriggerStep->pWhere = pWhere; pTriggerStep->pFrom = pFrom; pEList = 0; pWhere = 0; pFrom = 0; }else{ pTriggerStep->pExprList = sqlite3ExprListDup(db, pEList, EXPRDUP_REDUCE); pTriggerStep->pWhere = sqlite3ExprDup(db, pWhere, EXPRDUP_REDUCE); pTriggerStep->pFrom = sqlite3SrcListDup(db, pFrom, EXPRDUP_REDUCE); } pTriggerStep->orconf = orconf; } sqlite3ExprListDelete(db, pEList); sqlite3ExprDelete(db, pWhere); sqlite3SrcListDelete(db, pFrom); return pTriggerStep; } /* ** Construct a trigger step that implements a DELETE statement and return ** a pointer to that trigger step. The parser calls this routine when it ** sees a DELETE statement inside the body of a CREATE TRIGGER. |
︙ | ︙ | |||
533 534 535 536 537 538 539 | return pTriggerStep; } /* ** Recursively delete a Trigger structure */ void sqlite3DeleteTrigger(sqlite3 *db, Trigger *pTrigger){ | | | 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 | return pTriggerStep; } /* ** Recursively delete a Trigger structure */ void sqlite3DeleteTrigger(sqlite3 *db, Trigger *pTrigger){ if( pTrigger==0 || pTrigger->bReturning ) return; sqlite3DeleteTriggerStep(db, pTrigger->step_list); sqlite3DbFree(db, pTrigger->zName); sqlite3DbFree(db, pTrigger->table); sqlite3ExprDelete(db, pTrigger->pWhen); sqlite3IdListDelete(db, pTrigger->pColumns); sqlite3DbFree(db, pTrigger); } |
︙ | ︙ | |||
568 569 570 571 572 573 574 | assert( pName->nSrc==1 ); zDb = pName->a[0].zDatabase; zName = pName->a[0].zName; assert( zDb!=0 || sqlite3BtreeHoldsAllMutexes(db) ); for(i=OMIT_TEMPDB; i<db->nDb; i++){ int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */ | | | | 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 | assert( pName->nSrc==1 ); zDb = pName->a[0].zDatabase; zName = pName->a[0].zName; assert( zDb!=0 || sqlite3BtreeHoldsAllMutexes(db) ); for(i=OMIT_TEMPDB; i<db->nDb; i++){ int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */ if( zDb && sqlite3DbIsNamed(db, j, zDb)==0 ) continue; assert( sqlite3SchemaMutexHeld(db, j, 0) ); pTrigger = sqlite3HashFind(&(db->aDb[j].pSchema->trigHash), zName); if( pTrigger ) break; } if( !pTrigger ){ if( !noErr ){ sqlite3ErrorMsg(pParse, "no such trigger: %S", pName->a); }else{ sqlite3CodeVerifyNamedSchema(pParse, zDb); } pParse->checkSchema = 1; goto drop_trigger_cleanup; } sqlite3DropTriggerPtr(pParse, pTrigger); |
︙ | ︙ | |||
609 610 611 612 613 614 615 | Vdbe *v; sqlite3 *db = pParse->db; int iDb; iDb = sqlite3SchemaToIndex(pParse->db, pTrigger->pSchema); assert( iDb>=0 && iDb<db->nDb ); pTable = tableOfTrigger(pTrigger); | < | < > < | | > | | > | > > > > | | 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 | Vdbe *v; sqlite3 *db = pParse->db; int iDb; iDb = sqlite3SchemaToIndex(pParse->db, pTrigger->pSchema); assert( iDb>=0 && iDb<db->nDb ); pTable = tableOfTrigger(pTrigger); assert( (pTable && pTable->pSchema==pTrigger->pSchema) || iDb==1 ); #ifndef SQLITE_OMIT_AUTHORIZATION if( pTable ){ int code = SQLITE_DROP_TRIGGER; const char *zDb = db->aDb[iDb].zDbSName; const char *zTab = SCHEMA_TABLE(iDb); if( iDb==1 ) code = SQLITE_DROP_TEMP_TRIGGER; if( sqlite3AuthCheck(pParse, code, pTrigger->zName, pTable->zName, zDb) || sqlite3AuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb) ){ return; } } #endif /* Generate code to destroy the database record of the trigger. */ if( (v = sqlite3GetVdbe(pParse))!=0 ){ sqlite3NestedParse(pParse, "DELETE FROM %Q." LEGACY_SCHEMA_TABLE " WHERE name=%Q AND type='trigger'", db->aDb[iDb].zDbSName, pTrigger->zName ); sqlite3ChangeCookie(pParse, iDb); sqlite3VdbeAddOp4(v, OP_DropTrigger, iDb, 0, 0, pTrigger->zName, 0); } } /* ** Remove a trigger from the hash tables of the sqlite* pointer. */ void sqlite3UnlinkAndDeleteTrigger(sqlite3 *db, int iDb, const char *zName){ Trigger *pTrigger; Hash *pHash; assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); pHash = &(db->aDb[iDb].pSchema->trigHash); pTrigger = sqlite3HashInsert(pHash, zName, 0); if( ALWAYS(pTrigger) ){ if( pTrigger->pSchema==pTrigger->pTabSchema ){ Table *pTab = tableOfTrigger(pTrigger); if( pTab ){ Trigger **pp; for(pp=&pTab->pTrigger; *pp; pp=&((*pp)->pNext)){ if( *pp==pTrigger ){ *pp = (*pp)->pNext; break; } } } } sqlite3DeleteTrigger(db, pTrigger); db->mDbFlags |= DBFLAG_SchemaChange; } } /* ** pEList is the SET clause of an UPDATE statement. Each entry ** in pEList is of the format <id>=<expr>. If any of the entries ** in pEList have an <id> which matches an identifier in pIdList, ** then return TRUE. If pIdList==NULL, then it is considered a ** wildcard that matches anything. Likewise if pEList==NULL then ** it matches anything so always return true. Return false only ** if there is no match. */ static int checkColumnOverlap(IdList *pIdList, ExprList *pEList){ int e; if( pIdList==0 || NEVER(pEList==0) ) return 1; for(e=0; e<pEList->nExpr; e++){ if( sqlite3IdListIndex(pIdList, pEList->a[e].zEName)>=0 ) return 1; } return 0; } /* ** Return a list of all triggers on table pTab if there exists at least ** one trigger that must be fired when an operation of type 'op' is |
︙ | ︙ | |||
694 695 696 697 698 699 700 | ExprList *pChanges, /* Columns that change in an UPDATE statement */ int *pMask /* OUT: Mask of TRIGGER_BEFORE|TRIGGER_AFTER */ ){ int mask = 0; Trigger *pList = 0; Trigger *p; | > > > > > | > > > > > > | > | < > | > > > | | > > > > > > > > > > | > > > | > > > > > > > > > > | < | | | > > < < | > | | > | < > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | ExprList *pChanges, /* Columns that change in an UPDATE statement */ int *pMask /* OUT: Mask of TRIGGER_BEFORE|TRIGGER_AFTER */ ){ int mask = 0; Trigger *pList = 0; Trigger *p; pList = sqlite3TriggerList(pParse, pTab); assert( pList==0 || IsVirtual(pTab)==0 || (pList->bReturning && pList->pNext==0) ); if( pList!=0 ){ p = pList; if( (pParse->db->flags & SQLITE_EnableTrigger)==0 && pTab->pTrigger!=0 ){ /* The SQLITE_DBCONFIG_ENABLE_TRIGGER setting is off. That means that ** only TEMP triggers are allowed. Truncate the pList so that it ** includes only TEMP triggers */ if( pList==pTab->pTrigger ){ pList = 0; goto exit_triggers_exist; } while( ALWAYS(p->pNext) && p->pNext!=pTab->pTrigger ) p = p->pNext; p->pNext = 0; p = pList; } do{ if( p->op==op && checkColumnOverlap(p->pColumns, pChanges) ){ mask |= p->tr_tm; }else if( p->op==TK_RETURNING ){ /* The first time a RETURNING trigger is seen, the "op" value tells ** us what time of trigger it should be. */ assert( sqlite3IsToplevel(pParse) ); p->op = op; if( IsVirtual(pTab) ){ if( op!=TK_INSERT ){ sqlite3ErrorMsg(pParse, "%s RETURNING is not available on virtual tables", op==TK_DELETE ? "DELETE" : "UPDATE"); } p->tr_tm = TRIGGER_BEFORE; }else{ p->tr_tm = TRIGGER_AFTER; } mask |= p->tr_tm; }else if( p->bReturning && p->op==TK_INSERT && op==TK_UPDATE && sqlite3IsToplevel(pParse) ){ /* Also fire a RETURNING trigger for an UPSERT */ mask |= p->tr_tm; } p = p->pNext; }while( p ); } exit_triggers_exist: if( pMask ){ *pMask = mask; } return (mask ? pList : 0); } /* ** Convert the pStep->zTarget string into a SrcList and return a pointer ** to that SrcList. ** ** This routine adds a specific database name, if needed, to the target when ** forming the SrcList. This prevents a trigger in one database from ** referring to a target in another database. An exception is when the ** trigger is in TEMP in which case it can refer to any other database it ** wants. */ SrcList *sqlite3TriggerStepSrc( Parse *pParse, /* The parsing context */ TriggerStep *pStep /* The trigger containing the target token */ ){ sqlite3 *db = pParse->db; SrcList *pSrc; /* SrcList to be returned */ char *zName = sqlite3DbStrDup(db, pStep->zTarget); pSrc = sqlite3SrcListAppend(pParse, 0, 0, 0); assert( pSrc==0 || pSrc->nSrc==1 ); assert( zName || pSrc==0 ); if( pSrc ){ Schema *pSchema = pStep->pTrig->pSchema; pSrc->a[0].zName = zName; if( pSchema!=db->aDb[1].pSchema ){ pSrc->a[0].pSchema = pSchema; } if( pStep->pFrom ){ SrcList *pDup = sqlite3SrcListDup(db, pStep->pFrom, 0); pSrc = sqlite3SrcListAppendList(pParse, pSrc, pDup); } }else{ sqlite3DbFree(db, zName); } return pSrc; } /* ** Return true if the pExpr term from the RETURNING clause argument ** list is of the form "*". Raise an error if the terms if of the ** form "table.*". */ static int isAsteriskTerm( Parse *pParse, /* Parsing context */ Expr *pTerm /* A term in the RETURNING clause */ ){ assert( pTerm!=0 ); if( pTerm->op==TK_ASTERISK ) return 1; if( pTerm->op!=TK_DOT ) return 0; assert( pTerm->pRight!=0 ); assert( pTerm->pLeft!=0 ); if( pTerm->pRight->op!=TK_ASTERISK ) return 0; sqlite3ErrorMsg(pParse, "RETURNING may not use \"TABLE.*\" wildcards"); return 1; } /* The input list pList is the list of result set terms from a RETURNING ** clause. The table that we are returning from is pTab. ** ** This routine makes a copy of the pList, and at the same time expands ** any "*" wildcards to be the complete set of columns from pTab. */ static ExprList *sqlite3ExpandReturning( Parse *pParse, /* Parsing context */ ExprList *pList, /* The arguments to RETURNING */ Table *pTab /* The table being updated */ ){ ExprList *pNew = 0; sqlite3 *db = pParse->db; int i; for(i=0; i<pList->nExpr; i++){ Expr *pOldExpr = pList->a[i].pExpr; if( NEVER(pOldExpr==0) ) continue; if( isAsteriskTerm(pParse, pOldExpr) ){ int jj; for(jj=0; jj<pTab->nCol; jj++){ Expr *pNewExpr; if( IsHiddenColumn(pTab->aCol+jj) ) continue; pNewExpr = sqlite3Expr(db, TK_ID, pTab->aCol[jj].zCnName); pNew = sqlite3ExprListAppend(pParse, pNew, pNewExpr); if( !db->mallocFailed ){ struct ExprList_item *pItem = &pNew->a[pNew->nExpr-1]; pItem->zEName = sqlite3DbStrDup(db, pTab->aCol[jj].zCnName); pItem->eEName = ENAME_NAME; } } }else{ Expr *pNewExpr = sqlite3ExprDup(db, pOldExpr, 0); pNew = sqlite3ExprListAppend(pParse, pNew, pNewExpr); if( !db->mallocFailed && ALWAYS(pList->a[i].zEName!=0) ){ struct ExprList_item *pItem = &pNew->a[pNew->nExpr-1]; pItem->zEName = sqlite3DbStrDup(db, pList->a[i].zEName); pItem->eEName = pList->a[i].eEName; } } } return pNew; } /* ** Generate code for the RETURNING trigger. Unlike other triggers ** that invoke a subprogram in the bytecode, the code for RETURNING ** is generated in-line. */ static void codeReturningTrigger( Parse *pParse, /* Parse context */ Trigger *pTrigger, /* The trigger step that defines the RETURNING */ Table *pTab, /* The table to code triggers from */ int regIn /* The first in an array of registers */ ){ Vdbe *v = pParse->pVdbe; sqlite3 *db = pParse->db; ExprList *pNew; Returning *pReturning; Select sSelect; SrcList sFrom; assert( v!=0 ); assert( pParse->bReturning ); pReturning = pParse->u1.pReturning; assert( pTrigger == &(pReturning->retTrig) ); memset(&sSelect, 0, sizeof(sSelect)); memset(&sFrom, 0, sizeof(sFrom)); sSelect.pEList = sqlite3ExprListDup(db, pReturning->pReturnEL, 0); sSelect.pSrc = &sFrom; sFrom.nSrc = 1; sFrom.a[0].pTab = pTab; sFrom.a[0].iCursor = -1; sqlite3SelectPrep(pParse, &sSelect, 0); if( db->mallocFailed==0 && pParse->nErr==0 ){ sqlite3GenerateColumnNames(pParse, &sSelect); } sqlite3ExprListDelete(db, sSelect.pEList); pNew = sqlite3ExpandReturning(pParse, pReturning->pReturnEL, pTab); if( pNew ){ NameContext sNC; memset(&sNC, 0, sizeof(sNC)); if( pReturning->nRetCol==0 ){ pReturning->nRetCol = pNew->nExpr; pReturning->iRetCur = pParse->nTab++; } sNC.pParse = pParse; sNC.uNC.iBaseReg = regIn; sNC.ncFlags = NC_UBaseReg; pParse->eTriggerOp = pTrigger->op; pParse->pTriggerTab = pTab; if( sqlite3ResolveExprListNames(&sNC, pNew)==SQLITE_OK ){ int i; int nCol = pNew->nExpr; int reg = pParse->nMem+1; pParse->nMem += nCol+2; pReturning->iRetReg = reg; for(i=0; i<nCol; i++){ Expr *pCol = pNew->a[i].pExpr; sqlite3ExprCodeFactorable(pParse, pCol, reg+i); } sqlite3VdbeAddOp3(v, OP_MakeRecord, reg, i, reg+i); sqlite3VdbeAddOp2(v, OP_NewRowid, pReturning->iRetCur, reg+i+1); sqlite3VdbeAddOp3(v, OP_Insert, pReturning->iRetCur, reg+i, reg+i+1); } sqlite3ExprListDelete(db, pNew); pParse->eTriggerOp = 0; pParse->pTriggerTab = 0; } } /* ** Generate VDBE code for the statements inside the body of a single ** trigger. */ static int codeTriggerProgram( Parse *pParse, /* The parser context */ |
︙ | ︙ | |||
786 787 788 789 790 791 792 | P4_DYNAMIC); } #endif switch( pStep->op ){ case TK_UPDATE: { sqlite3Update(pParse, | | > | > | > < < < | 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 | P4_DYNAMIC); } #endif switch( pStep->op ){ case TK_UPDATE: { sqlite3Update(pParse, sqlite3TriggerStepSrc(pParse, pStep), sqlite3ExprListDup(db, pStep->pExprList, 0), sqlite3ExprDup(db, pStep->pWhere, 0), pParse->eOrconf, 0, 0, 0 ); sqlite3VdbeAddOp0(v, OP_ResetCount); break; } case TK_INSERT: { sqlite3Insert(pParse, sqlite3TriggerStepSrc(pParse, pStep), sqlite3SelectDup(db, pStep->pSelect, 0), sqlite3IdListDup(db, pStep->pIdList), pParse->eOrconf, sqlite3UpsertDup(db, pStep->pUpsert) ); sqlite3VdbeAddOp0(v, OP_ResetCount); break; } case TK_DELETE: { sqlite3DeleteFrom(pParse, sqlite3TriggerStepSrc(pParse, pStep), sqlite3ExprDup(db, pStep->pWhere, 0), 0, 0 ); sqlite3VdbeAddOp0(v, OP_ResetCount); break; } default: assert( pStep->op==TK_SELECT ); { SelectDest sDest; Select *pSelect = sqlite3SelectDup(db, pStep->pSelect, 0); sqlite3SelectDestInit(&sDest, SRT_Discard, 0); sqlite3Select(pParse, pSelect, &sDest); sqlite3SelectDelete(db, pSelect); break; } } } return 0; } #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS /* |
︙ | ︙ | |||
912 913 914 915 916 917 918 919 920 921 922 923 924 925 | sNC.pParse = pSubParse; pSubParse->db = db; pSubParse->pTriggerTab = pTab; pSubParse->pToplevel = pTop; pSubParse->zAuthContext = pTrigger->zName; pSubParse->eTriggerOp = pTrigger->op; pSubParse->nQueryLoop = pParse->nQueryLoop; v = sqlite3GetVdbe(pSubParse); if( v ){ VdbeComment((v, "Start: %s.%s (%s %s%s%s ON %s)", pTrigger->zName, onErrorText(orconf), (pTrigger->tr_tm==TRIGGER_BEFORE ? "BEFORE" : "AFTER"), (pTrigger->op==TK_UPDATE ? "UPDATE" : ""), | > | 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 | sNC.pParse = pSubParse; pSubParse->db = db; pSubParse->pTriggerTab = pTab; pSubParse->pToplevel = pTop; pSubParse->zAuthContext = pTrigger->zName; pSubParse->eTriggerOp = pTrigger->op; pSubParse->nQueryLoop = pParse->nQueryLoop; pSubParse->disableVtab = pParse->disableVtab; v = sqlite3GetVdbe(pSubParse); if( v ){ VdbeComment((v, "Start: %s.%s (%s %s%s%s ON %s)", pTrigger->zName, onErrorText(orconf), (pTrigger->tr_tm==TRIGGER_BEFORE ? "BEFORE" : "AFTER"), (pTrigger->op==TK_UPDATE ? "UPDATE" : ""), |
︙ | ︙ | |||
936 937 938 939 940 941 942 | #endif /* If one was specified, code the WHEN clause. If it evaluates to false ** (or NULL) the sub-vdbe is immediately halted by jumping to the ** OP_Halt inserted at the end of the program. */ if( pTrigger->pWhen ){ pWhen = sqlite3ExprDup(db, pTrigger->pWhen, 0); | > | < | | 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 | #endif /* If one was specified, code the WHEN clause. If it evaluates to false ** (or NULL) the sub-vdbe is immediately halted by jumping to the ** OP_Halt inserted at the end of the program. */ if( pTrigger->pWhen ){ pWhen = sqlite3ExprDup(db, pTrigger->pWhen, 0); if( db->mallocFailed==0 && SQLITE_OK==sqlite3ResolveExprNames(&sNC, pWhen) ){ iEndTrigger = sqlite3VdbeMakeLabel(pSubParse); sqlite3ExprIfFalse(pSubParse, pWhen, iEndTrigger, SQLITE_JUMPIFNULL); } sqlite3ExprDelete(db, pWhen); } /* Code the trigger program into the sub-vdbe. */ codeTriggerProgram(pSubParse, pTrigger->step_list, orconf); |
︙ | ︙ | |||
967 968 969 970 971 972 973 | pProgram->nCsr = pSubParse->nTab; pProgram->token = (void *)pTrigger; pPrg->aColmask[0] = pSubParse->oldmask; pPrg->aColmask[1] = pSubParse->newmask; sqlite3VdbeDelete(v); } | < | 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 | pProgram->nCsr = pSubParse->nTab; pProgram->token = (void *)pTrigger; pPrg->aColmask[0] = pSubParse->oldmask; pPrg->aColmask[1] = pSubParse->newmask; sqlite3VdbeDelete(v); } assert( !pSubParse->pTriggerPrg && !pSubParse->nMaxArg ); sqlite3ParserReset(pSubParse); sqlite3StackFree(db, pSubParse); return pPrg; } |
︙ | ︙ | |||
1069 1070 1071 1072 1073 1074 1075 | ** Register Contains ** ------------------------------------------------------ ** reg+0 OLD.rowid ** reg+1 OLD.* value of left-most column of pTab ** ... ... ** reg+N OLD.* value of right-most column of pTab ** reg+N+1 NEW.rowid | | | 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 | ** Register Contains ** ------------------------------------------------------ ** reg+0 OLD.rowid ** reg+1 OLD.* value of left-most column of pTab ** ... ... ** reg+N OLD.* value of right-most column of pTab ** reg+N+1 NEW.rowid ** reg+N+2 NEW.* value of left-most column of pTab ** ... ... ** reg+N+N+1 NEW.* value of right-most column of pTab ** ** For ON DELETE triggers, the registers containing the NEW.* values will ** never be accessed by the trigger program, so they are not allocated or ** populated by the caller (there is no data to populate them with anyway). ** Similarly, for ON INSERT triggers the values stored in the OLD.* registers |
︙ | ︙ | |||
1114 1115 1116 1117 1118 1119 1120 | ** always defined. The trigger must be in the same schema as the table ** or else it must be a TEMP trigger. */ assert( p->pSchema!=0 ); assert( p->pTabSchema!=0 ); assert( p->pSchema==p->pTabSchema || p->pSchema==pParse->db->aDb[1].pSchema ); | | > > > > | > | > > > | 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 | ** always defined. The trigger must be in the same schema as the table ** or else it must be a TEMP trigger. */ assert( p->pSchema!=0 ); assert( p->pTabSchema!=0 ); assert( p->pSchema==p->pTabSchema || p->pSchema==pParse->db->aDb[1].pSchema ); /* Determine whether we should code this trigger. One of two choices: ** 1. The trigger is an exact match to the current DML statement ** 2. This is a RETURNING trigger for INSERT but we are currently ** doing the UPDATE part of an UPSERT. */ if( (p->op==op || (p->bReturning && p->op==TK_INSERT && op==TK_UPDATE)) && p->tr_tm==tr_tm && checkColumnOverlap(p->pColumns, pChanges) ){ if( !p->bReturning ){ sqlite3CodeRowTriggerDirect(pParse, p, pTab, reg, orconf, ignoreJump); }else if( sqlite3IsToplevel(pParse) ){ codeReturningTrigger(pParse, p, pTab, reg); } } } } /* ** Triggers may access values stored in the old.* or new.* pseudo-table. ** This function returns a 32-bit bitmask indicating which columns of the |
︙ | ︙ | |||
1164 1165 1166 1167 1168 1169 1170 | ){ const int op = pChanges ? TK_UPDATE : TK_DELETE; u32 mask = 0; Trigger *p; assert( isNew==1 || isNew==0 ); for(p=pTrigger; p; p=p->pNext){ | | > > > > | | | | > | 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 | ){ const int op = pChanges ? TK_UPDATE : TK_DELETE; u32 mask = 0; Trigger *p; assert( isNew==1 || isNew==0 ); for(p=pTrigger; p; p=p->pNext){ if( p->op==op && (tr_tm&p->tr_tm) && checkColumnOverlap(p->pColumns,pChanges) ){ if( p->bReturning ){ mask = 0xffffffff; }else{ TriggerPrg *pPrg; pPrg = getRowTrigger(pParse, p, pTab, orconf); if( pPrg ){ mask |= pPrg->aColmask[isNew]; } } } } return mask; } #endif /* !defined(SQLITE_OMIT_TRIGGER) */ |
Changes to src/update.c.
︙ | ︙ | |||
42 43 44 45 46 47 48 | ** If the former, then all row-records are guaranteed to include a value ** for the column and the P4 value is not required. ** ** Column definitions created by an ALTER TABLE command may only have ** literal default values specified: a number, null or a string. (If a more ** complicated default expression value was provided, it is evaluated ** when the ALTER TABLE is executed and one of the literal values written | | > > | < < | | | | > | | 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 | ** If the former, then all row-records are guaranteed to include a value ** for the column and the P4 value is not required. ** ** Column definitions created by an ALTER TABLE command may only have ** literal default values specified: a number, null or a string. (If a more ** complicated default expression value was provided, it is evaluated ** when the ALTER TABLE is executed and one of the literal values written ** into the sqlite_schema table.) ** ** Therefore, the P4 parameter is only required if the default value for ** the column is a literal number, string or null. The sqlite3ValueFromExpr() ** function is capable of transforming these types of expressions into ** sqlite3_value objects. ** ** If column as REAL affinity and the table is an ordinary b-tree table ** (not a virtual table) then the value might have been stored as an ** integer. In that case, add an OP_RealAffinity opcode to make sure ** it has been converted into REAL. */ void sqlite3ColumnDefault(Vdbe *v, Table *pTab, int i, int iReg){ assert( pTab!=0 ); if( !IsView(pTab) ){ sqlite3_value *pValue = 0; u8 enc = ENC(sqlite3VdbeDb(v)); Column *pCol = &pTab->aCol[i]; VdbeComment((v, "%s.%s", pTab->zName, pCol->zCnName)); assert( i<pTab->nCol ); sqlite3ValueFromExpr(sqlite3VdbeDb(v), sqlite3ColumnExpr(pTab,pCol), enc, pCol->affinity, &pValue); if( pValue ){ sqlite3VdbeAppendP4(v, pValue, P4_MEM); } } #ifndef SQLITE_OMIT_FLOATING_POINT if( pTab->aCol[i].affinity==SQLITE_AFF_REAL && !IsVirtual(pTab) ){ sqlite3VdbeAddOp1(v, OP_RealAffinity, iReg); } #endif } /* ** Check to see if column iCol of index pIdx references any of the |
︙ | ︙ | |||
125 126 127 128 129 130 131 132 133 134 135 | int *aXRef, /* aXRef[j]>=0 if column j is being updated */ int chngRowid /* true if the rowid is being updated */ ){ if( pIdx->pPartIdxWhere==0 ) return 0; return sqlite3ExprReferencesUpdatedColumn(pIdx->pPartIdxWhere, aXRef, chngRowid); } /* ** Process an UPDATE statement. ** | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | > > | | > | > | 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 | int *aXRef, /* aXRef[j]>=0 if column j is being updated */ int chngRowid /* true if the rowid is being updated */ ){ if( pIdx->pPartIdxWhere==0 ) return 0; return sqlite3ExprReferencesUpdatedColumn(pIdx->pPartIdxWhere, aXRef, chngRowid); } /* ** Allocate and return a pointer to an expression of type TK_ROW with ** Expr.iColumn set to value (iCol+1). The resolver will modify the ** expression to be a TK_COLUMN reading column iCol of the first ** table in the source-list (pSrc->a[0]). */ static Expr *exprRowColumn(Parse *pParse, int iCol){ Expr *pRet = sqlite3PExpr(pParse, TK_ROW, 0, 0); if( pRet ) pRet->iColumn = iCol+1; return pRet; } /* ** Assuming both the pLimit and pOrderBy parameters are NULL, this function ** generates VM code to run the query: ** ** SELECT <other-columns>, pChanges FROM pTabList WHERE pWhere ** ** and write the results to the ephemeral table already opened as cursor ** iEph. None of pChanges, pTabList or pWhere are modified or consumed by ** this function, they must be deleted by the caller. ** ** Or, if pLimit and pOrderBy are not NULL, and pTab is not a view: ** ** SELECT <other-columns>, pChanges FROM pTabList ** WHERE pWhere ** GROUP BY <other-columns> ** ORDER BY pOrderBy LIMIT pLimit ** ** If pTab is a view, the GROUP BY clause is omitted. ** ** Exactly how results are written to table iEph, and exactly what ** the <other-columns> in the query above are is determined by the type ** of table pTabList->a[0].pTab. ** ** If the table is a WITHOUT ROWID table, then argument pPk must be its ** PRIMARY KEY. In this case <other-columns> are the primary key columns ** of the table, in order. The results of the query are written to ephemeral ** table iEph as index keys, using OP_IdxInsert. ** ** If the table is actually a view, then <other-columns> are all columns of ** the view. The results are written to the ephemeral table iEph as records ** with automatically assigned integer keys. ** ** If the table is a virtual or ordinary intkey table, then <other-columns> ** is its rowid. For a virtual table, the results are written to iEph as ** records with automatically assigned integer keys For intkey tables, the ** rowid value in <other-columns> is used as the integer key, and the ** remaining fields make up the table record. */ static void updateFromSelect( Parse *pParse, /* Parse context */ int iEph, /* Cursor for open eph. table */ Index *pPk, /* PK if table 0 is WITHOUT ROWID */ ExprList *pChanges, /* List of expressions to return */ SrcList *pTabList, /* List of tables to select from */ Expr *pWhere, /* WHERE clause for query */ ExprList *pOrderBy, /* ORDER BY clause */ Expr *pLimit /* LIMIT clause */ ){ int i; SelectDest dest; Select *pSelect = 0; ExprList *pList = 0; ExprList *pGrp = 0; Expr *pLimit2 = 0; ExprList *pOrderBy2 = 0; sqlite3 *db = pParse->db; Table *pTab = pTabList->a[0].pTab; SrcList *pSrc; Expr *pWhere2; int eDest; #ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT if( pOrderBy && pLimit==0 ) { sqlite3ErrorMsg(pParse, "ORDER BY without LIMIT on UPDATE"); return; } pOrderBy2 = sqlite3ExprListDup(db, pOrderBy, 0); pLimit2 = sqlite3ExprDup(db, pLimit, 0); #else UNUSED_PARAMETER(pOrderBy); UNUSED_PARAMETER(pLimit); #endif pSrc = sqlite3SrcListDup(db, pTabList, 0); pWhere2 = sqlite3ExprDup(db, pWhere, 0); assert( pTabList->nSrc>1 ); if( pSrc ){ pSrc->a[0].fg.notCte = 1; pSrc->a[0].iCursor = -1; pSrc->a[0].pTab->nTabRef--; pSrc->a[0].pTab = 0; } if( pPk ){ for(i=0; i<pPk->nKeyCol; i++){ Expr *pNew = exprRowColumn(pParse, pPk->aiColumn[i]); #ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT if( pLimit ){ pGrp = sqlite3ExprListAppend(pParse, pGrp, sqlite3ExprDup(db, pNew, 0)); } #endif pList = sqlite3ExprListAppend(pParse, pList, pNew); } eDest = IsVirtual(pTab) ? SRT_Table : SRT_Upfrom; }else if( IsView(pTab) ){ for(i=0; i<pTab->nCol; i++){ pList = sqlite3ExprListAppend(pParse, pList, exprRowColumn(pParse, i)); } eDest = SRT_Table; }else{ eDest = IsVirtual(pTab) ? SRT_Table : SRT_Upfrom; pList = sqlite3ExprListAppend(pParse, 0, sqlite3PExpr(pParse,TK_ROW,0,0)); #ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT if( pLimit ){ pGrp = sqlite3ExprListAppend(pParse, 0, sqlite3PExpr(pParse,TK_ROW,0,0)); } #endif } assert( pChanges!=0 || pParse->db->mallocFailed ); if( pChanges ){ for(i=0; i<pChanges->nExpr; i++){ pList = sqlite3ExprListAppend(pParse, pList, sqlite3ExprDup(db, pChanges->a[i].pExpr, 0) ); } } pSelect = sqlite3SelectNew(pParse, pList, pSrc, pWhere2, pGrp, 0, pOrderBy2, SF_UFSrcCheck|SF_IncludeHidden, pLimit2 ); if( pSelect ) pSelect->selFlags |= SF_OrderByReqd; sqlite3SelectDestInit(&dest, eDest, iEph); dest.iSDParm2 = (pPk ? pPk->nKeyCol : -1); sqlite3Select(pParse, pSelect, &dest); sqlite3SelectDelete(db, pSelect); } /* ** Process an UPDATE statement. ** ** UPDATE OR IGNORE tbl SET a=b, c=d FROM tbl2... WHERE e<5 AND f NOT NULL; ** \_______/ \_/ \______/ \_____/ \________________/ ** onError | pChanges | pWhere ** \_______________________/ ** pTabList */ void sqlite3Update( Parse *pParse, /* The parser context */ SrcList *pTabList, /* The table in which we should change things */ ExprList *pChanges, /* Things to be changed */ Expr *pWhere, /* The WHERE clause. May be null */ int onError, /* How to handle constraint errors */ ExprList *pOrderBy, /* ORDER BY clause. May be null */ Expr *pLimit, /* LIMIT clause. May be null */ Upsert *pUpsert /* ON CONFLICT clause, or null */ ){ int i, j, k; /* Loop counters */ Table *pTab; /* The table to be updated */ int addrTop = 0; /* VDBE instruction address of the start of the loop */ WhereInfo *pWInfo = 0; /* Information about the WHERE clause */ Vdbe *v; /* The virtual database engine */ Index *pIdx; /* For looping over indices */ Index *pPk; /* The PRIMARY KEY index for WITHOUT ROWID tables */ int nIdx; /* Number of indices that need updating */ int nAllIdx; /* Total number of indexes */ int iBaseCur; /* Base cursor number */ int iDataCur; /* Cursor for the canonical data btree */ int iIdxCur; /* Cursor for the first index */ sqlite3 *db; /* The database structure */ int *aRegIdx = 0; /* Registers for to each index and the main table */ int *aXRef = 0; /* aXRef[i] is the index in pChanges->a[] of the ** an expression for the i-th column of the table. ** aXRef[i]==-1 if the i-th column is not changed. */ u8 *aToOpen; /* 1 for tables and indices to be opened */ u8 chngPk; /* PRIMARY KEY changed in a WITHOUT ROWID table */ u8 chngRowid; /* Rowid changed in a normal table */ u8 chngKey; /* Either chngPk or chngRowid */ Expr *pRowidExpr = 0; /* Expression defining the new record number */ int iRowidExpr = -1; /* Index of "rowid=" (or IPK) assignment in pChanges */ AuthContext sContext; /* The authorization context */ NameContext sNC; /* The name-context to resolve expressions in */ int iDb; /* Database containing the table being updated */ int eOnePass; /* ONEPASS_XXX value from where.c */ int hasFK; /* True if foreign key processing is required */ int labelBreak; /* Jump here to break out of UPDATE loop */ int labelContinue; /* Jump here to continue next step of UPDATE loop */ |
︙ | ︙ | |||
186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 | int iEph = 0; /* Ephemeral table holding all primary key values */ int nKey = 0; /* Number of elements in regKey for WITHOUT ROWID */ int aiCurOnePass[2]; /* The write cursors opened by WHERE_ONEPASS */ int addrOpen = 0; /* Address of OP_OpenEphemeral */ int iPk = 0; /* First of nPk cells holding PRIMARY KEY value */ i16 nPk = 0; /* Number of components of the PRIMARY KEY */ int bReplace = 0; /* True if REPLACE conflict resolution might happen */ /* Register Allocations */ int regRowCount = 0; /* A count of rows changed */ int regOldRowid = 0; /* The old rowid */ int regNewRowid = 0; /* The new rowid */ int regNew = 0; /* Content of the NEW.* table in triggers */ int regOld = 0; /* Content of OLD.* table in triggers */ int regRowSet = 0; /* Rowset of rows to be updated */ int regKey = 0; /* composite PRIMARY KEY value */ memset(&sContext, 0, sizeof(sContext)); db = pParse->db; if( pParse->nErr || db->mallocFailed ){ goto update_cleanup; } | > > < | > > > > > > > | | 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 | int iEph = 0; /* Ephemeral table holding all primary key values */ int nKey = 0; /* Number of elements in regKey for WITHOUT ROWID */ int aiCurOnePass[2]; /* The write cursors opened by WHERE_ONEPASS */ int addrOpen = 0; /* Address of OP_OpenEphemeral */ int iPk = 0; /* First of nPk cells holding PRIMARY KEY value */ i16 nPk = 0; /* Number of components of the PRIMARY KEY */ int bReplace = 0; /* True if REPLACE conflict resolution might happen */ int bFinishSeek = 1; /* The OP_FinishSeek opcode is needed */ int nChangeFrom = 0; /* If there is a FROM, pChanges->nExpr, else 0 */ /* Register Allocations */ int regRowCount = 0; /* A count of rows changed */ int regOldRowid = 0; /* The old rowid */ int regNewRowid = 0; /* The new rowid */ int regNew = 0; /* Content of the NEW.* table in triggers */ int regOld = 0; /* Content of OLD.* table in triggers */ int regRowSet = 0; /* Rowset of rows to be updated */ int regKey = 0; /* composite PRIMARY KEY value */ memset(&sContext, 0, sizeof(sContext)); db = pParse->db; if( pParse->nErr || db->mallocFailed ){ goto update_cleanup; } /* Locate the table which we want to update. */ pTab = sqlite3SrcListLookup(pParse, pTabList); if( pTab==0 ) goto update_cleanup; iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); /* Figure out if we have any triggers and if the table being ** updated is a view. */ #ifndef SQLITE_OMIT_TRIGGER pTrigger = sqlite3TriggersExist(pParse, pTab, TK_UPDATE, pChanges, &tmask); isView = IsView(pTab); assert( pTrigger || tmask==0 ); #else # define pTrigger 0 # define isView 0 # define tmask 0 #endif #ifdef SQLITE_OMIT_VIEW # undef isView # define isView 0 #endif /* If there was a FROM clause, set nChangeFrom to the number of expressions ** in the change-list. Otherwise, set it to 0. There cannot be a FROM ** clause if this function is being called to generate code for part of ** an UPSERT statement. */ nChangeFrom = (pTabList->nSrc>1) ? pChanges->nExpr : 0; assert( nChangeFrom==0 || pUpsert==0 ); #ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT if( !isView && nChangeFrom==0 ){ pWhere = sqlite3LimitWhere( pParse, pTabList, pWhere, pOrderBy, pLimit, "UPDATE" ); pOrderBy = 0; pLimit = 0; } #endif |
︙ | ︙ | |||
269 270 271 272 273 274 275 | pParse->nTab = iBaseCur; } pTabList->a[0].iCursor = iDataCur; /* Allocate space for aXRef[], aRegIdx[], and aToOpen[]. ** Initialize aXRef[] and aToOpen[] to their default values. */ | | | > > > > > > > > > > > > > > > > > > | > | > > > > > > > > > > > > | > | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | < | < | | > < < < > > > > > > | | 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 | pParse->nTab = iBaseCur; } pTabList->a[0].iCursor = iDataCur; /* Allocate space for aXRef[], aRegIdx[], and aToOpen[]. ** Initialize aXRef[] and aToOpen[] to their default values. */ aXRef = sqlite3DbMallocRawNN(db, sizeof(int) * (pTab->nCol+nIdx+1) + nIdx+2 ); if( aXRef==0 ) goto update_cleanup; aRegIdx = aXRef+pTab->nCol; aToOpen = (u8*)(aRegIdx+nIdx+1); memset(aToOpen, 1, nIdx+1); aToOpen[nIdx+1] = 0; for(i=0; i<pTab->nCol; i++) aXRef[i] = -1; /* Initialize the name-context */ memset(&sNC, 0, sizeof(sNC)); sNC.pParse = pParse; sNC.pSrcList = pTabList; sNC.uNC.pUpsert = pUpsert; sNC.ncFlags = NC_UUpsert; /* Begin generating code. */ v = sqlite3GetVdbe(pParse); if( v==0 ) goto update_cleanup; /* Resolve the column names in all the expressions of the ** of the UPDATE statement. Also find the column index ** for each column to be updated in the pChanges array. For each ** column to be updated, make sure we have authorization to change ** that column. */ chngRowid = chngPk = 0; for(i=0; i<pChanges->nExpr; i++){ #if defined(SQLITE_ENABLE_NOOP_UPDATE) && !defined(SQLITE_OMIT_FLAG_PRAGMAS) if( db->flags & SQLITE_NoopUpdate ){ Token x; sqlite3ExprDelete(db, pChanges->a[i].pExpr); x.z = pChanges->a[i].zEName; x.n = sqlite3Strlen30(x.z); pChanges->a[i].pExpr = sqlite3PExpr(pParse, TK_UPLUS, sqlite3ExprAlloc(db, TK_ID, &x, 0), 0); if( db->mallocFailed ) goto update_cleanup; } #endif u8 hCol = sqlite3StrIHash(pChanges->a[i].zEName); /* If this is an UPDATE with a FROM clause, do not resolve expressions ** here. The call to sqlite3Select() below will do that. */ if( nChangeFrom==0 && sqlite3ResolveExprNames(&sNC, pChanges->a[i].pExpr) ){ goto update_cleanup; } for(j=0; j<pTab->nCol; j++){ if( pTab->aCol[j].hName==hCol && sqlite3StrICmp(pTab->aCol[j].zCnName, pChanges->a[i].zEName)==0 ){ if( j==pTab->iPKey ){ chngRowid = 1; pRowidExpr = pChanges->a[i].pExpr; iRowidExpr = i; }else if( pPk && (pTab->aCol[j].colFlags & COLFLAG_PRIMKEY)!=0 ){ chngPk = 1; } #ifndef SQLITE_OMIT_GENERATED_COLUMNS else if( pTab->aCol[j].colFlags & COLFLAG_GENERATED ){ testcase( pTab->aCol[j].colFlags & COLFLAG_VIRTUAL ); testcase( pTab->aCol[j].colFlags & COLFLAG_STORED ); sqlite3ErrorMsg(pParse, "cannot UPDATE generated column \"%s\"", pTab->aCol[j].zCnName); goto update_cleanup; } #endif aXRef[j] = i; break; } } if( j>=pTab->nCol ){ if( pPk==0 && sqlite3IsRowid(pChanges->a[i].zEName) ){ j = -1; chngRowid = 1; pRowidExpr = pChanges->a[i].pExpr; iRowidExpr = i; }else{ sqlite3ErrorMsg(pParse, "no such column: %s", pChanges->a[i].zEName); 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].zCnName, db->aDb[iDb].zDbSName); if( rc==SQLITE_DENY ){ goto update_cleanup; }else if( rc==SQLITE_IGNORE ){ aXRef[j] = -1; } } #endif } assert( (chngRowid & chngPk)==0 ); assert( chngRowid==0 || chngRowid==1 ); assert( chngPk==0 || chngPk==1 ); chngKey = chngRowid + chngPk; #ifndef SQLITE_OMIT_GENERATED_COLUMNS /* Mark generated columns as changing if their generator expressions ** reference any changing column. The actual aXRef[] value for ** generated expressions is not used, other than to check to see that it ** is non-negative, so the value of aXRef[] for generated columns can be ** set to any non-negative number. We use 99999 so that the value is ** obvious when looking at aXRef[] in a symbolic debugger. */ if( pTab->tabFlags & TF_HasGenerated ){ int bProgress; testcase( pTab->tabFlags & TF_HasVirtual ); testcase( pTab->tabFlags & TF_HasStored ); do{ bProgress = 0; for(i=0; i<pTab->nCol; i++){ if( aXRef[i]>=0 ) continue; if( (pTab->aCol[i].colFlags & COLFLAG_GENERATED)==0 ) continue; if( sqlite3ExprReferencesUpdatedColumn( sqlite3ColumnExpr(pTab, &pTab->aCol[i]), aXRef, chngRowid) ){ aXRef[i] = 99999; bProgress = 1; } } }while( bProgress ); } #endif /* The SET expressions are not actually used inside the WHERE loop. ** So reset the colUsed mask. Unless this is a virtual table. In that ** case, set all bits of the colUsed mask (to ensure that the virtual ** table implementation makes all columns available). */ pTabList->a[0].colUsed = IsVirtual(pTab) ? ALLBITS : 0; hasFK = sqlite3FkRequired(pParse, pTab, aXRef, chngKey); /* There is one entry in the aRegIdx[] array for each index on the table ** being updated. Fill in aRegIdx[] with a register number that will hold ** the key for accessing each index. */ if( onError==OE_Replace ) bReplace = 1; for(nAllIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nAllIdx++){ int reg; if( chngKey || hasFK>1 || pIdx==pPk || indexWhereClauseMightChange(pIdx,aXRef,chngRowid) ){ reg = ++pParse->nMem; pParse->nMem += pIdx->nColumn; }else{ reg = 0; for(i=0; i<pIdx->nKeyCol; i++){ if( indexColumnIsBeingUpdated(pIdx, i, aXRef, chngRowid) ){ reg = ++pParse->nMem; pParse->nMem += pIdx->nColumn; if( onError==OE_Default && pIdx->onError==OE_Replace ){ bReplace = 1; } break; } } } if( reg==0 ) aToOpen[nAllIdx+1] = 0; aRegIdx[nAllIdx] = reg; } aRegIdx[nAllIdx] = ++pParse->nMem; /* Register storing the table record */ if( bReplace ){ /* If REPLACE conflict resolution might be invoked, open cursors on all ** indexes in case they are needed to delete records. */ memset(aToOpen, 1, nIdx+1); } if( pParse->nested==0 ) sqlite3VdbeCountChanges(v); sqlite3BeginWriteOperation(pParse, pTrigger || hasFK, iDb); /* Allocate required registers. */ if( !IsVirtual(pTab) ){ /* For now, regRowSet and aRegIdx[nAllIdx] share the same register. ** If regRowSet turns out to be needed, then aRegIdx[nAllIdx] will be ** reallocated. aRegIdx[nAllIdx] is the register in which the main ** table record is written. regRowSet holds the RowSet for the ** two-pass update algorithm. */ assert( aRegIdx[nAllIdx]==pParse->nMem ); regRowSet = aRegIdx[nAllIdx]; regOldRowid = regNewRowid = ++pParse->nMem; if( chngPk || pTrigger || hasFK ){ regOld = pParse->nMem + 1; pParse->nMem += pTab->nCol; } if( chngKey || pTrigger || hasFK ){ regNewRowid = ++pParse->nMem; |
︙ | ︙ | |||
411 412 413 414 415 416 417 | sqlite3AuthContextPush(pParse, &sContext, pTab->zName); } /* If we are trying to update a view, realize that view into ** an ephemeral table. */ #if !defined(SQLITE_OMIT_VIEW) && !defined(SQLITE_OMIT_TRIGGER) | | | | > | > > | | > > | | > | > > > | | > > > > > > > | > > > > > > > > > | | | | | | | | | > | | | | | | | | | | | | | | | | | | | | | | | | | | > | | | | | | | | | | | | | | | | | > | > > | | | | | | | | | | > | | | | | | | | | | | | > | | > > > | > > > > | | | > > > > > > > > > > > > > > > > > > | | | > > | | > > | > > > > > | | | | 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 | sqlite3AuthContextPush(pParse, &sContext, pTab->zName); } /* If we are trying to update a view, realize that view into ** an ephemeral table. */ #if !defined(SQLITE_OMIT_VIEW) && !defined(SQLITE_OMIT_TRIGGER) if( nChangeFrom==0 && isView ){ sqlite3MaterializeView(pParse, pTab, pWhere, pOrderBy, pLimit, iDataCur ); pOrderBy = 0; pLimit = 0; } #endif /* Resolve the column names in all the expressions in the ** WHERE clause. */ if( nChangeFrom==0 && sqlite3ResolveExprNames(&sNC, pWhere) ){ goto update_cleanup; } #ifndef SQLITE_OMIT_VIRTUALTABLE /* Virtual tables must be handled separately */ if( IsVirtual(pTab) ){ updateVirtualTable(pParse, pTabList, pTab, pChanges, pRowidExpr, aXRef, pWhere, onError); goto update_cleanup; } #endif /* Jump to labelBreak to abandon further processing of this UPDATE */ labelContinue = labelBreak = sqlite3VdbeMakeLabel(pParse); /* Not an UPSERT. Normal processing. Begin by ** initialize the count of updated rows */ if( (db->flags&SQLITE_CountRows)!=0 && !pParse->pTriggerTab && !pParse->nested && !pParse->bReturning && pUpsert==0 ){ regRowCount = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_Integer, 0, regRowCount); } if( nChangeFrom==0 && HasRowid(pTab) ){ sqlite3VdbeAddOp3(v, OP_Null, 0, regRowSet, regOldRowid); iEph = pParse->nTab++; addrOpen = sqlite3VdbeAddOp3(v, OP_OpenEphemeral, iEph, 0, regRowSet); }else{ assert( pPk!=0 || HasRowid(pTab) ); nPk = pPk ? pPk->nKeyCol : 0; iPk = pParse->nMem+1; pParse->nMem += nPk; pParse->nMem += nChangeFrom; regKey = ++pParse->nMem; if( pUpsert==0 ){ int nEphCol = nPk + nChangeFrom + (isView ? pTab->nCol : 0); iEph = pParse->nTab++; if( pPk ) sqlite3VdbeAddOp3(v, OP_Null, 0, iPk, iPk+nPk-1); addrOpen = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, iEph, nEphCol); if( pPk ){ KeyInfo *pKeyInfo = sqlite3KeyInfoOfIndex(pParse, pPk); if( pKeyInfo ){ pKeyInfo->nAllField = nEphCol; sqlite3VdbeAppendP4(v, pKeyInfo, P4_KEYINFO); } } if( nChangeFrom ){ updateFromSelect( pParse, iEph, pPk, pChanges, pTabList, pWhere, pOrderBy, pLimit ); #ifndef SQLITE_OMIT_SUBQUERY if( isView ) iDataCur = iEph; #endif } } } if( nChangeFrom ){ sqlite3MultiWrite(pParse); eOnePass = ONEPASS_OFF; nKey = nPk; regKey = iPk; }else{ if( pUpsert ){ /* If this is an UPSERT, then all cursors have already been opened by ** the outer INSERT and the data cursor should be pointing at the row ** that is to be updated. So bypass the code that searches for the ** row(s) to be updated. */ pWInfo = 0; eOnePass = ONEPASS_SINGLE; sqlite3ExprIfFalse(pParse, pWhere, labelBreak, SQLITE_JUMPIFNULL); bFinishSeek = 0; }else{ /* Begin the database scan. ** ** Do not consider a single-pass strategy for a multi-row update if ** there are any triggers or foreign keys to process, or rows may ** be deleted as a result of REPLACE conflict handling. Any of these ** things might disturb a cursor being used to scan through the table ** or index, causing a single-pass approach to malfunction. */ flags = WHERE_ONEPASS_DESIRED; if( !pParse->nested && !pTrigger && !hasFK && !chngKey && !bReplace ){ flags |= WHERE_ONEPASS_MULTIROW; } pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0, 0, flags,iIdxCur); if( pWInfo==0 ) goto update_cleanup; /* A one-pass strategy that might update more than one row may not ** be used if any column of the index used for the scan is being ** updated. Otherwise, if there is an index on "b", statements like ** the following could create an infinite loop: ** ** UPDATE t1 SET b=b+1 WHERE b>? ** ** Fall back to ONEPASS_OFF if where.c has selected a ONEPASS_MULTI ** strategy that uses an index for which one or more columns are being ** updated. */ eOnePass = sqlite3WhereOkOnePass(pWInfo, aiCurOnePass); bFinishSeek = sqlite3WhereUsesDeferredSeek(pWInfo); if( eOnePass!=ONEPASS_SINGLE ){ sqlite3MultiWrite(pParse); if( eOnePass==ONEPASS_MULTI ){ int iCur = aiCurOnePass[1]; if( iCur>=0 && iCur!=iDataCur && aToOpen[iCur-iBaseCur] ){ eOnePass = ONEPASS_OFF; } assert( iCur!=iDataCur || !HasRowid(pTab) ); } } } if( HasRowid(pTab) ){ /* Read the rowid of the current row of the WHERE scan. In ONEPASS_OFF ** mode, write the rowid into the FIFO. In either of the one-pass modes, ** leave it in register regOldRowid. */ sqlite3VdbeAddOp2(v, OP_Rowid, iDataCur, regOldRowid); if( eOnePass==ONEPASS_OFF ){ aRegIdx[nAllIdx] = ++pParse->nMem; sqlite3VdbeAddOp3(v, OP_Insert, iEph, regRowSet, regOldRowid); }else{ if( ALWAYS(addrOpen) ) sqlite3VdbeChangeToNoop(v, addrOpen); } }else{ /* Read the PK of the current row into an array of registers. In ** ONEPASS_OFF mode, serialize the array into a record and store it in ** the ephemeral table. Or, in ONEPASS_SINGLE or MULTI mode, change ** the OP_OpenEphemeral instruction to a Noop (the ephemeral table ** is not required) and leave the PK fields in the array of registers. */ for(i=0; i<nPk; i++){ assert( pPk->aiColumn[i]>=0 ); sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, pPk->aiColumn[i], iPk+i); } if( eOnePass ){ if( addrOpen ) sqlite3VdbeChangeToNoop(v, addrOpen); nKey = nPk; regKey = iPk; }else{ sqlite3VdbeAddOp4(v, OP_MakeRecord, iPk, nPk, regKey, sqlite3IndexAffinityStr(db, pPk), nPk); sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iEph, regKey, iPk, nPk); } } } if( pUpsert==0 ){ if( nChangeFrom==0 && eOnePass!=ONEPASS_MULTI ){ sqlite3WhereEnd(pWInfo); } if( !isView ){ int addrOnce = 0; /* Open every index that needs updating. */ if( eOnePass!=ONEPASS_OFF ){ if( aiCurOnePass[0]>=0 ) aToOpen[aiCurOnePass[0]-iBaseCur] = 0; if( aiCurOnePass[1]>=0 ) aToOpen[aiCurOnePass[1]-iBaseCur] = 0; } if( eOnePass==ONEPASS_MULTI && (nIdx-(aiCurOnePass[1]>=0))>0 ){ addrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v); } sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, 0, iBaseCur, aToOpen, 0, 0); if( addrOnce ){ sqlite3VdbeJumpHereOrPopInst(v, addrOnce); } } /* Top of the update loop */ if( eOnePass!=ONEPASS_OFF ){ if( aiCurOnePass[0]!=iDataCur && aiCurOnePass[1]!=iDataCur #ifdef SQLITE_ALLOW_ROWID_IN_VIEW && !isView #endif ){ assert( pPk ); sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, labelBreak, regKey,nKey); VdbeCoverage(v); } if( eOnePass!=ONEPASS_SINGLE ){ labelContinue = sqlite3VdbeMakeLabel(pParse); } sqlite3VdbeAddOp2(v, OP_IsNull, pPk ? regKey : regOldRowid, labelBreak); VdbeCoverageIf(v, pPk==0); VdbeCoverageIf(v, pPk!=0); }else if( pPk || nChangeFrom ){ labelContinue = sqlite3VdbeMakeLabel(pParse); sqlite3VdbeAddOp2(v, OP_Rewind, iEph, labelBreak); VdbeCoverage(v); addrTop = sqlite3VdbeCurrentAddr(v); if( nChangeFrom ){ if( !isView ){ if( pPk ){ for(i=0; i<nPk; i++){ sqlite3VdbeAddOp3(v, OP_Column, iEph, i, iPk+i); } sqlite3VdbeAddOp4Int( v, OP_NotFound, iDataCur, labelContinue, iPk, nPk ); VdbeCoverage(v); }else{ sqlite3VdbeAddOp2(v, OP_Rowid, iEph, regOldRowid); sqlite3VdbeAddOp3( v, OP_NotExists, iDataCur, labelContinue, regOldRowid ); VdbeCoverage(v); } } }else{ sqlite3VdbeAddOp2(v, OP_RowData, iEph, regKey); sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, labelContinue, regKey,0); VdbeCoverage(v); } }else{ sqlite3VdbeAddOp2(v, OP_Rewind, iEph, labelBreak); VdbeCoverage(v); labelContinue = sqlite3VdbeMakeLabel(pParse); addrTop = sqlite3VdbeAddOp2(v, OP_Rowid, iEph, regOldRowid); VdbeCoverage(v); sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, labelContinue, regOldRowid); VdbeCoverage(v); } } /* If the rowid value will change, set register regNewRowid to ** contain the new value. If the rowid is not being modified, ** then regNewRowid is the same register as regOldRowid, which is ** already populated. */ assert( chngKey || pTrigger || hasFK || regOldRowid==regNewRowid ); if( chngRowid ){ assert( iRowidExpr>=0 ); if( nChangeFrom==0 ){ sqlite3ExprCode(pParse, pRowidExpr, regNewRowid); }else{ sqlite3VdbeAddOp3(v, OP_Column, iEph, iRowidExpr, regNewRowid); } sqlite3VdbeAddOp1(v, OP_MustBeInt, regNewRowid); VdbeCoverage(v); } /* Compute the old pre-UPDATE content of the row being changed, if that ** information is needed */ if( chngPk || hasFK || pTrigger ){ u32 oldmask = (hasFK ? sqlite3FkOldmask(pParse, pTab) : 0); oldmask |= sqlite3TriggerColmask(pParse, pTrigger, pChanges, 0, TRIGGER_BEFORE|TRIGGER_AFTER, pTab, onError ); for(i=0; i<pTab->nCol; i++){ u32 colFlags = pTab->aCol[i].colFlags; k = sqlite3TableColumnToStorage(pTab, i) + regOld; if( oldmask==0xffffffff || (i<32 && (oldmask & MASKBIT32(i))!=0) || (colFlags & COLFLAG_PRIMKEY)!=0 ){ testcase( oldmask!=0xffffffff && i==31 ); sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, i, k); }else{ sqlite3VdbeAddOp2(v, OP_Null, 0, k); } } if( chngRowid==0 && pPk==0 ){ sqlite3VdbeAddOp2(v, OP_Copy, regOldRowid, regNewRowid); } } |
︙ | ︙ | |||
641 642 643 644 645 646 647 | ** the database after the BEFORE triggers are fired anyway (as the trigger ** may have modified them). So not loading those that are not going to ** be used eliminates some redundant opcodes. */ newmask = sqlite3TriggerColmask( pParse, pTrigger, pChanges, 1, TRIGGER_BEFORE, pTab, onError ); | | | > > > > > > > | > | > | > > > > > > > > | | | | | | | | | | | | | | | | | | | | | | | > > | | | > > > > > > > > < < > > > > > > > > > > > > < < < < | | > > > > > > | < | 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 | ** the database after the BEFORE triggers are fired anyway (as the trigger ** may have modified them). So not loading those that are not going to ** be used eliminates some redundant opcodes. */ newmask = sqlite3TriggerColmask( pParse, pTrigger, pChanges, 1, TRIGGER_BEFORE, pTab, onError ); for(i=0, k=regNew; i<pTab->nCol; i++, k++){ if( i==pTab->iPKey ){ sqlite3VdbeAddOp2(v, OP_Null, 0, k); }else if( (pTab->aCol[i].colFlags & COLFLAG_GENERATED)!=0 ){ if( pTab->aCol[i].colFlags & COLFLAG_VIRTUAL ) k--; }else{ j = aXRef[i]; if( j>=0 ){ if( nChangeFrom ){ int nOff = (isView ? pTab->nCol : nPk); assert( eOnePass==ONEPASS_OFF ); sqlite3VdbeAddOp3(v, OP_Column, iEph, nOff+j, k); }else{ sqlite3ExprCode(pParse, pChanges->a[j].pExpr, k); } }else if( 0==(tmask&TRIGGER_BEFORE) || i>31 || (newmask & MASKBIT32(i)) ){ /* This branch loads the value of a column that will not be changed ** into a register. This is done if there are no BEFORE triggers, or ** if there are one or more BEFORE triggers that use this value via ** a new.* reference in a trigger program. */ testcase( i==31 ); testcase( i==32 ); sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, i, k); bFinishSeek = 0; }else{ sqlite3VdbeAddOp2(v, OP_Null, 0, k); } } } #ifndef SQLITE_OMIT_GENERATED_COLUMNS if( pTab->tabFlags & TF_HasGenerated ){ testcase( pTab->tabFlags & TF_HasVirtual ); testcase( pTab->tabFlags & TF_HasStored ); sqlite3ComputeGeneratedColumns(pParse, regNew, pTab); } #endif /* Fire any BEFORE UPDATE triggers. This happens before constraints are ** verified. One could argue that this is wrong. */ if( tmask&TRIGGER_BEFORE ){ sqlite3TableAffinity(v, pTab, regNew); sqlite3CodeRowTrigger(pParse, pTrigger, TK_UPDATE, pChanges, TRIGGER_BEFORE, pTab, regOldRowid, onError, labelContinue); if( !isView ){ /* 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. */ if( pPk ){ sqlite3VdbeAddOp4Int(v, OP_NotFound,iDataCur,labelContinue,regKey,nKey); VdbeCoverage(v); }else{ sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, labelContinue,regOldRowid); VdbeCoverage(v); } /* After-BEFORE-trigger-reload-loop: ** If it did not delete it, the BEFORE trigger may still have modified ** some of the columns of the row being updated. Load the values for ** all columns not modified by the update statement into their registers ** in case this has happened. Only unmodified columns are reloaded. ** The values computed for modified columns use the values before the ** BEFORE trigger runs. See test case trigger1-18.0 (added 2018-04-26) ** for an example. */ for(i=0, k=regNew; i<pTab->nCol; i++, k++){ if( pTab->aCol[i].colFlags & COLFLAG_GENERATED ){ if( pTab->aCol[i].colFlags & COLFLAG_VIRTUAL ) k--; }else if( aXRef[i]<0 && i!=pTab->iPKey ){ sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, i, k); } } #ifndef SQLITE_OMIT_GENERATED_COLUMNS if( pTab->tabFlags & TF_HasGenerated ){ testcase( pTab->tabFlags & TF_HasVirtual ); testcase( pTab->tabFlags & TF_HasStored ); sqlite3ComputeGeneratedColumns(pParse, regNew, pTab); } #endif } } if( !isView ){ /* Do constraint checks. */ assert( regOldRowid>0 ); sqlite3GenerateConstraintChecks(pParse, pTab, aRegIdx, iDataCur, iIdxCur, regNewRowid, regOldRowid, chngKey, onError, labelContinue, &bReplace, aXRef, 0); /* If REPLACE conflict handling may have been used, or if the PK of the ** row is changing, then the GenerateConstraintChecks() above may have ** moved cursor iDataCur. Reseek it. */ if( bReplace || chngKey ){ if( pPk ){ sqlite3VdbeAddOp4Int(v, OP_NotFound,iDataCur,labelContinue,regKey,nKey); }else{ sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, labelContinue,regOldRowid); } VdbeCoverageNeverTaken(v); } /* Do FK constraint checks. */ if( hasFK ){ sqlite3FkCheck(pParse, pTab, regOldRowid, 0, aXRef, chngKey); } /* Delete the index entries associated with the current record. */ sqlite3GenerateRowIndexDelete(pParse, pTab, iDataCur, iIdxCur, aRegIdx, -1); /* We must run the OP_FinishSeek opcode to resolve a prior ** OP_DeferredSeek if there is any possibility that there have been ** no OP_Column opcodes since the OP_DeferredSeek was issued. But ** we want to avoid the OP_FinishSeek if possible, as running it ** costs CPU cycles. */ if( bFinishSeek ){ sqlite3VdbeAddOp1(v, OP_FinishSeek, iDataCur); } /* If changing the rowid value, or if there are foreign key constraints ** to process, delete the old record. Otherwise, add a noop OP_Delete ** to invoke the pre-update hook. ** ** That (regNew==regnewRowid+1) is true is also important for the ** pre-update hook. If the caller invokes preupdate_new(), the returned |
︙ | ︙ | |||
753 754 755 756 757 758 759 | sqlite3VdbeAppendP4(v, pTab, P4_TABLE); } #else if( hasFK>1 || chngKey ){ sqlite3VdbeAddOp2(v, OP_Delete, iDataCur, 0); } #endif | < < < | 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 | sqlite3VdbeAppendP4(v, pTab, P4_TABLE); } #else if( hasFK>1 || chngKey ){ sqlite3VdbeAddOp2(v, OP_Delete, iDataCur, 0); } #endif if( hasFK ){ sqlite3FkCheck(pParse, pTab, 0, regNewRowid, aXRef, chngKey); } /* Insert the new index entries and the new record. */ sqlite3CompleteInsertion( |
︙ | ︙ | |||
793 794 795 796 797 798 799 | ** all record selected by the WHERE clause have been updated. */ if( eOnePass==ONEPASS_SINGLE ){ /* Nothing to do at end-of-loop for a single-pass */ }else if( eOnePass==ONEPASS_MULTI ){ sqlite3VdbeResolveLabel(v, labelContinue); sqlite3WhereEnd(pWInfo); | | < < | | 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 | ** all record selected by the WHERE clause have been updated. */ if( eOnePass==ONEPASS_SINGLE ){ /* Nothing to do at end-of-loop for a single-pass */ }else if( eOnePass==ONEPASS_MULTI ){ sqlite3VdbeResolveLabel(v, labelContinue); sqlite3WhereEnd(pWInfo); }else{ sqlite3VdbeResolveLabel(v, labelContinue); sqlite3VdbeAddOp2(v, OP_Next, iEph, addrTop); VdbeCoverage(v); } sqlite3VdbeResolveLabel(v, labelBreak); /* Update the sqlite_sequence table by storing the content of the ** maximum rowid counter values recorded while inserting into ** autoincrement tables. */ if( pParse->nested==0 && pParse->pTriggerTab==0 && pUpsert==0 ){ sqlite3AutoincrementEnd(pParse); } /* ** Return the number of rows that were changed, if we are tracking ** that information. */ if( regRowCount ){ sqlite3VdbeAddOp2(v, OP_ChngCntRow, regRowCount, 1); sqlite3VdbeSetNumCols(v, 1); sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows updated", SQLITE_STATIC); } update_cleanup: sqlite3AuthContextPop(&sContext); sqlite3DbFree(db, aXRef); /* Also frees aRegIdx[] and aToOpen[] */ |
︙ | ︙ | |||
878 879 880 881 882 883 884 | int onError /* ON CONFLICT strategy */ ){ Vdbe *v = pParse->pVdbe; /* Virtual machine under construction */ int ephemTab; /* Table holding the result of the SELECT */ int i; /* Loop counter */ sqlite3 *db = pParse->db; /* Database connection */ const char *pVTab = (const char*)sqlite3GetVTable(db, pTab); | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | | | | > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | > > | > | 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 | int onError /* ON CONFLICT strategy */ ){ Vdbe *v = pParse->pVdbe; /* Virtual machine under construction */ int ephemTab; /* Table holding the result of the SELECT */ int i; /* Loop counter */ sqlite3 *db = pParse->db; /* Database connection */ const char *pVTab = (const char*)sqlite3GetVTable(db, pTab); WhereInfo *pWInfo = 0; int nArg = 2 + pTab->nCol; /* Number of arguments to VUpdate */ int regArg; /* First register in VUpdate arg array */ int regRec; /* Register in which to assemble record */ int regRowid; /* Register for ephem table rowid */ int iCsr = pSrc->a[0].iCursor; /* Cursor used for virtual table scan */ int aDummy[2]; /* Unused arg for sqlite3WhereOkOnePass() */ int eOnePass; /* True to use onepass strategy */ int addr; /* Address of OP_OpenEphemeral */ /* Allocate nArg registers in which to gather the arguments for VUpdate. Then ** create and open the ephemeral table in which the records created from ** these arguments will be temporarily stored. */ assert( v ); ephemTab = pParse->nTab++; addr= sqlite3VdbeAddOp2(v, OP_OpenEphemeral, ephemTab, nArg); regArg = pParse->nMem + 1; pParse->nMem += nArg; if( pSrc->nSrc>1 ){ Index *pPk = 0; Expr *pRow; ExprList *pList; if( HasRowid(pTab) ){ if( pRowid ){ pRow = sqlite3ExprDup(db, pRowid, 0); }else{ pRow = sqlite3PExpr(pParse, TK_ROW, 0, 0); } }else{ i16 iPk; /* PRIMARY KEY column */ pPk = sqlite3PrimaryKeyIndex(pTab); assert( pPk!=0 ); assert( pPk->nKeyCol==1 ); iPk = pPk->aiColumn[0]; if( aXRef[iPk]>=0 ){ pRow = sqlite3ExprDup(db, pChanges->a[aXRef[iPk]].pExpr, 0); }else{ pRow = exprRowColumn(pParse, iPk); } } pList = sqlite3ExprListAppend(pParse, 0, pRow); for(i=0; i<pTab->nCol; i++){ if( aXRef[i]>=0 ){ pList = sqlite3ExprListAppend(pParse, pList, sqlite3ExprDup(db, pChanges->a[aXRef[i]].pExpr, 0) ); }else{ pList = sqlite3ExprListAppend(pParse, pList, exprRowColumn(pParse, i)); } } updateFromSelect(pParse, ephemTab, pPk, pList, pSrc, pWhere, 0, 0); sqlite3ExprListDelete(db, pList); eOnePass = ONEPASS_OFF; }else{ regRec = ++pParse->nMem; regRowid = ++pParse->nMem; /* Start scanning the virtual table */ pWInfo = sqlite3WhereBegin(pParse, pSrc,pWhere,0,0,WHERE_ONEPASS_DESIRED,0); if( pWInfo==0 ) return; /* Populate the argument registers. */ for(i=0; i<pTab->nCol; i++){ assert( (pTab->aCol[i].colFlags & COLFLAG_GENERATED)==0 ); if( aXRef[i]>=0 ){ sqlite3ExprCode(pParse, pChanges->a[aXRef[i]].pExpr, regArg+2+i); }else{ sqlite3VdbeAddOp3(v, OP_VColumn, iCsr, i, regArg+2+i); sqlite3VdbeChangeP5(v, OPFLAG_NOCHNG);/* For sqlite3_vtab_nochange() */ } } if( HasRowid(pTab) ){ sqlite3VdbeAddOp2(v, OP_Rowid, iCsr, regArg); if( pRowid ){ sqlite3ExprCode(pParse, pRowid, regArg+1); }else{ sqlite3VdbeAddOp2(v, OP_Rowid, iCsr, regArg+1); } }else{ Index *pPk; /* PRIMARY KEY index */ i16 iPk; /* PRIMARY KEY column */ pPk = sqlite3PrimaryKeyIndex(pTab); assert( pPk!=0 ); assert( pPk->nKeyCol==1 ); iPk = pPk->aiColumn[0]; sqlite3VdbeAddOp3(v, OP_VColumn, iCsr, iPk, regArg); sqlite3VdbeAddOp2(v, OP_SCopy, regArg+2+iPk, regArg+1); } eOnePass = sqlite3WhereOkOnePass(pWInfo, aDummy); /* There is no ONEPASS_MULTI on virtual tables */ assert( eOnePass==ONEPASS_OFF || eOnePass==ONEPASS_SINGLE ); if( eOnePass ){ /* If using the onepass strategy, no-op out the OP_OpenEphemeral coded ** above. */ sqlite3VdbeChangeToNoop(v, addr); sqlite3VdbeAddOp1(v, OP_Close, iCsr); }else{ /* Create a record from the argument register contents and insert it into ** the ephemeral table. */ sqlite3MultiWrite(pParse); sqlite3VdbeAddOp3(v, OP_MakeRecord, regArg, nArg, regRec); #if defined(SQLITE_DEBUG) && !defined(SQLITE_ENABLE_NULL_TRIM) /* Signal an assert() within OP_MakeRecord that it is allowed to ** accept no-change records with serial_type 10 */ sqlite3VdbeChangeP5(v, OPFLAG_NOCHNG_MAGIC); #endif sqlite3VdbeAddOp2(v, OP_NewRowid, ephemTab, regRowid); sqlite3VdbeAddOp3(v, OP_Insert, ephemTab, regRec, regRowid); } } if( eOnePass==ONEPASS_OFF ){ /* End the virtual table scan */ if( pSrc->nSrc==1 ){ sqlite3WhereEnd(pWInfo); } /* Begin scannning through the ephemeral table. */ addr = sqlite3VdbeAddOp1(v, OP_Rewind, ephemTab); VdbeCoverage(v); /* Extract arguments from the current row of the ephemeral table and ** invoke the VUpdate method. */ for(i=0; i<nArg; i++){ |
︙ | ︙ |
Changes to src/upsert.c.
︙ | ︙ | |||
14 15 16 17 18 19 20 | */ #include "sqliteInt.h" #ifndef SQLITE_OMIT_UPSERT /* ** Free a list of Upsert objects */ | | > | > > > | > > > | > | > | > > | | 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 | */ #include "sqliteInt.h" #ifndef SQLITE_OMIT_UPSERT /* ** Free a list of Upsert objects */ static void SQLITE_NOINLINE upsertDelete(sqlite3 *db, Upsert *p){ do{ Upsert *pNext = p->pNextUpsert; sqlite3ExprListDelete(db, p->pUpsertTarget); sqlite3ExprDelete(db, p->pUpsertTargetWhere); sqlite3ExprListDelete(db, p->pUpsertSet); sqlite3ExprDelete(db, p->pUpsertWhere); sqlite3DbFree(db, p->pToFree); sqlite3DbFree(db, p); p = pNext; }while( p ); } void sqlite3UpsertDelete(sqlite3 *db, Upsert *p){ if( p ) upsertDelete(db, p); } /* ** Duplicate an Upsert object. */ Upsert *sqlite3UpsertDup(sqlite3 *db, Upsert *p){ if( p==0 ) return 0; return sqlite3UpsertNew(db, sqlite3ExprListDup(db, p->pUpsertTarget, 0), sqlite3ExprDup(db, p->pUpsertTargetWhere, 0), sqlite3ExprListDup(db, p->pUpsertSet, 0), sqlite3ExprDup(db, p->pUpsertWhere, 0), sqlite3UpsertDup(db, p->pNextUpsert) ); } /* ** Create a new Upsert object. */ Upsert *sqlite3UpsertNew( sqlite3 *db, /* Determines which memory allocator to use */ ExprList *pTarget, /* Target argument to ON CONFLICT, or NULL */ Expr *pTargetWhere, /* Optional WHERE clause on the target */ ExprList *pSet, /* UPDATE columns, or NULL for a DO NOTHING */ Expr *pWhere, /* WHERE clause for the ON CONFLICT UPDATE */ Upsert *pNext /* Next ON CONFLICT clause in the list */ ){ Upsert *pNew; pNew = sqlite3DbMallocZero(db, sizeof(Upsert)); if( pNew==0 ){ sqlite3ExprListDelete(db, pTarget); sqlite3ExprDelete(db, pTargetWhere); sqlite3ExprListDelete(db, pSet); sqlite3ExprDelete(db, pWhere); sqlite3UpsertDelete(db, pNext); return 0; }else{ pNew->pUpsertTarget = pTarget; pNew->pUpsertTargetWhere = pTargetWhere; pNew->pUpsertSet = pSet; pNew->pUpsertWhere = pWhere; pNew->isDoUpdate = pSet!=0; pNew->pNextUpsert = pNext; } return pNew; } /* ** Analyze the ON CONFLICT clause described by pUpsert. Resolve all ** symbols in the conflict-target. |
︙ | ︙ | |||
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 | int rc; /* Result code */ int iCursor; /* Cursor used by pTab */ Index *pIdx; /* One of the indexes of pTab */ ExprList *pTarget; /* The conflict-target clause */ Expr *pTerm; /* One term of the conflict-target clause */ NameContext sNC; /* Context for resolving symbolic names */ Expr sCol[2]; /* Index column converted into an Expr */ assert( pTabList->nSrc==1 ); assert( pTabList->a[0].pTab!=0 ); assert( pUpsert!=0 ); assert( pUpsert->pUpsertTarget!=0 ); /* Resolve all symbolic names in the conflict-target clause, which ** includes both the list of columns and the optional partial-index ** WHERE clause. */ memset(&sNC, 0, sizeof(sNC)); sNC.pParse = pParse; sNC.pSrcList = pTabList; | > > > | | | | | | | | | | | | | | | | < > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | > > > > > > > | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | int rc; /* Result code */ int iCursor; /* Cursor used by pTab */ Index *pIdx; /* One of the indexes of pTab */ ExprList *pTarget; /* The conflict-target clause */ Expr *pTerm; /* One term of the conflict-target clause */ NameContext sNC; /* Context for resolving symbolic names */ Expr sCol[2]; /* Index column converted into an Expr */ int nClause = 0; /* Counter of ON CONFLICT clauses */ assert( pTabList->nSrc==1 ); assert( pTabList->a[0].pTab!=0 ); assert( pUpsert!=0 ); assert( pUpsert->pUpsertTarget!=0 ); /* Resolve all symbolic names in the conflict-target clause, which ** includes both the list of columns and the optional partial-index ** WHERE clause. */ memset(&sNC, 0, sizeof(sNC)); sNC.pParse = pParse; sNC.pSrcList = pTabList; for(; pUpsert && pUpsert->pUpsertTarget; pUpsert=pUpsert->pNextUpsert, nClause++){ rc = sqlite3ResolveExprListNames(&sNC, pUpsert->pUpsertTarget); if( rc ) return rc; rc = sqlite3ResolveExprNames(&sNC, pUpsert->pUpsertTargetWhere); if( rc ) return rc; /* Check to see if the conflict target matches the rowid. */ pTab = pTabList->a[0].pTab; pTarget = pUpsert->pUpsertTarget; iCursor = pTabList->a[0].iCursor; if( HasRowid(pTab) && pTarget->nExpr==1 && (pTerm = pTarget->a[0].pExpr)->op==TK_COLUMN && pTerm->iColumn==XN_ROWID ){ /* The conflict-target is the rowid of the primary table */ assert( pUpsert->pUpsertIdx==0 ); continue; } /* Initialize sCol[0..1] to be an expression parse tree for a ** single column of an index. The sCol[0] node will be the TK_COLLATE ** operator and sCol[1] will be the TK_COLUMN operator. Code below ** will populate the specific collation and column number values ** prior to comparing against the conflict-target expression. */ memset(sCol, 0, sizeof(sCol)); sCol[0].op = TK_COLLATE; sCol[0].pLeft = &sCol[1]; sCol[1].op = TK_COLUMN; sCol[1].iTable = pTabList->a[0].iCursor; /* Check for matches against other indexes */ for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ int ii, jj, nn; if( !IsUniqueIndex(pIdx) ) continue; if( pTarget->nExpr!=pIdx->nKeyCol ) continue; if( pIdx->pPartIdxWhere ){ if( pUpsert->pUpsertTargetWhere==0 ) continue; if( sqlite3ExprCompare(pParse, pUpsert->pUpsertTargetWhere, pIdx->pPartIdxWhere, iCursor)!=0 ){ continue; } } nn = pIdx->nKeyCol; for(ii=0; ii<nn; ii++){ Expr *pExpr; sCol[0].u.zToken = (char*)pIdx->azColl[ii]; if( pIdx->aiColumn[ii]==XN_EXPR ){ assert( pIdx->aColExpr!=0 ); assert( pIdx->aColExpr->nExpr>ii ); pExpr = pIdx->aColExpr->a[ii].pExpr; if( pExpr->op!=TK_COLLATE ){ sCol[0].pLeft = pExpr; pExpr = &sCol[0]; } }else{ sCol[0].pLeft = &sCol[1]; sCol[1].iColumn = pIdx->aiColumn[ii]; pExpr = &sCol[0]; } for(jj=0; jj<nn; jj++){ if( sqlite3ExprCompare(pParse,pTarget->a[jj].pExpr,pExpr,iCursor)<2 ){ break; /* Column ii of the index matches column jj of target */ } } if( jj>=nn ){ /* The target contains no match for column jj of the index */ break; } } if( ii<nn ){ /* Column ii of the index did not match any term of the conflict target. ** Continue the search with the next index. */ continue; } pUpsert->pUpsertIdx = pIdx; break; } if( pUpsert->pUpsertIdx==0 ){ char zWhich[16]; if( nClause==0 && pUpsert->pNextUpsert==0 ){ zWhich[0] = 0; }else{ sqlite3_snprintf(sizeof(zWhich),zWhich,"%r ", nClause+1); } sqlite3ErrorMsg(pParse, "%sON CONFLICT clause does not match any " "PRIMARY KEY or UNIQUE constraint", zWhich); return SQLITE_ERROR; } } return SQLITE_OK; } /* ** Return true if pUpsert is the last ON CONFLICT clause with a ** conflict target, or if pUpsert is followed by another ON CONFLICT ** clause that targets the INTEGER PRIMARY KEY. */ int sqlite3UpsertNextIsIPK(Upsert *pUpsert){ Upsert *pNext; if( NEVER(pUpsert==0) ) return 0; pNext = pUpsert->pNextUpsert; if( pNext==0 ) return 1; if( pNext->pUpsertTarget==0 ) return 1; if( pNext->pUpsertIdx==0 ) return 1; return 0; } /* ** Given the list of ON CONFLICT clauses described by pUpsert, and ** a particular index pIdx, return a pointer to the particular ON CONFLICT ** clause that applies to the index. Or, if the index is not subject to ** any ON CONFLICT clause, return NULL. */ Upsert *sqlite3UpsertOfIndex(Upsert *pUpsert, Index *pIdx){ while( pUpsert && pUpsert->pUpsertTarget!=0 && pUpsert->pUpsertIdx!=pIdx ){ pUpsert = pUpsert->pNextUpsert; } return pUpsert; } /* ** Generate bytecode that does an UPDATE as part of an upsert. ** ** If pIdx is NULL, then the UNIQUE constraint that failed was the IPK. ** In this case parameter iCur is a cursor open on the table b-tree that |
︙ | ︙ | |||
201 202 203 204 205 206 207 208 209 210 | Index *pIdx, /* The UNIQUE constraint that failed */ int iCur /* Cursor for pIdx (or pTab if pIdx==NULL) */ ){ Vdbe *v = pParse->pVdbe; sqlite3 *db = pParse->db; SrcList *pSrc; /* FROM clause for the UPDATE */ int iDataCur; assert( v!=0 ); assert( pUpsert!=0 ); | > > < > > < | | > | | | > > > > > > | | < < | 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 | Index *pIdx, /* The UNIQUE constraint that failed */ int iCur /* Cursor for pIdx (or pTab if pIdx==NULL) */ ){ Vdbe *v = pParse->pVdbe; sqlite3 *db = pParse->db; SrcList *pSrc; /* FROM clause for the UPDATE */ int iDataCur; int i; Upsert *pTop = pUpsert; assert( v!=0 ); assert( pUpsert!=0 ); iDataCur = pUpsert->iDataCur; pUpsert = sqlite3UpsertOfIndex(pTop, pIdx); VdbeNoopComment((v, "Begin DO UPDATE of UPSERT")); if( pIdx && iCur!=iDataCur ){ if( HasRowid(pTab) ){ int regRowid = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp2(v, OP_IdxRowid, iCur, regRowid); sqlite3VdbeAddOp3(v, OP_SeekRowid, iDataCur, 0, regRowid); VdbeCoverage(v); sqlite3ReleaseTempReg(pParse, regRowid); }else{ Index *pPk = sqlite3PrimaryKeyIndex(pTab); int nPk = pPk->nKeyCol; int iPk = pParse->nMem+1; pParse->nMem += nPk; for(i=0; i<nPk; i++){ int k; assert( pPk->aiColumn[i]>=0 ); k = sqlite3TableColumnToIndex(pIdx, pPk->aiColumn[i]); sqlite3VdbeAddOp3(v, OP_Column, iCur, k, iPk+i); VdbeComment((v, "%s.%s", pIdx->zName, pTab->aCol[pPk->aiColumn[i]].zCnName)); } sqlite3VdbeVerifyAbortable(v, OE_Abort); i = sqlite3VdbeAddOp4Int(v, OP_Found, iDataCur, 0, iPk, nPk); VdbeCoverage(v); sqlite3VdbeAddOp4(v, OP_Halt, SQLITE_CORRUPT, OE_Abort, 0, "corrupt database", P4_STATIC); sqlite3MayAbort(pParse); sqlite3VdbeJumpHere(v, i); } } /* pUpsert does not own pTop->pUpsertSrc - the outer INSERT statement does. ** So we have to make a copy before passing it down into sqlite3Update() */ pSrc = sqlite3SrcListDup(db, pTop->pUpsertSrc, 0); /* excluded.* columns of type REAL need to be converted to a hard real */ for(i=0; i<pTab->nCol; i++){ if( pTab->aCol[i].affinity==SQLITE_AFF_REAL ){ sqlite3VdbeAddOp1(v, OP_RealAffinity, pTop->regData+i); } } sqlite3Update(pParse, pSrc, sqlite3ExprListDup(db,pUpsert->pUpsertSet,0), sqlite3ExprDup(db,pUpsert->pUpsertWhere,0), OE_Abort, 0, 0, pUpsert); VdbeNoopComment((v, "End DO UPDATE of UPSERT")); } #endif /* SQLITE_OMIT_UPSERT */ |
Changes to src/utf.c.
︙ | ︙ | |||
101 102 103 104 105 106 107 | *zOut++ = (u8)(0x00D8 + (((c-0x10000)>>18)&0x03)); \ *zOut++ = (u8)(((c>>10)&0x003F) + (((c-0x10000)>>10)&0x00C0)); \ *zOut++ = (u8)(0x00DC + ((c>>8)&0x03)); \ *zOut++ = (u8)(c&0x00FF); \ } \ } | < < < < < < < < < < < < < < < < < < < < | 101 102 103 104 105 106 107 108 109 110 111 112 113 114 | *zOut++ = (u8)(0x00D8 + (((c-0x10000)>>18)&0x03)); \ *zOut++ = (u8)(((c>>10)&0x003F) + (((c-0x10000)>>10)&0x00C0)); \ *zOut++ = (u8)(0x00DC + ((c>>8)&0x03)); \ *zOut++ = (u8)(c&0x00FF); \ } \ } /* ** Translate a single UTF-8 character. Return the unicode value. ** ** During translation, assume that the byte that zTerm points ** is a 0x00. ** ** Write a pointer to the next unread byte back into *pzNext. |
︙ | ︙ | |||
196 197 198 199 200 201 202 | #ifndef SQLITE_OMIT_UTF16 /* ** This routine transforms the internal text encoding used by pMem to ** desiredEnc. It is an error if the string is already of the desired ** encoding, or if *pMem does not contain a string value. */ SQLITE_NOINLINE int sqlite3VdbeMemTranslate(Mem *pMem, u8 desiredEnc){ | | | | | | > | > | | | 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 | #ifndef SQLITE_OMIT_UTF16 /* ** This routine transforms the internal text encoding used by pMem to ** desiredEnc. It is an error if the string is already of the desired ** encoding, or if *pMem does not contain a string value. */ SQLITE_NOINLINE int sqlite3VdbeMemTranslate(Mem *pMem, u8 desiredEnc){ sqlite3_int64 len; /* Maximum length of output string in bytes */ unsigned char *zOut; /* Output buffer */ unsigned char *zIn; /* Input iterator */ unsigned char *zTerm; /* End of input */ unsigned char *z; /* Output iterator */ unsigned int c; assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); assert( pMem->flags&MEM_Str ); assert( pMem->enc!=desiredEnc ); assert( pMem->enc!=0 ); assert( pMem->n>=0 ); #if defined(TRANSLATE_TRACE) && defined(SQLITE_DEBUG) { StrAccum acc; char zBuf[1000]; sqlite3StrAccumInit(&acc, 0, zBuf, sizeof(zBuf), 0); sqlite3VdbeMemPrettyPrint(pMem, &acc); fprintf(stderr, "INPUT: %s\n", sqlite3StrAccumFinish(&acc)); } #endif /* If the translation is between UTF-16 little and big endian, then ** all that is required is to swap the byte order. This case is handled ** differently from the others. */ |
︙ | ︙ | |||
249 250 251 252 253 254 255 | if( desiredEnc==SQLITE_UTF8 ){ /* When converting from UTF-16, the maximum growth results from ** translating a 2-byte character to a 4-byte UTF-8 character. ** A single byte is required for the output string ** nul-terminator. */ pMem->n &= ~1; | | | | 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 | if( desiredEnc==SQLITE_UTF8 ){ /* When converting from UTF-16, the maximum growth results from ** translating a 2-byte character to a 4-byte UTF-8 character. ** A single byte is required for the output string ** nul-terminator. */ pMem->n &= ~1; len = 2 * (sqlite3_int64)pMem->n + 1; }else{ /* When converting from UTF-8 to UTF-16 the maximum growth is caused ** when a 1-byte UTF-8 character is translated into a 2-byte UTF-16 ** character. Two bytes are required in the output buffer for the ** nul-terminator. */ len = 2 * (sqlite3_int64)pMem->n + 2; } /* Set zIn to point at the start of the input buffer and zTerm to point 1 ** byte past the end. ** ** Variable zOut is set to point at the output buffer, space obtained ** from sqlite3_malloc(). |
︙ | ︙ | |||
295 296 297 298 299 300 301 | pMem->n = (int)(z - zOut); *z++ = 0; }else{ assert( desiredEnc==SQLITE_UTF8 ); if( pMem->enc==SQLITE_UTF16LE ){ /* UTF-16 Little-endian -> UTF-8 */ while( zIn<zTerm ){ | > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > | | > | > | | | 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 | pMem->n = (int)(z - zOut); *z++ = 0; }else{ assert( desiredEnc==SQLITE_UTF8 ); if( pMem->enc==SQLITE_UTF16LE ){ /* UTF-16 Little-endian -> UTF-8 */ while( zIn<zTerm ){ c = *(zIn++); c += (*(zIn++))<<8; if( c>=0xd800 && c<0xe000 ){ #ifdef SQLITE_REPLACE_INVALID_UTF if( c>=0xdc00 || zIn>=zTerm ){ c = 0xfffd; }else{ int c2 = *(zIn++); c2 += (*(zIn++))<<8; if( c2<0xdc00 || c2>=0xe000 ){ zIn -= 2; c = 0xfffd; }else{ c = ((c&0x3ff)<<10) + (c2&0x3ff) + 0x10000; } } #else if( zIn<zTerm ){ int c2 = (*zIn++); c2 += ((*zIn++)<<8); c = (c2&0x03FF) + ((c&0x003F)<<10) + (((c&0x03C0)+0x0040)<<10); } #endif } WRITE_UTF8(z, c); } }else{ /* UTF-16 Big-endian -> UTF-8 */ while( zIn<zTerm ){ c = (*(zIn++))<<8; c += *(zIn++); if( c>=0xd800 && c<0xe000 ){ #ifdef SQLITE_REPLACE_INVALID_UTF if( c>=0xdc00 || zIn>=zTerm ){ c = 0xfffd; }else{ int c2 = (*(zIn++))<<8; c2 += *(zIn++); if( c2<0xdc00 || c2>=0xe000 ){ zIn -= 2; c = 0xfffd; }else{ c = ((c&0x3ff)<<10) + (c2&0x3ff) + 0x10000; } } #else if( zIn<zTerm ){ int c2 = ((*zIn++)<<8); c2 += (*zIn++); c = (c2&0x03FF) + ((c&0x003F)<<10) + (((c&0x03C0)+0x0040)<<10); } #endif } WRITE_UTF8(z, c); } } pMem->n = (int)(z - zOut); } *z = 0; assert( (pMem->n+(desiredEnc==SQLITE_UTF8?1:2))<=len ); c = MEM_Str|MEM_Term|(pMem->flags&(MEM_AffMask|MEM_Subtype)); sqlite3VdbeMemRelease(pMem); pMem->flags = c; pMem->enc = desiredEnc; pMem->z = (char*)zOut; pMem->zMalloc = pMem->z; pMem->szMalloc = sqlite3DbMallocSize(pMem->db, pMem->z); translate_out: #if defined(TRANSLATE_TRACE) && defined(SQLITE_DEBUG) { StrAccum acc; char zBuf[1000]; sqlite3StrAccumInit(&acc, 0, zBuf, sizeof(zBuf), 0); sqlite3VdbeMemPrettyPrint(pMem, &acc); fprintf(stderr, "OUTPUT: %s\n", sqlite3StrAccumFinish(&acc)); } #endif return SQLITE_OK; } #endif /* SQLITE_OMIT_UTF16 */ #ifndef SQLITE_OMIT_UTF16 |
︙ | ︙ | |||
458 459 460 461 462 463 464 | ** in pZ. nChar must be non-negative. */ int sqlite3Utf16ByteLen(const void *zIn, int nChar){ int c; unsigned char const *z = zIn; int n = 0; | | | | | < < < < > | | < | > | 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 | ** in pZ. nChar must be non-negative. */ int sqlite3Utf16ByteLen(const void *zIn, int nChar){ int c; unsigned char const *z = zIn; int n = 0; if( SQLITE_UTF16NATIVE==SQLITE_UTF16LE ) z++; while( n<nChar ){ c = z[0]; z += 2; if( c>=0xd8 && c<0xdc && z[0]>=0xdc && z[0]<0xe0 ) z += 2; n++; } return (int)(z-(unsigned char const *)zIn) - (SQLITE_UTF16NATIVE==SQLITE_UTF16LE); } #if defined(SQLITE_TEST) /* ** This routine is called from the TCL test function "translate_selftest". ** It checks that the primitives for serializing and deserializing ** characters in each encoding are inverses of each other. |
︙ | ︙ | |||
497 498 499 500 501 502 503 | z[0] = 0; z = zBuf; c = sqlite3Utf8Read((const u8**)&z); t = i; if( i>=0xD800 && i<=0xDFFF ) t = 0xFFFD; if( (i&0xFFFFFFFE)==0xFFFE ) t = 0xFFFD; assert( c==t ); | < < < < < < < < < < < < < < < < < < < < < < < < | 524 525 526 527 528 529 530 531 532 533 534 535 | z[0] = 0; z = zBuf; c = sqlite3Utf8Read((const u8**)&z); t = i; if( i>=0xD800 && i<=0xDFFF ) t = 0xFFFD; if( (i&0xFFFFFFFE)==0xFFFE ) t = 0xFFFD; assert( c==t ); assert( (z-zBuf)==n ); } } #endif /* SQLITE_TEST */ #endif /* SQLITE_OMIT_UTF16 */ |
Changes to src/util.c.
︙ | ︙ | |||
13 14 15 16 17 18 19 | ** ** This file contains functions for allocating memory, comparing ** strings, and stuff like that. ** */ #include "sqliteInt.h" #include <stdarg.h> | | | | > > | < | < < < < | < < < < > > > | | | < > > > < < < < < < < < | < < < < < < < < | < < < < < < < < < < | | | 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 | ** ** This file contains functions for allocating memory, comparing ** strings, and stuff like that. ** */ #include "sqliteInt.h" #include <stdarg.h> #ifndef SQLITE_OMIT_FLOATING_POINT #include <math.h> #endif /* ** Calls to sqlite3FaultSim() are used to simulate a failure during testing, ** or to bypass normal error detection during testing in order to let ** execute proceed futher downstream. ** ** In deployment, sqlite3FaultSim() *always* return SQLITE_OK (0). The ** sqlite3FaultSim() function only returns non-zero during testing. ** ** During testing, if the test harness has set a fault-sim callback using ** a call to sqlite3_test_control(SQLITE_TESTCTRL_FAULT_INSTALL), then ** each call to sqlite3FaultSim() is relayed to that application-supplied ** callback and the integer return value form the application-supplied ** callback is returned by sqlite3FaultSim(). ** ** The integer argument to sqlite3FaultSim() is a code to identify which ** sqlite3FaultSim() instance is being invoked. Each call to sqlite3FaultSim() ** should have a unique code. To prevent legacy testing applications from ** breaking, the codes should not be changed or reused. */ #ifndef SQLITE_UNTESTABLE int sqlite3FaultSim(int iTest){ int (*xCallback)(int) = sqlite3GlobalConfig.xTestCallback; return xCallback ? xCallback(iTest) : SQLITE_OK; } #endif #ifndef SQLITE_OMIT_FLOATING_POINT /* ** Return true if the floating point value is Not a Number (NaN). ** ** Use the math library isnan() function if compiled with SQLITE_HAVE_ISNAN. ** Otherwise, we have our own implementation that works on most systems. */ int sqlite3IsNaN(double x){ int rc; /* The value return */ #if !SQLITE_HAVE_ISNAN && !HAVE_ISNAN u64 y; memcpy(&y,&x,sizeof(y)); rc = IsNaN(y); #else rc = isnan(x); #endif /* HAVE_ISNAN */ testcase( rc ); return rc; } #endif /* SQLITE_OMIT_FLOATING_POINT */ |
︙ | ︙ | |||
113 114 115 116 117 118 119 | ** Return the declared type of a column. Or return zDflt if the column ** has no declared type. ** ** The column type is an extra string stored after the zero-terminator on ** the column name if and only if the COLFLAG_HASTYPE flag is set. */ char *sqlite3ColumnType(Column *pCol, char *zDflt){ | | | > > > > > > | 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 | ** Return the declared type of a column. Or return zDflt if the column ** has no declared type. ** ** The column type is an extra string stored after the zero-terminator on ** the column name if and only if the COLFLAG_HASTYPE flag is set. */ char *sqlite3ColumnType(Column *pCol, char *zDflt){ if( pCol->colFlags & COLFLAG_HASTYPE ){ return pCol->zCnName + strlen(pCol->zCnName) + 1; }else if( pCol->eCType ){ assert( pCol->eCType<=SQLITE_N_STDTYPE ); return (char*)sqlite3StdType[pCol->eCType-1]; }else{ return zDflt; } } /* ** Helper function for sqlite3Error() - called rarely. Broken out into ** a separate routine to avoid unnecessary register saves on entry to ** sqlite3Error(). */ |
︙ | ︙ | |||
137 138 139 140 141 142 143 144 145 146 147 148 149 150 | ** that would be appropriate. */ void sqlite3Error(sqlite3 *db, int err_code){ assert( db!=0 ); db->errCode = err_code; if( err_code || db->pErr ) sqlite3ErrorFinish(db, err_code); } /* ** Load the sqlite3.iSysErrno field if that is an appropriate thing ** to do based on the SQLite error code in rc. */ void sqlite3SystemError(sqlite3 *db, int rc){ if( rc==SQLITE_IOERR_NOMEM ) return; | > > > > > > > > > > | 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 | ** that would be appropriate. */ void sqlite3Error(sqlite3 *db, int err_code){ assert( db!=0 ); db->errCode = err_code; if( err_code || db->pErr ) sqlite3ErrorFinish(db, err_code); } /* ** The equivalent of sqlite3Error(db, SQLITE_OK). Clear the error state ** and error message. */ void sqlite3ErrorClear(sqlite3 *db){ assert( db!=0 ); db->errCode = SQLITE_OK; if( db->pErr ) sqlite3ValueSetNull(db->pErr); } /* ** Load the sqlite3.iSysErrno field if that is an appropriate thing ** to do based on the SQLite error code in rc. */ void sqlite3SystemError(sqlite3 *db, int rc){ if( rc==SQLITE_IOERR_NOMEM ) return; |
︙ | ︙ | |||
218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 | if( db->suppressErr ){ sqlite3DbFree(db, zMsg); }else{ pParse->nErr++; sqlite3DbFree(db, pParse->zErrMsg); pParse->zErrMsg = zMsg; pParse->rc = SQLITE_ERROR; } } /* ** Convert an SQL-style quoted string into a normal string by removing ** the quote characters. The conversion is done in-place. If the ** input does not begin with a quote character, then this routine ** is a no-op. ** ** The input string must be zero-terminated. A new zero-terminator ** is added to the dequoted string. ** ** The return value is -1 if no dequoting occurs or the length of the ** dequoted string, exclusive of the zero terminator, if dequoting does ** occur. ** | > > > > > > > > > > > > > > | | 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 | if( db->suppressErr ){ sqlite3DbFree(db, zMsg); }else{ pParse->nErr++; sqlite3DbFree(db, pParse->zErrMsg); pParse->zErrMsg = zMsg; pParse->rc = SQLITE_ERROR; pParse->pWith = 0; } } /* ** If database connection db is currently parsing SQL, then transfer ** error code errCode to that parser if the parser has not already ** encountered some other kind of error. */ int sqlite3ErrorToParser(sqlite3 *db, int errCode){ Parse *pParse; if( db==0 || (pParse = db->pParse)==0 ) return errCode; pParse->rc = errCode; pParse->nErr++; return errCode; } /* ** Convert an SQL-style quoted string into a normal string by removing ** the quote characters. The conversion is done in-place. If the ** input does not begin with a quote character, then this routine ** is a no-op. ** ** The input string must be zero-terminated. A new zero-terminator ** is added to the dequoted string. ** ** The return value is -1 if no dequoting occurs or the length of the ** dequoted string, exclusive of the zero terminator, if dequoting does ** occur. ** ** 2002-02-14: This routine is extended to remove MS-Access style ** brackets from around identifiers. For example: "[a-b-c]" becomes ** "a-b-c". */ void sqlite3Dequote(char *z){ char quote; int i, j; if( z==0 ) return; |
︙ | ︙ | |||
259 260 261 262 263 264 265 266 267 268 269 270 271 272 | break; } }else{ z[j++] = z[i]; } } z[j] = 0; } /* ** Generate a Token object from a string */ void sqlite3TokenInit(Token *p, char *z){ p->z = z; | > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | break; } }else{ z[j++] = z[i]; } } z[j] = 0; } void sqlite3DequoteExpr(Expr *p){ assert( !ExprHasProperty(p, EP_IntValue) ); assert( sqlite3Isquote(p->u.zToken[0]) ); p->flags |= p->u.zToken[0]=='"' ? EP_Quoted|EP_DblQuoted : EP_Quoted; sqlite3Dequote(p->u.zToken); } /* ** If the input token p is quoted, try to adjust the token to remove ** the quotes. This is not always possible: ** ** "abc" -> abc ** "ab""cd" -> (not possible because of the interior "") ** ** Remove the quotes if possible. This is a optimization. The overall ** system should still return the correct answer even if this routine ** is always a no-op. */ void sqlite3DequoteToken(Token *p){ unsigned int i; if( p->n<2 ) return; if( !sqlite3Isquote(p->z[0]) ) return; for(i=1; i<p->n-1; i++){ if( sqlite3Isquote(p->z[i]) ) return; } p->n -= 2; p->z++; } /* ** Generate a Token object from a string */ void sqlite3TokenInit(Token *p, char *z){ p->z = z; |
︙ | ︙ | |||
292 293 294 295 296 297 298 | }else if( zRight==0 ){ return 1; } return sqlite3StrICmp(zLeft, zRight); } int sqlite3StrICmp(const char *zLeft, const char *zRight){ unsigned char *a, *b; | | > > > > > | | > > > > > > > > > > > > > > | | | | | | | | | | 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 | }else if( zRight==0 ){ return 1; } return sqlite3StrICmp(zLeft, zRight); } int sqlite3StrICmp(const char *zLeft, const char *zRight){ unsigned char *a, *b; int c, x; a = (unsigned char *)zLeft; b = (unsigned char *)zRight; for(;;){ c = *a; x = *b; if( c==x ){ if( c==0 ) break; }else{ c = (int)UpperToLower[c] - (int)UpperToLower[x]; if( c ) break; } a++; b++; } return c; } int sqlite3_strnicmp(const char *zLeft, const char *zRight, int N){ register unsigned char *a, *b; if( zLeft==0 ){ return zRight ? -1 : 0; }else if( zRight==0 ){ return 1; } a = (unsigned char *)zLeft; b = (unsigned char *)zRight; while( N-- > 0 && *a!=0 && UpperToLower[*a]==UpperToLower[*b]){ a++; b++; } return N<0 ? 0 : UpperToLower[*a] - UpperToLower[*b]; } /* ** Compute an 8-bit hash on a string that is insensitive to case differences */ u8 sqlite3StrIHash(const char *z){ u8 h = 0; if( z==0 ) return 0; while( z[0] ){ h += UpperToLower[(unsigned char)z[0]]; z++; } return h; } /* ** Compute 10 to the E-th power. Examples: E==1 results in 10. ** E==2 results in 100. E==50 results in 1.0e50. ** ** This routine only works for values of E between 1 and 341. */ static LONGDOUBLE_TYPE sqlite3Pow10(int E){ #if defined(_MSC_VER) static const LONGDOUBLE_TYPE x[] = { 1.0e+001L, 1.0e+002L, 1.0e+004L, 1.0e+008L, 1.0e+016L, 1.0e+032L, 1.0e+064L, 1.0e+128L, 1.0e+256L }; LONGDOUBLE_TYPE r = 1.0; int i; assert( E>=0 && E<=307 ); for(i=0; E!=0; i++, E >>=1){ if( E & 1 ) r *= x[i]; } |
︙ | ︙ | |||
363 364 365 366 367 368 369 | ** The string z[] is an text representation of a real number. ** Convert this string to a double and write it into *pResult. ** ** The string z[] is length bytes in length (bytes, not characters) and ** uses the encoding enc. The string is not necessarily zero-terminated. ** ** Return TRUE if the result is a valid real number (or integer) and FALSE | | > > > > > > > | > > > | | | > > > > > | | | < | | | | > > > > | > | 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 | ** The string z[] is an text representation of a real number. ** Convert this string to a double and write it into *pResult. ** ** The string z[] is length bytes in length (bytes, not characters) and ** uses the encoding enc. The string is not necessarily zero-terminated. ** ** Return TRUE if the result is a valid real number (or integer) and FALSE ** if the string is empty or contains extraneous text. More specifically ** return ** 1 => The input string is a pure integer ** 2 or more => The input has a decimal point or eNNN clause ** 0 or less => The input string is not a valid number ** -1 => Not a valid number, but has a valid prefix which ** includes a decimal point and/or an eNNN clause ** ** Valid numbers are in one of these formats: ** ** [+-]digits[E[+-]digits] ** [+-]digits.[digits][E[+-]digits] ** [+-].digits[E[+-]digits] ** ** Leading and trailing whitespace is ignored for the purpose of determining ** validity. ** ** 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. */ #if defined(_MSC_VER) #pragma warning(disable : 4756) #endif int sqlite3AtoF(const char *z, double *pResult, int length, u8 enc){ #ifndef SQLITE_OMIT_FLOATING_POINT int incr; const char *zEnd; /* 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 nDigit = 0; /* Number of digits processed */ int eType = 1; /* 1: pure integer, 2+: fractional -1 or less: bad UTF16 */ assert( enc==SQLITE_UTF8 || enc==SQLITE_UTF16LE || enc==SQLITE_UTF16BE ); *pResult = 0.0; /* Default return value, in case of an error */ if( length==0 ) return 0; if( enc==SQLITE_UTF8 ){ incr = 1; zEnd = z + length; }else{ int i; incr = 2; length &= ~1; assert( SQLITE_UTF16LE==2 && SQLITE_UTF16BE==3 ); testcase( enc==SQLITE_UTF16LE ); testcase( enc==SQLITE_UTF16BE ); for(i=3-enc; i<length && z[i]==0; i+=2){} if( i<length ) eType = -100; zEnd = &z[i^1]; z += (enc&1); } /* skip leading spaces */ while( z<zEnd && sqlite3Isspace(*z) ) z+=incr; if( z>=zEnd ) return 0; /* get sign of significand */ if( *z=='-' ){ sign = -1; z+=incr; }else if( *z=='+' ){ z+=incr; } /* copy max significant digits to significand */ while( z<zEnd && sqlite3Isdigit(*z) ){ s = s*10 + (*z - '0'); z+=incr; nDigit++; if( s>=((LARGEST_INT64-9)/10) ){ /* skip non-significant significand digits ** (increase exponent by d to shift decimal left) */ while( z<zEnd && sqlite3Isdigit(*z) ){ z+=incr; d++; } } } if( z>=zEnd ) goto do_atof_calc; /* if decimal point is present */ if( *z=='.' ){ z+=incr; eType++; /* copy digits from after decimal to significand ** (decrease exponent by d to shift decimal right) */ while( z<zEnd && sqlite3Isdigit(*z) ){ if( s<((LARGEST_INT64-9)/10) ){ s = s*10 + (*z - '0'); d--; nDigit++; } z+=incr; } } if( z>=zEnd ) goto do_atof_calc; /* if exponent is present */ if( *z=='e' || *z=='E' ){ z+=incr; eValid = 0; eType++; /* This branch is needed to avoid a (harmless) buffer overread. The ** special comment alerts the mutation tester that the correct answer ** is obtained even if the branch is omitted */ if( z>=zEnd ) goto do_atof_calc; /*PREVENTS-HARMLESS-OVERREAD*/ /* get sign of exponent */ |
︙ | ︙ | |||
547 548 549 550 551 552 553 | } } /* store the result */ *pResult = result; /* return true if number and no extra non-whitespace chracters after */ | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | } } /* store the result */ *pResult = result; /* return true if number and no extra non-whitespace chracters after */ if( z==zEnd && nDigit>0 && eValid && eType>0 ){ return eType; }else if( eType>=2 && (eType==3 || eValid) && nDigit>0 ){ return -1; }else{ return 0; } #else return !sqlite3Atoi64(z, pResult, length, enc); #endif /* SQLITE_OMIT_FLOATING_POINT */ } #if defined(_MSC_VER) #pragma warning(default : 4756) #endif /* ** Render an signed 64-bit integer as text. Store the result in zOut[]. ** ** The caller must ensure that zOut[] is at least 21 bytes in size. */ void sqlite3Int64ToText(i64 v, char *zOut){ int i; u64 x; char zTemp[22]; if( v<0 ){ x = (v==SMALLEST_INT64) ? ((u64)1)<<63 : (u64)-v; }else{ x = v; } i = sizeof(zTemp)-2; zTemp[sizeof(zTemp)-1] = 0; do{ zTemp[i--] = (x%10) + '0'; x = x/10; }while( x ); if( v<0 ) zTemp[i--] = '-'; memcpy(zOut, &zTemp[i+1], sizeof(zTemp)-1-i); } /* ** Compare the 19-character string zNum against the text representation ** value 2^63: 9223372036854775808. Return negative, zero, or positive ** if zNum is less than, equal to, or greater than the string. ** Note that zNum must contain exactly 19 characters. ** |
︙ | ︙ | |||
590 591 592 593 594 595 596 597 598 599 600 601 602 603 | /* ** Convert zNum to a 64-bit signed integer. zNum must be decimal. This ** routine does *not* accept hexadecimal notation. ** ** Returns: ** ** 0 Successful transformation. Fits in a 64-bit signed integer. ** 1 Excess non-space text after the integer value ** 2 Integer too large for a 64-bit signed integer or is malformed ** 3 Special case of 9223372036854775808 ** ** length is the number of bytes in the string (bytes, not characters). ** The string is not necessarily zero-terminated. The encoding is | > | 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 | /* ** Convert zNum to a 64-bit signed integer. zNum must be decimal. This ** routine does *not* accept hexadecimal notation. ** ** Returns: ** ** -1 Not even a prefix of the input text looks like an integer ** 0 Successful transformation. Fits in a 64-bit signed integer. ** 1 Excess non-space text after the integer value ** 2 Integer too large for a 64-bit signed integer or is malformed ** 3 Special case of 9223372036854775808 ** ** length is the number of bytes in the string (bytes, not characters). ** The string is not necessarily zero-terminated. The encoding is |
︙ | ︙ | |||
614 615 616 617 618 619 620 621 622 623 624 625 626 627 | 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^1]; zNum += (enc&1); } while( zNum<zEnd && sqlite3Isspace(*zNum) ) zNum+=incr; | > | 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 | 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; length &= ~1; assert( SQLITE_UTF16LE==2 && SQLITE_UTF16BE==3 ); for(i=3-enc; i<length && zNum[i]==0; i+=2){} nonNum = i<length; zEnd = &zNum[i^1]; zNum += (enc&1); } while( zNum<zEnd && sqlite3Isspace(*zNum) ) zNum+=incr; |
︙ | ︙ | |||
649 650 651 652 653 654 655 | *pNum = neg ? SMALLEST_INT64 : LARGEST_INT64; }else if( neg ){ *pNum = -(i64)u; }else{ *pNum = (i64)u; } rc = 0; | | > | < | 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 | *pNum = neg ? SMALLEST_INT64 : LARGEST_INT64; }else if( neg ){ *pNum = -(i64)u; }else{ *pNum = (i64)u; } rc = 0; if( i==0 && zStart==zNum ){ /* No digits */ rc = -1; }else if( nonNum ){ /* UTF16 with high-order bytes non-zero */ rc = 1; }else if( &zNum[i]<zEnd ){ /* Extra bytes at the end */ int jj = i; do{ if( !sqlite3Isspace(zNum[jj]) ){ rc = 1; /* Extra non-space text after the integer */ break; |
︙ | ︙ | |||
792 793 794 795 796 797 798 | /* ** Return a 32-bit integer value extracted from a string. If the ** string is not an integer, just return 0. */ int sqlite3Atoi(const char *z){ int x = 0; | | > > > > > > > > > > > > > > > > > > | 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 | /* ** Return a 32-bit integer value extracted from a string. If the ** string is not an integer, just return 0. */ int sqlite3Atoi(const char *z){ int x = 0; sqlite3GetInt32(z, &x); return x; } /* ** Try to convert z into an unsigned 32-bit integer. Return true on ** success and false if there is an error. ** ** Only decimal notation is accepted. */ int sqlite3GetUInt32(const char *z, u32 *pI){ u64 v = 0; int i; for(i=0; sqlite3Isdigit(z[i]); i++){ v = v*10 + z[i] - '0'; if( v>4294967296LL ){ *pI = 0; return 0; } } if( i==0 || z[i]!=0 ){ *pI = 0; return 0; } *pI = (u32)v; return 1; } /* ** The variable-length integer encoding is as follows: ** ** KEY: ** A = 0xxxxxxx 7 bits of data and one flag bit ** B = 1xxxxxxx 7 bits of data and one flag bit |
︙ | ︙ | |||
882 883 884 885 886 887 888 | /* ** Read a 64-bit variable-length integer from memory starting at p[0]. ** Return the number of bytes read. The value is stored in *v. */ u8 sqlite3GetVarint(const unsigned char *p, u64 *v){ u32 a,b,s; | > | < < < < | < < < < < < < < | | | > | 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 | /* ** Read a 64-bit variable-length integer from memory starting at p[0]. ** Return the number of bytes read. The value is stored in *v. */ u8 sqlite3GetVarint(const unsigned char *p, u64 *v){ u32 a,b,s; if( ((signed char*)p)[0]>=0 ){ *v = *p; return 1; } if( ((signed char*)p)[1]>=0 ){ *v = ((u32)(p[0]&0x7f)<<7) | p[1]; return 2; } /* Verify that constants are precomputed correctly */ assert( SLOT_2_0 == ((0x7f<<14) | (0x7f)) ); assert( SLOT_4_2_0 == ((0xfU<<28) | (0x7f<<14) | (0x7f)) ); a = ((u32)p[0])<<14; b = p[1]; p += 2; a |= *p; /* a: p0<<14 | p2 (unmasked) */ if (!(a&0x80)) { a &= SLOT_2_0; b &= 0x7f; b = b<<7; |
︙ | ︙ | |||
1108 1109 1110 1111 1112 1113 1114 | ** routine. */ #if 1 { u64 v64; u8 n; | < | | 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 | ** routine. */ #if 1 { u64 v64; u8 n; n = sqlite3GetVarint(p-2, &v64); assert( n>3 && n<=9 ); if( (v64 & SQLITE_MAX_U32)!=v64 ){ *v = 0xffffffff; }else{ *v = (u32)v64; } return n; |
︙ | ︙ | |||
1236 1237 1238 1239 1240 1241 1242 | #endif #ifdef SQLITE_EBCDIC h += 9*(1&~(h>>4)); #endif return (u8)(h & 0xf); } | | | | 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 | #endif #ifdef SQLITE_EBCDIC h += 9*(1&~(h>>4)); #endif return (u8)(h & 0xf); } #if !defined(SQLITE_OMIT_BLOB_LITERAL) /* ** Convert a BLOB literal of the form "x'hhhhhh'" into its binary ** value. Return a pointer to its binary value. Space to hold the ** binary value has been obtained from malloc and must be freed by ** the calling routine. */ void *sqlite3HexToBlob(sqlite3 *db, const char *z, int n){ char *zBlob; int i; zBlob = (char *)sqlite3DbMallocRawNN(db, n/2 + 1); n--; if( zBlob ){ for(i=0; i<n; i+=2){ zBlob[i/2] = (sqlite3HexToInt(z[i])<<4) | sqlite3HexToInt(z[i+1]); } zBlob[i/2] = 0; } return zBlob; } #endif /* !SQLITE_OMIT_BLOB_LITERAL */ /* ** Log an error that is an API call on a connection pointer that should ** not have been used. The "type" of connection pointer is given as the ** argument. The zType is a word like "NULL" or "closed" or "invalid". */ static void logBadConnection(const char *zType){ |
︙ | ︙ | |||
1286 1287 1288 1289 1290 1291 1292 | ** ** sqlite3SafetyCheckOk() requires that the db pointer be valid for ** use. sqlite3SafetyCheckSickOrOk() allows a db pointer that failed to ** open properly and is not fit for general use but which can be ** used as an argument to sqlite3_errmsg() or sqlite3_close(). */ int sqlite3SafetyCheckOk(sqlite3 *db){ | | | | | | | | | | 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 | ** ** sqlite3SafetyCheckOk() requires that the db pointer be valid for ** use. sqlite3SafetyCheckSickOrOk() allows a db pointer that failed to ** open properly and is not fit for general use but which can be ** used as an argument to sqlite3_errmsg() or sqlite3_close(). */ int sqlite3SafetyCheckOk(sqlite3 *db){ u8 eOpenState; if( db==0 ){ logBadConnection("NULL"); return 0; } eOpenState = db->eOpenState; if( eOpenState!=SQLITE_STATE_OPEN ){ if( sqlite3SafetyCheckSickOrOk(db) ){ testcase( sqlite3GlobalConfig.xLog!=0 ); logBadConnection("unopened"); } return 0; }else{ return 1; } } int sqlite3SafetyCheckSickOrOk(sqlite3 *db){ u8 eOpenState; eOpenState = db->eOpenState; if( eOpenState!=SQLITE_STATE_SICK && eOpenState!=SQLITE_STATE_OPEN && eOpenState!=SQLITE_STATE_BUSY ){ testcase( sqlite3GlobalConfig.xLog!=0 ); logBadConnection("invalid"); return 0; }else{ return 1; } } |
︙ | ︙ | |||
1490 1491 1492 1493 1494 1495 1496 | memcpy(&a, &x, 8); e = (a>>52) - 1022; return e*10; } #endif /* SQLITE_OMIT_VIRTUALTABLE */ #if defined(SQLITE_ENABLE_STMT_SCANSTATUS) || \ | | | | 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 | memcpy(&a, &x, 8); e = (a>>52) - 1022; return e*10; } #endif /* SQLITE_OMIT_VIRTUALTABLE */ #if defined(SQLITE_ENABLE_STMT_SCANSTATUS) || \ defined(SQLITE_ENABLE_STAT4) || \ defined(SQLITE_EXPLAIN_ESTIMATED_ROWS) /* ** Convert a LogEst into an integer. ** ** Note that this routine is only used when one or more of various ** non-standard compile-time options is enabled. */ u64 sqlite3LogEstToInt(LogEst x){ u64 n; n = x%10; x /= 10; if( n>=5 ) n -= 2; else if( n>=1 ) n -= 1; #if defined(SQLITE_ENABLE_STMT_SCANSTATUS) || \ defined(SQLITE_EXPLAIN_ESTIMATED_ROWS) if( x>60 ) return (u64)LARGEST_INT64; #else /* If only SQLITE_ENABLE_STAT4 is on, then the largest input ** possible to this routine is 310, resulting in a maximum x of 31 */ assert( x<=60 ); #endif return x>=3 ? (n+8)<<(x-3) : (n+8)>>(3-x); } #endif /* defined SCANSTAT or STAT4 or ESTIMATED_ROWS */ |
︙ | ︙ | |||
1567 1568 1569 1570 1571 1572 1573 | char *z; /* Pointer to where zName will be stored */ int i; /* Index in pIn[] where zName is stored */ nInt = nName/4 + 3; assert( pIn==0 || pIn[0]>=3 ); /* Verify ok to add new elements */ if( pIn==0 || pIn[1]+nInt > pIn[0] ){ /* Enlarge the allocation */ | | | 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 | char *z; /* Pointer to where zName will be stored */ int i; /* Index in pIn[] where zName is stored */ nInt = nName/4 + 3; assert( pIn==0 || pIn[0]>=3 ); /* Verify ok to add new elements */ if( pIn==0 || pIn[1]+nInt > pIn[0] ){ /* Enlarge the allocation */ sqlite3_int64 nAlloc = (pIn ? 2*(sqlite3_int64)pIn[0] : 10) + nInt; VList *pOut = sqlite3DbRealloc(db, pIn, nAlloc*sizeof(int)); if( pOut==0 ) return pIn; if( pIn==0 ) pOut[1] = 2; pIn = pOut; pIn[0] = nAlloc; } i = pIn[1]; |
︙ | ︙ |
Changes to src/vacuum.c.
︙ | ︙ | |||
37 38 39 40 41 42 43 | rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0); if( rc!=SQLITE_OK ) return rc; while( SQLITE_ROW==(rc = sqlite3_step(pStmt)) ){ const char *zSubSql = (const char*)sqlite3_column_text(pStmt,0); assert( sqlite3_strnicmp(zSql,"SELECT",6)==0 ); /* The secondary SQL must be one of CREATE TABLE, CREATE INDEX, ** or INSERT. Historically there have been attacks that first | | | 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0); if( rc!=SQLITE_OK ) return rc; while( SQLITE_ROW==(rc = sqlite3_step(pStmt)) ){ const char *zSubSql = (const char*)sqlite3_column_text(pStmt,0); assert( sqlite3_strnicmp(zSql,"SELECT",6)==0 ); /* The secondary SQL must be one of CREATE TABLE, CREATE INDEX, ** or INSERT. Historically there have been attacks that first ** corrupt the sqlite_schema.sql field with other kinds of statements ** then run VACUUM to get those statements to execute at inappropriate ** times. */ if( zSubSql && (strncmp(zSubSql,"CRE",3)==0 || strncmp(zSubSql,"INS",3)==0) ){ rc = execSql(db, pzErrMsg, zSubSql); if( rc!=SQLITE_OK ) break; |
︙ | ︙ | |||
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 | ** transient would cause the database file to appear to be deleted ** following reboot. */ void sqlite3Vacuum(Parse *pParse, Token *pNm, Expr *pInto){ Vdbe *v = sqlite3GetVdbe(pParse); int iDb = 0; if( v==0 ) goto build_vacuum_end; if( pNm ){ #ifndef SQLITE_BUG_COMPATIBLE_20160819 /* Default behavior: Report an error if the argument to VACUUM is ** not recognized */ iDb = sqlite3TwoPartName(pParse, pNm, pNm, &pNm); if( iDb<0 ) goto build_vacuum_end; #else /* When SQLITE_BUG_COMPATIBLE_20160819 is defined, unrecognized arguments ** to VACUUM are silently ignored. This is a back-out of a bug fix that ** occurred on 2016-08-19 (https://www.sqlite.org/src/info/083f9e6270). ** The buggy behavior is required for binary compatibility with some ** legacy applications. */ iDb = sqlite3FindDb(pParse->db, pNm); if( iDb<0 ) iDb = 0; #endif } if( iDb!=1 ){ int iIntoReg = 0; | > | | | | | > | | > > > | 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 | ** transient would cause the database file to appear to be deleted ** following reboot. */ void sqlite3Vacuum(Parse *pParse, Token *pNm, Expr *pInto){ Vdbe *v = sqlite3GetVdbe(pParse); int iDb = 0; if( v==0 ) goto build_vacuum_end; if( pParse->nErr ) goto build_vacuum_end; if( pNm ){ #ifndef SQLITE_BUG_COMPATIBLE_20160819 /* Default behavior: Report an error if the argument to VACUUM is ** not recognized */ iDb = sqlite3TwoPartName(pParse, pNm, pNm, &pNm); if( iDb<0 ) goto build_vacuum_end; #else /* When SQLITE_BUG_COMPATIBLE_20160819 is defined, unrecognized arguments ** to VACUUM are silently ignored. This is a back-out of a bug fix that ** occurred on 2016-08-19 (https://www.sqlite.org/src/info/083f9e6270). ** The buggy behavior is required for binary compatibility with some ** legacy applications. */ iDb = sqlite3FindDb(pParse->db, pNm); if( iDb<0 ) iDb = 0; #endif } if( iDb!=1 ){ int iIntoReg = 0; if( pInto && sqlite3ResolveSelfReference(pParse,0,0,pInto,0)==0 ){ iIntoReg = ++pParse->nMem; sqlite3ExprCode(pParse, pInto, iIntoReg); } sqlite3VdbeAddOp2(v, OP_Vacuum, iDb, iIntoReg); sqlite3VdbeUsesBtree(v, iDb); } build_vacuum_end: sqlite3ExprDelete(pParse->db, pInto); return; } /* ** This routine implements the OP_Vacuum opcode of the VDBE. */ SQLITE_NOINLINE int sqlite3RunVacuum( char **pzErrMsg, /* Write error message here */ sqlite3 *db, /* Database connection */ int iDb, /* Which attached DB to vacuum */ sqlite3_value *pOut /* Write results here, if not NULL. VACUUM INTO */ ){ int rc = SQLITE_OK; /* Return code from service routines */ Btree *pMain; /* The database being vacuumed */ Btree *pTemp; /* The temporary database we vacuum into */ u32 saved_mDbFlags; /* Saved value of db->mDbFlags */ u64 saved_flags; /* Saved value of db->flags */ i64 saved_nChange; /* Saved value of db->nChange */ i64 saved_nTotalChange; /* Saved value of db->nTotalChange */ u32 saved_openFlags; /* Saved value of db->openFlags */ u8 saved_mTrace; /* Saved trace settings */ Db *pDb = 0; /* Database to detach at end of vacuum */ int isMemDb; /* True if vacuuming a :memory: database */ int nRes; /* Bytes of reserved space at the end of each page */ int nDb; /* Number of attached databases */ const char *zDbMain; /* Schema name of database to vacuum */ const char *zOut; /* Name of output file */ if( !db->autoCommit ){ sqlite3SetString(pzErrMsg, db, "cannot VACUUM from within a transaction"); return SQLITE_ERROR; /* IMP: R-12218-18073 */ } if( db->nVdbeActive>1 ){ sqlite3SetString(pzErrMsg, db,"cannot VACUUM - SQL statements in progress"); return SQLITE_ERROR; /* IMP: R-15610-35227 */ } saved_openFlags = db->openFlags; if( pOut ){ if( sqlite3_value_type(pOut)!=SQLITE_TEXT ){ sqlite3SetString(pzErrMsg, db, "non-text filename"); return SQLITE_ERROR; } zOut = (const char*)sqlite3_value_text(pOut); db->openFlags &= ~SQLITE_OPEN_READONLY; db->openFlags |= SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE; }else{ zOut = ""; } /* Save the current value of the database flags so that it can be ** restored before returning. Then set the writable-schema flag, and ** disable CHECK and foreign key constraints. */ |
︙ | ︙ | |||
208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 | ** actually occurs when doing a vacuum since the vacuum_db is initially ** empty. Only the journal header is written. Apparently it takes more ** time to parse and run the PRAGMA to turn journalling off than it does ** to write the journal header file. */ nDb = db->nDb; rc = execSqlF(db, pzErrMsg, "ATTACH %Q AS vacuum_db", zOut); if( rc!=SQLITE_OK ) goto end_of_vacuum; assert( (db->nDb-1)==nDb ); pDb = &db->aDb[nDb]; assert( strcmp(pDb->zDbSName,"vacuum_db")==0 ); pTemp = pDb->pBt; if( pOut ){ sqlite3_file *id = sqlite3PagerFile(sqlite3BtreePager(pTemp)); i64 sz = 0; if( id->pMethods!=0 && (sqlite3OsFileSize(id, &sz)!=SQLITE_OK || sz>0) ){ rc = SQLITE_ERROR; sqlite3SetString(pzErrMsg, db, "output file already exists"); goto end_of_vacuum; } } | > > | < < < < < < < < < < < | > > | 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 | ** actually occurs when doing a vacuum since the vacuum_db is initially ** empty. Only the journal header is written. Apparently it takes more ** time to parse and run the PRAGMA to turn journalling off than it does ** to write the journal header file. */ nDb = db->nDb; rc = execSqlF(db, pzErrMsg, "ATTACH %Q AS vacuum_db", zOut); db->openFlags = saved_openFlags; if( rc!=SQLITE_OK ) goto end_of_vacuum; assert( (db->nDb-1)==nDb ); pDb = &db->aDb[nDb]; assert( strcmp(pDb->zDbSName,"vacuum_db")==0 ); pTemp = pDb->pBt; if( pOut ){ sqlite3_file *id = sqlite3PagerFile(sqlite3BtreePager(pTemp)); i64 sz = 0; if( id->pMethods!=0 && (sqlite3OsFileSize(id, &sz)!=SQLITE_OK || sz>0) ){ rc = SQLITE_ERROR; sqlite3SetString(pzErrMsg, db, "output file already exists"); goto end_of_vacuum; } db->mDbFlags |= DBFLAG_VacuumInto; } nRes = sqlite3BtreeGetRequestedReserve(pMain); sqlite3BtreeSetCacheSize(pTemp, db->aDb[iDb].pSchema->cache_size); sqlite3BtreeSetSpillSize(pTemp, sqlite3BtreeSetSpillSize(pMain,0)); sqlite3BtreeSetPagerFlags(pTemp, PAGER_SYNCHRONOUS_OFF|PAGER_CACHESPILL); /* Begin a transaction and take an exclusive lock on the main database ** file. This is done before the sqlite3BtreeGetPageSize(pMain) call below, ** to ensure that we do not try to change the page-size on a WAL database. */ rc = execSql(db, pzErrMsg, "BEGIN"); if( rc!=SQLITE_OK ) goto end_of_vacuum; rc = sqlite3BtreeBeginTrans(pMain, pOut==0 ? 2 : 0, 0); if( rc!=SQLITE_OK ) goto end_of_vacuum; /* Do not attempt to change the page size for a WAL database */ if( sqlite3PagerGetJournalMode(sqlite3BtreePager(pMain)) ==PAGER_JOURNALMODE_WAL && pOut==0 ){ db->nextPagesize = 0; } if( sqlite3BtreeSetPageSize(pTemp, sqlite3BtreeGetPageSize(pMain), nRes, 0) || (!isMemDb && sqlite3BtreeSetPageSize(pTemp, db->nextPagesize, nRes, 0)) || NEVER(db->mallocFailed) ){ |
︙ | ︙ | |||
272 273 274 275 276 277 278 | #endif /* Query the schema of the main database. Create a mirror schema ** in the temporary database. */ db->init.iDb = nDb; /* force new CREATE statements into vacuum_db */ rc = execSqlF(db, pzErrMsg, | | | | | | | | 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 | #endif /* Query the schema of the main database. Create a mirror schema ** in the temporary database. */ db->init.iDb = nDb; /* force new CREATE statements into vacuum_db */ rc = execSqlF(db, pzErrMsg, "SELECT sql FROM \"%w\".sqlite_schema" " WHERE type='table'AND name<>'sqlite_sequence'" " AND coalesce(rootpage,1)>0", zDbMain ); if( rc!=SQLITE_OK ) goto end_of_vacuum; rc = execSqlF(db, pzErrMsg, "SELECT sql FROM \"%w\".sqlite_schema" " WHERE type='index'", zDbMain ); if( rc!=SQLITE_OK ) goto end_of_vacuum; db->init.iDb = 0; /* Loop through the tables in the main database. For each, do ** an "INSERT INTO vacuum_db.xxx SELECT * FROM main.xxx;" to copy ** the contents to the temporary database. */ rc = execSqlF(db, pzErrMsg, "SELECT'INSERT INTO vacuum_db.'||quote(name)" "||' SELECT*FROM\"%w\".'||quote(name)" "FROM vacuum_db.sqlite_schema " "WHERE type='table'AND coalesce(rootpage,1)>0", zDbMain ); assert( (db->mDbFlags & DBFLAG_Vacuum)!=0 ); db->mDbFlags &= ~DBFLAG_Vacuum; if( rc!=SQLITE_OK ) goto end_of_vacuum; /* Copy the triggers, views, and virtual tables from the main database ** over to the temporary database. None of these objects has any ** associated storage, so all we have to do is copy their entries ** from the schema table. */ rc = execSqlF(db, pzErrMsg, "INSERT INTO vacuum_db.sqlite_schema" " SELECT*FROM \"%w\".sqlite_schema" " WHERE type IN('view','trigger')" " OR(type='table'AND rootpage=0)", zDbMain ); if( rc ) goto end_of_vacuum; /* At this point, there is a write transaction open on both the |
︙ | ︙ | |||
339 340 341 342 343 344 345 | 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 */ }; | | | | 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 | 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( SQLITE_TXN_WRITE==sqlite3BtreeTxnState(pTemp) ); assert( pOut!=0 || SQLITE_TXN_WRITE==sqlite3BtreeTxnState(pMain) ); /* Copy Btree meta values */ for(i=0; i<ArraySize(aCopy); i+=2){ /* GetMeta() and UpdateMeta() cannot fail in this context because ** we already have page 1 loaded into cache and marked dirty. */ sqlite3BtreeGetMeta(pMain, aCopy[i], &meta); rc = sqlite3BtreeUpdateMeta(pTemp, aCopy[i], meta+aCopy[i+1]); |
︙ | ︙ | |||
377 378 379 380 381 382 383 | /* Restore the original value of db->flags */ db->init.iDb = 0; db->mDbFlags = saved_mDbFlags; db->flags = saved_flags; db->nChange = saved_nChange; db->nTotalChange = saved_nTotalChange; db->mTrace = saved_mTrace; | | | | 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 | /* Restore the original value of db->flags */ db->init.iDb = 0; db->mDbFlags = saved_mDbFlags; db->flags = saved_flags; db->nChange = saved_nChange; db->nTotalChange = saved_nTotalChange; db->mTrace = saved_mTrace; sqlite3BtreeSetPageSize(pMain, -1, 0, 1); /* Currently there is an SQL level transaction open on the vacuum ** database. No locks are held on any other files (since the main file ** was committed at the btree level). So it safe to end the transaction ** by manually setting the autoCommit flag to true and detaching the ** vacuum database. The vacuum_db journal file is deleted when the pager ** is closed by the DETACH. */ db->autoCommit = 1; assert( db->eConcurrent==0 ); if( pDb ){ sqlite3BtreeClose(pDb->pBt); pDb->pBt = 0; pDb->pSchema = 0; } |
︙ | ︙ |
Changes to src/vdbe.c.
︙ | ︙ | |||
113 114 115 116 117 118 119 120 121 122 123 124 | */ #if defined(SQLITE_TEST) && !defined(SQLITE_UNTESTABLE) # define UPDATE_MAX_BLOBSIZE(P) updateMaxBlobsize(P) #else # define UPDATE_MAX_BLOBSIZE(P) #endif /* ** Invoke the VDBE coverage callback, if that callback is defined. This ** feature is used for test suite validation only and does not appear an ** production builds. ** | > > > > > > > > > > > > > > > > > > > > | | > | > > > > > > > > | | < | | | 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 | */ #if defined(SQLITE_TEST) && !defined(SQLITE_UNTESTABLE) # define UPDATE_MAX_BLOBSIZE(P) updateMaxBlobsize(P) #else # define UPDATE_MAX_BLOBSIZE(P) #endif #ifdef SQLITE_DEBUG /* This routine provides a convenient place to set a breakpoint during ** tracing with PRAGMA vdbe_trace=on. The breakpoint fires right after ** each opcode is printed. Variables "pc" (program counter) and pOp are ** available to add conditionals to the breakpoint. GDB example: ** ** break test_trace_breakpoint if pc=22 ** ** Other useful labels for breakpoints include: ** test_addop_breakpoint(pc,pOp) ** sqlite3CorruptError(lineno) ** sqlite3MisuseError(lineno) ** sqlite3CantopenError(lineno) */ static void test_trace_breakpoint(int pc, Op *pOp, Vdbe *v){ static int n = 0; n++; } #endif /* ** Invoke the VDBE coverage callback, if that callback is defined. This ** feature is used for test suite validation only and does not appear an ** production builds. ** ** M is the type of branch. I is the direction taken for this instance of ** the branch. ** ** M: 2 - two-way branch (I=0: fall-thru 1: jump ) ** 3 - two-way + NULL (I=0: fall-thru 1: jump 2: NULL ) ** 4 - OP_Jump (I=0: jump p1 1: jump p2 2: jump p3) ** ** In other words, if M is 2, then I is either 0 (for fall-through) or ** 1 (for when the branch is taken). If M is 3, the I is 0 for an ** ordinary fall-through, I is 1 if the branch was taken, and I is 2 ** if the result of comparison is NULL. For M=3, I=2 the jump may or ** may not be taken, depending on the SQLITE_JUMPIFNULL flags in p5. ** When M is 4, that means that an OP_Jump is being run. I is 0, 1, or 2 ** depending on if the operands are less than, equal, or greater than. ** ** iSrcLine is the source code line (from the __LINE__ macro) that ** generated the VDBE instruction combined with flag bits. The source ** code line number is in the lower 24 bits of iSrcLine and the upper ** 8 bytes are flags. The lower three bits of the flags indicate ** values for I that should never occur. For example, if the branch is ** always taken, the flags should be 0x05 since the fall-through and ** alternate branch are never taken. If a branch is never taken then ** flags should be 0x06 since only the fall-through approach is allowed. ** ** Bit 0x08 of the flags indicates an OP_Jump opcode that is only ** interested in equal or not-equal. In other words, I==0 and I==2 ** should be treated as equivalent ** ** Since only a line number is retained, not the filename, this macro ** only works for amalgamation builds. But that is ok, since these macros ** should be no-ops except for special builds used to measure test coverage. */ #if !defined(SQLITE_VDBE_COVERAGE) # define VdbeBranchTaken(I,M) |
︙ | ︙ | |||
160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 | /* The upper 8 bits of iSrcLine are flags. The lower three bits of ** the flags indicate directions that the branch can never go. If ** a branch really does go in one of those directions, assert right ** away. */ mNever = iSrcLine >> 24; assert( (I & mNever)==0 ); if( sqlite3GlobalConfig.xVdbeBranch==0 ) return; /*NO_TEST*/ I |= mNever; if( M==2 ) I |= 0x04; if( M==4 ){ I |= 0x08; if( (mNever&0x08)!=0 && (I&0x05)!=0) I |= 0x05; /*NO_TEST*/ } sqlite3GlobalConfig.xVdbeBranch(sqlite3GlobalConfig.pVdbeBranchArg, iSrcLine&0xffffff, I, M); } #endif | > > > > > > > > > > > > < < < < < < < < | 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 | /* The upper 8 bits of iSrcLine are flags. The lower three bits of ** the flags indicate directions that the branch can never go. If ** a branch really does go in one of those directions, assert right ** away. */ mNever = iSrcLine >> 24; assert( (I & mNever)==0 ); if( sqlite3GlobalConfig.xVdbeBranch==0 ) return; /*NO_TEST*/ /* Invoke the branch coverage callback with three arguments: ** iSrcLine - the line number of the VdbeCoverage() macro, with ** flags removed. ** I - Mask of bits 0x07 indicating which cases are are ** fulfilled by this instance of the jump. 0x01 means ** fall-thru, 0x02 means taken, 0x04 means NULL. Any ** impossible cases (ex: if the comparison is never NULL) ** are filled in automatically so that the coverage ** measurement logic does not flag those impossible cases ** as missed coverage. ** M - Type of jump. Same as M argument above */ I |= mNever; if( M==2 ) I |= 0x04; if( M==4 ){ I |= 0x08; if( (mNever&0x08)!=0 && (I&0x05)!=0) I |= 0x05; /*NO_TEST*/ } sqlite3GlobalConfig.xVdbeBranch(sqlite3GlobalConfig.pVdbeBranchArg, iSrcLine&0xffffff, I, M); } #endif /* ** An ephemeral string value (signified by the MEM_Ephem flag) contains ** a pointer to a dynamically allocated string where some other entity ** is responsible for deallocating that string. Because the register ** does not control the string, it might be deleted without the register ** knowing it. ** |
︙ | ︙ | |||
239 240 241 242 243 244 245 | (eCurType==CURTYPE_BTREE?sqlite3BtreeCursorSize():0); assert( iCur>=0 && iCur<p->nCursor ); if( p->apCsr[iCur] ){ /*OPTIMIZATION-IF-FALSE*/ sqlite3VdbeFreeCursor(p, p->apCsr[iCur]); p->apCsr[iCur] = 0; } | > | > > > > > > > > > > > > > > > > > > | | | | | | | | | | | > | > > > > > > > > > > > | | > > < > | | | | | 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 | (eCurType==CURTYPE_BTREE?sqlite3BtreeCursorSize():0); assert( iCur>=0 && iCur<p->nCursor ); if( p->apCsr[iCur] ){ /*OPTIMIZATION-IF-FALSE*/ sqlite3VdbeFreeCursor(p, p->apCsr[iCur]); p->apCsr[iCur] = 0; } /* There used to be a call to sqlite3VdbeMemClearAndResize() to make sure ** the pMem used to hold space for the cursor has enough storage available ** in pMem->zMalloc. But for the special case of the aMem[] entries used ** to hold cursors, it is faster to in-line the logic. */ assert( pMem->flags==MEM_Undefined ); assert( (pMem->flags & MEM_Dyn)==0 ); assert( pMem->szMalloc==0 || pMem->z==pMem->zMalloc ); if( pMem->szMalloc<nByte ){ if( pMem->szMalloc>0 ){ sqlite3DbFreeNN(pMem->db, pMem->zMalloc); } pMem->z = pMem->zMalloc = sqlite3DbMallocRaw(pMem->db, nByte); if( pMem->zMalloc==0 ){ pMem->szMalloc = 0; return 0; } pMem->szMalloc = nByte; } p->apCsr[iCur] = pCx = (VdbeCursor*)pMem->zMalloc; memset(pCx, 0, offsetof(VdbeCursor,pAltCursor)); pCx->eCurType = eCurType; pCx->iDb = iDb; pCx->nField = nField; pCx->aOffset = &pCx->aType[nField]; if( eCurType==CURTYPE_BTREE ){ pCx->uc.pCursor = (BtCursor*) &pMem->z[ROUND8(sizeof(VdbeCursor))+2*sizeof(u32)*nField]; sqlite3BtreeCursorZero(pCx->uc.pCursor); } return pCx; } /* ** The string in pRec is known to look like an integer and to have a ** floating point value of rValue. Return true and set *piValue to the ** integer value if the string is in range to be an integer. Otherwise, ** return false. */ static int alsoAnInt(Mem *pRec, double rValue, i64 *piValue){ i64 iValue = (double)rValue; if( sqlite3RealSameAsInt(rValue,iValue) ){ *piValue = iValue; return 1; } return 0==sqlite3Atoi64(pRec->z, piValue, pRec->n, pRec->enc); } /* ** Try to convert a value into a numeric representation if we can ** do so without loss of information. In other words, if the string ** looks like a number, convert it into a number. If it does not ** look like a number, leave it alone. ** ** If the bTryForInt flag is true, then extra effort is made to give ** an integer representation. Strings that look like floating point ** values but which have no fractional component (example: '48.00') ** will have a MEM_Int representation when bTryForInt is true. ** ** If bTryForInt is false, then if the input string contains a decimal ** point or exponential notation, the result is only MEM_Real, even ** if there is an exact integer representation of the quantity. */ static void applyNumericAffinity(Mem *pRec, int bTryForInt){ double rValue; u8 enc = pRec->enc; int rc; assert( (pRec->flags & (MEM_Str|MEM_Int|MEM_Real|MEM_IntReal))==MEM_Str ); rc = sqlite3AtoF(pRec->z, &rValue, pRec->n, enc); if( rc<=0 ) return; if( rc==1 && alsoAnInt(pRec, rValue, &pRec->u.i) ){ pRec->flags |= MEM_Int; }else{ pRec->u.r = rValue; pRec->flags |= MEM_Real; if( bTryForInt ) sqlite3VdbeIntegerAffinity(pRec); } /* TEXT->NUMERIC is many->one. Hence, it is important to invalidate the |
︙ | ︙ | |||
307 308 309 310 311 312 313 314 315 316 317 318 319 320 | ** always preferred, even if the affinity is REAL, because ** an integer representation is more space efficient on disk. ** ** SQLITE_AFF_TEXT: ** Convert pRec to a text representation. ** ** SQLITE_AFF_BLOB: ** No-op. pRec is unchanged. */ static void applyAffinity( Mem *pRec, /* The value to apply affinity to */ char affinity, /* The affinity to be applied */ u8 enc /* Use this text encoding */ ){ | > | 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 | ** always preferred, even if the affinity is REAL, because ** an integer representation is more space efficient on disk. ** ** SQLITE_AFF_TEXT: ** Convert pRec to a text representation. ** ** SQLITE_AFF_BLOB: ** SQLITE_AFF_NONE: ** No-op. pRec is unchanged. */ static void applyAffinity( Mem *pRec, /* The value to apply affinity to */ char affinity, /* The affinity to be applied */ u8 enc /* Use this text encoding */ ){ |
︙ | ︙ | |||
331 332 333 334 335 336 337 | }else if( affinity==SQLITE_AFF_TEXT ){ /* Only attempt the conversion to TEXT if there is an integer or real ** representation (blob and NULL do not get converted) but no string ** representation. It would be harmless to repeat the conversion if ** there is already a string rep, but it is pointless to waste those ** CPU cycles. */ if( 0==(pRec->flags&MEM_Str) ){ /*OPTIMIZATION-IF-FALSE*/ | | > > > | | 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 | }else if( affinity==SQLITE_AFF_TEXT ){ /* Only attempt the conversion to TEXT if there is an integer or real ** representation (blob and NULL do not get converted) but no string ** representation. It would be harmless to repeat the conversion if ** there is already a string rep, but it is pointless to waste those ** CPU cycles. */ if( 0==(pRec->flags&MEM_Str) ){ /*OPTIMIZATION-IF-FALSE*/ if( (pRec->flags&(MEM_Real|MEM_Int|MEM_IntReal)) ){ testcase( pRec->flags & MEM_Int ); testcase( pRec->flags & MEM_Real ); testcase( pRec->flags & MEM_IntReal ); sqlite3VdbeMemStringify(pRec, enc, 1); } } pRec->flags &= ~(MEM_Real|MEM_Int|MEM_IntReal); } } /* ** Try to convert the type of a function argument or a result column ** into a numeric representation. Use either INTEGER or REAL whichever ** is appropriate. But only do the conversion if it is possible without |
︙ | ︙ | |||
374 375 376 377 378 379 380 | /* ** pMem currently only holds a string type (or maybe a BLOB that we can ** interpret as a string if we want to). Compute its corresponding ** numeric type, if has one. Set the pMem->u.r and pMem->u.i fields ** accordingly. */ static u16 SQLITE_NOINLINE computeNumericType(Mem *pMem){ | > > | > > > > | > > > | > > | | > | > > > | > > | < < < < | < | | < > | < < > < > | < < | | | | | | < | < < | | | < < < | < < | < < > > | > | > | | | > > > > > > > > > > > > > > > > > > > > | 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 | /* ** pMem currently only holds a string type (or maybe a BLOB that we can ** interpret as a string if we want to). Compute its corresponding ** numeric type, if has one. Set the pMem->u.r and pMem->u.i fields ** accordingly. */ static u16 SQLITE_NOINLINE computeNumericType(Mem *pMem){ int rc; sqlite3_int64 ix; assert( (pMem->flags & (MEM_Int|MEM_Real|MEM_IntReal))==0 ); assert( (pMem->flags & (MEM_Str|MEM_Blob))!=0 ); if( ExpandBlob(pMem) ){ pMem->u.i = 0; return MEM_Int; } rc = sqlite3AtoF(pMem->z, &pMem->u.r, pMem->n, pMem->enc); if( rc<=0 ){ if( rc==0 && sqlite3Atoi64(pMem->z, &ix, pMem->n, pMem->enc)<=1 ){ pMem->u.i = ix; return MEM_Int; }else{ return MEM_Real; } }else if( rc==1 && sqlite3Atoi64(pMem->z, &ix, pMem->n, pMem->enc)==0 ){ pMem->u.i = ix; return MEM_Int; } return MEM_Real; } /* ** Return the numeric type for pMem, either MEM_Int or MEM_Real or both or ** none. ** ** Unlike applyNumericAffinity(), this routine does not modify pMem->flags. ** But it does set pMem->u.r and pMem->u.i appropriately. */ static u16 numericType(Mem *pMem){ if( pMem->flags & (MEM_Int|MEM_Real|MEM_IntReal) ){ testcase( pMem->flags & MEM_Int ); testcase( pMem->flags & MEM_Real ); testcase( pMem->flags & MEM_IntReal ); return pMem->flags & (MEM_Int|MEM_Real|MEM_IntReal); } if( pMem->flags & (MEM_Str|MEM_Blob) ){ testcase( pMem->flags & MEM_Str ); testcase( pMem->flags & MEM_Blob ); return computeNumericType(pMem); } return 0; } #ifdef SQLITE_DEBUG /* ** Write a nice string representation of the contents of cell pMem ** into buffer zBuf, length nBuf. */ void sqlite3VdbeMemPrettyPrint(Mem *pMem, StrAccum *pStr){ int f = pMem->flags; static const char *const encnames[] = {"(X)", "(8)", "(16LE)", "(16BE)"}; if( f&MEM_Blob ){ int i; char c; if( f & MEM_Dyn ){ c = 'z'; assert( (f & (MEM_Static|MEM_Ephem))==0 ); }else if( f & MEM_Static ){ c = 't'; assert( (f & (MEM_Dyn|MEM_Ephem))==0 ); }else if( f & MEM_Ephem ){ c = 'e'; assert( (f & (MEM_Static|MEM_Dyn))==0 ); }else{ c = 's'; } sqlite3_str_appendf(pStr, "%cx[", c); for(i=0; i<25 && i<pMem->n; i++){ sqlite3_str_appendf(pStr, "%02X", ((int)pMem->z[i] & 0xFF)); } sqlite3_str_appendf(pStr, "|"); for(i=0; i<25 && i<pMem->n; i++){ char z = pMem->z[i]; sqlite3_str_appendchar(pStr, 1, (z<32||z>126)?'.':z); } sqlite3_str_appendf(pStr,"]"); if( f & MEM_Zero ){ sqlite3_str_appendf(pStr, "+%dz",pMem->u.nZero); } }else if( f & MEM_Str ){ int j; u8 c; if( f & MEM_Dyn ){ c = 'z'; assert( (f & (MEM_Static|MEM_Ephem))==0 ); }else if( f & MEM_Static ){ c = 't'; assert( (f & (MEM_Dyn|MEM_Ephem))==0 ); }else if( f & MEM_Ephem ){ c = 'e'; assert( (f & (MEM_Static|MEM_Dyn))==0 ); }else{ c = 's'; } sqlite3_str_appendf(pStr, " %c%d[", c, pMem->n); for(j=0; j<25 && j<pMem->n; j++){ c = pMem->z[j]; sqlite3_str_appendchar(pStr, 1, (c>=0x20&&c<=0x7f) ? c : '.'); } sqlite3_str_appendf(pStr, "]%s", encnames[pMem->enc]); } } #endif #ifdef SQLITE_DEBUG /* ** Print the value of a register for tracing purposes: */ static void memTracePrint(Mem *p){ if( p->flags & MEM_Undefined ){ printf(" undefined"); }else if( p->flags & MEM_Null ){ printf(p->flags & MEM_Zero ? " NULL-nochng" : " NULL"); }else if( (p->flags & (MEM_Int|MEM_Str))==(MEM_Int|MEM_Str) ){ printf(" si:%lld", p->u.i); }else if( (p->flags & (MEM_IntReal))!=0 ){ printf(" ir:%lld", p->u.i); }else if( p->flags & MEM_Int ){ printf(" i:%lld", p->u.i); #ifndef SQLITE_OMIT_FLOATING_POINT }else if( p->flags & MEM_Real ){ printf(" r:%.17g", p->u.r); #endif }else if( sqlite3VdbeMemIsRowSet(p) ){ printf(" (rowset)"); }else{ StrAccum acc; char zBuf[1000]; sqlite3StrAccumInit(&acc, 0, zBuf, sizeof(zBuf), 0); sqlite3VdbeMemPrettyPrint(p, &acc); printf(" %s", sqlite3StrAccumFinish(&acc)); } if( p->flags & MEM_Subtype ) printf(" subtype=0x%02x", p->eSubtype); } static void registerTrace(int iReg, Mem *p){ printf("R[%d] = ", iReg); memTracePrint(p); if( p->pScopyFrom ){ printf(" <== R[%d]", (int)(p->pScopyFrom - &p[-iReg])); } printf("\n"); sqlite3VdbeCheckMemInvariants(p); } /**/ void sqlite3PrintMem(Mem *pMem){ memTracePrint(pMem); printf("\n"); fflush(stdout); } #endif #ifdef SQLITE_DEBUG /* ** Show the values of all registers in the virtual machine. Used for ** interactive debugging. */ void sqlite3VdbeRegisterDump(Vdbe *v){ int i; for(i=1; i<v->nMem; i++) registerTrace(i, v->aMem+i); } #endif /* SQLITE_DEBUG */ #ifdef SQLITE_DEBUG # define REGISTER_TRACE(R,M) if(db->flags&SQLITE_VdbeTrace)registerTrace(R,M) #else # define REGISTER_TRACE(R,M) #endif |
︙ | ︙ | |||
575 576 577 578 579 580 581 582 583 584 585 586 587 588 | return out2PrereleaseWithClear(pOut); }else{ pOut->flags = MEM_Int; return pOut; } } /* ** Execute as much of a VDBE program as we can. ** This is the core of sqlite3_step(). */ int sqlite3VdbeExec( Vdbe *p /* The VDBE */ | > > > > > > > > > > > > > | 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 | return out2PrereleaseWithClear(pOut); }else{ pOut->flags = MEM_Int; return pOut; } } /* ** Return the symbolic name for the data type of a pMem */ static const char *vdbeMemTypeName(Mem *pMem){ static const char *azTypes[] = { /* SQLITE_INTEGER */ "INT", /* SQLITE_FLOAT */ "REAL", /* SQLITE_TEXT */ "TEXT", /* SQLITE_BLOB */ "BLOB", /* SQLITE_NULL */ "NULL" }; return azTypes[sqlite3_value_type(pMem)-1]; } /* ** Execute as much of a VDBE program as we can. ** This is the core of sqlite3_step(). */ int sqlite3VdbeExec( Vdbe *p /* The VDBE */ |
︙ | ︙ | |||
596 597 598 599 600 601 602 | int nExtraDelete = 0; /* Verifies FORDELETE and AUXDELETE flags */ #endif int rc = SQLITE_OK; /* Value to return */ sqlite3 *db = p->db; /* The database */ u8 resetSchemaOnFault = 0; /* Reset schema after an error if positive */ u8 encoding = ENC(db); /* The database encoding */ int iCompare = 0; /* Result of last comparison */ | | | | > > > > > > > > > > > | < < < < < < < < < | 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 | int nExtraDelete = 0; /* Verifies FORDELETE and AUXDELETE flags */ #endif int rc = SQLITE_OK; /* Value to return */ sqlite3 *db = p->db; /* The database */ u8 resetSchemaOnFault = 0; /* Reset schema after an error if positive */ u8 encoding = ENC(db); /* The database encoding */ int iCompare = 0; /* Result of last comparison */ u64 nVmStep = 0; /* Number of virtual machine steps */ #ifndef SQLITE_OMIT_PROGRESS_CALLBACK u64 nProgressLimit; /* Invoke xProgress() when nVmStep reaches this */ #endif Mem *aMem = p->aMem; /* Copy of p->aMem */ Mem *pIn1 = 0; /* 1st input operand */ Mem *pIn2 = 0; /* 2nd input operand */ Mem *pIn3 = 0; /* 3rd input operand */ Mem *pOut = 0; /* Output operand */ #ifdef VDBE_PROFILE u64 start; /* CPU clock count at start of opcode */ #endif /*** INSERT STACK UNION HERE ***/ assert( p->iVdbeMagic==VDBE_MAGIC_RUN ); /* sqlite3_step() verifies this */ sqlite3VdbeEnter(p); #ifndef SQLITE_OMIT_PROGRESS_CALLBACK if( db->xProgress ){ u32 iPrior = p->aCounter[SQLITE_STMTSTATUS_VM_STEP]; assert( 0 < db->nProgressOps ); nProgressLimit = db->nProgressOps - (iPrior % db->nProgressOps); }else{ nProgressLimit = LARGEST_UINT64; } #endif if( p->rc==SQLITE_NOMEM ){ /* This happens if a malloc() inside a call to sqlite3_column_text() or ** sqlite3_column_text16() failed. */ goto no_mem; } assert( p->rc==SQLITE_OK || (p->rc&0xff)==SQLITE_BUSY ); testcase( p->rc!=SQLITE_OK ); p->rc = SQLITE_OK; assert( p->bIsReader || p->readOnly!=0 ); p->iCurrentTime = 0; assert( p->explain==0 ); p->pResultSet = 0; db->busyHandler.nBusy = 0; if( AtomicLoad(&db->u1.isInterrupted) ) goto abort_due_to_interrupt; sqlite3VdbeIOTraceSql(p); #ifdef SQLITE_DEBUG sqlite3BeginBenignMalloc(); if( p->pc==0 && (p->db->flags & (SQLITE_VdbeListing|SQLITE_VdbeEQP|SQLITE_VdbeTrace))!=0 ){ int i; int once = 1; |
︙ | ︙ | |||
680 681 682 683 684 685 686 687 688 689 690 691 692 693 | #endif /* Only allow tracing if SQLITE_DEBUG is defined. */ #ifdef SQLITE_DEBUG if( db->flags & SQLITE_VdbeTrace ){ sqlite3VdbePrintOp(stdout, (int)(pOp - aOp), pOp); } #endif /* Check to see if we need to simulate an interrupt. This only happens ** if we have a special test build. */ | > | 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 | #endif /* Only allow tracing if SQLITE_DEBUG is defined. */ #ifdef SQLITE_DEBUG if( db->flags & SQLITE_VdbeTrace ){ sqlite3VdbePrintOp(stdout, (int)(pOp - aOp), pOp); test_trace_breakpoint((int)(pOp - aOp),pOp,p); } #endif /* Check to see if we need to simulate an interrupt. This only happens ** if we have a special test build. */ |
︙ | ︙ | |||
787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 | ** ** The P1 parameter is not actually used by this opcode. However, it ** is sometimes set to 1 instead of 0 as a hint to the command-line shell ** that this Goto is the bottom of a loop and that the lines from P2 down ** to the current line should be indented for EXPLAIN output. */ case OP_Goto: { /* jump */ jump_to_p2_and_check_for_interrupt: pOp = &aOp[pOp->p2 - 1]; /* Opcodes that are used as the bottom of a loop (OP_Next, OP_Prev, ** OP_VNext, or OP_SorterNext) all jump here upon ** completion. Check to see if sqlite3_interrupt() has been called ** or if the progress callback needs to be invoked. ** ** This code uses unstructured "goto" statements and does not look clean. ** But that is not due to sloppy coding habits. The code is written this ** way for performance, to avoid having to run the interrupt and progress ** checks on every opcode. This helps sqlite3_step() to run about 1.5% ** faster according to "valgrind --tool=cachegrind" */ check_for_interrupt: | > > > > > > > > > > > > > > | | | > | 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 | ** ** The P1 parameter is not actually used by this opcode. However, it ** is sometimes set to 1 instead of 0 as a hint to the command-line shell ** that this Goto is the bottom of a loop and that the lines from P2 down ** to the current line should be indented for EXPLAIN output. */ case OP_Goto: { /* jump */ #ifdef SQLITE_DEBUG /* In debuggging mode, when the p5 flags is set on an OP_Goto, that ** means we should really jump back to the preceeding OP_ReleaseReg ** instruction. */ if( pOp->p5 ){ assert( pOp->p2 < (int)(pOp - aOp) ); assert( pOp->p2 > 1 ); pOp = &aOp[pOp->p2 - 2]; assert( pOp[1].opcode==OP_ReleaseReg ); goto check_for_interrupt; } #endif jump_to_p2_and_check_for_interrupt: pOp = &aOp[pOp->p2 - 1]; /* Opcodes that are used as the bottom of a loop (OP_Next, OP_Prev, ** OP_VNext, or OP_SorterNext) all jump here upon ** completion. Check to see if sqlite3_interrupt() has been called ** or if the progress callback needs to be invoked. ** ** This code uses unstructured "goto" statements and does not look clean. ** But that is not due to sloppy coding habits. The code is written this ** way for performance, to avoid having to run the interrupt and progress ** checks on every opcode. This helps sqlite3_step() to run about 1.5% ** faster according to "valgrind --tool=cachegrind" */ check_for_interrupt: if( AtomicLoad(&db->u1.isInterrupted) ) goto abort_due_to_interrupt; #ifndef SQLITE_OMIT_PROGRESS_CALLBACK /* Call the progress callback if it is configured and the required number ** of VDBE ops have been executed (either since this invocation of ** sqlite3VdbeExec() or since last time the progress callback was called). ** If the progress callback returns non-zero, exit the virtual machine with ** a return code SQLITE_ABORT. */ while( nVmStep>=nProgressLimit && db->xProgress!=0 ){ assert( db->nProgressOps!=0 ); nProgressLimit += db->nProgressOps; if( db->xProgress(db->pProgressArg) ){ nProgressLimit = LARGEST_UINT64; rc = SQLITE_INTERRUPT; goto abort_due_to_error; } } #endif break; |
︙ | ︙ | |||
940 941 942 943 944 945 946 947 948 949 950 951 952 953 | case OP_HaltIfNull: { /* in3 */ pIn3 = &aMem[pOp->p3]; #ifdef SQLITE_DEBUG if( pOp->p2==OE_Abort ){ sqlite3VdbeAssertAbortable(p); } #endif if( (pIn3->flags & MEM_Null)==0 ) break; /* Fall through into OP_Halt */ } /* Opcode: Halt P1 P2 * P4 P5 ** ** Exit immediately. All open cursors, etc are closed ** automatically. ** | > | 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 | case OP_HaltIfNull: { /* in3 */ pIn3 = &aMem[pOp->p3]; #ifdef SQLITE_DEBUG if( pOp->p2==OE_Abort ){ sqlite3VdbeAssertAbortable(p); } #endif if( (pIn3->flags & MEM_Null)==0 ) break; /* Fall through into OP_Halt */ /* no break */ deliberate_fall_through } /* Opcode: Halt P1 P2 * P4 P5 ** ** Exit immediately. All open cursors, etc are closed ** automatically. ** |
︙ | ︙ | |||
1084 1085 1086 1087 1088 1089 1090 | ** into a String opcode before it is executed for the first time. During ** this transformation, the length of string P4 is computed and stored ** as the P1 parameter. */ case OP_String8: { /* same as TK_STRING, out2 */ assert( pOp->p4.z!=0 ); pOut = out2Prerelease(p, pOp); | < > < > > | 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 | ** into a String opcode before it is executed for the first time. During ** this transformation, the length of string P4 is computed and stored ** as the P1 parameter. */ case OP_String8: { /* same as TK_STRING, out2 */ assert( pOp->p4.z!=0 ); pOut = out2Prerelease(p, pOp); pOp->p1 = sqlite3Strlen30(pOp->p4.z); #ifndef SQLITE_OMIT_UTF16 if( encoding!=SQLITE_UTF8 ){ rc = sqlite3VdbeMemSetStr(pOut, pOp->p4.z, -1, SQLITE_UTF8, SQLITE_STATIC); assert( rc==SQLITE_OK || rc==SQLITE_TOOBIG ); if( rc ) goto too_big; if( SQLITE_OK!=sqlite3VdbeChangeEncoding(pOut, encoding) ) goto no_mem; assert( pOut->szMalloc>0 && pOut->zMalloc==pOut->z ); assert( VdbeMemDynamic(pOut)==0 ); pOut->szMalloc = 0; pOut->flags |= MEM_Static; if( pOp->p4type==P4_DYNAMIC ){ sqlite3DbFree(db, pOp->p4.z); } pOp->p4type = P4_DYNAMIC; pOp->p4.z = pOut->z; pOp->p1 = pOut->n; } #endif if( pOp->p1>db->aLimit[SQLITE_LIMIT_LENGTH] ){ goto too_big; } pOp->opcode = OP_String; assert( rc==SQLITE_OK ); /* Fall through to the next case, OP_String */ /* no break */ deliberate_fall_through } /* Opcode: String P1 P2 P3 P4 P5 ** Synopsis: r[P2]='P4' (len=P1) ** ** The string value P4 of length P1 (bytes) is stored in register P2. ** |
︙ | ︙ | |||
1225 1226 1227 1228 1229 1230 1231 | assert( pOp->p1>0 && pOp->p1<=p->nVar ); assert( pOp->p4.z==0 || pOp->p4.z==sqlite3VListNumToName(p->pVList,pOp->p1) ); pVar = &p->aVar[pOp->p1 - 1]; if( sqlite3VdbeMemTooBig(pVar) ){ goto too_big; } pOut = &aMem[pOp->p2]; | > | > > | 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 | assert( pOp->p1>0 && pOp->p1<=p->nVar ); assert( pOp->p4.z==0 || pOp->p4.z==sqlite3VListNumToName(p->pVList,pOp->p1) ); pVar = &p->aVar[pOp->p1 - 1]; if( sqlite3VdbeMemTooBig(pVar) ){ goto too_big; } pOut = &aMem[pOp->p2]; if( VdbeMemDynamic(pOut) ) sqlite3VdbeMemSetNull(pOut); memcpy(pOut, pVar, MEMCELLSIZE); pOut->flags &= ~(MEM_Dyn|MEM_Ephem); pOut->flags |= MEM_Static|MEM_FromBind; UPDATE_MAX_BLOBSIZE(pOut); break; } /* Opcode: Move P1 P2 P3 * * ** Synopsis: r[P2@P3]=r[P1@P3] ** |
︙ | ︙ | |||
1259 1260 1261 1262 1263 1264 1265 | do{ assert( pOut<=&aMem[(p->nMem+1 - p->nCursor)] ); assert( pIn1<=&aMem[(p->nMem+1 - p->nCursor)] ); assert( memIsValid(pIn1) ); memAboutToChange(p, pOut); sqlite3VdbeMemMove(pOut, pIn1); #ifdef SQLITE_DEBUG | | > > > | > > | 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 | do{ assert( pOut<=&aMem[(p->nMem+1 - p->nCursor)] ); assert( pIn1<=&aMem[(p->nMem+1 - p->nCursor)] ); assert( memIsValid(pIn1) ); memAboutToChange(p, pOut); sqlite3VdbeMemMove(pOut, pIn1); #ifdef SQLITE_DEBUG pIn1->pScopyFrom = 0; { int i; for(i=1; i<p->nMem; i++){ if( aMem[i].pScopyFrom==pIn1 ){ aMem[i].pScopyFrom = pOut; } } } #endif Deephemeralize(pOut); REGISTER_TRACE(p2++, pOut); pIn1++; pOut++; }while( --n ); |
︙ | ︙ | |||
1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 | case OP_IntCopy: { /* out2 */ pIn1 = &aMem[pOp->p1]; assert( (pIn1->flags & MEM_Int)!=0 ); pOut = &aMem[pOp->p2]; sqlite3VdbeMemSetInt64(pOut, pIn1->u.i); break; } /* Opcode: ResultRow P1 P2 * * * ** Synopsis: output=r[P1@P2] ** ** The registers P1 through P1+P2-1 contain a single row of ** results. This opcode causes the sqlite3_step() call to terminate ** with an SQLITE_ROW return code and it sets up the sqlite3_stmt ** structure to provide access to the r(P1)..r(P1+P2-1) values as ** the result row. */ case OP_ResultRow: { Mem *pMem; int i; assert( p->nResColumn==pOp->p2 ); | > > > > > > > > > > > > > > > > > > > > | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < > > > > > > > > | > | 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 | case OP_IntCopy: { /* out2 */ pIn1 = &aMem[pOp->p1]; assert( (pIn1->flags & MEM_Int)!=0 ); pOut = &aMem[pOp->p2]; sqlite3VdbeMemSetInt64(pOut, pIn1->u.i); break; } /* Opcode: ChngCntRow P1 P2 * * * ** Synopsis: output=r[P1] ** ** Output value in register P1 as the chance count for a DML statement, ** due to the "PRAGMA count_changes=ON" setting. Or, if there was a ** foreign key error in the statement, trigger the error now. ** ** This opcode is a variant of OP_ResultRow that checks the foreign key ** immediate constraint count and throws an error if the count is ** non-zero. The P2 opcode must be 1. */ case OP_ChngCntRow: { assert( pOp->p2==1 ); if( (rc = sqlite3VdbeCheckFk(p,0))!=SQLITE_OK ){ goto abort_due_to_error; } /* Fall through to the next case, OP_ResultRow */ /* no break */ deliberate_fall_through } /* Opcode: ResultRow P1 P2 * * * ** Synopsis: output=r[P1@P2] ** ** The registers P1 through P1+P2-1 contain a single row of ** results. This opcode causes the sqlite3_step() call to terminate ** with an SQLITE_ROW return code and it sets up the sqlite3_stmt ** structure to provide access to the r(P1)..r(P1+P2-1) values as ** the result row. */ case OP_ResultRow: { Mem *pMem; int i; assert( p->nResColumn==pOp->p2 ); assert( pOp->p1>0 || CORRUPT_DB ); assert( pOp->p1+pOp->p2<=(p->nMem+1 - p->nCursor)+1 ); /* Invalidate all ephemeral cursor row caches */ p->cacheCtr = (p->cacheCtr + 2)|1; /* Make sure the results of the current row are \000 terminated ** and have an assigned type. The results are de-ephemeralized as ** a side effect. */ pMem = p->pResultSet = &aMem[pOp->p1]; for(i=0; i<pOp->p2; i++){ assert( memIsValid(&pMem[i]) ); Deephemeralize(&pMem[i]); assert( (pMem[i].flags & MEM_Ephem)==0 || (pMem[i].flags & (MEM_Str|MEM_Blob))==0 ); sqlite3VdbeMemNulTerminate(&pMem[i]); REGISTER_TRACE(pOp->p1+i, &pMem[i]); #ifdef SQLITE_DEBUG /* The registers in the result will not be used again when the ** prepared statement restarts. This is because sqlite3_column() ** APIs might have caused type conversions of made other changes to ** the register values. Therefore, we can go ahead and break any ** OP_SCopy dependencies. */ pMem[i].pScopyFrom = 0; #endif } if( db->mallocFailed ) goto no_mem; if( db->mTrace & SQLITE_TRACE_ROW ){ db->trace.xV2(SQLITE_TRACE_ROW, db->pTraceArg, p, 0); } /* Return SQLITE_ROW */ p->pc = (int)(pOp - aOp) + 1; rc = SQLITE_ROW; goto vdbe_return; } |
︙ | ︙ | |||
1441 1442 1443 1444 1445 1446 1447 | ** P3 = P2 || P1 ** ** It is illegal for P1 and P3 to be the same register. Sometimes, ** if P3 is the same register as P2, the implementation is able ** to avoid a memcpy(). */ case OP_Concat: { /* same as TK_CONCAT, in1, in2, out3 */ | | > > > > > > | > > > > | | > > > | > > > > > | > > > > > | 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 | ** P3 = P2 || P1 ** ** It is illegal for P1 and P3 to be the same register. Sometimes, ** if P3 is the same register as P2, the implementation is able ** to avoid a memcpy(). */ case OP_Concat: { /* same as TK_CONCAT, in1, in2, out3 */ i64 nByte; /* Total size of the output string or blob */ u16 flags1; /* Initial flags for P1 */ u16 flags2; /* Initial flags for P2 */ pIn1 = &aMem[pOp->p1]; pIn2 = &aMem[pOp->p2]; pOut = &aMem[pOp->p3]; testcase( pOut==pIn2 ); assert( pIn1!=pOut ); flags1 = pIn1->flags; testcase( flags1 & MEM_Null ); testcase( pIn2->flags & MEM_Null ); if( (flags1 | pIn2->flags) & MEM_Null ){ sqlite3VdbeMemSetNull(pOut); break; } if( (flags1 & (MEM_Str|MEM_Blob))==0 ){ if( sqlite3VdbeMemStringify(pIn1,encoding,0) ) goto no_mem; flags1 = pIn1->flags & ~MEM_Str; }else if( (flags1 & MEM_Zero)!=0 ){ if( sqlite3VdbeMemExpandBlob(pIn1) ) goto no_mem; flags1 = pIn1->flags & ~MEM_Str; } flags2 = pIn2->flags; if( (flags2 & (MEM_Str|MEM_Blob))==0 ){ if( sqlite3VdbeMemStringify(pIn2,encoding,0) ) goto no_mem; flags2 = pIn2->flags & ~MEM_Str; }else if( (flags2 & MEM_Zero)!=0 ){ if( sqlite3VdbeMemExpandBlob(pIn2) ) goto no_mem; flags2 = pIn2->flags & ~MEM_Str; } nByte = pIn1->n + pIn2->n; if( nByte>db->aLimit[SQLITE_LIMIT_LENGTH] ){ goto too_big; } if( sqlite3VdbeMemGrow(pOut, (int)nByte+3, pOut==pIn2) ){ goto no_mem; } MemSetTypeFlag(pOut, MEM_Str); if( pOut!=pIn2 ){ memcpy(pOut->z, pIn2->z, pIn2->n); assert( (pIn2->flags & MEM_Dyn) == (flags2 & MEM_Dyn) ); pIn2->flags = flags2; } memcpy(&pOut->z[pIn2->n], pIn1->z, pIn1->n); assert( (pIn1->flags & MEM_Dyn) == (flags1 & MEM_Dyn) ); pIn1->flags = flags1; pOut->z[nByte]=0; pOut->z[nByte+1] = 0; pOut->z[nByte+2] = 0; pOut->flags |= MEM_Term; pOut->n = (int)nByte; pOut->enc = encoding; UPDATE_MAX_BLOBSIZE(pOut); break; } |
︙ | ︙ | |||
1518 1519 1520 1521 1522 1523 1524 | ** If either operand is NULL, the result is NULL. */ case OP_Add: /* same as TK_PLUS, in1, in2, out3 */ case OP_Subtract: /* same as TK_MINUS, in1, in2, out3 */ case OP_Multiply: /* same as TK_STAR, in1, in2, out3 */ case OP_Divide: /* same as TK_SLASH, in1, in2, out3 */ case OP_Remainder: { /* same as TK_REM, in1, in2, out3 */ | < < | 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 1690 1691 1692 1693 | ** If either operand is NULL, the result is NULL. */ case OP_Add: /* same as TK_PLUS, in1, in2, out3 */ case OP_Subtract: /* same as TK_MINUS, in1, in2, out3 */ case OP_Multiply: /* same as TK_STAR, in1, in2, out3 */ case OP_Divide: /* same as TK_SLASH, in1, in2, out3 */ case OP_Remainder: { /* same as TK_REM, in1, in2, out3 */ u16 flags; /* Combined MEM_* flags from both inputs */ u16 type1; /* Numeric type of left operand */ u16 type2; /* Numeric type of right operand */ i64 iA; /* Integer value of left operand */ i64 iB; /* Integer value of right operand */ double rA; /* Real value of left operand */ double rB; /* Real value of right operand */ pIn1 = &aMem[pOp->p1]; type1 = numericType(pIn1); pIn2 = &aMem[pOp->p2]; type2 = numericType(pIn2); pOut = &aMem[pOp->p3]; flags = pIn1->flags | pIn2->flags; if( (type1 & type2 & MEM_Int)!=0 ){ iA = pIn1->u.i; iB = pIn2->u.i; switch( pOp->opcode ){ case OP_Add: if( sqlite3AddInt64(&iB,iA) ) goto fp_math; break; case OP_Subtract: if( sqlite3SubInt64(&iB,iA) ) goto fp_math; break; case OP_Multiply: if( sqlite3MulInt64(&iB,iA) ) goto fp_math; break; case OP_Divide: { if( iA==0 ) goto arithmetic_result_is_null; if( iA==-1 && iB==SMALLEST_INT64 ) goto fp_math; |
︙ | ︙ | |||
1559 1560 1561 1562 1563 1564 1565 | } } pOut->u.i = iB; MemSetTypeFlag(pOut, MEM_Int); }else if( (flags & MEM_Null)!=0 ){ goto arithmetic_result_is_null; }else{ | < | | < < < | 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 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 1744 1745 1746 | } } pOut->u.i = iB; MemSetTypeFlag(pOut, MEM_Int); }else if( (flags & MEM_Null)!=0 ){ goto arithmetic_result_is_null; }else{ fp_math: rA = sqlite3VdbeRealValue(pIn1); rB = sqlite3VdbeRealValue(pIn2); switch( pOp->opcode ){ case OP_Add: rB += rA; break; case OP_Subtract: rB -= rA; break; case OP_Multiply: rB *= rA; break; case OP_Divide: { /* (double)0 In case of SQLITE_OMIT_FLOATING_POINT... */ if( rA==(double)0 ) goto arithmetic_result_is_null; rB /= rA; break; } default: { iA = sqlite3VdbeIntValue(pIn1); iB = sqlite3VdbeIntValue(pIn2); if( iA==0 ) goto arithmetic_result_is_null; if( iA==-1 ) iA = 1; rB = (double)(iB % iA); break; } } #ifdef SQLITE_OMIT_FLOATING_POINT pOut->u.i = rB; MemSetTypeFlag(pOut, MEM_Int); #else if( sqlite3IsNaN(rB) ){ goto arithmetic_result_is_null; } pOut->u.r = rB; MemSetTypeFlag(pOut, MEM_Real); #endif } break; arithmetic_result_is_null: sqlite3VdbeMemSetNull(pOut); break; |
︙ | ︙ | |||
1735 1736 1737 1738 1739 1740 1741 | ** without data loss, then jump immediately to P2, or if P2==0 ** raise an SQLITE_MISMATCH exception. */ case OP_MustBeInt: { /* jump, in1 */ pIn1 = &aMem[pOp->p1]; if( (pIn1->flags & MEM_Int)==0 ){ applyAffinity(pIn1, SQLITE_AFF_NUMERIC, encoding); | < > > > | > > | 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 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 | ** without data loss, then jump immediately to P2, or if P2==0 ** raise an SQLITE_MISMATCH exception. */ case OP_MustBeInt: { /* jump, in1 */ pIn1 = &aMem[pOp->p1]; if( (pIn1->flags & MEM_Int)==0 ){ applyAffinity(pIn1, SQLITE_AFF_NUMERIC, encoding); if( (pIn1->flags & MEM_Int)==0 ){ VdbeBranchTaken(1, 2); if( pOp->p2==0 ){ rc = SQLITE_MISMATCH; goto abort_due_to_error; }else{ goto jump_to_p2; } } } VdbeBranchTaken(0, 2); MemSetTypeFlag(pIn1, MEM_Int); break; } #ifndef SQLITE_OMIT_FLOATING_POINT /* Opcode: RealAffinity P1 * * * * ** ** If register P1 holds an integer convert it to a real value. ** ** This opcode is used when extracting information from a column that ** has REAL affinity. Such column values may still be stored as ** integers, for space efficiency, but after extraction we want them ** to have only a real value. */ case OP_RealAffinity: { /* in1 */ pIn1 = &aMem[pOp->p1]; if( pIn1->flags & (MEM_Int|MEM_IntReal) ){ testcase( pIn1->flags & MEM_Int ); testcase( pIn1->flags & MEM_IntReal ); sqlite3VdbeMemRealify(pIn1); REGISTER_TRACE(pOp->p1, pIn1); } break; } #endif #ifndef SQLITE_OMIT_CAST /* Opcode: Cast P1 P2 * * * |
︙ | ︙ | |||
1794 1795 1796 1797 1798 1799 1800 | testcase( pOp->p2==SQLITE_AFF_BLOB ); testcase( pOp->p2==SQLITE_AFF_NUMERIC ); testcase( pOp->p2==SQLITE_AFF_INTEGER ); testcase( pOp->p2==SQLITE_AFF_REAL ); pIn1 = &aMem[pOp->p1]; memAboutToChange(p, pIn1); rc = ExpandBlob(pIn1); | > | < > > | < | 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 | testcase( pOp->p2==SQLITE_AFF_BLOB ); testcase( pOp->p2==SQLITE_AFF_NUMERIC ); testcase( pOp->p2==SQLITE_AFF_INTEGER ); testcase( pOp->p2==SQLITE_AFF_REAL ); pIn1 = &aMem[pOp->p1]; memAboutToChange(p, pIn1); rc = ExpandBlob(pIn1); if( rc ) goto abort_due_to_error; rc = sqlite3VdbeMemCast(pIn1, pOp->p2, encoding); if( rc ) goto abort_due_to_error; UPDATE_MAX_BLOBSIZE(pIn1); REGISTER_TRACE(pOp->p1, pIn1); break; } #endif /* SQLITE_OMIT_CAST */ /* Opcode: Eq P1 P2 P3 P4 P5 ** Synopsis: IF r[P3]==r[P1] ** ** Compare the values in register P1 and P3. If reg(P3)==reg(P1) then ** jump to address P2. ** ** The SQLITE_AFF_MASK portion of P5 must be an affinity character - ** SQLITE_AFF_TEXT, SQLITE_AFF_INTEGER, and so forth. An attempt is made ** to coerce both inputs according to this affinity before the ** comparison is made. If the SQLITE_AFF_MASK is 0x00, then numeric ** affinity is used. Note that the affinity conversions are stored ** back into the input registers P1 and P3. So this opcode can cause |
︙ | ︙ | |||
1832 1833 1834 1835 1836 1837 1838 | ** ** If SQLITE_NULLEQ is set in P5 then the result of comparison is always either ** true or false and is never NULL. If both operands are NULL then the result ** of comparison is true. If either operand is NULL then the result is false. ** If neither operand is NULL the result is the same as it would be if ** the SQLITE_NULLEQ flag were omitted from P5. ** | | | < < < < < | < | 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 | ** ** If SQLITE_NULLEQ is set in P5 then the result of comparison is always either ** true or false and is never NULL. If both operands are NULL then the result ** of comparison is true. If either operand is NULL then the result is false. ** If neither operand is NULL the result is the same as it would be if ** the SQLITE_NULLEQ flag were omitted from P5. ** ** This opcode saves the result of comparison for use by the new ** OP_Jump opcode. */ /* Opcode: Ne P1 P2 P3 P4 P5 ** Synopsis: IF r[P3]!=r[P1] ** ** This works just like the Eq opcode except that the jump is taken if ** the operands in registers P1 and P3 are not equal. See the Eq opcode for ** additional information. */ /* Opcode: Lt P1 P2 P3 P4 P5 ** Synopsis: IF r[P3]<r[P1] ** ** Compare the values in register P1 and P3. If reg(P3)<reg(P1) then ** jump to address P2. ** ** If the SQLITE_JUMPIFNULL bit of P5 is set and either reg(P1) or ** reg(P3) is NULL then the take the jump. If the SQLITE_JUMPIFNULL ** bit is clear then fall through if either operand is NULL. ** ** The SQLITE_AFF_MASK portion of P5 must be an affinity character - ** SQLITE_AFF_TEXT, SQLITE_AFF_INTEGER, and so forth. An attempt is made |
︙ | ︙ | |||
1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 | ** used to determine the results of the comparison. If both values ** are text, then the appropriate collating function specified in ** P4 is used to do the comparison. If P4 is not specified then ** memcmp() is used to compare text string. If both values are ** numeric, then a numeric comparison is used. If the two values ** are of different types, then numbers are considered less than ** strings and strings are considered less than blobs. */ /* Opcode: Le P1 P2 P3 P4 P5 ** Synopsis: IF r[P3]<=r[P1] ** ** This works just like the Lt opcode except that the jump is taken if ** the content of register P3 is less than or equal to the content of ** register P1. See the Lt opcode for additional information. | > > > | 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 | ** used to determine the results of the comparison. If both values ** are text, then the appropriate collating function specified in ** P4 is used to do the comparison. If P4 is not specified then ** memcmp() is used to compare text string. If both values are ** numeric, then a numeric comparison is used. If the two values ** are of different types, then numbers are considered less than ** strings and strings are considered less than blobs. ** ** This opcode saves the result of comparison for use by the new ** OP_Jump opcode. */ /* Opcode: Le P1 P2 P3 P4 P5 ** Synopsis: IF r[P3]<=r[P1] ** ** This works just like the Lt opcode except that the jump is taken if ** the content of register P3 is less than or equal to the content of ** register P1. See the Lt opcode for additional information. |
︙ | ︙ | |||
1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 | u16 flags1; /* Copy of initial value of pIn1->flags */ u16 flags3; /* Copy of initial value of pIn3->flags */ pIn1 = &aMem[pOp->p1]; pIn3 = &aMem[pOp->p3]; flags1 = pIn1->flags; flags3 = pIn3->flags; if( (flags1 | flags3)&MEM_Null ){ /* One or both operands are NULL */ if( pOp->p5 & SQLITE_NULLEQ ){ /* If SQLITE_NULLEQ is set (which will only happen if the operator is ** OP_Eq or OP_Ne) then take the jump or not depending on whether ** or not both operands are null. */ | > > > > > > > > > > > > > > > > > > > > > > > > > < | > | < < | < < < < | | | < | > | | < < < < < | < < < < < < < < | > | | > | | < | < | < | > < < | < < | < < < < < < < < < < < < < < < | < < < < < | | | | < | | > > > > | | | | | | > > > > > > | > > | | | | 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 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 | u16 flags1; /* Copy of initial value of pIn1->flags */ u16 flags3; /* Copy of initial value of pIn3->flags */ pIn1 = &aMem[pOp->p1]; pIn3 = &aMem[pOp->p3]; flags1 = pIn1->flags; flags3 = pIn3->flags; if( (flags1 & flags3 & MEM_Int)!=0 ){ assert( (pOp->p5 & SQLITE_AFF_MASK)!=SQLITE_AFF_TEXT || CORRUPT_DB ); /* Common case of comparison of two integers */ if( pIn3->u.i > pIn1->u.i ){ iCompare = +1; if( sqlite3aGTb[pOp->opcode] ){ VdbeBranchTaken(1, (pOp->p5 & SQLITE_NULLEQ)?2:3); goto jump_to_p2; } }else if( pIn3->u.i < pIn1->u.i ){ iCompare = -1; if( sqlite3aLTb[pOp->opcode] ){ VdbeBranchTaken(1, (pOp->p5 & SQLITE_NULLEQ)?2:3); goto jump_to_p2; } }else{ iCompare = 0; if( sqlite3aEQb[pOp->opcode] ){ VdbeBranchTaken(1, (pOp->p5 & SQLITE_NULLEQ)?2:3); goto jump_to_p2; } } VdbeBranchTaken(0, (pOp->p5 & SQLITE_NULLEQ)?2:3); break; } if( (flags1 | flags3)&MEM_Null ){ /* One or both operands are NULL */ if( pOp->p5 & SQLITE_NULLEQ ){ /* If SQLITE_NULLEQ is set (which will only happen if the operator is ** OP_Eq or OP_Ne) then take the jump or not depending on whether ** or not both operands are null. */ assert( (flags1 & MEM_Cleared)==0 ); assert( (pOp->p5 & SQLITE_JUMPIFNULL)==0 || CORRUPT_DB ); testcase( (pOp->p5 & SQLITE_JUMPIFNULL)!=0 ); if( (flags1&flags3&MEM_Null)!=0 && (flags3&MEM_Cleared)==0 ){ res = 0; /* Operands are equal */ }else{ res = ((flags3 & MEM_Null) ? -1 : +1); /* Operands are not equal */ } }else{ /* SQLITE_NULLEQ is clear and at least one operand is NULL, ** then the result is always NULL. ** The jump is taken if the SQLITE_JUMPIFNULL bit is set. */ iCompare = 1; /* Operands are not equal */ VdbeBranchTaken(2,3); if( pOp->p5 & SQLITE_JUMPIFNULL ){ goto jump_to_p2; } break; } }else{ /* Neither operand is NULL and we couldn't do the special high-speed ** integer comparison case. So do a general-case comparison. */ affinity = pOp->p5 & SQLITE_AFF_MASK; if( affinity>=SQLITE_AFF_NUMERIC ){ if( (flags1 | flags3)&MEM_Str ){ if( (flags1 & (MEM_Int|MEM_IntReal|MEM_Real|MEM_Str))==MEM_Str ){ applyNumericAffinity(pIn1,0); testcase( flags3==pIn3->flags ); flags3 = pIn3->flags; } if( (flags3 & (MEM_Int|MEM_IntReal|MEM_Real|MEM_Str))==MEM_Str ){ applyNumericAffinity(pIn3,0); } } }else if( affinity==SQLITE_AFF_TEXT ){ if( (flags1 & MEM_Str)==0 && (flags1&(MEM_Int|MEM_Real|MEM_IntReal))!=0 ){ testcase( pIn1->flags & MEM_Int ); testcase( pIn1->flags & MEM_Real ); testcase( pIn1->flags & MEM_IntReal ); sqlite3VdbeMemStringify(pIn1, encoding, 1); testcase( (flags1&MEM_Dyn) != (pIn1->flags&MEM_Dyn) ); flags1 = (pIn1->flags & ~MEM_TypeMask) | (flags1 & MEM_TypeMask); if( NEVER(pIn1==pIn3) ) flags3 = flags1 | MEM_Str; } if( (flags3 & MEM_Str)==0 && (flags3&(MEM_Int|MEM_Real|MEM_IntReal))!=0 ){ testcase( pIn3->flags & MEM_Int ); testcase( pIn3->flags & MEM_Real ); testcase( pIn3->flags & MEM_IntReal ); sqlite3VdbeMemStringify(pIn3, encoding, 1); testcase( (flags3&MEM_Dyn) != (pIn3->flags&MEM_Dyn) ); flags3 = (pIn3->flags & ~MEM_TypeMask) | (flags3 & MEM_TypeMask); } } assert( pOp->p4type==P4_COLLSEQ || pOp->p4.pColl==0 ); res = sqlite3MemCompare(pIn3, pIn1, pOp->p4.pColl); } /* At this point, res is negative, zero, or positive if reg[P1] is ** less than, equal to, or greater than reg[P3], respectively. Compute ** the answer to this operator in res2, depending on what the comparison ** operator actually is. The next block of code depends on the fact ** that the 6 comparison operators are consecutive integers in this ** order: NE, EQ, GT, LE, LT, GE */ assert( OP_Eq==OP_Ne+1 ); assert( OP_Gt==OP_Ne+2 ); assert( OP_Le==OP_Ne+3 ); assert( OP_Lt==OP_Ne+4 ); assert( OP_Ge==OP_Ne+5 ); if( res<0 ){ res2 = sqlite3aLTb[pOp->opcode]; }else if( res==0 ){ res2 = sqlite3aEQb[pOp->opcode]; }else{ res2 = sqlite3aGTb[pOp->opcode]; } iCompare = res; /* Undo any changes made by applyAffinity() to the input registers. */ assert( (pIn3->flags & MEM_Dyn) == (flags3 & MEM_Dyn) ); pIn3->flags = flags3; assert( (pIn1->flags & MEM_Dyn) == (flags1 & MEM_Dyn) ); pIn1->flags = flags1; VdbeBranchTaken(res2!=0, (pOp->p5 & SQLITE_NULLEQ)?2:3); if( res2 ){ goto jump_to_p2; } break; } /* Opcode: ElseEq * P2 * * * ** ** This opcode must follow an OP_Lt or OP_Gt comparison operator. There ** can be zero or more OP_ReleaseReg opcodes intervening, but no other ** opcodes are allowed to occur between this instruction and the previous ** OP_Lt or OP_Gt. ** ** If result of an OP_Eq comparison on the same two operands as the ** prior OP_Lt or OP_Gt would have been true, then jump to P2. ** If the result of an OP_Eq comparison on the two previous ** operands would have been false or NULL, then fall through. */ case OP_ElseEq: { /* same as TK_ESCAPE, jump */ #ifdef SQLITE_DEBUG /* Verify the preconditions of this opcode - that it follows an OP_Lt or ** OP_Gt with zero or more intervening OP_ReleaseReg opcodes */ int iAddr; for(iAddr = (int)(pOp - aOp) - 1; ALWAYS(iAddr>=0); iAddr--){ if( aOp[iAddr].opcode==OP_ReleaseReg ) continue; assert( aOp[iAddr].opcode==OP_Lt || aOp[iAddr].opcode==OP_Gt ); break; } #endif /* SQLITE_DEBUG */ VdbeBranchTaken(iCompare==0, 2); if( iCompare==0 ) goto jump_to_p2; break; } /* Opcode: Permutation * * * P4 * ** ** Set the permutation used by the OP_Compare operator in the next |
︙ | ︙ | |||
2117 2118 2119 2120 2121 2122 2123 | */ case OP_Compare: { int n; int i; int p1; int p2; const KeyInfo *pKeyInfo; | | | | | | > > > > > | 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 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 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 | */ case OP_Compare: { int n; int i; int p1; int p2; const KeyInfo *pKeyInfo; u32 idx; CollSeq *pColl; /* Collating sequence to use on this term */ int bRev; /* True for DESCENDING sort order */ u32 *aPermute; /* The permutation */ if( (pOp->p5 & OPFLAG_PERMUTE)==0 ){ aPermute = 0; }else{ assert( pOp>aOp ); assert( pOp[-1].opcode==OP_Permutation ); assert( pOp[-1].p4type==P4_INTARRAY ); aPermute = pOp[-1].p4.ai + 1; assert( aPermute!=0 ); } n = pOp->p3; pKeyInfo = pOp->p4.pKeyInfo; assert( n>0 ); assert( pKeyInfo!=0 ); p1 = pOp->p1; p2 = pOp->p2; #ifdef SQLITE_DEBUG if( aPermute ){ int k, mx = 0; for(k=0; k<n; k++) if( aPermute[k]>(u32)mx ) mx = aPermute[k]; assert( p1>0 && p1+mx<=(p->nMem+1 - p->nCursor)+1 ); assert( p2>0 && p2+mx<=(p->nMem+1 - p->nCursor)+1 ); }else{ assert( p1>0 && p1+n<=(p->nMem+1 - p->nCursor)+1 ); assert( p2>0 && p2+n<=(p->nMem+1 - p->nCursor)+1 ); } #endif /* SQLITE_DEBUG */ for(i=0; i<n; i++){ idx = aPermute ? aPermute[i] : (u32)i; assert( memIsValid(&aMem[p1+idx]) ); assert( memIsValid(&aMem[p2+idx]) ); REGISTER_TRACE(p1+idx, &aMem[p1+idx]); REGISTER_TRACE(p2+idx, &aMem[p2+idx]); assert( i<pKeyInfo->nKeyField ); pColl = pKeyInfo->aColl[i]; bRev = (pKeyInfo->aSortFlags[i] & KEYINFO_ORDER_DESC); iCompare = sqlite3MemCompare(&aMem[p1+idx], &aMem[p2+idx], pColl); if( iCompare ){ if( (pKeyInfo->aSortFlags[i] & KEYINFO_ORDER_BIGNULL) && ((aMem[p1+idx].flags & MEM_Null) || (aMem[p2+idx].flags & MEM_Null)) ){ iCompare = -iCompare; } if( bRev ) iCompare = -iCompare; break; } } break; } |
︙ | ︙ | |||
2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 | pIn1 = &aMem[pOp->p1]; VdbeBranchTaken( (pIn1->flags & MEM_Null)!=0, 2); if( (pIn1->flags & MEM_Null)!=0 ){ goto jump_to_p2; } break; } /* Opcode: NotNull P1 P2 * * * ** Synopsis: if r[P1]!=NULL goto P2 ** ** Jump to P2 if the value in register P1 is not NULL. */ case OP_NotNull: { /* same as TK_NOTNULL, jump, in1 */ | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 2510 2511 2512 2513 2514 2515 2516 2517 2518 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 | pIn1 = &aMem[pOp->p1]; VdbeBranchTaken( (pIn1->flags & MEM_Null)!=0, 2); if( (pIn1->flags & MEM_Null)!=0 ){ goto jump_to_p2; } break; } /* Opcode: IsNullOrType P1 P2 P3 * * ** Synopsis: if typeof(r[P1]) IN (P3,5) goto P2 ** ** Jump to P2 if the value in register P1 is NULL or has a datatype P3. ** P3 is an integer which should be one of SQLITE_INTEGER, SQLITE_FLOAT, ** SQLITE_BLOB, SQLITE_NULL, or SQLITE_TEXT. */ case OP_IsNullOrType: { /* jump, in1 */ int doTheJump; pIn1 = &aMem[pOp->p1]; doTheJump = (pIn1->flags & MEM_Null)!=0 || sqlite3_value_type(pIn1)==pOp->p3; VdbeBranchTaken( doTheJump, 2); if( doTheJump ) goto jump_to_p2; break; } /* Opcode: ZeroOrNull P1 P2 P3 * * ** Synopsis: r[P2] = 0 OR NULL ** ** If all both registers P1 and P3 are NOT NULL, then store a zero in ** register P2. If either registers P1 or P3 are NULL then put ** a NULL in register P2. */ case OP_ZeroOrNull: { /* in1, in2, out2, in3 */ if( (aMem[pOp->p1].flags & MEM_Null)!=0 || (aMem[pOp->p3].flags & MEM_Null)!=0 ){ sqlite3VdbeMemSetNull(aMem + pOp->p2); }else{ sqlite3VdbeMemSetInt64(aMem + pOp->p2, 0); } break; } /* Opcode: NotNull P1 P2 * * * ** Synopsis: if r[P1]!=NULL goto P2 ** ** Jump to P2 if the value in register P1 is not NULL. */ case OP_NotNull: { /* same as TK_NOTNULL, jump, in1 */ |
︙ | ︙ | |||
2449 2450 2451 2452 2453 2454 2455 | ** ** The value extracted is stored in register P3. ** ** If the record contains fewer than P2 fields, then extract a NULL. Or, ** if the P4 argument is a P4_MEM use the value of the P4 argument as ** the result. ** | < < < < < | > > | < | | 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 | ** ** The value extracted is stored in register P3. ** ** If the record contains fewer than P2 fields, then extract a NULL. Or, ** if the P4 argument is a P4_MEM use the value of the P4 argument as ** the result. ** ** If the OPFLAG_LENGTHARG and OPFLAG_TYPEOFARG bits are set on P5 then ** the result is guaranteed to only be used as the argument of a length() ** or typeof() function, respectively. The loading of large blobs can be ** skipped for length() and all content loading can be skipped for typeof(). */ case OP_Column: { u32 p2; /* column number to retrieve */ VdbeCursor *pC; /* The VDBE cursor */ BtCursor *pCrsr; /* The BTree cursor */ u32 *aOffset; /* aOffset[i] is offset to start of data for i-th column */ int len; /* The length of the serialized data for the column */ int i; /* Loop counter */ Mem *pDest; /* Where to write the extracted value */ Mem sMem; /* For storing the record being decoded */ const u8 *zData; /* Part of the record being decoded */ const u8 *zHdr; /* Next unparsed byte of the header */ const u8 *zEndHdr; /* Pointer to first byte after the header */ u64 offset64; /* 64-bit offset */ u32 t; /* A type code from the record header */ Mem *pReg; /* PseudoTable input register */ assert( pOp->p1>=0 && pOp->p1<p->nCursor ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); p2 = (u32)pOp->p2; /* If the cursor cache is stale (meaning it is not currently point at ** the correct row) then bring it up-to-date by doing the necessary ** B-Tree seek. */ rc = sqlite3VdbeCursorMoveto(&pC, &p2); if( rc ) goto abort_due_to_error; assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) ); pDest = &aMem[pOp->p3]; memAboutToChange(p, pDest); assert( pC!=0 ); assert( p2<(u32)pC->nField ); aOffset = pC->aOffset; assert( pC->eCurType!=CURTYPE_VTAB ); assert( pC->eCurType!=CURTYPE_PSEUDO || pC->nullRow ); assert( pC->eCurType!=CURTYPE_SORTER ); if( pC->cacheStatus!=p->cacheCtr ){ /*OPTIMIZATION-IF-FALSE*/ if( pC->nullRow ){ |
︙ | ︙ | |||
2580 2581 2582 2583 2584 2585 2586 | /* If there is more header available for parsing in the record, try ** to extract additional fields up through the p2+1-th field */ if( pC->iHdrOffset<aOffset[0] ){ /* Make sure zData points to enough of the record to cover the header. */ if( pC->aRow==0 ){ memset(&sMem, 0, sizeof(sMem)); | | | > < | | | 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 | /* If there is more header available for parsing in the record, try ** to extract additional fields up through the p2+1-th field */ if( pC->iHdrOffset<aOffset[0] ){ /* Make sure zData points to enough of the record to cover the header. */ if( pC->aRow==0 ){ memset(&sMem, 0, sizeof(sMem)); rc = sqlite3VdbeMemFromBtreeZeroOffset(pC->uc.pCursor,aOffset[0],&sMem); if( rc!=SQLITE_OK ) goto abort_due_to_error; zData = (u8*)sMem.z; }else{ zData = pC->aRow; } /* Fill in pC->aType[i] and aOffset[i] values through the p2-th field. */ op_column_read_header: i = pC->nHdrParsed; offset64 = aOffset[i]; zHdr = zData + pC->iHdrOffset; zEndHdr = zData + aOffset[0]; testcase( zHdr>=zEndHdr ); do{ if( (pC->aType[i] = t = zHdr[0])<0x80 ){ zHdr++; offset64 += sqlite3VdbeOneByteSerialTypeLen(t); }else{ zHdr += sqlite3GetVarint32(zHdr, &t); pC->aType[i] = t; offset64 += sqlite3VdbeSerialTypeLen(t); } aOffset[++i] = (u32)(offset64 & 0xffffffff); }while( (u32)i<=p2 && zHdr<zEndHdr ); /* The record is corrupt if any of the following are true: ** (1) the bytes of the header extend past the declared header size ** (2) the entire header was used but not all data was used ** (3) the end of the data extends beyond the end of the record. */ if( (zHdr>=zEndHdr && (zHdr>zEndHdr || offset64!=pC->payloadSize)) |
︙ | ︙ | |||
2698 2699 2700 2701 2702 2703 2704 | ** 2. the length(X) function if X is a blob, and ** 3. if the content length is zero. ** So we might as well use bogus content rather than reading ** content from disk. ** ** Although sqlite3VdbeSerialGet() may read at most 8 bytes from the ** buffer passed to it, debugging function VdbeMemPrettyPrint() may | > | > < | | 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 | ** 2. the length(X) function if X is a blob, and ** 3. if the content length is zero. ** So we might as well use bogus content rather than reading ** content from disk. ** ** Although sqlite3VdbeSerialGet() may read at most 8 bytes from the ** buffer passed to it, debugging function VdbeMemPrettyPrint() may ** read more. Use the global constant sqlite3CtypeMap[] as the array, ** as that array is 256 bytes long (plenty for VdbeMemPrettyPrint()) ** and it begins with a bunch of zeros. */ sqlite3VdbeSerialGet((u8*)sqlite3CtypeMap, t, pDest); }else{ rc = sqlite3VdbeMemFromBtree(pC->uc.pCursor, aOffset[p2], len, pDest); if( rc!=SQLITE_OK ) goto abort_due_to_error; sqlite3VdbeSerialGet((const u8*)pDest->z, t, pDest); pDest->flags &= ~MEM_Ephem; } } |
︙ | ︙ | |||
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 | pOp = &aOp[aOp[0].p3-1]; break; }else{ rc = SQLITE_CORRUPT_BKPT; goto abort_due_to_error; } } /* Opcode: Affinity P1 P2 * P4 * ** Synopsis: affinity(r[P1@P2]) ** ** Apply affinities to a range of P2 registers starting with P1. ** ** P4 is a string that is P2 characters long. The N-th character of the ** string indicates the column affinity that should be used for the N-th ** memory cell in the range. */ case OP_Affinity: { const char *zAffinity; /* The affinity to be applied */ zAffinity = pOp->p4.z; assert( zAffinity!=0 ); assert( pOp->p2>0 ); assert( zAffinity[pOp->p2]==0 ); pIn1 = &aMem[pOp->p1]; | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > < > | | > > > > > > > > > > > > > > > > > > > > > < > > > > > > > > > > > > < < < > > | 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 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 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 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 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 | pOp = &aOp[aOp[0].p3-1]; break; }else{ rc = SQLITE_CORRUPT_BKPT; goto abort_due_to_error; } } /* Opcode: TypeCheck P1 P2 P3 P4 * ** Synopsis: typecheck(r[P1@P2]) ** ** Apply affinities to the range of P2 registers beginning with P1. ** Take the affinities from the Table object in P4. If any value ** cannot be coerced into the correct type, then raise an error. ** ** This opcode is similar to OP_Affinity except that this opcode ** forces the register type to the Table column type. This is used ** to implement "strict affinity". ** ** GENERATED ALWAYS AS ... STATIC columns are only checked if P3 ** is zero. When P3 is non-zero, no type checking occurs for ** static generated columns. Virtual columns are computed at query time ** and so they are never checked. ** ** Preconditions: ** ** <ul> ** <li> P2 should be the number of non-virtual columns in the ** table of P4. ** <li> Table P4 should be a STRICT table. ** </ul> ** ** If any precondition is false, an assertion fault occurs. */ case OP_TypeCheck: { Table *pTab; Column *aCol; int i; assert( pOp->p4type==P4_TABLE ); pTab = pOp->p4.pTab; assert( pTab->tabFlags & TF_Strict ); assert( pTab->nNVCol==pOp->p2 ); aCol = pTab->aCol; pIn1 = &aMem[pOp->p1]; for(i=0; i<pTab->nCol; i++){ if( aCol[i].colFlags & COLFLAG_GENERATED ){ if( aCol[i].colFlags & COLFLAG_VIRTUAL ) continue; if( pOp->p3 ){ pIn1++; continue; } } assert( pIn1 < &aMem[pOp->p1+pOp->p2] ); applyAffinity(pIn1, aCol[i].affinity, encoding); if( (pIn1->flags & MEM_Null)==0 ){ switch( aCol[i].eCType ){ case COLTYPE_BLOB: { if( (pIn1->flags & MEM_Blob)==0 ) goto vdbe_type_error; break; } case COLTYPE_INTEGER: case COLTYPE_INT: { if( (pIn1->flags & MEM_Int)==0 ) goto vdbe_type_error; break; } case COLTYPE_TEXT: { if( (pIn1->flags & MEM_Str)==0 ) goto vdbe_type_error; break; } case COLTYPE_REAL: { if( pIn1->flags & MEM_Int ){ /* When applying REAL affinity, if the result is still an MEM_Int ** that will fit in 6 bytes, then change the type to MEM_IntReal ** so that we keep the high-resolution integer value but know that ** the type really wants to be REAL. */ testcase( pIn1->u.i==140737488355328LL ); testcase( pIn1->u.i==140737488355327LL ); testcase( pIn1->u.i==-140737488355328LL ); testcase( pIn1->u.i==-140737488355329LL ); if( pIn1->u.i<=140737488355327LL && pIn1->u.i>=-140737488355328LL){ pIn1->flags |= MEM_IntReal; pIn1->flags &= ~MEM_Int; }else{ pIn1->u.r = (double)pIn1->u.i; pIn1->flags |= MEM_Real; pIn1->flags &= ~MEM_Int; } }else if( (pIn1->flags & MEM_Real)==0 ){ goto vdbe_type_error; } break; } default: { /* COLTYPE_ANY. Accept anything. */ break; } } } REGISTER_TRACE((int)(pIn1-aMem), pIn1); pIn1++; } assert( pIn1 == &aMem[pOp->p1+pOp->p2] ); break; vdbe_type_error: sqlite3VdbeError(p, "cannot store %s value in %s column %s.%s", vdbeMemTypeName(pIn1), sqlite3StdType[aCol[i].eCType-1], pTab->zName, aCol[i].zCnName); rc = SQLITE_CONSTRAINT_DATATYPE; goto abort_due_to_error; } /* Opcode: Affinity P1 P2 * P4 * ** Synopsis: affinity(r[P1@P2]) ** ** Apply affinities to a range of P2 registers starting with P1. ** ** P4 is a string that is P2 characters long. The N-th character of the ** string indicates the column affinity that should be used for the N-th ** memory cell in the range. */ case OP_Affinity: { const char *zAffinity; /* The affinity to be applied */ zAffinity = pOp->p4.z; assert( zAffinity!=0 ); assert( pOp->p2>0 ); assert( zAffinity[pOp->p2]==0 ); pIn1 = &aMem[pOp->p1]; while( 1 /*exit-by-break*/ ){ assert( pIn1 <= &p->aMem[(p->nMem+1 - p->nCursor)] ); assert( zAffinity[0]==SQLITE_AFF_NONE || memIsValid(pIn1) ); applyAffinity(pIn1, zAffinity[0], encoding); if( zAffinity[0]==SQLITE_AFF_REAL && (pIn1->flags & MEM_Int)!=0 ){ /* When applying REAL affinity, if the result is still an MEM_Int ** that will fit in 6 bytes, then change the type to MEM_IntReal ** so that we keep the high-resolution integer value but know that ** the type really wants to be REAL. */ testcase( pIn1->u.i==140737488355328LL ); testcase( pIn1->u.i==140737488355327LL ); testcase( pIn1->u.i==-140737488355328LL ); testcase( pIn1->u.i==-140737488355329LL ); if( pIn1->u.i<=140737488355327LL && pIn1->u.i>=-140737488355328LL ){ pIn1->flags |= MEM_IntReal; pIn1->flags &= ~MEM_Int; }else{ pIn1->u.r = (double)pIn1->u.i; pIn1->flags |= MEM_Real; pIn1->flags &= ~MEM_Int; } } REGISTER_TRACE((int)(pIn1-aMem), pIn1); zAffinity++; if( zAffinity[0]==0 ) break; pIn1++; } break; } /* Opcode: MakeRecord P1 P2 P3 P4 * ** Synopsis: r[P3]=mkrec(r[P1@P2]) ** ** Convert P2 registers beginning with P1 into the [record format] ** use as a data record in a database table or as a key ** in an index. The OP_Column opcode can decode the record later. ** ** P4 may be a string that is P2 characters long. The N-th character of the ** string indicates the column affinity that should be used for the N-th ** field of the index key. ** ** The mapping from character to affinity is given by the SQLITE_AFF_ ** macros defined in sqliteInt.h. ** ** If P4 is NULL then all index fields have the affinity BLOB. ** ** The meaning of P5 depends on whether or not the SQLITE_ENABLE_NULL_TRIM ** compile-time option is enabled: ** ** * If SQLITE_ENABLE_NULL_TRIM is enabled, then the P5 is the index ** of the right-most table that can be null-trimmed. ** ** * If SQLITE_ENABLE_NULL_TRIM is omitted, then P5 has the value ** OPFLAG_NOCHNG_MAGIC if the OP_MakeRecord opcode is allowed to ** accept no-change records with serial_type 10. This value is ** only used inside an assert() and does not affect the end result. */ case OP_MakeRecord: { Mem *pRec; /* The new record */ u64 nData; /* Number of bytes of data space */ int nHdr; /* Number of bytes of header space */ i64 nByte; /* Data space required for this record */ i64 nZero; /* Number of zero bytes at the end of the record */ int nVarint; /* Number of bytes in a varint */ u32 serial_type; /* Type field */ Mem *pData0; /* First field to be combined into the record */ Mem *pLast; /* Last field of the record */ int nField; /* Number of fields in the record */ char *zAffinity; /* The affinity string for the record */ int file_format; /* File format to use for encoding */ u32 len; /* Length of a field */ u8 *zHdr; /* Where to write next byte of the header */ u8 *zPayload; /* Where to write next byte of the payload */ /* Assuming the record contains N fields, the record format looks ** like this: ** ** ------------------------------------------------------------------------ ** | hdr-size | type 0 | type 1 | ... | type N-1 | data0 | ... | data N-1 | ** ------------------------------------------------------------------------ |
︙ | ︙ | |||
2822 2823 2824 2825 2826 2827 2828 | /* Apply the requested affinity to all inputs */ assert( pData0<=pLast ); if( zAffinity ){ pRec = pData0; do{ | | > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > | | < > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | > | | < | | | < < | | > | 3125 3126 3127 3128 3129 3130 3131 3132 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 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 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 | /* Apply the requested affinity to all inputs */ assert( pData0<=pLast ); if( zAffinity ){ pRec = pData0; do{ applyAffinity(pRec, zAffinity[0], encoding); if( zAffinity[0]==SQLITE_AFF_REAL && (pRec->flags & MEM_Int) ){ pRec->flags |= MEM_IntReal; pRec->flags &= ~(MEM_Int); } REGISTER_TRACE((int)(pRec-aMem), pRec); zAffinity++; pRec++; assert( zAffinity[0]==0 || pRec<=pLast ); }while( zAffinity[0] ); } #ifdef SQLITE_ENABLE_NULL_TRIM /* NULLs can be safely trimmed from the end of the record, as long as ** as the schema format is 2 or more and none of the omitted columns ** have a non-NULL default value. Also, the record must be left with ** at least one field. If P5>0 then it will be one more than the ** index of the right-most column with a non-NULL default value */ if( pOp->p5 ){ while( (pLast->flags & MEM_Null)!=0 && nField>pOp->p5 ){ pLast--; nField--; } } #endif /* Loop through the elements that will make up the record to figure ** out how much space is required for the new record. After this loop, ** the Mem.uTemp field of each term should hold the serial-type that will ** be used for that term in the generated record: ** ** Mem.uTemp value type ** --------------- --------------- ** 0 NULL ** 1 1-byte signed integer ** 2 2-byte signed integer ** 3 3-byte signed integer ** 4 4-byte signed integer ** 5 6-byte signed integer ** 6 8-byte signed integer ** 7 IEEE float ** 8 Integer constant 0 ** 9 Integer constant 1 ** 10,11 reserved for expansion ** N>=12 and even BLOB ** N>=13 and odd text ** ** The following additional values are computed: ** nHdr Number of bytes needed for the record header ** nData Number of bytes of data space needed for the record ** nZero Zero bytes at the end of the record */ pRec = pLast; do{ assert( memIsValid(pRec) ); if( pRec->flags & MEM_Null ){ if( pRec->flags & MEM_Zero ){ /* Values with MEM_Null and MEM_Zero are created by xColumn virtual ** table methods that never invoke sqlite3_result_xxxxx() while ** computing an unchanging column value in an UPDATE statement. ** Give such values a special internal-use-only serial-type of 10 ** so that they can be passed through to xUpdate and have ** a true sqlite3_value_nochange(). */ #ifndef SQLITE_ENABLE_NULL_TRIM assert( pOp->p5==OPFLAG_NOCHNG_MAGIC || CORRUPT_DB ); #endif pRec->uTemp = 10; }else{ pRec->uTemp = 0; } nHdr++; }else if( pRec->flags & (MEM_Int|MEM_IntReal) ){ /* Figure out whether to use 1, 2, 4, 6 or 8 bytes. */ i64 i = pRec->u.i; u64 uu; testcase( pRec->flags & MEM_Int ); testcase( pRec->flags & MEM_IntReal ); if( i<0 ){ uu = ~i; }else{ uu = i; } nHdr++; testcase( uu==127 ); testcase( uu==128 ); testcase( uu==32767 ); testcase( uu==32768 ); testcase( uu==8388607 ); testcase( uu==8388608 ); testcase( uu==2147483647 ); testcase( uu==2147483648 ); testcase( uu==140737488355327LL ); testcase( uu==140737488355328LL ); if( uu<=127 ){ if( (i&1)==i && file_format>=4 ){ pRec->uTemp = 8+(u32)uu; }else{ nData++; pRec->uTemp = 1; } }else if( uu<=32767 ){ nData += 2; pRec->uTemp = 2; }else if( uu<=8388607 ){ nData += 3; pRec->uTemp = 3; }else if( uu<=2147483647 ){ nData += 4; pRec->uTemp = 4; }else if( uu<=140737488355327LL ){ nData += 6; pRec->uTemp = 5; }else{ nData += 8; if( pRec->flags & MEM_IntReal ){ /* If the value is IntReal and is going to take up 8 bytes to store ** as an integer, then we might as well make it an 8-byte floating ** point value */ pRec->u.r = (double)pRec->u.i; pRec->flags &= ~MEM_IntReal; pRec->flags |= MEM_Real; pRec->uTemp = 7; }else{ pRec->uTemp = 6; } } }else if( pRec->flags & MEM_Real ){ nHdr++; nData += 8; pRec->uTemp = 7; }else{ assert( db->mallocFailed || pRec->flags&(MEM_Str|MEM_Blob) ); assert( pRec->n>=0 ); len = (u32)pRec->n; serial_type = (len*2) + 12 + ((pRec->flags & MEM_Str)!=0); if( pRec->flags & MEM_Zero ){ serial_type += pRec->u.nZero*2; if( nData ){ if( sqlite3VdbeMemExpandBlob(pRec) ) goto no_mem; len += pRec->u.nZero; }else{ nZero += pRec->u.nZero; } } nData += len; nHdr += sqlite3VarintLen(serial_type); pRec->uTemp = serial_type; } if( pRec==pData0 ) break; pRec--; }while(1); /* EVIDENCE-OF: R-22564-11647 The header begins with a single varint ** which determines the total number of bytes in the header. The varint ** value is the size of the header in bytes including the size varint |
︙ | ︙ | |||
2910 2911 2912 2913 2914 2915 2916 | if( nByte+nZero>db->aLimit[SQLITE_LIMIT_LENGTH] ){ goto too_big; } if( sqlite3VdbeMemClearAndResize(pOut, (int)nByte) ){ goto no_mem; } } | > > > > > > > | > | < | | | | < < < < < < < | | > > > > < > > > | | | > < > < | > | | 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 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 3368 3369 3370 3371 3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 | if( nByte+nZero>db->aLimit[SQLITE_LIMIT_LENGTH] ){ goto too_big; } if( sqlite3VdbeMemClearAndResize(pOut, (int)nByte) ){ goto no_mem; } } pOut->n = (int)nByte; pOut->flags = MEM_Blob; if( nZero ){ pOut->u.nZero = nZero; pOut->flags |= MEM_Zero; } UPDATE_MAX_BLOBSIZE(pOut); zHdr = (u8 *)pOut->z; zPayload = zHdr + nHdr; /* Write the record */ zHdr += putVarint32(zHdr, nHdr); assert( pData0<=pLast ); pRec = pData0; do{ serial_type = pRec->uTemp; /* EVIDENCE-OF: R-06529-47362 Following the size varint are one or more ** additional varints, one per column. */ zHdr += putVarint32(zHdr, serial_type); /* serial type */ /* EVIDENCE-OF: R-64536-51728 The values for each column in the record ** immediately follow the header. */ zPayload += sqlite3VdbeSerialPut(zPayload, pRec, serial_type); /* content */ }while( (++pRec)<=pLast ); assert( nHdr==(int)(zHdr - (u8*)pOut->z) ); assert( nByte==(int)(zPayload - (u8*)pOut->z) ); assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) ); REGISTER_TRACE(pOp->p3, pOut); break; } /* Opcode: Count P1 P2 p3 * * ** Synopsis: r[P2]=count() ** ** Store the number of entries (an integer value) in the table or index ** opened by cursor P1 in register P2. ** ** If P3==0, then an exact count is obtained, which involves visiting ** every btree page of the table. But if P3 is non-zero, an estimate ** is returned based on the current cursor position. */ case OP_Count: { /* out2 */ i64 nEntry; BtCursor *pCrsr; assert( p->apCsr[pOp->p1]->eCurType==CURTYPE_BTREE ); pCrsr = p->apCsr[pOp->p1]->uc.pCursor; assert( pCrsr ); if( pOp->p3 ){ nEntry = sqlite3BtreeRowCountEst(pCrsr); }else{ nEntry = 0; /* Not needed. Only used to silence a warning. */ rc = sqlite3BtreeCount(db, pCrsr, &nEntry); if( rc ) goto abort_due_to_error; } pOut = out2Prerelease(p, pOp); pOut->u.i = nEntry; goto check_for_interrupt; } /* Opcode: Savepoint P1 * * P4 * ** ** Open, release or rollback the savepoint named by parameter P4, depending ** on the value of P1. To open a new savepoint set P1==0 (SAVEPOINT_BEGIN). ** To release (commit) an existing savepoint set P1==1 (SAVEPOINT_RELEASE). ** To rollback an existing savepoint set P1==2 (SAVEPOINT_ROLLBACK). */ case OP_Savepoint: { int p1; /* Value of P1 operand */ char *zName; /* Name of savepoint */ int nName; Savepoint *pNew; Savepoint *pSavepoint; |
︙ | ︙ | |||
3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 | pNew->pNext = db->pSavepoint; db->pSavepoint = pNew; pNew->nDeferredCons = db->nDeferredCons; pNew->nDeferredImmCons = db->nDeferredImmCons; } } }else{ iSavepoint = 0; /* Find the named savepoint. If there is no such savepoint, then an ** an error is returned to the user. */ for( pSavepoint = db->pSavepoint; pSavepoint && sqlite3StrICmp(pSavepoint->zName, zName); | > | 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 | pNew->pNext = db->pSavepoint; db->pSavepoint = pNew; pNew->nDeferredCons = db->nDeferredCons; pNew->nDeferredImmCons = db->nDeferredImmCons; } } }else{ assert( p1==SAVEPOINT_RELEASE || p1==SAVEPOINT_ROLLBACK ); iSavepoint = 0; /* Find the named savepoint. If there is no such savepoint, then an ** an error is returned to the user. */ for( pSavepoint = db->pSavepoint; pSavepoint && sqlite3StrICmp(pSavepoint->zName, zName); |
︙ | ︙ | |||
3064 3065 3066 3067 3068 3069 3070 | }else{ /* Determine whether or not this is a transaction savepoint. If so, ** and this is a RELEASE command, then the current transaction ** is committed. */ int isTransaction = pSavepoint->pNext==0 && db->isTransactionSavepoint; | | < > > > > > > > | 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 | }else{ /* Determine whether or not this is a transaction savepoint. If so, ** and this is a RELEASE command, then the current transaction ** is committed. */ int isTransaction = pSavepoint->pNext==0 && db->isTransactionSavepoint; assert( db->eConcurrent==0 || db->isTransactionSavepoint==0 ); if( isTransaction && p1==SAVEPOINT_RELEASE ){ if( (rc = sqlite3VdbeCheckFk(p, 1))!=SQLITE_OK ){ goto vdbe_return; } db->autoCommit = 1; if( sqlite3VdbeHalt(p)==SQLITE_BUSY ){ p->pc = (int)(pOp - aOp); db->autoCommit = 0; p->rc = rc = SQLITE_BUSY; goto vdbe_return; } rc = p->rc; if( rc ){ db->autoCommit = 0; }else{ db->isTransactionSavepoint = 0; } }else{ int isSchemaChange; iSavepoint = db->nSavepoint - iSavepoint - 1; if( p1==SAVEPOINT_ROLLBACK ){ isSchemaChange = (db->mDbFlags & DBFLAG_SchemaChange)!=0; for(ii=0; ii<db->nDb; ii++){ rc = sqlite3BtreeTripAllCursors(db->aDb[ii].pBt, SQLITE_ABORT_ROLLBACK, isSchemaChange==0); if( rc!=SQLITE_OK ) goto abort_due_to_error; } }else{ assert( p1==SAVEPOINT_RELEASE ); isSchemaChange = 0; } for(ii=0; ii<db->nDb; ii++){ rc = sqlite3BtreeSavepoint(db->aDb[ii].pBt, p1, iSavepoint); if( rc!=SQLITE_OK ){ goto abort_due_to_error; } } if( isSchemaChange ){ sqlite3ExpirePreparedStatements(db, 0); sqlite3ResetAllSchemasOfConnection(db); db->mDbFlags |= DBFLAG_SchemaChange; } } if( rc ) goto abort_due_to_error; /* Regardless of whether this is a RELEASE or ROLLBACK, destroy all ** savepoints nested inside of the savepoint being operated on. */ while( db->pSavepoint!=pSavepoint ){ pTmp = db->pSavepoint; db->pSavepoint = pTmp->pNext; sqlite3DbFree(db, pTmp); |
︙ | ︙ | |||
3126 3127 3128 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139 | assert( pSavepoint==db->pSavepoint ); db->pSavepoint = pSavepoint->pNext; sqlite3DbFree(db, pSavepoint); if( !isTransaction ){ db->nSavepoint--; } }else{ db->nDeferredCons = pSavepoint->nDeferredCons; db->nDeferredImmCons = pSavepoint->nDeferredImmCons; } if( !isTransaction || p1==SAVEPOINT_ROLLBACK ){ rc = sqlite3VtabSavepoint(db, p1, iSavepoint); if( rc!=SQLITE_OK ) goto abort_due_to_error; | > | 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 3551 3552 | assert( pSavepoint==db->pSavepoint ); db->pSavepoint = pSavepoint->pNext; sqlite3DbFree(db, pSavepoint); if( !isTransaction ){ db->nSavepoint--; } }else{ assert( p1==SAVEPOINT_ROLLBACK ); db->nDeferredCons = pSavepoint->nDeferredCons; db->nDeferredImmCons = pSavepoint->nDeferredImmCons; } if( !isTransaction || p1==SAVEPOINT_ROLLBACK ){ rc = sqlite3VtabSavepoint(db, p1, iSavepoint); if( rc!=SQLITE_OK ) goto abort_due_to_error; |
︙ | ︙ | |||
3165 3166 3167 3168 3169 3170 3171 | desiredAutoCommit = pOp->p1; iRollback = pOp->p2; bConcurrent = pOp->p3; assert( desiredAutoCommit==1 || desiredAutoCommit==0 ); assert( desiredAutoCommit==1 || iRollback==0 ); assert( desiredAutoCommit==0 || bConcurrent==0 ); | | | | | 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 | desiredAutoCommit = pOp->p1; iRollback = pOp->p2; bConcurrent = pOp->p3; assert( desiredAutoCommit==1 || desiredAutoCommit==0 ); assert( desiredAutoCommit==1 || iRollback==0 ); assert( desiredAutoCommit==0 || bConcurrent==0 ); assert( db->autoCommit==0 || db->eConcurrent==CONCURRENT_NONE ); assert( db->nVdbeActive>0 ); /* At least this one VM is active */ assert( p->bIsReader ); if( desiredAutoCommit!=db->autoCommit ){ if( iRollback ){ assert( desiredAutoCommit==1 ); sqlite3RollbackAll(db, SQLITE_ABORT_ROLLBACK); db->autoCommit = 1; db->eConcurrent = CONCURRENT_NONE; }else if( desiredAutoCommit && (db->nVdbeWrite>0 || (db->eConcurrent && db->nVdbeActive>1)) ){ /* A transaction may only be committed if there are no other active ** writer VMs. If the transaction is CONCURRENT, then it may only be ** committed if there are no active VMs at all (readers or writers). ** ** If this instruction is a COMMIT and the transaction may not be ** committed due to one of the conditions above, return an error ** indicating that other VMs must complete before the COMMIT can |
︙ | ︙ | |||
3202 3203 3204 3205 3206 3207 3208 | if( (hrc & 0xFF)==SQLITE_BUSY ){ p->pc = (int)(pOp - aOp); db->autoCommit = (u8)(1-desiredAutoCommit); p->rc = hrc; rc = SQLITE_BUSY; goto vdbe_return; } | > | < | | > | 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 | if( (hrc & 0xFF)==SQLITE_BUSY ){ p->pc = (int)(pOp - aOp); db->autoCommit = (u8)(1-desiredAutoCommit); p->rc = hrc; rc = SQLITE_BUSY; goto vdbe_return; } assert( bConcurrent==CONCURRENT_NONE || bConcurrent==CONCURRENT_OPEN ); db->eConcurrent = (u8)bConcurrent; sqlite3CloseSavepoints(db); if( p->rc==SQLITE_OK ){ rc = SQLITE_DONE; }else{ rc = SQLITE_ERROR; } goto vdbe_return; }else{ sqlite3VdbeError(p, (!desiredAutoCommit)?"cannot start a transaction within a transaction":( (iRollback)?"cannot rollback - no transaction is active": "cannot commit - no transaction is active")); rc = SQLITE_ERROR; goto abort_due_to_error; } /*NOTREACHED*/ assert(0); } /* Opcode: Transaction P1 P2 P3 P4 P5 ** ** Begin a transaction on database P1 if a transaction is not already ** active. ** If P2 is non-zero, then a write-transaction is started, or if a ** read-transaction is already active, it is upgraded to a write-transaction. ** If P2 is zero, then a read-transaction is started. If P2 is 2 or more ** then an exclusive transaction is started. ** ** P1 is the index of the database file on which the transaction is ** started. Index 0 is the main database file and index 1 is the ** file used for temporary tables. Indices of 2 or more are used for ** attached databases. ** ** If a write-transaction is started and the Vdbe.usesStmtJournal flag is |
︙ | ︙ | |||
3263 3264 3265 3266 3267 3268 3269 3270 3271 | */ case OP_Transaction: { Btree *pBt; int iMeta = 0; assert( p->bIsReader ); assert( p->readOnly==0 || pOp->p2==0 ); assert( pOp->p1>=0 && pOp->p1<db->nDb ); assert( DbMaskTest(p->btreeMask, pOp->p1) ); | > > | > > | > > > > > | > | > | | 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 | */ case OP_Transaction: { Btree *pBt; int iMeta = 0; assert( p->bIsReader ); assert( p->readOnly==0 || pOp->p2==0 ); assert( pOp->p2>=0 && pOp->p2<=2 ); assert( pOp->p1>=0 && pOp->p1<db->nDb ); assert( DbMaskTest(p->btreeMask, pOp->p1) ); assert( rc==SQLITE_OK ); if( pOp->p2 && (db->flags & (SQLITE_QueryOnly|SQLITE_CorruptRdOnly))!=0 ){ if( db->flags & SQLITE_QueryOnly ){ /* Writes prohibited by the "PRAGMA query_only=TRUE" statement */ rc = SQLITE_READONLY; }else{ /* Writes prohibited due to a prior SQLITE_CORRUPT in the current ** transaction */ rc = SQLITE_CORRUPT; } goto abort_due_to_error; } pBt = db->aDb[pOp->p1].pBt; if( pBt ){ rc = sqlite3BtreeBeginTrans(pBt, pOp->p2, &iMeta); testcase( rc==SQLITE_BUSY_SNAPSHOT ); testcase( rc==SQLITE_BUSY_RECOVERY ); if( rc!=SQLITE_OK ){ if( (rc&0xff)==SQLITE_BUSY ){ p->pc = (int)(pOp - aOp); p->rc = rc; goto vdbe_return; } goto abort_due_to_error; } if( p->usesStmtJournal && pOp->p2 && (db->autoCommit==0 || db->nVdbeRead>1) ){ assert( sqlite3BtreeTxnState(pBt)==SQLITE_TXN_WRITE ); if( p->iStatement==0 ){ assert( db->nStatement>=0 && db->nSavepoint>=0 ); db->nStatement++; p->iStatement = db->nSavepoint + db->nStatement; } rc = sqlite3VtabSavepoint(db, SAVEPOINT_BEGIN, p->iStatement-1); if( rc==SQLITE_OK ){ rc = sqlite3BtreeBeginStmt(pBt, p->iStatement); } /* Store the current value of the database handles deferred constraint ** counter. If the statement transaction needs to be rolled back, ** the value of this counter needs to be restored too. */ p->nStmtDefCons = db->nDeferredCons; p->nStmtDefImmCons = db->nDeferredImmCons; } } assert( pOp->p5==0 || pOp->p4type==P4_INT32 ); if( rc==SQLITE_OK && pOp->p5 && (iMeta!=pOp->p3 || db->aDb[pOp->p1].pSchema->iGeneration!=pOp->p4.i) ){ /* ** IMPLEMENTATION-OF: R-03189-51135 As each SQL statement runs, the schema ** version is checked to ensure that the schema has not changed since the ** SQL statement was prepared. |
︙ | ︙ | |||
3372 3373 3374 3375 3376 3377 3378 | sqlite3BtreeGetMeta(db->aDb[iDb].pBt, iCookie, (u32 *)&iMeta); pOut = out2Prerelease(p, pOp); pOut->u.i = iMeta; break; } | | > > > > > | < | | 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 3844 3845 3846 3847 3848 3849 3850 3851 3852 | sqlite3BtreeGetMeta(db->aDb[iDb].pBt, iCookie, (u32 *)&iMeta); pOut = out2Prerelease(p, pOp); pOut->u.i = iMeta; break; } /* Opcode: SetCookie P1 P2 P3 * P5 ** ** Write the integer value P3 into cookie number P2 of database P1. ** P2==1 is the schema version. P2==2 is the database format. ** P2==3 is the recommended pager cache ** size, and so forth. P1==0 is the main database file and P1==1 is the ** database file used to store temporary tables. ** ** A transaction must be started before executing this opcode. ** ** If P2 is the SCHEMA_VERSION cookie (cookie number 1) then the internal ** schema version is set to P3-P5. The "PRAGMA schema_version=N" statement ** has P5 set to 1, so that the internal schema version will be different ** from the database schema version, resulting in a schema reset. */ case OP_SetCookie: { Db *pDb; sqlite3VdbeIncrWriteCounter(p, 0); assert( pOp->p2<SQLITE_N_BTREE_META ); assert( pOp->p1>=0 && pOp->p1<db->nDb ); assert( DbMaskTest(p->btreeMask, pOp->p1) ); assert( p->readOnly==0 ); pDb = &db->aDb[pOp->p1]; assert( pDb->pBt!=0 ); assert( sqlite3SchemaMutexHeld(db, pOp->p1, 0) ); #ifndef SQLITE_OMIT_CONCURRENT if( db->eConcurrent && (pOp->p2==BTREE_USER_VERSION || pOp->p2==BTREE_APPLICATION_ID) ){ rc = SQLITE_ERROR; sqlite3VdbeError(p, "cannot modify %s within CONCURRENT transaction", pOp->p2==BTREE_USER_VERSION ? "user_version" : "application_id" ); goto abort_due_to_error; } #endif /* See note about index shifting on OP_ReadCookie */ rc = sqlite3BtreeUpdateMeta(pDb->pBt, pOp->p2, pOp->p3); if( pOp->p2==BTREE_SCHEMA_VERSION ){ /* When the schema cookie changes, record the new cookie internally */ pDb->pSchema->schema_cookie = pOp->p3 - pOp->p5; db->mDbFlags |= DBFLAG_SchemaChange; }else if( pOp->p2==BTREE_FILE_FORMAT ){ /* Record changes in the file format */ pDb->pSchema->file_format = pOp->p3; } if( pOp->p1==1 ){ /* Invalidate all prepared statements whenever the TEMP database |
︙ | ︙ | |||
3440 3441 3442 3443 3444 3445 3446 | ** values need not be contiguous but all P1 values should be small integers. ** It is an error for P1 to be negative. ** ** Allowed P5 bits: ** <ul> ** <li> <b>0x02 OPFLAG_SEEKEQ</b>: This cursor will only be used for ** equality lookups (implemented as a pair of opcodes OP_SeekGE/OP_IdxGT | | | 3869 3870 3871 3872 3873 3874 3875 3876 3877 3878 3879 3880 3881 3882 3883 | ** values need not be contiguous but all P1 values should be small integers. ** It is an error for P1 to be negative. ** ** Allowed P5 bits: ** <ul> ** <li> <b>0x02 OPFLAG_SEEKEQ</b>: This cursor will only be used for ** equality lookups (implemented as a pair of opcodes OP_SeekGE/OP_IdxGT ** of OP_SeekLE/OP_IdxLT) ** </ul> ** ** The P4 value may be either an integer (P4_INT32) or a pointer to ** a KeyInfo structure (P4_KEYINFO). If it is a pointer to a KeyInfo ** object, then table being opened must be an [index b-tree] where the ** KeyInfo object defines the content and collating ** sequence of that index b-tree. Otherwise, if P4 is an integer |
︙ | ︙ | |||
3470 3471 3472 3473 3474 3475 3476 | ** be the same as every other ReopenIdx or OpenRead for the same cursor ** number. ** ** Allowed P5 bits: ** <ul> ** <li> <b>0x02 OPFLAG_SEEKEQ</b>: This cursor will only be used for ** equality lookups (implemented as a pair of opcodes OP_SeekGE/OP_IdxGT | | | 3899 3900 3901 3902 3903 3904 3905 3906 3907 3908 3909 3910 3911 3912 3913 | ** be the same as every other ReopenIdx or OpenRead for the same cursor ** number. ** ** Allowed P5 bits: ** <ul> ** <li> <b>0x02 OPFLAG_SEEKEQ</b>: This cursor will only be used for ** equality lookups (implemented as a pair of opcodes OP_SeekGE/OP_IdxGT ** of OP_SeekLE/OP_IdxLT) ** </ul> ** ** See also: OP_OpenRead, OP_OpenWrite */ /* Opcode: OpenWrite P1 P2 P3 P4 P5 ** Synopsis: root=P2 iDb=P3 ** |
︙ | ︙ | |||
3494 3495 3496 3497 3498 3499 3500 | ** value, then the table being opened must be a [table b-tree] with a ** number of columns no less than the value of P4. ** ** Allowed P5 bits: ** <ul> ** <li> <b>0x02 OPFLAG_SEEKEQ</b>: This cursor will only be used for ** equality lookups (implemented as a pair of opcodes OP_SeekGE/OP_IdxGT | | | > > | > > > > > | | 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 3953 3954 3955 3956 3957 3958 3959 3960 3961 3962 3963 3964 3965 3966 3967 3968 3969 3970 3971 3972 3973 3974 3975 3976 3977 3978 3979 3980 3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994 3995 3996 3997 3998 3999 4000 4001 4002 4003 4004 4005 4006 4007 4008 4009 4010 4011 4012 | ** value, then the table being opened must be a [table b-tree] with a ** number of columns no less than the value of P4. ** ** Allowed P5 bits: ** <ul> ** <li> <b>0x02 OPFLAG_SEEKEQ</b>: This cursor will only be used for ** equality lookups (implemented as a pair of opcodes OP_SeekGE/OP_IdxGT ** of OP_SeekLE/OP_IdxLT) ** <li> <b>0x08 OPFLAG_FORDELETE</b>: This cursor is used only to seek ** and subsequently delete entries in an index btree. This is a ** hint to the storage engine that the storage engine is allowed to ** ignore. The hint is not used by the official SQLite b*tree storage ** engine, but is used by COMDB2. ** <li> <b>0x10 OPFLAG_P2ISREG</b>: Use the content of register P2 ** as the root page, not the value of P2 itself. ** </ul> ** ** This instruction works like OpenRead except that it opens the cursor ** in read/write mode. ** ** See also: OP_OpenRead, OP_ReopenIdx */ case OP_ReopenIdx: { int nField; KeyInfo *pKeyInfo; u32 p2; int iDb; int wrFlag; Btree *pX; VdbeCursor *pCur; Db *pDb; assert( pOp->p5==0 || pOp->p5==OPFLAG_SEEKEQ ); assert( pOp->p4type==P4_KEYINFO ); pCur = p->apCsr[pOp->p1]; if( pCur && pCur->pgnoRoot==(u32)pOp->p2 ){ assert( pCur->iDb==pOp->p3 ); /* Guaranteed by the code generator */ assert( pCur->eCurType==CURTYPE_BTREE ); sqlite3BtreeClearCursor(pCur->uc.pCursor); goto open_cursor_set_hints; } /* If the cursor is not currently open or is open on a different ** index, then fall through into OP_OpenRead to force a reopen */ case OP_OpenRead: case OP_OpenWrite: assert( pOp->opcode==OP_OpenWrite || pOp->p5==0 || pOp->p5==OPFLAG_SEEKEQ ); assert( p->bIsReader ); assert( pOp->opcode==OP_OpenRead || pOp->opcode==OP_ReopenIdx || p->readOnly==0 ); if( p->expired==1 ){ rc = SQLITE_ABORT_ROLLBACK; goto abort_due_to_error; } nField = 0; pKeyInfo = 0; p2 = (u32)pOp->p2; iDb = pOp->p3; assert( iDb>=0 && iDb<db->nDb ); assert( DbMaskTest(p->btreeMask, iDb) ); pDb = &db->aDb[iDb]; pX = pDb->pBt; assert( pX!=0 ); if( pOp->opcode==OP_OpenWrite ){ #ifndef SQLITE_OMIT_CONCURRENT if( db->eConcurrent==CONCURRENT_OPEN && p2==1 && iDb!=1 ){ db->eConcurrent = CONCURRENT_SCHEMA; } #endif assert( OPFLAG_FORDELETE==BTREE_FORDELETE ); wrFlag = BTREE_WRCSR | (pOp->p5 & OPFLAG_FORDELETE); assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); if( pDb->pSchema->file_format < p->minWriteFileFormat ){ p->minWriteFileFormat = pDb->pSchema->file_format; } }else{ wrFlag = 0; } if( pOp->p5 & OPFLAG_P2ISREG ){ assert( p2>0 ); assert( p2<=(u32)(p->nMem+1 - p->nCursor) ); assert( pOp->opcode==OP_OpenWrite ); pIn2 = &aMem[p2]; assert( memIsValid(pIn2) ); assert( (pIn2->flags & MEM_Int)!=0 ); sqlite3VdbeMemIntegerify(pIn2); p2 = (int)pIn2->u.i; /* The p2 value always comes from a prior OP_CreateBtree opcode and |
︙ | ︙ | |||
3606 3607 3608 3609 3610 3611 3612 | ** since moved into the btree layer. */ pCur->isTable = pOp->p4type!=P4_KEYINFO; open_cursor_set_hints: assert( OPFLAG_BULKCSR==BTREE_BULKLOAD ); assert( OPFLAG_SEEKEQ==BTREE_SEEK_EQ ); testcase( pOp->p5 & OPFLAG_BULKCSR ); | < < > | > > > > > | | > > > > > > > | 4042 4043 4044 4045 4046 4047 4048 4049 4050 4051 4052 4053 4054 4055 4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075 4076 4077 4078 4079 4080 4081 4082 4083 4084 4085 4086 4087 4088 4089 4090 4091 4092 4093 4094 4095 4096 4097 4098 4099 4100 4101 4102 4103 4104 4105 4106 4107 4108 4109 4110 4111 4112 4113 4114 4115 4116 4117 4118 4119 4120 4121 4122 4123 | ** since moved into the btree layer. */ pCur->isTable = pOp->p4type!=P4_KEYINFO; open_cursor_set_hints: assert( OPFLAG_BULKCSR==BTREE_BULKLOAD ); assert( OPFLAG_SEEKEQ==BTREE_SEEK_EQ ); testcase( pOp->p5 & OPFLAG_BULKCSR ); testcase( pOp->p2 & OPFLAG_SEEKEQ ); sqlite3BtreeCursorHintFlags(pCur->uc.pCursor, (pOp->p5 & (OPFLAG_BULKCSR|OPFLAG_SEEKEQ))); if( rc ) goto abort_due_to_error; break; } /* Opcode: OpenDup P1 P2 * * * ** ** Open a new cursor P1 that points to the same ephemeral table as ** cursor P2. The P2 cursor must have been opened by a prior OP_OpenEphemeral ** opcode. Only ephemeral cursors may be duplicated. ** ** Duplicate ephemeral cursors are used for self-joins of materialized views. */ case OP_OpenDup: { VdbeCursor *pOrig; /* The original cursor to be duplicated */ VdbeCursor *pCx; /* The new cursor */ pOrig = p->apCsr[pOp->p2]; assert( pOrig ); assert( pOrig->isEphemeral ); /* Only ephemeral cursors can be duplicated */ pCx = allocateCursor(p, pOp->p1, pOrig->nField, -1, CURTYPE_BTREE); if( pCx==0 ) goto no_mem; pCx->nullRow = 1; pCx->isEphemeral = 1; pCx->pKeyInfo = pOrig->pKeyInfo; pCx->isTable = pOrig->isTable; pCx->pgnoRoot = pOrig->pgnoRoot; pCx->isOrdered = pOrig->isOrdered; pCx->pBtx = pOrig->pBtx; pCx->hasBeenDuped = 1; pOrig->hasBeenDuped = 1; rc = sqlite3BtreeCursor(pCx->pBtx, pCx->pgnoRoot, BTREE_WRCSR, pCx->pKeyInfo, pCx->uc.pCursor); /* The sqlite3BtreeCursor() routine can only fail for the first cursor ** opened for a database. Since there is already an open cursor when this ** opcode is run, the sqlite3BtreeCursor() cannot fail */ assert( rc==SQLITE_OK ); break; } /* Opcode: OpenEphemeral P1 P2 P3 P4 P5 ** Synopsis: nColumn=P2 ** ** Open a new cursor P1 to a transient table. ** The cursor is always opened read/write even if ** the main database is read-only. The ephemeral ** table is deleted automatically when the cursor is closed. ** ** If the cursor P1 is already opened on an ephemeral table, the table ** is cleared (all content is erased). ** ** P2 is the number of columns in the ephemeral table. ** The cursor points to a BTree table if P4==0 and to a BTree index ** if P4 is not 0. If P4 is not NULL, it points to a KeyInfo structure ** that defines the format of keys in the index. ** ** The P5 parameter can be a mask of the BTREE_* flags defined ** in btree.h. These flags control aspects of the operation of ** the btree. The BTREE_OMIT_JOURNAL and BTREE_SINGLE flags are ** added automatically. ** ** If P3 is positive, then reg[P3] is modified slightly so that it ** can be used as zero-length data for OP_Insert. This is an optimization ** that avoids an extra OP_Blob opcode to initialize that register. */ /* Opcode: OpenAutoindex P1 P2 * P4 * ** Synopsis: nColumn=P2 ** ** This opcode works the same as OP_OpenEphemeral. It has a ** different name to distinguish its use. Tables created using ** by this opcode will be used for automatically created transient |
︙ | ︙ | |||
3685 3686 3687 3688 3689 3690 3691 | SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_EXCLUSIVE | SQLITE_OPEN_DELETEONCLOSE | SQLITE_OPEN_TRANSIENT_DB; assert( pOp->p1>=0 ); assert( pOp->p2>=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 4156 4157 4158 4159 4160 4161 4162 4163 4164 4165 4166 4167 4168 4169 4170 4171 4172 4173 4174 4175 4176 4177 4178 4179 4180 4181 4182 4183 4184 4185 4186 4187 4188 4189 4190 4191 4192 4193 4194 4195 4196 4197 4198 4199 4200 4201 4202 4203 4204 4205 | SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_EXCLUSIVE | SQLITE_OPEN_DELETEONCLOSE | SQLITE_OPEN_TRANSIENT_DB; assert( pOp->p1>=0 ); assert( pOp->p2>=0 ); if( pOp->p3>0 ){ /* Make register reg[P3] into a value that can be used as the data ** form sqlite3BtreeInsert() where the length of the data is zero. */ assert( pOp->p2==0 ); /* Only used when number of columns is zero */ assert( pOp->opcode==OP_OpenEphemeral ); assert( aMem[pOp->p3].flags & MEM_Null ); aMem[pOp->p3].n = 0; aMem[pOp->p3].z = ""; } pCx = p->apCsr[pOp->p1]; if( pCx && !pCx->hasBeenDuped && ALWAYS(pOp->p2<=pCx->nField) ){ /* If the ephermeral table is already open and has no duplicates from ** OP_OpenDup, then erase all existing content so that the table is ** empty again, rather than creating a new table. */ assert( pCx->isEphemeral ); pCx->seqCount = 0; pCx->cacheStatus = CACHE_STALE; rc = sqlite3BtreeClearTable(pCx->pBtx, pCx->pgnoRoot, 0); }else{ pCx = allocateCursor(p, pOp->p1, pOp->p2, -1, CURTYPE_BTREE); if( pCx==0 ) goto no_mem; pCx->isEphemeral = 1; rc = sqlite3BtreeOpen(db->pVfs, 0, db, &pCx->pBtx, BTREE_OMIT_JOURNAL | BTREE_SINGLE | pOp->p5, vfsFlags); if( rc==SQLITE_OK ){ rc = sqlite3BtreeBeginTrans(pCx->pBtx, 1, 0); if( rc==SQLITE_OK ){ /* If a transient index is required, create it by calling ** sqlite3BtreeCreateTable() with the BTREE_BLOBKEY flag before ** opening it. If a transient table is required, just use the ** automatically created table with root-page 1 (an BLOB_INTKEY table). */ if( (pCx->pKeyInfo = pKeyInfo = pOp->p4.pKeyInfo)!=0 ){ assert( pOp->p4type==P4_KEYINFO ); rc = sqlite3BtreeCreateTable(pCx->pBtx, &pCx->pgnoRoot, BTREE_BLOBKEY | pOp->p5); if( rc==SQLITE_OK ){ assert( pCx->pgnoRoot==SCHEMA_ROOT+1 ); assert( pKeyInfo->db==db ); assert( pKeyInfo->enc==ENC(db) ); rc = sqlite3BtreeCursor(pCx->pBtx, pCx->pgnoRoot, BTREE_WRCSR, pKeyInfo, pCx->uc.pCursor); } pCx->isTable = 0; }else{ pCx->pgnoRoot = SCHEMA_ROOT; rc = sqlite3BtreeCursor(pCx->pBtx, SCHEMA_ROOT, BTREE_WRCSR, 0, pCx->uc.pCursor); pCx->isTable = 1; } } pCx->isOrdered = (pOp->p5!=BTREE_UNORDERED); if( rc ){ sqlite3BtreeClose(pCx->pBtx); } } } if( rc ) goto abort_due_to_error; pCx->nullRow = 1; break; } /* Opcode: SorterOpen P1 P2 P3 P4 * ** ** This opcode works like OP_OpenEphemeral except that it opens ** a transient index that is specifically designed to sort large |
︙ | ︙ | |||
3846 3847 3848 3849 3850 3851 3852 | ** that are used as an unpacked index key. ** ** Reposition cursor P1 so that it points to the smallest entry that ** is greater than or equal to the key value. If there are no records ** greater than or equal to the key and P2 is not zero, then jump to P2. ** ** If the cursor P1 was opened using the OPFLAG_SEEKEQ flag, then this | | | | | | > > | | 4318 4319 4320 4321 4322 4323 4324 4325 4326 4327 4328 4329 4330 4331 4332 4333 4334 4335 4336 4337 4338 4339 4340 4341 4342 4343 4344 4345 4346 4347 4348 4349 4350 4351 4352 4353 4354 | ** that are used as an unpacked index key. ** ** Reposition cursor P1 so that it points to the smallest entry that ** is greater than or equal to the key value. If there are no records ** greater than or equal to the key and P2 is not zero, then jump to P2. ** ** If the cursor P1 was opened using the OPFLAG_SEEKEQ flag, then this ** opcode will either land on a record that exactly matches the key, or ** else it will cause a jump to P2. When the cursor is OPFLAG_SEEKEQ, ** this opcode must be followed by an IdxLE opcode with the same arguments. ** The IdxGT opcode will be skipped if this opcode succeeds, but the ** IdxGT opcode will be used on subsequent loop iterations. The ** OPFLAG_SEEKEQ flags is a hint to the btree layer to say that this ** is an equality search. ** ** This opcode leaves the cursor configured to move in forward order, ** from the beginning toward the end. In other words, the cursor is ** configured to use Next, not Prev. ** ** See also: Found, NotFound, SeekLt, SeekGt, SeekLe */ /* Opcode: SeekGT P1 P2 P3 P4 * ** Synopsis: key=r[P3@P4] ** ** If cursor P1 refers to an SQL table (B-Tree that uses integer keys), ** use the value in register P3 as a key. If cursor P1 refers ** to an SQL index, then P3 is the first in an array of P4 registers ** that are used as an unpacked index key. ** ** Reposition cursor P1 so that it points to the smallest entry that ** is greater than the key value. If there are no records greater than ** the key and P2 is not zero, then jump to P2. ** ** This opcode leaves the cursor configured to move in forward order, ** from the beginning toward the end. In other words, the cursor is ** configured to use Next, not Prev. ** |
︙ | ︙ | |||
3911 3912 3913 3914 3915 3916 3917 | ** less than or equal to the key and P2 is not zero, then jump to P2. ** ** This opcode leaves the cursor configured to move in reverse order, ** from the end toward the beginning. In other words, the cursor is ** configured to use Prev, not Next. ** ** If the cursor P1 was opened using the OPFLAG_SEEKEQ flag, then this | | | | | > > | 4385 4386 4387 4388 4389 4390 4391 4392 4393 4394 4395 4396 4397 4398 4399 4400 4401 4402 4403 4404 4405 | ** less than or equal to the key and P2 is not zero, then jump to P2. ** ** This opcode leaves the cursor configured to move in reverse order, ** from the end toward the beginning. In other words, the cursor is ** configured to use Prev, not Next. ** ** If the cursor P1 was opened using the OPFLAG_SEEKEQ flag, then this ** opcode will either land on a record that exactly matches the key, or ** else it will cause a jump to P2. When the cursor is OPFLAG_SEEKEQ, ** this opcode must be followed by an IdxLE opcode with the same arguments. ** The IdxGE opcode will be skipped if this opcode succeeds, but the ** IdxGE opcode will be used on subsequent loop iterations. The ** OPFLAG_SEEKEQ flags is a hint to the btree layer to say that this ** is an equality search. ** ** See also: Found, NotFound, SeekGt, SeekGe, SeekLt */ case OP_SeekLT: /* jump, in3, group */ case OP_SeekLE: /* jump, in3, group */ case OP_SeekGE: /* jump, in3, group */ case OP_SeekGT: { /* jump, in3, group */ |
︙ | ︙ | |||
3948 3949 3950 3951 3952 3953 3954 3955 | oc = pOp->opcode; eqOnly = 0; pC->nullRow = 0; #ifdef SQLITE_DEBUG pC->seekOp = pOp->opcode; #endif if( pC->isTable ){ | > > > | > | | > > | > | < | | > | > > > | > > | | | | | | | > > > | 4424 4425 4426 4427 4428 4429 4430 4431 4432 4433 4434 4435 4436 4437 4438 4439 4440 4441 4442 4443 4444 4445 4446 4447 4448 4449 4450 4451 4452 4453 4454 4455 4456 4457 4458 4459 4460 4461 4462 4463 4464 4465 4466 4467 4468 4469 4470 4471 4472 4473 4474 4475 4476 4477 4478 4479 4480 4481 4482 4483 4484 4485 4486 4487 4488 4489 4490 4491 4492 4493 4494 4495 4496 4497 4498 4499 4500 4501 4502 4503 4504 4505 4506 4507 4508 4509 4510 4511 4512 4513 | oc = pOp->opcode; eqOnly = 0; pC->nullRow = 0; #ifdef SQLITE_DEBUG pC->seekOp = pOp->opcode; #endif pC->deferredMoveto = 0; pC->cacheStatus = CACHE_STALE; if( pC->isTable ){ u16 flags3, newType; /* The OPFLAG_SEEKEQ/BTREE_SEEK_EQ flag is only set on index cursors */ assert( sqlite3BtreeCursorHasHint(pC->uc.pCursor, BTREE_SEEK_EQ)==0 || CORRUPT_DB ); /* The input value in P3 might be of any type: integer, real, string, ** blob, or NULL. But it needs to be an integer before we can do ** the seek, so convert it. */ pIn3 = &aMem[pOp->p3]; flags3 = pIn3->flags; if( (flags3 & (MEM_Int|MEM_Real|MEM_IntReal|MEM_Str))==MEM_Str ){ applyNumericAffinity(pIn3, 0); } iKey = sqlite3VdbeIntValue(pIn3); /* Get the integer key value */ newType = pIn3->flags; /* Record the type after applying numeric affinity */ pIn3->flags = flags3; /* But convert the type back to its original */ /* If the P3 value could not be converted into an integer without ** loss of information, then special processing is required... */ if( (newType & (MEM_Int|MEM_IntReal))==0 ){ int c; if( (newType & MEM_Real)==0 ){ if( (newType & MEM_Null) || oc>=OP_SeekGE ){ VdbeBranchTaken(1,2); goto jump_to_p2; }else{ rc = sqlite3BtreeLast(pC->uc.pCursor, &res); if( rc!=SQLITE_OK ) goto abort_due_to_error; goto seek_not_found; } } c = sqlite3IntFloatCompare(iKey, pIn3->u.r); /* If the approximation iKey is larger than the actual real search ** term, substitute >= for > and < for <=. e.g. if the search term ** is 4.9 and the integer approximation 5: ** ** (x > 4.9) -> (x >= 5) ** (x <= 4.9) -> (x < 5) */ if( c>0 ){ assert( OP_SeekGE==(OP_SeekGT-1) ); assert( OP_SeekLT==(OP_SeekLE-1) ); assert( (OP_SeekLE & 0x0001)==(OP_SeekGT & 0x0001) ); if( (oc & 0x0001)==(OP_SeekGT & 0x0001) ) oc--; } /* If the approximation iKey is smaller than the actual real search ** term, substitute <= for < and > for >=. */ else if( c<0 ){ assert( OP_SeekLE==(OP_SeekLT+1) ); assert( OP_SeekGT==(OP_SeekGE+1) ); assert( (OP_SeekLT & 0x0001)==(OP_SeekGE & 0x0001) ); if( (oc & 0x0001)==(OP_SeekLT & 0x0001) ) oc++; } } rc = sqlite3BtreeTableMoveto(pC->uc.pCursor, (u64)iKey, 0, &res); pC->movetoTarget = iKey; /* Used by OP_Delete */ if( rc!=SQLITE_OK ){ goto abort_due_to_error; } }else{ /* For a cursor with the OPFLAG_SEEKEQ/BTREE_SEEK_EQ hint, only the ** OP_SeekGE and OP_SeekLE opcodes are allowed, and these must be ** immediately followed by an OP_IdxGT or OP_IdxLT opcode, respectively, ** with the same key. */ if( sqlite3BtreeCursorHasHint(pC->uc.pCursor, BTREE_SEEK_EQ) ){ eqOnly = 1; assert( pOp->opcode==OP_SeekGE || pOp->opcode==OP_SeekLE ); assert( pOp[1].opcode==OP_IdxLT || pOp[1].opcode==OP_IdxGT ); assert( pOp->opcode==OP_SeekGE || pOp[1].opcode==OP_IdxLT ); assert( pOp->opcode==OP_SeekLE || pOp[1].opcode==OP_IdxGT ); assert( pOp[1].p1==pOp[0].p1 ); assert( pOp[1].p2==pOp[0].p2 ); assert( pOp[1].p3==pOp[0].p3 ); assert( pOp[1].p4.i==pOp[0].p4.i ); } nField = pOp->p4.i; |
︙ | ︙ | |||
4039 4040 4041 4042 4043 4044 4045 | assert( oc!=OP_SeekLT || r.default_rc==+1 ); r.aMem = &aMem[pOp->p3]; #ifdef SQLITE_DEBUG { int i; for(i=0; i<r.nField; i++) assert( memIsValid(&r.aMem[i]) ); } #endif r.eqSeen = 0; | | < < | 4530 4531 4532 4533 4534 4535 4536 4537 4538 4539 4540 4541 4542 4543 4544 4545 4546 4547 4548 4549 4550 4551 4552 | assert( oc!=OP_SeekLT || r.default_rc==+1 ); r.aMem = &aMem[pOp->p3]; #ifdef SQLITE_DEBUG { int i; for(i=0; i<r.nField; i++) assert( memIsValid(&r.aMem[i]) ); } #endif r.eqSeen = 0; rc = sqlite3BtreeIndexMoveto(pC->uc.pCursor, &r, &res); if( rc!=SQLITE_OK ){ goto abort_due_to_error; } if( eqOnly && r.eqSeen==0 ){ assert( res!=0 ); goto seek_not_found; } } #ifdef SQLITE_TEST sqlite3_search_count++; #endif if( oc>=OP_SeekGE ){ assert( oc==OP_SeekGE || oc==OP_SeekGT ); if( res<0 || (res==0 && oc==OP_SeekGT) ){ res = 0; rc = sqlite3BtreeNext(pC->uc.pCursor, 0); |
︙ | ︙ | |||
4100 4101 4102 4103 4104 4105 4106 | }else if( eqOnly ){ assert( pOp[1].opcode==OP_IdxLT || pOp[1].opcode==OP_IdxGT ); pOp++; /* Skip the OP_IdxLt or OP_IdxGT that follows */ } break; } | > | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > | < | > > > > > > | > > > > > > > > > > > > > > > > > > > > > > | 4589 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 | }else if( eqOnly ){ assert( pOp[1].opcode==OP_IdxLT || pOp[1].opcode==OP_IdxGT ); pOp++; /* Skip the OP_IdxLt or OP_IdxGT that follows */ } break; } /* Opcode: SeekScan P1 P2 * * * ** Synopsis: Scan-ahead up to P1 rows ** ** This opcode is a prefix opcode to OP_SeekGE. In other words, this ** opcode must be immediately followed by OP_SeekGE. This constraint is ** checked by assert() statements. ** ** This opcode uses the P1 through P4 operands of the subsequent ** OP_SeekGE. In the text that follows, the operands of the subsequent ** OP_SeekGE opcode are denoted as SeekOP.P1 through SeekOP.P4. Only ** the P1 and P2 operands of this opcode are also used, and are called ** This.P1 and This.P2. ** ** This opcode helps to optimize IN operators on a multi-column index ** where the IN operator is on the later terms of the index by avoiding ** unnecessary seeks on the btree, substituting steps to the next row ** of the b-tree instead. A correct answer is obtained if this opcode ** is omitted or is a no-op. ** ** The SeekGE.P3 and SeekGE.P4 operands identify an unpacked key which ** is the desired entry that we want the cursor SeekGE.P1 to be pointing ** to. Call this SeekGE.P4/P5 row the "target". ** ** If the SeekGE.P1 cursor is not currently pointing to a valid row, ** then this opcode is a no-op and control passes through into the OP_SeekGE. ** ** If the SeekGE.P1 cursor is pointing to a valid row, then that row ** might be the target row, or it might be near and slightly before the ** target row. This opcode attempts to position the cursor on the target ** row by, perhaps by invoking sqlite3BtreeStep() on the cursor ** between 0 and This.P1 times. ** ** There are three possible outcomes from this opcode:<ol> ** ** <li> If after This.P1 steps, the cursor is still pointing to a place that ** is earlier in the btree than the target row, then fall through ** into the subsquence OP_SeekGE opcode. ** ** <li> If the cursor is successfully moved to the target row by 0 or more ** sqlite3BtreeNext() calls, then jump to This.P2, which will land just ** past the OP_IdxGT or OP_IdxGE opcode that follows the OP_SeekGE. ** ** <li> If the cursor ends up past the target row (indicating the the target ** row does not exist in the btree) then jump to SeekOP.P2. ** </ol> */ case OP_SeekScan: { VdbeCursor *pC; int res; int nStep; UnpackedRecord r; assert( pOp[1].opcode==OP_SeekGE ); /* pOp->p2 points to the first instruction past the OP_IdxGT that ** follows the OP_SeekGE. */ assert( pOp->p2>=(int)(pOp-aOp)+2 ); assert( aOp[pOp->p2-1].opcode==OP_IdxGT || aOp[pOp->p2-1].opcode==OP_IdxGE ); testcase( aOp[pOp->p2-1].opcode==OP_IdxGE ); assert( pOp[1].p1==aOp[pOp->p2-1].p1 ); assert( pOp[1].p2==aOp[pOp->p2-1].p2 ); assert( pOp[1].p3==aOp[pOp->p2-1].p3 ); assert( pOp->p1>0 ); pC = p->apCsr[pOp[1].p1]; assert( pC!=0 ); assert( pC->eCurType==CURTYPE_BTREE ); assert( !pC->isTable ); if( !sqlite3BtreeCursorIsValidNN(pC->uc.pCursor) ){ #ifdef SQLITE_DEBUG if( db->flags&SQLITE_VdbeTrace ){ printf("... cursor not valid - fall through\n"); } #endif break; } nStep = pOp->p1; assert( nStep>=1 ); r.pKeyInfo = pC->pKeyInfo; r.nField = (u16)pOp[1].p4.i; r.default_rc = 0; r.aMem = &aMem[pOp[1].p3]; #ifdef SQLITE_DEBUG { int i; for(i=0; i<r.nField; i++){ assert( memIsValid(&r.aMem[i]) ); REGISTER_TRACE(pOp[1].p3+i, &aMem[pOp[1].p3+i]); } } #endif res = 0; /* Not needed. Only used to silence a warning. */ while(1){ rc = sqlite3VdbeIdxKeyCompare(db, pC, &r, &res); if( rc ) goto abort_due_to_error; if( res>0 ){ seekscan_search_fail: #ifdef SQLITE_DEBUG if( db->flags&SQLITE_VdbeTrace ){ printf("... %d steps and then skip\n", pOp->p1 - nStep); } #endif VdbeBranchTaken(1,3); pOp++; goto jump_to_p2; } if( res==0 ){ #ifdef SQLITE_DEBUG if( db->flags&SQLITE_VdbeTrace ){ printf("... %d steps and then success\n", pOp->p1 - nStep); } #endif VdbeBranchTaken(2,3); goto jump_to_p2; break; } if( nStep<=0 ){ #ifdef SQLITE_DEBUG if( db->flags&SQLITE_VdbeTrace ){ printf("... fall through after %d steps\n", pOp->p1); } #endif VdbeBranchTaken(0,3); break; } nStep--; rc = sqlite3BtreeNext(pC->uc.pCursor, 0); if( rc ){ if( rc==SQLITE_DONE ){ rc = SQLITE_OK; goto seekscan_search_fail; }else{ goto abort_due_to_error; } } } break; } /* Opcode: SeekHit P1 P2 P3 * * ** Synopsis: set P2<=seekHit<=P3 ** ** Increase or decrease the seekHit value for cursor P1, if necessary, ** so that it is no less than P2 and no greater than P3. ** ** The seekHit integer represents the maximum of terms in an index for which ** there is known to be at least one match. If the seekHit value is smaller ** than the total number of equality terms in an index lookup, then the ** OP_IfNoHope opcode might run to see if the IN loop can be abandoned ** early, thus saving work. This is part of the IN-early-out optimization. ** ** P1 must be a valid b-tree cursor. */ case OP_SeekHit: { VdbeCursor *pC; assert( pOp->p1>=0 && pOp->p1<p->nCursor ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); assert( pOp->p3>=pOp->p2 ); if( pC->seekHit<pOp->p2 ){ #ifdef SQLITE_DEBUG if( db->flags&SQLITE_VdbeTrace ){ printf("seekHit changes from %d to %d\n", pC->seekHit, pOp->p2); } #endif pC->seekHit = pOp->p2; }else if( pC->seekHit>pOp->p3 ){ #ifdef SQLITE_DEBUG if( db->flags&SQLITE_VdbeTrace ){ printf("seekHit changes from %d to %d\n", pC->seekHit, pOp->p3); } #endif pC->seekHit = pOp->p3; } break; } /* Opcode: IfNotOpen P1 P2 * * * ** Synopsis: if( !csr[P1] ) goto P2 ** ** If cursor P1 is not open, jump to instruction P2. Otherwise, fall through. */ case OP_IfNotOpen: { /* jump */ assert( pOp->p1>=0 && pOp->p1<p->nCursor ); VdbeBranchTaken(p->apCsr[pOp->p1]==0, 2); if( !p->apCsr[pOp->p1] ){ goto jump_to_p2_and_check_for_interrupt; } break; } /* Opcode: Found P1 P2 P3 P4 * ** Synopsis: key=r[P3@P4] ** ** If P4==0 then register P3 holds a blob constructed by MakeRecord. If |
︙ | ︙ | |||
4159 4160 4161 4162 4163 4164 4165 | ** ** See also: Found, NotExists, NoConflict, IfNoHope */ /* Opcode: IfNoHope P1 P2 P3 P4 * ** Synopsis: key=r[P3@P4] ** ** Register P3 is the first of P4 registers that form an unpacked | | > > < | < | | > > > > > | < | 4823 4824 4825 4826 4827 4828 4829 4830 4831 4832 4833 4834 4835 4836 4837 4838 4839 4840 4841 4842 4843 4844 4845 4846 4847 4848 4849 4850 | ** ** See also: Found, NotExists, NoConflict, IfNoHope */ /* Opcode: IfNoHope P1 P2 P3 P4 * ** Synopsis: key=r[P3@P4] ** ** Register P3 is the first of P4 registers that form an unpacked ** record. Cursor P1 is an index btree. P2 is a jump destination. ** In other words, the operands to this opcode are the same as the ** operands to OP_NotFound and OP_IdxGT. ** ** This opcode is an optimization attempt only. If this opcode always ** falls through, the correct answer is still obtained, but extra works ** is performed. ** ** A value of N in the seekHit flag of cursor P1 means that there exists ** a key P3:N that will match some record in the index. We want to know ** if it is possible for a record P3:P4 to match some record in the ** index. If it is not possible, we can skips some work. So if seekHit ** is less than P4, attempt to find out if a match is possible by running ** OP_NotFound. ** ** This opcode is used in IN clause processing for a multi-column key. ** If an IN clause is attached to an element of the key other than the ** left-most element, and if there are no matches on the most recent ** seek over the whole key, then it might be that one of the key element ** to the left is prohibiting a match, and hence there is "no hope" of ** any match regardless of how many IN clause elements are checked. |
︙ | ︙ | |||
4210 4211 4212 4213 4214 4215 4216 | ** See also: NotFound, Found, NotExists */ case OP_IfNoHope: { /* jump, in3 */ VdbeCursor *pC; assert( pOp->p1>=0 && pOp->p1<p->nCursor ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); | > > > > > | > | 4878 4879 4880 4881 4882 4883 4884 4885 4886 4887 4888 4889 4890 4891 4892 4893 4894 4895 4896 4897 4898 4899 | ** See also: NotFound, Found, NotExists */ case OP_IfNoHope: { /* jump, in3 */ VdbeCursor *pC; assert( pOp->p1>=0 && pOp->p1<p->nCursor ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); #ifdef SQLITE_DEBUG if( db->flags&SQLITE_VdbeTrace ){ printf("seekHit is %d\n", pC->seekHit); } #endif if( pC->seekHit>=pOp->p4.i ) break; /* Fall through into OP_NotFound */ /* no break */ deliberate_fall_through } case OP_NoConflict: /* jump, in3 */ case OP_NotFound: /* jump, in3 */ case OP_Found: { /* jump, in3 */ int alreadyExists; int takeJump; int ii; |
︙ | ︙ | |||
4275 4276 4277 4278 4279 4280 4281 | for(ii=0; ii<pIdxKey->nField; ii++){ if( pIdxKey->aMem[ii].flags & MEM_Null ){ takeJump = 1; break; } } } | | > | 4949 4950 4951 4952 4953 4954 4955 4956 4957 4958 4959 4960 4961 4962 4963 4964 4965 4966 4967 4968 4969 4970 4971 4972 4973 4974 4975 4976 4977 4978 4979 | for(ii=0; ii<pIdxKey->nField; ii++){ if( pIdxKey->aMem[ii].flags & MEM_Null ){ takeJump = 1; break; } } } rc = sqlite3BtreeIndexMoveto(pC->uc.pCursor, pIdxKey, &res); if( pFree ) sqlite3DbFreeNN(db, pFree); if( rc!=SQLITE_OK ){ goto abort_due_to_error; } pC->seekResult = res; alreadyExists = (res==0); pC->nullRow = 1-alreadyExists; pC->deferredMoveto = 0; pC->cacheStatus = CACHE_STALE; if( pOp->opcode==OP_Found ){ VdbeBranchTaken(alreadyExists!=0,2); if( alreadyExists ) goto jump_to_p2; }else{ VdbeBranchTaken(takeJump||alreadyExists==0,2); if( takeJump || !alreadyExists ) goto jump_to_p2; if( pOp->opcode==OP_IfNoHope ) pC->seekHit = pOp->p4.i; } break; } /* Opcode: SeekRowid P1 P2 P3 * * ** Synopsis: intkey=r[P3] ** |
︙ | ︙ | |||
4349 4350 4351 4352 4353 4354 4355 | case OP_SeekRowid: { /* jump, in3 */ VdbeCursor *pC; BtCursor *pCrsr; int res; u64 iKey; pIn3 = &aMem[pOp->p3]; | > > > > | | > > | | < | < | | | | > > > | < | | 5024 5025 5026 5027 5028 5029 5030 5031 5032 5033 5034 5035 5036 5037 5038 5039 5040 5041 5042 5043 5044 5045 5046 5047 5048 5049 5050 5051 5052 5053 5054 5055 5056 5057 5058 5059 5060 5061 5062 5063 5064 5065 5066 5067 5068 5069 5070 5071 5072 | case OP_SeekRowid: { /* jump, in3 */ VdbeCursor *pC; BtCursor *pCrsr; int res; u64 iKey; pIn3 = &aMem[pOp->p3]; testcase( pIn3->flags & MEM_Int ); testcase( pIn3->flags & MEM_IntReal ); testcase( pIn3->flags & MEM_Real ); testcase( (pIn3->flags & (MEM_Str|MEM_Int))==MEM_Str ); if( (pIn3->flags & (MEM_Int|MEM_IntReal))==0 ){ /* If pIn3->u.i does not contain an integer, compute iKey as the ** integer value of pIn3. Jump to P2 if pIn3 cannot be converted ** into an integer without loss of information. Take care to avoid ** changing the datatype of pIn3, however, as it is used by other ** parts of the prepared statement. */ Mem x = pIn3[0]; applyAffinity(&x, SQLITE_AFF_NUMERIC, encoding); if( (x.flags & MEM_Int)==0 ) goto jump_to_p2; iKey = x.u.i; goto notExistsWithKey; } /* Fall through into OP_NotExists */ /* no break */ deliberate_fall_through case OP_NotExists: /* jump, in3 */ pIn3 = &aMem[pOp->p3]; assert( (pIn3->flags & MEM_Int)!=0 || pOp->opcode==OP_SeekRowid ); assert( pOp->p1>=0 && pOp->p1<p->nCursor ); iKey = pIn3->u.i; notExistsWithKey: pC = p->apCsr[pOp->p1]; assert( pC!=0 ); #ifdef SQLITE_DEBUG if( pOp->opcode==OP_SeekRowid ) pC->seekOp = OP_SeekRowid; #endif assert( pC->isTable ); assert( pC->eCurType==CURTYPE_BTREE ); pCrsr = pC->uc.pCursor; assert( pCrsr!=0 ); res = 0; rc = sqlite3BtreeTableMoveto(pCrsr, iKey, 0, &res); assert( rc==SQLITE_OK || res==0 ); pC->movetoTarget = iKey; /* Used by OP_Delete */ pC->nullRow = 0; pC->cacheStatus = CACHE_STALE; pC->deferredMoveto = 0; VdbeBranchTaken(res!=0,2); pC->seekResult = res; |
︙ | ︙ | |||
4435 4436 4437 4438 4439 4440 4441 4442 4443 4444 4445 4446 4447 4448 4449 4450 | ** AUTOINCREMENT feature. */ case OP_NewRowid: { /* out2 */ i64 v; /* The new rowid */ VdbeCursor *pC; /* Cursor of table to get the new rowid */ int res; /* Result of an sqlite3BtreeLast() */ int cnt; /* Counter to limit the number of searches */ Mem *pMem; /* Register holding largest rowid for AUTOINCREMENT */ VdbeFrame *pFrame; /* Root frame of VDBE */ v = 0; res = 0; pOut = out2Prerelease(p, pOp); assert( pOp->p1>=0 && pOp->p1<p->nCursor ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); | > > | 5116 5117 5118 5119 5120 5121 5122 5123 5124 5125 5126 5127 5128 5129 5130 5131 5132 5133 | ** AUTOINCREMENT feature. */ case OP_NewRowid: { /* out2 */ i64 v; /* The new rowid */ VdbeCursor *pC; /* Cursor of table to get the new rowid */ int res; /* Result of an sqlite3BtreeLast() */ int cnt; /* Counter to limit the number of searches */ #ifndef SQLITE_OMIT_AUTOINCREMENT Mem *pMem; /* Register holding largest rowid for AUTOINCREMENT */ VdbeFrame *pFrame; /* Root frame of VDBE */ #endif v = 0; res = 0; pOut = out2Prerelease(p, pOp); assert( pOp->p1>=0 && pOp->p1<p->nCursor ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); |
︙ | ︙ | |||
4532 4533 4534 4535 4536 4537 4538 | ** it finds one that is not previously used. */ assert( pOp->p3==0 ); /* We cannot be in random rowid mode if this is ** an AUTOINCREMENT table. */ cnt = 0; do{ sqlite3_randomness(sizeof(v), &v); v &= (MAX_ROWID>>1); v++; /* Ensure that v is greater than zero */ | | | 5215 5216 5217 5218 5219 5220 5221 5222 5223 5224 5225 5226 5227 5228 5229 | ** it finds one that is not previously used. */ assert( pOp->p3==0 ); /* We cannot be in random rowid mode if this is ** an AUTOINCREMENT table. */ cnt = 0; do{ sqlite3_randomness(sizeof(v), &v); v &= (MAX_ROWID>>1); v++; /* Ensure that v is greater than zero */ }while( ((rc = sqlite3BtreeTableMoveto(pC->uc.pCursor, (u64)v, 0, &res))==SQLITE_OK) && (res==0) && (++cnt<100)); if( rc ) goto abort_due_to_error; if( res==0 ){ rc = SQLITE_FULL; /* IMP: R-38219-53002 */ goto abort_due_to_error; |
︙ | ︙ | |||
4587 4588 4589 4590 4591 4592 4593 | ** and register P2 becomes ephemeral. If the cursor is changed, the ** value of register P2 will then change. Make sure this does not ** cause any problems.) ** ** This instruction only works on tables. The equivalent instruction ** for indices is OP_IdxInsert. */ | < < < < < < | < > < | | | | | < < < < | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 5270 5271 5272 5273 5274 5275 5276 5277 5278 5279 5280 5281 5282 5283 5284 5285 5286 5287 5288 5289 5290 5291 5292 5293 5294 5295 5296 5297 5298 5299 5300 5301 5302 5303 5304 5305 5306 5307 5308 5309 5310 5311 5312 5313 5314 5315 5316 5317 5318 5319 5320 5321 5322 5323 5324 5325 5326 5327 5328 5329 5330 5331 5332 5333 5334 5335 5336 5337 5338 5339 5340 5341 5342 5343 5344 5345 5346 5347 5348 5349 5350 5351 5352 5353 5354 5355 5356 5357 5358 5359 5360 5361 5362 5363 5364 5365 5366 5367 5368 5369 5370 5371 5372 5373 5374 5375 5376 5377 5378 5379 5380 5381 5382 5383 5384 5385 5386 5387 5388 5389 5390 5391 5392 | ** and register P2 becomes ephemeral. If the cursor is changed, the ** value of register P2 will then change. Make sure this does not ** cause any problems.) ** ** This instruction only works on tables. The equivalent instruction ** for indices is OP_IdxInsert. */ case OP_Insert: { Mem *pData; /* MEM cell holding data for the record to be inserted */ Mem *pKey; /* MEM cell holding key for the record */ VdbeCursor *pC; /* Cursor to table into which insert is written */ int seekResult; /* Result of prior seek or 0 if no USESEEKRESULT flag */ const char *zDb; /* database name - used by the update hook */ Table *pTab; /* Table structure - used by update and pre-update hooks */ BtreePayload x; /* Payload to be inserted */ pData = &aMem[pOp->p2]; assert( pOp->p1>=0 && pOp->p1<p->nCursor ); assert( memIsValid(pData) ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); assert( pC->eCurType==CURTYPE_BTREE ); assert( pC->deferredMoveto==0 ); assert( pC->uc.pCursor!=0 ); assert( (pOp->p5 & OPFLAG_ISNOOP) || pC->isTable ); assert( pOp->p4type==P4_TABLE || pOp->p4type>=P4_STATIC ); REGISTER_TRACE(pOp->p2, pData); sqlite3VdbeIncrWriteCounter(p, pC); pKey = &aMem[pOp->p3]; assert( pKey->flags & MEM_Int ); assert( memIsValid(pKey) ); REGISTER_TRACE(pOp->p3, pKey); x.nKey = pKey->u.i; if( pOp->p4type==P4_TABLE && HAS_UPDATE_HOOK(db) ){ assert( pC->iDb>=0 ); zDb = db->aDb[pC->iDb].zDbSName; pTab = pOp->p4.pTab; assert( (pOp->p5 & OPFLAG_ISNOOP) || HasRowid(pTab) ); }else{ pTab = 0; zDb = 0; } #ifdef SQLITE_ENABLE_PREUPDATE_HOOK /* Invoke the pre-update hook, if any */ if( pTab ){ if( db->xPreUpdateCallback && !(pOp->p5 & OPFLAG_ISUPDATE) ){ sqlite3VdbePreUpdateHook(p,pC,SQLITE_INSERT,zDb,pTab,x.nKey,pOp->p2,-1); } if( db->xUpdateCallback==0 || pTab->aCol==0 ){ /* Prevent post-update hook from running in cases when it should not */ pTab = 0; } } if( pOp->p5 & OPFLAG_ISNOOP ) break; #endif if( pOp->p5 & OPFLAG_NCHANGE ) p->nChange++; if( pOp->p5 & OPFLAG_LASTROWID ) db->lastRowid = x.nKey; assert( (pData->flags & (MEM_Blob|MEM_Str))!=0 || pData->n==0 ); x.pData = pData->z; x.nData = pData->n; seekResult = ((pOp->p5 & OPFLAG_USESEEKRESULT) ? pC->seekResult : 0); if( pData->flags & MEM_Zero ){ x.nZero = pData->u.nZero; }else{ x.nZero = 0; } x.pKey = 0; rc = sqlite3BtreeInsert(pC->uc.pCursor, &x, (pOp->p5 & (OPFLAG_APPEND|OPFLAG_SAVEPOSITION|OPFLAG_PREFORMAT)), seekResult ); pC->deferredMoveto = 0; pC->cacheStatus = CACHE_STALE; /* Invoke the update-hook if required. */ if( rc ) goto abort_due_to_error; if( pTab ){ assert( db->xUpdateCallback!=0 ); assert( pTab->aCol!=0 ); db->xUpdateCallback(db->pUpdateArg, (pOp->p5 & OPFLAG_ISUPDATE) ? SQLITE_UPDATE : SQLITE_INSERT, zDb, pTab->zName, x.nKey); } break; } /* Opcode: RowCell P1 P2 P3 * * ** ** P1 and P2 are both open cursors. Both must be opened on the same type ** of table - intkey or index. This opcode is used as part of copying ** the current row from P2 into P1. If the cursors are opened on intkey ** tables, register P3 contains the rowid to use with the new record in ** P1. If they are opened on index tables, P3 is not used. ** ** This opcode must be followed by either an Insert or InsertIdx opcode ** with the OPFLAG_PREFORMAT flag set to complete the insert operation. */ case OP_RowCell: { VdbeCursor *pDest; /* Cursor to write to */ VdbeCursor *pSrc; /* Cursor to read from */ i64 iKey; /* Rowid value to insert with */ assert( pOp[1].opcode==OP_Insert || pOp[1].opcode==OP_IdxInsert ); assert( pOp[1].opcode==OP_Insert || pOp->p3==0 ); assert( pOp[1].opcode==OP_IdxInsert || pOp->p3>0 ); assert( pOp[1].p5 & OPFLAG_PREFORMAT ); pDest = p->apCsr[pOp->p1]; pSrc = p->apCsr[pOp->p2]; iKey = pOp->p3 ? aMem[pOp->p3].u.i : 0; rc = sqlite3BtreeTransferRow(pDest->uc.pCursor, pSrc->uc.pCursor, iKey); if( rc!=SQLITE_OK ) goto abort_due_to_error; break; }; /* Opcode: Delete P1 P2 P3 P4 P5 ** ** Delete the record at which the P1 cursor is currently pointing. ** ** If the OPFLAG_SAVEPOSITION bit of the P5 parameter is set, then ** the cursor will be left pointing at either the next or the previous |
︙ | ︙ | |||
4731 4732 4733 4734 4735 4736 4737 | assert( pC!=0 ); assert( pC->eCurType==CURTYPE_BTREE ); assert( pC->uc.pCursor!=0 ); assert( pC->deferredMoveto==0 ); sqlite3VdbeIncrWriteCounter(p, pC); #ifdef SQLITE_DEBUG | | > > > > | | | > | | | 5431 5432 5433 5434 5435 5436 5437 5438 5439 5440 5441 5442 5443 5444 5445 5446 5447 5448 5449 5450 5451 5452 5453 5454 5455 5456 5457 5458 5459 5460 5461 5462 5463 5464 5465 5466 5467 5468 5469 5470 5471 5472 5473 5474 5475 5476 5477 5478 5479 5480 5481 5482 5483 5484 5485 5486 5487 | assert( pC!=0 ); assert( pC->eCurType==CURTYPE_BTREE ); assert( pC->uc.pCursor!=0 ); assert( pC->deferredMoveto==0 ); sqlite3VdbeIncrWriteCounter(p, pC); #ifdef SQLITE_DEBUG if( pOp->p4type==P4_TABLE && HasRowid(pOp->p4.pTab) && pOp->p5==0 && sqlite3BtreeCursorIsValidNN(pC->uc.pCursor) ){ /* If p5 is zero, the seek operation that positioned the cursor prior to ** OP_Delete will have also set the pC->movetoTarget field to the rowid of ** the row that is being deleted */ i64 iKey = sqlite3BtreeIntegerKey(pC->uc.pCursor); assert( CORRUPT_DB || pC->movetoTarget==iKey ); } #endif /* If the update-hook or pre-update-hook will be invoked, set zDb to ** the name of the db to pass as to it. Also set local pTab to a copy ** of p4.pTab. Finally, if p5 is true, indicating that this cursor was ** last moved with OP_Next or OP_Prev, not Seek or NotFound, set ** VdbeCursor.movetoTarget to the current rowid. */ if( pOp->p4type==P4_TABLE && HAS_UPDATE_HOOK(db) ){ assert( pC->iDb>=0 ); assert( pOp->p4.pTab!=0 ); zDb = db->aDb[pC->iDb].zDbSName; pTab = pOp->p4.pTab; if( (pOp->p5 & OPFLAG_SAVEPOSITION)!=0 && pC->isTable ){ pC->movetoTarget = sqlite3BtreeIntegerKey(pC->uc.pCursor); } }else{ zDb = 0; pTab = 0; } #ifdef SQLITE_ENABLE_PREUPDATE_HOOK /* Invoke the pre-update-hook if required. */ assert( db->xPreUpdateCallback==0 || pTab==pOp->p4.pTab ); if( db->xPreUpdateCallback && pTab ){ assert( !(opflags & OPFLAG_ISUPDATE) || HasRowid(pTab)==0 || (aMem[pOp->p3].flags & MEM_Int) ); sqlite3VdbePreUpdateHook(p, pC, (opflags & OPFLAG_ISUPDATE) ? SQLITE_UPDATE : SQLITE_DELETE, zDb, pTab, pC->movetoTarget, pOp->p3, -1 ); } if( opflags & OPFLAG_ISNOOP ) break; #endif /* Only flags that can be set are SAVEPOISTION and AUXDELETE */ assert( (pOp->p5 & ~(OPFLAG_SAVEPOSITION|OPFLAG_AUXDELETE))==0 ); |
︙ | ︙ | |||
4801 4802 4803 4804 4805 4806 4807 | pC->cacheStatus = CACHE_STALE; pC->seekResult = 0; if( rc ) goto abort_due_to_error; /* Invoke the update-hook if required. */ if( opflags & OPFLAG_NCHANGE ){ p->nChange++; | | | 5506 5507 5508 5509 5510 5511 5512 5513 5514 5515 5516 5517 5518 5519 5520 | pC->cacheStatus = CACHE_STALE; pC->seekResult = 0; if( rc ) goto abort_due_to_error; /* Invoke the update-hook if required. */ if( opflags & OPFLAG_NCHANGE ){ p->nChange++; if( db->xUpdateCallback && ALWAYS(pTab!=0) && HasRowid(pTab) ){ db->xUpdateCallback(db->pUpdateArg, SQLITE_DELETE, zDb, pTab->zName, pC->movetoTarget); assert( pC->iDb>=0 ); } } break; |
︙ | ︙ | |||
4936 4937 4938 4939 4940 4941 4942 | ** If this where not the case, on of the following assert()s ** would fail. Should this ever change (because of changes in the code ** generator) then the fix would be to insert a call to ** sqlite3VdbeCursorMoveto(). */ assert( pC->deferredMoveto==0 ); assert( sqlite3BtreeCursorIsValid(pCrsr) ); | < < < < | | 5641 5642 5643 5644 5645 5646 5647 5648 5649 5650 5651 5652 5653 5654 5655 5656 5657 5658 5659 5660 5661 | ** If this where not the case, on of the following assert()s ** would fail. Should this ever change (because of changes in the code ** generator) then the fix would be to insert a call to ** sqlite3VdbeCursorMoveto(). */ assert( pC->deferredMoveto==0 ); assert( sqlite3BtreeCursorIsValid(pCrsr) ); n = sqlite3BtreePayloadSize(pCrsr); if( n>(u32)db->aLimit[SQLITE_LIMIT_LENGTH] ){ goto too_big; } testcase( n==0 ); rc = sqlite3VdbeMemFromBtreeZeroOffset(pCrsr, n, pOut); if( rc ) goto abort_due_to_error; if( !pOp->p3 ) Deephemeralize(pOut); UPDATE_MAX_BLOBSIZE(pOut); REGISTER_TRACE(pOp->p2, pOut); break; } |
︙ | ︙ | |||
5143 5144 5145 5146 5147 5148 5149 5150 | case OP_Sort: { /* jump */ #ifdef SQLITE_TEST sqlite3_sort_count++; sqlite3_search_count--; #endif p->aCounter[SQLITE_STMTSTATUS_SORT]++; /* Fall through into OP_Rewind */ } | > | < < < < > < < < | 5844 5845 5846 5847 5848 5849 5850 5851 5852 5853 5854 5855 5856 5857 5858 5859 5860 5861 5862 5863 5864 5865 5866 5867 5868 5869 5870 5871 5872 5873 5874 5875 5876 5877 5878 5879 5880 5881 5882 5883 5884 5885 5886 5887 5888 5889 5890 5891 5892 | case OP_Sort: { /* jump */ #ifdef SQLITE_TEST sqlite3_sort_count++; sqlite3_search_count--; #endif p->aCounter[SQLITE_STMTSTATUS_SORT]++; /* Fall through into OP_Rewind */ /* no break */ deliberate_fall_through } /* Opcode: Rewind P1 P2 * * * ** ** The next use of the Rowid or Column or Next instruction for P1 ** will refer to the first entry in the database table or index. ** If the table or index is empty, jump immediately to P2. ** If the table or index is not empty, fall through to the following ** instruction. ** ** This opcode leaves the cursor configured to move in forward order, ** from the beginning toward the end. In other words, the cursor is ** configured to use Next, not Prev. */ case OP_Rewind: { /* jump */ VdbeCursor *pC; BtCursor *pCrsr; int res; assert( pOp->p1>=0 && pOp->p1<p->nCursor ); assert( pOp->p5==0 ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); assert( isSorter(pC)==(pOp->opcode==OP_SorterSort) ); res = 1; #ifdef SQLITE_DEBUG pC->seekOp = OP_Rewind; #endif if( isSorter(pC) ){ rc = sqlite3VdbeSorterRewind(pC, &res); }else{ assert( pC->eCurType==CURTYPE_BTREE ); pCrsr = pC->uc.pCursor; assert( pCrsr ); rc = sqlite3BtreeFirst(pCrsr, &res); pC->deferredMoveto = 0; pC->cacheStatus = CACHE_STALE; } if( rc ) goto abort_due_to_error; pC->nullRow = (u8)res; assert( pOp->p2>0 && pOp->p2<p->nOp ); VdbeBranchTaken(res!=0,2); |
︙ | ︙ | |||
5276 5277 5278 5279 5280 5281 5282 | assert( pOp->opcode!=OP_Next || pOp->p4.xAdvance==sqlite3BtreeNext ); assert( pOp->opcode!=OP_Prev || pOp->p4.xAdvance==sqlite3BtreePrevious ); /* The Next opcode is only used after SeekGT, SeekGE, Rewind, and Found. ** The Prev opcode is only used after SeekLT, SeekLE, and Last. */ assert( pOp->opcode!=OP_Next || pC->seekOp==OP_SeekGT || pC->seekOp==OP_SeekGE | | | > | | 5972 5973 5974 5975 5976 5977 5978 5979 5980 5981 5982 5983 5984 5985 5986 5987 5988 5989 5990 5991 | assert( pOp->opcode!=OP_Next || pOp->p4.xAdvance==sqlite3BtreeNext ); assert( pOp->opcode!=OP_Prev || pOp->p4.xAdvance==sqlite3BtreePrevious ); /* The Next opcode is only used after SeekGT, SeekGE, Rewind, and Found. ** The Prev opcode is only used after SeekLT, SeekLE, and Last. */ assert( pOp->opcode!=OP_Next || pC->seekOp==OP_SeekGT || pC->seekOp==OP_SeekGE || pC->seekOp==OP_Rewind || pC->seekOp==OP_Found || pC->seekOp==OP_NullRow|| pC->seekOp==OP_SeekRowid || pC->seekOp==OP_IfNoHope); assert( pOp->opcode!=OP_Prev || pC->seekOp==OP_SeekLT || pC->seekOp==OP_SeekLE || pC->seekOp==OP_Last || pC->seekOp==OP_IfNoHope || pC->seekOp==OP_NullRow); rc = pOp->p4.xAdvance(pC->uc.pCursor, pOp->p3); next_tail: pC->cacheStatus = CACHE_STALE; VdbeBranchTaken(rc==SQLITE_OK,2); if( rc==SQLITE_OK ){ |
︙ | ︙ | |||
5329 5330 5331 5332 5333 5334 5335 | ** the OPFLAG_USESEEKRESULT flag must only be set if there have been no prior ** seeks on the cursor or if the most recent seek used a key equivalent ** to P2. ** ** This instruction only works for indices. The equivalent instruction ** for tables is OP_Insert. */ | < < < < < < < < | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > < | < < < < < < < < < < < < | > > > > > > > > < | > > > | 6026 6027 6028 6029 6030 6031 6032 6033 6034 6035 6036 6037 6038 6039 6040 6041 6042 6043 6044 6045 6046 6047 6048 6049 6050 6051 6052 6053 6054 6055 6056 6057 6058 6059 6060 6061 6062 6063 6064 6065 6066 6067 6068 6069 6070 6071 6072 6073 6074 6075 6076 6077 6078 6079 6080 6081 6082 6083 6084 6085 6086 6087 6088 6089 6090 6091 6092 6093 6094 6095 6096 6097 6098 6099 6100 6101 6102 6103 6104 6105 6106 6107 6108 6109 6110 6111 6112 6113 6114 6115 6116 6117 6118 6119 6120 6121 6122 6123 6124 6125 6126 6127 6128 6129 6130 6131 6132 6133 6134 6135 6136 | ** the OPFLAG_USESEEKRESULT flag must only be set if there have been no prior ** seeks on the cursor or if the most recent seek used a key equivalent ** to P2. ** ** This instruction only works for indices. The equivalent instruction ** for tables is OP_Insert. */ case OP_IdxInsert: { /* in2 */ VdbeCursor *pC; BtreePayload x; assert( pOp->p1>=0 && pOp->p1<p->nCursor ); pC = p->apCsr[pOp->p1]; sqlite3VdbeIncrWriteCounter(p, pC); assert( pC!=0 ); assert( !isSorter(pC) ); pIn2 = &aMem[pOp->p2]; assert( (pIn2->flags & MEM_Blob) || (pOp->p5 & OPFLAG_PREFORMAT) ); if( pOp->p5 & OPFLAG_NCHANGE ) p->nChange++; assert( pC->eCurType==CURTYPE_BTREE ); assert( pC->isTable==0 ); rc = ExpandBlob(pIn2); if( rc ) goto abort_due_to_error; x.nKey = pIn2->n; x.pKey = pIn2->z; x.aMem = aMem + pOp->p3; x.nMem = (u16)pOp->p4.i; rc = sqlite3BtreeInsert(pC->uc.pCursor, &x, (pOp->p5 & (OPFLAG_APPEND|OPFLAG_SAVEPOSITION|OPFLAG_PREFORMAT)), ((pOp->p5 & OPFLAG_USESEEKRESULT) ? pC->seekResult : 0) ); assert( pC->deferredMoveto==0 ); pC->cacheStatus = CACHE_STALE; if( rc) goto abort_due_to_error; break; } /* Opcode: SorterInsert P1 P2 * * * ** Synopsis: key=r[P2] ** ** Register P2 holds an SQL index key made using the ** MakeRecord instructions. This opcode writes that key ** into the sorter P1. Data for the entry is nil. */ case OP_SorterInsert: { /* in2 */ VdbeCursor *pC; assert( pOp->p1>=0 && pOp->p1<p->nCursor ); pC = p->apCsr[pOp->p1]; sqlite3VdbeIncrWriteCounter(p, pC); assert( pC!=0 ); assert( isSorter(pC) ); pIn2 = &aMem[pOp->p2]; assert( pIn2->flags & MEM_Blob ); assert( pC->isTable==0 ); rc = ExpandBlob(pIn2); if( rc ) goto abort_due_to_error; rc = sqlite3VdbeSorterWrite(pC, pIn2); if( rc) goto abort_due_to_error; break; } /* Opcode: IdxDelete P1 P2 P3 * P5 ** Synopsis: key=r[P2@P3] ** ** The content of P3 registers starting at register P2 form ** an unpacked index key. This opcode removes that entry from the ** index opened by cursor P1. ** ** If P5 is not zero, then raise an SQLITE_CORRUPT_INDEX error ** if no matching index entry is found. This happens when running ** an UPDATE or DELETE statement and the index entry to be updated ** or deleted is not found. For some uses of IdxDelete ** (example: the EXCEPT operator) it does not matter that no matching ** entry is found. For those cases, P5 is zero. Also, do not raise ** this (self-correcting and non-critical) error if in writable_schema mode. */ case OP_IdxDelete: { VdbeCursor *pC; BtCursor *pCrsr; int res; UnpackedRecord r; assert( pOp->p3>0 ); assert( pOp->p2>0 && pOp->p2+pOp->p3<=(p->nMem+1 - p->nCursor)+1 ); assert( pOp->p1>=0 && pOp->p1<p->nCursor ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); assert( pC->eCurType==CURTYPE_BTREE ); sqlite3VdbeIncrWriteCounter(p, pC); pCrsr = pC->uc.pCursor; assert( pCrsr!=0 ); r.pKeyInfo = pC->pKeyInfo; r.nField = (u16)pOp->p3; r.default_rc = 0; r.aMem = &aMem[pOp->p2]; rc = sqlite3BtreeIndexMoveto(pCrsr, &r, &res); if( rc ) goto abort_due_to_error; if( res==0 ){ rc = sqlite3BtreeDelete(pCrsr, BTREE_AUXDELETE); if( rc ) goto abort_due_to_error; }else if( pOp->p5 && !sqlite3WritableSchema(db) ){ rc = sqlite3ReportError(SQLITE_CORRUPT_INDEX, __LINE__, "index corruption"); goto abort_due_to_error; } assert( pC->deferredMoveto==0 ); pC->cacheStatus = CACHE_STALE; pC->seekResult = 0; break; } |
︙ | ︙ | |||
5480 5481 5482 5483 5484 5485 5486 5487 5488 5489 5490 5491 5492 5493 5494 5495 5496 5497 5498 | assert( pTabCur->uc.pCursor!=0 ); assert( pTabCur->isTable ); pTabCur->nullRow = 0; pTabCur->movetoTarget = rowid; pTabCur->deferredMoveto = 1; assert( pOp->p4type==P4_INTARRAY || pOp->p4.ai==0 ); pTabCur->aAltMap = pOp->p4.ai; pTabCur->pAltCursor = pC; }else{ pOut = out2Prerelease(p, pOp); pOut->u.i = rowid; } }else{ assert( pOp->opcode==OP_IdxRowid ); sqlite3VdbeMemSetNull(&aMem[pOp->p2]); } break; } | > > > > > > > > > > > > > > > > > > > > | | | | | 6200 6201 6202 6203 6204 6205 6206 6207 6208 6209 6210 6211 6212 6213 6214 6215 6216 6217 6218 6219 6220 6221 6222 6223 6224 6225 6226 6227 6228 6229 6230 6231 6232 6233 6234 6235 6236 6237 6238 6239 6240 6241 6242 6243 6244 6245 6246 6247 6248 6249 6250 6251 6252 6253 6254 6255 6256 6257 6258 6259 6260 6261 6262 6263 6264 6265 6266 6267 6268 6269 6270 6271 6272 6273 6274 6275 6276 6277 6278 6279 | assert( pTabCur->uc.pCursor!=0 ); assert( pTabCur->isTable ); pTabCur->nullRow = 0; pTabCur->movetoTarget = rowid; pTabCur->deferredMoveto = 1; assert( pOp->p4type==P4_INTARRAY || pOp->p4.ai==0 ); pTabCur->aAltMap = pOp->p4.ai; assert( !pC->isEphemeral ); assert( !pTabCur->isEphemeral ); pTabCur->pAltCursor = pC; }else{ pOut = out2Prerelease(p, pOp); pOut->u.i = rowid; } }else{ assert( pOp->opcode==OP_IdxRowid ); sqlite3VdbeMemSetNull(&aMem[pOp->p2]); } break; } /* Opcode: FinishSeek P1 * * * * ** ** If cursor P1 was previously moved via OP_DeferredSeek, complete that ** seek operation now, without further delay. If the cursor seek has ** already occurred, this instruction is a no-op. */ case OP_FinishSeek: { VdbeCursor *pC; /* The P1 index cursor */ assert( pOp->p1>=0 && pOp->p1<p->nCursor ); pC = p->apCsr[pOp->p1]; if( pC->deferredMoveto ){ rc = sqlite3VdbeFinishMoveto(pC); if( rc ) goto abort_due_to_error; } break; } /* Opcode: IdxGE P1 P2 P3 P4 * ** Synopsis: key=r[P3@P4] ** ** The P4 register values beginning with P3 form an unpacked index ** key that omits the PRIMARY KEY. Compare this key value against the index ** that P1 is currently pointing to, ignoring the PRIMARY KEY or ROWID ** fields at the end. ** ** If the P1 index entry is greater than or equal to the key value ** then jump to P2. Otherwise fall through to the next instruction. */ /* Opcode: IdxGT P1 P2 P3 P4 * ** Synopsis: key=r[P3@P4] ** ** The P4 register values beginning with P3 form an unpacked index ** key that omits the PRIMARY KEY. Compare this key value against the index ** that P1 is currently pointing to, ignoring the PRIMARY KEY or ROWID ** fields at the end. ** ** If the P1 index entry is greater than the key value ** then jump to P2. Otherwise fall through to the next instruction. */ /* Opcode: IdxLT P1 P2 P3 P4 * ** Synopsis: key=r[P3@P4] ** ** The P4 register values beginning with P3 form an unpacked index ** key that omits the PRIMARY KEY or ROWID. Compare this key value against ** the index that P1 is currently pointing to, ignoring the PRIMARY KEY or ** ROWID on the P1 index. ** ** If the P1 index entry is less than the key value then jump to P2. ** Otherwise fall through to the next instruction. */ /* Opcode: IdxLE P1 P2 P3 P4 * ** Synopsis: key=r[P3@P4] ** ** The P4 register values beginning with P3 form an unpacked index ** key that omits the PRIMARY KEY or ROWID. Compare this key value against ** the index that P1 is currently pointing to, ignoring the PRIMARY KEY or ** ROWID on the P1 index. ** |
︙ | ︙ | |||
5551 5552 5553 5554 5555 5556 5557 | assert( pOp->p1>=0 && pOp->p1<p->nCursor ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); assert( pC->isOrdered ); assert( pC->eCurType==CURTYPE_BTREE ); assert( pC->uc.pCursor!=0); assert( pC->deferredMoveto==0 ); | < | > > > > > > > > > > > > > > > > > > > > > > | > | | 6291 6292 6293 6294 6295 6296 6297 6298 6299 6300 6301 6302 6303 6304 6305 6306 6307 6308 6309 6310 6311 6312 6313 6314 6315 6316 6317 6318 6319 6320 6321 6322 6323 6324 6325 6326 6327 6328 6329 6330 6331 6332 6333 6334 6335 6336 6337 6338 6339 6340 6341 6342 6343 6344 6345 6346 6347 6348 6349 6350 6351 6352 6353 6354 6355 6356 6357 6358 6359 | assert( pOp->p1>=0 && pOp->p1<p->nCursor ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); assert( pC->isOrdered ); assert( pC->eCurType==CURTYPE_BTREE ); assert( pC->uc.pCursor!=0); assert( pC->deferredMoveto==0 ); assert( pOp->p4type==P4_INT32 ); r.pKeyInfo = pC->pKeyInfo; r.nField = (u16)pOp->p4.i; if( pOp->opcode<OP_IdxLT ){ assert( pOp->opcode==OP_IdxLE || pOp->opcode==OP_IdxGT ); r.default_rc = -1; }else{ assert( pOp->opcode==OP_IdxGE || pOp->opcode==OP_IdxLT ); r.default_rc = 0; } r.aMem = &aMem[pOp->p3]; #ifdef SQLITE_DEBUG { int i; for(i=0; i<r.nField; i++){ assert( memIsValid(&r.aMem[i]) ); REGISTER_TRACE(pOp->p3+i, &aMem[pOp->p3+i]); } } #endif /* Inlined version of sqlite3VdbeIdxKeyCompare() */ { i64 nCellKey = 0; BtCursor *pCur; Mem m; assert( pC->eCurType==CURTYPE_BTREE ); pCur = pC->uc.pCursor; assert( sqlite3BtreeCursorIsValid(pCur) ); nCellKey = sqlite3BtreePayloadSize(pCur); /* nCellKey will always be between 0 and 0xffffffff because of the way ** that btreeParseCellPtr() and sqlite3GetVarint32() are implemented */ if( nCellKey<=0 || nCellKey>0x7fffffff ){ rc = SQLITE_CORRUPT_BKPT; goto abort_due_to_error; } sqlite3VdbeMemInit(&m, db, 0); rc = sqlite3VdbeMemFromBtreeZeroOffset(pCur, (u32)nCellKey, &m); if( rc ) goto abort_due_to_error; res = sqlite3VdbeRecordCompareWithSkip(m.n, m.z, &r, 0); sqlite3VdbeMemRelease(&m); } /* End of inlined sqlite3VdbeIdxKeyCompare() */ assert( (OP_IdxLE&1)==(OP_IdxLT&1) && (OP_IdxGE&1)==(OP_IdxGT&1) ); if( (pOp->opcode&1)==(OP_IdxLT&1) ){ assert( pOp->opcode==OP_IdxLE || pOp->opcode==OP_IdxLT ); res = -res; }else{ assert( pOp->opcode==OP_IdxGE || pOp->opcode==OP_IdxGT ); res++; } VdbeBranchTaken(res>0,2); assert( rc==SQLITE_OK ); if( res>0 ) goto jump_to_p2; break; } /* Opcode: Destroy P1 P2 P3 * * ** ** Delete an entire database table or index whose root page in the database |
︙ | ︙ | |||
5658 5659 5660 5661 5662 5663 5664 | ** in the database file is given by P1. But, unlike Destroy, do not ** remove the table or index from the database file. ** ** The table being clear is in the main database file if P2==0. If ** P2==1 then the table to be clear is in the auxiliary database file ** that is used to store tables create using CREATE TEMPORARY TABLE. ** | | < | | | | | < < | 6420 6421 6422 6423 6424 6425 6426 6427 6428 6429 6430 6431 6432 6433 6434 6435 6436 6437 6438 6439 6440 6441 6442 6443 6444 6445 6446 6447 6448 | ** in the database file is given by P1. But, unlike Destroy, do not ** remove the table or index from the database file. ** ** The table being clear is in the main database file if P2==0. If ** P2==1 then the table to be clear is in the auxiliary database file ** that is used to store tables create using CREATE TEMPORARY TABLE. ** ** If the P3 value is non-zero, then the row change count is incremented ** by the number of rows in the table being cleared. If P3 is greater ** than zero, then the value stored in register P3 is also incremented ** by the number of rows in the table being cleared. ** ** See also: Destroy */ case OP_Clear: { i64 nChange; sqlite3VdbeIncrWriteCounter(p, 0); nChange = 0; assert( p->readOnly==0 ); assert( DbMaskTest(p->btreeMask, pOp->p2) ); rc = sqlite3BtreeClearTable(db->aDb[pOp->p2].pBt, (u32)pOp->p1, &nChange); if( pOp->p3 ){ p->nChange += nChange; if( pOp->p3>0 ){ assert( memIsValid(&aMem[pOp->p3]) ); memAboutToChange(p, &aMem[pOp->p3]); aMem[pOp->p3].u.i += nChange; } |
︙ | ︙ | |||
5723 5724 5725 5726 5727 5728 5729 | ** Allocate a new b-tree in the main database file if P1==0 or in the ** TEMP database file if P1==1 or in an attached database if ** P1>1. The P3 argument must be 1 (BTREE_INTKEY) for a rowid table ** it must be 2 (BTREE_BLOBKEY) for an index or WITHOUT ROWID table. ** The root page number of the new b-tree is stored in register P2. */ case OP_CreateBtree: { /* out2 */ | | | 6482 6483 6484 6485 6486 6487 6488 6489 6490 6491 6492 6493 6494 6495 6496 | ** Allocate a new b-tree in the main database file if P1==0 or in the ** TEMP database file if P1==1 or in an attached database if ** P1>1. The P3 argument must be 1 (BTREE_INTKEY) for a rowid table ** it must be 2 (BTREE_BLOBKEY) for an index or WITHOUT ROWID table. ** The root page number of the new b-tree is stored in register P2. */ case OP_CreateBtree: { /* out2 */ Pgno pgno; Db *pDb; sqlite3VdbeIncrWriteCounter(p, 0); pOut = out2Prerelease(p, pOp); pgno = 0; assert( pOp->p3==BTREE_INTKEY || pOp->p3==BTREE_BLOBKEY ); assert( pOp->p1>=0 && pOp->p1<db->nDb ); |
︙ | ︙ | |||
5756 5757 5758 5759 5760 5761 5762 | db->nSqlExec--; if( rc ) goto abort_due_to_error; break; } /* Opcode: ParseSchema P1 * * P4 * ** | | | | > > | | > | | > > > > > > > | 6515 6516 6517 6518 6519 6520 6521 6522 6523 6524 6525 6526 6527 6528 6529 6530 6531 6532 6533 6534 6535 6536 6537 6538 6539 6540 6541 6542 6543 6544 6545 6546 6547 6548 6549 6550 6551 6552 6553 6554 6555 6556 6557 6558 6559 6560 6561 6562 6563 6564 6565 6566 6567 6568 6569 6570 6571 6572 6573 6574 6575 6576 6577 6578 6579 6580 6581 6582 6583 6584 6585 6586 6587 6588 6589 6590 6591 6592 | db->nSqlExec--; if( rc ) goto abort_due_to_error; break; } /* Opcode: ParseSchema P1 * * P4 * ** ** Read and parse all entries from the schema table of database P1 ** that match the WHERE clause P4. If P4 is a NULL pointer, then the ** entire schema for P1 is reparsed. ** ** This opcode invokes the parser to create a new virtual machine, ** then runs the new virtual machine. It is thus a re-entrant opcode. */ case OP_ParseSchema: { int iDb; const char *zSchema; char *zSql; InitData initData; /* Any prepared statement that invokes this opcode will hold mutexes ** on every btree. This is a prerequisite for invoking ** sqlite3InitCallback(). */ #ifdef SQLITE_DEBUG for(iDb=0; iDb<db->nDb; iDb++){ assert( iDb==1 || sqlite3BtreeHoldsMutex(db->aDb[iDb].pBt) ); } #endif iDb = pOp->p1; assert( iDb>=0 && iDb<db->nDb ); assert( DbHasProperty(db, iDb, DB_SchemaLoaded) || db->mallocFailed || (CORRUPT_DB && (db->flags & SQLITE_NoSchemaError)!=0) ); #ifndef SQLITE_OMIT_ALTERTABLE if( pOp->p4.z==0 ){ sqlite3SchemaClear(db->aDb[iDb].pSchema); db->mDbFlags &= ~DBFLAG_SchemaKnownOk; rc = sqlite3InitOne(db, iDb, &p->zErrMsg, pOp->p5); db->mDbFlags |= DBFLAG_SchemaChange; p->expired = 0; }else #endif { zSchema = LEGACY_SCHEMA_TABLE; initData.db = db; initData.iDb = iDb; initData.pzErrMsg = &p->zErrMsg; initData.mInitFlags = 0; initData.mxPage = sqlite3BtreeLastPage(db->aDb[iDb].pBt); zSql = sqlite3MPrintf(db, "SELECT*FROM\"%w\".%s WHERE %s ORDER BY rowid", db->aDb[iDb].zDbSName, zSchema, pOp->p4.z); if( zSql==0 ){ rc = SQLITE_NOMEM_BKPT; }else{ assert( db->init.busy==0 ); db->init.busy = 1; initData.rc = SQLITE_OK; initData.nInitRow = 0; assert( !db->mallocFailed ); rc = sqlite3_exec(db, zSql, sqlite3InitCallback, &initData, 0); if( rc==SQLITE_OK ) rc = initData.rc; if( rc==SQLITE_OK && initData.nInitRow==0 ){ /* The OP_ParseSchema opcode with a non-NULL P4 argument should parse ** at least one SQL statement. Any less than that indicates that ** the sqlite_schema table is corrupt. */ rc = SQLITE_CORRUPT_BKPT; } sqlite3DbFreeNN(db, zSql); db->init.busy = 0; } } if( rc ){ sqlite3ResetAllSchemasOfConnection(db); if( rc==SQLITE_NOMEM ){ |
︙ | ︙ | |||
5904 5905 5906 5907 5908 5909 5910 | ** If P5 is not zero, the check is done on the auxiliary database ** file, not the main database file. ** ** This opcode is used to implement the integrity_check pragma. */ case OP_IntegrityCk: { int nRoot; /* Number of tables to check. (Number of root pages.) */ | | | | | | 6673 6674 6675 6676 6677 6678 6679 6680 6681 6682 6683 6684 6685 6686 6687 6688 6689 6690 6691 6692 6693 6694 6695 6696 6697 6698 6699 6700 6701 6702 6703 6704 6705 6706 6707 6708 6709 6710 6711 6712 6713 6714 6715 6716 6717 | ** If P5 is not zero, the check is done on the auxiliary database ** file, not the main database file. ** ** This opcode is used to implement the integrity_check pragma. */ case OP_IntegrityCk: { int nRoot; /* Number of tables to check. (Number of root pages.) */ Pgno *aRoot; /* Array of rootpage numbers for tables to be checked */ int nErr; /* Number of errors reported */ char *z; /* Text of the error report */ Mem *pnErr; /* Register keeping track of errors remaining */ assert( p->bIsReader ); nRoot = pOp->p2; aRoot = pOp->p4.ai; assert( nRoot>0 ); assert( aRoot[0]==(Pgno)nRoot ); assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) ); pnErr = &aMem[pOp->p3]; assert( (pnErr->flags & MEM_Int)!=0 ); assert( (pnErr->flags & (MEM_Str|MEM_Blob))==0 ); pIn1 = &aMem[pOp->p1]; assert( pOp->p5<db->nDb ); assert( DbMaskTest(p->btreeMask, pOp->p5) ); z = sqlite3BtreeIntegrityCheck(db, db->aDb[pOp->p5].pBt, &aRoot[1], nRoot, (int)pnErr->u.i+1, &nErr); sqlite3VdbeMemSetNull(pIn1); if( nErr==0 ){ assert( z==0 ); }else if( z==0 ){ goto no_mem; }else{ pnErr->u.i -= nErr-1; sqlite3VdbeMemSetStr(pIn1, z, -1, SQLITE_UTF8, sqlite3_free); } UPDATE_MAX_BLOBSIZE(pIn1); sqlite3VdbeChangeEncoding(pIn1, encoding); goto check_for_interrupt; } #endif /* SQLITE_OMIT_INTEGRITY_CHECK */ /* Opcode: RowSetAdd P1 P2 * * * ** Synopsis: rowset(P1)=r[P2] ** ** Insert the integer value held by register P2 into a RowSet object |
︙ | ︙ | |||
6172 6173 6174 6175 6176 6177 6178 6179 6180 | p->apCsr = (VdbeCursor **)&aMem[p->nMem]; pFrame->aOnce = (u8*)&p->apCsr[pProgram->nCsr]; memset(pFrame->aOnce, 0, (pProgram->nOp + 7)/8); p->aOp = aOp = pProgram->aOp; p->nOp = pProgram->nOp; #ifdef SQLITE_ENABLE_STMT_SCANSTATUS p->anExec = 0; #endif pOp = &aOp[-1]; | > > > > > > > > > > > | < | 6941 6942 6943 6944 6945 6946 6947 6948 6949 6950 6951 6952 6953 6954 6955 6956 6957 6958 6959 6960 6961 6962 6963 6964 6965 6966 6967 6968 | p->apCsr = (VdbeCursor **)&aMem[p->nMem]; pFrame->aOnce = (u8*)&p->apCsr[pProgram->nCsr]; memset(pFrame->aOnce, 0, (pProgram->nOp + 7)/8); p->aOp = aOp = pProgram->aOp; p->nOp = pProgram->nOp; #ifdef SQLITE_ENABLE_STMT_SCANSTATUS p->anExec = 0; #endif #ifdef SQLITE_DEBUG /* Verify that second and subsequent executions of the same trigger do not ** try to reuse register values from the first use. */ { int i; for(i=0; i<p->nMem; i++){ aMem[i].pScopyFrom = 0; /* Prevent false-positive AboutToChange() errs */ MemSetTypeFlag(&aMem[i], MEM_Undefined); /* Fault if this reg is reused */ } } #endif pOp = &aOp[-1]; goto check_for_interrupt; } /* Opcode: Param P1 P2 * * * ** ** This opcode is only ever present in sub-programs called via the ** OP_Program instruction. Copy a value currently stored in a memory ** cell of the calling (parent) frame to cell P2 in the current frames |
︙ | ︙ | |||
6443 6444 6445 6446 6447 6448 6449 6450 6451 6452 6453 6454 6455 6456 | pOp->p4.pCtx = pCtx; /* OP_AggInverse must have P1==1 and OP_AggStep must have P1==0 */ assert( pOp->p1==(pOp->opcode==OP_AggInverse) ); pOp->opcode = OP_AggStep1; /* Fall through into OP_AggStep */ } case OP_AggStep1: { int i; sqlite3_context *pCtx; Mem *pMem; assert( pOp->p4type==P4_FUNCCTX ); | > | 7222 7223 7224 7225 7226 7227 7228 7229 7230 7231 7232 7233 7234 7235 7236 | pOp->p4.pCtx = pCtx; /* OP_AggInverse must have P1==1 and OP_AggStep must have P1==0 */ assert( pOp->p1==(pOp->opcode==OP_AggInverse) ); pOp->opcode = OP_AggStep1; /* Fall through into OP_AggStep */ /* no break */ deliberate_fall_through } case OP_AggStep1: { int i; sqlite3_context *pCtx; Mem *pMem; assert( pOp->p4type==P4_FUNCCTX ); |
︙ | ︙ | |||
6547 6548 6549 6550 6551 6552 6553 6554 6555 6556 6557 6558 6559 6560 | Mem *pMem; assert( pOp->p1>0 && pOp->p1<=(p->nMem+1 - p->nCursor) ); assert( pOp->p3==0 || pOp->opcode==OP_AggValue ); pMem = &aMem[pOp->p1]; assert( (pMem->flags & ~(MEM_Null|MEM_Agg))==0 ); #ifndef SQLITE_OMIT_WINDOWFUNC if( pOp->p3 ){ rc = sqlite3VdbeMemAggValue(pMem, &aMem[pOp->p3], pOp->p4.pFunc); pMem = &aMem[pOp->p3]; }else #endif { rc = sqlite3VdbeMemFinalize(pMem, pOp->p4.pFunc); } | > | 7327 7328 7329 7330 7331 7332 7333 7334 7335 7336 7337 7338 7339 7340 7341 | Mem *pMem; assert( pOp->p1>0 && pOp->p1<=(p->nMem+1 - p->nCursor) ); assert( pOp->p3==0 || pOp->opcode==OP_AggValue ); pMem = &aMem[pOp->p1]; assert( (pMem->flags & ~(MEM_Null|MEM_Agg))==0 ); #ifndef SQLITE_OMIT_WINDOWFUNC if( pOp->p3 ){ memAboutToChange(p, &aMem[pOp->p3]); rc = sqlite3VdbeMemAggValue(pMem, &aMem[pOp->p3], pOp->p4.pFunc); pMem = &aMem[pOp->p3]; }else #endif { rc = sqlite3VdbeMemFinalize(pMem, pOp->p4.pFunc); } |
︙ | ︙ | |||
6643 6644 6645 6646 6647 6648 6649 6650 6651 6652 6653 6654 6655 6656 | assert( pOp->p1>=0 && pOp->p1<db->nDb ); assert( p->readOnly==0 ); pBt = db->aDb[pOp->p1].pBt; pPager = sqlite3BtreePager(pBt); eOld = sqlite3PagerGetJournalMode(pPager); if( eNew==PAGER_JOURNALMODE_QUERY ) eNew = eOld; if( !sqlite3PagerOkToChangeJournalMode(pPager) ) eNew = eOld; #ifndef SQLITE_OMIT_WAL zFilename = sqlite3PagerFilename(pPager, 1); /* Do not allow a transition to journal_mode=WAL for a database ** in temporary storage or if the VFS does not support shared memory | > | 7424 7425 7426 7427 7428 7429 7430 7431 7432 7433 7434 7435 7436 7437 7438 | assert( pOp->p1>=0 && pOp->p1<db->nDb ); assert( p->readOnly==0 ); pBt = db->aDb[pOp->p1].pBt; pPager = sqlite3BtreePager(pBt); eOld = sqlite3PagerGetJournalMode(pPager); if( eNew==PAGER_JOURNALMODE_QUERY ) eNew = eOld; assert( sqlite3BtreeHoldsMutex(pBt) ); if( !sqlite3PagerOkToChangeJournalMode(pPager) ) eNew = eOld; #ifndef SQLITE_OMIT_WAL zFilename = sqlite3PagerFilename(pPager, 1); /* Do not allow a transition to journal_mode=WAL for a database ** in temporary storage or if the VFS does not support shared memory |
︙ | ︙ | |||
6689 6690 6691 6692 6693 6694 6695 | ** as an intermediate */ sqlite3PagerSetJournalMode(pPager, PAGER_JOURNALMODE_OFF); } /* Open a transaction on the database file. Regardless of the journal ** mode, this transaction always uses a rollback journal. */ | | | 7471 7472 7473 7474 7475 7476 7477 7478 7479 7480 7481 7482 7483 7484 7485 | ** as an intermediate */ sqlite3PagerSetJournalMode(pPager, PAGER_JOURNALMODE_OFF); } /* Open a transaction on the database file. Regardless of the journal ** mode, this transaction always uses a rollback journal. */ assert( sqlite3BtreeTxnState(pBt)!=SQLITE_TXN_WRITE ); if( rc==SQLITE_OK ){ rc = sqlite3BtreeSetVersion(pBt, (eNew==PAGER_JOURNALMODE_WAL ? 2 : 1)); } } } #endif /* ifndef SQLITE_OMIT_WAL */ |
︙ | ︙ | |||
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 | if( !pOp->p1 ){ sqlite3ExpirePreparedStatements(db, pOp->p2); }else{ p->expired = pOp->p2+1; } break; } #ifndef SQLITE_OMIT_SHARED_CACHE /* Opcode: TableLock P1 P2 P3 P4 * ** Synopsis: iDb=P1 root=P2 write=P3 ** ** Obtain a lock on a particular table. This instruction is only used when ** the shared-cache feature is enabled. ** ** P1 is the index of the database in sqlite3.aDb[] of the database ** on which the lock is acquired. A readlock is obtained if P3==0 or ** a write lock if P3==1. ** ** P2 contains the root-page of the table to lock. ** ** P4 contains a pointer to the name of the table being locked. This is only ** used to generate an error message if the lock cannot be obtained. */ case OP_TableLock: { u8 isWriteLock = (u8)pOp->p3; #ifndef SQLITE_OMIT_CONCURRENT | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | < < | < | 7561 7562 7563 7564 7565 7566 7567 7568 7569 7570 7571 7572 7573 7574 7575 7576 7577 7578 7579 7580 7581 7582 7583 7584 7585 7586 7587 7588 7589 7590 7591 7592 7593 7594 7595 7596 7597 7598 7599 7600 7601 7602 7603 7604 7605 7606 7607 7608 7609 7610 7611 7612 7613 7614 7615 7616 7617 7618 7619 7620 7621 7622 7623 7624 7625 7626 | if( !pOp->p1 ){ sqlite3ExpirePreparedStatements(db, pOp->p2); }else{ p->expired = pOp->p2+1; } break; } /* Opcode: CursorLock P1 * * * * ** ** Lock the btree to which cursor P1 is pointing so that the btree cannot be ** written by an other cursor. */ case OP_CursorLock: { VdbeCursor *pC; assert( pOp->p1>=0 && pOp->p1<p->nCursor ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); assert( pC->eCurType==CURTYPE_BTREE ); sqlite3BtreeCursorPin(pC->uc.pCursor); break; } /* Opcode: CursorUnlock P1 * * * * ** ** Unlock the btree to which cursor P1 is pointing so that it can be ** written by other cursors. */ case OP_CursorUnlock: { VdbeCursor *pC; assert( pOp->p1>=0 && pOp->p1<p->nCursor ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); assert( pC->eCurType==CURTYPE_BTREE ); sqlite3BtreeCursorUnpin(pC->uc.pCursor); break; } #ifndef SQLITE_OMIT_SHARED_CACHE /* Opcode: TableLock P1 P2 P3 P4 * ** Synopsis: iDb=P1 root=P2 write=P3 ** ** Obtain a lock on a particular table. This instruction is only used when ** the shared-cache feature is enabled. ** ** P1 is the index of the database in sqlite3.aDb[] of the database ** on which the lock is acquired. A readlock is obtained if P3==0 or ** a write lock if P3==1. ** ** P2 contains the root-page of the table to lock. ** ** P4 contains a pointer to the name of the table being locked. This is only ** used to generate an error message if the lock cannot be obtained. */ case OP_TableLock: { u8 isWriteLock = (u8)pOp->p3; #ifndef SQLITE_OMIT_CONCURRENT if( isWriteLock && db->eConcurrent && pOp->p2==1 && pOp->p1!=1 ){ db->eConcurrent = CONCURRENT_SCHEMA; } #endif if( isWriteLock || 0==(db->flags&SQLITE_ReadUncommit) ){ int p1 = pOp->p1; assert( p1>=0 && p1<db->nDb ); assert( DbMaskTest(p->btreeMask, p1) ); assert( isWriteLock==0 || isWriteLock==1 ); |
︙ | ︙ | |||
6883 6884 6885 6886 6887 6888 6889 6890 6891 6892 6893 6894 6895 6896 | ** P4 is the name of a virtual table in database P1. Call the xDestroy method ** of that table. */ case OP_VDestroy: { db->nVDestroy++; rc = sqlite3VtabCallDestroy(db, pOp->p1, pOp->p4.z); db->nVDestroy--; if( rc ) goto abort_due_to_error; break; } #endif /* SQLITE_OMIT_VIRTUALTABLE */ #ifndef SQLITE_OMIT_VIRTUALTABLE /* Opcode: VOpen P1 * * P4 * | > | 7692 7693 7694 7695 7696 7697 7698 7699 7700 7701 7702 7703 7704 7705 7706 | ** P4 is the name of a virtual table in database P1. Call the xDestroy method ** of that table. */ case OP_VDestroy: { db->nVDestroy++; rc = sqlite3VtabCallDestroy(db, pOp->p1, pOp->p4.z); db->nVDestroy--; assert( p->errorAction==OE_Abort && p->usesStmtJournal ); if( rc ) goto abort_due_to_error; break; } #endif /* SQLITE_OMIT_VIRTUALTABLE */ #ifndef SQLITE_OMIT_VIRTUALTABLE /* Opcode: VOpen P1 * * P4 * |
︙ | ︙ | |||
6969 6970 6971 6972 6973 6974 6975 6976 6977 6978 6979 6980 6981 6982 6983 6984 6985 6986 | Mem **apArg; pQuery = &aMem[pOp->p3]; pArgc = &pQuery[1]; pCur = p->apCsr[pOp->p1]; assert( memIsValid(pQuery) ); REGISTER_TRACE(pOp->p3, pQuery); assert( pCur->eCurType==CURTYPE_VTAB ); pVCur = pCur->uc.pVCur; pVtab = pVCur->pVtab; pModule = pVtab->pModule; /* Grab the index number and argc parameters */ assert( (pQuery->flags&MEM_Int)!=0 && pArgc->flags==MEM_Int ); nArg = (int)pArgc->u.i; iQuery = (int)pQuery->u.i; /* Invoke the xFilter method */ | > < | 7779 7780 7781 7782 7783 7784 7785 7786 7787 7788 7789 7790 7791 7792 7793 7794 7795 7796 7797 7798 7799 7800 7801 7802 7803 7804 | Mem **apArg; pQuery = &aMem[pOp->p3]; pArgc = &pQuery[1]; pCur = p->apCsr[pOp->p1]; assert( memIsValid(pQuery) ); REGISTER_TRACE(pOp->p3, pQuery); assert( pCur!=0 ); assert( pCur->eCurType==CURTYPE_VTAB ); pVCur = pCur->uc.pVCur; pVtab = pVCur->pVtab; pModule = pVtab->pModule; /* Grab the index number and argc parameters */ assert( (pQuery->flags&MEM_Int)!=0 && pArgc->flags==MEM_Int ); nArg = (int)pArgc->u.i; iQuery = (int)pQuery->u.i; /* Invoke the xFilter method */ apArg = p->apArg; for(i = 0; i<nArg; i++){ apArg[i] = &pArgc[i+1]; } rc = pModule->xFilter(pVCur, iQuery, pOp->p4.z, nArg, apArg); sqlite3VtabImportErrmsg(p, pVtab); if( rc ) goto abort_due_to_error; |
︙ | ︙ | |||
7018 7019 7020 7021 7022 7023 7024 7025 7026 7027 7028 7029 7030 7031 7032 7033 7034 7035 7036 7037 | case OP_VColumn: { sqlite3_vtab *pVtab; const sqlite3_module *pModule; Mem *pDest; sqlite3_context sContext; VdbeCursor *pCur = p->apCsr[pOp->p1]; assert( pCur->eCurType==CURTYPE_VTAB ); assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) ); pDest = &aMem[pOp->p3]; memAboutToChange(p, pDest); if( pCur->nullRow ){ sqlite3VdbeMemSetNull(pDest); break; } pVtab = pCur->uc.pVCur->pVtab; pModule = pVtab->pModule; assert( pModule->xColumn ); memset(&sContext, 0, sizeof(sContext)); sContext.pOut = pDest; | > | | 7828 7829 7830 7831 7832 7833 7834 7835 7836 7837 7838 7839 7840 7841 7842 7843 7844 7845 7846 7847 7848 7849 7850 7851 7852 7853 7854 7855 7856 | case OP_VColumn: { sqlite3_vtab *pVtab; const sqlite3_module *pModule; Mem *pDest; sqlite3_context sContext; VdbeCursor *pCur = p->apCsr[pOp->p1]; assert( pCur!=0 ); assert( pCur->eCurType==CURTYPE_VTAB ); assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) ); pDest = &aMem[pOp->p3]; memAboutToChange(p, pDest); if( pCur->nullRow ){ sqlite3VdbeMemSetNull(pDest); break; } pVtab = pCur->uc.pVCur->pVtab; pModule = pVtab->pModule; assert( pModule->xColumn ); memset(&sContext, 0, sizeof(sContext)); sContext.pOut = pDest; assert( pOp->p5==OPFLAG_NOCHNG || pOp->p5==0 ); if( pOp->p5 & OPFLAG_NOCHNG ){ sqlite3VdbeMemSetNull(pDest); pDest->flags = MEM_Null|MEM_Zero; pDest->u.nZero = 0; }else{ MemSetTypeFlag(pDest, MEM_Null); } |
︙ | ︙ | |||
7070 7071 7072 7073 7074 7075 7076 | */ case OP_VNext: { /* jump */ sqlite3_vtab *pVtab; const sqlite3_module *pModule; int res; VdbeCursor *pCur; | < > | 7881 7882 7883 7884 7885 7886 7887 7888 7889 7890 7891 7892 7893 7894 7895 7896 | */ case OP_VNext: { /* jump */ sqlite3_vtab *pVtab; const sqlite3_module *pModule; int res; VdbeCursor *pCur; pCur = p->apCsr[pOp->p1]; assert( pCur!=0 ); assert( pCur->eCurType==CURTYPE_VTAB ); if( pCur->nullRow ){ break; } pVtab = pCur->uc.pVCur->pVtab; pModule = pVtab->pModule; assert( pModule->xNext ); |
︙ | ︙ | |||
7167 7168 7169 7170 7171 7172 7173 | ** apply in the case of a constraint failure on an insert or update. */ case OP_VUpdate: { sqlite3_vtab *pVtab; const sqlite3_module *pModule; int nArg; int i; | | | 7978 7979 7980 7981 7982 7983 7984 7985 7986 7987 7988 7989 7990 7991 7992 | ** apply in the case of a constraint failure on an insert or update. */ case OP_VUpdate: { sqlite3_vtab *pVtab; const sqlite3_module *pModule; int nArg; int i; sqlite_int64 rowid = 0; Mem **apArg; Mem *pX; assert( pOp->p2==1 || pOp->p5==OE_Fail || pOp->p5==OE_Rollback || pOp->p5==OE_Abort || pOp->p5==OE_Ignore || pOp->p5==OE_Replace ); assert( p->readOnly==0 ); |
︙ | ︙ | |||
7256 7257 7258 7259 7260 7261 7262 | if( newMax < (unsigned)pOp->p3 ) newMax = (unsigned)pOp->p3; } pOut->u.i = sqlite3BtreeMaxPageCount(pBt, newMax); break; } #endif | | | | > | > | | | | | | | > > | | | > | < > | | < < < < < < < < < < < < < < < < < < < < < < < < < > > | 8067 8068 8069 8070 8071 8072 8073 8074 8075 8076 8077 8078 8079 8080 8081 8082 8083 8084 8085 8086 8087 8088 8089 8090 8091 8092 8093 8094 8095 8096 8097 8098 8099 8100 8101 8102 8103 8104 8105 8106 8107 8108 8109 8110 8111 8112 8113 8114 8115 8116 8117 8118 8119 8120 8121 8122 8123 8124 8125 8126 8127 8128 8129 8130 8131 8132 8133 8134 8135 8136 8137 8138 8139 8140 8141 8142 8143 8144 8145 | if( newMax < (unsigned)pOp->p3 ) newMax = (unsigned)pOp->p3; } pOut->u.i = sqlite3BtreeMaxPageCount(pBt, newMax); break; } #endif /* Opcode: Function P1 P2 P3 P4 * ** Synopsis: r[P3]=func(r[P2@NP]) ** ** Invoke a user function (P4 is a pointer to an sqlite3_context object that ** contains a pointer to the function to be run) with arguments taken ** from register P2 and successors. The number of arguments is in ** the sqlite3_context object that P4 points to. ** The result of the function is stored ** in register P3. Register P3 must not be one of the function inputs. ** ** P1 is a 32-bit bitmask indicating whether or not each argument to the ** function was determined to be constant at compile time. If the first ** argument was constant then bit 0 of P1 is set. This is used to determine ** whether meta data associated with a user function argument using the ** sqlite3_set_auxdata() API may be safely retained until the next ** invocation of this opcode. ** ** See also: AggStep, AggFinal, PureFunc */ /* Opcode: PureFunc P1 P2 P3 P4 * ** Synopsis: r[P3]=func(r[P2@NP]) ** ** Invoke a user function (P4 is a pointer to an sqlite3_context object that ** contains a pointer to the function to be run) with arguments taken ** from register P2 and successors. The number of arguments is in ** the sqlite3_context object that P4 points to. ** The result of the function is stored ** in register P3. Register P3 must not be one of the function inputs. ** ** P1 is a 32-bit bitmask indicating whether or not each argument to the ** function was determined to be constant at compile time. If the first ** argument was constant then bit 0 of P1 is set. This is used to determine ** whether meta data associated with a user function argument using the ** sqlite3_set_auxdata() API may be safely retained until the next ** invocation of this opcode. ** ** This opcode works exactly like OP_Function. The only difference is in ** its name. This opcode is used in places where the function must be ** purely non-deterministic. Some built-in date/time functions can be ** either determinitic of non-deterministic, depending on their arguments. ** When those function are used in a non-deterministic way, they will check ** to see if they were called using OP_PureFunc instead of OP_Function, and ** if they were, they throw an error. ** ** See also: AggStep, AggFinal, Function */ case OP_PureFunc: /* group */ case OP_Function: { /* group */ int i; sqlite3_context *pCtx; assert( pOp->p4type==P4_FUNCCTX ); pCtx = pOp->p4.pCtx; /* If this function is inside of a trigger, the register array in aMem[] ** might change from one evaluation to the next. The next block of code ** checks to see if the register array has changed, and if so it ** reinitializes the relavant parts of the sqlite3_context object */ pOut = &aMem[pOp->p3]; if( pCtx->pOut != pOut ){ pCtx->pVdbe = p; pCtx->pOut = pOut; for(i=pCtx->argc-1; i>=0; i--) pCtx->argv[i] = &aMem[pOp->p2+i]; } assert( pCtx->pVdbe==p ); memAboutToChange(p, pOut); #ifdef SQLITE_DEBUG for(i=0; i<pCtx->argc; i++){ assert( memIsValid(pCtx->argv[i]) ); REGISTER_TRACE(pOp->p2+i, pCtx->argv[i]); } |
︙ | ︙ | |||
7426 7427 7428 7429 7430 7431 7432 | #ifndef SQLITE_OMIT_TRACE if( (db->mTrace & (SQLITE_TRACE_STMT|SQLITE_TRACE_LEGACY))!=0 && !p->doingRerun && (zTrace = (pOp->p4.z ? pOp->p4.z : p->zSql))!=0 ){ #ifndef SQLITE_OMIT_DEPRECATED if( db->mTrace & SQLITE_TRACE_LEGACY ){ | < | | | | 8219 8220 8221 8222 8223 8224 8225 8226 8227 8228 8229 8230 8231 8232 8233 8234 8235 8236 8237 8238 8239 8240 8241 8242 8243 | #ifndef SQLITE_OMIT_TRACE if( (db->mTrace & (SQLITE_TRACE_STMT|SQLITE_TRACE_LEGACY))!=0 && !p->doingRerun && (zTrace = (pOp->p4.z ? pOp->p4.z : p->zSql))!=0 ){ #ifndef SQLITE_OMIT_DEPRECATED if( db->mTrace & SQLITE_TRACE_LEGACY ){ char *z = sqlite3VdbeExpandSql(p, zTrace); db->trace.xLegacy(db->pTraceArg, z); sqlite3_free(z); }else #endif if( db->nVdbeExec>1 ){ char *z = sqlite3MPrintf(db, "-- %s", zTrace); (void)db->trace.xV2(SQLITE_TRACE_STMT, db->pTraceArg, p, z); sqlite3DbFree(db, z); }else{ (void)db->trace.xV2(SQLITE_TRACE_STMT, db->pTraceArg, p, zTrace); } } #ifdef SQLITE_USE_FCNTL_TRACE zTrace = (pOp->p4.z ? pOp->p4.z : p->zSql); if( zTrace ){ int j; for(j=0; j<db->nDb; j++){ |
︙ | ︙ | |||
7509 7510 7511 7512 7513 7514 7515 7516 7517 7518 7519 7520 7521 7522 | ** an active statement journal. */ case OP_Abortable: { sqlite3VdbeAssertAbortable(p); break; } #endif /* Opcode: Noop * * * * * ** ** Do nothing. This instruction is often useful as a jump ** destination. */ /* | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 8301 8302 8303 8304 8305 8306 8307 8308 8309 8310 8311 8312 8313 8314 8315 8316 8317 8318 8319 8320 8321 8322 8323 8324 8325 8326 8327 8328 8329 8330 8331 8332 8333 8334 8335 8336 8337 8338 8339 8340 8341 8342 8343 8344 8345 8346 8347 8348 8349 8350 8351 8352 8353 8354 8355 8356 8357 8358 8359 8360 8361 8362 8363 | ** an active statement journal. */ case OP_Abortable: { sqlite3VdbeAssertAbortable(p); break; } #endif #ifdef SQLITE_DEBUG /* Opcode: ReleaseReg P1 P2 P3 * P5 ** Synopsis: release r[P1@P2] mask P3 ** ** Release registers from service. Any content that was in the ** the registers is unreliable after this opcode completes. ** ** The registers released will be the P2 registers starting at P1, ** except if bit ii of P3 set, then do not release register P1+ii. ** In other words, P3 is a mask of registers to preserve. ** ** Releasing a register clears the Mem.pScopyFrom pointer. That means ** that if the content of the released register was set using OP_SCopy, ** a change to the value of the source register for the OP_SCopy will no longer ** generate an assertion fault in sqlite3VdbeMemAboutToChange(). ** ** If P5 is set, then all released registers have their type set ** to MEM_Undefined so that any subsequent attempt to read the released ** register (before it is reinitialized) will generate an assertion fault. ** ** P5 ought to be set on every call to this opcode. ** However, there are places in the code generator will release registers ** before their are used, under the (valid) assumption that the registers ** will not be reallocated for some other purpose before they are used and ** hence are safe to release. ** ** This opcode is only available in testing and debugging builds. It is ** not generated for release builds. The purpose of this opcode is to help ** validate the generated bytecode. This opcode does not actually contribute ** to computing an answer. */ case OP_ReleaseReg: { Mem *pMem; int i; u32 constMask; assert( pOp->p1>0 ); assert( pOp->p1+pOp->p2<=(p->nMem+1 - p->nCursor)+1 ); pMem = &aMem[pOp->p1]; constMask = pOp->p3; for(i=0; i<pOp->p2; i++, pMem++){ if( i>=32 || (constMask & MASKBIT32(i))==0 ){ pMem->pScopyFrom = 0; if( i<32 && pOp->p5 ) MemSetTypeFlag(pMem, MEM_Undefined); } } break; } #endif /* Opcode: Noop * * * * * ** ** Do nothing. This instruction is often useful as a jump ** destination. */ /* |
︙ | ︙ | |||
7561 7562 7563 7564 7565 7566 7567 7568 7569 7570 7571 7572 7573 7574 7575 7576 | if( rc!=0 ) printf("rc=%d\n",rc); if( opProperty & (OPFLG_OUT2) ){ registerTrace(pOrigOp->p2, &aMem[pOrigOp->p2]); } if( opProperty & OPFLG_OUT3 ){ registerTrace(pOrigOp->p3, &aMem[pOrigOp->p3]); } } #endif /* SQLITE_DEBUG */ #endif /* NDEBUG */ } /* The end of the for(;;) loop the loops through opcodes */ /* If we reach this point, it means that execution is finished with ** an error of some kind. */ abort_due_to_error: | > > > > > > | > > > > > > > > > > > > > > > > > > > > | > > > > > > > > | 8402 8403 8404 8405 8406 8407 8408 8409 8410 8411 8412 8413 8414 8415 8416 8417 8418 8419 8420 8421 8422 8423 8424 8425 8426 8427 8428 8429 8430 8431 8432 8433 8434 8435 8436 8437 8438 8439 8440 8441 8442 8443 8444 8445 8446 8447 8448 8449 8450 8451 8452 8453 8454 8455 8456 8457 8458 8459 8460 8461 8462 8463 8464 8465 8466 8467 8468 8469 8470 8471 8472 8473 8474 8475 8476 8477 8478 8479 8480 | if( rc!=0 ) printf("rc=%d\n",rc); if( opProperty & (OPFLG_OUT2) ){ registerTrace(pOrigOp->p2, &aMem[pOrigOp->p2]); } if( opProperty & OPFLG_OUT3 ){ registerTrace(pOrigOp->p3, &aMem[pOrigOp->p3]); } if( opProperty==0xff ){ /* Never happens. This code exists to avoid a harmless linkage ** warning aboud sqlite3VdbeRegisterDump() being defined but not ** used. */ sqlite3VdbeRegisterDump(p); } } #endif /* SQLITE_DEBUG */ #endif /* NDEBUG */ } /* The end of the for(;;) loop the loops through opcodes */ /* If we reach this point, it means that execution is finished with ** an error of some kind. */ abort_due_to_error: if( db->mallocFailed ){ rc = SQLITE_NOMEM_BKPT; }else if( rc==SQLITE_IOERR_CORRUPTFS ){ rc = SQLITE_CORRUPT_BKPT; } assert( rc ); #ifdef SQLITE_DEBUG if( db->flags & SQLITE_VdbeTrace ){ const char *zTrace = p->zSql; if( zTrace==0 ){ if( aOp[0].opcode==OP_Trace ){ zTrace = aOp[0].p4.z; } if( zTrace==0 ) zTrace = "???"; } printf("ABORT-due-to-error (rc=%d): %s\n", rc, zTrace); } #endif if( p->zErrMsg==0 && rc!=SQLITE_IOERR_NOMEM ){ sqlite3VdbeError(p, "%s", sqlite3ErrStr(rc)); } p->rc = rc; sqlite3SystemError(db, rc); testcase( sqlite3GlobalConfig.xLog!=0 ); sqlite3_log(rc, "statement aborts at %d: [%s] %s", (int)(pOp - aOp), p->zSql, p->zErrMsg); sqlite3VdbeHalt(p); if( rc==SQLITE_IOERR_NOMEM ) sqlite3OomFault(db); if( rc==SQLITE_CORRUPT && db->autoCommit==0 ){ db->flags |= SQLITE_CorruptRdOnly; } rc = SQLITE_ERROR; if( resetSchemaOnFault>0 ){ sqlite3ResetOneSchema(db, resetSchemaOnFault-1); } /* This is the only way out of this procedure. We have to ** release the mutexes on btrees that were acquired at the ** top. */ vdbe_return: #ifndef SQLITE_OMIT_PROGRESS_CALLBACK while( nVmStep>=nProgressLimit && db->xProgress!=0 ){ nProgressLimit += db->nProgressOps; if( db->xProgress(db->pProgressArg) ){ nProgressLimit = LARGEST_UINT64; rc = SQLITE_INTERRUPT; goto abort_due_to_error; } } #endif p->aCounter[SQLITE_STMTSTATUS_VM_STEP] += (int)nVmStep; sqlite3VdbeLeave(p); assert( rc!=SQLITE_OK || nExtraDelete==0 || sqlite3_strlike("DELETE%",p->zSql,0)!=0 ); return rc; |
︙ | ︙ | |||
7619 7620 7621 7622 7623 7624 7625 | rc = SQLITE_NOMEM_BKPT; goto abort_due_to_error; /* Jump to here if the sqlite3_interrupt() API sets the interrupt ** flag. */ abort_due_to_interrupt: | | | < < | 8494 8495 8496 8497 8498 8499 8500 8501 8502 8503 8504 | rc = SQLITE_NOMEM_BKPT; goto abort_due_to_error; /* Jump to here if the sqlite3_interrupt() API sets the interrupt ** flag. */ abort_due_to_interrupt: assert( AtomicLoad(&db->u1.isInterrupted) ); rc = SQLITE_INTERRUPT; goto abort_due_to_error; } |
Changes to src/vdbe.h.
︙ | ︙ | |||
53 54 55 56 57 58 59 | double *pReal; /* Used when p4type is P4_REAL */ FuncDef *pFunc; /* Used when p4type is P4_FUNCDEF */ sqlite3_context *pCtx; /* Used when p4type is P4_FUNCCTX */ CollSeq *pColl; /* Used when p4type is P4_COLLSEQ */ Mem *pMem; /* Used when p4type is P4_MEM */ VTable *pVtab; /* Used when p4type is P4_VTAB */ KeyInfo *pKeyInfo; /* Used when p4type is P4_KEYINFO */ | | | 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | double *pReal; /* Used when p4type is P4_REAL */ FuncDef *pFunc; /* Used when p4type is P4_FUNCDEF */ sqlite3_context *pCtx; /* Used when p4type is P4_FUNCCTX */ CollSeq *pColl; /* Used when p4type is P4_COLLSEQ */ Mem *pMem; /* Used when p4type is P4_MEM */ VTable *pVtab; /* Used when p4type is P4_VTAB */ KeyInfo *pKeyInfo; /* Used when p4type is P4_KEYINFO */ u32 *ai; /* Used when p4type is P4_INTARRAY */ SubProgram *pProgram; /* Used when p4type is P4_SUBPROGRAM */ Table *pTab; /* Used when p4type is P4_TABLE */ #ifdef SQLITE_ENABLE_CURSOR_HINTS Expr *pExpr; /* Used when p4type is P4_EXPR */ #endif int (*xAdvance)(BtCursor *, int); } p4; |
︙ | ︙ | |||
152 153 154 155 156 157 158 | # define COLNAME_N 1 /* Store only the name */ # else # define COLNAME_N 2 /* Store the name and decltype */ # endif #endif /* | | | < | | > > | 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 | # define COLNAME_N 1 /* Store only the name */ # else # define COLNAME_N 2 /* Store the name and decltype */ # endif #endif /* ** The following macro converts a label returned by sqlite3VdbeMakeLabel() ** into an index into the Parse.aLabel[] array that contains the resolved ** address of that label. */ #define ADDR(X) (~(X)) /* ** The makefile scans the vdbe.c source file and creates the "opcodes.h" ** header file that defines a number for each opcode used by the VDBE. */ #include "opcodes.h" /* ** Additional non-public SQLITE_PREPARE_* flags */ #define SQLITE_PREPARE_SAVESQL 0x80 /* Preserve SQL text */ #define SQLITE_PREPARE_MASK 0x0f /* Mask of public flags */ /* ** Prototypes for the VDBE interface. See comments on the implementation ** for a description of what each of these routines does. */ Vdbe *sqlite3VdbeCreate(Parse*); Parse *sqlite3VdbeParser(Vdbe*); int sqlite3VdbeAddOp0(Vdbe*,int); int sqlite3VdbeAddOp1(Vdbe*,int,int); int sqlite3VdbeAddOp2(Vdbe*,int,int,int); int sqlite3VdbeGoto(Vdbe*,int); int sqlite3VdbeLoadString(Vdbe*,int,const char*); void sqlite3VdbeMultiLoad(Vdbe*,int,const char*,...); int sqlite3VdbeAddOp3(Vdbe*,int,int,int,int); int sqlite3VdbeAddOp4(Vdbe*,int,int,int,int,const char *zP4,int); int sqlite3VdbeAddOp4Dup8(Vdbe*,int,int,int,int,const u8*,int); int sqlite3VdbeAddOp4Int(Vdbe*,int,int,int,int,int); int sqlite3VdbeAddFunctionCall(Parse*,int,int,int,int,const FuncDef*,int); void sqlite3VdbeEndCoroutine(Vdbe*,int); #if defined(SQLITE_DEBUG) && !defined(SQLITE_TEST_REALLOC_STRESS) void sqlite3VdbeVerifyNoMallocRequired(Vdbe *p, int N); void sqlite3VdbeVerifyNoResultRow(Vdbe *p); #else # define sqlite3VdbeVerifyNoMallocRequired(A,B) # define sqlite3VdbeVerifyNoResultRow(A) |
︙ | ︙ | |||
211 212 213 214 215 216 217 218 | # define ExplainQueryPlan(P) sqlite3VdbeExplain P # define ExplainQueryPlanPop(P) sqlite3VdbeExplainPop(P) # define ExplainQueryPlanParent(P) sqlite3VdbeExplainParent(P) #else # define ExplainQueryPlan(P) # define ExplainQueryPlanPop(P) # define ExplainQueryPlanParent(P) 0 #endif | > > > > > > | | | | | > > > > > > | | 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 | # define ExplainQueryPlan(P) sqlite3VdbeExplain P # define ExplainQueryPlanPop(P) sqlite3VdbeExplainPop(P) # define ExplainQueryPlanParent(P) sqlite3VdbeExplainParent(P) #else # define ExplainQueryPlan(P) # define ExplainQueryPlanPop(P) # define ExplainQueryPlanParent(P) 0 # define sqlite3ExplainBreakpoint(A,B) /*no-op*/ #endif #if defined(SQLITE_DEBUG) && !defined(SQLITE_OMIT_EXPLAIN) void sqlite3ExplainBreakpoint(const char*,const char*); #else # define sqlite3ExplainBreakpoint(A,B) /*no-op*/ #endif void sqlite3VdbeAddParseSchemaOp(Vdbe*, int, char*, u16); void sqlite3VdbeChangeOpcode(Vdbe*, int addr, u8); void sqlite3VdbeChangeP1(Vdbe*, int addr, int P1); void sqlite3VdbeChangeP2(Vdbe*, int addr, int P2); void sqlite3VdbeChangeP3(Vdbe*, int addr, int P3); void sqlite3VdbeChangeP5(Vdbe*, u16 P5); void sqlite3VdbeJumpHere(Vdbe*, int addr); void sqlite3VdbeJumpHereOrPopInst(Vdbe*, int addr); int sqlite3VdbeChangeToNoop(Vdbe*, int addr); int sqlite3VdbeDeletePriorOpcode(Vdbe*, u8 op); #ifdef SQLITE_DEBUG void sqlite3VdbeReleaseRegisters(Parse*,int addr, int n, u32 mask, int); #else # define sqlite3VdbeReleaseRegisters(P,A,N,M,F) #endif void sqlite3VdbeChangeP4(Vdbe*, int addr, const char *zP4, int N); void sqlite3VdbeAppendP4(Vdbe*, void *pP4, int p4type); void sqlite3VdbeSetP4KeyInfo(Parse*, Index*); void sqlite3VdbeUsesBtree(Vdbe*, int); VdbeOp *sqlite3VdbeGetOp(Vdbe*, int); int sqlite3VdbeMakeLabel(Parse*); void sqlite3VdbeRunOnlyOnce(Vdbe*); void sqlite3VdbeReusable(Vdbe*); void sqlite3VdbeDelete(Vdbe*); void sqlite3VdbeClearObject(sqlite3*,Vdbe*); void sqlite3VdbeMakeReady(Vdbe*,Parse*); int sqlite3VdbeFinalize(Vdbe*); void sqlite3VdbeResolveLabel(Vdbe*, int); |
︙ | ︙ | |||
269 270 271 272 273 274 275 | int sqlite3VdbeRecordCompare(int,const void*,UnpackedRecord*); int sqlite3VdbeRecordCompareWithSkip(int, const void *, UnpackedRecord *, int); UnpackedRecord *sqlite3VdbeAllocUnpackedRecord(KeyInfo*); typedef int (*RecordCompare)(int,const void*,UnpackedRecord*); RecordCompare sqlite3VdbeFindCompare(UnpackedRecord*); | < < > > > > | 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 | int sqlite3VdbeRecordCompare(int,const void*,UnpackedRecord*); int sqlite3VdbeRecordCompareWithSkip(int, const void *, UnpackedRecord *, int); UnpackedRecord *sqlite3VdbeAllocUnpackedRecord(KeyInfo*); typedef int (*RecordCompare)(int,const void*,UnpackedRecord*); RecordCompare sqlite3VdbeFindCompare(UnpackedRecord*); void sqlite3VdbeLinkSubProgram(Vdbe *, SubProgram *); int sqlite3VdbeHasSubProgram(Vdbe*); int sqlite3NotPureFunc(sqlite3_context*); #ifdef SQLITE_ENABLE_BYTECODE_VTAB int sqlite3VdbeBytecodeVtabInit(sqlite3*); #endif /* Use SQLITE_ENABLE_COMMENTS to enable generation of extra comments on ** each VDBE opcode. ** ** Use the SQLITE_ENABLE_MODULE_COMMENTS macro to see some extra no-op ** comments in VDBE programs that show key decision points in the code ** generator. |
︙ | ︙ |
Changes to src/vdbeInt.h.
︙ | ︙ | |||
27 28 29 30 31 32 33 | #endif /* ** VDBE_DISPLAY_P4 is true or false depending on whether or not the ** "explain" P4 display logic is enabled. */ #if !defined(SQLITE_OMIT_EXPLAIN) || !defined(NDEBUG) \ | | > | 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | #endif /* ** VDBE_DISPLAY_P4 is true or false depending on whether or not the ** "explain" P4 display logic is enabled. */ #if !defined(SQLITE_OMIT_EXPLAIN) || !defined(NDEBUG) \ || defined(VDBE_PROFILE) || defined(SQLITE_DEBUG) \ || defined(SQLITE_ENABLE_BYTECODE_VTAB) # define VDBE_DISPLAY_P4 1 #else # define VDBE_DISPLAY_P4 0 #endif /* ** SQL is translated into a sequence of instructions to be |
︙ | ︙ | |||
81 82 83 84 85 86 87 | #ifdef SQLITE_DEBUG u8 seekOp; /* Most recent seek operation on this cursor */ u8 wrFlag; /* The wrFlag argument to sqlite3BtreeCursor() */ #endif Bool isEphemeral:1; /* True for an ephemeral table */ Bool useRandomRowid:1; /* Generate new record numbers semi-randomly */ Bool isOrdered:1; /* True if the table is not BTREE_UNORDERED */ | > | | | 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 | #ifdef SQLITE_DEBUG u8 seekOp; /* Most recent seek operation on this cursor */ u8 wrFlag; /* The wrFlag argument to sqlite3BtreeCursor() */ #endif Bool isEphemeral:1; /* True for an ephemeral table */ Bool useRandomRowid:1; /* Generate new record numbers semi-randomly */ Bool isOrdered:1; /* True if the table is not BTREE_UNORDERED */ Bool hasBeenDuped:1; /* This cursor was source or target of OP_OpenDup */ u16 seekHit; /* See the OP_SeekHit and OP_IfNoHope opcodes */ Btree *pBtx; /* Separate file holding temporary table */ i64 seqCount; /* Sequence counter */ u32 *aAltMap; /* Mapping from table to index column numbers */ /* Cached OP_Column parse information is only valid if cacheStatus matches ** Vdbe.cacheCtr. Vdbe.cacheCtr will never take on the value of ** CACHE_STALE (0) and so setting cacheStatus=CACHE_STALE guarantees that ** the cache is out of date. */ u32 cacheStatus; /* Cache is valid if this matches Vdbe.cacheCtr */ int seekResult; /* Result of previous sqlite3BtreeMoveto() or 0 |
︙ | ︙ | |||
174 175 176 177 178 179 180 | #endif int nCursor; /* Number of entries in apCsr */ int pc; /* Program Counter in parent (calling) frame */ int nOp; /* Size of aOp array */ int nMem; /* Number of entries in aMem */ int nChildMem; /* Number of memory cells for child frame */ int nChildCsr; /* Number of cursors for child frame */ | | | | 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 | #endif int nCursor; /* Number of entries in apCsr */ int pc; /* Program Counter in parent (calling) frame */ int nOp; /* Size of aOp array */ int nMem; /* Number of entries in aMem */ int nChildMem; /* Number of memory cells for child frame */ int nChildCsr; /* Number of cursors for child frame */ i64 nChange; /* Statement changes (Vdbe.nChange) */ i64 nDbChange; /* Value of db->nChange */ }; /* Magic number for sanity checking on VdbeFrame objects */ #define SQLITE_FRAME_MAGIC 0x879fb71e /* ** Return a pointer to the array of registers allocated for use |
︙ | ︙ | |||
241 242 243 244 245 246 247 | ** flags may coexist with the MEM_Str flag. */ #define MEM_Null 0x0001 /* Value is NULL (or a pointer) */ #define MEM_Str 0x0002 /* Value is a string */ #define MEM_Int 0x0004 /* Value is an integer */ #define MEM_Real 0x0008 /* Value is a real number */ #define MEM_Blob 0x0010 /* Value is a BLOB */ | > | < | | | 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 | ** flags may coexist with the MEM_Str flag. */ #define MEM_Null 0x0001 /* Value is NULL (or a pointer) */ #define MEM_Str 0x0002 /* Value is a string */ #define MEM_Int 0x0004 /* Value is an integer */ #define MEM_Real 0x0008 /* Value is a real number */ #define MEM_Blob 0x0010 /* Value is a BLOB */ #define MEM_IntReal 0x0020 /* MEM_Int that stringifies like MEM_Real */ #define MEM_AffMask 0x003f /* Mask of affinity bits */ #define MEM_FromBind 0x0040 /* Value originates from sqlite3_bind() */ #define MEM_Undefined 0x0080 /* Value is undefined */ #define MEM_Cleared 0x0100 /* NULL set by OP_Null, not from data */ #define MEM_TypeMask 0xc1bf /* Mask of type bits */ /* Whenever Mem contains a valid string or blob representation, one of ** the following flags must be set to determine the memory management ** policy for Mem.z. The MEM_Term flag tells us whether or not the ** string is \000 or \u0000 terminated */ |
︙ | ︙ | |||
278 279 280 281 282 283 284 285 286 287 288 289 290 291 | /* ** Clear any existing type flags from a Mem and replace them with f */ #define MemSetTypeFlag(p, f) \ ((p)->flags = ((p)->flags&~(MEM_TypeMask|MEM_Zero))|f) /* ** Return true if a memory cell is not marked as invalid. This macro ** is for use inside assert() statements only. */ #ifdef SQLITE_DEBUG #define memIsValid(M) ((M)->flags & MEM_Undefined)==0 #endif | > > > > > > > | 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 | /* ** Clear any existing type flags from a Mem and replace them with f */ #define MemSetTypeFlag(p, f) \ ((p)->flags = ((p)->flags&~(MEM_TypeMask|MEM_Zero))|f) /* ** True if Mem X is a NULL-nochng type. */ #define MemNullNochng(X) \ (((X)->flags&MEM_TypeMask)==(MEM_Null|MEM_Zero) \ && (X)->n==0 && (X)->u.nZero==0) /* ** Return true if a memory cell is not marked as invalid. This macro ** is for use inside assert() statements only. */ #ifdef SQLITE_DEBUG #define memIsValid(M) ((M)->flags & MEM_Undefined)==0 #endif |
︙ | ︙ | |||
369 370 371 372 373 374 375 | ** is really a pointer to an instance of this structure. */ struct Vdbe { sqlite3 *db; /* The database connection that owns this statement */ Vdbe *pPrev,*pNext; /* Linked list of VDBEs with the same Vdbe.db */ Parse *pParse; /* Parsing context used to create this Vdbe */ ynVar nVar; /* Number of entries in aVar[] */ | | | > > > > | | < < < > < | 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 | ** is really a pointer to an instance of this structure. */ struct Vdbe { sqlite3 *db; /* The database connection that owns this statement */ Vdbe *pPrev,*pNext; /* Linked list of VDBEs with the same Vdbe.db */ Parse *pParse; /* Parsing context used to create this Vdbe */ ynVar nVar; /* Number of entries in aVar[] */ u32 iVdbeMagic; /* Magic number defining state of the SQL statement */ int nMem; /* Number of memory locations currently allocated */ int nCursor; /* Number of slots in apCsr[] */ u32 cacheCtr; /* VdbeCursor row cache generation counter */ int pc; /* The program counter */ int rc; /* Value to return */ i64 nChange; /* Number of db changes made since last reset */ int iStatement; /* Statement number (or 0 if has no opened stmt) */ i64 iCurrentTime; /* Value of julianday('now') for this statement */ i64 nFkConstraint; /* Number of imm. FK constraints this VM */ i64 nStmtDefCons; /* Number of def. constraints when stmt started */ i64 nStmtDefImmCons; /* Number of def. imm constraints when stmt started */ Mem *aMem; /* The memory locations */ Mem **apArg; /* Arguments to currently executing user function */ VdbeCursor **apCsr; /* One element of this array for each open cursor */ Mem *aVar; /* Values for the OP_Variable opcode. */ /* When allocating a new Vdbe object, all of the fields below should be ** initialized to zero or NULL */ Op *aOp; /* Space to hold the virtual machine's program */ int nOp; /* Number of instructions in the program */ int nOpAlloc; /* Slots allocated for aOp[] */ Mem *aColName; /* Column names to return */ Mem *pResultSet; /* Pointer to an array of results */ char *zErrMsg; /* Error message written here */ VList *pVList; /* Name of variables */ #ifndef SQLITE_OMIT_TRACE i64 startTime; /* Time when query started - used for profiling */ #endif #ifdef SQLITE_DEBUG int rcApp; /* errcode set by sqlite3_result_error_code() */ u32 nWrite; /* Number of write operations that have occurred */ #endif u16 nResColumn; /* Number of columns in one row of the result set */ u8 errorAction; /* Recovery action to do in case of an error */ u8 minWriteFileFormat; /* Minimum file format for writable database files */ u8 prepFlags; /* SQLITE_PREPARE_* flags */ u8 doingRerun; /* True if rerunning after an auto-reprepare */ bft expired:2; /* 1: recompile VM immediately 2: when convenient */ bft explain:2; /* True if EXPLAIN present on SQL command */ bft changeCntOn:1; /* True to update the change-counter */ bft runOnlyOnce:1; /* Automatically expire on reset */ bft usesStmtJournal:1; /* True if uses a statement journal */ bft readOnly:1; /* True for statements that do not write */ bft bIsReader:1; /* True for statements that read */ yDbMask btreeMask; /* Bitmask of db->aDb[] entries referenced */ yDbMask lockMask; /* Subset of btreeMask that requires a lock */ |
︙ | ︙ | |||
458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 | VdbeCursor *pCsr; /* Cursor to read old values from */ int op; /* One of SQLITE_INSERT, UPDATE, DELETE */ u8 *aRecord; /* old.* database record */ KeyInfo keyinfo; UnpackedRecord *pUnpacked; /* Unpacked version of aRecord[] */ UnpackedRecord *pNewUnpacked; /* Unpacked version of new.* record */ int iNewReg; /* Register for new.* values */ i64 iKey1; /* First key value passed to hook */ i64 iKey2; /* Second key value passed to hook */ Mem *aNew; /* Array of new.* values */ Table *pTab; /* Schema object being upated */ Index *pPk; /* PK index if pTab is WITHOUT ROWID */ }; /* ** Function prototypes */ void sqlite3VdbeError(Vdbe*, const char *, ...); void sqlite3VdbeFreeCursor(Vdbe *, VdbeCursor*); void sqliteVdbePopStack(Vdbe*,int); | > > | < > > > > > > > | | > > > > > | > | | > | 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 | VdbeCursor *pCsr; /* Cursor to read old values from */ int op; /* One of SQLITE_INSERT, UPDATE, DELETE */ u8 *aRecord; /* old.* database record */ KeyInfo keyinfo; UnpackedRecord *pUnpacked; /* Unpacked version of aRecord[] */ UnpackedRecord *pNewUnpacked; /* Unpacked version of new.* record */ int iNewReg; /* Register for new.* values */ int iBlobWrite; /* Value returned by preupdate_blobwrite() */ i64 iKey1; /* First key value passed to hook */ i64 iKey2; /* Second key value passed to hook */ Mem *aNew; /* Array of new.* values */ Table *pTab; /* Schema object being upated */ Index *pPk; /* PK index if pTab is WITHOUT ROWID */ }; /* ** Function prototypes */ void sqlite3VdbeError(Vdbe*, const char *, ...); void sqlite3VdbeFreeCursor(Vdbe *, VdbeCursor*); void sqliteVdbePopStack(Vdbe*,int); int SQLITE_NOINLINE sqlite3VdbeFinishMoveto(VdbeCursor*); int sqlite3VdbeCursorMoveto(VdbeCursor**, u32*); int sqlite3VdbeCursorRestore(VdbeCursor*); u32 sqlite3VdbeSerialTypeLen(u32); u8 sqlite3VdbeOneByteSerialTypeLen(u8); u32 sqlite3VdbeSerialPut(unsigned char*, Mem*, u32); u32 sqlite3VdbeSerialGet(const unsigned char*, u32, Mem*); void sqlite3VdbeDeleteAuxData(sqlite3*, AuxData**, int, int); int sqlite2BtreeKeyCompare(BtCursor *, const void *, int, int, int *); int sqlite3VdbeIdxKeyCompare(sqlite3*,VdbeCursor*,UnpackedRecord*,int*); int sqlite3VdbeIdxRowid(sqlite3*, BtCursor*, i64*); int sqlite3VdbeExec(Vdbe*); #if !defined(SQLITE_OMIT_EXPLAIN) || defined(SQLITE_ENABLE_BYTECODE_VTAB) int sqlite3VdbeNextOpcode(Vdbe*,Mem*,int,int*,int*,Op**); char *sqlite3VdbeDisplayP4(sqlite3*,Op*); #endif #if defined(SQLITE_ENABLE_EXPLAIN_COMMENTS) char *sqlite3VdbeDisplayComment(sqlite3*,const Op*,const char*); #endif #if !defined(SQLITE_OMIT_EXPLAIN) int sqlite3VdbeList(Vdbe*); #endif int sqlite3VdbeHalt(Vdbe*); int sqlite3VdbeChangeEncoding(Mem *, int); int sqlite3VdbeMemTooBig(Mem*); int sqlite3VdbeMemCopy(Mem*, const Mem*); void sqlite3VdbeMemShallowCopy(Mem*, const Mem*, int); void sqlite3VdbeMemMove(Mem*, Mem*); int sqlite3VdbeMemNulTerminate(Mem*); int sqlite3VdbeMemSetStr(Mem*, const char*, i64, u8, void(*)(void*)); void sqlite3VdbeMemSetInt64(Mem*, i64); #ifdef SQLITE_OMIT_FLOATING_POINT # define sqlite3VdbeMemSetDouble sqlite3VdbeMemSetInt64 #else void sqlite3VdbeMemSetDouble(Mem*, double); #endif void sqlite3VdbeMemSetPointer(Mem*, void*, const char*, void(*)(void*)); void sqlite3VdbeMemInit(Mem*,sqlite3*,u16); void sqlite3VdbeMemSetNull(Mem*); #ifndef SQLITE_OMIT_INCRBLOB void sqlite3VdbeMemSetZeroBlob(Mem*,int); #else int sqlite3VdbeMemSetZeroBlob(Mem*,int); #endif #ifdef SQLITE_DEBUG int sqlite3VdbeMemIsRowSet(const Mem*); #endif int sqlite3VdbeMemSetRowSet(Mem*); int sqlite3VdbeMemMakeWriteable(Mem*); int sqlite3VdbeMemStringify(Mem*, u8, u8); int sqlite3IntFloatCompare(i64,double); i64 sqlite3VdbeIntValue(Mem*); int sqlite3VdbeMemIntegerify(Mem*); double sqlite3VdbeRealValue(Mem*); int sqlite3VdbeBooleanValue(Mem*, int ifNull); void sqlite3VdbeIntegerAffinity(Mem*); int sqlite3VdbeMemRealify(Mem*); int sqlite3VdbeMemNumerify(Mem*); int sqlite3VdbeMemCast(Mem*,u8,u8); int sqlite3VdbeMemFromBtree(BtCursor*,u32,u32,Mem*); int sqlite3VdbeMemFromBtreeZeroOffset(BtCursor*,u32,Mem*); void sqlite3VdbeMemRelease(Mem *p); int sqlite3VdbeMemFinalize(Mem*, FuncDef*); #ifndef SQLITE_OMIT_WINDOWFUNC int sqlite3VdbeMemAggValue(Mem*, Mem*, FuncDef*); #endif #if !defined(SQLITE_OMIT_EXPLAIN) || defined(SQLITE_ENABLE_BYTECODE_VTAB) const char *sqlite3OpcodeName(int); #endif int sqlite3VdbeMemGrow(Mem *pMem, int n, int preserve); int sqlite3VdbeMemClearAndResize(Mem *pMem, int n); int sqlite3VdbeCloseStatement(Vdbe *, int); #ifdef SQLITE_DEBUG int sqlite3VdbeFrameIsValid(VdbeFrame*); #endif void sqlite3VdbeFrameMemDel(void*); /* Destructor on Mem */ void sqlite3VdbeFrameDelete(VdbeFrame*); /* Actually deletes the Frame */ int sqlite3VdbeFrameRestore(VdbeFrame *); #ifdef SQLITE_ENABLE_PREUPDATE_HOOK void sqlite3VdbePreUpdateHook( Vdbe*,VdbeCursor*,int,const char*,Table*,i64,int,int); #endif int sqlite3VdbeTransferError(Vdbe *p); int sqlite3VdbeSorterInit(sqlite3 *, int, VdbeCursor *); void sqlite3VdbeSorterReset(sqlite3 *, VdbeSorter *); void sqlite3VdbeSorterClose(sqlite3 *, VdbeCursor *); int sqlite3VdbeSorterRowkey(const VdbeCursor *, Mem *); |
︙ | ︙ | |||
584 585 586 587 588 589 590 | int sqlite3VdbeCheckFk(Vdbe *, int); #else # define sqlite3VdbeCheckFk(p,i) 0 #endif #ifdef SQLITE_DEBUG void sqlite3VdbePrintSql(Vdbe*); | | | 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 | int sqlite3VdbeCheckFk(Vdbe *, int); #else # define sqlite3VdbeCheckFk(p,i) 0 #endif #ifdef SQLITE_DEBUG void sqlite3VdbePrintSql(Vdbe*); void sqlite3VdbeMemPrettyPrint(Mem *pMem, StrAccum *pStr); #endif #ifndef SQLITE_OMIT_UTF16 int sqlite3VdbeMemTranslate(Mem*, u8); int sqlite3VdbeMemHandleBom(Mem *pMem); #endif #ifndef SQLITE_OMIT_INCRBLOB |
︙ | ︙ |
Changes to src/vdbeapi.c.
︙ | ︙ | |||
63 64 65 66 67 68 69 | sqlite3_int64 iElapse; assert( p->startTime>0 ); assert( (db->mTrace & (SQLITE_TRACE_PROFILE|SQLITE_TRACE_XPROFILE))!=0 ); assert( db->init.busy==0 ); assert( p->zSql!=0 ); sqlite3OsCurrentTimeInt64(db->pVfs, &iNow); iElapse = (iNow - p->startTime)*1000000; | | | | 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | sqlite3_int64 iElapse; assert( p->startTime>0 ); assert( (db->mTrace & (SQLITE_TRACE_PROFILE|SQLITE_TRACE_XPROFILE))!=0 ); assert( db->init.busy==0 ); assert( p->zSql!=0 ); sqlite3OsCurrentTimeInt64(db->pVfs, &iNow); iElapse = (iNow - p->startTime)*1000000; #ifndef SQLITE_OMIT_DEPRECATED if( db->xProfile ){ db->xProfile(db->pProfileArg, p->zSql, iElapse); } #endif if( db->mTrace & SQLITE_TRACE_PROFILE ){ db->trace.xV2(SQLITE_TRACE_PROFILE, db->pTraceArg, p, (void*)&iElapse); } p->startTime = 0; } /* ** The checkProfileCallback(DB,P) macro checks to see if a profile callback ** is needed, and it invokes the callback if it is needed. */ |
︙ | ︙ | |||
230 231 232 233 234 235 236 | #endif /* SQLITE_OMIT_UTF16 */ /* EVIDENCE-OF: R-12793-43283 Every value in SQLite has one of five ** fundamental datatypes: 64-bit signed integer 64-bit IEEE floating ** point number string BLOB NULL */ int sqlite3_value_type(sqlite3_value* pVal){ static const u8 aType[] = { | | > > | > > > > > > > > > > > > > > | | | | | | | | > > > > > > > > > > | | | | | | > > > > > > | | | | | | | | | | | | | | | | > > > > > > > > > > > > > > > > > > > > | 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 | #endif /* SQLITE_OMIT_UTF16 */ /* EVIDENCE-OF: R-12793-43283 Every value in SQLite has one of five ** fundamental datatypes: 64-bit signed integer 64-bit IEEE floating ** point number string BLOB NULL */ int sqlite3_value_type(sqlite3_value* pVal){ static const u8 aType[] = { SQLITE_BLOB, /* 0x00 (not possible) */ SQLITE_NULL, /* 0x01 NULL */ SQLITE_TEXT, /* 0x02 TEXT */ SQLITE_NULL, /* 0x03 (not possible) */ SQLITE_INTEGER, /* 0x04 INTEGER */ SQLITE_NULL, /* 0x05 (not possible) */ SQLITE_INTEGER, /* 0x06 INTEGER + TEXT */ SQLITE_NULL, /* 0x07 (not possible) */ SQLITE_FLOAT, /* 0x08 FLOAT */ SQLITE_NULL, /* 0x09 (not possible) */ SQLITE_FLOAT, /* 0x0a FLOAT + TEXT */ SQLITE_NULL, /* 0x0b (not possible) */ SQLITE_INTEGER, /* 0x0c (not possible) */ SQLITE_NULL, /* 0x0d (not possible) */ SQLITE_INTEGER, /* 0x0e (not possible) */ SQLITE_NULL, /* 0x0f (not possible) */ SQLITE_BLOB, /* 0x10 BLOB */ SQLITE_NULL, /* 0x11 (not possible) */ SQLITE_TEXT, /* 0x12 (not possible) */ SQLITE_NULL, /* 0x13 (not possible) */ SQLITE_INTEGER, /* 0x14 INTEGER + BLOB */ SQLITE_NULL, /* 0x15 (not possible) */ SQLITE_INTEGER, /* 0x16 (not possible) */ SQLITE_NULL, /* 0x17 (not possible) */ SQLITE_FLOAT, /* 0x18 FLOAT + BLOB */ SQLITE_NULL, /* 0x19 (not possible) */ SQLITE_FLOAT, /* 0x1a (not possible) */ SQLITE_NULL, /* 0x1b (not possible) */ SQLITE_INTEGER, /* 0x1c (not possible) */ SQLITE_NULL, /* 0x1d (not possible) */ SQLITE_INTEGER, /* 0x1e (not possible) */ SQLITE_NULL, /* 0x1f (not possible) */ SQLITE_FLOAT, /* 0x20 INTREAL */ SQLITE_NULL, /* 0x21 (not possible) */ SQLITE_TEXT, /* 0x22 INTREAL + TEXT */ SQLITE_NULL, /* 0x23 (not possible) */ SQLITE_FLOAT, /* 0x24 (not possible) */ SQLITE_NULL, /* 0x25 (not possible) */ SQLITE_FLOAT, /* 0x26 (not possible) */ SQLITE_NULL, /* 0x27 (not possible) */ SQLITE_FLOAT, /* 0x28 (not possible) */ SQLITE_NULL, /* 0x29 (not possible) */ SQLITE_FLOAT, /* 0x2a (not possible) */ SQLITE_NULL, /* 0x2b (not possible) */ SQLITE_FLOAT, /* 0x2c (not possible) */ SQLITE_NULL, /* 0x2d (not possible) */ SQLITE_FLOAT, /* 0x2e (not possible) */ SQLITE_NULL, /* 0x2f (not possible) */ SQLITE_BLOB, /* 0x30 (not possible) */ SQLITE_NULL, /* 0x31 (not possible) */ SQLITE_TEXT, /* 0x32 (not possible) */ SQLITE_NULL, /* 0x33 (not possible) */ SQLITE_FLOAT, /* 0x34 (not possible) */ SQLITE_NULL, /* 0x35 (not possible) */ SQLITE_FLOAT, /* 0x36 (not possible) */ SQLITE_NULL, /* 0x37 (not possible) */ SQLITE_FLOAT, /* 0x38 (not possible) */ SQLITE_NULL, /* 0x39 (not possible) */ SQLITE_FLOAT, /* 0x3a (not possible) */ SQLITE_NULL, /* 0x3b (not possible) */ SQLITE_FLOAT, /* 0x3c (not possible) */ SQLITE_NULL, /* 0x3d (not possible) */ SQLITE_FLOAT, /* 0x3e (not possible) */ SQLITE_NULL, /* 0x3f (not possible) */ }; #ifdef SQLITE_DEBUG { int eType = SQLITE_BLOB; if( pVal->flags & MEM_Null ){ eType = SQLITE_NULL; }else if( pVal->flags & (MEM_Real|MEM_IntReal) ){ eType = SQLITE_FLOAT; }else if( pVal->flags & MEM_Int ){ eType = SQLITE_INTEGER; }else if( pVal->flags & MEM_Str ){ eType = SQLITE_TEXT; } assert( eType == aType[pVal->flags&MEM_AffMask] ); } #endif return aType[pVal->flags&MEM_AffMask]; } /* Return true if a parameter to xUpdate represents an unchanged column */ int sqlite3_value_nochange(sqlite3_value *pVal){ return (pVal->flags&(MEM_Null|MEM_Zero))==(MEM_Null|MEM_Zero); } /* Return true if a parameter value originated from an sqlite3_bind() */ int sqlite3_value_frombind(sqlite3_value *pVal){ return (pVal->flags&MEM_FromBind)!=0; } /* Make a copy of an sqlite3_value object */ sqlite3_value *sqlite3_value_dup(const sqlite3_value *pOrig){ sqlite3_value *pNew; if( pOrig==0 ) return 0; pNew = sqlite3_malloc( sizeof(*pNew) ); |
︙ | ︙ | |||
306 307 308 309 310 311 312 | /**************************** sqlite3_result_ ******************************* ** The following routines are used by user-defined functions to specify ** the function result. ** ** The setStrOrError() function calls sqlite3VdbeMemSetStr() to store the | | | | > > | > > > > > > | | 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 | /**************************** sqlite3_result_ ******************************* ** The following routines are used by user-defined functions to specify ** the function result. ** ** The setStrOrError() function calls sqlite3VdbeMemSetStr() to store the ** result as a string or blob. Appropriate errors are set if the string/blob ** is too big or if an OOM occurs. ** ** The invokeValueDestructor(P,X) routine invokes destructor function X() ** on value P is not going to be used and need to be destroyed. */ static void setResultStrOrError( sqlite3_context *pCtx, /* Function context */ const char *z, /* String pointer */ int n, /* Bytes in string, or negative */ u8 enc, /* Encoding of z. 0 for BLOBs */ void (*xDel)(void*) /* Destructor function */ ){ int rc = sqlite3VdbeMemSetStr(pCtx->pOut, z, n, enc, xDel); if( rc ){ if( rc==SQLITE_TOOBIG ){ sqlite3_result_error_toobig(pCtx); }else{ /* The only errors possible from sqlite3VdbeMemSetStr are ** SQLITE_TOOBIG and SQLITE_NOMEM */ assert( rc==SQLITE_NOMEM ); sqlite3_result_error_nomem(pCtx); } } } static int invokeValueDestructor( const void *p, /* Value to destroy */ void (*xDel)(void*), /* The destructor */ sqlite3_context *pCtx /* Set a SQLITE_TOOBIG error if no NULL */ ){ assert( xDel!=SQLITE_DYNAMIC ); if( xDel==0 ){ /* noop */ }else if( xDel==SQLITE_TRANSIENT ){ /* noop */ }else{ xDel((void*)p); } sqlite3_result_error_toobig(pCtx); return SQLITE_TOOBIG; } void sqlite3_result_blob( sqlite3_context *pCtx, const void *z, int n, void (*xDel)(void *) |
︙ | ︙ | |||
477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 | } int sqlite3_result_zeroblob64(sqlite3_context *pCtx, u64 n){ Mem *pOut = pCtx->pOut; assert( sqlite3_mutex_held(pOut->db->mutex) ); if( n>(u64)pOut->db->aLimit[SQLITE_LIMIT_LENGTH] ){ return SQLITE_TOOBIG; } sqlite3VdbeMemSetZeroBlob(pCtx->pOut, (int)n); return SQLITE_OK; } void sqlite3_result_error_code(sqlite3_context *pCtx, int errCode){ pCtx->isError = errCode ? errCode : -1; #ifdef SQLITE_DEBUG if( pCtx->pVdbe ) pCtx->pVdbe->rcApp = errCode; #endif if( pCtx->pOut->flags & MEM_Null ){ | > > > > | 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 | } int sqlite3_result_zeroblob64(sqlite3_context *pCtx, u64 n){ Mem *pOut = pCtx->pOut; assert( sqlite3_mutex_held(pOut->db->mutex) ); if( n>(u64)pOut->db->aLimit[SQLITE_LIMIT_LENGTH] ){ return SQLITE_TOOBIG; } #ifndef SQLITE_OMIT_INCRBLOB sqlite3VdbeMemSetZeroBlob(pCtx->pOut, (int)n); return SQLITE_OK; #else return sqlite3VdbeMemSetZeroBlob(pCtx->pOut, (int)n); #endif } void sqlite3_result_error_code(sqlite3_context *pCtx, int errCode){ pCtx->isError = errCode ? errCode : -1; #ifdef SQLITE_DEBUG if( pCtx->pVdbe ) pCtx->pVdbe->rcApp = errCode; #endif if( pCtx->pOut->flags & MEM_Null ){ |
︙ | ︙ | |||
506 507 508 509 510 511 512 513 514 515 516 517 518 519 | /* An SQLITE_NOMEM error. */ void sqlite3_result_error_nomem(sqlite3_context *pCtx){ assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); sqlite3VdbeMemSetNull(pCtx->pOut); pCtx->isError = SQLITE_NOMEM_BKPT; sqlite3OomFault(pCtx->pOut->db); } /* ** This function is called after a transaction has been committed. It ** invokes callbacks registered with sqlite3_wal_hook() as required. */ static int doWalCallbacks(sqlite3 *db){ int rc = SQLITE_OK; | > > > > > > > > > > > > > > > | 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 | /* An SQLITE_NOMEM error. */ void sqlite3_result_error_nomem(sqlite3_context *pCtx){ assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); sqlite3VdbeMemSetNull(pCtx->pOut); pCtx->isError = SQLITE_NOMEM_BKPT; sqlite3OomFault(pCtx->pOut->db); } #ifndef SQLITE_UNTESTABLE /* Force the INT64 value currently stored as the result to be ** a MEM_IntReal value. See the SQLITE_TESTCTRL_RESULT_INTREAL ** test-control. */ void sqlite3ResultIntReal(sqlite3_context *pCtx){ assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); if( pCtx->pOut->flags & MEM_Int ){ pCtx->pOut->flags &= ~MEM_Int; pCtx->pOut->flags |= MEM_IntReal; } } #endif /* ** This function is called after a transaction has been committed. It ** invokes callbacks registered with sqlite3_wal_hook() as required. */ static int doWalCallbacks(sqlite3 *db){ int rc = SQLITE_OK; |
︙ | ︙ | |||
546 547 548 549 550 551 552 | ** outer sqlite3_step() wrapper procedure. */ static int sqlite3Step(Vdbe *p){ sqlite3 *db; int rc; assert(p); | | | 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 | ** outer sqlite3_step() wrapper procedure. */ static int sqlite3Step(Vdbe *p){ sqlite3 *db; int rc; assert(p); if( p->iVdbeMagic!=VDBE_MAGIC_RUN ){ /* We used to require that sqlite3_reset() be called before retrying ** sqlite3_step() after any error or after SQLITE_DONE. But beginning ** with version 3.7.0, we changed this so that sqlite3_reset() would ** be called automatically instead of throwing the SQLITE_MISUSE error. ** This "automatic-reset" change is not technically an incompatibility, ** since any application that receives an SQLITE_MISUSE is broken by ** definition. |
︙ | ︙ | |||
584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 | p->rc = SQLITE_NOMEM; return SQLITE_NOMEM_BKPT; } if( p->pc<0 && p->expired ){ p->rc = SQLITE_SCHEMA; rc = SQLITE_ERROR; goto end_of_step; } if( p->pc<0 ){ /* If there are no other statements currently running, then ** reset the interrupt flag. This prevents a call to sqlite3_interrupt ** from interrupting a statement that has not yet started. */ if( db->nVdbeActive==0 ){ | > > > > > > > | | 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 | p->rc = SQLITE_NOMEM; return SQLITE_NOMEM_BKPT; } if( p->pc<0 && p->expired ){ p->rc = SQLITE_SCHEMA; rc = SQLITE_ERROR; if( (p->prepFlags & SQLITE_PREPARE_SAVESQL)!=0 ){ /* If this statement was prepared using saved SQL 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); } goto end_of_step; } if( p->pc<0 ){ /* If there are no other statements currently running, then ** reset the interrupt flag. This prevents a call to sqlite3_interrupt ** from interrupting a statement that has not yet started. */ if( db->nVdbeActive==0 ){ AtomicStore(&db->u1.isInterrupted, 0); } assert( db->nVdbeWrite>0 || db->autoCommit==0 || (db->nDeferredCons==0 && db->nDeferredImmCons==0) ); #ifndef SQLITE_OMIT_TRACE |
︙ | ︙ | |||
639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 | if( rc==SQLITE_DONE && db->autoCommit ){ assert( p->rc==SQLITE_OK ); p->rc = doWalCallbacks(db); if( p->rc!=SQLITE_OK ){ rc = SQLITE_ERROR; } } } db->errCode = rc; if( SQLITE_NOMEM==sqlite3ApiExit(p->db, p->rc) ){ p->rc = SQLITE_NOMEM_BKPT; } end_of_step: | > > > > > > > < | | | < < < | < < < < < < < < < < < | 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 | if( rc==SQLITE_DONE && db->autoCommit ){ assert( p->rc==SQLITE_OK ); p->rc = doWalCallbacks(db); if( p->rc!=SQLITE_OK ){ rc = SQLITE_ERROR; } }else if( rc!=SQLITE_DONE && (p->prepFlags & SQLITE_PREPARE_SAVESQL)!=0 ){ /* If this statement was prepared using saved SQL 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); } } db->errCode = rc; if( SQLITE_NOMEM==sqlite3ApiExit(p->db, p->rc) ){ p->rc = SQLITE_NOMEM_BKPT; if( (p->prepFlags & SQLITE_PREPARE_SAVESQL)!=0 ) rc = p->rc; } end_of_step: /* There are only a limited number of result codes allowed from the ** statements prepared using the legacy sqlite3_prepare() interface */ assert( (p->prepFlags & SQLITE_PREPARE_SAVESQL)!=0 || rc==SQLITE_ROW || rc==SQLITE_DONE || rc==SQLITE_ERROR || (rc&0xff)==SQLITE_BUSY || rc==SQLITE_MISUSE ); 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. |
︙ | ︙ | |||
773 774 775 776 777 778 779 | ** is requested more than once within the same run of a single prepared ** statement, the exact same time is returned for each invocation regardless ** of the amount of time that elapses between invocations. In other words, ** the time returned is always the time of the first call. */ sqlite3_int64 sqlite3StmtCurrentTime(sqlite3_context *p){ int rc; | | | 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 | ** is requested more than once within the same run of a single prepared ** statement, the exact same time is returned for each invocation regardless ** of the amount of time that elapses between invocations. In other words, ** the time returned is always the time of the first call. */ sqlite3_int64 sqlite3StmtCurrentTime(sqlite3_context *p){ int rc; #ifndef SQLITE_ENABLE_STAT4 sqlite3_int64 *piTime = &p->pVdbe->iCurrentTime; assert( p->pVdbe!=0 ); #else sqlite3_int64 iTime = 0; sqlite3_int64 *piTime = p->pVdbe!=0 ? &p->pVdbe->iCurrentTime : &iTime; #endif if( *piTime==0 ){ |
︙ | ︙ | |||
838 839 840 841 842 843 844 | ** auxiliary data pointers that is available to all functions within a ** single prepared statement. The iArg values must match. */ void *sqlite3_get_auxdata(sqlite3_context *pCtx, int iArg){ AuxData *pAuxData; assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); | | | 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 | ** auxiliary data pointers that is available to all functions within a ** single prepared statement. The iArg values must match. */ void *sqlite3_get_auxdata(sqlite3_context *pCtx, int iArg){ AuxData *pAuxData; assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); #if SQLITE_ENABLE_STAT4 if( pCtx->pVdbe==0 ) return 0; #else assert( pCtx->pVdbe!=0 ); #endif for(pAuxData=pCtx->pVdbe->pAuxData; pAuxData; pAuxData=pAuxData->pNextAux){ if( pAuxData->iAuxArg==iArg && (pAuxData->iAuxOp==pCtx->iOp || iArg<0) ){ return pAuxData->pAux; |
︙ | ︙ | |||
872 873 874 875 876 877 878 | void *pAux, void (*xDelete)(void*) ){ AuxData *pAuxData; Vdbe *pVdbe = pCtx->pVdbe; assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); | | | 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 | void *pAux, void (*xDelete)(void*) ){ AuxData *pAuxData; Vdbe *pVdbe = pCtx->pVdbe; assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); #ifdef SQLITE_ENABLE_STAT4 if( pVdbe==0 ) goto failed; #else assert( pVdbe!=0 ); #endif for(pAuxData=pVdbe->pAuxData; pAuxData; pAuxData=pAuxData->pNextAux){ if( pAuxData->iAuxArg==iArg && (pAuxData->iAuxOp==pCtx->iOp || iArg<0) ){ |
︙ | ︙ | |||
1116 1117 1118 1119 1120 1121 1122 | ** 3 The name of the table that the column derives from ** 4 The name of the table column that the result column derives from ** ** If the result is not a simple column reference (if it is an expression ** or a constant) then useTypes 2, 3, and 4 return NULL. */ static const void *columnName( | | | | | > > > > > > | > | | < | < | < | < | < | < | < | < | < | < | 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 | ** 3 The name of the table that the column derives from ** 4 The name of the table column that the result column derives from ** ** If the result is not a simple column reference (if it is an expression ** or a constant) then useTypes 2, 3, and 4 return NULL. */ static const void *columnName( sqlite3_stmt *pStmt, /* The statement */ int N, /* Which column to get the name for */ int useUtf16, /* True to return the name as UTF16 */ int useType /* What type of name */ ){ const void *ret; Vdbe *p; int n; sqlite3 *db; #ifdef SQLITE_ENABLE_API_ARMOR if( pStmt==0 ){ (void)SQLITE_MISUSE_BKPT; return 0; } #endif ret = 0; p = (Vdbe *)pStmt; db = p->db; assert( db!=0 ); n = sqlite3_column_count(pStmt); if( N<n && N>=0 ){ N += useType*n; sqlite3_mutex_enter(db->mutex); assert( db->mallocFailed==0 ); #ifndef SQLITE_OMIT_UTF16 if( useUtf16 ){ ret = sqlite3_value_text16((sqlite3_value*)&p->aColName[N]); }else #endif { ret = sqlite3_value_text((sqlite3_value*)&p->aColName[N]); } /* A malloc may have failed inside of the _text() call. If this ** is the case, clear the mallocFailed flag and return NULL. */ if( db->mallocFailed ){ sqlite3OomClear(db); ret = 0; } sqlite3_mutex_leave(db->mutex); } return ret; } /* ** Return the name of the Nth column of the result set returned by SQL ** statement pStmt. */ const char *sqlite3_column_name(sqlite3_stmt *pStmt, int N){ return columnName(pStmt, N, 0, COLNAME_NAME); } #ifndef SQLITE_OMIT_UTF16 const void *sqlite3_column_name16(sqlite3_stmt *pStmt, int N){ return columnName(pStmt, N, 1, COLNAME_NAME); } #endif /* ** Constraint: If you have ENABLE_COLUMN_METADATA then you must ** not define OMIT_DECLTYPE. */ #if defined(SQLITE_OMIT_DECLTYPE) && defined(SQLITE_ENABLE_COLUMN_METADATA) # error "Must not define both SQLITE_OMIT_DECLTYPE \ and SQLITE_ENABLE_COLUMN_METADATA" #endif #ifndef SQLITE_OMIT_DECLTYPE /* ** Return the column declaration type (if applicable) of the 'i'th column ** of the result set of SQL statement pStmt. */ const char *sqlite3_column_decltype(sqlite3_stmt *pStmt, int N){ return columnName(pStmt, N, 0, COLNAME_DECLTYPE); } #ifndef SQLITE_OMIT_UTF16 const void *sqlite3_column_decltype16(sqlite3_stmt *pStmt, int N){ return columnName(pStmt, N, 1, COLNAME_DECLTYPE); } #endif /* SQLITE_OMIT_UTF16 */ #endif /* SQLITE_OMIT_DECLTYPE */ #ifdef SQLITE_ENABLE_COLUMN_METADATA /* ** Return the name of the database from which a result column derives. ** NULL is returned if the result column is an expression or constant or ** anything else which is not an unambiguous reference to a database column. */ const char *sqlite3_column_database_name(sqlite3_stmt *pStmt, int N){ return columnName(pStmt, N, 0, COLNAME_DATABASE); } #ifndef SQLITE_OMIT_UTF16 const void *sqlite3_column_database_name16(sqlite3_stmt *pStmt, int N){ return columnName(pStmt, N, 1, COLNAME_DATABASE); } #endif /* SQLITE_OMIT_UTF16 */ /* ** Return the name of the table from which a result column derives. ** NULL is returned if the result column is an expression or constant or ** anything else which is not an unambiguous reference to a database column. */ const char *sqlite3_column_table_name(sqlite3_stmt *pStmt, int N){ return columnName(pStmt, N, 0, COLNAME_TABLE); } #ifndef SQLITE_OMIT_UTF16 const void *sqlite3_column_table_name16(sqlite3_stmt *pStmt, int N){ return columnName(pStmt, N, 1, COLNAME_TABLE); } #endif /* SQLITE_OMIT_UTF16 */ /* ** Return the name of the table column from which a result column derives. ** NULL is returned if the result column is an expression or constant or ** anything else which is not an unambiguous reference to a database column. */ const char *sqlite3_column_origin_name(sqlite3_stmt *pStmt, int N){ return columnName(pStmt, N, 0, COLNAME_COLUMN); } #ifndef SQLITE_OMIT_UTF16 const void *sqlite3_column_origin_name16(sqlite3_stmt *pStmt, int N){ return columnName(pStmt, N, 1, COLNAME_COLUMN); } #endif /* SQLITE_OMIT_UTF16 */ #endif /* SQLITE_ENABLE_COLUMN_METADATA */ /******************************* sqlite3_bind_ *************************** ** |
︙ | ︙ | |||
1266 1267 1268 1269 1270 1271 1272 | */ static int vdbeUnbind(Vdbe *p, int i){ Mem *pVar; if( vdbeSafetyNotNull(p) ){ return SQLITE_MISUSE_BKPT; } sqlite3_mutex_enter(p->db->mutex); | | | | | 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 | */ static int vdbeUnbind(Vdbe *p, int i){ Mem *pVar; if( vdbeSafetyNotNull(p) ){ return SQLITE_MISUSE_BKPT; } sqlite3_mutex_enter(p->db->mutex); if( p->iVdbeMagic!=VDBE_MAGIC_RUN || p->pc>=0 ){ sqlite3Error(p->db, SQLITE_MISUSE); sqlite3_mutex_leave(p->db->mutex); sqlite3_log(SQLITE_MISUSE, "bind on a busy prepared statement: [%s]", p->zSql); return SQLITE_MISUSE_BKPT; } if( i<1 || i>p->nVar ){ sqlite3Error(p->db, SQLITE_RANGE); sqlite3_mutex_leave(p->db->mutex); return SQLITE_RANGE; } i--; pVar = &p->aVar[i]; sqlite3VdbeMemRelease(pVar); pVar->flags = MEM_Null; p->db->errCode = SQLITE_OK; /* If the bit corresponding to this variable in Vdbe.expmask is set, then ** binding a new value to this variable invalidates the current query plan. ** ** IMPLEMENTATION-OF: R-57496-20354 If the specific value bound to a host ** parameter in the WHERE clause might influence the choice of query plan ** for a statement, then the statement will be automatically recompiled, ** as if there had been a schema change, on the first sqlite3_step() call ** following any change to the bindings of that parameter. */ assert( (p->prepFlags & SQLITE_PREPARE_SAVESQL)!=0 || p->expmask==0 ); if( p->expmask!=0 && (p->expmask & (i>=31 ? 0x80000000 : (u32)1<<i))!=0 ){ p->expired = 1; } return SQLITE_OK; } /* ** Bind a text or BLOB value. */ static int bindText( sqlite3_stmt *pStmt, /* The statement to bind against */ int i, /* Index of the parameter to bind */ const void *zData, /* Pointer to the data to be bound */ i64 nData, /* Number of bytes of data to be bound */ void (*xDel)(void*), /* Destructor for the data */ u8 encoding /* Encoding for the data */ ){ Vdbe *p = (Vdbe *)pStmt; Mem *pVar; int rc; |
︙ | ︙ | |||
1359 1360 1361 1362 1363 1364 1365 | sqlite3_stmt *pStmt, int i, const void *zData, sqlite3_uint64 nData, void (*xDel)(void*) ){ assert( xDel!=SQLITE_DYNAMIC ); | < < < | < | 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 | sqlite3_stmt *pStmt, int i, const void *zData, sqlite3_uint64 nData, void (*xDel)(void*) ){ assert( xDel!=SQLITE_DYNAMIC ); return bindText(pStmt, i, zData, nData, xDel, 0); } int sqlite3_bind_double(sqlite3_stmt *pStmt, int i, double rValue){ int rc; Vdbe *p = (Vdbe *)pStmt; rc = vdbeUnbind(p, i); if( rc==SQLITE_OK ){ sqlite3VdbeMemSetDouble(&p->aVar[i-1], rValue); |
︙ | ︙ | |||
1433 1434 1435 1436 1437 1438 1439 | int i, const char *zData, sqlite3_uint64 nData, void (*xDel)(void*), unsigned char enc ){ assert( xDel!=SQLITE_DYNAMIC ); | < < < | | < | 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 | int i, const char *zData, sqlite3_uint64 nData, void (*xDel)(void*), unsigned char enc ){ assert( xDel!=SQLITE_DYNAMIC ); if( enc==SQLITE_UTF16 ) enc = SQLITE_UTF16NATIVE; return bindText(pStmt, i, zData, nData, xDel, enc); } #ifndef SQLITE_OMIT_UTF16 int sqlite3_bind_text16( sqlite3_stmt *pStmt, int i, const void *zData, int nData, |
︙ | ︙ | |||
1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 | return rc; } int sqlite3_bind_zeroblob(sqlite3_stmt *pStmt, int i, int n){ int rc; Vdbe *p = (Vdbe *)pStmt; rc = vdbeUnbind(p, i); if( rc==SQLITE_OK ){ sqlite3VdbeMemSetZeroBlob(&p->aVar[i-1], n); sqlite3_mutex_leave(p->db->mutex); } return rc; } int sqlite3_bind_zeroblob64(sqlite3_stmt *pStmt, int i, sqlite3_uint64 n){ int rc; Vdbe *p = (Vdbe *)pStmt; | > > > > | 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 | return rc; } int sqlite3_bind_zeroblob(sqlite3_stmt *pStmt, int i, int n){ int rc; Vdbe *p = (Vdbe *)pStmt; rc = vdbeUnbind(p, i); if( rc==SQLITE_OK ){ #ifndef SQLITE_OMIT_INCRBLOB sqlite3VdbeMemSetZeroBlob(&p->aVar[i-1], n); #else rc = sqlite3VdbeMemSetZeroBlob(&p->aVar[i-1], n); #endif sqlite3_mutex_leave(p->db->mutex); } return rc; } int sqlite3_bind_zeroblob64(sqlite3_stmt *pStmt, int i, sqlite3_uint64 n){ int rc; Vdbe *p = (Vdbe *)pStmt; |
︙ | ︙ | |||
1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 | /* ** Return true if the prepared statement is guaranteed to not modify the ** database. */ int sqlite3_stmt_readonly(sqlite3_stmt *pStmt){ return pStmt ? ((Vdbe*)pStmt)->readOnly : 1; } /* ** Return true if the prepared statement is in need of being reset. */ int sqlite3_stmt_busy(sqlite3_stmt *pStmt){ Vdbe *v = (Vdbe*)pStmt; | > > > > > > > > | | 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 | /* ** Return true if the prepared statement is guaranteed to not modify the ** database. */ int sqlite3_stmt_readonly(sqlite3_stmt *pStmt){ return pStmt ? ((Vdbe*)pStmt)->readOnly : 1; } /* ** Return 1 if the statement is an EXPLAIN and return 2 if the ** statement is an EXPLAIN QUERY PLAN */ int sqlite3_stmt_isexplain(sqlite3_stmt *pStmt){ return pStmt ? ((Vdbe*)pStmt)->explain : 0; } /* ** Return true if the prepared statement is in need of being reset. */ int sqlite3_stmt_busy(sqlite3_stmt *pStmt){ Vdbe *v = (Vdbe*)pStmt; return v!=0 && v->iVdbeMagic==VDBE_MAGIC_RUN && v->pc>=0; } /* ** Return a pointer to the next prepared statement after pStmt associated ** with database connection pDb. If pStmt is NULL, return the first ** prepared statement for the database connection. Return NULL if there ** are no more. |
︙ | ︙ | |||
1755 1756 1757 1758 1759 1760 1761 | /* Test that this call is being made from within an SQLITE_DELETE or ** SQLITE_UPDATE pre-update callback, and that iIdx is within range. */ if( !p || p->op==SQLITE_INSERT ){ rc = SQLITE_MISUSE_BKPT; goto preupdate_old_out; } if( p->pPk ){ | | > | 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 | /* Test that this call is being made from within an SQLITE_DELETE or ** SQLITE_UPDATE pre-update callback, and that iIdx is within range. */ if( !p || p->op==SQLITE_INSERT ){ rc = SQLITE_MISUSE_BKPT; goto preupdate_old_out; } if( p->pPk ){ iIdx = sqlite3TableColumnToIndex(p->pPk, iIdx); } if( iIdx>=p->pCsr->nField || iIdx<0 ){ rc = SQLITE_RANGE; goto preupdate_old_out; } /* If the old.* record has not yet been loaded into memory, do so now. */ if( p->pUnpacked==0 ){ u32 nRec; u8 *aRec; assert( p->pCsr->eCurType==CURTYPE_BTREE ); nRec = sqlite3BtreePayloadSize(p->pCsr->uc.pCursor); aRec = sqlite3DbMallocRaw(db, nRec); if( !aRec ) goto preupdate_old_out; rc = sqlite3BtreePayload(p->pCsr->uc.pCursor, 0, nRec, aRec); if( rc==SQLITE_OK ){ p->pUnpacked = vdbeUnpackRecord(&p->keyinfo, nRec, aRec); if( !p->pUnpacked ) rc = SQLITE_NOMEM; |
︙ | ︙ | |||
1788 1789 1790 1791 1792 1793 1794 | pMem = *ppValue = &p->pUnpacked->aMem[iIdx]; if( iIdx==p->pTab->iPKey ){ sqlite3VdbeMemSetInt64(pMem, p->iKey1); }else if( iIdx>=p->pUnpacked->nField ){ *ppValue = (sqlite3_value *)columnNullValue(); }else if( p->pTab->aCol[iIdx].affinity==SQLITE_AFF_REAL ){ | > | > | 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 | pMem = *ppValue = &p->pUnpacked->aMem[iIdx]; if( iIdx==p->pTab->iPKey ){ sqlite3VdbeMemSetInt64(pMem, p->iKey1); }else if( iIdx>=p->pUnpacked->nField ){ *ppValue = (sqlite3_value *)columnNullValue(); }else if( p->pTab->aCol[iIdx].affinity==SQLITE_AFF_REAL ){ if( pMem->flags & (MEM_Int|MEM_IntReal) ){ testcase( pMem->flags & MEM_Int ); testcase( pMem->flags & MEM_IntReal ); sqlite3VdbeMemRealify(pMem); } } preupdate_old_out: sqlite3Error(db, rc); return sqlite3ApiExit(db, rc); |
︙ | ︙ | |||
1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 | ** or SET DEFAULT action is considered a trigger. */ int sqlite3_preupdate_depth(sqlite3 *db){ PreUpdate *p = db->pPreUpdate; return (p ? p->v->nFrame : 0); } #endif /* SQLITE_ENABLE_PREUPDATE_HOOK */ #ifdef SQLITE_ENABLE_PREUPDATE_HOOK /* ** This function is called from within a pre-update callback to retrieve ** a field of the row currently being updated or inserted. */ int sqlite3_preupdate_new(sqlite3 *db, int iIdx, sqlite3_value **ppValue){ PreUpdate *p = db->pPreUpdate; int rc = SQLITE_OK; Mem *pMem; if( !p || p->op==SQLITE_DELETE ){ rc = SQLITE_MISUSE_BKPT; goto preupdate_new_out; } if( p->pPk && p->op!=SQLITE_UPDATE ){ | > > > > > > > > > > > | | 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 | ** or SET DEFAULT action is considered a trigger. */ int sqlite3_preupdate_depth(sqlite3 *db){ PreUpdate *p = db->pPreUpdate; return (p ? p->v->nFrame : 0); } #endif /* SQLITE_ENABLE_PREUPDATE_HOOK */ #ifdef SQLITE_ENABLE_PREUPDATE_HOOK /* ** This function is designed to be called from within a pre-update callback ** only. */ int sqlite3_preupdate_blobwrite(sqlite3 *db){ PreUpdate *p = db->pPreUpdate; return (p ? p->iBlobWrite : -1); } #endif #ifdef SQLITE_ENABLE_PREUPDATE_HOOK /* ** This function is called from within a pre-update callback to retrieve ** a field of the row currently being updated or inserted. */ int sqlite3_preupdate_new(sqlite3 *db, int iIdx, sqlite3_value **ppValue){ PreUpdate *p = db->pPreUpdate; int rc = SQLITE_OK; Mem *pMem; if( !p || p->op==SQLITE_DELETE ){ rc = SQLITE_MISUSE_BKPT; goto preupdate_new_out; } if( p->pPk && p->op!=SQLITE_UPDATE ){ iIdx = sqlite3TableColumnToIndex(p->pPk, iIdx); } if( iIdx>=p->pCsr->nField || iIdx<0 ){ rc = SQLITE_RANGE; goto preupdate_new_out; } if( p->op==SQLITE_INSERT ){ |
︙ | ︙ |
Changes to src/vdbeaux.c.
︙ | ︙ | |||
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | ************************************************************************* ** This file contains code used for creating, destroying, and populating ** a VDBE (or an "sqlite3_stmt" as it is known to the outside world.) */ #include "sqliteInt.h" #include "vdbeInt.h" /* ** Create a new virtual database engine. */ Vdbe *sqlite3VdbeCreate(Parse *pParse){ sqlite3 *db = pParse->db; Vdbe *p; p = sqlite3DbMallocRawNN(db, sizeof(Vdbe) ); if( p==0 ) return 0; memset(&p->aOp, 0, sizeof(Vdbe)-offsetof(Vdbe,aOp)); p->db = db; if( db->pVdbe ){ db->pVdbe->pPrev = p; } p->pNext = db->pVdbe; p->pPrev = 0; db->pVdbe = p; | > > > > | | > > > > > > > | 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 | ************************************************************************* ** This file contains code used for creating, destroying, and populating ** a VDBE (or an "sqlite3_stmt" as it is known to the outside world.) */ #include "sqliteInt.h" #include "vdbeInt.h" /* Forward references */ static void freeEphemeralFunction(sqlite3 *db, FuncDef *pDef); static void vdbeFreeOpArray(sqlite3 *, Op *, int); /* ** Create a new virtual database engine. */ Vdbe *sqlite3VdbeCreate(Parse *pParse){ sqlite3 *db = pParse->db; Vdbe *p; p = sqlite3DbMallocRawNN(db, sizeof(Vdbe) ); if( p==0 ) return 0; memset(&p->aOp, 0, sizeof(Vdbe)-offsetof(Vdbe,aOp)); p->db = db; if( db->pVdbe ){ db->pVdbe->pPrev = p; } p->pNext = db->pVdbe; p->pPrev = 0; db->pVdbe = p; p->iVdbeMagic = VDBE_MAGIC_INIT; p->pParse = pParse; pParse->pVdbe = p; assert( pParse->aLabel==0 ); assert( pParse->nLabel==0 ); assert( p->nOpAlloc==0 ); assert( pParse->szOpAlloc==0 ); sqlite3VdbeAddOp2(p, OP_Init, 0, 1); return p; } /* ** Return the Parse object that owns a Vdbe object. */ Parse *sqlite3VdbeParser(Vdbe *p){ return p->pParse; } /* ** Change the error string stored in Vdbe.zErrMsg */ void sqlite3VdbeError(Vdbe *p, const char *zFormat, ...){ va_list ap; sqlite3DbFree(p->db, p->zErrMsg); |
︙ | ︙ | |||
118 119 120 121 122 123 124 | pB->pNext = pTmp; pTmp = pA->pPrev; pA->pPrev = pB->pPrev; pB->pPrev = pTmp; zTmp = pA->zSql; pA->zSql = pB->zSql; pB->zSql = zTmp; | | | > | > | | | | > > > > > > > | | 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 | pB->pNext = pTmp; pTmp = pA->pPrev; pA->pPrev = pB->pPrev; pB->pPrev = pTmp; zTmp = pA->zSql; pA->zSql = pB->zSql; pB->zSql = zTmp; #ifdef SQLITE_ENABLE_NORMALIZE zTmp = pA->zNormSql; pA->zNormSql = pB->zNormSql; pB->zNormSql = zTmp; #endif pB->expmask = pA->expmask; pB->prepFlags = pA->prepFlags; memcpy(pB->aCounter, pA->aCounter, sizeof(pB->aCounter)); pB->aCounter[SQLITE_STMTSTATUS_REPREPARE]++; } /* ** Resize the Vdbe.aOp array so that it is at least nOp elements larger ** than its current size. nOp is guaranteed to be less than or equal ** to 1024/sizeof(Op). ** ** If an out-of-memory error occurs while resizing the array, return ** SQLITE_NOMEM. In this case Vdbe.aOp and Vdbe.nOpAlloc remain ** unchanged (this is so that any opcodes already allocated can be ** correctly deallocated along with the rest of the Vdbe). */ static int growOpArray(Vdbe *v, int nOp){ VdbeOp *pNew; Parse *p = v->pParse; /* The SQLITE_TEST_REALLOC_STRESS compile-time option is designed to force ** more frequent reallocs and hence provide more opportunities for ** simulated OOM faults. SQLITE_TEST_REALLOC_STRESS is generally used ** during testing only. With SQLITE_TEST_REALLOC_STRESS grow the op array ** by the minimum* amount required until the size reaches 512. Normal ** operation (without SQLITE_TEST_REALLOC_STRESS) is to double the current ** size of the op array or add 1KB of space, whichever is smaller. */ #ifdef SQLITE_TEST_REALLOC_STRESS sqlite3_int64 nNew = (v->nOpAlloc>=512 ? 2*(sqlite3_int64)v->nOpAlloc : (sqlite3_int64)v->nOpAlloc+nOp); #else sqlite3_int64 nNew = (v->nOpAlloc ? 2*(sqlite3_int64)v->nOpAlloc : (sqlite3_int64)(1024/sizeof(Op))); UNUSED_PARAMETER(nOp); #endif /* Ensure that the size of a VDBE does not grow too large */ if( nNew > p->db->aLimit[SQLITE_LIMIT_VDBE_OP] ){ sqlite3OomFault(p->db); return SQLITE_NOMEM; } assert( nOp<=(1024/sizeof(Op)) ); assert( nNew>=(v->nOpAlloc+nOp) ); pNew = sqlite3DbRealloc(p->db, v->aOp, nNew*sizeof(Op)); if( pNew ){ p->szOpAlloc = sqlite3DbMallocSize(p->db, pNew); v->nOpAlloc = p->szOpAlloc/sizeof(Op); v->aOp = pNew; } return (pNew ? SQLITE_OK : SQLITE_NOMEM_BKPT); } #ifdef SQLITE_DEBUG /* This routine is just a convenient place to set a breakpoint that will ** fire after each opcode is inserted and displayed using ** "PRAGMA vdbe_addoptrace=on". Parameters "pc" (program counter) and ** pOp are available to make the breakpoint conditional. ** ** Other useful labels for breakpoints include: ** test_trace_breakpoint(pc,pOp) ** sqlite3CorruptError(lineno) ** sqlite3MisuseError(lineno) ** sqlite3CantopenError(lineno) */ static void test_addop_breakpoint(int pc, Op *pOp){ static int n = 0; n++; } #endif /* ** Add a new instruction to the list of instructions current in the |
︙ | ︙ | |||
202 203 204 205 206 207 208 | ** p1, p2, p3 Operands ** ** Use the sqlite3VdbeResolveLabel() function to fix an address and ** the sqlite3VdbeChangeP4() function to change the value of the P4 ** operand. */ static SQLITE_NOINLINE int growOp3(Vdbe *p, int op, int p1, int p2, int p3){ | | | | | > > | | 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 | ** p1, p2, p3 Operands ** ** Use the sqlite3VdbeResolveLabel() function to fix an address and ** the sqlite3VdbeChangeP4() function to change the value of the P4 ** operand. */ static SQLITE_NOINLINE int growOp3(Vdbe *p, int op, int p1, int p2, int p3){ assert( p->nOpAlloc<=p->nOp ); if( growOpArray(p, 1) ) return 1; assert( p->nOpAlloc>p->nOp ); return sqlite3VdbeAddOp3(p, op, p1, p2, p3); } int sqlite3VdbeAddOp3(Vdbe *p, int op, int p1, int p2, int p3){ int i; VdbeOp *pOp; i = p->nOp; assert( p->iVdbeMagic==VDBE_MAGIC_INIT ); assert( op>=0 && op<0xff ); if( p->nOpAlloc<=i ){ return growOp3(p, op, p1, p2, p3); } assert( p->aOp!=0 ); p->nOp++; pOp = &p->aOp[i]; assert( pOp!=0 ); pOp->opcode = (u8)op; pOp->p5 = 0; pOp->p1 = p1; pOp->p2 = p2; pOp->p3 = p3; pOp->p4.p = 0; pOp->p4type = P4_NOTUSED; #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS pOp->zComment = 0; #endif #ifdef SQLITE_DEBUG if( p->db->flags & SQLITE_VdbeAddopTrace ){ sqlite3VdbePrintOp(0, i, &p->aOp[i]); test_addop_breakpoint(i, &p->aOp[i]); } #endif #ifdef VDBE_PROFILE pOp->cycles = 0; pOp->cnt = 0; #endif #ifdef SQLITE_VDBE_COVERAGE |
︙ | ︙ | |||
314 315 316 317 318 319 320 321 322 323 324 325 326 327 | const char *zP4, /* The P4 operand */ int p4type /* P4 operand type */ ){ int addr = sqlite3VdbeAddOp3(p, op, p1, p2, p3); sqlite3VdbeChangeP4(p, addr, zP4, p4type); return addr; } /* ** Add an opcode that includes the p4 value with a P4_INT64 or ** P4_REAL type. */ int sqlite3VdbeAddOp4Dup8( Vdbe *p, /* Add the opcode to this VM */ | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | const char *zP4, /* The P4 operand */ int p4type /* P4 operand type */ ){ int addr = sqlite3VdbeAddOp3(p, op, p1, p2, p3); sqlite3VdbeChangeP4(p, addr, zP4, p4type); return addr; } /* ** Add an OP_Function or OP_PureFunc opcode. ** ** The eCallCtx argument is information (typically taken from Expr.op2) ** that describes the calling context of the function. 0 means a general ** function call. NC_IsCheck means called by a check constraint, ** NC_IdxExpr means called as part of an index expression. NC_PartIdx ** means in the WHERE clause of a partial index. NC_GenCol means called ** while computing a generated column value. 0 is the usual case. */ int sqlite3VdbeAddFunctionCall( Parse *pParse, /* Parsing context */ int p1, /* Constant argument mask */ int p2, /* First argument register */ int p3, /* Register into which results are written */ int nArg, /* Number of argument */ const FuncDef *pFunc, /* The function to be invoked */ int eCallCtx /* Calling context */ ){ Vdbe *v = pParse->pVdbe; int nByte; int addr; sqlite3_context *pCtx; assert( v ); nByte = sizeof(*pCtx) + (nArg-1)*sizeof(sqlite3_value*); pCtx = sqlite3DbMallocRawNN(pParse->db, nByte); if( pCtx==0 ){ assert( pParse->db->mallocFailed ); freeEphemeralFunction(pParse->db, (FuncDef*)pFunc); return 0; } pCtx->pOut = 0; pCtx->pFunc = (FuncDef*)pFunc; pCtx->pVdbe = 0; pCtx->isError = 0; pCtx->argc = nArg; pCtx->iOp = sqlite3VdbeCurrentAddr(v); addr = sqlite3VdbeAddOp4(v, eCallCtx ? OP_PureFunc : OP_Function, p1, p2, p3, (char*)pCtx, P4_FUNCCTX); sqlite3VdbeChangeP5(v, eCallCtx & NC_SelfRef); return addr; } /* ** Add an opcode that includes the p4 value with a P4_INT64 or ** P4_REAL type. */ int sqlite3VdbeAddOp4Dup8( Vdbe *p, /* Add the opcode to this VM */ |
︙ | ︙ | |||
345 346 347 348 349 350 351 352 353 354 355 356 357 358 | int sqlite3VdbeExplainParent(Parse *pParse){ VdbeOp *pOp; if( pParse->addrExplain==0 ) return 0; pOp = sqlite3VdbeGetOp(pParse->pVdbe, pParse->addrExplain); return pOp->p2; } /* ** Add a new OP_Explain opcode. ** ** If the bPush flag is true, then make this opcode the parent for ** subsequent Explains until sqlite3VdbeExplainPop() is called. */ void sqlite3VdbeExplain(Parse *pParse, u8 bPush, const char *zFmt, ...){ | > > > > > > > > > > > > > > | > > > > | > > | > > | 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 | int sqlite3VdbeExplainParent(Parse *pParse){ VdbeOp *pOp; if( pParse->addrExplain==0 ) return 0; pOp = sqlite3VdbeGetOp(pParse->pVdbe, pParse->addrExplain); return pOp->p2; } /* ** Set a debugger breakpoint on the following routine in order to ** monitor the EXPLAIN QUERY PLAN code generation. */ #if defined(SQLITE_DEBUG) void sqlite3ExplainBreakpoint(const char *z1, const char *z2){ (void)z1; (void)z2; } #endif /* ** Add a new OP_Explain opcode. ** ** If the bPush flag is true, then make this opcode the parent for ** subsequent Explains until sqlite3VdbeExplainPop() is called. */ void sqlite3VdbeExplain(Parse *pParse, u8 bPush, const char *zFmt, ...){ #ifndef SQLITE_DEBUG /* Always include the OP_Explain opcodes if SQLITE_DEBUG is defined. ** But omit them (for performance) during production builds */ if( pParse->explain==2 ) #endif { char *zMsg; Vdbe *v; va_list ap; int iThis; va_start(ap, zFmt); zMsg = sqlite3VMPrintf(pParse->db, zFmt, ap); va_end(ap); v = pParse->pVdbe; iThis = v->nOp; sqlite3VdbeAddOp4(v, OP_Explain, iThis, pParse->addrExplain, 0, zMsg, P4_DYNAMIC); sqlite3ExplainBreakpoint(bPush?"PUSH":"", sqlite3VdbeGetOp(v,-1)->p4.z); if( bPush){ pParse->addrExplain = iThis; } } } /* ** Pop the EXPLAIN QUERY PLAN stack one level. */ void sqlite3VdbeExplainPop(Parse *pParse){ sqlite3ExplainBreakpoint("POP", 0); pParse->addrExplain = sqlite3VdbeExplainParent(pParse); } #endif /* SQLITE_OMIT_EXPLAIN */ /* ** Add an OP_ParseSchema opcode. This routine is broken out from ** sqlite3VdbeAddOp4() since it needs to also needs to mark all btrees ** as having been used. ** ** The zWhere string must have been obtained from sqlite3_malloc(). ** This routine will take ownership of the allocated memory. */ void sqlite3VdbeAddParseSchemaOp(Vdbe *p, int iDb, char *zWhere, u16 p5){ int j; sqlite3VdbeAddOp4(p, OP_ParseSchema, iDb, 0, 0, zWhere, P4_DYNAMIC); sqlite3VdbeChangeP5(p, p5); for(j=0; j<p->db->nDb; j++) sqlite3VdbeUsesBtree(p, j); sqlite3MayAbort(p->pParse); } /* ** Add an opcode that includes the p4 value as an integer. */ int sqlite3VdbeAddOp4Int( Vdbe *p, /* Add the opcode to this VM */ |
︙ | ︙ | |||
436 437 438 439 440 441 442 443 | ** the label is resolved to a specific address, the VDBE will scan ** through its operation list and change all values of P2 which match ** the label into the resolved address. ** ** The VDBE knows that a P2 value is a label because labels are ** always negative and P2 values are suppose to be non-negative. ** Hence, a negative P2 value is a label that has yet to be resolved. ** | > > > | > > > > > > > > | < | < < < < < < < < < > > > > > > > > > > > > > > > | | < | | | > > > | 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 | ** the label is resolved to a specific address, the VDBE will scan ** through its operation list and change all values of P2 which match ** the label into the resolved address. ** ** The VDBE knows that a P2 value is a label because labels are ** always negative and P2 values are suppose to be non-negative. ** Hence, a negative P2 value is a label that has yet to be resolved. ** (Later:) This is only true for opcodes that have the OPFLG_JUMP ** property. ** ** Variable usage notes: ** ** Parse.aLabel[x] Stores the address that the x-th label resolves ** into. For testing (SQLITE_DEBUG), unresolved ** labels stores -1, but that is not required. ** Parse.nLabelAlloc Number of slots allocated to Parse.aLabel[] ** Parse.nLabel The *negative* of the number of labels that have ** been issued. The negative is stored because ** that gives a performance improvement over storing ** the equivalent positive value. */ int sqlite3VdbeMakeLabel(Parse *pParse){ return --pParse->nLabel; } /* ** Resolve label "x" to be the address of the next instruction to ** be inserted. The parameter "x" must have been obtained from ** a prior call to sqlite3VdbeMakeLabel(). */ static SQLITE_NOINLINE void resizeResolveLabel(Parse *p, Vdbe *v, int j){ int nNewSize = 10 - p->nLabel; p->aLabel = sqlite3DbReallocOrFree(p->db, p->aLabel, nNewSize*sizeof(p->aLabel[0])); if( p->aLabel==0 ){ p->nLabelAlloc = 0; }else{ #ifdef SQLITE_DEBUG int i; for(i=p->nLabelAlloc; i<nNewSize; i++) p->aLabel[i] = -1; #endif p->nLabelAlloc = nNewSize; p->aLabel[j] = v->nOp; } } void sqlite3VdbeResolveLabel(Vdbe *v, int x){ Parse *p = v->pParse; int j = ADDR(x); assert( v->iVdbeMagic==VDBE_MAGIC_INIT ); assert( j<-p->nLabel ); assert( j>=0 ); #ifdef SQLITE_DEBUG if( p->db->flags & SQLITE_VdbeAddopTrace ){ printf("RESOLVE LABEL %d to %d\n", x, v->nOp); } #endif if( p->nLabelAlloc + p->nLabel < 0 ){ resizeResolveLabel(p,v,j); }else{ assert( p->aLabel[j]==(-1) ); /* Labels may only be resolved once */ p->aLabel[j] = v->nOp; } } /* ** Mark the VDBE as one that can only be run one time. |
︙ | ︙ | |||
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 | ** to be rolled back). This condition is true if the main program or any ** sub-programs contains any of the following: ** ** * OP_Halt with P1=SQLITE_CONSTRAINT and P2=OE_Abort. ** * OP_HaltIfNull with P1=SQLITE_CONSTRAINT and P2=OE_Abort. ** * OP_Destroy ** * OP_VUpdate ** * OP_VRename ** * OP_FkCounter with P2==0 (immediate foreign key constraint) ** * OP_CreateBtree/BTREE_INTKEY and OP_InitCoroutine ** (for CREATE TABLE AS SELECT ...) ** ** Then check that the value of Parse.mayAbort is true if an ** ABORT may be thrown, or false otherwise. Return true if it does ** match, or false otherwise. This function is intended to be used as ** part of an assert statement in the compiler. Similar to: ** ** assert( sqlite3VdbeAssertMayAbort(pParse->pVdbe, pParse->mayAbort) ); */ int sqlite3VdbeAssertMayAbort(Vdbe *v, int mayAbort){ int hasAbort = 0; int hasFkCounter = 0; int hasCreateTable = 0; int hasInitCoroutine = 0; Op *pOp; VdbeOpIter sIter; memset(&sIter, 0, sizeof(sIter)); sIter.v = v; while( (pOp = opIterNext(&sIter))!=0 ){ int opcode = pOp->opcode; if( opcode==OP_Destroy || opcode==OP_VUpdate || opcode==OP_VRename || ((opcode==OP_Halt || opcode==OP_HaltIfNull) | > > > > > | > > > > > > > > | > | 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 | ** to be rolled back). This condition is true if the main program or any ** sub-programs contains any of the following: ** ** * OP_Halt with P1=SQLITE_CONSTRAINT and P2=OE_Abort. ** * OP_HaltIfNull with P1=SQLITE_CONSTRAINT and P2=OE_Abort. ** * OP_Destroy ** * OP_VUpdate ** * OP_VCreate ** * OP_VRename ** * OP_FkCounter with P2==0 (immediate foreign key constraint) ** * OP_CreateBtree/BTREE_INTKEY and OP_InitCoroutine ** (for CREATE TABLE AS SELECT ...) ** ** Then check that the value of Parse.mayAbort is true if an ** ABORT may be thrown, or false otherwise. Return true if it does ** match, or false otherwise. This function is intended to be used as ** part of an assert statement in the compiler. Similar to: ** ** assert( sqlite3VdbeAssertMayAbort(pParse->pVdbe, pParse->mayAbort) ); */ int sqlite3VdbeAssertMayAbort(Vdbe *v, int mayAbort){ int hasAbort = 0; int hasFkCounter = 0; int hasCreateTable = 0; int hasCreateIndex = 0; int hasInitCoroutine = 0; Op *pOp; VdbeOpIter sIter; memset(&sIter, 0, sizeof(sIter)); sIter.v = v; while( (pOp = opIterNext(&sIter))!=0 ){ int opcode = pOp->opcode; if( opcode==OP_Destroy || opcode==OP_VUpdate || opcode==OP_VRename || opcode==OP_VDestroy || opcode==OP_VCreate || opcode==OP_ParseSchema || ((opcode==OP_Halt || opcode==OP_HaltIfNull) && ((pOp->p1)!=SQLITE_OK && pOp->p2==OE_Abort)) ){ hasAbort = 1; break; } if( opcode==OP_CreateBtree && pOp->p3==BTREE_INTKEY ) hasCreateTable = 1; if( mayAbort ){ /* hasCreateIndex may also be set for some DELETE statements that use ** OP_Clear. So this routine may end up returning true in the case ** where a "DELETE FROM tbl" has a statement-journal but does not ** require one. This is not so bad - it is an inefficiency, not a bug. */ if( opcode==OP_CreateBtree && pOp->p3==BTREE_BLOBKEY ) hasCreateIndex = 1; if( opcode==OP_Clear ) hasCreateIndex = 1; } if( opcode==OP_InitCoroutine ) hasInitCoroutine = 1; #ifndef SQLITE_OMIT_FOREIGN_KEY if( opcode==OP_FkCounter && pOp->p1==0 && pOp->p2==1 ){ hasFkCounter = 1; } #endif } 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 || hasFkCounter || (hasCreateTable && hasInitCoroutine) || hasCreateIndex ); } #endif /* SQLITE_DEBUG - the sqlite3AssertMayAbort() function */ #ifdef SQLITE_DEBUG /* ** Increment the nWrite counter in the VDBE if the cursor is not an ** ephemeral cursor, or if the cursor argument is NULL. |
︙ | ︙ | |||
689 690 691 692 693 694 695 | */ if( pOp->opcode<=SQLITE_MX_JUMP_OPCODE ){ /* NOTE: Be sure to update mkopcodeh.tcl when adding or removing ** cases from this switch! */ switch( pOp->opcode ){ case OP_Transaction: { if( pOp->p2!=0 ) p->readOnly = 0; | | | 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 | */ if( pOp->opcode<=SQLITE_MX_JUMP_OPCODE ){ /* NOTE: Be sure to update mkopcodeh.tcl when adding or removing ** cases from this switch! */ switch( pOp->opcode ){ case OP_Transaction: { if( pOp->p2!=0 ) p->readOnly = 0; /* no break */ deliberate_fall_through } case OP_AutoCommit: case OP_Savepoint: { p->bIsReader = 1; break; } #ifndef SQLITE_OMIT_WAL |
︙ | ︙ | |||
736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 | case OP_VFilter: { int n; assert( (pOp - p->aOp) >= 3 ); assert( pOp[-1].opcode==OP_Integer ); n = pOp[-1].p1; if( n>nMaxArgs ) nMaxArgs = n; /* Fall through into the default case */ } #endif default: { if( pOp->p2<0 ){ /* The mkopcodeh.tcl script has so arranged things that the only ** non-jump opcodes less than SQLITE_MX_JUMP_CODE are guaranteed to ** have non-negative values for P2. */ assert( (sqlite3OpcodeProperty[pOp->opcode] & OPFLG_JUMP)!=0 ); | > | | 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 | case OP_VFilter: { int n; assert( (pOp - p->aOp) >= 3 ); assert( pOp[-1].opcode==OP_Integer ); n = pOp[-1].p1; if( n>nMaxArgs ) nMaxArgs = n; /* Fall through into the default case */ /* no break */ deliberate_fall_through } #endif default: { if( pOp->p2<0 ){ /* The mkopcodeh.tcl script has so arranged things that the only ** non-jump opcodes less than SQLITE_MX_JUMP_CODE are guaranteed to ** have non-negative values for P2. */ assert( (sqlite3OpcodeProperty[pOp->opcode] & OPFLG_JUMP)!=0 ); assert( ADDR(pOp->p2)<-pParse->nLabel ); pOp->p2 = aLabel[ADDR(pOp->p2)]; } break; } } /* The mkopcodeh.tcl script has so arranged things that the only ** non-jump opcodes less than SQLITE_MX_JUMP_CODE are guaranteed to |
︙ | ︙ | |||
769 770 771 772 773 774 775 | assert( p->bIsReader!=0 || DbMaskAllZero(p->btreeMask) ); } /* ** Return the address of the next instruction to be inserted. */ int sqlite3VdbeCurrentAddr(Vdbe *p){ | | | | 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 | assert( p->bIsReader!=0 || DbMaskAllZero(p->btreeMask) ); } /* ** Return the address of the next instruction to be inserted. */ int sqlite3VdbeCurrentAddr(Vdbe *p){ assert( p->iVdbeMagic==VDBE_MAGIC_INIT ); return p->nOp; } /* ** Verify that at least N opcode slots are available in p without ** having to malloc for more space (except when compiled using ** SQLITE_TEST_REALLOC_STRESS). This interface is used during testing ** to verify that certain calls to sqlite3VdbeAddOpList() can never ** fail due to a OOM fault and hence that the return value from ** sqlite3VdbeAddOpList() will always be non-NULL. */ #if defined(SQLITE_DEBUG) && !defined(SQLITE_TEST_REALLOC_STRESS) void sqlite3VdbeVerifyNoMallocRequired(Vdbe *p, int N){ assert( p->nOp + N <= p->nOpAlloc ); } #endif /* ** Verify that the VM passed as the only argument does not contain ** an OP_ResultRow opcode. Fail an assert() if it does. This is used ** by code in pragma.c to ensure that the implementation of certain |
︙ | ︙ | |||
854 855 856 857 858 859 860 | int nOp, /* Number of opcodes to add */ VdbeOpList const *aOp, /* The opcodes to be added */ int iLineno /* Source-file line number of first opcode */ ){ int i; VdbeOp *pOut, *pFirst; assert( nOp>0 ); | | | | 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 | int nOp, /* Number of opcodes to add */ VdbeOpList const *aOp, /* The opcodes to be added */ int iLineno /* Source-file line number of first opcode */ ){ int i; VdbeOp *pOut, *pFirst; assert( nOp>0 ); assert( p->iVdbeMagic==VDBE_MAGIC_INIT ); if( p->nOp + nOp > p->nOpAlloc && growOpArray(p, nOp) ){ return 0; } pFirst = pOut = &p->aOp[p->nOp]; for(i=0; i<nOp; i++, aOp++, pOut++){ pOut->opcode = aOp->opcode; pOut->p1 = aOp->p1; pOut->p2 = aOp->p2; |
︙ | ︙ | |||
901 902 903 904 905 906 907 | Vdbe *p, /* VM to add scanstatus() to */ int addrExplain, /* Address of OP_Explain (or 0) */ int addrLoop, /* Address of loop counter */ int addrVisit, /* Address of rows visited counter */ LogEst nEst, /* Estimated number of output rows */ const char *zName /* Name of table or index being scanned */ ){ | | | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > < < | | 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 | Vdbe *p, /* VM to add scanstatus() to */ int addrExplain, /* Address of OP_Explain (or 0) */ int addrLoop, /* Address of loop counter */ int addrVisit, /* Address of rows visited counter */ LogEst nEst, /* Estimated number of output rows */ const char *zName /* Name of table or index being scanned */ ){ sqlite3_int64 nByte = (p->nScan+1) * sizeof(ScanStatus); ScanStatus *aNew; aNew = (ScanStatus*)sqlite3DbRealloc(p->db, p->aScan, nByte); if( aNew ){ ScanStatus *pNew = &aNew[p->nScan++]; pNew->addrExplain = addrExplain; pNew->addrLoop = addrLoop; pNew->addrVisit = addrVisit; pNew->nEst = nEst; pNew->zName = sqlite3DbStrDup(p->db, zName); p->aScan = aNew; } } #endif /* ** Change the value of the opcode, or P1, P2, P3, or P5 operands ** for a specific instruction. */ void sqlite3VdbeChangeOpcode(Vdbe *p, int addr, u8 iNewOpcode){ sqlite3VdbeGetOp(p,addr)->opcode = iNewOpcode; } void sqlite3VdbeChangeP1(Vdbe *p, int addr, int val){ sqlite3VdbeGetOp(p,addr)->p1 = val; } void sqlite3VdbeChangeP2(Vdbe *p, int addr, int val){ sqlite3VdbeGetOp(p,addr)->p2 = val; } void sqlite3VdbeChangeP3(Vdbe *p, int addr, int val){ sqlite3VdbeGetOp(p,addr)->p3 = val; } void sqlite3VdbeChangeP5(Vdbe *p, u16 p5){ assert( p->nOp>0 || p->db->mallocFailed ); if( p->nOp>0 ) p->aOp[p->nOp-1].p5 = p5; } /* ** Change the P2 operand of instruction addr so that it points to ** the address of the next instruction to be coded. */ void sqlite3VdbeJumpHere(Vdbe *p, int addr){ sqlite3VdbeChangeP2(p, addr, p->nOp); } /* ** Change the P2 operand of the jump instruction at addr so that ** the jump lands on the next opcode. Or if the jump instruction was ** the previous opcode (and is thus a no-op) then simply back up ** the next instruction counter by one slot so that the jump is ** overwritten by the next inserted opcode. ** ** This routine is an optimization of sqlite3VdbeJumpHere() that ** strives to omit useless byte-code like this: ** ** 7 Once 0 8 0 ** 8 ... */ void sqlite3VdbeJumpHereOrPopInst(Vdbe *p, int addr){ if( addr==p->nOp-1 ){ assert( p->aOp[addr].opcode==OP_Once || p->aOp[addr].opcode==OP_If || p->aOp[addr].opcode==OP_FkIfZero ); assert( p->aOp[addr].p4type==0 ); #ifdef SQLITE_VDBE_COVERAGE sqlite3VdbeGetOp(p,-1)->iSrcLine = 0; /* Erase VdbeCoverage() macros */ #endif p->nOp--; }else{ sqlite3VdbeChangeP2(p, addr, p->nOp); } } /* ** If the input FuncDef structure is ephemeral, then free it. If ** the FuncDef is not ephermal, then do nothing. */ static void freeEphemeralFunction(sqlite3 *db, FuncDef *pDef){ if( (pDef->funcFlags & SQLITE_FUNC_EPHEM)!=0 ){ sqlite3DbFreeNN(db, pDef); } } /* ** Delete a P4 value if necessary. */ static SQLITE_NOINLINE void freeP4Mem(sqlite3 *db, Mem *p){ if( p->szMalloc ) sqlite3DbFree(db, p->zMalloc); sqlite3DbFreeNN(db, p); } static SQLITE_NOINLINE void freeP4FuncCtx(sqlite3 *db, sqlite3_context *p){ freeEphemeralFunction(db, p->pFunc); sqlite3DbFreeNN(db, p); } static void freeP4(sqlite3 *db, int p4type, void *p4){ assert( db ); switch( p4type ){ case P4_FUNCCTX: { freeP4FuncCtx(db, (sqlite3_context*)p4); break; |
︙ | ︙ | |||
1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 | ** list at Vdbe.pSubProgram. This list is used to delete all sub-program ** objects when the VM is no longer required. */ void sqlite3VdbeLinkSubProgram(Vdbe *pVdbe, SubProgram *p){ p->pNext = pVdbe->pProgram; pVdbe->pProgram = p; } /* ** Change the opcode at addr into OP_Noop */ int sqlite3VdbeChangeToNoop(Vdbe *p, int addr){ VdbeOp *pOp; if( p->db->mallocFailed ) return 0; | > > > > > > > | 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 | ** list at Vdbe.pSubProgram. This list is used to delete all sub-program ** objects when the VM is no longer required. */ void sqlite3VdbeLinkSubProgram(Vdbe *pVdbe, SubProgram *p){ p->pNext = pVdbe->pProgram; pVdbe->pProgram = p; } /* ** Return true if the given Vdbe has any SubPrograms. */ int sqlite3VdbeHasSubProgram(Vdbe *pVdbe){ return pVdbe->pProgram!=0; } /* ** Change the opcode at addr into OP_Noop */ int sqlite3VdbeChangeToNoop(Vdbe *p, int addr){ VdbeOp *pOp; if( p->db->mallocFailed ) return 0; |
︙ | ︙ | |||
1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 | int sqlite3VdbeDeletePriorOpcode(Vdbe *p, u8 op){ if( p->nOp>0 && p->aOp[p->nOp-1].opcode==op ){ return sqlite3VdbeChangeToNoop(p, p->nOp-1); }else{ return 0; } } /* ** Change the value of the P4 operand for a specific instruction. ** This routine is useful when a large program is loaded from a ** static array using sqlite3VdbeAddOpList but we want to make a ** few minor changes to the program. ** | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | int sqlite3VdbeDeletePriorOpcode(Vdbe *p, u8 op){ if( p->nOp>0 && p->aOp[p->nOp-1].opcode==op ){ return sqlite3VdbeChangeToNoop(p, p->nOp-1); }else{ return 0; } } #ifdef SQLITE_DEBUG /* ** Generate an OP_ReleaseReg opcode to indicate that a range of ** registers, except any identified by mask, are no longer in use. */ void sqlite3VdbeReleaseRegisters( Parse *pParse, /* Parsing context */ int iFirst, /* Index of first register to be released */ int N, /* Number of registers to release */ u32 mask, /* Mask of registers to NOT release */ int bUndefine /* If true, mark registers as undefined */ ){ if( N==0 ) return; assert( pParse->pVdbe ); assert( iFirst>=1 ); assert( iFirst+N-1<=pParse->nMem ); if( N<=31 && mask!=0 ){ while( N>0 && (mask&1)!=0 ){ mask >>= 1; iFirst++; N--; } while( N>0 && N<=32 && (mask & MASKBIT32(N-1))!=0 ){ mask &= ~MASKBIT32(N-1); N--; } } if( N>0 ){ sqlite3VdbeAddOp3(pParse->pVdbe, OP_ReleaseReg, iFirst, N, *(int*)&mask); if( bUndefine ) sqlite3VdbeChangeP5(pParse->pVdbe, 1); } } #endif /* SQLITE_DEBUG */ /* ** Change the value of the P4 operand for a specific instruction. ** This routine is useful when a large program is loaded from a ** static array using sqlite3VdbeAddOpList but we want to make a ** few minor changes to the program. ** |
︙ | ︙ | |||
1110 1111 1112 1113 1114 1115 1116 | } } void sqlite3VdbeChangeP4(Vdbe *p, int addr, const char *zP4, int n){ Op *pOp; sqlite3 *db; assert( p!=0 ); db = p->db; | | | 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 | } } void sqlite3VdbeChangeP4(Vdbe *p, int addr, const char *zP4, int n){ Op *pOp; sqlite3 *db; assert( p!=0 ); db = p->db; assert( p->iVdbeMagic==VDBE_MAGIC_INIT ); assert( p->aOp!=0 || db->mallocFailed ); if( db->mallocFailed ){ if( n!=P4_VTAB ) freeP4(db, n, (void*)*(char**)&zP4); return; } assert( p->nOp>0 ); assert( addr<p->nOp ); |
︙ | ︙ | |||
1186 1187 1188 1189 1190 1191 1192 | ** Change the comment on the most recently coded instruction. Or ** insert a No-op and add the comment to that new instruction. This ** makes the code easier to read during debugging. None of this happens ** in a production build. */ static void vdbeVComment(Vdbe *p, const char *zFormat, va_list ap){ assert( p->nOp>0 || p->aOp==0 ); | | > | 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 | ** Change the comment on the most recently coded instruction. Or ** insert a No-op and add the comment to that new instruction. This ** makes the code easier to read during debugging. None of this happens ** in a production build. */ static void vdbeVComment(Vdbe *p, const char *zFormat, va_list ap){ assert( p->nOp>0 || p->aOp==0 ); assert( p->aOp==0 || p->aOp[p->nOp-1].zComment==0 || p->db->mallocFailed || p->pParse->nErr>0 ); if( p->nOp ){ assert( p->aOp ); sqlite3DbFree(p->db, p->aOp[p->nOp-1].zComment); p->aOp[p->nOp-1].zComment = sqlite3VMPrintf(p->db, zFormat, ap); } } void sqlite3VdbeComment(Vdbe *p, const char *zFormat, ...){ |
︙ | ︙ | |||
1238 1239 1240 1241 1242 1243 1244 | ** dummy will never be written to. This is verified by code inspection and ** by running with Valgrind. */ VdbeOp *sqlite3VdbeGetOp(Vdbe *p, int addr){ /* C89 specifies that the constant "dummy" will be initialized to all ** zeros, which is correct. MSVC generates a warning, nevertheless. */ static VdbeOp dummy; /* Ignore the MSVC warning about no initializer */ | | | 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 | ** dummy will never be written to. This is verified by code inspection and ** by running with Valgrind. */ VdbeOp *sqlite3VdbeGetOp(Vdbe *p, int addr){ /* C89 specifies that the constant "dummy" will be initialized to all ** zeros, which is correct. MSVC generates a warning, nevertheless. */ static VdbeOp dummy; /* Ignore the MSVC warning about no initializer */ assert( p->iVdbeMagic==VDBE_MAGIC_INIT ); if( addr<0 ){ addr = p->nOp - 1; } assert( (addr>=0 && addr<p->nOp) || p->db->mallocFailed ); if( p->db->mallocFailed ){ return (VdbeOp*)&dummy; }else{ |
︙ | ︙ | |||
1276 1277 1278 1279 1280 1281 1282 | ** Some translation occurs: ** ** "PX" -> "r[X]" ** "PX@PY" -> "r[X..X+Y-1]" or "r[x]" if y is 0 or 1 ** "PX@PY+1" -> "r[X..X+Y]" or "r[x]" if y is 0 ** "PY..PY" -> "r[X..Y]" or "r[x]" if y<=x */ | | > | < < | > > > | < < < | < | | | < < | | > > > > > > > > > > > > > > > > | | | | < > < > | | < < | > > | < < < | | > | 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 | ** Some translation occurs: ** ** "PX" -> "r[X]" ** "PX@PY" -> "r[X..X+Y-1]" or "r[x]" if y is 0 or 1 ** "PX@PY+1" -> "r[X..X+Y]" or "r[x]" if y is 0 ** "PY..PY" -> "r[X..Y]" or "r[x]" if y<=x */ char *sqlite3VdbeDisplayComment( sqlite3 *db, /* Optional - Oom error reporting only */ const Op *pOp, /* The opcode to be commented */ const char *zP4 /* Previously obtained value for P4 */ ){ const char *zOpName; const char *zSynopsis; int nOpName; int ii; char zAlt[50]; StrAccum x; sqlite3StrAccumInit(&x, 0, 0, 0, SQLITE_MAX_LENGTH); zOpName = sqlite3OpcodeName(pOp->opcode); nOpName = sqlite3Strlen30(zOpName); if( zOpName[nOpName+1] ){ int seenCom = 0; char c; zSynopsis = zOpName + nOpName + 1; if( strncmp(zSynopsis,"IF ",3)==0 ){ sqlite3_snprintf(sizeof(zAlt), zAlt, "if %s goto P2", zSynopsis+3); zSynopsis = zAlt; } for(ii=0; (c = zSynopsis[ii])!=0; ii++){ if( c=='P' ){ c = zSynopsis[++ii]; if( c=='4' ){ sqlite3_str_appendall(&x, zP4); }else if( c=='X' ){ sqlite3_str_appendall(&x, pOp->zComment); seenCom = 1; }else{ int v1 = translateP(c, pOp); int v2; if( strncmp(zSynopsis+ii+1, "@P", 2)==0 ){ ii += 3; v2 = translateP(zSynopsis[ii], pOp); if( strncmp(zSynopsis+ii+1,"+1",2)==0 ){ ii += 2; v2++; } if( v2<2 ){ sqlite3_str_appendf(&x, "%d", v1); }else{ sqlite3_str_appendf(&x, "%d..%d", v1, v1+v2-1); } }else if( strncmp(zSynopsis+ii+1, "@NP", 3)==0 ){ sqlite3_context *pCtx = pOp->p4.pCtx; if( pOp->p4type!=P4_FUNCCTX || pCtx->argc==1 ){ sqlite3_str_appendf(&x, "%d", v1); }else if( pCtx->argc>1 ){ sqlite3_str_appendf(&x, "%d..%d", v1, v1+pCtx->argc-1); }else if( x.accError==0 ){ assert( x.nChar>2 ); x.nChar -= 2; ii++; } ii += 3; }else{ sqlite3_str_appendf(&x, "%d", v1); if( strncmp(zSynopsis+ii+1, "..P3", 4)==0 && pOp->p3==0 ){ ii += 4; } } } }else{ sqlite3_str_appendchar(&x, 1, c); } } if( !seenCom && pOp->zComment ){ sqlite3_str_appendf(&x, "; %s", pOp->zComment); } }else if( pOp->zComment ){ sqlite3_str_appendall(&x, pOp->zComment); } if( (x.accError & SQLITE_NOMEM)!=0 && db!=0 ){ sqlite3OomFault(db); } return sqlite3StrAccumFinish(&x); } #endif /* SQLITE_ENABLE_EXPLAIN_COMMENTS */ #if VDBE_DISPLAY_P4 && defined(SQLITE_ENABLE_CURSOR_HINTS) /* ** Translate the P4.pExpr value for an OP_CursorHint opcode into text ** that can be displayed in the P4 column of EXPLAIN output. */ static void displayP4Expr(StrAccum *p, Expr *pExpr){ const char *zOp = 0; switch( pExpr->op ){ case TK_STRING: assert( !ExprHasProperty(pExpr, EP_IntValue) ); sqlite3_str_appendf(p, "%Q", pExpr->u.zToken); break; case TK_INTEGER: sqlite3_str_appendf(p, "%d", pExpr->u.iValue); break; case TK_NULL: sqlite3_str_appendf(p, "NULL"); |
︙ | ︙ | |||
1428 1429 1430 1431 1432 1433 1434 | #if VDBE_DISPLAY_P4 /* ** Compute a string that describes the P4 parameter for an opcode. ** Use zTemp for any required temporary buffer space. */ | | | | | | | | > > > > | > < < | | | | | < | < | < < < | | > > > | < < | 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 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 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 | #if VDBE_DISPLAY_P4 /* ** Compute a string that describes the P4 parameter for an opcode. ** Use zTemp for any required temporary buffer space. */ char *sqlite3VdbeDisplayP4(sqlite3 *db, Op *pOp){ char *zP4 = 0; StrAccum x; sqlite3StrAccumInit(&x, 0, 0, 0, SQLITE_MAX_LENGTH); switch( pOp->p4type ){ case P4_KEYINFO: { int j; KeyInfo *pKeyInfo = pOp->p4.pKeyInfo; assert( pKeyInfo->aSortFlags!=0 ); sqlite3_str_appendf(&x, "k(%d", pKeyInfo->nKeyField); for(j=0; j<pKeyInfo->nKeyField; j++){ CollSeq *pColl = pKeyInfo->aColl[j]; const char *zColl = pColl ? pColl->zName : ""; if( strcmp(zColl, "BINARY")==0 ) zColl = "B"; sqlite3_str_appendf(&x, ",%s%s%s", (pKeyInfo->aSortFlags[j] & KEYINFO_ORDER_DESC) ? "-" : "", (pKeyInfo->aSortFlags[j] & KEYINFO_ORDER_BIGNULL)? "N." : "", zColl); } sqlite3_str_append(&x, ")", 1); break; } #ifdef SQLITE_ENABLE_CURSOR_HINTS case P4_EXPR: { displayP4Expr(&x, pOp->p4.pExpr); break; } #endif case P4_COLLSEQ: { static const char *const encnames[] = {"?", "8", "16LE", "16BE"}; CollSeq *pColl = pOp->p4.pColl; assert( pColl->enc<4 ); sqlite3_str_appendf(&x, "%.18s-%s", pColl->zName, encnames[pColl->enc]); break; } case P4_FUNCDEF: { FuncDef *pDef = pOp->p4.pFunc; sqlite3_str_appendf(&x, "%s(%d)", pDef->zName, pDef->nArg); break; } case P4_FUNCCTX: { FuncDef *pDef = pOp->p4.pCtx->pFunc; sqlite3_str_appendf(&x, "%s(%d)", pDef->zName, pDef->nArg); break; } case P4_INT64: { sqlite3_str_appendf(&x, "%lld", *pOp->p4.pI64); break; } case P4_INT32: { sqlite3_str_appendf(&x, "%d", pOp->p4.i); break; } case P4_REAL: { sqlite3_str_appendf(&x, "%.16g", *pOp->p4.pReal); break; } case P4_MEM: { Mem *pMem = pOp->p4.pMem; if( pMem->flags & MEM_Str ){ zP4 = pMem->z; }else if( pMem->flags & (MEM_Int|MEM_IntReal) ){ sqlite3_str_appendf(&x, "%lld", pMem->u.i); }else if( pMem->flags & MEM_Real ){ sqlite3_str_appendf(&x, "%.16g", pMem->u.r); }else if( pMem->flags & MEM_Null ){ zP4 = "NULL"; }else{ assert( pMem->flags & MEM_Blob ); zP4 = "(blob)"; } break; } #ifndef SQLITE_OMIT_VIRTUALTABLE case P4_VTAB: { sqlite3_vtab *pVtab = pOp->p4.pVtab->pVtab; sqlite3_str_appendf(&x, "vtab:%p", pVtab); break; } #endif case P4_INTARRAY: { u32 i; u32 *ai = pOp->p4.ai; u32 n = ai[0]; /* The first element of an INTARRAY is always the ** count of the number of elements to follow */ for(i=1; i<=n; i++){ sqlite3_str_appendf(&x, "%c%u", (i==1 ? '[' : ','), ai[i]); } sqlite3_str_append(&x, "]", 1); break; } case P4_SUBPROGRAM: { zP4 = "program"; break; } case P4_DYNBLOB: case P4_ADVANCE: { break; } case P4_TABLE: { zP4 = pOp->p4.pTab->zName; break; } default: { zP4 = pOp->p4.z; } } if( zP4 ) sqlite3_str_appendall(&x, zP4); if( (x.accError & SQLITE_NOMEM)!=0 ){ sqlite3OomFault(db); } return sqlite3StrAccumFinish(&x); } #endif /* VDBE_DISPLAY_P4 */ /* ** Declare to the Vdbe that the BTree object at db->aDb[i] is used. ** ** The prepared statements need to know in advance the complete set of |
︙ | ︙ | |||
1632 1633 1634 1635 1636 1637 1638 | #if defined(VDBE_PROFILE) || defined(SQLITE_DEBUG) /* ** Print a single opcode. This routine is used for debugging only. */ void sqlite3VdbePrintOp(FILE *pOut, int pc, VdbeOp *pOp){ char *zP4; | | | > > | | | | > | > > > | 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 | #if defined(VDBE_PROFILE) || defined(SQLITE_DEBUG) /* ** Print a single opcode. This routine is used for debugging only. */ void sqlite3VdbePrintOp(FILE *pOut, int pc, VdbeOp *pOp){ char *zP4; char *zCom; sqlite3 dummyDb; static const char *zFormat1 = "%4d %-13s %4d %4d %4d %-13s %.2X %s\n"; if( pOut==0 ) pOut = stdout; sqlite3BeginBenignMalloc(); dummyDb.mallocFailed = 1; zP4 = sqlite3VdbeDisplayP4(&dummyDb, pOp); #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS zCom = sqlite3VdbeDisplayComment(0, pOp, zP4); #else zCom = 0; #endif /* NB: The sqlite3OpcodeName() function is implemented by code created ** by the mkopcodeh.awk and mkopcodec.awk scripts which extract the ** information from the vdbe.c source text */ fprintf(pOut, zFormat1, pc, sqlite3OpcodeName(pOp->opcode), pOp->p1, pOp->p2, pOp->p3, zP4 ? zP4 : "", pOp->p5, zCom ? zCom : "" ); fflush(pOut); sqlite3_free(zP4); sqlite3_free(zCom); sqlite3EndBenignMalloc(); } #endif /* ** Initialize an array of N Mem element. */ static void initMemArray(Mem *p, int N, sqlite3 *db, u16 flags){ |
︙ | ︙ | |||
1699 1700 1701 1702 1703 1704 1705 | ** sqlite3MemRelease() were called from here. With -O2, this jumps ** to 6.6 percent. The test case is inserting 1000 rows into a table ** with no indexes using a single prepared INSERT statement, bind() ** and reset(). Inserts are grouped into a transaction. */ testcase( p->flags & MEM_Agg ); testcase( p->flags & MEM_Dyn ); | < > | 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 | ** sqlite3MemRelease() were called from here. With -O2, this jumps ** to 6.6 percent. The test case is inserting 1000 rows into a table ** with no indexes using a single prepared INSERT statement, bind() ** and reset(). Inserts are grouped into a transaction. */ testcase( p->flags & MEM_Agg ); testcase( p->flags & MEM_Dyn ); if( p->flags&(MEM_Agg|MEM_Dyn) ){ testcase( (p->flags & MEM_Dyn)!=0 && p->xDel==sqlite3VdbeFrameMemDel ); sqlite3VdbeMemRelease(p); }else if( p->szMalloc ){ sqlite3DbFreeNN(db, p->zMalloc); p->szMalloc = 0; } p->flags = MEM_Undefined; |
︙ | ︙ | |||
1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 | */ void sqlite3VdbeFrameMemDel(void *pArg){ VdbeFrame *pFrame = (VdbeFrame*)pArg; assert( sqlite3VdbeFrameIsValid(pFrame) ); pFrame->pParent = pFrame->v->pDelFrame; pFrame->v->pDelFrame = pFrame; } /* ** Delete a VdbeFrame object and its contents. VdbeFrame objects are ** allocated by the OP_Program opcode in sqlite3VdbeExec(). */ void sqlite3VdbeFrameDelete(VdbeFrame *p){ | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 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 | */ void sqlite3VdbeFrameMemDel(void *pArg){ VdbeFrame *pFrame = (VdbeFrame*)pArg; assert( sqlite3VdbeFrameIsValid(pFrame) ); pFrame->pParent = pFrame->v->pDelFrame; pFrame->v->pDelFrame = pFrame; } #if defined(SQLITE_ENABLE_BYTECODE_VTAB) || !defined(SQLITE_OMIT_EXPLAIN) /* ** Locate the next opcode to be displayed in EXPLAIN or EXPLAIN ** QUERY PLAN output. ** ** Return SQLITE_ROW on success. Return SQLITE_DONE if there are no ** more opcodes to be displayed. */ int sqlite3VdbeNextOpcode( Vdbe *p, /* The statement being explained */ Mem *pSub, /* Storage for keeping track of subprogram nesting */ int eMode, /* 0: normal. 1: EQP. 2: TablesUsed */ int *piPc, /* IN/OUT: Current rowid. Overwritten with next rowid */ int *piAddr, /* OUT: Write index into (*paOp)[] here */ Op **paOp /* OUT: Write the opcode array here */ ){ int nRow; /* Stop when row count reaches this */ int nSub = 0; /* Number of sub-vdbes seen so far */ SubProgram **apSub = 0; /* Array of sub-vdbes */ int i; /* Next instruction address */ int rc = SQLITE_OK; /* Result code */ Op *aOp = 0; /* Opcode array */ int iPc; /* Rowid. Copy of value in *piPc */ /* When the number of output rows reaches nRow, that means the ** listing has finished and sqlite3_step() should return SQLITE_DONE. ** nRow is the sum of the number of rows in the main program, plus ** the sum of the number of rows in all trigger subprograms encountered ** so far. The nRow value will increase as new trigger subprograms are ** encountered, but p->pc will eventually catch up to nRow. */ nRow = p->nOp; if( pSub!=0 ){ if( pSub->flags&MEM_Blob ){ /* pSub is initiallly NULL. It is initialized to a BLOB by ** the P4_SUBPROGRAM processing logic below */ nSub = pSub->n/sizeof(Vdbe*); apSub = (SubProgram **)pSub->z; } for(i=0; i<nSub; i++){ nRow += apSub[i]->nOp; } } iPc = *piPc; while(1){ /* Loop exits via break */ i = iPc++; if( i>=nRow ){ p->rc = SQLITE_OK; rc = SQLITE_DONE; break; } if( i<p->nOp ){ /* The rowid is small enough that we are still in the ** main program. */ aOp = p->aOp; }else{ /* We are currently listing subprograms. Figure out which one and ** pick up the appropriate opcode. */ int j; i -= p->nOp; assert( apSub!=0 ); assert( nSub>0 ); for(j=0; i>=apSub[j]->nOp; j++){ i -= apSub[j]->nOp; assert( i<apSub[j]->nOp || j+1<nSub ); } aOp = apSub[j]->aOp; } /* When an OP_Program opcode is encounter (the only opcode that has ** a P4_SUBPROGRAM argument), expand the size of the array of subprograms ** kept in p->aMem[9].z to hold the new program - assuming this subprogram ** has not already been seen. */ if( pSub!=0 && aOp[i].p4type==P4_SUBPROGRAM ){ int nByte = (nSub+1)*sizeof(SubProgram*); int j; for(j=0; j<nSub; j++){ if( apSub[j]==aOp[i].p4.pProgram ) break; } if( j==nSub ){ p->rc = sqlite3VdbeMemGrow(pSub, nByte, nSub!=0); if( p->rc!=SQLITE_OK ){ rc = SQLITE_ERROR; break; } apSub = (SubProgram **)pSub->z; apSub[nSub++] = aOp[i].p4.pProgram; MemSetTypeFlag(pSub, MEM_Blob); pSub->n = nSub*sizeof(SubProgram*); nRow += aOp[i].p4.pProgram->nOp; } } if( eMode==0 ) break; #ifdef SQLITE_ENABLE_BYTECODE_VTAB if( eMode==2 ){ Op *pOp = aOp + i; if( pOp->opcode==OP_OpenRead ) break; if( pOp->opcode==OP_OpenWrite && (pOp->p5 & OPFLAG_P2ISREG)==0 ) break; if( pOp->opcode==OP_ReopenIdx ) break; }else #endif { assert( eMode==1 ); if( aOp[i].opcode==OP_Explain ) break; if( aOp[i].opcode==OP_Init && iPc>1 ) break; } } *piPc = iPc; *piAddr = i; *paOp = aOp; return rc; } #endif /* SQLITE_ENABLE_BYTECODE_VTAB || !SQLITE_OMIT_EXPLAIN */ /* ** Delete a VdbeFrame object and its contents. VdbeFrame objects are ** allocated by the OP_Program opcode in sqlite3VdbeExec(). */ void sqlite3VdbeFrameDelete(VdbeFrame *p){ |
︙ | ︙ | |||
1780 1781 1782 1783 1784 1785 1786 | ** ** When p->explain==1, first the main program is listed, then each of ** the trigger subprograms are listed one by one. */ int sqlite3VdbeList( Vdbe *p /* The VDBE */ ){ | < < < > | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < | | < | | < < < < < < < < < < < < | < < < < < < < < < < < < < < < > | | | < < < | < < < < < < < | < < < | < < < | < < < | < < < < < < < < < | | | < | | < | < < < < | | | < | < | < | < < < < > < | | > | > > > > | | > | 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 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 | ** ** When p->explain==1, first the main program is listed, then each of ** the trigger subprograms are listed one by one. */ int sqlite3VdbeList( Vdbe *p /* The VDBE */ ){ Mem *pSub = 0; /* Memory cell hold array of subprogs */ sqlite3 *db = p->db; /* The database connection */ int i; /* Loop counter */ int rc = SQLITE_OK; /* Return code */ Mem *pMem = &p->aMem[1]; /* First Mem of result set */ int bListSubprogs = (p->explain==1 || (db->flags & SQLITE_TriggerEQP)!=0); Op *aOp; /* Array of opcodes */ Op *pOp; /* Current opcode */ assert( p->explain ); assert( p->iVdbeMagic==VDBE_MAGIC_RUN ); assert( p->rc==SQLITE_OK || p->rc==SQLITE_BUSY || p->rc==SQLITE_NOMEM ); /* Even though this opcode does not use dynamic strings for ** the result, result columns may become dynamic if the user calls ** sqlite3_column_text16(), causing a translation to UTF-16 encoding. */ releaseMemArray(pMem, 8); p->pResultSet = 0; if( p->rc==SQLITE_NOMEM ){ /* This happens if a malloc() inside a call to sqlite3_column_text() or ** sqlite3_column_text16() failed. */ sqlite3OomFault(db); return SQLITE_ERROR; } if( bListSubprogs ){ /* The first 8 memory cells are used for the result set. So we will ** commandeer the 9th cell to use as storage for an array of pointers ** to trigger subprograms. The VDBE is guaranteed to have at least 9 ** cells. */ assert( p->nMem>9 ); pSub = &p->aMem[9]; }else{ pSub = 0; } /* Figure out which opcode is next to display */ rc = sqlite3VdbeNextOpcode(p, pSub, p->explain==2, &p->pc, &i, &aOp); if( rc==SQLITE_OK ){ pOp = aOp + i; if( AtomicLoad(&db->u1.isInterrupted) ){ p->rc = SQLITE_INTERRUPT; rc = SQLITE_ERROR; sqlite3VdbeError(p, sqlite3ErrStr(p->rc)); }else{ char *zP4 = sqlite3VdbeDisplayP4(db, pOp); if( p->explain==2 ){ sqlite3VdbeMemSetInt64(pMem, pOp->p1); sqlite3VdbeMemSetInt64(pMem+1, pOp->p2); sqlite3VdbeMemSetInt64(pMem+2, pOp->p3); sqlite3VdbeMemSetStr(pMem+3, zP4, -1, SQLITE_UTF8, sqlite3_free); p->nResColumn = 4; }else{ sqlite3VdbeMemSetInt64(pMem+0, i); sqlite3VdbeMemSetStr(pMem+1, (char*)sqlite3OpcodeName(pOp->opcode), -1, SQLITE_UTF8, SQLITE_STATIC); sqlite3VdbeMemSetInt64(pMem+2, pOp->p1); sqlite3VdbeMemSetInt64(pMem+3, pOp->p2); sqlite3VdbeMemSetInt64(pMem+4, pOp->p3); /* pMem+5 for p4 is done last */ sqlite3VdbeMemSetInt64(pMem+6, pOp->p5); #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS { char *zCom = sqlite3VdbeDisplayComment(db, pOp, zP4); sqlite3VdbeMemSetStr(pMem+7, zCom, -1, SQLITE_UTF8, sqlite3_free); } #else sqlite3VdbeMemSetNull(pMem+7); #endif sqlite3VdbeMemSetStr(pMem+5, zP4, -1, SQLITE_UTF8, sqlite3_free); p->nResColumn = 8; } p->pResultSet = pMem; if( db->mallocFailed ){ p->rc = SQLITE_NOMEM; rc = SQLITE_ERROR; }else{ p->rc = SQLITE_OK; rc = SQLITE_ROW; } } } return rc; } #endif /* SQLITE_OMIT_EXPLAIN */ #ifdef SQLITE_DEBUG |
︙ | ︙ | |||
2022 2023 2024 2025 2026 2027 2028 | #endif /* !SQLITE_OMIT_TRACE && SQLITE_ENABLE_IOTRACE */ /* An instance of this object describes bulk memory available for use ** by subcomponents of a prepared statement. Space is allocated out ** of a ReusableSpace object by the allocSpace() routine below. */ struct ReusableSpace { | | | | | | 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 | #endif /* !SQLITE_OMIT_TRACE && SQLITE_ENABLE_IOTRACE */ /* An instance of this object describes bulk memory available for use ** by subcomponents of a prepared statement. Space is allocated out ** of a ReusableSpace object by the allocSpace() routine below. */ struct ReusableSpace { u8 *pSpace; /* Available memory */ sqlite3_int64 nFree; /* Bytes of available memory */ sqlite3_int64 nNeeded; /* Total bytes that could not be allocated */ }; /* Try to allocate nByte bytes of 8-byte aligned bulk memory for pBuf ** from the ReusableSpace object. Return a pointer to the allocated ** memory on success. If insufficient memory is available in the ** ReusableSpace object, increase the ReusableSpace.nNeeded ** value by the amount needed and return NULL. ** ** If pBuf is not initially NULL, that means that the memory has already ** been allocated by a prior call to this routine, so just return a copy ** of pBuf and leave ReusableSpace unchanged. ** ** This allocator is employed to repurpose unused slots at the end of the ** opcode array of prepared state for other memory needs of the prepared ** statement. */ static void *allocSpace( struct ReusableSpace *p, /* Bulk memory available for allocation */ void *pBuf, /* Pointer to a prior allocation */ sqlite3_int64 nByte /* Bytes of memory needed */ ){ assert( EIGHT_BYTE_ALIGNMENT(p->pSpace) ); if( pBuf==0 ){ nByte = ROUND8(nByte); if( nByte <= p->nFree ){ p->nFree -= nByte; pBuf = &p->pSpace[p->nFree]; |
︙ | ︙ | |||
2069 2070 2071 2072 2073 2074 2075 | ** running it. */ void sqlite3VdbeRewind(Vdbe *p){ #if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE) int i; #endif assert( p!=0 ); | | | | 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 | ** running it. */ void sqlite3VdbeRewind(Vdbe *p){ #if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE) int i; #endif assert( p!=0 ); assert( p->iVdbeMagic==VDBE_MAGIC_INIT || p->iVdbeMagic==VDBE_MAGIC_RESET ); /* There should be at least one opcode. */ assert( p->nOp>0 ); /* Set the magic to VDBE_MAGIC_RUN sooner rather than later. */ p->iVdbeMagic = VDBE_MAGIC_RUN; #ifdef SQLITE_DEBUG for(i=0; i<p->nMem; i++){ assert( p->aMem[i].db==p->db ); } #endif p->pc = -1; |
︙ | ︙ | |||
2132 2133 2134 2135 2136 2137 2138 | int nArg; /* Number of arguments in subprograms */ int n; /* Loop counter */ struct ReusableSpace x; /* Reusable bulk memory */ assert( p!=0 ); assert( p->nOp>0 ); assert( pParse!=0 ); | | > > | 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 | int nArg; /* Number of arguments in subprograms */ int n; /* Loop counter */ struct ReusableSpace x; /* Reusable bulk memory */ assert( p!=0 ); assert( p->nOp>0 ); assert( pParse!=0 ); assert( p->iVdbeMagic==VDBE_MAGIC_INIT ); assert( pParse==p->pParse ); p->pVList = pParse->pVList; pParse->pVList = 0; db = p->db; assert( db->mallocFailed==0 ); nVar = pParse->nVar; nMem = pParse->nMem; nCursor = pParse->nTab; nArg = pParse->nMaxArg; |
︙ | ︙ | |||
2162 2163 2164 2165 2166 2167 2168 | assert( EIGHT_BYTE_ALIGNMENT(x.pSpace) ); x.nFree = ROUNDDOWN8(pParse->szOpAlloc - n); /* Bytes of unused memory */ assert( x.nFree>=0 ); assert( EIGHT_BYTE_ALIGNMENT(&x.pSpace[x.nFree]) ); resolveP2Values(p, &nArg); p->usesStmtJournal = (u8)(pParse->isMultiWrite && pParse->mayAbort); | | > > > > > | > > > > > > > > > > > > > > < | | | | | | | | > > > > > > > | > | < < | 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 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 | assert( EIGHT_BYTE_ALIGNMENT(x.pSpace) ); x.nFree = ROUNDDOWN8(pParse->szOpAlloc - n); /* Bytes of unused memory */ assert( x.nFree>=0 ); assert( EIGHT_BYTE_ALIGNMENT(&x.pSpace[x.nFree]) ); resolveP2Values(p, &nArg); p->usesStmtJournal = (u8)(pParse->isMultiWrite && pParse->mayAbort); if( pParse->explain ){ static const char * const azColName[] = { "addr", "opcode", "p1", "p2", "p3", "p4", "p5", "comment", "id", "parent", "notused", "detail" }; int iFirst, mx, i; if( nMem<10 ) nMem = 10; p->explain = pParse->explain; if( pParse->explain==2 ){ sqlite3VdbeSetNumCols(p, 4); iFirst = 8; mx = 12; }else{ sqlite3VdbeSetNumCols(p, 8); iFirst = 0; mx = 8; } for(i=iFirst; i<mx; i++){ sqlite3VdbeSetColName(p, i-iFirst, COLNAME_NAME, azColName[i], SQLITE_STATIC); } } p->expired = 0; /* Memory for registers, parameters, cursor, etc, is allocated in one or two ** passes. On the first pass, we try to reuse unused memory at the ** end of the opcode array. If we are unable to satisfy all memory ** requirements by reusing the opcode array tail, then the second ** pass will fill in the remainder using a fresh memory allocation. ** ** This two-pass approach that reuses as much memory as possible from ** the leftover memory at the end of the opcode array. This can significantly ** reduce the amount of memory held by a prepared statement. */ x.nNeeded = 0; p->aMem = allocSpace(&x, 0, nMem*sizeof(Mem)); p->aVar = allocSpace(&x, 0, nVar*sizeof(Mem)); p->apArg = allocSpace(&x, 0, nArg*sizeof(Mem*)); p->apCsr = allocSpace(&x, 0, nCursor*sizeof(VdbeCursor*)); #ifdef SQLITE_ENABLE_STMT_SCANSTATUS p->anExec = allocSpace(&x, 0, p->nOp*sizeof(i64)); #endif if( x.nNeeded ){ x.pSpace = p->pFree = sqlite3DbMallocRawNN(db, x.nNeeded); x.nFree = x.nNeeded; if( !db->mallocFailed ){ p->aMem = allocSpace(&x, p->aMem, nMem*sizeof(Mem)); p->aVar = allocSpace(&x, p->aVar, nVar*sizeof(Mem)); p->apArg = allocSpace(&x, p->apArg, nArg*sizeof(Mem*)); p->apCsr = allocSpace(&x, p->apCsr, nCursor*sizeof(VdbeCursor*)); #ifdef SQLITE_ENABLE_STMT_SCANSTATUS p->anExec = allocSpace(&x, p->anExec, p->nOp*sizeof(i64)); #endif } } if( db->mallocFailed ){ p->nVar = 0; p->nCursor = 0; p->nMem = 0; }else{ p->nCursor = nCursor; p->nVar = (ynVar)nVar; |
︙ | ︙ | |||
2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 | ** happens to hold. */ void sqlite3VdbeFreeCursor(Vdbe *p, VdbeCursor *pCx){ if( pCx==0 ){ return; } assert( pCx->pBtx==0 || pCx->eCurType==CURTYPE_BTREE ); switch( pCx->eCurType ){ case CURTYPE_SORTER: { sqlite3VdbeSorterClose(p->db, pCx); break; } case CURTYPE_BTREE: { | > < < < < < | | < | 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 | ** happens to hold. */ void sqlite3VdbeFreeCursor(Vdbe *p, VdbeCursor *pCx){ if( pCx==0 ){ return; } assert( pCx->pBtx==0 || pCx->eCurType==CURTYPE_BTREE ); assert( pCx->pBtx==0 || pCx->isEphemeral ); switch( pCx->eCurType ){ case CURTYPE_SORTER: { sqlite3VdbeSorterClose(p->db, pCx); break; } case CURTYPE_BTREE: { assert( pCx->uc.pCursor!=0 ); sqlite3BtreeCloseCursor(pCx->uc.pCursor); break; } #ifndef SQLITE_OMIT_VIRTUALTABLE case CURTYPE_VTAB: { sqlite3_vtab_cursor *pVCur = pCx->uc.pVCur; const sqlite3_module *pModule = pVCur->pVtab->pModule; assert( pVCur->pVtab->nRef>0 ); |
︙ | ︙ | |||
2381 2382 2383 2384 2385 2386 2387 | return rc; } /* ** A read or write transaction may or may not be active on database handle ** db. If a transaction is active, commit it. If there is a ** write-transaction spanning more than one database file, this routine | | | | | | | | | 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 | return rc; } /* ** A read or write transaction may or may not be active on database handle ** db. If a transaction is active, commit it. If there is a ** write-transaction spanning more than one database file, this routine ** takes care of the super-journal trickery. */ static int vdbeCommit(sqlite3 *db, Vdbe *p){ int i; int nTrans = 0; /* Number of databases with an active write-transaction ** that are candidates for a two-phase commit using a ** super-journal */ int rc = SQLITE_OK; int needXcommit = 0; #ifdef SQLITE_OMIT_VIRTUALTABLE /* With this option, sqlite3VtabSync() is defined to be simply ** SQLITE_OK so p is not used. */ UNUSED_PARAMETER(p); #endif /* Before doing anything else, call the xSync() callback for any ** virtual module tables written in this transaction. This has to ** be done before determining whether a super-journal file is ** required, as an xSync() callback may add an attached database ** to the transaction. */ rc = sqlite3VtabSync(db, p); /* This loop determines (a) if the commit hook should be invoked and ** (b) how many database files have open write transactions, not ** including the temp database. (b) is important because if more than ** one database file has an open write transaction, a super-journal ** file is required for an atomic commit. */ for(i=0; rc==SQLITE_OK && i<db->nDb; i++){ Btree *pBt = db->aDb[i].pBt; if( sqlite3BtreeTxnState(pBt)==SQLITE_TXN_WRITE ){ /* Whether or not a database might need a super-journal depends upon ** its journal mode (among other things). This matrix determines which ** journal modes use a super-journal and which do not */ static const u8 aMJNeeded[] = { /* DELETE */ 1, /* PERSIST */ 1, /* OFF */ 0, /* TRUNCATE */ 1, /* MEMORY */ 0, /* WAL */ 0 |
︙ | ︙ | |||
2443 2444 2445 2446 2447 2448 2449 | } rc = sqlite3BtreeExclusiveLock(pBt); sqlite3BtreeLeave(pBt); } } #ifndef SQLITE_OMIT_CONCURRENT | | | | 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 | } rc = sqlite3BtreeExclusiveLock(pBt); sqlite3BtreeLeave(pBt); } } #ifndef SQLITE_OMIT_CONCURRENT if( db->eConcurrent && (rc & 0xFF)==SQLITE_BUSY ){ /* An SQLITE_BUSY or SQLITE_BUSY_SNAPSHOT was encountered while ** attempting to take the WRITER lock on a wal file. Release the ** WRITER locks on all wal files and return early. */ for(i=0; i<db->nDb; i++){ Btree *pBt = db->aDb[i].pBt; if( sqlite3BtreeTxnState(pBt)==SQLITE_TXN_WRITE ){ sqlite3BtreeEnter(pBt); sqlite3PagerDropExclusiveLock(sqlite3BtreePager(pBt)); sqlite3BtreeLeave(pBt); } } } #endif |
︙ | ︙ | |||
2472 2473 2474 2475 2476 2477 2478 | if( rc ){ return SQLITE_CONSTRAINT_COMMITHOOK; } } /* The simple case - no more than one database file (not counting the ** TEMP database) has a transaction active. There is no need for the | | | 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 | if( rc ){ return SQLITE_CONSTRAINT_COMMITHOOK; } } /* The simple case - no more than one database file (not counting the ** TEMP database) has a transaction active. There is no need for the ** super-journal. ** ** If the return value of sqlite3BtreeGetFilename() is a zero length ** string, it means the main database is :memory: or a temp file. In ** that case we do not support atomic multi-file commits, so use the ** simple case then too. */ if( 0==sqlite3Strlen30(sqlite3BtreeGetFilename(db->aDb[0].pBt)) |
︙ | ︙ | |||
2506 2507 2508 2509 2510 2511 2512 | } if( rc==SQLITE_OK ){ sqlite3VtabCommit(db); } } /* The complex case - There is a multi-file write-transaction active. | | | | | | | > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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 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 | } if( rc==SQLITE_OK ){ sqlite3VtabCommit(db); } } /* The complex case - There is a multi-file write-transaction active. ** This requires a super-journal file to ensure the transaction is ** committed atomically. */ #ifndef SQLITE_OMIT_DISKIO else{ sqlite3_vfs *pVfs = db->pVfs; char *zSuper = 0; /* File-name for the super-journal */ char const *zMainFile = sqlite3BtreeGetFilename(db->aDb[0].pBt); sqlite3_file *pSuperJrnl = 0; i64 offset = 0; int res; int retryCount = 0; int nMainFile; /* Select a super-journal file name */ nMainFile = sqlite3Strlen30(zMainFile); zSuper = sqlite3MPrintf(db, "%.4c%s%.16c", 0,zMainFile,0); if( zSuper==0 ) return SQLITE_NOMEM_BKPT; zSuper += 4; do { u32 iRandom; if( retryCount ){ if( retryCount>100 ){ sqlite3_log(SQLITE_FULL, "MJ delete: %s", zSuper); sqlite3OsDelete(pVfs, zSuper, 0); break; }else if( retryCount==1 ){ sqlite3_log(SQLITE_FULL, "MJ collide: %s", zSuper); } } retryCount++; sqlite3_randomness(sizeof(iRandom), &iRandom); sqlite3_snprintf(13, &zSuper[nMainFile], "-mj%06X9%02X", (iRandom>>8)&0xffffff, iRandom&0xff); /* The antipenultimate character of the super-journal name must ** be "9" to avoid name collisions when using 8+3 filenames. */ assert( zSuper[sqlite3Strlen30(zSuper)-3]=='9' ); sqlite3FileSuffix3(zMainFile, zSuper); rc = sqlite3OsAccess(pVfs, zSuper, SQLITE_ACCESS_EXISTS, &res); }while( rc==SQLITE_OK && res ); if( rc==SQLITE_OK ){ /* Open the super-journal. */ rc = sqlite3OsOpenMalloc(pVfs, zSuper, &pSuperJrnl, SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE| SQLITE_OPEN_EXCLUSIVE|SQLITE_OPEN_SUPER_JOURNAL, 0 ); } if( rc!=SQLITE_OK ){ sqlite3DbFree(db, zSuper-4); return rc; } /* Write the name of each database file in the transaction into the new ** super-journal file. If an error occurs at this point close ** and delete the super-journal file. All the individual journal files ** still have 'null' as the super-journal pointer, so they will roll ** back independently if a failure occurs. */ for(i=0; i<db->nDb; i++){ Btree *pBt = db->aDb[i].pBt; if( sqlite3BtreeTxnState(pBt)==SQLITE_TXN_WRITE ){ char const *zFile = sqlite3BtreeGetJournalname(pBt); if( zFile==0 ){ continue; /* Ignore TEMP and :memory: databases */ } assert( zFile[0]!=0 ); rc = sqlite3OsWrite(pSuperJrnl, zFile, sqlite3Strlen30(zFile)+1,offset); offset += sqlite3Strlen30(zFile)+1; if( rc!=SQLITE_OK ){ sqlite3OsCloseFree(pSuperJrnl); sqlite3OsDelete(pVfs, zSuper, 0); sqlite3DbFree(db, zSuper-4); return rc; } } } /* Sync the super-journal file. If the IOCAP_SEQUENTIAL device ** flag is set this is not required. */ if( 0==(sqlite3OsDeviceCharacteristics(pSuperJrnl)&SQLITE_IOCAP_SEQUENTIAL) && SQLITE_OK!=(rc = sqlite3OsSync(pSuperJrnl, SQLITE_SYNC_NORMAL)) ){ sqlite3OsCloseFree(pSuperJrnl); sqlite3OsDelete(pVfs, zSuper, 0); sqlite3DbFree(db, zSuper-4); return rc; } /* Sync all the db files involved in the transaction. The same call ** sets the super-journal pointer in each individual journal. If ** an error occurs here, do not delete the super-journal file. ** ** If the error occurs during the first call to ** sqlite3BtreeCommitPhaseOne(), then there is a chance that the ** super-journal file will be orphaned. But we cannot delete it, ** in case the super-journal file name was written into the journal ** file before the failure occurred. */ for(i=0; rc==SQLITE_OK && i<db->nDb; i++){ Btree *pBt = db->aDb[i].pBt; if( pBt ){ rc = sqlite3BtreeCommitPhaseOne(pBt, zSuper); } } sqlite3OsCloseFree(pSuperJrnl); assert( rc!=SQLITE_BUSY ); if( rc!=SQLITE_OK ){ sqlite3DbFree(db, zSuper-4); return rc; } /* Delete the super-journal file. This commits the transaction. After ** doing this the directory is synced again before any individual ** transaction files are deleted. */ rc = sqlite3OsDelete(pVfs, zSuper, 1); sqlite3DbFree(db, zSuper-4); zSuper = 0; if( rc ){ return rc; } /* All files and directories have already been synced, so the following ** calls to sqlite3BtreeCommitPhaseTwo() are only closing files and ** deleting or truncating journals. If something goes wrong while |
︙ | ︙ | |||
2779 2780 2781 2782 2783 2784 2785 | #endif /* ** This routine is called the when a VDBE tries to halt. If the VDBE ** has made changes and is in autocommit mode, then commit those ** changes. If a rollback is needed, then do the rollback. ** | | | | | 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 | #endif /* ** This routine is called the when a VDBE tries to halt. If the VDBE ** has made changes and is in autocommit mode, then commit those ** changes. If a rollback is needed, then do the rollback. ** ** This routine is the only way to move the sqlite3eOpenState of a VM from ** SQLITE_STATE_RUN to SQLITE_STATE_HALT. It is harmless to ** call this on a VM that is in the SQLITE_STATE_HALT state. ** ** Return an error code. If the commit could not complete because of ** lock contention, return SQLITE_BUSY. If SQLITE_BUSY is returned, it ** means the close did not happen and needs to be repeated. */ int sqlite3VdbeHalt(Vdbe *p){ int rc; /* Used to store transient return codes */ |
︙ | ︙ | |||
2807 2808 2809 2810 2811 2812 2813 | ** SQLITE_INTERRUPT ** ** Then the internal cache might have been left in an inconsistent ** state. We need to rollback the statement transaction, if there is ** one, or the complete transaction if there is no statement transaction. */ | | > | | > | > > > > | 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 | ** SQLITE_INTERRUPT ** ** Then the internal cache might have been left in an inconsistent ** state. We need to rollback the statement transaction, if there is ** one, or the complete transaction if there is no statement transaction. */ if( p->iVdbeMagic!=VDBE_MAGIC_RUN ){ return SQLITE_OK; } if( db->mallocFailed ){ p->rc = SQLITE_NOMEM_BKPT; } closeAllCursors(p); checkActiveVdbeCnt(db); /* No commit or rollback needed if the program never started or if the ** SQL statement does not read or write a database file. */ if( p->pc>=0 && p->bIsReader ){ int mrc; /* Primary error code from p->rc */ int eStatementOp = 0; int isSpecialError; /* Set to true if a 'special' error */ /* Lock all btrees used by the statement */ sqlite3VdbeEnter(p); /* Check for one of the special errors */ if( p->rc ){ mrc = p->rc & 0xff; isSpecialError = mrc==SQLITE_NOMEM || mrc==SQLITE_IOERR || mrc==SQLITE_INTERRUPT || mrc==SQLITE_FULL; }else{ mrc = isSpecialError = 0; } if( isSpecialError ){ /* 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 |
︙ | ︙ | |||
2853 2854 2855 2856 2857 2858 2859 | }else{ /* We are forced to roll back the active transaction. Before doing ** so, abort any other statements this handle currently has active. */ sqlite3RollbackAll(db, SQLITE_ABORT_ROLLBACK); sqlite3CloseSavepoints(db); db->autoCommit = 1; | | | | 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 | }else{ /* We are forced to roll back the active transaction. Before doing ** so, abort any other statements this handle currently has active. */ sqlite3RollbackAll(db, SQLITE_ABORT_ROLLBACK); sqlite3CloseSavepoints(db); db->autoCommit = 1; db->eConcurrent = CONCURRENT_NONE; p->nChange = 0; } } } /* Check for immediate foreign key violations. */ if( p->rc==SQLITE_OK || (p->errorAction==OE_Fail && !isSpecialError) ){ sqlite3VdbeCheckFk(p, 0); } /* If the auto-commit flag is set and this is the only active writer ** VM, then we do either a commit or rollback of the current transaction. ** ** Note: This block also runs if one of the special errors handled |
︙ | ︙ | |||
2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 | rc = sqlite3VdbeCheckFk(p, 1); if( rc!=SQLITE_OK ){ if( NEVER(p->readOnly) ){ sqlite3VdbeLeave(p); return SQLITE_ERROR; } rc = SQLITE_CONSTRAINT_FOREIGNKEY; }else{ /* The auto-commit flag is true, the vdbe program was successful ** or hit an 'OR FAIL' constraint and there are no deferred foreign ** key constraints to hold up the transaction. This means a commit ** is required. */ rc = vdbeCommit(db, p); } | > > > | 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 | rc = sqlite3VdbeCheckFk(p, 1); if( rc!=SQLITE_OK ){ if( NEVER(p->readOnly) ){ sqlite3VdbeLeave(p); return SQLITE_ERROR; } rc = SQLITE_CONSTRAINT_FOREIGNKEY; }else if( db->flags & SQLITE_CorruptRdOnly ){ rc = SQLITE_CORRUPT; db->flags &= ~SQLITE_CorruptRdOnly; }else{ /* The auto-commit flag is true, the vdbe program was successful ** or hit an 'OR FAIL' constraint and there are no deferred foreign ** key constraints to hold up the transaction. This means a commit ** is required. */ rc = vdbeCommit(db, p); } |
︙ | ︙ | |||
2916 2917 2918 2919 2920 2921 2922 | eStatementOp = SAVEPOINT_RELEASE; }else if( p->errorAction==OE_Abort ){ eStatementOp = SAVEPOINT_ROLLBACK; }else{ sqlite3RollbackAll(db, SQLITE_ABORT_ROLLBACK); sqlite3CloseSavepoints(db); db->autoCommit = 1; | | | 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 | eStatementOp = SAVEPOINT_RELEASE; }else if( p->errorAction==OE_Abort ){ eStatementOp = SAVEPOINT_ROLLBACK; }else{ sqlite3RollbackAll(db, SQLITE_ABORT_ROLLBACK); sqlite3CloseSavepoints(db); db->autoCommit = 1; db->eConcurrent = CONCURRENT_NONE; p->nChange = 0; } } /* If eStatementOp is non-zero, then a statement transaction needs to ** be committed or rolled back. Call sqlite3VdbeCloseStatement() to ** do so. If this operation returns an error, and the current statement |
︙ | ︙ | |||
2938 2939 2940 2941 2942 2943 2944 | p->rc = rc; sqlite3DbFree(db, p->zErrMsg); p->zErrMsg = 0; } sqlite3RollbackAll(db, SQLITE_ABORT_ROLLBACK); sqlite3CloseSavepoints(db); db->autoCommit = 1; | | | 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202 3203 | p->rc = rc; sqlite3DbFree(db, p->zErrMsg); p->zErrMsg = 0; } sqlite3RollbackAll(db, SQLITE_ABORT_ROLLBACK); sqlite3CloseSavepoints(db); db->autoCommit = 1; db->eConcurrent = CONCURRENT_NONE; p->nChange = 0; } } /* If this was an INSERT, UPDATE or DELETE and no statement transaction ** has been rolled back, update the database connection change-counter. */ |
︙ | ︙ | |||
2968 2969 2970 2971 2972 2973 2974 | db->nVdbeActive--; if( !p->readOnly ) db->nVdbeWrite--; if( p->bIsReader ) db->nVdbeRead--; assert( db->nVdbeActive>=db->nVdbeRead ); assert( db->nVdbeRead>=db->nVdbeWrite ); assert( db->nVdbeWrite>=0 ); } | | | 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 | db->nVdbeActive--; if( !p->readOnly ) db->nVdbeWrite--; if( p->bIsReader ) db->nVdbeRead--; assert( db->nVdbeActive>=db->nVdbeRead ); assert( db->nVdbeRead>=db->nVdbeWrite ); assert( db->nVdbeWrite>=0 ); } p->iVdbeMagic = VDBE_MAGIC_HALT; checkActiveVdbeCnt(db); if( db->mallocFailed ){ p->rc = SQLITE_NOMEM_BKPT; } /* If the auto-commit flag is set to true, then any locks that were held ** by connection db have now been released. Call sqlite3ConnectionUnlocked() |
︙ | ︙ | |||
3073 3074 3075 3076 3077 3078 3079 | /* If the VDBE has been run even partially, then transfer the error code ** and error message from the VDBE into the main database structure. But ** if the VDBE has just been set to run but has not actually executed any ** instructions yet, leave the main database error information unchanged. */ if( p->pc>=0 ){ vdbeInvokeSqllog(p); | > | > > > > | | > | 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 | /* If the VDBE has been run even partially, then transfer the error code ** and error message from the VDBE into the main database structure. But ** if the VDBE has just been set to run but has not actually executed any ** instructions yet, leave the main database error information unchanged. */ if( p->pc>=0 ){ vdbeInvokeSqllog(p); if( db->pErr || p->zErrMsg ){ sqlite3VdbeTransferError(p); }else{ db->errCode = p->rc; } if( p->runOnlyOnce ) p->expired = 1; }else if( p->rc && p->expired ){ /* The expired flag was set on the VDBE before the first call ** to sqlite3_step(). For consistency (since sqlite3_step() was ** called), set the database error in this case as well. */ sqlite3ErrorWithMsg(db, p->rc, p->zErrMsg ? "%s" : 0, p->zErrMsg); } /* Reset register contents and reclaim error message memory. */ #ifdef SQLITE_DEBUG /* Execute assert() statements to ensure that the Vdbe.apCsr[] and ** Vdbe.aMem[] arrays have already been cleaned up. */ if( p->apCsr ) for(i=0; i<p->nCursor; i++) assert( p->apCsr[i]==0 ); if( p->aMem ){ for(i=0; i<p->nMem; i++) assert( p->aMem[i].flags==MEM_Undefined ); } #endif if( p->zErrMsg ){ sqlite3DbFree(db, p->zErrMsg); p->zErrMsg = 0; } p->pResultSet = 0; #ifdef SQLITE_DEBUG p->nWrite = 0; #endif /* Save profiling information from this VDBE run. */ |
︙ | ︙ | |||
3135 3136 3137 3138 3139 3140 3141 | fprintf(out, "%s", zHdr); sqlite3VdbePrintOp(out, i, &p->aOp[i]); } fclose(out); } } #endif | | | | 3392 3393 3394 3395 3396 3397 3398 3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 | fprintf(out, "%s", zHdr); sqlite3VdbePrintOp(out, i, &p->aOp[i]); } fclose(out); } } #endif p->iVdbeMagic = VDBE_MAGIC_RESET; return p->rc & db->errMask; } /* ** Clean up and delete a VDBE after execution. Return an integer which is ** the result code. Write any error message text into *pzErrMsg. */ int sqlite3VdbeFinalize(Vdbe *p){ int rc = SQLITE_OK; if( p->iVdbeMagic==VDBE_MAGIC_RUN || p->iVdbeMagic==VDBE_MAGIC_HALT ){ rc = sqlite3VdbeReset(p); assert( (rc & p->db->errMask)==rc ); } sqlite3VdbeDelete(p); return rc; } |
︙ | ︙ | |||
3206 3207 3208 3209 3210 3211 3212 | assert( p->db==0 || p->db==db ); releaseMemArray(p->aColName, p->nResColumn*COLNAME_N); for(pSub=p->pProgram; pSub; pSub=pNext){ pNext = pSub->pNext; vdbeFreeOpArray(db, pSub->aOp, pSub->nOp); sqlite3DbFree(db, pSub); } | | | 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 | assert( p->db==0 || p->db==db ); releaseMemArray(p->aColName, p->nResColumn*COLNAME_N); for(pSub=p->pProgram; pSub; pSub=pNext){ pNext = pSub->pNext; vdbeFreeOpArray(db, pSub->aOp, pSub->nOp); sqlite3DbFree(db, pSub); } if( p->iVdbeMagic!=VDBE_MAGIC_INIT ){ releaseMemArray(p->aVar, p->nVar); sqlite3DbFree(db, p->pVList); sqlite3DbFree(db, p->pFree); } vdbeFreeOpArray(db, p->aOp, p->nOp); sqlite3DbFree(db, p->aColName); sqlite3DbFree(db, p->zSql); |
︙ | ︙ | |||
3254 3255 3256 3257 3258 3259 3260 | }else{ assert( db->pVdbe==p ); db->pVdbe = p->pNext; } if( p->pNext ){ p->pNext->pPrev = p->pPrev; } | | | | | 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 | }else{ assert( db->pVdbe==p ); db->pVdbe = p->pNext; } if( p->pNext ){ p->pNext->pPrev = p->pPrev; } p->iVdbeMagic = VDBE_MAGIC_DEAD; p->db = 0; sqlite3DbFreeNN(db, p); } /* ** The cursor "p" has a pending seek operation that has not yet been ** carried out. Seek the cursor now. If an error occurs, return ** the appropriate error code. */ int SQLITE_NOINLINE sqlite3VdbeFinishMoveto(VdbeCursor *p){ int res, rc; #ifdef SQLITE_TEST extern int sqlite3_search_count; #endif assert( p->deferredMoveto ); assert( p->isTable ); assert( p->eCurType==CURTYPE_BTREE ); rc = sqlite3BtreeTableMoveto(p->uc.pCursor, p->movetoTarget, 0, &res); if( rc ) return rc; if( res!=0 ) return SQLITE_CORRUPT_BKPT; #ifdef SQLITE_TEST sqlite3_search_count++; #endif p->deferredMoveto = 0; p->cacheStatus = CACHE_STALE; |
︙ | ︙ | |||
3326 3327 3328 3329 3330 3331 3332 | ** MoveTo now. If no move is pending, check to see if the row has been ** deleted out from under the cursor and if it has, mark the row as ** a NULL row. ** ** If the cursor is already pointing to the correct row and that row has ** not been deleted out from under the cursor, then this routine is a no-op. */ | | | > | | | 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 | ** MoveTo now. If no move is pending, check to see if the row has been ** deleted out from under the cursor and if it has, mark the row as ** a NULL row. ** ** If the cursor is already pointing to the correct row and that row has ** not been deleted out from under the cursor, then this routine is a no-op. */ int sqlite3VdbeCursorMoveto(VdbeCursor **pp, u32 *piCol){ VdbeCursor *p = *pp; assert( p->eCurType==CURTYPE_BTREE || p->eCurType==CURTYPE_PSEUDO ); if( p->deferredMoveto ){ u32 iMap; assert( !p->isEphemeral ); if( p->aAltMap && (iMap = p->aAltMap[1+*piCol])>0 && !p->nullRow ){ *pp = p->pAltCursor; *piCol = iMap - 1; return SQLITE_OK; } return sqlite3VdbeFinishMoveto(p); } if( sqlite3BtreeCursorHasMoved(p->uc.pCursor) ){ return handleMovedCursor(p); } return SQLITE_OK; } |
︙ | ︙ | |||
3386 3387 3388 3389 3390 3391 3392 3393 3394 3395 3396 3397 3398 3399 3400 3401 3402 3403 3404 | ** N>=12 and even (N-12)/2 BLOB ** N>=13 and odd (N-13)/2 text ** ** The 8 and 9 types were added in 3.3.0, file format 4. Prior versions ** of SQLite will not understand those serial types. */ /* ** Return the serial-type for the value stored in pMem. */ u32 sqlite3VdbeSerialType(Mem *pMem, int file_format, u32 *pLen){ int flags = pMem->flags; u32 n; assert( pLen!=0 ); if( flags&MEM_Null ){ *pLen = 0; return 0; } | > > > > > > > > > | > > > > > > > > > > > > | 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 | ** N>=12 and even (N-12)/2 BLOB ** N>=13 and odd (N-13)/2 text ** ** The 8 and 9 types were added in 3.3.0, file format 4. Prior versions ** of SQLite will not understand those serial types. */ #if 0 /* Inlined into the OP_MakeRecord opcode */ /* ** Return the serial-type for the value stored in pMem. ** ** This routine might convert a large MEM_IntReal value into MEM_Real. ** ** 2019-07-11: The primary user of this subroutine was the OP_MakeRecord ** opcode in the byte-code engine. But by moving this routine in-line, we ** can omit some redundant tests and make that opcode a lot faster. So ** this routine is now only used by the STAT3 logic and STAT3 support has ** ended. The code is kept here for historical reference only. */ u32 sqlite3VdbeSerialType(Mem *pMem, int file_format, u32 *pLen){ int flags = pMem->flags; u32 n; assert( pLen!=0 ); if( flags&MEM_Null ){ *pLen = 0; return 0; } if( flags&(MEM_Int|MEM_IntReal) ){ /* Figure out whether to use 1, 2, 4, 6 or 8 bytes. */ # define MAX_6BYTE ((((i64)0x00008000)<<32)-1) i64 i = pMem->u.i; u64 u; testcase( flags & MEM_Int ); testcase( flags & MEM_IntReal ); if( i<0 ){ u = ~i; }else{ u = i; } if( u<=127 ){ if( (i&1)==i && file_format>=4 ){ *pLen = 0; return 8+(u32)u; }else{ *pLen = 1; return 1; } } if( u<=32767 ){ *pLen = 2; return 2; } if( u<=8388607 ){ *pLen = 3; return 3; } if( u<=2147483647 ){ *pLen = 4; return 4; } if( u<=MAX_6BYTE ){ *pLen = 6; return 5; } *pLen = 8; if( flags&MEM_IntReal ){ /* If the value is IntReal and is going to take up 8 bytes to store ** as an integer, then we might as well make it an 8-byte floating ** point value */ pMem->u.r = (double)pMem->u.i; pMem->flags &= ~MEM_IntReal; pMem->flags |= MEM_Real; return 7; } return 6; } if( flags&MEM_Real ){ *pLen = 8; return 7; } assert( pMem->db->mallocFailed || flags&(MEM_Str|MEM_Blob) ); assert( pMem->n>=0 ); n = (u32)pMem->n; if( flags & MEM_Zero ){ n += pMem->u.nZero; } *pLen = n; return ((n*2) + 12 + ((flags&MEM_Str)!=0)); } #endif /* inlined into OP_MakeRecord */ /* ** The sizes for serial types less than 128 */ static const u8 sqlite3SmallTypeSizes[] = { /* 0 1 2 3 4 5 6 7 8 9 */ /* 0 */ 0, 1, 2, 3, 4, 6, 8, 8, 0, 0, |
︙ | ︙ | |||
3595 3596 3597 3598 3599 3600 3601 | ** and store the result in pMem. Return the number of bytes read. ** ** This function is implemented as two separate routines for performance. ** The few cases that require local variables are broken out into a separate ** routine so that in most cases the overhead of moving the stack pointer ** is avoided. */ | | | 3874 3875 3876 3877 3878 3879 3880 3881 3882 3883 3884 3885 3886 3887 3888 | ** and store the result in pMem. Return the number of bytes read. ** ** This function is implemented as two separate routines for performance. ** The few cases that require local variables are broken out into a separate ** routine so that in most cases the overhead of moving the stack pointer ** is avoided. */ static u32 serialGet( const unsigned char *buf, /* Buffer to deserialize from */ u32 serial_type, /* Serial type to deserialize */ Mem *pMem /* Memory cell to write value into */ ){ u64 x = FOUR_BYTE_UINT(buf); u32 y = FOUR_BYTE_UINT(buf+4); x = (x<<32) + y; |
︙ | ︙ | |||
3627 3628 3629 3630 3631 3632 3633 | u64 t2 = t1; swapMixedEndianFloat(t2); assert( sizeof(r1)==sizeof(t2) && memcmp(&r1, &t2, sizeof(r1))==0 ); #endif assert( sizeof(x)==8 && sizeof(pMem->u.r)==8 ); swapMixedEndianFloat(x); memcpy(&pMem->u.r, &x, sizeof(x)); | | | 3906 3907 3908 3909 3910 3911 3912 3913 3914 3915 3916 3917 3918 3919 3920 | u64 t2 = t1; swapMixedEndianFloat(t2); assert( sizeof(r1)==sizeof(t2) && memcmp(&r1, &t2, sizeof(r1))==0 ); #endif assert( sizeof(x)==8 && sizeof(pMem->u.r)==8 ); swapMixedEndianFloat(x); memcpy(&pMem->u.r, &x, sizeof(x)); pMem->flags = IsNaN(x) ? MEM_Null : MEM_Real; } return 8; } u32 sqlite3VdbeSerialGet( const unsigned char *buf, /* Buffer to deserialize from */ u32 serial_type, /* Serial type to deserialize */ Mem *pMem /* Memory cell to write value into */ |
︙ | ︙ | |||
3745 3746 3747 3748 3749 3750 3751 | ){ UnpackedRecord *p; /* Unpacked record to return */ int nByte; /* Number of bytes required for *p */ nByte = ROUND8(sizeof(UnpackedRecord)) + sizeof(Mem)*(pKeyInfo->nKeyField+1); p = (UnpackedRecord *)sqlite3DbMallocRaw(pKeyInfo->db, nByte); if( !p ) return 0; p->aMem = (Mem*)&((char*)p)[ROUND8(sizeof(UnpackedRecord))]; | | | | > > > > > > > | 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 4034 4035 4036 4037 4038 4039 4040 4041 4042 4043 4044 4045 4046 4047 4048 4049 4050 4051 4052 4053 4054 4055 4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075 4076 4077 4078 4079 4080 4081 4082 4083 4084 4085 4086 | ){ UnpackedRecord *p; /* Unpacked record to return */ int nByte; /* Number of bytes required for *p */ nByte = ROUND8(sizeof(UnpackedRecord)) + sizeof(Mem)*(pKeyInfo->nKeyField+1); p = (UnpackedRecord *)sqlite3DbMallocRaw(pKeyInfo->db, nByte); if( !p ) return 0; p->aMem = (Mem*)&((char*)p)[ROUND8(sizeof(UnpackedRecord))]; assert( pKeyInfo->aSortFlags!=0 ); p->pKeyInfo = pKeyInfo; p->nField = pKeyInfo->nKeyField + 1; return p; } /* ** Given the nKey-byte encoding of a record in pKey[], populate the ** UnpackedRecord structure indicated by the fourth argument with the ** contents of the decoded record. */ void sqlite3VdbeRecordUnpack( KeyInfo *pKeyInfo, /* Information about the record format */ int nKey, /* Size of the binary record */ const void *pKey, /* The binary record */ UnpackedRecord *p /* Populate this structure before returning. */ ){ const unsigned char *aKey = (const unsigned char *)pKey; u32 d; u32 idx; /* Offset in aKey[] to read from */ u16 u; /* Unsigned loop counter */ u32 szHdr; Mem *pMem = p->aMem; p->default_rc = 0; assert( EIGHT_BYTE_ALIGNMENT(pMem) ); idx = getVarint32(aKey, szHdr); d = szHdr; u = 0; while( idx<szHdr && d<=(u32)nKey ){ u32 serial_type; idx += getVarint32(&aKey[idx], serial_type); pMem->enc = pKeyInfo->enc; pMem->db = pKeyInfo->db; /* pMem->flags = 0; // sqlite3VdbeSerialGet() will set this for us */ pMem->szMalloc = 0; pMem->z = 0; d += sqlite3VdbeSerialGet(&aKey[d], serial_type, pMem); pMem++; if( (++u)>=p->nField ) break; } if( d>(u32)nKey && u ){ assert( CORRUPT_DB ); /* In a corrupt record entry, the last pMem might have been set up using ** uninitialized memory. Overwrite its value with NULL, to prevent ** warnings from MSAN. */ sqlite3VdbeMemSetNull(pMem-1); } assert( u<=pKeyInfo->nKeyField + 1 ); p->nField = u; } #ifdef SQLITE_DEBUG /* ** This function compares two index or table record keys in the same way |
︙ | ︙ | |||
3837 3838 3839 3840 3841 3842 3843 | */ /* mem1.u.i = 0; // not needed, here to silence compiler warning */ idx1 = getVarint32(aKey1, szHdr1); if( szHdr1>98307 ) return SQLITE_CORRUPT; d1 = szHdr1; assert( pKeyInfo->nAllField>=pPKey2->nField || CORRUPT_DB ); | | | | | > > > > > > | | 4123 4124 4125 4126 4127 4128 4129 4130 4131 4132 4133 4134 4135 4136 4137 4138 4139 4140 4141 4142 4143 4144 4145 4146 4147 4148 4149 4150 4151 4152 4153 4154 4155 4156 4157 4158 4159 4160 4161 4162 4163 4164 4165 4166 4167 4168 4169 4170 4171 4172 4173 | */ /* mem1.u.i = 0; // not needed, here to silence compiler warning */ idx1 = getVarint32(aKey1, szHdr1); if( szHdr1>98307 ) return SQLITE_CORRUPT; d1 = szHdr1; assert( pKeyInfo->nAllField>=pPKey2->nField || CORRUPT_DB ); assert( pKeyInfo->aSortFlags!=0 ); assert( pKeyInfo->nKeyField>0 ); assert( idx1<=szHdr1 || CORRUPT_DB ); do{ u32 serial_type1; /* Read the serial types for the next element in each key. */ idx1 += getVarint32( aKey1+idx1, serial_type1 ); /* Verify that there is enough key space remaining to avoid ** a buffer overread. The "d1+serial_type1+2" subexpression will ** always be greater than or equal to the amount of required key space. ** Use that approximation to avoid the more expensive call to ** sqlite3VdbeSerialTypeLen() in the common case. */ if( d1+(u64)serial_type1+2>(u64)nKey1 && d1+(u64)sqlite3VdbeSerialTypeLen(serial_type1)>(u64)nKey1 ){ break; } /* Extract the values to be compared. */ d1 += sqlite3VdbeSerialGet(&aKey1[d1], serial_type1, &mem1); /* Do the comparison */ rc = sqlite3MemCompare(&mem1, &pPKey2->aMem[i], pKeyInfo->nAllField>i ? pKeyInfo->aColl[i] : 0); if( rc!=0 ){ assert( mem1.szMalloc==0 ); /* See comment below */ if( (pKeyInfo->aSortFlags[i] & KEYINFO_ORDER_BIGNULL) && ((mem1.flags & MEM_Null) || (pPKey2->aMem[i].flags & MEM_Null)) ){ rc = -rc; } if( pKeyInfo->aSortFlags[i] & KEYINFO_ORDER_DESC ){ rc = -rc; /* Invert the result for DESC sort order. */ } goto debugCompareEnd; } i++; }while( idx1<szHdr1 && i<pPKey2->nField ); |
︙ | ︙ | |||
4021 4022 4023 4024 4025 4026 4027 | } /* ** Do a comparison between a 64-bit signed integer and a 64-bit floating-point ** number. Return negative, zero, or positive if the first (i64) is less than, ** equal to, or greater than the second (double). */ | | > > > | | | 4313 4314 4315 4316 4317 4318 4319 4320 4321 4322 4323 4324 4325 4326 4327 4328 4329 4330 4331 4332 4333 4334 4335 | } /* ** Do a comparison between a 64-bit signed integer and a 64-bit floating-point ** number. Return negative, zero, or positive if the first (i64) is less than, ** equal to, or greater than the second (double). */ int sqlite3IntFloatCompare(i64 i, double r){ if( sizeof(LONGDOUBLE_TYPE)>8 ){ LONGDOUBLE_TYPE x = (LONGDOUBLE_TYPE)i; testcase( x<r ); testcase( x>r ); testcase( x==r ); if( x<r ) return -1; if( x>r ) return +1; /*NO_TEST*/ /* work around bugs in gcov */ return 0; /*NO_TEST*/ /* work around bugs in gcov */ }else{ i64 y; double s; if( r<-9223372036854775808.0 ) return +1; if( r>=9223372036854775808.0 ) return -1; y = (i64)r; if( i<y ) return -1; |
︙ | ︙ | |||
4069 4070 4071 4072 4073 4074 4075 | */ if( combined_flags&MEM_Null ){ return (f2&MEM_Null) - (f1&MEM_Null); } /* At least one of the two values is a number */ | | > > > | > > > | > > > > > > | > | 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 4402 4403 4404 4405 4406 4407 4408 4409 4410 | */ if( combined_flags&MEM_Null ){ return (f2&MEM_Null) - (f1&MEM_Null); } /* At least one of the two values is a number */ if( combined_flags&(MEM_Int|MEM_Real|MEM_IntReal) ){ testcase( combined_flags & MEM_Int ); testcase( combined_flags & MEM_Real ); testcase( combined_flags & MEM_IntReal ); if( (f1 & f2 & (MEM_Int|MEM_IntReal))!=0 ){ testcase( f1 & f2 & MEM_Int ); testcase( f1 & f2 & MEM_IntReal ); if( pMem1->u.i < pMem2->u.i ) return -1; if( pMem1->u.i > pMem2->u.i ) return +1; return 0; } if( (f1 & f2 & MEM_Real)!=0 ){ if( pMem1->u.r < pMem2->u.r ) return -1; if( pMem1->u.r > pMem2->u.r ) return +1; return 0; } if( (f1&(MEM_Int|MEM_IntReal))!=0 ){ testcase( f1 & MEM_Int ); testcase( f1 & MEM_IntReal ); if( (f2&MEM_Real)!=0 ){ return sqlite3IntFloatCompare(pMem1->u.i, pMem2->u.r); }else if( (f2&(MEM_Int|MEM_IntReal))!=0 ){ if( pMem1->u.i < pMem2->u.i ) return -1; if( pMem1->u.i > pMem2->u.i ) return +1; return 0; }else{ return -1; } } if( (f1&MEM_Real)!=0 ){ if( (f2&(MEM_Int|MEM_IntReal))!=0 ){ testcase( f2 & MEM_Int ); testcase( f2 & MEM_IntReal ); return -sqlite3IntFloatCompare(pMem2->u.i, pMem1->u.r); }else{ return -1; } } return +1; } |
︙ | ︙ | |||
4220 4221 4222 4223 4224 4225 4226 | szHdr1 = aKey1[0]; d1 = szHdr1 + sqlite3VdbeSerialTypeLen(s1); i = 1; pRhs++; }else{ idx1 = getVarint32(aKey1, szHdr1); d1 = szHdr1; | > > | | | | < < | > | > | 4528 4529 4530 4531 4532 4533 4534 4535 4536 4537 4538 4539 4540 4541 4542 4543 4544 4545 4546 4547 4548 4549 4550 4551 4552 4553 4554 4555 4556 4557 4558 4559 4560 4561 | szHdr1 = aKey1[0]; d1 = szHdr1 + sqlite3VdbeSerialTypeLen(s1); i = 1; pRhs++; }else{ idx1 = getVarint32(aKey1, szHdr1); d1 = szHdr1; i = 0; } if( d1>(unsigned)nKey1 ){ pPKey2->errCode = (u8)SQLITE_CORRUPT_BKPT; return 0; /* Corruption */ } VVA_ONLY( mem1.szMalloc = 0; ) /* Only needed by assert() statements */ assert( pPKey2->pKeyInfo->nAllField>=pPKey2->nField || CORRUPT_DB ); assert( pPKey2->pKeyInfo->aSortFlags!=0 ); assert( pPKey2->pKeyInfo->nKeyField>0 ); assert( idx1<=szHdr1 || CORRUPT_DB ); do{ u32 serial_type; /* RHS is an integer */ if( pRhs->flags & (MEM_Int|MEM_IntReal) ){ testcase( pRhs->flags & MEM_Int ); testcase( pRhs->flags & MEM_IntReal ); serial_type = aKey1[idx1]; testcase( serial_type==12 ); if( serial_type>=10 ){ rc = +1; }else if( serial_type==0 ){ rc = -1; }else if( serial_type==7 ){ |
︙ | ︙ | |||
4285 4286 4287 4288 4289 4290 4291 | rc = sqlite3IntFloatCompare(mem1.u.i, pRhs->u.r); } } } /* RHS is a string */ else if( pRhs->flags & MEM_Str ){ | | | > > | | | 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 | rc = sqlite3IntFloatCompare(mem1.u.i, pRhs->u.r); } } } /* RHS is a string */ else if( pRhs->flags & MEM_Str ){ getVarint32NR(&aKey1[idx1], serial_type); testcase( serial_type==12 ); if( serial_type<12 ){ rc = -1; }else if( !(serial_type & 0x01) ){ rc = +1; }else{ mem1.n = (serial_type - 12) / 2; testcase( (d1+mem1.n)==(unsigned)nKey1 ); testcase( (d1+mem1.n+1)==(unsigned)nKey1 ); if( (d1+mem1.n) > (unsigned)nKey1 || (pKeyInfo = pPKey2->pKeyInfo)->nAllField<=i ){ pPKey2->errCode = (u8)SQLITE_CORRUPT_BKPT; return 0; /* Corruption */ }else if( pKeyInfo->aColl[i] ){ mem1.enc = pKeyInfo->enc; mem1.db = pKeyInfo->db; mem1.flags = MEM_Str; mem1.z = (char*)&aKey1[d1]; rc = vdbeCompareMemString( &mem1, pRhs, pKeyInfo->aColl[i], &pPKey2->errCode ); }else{ int nCmp = MIN(mem1.n, pRhs->n); rc = memcmp(&aKey1[d1], pRhs->z, nCmp); if( rc==0 ) rc = mem1.n - pRhs->n; } } } /* RHS is a blob */ else if( pRhs->flags & MEM_Blob ){ assert( (pRhs->flags & MEM_Zero)==0 || pRhs->n==0 ); getVarint32NR(&aKey1[idx1], serial_type); testcase( serial_type==12 ); if( serial_type<12 || (serial_type & 0x01) ){ rc = -1; }else{ int nStr = (serial_type - 12) / 2; testcase( (d1+nStr)==(unsigned)nKey1 ); testcase( (d1+nStr+1)==(unsigned)nKey1 ); |
︙ | ︙ | |||
4349 4350 4351 4352 4353 4354 4355 | /* RHS is null */ else{ serial_type = aKey1[idx1]; rc = (serial_type!=0); } if( rc!=0 ){ | | > > > > > | > | 4661 4662 4663 4664 4665 4666 4667 4668 4669 4670 4671 4672 4673 4674 4675 4676 4677 4678 4679 4680 4681 4682 | /* RHS is null */ else{ serial_type = aKey1[idx1]; rc = (serial_type!=0); } if( rc!=0 ){ int sortFlags = pPKey2->pKeyInfo->aSortFlags[i]; if( sortFlags ){ if( (sortFlags & KEYINFO_ORDER_BIGNULL)==0 || ((sortFlags & KEYINFO_ORDER_DESC) !=(serial_type==0 || (pRhs->flags&MEM_Null))) ){ rc = -rc; } } assert( vdbeRecordCompareDebug(nKey1, pKey1, pPKey2, rc) ); assert( mem1.szMalloc==0 ); /* See comment below */ return rc; } i++; |
︙ | ︙ | |||
4500 4501 4502 4503 4504 4505 4506 | ){ const u8 *aKey1 = (const u8*)pKey1; int serial_type; int res; assert( pPKey2->aMem[0].flags & MEM_Str ); vdbeAssertFieldCountWithinLimits(nKey1, pKey1, pPKey2->pKeyInfo); | > > | > | > > > > < < < < | 4818 4819 4820 4821 4822 4823 4824 4825 4826 4827 4828 4829 4830 4831 4832 4833 4834 4835 4836 4837 4838 4839 4840 4841 4842 4843 4844 4845 4846 4847 4848 4849 4850 4851 4852 4853 4854 4855 4856 4857 4858 4859 4860 4861 4862 4863 4864 4865 4866 4867 4868 4869 4870 | ){ const u8 *aKey1 = (const u8*)pKey1; int serial_type; int res; assert( pPKey2->aMem[0].flags & MEM_Str ); vdbeAssertFieldCountWithinLimits(nKey1, pKey1, pPKey2->pKeyInfo); serial_type = (u8)(aKey1[1]); if( serial_type >= 0x80 ){ sqlite3GetVarint32(&aKey1[1], (u32*)&serial_type); } if( serial_type<12 ){ res = pPKey2->r1; /* (pKey1/nKey1) is a number or a null */ }else if( !(serial_type & 0x01) ){ res = pPKey2->r2; /* (pKey1/nKey1) is a blob */ }else{ int nCmp; int nStr; int szHdr = aKey1[0]; nStr = (serial_type-12) / 2; if( (szHdr + nStr) > nKey1 ){ pPKey2->errCode = (u8)SQLITE_CORRUPT_BKPT; return 0; /* Corruption */ } nCmp = MIN( pPKey2->aMem[0].n, nStr ); res = memcmp(&aKey1[szHdr], pPKey2->aMem[0].z, nCmp); if( res>0 ){ res = pPKey2->r2; }else if( res<0 ){ res = pPKey2->r1; }else{ res = nStr - pPKey2->aMem[0].n; if( res==0 ){ if( pPKey2->nField>1 ){ res = sqlite3VdbeRecordCompareWithSkip(nKey1, pKey1, pPKey2, 1); }else{ res = pPKey2->default_rc; pPKey2->eqSeen = 1; } }else if( res>0 ){ res = pPKey2->r2; }else{ res = pPKey2->r1; } } } assert( vdbeRecordCompareDebug(nKey1, pKey1, pPKey2, res) || CORRUPT_DB || pPKey2->pKeyInfo->db->mallocFailed ); |
︙ | ︙ | |||
4567 4568 4569 4570 4571 4572 4573 | ** is an integer. ** ** The easiest way to enforce this limit is to consider only records with ** 13 fields or less. If the first field is an integer, the maximum legal ** header size is (12*5 + 1 + 1) bytes. */ if( p->pKeyInfo->nAllField<=13 ){ int flags = p->aMem[0].flags; | | > > > > | > | 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 | ** is an integer. ** ** The easiest way to enforce this limit is to consider only records with ** 13 fields or less. If the first field is an integer, the maximum legal ** header size is (12*5 + 1 + 1) bytes. */ if( p->pKeyInfo->nAllField<=13 ){ int flags = p->aMem[0].flags; if( p->pKeyInfo->aSortFlags[0] ){ if( p->pKeyInfo->aSortFlags[0] & KEYINFO_ORDER_BIGNULL ){ return sqlite3VdbeRecordCompare; } p->r1 = 1; p->r2 = -1; }else{ p->r1 = -1; p->r2 = 1; } if( (flags & MEM_Int) ){ return vdbeRecordCompareInt; } testcase( flags & MEM_Real ); testcase( flags & MEM_Null ); testcase( flags & MEM_Blob ); if( (flags & (MEM_Real|MEM_IntReal|MEM_Null|MEM_Blob))==0 && p->pKeyInfo->aColl[0]==0 ){ assert( flags & MEM_Str ); return vdbeRecordCompareString; } } return sqlite3VdbeRecordCompare; } |
︙ | ︙ | |||
4616 4617 4618 4619 4620 4621 4622 | */ assert( sqlite3BtreeCursorIsValid(pCur) ); nCellKey = sqlite3BtreePayloadSize(pCur); assert( (nCellKey & SQLITE_MAX_U32)==(u64)nCellKey ); /* Read in the complete content of the index entry */ sqlite3VdbeMemInit(&m, db, 0); | | | | | 4942 4943 4944 4945 4946 4947 4948 4949 4950 4951 4952 4953 4954 4955 4956 4957 4958 4959 4960 4961 4962 4963 4964 4965 4966 4967 4968 4969 4970 4971 4972 4973 | */ assert( sqlite3BtreeCursorIsValid(pCur) ); nCellKey = sqlite3BtreePayloadSize(pCur); assert( (nCellKey & SQLITE_MAX_U32)==(u64)nCellKey ); /* Read in the complete content of the index entry */ sqlite3VdbeMemInit(&m, db, 0); rc = sqlite3VdbeMemFromBtreeZeroOffset(pCur, (u32)nCellKey, &m); if( rc ){ return rc; } /* The index entry must begin with a header size */ getVarint32NR((u8*)m.z, szHdr); testcase( szHdr==3 ); testcase( szHdr==m.n ); testcase( szHdr>0x7fffffff ); assert( m.n>=0 ); if( unlikely(szHdr<3 || szHdr>(unsigned)m.n) ){ goto idx_rowid_corruption; } /* The last field of the index should be an integer - the ROWID. ** Verify that the last entry really is an integer. */ getVarint32NR((u8*)&m.z[szHdr-1], typeRowid); testcase( typeRowid==1 ); testcase( typeRowid==2 ); testcase( typeRowid==3 ); testcase( typeRowid==4 ); testcase( typeRowid==5 ); testcase( typeRowid==6 ); testcase( typeRowid==8 ); |
︙ | ︙ | |||
4698 4699 4700 4701 4702 4703 4704 | /* nCellKey will always be between 0 and 0xffffffff because of the way ** that btreeParseCellPtr() and sqlite3GetVarint32() are implemented */ if( nCellKey<=0 || nCellKey>0x7fffffff ){ *res = 0; return SQLITE_CORRUPT_BKPT; } sqlite3VdbeMemInit(&m, db, 0); | | | | 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 | /* nCellKey will always be between 0 and 0xffffffff because of the way ** that btreeParseCellPtr() and sqlite3GetVarint32() are implemented */ if( nCellKey<=0 || nCellKey>0x7fffffff ){ *res = 0; return SQLITE_CORRUPT_BKPT; } sqlite3VdbeMemInit(&m, db, 0); rc = sqlite3VdbeMemFromBtreeZeroOffset(pCur, (u32)nCellKey, &m); if( rc ){ return rc; } *res = sqlite3VdbeRecordCompareWithSkip(m.n, m.z, pUnpacked, 0); sqlite3VdbeMemRelease(&m); return SQLITE_OK; } /* ** This routine sets the value to be returned by subsequent calls to ** sqlite3_changes() on the database handle 'db'. */ void sqlite3VdbeSetChanges(sqlite3 *db, i64 nChange){ assert( sqlite3_mutex_held(db->mutex) ); db->nChange = nChange; db->nTotalChange += nChange; } /* ** Set a flag in the vdbe to update the change counter when it is finalised |
︙ | ︙ | |||
4814 4815 4816 4817 4818 4819 4820 | ** ** OP_PureFunc means that the function must be deterministic, and should ** throw an error if it is given inputs that would make it non-deterministic. ** This routine is invoked by date/time functions that use non-deterministic ** features such as 'now'. */ int sqlite3NotPureFunc(sqlite3_context *pCtx){ | > | > | > > > > > > > > > > > | < | | 5140 5141 5142 5143 5144 5145 5146 5147 5148 5149 5150 5151 5152 5153 5154 5155 5156 5157 5158 5159 5160 5161 5162 5163 5164 5165 5166 5167 5168 5169 5170 5171 5172 | ** ** OP_PureFunc means that the function must be deterministic, and should ** throw an error if it is given inputs that would make it non-deterministic. ** This routine is invoked by date/time functions that use non-deterministic ** features such as 'now'. */ int sqlite3NotPureFunc(sqlite3_context *pCtx){ const VdbeOp *pOp; #ifdef SQLITE_ENABLE_STAT4 if( pCtx->pVdbe==0 ) return 1; #endif pOp = pCtx->pVdbe->aOp + pCtx->iOp; if( pOp->opcode==OP_PureFunc ){ const char *zContext; char *zMsg; if( pOp->p5 & NC_IsCheck ){ zContext = "a CHECK constraint"; }else if( pOp->p5 & NC_GenCol ){ zContext = "a generated column"; }else{ zContext = "an index"; } zMsg = sqlite3_mprintf("non-deterministic use of %s() in %s", pCtx->pFunc->zName, zContext); sqlite3_result_error(pCtx, zMsg, -1); sqlite3_free(zMsg); return 0; } return 1; } #ifndef SQLITE_OMIT_VIRTUALTABLE /* |
︙ | ︙ | |||
4879 4880 4881 4882 4883 4884 4885 | void sqlite3VdbePreUpdateHook( Vdbe *v, /* Vdbe pre-update hook is invoked by */ VdbeCursor *pCsr, /* Cursor to grab old.* values from */ int op, /* SQLITE_INSERT, UPDATE or DELETE */ const char *zDb, /* Database name */ Table *pTab, /* Modified table */ i64 iKey1, /* Initial key value */ | | > > > | > | 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 | void sqlite3VdbePreUpdateHook( Vdbe *v, /* Vdbe pre-update hook is invoked by */ VdbeCursor *pCsr, /* Cursor to grab old.* values from */ int op, /* SQLITE_INSERT, UPDATE or DELETE */ const char *zDb, /* Database name */ Table *pTab, /* Modified table */ i64 iKey1, /* Initial key value */ int iReg, /* Register for new.* record */ int iBlobWrite ){ sqlite3 *db = v->db; i64 iKey2; PreUpdate preupdate; const char *zTbl = pTab->zName; static const u8 fakeSortOrder = 0; assert( db->pPreUpdate==0 ); memset(&preupdate, 0, sizeof(PreUpdate)); if( HasRowid(pTab)==0 ){ iKey1 = iKey2 = 0; preupdate.pPk = sqlite3PrimaryKeyIndex(pTab); }else{ if( op==SQLITE_UPDATE ){ iKey2 = v->aMem[iReg].u.i; }else{ iKey2 = iKey1; } } assert( pCsr!=0 ); assert( pCsr->eCurType==CURTYPE_BTREE ); assert( pCsr->nField==pTab->nCol || (pCsr->nField==pTab->nCol+1 && op==SQLITE_DELETE && iReg==-1) ); preupdate.v = v; preupdate.pCsr = pCsr; preupdate.op = op; preupdate.iNewReg = iReg; preupdate.keyinfo.db = db; preupdate.keyinfo.enc = ENC(db); preupdate.keyinfo.nKeyField = pTab->nCol; preupdate.keyinfo.aSortFlags = (u8*)&fakeSortOrder; preupdate.iKey1 = iKey1; preupdate.iKey2 = iKey2; preupdate.pTab = pTab; preupdate.iBlobWrite = iBlobWrite; db->pPreUpdate = &preupdate; db->xPreUpdateCallback(db->pPreUpdateArg, db, op, zDb, zTbl, iKey1, iKey2); db->pPreUpdate = 0; sqlite3DbFree(db, preupdate.aRecord); vdbeFreeUnpacked(db, preupdate.keyinfo.nKeyField+1, preupdate.pUnpacked); vdbeFreeUnpacked(db, preupdate.keyinfo.nKeyField+1, preupdate.pNewUnpacked); |
︙ | ︙ |
Changes to src/vdbeblob.c.
︙ | ︙ | |||
71 72 73 74 75 76 77 | assert( v->aOp[v->pc].opcode==OP_NotExists ); rc = sqlite3VdbeExec(v); }else{ rc = sqlite3_step(p->pStmt); } if( rc==SQLITE_ROW ){ VdbeCursor *pC = v->apCsr[0]; | > > > | | 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 | assert( v->aOp[v->pc].opcode==OP_NotExists ); rc = sqlite3VdbeExec(v); }else{ rc = sqlite3_step(p->pStmt); } if( rc==SQLITE_ROW ){ VdbeCursor *pC = v->apCsr[0]; u32 type; assert( pC!=0 ); assert( pC->eCurType==CURTYPE_BTREE ); type = pC->nHdrParsed>p->iCol ? pC->aType[p->iCol] : 0; testcase( pC->nHdrParsed==p->iCol ); testcase( pC->nHdrParsed==p->iCol+1 ); if( type<12 ){ zErr = sqlite3MPrintf(p->db, "cannot open value of type %s", type==0?"null": type==7?"real": "integer" ); rc = SQLITE_ERROR; |
︙ | ︙ | |||
163 164 165 166 167 168 169 | sqlite3ErrorMsg(&sParse, "cannot open virtual table: %s", zTable); } if( pTab && !HasRowid(pTab) ){ pTab = 0; sqlite3ErrorMsg(&sParse, "cannot open table without rowid: %s", zTable); } #ifndef SQLITE_OMIT_VIEW | | | | 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 | sqlite3ErrorMsg(&sParse, "cannot open virtual table: %s", zTable); } if( pTab && !HasRowid(pTab) ){ pTab = 0; sqlite3ErrorMsg(&sParse, "cannot open table without rowid: %s", zTable); } #ifndef SQLITE_OMIT_VIEW if( pTab && IsView(pTab) ){ pTab = 0; sqlite3ErrorMsg(&sParse, "cannot open view: %s", zTable); } #endif if( !pTab ){ if( sParse.zErrMsg ){ sqlite3DbFree(db, zErr); zErr = sParse.zErrMsg; sParse.zErrMsg = 0; } rc = SQLITE_ERROR; sqlite3BtreeLeaveAll(db); goto blob_open_out; } pBlob->pTab = pTab; pBlob->zDb = db->aDb[sqlite3SchemaToIndex(db, pTab->pSchema)].zDbSName; /* Now search pTab for the exact column. */ for(iCol=0; iCol<pTab->nCol; iCol++) { if( sqlite3StrICmp(pTab->aCol[iCol].zCnName, zColumn)==0 ){ break; } } if( iCol==pTab->nCol ){ sqlite3DbFree(db, zErr); zErr = sqlite3MPrintf(db, "no such column: \"%s\"", zColumn); rc = SQLITE_ERROR; |
︙ | ︙ | |||
208 209 210 211 212 213 214 | #ifndef SQLITE_OMIT_FOREIGN_KEY if( db->flags&SQLITE_ForeignKeys ){ /* Check that the column is not part of an FK child key definition. It ** is not necessary to check if it is part of a parent key, as parent ** key columns must be indexed. The check below will pick up this ** case. */ FKey *pFKey; | > | | 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 | #ifndef SQLITE_OMIT_FOREIGN_KEY if( db->flags&SQLITE_ForeignKeys ){ /* Check that the column is not part of an FK child key definition. It ** is not necessary to check if it is part of a parent key, as parent ** key columns must be indexed. The check below will pick up this ** case. */ FKey *pFKey; assert( IsOrdinaryTable(pTab) ); for(pFKey=pTab->u.tab.pFKey; pFKey; pFKey=pFKey->pNextFrom){ int j; for(j=0; j<pFKey->nCol; j++){ if( pFKey->aCol[j].iFrom==iCol ){ zFault = "foreign key"; } } } |
︙ | ︙ | |||
351 352 353 354 355 356 357 358 359 | */ int sqlite3_blob_close(sqlite3_blob *pBlob){ Incrblob *p = (Incrblob *)pBlob; int rc; sqlite3 *db; if( p ){ db = p->db; sqlite3_mutex_enter(db->mutex); | > < > | 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 | */ int sqlite3_blob_close(sqlite3_blob *pBlob){ Incrblob *p = (Incrblob *)pBlob; int rc; sqlite3 *db; if( p ){ sqlite3_stmt *pStmt = p->pStmt; db = p->db; sqlite3_mutex_enter(db->mutex); sqlite3DbFree(db, p); sqlite3_mutex_leave(db->mutex); rc = sqlite3_finalize(pStmt); }else{ rc = SQLITE_OK; } return rc; } /* |
︙ | ︙ | |||
414 415 416 417 418 419 420 421 | ** same way as an SQLITE_DELETE (the SQLITE_DELETE code is actually ** slightly more efficient). Since you cannot write to a PK column ** using the incremental-blob API, this works. For the sessions module ** anyhow. */ sqlite3_int64 iKey; iKey = sqlite3BtreeIntegerKey(p->pCsr); sqlite3VdbePreUpdateHook( | > > | | 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 | ** same way as an SQLITE_DELETE (the SQLITE_DELETE code is actually ** slightly more efficient). Since you cannot write to a PK column ** using the incremental-blob API, this works. For the sessions module ** anyhow. */ sqlite3_int64 iKey; iKey = sqlite3BtreeIntegerKey(p->pCsr); assert( v->apCsr[0]!=0 ); assert( v->apCsr[0]->eCurType==CURTYPE_BTREE ); sqlite3VdbePreUpdateHook( v, v->apCsr[0], SQLITE_DELETE, p->zDb, p->pTab, iKey, -1, p->iCol ); } #endif rc = xCall(p->pCsr, iOffset+p->iOffset, n, z); sqlite3BtreeLeaveCursor(p->pCsr); if( rc==SQLITE_ABORT ){ |
︙ | ︙ | |||
486 487 488 489 490 491 492 493 494 495 496 497 498 499 | if( p->pStmt==0 ){ /* If there is no statement handle, then the blob-handle has ** already been invalidated. Return SQLITE_ABORT in this case. */ rc = SQLITE_ABORT; }else{ char *zErr; rc = blobSeekToRow(p, iRow, &zErr); if( rc!=SQLITE_OK ){ sqlite3ErrorWithMsg(db, rc, (zErr ? "%s" : 0), zErr); sqlite3DbFree(db, zErr); } assert( rc!=SQLITE_SCHEMA ); } | > | 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 | if( p->pStmt==0 ){ /* If there is no statement handle, then the blob-handle has ** already been invalidated. Return SQLITE_ABORT in this case. */ rc = SQLITE_ABORT; }else{ char *zErr; ((Vdbe*)p->pStmt)->rc = SQLITE_OK; rc = blobSeekToRow(p, iRow, &zErr); if( rc!=SQLITE_OK ){ sqlite3ErrorWithMsg(db, rc, (zErr ? "%s" : 0), zErr); sqlite3DbFree(db, zErr); } assert( rc!=SQLITE_SCHEMA ); } |
︙ | ︙ |
Changes to src/vdbemem.c.
︙ | ︙ | |||
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 | ** stores a single value in the VDBE. Mem is an opaque structure visible ** only within the VDBE. Interface routines refer to a Mem using the ** name sqlite_value */ #include "sqliteInt.h" #include "vdbeInt.h" #ifdef SQLITE_DEBUG /* ** Check invariants on a Mem object. ** ** This routine is intended for use inside of assert() statements, like ** this: assert( sqlite3VdbeCheckMemInvariants(pMem) ); */ int sqlite3VdbeCheckMemInvariants(Mem *p){ /* If MEM_Dyn is set then Mem.xDel!=0. ** Mem.xDel might not be initialized if MEM_Dyn is clear. */ assert( (p->flags & MEM_Dyn)==0 || p->xDel!=0 ); /* MEM_Dyn may only be set if Mem.szMalloc==0. In this way we ** ensure that if Mem.szMalloc>0 then it is safe to do ** Mem.z = Mem.zMalloc without having to check Mem.flags&MEM_Dyn. ** That saves a few cycles in inner loops. */ assert( (p->flags & MEM_Dyn)==0 || p->szMalloc==0 ); | > > > > > | | | > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > | < | > | > > > > | < > > > > | 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 | ** stores a single value in the VDBE. Mem is an opaque structure visible ** only within the VDBE. Interface routines refer to a Mem using the ** name sqlite_value */ #include "sqliteInt.h" #include "vdbeInt.h" /* True if X is a power of two. 0 is considered a power of two here. ** In other words, return true if X has at most one bit set. */ #define ISPOWEROF2(X) (((X)&((X)-1))==0) #ifdef SQLITE_DEBUG /* ** Check invariants on a Mem object. ** ** This routine is intended for use inside of assert() statements, like ** this: assert( sqlite3VdbeCheckMemInvariants(pMem) ); */ int sqlite3VdbeCheckMemInvariants(Mem *p){ /* If MEM_Dyn is set then Mem.xDel!=0. ** Mem.xDel might not be initialized if MEM_Dyn is clear. */ assert( (p->flags & MEM_Dyn)==0 || p->xDel!=0 ); /* MEM_Dyn may only be set if Mem.szMalloc==0. In this way we ** ensure that if Mem.szMalloc>0 then it is safe to do ** Mem.z = Mem.zMalloc without having to check Mem.flags&MEM_Dyn. ** That saves a few cycles in inner loops. */ assert( (p->flags & MEM_Dyn)==0 || p->szMalloc==0 ); /* Cannot have more than one of MEM_Int, MEM_Real, or MEM_IntReal */ assert( ISPOWEROF2(p->flags & (MEM_Int|MEM_Real|MEM_IntReal)) ); if( p->flags & MEM_Null ){ /* Cannot be both MEM_Null and some other type */ assert( (p->flags & (MEM_Int|MEM_Real|MEM_Str|MEM_Blob|MEM_Agg))==0 ); /* If MEM_Null is set, then either the value is a pure NULL (the usual ** case) or it is a pointer set using sqlite3_bind_pointer() or ** sqlite3_result_pointer(). If a pointer, then MEM_Term must also be ** set. */ if( (p->flags & (MEM_Term|MEM_Subtype))==(MEM_Term|MEM_Subtype) ){ /* This is a pointer type. There may be a flag to indicate what to ** do with the pointer. */ assert( ((p->flags&MEM_Dyn)!=0 ? 1 : 0) + ((p->flags&MEM_Ephem)!=0 ? 1 : 0) + ((p->flags&MEM_Static)!=0 ? 1 : 0) <= 1 ); /* No other bits set */ assert( (p->flags & ~(MEM_Null|MEM_Term|MEM_Subtype|MEM_FromBind |MEM_Dyn|MEM_Ephem|MEM_Static))==0 ); }else{ /* A pure NULL might have other flags, such as MEM_Static, MEM_Dyn, ** MEM_Ephem, MEM_Cleared, or MEM_Subtype */ } }else{ /* The MEM_Cleared bit is only allowed on NULLs */ assert( (p->flags & MEM_Cleared)==0 ); } /* The szMalloc field holds the correct memory allocation size */ assert( p->szMalloc==0 || (p->flags==MEM_Undefined && p->szMalloc<=sqlite3DbMallocSize(p->db,p->zMalloc)) || p->szMalloc==sqlite3DbMallocSize(p->db,p->zMalloc)); /* If p holds a string or blob, the Mem.z must point to exactly ** one of the following: ** ** (1) Memory in Mem.zMalloc and managed by the Mem object ** (2) Memory to be freed using Mem.xDel ** (3) An ephemeral string or blob ** (4) A static string or blob */ if( (p->flags & (MEM_Str|MEM_Blob)) && p->n>0 ){ assert( ((p->szMalloc>0 && p->z==p->zMalloc)? 1 : 0) + ((p->flags&MEM_Dyn)!=0 ? 1 : 0) + ((p->flags&MEM_Ephem)!=0 ? 1 : 0) + ((p->flags&MEM_Static)!=0 ? 1 : 0) == 1 ); } return 1; } #endif /* ** Render a Mem object which is one of MEM_Int, MEM_Real, or MEM_IntReal ** into a buffer. */ static void vdbeMemRenderNum(int sz, char *zBuf, Mem *p){ StrAccum acc; assert( p->flags & (MEM_Int|MEM_Real|MEM_IntReal) ); assert( sz>22 ); if( p->flags & MEM_Int ){ #if GCC_VERSION>=7000000 /* Work-around for GCC bug ** https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96270 */ i64 x; assert( (p->flags&MEM_Int)*2==sizeof(x) ); memcpy(&x, (char*)&p->u, (p->flags&MEM_Int)*2); sqlite3Int64ToText(x, zBuf); #else sqlite3Int64ToText(p->u.i, zBuf); #endif }else{ sqlite3StrAccumInit(&acc, 0, zBuf, sz, 0); sqlite3_str_appendf(&acc, "%!.15g", (p->flags & MEM_IntReal)!=0 ? (double)p->u.i : p->u.r); assert( acc.zText==zBuf && acc.mxAlloc<=0 ); zBuf[acc.nChar] = 0; /* Fast version of sqlite3StrAccumFinish(&acc) */ } } #ifdef SQLITE_DEBUG /* ** Validity checks on pMem. pMem holds a string. ** ** (1) Check that string value of pMem agrees with its integer or real value. ** (2) Check that the string is correctly zero terminated ** ** A single int or real value always converts to the same strings. But ** many different strings can be converted into the same int or real. ** If a table contains a numeric value and an index is based on the ** corresponding string value, then it is important that the string be ** derived from the numeric value, not the other way around, to ensure ** that the index and table are consistent. See ticket ** https://www.sqlite.org/src/info/343634942dd54ab (2018-01-31) for ** an example. ** ** This routine looks at pMem to verify that if it has both a numeric ** representation and a string representation then the string rep has ** been derived from the numeric and not the other way around. It returns ** true if everything is ok and false if there is a problem. ** ** This routine is for use inside of assert() statements only. */ int sqlite3VdbeMemValidStrRep(Mem *p){ char zBuf[100]; char *z; int i, j, incr; if( (p->flags & MEM_Str)==0 ) return 1; if( p->flags & MEM_Term ){ /* Insure that the string is properly zero-terminated. Pay particular ** attention to the case where p->n is odd */ if( p->szMalloc>0 && p->z==p->zMalloc ){ assert( p->enc==SQLITE_UTF8 || p->szMalloc >= ((p->n+1)&~1)+2 ); assert( p->enc!=SQLITE_UTF8 || p->szMalloc >= p->n+1 ); } assert( p->z[p->n]==0 ); assert( p->enc==SQLITE_UTF8 || p->z[(p->n+1)&~1]==0 ); assert( p->enc==SQLITE_UTF8 || p->z[((p->n+1)&~1)+1]==0 ); } if( (p->flags & (MEM_Int|MEM_Real|MEM_IntReal))==0 ) return 1; vdbeMemRenderNum(sizeof(zBuf), zBuf, p); z = p->z; i = j = 0; incr = 1; if( p->enc!=SQLITE_UTF8 ){ incr = 2; if( p->enc==SQLITE_UTF16BE ) z++; } |
︙ | ︙ | |||
151 152 153 154 155 156 157 158 159 160 161 162 163 164 | ** SQLITE_NOMEM may be returned if a malloc() fails during conversion ** between formats. */ int sqlite3VdbeChangeEncoding(Mem *pMem, int desiredEnc){ #ifndef SQLITE_OMIT_UTF16 int rc; #endif assert( !sqlite3VdbeMemIsRowSet(pMem) ); assert( desiredEnc==SQLITE_UTF8 || desiredEnc==SQLITE_UTF16LE || desiredEnc==SQLITE_UTF16BE ); if( !(pMem->flags&MEM_Str) || pMem->enc==desiredEnc ){ return SQLITE_OK; } assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); | > | 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 | ** SQLITE_NOMEM may be returned if a malloc() fails during conversion ** between formats. */ int sqlite3VdbeChangeEncoding(Mem *pMem, int desiredEnc){ #ifndef SQLITE_OMIT_UTF16 int rc; #endif assert( pMem!=0 ); assert( !sqlite3VdbeMemIsRowSet(pMem) ); assert( desiredEnc==SQLITE_UTF8 || desiredEnc==SQLITE_UTF16LE || desiredEnc==SQLITE_UTF16BE ); if( !(pMem->flags&MEM_Str) || pMem->enc==desiredEnc ){ return SQLITE_OK; } assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); |
︙ | ︙ | |||
174 175 176 177 178 179 180 | assert(rc==SQLITE_OK || pMem->enc!=desiredEnc); assert(rc==SQLITE_NOMEM || pMem->enc==desiredEnc); return rc; #endif } /* | | < > > | < > | > > > > > | 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 | assert(rc==SQLITE_OK || pMem->enc!=desiredEnc); assert(rc==SQLITE_NOMEM || pMem->enc==desiredEnc); return rc; #endif } /* ** Make sure pMem->z points to a writable allocation of at least n bytes. ** ** If the bPreserve argument is true, then copy of the content of ** pMem->z into the new allocation. pMem must be either a string or ** blob if bPreserve is true. If bPreserve is false, any prior content ** in pMem->z is discarded. */ SQLITE_NOINLINE int sqlite3VdbeMemGrow(Mem *pMem, int n, int bPreserve){ assert( sqlite3VdbeCheckMemInvariants(pMem) ); assert( !sqlite3VdbeMemIsRowSet(pMem) ); testcase( pMem->db==0 ); /* If the bPreserve flag is set to true, then the memory cell must already ** contain a valid string or blob value. */ assert( bPreserve==0 || pMem->flags&(MEM_Blob|MEM_Str) ); testcase( bPreserve && pMem->z==0 ); assert( pMem->szMalloc==0 || (pMem->flags==MEM_Undefined && pMem->szMalloc<=sqlite3DbMallocSize(pMem->db,pMem->zMalloc)) || pMem->szMalloc==sqlite3DbMallocSize(pMem->db,pMem->zMalloc)); if( pMem->szMalloc>0 && bPreserve && pMem->z==pMem->zMalloc ){ if( pMem->db ){ pMem->z = pMem->zMalloc = sqlite3DbReallocOrFree(pMem->db, pMem->z, n); }else{ pMem->zMalloc = sqlite3Realloc(pMem->z, n); if( pMem->zMalloc==0 ) sqlite3_free(pMem->z); pMem->z = pMem->zMalloc; } bPreserve = 0; }else{ if( pMem->szMalloc>0 ) sqlite3DbFreeNN(pMem->db, pMem->zMalloc); pMem->zMalloc = sqlite3DbMallocRaw(pMem->db, n); } if( pMem->zMalloc==0 ){ sqlite3VdbeMemSetNull(pMem); |
︙ | ︙ | |||
232 233 234 235 236 237 238 | /* ** Change the pMem->zMalloc allocation to be at least szNew bytes. ** If pMem->zMalloc already meets or exceeds the requested size, this ** routine is a no-op. ** ** Any prior string or blob content in the pMem object may be discarded. ** The pMem->xDel destructor is called, if it exists. Though MEM_Str | | | | | > > > > > | > > | 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 | /* ** Change the pMem->zMalloc allocation to be at least szNew bytes. ** If pMem->zMalloc already meets or exceeds the requested size, this ** routine is a no-op. ** ** Any prior string or blob content in the pMem object may be discarded. ** The pMem->xDel destructor is called, if it exists. Though MEM_Str ** and MEM_Blob values may be discarded, MEM_Int, MEM_Real, MEM_IntReal, ** and MEM_Null values are preserved. ** ** Return SQLITE_OK on success or an error code (probably SQLITE_NOMEM) ** if unable to complete the resizing. */ int sqlite3VdbeMemClearAndResize(Mem *pMem, int szNew){ assert( CORRUPT_DB || szNew>0 ); assert( (pMem->flags & MEM_Dyn)==0 || pMem->szMalloc==0 ); if( pMem->szMalloc<szNew ){ return sqlite3VdbeMemGrow(pMem, szNew, 0); } assert( (pMem->flags & MEM_Dyn)==0 ); pMem->z = pMem->zMalloc; pMem->flags &= (MEM_Null|MEM_Int|MEM_Real|MEM_IntReal); return SQLITE_OK; } /* ** It is already known that pMem contains an unterminated string. ** Add the zero terminator. ** ** Three bytes of zero are added. In this way, there is guaranteed ** to be a double-zero byte at an even byte boundary in order to ** terminate a UTF16 string, even if the initial size of the buffer ** is an odd number of bytes. */ static SQLITE_NOINLINE int vdbeMemAddTerminator(Mem *pMem){ if( sqlite3VdbeMemGrow(pMem, pMem->n+3, 1) ){ return SQLITE_NOMEM_BKPT; } pMem->z[pMem->n] = 0; pMem->z[pMem->n+1] = 0; pMem->z[pMem->n+2] = 0; pMem->flags |= MEM_Term; return SQLITE_OK; } /* ** Change pMem so that its MEM_Str or MEM_Blob value is stored in ** MEM.zMalloc, where it can be safely written. ** ** Return SQLITE_OK on success or SQLITE_NOMEM if malloc fails. */ int sqlite3VdbeMemMakeWriteable(Mem *pMem){ assert( pMem!=0 ); assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); assert( !sqlite3VdbeMemIsRowSet(pMem) ); if( (pMem->flags & (MEM_Str|MEM_Blob))!=0 ){ if( ExpandBlob(pMem) ) return SQLITE_NOMEM; if( pMem->szMalloc==0 || pMem->z!=pMem->zMalloc ){ int rc = vdbeMemAddTerminator(pMem); if( rc ) return rc; |
︙ | ︙ | |||
295 296 297 298 299 300 301 | /* ** If the given Mem* has a zero-filled tail, turn it into an ordinary ** blob stored in dynamically allocated space. */ #ifndef SQLITE_OMIT_INCRBLOB int sqlite3VdbeMemExpandBlob(Mem *pMem){ int nByte; | | | > > > > > > | | | | | < > | | | < < < < < < < | < < < < | > | 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 | /* ** If the given Mem* has a zero-filled tail, turn it into an ordinary ** blob stored in dynamically allocated space. */ #ifndef SQLITE_OMIT_INCRBLOB int sqlite3VdbeMemExpandBlob(Mem *pMem){ int nByte; assert( pMem!=0 ); assert( pMem->flags & MEM_Zero ); assert( (pMem->flags&MEM_Blob)!=0 || MemNullNochng(pMem) ); testcase( sqlite3_value_nochange(pMem) ); assert( !sqlite3VdbeMemIsRowSet(pMem) ); assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); /* Set nByte to the number of bytes required to store the expanded blob. */ nByte = pMem->n + pMem->u.nZero; if( nByte<=0 ){ if( (pMem->flags & MEM_Blob)==0 ) return SQLITE_OK; nByte = 1; } if( sqlite3VdbeMemGrow(pMem, nByte, 1) ){ return SQLITE_NOMEM_BKPT; } assert( pMem->z!=0 ); assert( sqlite3DbMallocSize(pMem->db,pMem->z) >= nByte ); memset(&pMem->z[pMem->n], 0, pMem->u.nZero); pMem->n += pMem->u.nZero; pMem->flags &= ~(MEM_Zero|MEM_Term); return SQLITE_OK; } #endif /* ** Make sure the given Mem is \u0000 terminated. */ int sqlite3VdbeMemNulTerminate(Mem *pMem){ assert( pMem!=0 ); assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); testcase( (pMem->flags & (MEM_Term|MEM_Str))==(MEM_Term|MEM_Str) ); testcase( (pMem->flags & (MEM_Term|MEM_Str))==0 ); if( (pMem->flags & (MEM_Term|MEM_Str))!=MEM_Str ){ return SQLITE_OK; /* Nothing to do */ }else{ return vdbeMemAddTerminator(pMem); } } /* ** Add MEM_Str to the set of representations for the given Mem. This ** routine is only called if pMem is a number of some kind, not a NULL ** or a BLOB. ** ** Existing representations MEM_Int, MEM_Real, or MEM_IntReal are invalidated ** if bForce is true but are retained if bForce is false. ** ** A MEM_Null value will never be passed to this function. This function is ** used for converting values to text for returning to the user (i.e. via ** sqlite3_value_text()), or for ensuring that values to be used as btree ** keys are strings. In the former case a NULL pointer is returned the ** user and the latter is an internal programming error. */ int sqlite3VdbeMemStringify(Mem *pMem, u8 enc, u8 bForce){ const int nByte = 32; assert( pMem!=0 ); assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); assert( !(pMem->flags&MEM_Zero) ); assert( !(pMem->flags&(MEM_Str|MEM_Blob)) ); assert( pMem->flags&(MEM_Int|MEM_Real|MEM_IntReal) ); assert( !sqlite3VdbeMemIsRowSet(pMem) ); assert( EIGHT_BYTE_ALIGNMENT(pMem) ); if( sqlite3VdbeMemClearAndResize(pMem, nByte) ){ pMem->enc = 0; return SQLITE_NOMEM_BKPT; } vdbeMemRenderNum(nByte, pMem->z, pMem); assert( pMem->z!=0 ); pMem->n = sqlite3Strlen30NN(pMem->z); pMem->enc = SQLITE_UTF8; pMem->flags |= MEM_Str|MEM_Term; if( bForce ) pMem->flags &= ~(MEM_Int|MEM_Real|MEM_IntReal); sqlite3VdbeChangeEncoding(pMem, enc); return SQLITE_OK; } /* ** Memory cell pMem contains the context of an aggregate function. ** This routine calls the finalize method for that function. The ** result of the aggregate is stored back into pMem. ** ** Return SQLITE_ERROR if the finalizer reports an error. SQLITE_OK ** otherwise. */ int sqlite3VdbeMemFinalize(Mem *pMem, FuncDef *pFunc){ sqlite3_context ctx; Mem t; assert( pFunc!=0 ); assert( pMem!=0 ); assert( pFunc->xFinalize!=0 ); assert( (pMem->flags & MEM_Null)!=0 || pFunc==pMem->u.pDef ); assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); memset(&ctx, 0, sizeof(ctx)); memset(&t, 0, sizeof(t)); t.flags = MEM_Null; t.db = pMem->db; |
︙ | ︙ | |||
422 423 424 425 426 427 428 | ** ** SQLITE_ERROR is returned if xValue() reports an error. SQLITE_OK ** otherwise. */ #ifndef SQLITE_OMIT_WINDOWFUNC int sqlite3VdbeMemAggValue(Mem *pAccum, Mem *pOut, FuncDef *pFunc){ sqlite3_context ctx; | < < < < | 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 | ** ** SQLITE_ERROR is returned if xValue() reports an error. SQLITE_OK ** otherwise. */ #ifndef SQLITE_OMIT_WINDOWFUNC int sqlite3VdbeMemAggValue(Mem *pAccum, Mem *pOut, FuncDef *pFunc){ sqlite3_context ctx; assert( pFunc!=0 ); assert( pFunc->xValue!=0 ); assert( (pAccum->flags & MEM_Null)!=0 || pFunc==pAccum->u.pDef ); assert( pAccum->db==0 || sqlite3_mutex_held(pAccum->db->mutex) ); memset(&ctx, 0, sizeof(ctx)); sqlite3VdbeMemSetNull(pOut); ctx.pOut = pOut; ctx.pMem = pAccum; ctx.pFunc = pFunc; pFunc->xValue(&ctx); return ctx.isError; } |
︙ | ︙ | |||
548 549 550 551 552 553 554 555 556 557 | static SQLITE_NOINLINE i64 memIntValue(Mem *pMem){ i64 value = 0; sqlite3Atoi64(pMem->z, &value, pMem->n, pMem->enc); return value; } i64 sqlite3VdbeIntValue(Mem *pMem){ int flags; assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); assert( EIGHT_BYTE_ALIGNMENT(pMem) ); flags = pMem->flags; | > > | | < > | > | > > | 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 | static SQLITE_NOINLINE i64 memIntValue(Mem *pMem){ i64 value = 0; sqlite3Atoi64(pMem->z, &value, pMem->n, pMem->enc); return value; } i64 sqlite3VdbeIntValue(Mem *pMem){ int flags; assert( pMem!=0 ); assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); assert( EIGHT_BYTE_ALIGNMENT(pMem) ); flags = pMem->flags; if( flags & (MEM_Int|MEM_IntReal) ){ testcase( flags & MEM_IntReal ); return pMem->u.i; }else if( flags & MEM_Real ){ return doubleToInt64(pMem->u.r); }else if( (flags & (MEM_Str|MEM_Blob))!=0 && pMem->z!=0 ){ return memIntValue(pMem); }else{ return 0; } } /* ** Return the best representation of pMem that we can get into a ** double. If pMem is already a double or an integer, return its ** value. If it is a string or blob, try to convert it to a double. ** If it is a NULL, return 0.0. */ static SQLITE_NOINLINE double memRealValue(Mem *pMem){ /* (double)0 In case of SQLITE_OMIT_FLOATING_POINT... */ double val = (double)0; sqlite3AtoF(pMem->z, &val, pMem->n, pMem->enc); return val; } double sqlite3VdbeRealValue(Mem *pMem){ assert( pMem!=0 ); assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); assert( EIGHT_BYTE_ALIGNMENT(pMem) ); if( pMem->flags & MEM_Real ){ return pMem->u.r; }else if( pMem->flags & (MEM_Int|MEM_IntReal) ){ testcase( pMem->flags & MEM_IntReal ); return (double)pMem->u.i; }else if( pMem->flags & (MEM_Str|MEM_Blob) ){ return memRealValue(pMem); }else{ /* (double)0 In case of SQLITE_OMIT_FLOATING_POINT... */ return (double)0; } } /* ** Return 1 if pMem represents true, and return 0 if pMem represents false. ** Return the value ifNull if pMem is NULL. */ int sqlite3VdbeBooleanValue(Mem *pMem, int ifNull){ testcase( pMem->flags & MEM_IntReal ); if( pMem->flags & (MEM_Int|MEM_IntReal) ) return pMem->u.i!=0; if( pMem->flags & MEM_Null ) return ifNull; return sqlite3VdbeRealValue(pMem)!=0.0; } /* ** The MEM structure is already a MEM_Real. Try to also make it a ** MEM_Int if we can. */ void sqlite3VdbeIntegerAffinity(Mem *pMem){ i64 ix; assert( pMem!=0 ); assert( pMem->flags & MEM_Real ); assert( !sqlite3VdbeMemIsRowSet(pMem) ); assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); assert( EIGHT_BYTE_ALIGNMENT(pMem) ); ix = doubleToInt64(pMem->u.r); |
︙ | ︙ | |||
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 | } } /* ** Convert pMem to type integer. Invalidate any prior representations. */ int sqlite3VdbeMemIntegerify(Mem *pMem){ assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); assert( !sqlite3VdbeMemIsRowSet(pMem) ); assert( EIGHT_BYTE_ALIGNMENT(pMem) ); pMem->u.i = sqlite3VdbeIntValue(pMem); MemSetTypeFlag(pMem, MEM_Int); return SQLITE_OK; } /* ** Convert pMem so that it is of type MEM_Real. ** Invalidate any prior representations. */ int sqlite3VdbeMemRealify(Mem *pMem){ assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); assert( EIGHT_BYTE_ALIGNMENT(pMem) ); pMem->u.r = sqlite3VdbeRealValue(pMem); MemSetTypeFlag(pMem, MEM_Real); return SQLITE_OK; } /* Compare a floating point value to an integer. Return true if the two ** values are the same within the precision of the floating point value. ** ** For some versions of GCC on 32-bit machines, if you do the more obvious ** comparison of "r1==(double)i" you sometimes get an answer of false even ** though the r1 and (double)i values are bit-for-bit the same. */ | > > > > | > | > | > > > > > | > < < < < < | > | > | | | | | | < | | | | 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 | } } /* ** Convert pMem to type integer. Invalidate any prior representations. */ int sqlite3VdbeMemIntegerify(Mem *pMem){ assert( pMem!=0 ); assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); assert( !sqlite3VdbeMemIsRowSet(pMem) ); assert( EIGHT_BYTE_ALIGNMENT(pMem) ); pMem->u.i = sqlite3VdbeIntValue(pMem); MemSetTypeFlag(pMem, MEM_Int); return SQLITE_OK; } /* ** Convert pMem so that it is of type MEM_Real. ** Invalidate any prior representations. */ int sqlite3VdbeMemRealify(Mem *pMem){ assert( pMem!=0 ); assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); assert( EIGHT_BYTE_ALIGNMENT(pMem) ); pMem->u.r = sqlite3VdbeRealValue(pMem); MemSetTypeFlag(pMem, MEM_Real); return SQLITE_OK; } /* Compare a floating point value to an integer. Return true if the two ** values are the same within the precision of the floating point value. ** ** This function assumes that i was obtained by assignment from r1. ** ** For some versions of GCC on 32-bit machines, if you do the more obvious ** comparison of "r1==(double)i" you sometimes get an answer of false even ** though the r1 and (double)i values are bit-for-bit the same. */ int sqlite3RealSameAsInt(double r1, sqlite3_int64 i){ double r2 = (double)i; return r1==0.0 || (memcmp(&r1, &r2, sizeof(r1))==0 && i >= -2251799813685248LL && i < 2251799813685248LL); } /* ** Convert pMem so that it has type MEM_Real or MEM_Int. ** Invalidate any prior representations. ** ** Every effort is made to force the conversion, even if the input ** is a string that does not look completely like a number. Convert ** as much of the string as we can and ignore the rest. */ int sqlite3VdbeMemNumerify(Mem *pMem){ assert( pMem!=0 ); testcase( pMem->flags & MEM_Int ); testcase( pMem->flags & MEM_Real ); testcase( pMem->flags & MEM_IntReal ); testcase( pMem->flags & MEM_Null ); if( (pMem->flags & (MEM_Int|MEM_Real|MEM_IntReal|MEM_Null))==0 ){ int rc; sqlite3_int64 ix; assert( (pMem->flags & (MEM_Blob|MEM_Str))!=0 ); assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); rc = sqlite3AtoF(pMem->z, &pMem->u.r, pMem->n, pMem->enc); if( ((rc==0 || rc==1) && sqlite3Atoi64(pMem->z, &ix, pMem->n, pMem->enc)<=1) || sqlite3RealSameAsInt(pMem->u.r, (ix = (i64)pMem->u.r)) ){ pMem->u.i = ix; MemSetTypeFlag(pMem, MEM_Int); }else{ MemSetTypeFlag(pMem, MEM_Real); } } assert( (pMem->flags & (MEM_Int|MEM_Real|MEM_IntReal|MEM_Null))!=0 ); pMem->flags &= ~(MEM_Str|MEM_Blob|MEM_Zero); return SQLITE_OK; } /* ** Cast the datatype of the value in pMem according to the affinity ** "aff". Casting is different from applying affinity in that a cast ** is forced. In other words, the value is converted into the desired ** affinity even if that results in loss of data. This routine is ** used (for example) to implement the SQL "cast()" operator. */ int sqlite3VdbeMemCast(Mem *pMem, u8 aff, u8 encoding){ if( pMem->flags & MEM_Null ) return SQLITE_OK; switch( aff ){ case SQLITE_AFF_BLOB: { /* Really a cast to BLOB */ if( (pMem->flags & MEM_Blob)==0 ){ sqlite3ValueApplyAffinity(pMem, SQLITE_AFF_TEXT, encoding); assert( pMem->flags & MEM_Str || pMem->db->mallocFailed ); if( pMem->flags & MEM_Str ) MemSetTypeFlag(pMem, MEM_Blob); }else{ |
︙ | ︙ | |||
737 738 739 740 741 742 743 | } default: { assert( aff==SQLITE_AFF_TEXT ); assert( MEM_Str==(MEM_Blob>>3) ); pMem->flags |= (pMem->flags&MEM_Blob)>>3; sqlite3ValueApplyAffinity(pMem, SQLITE_AFF_TEXT, encoding); assert( pMem->flags & MEM_Str || pMem->db->mallocFailed ); | | | > | 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 | } default: { assert( aff==SQLITE_AFF_TEXT ); assert( MEM_Str==(MEM_Blob>>3) ); pMem->flags |= (pMem->flags&MEM_Blob)>>3; sqlite3ValueApplyAffinity(pMem, SQLITE_AFF_TEXT, encoding); assert( pMem->flags & MEM_Str || pMem->db->mallocFailed ); pMem->flags &= ~(MEM_Int|MEM_Real|MEM_IntReal|MEM_Blob|MEM_Zero); return sqlite3VdbeChangeEncoding(pMem, encoding); } } return SQLITE_OK; } /* ** Initialize bulk memory to be a consistent Mem object. ** ** The minimum amount of initialization feasible is performed. */ |
︙ | ︙ | |||
783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 | sqlite3VdbeMemSetNull((Mem*)p); } /* ** Delete any previous value and set the value to be a BLOB of length ** n containing all zeros. */ void sqlite3VdbeMemSetZeroBlob(Mem *pMem, int n){ sqlite3VdbeMemRelease(pMem); pMem->flags = MEM_Blob|MEM_Zero; pMem->n = 0; if( n<0 ) n = 0; pMem->u.nZero = n; pMem->enc = SQLITE_UTF8; pMem->z = 0; } /* ** The pMem is known to contain content that needs to be destroyed prior ** to a value change. So invoke the destructor, then set the value to ** a 64-bit integer. */ static SQLITE_NOINLINE void vdbeReleaseAndSetInt64(Mem *pMem, i64 val){ | > > > > > > > > > > > > > > > > | 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 | sqlite3VdbeMemSetNull((Mem*)p); } /* ** Delete any previous value and set the value to be a BLOB of length ** n containing all zeros. */ #ifndef SQLITE_OMIT_INCRBLOB void sqlite3VdbeMemSetZeroBlob(Mem *pMem, int n){ sqlite3VdbeMemRelease(pMem); pMem->flags = MEM_Blob|MEM_Zero; pMem->n = 0; if( n<0 ) n = 0; pMem->u.nZero = n; pMem->enc = SQLITE_UTF8; pMem->z = 0; } #else int sqlite3VdbeMemSetZeroBlob(Mem *pMem, int n){ int nByte = n>0?n:1; if( sqlite3VdbeMemGrow(pMem, nByte, 0) ){ return SQLITE_NOMEM_BKPT; } assert( pMem->z!=0 ); assert( sqlite3DbMallocSize(pMem->db, pMem->z)>=nByte ); memset(pMem->z, 0, nByte); pMem->n = n>0?n:0; pMem->flags = MEM_Blob; pMem->enc = SQLITE_UTF8; return SQLITE_OK; } #endif /* ** The pMem is known to contain content that needs to be destroyed prior ** to a value change. So invoke the destructor, then set the value to ** a 64-bit integer. */ static SQLITE_NOINLINE void vdbeReleaseAndSetInt64(Mem *pMem, i64 val){ |
︙ | ︙ | |||
906 907 908 909 910 911 912 | #ifdef SQLITE_DEBUG /* ** This routine prepares a memory cell for modification by breaking ** its link to a shallow copy and by marking any current shallow ** copies of this cell as invalid. ** | | | | > > > > > | | | < < < < | 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 | #ifdef SQLITE_DEBUG /* ** This routine prepares a memory cell for modification by breaking ** its link to a shallow copy and by marking any current shallow ** copies of this cell as invalid. ** ** This is used for testing and debugging only - to help ensure that shallow ** copies (created by OP_SCopy) are not misused. */ void sqlite3VdbeMemAboutToChange(Vdbe *pVdbe, Mem *pMem){ int i; Mem *pX; for(i=1, pX=pVdbe->aMem+1; i<pVdbe->nMem; i++, pX++){ if( pX->pScopyFrom==pMem ){ u16 mFlags; if( pVdbe->db->flags & SQLITE_VdbeTrace ){ sqlite3DebugPrintf("Invalidate R[%d] due to change in R[%d]\n", (int)(pX - pVdbe->aMem), (int)(pMem - pVdbe->aMem)); } /* If pX is marked as a shallow copy of pMem, then try to verify that ** no significant changes have been made to pX since the OP_SCopy. ** A significant change would indicated a missed call to this ** function for pX. Minor changes, such as adding or removing a ** dual type, are allowed, as long as the underlying value is the ** same. */ mFlags = pMem->flags & pX->flags & pX->mScopyFlags; assert( (mFlags&(MEM_Int|MEM_IntReal))==0 || pMem->u.i==pX->u.i ); /* pMem is the register that is changing. But also mark pX as ** undefined so that we can quickly detect the shallow-copy error */ pX->flags = MEM_Undefined; pX->pScopyFrom = 0; } } pMem->pScopyFrom = 0; } #endif /* SQLITE_DEBUG */ /* ** Make an shallow copy of pFrom into pTo. Prior contents of ** pTo are freed. The pFrom->z field is not duplicated. If ** pFrom->z is used, then pTo->z points to the same thing as pFrom->z ** and flags gets srcType (either MEM_Ephem or MEM_Static). */ |
︙ | ︙ | |||
1016 1017 1018 1019 1020 1021 1022 | ** stored without allocating memory, then it is. If a memory allocation ** is required to store the string, then value of pMem is unchanged. In ** either case, SQLITE_TOOBIG is returned. */ int sqlite3VdbeMemSetStr( Mem *pMem, /* Memory cell to set to string value */ const char *z, /* String pointer */ | | | > | < | | | < < < < > > > > | | | | > | > | > > > > > > > | > | | | > > > | < < | | | < | | 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 | ** stored without allocating memory, then it is. If a memory allocation ** is required to store the string, then value of pMem is unchanged. In ** either case, SQLITE_TOOBIG is returned. */ int sqlite3VdbeMemSetStr( Mem *pMem, /* Memory cell to set to string value */ const char *z, /* String pointer */ i64 n, /* Bytes in string, or negative */ u8 enc, /* Encoding of z. 0 for BLOBs */ void (*xDel)(void*) /* Destructor function */ ){ i64 nByte = n; /* New value for pMem->n */ int iLimit; /* Maximum allowed string or blob size */ u16 flags = 0; /* New value for pMem->flags */ assert( pMem!=0 ); assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); assert( !sqlite3VdbeMemIsRowSet(pMem) ); /* If z is a NULL pointer, set pMem to contain an SQL NULL. */ if( !z ){ sqlite3VdbeMemSetNull(pMem); return SQLITE_OK; } if( pMem->db ){ iLimit = pMem->db->aLimit[SQLITE_LIMIT_LENGTH]; }else{ iLimit = SQLITE_MAX_LENGTH; } flags = (enc==0?MEM_Blob:MEM_Str); if( nByte<0 ){ assert( enc!=0 ); if( enc==SQLITE_UTF8 ){ nByte = strlen(z); }else{ for(nByte=0; nByte<=iLimit && (z[nByte] | z[nByte+1]); nByte+=2){} } flags |= MEM_Term; } /* The following block sets the new values of Mem.z and Mem.xDel. It ** also sets a flag in local variable "flags" to indicate the memory ** management (one of MEM_Dyn or MEM_Static). */ if( xDel==SQLITE_TRANSIENT ){ i64 nAlloc = nByte; if( flags&MEM_Term ){ nAlloc += (enc==SQLITE_UTF8?1:2); } if( nByte>iLimit ){ return sqlite3ErrorToParser(pMem->db, SQLITE_TOOBIG); } testcase( nAlloc==0 ); testcase( nAlloc==31 ); testcase( nAlloc==32 ); if( sqlite3VdbeMemClearAndResize(pMem, (int)MAX(nAlloc,32)) ){ return SQLITE_NOMEM_BKPT; } memcpy(pMem->z, z, nAlloc); }else{ sqlite3VdbeMemRelease(pMem); pMem->z = (char *)z; if( xDel==SQLITE_DYNAMIC ){ pMem->zMalloc = pMem->z; pMem->szMalloc = sqlite3DbMallocSize(pMem->db, pMem->zMalloc); }else{ pMem->xDel = xDel; flags |= ((xDel==SQLITE_STATIC)?MEM_Static:MEM_Dyn); } } pMem->n = (int)(nByte & 0x7fffffff); pMem->flags = flags; if( enc ){ pMem->enc = enc; #ifdef SQLITE_ENABLE_SESSION }else if( pMem->db==0 ){ pMem->enc = SQLITE_UTF8; #endif }else{ assert( pMem->db!=0 ); pMem->enc = ENC(pMem->db); } #ifndef SQLITE_OMIT_UTF16 if( enc>SQLITE_UTF8 && sqlite3VdbeMemHandleBom(pMem) ){ return SQLITE_NOMEM_BKPT; } #endif if( nByte>iLimit ){ return sqlite3ErrorToParser(pMem->db, SQLITE_TOOBIG); } return SQLITE_OK; } /* ** Move data out of a btree key or data field and into a Mem structure. ** The data is payload from the entry that pCur is currently pointing ** to. offset and amt determine what portion of the data or key to retrieve. ** The result is written into the pMem element. ** ** The pMem object must have been initialized. This routine will use ** pMem->zMalloc to hold the content from the btree, if possible. New ** pMem->zMalloc space will be allocated if necessary. The calling routine ** is responsible for making sure that the pMem object is eventually ** destroyed. ** ** If this routine fails for any reason (malloc returns NULL or unable ** to read from the disk) then the pMem is left in an inconsistent state. */ int sqlite3VdbeMemFromBtree( BtCursor *pCur, /* Cursor pointing at record to retrieve. */ u32 offset, /* Offset from the start of data to return bytes from. */ u32 amt, /* Number of bytes to return. */ Mem *pMem /* OUT: Return data in this Mem structure. */ ){ int rc; pMem->flags = MEM_Null; if( sqlite3BtreeMaxRecordSize(pCur)<offset+amt ){ return SQLITE_CORRUPT_BKPT; } if( SQLITE_OK==(rc = sqlite3VdbeMemClearAndResize(pMem, amt+1)) ){ rc = sqlite3BtreePayload(pCur, offset, amt, pMem->z); if( rc==SQLITE_OK ){ pMem->z[amt] = 0; /* Overrun area used when reading malformed records */ pMem->flags = MEM_Blob; pMem->n = (int)amt; }else{ sqlite3VdbeMemRelease(pMem); } } return rc; } int sqlite3VdbeMemFromBtreeZeroOffset( BtCursor *pCur, /* Cursor pointing at record to retrieve. */ u32 amt, /* Number of bytes to return. */ Mem *pMem /* OUT: Return data in this Mem structure. */ ){ u32 available = 0; /* Number of bytes available on the local btree page */ int rc = SQLITE_OK; /* Return code */ assert( sqlite3BtreeCursorIsValid(pCur) ); assert( !VdbeMemDynamic(pMem) ); /* Note: the calls to BtreeKeyFetch() and DataFetch() below assert() ** that both the BtShared and database handle mutexes are held. */ assert( !sqlite3VdbeMemIsRowSet(pMem) ); pMem->z = (char *)sqlite3BtreePayloadFetch(pCur, &available); assert( pMem->z!=0 ); if( amt<=available ){ pMem->flags = MEM_Blob|MEM_Ephem; pMem->n = (int)amt; }else{ rc = sqlite3VdbeMemFromBtree(pCur, 0, amt, pMem); } return rc; } /* ** The pVal argument is known to be a value other than NULL. |
︙ | ︙ | |||
1193 1194 1195 1196 1197 1198 1199 | }else{ sqlite3VdbeMemStringify(pVal, enc, 0); assert( 0==(1&SQLITE_PTR_TO_INT(pVal->z)) ); } assert(pVal->enc==(enc & ~SQLITE_UTF16_ALIGNED) || pVal->db==0 || pVal->db->mallocFailed ); if( pVal->enc==(enc & ~SQLITE_UTF16_ALIGNED) ){ | | | 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 | }else{ sqlite3VdbeMemStringify(pVal, enc, 0); assert( 0==(1&SQLITE_PTR_TO_INT(pVal->z)) ); } assert(pVal->enc==(enc & ~SQLITE_UTF16_ALIGNED) || pVal->db==0 || pVal->db->mallocFailed ); if( pVal->enc==(enc & ~SQLITE_UTF16_ALIGNED) ){ assert( sqlite3VdbeMemValidStrRep(pVal) ); return pVal->z; }else{ return 0; } } /* This function is only available internally, it is not part of the |
︙ | ︙ | |||
1216 1217 1218 1219 1220 1221 1222 | */ const void *sqlite3ValueText(sqlite3_value* pVal, u8 enc){ if( !pVal ) return 0; assert( pVal->db==0 || sqlite3_mutex_held(pVal->db->mutex) ); assert( (enc&3)==(enc&~SQLITE_UTF16_ALIGNED) ); assert( !sqlite3VdbeMemIsRowSet(pVal) ); if( (pVal->flags&(MEM_Str|MEM_Term))==(MEM_Str|MEM_Term) && pVal->enc==enc ){ | | | 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 | */ const void *sqlite3ValueText(sqlite3_value* pVal, u8 enc){ if( !pVal ) return 0; assert( pVal->db==0 || sqlite3_mutex_held(pVal->db->mutex) ); assert( (enc&3)==(enc&~SQLITE_UTF16_ALIGNED) ); assert( !sqlite3VdbeMemIsRowSet(pVal) ); if( (pVal->flags&(MEM_Str|MEM_Term))==(MEM_Str|MEM_Term) && pVal->enc==enc ){ assert( sqlite3VdbeMemValidStrRep(pVal) ); return pVal->z; } if( pVal->flags&MEM_Null ){ return 0; } return valueToText(pVal, enc); } |
︙ | ︙ | |||
1260 1261 1262 1263 1264 1265 1266 | ** Otherwise, if the second argument is non-zero, then this function is ** being called indirectly by sqlite3Stat4ProbeSetValue(). If it has not ** already been allocated, allocate the UnpackedRecord structure that ** that function will return to its caller here. Then return a pointer to ** an sqlite3_value within the UnpackedRecord.a[] array. */ static sqlite3_value *valueNew(sqlite3 *db, struct ValueNewStat4Ctx *p){ | | | 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 | ** Otherwise, if the second argument is non-zero, then this function is ** being called indirectly by sqlite3Stat4ProbeSetValue(). If it has not ** already been allocated, allocate the UnpackedRecord structure that ** that function will return to its caller here. Then return a pointer to ** an sqlite3_value within the UnpackedRecord.a[] array. */ static sqlite3_value *valueNew(sqlite3 *db, struct ValueNewStat4Ctx *p){ #ifdef SQLITE_ENABLE_STAT4 if( p ){ UnpackedRecord *pRec = p->ppRec[0]; if( pRec==0 ){ Index *pIdx = p->pIdx; /* Index being probed */ int nByte; /* Bytes of space to allocate */ int i; /* Counter variable */ |
︙ | ︙ | |||
1296 1297 1298 1299 1300 1301 1302 | } pRec->nField = p->iVal+1; return &pRec->aMem[p->iVal]; } #else UNUSED_PARAMETER(p); | | | 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 | } pRec->nField = p->iVal+1; return &pRec->aMem[p->iVal]; } #else UNUSED_PARAMETER(p); #endif /* defined(SQLITE_ENABLE_STAT4) */ return sqlite3ValueNew(db); } /* ** The expression object indicated by the second argument is guaranteed ** to be a scalar SQL function. If ** |
︙ | ︙ | |||
1320 1321 1322 1323 1324 1325 1326 | ** If the result is a text value, the sqlite3_value object uses encoding ** enc. ** ** If the conditions above are not met, this function returns SQLITE_OK ** and sets (*ppVal) to NULL. Or, if an error occurs, (*ppVal) is set to ** NULL and an SQLite error code returned. */ | | | > > | 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 | ** If the result is a text value, the sqlite3_value object uses encoding ** enc. ** ** If the conditions above are not met, this function returns SQLITE_OK ** and sets (*ppVal) to NULL. Or, if an error occurs, (*ppVal) is set to ** NULL and an SQLite error code returned. */ #ifdef SQLITE_ENABLE_STAT4 static int valueFromFunction( sqlite3 *db, /* The database connection */ const Expr *p, /* The expression to evaluate */ u8 enc, /* Encoding to use */ u8 aff, /* Affinity to use */ sqlite3_value **ppVal, /* Write the new value here */ struct ValueNewStat4Ctx *pCtx /* Second argument for valueNew() */ ){ sqlite3_context ctx; /* Context object for function invocation */ sqlite3_value **apVal = 0; /* Function arguments */ int nVal = 0; /* Size of apVal[] array */ FuncDef *pFunc = 0; /* Function definition */ sqlite3_value *pVal = 0; /* New value */ int rc = SQLITE_OK; /* Return code */ ExprList *pList = 0; /* Function arguments */ int i; /* Iterator variable */ assert( pCtx!=0 ); assert( (p->flags & EP_TokenOnly)==0 ); assert( ExprUseXList(p) ); pList = p->x.pList; if( pList ) nVal = pList->nExpr; assert( !ExprHasProperty(p, EP_IntValue) ); pFunc = sqlite3FindFunction(db, p->u.zToken, nVal, enc, 0); assert( pFunc ); if( (pFunc->funcFlags & (SQLITE_FUNC_CONSTANT|SQLITE_FUNC_SLOCHNG))==0 || (pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL) ){ return SQLITE_OK; } |
︙ | ︙ | |||
1403 1404 1405 1406 1407 1408 1409 | } *ppVal = pVal; return rc; } #else # define valueFromFunction(a,b,c,d,e,f) SQLITE_OK | | | | > > | | 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 | } *ppVal = pVal; return rc; } #else # define valueFromFunction(a,b,c,d,e,f) SQLITE_OK #endif /* defined(SQLITE_ENABLE_STAT4) */ /* ** Extract a value from the supplied expression in the manner described ** above sqlite3ValueFromExpr(). Allocate the sqlite3_value object ** using valueNew(). ** ** If pCtx is NULL and an error occurs after the sqlite3_value object ** has been allocated, it is freed before returning. Or, if pCtx is not ** NULL, it is assumed that the caller will free any allocated object ** in all cases. */ static int valueFromExpr( sqlite3 *db, /* The database connection */ const Expr *pExpr, /* The expression to evaluate */ u8 enc, /* Encoding to use */ u8 affinity, /* Affinity to use */ sqlite3_value **ppVal, /* Write the new value here */ struct ValueNewStat4Ctx *pCtx /* Second argument for valueNew() */ ){ int op; char *zVal = 0; sqlite3_value *pVal = 0; int negInt = 1; const char *zNeg = ""; int rc = SQLITE_OK; assert( pExpr!=0 ); while( (op = pExpr->op)==TK_UPLUS || op==TK_SPAN ) pExpr = pExpr->pLeft; #if defined(SQLITE_ENABLE_STAT4) if( op==TK_REGISTER ) op = pExpr->op2; #else if( NEVER(op==TK_REGISTER) ) op = pExpr->op2; #endif /* Compressed expressions only appear when parsing the DEFAULT clause ** on a table column definition, and hence only when pCtx==0. This ** check ensures that an EP_TokenOnly expression is never passed down ** into valueFromFunction(). */ assert( (pExpr->flags & EP_TokenOnly)==0 || pCtx==0 ); if( op==TK_CAST ){ u8 aff; assert( !ExprHasProperty(pExpr, EP_IntValue) ); aff = sqlite3AffinityType(pExpr->u.zToken,0); rc = valueFromExpr(db, pExpr->pLeft, enc, aff, ppVal, pCtx); testcase( rc!=SQLITE_OK ); if( *ppVal ){ sqlite3VdbeMemCast(*ppVal, aff, SQLITE_UTF8); sqlite3ValueApplyAffinity(*ppVal, affinity, SQLITE_UTF8); } return rc; |
︙ | ︙ | |||
1481 1482 1483 1484 1485 1486 1487 | sqlite3ValueSetStr(pVal, -1, zVal, SQLITE_UTF8, SQLITE_DYNAMIC); } if( (op==TK_INTEGER || op==TK_FLOAT ) && affinity==SQLITE_AFF_BLOB ){ sqlite3ValueApplyAffinity(pVal, SQLITE_AFF_NUMERIC, SQLITE_UTF8); }else{ sqlite3ValueApplyAffinity(pVal, affinity, SQLITE_UTF8); } | > | > > > > > > > > | > | > | > | | > | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 | sqlite3ValueSetStr(pVal, -1, zVal, SQLITE_UTF8, SQLITE_DYNAMIC); } if( (op==TK_INTEGER || op==TK_FLOAT ) && affinity==SQLITE_AFF_BLOB ){ sqlite3ValueApplyAffinity(pVal, SQLITE_AFF_NUMERIC, SQLITE_UTF8); }else{ sqlite3ValueApplyAffinity(pVal, affinity, SQLITE_UTF8); } assert( (pVal->flags & MEM_IntReal)==0 ); if( pVal->flags & (MEM_Int|MEM_IntReal|MEM_Real) ){ testcase( pVal->flags & MEM_Int ); testcase( pVal->flags & MEM_Real ); pVal->flags &= ~MEM_Str; } if( enc!=SQLITE_UTF8 ){ rc = sqlite3VdbeChangeEncoding(pVal, enc); } }else if( op==TK_UMINUS ) { /* This branch happens for multiple negative signs. Ex: -(-5) */ if( SQLITE_OK==valueFromExpr(db,pExpr->pLeft,enc,affinity,&pVal,pCtx) && pVal!=0 ){ sqlite3VdbeMemNumerify(pVal); if( pVal->flags & MEM_Real ){ pVal->u.r = -pVal->u.r; }else if( pVal->u.i==SMALLEST_INT64 ){ #ifndef SQLITE_OMIT_FLOATING_POINT pVal->u.r = -(double)SMALLEST_INT64; #else pVal->u.r = LARGEST_INT64; #endif MemSetTypeFlag(pVal, MEM_Real); }else{ pVal->u.i = -pVal->u.i; } sqlite3ValueApplyAffinity(pVal, affinity, enc); } }else if( op==TK_NULL ){ pVal = valueNew(db, pCtx); if( pVal==0 ) goto no_mem; sqlite3VdbeMemSetNull(pVal); } #ifndef SQLITE_OMIT_BLOB_LITERAL else if( op==TK_BLOB ){ int nVal; assert( !ExprHasProperty(pExpr, EP_IntValue) ); assert( pExpr->u.zToken[0]=='x' || pExpr->u.zToken[0]=='X' ); assert( pExpr->u.zToken[1]=='\'' ); pVal = valueNew(db, pCtx); if( !pVal ) goto no_mem; zVal = &pExpr->u.zToken[2]; nVal = sqlite3Strlen30(zVal)-1; assert( zVal[nVal]=='\'' ); sqlite3VdbeMemSetStr(pVal, sqlite3HexToBlob(db, zVal, nVal), nVal/2, 0, SQLITE_DYNAMIC); } #endif #ifdef SQLITE_ENABLE_STAT4 else if( op==TK_FUNCTION && pCtx!=0 ){ rc = valueFromFunction(db, pExpr, enc, affinity, &pVal, pCtx); } #endif else if( op==TK_TRUEFALSE ){ assert( !ExprHasProperty(pExpr, EP_IntValue) ); pVal = valueNew(db, pCtx); if( pVal ){ pVal->flags = MEM_Int; pVal->u.i = pExpr->u.zToken[4]==0; } } *ppVal = pVal; return rc; no_mem: #ifdef SQLITE_ENABLE_STAT4 if( pCtx==0 || pCtx->pParse->nErr==0 ) #endif sqlite3OomFault(db); sqlite3DbFree(db, zVal); assert( *ppVal==0 ); #ifdef SQLITE_ENABLE_STAT4 if( pCtx==0 ) sqlite3ValueFree(pVal); #else assert( pCtx==0 ); sqlite3ValueFree(pVal); #endif return SQLITE_NOMEM_BKPT; } /* ** Create a new sqlite3_value object, containing the value of pExpr. ** ** This only works for very simple expressions that consist of one constant ** token (i.e. "5", "5.1", "'a string'"). If the expression can ** be converted directly into a value, then the value is allocated and ** a pointer written to *ppVal. The caller is responsible for deallocating ** the value by passing it to sqlite3ValueFree() later on. If the expression ** cannot be converted to a value, then *ppVal is set to NULL. */ int sqlite3ValueFromExpr( sqlite3 *db, /* The database connection */ const Expr *pExpr, /* The expression to evaluate */ u8 enc, /* Encoding to use */ u8 affinity, /* Affinity to use */ sqlite3_value **ppVal /* Write the new value here */ ){ return pExpr ? valueFromExpr(db, pExpr, enc, affinity, ppVal, 0) : 0; } #ifdef SQLITE_ENABLE_STAT4 /* ** Attempt to extract a value from pExpr and use it to construct *ppVal. ** ** If pAlloc is not NULL, then an UnpackedRecord object is created for ** pAlloc if one does not exist and the new value is added to the ** UnpackedRecord object. ** |
︙ | ︙ |
Changes to src/vdbesort.c.
︙ | ︙ | |||
533 534 535 536 537 538 539 | ** In this case, allocate space at p->aAlloc[] to copy the requested ** range into. Then return a copy of pointer p->aAlloc to the caller. */ int nRem; /* Bytes remaining to copy */ /* Extend the p->aAlloc[] allocation if required. */ if( p->nAlloc<nByte ){ u8 *aNew; | | | 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 | ** In this case, allocate space at p->aAlloc[] to copy the requested ** range into. Then return a copy of pointer p->aAlloc to the caller. */ int nRem; /* Bytes remaining to copy */ /* Extend the p->aAlloc[] allocation if required. */ if( p->nAlloc<nByte ){ u8 *aNew; sqlite3_int64 nNew = MAX(128, 2*(sqlite3_int64)p->nAlloc); while( nByte>nNew ) nNew = nNew*2; aNew = sqlite3Realloc(p->aAlloc, nNew); if( !aNew ) return SQLITE_NOMEM_BKPT; p->nAlloc = nNew; p->aAlloc = aNew; } |
︙ | ︙ | |||
811 812 813 814 815 816 817 | const u8 * const v1 = &p1[ p1[0] ]; /* Pointer to value 1 */ const u8 * const v2 = &p2[ p2[0] ]; /* Pointer to value 2 */ int n1; int n2; int res; | | | > | | 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 | const u8 * const v1 = &p1[ p1[0] ]; /* Pointer to value 1 */ const u8 * const v2 = &p2[ p2[0] ]; /* Pointer to value 2 */ int n1; int n2; int res; getVarint32NR(&p1[1], n1); getVarint32NR(&p2[1], n2); res = memcmp(v1, v2, (MIN(n1, n2) - 13)/2); if( res==0 ){ res = n1 - n2; } if( res==0 ){ if( pTask->pSorter->pKeyInfo->nKeyField>1 ){ res = vdbeSorterCompareTail( pTask, pbKey2Cached, pKey1, nKey1, pKey2, nKey2 ); } }else{ assert( !(pTask->pSorter->pKeyInfo->aSortFlags[0]&KEYINFO_ORDER_BIGNULL) ); if( pTask->pSorter->pKeyInfo->aSortFlags[0] ){ res = res * -1; } } return res; } |
︙ | ︙ | |||
893 894 895 896 897 898 899 | if( res==0 ){ if( pTask->pSorter->pKeyInfo->nKeyField>1 ){ res = vdbeSorterCompareTail( pTask, pbKey2Cached, pKey1, nKey1, pKey2, nKey2 ); } | | > | 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 | if( res==0 ){ if( pTask->pSorter->pKeyInfo->nKeyField>1 ){ res = vdbeSorterCompareTail( pTask, pbKey2Cached, pKey1, nKey1, pKey2, nKey2 ); } }else if( pTask->pSorter->pKeyInfo->aSortFlags[0] ){ assert( !(pTask->pSorter->pKeyInfo->aSortFlags[0]&KEYINFO_ORDER_BIGNULL) ); res = res * -1; } return res; } /* |
︙ | ︙ | |||
964 965 966 967 968 969 970 971 972 973 974 975 976 | sz = sizeof(VdbeSorter) + nWorker * sizeof(SortSubtask); pSorter = (VdbeSorter*)sqlite3DbMallocZero(db, sz + szKeyInfo); pCsr->uc.pSorter = pSorter; if( pSorter==0 ){ rc = SQLITE_NOMEM_BKPT; }else{ pSorter->pKeyInfo = pKeyInfo = (KeyInfo*)((u8*)pSorter + sz); memcpy(pKeyInfo, pCsr->pKeyInfo, szKeyInfo); pKeyInfo->db = 0; if( nField && nWorker==0 ){ pKeyInfo->nKeyField = nField; } | > > | > | 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 | sz = sizeof(VdbeSorter) + nWorker * sizeof(SortSubtask); pSorter = (VdbeSorter*)sqlite3DbMallocZero(db, sz + szKeyInfo); pCsr->uc.pSorter = pSorter; if( pSorter==0 ){ rc = SQLITE_NOMEM_BKPT; }else{ Btree *pBt = db->aDb[0].pBt; pSorter->pKeyInfo = pKeyInfo = (KeyInfo*)((u8*)pSorter + sz); memcpy(pKeyInfo, pCsr->pKeyInfo, szKeyInfo); pKeyInfo->db = 0; if( nField && nWorker==0 ){ pKeyInfo->nKeyField = nField; } sqlite3BtreeEnter(pBt); pSorter->pgsz = pgsz = sqlite3BtreeGetPageSize(pBt); sqlite3BtreeLeave(pBt); pSorter->nTask = nWorker + 1; pSorter->iPrev = (u8)(nWorker - 1); pSorter->bUseThreads = (pSorter->nTask>1); pSorter->db = db; for(i=0; i<pSorter->nTask; i++){ SortSubtask *pTask = &pSorter->aTask[i]; pTask->pSorter = pSorter; |
︙ | ︙ | |||
1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 | pSorter->list.aMemory = (u8*)sqlite3Malloc(pgsz); if( !pSorter->list.aMemory ) rc = SQLITE_NOMEM_BKPT; } } if( pKeyInfo->nAllField<13 && (pKeyInfo->aColl[0]==0 || pKeyInfo->aColl[0]==db->pDfltColl) ){ pSorter->typeMask = SORTER_TYPE_INTEGER | SORTER_TYPE_TEXT; } } return rc; } | > | 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 | pSorter->list.aMemory = (u8*)sqlite3Malloc(pgsz); if( !pSorter->list.aMemory ) rc = SQLITE_NOMEM_BKPT; } } if( pKeyInfo->nAllField<13 && (pKeyInfo->aColl[0]==0 || pKeyInfo->aColl[0]==db->pDfltColl) && (pKeyInfo->aSortFlags[0] & KEYINFO_ORDER_BIGNULL)==0 ){ pSorter->typeMask = SORTER_TYPE_INTEGER | SORTER_TYPE_TEXT; } } return rc; } |
︙ | ︙ | |||
1063 1064 1065 1066 1067 1068 1069 | static void vdbeSorterWorkDebug(SortSubtask *pTask, const char *zEvent){ i64 t; int iTask = (pTask - pTask->pSorter->aTask); sqlite3OsCurrentTimeInt64(pTask->pSorter->db->pVfs, &t); fprintf(stderr, "%lld:%d %s\n", t, iTask, zEvent); } static void vdbeSorterRewindDebug(const char *zEvent){ | | > | | 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 | static void vdbeSorterWorkDebug(SortSubtask *pTask, const char *zEvent){ i64 t; int iTask = (pTask - pTask->pSorter->aTask); sqlite3OsCurrentTimeInt64(pTask->pSorter->db->pVfs, &t); fprintf(stderr, "%lld:%d %s\n", t, iTask, zEvent); } static void vdbeSorterRewindDebug(const char *zEvent){ i64 t = 0; sqlite3_vfs *pVfs = sqlite3_vfs_find(0); if( ALWAYS(pVfs) ) sqlite3OsCurrentTimeInt64(pVfs, &t); fprintf(stderr, "%lld:X %s\n", t, zEvent); } static void vdbeSorterPopulateDebug( SortSubtask *pTask, const char *zEvent ){ i64 t; |
︙ | ︙ | |||
1278 1279 1280 1281 1282 1283 1284 | static void vdbeSorterExtendFile(sqlite3 *db, sqlite3_file *pFd, i64 nByte){ if( nByte<=(i64)(db->nMaxSorterMmap) && pFd->pMethods->iVersion>=3 ){ void *p = 0; int chunksize = 4*1024; sqlite3OsFileControlHint(pFd, SQLITE_FCNTL_CHUNK_SIZE, &chunksize); sqlite3OsFileControlHint(pFd, SQLITE_FCNTL_SIZE_HINT, &nByte); sqlite3OsFetch(pFd, 0, (int)nByte, &p); | | | 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 | static void vdbeSorterExtendFile(sqlite3 *db, sqlite3_file *pFd, i64 nByte){ if( nByte<=(i64)(db->nMaxSorterMmap) && pFd->pMethods->iVersion>=3 ){ void *p = 0; int chunksize = 4*1024; sqlite3OsFileControlHint(pFd, SQLITE_FCNTL_CHUNK_SIZE, &chunksize); sqlite3OsFileControlHint(pFd, SQLITE_FCNTL_SIZE_HINT, &nByte); sqlite3OsFetch(pFd, 0, (int)nByte, &p); if( p ) sqlite3OsUnfetch(pFd, 0, p); } } #else # define vdbeSorterExtendFile(x,y,z) #endif /* |
︙ | ︙ | |||
1389 1390 1391 1392 1393 1394 1395 | /* ** Sort the linked list of records headed at pTask->pList. Return ** SQLITE_OK if successful, or an SQLite error code (i.e. SQLITE_NOMEM) if ** an error occurs. */ static int vdbeSorterSort(SortSubtask *pTask, SorterList *pList){ int i; | < > | < < < < | 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 | /* ** Sort the linked list of records headed at pTask->pList. Return ** SQLITE_OK if successful, or an SQLite error code (i.e. SQLITE_NOMEM) if ** an error occurs. */ static int vdbeSorterSort(SortSubtask *pTask, SorterList *pList){ int i; SorterRecord *p; int rc; SorterRecord *aSlot[64]; rc = vdbeSortAllocUnpacked(pTask); if( rc!=SQLITE_OK ) return rc; p = pList->pList; pTask->xCompare = vdbeSorterGetCompare(pTask->pSorter); memset(aSlot, 0, sizeof(aSlot)); while( p ){ SorterRecord *pNext; if( pList->aMemory ){ if( (u8*)p==pList->aMemory ){ pNext = 0; }else{ |
︙ | ︙ | |||
1427 1428 1429 1430 1431 1432 1433 | aSlot[i] = 0; } aSlot[i] = p; p = pNext; } p = 0; | | < | 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 | aSlot[i] = 0; } aSlot[i] = p; p = pNext; } p = 0; for(i=0; i<ArraySize(aSlot); i++){ if( aSlot[i]==0 ) continue; p = p ? vdbeSorterMerge(pTask, p, aSlot[i]) : aSlot[i]; } pList->pList = p; assert( pTask->pUnpacked->errCode==SQLITE_OK || pTask->pUnpacked->errCode==SQLITE_NOMEM ); return pTask->pUnpacked->errCode; } /* |
︙ | ︙ | |||
1724 1725 1726 1727 1728 1729 1730 | if( rc==SQLITE_OK ){ if( i==nWorker ){ /* Use the foreground thread for this operation */ rc = vdbeSorterListToPMA(&pSorter->aTask[nWorker], &pSorter->list); }else{ /* Launch a background thread for this operation */ | | | > > > | 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 | if( rc==SQLITE_OK ){ if( i==nWorker ){ /* Use the foreground thread for this operation */ rc = vdbeSorterListToPMA(&pSorter->aTask[nWorker], &pSorter->list); }else{ /* Launch a background thread for this operation */ u8 *aMem; void *pCtx; assert( pTask!=0 ); assert( pTask->pThread==0 && pTask->bDone==0 ); assert( pTask->list.pList==0 ); assert( pTask->list.aMemory==0 || pSorter->list.aMemory!=0 ); aMem = pTask->list.aMemory; pCtx = (void*)pTask; pSorter->iPrev = (u8)(pTask - pSorter->aTask); pTask->list = pSorter->list; pSorter->list.pList = 0; pSorter->list.szPMA = 0; if( aMem ){ pSorter->list.aMemory = aMem; pSorter->nMemory = sqlite3MallocSize(aMem); |
︙ | ︙ | |||
1768 1769 1770 1771 1772 1773 1774 | int bFlush; /* True to flush contents of memory to PMA */ int nReq; /* Bytes of memory required */ int nPMA; /* Bytes of PMA space required */ int t; /* serial type of first record field */ assert( pCsr->eCurType==CURTYPE_SORTER ); pSorter = pCsr->uc.pSorter; | | | 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 | int bFlush; /* True to flush contents of memory to PMA */ int nReq; /* Bytes of memory required */ int nPMA; /* Bytes of PMA space required */ int t; /* serial type of first record field */ assert( pCsr->eCurType==CURTYPE_SORTER ); pSorter = pCsr->uc.pSorter; getVarint32NR((const u8*)&pVal->z[1], t); if( t>0 && t<10 && t!=7 ){ pSorter->typeMask &= SORTER_TYPE_INTEGER; }else if( t>10 && (t & 0x01) ){ pSorter->typeMask &= SORTER_TYPE_TEXT; }else{ pSorter->typeMask = 0; } |
︙ | ︙ | |||
1824 1825 1826 1827 1828 1829 1830 | } if( pSorter->list.aMemory ){ int nMin = pSorter->iMemory + nReq; if( nMin>pSorter->nMemory ){ u8 *aNew; | > > > | < > < > | > | 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 | } if( pSorter->list.aMemory ){ int nMin = pSorter->iMemory + nReq; if( nMin>pSorter->nMemory ){ u8 *aNew; sqlite3_int64 nNew = 2 * (sqlite3_int64)pSorter->nMemory; int iListOff = -1; if( pSorter->list.pList ){ iListOff = (u8*)pSorter->list.pList - pSorter->list.aMemory; } while( nNew < nMin ) nNew = nNew*2; if( nNew > pSorter->mxPmaSize ) nNew = pSorter->mxPmaSize; if( nNew < nMin ) nNew = nMin; aNew = sqlite3Realloc(pSorter->list.aMemory, nNew); if( !aNew ) return SQLITE_NOMEM_BKPT; if( iListOff>=0 ){ pSorter->list.pList = (SorterRecord*)&aNew[iListOff]; } pSorter->list.aMemory = aNew; pSorter->nMemory = nNew; } pNew = (SorterRecord*)&pSorter->list.aMemory[pSorter->iMemory]; pSorter->iMemory += ROUND8(nReq); if( pSorter->list.pList ){ |
︙ | ︙ | |||
1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 | pIncr->pTask = pTask; pIncr->mxSz = MAX(pTask->pSorter->mxKeysize+9,pTask->pSorter->mxPmaSize/2); pTask->file2.iEof += pIncr->mxSz; }else{ vdbeMergeEngineFree(pMerger); rc = SQLITE_NOMEM_BKPT; } return rc; } #if SQLITE_MAX_WORKER_THREADS>0 /* ** Set the "use-threads" flag on object pIncr. */ | > | 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 | pIncr->pTask = pTask; pIncr->mxSz = MAX(pTask->pSorter->mxKeysize+9,pTask->pSorter->mxPmaSize/2); pTask->file2.iEof += pIncr->mxSz; }else{ vdbeMergeEngineFree(pMerger); rc = SQLITE_NOMEM_BKPT; } assert( *ppOut!=0 || rc!=SQLITE_OK ); return rc; } #if SQLITE_MAX_WORKER_THREADS>0 /* ** Set the "use-threads" flag on object pIncr. */ |
︙ | ︙ |
Changes to src/vdbetrace.c.
︙ | ︙ | |||
80 81 82 83 84 85 86 | int nToken; /* Length of the parameter token */ int i; /* Loop counter */ Mem *pVar; /* Value of a host parameter */ StrAccum out; /* Accumulate the output here */ #ifndef SQLITE_OMIT_UTF16 Mem utf8; /* Used to convert UTF16 into UTF8 for display */ #endif | < | < | 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 | int nToken; /* Length of the parameter token */ int i; /* Loop counter */ Mem *pVar; /* Value of a host parameter */ StrAccum out; /* Accumulate the output here */ #ifndef SQLITE_OMIT_UTF16 Mem utf8; /* Used to convert UTF16 into UTF8 for display */ #endif db = p->db; sqlite3StrAccumInit(&out, 0, 0, 0, db->aLimit[SQLITE_LIMIT_LENGTH]); if( db->nVdbeExec>1 ){ while( *zRawSql ){ const char *zStart = zRawSql; while( *(zRawSql++)!='\n' && *zRawSql ); sqlite3_str_append(&out, "-- ", 3); assert( (zRawSql - zStart) > 0 ); sqlite3_str_append(&out, zStart, (int)(zRawSql-zStart)); |
︙ | ︙ | |||
121 122 123 124 125 126 127 | testcase( zRawSql[0]=='$' ); testcase( zRawSql[0]=='@' ); testcase( zRawSql[0]=='#' ); idx = sqlite3VdbeParameterIndex(p, zRawSql, nToken); assert( idx>0 ); } zRawSql += nToken; | | | | 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 | testcase( zRawSql[0]=='$' ); testcase( zRawSql[0]=='@' ); testcase( zRawSql[0]=='#' ); idx = sqlite3VdbeParameterIndex(p, zRawSql, nToken); assert( idx>0 ); } zRawSql += nToken; nextIndex = MAX(idx + 1, nextIndex); assert( idx>0 && idx<=p->nVar ); pVar = &p->aVar[idx-1]; if( pVar->flags & MEM_Null ){ sqlite3_str_append(&out, "NULL", 4); }else if( pVar->flags & (MEM_Int|MEM_IntReal) ){ sqlite3_str_appendf(&out, "%lld", pVar->u.i); }else if( pVar->flags & MEM_Real ){ sqlite3_str_appendf(&out, "%!.15g", pVar->u.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); |
︙ | ︙ |
Added src/vdbevtab.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 | /* ** 2020-03-23 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** ** This file implements virtual-tables for examining the bytecode content ** of a prepared statement. */ #include "sqliteInt.h" #if defined(SQLITE_ENABLE_BYTECODE_VTAB) && !defined(SQLITE_OMIT_VIRTUALTABLE) #include "vdbeInt.h" /* An instance of the bytecode() table-valued function. */ typedef struct bytecodevtab bytecodevtab; struct bytecodevtab { sqlite3_vtab base; /* Base class - must be first */ sqlite3 *db; /* Database connection */ int bTablesUsed; /* 2 for tables_used(). 0 for bytecode(). */ }; /* A cursor for scanning through the bytecode */ typedef struct bytecodevtab_cursor bytecodevtab_cursor; struct bytecodevtab_cursor { sqlite3_vtab_cursor base; /* Base class - must be first */ sqlite3_stmt *pStmt; /* The statement whose bytecode is displayed */ int iRowid; /* The rowid of the output table */ int iAddr; /* Address */ int needFinalize; /* Cursors owns pStmt and must finalize it */ int showSubprograms; /* Provide a listing of subprograms */ Op *aOp; /* Operand array */ char *zP4; /* Rendered P4 value */ const char *zType; /* tables_used.type */ const char *zSchema; /* tables_used.schema */ const char *zName; /* tables_used.name */ Mem sub; /* Subprograms */ }; /* ** Create a new bytecode() table-valued function. */ static int bytecodevtabConnect( sqlite3 *db, void *pAux, int argc, const char *const*argv, sqlite3_vtab **ppVtab, char **pzErr ){ bytecodevtab *pNew; int rc; int isTabUsed = pAux!=0; const char *azSchema[2] = { /* bytecode() schema */ "CREATE TABLE x(" "addr INT," "opcode TEXT," "p1 INT," "p2 INT," "p3 INT," "p4 TEXT," "p5 INT," "comment TEXT," "subprog TEXT," "stmt HIDDEN" ");", /* Tables_used() schema */ "CREATE TABLE x(" "type TEXT," "schema TEXT," "name TEXT," "wr INT," "subprog TEXT," "stmt HIDDEN" ");" }; rc = sqlite3_declare_vtab(db, azSchema[isTabUsed]); if( rc==SQLITE_OK ){ pNew = sqlite3_malloc( sizeof(*pNew) ); *ppVtab = (sqlite3_vtab*)pNew; if( pNew==0 ) return SQLITE_NOMEM; memset(pNew, 0, sizeof(*pNew)); pNew->db = db; pNew->bTablesUsed = isTabUsed*2; } return rc; } /* ** This method is the destructor for bytecodevtab objects. */ static int bytecodevtabDisconnect(sqlite3_vtab *pVtab){ bytecodevtab *p = (bytecodevtab*)pVtab; sqlite3_free(p); return SQLITE_OK; } /* ** Constructor for a new bytecodevtab_cursor object. */ static int bytecodevtabOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){ bytecodevtab *pVTab = (bytecodevtab*)p; bytecodevtab_cursor *pCur; pCur = sqlite3_malloc( sizeof(*pCur) ); if( pCur==0 ) return SQLITE_NOMEM; memset(pCur, 0, sizeof(*pCur)); sqlite3VdbeMemInit(&pCur->sub, pVTab->db, 1); *ppCursor = &pCur->base; return SQLITE_OK; } /* ** Clear all internal content from a bytecodevtab cursor. */ static void bytecodevtabCursorClear(bytecodevtab_cursor *pCur){ sqlite3_free(pCur->zP4); pCur->zP4 = 0; sqlite3VdbeMemRelease(&pCur->sub); sqlite3VdbeMemSetNull(&pCur->sub); if( pCur->needFinalize ){ sqlite3_finalize(pCur->pStmt); } pCur->pStmt = 0; pCur->needFinalize = 0; pCur->zType = 0; pCur->zSchema = 0; pCur->zName = 0; } /* ** Destructor for a bytecodevtab_cursor. */ static int bytecodevtabClose(sqlite3_vtab_cursor *cur){ bytecodevtab_cursor *pCur = (bytecodevtab_cursor*)cur; bytecodevtabCursorClear(pCur); sqlite3_free(pCur); return SQLITE_OK; } /* ** Advance a bytecodevtab_cursor to its next row of output. */ static int bytecodevtabNext(sqlite3_vtab_cursor *cur){ bytecodevtab_cursor *pCur = (bytecodevtab_cursor*)cur; bytecodevtab *pTab = (bytecodevtab*)cur->pVtab; int rc; if( pCur->zP4 ){ sqlite3_free(pCur->zP4); pCur->zP4 = 0; } if( pCur->zName ){ pCur->zName = 0; pCur->zType = 0; pCur->zSchema = 0; } rc = sqlite3VdbeNextOpcode( (Vdbe*)pCur->pStmt, pCur->showSubprograms ? &pCur->sub : 0, pTab->bTablesUsed, &pCur->iRowid, &pCur->iAddr, &pCur->aOp); if( rc!=SQLITE_OK ){ sqlite3VdbeMemSetNull(&pCur->sub); pCur->aOp = 0; } return SQLITE_OK; } /* ** Return TRUE if the cursor has been moved off of the last ** row of output. */ static int bytecodevtabEof(sqlite3_vtab_cursor *cur){ bytecodevtab_cursor *pCur = (bytecodevtab_cursor*)cur; return pCur->aOp==0; } /* ** Return values of columns for the row at which the bytecodevtab_cursor ** is currently pointing. */ static int bytecodevtabColumn( sqlite3_vtab_cursor *cur, /* The cursor */ sqlite3_context *ctx, /* First argument to sqlite3_result_...() */ int i /* Which column to return */ ){ bytecodevtab_cursor *pCur = (bytecodevtab_cursor*)cur; bytecodevtab *pVTab = (bytecodevtab*)cur->pVtab; Op *pOp = pCur->aOp + pCur->iAddr; if( pVTab->bTablesUsed ){ if( i==4 ){ i = 8; }else{ if( i<=2 && pCur->zType==0 ){ Schema *pSchema; HashElem *k; int iDb = pOp->p3; Pgno iRoot = (Pgno)pOp->p2; sqlite3 *db = pVTab->db; pSchema = db->aDb[iDb].pSchema; pCur->zSchema = db->aDb[iDb].zDbSName; for(k=sqliteHashFirst(&pSchema->tblHash); k; k=sqliteHashNext(k)){ Table *pTab = (Table*)sqliteHashData(k); if( !IsVirtual(pTab) && pTab->tnum==iRoot ){ pCur->zName = pTab->zName; pCur->zType = "table"; break; } } if( pCur->zName==0 ){ for(k=sqliteHashFirst(&pSchema->idxHash); k; k=sqliteHashNext(k)){ Index *pIdx = (Index*)sqliteHashData(k); if( pIdx->tnum==iRoot ){ pCur->zName = pIdx->zName; pCur->zType = "index"; } } } } i += 10; } } switch( i ){ case 0: /* addr */ sqlite3_result_int(ctx, pCur->iAddr); break; case 1: /* opcode */ sqlite3_result_text(ctx, (char*)sqlite3OpcodeName(pOp->opcode), -1, SQLITE_STATIC); break; case 2: /* p1 */ sqlite3_result_int(ctx, pOp->p1); break; case 3: /* p2 */ sqlite3_result_int(ctx, pOp->p2); break; case 4: /* p3 */ sqlite3_result_int(ctx, pOp->p3); break; case 5: /* p4 */ case 7: /* comment */ if( pCur->zP4==0 ){ pCur->zP4 = sqlite3VdbeDisplayP4(pVTab->db, pOp); } if( i==5 ){ sqlite3_result_text(ctx, pCur->zP4, -1, SQLITE_STATIC); }else{ #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS char *zCom = sqlite3VdbeDisplayComment(pVTab->db, pOp, pCur->zP4); sqlite3_result_text(ctx, zCom, -1, sqlite3_free); #endif } break; case 6: /* p5 */ sqlite3_result_int(ctx, pOp->p5); break; case 8: { /* subprog */ Op *aOp = pCur->aOp; assert( aOp[0].opcode==OP_Init ); assert( aOp[0].p4.z==0 || strncmp(aOp[0].p4.z,"-" "- ",3)==0 ); if( pCur->iRowid==pCur->iAddr+1 ){ break; /* Result is NULL for the main program */ }else if( aOp[0].p4.z!=0 ){ sqlite3_result_text(ctx, aOp[0].p4.z+3, -1, SQLITE_STATIC); }else{ sqlite3_result_text(ctx, "(FK)", 4, SQLITE_STATIC); } break; } case 10: /* tables_used.type */ sqlite3_result_text(ctx, pCur->zType, -1, SQLITE_STATIC); break; case 11: /* tables_used.schema */ sqlite3_result_text(ctx, pCur->zSchema, -1, SQLITE_STATIC); break; case 12: /* tables_used.name */ sqlite3_result_text(ctx, pCur->zName, -1, SQLITE_STATIC); break; case 13: /* tables_used.wr */ sqlite3_result_int(ctx, pOp->opcode==OP_OpenWrite); break; } return SQLITE_OK; } /* ** Return the rowid for the current row. In this implementation, the ** rowid is the same as the output value. */ static int bytecodevtabRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){ bytecodevtab_cursor *pCur = (bytecodevtab_cursor*)cur; *pRowid = pCur->iRowid; return SQLITE_OK; } /* ** Initialize a cursor. ** ** idxNum==0 means show all subprograms ** idxNum==1 means show only the main bytecode and omit subprograms. */ static int bytecodevtabFilter( sqlite3_vtab_cursor *pVtabCursor, int idxNum, const char *idxStr, int argc, sqlite3_value **argv ){ bytecodevtab_cursor *pCur = (bytecodevtab_cursor *)pVtabCursor; bytecodevtab *pVTab = (bytecodevtab *)pVtabCursor->pVtab; int rc = SQLITE_OK; bytecodevtabCursorClear(pCur); pCur->iRowid = 0; pCur->iAddr = 0; pCur->showSubprograms = idxNum==0; assert( argc==1 ); if( sqlite3_value_type(argv[0])==SQLITE_TEXT ){ const char *zSql = (const char*)sqlite3_value_text(argv[0]); if( zSql==0 ){ rc = SQLITE_NOMEM; }else{ rc = sqlite3_prepare_v2(pVTab->db, zSql, -1, &pCur->pStmt, 0); pCur->needFinalize = 1; } }else{ pCur->pStmt = (sqlite3_stmt*)sqlite3_value_pointer(argv[0],"stmt-pointer"); } if( pCur->pStmt==0 ){ pVTab->base.zErrMsg = sqlite3_mprintf( "argument to %s() is not a valid SQL statement", pVTab->bTablesUsed ? "tables_used" : "bytecode" ); rc = SQLITE_ERROR; }else{ bytecodevtabNext(pVtabCursor); } return rc; } /* ** We must have a single stmt=? constraint that will be passed through ** into the xFilter method. If there is no valid stmt=? constraint, ** then return an SQLITE_CONSTRAINT error. */ static int bytecodevtabBestIndex( sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo ){ int i; int rc = SQLITE_CONSTRAINT; struct sqlite3_index_constraint *p; bytecodevtab *pVTab = (bytecodevtab*)tab; int iBaseCol = pVTab->bTablesUsed ? 4 : 8; pIdxInfo->estimatedCost = (double)100; pIdxInfo->estimatedRows = 100; pIdxInfo->idxNum = 0; for(i=0, p=pIdxInfo->aConstraint; i<pIdxInfo->nConstraint; i++, p++){ if( p->usable==0 ) continue; if( p->op==SQLITE_INDEX_CONSTRAINT_EQ && p->iColumn==iBaseCol+1 ){ rc = SQLITE_OK; pIdxInfo->aConstraintUsage[i].omit = 1; pIdxInfo->aConstraintUsage[i].argvIndex = 1; } if( p->op==SQLITE_INDEX_CONSTRAINT_ISNULL && p->iColumn==iBaseCol ){ pIdxInfo->aConstraintUsage[i].omit = 1; pIdxInfo->idxNum = 1; } } return rc; } /* ** This following structure defines all the methods for the ** virtual table. */ static sqlite3_module bytecodevtabModule = { /* iVersion */ 0, /* xCreate */ 0, /* xConnect */ bytecodevtabConnect, /* xBestIndex */ bytecodevtabBestIndex, /* xDisconnect */ bytecodevtabDisconnect, /* xDestroy */ 0, /* xOpen */ bytecodevtabOpen, /* xClose */ bytecodevtabClose, /* xFilter */ bytecodevtabFilter, /* xNext */ bytecodevtabNext, /* xEof */ bytecodevtabEof, /* xColumn */ bytecodevtabColumn, /* xRowid */ bytecodevtabRowid, /* xUpdate */ 0, /* xBegin */ 0, /* xSync */ 0, /* xCommit */ 0, /* xRollback */ 0, /* xFindMethod */ 0, /* xRename */ 0, /* xSavepoint */ 0, /* xRelease */ 0, /* xRollbackTo */ 0, /* xShadowName */ 0 }; int sqlite3VdbeBytecodeVtabInit(sqlite3 *db){ int rc; rc = sqlite3_create_module(db, "bytecode", &bytecodevtabModule, 0); if( rc==SQLITE_OK ){ rc = sqlite3_create_module(db, "tables_used", &bytecodevtabModule, &db); } return rc; } #elif defined(SQLITE_ENABLE_BYTECODE_VTAB) int sqlite3VdbeBytecodeVtabInit(sqlite3 *db){ return SQLITE_OK; } #endif /* SQLITE_ENABLE_BYTECODE_VTAB */ |
Changes to src/vtab.c.
︙ | ︙ | |||
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | int bDeclared; /* True after sqlite3_declare_vtab() is called */ }; /* ** Construct and install a Module object for a virtual table. When this ** routine is called, it is guaranteed that all appropriate locks are held ** and the module is not already part of the connection. */ Module *sqlite3VtabCreateModule( sqlite3 *db, /* Database in which module is registered */ const char *zName, /* Name assigned to this module */ const sqlite3_module *pModule, /* The definition of the module */ void *pAux, /* Context pointer for xCreate/xConnect */ void (*xDestroy)(void *) /* Module destructor function */ ){ Module *pMod; | > > > > > > > > > | | | | | < > | > > | | | > > > < < < | < | 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 | int bDeclared; /* True after sqlite3_declare_vtab() is called */ }; /* ** Construct and install a Module object for a virtual table. When this ** routine is called, it is guaranteed that all appropriate locks are held ** and the module is not already part of the connection. ** ** If there already exists a module with zName, replace it with the new one. ** If pModule==0, then delete the module zName if it exists. */ Module *sqlite3VtabCreateModule( sqlite3 *db, /* Database in which module is registered */ const char *zName, /* Name assigned to this module */ const sqlite3_module *pModule, /* The definition of the module */ void *pAux, /* Context pointer for xCreate/xConnect */ void (*xDestroy)(void *) /* Module destructor function */ ){ Module *pMod; Module *pDel; char *zCopy; if( pModule==0 ){ zCopy = (char*)zName; pMod = 0; }else{ int nName = sqlite3Strlen30(zName); pMod = (Module *)sqlite3Malloc(sizeof(Module) + nName + 1); if( pMod==0 ){ sqlite3OomFault(db); return 0; } zCopy = (char *)(&pMod[1]); memcpy(zCopy, zName, nName+1); pMod->zName = zCopy; pMod->pModule = pModule; pMod->pAux = pAux; pMod->xDestroy = xDestroy; pMod->pEpoTab = 0; pMod->nRefModule = 1; } pDel = (Module *)sqlite3HashInsert(&db->aModule,zCopy,(void*)pMod); if( pDel ){ if( pDel==pMod ){ sqlite3OomFault(db); sqlite3DbFree(db, pDel); pMod = 0; }else{ sqlite3VtabEponymousTableClear(db, pDel); sqlite3VtabModuleUnref(db, pDel); } } return pMod; } /* ** The actual function that does the work of creating a new module. ** This function implements the sqlite3_create_module() and ** sqlite3_create_module_v2() interfaces. */ static int createModule( sqlite3 *db, /* Database in which module is registered */ const char *zName, /* Name assigned to this module */ const sqlite3_module *pModule, /* The definition of the module */ void *pAux, /* Context pointer for xCreate/xConnect */ void (*xDestroy)(void *) /* Module destructor function */ ){ int rc = SQLITE_OK; sqlite3_mutex_enter(db->mutex); (void)sqlite3VtabCreateModule(db, zName, pModule, pAux, xDestroy); rc = sqlite3ApiExit(db, rc); if( rc!=SQLITE_OK && xDestroy ) xDestroy(pAux); sqlite3_mutex_leave(db->mutex); return rc; } |
︙ | ︙ | |||
118 119 120 121 122 123 124 125 126 127 128 129 130 131 | void (*xDestroy)(void *) /* Module destructor function */ ){ #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) || zName==0 ) return SQLITE_MISUSE_BKPT; #endif return createModule(db, zName, pModule, pAux, xDestroy); } /* ** Lock the virtual table so that it cannot be disconnected. ** Locks nest. Every lock should have a corresponding unlock. ** If an unlock is omitted, resources leaks will occur. ** ** If a disconnect is attempted while a virtual table is locked, | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | void (*xDestroy)(void *) /* Module destructor function */ ){ #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) || zName==0 ) return SQLITE_MISUSE_BKPT; #endif return createModule(db, zName, pModule, pAux, xDestroy); } /* ** External API to drop all virtual-table modules, except those named ** on the azNames list. */ int sqlite3_drop_modules(sqlite3 *db, const char** azNames){ HashElem *pThis, *pNext; #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; #endif for(pThis=sqliteHashFirst(&db->aModule); pThis; pThis=pNext){ Module *pMod = (Module*)sqliteHashData(pThis); pNext = sqliteHashNext(pThis); if( azNames ){ int ii; for(ii=0; azNames[ii]!=0 && strcmp(azNames[ii],pMod->zName)!=0; ii++){} if( azNames[ii]!=0 ) continue; } createModule(db, pMod->zName, 0, 0, 0); } return SQLITE_OK; } /* ** Decrement the reference count on a Module object. Destroy the ** module when the reference count reaches zero. */ void sqlite3VtabModuleUnref(sqlite3 *db, Module *pMod){ assert( pMod->nRefModule>0 ); pMod->nRefModule--; if( pMod->nRefModule==0 ){ if( pMod->xDestroy ){ pMod->xDestroy(pMod->pAux); } assert( pMod->pEpoTab==0 ); sqlite3DbFree(db, pMod); } } /* ** Lock the virtual table so that it cannot be disconnected. ** Locks nest. Every lock should have a corresponding unlock. ** If an unlock is omitted, resources leaks will occur. ** ** If a disconnect is attempted while a virtual table is locked, |
︙ | ︙ | |||
140 141 142 143 144 145 146 | ** pTab is a pointer to a Table structure representing a virtual-table. ** Return a pointer to the VTable object used by connection db to access ** this virtual-table, if one has been created, or NULL otherwise. */ VTable *sqlite3GetVTable(sqlite3 *db, Table *pTab){ VTable *pVtab; assert( IsVirtual(pTab) ); | | | > > | | | > > | > | | | 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 | ** pTab is a pointer to a Table structure representing a virtual-table. ** Return a pointer to the VTable object used by connection db to access ** this virtual-table, if one has been created, or NULL otherwise. */ VTable *sqlite3GetVTable(sqlite3 *db, Table *pTab){ VTable *pVtab; assert( IsVirtual(pTab) ); for(pVtab=pTab->u.vtab.p; pVtab && pVtab->db!=db; pVtab=pVtab->pNext); return pVtab; } /* ** Decrement the ref-count on a virtual table object. When the ref-count ** reaches zero, call the xDisconnect() method to delete the object. */ void sqlite3VtabUnlock(VTable *pVTab){ sqlite3 *db = pVTab->db; assert( db ); assert( pVTab->nRef>0 ); assert( db->eOpenState==SQLITE_STATE_OPEN || db->eOpenState==SQLITE_STATE_ZOMBIE ); pVTab->nRef--; if( pVTab->nRef==0 ){ sqlite3_vtab *p = pVTab->pVtab; sqlite3VtabModuleUnref(pVTab->db, pVTab->pMod); if( p ){ p->pModule->xDisconnect(p); } sqlite3DbFree(db, pVTab); } } /* ** Table p is a virtual table. This function moves all elements in the ** p->u.vtab.p list to the sqlite3.pDisconnect lists of their associated ** database connections to be disconnected at the next opportunity. ** Except, if argument db is not NULL, then the entry associated with ** connection db is left in the p->u.vtab.p list. */ static VTable *vtabDisconnectAll(sqlite3 *db, Table *p){ VTable *pRet = 0; VTable *pVTable; assert( IsVirtual(p) ); pVTable = p->u.vtab.p; p->u.vtab.p = 0; /* Assert that the mutex (if any) associated with the BtShared database ** that contains table p is held by the caller. See header comments ** above function sqlite3VtabUnlockList() for an explanation of why ** this makes it safe to access the sqlite3.pDisconnect list of any ** database connection that may have an entry in the p->u.vtab.p list. */ assert( db==0 || sqlite3SchemaMutexHeld(db, 0, p->pSchema) ); while( pVTable ){ sqlite3 *db2 = pVTable->db; VTable *pNext = pVTable->pNext; assert( db2 ); if( db2==db ){ pRet = pVTable; p->u.vtab.p = pRet; pRet->pNext = 0; }else{ pVTable->pNext = db2->pDisconnect; db2->pDisconnect = pVTable; } pVTable = pNext; } |
︙ | ︙ | |||
219 220 221 222 223 224 225 | void sqlite3VtabDisconnect(sqlite3 *db, Table *p){ VTable **ppVTab; assert( IsVirtual(p) ); assert( sqlite3BtreeHoldsAllMutexes(db) ); assert( sqlite3_mutex_held(db->mutex) ); | | | 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 | void sqlite3VtabDisconnect(sqlite3 *db, Table *p){ VTable **ppVTab; assert( IsVirtual(p) ); assert( sqlite3BtreeHoldsAllMutexes(db) ); assert( sqlite3_mutex_held(db->mutex) ); for(ppVTab=&p->u.vtab.p; *ppVTab; ppVTab=&(*ppVTab)->pNext){ if( (*ppVTab)->db==db ){ VTable *pVTab = *ppVTab; *ppVTab = pVTab->pNext; sqlite3VtabUnlock(pVTab); break; } } |
︙ | ︙ | |||
252 253 254 255 256 257 258 | ** the database handle mutex is held. ** ** As a result, a sqlite3.pDisconnect cannot be accessed simultaneously ** by multiple threads. It is thread-safe. */ void sqlite3VtabUnlockList(sqlite3 *db){ VTable *p = db->pDisconnect; | < > | 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 | ** the database handle mutex is held. ** ** As a result, a sqlite3.pDisconnect cannot be accessed simultaneously ** by multiple threads. It is thread-safe. */ void sqlite3VtabUnlockList(sqlite3 *db){ VTable *p = db->pDisconnect; assert( sqlite3BtreeHoldsAllMutexes(db) ); assert( sqlite3_mutex_held(db->mutex) ); if( p ){ db->pDisconnect = 0; sqlite3ExpirePreparedStatements(db, 0); do { VTable *pNext = p->pNext; sqlite3VtabUnlock(p); p = pNext; }while( p ); } |
︙ | ︙ | |||
282 283 284 285 286 287 288 289 | ** The reference count of the VTable structure associated with database ** connection db is decremented immediately (which may lead to the ** structure being xDisconnected and free). Any other VTable structures ** in the list are moved to the sqlite3.pDisconnect list of the associated ** database connection. */ void sqlite3VtabClear(sqlite3 *db, Table *p){ if( !db || db->pnBytesFreed==0 ) vtabDisconnectAll(0, p); | > | | | | | | | > > > > > > > | | | | 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 | ** The reference count of the VTable structure associated with database ** connection db is decremented immediately (which may lead to the ** structure being xDisconnected and free). Any other VTable structures ** in the list are moved to the sqlite3.pDisconnect list of the associated ** database connection. */ void sqlite3VtabClear(sqlite3 *db, Table *p){ assert( IsVirtual(p) ); if( !db || db->pnBytesFreed==0 ) vtabDisconnectAll(0, p); if( p->u.vtab.azArg ){ int i; for(i=0; i<p->u.vtab.nArg; i++){ if( i!=1 ) sqlite3DbFree(db, p->u.vtab.azArg[i]); } sqlite3DbFree(db, p->u.vtab.azArg); } } /* ** Add a new module argument to pTable->u.vtab.azArg[]. ** The string is not copied - the pointer is stored. The ** string will be freed automatically when the table is ** deleted. */ static void addModuleArgument(Parse *pParse, Table *pTable, char *zArg){ sqlite3_int64 nBytes; char **azModuleArg; sqlite3 *db = pParse->db; assert( IsVirtual(pTable) ); nBytes = sizeof(char *)*(2+pTable->u.vtab.nArg); if( pTable->u.vtab.nArg+3>=db->aLimit[SQLITE_LIMIT_COLUMN] ){ sqlite3ErrorMsg(pParse, "too many columns on %s", pTable->zName); } azModuleArg = sqlite3DbRealloc(db, pTable->u.vtab.azArg, nBytes); if( azModuleArg==0 ){ sqlite3DbFree(db, zArg); }else{ int i = pTable->u.vtab.nArg++; azModuleArg[i] = zArg; azModuleArg[i+1] = 0; pTable->u.vtab.azArg = azModuleArg; } } /* ** The parser calls this routine when it first sees a CREATE VIRTUAL TABLE ** statement. The module name has been parsed, but the optional list ** of parameters that follow the module name are still pending. |
︙ | ︙ | |||
331 332 333 334 335 336 337 338 339 340 | Table *pTable; /* The new virtual table */ sqlite3 *db; /* Database connection */ sqlite3StartTable(pParse, pName1, pName2, 0, 0, 1, ifNotExists); pTable = pParse->pNewTable; if( pTable==0 ) return; assert( 0==pTable->pIndex ); db = pParse->db; | > | | | | | | | | > | | | > > | | | | < | | > | < | | < < < < | > | 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 | Table *pTable; /* The new virtual table */ sqlite3 *db; /* Database connection */ sqlite3StartTable(pParse, pName1, pName2, 0, 0, 1, ifNotExists); pTable = pParse->pNewTable; if( pTable==0 ) return; assert( 0==pTable->pIndex ); pTable->eTabType = TABTYP_VTAB; db = pParse->db; assert( pTable->u.vtab.nArg==0 ); addModuleArgument(pParse, pTable, sqlite3NameFromToken(db, pModuleName)); addModuleArgument(pParse, pTable, 0); addModuleArgument(pParse, pTable, sqlite3DbStrDup(db, pTable->zName)); assert( (pParse->sNameToken.z==pName2->z && pName2->z!=0) || (pParse->sNameToken.z==pName1->z && pName2->z==0) ); pParse->sNameToken.n = (int)( &pModuleName->z[pModuleName->n] - pParse->sNameToken.z ); #ifndef SQLITE_OMIT_AUTHORIZATION /* Creating a virtual table invokes the authorization callback twice. ** The first invocation, to obtain permission to INSERT a row into the ** sqlite_schema table, has already been made by sqlite3StartTable(). ** The second call, to obtain permission to create the table, is made now. */ if( pTable->u.vtab.azArg ){ int iDb = sqlite3SchemaToIndex(db, pTable->pSchema); assert( iDb>=0 ); /* The database the table is being created in */ sqlite3AuthCheck(pParse, SQLITE_CREATE_VTABLE, pTable->zName, pTable->u.vtab.azArg[0], pParse->db->aDb[iDb].zDbSName); } #endif } /* ** This routine takes the module argument that has been accumulating ** in pParse->zArg[] and appends it to the list of arguments on the ** virtual table currently under construction in pParse->pTable. */ static void addArgumentToVtab(Parse *pParse){ if( pParse->sArg.z && pParse->pNewTable ){ const char *z = (const char*)pParse->sArg.z; int n = pParse->sArg.n; sqlite3 *db = pParse->db; addModuleArgument(pParse, pParse->pNewTable, sqlite3DbStrNDup(db, z, n)); } } /* ** The parser calls this routine after the CREATE VIRTUAL TABLE statement ** has been completely parsed. */ void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){ Table *pTab = pParse->pNewTable; /* The table being constructed */ sqlite3 *db = pParse->db; /* The database connection */ if( pTab==0 ) return; assert( IsVirtual(pTab) ); addArgumentToVtab(pParse); pParse->sArg.z = 0; if( pTab->u.vtab.nArg<1 ) return; /* If the CREATE VIRTUAL TABLE statement is being entered for the ** first time (in other words if the virtual table is actually being ** created now instead of just being read out of sqlite_schema) then ** do additional initialization work and store the statement text ** in the sqlite_schema table. */ if( !db->init.busy ){ char *zStmt; char *zWhere; int iDb; int iReg; Vdbe *v; sqlite3MayAbort(pParse); /* Compute the complete text of the CREATE VIRTUAL TABLE statement */ if( pEnd ){ pParse->sNameToken.n = (int)(pEnd->z - pParse->sNameToken.z) + pEnd->n; } zStmt = sqlite3MPrintf(db, "CREATE VIRTUAL TABLE %T", &pParse->sNameToken); /* A slot for the record has already been allocated in the ** schema table. We just need to update that slot with all ** the information we've collected. ** ** The VM register number pParse->regRowid holds the rowid of an ** entry in the sqlite_schema table tht was created for this vtab ** by sqlite3StartTable(). */ iDb = sqlite3SchemaToIndex(db, pTab->pSchema); sqlite3NestedParse(pParse, "UPDATE %Q." LEGACY_SCHEMA_TABLE " " "SET type='table', name=%Q, tbl_name=%Q, rootpage=0, sql=%Q " "WHERE rowid=#%d", db->aDb[iDb].zDbSName, pTab->zName, pTab->zName, zStmt, pParse->regRowid ); v = sqlite3GetVdbe(pParse); sqlite3ChangeCookie(pParse, iDb); sqlite3VdbeAddOp0(v, OP_Expire); zWhere = sqlite3MPrintf(db, "name=%Q AND sql=%Q", pTab->zName, zStmt); sqlite3VdbeAddParseSchemaOp(v, iDb, zWhere, 0); sqlite3DbFree(db, zStmt); iReg = ++pParse->nMem; sqlite3VdbeLoadString(v, iReg, pTab->zName); sqlite3VdbeAddOp2(v, OP_VCreate, iDb, iReg); }else{ /* If we are rereading the sqlite_schema table create the in-memory ** record of the table. */ Table *pOld; Schema *pSchema = pTab->pSchema; const char *zName = pTab->zName; assert( zName!=0 ); sqlite3MarkAllShadowTablesOf(db, pTab); pOld = sqlite3HashInsert(&pSchema->tblHash, zName, pTab); if( pOld ){ sqlite3OomFault(db); assert( pTab==pOld ); /* Malloc must have failed inside HashInsert() */ return; } pParse->pNewTable = 0; |
︙ | ︙ | |||
498 499 500 501 502 503 504 | Module *pMod, int (*xConstruct)(sqlite3*,void*,int,const char*const*,sqlite3_vtab**,char**), char **pzErr ){ VtabCtx sCtx; VTable *pVTable; int rc; | | | > > > | 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 | Module *pMod, int (*xConstruct)(sqlite3*,void*,int,const char*const*,sqlite3_vtab**,char**), char **pzErr ){ VtabCtx sCtx; VTable *pVTable; int rc; const char *const*azArg; int nArg = pTab->u.vtab.nArg; char *zErr = 0; char *zModuleName; int iDb; VtabCtx *pCtx; assert( IsVirtual(pTab) ); azArg = (const char *const*)pTab->u.vtab.azArg; /* Check that the virtual-table is not already being initialized */ for(pCtx=db->pVtabCtx; pCtx; pCtx=pCtx->pPrior){ if( pCtx->pTab==pTab ){ *pzErr = sqlite3MPrintf(db, "vtable constructor called recursively: %s", pTab->zName ); return SQLITE_LOCKED; |
︙ | ︙ | |||
528 529 530 531 532 533 534 535 536 | if( !pVTable ){ sqlite3OomFault(db); sqlite3DbFree(db, zModuleName); return SQLITE_NOMEM_BKPT; } pVTable->db = db; pVTable->pMod = pMod; iDb = sqlite3SchemaToIndex(db, pTab->pSchema); | > | | 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 | if( !pVTable ){ sqlite3OomFault(db); sqlite3DbFree(db, zModuleName); return SQLITE_NOMEM_BKPT; } pVTable->db = db; pVTable->pMod = pMod; pVTable->eVtabRisk = SQLITE_VTABRISK_Normal; iDb = sqlite3SchemaToIndex(db, pTab->pSchema); pTab->u.vtab.azArg[1] = db->aDb[iDb].zDbSName; /* Invoke the virtual table constructor */ assert( &db->pVtabCtx ); assert( xConstruct ); sCtx.pTab = pTab; sCtx.pVTable = pVTable; sCtx.pPrior = db->pVtabCtx; |
︙ | ︙ | |||
558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 | } sqlite3DbFree(db, pVTable); }else if( ALWAYS(pVTable->pVtab) ){ /* Justification of ALWAYS(): A correct vtab constructor must allocate ** the sqlite3_vtab object if successful. */ memset(pVTable->pVtab, 0, sizeof(pVTable->pVtab[0])); pVTable->pVtab->pModule = pMod->pModule; pVTable->nRef = 1; if( sCtx.bDeclared==0 ){ const char *zFormat = "vtable constructor did not declare schema: %s"; *pzErr = sqlite3MPrintf(db, zFormat, pTab->zName); sqlite3VtabUnlock(pVTable); rc = SQLITE_ERROR; }else{ int iCol; | > | | | | | 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 | } sqlite3DbFree(db, pVTable); }else if( ALWAYS(pVTable->pVtab) ){ /* Justification of ALWAYS(): A correct vtab constructor must allocate ** the sqlite3_vtab object if successful. */ memset(pVTable->pVtab, 0, sizeof(pVTable->pVtab[0])); pVTable->pVtab->pModule = pMod->pModule; pMod->nRefModule++; pVTable->nRef = 1; if( sCtx.bDeclared==0 ){ const char *zFormat = "vtable constructor did not declare schema: %s"; *pzErr = sqlite3MPrintf(db, zFormat, pTab->zName); sqlite3VtabUnlock(pVTable); rc = SQLITE_ERROR; }else{ int iCol; u16 oooHidden = 0; /* If everything went according to plan, link the new VTable structure ** into the linked list headed by pTab->u.vtab.p. Then loop through the ** columns of the table to see if any of them contain the token "hidden". ** If so, set the Column COLFLAG_HIDDEN flag and remove the token from ** the type string. */ pVTable->pNext = pTab->u.vtab.p; pTab->u.vtab.p = pVTable; for(iCol=0; iCol<pTab->nCol; iCol++){ char *zType = sqlite3ColumnType(&pTab->aCol[iCol], ""); int nType; int i = 0; nType = sqlite3Strlen30(zType); for(i=0; i<nType; i++){ |
︙ | ︙ | |||
599 600 601 602 603 604 605 606 607 608 609 610 611 612 | zType[j] = zType[j+nDel]; } if( zType[i]=='\0' && i>0 ){ assert(zType[i-1]==' '); zType[i-1] = '\0'; } pTab->aCol[iCol].colFlags |= COLFLAG_HIDDEN; oooHidden = TF_OOOHidden; }else{ pTab->tabFlags |= oooHidden; } } } } | > | 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 | zType[j] = zType[j+nDel]; } if( zType[i]=='\0' && i>0 ){ assert(zType[i-1]==' '); zType[i-1] = '\0'; } pTab->aCol[iCol].colFlags |= COLFLAG_HIDDEN; pTab->tabFlags |= TF_HasHidden; oooHidden = TF_OOOHidden; }else{ pTab->tabFlags |= oooHidden; } } } } |
︙ | ︙ | |||
625 626 627 628 629 630 631 | int sqlite3VtabCallConnect(Parse *pParse, Table *pTab){ sqlite3 *db = pParse->db; const char *zMod; Module *pMod; int rc; assert( pTab ); | > | | | | 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 | int sqlite3VtabCallConnect(Parse *pParse, Table *pTab){ sqlite3 *db = pParse->db; const char *zMod; Module *pMod; int rc; assert( pTab ); assert( IsVirtual(pTab) ); if( sqlite3GetVTable(db, pTab) ){ return SQLITE_OK; } /* Locate the required virtual table module */ zMod = pTab->u.vtab.azArg[0]; pMod = (Module*)sqlite3HashFind(&db->aModule, zMod); if( !pMod ){ const char *zModule = pTab->u.vtab.azArg[0]; sqlite3ErrorMsg(pParse, "no such module: %s", zModule); rc = SQLITE_ERROR; }else{ char *zErr = 0; rc = vtabCallConstructor(db, pTab, pMod, pMod->pModule->xConnect, &zErr); if( rc!=SQLITE_OK ){ sqlite3ErrorMsg(pParse, "%s", zErr); |
︙ | ︙ | |||
659 660 661 662 663 664 665 | */ static int growVTrans(sqlite3 *db){ const int ARRAY_INCR = 5; /* Grow the sqlite3.aVTrans array if required */ if( (db->nVTrans%ARRAY_INCR)==0 ){ VTable **aVTrans; | | > | 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 | */ static int growVTrans(sqlite3 *db){ const int ARRAY_INCR = 5; /* Grow the sqlite3.aVTrans array if required */ if( (db->nVTrans%ARRAY_INCR)==0 ){ VTable **aVTrans; sqlite3_int64 nBytes = sizeof(sqlite3_vtab*)* ((sqlite3_int64)db->nVTrans + ARRAY_INCR); aVTrans = sqlite3DbRealloc(db, (void *)db->aVTrans, nBytes); if( !aVTrans ){ return SQLITE_NOMEM_BKPT; } memset(&aVTrans[db->nVTrans], 0, sizeof(sqlite3_vtab *)*ARRAY_INCR); db->aVTrans = aVTrans; } |
︙ | ︙ | |||
696 697 698 699 700 701 702 | int sqlite3VtabCallCreate(sqlite3 *db, int iDb, const char *zTab, char **pzErr){ int rc = SQLITE_OK; Table *pTab; Module *pMod; const char *zMod; pTab = sqlite3FindTable(db, zTab, db->aDb[iDb].zDbSName); | | | | 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 | int sqlite3VtabCallCreate(sqlite3 *db, int iDb, const char *zTab, char **pzErr){ int rc = SQLITE_OK; Table *pTab; Module *pMod; const char *zMod; pTab = sqlite3FindTable(db, zTab, db->aDb[iDb].zDbSName); assert( pTab && IsVirtual(pTab) && !pTab->u.vtab.p ); /* Locate the required virtual table module */ zMod = pTab->u.vtab.azArg[0]; pMod = (Module*)sqlite3HashFind(&db->aModule, zMod); /* If the module has been registered and includes a Create method, ** invoke it now. If the module has not been registered, return an ** error. Otherwise, do nothing. */ if( pMod==0 || pMod->pModule->xCreate==0 || pMod->pModule->xDestroy==0 ){ |
︙ | ︙ | |||
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 | */ int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){ VtabCtx *pCtx; int rc = SQLITE_OK; Table *pTab; char *zErr = 0; Parse sParse; #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) || zCreateTable==0 ){ return SQLITE_MISUSE_BKPT; } #endif sqlite3_mutex_enter(db->mutex); pCtx = db->pVtabCtx; if( !pCtx || pCtx->bDeclared ){ sqlite3Error(db, SQLITE_MISUSE); sqlite3_mutex_leave(db->mutex); return SQLITE_MISUSE_BKPT; } pTab = pCtx->pTab; assert( IsVirtual(pTab) ); memset(&sParse, 0, sizeof(sParse)); sParse.eParseMode = PARSE_MODE_DECLARE_VTAB; sParse.db = db; sParse.nQueryLoop = 1; if( SQLITE_OK==sqlite3RunParser(&sParse, zCreateTable, &zErr) && sParse.pNewTable && !db->mallocFailed | > > > > > > > < | > | | 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 | */ int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){ VtabCtx *pCtx; int rc = SQLITE_OK; Table *pTab; char *zErr = 0; Parse sParse; int initBusy; #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) || zCreateTable==0 ){ return SQLITE_MISUSE_BKPT; } #endif sqlite3_mutex_enter(db->mutex); pCtx = db->pVtabCtx; if( !pCtx || pCtx->bDeclared ){ sqlite3Error(db, SQLITE_MISUSE); sqlite3_mutex_leave(db->mutex); return SQLITE_MISUSE_BKPT; } pTab = pCtx->pTab; assert( IsVirtual(pTab) ); memset(&sParse, 0, sizeof(sParse)); sParse.eParseMode = PARSE_MODE_DECLARE_VTAB; sParse.db = db; /* We should never be able to reach this point while loading the ** schema. Nevertheless, defend against that (turn off db->init.busy) ** in case a bug arises. */ assert( db->init.busy==0 ); initBusy = db->init.busy; db->init.busy = 0; sParse.nQueryLoop = 1; if( SQLITE_OK==sqlite3RunParser(&sParse, zCreateTable, &zErr) && sParse.pNewTable && !db->mallocFailed && IsOrdinaryTable(sParse.pNewTable) ){ if( !pTab->aCol ){ Table *pNew = sParse.pNewTable; Index *pIdx; pTab->aCol = pNew->aCol; sqlite3ExprListDelete(db, pNew->u.tab.pDfltList); pTab->nNVCol = pTab->nCol = pNew->nCol; pTab->tabFlags |= pNew->tabFlags & (TF_WithoutRowid|TF_NoVisibleRowid); pNew->nCol = 0; pNew->aCol = 0; assert( pTab->pIndex==0 ); assert( HasRowid(pNew) || sqlite3PrimaryKeyIndex(pNew)!=0 ); if( !HasRowid(pNew) && pCtx->pVTable->pMod->pModule->xUpdate!=0 |
︙ | ︙ | |||
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 | sParse.eParseMode = PARSE_MODE_NORMAL; if( sParse.pVdbe ){ sqlite3VdbeFinalize(sParse.pVdbe); } sqlite3DeleteTable(db, sParse.pNewTable); sqlite3ParserReset(&sParse); assert( (rc&0xff)==rc ); rc = sqlite3ApiExit(db, rc); sqlite3_mutex_leave(db->mutex); return rc; } /* ** This function is invoked by the vdbe to call the xDestroy method ** of the virtual table named zTab in database iDb. This occurs ** when a DROP TABLE is mentioned. ** ** This call is a no-op if zTab is not a virtual table. */ int sqlite3VtabCallDestroy(sqlite3 *db, int iDb, const char *zTab){ int rc = SQLITE_OK; Table *pTab; pTab = sqlite3FindTable(db, zTab, db->aDb[iDb].zDbSName); | > > > | > | > | > | | > | 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 | sParse.eParseMode = PARSE_MODE_NORMAL; if( sParse.pVdbe ){ sqlite3VdbeFinalize(sParse.pVdbe); } sqlite3DeleteTable(db, sParse.pNewTable); sqlite3ParserReset(&sParse); db->init.busy = initBusy; assert( (rc&0xff)==rc ); rc = sqlite3ApiExit(db, rc); sqlite3_mutex_leave(db->mutex); return rc; } /* ** This function is invoked by the vdbe to call the xDestroy method ** of the virtual table named zTab in database iDb. This occurs ** when a DROP TABLE is mentioned. ** ** This call is a no-op if zTab is not a virtual table. */ int sqlite3VtabCallDestroy(sqlite3 *db, int iDb, const char *zTab){ int rc = SQLITE_OK; Table *pTab; pTab = sqlite3FindTable(db, zTab, db->aDb[iDb].zDbSName); if( ALWAYS(pTab!=0) && ALWAYS(IsVirtual(pTab)) && ALWAYS(pTab->u.vtab.p!=0) ){ VTable *p; int (*xDestroy)(sqlite3_vtab *); for(p=pTab->u.vtab.p; p; p=p->pNext){ assert( p->pVtab ); if( p->pVtab->nRef>0 ){ return SQLITE_LOCKED; } } p = vtabDisconnectAll(db, pTab); xDestroy = p->pMod->pModule->xDestroy; if( xDestroy==0 ) xDestroy = p->pMod->pModule->xDisconnect; assert( xDestroy!=0 ); pTab->nTabRef++; rc = xDestroy(p->pVtab); /* Remove the sqlite3_vtab* from the aVTrans[] array, if applicable */ if( rc==SQLITE_OK ){ assert( pTab->u.vtab.p==p && p->pNext==0 ); p->pVtab = 0; pTab->u.vtab.p = 0; sqlite3VtabUnlock(p); } sqlite3DeleteTable(db, pTab); } return rc; } /* ** This function invokes either the xRollback or xCommit method |
︙ | ︙ | |||
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 | if( db->aVTrans ){ int i; for(i=0; rc==SQLITE_OK && i<db->nVTrans; i++){ VTable *pVTab = db->aVTrans[i]; const sqlite3_module *pMod = pVTab->pMod->pModule; if( pVTab->pVtab && pMod->iVersion>=2 ){ int (*xMethod)(sqlite3_vtab *, int); switch( op ){ case SAVEPOINT_BEGIN: xMethod = pMod->xSavepoint; pVTab->iSavepoint = iSavepoint+1; break; case SAVEPOINT_ROLLBACK: xMethod = pMod->xRollbackTo; break; default: xMethod = pMod->xRelease; break; } if( xMethod && pVTab->iSavepoint>iSavepoint ){ rc = xMethod(pVTab->pVtab, iSavepoint); } } } } return rc; } /* | > > | 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 | if( db->aVTrans ){ int i; for(i=0; rc==SQLITE_OK && i<db->nVTrans; i++){ VTable *pVTab = db->aVTrans[i]; const sqlite3_module *pMod = pVTab->pMod->pModule; if( pVTab->pVtab && pMod->iVersion>=2 ){ int (*xMethod)(sqlite3_vtab *, int); sqlite3VtabLock(pVTab); switch( op ){ case SAVEPOINT_BEGIN: xMethod = pMod->xSavepoint; pVTab->iSavepoint = iSavepoint+1; break; case SAVEPOINT_ROLLBACK: xMethod = pMod->xRollbackTo; break; default: xMethod = pMod->xRelease; break; } if( xMethod && pVTab->iSavepoint>iSavepoint ){ rc = xMethod(pVTab->pVtab, iSavepoint); } sqlite3VtabUnlock(pVTab); } } } return rc; } /* |
︙ | ︙ | |||
1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 | void *pArg = 0; FuncDef *pNew; int rc = 0; /* Check to see the left operand is a column in a virtual table */ if( NEVER(pExpr==0) ) return pDef; if( pExpr->op!=TK_COLUMN ) return pDef; pTab = pExpr->y.pTab; if( pTab==0 ) return pDef; if( !IsVirtual(pTab) ) return pDef; pVtab = sqlite3GetVTable(db, pTab)->pVtab; assert( pVtab!=0 ); assert( pVtab->pModule!=0 ); pMod = (sqlite3_module *)pVtab->pModule; | > | 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 | void *pArg = 0; FuncDef *pNew; int rc = 0; /* Check to see the left operand is a column in a virtual table */ if( NEVER(pExpr==0) ) return pDef; if( pExpr->op!=TK_COLUMN ) return pDef; assert( ExprUseYTab(pExpr) ); pTab = pExpr->y.pTab; if( pTab==0 ) return pDef; if( !IsVirtual(pTab) ) return pDef; pVtab = sqlite3GetVTable(db, pTab)->pVtab; assert( pVtab!=0 ); assert( pVtab->pModule!=0 ); pMod = (sqlite3_module *)pVtab->pModule; |
︙ | ︙ | |||
1110 1111 1112 1113 1114 1115 1116 | Table **apVtabLock; assert( IsVirtual(pTab) ); for(i=0; i<pToplevel->nVtabLock; i++){ if( pTab==pToplevel->apVtabLock[i] ) return; } n = (pToplevel->nVtabLock+1)*sizeof(pToplevel->apVtabLock[0]); | | | | > | 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 | Table **apVtabLock; assert( IsVirtual(pTab) ); for(i=0; i<pToplevel->nVtabLock; i++){ if( pTab==pToplevel->apVtabLock[i] ) return; } n = (pToplevel->nVtabLock+1)*sizeof(pToplevel->apVtabLock[0]); apVtabLock = sqlite3Realloc(pToplevel->apVtabLock, n); if( apVtabLock ){ pToplevel->apVtabLock = apVtabLock; pToplevel->apVtabLock[pToplevel->nVtabLock++] = pTab; }else{ sqlite3OomFault(pToplevel->db); } } /* ** Check to see if virtual table module pMod can be have an eponymous ** virtual table instance. If it can, create one if one does not already ** exist. Return non-zero if either the eponymous virtual table instance ** exists when this routine returns or if an attempt to create it failed ** and an error message was left in pParse. ** ** An eponymous virtual table instance is one that is named after its ** module, and more importantly, does not require a CREATE VIRTUAL TABLE ** statement in order to come into existance. Eponymous virtual table ** instances always exist. They cannot be DROP-ed. ** ** Any virtual table module for which xConnect and xCreate are the same |
︙ | ︙ | |||
1150 1151 1152 1153 1154 1155 1156 1157 | pTab->zName = sqlite3DbStrDup(db, pMod->zName); if( pTab->zName==0 ){ sqlite3DbFree(db, pTab); return 0; } pMod->pEpoTab = pTab; pTab->nTabRef = 1; pTab->pSchema = db->aDb[0].pSchema; | > | > | | | < | 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 | pTab->zName = sqlite3DbStrDup(db, pMod->zName); if( pTab->zName==0 ){ sqlite3DbFree(db, pTab); return 0; } pMod->pEpoTab = pTab; pTab->nTabRef = 1; pTab->eTabType = TABTYP_VTAB; pTab->pSchema = db->aDb[0].pSchema; assert( pTab->u.vtab.nArg==0 ); pTab->iPKey = -1; pTab->tabFlags |= TF_Eponymous; addModuleArgument(pParse, pTab, sqlite3DbStrDup(db, pTab->zName)); addModuleArgument(pParse, pTab, 0); addModuleArgument(pParse, pTab, sqlite3DbStrDup(db, pTab->zName)); rc = vtabCallConstructor(db, pTab, pMod, pModule->xConnect, &zErr); if( rc ){ sqlite3ErrorMsg(pParse, "%s", zErr); sqlite3DbFree(db, zErr); sqlite3VtabEponymousTableClear(db, pMod); } return 1; } /* ** Erase the eponymous virtual table instance associated with ** virtual table module pMod, if it exists. |
︙ | ︙ | |||
1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 | ** Call from within the xCreate() or xConnect() methods to provide ** the SQLite core with additional information about the behavior ** of the virtual table being implemented. */ int sqlite3_vtab_config(sqlite3 *db, int op, ...){ va_list ap; int rc = SQLITE_OK; #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; #endif sqlite3_mutex_enter(db->mutex); | > < < < | | | | | > > > > > > | | > > > > | | | | > | > | 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 | ** Call from within the xCreate() or xConnect() methods to provide ** the SQLite core with additional information about the behavior ** of the virtual table being implemented. */ int sqlite3_vtab_config(sqlite3 *db, int op, ...){ va_list ap; int rc = SQLITE_OK; VtabCtx *p; #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; #endif sqlite3_mutex_enter(db->mutex); p = db->pVtabCtx; if( !p ){ rc = SQLITE_MISUSE_BKPT; }else{ assert( p->pTab==0 || IsVirtual(p->pTab) ); va_start(ap, op); switch( op ){ case SQLITE_VTAB_CONSTRAINT_SUPPORT: { p->pVTable->bConstraint = (u8)va_arg(ap, int); break; } case SQLITE_VTAB_INNOCUOUS: { p->pVTable->eVtabRisk = SQLITE_VTABRISK_Low; break; } case SQLITE_VTAB_DIRECTONLY: { p->pVTable->eVtabRisk = SQLITE_VTABRISK_High; break; } default: { rc = SQLITE_MISUSE_BKPT; break; } } va_end(ap); } if( rc!=SQLITE_OK ) sqlite3Error(db, rc); sqlite3_mutex_leave(db->mutex); return rc; } #endif /* SQLITE_OMIT_VIRTUALTABLE */ |
Changes to src/wal.c.
︙ | ︙ | |||
157 158 159 160 161 162 163 | ** in the mxFrame field. ** ** Each index block except for the first contains information on ** HASHTABLE_NPAGE frames. The first index block contains information on ** HASHTABLE_NPAGE_ONE frames. The values of HASHTABLE_NPAGE_ONE and ** HASHTABLE_NPAGE are selected so that together the wal-index header and ** first index block are the same size as all other index blocks in the | | > > > | 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 | ** in the mxFrame field. ** ** Each index block except for the first contains information on ** HASHTABLE_NPAGE frames. The first index block contains information on ** HASHTABLE_NPAGE_ONE frames. The values of HASHTABLE_NPAGE_ONE and ** HASHTABLE_NPAGE are selected so that together the wal-index header and ** first index block are the same size as all other index blocks in the ** wal-index. The values are: ** ** HASHTABLE_NPAGE 4096 ** HASHTABLE_NPAGE_ONE 4062 ** ** Each index block contains two sections, a page-mapping that contains the ** database page number associated with each wal frame, and a hash-table ** that allows readers to query an index block for a specific page number. ** The page-mapping is an array of HASHTABLE_NPAGE (or HASHTABLE_NPAGE_ONE ** for the first index block) 32-bit page numbers. The first entry in the ** first index-block contains the database page number corresponding to the |
︙ | ︙ | |||
254 255 256 257 258 259 260 | #if defined(SQLITE_TEST) && defined(SQLITE_DEBUG) int sqlite3WalTrace = 0; # define WALTRACE(X) if(sqlite3WalTrace) sqlite3DebugPrintf X #else # define WALTRACE(X) #endif | < < < < < < < < < < < < | 257 258 259 260 261 262 263 264 265 266 267 268 269 270 | #if defined(SQLITE_TEST) && defined(SQLITE_DEBUG) int sqlite3WalTrace = 0; # define WALTRACE(X) if(sqlite3WalTrace) sqlite3DebugPrintf X #else # define WALTRACE(X) #endif /* ** The maximum (and only) versions of the wal and wal-index formats ** that may be interpreted by this version of SQLite. ** ** If a client begins recovering a WAL file and finds that (a) the checksum ** values in the wal-header are correct and (b) the version field is not ** WAL_MAX_VERSION, recovery fails and SQLite returns SQLITE_CANTOPEN. |
︙ | ︙ | |||
405 406 407 408 409 410 411 412 413 414 415 416 417 418 | u32 aReadMark[WAL_NREADER]; /* Reader marks */ u8 aLock[SQLITE_SHM_NLOCK]; /* Reserved space for locks */ u32 nBackfillAttempted; /* WAL frames perhaps written, or maybe not */ u32 notUsed0; /* Available for future enhancements */ }; #define READMARK_NOT_USED 0xffffffff /* A block of WALINDEX_LOCK_RESERVED bytes beginning at ** WALINDEX_LOCK_OFFSET is reserved for locks. Since some systems ** only support mandatory file-locks, we do not read or write data ** from the region of the file on which locks are applied. */ #define WALINDEX_LOCK_OFFSET (sizeof(WalIndexHdr)*2+offsetof(WalCkptInfo,aLock)) | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | u32 aReadMark[WAL_NREADER]; /* Reader marks */ u8 aLock[SQLITE_SHM_NLOCK]; /* Reserved space for locks */ u32 nBackfillAttempted; /* WAL frames perhaps written, or maybe not */ u32 notUsed0; /* Available for future enhancements */ }; #define READMARK_NOT_USED 0xffffffff /* ** This is a schematic view of the complete 136-byte header of the ** wal-index file (also known as the -shm file): ** ** +-----------------------------+ ** 0: | iVersion | \ ** +-----------------------------+ | ** 4: | (unused padding) | | ** +-----------------------------+ | ** 8: | iChange | | ** +-------+-------+-------------+ | ** 12: | bInit | bBig | szPage | | ** +-------+-------+-------------+ | ** 16: | mxFrame | | First copy of the ** +-----------------------------+ | WalIndexHdr object ** 20: | nPage | | ** +-----------------------------+ | ** 24: | aFrameCksum | | ** | | | ** +-----------------------------+ | ** 32: | aSalt | | ** | | | ** +-----------------------------+ | ** 40: | aCksum | | ** | | / ** +-----------------------------+ ** 48: | iVersion | \ ** +-----------------------------+ | ** 52: | (unused padding) | | ** +-----------------------------+ | ** 56: | iChange | | ** +-------+-------+-------------+ | ** 60: | bInit | bBig | szPage | | ** +-------+-------+-------------+ | Second copy of the ** 64: | mxFrame | | WalIndexHdr ** +-----------------------------+ | ** 68: | nPage | | ** +-----------------------------+ | ** 72: | aFrameCksum | | ** | | | ** +-----------------------------+ | ** 80: | aSalt | | ** | | | ** +-----------------------------+ | ** 88: | aCksum | | ** | | / ** +-----------------------------+ ** 96: | nBackfill | ** +-----------------------------+ ** 100: | 5 read marks | ** | | ** | | ** | | ** | | ** +-------+-------+------+------+ ** 120: | Write | Ckpt | Rcvr | Rd0 | \ ** +-------+-------+------+------+ ) 8 lock bytes ** | Read1 | Read2 | Rd3 | Rd4 | / ** +-------+-------+------+------+ ** 128: | nBackfillAttempted | ** +-----------------------------+ ** 132: | (unused padding) | ** +-----------------------------+ */ /* A block of WALINDEX_LOCK_RESERVED bytes beginning at ** WALINDEX_LOCK_OFFSET is reserved for locks. Since some systems ** only support mandatory file-locks, we do not read or write data ** from the region of the file on which locks are applied. */ #define WALINDEX_LOCK_OFFSET (sizeof(WalIndexHdr)*2+offsetof(WalCkptInfo,aLock)) |
︙ | ︙ | |||
470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 | u8 bShmUnreliable; /* SHM content is read-only and unreliable */ WalIndexHdr hdr; /* Wal-index header for current transaction */ u32 minFrame; /* Ignore wal frames before this one */ u32 iReCksum; /* On commit, recalculate checksums from here */ u32 nPriorFrame; /* For sqlite3WalInfo() */ const char *zWalName; /* Name of WAL file */ u32 nCkpt; /* Checkpoint sequence counter in the wal-header */ #ifdef SQLITE_DEBUG u8 lockError; /* True if a locking error has occurred */ #endif #ifdef SQLITE_ENABLE_SNAPSHOT WalIndexHdr *pSnapshot; /* Start transaction here if not NULL */ #endif }; /* ** Candidate values for Wal.exclusiveMode. */ #define WAL_NORMAL_MODE 0 | > > > > | 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 | u8 bShmUnreliable; /* SHM content is read-only and unreliable */ WalIndexHdr hdr; /* Wal-index header for current transaction */ u32 minFrame; /* Ignore wal frames before this one */ u32 iReCksum; /* On commit, recalculate checksums from here */ u32 nPriorFrame; /* For sqlite3WalInfo() */ const char *zWalName; /* Name of WAL file */ u32 nCkpt; /* Checkpoint sequence counter in the wal-header */ FastPrng sPrng; /* Random number generator */ #ifdef SQLITE_DEBUG u8 lockError; /* True if a locking error has occurred */ #endif #ifdef SQLITE_ENABLE_SNAPSHOT WalIndexHdr *pSnapshot; /* Start transaction here if not NULL */ #endif #ifdef SQLITE_ENABLE_SETLK_TIMEOUT sqlite3 *db; #endif }; /* ** Candidate values for Wal.exclusiveMode. */ #define WAL_NORMAL_MODE 0 |
︙ | ︙ | |||
514 515 516 517 518 519 520 | ** walIteratorInit() - Create a new iterator, ** walIteratorNext() - Step an iterator, ** walIteratorFree() - Free an iterator. ** ** This functionality is used by the checkpoint code (see walCheckpoint()). */ struct WalIterator { | | | 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 | ** walIteratorInit() - Create a new iterator, ** walIteratorNext() - Step an iterator, ** walIteratorFree() - Free an iterator. ** ** This functionality is used by the checkpoint code (see walCheckpoint()). */ struct WalIterator { u32 iPrior; /* Last result returned from the iterator */ int nSegment; /* Number of entries in aSegment[] */ struct WalSegment { int iNext; /* Next slot in aIndex[] not yet returned */ ht_slot *aIndex; /* i0, i1, i2... such that aPgno[iN] ascend */ u32 *aPgno; /* Array of page numbers. */ int nEntry; /* Nr. of entries in aPgno[] and aIndex[] */ int iZero; /* Frame number associated with aPgno[0] */ |
︙ | ︙ | |||
559 560 561 562 563 564 565 | ** numbered from zero. ** ** If the wal-index is currently smaller the iPage pages then the size ** of the wal-index might be increased, but only if it is safe to do ** so. It is safe to enlarge the wal-index if pWal->writeLock is true ** or pWal->exclusiveMode==WAL_HEAPMEMORY_MODE. ** | | > | | > > > | | | > > > > | | 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 | ** numbered from zero. ** ** If the wal-index is currently smaller the iPage pages then the size ** of the wal-index might be increased, but only if it is safe to do ** so. It is safe to enlarge the wal-index if pWal->writeLock is true ** or pWal->exclusiveMode==WAL_HEAPMEMORY_MODE. ** ** Three possible result scenarios: ** ** (1) rc==SQLITE_OK and *ppPage==Requested-Wal-Index-Page ** (2) rc>=SQLITE_ERROR and *ppPage==NULL ** (3) rc==SQLITE_OK and *ppPage==NULL // only if iPage==0 ** ** Scenario (3) can only occur when pWal->writeLock is false and iPage==0 */ static SQLITE_NOINLINE int walIndexPageRealloc( Wal *pWal, /* The WAL context */ int iPage, /* The page we seek */ volatile u32 **ppPage /* Write the page pointer here */ ){ int rc = SQLITE_OK; /* Enlarge the pWal->apWiData[] array if required */ if( pWal->nWiData<=iPage ){ sqlite3_int64 nByte = sizeof(u32*)*(iPage+1); volatile u32 **apNew; apNew = (volatile u32 **)sqlite3Realloc((void *)pWal->apWiData, nByte); if( !apNew ){ *ppPage = 0; return SQLITE_NOMEM_BKPT; } memset((void*)&apNew[pWal->nWiData], 0, sizeof(u32*)*(iPage+1-pWal->nWiData)); pWal->apWiData = apNew; pWal->nWiData = iPage+1; } /* Request a pointer to the required page from the VFS */ assert( pWal->apWiData[iPage]==0 ); if( pWal->exclusiveMode==WAL_HEAPMEMORY_MODE ){ pWal->apWiData[iPage] = (u32 volatile *)sqlite3MallocZero(WALINDEX_PGSZ); if( !pWal->apWiData[iPage] ) rc = SQLITE_NOMEM_BKPT; }else{ rc = sqlite3OsShmMap(pWal->pDbFd, iPage, WALINDEX_PGSZ, pWal->writeLock, (void volatile **)&pWal->apWiData[iPage] ); assert( pWal->apWiData[iPage]!=0 || rc!=SQLITE_OK || (pWal->writeLock==0 && iPage==0) ); testcase( pWal->apWiData[iPage]==0 && rc==SQLITE_OK ); if( rc==SQLITE_OK ){ if( iPage>0 && sqlite3FaultSim(600) ) rc = SQLITE_NOMEM; }else if( (rc&0xff)==SQLITE_READONLY ){ pWal->readOnly |= WAL_SHM_RDONLY; if( rc==SQLITE_READONLY ){ rc = SQLITE_OK; } } } |
︙ | ︙ | |||
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 | s2 = aIn[1]; }else{ s1 = s2 = 0; } assert( nByte>=8 ); assert( (nByte&0x00000007)==0 ); if( nativeCksum ){ do { s1 += *aData++ + s2; s2 += *aData++ + s1; }while( aData<aEnd ); }else{ do { s1 += BYTESWAP32(aData[0]) + s2; s2 += BYTESWAP32(aData[1]) + s1; aData += 2; }while( aData<aEnd ); } aOut[0] = s1; aOut[1] = s2; } static void walShmBarrier(Wal *pWal){ if( pWal->exclusiveMode!=WAL_HEAPMEMORY_MODE ){ sqlite3OsShmBarrier(pWal->pDbFd); } } /* ** Write the header information in pWal->hdr into the wal-index. ** ** The checksum on pWal->hdr is updated before it is written. */ | > > > > > > > > > > > > > > > > > > | > | 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 | s2 = aIn[1]; }else{ s1 = s2 = 0; } assert( nByte>=8 ); assert( (nByte&0x00000007)==0 ); assert( nByte<=65536 ); if( nativeCksum ){ do { s1 += *aData++ + s2; s2 += *aData++ + s1; }while( aData<aEnd ); }else{ do { s1 += BYTESWAP32(aData[0]) + s2; s2 += BYTESWAP32(aData[1]) + s1; aData += 2; }while( aData<aEnd ); } aOut[0] = s1; aOut[1] = s2; } /* ** If there is the possibility of concurrent access to the SHM file ** from multiple threads and/or processes, then do a memory barrier. */ static void walShmBarrier(Wal *pWal){ if( pWal->exclusiveMode!=WAL_HEAPMEMORY_MODE ){ sqlite3OsShmBarrier(pWal->pDbFd); } } /* ** Add the SQLITE_NO_TSAN as part of the return-type of a function ** definition as a hint that the function contains constructs that ** might give false-positive TSAN warnings. ** ** See tag-20200519-1. */ #if defined(__clang__) && !defined(SQLITE_NO_TSAN) # define SQLITE_NO_TSAN __attribute__((no_sanitize_thread)) #else # define SQLITE_NO_TSAN #endif /* ** Write the header information in pWal->hdr into the wal-index. ** ** The checksum on pWal->hdr is updated before it is written. */ static SQLITE_NO_TSAN void walIndexWriteHdr(Wal *pWal){ volatile WalIndexHdr *aHdr = walIndexHdr(pWal); const int nCksum = offsetof(WalIndexHdr, aCksum); assert( pWal->writeLock ); pWal->hdr.isInit = 1; pWal->hdr.iVersion = WALINDEX_MAX_VERSION; walChecksumBytes(1, (u8*)&pWal->hdr, nCksum, 0, pWal->hdr.aCksum); /* Possible TSAN false-positive. See tag-20200519-1 */ memcpy((void*)&aHdr[1], (const void*)&pWal->hdr, sizeof(WalIndexHdr)); walShmBarrier(pWal); memcpy((void*)&aHdr[0], (const void*)&pWal->hdr, sizeof(WalIndexHdr)); } /* ** This function encodes a single frame header and writes it to a buffer |
︙ | ︙ | |||
848 849 850 851 852 853 854 | static int walLockShared(Wal *pWal, int lockIdx){ int rc; if( pWal->exclusiveMode ) return SQLITE_OK; rc = sqlite3OsShmLock(pWal->pDbFd, lockIdx, 1, SQLITE_SHM_LOCK | SQLITE_SHM_SHARED); WALTRACE(("WAL%p: acquire SHARED-%s %s\n", pWal, walLockName(lockIdx), rc ? "failed" : "ok")); | | | | 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 | static int walLockShared(Wal *pWal, int lockIdx){ int rc; if( pWal->exclusiveMode ) return SQLITE_OK; rc = sqlite3OsShmLock(pWal->pDbFd, lockIdx, 1, SQLITE_SHM_LOCK | SQLITE_SHM_SHARED); WALTRACE(("WAL%p: acquire SHARED-%s %s\n", pWal, walLockName(lockIdx), rc ? "failed" : "ok")); VVA_ONLY( pWal->lockError = (u8)(rc!=SQLITE_OK && (rc&0xFF)!=SQLITE_BUSY); ) return rc; } static void walUnlockShared(Wal *pWal, int lockIdx){ if( pWal->exclusiveMode ) return; (void)sqlite3OsShmLock(pWal->pDbFd, lockIdx, 1, SQLITE_SHM_UNLOCK | SQLITE_SHM_SHARED); WALTRACE(("WAL%p: release SHARED-%s\n", pWal, walLockName(lockIdx))); } static int walLockExclusive(Wal *pWal, int lockIdx, int n){ int rc; if( pWal->exclusiveMode ) return SQLITE_OK; rc = sqlite3OsShmLock(pWal->pDbFd, lockIdx, n, SQLITE_SHM_LOCK | SQLITE_SHM_EXCLUSIVE); WALTRACE(("WAL%p: acquire EXCLUSIVE-%s cnt=%d %s\n", pWal, walLockName(lockIdx), n, rc ? "failed" : "ok")); VVA_ONLY( pWal->lockError = (u8)(rc!=SQLITE_OK && (rc&0xFF)!=SQLITE_BUSY); ) return rc; } static void walUnlockExclusive(Wal *pWal, int lockIdx, int n){ if( pWal->exclusiveMode ) return; (void)sqlite3OsShmLock(pWal->pDbFd, lockIdx, n, SQLITE_SHM_UNLOCK | SQLITE_SHM_EXCLUSIVE); WALTRACE(("WAL%p: release EXCLUSIVE-%s cnt=%d\n", pWal, |
︙ | ︙ | |||
912 913 914 915 916 917 918 | ** ** Set output variable pLoc->aHash to point to the start of the hash table ** in the wal-index file. Set pLoc->iZero to one less than the frame ** number of the first frame indexed by this hash table. If a ** slot in the hash table is set to N, it refers to frame number ** (pLoc->iZero+N) in the log. ** | | | | > | > | 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 | ** ** Set output variable pLoc->aHash to point to the start of the hash table ** in the wal-index file. Set pLoc->iZero to one less than the frame ** number of the first frame indexed by this hash table. If a ** slot in the hash table is set to N, it refers to frame number ** (pLoc->iZero+N) in the log. ** ** Finally, set pLoc->aPgno so that pLoc->aPgno[0] is the page number of the ** first frame indexed by the hash table, frame (pLoc->iZero). */ static int walHashGet( Wal *pWal, /* WAL handle */ int iHash, /* Find the iHash'th table */ WalHashLoc *pLoc /* OUT: Hash table location */ ){ int rc; /* Return code */ rc = walIndexPage(pWal, iHash, &pLoc->aPgno); assert( rc==SQLITE_OK || iHash>0 ); if( pLoc->aPgno ){ pLoc->aHash = (volatile ht_slot *)&pLoc->aPgno[HASHTABLE_NPAGE]; if( iHash==0 ){ pLoc->aPgno = &pLoc->aPgno[WALINDEX_HDR_SIZE/sizeof(u32)]; pLoc->iZero = 0; }else{ pLoc->iZero = HASHTABLE_NPAGE_ONE + (iHash-1)*HASHTABLE_NPAGE; } }else if( NEVER(rc==SQLITE_OK) ){ rc = SQLITE_ERROR; } return rc; } /* ** Return the number of the wal-index page that contains the hash-table ** and page-number array that contain entries corresponding to WAL frame ** iFrame. The wal-index is broken up into 32KB pages. Wal-index pages ** are numbered starting from 0. */ static int walFramePage(u32 iFrame){ int iHash = (iFrame+HASHTABLE_NPAGE-HASHTABLE_NPAGE_ONE-1) / HASHTABLE_NPAGE; assert( (iHash==0 || iFrame>HASHTABLE_NPAGE_ONE) && (iHash>=1 || iFrame<=HASHTABLE_NPAGE_ONE) && (iHash<=1 || iFrame>(HASHTABLE_NPAGE_ONE+HASHTABLE_NPAGE)) && (iHash>=2 || iFrame<=HASHTABLE_NPAGE_ONE+HASHTABLE_NPAGE) && (iHash<=2 || iFrame>(HASHTABLE_NPAGE_ONE+2*HASHTABLE_NPAGE)) ); assert( iHash>=0 ); return iHash; } /* ** Return the page number associated with frame iFrame in this WAL. */ static u32 walFramePgno(Wal *pWal, u32 iFrame){ |
︙ | ︙ | |||
993 994 995 996 997 998 999 | testcase( pWal->hdr.mxFrame==HASHTABLE_NPAGE_ONE ); testcase( pWal->hdr.mxFrame==HASHTABLE_NPAGE_ONE+1 ); if( pWal->hdr.mxFrame==0 ) return; /* Obtain pointers to the hash-table and page-number array containing ** the entry that corresponds to frame pWal->hdr.mxFrame. It is guaranteed | | | > | > | | | | | 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 | testcase( pWal->hdr.mxFrame==HASHTABLE_NPAGE_ONE ); testcase( pWal->hdr.mxFrame==HASHTABLE_NPAGE_ONE+1 ); if( pWal->hdr.mxFrame==0 ) return; /* Obtain pointers to the hash-table and page-number array containing ** the entry that corresponds to frame pWal->hdr.mxFrame. It is guaranteed ** that the page said hash-table and array reside on is already mapped.(1) */ assert( pWal->nWiData>walFramePage(pWal->hdr.mxFrame) ); assert( pWal->apWiData[walFramePage(pWal->hdr.mxFrame)] ); i = walHashGet(pWal, walFramePage(pWal->hdr.mxFrame), &sLoc); if( NEVER(i) ) return; /* Defense-in-depth, in case (1) above is wrong */ /* Zero all hash-table entries that correspond to frame numbers greater ** than pWal->hdr.mxFrame. */ iLimit = pWal->hdr.mxFrame - sLoc.iZero; assert( iLimit>0 ); for(i=0; i<HASHTABLE_NSLOT; i++){ if( sLoc.aHash[i]>iLimit ){ sLoc.aHash[i] = 0; } } /* Zero the entries in the aPgno array that correspond to frames with ** frame numbers greater than pWal->hdr.mxFrame. */ nByte = (int)((char *)sLoc.aHash - (char *)&sLoc.aPgno[iLimit]); assert( nByte>=0 ); memset((void *)&sLoc.aPgno[iLimit], 0, nByte); #ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT /* Verify that the every entry in the mapping region is still reachable ** via the hash table even after the cleanup. */ if( iLimit ){ int j; /* Loop counter */ int iKey; /* Hash key */ for(j=0; j<iLimit; j++){ for(iKey=walHash(sLoc.aPgno[j]);sLoc.aHash[iKey];iKey=walNextHash(iKey)){ if( sLoc.aHash[iKey]==j+1 ) break; } assert( sLoc.aHash[iKey]==j+1 ); } } #endif /* SQLITE_ENABLE_EXPENSIVE_ASSERT */ } /* |
︙ | ︙ | |||
1059 1060 1061 1062 1063 1064 1065 | idx = iFrame - sLoc.iZero; assert( idx <= HASHTABLE_NSLOT/2 + 1 ); /* If this is the first entry to be added to this hash-table, zero the ** entire hash table and aPgno[] array before proceeding. */ if( idx==1 ){ | | | | | | | | | | | < | 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 | idx = iFrame - sLoc.iZero; assert( idx <= HASHTABLE_NSLOT/2 + 1 ); /* If this is the first entry to be added to this hash-table, zero the ** entire hash table and aPgno[] array before proceeding. */ if( idx==1 ){ int nByte = (int)((u8*)&sLoc.aHash[HASHTABLE_NSLOT] - (u8*)sLoc.aPgno); assert( nByte>=0 ); memset((void*)sLoc.aPgno, 0, nByte); } /* If the entry in aPgno[] is already set, then the previous writer ** must have exited unexpectedly in the middle of a transaction (after ** writing one or more dirty pages to the WAL to free up memory). ** Remove the remnants of that writers uncommitted transaction from ** the hash-table before writing any new entries. */ if( sLoc.aPgno[idx-1] ){ walCleanupHash(pWal); assert( !sLoc.aPgno[idx-1] ); } /* Write the aPgno[] array entry and the hash-table slot. */ nCollide = idx; for(iKey=walHash(iPage); sLoc.aHash[iKey]; iKey=walNextHash(iKey)){ if( (nCollide--)==0 ) return SQLITE_CORRUPT_BKPT; } sLoc.aPgno[idx-1] = iPage; AtomicStore(&sLoc.aHash[iKey], (ht_slot)idx); #ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT /* Verify that the number of entries in the hash table exactly equals ** the number of entries in the mapping region. */ { int i; /* Loop counter */ int nEntry = 0; /* Number of entries in the hash table */ for(i=0; i<HASHTABLE_NSLOT; i++){ if( sLoc.aHash[i] ) nEntry++; } assert( nEntry==idx ); } /* Verify that the every entry in the mapping region is reachable ** via the hash table. This turns out to be a really, really expensive ** thing to check, so only do this occasionally - not on every ** iteration. */ if( (idx&0x3ff)==0 ){ int i; /* Loop counter */ for(i=0; i<idx; i++){ for(iKey=walHash(sLoc.aPgno[i]); sLoc.aHash[iKey]; iKey=walNextHash(iKey)){ if( sLoc.aHash[iKey]==i+1 ) break; } assert( sLoc.aHash[iKey]==i+1 ); } } #endif /* SQLITE_ENABLE_EXPENSIVE_ASSERT */ } return rc; } /* ** Recover the wal-index by reading the write-ahead log file. |
︙ | ︙ | |||
1146 1147 1148 1149 1150 1151 1152 | */ assert( pWal->ckptLock==1 || pWal->ckptLock==0 ); assert( WAL_ALL_BUT_WRITE==WAL_WRITE_LOCK+1 ); assert( WAL_CKPT_LOCK==WAL_ALL_BUT_WRITE ); assert( pWal->writeLock ); iLock = WAL_ALL_BUT_WRITE + pWal->ckptLock; rc = walLockExclusive(pWal, iLock, WAL_READ_LOCK(0)-iLock); | < < < < < < > < < > > | 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 | */ assert( pWal->ckptLock==1 || pWal->ckptLock==0 ); assert( WAL_ALL_BUT_WRITE==WAL_WRITE_LOCK+1 ); assert( WAL_CKPT_LOCK==WAL_ALL_BUT_WRITE ); assert( pWal->writeLock ); iLock = WAL_ALL_BUT_WRITE + pWal->ckptLock; rc = walLockExclusive(pWal, iLock, WAL_READ_LOCK(0)-iLock); if( rc ){ return rc; } WALTRACE(("WAL%p: recovery begin...\n", pWal)); memset(&pWal->hdr, 0, sizeof(WalIndexHdr)); rc = sqlite3OsFileSize(pWal->pWalFd, &nSize); if( rc!=SQLITE_OK ){ goto recovery_error; } if( nSize>WAL_HDRSIZE ){ u8 aBuf[WAL_HDRSIZE]; /* Buffer to load WAL header into */ u32 *aPrivate = 0; /* Heap copy of *-shm hash being populated */ u8 *aFrame = 0; /* Malloc'd buffer to load entire frame */ int szFrame; /* Number of bytes in buffer aFrame[] */ u8 *aData; /* Pointer to data part of aFrame buffer */ int szPage; /* Page size according to the log */ u32 magic; /* Magic value read from WAL header */ u32 version; /* Magic value read from WAL header */ int isValid; /* True if this frame is valid */ u32 iPg; /* Current 32KB wal-index page */ u32 iLastFrame; /* Last frame in wal, based on nSize alone */ /* Read in the WAL header. */ rc = sqlite3OsRead(pWal->pWalFd, aBuf, WAL_HDRSIZE, 0); if( rc!=SQLITE_OK ){ goto recovery_error; } |
︙ | ︙ | |||
1222 1223 1224 1225 1226 1227 1228 | if( version!=WAL_MAX_VERSION ){ rc = SQLITE_CANTOPEN_BKPT; goto finished; } /* Malloc a buffer to read frames into. */ szFrame = szPage + WAL_FRAME_HDRSIZE; | | > | > > > > > > > > > > | > > | | | < | | | | | | | | | | | | | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | > > > | > > > > > > > > < | 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 | if( version!=WAL_MAX_VERSION ){ rc = SQLITE_CANTOPEN_BKPT; goto finished; } /* Malloc a buffer to read frames into. */ szFrame = szPage + WAL_FRAME_HDRSIZE; aFrame = (u8 *)sqlite3_malloc64(szFrame + WALINDEX_PGSZ); if( !aFrame ){ rc = SQLITE_NOMEM_BKPT; goto recovery_error; } aData = &aFrame[WAL_FRAME_HDRSIZE]; aPrivate = (u32*)&aData[szPage]; /* Read all frames from the log file. */ iLastFrame = (nSize - WAL_HDRSIZE) / szFrame; for(iPg=0; iPg<=(u32)walFramePage(iLastFrame); iPg++){ u32 *aShare; u32 iFrame; /* Index of last frame read */ u32 iLast = MIN(iLastFrame, HASHTABLE_NPAGE_ONE+iPg*HASHTABLE_NPAGE); u32 iFirst = 1 + (iPg==0?0:HASHTABLE_NPAGE_ONE+(iPg-1)*HASHTABLE_NPAGE); u32 nHdr, nHdr32; rc = walIndexPage(pWal, iPg, (volatile u32**)&aShare); assert( aShare!=0 || rc!=SQLITE_OK ); if( aShare==0 ) break; pWal->apWiData[iPg] = aPrivate; for(iFrame=iFirst; iFrame<=iLast; iFrame++){ i64 iOffset = walFrameOffset(iFrame, szPage); u32 pgno; /* Database page number for frame */ u32 nTruncate; /* dbsize field from frame header */ /* Read and decode the next log frame. */ rc = sqlite3OsRead(pWal->pWalFd, aFrame, szFrame, iOffset); if( rc!=SQLITE_OK ) break; isValid = walDecodeFrame(pWal, &pgno, &nTruncate, aData, aFrame); if( !isValid ) break; rc = walIndexAppend(pWal, iFrame, pgno); if( NEVER(rc!=SQLITE_OK) ) break; /* If nTruncate is non-zero, this is a commit record. */ if( nTruncate ){ pWal->hdr.mxFrame = iFrame; pWal->hdr.nPage = nTruncate; pWal->hdr.szPage = (u16)((szPage&0xff00) | (szPage>>16)); testcase( szPage<=32768 ); testcase( szPage>=65536 ); aFrameCksum[0] = pWal->hdr.aFrameCksum[0]; aFrameCksum[1] = pWal->hdr.aFrameCksum[1]; } } pWal->apWiData[iPg] = aShare; nHdr = (iPg==0 ? WALINDEX_HDR_SIZE : 0); nHdr32 = nHdr / sizeof(u32); #ifndef SQLITE_SAFER_WALINDEX_RECOVERY /* Memcpy() should work fine here, on all reasonable implementations. ** Technically, memcpy() might change the destination to some ** intermediate value before setting to the final value, and that might ** cause a concurrent reader to malfunction. Memcpy() is allowed to ** do that, according to the spec, but no memcpy() implementation that ** we know of actually does that, which is why we say that memcpy() ** is safe for this. Memcpy() is certainly a lot faster. */ memcpy(&aShare[nHdr32], &aPrivate[nHdr32], WALINDEX_PGSZ-nHdr); #else /* In the event that some platform is found for which memcpy() ** changes the destination to some intermediate value before ** setting the final value, this alternative copy routine is ** provided. */ { int i; for(i=nHdr32; i<WALINDEX_PGSZ/sizeof(u32); i++){ if( aShare[i]!=aPrivate[i] ){ /* Atomic memory operations are not required here because if ** the value needs to be changed, that means it is not being ** accessed concurrently. */ aShare[i] = aPrivate[i]; } } } #endif if( iFrame<=iLast ) break; } sqlite3_free(aFrame); } finished: if( rc==SQLITE_OK ){ volatile WalCkptInfo *pInfo; int i; pWal->hdr.aFrameCksum[0] = aFrameCksum[0]; pWal->hdr.aFrameCksum[1] = aFrameCksum[1]; walIndexWriteHdr(pWal); /* Reset the checkpoint-header. This is safe because this thread is ** currently holding locks that exclude all other writers and ** checkpointers. Then set the values of read-mark slots 1 through N. */ pInfo = walCkptInfo(pWal); pInfo->nBackfill = 0; pInfo->nBackfillAttempted = pWal->hdr.mxFrame; pInfo->aReadMark[0] = 0; for(i=1; i<WAL_NREADER; i++){ rc = walLockExclusive(pWal, WAL_READ_LOCK(i), 1); if( rc==SQLITE_OK ){ if( i==1 && pWal->hdr.mxFrame ){ pInfo->aReadMark[i] = pWal->hdr.mxFrame; }else{ pInfo->aReadMark[i] = READMARK_NOT_USED; } walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1); }else if( rc!=SQLITE_BUSY ){ goto recovery_error; } } /* 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, WAL_READ_LOCK(0)-iLock); return rc; } /* ** Close an open wal-index. */ static void walIndexClose(Wal *pWal, int isDelete){ |
︙ | ︙ | |||
1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 | ){ int rc; /* Return Code */ Wal *pRet; /* Object to allocate and return */ int flags; /* Flags passed to OsOpen() */ assert( zWalName && zWalName[0] ); assert( pDbFd ); /* In the amalgamation, the os_unix.c and os_win.c source files come before ** this source file. Verify that the #defines of the locking byte offsets ** in os_unix.c and os_win.c agree with the WALINDEX_LOCK_OFFSET value. ** For that matter, if the lock offset ever changes from its initial design ** value of 120, we need to know that so there is an assert() to check it. */ | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > < < | 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 | ){ int rc; /* Return Code */ Wal *pRet; /* Object to allocate and return */ int flags; /* Flags passed to OsOpen() */ assert( zWalName && zWalName[0] ); assert( pDbFd ); /* Verify the values of various constants. Any changes to the values ** of these constants would result in an incompatible on-disk format ** for the -shm file. Any change that causes one of these asserts to ** fail is a backward compatibility problem, even if the change otherwise ** works. ** ** This table also serves as a helpful cross-reference when trying to ** interpret hex dumps of the -shm file. */ assert( 48 == sizeof(WalIndexHdr) ); assert( 40 == sizeof(WalCkptInfo) ); assert( 120 == WALINDEX_LOCK_OFFSET ); assert( 136 == WALINDEX_HDR_SIZE ); assert( 4096 == HASHTABLE_NPAGE ); assert( 4062 == HASHTABLE_NPAGE_ONE ); assert( 8192 == HASHTABLE_NSLOT ); assert( 383 == HASHTABLE_HASH_1 ); assert( 32768 == WALINDEX_PGSZ ); assert( 8 == SQLITE_SHM_NLOCK ); assert( 5 == WAL_NREADER ); assert( 24 == WAL_FRAME_HDRSIZE ); assert( 32 == WAL_HDRSIZE ); assert( 120 == WALINDEX_LOCK_OFFSET + WAL_WRITE_LOCK ); assert( 121 == WALINDEX_LOCK_OFFSET + WAL_CKPT_LOCK ); assert( 122 == WALINDEX_LOCK_OFFSET + WAL_RECOVER_LOCK ); assert( 123 == WALINDEX_LOCK_OFFSET + WAL_READ_LOCK(0) ); assert( 124 == WALINDEX_LOCK_OFFSET + WAL_READ_LOCK(1) ); assert( 125 == WALINDEX_LOCK_OFFSET + WAL_READ_LOCK(2) ); assert( 126 == WALINDEX_LOCK_OFFSET + WAL_READ_LOCK(3) ); assert( 127 == WALINDEX_LOCK_OFFSET + WAL_READ_LOCK(4) ); /* In the amalgamation, the os_unix.c and os_win.c source files come before ** this source file. Verify that the #defines of the locking byte offsets ** in os_unix.c and os_win.c agree with the WALINDEX_LOCK_OFFSET value. ** For that matter, if the lock offset ever changes from its initial design ** value of 120, we need to know that so there is an assert() to check it. */ #ifdef WIN_SHM_BASE assert( WIN_SHM_BASE==WALINDEX_LOCK_OFFSET ); #endif #ifdef UNIX_SHM_BASE assert( UNIX_SHM_BASE==WALINDEX_LOCK_OFFSET ); #endif |
︙ | ︙ | |||
1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 | pRet->pDbFd = pDbFd; pRet->readLock = -1; pRet->mxWalSize = mxWalSize; pRet->zWalName = zWalName; pRet->syncHeader = 1; pRet->padToSectorBoundary = 1; pRet->exclusiveMode = (bNoShm ? WAL_HEAPMEMORY_MODE: WAL_NORMAL_MODE); /* Open file handle on the write-ahead log file. */ flags = (SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|SQLITE_OPEN_WAL); rc = sqlite3OsOpen(pVfs, zWalName, pRet->pWalFd, flags, &flags); if( rc==SQLITE_OK && flags&SQLITE_OPEN_READONLY ){ pRet->readOnly = WAL_RDONLY; } | > | 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 | pRet->pDbFd = pDbFd; pRet->readLock = -1; pRet->mxWalSize = mxWalSize; pRet->zWalName = zWalName; pRet->syncHeader = 1; pRet->padToSectorBoundary = 1; pRet->exclusiveMode = (bNoShm ? WAL_HEAPMEMORY_MODE: WAL_NORMAL_MODE); sqlite3FastPrngInit(&pRet->sPrng); /* Open file handle on the write-ahead log file. */ flags = (SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|SQLITE_OPEN_WAL); rc = sqlite3OsOpen(pVfs, zWalName, pRet->pWalFd, flags, &flags); if( rc==SQLITE_OK && flags&SQLITE_OPEN_READONLY ){ pRet->readOnly = WAL_RDONLY; } |
︙ | ︙ | |||
1611 1612 1613 1614 1615 1616 1617 | ** The calling routine should invoke walIteratorFree() to destroy the ** WalIterator object when it has finished with it. */ static int walIteratorInit(Wal *pWal, u32 nBackfill, WalIterator **pp){ WalIterator *p; /* Return value */ int nSegment; /* Number of segments to merge */ u32 iLast; /* Last frame in log */ | | | 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 | ** The calling routine should invoke walIteratorFree() to destroy the ** WalIterator object when it has finished with it. */ static int walIteratorInit(Wal *pWal, u32 nBackfill, WalIterator **pp){ WalIterator *p; /* Return value */ int nSegment; /* Number of segments to merge */ u32 iLast; /* Last frame in log */ sqlite3_int64 nByte; /* Number of bytes to allocate */ int i; /* Iterator variable */ ht_slot *aTmp; /* Temp space used by merge-sort */ int rc = SQLITE_OK; /* Return Code */ /* This routine only runs while holding the checkpoint lock. And ** it only runs if there is actually content in the log (mxFrame>0). */ |
︙ | ︙ | |||
1653 1654 1655 1656 1657 1658 1659 | rc = walHashGet(pWal, i, &sLoc); if( rc==SQLITE_OK ){ int j; /* Counter variable */ int nEntry; /* Number of entries in this segment */ ht_slot *aIndex; /* Sorted index for this segment */ | < | 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 | rc = walHashGet(pWal, i, &sLoc); if( rc==SQLITE_OK ){ int j; /* Counter variable */ int nEntry; /* Number of entries in this segment */ ht_slot *aIndex; /* Sorted index for this segment */ if( (i+1)==nSegment ){ nEntry = (int)(iLast - sLoc.iZero); }else{ nEntry = (int)((u32*)sLoc.aHash - (u32*)sLoc.aPgno); } aIndex = &((ht_slot *)&p->aSegment[p->nSegment])[sLoc.iZero]; sLoc.iZero++; |
︙ | ︙ | |||
1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 | if( rc!=SQLITE_OK ){ walIteratorFree(p); p = 0; } *pp = p; return rc; } /* ** Attempt to obtain the exclusive WAL lock defined by parameters lockIdx and ** n. If the attempt fails and parameter xBusy is not NULL, then it is a ** busy-handler function. Invoke it and retry the lock until either the ** lock is successfully obtained or the busy-handler returns 0. */ static int walBusyLock( Wal *pWal, /* WAL connection */ int (*xBusy)(void*), /* Function to call when busy */ void *pBusyArg, /* Context argument for xBusyHandler */ int lockIdx, /* Offset of first byte to lock */ int n /* Number of bytes to lock */ ){ int rc; do { rc = walLockExclusive(pWal, lockIdx, n); }while( xBusy && rc==SQLITE_BUSY && xBusy(pBusyArg) ); return rc; } /* ** The cache of the wal-index header must be valid to call this function. ** Return the page-size in bytes used by the database. */ | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 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 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 | if( rc!=SQLITE_OK ){ walIteratorFree(p); p = 0; } *pp = p; return rc; } #ifdef SQLITE_ENABLE_SETLK_TIMEOUT /* ** Attempt to enable blocking locks. Blocking locks are enabled only if (a) ** they are supported by the VFS, and (b) the database handle is configured ** with a busy-timeout. Return 1 if blocking locks are successfully enabled, ** or 0 otherwise. */ static int walEnableBlocking(Wal *pWal){ int res = 0; if( pWal->db ){ int tmout = pWal->db->busyTimeout; if( tmout ){ int rc; rc = sqlite3OsFileControl( pWal->pDbFd, SQLITE_FCNTL_LOCK_TIMEOUT, (void*)&tmout ); res = (rc==SQLITE_OK); } } return res; } /* ** Disable blocking locks. */ static void walDisableBlocking(Wal *pWal){ int tmout = 0; sqlite3OsFileControl(pWal->pDbFd, SQLITE_FCNTL_LOCK_TIMEOUT, (void*)&tmout); } /* ** If parameter bLock is true, attempt to enable blocking locks, take ** the WRITER lock, and then disable blocking locks. If blocking locks ** cannot be enabled, no attempt to obtain the WRITER lock is made. Return ** an SQLite error code if an error occurs, or SQLITE_OK otherwise. It is not ** an error if blocking locks can not be enabled. ** ** If the bLock parameter is false and the WRITER lock is held, release it. */ int sqlite3WalWriteLock(Wal *pWal, int bLock){ int rc = SQLITE_OK; assert( pWal->readLock<0 || bLock==0 ); if( bLock ){ assert( pWal->db ); if( walEnableBlocking(pWal) ){ rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1); if( rc==SQLITE_OK ){ pWal->writeLock = 1; } walDisableBlocking(pWal); } }else if( pWal->writeLock ){ walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1); pWal->writeLock = 0; } return rc; } /* ** Set the database handle used to determine if blocking locks are required. */ void sqlite3WalDb(Wal *pWal, sqlite3 *db){ pWal->db = db; } /* ** Take an exclusive WRITE lock. Blocking if so configured. */ static int walLockWriter(Wal *pWal){ int rc; walEnableBlocking(pWal); rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1); walDisableBlocking(pWal); return rc; } #else # define walEnableBlocking(x) 0 # define walDisableBlocking(x) # define walLockWriter(pWal) walLockExclusive((pWal), WAL_WRITE_LOCK, 1) # define sqlite3WalDb(pWal, db) #endif /* ifdef SQLITE_ENABLE_SETLK_TIMEOUT */ /* ** Attempt to obtain the exclusive WAL lock defined by parameters lockIdx and ** n. If the attempt fails and parameter xBusy is not NULL, then it is a ** busy-handler function. Invoke it and retry the lock until either the ** lock is successfully obtained or the busy-handler returns 0. */ static int walBusyLock( Wal *pWal, /* WAL connection */ int (*xBusy)(void*), /* Function to call when busy */ void *pBusyArg, /* Context argument for xBusyHandler */ int lockIdx, /* Offset of first byte to lock */ int n /* Number of bytes to lock */ ){ int rc; do { rc = walLockExclusive(pWal, lockIdx, n); }while( xBusy && rc==SQLITE_BUSY && xBusy(pBusyArg) ); #ifdef SQLITE_ENABLE_SETLK_TIMEOUT if( rc==SQLITE_BUSY_TIMEOUT ){ walDisableBlocking(pWal); rc = SQLITE_BUSY; } #endif return rc; } /* ** The cache of the wal-index header must be valid to call this function. ** Return the page-size in bytes used by the database. */ |
︙ | ︙ | |||
1736 1737 1738 1739 1740 1741 1742 | int i; /* Loop counter */ u32 *aSalt = pWal->hdr.aSalt; /* Big-endian salt values */ pWal->nCkpt++; pWal->hdr.mxFrame = 0; sqlite3Put4byte((u8*)&aSalt[0], 1 + sqlite3Get4byte((u8*)&aSalt[0])); memcpy(&pWal->hdr.aSalt[1], &salt1, 4); walIndexWriteHdr(pWal); | | | 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 | int i; /* Loop counter */ u32 *aSalt = pWal->hdr.aSalt; /* Big-endian salt values */ pWal->nCkpt++; pWal->hdr.mxFrame = 0; sqlite3Put4byte((u8*)&aSalt[0], 1 + sqlite3Get4byte((u8*)&aSalt[0])); memcpy(&pWal->hdr.aSalt[1], &salt1, 4); walIndexWriteHdr(pWal); AtomicStore(&pInfo->nBackfill, 0); pInfo->nBackfillAttempted = 0; pInfo->aReadMark[1] = 0; for(i=2; i<WAL_NREADER; i++) pInfo->aReadMark[i] = READMARK_NOT_USED; assert( pInfo->aReadMark[0]==0 ); } /* |
︙ | ︙ | |||
1811 1812 1813 1814 1815 1816 1817 | ** safe to write into the database. Frames beyond mxSafeFrame might ** overwrite database pages that are in use by active readers and thus ** cannot be backfilled from the WAL. */ mxSafeFrame = pWal->hdr.mxFrame; mxPage = pWal->hdr.nPage; for(i=1; i<WAL_NREADER; i++){ | < < < < < < < < | | > | > > > > > > > > | | | > | > | | 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 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 | ** safe to write into the database. Frames beyond mxSafeFrame might ** overwrite database pages that are in use by active readers and thus ** cannot be backfilled from the WAL. */ mxSafeFrame = pWal->hdr.mxFrame; mxPage = pWal->hdr.nPage; for(i=1; i<WAL_NREADER; i++){ u32 y = AtomicLoad(pInfo->aReadMark+i); if( mxSafeFrame>y ){ assert( y<=pWal->hdr.mxFrame ); rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(i), 1); if( rc==SQLITE_OK ){ u32 iMark = (i==1 ? mxSafeFrame : READMARK_NOT_USED); AtomicStore(pInfo->aReadMark+i, iMark); walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1); }else if( rc==SQLITE_BUSY ){ mxSafeFrame = y; xBusy = 0; }else{ goto walcheckpoint_out; } } } /* Allocate the iterator */ if( pInfo->nBackfill<mxSafeFrame ){ rc = walIteratorInit(pWal, pInfo->nBackfill, &pIter); assert( rc==SQLITE_OK || pIter==0 ); } if( pIter && (rc = walBusyLock(pWal,xBusy,pBusyArg,WAL_READ_LOCK(0),1))==SQLITE_OK ){ u32 nBackfill = pInfo->nBackfill; pInfo->nBackfillAttempted = mxSafeFrame; /* Sync the WAL to disk */ rc = sqlite3OsSync(pWal->pWalFd, CKPT_SYNC_FLAGS(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); i64 nSize; /* Current size of database file */ sqlite3OsFileControl(pWal->pDbFd, SQLITE_FCNTL_CKPT_START, 0); rc = sqlite3OsFileSize(pWal->pDbFd, &nSize); if( rc==SQLITE_OK && nSize<nReq ){ if( (nSize+65536+(i64)pWal->hdr.mxFrame*szPage)<nReq ){ /* If the size of the final database is larger than the current ** database plus the amount of data in the wal file, plus the ** maximum size of the pending-byte page (65536 bytes), then ** must be corruption somewhere. */ rc = SQLITE_CORRUPT_BKPT; }else{ 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( AtomicLoad(&db->u1.isInterrupted) ){ rc = db->mallocFailed ? SQLITE_NOMEM_BKPT : SQLITE_INTERRUPT; break; } if( iFrame<=nBackfill || iFrame>mxSafeFrame || iDbpage>mxPage ){ continue; } iOffset = walFrameOffset(iFrame, szPage) + WAL_FRAME_HDRSIZE; /* testcase( IS_BIG_INT(iOffset) ); // requires a 4GiB WAL file */ rc = sqlite3OsRead(pWal->pWalFd, zBuf, szPage, iOffset); if( rc!=SQLITE_OK ) break; iOffset = (iDbpage-1)*(i64)szPage; testcase( IS_BIG_INT(iOffset) ); rc = sqlite3OsWrite(pWal->pDbFd, zBuf, szPage, iOffset); if( rc!=SQLITE_OK ) break; } sqlite3OsFileControl(pWal->pDbFd, SQLITE_FCNTL_CKPT_DONE, 0); /* If work was actually accomplished... */ if( rc==SQLITE_OK ){ if( mxSafeFrame==walIndexHdr(pWal)->mxFrame ){ i64 szDb = pWal->hdr.nPage*(i64)szPage; testcase( IS_BIG_INT(szDb) ); rc = sqlite3OsTruncate(pWal->pDbFd, szDb); if( rc==SQLITE_OK ){ rc = sqlite3OsSync(pWal->pDbFd, CKPT_SYNC_FLAGS(sync_flags)); } } if( rc==SQLITE_OK ){ AtomicStore(&pInfo->nBackfill, mxSafeFrame); } } /* Release the reader lock held while backfilling */ walUnlockExclusive(pWal, WAL_READ_LOCK(0), 1); } |
︙ | ︙ | |||
1922 1923 1924 1925 1926 1927 1928 | */ if( rc==SQLITE_OK && eMode!=SQLITE_CHECKPOINT_PASSIVE ){ assert( pWal->writeLock ); if( pInfo->nBackfill<pWal->hdr.mxFrame ){ rc = SQLITE_BUSY; }else if( eMode>=SQLITE_CHECKPOINT_RESTART ){ u32 salt1; | | | 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 | */ if( rc==SQLITE_OK && eMode!=SQLITE_CHECKPOINT_PASSIVE ){ assert( pWal->writeLock ); if( pInfo->nBackfill<pWal->hdr.mxFrame ){ rc = SQLITE_BUSY; }else if( eMode>=SQLITE_CHECKPOINT_RESTART ){ u32 salt1; sqlite3FastRandomness(&pWal->sPrng, 4, &salt1); assert( pInfo->nBackfill==pWal->hdr.mxFrame ); rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(1), WAL_NREADER-1); if( rc==SQLITE_OK ){ if( eMode==SQLITE_CHECKPOINT_TRUNCATE ){ /* IMPLEMENTATION-OF: R-44699-57140 This mode works the same way as ** SQLITE_CHECKPOINT_RESTART with the addition that it also ** truncates the log file to zero bytes just prior to a |
︙ | ︙ | |||
2098 2099 2100 2101 2102 2103 2104 | ** If and only if the read is consistent and the header is different from ** pWal->hdr, then pWal->hdr is updated to the content of the new header ** and *pChanged is set to 1. ** ** If the checksum cannot be verified return non-zero. If the header ** is read successfully and the checksum verified, return zero. */ | | | 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 | ** If and only if the read is consistent and the header is different from ** pWal->hdr, then pWal->hdr is updated to the content of the new header ** and *pChanged is set to 1. ** ** If the checksum cannot be verified return non-zero. If the header ** is read successfully and the checksum verified, return zero. */ static SQLITE_NO_TSAN int walIndexTryHdr(Wal *pWal, int *pChanged){ WalIndexHdr h1; /* Copy of the header content */ if( walIndexLoadHdr(pWal, &h1) ){ return 1; } if( memcmp(&pWal->hdr, &h1, sizeof(WalIndexHdr)) ){ |
︙ | ︙ | |||
2180 2181 2182 2183 2184 2185 2186 | ** being modified by another thread or process. */ badHdr = (page0 ? walIndexTryHdr(pWal, pChanged) : 1); /* If the first attempt failed, it might have been due to a race ** with a writer. So get a WRITE lock and try again. */ | < > > | | | | | | | | | | | | | > | | > > | 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 | ** being modified by another thread or process. */ badHdr = (page0 ? walIndexTryHdr(pWal, pChanged) : 1); /* If the first attempt failed, it might have been due to a race ** with a writer. So get a WRITE lock and try again. */ if( badHdr ){ if( pWal->bShmUnreliable==0 && (pWal->readOnly & WAL_SHM_RDONLY) ){ if( SQLITE_OK==(rc = walLockShared(pWal, WAL_WRITE_LOCK)) ){ walUnlockShared(pWal, WAL_WRITE_LOCK); rc = SQLITE_READONLY_RECOVERY; } }else{ int bWriteLock = pWal->writeLock; if( bWriteLock || SQLITE_OK==(rc = walLockWriter(pWal)) ){ pWal->writeLock = 1; if( SQLITE_OK==(rc = walIndexPage(pWal, 0, &page0)) ){ badHdr = walIndexTryHdr(pWal, pChanged); if( badHdr ){ /* If the wal-index header is still malformed even while holding ** a WRITE lock, it can only mean that the header is corrupted and ** needs to be reconstructed. So run recovery to do exactly that. */ rc = walIndexRecover(pWal); *pChanged = 1; } } if( bWriteLock==0 ){ pWal->writeLock = 0; walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1); } } } } /* If the header is read successfully, check the version number to make ** sure the wal-index was not constructed with some future format that ** this version of SQLite cannot understand. */ |
︙ | ︙ | |||
2531 2532 2533 2534 2535 2536 2537 | return walBeginShmUnreliable(pWal, pChanged); } } assert( pWal->nWiData>0 ); assert( pWal->apWiData[0]!=0 ); pInfo = walCkptInfo(pWal); | | | 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 | return walBeginShmUnreliable(pWal, pChanged); } } assert( pWal->nWiData>0 ); assert( pWal->apWiData[0]!=0 ); pInfo = walCkptInfo(pWal); if( !useWal && AtomicLoad(&pInfo->nBackfill)==pWal->hdr.mxFrame #ifdef SQLITE_ENABLE_SNAPSHOT && (pWal->pSnapshot==0 || pWal->hdr.mxFrame==0) #endif ){ /* The WAL has been completely backfilled (or it is empty). ** and can be safely ignored. */ |
︙ | ︙ | |||
2593 2594 2595 2596 2597 2598 2599 | } if( (pWal->readOnly & WAL_SHM_RDONLY)==0 && (mxReadMark<mxFrame || mxI==0) ){ for(i=1; i<WAL_NREADER; i++){ rc = walLockExclusive(pWal, WAL_READ_LOCK(i), 1); if( rc==SQLITE_OK ){ | | > | 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 | } if( (pWal->readOnly & WAL_SHM_RDONLY)==0 && (mxReadMark<mxFrame || mxI==0) ){ for(i=1; i<WAL_NREADER; i++){ rc = walLockExclusive(pWal, WAL_READ_LOCK(i), 1); if( rc==SQLITE_OK ){ AtomicStore(pInfo->aReadMark+i,mxFrame); mxReadMark = mxFrame; mxI = i; walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1); break; }else if( rc!=SQLITE_BUSY ){ return rc; } } |
︙ | ︙ | |||
2697 2698 2699 2700 2701 2702 2703 | if( rc==SQLITE_OK ){ void *pBuf1 = sqlite3_malloc(szPage); void *pBuf2 = sqlite3_malloc(szPage); if( pBuf1==0 || pBuf2==0 ){ rc = SQLITE_NOMEM; }else{ u32 i = pInfo->nBackfillAttempted; | | > | | 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 | if( rc==SQLITE_OK ){ void *pBuf1 = sqlite3_malloc(szPage); void *pBuf2 = sqlite3_malloc(szPage); if( pBuf1==0 || pBuf2==0 ){ rc = SQLITE_NOMEM; }else{ u32 i = pInfo->nBackfillAttempted; for(i=pInfo->nBackfillAttempted; i>AtomicLoad(&pInfo->nBackfill); i--){ WalHashLoc sLoc; /* Hash table location */ u32 pgno; /* Page number in db file */ i64 iDbOff; /* Offset of db file entry */ i64 iWalOff; /* Offset of wal file entry */ rc = walHashGet(pWal, walFramePage(i), &sLoc); if( rc!=SQLITE_OK ) break; assert( i - sLoc.iZero - 1 >=0 ); pgno = sLoc.aPgno[i-sLoc.iZero-1]; iDbOff = (i64)(pgno-1) * szPage; if( iDbOff+szPage<=szDb ){ iWalOff = walFrameOffset(i, szPage) + WAL_FRAME_HDRSIZE; rc = sqlite3OsRead(pWal->pWalFd, pBuf1, szPage, iWalOff); if( rc==SQLITE_OK ){ |
︙ | ︙ | |||
2752 2753 2754 2755 2756 2757 2758 | ** transaction, then *pChanged is set to 1 before returning. The ** Pager layer will use this to know that its cache is stale and ** needs to be flushed. */ int sqlite3WalBeginReadTransaction(Wal *pWal, int *pChanged){ int rc; /* Return code */ int cnt = 0; /* Number of TryBeginRead attempts */ | < > > > > > > | | > > > > > > > > > > > > > > > > > > | 3018 3019 3020 3021 3022 3023 3024 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 | ** transaction, then *pChanged is set to 1 before returning. The ** Pager layer will use this to know that its cache is stale and ** needs to be flushed. */ int sqlite3WalBeginReadTransaction(Wal *pWal, int *pChanged){ int rc; /* Return code */ int cnt = 0; /* Number of TryBeginRead attempts */ #ifdef SQLITE_ENABLE_SNAPSHOT int bChanged = 0; WalIndexHdr *pSnapshot = pWal->pSnapshot; #endif assert( pWal->ckptLock==0 ); #ifdef SQLITE_ENABLE_SNAPSHOT if( pSnapshot ){ if( memcmp(pSnapshot, &pWal->hdr, sizeof(WalIndexHdr))!=0 ){ bChanged = 1; } /* It is possible that there is a checkpointer thread running ** concurrent with this code. If this is the case, it may be that the ** checkpointer has already determined that it will checkpoint ** snapshot X, where X is later in the wal file than pSnapshot, but ** has not yet set the pInfo->nBackfillAttempted variable to indicate ** its intent. To avoid the race condition this leads to, ensure that ** there is no checkpointer process by taking a shared CKPT lock ** before checking pInfo->nBackfillAttempted. */ (void)walEnableBlocking(pWal); rc = walLockShared(pWal, WAL_CKPT_LOCK); walDisableBlocking(pWal); if( rc!=SQLITE_OK ){ return rc; } pWal->ckptLock = 1; } #endif do{ rc = walTryBeginRead(pWal, pChanged, 0, ++cnt); }while( rc==WAL_RETRY ); testcase( (rc&0xff)==SQLITE_BUSY ); |
︙ | ︙ | |||
2791 2792 2793 2794 2795 2796 2797 | ** checkpoint need not have completed for this to cause problems. */ volatile WalCkptInfo *pInfo = walCkptInfo(pWal); assert( pWal->readLock>0 || pWal->hdr.mxFrame==0 ); assert( pInfo->aReadMark[pWal->readLock]<=pSnapshot->mxFrame ); | < < < < < < < < < < < < < < < | | | | | | | | | | | | | | | > > > > > | < | < < > > > > > > > | 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 | ** checkpoint need not have completed for this to cause problems. */ volatile WalCkptInfo *pInfo = walCkptInfo(pWal); assert( pWal->readLock>0 || pWal->hdr.mxFrame==0 ); assert( pInfo->aReadMark[pWal->readLock]<=pSnapshot->mxFrame ); /* Check that the wal file has not been wrapped. Assuming that it has ** not, also check that no checkpointer has attempted to checkpoint any ** frames beyond pSnapshot->mxFrame. If either of these conditions are ** true, return SQLITE_ERROR_SNAPSHOT. Otherwise, overwrite pWal->hdr ** with *pSnapshot and set *pChanged as appropriate for opening the ** snapshot. */ if( !memcmp(pSnapshot->aSalt, pWal->hdr.aSalt, sizeof(pWal->hdr.aSalt)) && pSnapshot->mxFrame>=pInfo->nBackfillAttempted ){ assert( pWal->readLock>0 ); memcpy(&pWal->hdr, pSnapshot, sizeof(WalIndexHdr)); *pChanged = bChanged; }else{ rc = SQLITE_ERROR_SNAPSHOT; } /* A client using a non-current snapshot may not ignore any frames ** from the start of the wal file. This is because, for a system ** where (minFrame < iSnapshot < maxFrame), a checkpointer may ** have omitted to checkpoint a frame earlier than minFrame in ** the file because there exists a frame after iSnapshot that ** is the same database page. */ pWal->minFrame = 1; if( rc!=SQLITE_OK ){ sqlite3WalEndReadTransaction(pWal); } } } /* Release the shared CKPT lock obtained above. */ if( pWal->ckptLock ){ assert( pSnapshot ); walUnlockShared(pWal, WAL_CKPT_LOCK); pWal->ckptLock = 0; } #endif return rc; } /* ** Finish with a read transaction. All this does is release the ** read-lock. |
︙ | ︙ | |||
2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 | */ iMinHash = walFramePage(pWal->minFrame); for(iHash=walFramePage(iLast); iHash>=iMinHash; iHash--){ WalHashLoc sLoc; /* Hash table location */ int iKey; /* Hash slot index */ int nCollide; /* Number of hash collisions remaining */ int rc; /* Error code */ rc = walHashGet(pWal, iHash, &sLoc); if( rc!=SQLITE_OK ){ return rc; } nCollide = HASHTABLE_NSLOT; | > | > | | < > | 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 | */ iMinHash = walFramePage(pWal->minFrame); for(iHash=walFramePage(iLast); iHash>=iMinHash; iHash--){ WalHashLoc sLoc; /* Hash table location */ int iKey; /* Hash slot index */ int nCollide; /* Number of hash collisions remaining */ int rc; /* Error code */ u32 iH; rc = walHashGet(pWal, iHash, &sLoc); if( rc!=SQLITE_OK ){ return rc; } nCollide = HASHTABLE_NSLOT; iKey = walHash(pgno); while( (iH = AtomicLoad(&sLoc.aHash[iKey]))!=0 ){ u32 iFrame = iH + sLoc.iZero; if( iFrame<=iLast && iFrame>=pWal->minFrame && sLoc.aPgno[iH-1]==pgno ){ assert( iFrame>iRead || CORRUPT_DB ); iRead = iFrame; } if( (nCollide--)==0 ){ return SQLITE_CORRUPT_BKPT; } iKey = walNextHash(iKey); } if( iRead ) break; } #ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT /* If expensive assert() statements are available, do a linear search ** of the wal-index file content. Make sure the results agree with the |
︙ | ︙ | |||
3029 3030 3031 3032 3033 3034 3035 | ** the read transaction was started, then it is not possible for this ** thread to write as doing so would cause a fork. So this routine ** returns SQLITE_BUSY in that case and no write transaction is started. ** ** There can only be a single writer active at a time. */ int sqlite3WalBeginWriteTransaction(Wal *pWal){ | > > > > > > > > > > > > | | 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 | ** the read transaction was started, then it is not possible for this ** thread to write as doing so would cause a fork. So this routine ** returns SQLITE_BUSY in that case and no write transaction is started. ** ** There can only be a single writer active at a time. */ int sqlite3WalBeginWriteTransaction(Wal *pWal){ int rc; #ifdef SQLITE_ENABLE_SETLK_TIMEOUT /* If the write-lock is already held, then it was obtained before the ** read-transaction was even opened, making this call a no-op. ** Return early. */ if( pWal->writeLock ){ assert( !memcmp(&pWal->hdr,(void *)walIndexHdr(pWal),sizeof(WalIndexHdr)) ); return SQLITE_OK; } #endif rc = walWriteLock(pWal); if( rc==SQLITE_OK ){ /* If another connection has written to the database file since the ** time the read transaction on this connection was started, then ** the write is disallowed. Release the WRITER lock and return ** SQLITE_BUSY_SNAPSHOT in this case. */ if( memcmp(&pWal->hdr, (void *)walIndexHdr(pWal), sizeof(WalIndexHdr))!=0 ){ walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1); |
︙ | ︙ | |||
3101 3102 3103 3104 3105 3106 3107 | ** lock cannot be obtained. Or, if the WRITER lock can be obtained but there ** are conflicts with a committed transaction, SQLITE_BUSY_SNAPSHOT. Finally, ** if an error (i.e. an OOM condition or IO error), an SQLite error code ** is returned. */ int sqlite3WalLockForCommit( Wal *pWal, | | < | 3398 3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 | ** lock cannot be obtained. Or, if the WRITER lock can be obtained but there ** are conflicts with a committed transaction, SQLITE_BUSY_SNAPSHOT. Finally, ** if an error (i.e. an OOM condition or IO error), an SQLite error code ** is returned. */ int sqlite3WalLockForCommit( Wal *pWal, PgHdr *pPg1, Bitvec *pAllRead, Pgno *piConflict ){ int rc = walWriteLock(pWal); /* If the database has been modified since this transaction was started, ** check if it is still possible to commit. The transaction can be ** committed if: ** ** a) None of the pages in pList have been modified since the |
︙ | ︙ | |||
3129 3130 3131 3132 3133 3134 3135 | /* This branch is taken if the wal-index header is corrupted. This ** occurs if some other writer has crashed while committing a ** transaction to this database since the current concurrent transaction ** was opened. */ rc = SQLITE_BUSY_SNAPSHOT; }else if( memcmp(&pWal->hdr, (void*)&head, sizeof(WalIndexHdr))!=0 ){ int iHash; | | > > > > > > | | | | | > | | | 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 | /* This branch is taken if the wal-index header is corrupted. This ** occurs if some other writer has crashed while committing a ** transaction to this database since the current concurrent transaction ** was opened. */ rc = SQLITE_BUSY_SNAPSHOT; }else if( memcmp(&pWal->hdr, (void*)&head, sizeof(WalIndexHdr))!=0 ){ int iHash; int iLast = walFramePage(head.mxFrame); u32 iFirst = pWal->hdr.mxFrame+1; /* First wal frame to check */ if( memcmp(pWal->hdr.aSalt, (u32*)head.aSalt, sizeof(u32)*2) ){ assert( pWal->readLock==0 ); iFirst = 1; } if( pPg1==0 ){ /* If pPg1==0, then the current transaction modified the database ** schema. This means it conflicts with all other transactions. */ *piConflict = 1; rc = SQLITE_BUSY_SNAPSHOT; } for(iHash=walFramePage(iFirst); rc==SQLITE_OK && iHash<=iLast; iHash++){ WalHashLoc sLoc; rc = walHashGet(pWal, iHash, &sLoc); if( rc==SQLITE_OK ){ u32 i, iMin, iMax; assert( head.mxFrame>=sLoc.iZero ); iMin = (sLoc.iZero >= iFirst) ? 1 : (iFirst - sLoc.iZero); iMax = (iHash==0) ? HASHTABLE_NPAGE_ONE : HASHTABLE_NPAGE; if( iMax>(head.mxFrame-sLoc.iZero) ) iMax = (head.mxFrame-sLoc.iZero); for(i=iMin; rc==SQLITE_OK && i<=iMax; i++){ PgHdr *pPg; if( sLoc.aPgno[i-1]==1 ){ /* Check that the schema cookie has not been modified. If ** it has not, the commit can proceed. */ u8 aNew[4]; u8 *aOld = &((u8*)pPg1->pData)[40]; int sz; i64 iOffset; sz = pWal->hdr.szPage; sz = (sz&0xfe00) + ((sz&0x0001)<<16); iOffset = walFrameOffset(i+sLoc.iZero, sz) + WAL_FRAME_HDRSIZE+40; rc = sqlite3OsRead(pWal->pWalFd, aNew, sizeof(aNew), iOffset); if( rc==SQLITE_OK && memcmp(aOld, aNew, sizeof(aNew)) ){ rc = SQLITE_BUSY_SNAPSHOT; } }else if( sqlite3BitvecTestNotNull(pAllRead, sLoc.aPgno[i-1]) ){ *piConflict = sLoc.aPgno[i-1]; rc = SQLITE_BUSY_SNAPSHOT; }else if( (pPg = sqlite3PagerLookup(pPg1->pPager, sLoc.aPgno[i-1])) ){ /* Page aPgno[i-1], which is present in the pager cache, has been ** modified since the current CONCURRENT transaction was started. ** However it was not read by the current transaction, so is not ** a conflict. There are two possibilities: (a) the page was ** allocated at the of the file by the current transaction or ** (b) was present in the cache at the start of the transaction. ** ** For case (a), do nothing. This page will be moved within the |
︙ | ︙ | |||
3188 3189 3190 3191 3192 3193 3194 | sqlite3PagerUnref(pPg); }else{ sqlite3PcacheDrop(pPg); } } } } | < | 3491 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 3504 | sqlite3PagerUnref(pPg); }else{ sqlite3PcacheDrop(pPg); } } } } } } } pWal->nPriorFrame = pWal->hdr.mxFrame; return rc; } |
︙ | ︙ | |||
3252 3253 3254 3255 3256 3257 3258 | ** to the WAL since the start of the transaction. If the callback returns ** other than SQLITE_OK, it is not invoked again and the error code is ** returned to the caller. ** ** Otherwise, if the callback function does not return an error, this ** function returns SQLITE_OK. */ | | > > > > > > > > > > > > | 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 3587 3588 3589 | ** to the WAL since the start of the transaction. If the callback returns ** other than SQLITE_OK, it is not invoked again and the error code is ** returned to the caller. ** ** Otherwise, if the callback function does not return an error, this ** function returns SQLITE_OK. */ int sqlite3WalUndo( Wal *pWal, int (*xUndo)(void *, Pgno), void *pUndoCtx, int bConcurrent /* True if this is a CONCURRENT transaction */ ){ int rc = SQLITE_OK; if( pWal->writeLock ){ Pgno iMax = pWal->hdr.mxFrame; Pgno iFrame; /* Restore the clients cache of the wal-index header to the state it ** was in before the client began writing to the database. */ memcpy(&pWal->hdr, (void *)walIndexHdr(pWal), sizeof(WalIndexHdr)); #ifndef SQLITE_OMIT_CONCURRENT if( bConcurrent ){ pWal->hdr.aCksum[0]++; } #else UNUSED_PARAMETER(bConcurrent); #endif for(iFrame=pWal->hdr.mxFrame+1; ALWAYS(rc==SQLITE_OK) && iFrame<=iMax; iFrame++ ){ /* This call cannot fail. Unless the page for which the page number ** is passed as the second argument is (a) in the cache and |
︙ | ︙ | |||
3350 3351 3352 3353 3354 3355 3356 | int rc = SQLITE_OK; if( pWal->readLock==0 ){ volatile WalCkptInfo *pInfo = walCkptInfo(pWal); assert( pInfo->nBackfill==pWal->hdr.mxFrame ); if( pInfo->nBackfill>0 ){ u32 salt1; | | | 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 3676 3677 3678 | int rc = SQLITE_OK; if( pWal->readLock==0 ){ volatile WalCkptInfo *pInfo = walCkptInfo(pWal); assert( pInfo->nBackfill==pWal->hdr.mxFrame ); if( pInfo->nBackfill>0 ){ u32 salt1; sqlite3FastRandomness(&pWal->sPrng, 4, &salt1); rc = walLockExclusive(pWal, WAL_READ_LOCK(1), WAL_NREADER-1); if( rc==SQLITE_OK ){ /* If all readers are using WAL_READ_LOCK(0) (in other words if no ** readers are currently using the WAL), then the transactions ** frames will overwrite the start of the existing log. Update the ** wal-index header to reflect this. ** |
︙ | ︙ | |||
3438 3439 3440 3441 3442 3443 3444 | PgHdr *pPage, /* The page of the frame to be written */ int nTruncate, /* The commit flag. Usually 0. >0 for commit */ sqlite3_int64 iOffset /* Byte offset at which to write */ ){ int rc; /* Result code from subfunctions */ void *pData; /* Data actually written */ u8 aFrame[WAL_FRAME_HDRSIZE]; /* Buffer to assemble frame-header in */ | < < < < | 3752 3753 3754 3755 3756 3757 3758 3759 3760 3761 3762 3763 3764 3765 3766 | PgHdr *pPage, /* The page of the frame to be written */ int nTruncate, /* The commit flag. Usually 0. >0 for commit */ sqlite3_int64 iOffset /* Byte offset at which to write */ ){ int rc; /* Result code from subfunctions */ void *pData; /* Data actually written */ u8 aFrame[WAL_FRAME_HDRSIZE]; /* Buffer to assemble frame-header in */ pData = pPage->pData; walEncodeFrame(p->pWal, pPage->pgno, nTruncate, pData, aFrame); rc = walWriteToLog(p, aFrame, sizeof(aFrame), iOffset); if( rc ) return rc; /* Write the page data */ rc = walWriteToLog(p, pData, p->szPage, iOffset+sizeof(aFrame)); return rc; } |
︙ | ︙ | |||
3566 3567 3568 3569 3570 3571 3572 | u8 aWalHdr[WAL_HDRSIZE]; /* Buffer to assemble wal-header in */ u32 aCksum[2]; /* Checksum for wal-header */ sqlite3Put4byte(&aWalHdr[0], (WAL_MAGIC | SQLITE_BIGENDIAN)); sqlite3Put4byte(&aWalHdr[4], WAL_MAX_VERSION); sqlite3Put4byte(&aWalHdr[8], szPage); sqlite3Put4byte(&aWalHdr[12], pWal->nCkpt); | | | 3876 3877 3878 3879 3880 3881 3882 3883 3884 3885 3886 3887 3888 3889 3890 | u8 aWalHdr[WAL_HDRSIZE]; /* Buffer to assemble wal-header in */ u32 aCksum[2]; /* Checksum for wal-header */ sqlite3Put4byte(&aWalHdr[0], (WAL_MAGIC | SQLITE_BIGENDIAN)); sqlite3Put4byte(&aWalHdr[4], WAL_MAX_VERSION); sqlite3Put4byte(&aWalHdr[8], szPage); sqlite3Put4byte(&aWalHdr[12], pWal->nCkpt); if( pWal->nCkpt==0 ) sqlite3FastRandomness(&pWal->sPrng, 8, pWal->hdr.aSalt); memcpy(&aWalHdr[16], pWal->hdr.aSalt, 8); walChecksumBytes(1, aWalHdr, WAL_HDRSIZE-2*4, 0, aCksum); sqlite3Put4byte(&aWalHdr[24], aCksum[0]); sqlite3Put4byte(&aWalHdr[28], aCksum[1]); pWal->szPage = szPage; pWal->hdr.bigEndCksum = SQLITE_BIGENDIAN; |
︙ | ︙ | |||
3625 3626 3627 3628 3629 3630 3631 | assert( rc==SQLITE_OK || iWrite==0 ); if( iWrite>=iFirst ){ i64 iOff = walFrameOffset(iWrite, szPage) + WAL_FRAME_HDRSIZE; void *pData; if( pWal->iReCksum==0 || iWrite<pWal->iReCksum ){ pWal->iReCksum = iWrite; } | < < < < | 3935 3936 3937 3938 3939 3940 3941 3942 3943 3944 3945 3946 3947 3948 3949 | assert( rc==SQLITE_OK || iWrite==0 ); if( iWrite>=iFirst ){ i64 iOff = walFrameOffset(iWrite, szPage) + WAL_FRAME_HDRSIZE; void *pData; if( pWal->iReCksum==0 || iWrite<pWal->iReCksum ){ pWal->iReCksum = iWrite; } pData = p->pData; rc = sqlite3OsWrite(pWal->pWalFd, pData, szPage, iOff); if( rc ) return rc; p->flags &= ~PGHDR_WAL_APPEND; continue; } } |
︙ | ︙ | |||
3680 3681 3682 3683 3684 3685 3686 3687 3688 3689 3690 3691 3692 3693 | bSync = (w.iSyncPoint==iOffset); testcase( bSync ); while( iOffset<w.iSyncPoint ){ rc = walWriteOneFrame(&w, pLast, nTruncate, iOffset); if( rc ) return rc; iOffset += szFrame; nExtra++; } } if( bSync ){ assert( rc==SQLITE_OK ); rc = sqlite3OsSync(w.pFd, WAL_SYNC_FLAGS(sync_flags)); } } | > | 3986 3987 3988 3989 3990 3991 3992 3993 3994 3995 3996 3997 3998 3999 4000 | bSync = (w.iSyncPoint==iOffset); testcase( bSync ); while( iOffset<w.iSyncPoint ){ rc = walWriteOneFrame(&w, pLast, nTruncate, iOffset); if( rc ) return rc; iOffset += szFrame; nExtra++; assert( pLast!=0 ); } } if( bSync ){ assert( rc==SQLITE_OK ); rc = sqlite3OsSync(w.pFd, WAL_SYNC_FLAGS(sync_flags)); } } |
︙ | ︙ | |||
3712 3713 3714 3715 3716 3717 3718 3719 3720 3721 3722 3723 3724 3725 | */ iFrame = pWal->hdr.mxFrame; for(p=pList; p && rc==SQLITE_OK; p=p->pDirty){ if( (p->flags & PGHDR_WAL_APPEND)==0 ) continue; iFrame++; rc = walIndexAppend(pWal, iFrame, p->pgno); } while( rc==SQLITE_OK && nExtra>0 ){ iFrame++; nExtra--; rc = walIndexAppend(pWal, iFrame, pLast->pgno); } if( rc==SQLITE_OK ){ | > | 4019 4020 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 | */ iFrame = pWal->hdr.mxFrame; for(p=pList; p && rc==SQLITE_OK; p=p->pDirty){ if( (p->flags & PGHDR_WAL_APPEND)==0 ) continue; iFrame++; rc = walIndexAppend(pWal, iFrame, p->pgno); } assert( pLast!=0 || nExtra==0 ); while( rc==SQLITE_OK && nExtra>0 ){ iFrame++; nExtra--; rc = walIndexAppend(pWal, iFrame, pLast->pgno); } if( rc==SQLITE_OK ){ |
︙ | ︙ | |||
3776 3777 3778 3779 3780 3781 3782 3783 | /* EVIDENCE-OF: R-62920-47450 The busy-handler callback is never invoked ** in the SQLITE_CHECKPOINT_PASSIVE mode. */ assert( eMode!=SQLITE_CHECKPOINT_PASSIVE || xBusy==0 ); if( pWal->readOnly ) return SQLITE_READONLY; WALTRACE(("WAL%p: checkpoint begins\n", pWal)); /* IMPLEMENTATION-OF: R-62028-47212 All calls obtain an exclusive | > > > > > | < < | | | | | | > | | | < | | | | | | | | | | | | | | | | | | | | | > > > > | 4084 4085 4086 4087 4088 4089 4090 4091 4092 4093 4094 4095 4096 4097 4098 4099 4100 4101 4102 4103 4104 4105 4106 4107 4108 4109 4110 4111 4112 4113 4114 4115 4116 4117 4118 4119 4120 4121 4122 4123 4124 4125 4126 4127 4128 4129 4130 4131 4132 4133 4134 4135 4136 4137 4138 4139 4140 4141 4142 4143 | /* EVIDENCE-OF: R-62920-47450 The busy-handler callback is never invoked ** in the SQLITE_CHECKPOINT_PASSIVE mode. */ assert( eMode!=SQLITE_CHECKPOINT_PASSIVE || xBusy==0 ); if( pWal->readOnly ) return SQLITE_READONLY; WALTRACE(("WAL%p: checkpoint begins\n", pWal)); /* Enable blocking locks, if possible. If blocking locks are successfully ** enabled, set xBusy2=0 so that the busy-handler is never invoked. */ sqlite3WalDb(pWal, db); (void)walEnableBlocking(pWal); /* IMPLEMENTATION-OF: R-62028-47212 All calls obtain an exclusive ** "checkpoint" lock on the database file. ** EVIDENCE-OF: R-10421-19736 If any other process is running a ** checkpoint operation at the same time, the lock cannot be obtained and ** SQLITE_BUSY is returned. ** EVIDENCE-OF: R-53820-33897 Even if there is a busy-handler configured, ** it will not be invoked in this case. */ rc = walLockExclusive(pWal, WAL_CKPT_LOCK, 1); testcase( rc==SQLITE_BUSY ); testcase( rc!=SQLITE_OK && xBusy2!=0 ); if( rc==SQLITE_OK ){ pWal->ckptLock = 1; /* IMPLEMENTATION-OF: R-59782-36818 The SQLITE_CHECKPOINT_FULL, RESTART and ** TRUNCATE modes also obtain the exclusive "writer" lock on the database ** file. ** ** EVIDENCE-OF: R-60642-04082 If the writer lock cannot be obtained ** immediately, and a busy-handler is configured, it is invoked and the ** writer lock retried until either the busy-handler returns 0 or the ** lock is successfully obtained. */ if( eMode!=SQLITE_CHECKPOINT_PASSIVE ){ rc = walBusyLock(pWal, xBusy2, pBusyArg, WAL_WRITE_LOCK, 1); if( rc==SQLITE_OK ){ pWal->writeLock = 1; }else if( rc==SQLITE_BUSY ){ eMode2 = SQLITE_CHECKPOINT_PASSIVE; xBusy2 = 0; rc = SQLITE_OK; } } } /* Read the wal-index header. */ if( rc==SQLITE_OK ){ walDisableBlocking(pWal); rc = walIndexReadHdr(pWal, &isChanged); (void)walEnableBlocking(pWal); 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 ){ |
︙ | ︙ | |||
3844 3845 3846 3847 3848 3849 3850 3851 3852 3853 | ** performed, then the pager-cache associated with pWal is now ** out of date. So zero the cached wal-index header to ensure that ** next time the pager opens a snapshot on this database it knows that ** the cache needs to be reset. */ memset(&pWal->hdr, 0, sizeof(WalIndexHdr)); } /* Release the locks. */ sqlite3WalEndWriteTransaction(pWal); | > > > > | | > > > > | 4159 4160 4161 4162 4163 4164 4165 4166 4167 4168 4169 4170 4171 4172 4173 4174 4175 4176 4177 4178 4179 4180 4181 4182 4183 4184 4185 4186 | ** performed, then the pager-cache associated with pWal is now ** out of date. So zero the cached wal-index header to ensure that ** next time the pager opens a snapshot on this database it knows that ** the cache needs to be reset. */ memset(&pWal->hdr, 0, sizeof(WalIndexHdr)); } walDisableBlocking(pWal); sqlite3WalDb(pWal, 0); /* Release the locks. */ sqlite3WalEndWriteTransaction(pWal); if( pWal->ckptLock ){ walUnlockExclusive(pWal, WAL_CKPT_LOCK, 1); pWal->ckptLock = 0; } WALTRACE(("WAL%p: checkpoint %s\n", pWal, rc ? "failed" : "ok")); #ifdef SQLITE_ENABLE_SETLK_TIMEOUT if( rc==SQLITE_BUSY_TIMEOUT ) rc = SQLITE_BUSY; #endif return (rc==SQLITE_OK && eMode!=eMode2 ? SQLITE_BUSY : rc); } /* Return the value to pass to a sqlite3_wal_hook callback, the ** number of frames in the WAL at the point of the last commit since ** sqlite3WalCallback() was called. If no commits have occurred since ** the last call, then return 0. |
︙ | ︙ | |||
3966 3967 3968 3969 3970 3971 3972 | } return rc; } /* Try to open on pSnapshot when the next read-transaction starts */ | | > > > | 4289 4290 4291 4292 4293 4294 4295 4296 4297 4298 4299 4300 4301 4302 4303 4304 4305 4306 | } return rc; } /* Try to open on pSnapshot when the next read-transaction starts */ void sqlite3WalSnapshotOpen( Wal *pWal, sqlite3_snapshot *pSnapshot ){ pWal->pSnapshot = (WalIndexHdr*)pSnapshot; } /* ** Return a +ve value if snapshot p1 is newer than p2. A -ve value if ** p1 is older than p2 and zero if p1 and p2 are the same snapshot. */ |
︙ | ︙ |
Changes to src/wal.h.
︙ | ︙ | |||
30 31 32 33 34 35 36 | # define sqlite3WalLimit(x,y) # define sqlite3WalClose(v,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 | | | 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | # define sqlite3WalLimit(x,y) # define sqlite3WalClose(v,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(w,x,y,z) 0 # define sqlite3WalSavepoint(y,z) # define sqlite3WalSavepointUndo(y,z) 0 # define sqlite3WalFrames(u,v,w,x,y,z) 0 # define sqlite3WalCheckpoint(q,r,s,t,u,v,w,x,y,z) 0 # define sqlite3WalCallback(z) 0 # define sqlite3WalExclusiveMode(y,z) 0 # define sqlite3WalHeapMemory(z) 0 |
︙ | ︙ | |||
79 80 81 82 83 84 85 | Pgno sqlite3WalDbsize(Wal *pWal); /* Obtain or release the WRITER lock. */ int sqlite3WalBeginWriteTransaction(Wal *pWal); int sqlite3WalEndWriteTransaction(Wal *pWal); /* Undo any frames written (but not committed) to the log */ | | | 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 | Pgno sqlite3WalDbsize(Wal *pWal); /* Obtain or release the WRITER lock. */ int sqlite3WalBeginWriteTransaction(Wal *pWal); int sqlite3WalEndWriteTransaction(Wal *pWal); /* Undo any frames written (but not committed) to the log */ int sqlite3WalUndo(Wal *pWal, int (*xUndo)(void *, Pgno), void *pUndoCtx, int); /* Return an integer that records the current (uncommitted) write ** position in the WAL */ void sqlite3WalSavepoint(Wal *pWal, u32 *aWalData); /* Move the write position of the WAL back to iFrame. Called in ** response to a ROLLBACK TO command. */ |
︙ | ︙ | |||
150 151 152 153 154 155 156 157 158 159 160 161 162 | ** stored in each frame (i.e. the db page-size when the WAL was created). */ int sqlite3WalFramesize(Wal *pWal); #endif /* Return the sqlite3_file object for the WAL file */ sqlite3_file *sqlite3WalFile(Wal *pWal); /* sqlite3_wal_info() data */ int sqlite3WalInfo(Wal *pWal, u32 *pnPrior, u32 *pnFrame); #endif /* ifndef SQLITE_OMIT_WAL */ #endif /* SQLITE_WAL_H */ | > > > > > | 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 | ** stored in each frame (i.e. the db page-size when the WAL was created). */ int sqlite3WalFramesize(Wal *pWal); #endif /* Return the sqlite3_file object for the WAL file */ sqlite3_file *sqlite3WalFile(Wal *pWal); #ifdef SQLITE_ENABLE_SETLK_TIMEOUT int sqlite3WalWriteLock(Wal *pWal, int bLock); void sqlite3WalDb(Wal *pWal, sqlite3 *db); #endif /* sqlite3_wal_info() data */ int sqlite3WalInfo(Wal *pWal, u32 *pnPrior, u32 *pnFrame); #endif /* ifndef SQLITE_OMIT_WAL */ #endif /* SQLITE_WAL_H */ |
Changes to src/walker.c.
︙ | ︙ | |||
13 14 15 16 17 18 19 20 21 22 23 24 25 26 | ** an SQL statement. */ #include "sqliteInt.h" #include <stdlib.h> #include <string.h> /* ** Walk an expression tree. Invoke the callback once for each node ** of the expression, while descending. (In other words, the callback ** is invoked before visiting children.) ** ** The return value from the callback should be one of the WRC_* ** constants to specify how to proceed with the walk. | > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | ** an SQL statement. */ #include "sqliteInt.h" #include <stdlib.h> #include <string.h> #if !defined(SQLITE_OMIT_WINDOWFUNC) /* ** Walk all expressions linked into the list of Window objects passed ** as the second argument. */ static int walkWindowList(Walker *pWalker, Window *pList, int bOneOnly){ Window *pWin; for(pWin=pList; pWin; pWin=pWin->pNextWin){ int rc; rc = sqlite3WalkExprList(pWalker, pWin->pOrderBy); if( rc ) return WRC_Abort; rc = sqlite3WalkExprList(pWalker, pWin->pPartition); if( rc ) return WRC_Abort; rc = sqlite3WalkExpr(pWalker, pWin->pFilter); if( rc ) return WRC_Abort; rc = sqlite3WalkExpr(pWalker, pWin->pStart); if( rc ) return WRC_Abort; rc = sqlite3WalkExpr(pWalker, pWin->pEnd); if( rc ) return WRC_Abort; if( bOneOnly ) break; } return WRC_Continue; } #endif /* ** Walk an expression tree. Invoke the callback once for each node ** of the expression, while descending. (In other words, the callback ** is invoked before visiting children.) ** ** The return value from the callback should be one of the WRC_* ** constants to specify how to proceed with the walk. |
︙ | ︙ | |||
40 41 42 43 44 45 46 | int rc; testcase( ExprHasProperty(pExpr, EP_TokenOnly) ); testcase( ExprHasProperty(pExpr, EP_Reduced) ); while(1){ rc = pWalker->xExprCallback(pWalker, pExpr); if( rc ) return rc & WRC_Abort; if( !ExprHasProperty(pExpr,(EP_TokenOnly|EP_Leaf)) ){ | < | > > > | > | | | | < < < | | > | 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 | int rc; testcase( ExprHasProperty(pExpr, EP_TokenOnly) ); testcase( ExprHasProperty(pExpr, EP_Reduced) ); while(1){ rc = pWalker->xExprCallback(pWalker, pExpr); if( rc ) return rc & WRC_Abort; if( !ExprHasProperty(pExpr,(EP_TokenOnly|EP_Leaf)) ){ assert( pExpr->x.pList==0 || pExpr->pRight==0 ); if( pExpr->pLeft && walkExpr(pWalker, pExpr->pLeft) ) return WRC_Abort; if( pExpr->pRight ){ assert( !ExprHasProperty(pExpr, EP_WinFunc) ); pExpr = pExpr->pRight; continue; }else if( ExprUseXSelect(pExpr) ){ assert( !ExprHasProperty(pExpr, EP_WinFunc) ); if( sqlite3WalkSelect(pWalker, pExpr->x.pSelect) ) return WRC_Abort; }else{ if( pExpr->x.pList ){ if( sqlite3WalkExprList(pWalker, pExpr->x.pList) ) return WRC_Abort; } #ifndef SQLITE_OMIT_WINDOWFUNC if( ExprHasProperty(pExpr, EP_WinFunc) ){ if( walkWindowList(pWalker, pExpr->y.pWin, 1) ) return WRC_Abort; } #endif } } break; } return WRC_Continue; } int sqlite3WalkExpr(Walker *pWalker, Expr *pExpr){ return pExpr ? walkExpr(pWalker,pExpr) : WRC_Continue; |
︙ | ︙ | |||
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 | if( p ){ for(i=p->nExpr, pItem=p->a; i>0; i--, pItem++){ if( sqlite3WalkExpr(pWalker, pItem->pExpr) ) return WRC_Abort; } } return WRC_Continue; } /* ** Walk all expressions associated with SELECT statement p. Do ** not invoke the SELECT callback on p, but do (of course) invoke ** any expr callbacks and SELECT callbacks that come from subqueries. ** Return WRC_Abort or WRC_Continue. */ int sqlite3WalkSelectExpr(Walker *pWalker, Select *p){ if( sqlite3WalkExprList(pWalker, p->pEList) ) return WRC_Abort; if( sqlite3WalkExpr(pWalker, p->pWhere) ) return WRC_Abort; if( sqlite3WalkExprList(pWalker, p->pGroupBy) ) return WRC_Abort; if( sqlite3WalkExpr(pWalker, p->pHaving) ) return WRC_Abort; if( sqlite3WalkExprList(pWalker, p->pOrderBy) ) return WRC_Abort; if( sqlite3WalkExpr(pWalker, p->pLimit) ) return WRC_Abort; return WRC_Continue; } /* ** Walk the parse trees associated with all subqueries in the ** FROM clause of SELECT statement p. Do not invoke the select ** callback on p, but do invoke it on each FROM clause subquery ** and on any subqueries further down in the tree. Return ** WRC_Abort or WRC_Continue; */ int sqlite3WalkSelectFrom(Walker *pWalker, Select *p){ SrcList *pSrc; int i; | > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | | | | | | | > | | 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 | if( p ){ for(i=p->nExpr, pItem=p->a; i>0; i--, pItem++){ if( sqlite3WalkExpr(pWalker, pItem->pExpr) ) return WRC_Abort; } } return WRC_Continue; } /* ** This is a no-op callback for Walker->xSelectCallback2. If this ** callback is set, then the Select->pWinDefn list is traversed. */ void sqlite3WalkWinDefnDummyCallback(Walker *pWalker, Select *p){ UNUSED_PARAMETER(pWalker); UNUSED_PARAMETER(p); /* No-op */ } /* ** Walk all expressions associated with SELECT statement p. Do ** not invoke the SELECT callback on p, but do (of course) invoke ** any expr callbacks and SELECT callbacks that come from subqueries. ** Return WRC_Abort or WRC_Continue. */ int sqlite3WalkSelectExpr(Walker *pWalker, Select *p){ if( sqlite3WalkExprList(pWalker, p->pEList) ) return WRC_Abort; if( sqlite3WalkExpr(pWalker, p->pWhere) ) return WRC_Abort; if( sqlite3WalkExprList(pWalker, p->pGroupBy) ) return WRC_Abort; if( sqlite3WalkExpr(pWalker, p->pHaving) ) return WRC_Abort; if( sqlite3WalkExprList(pWalker, p->pOrderBy) ) return WRC_Abort; if( sqlite3WalkExpr(pWalker, p->pLimit) ) return WRC_Abort; #if !defined(SQLITE_OMIT_WINDOWFUNC) if( p->pWinDefn ){ Parse *pParse; if( pWalker->xSelectCallback2==sqlite3WalkWinDefnDummyCallback || ((pParse = pWalker->pParse)!=0 && IN_RENAME_OBJECT) #ifndef SQLITE_OMIT_CTE || pWalker->xSelectCallback2==sqlite3SelectPopWith #endif ){ /* The following may return WRC_Abort if there are unresolvable ** symbols (e.g. a table that does not exist) in a window definition. */ int rc = walkWindowList(pWalker, p->pWinDefn, 0); return rc; } } #endif return WRC_Continue; } /* ** Walk the parse trees associated with all subqueries in the ** FROM clause of SELECT statement p. Do not invoke the select ** callback on p, but do invoke it on each FROM clause subquery ** and on any subqueries further down in the tree. Return ** WRC_Abort or WRC_Continue; */ int sqlite3WalkSelectFrom(Walker *pWalker, Select *p){ SrcList *pSrc; int i; SrcItem *pItem; pSrc = p->pSrc; if( ALWAYS(pSrc) ){ for(i=pSrc->nSrc, pItem=pSrc->a; i>0; i--, pItem++){ if( pItem->pSelect && sqlite3WalkSelect(pWalker, pItem->pSelect) ){ return WRC_Abort; } if( pItem->fg.isTabFunc && sqlite3WalkExprList(pWalker, pItem->u1.pFuncArg) ){ return WRC_Abort; } } } 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. ** ** If it is not NULL, the xSelectCallback() callback is invoked before |
︙ | ︙ | |||
161 162 163 164 165 166 167 | if( pWalker->xSelectCallback2 ){ pWalker->xSelectCallback2(pWalker, p); } p = p->pPrior; }while( p!=0 ); return WRC_Continue; } | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | if( pWalker->xSelectCallback2 ){ pWalker->xSelectCallback2(pWalker, p); } p = p->pPrior; }while( p!=0 ); return WRC_Continue; } /* Increase the walkerDepth when entering a subquery, and ** descrease when leaving the subquery. */ int sqlite3WalkerDepthIncrease(Walker *pWalker, Select *pSelect){ UNUSED_PARAMETER(pSelect); pWalker->walkerDepth++; return WRC_Continue; } void sqlite3WalkerDepthDecrease(Walker *pWalker, Select *pSelect){ UNUSED_PARAMETER(pSelect); pWalker->walkerDepth--; } /* ** No-op routine for the parse-tree walker. ** ** When this routine is the Walker.xExprCallback then expression trees ** are walked without any actions being taken at each node. Presumably, ** when this routine is used for Walker.xExprCallback then ** Walker.xSelectCallback is set to do something useful for every ** subquery in the parser tree. */ int sqlite3ExprWalkNoop(Walker *NotUsed, Expr *NotUsed2){ UNUSED_PARAMETER2(NotUsed, NotUsed2); return WRC_Continue; } /* ** No-op routine for the parse-tree walker for SELECT statements. ** subquery in the parser tree. */ int sqlite3SelectWalkNoop(Walker *NotUsed, Select *NotUsed2){ UNUSED_PARAMETER2(NotUsed, NotUsed2); return WRC_Continue; } |
Changes to src/where.c.
︙ | ︙ | |||
32 33 34 35 36 37 38 | struct HiddenIndexInfo { WhereClause *pWC; /* The Where clause being analyzed */ Parse *pParse; /* The parsing context */ }; /* Forward declaration of methods */ static int whereLoopResize(sqlite3*, WhereLoop*, int); | < < < < < < > | | > > > | 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 | struct HiddenIndexInfo { WhereClause *pWC; /* The Where clause being analyzed */ Parse *pParse; /* The parsing context */ }; /* Forward declaration of methods */ static int whereLoopResize(sqlite3*, WhereLoop*, int); /* ** Return the estimated number of output rows from a WHERE clause */ LogEst sqlite3WhereOutputRowCount(WhereInfo *pWInfo){ return pWInfo->nRowOut; } /* ** Return one of the WHERE_DISTINCT_xxxxx values to indicate how this ** WHERE clause returns outputs for DISTINCT processing. */ int sqlite3WhereIsDistinct(WhereInfo *pWInfo){ return pWInfo->eDistinct; } /* ** Return the number of ORDER BY terms that are satisfied by the ** WHERE clause. A return of 0 means that the output must be ** completely sorted. A return equal to the number of ORDER BY ** terms means that no sorting is needed at all. A return that ** is positive but less than the number of ORDER BY terms means that ** block sorting is required. */ int sqlite3WhereIsOrdered(WhereInfo *pWInfo){ return pWInfo->nOBSat; } /* ** In the ORDER BY LIMIT optimization, if the inner-most loop is known |
︙ | ︙ | |||
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 | ** continuation of the inner-most loop. */ return pWInfo->iContinue; } pInner = &pWInfo->a[pWInfo->nLevel-1]; assert( pInner->addrNxt!=0 ); return pInner->addrNxt; } /* ** Return the VDBE address or label to jump to in order to continue ** immediately with the next row of a WHERE clause. */ int sqlite3WhereContinueLabel(WhereInfo *pWInfo){ assert( pWInfo->iContinue!=0 ); return pWInfo->iContinue; } /* ** Return the VDBE address or label to jump to in order to break ** out of a WHERE loop. */ int sqlite3WhereBreakLabel(WhereInfo *pWInfo){ return pWInfo->iBreak; } /* ** Return ONEPASS_OFF (0) if an UPDATE or DELETE statement is unable to | > > > > > > > > > > > > > > > > > > > > > > > > > > | | 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 | ** continuation of the inner-most loop. */ return pWInfo->iContinue; } pInner = &pWInfo->a[pWInfo->nLevel-1]; assert( pInner->addrNxt!=0 ); return pInner->addrNxt; } /* ** While generating code for the min/max optimization, after handling ** the aggregate-step call to min() or max(), check to see if any ** additional looping is required. If the output order is such that ** we are certain that the correct answer has already been found, then ** code an OP_Goto to by pass subsequent processing. ** ** Any extra OP_Goto that is coded here is an optimization. The ** correct answer should be obtained regardless. This OP_Goto just ** makes the answer appear faster. */ void sqlite3WhereMinMaxOptEarlyOut(Vdbe *v, WhereInfo *pWInfo){ WhereLevel *pInner; int i; if( !pWInfo->bOrderedInnerLoop ) return; if( pWInfo->nOBSat==0 ) return; for(i=pWInfo->nLevel-1; i>=0; i--){ pInner = &pWInfo->a[i]; if( (pInner->pWLoop->wsFlags & WHERE_COLUMN_IN)!=0 ){ sqlite3VdbeGoto(v, pInner->addrNxt); return; } } sqlite3VdbeGoto(v, pWInfo->iBreak); } /* ** Return the VDBE address or label to jump to in order to continue ** immediately with the next row of a WHERE clause. */ int sqlite3WhereContinueLabel(WhereInfo *pWInfo){ assert( pWInfo->iContinue!=0 ); return pWInfo->iContinue; } /* ** Return the VDBE address or label to jump to in order to break ** out of a WHERE loop. */ int sqlite3WhereBreakLabel(WhereInfo *pWInfo){ return pWInfo->iBreak; } /* ** Return ONEPASS_OFF (0) if an UPDATE or DELETE statement is unable to ** operate directly on the rowids returned by a WHERE clause. Return ** ONEPASS_SINGLE (1) if the statement can operation directly because only ** a single row is to be changed. Return ONEPASS_MULTI (2) if the one-pass ** optimization can be used on multiple ** ** If the ONEPASS optimization is used (if this routine returns true) ** then also write the indices of open cursors used by ONEPASS ** into aiCur[0] and aiCur[1]. iaCur[0] gets the cursor of the data |
︙ | ︙ | |||
142 143 144 145 146 147 148 149 150 151 152 153 154 155 | sqlite3DebugPrintf("%s cursors: %d %d\n", pWInfo->eOnePass==ONEPASS_SINGLE ? "ONEPASS_SINGLE" : "ONEPASS_MULTI", aiCur[0], aiCur[1]); } #endif return pWInfo->eOnePass; } /* ** Move the content of pSrc into pDest */ static void whereOrMove(WhereOrSet *pDest, WhereOrSet *pSrc){ pDest->n = pSrc->n; memcpy(pDest->a, pSrc->a, pDest->n*sizeof(pDest->a[0])); | > > > > > > > > | 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 | sqlite3DebugPrintf("%s cursors: %d %d\n", pWInfo->eOnePass==ONEPASS_SINGLE ? "ONEPASS_SINGLE" : "ONEPASS_MULTI", aiCur[0], aiCur[1]); } #endif return pWInfo->eOnePass; } /* ** Return TRUE if the WHERE loop uses the OP_DeferredSeek opcode to move ** the data cursor to the row selected by the index cursor. */ int sqlite3WhereUsesDeferredSeek(WhereInfo *pWInfo){ return pWInfo->bDeferredSeek; } /* ** Move the content of pSrc into pDest */ static void whereOrMove(WhereOrSet *pDest, WhereOrSet *pSrc){ pDest->n = pSrc->n; memcpy(pDest->a, pSrc->a, pDest->n*sizeof(pDest->a[0])); |
︙ | ︙ | |||
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 | ** sqlite3WhereBegin() routine. So we know that the pMaskSet->ix[] ** array will never overflow. */ static void createMask(WhereMaskSet *pMaskSet, int iCursor){ assert( pMaskSet->n < ArraySize(pMaskSet->ix) ); pMaskSet->ix[pMaskSet->n++] = iCursor; } /* ** Advance to the next WhereTerm that matches according to the criteria ** established when the pScan object was initialized by whereScanInit(). ** Return NULL if there are no more matching WhereTerms. */ static WhereTerm *whereScanNext(WhereScan *pScan){ int iCur; /* The cursor on the LHS of the term */ i16 iColumn; /* The column on the LHS of the term. -1 for IPK */ Expr *pX; /* An expression being tested */ WhereClause *pWC; /* Shorthand for pScan->pWC */ WhereTerm *pTerm; /* The term being tested */ int k = pScan->k; /* Where to start scanning */ assert( pScan->iEquiv<=pScan->nEquiv ); pWC = pScan->pWC; while(1){ iColumn = pScan->aiColumn[pScan->iEquiv-1]; iCur = pScan->aiCur[pScan->iEquiv-1]; assert( pWC!=0 ); do{ for(pTerm=pWC->a+k; k<pWC->nTerm; k++, pTerm++){ if( pTerm->leftCursor==iCur | > > > > > > > > > > > > > > | | | 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 | ** sqlite3WhereBegin() routine. So we know that the pMaskSet->ix[] ** array will never overflow. */ static void createMask(WhereMaskSet *pMaskSet, int iCursor){ assert( pMaskSet->n < ArraySize(pMaskSet->ix) ); pMaskSet->ix[pMaskSet->n++] = iCursor; } /* ** If the right-hand branch of the expression is a TK_COLUMN, then return ** a pointer to the right-hand branch. Otherwise, return NULL. */ static Expr *whereRightSubexprIsColumn(Expr *p){ p = sqlite3ExprSkipCollateAndLikely(p->pRight); if( ALWAYS(p!=0) && p->op==TK_COLUMN && !ExprHasProperty(p, EP_FixedCol) ){ return p; } return 0; } /* ** Advance to the next WhereTerm that matches according to the criteria ** established when the pScan object was initialized by whereScanInit(). ** Return NULL if there are no more matching WhereTerms. */ static WhereTerm *whereScanNext(WhereScan *pScan){ int iCur; /* The cursor on the LHS of the term */ i16 iColumn; /* The column on the LHS of the term. -1 for IPK */ Expr *pX; /* An expression being tested */ WhereClause *pWC; /* Shorthand for pScan->pWC */ WhereTerm *pTerm; /* The term being tested */ int k = pScan->k; /* Where to start scanning */ assert( pScan->iEquiv<=pScan->nEquiv ); pWC = pScan->pWC; while(1){ iColumn = pScan->aiColumn[pScan->iEquiv-1]; iCur = pScan->aiCur[pScan->iEquiv-1]; assert( pWC!=0 ); assert( iCur>=0 ); do{ for(pTerm=pWC->a+k; k<pWC->nTerm; k++, pTerm++){ assert( (pTerm->eOperator & (WO_OR|WO_AND))==0 || pTerm->leftCursor<0 ); if( pTerm->leftCursor==iCur && pTerm->u.x.leftColumn==iColumn && (iColumn!=XN_EXPR || sqlite3ExprCompareSkip(pTerm->pExpr->pLeft, pScan->pIdxExpr,iCur)==0) && (pScan->iEquiv<=1 || !ExprHasProperty(pTerm->pExpr, EP_FromJoin)) ){ if( (pTerm->eOperator & WO_EQUIV)!=0 && pScan->nEquiv<ArraySize(pScan->aiCur) && (pX = whereRightSubexprIsColumn(pTerm->pExpr))!=0 ){ int j; for(j=0; j<pScan->nEquiv; j++){ if( pScan->aiCur[j]==pX->iTable && pScan->aiColumn[j]==pX->iColumn ){ break; } |
︙ | ︙ | |||
274 275 276 277 278 279 280 | CollSeq *pColl; Parse *pParse = pWC->pWInfo->pParse; pX = pTerm->pExpr; if( !sqlite3IndexAffinityOk(pX, pScan->idxaff) ){ continue; } assert(pX->pLeft); | | < | > > > > > > > > > > > > > > > > > > > > > > > > | 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 | CollSeq *pColl; Parse *pParse = pWC->pWInfo->pParse; pX = pTerm->pExpr; if( !sqlite3IndexAffinityOk(pX, pScan->idxaff) ){ continue; } assert(pX->pLeft); pColl = sqlite3ExprCompareCollSeq(pParse, pX); if( pColl==0 ) pColl = pParse->db->pDfltColl; if( sqlite3StrICmp(pColl->zName, pScan->zCollName) ){ continue; } } if( (pTerm->eOperator & (WO_EQ|WO_IS))!=0 && (pX = pTerm->pExpr->pRight, ALWAYS(pX!=0)) && pX->op==TK_COLUMN && pX->iTable==pScan->aiCur[0] && pX->iColumn==pScan->aiColumn[0] ){ testcase( pTerm->eOperator & WO_IS ); continue; } pScan->pWC = pWC; pScan->k = k+1; #ifdef WHERETRACE_ENABLED if( sqlite3WhereTrace & 0x20000 ){ int ii; sqlite3DebugPrintf("SCAN-TERM %p: nEquiv=%d", pTerm, pScan->nEquiv); for(ii=0; ii<pScan->nEquiv; ii++){ sqlite3DebugPrintf(" {%d:%d}", pScan->aiCur[ii], pScan->aiColumn[ii]); } sqlite3DebugPrintf("\n"); } #endif return pTerm; } } } pWC = pWC->pOuter; k = 0; }while( pWC!=0 ); if( pScan->iEquiv>=pScan->nEquiv ) break; pWC = pScan->pOrigWC; k = 0; pScan->iEquiv++; } return 0; } /* ** This is whereScanInit() for the case of an index on an expression. ** It is factored out into a separate tail-recursion subroutine so that ** the normal whereScanInit() routine, which is a high-runner, does not ** need to push registers onto the stack as part of its prologue. */ static SQLITE_NOINLINE WhereTerm *whereScanInitIndexExpr(WhereScan *pScan){ pScan->idxaff = sqlite3ExprAffinity(pScan->pIdxExpr); return whereScanNext(pScan); } /* ** Initialize a WHERE clause scanner object. Return a pointer to the ** first match. Return NULL if there are no matches. ** ** The scanner will be searching the WHERE clause pWC. It will look ** for terms of the form "X <op> <expr>" where X is column iColumn of table |
︙ | ︙ | |||
338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 | Index *pIdx /* Must be compatible with this index */ ){ pScan->pOrigWC = pWC; pScan->pWC = pWC; pScan->pIdxExpr = 0; pScan->idxaff = 0; pScan->zCollName = 0; if( pIdx ){ int j = iColumn; iColumn = pIdx->aiColumn[j]; if( iColumn==XN_EXPR ){ pScan->pIdxExpr = pIdx->aColExpr->a[j].pExpr; pScan->zCollName = pIdx->azColl[j]; }else if( iColumn==pIdx->pTable->iPKey ){ iColumn = XN_ROWID; }else if( iColumn>=0 ){ pScan->idxaff = pIdx->pTable->aCol[iColumn].affinity; pScan->zCollName = pIdx->azColl[j]; } }else if( iColumn==XN_EXPR ){ return 0; } | > > > > > > > < < < < < | 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 | Index *pIdx /* Must be compatible with this index */ ){ pScan->pOrigWC = pWC; pScan->pWC = pWC; pScan->pIdxExpr = 0; pScan->idxaff = 0; pScan->zCollName = 0; pScan->opMask = opMask; pScan->k = 0; pScan->aiCur[0] = iCur; pScan->nEquiv = 1; pScan->iEquiv = 1; if( pIdx ){ int j = iColumn; iColumn = pIdx->aiColumn[j]; if( iColumn==XN_EXPR ){ pScan->pIdxExpr = pIdx->aColExpr->a[j].pExpr; pScan->zCollName = pIdx->azColl[j]; pScan->aiColumn[0] = XN_EXPR; return whereScanInitIndexExpr(pScan); }else if( iColumn==pIdx->pTable->iPKey ){ iColumn = XN_ROWID; }else if( iColumn>=0 ){ pScan->idxaff = pIdx->pTable->aCol[iColumn].affinity; pScan->zCollName = pIdx->azColl[j]; } }else if( iColumn==XN_EXPR ){ return 0; } pScan->aiColumn[0] = iColumn; return whereScanNext(pScan); } /* ** Search for a term in the WHERE clause that is of the form "X <op> <expr>" ** where X is a reference to the iColumn of table iCur or of index pIdx ** if pIdx!=0 and <op> is one of the WO_xx operator codes specified by |
︙ | ︙ | |||
432 433 434 435 436 437 438 | Index *pIdx, /* Index to match column of */ int iCol /* Column of index to match */ ){ int i; const char *zColl = pIdx->azColl[iCol]; for(i=0; i<pList->nExpr; i++){ | | > | | 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 | Index *pIdx, /* Index to match column of */ int iCol /* Column of index to match */ ){ int i; const char *zColl = pIdx->azColl[iCol]; for(i=0; i<pList->nExpr; i++){ Expr *p = sqlite3ExprSkipCollateAndLikely(pList->a[i].pExpr); if( ALWAYS(p!=0) && (p->op==TK_COLUMN || p->op==TK_AGG_COLUMN) && p->iColumn==pIdx->aiColumn[iCol] && p->iTable==iBase ){ CollSeq *pColl = sqlite3ExprNNCollSeq(pParse, pList->a[i].pExpr); if( 0==sqlite3StrICmp(pColl->zName, zColl) ){ return i; } |
︙ | ︙ | |||
496 497 498 499 500 501 502 | pTab = pTabList->a[0].pTab; /* If any of the expressions is an IPK column on table iBase, then return ** true. Note: The (p->iTable==iBase) part of this test may be false if the ** current SELECT is a correlated sub-query. */ for(i=0; i<pDistinct->nExpr; i++){ | | > > | > | 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 | pTab = pTabList->a[0].pTab; /* If any of the expressions is an IPK column on table iBase, then return ** true. Note: The (p->iTable==iBase) part of this test may be false if the ** current SELECT is a correlated sub-query. */ for(i=0; i<pDistinct->nExpr; i++){ Expr *p = sqlite3ExprSkipCollateAndLikely(pDistinct->a[i].pExpr); if( NEVER(p==0) ) continue; if( p->op!=TK_COLUMN && p->op!=TK_AGG_COLUMN ) continue; if( p->iTable==iBase && p->iColumn<0 ) return 1; } /* Loop through all indices on the table, checking each to see if it makes ** the DISTINCT qualifier redundant. It does so if: ** ** 1. The index is itself UNIQUE, and ** ** 2. All of the columns in the index are either part of the pDistinct ** list, or else the WHERE clause contains a term of the form "col=X", ** where X is a constant value. The collation sequences of the ** comparison and select-list expressions must match those of the index. ** ** 3. All of those index columns for which the WHERE clause does not ** contain a "col=X" term are subject to a NOT NULL constraint. */ for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ if( !IsUniqueIndex(pIdx) ) continue; if( pIdx->pPartIdxWhere ) continue; for(i=0; i<pIdx->nKeyCol; i++){ if( 0==sqlite3WhereFindTerm(pWC, iBase, i, ~(Bitmask)0, WO_EQ, pIdx) ){ if( findIndexCol(pParse, pDistinct, iBase, pIdx, i)<0 ) break; if( indexColumnNotNull(pIdx, i)==0 ) break; } } if( i==pIdx->nKeyCol ){ |
︙ | ︙ | |||
545 546 547 548 549 550 551 | /* ** Convert OP_Column opcodes to OP_Copy in previously generated code. ** ** This routine runs over generated VDBE code and translates OP_Column ** opcodes into OP_Copy when the table is being accessed via co-routine ** instead of via table lookup. ** | | | | | | < < | | < < > > < > | | | | | > | | | | 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 | /* ** Convert OP_Column opcodes to OP_Copy in previously generated code. ** ** This routine runs over generated VDBE code and translates OP_Column ** opcodes into OP_Copy when the table is being accessed via co-routine ** instead of via table lookup. ** ** If the iAutoidxCur is not zero, then any OP_Rowid instructions on ** cursor iTabCur are transformed into OP_Sequence opcode for the ** iAutoidxCur cursor, in order to generate unique rowids for the ** automatic index being generated. */ static void translateColumnToCopy( Parse *pParse, /* Parsing context */ int iStart, /* Translate from this opcode to the end */ int iTabCur, /* OP_Column/OP_Rowid references to this table */ int iRegister, /* The first column is in this register */ int iAutoidxCur /* If non-zero, cursor of autoindex being generated */ ){ Vdbe *v = pParse->pVdbe; VdbeOp *pOp = sqlite3VdbeGetOp(v, iStart); int iEnd = sqlite3VdbeCurrentAddr(v); if( pParse->db->mallocFailed ) return; for(; iStart<iEnd; iStart++, pOp++){ if( pOp->p1!=iTabCur ) continue; if( pOp->opcode==OP_Column ){ pOp->opcode = OP_Copy; pOp->p1 = pOp->p2 + iRegister; pOp->p2 = pOp->p3; pOp->p3 = 0; }else if( pOp->opcode==OP_Rowid ){ pOp->opcode = OP_Sequence; pOp->p1 = iAutoidxCur; #ifdef SQLITE_ALLOW_ROWID_IN_VIEW if( iAutoidxCur==0 ){ pOp->opcode = OP_Null; pOp->p3 = 0; } #endif } } } /* ** Two routines for printing the content of an sqlite3_index_info ** structure. Used for testing and debugging only. If neither ** SQLITE_TEST or SQLITE_DEBUG are defined, then these routines ** are no-ops. */ #if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(WHERETRACE_ENABLED) static void whereTraceIndexInfoInputs(sqlite3_index_info *p){ int i; if( !sqlite3WhereTrace ) return; for(i=0; i<p->nConstraint; i++){ sqlite3DebugPrintf(" constraint[%d]: col=%d termid=%d op=%d usabled=%d\n", i, p->aConstraint[i].iColumn, p->aConstraint[i].iTermOffset, p->aConstraint[i].op, p->aConstraint[i].usable); } for(i=0; i<p->nOrderBy; i++){ sqlite3DebugPrintf(" orderby[%d]: col=%d desc=%d\n", i, p->aOrderBy[i].iColumn, p->aOrderBy[i].desc); } } static void whereTraceIndexInfoOutputs(sqlite3_index_info *p){ int i; if( !sqlite3WhereTrace ) return; for(i=0; i<p->nConstraint; i++){ sqlite3DebugPrintf(" usage[%d]: argvIdx=%d omit=%d\n", i, p->aConstraintUsage[i].argvIndex, p->aConstraintUsage[i].omit); } sqlite3DebugPrintf(" idxNum=%d\n", p->idxNum); sqlite3DebugPrintf(" idxStr=%s\n", p->idxStr); sqlite3DebugPrintf(" orderByConsumed=%d\n", p->orderByConsumed); sqlite3DebugPrintf(" estimatedCost=%g\n", p->estimatedCost); sqlite3DebugPrintf(" estimatedRows=%lld\n", p->estimatedRows); } #else #define whereTraceIndexInfoInputs(A) #define whereTraceIndexInfoOutputs(A) #endif #ifndef SQLITE_OMIT_AUTOMATIC_INDEX /* ** Return TRUE if the WHERE clause term pTerm is of a form where it ** could be used with an index to access pSrc, assuming an appropriate ** index existed. */ static int termCanDriveIndex( WhereTerm *pTerm, /* WHERE clause term to check */ SrcItem *pSrc, /* Table we are trying to access */ Bitmask notReady /* Tables in outer loops of the join */ ){ char aff; if( pTerm->leftCursor!=pSrc->iCursor ) return 0; if( (pTerm->eOperator & (WO_EQ|WO_IS))==0 ) return 0; if( (pSrc->fg.jointype & JT_LEFT) && !ExprHasProperty(pTerm->pExpr, EP_FromJoin) && (pTerm->eOperator & WO_IS) ){ /* Cannot use an IS term from the WHERE clause as an index driver for ** the RHS of a LEFT JOIN. Such a term can only be used if it is from ** the ON clause. */ return 0; } if( (pTerm->prereqRight & notReady)!=0 ) return 0; assert( (pTerm->eOperator & (WO_OR|WO_AND))==0 ); if( pTerm->u.x.leftColumn<0 ) return 0; aff = pSrc->pTab->aCol[pTerm->u.x.leftColumn].affinity; if( !sqlite3IndexAffinityOk(pTerm->pExpr, aff) ) return 0; testcase( pTerm->pExpr->op==TK_IS ); return 1; } #endif #ifndef SQLITE_OMIT_AUTOMATIC_INDEX /* ** Generate code to construct the Index object for an automatic index ** and to set up the WhereLevel object pLevel so that the code generator ** makes use of the automatic index. */ static void constructAutomaticIndex( Parse *pParse, /* The parsing context */ WhereClause *pWC, /* The WHERE clause */ SrcItem *pSrc, /* The FROM clause term to get the next index */ Bitmask notReady, /* Mask of cursors that are not available */ WhereLevel *pLevel /* Write new index here */ ){ int nKeyCol; /* Number of columns in the constructed index */ WhereTerm *pTerm; /* A single term of the WHERE clause */ WhereTerm *pWCEnd; /* End of pWC->a[] */ Index *pIdx; /* Object describing the transient index */ |
︙ | ︙ | |||
694 695 696 697 698 699 700 | WhereLoop *pLoop; /* The Loop object */ char *zNotUsed; /* Extra space on the end of pIdx */ Bitmask idxCols; /* Bitmap of columns used for indexing */ Bitmask extraCols; /* Bitmap of additional columns */ u8 sentWarning = 0; /* True if a warnning has been issued */ Expr *pPartial = 0; /* Partial Index Expression */ int iContinue = 0; /* Jump here to skip excluded rows */ | | | 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 | WhereLoop *pLoop; /* The Loop object */ char *zNotUsed; /* Extra space on the end of pIdx */ Bitmask idxCols; /* Bitmap of columns used for indexing */ Bitmask extraCols; /* Bitmap of additional columns */ u8 sentWarning = 0; /* True if a warnning has been issued */ Expr *pPartial = 0; /* Partial Index Expression */ int iContinue = 0; /* Jump here to skip excluded rows */ SrcItem *pTabItem; /* FROM clause term being indexed */ int addrCounter = 0; /* Address where integer counter is initialized */ int regBase; /* Array of registers where record is assembled */ /* Generate code to skip over the creation and initialization of the ** transient index on 2nd and subsequent iterations of the loop. */ v = pParse->pVdbe; assert( v!=0 ); |
︙ | ︙ | |||
720 721 722 723 724 725 726 | assert( !ExprHasProperty(pExpr, EP_FromJoin) /* prereq always non-zero */ || pExpr->iRightJoinTable!=pSrc->iCursor /* for the right-hand */ || pLoop->prereq!=0 ); /* table of a LEFT JOIN */ if( pLoop->prereq==0 && (pTerm->wtFlags & TERM_VIRTUAL)==0 && !ExprHasProperty(pExpr, EP_FromJoin) && sqlite3ExprIsTableConstant(pExpr, pSrc->iCursor) ){ | | | > > > | | | | 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 | assert( !ExprHasProperty(pExpr, EP_FromJoin) /* prereq always non-zero */ || pExpr->iRightJoinTable!=pSrc->iCursor /* for the right-hand */ || pLoop->prereq!=0 ); /* table of a LEFT JOIN */ if( pLoop->prereq==0 && (pTerm->wtFlags & TERM_VIRTUAL)==0 && !ExprHasProperty(pExpr, EP_FromJoin) && sqlite3ExprIsTableConstant(pExpr, pSrc->iCursor) ){ pPartial = sqlite3ExprAnd(pParse, pPartial, sqlite3ExprDup(pParse->db, pExpr, 0)); } if( termCanDriveIndex(pTerm, pSrc, notReady) ){ int iCol; Bitmask cMask; assert( (pTerm->eOperator & (WO_OR|WO_AND))==0 ); iCol = pTerm->u.x.leftColumn; cMask = iCol>=BMS ? MASKBIT(BMS-1) : MASKBIT(iCol); testcase( iCol==BMS ); testcase( iCol==BMS-1 ); if( !sentWarning ){ sqlite3_log(SQLITE_WARNING_AUTOINDEX, "automatic index on %s(%s)", pTable->zName, pTable->aCol[iCol].zCnName); sentWarning = 1; } if( (idxCols & cMask)==0 ){ if( whereLoopResize(pParse->db, pLoop, nKeyCol+1) ){ goto end_auto_index_create; } pLoop->aLTerm[nKeyCol++] = pTerm; idxCols |= cMask; } } } assert( nKeyCol>0 || pParse->db->mallocFailed ); pLoop->u.btree.nEq = pLoop->nLTerm = nKeyCol; pLoop->wsFlags = WHERE_COLUMN_EQ | WHERE_IDX_ONLY | WHERE_INDEXED | WHERE_AUTO_INDEX; /* Count the number of additional columns needed to create a ** covering index. A "covering index" is an index that contains all ** columns that are needed by the query. With a covering index, the |
︙ | ︙ | |||
777 778 779 780 781 782 783 | pLoop->u.btree.pIndex = pIdx; pIdx->zName = "auto-index"; pIdx->pTable = pTable; n = 0; idxCols = 0; for(pTerm=pWC->a; pTerm<pWCEnd; pTerm++){ if( termCanDriveIndex(pTerm, pSrc, notReady) ){ | | > > > | | | > | 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 | pLoop->u.btree.pIndex = pIdx; pIdx->zName = "auto-index"; pIdx->pTable = pTable; n = 0; idxCols = 0; for(pTerm=pWC->a; pTerm<pWCEnd; pTerm++){ if( termCanDriveIndex(pTerm, pSrc, notReady) ){ int iCol; Bitmask cMask; assert( (pTerm->eOperator & (WO_OR|WO_AND))==0 ); iCol = pTerm->u.x.leftColumn; cMask = iCol>=BMS ? MASKBIT(BMS-1) : MASKBIT(iCol); testcase( iCol==BMS-1 ); testcase( iCol==BMS ); if( (idxCols & cMask)==0 ){ Expr *pX = pTerm->pExpr; idxCols |= cMask; pIdx->aiColumn[n] = pTerm->u.x.leftColumn; pColl = sqlite3ExprCompareCollSeq(pParse, pX); assert( pColl!=0 || pParse->nErr>0 ); /* TH3 collate01.800 */ pIdx->azColl[n] = pColl ? pColl->zName : sqlite3StrBINARY; n++; } } } assert( (u32)n==pLoop->u.btree.nEq ); |
︙ | ︙ | |||
833 834 835 836 837 838 839 | addrTop = sqlite3VdbeAddOp1(v, OP_Yield, regYield); VdbeCoverage(v); VdbeComment((v, "next row of %s", pTabItem->pTab->zName)); }else{ addrTop = sqlite3VdbeAddOp1(v, OP_Rewind, pLevel->iTabCur); VdbeCoverage(v); } if( pPartial ){ | | > | > < | > | 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 | addrTop = sqlite3VdbeAddOp1(v, OP_Yield, regYield); VdbeCoverage(v); VdbeComment((v, "next row of %s", pTabItem->pTab->zName)); }else{ addrTop = sqlite3VdbeAddOp1(v, OP_Rewind, pLevel->iTabCur); VdbeCoverage(v); } if( pPartial ){ iContinue = sqlite3VdbeMakeLabel(pParse); sqlite3ExprIfFalse(pParse, pPartial, iContinue, SQLITE_JUMPIFNULL); pLoop->wsFlags |= WHERE_PARTIALIDX; } regRecord = sqlite3GetTempReg(pParse); regBase = sqlite3GenerateIndexKey( pParse, pIdx, pLevel->iTabCur, regRecord, 0, 0, 0, 0 ); sqlite3VdbeAddOp2(v, OP_IdxInsert, pLevel->iIdxCur, regRecord); sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT); if( pPartial ) sqlite3VdbeResolveLabel(v, iContinue); if( pTabItem->fg.viaCoroutine ){ sqlite3VdbeChangeP2(v, addrCounter, regBase+n); testcase( pParse->db->mallocFailed ); assert( pLevel->iIdxCur>0 ); translateColumnToCopy(pParse, addrTop, pLevel->iTabCur, pTabItem->regResult, pLevel->iIdxCur); sqlite3VdbeGoto(v, addrTop); pTabItem->fg.viaCoroutine = 0; }else{ sqlite3VdbeAddOp2(v, OP_Next, pLevel->iTabCur, addrTop+1); VdbeCoverage(v); sqlite3VdbeChangeP5(v, SQLITE_STMTSTATUS_AUTOINDEX); } sqlite3VdbeJumpHere(v, addrTop); sqlite3ReleaseTempReg(pParse, regRecord); /* Jump here when skipping the initialization */ sqlite3VdbeJumpHere(v, addrInit); end_auto_index_create: |
︙ | ︙ | |||
875 876 877 878 879 880 881 | ** responsibility of the caller to eventually release the structure ** by passing the pointer returned by this function to sqlite3_free(). */ static sqlite3_index_info *allocateIndexInfo( Parse *pParse, /* The parsing context */ WhereClause *pWC, /* The WHERE clause being analyzed */ Bitmask mUnusable, /* Ignore terms with these prereqs */ | | | 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 | ** responsibility of the caller to eventually release the structure ** by passing the pointer returned by this function to sqlite3_free(). */ static sqlite3_index_info *allocateIndexInfo( Parse *pParse, /* The parsing context */ WhereClause *pWC, /* The WHERE clause being analyzed */ Bitmask mUnusable, /* Ignore terms with these prereqs */ SrcItem *pSrc, /* The FROM clause term that is the vtab */ ExprList *pOrderBy, /* The ORDER BY clause */ u16 *pmNoOmit /* Mask of terms not to omit */ ){ int i, j; int nTerm; struct sqlite3_index_constraint *pIdxCons; struct sqlite3_index_orderby *pIdxOrderBy; |
︙ | ︙ | |||
902 903 904 905 906 907 908 | assert( IsPowerOfTwo(pTerm->eOperator & ~WO_EQUIV) ); testcase( pTerm->eOperator & WO_IN ); testcase( pTerm->eOperator & WO_ISNULL ); testcase( pTerm->eOperator & WO_IS ); testcase( pTerm->eOperator & WO_ALL ); if( (pTerm->eOperator & ~(WO_EQUIV))==0 ) continue; if( pTerm->wtFlags & TERM_VNULL ) continue; | > | > < < < < < < < | | | | < < > > > > < < < < < < < < < > | | | 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 | assert( IsPowerOfTwo(pTerm->eOperator & ~WO_EQUIV) ); testcase( pTerm->eOperator & WO_IN ); testcase( pTerm->eOperator & WO_ISNULL ); testcase( pTerm->eOperator & WO_IS ); testcase( pTerm->eOperator & WO_ALL ); if( (pTerm->eOperator & ~(WO_EQUIV))==0 ) continue; if( pTerm->wtFlags & TERM_VNULL ) continue; assert( (pTerm->eOperator & (WO_OR|WO_AND))==0 ); assert( pTerm->u.x.leftColumn>=(-1) ); nTerm++; } /* If the ORDER BY clause contains only columns in the current ** virtual table then allocate space for the aOrderBy part of ** the sqlite3_index_info structure. */ nOrderBy = 0; if( pOrderBy ){ int n = pOrderBy->nExpr; for(i=0; i<n; i++){ Expr *pExpr = pOrderBy->a[i].pExpr; if( pExpr->op!=TK_COLUMN || pExpr->iTable!=pSrc->iCursor ) break; if( pOrderBy->a[i].sortFlags & KEYINFO_ORDER_BIGNULL ) break; } if( i==n){ nOrderBy = n; } } /* Allocate the sqlite3_index_info structure */ pIdxInfo = sqlite3DbMallocZero(pParse->db, sizeof(*pIdxInfo) + (sizeof(*pIdxCons) + sizeof(*pUsage))*nTerm + sizeof(*pIdxOrderBy)*nOrderBy + sizeof(*pHidden) ); if( pIdxInfo==0 ){ sqlite3ErrorMsg(pParse, "out of memory"); return 0; } pHidden = (struct HiddenIndexInfo*)&pIdxInfo[1]; pIdxCons = (struct sqlite3_index_constraint*)&pHidden[1]; pIdxOrderBy = (struct sqlite3_index_orderby*)&pIdxCons[nTerm]; pUsage = (struct sqlite3_index_constraint_usage*)&pIdxOrderBy[nOrderBy]; pIdxInfo->nOrderBy = nOrderBy; pIdxInfo->aConstraint = pIdxCons; pIdxInfo->aOrderBy = pIdxOrderBy; pIdxInfo->aConstraintUsage = pUsage; pHidden->pWC = pWC; pHidden->pParse = pParse; for(i=j=0, pTerm=pWC->a; i<pWC->nTerm; i++, pTerm++){ u16 op; if( pTerm->leftCursor != pSrc->iCursor ) continue; if( pTerm->prereqRight & mUnusable ) continue; assert( IsPowerOfTwo(pTerm->eOperator & ~WO_EQUIV) ); testcase( pTerm->eOperator & WO_IN ); testcase( pTerm->eOperator & WO_IS ); testcase( pTerm->eOperator & WO_ISNULL ); testcase( pTerm->eOperator & WO_ALL ); if( (pTerm->eOperator & ~(WO_EQUIV))==0 ) continue; if( pTerm->wtFlags & TERM_VNULL ) continue; /* tag-20191211-002: WHERE-clause constraints are not useful to the ** right-hand table of a LEFT JOIN. See tag-20191211-001 for the ** equivalent restriction for ordinary tables. */ if( (pSrc->fg.jointype & JT_LEFT)!=0 && !ExprHasProperty(pTerm->pExpr, EP_FromJoin) ){ continue; } assert( (pTerm->eOperator & (WO_OR|WO_AND))==0 ); assert( pTerm->u.x.leftColumn>=(-1) ); pIdxCons[j].iColumn = pTerm->u.x.leftColumn; pIdxCons[j].iTermOffset = i; op = pTerm->eOperator & WO_ALL; if( op==WO_IN ) op = WO_EQ; if( op==WO_AUX ){ pIdxCons[j].op = pTerm->eMatchOp; }else if( op & (WO_ISNULL|WO_IS) ){ if( op==WO_ISNULL ){ |
︙ | ︙ | |||
1003 1004 1005 1006 1007 1008 1009 | assert( WO_GT==SQLITE_INDEX_CONSTRAINT_GT ); assert( WO_GE==SQLITE_INDEX_CONSTRAINT_GE ); assert( pTerm->eOperator&(WO_IN|WO_EQ|WO_LT|WO_LE|WO_GT|WO_GE|WO_AUX) ); if( op & (WO_LT|WO_LE|WO_GT|WO_GE) && sqlite3ExprIsVector(pTerm->pExpr->pRight) ){ | > | > | | 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 | assert( WO_GT==SQLITE_INDEX_CONSTRAINT_GT ); assert( WO_GE==SQLITE_INDEX_CONSTRAINT_GE ); assert( pTerm->eOperator&(WO_IN|WO_EQ|WO_LT|WO_LE|WO_GT|WO_GE|WO_AUX) ); if( op & (WO_LT|WO_LE|WO_GT|WO_GE) && sqlite3ExprIsVector(pTerm->pExpr->pRight) ){ testcase( j!=i ); if( j<16 ) mNoOmit |= (1 << j); if( op==WO_LT ) pIdxCons[j].op = WO_LE; if( op==WO_GT ) pIdxCons[j].op = WO_GE; } } j++; } pIdxInfo->nConstraint = j; for(i=0; i<nOrderBy; i++){ Expr *pExpr = pOrderBy->a[i].pExpr; pIdxOrderBy[i].iColumn = pExpr->iColumn; pIdxOrderBy[i].desc = pOrderBy->a[i].sortFlags & KEYINFO_ORDER_DESC; } *pmNoOmit = mNoOmit; return pIdxInfo; } /* |
︙ | ︙ | |||
1041 1042 1043 1044 1045 1046 1047 | ** caller to eventually free p->idxStr if p->needToFreeIdxStr indicates ** that this is required. */ static int vtabBestIndex(Parse *pParse, Table *pTab, sqlite3_index_info *p){ sqlite3_vtab *pVtab = sqlite3GetVTable(pParse->db, pTab)->pVtab; int rc; | | | | | 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 | ** caller to eventually free p->idxStr if p->needToFreeIdxStr indicates ** that this is required. */ static int vtabBestIndex(Parse *pParse, Table *pTab, sqlite3_index_info *p){ sqlite3_vtab *pVtab = sqlite3GetVTable(pParse->db, pTab)->pVtab; int rc; whereTraceIndexInfoInputs(p); rc = pVtab->pModule->xBestIndex(pVtab, p); whereTraceIndexInfoOutputs(p); if( rc!=SQLITE_OK && rc!=SQLITE_CONSTRAINT ){ if( rc==SQLITE_NOMEM ){ sqlite3OomFault(pParse->db); }else if( !pVtab->zErrMsg ){ sqlite3ErrorMsg(pParse, "%s", sqlite3ErrStr(rc)); }else{ sqlite3ErrorMsg(pParse, "%s", pVtab->zErrMsg); } } sqlite3_free(pVtab->zErrMsg); pVtab->zErrMsg = 0; return rc; } #endif /* !defined(SQLITE_OMIT_VIRTUALTABLE) */ #ifdef SQLITE_ENABLE_STAT4 /* ** Estimate the location of a particular key among all keys in an ** index. Store the results in aStat as follows: ** ** aStat[0] Est. number of rows less than pRec ** aStat[1] Est. number of rows equal to pRec ** |
︙ | ︙ | |||
1253 1254 1255 1256 1257 1258 1259 | aStat[1] = pIdx->aAvgEq[nField-1]; } /* Restore the pRec->nField value before returning. */ pRec->nField = nField; return i; } | | | 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 | aStat[1] = pIdx->aAvgEq[nField-1]; } /* Restore the pRec->nField value before returning. */ pRec->nField = nField; return i; } #endif /* SQLITE_ENABLE_STAT4 */ /* ** If it is not NULL, pTerm is a term that provides an upper or lower ** bound on a range scan. Without considering pTerm, it is estimated ** that the scan will visit nNew rows. This function returns the number ** estimated to be visited after taking pTerm into account. ** |
︙ | ︙ | |||
1279 1280 1281 1282 1283 1284 1285 | nRet -= 20; assert( 20==sqlite3LogEst(4) ); } } return nRet; } | | > | | 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 | nRet -= 20; assert( 20==sqlite3LogEst(4) ); } } return nRet; } #ifdef SQLITE_ENABLE_STAT4 /* ** Return the affinity for a single column of an index. */ char sqlite3IndexColumnAffinity(sqlite3 *db, Index *pIdx, int iCol){ assert( iCol>=0 && iCol<pIdx->nColumn ); if( !pIdx->zColAff ){ if( sqlite3IndexAffinityStr(db, pIdx)==0 ) return SQLITE_AFF_BLOB; } assert( pIdx->zColAff[iCol]!=0 ); return pIdx->zColAff[iCol]; } #endif #ifdef SQLITE_ENABLE_STAT4 /* ** This function is called to estimate the number of rows visited by a ** range-scan on a skip-scan index. For example: ** ** CREATE INDEX i1 ON t1(a, b, c); ** SELECT * FROM t1 WHERE a=? AND c BETWEEN ? AND ?; ** |
︙ | ︙ | |||
1399 1400 1401 1402 1403 1404 1405 | sqlite3ValueFree(p1); sqlite3ValueFree(p2); sqlite3ValueFree(pVal); return rc; } | | | 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 | sqlite3ValueFree(p1); sqlite3ValueFree(p2); sqlite3ValueFree(pVal); return rc; } #endif /* SQLITE_ENABLE_STAT4 */ /* ** This function is used to estimate the number of rows that will be visited ** by scanning an index for a range of values. The range may have an upper ** bound, a lower bound, or both. The WHERE clause terms that set the upper ** and lower bounds are represented by pLower and pUpper respectively. For ** example, assuming that index p is on t1(a): |
︙ | ︙ | |||
1452 1453 1454 1455 1456 1457 1458 | WhereTerm *pUpper, /* Upper bound on the range. ex: "x<455" Might be NULL */ WhereLoop *pLoop /* Modify the .nOut and maybe .rRun fields */ ){ int rc = SQLITE_OK; int nOut = pLoop->nOut; LogEst nNew; | | | | | 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 | WhereTerm *pUpper, /* Upper bound on the range. ex: "x<455" Might be NULL */ WhereLoop *pLoop /* Modify the .nOut and maybe .rRun fields */ ){ int rc = SQLITE_OK; int nOut = pLoop->nOut; LogEst nNew; #ifdef SQLITE_ENABLE_STAT4 Index *p = pLoop->u.btree.pIndex; int nEq = pLoop->u.btree.nEq; if( p->nSample>0 && ALWAYS(nEq<p->nSampleCol) && OptimizationEnabled(pParse->db, SQLITE_Stat4) ){ if( nEq==pBuilder->nRecValid ){ UnpackedRecord *pRec = pBuilder->pRec; tRowcnt a[2]; int nBtm = pLoop->u.btree.nBtm; int nTop = pLoop->u.btree.nTop; |
︙ | ︙ | |||
1555 1556 1557 1558 1559 1560 1561 | pBuilder->pRec = pRec; if( rc==SQLITE_OK ){ if( iUpper>iLower ){ nNew = sqlite3LogEst(iUpper - iLower); /* TUNING: If both iUpper and iLower are derived from the same ** sample, then assume they are 4x more selective. This brings ** the estimated selectivity more in line with what it would be | | | 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 | pBuilder->pRec = pRec; if( rc==SQLITE_OK ){ if( iUpper>iLower ){ nNew = sqlite3LogEst(iUpper - iLower); /* TUNING: If both iUpper and iLower are derived from the same ** sample, then assume they are 4x more selective. This brings ** the estimated selectivity more in line with what it would be ** if estimated without the use of STAT4 tables. */ if( iLwrIdx==iUprIdx ) nNew -= 20; assert( 20==sqlite3LogEst(4) ); }else{ nNew = 10; assert( 10==sqlite3LogEst(2) ); } if( nNew<nOut ){ nOut = nNew; } |
︙ | ︙ | |||
1604 1605 1606 1607 1608 1609 1610 | pLoop->nOut, nOut)); } #endif pLoop->nOut = (LogEst)nOut; return rc; } | | | | 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 | pLoop->nOut, nOut)); } #endif pLoop->nOut = (LogEst)nOut; return rc; } #ifdef SQLITE_ENABLE_STAT4 /* ** Estimate the number of rows that will be returned based on ** an equality constraint x=VALUE and where that VALUE occurs in ** the histogram data. This only works when x is the left-most ** column of an index and sqlite_stat4 histogram data is available ** for that index. When pExpr==NULL that means the constraint is ** "x IS NULL" instead of "x=VALUE". ** ** Write the estimated row count into *pnRow and return SQLITE_OK. ** If unable to make an estimate, leave *pnRow unchanged and return ** non-zero. ** |
︙ | ︙ | |||
1667 1668 1669 1670 1671 1672 1673 | whereKeyStats(pParse, p, pRec, 0, a); WHERETRACE(0x10,("equality scan regions %s(%d): %d\n", p->zName, nEq-1, (int)a[1])); *pnRow = a[1]; return rc; } | | | | 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 | whereKeyStats(pParse, p, pRec, 0, a); WHERETRACE(0x10,("equality scan regions %s(%d): %d\n", p->zName, nEq-1, (int)a[1])); *pnRow = a[1]; return rc; } #endif /* SQLITE_ENABLE_STAT4 */ #ifdef SQLITE_ENABLE_STAT4 /* ** Estimate the number of rows that will be returned based on ** an IN constraint where the right-hand side of the IN operator ** is a list of values. Example: ** ** WHERE x IN (1,2,3,4) ** |
︙ | ︙ | |||
1716 1717 1718 1719 1720 1721 1722 | if( nRowEst > nRow0 ) nRowEst = nRow0; *pnRow = nRowEst; WHERETRACE(0x10,("IN row estimate: est=%d\n", nRowEst)); } assert( pBuilder->nRecValid==nRecValid ); return rc; } | | | | | > > | | | | > > > > > > | < | < > > | > | | | | 1791 1792 1793 1794 1795 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 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 | if( nRowEst > nRow0 ) nRowEst = nRow0; *pnRow = nRowEst; WHERETRACE(0x10,("IN row estimate: est=%d\n", nRowEst)); } assert( pBuilder->nRecValid==nRecValid ); return rc; } #endif /* SQLITE_ENABLE_STAT4 */ #ifdef WHERETRACE_ENABLED /* ** Print the content of a WhereTerm object */ void sqlite3WhereTermPrint(WhereTerm *pTerm, int iTerm){ if( pTerm==0 ){ sqlite3DebugPrintf("TERM-%-3d NULL\n", iTerm); }else{ char zType[8]; char zLeft[50]; memcpy(zType, "....", 5); if( pTerm->wtFlags & TERM_VIRTUAL ) zType[0] = 'V'; if( pTerm->eOperator & WO_EQUIV ) zType[1] = 'E'; if( ExprHasProperty(pTerm->pExpr, EP_FromJoin) ) zType[2] = 'L'; if( pTerm->wtFlags & TERM_CODED ) zType[3] = 'C'; if( pTerm->eOperator & WO_SINGLE ){ assert( (pTerm->eOperator & (WO_OR|WO_AND))==0 ); sqlite3_snprintf(sizeof(zLeft),zLeft,"left={%d:%d}", pTerm->leftCursor, pTerm->u.x.leftColumn); }else if( (pTerm->eOperator & WO_OR)!=0 && pTerm->u.pOrInfo!=0 ){ sqlite3_snprintf(sizeof(zLeft),zLeft,"indexable=0x%llx", pTerm->u.pOrInfo->indexable); }else{ sqlite3_snprintf(sizeof(zLeft),zLeft,"left=%d", pTerm->leftCursor); } sqlite3DebugPrintf( "TERM-%-3d %p %s %-12s op=%03x wtFlags=%04x", iTerm, pTerm, zType, zLeft, pTerm->eOperator, pTerm->wtFlags); /* The 0x10000 .wheretrace flag causes extra information to be ** shown about each Term */ if( sqlite3WhereTrace & 0x10000 ){ sqlite3DebugPrintf(" prob=%-3d prereq=%llx,%llx", pTerm->truthProb, (u64)pTerm->prereqAll, (u64)pTerm->prereqRight); } if( (pTerm->eOperator & (WO_OR|WO_AND))==0 && pTerm->u.x.iField ){ sqlite3DebugPrintf(" iField=%d", pTerm->u.x.iField); } if( pTerm->iParent>=0 ){ sqlite3DebugPrintf(" iParent=%d", pTerm->iParent); } sqlite3DebugPrintf("\n"); sqlite3TreeViewExpr(0, pTerm->pExpr, 0); } } #endif #ifdef WHERETRACE_ENABLED /* ** Show the complete content of a WhereClause */ void sqlite3WhereClausePrint(WhereClause *pWC){ int i; for(i=0; i<pWC->nTerm; i++){ sqlite3WhereTermPrint(&pWC->a[i], i); } } #endif #ifdef WHERETRACE_ENABLED /* ** Print a WhereLoop object for debugging purposes */ void sqlite3WhereLoopPrint(WhereLoop *p, WhereClause *pWC){ WhereInfo *pWInfo = pWC->pWInfo; int nb = 1+(pWInfo->pTabList->nSrc+3)/4; SrcItem *pItem = pWInfo->pTabList->a + p->iTab; Table *pTab = pItem->pTab; Bitmask mAll = (((Bitmask)1)<<(nb*4)) - 1; sqlite3DebugPrintf("%c%2d.%0*llx.%0*llx", p->cId, p->iTab, nb, p->maskSelf, nb, p->prereq & mAll); sqlite3DebugPrintf(" %12s", pItem->zAlias ? pItem->zAlias : pTab->zName); if( (p->wsFlags & WHERE_VIRTUALTABLE)==0 ){ |
︙ | ︙ | |||
1797 1798 1799 1800 1801 1802 1803 | sqlite3DebugPrintf(".%-16s %2d", zName, p->u.btree.nEq); }else{ sqlite3DebugPrintf("%20s",""); } }else{ char *z; if( p->u.vtab.idxStr ){ | | | | 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 | sqlite3DebugPrintf(".%-16s %2d", zName, p->u.btree.nEq); }else{ sqlite3DebugPrintf("%20s",""); } }else{ char *z; if( p->u.vtab.idxStr ){ z = sqlite3_mprintf("(%d,\"%s\",%#x)", p->u.vtab.idxNum, p->u.vtab.idxStr, p->u.vtab.omitMask); }else{ z = sqlite3_mprintf("(%d,%x)", p->u.vtab.idxNum, p->u.vtab.omitMask); } sqlite3DebugPrintf(" %-19s", z); sqlite3_free(z); } if( p->wsFlags & WHERE_SKIPSCAN ){ sqlite3DebugPrintf(" f %05x %d-%d", p->wsFlags, p->nLTerm,p->nSkip); }else{ sqlite3DebugPrintf(" f %05x N %d", p->wsFlags, p->nLTerm); } sqlite3DebugPrintf(" cost %d,%d,%d\n", p->rSetup, p->rRun, p->nOut); if( p->nLTerm && (sqlite3WhereTrace & 0x100)!=0 ){ int i; for(i=0; i<p->nLTerm; i++){ sqlite3WhereTermPrint(p->aLTerm[i], i); } } } #endif /* ** Convert bulk memory into a valid WhereLoop that can be passed |
︙ | ︙ | |||
1879 1880 1881 1882 1883 1884 1885 | /* ** Transfer content from the second pLoop into the first. */ static int whereLoopXfer(sqlite3 *db, WhereLoop *pTo, WhereLoop *pFrom){ whereLoopClearUnion(db, pTo); if( whereLoopResize(db, pTo, pFrom->nLTerm) ){ | | | 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 | /* ** Transfer content from the second pLoop into the first. */ static int whereLoopXfer(sqlite3 *db, WhereLoop *pTo, WhereLoop *pFrom){ whereLoopClearUnion(db, pTo); if( whereLoopResize(db, pTo, pFrom->nLTerm) ){ memset(pTo, 0, WHERE_LOOP_XFER_SZ); return SQLITE_NOMEM_BKPT; } memcpy(pTo, pFrom, WHERE_LOOP_XFER_SZ); memcpy(pTo->aLTerm, pFrom->aLTerm, pTo->nLTerm*sizeof(pTo->aLTerm[0])); if( pFrom->wsFlags & WHERE_VIRTUALTABLE ){ pFrom->u.vtab.needFree = 0; }else if( (pFrom->wsFlags & WHERE_AUTO_INDEX)!=0 ){ |
︙ | ︙ | |||
1908 1909 1910 1911 1912 1913 1914 | ** Free a WhereInfo structure */ static void whereInfoFree(sqlite3 *db, WhereInfo *pWInfo){ int i; assert( pWInfo!=0 ); for(i=0; i<pWInfo->nLevel; i++){ WhereLevel *pLevel = &pWInfo->a[i]; | | > > > > > > > > > > > > > | > | 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 | ** Free a WhereInfo structure */ static void whereInfoFree(sqlite3 *db, WhereInfo *pWInfo){ int i; assert( pWInfo!=0 ); for(i=0; i<pWInfo->nLevel; i++){ WhereLevel *pLevel = &pWInfo->a[i]; if( pLevel->pWLoop && (pLevel->pWLoop->wsFlags & WHERE_IN_ABLE)!=0 ){ assert( (pLevel->pWLoop->wsFlags & WHERE_MULTI_OR)==0 ); sqlite3DbFree(db, pLevel->u.in.aInLoop); } } sqlite3WhereClauseClear(&pWInfo->sWC); while( pWInfo->pLoops ){ WhereLoop *p = pWInfo->pLoops; pWInfo->pLoops = p->pNextLoop; whereLoopDelete(db, p); } assert( pWInfo->pExprMods==0 ); sqlite3DbFreeNN(db, pWInfo); } /* Undo all Expr node modifications */ static void whereUndoExprMods(WhereInfo *pWInfo){ while( pWInfo->pExprMods ){ WhereExprMod *p = pWInfo->pExprMods; pWInfo->pExprMods = p->pNext; memcpy(p->pExpr, &p->orig, sizeof(p->orig)); sqlite3DbFree(pWInfo->pParse->db, p); } } /* ** Return TRUE if all of the following are true: ** ** (1) X has the same or lower cost, or returns the same or fewer rows, ** than Y. ** (2) X uses fewer WHERE clause terms than Y ** (3) Every WHERE clause term used by X is also used by Y ** (4) X skips at least as many columns as Y ** (5) If X is a covering index, than Y is too ** ** Conditions (2) and (3) mean that X is a "proper subset" of Y. ** If X is a proper subset of Y then Y is a better choice and ought |
︙ | ︙ | |||
1947 1948 1949 1950 1951 1952 1953 1954 | const WhereLoop *pX, /* First WhereLoop to compare */ const WhereLoop *pY /* Compare against this WhereLoop */ ){ int i, j; if( pX->nLTerm-pX->nSkip >= pY->nLTerm-pY->nSkip ){ return 0; /* X is not a subset of Y */ } if( pY->nSkip > pX->nSkip ) return 0; | > < < < < | | | > > | | | > > | | | 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 | const WhereLoop *pX, /* First WhereLoop to compare */ const WhereLoop *pY /* Compare against this WhereLoop */ ){ int i, j; if( pX->nLTerm-pX->nSkip >= pY->nLTerm-pY->nSkip ){ return 0; /* X is not a subset of Y */ } if( pX->rRun>pY->rRun && pX->nOut>pY->nOut ) return 0; if( pY->nSkip > pX->nSkip ) return 0; for(i=pX->nLTerm-1; i>=0; i--){ if( pX->aLTerm[i]==0 ) continue; for(j=pY->nLTerm-1; j>=0; j--){ if( pY->aLTerm[j]==pX->aLTerm[i] ) break; } if( j<0 ) return 0; /* X not a subset of Y since term X[i] not used by Y */ } if( (pX->wsFlags&WHERE_IDX_ONLY)!=0 && (pY->wsFlags&WHERE_IDX_ONLY)==0 ){ return 0; /* Constraint (5) */ } return 1; /* All conditions meet */ } /* ** Try to adjust the cost and number of output rows of WhereLoop pTemplate ** upwards or downwards so that: ** ** (1) pTemplate costs less than any other WhereLoops that are a proper ** subset of pTemplate ** ** (2) pTemplate costs more than any other WhereLoops for which pTemplate ** is a proper subset. ** ** To say "WhereLoop X is a proper subset of Y" means that X uses fewer ** WHERE clause terms than Y and that every WHERE clause term used by X is ** also used by Y. */ static void whereLoopAdjustCost(const WhereLoop *p, WhereLoop *pTemplate){ if( (pTemplate->wsFlags & WHERE_INDEXED)==0 ) return; for(; p; p=p->pNextLoop){ if( p->iTab!=pTemplate->iTab ) continue; if( (p->wsFlags & WHERE_INDEXED)==0 ) continue; if( whereLoopCheaperProperSubset(p, pTemplate) ){ /* Adjust pTemplate cost downward so that it is cheaper than its ** subset p. */ WHERETRACE(0x80,("subset cost adjustment %d,%d to %d,%d\n", pTemplate->rRun, pTemplate->nOut, MIN(p->rRun, pTemplate->rRun), MIN(p->nOut - 1, pTemplate->nOut))); pTemplate->rRun = MIN(p->rRun, pTemplate->rRun); pTemplate->nOut = MIN(p->nOut - 1, pTemplate->nOut); }else if( whereLoopCheaperProperSubset(pTemplate, p) ){ /* Adjust pTemplate cost upward so that it is costlier than p since ** pTemplate is a proper subset of p */ WHERETRACE(0x80,("subset cost adjustment %d,%d to %d,%d\n", pTemplate->rRun, pTemplate->nOut, MAX(p->rRun, pTemplate->rRun), MAX(p->nOut + 1, pTemplate->nOut))); pTemplate->rRun = MAX(p->rRun, pTemplate->rRun); pTemplate->nOut = MAX(p->nOut + 1, pTemplate->nOut); } } } /* ** Search the list of WhereLoops in *ppPrev looking for one that can be ** replaced by pTemplate. |
︙ | ︙ | |||
2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 | /* Stop the search once we hit the query planner search limit */ if( pBuilder->iPlanLimit==0 ){ WHERETRACE(0xffffffff,("=== query planner search limit reached ===\n")); if( pBuilder->pOrSet ) pBuilder->pOrSet->n = 0; return SQLITE_DONE; } pBuilder->iPlanLimit--; /* If pBuilder->pOrSet is defined, then only keep track of the costs ** and prereqs. */ if( pBuilder->pOrSet!=0 ){ if( pTemplate->nLTerm ){ #if WHERETRACE_ENABLED u16 n = pBuilder->pOrSet->n; int x = #endif whereOrInsert(pBuilder->pOrSet, pTemplate->prereq, pTemplate->rRun, pTemplate->nOut); #if WHERETRACE_ENABLED /* 0x8 */ if( sqlite3WhereTrace & 0x8 ){ sqlite3DebugPrintf(x?" or-%d: ":" or-X: ", n); | > > | < | | | | 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 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 | /* Stop the search once we hit the query planner search limit */ if( pBuilder->iPlanLimit==0 ){ WHERETRACE(0xffffffff,("=== query planner search limit reached ===\n")); if( pBuilder->pOrSet ) pBuilder->pOrSet->n = 0; return SQLITE_DONE; } pBuilder->iPlanLimit--; whereLoopAdjustCost(pWInfo->pLoops, pTemplate); /* If pBuilder->pOrSet is defined, then only keep track of the costs ** and prereqs. */ if( pBuilder->pOrSet!=0 ){ if( pTemplate->nLTerm ){ #if WHERETRACE_ENABLED u16 n = pBuilder->pOrSet->n; int x = #endif whereOrInsert(pBuilder->pOrSet, pTemplate->prereq, pTemplate->rRun, pTemplate->nOut); #if WHERETRACE_ENABLED /* 0x8 */ if( sqlite3WhereTrace & 0x8 ){ sqlite3DebugPrintf(x?" or-%d: ":" or-X: ", n); sqlite3WhereLoopPrint(pTemplate, pBuilder->pWC); } #endif } return SQLITE_OK; } /* Look for an existing WhereLoop to replace with pTemplate */ ppPrev = whereLoopFindLesser(&pWInfo->pLoops, pTemplate); if( ppPrev==0 ){ /* There already exists a WhereLoop on the list that is better ** than pTemplate, so just ignore pTemplate */ #if WHERETRACE_ENABLED /* 0x8 */ if( sqlite3WhereTrace & 0x8 ){ sqlite3DebugPrintf(" skip: "); sqlite3WhereLoopPrint(pTemplate, pBuilder->pWC); } #endif return SQLITE_OK; }else{ p = *ppPrev; } /* If we reach this point it means that either p[] should be overwritten ** with pTemplate[] if p[] exists, or if p==NULL then allocate a new ** WhereLoop and insert it. */ #if WHERETRACE_ENABLED /* 0x8 */ if( sqlite3WhereTrace & 0x8 ){ if( p!=0 ){ sqlite3DebugPrintf("replace: "); sqlite3WhereLoopPrint(p, pBuilder->pWC); sqlite3DebugPrintf(" with: "); }else{ sqlite3DebugPrintf(" add: "); } sqlite3WhereLoopPrint(pTemplate, pBuilder->pWC); } #endif if( p==0 ){ /* Allocate a new WhereLoop to add to the end of the list */ *ppPrev = p = sqlite3DbMallocRawNN(db, sizeof(WhereLoop)); if( p==0 ) return SQLITE_NOMEM_BKPT; whereLoopInit(p); |
︙ | ︙ | |||
2196 2197 2198 2199 2200 2201 2202 | if( ppTail==0 ) break; pToDel = *ppTail; if( pToDel==0 ) break; *ppTail = pToDel->pNextLoop; #if WHERETRACE_ENABLED /* 0x8 */ if( sqlite3WhereTrace & 0x8 ){ sqlite3DebugPrintf(" delete: "); | | | | 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 | if( ppTail==0 ) break; pToDel = *ppTail; if( pToDel==0 ) break; *ppTail = pToDel->pNextLoop; #if WHERETRACE_ENABLED /* 0x8 */ if( sqlite3WhereTrace & 0x8 ){ sqlite3DebugPrintf(" delete: "); sqlite3WhereLoopPrint(pToDel, pBuilder->pWC); } #endif whereLoopDelete(db, pToDel); } } rc = whereLoopXfer(db, p, pTemplate); if( (p->wsFlags & WHERE_VIRTUALTABLE)==0 ){ Index *pIndex = p->u.btree.pIndex; if( pIndex && pIndex->idxType==SQLITE_IDXTYPE_IPK ){ p->u.btree.pIndex = 0; } } return rc; } /* |
︙ | ︙ | |||
2248 2249 2250 2251 2252 2253 2254 | static void whereLoopOutputAdjust( WhereClause *pWC, /* The WHERE clause */ WhereLoop *pLoop, /* The loop to adjust downward */ LogEst nRow /* Number of rows in the entire table */ ){ WhereTerm *pTerm, *pX; Bitmask notAllowed = ~(pLoop->prereq|pLoop->maskSelf); | | > | > > > | > > > | 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 | static void whereLoopOutputAdjust( WhereClause *pWC, /* The WHERE clause */ WhereLoop *pLoop, /* The loop to adjust downward */ LogEst nRow /* Number of rows in the entire table */ ){ WhereTerm *pTerm, *pX; Bitmask notAllowed = ~(pLoop->prereq|pLoop->maskSelf); int i, j; LogEst iReduce = 0; /* pLoop->nOut should not exceed nRow-iReduce */ assert( (pLoop->wsFlags & WHERE_AUTO_INDEX)==0 ); for(i=pWC->nTerm, pTerm=pWC->a; i>0; i--, pTerm++){ assert( pTerm!=0 ); if( (pTerm->wtFlags & TERM_VIRTUAL)!=0 ) break; if( (pTerm->prereqAll & pLoop->maskSelf)==0 ) continue; if( (pTerm->prereqAll & notAllowed)!=0 ) continue; for(j=pLoop->nLTerm-1; j>=0; j--){ pX = pLoop->aLTerm[j]; if( pX==0 ) continue; if( pX==pTerm ) break; if( pX->iParent>=0 && (&pWC->a[pX->iParent])==pTerm ) break; } if( j<0 ){ if( pTerm->truthProb<=0 ){ /* If a truth probability is specified using the likelihood() hints, ** then use the probability provided by the application. */ pLoop->nOut += pTerm->truthProb; }else{ /* In the absence of explicit truth probabilities, use heuristics to ** guess a reasonable truth probability. */ pLoop->nOut--; if( (pTerm->eOperator&(WO_EQ|WO_IS))!=0 && (pTerm->wtFlags & TERM_HIGHTRUTH)==0 /* tag-20200224-1 */ ){ Expr *pRight = pTerm->pExpr->pRight; int k = 0; testcase( pTerm->pExpr->op==TK_IS ); if( sqlite3ExprIsInteger(pRight, &k) && k>=(-1) && k<=1 ){ k = 10; }else{ k = 20; } if( iReduce<k ){ pTerm->wtFlags |= TERM_HEURTRUTH; iReduce = k; } } } } } if( pLoop->nOut > nRow-iReduce ) pLoop->nOut = nRow - iReduce; } |
︙ | ︙ | |||
2321 2322 2323 2324 2325 2326 2327 | nCmp = MIN(nCmp, (pIdx->nColumn - nEq)); for(i=1; i<nCmp; i++){ /* Test if comparison i of pTerm is compatible with column (i+nEq) ** of the index. If not, exit the loop. */ char aff; /* Comparison affinity */ char idxaff = 0; /* Indexed columns affinity */ CollSeq *pColl; /* Comparison collation sequence */ | > > > | | | | 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 | nCmp = MIN(nCmp, (pIdx->nColumn - nEq)); for(i=1; i<nCmp; i++){ /* Test if comparison i of pTerm is compatible with column (i+nEq) ** of the index. If not, exit the loop. */ char aff; /* Comparison affinity */ char idxaff = 0; /* Indexed columns affinity */ CollSeq *pColl; /* Comparison collation sequence */ Expr *pLhs, *pRhs; assert( ExprUseXList(pTerm->pExpr->pLeft) ); pLhs = pTerm->pExpr->pLeft->x.pList->a[i].pExpr; pRhs = pTerm->pExpr->pRight; if( ExprUseXSelect(pRhs) ){ pRhs = pRhs->x.pSelect->pEList->a[i].pExpr; }else{ pRhs = pRhs->x.pList->a[i].pExpr; } /* Check that the LHS of the comparison is a column reference to ** the right column of the right source table. And that the sort |
︙ | ︙ | |||
2372 2373 2374 2375 2376 2377 2378 | ** index pIndex. Try to match one more. ** ** When this function is called, pBuilder->pNew->nOut contains the ** number of rows expected to be visited by filtering using the nEq ** terms only. If it is modified, this value is restored before this ** function returns. ** | | | | | 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 | ** index pIndex. Try to match one more. ** ** When this function is called, pBuilder->pNew->nOut contains the ** number of rows expected to be visited by filtering using the nEq ** terms only. If it is modified, this value is restored before this ** function returns. ** ** If pProbe->idxType==SQLITE_IDXTYPE_IPK, that means pIndex is ** a fake index used for the INTEGER PRIMARY KEY. */ static int whereLoopAddBtreeIndex( WhereLoopBuilder *pBuilder, /* The WhereLoop factory */ SrcItem *pSrc, /* FROM clause term being analyzed */ Index *pProbe, /* An index on pSrc */ LogEst nInMul /* log(Number of iterations due to IN) */ ){ WhereInfo *pWInfo = pBuilder->pWInfo; /* WHERE analyse context */ Parse *pParse = pWInfo->pParse; /* Parsing context */ sqlite3 *db = pParse->db; /* Database connection malloc context */ WhereLoop *pNew; /* Template WhereLoop under construction */ |
︙ | ︙ | |||
2403 2404 2405 2406 2407 2408 2409 | int rc = SQLITE_OK; /* Return code */ LogEst rSize; /* Number of rows in the table */ LogEst rLogSize; /* Logarithm of table size */ WhereTerm *pTop = 0, *pBtm = 0; /* Top and bottom range constraints */ pNew = pBuilder->pNew; if( db->mallocFailed ) return SQLITE_NOMEM_BKPT; | | | > > > | | | | | | | < < | | | > | | > | > | < > > > > > > | > | > > | | 2513 2514 2515 2516 2517 2518 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 | int rc = SQLITE_OK; /* Return code */ LogEst rSize; /* Number of rows in the table */ LogEst rLogSize; /* Logarithm of table size */ WhereTerm *pTop = 0, *pBtm = 0; /* Top and bottom range constraints */ pNew = pBuilder->pNew; if( db->mallocFailed ) return SQLITE_NOMEM_BKPT; WHERETRACE(0x800, ("BEGIN %s.addBtreeIdx(%s), nEq=%d, nSkip=%d, rRun=%d\n", pProbe->pTable->zName,pProbe->zName, pNew->u.btree.nEq, pNew->nSkip, pNew->rRun)); assert( (pNew->wsFlags & WHERE_VIRTUALTABLE)==0 ); assert( (pNew->wsFlags & WHERE_TOP_LIMIT)==0 ); if( pNew->wsFlags & WHERE_BTM_LIMIT ){ opMask = WO_LT|WO_LE; }else{ assert( pNew->u.btree.nBtm==0 ); opMask = WO_EQ|WO_IN|WO_GT|WO_GE|WO_LT|WO_LE|WO_ISNULL|WO_IS; } if( pProbe->bUnordered ) opMask &= ~(WO_GT|WO_GE|WO_LT|WO_LE); assert( pNew->u.btree.nEq<pProbe->nColumn ); assert( pNew->u.btree.nEq<pProbe->nKeyCol || pProbe->idxType!=SQLITE_IDXTYPE_PRIMARYKEY ); saved_nEq = pNew->u.btree.nEq; saved_nBtm = pNew->u.btree.nBtm; saved_nTop = pNew->u.btree.nTop; saved_nSkip = pNew->nSkip; saved_nLTerm = pNew->nLTerm; saved_wsFlags = pNew->wsFlags; saved_prereq = pNew->prereq; saved_nOut = pNew->nOut; pTerm = whereScanInit(&scan, pBuilder->pWC, pSrc->iCursor, saved_nEq, opMask, pProbe); pNew->rSetup = 0; rSize = pProbe->aiRowLogEst[0]; rLogSize = estLog(rSize); for(; rc==SQLITE_OK && pTerm!=0; pTerm = whereScanNext(&scan)){ u16 eOp = pTerm->eOperator; /* Shorthand for pTerm->eOperator */ LogEst rCostIdx; LogEst nOutUnadjusted; /* nOut before IN() and WHERE adjustments */ int nIn = 0; #ifdef SQLITE_ENABLE_STAT4 int nRecValid = pBuilder->nRecValid; #endif if( (eOp==WO_ISNULL || (pTerm->wtFlags&TERM_VNULL)!=0) && indexColumnNotNull(pProbe, saved_nEq) ){ continue; /* ignore IS [NOT] NULL constraints on NOT NULL columns */ } if( pTerm->prereqRight & pNew->maskSelf ) continue; /* Do not allow the upper bound of a LIKE optimization range constraint ** to mix with a lower range bound from some other source */ if( pTerm->wtFlags & TERM_LIKEOPT && pTerm->eOperator==WO_LT ) continue; /* tag-20191211-001: Do not allow constraints from the WHERE clause to ** be used by the right table of a LEFT JOIN. Only constraints in the ** ON clause are allowed. See tag-20191211-002 for the vtab equivalent. */ if( (pSrc->fg.jointype & JT_LEFT)!=0 && !ExprHasProperty(pTerm->pExpr, EP_FromJoin) ){ continue; } if( IsUniqueIndex(pProbe) && saved_nEq==pProbe->nKeyCol-1 ){ pBuilder->bldFlags1 |= SQLITE_BLDF1_UNIQUE; }else{ pBuilder->bldFlags1 |= SQLITE_BLDF1_INDEXED; } pNew->wsFlags = saved_wsFlags; pNew->u.btree.nEq = saved_nEq; pNew->u.btree.nBtm = saved_nBtm; pNew->u.btree.nTop = saved_nTop; pNew->nLTerm = saved_nLTerm; if( whereLoopResize(db, pNew, pNew->nLTerm+1) ) break; /* OOM */ pNew->aLTerm[pNew->nLTerm++] = pTerm; pNew->prereq = (saved_prereq | pTerm->prereqRight) & ~pNew->maskSelf; assert( nInMul==0 || (pNew->wsFlags & WHERE_COLUMN_NULL)!=0 || (pNew->wsFlags & WHERE_COLUMN_IN)!=0 || (pNew->wsFlags & WHERE_SKIPSCAN)!=0 ); if( eOp & WO_IN ){ Expr *pExpr = pTerm->pExpr; if( ExprUseXSelect(pExpr) ){ /* "x IN (SELECT ...)": TUNING: the SELECT returns 25 rows */ int i; nIn = 46; assert( 46==sqlite3LogEst(25) ); /* The expression may actually be of the form (x, y) IN (SELECT...). ** In this case there is a separate term for each of (x) and (y). ** However, the nIn multiplier should only be applied once, not once ** for each such term. The following loop checks that pTerm is the ** first such term in use, and sets nIn back to 0 if it is not. */ for(i=0; i<pNew->nLTerm-1; i++){ if( pNew->aLTerm[i] && pNew->aLTerm[i]->pExpr==pExpr ) nIn = 0; } }else if( ALWAYS(pExpr->x.pList && pExpr->x.pList->nExpr) ){ /* "x IN (value, value, ...)" */ nIn = sqlite3LogEst(pExpr->x.pList->nExpr); } if( pProbe->hasStat1 && rLogSize>=10 ){ LogEst M, logK, x; /* Let: ** N = the total number of rows in the table ** K = the number of entries on the RHS of the IN operator ** M = the number of rows in the table that match terms to the ** to the left in the same index. If the IN operator is on ** the left-most index column, M==N. ** ** Given the definitions above, it is better to omit the IN operator ** from the index lookup and instead do a scan of the M elements, ** testing each scanned row against the IN operator separately, if: ** ** M*log(K) < K*log(N) ** ** Our estimates for M, K, and N might be inaccurate, so we build in ** a safety margin of 2 (LogEst: 10) that favors using the IN operator ** with the index, as using an index has better worst-case behavior. ** If we do not have real sqlite_stat1 data, always prefer to use ** the index. Do not bother with this optimization on very small ** tables (less than 2 rows) as it is pointless in that case. */ M = pProbe->aiRowLogEst[saved_nEq]; logK = estLog(nIn); /* TUNING v----- 10 to bias toward indexed IN */ x = M + logK + 10 - (nIn + rLogSize); if( x>=0 ){ WHERETRACE(0x40, ("IN operator (N=%d M=%d logK=%d nIn=%d rLogSize=%d x=%d) " "prefers indexed lookup\n", saved_nEq, M, logK, nIn, rLogSize, x)); }else if( nInMul<2 && OptimizationEnabled(db, SQLITE_SeekScan) ){ WHERETRACE(0x40, ("IN operator (N=%d M=%d logK=%d nIn=%d rLogSize=%d x=%d" " nInMul=%d) prefers skip-scan\n", saved_nEq, M, logK, nIn, rLogSize, x, nInMul)); pNew->wsFlags |= WHERE_IN_SEEKSCAN; }else{ WHERETRACE(0x40, ("IN operator (N=%d M=%d logK=%d nIn=%d rLogSize=%d x=%d" " nInMul=%d) prefers normal scan\n", saved_nEq, M, logK, nIn, rLogSize, x, nInMul)); continue; } } pNew->wsFlags |= WHERE_COLUMN_IN; }else if( eOp & (WO_EQ|WO_IS) ){ int iCol = pProbe->aiColumn[saved_nEq]; pNew->wsFlags |= WHERE_COLUMN_EQ; assert( saved_nEq==pNew->u.btree.nEq ); if( iCol==XN_ROWID || (iCol>=0 && nInMul==0 && saved_nEq==pProbe->nKeyCol-1) ){ if( iCol==XN_ROWID || pProbe->uniqNotNull || (pProbe->nKeyCol==1 && pProbe->onError && eOp==WO_EQ) ){ pNew->wsFlags |= WHERE_ONEROW; }else{ pNew->wsFlags |= WHERE_UNQ_WANTED; } } if( scan.iEquiv>1 ) pNew->wsFlags |= WHERE_TRANSCONS; }else if( eOp & WO_ISNULL ){ pNew->wsFlags |= WHERE_COLUMN_NULL; }else if( eOp & (WO_GT|WO_GE) ){ testcase( eOp & WO_GT ); testcase( eOp & WO_GE ); pNew->wsFlags |= WHERE_COLUMN_RANGE|WHERE_BTM_LIMIT; pNew->u.btree.nBtm = whereRangeVectorLen( pParse, pSrc->iCursor, pProbe, saved_nEq, pTerm ); pBtm = pTerm; pTop = 0; if( pTerm->wtFlags & TERM_LIKEOPT ){ /* Range constraints that come from the LIKE optimization are ** always used in pairs. */ pTop = &pTerm[1]; assert( (pTop-(pTerm->pWC->a))<pTerm->pWC->nTerm ); assert( pTop->wtFlags & TERM_LIKEOPT ); assert( pTop->eOperator==WO_LT ); if( whereLoopResize(db, pNew, pNew->nLTerm+1) ) break; /* OOM */ pNew->aLTerm[pNew->nLTerm++] = pTop; |
︙ | ︙ | |||
2594 2595 2596 2597 2598 2599 2600 | /* At this point pNew->nOut is set to the number of rows expected to ** be visited by the index scan before considering term pTerm, or the ** values of nIn and nInMul. In other words, assuming that all ** "x IN(...)" terms are replaced with "x = ?". This block updates ** the value of pNew->nOut to account for pTerm (but not nIn/nInMul). */ assert( pNew->nOut==saved_nOut ); if( pNew->wsFlags & WHERE_COLUMN_RANGE ){ | | | | | | > > > > > > > > > > > > > > > > > > > > > | 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 | /* At this point pNew->nOut is set to the number of rows expected to ** be visited by the index scan before considering term pTerm, or the ** values of nIn and nInMul. In other words, assuming that all ** "x IN(...)" terms are replaced with "x = ?". This block updates ** the value of pNew->nOut to account for pTerm (but not nIn/nInMul). */ assert( pNew->nOut==saved_nOut ); if( pNew->wsFlags & WHERE_COLUMN_RANGE ){ /* Adjust nOut using stat4 data. Or, if there is no stat4 ** data, using some other estimate. */ whereRangeScanEst(pParse, pBuilder, pBtm, pTop, pNew); }else{ int nEq = ++pNew->u.btree.nEq; assert( eOp & (WO_ISNULL|WO_EQ|WO_IN|WO_IS) ); assert( pNew->nOut==saved_nOut ); if( pTerm->truthProb<=0 && pProbe->aiColumn[saved_nEq]>=0 ){ assert( (eOp & WO_IN) || nIn==0 ); testcase( eOp & WO_IN ); pNew->nOut += pTerm->truthProb; pNew->nOut -= nIn; }else{ #ifdef SQLITE_ENABLE_STAT4 tRowcnt nOut = 0; if( nInMul==0 && pProbe->nSample && ALWAYS(pNew->u.btree.nEq<=pProbe->nSampleCol) && ((eOp & WO_IN)==0 || ExprUseXList(pTerm->pExpr)) && OptimizationEnabled(db, SQLITE_Stat4) ){ Expr *pExpr = pTerm->pExpr; if( (eOp & (WO_EQ|WO_ISNULL|WO_IS))!=0 ){ testcase( eOp & WO_EQ ); testcase( eOp & WO_IS ); testcase( eOp & WO_ISNULL ); rc = whereEqualScanEst(pParse, pBuilder, pExpr->pRight, &nOut); }else{ rc = whereInScanEst(pParse, pBuilder, pExpr->x.pList, &nOut); } if( rc==SQLITE_NOTFOUND ) rc = SQLITE_OK; if( rc!=SQLITE_OK ) break; /* Jump out of the pTerm loop */ if( nOut ){ pNew->nOut = sqlite3LogEst(nOut); if( nEq==1 /* TUNING: Mark terms as "low selectivity" if they seem likely ** to be true for half or more of the rows in the table. ** See tag-202002240-1 */ && pNew->nOut+10 > pProbe->aiRowLogEst[0] ){ #if WHERETRACE_ENABLED /* 0x01 */ if( sqlite3WhereTrace & 0x01 ){ sqlite3DebugPrintf( "STAT4 determines term has low selectivity:\n"); sqlite3WhereTermPrint(pTerm, 999); } #endif pTerm->wtFlags |= TERM_HIGHTRUTH; if( pTerm->wtFlags & TERM_HEURTRUTH ){ /* If the term has previously been used with an assumption of ** higher selectivity, then set the flag to rerun the ** loop computations. */ pBuilder->bldFlags2 |= SQLITE_BLDF2_2NDPASS; } } if( pNew->nOut>saved_nOut ) pNew->nOut = saved_nOut; pNew->nOut -= nIn; } } if( nOut==0 ) #endif { |
︙ | ︙ | |||
2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 | } } /* Set rCostIdx to the cost of visiting selected rows in index. Add ** it to pNew->rRun, which is currently set to the cost of the index ** seek only. Then, if this is a non-covering index, add the cost of ** visiting the rows in the main table. */ rCostIdx = pNew->nOut + 1 + (15*pProbe->szIdxRow)/pSrc->pTab->szTabRow; pNew->rRun = sqlite3LogEstAdd(rLogSize, rCostIdx); if( (pNew->wsFlags & (WHERE_IDX_ONLY|WHERE_IPK))==0 ){ pNew->rRun = sqlite3LogEstAdd(pNew->rRun, pNew->nOut + 16); } ApplyCostMultiplier(pNew->rRun, pProbe->pTable->costMult); | > | 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 | } } /* Set rCostIdx to the cost of visiting selected rows in index. Add ** it to pNew->rRun, which is currently set to the cost of the index ** seek only. Then, if this is a non-covering index, add the cost of ** visiting the rows in the main table. */ assert( pSrc->pTab->szTabRow>0 ); rCostIdx = pNew->nOut + 1 + (15*pProbe->szIdxRow)/pSrc->pTab->szTabRow; pNew->rRun = sqlite3LogEstAdd(rLogSize, rCostIdx); if( (pNew->wsFlags & (WHERE_IDX_ONLY|WHERE_IPK))==0 ){ pNew->rRun = sqlite3LogEstAdd(pNew->rRun, pNew->nOut + 16); } ApplyCostMultiplier(pNew->rRun, pProbe->pTable->costMult); |
︙ | ︙ | |||
2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 | pNew->nOut = saved_nOut; }else{ pNew->nOut = nOutUnadjusted; } if( (pNew->wsFlags & WHERE_TOP_LIMIT)==0 && pNew->u.btree.nEq<pProbe->nColumn ){ whereLoopAddBtreeIndex(pBuilder, pSrc, pProbe, nInMul+nIn); } pNew->nOut = saved_nOut; | > > | | 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 | pNew->nOut = saved_nOut; }else{ pNew->nOut = nOutUnadjusted; } if( (pNew->wsFlags & WHERE_TOP_LIMIT)==0 && pNew->u.btree.nEq<pProbe->nColumn && (pNew->u.btree.nEq<pProbe->nKeyCol || pProbe->idxType!=SQLITE_IDXTYPE_PRIMARYKEY) ){ whereLoopAddBtreeIndex(pBuilder, pSrc, pProbe, nInMul+nIn); } pNew->nOut = saved_nOut; #ifdef SQLITE_ENABLE_STAT4 pBuilder->nRecValid = nRecValid; #endif } pNew->prereq = saved_prereq; pNew->u.btree.nEq = saved_nEq; pNew->u.btree.nBtm = saved_nBtm; pNew->u.btree.nTop = saved_nTop; |
︙ | ︙ | |||
2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 | ** contains fewer than 2^17 rows we assume otherwise in other parts of ** the code). And, even if it is not, it should not be too much slower. ** On the other hand, the extra seeks could end up being significantly ** more expensive. */ assert( 42==sqlite3LogEst(18) ); if( saved_nEq==saved_nSkip && saved_nEq+1<pProbe->nKeyCol && pProbe->noSkipScan==0 && OptimizationEnabled(db, SQLITE_SkipScan) && pProbe->aiRowLogEst[saved_nEq+1]>=42 /* TUNING: Minimum for skip-scan */ && (rc = whereLoopResize(db, pNew, pNew->nLTerm+1))==SQLITE_OK ){ LogEst nIter; pNew->u.btree.nEq++; pNew->nSkip++; | > > | 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 | ** contains fewer than 2^17 rows we assume otherwise in other parts of ** the code). And, even if it is not, it should not be too much slower. ** On the other hand, the extra seeks could end up being significantly ** more expensive. */ assert( 42==sqlite3LogEst(18) ); if( saved_nEq==saved_nSkip && saved_nEq+1<pProbe->nKeyCol && saved_nEq==pNew->nLTerm && pProbe->noSkipScan==0 && pProbe->hasStat1!=0 && OptimizationEnabled(db, SQLITE_SkipScan) && pProbe->aiRowLogEst[saved_nEq+1]>=42 /* TUNING: Minimum for skip-scan */ && (rc = whereLoopResize(db, pNew, pNew->nLTerm+1))==SQLITE_OK ){ LogEst nIter; pNew->u.btree.nEq++; pNew->nSkip++; |
︙ | ︙ | |||
2749 2750 2751 2752 2753 2754 2755 | ExprList *pOB; ExprList *aColExpr; int ii, jj; if( pIndex->bUnordered ) return 0; if( (pOB = pBuilder->pWInfo->pOrderBy)==0 ) return 0; for(ii=0; ii<pOB->nExpr; ii++){ | | > | > > > > > | > | > | > | 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 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 | ExprList *pOB; ExprList *aColExpr; int ii, jj; if( pIndex->bUnordered ) return 0; if( (pOB = pBuilder->pWInfo->pOrderBy)==0 ) return 0; for(ii=0; ii<pOB->nExpr; ii++){ Expr *pExpr = sqlite3ExprSkipCollateAndLikely(pOB->a[ii].pExpr); if( NEVER(pExpr==0) ) continue; if( pExpr->op==TK_COLUMN && pExpr->iTable==iCursor ){ if( pExpr->iColumn<0 ) return 1; for(jj=0; jj<pIndex->nKeyCol; jj++){ if( pExpr->iColumn==pIndex->aiColumn[jj] ) return 1; } }else if( (aColExpr = pIndex->aColExpr)!=0 ){ for(jj=0; jj<pIndex->nKeyCol; jj++){ if( pIndex->aiColumn[jj]!=XN_EXPR ) continue; if( sqlite3ExprCompareSkip(pExpr,aColExpr->a[jj].pExpr,iCursor)==0 ){ return 1; } } } } return 0; } /* Check to see if a partial index with pPartIndexWhere can be used ** in the current query. Return true if it can be and false if not. */ static int whereUsablePartialIndex( int iTab, /* The table for which we want an index */ int isLeft, /* True if iTab is the right table of a LEFT JOIN */ WhereClause *pWC, /* The WHERE clause of the query */ Expr *pWhere /* The WHERE clause from the partial index */ ){ int i; WhereTerm *pTerm; Parse *pParse = pWC->pWInfo->pParse; while( pWhere->op==TK_AND ){ if( !whereUsablePartialIndex(iTab,isLeft,pWC,pWhere->pLeft) ) return 0; pWhere = pWhere->pRight; } if( pParse->db->flags & SQLITE_EnableQPSG ) pParse = 0; for(i=0, pTerm=pWC->a; i<pWC->nTerm; i++, pTerm++){ Expr *pExpr; pExpr = pTerm->pExpr; if( (!ExprHasProperty(pExpr, EP_FromJoin) || pExpr->iRightJoinTable==iTab) && (isLeft==0 || ExprHasProperty(pExpr, EP_FromJoin)) && sqlite3ExprImpliesExpr(pParse, pExpr, pWhere, iTab) && (pTerm->wtFlags & TERM_VNULL)==0 ){ return 1; } } return 0; } |
︙ | ︙ | |||
2836 2837 2838 2839 2840 2841 2842 | ){ WhereInfo *pWInfo; /* WHERE analysis context */ Index *pProbe; /* An index we are evaluating */ Index sPk; /* A fake index object for the primary key */ LogEst aiRowEstPk[2]; /* The aiRowLogEst[] value for the sPk index */ i16 aiColumnPk = -1; /* The aColumn[] value for the sPk index */ SrcList *pTabList; /* The FROM clause */ | | < | > | > < | > > | | 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 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 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 | ){ WhereInfo *pWInfo; /* WHERE analysis context */ Index *pProbe; /* An index we are evaluating */ Index sPk; /* A fake index object for the primary key */ LogEst aiRowEstPk[2]; /* The aiRowLogEst[] value for the sPk index */ i16 aiColumnPk = -1; /* The aColumn[] value for the sPk index */ SrcList *pTabList; /* The FROM clause */ SrcItem *pSrc; /* The FROM clause btree term to add */ WhereLoop *pNew; /* Template WhereLoop object */ int rc = SQLITE_OK; /* Return code */ int iSortIdx = 1; /* Index number */ int b; /* A boolean value */ LogEst rSize; /* number of rows in the table */ WhereClause *pWC; /* The parsed WHERE clause */ Table *pTab; /* Table being queried */ pNew = pBuilder->pNew; pWInfo = pBuilder->pWInfo; pTabList = pWInfo->pTabList; pSrc = pTabList->a + pNew->iTab; pTab = pSrc->pTab; pWC = pBuilder->pWC; assert( !IsVirtual(pSrc->pTab) ); if( pSrc->fg.isIndexedBy ){ assert( pSrc->fg.isCte==0 ); /* An INDEXED BY clause specifies a particular index to use */ pProbe = pSrc->u2.pIBIndex; }else if( !HasRowid(pTab) ){ pProbe = pTab->pIndex; }else{ /* There is no INDEXED BY clause. Create a fake Index object in local ** variable sPk to represent the rowid primary key index. Make this ** fake index the first in a chain of Index objects with all of the real ** indices to follow */ Index *pFirst; /* First of real indices on the table */ memset(&sPk, 0, sizeof(Index)); sPk.nKeyCol = 1; sPk.nColumn = 1; sPk.aiColumn = &aiColumnPk; sPk.aiRowLogEst = aiRowEstPk; sPk.onError = OE_Replace; sPk.pTable = pTab; sPk.szIdxRow = pTab->szTabRow; sPk.idxType = SQLITE_IDXTYPE_IPK; aiRowEstPk[0] = pTab->nRowLogEst; aiRowEstPk[1] = 0; pFirst = pSrc->pTab->pIndex; if( pSrc->fg.notIndexed==0 ){ /* The real indices of the table are only considered if the ** NOT INDEXED qualifier is omitted from the FROM clause */ sPk.pNext = pFirst; } pProbe = &sPk; } rSize = pTab->nRowLogEst; #ifndef SQLITE_OMIT_AUTOMATIC_INDEX /* Automatic indexes */ if( !pBuilder->pOrSet /* Not part of an OR optimization */ && (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)==0 && (pWInfo->pParse->db->flags & SQLITE_AutoIndex)!=0 && !pSrc->fg.isIndexedBy /* Has no INDEXED BY clause */ && !pSrc->fg.notIndexed /* Has no NOT INDEXED clause */ && HasRowid(pTab) /* Not WITHOUT ROWID table. (FIXME: Why not?) */ && !pSrc->fg.isCorrelated /* Not a correlated subquery */ && !pSrc->fg.isRecursive /* Not a recursive common table expression. */ ){ /* Generate auto-index WhereLoops */ LogEst rLogSize; /* Logarithm of the number of rows in the table */ WhereTerm *pTerm; WhereTerm *pWCEnd = pWC->a + pWC->nTerm; rLogSize = estLog(rSize); for(pTerm=pWC->a; rc==SQLITE_OK && pTerm<pWCEnd; pTerm++){ if( pTerm->prereqRight & pNew->maskSelf ) continue; if( termCanDriveIndex(pTerm, pSrc, 0) ){ pNew->u.btree.nEq = 1; pNew->nSkip = 0; pNew->u.btree.pIndex = 0; pNew->nLTerm = 1; pNew->aLTerm[0] = pTerm; /* TUNING: One-time cost for computing the automatic index is ** estimated to be X*N*log2(N) where N is the number of rows in ** the table being indexed and where X is 7 (LogEst=28) for normal ** tables or 0.5 (LogEst=-10) for views and subqueries. The value ** of X is smaller for views and subqueries so that the query planner ** will be more aggressive about generating automatic indexes for ** those objects, since there is no opportunity to add schema ** indexes on subqueries and views. */ pNew->rSetup = rLogSize + rSize; if( !IsView(pTab) && (pTab->tabFlags & TF_Ephemeral)==0 ){ pNew->rSetup += 28; }else{ pNew->rSetup -= 10; } ApplyCostMultiplier(pNew->rSetup, pTab->costMult); if( pNew->rSetup<0 ) pNew->rSetup = 0; /* TUNING: Each index lookup yields 20 rows in the table. This |
︙ | ︙ | |||
2941 2942 2943 2944 2945 2946 2947 | } } #endif /* SQLITE_OMIT_AUTOMATIC_INDEX */ /* Loop over all indices. If there was an INDEXED BY clause, then only ** consider index pProbe. */ for(; rc==SQLITE_OK && pProbe; | | > | > > > | | > > > > > > > > > > > > > > > > | 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 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 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 | } } #endif /* SQLITE_OMIT_AUTOMATIC_INDEX */ /* Loop over all indices. If there was an INDEXED BY clause, then only ** consider index pProbe. */ for(; rc==SQLITE_OK && pProbe; pProbe=(pSrc->fg.isIndexedBy ? 0 : pProbe->pNext), iSortIdx++ ){ int isLeft = (pSrc->fg.jointype & JT_OUTER)!=0; if( pProbe->pPartIdxWhere!=0 && !whereUsablePartialIndex(pSrc->iCursor, isLeft, pWC, pProbe->pPartIdxWhere) ){ testcase( pNew->iTab!=pSrc->iCursor ); /* See ticket [98d973b8f5] */ continue; /* Partial index inappropriate for this query */ } if( pProbe->bNoQuery ) continue; rSize = pProbe->aiRowLogEst[0]; pNew->u.btree.nEq = 0; pNew->u.btree.nBtm = 0; pNew->u.btree.nTop = 0; pNew->nSkip = 0; pNew->nLTerm = 0; pNew->iSortIdx = 0; pNew->rSetup = 0; pNew->prereq = mPrereq; pNew->nOut = rSize; pNew->u.btree.pIndex = pProbe; b = indexMightHelpWithOrderBy(pBuilder, pProbe, pSrc->iCursor); /* The ONEPASS_DESIRED flags never occurs together with ORDER BY */ assert( (pWInfo->wctrlFlags & WHERE_ONEPASS_DESIRED)==0 || b==0 ); if( pProbe->idxType==SQLITE_IDXTYPE_IPK ){ /* Integer primary key index */ pNew->wsFlags = WHERE_IPK; /* Full table scan */ pNew->iSortIdx = b ? iSortIdx : 0; /* TUNING: Cost of full table scan is 3.0*N. The 3.0 factor is an ** extra cost designed to discourage the use of full table scans, ** since index lookups have better worst-case performance if our ** stat guesses are wrong. Reduce the 3.0 penalty slightly ** (to 2.75) if we have valid STAT4 information for the table. ** At 2.75, a full table scan is preferred over using an index on ** a column with just two distinct values where each value has about ** an equal number of appearances. Without STAT4 data, we still want ** to use an index in that case, since the constraint might be for ** the scarcer of the two values, and in that case an index lookup is ** better. */ #ifdef SQLITE_ENABLE_STAT4 pNew->rRun = rSize + 16 - 2*((pTab->tabFlags & TF_HasStat4)!=0); #else pNew->rRun = rSize + 16; #endif ApplyCostMultiplier(pNew->rRun, pTab->costMult); whereLoopOutputAdjust(pWC, pNew, rSize); rc = whereLoopInsert(pBuilder, pNew); pNew->nOut = rSize; if( rc ) break; }else{ Bitmask m; if( pProbe->isCovering ){ pNew->wsFlags = WHERE_IDX_ONLY | WHERE_INDEXED; m = 0; }else{ m = pSrc->colUsed & pProbe->colNotIdxed; pNew->wsFlags = (m==0) ? (WHERE_IDX_ONLY|WHERE_INDEXED) : WHERE_INDEXED; } /* Full scan via index */ if( b || !HasRowid(pTab) || pProbe->pPartIdxWhere!=0 || pSrc->fg.isIndexedBy || ( m==0 && pProbe->bUnordered==0 && (pProbe->szIdxRow<pTab->szTabRow) && (pWInfo->wctrlFlags & WHERE_ONEPASS_DESIRED)==0 && sqlite3GlobalConfig.bUseCis && OptimizationEnabled(pWInfo->pParse->db, SQLITE_CoverIdxScan) ) |
︙ | ︙ | |||
3039 3040 3041 3042 3043 3044 3045 | whereLoopOutputAdjust(pWC, pNew, rSize); rc = whereLoopInsert(pBuilder, pNew); pNew->nOut = rSize; if( rc ) break; } } | | | | | 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 | whereLoopOutputAdjust(pWC, pNew, rSize); rc = whereLoopInsert(pBuilder, pNew); pNew->nOut = rSize; if( rc ) break; } } pBuilder->bldFlags1 = 0; rc = whereLoopAddBtreeIndex(pBuilder, pSrc, pProbe, 0); if( pBuilder->bldFlags1==SQLITE_BLDF1_INDEXED ){ /* If a non-unique index is used, or if a prefix of the key for ** unique index is used (making the index functionally non-unique) ** then the sqlite_stat1 data becomes important for scoring the ** plan */ pTab->tabFlags |= TF_StatsUsed; } #ifdef SQLITE_ENABLE_STAT4 sqlite3Stat4ProbeFree(pBuilder->pRec); pBuilder->nRecValid = 0; pBuilder->pRec = 0; #endif } return rc; } |
︙ | ︙ | |||
3096 3097 3098 3099 3100 3101 3102 | struct sqlite3_index_constraint *pIdxCons; struct sqlite3_index_constraint_usage *pUsage = pIdxInfo->aConstraintUsage; int i; int mxTerm; int rc = SQLITE_OK; WhereLoop *pNew = pBuilder->pNew; Parse *pParse = pBuilder->pWInfo->pParse; | | | 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 | struct sqlite3_index_constraint *pIdxCons; struct sqlite3_index_constraint_usage *pUsage = pIdxInfo->aConstraintUsage; int i; int mxTerm; int rc = SQLITE_OK; WhereLoop *pNew = pBuilder->pNew; Parse *pParse = pBuilder->pWInfo->pParse; SrcItem *pSrc = &pBuilder->pWInfo->pTabList->a[pNew->iTab]; int nConstraint = pIdxInfo->nConstraint; assert( (mUsable & mPrereq)==mPrereq ); *pbIn = 0; pNew->prereq = mPrereq; /* Set the usable flag on the subset of constraints identified by |
︙ | ︙ | |||
3171 3172 3173 3174 3175 3176 3177 | pTerm = &pWC->a[j]; pNew->prereq |= pTerm->prereqRight; assert( iTerm<pNew->nLSlot ); pNew->aLTerm[iTerm] = pTerm; if( iTerm>mxTerm ) mxTerm = iTerm; testcase( iTerm==15 ); testcase( iTerm==16 ); | > > > | > > > > < | 3350 3351 3352 3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 3368 3369 3370 3371 3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 | pTerm = &pWC->a[j]; pNew->prereq |= pTerm->prereqRight; assert( iTerm<pNew->nLSlot ); pNew->aLTerm[iTerm] = pTerm; if( iTerm>mxTerm ) mxTerm = iTerm; testcase( iTerm==15 ); testcase( iTerm==16 ); if( pUsage[i].omit ){ if( i<16 && ((1<<i)&mNoOmit)==0 ){ testcase( i!=iTerm ); pNew->u.vtab.omitMask |= 1<<iTerm; }else{ testcase( i!=iTerm ); } } if( (pTerm->eOperator & WO_IN)!=0 ){ /* A virtual table that is constrained by an IN clause may not ** consume the ORDER BY clause because (1) the order of IN terms ** is not necessarily related to the order of output terms and ** (2) Multiple outputs from a single IN value will not merge ** together. */ pIdxInfo->orderByConsumed = 0; pIdxInfo->idxFlags &= ~SQLITE_INDEX_SCAN_UNIQUE; *pbIn = 1; assert( (mExclude & WO_IN)==0 ); } } } pNew->nLTerm = mxTerm+1; for(i=0; i<=mxTerm; i++){ if( pNew->aLTerm[i]==0 ){ /* The non-zero argvIdx values must be contiguous. Raise an ** error if they are not */ sqlite3ErrorMsg(pParse,"%s.xBestIndex malfunction",pSrc->pTab->zName); |
︙ | ︙ | |||
3241 3242 3243 3244 3245 3246 3247 | HiddenIndexInfo *pHidden = (HiddenIndexInfo*)&pIdxInfo[1]; const char *zRet = 0; if( iCons>=0 && iCons<pIdxInfo->nConstraint ){ CollSeq *pC = 0; int iTerm = pIdxInfo->aConstraint[iCons].iTermOffset; Expr *pX = pHidden->pWC->a[iTerm].pExpr; if( pX->pLeft ){ | | | 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 | HiddenIndexInfo *pHidden = (HiddenIndexInfo*)&pIdxInfo[1]; const char *zRet = 0; if( iCons>=0 && iCons<pIdxInfo->nConstraint ){ CollSeq *pC = 0; int iTerm = pIdxInfo->aConstraint[iCons].iTermOffset; Expr *pX = pHidden->pWC->a[iTerm].pExpr; if( pX->pLeft ){ pC = sqlite3ExprCompareCollSeq(pHidden->pParse, pX); } zRet = (pC ? pC->zName : sqlite3StrBINARY); } return zRet; } /* |
︙ | ︙ | |||
3282 3283 3284 3285 3286 3287 3288 | Bitmask mPrereq, /* Tables that must be scanned before this one */ Bitmask mUnusable /* Tables that must be scanned after this one */ ){ int rc = SQLITE_OK; /* Return code */ WhereInfo *pWInfo; /* WHERE analysis context */ Parse *pParse; /* The parsing context */ WhereClause *pWC; /* The WHERE clause */ | | | 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 | Bitmask mPrereq, /* Tables that must be scanned before this one */ Bitmask mUnusable /* Tables that must be scanned after this one */ ){ int rc = SQLITE_OK; /* Return code */ WhereInfo *pWInfo; /* WHERE analysis context */ Parse *pParse; /* The parsing context */ WhereClause *pWC; /* The WHERE clause */ SrcItem *pSrc; /* The FROM clause term to search */ sqlite3_index_info *p; /* Object to pass to xBestIndex() */ int nConstraint; /* Number of constraints in p */ int bIn; /* True if plan uses IN(...) operator */ WhereLoop *pNew; Bitmask mBest; /* Tables used by best possible plan */ u16 mNoOmit; |
︙ | ︙ | |||
3316 3317 3318 3319 3320 3321 3322 | /* First call xBestIndex() with all constraints usable. */ WHERETRACE(0x800, ("BEGIN %s.addVirtual()\n", pSrc->pTab->zName)); WHERETRACE(0x40, (" VirtualOne: all usable\n")); rc = whereLoopAddVirtualOne(pBuilder, mPrereq, ALLBITS, 0, p, mNoOmit, &bIn); /* If the call to xBestIndex() with all terms enabled produced a plan | | | | | | | 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 | /* First call xBestIndex() with all constraints usable. */ WHERETRACE(0x800, ("BEGIN %s.addVirtual()\n", pSrc->pTab->zName)); WHERETRACE(0x40, (" VirtualOne: all usable\n")); rc = whereLoopAddVirtualOne(pBuilder, mPrereq, ALLBITS, 0, p, mNoOmit, &bIn); /* If the call to xBestIndex() with all terms enabled produced a plan ** that does not require any source tables (IOW: a plan with mBest==0) ** and does not use an IN(...) operator, then there is no point in making ** any further calls to xBestIndex() since they will all return the same ** result (if the xBestIndex() implementation is sane). */ if( rc==SQLITE_OK && ((mBest = (pNew->prereq & ~mPrereq))!=0 || bIn) ){ int seenZero = 0; /* True if a plan with no prereqs seen */ int seenZeroNoIN = 0; /* Plan with no prereqs and no IN(...) seen */ Bitmask mPrev = 0; Bitmask mBestNoIn = 0; /* If the plan produced by the earlier call uses an IN(...) term, call ** xBestIndex again, this time with IN(...) terms disabled. */ |
︙ | ︙ | |||
3410 3411 3412 3413 3414 3415 3416 | WhereLoop *pNew; WhereTerm *pTerm, *pWCEnd; int rc = SQLITE_OK; int iCur; WhereClause tempWC; WhereLoopBuilder sSubBuild; WhereOrSet sSum, sCur; | | | 3595 3596 3597 3598 3599 3600 3601 3602 3603 3604 3605 3606 3607 3608 3609 | WhereLoop *pNew; WhereTerm *pTerm, *pWCEnd; int rc = SQLITE_OK; int iCur; WhereClause tempWC; WhereLoopBuilder sSubBuild; WhereOrSet sSum, sCur; SrcItem *pItem; pWC = pBuilder->pWC; pWCEnd = pWC->a + pWC->nTerm; pNew = pBuilder->pNew; memset(&sSum, 0, sizeof(sSum)); pItem = pWInfo->pTabList->a + pNew->iTab; iCur = pItem->iCursor; |
︙ | ︙ | |||
3466 3467 3468 3469 3470 3471 3472 | #endif { rc = whereLoopAddBtree(&sSubBuild, mPrereq); } if( rc==SQLITE_OK ){ rc = whereLoopAddOr(&sSubBuild, mPrereq, mUnusable); } | | > > > | 3651 3652 3653 3654 3655 3656 3657 3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 | #endif { rc = whereLoopAddBtree(&sSubBuild, mPrereq); } if( rc==SQLITE_OK ){ rc = whereLoopAddOr(&sSubBuild, mPrereq, mUnusable); } assert( rc==SQLITE_OK || rc==SQLITE_DONE || sCur.n==0 || rc==SQLITE_NOMEM ); testcase( rc==SQLITE_NOMEM && sCur.n>0 ); testcase( rc==SQLITE_DONE ); if( sCur.n==0 ){ sSum.n = 0; break; }else if( once ){ whereOrMove(&sSum, &sCur); once = 0; }else{ |
︙ | ︙ | |||
3525 3526 3527 3528 3529 3530 3531 | */ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){ WhereInfo *pWInfo = pBuilder->pWInfo; Bitmask mPrereq = 0; Bitmask mPrior = 0; int iTab; SrcList *pTabList = pWInfo->pTabList; | | | < | > > < | | 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 | */ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){ WhereInfo *pWInfo = pBuilder->pWInfo; Bitmask mPrereq = 0; Bitmask mPrior = 0; int iTab; SrcList *pTabList = pWInfo->pTabList; SrcItem *pItem; SrcItem *pEnd = &pTabList->a[pWInfo->nLevel]; sqlite3 *db = pWInfo->pParse->db; int rc = SQLITE_OK; WhereLoop *pNew; /* Loop over the tables in the join, from left to right */ pNew = pBuilder->pNew; whereLoopInit(pNew); pBuilder->iPlanLimit = SQLITE_QUERY_PLANNER_LIMIT; for(iTab=0, pItem=pTabList->a; pItem<pEnd; iTab++, pItem++){ Bitmask mUnusable = 0; pNew->iTab = iTab; pBuilder->iPlanLimit += SQLITE_QUERY_PLANNER_LIMIT_INCR; pNew->maskSelf = sqlite3WhereGetMask(&pWInfo->sMaskSet, pItem->iCursor); if( (pItem->fg.jointype & (JT_LEFT|JT_CROSS))!=0 ){ /* This condition is true when pItem is the FROM clause term on the ** right-hand-side of a LEFT or CROSS JOIN. */ mPrereq = mPrior; }else{ mPrereq = 0; } #ifndef SQLITE_OMIT_VIRTUALTABLE if( IsVirtual(pItem->pTab) ){ SrcItem *p; for(p=&pItem[1]; p<pEnd; p++){ if( mUnusable || (p->fg.jointype & (JT_LEFT|JT_CROSS)) ){ mUnusable |= sqlite3WhereGetMask(&pWInfo->sMaskSet, p->iCursor); } } rc = whereLoopAddVirtual(pBuilder, mPrereq, mUnusable); }else |
︙ | ︙ | |||
3664 3665 3666 3667 3668 3669 3670 | testcase( nOrderBy==BMS-1 ); if( nOrderBy>BMS-1 ) return 0; /* Cannot optimize overly large ORDER BYs */ isOrderDistinct = 1; obDone = MASKBIT(nOrderBy)-1; orderDistinctMask = 0; ready = 0; eqOpMask = WO_EQ | WO_IS | WO_ISNULL; | > | > | > > | | | > | | > | | > > > > > > > | > | > > > | > > | > | 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 3940 3941 3942 3943 3944 3945 3946 3947 3948 3949 3950 3951 3952 3953 3954 3955 3956 3957 3958 3959 3960 3961 3962 3963 3964 3965 3966 3967 3968 3969 3970 3971 3972 3973 | testcase( nOrderBy==BMS-1 ); if( nOrderBy>BMS-1 ) return 0; /* Cannot optimize overly large ORDER BYs */ isOrderDistinct = 1; obDone = MASKBIT(nOrderBy)-1; orderDistinctMask = 0; ready = 0; eqOpMask = WO_EQ | WO_IS | WO_ISNULL; if( wctrlFlags & (WHERE_ORDERBY_LIMIT|WHERE_ORDERBY_MAX|WHERE_ORDERBY_MIN) ){ eqOpMask |= WO_IN; } for(iLoop=0; isOrderDistinct && obSat<obDone && iLoop<=nLoop; iLoop++){ if( iLoop>0 ) ready |= pLoop->maskSelf; if( iLoop<nLoop ){ pLoop = pPath->aLoop[iLoop]; if( wctrlFlags & WHERE_ORDERBY_LIMIT ) continue; }else{ pLoop = pLast; } if( pLoop->wsFlags & WHERE_VIRTUALTABLE ){ if( pLoop->u.vtab.isOrdered && (wctrlFlags & WHERE_DISTINCTBY)==0 ){ obSat = obDone; } break; }else if( wctrlFlags & WHERE_DISTINCTBY ){ pLoop->u.btree.nDistinctCol = 0; } iCur = pWInfo->pTabList->a[pLoop->iTab].iCursor; /* Mark off any ORDER BY term X that is a column in the table of ** the current loop for which there is term in the WHERE ** clause of the form X IS NULL or X=? that reference only outer ** loops. */ for(i=0; i<nOrderBy; i++){ if( MASKBIT(i) & obSat ) continue; pOBExpr = sqlite3ExprSkipCollateAndLikely(pOrderBy->a[i].pExpr); if( NEVER(pOBExpr==0) ) continue; if( pOBExpr->op!=TK_COLUMN && pOBExpr->op!=TK_AGG_COLUMN ) continue; if( pOBExpr->iTable!=iCur ) continue; pTerm = sqlite3WhereFindTerm(&pWInfo->sWC, iCur, pOBExpr->iColumn, ~ready, eqOpMask, 0); if( pTerm==0 ) continue; if( pTerm->eOperator==WO_IN ){ /* IN terms are only valid for sorting in the ORDER BY LIMIT ** optimization, and then only if they are actually used ** by the query plan */ assert( wctrlFlags & (WHERE_ORDERBY_LIMIT|WHERE_ORDERBY_MIN|WHERE_ORDERBY_MAX) ); for(j=0; j<pLoop->nLTerm && pTerm!=pLoop->aLTerm[j]; j++){} if( j>=pLoop->nLTerm ) continue; } if( (pTerm->eOperator&(WO_EQ|WO_IS))!=0 && pOBExpr->iColumn>=0 ){ Parse *pParse = pWInfo->pParse; CollSeq *pColl1 = sqlite3ExprNNCollSeq(pParse, pOrderBy->a[i].pExpr); CollSeq *pColl2 = sqlite3ExprCompareCollSeq(pParse, pTerm->pExpr); assert( pColl1 ); if( pColl2==0 || sqlite3StrICmp(pColl1->zName, pColl2->zName) ){ continue; } testcase( pTerm->pExpr->op==TK_IS ); } obSat |= MASKBIT(i); } if( (pLoop->wsFlags & WHERE_ONEROW)==0 ){ if( pLoop->wsFlags & WHERE_IPK ){ pIndex = 0; nKeyCol = 0; nColumn = 1; }else if( (pIndex = pLoop->u.btree.pIndex)==0 || pIndex->bUnordered ){ return 0; }else{ nKeyCol = pIndex->nKeyCol; nColumn = pIndex->nColumn; assert( nColumn==nKeyCol+1 || !HasRowid(pIndex->pTable) ); assert( pIndex->aiColumn[nColumn-1]==XN_ROWID || !HasRowid(pIndex->pTable)); /* All relevant terms of the index must also be non-NULL in order ** for isOrderDistinct to be true. So the isOrderDistint value ** computed here might be a false positive. Corrections will be ** made at tag-20210426-1 below */ isOrderDistinct = IsUniqueIndex(pIndex) && (pLoop->wsFlags & WHERE_SKIPSCAN)==0; } /* Loop through all columns of the index and deal with the ones ** that are not constrained by == or IN. */ rev = revSet = 0; distinctColumns = 0; for(j=0; j<nColumn; j++){ u8 bOnce = 1; /* True to run the ORDER BY search loop */ assert( j>=pLoop->u.btree.nEq || (pLoop->aLTerm[j]==0)==(j<pLoop->nSkip) ); if( j<pLoop->u.btree.nEq && j>=pLoop->nSkip ){ u16 eOp = pLoop->aLTerm[j]->eOperator; /* Skip over == and IS and ISNULL terms. (Also skip IN terms when ** doing WHERE_ORDERBY_LIMIT processing). Except, IS and ISNULL ** terms imply that the index is not UNIQUE NOT NULL in which case ** the loop need to be marked as not order-distinct because it can ** have repeated NULL rows. ** ** If the current term is a column of an ((?,?) IN (SELECT...)) ** expression for which the SELECT returns more than one column, ** check that it is the only column used by this loop. Otherwise, ** if it is one of two or more, none of the columns can be ** considered to match an ORDER BY term. */ if( (eOp & eqOpMask)!=0 ){ if( eOp & (WO_ISNULL|WO_IS) ){ testcase( eOp & WO_ISNULL ); testcase( eOp & WO_IS ); testcase( isOrderDistinct ); isOrderDistinct = 0; } continue; }else if( ALWAYS(eOp & WO_IN) ){ /* ALWAYS() justification: eOp is an equality operator due to the ** j<pLoop->u.btree.nEq constraint above. Any equality other |
︙ | ︙ | |||
3777 3778 3779 3780 3781 3782 3783 | } /* Get the column number in the table (iColumn) and sort order ** (revIdx) for the j-th column of the index. */ if( pIndex ){ iColumn = pIndex->aiColumn[j]; | | | | | | | | | | > > > > | > | > | > > | > | > > > > > > > | 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994 3995 3996 3997 3998 3999 4000 4001 4002 4003 4004 4005 4006 4007 4008 4009 4010 4011 4012 4013 4014 4015 4016 4017 4018 4019 4020 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 4034 4035 4036 4037 4038 4039 4040 4041 4042 4043 4044 4045 4046 4047 4048 4049 4050 4051 4052 4053 4054 4055 4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 | } /* Get the column number in the table (iColumn) and sort order ** (revIdx) for the j-th column of the index. */ if( pIndex ){ iColumn = pIndex->aiColumn[j]; revIdx = pIndex->aSortOrder[j] & KEYINFO_ORDER_DESC; if( iColumn==pIndex->pTable->iPKey ) iColumn = XN_ROWID; }else{ iColumn = XN_ROWID; revIdx = 0; } /* An unconstrained column that might be NULL means that this ** WhereLoop is not well-ordered. tag-20210426-1 */ if( isOrderDistinct ){ if( iColumn>=0 && j>=pLoop->u.btree.nEq && pIndex->pTable->aCol[iColumn].notNull==0 ){ isOrderDistinct = 0; } if( iColumn==XN_EXPR ){ isOrderDistinct = 0; } } /* Find the ORDER BY term that corresponds to the j-th column ** of the index and mark that ORDER BY term off */ isMatch = 0; for(i=0; bOnce && i<nOrderBy; i++){ if( MASKBIT(i) & obSat ) continue; pOBExpr = sqlite3ExprSkipCollateAndLikely(pOrderBy->a[i].pExpr); testcase( wctrlFlags & WHERE_GROUPBY ); testcase( wctrlFlags & WHERE_DISTINCTBY ); if( NEVER(pOBExpr==0) ) continue; if( (wctrlFlags & (WHERE_GROUPBY|WHERE_DISTINCTBY))==0 ) bOnce = 0; if( iColumn>=XN_ROWID ){ if( pOBExpr->op!=TK_COLUMN && pOBExpr->op!=TK_AGG_COLUMN ) continue; if( pOBExpr->iTable!=iCur ) continue; if( pOBExpr->iColumn!=iColumn ) continue; }else{ Expr *pIdxExpr = pIndex->aColExpr->a[j].pExpr; if( sqlite3ExprCompareSkip(pOBExpr, pIdxExpr, iCur) ){ continue; } } if( iColumn!=XN_ROWID ){ pColl = sqlite3ExprNNCollSeq(pWInfo->pParse, pOrderBy->a[i].pExpr); if( sqlite3StrICmp(pColl->zName, pIndex->azColl[j])!=0 ) continue; } if( wctrlFlags & WHERE_DISTINCTBY ){ pLoop->u.btree.nDistinctCol = j+1; } isMatch = 1; break; } if( isMatch && (wctrlFlags & WHERE_GROUPBY)==0 ){ /* Make sure the sort order is compatible in an ORDER BY clause. ** Sort order is irrelevant for a GROUP BY clause. */ if( revSet ){ if( (rev ^ revIdx)!=(pOrderBy->a[i].sortFlags&KEYINFO_ORDER_DESC) ){ isMatch = 0; } }else{ rev = revIdx ^ (pOrderBy->a[i].sortFlags & KEYINFO_ORDER_DESC); if( rev ) *pRevMask |= MASKBIT(iLoop); revSet = 1; } } if( isMatch && (pOrderBy->a[i].sortFlags & KEYINFO_ORDER_BIGNULL) ){ if( j==pLoop->u.btree.nEq ){ pLoop->wsFlags |= WHERE_BIGNULL_SORT; }else{ isMatch = 0; } } if( isMatch ){ if( iColumn==XN_ROWID ){ testcase( distinctColumns==0 ); distinctColumns = 1; } obSat |= MASKBIT(i); |
︙ | ︙ | |||
3874 3875 3876 3877 3878 3879 3880 | } } } } /* End the loop over all WhereLoops from outer-most down to inner-most */ if( obSat==obDone ) return (i8)nOrderBy; if( !isOrderDistinct ){ for(i=nOrderBy-1; i>0; i--){ | | | 4098 4099 4100 4101 4102 4103 4104 4105 4106 4107 4108 4109 4110 4111 4112 | } } } } /* End the loop over all WhereLoops from outer-most down to inner-most */ if( obSat==obDone ) return (i8)nOrderBy; if( !isOrderDistinct ){ for(i=nOrderBy-1; i>0; i--){ Bitmask m = ALWAYS(i<BMS) ? MASKBIT(i) - 1 : 0; if( (obSat&m)==m ) return i; } return 0; } return -1; } |
︙ | ︙ | |||
3947 3948 3949 3950 3951 3952 3953 | ** Or, if the order-by clause has X terms but only the last Y ** terms are out of order, then block-sorting will reduce the ** sorting cost to: ** ** cost = (3.0 * N * log(N)) * (Y/X) ** ** The (Y/X) term is implemented using stack variable rScale | | > | > > > > > > > | 4171 4172 4173 4174 4175 4176 4177 4178 4179 4180 4181 4182 4183 4184 4185 4186 4187 4188 4189 4190 4191 4192 4193 4194 4195 4196 4197 4198 4199 4200 4201 4202 | ** Or, if the order-by clause has X terms but only the last Y ** terms are out of order, then block-sorting will reduce the ** sorting cost to: ** ** cost = (3.0 * N * log(N)) * (Y/X) ** ** The (Y/X) term is implemented using stack variable rScale ** below. */ LogEst rScale, rSortCost; assert( nOrderBy>0 && 66==sqlite3LogEst(100) ); rScale = sqlite3LogEst((nOrderBy-nSorted)*100/nOrderBy) - 66; rSortCost = nRow + rScale + 16; /* Multiple by log(M) where M is the number of output rows. ** Use the LIMIT for M if it is smaller. Or if this sort is for ** a DISTINCT operator, M will be the number of distinct output ** rows, so fudge it downwards a bit. */ if( (pWInfo->wctrlFlags & WHERE_USE_LIMIT)!=0 && pWInfo->iLimit<nRow ){ nRow = pWInfo->iLimit; }else if( (pWInfo->wctrlFlags & WHERE_WANT_DISTINCT) ){ /* TUNING: In the sort for a DISTINCT operator, assume that the DISTINCT ** reduces the number of output rows by a factor of 2 */ if( nRow>10 ){ nRow -= 10; assert( 10==sqlite3LogEst(2) ); } } rSortCost += estLog(nRow); return rSortCost; } /* ** Given the list of WhereLoop objects at pWInfo->pLoops, this routine |
︙ | ︙ | |||
4325 4326 4327 4328 4329 4330 4331 4332 4333 4334 4335 4336 4337 4338 | testcase( wsFlags & WHERE_COLUMN_IN ); if( rc==pWInfo->pOrderBy->nExpr ){ pWInfo->bOrderedInnerLoop = 1; pWInfo->revMask = m; } } } } } if( (pWInfo->wctrlFlags & WHERE_SORTBYGROUP) && pWInfo->nOBSat==pWInfo->pOrderBy->nExpr && nLoop>0 ){ Bitmask revMask = 0; int nOrder = wherePathSatisfiesOrderBy(pWInfo, pWInfo->pOrderBy, | > > > > > | 4557 4558 4559 4560 4561 4562 4563 4564 4565 4566 4567 4568 4569 4570 4571 4572 4573 4574 4575 | testcase( wsFlags & WHERE_COLUMN_IN ); if( rc==pWInfo->pOrderBy->nExpr ){ pWInfo->bOrderedInnerLoop = 1; pWInfo->revMask = m; } } } }else if( nLoop && pWInfo->nOBSat==1 && (pWInfo->wctrlFlags & (WHERE_ORDERBY_MIN|WHERE_ORDERBY_MAX))!=0 ){ pWInfo->bOrderedInnerLoop = 1; } } if( (pWInfo->wctrlFlags & WHERE_SORTBYGROUP) && pWInfo->nOBSat==pWInfo->pOrderBy->nExpr && nLoop>0 ){ Bitmask revMask = 0; int nOrder = wherePathSatisfiesOrderBy(pWInfo, pWInfo->pOrderBy, |
︙ | ︙ | |||
4363 4364 4365 4366 4367 4368 4369 | ** ** Return non-zero on success, if this query can be handled by this ** no-frills query planner. Return zero if this query needs the ** general-purpose query planner. */ static int whereShortCut(WhereLoopBuilder *pBuilder){ WhereInfo *pWInfo; | | > | > | > | 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 | ** ** Return non-zero on success, if this query can be handled by this ** no-frills query planner. Return zero if this query needs the ** general-purpose query planner. */ static int whereShortCut(WhereLoopBuilder *pBuilder){ WhereInfo *pWInfo; SrcItem *pItem; WhereClause *pWC; WhereTerm *pTerm; WhereLoop *pLoop; int iCur; int j; Table *pTab; Index *pIdx; WhereScan scan; pWInfo = pBuilder->pWInfo; if( pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE ) return 0; assert( pWInfo->pTabList->nSrc>=1 ); pItem = pWInfo->pTabList->a; pTab = pItem->pTab; if( IsVirtual(pTab) ) return 0; if( pItem->fg.isIndexedBy ) return 0; iCur = pItem->iCursor; pWC = &pWInfo->sWC; pLoop = pBuilder->pNew; pLoop->wsFlags = 0; pLoop->nSkip = 0; pTerm = whereScanInit(&scan, pWC, iCur, -1, WO_EQ|WO_IS, 0); while( pTerm && pTerm->prereqRight ) pTerm = whereScanNext(&scan); if( pTerm ){ testcase( pTerm->eOperator & WO_IS ); pLoop->wsFlags = WHERE_COLUMN_EQ|WHERE_IPK|WHERE_ONEROW; pLoop->aLTerm[0] = pTerm; pLoop->nLTerm = 1; pLoop->u.btree.nEq = 1; /* TUNING: Cost of a rowid lookup is 10 */ pLoop->rRun = 33; /* 33==sqlite3LogEst(10) */ }else{ for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ int opMask; assert( pLoop->aLTermSpace==pLoop->aLTerm ); if( !IsUniqueIndex(pIdx) || pIdx->pPartIdxWhere!=0 || pIdx->nKeyCol>ArraySize(pLoop->aLTermSpace) ) continue; opMask = pIdx->uniqNotNull ? (WO_EQ|WO_IS) : WO_EQ; for(j=0; j<pIdx->nKeyCol; j++){ pTerm = whereScanInit(&scan, pWC, iCur, j, opMask, pIdx); while( pTerm && pTerm->prereqRight ) pTerm = whereScanNext(&scan); if( pTerm==0 ) break; testcase( pTerm->eOperator & WO_IS ); pLoop->aLTerm[j] = pTerm; } if( j!=pIdx->nKeyCol ) continue; pLoop->wsFlags = WHERE_COLUMN_EQ|WHERE_ONEROW|WHERE_INDEXED; if( pIdx->isCovering || (pItem->colUsed & pIdx->colNotIdxed)==0 ){ |
︙ | ︙ | |||
4432 4433 4434 4435 4436 4437 4438 4439 4440 4441 4442 4443 4444 4445 4446 4447 | pLoop->maskSelf = 1; /* sqlite3WhereGetMask(&pWInfo->sMaskSet, iCur); */ pWInfo->a[0].iTabCur = iCur; pWInfo->nRowOut = 1; if( pWInfo->pOrderBy ) pWInfo->nOBSat = pWInfo->pOrderBy->nExpr; if( pWInfo->wctrlFlags & WHERE_WANT_DISTINCT ){ pWInfo->eDistinct = WHERE_DISTINCT_UNIQUE; } #ifdef SQLITE_DEBUG pLoop->cId = '0'; #endif return 1; } return 0; } /* | > > > > > > | 4672 4673 4674 4675 4676 4677 4678 4679 4680 4681 4682 4683 4684 4685 4686 4687 4688 4689 4690 4691 4692 4693 | pLoop->maskSelf = 1; /* sqlite3WhereGetMask(&pWInfo->sMaskSet, iCur); */ pWInfo->a[0].iTabCur = iCur; pWInfo->nRowOut = 1; if( pWInfo->pOrderBy ) pWInfo->nOBSat = pWInfo->pOrderBy->nExpr; if( pWInfo->wctrlFlags & WHERE_WANT_DISTINCT ){ pWInfo->eDistinct = WHERE_DISTINCT_UNIQUE; } if( scan.iEquiv>1 ) pLoop->wsFlags |= WHERE_TRANSCONS; #ifdef SQLITE_DEBUG pLoop->cId = '0'; #endif #ifdef WHERETRACE_ENABLED if( sqlite3WhereTrace ){ sqlite3DebugPrintf("whereShortCut() used to compute solution\n"); } #endif return 1; } return 0; } /* |
︙ | ︙ | |||
4466 4467 4468 4469 4470 4471 4472 4473 4474 4475 4476 4477 4478 4479 | w.eCode = 1; w.xExprCallback = exprNodeIsDeterministic; w.xSelectCallback = sqlite3SelectWalkFail; sqlite3WalkExpr(&w, p); return w.eCode; } /* ** Generate the beginning of the loop used for WHERE clause processing. ** The return value is a pointer to an opaque structure that contains ** information needed to terminate the loop. Later, the calling routine ** should invoke sqlite3WhereEnd() with the return value of this function ** in order to complete the WHERE clause processing. ** | > > > > > > > > > > > > > > > > > > > > > > | 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 | w.eCode = 1; w.xExprCallback = exprNodeIsDeterministic; w.xSelectCallback = sqlite3SelectWalkFail; sqlite3WalkExpr(&w, p); return w.eCode; } #ifdef WHERETRACE_ENABLED /* ** Display all WhereLoops in pWInfo */ static void showAllWhereLoops(WhereInfo *pWInfo, WhereClause *pWC){ if( sqlite3WhereTrace ){ /* Display all of the WhereLoop objects */ WhereLoop *p; int i; static const char zLabel[] = "0123456789abcdefghijklmnopqrstuvwyxz" "ABCDEFGHIJKLMNOPQRSTUVWYXZ"; for(p=pWInfo->pLoops, i=0; p; p=p->pNextLoop, i++){ p->cId = zLabel[i%(sizeof(zLabel)-1)]; sqlite3WhereLoopPrint(p, pWC); } } } # define WHERETRACE_ALL_LOOPS(W,C) showAllWhereLoops(W,C) #else # define WHERETRACE_ALL_LOOPS(W,C) #endif /* ** Generate the beginning of the loop used for WHERE clause processing. ** The return value is a pointer to an opaque structure that contains ** information needed to terminate the loop. Later, the calling routine ** should invoke sqlite3WhereEnd() with the return value of this function ** in order to complete the WHERE clause processing. ** |
︙ | ︙ | |||
4639 4640 4641 4642 4643 4644 4645 | pWInfo->pParse = pParse; pWInfo->pTabList = pTabList; pWInfo->pOrderBy = pOrderBy; pWInfo->pWhere = pWhere; pWInfo->pResultSet = pResultSet; pWInfo->aiCurOnePass[0] = pWInfo->aiCurOnePass[1] = -1; pWInfo->nLevel = nTabList; | | | 4907 4908 4909 4910 4911 4912 4913 4914 4915 4916 4917 4918 4919 4920 4921 | pWInfo->pParse = pParse; pWInfo->pTabList = pTabList; pWInfo->pOrderBy = pOrderBy; pWInfo->pWhere = pWhere; pWInfo->pResultSet = pResultSet; pWInfo->aiCurOnePass[0] = pWInfo->aiCurOnePass[1] = -1; pWInfo->nLevel = nTabList; pWInfo->iBreak = pWInfo->iContinue = sqlite3VdbeMakeLabel(pParse); pWInfo->wctrlFlags = wctrlFlags; pWInfo->iLimit = iAuxArg; pWInfo->savedNQueryLoop = pParse->nQueryLoop; memset(&pWInfo->nOBSat, 0, offsetof(WhereInfo,sWC) - offsetof(WhereInfo,nOBSat)); memset(&pWInfo->a[0], 0, sizeof(WhereLoop)+nTabList*sizeof(WhereLevel)); assert( pWInfo->eOnePass==ONEPASS_OFF ); /* ONEPASS defaults to OFF */ |
︙ | ︙ | |||
4747 4748 4749 4750 4751 4752 4753 | #if defined(WHERETRACE_ENABLED) if( sqlite3WhereTrace & 0xffff ){ sqlite3DebugPrintf("*** Optimizer Start *** (wctrlFlags: 0x%x",wctrlFlags); if( wctrlFlags & WHERE_USE_LIMIT ){ sqlite3DebugPrintf(", limit: %d", iAuxArg); } sqlite3DebugPrintf(")\n"); | > > > > > > > > > | > > | > > > > > > > > | < > > > | < < < | < | > > > | | 5015 5016 5017 5018 5019 5020 5021 5022 5023 5024 5025 5026 5027 5028 5029 5030 5031 5032 5033 5034 5035 5036 5037 5038 5039 5040 5041 5042 5043 5044 5045 5046 5047 5048 5049 5050 5051 5052 5053 5054 5055 5056 5057 5058 5059 5060 5061 5062 5063 5064 5065 5066 5067 5068 5069 5070 5071 5072 5073 5074 5075 5076 5077 5078 5079 5080 5081 5082 | #if defined(WHERETRACE_ENABLED) if( sqlite3WhereTrace & 0xffff ){ sqlite3DebugPrintf("*** Optimizer Start *** (wctrlFlags: 0x%x",wctrlFlags); if( wctrlFlags & WHERE_USE_LIMIT ){ sqlite3DebugPrintf(", limit: %d", iAuxArg); } sqlite3DebugPrintf(")\n"); if( sqlite3WhereTrace & 0x100 ){ Select sSelect; memset(&sSelect, 0, sizeof(sSelect)); sSelect.selFlags = SF_WhereBegin; sSelect.pSrc = pTabList; sSelect.pWhere = pWhere; sSelect.pOrderBy = pOrderBy; sSelect.pEList = pResultSet; sqlite3TreeViewSelect(0, &sSelect, 0); } } if( sqlite3WhereTrace & 0x100 ){ /* Display all terms of the WHERE clause */ sqlite3DebugPrintf("---- WHERE clause at start of analysis:\n"); sqlite3WhereClausePrint(sWLB.pWC); } #endif if( nTabList!=1 || whereShortCut(&sWLB)==0 ){ rc = whereLoopAddAll(&sWLB); if( rc ) goto whereBeginError; #ifdef SQLITE_ENABLE_STAT4 /* If one or more WhereTerm.truthProb values were used in estimating ** loop parameters, but then those truthProb values were subsequently ** changed based on STAT4 information while computing subsequent loops, ** then we need to rerun the whole loop building process so that all ** loops will be built using the revised truthProb values. */ if( sWLB.bldFlags2 & SQLITE_BLDF2_2NDPASS ){ WHERETRACE_ALL_LOOPS(pWInfo, sWLB.pWC); WHERETRACE(0xffff, ("**** Redo all loop computations due to" " TERM_HIGHTRUTH changes ****\n")); while( pWInfo->pLoops ){ WhereLoop *p = pWInfo->pLoops; pWInfo->pLoops = p->pNextLoop; whereLoopDelete(db, p); } rc = whereLoopAddAll(&sWLB); if( rc ) goto whereBeginError; } #endif WHERETRACE_ALL_LOOPS(pWInfo, sWLB.pWC); wherePathSolver(pWInfo, 0); if( db->mallocFailed ) goto whereBeginError; if( pWInfo->pOrderBy ){ wherePathSolver(pWInfo, pWInfo->nRowOut+1); if( db->mallocFailed ) goto whereBeginError; } } if( pWInfo->pOrderBy==0 && (db->flags & SQLITE_ReverseOrder)!=0 ){ pWInfo->revMask = ALLBITS; } if( pParse->nErr || db->mallocFailed ){ goto whereBeginError; } #ifdef WHERETRACE_ENABLED if( sqlite3WhereTrace ){ sqlite3DebugPrintf("---- Solution nRow=%d", pWInfo->nRowOut); if( pWInfo->nOBSat>0 ){ sqlite3DebugPrintf(" ORDERBY=%d,0x%llx", pWInfo->nOBSat, pWInfo->revMask); |
︙ | ︙ | |||
4805 4806 4807 4808 4809 4810 4811 | case WHERE_DISTINCT_UNORDERED: { sqlite3DebugPrintf(" DISTINCT=unordered"); break; } } sqlite3DebugPrintf("\n"); for(ii=0; ii<pWInfo->nLevel; ii++){ | | | 5093 5094 5095 5096 5097 5098 5099 5100 5101 5102 5103 5104 5105 5106 5107 | case WHERE_DISTINCT_UNORDERED: { sqlite3DebugPrintf(" DISTINCT=unordered"); break; } } sqlite3DebugPrintf("\n"); for(ii=0; ii<pWInfo->nLevel; ii++){ sqlite3WhereLoopPrint(pWInfo->a[ii].pWLoop, sWLB.pWC); } } #endif /* Attempt to omit tables from the join that do not affect the result. ** For a table to not affect the result, the following must be true: ** |
︙ | ︙ | |||
4830 4831 4832 4833 4834 4835 4836 | ** CREATE TABLE t1(ipk INTEGER PRIMARY KEY, v1); ** CREATE TABLE t2(ipk INTEGER PRIMARY KEY, v2); ** CREATE TABLE t3(ipk INTEGER PRIMARY KEY, v3); ** ** then table t2 can be omitted from the following: ** ** SELECT v1, v3 FROM t1 | | | | | > | | 5118 5119 5120 5121 5122 5123 5124 5125 5126 5127 5128 5129 5130 5131 5132 5133 5134 5135 5136 5137 5138 5139 5140 5141 5142 5143 5144 5145 5146 5147 5148 5149 5150 5151 5152 5153 5154 | ** CREATE TABLE t1(ipk INTEGER PRIMARY KEY, v1); ** CREATE TABLE t2(ipk INTEGER PRIMARY KEY, v2); ** CREATE TABLE t3(ipk INTEGER PRIMARY KEY, v3); ** ** then table t2 can be omitted from the following: ** ** SELECT v1, v3 FROM t1 ** LEFT JOIN t2 ON (t1.ipk=t2.ipk) ** LEFT JOIN t3 ON (t1.ipk=t3.ipk) ** ** or from: ** ** SELECT DISTINCT v1, v3 FROM t1 ** LEFT JOIN t2 ** LEFT JOIN t3 ON (t1.ipk=t3.ipk) */ notReady = ~(Bitmask)0; if( pWInfo->nLevel>=2 && pResultSet!=0 /* these two combine to guarantee */ && 0==(wctrlFlags & WHERE_AGG_DISTINCT) /* condition (1) above */ && OptimizationEnabled(db, SQLITE_OmitNoopJoin) ){ int i; Bitmask tabUsed = sqlite3WhereExprListUsage(pMaskSet, pResultSet); if( sWLB.pOrderBy ){ tabUsed |= sqlite3WhereExprListUsage(pMaskSet, sWLB.pOrderBy); } for(i=pWInfo->nLevel-1; i>=1; i--){ WhereTerm *pTerm, *pEnd; SrcItem *pItem; pLoop = pWInfo->a[i].pWLoop; pItem = &pWInfo->pTabList->a[pLoop->iTab]; if( (pItem->fg.jointype & JT_LEFT)==0 ) continue; if( (wctrlFlags & WHERE_WANT_DISTINCT)==0 && (pLoop->wsFlags & WHERE_ONEROW)==0 ){ continue; |
︙ | ︙ | |||
4887 4888 4889 4890 4891 4892 4893 4894 4895 4896 4897 4898 4899 4900 4901 | int nByte = (pWInfo->nLevel-1-i) * sizeof(WhereLevel); memmove(&pWInfo->a[i], &pWInfo->a[i+1], nByte); } pWInfo->nLevel--; nTabList--; } } WHERETRACE(0xffff,("*** Optimizer Finished ***\n")); pWInfo->pParse->nQueryLoop += pWInfo->nRowOut; /* If the caller is an UPDATE or DELETE statement that is requesting ** to use a one-pass algorithm, determine if this is appropriate. ** ** A one-pass approach can be used if the caller has requested one ** and either (a) the scan visits at most one row or (b) each | > > > > > > | 5176 5177 5178 5179 5180 5181 5182 5183 5184 5185 5186 5187 5188 5189 5190 5191 5192 5193 5194 5195 5196 | int nByte = (pWInfo->nLevel-1-i) * sizeof(WhereLevel); memmove(&pWInfo->a[i], &pWInfo->a[i+1], nByte); } pWInfo->nLevel--; nTabList--; } } #if defined(WHERETRACE_ENABLED) if( sqlite3WhereTrace & 0x100 ){ /* Display all terms of the WHERE clause */ sqlite3DebugPrintf("---- WHERE clause at end of analysis:\n"); sqlite3WhereClausePrint(sWLB.pWC); } WHERETRACE(0xffff,("*** Optimizer Finished ***\n")); #endif pWInfo->pParse->nQueryLoop += pWInfo->nRowOut; /* If the caller is an UPDATE or DELETE statement that is requesting ** to use a one-pass algorithm, determine if this is appropriate. ** ** A one-pass approach can be used if the caller has requested one ** and either (a) the scan visits at most one row or (b) each |
︙ | ︙ | |||
4913 4914 4915 4916 4917 4918 4919 4920 4921 | ** use a one-pass approach, and this is not set accurately for scans ** that use the OR optimization. */ assert( (wctrlFlags & WHERE_ONEPASS_DESIRED)==0 || pWInfo->nLevel==1 ); if( (wctrlFlags & WHERE_ONEPASS_DESIRED)!=0 ){ int wsFlags = pWInfo->a[0].pWLoop->wsFlags; int bOnerow = (wsFlags & WHERE_ONEROW)!=0; if( bOnerow || ( 0!=(wctrlFlags & WHERE_ONEPASS_MULTIROW) | > < > | | | 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 | ** use a one-pass approach, and this is not set accurately for scans ** that use the OR optimization. */ assert( (wctrlFlags & WHERE_ONEPASS_DESIRED)==0 || pWInfo->nLevel==1 ); if( (wctrlFlags & WHERE_ONEPASS_DESIRED)!=0 ){ int wsFlags = pWInfo->a[0].pWLoop->wsFlags; int bOnerow = (wsFlags & WHERE_ONEROW)!=0; assert( !(wsFlags & WHERE_VIRTUALTABLE) || IsVirtual(pTabList->a[0].pTab) ); if( bOnerow || ( 0!=(wctrlFlags & WHERE_ONEPASS_MULTIROW) && !IsVirtual(pTabList->a[0].pTab) && (0==(wsFlags & WHERE_MULTI_OR) || (wctrlFlags & WHERE_DUPLICATES_OK)) )){ pWInfo->eOnePass = bOnerow ? ONEPASS_SINGLE : ONEPASS_MULTI; if( HasRowid(pTabList->a[0].pTab) && (wsFlags & WHERE_IDX_ONLY) ){ if( wctrlFlags & WHERE_ONEPASS_MULTIROW ){ bFordelete = OPFLAG_FORDELETE; } pWInfo->a[0].pWLoop->wsFlags = (wsFlags & ~WHERE_IDX_ONLY); } } } /* Open all tables in the pTabList and any indices selected for ** searching those tables. */ for(ii=0, pLevel=pWInfo->a; ii<nTabList; ii++, pLevel++){ Table *pTab; /* Table to open */ int iDb; /* Index of database containing table/index */ SrcItem *pTabItem; pTabItem = &pTabList->a[pLevel->iFrom]; pTab = pTabItem->pTab; iDb = sqlite3SchemaToIndex(db, pTab->pSchema); pLoop = pLevel->pWLoop; if( (pTab->tabFlags & TF_Ephemeral)!=0 || IsView(pTab) ){ /* Do nothing */ }else #ifndef SQLITE_OMIT_VIRTUALTABLE if( (pLoop->wsFlags & WHERE_VIRTUALTABLE)!=0 ){ const char *pVTab = (const char *)sqlite3GetVTable(db, pTab); int iCur = pTabItem->iCursor; sqlite3VdbeAddOp4(v, OP_VOpen, iCur, 0, 0, pVTab, P4_VTAB); |
︙ | ︙ | |||
4963 4964 4965 4966 4967 4968 4969 | op = OP_OpenWrite; pWInfo->aiCurOnePass[0] = pTabItem->iCursor; }; sqlite3OpenTable(pParse, pTabItem->iCursor, iDb, pTab, op); assert( pTabItem->iCursor==pLevel->iTabCur ); testcase( pWInfo->eOnePass==ONEPASS_OFF && pTab->nCol==BMS-1 ); testcase( pWInfo->eOnePass==ONEPASS_OFF && pTab->nCol==BMS ); | | > > > > > > | 5259 5260 5261 5262 5263 5264 5265 5266 5267 5268 5269 5270 5271 5272 5273 5274 5275 5276 5277 5278 5279 | op = OP_OpenWrite; pWInfo->aiCurOnePass[0] = pTabItem->iCursor; }; sqlite3OpenTable(pParse, pTabItem->iCursor, iDb, pTab, op); assert( pTabItem->iCursor==pLevel->iTabCur ); testcase( pWInfo->eOnePass==ONEPASS_OFF && pTab->nCol==BMS-1 ); testcase( pWInfo->eOnePass==ONEPASS_OFF && pTab->nCol==BMS ); if( pWInfo->eOnePass==ONEPASS_OFF && pTab->nCol<BMS && (pTab->tabFlags & (TF_HasGenerated|TF_WithoutRowid))==0 ){ /* If we know that only a prefix of the record will be used, ** it is advantageous to reduce the "column count" field in ** the P4 operand of the OP_OpenRead/Write opcode. */ Bitmask b = pTabItem->colUsed; int n = 0; for(; b; b=b>>1, n++){} sqlite3VdbeChangeP4(v, -1, SQLITE_INT_TO_PTR(n), P4_INT32); assert( n<=pTab->nCol ); } #ifdef SQLITE_ENABLE_CURSOR_HINTS |
︙ | ︙ | |||
5022 5023 5024 5025 5026 5027 5028 5029 5030 5031 | assert( pIx->pSchema==pTab->pSchema ); assert( iIndexCur>=0 ); if( op ){ sqlite3VdbeAddOp3(v, op, iIndexCur, pIx->tnum, iDb); sqlite3VdbeSetP4KeyInfo(pParse, pIx); if( (pLoop->wsFlags & WHERE_CONSTRAINT)!=0 && (pLoop->wsFlags & (WHERE_COLUMN_RANGE|WHERE_SKIPSCAN))==0 && (pWInfo->wctrlFlags&WHERE_ORDERBY_MIN)==0 && pWInfo->eDistinct!=WHERE_DISTINCT_ORDERED ){ | > > | | 5324 5325 5326 5327 5328 5329 5330 5331 5332 5333 5334 5335 5336 5337 5338 5339 5340 5341 5342 5343 | assert( pIx->pSchema==pTab->pSchema ); assert( iIndexCur>=0 ); if( op ){ sqlite3VdbeAddOp3(v, op, iIndexCur, pIx->tnum, iDb); sqlite3VdbeSetP4KeyInfo(pParse, pIx); if( (pLoop->wsFlags & WHERE_CONSTRAINT)!=0 && (pLoop->wsFlags & (WHERE_COLUMN_RANGE|WHERE_SKIPSCAN))==0 && (pLoop->wsFlags & WHERE_BIGNULL_SORT)==0 && (pLoop->wsFlags & WHERE_IN_SEEKSCAN)==0 && (pWInfo->wctrlFlags&WHERE_ORDERBY_MIN)==0 && pWInfo->eDistinct!=WHERE_DISTINCT_ORDERED ){ sqlite3VdbeChangeP5(v, OPFLAG_SEEKEQ); } VdbeComment((v, "%s", pIx->zName)); #ifdef SQLITE_ENABLE_COLUMN_USED_MASK { u64 colUsed = 0; int ii, jj; for(ii=0; ii<pIx->nColumn; ii++){ |
︙ | ︙ | |||
5057 5058 5059 5060 5061 5062 5063 5064 5065 5066 5067 5068 5069 5070 5071 5072 5073 5074 5075 5076 | /* Generate the code to do the search. Each iteration of the for ** loop below generates code for a single nested loop of the VM ** program. */ for(ii=0; ii<nTabList; ii++){ int addrExplain; int wsFlags; pLevel = &pWInfo->a[ii]; wsFlags = pLevel->pWLoop->wsFlags; #ifndef SQLITE_OMIT_AUTOMATIC_INDEX if( (pLevel->pWLoop->wsFlags & WHERE_AUTO_INDEX)!=0 ){ constructAutomaticIndex(pParse, &pWInfo->sWC, &pTabList->a[pLevel->iFrom], notReady, pLevel); if( db->mallocFailed ) goto whereBeginError; } #endif addrExplain = sqlite3WhereExplainOneScan( pParse, pTabList, pLevel, wctrlFlags ); pLevel->addrBody = sqlite3VdbeCurrentAddr(v); | > | > > > | 5361 5362 5363 5364 5365 5366 5367 5368 5369 5370 5371 5372 5373 5374 5375 5376 5377 5378 5379 5380 5381 5382 5383 5384 5385 5386 5387 5388 5389 5390 5391 5392 5393 5394 5395 5396 5397 5398 5399 5400 5401 5402 5403 5404 5405 | /* Generate the code to do the search. Each iteration of the for ** loop below generates code for a single nested loop of the VM ** program. */ for(ii=0; ii<nTabList; ii++){ int addrExplain; int wsFlags; if( pParse->nErr ) goto whereBeginError; pLevel = &pWInfo->a[ii]; wsFlags = pLevel->pWLoop->wsFlags; #ifndef SQLITE_OMIT_AUTOMATIC_INDEX if( (pLevel->pWLoop->wsFlags & WHERE_AUTO_INDEX)!=0 ){ constructAutomaticIndex(pParse, &pWInfo->sWC, &pTabList->a[pLevel->iFrom], notReady, pLevel); if( db->mallocFailed ) goto whereBeginError; } #endif addrExplain = sqlite3WhereExplainOneScan( pParse, pTabList, pLevel, wctrlFlags ); pLevel->addrBody = sqlite3VdbeCurrentAddr(v); notReady = sqlite3WhereCodeOneLoopStart(pParse,v,pWInfo,ii,pLevel,notReady); pWInfo->iContinue = pLevel->addrCont; if( (wsFlags&WHERE_MULTI_OR)==0 && (wctrlFlags&WHERE_OR_SUBCLAUSE)==0 ){ sqlite3WhereAddScanStatus(v, pTabList, pLevel, addrExplain); } } /* Done. */ VdbeModuleComment((v, "Begin WHERE-core")); pWInfo->iEndWhere = sqlite3VdbeCurrentAddr(v); return pWInfo; /* Jump here if malloc fails */ whereBeginError: if( pWInfo ){ testcase( pWInfo->pExprMods!=0 ); whereUndoExprMods(pWInfo); pParse->nQueryLoop = pWInfo->savedNQueryLoop; whereInfoFree(db, pWInfo); } return 0; } /* |
︙ | ︙ | |||
5122 5123 5124 5125 5126 5127 5128 5129 5130 5131 5132 5133 5134 5135 5136 5137 5138 5139 5140 5141 5142 5143 5144 5145 | Parse *pParse = pWInfo->pParse; Vdbe *v = pParse->pVdbe; int i; WhereLevel *pLevel; WhereLoop *pLoop; SrcList *pTabList = pWInfo->pTabList; sqlite3 *db = pParse->db; /* Generate loop termination code. */ VdbeModuleComment((v, "End WHERE-core")); for(i=pWInfo->nLevel-1; i>=0; i--){ int addr; pLevel = &pWInfo->a[i]; pLoop = pLevel->pWLoop; if( pLevel->op!=OP_Noop ){ #ifndef SQLITE_DISABLE_SKIPAHEAD_DISTINCT int addrSeek = 0; Index *pIdx; int n; if( pWInfo->eDistinct==WHERE_DISTINCT_ORDERED && i==pWInfo->nLevel-1 /* Ticket [ef9318757b152e3] 2017-10-21 */ && (pLoop->wsFlags & WHERE_INDEXED)!=0 && (pIdx = pLoop->u.btree.pIndex)->hasStat1 | > | | 5430 5431 5432 5433 5434 5435 5436 5437 5438 5439 5440 5441 5442 5443 5444 5445 5446 5447 5448 5449 5450 5451 5452 5453 5454 5455 5456 5457 5458 5459 5460 5461 5462 | Parse *pParse = pWInfo->pParse; Vdbe *v = pParse->pVdbe; int i; WhereLevel *pLevel; WhereLoop *pLoop; SrcList *pTabList = pWInfo->pTabList; sqlite3 *db = pParse->db; int iEnd = sqlite3VdbeCurrentAddr(v); /* Generate loop termination code. */ VdbeModuleComment((v, "End WHERE-core")); for(i=pWInfo->nLevel-1; i>=0; i--){ int addr; pLevel = &pWInfo->a[i]; pLoop = pLevel->pWLoop; if( pLevel->op!=OP_Noop ){ #ifndef SQLITE_DISABLE_SKIPAHEAD_DISTINCT int addrSeek = 0; Index *pIdx; int n; if( pWInfo->eDistinct==WHERE_DISTINCT_ORDERED && i==pWInfo->nLevel-1 /* Ticket [ef9318757b152e3] 2017-10-21 */ && (pLoop->wsFlags & WHERE_INDEXED)!=0 && (pIdx = pLoop->u.btree.pIndex)->hasStat1 && (n = pLoop->u.btree.nDistinctCol)>0 && pIdx->aiRowLogEst[n]>=36 ){ int r1 = pParse->nMem+1; int j, op; for(j=0; j<n; j++){ sqlite3VdbeAddOp3(v, OP_Column, pLevel->iIdxCur, j, r1+j); } |
︙ | ︙ | |||
5163 5164 5165 5166 5167 5168 5169 5170 5171 5172 5173 5174 5175 | sqlite3VdbeResolveLabel(v, pLevel->addrCont); sqlite3VdbeAddOp3(v, pLevel->op, pLevel->p1, pLevel->p2, pLevel->p3); sqlite3VdbeChangeP5(v, pLevel->p5); VdbeCoverage(v); VdbeCoverageIf(v, pLevel->op==OP_Next); VdbeCoverageIf(v, pLevel->op==OP_Prev); VdbeCoverageIf(v, pLevel->op==OP_VNext); #ifndef SQLITE_DISABLE_SKIPAHEAD_DISTINCT if( addrSeek ) sqlite3VdbeJumpHere(v, addrSeek); #endif }else{ sqlite3VdbeResolveLabel(v, pLevel->addrCont); } | > > > > > | > > > > | > > > > > > > > > > > > > > | | | | > > > > > > | 5472 5473 5474 5475 5476 5477 5478 5479 5480 5481 5482 5483 5484 5485 5486 5487 5488 5489 5490 5491 5492 5493 5494 5495 5496 5497 5498 5499 5500 5501 5502 5503 5504 5505 5506 5507 5508 5509 5510 5511 5512 5513 5514 5515 5516 5517 5518 5519 5520 5521 5522 5523 5524 5525 5526 5527 5528 5529 5530 5531 5532 5533 | sqlite3VdbeResolveLabel(v, pLevel->addrCont); sqlite3VdbeAddOp3(v, pLevel->op, pLevel->p1, pLevel->p2, pLevel->p3); sqlite3VdbeChangeP5(v, pLevel->p5); VdbeCoverage(v); VdbeCoverageIf(v, pLevel->op==OP_Next); VdbeCoverageIf(v, pLevel->op==OP_Prev); VdbeCoverageIf(v, pLevel->op==OP_VNext); if( pLevel->regBignull ){ sqlite3VdbeResolveLabel(v, pLevel->addrBignull); sqlite3VdbeAddOp2(v, OP_DecrJumpZero, pLevel->regBignull, pLevel->p2-1); VdbeCoverage(v); } #ifndef SQLITE_DISABLE_SKIPAHEAD_DISTINCT if( addrSeek ) sqlite3VdbeJumpHere(v, addrSeek); #endif }else{ sqlite3VdbeResolveLabel(v, pLevel->addrCont); } if( (pLoop->wsFlags & WHERE_IN_ABLE)!=0 && pLevel->u.in.nIn>0 ){ struct InLoop *pIn; int j; sqlite3VdbeResolveLabel(v, pLevel->addrNxt); for(j=pLevel->u.in.nIn, pIn=&pLevel->u.in.aInLoop[j-1]; j>0; j--, pIn--){ assert( sqlite3VdbeGetOp(v, pIn->addrInTop+1)->opcode==OP_IsNull || pParse->db->mallocFailed ); sqlite3VdbeJumpHere(v, pIn->addrInTop+1); if( pIn->eEndLoopOp!=OP_Noop ){ if( pIn->nPrefix ){ int bEarlyOut = (pLoop->wsFlags & WHERE_VIRTUALTABLE)==0 && (pLoop->wsFlags & WHERE_IN_EARLYOUT)!=0; if( pLevel->iLeftJoin ){ /* For LEFT JOIN queries, cursor pIn->iCur may not have been ** opened yet. This occurs for WHERE clauses such as ** "a = ? AND b IN (...)", where the index is on (a, b). If ** the RHS of the (a=?) is NULL, then the "b IN (...)" may ** never have been coded, but the body of the loop run to ** return the null-row. So, if the cursor is not open yet, ** jump over the OP_Next or OP_Prev instruction about to ** be coded. */ sqlite3VdbeAddOp2(v, OP_IfNotOpen, pIn->iCur, sqlite3VdbeCurrentAddr(v) + 2 + bEarlyOut); VdbeCoverage(v); } if( bEarlyOut ){ sqlite3VdbeAddOp4Int(v, OP_IfNoHope, pLevel->iIdxCur, sqlite3VdbeCurrentAddr(v)+2, pIn->iBase, pIn->nPrefix); VdbeCoverage(v); /* Retarget the OP_IsNull against the left operand of IN so ** it jumps past the OP_IfNoHope. This is because the ** OP_IsNull also bypasses the OP_Affinity opcode that is ** required by OP_IfNoHope. */ sqlite3VdbeJumpHere(v, pIn->addrInTop+1); } } sqlite3VdbeAddOp2(v, pIn->eEndLoopOp, pIn->iCur, pIn->addrInTop); VdbeCoverage(v); VdbeCoverageIf(v, pIn->eEndLoopOp==OP_Prev); VdbeCoverageIf(v, pIn->eEndLoopOp==OP_Next); } sqlite3VdbeJumpHere(v, pIn->addrInTop-1); |
︙ | ︙ | |||
5214 5215 5216 5217 5218 5219 5220 | addr = sqlite3VdbeAddOp1(v, OP_IfPos, pLevel->iLeftJoin); VdbeCoverage(v); assert( (ws & WHERE_IDX_ONLY)==0 || (ws & WHERE_INDEXED)!=0 ); if( (ws & WHERE_IDX_ONLY)==0 ){ assert( pLevel->iTabCur==pTabList->a[pLevel->iFrom].iCursor ); sqlite3VdbeAddOp1(v, OP_NullRow, pLevel->iTabCur); } if( (ws & WHERE_INDEXED) | | > > > > > > | 5552 5553 5554 5555 5556 5557 5558 5559 5560 5561 5562 5563 5564 5565 5566 5567 5568 5569 5570 5571 5572 5573 | addr = sqlite3VdbeAddOp1(v, OP_IfPos, pLevel->iLeftJoin); VdbeCoverage(v); assert( (ws & WHERE_IDX_ONLY)==0 || (ws & WHERE_INDEXED)!=0 ); if( (ws & WHERE_IDX_ONLY)==0 ){ assert( pLevel->iTabCur==pTabList->a[pLevel->iFrom].iCursor ); sqlite3VdbeAddOp1(v, OP_NullRow, pLevel->iTabCur); } if( (ws & WHERE_INDEXED) || ((ws & WHERE_MULTI_OR) && pLevel->u.pCoveringIdx) ){ if( ws & WHERE_MULTI_OR ){ Index *pIx = pLevel->u.pCoveringIdx; int iDb = sqlite3SchemaToIndex(db, pIx->pSchema); sqlite3VdbeAddOp3(v, OP_ReopenIdx, pLevel->iIdxCur, pIx->tnum, iDb); sqlite3VdbeSetP4KeyInfo(pParse, pIx); } sqlite3VdbeAddOp1(v, OP_NullRow, pLevel->iIdxCur); } if( pLevel->op==OP_Return ){ sqlite3VdbeAddOp2(v, OP_Gosub, pLevel->p1, pLevel->addrFirst); }else{ sqlite3VdbeGoto(v, pLevel->addrFirst); } |
︙ | ︙ | |||
5237 5238 5239 5240 5241 5242 5243 | ** Set it. */ sqlite3VdbeResolveLabel(v, pWInfo->iBreak); assert( pWInfo->nLevel<=pTabList->nSrc ); for(i=0, pLevel=pWInfo->a; i<pWInfo->nLevel; i++, pLevel++){ int k, last; | | | > > > > > > > > > > > > > > > > > > > > > > > | < > | > > > | > > > > > > | > | > | > > > | < > > > > > | 5581 5582 5583 5584 5585 5586 5587 5588 5589 5590 5591 5592 5593 5594 5595 5596 5597 5598 5599 5600 5601 5602 5603 5604 5605 5606 5607 5608 5609 5610 5611 5612 5613 5614 5615 5616 5617 5618 5619 5620 5621 5622 5623 5624 5625 5626 5627 5628 5629 5630 5631 5632 5633 5634 5635 5636 5637 5638 5639 5640 5641 5642 5643 5644 5645 5646 5647 5648 5649 5650 5651 5652 5653 5654 5655 5656 5657 5658 5659 5660 5661 5662 5663 5664 5665 5666 5667 5668 5669 5670 5671 5672 5673 5674 5675 5676 5677 5678 5679 5680 5681 5682 5683 5684 5685 5686 5687 5688 5689 5690 5691 5692 5693 5694 5695 5696 5697 5698 5699 5700 5701 5702 5703 5704 5705 5706 5707 5708 5709 5710 5711 5712 5713 5714 5715 5716 5717 | ** Set it. */ sqlite3VdbeResolveLabel(v, pWInfo->iBreak); assert( pWInfo->nLevel<=pTabList->nSrc ); for(i=0, pLevel=pWInfo->a; i<pWInfo->nLevel; i++, pLevel++){ int k, last; VdbeOp *pOp, *pLastOp; Index *pIdx = 0; SrcItem *pTabItem = &pTabList->a[pLevel->iFrom]; Table *pTab = pTabItem->pTab; assert( pTab!=0 ); pLoop = pLevel->pWLoop; /* For a co-routine, change all OP_Column references to the table of ** the co-routine into OP_Copy of result contained in a register. ** OP_Rowid becomes OP_Null. */ if( pTabItem->fg.viaCoroutine ){ testcase( pParse->db->mallocFailed ); translateColumnToCopy(pParse, pLevel->addrBody, pLevel->iTabCur, pTabItem->regResult, 0); continue; } #ifdef SQLITE_ENABLE_EARLY_CURSOR_CLOSE /* Close all of the cursors that were opened by sqlite3WhereBegin. ** Except, do not close cursors that will be reused by the OR optimization ** (WHERE_OR_SUBCLAUSE). And do not close the OP_OpenWrite cursors ** created for the ONEPASS optimization. */ if( (pTab->tabFlags & TF_Ephemeral)==0 && !IsView(pTab) && (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)==0 ){ int ws = pLoop->wsFlags; if( pWInfo->eOnePass==ONEPASS_OFF && (ws & WHERE_IDX_ONLY)==0 ){ sqlite3VdbeAddOp1(v, OP_Close, pTabItem->iCursor); } if( (ws & WHERE_INDEXED)!=0 && (ws & (WHERE_IPK|WHERE_AUTO_INDEX))==0 && pLevel->iIdxCur!=pWInfo->aiCurOnePass[1] ){ sqlite3VdbeAddOp1(v, OP_Close, pLevel->iIdxCur); } } #endif /* If this scan uses an index, make VDBE code substitutions to read data ** from the index instead of from the table where possible. In some cases ** this optimization prevents the table from ever being read, which can ** yield a significant performance boost. ** ** Calls to the code generator in between sqlite3WhereBegin and ** sqlite3WhereEnd will have created code that references the table ** directly. This loop scans all that code looking for opcodes ** that reference the table and converts them into opcodes that ** reference the index. */ if( pLoop->wsFlags & (WHERE_INDEXED|WHERE_IDX_ONLY) ){ pIdx = pLoop->u.btree.pIndex; }else if( pLoop->wsFlags & WHERE_MULTI_OR ){ pIdx = pLevel->u.pCoveringIdx; } if( pIdx && !db->mallocFailed ){ if( pWInfo->eOnePass==ONEPASS_OFF || !HasRowid(pIdx->pTable) ){ last = iEnd; }else{ last = pWInfo->iEndWhere; } k = pLevel->addrBody + 1; #ifdef SQLITE_DEBUG if( db->flags & SQLITE_VdbeAddopTrace ){ printf("TRANSLATE opcodes in range %d..%d\n", k, last-1); } /* Proof that the "+1" on the k value above is safe */ pOp = sqlite3VdbeGetOp(v, k - 1); assert( pOp->opcode!=OP_Column || pOp->p1!=pLevel->iTabCur ); assert( pOp->opcode!=OP_Rowid || pOp->p1!=pLevel->iTabCur ); assert( pOp->opcode!=OP_IfNullRow || pOp->p1!=pLevel->iTabCur ); #endif pOp = sqlite3VdbeGetOp(v, k); pLastOp = pOp + (last - k); assert( pOp<=pLastOp ); do{ if( pOp->p1!=pLevel->iTabCur ){ /* no-op */ }else if( pOp->opcode==OP_Column #ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC || pOp->opcode==OP_Offset #endif ){ int x = pOp->p2; assert( pIdx->pTable==pTab ); if( !HasRowid(pTab) ){ Index *pPk = sqlite3PrimaryKeyIndex(pTab); x = pPk->aiColumn[x]; assert( x>=0 ); }else{ testcase( x!=sqlite3StorageColumnToTable(pTab,x) ); x = sqlite3StorageColumnToTable(pTab,x); } x = sqlite3TableColumnToIndex(pIdx, x); if( x>=0 ){ pOp->p2 = x; pOp->p1 = pLevel->iIdxCur; OpcodeRewriteTrace(db, k, pOp); } assert( (pLoop->wsFlags & WHERE_IDX_ONLY)==0 || x>=0 || pWInfo->eOnePass ); }else if( pOp->opcode==OP_Rowid ){ pOp->p1 = pLevel->iIdxCur; pOp->opcode = OP_IdxRowid; OpcodeRewriteTrace(db, k, pOp); }else if( pOp->opcode==OP_IfNullRow ){ pOp->p1 = pLevel->iIdxCur; OpcodeRewriteTrace(db, k, pOp); } #ifdef SQLITE_DEBUG k++; #endif }while( (++pOp)<pLastOp ); #ifdef SQLITE_DEBUG if( db->flags & SQLITE_VdbeAddopTrace ) printf("TRANSLATE complete\n"); #endif } } /* Final cleanup */ if( pWInfo->pExprMods ) whereUndoExprMods(pWInfo); pParse->nQueryLoop = pWInfo->savedNQueryLoop; whereInfoFree(db, pWInfo); return; } |
Changes to src/whereInt.h.
︙ | ︙ | |||
10 11 12 13 14 15 16 17 | ** ************************************************************************* ** ** This file contains structure and macro definitions for the query ** planner logic in "where.c". These definitions are broken out into ** a separate source file for easier editing. */ | > > < < < < < < < < < < < < < | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | ** ************************************************************************* ** ** This file contains structure and macro definitions for the query ** planner logic in "where.c". These definitions are broken out into ** a separate source file for easier editing. */ #ifndef SQLITE_WHEREINT_H #define SQLITE_WHEREINT_H /* Forward references */ typedef struct WhereClause WhereClause; typedef struct WhereMaskSet WhereMaskSet; typedef struct WhereOrInfo WhereOrInfo; typedef struct WhereAndInfo WhereAndInfo; |
︙ | ︙ | |||
65 66 67 68 69 70 71 72 73 74 75 76 77 | int iIdxCur; /* The VDBE cursor used to access pIdx */ int addrBrk; /* Jump here to break out of the loop */ int addrNxt; /* Jump here to start the next IN combination */ int addrSkip; /* Jump here for next iteration of skip-scan */ int addrCont; /* Jump here to continue with the next loop cycle */ int addrFirst; /* First instruction of interior of the loop */ int addrBody; /* Beginning of the body of this loop */ #ifndef SQLITE_LIKE_DOESNT_MATCH_BLOBS u32 iLikeRepCntr; /* LIKE range processing counter register (times 2) */ int addrLikeRep; /* LIKE range processing address */ #endif u8 iFrom; /* Which entry in the FROM clause */ u8 op, p3, p5; /* Opcode, P3 & P5 of the opcode that ends the loop */ | > > | | | 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 | int iIdxCur; /* The VDBE cursor used to access pIdx */ int addrBrk; /* Jump here to break out of the loop */ int addrNxt; /* Jump here to start the next IN combination */ int addrSkip; /* Jump here for next iteration of skip-scan */ int addrCont; /* Jump here to continue with the next loop cycle */ int addrFirst; /* First instruction of interior of the loop */ int addrBody; /* Beginning of the body of this loop */ int regBignull; /* big-null flag reg. True if a NULL-scan is needed */ int addrBignull; /* Jump here for next part of big-null scan */ #ifndef SQLITE_LIKE_DOESNT_MATCH_BLOBS u32 iLikeRepCntr; /* LIKE range processing counter register (times 2) */ int addrLikeRep; /* LIKE range processing address */ #endif u8 iFrom; /* Which entry in the FROM clause */ u8 op, p3, p5; /* Opcode, P3 & P5 of the opcode that ends the loop */ int p1, p2; /* Operands of the opcode used to end the loop */ union { /* Information that depends on pWLoop->wsFlags */ struct { int nIn; /* Number of entries in aInLoop[] */ struct InLoop { int iCur; /* The VDBE cursor used by this IN operator */ int addrInTop; /* Top of the IN loop */ int iBase; /* Base register of multi-key index record */ int nPrefix; /* Number of prior entires in the key */ u8 eEndLoopOp; /* IN Loop terminator. OP_Next or OP_Prev */ } *aInLoop; /* Information about each nested IN operator */ } in; /* Used when pWLoop->wsFlags&WHERE_IN_ABLE */ Index *pCoveringIdx; /* Possible covering index for WHERE_MULTI_OR */ } u; struct WhereLoop *pWLoop; /* The selected WhereLoop object */ Bitmask notReady; /* FROM entries not usable at this level */ #ifdef SQLITE_ENABLE_STMT_SCANSTATUS int addrVisit; /* Address at which row is visited */ #endif }; |
︙ | ︙ | |||
122 123 124 125 126 127 128 | LogEst rRun; /* Cost of running each loop */ LogEst nOut; /* Estimated number of output rows */ union { struct { /* Information for internal btree tables */ u16 nEq; /* Number of equality constraints */ u16 nBtm; /* Size of BTM vector */ u16 nTop; /* Size of TOP vector */ | | | 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 | LogEst rRun; /* Cost of running each loop */ LogEst nOut; /* Estimated number of output rows */ union { struct { /* Information for internal btree tables */ u16 nEq; /* Number of equality constraints */ u16 nBtm; /* Size of BTM vector */ u16 nTop; /* Size of TOP vector */ u16 nDistinctCol; /* Index columns used to sort for DISTINCT */ Index *pIndex; /* Index used, or NULL */ } btree; struct { /* Information for virtual tables */ int idxNum; /* Index number */ u8 needFree; /* True if sqlite3_free(idxStr) is needed */ i8 isOrdered; /* True if satisfies ORDER BY */ u16 omitMask; /* Terms that may be omitted */ |
︙ | ︙ | |||
253 254 255 256 257 258 259 | LogEst truthProb; /* Probability of truth for this expression */ u16 wtFlags; /* TERM_xxx bit flags. See below */ u16 eOperator; /* A WO_xx value describing <op> */ u8 nChild; /* Number of children that must disable us */ u8 eMatchOp; /* Op for vtab MATCH/LIKE/GLOB/REGEXP terms */ int iParent; /* Disable pWC->a[iParent] when this term disabled */ int leftCursor; /* Cursor number of X in "X <op> <expr>" */ | < > | > > | | | | | | | < | < < < | | | | > > > > > > | | | 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 | LogEst truthProb; /* Probability of truth for this expression */ u16 wtFlags; /* TERM_xxx bit flags. See below */ u16 eOperator; /* A WO_xx value describing <op> */ u8 nChild; /* Number of children that must disable us */ u8 eMatchOp; /* Op for vtab MATCH/LIKE/GLOB/REGEXP terms */ int iParent; /* Disable pWC->a[iParent] when this term disabled */ int leftCursor; /* Cursor number of X in "X <op> <expr>" */ union { struct { int leftColumn; /* Column number of X in "X <op> <expr>" */ int iField; /* Field in (?,?,?) IN (SELECT...) vector */ } x; /* Opcode other than OP_OR or OP_AND */ WhereOrInfo *pOrInfo; /* Extra information if (eOperator & WO_OR)!=0 */ WhereAndInfo *pAndInfo; /* Extra information if (eOperator& WO_AND)!=0 */ } u; Bitmask prereqRight; /* Bitmask of tables used by pExpr->pRight */ Bitmask prereqAll; /* Bitmask of tables referenced by pExpr */ }; /* ** Allowed values of WhereTerm.wtFlags */ #define TERM_DYNAMIC 0x0001 /* Need to call sqlite3ExprDelete(db, pExpr) */ #define TERM_VIRTUAL 0x0002 /* Added by the optimizer. Do not code */ #define TERM_CODED 0x0004 /* This term is already coded */ #define TERM_COPIED 0x0008 /* Has a child */ #define TERM_ORINFO 0x0010 /* Need to free the WhereTerm.u.pOrInfo object */ #define TERM_ANDINFO 0x0020 /* Need to free the WhereTerm.u.pAndInfo obj */ #define TERM_OR_OK 0x0040 /* Used during OR-clause processing */ #define TERM_VNULL 0x0080 /* Manufactured x>NULL or x<=NULL term */ #define TERM_LIKEOPT 0x0100 /* Virtual terms from the LIKE optimization */ #define TERM_LIKECOND 0x0200 /* Conditionally this LIKE operator term */ #define TERM_LIKE 0x0400 /* The original LIKE operator */ #define TERM_IS 0x0800 /* Term.pExpr is an IS operator */ #define TERM_VARSELECT 0x1000 /* Term.pExpr contains a correlated sub-query */ #define TERM_HEURTRUTH 0x2000 /* Heuristic truthProb used */ #ifdef SQLITE_ENABLE_STAT4 # define TERM_HIGHTRUTH 0x4000 /* Term excludes few rows */ #else # define TERM_HIGHTRUTH 0 /* Only used with STAT4 */ #endif /* ** An instance of the WhereScan object is used as an iterator for locating ** terms in the WHERE clause that are useful to the query planner. */ struct WhereScan { WhereClause *pOrigWC; /* Original, innermost WhereClause */ WhereClause *pWC; /* WhereClause currently being scanned */ const char *zCollName; /* Required collating sequence, if not NULL */ Expr *pIdxExpr; /* Search for this index expression */ char idxaff; /* Must match this affinity, if zCollName!=NULL */ unsigned char nEquiv; /* Number of entries in aiCur[] and aiColumn[] */ unsigned char iEquiv; /* Next unused slot in aiCur[] and aiColumn[] */ u32 opMask; /* Acceptable operators */ int k; /* Resume scanning at this->pWC->a[this->k] */ int aiCur[11]; /* Cursors in the equivalence class */ i16 aiColumn[11]; /* Corresponding column number in the eq-class */ }; /* |
︙ | ︙ | |||
393 394 395 396 397 398 399 | */ struct WhereLoopBuilder { WhereInfo *pWInfo; /* Information about this WHERE */ WhereClause *pWC; /* WHERE clause terms */ ExprList *pOrderBy; /* ORDER BY clause */ WhereLoop *pNew; /* Template WhereLoop */ WhereOrSet *pOrSet; /* Record best loops here, if not NULL */ | | | > | | > > | 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 | */ struct WhereLoopBuilder { WhereInfo *pWInfo; /* Information about this WHERE */ WhereClause *pWC; /* WHERE clause terms */ ExprList *pOrderBy; /* ORDER BY clause */ WhereLoop *pNew; /* Template WhereLoop */ WhereOrSet *pOrSet; /* Record best loops here, if not NULL */ #ifdef SQLITE_ENABLE_STAT4 UnpackedRecord *pRec; /* Probe for stat4 (if required) */ int nRecValid; /* Number of valid fields currently in pRec */ #endif unsigned char bldFlags1; /* First set of SQLITE_BLDF_* flags */ unsigned char bldFlags2; /* Second set of SQLITE_BLDF_* flags */ unsigned int iPlanLimit; /* Search limiter */ }; /* Allowed values for WhereLoopBuider.bldFlags */ #define SQLITE_BLDF1_INDEXED 0x0001 /* An index is used */ #define SQLITE_BLDF1_UNIQUE 0x0002 /* All keys of a UNIQUE index used */ #define SQLITE_BLDF2_2NDPASS 0x0004 /* Second builder pass needed */ /* The WhereLoopBuilder.iPlanLimit is used to limit the number of ** index+constraint combinations the query planner will consider for a ** particular query. If this parameter is unlimited, then certain ** pathological queries can spend excess time in the sqlite3WhereBegin() ** routine. The limit is high enough that is should not impact real-world ** queries. |
︙ | ︙ | |||
425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 | #ifndef SQLITE_QUERY_PLANNER_LIMIT # define SQLITE_QUERY_PLANNER_LIMIT 20000 #endif #ifndef SQLITE_QUERY_PLANNER_LIMIT_INCR # define SQLITE_QUERY_PLANNER_LIMIT_INCR 1000 #endif /* ** The WHERE clause processing routine has two halves. The ** first part does the start of the WHERE loop and the second ** half does the tail of the WHERE loop. An instance of ** this structure is returned by the first half and passed ** into the second half to give some continuity. ** ** An instance of this object holds the complete state of the query ** planner. */ struct WhereInfo { Parse *pParse; /* Parsing and code generating context */ SrcList *pTabList; /* List of tables in the join */ ExprList *pOrderBy; /* The ORDER BY clause or NULL */ ExprList *pResultSet; /* Result set of the query */ Expr *pWhere; /* The complete WHERE clause */ | > > > > > > > > > > > > > > < > < < > > | > > > > < > > | 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 | #ifndef SQLITE_QUERY_PLANNER_LIMIT # define SQLITE_QUERY_PLANNER_LIMIT 20000 #endif #ifndef SQLITE_QUERY_PLANNER_LIMIT_INCR # define SQLITE_QUERY_PLANNER_LIMIT_INCR 1000 #endif /* ** Each instance of this object records a change to a single node ** in an expression tree to cause that node to point to a column ** of an index rather than an expression or a virtual column. All ** such transformations need to be undone at the end of WHERE clause ** processing. */ typedef struct WhereExprMod WhereExprMod; struct WhereExprMod { WhereExprMod *pNext; /* Next translation on a list of them all */ Expr *pExpr; /* The Expr node that was transformed */ Expr orig; /* Original value of the Expr node */ }; /* ** The WHERE clause processing routine has two halves. The ** first part does the start of the WHERE loop and the second ** half does the tail of the WHERE loop. An instance of ** this structure is returned by the first half and passed ** into the second half to give some continuity. ** ** An instance of this object holds the complete state of the query ** planner. */ struct WhereInfo { Parse *pParse; /* Parsing and code generating context */ SrcList *pTabList; /* List of tables in the join */ ExprList *pOrderBy; /* The ORDER BY clause or NULL */ ExprList *pResultSet; /* Result set of the query */ Expr *pWhere; /* The complete WHERE clause */ int aiCurOnePass[2]; /* OP_OpenWrite cursors for the ONEPASS opt */ int iContinue; /* Jump here to continue with next record */ int iBreak; /* Jump here to break out of the loop */ int savedNQueryLoop; /* pParse->nQueryLoop outside the WHERE loop */ u16 wctrlFlags; /* Flags originally passed to sqlite3WhereBegin() */ LogEst iLimit; /* LIMIT if wctrlFlags has WHERE_USE_LIMIT */ u8 nLevel; /* Number of nested loop */ i8 nOBSat; /* Number of ORDER BY terms satisfied by indices */ u8 eOnePass; /* ONEPASS_OFF, or _SINGLE, or _MULTI */ u8 eDistinct; /* One of the WHERE_DISTINCT_* values */ unsigned bDeferredSeek :1; /* Uses OP_DeferredSeek */ unsigned untestedTerms :1; /* Not all WHERE terms resolved by outer loop */ unsigned bOrderedInnerLoop:1;/* True if only the inner-most loop is ordered */ unsigned sorted :1; /* True if really sorted (not just grouped) */ LogEst nRowOut; /* Estimated number of output rows */ int iTop; /* The very beginning of the WHERE loop */ int iEndWhere; /* End of the WHERE clause itself */ WhereLoop *pLoops; /* List of all WhereLoop objects */ WhereExprMod *pExprMods; /* Expression modifications */ Bitmask revMask; /* Mask of ORDER BY terms that need reversing */ WhereClause sWC; /* Decomposition of the WHERE clause */ WhereMaskSet sMaskSet; /* Map cursor numbers to bitmasks */ WhereLevel a[1]; /* Information about each nest loop in WHERE */ }; /* ** Private interfaces - callable only by other where.c routines. ** ** where.c: */ Bitmask sqlite3WhereGetMask(WhereMaskSet*,int); #ifdef WHERETRACE_ENABLED void sqlite3WhereClausePrint(WhereClause *pWC); void sqlite3WhereTermPrint(WhereTerm *pTerm, int iTerm); void sqlite3WhereLoopPrint(WhereLoop *p, WhereClause *pWC); #endif WhereTerm *sqlite3WhereFindTerm( WhereClause *pWC, /* The WHERE clause to be searched */ int iCur, /* Cursor number of LHS */ int iColumn, /* Column number of LHS */ Bitmask notReady, /* RHS must not overlap with this mask */ u32 op, /* Mask of WO_xx values describing operator */ |
︙ | ︙ | |||
503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 | WhereLevel *pLvl, /* Level to add scanstatus() entry for */ int addrExplain /* Address of OP_Explain (or 0) */ ); #else # define sqlite3WhereAddScanStatus(a, b, c, d) ((void)d) #endif Bitmask sqlite3WhereCodeOneLoopStart( WhereInfo *pWInfo, /* Complete information about the WHERE clause */ int iLevel, /* Which level of pWInfo->a[] should be coded */ Bitmask notReady /* Which tables are currently available */ ); /* whereexpr.c: */ void sqlite3WhereClauseInit(WhereClause*,WhereInfo*); void sqlite3WhereClauseClear(WhereClause*); void sqlite3WhereSplit(WhereClause*,Expr*,u8); Bitmask sqlite3WhereExprUsage(WhereMaskSet*, Expr*); Bitmask sqlite3WhereExprUsageNN(WhereMaskSet*, Expr*); Bitmask sqlite3WhereExprListUsage(WhereMaskSet*, ExprList*); void sqlite3WhereExprAnalyze(SrcList*, WhereClause*); | > > > | | 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 | WhereLevel *pLvl, /* Level to add scanstatus() entry for */ int addrExplain /* Address of OP_Explain (or 0) */ ); #else # define sqlite3WhereAddScanStatus(a, b, c, d) ((void)d) #endif Bitmask sqlite3WhereCodeOneLoopStart( Parse *pParse, /* Parsing context */ Vdbe *v, /* Prepared statement under construction */ WhereInfo *pWInfo, /* Complete information about the WHERE clause */ int iLevel, /* Which level of pWInfo->a[] should be coded */ WhereLevel *pLevel, /* The current level pointer */ Bitmask notReady /* Which tables are currently available */ ); /* whereexpr.c: */ void sqlite3WhereClauseInit(WhereClause*,WhereInfo*); void sqlite3WhereClauseClear(WhereClause*); void sqlite3WhereSplit(WhereClause*,Expr*,u8); Bitmask sqlite3WhereExprUsage(WhereMaskSet*, Expr*); Bitmask sqlite3WhereExprUsageNN(WhereMaskSet*, Expr*); Bitmask sqlite3WhereExprListUsage(WhereMaskSet*, ExprList*); void sqlite3WhereExprAnalyze(SrcList*, WhereClause*); void sqlite3WhereTabFuncArgs(Parse*, SrcItem*, WhereClause*); /* ** Bitmasks for the operators on WhereTerm objects. These are all |
︙ | ︙ | |||
577 578 579 580 581 582 583 | #define WHERE_ONEROW 0x00001000 /* Selects no more than one row */ #define WHERE_MULTI_OR 0x00002000 /* OR using multiple indices */ #define WHERE_AUTO_INDEX 0x00004000 /* Uses an ephemeral index */ #define WHERE_SKIPSCAN 0x00008000 /* Uses the skip-scan algorithm */ #define WHERE_UNQ_WANTED 0x00010000 /* WHERE_ONEROW would have been helpful*/ #define WHERE_PARTIALIDX 0x00020000 /* The automatic index is partial */ #define WHERE_IN_EARLYOUT 0x00040000 /* Perhaps quit IN loops early */ | > > > > > | 597 598 599 600 601 602 603 604 605 606 607 608 | #define WHERE_ONEROW 0x00001000 /* Selects no more than one row */ #define WHERE_MULTI_OR 0x00002000 /* OR using multiple indices */ #define WHERE_AUTO_INDEX 0x00004000 /* Uses an ephemeral index */ #define WHERE_SKIPSCAN 0x00008000 /* Uses the skip-scan algorithm */ #define WHERE_UNQ_WANTED 0x00010000 /* WHERE_ONEROW would have been helpful*/ #define WHERE_PARTIALIDX 0x00020000 /* The automatic index is partial */ #define WHERE_IN_EARLYOUT 0x00040000 /* Perhaps quit IN loops early */ #define WHERE_BIGNULL_SORT 0x00080000 /* Column nEq of index is BIGNULL */ #define WHERE_IN_SEEKSCAN 0x00100000 /* Seek-scan optimization for IN */ #define WHERE_TRANSCONS 0x00200000 /* Uses a transitive constraint */ #endif /* !defined(SQLITE_WHEREINT_H) */ |
Changes to src/wherecode.c.
︙ | ︙ | |||
25 26 27 28 29 30 31 | /* ** Return the name of the i-th column of the pIdx index. */ static const char *explainIndexColumnName(Index *pIdx, int i){ i = pIdx->aiColumn[i]; if( i==XN_EXPR ) return "<expr>"; if( i==XN_ROWID ) return "rowid"; | | | 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | /* ** Return the name of the i-th column of the pIdx index. */ static const char *explainIndexColumnName(Index *pIdx, int i){ i = pIdx->aiColumn[i]; if( i==XN_EXPR ) return "<expr>"; if( i==XN_ROWID ) return "rowid"; return pIdx->pTable->aCol[i].zCnName; } /* ** This routine is a helper for explainIndexRange() below ** ** pStr holds the text of an expression that we are building up one term ** at a time. This routine adds a new term to the end of the expression. |
︙ | ︙ | |||
125 126 127 128 129 130 131 | u16 wctrlFlags /* Flags passed to sqlite3WhereBegin() */ ){ int ret = 0; #if !defined(SQLITE_DEBUG) && !defined(SQLITE_ENABLE_STMT_SCANSTATUS) if( sqlite3ParseToplevel(pParse)->explain==2 ) #endif { | | < < < < < < | < | < | 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 | u16 wctrlFlags /* Flags passed to sqlite3WhereBegin() */ ){ int ret = 0; #if !defined(SQLITE_DEBUG) && !defined(SQLITE_ENABLE_STMT_SCANSTATUS) if( sqlite3ParseToplevel(pParse)->explain==2 ) #endif { SrcItem *pItem = &pTabList->a[pLevel->iFrom]; Vdbe *v = pParse->pVdbe; /* VM being constructed */ sqlite3 *db = pParse->db; /* Database handle */ int isSearch; /* True for a SEARCH. False for SCAN. */ WhereLoop *pLoop; /* The controlling WhereLoop object */ u32 flags; /* Flags that describe this loop */ char *zMsg; /* Text to add to EQP output */ StrAccum str; /* EQP output string */ char zBuf[100]; /* Initial space for EQP output string */ pLoop = pLevel->pWLoop; flags = pLoop->wsFlags; if( (flags&WHERE_MULTI_OR) || (wctrlFlags&WHERE_OR_SUBCLAUSE) ) return 0; isSearch = (flags&(WHERE_BTM_LIMIT|WHERE_TOP_LIMIT))!=0 || ((flags&WHERE_VIRTUALTABLE)==0 && (pLoop->u.btree.nEq>0)) || (wctrlFlags&(WHERE_ORDERBY_MIN|WHERE_ORDERBY_MAX)); sqlite3StrAccumInit(&str, db, zBuf, sizeof(zBuf), SQLITE_MAX_LENGTH); str.printfFlags = SQLITE_PRINTF_INTERNAL; sqlite3_str_appendf(&str, "%s %S", isSearch ? "SEARCH" : "SCAN", pItem); if( (flags & (WHERE_IPK|WHERE_VIRTUALTABLE))==0 ){ const char *zFmt = 0; Index *pIdx; assert( pLoop->u.btree.pIndex!=0 ); pIdx = pLoop->u.btree.pIndex; assert( !(flags&WHERE_AUTO_INDEX) || (flags&WHERE_IDX_ONLY) ); |
︙ | ︙ | |||
209 210 211 212 213 214 215 216 217 218 219 220 221 222 | sqlite3_str_appendf(&str, " (~%llu rows)", sqlite3LogEstToInt(pLoop->nOut)); }else{ sqlite3_str_append(&str, " (~1 row)", 9); } #endif zMsg = sqlite3StrAccumFinish(&str); ret = sqlite3VdbeAddOp4(v, OP_Explain, sqlite3VdbeCurrentAddr(v), pParse->addrExplain, 0, zMsg,P4_DYNAMIC); } return ret; } #endif /* SQLITE_OMIT_EXPLAIN */ | > | 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 | sqlite3_str_appendf(&str, " (~%llu rows)", sqlite3LogEstToInt(pLoop->nOut)); }else{ sqlite3_str_append(&str, " (~1 row)", 9); } #endif zMsg = sqlite3StrAccumFinish(&str); sqlite3ExplainBreakpoint("",zMsg); ret = sqlite3VdbeAddOp4(v, OP_Explain, sqlite3VdbeCurrentAddr(v), pParse->addrExplain, 0, zMsg,P4_DYNAMIC); } return ret; } #endif /* SQLITE_OMIT_EXPLAIN */ |
︙ | ︙ | |||
300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 | && (pLevel->notReady & pTerm->prereqAll)==0 ){ if( nLoop && (pTerm->wtFlags & TERM_LIKE)!=0 ){ pTerm->wtFlags |= TERM_LIKECOND; }else{ pTerm->wtFlags |= TERM_CODED; } if( pTerm->iParent<0 ) break; pTerm = &pTerm->pWC->a[pTerm->iParent]; assert( pTerm!=0 ); pTerm->nChild--; if( pTerm->nChild!=0 ) break; nLoop++; } } /* ** Code an OP_Affinity opcode to apply the column affinity string zAff ** to the n registers starting at base. ** | > > > > > > | | | | | > | | | 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 | && (pLevel->notReady & pTerm->prereqAll)==0 ){ if( nLoop && (pTerm->wtFlags & TERM_LIKE)!=0 ){ pTerm->wtFlags |= TERM_LIKECOND; }else{ pTerm->wtFlags |= TERM_CODED; } #ifdef WHERETRACE_ENABLED if( sqlite3WhereTrace & 0x20000 ){ sqlite3DebugPrintf("DISABLE-"); sqlite3WhereTermPrint(pTerm, (int)(pTerm - (pTerm->pWC->a))); } #endif if( pTerm->iParent<0 ) break; pTerm = &pTerm->pWC->a[pTerm->iParent]; assert( pTerm!=0 ); pTerm->nChild--; if( pTerm->nChild!=0 ) break; nLoop++; } } /* ** Code an OP_Affinity opcode to apply the column affinity string zAff ** to the n registers starting at base. ** ** As an optimization, SQLITE_AFF_BLOB and SQLITE_AFF_NONE entries (which ** are no-ops) at the beginning and end of zAff are ignored. If all entries ** in zAff are SQLITE_AFF_BLOB or SQLITE_AFF_NONE, then no code gets generated. ** ** This routine makes its own copy of zAff so that the caller is free ** to modify zAff after this routine returns. */ static void codeApplyAffinity(Parse *pParse, int base, int n, char *zAff){ Vdbe *v = pParse->pVdbe; if( zAff==0 ){ assert( pParse->db->mallocFailed ); return; } assert( v!=0 ); /* Adjust base and n to skip over SQLITE_AFF_BLOB and SQLITE_AFF_NONE ** entries at the beginning and end of the affinity string. */ assert( SQLITE_AFF_NONE<SQLITE_AFF_BLOB ); while( n>0 && zAff[0]<=SQLITE_AFF_BLOB ){ n--; base++; zAff++; } while( n>1 && zAff[n-1]<=SQLITE_AFF_BLOB ){ n--; } /* Code the OP_Affinity opcode if there is anything left to do. */ if( n>0 ){ sqlite3VdbeAddOp4(v, OP_Affinity, base, n, 0, zAff, n); } |
︙ | ︙ | |||
409 410 411 412 413 414 415 | static Expr *removeUnindexableInClauseTerms( Parse *pParse, /* The parsing context */ int iEq, /* Look at loop terms starting here */ WhereLoop *pLoop, /* The current loop */ Expr *pX /* The IN expression to be reduced */ ){ sqlite3 *db = pParse->db; | > | | | > > > > > > > | | 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 | static Expr *removeUnindexableInClauseTerms( Parse *pParse, /* The parsing context */ int iEq, /* Look at loop terms starting here */ WhereLoop *pLoop, /* The current loop */ Expr *pX /* The IN expression to be reduced */ ){ sqlite3 *db = pParse->db; Expr *pNew; pNew = sqlite3ExprDup(db, pX, 0); if( db->mallocFailed==0 ){ ExprList *pOrigRhs; /* Original unmodified RHS */ ExprList *pOrigLhs; /* Original unmodified LHS */ ExprList *pRhs = 0; /* New RHS after modifications */ ExprList *pLhs = 0; /* New LHS after mods */ int i; /* Loop counter */ Select *pSelect; /* Pointer to the SELECT on the RHS */ assert( ExprUseXSelect(pNew) ); pOrigRhs = pNew->x.pSelect->pEList; assert( pNew->pLeft!=0 ); assert( ExprUseXList(pNew->pLeft) ); pOrigLhs = pNew->pLeft->x.pList; for(i=iEq; i<pLoop->nLTerm; i++){ if( pLoop->aLTerm[i]->pExpr==pX ){ int iField; assert( (pLoop->aLTerm[i]->eOperator & (WO_OR|WO_AND))==0 ); iField = pLoop->aLTerm[i]->u.x.iField - 1; if( pOrigRhs->a[iField].pExpr==0 ) continue; /* Duplicate PK column */ pRhs = sqlite3ExprListAppend(pParse, pRhs, pOrigRhs->a[iField].pExpr); pOrigRhs->a[iField].pExpr = 0; assert( pOrigLhs->a[iField].pExpr!=0 ); pLhs = sqlite3ExprListAppend(pParse, pLhs, pOrigLhs->a[iField].pExpr); pOrigLhs->a[iField].pExpr = 0; } |
︙ | ︙ | |||
534 535 536 537 538 539 540 | } } for(i=iEq;i<pLoop->nLTerm; i++){ assert( pLoop->aLTerm[i]!=0 ); if( pLoop->aLTerm[i]->pExpr==pX ) nEq++; } | > | | | | < < > | > > > < | < > > > > > > > > > > > > > > > > > > > > > | > > | 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 | } } for(i=iEq;i<pLoop->nLTerm; i++){ assert( pLoop->aLTerm[i]!=0 ); if( pLoop->aLTerm[i]->pExpr==pX ) nEq++; } iTab = 0; if( !ExprUseXSelect(pX) || pX->x.pSelect->pEList->nExpr==1 ){ eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0, 0, &iTab); }else{ sqlite3 *db = pParse->db; pX = removeUnindexableInClauseTerms(pParse, iEq, pLoop, pX); if( !db->mallocFailed ){ aiMap = (int*)sqlite3DbMallocZero(pParse->db, sizeof(int)*nEq); eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0, aiMap, &iTab); pTerm->pExpr->iTable = iTab; } sqlite3ExprDelete(db, pX); pX = pTerm->pExpr; } if( eType==IN_INDEX_INDEX_DESC ){ testcase( bRev ); bRev = !bRev; } sqlite3VdbeAddOp2(v, bRev ? OP_Last : OP_Rewind, iTab, 0); VdbeCoverageIf(v, bRev); VdbeCoverageIf(v, !bRev); assert( (pLoop->wsFlags & WHERE_MULTI_OR)==0 ); pLoop->wsFlags |= WHERE_IN_ABLE; if( pLevel->u.in.nIn==0 ){ pLevel->addrNxt = sqlite3VdbeMakeLabel(pParse); } if( iEq>0 && (pLoop->wsFlags & WHERE_IN_SEEKSCAN)==0 ){ pLoop->wsFlags |= WHERE_IN_EARLYOUT; } i = pLevel->u.in.nIn; pLevel->u.in.nIn += nEq; pLevel->u.in.aInLoop = sqlite3DbReallocOrFree(pParse->db, pLevel->u.in.aInLoop, sizeof(pLevel->u.in.aInLoop[0])*pLevel->u.in.nIn); pIn = pLevel->u.in.aInLoop; if( pIn ){ int iMap = 0; /* Index in aiMap[] */ pIn += i; for(i=iEq;i<pLoop->nLTerm; i++){ if( pLoop->aLTerm[i]->pExpr==pX ){ int iOut = iReg + i - iEq; if( eType==IN_INDEX_ROWID ){ pIn->addrInTop = sqlite3VdbeAddOp2(v, OP_Rowid, iTab, iOut); }else{ int iCol = aiMap ? aiMap[iMap++] : 0; pIn->addrInTop = sqlite3VdbeAddOp3(v,OP_Column,iTab, iCol, iOut); } sqlite3VdbeAddOp1(v, OP_IsNull, iOut); VdbeCoverage(v); if( i==iEq ){ pIn->iCur = iTab; pIn->eEndLoopOp = bRev ? OP_Prev : OP_Next; if( iEq>0 ){ pIn->iBase = iReg - i; pIn->nPrefix = i; }else{ pIn->nPrefix = 0; } }else{ pIn->eEndLoopOp = OP_Noop; } pIn++; } } testcase( iEq>0 && (pLoop->wsFlags & WHERE_IN_SEEKSCAN)==0 && (pLoop->wsFlags & WHERE_VIRTUALTABLE)!=0 ); if( iEq>0 && (pLoop->wsFlags & (WHERE_IN_SEEKSCAN|WHERE_VIRTUALTABLE))==0 ){ sqlite3VdbeAddOp3(v, OP_SeekHit, pLevel->iIdxCur, 0, iEq); } }else{ pLevel->u.in.nIn = 0; } sqlite3DbFree(pParse->db, aiMap); #endif } /* As an optimization, try to disable the WHERE clause term that is ** driving the index as it will always be true. The correct answer is ** obtained regardless, but we might get the answer with fewer CPU cycles ** by omitting the term. ** ** But do not disable the term unless we are certain that the term is ** not a transitive constraint. For an example of where that does not ** work, see https://sqlite.org/forum/forumpost/eb8613976a (2021-05-04) */ if( (pLevel->pWLoop->wsFlags & WHERE_TRANSCONS)==0 || (pTerm->eOperator & WO_EQUIV)==0 ){ disableTerm(pLevel, pTerm); } return iReg; } /* ** Generate code that will evaluate all == and IN constraints for an ** index scan. ** |
︙ | ︙ | |||
692 693 694 695 696 697 698 699 700 701 702 703 704 705 | pParse->nMem += nReg; zAff = sqlite3DbStrDup(pParse->db,sqlite3IndexAffinityStr(pParse->db,pIdx)); assert( zAff!=0 || pParse->db->mallocFailed ); if( nSkip ){ int iIdxCur = pLevel->iIdxCur; sqlite3VdbeAddOp1(v, (bRev?OP_Last:OP_Rewind), iIdxCur); VdbeCoverageIf(v, bRev==0); VdbeCoverageIf(v, bRev!=0); VdbeComment((v, "begin skip-scan on %s", pIdx->zName)); j = sqlite3VdbeAddOp0(v, OP_Goto); pLevel->addrSkip = sqlite3VdbeAddOp4Int(v, (bRev?OP_SeekLT:OP_SeekGT), iIdxCur, 0, regBase, nSkip); | > | 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 | pParse->nMem += nReg; zAff = sqlite3DbStrDup(pParse->db,sqlite3IndexAffinityStr(pParse->db,pIdx)); assert( zAff!=0 || pParse->db->mallocFailed ); if( nSkip ){ int iIdxCur = pLevel->iIdxCur; sqlite3VdbeAddOp3(v, OP_Null, 0, regBase, regBase+nSkip-1); sqlite3VdbeAddOp1(v, (bRev?OP_Last:OP_Rewind), iIdxCur); VdbeCoverageIf(v, bRev==0); VdbeCoverageIf(v, bRev!=0); VdbeComment((v, "begin skip-scan on %s", pIdx->zName)); j = sqlite3VdbeAddOp0(v, OP_Goto); pLevel->addrSkip = sqlite3VdbeAddOp4Int(v, (bRev?OP_SeekLT:OP_SeekGT), iIdxCur, 0, regBase, nSkip); |
︙ | ︙ | |||
726 727 728 729 730 731 732 | testcase( pTerm->wtFlags & TERM_VIRTUAL ); r1 = codeEqualityTerm(pParse, pTerm, pLevel, j, bRev, regBase+j); if( r1!=regBase+j ){ if( nReg==1 ){ sqlite3ReleaseTempReg(pParse, regBase); regBase = r1; }else{ | | | | 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 | testcase( pTerm->wtFlags & TERM_VIRTUAL ); r1 = codeEqualityTerm(pParse, pTerm, pLevel, j, bRev, regBase+j); if( r1!=regBase+j ){ if( nReg==1 ){ sqlite3ReleaseTempReg(pParse, regBase); regBase = r1; }else{ sqlite3VdbeAddOp2(v, OP_Copy, r1, regBase+j); } } if( pTerm->eOperator & WO_IN ){ if( pTerm->pExpr->flags & EP_xIsSelect ){ /* No affinity ever needs to be (or should be) applied to a value ** from the RHS of an "? IN (SELECT ...)" expression. The ** sqlite3FindInIndex() routine has already ensured that the ** affinity of the comparison has been applied to the value. */ if( zAff ) zAff[j] = SQLITE_AFF_BLOB; } }else if( (pTerm->eOperator & WO_ISNULL)==0 ){ Expr *pRight = pTerm->pExpr->pRight; if( (pTerm->wtFlags & TERM_IS)==0 && sqlite3ExprCanBeNull(pRight) ){ sqlite3VdbeAddOp2(v, OP_IsNull, regBase+j, pLevel->addrBrk); VdbeCoverage(v); } if( pParse->db->mallocFailed==0 && pParse->nErr==0 ){ if( sqlite3CompareAffinity(pRight, zAff[j])==SQLITE_AFF_BLOB ){ zAff[j] = SQLITE_AFF_BLOB; } if( sqlite3ExprNeedsNoAffinityChange(pRight, zAff[j]) ){ zAff[j] = SQLITE_AFF_BLOB; } } |
︙ | ︙ | |||
818 819 820 821 822 823 824 | ** accessed through the index. If it cannot, then set pWalker->eCode to 1. */ static int codeCursorHintCheckExpr(Walker *pWalker, Expr *pExpr){ struct CCurHint *pHint = pWalker->u.pCCurHint; assert( pHint->pIdx!=0 ); if( pExpr->op==TK_COLUMN && pExpr->iTable==pHint->iTabCur | | | 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 | ** accessed through the index. If it cannot, then set pWalker->eCode to 1. */ static int codeCursorHintCheckExpr(Walker *pWalker, Expr *pExpr){ struct CCurHint *pHint = pWalker->u.pCCurHint; assert( pHint->pIdx!=0 ); if( pExpr->op==TK_COLUMN && pExpr->iTable==pHint->iTabCur && sqlite3TableColumnToIndex(pHint->pIdx, pExpr->iColumn)<0 ){ pWalker->eCode = 1; } return WRC_Continue; } /* |
︙ | ︙ | |||
886 887 888 889 890 891 892 | if( pExpr->iTable!=pHint->iTabCur ){ int reg = ++pWalker->pParse->nMem; /* Register for column value */ sqlite3ExprCode(pWalker->pParse, pExpr, reg); pExpr->op = TK_REGISTER; pExpr->iTable = reg; }else if( pHint->pIdx!=0 ){ pExpr->iTable = pHint->iIdxCur; | | | | 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 | if( pExpr->iTable!=pHint->iTabCur ){ int reg = ++pWalker->pParse->nMem; /* Register for column value */ sqlite3ExprCode(pWalker->pParse, pExpr, reg); pExpr->op = TK_REGISTER; pExpr->iTable = reg; }else if( pHint->pIdx!=0 ){ pExpr->iTable = pHint->iIdxCur; pExpr->iColumn = sqlite3TableColumnToIndex(pHint->pIdx, pExpr->iColumn); assert( pExpr->iColumn>=0 ); } }else if( pExpr->op==TK_AGG_FUNCTION ){ /* An aggregate function in the WHERE clause of a query means this must ** be a correlated sub-query, and expression pExpr is an aggregate from ** the parent context. Do not walk the function arguments in this case. ** ** todo: It should be possible to replace this node with a TK_REGISTER ** expression, as the result of the expression must be stored in a ** register at this point. The same holds for TK_AGG_COLUMN nodes. */ rc = WRC_Prune; } return rc; } /* ** Insert an OP_CursorHint instruction if it is appropriate to do so. */ static void codeCursorHint( SrcItem *pTabItem, /* FROM clause item */ WhereInfo *pWInfo, /* The where clause */ WhereLevel *pLevel, /* Which loop to provide hints for */ WhereTerm *pEndRange /* Hint this end-of-scan boundary term if not NULL */ ){ Parse *pParse = pWInfo->pParse; sqlite3 *db = pParse->db; Vdbe *v = pParse->pVdbe; |
︙ | ︙ | |||
995 996 997 998 999 1000 1001 | sWalker.eCode = 0; sWalker.xExprCallback = codeCursorHintCheckExpr; sqlite3WalkExpr(&sWalker, pTerm->pExpr); if( sWalker.eCode ) continue; } /* If we survive all prior tests, that means this term is worth hinting */ | | | 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 | sWalker.eCode = 0; sWalker.xExprCallback = codeCursorHintCheckExpr; sqlite3WalkExpr(&sWalker, pTerm->pExpr); if( sWalker.eCode ) continue; } /* If we survive all prior tests, that means this term is worth hinting */ pExpr = sqlite3ExprAnd(pParse, pExpr, sqlite3ExprDup(db, pTerm->pExpr, 0)); } if( pExpr!=0 ){ sWalker.xExprCallback = codeCursorHintFixExpr; sqlite3WalkExpr(&sWalker, pExpr); sqlite3VdbeAddOp4(v, OP_CursorHint, (sHint.pIdx ? sHint.iIdxCur : sHint.iTabCur), 0, 0, (const char*)pExpr, P4_EXPR); |
︙ | ︙ | |||
1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 | ){ Parse *pParse = pWInfo->pParse; /* Parse context */ Vdbe *v = pParse->pVdbe; /* Vdbe to generate code within */ assert( iIdxCur>0 ); assert( pIdx->aiColumn[pIdx->nColumn-1]==-1 ); sqlite3VdbeAddOp3(v, OP_DeferredSeek, iIdxCur, 0, iCur); if( (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE) && DbMaskAllZero(sqlite3ParseToplevel(pParse)->writeMask) ){ int i; Table *pTab = pIdx->pTable; | > | > | > > > | > > | > > | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > < > > | | > > | > > > > > > > > > > > > > > > > > > > > > < > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > < < < < | < < < < < > > > > > > > > > > > > > > > | | | 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 | ){ Parse *pParse = pWInfo->pParse; /* Parse context */ Vdbe *v = pParse->pVdbe; /* Vdbe to generate code within */ assert( iIdxCur>0 ); assert( pIdx->aiColumn[pIdx->nColumn-1]==-1 ); pWInfo->bDeferredSeek = 1; sqlite3VdbeAddOp3(v, OP_DeferredSeek, iIdxCur, 0, iCur); if( (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE) && DbMaskAllZero(sqlite3ParseToplevel(pParse)->writeMask) ){ int i; Table *pTab = pIdx->pTable; u32 *ai = (u32*)sqlite3DbMallocZero(pParse->db, sizeof(u32)*(pTab->nCol+1)); if( ai ){ ai[0] = pTab->nCol; for(i=0; i<pIdx->nColumn-1; i++){ int x1, x2; assert( pIdx->aiColumn[i]<pTab->nCol ); x1 = pIdx->aiColumn[i]; x2 = sqlite3TableColumnToStorage(pTab, x1); testcase( x1!=x2 ); if( x1>=0 ) ai[x2+1] = i+1; } sqlite3VdbeChangeP4(v, -1, (char*)ai, P4_INTARRAY); } } } /* ** If the expression passed as the second argument is a vector, generate ** code to write the first nReg elements of the vector into an array ** of registers starting with iReg. ** ** If the expression is not a vector, then nReg must be passed 1. In ** this case, generate code to evaluate the expression and leave the ** result in register iReg. */ static void codeExprOrVector(Parse *pParse, Expr *p, int iReg, int nReg){ assert( nReg>0 ); if( p && sqlite3ExprIsVector(p) ){ #ifndef SQLITE_OMIT_SUBQUERY if( ExprUseXSelect(p) ){ Vdbe *v = pParse->pVdbe; int iSelect; assert( p->op==TK_SELECT ); iSelect = sqlite3CodeSubselect(pParse, p); sqlite3VdbeAddOp3(v, OP_Copy, iSelect, iReg, nReg-1); }else #endif { int i; const ExprList *pList; assert( ExprUseXList(p) ); pList = p->x.pList; assert( nReg<=pList->nExpr ); for(i=0; i<nReg; i++){ sqlite3ExprCode(pParse, pList->a[i].pExpr, iReg+i); } } }else{ assert( nReg==1 || pParse->nErr ); sqlite3ExprCode(pParse, p, iReg); } } /* An instance of the IdxExprTrans object carries information about a ** mapping from an expression on table columns into a column in an index ** down through the Walker. */ typedef struct IdxExprTrans { Expr *pIdxExpr; /* The index expression */ int iTabCur; /* The cursor of the corresponding table */ int iIdxCur; /* The cursor for the index */ int iIdxCol; /* The column for the index */ int iTabCol; /* The column for the table */ WhereInfo *pWInfo; /* Complete WHERE clause information */ sqlite3 *db; /* Database connection (for malloc()) */ } IdxExprTrans; /* ** Preserve pExpr on the WhereETrans list of the WhereInfo. */ static void preserveExpr(IdxExprTrans *pTrans, Expr *pExpr){ WhereExprMod *pNew; pNew = sqlite3DbMallocRaw(pTrans->db, sizeof(*pNew)); if( pNew==0 ) return; pNew->pNext = pTrans->pWInfo->pExprMods; pTrans->pWInfo->pExprMods = pNew; pNew->pExpr = pExpr; memcpy(&pNew->orig, pExpr, sizeof(*pExpr)); } /* The walker node callback used to transform matching expressions into ** a reference to an index column for an index on an expression. ** ** If pExpr matches, then transform it into a reference to the index column ** that contains the value of pExpr. */ static int whereIndexExprTransNode(Walker *p, Expr *pExpr){ IdxExprTrans *pX = p->u.pIdxTrans; if( sqlite3ExprCompare(0, pExpr, pX->pIdxExpr, pX->iTabCur)==0 ){ preserveExpr(pX, pExpr); pExpr->affExpr = sqlite3ExprAffinity(pExpr); pExpr->op = TK_COLUMN; pExpr->iTable = pX->iIdxCur; pExpr->iColumn = pX->iIdxCol; testcase( ExprHasProperty(pExpr, EP_Skip) ); testcase( ExprHasProperty(pExpr, EP_Unlikely) ); ExprClearProperty(pExpr, EP_Skip|EP_Unlikely|EP_WinFunc|EP_Subrtn); pExpr->y.pTab = 0; return WRC_Prune; }else{ return WRC_Continue; } } #ifndef SQLITE_OMIT_GENERATED_COLUMNS /* A walker node callback that translates a column reference to a table ** into a corresponding column reference of an index. */ static int whereIndexExprTransColumn(Walker *p, Expr *pExpr){ if( pExpr->op==TK_COLUMN ){ IdxExprTrans *pX = p->u.pIdxTrans; if( pExpr->iTable==pX->iTabCur && pExpr->iColumn==pX->iTabCol ){ assert( ExprUseYTab(pExpr) && pExpr->y.pTab!=0 ); preserveExpr(pX, pExpr); pExpr->affExpr = sqlite3TableColumnAffinity(pExpr->y.pTab,pExpr->iColumn); pExpr->iTable = pX->iIdxCur; pExpr->iColumn = pX->iIdxCol; pExpr->y.pTab = 0; } } return WRC_Continue; } #endif /* SQLITE_OMIT_GENERATED_COLUMNS */ /* ** For an indexes on expression X, locate every instance of expression X ** in pExpr and change that subexpression into a reference to the appropriate ** column of the index. ** ** 2019-10-24: Updated to also translate references to a VIRTUAL column in ** the table into references to the corresponding (stored) column of the ** index. */ static void whereIndexExprTrans( Index *pIdx, /* The Index */ int iTabCur, /* Cursor of the table that is being indexed */ int iIdxCur, /* Cursor of the index itself */ WhereInfo *pWInfo /* Transform expressions in this WHERE clause */ ){ int iIdxCol; /* Column number of the index */ ExprList *aColExpr; /* Expressions that are indexed */ Table *pTab; Walker w; IdxExprTrans x; aColExpr = pIdx->aColExpr; if( aColExpr==0 && !pIdx->bHasVCol ){ /* The index does not reference any expressions or virtual columns ** so no translations are needed. */ return; } pTab = pIdx->pTable; memset(&w, 0, sizeof(w)); w.u.pIdxTrans = &x; x.iTabCur = iTabCur; x.iIdxCur = iIdxCur; x.pWInfo = pWInfo; x.db = pWInfo->pParse->db; for(iIdxCol=0; iIdxCol<pIdx->nColumn; iIdxCol++){ i16 iRef = pIdx->aiColumn[iIdxCol]; if( iRef==XN_EXPR ){ assert( aColExpr!=0 && aColExpr->a[iIdxCol].pExpr!=0 ); x.pIdxExpr = aColExpr->a[iIdxCol].pExpr; if( sqlite3ExprIsConstant(x.pIdxExpr) ) continue; w.xExprCallback = whereIndexExprTransNode; #ifndef SQLITE_OMIT_GENERATED_COLUMNS }else if( iRef>=0 && (pTab->aCol[iRef].colFlags & COLFLAG_VIRTUAL)!=0 && ((pTab->aCol[iRef].colFlags & COLFLAG_HASCOLL)==0 || sqlite3StrICmp(sqlite3ColumnColl(&pTab->aCol[iRef]), sqlite3StrBINARY)==0) ){ /* Check to see if there are direct references to generated columns ** that are contained in the index. Pulling the generated column ** out of the index is an optimization only - the main table is always ** available if the index cannot be used. To avoid unnecessary ** complication, omit this optimization if the collating sequence for ** the column is non-standard */ x.iTabCol = iRef; w.xExprCallback = whereIndexExprTransColumn; #endif /* SQLITE_OMIT_GENERATED_COLUMNS */ }else{ continue; } x.iIdxCol = iIdxCol; sqlite3WalkExpr(&w, pWInfo->pWhere); sqlite3WalkExprList(&w, pWInfo->pOrderBy); sqlite3WalkExprList(&w, pWInfo->pResultSet); } } /* ** The pTruth expression is always true because it is the WHERE clause ** a partial index that is driving a query loop. Look through all of the ** WHERE clause terms on the query, and if any of those terms must be ** true because pTruth is true, then mark those WHERE clause terms as ** coded. */ static void whereApplyPartialIndexConstraints( Expr *pTruth, int iTabCur, WhereClause *pWC ){ int i; WhereTerm *pTerm; while( pTruth->op==TK_AND ){ whereApplyPartialIndexConstraints(pTruth->pLeft, iTabCur, pWC); pTruth = pTruth->pRight; } for(i=0, pTerm=pWC->a; i<pWC->nTerm; i++, pTerm++){ Expr *pExpr; if( pTerm->wtFlags & TERM_CODED ) continue; pExpr = pTerm->pExpr; if( sqlite3ExprCompare(0, pExpr, pTruth, iTabCur)==0 ){ pTerm->wtFlags |= TERM_CODED; } } } /* ** Generate code for the start of the iLevel-th loop in the WHERE clause ** implementation described by pWInfo. */ Bitmask sqlite3WhereCodeOneLoopStart( Parse *pParse, /* Parsing context */ Vdbe *v, /* Prepared statement under construction */ WhereInfo *pWInfo, /* Complete information about the WHERE clause */ int iLevel, /* Which level of pWInfo->a[] should be coded */ WhereLevel *pLevel, /* The current level pointer */ Bitmask notReady /* Which tables are currently available */ ){ int j, k; /* Loop counters */ int iCur; /* The VDBE cursor for the table */ int addrNxt; /* Where to jump to continue with the next IN case */ int bRev; /* True if we need to scan in reverse order */ WhereLoop *pLoop; /* The WhereLoop object being coded */ WhereClause *pWC; /* Decomposition of the entire WHERE clause */ WhereTerm *pTerm; /* A WHERE clause term */ sqlite3 *db; /* Database connection */ SrcItem *pTabItem; /* FROM clause term being coded */ int addrBrk; /* Jump here to break out of the loop */ int addrHalt; /* addrBrk for the outermost 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 */ Index *pIdx = 0; /* Index used by loop (if any) */ int iLoop; /* Iteration of constraint generator loop */ pWC = &pWInfo->sWC; db = pParse->db; pLoop = pLevel->pWLoop; pTabItem = &pWInfo->pTabList->a[pLevel->iFrom]; iCur = pTabItem->iCursor; pLevel->notReady = notReady & ~sqlite3WhereGetMask(&pWInfo->sMaskSet, iCur); bRev = (pWInfo->revMask>>iLevel)&1; VdbeModuleComment((v, "Begin WHERE-loop%d: %s",iLevel,pTabItem->pTab->zName)); #if WHERETRACE_ENABLED /* 0x20800 */ if( sqlite3WhereTrace & 0x800 ){ sqlite3DebugPrintf("Coding level %d of %d: notReady=%llx iFrom=%d\n", iLevel, pWInfo->nLevel, (u64)notReady, pLevel->iFrom); sqlite3WhereLoopPrint(pLoop, pWC); } if( sqlite3WhereTrace & 0x20000 ){ if( iLevel==0 ){ sqlite3DebugPrintf("WHERE clause being coded:\n"); sqlite3TreeViewExpr(0, pWInfo->pWhere, 0); } sqlite3DebugPrintf("All WHERE-clause terms before coding:\n"); sqlite3WhereClausePrint(pWC); } #endif /* 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 ** means to continue with the next IN value combination. When ** there are no IN operators in the constraints, the "addrNxt" label ** is the same as "addrBrk". */ addrBrk = pLevel->addrBrk = pLevel->addrNxt = sqlite3VdbeMakeLabel(pParse); addrCont = pLevel->addrCont = sqlite3VdbeMakeLabel(pParse); /* If this is the right table of a LEFT OUTER JOIN, allocate and ** initialize a memory cell that records if this table matches any ** row of the left table of the join. */ assert( (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE) || pLevel->iFrom>0 || (pTabItem[0].fg.jointype & JT_LEFT)==0 |
︙ | ︙ | |||
1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 | sqlite3VdbeAddOp2(v, OP_Integer, pLoop->u.vtab.idxNum, iReg); sqlite3VdbeAddOp2(v, OP_Integer, nConstraint, iReg+1); sqlite3VdbeAddOp4(v, OP_VFilter, iCur, addrNotFound, iReg, pLoop->u.vtab.idxStr, pLoop->u.vtab.needFree ? P4_DYNAMIC : P4_STATIC); VdbeCoverage(v); pLoop->u.vtab.needFree = 0; pLevel->p1 = iCur; pLevel->op = pWInfo->eOnePass ? OP_Noop : OP_VNext; pLevel->p2 = sqlite3VdbeCurrentAddr(v); | > > > > > | > > > > | > > | | | > > > | 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 | sqlite3VdbeAddOp2(v, OP_Integer, pLoop->u.vtab.idxNum, iReg); sqlite3VdbeAddOp2(v, OP_Integer, nConstraint, iReg+1); sqlite3VdbeAddOp4(v, OP_VFilter, iCur, addrNotFound, iReg, pLoop->u.vtab.idxStr, pLoop->u.vtab.needFree ? P4_DYNAMIC : P4_STATIC); VdbeCoverage(v); pLoop->u.vtab.needFree = 0; /* An OOM inside of AddOp4(OP_VFilter) instruction above might have freed ** the u.vtab.idxStr. NULL it out to prevent a use-after-free */ if( db->mallocFailed ) pLoop->u.vtab.idxStr = 0; pLevel->p1 = iCur; pLevel->op = pWInfo->eOnePass ? OP_Noop : OP_VNext; pLevel->p2 = sqlite3VdbeCurrentAddr(v); assert( (pLoop->wsFlags & WHERE_MULTI_OR)==0 ); if( pLoop->wsFlags & WHERE_IN_ABLE ){ iIn = pLevel->u.in.nIn; }else{ iIn = 0; } for(j=nConstraint-1; j>=0; j--){ pTerm = pLoop->aLTerm[j]; if( (pTerm->eOperator & WO_IN)!=0 ) iIn--; if( j<16 && (pLoop->u.vtab.omitMask>>j)&1 ){ disableTerm(pLevel, pTerm); }else if( (pTerm->eOperator & WO_IN)!=0 && sqlite3ExprVectorSize(pTerm->pExpr->pLeft)==1 ){ Expr *pCompare; /* The comparison operator */ Expr *pRight; /* RHS of the comparison */ VdbeOp *pOp; /* Opcode to access the value of the IN constraint */ /* Reload the constraint value into reg[iReg+j+2]. The same value ** was loaded into the same register prior to the OP_VFilter, but ** the xFilter implementation might have changed the datatype or ** encoding of the value in the register, so it *must* be reloaded. */ assert( pLevel->u.in.aInLoop!=0 || db->mallocFailed ); if( !db->mallocFailed ){ assert( iIn>=0 && iIn<pLevel->u.in.nIn ); pOp = sqlite3VdbeGetOp(v, pLevel->u.in.aInLoop[iIn].addrInTop); assert( pOp->opcode==OP_Column || pOp->opcode==OP_Rowid ); assert( pOp->opcode!=OP_Column || pOp->p3==iReg+j+2 ); assert( pOp->opcode!=OP_Rowid || pOp->p2==iReg+j+2 ); testcase( pOp->opcode==OP_Rowid ); sqlite3VdbeAddOp3(v, pOp->opcode, pOp->p1, pOp->p2, pOp->p3); } /* Generate code that will continue to the next row if ** the IN constraint is not satisfied */ pCompare = sqlite3PExpr(pParse, TK_EQ, 0, 0); assert( pCompare!=0 || db->mallocFailed ); if( pCompare ){ pCompare->pLeft = pTerm->pExpr->pLeft; pCompare->pRight = pRight = sqlite3Expr(db, TK_REGISTER, 0); if( pRight ){ pRight->iTable = iReg+j+2; sqlite3ExprIfFalse( pParse, pCompare, pLevel->addrCont, SQLITE_JUMPIFNULL ); } pCompare->pLeft = 0; sqlite3ExprDelete(db, pCompare); } } } assert( iIn==0 || db->mallocFailed ); /* These registers need to be preserved in case there is an IN operator ** loop. So we could deallocate the registers here (and potentially ** reuse them later) if (pLoop->wsFlags & WHERE_IN_ABLE)==0. But it seems ** simpler and safer to simply not reuse the registers. ** ** sqlite3ReleaseTempRange(pParse, iReg, nConstraint+2); */ |
︙ | ︙ | |||
1335 1336 1337 1338 1339 1340 1341 | ** we reference multiple rows using a "rowid IN (...)" ** construct. */ assert( pLoop->u.btree.nEq==1 ); pTerm = pLoop->aLTerm[0]; assert( pTerm!=0 ); assert( pTerm->pExpr!=0 ); | < < | 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 | ** we reference multiple rows using a "rowid IN (...)" ** construct. */ assert( pLoop->u.btree.nEq==1 ); pTerm = pLoop->aLTerm[0]; assert( pTerm!=0 ); assert( pTerm->pExpr!=0 ); testcase( pTerm->wtFlags & TERM_VIRTUAL ); iReleaseReg = ++pParse->nMem; iRowidReg = codeEqualityTerm(pParse, pTerm, pLevel, 0, bRev, iReleaseReg); if( iRowidReg!=iReleaseReg ) sqlite3ReleaseTempReg(pParse, iReleaseReg); addrNxt = pLevel->addrNxt; sqlite3VdbeAddOp3(v, OP_SeekRowid, iCur, addrNxt, iRowidReg); VdbeCoverage(v); pLevel->op = OP_Noop; }else if( (pLoop->wsFlags & WHERE_IPK)!=0 && (pLoop->wsFlags & WHERE_COLUMN_RANGE)!=0 ){ /* Case 3: We have an inequality comparison against the ROWID field. */ int testOp = OP_Noop; int start; int memEndValue = 0; WhereTerm *pStart, *pEnd; j = 0; pStart = pEnd = 0; if( pLoop->wsFlags & WHERE_BTM_LIMIT ) pStart = pLoop->aLTerm[j++]; if( pLoop->wsFlags & WHERE_TOP_LIMIT ) pEnd = pLoop->aLTerm[j++]; assert( pStart!=0 || pEnd!=0 ); if( bRev ){ pTerm = pStart; |
︙ | ︙ | |||
1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 | int iIdxCur; /* The VDBE cursor for the index */ int nExtraReg = 0; /* Number of extra registers needed */ int op; /* Instruction opcode */ char *zStartAff; /* Affinity for start of range constraint */ char *zEndAff = 0; /* Affinity for end of range constraint */ u8 bSeekPastNull = 0; /* True to seek past initial nulls */ u8 bStopAtNull = 0; /* Add condition to terminate at NULLs */ pIdx = pLoop->u.btree.pIndex; iIdxCur = pLevel->iIdxCur; assert( nEq>=pLoop->nSkip ); | > > > < < < < < < < < < < < < < < < < < < < < | 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 | int iIdxCur; /* The VDBE cursor for the index */ int nExtraReg = 0; /* Number of extra registers needed */ int op; /* Instruction opcode */ char *zStartAff; /* Affinity for start of range constraint */ char *zEndAff = 0; /* Affinity for end of range constraint */ u8 bSeekPastNull = 0; /* True to seek past initial nulls */ u8 bStopAtNull = 0; /* Add condition to terminate at NULLs */ int omitTable; /* True if we use the index only */ int regBignull = 0; /* big-null flag register */ int addrSeekScan = 0; /* Opcode of the OP_SeekScan, if any */ pIdx = pLoop->u.btree.pIndex; iIdxCur = pLevel->iIdxCur; assert( nEq>=pLoop->nSkip ); /* Find any inequality constraint terms for the start and end ** of the range. */ j = nEq; if( pLoop->wsFlags & WHERE_BTM_LIMIT ){ pRangeStart = pLoop->aLTerm[j++]; nExtraReg = MAX(nExtraReg, pLoop->u.btree.nBtm); |
︙ | ︙ | |||
1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 | j = pIdx->aiColumn[nEq]; if( (j>=0 && pIdx->pTable->aCol[j].notNull==0) || j==XN_EXPR ){ bSeekPastNull = 1; } } } assert( pRangeEnd==0 || (pRangeEnd->wtFlags & TERM_VNULL)==0 ); /* If we are doing a reverse order scan on an ascending index, or ** a forward order scan on a descending index, interchange the ** start and end terms (pRangeStart and pRangeEnd). */ | > > > > > > > > > > > > > > > > > > > > > > | < < > > > > > > | | 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 | j = pIdx->aiColumn[nEq]; if( (j>=0 && pIdx->pTable->aCol[j].notNull==0) || j==XN_EXPR ){ bSeekPastNull = 1; } } } assert( pRangeEnd==0 || (pRangeEnd->wtFlags & TERM_VNULL)==0 ); /* If the WHERE_BIGNULL_SORT flag is set, then index column nEq uses ** a non-default "big-null" sort (either ASC NULLS LAST or DESC NULLS ** FIRST). In both cases separate ordered scans are made of those ** index entries for which the column is null and for those for which ** it is not. For an ASC sort, the non-NULL entries are scanned first. ** For DESC, NULL entries are scanned first. */ if( (pLoop->wsFlags & (WHERE_TOP_LIMIT|WHERE_BTM_LIMIT))==0 && (pLoop->wsFlags & WHERE_BIGNULL_SORT)!=0 ){ assert( bSeekPastNull==0 && nExtraReg==0 && nBtm==0 && nTop==0 ); assert( pRangeEnd==0 && pRangeStart==0 ); testcase( pLoop->nSkip>0 ); nExtraReg = 1; bSeekPastNull = 1; pLevel->regBignull = regBignull = ++pParse->nMem; if( pLevel->iLeftJoin ){ sqlite3VdbeAddOp2(v, OP_Integer, 0, regBignull); } pLevel->addrBignull = sqlite3VdbeMakeLabel(pParse); } /* If we are doing a reverse order scan on an ascending index, or ** a forward order scan on a descending index, interchange the ** start and end terms (pRangeStart and pRangeEnd). */ if( (nEq<pIdx->nColumn && bRev==(pIdx->aSortOrder[nEq]==SQLITE_SO_ASC)) ){ SWAP(WhereTerm *, pRangeEnd, pRangeStart); SWAP(u8, bSeekPastNull, bStopAtNull); SWAP(u8, nBtm, nTop); } if( iLevel>0 && (pLoop->wsFlags & WHERE_IN_SEEKSCAN)!=0 ){ /* In case OP_SeekScan is used, ensure that the index cursor does not ** point to a valid row for the first iteration of this loop. */ sqlite3VdbeAddOp1(v, OP_NullRow, iIdxCur); } /* Generate code to evaluate all constraint terms using == or IN ** and store the values of those terms in an array of registers ** starting at regBase. */ codeCursorHint(pTabItem, pWInfo, pLevel, pRangeEnd); regBase = codeAllEqualityTerms(pParse,pLevel,bRev,nExtraReg,&zStartAff); assert( zStartAff==0 || sqlite3Strlen30(zStartAff)>=nEq ); if( zStartAff && nTop ){ zEndAff = sqlite3DbStrDup(db, &zStartAff[nEq]); } addrNxt = (regBignull ? pLevel->addrBignull : pLevel->addrNxt); testcase( pRangeStart && (pRangeStart->eOperator & WO_LE)!=0 ); testcase( pRangeStart && (pRangeStart->eOperator & WO_GE)!=0 ); testcase( pRangeEnd && (pRangeEnd->eOperator & WO_LE)!=0 ); testcase( pRangeEnd && (pRangeEnd->eOperator & WO_GE)!=0 ); startEq = !pRangeStart || pRangeStart->eOperator & (WO_LE|WO_GE); endEq = !pRangeEnd || pRangeEnd->eOperator & (WO_LE|WO_GE); |
︙ | ︙ | |||
1639 1640 1641 1642 1643 1644 1645 1646 1647 | if( sqlite3ExprIsVector(pRight)==0 ){ disableTerm(pLevel, pRangeStart); }else{ startEq = 1; } bSeekPastNull = 0; }else if( bSeekPastNull ){ sqlite3VdbeAddOp2(v, OP_Null, 0, regBase+nEq); nConstraint++; | > > < > > > | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 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 1904 1905 1906 | if( sqlite3ExprIsVector(pRight)==0 ){ disableTerm(pLevel, pRangeStart); }else{ startEq = 1; } bSeekPastNull = 0; }else if( bSeekPastNull ){ startEq = 0; sqlite3VdbeAddOp2(v, OP_Null, 0, regBase+nEq); start_constraints = 1; nConstraint++; }else if( regBignull ){ sqlite3VdbeAddOp2(v, OP_Null, 0, regBase+nEq); start_constraints = 1; nConstraint++; } codeApplyAffinity(pParse, regBase, nConstraint - bSeekPastNull, zStartAff); if( pLoop->nSkip>0 && nConstraint==pLoop->nSkip ){ /* The skip-scan logic inside the call to codeAllEqualityConstraints() ** above has already left the cursor sitting on the correct row, ** so no further seeking is needed */ }else{ if( regBignull ){ sqlite3VdbeAddOp2(v, OP_Integer, 1, regBignull); VdbeComment((v, "NULL-scan pass ctr")); } op = aStartOp[(start_constraints<<2) + (startEq<<1) + bRev]; assert( op!=0 ); if( (pLoop->wsFlags & WHERE_IN_SEEKSCAN)!=0 && op==OP_SeekGE ){ assert( regBignull==0 ); /* TUNING: The OP_SeekScan opcode seeks to reduce the number ** of expensive seek operations by replacing a single seek with ** 1 or more step operations. The question is, how many steps ** should we try before giving up and going with a seek. The cost ** of a seek is proportional to the logarithm of the of the number ** of entries in the tree, so basing the number of steps to try ** on the estimated number of rows in the btree seems like a good ** guess. */ addrSeekScan = sqlite3VdbeAddOp1(v, OP_SeekScan, (pIdx->aiRowLogEst[0]+9)/10); VdbeCoverage(v); } sqlite3VdbeAddOp4Int(v, op, iIdxCur, addrNxt, regBase, nConstraint); VdbeCoverage(v); VdbeCoverageIf(v, op==OP_Rewind); testcase( op==OP_Rewind ); VdbeCoverageIf(v, op==OP_Last); testcase( op==OP_Last ); VdbeCoverageIf(v, op==OP_SeekGT); testcase( op==OP_SeekGT ); VdbeCoverageIf(v, op==OP_SeekGE); testcase( op==OP_SeekGE ); VdbeCoverageIf(v, op==OP_SeekLE); testcase( op==OP_SeekLE ); VdbeCoverageIf(v, op==OP_SeekLT); testcase( op==OP_SeekLT ); assert( bSeekPastNull==0 || bStopAtNull==0 ); if( regBignull ){ assert( bSeekPastNull==1 || bStopAtNull==1 ); assert( bSeekPastNull==!bStopAtNull ); assert( bStopAtNull==startEq ); sqlite3VdbeAddOp2(v, OP_Goto, 0, sqlite3VdbeCurrentAddr(v)+2); op = aStartOp[(nConstraint>1)*4 + 2 + bRev]; sqlite3VdbeAddOp4Int(v, op, iIdxCur, addrNxt, regBase, nConstraint-startEq); VdbeCoverage(v); VdbeCoverageIf(v, op==OP_Rewind); testcase( op==OP_Rewind ); VdbeCoverageIf(v, op==OP_Last); testcase( op==OP_Last ); VdbeCoverageIf(v, op==OP_SeekGE); testcase( op==OP_SeekGE ); VdbeCoverageIf(v, op==OP_SeekLE); testcase( op==OP_SeekLE ); assert( op==OP_Rewind || op==OP_Last || op==OP_SeekGE || op==OP_SeekLE); } } /* Load the value for the inequality constraint at the end of the ** range (if any). */ nConstraint = nEq; assert( pLevel->p2==0 ); if( pRangeEnd ){ Expr *pRight = pRangeEnd->pExpr->pRight; if( addrSeekScan ){ /* For a seek-scan that has a range on the lowest term of the index, ** we have to make the top of the loop be code that sets the end ** condition of the range. Otherwise, the OP_SeekScan might jump ** over that initialization, leaving the range-end value set to the ** range-start value, resulting in a wrong answer. ** See ticket 5981a8c041a3c2f3 (2021-11-02). */ pLevel->p2 = sqlite3VdbeCurrentAddr(v); } codeExprOrVector(pParse, pRight, regBase+nEq, nTop); whereLikeOptimizationStringFixup(v, pLevel, pRangeEnd); if( (pRangeEnd->wtFlags & TERM_VNULL)==0 && sqlite3ExprCanBeNull(pRight) ){ sqlite3VdbeAddOp2(v, OP_IsNull, regBase+nEq, addrNxt); VdbeCoverage(v); |
︙ | ︙ | |||
1694 1695 1696 1697 1698 1699 1700 | if( sqlite3ExprIsVector(pRight)==0 ){ disableTerm(pLevel, pRangeEnd); }else{ endEq = 1; } }else if( bStopAtNull ){ | > | | > | > > > > > > > > > > > > > > > > > > > > > > > | > | | > > < < < < < < < < < | < | > | | | > > | | | | | | > > > > > | | | | | > > > > > > > > > > > > > > > > > > | 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 | if( sqlite3ExprIsVector(pRight)==0 ){ disableTerm(pLevel, pRangeEnd); }else{ endEq = 1; } }else if( bStopAtNull ){ if( regBignull==0 ){ sqlite3VdbeAddOp2(v, OP_Null, 0, regBase+nEq); endEq = 0; } nConstraint++; } sqlite3DbFree(db, zStartAff); sqlite3DbFree(db, zEndAff); /* Top of the loop body */ if( pLevel->p2==0 ) pLevel->p2 = sqlite3VdbeCurrentAddr(v); /* Check if the index cursor is past the end of the range. */ if( nConstraint ){ if( regBignull ){ /* Except, skip the end-of-range check while doing the NULL-scan */ sqlite3VdbeAddOp2(v, OP_IfNot, regBignull, sqlite3VdbeCurrentAddr(v)+3); VdbeComment((v, "If NULL-scan 2nd pass")); VdbeCoverage(v); } op = aEndOp[bRev*2 + endEq]; sqlite3VdbeAddOp4Int(v, op, iIdxCur, addrNxt, regBase, nConstraint); testcase( op==OP_IdxGT ); VdbeCoverageIf(v, op==OP_IdxGT ); testcase( op==OP_IdxGE ); VdbeCoverageIf(v, op==OP_IdxGE ); testcase( op==OP_IdxLT ); VdbeCoverageIf(v, op==OP_IdxLT ); testcase( op==OP_IdxLE ); VdbeCoverageIf(v, op==OP_IdxLE ); if( addrSeekScan ) sqlite3VdbeJumpHere(v, addrSeekScan); } if( regBignull ){ /* During a NULL-scan, check to see if we have reached the end of ** the NULLs */ assert( bSeekPastNull==!bStopAtNull ); assert( bSeekPastNull+bStopAtNull==1 ); assert( nConstraint+bSeekPastNull>0 ); sqlite3VdbeAddOp2(v, OP_If, regBignull, sqlite3VdbeCurrentAddr(v)+2); VdbeComment((v, "If NULL-scan 1st pass")); VdbeCoverage(v); op = aEndOp[bRev*2 + bSeekPastNull]; sqlite3VdbeAddOp4Int(v, op, iIdxCur, addrNxt, regBase, nConstraint+bSeekPastNull); testcase( op==OP_IdxGT ); VdbeCoverageIf(v, op==OP_IdxGT ); testcase( op==OP_IdxGE ); VdbeCoverageIf(v, op==OP_IdxGE ); testcase( op==OP_IdxLT ); VdbeCoverageIf(v, op==OP_IdxLT ); testcase( op==OP_IdxLE ); VdbeCoverageIf(v, op==OP_IdxLE ); } if( (pLoop->wsFlags & WHERE_IN_EARLYOUT)!=0 ){ sqlite3VdbeAddOp3(v, OP_SeekHit, iIdxCur, nEq, nEq); } /* Seek the table cursor, if required */ omitTable = (pLoop->wsFlags & WHERE_IDX_ONLY)!=0 && (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)==0; if( omitTable ){ /* pIdx is a covering index. No need to access the main table. */ }else if( HasRowid(pIdx->pTable) ){ codeDeferredSeek(pWInfo, pIdx, iCur, iIdxCur); }else if( iCur!=iIdxCur ){ Index *pPk = sqlite3PrimaryKeyIndex(pIdx->pTable); iRowidReg = sqlite3GetTempRange(pParse, pPk->nKeyCol); for(j=0; j<pPk->nKeyCol; j++){ k = sqlite3TableColumnToIndex(pIdx, pPk->aiColumn[j]); sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, k, iRowidReg+j); } sqlite3VdbeAddOp4Int(v, OP_NotFound, iCur, addrCont, iRowidReg, pPk->nKeyCol); VdbeCoverage(v); } if( pLevel->iLeftJoin==0 ){ /* If pIdx is an index on one or more expressions, then look through ** all the expressions in pWInfo and try to transform matching expressions ** into reference to index columns. Also attempt to translate references ** to virtual columns in the table into references to (stored) columns ** of the index. ** ** Do not do this for the RHS of a LEFT JOIN. This is because the ** expression may be evaluated after OP_NullRow has been executed on ** the cursor. In this case it is important to do the full evaluation, ** as the result of the expression may not be NULL, even if all table ** column values are. https://www.sqlite.org/src/info/7fa8049685b50b5a ** ** Also, do not do this when processing one index an a multi-index ** OR clause, since the transformation will become invalid once we ** move forward to the next index. ** https://sqlite.org/src/info/4e8e4857d32d401f */ if( (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)==0 ){ whereIndexExprTrans(pIdx, iCur, iIdxCur, pWInfo); } /* If a partial index is driving the loop, try to eliminate WHERE clause ** terms from the query that must be true due to the WHERE clause of ** the partial index. ** ** 2019-11-02 ticket 623eff57e76d45f6: This optimization does not work ** for a LEFT JOIN. */ if( pIdx->pPartIdxWhere ){ whereApplyPartialIndexConstraints(pIdx->pPartIdxWhere, iCur, pWC); } }else{ testcase( pIdx->pPartIdxWhere ); /* The following assert() is not a requirement, merely an observation: ** The OR-optimization doesn't work for the right hand table of ** a LEFT JOIN: */ assert( (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)==0 ); } /* Record the instruction used to terminate the loop. */ if( pLoop->wsFlags & WHERE_ONEROW ){ pLevel->op = OP_Noop; }else if( bRev ){ pLevel->op = OP_Prev; }else{ pLevel->op = OP_Next; |
︙ | ︙ | |||
1829 1830 1831 1832 1833 1834 1835 | SrcList *pOrTab; /* Shortened table list or OR-clause generation */ Index *pCov = 0; /* Potential covering index (or NULL) */ int iCovCur = pParse->nTab++; /* Cursor used for index scans (if any) */ int regReturn = ++pParse->nMem; /* Register used with OP_Gosub */ int regRowset = 0; /* Register for RowSet object */ int regRowid = 0; /* Register holding rowid */ | | < | | 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 | SrcList *pOrTab; /* Shortened table list or OR-clause generation */ Index *pCov = 0; /* Potential covering index (or NULL) */ int iCovCur = pParse->nTab++; /* Cursor used for index scans (if any) */ int regReturn = ++pParse->nMem; /* Register used with OP_Gosub */ int regRowset = 0; /* Register for RowSet object */ int regRowid = 0; /* Register holding rowid */ int iLoopBody = sqlite3VdbeMakeLabel(pParse);/* Start of loop body */ int iRetInit; /* Address of regReturn init */ int untestedTerms = 0; /* Some terms not completely tested */ int ii; /* Loop counter */ Expr *pAndExpr = 0; /* An ".. AND (...)" expression */ Table *pTab = pTabItem->pTab; pTerm = pLoop->aLTerm[0]; assert( pTerm!=0 ); assert( pTerm->eOperator & WO_OR ); assert( (pTerm->wtFlags & TERM_ORINFO)!=0 ); pOrWc = &pTerm->u.pOrInfo->wc; pLevel->op = OP_Return; pLevel->p1 = regReturn; /* Set up a new SrcList in pOrTab containing the table being scanned ** by this loop in the a[0] slot and all notReady tables in a[1..] slots. ** This becomes the SrcList in the recursive call to sqlite3WhereBegin(). */ if( pWInfo->nLevel>1 ){ int nNotReady; /* The number of notReady tables */ SrcItem *origSrc; /* Original list of tables */ nNotReady = pWInfo->nLevel - iLevel - 1; pOrTab = sqlite3StackAllocRaw(db, sizeof(*pOrTab)+ nNotReady*sizeof(pOrTab->a[0])); if( pOrTab==0 ) return notReady; pOrTab->nAlloc = (u8)(nNotReady + 1); pOrTab->nSrc = pOrTab->nAlloc; memcpy(pOrTab->a, pTabItem, sizeof(*pTabItem)); |
︙ | ︙ | |||
1918 1919 1920 1921 1922 1923 1924 | if( &pWC->a[iTerm] == pTerm ) continue; testcase( pWC->a[iTerm].wtFlags & TERM_VIRTUAL ); testcase( pWC->a[iTerm].wtFlags & TERM_CODED ); if( (pWC->a[iTerm].wtFlags & (TERM_VIRTUAL|TERM_CODED))!=0 ) continue; if( (pWC->a[iTerm].eOperator & WO_ALL)==0 ) continue; testcase( pWC->a[iTerm].wtFlags & TERM_ORINFO ); pExpr = sqlite3ExprDup(db, pExpr, 0); | | > > > > > | < > | | > > > | > > > | | 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 | if( &pWC->a[iTerm] == pTerm ) continue; testcase( pWC->a[iTerm].wtFlags & TERM_VIRTUAL ); testcase( pWC->a[iTerm].wtFlags & TERM_CODED ); if( (pWC->a[iTerm].wtFlags & (TERM_VIRTUAL|TERM_CODED))!=0 ) continue; if( (pWC->a[iTerm].eOperator & WO_ALL)==0 ) continue; testcase( pWC->a[iTerm].wtFlags & TERM_ORINFO ); pExpr = sqlite3ExprDup(db, pExpr, 0); pAndExpr = sqlite3ExprAnd(pParse, pAndExpr, pExpr); } if( pAndExpr ){ /* The extra 0x10000 bit on the opcode is masked off and does not ** become part of the new Expr.op. However, it does make the ** op==TK_AND comparison inside of sqlite3PExpr() false, and this ** prevents sqlite3PExpr() from applying the AND short-circuit ** optimization, which we do not want here. */ pAndExpr = sqlite3PExpr(pParse, TK_AND|0x10000, 0, pAndExpr); } } /* Run a separate WHERE clause for each term of the OR clause. After ** eliminating duplicates from other WHERE clauses, the action for each ** sub-WHERE clause is to to invoke the main loop body as a subroutine. */ ExplainQueryPlan((pParse, 1, "MULTI-INDEX OR")); 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; /* Current OR clause term */ Expr *pDelete; /* Local copy of OR clause term */ int jmp1 = 0; /* Address of jump operation */ testcase( (pTabItem[0].fg.jointype & JT_LEFT)!=0 && !ExprHasProperty(pOrExpr, EP_FromJoin) ); /* See TH3 vtab25.400 and ticket 614b25314c766238 */ pDelete = pOrExpr = sqlite3ExprDup(db, pOrExpr, 0); if( db->mallocFailed ){ sqlite3ExprDelete(db, pDelete); continue; } if( pAndExpr ){ pAndExpr->pLeft = pOrExpr; pOrExpr = pAndExpr; } /* Loop through table entries that match term pOrTerm. */ ExplainQueryPlan((pParse, 1, "INDEX %d", ii+1)); WHERETRACE(0xffff, ("Subplan for OR-clause:\n")); pSubWInfo = sqlite3WhereBegin(pParse, pOrTab, pOrExpr, 0, 0, WHERE_OR_SUBCLAUSE, iCovCur); assert( pSubWInfo || pParse->nErr || db->mallocFailed ); if( pSubWInfo ){ WhereLoop *pSubLoop; int addrExplain = sqlite3WhereExplainOneScan( pParse, pOrTab, &pSubWInfo->a[0], 0 ); sqlite3WhereAddScanStatus(v, pOrTab, &pSubWInfo->a[0], addrExplain); |
︙ | ︙ | |||
1978 1979 1980 1981 1982 1983 1984 | int iPk; int r; /* Read the PK into an array of temp registers. */ r = sqlite3GetTempRange(pParse, nPk); for(iPk=0; iPk<nPk; iPk++){ int iCol = pPk->aiColumn[iPk]; | | | 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 | int iPk; int r; /* Read the PK into an array of temp registers. */ r = sqlite3GetTempRange(pParse, nPk); for(iPk=0; iPk<nPk; iPk++){ int iCol = pPk->aiColumn[iPk]; sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, iCol,r+iPk); } /* Check if the temp table already contains this key. If so, ** the row has already been included in the result set and ** can be ignored (by jumping past the Gosub below). Otherwise, ** insert the key into the temp table and proceed with processing ** the row. |
︙ | ︙ | |||
2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 | && (HasRowid(pTab) || !IsPrimaryKeyIndex(pSubLoop->u.btree.pIndex)) ){ assert( pSubWInfo->a[0].iIdxCur==iCovCur ); pCov = pSubLoop->u.btree.pIndex; }else{ pCov = 0; } /* Finish the loop through table entries that match term pOrTerm. */ sqlite3WhereEnd(pSubWInfo); } } } ExplainQueryPlanPop(pParse); | > > > > > > > > | | | 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 | && (HasRowid(pTab) || !IsPrimaryKeyIndex(pSubLoop->u.btree.pIndex)) ){ assert( pSubWInfo->a[0].iIdxCur==iCovCur ); pCov = pSubLoop->u.btree.pIndex; }else{ pCov = 0; } if( sqlite3WhereUsesDeferredSeek(pSubWInfo) ){ pWInfo->bDeferredSeek = 1; } /* Finish the loop through table entries that match term pOrTerm. */ sqlite3WhereEnd(pSubWInfo); ExplainQueryPlanPop(pParse); } sqlite3ExprDelete(db, pDelete); } } ExplainQueryPlanPop(pParse); assert( pLevel->pWLoop==pLoop ); assert( (pLoop->wsFlags & WHERE_MULTI_OR)!=0 ); assert( (pLoop->wsFlags & WHERE_IN_ABLE)==0 ); pLevel->u.pCoveringIdx = pCov; if( pCov ) pLevel->iIdxCur = iCovCur; if( pAndExpr ){ pAndExpr->pLeft = 0; sqlite3ExprDelete(db, pAndExpr); } sqlite3VdbeChangeP1(v, iRetInit, sqlite3VdbeCurrentAddr(v)); sqlite3VdbeGoto(v, pLevel->addrBrk); sqlite3VdbeResolveLabel(v, iLoopBody); if( pWInfo->nLevel>1 ){ sqlite3StackFree(db, pOrTab); } if( !untestedTerms ) disableTerm(pLevel, pTerm); }else #endif /* SQLITE_OMIT_OR_OPTIMIZATION */ { /* Case 6: There is no usable index. We must do a complete ** scan of the entire table. |
︙ | ︙ | |||
2149 2150 2151 2152 2153 2154 2155 2156 | ** that compares BLOBs. */ #ifdef SQLITE_LIKE_DOESNT_MATCH_BLOBS continue; #else u32 x = pLevel->iLikeRepCntr; if( x>0 ){ skipLikeAddr = sqlite3VdbeAddOp1(v, (x&1)?OP_IfNot:OP_If,(int)(x>>1)); } | > > < > > > > | 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 2458 2459 2460 | ** that compares BLOBs. */ #ifdef SQLITE_LIKE_DOESNT_MATCH_BLOBS continue; #else u32 x = pLevel->iLikeRepCntr; if( x>0 ){ skipLikeAddr = sqlite3VdbeAddOp1(v, (x&1)?OP_IfNot:OP_If,(int)(x>>1)); VdbeCoverageIf(v, (x&1)==1); VdbeCoverageIf(v, (x&1)==0); } #endif } #ifdef WHERETRACE_ENABLED /* 0xffff */ if( sqlite3WhereTrace ){ VdbeNoopComment((v, "WhereTerm[%d] (%p) priority=%d", pWC->nTerm-j, pTerm, iLoop)); } if( sqlite3WhereTrace & 0x800 ){ sqlite3DebugPrintf("Coding auxiliary constraint:\n"); sqlite3WhereTermPrint(pTerm, pWC->nTerm-j); } #endif sqlite3ExprIfFalse(pParse, pE, addrCont, SQLITE_JUMPIFNULL); if( skipLikeAddr ) sqlite3VdbeJumpHere(v, skipLikeAddr); pTerm->wtFlags |= TERM_CODED; } iLoop = iNext; }while( iLoop>0 ); |
︙ | ︙ | |||
2181 2182 2183 2184 2185 2186 2187 | for(pTerm=pWC->a, j=pWC->nTerm; j>0; j--, pTerm++){ Expr *pE, sEAlt; WhereTerm *pAlt; if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue; if( (pTerm->eOperator & (WO_EQ|WO_IS))==0 ) continue; if( (pTerm->eOperator & WO_EQUIV)==0 ) continue; if( pTerm->leftCursor!=iCur ) continue; | | > > > > > > > | | > | 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 | for(pTerm=pWC->a, j=pWC->nTerm; j>0; j--, pTerm++){ Expr *pE, sEAlt; WhereTerm *pAlt; if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue; if( (pTerm->eOperator & (WO_EQ|WO_IS))==0 ) continue; if( (pTerm->eOperator & WO_EQUIV)==0 ) continue; if( pTerm->leftCursor!=iCur ) continue; if( pTabItem->fg.jointype & JT_LEFT ) continue; pE = pTerm->pExpr; #ifdef WHERETRACE_ENABLED /* 0x800 */ if( sqlite3WhereTrace & 0x800 ){ sqlite3DebugPrintf("Coding transitive constraint:\n"); sqlite3WhereTermPrint(pTerm, pWC->nTerm-j); } #endif assert( !ExprHasProperty(pE, EP_FromJoin) ); assert( (pTerm->prereqRight & pLevel->notReady)!=0 ); assert( (pTerm->eOperator & (WO_OR|WO_AND))==0 ); pAlt = sqlite3WhereFindTerm(pWC, iCur, pTerm->u.x.leftColumn, notReady, WO_EQ|WO_IN|WO_IS, 0); if( pAlt==0 ) continue; if( pAlt->wtFlags & (TERM_CODED) ) continue; if( (pAlt->eOperator & WO_IN) && ExprUseXSelect(pAlt->pExpr) && (pAlt->pExpr->x.pSelect->pEList->nExpr>1) ){ continue; } testcase( pAlt->eOperator & WO_EQ ); testcase( pAlt->eOperator & WO_IS ); testcase( pAlt->eOperator & WO_IN ); VdbeModuleComment((v, "begin transitive constraint")); sEAlt = *pAlt->pExpr; sEAlt.pLeft = pE->pLeft; sqlite3ExprIfFalse(pParse, &sEAlt, addrCont, SQLITE_JUMPIFNULL); pAlt->wtFlags |= TERM_CODED; } /* 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); |
︙ | ︙ | |||
2225 2226 2227 2228 2229 2230 2231 2232 2233 | } assert( pTerm->pExpr ); sqlite3ExprIfFalse(pParse, pTerm->pExpr, addrCont, SQLITE_JUMPIFNULL); pTerm->wtFlags |= TERM_CODED; } } return pLevel->notReady; } | > > > > > > > > > > > | 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 | } assert( pTerm->pExpr ); sqlite3ExprIfFalse(pParse, pTerm->pExpr, addrCont, SQLITE_JUMPIFNULL); pTerm->wtFlags |= TERM_CODED; } } #if WHERETRACE_ENABLED /* 0x20800 */ if( sqlite3WhereTrace & 0x20000 ){ sqlite3DebugPrintf("All WHERE-clause terms after coding level %d:\n", iLevel); sqlite3WhereClausePrint(pWC); } if( sqlite3WhereTrace & 0x800 ){ sqlite3DebugPrintf("End Coding level %d: notReady=%llx\n", iLevel, (u64)pLevel->notReady); } #endif return pLevel->notReady; } |
Changes to src/whereexpr.c.
︙ | ︙ | |||
80 81 82 83 84 85 86 | } pTerm = &pWC->a[idx = pWC->nTerm++]; if( p && ExprHasProperty(p, EP_Unlikely) ){ pTerm->truthProb = sqlite3LogEst(p->iTable) - 270; }else{ pTerm->truthProb = 1; } | | | 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 | } pTerm = &pWC->a[idx = pWC->nTerm++]; if( p && ExprHasProperty(p, EP_Unlikely) ){ pTerm->truthProb = sqlite3LogEst(p->iTable) - 270; }else{ pTerm->truthProb = 1; } pTerm->pExpr = sqlite3ExprSkipCollateAndLikely(p); pTerm->wtFlags = wtFlags; pTerm->pWC = pWC; pTerm->iParent = -1; memset(&pTerm->eOperator, 0, sizeof(WhereTerm) - offsetof(WhereTerm,eOperator)); return idx; } |
︙ | ︙ | |||
105 106 107 108 109 110 111 | assert( TK_GE==TK_EQ+4 ); return op==TK_IN || (op>=TK_EQ && op<=TK_GE) || op==TK_ISNULL || op==TK_IS; } /* ** Commute a comparison operator. Expressions of the form "X op Y" ** are converted into "Y op X". | < < < < < < < < | < | < < < < < < | | < < < > > | < > | 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 | assert( TK_GE==TK_EQ+4 ); return op==TK_IN || (op>=TK_EQ && op<=TK_GE) || op==TK_ISNULL || op==TK_IS; } /* ** Commute a comparison operator. Expressions of the form "X op Y" ** are converted into "Y op X". */ static u16 exprCommute(Parse *pParse, Expr *pExpr){ if( pExpr->pLeft->op==TK_VECTOR || pExpr->pRight->op==TK_VECTOR || sqlite3BinaryCompareCollSeq(pParse, pExpr->pLeft, pExpr->pRight) != sqlite3BinaryCompareCollSeq(pParse, pExpr->pRight, pExpr->pLeft) ){ pExpr->flags ^= EP_Commuted; } SWAP(Expr*,pExpr->pRight,pExpr->pLeft); if( pExpr->op>=TK_GT ){ assert( TK_LT==TK_GT+2 ); assert( TK_GE==TK_LE+2 ); assert( TK_GT>TK_EQ ); assert( TK_GT<TK_LE ); assert( pExpr->op>=TK_GT && pExpr->op<=TK_GE ); pExpr->op = ((pExpr->op-TK_GT)^2)+TK_GT; } return 0; } /* ** Translate from TK_xx operator to WO_xx bitmask. */ static u16 operatorMask(int op){ u16 c; |
︙ | ︙ | |||
207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 | if( !sqlite3IsLikeFunction(db, pExpr, pnoCase, (char*)wc) ){ return 0; } #ifdef SQLITE_EBCDIC if( *pnoCase ) return 0; #endif pList = pExpr->x.pList; pLeft = pList->a[1].pExpr; pRight = sqlite3ExprSkipCollate(pList->a[0].pExpr); op = pRight->op; if( op==TK_VARIABLE && (db->flags & SQLITE_EnableQPSG)==0 ){ Vdbe *pReprepare = pParse->pReprepare; int iCol = pRight->iColumn; pVal = sqlite3VdbeGetBoundValue(pReprepare, iCol, SQLITE_AFF_BLOB); if( pVal && sqlite3_value_type(pVal)==SQLITE_TEXT ){ z = sqlite3_value_text(pVal); } sqlite3VdbeSetVarmask(pParse->pVdbe, iCol); assert( pRight->op==TK_VARIABLE || pRight->op==TK_REGISTER ); }else if( op==TK_STRING ){ | > > | | 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 | if( !sqlite3IsLikeFunction(db, pExpr, pnoCase, (char*)wc) ){ return 0; } #ifdef SQLITE_EBCDIC if( *pnoCase ) return 0; #endif assert( ExprUseXList(pExpr) ); pList = pExpr->x.pList; pLeft = pList->a[1].pExpr; pRight = sqlite3ExprSkipCollate(pList->a[0].pExpr); op = pRight->op; if( op==TK_VARIABLE && (db->flags & SQLITE_EnableQPSG)==0 ){ Vdbe *pReprepare = pParse->pReprepare; int iCol = pRight->iColumn; pVal = sqlite3VdbeGetBoundValue(pReprepare, iCol, SQLITE_AFF_BLOB); if( pVal && sqlite3_value_type(pVal)==SQLITE_TEXT ){ z = sqlite3_value_text(pVal); } sqlite3VdbeSetVarmask(pParse->pVdbe, iCol); assert( pRight->op==TK_VARIABLE || pRight->op==TK_REGISTER ); }else if( op==TK_STRING ){ assert( !ExprHasProperty(pRight, EP_IntValue) ); z = (u8*)pRight->u.zToken; } if( z ){ /* Count the number of prefix characters prior to the first wildcard */ cnt = 0; while( (c=z[cnt])!=0 && c!=wc[0] && c!=wc[1] && c!=wc[2] ){ cnt++; |
︙ | ︙ | |||
251 252 253 254 255 256 257 | /* A "complete" match if the pattern ends with "*" or "%" */ *pisComplete = c==wc[0] && z[cnt+1]==0; /* Get the pattern prefix. Remove all escapes from the prefix. */ pPrefix = sqlite3Expr(db, TK_STRING, (char*)z); if( pPrefix ){ int iFrom, iTo; | > > | > < | > | < < | > > | < | | > > < < < < | | > > | | > > > > > > > > > > > > > > | 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 | /* A "complete" match if the pattern ends with "*" or "%" */ *pisComplete = c==wc[0] && z[cnt+1]==0; /* Get the pattern prefix. Remove all escapes from the prefix. */ pPrefix = sqlite3Expr(db, TK_STRING, (char*)z); if( pPrefix ){ int iFrom, iTo; char *zNew; assert( !ExprHasProperty(pPrefix, EP_IntValue) ); zNew = pPrefix->u.zToken; zNew[cnt] = 0; for(iFrom=iTo=0; iFrom<cnt; iFrom++){ if( zNew[iFrom]==wc[3] ) iFrom++; zNew[iTo++] = zNew[iFrom]; } zNew[iTo] = 0; assert( iTo>0 ); /* If the LHS is not an ordinary column with TEXT affinity, then the ** pattern prefix boundaries (both the start and end boundaries) must ** not look like a number. Otherwise the pattern might be treated as ** a number, which will invalidate the LIKE optimization. ** ** Getting this right has been a persistent source of bugs in the ** LIKE optimization. See, for example: ** 2018-09-10 https://sqlite.org/src/info/c94369cae9b561b1 ** 2019-05-02 https://sqlite.org/src/info/b043a54c3de54b28 ** 2019-06-10 https://sqlite.org/src/info/fd76310a5e843e07 ** 2019-06-14 https://sqlite.org/src/info/ce8717f0885af975 ** 2019-09-03 https://sqlite.org/src/info/0f0428096f17252a */ if( pLeft->op!=TK_COLUMN || sqlite3ExprAffinity(pLeft)!=SQLITE_AFF_TEXT || (ALWAYS( ExprUseYTab(pLeft) ) && pLeft->y.pTab && IsVirtual(pLeft->y.pTab)) /* Might be numeric */ ){ int isNum; double rDummy; isNum = sqlite3AtoF(zNew, &rDummy, iTo, SQLITE_UTF8); if( isNum<=0 ){ if( iTo==1 && zNew[0]=='-' ){ isNum = +1; }else{ zNew[iTo-1]++; isNum = sqlite3AtoF(zNew, &rDummy, iTo, SQLITE_UTF8); zNew[iTo-1]--; } } if( isNum>0 ){ sqlite3ExprDelete(db, pPrefix); sqlite3ValueFree(pVal); return 0; } } } *ppPrefix = pPrefix; /* If the RHS pattern is a bound parameter, make arrangements to ** reprepare the statement when that parameter is rebound */ if( op==TK_VARIABLE ){ Vdbe *v = pParse->pVdbe; sqlite3VdbeSetVarmask(v, pRight->iColumn); assert( !ExprHasProperty(pRight, EP_IntValue) ); if( *pisComplete && pRight->u.zToken[1] ){ /* If the rhs of the LIKE expression is a variable, and the current ** value of the variable means there is no need to invoke the LIKE ** function, then no OP_Variable will be added to the program. ** This causes problems for the sqlite3_bind_parameter_name() ** API. To work around them, add a dummy OP_Variable here. */ |
︙ | ︙ | |||
365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 | { "like", SQLITE_INDEX_CONSTRAINT_LIKE }, { "regexp", SQLITE_INDEX_CONSTRAINT_REGEXP } }; ExprList *pList; Expr *pCol; /* Column reference */ int i; pList = pExpr->x.pList; if( pList==0 || pList->nExpr!=2 ){ return 0; } /* Built-in operators MATCH, GLOB, LIKE, and REGEXP attach to a ** virtual table on their second argument, which is the same as ** the left-hand side operand in their in-fix form. ** ** vtab_column MATCH expression ** MATCH(expression,vtab_column) */ pCol = pList->a[1].pExpr; | > > | > > > | > > | > | > > | > | 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 | { "like", SQLITE_INDEX_CONSTRAINT_LIKE }, { "regexp", SQLITE_INDEX_CONSTRAINT_REGEXP } }; ExprList *pList; Expr *pCol; /* Column reference */ int i; assert( ExprUseXList(pExpr) ); pList = pExpr->x.pList; if( pList==0 || pList->nExpr!=2 ){ return 0; } /* Built-in operators MATCH, GLOB, LIKE, and REGEXP attach to a ** virtual table on their second argument, which is the same as ** the left-hand side operand in their in-fix form. ** ** vtab_column MATCH expression ** MATCH(expression,vtab_column) */ pCol = pList->a[1].pExpr; assert( pCol->op!=TK_COLUMN || ExprUseYTab(pCol) ); testcase( pCol->op==TK_COLUMN && pCol->y.pTab==0 ); if( ExprIsVtab(pCol) ){ for(i=0; i<ArraySize(aOp); i++){ assert( !ExprHasProperty(pExpr, EP_IntValue) ); if( sqlite3StrICmp(pExpr->u.zToken, aOp[i].zOp)==0 ){ *peOp2 = aOp[i].eOp2; *ppRight = pList->a[0].pExpr; *ppLeft = pCol; return 1; } } } /* We can also match against the first column of overloaded ** functions where xFindFunction returns a value of at least ** SQLITE_INDEX_CONSTRAINT_FUNCTION. ** ** OVERLOADED(vtab_column,expression) ** ** Historically, xFindFunction expected to see lower-case function ** names. But for this use case, xFindFunction is expected to deal ** with function names in an arbitrary case. */ pCol = pList->a[0].pExpr; assert( pCol->op!=TK_COLUMN || ExprUseYTab(pCol) ); testcase( pCol->op==TK_COLUMN && pCol->y.pTab==0 ); if( ExprIsVtab(pCol) ){ sqlite3_vtab *pVtab; sqlite3_module *pMod; void (*xNotUsed)(sqlite3_context*,int,sqlite3_value**); void *pNotUsed; pVtab = sqlite3GetVTable(db, pCol->y.pTab)->pVtab; assert( pVtab!=0 ); assert( pVtab->pModule!=0 ); assert( !ExprHasProperty(pExpr, EP_IntValue) ); pMod = (sqlite3_module *)pVtab->pModule; if( pMod->xFindFunction!=0 ){ i = pMod->xFindFunction(pVtab,2, pExpr->u.zToken, &xNotUsed, &pNotUsed); if( i>=SQLITE_INDEX_CONSTRAINT_FUNCTION ){ *peOp2 = i; *ppRight = pList->a[1].pExpr; *ppLeft = pCol; return 1; } } } }else if( pExpr->op==TK_NE || pExpr->op==TK_ISNOT || pExpr->op==TK_NOTNULL ){ int res = 0; Expr *pLeft = pExpr->pLeft; Expr *pRight = pExpr->pRight; assert( pLeft->op!=TK_COLUMN || ExprUseYTab(pLeft) ); testcase( pLeft->op==TK_COLUMN && pLeft->y.pTab==0 ); if( ExprIsVtab(pLeft) ){ res++; } assert( pRight==0 || pRight->op!=TK_COLUMN || ExprUseYTab(pRight) ); testcase( pRight && pRight->op==TK_COLUMN && pRight->y.pTab==0 ); if( pRight && ExprIsVtab(pRight) ){ res++; SWAP(Expr*, pLeft, pRight); } *ppLeft = pLeft; *ppRight = pRight; if( pExpr->op==TK_NE ) *peOp2 = SQLITE_INDEX_CONSTRAINT_NE; if( pExpr->op==TK_ISNOT ) *peOp2 = SQLITE_INDEX_CONSTRAINT_ISNOT; |
︙ | ︙ | |||
508 509 510 511 512 513 514 515 516 517 518 519 520 521 | ){ u16 eOp = pOne->eOperator | pTwo->eOperator; sqlite3 *db; /* Database connection (for malloc) */ Expr *pNew; /* New virtual expression */ int op; /* Operator for the combined expression */ int idxNew; /* Index in pWC of the next virtual term */ if( (pOne->eOperator & (WO_EQ|WO_LT|WO_LE|WO_GT|WO_GE))==0 ) return; if( (pTwo->eOperator & (WO_EQ|WO_LT|WO_LE|WO_GT|WO_GE))==0 ) return; if( (eOp & (WO_EQ|WO_LT|WO_LE))!=eOp && (eOp & (WO_EQ|WO_GT|WO_GE))!=eOp ) return; assert( pOne->pExpr->pLeft!=0 && pOne->pExpr->pRight!=0 ); assert( pTwo->pExpr->pLeft!=0 && pTwo->pExpr->pRight!=0 ); if( sqlite3ExprCompare(0,pOne->pExpr->pLeft, pTwo->pExpr->pLeft, -1) ) return; | > | 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 | ){ u16 eOp = pOne->eOperator | pTwo->eOperator; sqlite3 *db; /* Database connection (for malloc) */ Expr *pNew; /* New virtual expression */ int op; /* Operator for the combined expression */ int idxNew; /* Index in pWC of the next virtual term */ if( (pOne->wtFlags | pTwo->wtFlags) & TERM_VNULL ) return; if( (pOne->eOperator & (WO_EQ|WO_LT|WO_LE|WO_GT|WO_GE))==0 ) return; if( (pTwo->eOperator & (WO_EQ|WO_LT|WO_LE|WO_GT|WO_GE))==0 ) return; if( (eOp & (WO_EQ|WO_LT|WO_LE))!=eOp && (eOp & (WO_EQ|WO_GT|WO_GE))!=eOp ) return; assert( pOne->pExpr->pLeft!=0 && pOne->pExpr->pRight!=0 ); assert( pTwo->pExpr->pLeft!=0 && pTwo->pExpr->pRight!=0 ); if( sqlite3ExprCompare(0,pOne->pExpr->pLeft, pTwo->pExpr->pLeft, -1) ) return; |
︙ | ︙ | |||
676 677 678 679 680 681 682 683 684 685 686 687 688 689 | WhereClause *pAndWC; WhereTerm *pAndTerm; int j; Bitmask b = 0; pOrTerm->u.pAndInfo = pAndInfo; pOrTerm->wtFlags |= TERM_ANDINFO; pOrTerm->eOperator = WO_AND; pAndWC = &pAndInfo->wc; memset(pAndWC->aStatic, 0, sizeof(pAndWC->aStatic)); sqlite3WhereClauseInit(pAndWC, pWC->pWInfo); sqlite3WhereSplit(pAndWC, pOrTerm->pExpr, TK_AND); sqlite3WhereExprAnalyze(pSrc, pAndWC); pAndWC->pOuter = pWC; if( !db->mallocFailed ){ | > | 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 | WhereClause *pAndWC; WhereTerm *pAndTerm; int j; Bitmask b = 0; pOrTerm->u.pAndInfo = pAndInfo; pOrTerm->wtFlags |= TERM_ANDINFO; pOrTerm->eOperator = WO_AND; pOrTerm->leftCursor = -1; pAndWC = &pAndInfo->wc; memset(pAndWC->aStatic, 0, sizeof(pAndWC->aStatic)); sqlite3WhereClauseInit(pAndWC, pWC->pWInfo); sqlite3WhereSplit(pAndWC, pOrTerm->pExpr, TK_AND); sqlite3WhereExprAnalyze(pSrc, pAndWC); pAndWC->pOuter = pWC; if( !db->mallocFailed ){ |
︙ | ︙ | |||
718 719 720 721 722 723 724 | } /* ** Record the set of tables that satisfy case 3. The set might be ** empty. */ pOrInfo->indexable = indexable; | < | > > < < | 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 | } /* ** Record the set of tables that satisfy case 3. The set might be ** empty. */ pOrInfo->indexable = indexable; pTerm->eOperator = WO_OR; pTerm->leftCursor = -1; if( indexable ){ pWC->hasOr = 1; } /* For a two-way OR, attempt to implementation case 2. */ if( indexable && pOrWc->nTerm==2 ){ int iOne = 0; WhereTerm *pOne; |
︙ | ︙ | |||
795 796 797 798 799 800 801 | ** or follwed by an inverted copy (t2.b==t1.a). Skip this term ** and use its inversion. */ testcase( pOrTerm->wtFlags & TERM_COPIED ); testcase( pOrTerm->wtFlags & TERM_VIRTUAL ); assert( pOrTerm->wtFlags & (TERM_COPIED|TERM_VIRTUAL) ); continue; } | > | > | | 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 | ** or follwed by an inverted copy (t2.b==t1.a). Skip this term ** and use its inversion. */ testcase( pOrTerm->wtFlags & TERM_COPIED ); testcase( pOrTerm->wtFlags & TERM_VIRTUAL ); assert( pOrTerm->wtFlags & (TERM_COPIED|TERM_VIRTUAL) ); continue; } assert( (pOrTerm->eOperator & (WO_OR|WO_AND))==0 ); iColumn = pOrTerm->u.x.leftColumn; iCursor = pOrTerm->leftCursor; pLeft = pOrTerm->pExpr->pLeft; break; } if( i<0 ){ /* No candidate table+column was found. This can only occur ** on the second iteration */ assert( j==1 ); assert( IsPowerOfTwo(chngToIN) ); assert( chngToIN==sqlite3WhereGetMask(&pWInfo->sMaskSet, iCursor) ); break; } testcase( j==1 ); /* We have found a candidate table and column. Check to see if that ** table and column is common to every term in the OR clause */ okToChngToIN = 1; for(; i>=0 && okToChngToIN; i--, pOrTerm++){ assert( pOrTerm->eOperator & WO_EQ ); assert( (pOrTerm->eOperator & (WO_OR|WO_AND))==0 ); if( pOrTerm->leftCursor!=iCursor ){ pOrTerm->wtFlags &= ~TERM_OR_OK; }else if( pOrTerm->u.x.leftColumn!=iColumn || (iColumn==XN_EXPR && sqlite3ExprCompare(pParse, pOrTerm->pExpr->pLeft, pLeft, -1) )){ okToChngToIN = 0; }else{ int affLeft, affRight; /* If the right-hand side is also a column, then the affinities ** of both right and left sides must be such that no type |
︙ | ︙ | |||
851 852 853 854 855 856 857 858 | ExprList *pList = 0; /* The RHS of the IN operator */ Expr *pLeft = 0; /* The LHS of the IN operator */ Expr *pNew; /* The complete IN operator */ for(i=pOrWc->nTerm-1, pOrTerm=pOrWc->a; i>=0; i--, pOrTerm++){ if( (pOrTerm->wtFlags & TERM_OR_OK)==0 ) continue; assert( pOrTerm->eOperator & WO_EQ ); assert( pOrTerm->leftCursor==iCursor ); | > | | | | 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 | ExprList *pList = 0; /* The RHS of the IN operator */ Expr *pLeft = 0; /* The LHS of the IN operator */ Expr *pNew; /* The complete IN operator */ for(i=pOrWc->nTerm-1, pOrTerm=pOrWc->a; i>=0; i--, pOrTerm++){ if( (pOrTerm->wtFlags & TERM_OR_OK)==0 ) continue; assert( pOrTerm->eOperator & WO_EQ ); assert( (pOrTerm->eOperator & (WO_OR|WO_AND))==0 ); assert( pOrTerm->leftCursor==iCursor ); assert( pOrTerm->u.x.leftColumn==iColumn ); pDup = sqlite3ExprDup(db, pOrTerm->pExpr->pRight, 0); pList = sqlite3ExprListAppend(pWInfo->pParse, pList, pDup); pLeft = pOrTerm->pExpr->pLeft; } assert( pLeft!=0 ); pDup = sqlite3ExprDup(db, pLeft, 0); pNew = sqlite3PExpr(pParse, TK_IN, pDup, 0); if( pNew ){ int idxNew; transferJoinMarkings(pNew, pExpr); assert( ExprUseXList(pNew) ); pNew->x.pList = pList; idxNew = whereClauseInsert(pWC, pNew, TERM_VIRTUAL|TERM_DYNAMIC); testcase( idxNew==0 ); exprAnalyze(pSrc, pWC, idxNew); /* pTerm = &pWC->a[idxTerm]; // would be needed if pTerm where reused */ markTermAsChild(pWC, idxNew, idxTerm); }else{ sqlite3ExprListDelete(db, pList); } } } } |
︙ | ︙ | |||
906 907 908 909 910 911 912 | aff1 = sqlite3ExprAffinity(pExpr->pLeft); aff2 = sqlite3ExprAffinity(pExpr->pRight); if( aff1!=aff2 && (!sqlite3IsNumericAffinity(aff1) || !sqlite3IsNumericAffinity(aff2)) ){ return 0; } | | | 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 | aff1 = sqlite3ExprAffinity(pExpr->pLeft); aff2 = sqlite3ExprAffinity(pExpr->pRight); if( aff1!=aff2 && (!sqlite3IsNumericAffinity(aff1) || !sqlite3IsNumericAffinity(aff2)) ){ return 0; } pColl = sqlite3ExprCompareCollSeq(pParse, pExpr); if( sqlite3IsBinary(pColl) ) return 1; return sqlite3ExprCollSeqMatch(pParse, pExpr->pLeft, pExpr->pRight); } /* ** Recursively walk the expressions of a SELECT statement and generate ** a bitmask indicating which tables are used in that expression |
︙ | ︙ | |||
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 | /* If this expression is a vector to the left or right of a ** inequality constraint (>, <, >= or <=), perform the processing ** on the first element of the vector. */ assert( TK_GT+1==TK_LE && TK_GT+2==TK_LT && TK_GT+3==TK_GE ); assert( TK_IS<TK_GE && TK_ISNULL<TK_GE && TK_IN<TK_GE ); assert( op<=TK_GE ); if( pExpr->op==TK_VECTOR && (op>=TK_GT && ALWAYS(op<=TK_GE)) ){ pExpr = pExpr->x.pList->a[0].pExpr; } if( pExpr->op==TK_COLUMN ){ aiCurCol[0] = pExpr->iTable; aiCurCol[1] = pExpr->iColumn; return 1; } if( mPrereq==0 ) return 0; /* No table references */ if( (mPrereq&(mPrereq-1))!=0 ) return 0; /* Refs more than one table */ return exprMightBeIndexed2(pFrom,mPrereq,aiCurCol,pExpr); } /* ** The input to this routine is an WhereTerm structure with only the ** "pExpr" field filled in. The job of this routine is to analyze the ** subexpression and populate all the other fields of the WhereTerm ** structure. ** | > > > | 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 | /* If this expression is a vector to the left or right of a ** inequality constraint (>, <, >= or <=), perform the processing ** on the first element of the vector. */ assert( TK_GT+1==TK_LE && TK_GT+2==TK_LT && TK_GT+3==TK_GE ); assert( TK_IS<TK_GE && TK_ISNULL<TK_GE && TK_IN<TK_GE ); assert( op<=TK_GE ); if( pExpr->op==TK_VECTOR && (op>=TK_GT && ALWAYS(op<=TK_GE)) ){ assert( ExprUseXList(pExpr) ); pExpr = pExpr->x.pList->a[0].pExpr; } if( pExpr->op==TK_COLUMN ){ aiCurCol[0] = pExpr->iTable; aiCurCol[1] = pExpr->iColumn; return 1; } if( mPrereq==0 ) return 0; /* No table references */ if( (mPrereq&(mPrereq-1))!=0 ) return 0; /* Refs more than one table */ return exprMightBeIndexed2(pFrom,mPrereq,aiCurCol,pExpr); } /* ** The input to this routine is an WhereTerm structure with only the ** "pExpr" field filled in. The job of this routine is to analyze the ** subexpression and populate all the other fields of the WhereTerm ** structure. ** |
︙ | ︙ | |||
1055 1056 1057 1058 1059 1060 1061 | pExpr = pTerm->pExpr; assert( pExpr->op!=TK_AS && pExpr->op!=TK_COLLATE ); prereqLeft = sqlite3WhereExprUsage(pMaskSet, pExpr->pLeft); op = pExpr->op; if( op==TK_IN ){ assert( pExpr->pRight==0 ); if( sqlite3ExprCheckIN(pParse, pExpr) ) return; | | | 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 | pExpr = pTerm->pExpr; assert( pExpr->op!=TK_AS && pExpr->op!=TK_COLLATE ); prereqLeft = sqlite3WhereExprUsage(pMaskSet, pExpr->pLeft); op = pExpr->op; if( op==TK_IN ){ assert( pExpr->pRight==0 ); if( sqlite3ExprCheckIN(pParse, pExpr) ) return; if( ExprUseXSelect(pExpr) ){ pTerm->prereqRight = exprSelectUsage(pMaskSet, pExpr->x.pSelect); }else{ pTerm->prereqRight = sqlite3WhereExprListUsage(pMaskSet, pExpr->x.pList); } }else if( op==TK_ISNULL ){ pTerm->prereqRight = 0; }else{ |
︙ | ︙ | |||
1088 1089 1090 1091 1092 1093 1094 | pTerm->eOperator = 0; if( allowedOp(op) ){ int aiCurCol[2]; Expr *pLeft = sqlite3ExprSkipCollate(pExpr->pLeft); Expr *pRight = sqlite3ExprSkipCollate(pExpr->pRight); u16 opMask = (pTerm->prereqRight & prereqLeft)==0 ? WO_ALL : WO_EQUIV; | | > | > | > | | 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 | pTerm->eOperator = 0; if( allowedOp(op) ){ int aiCurCol[2]; Expr *pLeft = sqlite3ExprSkipCollate(pExpr->pLeft); Expr *pRight = sqlite3ExprSkipCollate(pExpr->pRight); u16 opMask = (pTerm->prereqRight & prereqLeft)==0 ? WO_ALL : WO_EQUIV; if( pTerm->u.x.iField>0 ){ assert( op==TK_IN ); assert( pLeft->op==TK_VECTOR ); assert( ExprUseXList(pLeft) ); pLeft = pLeft->x.pList->a[pTerm->u.x.iField-1].pExpr; } if( exprMightBeIndexed(pSrc, prereqLeft, aiCurCol, pLeft, op) ){ pTerm->leftCursor = aiCurCol[0]; assert( (pTerm->eOperator & (WO_OR|WO_AND))==0 ); pTerm->u.x.leftColumn = aiCurCol[1]; pTerm->eOperator = operatorMask(op) & opMask; } if( op==TK_IS ) pTerm->wtFlags |= TERM_IS; if( pRight && exprMightBeIndexed(pSrc, pTerm->prereqRight, aiCurCol, pRight, op) && !ExprHasProperty(pRight, EP_FixedCol) ){ WhereTerm *pNew; Expr *pDup; u16 eExtraOp = 0; /* Extra bits for pNew->eOperator */ assert( pTerm->u.x.iField==0 ); if( pTerm->leftCursor>=0 ){ int idxNew; pDup = sqlite3ExprDup(db, pExpr, 0); if( db->mallocFailed ){ sqlite3ExprDelete(db, pDup); return; } |
︙ | ︙ | |||
1130 1131 1132 1133 1134 1135 1136 | pTerm->eOperator |= WO_EQUIV; eExtraOp = WO_EQUIV; } }else{ pDup = pExpr; pNew = pTerm; } | | > | > > > > > > > > > > > | > > | 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 | pTerm->eOperator |= WO_EQUIV; eExtraOp = WO_EQUIV; } }else{ pDup = pExpr; pNew = pTerm; } pNew->wtFlags |= exprCommute(pParse, pDup); pNew->leftCursor = aiCurCol[0]; assert( (pTerm->eOperator & (WO_OR|WO_AND))==0 ); pNew->u.x.leftColumn = aiCurCol[1]; testcase( (prereqLeft | extraRight) != prereqLeft ); pNew->prereqRight = prereqLeft | extraRight; pNew->prereqAll = prereqAll; pNew->eOperator = (operatorMask(pDup->op) + eExtraOp) & opMask; }else if( op==TK_ISNULL && !ExprHasProperty(pExpr,EP_FromJoin) && 0==sqlite3ExprCanBeNull(pLeft) ){ assert( !ExprHasProperty(pExpr, EP_IntValue) ); pExpr->op = TK_TRUEFALSE; pExpr->u.zToken = "false"; ExprSetProperty(pExpr, EP_IsFalse); pTerm->prereqAll = 0; pTerm->eOperator = 0; } } #ifndef SQLITE_OMIT_BETWEEN_OPTIMIZATION /* If a term is the BETWEEN operator, create two new virtual terms ** that define the range that the BETWEEN implements. For example: ** ** a BETWEEN b AND c ** ** is converted into: ** ** (a BETWEEN b AND c) AND (a>=b) AND (a<=c) ** ** The two new terms are added onto the end of the WhereClause object. ** The new terms are "dynamic" and are children of the original BETWEEN ** term. That means that if the BETWEEN term is coded, the children are ** skipped. Or, if the children are satisfied by an index, the original ** BETWEEN term is skipped. */ else if( pExpr->op==TK_BETWEEN && pWC->op==TK_AND ){ ExprList *pList; int i; static const u8 ops[] = {TK_GE, TK_LE}; assert( ExprUseXList(pExpr) ); pList = pExpr->x.pList; assert( pList!=0 ); assert( pList->nExpr==2 ); for(i=0; i<2; i++){ Expr *pNewExpr; int idxNew; pNewExpr = sqlite3PExpr(pParse, ops[i], sqlite3ExprDup(db, pExpr->pLeft, 0), |
︙ | ︙ | |||
1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 | */ else if( pExpr->op==TK_OR ){ assert( pWC->op==TK_AND ); exprAnalyzeOrTerm(pSrc, pWC, idxTerm); pTerm = &pWC->a[idxTerm]; } #endif /* SQLITE_OMIT_OR_OPTIMIZATION */ #ifndef SQLITE_OMIT_LIKE_OPTIMIZATION /* Add constraints to reduce the search space on a LIKE or GLOB ** operator. ** ** A like pattern of the form "x LIKE 'aBc%'" is changed into constraints ** ** x>='ABC' AND x<'abd' AND x LIKE 'aBc%' ** ** The last character of the prefix "abc" is incremented to form the ** termination condition "abd". If case is not significant (the default ** for LIKE) then the lower-bound is made all uppercase and the upper- ** bound is made all lowercase so that the bounds also work when comparing ** BLOBs. */ | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > | 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 | */ else if( pExpr->op==TK_OR ){ assert( pWC->op==TK_AND ); exprAnalyzeOrTerm(pSrc, pWC, idxTerm); pTerm = &pWC->a[idxTerm]; } #endif /* SQLITE_OMIT_OR_OPTIMIZATION */ /* The form "x IS NOT NULL" can sometimes be evaluated more efficiently ** as "x>NULL" if x is not an INTEGER PRIMARY KEY. So construct a ** virtual term of that form. ** ** The virtual term must be tagged with TERM_VNULL. */ else if( pExpr->op==TK_NOTNULL ){ if( pExpr->pLeft->op==TK_COLUMN && pExpr->pLeft->iColumn>=0 && !ExprHasProperty(pExpr, EP_FromJoin) ){ Expr *pNewExpr; Expr *pLeft = pExpr->pLeft; int idxNew; WhereTerm *pNewTerm; pNewExpr = sqlite3PExpr(pParse, TK_GT, sqlite3ExprDup(db, pLeft, 0), sqlite3ExprAlloc(db, TK_NULL, 0, 0)); idxNew = whereClauseInsert(pWC, pNewExpr, TERM_VIRTUAL|TERM_DYNAMIC|TERM_VNULL); if( idxNew ){ pNewTerm = &pWC->a[idxNew]; pNewTerm->prereqRight = 0; pNewTerm->leftCursor = pLeft->iTable; pNewTerm->u.x.leftColumn = pLeft->iColumn; pNewTerm->eOperator = WO_GT; markTermAsChild(pWC, idxNew, idxTerm); pTerm = &pWC->a[idxTerm]; pTerm->wtFlags |= TERM_COPIED; pNewTerm->prereqAll = pTerm->prereqAll; } } } #ifndef SQLITE_OMIT_LIKE_OPTIMIZATION /* Add constraints to reduce the search space on a LIKE or GLOB ** operator. ** ** A like pattern of the form "x LIKE 'aBc%'" is changed into constraints ** ** x>='ABC' AND x<'abd' AND x LIKE 'aBc%' ** ** The last character of the prefix "abc" is incremented to form the ** termination condition "abd". If case is not significant (the default ** for LIKE) then the lower-bound is made all uppercase and the upper- ** bound is made all lowercase so that the bounds also work when comparing ** BLOBs. */ else if( pExpr->op==TK_FUNCTION && pWC->op==TK_AND && isLikeOrGlob(pParse, pExpr, &pStr1, &isComplete, &noCase) ){ Expr *pLeft; /* LHS of LIKE/GLOB operator */ Expr *pStr2; /* Copy of pStr1 - RHS of LIKE/GLOB operator */ Expr *pNewExpr1; Expr *pNewExpr2; int idxNew1; int idxNew2; const char *zCollSeqName; /* Name of collating sequence */ const u16 wtFlags = TERM_LIKEOPT | TERM_VIRTUAL | TERM_DYNAMIC; assert( ExprUseXList(pExpr) ); pLeft = pExpr->x.pList->a[1].pExpr; pStr2 = sqlite3ExprDup(db, pStr1, 0); assert( pStr1==0 || !ExprHasProperty(pStr1, EP_IntValue) ); assert( pStr2==0 || !ExprHasProperty(pStr2, EP_IntValue) ); /* Convert the lower bound to upper-case and the upper bound to ** lower-case (upper-case is less than lower-case in ASCII) so that ** the range constraints also work for BLOBs */ if( noCase && !pParse->db->mallocFailed ){ int i; |
︙ | ︙ | |||
1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 | pTerm = &pWC->a[idxTerm]; if( isComplete ){ markTermAsChild(pWC, idxNew1, idxTerm); markTermAsChild(pWC, idxNew2, idxTerm); } } #endif /* SQLITE_OMIT_LIKE_OPTIMIZATION */ #ifndef SQLITE_OMIT_VIRTUALTABLE /* Add a WO_AUX auxiliary term to the constraint set if the ** current expression is of the form "column OP expr" where OP ** is an operator that gets passed into virtual tables but which is ** not normally optimized for ordinary tables. In other words, OP ** is one of MATCH, LIKE, GLOB, REGEXP, !=, IS, IS NOT, or NOT NULL. ** This information is used by the xBestIndex methods of ** virtual tables. The native query optimizer does not attempt ** to do anything with MATCH functions. */ | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 | pTerm = &pWC->a[idxTerm]; if( isComplete ){ markTermAsChild(pWC, idxNew1, idxTerm); markTermAsChild(pWC, idxNew2, idxTerm); } } #endif /* SQLITE_OMIT_LIKE_OPTIMIZATION */ /* If there is a vector == or IS term - e.g. "(a, b) == (?, ?)" - create ** new terms for each component comparison - "a = ?" and "b = ?". The ** new terms completely replace the original vector comparison, which is ** no longer used. ** ** This is only required if at least one side of the comparison operation ** is not a sub-select. */ if( (pExpr->op==TK_EQ || pExpr->op==TK_IS) && (nLeft = sqlite3ExprVectorSize(pExpr->pLeft))>1 && sqlite3ExprVectorSize(pExpr->pRight)==nLeft && ( (pExpr->pLeft->flags & EP_xIsSelect)==0 || (pExpr->pRight->flags & EP_xIsSelect)==0) && pWC->op==TK_AND ){ int i; for(i=0; i<nLeft; i++){ int idxNew; Expr *pNew; Expr *pLeft = sqlite3ExprForVectorField(pParse, pExpr->pLeft, i, nLeft); Expr *pRight = sqlite3ExprForVectorField(pParse, pExpr->pRight, i, nLeft); pNew = sqlite3PExpr(pParse, pExpr->op, pLeft, pRight); transferJoinMarkings(pNew, pExpr); idxNew = whereClauseInsert(pWC, pNew, TERM_DYNAMIC); exprAnalyze(pSrc, pWC, idxNew); } pTerm = &pWC->a[idxTerm]; pTerm->wtFlags |= TERM_CODED|TERM_VIRTUAL; /* Disable the original */ pTerm->eOperator = 0; } /* If there is a vector IN term - e.g. "(a, b) IN (SELECT ...)" - create ** a virtual term for each vector component. The expression object ** used by each such virtual term is pExpr (the full vector IN(...) ** expression). The WhereTerm.u.x.iField variable identifies the index within ** the vector on the LHS that the virtual term represents. ** ** This only works if the RHS is a simple SELECT (not a compound) that does ** not use window functions. */ else if( pExpr->op==TK_IN && pTerm->u.x.iField==0 && pExpr->pLeft->op==TK_VECTOR && ALWAYS( ExprUseXSelect(pExpr) ) && pExpr->x.pSelect->pPrior==0 #ifndef SQLITE_OMIT_WINDOWFUNC && pExpr->x.pSelect->pWin==0 #endif && pWC->op==TK_AND ){ int i; for(i=0; i<sqlite3ExprVectorSize(pExpr->pLeft); i++){ int idxNew; idxNew = whereClauseInsert(pWC, pExpr, TERM_VIRTUAL); pWC->a[idxNew].u.x.iField = i+1; exprAnalyze(pSrc, pWC, idxNew); markTermAsChild(pWC, idxNew, idxTerm); } } #ifndef SQLITE_OMIT_VIRTUALTABLE /* Add a WO_AUX auxiliary term to the constraint set if the ** current expression is of the form "column OP expr" where OP ** is an operator that gets passed into virtual tables but which is ** not normally optimized for ordinary tables. In other words, OP ** is one of MATCH, LIKE, GLOB, REGEXP, !=, IS, IS NOT, or NOT NULL. ** This information is used by the xBestIndex methods of ** virtual tables. The native query optimizer does not attempt ** to do anything with MATCH functions. */ else if( pWC->op==TK_AND ){ Expr *pRight = 0, *pLeft = 0; int res = isAuxiliaryVtabOperator(db, pExpr, &eOp2, &pLeft, &pRight); while( res-- > 0 ){ int idxNew; WhereTerm *pNewTerm; Bitmask prereqColumn, prereqExpr; prereqExpr = sqlite3WhereExprUsage(pMaskSet, pRight); prereqColumn = sqlite3WhereExprUsage(pMaskSet, pLeft); if( (prereqExpr & prereqColumn)==0 ){ Expr *pNewExpr; pNewExpr = sqlite3PExpr(pParse, TK_MATCH, 0, sqlite3ExprDup(db, pRight, 0)); if( ExprHasProperty(pExpr, EP_FromJoin) && pNewExpr ){ ExprSetProperty(pNewExpr, EP_FromJoin); pNewExpr->iRightJoinTable = pExpr->iRightJoinTable; } idxNew = whereClauseInsert(pWC, pNewExpr, TERM_VIRTUAL|TERM_DYNAMIC); testcase( idxNew==0 ); pNewTerm = &pWC->a[idxNew]; pNewTerm->prereqRight = prereqExpr; pNewTerm->leftCursor = pLeft->iTable; pNewTerm->u.x.leftColumn = pLeft->iColumn; pNewTerm->eOperator = WO_AUX; pNewTerm->eMatchOp = eOp2; markTermAsChild(pWC, idxNew, idxTerm); pTerm = &pWC->a[idxTerm]; pTerm->wtFlags |= TERM_COPIED; pNewTerm->prereqAll = pTerm->prereqAll; } SWAP(Expr*, pLeft, pRight); } } #endif /* SQLITE_OMIT_VIRTUALTABLE */ /* Prevent ON clause terms of a LEFT JOIN from being used to drive ** an index for tables to the left of the join. */ testcase( pTerm!=&pWC->a[idxTerm] ); pTerm = &pWC->a[idxTerm]; pTerm->prereqRight |= extraRight; } |
︙ | ︙ | |||
1441 1442 1443 1444 1445 1446 1447 | ** does is make slot[] entries point to substructure within pExpr. ** ** In the previous sentence and in the diagram, "slot[]" refers to ** the WhereClause.a[] array. The slot[] array grows as needed to contain ** all terms of the WHERE clause. */ void sqlite3WhereSplit(WhereClause *pWC, Expr *pExpr, u8 op){ | | > | 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 | ** does is make slot[] entries point to substructure within pExpr. ** ** In the previous sentence and in the diagram, "slot[]" refers to ** the WhereClause.a[] array. The slot[] array grows as needed to contain ** all terms of the WHERE clause. */ void sqlite3WhereSplit(WhereClause *pWC, Expr *pExpr, u8 op){ Expr *pE2 = sqlite3ExprSkipCollateAndLikely(pExpr); pWC->op = op; assert( pE2!=0 || pExpr==0 ); if( pE2==0 ) return; if( pE2->op!=op ){ whereClauseInsert(pWC, pExpr, 0); }else{ sqlite3WhereSplit(pWC, pE2->pLeft, op); sqlite3WhereSplit(pWC, pE2->pRight, op); } |
︙ | ︙ | |||
1510 1511 1512 1513 1514 1515 1516 | return 0; } mask = (p->op==TK_IF_NULL_ROW) ? sqlite3WhereGetMask(pMaskSet, p->iTable) : 0; if( p->pLeft ) mask |= sqlite3WhereExprUsageNN(pMaskSet, p->pLeft); if( p->pRight ){ mask |= sqlite3WhereExprUsageNN(pMaskSet, p->pRight); assert( p->x.pList==0 ); | | > > > > > > > > | 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 | return 0; } mask = (p->op==TK_IF_NULL_ROW) ? sqlite3WhereGetMask(pMaskSet, p->iTable) : 0; if( p->pLeft ) mask |= sqlite3WhereExprUsageNN(pMaskSet, p->pLeft); if( p->pRight ){ mask |= sqlite3WhereExprUsageNN(pMaskSet, p->pRight); assert( p->x.pList==0 ); }else if( ExprUseXSelect(p) ){ if( ExprHasProperty(p, EP_VarSelect) ) pMaskSet->bVarSelect = 1; mask |= exprSelectUsage(pMaskSet, p->x.pSelect); }else if( p->x.pList ){ mask |= sqlite3WhereExprListUsage(pMaskSet, p->x.pList); } #ifndef SQLITE_OMIT_WINDOWFUNC if( (p->op==TK_FUNCTION || p->op==TK_AGG_FUNCTION) && ExprUseYWin(p) ){ assert( p->y.pWin!=0 ); mask |= sqlite3WhereExprListUsage(pMaskSet, p->y.pWin->pPartition); mask |= sqlite3WhereExprListUsage(pMaskSet, p->y.pWin->pOrderBy); mask |= sqlite3WhereExprUsage(pMaskSet, p->y.pWin->pFilter); } #endif return mask; } Bitmask sqlite3WhereExprUsage(WhereMaskSet *pMaskSet, Expr *p){ return p ? sqlite3WhereExprUsageNN(pMaskSet,p) : 0; } Bitmask sqlite3WhereExprListUsage(WhereMaskSet *pMaskSet, ExprList *pList){ int i; |
︙ | ︙ | |||
1560 1561 1562 1563 1564 1565 1566 | ** new WHERE clause terms. ** ** Each function argument translates into an equality constraint against ** a HIDDEN column in the table. */ void sqlite3WhereTabFuncArgs( Parse *pParse, /* Parsing context */ | | | 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 | ** new WHERE clause terms. ** ** Each function argument translates into an equality constraint against ** a HIDDEN column in the table. */ void sqlite3WhereTabFuncArgs( Parse *pParse, /* Parsing context */ SrcItem *pItem, /* The FROM clause term to process */ WhereClause *pWC /* Xfer function arguments to here */ ){ Table *pTab; int j, k; ExprList *pArgs; Expr *pColRef; Expr *pTerm; |
︙ | ︙ | |||
1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 | pTab->zName, j); return; } pColRef = sqlite3ExprAlloc(pParse->db, TK_COLUMN, 0, 0); if( pColRef==0 ) return; pColRef->iTable = pItem->iCursor; pColRef->iColumn = k++; pColRef->y.pTab = pTab; pRhs = sqlite3PExpr(pParse, TK_UPLUS, sqlite3ExprDup(pParse->db, pArgs->a[j].pExpr, 0), 0); pTerm = sqlite3PExpr(pParse, TK_EQ, pColRef, pRhs); whereClauseInsert(pWC, pTerm, TERM_DYNAMIC); } } | > > > > | 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 | pTab->zName, j); return; } pColRef = sqlite3ExprAlloc(pParse->db, TK_COLUMN, 0, 0); if( pColRef==0 ) return; pColRef->iTable = pItem->iCursor; pColRef->iColumn = k++; assert( ExprUseYTab(pColRef) ); pColRef->y.pTab = pTab; pRhs = sqlite3PExpr(pParse, TK_UPLUS, sqlite3ExprDup(pParse->db, pArgs->a[j].pExpr, 0), 0); pTerm = sqlite3PExpr(pParse, TK_EQ, pColRef, pRhs); if( pItem->fg.jointype & JT_LEFT ){ sqlite3SetJoinExpr(pTerm, pItem->iCursor); } whereClauseInsert(pWC, pTerm, TERM_DYNAMIC); } } |
Changes to src/window.c.
︙ | ︙ | |||
194 195 196 197 198 199 200 201 202 203 204 205 206 207 | p->nValue++; p->nStep = 0; } sqlite3_result_int64(pCtx, p->nValue); } } /* ** Implementation of built-in window function rank(). Assumes that ** the window frame has been set to: ** ** RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW */ static void rankStepFunc( | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | p->nValue++; p->nStep = 0; } sqlite3_result_int64(pCtx, p->nValue); } } /* ** Implementation of built-in window function nth_value(). This ** implementation is used in "slow mode" only - when the EXCLUDE clause ** is not set to the default value "NO OTHERS". */ struct NthValueCtx { i64 nStep; sqlite3_value *pValue; }; static void nth_valueStepFunc( sqlite3_context *pCtx, int nArg, sqlite3_value **apArg ){ struct NthValueCtx *p; p = (struct NthValueCtx*)sqlite3_aggregate_context(pCtx, sizeof(*p)); if( p ){ i64 iVal; switch( sqlite3_value_numeric_type(apArg[1]) ){ case SQLITE_INTEGER: iVal = sqlite3_value_int64(apArg[1]); break; case SQLITE_FLOAT: { double fVal = sqlite3_value_double(apArg[1]); if( ((i64)fVal)!=fVal ) goto error_out; iVal = (i64)fVal; break; } default: goto error_out; } if( iVal<=0 ) goto error_out; p->nStep++; if( iVal==p->nStep ){ p->pValue = sqlite3_value_dup(apArg[0]); if( !p->pValue ){ sqlite3_result_error_nomem(pCtx); } } } UNUSED_PARAMETER(nArg); UNUSED_PARAMETER(apArg); return; error_out: sqlite3_result_error( pCtx, "second argument to nth_value must be a positive integer", -1 ); } static void nth_valueFinalizeFunc(sqlite3_context *pCtx){ struct NthValueCtx *p; p = (struct NthValueCtx*)sqlite3_aggregate_context(pCtx, 0); if( p && p->pValue ){ sqlite3_result_value(pCtx, p->pValue); sqlite3_value_free(p->pValue); p->pValue = 0; } } #define nth_valueInvFunc noopStepFunc #define nth_valueValueFunc noopValueFunc static void first_valueStepFunc( sqlite3_context *pCtx, int nArg, sqlite3_value **apArg ){ struct NthValueCtx *p; p = (struct NthValueCtx*)sqlite3_aggregate_context(pCtx, sizeof(*p)); if( p && p->pValue==0 ){ p->pValue = sqlite3_value_dup(apArg[0]); if( !p->pValue ){ sqlite3_result_error_nomem(pCtx); } } UNUSED_PARAMETER(nArg); UNUSED_PARAMETER(apArg); } static void first_valueFinalizeFunc(sqlite3_context *pCtx){ struct NthValueCtx *p; p = (struct NthValueCtx*)sqlite3_aggregate_context(pCtx, sizeof(*p)); if( p && p->pValue ){ sqlite3_result_value(pCtx, p->pValue); sqlite3_value_free(p->pValue); p->pValue = 0; } } #define first_valueInvFunc noopStepFunc #define first_valueValueFunc noopValueFunc /* ** Implementation of built-in window function rank(). Assumes that ** the window frame has been set to: ** ** RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW */ static void rankStepFunc( |
︙ | ︙ | |||
229 230 231 232 233 234 235 | } } /* ** Implementation of built-in window function percent_rank(). Assumes that ** the window frame has been set to: ** | | | | | < | < < < | < > > > > > > > > > > > | < > | | | | < | < | > > > > > > > > > > | | > | | < | > > > > > > > > > > > | | > | 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 | } } /* ** Implementation of built-in window function percent_rank(). Assumes that ** the window frame has been set to: ** ** GROUPS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING */ static void percent_rankStepFunc( sqlite3_context *pCtx, int nArg, sqlite3_value **apArg ){ struct CallCount *p; UNUSED_PARAMETER(nArg); assert( nArg==0 ); UNUSED_PARAMETER(apArg); p = (struct CallCount*)sqlite3_aggregate_context(pCtx, sizeof(*p)); if( p ){ p->nTotal++; } } static void percent_rankInvFunc( sqlite3_context *pCtx, int nArg, sqlite3_value **apArg ){ struct CallCount *p; UNUSED_PARAMETER(nArg); assert( nArg==0 ); UNUSED_PARAMETER(apArg); p = (struct CallCount*)sqlite3_aggregate_context(pCtx, sizeof(*p)); p->nStep++; } static void percent_rankValueFunc(sqlite3_context *pCtx){ struct CallCount *p; p = (struct CallCount*)sqlite3_aggregate_context(pCtx, sizeof(*p)); if( p ){ p->nValue = p->nStep; if( p->nTotal>1 ){ double r = (double)p->nValue / (double)(p->nTotal-1); sqlite3_result_double(pCtx, r); }else{ sqlite3_result_double(pCtx, 0.0); } } } #define percent_rankFinalizeFunc percent_rankValueFunc /* ** Implementation of built-in window function cume_dist(). Assumes that ** the window frame has been set to: ** ** GROUPS BETWEEN 1 FOLLOWING AND UNBOUNDED FOLLOWING */ static void cume_distStepFunc( sqlite3_context *pCtx, int nArg, sqlite3_value **apArg ){ struct CallCount *p; UNUSED_PARAMETER(nArg); assert( nArg==0 ); UNUSED_PARAMETER(apArg); p = (struct CallCount*)sqlite3_aggregate_context(pCtx, sizeof(*p)); if( p ){ p->nTotal++; } } static void cume_distInvFunc( sqlite3_context *pCtx, int nArg, sqlite3_value **apArg ){ struct CallCount *p; UNUSED_PARAMETER(nArg); assert( nArg==0 ); UNUSED_PARAMETER(apArg); p = (struct CallCount*)sqlite3_aggregate_context(pCtx, sizeof(*p)); p->nStep++; } static void cume_distValueFunc(sqlite3_context *pCtx){ struct CallCount *p; p = (struct CallCount*)sqlite3_aggregate_context(pCtx, 0); if( p ){ double r = (double)(p->nStep) / (double)(p->nTotal); sqlite3_result_double(pCtx, r); } } #define cume_distFinalizeFunc cume_distValueFunc /* ** Context object for ntile() window function. */ struct NtileCtx { i64 nTotal; /* Total rows in partition */ i64 nParam; /* Parameter passed to ntile(N) */ i64 iRow; /* Current row */ }; /* ** Implementation of ntile(). This assumes that the window frame has ** been coerced to: ** ** ROWS CURRENT ROW AND UNBOUNDED FOLLOWING */ static void ntileStepFunc( sqlite3_context *pCtx, int nArg, sqlite3_value **apArg ){ struct NtileCtx *p; assert( nArg==1 ); UNUSED_PARAMETER(nArg); p = (struct NtileCtx*)sqlite3_aggregate_context(pCtx, sizeof(*p)); if( p ){ if( p->nTotal==0 ){ p->nParam = sqlite3_value_int64(apArg[0]); if( p->nParam<=0 ){ sqlite3_result_error( pCtx, "argument of ntile must be a positive integer", -1 ); } } p->nTotal++; } } static void ntileInvFunc( sqlite3_context *pCtx, int nArg, sqlite3_value **apArg ){ struct NtileCtx *p; assert( nArg==1 ); UNUSED_PARAMETER(nArg); UNUSED_PARAMETER(apArg); p = (struct NtileCtx*)sqlite3_aggregate_context(pCtx, sizeof(*p)); p->iRow++; } static void ntileValueFunc(sqlite3_context *pCtx){ struct NtileCtx *p; p = (struct NtileCtx*)sqlite3_aggregate_context(pCtx, sizeof(*p)); if( p && p->nParam>0 ){ int nSize = (p->nTotal / p->nParam); if( nSize==0 ){ sqlite3_result_int64(pCtx, p->iRow+1); }else{ i64 nLarge = p->nTotal - p->nParam*nSize; i64 iSmall = nLarge*(nSize+1); i64 iRow = p->iRow; assert( (nLarge*(nSize+1) + (p->nParam-nLarge)*nSize)==p->nTotal ); if( iRow<iSmall ){ sqlite3_result_int64(pCtx, 1 + iRow/(nSize+1)); }else{ sqlite3_result_int64(pCtx, 1 + nLarge + (iRow-iSmall)/nSize); } } } } #define ntileFinalizeFunc ntileValueFunc /* ** Context object for last_value() window function. */ struct LastValueCtx { sqlite3_value *pVal; int nVal; |
︙ | ︙ | |||
402 403 404 405 406 407 408 | sqlite3_value_free(p->pVal); p->pVal = 0; } } } static void last_valueValueFunc(sqlite3_context *pCtx){ struct LastValueCtx *p; | | | 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 | sqlite3_value_free(p->pVal); p->pVal = 0; } } } static void last_valueValueFunc(sqlite3_context *pCtx){ struct LastValueCtx *p; p = (struct LastValueCtx*)sqlite3_aggregate_context(pCtx, 0); if( p && p->pVal ){ sqlite3_result_value(pCtx, p->pVal); } } static void last_valueFinalizeFunc(sqlite3_context *pCtx){ struct LastValueCtx *p; p = (struct LastValueCtx*)sqlite3_aggregate_context(pCtx, sizeof(*p)); |
︙ | ︙ | |||
461 462 463 464 465 466 467 | assert(0); /*NO_TEST*/ } /*NO_TEST*/ static void noopValueFunc(sqlite3_context *p){ UNUSED_PARAMETER(p); /*no-op*/ } /* Window functions that use all window interfaces: xStep, xFinal, ** xValue, and xInverse */ #define WINDOWFUNCALL(name,nArg,extra) { \ | | | | | | | | | > > > > > > > > > > > | 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 | assert(0); /*NO_TEST*/ } /*NO_TEST*/ static void noopValueFunc(sqlite3_context *p){ UNUSED_PARAMETER(p); /*no-op*/ } /* Window functions that use all window interfaces: xStep, xFinal, ** xValue, and xInverse */ #define WINDOWFUNCALL(name,nArg,extra) { \ nArg, (SQLITE_FUNC_BUILTIN|SQLITE_UTF8|SQLITE_FUNC_WINDOW|extra), 0, 0, \ name ## StepFunc, name ## FinalizeFunc, name ## ValueFunc, \ name ## InvFunc, name ## Name, {0} \ } /* Window functions that are implemented using bytecode and thus have ** no-op routines for their methods */ #define WINDOWFUNCNOOP(name,nArg,extra) { \ nArg, (SQLITE_FUNC_BUILTIN|SQLITE_UTF8|SQLITE_FUNC_WINDOW|extra), 0, 0, \ noopStepFunc, noopValueFunc, noopValueFunc, \ noopStepFunc, name ## Name, {0} \ } /* Window functions that use all window interfaces: xStep, the ** same routine for xFinalize and xValue and which never call ** xInverse. */ #define WINDOWFUNCX(name,nArg,extra) { \ nArg, (SQLITE_FUNC_BUILTIN|SQLITE_UTF8|SQLITE_FUNC_WINDOW|extra), 0, 0, \ name ## StepFunc, name ## ValueFunc, name ## ValueFunc, \ noopStepFunc, name ## Name, {0} \ } /* ** Register those built-in window functions that are not also aggregates. */ void sqlite3WindowFunctions(void){ static FuncDef aWindowFuncs[] = { WINDOWFUNCX(row_number, 0, 0), WINDOWFUNCX(dense_rank, 0, 0), WINDOWFUNCX(rank, 0, 0), WINDOWFUNCALL(percent_rank, 0, 0), WINDOWFUNCALL(cume_dist, 0, 0), WINDOWFUNCALL(ntile, 1, 0), WINDOWFUNCALL(last_value, 1, 0), WINDOWFUNCALL(nth_value, 2, 0), WINDOWFUNCALL(first_value, 1, 0), WINDOWFUNCNOOP(lead, 1, 0), WINDOWFUNCNOOP(lead, 2, 0), WINDOWFUNCNOOP(lead, 3, 0), WINDOWFUNCNOOP(lag, 1, 0), WINDOWFUNCNOOP(lag, 2, 0), WINDOWFUNCNOOP(lag, 3, 0), }; sqlite3InsertBuiltinFuncs(aWindowFuncs, ArraySize(aWindowFuncs)); } static Window *windowFind(Parse *pParse, Window *pList, const char *zName){ Window *p; for(p=pList; p; p=p->pNextWin){ if( sqlite3StrICmp(p->zName, zName)==0 ) break; } if( p==0 ){ sqlite3ErrorMsg(pParse, "no such window: %s", zName); } return p; } /* ** This function is called immediately after resolving the function name ** for a window function within a SELECT statement. Argument pList is a ** linked list of WINDOW definitions for the current SELECT statement. ** Argument pFunc is the function definition just resolved and pWin ** is the Window object representing the associated OVER clause. This |
︙ | ︙ | |||
531 532 533 534 535 536 537 | */ void sqlite3WindowUpdate( Parse *pParse, Window *pList, /* List of named windows for this SELECT */ Window *pWin, /* Window frame to update */ FuncDef *pFunc /* Window function definition */ ){ | | | < < < | < < < | > > > > > > > > > > > | > | > | | | | > > > | > > | | | > | < < | | | | | | > > > > > > > > > > | 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 | */ void sqlite3WindowUpdate( Parse *pParse, Window *pList, /* List of named windows for this SELECT */ Window *pWin, /* Window frame to update */ FuncDef *pFunc /* Window function definition */ ){ if( pWin->zName && pWin->eFrmType==0 ){ Window *p = windowFind(pParse, pList, pWin->zName); if( p==0 ) return; pWin->pPartition = sqlite3ExprListDup(pParse->db, p->pPartition, 0); pWin->pOrderBy = sqlite3ExprListDup(pParse->db, p->pOrderBy, 0); pWin->pStart = sqlite3ExprDup(pParse->db, p->pStart, 0); pWin->pEnd = sqlite3ExprDup(pParse->db, p->pEnd, 0); pWin->eStart = p->eStart; pWin->eEnd = p->eEnd; pWin->eFrmType = p->eFrmType; pWin->eExclude = p->eExclude; }else{ sqlite3WindowChain(pParse, pWin, pList); } if( (pWin->eFrmType==TK_RANGE) && (pWin->pStart || pWin->pEnd) && (pWin->pOrderBy==0 || pWin->pOrderBy->nExpr!=1) ){ sqlite3ErrorMsg(pParse, "RANGE with offset PRECEDING/FOLLOWING requires one ORDER BY expression" ); }else if( pFunc->funcFlags & SQLITE_FUNC_WINDOW ){ sqlite3 *db = pParse->db; if( pWin->pFilter ){ sqlite3ErrorMsg(pParse, "FILTER clause may only be used with aggregate window functions" ); }else{ struct WindowUpdate { const char *zFunc; int eFrmType; int eStart; int eEnd; } aUp[] = { { row_numberName, TK_ROWS, TK_UNBOUNDED, TK_CURRENT }, { dense_rankName, TK_RANGE, TK_UNBOUNDED, TK_CURRENT }, { rankName, TK_RANGE, TK_UNBOUNDED, TK_CURRENT }, { percent_rankName, TK_GROUPS, TK_CURRENT, TK_UNBOUNDED }, { cume_distName, TK_GROUPS, TK_FOLLOWING, TK_UNBOUNDED }, { ntileName, TK_ROWS, TK_CURRENT, TK_UNBOUNDED }, { leadName, TK_ROWS, TK_UNBOUNDED, TK_UNBOUNDED }, { lagName, TK_ROWS, TK_UNBOUNDED, TK_CURRENT }, }; int i; for(i=0; i<ArraySize(aUp); i++){ if( pFunc->zName==aUp[i].zFunc ){ sqlite3ExprDelete(db, pWin->pStart); sqlite3ExprDelete(db, pWin->pEnd); pWin->pEnd = pWin->pStart = 0; pWin->eFrmType = aUp[i].eFrmType; pWin->eStart = aUp[i].eStart; pWin->eEnd = aUp[i].eEnd; pWin->eExclude = 0; if( pWin->eStart==TK_FOLLOWING ){ pWin->pStart = sqlite3Expr(db, TK_INTEGER, "1"); } break; } } } } pWin->pFunc = pFunc; } /* ** Context object passed through sqlite3WalkExprList() to ** selectWindowRewriteExprCb() by selectWindowRewriteEList(). */ typedef struct WindowRewrite WindowRewrite; struct WindowRewrite { Window *pWin; SrcList *pSrc; ExprList *pSub; Table *pTab; Select *pSubSelect; /* Current sub-select, if any */ }; /* ** Callback function used by selectWindowRewriteEList(). If necessary, ** this function appends to the output expression-list and updates ** expression (*ppExpr) in place. */ static int selectWindowRewriteExprCb(Walker *pWalker, Expr *pExpr){ struct WindowRewrite *p = pWalker->u.pRewrite; Parse *pParse = pWalker->pParse; assert( p!=0 ); assert( p->pWin!=0 ); /* If this function is being called from within a scalar sub-select ** that used by the SELECT statement being processed, only process ** TK_COLUMN expressions that refer to it (the outer SELECT). Do ** not process aggregates or window functions at all, as they belong ** to the scalar sub-select. */ if( p->pSubSelect ){ |
︙ | ︙ | |||
631 632 633 634 635 636 637 | for(pWin=p->pWin; pWin; pWin=pWin->pNextWin){ if( pExpr->y.pWin==pWin ){ assert( pWin->pOwner==pExpr ); return WRC_Prune; } } } | | > > > > > > > > > > > > | > | > > | > > | | 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 | for(pWin=p->pWin; pWin; pWin=pWin->pNextWin){ if( pExpr->y.pWin==pWin ){ assert( pWin->pOwner==pExpr ); return WRC_Prune; } } } /* no break */ deliberate_fall_through case TK_AGG_FUNCTION: case TK_COLUMN: { int iCol = -1; if( pParse->db->mallocFailed ) return WRC_Abort; if( p->pSub ){ int i; for(i=0; i<p->pSub->nExpr; i++){ if( 0==sqlite3ExprCompare(0, p->pSub->a[i].pExpr, pExpr, -1) ){ iCol = i; break; } } } if( iCol<0 ){ Expr *pDup = sqlite3ExprDup(pParse->db, pExpr, 0); if( pDup && pDup->op==TK_AGG_FUNCTION ) pDup->op = TK_FUNCTION; p->pSub = sqlite3ExprListAppend(pParse, p->pSub, pDup); } if( p->pSub ){ int f = pExpr->flags & EP_Collate; assert( ExprHasProperty(pExpr, EP_Static)==0 ); ExprSetProperty(pExpr, EP_Static); sqlite3ExprDelete(pParse->db, pExpr); ExprClearProperty(pExpr, EP_Static); memset(pExpr, 0, sizeof(Expr)); pExpr->op = TK_COLUMN; pExpr->iColumn = (iCol<0 ? p->pSub->nExpr-1: iCol); pExpr->iTable = p->pWin->iEphCsr; pExpr->y.pTab = p->pTab; pExpr->flags = f; } if( pParse->db->mallocFailed ) return WRC_Abort; break; } default: /* no-op */ break; } |
︙ | ︙ | |||
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 | ** appending the new one. */ static void selectWindowRewriteEList( Parse *pParse, Window *pWin, SrcList *pSrc, ExprList *pEList, /* Rewrite expressions in this list */ ExprList **ppSub /* IN/OUT: Sub-select expression-list */ ){ Walker sWalker; WindowRewrite sRewrite; memset(&sWalker, 0, sizeof(Walker)); memset(&sRewrite, 0, sizeof(WindowRewrite)); sRewrite.pSub = *ppSub; sRewrite.pWin = pWin; sRewrite.pSrc = pSrc; sWalker.pParse = pParse; sWalker.xExprCallback = selectWindowRewriteExprCb; sWalker.xSelectCallback = selectWindowRewriteSelectCb; sWalker.u.pRewrite = &sRewrite; (void)sqlite3WalkExprList(&sWalker, pEList); *ppSub = sRewrite.pSub; } /* ** Append a copy of each expression in expression-list pAppend to ** expression list pList. Return a pointer to the result list. */ static ExprList *exprListAppendList( Parse *pParse, /* Parsing context */ ExprList *pList, /* List to which to append. Might be NULL */ | > > > | > > | > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > | | > > > > > > > > > > > > > > > > > > | | | > > > > | | | | > > > > > | > > > | > | > > > | | > > > > | > > > > > > | | > > > > > | < < | > > > > | > > > > > > > > > > > > > > > > > > > > > | 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 | ** appending the new one. */ static void selectWindowRewriteEList( Parse *pParse, Window *pWin, SrcList *pSrc, ExprList *pEList, /* Rewrite expressions in this list */ Table *pTab, ExprList **ppSub /* IN/OUT: Sub-select expression-list */ ){ Walker sWalker; WindowRewrite sRewrite; assert( pWin!=0 ); memset(&sWalker, 0, sizeof(Walker)); memset(&sRewrite, 0, sizeof(WindowRewrite)); sRewrite.pSub = *ppSub; sRewrite.pWin = pWin; sRewrite.pSrc = pSrc; sRewrite.pTab = pTab; sWalker.pParse = pParse; sWalker.xExprCallback = selectWindowRewriteExprCb; sWalker.xSelectCallback = selectWindowRewriteSelectCb; sWalker.u.pRewrite = &sRewrite; (void)sqlite3WalkExprList(&sWalker, pEList); *ppSub = sRewrite.pSub; } /* ** Append a copy of each expression in expression-list pAppend to ** expression list pList. Return a pointer to the result list. */ static ExprList *exprListAppendList( Parse *pParse, /* Parsing context */ ExprList *pList, /* List to which to append. Might be NULL */ ExprList *pAppend, /* List of values to append. Might be NULL */ int bIntToNull ){ if( pAppend ){ int i; int nInit = pList ? pList->nExpr : 0; for(i=0; i<pAppend->nExpr; i++){ sqlite3 *db = pParse->db; Expr *pDup = sqlite3ExprDup(db, pAppend->a[i].pExpr, 0); assert( pDup==0 || !ExprHasProperty(pDup, EP_MemToken) ); if( db->mallocFailed ){ sqlite3ExprDelete(db, pDup); break; } if( bIntToNull ){ int iDummy; Expr *pSub; pSub = sqlite3ExprSkipCollateAndLikely(pDup); if( sqlite3ExprIsInteger(pSub, &iDummy) ){ pSub->op = TK_NULL; pSub->flags &= ~(EP_IntValue|EP_IsTrue|EP_IsFalse); pSub->u.zToken = 0; } } pList = sqlite3ExprListAppend(pParse, pList, pDup); if( pList ) pList->a[nInit+i].sortFlags = pAppend->a[i].sortFlags; } } return pList; } /* ** When rewriting a query, if the new subquery in the FROM clause ** contains TK_AGG_FUNCTION nodes that refer to an outer query, ** then we have to increase the Expr->op2 values of those nodes ** due to the extra subquery layer that was added. ** ** See also the incrAggDepth() routine in resolve.c */ static int sqlite3WindowExtraAggFuncDepth(Walker *pWalker, Expr *pExpr){ if( pExpr->op==TK_AGG_FUNCTION && pExpr->op2>=pWalker->walkerDepth ){ pExpr->op2++; } return WRC_Continue; } static int disallowAggregatesInOrderByCb(Walker *pWalker, Expr *pExpr){ if( pExpr->op==TK_AGG_FUNCTION && pExpr->pAggInfo==0 ){ assert( !ExprHasProperty(pExpr, EP_IntValue) ); sqlite3ErrorMsg(pWalker->pParse, "misuse of aggregate: %s()", pExpr->u.zToken); } return WRC_Continue; } /* ** If the SELECT statement passed as the second argument does not invoke ** any SQL window functions, this function is a no-op. Otherwise, it ** rewrites the SELECT statement so that window function xStep functions ** are invoked in the correct order as described under "SELECT REWRITING" ** at the top of this file. */ int sqlite3WindowRewrite(Parse *pParse, Select *p){ int rc = SQLITE_OK; if( p->pWin && p->pPrior==0 && ALWAYS((p->selFlags & SF_WinRewrite)==0) ){ Vdbe *v = sqlite3GetVdbe(pParse); sqlite3 *db = pParse->db; Select *pSub = 0; /* The subquery */ SrcList *pSrc = p->pSrc; Expr *pWhere = p->pWhere; ExprList *pGroupBy = p->pGroupBy; Expr *pHaving = p->pHaving; ExprList *pSort = 0; ExprList *pSublist = 0; /* Expression list for sub-query */ Window *pMWin = p->pWin; /* Main window object */ Window *pWin; /* Window object iterator */ Table *pTab; Walker w; u32 selFlags = p->selFlags; pTab = sqlite3DbMallocZero(db, sizeof(Table)); if( pTab==0 ){ return sqlite3ErrorToParser(db, SQLITE_NOMEM); } sqlite3AggInfoPersistWalkerInit(&w, pParse); sqlite3WalkSelect(&w, p); if( (p->selFlags & SF_Aggregate)==0 ){ w.xExprCallback = disallowAggregatesInOrderByCb; w.xSelectCallback = 0; sqlite3WalkExprList(&w, p->pOrderBy); } p->pSrc = 0; p->pWhere = 0; p->pGroupBy = 0; p->pHaving = 0; p->selFlags &= ~SF_Aggregate; p->selFlags |= SF_WinRewrite; /* Create the ORDER BY clause for the sub-select. This is the concatenation ** of the window PARTITION and ORDER BY clauses. Then, if this makes it ** redundant, remove the ORDER BY from the parent SELECT. */ pSort = exprListAppendList(pParse, 0, pMWin->pPartition, 1); pSort = exprListAppendList(pParse, pSort, pMWin->pOrderBy, 1); if( pSort && p->pOrderBy && p->pOrderBy->nExpr<=pSort->nExpr ){ int nSave = pSort->nExpr; pSort->nExpr = p->pOrderBy->nExpr; if( sqlite3ExprListCompare(pSort, p->pOrderBy, -1)==0 ){ sqlite3ExprListDelete(db, p->pOrderBy); p->pOrderBy = 0; } pSort->nExpr = nSave; } /* Assign a cursor number for the ephemeral table used to buffer rows. ** The OpenEphemeral instruction is coded later, after it is known how ** many columns the table will have. */ pMWin->iEphCsr = pParse->nTab++; pParse->nTab += 3; selectWindowRewriteEList(pParse, pMWin, pSrc, p->pEList, pTab, &pSublist); selectWindowRewriteEList(pParse, pMWin, pSrc, p->pOrderBy, pTab, &pSublist); pMWin->nBufferCol = (pSublist ? pSublist->nExpr : 0); /* Append the PARTITION BY and ORDER BY expressions to the to the ** sub-select expression list. They are required to figure out where ** boundaries for partitions and sets of peer rows lie. */ pSublist = exprListAppendList(pParse, pSublist, pMWin->pPartition, 0); pSublist = exprListAppendList(pParse, pSublist, pMWin->pOrderBy, 0); /* Append the arguments passed to each window function to the ** sub-select expression list. Also allocate two registers for each ** window function - one for the accumulator, another for interim ** results. */ for(pWin=pMWin; pWin; pWin=pWin->pNextWin){ ExprList *pArgs; assert( ExprUseXList(pWin->pOwner) ); pArgs = pWin->pOwner->x.pList; if( pWin->pFunc->funcFlags & SQLITE_FUNC_SUBTYPE ){ selectWindowRewriteEList(pParse, pMWin, pSrc, pArgs, pTab, &pSublist); pWin->iArgCol = (pSublist ? pSublist->nExpr : 0); pWin->bExprArgs = 1; }else{ pWin->iArgCol = (pSublist ? pSublist->nExpr : 0); pSublist = exprListAppendList(pParse, pSublist, pArgs, 0); } if( pWin->pFilter ){ Expr *pFilter = sqlite3ExprDup(db, pWin->pFilter, 0); pSublist = sqlite3ExprListAppend(pParse, pSublist, pFilter); } pWin->regAccum = ++pParse->nMem; pWin->regResult = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_Null, 0, pWin->regAccum); } /* If there is no ORDER BY or PARTITION BY clause, and the window ** function accepts zero arguments, and there are no other columns ** selected (e.g. "SELECT row_number() OVER () FROM t1"), it is possible ** that pSublist is still NULL here. Add a constant expression here to ** keep everything legal in this case. */ if( pSublist==0 ){ pSublist = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(db, TK_INTEGER, "0") ); } pSub = sqlite3SelectNew( pParse, pSublist, pSrc, pWhere, pGroupBy, pHaving, pSort, 0, 0 ); SELECTTRACE(1,pParse,pSub, ("New window-function subquery in FROM clause of (%u/%p)\n", p->selId, p)); p->pSrc = sqlite3SrcListAppend(pParse, 0, 0, 0); assert( pSub!=0 || p->pSrc==0 ); /* Due to db->mallocFailed test inside ** of sqlite3DbMallocRawNN() called from ** sqlite3SrcListAppend() */ if( p->pSrc ){ Table *pTab2; p->pSrc->a[0].pSelect = pSub; sqlite3SrcListAssignCursors(pParse, p->pSrc); pSub->selFlags |= SF_Expanded|SF_OrderByReqd; pTab2 = sqlite3ResultSetOfSelect(pParse, pSub, SQLITE_AFF_NONE); pSub->selFlags |= (selFlags & SF_Aggregate); if( pTab2==0 ){ /* Might actually be some other kind of error, but in that case ** pParse->nErr will be set, so if SQLITE_NOMEM is set, we will get ** the correct error message regardless. */ rc = SQLITE_NOMEM; }else{ memcpy(pTab, pTab2, sizeof(Table)); pTab->tabFlags |= TF_Ephemeral; p->pSrc->a[0].pTab = pTab; pTab = pTab2; memset(&w, 0, sizeof(w)); w.xExprCallback = sqlite3WindowExtraAggFuncDepth; w.xSelectCallback = sqlite3WalkerDepthIncrease; w.xSelectCallback2 = sqlite3WalkerDepthDecrease; sqlite3WalkSelect(&w, pSub); } }else{ sqlite3SelectDelete(db, pSub); } if( db->mallocFailed ) rc = SQLITE_NOMEM; /* Defer deleting the temporary table pTab because if an error occurred, ** there could still be references to that table embedded in the ** result-set or ORDER BY clause of the SELECT statement p. */ sqlite3ParserAddCleanup(pParse, sqlite3DbFree, pTab); } if( rc ){ if( pParse->nErr==0 ){ assert( pParse->db->mallocFailed ); sqlite3ErrorToParser(pParse->db, SQLITE_NOMEM); } } return rc; } /* ** Unlink the Window object from the Select to which it is attached, ** if it is attached. */ void sqlite3WindowUnlinkFromSelect(Window *p){ if( p->ppThis ){ *p->ppThis = p->pNextWin; if( p->pNextWin ) p->pNextWin->ppThis = p->ppThis; p->ppThis = 0; } } /* ** Free the Window object passed as the second argument. */ void sqlite3WindowDelete(sqlite3 *db, Window *p){ if( p ){ sqlite3WindowUnlinkFromSelect(p); sqlite3ExprDelete(db, p->pFilter); sqlite3ExprListDelete(db, p->pPartition); sqlite3ExprListDelete(db, p->pOrderBy); sqlite3ExprDelete(db, p->pEnd); sqlite3ExprDelete(db, p->pStart); sqlite3DbFree(db, p->zName); sqlite3DbFree(db, p->zBase); sqlite3DbFree(db, p); } } /* ** Free the linked list of Window objects starting at the second argument. */ |
︙ | ︙ | |||
877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 | ** value should be a non-negative integer. If the value is not a ** constant, change it to NULL. The fact that it is then a non-negative ** integer will be caught later. But it is important not to leave ** variable values in the expression tree. */ static Expr *sqlite3WindowOffsetExpr(Parse *pParse, Expr *pExpr){ if( 0==sqlite3ExprIsConstant(pExpr) ){ sqlite3ExprDelete(pParse->db, pExpr); pExpr = sqlite3ExprAlloc(pParse->db, TK_NULL, 0, 0); } return pExpr; } /* ** Allocate and return a new Window object describing a Window Definition. */ Window *sqlite3WindowAlloc( Parse *pParse, /* Parsing context */ | > | | > > | | | < < | < < | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > < < < | | | | | | | < > > > > > > > > > > > > > > > > > > > > > > > > | > | | > > > > > > > | > | > > | > > > > > > > | > > | > > > > | > > | > | | > > > > > > > > > > > > > > > > | | | | < < > > > > > > | | > > | | > > > > > > > > > > | > > | | | > > | | > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 | ** value should be a non-negative integer. If the value is not a ** constant, change it to NULL. The fact that it is then a non-negative ** integer will be caught later. But it is important not to leave ** variable values in the expression tree. */ static Expr *sqlite3WindowOffsetExpr(Parse *pParse, Expr *pExpr){ if( 0==sqlite3ExprIsConstant(pExpr) ){ if( IN_RENAME_OBJECT ) sqlite3RenameExprUnmap(pParse, pExpr); sqlite3ExprDelete(pParse->db, pExpr); pExpr = sqlite3ExprAlloc(pParse->db, TK_NULL, 0, 0); } return pExpr; } /* ** Allocate and return a new Window object describing a Window Definition. */ Window *sqlite3WindowAlloc( Parse *pParse, /* Parsing context */ int eType, /* Frame type. TK_RANGE, TK_ROWS, TK_GROUPS, or 0 */ int eStart, /* Start type: CURRENT, PRECEDING, FOLLOWING, UNBOUNDED */ Expr *pStart, /* Start window size if TK_PRECEDING or FOLLOWING */ int eEnd, /* End type: CURRENT, FOLLOWING, TK_UNBOUNDED, PRECEDING */ Expr *pEnd, /* End window size if TK_FOLLOWING or PRECEDING */ u8 eExclude /* EXCLUDE clause */ ){ Window *pWin = 0; int bImplicitFrame = 0; /* Parser assures the following: */ assert( eType==0 || eType==TK_RANGE || eType==TK_ROWS || eType==TK_GROUPS ); assert( eStart==TK_CURRENT || eStart==TK_PRECEDING || eStart==TK_UNBOUNDED || eStart==TK_FOLLOWING ); assert( eEnd==TK_CURRENT || eEnd==TK_FOLLOWING || eEnd==TK_UNBOUNDED || eEnd==TK_PRECEDING ); assert( (eStart==TK_PRECEDING || eStart==TK_FOLLOWING)==(pStart!=0) ); assert( (eEnd==TK_FOLLOWING || eEnd==TK_PRECEDING)==(pEnd!=0) ); if( eType==0 ){ bImplicitFrame = 1; eType = TK_RANGE; } /* Additionally, the ** starting boundary type may not occur earlier in the following list than ** the ending boundary type: ** ** UNBOUNDED PRECEDING ** <expr> PRECEDING ** CURRENT ROW ** <expr> FOLLOWING ** UNBOUNDED FOLLOWING ** ** The parser ensures that "UNBOUNDED PRECEDING" cannot be used as an ending ** boundary, and than "UNBOUNDED FOLLOWING" cannot be used as a starting ** frame boundary. */ if( (eStart==TK_CURRENT && eEnd==TK_PRECEDING) || (eStart==TK_FOLLOWING && (eEnd==TK_PRECEDING || eEnd==TK_CURRENT)) ){ sqlite3ErrorMsg(pParse, "unsupported frame specification"); goto windowAllocErr; } pWin = (Window*)sqlite3DbMallocZero(pParse->db, sizeof(Window)); if( pWin==0 ) goto windowAllocErr; pWin->eFrmType = eType; pWin->eStart = eStart; pWin->eEnd = eEnd; if( eExclude==0 && OptimizationDisabled(pParse->db, SQLITE_WindowFunc) ){ eExclude = TK_NO; } pWin->eExclude = eExclude; pWin->bImplicitFrame = bImplicitFrame; pWin->pEnd = sqlite3WindowOffsetExpr(pParse, pEnd); pWin->pStart = sqlite3WindowOffsetExpr(pParse, pStart); return pWin; windowAllocErr: sqlite3ExprDelete(pParse->db, pEnd); sqlite3ExprDelete(pParse->db, pStart); return 0; } /* ** Attach PARTITION and ORDER BY clauses pPartition and pOrderBy to window ** pWin. Also, if parameter pBase is not NULL, set pWin->zBase to the ** equivalent nul-terminated string. */ Window *sqlite3WindowAssemble( Parse *pParse, Window *pWin, ExprList *pPartition, ExprList *pOrderBy, Token *pBase ){ if( pWin ){ pWin->pPartition = pPartition; pWin->pOrderBy = pOrderBy; if( pBase ){ pWin->zBase = sqlite3DbStrNDup(pParse->db, pBase->z, pBase->n); } }else{ sqlite3ExprListDelete(pParse->db, pPartition); sqlite3ExprListDelete(pParse->db, pOrderBy); } return pWin; } /* ** Window *pWin has just been created from a WINDOW clause. Tokne pBase ** is the base window. Earlier windows from the same WINDOW clause are ** stored in the linked list starting at pWin->pNextWin. This function ** either updates *pWin according to the base specification, or else ** leaves an error in pParse. */ void sqlite3WindowChain(Parse *pParse, Window *pWin, Window *pList){ if( pWin->zBase ){ sqlite3 *db = pParse->db; Window *pExist = windowFind(pParse, pList, pWin->zBase); if( pExist ){ const char *zErr = 0; /* Check for errors */ if( pWin->pPartition ){ zErr = "PARTITION clause"; }else if( pExist->pOrderBy && pWin->pOrderBy ){ zErr = "ORDER BY clause"; }else if( pExist->bImplicitFrame==0 ){ zErr = "frame specification"; } if( zErr ){ sqlite3ErrorMsg(pParse, "cannot override %s of window: %s", zErr, pWin->zBase ); }else{ pWin->pPartition = sqlite3ExprListDup(db, pExist->pPartition, 0); if( pExist->pOrderBy ){ assert( pWin->pOrderBy==0 ); pWin->pOrderBy = sqlite3ExprListDup(db, pExist->pOrderBy, 0); } sqlite3DbFree(db, pWin->zBase); pWin->zBase = 0; } } } } /* ** Attach window object pWin to expression p. */ void sqlite3WindowAttach(Parse *pParse, Expr *p, Window *pWin){ if( p ){ assert( p->op==TK_FUNCTION ); assert( pWin ); p->y.pWin = pWin; ExprSetProperty(p, EP_WinFunc); pWin->pOwner = p; if( (p->flags & EP_Distinct) && pWin->eFrmType!=TK_FILTER ){ sqlite3ErrorMsg(pParse, "DISTINCT is not supported for window functions" ); } }else{ sqlite3WindowDelete(pParse->db, pWin); } } /* ** Possibly link window pWin into the list at pSel->pWin (window functions ** to be processed as part of SELECT statement pSel). The window is linked ** in if either (a) there are no other windows already linked to this ** SELECT, or (b) the windows already linked use a compatible window frame. */ void sqlite3WindowLink(Select *pSel, Window *pWin){ if( pSel ){ if( 0==pSel->pWin || 0==sqlite3WindowCompare(0, pSel->pWin, pWin, 0) ){ pWin->pNextWin = pSel->pWin; if( pSel->pWin ){ pSel->pWin->ppThis = &pWin->pNextWin; } pSel->pWin = pWin; pWin->ppThis = &pSel->pWin; }else{ if( sqlite3ExprListCompare(pWin->pPartition, pSel->pWin->pPartition,-1) ){ pSel->selFlags |= SF_MultiPart; } } } } /* ** Return 0 if the two window objects are identical, 1 if they are ** different, or 2 if it cannot be determined if the objects are identical ** or not. Identical window objects can be processed in a single scan. */ int sqlite3WindowCompare( const Parse *pParse, const Window *p1, const Window *p2, int bFilter ){ int res; if( NEVER(p1==0) || NEVER(p2==0) ) return 1; if( p1->eFrmType!=p2->eFrmType ) return 1; if( p1->eStart!=p2->eStart ) return 1; if( p1->eEnd!=p2->eEnd ) return 1; if( p1->eExclude!=p2->eExclude ) return 1; if( sqlite3ExprCompare(pParse, p1->pStart, p2->pStart, -1) ) return 1; if( sqlite3ExprCompare(pParse, p1->pEnd, p2->pEnd, -1) ) return 1; if( (res = sqlite3ExprListCompare(p1->pPartition, p2->pPartition, -1)) ){ return res; } if( (res = sqlite3ExprListCompare(p1->pOrderBy, p2->pOrderBy, -1)) ){ return res; } if( bFilter ){ if( (res = sqlite3ExprCompare(pParse, p1->pFilter, p2->pFilter, -1)) ){ return res; } } return 0; } /* ** This is called by code in select.c before it calls sqlite3WhereBegin() ** to begin iterating through the sub-query results. It is used to allocate ** and initialize registers and cursors used by sqlite3WindowCodeStep(). */ void sqlite3WindowCodeInit(Parse *pParse, Select *pSelect){ int nEphExpr = pSelect->pSrc->a[0].pSelect->pEList->nExpr; Window *pMWin = pSelect->pWin; Window *pWin; Vdbe *v = sqlite3GetVdbe(pParse); sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pMWin->iEphCsr, nEphExpr); sqlite3VdbeAddOp2(v, OP_OpenDup, pMWin->iEphCsr+1, pMWin->iEphCsr); sqlite3VdbeAddOp2(v, OP_OpenDup, pMWin->iEphCsr+2, pMWin->iEphCsr); sqlite3VdbeAddOp2(v, OP_OpenDup, pMWin->iEphCsr+3, pMWin->iEphCsr); /* Allocate registers to use for PARTITION BY values, if any. Initialize ** said registers to NULL. */ if( pMWin->pPartition ){ int nExpr = pMWin->pPartition->nExpr; pMWin->regPart = pParse->nMem+1; pParse->nMem += nExpr; sqlite3VdbeAddOp3(v, OP_Null, 0, pMWin->regPart, pMWin->regPart+nExpr-1); } pMWin->regOne = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_Integer, 1, pMWin->regOne); if( pMWin->eExclude ){ pMWin->regStartRowid = ++pParse->nMem; pMWin->regEndRowid = ++pParse->nMem; pMWin->csrApp = pParse->nTab++; sqlite3VdbeAddOp2(v, OP_Integer, 1, pMWin->regStartRowid); sqlite3VdbeAddOp2(v, OP_Integer, 0, pMWin->regEndRowid); sqlite3VdbeAddOp2(v, OP_OpenDup, pMWin->csrApp, pMWin->iEphCsr); return; } for(pWin=pMWin; pWin; pWin=pWin->pNextWin){ FuncDef *p = pWin->pFunc; if( (p->funcFlags & SQLITE_FUNC_MINMAX) && pWin->eStart!=TK_UNBOUNDED ){ /* The inline versions of min() and max() require a single ephemeral ** table and 3 registers. The registers are used as follows: ** ** regApp+0: slot to copy min()/max() argument to for MakeRecord ** regApp+1: integer value used to ensure keys are unique ** regApp+2: output of MakeRecord */ ExprList *pList; KeyInfo *pKeyInfo; assert( ExprUseXList(pWin->pOwner) ); pList = pWin->pOwner->x.pList; pKeyInfo = sqlite3KeyInfoFromExprList(pParse, pList, 0, 0); pWin->csrApp = pParse->nTab++; pWin->regApp = pParse->nMem+1; pParse->nMem += 3; if( pKeyInfo && pWin->pFunc->zName[1]=='i' ){ assert( pKeyInfo->aSortFlags[0]==0 ); pKeyInfo->aSortFlags[0] = KEYINFO_ORDER_DESC; } sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pWin->csrApp, 2); sqlite3VdbeAppendP4(v, pKeyInfo, P4_KEYINFO); sqlite3VdbeAddOp2(v, OP_Integer, 0, pWin->regApp+1); } else if( p->zName==nth_valueName || p->zName==first_valueName ){ /* Allocate two registers at pWin->regApp. These will be used to ** store the start and end index of the current frame. */ pWin->regApp = pParse->nMem+1; pWin->csrApp = pParse->nTab++; pParse->nMem += 2; sqlite3VdbeAddOp2(v, OP_OpenDup, pWin->csrApp, pMWin->iEphCsr); } else if( p->zName==leadName || p->zName==lagName ){ pWin->csrApp = pParse->nTab++; sqlite3VdbeAddOp2(v, OP_OpenDup, pWin->csrApp, pMWin->iEphCsr); } } } #define WINDOW_STARTING_INT 0 #define WINDOW_ENDING_INT 1 #define WINDOW_NTH_VALUE_INT 2 #define WINDOW_STARTING_NUM 3 #define WINDOW_ENDING_NUM 4 /* ** A "PRECEDING <expr>" (eCond==0) or "FOLLOWING <expr>" (eCond==1) or the ** value of the second argument to nth_value() (eCond==2) has just been ** evaluated and the result left in register reg. This function generates VM ** code to check that the value is a non-negative integer and throws an ** exception if it is not. */ static void windowCheckValue(Parse *pParse, int reg, int eCond){ static const char *azErr[] = { "frame starting offset must be a non-negative integer", "frame ending offset must be a non-negative integer", "second argument to nth_value must be a positive integer", "frame starting offset must be a non-negative number", "frame ending offset must be a non-negative number", }; static int aOp[] = { OP_Ge, OP_Ge, OP_Gt, OP_Ge, OP_Ge }; Vdbe *v = sqlite3GetVdbe(pParse); int regZero = sqlite3GetTempReg(pParse); assert( eCond>=0 && eCond<ArraySize(azErr) ); sqlite3VdbeAddOp2(v, OP_Integer, 0, regZero); if( eCond>=WINDOW_STARTING_NUM ){ int regString = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp4(v, OP_String8, 0, regString, 0, "", P4_STATIC); sqlite3VdbeAddOp3(v, OP_Ge, regString, sqlite3VdbeCurrentAddr(v)+2, reg); sqlite3VdbeChangeP5(v, SQLITE_AFF_NUMERIC|SQLITE_JUMPIFNULL); VdbeCoverage(v); assert( eCond==3 || eCond==4 ); VdbeCoverageIf(v, eCond==3); VdbeCoverageIf(v, eCond==4); }else{ sqlite3VdbeAddOp2(v, OP_MustBeInt, reg, sqlite3VdbeCurrentAddr(v)+2); VdbeCoverage(v); assert( eCond==0 || eCond==1 || eCond==2 ); VdbeCoverageIf(v, eCond==0); VdbeCoverageIf(v, eCond==1); VdbeCoverageIf(v, eCond==2); } sqlite3VdbeAddOp3(v, aOp[eCond], regZero, sqlite3VdbeCurrentAddr(v)+2, reg); sqlite3VdbeChangeP5(v, SQLITE_AFF_NUMERIC); VdbeCoverageNeverNullIf(v, eCond==0); /* NULL case captured by */ VdbeCoverageNeverNullIf(v, eCond==1); /* the OP_MustBeInt */ VdbeCoverageNeverNullIf(v, eCond==2); VdbeCoverageNeverNullIf(v, eCond==3); /* NULL case caught by */ VdbeCoverageNeverNullIf(v, eCond==4); /* the OP_Ge */ sqlite3MayAbort(pParse); sqlite3VdbeAddOp2(v, OP_Halt, SQLITE_ERROR, OE_Abort); sqlite3VdbeAppendP4(v, (void*)azErr[eCond], P4_STATIC); sqlite3ReleaseTempReg(pParse, regZero); } /* ** Return the number of arguments passed to the window-function associated ** with the object passed as the only argument to this function. */ static int windowArgCount(Window *pWin){ const ExprList *pList; assert( ExprUseXList(pWin->pOwner) ); pList = pWin->pOwner->x.pList; return (pList ? pList->nExpr : 0); } typedef struct WindowCodeArg WindowCodeArg; typedef struct WindowCsrAndReg WindowCsrAndReg; /* ** See comments above struct WindowCodeArg. */ struct WindowCsrAndReg { int csr; /* Cursor number */ int reg; /* First in array of peer values */ }; /* ** A single instance of this structure is allocated on the stack by ** sqlite3WindowCodeStep() and a pointer to it passed to the various helper ** routines. This is to reduce the number of arguments required by each ** helper function. ** ** regArg: ** Each window function requires an accumulator register (just as an ** ordinary aggregate function does). This variable is set to the first ** in an array of accumulator registers - one for each window function ** in the WindowCodeArg.pMWin list. ** ** eDelete: ** The window functions implementation sometimes caches the input rows ** that it processes in a temporary table. If it is not zero, this ** variable indicates when rows may be removed from the temp table (in ** order to reduce memory requirements - it would always be safe just ** to leave them there). Possible values for eDelete are: ** ** WINDOW_RETURN_ROW: ** An input row can be discarded after it is returned to the caller. ** ** WINDOW_AGGINVERSE: ** An input row can be discarded after the window functions xInverse() ** callbacks have been invoked in it. ** ** WINDOW_AGGSTEP: ** An input row can be discarded after the window functions xStep() ** callbacks have been invoked in it. ** ** start,current,end ** Consider a window-frame similar to the following: ** ** (ORDER BY a, b GROUPS BETWEEN 2 PRECEDING AND 2 FOLLOWING) ** ** The windows functions implmentation caches the input rows in a temp ** table, sorted by "a, b" (it actually populates the cache lazily, and ** aggressively removes rows once they are no longer required, but that's ** a mere detail). It keeps three cursors open on the temp table. One ** (current) that points to the next row to return to the query engine ** once its window function values have been calculated. Another (end) ** points to the next row to call the xStep() method of each window function ** on (so that it is 2 groups ahead of current). And a third (start) that ** points to the next row to call the xInverse() method of each window ** function on. ** ** Each cursor (start, current and end) consists of a VDBE cursor ** (WindowCsrAndReg.csr) and an array of registers (starting at ** WindowCodeArg.reg) that always contains a copy of the peer values ** read from the corresponding cursor. ** ** Depending on the window-frame in question, all three cursors may not ** be required. In this case both WindowCodeArg.csr and reg are set to ** 0. */ struct WindowCodeArg { Parse *pParse; /* Parse context */ Window *pMWin; /* First in list of functions being processed */ Vdbe *pVdbe; /* VDBE object */ int addrGosub; /* OP_Gosub to this address to return one row */ int regGosub; /* Register used with OP_Gosub(addrGosub) */ int regArg; /* First in array of accumulator registers */ int eDelete; /* See above */ int regRowid; WindowCsrAndReg start; WindowCsrAndReg current; WindowCsrAndReg end; }; /* ** Generate VM code to read the window frames peer values from cursor csr into ** an array of registers starting at reg. */ static void windowReadPeerValues( WindowCodeArg *p, int csr, int reg ){ Window *pMWin = p->pMWin; ExprList *pOrderBy = pMWin->pOrderBy; if( pOrderBy ){ Vdbe *v = sqlite3GetVdbe(p->pParse); ExprList *pPart = pMWin->pPartition; int iColOff = pMWin->nBufferCol + (pPart ? pPart->nExpr : 0); int i; for(i=0; i<pOrderBy->nExpr; i++){ sqlite3VdbeAddOp3(v, OP_Column, csr, iColOff+i, reg+i); } } } /* ** Generate VM code to invoke either xStep() (if bInverse is 0) or ** xInverse (if bInverse is non-zero) for each window function in the ** linked list starting at pMWin. Or, for built-in window functions ** that do not use the standard function API, generate the required ** inline VM code. |
︙ | ︙ | |||
1105 1106 1107 1108 1109 1110 1111 | ** Or, if csr is less than zero, then the array of registers at reg is ** already populated with all columns from the current row of the sub-query. ** ** If argument regPartSize is non-zero, then it is a register containing the ** number of rows in the current partition. */ static void windowAggStep( | | | < > | | > > | > > > | | > < < < < < | | | < | < < | | | | | | | | < < < < > | | < | | < < < < | | | > > > > > > > > > > > > > > > > | > | > > > > > > > > > > | | | > > > | | < < < > > | | | < | | | > | > | < < < < < < | | | > > > > | > > > > | > > > > > > > > > | < | > > > | < < < < < | > | > | | | > > > > > > | | > > > > | | | | | > > > > > > | | > | | < > | > | > | > | > > > | > > > > | < < < < > | | < | > | | | > | | > | | > | | | | | | | | | | | | | | | | | | | | | | | | | < | | | > | | | | | | | | | | | | | | | | | | | | | | | | | < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < > > | < < | | | | | | | > < | > | < < | < > | < | < < < < < < < > | < < < < < < < < < | | < < < < < < < < > > > | > > | < < > | < > | | | < < < < < < < < | < < < < < < < < < > > | < | > | | | | | < | < > | > > | > > | < < > > > | < > > > | < > | | > | < < < < < | < < < < < < < < < > > | > > > > | < < < < < < < < < < > > > | < < | > > | | > | < < < | | | | < < | | < < < < < < < < < < < < < < < < < < < | | < < < < < | < < < < < | | < < > > | < < > > > > | < < < > < < | < | < < < < < < < < < < < | < < > < < < < < | | < < | < < < < < < < < | < > > > | | < | < < < < < | < | < < < > | < | < < < | > > > > > > > | | < < < < < < < < < < | < < < | < < < < | < < < < < | | < > | | | > > < | | < > | > > > | < | < < < < < < < < | < | < < < < > | | < < < < < < < < | < < < < < < < < < | < < | | > > > > > > > > > > > > | | | | | < > | | < < < < < < < < < < < < < < < < < < < < < < < < < | | < < < < < < > > > > > > > | | > | < < > | | | < < < < < < < < < | < < < < < < < < < | < | < > | < > > > | < < < < < < | | < < < < | | | < | | < > | | < < < | < | < | < < < < | | < | | < < < < < | < > | | | | | | | | | < | | | < < | < | < < < < < < < < < < < < | < | < < < < | > > | < > < | > > > > > > > > > > > > | | > | | < | < < | | < < | | > > | < < < < < < < < < < < < < < < < < < < < < < < < | | < < < < < < < < < | < | | < < | < | | > | | < < < < < | | < < | < < < < < | | < | > < | < < < < < | < < < | < < | | | < < < | < > | < < > | | < < > > | < < < < < < < < < | < < < | | | > | | < | < < | < > > > | | > | | | < < | < | < | < < | < < < < < < | > | > > > > > > > | 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 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 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 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 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 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 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 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 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 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 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 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 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 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 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 2400 2401 2402 2403 2404 2405 2406 2407 | ** Or, if csr is less than zero, then the array of registers at reg is ** already populated with all columns from the current row of the sub-query. ** ** If argument regPartSize is non-zero, then it is a register containing the ** number of rows in the current partition. */ static void windowAggStep( WindowCodeArg *p, Window *pMWin, /* Linked list of window functions */ int csr, /* Read arguments from this cursor */ int bInverse, /* True to invoke xInverse instead of xStep */ int reg /* Array of registers */ ){ Parse *pParse = p->pParse; Vdbe *v = sqlite3GetVdbe(pParse); Window *pWin; for(pWin=pMWin; pWin; pWin=pWin->pNextWin){ FuncDef *pFunc = pWin->pFunc; int regArg; int nArg = pWin->bExprArgs ? 0 : windowArgCount(pWin); int i; assert( bInverse==0 || pWin->eStart!=TK_UNBOUNDED ); /* All OVER clauses in the same window function aggregate step must ** be the same. */ assert( pWin==pMWin || sqlite3WindowCompare(pParse,pWin,pMWin,0)!=1 ); for(i=0; i<nArg; i++){ if( i!=1 || pFunc->zName!=nth_valueName ){ sqlite3VdbeAddOp3(v, OP_Column, csr, pWin->iArgCol+i, reg+i); }else{ sqlite3VdbeAddOp3(v, OP_Column, pMWin->iEphCsr, pWin->iArgCol+i, reg+i); } } regArg = reg; if( pMWin->regStartRowid==0 && (pFunc->funcFlags & SQLITE_FUNC_MINMAX) && (pWin->eStart!=TK_UNBOUNDED) ){ int addrIsNull = sqlite3VdbeAddOp1(v, OP_IsNull, regArg); VdbeCoverage(v); if( bInverse==0 ){ sqlite3VdbeAddOp2(v, OP_AddImm, pWin->regApp+1, 1); sqlite3VdbeAddOp2(v, OP_SCopy, regArg, pWin->regApp); sqlite3VdbeAddOp3(v, OP_MakeRecord, pWin->regApp, 2, pWin->regApp+2); sqlite3VdbeAddOp2(v, OP_IdxInsert, pWin->csrApp, pWin->regApp+2); }else{ sqlite3VdbeAddOp4Int(v, OP_SeekGE, pWin->csrApp, 0, regArg, 1); VdbeCoverageNeverTaken(v); sqlite3VdbeAddOp1(v, OP_Delete, pWin->csrApp); sqlite3VdbeJumpHere(v, sqlite3VdbeCurrentAddr(v)-2); } sqlite3VdbeJumpHere(v, addrIsNull); }else if( pWin->regApp ){ assert( pFunc->zName==nth_valueName || pFunc->zName==first_valueName ); assert( bInverse==0 || bInverse==1 ); sqlite3VdbeAddOp2(v, OP_AddImm, pWin->regApp+1-bInverse, 1); }else if( pFunc->xSFunc!=noopStepFunc ){ int addrIf = 0; if( pWin->pFilter ){ int regTmp; assert( ExprUseXList(pWin->pOwner) ); assert( pWin->bExprArgs || !nArg ||nArg==pWin->pOwner->x.pList->nExpr ); assert( pWin->bExprArgs || nArg ||pWin->pOwner->x.pList==0 ); regTmp = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp3(v, OP_Column, csr, pWin->iArgCol+nArg,regTmp); addrIf = sqlite3VdbeAddOp3(v, OP_IfNot, regTmp, 0, 1); VdbeCoverage(v); sqlite3ReleaseTempReg(pParse, regTmp); } if( pWin->bExprArgs ){ int iOp = sqlite3VdbeCurrentAddr(v); int iEnd; assert( ExprUseXList(pWin->pOwner) ); nArg = pWin->pOwner->x.pList->nExpr; regArg = sqlite3GetTempRange(pParse, nArg); sqlite3ExprCodeExprList(pParse, pWin->pOwner->x.pList, regArg, 0, 0); for(iEnd=sqlite3VdbeCurrentAddr(v); iOp<iEnd; iOp++){ VdbeOp *pOp = sqlite3VdbeGetOp(v, iOp); if( pOp->opcode==OP_Column && pOp->p1==pWin->iEphCsr ){ pOp->p1 = csr; } } } if( pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL ){ CollSeq *pColl; assert( nArg>0 ); assert( ExprUseXList(pWin->pOwner) ); pColl = sqlite3ExprNNCollSeq(pParse, pWin->pOwner->x.pList->a[0].pExpr); sqlite3VdbeAddOp4(v, OP_CollSeq, 0,0,0, (const char*)pColl, P4_COLLSEQ); } sqlite3VdbeAddOp3(v, bInverse? OP_AggInverse : OP_AggStep, bInverse, regArg, pWin->regAccum); sqlite3VdbeAppendP4(v, pFunc, P4_FUNCDEF); sqlite3VdbeChangeP5(v, (u8)nArg); if( pWin->bExprArgs ){ sqlite3ReleaseTempRange(pParse, regArg, nArg); } if( addrIf ) sqlite3VdbeJumpHere(v, addrIf); } } } /* ** Values that may be passed as the second argument to windowCodeOp(). */ #define WINDOW_RETURN_ROW 1 #define WINDOW_AGGINVERSE 2 #define WINDOW_AGGSTEP 3 /* ** Generate VM code to invoke either xValue() (bFin==0) or xFinalize() ** (bFin==1) for each window function in the linked list starting at ** pMWin. Or, for built-in window-functions that do not use the standard ** API, generate the equivalent VM code. */ static void windowAggFinal(WindowCodeArg *p, int bFin){ Parse *pParse = p->pParse; Window *pMWin = p->pMWin; Vdbe *v = sqlite3GetVdbe(pParse); Window *pWin; for(pWin=pMWin; pWin; pWin=pWin->pNextWin){ if( pMWin->regStartRowid==0 && (pWin->pFunc->funcFlags & SQLITE_FUNC_MINMAX) && (pWin->eStart!=TK_UNBOUNDED) ){ sqlite3VdbeAddOp2(v, OP_Null, 0, pWin->regResult); sqlite3VdbeAddOp1(v, OP_Last, pWin->csrApp); VdbeCoverage(v); sqlite3VdbeAddOp3(v, OP_Column, pWin->csrApp, 0, pWin->regResult); sqlite3VdbeJumpHere(v, sqlite3VdbeCurrentAddr(v)-2); }else if( pWin->regApp ){ assert( pMWin->regStartRowid==0 ); }else{ int nArg = windowArgCount(pWin); if( bFin ){ sqlite3VdbeAddOp2(v, OP_AggFinal, pWin->regAccum, nArg); sqlite3VdbeAppendP4(v, pWin->pFunc, P4_FUNCDEF); sqlite3VdbeAddOp2(v, OP_Copy, pWin->regAccum, pWin->regResult); sqlite3VdbeAddOp2(v, OP_Null, 0, pWin->regAccum); }else{ sqlite3VdbeAddOp3(v, OP_AggValue,pWin->regAccum,nArg,pWin->regResult); sqlite3VdbeAppendP4(v, pWin->pFunc, P4_FUNCDEF); } } } } /* ** Generate code to calculate the current values of all window functions in the ** p->pMWin list by doing a full scan of the current window frame. Store the ** results in the Window.regResult registers, ready to return the upper ** layer. */ static void windowFullScan(WindowCodeArg *p){ Window *pWin; Parse *pParse = p->pParse; Window *pMWin = p->pMWin; Vdbe *v = p->pVdbe; int regCRowid = 0; /* Current rowid value */ int regCPeer = 0; /* Current peer values */ int regRowid = 0; /* AggStep rowid value */ int regPeer = 0; /* AggStep peer values */ int nPeer; int lblNext; int lblBrk; int addrNext; int csr; VdbeModuleComment((v, "windowFullScan begin")); assert( pMWin!=0 ); csr = pMWin->csrApp; nPeer = (pMWin->pOrderBy ? pMWin->pOrderBy->nExpr : 0); lblNext = sqlite3VdbeMakeLabel(pParse); lblBrk = sqlite3VdbeMakeLabel(pParse); regCRowid = sqlite3GetTempReg(pParse); regRowid = sqlite3GetTempReg(pParse); if( nPeer ){ regCPeer = sqlite3GetTempRange(pParse, nPeer); regPeer = sqlite3GetTempRange(pParse, nPeer); } sqlite3VdbeAddOp2(v, OP_Rowid, pMWin->iEphCsr, regCRowid); windowReadPeerValues(p, pMWin->iEphCsr, regCPeer); for(pWin=pMWin; pWin; pWin=pWin->pNextWin){ sqlite3VdbeAddOp2(v, OP_Null, 0, pWin->regAccum); } sqlite3VdbeAddOp3(v, OP_SeekGE, csr, lblBrk, pMWin->regStartRowid); VdbeCoverage(v); addrNext = sqlite3VdbeCurrentAddr(v); sqlite3VdbeAddOp2(v, OP_Rowid, csr, regRowid); sqlite3VdbeAddOp3(v, OP_Gt, pMWin->regEndRowid, lblBrk, regRowid); VdbeCoverageNeverNull(v); if( pMWin->eExclude==TK_CURRENT ){ sqlite3VdbeAddOp3(v, OP_Eq, regCRowid, lblNext, regRowid); VdbeCoverageNeverNull(v); }else if( pMWin->eExclude!=TK_NO ){ int addr; int addrEq = 0; KeyInfo *pKeyInfo = 0; if( pMWin->pOrderBy ){ pKeyInfo = sqlite3KeyInfoFromExprList(pParse, pMWin->pOrderBy, 0, 0); } if( pMWin->eExclude==TK_TIES ){ addrEq = sqlite3VdbeAddOp3(v, OP_Eq, regCRowid, 0, regRowid); VdbeCoverageNeverNull(v); } if( pKeyInfo ){ windowReadPeerValues(p, csr, regPeer); sqlite3VdbeAddOp3(v, OP_Compare, regPeer, regCPeer, nPeer); sqlite3VdbeAppendP4(v, (void*)pKeyInfo, P4_KEYINFO); addr = sqlite3VdbeCurrentAddr(v)+1; sqlite3VdbeAddOp3(v, OP_Jump, addr, lblNext, addr); VdbeCoverageEqNe(v); }else{ sqlite3VdbeAddOp2(v, OP_Goto, 0, lblNext); } if( addrEq ) sqlite3VdbeJumpHere(v, addrEq); } windowAggStep(p, pMWin, csr, 0, p->regArg); sqlite3VdbeResolveLabel(v, lblNext); sqlite3VdbeAddOp2(v, OP_Next, csr, addrNext); VdbeCoverage(v); sqlite3VdbeJumpHere(v, addrNext-1); sqlite3VdbeJumpHere(v, addrNext+1); sqlite3ReleaseTempReg(pParse, regRowid); sqlite3ReleaseTempReg(pParse, regCRowid); if( nPeer ){ sqlite3ReleaseTempRange(pParse, regPeer, nPeer); sqlite3ReleaseTempRange(pParse, regCPeer, nPeer); } windowAggFinal(p, 1); VdbeModuleComment((v, "windowFullScan end")); } /* ** Invoke the sub-routine at regGosub (generated by code in select.c) to ** return the current row of Window.iEphCsr. If all window functions are ** aggregate window functions that use the standard API, a single ** OP_Gosub instruction is all that this routine generates. Extra VM code ** for per-row processing is only generated for the following built-in window ** functions: ** ** nth_value() ** first_value() ** lag() ** lead() */ static void windowReturnOneRow(WindowCodeArg *p){ Window *pMWin = p->pMWin; Vdbe *v = p->pVdbe; if( pMWin->regStartRowid ){ windowFullScan(p); }else{ Parse *pParse = p->pParse; Window *pWin; for(pWin=pMWin; pWin; pWin=pWin->pNextWin){ FuncDef *pFunc = pWin->pFunc; assert( ExprUseXList(pWin->pOwner) ); if( pFunc->zName==nth_valueName || pFunc->zName==first_valueName ){ int csr = pWin->csrApp; int lbl = sqlite3VdbeMakeLabel(pParse); int tmpReg = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp2(v, OP_Null, 0, pWin->regResult); if( pFunc->zName==nth_valueName ){ sqlite3VdbeAddOp3(v, OP_Column,pMWin->iEphCsr,pWin->iArgCol+1,tmpReg); windowCheckValue(pParse, tmpReg, 2); }else{ sqlite3VdbeAddOp2(v, OP_Integer, 1, tmpReg); } sqlite3VdbeAddOp3(v, OP_Add, tmpReg, pWin->regApp, tmpReg); sqlite3VdbeAddOp3(v, OP_Gt, pWin->regApp+1, lbl, tmpReg); VdbeCoverageNeverNull(v); sqlite3VdbeAddOp3(v, OP_SeekRowid, csr, 0, tmpReg); VdbeCoverageNeverTaken(v); sqlite3VdbeAddOp3(v, OP_Column, csr, pWin->iArgCol, pWin->regResult); sqlite3VdbeResolveLabel(v, lbl); sqlite3ReleaseTempReg(pParse, tmpReg); } else if( pFunc->zName==leadName || pFunc->zName==lagName ){ int nArg = pWin->pOwner->x.pList->nExpr; int csr = pWin->csrApp; int lbl = sqlite3VdbeMakeLabel(pParse); int tmpReg = sqlite3GetTempReg(pParse); int iEph = pMWin->iEphCsr; if( nArg<3 ){ sqlite3VdbeAddOp2(v, OP_Null, 0, pWin->regResult); }else{ sqlite3VdbeAddOp3(v, OP_Column, iEph,pWin->iArgCol+2,pWin->regResult); } sqlite3VdbeAddOp2(v, OP_Rowid, iEph, tmpReg); if( nArg<2 ){ int val = (pFunc->zName==leadName ? 1 : -1); sqlite3VdbeAddOp2(v, OP_AddImm, tmpReg, val); }else{ int op = (pFunc->zName==leadName ? OP_Add : OP_Subtract); int tmpReg2 = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp3(v, OP_Column, iEph, pWin->iArgCol+1, tmpReg2); sqlite3VdbeAddOp3(v, op, tmpReg2, tmpReg, tmpReg); sqlite3ReleaseTempReg(pParse, tmpReg2); } sqlite3VdbeAddOp3(v, OP_SeekRowid, csr, lbl, tmpReg); VdbeCoverage(v); sqlite3VdbeAddOp3(v, OP_Column, csr, pWin->iArgCol, pWin->regResult); sqlite3VdbeResolveLabel(v, lbl); sqlite3ReleaseTempReg(pParse, tmpReg); } } } sqlite3VdbeAddOp2(v, OP_Gosub, p->regGosub, p->addrGosub); } /* ** Generate code to set the accumulator register for each window function ** in the linked list passed as the second argument to NULL. And perform ** any equivalent initialization required by any built-in window functions ** in the list. */ static int windowInitAccum(Parse *pParse, Window *pMWin){ Vdbe *v = sqlite3GetVdbe(pParse); int regArg; int nArg = 0; Window *pWin; for(pWin=pMWin; pWin; pWin=pWin->pNextWin){ FuncDef *pFunc = pWin->pFunc; assert( pWin->regAccum ); sqlite3VdbeAddOp2(v, OP_Null, 0, pWin->regAccum); nArg = MAX(nArg, windowArgCount(pWin)); if( pMWin->regStartRowid==0 ){ if( pFunc->zName==nth_valueName || pFunc->zName==first_valueName ){ sqlite3VdbeAddOp2(v, OP_Integer, 0, pWin->regApp); sqlite3VdbeAddOp2(v, OP_Integer, 0, pWin->regApp+1); } if( (pFunc->funcFlags & SQLITE_FUNC_MINMAX) && pWin->csrApp ){ assert( pWin->eStart!=TK_UNBOUNDED ); sqlite3VdbeAddOp1(v, OP_ResetSorter, pWin->csrApp); sqlite3VdbeAddOp2(v, OP_Integer, 0, pWin->regApp+1); } } } regArg = pParse->nMem+1; pParse->nMem += nArg; return regArg; } /* ** Return true if the current frame should be cached in the ephemeral table, ** even if there are no xInverse() calls required. */ static int windowCacheFrame(Window *pMWin){ Window *pWin; if( pMWin->regStartRowid ) return 1; for(pWin=pMWin; pWin; pWin=pWin->pNextWin){ FuncDef *pFunc = pWin->pFunc; if( (pFunc->zName==nth_valueName) || (pFunc->zName==first_valueName) || (pFunc->zName==leadName) || (pFunc->zName==lagName) ){ return 1; } } return 0; } /* ** regOld and regNew are each the first register in an array of size ** pOrderBy->nExpr. This function generates code to compare the two ** arrays of registers using the collation sequences and other comparison ** parameters specified by pOrderBy. ** ** If the two arrays are not equal, the contents of regNew is copied to ** regOld and control falls through. Otherwise, if the contents of the arrays ** are equal, an OP_Goto is executed. The address of the OP_Goto is returned. */ static void windowIfNewPeer( Parse *pParse, ExprList *pOrderBy, int regNew, /* First in array of new values */ int regOld, /* First in array of old values */ int addr /* Jump here */ ){ Vdbe *v = sqlite3GetVdbe(pParse); if( pOrderBy ){ int nVal = pOrderBy->nExpr; KeyInfo *pKeyInfo = sqlite3KeyInfoFromExprList(pParse, pOrderBy, 0, 0); sqlite3VdbeAddOp3(v, OP_Compare, regOld, regNew, nVal); sqlite3VdbeAppendP4(v, (void*)pKeyInfo, P4_KEYINFO); sqlite3VdbeAddOp3(v, OP_Jump, sqlite3VdbeCurrentAddr(v)+1, addr, sqlite3VdbeCurrentAddr(v)+1 ); VdbeCoverageEqNe(v); sqlite3VdbeAddOp3(v, OP_Copy, regNew, regOld, nVal-1); }else{ sqlite3VdbeAddOp2(v, OP_Goto, 0, addr); } } /* ** This function is called as part of generating VM programs for RANGE ** offset PRECEDING/FOLLOWING frame boundaries. Assuming "ASC" order for ** the ORDER BY term in the window, and that argument op is OP_Ge, it generates ** code equivalent to: ** ** if( csr1.peerVal + regVal >= csr2.peerVal ) goto lbl; ** ** The value of parameter op may also be OP_Gt or OP_Le. In these cases the ** operator in the above pseudo-code is replaced with ">" or "<=", respectively. ** ** If the sort-order for the ORDER BY term in the window is DESC, then the ** comparison is reversed. Instead of adding regVal to csr1.peerVal, it is ** subtracted. And the comparison operator is inverted to - ">=" becomes "<=", ** ">" becomes "<", and so on. So, with DESC sort order, if the argument op ** is OP_Ge, the generated code is equivalent to: ** ** if( csr1.peerVal - regVal <= csr2.peerVal ) goto lbl; ** ** A special type of arithmetic is used such that if csr1.peerVal is not ** a numeric type (real or integer), then the result of the addition ** or subtraction is a a copy of csr1.peerVal. */ static void windowCodeRangeTest( WindowCodeArg *p, int op, /* OP_Ge, OP_Gt, or OP_Le */ int csr1, /* Cursor number for cursor 1 */ int regVal, /* Register containing non-negative number */ int csr2, /* Cursor number for cursor 2 */ int lbl /* Jump destination if condition is true */ ){ Parse *pParse = p->pParse; Vdbe *v = sqlite3GetVdbe(pParse); ExprList *pOrderBy = p->pMWin->pOrderBy; /* ORDER BY clause for window */ int reg1 = sqlite3GetTempReg(pParse); /* Reg. for csr1.peerVal+regVal */ int reg2 = sqlite3GetTempReg(pParse); /* Reg. for csr2.peerVal */ int regString = ++pParse->nMem; /* Reg. for constant value '' */ int arith = OP_Add; /* OP_Add or OP_Subtract */ int addrGe; /* Jump destination */ int addrDone = sqlite3VdbeMakeLabel(pParse); /* Address past OP_Ge */ CollSeq *pColl; /* Read the peer-value from each cursor into a register */ windowReadPeerValues(p, csr1, reg1); windowReadPeerValues(p, csr2, reg2); assert( op==OP_Ge || op==OP_Gt || op==OP_Le ); assert( pOrderBy && pOrderBy->nExpr==1 ); if( pOrderBy->a[0].sortFlags & KEYINFO_ORDER_DESC ){ switch( op ){ case OP_Ge: op = OP_Le; break; case OP_Gt: op = OP_Lt; break; default: assert( op==OP_Le ); op = OP_Ge; break; } arith = OP_Subtract; } VdbeModuleComment((v, "CodeRangeTest: if( R%d %s R%d %s R%d ) goto lbl", reg1, (arith==OP_Add ? "+" : "-"), regVal, ((op==OP_Ge) ? ">=" : (op==OP_Le) ? "<=" : (op==OP_Gt) ? ">" : "<"), reg2 )); /* If the BIGNULL flag is set for the ORDER BY, then it is required to ** consider NULL values to be larger than all other values, instead of ** the usual smaller. The VDBE opcodes OP_Ge and so on do not handle this ** (and adding that capability causes a performance regression), so ** instead if the BIGNULL flag is set then cases where either reg1 or ** reg2 are NULL are handled separately in the following block. The code ** generated is equivalent to: ** ** if( reg1 IS NULL ){ ** if( op==OP_Ge ) goto lbl; ** if( op==OP_Gt && reg2 IS NOT NULL ) goto lbl; ** if( op==OP_Le && reg2 IS NULL ) goto lbl; ** }else if( reg2 IS NULL ){ ** if( op==OP_Le ) goto lbl; ** } ** ** Additionally, if either reg1 or reg2 are NULL but the jump to lbl is ** not taken, control jumps over the comparison operator coded below this ** block. */ if( pOrderBy->a[0].sortFlags & KEYINFO_ORDER_BIGNULL ){ /* This block runs if reg1 contains a NULL. */ int addr = sqlite3VdbeAddOp1(v, OP_NotNull, reg1); VdbeCoverage(v); switch( op ){ case OP_Ge: sqlite3VdbeAddOp2(v, OP_Goto, 0, lbl); break; case OP_Gt: sqlite3VdbeAddOp2(v, OP_NotNull, reg2, lbl); VdbeCoverage(v); break; case OP_Le: sqlite3VdbeAddOp2(v, OP_IsNull, reg2, lbl); VdbeCoverage(v); break; default: assert( op==OP_Lt ); /* no-op */ break; } sqlite3VdbeAddOp2(v, OP_Goto, 0, addrDone); /* This block runs if reg1 is not NULL, but reg2 is. */ sqlite3VdbeJumpHere(v, addr); sqlite3VdbeAddOp2(v, OP_IsNull, reg2, lbl); VdbeCoverage(v); if( op==OP_Gt || op==OP_Ge ){ sqlite3VdbeChangeP2(v, -1, addrDone); } } /* Register reg1 currently contains csr1.peerVal (the peer-value from csr1). ** This block adds (or subtracts for DESC) the numeric value in regVal ** from it. Or, if reg1 is not numeric (it is a NULL, a text value or a blob), ** then leave reg1 as it is. In pseudo-code, this is implemented as: ** ** if( reg1>='' ) goto addrGe; ** reg1 = reg1 +/- regVal ** addrGe: ** ** Since all strings and blobs are greater-than-or-equal-to an empty string, ** the add/subtract is skipped for these, as required. If reg1 is a NULL, ** then the arithmetic is performed, but since adding or subtracting from ** NULL is always NULL anyway, this case is handled as required too. */ sqlite3VdbeAddOp4(v, OP_String8, 0, regString, 0, "", P4_STATIC); addrGe = sqlite3VdbeAddOp3(v, OP_Ge, regString, 0, reg1); VdbeCoverage(v); if( (op==OP_Ge && arith==OP_Add) || (op==OP_Le && arith==OP_Subtract) ){ sqlite3VdbeAddOp3(v, op, reg2, lbl, reg1); VdbeCoverage(v); } sqlite3VdbeAddOp3(v, arith, regVal, reg1, reg1); sqlite3VdbeJumpHere(v, addrGe); /* Compare registers reg2 and reg1, taking the jump if required. Note that ** control skips over this test if the BIGNULL flag is set and either ** reg1 or reg2 contain a NULL value. */ sqlite3VdbeAddOp3(v, op, reg2, lbl, reg1); VdbeCoverage(v); pColl = sqlite3ExprNNCollSeq(pParse, pOrderBy->a[0].pExpr); sqlite3VdbeAppendP4(v, (void*)pColl, P4_COLLSEQ); sqlite3VdbeChangeP5(v, SQLITE_NULLEQ); sqlite3VdbeResolveLabel(v, addrDone); assert( op==OP_Ge || op==OP_Gt || op==OP_Lt || op==OP_Le ); testcase(op==OP_Ge); VdbeCoverageIf(v, op==OP_Ge); testcase(op==OP_Lt); VdbeCoverageIf(v, op==OP_Lt); testcase(op==OP_Le); VdbeCoverageIf(v, op==OP_Le); testcase(op==OP_Gt); VdbeCoverageIf(v, op==OP_Gt); sqlite3ReleaseTempReg(pParse, reg1); sqlite3ReleaseTempReg(pParse, reg2); VdbeModuleComment((v, "CodeRangeTest: end")); } /* ** Helper function for sqlite3WindowCodeStep(). Each call to this function ** generates VM code for a single RETURN_ROW, AGGSTEP or AGGINVERSE ** operation. Refer to the header comment for sqlite3WindowCodeStep() for ** details. */ static int windowCodeOp( WindowCodeArg *p, /* Context object */ int op, /* WINDOW_RETURN_ROW, AGGSTEP or AGGINVERSE */ int regCountdown, /* Register for OP_IfPos countdown */ int jumpOnEof /* Jump here if stepped cursor reaches EOF */ ){ int csr, reg; Parse *pParse = p->pParse; Window *pMWin = p->pMWin; int ret = 0; Vdbe *v = p->pVdbe; int addrContinue = 0; int bPeer = (pMWin->eFrmType!=TK_ROWS); int lblDone = sqlite3VdbeMakeLabel(pParse); int addrNextRange = 0; /* Special case - WINDOW_AGGINVERSE is always a no-op if the frame ** starts with UNBOUNDED PRECEDING. */ if( op==WINDOW_AGGINVERSE && pMWin->eStart==TK_UNBOUNDED ){ assert( regCountdown==0 && jumpOnEof==0 ); return 0; } if( regCountdown>0 ){ if( pMWin->eFrmType==TK_RANGE ){ addrNextRange = sqlite3VdbeCurrentAddr(v); assert( op==WINDOW_AGGINVERSE || op==WINDOW_AGGSTEP ); if( op==WINDOW_AGGINVERSE ){ if( pMWin->eStart==TK_FOLLOWING ){ windowCodeRangeTest( p, OP_Le, p->current.csr, regCountdown, p->start.csr, lblDone ); }else{ windowCodeRangeTest( p, OP_Ge, p->start.csr, regCountdown, p->current.csr, lblDone ); } }else{ windowCodeRangeTest( p, OP_Gt, p->end.csr, regCountdown, p->current.csr, lblDone ); } }else{ sqlite3VdbeAddOp3(v, OP_IfPos, regCountdown, lblDone, 1); VdbeCoverage(v); } } if( op==WINDOW_RETURN_ROW && pMWin->regStartRowid==0 ){ windowAggFinal(p, 0); } addrContinue = sqlite3VdbeCurrentAddr(v); /* If this is a (RANGE BETWEEN a FOLLOWING AND b FOLLOWING) or ** (RANGE BETWEEN b PRECEDING AND a PRECEDING) frame, ensure the ** start cursor does not advance past the end cursor within the ** temporary table. It otherwise might, if (a>b). Also ensure that, ** if the input cursor is still finding new rows, that the end ** cursor does not go past it to EOF. */ if( pMWin->eStart==pMWin->eEnd && regCountdown && pMWin->eFrmType==TK_RANGE ){ int regRowid1 = sqlite3GetTempReg(pParse); int regRowid2 = sqlite3GetTempReg(pParse); if( op==WINDOW_AGGINVERSE ){ sqlite3VdbeAddOp2(v, OP_Rowid, p->start.csr, regRowid1); sqlite3VdbeAddOp2(v, OP_Rowid, p->end.csr, regRowid2); sqlite3VdbeAddOp3(v, OP_Ge, regRowid2, lblDone, regRowid1); VdbeCoverage(v); }else if( p->regRowid ){ sqlite3VdbeAddOp2(v, OP_Rowid, p->end.csr, regRowid1); sqlite3VdbeAddOp3(v, OP_Ge, p->regRowid, lblDone, regRowid1); VdbeCoverageNeverNull(v); } sqlite3ReleaseTempReg(pParse, regRowid1); sqlite3ReleaseTempReg(pParse, regRowid2); assert( pMWin->eStart==TK_PRECEDING || pMWin->eStart==TK_FOLLOWING ); } switch( op ){ case WINDOW_RETURN_ROW: csr = p->current.csr; reg = p->current.reg; windowReturnOneRow(p); break; case WINDOW_AGGINVERSE: csr = p->start.csr; reg = p->start.reg; if( pMWin->regStartRowid ){ assert( pMWin->regEndRowid ); sqlite3VdbeAddOp2(v, OP_AddImm, pMWin->regStartRowid, 1); }else{ windowAggStep(p, pMWin, csr, 1, p->regArg); } break; default: assert( op==WINDOW_AGGSTEP ); csr = p->end.csr; reg = p->end.reg; if( pMWin->regStartRowid ){ assert( pMWin->regEndRowid ); sqlite3VdbeAddOp2(v, OP_AddImm, pMWin->regEndRowid, 1); }else{ windowAggStep(p, pMWin, csr, 0, p->regArg); } break; } if( op==p->eDelete ){ sqlite3VdbeAddOp1(v, OP_Delete, csr); sqlite3VdbeChangeP5(v, OPFLAG_SAVEPOSITION); } if( jumpOnEof ){ sqlite3VdbeAddOp2(v, OP_Next, csr, sqlite3VdbeCurrentAddr(v)+2); VdbeCoverage(v); ret = sqlite3VdbeAddOp0(v, OP_Goto); }else{ sqlite3VdbeAddOp2(v, OP_Next, csr, sqlite3VdbeCurrentAddr(v)+1+bPeer); VdbeCoverage(v); if( bPeer ){ sqlite3VdbeAddOp2(v, OP_Goto, 0, lblDone); } } if( bPeer ){ int nReg = (pMWin->pOrderBy ? pMWin->pOrderBy->nExpr : 0); int regTmp = (nReg ? sqlite3GetTempRange(pParse, nReg) : 0); windowReadPeerValues(p, csr, regTmp); windowIfNewPeer(pParse, pMWin->pOrderBy, regTmp, reg, addrContinue); sqlite3ReleaseTempRange(pParse, regTmp, nReg); } if( addrNextRange ){ sqlite3VdbeAddOp2(v, OP_Goto, 0, addrNextRange); } sqlite3VdbeResolveLabel(v, lblDone); return ret; } /* ** Allocate and return a duplicate of the Window object indicated by the ** third argument. Set the Window.pOwner field of the new object to ** pOwner. */ Window *sqlite3WindowDup(sqlite3 *db, Expr *pOwner, Window *p){ Window *pNew = 0; if( ALWAYS(p) ){ pNew = sqlite3DbMallocZero(db, sizeof(Window)); if( pNew ){ pNew->zName = sqlite3DbStrDup(db, p->zName); pNew->zBase = sqlite3DbStrDup(db, p->zBase); pNew->pFilter = sqlite3ExprDup(db, p->pFilter, 0); pNew->pFunc = p->pFunc; pNew->pPartition = sqlite3ExprListDup(db, p->pPartition, 0); pNew->pOrderBy = sqlite3ExprListDup(db, p->pOrderBy, 0); pNew->eFrmType = p->eFrmType; pNew->eEnd = p->eEnd; pNew->eStart = p->eStart; pNew->eExclude = p->eExclude; pNew->regResult = p->regResult; pNew->regAccum = p->regAccum; pNew->iArgCol = p->iArgCol; pNew->iEphCsr = p->iEphCsr; pNew->bExprArgs = p->bExprArgs; pNew->pStart = sqlite3ExprDup(db, p->pStart, 0); pNew->pEnd = sqlite3ExprDup(db, p->pEnd, 0); pNew->pOwner = pOwner; pNew->bImplicitFrame = p->bImplicitFrame; } } return pNew; } /* ** Return a copy of the linked list of Window objects passed as the |
︙ | ︙ | |||
2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 | *pp = sqlite3WindowDup(db, 0, pWin); if( *pp==0 ) break; pp = &((*pp)->pNextWin); } return pRet; } /* ** sqlite3WhereBegin() has already been called for the SELECT statement ** passed as the second argument when this function is invoked. It generates | > > > > > > > > > > > > > > > > > > > > | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > | > > > > > > | < < < > > > > | < | < | < < > | > > > > > > > > > > > > | < > > | > > > > | > > > > > > > > > | > > > > > > | > > > > > | > > | > > > > | > | | | | > > > > > > | > > > > > > > > > | > > > > > | > | | > > > > | > > > | > > > > > > > > > > > > > > | > > > | > > > > > > > | > > > > > | > | > | > > | < | | > > > | > > > > > > | > > > > > | | | < < > > > > | < > > > > > | | > > > > | > > > > > > | > > > | | > | > > > | > > > > > | > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | < > > > > > > > | 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 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 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 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 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 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 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 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 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 | *pp = sqlite3WindowDup(db, 0, pWin); if( *pp==0 ) break; pp = &((*pp)->pNextWin); } return pRet; } /* ** Return true if it can be determined at compile time that expression ** pExpr evaluates to a value that, when cast to an integer, is greater ** than zero. False otherwise. ** ** If an OOM error occurs, this function sets the Parse.db.mallocFailed ** flag and returns zero. */ static int windowExprGtZero(Parse *pParse, Expr *pExpr){ int ret = 0; sqlite3 *db = pParse->db; sqlite3_value *pVal = 0; sqlite3ValueFromExpr(db, pExpr, db->enc, SQLITE_AFF_NUMERIC, &pVal); if( pVal && sqlite3_value_int(pVal)>0 ){ ret = 1; } sqlite3ValueFree(pVal); return ret; } /* ** sqlite3WhereBegin() has already been called for the SELECT statement ** passed as the second argument when this function is invoked. It generates ** code to populate the Window.regResult register for each window function ** and invoke the sub-routine at instruction addrGosub once for each row. ** sqlite3WhereEnd() is always called before returning. ** ** This function handles several different types of window frames, which ** require slightly different processing. The following pseudo code is ** used to implement window frames of the form: ** ** ROWS BETWEEN <expr1> PRECEDING AND <expr2> FOLLOWING ** ** Other window frame types use variants of the following: ** ** ... loop started by sqlite3WhereBegin() ... ** if( new partition ){ ** Gosub flush ** } ** Insert new row into eph table. ** ** if( first row of partition ){ ** // Rewind three cursors, all open on the eph table. ** Rewind(csrEnd); ** Rewind(csrStart); ** Rewind(csrCurrent); ** ** regEnd = <expr2> // FOLLOWING expression ** regStart = <expr1> // PRECEDING expression ** }else{ ** // First time this branch is taken, the eph table contains two ** // rows. The first row in the partition, which all three cursors ** // currently point to, and the following row. ** AGGSTEP ** if( (regEnd--)<=0 ){ ** RETURN_ROW ** if( (regStart--)<=0 ){ ** AGGINVERSE ** } ** } ** } ** } ** flush: ** AGGSTEP ** while( 1 ){ ** RETURN ROW ** if( csrCurrent is EOF ) break; ** if( (regStart--)<=0 ){ ** AggInverse(csrStart) ** Next(csrStart) ** } ** } ** ** The pseudo-code above uses the following shorthand: ** ** AGGSTEP: invoke the aggregate xStep() function for each window function ** with arguments read from the current row of cursor csrEnd, then ** step cursor csrEnd forward one row (i.e. sqlite3BtreeNext()). ** ** RETURN_ROW: return a row to the caller based on the contents of the ** current row of csrCurrent and the current state of all ** aggregates. Then step cursor csrCurrent forward one row. ** ** AGGINVERSE: invoke the aggregate xInverse() function for each window ** functions with arguments read from the current row of cursor ** csrStart. Then step csrStart forward one row. ** ** There are two other ROWS window frames that are handled significantly ** differently from the above - "BETWEEN <expr> PRECEDING AND <expr> PRECEDING" ** and "BETWEEN <expr> FOLLOWING AND <expr> FOLLOWING". These are special ** cases because they change the order in which the three cursors (csrStart, ** csrCurrent and csrEnd) iterate through the ephemeral table. Cases that ** use UNBOUNDED or CURRENT ROW are much simpler variations on one of these ** three. ** ** ROWS BETWEEN <expr1> PRECEDING AND <expr2> PRECEDING ** ** ... loop started by sqlite3WhereBegin() ... ** if( new partition ){ ** Gosub flush ** } ** Insert new row into eph table. ** if( first row of partition ){ ** Rewind(csrEnd) ; Rewind(csrStart) ; Rewind(csrCurrent) ** regEnd = <expr2> ** regStart = <expr1> ** }else{ ** if( (regEnd--)<=0 ){ ** AGGSTEP ** } ** RETURN_ROW ** if( (regStart--)<=0 ){ ** AGGINVERSE ** } ** } ** } ** flush: ** if( (regEnd--)<=0 ){ ** AGGSTEP ** } ** RETURN_ROW ** ** ** ROWS BETWEEN <expr1> FOLLOWING AND <expr2> FOLLOWING ** ** ... loop started by sqlite3WhereBegin() ... ** if( new partition ){ ** Gosub flush ** } ** Insert new row into eph table. ** if( first row of partition ){ ** Rewind(csrEnd) ; Rewind(csrStart) ; Rewind(csrCurrent) ** regEnd = <expr2> ** regStart = regEnd - <expr1> ** }else{ ** AGGSTEP ** if( (regEnd--)<=0 ){ ** RETURN_ROW ** } ** if( (regStart--)<=0 ){ ** AGGINVERSE ** } ** } ** } ** flush: ** AGGSTEP ** while( 1 ){ ** if( (regEnd--)<=0 ){ ** RETURN_ROW ** if( eof ) break; ** } ** if( (regStart--)<=0 ){ ** AGGINVERSE ** if( eof ) break ** } ** } ** while( !eof csrCurrent ){ ** RETURN_ROW ** } ** ** For the most part, the patterns above are adapted to support UNBOUNDED by ** assuming that it is equivalent to "infinity PRECEDING/FOLLOWING" and ** CURRENT ROW by assuming that it is equivilent to "0 PRECEDING/FOLLOWING". ** This is optimized of course - branches that will never be taken and ** conditions that are always true are omitted from the VM code. The only ** exceptional case is: ** ** ROWS BETWEEN <expr1> FOLLOWING AND UNBOUNDED FOLLOWING ** ** ... loop started by sqlite3WhereBegin() ... ** if( new partition ){ ** Gosub flush ** } ** Insert new row into eph table. ** if( first row of partition ){ ** Rewind(csrEnd) ; Rewind(csrStart) ; Rewind(csrCurrent) ** regStart = <expr1> ** }else{ ** AGGSTEP ** } ** } ** flush: ** AGGSTEP ** while( 1 ){ ** if( (regStart--)<=0 ){ ** AGGINVERSE ** if( eof ) break ** } ** RETURN_ROW ** } ** while( !eof csrCurrent ){ ** RETURN_ROW ** } ** ** Also requiring special handling are the cases: ** ** ROWS BETWEEN <expr1> PRECEDING AND <expr2> PRECEDING ** ROWS BETWEEN <expr1> FOLLOWING AND <expr2> FOLLOWING ** ** when (expr1 < expr2). This is detected at runtime, not by this function. ** To handle this case, the pseudo-code programs depicted above are modified ** slightly to be: ** ** ... loop started by sqlite3WhereBegin() ... ** if( new partition ){ ** Gosub flush ** } ** Insert new row into eph table. ** if( first row of partition ){ ** Rewind(csrEnd) ; Rewind(csrStart) ; Rewind(csrCurrent) ** regEnd = <expr2> ** regStart = <expr1> ** if( regEnd < regStart ){ ** RETURN_ROW ** delete eph table contents ** continue ** } ** ... ** ** The new "continue" statement in the above jumps to the next iteration ** of the outer loop - the one started by sqlite3WhereBegin(). ** ** The various GROUPS cases are implemented using the same patterns as ** ROWS. The VM code is modified slightly so that: ** ** 1. The else branch in the main loop is only taken if the row just ** added to the ephemeral table is the start of a new group. In ** other words, it becomes: ** ** ... loop started by sqlite3WhereBegin() ... ** if( new partition ){ ** Gosub flush ** } ** Insert new row into eph table. ** if( first row of partition ){ ** Rewind(csrEnd) ; Rewind(csrStart) ; Rewind(csrCurrent) ** regEnd = <expr2> ** regStart = <expr1> ** }else if( new group ){ ** ... ** } ** } ** ** 2. Instead of processing a single row, each RETURN_ROW, AGGSTEP or ** AGGINVERSE step processes the current row of the relevant cursor and ** all subsequent rows belonging to the same group. ** ** RANGE window frames are a little different again. As for GROUPS, the ** main loop runs once per group only. And RETURN_ROW, AGGSTEP and AGGINVERSE ** deal in groups instead of rows. As for ROWS and GROUPS, there are three ** basic cases: ** ** RANGE BETWEEN <expr1> PRECEDING AND <expr2> FOLLOWING ** ** ... loop started by sqlite3WhereBegin() ... ** if( new partition ){ ** Gosub flush ** } ** Insert new row into eph table. ** if( first row of partition ){ ** Rewind(csrEnd) ; Rewind(csrStart) ; Rewind(csrCurrent) ** regEnd = <expr2> ** regStart = <expr1> ** }else{ ** AGGSTEP ** while( (csrCurrent.key + regEnd) < csrEnd.key ){ ** RETURN_ROW ** while( csrStart.key + regStart) < csrCurrent.key ){ ** AGGINVERSE ** } ** } ** } ** } ** flush: ** AGGSTEP ** while( 1 ){ ** RETURN ROW ** if( csrCurrent is EOF ) break; ** while( csrStart.key + regStart) < csrCurrent.key ){ ** AGGINVERSE ** } ** } ** } ** ** In the above notation, "csr.key" means the current value of the ORDER BY ** expression (there is only ever 1 for a RANGE that uses an <expr> FOLLOWING ** or <expr PRECEDING) read from cursor csr. ** ** RANGE BETWEEN <expr1> PRECEDING AND <expr2> PRECEDING ** ** ... loop started by sqlite3WhereBegin() ... ** if( new partition ){ ** Gosub flush ** } ** Insert new row into eph table. ** if( first row of partition ){ ** Rewind(csrEnd) ; Rewind(csrStart) ; Rewind(csrCurrent) ** regEnd = <expr2> ** regStart = <expr1> ** }else{ ** while( (csrEnd.key + regEnd) <= csrCurrent.key ){ ** AGGSTEP ** } ** while( (csrStart.key + regStart) < csrCurrent.key ){ ** AGGINVERSE ** } ** RETURN_ROW ** } ** } ** flush: ** while( (csrEnd.key + regEnd) <= csrCurrent.key ){ ** AGGSTEP ** } ** while( (csrStart.key + regStart) < csrCurrent.key ){ ** AGGINVERSE ** } ** RETURN_ROW ** ** RANGE BETWEEN <expr1> FOLLOWING AND <expr2> FOLLOWING ** ** ... loop started by sqlite3WhereBegin() ... ** if( new partition ){ ** Gosub flush ** } ** Insert new row into eph table. ** if( first row of partition ){ ** Rewind(csrEnd) ; Rewind(csrStart) ; Rewind(csrCurrent) ** regEnd = <expr2> ** regStart = <expr1> ** }else{ ** AGGSTEP ** while( (csrCurrent.key + regEnd) < csrEnd.key ){ ** while( (csrCurrent.key + regStart) > csrStart.key ){ ** AGGINVERSE ** } ** RETURN_ROW ** } ** } ** } ** flush: ** AGGSTEP ** while( 1 ){ ** while( (csrCurrent.key + regStart) > csrStart.key ){ ** AGGINVERSE ** if( eof ) break "while( 1 )" loop. ** } ** RETURN_ROW ** } ** while( !eof csrCurrent ){ ** RETURN_ROW ** } ** ** The text above leaves out many details. Refer to the code and comments ** below for a more complete picture. */ void sqlite3WindowCodeStep( Parse *pParse, /* Parse context */ Select *p, /* Rewritten SELECT statement */ WhereInfo *pWInfo, /* Context returned by sqlite3WhereBegin() */ int regGosub, /* Register for OP_Gosub */ int addrGosub /* OP_Gosub here to return each row */ ){ Window *pMWin = p->pWin; ExprList *pOrderBy = pMWin->pOrderBy; Vdbe *v = sqlite3GetVdbe(pParse); int csrWrite; /* Cursor used to write to eph. table */ int csrInput = p->pSrc->a[0].iCursor; /* Cursor of sub-select */ int nInput = p->pSrc->a[0].pTab->nCol; /* Number of cols returned by sub */ int iInput; /* To iterate through sub cols */ int addrNe; /* Address of OP_Ne */ int addrGosubFlush = 0; /* Address of OP_Gosub to flush: */ int addrInteger = 0; /* Address of OP_Integer */ int addrEmpty; /* Address of OP_Rewind in flush: */ int regNew; /* Array of registers holding new input row */ int regRecord; /* regNew array in record form */ int regNewPeer = 0; /* Peer values for new row (part of regNew) */ int regPeer = 0; /* Peer values for current row */ int regFlushPart = 0; /* Register for "Gosub flush_partition" */ WindowCodeArg s; /* Context object for sub-routines */ int lblWhereEnd; /* Label just before sqlite3WhereEnd() code */ int regStart = 0; /* Value of <expr> PRECEDING */ int regEnd = 0; /* Value of <expr> FOLLOWING */ assert( pMWin->eStart==TK_PRECEDING || pMWin->eStart==TK_CURRENT || pMWin->eStart==TK_FOLLOWING || pMWin->eStart==TK_UNBOUNDED ); assert( pMWin->eEnd==TK_FOLLOWING || pMWin->eEnd==TK_CURRENT || pMWin->eEnd==TK_UNBOUNDED || pMWin->eEnd==TK_PRECEDING ); assert( pMWin->eExclude==0 || pMWin->eExclude==TK_CURRENT || pMWin->eExclude==TK_GROUP || pMWin->eExclude==TK_TIES || pMWin->eExclude==TK_NO ); lblWhereEnd = sqlite3VdbeMakeLabel(pParse); /* Fill in the context object */ memset(&s, 0, sizeof(WindowCodeArg)); s.pParse = pParse; s.pMWin = pMWin; s.pVdbe = v; s.regGosub = regGosub; s.addrGosub = addrGosub; s.current.csr = pMWin->iEphCsr; csrWrite = s.current.csr+1; s.start.csr = s.current.csr+2; s.end.csr = s.current.csr+3; /* Figure out when rows may be deleted from the ephemeral table. There ** are four options - they may never be deleted (eDelete==0), they may ** be deleted as soon as they are no longer part of the window frame ** (eDelete==WINDOW_AGGINVERSE), they may be deleted as after the row ** has been returned to the caller (WINDOW_RETURN_ROW), or they may ** be deleted after they enter the frame (WINDOW_AGGSTEP). */ switch( pMWin->eStart ){ case TK_FOLLOWING: if( pMWin->eFrmType!=TK_RANGE && windowExprGtZero(pParse, pMWin->pStart) ){ s.eDelete = WINDOW_RETURN_ROW; } break; case TK_UNBOUNDED: if( windowCacheFrame(pMWin)==0 ){ if( pMWin->eEnd==TK_PRECEDING ){ if( pMWin->eFrmType!=TK_RANGE && windowExprGtZero(pParse, pMWin->pEnd) ){ s.eDelete = WINDOW_AGGSTEP; } }else{ s.eDelete = WINDOW_RETURN_ROW; } } break; default: s.eDelete = WINDOW_AGGINVERSE; break; } /* Allocate registers for the array of values from the sub-query, the ** samve values in record form, and the rowid used to insert said record ** into the ephemeral table. */ regNew = pParse->nMem+1; pParse->nMem += nInput; regRecord = ++pParse->nMem; s.regRowid = ++pParse->nMem; /* If the window frame contains an "<expr> PRECEDING" or "<expr> FOLLOWING" ** clause, allocate registers to store the results of evaluating each ** <expr>. */ if( pMWin->eStart==TK_PRECEDING || pMWin->eStart==TK_FOLLOWING ){ regStart = ++pParse->nMem; } if( pMWin->eEnd==TK_PRECEDING || pMWin->eEnd==TK_FOLLOWING ){ regEnd = ++pParse->nMem; } /* If this is not a "ROWS BETWEEN ..." frame, then allocate arrays of ** registers to store copies of the ORDER BY expressions (peer values) ** for the main loop, and for each cursor (start, current and end). */ if( pMWin->eFrmType!=TK_ROWS ){ int nPeer = (pOrderBy ? pOrderBy->nExpr : 0); regNewPeer = regNew + pMWin->nBufferCol; if( pMWin->pPartition ) regNewPeer += pMWin->pPartition->nExpr; regPeer = pParse->nMem+1; pParse->nMem += nPeer; s.start.reg = pParse->nMem+1; pParse->nMem += nPeer; s.current.reg = pParse->nMem+1; pParse->nMem += nPeer; s.end.reg = pParse->nMem+1; pParse->nMem += nPeer; } /* Load the column values for the row returned by the sub-select ** into an array of registers starting at regNew. Assemble them into ** a record in register regRecord. */ for(iInput=0; iInput<nInput; iInput++){ sqlite3VdbeAddOp3(v, OP_Column, csrInput, iInput, regNew+iInput); } sqlite3VdbeAddOp3(v, OP_MakeRecord, regNew, nInput, regRecord); /* An input row has just been read into an array of registers starting ** at regNew. If the window has a PARTITION clause, this block generates ** VM code to check if the input row is the start of a new partition. ** If so, it does an OP_Gosub to an address to be filled in later. The ** address of the OP_Gosub is stored in local variable addrGosubFlush. */ if( pMWin->pPartition ){ int addr; ExprList *pPart = pMWin->pPartition; int nPart = pPart->nExpr; int regNewPart = regNew + pMWin->nBufferCol; KeyInfo *pKeyInfo = sqlite3KeyInfoFromExprList(pParse, pPart, 0, 0); regFlushPart = ++pParse->nMem; addr = sqlite3VdbeAddOp3(v, OP_Compare, regNewPart, pMWin->regPart, nPart); sqlite3VdbeAppendP4(v, (void*)pKeyInfo, P4_KEYINFO); sqlite3VdbeAddOp3(v, OP_Jump, addr+2, addr+4, addr+2); VdbeCoverageEqNe(v); addrGosubFlush = sqlite3VdbeAddOp1(v, OP_Gosub, regFlushPart); VdbeComment((v, "call flush_partition")); sqlite3VdbeAddOp3(v, OP_Copy, regNewPart, pMWin->regPart, nPart-1); } /* Insert the new row into the ephemeral table */ sqlite3VdbeAddOp2(v, OP_NewRowid, csrWrite, s.regRowid); sqlite3VdbeAddOp3(v, OP_Insert, csrWrite, regRecord, s.regRowid); addrNe = sqlite3VdbeAddOp3(v, OP_Ne, pMWin->regOne, 0, s.regRowid); VdbeCoverageNeverNull(v); /* This block is run for the first row of each partition */ s.regArg = windowInitAccum(pParse, pMWin); if( regStart ){ sqlite3ExprCode(pParse, pMWin->pStart, regStart); windowCheckValue(pParse, regStart, 0 + (pMWin->eFrmType==TK_RANGE?3:0)); } if( regEnd ){ sqlite3ExprCode(pParse, pMWin->pEnd, regEnd); windowCheckValue(pParse, regEnd, 1 + (pMWin->eFrmType==TK_RANGE?3:0)); } if( pMWin->eFrmType!=TK_RANGE && pMWin->eStart==pMWin->eEnd && regStart ){ int op = ((pMWin->eStart==TK_FOLLOWING) ? OP_Ge : OP_Le); int addrGe = sqlite3VdbeAddOp3(v, op, regStart, 0, regEnd); VdbeCoverageNeverNullIf(v, op==OP_Ge); /* NeverNull because bound <expr> */ VdbeCoverageNeverNullIf(v, op==OP_Le); /* values previously checked */ windowAggFinal(&s, 0); sqlite3VdbeAddOp2(v, OP_Rewind, s.current.csr, 1); VdbeCoverageNeverTaken(v); windowReturnOneRow(&s); sqlite3VdbeAddOp1(v, OP_ResetSorter, s.current.csr); sqlite3VdbeAddOp2(v, OP_Goto, 0, lblWhereEnd); sqlite3VdbeJumpHere(v, addrGe); } if( pMWin->eStart==TK_FOLLOWING && pMWin->eFrmType!=TK_RANGE && regEnd ){ assert( pMWin->eEnd==TK_FOLLOWING ); sqlite3VdbeAddOp3(v, OP_Subtract, regStart, regEnd, regStart); } if( pMWin->eStart!=TK_UNBOUNDED ){ sqlite3VdbeAddOp2(v, OP_Rewind, s.start.csr, 1); VdbeCoverageNeverTaken(v); } sqlite3VdbeAddOp2(v, OP_Rewind, s.current.csr, 1); VdbeCoverageNeverTaken(v); sqlite3VdbeAddOp2(v, OP_Rewind, s.end.csr, 1); VdbeCoverageNeverTaken(v); if( regPeer && pOrderBy ){ sqlite3VdbeAddOp3(v, OP_Copy, regNewPeer, regPeer, pOrderBy->nExpr-1); sqlite3VdbeAddOp3(v, OP_Copy, regPeer, s.start.reg, pOrderBy->nExpr-1); sqlite3VdbeAddOp3(v, OP_Copy, regPeer, s.current.reg, pOrderBy->nExpr-1); sqlite3VdbeAddOp3(v, OP_Copy, regPeer, s.end.reg, pOrderBy->nExpr-1); } sqlite3VdbeAddOp2(v, OP_Goto, 0, lblWhereEnd); sqlite3VdbeJumpHere(v, addrNe); /* Beginning of the block executed for the second and subsequent rows. */ if( regPeer ){ windowIfNewPeer(pParse, pOrderBy, regNewPeer, regPeer, lblWhereEnd); } if( pMWin->eStart==TK_FOLLOWING ){ windowCodeOp(&s, WINDOW_AGGSTEP, 0, 0); if( pMWin->eEnd!=TK_UNBOUNDED ){ if( pMWin->eFrmType==TK_RANGE ){ int lbl = sqlite3VdbeMakeLabel(pParse); int addrNext = sqlite3VdbeCurrentAddr(v); windowCodeRangeTest(&s, OP_Ge, s.current.csr, regEnd, s.end.csr, lbl); windowCodeOp(&s, WINDOW_AGGINVERSE, regStart, 0); windowCodeOp(&s, WINDOW_RETURN_ROW, 0, 0); sqlite3VdbeAddOp2(v, OP_Goto, 0, addrNext); sqlite3VdbeResolveLabel(v, lbl); }else{ windowCodeOp(&s, WINDOW_RETURN_ROW, regEnd, 0); windowCodeOp(&s, WINDOW_AGGINVERSE, regStart, 0); } } }else if( pMWin->eEnd==TK_PRECEDING ){ int bRPS = (pMWin->eStart==TK_PRECEDING && pMWin->eFrmType==TK_RANGE); windowCodeOp(&s, WINDOW_AGGSTEP, regEnd, 0); if( bRPS ) windowCodeOp(&s, WINDOW_AGGINVERSE, regStart, 0); windowCodeOp(&s, WINDOW_RETURN_ROW, 0, 0); if( !bRPS ) windowCodeOp(&s, WINDOW_AGGINVERSE, regStart, 0); }else{ int addr = 0; windowCodeOp(&s, WINDOW_AGGSTEP, 0, 0); if( pMWin->eEnd!=TK_UNBOUNDED ){ if( pMWin->eFrmType==TK_RANGE ){ int lbl = 0; addr = sqlite3VdbeCurrentAddr(v); if( regEnd ){ lbl = sqlite3VdbeMakeLabel(pParse); windowCodeRangeTest(&s, OP_Ge, s.current.csr, regEnd, s.end.csr, lbl); } windowCodeOp(&s, WINDOW_RETURN_ROW, 0, 0); windowCodeOp(&s, WINDOW_AGGINVERSE, regStart, 0); if( regEnd ){ sqlite3VdbeAddOp2(v, OP_Goto, 0, addr); sqlite3VdbeResolveLabel(v, lbl); } }else{ if( regEnd ){ addr = sqlite3VdbeAddOp3(v, OP_IfPos, regEnd, 0, 1); VdbeCoverage(v); } windowCodeOp(&s, WINDOW_RETURN_ROW, 0, 0); windowCodeOp(&s, WINDOW_AGGINVERSE, regStart, 0); if( regEnd ) sqlite3VdbeJumpHere(v, addr); } } } /* End of the main input loop */ sqlite3VdbeResolveLabel(v, lblWhereEnd); sqlite3WhereEnd(pWInfo); /* Fall through */ if( pMWin->pPartition ){ addrInteger = sqlite3VdbeAddOp2(v, OP_Integer, 0, regFlushPart); sqlite3VdbeJumpHere(v, addrGosubFlush); } s.regRowid = 0; addrEmpty = sqlite3VdbeAddOp1(v, OP_Rewind, csrWrite); VdbeCoverage(v); if( pMWin->eEnd==TK_PRECEDING ){ int bRPS = (pMWin->eStart==TK_PRECEDING && pMWin->eFrmType==TK_RANGE); windowCodeOp(&s, WINDOW_AGGSTEP, regEnd, 0); if( bRPS ) windowCodeOp(&s, WINDOW_AGGINVERSE, regStart, 0); windowCodeOp(&s, WINDOW_RETURN_ROW, 0, 0); }else if( pMWin->eStart==TK_FOLLOWING ){ int addrStart; int addrBreak1; int addrBreak2; int addrBreak3; windowCodeOp(&s, WINDOW_AGGSTEP, 0, 0); if( pMWin->eFrmType==TK_RANGE ){ addrStart = sqlite3VdbeCurrentAddr(v); addrBreak2 = windowCodeOp(&s, WINDOW_AGGINVERSE, regStart, 1); addrBreak1 = windowCodeOp(&s, WINDOW_RETURN_ROW, 0, 1); }else if( pMWin->eEnd==TK_UNBOUNDED ){ addrStart = sqlite3VdbeCurrentAddr(v); addrBreak1 = windowCodeOp(&s, WINDOW_RETURN_ROW, regStart, 1); addrBreak2 = windowCodeOp(&s, WINDOW_AGGINVERSE, 0, 1); }else{ assert( pMWin->eEnd==TK_FOLLOWING ); addrStart = sqlite3VdbeCurrentAddr(v); addrBreak1 = windowCodeOp(&s, WINDOW_RETURN_ROW, regEnd, 1); addrBreak2 = windowCodeOp(&s, WINDOW_AGGINVERSE, regStart, 1); } sqlite3VdbeAddOp2(v, OP_Goto, 0, addrStart); sqlite3VdbeJumpHere(v, addrBreak2); addrStart = sqlite3VdbeCurrentAddr(v); addrBreak3 = windowCodeOp(&s, WINDOW_RETURN_ROW, 0, 1); sqlite3VdbeAddOp2(v, OP_Goto, 0, addrStart); sqlite3VdbeJumpHere(v, addrBreak1); sqlite3VdbeJumpHere(v, addrBreak3); }else{ int addrBreak; int addrStart; windowCodeOp(&s, WINDOW_AGGSTEP, 0, 0); addrStart = sqlite3VdbeCurrentAddr(v); addrBreak = windowCodeOp(&s, WINDOW_RETURN_ROW, 0, 1); windowCodeOp(&s, WINDOW_AGGINVERSE, regStart, 0); sqlite3VdbeAddOp2(v, OP_Goto, 0, addrStart); sqlite3VdbeJumpHere(v, addrBreak); } sqlite3VdbeJumpHere(v, addrEmpty); sqlite3VdbeAddOp1(v, OP_ResetSorter, s.current.csr); if( pMWin->pPartition ){ if( pMWin->regStartRowid ){ sqlite3VdbeAddOp2(v, OP_Integer, 1, pMWin->regStartRowid); sqlite3VdbeAddOp2(v, OP_Integer, 0, pMWin->regEndRowid); } sqlite3VdbeChangeP1(v, addrInteger, sqlite3VdbeCurrentAddr(v)); sqlite3VdbeAddOp1(v, OP_Return, regFlushPart); } } #endif /* SQLITE_OMIT_WINDOWFUNC */ |
Changes to test/affinity2.test.
︙ | ︙ | |||
10 11 12 13 14 15 16 17 18 19 20 21 22 23 | #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this file is type affinity in comparison operations. # set testdir [file dirname $argv0] source $testdir/tester.tcl do_execsql_test affinity2-100 { CREATE TABLE t1( xi INTEGER, xr REAL, xb BLOB, xn NUMERIC, | > | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this file is type affinity in comparison operations. # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix affinity2 do_execsql_test affinity2-100 { CREATE TABLE t1( xi INTEGER, xr REAL, xb BLOB, xn NUMERIC, |
︙ | ︙ | |||
53 54 55 56 57 58 59 60 61 | do_execsql_test affinity2-220 { SELECT rowid, xn==xt, xn==xb, xn==+xt FROM t1 ORDER BY rowid; } {1 1 1 1 2 1 1 1 3 1 1 1} do_execsql_test affinity2-300 { SELECT rowid, xt==+xi, xt==xi, xt==xb FROM t1 ORDER BY rowid; } {1 1 1 0 2 1 1 1 3 0 1 1} finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | do_execsql_test affinity2-220 { SELECT rowid, xn==xt, xn==xb, xn==+xt FROM t1 ORDER BY rowid; } {1 1 1 1 2 1 1 1 3 1 1 1} do_execsql_test affinity2-300 { SELECT rowid, xt==+xi, xt==xi, xt==xb FROM t1 ORDER BY rowid; } {1 1 1 0 2 1 1 1 3 0 1 1} #------------------------------------------------------------------------- do_execsql_test 400 { CREATE TABLE ttt(c0, c1); CREATE INDEX ii ON ttt(CAST(c0 AS NUMERIC)); INSERT INTO ttt VALUES('abc', '-1'); } do_execsql_test 410 { SELECT * FROM ttt WHERE CAST(c0 AS NUMERIC) > c1 GROUP BY rowid; } {abc -1} do_execsql_test 420 { SELECT * FROM ttt INDEXED BY ii WHERE CAST(c0 AS NUMERIC) > c1 GROUP BY rowid; } {abc -1} do_execsql_test 430 { CREATE TABLE t3(a, b, c INTEGER); CREATE INDEX t3ac ON t3(a, c-1); INSERT INTO t3 VALUES(1, 1, 1); INSERT INTO t3 VALUES(2, 1, 0); INSERT INTO t3 VALUES(3, 1, 1); INSERT INTO t3 VALUES(4, 1, 0); INSERT INTO t3 VALUES(5, 1, 1); } do_execsql_test 440 { SELECT * FROM t3 WHERE c='0' ORDER BY a; } {2 1 0 4 1 0} # 2019-08-22 ticket https://sqlite.org/src/info/d99f1ffe836c591ac57f # False positive in sqlite3ExprNeedsNoAffinityChange() # do_execsql_test 500 { DROP TABLE IF EXISTS t0; CREATE TABLE t0(c0 TEXT UNIQUE, c1); INSERT INTO t0(c0) VALUES (-1); SELECT quote(- x'ce'), quote(t0.c0), quote(- x'ce' >= t0.c0) FROM t0; } {0 '-1' 1} do_execsql_test 501 { SELECT * FROM t0 WHERE - x'ce' >= t0.c0; } {-1 {}} do_execsql_test 502 { SELECT quote(+-+x'ce'), quote(t0.c0), quote(+-+x'ce' >= t0.c0) FROM t0; } {0 '-1' 1} do_execsql_test 503 { SELECT * FROM t0 WHERE +-+x'ce' >= t0.c0; } {-1 {}} do_execsql_test 504 { SELECT quote(- 'ce'), quote(t0.c0), quote(- 'ce' >= t0.c0) FROM t0; } {0 '-1' 1} do_execsql_test 505 { SELECT * FROM t0 WHERE - 'ce' >= t0.c0; } {-1 {}} do_execsql_test 506 { SELECT quote(+-+'ce'), quote(t0.c0), quote(+-+'ce' >= t0.c0) FROM t0; } {0 '-1' 1} do_execsql_test 507 { SELECT * FROM t0 WHERE +-+'ce' >= t0.c0; } {-1 {}} # 2019-08-30 ticket https://www.sqlite.org/src/info/40812aea1fde9594 # # Due to some differences in floating point computations, these tests do not # work under valgrind. # if {![info exists ::G(valgrind)]} { do_execsql_test 600 { DROP TABLE IF EXISTS t0; CREATE TABLE t0(c0 REAL UNIQUE); INSERT INTO t0(c0) VALUES (3175546974276630385); SELECT 3175546974276630385 < c0 FROM t0; } {1} do_execsql_test 601 { SELECT 1 FROM t0 WHERE 3175546974276630385 < c0; } {1} } finish_test |
Changes to test/affinity3.test.
︙ | ︙ | |||
68 69 70 71 72 73 74 | INSERT INTO data VALUES('4','xyz'); CREATE VIEW idmap as SELECT * FROM map_integer UNION SELECT * FROM map_text; CREATE TABLE mzed AS SELECT * FROM idmap; } | | | | | | 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 | INSERT INTO data VALUES('4','xyz'); CREATE VIEW idmap as SELECT * FROM map_integer UNION SELECT * FROM map_text; CREATE TABLE mzed AS SELECT * FROM idmap; } #do_execsql_test affinity3-210 { #PRAGMA automatic_index=ON; #SELECT * FROM data JOIN idmap USING(id); #} {1 abc a 4 xyz e} do_execsql_test affinity3-220 { SELECT * FROM data JOIN mzed USING(id); } {1 abc a 4 xyz e} do_execsql_test affinity3-250 { PRAGMA automatic_index=OFF; SELECT * FROM data JOIN idmap USING(id); |
︙ | ︙ |
Changes to test/aggnested.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 | # 2012-08-23 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. # # This file implements tests for processing aggregate queries with # subqueries in which the subqueries hold the aggregate functions # or in which the subqueries are themselves aggregate queries # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix aggnested do_test aggnested-1.1 { db eval { CREATE TABLE t1(a1 INTEGER); INSERT INTO t1 VALUES(1), (2), (3); CREATE TABLE t2(b1 INTEGER); INSERT INTO t2 VALUES(4), (5); |
︙ | ︙ | |||
228 229 230 231 232 233 234 | do_test aggnested-3.16 { db eval { SELECT max(value1), (SELECT sum(value2=value1) FROM t2) FROM t1 GROUP BY id1; } } {12 2 34 4} | | > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | do_test aggnested-3.16 { db eval { SELECT max(value1), (SELECT sum(value2=value1) FROM t2) FROM t1 GROUP BY id1; } } {12 2 34 4} # 2019-08-31 # Problem found by dbsqlfuzz # do_execsql_test aggnested-4.1 { DROP TABLE IF EXISTS aa; DROP TABLE IF EXISTS bb; CREATE TABLE aa(x INT); INSERT INTO aa(x) VALUES(123); CREATE TABLE bb(y INT); INSERT INTO bb(y) VALUES(456); SELECT (SELECT sum(x+(SELECT y)) FROM bb) FROM aa; } {579} do_execsql_test aggnested-4.2 { SELECT (SELECT sum(x+y) FROM bb) FROM aa; } {579} do_execsql_test aggnested-4.3 { DROP TABLE IF EXISTS tx; DROP TABLE IF EXISTS ty; CREATE TABLE tx(x INT); INSERT INTO tx VALUES(1),(2),(3),(4),(5); CREATE TABLE ty(y INT); INSERT INTO ty VALUES(91),(92),(93); SELECT min((SELECT count(y) FROM ty)) FROM tx; } {3} do_execsql_test aggnested-4.4 { SELECT max((SELECT a FROM (SELECT count(*) AS a FROM ty) AS s)) FROM tx; } {3} #-------------------------------------------------------------------------- # reset_db do_execsql_test 5.0 { CREATE TABLE x1(a, b); INSERT INTO x1 VALUES(1, 2); CREATE TABLE x2(x); INSERT INTO x2 VALUES(NULL), (NULL), (NULL); } # At one point, aggregate "total()" in the query below was being processed # as part of the outer SELECT, not as part of the sub-select with no FROM # clause. do_execsql_test 5.1 { SELECT ( SELECT total( (SELECT b FROM x1) ) ) FROM x2; } {2.0 2.0 2.0} do_execsql_test 5.2 { SELECT ( SELECT total( (SELECT 2 FROM x1) ) ) FROM x2; } {2.0 2.0 2.0} do_execsql_test 5.3 { CREATE TABLE t1(a); CREATE TABLE t2(b); } do_execsql_test 5.4 { SELECT( SELECT max(b) LIMIT ( SELECT total( (SELECT a FROM t1) ) ) ) FROM t2; } {{}} do_execsql_test 5.5 { CREATE TABLE a(b); WITH c AS(SELECT a) SELECT(SELECT(SELECT group_concat(b, b) LIMIT(SELECT 0.100000 * AVG(DISTINCT(SELECT 0 FROM a ORDER BY b, b, b)))) FROM a GROUP BY b, b, b) FROM a EXCEPT SELECT b FROM a ORDER BY b, b, b; } #------------------------------------------------------------------------- # dbsqlfuzz a779227f721a834df95f4f42d0c31550a1f8b8a2 # reset_db do_execsql_test 6.0 { CREATE TABLE t1(a); CREATE TABLE t2(b); INSERT INTO t1 VALUES('x'); INSERT INTO t2 VALUES(1); } do_execsql_test 6.1.1 { SELECT ( SELECT t2.b FROM (SELECT t2.b AS c FROM t1) GROUP BY 1 HAVING t2.b ) FROM t2 GROUP BY 'constant_string'; } {1} do_execsql_test 6.1.2 { SELECT ( SELECT c FROM (SELECT t2.b AS c FROM t1) GROUP BY c HAVING t2.b ) FROM t2 GROUP BY 'constant_string'; } {1} do_execsql_test 6.2.0 { UPDATE t2 SET b=0 } do_execsql_test 6.2.1 { SELECT ( SELECT t2.b FROM (SELECT t2.b AS c FROM t1) GROUP BY 1 HAVING t2.b ) FROM t2 GROUP BY 'constant_string'; } {{}} do_execsql_test 6.2.2 { SELECT ( SELECT c FROM (SELECT t2.b AS c FROM t1) GROUP BY c HAVING t2.b ) FROM t2 GROUP BY 'constant_string'; } {{}} finish_test |
Changes to test/alter.test.
︙ | ︙ | |||
680 681 682 683 684 685 686 | } } {1 18 2 9} #-------------------------------------------------------------------------- # alter-9.X - Special test: Make sure the sqlite_rename_column() and # rename_table() functions do not crash when handed bad input. # | | | | 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 | } } {1 18 2 9} #-------------------------------------------------------------------------- # alter-9.X - Special test: Make sure the sqlite_rename_column() and # rename_table() functions do not crash when handed bad input. # sqlite3_test_control SQLITE_TESTCTRL_INTERNAL_FUNCTIONS db do_test alter-9.1 { execsql {SELECT SQLITE_RENAME_COLUMN(0,0,0,0,0,0,0,0,0)} } {{}} foreach {tn sql} { 1 { SELECT SQLITE_RENAME_TABLE(0,0,0,0,0,0,0) } 2 { SELECT SQLITE_RENAME_TABLE(10,20,30,40,50,60,70) } 3 { SELECT SQLITE_RENAME_TABLE('foo','foo','foo','foo','foo','foo','foo') } } { do_test alter-9.2.$tn { catch { execsql $sql } } 1 } sqlite3_test_control SQLITE_TESTCTRL_INTERNAL_FUNCTIONS db # If the INTERNAL_FUNCTIONS test-control is disabled (which is the default), # then the sqlite_rename_table() SQL function is not accessible to ordinary SQL. # do_catchsql_test alter-9.3 { SELECT sqlite_rename_table(0,0,0,0,0,0,0); } {1 {no such function: sqlite_rename_table}} |
︙ | ︙ | |||
836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 | } } {t3102a_rename t3102b_rename t3102c} # Ticket #3651 do_test alter-14.1 { catchsql { CREATE TABLE t3651(a UNIQUE); ALTER TABLE t3651 ADD COLUMN b UNIQUE; } } {1 {Cannot add a UNIQUE column}} do_test alter-14.2 { catchsql { ALTER TABLE t3651 ADD COLUMN b PRIMARY KEY; } } {1 {Cannot add a PRIMARY KEY column}} #------------------------------------------------------------------------- # Test that it is not possible to use ALTER TABLE on any system table. # set system_table_list {1 sqlite_master} catchsql ANALYZE ifcapable analyze { lappend system_table_list 2 sqlite_stat1 } | > < | 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 | } } {t3102a_rename t3102b_rename t3102c} # Ticket #3651 do_test alter-14.1 { catchsql { CREATE TABLE t3651(a UNIQUE); INSERT INTO t3651 VALUES(5); ALTER TABLE t3651 ADD COLUMN b UNIQUE; } } {1 {Cannot add a UNIQUE column}} do_test alter-14.2 { catchsql { ALTER TABLE t3651 ADD COLUMN b PRIMARY KEY; } } {1 {Cannot add a PRIMARY KEY column}} #------------------------------------------------------------------------- # Test that it is not possible to use ALTER TABLE on any system table. # set system_table_list {1 sqlite_master} catchsql ANALYZE ifcapable analyze { lappend system_table_list 2 sqlite_stat1 } ifcapable stat4 { lappend system_table_list 4 sqlite_stat4 } foreach {tn tbl} $system_table_list { do_test alter-15.$tn.1 { catchsql "ALTER TABLE $tbl RENAME TO xyz" } [list 1 "table $tbl may not be altered"] |
︙ | ︙ | |||
898 899 900 901 902 903 904 905 906 | DELETE FROM t2 WHERE id = OLD.a; END; ALTER TABLE t1 RENAME TO t3; UPDATE t3 SET b='peach' WHERE a=2; SELECT * FROM t2 ORDER BY 1; } {1 1.0 2.0 3 1.5 3.5} } finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | DELETE FROM t2 WHERE id = OLD.a; END; ALTER TABLE t1 RENAME TO t3; UPDATE t3 SET b='peach' WHERE a=2; SELECT * FROM t2 ORDER BY 1; } {1 1.0 2.0 3 1.5 3.5} } # 2021-03-08 dbsqlfuzz 3f0a7245b69cd08617d7d7781ebaedb0fe765a93 reset_db do_catchsql_test alter-18.1 { CREATE TABLE t1(a,b,c); CREATE TABLE log(a INTEGER PRIMARY KEY,b,c); CREATE TRIGGER tr1 AFTER INSERT ON t1 BEGIN INSERT INTO logx(a,b,c) VALUES(new.a,new.b,new.c) ON CONFLICT(a) DO UPDATE SET c=excluded.c, b=new.b; END; ALTER TABLE log RENAME COLUMN a TO x; } {1 {error in trigger tr1: no such table: main.logx}} # 2021-10-13 dbsqlfuzz e89174cbfad2d904f06b5e24df0a22510b6a1c1e reset_db do_execsql_test alter-19.1 { CREATE TABLE t1(x); CREATE TABLE t2(c); CREATE TRIGGER r1 AFTER INSERT ON t2 BEGIN UPDATE t2 SET (c)=( EXISTS(SELECT 1 WHERE (WITH cte1(a) AS (SELECT 1 FROM t1 WHERE (SELECT 1 WHERE (WITH cte2(b) AS (VALUES(1))SELECT b FROM cte2)))SELECT a FROM cte1)) ); END; ALTER TABLE t2 RENAME TO t3; } {} do_execsql_test alter-19.2 { SELECT name FROM sqlite_schema WHERE sql LIKE '%t2%'; } {} do_execsql_test alter-19.3 { SELECT name FROM sqlite_schema WHERE sql LIKE '%t3%' ORDER BY name; } {r1 t3} finish_test |
Changes to test/alter3.test.
︙ | ︙ | |||
9 10 11 12 13 14 15 | # #************************************************************************* # This file implements regression tests for SQLite library. The # focus of this script is testing that SQLite can handle a subtle # file format change that may be used in the future to implement # "ALTER TABLE ... ADD COLUMN". # | < < | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | # #************************************************************************* # This file implements regression tests for SQLite library. The # focus of this script is testing that SQLite can handle a subtle # file format change that may be used in the future to implement # "ALTER TABLE ... ADD COLUMN". # set testdir [file dirname $argv0] source $testdir/tester.tcl # If SQLITE_OMIT_ALTERTABLE is defined, omit this file. ifcapable !altertable { |
︙ | ︙ | |||
50 51 52 53 54 55 56 57 | # This procedure returns the value of the file-format in file 'test.db'. # proc get_file_format {{fname test.db}} { return [hexio_get_int [hexio_read $fname 44 4]] } do_test alter3-1.1 { execsql { | > < | 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | # This procedure returns the value of the file-format in file 'test.db'. # proc get_file_format {{fname test.db}} { return [hexio_get_int [hexio_read $fname 44 4]] } do_test alter3-1.1 { sqlite3_db_config db LEGACY_FILE_FORMAT 1 execsql { CREATE TABLE abc(a, b, c); SELECT sql FROM sqlite_master; } } {{CREATE TABLE abc(a, b, c)}} do_test alter3-1.2 { execsql {ALTER TABLE abc ADD d INTEGER;} execsql { |
︙ | ︙ | |||
112 113 114 115 116 117 118 119 120 121 122 123 124 125 | DROP TABLE t3; } } {} do_test alter3-2.1 { execsql { CREATE TABLE t1(a, b); } catchsql { ALTER TABLE t1 ADD c PRIMARY KEY; } } {1 {Cannot add a PRIMARY KEY column}} do_test alter3-2.2 { catchsql { | > | 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 | DROP TABLE t3; } } {} do_test alter3-2.1 { execsql { CREATE TABLE t1(a, b); INSERT INTO t1 VALUES(1,2); } catchsql { ALTER TABLE t1 ADD c PRIMARY KEY; } } {1 {Cannot add a PRIMARY KEY column}} do_test alter3-2.2 { catchsql { |
︙ | ︙ | |||
194 195 196 197 198 199 200 201 | } {11} } do_test alter3-4.1 { db close forcedelete test.db set ::DB [sqlite3 db test.db] execsql { | > < | 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 | } {11} } do_test alter3-4.1 { db close forcedelete test.db set ::DB [sqlite3 db test.db] sqlite3_db_config db LEGACY_FILE_FORMAT 1 execsql { CREATE TABLE t1(a, b); INSERT INTO t1 VALUES(1, 100); INSERT INTO t1 VALUES(2, 300); SELECT * FROM t1; } } {1 100 2 300} do_test alter3-4.1 { |
︙ | ︙ | |||
389 390 391 392 393 394 395 396 397 | list } {} do_test alter3-8.2 { execsql { SELECT sql FROM sqlite_master WHERE name = 't4'; } } [list $::sql] finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 | list } {} do_test alter3-8.2 { execsql { SELECT sql FROM sqlite_master WHERE name = 't4'; } } [list $::sql] # 2021-07-20: Add support for detecting CHECK and NOT NULL constraint # violations in ALTER TABLE ADD COLUMN # reset_db do_execsql_test alter3-9.1 { CREATE TABLE t1(a,b); INSERT INTO t1 VALUES(1, 2), ('null!',NULL), (3,4); } {} do_catchsql_test alter3-9.2 { ALTER TABLE t1 ADD COLUMN c CHECK(a!=1); } {1 {CHECK constraint failed}} do_catchsql_test alter3-9.3 { ALTER TABLE t1 ADD COLUMN c CHECK(a!=3); } {1 {CHECK constraint failed}} do_catchsql_test alter3-9.4 { ALTER TABLE t1 ADD COLUMN c CHECK(a!=2); } {0 {}} do_catchsql_test alter3-9.5 { ALTER TABLE t1 ADD COLUMN d AS (b+1) NOT NULL; } {1 {NOT NULL constraint failed}} do_catchsql_test alter3-9.6 { ALTER TABLE t1 ADD COLUMN d AS (b+1) NOT NULL CHECK(a!=1); } {1 {CHECK constraint failed}} do_catchsql_test alter3-9.7 { ALTER TABLE t1 ADD COLUMN d AS (b+1) NOT NULL CHECK(a!=3); } {1 {NOT NULL constraint failed}} do_execsql_test alter3-9.10 { CREATE TEMP TABLE t0(m,n); INSERT INTO t0 VALUES(1, 2), ('null!',NULL), (3,4); ATTACH ':memory:' AS aux1; CREATE TABLE aux1.t2(x,y); INSERT INTO t2 VALUES(1, 2), ('null!',NULL), (3,4); } {} do_catchsql_test alter3-9.11 { ALTER TABLE t0 ADD COLUMN xtra1 AS (n+1) NOT NULL CHECK(m!=1); } {1 {CHECK constraint failed}} do_catchsql_test alter3-9.12 { ALTER TABLE t0 ADD COLUMN xtra1 AS (n+1) NOT NULL CHECK(m!=3); } {1 {NOT NULL constraint failed}} do_catchsql_test alter3-9.13 { ALTER TABLE t2 ADD COLUMN xtra1 AS (y+1) NOT NULL CHECK(x!=1); } {1 {CHECK constraint failed}} do_catchsql_test alter3-9.14 { ALTER TABLE t2 ADD COLUMN xtra1 AS (y+1) NOT NULL CHECK(x!=3); } {1 {NOT NULL constraint failed}} finish_test |
Changes to test/alter4.test.
︙ | ︙ | |||
119 120 121 122 123 124 125 126 127 128 129 130 131 132 | DROP TABLE t3; } } {} do_test alter4-2.1 { execsql { CREATE TABLE temp.t1(a, b); } catchsql { ALTER TABLE t1 ADD c PRIMARY KEY; } } {1 {Cannot add a PRIMARY KEY column}} do_test alter4-2.2 { catchsql { | > | 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 | DROP TABLE t3; } } {} do_test alter4-2.1 { execsql { CREATE TABLE temp.t1(a, b); INSERT INTO t1 VALUES(1,2); } catchsql { ALTER TABLE t1 ADD c PRIMARY KEY; } } {1 {Cannot add a PRIMARY KEY column}} do_test alter4-2.2 { catchsql { |
︙ | ︙ | |||
313 314 315 316 317 318 319 | INSERT INTO log VALUES('a', new.a, new.b); END; CREATE TEMP TRIGGER t1_b AFTER INSERT ON t1 BEGIN INSERT INTO log VALUES('b', new.a, new.b); END; INSERT INTO t1 VALUES(1, 2); | | | | | | 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 | INSERT INTO log VALUES('a', new.a, new.b); END; CREATE TEMP TRIGGER t1_b AFTER INSERT ON t1 BEGIN INSERT INTO log VALUES('b', new.a, new.b); END; INSERT INTO t1 VALUES(1, 2); SELECT * FROM log ORDER BY trig, a, b; } } {a 1 2 b 1 2} do_test alter4-6.2 { execsql { ALTER TABLE t1 ADD COLUMN c DEFAULT 'c'; INSERT INTO t1(a, b) VALUES(3, 4); SELECT * FROM log ORDER BY trig, a, b; } } {a 1 2 a 3 4 b 1 2 b 3 4} } # Ticket #1183 - Make sure adding columns to large tables does not cause # memory corruption (as was the case before this bug was fixed). do_test alter4-8.1 { execsql { CREATE TEMP TABLE t4(c1); |
︙ | ︙ | |||
379 380 381 382 383 384 385 386 | # does not corrupt DESC indexes. # # Ticket https://www.sqlite.org/src/tktview/f68bf68513a1c # do_test alter4-10.1 { db close sqlite3 db :memory: db eval { | > < > | 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 | # does not corrupt DESC indexes. # # Ticket https://www.sqlite.org/src/tktview/f68bf68513a1c # do_test alter4-10.1 { db close sqlite3 db :memory: sqlite3_db_config db LEGACY_FILE_FORMAT 1 db eval { CREATE TABLE t1(a,b,c); CREATE INDEX t1a ON t1(a DESC); INSERT INTO t1 VALUES(1,2,3); INSERT INTO t1 VALUES(2,3,4); ALTER TABLE t1 ADD COLUMN d; PRAGMA integrity_check; } } {ok} reset_db do_execsql_test alter4-11.0 { CREATE TABLE t1(c INTEGER PRIMARY KEY, d); INSERT INTO t1(c,d) VALUES(1,2); PRAGMA foreign_keys = on; ALTER TABLE t1 ADD COLUMN e; } do_execsql_test alter4-11.1 { ALTER TABLE t1 ADD COLUMN f REFERENCES t1; } |
︙ | ︙ |
Changes to test/alterauth2.test.
︙ | ︙ | |||
78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 | do_auth_test 1.2 { ALTER TABLE t2 RENAME a TO aaa; } { {SQLITE_ALTER_TABLE main t2 {} {}} {SQLITE_FUNCTION {} like {} {}} {SQLITE_FUNCTION {} sqlite_rename_column {} {}} {SQLITE_FUNCTION {} sqlite_rename_test {} {}} {SQLITE_READ sqlite_master name main {}} {SQLITE_READ sqlite_master sql main {}} {SQLITE_READ sqlite_master tbl_name main {}} {SQLITE_READ sqlite_master type main {}} {SQLITE_READ sqlite_temp_master name temp {}} {SQLITE_READ sqlite_temp_master sql temp {}} {SQLITE_READ sqlite_temp_master type temp {}} {SQLITE_SELECT {} {} {} {}} {SQLITE_UPDATE sqlite_master sql main {}} {SQLITE_UPDATE sqlite_temp_master sql temp {}} } finish_test | > > > > > > > > > > > > > > > > > > > > | 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 | do_auth_test 1.2 { ALTER TABLE t2 RENAME a TO aaa; } { {SQLITE_ALTER_TABLE main t2 {} {}} {SQLITE_FUNCTION {} like {} {}} {SQLITE_FUNCTION {} sqlite_rename_column {} {}} {SQLITE_FUNCTION {} sqlite_rename_quotefix {} {}} {SQLITE_FUNCTION {} sqlite_rename_test {} {}} {SQLITE_READ sqlite_master name main {}} {SQLITE_READ sqlite_master sql main {}} {SQLITE_READ sqlite_master tbl_name main {}} {SQLITE_READ sqlite_master type main {}} {SQLITE_READ sqlite_temp_master name temp {}} {SQLITE_READ sqlite_temp_master sql temp {}} {SQLITE_READ sqlite_temp_master type temp {}} {SQLITE_SELECT {} {} {} {}} {SQLITE_UPDATE sqlite_master sql main {}} {SQLITE_UPDATE sqlite_temp_master sql temp {}} } do_auth_test 1.3 { ALTER TABLE t2 DROP COLUMN c; } { {SQLITE_FUNCTION {} like {} {}} {SQLITE_FUNCTION {} sqlite_drop_column {} {}} {SQLITE_FUNCTION {} sqlite_rename_quotefix {} {}} {SQLITE_FUNCTION {} sqlite_rename_test {} {}} {SQLITE_READ sqlite_master name main {}} {SQLITE_READ sqlite_master sql main {}} {SQLITE_READ sqlite_master tbl_name main {}} {SQLITE_READ sqlite_master type main {}} {SQLITE_READ sqlite_temp_master name temp {}} {SQLITE_READ sqlite_temp_master sql temp {}} {SQLITE_READ sqlite_temp_master type temp {}} {SQLITE_SELECT {} {} {} {}} {SQLITE_UPDATE sqlite_master sql main {}} {SQLITE_UPDATE sqlite_temp_master sql temp {}} } finish_test |
Changes to test/altercol.test.
︙ | ︙ | |||
9 10 11 12 13 14 15 | # #************************************************************************* # This file implements regression tests for SQLite library. The # focus of this script is testing that SQLite can handle a subtle # file format change that may be used in the future to implement # "ALTER TABLE ... RENAME COLUMN ... TO". # | < < | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | # #************************************************************************* # This file implements regression tests for SQLite library. The # focus of this script is testing that SQLite can handle a subtle # file format change that may be used in the future to implement # "ALTER TABLE ... RENAME COLUMN ... TO". # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix altercol # If SQLITE_OMIT_ALTERTABLE is defined, omit this file. ifcapable !altertable { |
︙ | ︙ | |||
565 566 567 568 569 570 571 | do_execsql_test 13.1.6 { UPDATE sqlite_master SET sql = '' WHERE name='x1i'; } {} do_catchsql_test 13.1.7 { ALTER TABLE x1 RENAME COLUMN t TO ttt; | | | 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 | do_execsql_test 13.1.6 { UPDATE sqlite_master SET sql = '' WHERE name='x1i'; } {} do_catchsql_test 13.1.7 { ALTER TABLE x1 RENAME COLUMN t TO ttt; } {1 {error in index x1i: }} do_execsql_test 13.1.8 { DELETE FROM sqlite_master WHERE name = 'x1i'; } do_execsql_test 13.2.0 { CREATE TABLE data(x UNIQUE, y, z); |
︙ | ︙ | |||
614 615 616 617 618 619 620 | ALTER TABLE x1 RENAME COLUMN t TO ttt; } "1 {error in trigger tr1: $error}" } #------------------------------------------------------------------------- # Passing invalid parameters directly to sqlite_rename_column(). # | | | 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 | ALTER TABLE x1 RENAME COLUMN t TO ttt; } "1 {error in trigger tr1: $error}" } #------------------------------------------------------------------------- # Passing invalid parameters directly to sqlite_rename_column(). # sqlite3_test_control SQLITE_TESTCTRL_INTERNAL_FUNCTIONS db do_execsql_test 14.1 { CREATE TABLE ddd(sql, type, object, db, tbl, icol, znew, bquote); INSERT INTO ddd VALUES( 'CREATE TABLE x1(i INTEGER, t TEXT)', 'table', 'x1', 'main', 'x1', -1, 'zzz', 0 ), ( 'CREATE TABLE x1(i INTEGER, t TEXT)', |
︙ | ︙ | |||
637 638 639 640 641 642 643 | } {} do_execsql_test 14.2 { SELECT sqlite_rename_column(sql, type, object, db, tbl, icol, znew, bquote, 0) FROM ddd; } {{} {} {} {}} | | | 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 | } {} do_execsql_test 14.2 { SELECT sqlite_rename_column(sql, type, object, db, tbl, icol, znew, bquote, 0) FROM ddd; } {{} {} {} {}} sqlite3_test_control SQLITE_TESTCTRL_INTERNAL_FUNCTIONS db # If the INTERNAL_FUNCTIONS test-control is disabled (which is the default) # then the sqlite_rename_table() SQL function is not accessible to # ordinary SQL. # do_catchsql_test 14.3 { SELECT sqlite_rename_column(0,0,0,0,0,0,0,0,0); |
︙ | ︙ | |||
774 775 776 777 778 779 780 | do_execsql_test 19.1 { ALTER TABLE t1 RENAME a TO f; SELECT sql FROM sqlite_master WHERE name = 'v2'; } { {CREATE VIEW v2(e) AS SELECT coalesce(t2.c,t1.f) FROM t1, t2 WHERE t1.b=t2.d} } | > | > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | do_execsql_test 19.1 { ALTER TABLE t1 RENAME a TO f; SELECT sql FROM sqlite_master WHERE name = 'v2'; } { {CREATE VIEW v2(e) AS SELECT coalesce(t2.c,t1.f) FROM t1, t2 WHERE t1.b=t2.d} } # 2019-01-08: https://www.sqlite.org/src/tktview/bc8d94f0fbd633fd9a051e3 # # ALTER TABLE RENAME COLUMN does not work for tables that have redundant # UNIQUE constraints. # sqlite3 db :memory: do_execsql_test 20.100 { CREATE TABLE t1(aaa,b,c,UNIQUE(aaA),PRIMARY KEY(aAa),UNIQUE(aAA)); ALTER TABLE t1 RENAME aaa TO bbb; SELECT sql FROM sqlite_master WHERE name='t1'; } {{CREATE TABLE t1(bbb,b,c,UNIQUE(bbb),PRIMARY KEY(bbb),UNIQUE(bbb))}} do_execsql_test 20.105 { DROP TABLE t1; CREATE TABLE t1(aaa,b,c,UNIQUE(aaA),PRIMARY KEY(aAa),UNIQUE(aAA))WITHOUT ROWID; ALTER TABLE t1 RENAME aaa TO bbb; SELECT sql FROM sqlite_master WHERE name='t1'; } {{CREATE TABLE t1(bbb,b,c,UNIQUE(bbb),PRIMARY KEY(bbb),UNIQUE(bbb))WITHOUT ROWID}} do_execsql_test 20.110 { DROP TABLE t1; CREATE TABLE t1(aa UNIQUE,bb UNIQUE,cc UNIQUE,UNIQUE(aA),PRIMARY KEY(bB),UNIQUE(cC)); ALTER TABLE t1 RENAME aa TO xx; ALTER TABLE t1 RENAME bb TO yy; ALTER TABLE t1 RENAME cc TO zz; SELECT sql FROM sqlite_master WHERE name='t1'; } {{CREATE TABLE t1(xx UNIQUE,yy UNIQUE,zz UNIQUE,UNIQUE(xx),PRIMARY KEY(yy),UNIQUE(zz))}} #------------------------------------------------------------------------- reset_db do_execsql_test 21.0 { CREATE TABLE t1(a, b, c NOT NULL); CREATE TRIGGER tr1 AFTER INSERT ON t1 WHEN new.c IS NOT NULL BEGIN SELECT c NOT NULL FROM t1; END; } do_execsql_test 21.1 { ALTER TABLE t1 RENAME c TO d; } do_execsql_test 21.2 { SELECT sql FROM sqlite_schema WHERE name IS 'tr1' } {{CREATE TRIGGER tr1 AFTER INSERT ON t1 WHEN new.d IS NOT NULL BEGIN SELECT d NOT NULL FROM t1; END} } #------------------------------------------------------------------------- # reset_db do_execsql_test 22.0 { CREATE TABLE t1(a, b); CREATE TABLE t2(c, othername, extra AS (c + 1)); ALTER TABLE t1 RENAME a to othername; SELECT sql FROM sqlite_schema; } { {CREATE TABLE t1(othername, b)} {CREATE TABLE t2(c, othername, extra AS (c + 1))} } #------------------------------------------------------------------------- # reset_db do_execsql_test 22.0 { CREATE TABLE t1(a, b); CREATE INDEX x1 on t1("c"=b); INSERT INTO t1 VALUES('a', 'a'); INSERT INTO t1 VALUES('b', 'b'); INSERT INTO t1 VALUES('c', 'c'); ALTER TABLE t1 RENAME COLUMN a TO "c"; PRAGMA integrity_check; } {ok} reset_db do_execsql_test 23.0 { CREATE TABLE t1('a'"b",c); CREATE INDEX i1 ON t1('a'); INSERT INTO t1 VALUES(1,2), (3,4); ALTER TABLE t1 RENAME COLUMN a TO x; PRAGMA integrity_check; SELECT sql FROM sqlite_schema WHERE name='t1'; } {ok {CREATE TABLE t1("x" "b",c)}} finish_test |
Added test/altercorrupt.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 | # 2019-01-11 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix altercorrupt # If SQLITE_OMIT_ALTERTABLE is defined, omit this file. ifcapable !altertable { finish_test return } database_may_be_corrupt #-------------------------------------------------------------------------- reset_db do_test 1.0 { sqlite3 db {} db deserialize [decode_hexdb { .open --hexdb | size 24576 pagesize 4096 filename crash-685346d89b5e5f.db | page 1 offset 0 | 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3. | 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 06 .....@ ........ | 32: 00 00 63 00 00 05 f0 00 00 00 00 04 10 00 00 04 ..c............. | 48: 00 00 00 00 00 00 0f f0 00 00 00 01 00 00 00 00 ................ | 64: 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ | 96: 00 00 00 00 0d 0f f8 00 05 0e cf 00 0f 79 0f d3 .............y.. | 112: 0f 2e 0e f3 0e cf 00 00 00 00 00 00 00 00 00 00 ................ | 3776: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 22 ................ | 3792: 05 06 17 11 11 01 31 74 61 62 6c 65 74 34 74 34 ......1tablet4t4 | 3808: 06 43 52 45 41 54 45 20 54 41 42 4c 45 20 74 34 .CREATE TABLE t4 | 3824: 28 7a 29 39 04 06 17 11 11 01 5f 74 61 62 6c 65 (z)9......_table | 3840: 74 33 74 33 05 43 52 45 41 54 45 20 54 41 42 4c t3t3.CREATE TABL | 3856: 45 20 74 33 28 78 20 49 4e 54 45 47 45 52 20 50 E t3(x INTEGER P | 3872: 52 49 4d 41 52 59 20 4b 45 59 2c 20 79 29 49 03 RIMARY KEY, y)I. | 3888: 06 17 11 11 01 7f 74 61 62 6c 65 74 32 74 32 04 ......tablet2t2. | 3904: 43 52 45 41 54 45 20 54 41 42 4c 45 20 74 32 28 CREATE TABLE t2( | 3920: 61 2c 62 2c 63 20 50 52 49 4d 41 52 59 20 4b 45 a,b,c PRIMARY KE | 3936: 59 2c 20 64 2c 20 65 2c 20 66 29 20 57 49 54 48 Y, d, e, f) WITH | 3952: 4f 55 54 20 52 4f 57 49 44 58 03 07 17 11 11 01 OUT ROWIDX...... | 3968: 81 1b 74 61 62 6c 65 74 31 74 31 02 43 52 45 41 ..tablet1t1.CREA | 3984: 54 45 20 54 41 42 4c 45 20 74 31 28 61 2c 62 2c TE TABLE t1(a,b, | 4000: 63 20 41 53 20 28 2d 62 29 20 56 49 52 54 55 41 c AS (-b) VIRTUA | 4016: 4c 2c 64 20 43 48 45 43 4b 28 64 3e 35 29 2c 65 L,d CHECK(d>5),e | 4032: 20 55 4e 49 51 55 45 2c 20 66 20 41 53 20 28 2b UNIQUE, f AS (+ | 4048: 62 29 29 23 02 06 17 37 11 01 00 69 6e 64 65 78 b))#...7...index | 4064: 73 71 6c 69 74 65 5f 61 75 74 6f 69 6e 64 65 78 sqlite_autoindex | 4080: 5f 74 31 5f 31 74 31 03 00 00 00 08 00 00 00 00 _t1_1t1......... | page 2 offset 4096 | 0: 0d 00 00 00 0a 0f 93 00 0f f6 0f eb 0f e0 0f d5 ................ | 16: 0f ca 0f 8f 0f b4 0f a9 0f 9e 0f 93 00 00 00 00 ................ | 3984: 00 00 00 09 0a 05 01 01 01 01 0a 64 6e 14 09 09 ...........dn... | 4000: 05 01 01 01 01 09 5a 6d 12 09 08 05 01 01 01 01 ......Zm........ | 4016: 08 50 6c 10 09 07 05 01 01 01 01 07 46 6b 0e 09 .Pl.........Fk.. | 4032: 06 05 01 01 01 01 06 3c 6a 0c 09 05 05 01 01 01 .......<j....... | 4048: 01 05 32 69 0a 09 04 05 01 01 01 01 04 28 68 08 ..2i.........(h. | 4064: 09 03 05 01 01 01 01 03 1e 67 06 09 02 05 01 01 .........g...... | 4080: 01 01 02 14 66 04 08 01 05 09 01 01 01 0a 65 02 ....f.........e. | page 3 offset 8192 | 0: 0a 00 00 00 0a 0f c5 00 0f fb 0f f5 0f ef 0f e9 ................ | 16: 0f e3 0f dd 0f d7 0f d1 0f cb 0f c5 00 00 00 00 ................ | 4032: 00 00 00 00 00 05 03 01 01 14 0a 05 03 01 01 12 ................ | 4048: 09 05 03 01 01 10 08 05 03 01 01 0e 07 05 03 01 ................ | 4064: 01 0c 06 05 03 01 01 0a 05 05 03 01 01 08 04 05 ................ | 4080: 03 01 01 06 03 05 03 01 01 04 02 04 03 01 09 02 ................ | page 4 offset 12288 | 0: 0a 00 00 00 0a 0f 75 00 0f 75 0f 83 0f 91 0f 9f ......u..u...... | 16: 0f ad 0f bb 0f 00 00 00 00 00 00 00 00 00 00 00 ................ | 3952: 00 00 00 00 00 0d 07 01 01 01 01 01 01 9c 0a 64 ...............d | 3968: 6e 14 64 0d 07 02 01 01 01 01 01 a6 09 5a 6d 12 n.d..........Zm. | 3984: 5a 0d 07 01 01 01 01 01 01 b0 08 50 6c 10 50 0d Z..........Pl.P. | 4000: 07 01 01 01 01 01 01 ba 07 46 6b 0e 46 0d 07 01 .........Fk.F... | 4016: 01 01 01 01 01 c4 06 3c 6a 0c 3c 0d 07 01 01 01 .......<j.<..... | 4032: 01 01 01 ce 05 32 69 0a 32 0d 07 01 01 01 01 01 .....2i.2....... | 4048: 01 d8 04 28 68 08 28 0d 07 01 01 01 01 01 01 e2 ...(h.(......... | 4064: 03 1e 67 06 1e 0d 07 01 01 01 01 01 01 ec 02 14 ..g............. | 4080: 66 04 14 0c 07 01 09 01 01 01 01 f6 0a 65 02 0a f............e.. | page 5 offset 16384 | 0: 0d 00 00 00 03 0f e9 00 0f e9 0f fb 0f f6 00 00 ................ | 16: 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ | 4064: 00 00 00 00 00 00 00 00 00 03 ff ff ff ff ff ff ................ | 4080: ff ff 9c 03 00 00 03 64 03 00 00 03 01 03 00 00 .......d........ | page 6 offset 20480 | 0: 0d 00 00 00 00 10 00 00 00 00 00 00 00 00 00 00 ................ | end crash-685346d89b5e5f.db }]} {} do_catchsql_test 1.1 { ALTER TABLE t2 DROP COLUMN e; ALTER TABLE t1 DROP COLUMN f; } {1 {database disk image is malformed}} #-------------------------------------------------------------------------- reset_db do_test 2.0 { sqlite3 db {} db deserialize [decode_hexdb { .open --hexdb | size 24576 pagesize 4096 filename crash-0572db8f391431.db | page 1 offset 0 | 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3. | 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 06 .....@ ........ | 32: 00 00 63 00 10 05 f0 00 00 00 00 04 10 00 00 04 ..c............. | 48: 00 00 00 00 00 00 0f f0 00 00 00 00 00 00 00 00 ................ | 96: 00 00 00 00 0d 0f f8 00 05 0e cf 00 0f 79 0f d3 .............y.. | 112: 0f 2e 0e f3 0e cf 00 00 00 00 00 00 00 00 00 00 ................ | 3776: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 22 ................ | 3792: 05 06 17 11 11 01 31 74 61 62 6c 65 74 34 74 34 ......1tablet4t4 | 3808: 06 43 52 45 41 54 45 20 54 41 42 4c 45 20 74 34 .CREATE TABLE t4 | 3824: 28 7a 29 39 04 06 17 11 11 01 5f 74 61 62 6c 65 (z)9......_table | 3840: 74 33 74 33 05 43 52 45 41 54 45 20 54 41 42 4c t3t3.CREATE TABL | 3856: 45 20 74 33 28 78 20 49 4e 54 55 47 45 52 20 50 E t3(x INTUGER P | 3872: 52 49 4d 41 52 59 20 4b 45 59 2c 20 79 29 49 03 RIMARY KEY, y)I. | 3888: 06 17 11 11 01 7f 74 61 62 6c 65 74 32 74 32 04 ......tablet2t2. | 3904: 43 52 45 41 54 45 20 54 41 42 4c 45 20 74 32 28 CREATE TABLE t2( | 3920: 61 2c 62 2c 63 20 50 52 49 4d 41 52 59 20 4b 45 a,b,c PRIMARY KE | 3936: 59 2c 20 64 2c 20 65 2c 20 66 29 20 57 49 54 48 Y, d, e, f) WITH | 3952: 4f 55 54 20 52 4f 57 49 44 58 05 07 17 11 11 01 OUT ROWIDX...... | 3968: 81 1b 74 61 62 6c 65 74 31 74 31 02 43 52 45 41 ..tablet1t1.CREA | 3984: 54 45 20 54 41 42 4c 45 20 74 31 28 61 2c 62 2c TE TABLE t1(a,b, | 4000: 63 20 41 53 20 28 2d 62 29 20 56 49 52 54 55 41 c AS (-b) VIRTUA | 4016: 4c 2c 64 20 43 48 45 43 4b 28 64 3e 35 29 2c 65 L,d CHECK(d>5),e | 4032: 20 55 4e 49 51 55 45 2c 20 66 20 41 53 20 28 2b UNIQUE, f AS (+ | 4048: 62 29 29 23 02 06 17 37 11 01 00 69 6e 64 65 78 b))#...7...index | 4064: 73 71 6c 69 74 65 5f 61 75 74 6f 69 6e 64 65 78 sqlite_autoindex | 4080: 5f 74 31 5f 31 84 31 03 01 00 00 08 00 00 00 00 _t1_1.1......... | page 2 offset 4096 | 0: 0d 00 00 00 0a 0f 93 00 0f f6 0f eb 0f e0 0f d5 ................ | 16: 0f ca 0f 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ | 3984: 00 00 00 09 0a 05 01 01 01 01 0a 64 6e 14 09 09 ...........dn... | 4000: 05 01 01 01 01 09 5a 6d 12 09 08 05 01 00 f1 01 ......Zm........ | 4016: 08 50 6c 10 09 07 05 01 01 01 01 07 46 6b 0e 09 .Pl.........Fk.. | 4032: 06 05 01 00 f1 01 06 3c 6a 0c 09 05 05 01 01 01 .......<j....... | 4048: 01 05 32 69 0a 09 04 05 01 01 01 01 04 28 68 08 ..2i.........(h. | 4064: 57 03 05 01 01 01 01 03 1e 67 06 09 02 05 01 01 W........g...... | 4080: 01 01 02 14 66 04 08 01 05 09 01 01 01 0a 65 02 ....f.........e. | page 3 offset 8192 | 0: 09 ff ff ff fa 0f c5 00 0f fb 0f f5 0f ef 0f e9 ................ | 16: 0f e3 0f dd 0f d7 00 00 00 00 00 00 00 00 00 00 ................ | 4032: 00 00 00 00 00 05 03 01 01 14 0a 05 03 01 01 12 ................ | 4048: 09 05 03 01 01 10 08 05 03 01 01 0e 07 05 03 01 ................ | 4064: 01 0c 06 05 03 01 01 0a 05 05 03 01 01 08 04 05 ................ | 4080: 03 01 01 06 03 05 03 01 01 04 02 04 03 01 09 02 ................ | page 4 offset 12288 | 0: 0a 00 00 00 0a 0f 75 00 0f 75 0f 83 0f 91 0f 9f ......u..u...... | 16: 0f ad 0f bb 0f 00 00 00 00 00 01 00 00 00 00 00 ................ | 3952: 00 00 00 00 00 0d 07 01 01 01 01 01 01 9c 0a 64 ...............d | 3968: 6e 14 64 0d 07 02 01 01 01 01 01 a6 09 5a 6d 12 n.d..........Zm. | 3984: 5a 0d 07 01 01 01 01 d4 01 b0 08 50 6c 10 50 0d Z..........Pl.P. | 4000: 07 01 01 01 01 01 01 ba 07 46 6b 0e 46 0d 07 00 .........Fk.F... | 4016: 01 01 01 01 01 c4 06 3c 6a 0c 3c 0d 07 01 01 01 .......<j.<..... | 4032: 01 01 01 ce 05 32 69 0a 32 0d 07 01 01 01 01 01 .....2i.2....... | 4048: 01 d8 04 28 68 08 28 0d 07 01 01 01 01 01 01 e2 ...(h.(......... | 4064: 03 1e 67 06 1e 0d 07 01 01 01 01 01 01 ec 02 14 ..g............. | 4080: 66 04 14 0c 07 01 09 01 01 00 f1 f6 0a 65 02 0a f............e.. | page 5 offset 16384 | 0: 0d 00 00 00 03 0f e9 00 0f e9 0f fb 0f f6 00 00 ................ | 4064: 00 00 00 00 00 00 00 00 00 03 ff ff ff ff ff ff ................ | 4080: ff ff 9c 03 00 00 03 64 03 00 01 03 01 03 00 00 .......d........ | page 6 offset 20480 | 0: 0d 00 10 00 00 10 01 00 00 00 00 00 00 00 00 00 ................ | end crash-0572db8f391431.db }]} {} do_catchsql_test 2.1 { ALTER TABLE t1 DROP COLUMN a; } {1 {database disk image is malformed}} finish_test |
Added test/alterdropcol.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 | # 2021 February 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. # #************************************************************************* # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix alterdropcol # If SQLITE_OMIT_ALTERTABLE is defined, omit this file. ifcapable !altertable { finish_test return } do_execsql_test 1.0 { CREATE TABLE t1(a, b, c); CREATE VIEW v1 AS SELECT * FROM t1; CREATE TABLE t2(x INTEGER PRIMARY KEY, y, z UNIQUE); CREATE INDEX t2y ON t2(y); CREATE TABLE t3(q, r, s); CREATE INDEX t3rs ON t3(r+s); } do_catchsql_test 1.1 { ALTER TABLE nosuch DROP COLUMN z; } {1 {no such table: nosuch}} do_catchsql_test 1.2 { ALTER TABLE v1 DROP COLUMN c; } {1 {cannot drop column from view "v1"}} ifcapable fts5 { do_execsql_test 1.3.1 { CREATE VIRTUAL TABLE ft1 USING fts5(one, two); } do_catchsql_test 1.3.2 { ALTER TABLE ft1 DROP COLUMN two; } {1 {cannot drop column from virtual table "ft1"}} } do_catchsql_test 1.4 { ALTER TABLE sqlite_schema DROP COLUMN sql; } {1 {table sqlite_master may not be altered}} do_catchsql_test 1.5 { ALTER TABLE t1 DROP COLUMN d; } {1 {no such column: "d"}} do_execsql_test 1.6.1 { ALTER TABLE t1 DROP COLUMN b; } do_execsql_test 1.6.2 { SELECT sql FROM sqlite_schema WHERE name = 't1' } {{CREATE TABLE t1(a, c)}} do_execsql_test 1.7.1 { ALTER TABLE t1 DROP COLUMN c; } do_execsql_test 1.7.2 { SELECT sql FROM sqlite_schema WHERE name = 't1' } {{CREATE TABLE t1(a)}} do_catchsql_test 1.7.3 { ALTER TABLE t1 DROP COLUMN a; } {1 {cannot drop column "a": no other columns exist}} do_catchsql_test 1.8 { ALTER TABLE t2 DROP COLUMN z } {1 {cannot drop UNIQUE column: "z"}} do_catchsql_test 1.9 { ALTER TABLE t2 DROP COLUMN x } {1 {cannot drop PRIMARY KEY column: "x"}} do_catchsql_test 1.10 { ALTER TABLE t2 DROP COLUMN y } {1 {error in index t2y after drop column: no such column: y}} do_catchsql_test 1.11 { ALTER TABLE t3 DROP COLUMN s } {1 {error in index t3rs after drop column: no such column: s}} #------------------------------------------------------------------------- foreach {tn wo} { 1 {} 2 {WITHOUT ROWID} } { eval [string map [list %TN% $tn %WO% $wo] { reset_db do_execsql_test 2.%TN%.0 { CREATE TABLE t1(x, y INTEGER PRIMARY KEY, z) %WO% ; INSERT INTO t1 VALUES(1, 2, 3); INSERT INTO t1 VALUES(4, 5, 6); INSERT INTO t1 VALUES(7, 8, 9); } do_execsql_test 2.%TN%.1 { ALTER TABLE t1 DROP COLUMN x; SELECT * FROM t1; } { 2 3 5 6 8 9 } do_execsql_test 2.%TN%.2 { ALTER TABLE t1 DROP COLUMN z; SELECT * FROM t1; } { 2 5 8 } }]} #------------------------------------------------------------------------- reset_db do_execsql_test 3.0 { CREATE TABLE t12(a, b, c, CHECK(c>10)); CREATE TABLE t13(a, b, c CHECK(c>10)); } do_catchsql_test 3.1 { ALTER TABLE t12 DROP COLUMN c; } {1 {error in table t12 after drop column: no such column: c}} do_catchsql_test 3.2 { ALTER TABLE t13 DROP COLUMN c; } {0 {}} #------------------------------------------------------------------------- # Test that generated columns can be dropped. And that other columns from # tables that contain generated columns can be dropped. # foreach {tn wo vs} { 1 "" "" 2 "" VIRTUAL 3 "" STORED 4 "WITHOUT ROWID" STORED 5 "WITHOUT ROWID" VIRTUAL } { reset_db do_execsql_test 4.$tn.0 " CREATE TABLE 'my table'(a, b PRIMARY KEY, c AS (a+b) $vs, d) $wo " do_execsql_test 4.$tn.1 { INSERT INTO "my table"(a, b, d) VALUES(1, 2, 'hello'); INSERT INTO "my table"(a, b, d) VALUES(3, 4, 'world'); SELECT * FROM "my table" } { 1 2 3 hello 3 4 7 world } do_execsql_test 4.$tn.2 { ALTER TABLE "my table" DROP COLUMN c; } do_execsql_test 4.$tn.3 { SELECT * FROM "my table" } { 1 2 hello 3 4 world } do_execsql_test 4.$tn.4 " CREATE TABLE x1(a, b, c PRIMARY KEY, d AS (b+c) $vs, e) $wo " do_execsql_test 4.$tn.5 { INSERT INTO x1(a, b, c, e) VALUES(1, 2, 3, 4); INSERT INTO x1(a, b, c, e) VALUES(5, 6, 7, 8); INSERT INTO x1(a, b, c, e) VALUES(9, 10, 11, 12); SELECT * FROM x1; } { 1 2 3 5 4 5 6 7 13 8 9 10 11 21 12 } do_execsql_test 4.$tn.6 { ALTER TABLE x1 DROP COLUMN a } do_execsql_test 4.$tn.7 { SELECT * FROM x1 } { 2 3 5 4 6 7 13 8 10 11 21 12 } do_execsql_test 4.$tn.8 { ALTER TABLE x1 DROP COLUMN e } do_execsql_test 4.$tn.9 { SELECT * FROM x1 } { 2 3 5 6 7 13 10 11 21 } } #------------------------------------------------------------------------- reset_db do_execsql_test 5.0 { CREATE TABLE p1(a PRIMARY KEY, b UNIQUE); CREATE TABLE c1(x, y, z REFERENCES p1(c)); CREATE TABLE c2(x, y, z, w REFERENCES p1(b)); } do_execsql_test 5.1 { ALTER TABLE c1 DROP COLUMN z; ALTER TABLE c2 DROP COLUMN z; SELECT sql FROM sqlite_schema WHERE name IN ('c1', 'c2'); } { {CREATE TABLE c1(x, y)} {CREATE TABLE c2(x, y, w REFERENCES p1(b))} } do_execsql_test 5.2.1 { CREATE VIEW v1 AS SELECT d, e FROM p1 } do_catchsql_test 5.2.2 { ALTER TABLE c1 DROP COLUMN x } {1 {error in view v1: no such column: d}} do_execsql_test 5.3.1 { DROP VIEW v1; CREATE VIEW v1 AS SELECT x, y FROM c1; } do_catchsql_test 5.3.2 { ALTER TABLE c1 DROP COLUMN x } {1 {error in view v1 after drop column: no such column: x}} do_execsql_test 5.4.1 { CREATE TRIGGER tr AFTER INSERT ON c1 BEGIN INSERT INTO p1 VALUES(new.y, new.xyz); END; } do_catchsql_test 5.4.2 { ALTER TABLE c1 DROP COLUMN y } {1 {error in trigger tr: no such column: new.xyz}} do_execsql_test 5.5.1 { DROP TRIGGER tr; CREATE TRIGGER tr AFTER INSERT ON c1 BEGIN INSERT INTO p1 VALUES(new.y, new.z); END; } do_catchsql_test 5.5.2 { ALTER TABLE c1 DROP COLUMN y } {1 {error in trigger tr: no such column: new.z}} # 2021-03-06 dbsqlfuzz crash-419aa525df93db6e463772c686ac6da27b46da9e reset_db do_catchsql_test 6.0 { CREATE TABLE t1(a,b,c); CREATE TABLE t2(x,y,z); PRAGMA writable_schema=ON; UPDATE sqlite_schema SET sql='CREATE INDEX t1b ON t1(b)' WHERE name='t2'; PRAGMA writable_schema=OFF; ALTER TABLE t2 DROP COLUMN z; } {1 {database disk image is malformed}} reset_db do_catchsql_test 6.1 { CREATE TABLE t1(a,b,c); CREATE TABLE t2(x,y,z); PRAGMA writable_schema=ON; UPDATE sqlite_schema SET sql='CREATE VIEW t2(x,y,z) AS SELECT b,a,c FROM t1' WHERE name='t2'; PRAGMA writable_schema=OFF; ALTER TABLE t2 DROP COLUMN z; } {1 {database disk image is malformed}} # 2021-04-06 dbsqlfuzz crash-331c5c29bb76257b198f1318eef3288f9624c8ce reset_db do_execsql_test 7.0 { CREATE TABLE t1(a, b, c, PRIMARY KEY(a COLLATE nocase, a)) WITHOUT ROWID; INSERT INTO t1 VALUES(1, 2, 3); INSERT INTO t1 VALUES(4, 5, 6); } do_execsql_test 7.1 { ALTER TABLE t1 DROP COLUMN c; } do_execsql_test 7.2 { SELECT sql FROM sqlite_schema; } {{CREATE TABLE t1(a, b, PRIMARY KEY(a COLLATE nocase, a)) WITHOUT ROWID}} do_execsql_test 7.3 { SELECT * FROM t1; } {1 2 4 5} reset_db do_execsql_test 8.0 { CREATE TABLE t1(a INTEGER PRIMARY KEY, b); PRAGMA writable_schema = 1; UPDATE sqlite_schema SET sql = 'CREATE TABLE t1(a INTEGER PRIMARY KEY AUTOINCREMENT, b)' } db close sqlite3 db test.db do_execsql_test 8.1 { ALTER TABLE t1 DROP COLUMN b; } do_execsql_test 8.2 { SELECT sql FROM sqlite_schema; } {{CREATE TABLE t1(a INTEGER PRIMARY KEY AUTOINCREMENT)}} #------------------------------------------------------------------------- foreach {tn wo} { 1 {} 2 {WITHOUT ROWID} } { reset_db do_execsql_test 9.$tn.0 " CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c) $wo; " do_execsql_test 9.$tn.1 { WITH s(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<50000 ) INSERT INTO t1(a, b, c) SELECT i, 123, 456 FROM s; } do_execsql_test 9.$tn.2 { ALTER TABLE t1 DROP COLUMN b; } do_execsql_test 9.$tn.3 { SELECT count(*), c FROM t1 GROUP BY c; } {50000 456} } finish_test |
Added test/alterdropcol2.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 | # 2021 February 19 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #************************************************************************* # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix alterdropcol2 # If SQLITE_OMIT_ALTERTABLE is defined, omit this file. ifcapable !altertable { finish_test return } # EVIDENCE-OF: R-58318-35349 The DROP COLUMN syntax is used to remove an # existing column from a table. do_execsql_test 1.0 { CREATE TABLE t1(c, b, a, PRIMARY KEY(b, a)) WITHOUT ROWID; INSERT INTO t1 VALUES(1, 2, 3), (4, 5, 6); } do_execsql_test 1.1 { ALTER TABLE t1 DROP c; } # EVIDENCE-OF: The DROP COLUMN command removes the named column from the table, # and also rewrites the entire table to purge the data associated with that # column. do_execsql_test 1.2.1 { SELECT * FROM t1; } {2 3 5 6} do_execsql_test 1.2.2 { SELECT sql FROM sqlite_schema; } { {CREATE TABLE t1(b, a, PRIMARY KEY(b, a)) WITHOUT ROWID} } proc do_atdc_error_test {tn schema atdc error} { reset_db execsql $schema uplevel [list do_catchsql_test $tn $atdc [list 1 [string trim $error]]] } #------------------------------------------------------------------------- # Test cases 2.* attempt to verify the following: # # EVIDENCE-OF: R-24098-10282 The DROP COLUMN command only works if the column # is not referenced by any other parts of the schema and is not a PRIMARY KEY # and does not have a UNIQUE constraint. # # EVIDENCE-OF: R-52436-31752 The column is a PRIMARY KEY or part of one. # do_atdc_error_test 2.1.1 { CREATE TABLE x1(a PRIMARY KEY, b, c); } { ALTER TABLE x1 DROP COLUMN a } { cannot drop PRIMARY KEY column: "a" } do_atdc_error_test 2.1.2 { CREATE TABLE x1(a,b,c,d,e, PRIMARY KEY(b,c,d)); } { ALTER TABLE x1 DROP COLUMN c } { cannot drop PRIMARY KEY column: "c" } # EVIDENCE-OF: R-43412-16016 The column has a UNIQUE constraint. # do_atdc_error_test 2.2.1 { CREATE TABLE x1(a PRIMARY KEY, b, c UNIQUE); } { ALTER TABLE x1 DROP COLUMN c } { cannot drop UNIQUE column: "c" } do_atdc_error_test 2.2.2 { CREATE TABLE x1(a PRIMARY KEY, b, c, UNIQUE(b, c)); } { ALTER TABLE x1 DROP COLUMN c } { error in table x1 after drop column: no such column: c } # EVIDENCE-OF: R-46731-08965 The column is indexed. # do_atdc_error_test 2.3.1 { CREATE TABLE 'one two'('x y', 'z 1', 'a b'); CREATE INDEX idx ON 'one two'('z 1'); } { ALTER TABLE 'one two' DROP COLUMN 'z 1' } { error in index idx after drop column: no such column: z 1 } do_atdc_error_test 2.3.2 { CREATE TABLE x1(a, b, c); CREATE INDEX idx ON x1(a); } { ALTER TABLE x1 DROP COLUMN a; } { error in index idx after drop column: no such column: a } # EVIDENCE-OF: R-46731-08965 The column is indexed. # do_atdc_error_test 2.4.1 { CREATE TABLE x1234(a, b, c PRIMARY KEY) WITHOUT ROWID; CREATE INDEX i1 ON x1234(b) WHERE ((a+5) % 10)==0; } { ALTER TABLE x1234 DROP a } { error in index i1 after drop column: no such column: a } # EVIDENCE-OF: R-47838-03249 The column is named in a table or column # CHECK constraint not associated with the column being dropped. # do_atdc_error_test 2.5.1 { CREATE TABLE x1234(a, b, c PRIMARY KEY, CHECK(((a+5)%10)!=0)) WITHOUT ROWID; } { ALTER TABLE x1234 DROP a } { error in table x1234 after drop column: no such column: a } # EVIDENCE-OF: R-55640-01652 The column is used in a foreign key constraint. # do_atdc_error_test 2.6.1 { CREATE TABLE p1(x, y UNIQUE); CREATE TABLE c1(u, v, FOREIGN KEY (v) REFERENCES p1(y)) } { ALTER TABLE c1 DROP v } { error in table c1 after drop column: unknown column "v" in foreign key definition } # EVIDENCE-OF: R-20795-39479 The column is used in the expression of a # generated column. do_atdc_error_test 2.7.1 { CREATE TABLE c1(u, v, w AS (u+v)); } { ALTER TABLE c1 DROP v } { error in table c1 after drop column: no such column: v } do_atdc_error_test 2.7.2 { CREATE TABLE c1(u, v, w AS (u+v) STORED); } { ALTER TABLE c1 DROP u } { error in table c1 after drop column: no such column: u } # EVIDENCE-OF: R-01515-49025 The column appears in a trigger or view. # do_atdc_error_test 2.8.1 { CREATE TABLE log(l); CREATE TABLE c1(u, v, w); CREATE TRIGGER tr1 AFTER INSERT ON c1 BEGIN INSERT INTO log VALUES(new.w); END; } { ALTER TABLE c1 DROP w } { error in trigger tr1 after drop column: no such column: new.w } do_atdc_error_test 2.8.2 { CREATE TABLE c1(u, v, w); CREATE VIEW v1 AS SELECT u, v, w FROM c1; } { ALTER TABLE c1 DROP w } { error in view v1 after drop column: no such column: w } do_atdc_error_test 2.8.3 { CREATE TABLE c1(u, v, w); CREATE VIEW v1 AS SELECT * FROM c1 WHERE w IS NOT NULL; } { ALTER TABLE c1 DROP w } { error in view v1 after drop column: no such column: w } #------------------------------------------------------------------------- # Verify that a column that is part of a CHECK constraint may be dropped # if the CHECK constraint was specified as part of the column definition. # # STALE-EVIDENCE: R-60924-11170 However, the column being deleted can be used in a # column CHECK constraint because the column CHECK constraint is dropped # together with the column itself. do_execsql_test 3.0 { CREATE TABLE yyy(q, w, e CHECK (e > 0), r); INSERT INTO yyy VALUES(1,1,1,1), (2,2,2,2); CREATE TABLE zzz(q, w, e, r, CHECK (e > 0)); INSERT INTO zzz VALUES(1,1,1,1), (2,2,2,2); } do_catchsql_test 3.1.1 { INSERT INTO yyy VALUES(0,0,0,0); } {1 {CHECK constraint failed: e > 0}} do_catchsql_test 3.1.2 { INSERT INTO yyy VALUES(0,0,0,0); } {1 {CHECK constraint failed: e > 0}} do_execsql_test 3.2.1 { ALTER TABLE yyy DROP e; } do_catchsql_test 3.2.2 { ALTER TABLE zzz DROP e; } {1 {error in table zzz after drop column: no such column: e}} finish_test |
Added test/alterfault.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 | # 2021 November 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 implements regression tests for SQLite library. # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix alterfault # If SQLITE_OMIT_ALTERTABLE is defined, omit this file. ifcapable !altertable { finish_test return } do_execsql_test 1.0 { CREATE TABLE t1(a); } faultsim_save_and_close do_faultsim_test 1.1 -faults oom* -prep { faultsim_restore_and_reopen } -body { execsql { ALTER TABLE t1 ADD COLUMN b CHECK (a!=1) } } -test { faultsim_test_result {0 {}} } finish_test |
Changes to test/alterlegacy.test.
︙ | ︙ | |||
36 37 38 39 40 41 42 | } # Legacy behavior is to corrupt the schema in this case, as the table name in # the CHECK constraint is incorrect after "t1" is renamed. This version is # slightly different - it rejects the change and rolls back the transaction. do_catchsql_test 1.2 { ALTER TABLE t1 RENAME TO t1new; | | | | 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 | } # Legacy behavior is to corrupt the schema in this case, as the table name in # the CHECK constraint is incorrect after "t1" is renamed. This version is # slightly different - it rejects the change and rolls back the transaction. do_catchsql_test 1.2 { ALTER TABLE t1 RENAME TO t1new; } {1 {error in table t1new after rename: no such column: t1.a}} do_execsql_test 1.3 { CREATE TABLE t3(c, d); ALTER TABLE t3 RENAME TO t3new; DROP TABLE t3new; } do_execsql_test 1.4 { SELECT sql FROM sqlite_master } { {CREATE TABLE t1(a, b, CHECK(t1.a != t1.b))} {CREATE TABLE t2(a, b)} {CREATE INDEX t2expr ON t2(a) WHERE t2.b>0} } do_catchsql_test 1.3 { ALTER TABLE t2 RENAME TO t2new; } {1 {error in index t2expr after rename: no such column: t2.b}} do_execsql_test 1.4 { SELECT sql FROM sqlite_master } { {CREATE TABLE t1(a, b, CHECK(t1.a != t1.b))} {CREATE TABLE t2(a, b)} {CREATE INDEX t2expr ON t2(a) WHERE t2.b>0} } |
︙ | ︙ |
Changes to test/altermalloc2.test.
︙ | ︙ | |||
90 91 92 93 94 95 96 97 98 99 100 101 | do_faultsim_test 4 -faults oom-* -prep { faultsim_restore_and_reopen execsql { SELECT * FROM sqlite_master } } -body { execsql { ALTER TABLE rr RENAME a TO c; } } -test { faultsim_test_result {0 {}} } finish_test | > > > > > > > > > > > > > > > > > > > > > | 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 | do_faultsim_test 4 -faults oom-* -prep { faultsim_restore_and_reopen execsql { SELECT * FROM sqlite_master } } -body { execsql { ALTER TABLE rr RENAME a TO c; } } -test { faultsim_test_result {0 {}} } reset_db do_execsql_test 5.0 { CREATE TABLE rr(a, b); CREATE VIEW vv AS SELECT * FROM ( WITH abc(d, e) AS (SELECT * FROM rr) SELECT * FROM abc ); } {} faultsim_save_and_close do_faultsim_test 5 -faults oom-* -prep { faultsim_restore_and_reopen execsql { SELECT * FROM sqlite_master } } -body { execsql { ALTER TABLE rr RENAME TO c; } } -test { faultsim_test_result {0 {}} } finish_test |
Added test/altermalloc3.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 | # 2021 February 18 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #************************************************************************* # set testdir [file dirname $argv0] source $testdir/tester.tcl source $testdir/malloc_common.tcl set testprefix altermalloc3 # If SQLITE_OMIT_ALTERTABLE is defined, omit this file. ifcapable !altertable { finish_test return } do_execsql_test 1.0 { CREATE TABLE x1( one, two, three, PRIMARY KEY(one), CHECK (three!="xyz"), CHECK (two!="one") ) WITHOUT ROWID; CREATE INDEX x1i ON x1(one+"two"+"four") WHERE "five"; CREATE TEMP TRIGGER AFTER INSERT ON x1 BEGIN UPDATE x1 SET two=new.three || "new" WHERE one=new.one||""; END; CREATE TABLE t1(a, b, c, d, PRIMARY KEY(d, b)) WITHOUT ROWID; INSERT INTO t1 VALUES(1, 2, 3, 4); } faultsim_save_and_close do_faultsim_test 1 -prep { faultsim_restore_and_reopen } -body { execsql { ALTER TABLE t1 DROP COLUMN c } } -test { faultsim_test_result {0 {}} } #------------------------------------------------------------------------- # dbsqlfuzz e3dd84cda3848016a6a6024c7249d09bc2ef2615 # reset_db do_execsql_test 2.0 { CREATE TABLE t2(k,v); CREATE TRIGGER r2 AFTER INSERT ON t2 BEGIN UPDATE t2 SET (k,v)= ( (WITH cte1(a) AS ( SELECT 1 FROM ( SELECT * FROM t2 ) ) SELECT a FROM cte1 ), 1); END; } faultsim_save_and_close faultsim_restore_and_reopen do_execsql_test 2.1 { ALTER TABLE t2 RENAME TO t2x; } do_faultsim_test 2.2 -prep { faultsim_restore_and_reopen db eval { SELECT * FROM sqlite_master } } -body { execsql { ALTER TABLE t2 RENAME TO t2x; } } -test { faultsim_test_result {0 {}} } finish_test |
Added test/alterqf.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 | # 2021 March 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 implements regression tests for SQLite library. This # script focuses on testing internal function sqlite_rename_quotefix(). # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix alterqf # If SQLITE_OMIT_ALTERTABLE is defined, omit this file. ifcapable !altertable { finish_test return } sqlite3_test_control SQLITE_TESTCTRL_INTERNAL_FUNCTIONS db do_execsql_test 1.0 { CREATE TABLE t1(a, b, c); } foreach {tn before after} { 1 {CREATE VIEW v1 AS SELECT "a", "b", "notacolumn!", "c" FROM t1} {CREATE VIEW v1 AS SELECT "a", "b", 'notacolumn!', "c" FROM t1} 2 {CREATE VIEW v1 AS SELECT "a", "b", "not'a'column!", "c" FROM t1} {CREATE VIEW v1 AS SELECT "a", "b", 'not''a''column!', "c" FROM t1} 3 {CREATE VIEW v1 AS SELECT "a", "b", "not""a""column!", "c" FROM t1} {CREATE VIEW v1 AS SELECT "a", "b", 'not"a"column!', "c" FROM t1} 4 {CREATE VIEW v1 AS SELECT "val", count("b") FROM t1 GROUP BY "abc"} {CREATE VIEW v1 AS SELECT 'val', count("b") FROM t1 GROUP BY 'abc'} 5 {CREATE TABLE xyz(a CHECK (a!="str"), b AS (a||"str"))} {CREATE TABLE xyz(a CHECK (a!='str'), b AS (a||'str'))} 6 {CREATE INDEX i1 ON t1(a || "str", "b", "val")} {CREATE INDEX i1 ON t1(a || 'str', "b", 'val')} 7 {CREATE TRIGGER tr AFTER INSERT ON t1 BEGIN SELECT "abcd"; END} {CREATE TRIGGER tr AFTER INSERT ON t1 BEGIN SELECT 'abcd'; END} 8 {CREATE VIEW v1 AS SELECT "string"'alias' FROM t1} {CREATE VIEW v1 AS SELECT 'string' 'alias' FROM t1} 9 {CREATE INDEX i1 ON t1(a) WHERE "b"="bb"} {CREATE INDEX i1 ON t1(a) WHERE "b"='bb'} 10 {CREATE TABLE t2(abc, xyz CHECK (xyz != "123"))} {CREATE TABLE t2(abc, xyz CHECK (xyz != '123'))} 11 { CREATE TRIGGER ott AFTER UPDATE ON t1 BEGIN SELECT max("str", new."a") FROM t1 WHERE group_concat("b", ",") OVER (ORDER BY c||"str"); UPDATE t1 SET c= b + "str"; DELETE FROM t1 WHERE EXISTS ( SELECT 1 FROM t1 AS o WHERE o."a" = "o.a" AND t1.b IN("t1.b") ); END; } { CREATE TRIGGER ott AFTER UPDATE ON t1 BEGIN SELECT max('str', new."a") FROM t1 WHERE group_concat("b", ',') OVER (ORDER BY c||'str'); UPDATE t1 SET c= b + 'str'; DELETE FROM t1 WHERE EXISTS ( SELECT 1 FROM t1 AS o WHERE o."a" = 'o.a' AND t1.b IN('t1.b') ); END; } } { do_execsql_test 1.$tn { SELECT sqlite_rename_quotefix('main', $before) } [list $after] } #------------------------------------------------------------------------- reset_db do_execsql_test 2.0 { CREATE TABLE x1( one, two, three, PRIMARY KEY(one), CHECK (three!="xyz"), CHECK (two!="one") ) WITHOUT ROWID; CREATE INDEX x1i ON x1(one+"two"+"four") WHERE "five"; CREATE TEMP TRIGGER AFTER INSERT ON x1 BEGIN UPDATE x1 SET two=new.three || "new" WHERE one=new.one||""; END; } do_execsql_test 2.1 { ALTER TABLE x1 RENAME two TO 'four'; SELECT sql FROM sqlite_schema; SELECT sql FROM sqlite_temp_schema; } {{CREATE TABLE x1( one, "four", three, PRIMARY KEY(one), CHECK (three!='xyz'), CHECK ("four"!="one") ) WITHOUT ROWID} {CREATE INDEX x1i ON x1(one+"four"+'four') WHERE 'five'} {CREATE TRIGGER AFTER INSERT ON x1 BEGIN UPDATE x1 SET "four"=new.three || 'new' WHERE one=new.one||''; END} } finish_test |
Changes to test/altertab.test.
︙ | ︙ | |||
236 237 238 239 240 241 242 | ), ( 'main', 'CREATE TABLE x1(i INTEGER, t TEXT)', NULL, 'eee', 0 ), ( 'main', NULL, 'ddd', 'eee', 0 ); } {} | | | | 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 | ), ( 'main', 'CREATE TABLE x1(i INTEGER, t TEXT)', NULL, 'eee', 0 ), ( 'main', NULL, 'ddd', 'eee', 0 ); } {} sqlite3_test_control SQLITE_TESTCTRL_INTERNAL_FUNCTIONS db do_execsql_test 7.2 { SELECT sqlite_rename_table(db, 0, 0, sql, zOld, zNew, bTemp) FROM ddd; } {{} {} {}} sqlite3_test_control SQLITE_TESTCTRL_INTERNAL_FUNCTIONS db } #------------------------------------------------------------------------- # reset_db forcedelete test.db2 do_execsql_test 8.1 { |
︙ | ︙ | |||
501 502 503 504 505 506 507 | SELECT * FROM x; } {x x x} do_execsql_test 15.5 { SELECT sql FROM sqlite_master WHERE name = 'y'; } {{CREATE VIEW y AS SELECT f2 AS f1 FROM x}} | > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | SELECT * FROM x; } {x x x} do_execsql_test 15.5 { SELECT sql FROM sqlite_master WHERE name = 'y'; } {{CREATE VIEW y AS SELECT f2 AS f1 FROM x}} #------------------------------------------------------------------------- # Test that it is not possible to rename a shadow table in DEFENSIVE mode. # ifcapable fts3 { proc vtab_command {method args} { switch -- $method { xConnect { if {[info exists ::vtab_connect_sql]} { execsql $::vtab_connect_sql } return "CREATE TABLE t1(a, b, c)" } xBestIndex { set clist [lindex $args 0] if {[llength $clist]!=1} { error "unexpected constraint list" } catch { array unset C } array set C [lindex $clist 0] if {$C(usable)} { return "omit 0 cost 0 rows 1 idxnum 555 idxstr eq!" } else { return "cost 1000000 rows 0 idxnum 0 idxstr scan..." } } } return {} } register_tcl_module db sqlite3_db_config db DEFENSIVE 1 do_execsql_test 16.0 { CREATE VIRTUAL TABLE y1 USING fts3; VACUUM; } do_catchsql_test 16.10 { INSERT INTO y1_segments VALUES(1, X'1234567890'); } {1 {table y1_segments may not be modified}} do_catchsql_test 16.20 { DROP TABLE y1_segments; } {1 {table y1_segments may not be dropped}} do_catchsql_test 16.20 { ALTER TABLE y1_segments RENAME TO abc; } {1 {table y1_segments may not be altered}} sqlite3_db_config db DEFENSIVE 0 do_catchsql_test 16.22 { ALTER TABLE y1_segments RENAME TO abc; } {0 {}} sqlite3_db_config db DEFENSIVE 1 do_catchsql_test 16.23 { CREATE TABLE y1_segments AS SELECT * FROM abc; } {1 {object name reserved for internal use: y1_segments}} do_catchsql_test 16.24 { CREATE VIEW y1_segments AS SELECT * FROM abc; } {1 {object name reserved for internal use: y1_segments}} sqlite3_db_config db DEFENSIVE 0 do_catchsql_test 16.25 { ALTER TABLE abc RENAME TO y1_segments; } {0 {}} sqlite3_db_config db DEFENSIVE 1 do_execsql_test 16.30 { ALTER TABLE y1 RENAME TO z1; } do_execsql_test 16.40 { SELECT * FROM z1_segments; } } #------------------------------------------------------------------------- reset_db do_execsql_test 17.0 { CREATE TABLE sqlite1234 (id integer); ALTER TABLE sqlite1234 RENAME TO User; SELECT name, sql FROM sqlite_master WHERE sql IS NOT NULL; } { User {CREATE TABLE "User" (id integer)} } #------------------------------------------------------------------------- reset_db do_execsql_test 18.1.0 { CREATE TABLE t0 (c0 INTEGER, PRIMARY KEY(c0)) WITHOUT ROWID; } do_execsql_test 18.1.1 { ALTER TABLE t0 RENAME COLUMN c0 TO c1; } do_execsql_test 18.1.2 { SELECT sql FROM sqlite_master; } {{CREATE TABLE t0 (c1 INTEGER, PRIMARY KEY(c1)) WITHOUT ROWID}} reset_db do_execsql_test 18.2.0 { CREATE TABLE t0 (c0 INTEGER, PRIMARY KEY(c0)); } do_execsql_test 18.2.1 { ALTER TABLE t0 RENAME COLUMN c0 TO c1; } do_execsql_test 18.2.2 { SELECT sql FROM sqlite_master; } {{CREATE TABLE t0 (c1 INTEGER, PRIMARY KEY(c1))}} # 2020-02-23 ticket f50af3e8a565776b reset_db do_execsql_test 19.100 { CREATE TABLE t1(x); CREATE VIEW t2 AS SELECT 1 FROM t1, (t1 AS a0, t1); ALTER TABLE t1 RENAME TO t3; SELECT sql FROM sqlite_master; } {{CREATE TABLE "t3"(x)} {CREATE VIEW t2 AS SELECT 1 FROM "t3", ("t3" AS a0, "t3")}} do_execsql_test 19.110 { INSERT INTO t3(x) VALUES(123); SELECT * FROM t2; } {1} do_execsql_test 19.120 { INSERT INTO t3(x) VALUES('xyz'); SELECT * FROM t2; } {1 1 1 1 1 1 1 1} # Ticket 4722bdab08cb14 reset_db do_execsql_test 20.0 { CREATE TABLE a(a); CREATE VIEW b AS SELECT(SELECT *FROM c JOIN a USING(d, a, a, a) JOIN a) IN(); } do_execsql_test 20.1 { ALTER TABLE a RENAME a TO e; } {} reset_db do_execsql_test 21.0 { CREATE TABLE a(b); CREATE VIEW c AS SELECT NULL INTERSECT SELECT NULL ORDER BY likelihood(NULL, (d, (SELECT c))); } {} do_catchsql_test 21.1 { SELECT likelihood(NULL, (d, (SELECT c))); } {1 {second argument to likelihood() must be a constant between 0.0 and 1.0}} do_catchsql_test 21.2 { SELECT * FROM c; } {1 {1st ORDER BY term does not match any column in the result set}} do_catchsql_test 21.3 { ALTER TABLE a RENAME TO e; } {1 {error in view c: 1st ORDER BY term does not match any column in the result set}} # After forum thread https://sqlite.org/forum/forumpost/ddbe1c7efa # Ensure that PRAGMA schema_version=N causes a full schema reload. # reset_db do_execsql_test 22.0 { CREATE TABLE t1(a INT, b TEXT NOT NULL); INSERT INTO t1 VALUES(1,2),('a','b'); BEGIN; PRAGMA writable_schema=ON; UPDATE sqlite_schema SET sql='CREATE TABLE t1(a INT, b TEXT)' WHERE name LIKE 't1'; PRAGMA schema_version=1234; COMMIT; PRAGMA integrity_check; } {ok} do_execsql_test 22.1 { ALTER TABLE t1 ADD COLUMN c INT DEFAULT 78; SELECT * FROM t1; } {1 2 78 a b 78} #------------------------------------------------------------------------- reset_db db collate compare64 compare64 do_execsql_test 23.1 { CREATE TABLE gigo(a text); CREATE TABLE idx(x text COLLATE compare64); CREATE VIEW v1 AS SELECT * FROM idx WHERE x='abc'; } db close sqlite3 db test.db do_execsql_test 23.2 { alter table gigo rename to ggiiggoo; alter table idx rename to idx2; } do_execsql_test 23.3 { SELECT sql FROM sqlite_master; } { {CREATE TABLE "ggiiggoo"(a text)} {CREATE TABLE "idx2"(x text COLLATE compare64)} {CREATE VIEW v1 AS SELECT * FROM "idx2" WHERE x='abc'} } do_execsql_test 23.4 { ALTER TABLE idx2 RENAME x TO y; SELECT sql FROM sqlite_master; } { {CREATE TABLE "ggiiggoo"(a text)} {CREATE TABLE "idx2"(y text COLLATE compare64)} {CREATE VIEW v1 AS SELECT * FROM "idx2" WHERE y='abc'} } #------------------------------------------------------------------------- # reset_db do_execsql_test 24.1.0 { CREATE TABLE t1(a, b); CREATE TRIGGER AFTER INSERT ON t1 BEGIN INSERT INTO nosuchtable VALUES(new.a) ON CONFLICT(a) DO NOTHING; END; } do_catchsql_test 24.1.1 { ALTER TABLE t1 RENAME TO t2; } {1 {error in trigger AFTER: no such table: main.nosuchtable}} reset_db do_execsql_test 24.2.0 { CREATE TABLE t1(a, b); CREATE TRIGGER AFTER INSERT ON t1 BEGIN INSERT INTO v1 VALUES(new.a) ON CONFLICT(a) DO NOTHING; END; CREATE VIEW v1 AS SELECT * FROM nosuchtable; } do_catchsql_test 24.2.1 { ALTER TABLE t1 RENAME TO t2; } {1 {error in trigger AFTER: no such table: main.nosuchtable}} #-------------------------------------------------------------------------- # reset_db do_execsql_test 25.1 { CREATE TABLE xx(x); CREATE VIEW v3(b) AS WITH b AS (SELECT b FROM (SELECT * FROM t2)) VALUES(1); } ifcapable json1&&vtab { do_catchsql_test 25.2 { ALTER TABLE json_each RENAME TO t4; } {1 {table json_each may not be altered}} } # 2021-05-01 dbsqlfuzz bc17a306a09329bba0ecc61547077f6178bcf321 # Remove a NEVER() inserted on 2019-12-09 that is reachable after all. # reset_db do_execsql_test 26.1 { CREATE TABLE t1(k,v); CREATE TABLE t2_a(k,v); CREATE VIEW t2 AS SELECT * FROM t2_a; CREATE TRIGGER r2 AFTER INSERT ON t1 BEGIN UPDATE t1 SET (k,v)=((WITH cte1(a) AS (SELECT 1 FROM t2) SELECT t2.k FROM t2, cte1),1); END; ALTER TABLE t1 RENAME TO t1x; INSERT INTO t2_a VALUES(2,3); INSERT INTO t1x VALUES(98,99); SELECT * FROM t1x; } {2 1} #------------------------------------------------------------------------- reset_db do_execsql_test 27.1 { create table t_sa ( c_muyat INTEGER NOT NULL, c_d4u TEXT ); create table t2 ( abc ); CREATE TRIGGER trig AFTER DELETE ON t_sa BEGIN DELETE FROM t_sa WHERE ( SELECT 123 FROM t2 WINDOW oamat7fzf AS ( PARTITION BY t_sa.c_d4u ) ); END; } do_execsql_test 27.2 { alter table t_sa rename column c_muyat to c_dg; } #------------------------------------------------------------------------- reset_db do_execsql_test 29.1 { CREATE TABLE t1(a, b, c); INSERT INTO t1 VALUES('a', 'b', 'c'); CREATE VIEW v0 AS WITH p AS ( SELECT 1 FROM t1 ), g AS ( SELECT 1 FROM p, t1 ) SELECT 1 FROM g; } do_execsql_test 29.2 { SELECT * FROM v0 } 1 do_execsql_test 29.2 { ALTER TABLE t1 RENAME TO t2 } do_execsql_test 29.3 { SELECT sql FROM sqlite_schema WHERE name='v0' } {{CREATE VIEW v0 AS WITH p AS ( SELECT 1 FROM "t2" ), g AS ( SELECT 1 FROM p, "t2" ) SELECT 1 FROM g}} do_execsql_test 29.4 { CREATE VIEW v2 AS WITH p AS ( SELECT 1 FROM t2 ), g AS ( SELECT 1 FROM ( WITH i AS (SELECT 1 FROM p, t2) SELECT * FROM i ) ) SELECT 1 FROM g; } do_execsql_test 29.4 { SELECT * FROM v2; } 1 do_execsql_test 29.5 { ALTER TABLE t2 RENAME TO t3; } do_execsql_test 29.5 { SELECT sql FROM sqlite_schema WHERE name='v2' } {{CREATE VIEW v2 AS WITH p AS ( SELECT 1 FROM "t3" ), g AS ( SELECT 1 FROM ( WITH i AS (SELECT 1 FROM p, "t3") SELECT * FROM i ) ) SELECT 1 FROM g}} #------------------------------------------------------------------------- reset_db do_execsql_test 28.1 { CREATE TABLE t1(a); CREATE TABLE t2(b,c); CREATE TABLE t4(b,c); INSERT INTO t2 VALUES(1,2),(1,3),(2,5); INSERT INTO t4 VALUES(1,2),(1,3),(2,5); CREATE VIEW v3 AS WITH RECURSIVE t3(x,y,z) AS ( SELECT b,c,NULL FROM t4 UNION SELECT x,y,NULL FROM t3, t2 ) SELECT * FROM t3 AS xyz; } do_execsql_test 28.2 { SELECT * FROM v3 } { 1 2 {} 1 3 {} 2 5 {} } do_execsql_test 28.3 { ALTER TABLE t1 RENAME a TO a2; -- fails in v3 } do_execsql_test 28.4 { ALTER TABLE t2 RENAME TO t5; } do_execsql_test 28.5 { SELECT sql FROM sqlite_schema WHERE name='v3' } {{CREATE VIEW v3 AS WITH RECURSIVE t3(x,y,z) AS ( SELECT b,c,NULL FROM t4 UNION SELECT x,y,NULL FROM t3, "t5" ) SELECT * FROM t3 AS xyz}} #------------------------------------------------------------------------- reset_db do_execsql_test 30.0 { CREATE TABLE t1(a,b,c,d,e,f); CREATE TABLE t2(a,b,c); CREATE INDEX t1abc ON t1(a,b,c+d+e); CREATE VIEW v1(x,y) AS SELECT t1.b,t2.b FROM t1,t2 WHERE t1.a=t2.a GROUP BY 1 HAVING t2.c NOT NULL LIMIT 10; CREATE TRIGGER r1 AFTER INSERT ON t1 WHEN 'no' NOT NULL BEGIN INSERT INTO t2(a,a,b,c) VALUES(new.b,new.a,new.c-7); WITH c1(x) AS ( VALUES(0) UNION ALL SELECT current_time+x FROM c1 WHERE x UNION ALL SELECT 1+x FROM c1 WHERE x<1 ), c2(x) AS (VALUES(0),(1)) SELECT * FROM c1 AS x1, c2 AS x2, ( SELECT x+1 FROM c1 WHERE x IS NOT TRUE UNION ALL SELECT 1+x FROM c1 WHERE 1<x ) AS x3, c2 x5; END; } do_execsql_test 30.1 { ALTER TABLE t1 RENAME TO t1x; } do_execsql_test 30.2 { SELECT sql FROM sqlite_schema ORDER BY rowid } { {CREATE TABLE "t1x"(a,b,c,d,e,f)} {CREATE TABLE t2(a,b,c)} {CREATE INDEX t1abc ON "t1x"(a,b,c+d+e)} {CREATE VIEW v1(x,y) AS SELECT "t1x".b,t2.b FROM "t1x",t2 WHERE "t1x".a=t2.a GROUP BY 1 HAVING t2.c NOT NULL LIMIT 10} {CREATE TRIGGER r1 AFTER INSERT ON "t1x" WHEN 'no' NOT NULL BEGIN INSERT INTO t2(a,a,b,c) VALUES(new.b,new.a,new.c-7); WITH c1(x) AS ( VALUES(0) UNION ALL SELECT current_time+x FROM c1 WHERE x UNION ALL SELECT 1+x FROM c1 WHERE x<1 ), c2(x) AS (VALUES(0),(1)) SELECT * FROM c1 AS x1, c2 AS x2, ( SELECT x+1 FROM c1 WHERE x IS NOT TRUE UNION ALL SELECT 1+x FROM c1 WHERE 1<x ) AS x3, c2 x5; END} } #------------------------------------------------------------------------- reset_db do_execsql_test 31.0 { CREATE TABLE t1(q); CREATE VIEW vvv AS WITH x AS (WITH y AS (SELECT * FROM x) SELECT 1) SELECT 1; } do_execsql_test 31.1 { SELECT * FROM vvv; } {1} do_execsql_test 31.2 { ALTER TABLE t1 RENAME TO t1x; } do_execsql_test 31.3 { ALTER TABLE t1x RENAME q TO x; } # 2021-07-02 OSSFuzz https://oss-fuzz.com/testcase-detail/5517690440646656 # Bad assert() statement # reset_db do_catchsql_test 32.0 { CREATE TABLE t1(x); CREATE TRIGGER r1 BEFORE INSERT ON t1 BEGIN UPDATE t1 SET x=x FROM (SELECT*); END; ALTER TABLE t1 RENAME TO x; } {1 {error in trigger r1: no tables specified}} finish_test |
Changes to test/altertab2.test.
︙ | ︙ | |||
138 139 140 141 142 143 144 145 | do_execsql_test 3.$tn.4 { ALTER TABLE log_entry RENAME col1 TO newname; SELECT sql FROM sqlite_master; } $expect } finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | do_execsql_test 3.$tn.4 { ALTER TABLE log_entry RENAME col1 TO newname; SELECT sql FROM sqlite_master; } $expect } #------------------------------------------------------------------------- reset_db do_execsql_test 4.0 { CREATE TABLE t1(a,b,c,d,e,f); CREATE TRIGGER r1 AFTER INSERT ON t1 WHEN new.a NOT NULL BEGIN UPDATE t1 SET (c,d)=(a,b); END; } do_execsql_test 4.1 { ALTER TABLE t1 RENAME TO t1x; SELECT sql FROM sqlite_master WHERE type = 'trigger'; } { {CREATE TRIGGER r1 AFTER INSERT ON "t1x" WHEN new.a NOT NULL BEGIN UPDATE "t1x" SET (c,d)=(a,b); END} } do_execsql_test 4.2 { ALTER TABLE t1x RENAME a TO aaa; SELECT sql FROM sqlite_master WHERE type = 'trigger'; } { {CREATE TRIGGER r1 AFTER INSERT ON "t1x" WHEN new.aaa NOT NULL BEGIN UPDATE "t1x" SET (c,d)=(aaa,b); END} } do_execsql_test 4.3 { ALTER TABLE t1x RENAME d TO ddd; SELECT sql FROM sqlite_master WHERE type = 'trigger'; } { {CREATE TRIGGER r1 AFTER INSERT ON "t1x" WHEN new.aaa NOT NULL BEGIN UPDATE "t1x" SET (c,ddd)=(aaa,b); END} } #------------------------------------------------------------------------- ifcapable windowfunc { do_execsql_test 5.0 { CREATE TABLE t2(a); CREATE TRIGGER r2 AFTER INSERT ON t2 WHEN new.a NOT NULL BEGIN SELECT a, sum(a) OVER w1 FROM t2 WINDOW w1 AS ( PARTITION BY a ORDER BY a ROWS BETWEEN 2 PRECEDING AND 3 FOLLOWING ), w2 AS ( PARTITION BY a ORDER BY rowid ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING ); END; } {} do_execsql_test 5.0.1 { INSERT INTO t2 VALUES(1); } {} do_execsql_test 5.1 { ALTER TABLE t2 RENAME TO t2x; SELECT sql FROM sqlite_master WHERE name = 'r2'; } { {CREATE TRIGGER r2 AFTER INSERT ON "t2x" WHEN new.a NOT NULL BEGIN SELECT a, sum(a) OVER w1 FROM "t2x" WINDOW w1 AS ( PARTITION BY a ORDER BY a ROWS BETWEEN 2 PRECEDING AND 3 FOLLOWING ), w2 AS ( PARTITION BY a ORDER BY rowid ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING ); END} } do_execsql_test 5.2 { ALTER TABLE t2x RENAME a TO aaaa; SELECT sql FROM sqlite_master WHERE name = 'r2'; } { {CREATE TRIGGER r2 AFTER INSERT ON "t2x" WHEN new.aaaa NOT NULL BEGIN SELECT aaaa, sum(aaaa) OVER w1 FROM "t2x" WINDOW w1 AS ( PARTITION BY aaaa ORDER BY aaaa ROWS BETWEEN 2 PRECEDING AND 3 FOLLOWING ), w2 AS ( PARTITION BY aaaa ORDER BY rowid ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING ); END} } do_execsql_test 5.3 { INSERT INTO t2x VALUES(1); } {} } ;# windowfunc #------------------------------------------------------------------------- do_execsql_test 6.0 { CREATE TABLE t3(a,b,c,d); CREATE TRIGGER r3 AFTER INSERT ON t3 WHEN new.a NOT NULL BEGIN SELECT a,b,c FROM t3 EXCEPT SELECT a,b,c FROM t3 ORDER BY a; SELECT rowid, * FROM t3; END; } {} do_execsql_test 6.1 { ALTER TABLE t3 RENAME TO t3x; SELECT sql FROM sqlite_master WHERE name = 'r3'; } { {CREATE TRIGGER r3 AFTER INSERT ON "t3x" WHEN new.a NOT NULL BEGIN SELECT a,b,c FROM "t3x" EXCEPT SELECT a,b,c FROM "t3x" ORDER BY a; SELECT rowid, * FROM "t3x"; END} } do_execsql_test 6.2 { ALTER TABLE t3x RENAME a TO abcd; SELECT sql FROM sqlite_master WHERE name = 'r3'; } { {CREATE TRIGGER r3 AFTER INSERT ON "t3x" WHEN new.abcd NOT NULL BEGIN SELECT abcd,b,c FROM "t3x" EXCEPT SELECT abcd,b,c FROM "t3x" ORDER BY abcd; SELECT rowid, * FROM "t3x"; END} } #------------------------------------------------------------------------- reset_db do_execsql_test 7.0 { CREATE TABLE t1(a,b,c,d,e,f); INSERT INTO t1 VALUES(1,2,3,4,5,6); CREATE TABLE t2(x,y,z); } do_execsql_test 7.1 { SELECT a,b,c FROM t1 UNION SELECT d,e,f FROM t1 ORDER BY b,c; } {1 2 3 4 5 6} do_execsql_test 7.2 { CREATE TRIGGER r1 AFTER INSERT ON t1 BEGIN INSERT INTO t2 SELECT a,b,c FROM t1 UNION SELECT d,e,f FROM t1 ORDER BY b,c; END; INSERT INTO t1 VALUES(2,3,4,5,6,7); SELECT * FROM t2; } {1 2 3 2 3 4 4 5 6 5 6 7} do_execsql_test 7.3 { ALTER TABLE t1 RENAME TO xyzzy; SELECT sql FROM sqlite_master WHERE name='r1' } { {CREATE TRIGGER r1 AFTER INSERT ON "xyzzy" BEGIN INSERT INTO t2 SELECT a,b,c FROM "xyzzy" UNION SELECT d,e,f FROM "xyzzy" ORDER BY b,c; END} } do_execsql_test 7.3 { ALTER TABLE xyzzy RENAME c TO ccc; SELECT sql FROM sqlite_master WHERE name='r1' } { {CREATE TRIGGER r1 AFTER INSERT ON "xyzzy" BEGIN INSERT INTO t2 SELECT a,b,ccc FROM "xyzzy" UNION SELECT d,e,f FROM "xyzzy" ORDER BY b,ccc; END} } #------------------------------------------------------------------------- reset_db do_execsql_test 8.0 { CREATE TABLE t1(a, b, c); CREATE TABLE t2(a, b, c); CREATE TABLE t3(d, e, f); CREATE VIEW v1 AS SELECT * FROM t1; CREATE TRIGGER tr AFTER INSERT ON t3 BEGIN UPDATE t2 SET a = new.d; SELECT a, b, c FROM v1; END; } do_execsql_test 8.1 { INSERT INTO t3 VALUES(1, 2, 3); } # The following ALTER TABLE fails as if column "t1.a" is renamed the "a" # in the "SELECT a, b, c FROM v1" within the trigger can no longer be # resolved. But at one point there was a bug allowing the ALTER TABLE # succeed. Which meant the subsequent INSERT statement would fail. do_catchsql_test 8.2 { ALTER TABLE t1 RENAME a TO aaa; } {1 {error in trigger tr after rename: no such column: a}} do_execsql_test 8.3 { INSERT INTO t3 VALUES(4, 5, 6); } do_execsql_test 8.4 { CREATE TABLE t4(a, b); CREATE VIEW v4 AS SELECT * FROM t4 WHERE (a=1 AND 0) OR b=2; } # Branches of an expression tree that are optimized out by the AND # optimization are renamed. # do_execsql_test 8.5 { ALTER TABLE t4 RENAME a TO c; SELECT sql FROM sqlite_master WHERE name = 'v4' } {{CREATE VIEW v4 AS SELECT * FROM t4 WHERE (c=1 AND 0) OR b=2}} # 2019-06-10 https://www.sqlite.org/src/info/533010b8cacebe82 reset_db do_catchsql_test 8.6 { CREATE TABLE t0(c0); CREATE INDEX i0 ON t0(LIKELIHOOD(1,2) AND 0); ALTER TABLE t0 RENAME TO t1; SELECT sql FROM sqlite_master WHERE name='i0'; } {1 {error in index i0: second argument to likelihood() must be a constant between 0.0 and 1.0}} finish_test |
Added test/altertab3.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 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 | # 2019 January 23 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #************************************************************************* # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix altertab3 # If SQLITE_OMIT_ALTERTABLE is defined, omit this file. ifcapable !altertable { finish_test return } ifcapable windowfunc { do_execsql_test 1.0 { CREATE TABLE t1(a, b); CREATE TRIGGER tr1 AFTER INSERT ON t1 BEGIN SELECT sum(b) OVER w FROM t1 WINDOW w AS (ORDER BY a); END; } do_execsql_test 1.1 { ALTER TABLE t1 RENAME a TO aaa; } do_execsql_test 1.2 { SELECT sql FROM sqlite_master WHERE name='tr1' } {{CREATE TRIGGER tr1 AFTER INSERT ON t1 BEGIN SELECT sum(b) OVER w FROM t1 WINDOW w AS (ORDER BY aaa); END}} do_execsql_test 1.3 { INSERT INTO t1 VALUES(1, 2); } } ;# windowfunc #------------------------------------------------------------------------- reset_db do_execsql_test 2.0 { CREATE TABLE t1(a,b,c); CREATE TABLE t2(a,b,c); CREATE TRIGGER r1 AFTER INSERT ON t1 WHEN new.a NOT NULL BEGIN SELECT a,b, a name FROM t1 INTERSECT SELECT a,b,c FROM t1 WHERE b>='d' ORDER BY name; SELECT new.c; END; } do_execsql_test 2.1 { ALTER TABLE t1 RENAME TO t1x; SELECT sql FROM sqlite_master WHERE name = 'r1'; } {{CREATE TRIGGER r1 AFTER INSERT ON "t1x" WHEN new.a NOT NULL BEGIN SELECT a,b, a name FROM "t1x" INTERSECT SELECT a,b,c FROM "t1x" WHERE b>='d' ORDER BY name; SELECT new.c; END}} #------------------------------------------------------------------------- reset_db do_execsql_test 3.0 { CREATE TABLE t1(a, b, c, d); CREATE VIEW v1 AS SELECT * FROM t1 WHERE a=1 OR (b IN ()); } do_execsql_test 3.1 { ALTER TABLE t1 RENAME b TO bbb; } do_execsql_test 3.2 { SELECT sql FROM sqlite_master WHERE name = 'v1' } {{CREATE VIEW v1 AS SELECT * FROM t1 WHERE a=1 OR (b IN ())}} #------------------------------------------------------------------------- reset_db do_execsql_test 4.0 { CREATE TABLE t1(a, b); CREATE TABLE t3(e, f); CREATE TRIGGER tr1 AFTER INSERT ON t1 BEGIN INSERT INTO t2 VALUES(new.a, new.b); END; } do_catchsql_test 4.1.2 { BEGIN; ALTER TABLE t3 RENAME TO t4; } {1 {error in trigger tr1: no such table: main.t2}} do_execsql_test 4.1.2 { COMMIT; } do_execsql_test 4.1.3 { SELECT type, name, tbl_name, sql FROM sqlite_master WHERE type='table' AND name!='t1'; } {table t3 t3 {CREATE TABLE t3(e, f)}} do_catchsql_test 4.2.1 { BEGIN; ALTER TABLE t3 RENAME e TO eee; } {1 {error in trigger tr1: no such table: main.t2}} do_execsql_test 4.2.2 { COMMIT; } do_execsql_test 4.2.3 { SELECT type, name, tbl_name, sql FROM sqlite_master WHERE type='table' AND name!='t1'; } {table t3 t3 {CREATE TABLE t3(e, f)}} #------------------------------------------------------------------------- reset_db do_execsql_test 5.0 { CREATE TABLE t1 ( c1 integer, c2, PRIMARY KEY(c1 collate rtrim), UNIQUE(c2) ) } do_execsql_test 5.1 { ALTER TABLE t1 RENAME c1 TO c3; } #------------------------------------------------------------------------- reset_db do_execsql_test 6.0 { CREATE TEMPORARY TABLE Table0 ( Col0 INTEGER, PRIMARY KEY(Col0 COLLATE RTRIM), FOREIGN KEY (Col0) REFERENCES Table0 ); } do_execsql_test 6.1 { ALTER TABLE Table0 RENAME Col0 TO Col0; } #------------------------------------------------------------------------- reset_db do_execsql_test 7.1.0 { CREATE TABLE t1(a,b,c); CREATE TRIGGER AFTER INSERT ON t1 BEGIN SELECT a, rank() OVER w1 FROM t1 WINDOW w1 AS (PARTITION BY b, percent_rank() OVER w1); END; } do_execsql_test 7.1.2 { ALTER TABLE t1 RENAME TO t1x; SELECT sql FROM sqlite_master; } { {CREATE TABLE "t1x"(a,b,c)} {CREATE TRIGGER AFTER INSERT ON "t1x" BEGIN SELECT a, rank() OVER w1 FROM "t1x" WINDOW w1 AS (PARTITION BY b, percent_rank() OVER w1); END} } do_execsql_test 7.2.1 { DROP TRIGGER after; CREATE TRIGGER AFTER INSERT ON t1x BEGIN SELECT a, rank() OVER w1 FROM t1x WINDOW w1 AS (PARTITION BY b, percent_rank() OVER w1 ORDER BY d); END; } do_catchsql_test 7.2.2 { ALTER TABLE t1x RENAME TO t1; } {1 {error in trigger AFTER: no such column: d}} #------------------------------------------------------------------------- reset_db do_execsql_test 8.0 { CREATE TABLE t0(c0); CREATE INDEX i0 ON t0('1' IN ()); } do_execsql_test 8.1 { ALTER TABLE t0 RENAME TO t1; SELECT sql FROM sqlite_master; } { {CREATE TABLE "t1"(c0)} {CREATE INDEX i0 ON "t1"('1' IN ())} } do_execsql_test 8.2.1 { CREATE TABLE t2 (c0); CREATE INDEX i2 ON t2((LIKELIHOOD(c0, 100) IN ())); ALTER TABLE t2 RENAME COLUMN c0 TO c1; } do_execsql_test 8.2.2 { SELECT sql FROM sqlite_master WHERE tbl_name = 't2'; } { {CREATE TABLE t2 (c1)} {CREATE INDEX i2 ON t2((LIKELIHOOD(c0, 100) IN ()))} } do_test 8.2.3 { sqlite3 db2 test.db db2 eval { INSERT INTO t2 VALUES (1), (2), (3) } db close } {} db2 close #------------------------------------------------------------------------- reset_db do_execsql_test 9.1 { CREATE TABLE t1(a,b,c); CREATE TRIGGER AFTER INSERT ON t1 WHEN new.a NOT NULL BEGIN SELECT true WHERE (SELECT a, b FROM (t1)) IN (); END; } do_execsql_test 9.2 { ALTER TABLE t1 RENAME TO t1x; } #------------------------------------------------------------------------- reset_db do_execsql_test 10.1 { CREATE TABLE t1(a, b, c); CREATE TABLE t2(a, b, c); CREATE VIEW v1 AS SELECT * FROM t1 WHERE ( SELECT t1.a FROM t1, t2 ) IN () OR t1.a=5; } do_execsql_test 10.2 { ALTER TABLE t2 RENAME TO t3; SELECT sql FROM sqlite_master WHERE name='v1'; } { {CREATE VIEW v1 AS SELECT * FROM t1 WHERE ( SELECT t1.a FROM t1, t2 ) IN () OR t1.a=5} } #------------------------------------------------------------------------- reset_db do_execsql_test 11.1 { CREATE TABLE t1( a,b,c,d,e,f,g,h,j,jj,jjb,k,aa,bb,cc,dd,ee DEFAULT 3.14, ff DEFAULT('hiccup'),Wg NOD NULL DEFAULT(false) ); CREATE TRIGGER b AFTER INSERT ON t1 WHEN new.a BEGIN SELECT a, sum() w3 FROM t1 WINDOW b AS (ORDER BY NOT EXISTS(SELECT 1 FROM abc)); END; } do_catchsql_test 11.2 { ALTER TABLE t1 RENAME TO t1x; } {1 {error in trigger b: no such table: main.abc}} do_execsql_test 11.3 { DROP TRIGGER b; CREATE TRIGGER b AFTER INSERT ON t1 WHEN new.a BEGIN SELECT a, sum() w3 FROM t1 WINDOW b AS (ORDER BY NOT EXISTS(SELECT 1 FROM t1)); END; } {} do_execsql_test 11.4 { ALTER TABLE t1 RENAME TO t1x; SELECT sql FROM sqlite_master WHERE name = 'b'; } { {CREATE TRIGGER b AFTER INSERT ON "t1x" WHEN new.a BEGIN SELECT a, sum() w3 FROM "t1x" WINDOW b AS (ORDER BY NOT EXISTS(SELECT 1 FROM "t1x")); END} } #------------------------------------------------------------------------- reset_db do_execsql_test 12.1 { CREATE TABLE t1(a,b,c,d,e,f,g,h,j,jj,Zjj,k,aQ,bb,cc,dd,ee DEFAULT 3.14, ff DEFAULT('hiccup'),gg NOD NULL DEFAULT(false)); CREATE TRIGGER AFTER INSERT ON t1 WHEN new.a NOT NULL BEGIN SELECT b () OVER , dense_rank() OVER d, d () OVER w1 FROM t1 WINDOW w1 AS ( w1 ORDER BY d ROWS BETWEEN 2 NOT IN(SELECT a, sum(d) w2,max(d)OVER FROM t1 WINDOW w1 AS (PARTITION BY d ROWS BETWEEN '' PRECEDING AND false FOLLOWING), d AS (PARTITION BY b ORDER BY d ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) ) PRECEDING AND 1 FOLLOWING), w2 AS (PARTITION BY b ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW), w3 AS (PARTITION BY b ORDER BY d ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) ; SELECT a, sum(d) w2,max(d)OVER FROM t1 WINDOW w1 AS (PARTITION BY d ROWS BETWEEN '' PRECEDING AND false FOLLOWING), d AS (PARTITION BY b ORDER BY d ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) ; END; } do_execsql_test 12.2 { ALTER TABLE t1 RENAME TO t1x; } #------------------------------------------------------------------------- reset_db do_execsql_test 13.1 { CREATE TABLE t1(a); CREATE TRIGGER r1 INSERT ON t1 BEGIN SELECT a(*) OVER (ORDER BY (SELECT 1)) FROM t1; END; } do_execsql_test 13.2 { ALTER TABLE t1 RENAME TO t1x; } #------------------------------------------------------------------------- reset_db do_execsql_test 14.1 { CREATE TABLE t1(a); CREATE TABLE t2(b); CREATE TRIGGER AFTER INSERT ON t1 BEGIN SELECT sum() FILTER (WHERE (SELECT sum() FILTER (WHERE 0)) AND a); END; } do_catchsql_test 14.2 { ALTER TABLE t1 RENAME TO t1x; } {1 {error in trigger AFTER: no such column: a}} #------------------------------------------------------------------------- reset_db do_execsql_test 16.1 { CREATE TABLE t1(x); CREATE TRIGGER AFTER INSERT ON t1 BEGIN SELECT (WITH t2 AS (WITH t3 AS (SELECT true) SELECT * FROM t3 ORDER BY true COLLATE nocase) SELECT 11); WITH t4 AS (SELECT * FROM t1) SELECT 33; END; } do_execsql_test 16.2 { ALTER TABLE t1 RENAME TO t1x; } #------------------------------------------------------------------------- reset_db do_execsql_test 17.1 { CREATE TABLE t1(a,b,c); CREATE TRIGGER AFTER INSERT ON t1 WHEN new.a NOT NULL BEGIN SELECT a () FILTER (WHERE a>0) FROM t1; END; } do_execsql_test 17.2 { ALTER TABLE t1 RENAME TO t1x; ALTER TABLE t1x RENAME a TO aaa; SELECT sql FROM sqlite_master WHERE type='trigger'; } { {CREATE TRIGGER AFTER INSERT ON "t1x" WHEN new.aaa NOT NULL BEGIN SELECT a () FILTER (WHERE aaa>0) FROM "t1x"; END} } #------------------------------------------------------------------------- reset_db do_execsql_test 18.1 { CREATE TABLE t1(a,b); CREATE TRIGGER r1 AFTER INSERT ON t1 BEGIN SELECT a, b FROM t1 INTERSECT SELECT b,a FROM t1 ORDER BY b IN ( SELECT a UNION SELECT b FROM t1 ORDER BY b COLLATE nocase ) ; END; } do_catchsql_test 18.2 { SELECT a, b FROM t1 INTERSECT SELECT b,a FROM t1 ORDER BY b IN ( SELECT a UNION SELECT b FROM t1 ORDER BY b COLLATE nocase ); } {1 {1st ORDER BY term does not match any column in the result set}} do_catchsql_test 18.3 { ALTER TABLE t1 RENAME TO t1x; } {1 {error in trigger r1: 1st ORDER BY term does not match any column in the result set}} #------------------------------------------------------------------------- reset_db do_execsql_test 19.0 { CREATE TABLE a(a,h CONSTRAINT a UNIQUE ON CONFLICT FAIL,CONSTRAINT a); } foreach {tn v res} { 1 { CREATE VIEW q AS SELECT 123 WINDOW x AS ( RANGE BETWEEN UNBOUNDED PRECEDING AND INDEXED() OVER( PARTITION BY ( WITH x AS(VALUES(col1)) VALUES(453) ) ) FOLLOWING ) } {1 {error in view q: no such column: col1}} 2 { CREATE VIEW q AS SELECT CAST(CAST(CAST(CAST(CAST(CAST(CAST(CAST(CAST(CAST(CAST(RIGHT AS)AS)AS)AS)AS)AS)AS)AS)AS)AS)AS)WINDOW x AS(RANGE BETWEEN UNBOUNDED PRECEDING AND INDEXED(*)OVER(PARTITION BY CROSS,CROSS,NATURAL,sqlite_master(*)OVER a,(WITH a AS(VALUES(LEFT)UNION VALUES(LEFT)UNION VALUES(LEFT)UNION VALUES(LEFT)UNION VALUES(LEFT)UNION VALUES(LEFT)UNION VALUES(LEFT))VALUES(LEFT))IN STORED,LEFT,LEFT,LEFT,LEFT,LEFT,LEFT)*LEFT FOLLOWING)ORDER BY LEFT,LEFT,LEFT,LEFT,LEFT,LEFT,LEFT,LEFT,LEFT,LEFT,LEFT LIMIT LEFT,INDEXED(*)OVER(PARTITION BY CROSS,CROSS,CROSS,LEFT,INDEXED(*)OVER(PARTITION BY CROSS,CROSS,CROSS),INDEXED(*)OVER(PARTITION BY LEFT,LEFT,LEFT,LEFT,LEFT,LEFT,LEFT,LEFT,LEFT,LEFT,LEFT), LEFT,LEFT,INNER,CROSS,CROSS,CROSS,INNER,NATURAL ORDER BY OUTER,NATURAL,NATURAL,NATURAL,NATURAL,NATURAL,NATURAL,NATURAL,INNER, INNER,INNER NULLS LAST GROUPS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING); } {1 {error in view q: no such column: LEFT}} 3 { CREATE VIEW q AS SELECT 99 WINDOW x AS (RANGE BETWEEN UNBOUNDED PRECEDING AND count(*)OVER(PARTITION BY (WITH a AS(VALUES(2),(x3))VALUES(0))) FOLLOWING)ORDER BY x2,sum(1)OVER(PARTITION BY avg(5)OVER(PARTITION BY x1)); } {1 {error in view q: no such column: x3}} } { do_execsql_test 19.$tn.1 " DROP VIEW IF EXISTS q; $v " {} do_catchsql_test 19.$tn.2 { ALTER TABLE a RENAME TO g; } $res } # Verify that the "if( pParse->nErr ) return WRC_Abort" at the top of the # renameUnmapSelectCb() routine in alter.c (2019-12-04) is really required. # sqlite3 db :memory: do_catchsql_test 20.10 { CREATE TABLE s(a, b, c); CREATE INDEX k ON s( (WITH s AS( SELECT * ) VALUES(2) ) IN () ); ALTER TABLE s RENAME a TO a2; } {1 {error in index k: no tables specified}} #------------------------------------------------------------------------ # reset_db do_execsql_test 21.1 { CREATE TABLE s(col); CREATE VIEW v AS SELECT ( WITH x(a) AS(SELECT * FROM s) VALUES(RIGHT) ) IN() ; CREATE TABLE a(a); ALTER TABLE a RENAME a TO b; } #------------------------------------------------------------------------ # reset_db do_execsql_test 22.1 { CREATE TABLE t1(a); CREATE VIEW v2(b) AS SELECT * FROM v2; } do_catchsql_test 22.2 { ALTER TABLE t1 RENAME TO t4; } {1 {error in view v2: view v2 is circularly defined}} do_execsql_test 22.3 { DROP VIEW v2; CREATE VIEW v2(b) AS WITH t3 AS (SELECT b FROM v2) SELECT * FROM t3; } do_catchsql_test 22.4 { ALTER TABLE t1 RENAME TO t4; } {1 {error in view v2: view v2 is circularly defined}} do_execsql_test 22.5 { DROP VIEW v2; CREATE VIEW v2(b) AS WITH t3 AS (SELECT b FROM v2) VALUES(1); } do_catchsql_test 22.6 { ALTER TABLE t1 RENAME TO t4; } {0 {}} #------------------------------------------------------------------------ # reset_db do_execsql_test 23.1 { CREATE TABLE t1(x); CREATE TRIGGER r1 AFTER INSERT ON t1 BEGIN UPDATE t1 SET (c,d)=((SELECT 1 FROM t1 JOIN t2 ON b=x),1); END; } do_catchsql_test 23.2 { ALTER TABLE t1 RENAME TO t1x; } {1 {error in trigger r1: no such table: main.t2}} #------------------------------------------------------------------------ # reset_db do_execsql_test 23.1 { CREATE TABLE v0 (a); CREATE VIEW v2 (v3) AS WITH x1 AS (SELECT * FROM v2) SELECT v3 AS x, v3 AS y FROM v2; } do_catchsql_test 23.2 { SELECT * FROM v2 } {1 {view v2 is circularly defined}} db close sqlite3 db test.db do_catchsql_test 23.3 { ALTER TABLE v0 RENAME TO t3 ; } {1 {error in view v2: view v2 is circularly defined}} #------------------------------------------------------------------------ # reset_db do_execsql_test 24.1 { CREATE TABLE v0 (v1); CREATE TABLE v2 (v3 INTEGER UNIQUE ON CONFLICT ABORT); CREATE TRIGGER x AFTER INSERT ON v2 WHEN ( ( SELECT v1 AS PROMO_REVENUE FROM v2 JOIN v0 USING ( VALUE ) ) AND 0 ) BEGIN DELETE FROM v2; END; } do_catchsql_test 24.2 { ALTER TABLE v0 RENAME TO x ; } {1 {error in trigger x: cannot join using column VALUE - column not present in both tables}} do_execsql_test 24.3 { DROP TRIGGER x; CREATE TRIGGER x AFTER INSERT ON v2 WHEN ( 0 AND (SELECT rowid FROM v0) ) BEGIN DELETE FROM v2; END; } do_execsql_test 24.4 { ALTER TABLE v0 RENAME TO xyz; SELECT sql FROM sqlite_master WHERE type='trigger' } {{CREATE TRIGGER x AFTER INSERT ON v2 WHEN ( 0 AND (SELECT rowid FROM "xyz") ) BEGIN DELETE FROM v2; END}} #------------------------------------------------------------------------ # reset_db do_execsql_test 25.1 { CREATE TABLE t1(a, b, c); CREATE TABLE t2(a, b, c); CREATE TRIGGER ttt AFTER INSERT ON t1 BEGIN UPDATE t1 SET a=t2.a FROM t2 WHERE t1.a=t2.a; END; } #do_execsql_test 25.2 { # ALTER TABLE t2 RENAME COLUMN a TO aaa; #} #------------------------------------------------------------------------ # reset_db do_execsql_test 26.1 { CREATE TABLE t1(x); CREATE TABLE t3(y); CREATE TABLE t4(z); CREATE TRIGGER tr1 INSERT ON t3 BEGIN UPDATE t3 SET y=z FROM (SELECT z FROM t4); END; CREATE TRIGGER tr2 INSERT ON t3 BEGIN UPDATE t3 SET y=abc FROM (SELECT x AS abc FROM t1); END; } do_execsql_test 26.2 { ALTER TABLE t1 RENAME TO t2; } do_execsql_test 26.3 { ALTER TABLE t2 RENAME x TO xx; } do_execsql_test 26.4 { SELECT sql FROM sqlite_schema WHERE name='tr2' } { {CREATE TRIGGER tr2 INSERT ON t3 BEGIN UPDATE t3 SET y=abc FROM (SELECT xx AS abc FROM "t2"); END} } # 2020-11-02 OSSFuzz # reset_db do_execsql_test 26.5 { CREATE TABLE t1(xx); CREATE TRIGGER xx INSERT ON t1 BEGIN UPDATE t1 SET xx=xx FROM(SELECT xx); END; } {} do_catchsql_test 26.6 { ALTER TABLE t1 RENAME TO t2; } {1 {error in trigger xx: ambiguous column name: xx}} #------------------------------------------------------------------------- reset_db do_execsql_test 27.1 { CREATE TABLE t1(a, b AS ((WITH w1 (xyz) AS ( SELECT t1.b FROM t1 ) SELECT 123) IN ()), c); } do_execsql_test 27.2 { ALTER TABLE t1 DROP COLUMN c; SELECT sql FROM sqlite_schema WHERE name = 't1'; } { {CREATE TABLE t1(a, b AS ((WITH w1 (xyz) AS ( SELECT t1.b FROM t1 ) SELECT 123) IN ()))} } do_execsql_test 27.3 { CREATE TABLE t0(c0 , c1 AS (CASE TRUE NOT IN () WHEN NULL THEN CASE + 0xa ISNULL WHEN NOT + 0x9 THEN t0.c1 ELSE CURRENT_TIME LIKE CAST (t0.c1 REGEXP '-([1-9]\d*.\d*|0\.\d*[1-9]\d*)'ESCAPE (c1) COLLATE BINARY BETWEEN c1 AND c1 NOT IN (WITH t4 (c0) AS (WITH t3 (c0) AS NOT MATERIALIZED (WITH RECURSIVE t2 (c0) AS (WITH RECURSIVE t1 AS (VALUES (x'717171ff71717171' ) ) SELECT DISTINCT t0.c0 FROM t0 NOT INDEXED WHERE t0.c0 =t0.c0 GROUP BY 0x9 ) SELECT DISTINCT t0.c0 FROM t0 NOT INDEXED WHERE t0.c0 =t0.c1 ) SELECT DISTINCT t0.c0 FROM t0 NOT INDEXED WHERE t0.c0 =t0.c0 GROUP BY typeof(0x9 ) ) SELECT DISTINCT t0.c0 FROM t0 NOT INDEXED WHERE t0.c0 =t0.c0 GROUP BY typeof(typeof(0x9 ) ) ) IN t0 BETWEEN typeof(typeof(typeof(hex(*) FILTER (WHERE + x'5ccd1e68' ) ) ) ) AND 1 >0xa AS BLOB (+4.4E4 , -0xe ) ) END <> c1 IN () END ) VIRTUAL , c35 PRIMARY KEY , c60 , c64 NUMERIC (-6.8 , -0xE ) ) WITHOUT ROWID ; } {} do_execsql_test 27.4 { ALTER TABLE t0 DROP COLUMN c60; } {} #------------------------------------------------------------------------- reset_db do_execsql_test 28.1 { CREATE TABLE t1(a,b,c,d); CREATE TRIGGER AFTER INSERT ON t1 BEGIN UPDATE t1 SET (c,d)=(a,b); END; ALTER TABLE t1 RENAME TO t2; } do_execsql_test 28.2 { SELECT sql FROM sqlite_schema WHERE type='trigger' } {{CREATE TRIGGER AFTER INSERT ON "t2" BEGIN UPDATE "t2" SET (c,d)=(a,b); END}} finish_test |
Changes to test/analyze.test.
︙ | ︙ | |||
284 285 286 287 288 289 290 | sqlite3 db test.db execsql { SELECT * FROM t4 WHERE x=1234; } } {} # Verify that DROP TABLE and DROP INDEX remove entries from the | | | < | | | < > | | | | < > | | | | < > | 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 | sqlite3 db test.db execsql { SELECT * FROM t4 WHERE x=1234; } } {} # Verify that DROP TABLE and DROP INDEX remove entries from the # sqlite_stat1 and sqlite_stat4 tables. # do_test analyze-5.0 { execsql { DELETE FROM t3; DELETE FROM t4; INSERT INTO t3 VALUES(1,2,3,4); INSERT INTO t3 VALUES(5,6,7,8); INSERT INTO t3 SELECT a+8, b+8, c+8, d+8 FROM t3; INSERT INTO t3 SELECT a+16, b+16, c+16, d+16 FROM t3; INSERT INTO t3 SELECT a+32, b+32, c+32, d+32 FROM t3; INSERT INTO t3 SELECT a+64, b+64, c+64, d+64 FROM t3; INSERT INTO t4 SELECT a, b, c FROM t3; ANALYZE; SELECT DISTINCT idx FROM sqlite_stat1 ORDER BY 1; SELECT DISTINCT tbl FROM sqlite_stat1 ORDER BY 1; } } {t3i1 t3i2 t3i3 t4i1 t4i2 t3 t4} ifcapable stat4 { do_test analyze-5.1 { execsql { SELECT DISTINCT idx FROM sqlite_stat4 ORDER BY 1; SELECT DISTINCT tbl FROM sqlite_stat4 ORDER BY 1; } } {t3i1 t3i2 t3i3 t4i1 t4i2 t3 t4} } do_test analyze-5.2 { execsql { DROP INDEX t3i2; SELECT DISTINCT idx FROM sqlite_stat1 ORDER BY 1; SELECT DISTINCT tbl FROM sqlite_stat1 ORDER BY 1; } } {t3i1 t3i3 t4i1 t4i2 t3 t4} ifcapable stat4 { do_test analyze-5.3 { execsql { SELECT DISTINCT idx FROM sqlite_stat4 ORDER BY 1; SELECT DISTINCT tbl FROM sqlite_stat4 ORDER BY 1; } } {t3i1 t3i3 t4i1 t4i2 t3 t4} } do_test analyze-5.4 { execsql { DROP TABLE t3; SELECT DISTINCT idx FROM sqlite_stat1 ORDER BY 1; SELECT DISTINCT tbl FROM sqlite_stat1 ORDER BY 1; } } {t4i1 t4i2 t4} ifcapable stat4 { do_test analyze-5.5 { execsql { SELECT DISTINCT idx FROM sqlite_stat4 ORDER BY 1; SELECT DISTINCT tbl FROM sqlite_stat4 ORDER BY 1; } } {t4i1 t4i2 t4} } # This test corrupts the database file so it must be the last test # in the series. # do_test analyze-5.99 { |
︙ | ︙ |
Changes to test/analyze3.test.
︙ | ︙ | |||
14 15 16 17 18 19 20 | # instead of literal constant arguments. # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix analyze3 | | > > > > > > > > > > | 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 | # instead of literal constant arguments. # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix analyze3 ifcapable !stat4 { finish_test return } # This test cannot be run with the sqlite3_prepare() permutation, as it # tests that stat4 data can be used to influence the plans of queries # based on bound variable values. And this is not possible when using # sqlite3_prepare() - as queries cannot be internally re-prepared after # binding values are available. if {[permutation]=="prepare"} { finish_test return } #---------------------------------------------------------------------- # Test Organization: # |
︙ | ︙ | |||
96 97 98 99 100 101 102 | execsql { INSERT INTO t1 VALUES($i+100, $i) } } execsql { COMMIT; ANALYZE; } | < | < < < | | | | | | | | 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 | execsql { INSERT INTO t1 VALUES($i+100, $i) } } execsql { COMMIT; ANALYZE; } execsql { SELECT count(*)>0 FROM sqlite_stat4; } } {1} do_execsql_test analyze3-1.1.x { SELECT count(*) FROM t1 WHERE x>200 AND x<300; SELECT count(*) FROM t1 WHERE x>0 AND x<1100; } {99 1000} # The first of the following two SELECT statements visits 99 rows. So # it is better to use the index. But the second visits every row in # the table (1000 in total) so it is better to do a full-table scan. # do_eqp_test analyze3-1.1.2 { SELECT sum(y) FROM t1 WHERE x>200 AND x<300 } {SEARCH t1 USING INDEX i1 (x>? AND x<?)} do_eqp_test analyze3-1.1.3 { SELECT sum(y) FROM t1 WHERE x>0 AND x<1100 } {SCAN t1} # 2017-06-26: Verify that the SQLITE_DBCONFIG_ENABLE_QPSG setting disables # the use of bound parameters by STAT4 # db cache flush unset -nocomplain l unset -nocomplain u do_eqp_test analyze3-1.1.3.100 { SELECT sum(y) FROM t1 WHERE x>$l AND x<$u } {SEARCH t1 USING INDEX i1 (x>? AND x<?)} set l 200 set u 300 do_eqp_test analyze3-1.1.3.101 { SELECT sum(y) FROM t1 WHERE x>$l AND x<$u } {SEARCH t1 USING INDEX i1 (x>? AND x<?)} set l 0 set u 1100 do_eqp_test analyze3-1.1.3.102 { SELECT sum(y) FROM t1 WHERE x>$l AND x<$u } {SCAN t1} db cache flush sqlite3_db_config db ENABLE_QPSG 1 do_eqp_test analyze3-1.1.3.103 { SELECT sum(y) FROM t1 WHERE x>$l AND x<$u } {SEARCH t1 USING INDEX i1 (x>? AND x<?)} db cache flush sqlite3_db_config db ENABLE_QPSG 0 do_eqp_test analyze3-1.1.3.104 { SELECT sum(y) FROM t1 WHERE x>$l AND x<$u } {SCAN t1} do_test analyze3-1.1.4 { sf_execsql { SELECT sum(y) FROM t1 WHERE x>200 AND x<300 } } {199 0 14850} do_test analyze3-1.1.5 { set l [string range "200" 0 end] set u [string range "300" 0 end] |
︙ | ︙ | |||
197 198 199 200 201 202 203 | } {} do_execsql_test analyze3-2.1.x { SELECT count(*) FROM t2 WHERE x>1 AND x<2; SELECT count(*) FROM t2 WHERE x>0 AND x<99; } {200 990} do_eqp_test analyze3-1.2.2 { SELECT sum(y) FROM t2 WHERE x>1 AND x<2 | | | | 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 | } {} do_execsql_test analyze3-2.1.x { SELECT count(*) FROM t2 WHERE x>1 AND x<2; SELECT count(*) FROM t2 WHERE x>0 AND x<99; } {200 990} do_eqp_test analyze3-1.2.2 { SELECT sum(y) FROM t2 WHERE x>1 AND x<2 } {SEARCH t2 USING INDEX i2 (x>? AND x<?)} do_eqp_test analyze3-1.2.3 { SELECT sum(y) FROM t2 WHERE x>0 AND x<99 } {SCAN t2} do_test analyze3-1.2.4 { sf_execsql { SELECT sum(y) FROM t2 WHERE x>12 AND x<20 } } {161 0 4760} do_test analyze3-1.2.5 { set l [string range "12" 0 end] set u [string range "20" 0 end] |
︙ | ︙ | |||
249 250 251 252 253 254 255 | } {} do_execsql_test analyze3-1.3.x { SELECT count(*) FROM t3 WHERE x>200 AND x<300; SELECT count(*) FROM t3 WHERE x>0 AND x<1100 } {99 1000} do_eqp_test analyze3-1.3.2 { SELECT sum(y) FROM t3 WHERE x>200 AND x<300 | | | | 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 | } {} do_execsql_test analyze3-1.3.x { SELECT count(*) FROM t3 WHERE x>200 AND x<300; SELECT count(*) FROM t3 WHERE x>0 AND x<1100 } {99 1000} do_eqp_test analyze3-1.3.2 { SELECT sum(y) FROM t3 WHERE x>200 AND x<300 } {SEARCH t3 USING INDEX i3 (x>? AND x<?)} do_eqp_test analyze3-1.3.3 { SELECT sum(y) FROM t3 WHERE x>0 AND x<1100 } {SCAN t3} do_test analyze3-1.3.4 { sf_execsql { SELECT sum(y) FROM t3 WHERE x>200 AND x<300 } } {199 0 14850} do_test analyze3-1.3.5 { set l [string range "200" 0 end] set u [string range "300" 0 end] |
︙ | ︙ | |||
304 305 306 307 308 309 310 | append t [lindex {a b c d e f g h i j} [expr ($i%10)]] execsql { INSERT INTO t1 VALUES($i, $t) } } execsql COMMIT } {} do_eqp_test analyze3-2.2 { SELECT count(a) FROM t1 WHERE b LIKE 'a%' | | | | 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 | append t [lindex {a b c d e f g h i j} [expr ($i%10)]] execsql { INSERT INTO t1 VALUES($i, $t) } } execsql COMMIT } {} do_eqp_test analyze3-2.2 { SELECT count(a) FROM t1 WHERE b LIKE 'a%' } {SEARCH t1 USING INDEX i1 (b>? AND b<?)} do_eqp_test analyze3-2.3 { SELECT count(a) FROM t1 WHERE b LIKE '%a' } {SCAN t1} # Return the first argument if like_match_blobs is true (the default) # or the second argument if not # proc ilmb {a b} { ifcapable like_match_blobs {return $a} return $b |
︙ | ︙ | |||
694 695 696 697 698 699 700 | } execsql COMMIT execsql ANALYZE } {} do_eqp_test analyze3-6-3 { SELECT * FROM t1 WHERE a = 5 AND c = 13; | | | | 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 | } execsql COMMIT execsql ANALYZE } {} do_eqp_test analyze3-6-3 { SELECT * FROM t1 WHERE a = 5 AND c = 13; } {SEARCH t1 USING INDEX i2 (c=?)} do_eqp_test analyze3-6-2 { SELECT * FROM t1 WHERE a = 5 AND b > 'w' AND c = 13; } {SEARCH t1 USING INDEX i2 (c=?)} #----------------------------------------------------------------------------- # 2015-04-20. # Memory leak in sqlite3Stat4ProbeFree(). (Discovered while fuzzing.) # do_execsql_test analyze-7.1 { DROP TABLE IF EXISTS t1; |
︙ | ︙ |
Changes to test/analyze4.test.
︙ | ︙ | |||
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 | # statistics. # # Also include test cases for collating sequences on indices. # set testdir [file dirname $argv0] source $testdir/tester.tcl do_test analyze4-1.0 { db eval { CREATE TABLE t1(a,b); CREATE INDEX t1a ON t1(a); CREATE INDEX t1b ON t1(b); INSERT INTO t1 VALUES(1,NULL); INSERT INTO t1 SELECT a+1, b FROM t1; INSERT INTO t1 SELECT a+2, b FROM t1; INSERT INTO t1 SELECT a+4, b FROM t1; INSERT INTO t1 SELECT a+8, b FROM t1; INSERT INTO t1 SELECT a+16, b FROM t1; INSERT INTO t1 SELECT a+32, b FROM t1; INSERT INTO t1 SELECT a+64, b FROM t1; ANALYZE; } # Should choose the t1a index since it is more specific than t1b. db eval {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a=5 AND b IS NULL} | > > > > > > | | 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 | # statistics. # # Also include test cases for collating sequences on indices. # set testdir [file dirname $argv0] source $testdir/tester.tcl # If SQLITE_OMIT_ALTERTABLE is defined, omit this file. ifcapable !altertable { finish_test return } do_test analyze4-1.0 { db eval { CREATE TABLE t1(a,b); CREATE INDEX t1a ON t1(a); CREATE INDEX t1b ON t1(b); INSERT INTO t1 VALUES(1,NULL); INSERT INTO t1 SELECT a+1, b FROM t1; INSERT INTO t1 SELECT a+2, b FROM t1; INSERT INTO t1 SELECT a+4, b FROM t1; INSERT INTO t1 SELECT a+8, b FROM t1; INSERT INTO t1 SELECT a+16, b FROM t1; INSERT INTO t1 SELECT a+32, b FROM t1; INSERT INTO t1 SELECT a+64, b FROM t1; ANALYZE; } # Should choose the t1a index since it is more specific than t1b. db eval {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a=5 AND b IS NULL} } {/*SEARCH t1 USING INDEX t1a (a=?)*/} # Verify that the t1b index shows that it does not narrow down the # search any at all. # do_test analyze4-1.1 { db eval { SELECT idx, stat FROM sqlite_stat1 WHERE tbl='t1' ORDER BY idx; |
︙ | ︙ |
Changes to test/analyze5.test.
︙ | ︙ | |||
13 14 15 16 17 18 19 | # in this file is the use of the sqlite_stat4 histogram data on tables # with many repeated values and only a few distinct values. # set testdir [file dirname $argv0] source $testdir/tester.tcl | | | 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | # in this file is the use of the sqlite_stat4 histogram data on tables # with many repeated values and only a few distinct values. # set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable !stat4 { finish_test return } set testprefix analyze5 proc eqp {sql {db db}} { |
︙ | ︙ | |||
63 64 65 66 67 68 69 | CREATE INDEX t1v ON t1(v); -- mixed case text CREATE INDEX t1w ON t1(w); -- integers 0, 1, 2 and a few NULLs CREATE INDEX t1x ON t1(x); -- integers 1, 2, 3 and many NULLs CREATE INDEX t1y ON t1(y); -- integers 0 and very few 1s CREATE INDEX t1z ON t1(z); -- integers 0, 1, 2, and 3 ANALYZE; } | < | | | < < < < < < | | | | < < < < < < | | | < < < < < | 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 | CREATE INDEX t1v ON t1(v); -- mixed case text CREATE INDEX t1w ON t1(w); -- integers 0, 1, 2 and a few NULLs CREATE INDEX t1x ON t1(x); -- integers 1, 2, 3 and many NULLs CREATE INDEX t1y ON t1(y); -- integers 0 and very few 1s CREATE INDEX t1z ON t1(z); -- integers 0, 1, 2, and 3 ANALYZE; } db eval { SELECT DISTINCT lindex(test_decode(sample),0) FROM sqlite_stat4 WHERE idx='t1u' ORDER BY nlt; } } {alpha bravo charlie delta} do_test analyze5-1.1 { db eval { SELECT DISTINCT lower(lindex(test_decode(sample), 0)) FROM sqlite_stat4 WHERE idx='t1v' ORDER BY 1 } } {alpha bravo charlie delta} do_test analyze5-1.2 { db eval {SELECT idx, count(*) FROM sqlite_stat4 GROUP BY 1 ORDER BY 1} } {t1t 8 t1u 8 t1v 8 t1w 8 t1x 8 t1y 9 t1z 8} # Verify that range queries generate the correct row count estimates # foreach {testid where index rows} { 1 {z>=0 AND z<=0} t1z 400 2 {z>=1 AND z<=1} t1z 300 3 {z>=2 AND z<=2} t1z 175 |
︙ | ︙ |
Changes to test/analyze6.test.
︙ | ︙ | |||
13 14 15 16 17 18 19 | # in this file a corner-case query planner optimization involving the # join order of two tables of different sizes. # set testdir [file dirname $argv0] source $testdir/tester.tcl | | | 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | # in this file a corner-case query planner optimization involving the # join order of two tables of different sizes. # set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable !stat4 { finish_test return } set testprefix analyze6 proc eqp {sql {db db}} { |
︙ | ︙ | |||
57 58 59 60 61 62 63 | # The lowest cost plan is to scan CAT and for each integer there, do a single # lookup of the first corresponding entry in EV then read off the equal values # in EV. (Prior to the 2011-03-04 enhancement to where.c, this query would # have used EV for the outer loop instead of CAT - which was about 3x slower.) # do_test analyze6-1.1 { eqp {SELECT count(*) FROM ev, cat WHERE x=y} | | | | | | | | | | | | | | 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 | # The lowest cost plan is to scan CAT and for each integer there, do a single # lookup of the first corresponding entry in EV then read off the equal values # in EV. (Prior to the 2011-03-04 enhancement to where.c, this query would # have used EV for the outer loop instead of CAT - which was about 3x slower.) # do_test analyze6-1.1 { eqp {SELECT count(*) FROM ev, cat WHERE x=y} } {/*SCAN cat USING COVERING INDEX catx*SEARCH ev USING COVERING INDEX evy (y=?)*/} # The same plan is chosen regardless of the order of the tables in the # FROM clause. # do_eqp_test analyze6-1.2 { SELECT count(*) FROM cat, ev WHERE x=y } { QUERY PLAN |--SCAN cat USING COVERING INDEX catx `--SEARCH ev USING COVERING INDEX evy (y=?) } # Ticket [83ea97620bd3101645138b7b0e71c12c5498fe3d] 2011-03-30 # If ANALYZE is run on an empty table, make sure indices are used # on the table. # do_test analyze6-2.1 { execsql { CREATE TABLE t201(x INTEGER PRIMARY KEY, y UNIQUE, z); CREATE INDEX t201z ON t201(z); ANALYZE; } eqp {SELECT * FROM t201 WHERE z=5} } {/*SEARCH t201 USING INDEX t201z (z=?)*/} do_test analyze6-2.2 { eqp {SELECT * FROM t201 WHERE y=5} } {/*SEARCH t201 USING INDEX sqlite_autoindex_t201_1 (y=?)*/} do_test analyze6-2.3 { eqp {SELECT * FROM t201 WHERE x=5} } {/*SEARCH t201 USING INTEGER PRIMARY KEY (rowid=?)*/} do_test analyze6-2.4 { execsql { INSERT INTO t201 VALUES(1,2,3),(2,3,4),(3,4,5); ANALYZE t201; } eqp {SELECT * FROM t201 WHERE z=5} } {/*SEARCH t201 USING INDEX t201z (z=?)*/} do_test analyze6-2.5 { eqp {SELECT * FROM t201 WHERE y=5} } {/*SEARCH t201 USING INDEX sqlite_autoindex_t201_1 (y=?)*/} do_test analyze6-2.6 { eqp {SELECT * FROM t201 WHERE x=5} } {/*SEARCH t201 USING INTEGER PRIMARY KEY (rowid=?)*/} do_test analyze6-2.7 { execsql { INSERT INTO t201 VALUES(4,5,7); INSERT INTO t201 SELECT x+100, y+100, z+100 FROM t201; INSERT INTO t201 SELECT x+200, y+200, z+200 FROM t201; INSERT INTO t201 SELECT x+400, y+400, z+400 FROM t201; ANALYZE t201; } eqp {SELECT * FROM t201 WHERE z=5} } {/*SEARCH t201 USING INDEX t201z (z=?)*/} do_test analyze6-2.8 { eqp {SELECT * FROM t201 WHERE y=5} } {/*SEARCH t201 USING INDEX sqlite_autoindex_t201_1 (y=?)*/} do_test analyze6-2.9 { eqp {SELECT * FROM t201 WHERE x=5} } {/*SEARCH t201 USING INTEGER PRIMARY KEY (rowid=?)*/} finish_test |
Changes to test/analyze7.test.
︙ | ︙ | |||
33 34 35 36 37 38 39 | 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 WHERE value BETWEEN 1 AND 256; EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a=123; } | | | | | | | | | | | | | | | | | | | | 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 | 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 WHERE value BETWEEN 1 AND 256; EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a=123; } } {/*SEARCH t1 USING INDEX t1a (a=?)*/} do_test analyze7-1.1 { execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE b=123;} } {/*SEARCH t1 USING INDEX t1b (b=?)*/} do_test analyze7-1.2 { execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE c=2;} } {/*SEARCH t1 USING INDEX t1cd (c=?)*/} # Run an analyze on one of the three indices. Verify that this # effects the row-count estimate on the one query that uses that # one index. # do_test analyze7-2.0 { execsql {ANALYZE t1a;} db cache flush execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a=123;} } {/*SEARCH t1 USING INDEX t1a (a=?)*/} do_test analyze7-2.1 { execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE b=123;} } {/*SEARCH t1 USING INDEX t1b (b=?)*/} do_test analyze7-2.2 { execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE c=2;} } {/*SEARCH t1 USING INDEX t1cd (c=?)*/} # Verify that since the query planner now things that t1a is more # selective than t1b, it prefers to use t1a. # do_test analyze7-2.3 { execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a=123 AND b=123} } {/*SEARCH t1 USING INDEX t1a (a=?)*/} # Run an analysis on another of the three indices. Verify that this # new analysis works and does not disrupt the previous analysis. # do_test analyze7-3.0 { execsql {ANALYZE t1cd;} db cache flush; execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a=123;} } {/*SEARCH t1 USING INDEX t1a (a=?)*/} do_test analyze7-3.1 { execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE b=123;} } {/*SEARCH t1 USING INDEX t1b (b=?)*/} do_test analyze7-3.2.1 { execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE c=?;} } {/*SEARCH t1 USING INDEX t1cd (c=?)*/} ifcapable stat4 { # If ENABLE_STAT4 is defined, SQLite comes up with a different estimated # row count for (c=2) than it does for (c=?). do_test analyze7-3.2.2 { execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE c=2;} } {/*SEARCH t1 USING INDEX t1cd (c=?)*/} } else { # If ENABLE_STAT4 is not defined, the expected row count for (c=2) is the # same as that for (c=?). do_test analyze7-3.2.3 { execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE c=2;} } {/*SEARCH t1 USING INDEX t1cd (c=?)*/} } do_test analyze7-3.3 { execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a=123 AND b=123} } {/*SEARCH t1 USING INDEX t1a (a=?)*/} ifcapable {!stat4} { do_test analyze7-3.4 { execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE c=123 AND b=123} } {/*SEARCH t1 USING INDEX t1b (b=?)*/} do_test analyze7-3.5 { execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a=123 AND c=123} } {/*SEARCH t1 USING INDEX t1a (a=?)*/} } do_test analyze7-3.6 { execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE c=123 AND d=123 AND b=123} } {/*SEARCH t1 USING INDEX t1cd (c=? AND d=?)*/} finish_test |
Changes to test/analyze8.test.
1 2 3 4 5 6 7 8 9 10 11 12 | # 2011 August 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 implements tests for SQLite library. The focus of the tests | | | | 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 | # 2011 August 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 implements tests for SQLite library. The focus of the tests # in this file is testing the capabilities of sqlite_stat4. # set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable !stat4 { finish_test return } set testprefix analyze8 proc eqp {sql {db db}} { |
︙ | ︙ | |||
57 58 59 60 61 62 63 | # with a==100. And so for those cases, choose the t1b index. # # Buf ro a==99 and a==101, there are far fewer rows so choose # the t1a index. # do_test 1.1 { eqp {SELECT * FROM t1 WHERE a=100 AND b=55} | | | | | | | | | | | | | 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 | # with a==100. And so for those cases, choose the t1b index. # # Buf ro a==99 and a==101, there are far fewer rows so choose # the t1a index. # do_test 1.1 { eqp {SELECT * FROM t1 WHERE a=100 AND b=55} } {/*SEARCH t1 USING INDEX t1b (b=?)*/} do_test 1.2 { eqp {SELECT * FROM t1 WHERE a=99 AND b=55} } {/*SEARCH t1 USING INDEX t1a (a=?)*/} do_test 1.3 { eqp {SELECT * FROM t1 WHERE a=101 AND b=55} } {/*SEARCH t1 USING INDEX t1a (a=?)*/} do_test 1.4 { eqp {SELECT * FROM t1 WHERE a=100 AND b=56} } {/*SEARCH t1 USING INDEX t1b (b=?)*/} do_test 1.5 { eqp {SELECT * FROM t1 WHERE a=99 AND b=56} } {/*SEARCH t1 USING INDEX t1a (a=?)*/} do_test 1.6 { eqp {SELECT * FROM t1 WHERE a=101 AND b=56} } {/*SEARCH t1 USING INDEX t1a (a=?)*/} do_test 2.1 { eqp {SELECT * FROM t1 WHERE a=100 AND b BETWEEN 50 AND 54} } {/*SEARCH t1 USING INDEX t1b (b>? AND b<?)*/} # There are many more values of c between 0 and 100000 than there are # between 800000 and 900000. So t1c is more selective for the latter # range. # # Test 3.2 is a little unstable. It depends on the planner estimating # that (b BETWEEN 30 AND 34) will match more rows than (c BETWEEN # 800000 AND 900000). Which is a pretty close call (50 vs. 32), so # the planner could get it wrong with an unlucky set of samples. This # case happens to work, but others ("b BETWEEN 40 AND 44" for example) # will fail. # do_execsql_test 3.0 { SELECT count(*) FROM t1 WHERE b BETWEEN 30 AND 34; SELECT count(*) FROM t1 WHERE c BETWEEN 0 AND 100000; SELECT count(*) FROM t1 WHERE c BETWEEN 800000 AND 900000; } {50 376 32} do_test 3.1 { eqp {SELECT * FROM t1 WHERE b BETWEEN 30 AND 34 AND c BETWEEN 0 AND 100000} } {/*SEARCH t1 USING INDEX t1b (b>? AND b<?)*/} do_test 3.2 { eqp {SELECT * FROM t1 WHERE b BETWEEN 30 AND 34 AND c BETWEEN 800000 AND 900000} } {/*SEARCH t1 USING INDEX t1c (c>? AND c<?)*/} do_test 3.3 { eqp {SELECT * FROM t1 WHERE a=100 AND c BETWEEN 0 AND 100000} } {/*SEARCH t1 USING INDEX t1a (a=?)*/} do_test 3.4 { eqp {SELECT * FROM t1 WHERE a=100 AND c BETWEEN 800000 AND 900000} } {/*SEARCH t1 USING INDEX t1c (c>? AND c<?)*/} finish_test |
Changes to test/analyze9.test.
︙ | ︙ | |||
574 575 576 577 578 579 580 | if {$i %2} {set a abc} else {set a def} execsql { INSERT INTO t1(rowid, a, b, c) VALUES($i, $a, $i, $i) } } execsql ANALYZE } {} do_eqp_test 13.2.1 { SELECT * FROM t1 WHERE a='abc' AND rowid<15 AND b<12 | | | | | | 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 | if {$i %2} {set a abc} else {set a def} execsql { INSERT INTO t1(rowid, a, b, c) VALUES($i, $a, $i, $i) } } execsql ANALYZE } {} do_eqp_test 13.2.1 { SELECT * FROM t1 WHERE a='abc' AND rowid<15 AND b<12 } {/SEARCH t1 USING INDEX i1/} do_eqp_test 13.2.2 { SELECT * FROM t1 WHERE a='abc' AND rowid<'15' AND b<12 } {/SEARCH t1 USING INDEX i1/} do_eqp_test 13.3.1 { SELECT * FROM t1 WHERE a='abc' AND rowid<100 AND b<12 } {/SEARCH t1 USING INDEX i2/} do_eqp_test 13.3.2 { SELECT * FROM t1 WHERE a='abc' AND rowid<'100' AND b<12 } {/SEARCH t1 USING INDEX i2/} #------------------------------------------------------------------------- # Check also that affinities are taken into account when using stat4 data # to estimate the number of rows scanned by any other constraint on a # column other than the leftmost. # drop_all_tables |
︙ | ︙ | |||
605 606 607 608 609 610 611 | CREATE INDEX i1 ON t1(a, b); CREATE INDEX i2 ON t1(c); ANALYZE; } } {} do_eqp_test 13.2.1 { SELECT * FROM t1 WHERE a='ott' AND b<10 AND c=1 | | | | 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 | CREATE INDEX i1 ON t1(a, b); CREATE INDEX i2 ON t1(c); ANALYZE; } } {} do_eqp_test 13.2.1 { SELECT * FROM t1 WHERE a='ott' AND b<10 AND c=1 } {/SEARCH t1 USING INDEX i1/} do_eqp_test 13.2.2 { SELECT * FROM t1 WHERE a='ott' AND b<'10' AND c=1 } {/SEARCH t1 USING INDEX i1/} #------------------------------------------------------------------------- # By default, 16 non-periodic samples are collected for the stat4 table. # The following tests attempt to verify that the most common keys are # being collected. # proc check_stat4 {tn} { |
︙ | ︙ | |||
1052 1053 1054 1055 1056 1057 1058 | do_eqp_test 23.1 { SELECT * FROM t4 WHERE (e=1 AND b='xyz' AND c='zyx' AND a<'AEA') AND f<300 -- Formerly used index i41. But i41 is not a covering index whereas -- the PRIMARY KEY is a covering index, and so as of 2017-10-15, the -- PRIMARY KEY is preferred. | | | | 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 | do_eqp_test 23.1 { SELECT * FROM t4 WHERE (e=1 AND b='xyz' AND c='zyx' AND a<'AEA') AND f<300 -- Formerly used index i41. But i41 is not a covering index whereas -- the PRIMARY KEY is a covering index, and so as of 2017-10-15, the -- PRIMARY KEY is preferred. } {SEARCH t4 USING PRIMARY KEY (c=? AND b=? AND a<?)} do_eqp_test 23.2 { SELECT * FROM t4 WHERE (e=1 AND b='xyz' AND c='zyx' AND a<'JJJ') AND f<300 } {SEARCH t4 USING INDEX i42 (f<?)} do_execsql_test 24.0 { CREATE TABLE t5(c, d, b, e, a, PRIMARY KEY(a, b, c)) WITHOUT ROWID; WITH data(a, b, c, d, e) AS ( SELECT 'z', 'y', 0, 0, 0 UNION ALL SELECT |
︙ | ︙ | |||
1102 1103 1104 1105 1106 1107 1108 | CREATE INDEX bb ON t6(b); ANALYZE; } # Term (b<?) is estimated at 25%. Better than (a<30) but not as # good as (a<20). do_eqp_test 25.2.1 { SELECT * FROM t6 WHERE a<30 AND b<? } \ | | | | | | | 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 | CREATE INDEX bb ON t6(b); ANALYZE; } # Term (b<?) is estimated at 25%. Better than (a<30) but not as # good as (a<20). do_eqp_test 25.2.1 { SELECT * FROM t6 WHERE a<30 AND b<? } \ {SEARCH t6 USING INDEX bb (b<?)} do_eqp_test 25.2.2 { SELECT * FROM t6 WHERE a<20 AND b<? } \ {SEARCH t6 USING INDEX aa (a<?)} # Term (b BETWEEN ? AND ?) is estimated at 1/64. do_eqp_test 25.3.1 { SELECT * FROM t6 WHERE a BETWEEN 5 AND 10 AND b BETWEEN ? AND ? } {SEARCH t6 USING INDEX bb (b>? AND b<?)} # Term (b BETWEEN ? AND 60) is estimated to return roughly 15 rows - # 60 from (b<=60) multiplied by 0.25 for the b>=? term. Better than # (a<20) but not as good as (a<10). do_eqp_test 25.4.1 { SELECT * FROM t6 WHERE a < 10 AND (b BETWEEN ? AND 60) } {SEARCH t6 USING INDEX aa (a<?)} do_eqp_test 25.4.2 { SELECT * FROM t6 WHERE a < 20 AND (b BETWEEN ? AND 60) } {SEARCH t6 USING INDEX bb (b>? AND b<?)} } #------------------------------------------------------------------------- # Check that a problem in they way stat4 data is used has been # resolved (see below). # reset_db |
︙ | ︙ | |||
1176 1177 1178 1179 1180 1181 1182 | # no more than that. Guessing less than 20 is therefore unreasonable. # # At one point though, due to a problem in whereKeyStats(), the planner was # estimating that (x=10000 AND y<50) would match only 2 rows. # do_eqp_test 26.1.4 { SELECT * FROM t1 WHERE x = 10000 AND y < 50 AND z = 444; | | | 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 | # no more than that. Guessing less than 20 is therefore unreasonable. # # At one point though, due to a problem in whereKeyStats(), the planner was # estimating that (x=10000 AND y<50) would match only 2 rows. # do_eqp_test 26.1.4 { SELECT * FROM t1 WHERE x = 10000 AND y < 50 AND z = 444; } {SEARCH t1 USING INDEX t1z (z=?)} # This test - 26.2.* - tests that another manifestation of the same problem # is no longer present in the library. Assuming: # # CREATE INDEX t1xy ON t1(x, y) # |
︙ | ︙ | |||
1225 1226 1227 1228 1229 1230 1231 | UPDATE t1 SET z = (rowid / 95); ANALYZE; COMMIT; } do_eqp_test 26.2.2 { SELECT * FROM t1 WHERE x='B' AND y>25 AND z=?; | | | 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 | UPDATE t1 SET z = (rowid / 95); ANALYZE; COMMIT; } do_eqp_test 26.2.2 { SELECT * FROM t1 WHERE x='B' AND y>25 AND z=?; } {SEARCH t1 USING INDEX i1 (x=? AND y>?)} finish_test |
Deleted test/analyzeA.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted test/analyzeB.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to test/analyzeC.test.
︙ | ︙ | |||
46 47 48 49 50 51 52 | } {/.* USING INDEX t1a .a>. AND a<...*/} do_execsql_test 1.2 { SELECT c FROM t1 ORDER BY a; } {3 111 6 12 9 12} do_execsql_test 1.3 { EXPLAIN QUERY PLAN SELECT c FROM t1 ORDER BY a; | | | 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | } {/.* USING INDEX t1a .a>. AND a<...*/} do_execsql_test 1.2 { SELECT c FROM t1 ORDER BY a; } {3 111 6 12 9 12} do_execsql_test 1.3 { EXPLAIN QUERY PLAN SELECT c FROM t1 ORDER BY a; } {/.*SCAN t1 USING INDEX t1a.*/} do_execsql_test 1.3x { EXPLAIN QUERY PLAN SELECT c FROM t1 ORDER BY a; } {~/.*B-TREE FOR ORDER BY.*/} # Now mark the t1a index as "unordered". Range queries and ORDER BY no # longer use the index, but equality queries do. |
︙ | ︙ | |||
127 128 129 130 131 132 133 134 135 136 137 138 139 140 | ANALYZE sqlite_master; SELECT count(a) FROM t1; } {6} do_execsql_test 4.3 { EXPLAIN QUERY PLAN SELECT count(a) FROM t1; } {/.*INDEX t1ca.*/} # The sz=NNN parameter works even if there is other extraneous text # in the sqlite_stat1.stat column. # do_execsql_test 5.0 { DELETE FROM sqlite_stat1; | > > > > > > > > > > > > > > | 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 | ANALYZE sqlite_master; SELECT count(a) FROM t1; } {6} do_execsql_test 4.3 { EXPLAIN QUERY PLAN SELECT count(a) FROM t1; } {/.*INDEX t1ca.*/} # 2019-08-15. # Ticket https://www.sqlite.org/src/tktview/e4598ecbdd18bd82945f602901 # The sz=N parameter in the sqlite_stat1 table needs to have a value of # 2 or more to avoid a division by zero in the query planner. # do_execsql_test 4.4 { DROP TABLE IF EXISTS t44; CREATE TABLE t44(a PRIMARY KEY); INSERT INTO sqlite_stat1 VALUES('t44',null,'sz=0'); ANALYZE sqlite_master; SELECT 0 FROM t44 WHERE a IN(1,2,3); } {} # The sz=NNN parameter works even if there is other extraneous text # in the sqlite_stat1.stat column. # do_execsql_test 5.0 { DELETE FROM sqlite_stat1; |
︙ | ︙ |
Changes to test/analyzeD.test.
︙ | ︙ | |||
59 60 61 62 63 64 65 | } {} # With full ANALYZE data, SQLite sees that c=150 (5 rows) is better than # a=3001 (7 rows). # do_eqp_test 1.2 { SELECT * FROM t1 WHERE a=3001 AND c=150; | | | | | | 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 | } {} # With full ANALYZE data, SQLite sees that c=150 (5 rows) is better than # a=3001 (7 rows). # do_eqp_test 1.2 { SELECT * FROM t1 WHERE a=3001 AND c=150; } {SEARCH t1 USING INDEX t1_c (c=?)} do_test 1.3 { execsql { DELETE FROM sqlite_stat1 } db close sqlite3 db test.db } {} # Without stat1, because 3001 is larger than all samples in the stat4 # table, SQLite thinks that a=3001 matches just 1 row. So it (incorrectly) # chooses it over the c=150 index (5 rows). Even with stat1 data, things # worked this way before commit [e6f7f97dbc]. # do_eqp_test 1.4 { SELECT * FROM t1 WHERE a=3001 AND c=150; } {SEARCH t1 USING INDEX t1_ab (a=?)} do_test 1.5 { execsql { UPDATE t1 SET a=13 WHERE a = 3001; ANALYZE; } } {} do_eqp_test 1.6 { SELECT * FROM t1 WHERE a=13 AND c=150; } {SEARCH t1 USING INDEX t1_c (c=?)} do_test 1.7 { execsql { DELETE FROM sqlite_stat1 } db close sqlite3 db test.db } {} # Same test as 1.4, except this time the 7 rows that match the a=? condition # do not feature larger values than all rows in the stat4 table. So SQLite # gets this right, even without stat1 data. do_eqp_test 1.8 { SELECT * FROM t1 WHERE a=13 AND c=150; } {SEARCH t1 USING INDEX t1_c (c=?)} finish_test |
Changes to test/analyzeE.test.
︙ | ︙ | |||
32 33 34 35 36 37 38 | INSERT INTO t1(a,b) SELECT x, x FROM cnt; CREATE INDEX t1a ON t1(a); ANALYZE; } {} do_execsql_test analyzeE-1.1 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a BETWEEN 500 AND 2500; | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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 | INSERT INTO t1(a,b) SELECT x, x FROM cnt; CREATE INDEX t1a ON t1(a); ANALYZE; } {} do_execsql_test analyzeE-1.1 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a BETWEEN 500 AND 2500; } {/SCAN t1/} do_execsql_test analyzeE-1.2 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a BETWEEN 2900 AND 3000; } {/SEARCH t1 USING INDEX t1a/} do_execsql_test analyzeE-1.3 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a BETWEEN 1700 AND 1750; } {/SEARCH t1 USING INDEX t1a/} do_execsql_test analyzeE-1.4 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a BETWEEN 1 AND 500 } {/SEARCH t1 USING INDEX t1a/} do_execsql_test analyzeE-1.5 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a BETWEEN 3000 AND 3000000 } {/SEARCH t1 USING INDEX t1a/} do_execsql_test analyzeE-1.6 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a<500 } {/SEARCH t1 USING INDEX t1a/} do_execsql_test analyzeE-1.7 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a>2500 } {/SEARCH t1 USING INDEX t1a/} do_execsql_test analyzeE-1.8 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a>1900 } {/SEARCH t1 USING INDEX t1a/} do_execsql_test analyzeE-1.9 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a>1100 } {/SCAN t1/} do_execsql_test analyzeE-1.10 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a<1100 } {/SEARCH t1 USING INDEX t1a/} do_execsql_test analyzeE-1.11 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a<1900 } {/SCAN t1/} # Verify that everything works the same on a DESCENDING index. # do_execsql_test analyzeE-2.0 { DROP INDEX t1a; CREATE INDEX t1a ON t1(a DESC); ANALYZE; } {} do_execsql_test analyzeE-2.1 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a BETWEEN 500 AND 2500; } {/SCAN t1/} do_execsql_test analyzeE-2.2 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a BETWEEN 2900 AND 3000; } {/SEARCH t1 USING INDEX t1a/} do_execsql_test analyzeE-2.3 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a BETWEEN 1700 AND 1750; } {/SEARCH t1 USING INDEX t1a/} do_execsql_test analyzeE-2.4 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a BETWEEN 1 AND 500 } {/SEARCH t1 USING INDEX t1a/} do_execsql_test analyzeE-2.5 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a BETWEEN 3000 AND 3000000 } {/SEARCH t1 USING INDEX t1a/} do_execsql_test analyzeE-2.6 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a<500 } {/SEARCH t1 USING INDEX t1a/} do_execsql_test analyzeE-2.7 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a>2500 } {/SEARCH t1 USING INDEX t1a/} do_execsql_test analyzeE-2.8 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a>1900 } {/SEARCH t1 USING INDEX t1a/} do_execsql_test analyzeE-2.9 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a>1100 } {/SCAN t1/} do_execsql_test analyzeE-2.10 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a<1100 } {/SEARCH t1 USING INDEX t1a/} do_execsql_test analyzeE-2.11 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a<1900 } {/SCAN t1/} # Now do a range query on the second term of an ASCENDING index # where the first term is constrained by equality. # do_execsql_test analyzeE-3.0 { DROP TABLE t1; CREATE TABLE t1(a,b,c); WITH RECURSIVE cnt(x) AS (VALUES(1000) UNION ALL SELECT x+1 FROM cnt WHERE x<2000) INSERT INTO t1(a,b,c) SELECT x, x, 123 FROM cnt; CREATE INDEX t1ca ON t1(c,a); ANALYZE; } {} do_execsql_test analyzeE-3.1 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a BETWEEN 500 AND 2500 AND c=123; } {/SCAN t1/} do_execsql_test analyzeE-3.2 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a BETWEEN 2900 AND 3000 AND c=123; } {/SEARCH t1 USING INDEX t1ca/} do_execsql_test analyzeE-3.3 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a BETWEEN 1700 AND 1750 AND c=123; } {/SEARCH t1 USING INDEX t1ca/} do_execsql_test analyzeE-3.4 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a BETWEEN 1 AND 500 AND c=123 } {/SEARCH t1 USING INDEX t1ca/} do_execsql_test analyzeE-3.5 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a BETWEEN 3000 AND 3000000 AND c=123 } {/SEARCH t1 USING INDEX t1ca/} do_execsql_test analyzeE-3.6 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a<500 AND c=123 } {/SEARCH t1 USING INDEX t1ca/} do_execsql_test analyzeE-3.7 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a>2500 AND c=123 } {/SEARCH t1 USING INDEX t1ca/} do_execsql_test analyzeE-3.8 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a>1900 AND c=123 } {/SEARCH t1 USING INDEX t1ca/} do_execsql_test analyzeE-3.9 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a>1100 AND c=123 } {/SCAN t1/} do_execsql_test analyzeE-3.10 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a<1100 AND c=123 } {/SEARCH t1 USING INDEX t1ca/} do_execsql_test analyzeE-3.11 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a<1900 AND c=123 } {/SCAN t1/} # Repeat the 3.x tests using a DESCENDING index # do_execsql_test analyzeE-4.0 { DROP INDEX t1ca; CREATE INDEX t1ca ON t1(c ASC,a DESC); ANALYZE; } {} do_execsql_test analyzeE-4.1 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a BETWEEN 500 AND 2500 AND c=123; } {/SCAN t1/} do_execsql_test analyzeE-4.2 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a BETWEEN 2900 AND 3000 AND c=123; } {/SEARCH t1 USING INDEX t1ca/} do_execsql_test analyzeE-4.3 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a BETWEEN 1700 AND 1750 AND c=123; } {/SEARCH t1 USING INDEX t1ca/} do_execsql_test analyzeE-4.4 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a BETWEEN 1 AND 500 AND c=123 } {/SEARCH t1 USING INDEX t1ca/} do_execsql_test analyzeE-4.5 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a BETWEEN 3000 AND 3000000 AND c=123 } {/SEARCH t1 USING INDEX t1ca/} do_execsql_test analyzeE-4.6 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a<500 AND c=123 } {/SEARCH t1 USING INDEX t1ca/} do_execsql_test analyzeE-4.7 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a>2500 AND c=123 } {/SEARCH t1 USING INDEX t1ca/} do_execsql_test analyzeE-4.8 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a>1900 AND c=123 } {/SEARCH t1 USING INDEX t1ca/} do_execsql_test analyzeE-4.9 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a>1100 AND c=123 } {/SCAN t1/} do_execsql_test analyzeE-4.10 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a<1100 AND c=123 } {/SEARCH t1 USING INDEX t1ca/} do_execsql_test analyzeE-4.11 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a<1900 AND c=123 } {/SCAN t1/} finish_test |
Changes to test/analyzeF.test.
︙ | ︙ | |||
58 59 60 61 62 63 64 | 9 "x = str('19') AND y = str('4')" {t1y (y=?)} 10 "x = str('4') AND y = str('19')" {t1y (y=?)} 11 "x = nullif('19', 0) AND y = nullif('4', 0)" {t1y (y=?)} 12 "x = nullif('4', 0) AND y = nullif('19', 0)" {t1y (y=?)} } { | | | 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | 9 "x = str('19') AND y = str('4')" {t1y (y=?)} 10 "x = str('4') AND y = str('19')" {t1y (y=?)} 11 "x = nullif('19', 0) AND y = nullif('4', 0)" {t1y (y=?)} 12 "x = nullif('4', 0) AND y = nullif('19', 0)" {t1y (y=?)} } { set res "SEARCH t1 USING INDEX $idx" do_eqp_test 1.$tn "SELECT * FROM t1 WHERE $where" $res } # Test that functions that do not exist - "func()" - do not cause an error. # do_catchsql_test 2.1 { SELECT * FROM t1 WHERE x = substr('145', 2, 1) AND y = func(1, 2, 3) |
︙ | ︙ | |||
88 89 90 91 92 93 94 | foreach {tn where idx} { 1 "x = det4() AND y = det19()" {t1x (x=?)} 2 "x = det19() AND y = det4()" {t1y (y=?)} 3 "x = nondet4() AND y = nondet19()" {t1y (y=?)} 4 "x = nondet19() AND y = nondet4()" {t1y (y=?)} } { | | | 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 | foreach {tn where idx} { 1 "x = det4() AND y = det19()" {t1x (x=?)} 2 "x = det19() AND y = det4()" {t1y (y=?)} 3 "x = nondet4() AND y = nondet19()" {t1y (y=?)} 4 "x = nondet19() AND y = nondet4()" {t1y (y=?)} } { set res "SEARCH t1 USING INDEX $idx" do_eqp_test 3.$tn "SELECT * FROM t1 WHERE $where" $res } execsql { DELETE FROM t1 } proc throw_error {err} { error $err } |
︙ | ︙ |
Added test/analyzeG.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 | # 2020-02-23 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # Tests for functionality related to ANALYZE. # set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable !stat4 { finish_test return } set testprefix analyzeG #------------------------------------------------------------------------- # Test cases 1.* seek to verify that even if an index is not used, its # stat4 data may be used by the planner to estimate the number of # rows that match an unindexed constraint on the same column. # do_execsql_test 1.0 { PRAGMA automatic_index = 0; CREATE TABLE t1(a, x); CREATE TABLE t2(b, y); WITH s(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<100 ) INSERT INTO t1 SELECT (i%50), NULL FROM s; WITH s(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<100 ) INSERT INTO t2 SELECT (CASE WHEN i<95 THEN 44 ELSE i END), NULL FROM s; } # Join tables t1 and t2. Both contain 100 rows. (a=44) matches 2 rows # in "t1", (b=44) matches 95 rows in table "t2". But the planner doesn't # know this, so it has no preference as to which order the tables are # scanned in. In practice this means that tables are scanned in the order # they are specified in in the FROM clause. do_eqp_test 1.1.1 { SELECT * FROM t1, t2 WHERE a=44 AND b=44; } { } do_eqp_test 1.1.2 { SELECT * FROM t2, t1 WHERE a=44 AND b=44 } { QUERY PLAN |--SCAN t2 `--SCAN t1 } do_execsql_test 1.2 { CREATE INDEX t2b ON t2(b); ANALYZE; } # Now, with the ANALYZE data, the planner knows that (b=44) matches a # large number of rows. So it elects to scan table "t1" first, regardless # of the order in which the tables are specified in the FROM clause. do_eqp_test 1.3.1 { SELECT * FROM t1, t2 WHERE a=44 AND b=44; } { QUERY PLAN |--SCAN t1 `--SCAN t2 } do_eqp_test 1.3.2 { SELECT * FROM t2, t1 WHERE a=44 AND b=44 } { QUERY PLAN |--SCAN t1 `--SCAN t2 } finish_test |
Changes to test/atof1.test.
︙ | ︙ | |||
51 52 53 54 55 56 57 58 59 60 | puts [format {QUOTE: %16s %s} {} [db eval {SELECT quote($x)}]] db eval {SELECT CAST(quote($x) AS real) c} {} puts "OUT: $b [format %.32e $c]" } set y } {1} } finish_test | > > > > > > > > > > > > > > > > > > > > > > > > | 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 | puts [format {QUOTE: %16s %s} {} [db eval {SELECT quote($x)}]] db eval {SELECT CAST(quote($x) AS real) c} {} puts "OUT: $b [format %.32e $c]" } set y } {1} } # 2020-01-08 ticket 9eda2697f5cc1aba # When running sqlite3AtoF() on a blob with an odd number of bytes using # UTF16, ignore the last byte so that the string has an integer number of # UTF16 code points. # reset_db do_execsql_test atof1-2.10 { PRAGMA encoding = 'UTF16be'; CREATE TABLE t1(a, b); INSERT INTO t1(rowid,a) VALUES (1,x'00'),(2,3); SELECT substr(a,',') is true FROM t1 ORDER BY rowid; } {0 1} do_execsql_test atof1-2.20 { SELECT substr(a,',') is true FROM t1 ORDER BY rowid DESC; } {1 0} do_execsql_test atof1-2.30 { CREATE INDEX i1 ON t1(a); SELECT count(*) FROM t1 WHERE substr(a,','); } {1} # 2020-08-27 OSSFuzz find related to the above. do_execsql_test atof1-2.40 { SELECT randomblob(0) - 1; } {-1} finish_test |
Changes to test/atrc.c.
︙ | ︙ | |||
71 72 73 74 75 76 77 | sqlite3_str *pUndo /* Append SQL to undo the rename here */ ){ sqlite3_stmt *pStmt; int rc; int cnt = 0; rc = sqlite3_prepare_v2(db, | | | 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 | sqlite3_str *pUndo /* Append SQL to undo the rename here */ ){ sqlite3_stmt *pStmt; int rc; int cnt = 0; rc = sqlite3_prepare_v2(db, "SELECT name FROM sqlite_schema WHERE type='table'" " AND name NOT LIKE 'sqlite_%';", -1, &pStmt, 0); if( rc ) return rc; while( sqlite3_step(pStmt)==SQLITE_ROW ){ const char *zTab = (const char*)sqlite3_column_text(pStmt, 0); char *zNewTab; char zPrefix[2]; |
︙ | ︙ |
Changes to test/attach.test.
︙ | ︙ | |||
144 145 146 147 148 149 150 | } } {1 {database db5 is already in use}} do_test attach-1.14 { catchsql { ATTACH 'test.db' as db9; } } {1 {database db9 is already in use}} | | < | < | < | < | 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 | } } {1 {database db5 is already in use}} do_test attach-1.14 { catchsql { ATTACH 'test.db' as db9; } } {1 {database db9 is already in use}} do_catchsql_test attach-1.15 { ATTACH 'test.db' as main; } {1 {database main is already in use}} ifcapable tempdb { do_test attach-1.16 { catchsql { ATTACH 'test.db' as temp; } } {1 {database temp is already in use}} } do_catchsql_test attach-1.17 { ATTACH 'test.db' as MAIN; } {1 {database MAIN is already in use}} do_test attach-1.18 { catchsql { ATTACH 'test.db' as db10; ATTACH 'test.db' as db11; } } {0 {}} |
︙ | ︙ | |||
226 227 228 229 230 231 232 233 234 235 236 237 238 239 | } } {1 {no such database: db12}} do_test attach-1.26 { catchsql { DETACH main; } } {1 {cannot detach database main}} ifcapable tempdb { do_test attach-1.27 { catchsql { DETACH Temp; } } {1 {cannot detach database Temp}} | > | 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 | } } {1 {no such database: db12}} do_test attach-1.26 { catchsql { DETACH main; } } {1 {cannot detach database main}} ifcapable tempdb { do_test attach-1.27 { catchsql { DETACH Temp; } } {1 {cannot detach database Temp}} |
︙ | ︙ | |||
908 909 910 911 912 913 914 915 916 | CREATE TABLE db2.Table2(col1 INTEGER, col2 INTEGER, col3 INTEGER, col4); CREATE UNIQUE INDEX db2.idx_col1_unique ON Table2 (col1); CREATE UNIQUE INDEX db2.idx_col23_unique ON Table2 (col2, col3); CREATE INDEX db2.idx_col2 ON Table2 (col2); INSERT INTO Table2 VALUES(1,2,3,4); PRAGMA integrity_check; } {ok} finish_test | > > > > > > > > > > > > > > > | 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 | CREATE TABLE db2.Table2(col1 INTEGER, col2 INTEGER, col3 INTEGER, col4); CREATE UNIQUE INDEX db2.idx_col1_unique ON Table2 (col1); CREATE UNIQUE INDEX db2.idx_col23_unique ON Table2 (col2, col3); CREATE INDEX db2.idx_col2 ON Table2 (col2); INSERT INTO Table2 VALUES(1,2,3,4); PRAGMA integrity_check; } {ok} # 2021-03-10 Forum post https://sqlite.org/forum/forumpost/a006d86f72 # reset_db do_test attach-13.1 { sqlite3 db :memory: db eval {CREATE TABLE base(x);} for {set i 0} {$i<$SQLITE_MAX_ATTACHED} {incr i} { db eval "ATTACH ':memory:' AS a$i" } set m "a[expr {$SQLITE_MAX_ATTACHED-1}]" db eval "CREATE TABLE $m.t1(a INTEGER PRIMARY KEY, b);" db eval "CREATE TABLE $m.t2(a INTEGER PRIMARY KEY, b);" db eval {SELECT a FROM t1 WHERE b IN (SELECT a FROM t2);} } {} finish_test |
Changes to test/attach4.test.
︙ | ︙ | |||
110 111 112 113 114 115 116 117 118 | lappend L $name [execsql "SELECT x FROM $name.tbl"] } set L } $files db close foreach {name f} $files { forcedelete $f } finish_test | > > > > > > > > > > > > > > > > > > > | 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 | lappend L $name [execsql "SELECT x FROM $name.tbl"] } set L } $files db close foreach {name f} $files { forcedelete $f } #------------------------------------------------------------------------- reset_db do_execsql_test 2.0 { ATTACH DATABASE '' AS aux; CREATE TABLE IF NOT EXISTS aux.t1(a, b); CREATE TEMPORARY TRIGGER tr1 DELETE ON t1 BEGIN DELETE FROM t1; END; CREATE TABLE temp.t1(a, b); } do_execsql_test 2.1 { DETACH DATABASE aux; } do_execsql_test 2.2 { DROP TRIGGER tr1; } finish_test |
Changes to test/auth.test.
︙ | ︙ | |||
1387 1388 1389 1390 1391 1392 1393 | set ::authargs [list $arg1 $arg2 $arg3 $arg4] return SQLITE_DENY } return SQLITE_OK } catchsql {DROP INDEX i2} } {1 {not authorized}} | | > > > > > > > > > > > > > > | 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 | set ::authargs [list $arg1 $arg2 $arg3 $arg4] return SQLITE_DENY } return SQLITE_OK } catchsql {DROP INDEX i2} } {1 {not authorized}} do_test auth-1.205a { set ::authargs } {i2 t2 main {}} db eval { ATTACH ':memory:' as di205; CREATE TABLE di205.t1(x); CREATE INDEX di205.t1x ON t1(x); } do_catchsql_test auth-1.205b { DROP INDEX di205.t1x; } {1 {not authorized}} db eval { DETACH di205; } do_test auth-1.206 { set ::authargs } {t1x t1 di205 {}} do_test auth-1.207 { execsql {SELECT name FROM sqlite_master} } {t2 i2} do_test auth-1.208 { proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_DELETE" && $arg1=="sqlite_master"} { return SQLITE_IGNORE |
︙ | ︙ | |||
2446 2447 2448 2449 2450 2451 2452 | DROP TABLE v1chng; } } } ifcapable stat4 { set stat4 "sqlite_stat4 " } else { | < < < | < | 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 | DROP TABLE v1chng; } } } ifcapable stat4 { set stat4 "sqlite_stat4 " } else { set stat4 "" } do_test auth-5.2 { execsql { SELECT name FROM ( SELECT * FROM sqlite_master UNION ALL SELECT * FROM temp.sqlite_master) WHERE type='table' ORDER BY name |
︙ | ︙ |
Changes to test/auth3.test.
︙ | ︙ | |||
111 112 113 114 115 116 117 | set sqlite_search_count } {1} # 2016-07-28. A problem report from a private client complaining about # an authorizer failure during an ALTER TABLE. The solution (I think) is # to disable the authorizer during schema parsing. # | > | | | | | | | | | | | | | > | 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 | set sqlite_search_count } {1} # 2016-07-28. A problem report from a private client complaining about # an authorizer failure during an ALTER TABLE. The solution (I think) is # to disable the authorizer during schema parsing. # ifcapable altertable { proc auth {code args} { if {$code=="SQLITE_READ" && [regexp {DoNotRead} $args]} { return SQLITE_DENY } return SQLITE_OK } do_execsql_test auth3-3.0 { CREATE TEMPORARY TABLE TempTable ( key TEXT NOT NULL ON CONFLICT FAIL UNIQUE ON CONFLICT REPLACE, value TEXT NOT NULL ON CONFLICT FAIL); ALTER TABLE TempTable RENAME TO DoNotRead; SELECT name FROM temp.sqlite_master; } {DoNotRead sqlite_autoindex_DoNotRead_1} } finish_test |
Changes to test/autoinc.test.
︙ | ︙ | |||
12 13 14 15 16 17 18 19 20 21 22 23 24 25 | # focus of this script is testing the AUTOINCREMENT features. # # $Id: autoinc.test,v 1.14 2009/06/23 20:28:54 drh Exp $ # set testdir [file dirname $argv0] source $testdir/tester.tcl # If the library is not compiled with autoincrement support then # skip all tests in this file. # ifcapable {!autoinc} { finish_test return | > | 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | # focus of this script is testing the AUTOINCREMENT features. # # $Id: autoinc.test,v 1.14 2009/06/23 20:28:54 drh Exp $ # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix autoinc # If the library is not compiled with autoincrement support then # skip all tests in this file. # ifcapable {!autoinc} { finish_test return |
︙ | ︙ | |||
851 852 853 854 855 856 857 858 859 | set res [catch {db eval { INSERT INTO t1(b) VALUES('two'),('three'),('four'); INSERT INTO t1(b) VALUES('five'); PRAGMA integrity_check; }} msg] lappend res $msg } {0 ok} finish_test | > > > > > > > > > > > > > > > > > > > > > > > | 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 | set res [catch {db eval { INSERT INTO t1(b) VALUES('two'),('three'),('four'); INSERT INTO t1(b) VALUES('five'); PRAGMA integrity_check; }} msg] lappend res $msg } {0 ok} #-------------------------------------------------------------------------- reset_db do_execsql_test 13.0 { CREATE TABLE t1(i INTEGER PRIMARY KEY AUTOINCREMENT, j); CREATE TABLE t2(i INTEGER PRIMARY KEY AUTOINCREMENT, j); CREATE TABLE t3(i INTEGER PRIMARY KEY AUTOINCREMENT, j); INSERT INTO t1 VALUES(NULL, 1); INSERT INTO t2 VALUES(NULL, 2); INSERT INTO t3 VALUES(NULL, 3); SELECT name FROM sqlite_sequence; } {t1 t2 t3} do_execsql_test 13.1 { UPDATE sqlite_sequence SET name=NULL WHERE name='t2'; INSERT INTO t3 VALUES(NULL, 4); DELETE FROM t3; INSERT INTO t3 VALUES(NULL, 5); SELECT * FROM t3; } {3 5} finish_test |
Changes to test/autoindex1.test.
︙ | ︙ | |||
179 180 181 182 183 184 185 | ANALYZE sqlite_master; } do_eqp_test autoindex1-500.1 { SELECT b FROM t501 WHERE t501.a IN (SELECT x FROM t502 WHERE y=?); } { QUERY PLAN | | | | | | | | | | | 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 | ANALYZE sqlite_master; } do_eqp_test autoindex1-500.1 { SELECT b FROM t501 WHERE t501.a IN (SELECT x FROM t502 WHERE y=?); } { QUERY PLAN |--SEARCH t501 USING INTEGER PRIMARY KEY (rowid=?) `--LIST SUBQUERY xxxxxx `--SCAN t502 } do_eqp_test autoindex1-501 { SELECT b FROM t501 WHERE t501.a IN (SELECT x FROM t502 WHERE y=t501.b); } { QUERY PLAN |--SCAN t501 `--CORRELATED LIST SUBQUERY xxxxxx `--SEARCH t502 USING AUTOMATIC COVERING INDEX (y=?) } do_eqp_test autoindex1-502 { SELECT b FROM t501 WHERE t501.a=123 AND t501.a IN (SELECT x FROM t502 WHERE y=t501.b); } { QUERY PLAN |--SEARCH t501 USING INTEGER PRIMARY KEY (rowid=?) `--CORRELATED LIST SUBQUERY xxxxxx `--SCAN t502 } # The following code checks a performance regression reported on the # mailing list on 2010-10-19. The problem is that the nRowEst field # of ephermeral tables was not being initialized correctly and so no # automatic index was being created for the emphemeral table when it was # used as part of a join. |
︙ | ︙ | |||
273 274 275 276 277 278 279 | AND later.owner_change_date > prev.owner_change_date AND later.owner_change_date <= s.date_of_registration||' 00:00:00') ) y ON x.sheep_no = y.sheep_no WHERE y.sheep_no IS NULL ORDER BY x.registering_flock; } { QUERY PLAN | | | | | | | | | | 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 | AND later.owner_change_date > prev.owner_change_date AND later.owner_change_date <= s.date_of_registration||' 00:00:00') ) y ON x.sheep_no = y.sheep_no WHERE y.sheep_no IS NULL ORDER BY x.registering_flock; } { QUERY PLAN |--MATERIALIZE y | |--SCAN s | |--SEARCH prev USING INDEX sqlite_autoindex_flock_owner_1 (flock_no=? AND owner_change_date<?) | `--CORRELATED SCALAR SUBQUERY xxxxxx | `--SEARCH later USING COVERING INDEX sqlite_autoindex_flock_owner_1 (flock_no=? AND owner_change_date>? AND owner_change_date<?) |--SCAN x USING INDEX sheep_reg_flock_index `--SEARCH y USING AUTOMATIC COVERING INDEX (sheep_no=?) } do_execsql_test autoindex1-700 { CREATE TABLE t5(a, b, c); } do_eqp_test autoindex1-700a { SELECT a FROM t5 WHERE b=10 ORDER BY c; } { QUERY PLAN |--SCAN t5 `--USE TEMP B-TREE FOR ORDER BY } # The following checks a performance issue reported on the sqlite-dev # mailing list on 2013-01-10 # do_execsql_test autoindex1-800 { |
︙ | ︙ | |||
409 410 411 412 413 414 415 | EXPLAIN QUERY PLAN SELECT * FROM data JOIN mimetypes ON (data.mimetype_id=mimetypes._id) JOIN raw_contacts ON (data.raw_contact_id=raw_contacts._id) JOIN accounts ON (raw_contacts.account_id=accounts._id) WHERE mimetype_id=10 AND data14 IS NOT NULL; | | | | 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 | EXPLAIN QUERY PLAN SELECT * FROM data JOIN mimetypes ON (data.mimetype_id=mimetypes._id) JOIN raw_contacts ON (data.raw_contact_id=raw_contacts._id) JOIN accounts ON (raw_contacts.account_id=accounts._id) WHERE mimetype_id=10 AND data14 IS NOT NULL; } {/SEARCH data .*SEARCH raw_contacts/} do_execsql_test autoindex1-801 { EXPLAIN QUERY PLAN SELECT * FROM data JOIN mimetypes ON (data.mimetype_id=mimetypes._id) JOIN raw_contacts ON (data.raw_contact_id=raw_contacts._id) JOIN accounts ON (raw_contacts.account_id=accounts._id) WHERE mimetypes._id=10 AND data14 IS NOT NULL; } {/SEARCH data .*SEARCH raw_contacts/} # Another test case from an important user of SQLite. The key feature of # this test is that the "aggindex" subquery should make use of an # automatic index. If it does, the query is fast. If it does not, the # query is deathly slow. It worked OK in 3.7.17 but started going slow # with version 3.8.0. The problem was fixed for 3.8.7 by reducing the # cost estimate for automatic indexes on views and subqueries. |
︙ | ︙ |
Changes to test/autoindex3.test.
︙ | ︙ | |||
70 71 72 73 74 75 76 | DROP TABLE IF EXISTS sqlite_stat4; ANALYZE sqlite_master; } # At one point, SQLite was using the inferior plan: # | | | | | | 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 | DROP TABLE IF EXISTS sqlite_stat4; ANALYZE sqlite_master; } # At one point, SQLite was using the inferior plan: # # 0|0|1|SEARCH v USING INDEX ve (e>?) # 0|1|0|SEARCH u USING COVERING INDEX uab (ANY(a) AND b=?) # # on the basis that the real index "uab" must be better than the automatic # index. This is not right - a skip-scan is not necessarily better than an # automatic index scan. # do_eqp_test 220 { select count(*) from u, v where u.b = v.b and v.e > 34; } { QUERY PLAN |--SEARCH v USING INDEX ve (e>?) `--SEARCH u USING AUTOMATIC COVERING INDEX (b=?) } finish_test |
Changes to test/autoindex5.test.
︙ | ︙ | |||
98 99 100 101 102 103 104 | WHERE sp.rowid = st.package AND st.bug_name = bugs.name AND ( st.bug_name LIKE 'CVE-%' OR st.bug_name LIKE 'TEMP-%' ) AND ( sp.release = 'sid' OR sp.release = 'stretch' OR sp.release = 'jessie' OR sp.release = 'wheezy' OR sp.release = 'squeeze' ) ORDER BY sp.name, st.bug_name, sp.release, sp.subrelease; | | > > > > > > > > > > > > > > > > > > > | 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 | WHERE sp.rowid = st.package AND st.bug_name = bugs.name AND ( st.bug_name LIKE 'CVE-%' OR st.bug_name LIKE 'TEMP-%' ) AND ( sp.release = 'sid' OR sp.release = 'stretch' OR sp.release = 'jessie' OR sp.release = 'wheezy' OR sp.release = 'squeeze' ) ORDER BY sp.name, st.bug_name, sp.release, sp.subrelease; } {SEARCH debian_cve USING AUTOMATIC COVERING INDEX (bug_name=?)} #------------------------------------------------------------------------- # Test that ticket [8a2adec1] has been fixed. # do_execsql_test 2.1 { CREATE TABLE one(o); INSERT INTO one DEFAULT VALUES; CREATE TABLE t1(x, z); INSERT INTO t1 VALUES('aaa', 4.0); INSERT INTO t1 VALUES('aaa', 4.0); CREATE VIEW vvv AS SELECT * FROM t1 UNION ALL SELECT 0, 0 WHERE 0; SELECT ( SELECT sum(z) FROM vvv WHERE x='aaa' ) FROM one; } {8.0} # At one point the following was returning "no such column: rowid". This # was incorrect - "rowid" matches against the rowid of table t1 in this # query. do_catchsql_test 2.2 { DROP TABLE t1; CREATE TABLE t1(aaa); INSERT INTO t1(aaa) VALUES(9); SELECT ( SELECT aaa FROM t1 GROUP BY ( SELECT bbb FROM ( SELECT ccc AS bbb FROM ( SELECT 1 ccc ) WHERE rowid IS NOT 1 ) WHERE bbb = 1 ) ); } {0 9} # Ticket https://www.sqlite.org/src/info/787fa716be3a7f65 # Segfault due to multiple uses of the same subquery where the # subquery is implemented via coroutine. # ifcapable windowfunc { sqlite3 db :memory: do_execsql_test 3.0 { -- This is the original test case reported on the mailing list CREATE TABLE artists ( id integer NOT NULL PRIMARY KEY AUTOINCREMENT, name varchar(255) ); |
︙ | ︙ | |||
162 163 164 165 166 167 168 169 170 171 172 173 174 175 | WHERE (name = 'Al') ) AS 't1' WHERE (x = 1) )) AND (albums.id IN (1, 2))) )); } {1 Ar} # The remaining test cases were discovered (by Dan) during trouble-shooting sqlite3 db :memory: do_execsql_test 3.1 { CREATE TABLE t1 (a); INSERT INTO t1 (a) VALUES (104); CREATE TABLE t2 (b); INSERT INTO t2 (b) VALUES (104); CREATE TABLE t3 (c); INSERT INTO t3 (c) VALUES (104); CREATE TABLE t4 (d); INSERT INTO t4 (d) VALUES (104); | > > | 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 | WHERE (name = 'Al') ) AS 't1' WHERE (x = 1) )) AND (albums.id IN (1, 2))) )); } {1 Ar} } ;# windowfunc # The remaining test cases were discovered (by Dan) during trouble-shooting sqlite3 db :memory: do_execsql_test 3.1 { CREATE TABLE t1 (a); INSERT INTO t1 (a) VALUES (104); CREATE TABLE t2 (b); INSERT INTO t2 (b) VALUES (104); CREATE TABLE t3 (c); INSERT INTO t3 (c) VALUES (104); CREATE TABLE t4 (d); INSERT INTO t4 (d) VALUES (104); |
︙ | ︙ |
Changes to test/autovacuum.test.
1 2 3 4 5 6 7 8 9 10 11 | # 2001 September 15 # # 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 | | < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | # 2001 September 15 # # 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 the autovacuum feature. # set testdir [file dirname $argv0] source $testdir/tester.tcl # If this build of the library does not support auto-vacuum, omit this # whole file. ifcapable {!autovacuum || !pragma} { |
︙ | ︙ |
Added test/autovacuum2.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 | # 2021-10-15 # # 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 the sqlite3_autovacuum_pages() interface # set testdir [file dirname $argv0] source $testdir/tester.tcl # If this build of the library does not support auto-vacuum, omit this # whole file. ifcapable {!autovacuum || !pragma} { finish_test return } # Demonstrate basic sqlite3_autovacuum_pages functionality # do_execsql_test autovacuum2-1.0 { PRAGMA page_size=1024; PRAGMA auto_vacuum=FULL; CREATE TABLE t1(x); VACUUM; INSERT INTO t1(x) VALUES(zeroblob(10000)); PRAGMA page_count; } {12} proc autovac_page_callback {schema filesize freesize pagesize} { global autovac_callback_data lappend autovac_callback_data $schema $filesize $freesize $pagesize return [expr {$freesize/2}] } sqlite3_autovacuum_pages db autovac_page_callback set autovac_callback_data {} do_execsql_test autovacuum2-1.1 { BEGIN; DELETE FROM t1; PRAGMA freelist_count; PRAGMA page_count; } {9 12} do_execsql_test autovacuum2-1.2 { COMMIT; } {} do_test autovacuum2-1.3 { set autovac_callback_data } {main 12 9 1024} do_execsql_test autovacuum2-1.4 { PRAGMA freelist_count; PRAGMA page_count; } {5 8} do_execsql_test autovacuum2-1.5 { PRAGMA integrity_check; } {ok} # Disable the autovacuum-pages callback. Then do any transaction. # The database should shrink to minimal size # sqlite3_autovacuum_pages db do_execsql_test autovacuum2-1.10 { CREATE TABLE t2(x); PRAGMA freelist_count; } {0} # Rig the autovacuum-pages callback to always return zero. No # autovacuum will happen. # proc autovac_page_callback_off {schema filesize freesize pagesize} { return 0 } sqlite3_autovacuum_pages db autovac_page_callback_off do_execsql_test autovacuum2-1.20 { BEGIN; INSERT INTO t1(x) VALUES(zeroblob(10000)); DELETE FROM t1; PRAGMA freelist_count; COMMIT; PRAGMA freelist_count; } {9 9} finish_test |
Added test/avfs.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 | # 2021-03-06 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # # This file implements tests for the appendvfs extension. # # Tests performed: # avfs-1.0. Test that an appendvfs DB can be added to an empty (ZLF) file. # avfs-1.1. Test that the DB can be read with correct content upon reopen. # avfs-1.2. Test that an appendvfs DB can be added to a simple text file. # avfs-1.3. Test that the DB can be read with correct content upon reopen. # avfs-1.4. Test that appended DB is aligned to default page boundary. # avfs-2.1. Test that the simple text file retains its initial text. # avfs-3.1. Test that the appendvfs can grow and shrink, remaining intact. # avfs-3.2. Test that appendvfs is intact after grow/shrink/close/reopen. # avfs-3.3. Test that appendvfs can grow by many pages and be written. # avfs-3.4. Test that grown appendvfs can be reopened and appear intact. # avfs-3.5. Test that much grown appendvfs can shrink and reopen intact. # avfs-4.1. Test shell's ability to append to a non-appendvfs file. # avfs-4.2. Test shell's ability to append to empty or nonexistent file. # avfs-4.3. Test shell's ability to reopen and alter an appendvfs file. # avfs-5.1. Test appendvfs refusal to open too-tiny DB appended onto ZLF. # avfs-5.2. Test appendvfs refusal to open too-tiny DB appended on other. # ... # (more to come) set testdir [file dirname $argv0] source $testdir/tester.tcl set ::testprefix avfs # Do not attempt this test if SQLITE_OMIT_VIRTUALTABLE is defined. # ifcapable !vtab { finish_test return } set CLI [test_find_cli] db close # forcedelete test.db load_static_extension db appendvfs set ::fa avfs.adb set ::fza avfs.sdb forcedelete $::fa $::fza set ::result {} proc shellDoesAr {} { set shdo "sh_app1.sql" forcedelete $shdo set fd [open $shdo w] puts $fd ".help\n.q" close $fd set res [catchcmd "-batch -cmd \".read $shdo\""] return [regexp {^.archive} [lindex $res 1]] } set ::vf "&vfs=apndvfs" # Return file offset of appendvfs portion of a file, or {} if none such. proc fosAvfs {fname} { if {[file size $fname] < 25} { return {} } if {[catch {set fd [open $fname rb]}]} { return {} } seek $fd -25 end set am [read $fd 17] set ao [read $fd 8] close $fd if {$am ne "Start-Of-SQLite3-"} { return {} } binary scan $ao "W" rvo return $rvo } do_test 1.0 { set results {} set out [open $::fza wb] close $out sqlite3 adb "file:$::fza?mode=rwc$::vf" -uri 1 adb eval { PRAGMA page_size=1024; PRAGMA cache_size=10; CREATE TABLE t1(a TEXT); INSERT INTO t1 VALUES ('dog'),('cat'); SELECT group_concat(a) as pets FROM (SELECT a FROM t1 ORDER BY a); } { lappend results $pets } adb close lappend results [fosAvfs $fza] set ::result [join $results " | "] } {cat,dog | 0} do_test 1.1 { set results {} sqlite3 adb "file:$::fza?mode=rw$::vf" -uri 1 adb eval { SELECT group_concat(a) as pets FROM (SELECT a FROM t1 ORDER BY a DESC); } { lappend results $pets } adb close set ::result [join $results " | "] } {dog,cat} do_test 1.2 { set results {} set out [open $::fa wb] set ::tlo { "Just some text," "and more text," "ending at 3 lines." } puts $out [join $::tlo "\n"] close $out set adbSz [file size $::fa] sqlite3 adb "file:$::fa?mode=rwc$::vf" -uri 1 adb eval { PRAGMA auto_vacuum = 0; PRAGMA page_size=512; PRAGMA cache_size=0; CREATE TABLE t1(a TEXT); INSERT INTO t1 VALUES ('dog'),('cat'),('pig'); SELECT group_concat(a) as pets FROM (SELECT a FROM t1 ORDER BY a); } { lappend results $pets } adb close set adaSz [file size $::fa] lappend results "Bytes before/after $adbSz/$adaSz" set ::result [join $results " | "] } {cat,dog,pig | Bytes before/after 50/5145} do_test 1.3 { set results {} sqlite3 adb "file:$::fa?mode=rw$::vf" -uri 1 adb eval { SELECT group_concat(a) as pets FROM (SELECT a FROM t1 ORDER BY a DESC); } { lappend results $pets } adb close set ::result [join $results " | "] } {pig,dog,cat} do_test 1.4 { set ::result [fosAvfs $fa] } {4096} do_test 2.1 { set in [open $::fa r] set tli {} for {set i [llength $::tlo]} {$i > 0} {incr i -1} { lappend tli [gets $in] } close $in if { [join $tli ":"] ne [join $::tlo ":"] } { set ::result "Appendee changed." } else { set ::result "Appendee intact." } } {Appendee intact.} # Set of repeatable random integers for a couple tests. set ::nrint 50000 proc rint {v} { return [::tcl::mathfunc::int [expr $v * 100000]] } array set ::randints [list 0 [rint [::tcl::mathfunc::srand 0]]] for {set i 1} {$i < $::nrint} {incr i} { set ::randints($i) [rint [::tcl::mathfunc::rand]] } do_test 3.1 { set results {} sqlite3 adb "file:$::fa?mode=rw$::vf" -uri 1 adb eval { DROP TABLE t1; PRAGMA cache_size=10; CREATE TABLE ri (i INTEGER); BEGIN; } for {set i 0} {$i < $::nrint} {incr i} { set r $::randints($i) set s $::randints([incr i]) set t $::randints([incr i]) set u $::randints([incr i]) set v $::randints([incr i]) adb eval { INSERT INTO ri VALUES ($r),($s),($t),($u),($v) } } adb eval { COMMIT; SELECT integrity_check as ic FROM pragma_integrity_check(); } { lappend results $ic } set adbSz [file size $::fa] set qr {} adb eval { SELECT count(*) as ic FROM ri; DELETE FROM ri WHERE (i % 50) <> 25; SELECT integrity_check as ic FROM pragma_integrity_check(); VACUUM; SELECT integrity_check as ic FROM pragma_integrity_check(); SELECT count(*) as ic FROM ri; } { lappend qr $ic } adb close set adaSz [file size $::fa] set adba [expr ($adbSz + 0.1)/$adaSz] # lappend results $adba set results [concat $results [lrange $qr 0 2]] lappend results [expr {$adba > 10.0}] set ::result [join $results " | "] } "ok | $::nrint | ok | ok | 1" do_test 3.2 { set results {} sqlite3 adb "file:$::fa?mode=rw$::vf" -uri 1 adb eval { SELECT integrity_check as ic FROM pragma_integrity_check(); } { lappend results $ic } adb close set ::result [join $results " | "] } {ok} # avfs-3.3. Test that appendvfs can grow by many pages and be written. do_test 3.3 { set results {} sqlite3 adb "file:$::fa?mode=rw$::vf" -uri 1 set npages 300 adb eval { BEGIN } while {$npages > 0} { adb eval { INSERT INTO ri VALUES (randomblob(1500)) } incr npages -1 } adb eval { COMMIT } adb eval { SELECT integrity_check as ic FROM pragma_integrity_check(); } { lappend results $ic } adb close set adaSzr [expr [file size $::fa] / 300.0 / 1500 ] set okSzr [expr $adaSzr > 1.0 && $adaSzr < 1.3 ] lappend results $okSzr set ::result [join $results " | "] } {ok | 1} # avfs-3.4. Test that grown appendvfs can be reopened and appear intact. do_test 3.4 { set results {} sqlite3 adb "file:$::fa?mode=rw$::vf" -uri 1 adb eval { SELECT integrity_check as ic FROM pragma_integrity_check(); } { lappend results $ic } adb close set ::result $ic } {ok} # avfs-3.5. Test that much grown appendvfs can shrink and reopen intact. do_test 3.5 { set results {} set adbsz [file size $::fa] sqlite3 adb "file:$::fa?mode=rw$::vf" -uri 1 adb eval { DELETE FROM ri WHERE rowid % 8 <> 0; SELECT integrity_check as ic FROM pragma_integrity_check(); VACUUM; SELECT integrity_check as ic FROM pragma_integrity_check(); } { lappend results $ic } adb close set adasz [file size $::fa] lappend results [expr {$adbsz/$adasz > 5}] sqlite3 adb "file:$::fa?mode=rw$::vf" -uri 1 adb eval { SELECT integrity_check as ic FROM pragma_integrity_check(); } { lappend results $ic } adb close set ::result [join $results " | "] } {ok | ok | 1 | ok} set ::cliDoesAr [shellDoesAr] do_test 4.1 { set shdo "sh_app1.sql" set shod "sh_app1.adb" forcedelete $shdo $shod set ofd [open $shdo w] if {$::cliDoesAr} { puts $ofd ".ar -c" } else { puts $ofd "pragma page_size=512;" puts $ofd "create table sqlar (a);" } puts $ofd ".tables" puts $ofd ".q" close $ofd set ofd [open $shod wb] puts $ofd "Some text." close $ofd set res [catchcmd "-append -batch -init $shdo $shod" ""] lappend res [fosAvfs $shod] forcedelete $shdo $shod set ::result [join $res " | "] } {0 | sqlar | 4096} do_test 4.2 { set shdo "sh_app1.sql" set shod "sh_app1.adb" forcedelete $shdo $shod set ofd [open $shdo w] if {$::cliDoesAr} { puts $ofd ".ar -c" } else { puts $ofd "pragma page_size=512;" puts $ofd "create table sqlar (a);" } puts $ofd ".tables" puts $ofd ".q" close $ofd set ofd [open $shod wb] close $ofd set res [catchcmd "-append -batch -init $shdo $shod" ""] lappend res [fosAvfs $shod] forcedelete $shdo ; # Leave $shod for next test. set ::result [join $res " | "] } {0 | sqlar | 0} do_test 4.3 { set shdo "sh_app1.sql" set shod "sh_app1.adb" ; # Same as test 4.2, reusing ADB. forcedelete $shdo set ofd [open $shdo w] if {$::cliDoesAr} { puts $ofd ".ar -u $shdo" puts $ofd "select count(*) from sqlar where name = '$shdo';" } else { puts $ofd "insert into sqlar values (1);" puts $ofd "select count(*) from sqlar;" } puts $ofd ".q" close $ofd set res [catchcmd "-append -batch -init $shdo $shod" ""] sqlite3 adb "file:$shod?mode=rw$::vf" -uri 1 adb eval { SELECT count(*) as n FROM sqlar } { lappend res $n } adb close forcedelete $shdo $shod; set ::result [join $res " | "] } {0 | 1 | 1} do_test 5.1 { set fake "faketiny.sdb" forcedelete $fake set ofd [open $fake wb] puts -nonewline $ofd "SQLite format 3" puts -nonewline $ofd [binary format "c" 0] puts -nonewline $ofd "Start-Of-SQLite3-" puts -nonewline $ofd [binary format "W" 0] close $ofd if {[catch {sqlite3 adb "file:$fake?mode=rw$::vf" -uri 1}]} { set res "Open failed." } else { adb close set res "Opened when should not." } forcedelete $fake set ::result $res } {Open failed.} do_test 5.2 { set fake "faketiny.sdb" forcedelete $fake set ofd [open $fake wb] set fakeAppendee "Dog ate my homework.\n" puts -nonewline $ofd $fakeAppendee puts -nonewline $ofd "SQLite format 3" puts -nonewline $ofd [binary format "c" 0] puts -nonewline $ofd "Start-Of-SQLite3-" puts -nonewline $ofd [binary format "W" [string length $fakeAppendee]] close $ofd if {[catch {sqlite3 adb "file:$fake?mode=rw$::vf" -uri 1}]} { set res "Open failed." } else { adb close set res "Opened when should not." } forcedelete $fake set ::result $res } {Open failed.} forcedelete $::fa $::fza unset -nocomplain ::fa ::fza ::tlo ::result ::randints ::nrint ::cliDoesAr finish_test |
Changes to test/backup2.test.
︙ | ︙ | |||
140 141 142 143 144 145 146 | } {1 {wrong # args: should be "db backup ?DATABASE? FILENAME"}} # Try to restore from an unreadable file. # if {$tcl_platform(platform)=="windows"} { set msg {cannot open source database: unable to open database file} } elseif {[string match *BSD $tcl_platform(os)]} { | | > | | 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 | } {1 {wrong # args: should be "db backup ?DATABASE? FILENAME"}} # Try to restore from an unreadable file. # if {$tcl_platform(platform)=="windows"} { set msg {cannot open source database: unable to open database file} } elseif {[string match *BSD $tcl_platform(os)]} { set msg {} } else { set msg {cannot open source database: disk I/O error} } do_test backup2-10 { forcedelete bu3.db file mkdir bu3.db set rc [catch {db restore temp bu3.db} res] if {[string match *BSD $tcl_platform(os)]} { set res "" } list $rc $res } [list 1 $msg] # Try to restore from something that is not a database file. # do_test backup2-11 { set rc [catch {db restore temp bu2.db} res] lappend rc $res |
︙ | ︙ |
Changes to test/badutf2.test.
︙ | ︙ | |||
94 95 96 97 98 99 100 | do_test badutf2-3.1.$i { set sql "SELECT hex('$hstr') AS x;" set res [ sqlite3_exec db $sql ] lindex [ lindex $res 1] 1 } $uval } | > > > > > | | | | | | > | 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 | do_test badutf2-3.1.$i { set sql "SELECT hex('$hstr') AS x;" set res [ sqlite3_exec db $sql ] lindex [ lindex $res 1] 1 } $uval } # Tcl 8.7 and later do automatic bad-utf8 correction for # characters 0x80 thru 0x9f so test case 5 does not work here. if {$i==5 && $tcl_version>=8.7} { # no-op } else { do_test badutf2-4.1.$i { sqlite3_reset $S sqlite3_bind_text $S 1 $xstr $len sqlite3_step $S utf8_to_ustr2 [ sqlite3_column_text $S 0 ] } $ustr } ifcapable debug { do_test badutf2-5.1.$i { utf8_to_utf8 $uval } $u2u } |
︙ | ︙ |
Changes to test/bestindex1.test.
︙ | ︙ | |||
47 48 49 50 51 52 53 | do_execsql_test 1.0 { CREATE VIRTUAL TABLE x1 USING tcl(vtab_command); } {} do_eqp_test 1.1 { SELECT * FROM x1 WHERE a = 'abc' | | | | 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | do_execsql_test 1.0 { CREATE VIRTUAL TABLE x1 USING tcl(vtab_command); } {} do_eqp_test 1.1 { SELECT * FROM x1 WHERE a = 'abc' } {SCAN x1 VIRTUAL TABLE INDEX 555:eq!} do_eqp_test 1.2 { SELECT * FROM x1 WHERE a IN ('abc', 'def'); } {SCAN x1 VIRTUAL TABLE INDEX 555:eq!} #------------------------------------------------------------------------- # reset_db register_tcl_module db # Parameter $mode may be one of: |
︙ | ︙ | |||
137 138 139 140 141 142 143 | do_execsql_test 2.2.$mode.5 { SELECT rowid FROM t1 WHERE a IN ('one', 'four') ORDER BY +rowid } {1 4} set plan(use) { QUERY PLAN | | | | | 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 | do_execsql_test 2.2.$mode.5 { SELECT rowid FROM t1 WHERE a IN ('one', 'four') ORDER BY +rowid } {1 4} set plan(use) { QUERY PLAN |--SCAN t1 VIRTUAL TABLE INDEX 0:SELECT * FROM t1x WHERE a='%1%' `--USE TEMP B-TREE FOR ORDER BY } set plan(omit) { QUERY PLAN |--SCAN t1 VIRTUAL TABLE INDEX 0:SELECT * FROM t1x WHERE a='%1%' `--USE TEMP B-TREE FOR ORDER BY } set plan(use2) { QUERY PLAN |--SCAN t1 VIRTUAL TABLE INDEX 0:SELECT * FROM t1x `--USE TEMP B-TREE FOR ORDER BY } do_eqp_test 2.2.$mode.6 { SELECT rowid FROM t1 WHERE a IN ('one', 'four') ORDER BY +rowid } [string map {"\n " "\n"} $plan($mode)] } |
︙ | ︙ | |||
262 263 264 265 266 267 268 | } { 1 0 ValueA 1 0 ValueA 2 0 ValueA 2 0 ValueA 3 0 ValueB 3 0 ValueB 4 0 ValueB 4 0 ValueB } | > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | } { 1 0 ValueA 1 0 ValueA 2 0 ValueA 2 0 ValueA 3 0 ValueB 3 0 ValueB 4 0 ValueB 4 0 ValueB } #------------------------------------------------------------------------- # If there is an IN(..) condition in the WHERE clause of a query on a # virtual table, the xBestIndex method is first invoked with the IN(...) # represented by a "usable" SQLITE_INDEX_CONSTRAINT_EQ constraint. If # the virtual table elects to use the IN(...) constraint, then the # xBestIndex method is invoked again, this time with the IN(...) marked # as "not usable". Depending on the relative costs of the two plans as # defined by the virtual table implementation, and the cardinality of the # IN(...) operator, SQLite chooses the most efficient plan. # # At one point the second invocation of xBestIndex() was only being made # for join queries. The following tests check that this problem has been # fixed. # proc vtab_command {method args} { switch -- $method { xConnect { return "CREATE TABLE t1(a, b, c, d)" } xBestIndex { set clist [lindex $args 0] lappend ::bestindex_calls $clist set ret "cost 1000000 idxnum 555" for {set i 0} {$i < [llength $clist]} {incr i} { array set C [lindex $clist $i] if {$C(usable)} { lappend ret use $i } } return $ret } } return {} } do_execsql_test 4.0 { CREATE VIRTUAL TABLE x1 USING tcl(vtab_command); } {} do_test 4.1 { set ::bestindex_calls [list] execsql { SELECT * FROM x1 WHERE a=? AND b BETWEEN ? AND ? AND c IN (1, 2, 3, 4); } set ::bestindex_calls } [list \ [list {op eq column 0 usable 1} \ {op eq column 2 usable 1} \ {op ge column 1 usable 1} \ {op le column 1 usable 1} \ ] \ [list {op eq column 0 usable 1} \ {op eq column 2 usable 0} \ {op ge column 1 usable 1} \ {op le column 1 usable 1} ] ] do_catchsql_test 5.0 { SELECT * FROM tcl('abc'); } {1 {wrong number of arguments}} finish_test |
Changes to test/bestindex2.test.
︙ | ︙ | |||
85 86 87 88 89 90 91 | CREATE VIRTUAL TABLE t1 USING tcl("vtab_cmd t1 {a b}"); CREATE VIRTUAL TABLE t2 USING tcl("vtab_cmd t2 {c d}"); CREATE VIRTUAL TABLE t3 USING tcl("vtab_cmd t3 {e f}"); } do_eqp_test 1.1 { SELECT * FROM t1 WHERE a='abc' | | | | | | | | | | | | | | | | | 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 | CREATE VIRTUAL TABLE t1 USING tcl("vtab_cmd t1 {a b}"); CREATE VIRTUAL TABLE t2 USING tcl("vtab_cmd t2 {c d}"); CREATE VIRTUAL TABLE t3 USING tcl("vtab_cmd t3 {e f}"); } do_eqp_test 1.1 { SELECT * FROM t1 WHERE a='abc' } {SCAN t1 VIRTUAL TABLE INDEX 0:indexed(a=?)} do_eqp_test 1.2 { SELECT * FROM t1 WHERE a='abc' AND b='def' } {SCAN t1 VIRTUAL TABLE INDEX 0:indexed(a=? AND b=?)} do_eqp_test 1.3 { SELECT * FROM t1 WHERE a='abc' AND a='def' } {SCAN t1 VIRTUAL TABLE INDEX 0:indexed(a=?)} do_eqp_test 1.4 { SELECT * FROM t1,t2 WHERE c=a } { QUERY PLAN |--SCAN t1 VIRTUAL TABLE INDEX 0: `--SCAN t2 VIRTUAL TABLE INDEX 0:indexed(c=?) } do_eqp_test 1.5 { SELECT * FROM t1, t2 CROSS JOIN t3 WHERE t2.c = +t1.b AND t3.e=t2.d } { QUERY PLAN |--SCAN t1 VIRTUAL TABLE INDEX 0: |--SCAN t2 VIRTUAL TABLE INDEX 0:indexed(c=?) `--SCAN t3 VIRTUAL TABLE INDEX 0:indexed(e=?) } do_eqp_test 1.6 { SELECT * FROM t1, t2, t3 WHERE t2.c = +t1.b AND t3.e = t2.d } { QUERY PLAN |--SCAN t1 VIRTUAL TABLE INDEX 0: |--SCAN t2 VIRTUAL TABLE INDEX 0:indexed(c=?) `--SCAN t3 VIRTUAL TABLE INDEX 0:indexed(e=?) } do_execsql_test 1.7.1 { CREATE TABLE x1(a, b); } do_eqp_test 1.7.2 { SELECT * FROM x1 CROSS JOIN t1, t2, t3 WHERE t1.a = t2.c AND t1.b = t3.e } { QUERY PLAN |--SCAN x1 |--SCAN t1 VIRTUAL TABLE INDEX 0: |--SCAN t2 VIRTUAL TABLE INDEX 0:indexed(c=?) `--SCAN t3 VIRTUAL TABLE INDEX 0:indexed(e=?) } finish_test |
Changes to test/bestindex3.test.
︙ | ︙ | |||
75 76 77 78 79 80 81 | do_execsql_test 1.0 { CREATE VIRTUAL TABLE t1 USING tcl("vtab_cmd 0"); } do_eqp_test 1.1 { SELECT * FROM t1 WHERE a LIKE 'abc'; | | | > | > | > | > | | 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 | do_execsql_test 1.0 { CREATE VIRTUAL TABLE t1 USING tcl("vtab_cmd 0"); } do_eqp_test 1.1 { SELECT * FROM t1 WHERE a LIKE 'abc'; } {SCAN t1 VIRTUAL TABLE INDEX 0:a LIKE ?} do_eqp_test 1.2 { SELECT * FROM t1 WHERE a = 'abc'; } {SCAN t1 VIRTUAL TABLE INDEX 0:a EQ ?} do_eqp_test 1.3 { SELECT * FROM t1 WHERE a = 'abc' OR b = 'def'; } { QUERY PLAN `--MULTI-INDEX OR |--INDEX 1 | `--SCAN t1 VIRTUAL TABLE INDEX 0:a EQ ? `--INDEX 2 `--SCAN t1 VIRTUAL TABLE INDEX 0:b EQ ? } do_eqp_test 1.4 { SELECT * FROM t1 WHERE a LIKE 'abc%' OR b = 'def'; } { QUERY PLAN `--MULTI-INDEX OR |--INDEX 1 | `--SCAN t1 VIRTUAL TABLE INDEX 0:a LIKE ? `--INDEX 2 `--SCAN t1 VIRTUAL TABLE INDEX 0:b EQ ? } do_execsql_test 1.5 { CREATE TABLE ttt(a, b, c); INSERT INTO ttt VALUES(1, 'two', 'three'); INSERT INTO ttt VALUES(2, 'one', 'two'); |
︙ | ︙ | |||
146 147 148 149 150 151 152 | } do_eqp_test 2.2 { SELECT * FROM t2 WHERE x LIKE 'abc%' OR y = 'def' } [string map {"\n " \n} { QUERY PLAN `--MULTI-INDEX OR | > | > | | 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 | } do_eqp_test 2.2 { SELECT * FROM t2 WHERE x LIKE 'abc%' OR y = 'def' } [string map {"\n " \n} { QUERY PLAN `--MULTI-INDEX OR |--INDEX 1 | `--SEARCH t2 USING INDEX t2x (x>? AND x<?) `--INDEX 2 `--SEARCH t2 USING INDEX t2y (y=?) }] } #------------------------------------------------------------------------- # Test that any PRIMARY KEY within a sqlite3_decl_vtab() CREATE TABLE # statement is currently ignored. # |
︙ | ︙ |
Changes to test/bestindex4.test.
︙ | ︙ | |||
155 156 157 158 159 160 161 | CREATE TABLE t1 (x INT PRIMARY KEY); } {} do_eqp_test 2.1 { SELECT * FROM t1, x1 WHERE x1.d=t1.x; } { QUERY PLAN | | | | | | 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 | CREATE TABLE t1 (x INT PRIMARY KEY); } {} do_eqp_test 2.1 { SELECT * FROM t1, x1 WHERE x1.d=t1.x; } { QUERY PLAN |--SCAN x1 VIRTUAL TABLE INDEX 0: `--SEARCH t1 USING COVERING INDEX sqlite_autoindex_t1_1 (x=?) } do_eqp_test 2.2 { SELECT * FROM t1, x1(t1.x) } { QUERY PLAN |--SCAN t1 `--SCAN x1 VIRTUAL TABLE INDEX 555: } finish_test |
Added test/bestindex7.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 | # 2020-01-29 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix bestindex7 ifcapable !vtab { finish_test return } register_tcl_module db proc vtab_command {src method args} { switch -- $method { xConnect { return "CREATE TABLE xxx(a)" } xBestIndex { set clist [lindex $args 0] set iCons 0 set ret [list] foreach cons $clist { catch { array unset C } array set C $cons if {$C(usable)} { lappend ret use $iCons } incr iCons } return $ret } xFilter { return [list sql "SELECT rowid, x FROM $src"] } } return {} } do_execsql_test 1.0 { CREATE TABLE t1(x); INSERT INTO t1 VALUES(0), (2); CREATE VIRTUAL TABLE vt1 USING tcl(vtab_command t1); } do_execsql_test 1.1 { select * from vt1 } {0 2} do_execsql_test 1.2 { select * from vt1 WHERE a=0 } {0} do_execsql_test 1.3 { select * from vt1 WHERE a=1 } {} do_execsql_test 1.4 { select * from vt1 WHERE a=1 OR a=0} {0} do_execsql_test 1.5 { UPDATE t1 SET x=NULL WHERE x=2; } do_execsql_test 1.6 { select * from vt1 } {0 {}} do_execsql_test 1.7 { select * from vt1 WHERE a=0 } {0} do_execsql_test 1.8 { select * from vt1 WHERE a=1 } {} do_execsql_test 1.9 { select * from vt1 WHERE a=1 OR a=0} {0} do_execsql_test 1.10 { select * from vt1 WHERE a IN (2) } {} do_execsql_test 1.10 { select * from vt1 WHERE a IN (0,1,2,3) } {0} do_execsql_test 1.11 { select * from vt1 WHERE a IN (0, NULL) } {0} do_execsql_test 1.12 { select * from vt1 WHERE a IN (NULL) } {} finish_test |
Changes to test/between.test.
︙ | ︙ | |||
54 55 56 57 58 59 60 | set ::sqlite_sort_count 0 set data [execsql $sql] if {$::sqlite_sort_count} {set x sort} {set x nosort} lappend data $x set eqp [execsql "EXPLAIN QUERY PLAN $sql"] # puts eqp=$eqp foreach {a b c x} $eqp { | | | | | 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | set ::sqlite_sort_count 0 set data [execsql $sql] if {$::sqlite_sort_count} {set x sort} {set x nosort} lappend data $x set eqp [execsql "EXPLAIN QUERY PLAN $sql"] # puts eqp=$eqp foreach {a b c x} $eqp { if {[regexp {(SCAN|SEARCH) (\w+ AS )?(\w+) USING.* INDEX (\w+)\y} \ $x all ss as tab idx]} { lappend data $tab $idx } elseif {[regexp {(SCAN|SEARCH) (\w+ AS )?(\w+)\y} $x all ss as tab]} { lappend data $tab * } } return $data } do_test between-1.1.1 { |
︙ | ︙ | |||
115 116 117 118 119 120 121 | } {4 2 25 27 sort t1 i1zyx} do_test between-1.5.3 { queryplan { SELECT * FROM t1 WHERE 26 BETWEEN y AND +z ORDER BY +w } } {4 2 25 27 sort t1 *} | > > > > > | > > > > > > > > > > > > > > > | 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 | } {4 2 25 27 sort t1 i1zyx} do_test between-1.5.3 { queryplan { SELECT * FROM t1 WHERE 26 BETWEEN y AND +z ORDER BY +w } } {4 2 25 27 sort t1 *} #------------------------------------------------------------------------- reset_db do_execsql_test between-2.0 { CREATE TABLE t1(x TEXT, y TEXT COLLATE nocase); INSERT INTO t1 VALUES('0', 'abc'); } foreach {tn expr res} { 1 "x BETWEEN 1 AND '5'" 0 2 "x COLLATE binary BETWEEN 1 AND '5'" 0 3 "x COLLATE nocase BETWEEN 1 AND '5'" 0 4 "y BETWEEN 'A' AND 'B'" 1 5 "y COLLATE nocase BETWEEN 'A' AND 'B'" 1 6 "y COLLATE binary BETWEEN 'A' AND 'B'" 0 7 "(y COLLATE binary) BETWEEN 'A' AND 'B'" 0 } { set sql "SELECT $expr FROM t1" do_execsql_test between-2.1.$tn $sql $res } finish_test |
Changes to test/bigmmap.test.
︙ | ︙ | |||
90 91 92 93 94 95 96 | do_eqp_test 2.$i.$t.3 " SELECT * FROM t$t AS o WHERE NOT EXISTS( SELECT * FROM t$t AS i WHERE a=o.a AND +b=o.b AND +c=o.c ) ORDER BY b, c; " [string map {"\n " "\n"} " QUERY PLAN | | | | | 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 | do_eqp_test 2.$i.$t.3 " SELECT * FROM t$t AS o WHERE NOT EXISTS( SELECT * FROM t$t AS i WHERE a=o.a AND +b=o.b AND +c=o.c ) ORDER BY b, c; " [string map {"\n " "\n"} " QUERY PLAN |--SCAN o USING COVERING INDEX sqlite_autoindex_t${t}_1 `--CORRELATED SCALAR SUBQUERY xxxxxx `--SEARCH i USING INTEGER PRIMARY KEY (rowid=?) "] } } finish_test |
Changes to test/btree02.test.
︙ | ︙ | |||
17 18 19 20 21 22 23 | set testdir [file dirname $argv0] source $testdir/tester.tcl load_static_extension db eval do_execsql_test btree02-100 { CREATE TABLE t1(a TEXT, ax INTEGER, b INT, PRIMARY KEY(a,ax)) WITHOUT ROWID; WITH RECURSIVE c(i) AS (VALUES(1) UNION ALL SELECT i+1 FROM c WHERE i<10) | | > > > > > > > | < | > > | | 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 | set testdir [file dirname $argv0] source $testdir/tester.tcl load_static_extension db eval do_execsql_test btree02-100 { CREATE TABLE t1(a TEXT, ax INTEGER, b INT, PRIMARY KEY(a,ax)) WITHOUT ROWID; WITH RECURSIVE c(i) AS (VALUES(1) UNION ALL SELECT i+1 FROM c WHERE i<10) INSERT INTO t1(a,ax,b) SELECT printf('%02x',i+160), random(), i FROM c; CREATE INDEX t1a ON t1(a); CREATE TABLE t2(x,y); CREATE TABLE t3(cnt); WITH RECURSIVE c(i) AS (VALUES(1) UNION ALL SELECT i+1 FROM c WHERE i<4) INSERT INTO t3(cnt) SELECT i FROM c; SELECT count(*) FROM t1; } {10} proc showt1 {} { puts -nonewline "t1: " puts [db eval {SELECT printf('(%s,%s)',quote(a),quote(b)) FROM t1}] } do_test btree02-110 { db eval BEGIN set i 0 # showt1 db eval {SELECT a, ax, b, cnt FROM t1 CROSS JOIN t3 WHERE b IS NOT NULL} { if {$a==""} continue db eval {INSERT INTO t2(x,y) VALUES($b,$cnt)} # puts "a,b,cnt = ($a,$b,$cnt)" incr i if {$i%2==1} { set bx [expr {$b+1000}] # puts "INSERT ($a),$bx" db eval {INSERT INTO t1(a,ax,b) VALUES(printf('(%s)',$a),random(),$bx)} # showt1 } else { # puts "DELETE a=$a" db eval {DELETE FROM t1 WHERE a=$a} # showt1 } db eval {COMMIT; BEGIN} } db one {COMMIT; SELECT count(*) FROM t1;} } {10} finish_test |
Added test/busy2.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 | # 2020 June 30 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # This file test the busy handler # set testdir [file dirname $argv0] source $testdir/tester.tcl source $testdir/lock_common.tcl set testprefix busy2 do_multiclient_test tn { do_test 1.$tn.0 { sql2 { CREATE TABLE t1(a, b); PRAGMA journal_mode = wal; INSERT INTO t1 VALUES('A', 'B'); } } {wal} do_test 1.$tn.1 { code1 { db timeout 1000 } sql1 { SELECT * FROM t1 } } {A B} do_test 1.$tn.2 { sql2 { BEGIN; INSERT INTO t1 VALUES('C', 'D'); } } {} do_test 1.$tn.3 { set us [lindex [time { catch { sql1 { BEGIN EXCLUSIVE } } }] 0] expr {$us>950000 && $us<1500000} } {1} do_test 1.$tn.4 { sql2 { COMMIT } } {} } #------------------------------------------------------------------------- do_multiclient_test tn { # Make the db a WAL mode db. And add a table and a row to it. Then open # a second connection within process 1. Process 1 now has connections # [db] and [db1.2], process 2 has connection [db2] only. # # Configure all connections to use a 1000 ms timeout. # do_test 2.$tn.0 { code1 { sqlite3 db1.2 test.db } sql1 { PRAGMA auto_vacuum = off; PRAGMA journal_mode = wal; CREATE TABLE t1(a, b); INSERT INTO t1 VALUES(1, 2); } code2 { db2 timeout 1000 } code1 { db1.2 timeout 1000 db timeout 1000 db1.2 eval {SELECT * FROM t1} } } {1 2} # Take a read lock with [db] in process 1. # do_test 2.$tn.1 { sql1 { BEGIN; SELECT * FROM t1; } } {1 2} # Insert a row using [db2] in process 2. Then try a passive checkpoint. # It fails to checkpoint the final frame (due to the readlock taken by # [db]), and returns in less than 250ms. do_test 2.$tn.2 { sql2 { INSERT INTO t1 VALUES(3, 4) } set us [lindex [time { set res [code2 { db2 eval { PRAGMA wal_checkpoint } }] }] 0] list [expr $us < 250000] $res } {1 {0 4 3}} # Now try a FULL checkpoint with [db2]. It returns SQLITE_BUSY. And takes # over 950ms to do so. do_test 2.$tn.3 { set us [lindex [time { set res [code2 { db2 eval { PRAGMA wal_checkpoint = FULL } }] }] 0] list [expr $us > 950000] $res } {1 {1 4 3}} # Passive checkpoint with [db1.2] (process 1). No SQLITE_BUSY, returns # in under 250ms. do_test 2.$tn.4 { set us [lindex [time { set res [code1 { db1.2 eval { PRAGMA wal_checkpoint } }] }] 0] list [expr $us < 250000] $res } {1 {0 4 3}} # Full checkpoint with [db1.2] (process 1). SQLITE_BUSY returned in # a bit over 950ms. do_test 2.$tn.5 { set us [lindex [time { set res [code1 { db1.2 eval { PRAGMA wal_checkpoint = FULL } }] }] 0] list [expr $us > 950000] $res } {1 {1 4 3}} code1 { db1.2 close } } #------------------------------------------------------------------------- # Check that even if the busy-handler fails (returns zero) within a # call to sqlite3_prepare() (or _v2(), or _v3()), it is still invoked # the next time an SQLITE_BUSY is encountered. # do_multiclient_test tn { code1 { set ::busy_called 0 proc busy {args} { if {$::busy_called} { return 1 } set ::busy_called 1 return 0 } db busy busy } do_test 3.$tn.1 { sql2 { CREATE TABLE t1(x); BEGIN EXCLUSIVE; INSERT INTO t1 VALUES('x'); } } {} do_test 3.$tn.2 { set ::busy_called 0 list [catch { sql1 { SELECT * FROM t1 } } msg] $::busy_called } {1 1} do_test 3.$tn.3 { set ::busy_called 0 list [catch { sql1 { SELECT * FROM t1 } } msg] $::busy_called } {1 1} } finish_test |
Changes to test/capi2.test.
︙ | ︙ | |||
60 61 62 63 64 65 66 | sqlite3_data_count $VM } {2} do_test capi2-1.4 { get_row_values $VM } {t1 1} do_test capi2-1.5 { get_column_names $VM | | | | | 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 | sqlite3_data_count $VM } {2} do_test capi2-1.4 { get_row_values $VM } {t1 1} do_test capi2-1.5 { get_column_names $VM } {name rowid TEXT INTEGER} do_test capi2-1.6 { sqlite3_step $VM } {SQLITE_DONE} do_test capi2-1.7 { list [sqlite3_column_count $VM] [get_row_values $VM] [get_column_names $VM] } {2 {} {name rowid TEXT INTEGER}} # This used to be SQLITE_MISUSE. But now we automatically reset prepared # statements. ifcapable autoreset { do_test capi2-1.8 { sqlite3_step $VM } {SQLITE_ROW} } else { do_test capi2-1.8 { sqlite3_step $VM } {SQLITE_MISUSE} } # Update: In v2, once SQLITE_MISUSE is returned the statement handle cannot # be interrogated for more information. However in v3, since the column # count, names and types are determined at compile time, these are still # accessible after an SQLITE_MISUSE error. do_test capi2-1.9 { sqlite3_reset $VM list [sqlite3_column_count $VM] [get_row_values $VM] [get_column_names $VM] } {2 {} {name rowid TEXT INTEGER}} do_test capi2-1.10 { sqlite3_data_count $VM } {0} do_test capi2-1.11 { sqlite3_finalize $VM } {SQLITE_OK} |
︙ | ︙ | |||
116 117 118 119 120 121 122 | -- A comment at the end } do_test capi2-2.2 { set r [sqlite3_step $VM] lappend r [sqlite3_column_count $VM] \ [get_row_values $VM] \ [get_column_names $VM] | | | | | 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 | -- A comment at the end } do_test capi2-2.2 { set r [sqlite3_step $VM] lappend r [sqlite3_column_count $VM] \ [get_row_values $VM] \ [get_column_names $VM] } {SQLITE_ROW 2 {t1 1} {name rowid TEXT INTEGER}} do_test capi2-2.3 { set r [sqlite3_step $VM] lappend r [sqlite3_column_count $VM] \ [get_row_values $VM] \ [get_column_names $VM] } {SQLITE_DONE 2 {} {name rowid TEXT INTEGER}} do_test capi2-2.4 { sqlite3_finalize $VM } {SQLITE_OK} do_test capi2-2.5 { set VM [sqlite3_prepare $DB $SQL -1 SQL] set SQL } { -- A comment at the end } do_test capi2-2.6 { set r [sqlite3_step $VM] lappend r [sqlite3_column_count $VM] \ [get_row_values $VM] \ [get_column_names $VM] } {SQLITE_DONE 2 {} {name rowid TEXT INTEGER}} do_test capi2-2.7 { sqlite3_finalize $VM } {SQLITE_OK} do_test capi2-2.8 { set VM [sqlite3_prepare $DB $SQL -1 SQL] list $SQL $VM } {{} {}} |
︙ | ︙ |
Changes to test/capi3d.test.
︙ | ︙ | |||
111 112 113 114 115 116 117 | ifcapable wal { test_is_readonly capi3d-2.6 {PRAGMA journal_mode=WAL} 0 test_is_readonly capi3d-2.7 {PRAGMA wal_checkpoint} 0 } test_is_readonly capi3d-2.8 {PRAGMA application_id=1234} 0 test_is_readonly capi3d-2.9 {VACUUM} 0 test_is_readonly capi3d-2.10 {PRAGMA integrity_check} 1 | | > > > > > > > > > > > > > > > > > > > > | 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 | ifcapable wal { test_is_readonly capi3d-2.6 {PRAGMA journal_mode=WAL} 0 test_is_readonly capi3d-2.7 {PRAGMA wal_checkpoint} 0 } test_is_readonly capi3d-2.8 {PRAGMA application_id=1234} 0 test_is_readonly capi3d-2.9 {VACUUM} 0 test_is_readonly capi3d-2.10 {PRAGMA integrity_check} 1 do_test capi3-2.49 { sqlite3_stmt_readonly 0 } 1 # Tests for the is-explain interface. # proc test_is_explain {testname sql truth} { do_test $testname [format { set DB [sqlite3_connection_pointer db] set STMT [sqlite3_prepare $DB {%s} -1 TAIL] set rc [sqlite3_stmt_isexplain $STMT] sqlite3_finalize $STMT set rc } $sql] $truth } test_is_explain capi3d-2.51 {SELECT * FROM sqlite_master} 0 test_is_explain capi3d-2.52 { explain SELECT * FROM sqlite_master} 1 test_is_explain capi3d-2.53 { Explain Query Plan select * FROM sqlite_master} 2 do_test capi3-2.99 { sqlite3_stmt_isexplain 0 } 0 # Tests for sqlite3_stmt_busy # do_test capi3d-3.1 { db eval {INSERT INTO t1 VALUES(6); INSERT INTO t1 VALUES(7);} set STMT [sqlite3_prepare db {SELECT * FROM t1} -1 TAIL] sqlite3_stmt_busy $STMT } {0} |
︙ | ︙ |
Added test/carray01.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 | # 2020-11-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 file implements tests for CARRAY extension # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix carray01 ifcapable !vtab { finish_test return } load_static_extension db carray # Parameter $stmt must be a prepared statement created using # the sqlite3_prepare_v2 command and with parameters fullly bound. # This routine simply runs the statement, gathers the result, and # returns a list containing the result. # # If the optional second argument is true, then the stmt is finalized # after it is run. # proc run_stmt {stmt {finalizeFlag 0}} { set r {} while {[sqlite3_step $stmt]=="SQLITE_ROW"} { for {set i 0} {$i<[sqlite3_data_count $stmt]} {incr i} { lappend r [sqlite3_column_text $stmt $i] } } if {$finalizeFlag} { sqlite3_finalize $stmt } else { sqlite3_reset $stmt } return $r } do_test 100 { set STMT [sqlite3_prepare_v2 db {SELECT 5 IN carray(?3)} -1] sqlite3_carray_bind $STMT 3 1 2 3 4 5 6 7 run_stmt $STMT 0 } {1} do_test 101 { sqlite3_carray_bind -static $STMT 3 1 2 3 4 5 6 7 run_stmt $STMT 0 } {1} do_test 110 { sqlite3_carray_bind $STMT 3 1 2 3 4 6 7 run_stmt $STMT 0 } {0} do_test 120 { sqlite3_carray_bind -int64 $STMT 3 1 2 3 4 5 6 7 run_stmt $STMT 0 } {1} do_test 121 { sqlite3_carray_bind -int64 -transient $STMT 3 1 2 3 4 5 6 7 run_stmt $STMT 0 } {1} do_test 122 { sqlite3_carray_bind -int64 -static $STMT 3 1 2 3 4 5 6 7 run_stmt $STMT 0 } {1} do_test 123 { sqlite3_carray_bind -int32 -transient $STMT 3 1 2 3 4 5 6 7 run_stmt $STMT 0 } {1} do_test 124 { sqlite3_carray_bind -int32 -static $STMT 3 1 2 3 4 5 6 7 run_stmt $STMT 0 } {1} do_test 125 { sqlite3_carray_bind -int32 $STMT 3 1 2 3 4 5 6 7 run_stmt $STMT 0 } {1} do_test 130 { sqlite3_carray_bind -int64 $STMT 3 1 2 3 4 6 7 run_stmt $STMT 0 } {0} do_test 131 { sqlite3_carray_bind -int64 -transient $STMT 3 1 2 3 4 6 7 run_stmt $STMT 0 } {0} do_test 131 { sqlite3_carray_bind -int64 -static $STMT 3 1 2 3 4 6 7 run_stmt $STMT 0 } {0} do_test 140 { sqlite3_carray_bind -double $STMT 3 1 2 3 4 5 6 7 run_stmt $STMT 0 } {1} do_test 141 { sqlite3_carray_bind -double -transient $STMT 3 1 2 3 4 5 6 7 run_stmt $STMT 0 } {1} do_test 142 { sqlite3_carray_bind -double -static $STMT 3 1 2 3 4 5 6 7 run_stmt $STMT 0 } {1} do_test 150 { sqlite3_carray_bind -double $STMT 3 1 2 3 4 6 7 run_stmt $STMT 0 } {0} do_test 160 { sqlite3_carray_bind -double $STMT 3 1 2 3 4 5 6 7 run_stmt $STMT 0 } {1} do_test 170 { sqlite3_carray_bind -text -static $STMT 3 1 2 3 4 6 7 run_stmt $STMT 0 } {0} do_test 180 { sqlite3_carray_bind -text -transient $STMT 3 1 2 3 4 5 6 7 run_stmt $STMT 0 } {0} do_test 190 { sqlite3_carray_bind $STMT 3 run_stmt $STMT 0 } {0} sqlite3_finalize $STMT finish_test |
Changes to test/cast.test.
︙ | ︙ | |||
179 180 181 182 183 184 185 | do_test cast-1.51 { execsql {SELECT CAST('123.5abc' AS numeric)} } 123.5 do_test cast-1.53 { execsql {SELECT CAST('123.5abc' AS integer)} } 123 | | | | | | | | | | | | 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 | do_test cast-1.51 { execsql {SELECT CAST('123.5abc' AS numeric)} } 123.5 do_test cast-1.53 { execsql {SELECT CAST('123.5abc' AS integer)} } 123 do_test cast-1.60 { execsql {SELECT CAST(null AS REAL)} } {{}} do_test cast-1.61 { execsql {SELECT typeof(CAST(null AS REAL))} } {null} do_test cast-1.62 { execsql {SELECT CAST(1 AS REAL)} } {1.0} do_test cast-1.63 { execsql {SELECT typeof(CAST(1 AS REAL))} } {real} do_test cast-1.64 { execsql {SELECT CAST('1' AS REAL)} } {1.0} do_test cast-1.65 { execsql {SELECT typeof(CAST('1' AS REAL))} } {real} do_test cast-1.66 { execsql {SELECT CAST('abc' AS REAL)} } {0.0} do_test cast-1.67 { execsql {SELECT typeof(CAST('abc' AS REAL))} } {real} do_test cast-1.68 { execsql {SELECT CAST(x'31' AS REAL)} } {1.0} do_test cast-1.69 { execsql {SELECT typeof(CAST(x'31' AS REAL))} } {real} # Ticket #1662. Ignore leading spaces in numbers when casting. # do_test cast-2.1 { |
︙ | ︙ | |||
295 296 297 298 299 300 301 | execsql { SELECT CAST(CAST(x'39323233333732303336383534373734383030' AS real) AS integer) } } 9223372036854774784 } } | | | 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 | execsql { SELECT CAST(CAST(x'39323233333732303336383534373734383030' AS real) AS integer) } } 9223372036854774784 } } do_test cast-3.31 { execsql {SELECT CAST(NULL AS numeric)} } {{}} # Test to see if it is possible to trick SQLite into reading past # the end of a blob when converting it to a number. do_test cast-3.32.1 { set blob "1234567890" |
︙ | ︙ | |||
364 365 366 367 368 369 370 | } {-9223372036854775808 -9223372036854775808 -9223372036854775808} # EVIDENCE-OF: R-33990-33527 When casting to INTEGER, if the text looks # like a floating point value with an exponent, the exponent will be # ignored because it is no part of the integer prefix. # EVIDENCE-OF: R-24225-46995 For example, "(CAST '123e+5' AS INTEGER)" # results in 123, not in 12300000. | | > | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | } {-9223372036854775808 -9223372036854775808 -9223372036854775808} # EVIDENCE-OF: R-33990-33527 When casting to INTEGER, if the text looks # like a floating point value with an exponent, the exponent will be # ignored because it is no part of the integer prefix. # EVIDENCE-OF: R-24225-46995 For example, "(CAST '123e+5' AS INTEGER)" # results in 123, not in 12300000. do_execsql_test cast-5.3 { SELECT CAST('123e+5' AS INTEGER); SELECT CAST('123e+5' AS NUMERIC); SELECT CAST('123e+5' AS REAL); } {123 12300000 12300000.0} # The following does not have anything to do with the CAST operator, # but it does deal with affinity transformations. # do_execsql_test cast-6.1 { DROP TABLE IF EXISTS t1; CREATE TABLE t1(a NUMERIC); INSERT INTO t1 VALUES ('9000000000000000001'), ('9000000000000000001 '), (' 9000000000000000001'), (' 9000000000000000001 '); SELECT * FROM t1; } {9000000000000000001 9000000000000000001 9000000000000000001 9000000000000000001} # 2019-06-07 # https://www.sqlite.org/src/info/4c2d7639f076aa7c do_execsql_test cast-7.1 { SELECT CAST('-' AS NUMERIC); } {0} do_execsql_test cast-7.2 { SELECT CAST('-0' AS NUMERIC); } {0} do_execsql_test cast-7.3 { SELECT CAST('+' AS NUMERIC); } {0} do_execsql_test cast-7.4 { SELECT CAST('/' AS NUMERIC); } {0} # 2019-06-07 # https://www.sqlite.org/src/info/e8bedb2a184001bb do_execsql_test cast-7.10 { SELECT '' - 2851427734582196970; } {-2851427734582196970} do_execsql_test cast-7.11 { SELECT 0 - 2851427734582196970; } {-2851427734582196970} do_execsql_test cast-7.12 { SELECT '' - 1; } {-1} # 2019-06-10 # https://www.sqlite.org/src/info/dd6bffbfb6e61db9 # # EVIDENCE-OF: R-55084-10555 Casting a TEXT or BLOB value into NUMERIC # yields either an INTEGER or a REAL result. # do_execsql_test cast-7.20 { DROP TABLE IF EXISTS t0; CREATE TABLE t0 (c0 TEXT); INSERT INTO t0(c0) VALUES ('1.0'); SELECT CAST(c0 AS NUMERIC) FROM t0; } {1} # 2019-06-10 # https://sqlite.org/src/info/27de823723a41df45af3 # do_execsql_test cast-7.30 { SELECT -'.'; } 0 do_execsql_test cast-7.31 { SELECT '.'+0; } 0 do_execsql_test cast-7.32 { SELECT CAST('.' AS numeric); } 0 do_execsql_test cast-7.33 { SELECT -CAST('.' AS numeric); } 0 # 2019-06-12 # https://www.sqlite.org/src/info/674385aeba91c774 # do_execsql_test cast-7.40 { SELECT CAST('-0.0' AS numeric); } 0 do_execsql_test cast-7.41 { SELECT CAST('0.0' AS numeric); } 0 do_execsql_test cast-7.42 { SELECT CAST('+0.0' AS numeric); } 0 do_execsql_test cast-7.43 { SELECT CAST('-1.0' AS numeric); } -1 ifcapable utf16 { reset_db execsql { PRAGMA encoding='utf16' } do_execsql_test cast-8.1 { SELECT quote(X'310032003300')==quote(substr(X'310032003300', 1)) } 1 do_execsql_test cast-8.2 { SELECT CAST(X'310032003300' AS TEXT) ==CAST(substr(X'310032003300', 1) AS TEXT) } 1 } reset_db do_execsql_test cast-9.0 { CREATE TABLE t0(c0); INSERT INTO t0(c0) VALUES (0); CREATE VIEW v1(c0, c1) AS SELECT CAST(0.0 AS NUMERIC), COUNT(*) OVER () FROM t0; SELECT v1.c0 FROM v1, t0 WHERE v1.c0=0; } {0.0} finish_test |
Added test/changes.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 | # 2021 June 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. # #*********************************************************************** # # Tests for the sqlite3_changes() and sqlite3_total_changes() APIs. # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix changes # To test that the change-counters do not suffer from 32-bit signed integer # rollover, add the following line to the array of test cases below. The # test will take will over an hour to run. # # 7 (1<<31)+10 "" # foreach {tn nRow wor} { 1 50 "" 2 50 "WITHOUT ROWID" 3 5000 "" 4 5000 "WITHOUT ROWID" 5 50000 "" 6 50000 "WITHOUT ROWID" } { reset_db set nBig [expr $nRow] do_execsql_test 1.$tn.0 " PRAGMA journal_mode = off; CREATE TABLE t1(x INTEGER PRIMARY KEY) $wor; " {off} do_execsql_test 1.$tn.1 { WITH s(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i < $nBig ) INSERT INTO t1 SELECT i FROM s; } do_test 1.$tn.2 { db changes } [expr $nBig] do_test 1.$tn.3 { db total_changes } [expr $nBig] do_execsql_test 1.$tn.4 { INSERT INTO t1 VALUES(-1) } do_test 1.$tn.5 { db changes } [expr 1] do_test 1.$tn.6 { db total_changes } [expr {$nBig+1}] do_execsql_test 1.$tn.7a { SELECT count(*) FROM t1 } [expr {$nBig+1}] do_execsql_test 1.$tn.7 { DELETE FROM t1 } do_test 1.$tn.8 { db changes } [expr {$nBig+1}] do_test 1.$tn.9 { db total_changes } [expr {2*($nBig+1)}] } finish_test |
Changes to test/check.test.
1 2 3 4 5 6 7 8 9 10 11 12 13 | # 2005 November 2 # # 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 CHECK constraints # | < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | # 2005 November 2 # # 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 CHECK constraints # set testdir [file dirname $argv0] source $testdir/tester.tcl set ::testprefix check # Only run these tests if the build includes support for CHECK constraints ifcapable !check { |
︙ | ︙ | |||
37 38 39 40 41 42 43 | SELECT * FROM t1; } } {3 4.0} do_test check-1.3 { catchsql { INSERT INTO t1 VALUES(6,7); } | | | | 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 | SELECT * FROM t1; } } {3 4.0} do_test check-1.3 { catchsql { INSERT INTO t1 VALUES(6,7); } } {1 {CHECK constraint failed: x<5}} do_test check-1.4 { execsql { SELECT * FROM t1; } } {3 4.0} do_test check-1.5 { catchsql { INSERT INTO t1 VALUES(4,3); } } {1 {CHECK constraint failed: y>x}} do_test check-1.6 { execsql { SELECT * FROM t1; } } {3 4.0} do_test check-1.7 { catchsql { |
︙ | ︙ | |||
84 85 86 87 88 89 90 | SELECT * FROM t1; } } {2 4.0} do_test check-1.12 { catchsql { UPDATE t1 SET x=7 WHERE x==2 } | | | > > > > > > > | 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 | SELECT * FROM t1; } } {2 4.0} do_test check-1.12 { catchsql { UPDATE t1 SET x=7 WHERE x==2 } } {1 {CHECK constraint failed: x<5}} do_test check-1.13 { execsql { SELECT * FROM t1; } } {2 4.0} do_test check-1.14 { catchsql { UPDATE t1 SET x=5 WHERE x==2 } } {1 {CHECK constraint failed: x<5}} do_test check-1.15 { execsql { SELECT * FROM t1; } } {2 4.0} do_test check-1.16 { catchsql { UPDATE t1 SET x=4, y=11 WHERE x==2 } } {0 {}} do_test check-1.17 { execsql { SELECT * FROM t1; } } {4 11.0} do_test check-2.1 { execsql { PRAGMA writable_schema = 1; CREATE TABLE t2( x INTEGER CONSTRAINT one CHECK( typeof(coalesce(x,0))=="integer" ), y REAL CONSTRAINT two CHECK( typeof(coalesce(y,0.1))=='real' ), z TEXT CONSTRAINT three CHECK( typeof(coalesce(z,''))=='text' ) ); CREATE TABLE t2n( x INTEGER CONSTRAINT one CHECK( typeof(coalesce(x,0))=="integer" ), y NUMERIC CONSTRAINT two CHECK( typeof(coalesce(y,0.1))=='real' ), z TEXT CONSTRAINT three CHECK( typeof(coalesce(z,''))=='text' ) ); PRAGMA writable_schema = 0; } } {} do_test check-2.2 { execsql { INSERT INTO t2 VALUES(1,2.2,'three'); SELECT * FROM t2; } |
︙ | ︙ | |||
140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 | } {1 2.2 three {} {} {}} do_test check-2.4 { catchsql { INSERT INTO t2 VALUES(1.1, NULL, NULL); } } {1 {CHECK constraint failed: one}} do_test check-2.5 { catchsql { INSERT INTO t2 VALUES(NULL, 5, NULL); } } {1 {CHECK constraint failed: two}} do_test check-2.6 { catchsql { INSERT INTO t2 VALUES(NULL, NULL, 3.14159); } | > > > > > > > > | | > | 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 | } {1 2.2 three {} {} {}} do_test check-2.4 { catchsql { INSERT INTO t2 VALUES(1.1, NULL, NULL); } } {1 {CHECK constraint failed: one}} do_test check-2.5 { # The 5 gets automatically promoted to 5.0 because the column type is REAL catchsql { INSERT INTO t2 VALUES(NULL, 5, NULL); } } {0 {}} do_test check-2.5b { # This time the column type is NUMERIC, so not automatic promption to REAL # occurs and the constraint fails. catchsql { INSERT INTO t2n VALUES(NULL, 5, NULL); } } {1 {CHECK constraint failed: two}} do_test check-2.6 { catchsql { INSERT INTO t2 VALUES(NULL, NULL, 3.14159); } } {0 {}} # Undocumented behavior: The CONSTRAINT name clause can follow a constraint. # Such a clause is ignored. But the parser must accept it for backwards # compatibility. # do_test check-2.10 { execsql { CREATE TABLE t2b( x INTEGER CHECK( typeof(coalesce(x,0))=='integer' ) CONSTRAINT one, y TEXT PRIMARY KEY constraint two, z INTEGER, UNIQUE(x,z) constraint three ); } } {} do_test check-2.11 { catchsql { INSERT INTO t2b VALUES('xyzzy','hi',5); } } {1 {CHECK constraint failed: typeof(coalesce(x,0))=='integer'}} do_test check-2.12 { execsql { CREATE TABLE t2c( x INTEGER CONSTRAINT x_one CONSTRAINT x_two CHECK( typeof(coalesce(x,0))=='integer' ) CONSTRAINT x_two CONSTRAINT x_three, y INTEGER, z INTEGER, CONSTRAINT u_one UNIQUE(x,y,z) CONSTRAINT u_two ); } } {} do_test check-2.13 { catchsql { INSERT INTO t2c VALUES('xyzzy',7,8); } } {1 {CHECK constraint failed: x_two}} do_test check-2.cleanup { execsql { DROP TABLE IF EXISTS t2b; DROP TABLE IF EXISTS t2c; DROP TABLE IF EXISTS t2n; } } {} ifcapable subquery { do_test check-3.1 { catchsql { CREATE TABLE t3( |
︙ | ︙ | |||
252 253 254 255 256 257 258 | SELECT * FROM t3; } } {1 2 3} do_test check-3.9 { catchsql { INSERT INTO t3 VALUES(111,222,333); } | | | 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 | SELECT * FROM t3; } } {1 2 3} do_test check-3.9 { catchsql { INSERT INTO t3 VALUES(111,222,333); } } {1 {CHECK constraint failed: t3.x<25}} do_test check-4.1 { execsql { CREATE TABLE t4(x, y, CHECK ( x+y==11 OR x*y==12 |
︙ | ︙ | |||
294 295 296 297 298 299 300 | SELECT * FROM t4 } } {12 -22} do_test check-4.6 { catchsql { UPDATE t4 SET x=0, y=1; } | | > > > | 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 | SELECT * FROM t4 } } {12 -22} do_test check-4.6 { catchsql { UPDATE t4 SET x=0, y=1; } } {1 {CHECK constraint failed: x+y==11 OR x*y==12 OR x/y BETWEEN 5 AND 8 OR -x==y+10}} do_test check-4.7 { execsql { SELECT * FROM t4; } } {12 -22} do_test check-4.8 { execsql { |
︙ | ︙ | |||
316 317 318 319 320 321 322 | PRAGMA ignore_check_constraints=OFF; PRAGMA integrity_check; } {{CHECK constraint failed in t4}} do_test check-4.9 { catchsql { UPDATE t4 SET x=0, y=2; } | | > > > | 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 | PRAGMA ignore_check_constraints=OFF; PRAGMA integrity_check; } {{CHECK constraint failed in t4}} do_test check-4.9 { catchsql { UPDATE t4 SET x=0, y=2; } } {1 {CHECK constraint failed: x+y==11 OR x*y==12 OR x/y BETWEEN 5 AND 8 OR -x==y+10}} ifcapable vacuum { do_test check_4.10 { catchsql { VACUUM } } {0 {}} } |
︙ | ︙ | |||
367 368 369 370 371 372 373 | SELECT * FROM t1; } } {4 11.0 2 20.0} do_test check-6.5 { catchsql { UPDATE OR FAIL t1 SET x=7-x, y=y+1; } | | | | | 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 | SELECT * FROM t1; } } {4 11.0 2 20.0} do_test check-6.5 { catchsql { UPDATE OR FAIL t1 SET x=7-x, y=y+1; } } {1 {CHECK constraint failed: x<5}} do_test check-6.6 { execsql { SELECT * FROM t1; } } {3 12.0 2 20.0} do_test check-6.7 { catchsql { BEGIN; INSERT INTO t1 VALUES(1,30.0); INSERT OR ROLLBACK INTO t1 VALUES(8,40.0); } } {1 {CHECK constraint failed: x<5}} do_test check-6.8 { catchsql { COMMIT; } } {1 {cannot commit - no transaction is active}} do_test check-6.9 { execsql { SELECT * FROM t1 } } {3 12.0 2 20.0} do_test check-6.11 { execsql {SELECT * FROM t1} } {3 12.0 2 20.0} do_test check-6.12 { catchsql { REPLACE INTO t1 VALUES(6,7); } } {1 {CHECK constraint failed: x<5}} do_test check-6.13 { execsql {SELECT * FROM t1} } {3 12.0 2 20.0} do_test check-6.14 { catchsql { INSERT OR IGNORE INTO t1 VALUES(6,7); } |
︙ | ︙ | |||
422 423 424 425 426 427 428 | # If a connection opens a database that contains a CHECK constraint that # uses an unknown UDF, the schema should not be considered malformed. # Attempting to modify the table should fail (since the CHECK constraint # cannot be tested). # reset_db proc myfunc {x} {expr $x < 10} | | | | 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 | # If a connection opens a database that contains a CHECK constraint that # uses an unknown UDF, the schema should not be considered malformed. # Attempting to modify the table should fail (since the CHECK constraint # cannot be tested). # reset_db proc myfunc {x} {expr $x < 10} db func myfunc -deterministic myfunc do_execsql_test 7.1 { CREATE TABLE t6(a CHECK (myfunc(a))) } do_execsql_test 7.2 { INSERT INTO t6 VALUES(9) } do_catchsql_test 7.3 { INSERT INTO t6 VALUES(11) } \ {1 {CHECK constraint failed: myfunc(a)}} do_test 7.4 { sqlite3 db2 test.db execsql { SELECT * FROM t6 } db2 } {9} do_test 7.5 { |
︙ | ︙ | |||
450 451 452 453 454 455 456 | db2 func myfunc myfunc execsql { INSERT INTO t6 VALUES(8) } db2 } {} do_test 7.8 { db2 func myfunc myfunc catchsql { INSERT INTO t6 VALUES(12) } db2 | | | 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 | db2 func myfunc myfunc execsql { INSERT INTO t6 VALUES(8) } db2 } {} do_test 7.8 { db2 func myfunc myfunc catchsql { INSERT INTO t6 VALUES(12) } db2 } {1 {CHECK constraint failed: myfunc(a)}} # 2013-08-02: Silently ignore database name qualifiers in CHECK constraints. # do_execsql_test 8.1 { CREATE TABLE t810(a, CHECK( main.t810.a>0 )); CREATE TABLE t811(b, CHECK( xyzzy.t811.b BETWEEN 5 AND 10 )); } {} |
︙ | ︙ | |||
488 489 490 491 492 493 494 495 496 | forcedelete test.db sqlite3 db test.db do_execsql_test 10.1 { CREATE TABLE t1(x); CREATE VIEW v1(y) AS SELECT x FROM t1; PRAGMA integrity_check; } {ok} finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | forcedelete test.db sqlite3 db test.db do_execsql_test 10.1 { CREATE TABLE t1(x); CREATE VIEW v1(y) AS SELECT x FROM t1; PRAGMA integrity_check; } {ok} #------------------------------------------------------------------------- reset_db do_execsql_test 11.0 { CREATE TABLE t1 (Col0 CHECK(1 COLLATE BINARY BETWEEN 1 AND 1) ) ; } do_execsql_test 11.1 { INSERT INTO t1 VALUES (NULL); } do_execsql_test 11.2 { INSERT INTO t1 VALUES (NULL); } do_execsql_test 11.3 { CREATE TABLE t2(b, a CHECK( CASE 'abc' COLLATE nocase WHEN a THEN 1 ELSE 0 END) ); } do_execsql_test 11.4 { INSERT INTO t2(a) VALUES('abc'); } do_execsql_test 11.5 { INSERT INTO t2(b, a) VALUES(1, 'abc'||''); } do_execsql_test 11.6 { INSERT INTO t2(b, a) VALUES(2, 'abc'); } # 2019-12-24 ticket b383b90278186263 # reset_db do_execsql_test 12.10 { CREATE TABLE t1(a TEXT, CHECK(a=+a)); INSERT INTO t1(a) VALUES(NULL),('xyz'),(5),(x'303132'),(4.75); SELECT quote(a) FROM t1 ORDER BY rowid; } {NULL 'xyz' '5' X'303132' '4.75'} do_execsql_test 12.20 { DROP TABLE t1; CREATE TABLE t1(a TEXT, CHECK(a<>+a)); INSERT INTO t1(a) VALUES(NULL); } {} do_catchsql_test 12.21 { INSERT INTO t1(a) VALUES('xyz'); } {1 {CHECK constraint failed: a<>+a}} do_catchsql_test 12.22 { INSERT INTO t1(a) VALUES(123); } {1 {CHECK constraint failed: a<>+a}} do_execsql_test 12.30 { DROP TABLE t1; CREATE TABLE t1(a TEXT, CHECK(NOT(a=+a))); INSERT INTO t1(a) VALUES(NULL); } {} do_catchsql_test 12.31 { INSERT INTO t1(a) VALUES('xyz'); } {1 {CHECK constraint failed: NOT(a=+a)}} do_catchsql_test 12.32 { INSERT INTO t1(a) VALUES(123); } {1 {CHECK constraint failed: NOT(a=+a)}} do_execsql_test 12.40 { DROP TABLE t1; CREATE TABLE t1(a TEXT, CHECK(NOT(a<>+a))); INSERT INTO t1(a) VALUES(NULL),('xyz'),(5),(x'303132'),(4.75); SELECT quote(a) FROM t1 ORDER BY rowid; } {NULL 'xyz' '5' X'303132' '4.75'} do_execsql_test 12.50 { DROP TABLE t1; CREATE TABLE t1(a TEXT, CHECK(a BETWEEN 0 AND +a)); INSERT INTO t1(a) VALUES(NULL),('xyz'),(5),(x'303132'),(4.75); SELECT quote(a) FROM t1 ORDER BY rowid; } {NULL 'xyz' '5' X'303132' '4.75'} do_execsql_test 12.60 { DROP TABLE t1; CREATE TABLE t1(a TEXT, CHECK(a NOT BETWEEN 0 AND +a)); INSERT INTO t1(a) VALUES(NULL); SELECT quote(a) FROM t1 ORDER BY rowid; } {NULL} do_catchsql_test 12.61 { INSERT INTO t1(a) VALUES(456); } {1 {CHECK constraint failed: a NOT BETWEEN 0 AND +a}} do_execsql_test 12.70 { DROP TABLE t1; CREATE TABLE t1(a TEXT, CHECK(a BETWEEN +a AND 999999)); INSERT INTO t1(a) VALUES(NULL),(5); SELECT quote(a) FROM t1 ORDER BY rowid; } {NULL '5'} do_execsql_test 12.80 { DROP TABLE t1; CREATE TABLE t1(a TEXT, CHECK(a NOT BETWEEN +a AND 999999)); INSERT INTO t1(a) VALUES(NULL); SELECT quote(a) FROM t1 ORDER BY rowid; } {NULL} do_catchsql_test 12.81 { INSERT INTO t1(a) VALUES(456); } {1 {CHECK constraint failed: a NOT BETWEEN +a AND 999999}} finish_test |
Added test/checkfault.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 | # 2019 July 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 file contains fault-injection test cases for the # sqlite3_db_cacheflush API. # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix cffault source $testdir/malloc_common.tcl do_execsql_test 1.0 { CREATE TABLE t1 (Col0 CHECK(1 COLLATE BINARY BETWEEN 1 AND 1) ) ; CREATE TABLE t2(b, a CHECK( CASE 'abc' COLLATE nocase WHEN a THEN 1 ELSE 0 END) ); } do_faultsim_test 1.1 -faults oom* -body { execsql { INSERT INTO t1 VALUES ('ABCDEFG') } } -test { faultsim_test_result {0 {}} } do_faultsim_test 1.2 -faults oom* -body { execsql { INSERT INTO t2(a) VALUES('abc') } } -test { faultsim_test_result {0 {}} } finish_test |
Added test/chunksize.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 | # 2019 June 5 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix chunksize if {$::tcl_platform(platform)!="unix"} { finish_test return } foreach {tn jrnlmode} { 1 delete 2 wal } { reset_db file_control_chunksize_test db main 32768 do_execsql_test $tn.0 " PRAGMA journal_mode = $jrnlmode " $jrnlmode do_execsql_test $tn.1 { CREATE TABLE t1(a, b); INSERT INTO t1 VALUES(1, 2); } execsql { PRAGMA wal_checkpoint } do_test $tn.2 { file size test.db } 32768 } finish_test |
Changes to test/close.test.
︙ | ︙ | |||
74 75 76 77 78 79 80 81 82 | sqlite3_prepare $DB "SELECT * FROM sqlite_master" -1 dummy } msg] $msg } {1 {(21) bad parameter or other API misuse}} do_test 1.4.4 { sqlite3_finalize $STMT } {SQLITE_OK} finish_test | > > > > > > > | 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 | sqlite3_prepare $DB "SELECT * FROM sqlite_master" -1 dummy } msg] $msg } {1 {(21) bad parameter or other API misuse}} do_test 1.4.4 { sqlite3_finalize $STMT } {SQLITE_OK} do_test 1.5 { set DB [sqlite3_open test.db] sqlite3_blob_open $DB main t1 x 2 0 BLOB sqlite3_close_v2 $DB sqlite3_blob_close $BLOB } {} finish_test |
Changes to test/collate1.test.
︙ | ︙ | |||
396 397 398 399 400 401 402 403 404 | ORDER BY 1 COLLATE nocase COLLATE nocase COLLATE nocase COLLATE binary; } {DEF abc} do_execsql_test 7.2 { SELECT 'abc' UNION ALL SELECT 'DEF' ORDER BY 1 COLLATE binary COLLATE binary COLLATE binary COLLATE nocase; } {abc DEF} finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | ORDER BY 1 COLLATE nocase COLLATE nocase COLLATE nocase COLLATE binary; } {DEF abc} do_execsql_test 7.2 { SELECT 'abc' UNION ALL SELECT 'DEF' ORDER BY 1 COLLATE binary COLLATE binary COLLATE binary COLLATE nocase; } {abc DEF} # 2019-06-14 # https://sqlite.org/src/info/f1580ba1b574e9e9 # do_execsql_test 8.0 { SELECT ' ' > char(20) COLLATE rtrim; } 0 do_execsql_test 8.1 { SELECT '' < char(20) COLLATE rtrim; } 1 do_execsql_test 8.2 { DROP TABLE IF EXISTS t0; CREATE TABLE t0(c0 COLLATE RTRIM, c1 BLOB UNIQUE, PRIMARY KEY (c0, c1)) WITHOUT ROWID; INSERT INTO t0 VALUES (123, 3), (' ', 1), (' ', 2), ('', 4); SELECT * FROM t0 WHERE c1 = 1; } {{ } 1} # 2019-10-09 # ALWAYS() macro fails following OOM # Problem detected by dbsqlfuzz. # do_execsql_test 9.0 { CREATE TABLE t1(a, b); CREATE TABLE t2(c, d); } do_faultsim_test 9.1 -faults oom* -body { execsql { SELECT * FROM ( SELECT b COLLATE nocase IN (SELECT c FROM t2) FROM t1 ); } } -test { faultsim_test_result {0 {}} } # 2020-01-03 dbsqlfuzz find # reset_db do_catchsql_test 10.0 { CREATE TABLE t1(a INTEGER PRIMARY KEY,b); INSERT INTO t1 VALUES(0,NULL); CREATE TABLE t2(x UNIQUE); CREATE VIEW v1a(z,y) AS SELECT x COLLATE x FROM t2; SELECT a,b,z,y,'' FROM t1 JOIN v1a ON b IS NOT FALSE; } {1 {no such collation sequence: x}} finish_test |
Changes to test/colname.test.
︙ | ︙ | |||
395 396 397 398 399 400 401 402 403 404 405 406 407 408 | } {Bbb 123} ifcapable vtab { do_execsql_test colname-9.320 { CREATE TABLE t2 AS SELECT BBb FROM (SELECT aaa AS Bbb FROM t1); SELECT name FROM pragma_table_info('t2'); } {Bbb} } # Issue detected by OSSFuzz on 2017-12-24 (Christmas Eve) # caused by check-in https://sqlite.org/src/info/6b2ff26c25 # # Prior to being fixed, the following CREATE TABLE was dereferencing # a NULL pointer and segfaulting. # | > > > > > > | 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 | } {Bbb 123} ifcapable vtab { do_execsql_test colname-9.320 { CREATE TABLE t2 AS SELECT BBb FROM (SELECT aaa AS Bbb FROM t1); SELECT name FROM pragma_table_info('t2'); } {Bbb} } do_execsql_test colname-9.330 { -- added 2019-08-10 to invalidate DROP TABLE IF EXISTS t1; -- a couple assert()s that were CREATE TABLE t1(a); -- added by ticket 3b44500725 INSERT INTO t1 VALUES(17),(2),(99),(-3),(7); SELECT (SELECT avg(a) UNION SELECT min(a) OVER()) FROM t1; } {17} # Issue detected by OSSFuzz on 2017-12-24 (Christmas Eve) # caused by check-in https://sqlite.org/src/info/6b2ff26c25 # # Prior to being fixed, the following CREATE TABLE was dereferencing # a NULL pointer and segfaulting. # |
︙ | ︙ |
Added test/columncount.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 | # 2021 February 15 # # 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 the sqlite3_column_count() API. # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix columncount # If SQLITE_OMIT_ALTERTABLE is defined, omit this file. ifcapable !altertable { finish_test return } proc do_ccsql_test {tn sql res} { uplevel [list do_test $tn [subst -nocommands { set stmt [sqlite3_prepare_v2 db {$sql} -1 dummy] set res [sqlite3_column_count [set stmt]] while {[sqlite3_step [set stmt]]=="SQLITE_ROW"} { for {set i 0} {[set i] < [sqlite3_data_count [set stmt]]} {incr i} { lappend res [sqlite3_column_text [set stmt] [set i]] } } set rc [sqlite3_finalize [set stmt]] if {[set rc]!="SQLITE_OK"} { error [sqlite3_errmsg db] } set res }] [list {*}$res]] } do_execsql_test 1.0 { CREATE TABLE t1(x, y, z); INSERT INTO t1 VALUES('a', 'b', 'c'); } do_ccsql_test 1.1 { SELECT * FROM t1 } {3 a b c} do_ccsql_test 1.2 { CREATE TABLE t2(a, b) } {0} do_ccsql_test 1.3 { ALTER TABLE t2 RENAME TO t3 } {0} do_ccsql_test 1.4 { ALTER TABLE t3 RENAME b TO ccc } {0} do_ccsql_test 1.5 { ALTER TABLE t3 ADD COLUMN d } {0} do_ccsql_test 1.6 { DROP TABLE t3 } {0} finish_test |
Changes to test/concfault.test.
︙ | ︙ | |||
78 79 80 81 82 83 84 | } } -test { faultsim_test_result {0 {}} catchsql { ROLLBACK } faultsim_integrity_check } | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > | > > | 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 | } } -test { faultsim_test_result {0 {}} catchsql { ROLLBACK } faultsim_integrity_check } #------------------------------------------------------------------------- reset_db do_execsql_test 2.0 { PRAGMA auto_vacuum = 0; PRAGMA journal_mode = wal; CREATE TABLE t1(a PRIMARY KEY, b); CREATE TABLE t2(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; } {wal} faultsim_save_and_close do_faultsim_test 1 -prep { faultsim_restore_and_reopen execsql { SELECT * FROM t1; BEGIN CONCURRENT; INSERT INTO t2 VALUES(1, 2); } sqlite3 db2 test.db execsql { PRAGMA journal_size_limit = 10000; INSERT INTO t1 VALUES(randomblob(1000), randomblob(1000)); } db2 db2 close } -body { execsql { COMMIT } } -test { faultsim_test_result {0 {}} catchsql { ROLLBACK } set res [catchsql { SELECT count(*) FROM t1 }] if {$res!="0 9"} { error "expected {0 9} got {$res}" } faultsim_integrity_check } finish_test |
Changes to test/concurrent.test.
︙ | ︙ | |||
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 | sqlite3_finalize $stmt catchsql ROLLBACK } #------------------------------------------------------------------------- # CONCURRENT transactions may not modify the db schema. # foreach {tn sql} { 1 { CREATE TABLE xx(a, b) } 2 { DROP TABLE t1 } 3 { CREATE INDEX i1 ON t1(a) } 4 { CREATE VIEW v1 AS SELECT * FROM t1 } } { do_catchsql_test 1.7.0.$tn.1 " BEGIN CONCURRENT; $sql | > > | > > > > > | > > | | 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 | sqlite3_finalize $stmt catchsql ROLLBACK } #------------------------------------------------------------------------- # CONCURRENT transactions may not modify the db schema. # sqlite3 db2 test.db foreach {tn sql} { 1 { CREATE TABLE xx(a, b) } 2 { DROP TABLE t1 } 3 { CREATE INDEX i1 ON t1(a) } 4 { CREATE VIEW v1 AS SELECT * FROM t1 } } { do_catchsql_test 1.7.0.$tn.1 " BEGIN CONCURRENT; $sql " {0 {}} db2 eval {INSERT INTO t1 DEFAULT VALUES} do_catchsql_test 1.7.0.$tn.2 { COMMIT } {1 {database is locked}} do_execsql_test 1.7.0.$tn.2 ROLLBACK do_execsql_test 1.7.0.$tn.3 { SELECT sql FROM sqlite_master; SELECT sql FROM sqlite_temp_master; } {{CREATE TABLE t1(a, b)}} #do_execsql_test 1.7.0.$tn.3 COMMIT } # Except the temp db schema. foreach {tn sql} { 1 { CREATE TEMP TABLE xx(a, b) } 2 { DROP TABLE xx } 3 { CREATE TEMP TABLE yy(a, b) } |
︙ | ︙ |
Changes to test/concurrent2.test.
︙ | ︙ | |||
339 340 341 342 343 344 345 | #------------------------------------------------------------------------- # Test that "PRAGMA integrity_check" works within a concurrent # transaction. Within a concurrent transaction, "PRAGMA integrity_check" # is unable to detect unused database pages, but can detect other types # of corruption. # reset_db | | > | | | | | | | | | > | > | | 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 | #------------------------------------------------------------------------- # Test that "PRAGMA integrity_check" works within a concurrent # transaction. Within a concurrent transaction, "PRAGMA integrity_check" # is unable to detect unused database pages, but can detect other types # of corruption. # reset_db do_test 8.1 { execsql { PRAGMA journal_mode = wal; CREATE TABLE kv(k INTEGER PRIMARY KEY, v UNIQUE); INSERT INTO kv VALUES(NULL, randomblob(750)); INSERT INTO kv SELECT NULL, randomblob(750) FROM kv; INSERT INTO kv SELECT NULL, randomblob(750) FROM kv; INSERT INTO kv SELECT NULL, randomblob(750) FROM kv; INSERT INTO kv SELECT NULL, randomblob(750) FROM kv; INSERT INTO kv SELECT NULL, randomblob(750) FROM kv; DELETE FROM kv WHERE rowid%2; } set v [db one {PRAGMA freelist_count}] expr $v==33 || $v==34 } {1} do_execsql_test 8.2 { PRAGMA integrity_check } ok do_execsql_test 8.3 { BEGIN CONCURRENT; PRAGMA integrity_check; } {ok} do_execsql_test 8.4 { INSERT INTO kv VALUES(1100, 1100); |
︙ | ︙ |
Added test/concurrent8.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 | # 2020 July 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. # #*********************************************************************** # set testdir [file dirname $argv0] source $testdir/tester.tcl set ::testprefix concurrent8 source $testdir/lock_common.tcl ifcapable !concurrent { finish_test return } do_multiclient_test tn { do_test 1.$tn.0 { sql1 { CREATE TABLE t1(x, y); PRAGMA journal_mode = wal; } } {wal} do_test 1.$tn.1 { sql1 { BEGIN CONCURRENT; INSERT INTO t1 VALUES(1, 1); } } {} do_test 1.$tn.2 { sql2 { CREATE TABLE t2(a, b); } } {} do_test 1.$tn.3 { list [catch { sql1 { COMMIT } } msg] $msg } {1 {database is locked}} do_test 1.$tn.4 { code1 { db errorcode } } {517} ;# SQLITE_BUSY_SNAPSHOT do_test 1.$tn.5 { sql1 { ROLLBACK; BEGIN CONCURRENT; CREATE TABLE t3(a, b); COMMIT; } } {} do_test 1.$tn.6 { set nPg [sql1 {PRAGMA page_count}] sql1 "BEGIN CONCURRENT" for {set i 0} {$i<250} {incr i} { sql1 "CREATE TABLE z$i (a, b, c)" } sql1 "COMMIT" set nPg2 [sql1 {PRAGMA page_count}] expr $nPg2>$nPg } {1} do_test 1.$tn.7 { sql2 { PRAGMA integrity_check } } {ok} do_test 1.$tn.8 { sql1 { BEGIN CONCURRENT; CREATE TABLE t4(a, b); } sql2 { INSERT INTO t1 VALUES(2, 2); } list [catch { sql1 COMMIT } msg] $msg } {1 {database is locked}} sql1 ROLLBACK do_test 1.$tn.9 { sql1 { BEGIN CONCURRENT; CREATE TEMP TABLE t5(a, b); INSERT INTO t2 VALUES('x', 'x'); } sql2 { INSERT INTO t1 VALUES(3, 3); CREATE TEMP TABLE t1(x, y); } sql1 COMMIT } {} } finish_test |
Changes to test/conflict.test.
︙ | ︙ | |||
9 10 11 12 13 14 15 | # #*********************************************************************** # This file implements regression tests for SQLite library. # # This file implements tests for the conflict resolution extension # to SQLite. # | < | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | # #*********************************************************************** # This file implements regression tests for SQLite library. # # This file implements tests for the conflict resolution extension # to SQLite. # set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable !conflict { finish_test return |
︙ | ︙ | |||
810 811 812 813 814 815 816 | CREATE TABLE t13(a CHECK(a!=2)); BEGIN; REPLACE INTO t13 VALUES(1); } catchsql { REPLACE INTO t13 VALUES(2); } | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | CREATE TABLE t13(a CHECK(a!=2)); BEGIN; REPLACE INTO t13 VALUES(1); } catchsql { REPLACE INTO t13 VALUES(2); } } {1 {CHECK constraint failed: a!=2}} verify_ex_errcode conflict-13.1b SQLITE_CONSTRAINT_CHECK do_test conflict-13.2 { execsql { REPLACE INTO t13 VALUES(3); COMMIT; SELECT * FROM t13; } } {1 3} # Ticket https://www.sqlite.org/src/tktview/e6f1f2e34dceeb1ed61531c7e9 # Verify that it is not possible to sneak a NULL value into a NOT NULL # column using REPLACE. # do_catchsql_test conflict-14.1 { DROP TABLE IF EXISTS t1; CREATE TABLE t1(x NOT NULL DEFAULT NULL); REPLACE INTO t1 DEFAULT VALUES; } {1 {NOT NULL constraint failed: t1.x}} # 2019-12-15 gramfuzz1 find # Three UNIQUE constraints, where the third would is a duplicate except # that it adds ON CONFLICT REPLACE. Verify that the indexes end up # sorted in the correct order (REPLACE last) so that constraint processing # works correctly. # reset_db do_execsql_test conflict-15.10 { CREATE TABLE t1( x PRIMARY KEY, UNIQUE(x,x), UNIQUE(x,x) ON CONFLICT REPLACE ); INSERT INTO t1(x) VALUES(1); SELECT * FROM t1; } {1} do_catchsql_test conflict-15.20 { INSERT INTO t1(x) VALUES(1); } {1 {UNIQUE constraint failed: t1.x}} do_execsql_test conflict-15.30 { SELECT * FROM t1; } {1} finish_test |
Changes to test/conflict2.test.
︙ | ︙ | |||
807 808 809 810 811 812 813 | CREATE TABLE t13(a PRIMARY KEY CHECK(a!=2)) WITHOUT rowid; BEGIN; REPLACE INTO t13 VALUES(1); } catchsql { REPLACE INTO t13 VALUES(2); } | | | 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 | CREATE TABLE t13(a PRIMARY KEY CHECK(a!=2)) WITHOUT rowid; BEGIN; REPLACE INTO t13 VALUES(1); } catchsql { REPLACE INTO t13 VALUES(2); } } {1 {CHECK constraint failed: a!=2}} verify_ex_errcode conflict2-13.1b SQLITE_CONSTRAINT_CHECK do_test conflict2-13.2 { execsql { REPLACE INTO t13 VALUES(3); COMMIT; SELECT * FROM t13; } |
︙ | ︙ |
Changes to test/conflict3.test.
︙ | ︙ | |||
362 363 364 365 366 367 368 369 370 | do_execsql_test 12.2 { REPLACE INTO t2 VALUES(NULL, '112'), (111, '111B'); } do_execsql_test 12.3 { SELECT * FROM t2; } {111 111B 112 112} finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | do_execsql_test 12.2 { REPLACE INTO t2 VALUES(NULL, '112'), (111, '111B'); } do_execsql_test 12.3 { SELECT * FROM t2; } {111 111B 112 112} #------------------------------------------------------------------------- ifcapable trigger { reset_db do_execsql_test 13.1.0 { PRAGMA recursive_triggers = true; CREATE TABLE t0 (c0 UNIQUE, c1 UNIQUE); CREATE TRIGGER tr0 AFTER DELETE ON t0 BEGIN DELETE FROM t0; END; INSERT INTO t0 VALUES(1, NULL); INSERT INTO t0 VALUES(0, NULL); } do_catchsql_test 13.1.1 { UPDATE OR REPLACE t0 SET c1 = 1; } {1 {constraint failed}} integrity_check 13.1.2 do_execsql_test 13.1.3 { SELECT * FROM t0 } {1 {} 0 {}} do_execsql_test 13.2.0 { CREATE TABLE t2 (a PRIMARY KEY, b UNIQUE, c UNIQUE) WITHOUT ROWID; CREATE TRIGGER tr3 AFTER DELETE ON t2 BEGIN DELETE FROM t2; END; INSERT INTO t2 VALUES(1, 1, 1); INSERT INTO t2 VALUES(2, 2, 2); } do_catchsql_test 13.2.1 { UPDATE OR REPLACE t2 SET c = 0; } {1 {constraint failed}} integrity_check 13.2.2 do_execsql_test 13.2.3 { SELECT * FROM t2 } {1 1 1 2 2 2} do_execsql_test 13.3.0 { CREATE TABLE t1(a, b); CREATE TABLE log(x); CREATE INDEX i1 ON t1(a); INSERT INTO t1 VALUES(1, 2); CREATE TRIGGER tb BEFORE UPDATE ON t1 BEGIN DELETE FROM t1; END; CREATE TRIGGER ta AFTER UPDATE ON t1 BEGIN INSERT INTO log VALUES('fired!'); END; UPDATE t1 SET b=3; } do_execsql_test 13.3.1 { SELECT * FROM t1; } {} do_execsql_test 13.3.2 { SELECT * FROM log; } {} } finish_test |
Changes to test/corrupt2.test.
︙ | ︙ | |||
91 92 93 94 95 96 97 | set f [open corrupt.db RDWR] fconfigure $f -encoding binary seek $f 101 start puts -nonewline $f "\xFF\xFF" close $f sqlite3 db2 corrupt.db | > > | < < < | > | < < < | > | 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 | set f [open corrupt.db RDWR] fconfigure $f -encoding binary seek $f 101 start puts -nonewline $f "\xFF\xFF" close $f sqlite3 db2 corrupt.db # Note: This test is no longer meaningful due to the deferred computation # of MemPage.nFree catchsql {PRAGMA quick_check} db2 } {0 {{*** in database main *** Page 1: free space corruption}}} do_test corrupt2-1.5 { db2 close # Corrupt the free-block list on page 1. forcedelete corrupt.db forcedelete corrupt.db-journal forcecopy test.db corrupt.db set f [open corrupt.db RDWR] fconfigure $f -encoding binary seek $f 101 start puts -nonewline $f "\x00\xC8" seek $f 200 start puts -nonewline $f "\x00\x00" puts -nonewline $f "\x10\x00" close $f sqlite3 db2 corrupt.db catchsql {PRAGMA quick_check} db2 } {0 {{*** in database main *** Page 1: free space corruption}}} db2 close # Corrupt a database by having 2 indices of the same name: do_test corrupt2-2.1 { forcedelete corrupt.db forcedelete corrupt.db-journal |
︙ | ︙ |
Changes to test/corrupt3.test.
︙ | ︙ | |||
90 91 92 93 94 95 96 | do_test corrupt3-1.9 { db close hexio_write test.db 2044 [hexio_render_int32 4] sqlite3 db test.db catchsql { SELECT substr(x,1,10) FROM t1 } | | | 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 | do_test corrupt3-1.9 { db close hexio_write test.db 2044 [hexio_render_int32 4] sqlite3 db test.db catchsql { SELECT substr(x,1,10) FROM t1 } } [list 1 {database disk image is malformed}] do_test corrupt3-1.10 { catchsql { PRAGMA integrity_check } } {0 {{*** in database main *** On tree page 2 cell 0: invalid page number 4 Page 3 is never used}}} |
︙ | ︙ |
Changes to test/corrupt4.test.
︙ | ︙ | |||
9 10 11 12 13 14 15 | # #*********************************************************************** # This file implements regression tests for SQLite library. # # This file implements tests to make sure SQLite does not crash or # segfault if it sees a corrupt database file. # | < > | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | # #*********************************************************************** # This file implements regression tests for SQLite library. # # This file implements tests to make sure SQLite does not crash or # segfault if it sees a corrupt database file. # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix corrupt4 # This module uses hard-coded offsets which do not work if the reserved_bytes # value is nonzero. if {[nonzero_reserved_bytes]} {finish_test; return;} # These tests deal with corrupt database files # |
︙ | ︙ | |||
74 75 76 77 78 79 80 81 82 | hexio_write test.db [expr {$::baseaddr+4}] [hexio_render_int32 -100000000] db close sqlite3 db test.db catchsql { DROP TABLE t2 } } {1 {database disk image is malformed}} finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | hexio_write test.db [expr {$::baseaddr+4}] [hexio_render_int32 -100000000] db close sqlite3 db test.db catchsql { DROP TABLE t2 } } {1 {database disk image is malformed}} #------------------------------------------------------------------------- reset_db do_execsql_test 2.0 { PRAGMA page_size = 512; CREATE TABLE t1(a, b, c); } # Create a database with a schema so large that the root of the # sqlite_schema table is the grandparent of its leaves. # set nView 1000 do_test 2.1 { execsql BEGIN for {set ii 0} {$ii<$nView} {incr ii} { execsql " CREATE VIEW v$ii AS SELECT a, b, c FROM t1 " } execsql COMMIT } {} db close proc get2byte {fd offset} { seek $fd $offset set bin [read $fd 2] binary scan $bin S val set val } proc get4byte {fd offset} { seek $fd $offset set bin [read $fd 4] binary scan $bin I val set val } proc put4byte {fd offset val} { seek $fd $offset set bin [binary format I $val] puts -nonewline $fd $bin } # Page 1 is now the grandparent of its leaves. Corrupt the database by setting # the second rightmost child page number of page 1 to 1. # set fd [open test.db r+] fconfigure $fd -encoding binary -translation binary set nChild [get2byte $fd 103] set offChild [get2byte $fd [expr 100+12+($nChild-2)*2]] set pgnoChild [get4byte $fd $offChild] put4byte $fd $offChild 1 close $fd if {![info exists ::G(perm:presql)]} { sqlite3 db test.db do_catchsql_test 2.2 { PRAGMA writable_schema = 1; SELECT * FROM sqlite_schema; } {1 {database disk image is malformed}} do_test 2.3 { list [catch { for {set ii $nView} {$ii<$nView*2} {incr ii} { execsql "INSERT INTO sqlite_master VALUES(1, 2, 3, 4, 5)" } } msg] $msg } {1 {database disk image is malformed}} } finish_test |
Changes to test/corruptC.test.
︙ | ︙ | |||
30 31 32 33 34 35 36 37 38 | # These tests deal with corrupt database files # database_may_be_corrupt # Construct a compact, dense database for testing. # do_test corruptC-1.1 { execsql { PRAGMA auto_vacuum = 0; | > < | 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | # These tests deal with corrupt database files # database_may_be_corrupt # Construct a compact, dense database for testing. # do_test corruptC-1.1 { sqlite3_db_config db LEGACY_FILE_FORMAT 1 execsql { PRAGMA auto_vacuum = 0; BEGIN; CREATE TABLE t1(x,y); INSERT INTO t1 VALUES(1,1); INSERT OR IGNORE INTO t1 SELECT x*2,y FROM t1; INSERT OR IGNORE INTO t1 SELECT x*3,y FROM t1; INSERT OR IGNORE INTO t1 SELECT x*5,y FROM t1; INSERT OR IGNORE INTO t1 SELECT x*7,y FROM t1; |
︙ | ︙ | |||
93 94 95 96 97 98 99 | forcecopy test.bu test.db # insert corrupt byte(s) hexio_write test.db 2053 [format %02x 0x04] sqlite3 db test.db catchsql {PRAGMA integrity_check} | | > | 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 | forcecopy test.bu test.db # insert corrupt byte(s) hexio_write test.db 2053 [format %02x 0x04] sqlite3 db test.db catchsql {PRAGMA integrity_check} } {0 {{*** in database main *** Page 3: free space corruption}}} # test that a corrupt content offset size is handled (seed 5649) # # Update 2016-12-27: As of check-in [0b86fbca66] "In sqlite3BtreeInsert() when # replacing a re-existing row, try to overwrite the cell directly rather than # deallocate and reallocate the cell" on 2016-12-09, this test case no longer # detects the offset size problem during the UPDATE. We have to run a subsequent |
︙ | ︙ |
Changes to test/corruptD.test.
︙ | ︙ | |||
107 108 109 110 111 112 113 | #------------------------------------------------------------------------- # The following tests, corruptD-1.1.*, focus on the page header field # containing the offset of the first free block in a page. # do_test corruptD-1.1.1 { incr_change_counter hexio_write test.db [expr 1024+1] FFFF | | | > | 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 | #------------------------------------------------------------------------- # The following tests, corruptD-1.1.*, focus on the page header field # containing the offset of the first free block in a page. # do_test corruptD-1.1.1 { incr_change_counter hexio_write test.db [expr 1024+1] FFFF catchsql { PRAGMA quick_check } } {0 {{*** in database main *** Page 2: free space corruption}}} do_test corruptD-1.1.2 { incr_change_counter hexio_write test.db [expr 1024+1] [hexio_render_int32 1021] catchsql { SELECT * FROM t1 ORDER BY rowid } } {1 {database disk image is malformed}} #------------------------------------------------------------------------- |
︙ | ︙ |
Changes to test/corruptE.test.
︙ | ︙ | |||
32 33 34 35 36 37 38 39 40 | finish_test return } # Construct a compact, dense database for testing. # do_test corruptE-1.1 { execsql { PRAGMA auto_vacuum = 0; | > < | 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | finish_test return } # Construct a compact, dense database for testing. # do_test corruptE-1.1 { sqlite3_db_config db LEGACY_FILE_FORMAT 1 execsql { PRAGMA auto_vacuum = 0; BEGIN; CREATE TABLE t1(x,y); INSERT INTO t1 VALUES(1,1); INSERT OR IGNORE INTO t1 SELECT x*2,y FROM t1; INSERT OR IGNORE INTO t1 SELECT x*3,y FROM t1; INSERT OR IGNORE INTO t1 SELECT x*5,y FROM t1; INSERT OR IGNORE INTO t1 SELECT x*7,y FROM t1; |
︙ | ︙ |
Changes to test/corruptK.test.
︙ | ︙ | |||
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 | seek $fd 30 puts -nonewline $fd "\x18" close $fd } {} do_execsql_test 1.3 { INSERT INTO t1 VALUES(randomblob(20)); } do_catchsql_test 1.4 { INSERT INTO t1 VALUES(randomblob(90)); } {1 {database disk image is malformed}} #------------------------------------------------------------------------- reset_db do_execsql_test 2.1 { PRAGMA page_size=1024; PRAGMA auto_vacuum=0; CREATE TABLE t1(x); | > > > > > > | 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 | seek $fd 30 puts -nonewline $fd "\x18" close $fd } {} do_execsql_test 1.3 { INSERT INTO t1 VALUES(randomblob(20)); } # This test no longer functions due to the deferred computation of # MemPage.nFree. # if 0 { do_catchsql_test 1.4 { INSERT INTO t1 VALUES(randomblob(90)); } {1 {database disk image is malformed}} } #------------------------------------------------------------------------- reset_db do_execsql_test 2.1 { PRAGMA page_size=1024; PRAGMA auto_vacuum=0; CREATE TABLE t1(x); |
︙ | ︙ |
Added test/corruptL.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 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 | # 2019-01-11 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix corruptL database_may_be_corrupt #------------------------------------------------------------------------- reset_db do_test 1.0 { sqlite3 db {} db deserialize [decode_hexdb { | size 356352 pagesize 4096 filename crash-acaae0347204ae.db | page 1 offset 0 | 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3. | 16: 10 00 01 01 00 40 20 20 00 00 00 00 d0 00 00 00 .....@ ........ | 32: 40 00 ea 00 00 00 00 00 00 40 00 00 00 40 00 00 @........@...@.. | 96: 00 00 00 00 0d 00 00 00 04 0e 9c 00 0f ad 0f 4f ...............O | 112: 0e fc 0e 9c 00 00 00 00 00 00 00 00 00 00 00 00 ................ | 3728: 00 00 00 00 00 00 00 00 00 00 00 00 5e 04 07 17 ............^... | 3744: 1f 1f 01 81 0b 74 61 62 6c 65 74 31 5f 70 61 72 .....tablet1_par | 3760: 65 6e 74 74 31 5f 70 61 72 65 6e 74 04 43 52 45 entt1_parent.CRE | 3776: 41 54 45 20 54 41 42 4c 45 20 22 74 31 5f 70 61 ATE TABLE .t1_pa | 3792: 72 65 6e 74 22 28 6e 6f 64 65 6e 6f 20 49 4e 54 rent.(nodeno INT | 3808: 45 47 45 52 20 50 52 49 4d 41 52 59 20 4b 45 59 EGER PRIMARY KEY | 3824: 2c 70 61 72 65 6e 74 6e 6f 64 65 29 51 03 06 17 ,parentnode)Q... | 3840: 1b 1b 01 7b 74 61 62 6c 65 74 31 5f 6e 6f 64 65 ....tablet1_node | 3856: 74 31 5f 6e 6f 64 65 03 43 52 45 41 54 45 20 54 t1_node.CREATE T | 3872: 41 42 4c 45 20 22 74 31 5f 6e 6f 64 65 22 28 6e ABLE .t1_node.(n | 3888: 6f 64 65 6e 6f 20 49 4e 54 45 47 45 52 20 50 52 odeno INTEGER PR | 3904: 49 4d 41 52 59 20 4b 45 59 2c 64 61 74 61 29 5c IMARY KEY,data). | 3920: 02 07 17 1d 1d 01 81 0b 74 61 62 6c 65 74 31 5f ........tablet1_ | 3936: 72 6f 77 69 64 74 31 5f 72 6f 77 69 64 02 43 52 rowidt1_rowid.CR | 3952: 45 41 54 45 20 54 41 42 4c 45 20 22 74 31 5f 72 EATE TABLE .t1_r | 3968: 6f 77 69 64 22 28 72 6f 77 69 64 20 49 4e 54 45 owid.(rowid INTE | 3984: 47 45 52 20 50 52 49 4d 41 52 59 20 4b 45 59 2c GER PRIMARY KEY, | 4000: 6e 6f 64 65 6e 6f 2c 61 30 2c 61 31 29 51 01 07 nodeno,a0,a1)Q.. | 4016: 17 11 11 08 81 0f 74 61 62 6c 65 74 31 74 31 43 ......tablet1t1C | 4032: 52 45 41 54 45 20 56 49 52 54 55 41 4c 20 54 41 REATE VIRTUAL TA | 4048: 42 4c 45 20 74 31 20 55 53 49 4e 47 20 72 74 72 BLE t1 USING rtr | 4064: 65 65 28 69 64 2c 78 30 20 50 52 49 4d 41 52 59 ee(id,x0 PRIMARY | 4080: 20 4b 45 59 2c 70 61 72 65 6e 74 6e 6f 64 65 29 KEY,parentnode) | page 2 offset 4096 | 0: 51 03 06 17 1b 1b 01 7b 74 61 62 6c 65 74 31 5f Q.......tablet1_ | 16: 6e 6f 64 65 74 31 5f 6e 6f 64 65 03 43 52 45 41 nodet1_node.CREA | 32: 54 45 20 54 41 42 4c 45 20 22 74 31 5f 6e 6f 64 TE TABLE .t1_nod | 48: 65 22 28 6e 6f 64 65 6e 6f 20 49 4e 54 45 47 45 e.(nodeno INTEGE | 64: 52 20 50 52 49 4d 41 52 59 20 4b 45 59 2c 64 61 R PRIMARY KEY,da | 80: 74 61 29 5c 02 07 17 1d 1d 01 81 0b 74 61 62 6c ta).........tabl | 96: 65 74 31 5f 72 6f 77 69 64 74 31 5f 72 6f 77 69 et1_rowidt1_rowi | 112: 64 02 43 52 45 41 54 45 20 54 41 42 4c 45 00 00 d.CREATE TABLE.. | 128: 01 0a 02 00 00 00 01 0e 0d 00 00 00 00 24 0e 0d .............$.. | 144: 0c 1a 06 85 50 46 60 27 70 08 00 00 00 00 00 00 ....PF`'p....... | 3824: 00 00 00 00 00 00 00 0d 0e 05 00 09 1d 00 74 6f ..............to | 3840: 79 20 68 61 6c 66 10 0d 05 00 09 23 00 62 6f 74 y half.....#.bot | 3856: 74 6f 6d 20 68 61 6c 66 0f 0c 05 00 09 21 00 72 tom half.....!.r | 3872: 69 67 68 74 20 68 61 6c 66 0e 0b 05 00 09 1f 00 ight half....... | 3888: 6c 65 66 74 20 43 15 f6 e6 f6 46 50 34 35 24 54 left C....FP45$T | 3904: 15 44 52 05 44 14 24 c4 52 02 27 43 15 f6 e6 f6 .DR.D.$.R.'C.... | 3920: 46 52 22 8e 6f 64 65 6e 6f 20 49 4e 54 45 47 45 FR..odeno INTEGE | 3936: 52 20 50 52 49 4d 41 52 59 20 4b 45 59 2c 64 61 R PRIMARY KEY,da | 3952: 74 61 29 5c 02 07 17 1d 1d 01 81 0b 74 61 62 6c ta).........tabl | 3968: 65 74 31 5f 72 6f 74 74 6f 6d 20 65 64 67 65 0f et1_rottom edge. | 3984: 07 05 00 09 21 00 72 69 67 68 74 20 65 64 67 65 ....!.right edge | 4000: 0e 06 05 00 09 1f 00 6c 65 66 74 20 65 64 67 65 .......left edge | 4016: 0b 05 05 00 09 19 00 63 65 6e 74 65 72 17 04 05 .......center... | 4032: 00 09 31 00 75 70 70 65 72 2d 72 69 67 68 74 20 ..1.upper-right | 4048: 63 6f 72 6e 65 72 17 03 05 00 09 31 00 6c 6f 77 corner.....1.low | 4064: 65 72 2d 72 69 67 68 74 20 63 6f 72 6e 65 72 16 er-right corner. | 4080: 02 05 00 09 2f 00 75 70 70 65 72 2d 6c 65 66 74 ..../.upper-left | page 3 offset 8192 | 0: 20 63 6f 72 6e 65 72 16 01 05 00 09 2f 01 8c 6f corner...../..o | 16: 77 65 72 2d 6c 53 51 4c 69 74 65 20 66 6f 72 6d wer-lSQLite form | 32: 61 74 20 33 00 10 00 01 01 00 40 20 20 00 00 00 at 3......@ ... | 48: 00 00 00 00 2f 00 00 0d eb 13 00 00 00 03 00 00 ..../........... | 64: 00 04 00 00 00 00 00 00 00 06 00 00 00 01 00 00 ................ | 80: 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 ................ | page 6 offset 20480 | 128: 00 00 00 00 00 00 00 00 97 3d 04 ae 7c 01 00 00 .........=..|... | 624: 00 00 00 00 00 00 21 97 3d 04 ae 7c 01 00 00 00 ......!.=..|.... | 1120: 00 00 00 00 00 20 97 3d 04 ae 7c 01 00 00 00 00 ..... .=..|..... | 1616: 00 00 00 00 1f 97 3d 04 ae 7c 01 00 00 00 00 00 ......=..|...... | 2112: 00 00 00 1e 97 3d 04 ae 7c 01 00 00 00 00 00 00 .....=..|....... | 2608: 00 00 1d 97 d3 d0 4a e7 c0 00 00 00 00 00 00 00 ......J......... | 3088: 00 00 00 00 00 00 00 00 00 00 00 00 01 f3 00 00 ................ | 3600: 23 97 3d 04 ae 7c 01 00 00 00 00 00 00 00 00 00 #.=..|.......... | 4080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 26 ...............& | page 8 offset 28672 | 0: 0d 00 00 00 01 04 30 00 04 30 00 00 00 00 00 00 ......0..0...... | 1072: 97 4d 1e 14 00 ae 7c 00 00 00 00 00 00 00 00 00 .M....|......... | 1088: 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 ................ | 4080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 03 ................ | page 10 offset 36864 | 0: 0d 00 00 00 01 04 30 00 04 30 00 00 00 00 00 00 ......0..0...... | 1072: 9a ee c1 80 fd 78 1f ce 1b ae eb b4 00 00 00 00 .....x.......... | 1088: 13 20 ff 20 00 70 00 00 00 60 50 00 00 00 11 e0 . . .p...`P..... | 1104: 00 00 00 70 00 00 00 60 50 05 35 14 c6 97 46 52 ...p...`P.5...FR | 1120: 06 66 f7 26 d6 17 42 03 30 01 00 00 10 10 04 02 .f.&..B.0....... | 1136: 02 00 00 00 00 00 00 00 00 40 00 00 00 00 00 00 .........@...... | 1152: 00 00 00 00 00 40 00 00 00 40 00 00 00 00 00 00 .....@...@...... | 4080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 05 ................ | page 12 offset 45056 | 0: 0d 00 00 00 01 04 30 00 04 30 e1 b4 30 97 4d 46 ......0..0..0.MF | 16: 14 00 ae 7c 00 00 00 00 00 00 00 03 00 00 43 00 ...|..........C. | page 47 offset 188416 | 2512: 00 00 00 00 00 00 00 00 be 00 00 00 00 00 00 00 ................ | page 87 offset 352256 | 2512: 00 00 00 00 00 00 00 00 aa 00 00 00 00 00 00 00 ................ | end crash-acaae0347204ae.db }]} {} do_catchsql_test 1.1 { PRAGMA cell_size_check = off; DROP INDEX t1x1; } {1 {database disk image is malformed}} do_catchsql_test 1.2 { SELECT sum(s+length(b)) FROM t1 WHERE a IN (110,10,150) AND q IS NULL; } {1 {database disk image is malformed}} do_catchsql_test 1.3 { REINDEX t1; } {1 {database disk image is malformed}} do_catchsql_test 1.4 { PRAGMA integrity_check } {1 {database disk image is malformed}} #------------------------------------------------------------------------- reset_db do_test 2.0 { sqlite3 db {} db deserialize [decode_hexdb { | size 20480 pagesize 4096 filename crash.txt.db | page 1 offset 0 | 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3. | 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 05 .....@ ........ | 32: 00 00 00 00 00 00 00 00 00 00 00 05 00 00 00 04 ................ | 48: 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 ................ | 96: 00 00 00 00 0d 00 00 00 05 0e 55 00 0f 74 0f 3c ..........U..t.< | 112: 0e f9 0e d1 0e 55 00 00 00 00 00 00 00 00 00 00 .....U.......... | 3664: 00 00 00 00 00 7a 05 07 15 11 11 08 81 63 76 69 .....z.......cvi | 3680: 65 77 76 31 76 31 43 52 45 41 54 45 20 56 49 45 ewv1v1CREATE VIE | 3696: 57 20 76 31 28 78 2c 79 29 20 41 53 0a 53 45 4c W v1(x,y) AS.SEL | 3712: 45 43 54 20 74 31 2e 62 2c 74 32 2e 62 20 46 52 ECT t1.b,t2.b FR | 3728: 4f 4d 20 74 31 2c 74 32 20 57 48 45 52 45 20 74 OM t1,t2 WHERE t | 3744: 31 2e 61 3d 74 32 2e 61 20 47 52 4f 55 50 20 42 1.a=t2.a GROUP B | 3760: 59 20 31 20 48 41 56 49 4e 47 20 74 32 2e 63 20 Y 1 HAVING t2.c | 3776: 4e 4f 54 20 4e 55 4c 4c 0a 4c 49 4d 49 54 20 31 NOT NULL.LIMIT 1 | 3792: 30 26 04 06 17 11 11 01 39 74 61 62 6c 65 74 32 0&......9tablet2 | 3808: 74 32 05 43 52 45 41 54 45 20 54 41 42 4c 45 20 t2.CREATE TABLE | 3824: 74 32 28 61 2c 62 2c 63 29 41 03 06 17 15 11 01 t2(a,b,c)A...... | 3840: 6b 69 6e 64 65 78 74 31 78 31 74 31 04 43 52 45 kindext1x1t1.CRE | 3856: 41 54 45 20 49 4e 44 45 58 20 73 31 78 31 20 4f ATE INDEX s1x1 O | 3872: 4e 20 74 31 28 64 29 20 57 48 45 52 45 20 65 65 N t1(d) WHERE ee | 3888: 20 49 53 20 4e 4f 54 20 4e 55 4c 4c 36 02 06 17 IS NOT NULL6... | 3904: 17 11 01 53 69 6e 64 65 78 74 31 61 62 63 74 31 ...Sindext1abct1 | 3920: 03 43 52 45 41 54 45 20 49 4e 44 45 58 20 74 31 .CREATE INDEX t1 | 3936: 61 62 63 20 4f 4e 20 74 31 28 61 2c 62 2c 63 2b abc ON t1(a,b,c+ | 3952: 64 2b 65 29 81 09 01 07 17 11 11 01 81 7d 74 61 d+e)..........ta | 3968: 62 6c 65 74 31 74 31 02 43 52 45 41 54 45 20 54 blet1t1.CREATE T | 3984: 41 42 4c 45 20 74 31 28 61 2c 62 2c 63 2c 64 2c ABLE t1(a,b,c,d, | 4000: 65 2c 66 2c 67 2c 68 2c 6a 2c 6a 6a 2c 6a 6a 6a e,f,g,h,j,jj,jjj | 4016: 2c 6b 2c 61 61 2c 62 62 2c 63 63 2c 64 64 2c 65 ,k,aa,bb,cc,dd,e | 4032: 65 20 44 45 46 41 55 4c 54 20 33 2e 31 34 2c 0a e DEFAULT 3.14,. | 4048: 66 66 20 44 45 46 41 55 4c 54 28 27 68 69 63 63 ff DEFAULT('hicc | 4064: 75 70 27 29 2c 67 67 20 4e 4f 54 20 4e 55 4c 4c up'),gg NOT NULL | 4080: 20 44 45 46 41 55 4c 54 28 66 61 6c 73 65 29 29 DEFAULT(false)) | page 2 offset 4096 | 0: 0d 00 00 00 0a 0e 7b 00 0f dc 0f b6 0f 8f 0f 68 ...............h | 16: 0f 41 0f 1a 0e f3 0e cb 0e a3 0e 7b 00 00 00 00 .A.............. | 3696: 00 00 00 00 00 00 00 00 00 00 00 26 0a 14 01 01 ...........&.... | 3712: 02 08 00 00 00 00 00 00 00 00 00 00 00 00 07 19 ................ | 3728: 08 09 5a 00 b4 40 09 1e b8 51 eb 85 1f 68 69 63 ..Z..@...Q...hic | 3744: 63 75 70 26 09 14 01 01 02 08 00 00 00 00 00 00 cup&............ | 3760: 00 00 00 00 00 00 07 19 08 08 50 00 a0 40 09 1e ..........P..@.. | 3776: b8 51 eb 85 1f 68 69 63 63 75 70 26 08 14 01 01 .Q...hiccup&.... | 3792: 02 08 00 00 00 00 00 00 00 00 00 00 00 00 07 19 ................ | 3808: 08 07 46 00 8c 40 09 1e b8 51 eb 85 1f 68 69 63 ..F..@...Q...hic | 3824: 63 75 70 25 07 14 01 01 01 08 00 00 00 00 00 00 cup%............ | 3840: 00 00 00 00 00 00 07 b9 08 06 3c 78 40 09 1e b8 ..........<x@... | 3856: 51 eb 85 1f 68 69 63 63 75 70 25 06 14 01 00 01 Q...hiccup%..... | 3872: 08 00 00 00 00 00 00 00 00 00 00 00 00 07 19 08 ................ | 3888: 05 32 64 40 09 1e b8 51 eb 85 1f 68 69 63 63 75 .2d@...Q...hiccu | 3904: 70 25 05 14 01 01 01 08 00 00 00 00 00 00 00 00 p%.............. | 3920: 00 00 00 00 07 19 08 04 28 50 40 09 1e b8 51 eb ........(P@...Q. | 3936: 85 1f 68 69 63 63 75 70 25 04 14 01 01 01 08 00 ..hiccup%....... | 3952: 00 00 00 00 00 00 00 00 00 00 00 07 19 08 03 1e ................ | 3968: 3c 40 09 1e b8 51 eb 85 1f 68 69 63 63 75 70 25 <@...Q...hiccup% | 3984: 03 14 01 01 01 08 00 00 00 00 00 00 00 00 00 00 ................ | 4000: 00 00 07 19 08 02 14 28 40 09 1e b8 51 eb 85 1f .......(@...Q... | 4016: 68 69 63 63 75 70 24 02 14 09 01 01 08 00 00 00 hiccup$......... | 4032: 00 00 00 00 00 00 00 00 00 07 19 08 0a 14 40 09 ..............@. | 4048: 1e b8 51 eb 85 1f 68 69 63 63 75 70 22 01 14 08 ..Q...hiccup.... | 4064: 08 08 07 ff ff ff ff ff ff 00 00 00 00 00 00 07 ................ | 4080: 19 08 40 09 1e b8 51 eb 85 1f 68 69 63 63 75 70 ..@...Q...hiccup | page 3 offset 8192 | 0: 0a 00 00 00 0a 0f aa 00 0f fa 0f f2 0f e9 0f e0 ................ | 16: 0f d7 0f ce 0f c5 0f bc 0e b3 0f aa 00 00 00 00 ................ | 4000: 00 00 00 00 00 00 00 00 00 00 08 05 01 01 00 01 ................ | 4016: 09 5a 0a 08 05 01 01 00 01 08 50 09 08 05 01 01 .Z........P..... | 4032: 00 01 07 46 08 08 05 01 01 00 01 06 3c 07 08 05 ...F........<... | 4048: 01 01 00 01 05 32 06 08 05 01 01 00 01 04 28 05 .....2........(. | 4064: 08 05 01 01 00 01 03 1e 04 08 05 01 01 00 01 02 ................ | 4080: 14 03 07 05 09 01 00 01 0a 02 05 05 08 08 00 09 ................ | page 4 offset 12288 | 0: 0a 00 00 00 0a 0f cf 00 0f fc 0f f7 0f f2 0f ed ................ | 16: 0f e8 0f e3 0f de 0f d9 0f d4 0f cf 00 00 00 00 ................ | 4032: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 04 ................ | 4048: 03 08 01 0a 04 03 08 01 09 04 03 08 01 08 04 03 ................ | 4064: 08 01 07 04 03 08 01 06 04 03 08 01 05 04 03 08 ................ | 4080: 01 04 04 03 08 01 13 04 03 08 01 02 03 03 08 09 ................ | page 5 offset 16384 | 0: 0d 00 00 00 00 10 00 00 00 00 00 00 00 00 00 00 ................ | end crash.txt.db }]} {} do_execsql_test 2.1 { PRAGMA writable_schema=ON; -- bypass improved sqlite_master consistency checking INSERT INTO t1(b) VALUES(X'a0fee3669f9fddefc5cba913e4225d4b6ce2b04f26b87fad3ee6f9b7d90a1ea62a169bf41e5d32707a6ca5c3d05e4bde05c9d89eaaa8c50e74333d2e9fcd7dfe95528a3a016aac1102d825c5cd70cf99d8a88e0ea7f798d4334386518b7ad359beb168b93aba059a2a3bd93112d65b44c12b9904ea786b204d80531cdf0504bf9b203dbe927061974caf7b9f30cbc3397b61f802e732012a6663d41c3607d6f1c0dbcfd489adac05ca500c0b04439d894cd93a840159225ef73b627e178b9f84b3ffe66cf22a963a8368813ff7961fc47f573211ccec95e0220dcbb3bf429f4a50ba54d7a53784ac51bfef346e6ac8ae0d0e7c3175946e62ba2b'); } do_catchsql_test 2.2 { SELECT b,c FROM t1 ORDER BY a; } {1 {database disk image is malformed}} #------------------------------------------------------------------------- reset_db do_execsql_test 3.0 { CREATE TABLE t1(a, b, c, d INTEGER PRIMARY KEY); CREATE TABLE t2(a, b, c, d INTEGER PRIMARY KEY); INSERT INTO t1(a, b, c, d) VALUES (1, 2, 3, 100), (4, 5, 6, 101); INSERT INTO t2(a, b, c, d) VALUES (1, 100, 3, 1000), (4, 101, 6, 1001); CREATE INDEX t1a ON t1(a); CREATE INDEX t2a ON t2(a, b, c); PRAGMA writable_schema = 1; UPDATE sqlite_master SET sql = 'CREATE INDEX t2a ON t2(a)' WHERE name='t2a'; } db close sqlite3 db test.db do_catchsql_test 3.1 { INSERT INTO t1 SELECT * FROM t2; } {1 {database disk image is malformed}} #------------------------------------------------------------------------- reset_db do_test 4.0 { sqlite3 db {} db deserialize [decode_hexdb { | size 4096 pagesize 512 filename crash-6b48ba69806134.db | page 1 offset 0 | 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3. | 16: 02 00 01 01 00 40 20 20 00 ff ff ff ff 00 00 07 .....@ ........ | 32: 00 00 00 00 00 00 00 00 00 00 00 08 00 00 00 04 ................ | 48: 00 00 00 00 00 00 00 05 00 eb 00 01 00 00 00 00 ................ | 80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0c ................ | 96: 00 2e 2c 50 0d 00 00 00 06 01 06 00 01 da 01 b0 ..,P............ | 112: 05 56 01 86 01 2a 01 06 00 00 00 00 00 00 00 00 .V...*.......... | 128: 00 ff 00 00 ff ff ff e1 00 00 00 00 00 00 00 00 ................ | 144: 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 ................ | 160: 00 00 00 00 00 00 00 00 f2 00 00 00 00 00 00 00 ................ | 176: 00 00 f9 ff ff ff ff ff ff ff 00 00 00 00 00 fb ................ | 208: 00 00 00 00 00 00 00 00 1e 00 00 00 fe 00 00 00 ................ | 224: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ca 00 ................ | 256: 00 00 00 00 ef ff 22 07 06 17 11 11 01 31 74 61 .............1ta | 272: 62 6c 65 74 38 38 74 04 43 52 45 41 54 45 20 54 blet88t.CREATE T | 288: 41 42 4c 45 20 74 34 28 87 29 2a 06 06 17 13 11 ABLE t4(.)*..... | 304: 01 3f 69 4f 64 65 78 74 33 78 74 33 05 43 52 45 .?iOdext3xt3.CRE | 320: 41 54 45 20 49 6e 44 45 58 20 74 33 78 20 4f 4e ATE InDEX t3x ON | 336: 20 74 33 28 78 29 2e 04 06 17 15 11 01 45 69 6e t3(x).......Ein | 352: 64 65 2e 74 32 63 64 74 3d 05 43 52 45 41 54 45 de.t2cdt=.CREATE | 368: 20 49 4e 44 45 58 20 74 32 63 64 20 4f 4e 20 74 INDEX t2cd ON t | 384: 32 28 0a 0c 44 29 28 05 06 17 11 11 01 3d 74 61 2(..D)(......=ta | 400: 62 6c 65 d4 33 74 33 04 43 52 45 41 54 45 20 54 ble.3t3.CREATE T | 416: 41 42 4c 45 20 74 33 28 63 2c 78 2c 65 2c 66 29 ABLE t3(c,x,e,f) | 432: 28 02 06 17 11 11 01 3d 74 61 62 6c 65 74 32 74 (......=tablet2t | 448: 32 03 43 52 45 41 54 45 20 54 41 42 4c 45 20 74 2.CREATE TABLE t | 464: 32 28 63 2c 64 2c 65 2c 66 29 24 01 06 17 11 11 2(c,d,e,f)$..... | 480: 01 35 74 60 62 6c 65 74 31 74 31 02 43 52 45 41 .5t`blet1t1.CREA | 496: 54 45 20 54 41 42 4c 45 20 74 30 28 61 2c 62 29 TE TABLE t0(a,b) | page 2 offset 512 | 0: 0d 00 ff 11 04 01 cf 00 01 fa 01 f3 01 de 01 cf ................ | 32: 00 00 08 00 00 00 00 00 00 00 00 00 00 00 00 13 ................ | 48: 00 00 00 00 00 00 00 00 00 00 00 01 00 20 00 00 ............. .. | 64: 00 00 00 00 00 00 f8 ff ff ff 00 00 00 00 00 00 ................ | 160: 01 64 00 00 00 00 00 80 ff ff ff 00 00 00 00 00 .d.............. | 176: 00 00 00 00 00 00 00 00 1f 00 00 00 00 00 00 03 ................ | 192: 00 00 40 00 00 00 00 00 00 00 00 00 00 00 00 00 ..@............. | 288: 00 00 00 00 00 00 ff ff ff e9 00 00 00 00 00 00 ................ | 336: 01 00 00 ff ff 00 00 00 00 00 00 00 00 00 00 00 ................ | 368: 20 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ............... | 384: 00 de ff 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ | 464: 00 00 00 00 00 13 76 65 6e 65 69 67 68 74 13 03 ......veneight.. | 480: 03 40 07 07 14 00 54 45 20 49 4e 44 45 58 20 74 .@....TE INDEX t | 496: 32 63 64 20 4f 4e 20 74 32 28 0a 0c 44 09 01 02 2cd ON t2(..D... | page 3 offset 1024 | 0: 0d 00 00 00 48 01 54 00 01 f7 01 ec 01 c5 01 aa ....H.T......... | 16: 30 34 28 87 29 2a 06 06 17 13 11 01 3f 69 4f 64 04(.)*......?iOd | 32: 65 79 74 33 78 74 33 6d 6d 6d 6d 6d 6d 7d 6d 6d eyt3xt3mmmmmm.mm | 48: 6d 41 6d 6d 6d 6d 6d 6d 6d 6d 6d 6d 6d 6d 6d 6d mAmmmmmmmmmmmmmm | 64: 6d 6d 6d 6d 6d 6d 6d 6d 6d 6d 6d 66 6d 6d 6d 6d mmmmmmmmmmmfmmmm | 80: 6d 4e 6d 6d 6d 6d 6d 6d 6d 6d 6d 6d 6d 6d 6d 6d mNmmmmmmmmmmmmmm | 96: 6d 6d 6d 6d 6d 6d 6d 6d 6d 6d 6d 6d 6d 6d 6d 6d mmmmmmmmmmmmmmmm | 112: 6d 6d 6d 6d 6d 6d 6d 6d 6d 6d 6d 6d 6d 6d 6d 6d mmmmmmmmmmmmmmmm | 128: 6d 6d 6d 6d 6d 00 00 00 00 00 00 00 00 00 00 00 mmmmm........... | 160: 80 00 00 00 00 00 00 03 00 00 00 ff e4 00 00 00 ................ | 208: 00 00 00 00 00 00 00 00 00 00 00 00 00 c5 00 00 ................ | 240: 14 00 00 00 00 00 00 00 00 00 00 00 08 00 00 00 ................ | 256: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0f ec ................ | 304: 00 00 00 00 19 08 05 17 17 17 17 65 69 67 68 74 ...........eight | 320: 65 69 67 68 74 73 65 00 00 00 00 00 00 00 00 00 eightse......... | 336: 00 00 00 00 19 08 05 17 17 17 17 65 69 67 68 74 ...........eight | 352: 65 69 67 68 74 73 65 01 65 6e 00 00 00 10 25 07 eightse.en....%. | 368: 07 6e 25 07 07 07 40 18 00 00 00 00 00 00 40 18 .n%...@.......@. | 384: 00 00 00 00 00 00 40 14 00 00 00 00 00 00 40 14 ......@.......@. | 400: 00 00 00 00 00 00 09 06 05 01 01 01 01 04 04 03 ................ | 416: 03 07 05 05 01 01 09 09 02 02 19 04 05 17 17 17 ................ | 432: 17 10 65 76 65 6e 65 69 67 68 74 65 69 67 68 74 ..eveneighteight | 448: 73 65 76 65 6e 25 03 05 07 07 07 07 40 14 00 00 seven%......@... | 464: 00 00 00 00 40 18 00 00 00 00 00 00 40 18 00 00 ....@.......@... | 480: 00 00 00 00 40 14 00 00 00 00 e8 f6 09 02 00 00 ....@........... | 496: 00 00 00 00 00 00 00 00 00 00 64 00 00 00 00 02 ..........d..... | page 4 offset 1536 | 0: 0d 00 00 00 00 02 00 00 00 00 00 00 00 00 00 fa ................ | 16: 1f a1 07 00 00 00 00 00 01 00 00 00 00 00 00 00 ................ | 32: 00 00 00 00 00 00 00 00 00 00 00 00 00 73 69 6d .............sim | 48: 70 6c 65 00 00 00 00 00 00 00 00 00 00 00 00 00 ple............. | 80: 00 00 00 00 00 10 00 00 00 00 00 00 01 00 00 00 ................ | 96: 00 00 00 00 00 00 00 00 00 00 00 00 00 fe ff ff ................ | 112: ff 00 00 00 00 00 00 00 00 00 00 00 4a 00 00 00 ............J... | 144: 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 ................ | 176: e5 ff ff ff 00 00 00 00 00 00 00 00 00 00 00 00 ................ | 208: 00 00 00 00 00 00 00 00 00 00 36 36 00 00 00 00 ..........66.... | 240: 00 00 00 6c 00 00 00 00 00 00 00 00 00 00 00 00 ...l............ | 256: 00 80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ | 320: 00 00 00 00 00 00 00 00 01 00 00 02 00 80 00 00 ................ | 336: 00 00 00 00 00 19 08 05 17 17 17 17 65 69 67 68 ............eigh | 352: 74 65 69 67 68 74 73 65 76 65 6e 73 65 76 65 6e teightsevenseven | 368: 25 07 05 07 07 07 07 40 18 00 00 00 00 00 00 40 %......@.......@ | 384: 18 00 20 00 00 00 40 00 14 00 00 00 00 00 00 40 .. ...@........@ | 400: 14 00 00 00 00 00 1c 09 06 05 01 01 01 01 04 04 ................ | 416: 03 03 07 05 05 01 01 00 00 00 00 00 00 00 00 00 ................ | 448: 74 73 65 76 65 6e 00 80 ff ff 00 00 00 00 00 aa tseven.......... | 464: 00 9e 00 00 00 00 00 00 00 00 00 00 00 70 6f 72 .............por | 480: 74 65 72 00 00 00 00 00 00 00 00 00 00 00 00 00 ter............. | 496: 00 00 00 00 00 00 29 00 00 00 00 00 00 00 00 00 ......)......... | page 5 offset 2048 | 0: 0a 00 00 00 08 01 96 00 01 fa 01 c5 01 f2 01 bc ................ | 16: 01 dc 01 a6 01 96 01 cc 00 00 00 00 00 00 00 00 ................ | 112: 00 00 00 09 00 00 00 00 01 00 00 00 00 00 00 00 ................ | 160: 74 72 69 67 62 ff ff ff ff fc 00 00 00 00 00 00 trigb........... | 240: 00 00 00 00 00 00 00 00 00 00 ff 00 00 00 00 00 ................ | 256: e5 ff ff ff 00 00 54 00 00 00 00 00 00 00 00 00 ......T......... | 304: 00 00 00 00 00 00 09 00 00 00 00 00 00 00 00 00 ................ | 400: 00 00 00 00 00 09 00 00 00 00 01 00 00 00 00 00 ................ | 448: 00 00 74 72 69 67 62 ff ff ff ff fc 00 00 07 05 ..trigb......... | 464: 05 01 01 09 09 02 02 19 04 05 17 17 17 17 10 65 ...............e | 480: 76 65 6e 65 69 67 68 74 65 40 18 00 00 00 00 01 veneighte@...... | 496: 02 03 07 04 01 01 01 03 04 02 05 04 09 01 ff fd ................ | end crash-6b48ba69806134.db }]} {} set res {1 {database disk image is malformed}} ifcapable oversize_cell_check { set res {1 {no such table: t3}} } do_catchsql_test 4.1 { PRAGMA writable_schema=ON; -- bypass improved sqlite_master consistency checking INSERT INTO t3 SELECT * FROM t2; } $res #------------------------------------------------------------------------- reset_db do_test 5.0 { sqlite3 db {} db deserialize [decode_hexdb { | size 192512 pagesize 4096 filename crash-9ae5502296c949.db | page 1 offset 0 | 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3. | 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 2f .....@ ......./ | 32: 00 00 00 1b 00 00 00 13 00 00 00 03 00 00 00 04 ................ | 48: 00 00 00 00 00 00 00 06 00 00 00 01 00 00 00 00 ................ | 64: 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 ................ | 96: 00 00 00 00 0d 00 00 00 04 0e e2 00 0f 96 0f 44 ...............D | 112: 0f 10 0e e2 00 00 00 00 00 00 00 00 00 00 00 00 ................ | 3808: 00 00 2c 04 06 17 15 11 01 41 69 6e 64 65 78 74 ..,......Aindext | 3824: 31 78 32 74 31 06 43 52 45 41 54 45 20 49 4e 44 1x2t1.CREATE IND | 3840: 45 58 20 74 31 78 32 20 4f 4e 20 74 31 28 62 29 EX t1x2 ON t1(b) | 3856: 32 03 06 17 15 11 01 4d 69 6e 64 65 78 74 31 78 2......Mindext1x | 3872: 31 74 31 05 43 52 45 41 54 45 20 49 4e 44 45 58 1t1.CREATE INDEX | 3888: 20 74 31 78 31 20 4f 4e 20 74 31 28 67 2b 68 2c t1x1 ON t1(g+h, | 3904: 6a 2c 6b 29 50 02 06 17 2b 2b 01 59 74 61 62 6c j,k)P...++.Ytabl | 3920: 65 73 71 6c 69 74 65 5f 73 65 71 75 65 6e 63 65 esqlite_sequence | 3936: 73 71 6c 69 74 65 5f 73 65 71 75 65 6e 63 65 04 sqlite_sequence. | 3952: 43 52 45 41 54 45 20 54 41 42 4c 45 20 73 71 6c CREATE TABLE sql | 3968: 69 74 65 5f 73 65 71 75 65 6e 63 65 28 6e 61 6d ite_sequence(nam | 3984: 65 2c 73 65 71 29 68 01 07 17 11 11 01 81 3b 74 e,seq)h.......;t | 4000: 61 62 6c 65 74 31 74 31 03 43 52 45 41 54 45 20 ablet1t1.CREATE | 4016: 54 41 42 4c 45 20 74 31 28 61 20 49 4e 54 45 47 TABLE t1(a INTEG | 4032: 45 52 20 50 52 49 4d 41 52 59 20 4b 45 59 20 41 ER PRIMARY KEY A | 4048: 55 54 4f 49 4e 43 52 45 4d 45 4e 54 2c 0a 62 2c UTOINCREMENT,.b, | 4064: 63 2c 64 2c 65 2c 66 2c 67 2c 68 2c 6a 2c 6b 2c c,d,e,f,g,h,j,k, | 4080: 6c 2c 6d 2c 6e 2c 6f 2c 70 2c 71 2c 72 2c 73 29 l,m,n,o,p,q,r,s) | page 2 offset 4096 | 0: 01 00 00 00 00 01 00 00 00 00 01 00 00 00 00 01 ................ | 16: 00 00 00 00 02 10 00 00 00 05 00 00 00 03 02 00 ................ | 32: 00 00 00 05 00 00 00 03 02 00 00 00 00 05 00 00 ................ | 48: 00 03 02 00 00 00 00 05 00 00 00 03 02 00 00 00 ................ | 64: 00 05 00 00 00 03 02 00 00 00 00 05 00 00 00 03 ................ | 80: 02 00 00 00 00 05 00 00 00 03 02 00 00 00 00 05 ................ | 96: 00 00 00 03 02 00 00 00 00 05 00 00 00 03 05 00 ................ | 112: 00 00 03 03 00 00 00 23 02 00 00 00 00 03 00 00 .......#........ | 128: 00 23 02 00 00 00 00 03 00 00 00 23 02 00 00 00 .#.........#.... | 144: 00 03 00 00 00 23 02 00 00 00 00 03 00 00 00 23 .....#.........# | 160: 05 00 00 00 06 05 00 00 00 06 02 00 00 00 00 03 ................ | 176: 00 00 00 06 02 00 00 00 00 03 00 00 00 24 02 00 .............$.. | 192: 00 00 00 03 00 00 00 24 02 00 00 00 00 03 00 00 .......$........ | 208: 00 24 02 00 00 00 00 02 00 00 00 00 03 00 00 00 .$.............. | 224: 24 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 $............... | page 3 offset 8192 | 0: 05 00 00 00 09 0f d0 00 00 00 00 19 0f fb 0f f6 ................ | 16: 0f f1 0f ec 0f e7 0f e2 0f dc 0f d6 0f d0 0f a0 ................ | 32: 0f a0 0f a0 0f a0 0f a0 0f a0 0f a0 0f a0 0f a0 ................ | 1072: 00 97 4c 0a 14 00 ae 7c 00 00 00 00 00 00 00 00 ..L....|........ | 1088: 00 00 00 00 00 00 00 09 00 00 00 00 00 00 00 00 ................ | 4000: 0f ac 00 06 00 00 00 00 00 30 00 00 00 00 00 00 .........0...... | 4048: 00 00 00 16 81 2a 00 00 00 14 81 16 00 00 00 12 .....*.......... | 4064: 81 02 00 00 00 10 6e 00 00 00 0e 5a 00 00 00 0c ......n....Z.... | 4080: 46 00 00 00 0a 32 00 00 00 08 1e 00 00 00 18 0a F....2.......... | page 4 offset 12288 | 0: 0d 00 00 00 01 0f f7 00 0f f7 00 00 00 00 00 00 ................ | 4080: 00 00 00 00 00 00 00 07 01 03 11 02 74 31 00 be ............t1.. | page 5 offset 16384 | 0: 0a 0f 7c 00 0a 0f 74 00 0f f9 0f eb 0f dd 0f cf ..|...t......... | 16: 0f c1 0f b3 0f a4 0f 94 0f 84 0f 74 0f 74 0f 74 ...........t.t.t | 32: 0f 74 0f 74 0f 74 0f 74 0f 74 0f 74 0f 74 00 00 .t.t.t.t.t.t.t.. | 3952: 00 00 00 00 07 05 00 00 00 02 00 be 0f 8c 00 08 ................ | 3968: 00 00 00 00 07 05 00 00 00 02 00 aa 0f 9c 00 08 ................ | 3984: 00 00 00 00 07 05 00 00 00 02 00 96 0f ac 00 08 ................ | 4000: 00 00 00 00 07 05 00 00 00 02 00 82 0f ba 00 07 ................ | 4016: 00 00 00 06 05 00 00 00 01 6e 0f c8 00 07 00 00 .........n...... | 4032: 00 06 05 00 00 00 01 5a 0f d6 00 07 00 00 00 06 .......Z........ | 4048: 05 00 00 00 01 46 0f e4 00 07 00 00 00 06 05 00 .....F.......... | 4064: 00 00 01 32 0f f2 00 07 00 00 00 06 05 00 00 00 ...2............ | 4080: 01 1e 00 00 00 07 00 00 00 06 05 00 00 00 01 0a ................ | page 6 offset 20480 | 0: 02 00 00 00 01 0e 0d 00 00 00 00 24 0e 0d 0c 1a ...........$.... | 16: 06 55 04 66 02 77 00 88 00 00 00 00 00 00 00 00 .U.f.w.......... | 128: 00 00 00 00 00 00 00 00 97 3d 04 ae 7c 01 00 00 .........=..|... | 624: 00 00 00 00 00 00 21 97 3d 04 ae 7c 01 00 00 00 ......!.=..|.... | 1120: 00 00 00 00 00 20 97 3d 04 ae 7c 01 00 00 00 00 ..... .=..|..... | 1616: 00 00 00 00 1f 97 3d 04 ae 7c 01 00 00 00 00 00 ......=..|...... | 2112: 00 00 00 1e 97 3d 04 ae 7c 01 00 00 00 00 00 00 .....=..|....... | 2608: 00 00 1d 97 3d 04 ae 7c 01 00 00 00 00 00 00 00 ....=..|........ | 3088: 00 00 00 00 00 00 00 00 00 00 00 00 01 f3 00 00 ................ | 3600: 23 97 3d 04 ae 7c 01 00 00 00 00 00 00 00 00 00 #.=..|.......... | 4080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 26 ...............& | page 8 offset 28672 | 0: 0d 00 00 00 01 04 30 00 04 30 00 00 00 00 00 00 ......0..0...... | 1072: 97 4d 1e 14 00 ae 7c 00 00 00 00 00 00 00 00 00 .M....|......... | 1088: 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 ................ | 4080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 03 ................ | page 10 offset 36864 | 256: 0d 00 00 00 01 04 30 00 04 30 00 00 00 00 00 00 ......0..0...... | 1072: 97 4d 32 14 00 ae 7c 00 00 00 00 00 00 00 00 00 .M2...|......... | 1088: 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 ................ | 4080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 05 ................ | page 12 offset 45056 | 0: 0d 00 00 00 01 04 30 00 04 30 00 00 00 00 00 00 ......0..0...... | 1072: 97 4d 46 14 00 ae 7c 00 00 00 00 00 00 00 00 00 .MF...|......... | 1088: 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 ................ | 4080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 07 ................ | page 14 offset 53248 | 0: 0d 00 00 00 01 04 30 00 04 30 00 00 00 00 00 00 ......0..0...... | 1072: 97 4d 5a 14 00 ae 7c 00 00 00 00 00 00 00 00 00 .MZ...|......... | 1088: 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 ................ | 4080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 09 ................ | page 16 offset 61440 | 0: 0d 00 00 00 01 04 30 00 04 30 00 00 00 00 00 00 ......0..0...... | 1072: 97 4d 6e 14 00 ae 7c 00 00 00 00 00 00 00 00 00 .Mn...|......... | 1088: 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 ................ | 4080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0b ................ | page 18 offset 69632 | 0: 0d 00 00 00 01 04 2f 00 04 2f 00 00 00 00 00 00 ....../../...... | 1056: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 97 ................ | 1072: 4d 81 02 14 00 ae 7c 00 00 00 00 00 00 00 00 00 M.....|......... | 1088: 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 ................ | 4080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0d ................ | page 20 offset 77824 | 0: 0d 00 00 00 01 04 2f 00 04 2f 00 00 00 00 00 00 ....../../...... | 1056: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 97 ................ | 1072: 4d 81 16 14 00 ae 7c 00 00 00 00 00 00 00 00 00 M.....|......... | 1088: 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 ................ | 4080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0f ................ | page 22 offset 86016 | 0: 0d 00 00 00 01 04 2f 00 04 2f 00 00 00 00 00 00 ....../../...... | 1056: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 97 ................ | 1072: 4d 81 2a 14 00 ae 7c 00 00 00 00 00 00 00 00 00 M.*...|......... | 1088: 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 ................ | 4080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 11 ................ | page 24 offset 94208 | 0: 0d 00 00 00 01 04 31 00 04 31 00 00 00 00 00 00 ......1..1...... | 1072: 00 97 4c 0a 14 00 ae 7c 00 00 00 00 00 00 00 00 ..L....|........ | 1088: 00 00 00 00 00 00 00 09 00 00 00 00 00 00 00 00 ................ | page 25 offset 98304 | 0: 0d 00 00 00 01 04 2f 00 04 2f 00 00 00 00 00 00 ....../../...... | 1056: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 97 ................ | 1072: 4d 81 3e 14 00 ae 7c 00 00 00 00 00 00 00 00 00 M.>...|......... | 1088: 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 ................ | 4080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 13 ................ | page 26 offset 102400 | 2512: 00 00 00 00 00 00 00 0a 00 00 00 00 00 00 00 00 ................ | page 27 offset 106496 | 0: 00 00 00 00 00 00 00 12 00 00 00 07 00 00 00 1d ................ | 16: 00 00 00 09 00 00 00 1f 00 00 00 0b 00 00 00 21 ...............! | 32: 00 00 00 0d 00 00 00 25 00 00 00 0f 00 00 00 19 .......%........ | 48: 00 00 00 11 00 00 00 29 00 00 00 13 00 00 00 2b .......).......+ | 64: 00 00 00 15 00 00 00 2d 00 00 00 2e 00 00 00 17 .......-........ | page 28 offset 110592 | 2512: 00 00 00 00 00 00 00 1e 00 00 00 00 00 00 00 00 ................ | page 30 offset 118784 | 2512: 00 00 00 00 00 00 00 32 00 00 00 00 00 00 00 00 .......2........ | page 32 offset 126976 | 2512: 00 00 00 00 00 00 00 46 00 00 00 00 00 00 00 00 .......F........ | page 34 offset 135168 | 2512: 00 00 00 00 00 00 00 5a 00 00 00 00 00 00 00 00 .......Z........ | page 35 offset 139264 | 0: 0a 08 44 00 05 02 77 00 0e 11 0a 33 06 55 02 77 ..D...w....3.U.w | 16: 04 66 00 88 00 88 00 88 00 00 00 00 00 00 00 00 .f.............. | 128: 00 00 00 00 00 00 00 00 04 66 01 ef 00 00 00 00 .........f...... | 624: 00 00 00 00 00 00 00 97 3d 04 ae 7c 01 00 00 00 ........=..|.... | 1120: 00 00 00 00 00 20 97 3d 04 ae 7c 01 00 00 00 00 ..... .=..|..... | 1616: 00 00 00 00 22 97 3d 04 ae 7c 01 00 00 00 00 00 ......=..|...... | 2112: 00 00 00 1e 0c 22 01 ef 00 00 00 00 00 00 00 00 ................ | 2608: 00 00 00 97 3d 04 ae 7c 01 00 00 00 00 00 00 00 ....=..|........ | 3104: 00 1c 00 00 01 ef 00 00 00 00 00 00 00 00 00 00 ................ | 3600: 00 97 3d 04 ae 7c 01 00 00 00 00 00 00 00 00 00 ..=..|.......... | 4080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 1a ................ | page 36 offset 143360 | 0: 0a 08 44 00 04 02 77 00 06 55 02 77 04 66 0e 11 ..D...w..U.w.f.. | 16: 00 88 00 88 00 88 0e 11 00 00 00 00 00 00 00 00 ................ | 128: 00 00 00 00 00 00 00 00 04 76 01 ef 00 00 00 00 .........v...... | 624: 00 00 00 00 00 00 00 97 3e 04 ae 7c 02 00 00 00 ........>..|.... | 1120: 00 00 00 00 00 2a 97 3e 04 ae 7c 02 00 00 00 00 .....*.>..|..... | 1616: 00 00 00 00 2c 97 3e 04 ae 7c 02 00 00 00 00 00 ....,.>..|...... | 2112: 00 00 00 28 00 00 05 cd 00 00 00 00 00 00 00 00 ...(............ | 3600: 00 97 3e 04 ae 7c 02 00 00 00 00 00 00 00 00 00 ..>..|.......... | 4080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 2f .............../ | page 38 offset 151552 | 2512: 00 00 00 00 00 00 00 6e 00 00 00 00 00 00 00 00 .......n........ | page 40 offset 159744 | 2512: 00 00 00 00 00 00 00 00 82 00 00 00 00 00 00 00 ................ | page 42 offset 167936 | 2512: 00 00 00 00 00 00 00 00 96 00 00 00 00 00 00 00 ................ | page 44 offset 176128 | 2512: 00 00 00 00 00 00 00 00 aa 00 00 00 00 00 00 00 ................ | page 47 offset 188416 | 2512: 00 00 00 00 00 00 00 00 be 00 00 00 00 00 00 00 ................ | end crash-9ae5502296c949.db }]} {} do_catchsql_test 5.1 { INSERT INTO t1(b) VALUES(zeroblob(40000)); } {1 {database disk image is malformed}} do_catchsql_test 5.2 { DROP INDEX t1x2; } {0 {}} do_catchsql_test 5.3 { INSERT INTO t1(b) VALUES(zeroblob(40000)); } {1 {database disk image is malformed}} #------------------------------------------------------------------------- reset_db do_test 6.0 { sqlite3 db {} db deserialize [decode_hexdb { | size 20480 pagesize 4096 filename crash-d260f001fa015c.db | page 1 offset 0 | 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3. | 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 05 .....@ ........ | 32: 00 00 00 00 00 ff ff f0 00 00 00 02 00 00 00 04 ................ | 48: 00 00 00 00 00 00 00 64 00 00 00 01 00 00 00 00 .......d........ | 96: 00 00 00 00 0d 0f f8 00 04 0e ce 00 0f 4c 0f d3 .............L.. | 112: 0e fa 0e ce 00 00 00 00 00 00 00 00 00 00 00 00 ................ | 3776: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 2a 04 ..............*. | 3792: 06 17 13 11 01 3f 69 6e 64 65 78 74 31 62 74 31 .....?indext1bt1 | 3808: 05 43 52 45 41 54 45 20 49 4e 44 45 58 20 74 31 .CREATE INDEX t1 | 3824: 62 20 4f 4e 20 74 31 28 62 29 50 03 06 17 2b 2b b ON t1(b)P...++ | 3840: 01 59 74 61 62 6c 65 73 71 6c 69 74 65 5f 73 65 .Ytablesqlite_se | 3856: 71 75 65 6e 63 65 73 71 6c 69 74 65 5f 73 65 71 quencesqlite_seq | 3872: 75 65 6e 63 65 04 43 52 45 41 54 45 20 54 41 42 uence.CREATE TAB | 3888: 4c 45 20 73 71 6c 69 74 65 5f 73 65 71 75 65 6e LE sqlite_sequen | 3904: 63 65 28 6e 61 6d 65 2c 73 65 71 29 81 04 01 07 ce(name,seq).... | 3920: 17 11 11 01 81 73 74 61 62 6c 65 74 31 74 31 02 .....stablet1t1. | 3936: 43 52 45 41 54 45 20 54 41 42 4c 45 20 74 31 28 CREATE TABLE t1( | 3952: 61 20 52 45 41 4c 20 4e 4f 54 20 4e 55 4c 4c 20 a REAL NOT NULL | 3968: 44 45 46 41 55 4c 54 28 32 35 2b 33 32 29 2c 62 DEFAULT(25+32),b | 3984: 20 46 4c 4f 41 54 2c 63 20 44 4f 55 42 4c 45 20 FLOAT,c DOUBLE | 4000: 55 4e 49 51 55 45 2c 0a 64 20 43 4c 4f 42 2c 65 UNIQUE,.d CLOB,e | 4016: 20 49 4e 54 45 47 45 52 20 50 52 49 4d 41 52 59 INTEGER PRIMARY | 4032: 20 4b 45 59 20 41 55 54 4f 49 4e 43 52 45 4d 45 KEY AUTOINCREME | 4048: 4e 54 29 23 02 06 17 37 11 01 00 69 6e 64 65 78 NT)#...7...index | 4064: 73 71 6c 69 74 65 5f 61 75 74 6f 69 6e 64 65 78 sqlite_autoindex | 4080: 5f 74 31 5f 31 74 31 05 00 00 00 08 00 00 00 00 _t1_1t1......... | page 2 offset 4096 | 0: 0d 00 00 00 00 10 00 00 00 00 00 00 00 00 00 00 ................ | page 3 offset 8192 | 0: 0a 00 00 00 00 10 00 00 00 00 00 00 00 00 00 00 ................ | page 4 offset 12288 | 0: 0d 00 00 00 00 10 00 00 00 00 00 00 00 00 00 00 ................ | page 5 offset 16384 | 0: 0a 00 00 00 00 10 00 00 00 00 00 00 00 00 00 00 ................ | end crash-d260f001fa015c.db }]} {} do_catchsql_test 6.1 { BEGIN; INSERT INTO t1(b) VALUES(1); INSERT INTO t1(b) VALUES(2); COMMIT; } {1 {malformed database schema (t1b) - invalid rootpage}} #------------------------------------------------------------------------- reset_db do_test 7.0 { sqlite3 db {} db deserialize [decode_hexdb { | size 20480 pagesize 4096 filename crash-8391315d75edff.db | page 1 offset 0 | 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3. | 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 05 .....@ ........ | 32: 00 00 00 00 00 00 00 00 00 00 00 05 00 00 00 04 ................ | 48: 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 ................ | 96: 00 00 00 00 0d 00 00 00 05 0e 55 00 0f 74 0f 3c ..........U..t.< | 112: 0e f9 0e d1 0e 55 00 00 00 00 00 00 00 00 00 00 .....U.......... | 3664: 00 00 00 00 00 7a 05 07 15 11 11 08 81 63 76 69 .....z.......cvi | 3680: 65 77 76 31 76 31 43 52 45 41 54 45 20 56 49 45 ewv1v1CREATE VIE | 3696: 57 20 76 31 28 78 2c 69 29 20 41 53 0a 53 45 4c W v1(x,i) AS.SEL | 3712: 45 43 54 20 74 31 2e 62 2c 74 32 2e 62 20 46 52 ECT t1.b,t2.b FR | 3728: 4f 4d 20 74 31 2c 74 32 20 57 48 45 52 45 20 74 OM t1,t2 WHERE t | 3744: 31 2e 61 3d 74 32 2e 61 20 47 52 4f 55 50 20 42 1.a=t2.a GROUP B | 3760: 59 20 31 20 48 41 56 49 4e 47 20 74 32 2e 63 20 Y 1 HAVING t2.c | 3776: 4e 4f 54 20 4e 55 4c 4c 0a 4c 49 4d 49 54 20 31 NOT NULL.LIMIT 1 | 3792: 30 26 04 06 17 11 11 01 39 74 61 62 6c 65 74 32 0&......9tablet2 | 3808: 74 32 05 43 52 45 41 54 45 20 54 41 42 4c 45 20 t2.CREATE TABLE | 3824: 74 32 28 61 2c 62 2c 63 29 41 03 06 17 15 11 01 t2(a,b,c)A...... | 3840: 6b 69 6e 64 65 78 74 31 78 31 74 31 03 43 52 45 kindext1x1t1.CRE | 3856: 41 54 45 20 49 4e 44 45 58 20 74 31 78 31 20 4f ATE INDEX t1x1 O | 3872: 4e 20 74 31 28 64 29 20 57 48 45 52 45 20 65 65 N t1(d) WHERE ee | 3888: 20 49 53 20 4e 4f 54 20 4e 55 4c 4c 36 02 06 17 IS NOT NULL6... | 3904: 17 11 01 53 69 6e 64 65 78 74 31 61 62 63 74 31 ...Sindext1abct1 | 3920: 03 43 52 45 41 54 45 20 49 4e 44 45 58 20 74 31 .CREATE INDEX t1 | 3936: 61 62 63 20 4f 4e 20 74 31 28 61 2c 62 2c 63 2b abc ON t1(a,b,c+ | 3952: 64 2b 65 29 81 09 01 07 17 11 11 01 81 7d 74 61 d+e)..........ta | 3968: 62 6c 65 74 31 74 31 02 43 52 45 41 54 45 20 54 blet1t1.CREATE T | 3984: 41 42 4c 45 20 74 31 28 61 2c 62 2c 63 2c 64 2c ABLE t1(a,b,c,d, | 4000: 65 2c 66 2c 67 2c 68 2c 6a 2c 6a 6a 2c 6a 6a 6a e,f,g,h,j,jj,jjj | 4016: 2c 6b 2c 61 61 2c 62 69 8c 63 63 2c 64 64 2c 65 ,k,aa,bi.cc,dd,e | 4032: 65 20 44 45 46 41 55 4c 54 20 33 2e 31 34 2c 0a e DEFAULT 3.14,. | 4048: 66 66 20 44 45 46 41 55 4c 54 28 27 68 69 63 63 ff DEFAULT('hicc | 4064: 75 70 27 29 2c 67 67 20 4e 4f 54 20 4e 55 4c 4c up'),gg NOT NULL | 4080: 20 44 45 46 41 55 4c 54 28 66 61 6c 73 65 29 29 DEFAULT(false)) | page 2 offset 4096 | 0: 0d 00 00 00 0a 0e 7b 00 0f dc 0f b6 0f 8f 0f 68 ...............h | 16: 0f 41 0f 1a 0e f3 0e cb 0e a3 0e 22 00 00 00 00 .A.............. | 3696: 00 00 00 00 00 00 00 00 00 00 00 26 0a 14 01 01 ...........&.... | 3712: 02 08 00 00 00 00 00 00 00 00 00 00 00 00 07 19 ................ | 3728: 08 09 5a 00 b4 40 09 1e b8 51 eb 95 1f 68 69 63 ..Z..@...Q...hic | 3744: 63 75 70 26 09 14 01 01 02 08 00 00 00 00 00 00 cup&............ | 3760: 00 00 00 00 00 00 07 19 08 08 50 00 a0 40 09 1e ..........P..@.. | 3776: b8 51 eb 85 1f 68 69 63 63 74 70 26 08 14 01 01 .Q...hicctp&.... | 3792: 03 08 00 00 00 00 00 00 00 00 00 00 00 00 07 19 ................ | 3808: 08 07 46 00 8c 40 09 1e b8 51 eb 85 1f 68 69 63 ..F..@...Q...hic | 3824: 63 75 70 25 07 14 01 01 01 08 00 00 00 00 00 00 cup%............ | 3840: 00 00 00 00 00 10 07 19 08 06 3c 78 40 09 1e b8 ..........<x@... | 3856: 51 eb 85 1f 68 69 63 63 75 70 25 06 14 01 01 01 Q...hiccup%..... | 3872: 08 00 00 00 00 00 00 00 00 00 00 00 00 07 19 08 ................ | 3888: 05 32 64 40 09 1e b8 51 eb 85 1f 68 69 63 63 75 .2d@...Q...hiccu | 3904: 70 25 05 14 01 01 01 08 00 00 00 00 00 00 00 00 p%.............. | 3920: 00 00 00 00 07 19 08 04 28 50 40 09 1e b8 51 eb ........(P@...Q. | 3936: 85 1f 68 69 63 63 75 70 25 04 14 01 00 f1 08 00 ..hiccup%....... | 3952: 00 00 00 00 00 00 00 00 00 00 00 07 19 08 03 1e ................ | 3968: 3c 40 09 1e b8 51 eb 85 1f 68 69 63 63 75 70 25 <@...Q...hiccup% | 3984: 03 14 01 01 01 08 00 00 00 00 00 00 00 00 00 00 ................ | 4000: 00 00 07 19 08 02 14 28 40 09 1e b8 51 eb 85 1f .......(@...Q... | 4016: 68 69 63 63 75 70 24 02 14 09 01 01 08 00 00 00 hiccup$......... | 4032: 00 00 00 00 00 00 00 00 00 07 19 08 0a 14 40 09 ..............@. | 4048: 1e b8 51 eb 85 1f 68 69 63 63 75 70 22 01 14 08 ..Q...hiccup.... | 4064: 08 08 08 00 00 00 00 00 00 00 00 00 00 00 00 07 ................ | 4080: 19 08 40 09 1e b8 51 eb 85 1f 68 69 63 63 75 70 ..@...Q...hiccup | page 3 offset 8192 | 0: 0a 00 00 00 0a 0f aa 00 0f fa 0f f2 0f e9 0f e0 ................ | 16: 0f d7 0f ce 0f c5 0f bc 0f b3 0f aa 00 00 00 00 ................ | 4000: 00 00 00 00 00 00 00 00 00 00 08 05 01 01 00 01 ................ | 4016: 09 5a 0a d8 05 01 01 00 01 08 50 09 08 05 01 01 .Z........P..... | 4032: 00 01 07 46 08 08 05 01 01 00 01 06 3c 07 08 05 ...F........<... | 4048: 01 01 00 01 05 32 06 08 05 01 01 00 01 04 28 05 .....2........(. | 4064: 08 05 01 02 60 01 03 1e 04 08 05 01 01 00 01 02 ....`........... | 4080: 14 03 07 05 09 01 00 01 0a 02 05 05 08 08 00 09 ................ | page 4 offset 12288 | 0: 0a 00 00 00 0a 0f cf 00 0f fc 0f f7 0f f2 0f ed ................ | 16: 0f e8 0f e3 0f de 0f d9 0f d4 0f cf 00 00 00 00 ................ | 4032: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 04 ................ | 4048: 03 08 01 0a 04 03 08 01 09 04 03 08 01 08 04 03 ................ | 4064: 08 01 07 04 03 08 01 06 04 03 08 01 05 04 03 08 ................ | 4080: 01 04 04 03 08 01 03 04 03 08 01 02 03 03 08 09 ................ | page 5 offset 16384 | 0: 0d 00 00 00 00 10 00 00 00 00 00 00 00 00 00 00 ................ | end crash-8391315d75edff.db }]} {} do_catchsql_test 7.1 { SELECT * FROM sqlite_master; } {1 {malformed database schema (t1x1) - invalid rootpage}} #------------------------------------------------------------------------- reset_db do_test 8.0 { sqlite3 db {} db deserialize [decode_hexdb { | size 2048 pagesize 512 filename a.db | page 1 offset 0 | 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3. | 16: 02 00 01 01 00 40 20 20 ff ff 00 0c 00 00 00 07 .....@ ........ | 32: 0b 00 00 00 00 00 00 00 00 00 00 08 9c 00 00 04 ................ | 48: 00 00 00 e0 09 00 00 01 00 00 00 01 00 00 00 00 ................ | 64: 00 00 00 00 f2 ff 00 00 00 00 00 00 00 00 00 00 ................ | 80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0c ................ | 96: 00 2e 2c 50 0d 00 00 00 06 01 06 00 01 da 01 b0 ..,P............ | 112: 05 56 01 86 01 2a 01 06 00 00 00 00 00 06 00 00 .V...*.......... | 128: 00 ff 00 00 ff ff ff e1 00 00 00 00 00 00 00 00 ................ | 144: 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 ................ | 160: 00 00 00 00 00 00 00 00 f2 00 00 00 00 00 00 00 ................ | 176: 00 00 f9 ff ff ff ff ff ff ff 00 00 00 5f 00 fb ............._.. | 192: 00 00 00 00 00 00 00 00 00 e1 ff 00 00 00 00 00 ................ | 208: 00 00 10 00 00 00 00 00 1e 00 00 00 fe 00 00 00 ................ | 224: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ca 00 ................ | 240: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 35 ...............5 | 256: 00 00 00 00 ef ff 22 07 06 17 11 11 01 30 39 38 .............098 | 272: 62 6c 65 74 38 38 74 04 43 52 45 41 54 45 20 54 blet88t.CREATE T | 288: 41 42 4c 45 20 74 34 28 87 29 2a 06 06 17 13 11 ABLE t4(.)*..... | 304: 01 3f 69 4f 64 65 78 74 33 78 74 40 05 43 52 45 .?iOdext3xt@.CRE | 320: 41 54 45 20 49 6e 44 45 58 20 74 33 78 20 4f 4e ATE InDEX t3x ON | 336: 20 74 33 28 78 29 2e 04 06 17 15 11 01 45 69 6e t3(x).......Ein | 352: 00 04 00 00 34 63 64 74 3d 05 43 52 45 41 54 45 ....4cdt=.CREATE | 368: 20 49 4e 44 45 58 20 63 74 64 32 20 4f 4e 20 74 INDEX ctd2 ON t | 384: 32 28 0a 0c 44 29 28 05 06 17 11 11 01 3d 74 6c 2(..D)(......=tl | 400: 62 61 d4 65 33 74 33 04 43 52 45 41 54 45 20 54 ba.e3t3.CREATE T | 416: 41 42 4c 45 20 74 33 28 63 2c 78 2c 65 2c 66 29 ABLE t3(c,x,e,f) | 432: 28 02 06 17 11 11 01 3d 74 61 62 6c 65 74 32 74 (......=tablet2t | 448: 32 03 43 52 45 41 54 45 20 54 41 42 4c 45 20 74 2.CREATE TABLE t | 464: 32 28 63 2c 64 2c 65 2c 66 29 24 01 06 17 11 11 2(c,d,e,f)$..... | 480: 01 35 74 60 62 6c 65 74 31 74 31 02 43 52 45 41 .5t`blet1t1.CREA | 496: 54 45 20 54 41 42 4c 45 20 74 30 28 61 2c 62 29 TE TABLE t0(a,b) | page 2 offset 512 | 0: 0d 00 ff 11 04 01 cf 80 01 fa 01 09 00 de 01 cf ................ | 16: 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 ................ | 32: 00 00 08 00 00 00 00 00 00 11 00 00 00 00 00 13 ................ | 48: 00 00 00 00 00 00 00 00 00 00 00 01 00 e0 ff ff ................ | 64: ff d2 ff ff ff 00 f8 ff ff ff 00 00 00 00 00 00 ................ | 80: 00 ff ff 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ | 96: 00 00 00 00 ff de 00 00 00 00 00 00 00 00 00 00 ................ | 112: 00 00 00 00 00 00 00 00 00 00 00 00 00 40 00 00 .............@.. | 128: 2a 00 00 00 00 00 00 00 00 f7 00 00 00 00 00 00 *............... | 144: 00 00 00 00 00 21 00 00 00 00 00 00 00 00 00 00 .....!.......... | 160: 01 64 00 00 00 00 04 80 ff ff ff 00 00 00 00 00 .d.............. | 176: 00 00 00 00 00 00 00 00 1f 00 00 00 00 00 00 00 ................ | 192: 00 00 40 00 00 00 00 00 00 00 00 00 00 00 00 00 ..@............. | 208: b5 00 00 00 00 00 00 40 00 00 00 00 00 00 00 00 .......@........ | 224: 00 00 00 f6 00 ee ff ff ff 00 00 00 00 00 00 00 ................ | 272: f2 00 00 00 00 00 00 00 00 00 f9 ff ff ff ff ff ................ | 288: ff ff 00 00 00 5f 00 fb 00 00 00 00 00 00 00 00 ....._.......... | 320: 1e 00 00 00 fe 00 00 00 00 00 00 00 00 00 00 00 ................ | 336: 00 00 00 00 00 00 ca 00 00 00 00 00 00 00 ff ec ................ | 352: 00 00 00 00 00 00 00 32 00 00 00 00 ef ff 22 07 .......2........ | 368: 06 17 11 11 01 30 74 61 62 6c 65 74 38 38 74 04 .....0tablet88t. | 384: 43 52 45 41 54 45 20 54 41 42 4c 45 20 8c cb d7 CREATE TABLE ... | 400: 78 d6 d5 f9 f9 17 13 11 01 3f 69 4f 64 65 78 74 x........?iOdext | 416: 33 78 74 33 05 43 52 45 41 54 45 26 49 6e 44 45 3xt3.CREATE&InDE | 432: 58 20 74 33 78 00 00 00 00 00 00 00 00 00 00 00 X t3x........... | 464: 00 00 00 00 00 13 76 65 6e 65 69 67 68 74 13 03 ......veneight.. | 480: 03 40 07 07 15 00 54 45 20 49 4e 44 45 58 20 74 .@....TE INDEX t | 496: 31 63 64 20 4f 4e 20 74 ce d7 f5 f0 44 09 01 02 1cd ON t....D... | page 3 offset 1024 | 0: 0d 00 00 00 48 01 54 00 01 f6 e2 ec 01 c5 01 aa ....H.T......... | 16: 30 34 28 87 29 32 06 f5 16 13 11 01 8e 61 24 64 04(.)2.......a$d | 32: 65 78 74 37 78 1f 33 6d 6d 6d 6d 6d 00 00 04 06 ext7x.3mmmmm.... | 48: 6d 41 6d 6d 6e 6d 6d 00 00 02 00 6d 6d 6d 6d 6d mAmmnmm....mmmmm | 64: 15 11 01 45 45 45 45 45 45 45 45 45 45 45 45 45 ...EEEEEEEEEEEEE | 80: 45 45 45 45 45 45 45 45 45 45 45 00 45 63 74 64 EEEEEEEEEEE.Ectd | 96: 34 20 4f 4e 20 61 62 6c 5d 74 38 38 74 04 43 52 4 ON abl]t88t.CR | 112: 45 41 54 45 20 54 41 42 4c 45 20 74 34 28 87 29 EATE TABLE t4(.) | 128: 2a 06 06 13 13 01 00 00 00 4f 64 6e 78 74 33 44 *........Odnxt3D | 144: 74 13 05 43 52 45 41 54 45 20 49 6e 44 45 00 00 t..CREATE InDE.. | 160: 00 00 00 00 00 00 00 f9 ff ff ff ff ff ff ff 00 ................ | 176: 00 00 5f 00 fb 00 00 2d 00 00 00 00 00 00 00 00 .._....-........ | 192: 00 00 00 00 00 00 00 00 00 00 00 00 00 1e 00 00 ................ | 208: 00 fe 00 00 00 00 17 15 11 01 45 69 6e 64 65 2e ..........Einde. | 224: 5b 38 63 64 74 3d 05 43 52 45 41 54 45 20 49 4e [8cdt=.CREATE IN | 240: 44 45 58 20 63 20 64 32 20 4f 4e 20 74 32 28 0a DEX c d2 ON t2(. | 256: 0c 44 32 05 00 10 00 00 11 11 3d 74 6c 62 61 d4 .D2.......=tlba. | 272: 65 33 74 33 04 43 52 45 41 54 45 20 54 41 42 4c e3t3.CREATE TABL | 288: 45 20 74 36 ff ff 7f ff 43 52 45 41 54 45 20 49 E t6....CREATE I | 304: 73 71 6c 69 74 65 5f 73 65 71 75 65 6e 63 65 28 sqlite_sequence( | 320: 0a 0c 44 29 28 05 06 17 11 11 01 3d 74 6c 62 61 ..D)(......=tlba | 336: 20 00 00 00 33 04 43 52 45 41 54 45 20 54 41 42 ...3.CREATE TAB | 352: 4c 45 20 74 33 28 63 2c 78 2c 65 2c 66 29 28 02 LE t3(c,x,e,f)(. | 368: 06 00 00 7f ff 40 41 54 45 20 49 6e 44 45 58 20 .....@ATE InDEX | 384: 74 33 78 20 4f 4e 20 74 31 28 78 29 2e 04 06 17 t3x ON t1(x).... | 400: 15 11 01 45 69 6e 64 65 2e 74 34 63 64 74 3d 05 ...Einde.t4cdt=. | 416: 00 00 00 00 00 00 00 00 00 00 00 4d 00 00 00 00 ...........M.... | 432: 01 00 00 00 00 00 00 05 00 00 10 00 00 00 00 00 ................ | 448: 00 01 00 00 00 00 01 00 00 00 00 07 40 14 00 00 ............@... | 464: 00 00 21 00 40 18 00 00 00 00 00 00 40 1c 00 00 ..!.@.......@... | 480: 00 00 ff ff ff 00 00 00 5f 00 fb 00 00 2d 00 00 ........_....-.. | 496: 00 00 00 1e 00 00 00 fe 00 00 64 00 00 ff fb 02 ..........d..... | page 4 offset 1536 | 0: 0d 00 39 00 00 02 00 00 00 00 00 00 00 00 00 00 ..9............. | end a.db }]} {} set res {1 {database disk image is malformed}} ifcapable oversize_cell_check { set res {1 {no such table: t3}} } do_catchsql_test 8.1 { PRAGMA writable_schema=ON; -- bypass improved sqlite_master consistency checking INSERT INTO t3 SELECT * FROM t2; } $res #------------------------------------------------------------------------- reset_db do_test 9.0 { sqlite3 db {} db deserialize [decode_hexdb { | size 8192 pagesize 4096 filename crash-ab10597e4e1c32.db | page 1 offset 0 | 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3. | 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 00 .....@ ........ | 96: 00 00 00 00 0d 00 00 00 01 0f d6 00 0f d6 00 00 ................ | 4048: 00 00 00 00 00 00 28 01 06 17 11 11 01 3d 74 61 ......(......=ta | 4064: 62 6c 65 74 31 74 31 02 43 52 45 41 54 45 20 54 blet1t1.CREATE T | 4080: 41 42 4c 45 20 74 31 28 61 2c 62 2c 63 2c 64 29 ABLE t1(a,b,c,d) | page 2 offset 4096 | 0: 0d 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ | end crash-ab10597e4e1c32.db }]} {} do_execsql_test 9.1 { SAVEPOINT one; } do_catchsql_test 9.3 { INSERT INTO t1(b,c) VALUES(5,6); } {1 {database disk image is malformed}} do_execsql_test 9.3 { ROLLBACK TO one; } #------------------------------------------------------------------------- reset_db do_test 10.0 { sqlite3 db {} db deserialize [decode_hexdb { | size 180224 pagesize 4096 filename crash-41390d95d613b6.db | page 1 offset 0 | 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3. | 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 00 .....@ ........ | 96: 00 00 00 00 0d 00 00 00 04 0e e2 00 0f 96 0f 44 ...............D | 112: 0f 10 0e e2 00 00 00 00 00 00 00 00 00 00 00 00 ................ | 3808: 00 00 2c 14 06 17 15 11 01 41 69 6e 64 65 78 74 ..,......Aindext | 3824: 41 78 33 74 31 06 43 52 45 41 54 45 20 49 4e 44 Ax3t1.CREATE IND | 3840: 45 58 20 74 31 78 32 20 4f 4e 20 74 31 28 62 29 EX t1x2 ON t1(b) | 3856: 32 03 06 17 15 11 01 4d 69 6e 64 65 78 74 31 88 2......Mindext1. | 3872: 31 74 31 05 43 52 45 41 54 45 20 49 4e 44 45 58 1t1.CREATE INDEX | 3888: 20 74 31 78 31 20 4f 4e 20 74 31 28 67 2b 68 2c t1x1 ON t1(g+h, | 3904: 6a 2d 6b 29 50 02 06 17 2b 2b 01 59 74 61 62 6c j-k)P...++.Ytabl | 3920: 65 73 71 6c 69 74 65 5e 73 65 71 74 65 6e 63 65 esqlite^seqtence | 3936: 73 71 6c 69 74 65 5f 73 65 71 75 65 6e 63 65 04 sqlite_sequence. | 3952: 43 52 45 41 54 45 20 54 41 42 4c 45 20 73 71 6c CREATE TABLE sql | 3968: 69 74 65 5f 73 65 71 75 65 6e 63 65 28 6e 61 6d ite_sequence(nam | 3984: 65 2c 73 65 71 29 68 00 07 17 11 11 01 81 3b 74 e,seq)h.......;t | 4000: 61 62 6c 65 74 31 74 31 03 43 52 45 41 54 45 20 ablet1t1.CREATE | 4016: 54 41 42 4c 45 20 74 31 28 61 20 49 4e 54 45 47 TABLE t1(a INTEG | 4032: 45 52 20 50 52 49 4d 41 52 59 20 4b 45 59 20 41 ER PRIMARY KEY A | 4048: 55 54 4f 49 4e 43 52 45 4d 45 4e 54 2c 0a 62 2c UTOINCREMENT,.b, | 4064: 63 2c 64 2c 65 2c 66 2c 67 2c 68 2c 6a 2c 6b 2c c,d,e,f,g,h,j,k, | 4080: 6c 2c 6d 2c 6e 2c 6f 2c 70 2c 71 2c 72 2c 73 29 l,m,n,o,p,q,r,s) | page 2 offset 4096 | 0: 01 00 00 00 00 01 00 00 10 00 01 00 00 00 00 01 ................ | 16: 00 00 00 00 02 00 0f f0 00 15 00 00 00 03 02 00 ................ | 32: 00 00 d9 05 00 00 00 03 02 00 00 00 00 05 00 00 ................ | 48: 10 03 02 00 00 00 00 05 00 00 00 03 02 00 00 00 ................ | 64: 00 05 00 00 00 02 62 00 00 00 00 05 00 00 00 03 ......b......... | 80: 02 00 00 00 00 05 00 00 00 03 02 00 00 00 00 05 ................ | 96: 00 00 00 03 02 00 00 00 00 05 00 00 00 03 05 00 ................ | 112: 00 00 03 03 01 00 00 23 02 00 00 4f 00 02 00 00 .......#...O.... | 128: 10 25 02 00 00 00 00 03 00 00 00 23 02 00 00 00 .%.........#.... | 144: 00 03 00 00 00 23 02 00 00 00 00 03 00 00 00 23 .....#.........# | 160: 05 00 08 90 06 05 00 00 00 06 01 ff 00 00 00 03 ................ | 176: 00 00 00 06 02 00 00 00 00 02 ff 00 00 00 00 00 ................ | page 3 offset 8192 | 0: 05 00 00 00 09 0f d0 00 00 00 00 19 0f fb 0f f6 ................ | 16: 0f f1 10 ec ec e7 0f e2 0f dc 0f d6 0f 00 00 00 ................ | 1072: 00 97 4c 0a 24 00 ae 00 00 00 00 00 00 00 00 00 ..L.$........... | 4048: 00 00 00 16 83 39 ff ff ff 14 81 16 00 00 00 12 .....9.......... | 4064: 81 02 00 00 00 10 6e 00 00 00 0e 5a 00 00 00 0c ......n....Z.... | 4080: 46 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 F............... | page 4 offset 12288 | 1072: 97 4d 32 14 00 ae 00 00 00 00 00 00 00 00 00 00 .M2............. | 4080: 00 00 00 00 00 00 00 07 01 03 11 02 74 31 00 bd ............t1.. | page 5 offset 16384 | 0: fa 0f 7c 00 0a 0f 74 00 0f f9 0f eb 0f dd 0f cf ..|...t......... | 16: 0f c1 0f b3 0f a4 0e 94 0f 84 0f 74 0f 74 0f 74 ...........t.t.t | 32: 0f 74 0f 64 0f 00 00 00 00 00 00 00 00 00 00 00 .t.d............ | 3952: 00 00 00 00 07 05 00 00 00 02 00 be 0f 8c 10 07 ................ | 3968: ff ff 00 00 07 05 00 00 00 02 00 aa 0f 9b f0 08 ................ | 3984: c8 00 00 00 37 06 00 00 00 01 00 96 0f ac 00 08 ....7........... | 4000: 00 00 00 b3 07 15 00 10 00 02 00 82 0f ba 00 07 ................ | 4016: 00 00 00 06 05 00 00 00 01 6e 0f c8 00 07 00 00 .........n...... | 4032: 00 06 05 00 00 00 01 5a 03 f6 00 07 00 00 00 06 .......Z........ | 4048: 05 00 00 00 01 46 0f e4 00 07 00 00 10 06 05 00 .....F.......... | 4064: 00 00 01 32 10 02 00 07 00 00 00 07 05 00 00 00 ...2............ | 4080: 01 1d ff ff ff 07 10 00 00 06 05 00 00 00 01 0a ................ | page 6 offset 20480 | 624: 00 00 00 00 00 21 97 00 00 00 00 00 00 00 00 00 .....!.......... | 1120: 00 00 00 00 00 24 57 3e 00 00 00 00 00 00 00 00 .....$W>........ | 1616: 00 00 00 00 1f 97 00 00 00 00 00 00 00 00 00 00 ................ | 2112: 00 00 00 1e 97 3d 00 00 00 00 00 00 00 00 00 00 .....=.......... | 2608: 00 1d 97 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ | page 8 offset 28672 | 1184: 00 00 00 00 00 00 00 00 00 97 4d 1e 13 ff ae 7c ..........M....| | 4080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 90 ................ | page 9 offset 32768 | 256: 0d 01 c0 00 01 04 30 00 04 30 00 00 00 00 00 00 ......0..0...... | page 10 offset 36864 | 0: 0d 00 22 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ | 4080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 05 ................ | page 12 offset 45056 | 0: 0d 00 00 00 01 04 30 00 00 00 00 00 00 00 00 00 ......0......... | page 14 offset 53248 | 0: 0d 00 00 00 01 04 30 00 04 30 00 00 00 00 00 00 ......0..0...... | 1072: 96 4d 5a 14 00 00 00 00 00 00 00 00 00 00 00 00 .MZ............. | page 16 offset 61440 | 0: 0d 00 00 00 01 04 30 00 04 30 00 00 00 00 00 00 ......0..0...... | 1072: 97 4d 6e 14 00 ae 7b ff ff ff ff 00 00 00 00 00 .Mn............. | page 18 offset 69632 | 1056: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 97 ................ | 1072: 4d 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 M............... | 4080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0d ................ | page 20 offset 77824 | 1056: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 97 ................ | 1072: 4d 81 16 14 00 ae 00 00 00 00 00 00 00 00 00 00 M............... | 4080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0f ................ | page 22 offset 86016 | 0: 0d 00 00 00 01 04 2f 00 04 2f 01 00 00 00 00 00 ....../../...... | 1056: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 97 ................ | 1072: 4d 81 2a 14 00 00 00 00 00 00 00 00 00 00 00 00 M.*............. | page 24 offset 94208 | 1072: 00 97 4c 0a 14 00 ae 7c 00 00 00 00 00 00 00 00 ..L....|........ | page 25 offset 98304 | 1056: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 97 ................ | 1072: 4d 81 3e 14 00 ae 7c 00 00 18 ff 00 00 00 00 00 M.>...|......... | page 27 offset 106496 | 0: 00 00 00 00 00 00 00 12 00 00 00 07 00 00 00 1d ................ | 16: 00 00 00 09 00 00 00 1f 00 00 00 0b 00 00 00 21 ...............! | 32: 00 00 00 0d 00 10 00 25 00 00 00 0f 00 00 00 27 .......%.......' | 48: 00 00 00 11 00 00 00 00 00 00 00 00 00 00 00 00 ................ | page 32 offset 126976 | 2512: 00 00 00 00 00 00 00 45 21 00 00 00 00 00 00 00 .......E!....... | page 35 offset 139264 | 0: 00 0a 08 44 00 05 02 77 00 0e 11 0a 92 00 00 00 ...D...w........ | 1120: 00 00 00 00 00 20 97 00 00 00 00 00 00 00 00 00 ..... .......... | 1616: 00 00 00 00 22 00 00 00 00 00 00 00 00 00 00 00 ................ | 2608: 00 00 00 97 3d 04 00 00 00 00 00 00 00 00 00 00 ....=........... | 3104: 00 1c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ | 3600: 00 97 3d 04 ae 7c 00 00 00 00 00 00 00 00 00 00 ..=..|.......... | 4080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 1a ................ | page 36 offset 143360 | 0: 0a 08 44 00 04 02 00 00 00 00 00 00 00 00 00 00 ..D............. | 1120: 00 00 00 00 00 2a 97 3e 04 00 00 00 00 00 00 00 .....*.>........ | 1616: 00 00 00 00 2c 97 3e 00 00 00 00 00 00 00 00 00 ....,.>......... | 2112: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 38 ...............8 | 2128: 00 00 05 cd 00 00 00 00 00 00 00 00 00 00 00 00 ................ | 3600: 00 97 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ | page 38 offset 151552 | 2464: 00 00 00 00 00 00 00 00 00 6e 00 00 00 00 00 00 .........n...... | page 40 offset 159744 | 2512: 00 00 00 00 00 00 00 00 82 00 00 00 00 00 00 00 ................ | page 42 offset 167936 | 2512: 00 00 00 00 00 00 00 96 00 00 00 00 00 00 00 00 ................ | page 44 offset 176128 | 2512: 00 00 00 00 00 00 00 00 aa 00 00 00 00 00 00 00 ................ | end crash-41390d95d613b6.db }]} {} do_catchsql_test 10.1 { PRAGMA writable_schema=ON; -- bypass improved sqlite_master consistency checking SELECT * FROM t1 WHERE a<='2019-05-09' ORDER BY a DESC; } {1 {database disk image is malformed}} #------------------------------------------------------------------------- reset_db do_test 11.0 { sqlite3 db {} db deserialize [decode_hexdb { | size 595 pagesize 512 filename x.db | page 1 offset 0 | 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3. | 16: 02 00 00 01 00 40 20 20 00 01 00 0c 00 00 00 07 .....@ ........ | 32: 00 00 00 05 07 a1 1f fa 00 00 00 08 00 00 00 04 ................ | 48: 00 00 01 00 00 49 00 00 00 00 00 05 00 00 00 00 .....I.......... | 80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 1c ................ | 96: 00 2e 2c 50 0d 00 00 00 06 01 06 00 01 da 01 b0 ..,P............ | 112: 01 56 01 86 01 2a 01 06 00 00 62 00 00 00 00 00 .V...*....b..... | 128: 00 ed e2 78 74 64 33 ff 43 52 45 41 54 45 20 49 ...xtd3.CREATE I | 144: 4e 44 45 58 20 74 33 78 20 4f 4e 20 74 33 28 38 NDEX t3x ON t3(8 | 160: 29 2e 04 06 17 15 11 01 45 69 6e 64 65 68 74 32 ).......Eindeht2 | 176: 63 64 74 31 e5 43 52 45 41 54 45 20 49 4e 44 45 cdt1.CREATE INDE | 192: 58 20 74 32 63 c4 20 4f 4e 20 74 32 28 63 2c 64 X t2c. ON t2(c,d | 208: 29 28 05 06 17 01 11 11 3d 74 61 6c 36 74 62 74 )(......=tal6tbt | 224: 65 32 04 43 52 45 41 54 45 20 54 41 42 4c 45 20 e2.CREATE TABLE | 240: 74 00 04 00 00 00 00 00 00 00 00 00 00 00 00 00 t............... | 256: 00 00 00 00 00 00 22 07 06 17 11 11 01 30 e8 03 .............0.. | 272: 62 6c 65 74 34 74 35 02 43 52 45 41 54 45 20 54 blet4t5.CREATE T | 288: 41 42 4c 45 20 74 34 28 94 29 2a 06 06 17 13 11 ABLE t4(.)*..... | 304: 01 3f 69 33 74 6e 65 78 78 74 64 33 ff 43 52 45 .?i3tnexxtd3.CRE | 320: 41 54 45 20 49 4e 44 45 58 20 74 33 78 20 4f 4e ATE INDEX t3x ON | 336: 20 74 31 28 38 29 2e 04 06 17 15 11 01 45 69 6e t1(8).......Ein | 352: 64 65 68 74 32 63 64 74 31 e5 43 52 45 41 54 45 deht2cdt1.CREATE | 368: 20 49 4e 44 45 58 20 74 32 63 c4 20 4f 4e 20 74 INDEX t2c. ON t | 384: 32 28 63 2c 64 29 28 05 06 17 01 11 11 3d 74 61 2(c,d)(......=ta | 400: 6c 32 74 62 74 65 32 04 43 52 45 41 54 45 20 54 l2tbte2.CREATE T | 416: 41 42 4c 45 20 74 33 28 63 2c 78 2c 65 2c 66 29 ABLE t3(c,x,e,f) | 432: 28 02 06 17 11 11 01 3d 74 61 9e 93 65 74 32 74 (......=ta..et2t | 448: 32 03 43 52 45 41 54 45 20 54 41 42 4c 45 20 74 2.CREATE TABLE t | 464: 32 28 63 2c 64 2c 65 2c 66 29 24 01 06 17 11 11 2(c,d,e,f)$..... | 480: 01 35 55 61 62 6c 88 74 31 74 31 02 43 52 45 41 .5Uabl.t1t1.CREA | 496: 54 45 20 54 41 42 4c 45 20 74 31 28 61 2c 62 29 TE TABLE t1(a,b) | page 2 offset 512 | 0: 0d 00 00 00 0d 25 00 01 cf 00 01 fa 01 f3 01 de .....%.......... | 16: 01 00 00 00 fd 00 00 0d 00 00 00 00 45 20 54 41 ............E TA | 32: 42 4c 45 20 74 34 28 94 29 2a 06 06 17 13 11 01 BLE t4(.)*...... | 48: 3f 69 33 74 6e 65 78 78 74 64 33 ff 43 52 45 a0 ?i3tnexxtd3.CRE. | 64: a0 a0 a0 a0 a0 a0 a0 a0 a0 a0 a0 a0 74 13 11 01 ............t... | 80: 49 45 74 00 00 00 00 00 00 00 00 00 00 00 00 00 IEt............. | end x.db }]} {} do_catchsql_test 11.1 { PRAGMA writable_schema=ON; -- bypass improved sqlite_master consistency checking DELETE FROM t3 WHERE x IN (SELECT x FROM t4); } {1 {database disk image is malformed}} #------------------------------------------------------------------------- reset_db do_test 12.0 { sqlite3 db {} db deserialize [decode_hexdb { | size 12288 pagesize 4096 filename crash-e6d070858a3a85.db | page 1 offset 0 | 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3. | 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 00 .....@ ........ | 96: 00 00 00 00 0d 00 00 00 02 0f 8f 00 0f bf 0f 8f ................ | 3968: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 2e ................ | 3984: 02 06 17 15 11 01 45 69 6e 64 65 78 74 31 63 62 ......Eindext1cb | 4000: 74 31 03 43 52 45 41 54 45 20 49 4e 44 45 58 20 t1.CREATE INDEX | 4016: 74 31 63 62 20 4f 4e 20 74 31 28 63 2c 62 29 3f t1cb ON t1(c,b)? | 4032: 01 06 17 11 11 01 6b 74 61 62 6c 65 74 31 74 31 ......ktablet1t1 | 4048: 02 43 52 45 41 54 45 20 54 41 42 4c 45 20 74 31 .CREATE TABLE t1 | 4064: 28 61 20 49 4e 54 2c 20 62 20 49 4e 54 2c 20 43 (a INT, b INT, C | 4080: 20 49 4e 54 20 44 45 46 41 55 4c 54 20 31 36 29 INT DEFAULT 16) | page 2 offset 4096 | 0: 0d 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ | 4000: 00 00 00 00 00 00 00 00 07 0b 04 01 01 01 63 63 ..............cc | 4016: 11 05 0a 04 00 00 01 11 05 09 04 08 08 01 0f 05 ................ | 4032: 08 04 00 00 01 01 56 07 04 01 08 01 07 10 07 06 ......V......... | 4048: 14 01 01 01 06 08 10 06 05 04 f5 00 01 05 10 07 ................ | 4064: 04 04 01 01 01 04 03 10 06 03 04 01 09 01 03 10 ................ | 4080: 06 02 04 01 00 01 02 10 06 01 04 09 01 01 02 10 ................ | page 3 offset 8192 | 0: 0a 00 00 00 0b 0f b0 00 0f f9 0f f2 0f eb 0f e4 ................ | 16: 0f dd 0f d6 0f 9f 0f c7 0f be 00 00 00 00 00 00 ................ | 4016: 07 04 01 01 01 11 e2 0b 06 04 91 00 01 11 0a 07 ................ | 4032: 04 01 01 01 10 08 06 07 04 01 01 01 10 04 04 06 ................ | 4048: 04 01 01 09 10 02 06 04 01 0a 01 10 00 00 00 00 ................ | end crash-e6d070858a3a85.db }]} {} do_catchsql_test 12.1 { SELECT CAST((SELECT b FROM t1 WHERE 16=c) AS int) FROM t1 WHERE 16=c; } {1 {database disk image is malformed}} #------------------------------------------------------------------------- reset_db do_test 13.0 { sqlite3 db {} db deserialize [decode_hexdb { | size 8192 pagesize 4096 filename crash-81dd2952aef34f.db | page 1 offset 0 | 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3. | 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 02 .....@ ........ | 32: 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 04 ................ | 48: 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 ................ | 96: 00 00 00 00 0d 00 00 00 01 0f c4 00 0f c4 00 00 ................ | 4032: 00 00 00 00 3a 11 06 17 11 11 01 61 74 61 62 6c ....:......atabl | 4048: 65 74 31 74 31 02 43 52 45 41 54 45 20 54 41 42 et1t1.CREATE TAB | 4064: 4c 45 20 74 31 28 61 20 49 4e 54 45 47 45 52 20 LE t1(a INTEGER | 4080: 50 52 49 4d 41 52 59 20 4b 45 59 2c 62 2c 63 29 PRIMARY KEY,b,c) | page 2 offset 4096 | 0: 0d 07 70 00 02 0f eb 00 0f fa 00 00 00 00 00 00 ..p............. | 4064: 00 00 00 00 00 00 00 00 00 00 00 05 bf ff ff ff ................ | 4080: ff ff ff ff ff 04 00 01 00 02 04 01 00 00 00 00 ................ | end crash-81dd2952aef34f.db }]} {} do_catchsql_test 13.1 { WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x-2019 FROM c WHERE x<2) INSERT INTO t1(b,c) SELECT last_insert_rowid(), x FROM c; } {1 {database disk image is malformed}} #------------------------------------------------------------------------- reset_db do_test 14.0 { sqlite3 db {} db deserialize [decode_hexdb { | size 512 pagesize 65536 filename clusterfuzz-testcase-minimized-sqlite3_dbfuzz2_fuzzer-4806406219825152 | page 1 offset 0 | 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3. | 16: 00 01 02 01 00 40 20 20 00 63 2e 78 00 00 00 07 .....@ .c.x.... | 32: 00 00 00 00 00 00 00 00 00 00 00 08 00 00 00 04 ................ | 48: 00 00 00 00 00 00 01 00 35 05 43 00 04 00 00 00 ........5.C..... | 80: 00 00 00 00 00 00 00 00 08 00 00 00 00 00 00 0c ................ | 96: 00 2e 2c 50 0d 00 00 00 03 00 00 00 01 da 01 b0 ..,P............ | 112: 01 56 01 86 01 2a 01 02 00 00 00 00 00 00 00 1c .V...*.......... | 128: 00 38 80 b2 e6 0e 00 00 00 00 00 00 00 00 00 10 .8.............. | 144: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 ................ | 160: 00 00 00 00 00 00 00 00 00 00 00 00 45 20 54 41 ............E TA | 256: 00 00 00 00 00 00 22 07 06 17 11 11 01 35 74 61 .............5ta | 272: 62 6c 00 10 00 00 34 07 43 52 54 45 20 54 41 42 bl....4.CRTE TAB | 288: 4c 45 20 74 33 28 63 2e 78 2c 65 2c 66 15 28 3a LE t3(c.x,e,f.(: | 304: 06 17 11 11 01 65 78 8c cc 87 85 35 05 43 72 45 .....ex....5.CrE | 320: 41 54 48 20 49 4e 44 45 58 20 74 33 78 20 4f 4e ATH INDEX t3x ON | 336: 20 74 33 28 78 39 2e 04 06 17 15 11 01 45 69 6e t3(x9.......Ein | 352: 64 65 78 74 32 63 64 74 32 05 43 52 45 41 54 45 dext2cdt2.CREATE | 368: 20 49 4e 44 45 58 20 74 32 63 64 20 4f 4e 20 74 INDEX t2cd ON t | 384: 32 28 63 2a 44 29 28 05 fa e8 ee ed 01 3d 74 63 2(c*D)(......=tc | 400: 62 6c 65 74 33 74 33 07 43 52 45 41 54 45 20 54 blet3t3.CREATE T | 416: 41 42 4c 45 20 74 33 28 63 2e 78 2c 65 2c 66 15 ABLE t3(c.x,e,f. | 432: 28 3a 06 17 11 11 01 3d 74 61 62 6c 65 74 32 74 (:.....=tablet2t | 448: 32 03 43 52 45 41 54 45 20 54 41 42 4c 45 20 74 2.CREATE TABLE t | 464: 32 28 63 2c 64 2c 65 2c 66 29 24 01 06 17 11 11 2(c,d,e,f)$..... | 480: 01 35 74 61 62 6c 65 74 31 74 31 02 43 52 45 41 .5tablet1t1.CREA | 496: 54 45 20 54 41 42 4c 45 20 74 31 28 61 2c 63 29 TE TABLE t1(a,c) | end clusterfuzz-testcase-minimized-sqlite3_dbfuzz2_fuzzer-4806406219825152 }]} {} extra_schema_checks 0 do_catchsql_test 14.1 { PRAGMA integrity_check; } {1 {database disk image is malformed}} # If SQLITE_OMIT_ALTERTABLE is defined, omit this file. ifcapable altertable { do_catchsql_test 14.2 { ALTER TABLE t1 RENAME TO alkjalkjdfiiiwuer987lkjwer82mx97sf98788s9789s; } {1 {database disk image is malformed}} } extra_schema_checks 1 #------------------------------------------------------------------------- reset_db do_test 15.0 { sqlite3 db {} db deserialize [decode_hexdb { | size 28672 pagesize 4096 filename crash-3afa1ca9e9c1bd.db | page 1 offset 0 | 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3. | 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 07 .....@ ........ | 32: 00 00 00 00 00 00 00 00 00 00 00 06 00 00 00 04 ................ | 48: 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 ................ | 96: 00 00 00 00 0d 00 00 00 06 0e 88 00 0f b8 0f 6d ...............m | 112: 0f 3a 0f 0b 0e d5 0e 88 01 00 00 00 00 00 00 00 .:.............. | 3712: 00 00 00 00 00 00 00 00 4b 06 06 17 25 25 01 5b ........K...%%.[ | 3728: 74 61 62 6c 65 73 71 6c 69 74 65 5f 73 74 61 74 tablesqlite_stat | 3744: 31 73 71 6c 69 74 65 5f 73 74 61 74 31 07 43 52 1sqlite_stat1.CR | 3760: 45 41 54 45 20 54 41 42 4c 45 20 73 71 6c 69 74 EATE TABLE sqlit | 3776: 65 5f 73 74 61 74 31 28 74 62 6c 2c 69 64 78 2c e_stat1(tbl,idx, | 3792: 73 74 61 74 29 34 05 06 17 13 11 01 53 69 6e 64 stat)4......Sind | 3808: 65 78 63 31 63 63 31 06 43 52 45 41 54 45 20 55 exc1cc1.CREATE U | 3824: 4e 49 51 55 45 20 49 4e 44 45 58 20 63 31 63 20 NIQUE INDEX c1c | 3840: 4f 4e 20 63 31 28 63 2c 20 62 29 2d 04 06 17 13 ON c1(c, b)-.... | 3856: 11 01 45 69 6e 64 65 78 63 31 64 63 31 05 43 52 ..Eindexc1dc1.CR | 3872: 45 41 54 45 20 49 4e 44 45 58 20 63 31 64 20 4f EATE INDEX c1d O | 3888: 4e 20 63 31 28 64 2c 20 62 29 31 03 06 17 13 11 N c1(d, b)1..... | 3904: 01 4d 69 6e 64 65 78 62 31 63 62 31 05 43 52 45 .Mindexb1cb1.CRE | 3920: 41 54 45 20 55 4e 49 51 55 45 20 49 4e 44 45 58 ATE UNIQUE INDEX | 3936: 20 62 31 63 20 4f 4e 20 62 31 28 63 29 49 02 06 b1c ON b1(c)I.. | 3952: 17 11 11 0f 7f 74 61 62 6c 65 63 31 63 31 03 43 .....tablec1c1.C | 3968: 52 45 41 54 45 20 54 41 42 4c 45 20 63 31 28 61 REATE TABLE c1(a | 3984: 20 49 4e 54 20 50 52 49 4d 41 52 59 20 4b 45 59 INT PRIMARY KEY | 4000: 2c 20 62 2c 20 63 2c 20 64 29 20 57 49 54 48 4f , b, c, d) WITHO | 4016: 55 54 20 52 4f 57 49 44 46 01 06 17 11 11 01 79 UT ROWIDF......y | 4032: 74 61 62 6c 65 62 31 62 31 02 43 52 45 41 54 45 tableb1b1.CREATE | 4048: 20 54 41 42 4c 45 20 62 31 28 61 20 49 4e 54 20 TABLE b1(a INT | 4064: 50 52 49 4d 41 52 59 20 4b 45 59 2c 20 62 2c 20 PRIMARY KEY, b, | 4080: 63 29 20 57 49 54 48 4f 55 54 20 52 4f 57 49 44 c) WITHOUT ROWID | page 2 offset 4096 | 0: 0a 00 00 00 07 0f ca 00 0f fa 0f f2 0f ea 0f e2 ................ | 16: 0f da 00 00 00 01 00 00 00 00 00 00 00 00 00 00 ................ | 4032: 00 00 00 00 00 00 00 00 00 00 07 04 01 0f 01 06 ................ | 4048: 67 07 07 04 01 0f 01 06 66 06 07 04 01 0f 01 05 g.......f....... | 4064: 65 05 07 04 01 0f 01 04 64 04 07 04 01 0f 01 03 e.......d....... | 4080: 63 03 07 04 01 0f 01 02 62 0f 05 04 09 0f 09 61 c.......b......a | page 3 offset 8192 | 0: 0a 00 00 00 07 0f bd 00 0f f9 0f ef 0f e5 0f db ................ | 16: 0f d1 0f c7 0f bd 00 00 00 00 01 00 00 00 00 00 ................ | 4016: 00 00 00 00 00 00 00 00 00 00 00 00 00 09 05 01 ................ | 4032: 0f 01 01 07 61 07 07 09 05 01 0f 01 01 06 61 06 ....a.........a. | 4048: 06 09 05 01 0f 01 01 05 61 05 05 09 05 01 0f 01 ........a....... | 4064: 01 04 61 04 04 09 05 01 0f 01 01 03 61 03 03 09 ..a.........a... | 4080: 05 01 0f 01 01 02 61 0f 02 06 05 09 0f 09 09 61 ......a........a | page 4 offset 12288 | 0: 0a 00 00 00 07 0f d8 00 0f fc 0f f0 0f ea 0f e4 ................ | 16: 0f de 0f d8 0f f6 00 00 00 00 00 00 00 00 00 00 ................ | 4048: 00 00 00 00 00 00 00 00 05 03 01 01 07 07 05 03 ................ | 4064: 01 01 06 06 05 03 01 01 05 05 05 03 01 01 04 04 ................ | 4080: 05 03 01 01 03 03 05 03 01 01 0f 02 03 03 09 09 ................ | page 5 offset 16384 | 0: 0a 00 00 00 07 0f ca 00 0f fa 0f f2 0f ea 0f 00 ................ | 4032: 00 00 00 00 00 00 00 00 00 00 07 04 01 0f 01 07 ................ | 4048: 61 07 07 04 01 0f 01 06 61 06 07 04 01 0f 01 05 a.......a....... | 4064: 61 05 07 04 01 1f 01 04 61 04 07 04 01 0f 01 03 a.......a....... | 4080: 61 03 07 04 01 0f 01 02 61 02 05 04 09 0f 09 61 a.......a......a | page 6 offset 20480 | 0: 0a 00 00 00 07 0f ca 00 0f fa 0f ea 0f e2 00 00 ................ | 4032: 00 00 00 00 00 00 00 00 00 00 07 04 01 0f 01 07 ................ | 4048: 61 07 07 04 01 0f 01 06 61 06 07 04 01 0f 01 05 a.......a....... | 4064: 61 05 07 04 01 0f 01 04 61 04 07 04 01 0f 01 03 a.......a....... | 4080: 61 03 07 04 01 0f 01 0f 61 02 05 04 09 0f 09 61 a.......a......a | page 7 offset 24576 | 0: 0d 00 00 00 05 0f 1c 00 0f f0 0f e0 0f d3 0f c5 ................ | 16: 0f b8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ | 4016: 00 00 00 00 00 00 00 00 0b 05 04 11 11 13 62 31 ..............b1 | 4032: 62 31 37 20 31 0c 04 04 11 13 13 62 31 62 31 63 b17 1......b1b1c | 4048: 37 20 31 0b 03 04 11 11 13 63 31 63 31 37 20 31 7 1......c1c17 1 | 4064: 0e 02 04 11 13 07 63 31 63 31 64 37 20 31 20 31 ......c1c1d7 1 1 | 4080: 0e 01 04 11 13 17 63 31 63 31 63 37 20 31 00 00 ......c1c1c7 1.. | end crash-3afa1ca9e9c1bd.db }]} {} extra_schema_checks 0 do_execsql_test 15.1 { PRAGMA cell_size_check = 0; UPDATE c1 SET c= NOT EXISTS(SELECT 1 FROM c1 ORDER BY (SELECT 1 FROM c1 ORDER BY a)) +10 WHERE d BETWEEN 4 AND 7; } {} extra_schema_checks 1 #------------------------------------------------------------------------- reset_db do_execsql_test 16.0 { CREATE TABLE t1(w, x, y, z, UNIQUE(w, x), UNIQUE(y, z)); INSERT INTO t1 VALUES(1, 1, 1, 1); CREATE TABLE t1idx(x, y, i INTEGER, PRIMARY KEY(x)) WITHOUT ROWID; INSERT INTO t1idx VALUES(10, NULL, 5); PRAGMA writable_schema = 1; UPDATE sqlite_master SET rootpage = ( SELECT rootpage FROM sqlite_master WHERE name='t1idx' ) WHERE type = 'index'; } extra_schema_checks 0 db close sqlite3 db test.db extra_schema_checks 1 do_catchsql_test 16.1 { PRAGMA writable_schema = ON; INSERT INTO t1(rowid, w, x, y, z) VALUES(5, 10, 11, 10, NULL); } {1 {database disk image is malformed}} #------------------------------------------------------------------------- # Test that corruption is reported from within a checkpoint if the # expected final size of the database (according to the last commit # frame in the wal file) is greater than the combined initial sizes # of the database and wal file. # if {[wal_is_capable]} { reset_db do_execsql_test 17.0 { CREATE TABLE t1(o INTEGER PRIMARY KEY, t UNIQUE); INSERT INTO t1(t) VALUES(randomblob(123)); INSERT INTO t1(t) SELECT randomblob(123) FROM t1; INSERT INTO t1(t) SELECT randomblob(123) FROM t1; INSERT INTO t1(t) SELECT randomblob(123) FROM t1; INSERT INTO t1(t) SELECT randomblob(123) FROM t1; INSERT INTO t1(t) SELECT randomblob(123) FROM t1; INSERT INTO t1(t) SELECT randomblob(123) FROM t1; INSERT INTO t1(t) SELECT randomblob(123) FROM t1; INSERT INTO t1(t) SELECT randomblob(123) FROM t1; INSERT INTO t1(t) SELECT randomblob(123) FROM t1; PRAGMA journal_mode = wal; INSERT INTO t1 VALUES(-1, 'b'); } {wal} do_test 17.1 { set fd [open test.db r+] chan truncate $fd 2048 file size test.db } {2048} do_catchsql_test 17.2 { PRAGMA wal_checkpoint } {1 {database disk image is malformed}} do_test 17.3 { close $fd } {} } #------------------------------------------------------------------------- reset_db do_test 18.0 { sqlite3 db {} db deserialize [decode_hexdb { .open --hexdb | size 12288 pagesize 4096 filename crash-40d5739835cbdb.db | page 1 offset 0 | 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3. | 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 00 .....@ ........ | 96: 00 00 00 00 0d 00 00 00 02 0f 4e 00 0f a2 0f 4e ..........N....N | 3904: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 52 02 ..............R. | 3920: 07 17 11 11 01 81 0f 74 61 62 6c 65 74 32 74 32 .......tablet2t2 | 3936: 03 43 52 45 41 54 45 20 54 41 42 4c 45 20 74 32 .CREATE TABLE t2 | 3952: 28 61 20 49 4e 54 2c 20 62 20 49 4e 54 45 47 45 (a INT, b INTEGE | 3968: 52 2c 20 50 52 49 4d 41 52 59 20 4b 45 59 28 61 R, PRIMARY KEY(a | 3984: 2c 62 29 29 20 57 49 54 48 4f 55 54 20 52 4f 57 ,b)) WITHOUT ROW | 4000: 49 44 5c 01 07 16 11 11 01 81 23 74 61 62 6c 65 ID........#table | 4016: 74 31 74 31 02 43 52 45 41 54 45 20 54 41 42 4c t1t1.CREATE TABL | 4032: 45 20 74 31 28 61 20 49 4e 54 20 50 52 49 4d 41 E t1(a INT PRIMA | 4048: 52 59 20 4b 45 59 2c 20 62 20 54 45 58 54 2c 20 RY KEY, b TEXT, | 4064: 63 20 54 45 58 54 2c 20 64 20 49 4e 54 45 47 45 c TEXT, d INTEGE | 4080: 52 29 20 57 49 54 48 4f 55 54 20 52 4f 57 49 44 R) WITHOUT ROWID | page 2 offset 4096 | 0: 0a 00 00 00 06 0f a7 00 0f f4 0f e5 0f d5 0f c5 ................ | 16: 0f b6 0f 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ | 4000: 00 00 00 00 00 00 00 0f 05 01 15 13 01 06 65 7f ..............e. | 4016: 25 6e 73 69 78 06 0e 05 01 13 15 03 b5 6f 64 64 %nsix........odd | 4032: 66 69 76 65 05 0f 05 01 15 15 01 04 65 76 65 61 five........evea | 4048: e6 6f 75 82 04 0f 05 01 13 17 01 03 6f 64 64 74 .ou.........oddt | 4064: 68 72 61 15 03 0e 05 01 15 12 01 02 64 76 64 6e hra.........dvdn | 4080: 74 77 6f 02 00 00 00 00 00 00 00 00 00 00 00 00 two............. | page 3 offset 8192 | 2816: 00 00 00 00 00 00 00 00 00 00 00 06 03 02 01 00 ................ | 2832: c8 07 06 03 02 01 00 c7 11 06 03 02 01 02 a6 52 ...............R | 2848: 06 d5 02 01 10 c5 1b 06 03 02 00 ef c4 53 06 03 .............S.. | 2864: 02 01 00 c3 22 06 04 02 01 00 c2 26 06 03 02 01 ...........&.... | 2880: 00 c2 1e 02 b3 02 01 00 c0 3a 06 03 3c 01 00 bf .........:..<... | 2896: 2c 06 03 02 01 00 be 27 00 83 02 01 01 bd 15 06 ,......'........ | 2912: 03 02 01 00 bc 21 06 03 02 01 00 bb 54 16 13 02 .....!......T... | 2928: 01 09 9a 0a 06 03 02 01 00 b9 53 06 03 02 01 00 ..........S..... | 2944: b8 52 06 13 02 01 00 b7 1e 06 03 02 01 00 b6 34 .R.............4 | 2960: 06 13 02 01 00 b5 3a 05 f3 12 01 00 b4 45 05 03 ......:......E.. | 2976: 02 00 00 b4 6f 06 03 02 01 00 b2 03 06 03 02 01 ....o........... | 2992: 00 b1 63 06 03 02 01 00 b0 24 06 03 02 01 00 9f ..c......$...... | 3008: ac 06 03 02 01 00 a2 2f 07 03 02 01 01 ad 21 06 ......./......!. | 3024: 03 02 01 fb cd 5b 06 c0 01 f1 00 ab 23 06 03 02 .....[......#... | 3040: 01 00 aa 5b 06 03 02 01 00 a3 ce 06 02 03 01 00 ...[............ | 3056: a8 0e 06 03 02 01 00 a7 0c 06 02 f1 01 00 a6 0d ................ | 3072: 06 03 02 01 00 95 25 06 03 02 01 00 a4 17 06 03 ......%......... | 3088: 02 01 00 a3 09 06 03 02 01 00 a2 51 06 03 02 02 ...........Q.... | 3104: 00 a1 40 06 01 e2 00 00 a0 4b 06 13 02 00 00 9e ..@......K...... | 3120: 5d 06 03 02 01 10 9e 81 06 03 02 01 00 9d 42 06 ].............B. | 3136: 03 69 01 00 9c 48 06 03 02 01 00 9b 48 06 03 01 .i...H......H... | 3152: 01 00 9a 09 06 03 02 01 00 99 2f 06 03 02 01 00 ........../..... | 3168: 98 3a 06 03 02 01 00 97 24 06 03 02 01 00 96 4a .:......$......J | 3184: 06 03 02 11 00 f9 50 02 93 02 01 00 94 2f 06 03 ......P....../.. | 3200: 02 11 04 93 1a 06 03 01 04 e0 92 1a 06 03 02 01 ................ | 3216: 00 91 27 06 03 02 01 00 90 23 06 03 02 01 00 8f ..'......#...... | 3232: 3b 06 03 02 01 00 8e 46 06 16 02 01 00 8d 1d 07 ;......F........ | 3248: 23 12 01 00 8c 5a 06 03 02 01 00 8a 39 06 03 02 #....Z......9... | 3264: 00 ff 84 b5 06 03 02 01 00 89 07 06 03 02 11 00 ................ | 3280: 88 02 06 03 02 01 00 87 19 06 03 02 01 00 86 4d ...............M | 3296: 06 13 12 00 00 85 4b 06 03 02 01 00 84 37 06 13 ......K......7.. | 3312: 02 01 00 83 2c 06 03 02 01 00 81 60 06 13 02 11 ....,......`.... | 3328: 00 81 3b 06 03 02 01 0a b0 5a 06 03 01 01 7f 22 ..;......Z...... | 3344: 05 03 01 01 7e 21 05 03 01 01 7d 0b 15 03 01 02 ....~!.......... | 3360: 7b 08 05 03 06 91 7b 22 05 03 01 01 7a 58 05 03 ............zX.. | 3376: 01 01 7a 4f 05 03 01 01 78 49 05 03 01 01 77 16 ..zO....xI....w. | 3392: 05 03 01 01 76 5f 05 03 01 01 75 0f 05 03 01 01 ....v_....u..... | 3408: 74 2f 05 03 01 01 3f 1f 05 03 01 02 72 14 05 03 t/....?.....r... | 3424: 00 f1 71 08 05 03 01 01 70 0c 05 03 01 47 7f 29 ..q.....p....G.) | 3440: 05 03 01 01 6e 57 05 03 01 01 6d 33 05 13 00 f1 ....nW....m3.... | 3456: 6c 0b 05 03 01 01 6b 49 05 03 01 01 69 05 05 03 l.....kI....i... | 3472: 01 02 ed 23 00 00 01 00 00 00 00 00 00 00 00 00 ...#............ | end crash-40d5739835cbdb.db }]} {} ifcapable json1 { do_catchsql_test 18.1 { SELECT json_group_array(c) OVER win4 FROM t1 WINDOW win4 AS ( ORDER BY a COLLATE nocase RANGE BETWEEN 1.0 PRECEDING AND CURRENT ROW ) } {1 {JSON cannot hold BLOB values}} } ;# ifcapable json1 finish_test |
Added test/corruptM.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 | # 2019-08-12 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # # Check to ensure that the type, name, and tbl_name fields of the # sqlite_master table are validated and errors are reported if they # are inconsistent with the sql. # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix corruptM # These tests deal with corrupt database files # database_may_be_corrupt proc open_db2_and_catchsql {sql} { set rc [catch { sqlite3 db2 test.db } msg] if {$rc} { return [list $rc $msg] } set res [catchsql $sql db2] db2 close set res } db close forcedelete test.db sqlite3 db test.db do_execsql_test corruptM-100 { CREATE TABLE t1(a,b,c); INSERT INTO t1 VALUES(111,222,333); CREATE INDEX i1 ON t1(b); CREATE VIEW v2 AS SELECT 15,22; CREATE TRIGGER r1 AFTER INSERT ON t1 BEGIN SELECT 5; END; SELECT type, name, tbl_name, '|' FROM sqlite_master; } {table t1 t1 | index i1 t1 | view v2 v2 | trigger r1 t1 |} do_execsql_test corruptM-101 { PRAGMA writable_schema=on; UPDATE sqlite_master SET tbl_name=NULL WHERE name='t1'; SELECT type, name, tbl_name, '|' FROM sqlite_master; } {table t1 {} | index i1 t1 | view v2 v2 | trigger r1 t1 |} do_test corruptM-102 { open_db2_and_catchsql { PRAGMA quick_check; } } {1 {malformed database schema (t1)}} do_execsql_test corruptM-110 { UPDATE sqlite_master SET tbl_name='tx' WHERE name='t1'; SELECT type, name, tbl_name, '|' FROM sqlite_master; } {table t1 tx | index i1 t1 | view v2 v2 | trigger r1 t1 |} do_test corruptM-111 { open_db2_and_catchsql { PRAGMA quick_check; } } {1 {malformed database schema (t1)}} do_execsql_test corruptM-112 { UPDATE sqlite_master SET tbl_name='t1', type='tabl' WHERE name='t1'; SELECT type, name, tbl_name, '|' FROM sqlite_master; } {tabl t1 t1 | index i1 t1 | view v2 v2 | trigger r1 t1 |} do_test corruptM-113 { open_db2_and_catchsql { PRAGMA quick_check; } } {1 {malformed database schema (t1)}} do_execsql_test corruptM-114 { UPDATE sqlite_master SET tbl_name='t9',type='table',name='t9'WHERE name='t1'; SELECT type, name, tbl_name, '|' FROM sqlite_master; } {table t9 t9 | index i1 t1 | view v2 v2 | trigger r1 t1 |} do_test corruptM-114 { open_db2_and_catchsql { PRAGMA quick_check; } } {1 {malformed database schema (t9)}} do_execsql_test corruptM-120 { UPDATE sqlite_master SET name='t1',tbl_name='T1' WHERE name='t9'; SELECT type, name, tbl_name, '|' FROM sqlite_master; } {table t1 T1 | index i1 t1 | view v2 v2 | trigger r1 t1 |} do_test corruptM-121 { open_db2_and_catchsql { PRAGMA quick_check; SELECT * FROM t1, v2; } } {0 {ok 111 222 333 15 22}} do_execsql_test corruptM-130 { UPDATE sqlite_master SET type='view' WHERE name='t1'; SELECT type, name, tbl_name, '|' FROM sqlite_master; } {view t1 T1 | index i1 t1 | view v2 v2 | trigger r1 t1 |} do_test corruptM-131 { open_db2_and_catchsql { PRAGMA quick_check; SELECT * FROM t1, v2; } } {1 {malformed database schema (t1)}} do_execsql_test corruptM-140 { UPDATE sqlite_master SET type='table', tbl_name='t1' WHERE name='t1'; UPDATE sqlite_master SET tbl_name='tx' WHERE name='i1'; SELECT type, name, tbl_name, '|' FROM sqlite_master; } {table t1 t1 | index i1 tx | view v2 v2 | trigger r1 t1 |} do_test corruptM-141 { open_db2_and_catchsql { PRAGMA quick_check; SELECT * FROM t1, v2; } } {1 {malformed database schema (i1)}} do_execsql_test corruptM-150 { UPDATE sqlite_master SET type='table', tbl_name='t1' WHERE name='i1'; SELECT type, name, tbl_name, '|' FROM sqlite_master; } {table t1 t1 | table i1 t1 | view v2 v2 | trigger r1 t1 |} do_test corruptM-151 { open_db2_and_catchsql { PRAGMA quick_check; SELECT * FROM t1, v2; } } {1 {malformed database schema (i1)}} do_execsql_test corruptM-160 { UPDATE sqlite_master SET type='view', tbl_name='t1' WHERE name='i1'; SELECT type, name, tbl_name, '|' FROM sqlite_master; } {table t1 t1 | view i1 t1 | view v2 v2 | trigger r1 t1 |} do_test corruptM-161 { open_db2_and_catchsql { PRAGMA quick_check; SELECT * FROM t1, v2; } } {1 {malformed database schema (i1)}} do_execsql_test corruptM-170 { UPDATE sqlite_master SET type='index', tbl_name='t1' WHERE name='i1'; UPDATE sqlite_master SET type='table', tbl_name='v2' WHERE name='v2'; SELECT type, name, tbl_name, '|' FROM sqlite_master; } {table t1 t1 | index i1 t1 | table v2 v2 | trigger r1 t1 |} do_test corruptM-171 { open_db2_and_catchsql { PRAGMA quick_check; SELECT * FROM t1, v2; } } {1 {malformed database schema (v2)}} do_execsql_test corruptM-180 { UPDATE sqlite_master SET type='view',name='v3',tbl_name='v3' WHERE name='v2'; SELECT type, name, tbl_name, '|' FROM sqlite_master; } {table t1 t1 | index i1 t1 | view v3 v3 | trigger r1 t1 |} do_test corruptM-181 { open_db2_and_catchsql { PRAGMA quick_check; SELECT * FROM t1, v2; } } {1 {malformed database schema (v3)}} do_execsql_test corruptM-190 { UPDATE sqlite_master SET type='view',name='v2',tbl_name='v2' WHERE name='v3'; UPDATE sqlite_master SET type='view' WHERE name='r1'; SELECT type, name, tbl_name, '|' FROM sqlite_master; } {table t1 t1 | index i1 t1 | view v2 v2 | view r1 t1 |} do_test corruptM-191 { open_db2_and_catchsql { PRAGMA quick_check; SELECT * FROM t1, v2; } } {1 {malformed database schema (r1)}} do_execsql_test corruptM-192 { UPDATE sqlite_master SET type='trigger',tbl_name='v2' WHERE name='r1'; SELECT type, name, tbl_name, '|' FROM sqlite_master; } {table t1 t1 | index i1 t1 | view v2 v2 | trigger r1 v2 |} do_test corruptM-193 { open_db2_and_catchsql { PRAGMA quick_check; SELECT * FROM t1, v2; } } {1 {malformed database schema (r1)}} finish_test |
Added test/corruptN.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 | # 2020-12-16 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix corruptN # These tests deal with corrupt database files # database_may_be_corrupt reset_db do_test 1.0 { sqlite3 db {} db deserialize [decode_hexdb { .open --hexdb | size 4096 pagesize 512 filename sql024239.txt.db | page 1 offset 0 | 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3. | 16: 02 00 01 01 00 40 20 20 00 00 00 0c 00 00 00 07 .....@ ........ | 32: 00 00 00 00 00 00 00 00 00 00 00 08 00 00 00 04 ................ | 48: 00 00 00 00 89 00 00 04 00 10 00 01 0a 00 00 01 ................ | 80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0c ................ | 96: 00 2e 2c 50 0d 00 00 00 06 01 06 00 01 da 01 b0 ..,P............ | 112: 01 56 01 86 01 2a 01 06 00 00 00 00 00 00 00 00 .V...*.......... | 256: 00 00 00 00 00 00 22 07 06 17 11 11 01 31 74 61 .............1ta | 272: 62 6c 65 74 34 74 34 07 43 52 45 41 54 45 20 54 blet4t4.CREATE T | 288: 41 42 4c 45 20 74 34 28 78 29 2a 06 06 17 13 11 ABLE t4(x)*..... | 304: 01 3f 69 6e 64 65 78 74 33 78 74 33 05 43 52 45 .?indext3xt3.CRE | 320: 41 54 45 20 49 4e 44 45 58 20 74 33 78 20 4f 4e ATE INDEX t3x ON | 336: 20 74 33 28 78 29 2e 04 06 17 15 11 01 45 69 6e t3(x).......Ein | 352: 64 65 78 74 32 63 64 74 32 05 43 52 45 41 54 45 dext2cdt2.CREATE | 368: 20 49 4e 44 45 58 20 74 32 63 64 20 4f 4e 20 74 INDEX t2cd ON t | 384: 32 28 63 2c 64 29 28 05 06 17 11 11 01 3d 74 61 2(c,d)(......=ta | 400: 62 6c 65 74 33 74 33 07 43 52 45 41 54 45 20 54 blet3t3.CREATE T | 416: 41 42 4c 45 20 74 33 28 63 2c 78 2c 65 2c 66 29 ABLE t3(c,x,e,f) | 432: 28 02 06 17 11 11 01 3d 74 61 62 6c 65 74 32 74 (......=tablet2t | 448: 32 03 43 52 45 41 54 45 20 54 41 42 4c 45 20 74 2.CREATE TABLE t | 464: 32 28 63 2c 64 2c 65 2c 66 29 24 01 06 17 11 11 2(c,d,e,f)$..... | 480: 01 35 74 61 62 6c 65 74 31 74 31 02 43 52 45 41 .5tablet1t1.CREA | 496: 54 45 20 54 41 42 4c 45 20 74 31 28 61 2c 62 29 TE TABLE t1(a,b) | page 2 offset 512 | 0: 0d 00 00 00 04 01 41 00 01 fa 01 f3 01 de 01 cf ......A......... | 160: 00 00 20 00 00 00 00 00 00 00 00 00 00 00 00 00 .. ............. | 448: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0d ................ | 464: 04 03 17 17 73 65 76 65 6e 65 69 67 68 74 13 03 ....seveneight.. | 480: 03 07 07 40 14 00 00 00 00 00 00 40 18 00 00 00 ...@.......@.... | 496: 00 00 00 05 02 03 01 01 03 04 04 01 03 09 01 02 ................ | page 3 offset 1024 | 0: 0d 00 00 00 08 01 54 00 01 f7 01 ec 01 c5 01 aa ......T......... | 16: 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ | 112: 00 00 dd 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ | 336: 00 00 00 00 19 08 05 17 17 17 17 65 69 67 68 74 ...........eight | 352: 65 69 67 68 74 73 65 76 65 6e 73 65 76 65 6e 25 eightsevenseven% | 368: 07 05 07 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ | 432: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 08 ................ | 480: 00 00 0f 04 17 17 01 65 69 67 68 74 65 69 67 68 .......eighteigh | 496: 74 08 15 04 07 07 01 40 18 00 00 00 00 00 00 40 t......@.......@ | page 4 offset 1536 | 0: 18 00 00 00 00 00 00 07 07 04 01 01 01 04 04 06 ................ | 16: 07 04 01 01 01 02 02 05 0f 04 17 17 01 73 6d 76 .............smv | 32: 65 6e 65 69 67 68 74 04 15 04 07 07 01 40 14 00 eneight......@.. | page 5 offset 2048 | 0: 0a 00 00 00 08 01 96 00 01 fa 01 c4 01 f2 01 bc ................ | 16: 01 dc 01 e1 01 96 01 cc 00 00 00 00 00 00 00 00 ................ | 160: 00 00 00 00 00 00 32 00 00 00 00 00 00 00 00 00 ......2......... | 368: 00 00 00 08 00 00 00 00 00 00 00 00 00 00 00 00 ................ | 400: 00 00 00 00 00 00 0f 04 17 17 01 85 69 67 68 74 ............ight | 416: 65 69 67 68 74 08 15 04 07 07 01 40 18 00 00 00 eight......@.... | 432: 00 00 00 40 18 00 00 00 00 00 00 07 07 04 01 01 ...@............ | 448: 01 04 04 06 07 04 01 01 01 02 02 05 0f 04 17 17 ................ | 464: 01 73 6d 76 65 6e 65 69 67 68 74 04 15 04 07 07 .smveneight..... | 480: 01 40 14 00 00 00 00 00 00 40 18 00 00 00 00 00 .@.......@...... | 496: 00 03 07 04 01 01 01 03 04 02 05 04 03 01 09 02 ................ | page 6 offset 2560 | 0: 0a 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ | 16: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 10 00 ................ | 304: 00 00 00 26 00 00 00 00 00 00 00 00 00 00 00 00 ...&............ | page 7 offset 3072 | 0: 0d 00 00 00 08 01 c2 00 01 fb 01 f6 01 f1 01 ec ................ | 16: 01 e0 01 d4 01 cb 01 c2 00 00 00 00 00 00 00 00 ................ | 128: 00 00 00 00 00 00 00 00 00 00 00 00 00 20 00 04 ............. .. | 384: 00 00 00 00 00 00 00 00 00 07 08 02 17 65 69 fc .............ei. | 400: 68 74 07 07 02 17 65 69 67 68 74 0a fb fd f8 bf ht....eight..... | 416: e7 ff ff ff 00 00 00 0a 05 02 07 40 18 00 00 00 ...........@.... | 432: 00 00 00 03 04 02 01 04 03 03 02 01 04 03 02 01 ................ | 448: ff ff ff ff ff ff 00 00 00 00 00 00 00 00 00 00 ................ | end sql024239.txt.db }]} {} do_catchsql_test 1.1 { VACUUM; } {1 {database disk image is malformed}} # 2021-04-05 dbsqlfuzz b92b72e4de80b5140c30ab71372ca719b8feb618 do_test 2.0 { sqlite3 db {} db deserialize [decode_hexdb { | size 16384 pagesize 4096 filename c-b92b.txt.db | page 1 offset 0 | 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3. | 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 04 .....@ ........ | 32: 00 00 00 00 00 00 00 00 00 00 00 03 00 00 00 04 ................ | 48: 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 ................ | 96: 00 00 00 00 0d 0f f8 00 04 0f 12 00 0f 91 0f d3 ................ | 112: 0f 67 0f 12 00 00 00 00 00 00 00 00 00 00 00 00 .g.............. | 3856: 00 00 53 04 07 1b 13 11 08 81 0d 74 72 69 67 67 ..S........trigg | 3872: 65 72 74 72 30 74 31 43 52 45 41 54 45 20 54 52 ertr0t1CREATE TR | 3888: 49 47 47 45 52 20 74 72 30 20 44 45 4c 45 54 45 IGGER tr0 DELETE | 3904: 20 4f 4e 20 74 31 20 42 45 47 49 4e 0a 20 20 55 ON t1 BEGIN. U | 3920: 50 44 41 54 45 20 74 31 20 53 45 54 20 62 20 3d PDATE t1 SET b = | 3936: 20 61 3b 0a 45 4e 44 28 03 06 17 11 11 01 3d 69 a;.END(......=i | 3952: 6e 64 65 78 69 30 74 31 04 43 52 45 41 54 45 20 ndexi0t1.CREATE | 3968: 49 4e 44 45 58 20 69 30 20 4f 4e 20 74 31 28 62 INDEX i0 ON t1(b | 3984: 29 40 01 06 17 11 11 01 6d 74 61 62 6c 65 74 31 )@......mtablet1 | 4000: 74 31 02 43 52 45 41 54 45 20 54 41 42 4c 45 20 t1.CREATE TABLE | 4016: 74 31 28 61 20 55 4e 49 51 55 45 20 4f 4e 20 43 t1(a UNIQUE ON C | 4032: 4f 4e 46 4c 49 43 54 20 52 45 50 4c 41 43 45 2c ONFLICT REPLACE, | 4048: 20 62 29 23 02 06 17 37 11 01 00 69 6e 64 65 78 b)#...7...index | 4064: 73 71 6c 69 74 65 5f 61 75 74 6f 69 6e 64 65 78 sqlite_autoindex | 4080: 5f 74 31 5f 31 74 31 03 00 00 00 08 00 00 00 00 _t1_1t1......... | page 2 offset 4096 | 0: 0d 00 00 00 02 0f 00 00 00 00 00 00 00 00 00 00 ................ | 4080: 00 00 05 02 03 01 01 09 0d 05 01 03 01 01 04 0c ................ | page 3 offset 8192 | 0: 0a 00 00 00 02 0f f5 00 0f fb 0f f5 00 00 00 00 ................ | 4080: 00 00 00 00 00 05 03 01 01 09 02 04 03 01 09 04 ................ | page 4 offset 12288 | 0: 0a 00 00 00 02 0f f5 00 0f fb 0f f5 00 00 00 00 ................ | 4080: 00 00 00 00 00 05 03 01 01 0d 02 04 03 00 00 00 ................ | end c-b92b.txt.db }]} {} prng_seed 0 db do_catchsql_test 2.1 { SELECT count(*) FROM sqlite_schema; WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<1000) INSERT INTO t1(a) SELECT randomblob(null) FROM c; } {0 4} reset_db if {![info exists ::G(perm:presql)]} { do_execsql_test 3.0 { CREATE TABLE t1(x INTEGER PRIMARY KEY AUTOINCREMENT, y); PRAGMA writable_schema = 1; UPDATE sqlite_schema SET sql = 'CREATE TABLE sqlite_sequence(name-seq)' WHERE name = 'sqlite_sequence'; } db close sqlite3 db test.db do_catchsql_test 3.1 { PRAGMA writable_schema = 1; INSERT INTO t1(y) VALUES('abc'); } {1 {database disk image is malformed}} reset_db do_execsql_test 4.1 { CREATE TABLE x1(a INTEGER PRIMARY KEY, b UNIQUE, c UNIQUE); INSERT INTO x1 VALUES(1, 1, 2); INSERT INTO x1 VALUES(2, 2, 3); INSERT INTO x1 VALUES(3, 3, 4); INSERT INTO x1 VALUES(4, 5, 6); PRAGMA writable_schema = 1; UPDATE sqlite_schema SET rootpage = ( SELECT rootpage FROM sqlite_schema WHERE name = 'sqlite_autoindex_x1_2' ) WHERE name = 'sqlite_autoindex_x1_1'; } db close sqlite3 db test.db breakpoint do_catchsql_test 4.2 { PRAGMA writable_schema = 1; REPLACE INTO x1 VALUES(5, 2, 3); } {0 {}} } #------------------------------------------------------------------------- reset_db ifcapable json1&&vtab { db func strreplace strreplace proc strreplace {orig a b} { string map [list $a $b] $orig } do_execsql_test 5.0 { CREATE TABLE t1(a, b); CREATE INDEX t1a ON t1(a); CREATE INDEX t1b ON t1(b); PRAGMA writable_schema = 1; UPDATE sqlite_schema SET sql = strreplace(sql, 't1', 'json_each') WHERE type='index'; } # Do not run this tests if there is any presql (SQL run from within # the [sqlite3] command) configured. In this case the schema is parsed # before the "PRAGMA writable_schema" command is executed and the # script throws and exception. if {[info exists ::G(perm:presql)]==0 || $::G(perm:presql)==""} { db close sqlite3 db test.db do_execsql_test 5.1 { PRAGMA writable_schema = 1; SELECT * FROM t1 } } }; # ifcapable json1&&vtab #------------------------------------------------------------------------- reset_db do_execsql_test 6.0 { PRAGMA auto_vacuum = 0; PRAGMA page_size=1024; CREATE TABLE t1(a INTEGER PRIMARY KEY, b); INSERT INTO t1(b) VALUES(zeroblob(300)),(zeroblob(300)),(zeroblob(300)),(zeroblob(300)); CREATE TABLE t2(a); CREATE TRIGGER t1tr BEFORE UPDATE ON t1 BEGIN DELETE FROM t2; END; PRAGMA writable_schema=ON; UPDATE sqlite_schema SET rootpage=3 WHERE rowid=2; PRAGMA writable_schema=RESET; INSERT INTO t2 VALUES('active'),('boomer'),('atom'),('atomic'), ('alpha channel backup abandon test aback boomer atom alpha active'); } do_catchsql_test 6.1 { UPDATE t1 SET b=zeroblob(299); } {1 {database disk image is malformed}} reset_db do_execsql_test 6.2 { -- Make "t1" a large table. Large enough that the children of the root -- node are interior nodes. PRAGMA page_size = 1024; PRAGMA auto_vacuum = 0; CREATE TABLE t1(x); WITH s(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<500 ) INSERT INTO t1 SELECT zeroblob(300) FROM s; CREATE TABLE t2(y); CREATE TRIGGER tr BEFORE UPDATE ON t1 BEGIN DELETE FROM t2; END; -- Set the root of table t2 to 137 - the leftmost child of the root of t1. PRAGMA writable_schema = ON; UPDATE sqlite_schema SET rootpage = 137 WHERE name='t2'; PRAGMA writable_schema = RESET; } do_catchsql_test 6.3 { -- Run an UPDATE on t1 that will hit a child of page 136. Have the trigger -- clear page 136 and its children. Assert fails. UPDATE t1 SET x='hello world' WHERE rowid=1; } {1 {database disk image is malformed}} finish_test |
Changes to test/cost.test.
︙ | ︙ | |||
21 22 23 24 25 26 27 | CREATE UNIQUE INDEX i3 ON t3(b); CREATE UNIQUE INDEX i4 ON t4(c, d); } do_eqp_test 1.2 { SELECT e FROM t3, t4 WHERE b=c ORDER BY b, d; } { QUERY PLAN | | | | > | > | > | | | | | > | > | | 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 | CREATE UNIQUE INDEX i3 ON t3(b); CREATE UNIQUE INDEX i4 ON t4(c, d); } do_eqp_test 1.2 { SELECT e FROM t3, t4 WHERE b=c ORDER BY b, d; } { QUERY PLAN |--SCAN t3 USING COVERING INDEX i3 `--SEARCH t4 USING INDEX i4 (c=?) } do_execsql_test 2.1 { CREATE TABLE t1(a, b); CREATE INDEX i1 ON t1(a); } # It is better to use an index for ORDER BY than sort externally, even # if the index is a non-covering index. do_eqp_test 2.2 { SELECT * FROM t1 ORDER BY a; } {SCAN t1 USING INDEX i1} do_execsql_test 3.1 { CREATE TABLE t5(a INTEGER PRIMARY KEY,b,c,d,e,f,g); CREATE INDEX t5b ON t5(b); CREATE INDEX t5c ON t5(c); CREATE INDEX t5d ON t5(d); CREATE INDEX t5e ON t5(e); CREATE INDEX t5f ON t5(f); CREATE INDEX t5g ON t5(g); } do_eqp_test 3.2 { SELECT a FROM t5 WHERE b IS NULL OR c IS NULL OR d IS NULL ORDER BY a; } { QUERY PLAN |--MULTI-INDEX OR | |--INDEX 1 | | `--SEARCH t5 USING INDEX t5b (b=?) | |--INDEX 2 | | `--SEARCH t5 USING INDEX t5c (c=?) | `--INDEX 3 | `--SEARCH t5 USING INDEX t5d (d=?) `--USE TEMP B-TREE FOR ORDER BY } #------------------------------------------------------------------------- # If there is no likelihood() or stat3 data, SQLite assumes that a closed # range scan (e.g. one constrained by "col BETWEEN ? AND ?" constraint) # visits 1/64 of the rows in a table. # # Note: 1/63 =~ 0.016 # Note: 1/65 =~ 0.015 # reset_db do_execsql_test 4.1 { CREATE TABLE t1(a, b); CREATE INDEX i1 ON t1(a); CREATE INDEX i2 ON t1(b); } do_eqp_test 4.2 { SELECT * FROM t1 WHERE likelihood(a=?, 0.014) AND b BETWEEN ? AND ?; } {SEARCH t1 USING INDEX i1 (a=?)} do_eqp_test 4.3 { SELECT * FROM t1 WHERE likelihood(a=?, 0.016) AND b BETWEEN ? AND ?; } {SEARCH t1 USING INDEX i2 (b>? AND b<?)} #------------------------------------------------------------------------- # reset_db do_execsql_test 5.1 { CREATE TABLE t2(x, y); CREATE INDEX t2i1 ON t2(x); } do_eqp_test 5.2 { SELECT * FROM t2 ORDER BY x, y; } { QUERY PLAN |--SCAN t2 USING INDEX t2i1 `--USE TEMP B-TREE FOR RIGHT PART OF ORDER BY } do_eqp_test 5.3 { SELECT * FROM t2 WHERE x BETWEEN ? AND ? ORDER BY rowid; } { QUERY PLAN |--SEARCH t2 USING INDEX t2i1 (x>? AND x<?) `--USE TEMP B-TREE FOR ORDER BY } # where7.test, where8.test: # do_execsql_test 6.1 { CREATE TABLE t3(a INTEGER PRIMARY KEY, b, c); CREATE INDEX t3i1 ON t3(b); CREATE INDEX t3i2 ON t3(c); } do_eqp_test 6.2 { SELECT a FROM t3 WHERE (b BETWEEN 2 AND 4) OR c=100 ORDER BY a } { QUERY PLAN |--MULTI-INDEX OR | |--INDEX 1 | | `--SEARCH t3 USING INDEX t3i1 (b>? AND b<?) | `--INDEX 2 | `--SEARCH t3 USING INDEX t3i2 (c=?) `--USE TEMP B-TREE FOR ORDER BY } #------------------------------------------------------------------------- # reset_db do_execsql_test 7.1 { |
︙ | ︙ | |||
145 146 147 148 149 150 151 | do_eqp_test 7.2 { SELECT a FROM t1 WHERE (b>=950 AND b<=1010) OR (b IS NULL AND c NOT NULL) ORDER BY a } { QUERY PLAN |--MULTI-INDEX OR | > | > | | | | 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 | do_eqp_test 7.2 { SELECT a FROM t1 WHERE (b>=950 AND b<=1010) OR (b IS NULL AND c NOT NULL) ORDER BY a } { QUERY PLAN |--MULTI-INDEX OR | |--INDEX 1 | | `--SEARCH t1 USING INDEX t1b (b>? AND b<?) | `--INDEX 2 | `--SEARCH t1 USING INDEX t1b (b=?) `--USE TEMP B-TREE FOR ORDER BY } do_eqp_test 7.3 { SELECT rowid FROM t1 WHERE (+b IS NULL AND c NOT NULL AND d NOT NULL) OR (b NOT NULL AND c IS NULL AND d NOT NULL) OR (b NOT NULL AND c NOT NULL AND d IS NULL) } {SCAN t1} do_eqp_test 7.4 { SELECT rowid FROM t1 WHERE (+b IS NULL AND c NOT NULL) OR c IS NULL } {SCAN t1} #------------------------------------------------------------------------- # reset_db do_execsql_test 8.1 { CREATE TABLE composer( cid INTEGER PRIMARY KEY, |
︙ | ︙ | |||
191 192 193 194 195 196 197 | SELECT DISTINCT aname FROM album, composer, track WHERE cname LIKE '%bach%' AND unlikely(composer.cid=track.cid) AND unlikely(album.aid=track.aid); } { QUERY PLAN | | | | | 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 | SELECT DISTINCT aname FROM album, composer, track WHERE cname LIKE '%bach%' AND unlikely(composer.cid=track.cid) AND unlikely(album.aid=track.aid); } { QUERY PLAN |--SCAN track |--SEARCH album USING INTEGER PRIMARY KEY (rowid=?) |--SEARCH composer USING INTEGER PRIMARY KEY (rowid=?) `--USE TEMP B-TREE FOR DISTINCT } #------------------------------------------------------------------------- # do_execsql_test 9.1 { CREATE TABLE t1( |
︙ | ︙ | |||
219 220 221 222 223 224 225 | CREATE INDEX i2 ON t1(a,b,c,d,e,f,g,h,i,j); } } {} set L [list a=? b=? c=? d=? e=? f=? g=? h=? i=? j=?] foreach {tn nTerm nRow} { 1 1 10 | | | | 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 | CREATE INDEX i2 ON t1(a,b,c,d,e,f,g,h,i,j); } } {} set L [list a=? b=? c=? d=? e=? f=? g=? h=? i=? j=?] foreach {tn nTerm nRow} { 1 1 10 2 2 10 3 3 8 4 4 7 5 5 7 6 6 5 7 7 5 8 8 5 9 9 5 10 10 5 } { set w [join [lrange $L 0 [expr $nTerm-1]] " AND "] |
︙ | ︙ | |||
260 261 262 263 264 265 266 | execsql { INSERT INTO t6 VALUES($i%4, 'xyz', $i%8) } } execsql ANALYZE } {} do_eqp_test 10.3 { SELECT rowid FROM t6 WHERE a=0 AND c=0 | | | | | | 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 | execsql { INSERT INTO t6 VALUES($i%4, 'xyz', $i%8) } } execsql ANALYZE } {} do_eqp_test 10.3 { SELECT rowid FROM t6 WHERE a=0 AND c=0 } {SEARCH t6 USING INDEX t6i2 (c=?)} do_eqp_test 10.4 { SELECT rowid FROM t6 WHERE a=0 AND b='xyz' AND c=0 } {SEARCH t6 USING INDEX t6i2 (c=?)} do_eqp_test 10.5 { SELECT rowid FROM t6 WHERE likelihood(a=0, 0.1) AND c=0 } {SEARCH t6 USING INDEX t6i1 (a=?)} do_eqp_test 10.6 { SELECT rowid FROM t6 WHERE likelihood(a=0, 0.1) AND b='xyz' AND c=0 } {SEARCH t6 USING INDEX t6i1 (a=? AND b=?)} } finish_test |
Changes to test/count.test.
︙ | ︙ | |||
191 192 193 194 195 196 197 198 199 | SELECT count(*) FROM t5; } {1} do_catchsql_test count-6.1 { CREATE TABLE t6(x); SELECT count(DISTINCT) FROM t6 GROUP BY x; } {1 {DISTINCT aggregates must have exactly one argument}} finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | SELECT count(*) FROM t5; } {1} do_catchsql_test count-6.1 { CREATE TABLE t6(x); SELECT count(DISTINCT) FROM t6 GROUP BY x; } {1 {DISTINCT aggregates must have exactly one argument}} # 2020-05-08. # The count() optimization should honor the NOT INDEXED clause # reset_db do_execsql_test count-7.1 { CREATE TABLE t1(a INTEGER PRIMARY KEY, b INT, c VARCHAR(1000)); CREATE INDEX t1b ON t1(b); INSERT INTO t1(a,b,c) values(1,2,'count.test cases for NOT INDEXED'); ANALYZE; UPDATE sqlite_stat1 SET stat='1000000 10' WHERE idx='t1b'; ANALYZE sqlite_master; } do_eqp_test count-7.2 { SELECT count(1) FROM t1; } { QUERY PLAN `--SCAN t1 USING COVERING INDEX t1b } do_eqp_test count-7.3 { SELECT count(1) FROM t1 NOT INDEXED } { QUERY PLAN `--SCAN t1 } do_eqp_test count-7.3 { SELECT count(*) FROM t1; } { QUERY PLAN `--SCAN t1 USING COVERING INDEX t1b } do_eqp_test count-7.4 { SELECT count(*) FROM t1 NOT INDEXED } { QUERY PLAN `--SCAN t1 } do_execsql_test count-8.0 { CREATE TABLE t7(a INT,b TEXT,c BLOB,d REAL); CREATE TABLE t8(a INT,b TEXT,c BLOB,d REAL); CREATE INDEX t8a ON t8(a); } do_catchsql_test count-8.1 { SELECT * FROM t8 WHERE (a, b) IN ( SELECT count(t8.b), count(*) FROM t7 AS ra0 ORDER BY count(*) ) AND t8.b=0; } {1 {misuse of aggregate: count()}} finish_test |
Changes to test/countofview.test.
︙ | ︙ | |||
35 36 37 38 39 40 41 42 43 | } {1} do_execsql_test 1.3 { select count(*) from ( select c from t2 union all select f from t3 ) } {3} finish_test | > > > > > > > > > > > > > | 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | } {1} do_execsql_test 1.3 { select count(*) from ( select c from t2 union all select f from t3 ) } {3} # 2019-05-15 do_execsql_test 2.0 { CREATE TABLE t1(x); INSERT INTO t1 VALUES(1),(99),('abc'); CREATE VIEW v1(x,y) AS SELECT x,1 FROM t1 UNION ALL SELECT x,2 FROM t1; SELECT count(*) FROM v1 WHERE x<>1; } {4} do_execsql_test 2.1 { SELECT count(*) FROM v1 GROUP BY y; } {3 3} finish_test |
Changes to test/coveridxscan.test.
︙ | ︙ | |||
105 106 107 108 109 110 111 | CREATE TABLE t2(i INTEGER PRIMARY KEY, $cols); CREATE INDEX i2 ON t2($cols); " do_eqp_test 5.1.1 { SELECT * FROM t1 ORDER BY c1, c2; | | | | 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 | CREATE TABLE t2(i INTEGER PRIMARY KEY, $cols); CREATE INDEX i2 ON t2($cols); " do_eqp_test 5.1.1 { SELECT * FROM t1 ORDER BY c1, c2; } {SCAN t1 USING COVERING INDEX i1} do_eqp_test 5.1.2 { SELECT * FROM t2 ORDER BY c1, c2; } {SCAN t2 USING COVERING INDEX i2} finish_test |
Changes to test/crash5.test.
︙ | ︙ | |||
17 18 19 20 21 22 23 | set testdir [file dirname $argv0] source $testdir/tester.tcl # Only run these tests if memory debugging is turned on. # ifcapable !crashtest||!memorymanage { | | | > > > > > > > > > > > > > > | | > > | | | | | | | | | | | | | | | | | | | | | | | | | | | > | 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 | set testdir [file dirname $argv0] source $testdir/tester.tcl # Only run these tests if memory debugging is turned on. # ifcapable !crashtest||!memorymanage { puts "Skipping crash5 tests: not compiled with -DSQLITE_ENABLE_MEMORY_MANAGEMENT..." finish_test return } db close for {set ii 0} {$ii < 10} {incr ii} { for {set jj 1} {$jj < 100} {incr jj} { # Set up the database so that it is an auto-vacuum database # containing a single table (root page 3) with a single row. # The row has an overflow page (page 4). forcedelete test.db test.db-journal sqlite3 db test.db set c [string repeat 3 1500] db eval { pragma auto_vacuum = 1; CREATE TABLE t1(a, b, c); INSERT INTO t1 VALUES('1111111111', '2222222222', $c); } db close do_test crash5-$ii.$jj.1 { crashsql -delay 1 -file test.db-journal -seed $ii -tclbody [join [list \ [list set iFail $jj] { proc get_pwd {} { if {$::tcl_platform(platform) eq "windows"} { if {[info exists ::env(ComSpec)]} { set comSpec $::env(ComSpec) } else { # NOTE: Hard-code the typical default value. set comSpec {C:\Windows\system32\cmd.exe} } return [string map [list \\ /] \ [string trim [exec -- $comSpec /c echo %CD%]]] } else { return [pwd] } } sqlite3_crashparams 0 [file join [get_pwd] test.db-journal] # Begin a transaction and evaluate a "CREATE INDEX" statement # with the iFail'th malloc() set to fail. This operation will # have to move the current contents of page 4 (the overflow # page) to make room for the new root page. The bug is that # if malloc() fails at a particular point in sqlite3PagerMovepage(), # sqlite mistakenly thinks that the page being moved (page 4) has # been safely synced into the journal. If the page is written # to later in the transaction, it may be written out to the database # before the relevant part of the journal has been synced. # db eval BEGIN sqlite3_memdebug_fail $iFail -repeat 0 set rc [catch {db eval { CREATE UNIQUE INDEX i1 ON t1(a); }} msg] # puts "$msg ac=[sqlite3_get_autocommit db] iFail=$iFail" # puts "fail=[sqlite3_memdebug_fail -1]" if {$rc} { # 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 INSERT INTO t1 SELECT * FROM t1; -- 4 INSERT INTO t1 SELECT * FROM t1; -- 8 INSERT INTO t1 SELECT * FROM t1; -- 16 INSERT INTO t1 SELECT * FROM t1; -- 32 INSERT INTO t1 SELECT * FROM t1 WHERE rowid%2; -- 48 } } # If the right malloc() failed during the 'CREATE INDEX' above and # the transaction was not rolled back, then the sqlite cache now # has a dirty page 4 that it incorrectly believes is already safely # in the synced part of the journal file. When # sqlite3_release_memory() is called sqlite tries to free memory # by writing page 4 out to the db file. If it crashes later on, # before syncing the journal... Corruption! # sqlite3_crashparams 1 [file join [get_pwd] test.db-journal] sqlite3_release_memory 8092 } }]] {} expr 1 } {1} sqlite3 db test.db do_test crash5-$ii.$jj.2 { db eval {pragma integrity_check} |
︙ | ︙ |
Changes to test/createtab.test.
︙ | ︙ | |||
8 9 10 11 12 13 14 | # 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 it is OK to create new tables # and indices while creating existing tables and indices. # | < | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | # 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 it is OK to create new tables # and indices while creating existing tables and indices. # set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable autovacuum { set upperBound 2 } else { |
︙ | ︙ | |||
138 139 140 141 142 143 144 | execsql { SELECT name FROM sqlite_master WHERE type='table' ORDER BY 1 } } {t1 t2 t3 t4} integrity_check createtab-$av.40 } | | > > > > > > > > > | 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 | execsql { SELECT name FROM sqlite_master WHERE type='table' ORDER BY 1 } } {t1 t2 t3 t4} integrity_check createtab-$av.40 } # 2019-03-31 Ensure that a proper error is returned for an index # with too many columns. # do_test createtab-3.1 { db eval {DROP TABLE IF EXISTS t1;} set sql "CREATE TABLE t1(x,UNIQUE(x[string repeat ,x 100000]))" catchsql $sql } {1 {too many columns in index}} finish_test |
Changes to test/cse.test.
︙ | ︙ | |||
14 15 16 17 18 19 20 21 22 23 24 25 26 27 | # common subexpression eliminations. # # $Id: cse.test,v 1.6 2008/08/04 03:51:24 danielk1977 Exp $ # set testdir [file dirname $argv0] source $testdir/tester.tcl do_test cse-1.1 { execsql { CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c, d, e, f); INSERT INTO t1 VALUES(1,11,12,13,14,15); INSERT INTO t1 VALUES(2,21,22,23,24,25); } | > | 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | # common subexpression eliminations. # # $Id: cse.test,v 1.6 2008/08/04 03:51:24 danielk1977 Exp $ # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix cse do_test cse-1.1 { execsql { CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c, d, e, f); INSERT INTO t1 VALUES(1,11,12,13,14,15); INSERT INTO t1 VALUES(2,21,22,23,24,25); } |
︙ | ︙ | |||
152 153 154 155 156 157 158 159 160 | } set sql "SELECT [join $colset ,] FROM t2" do_test cse-2.2.$i { # explain $::sql execsql $::sql } $answer } finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | } set sql "SELECT [join $colset ,] FROM t2" do_test cse-2.2.$i { # explain $::sql execsql $::sql } $answer } #------------------------------------------------------------------------- # Ticket fd1bda016d1a # reset_db do_execsql_test 3.0 { CREATE TABLE t1(a TEXT, b); INSERT INTO t1 VALUES('hello', 0); INSERT INTO t1 VALUES('world', 0); CREATE TABLE t2(x TEXT); INSERT INTO t2 VALUES('hello'); INSERT INTO t2 VALUES('world'); CREATE TABLE t3(y); INSERT INTO t3 VALUES(1000); } {} do_execsql_test 3.1 { SELECT 1000 = y FROM t3 } {1} do_execsql_test 3.2 { SELECT 1000 IN (SELECT x FROM t2), 1000 = y FROM t3 } {0 1} do_execsql_test 3.3 { SELECT 0 IN (SELECT a), (SELECT a LIMIT 0) FROM t1 } {0 {} 0 {}} do_execsql_test 3.4 { SELECT 0 IN (SELECT a) FROM t1 WHERE a = 'hello' OR (SELECT a LIMIT 0); } {0} do_execsql_test 3.5 { CREATE TABLE v0(v1 VARCHAR0); INSERT INTO v0 VALUES(2), (3); SELECT 0 IN(SELECT v1) FROM v0 WHERE v1 = 2 OR(SELECT v1 LIMIT 0); } {0} finish_test |
Changes to test/csv01.test.
︙ | ︙ | |||
210 211 212 213 214 215 216 217 | # by Trent W. Buck. # do_execsql_test 4.4 { CREATE VIRTUAL TABLE temp.trent USING csv(data='1'); SELECT * FROM trent; } {1} finish_test | > > > > > > > > > > > > > > > > > > > > > > > | 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 | # by Trent W. Buck. # do_execsql_test 4.4 { CREATE VIRTUAL TABLE temp.trent USING csv(data='1'); SELECT * FROM trent; } {1} # 2018-12-26 # Bug report on the mailing list # forcedelete csv01.csv set fd [open csv01.csv wb] puts $fd "a,b,c,d\r\n1,2,3,4\r\none,two,three,four\r\n5,6,7,8" close $fd do_execsql_test 5.1 { CREATE VIRTUAL TABLE t5_1 USING csv(filename='csv01.csv'); SELECT name FROM temp.pragma_table_info('t5_1'); } {c0 c1 c2 c3} do_execsql_test 5.2 { SELECT *, '|' FROM t5_1; } {a b c d | 1 2 3 4 | one two three four | 5 6 7 8 |} do_execsql_test 5.3 { DROP TABLE t5_1; CREATE VIRTUAL TABLE t5_1 USING csv(filename='csv01.csv', header); SELECT name FROM temp.pragma_table_info('t5_1'); } {a b c d} do_execsql_test 5.4 { SELECT *, '|' FROM t5_1; } {1 2 3 4 | one two three four | 5 6 7 8 |} finish_test |
Changes to test/cursorhint.test.
︙ | ︙ | |||
65 66 67 68 69 70 71 | SELECT * FROM t1 CROSS JOIN t2 WHERE a=x } } {{EQ(r[1],c0)}} do_test 1.2 { p5_of_opcode db OpenRead { SELECT * FROM t1 CROSS JOIN t2 WHERE a=x } | | | | 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 | SELECT * FROM t1 CROSS JOIN t2 WHERE a=x } } {{EQ(r[1],c0)}} do_test 1.2 { p5_of_opcode db OpenRead { SELECT * FROM t1 CROSS JOIN t2 WHERE a=x } } {0 0} # Do the same test the other way around. # do_test 2.1 { p4_of_opcode db CursorHint { SELECT * FROM t2 CROSS JOIN t1 WHERE a=x } } {{EQ(c0,r[1])}} do_test 2.2 { p5_of_opcode db OpenRead { SELECT * FROM t2 CROSS JOIN t1 WHERE a=x } } {0 0} # Various expressions captured by CursorHint # do_test 3.1 { p4_of_opcode db CursorHint { SELECT * FROM t1 WHERE a=15 AND c=22 AND rowid!=98 } |
︙ | ︙ | |||
113 114 115 116 117 118 119 | SELECT * FROM t1 WHERE b>11 ORDER BY b DESC; } } {GT(c0,11)} do_test 4.2 { p5_of_opcode db OpenRead { SELECT * FROM t1 WHERE b>11; } | | | | 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 | SELECT * FROM t1 WHERE b>11 ORDER BY b DESC; } } {GT(c0,11)} do_test 4.2 { p5_of_opcode db OpenRead { SELECT * FROM t1 WHERE b>11; } } {2 0} do_test 4.3asc { p4_of_opcode db CursorHint { SELECT c FROM t1 WHERE b<11 ORDER BY b ASC; } } {LT(c0,11)} do_test 4.3desc { p4_of_opcode db CursorHint { SELECT c FROM t1 WHERE b<11 ORDER BY b DESC; } } {} do_test 4.4 { p5_of_opcode db OpenRead { SELECT c FROM t1 WHERE b<11; } } {0} do_test 4.5asc { p4_of_opcode db CursorHint { SELECT c FROM t1 WHERE b>=10 AND b<=20 ORDER BY b ASC; } } {LE(c0,20)} do_test 4.5desc { |
︙ | ︙ |
Changes to test/date2.test.
︙ | ︙ | |||
26 27 28 29 30 31 32 | do_execsql_test date2-100 { CREATE TABLE t1(x, y, CHECK( date(x) BETWEEN '2017-07-01' AND '2017-07-31' )); INSERT INTO t1(x,y) VALUES('2017-07-20','one'); } {} do_catchsql_test date2-110 { INSERT INTO t1(x,y) VALUES('now','two'); | | | > > > > > > > | | | 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 | do_execsql_test date2-100 { CREATE TABLE t1(x, y, CHECK( date(x) BETWEEN '2017-07-01' AND '2017-07-31' )); INSERT INTO t1(x,y) VALUES('2017-07-20','one'); } {} do_catchsql_test date2-110 { INSERT INTO t1(x,y) VALUES('now','two'); } {1 {non-deterministic use of date() in a CHECK constraint}} do_execsql_test date2-120 { SELECT * FROM t1; } {2017-07-20 one} do_catchsql_test date2-130 { INSERT INTO t1(x,y) VALUES('2017-08-01','two'); } {1 {CHECK constraint failed: date(x) BETWEEN '2017-07-01' AND '2017-07-31'}} # 2021-03-16 Forum post https://sqlite.org/forum/forumpost/464afd4086 do_catchsql_test date2-140 { DROP TABLE t1; CREATE TABLE t1(x, y, z AS (date())); INSERT INTO t1(x,y) VALUES(1,2); } {1 {non-deterministic use of date() in a generated column}} do_execsql_test date2-200 { CREATE TABLE t2(x,y); INSERT INTO t2(x,y) VALUES(1, '2017-07-20'), (2, 'xyzzy'); CREATE INDEX t2y ON t2(date(y)); } do_catchsql_test date2-210 { INSERT INTO t2(x,y) VALUES(3, 'now'); } {1 {non-deterministic use of date() in an index}} do_execsql_test date2-220 { SELECT x, y FROM t2 ORDER BY x; } {1 2017-07-20 2 xyzzy} do_execsql_test date2-300 { CREATE TABLE t3(a INTEGER PRIMARY KEY,b); WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<1000) INSERT INTO t3(a,b) SELECT x, julianday('2017-07-01')+x FROM c; UPDATE t3 SET b='now' WHERE a=500; } do_catchsql_test date2-310 { CREATE INDEX t3b1 ON t3(datetime(b)); } {1 {non-deterministic use of datetime() in an index}} do_catchsql_test date2-320 { CREATE INDEX t3b1 ON t3(datetime(b)) WHERE typeof(b)='real'; } {0 {}} do_execsql_test date2-330 { EXPLAIN QUERY PLAN SELECT a FROM t3 WHERE typeof(b)='real' |
︙ | ︙ | |||
80 81 82 83 84 85 86 | WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<1000) INSERT INTO t4(a,b) SELECT x, julianday('2017-07-01')+x FROM c; UPDATE t4 SET b='now' WHERE a=500; } do_catchsql_test date2-410 { CREATE INDEX t4b1 ON t4(b) WHERE date(b) BETWEEN '2017-06-01' AND '2017-08-31'; | | | | 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 | WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<1000) INSERT INTO t4(a,b) SELECT x, julianday('2017-07-01')+x FROM c; UPDATE t4 SET b='now' WHERE a=500; } do_catchsql_test date2-410 { CREATE INDEX t4b1 ON t4(b) WHERE date(b) BETWEEN '2017-06-01' AND '2017-08-31'; } {1 {non-deterministic use of date() in an index}} do_execsql_test date2-420 { DELETE FROM t4 WHERE a=500; CREATE INDEX t4b1 ON t4(b) WHERE date(b) BETWEEN '2017-06-01' AND '2017-08-31'; } do_catchsql_test date2-430 { INSERT INTO t4(a,b) VALUES(9999,'now'); } {1 {non-deterministic use of date() in an index}} do_execsql_test date2-500 { CREATE TABLE mods(x); INSERT INTO mods(x) VALUES ('+10 days'), ('-10 days'), ('+10 hours'), |
︙ | ︙ | |||
117 118 119 120 121 122 123 | CREATE TABLE t5(y,m); WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<5) INSERT INTO t5(y,m) SELECT julianday('2017-07-01')+c.x, mods.x FROM c, mods; CREATE INDEX t5x1 on t5(y) WHERE datetime(y,m) IS NOT NULL; } do_catchsql_test date2-510 { INSERT INTO t5(y,m) VALUES('2017-07-20','localtime'); | | | > | > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > | 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 | CREATE TABLE t5(y,m); WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<5) INSERT INTO t5(y,m) SELECT julianday('2017-07-01')+c.x, mods.x FROM c, mods; CREATE INDEX t5x1 on t5(y) WHERE datetime(y,m) IS NOT NULL; } do_catchsql_test date2-510 { INSERT INTO t5(y,m) VALUES('2017-07-20','localtime'); } {1 {non-deterministic use of datetime() in an index}} do_catchsql_test date2-520 { INSERT INTO t5(y,m) VALUES('2017-07-20','utc'); } {1 {non-deterministic use of datetime() in an index}} # 2019-10-30 Ticket 830277d9db6c3ba1 # do_catchsql_test date2-600 { CREATE TABLE t600(a REAL CHECK( a<julianday('now') )); INSERT INTO t600(a) VALUES(1.0); } {1 {non-deterministic use of julianday() in a CHECK constraint}} do_catchsql_test date2-601 { CREATE TABLE t601(a REAL, b TEXT, CHECK( a<julianday(b) )); INSERT INTO t601(a,b) VALUES(1.0, '1970-01-01'); } {0 {}} do_catchsql_test date2-602 { INSERT INTO t601(a,b) VALUES(1e100, '1970-01-01'); } {1 {CHECK constraint failed: a<julianday(b)}} do_catchsql_test date2-603 { INSERT INTO t601(a,b) VALUES(10, 'now'); } {1 {non-deterministic use of julianday() in a CHECK constraint}} do_catchsql_test date2-604 { INSERT INTO t600(a) VALUES(julianday('now')+10); } {1 {non-deterministic use of julianday() in a CHECK constraint}} do_catchsql_test date2-610 { CREATE TABLE t610(a,b); CREATE INDEX t610x1 ON t610(julianday('now')+b); INSERT INTO t610(a,b) VALUES(123,456); } {1 {non-deterministic use of julianday() in an index}} do_catchsql_test date2-611 { CREATE TABLE t611(a,b); CREATE INDEX t611x1 ON t611(julianday(a)+b); INSERT INTO t611(a,b) VALUES('1970-01-01',10.0); } {0 {}} do_catchsql_test date2-612 { INSERT INTO t611(a,b) VALUES('now',10.0); } {1 {non-deterministic use of julianday() in an index}} do_catchsql_test date3-620 { CREATE TABLE t620(a, b AS (a+julianday('now'))); INSERT INTO t620 VALUES(10); } {1 {non-deterministic use of julianday() in a generated column}} finish_test |
Added test/dbdata.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 | # 2019-04-11 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this file is testing the sqlite_dbpage virtual table. # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix dbdata ifcapable !vtab||!compound { finish_test return } if { [catch { db enable_load_extension 1 }] || [catch { db eval { SELECT load_extension('../dbdata') } }] } { finish_test return } do_execsql_test 1.0 { CREATE TABLE T1(a, b); INSERT INTO t1(rowid, a ,b) VALUES(5, 'v', 'five'); INSERT INTO t1(rowid, a, b) VALUES(10, 'x', 'ten'); } do_execsql_test 1.1 { SELECT pgno, cell, field, quote(value) FROM sqlite_dbdata WHERE pgno=2; } { 2 0 -1 5 2 0 0 'v' 2 0 1 'five' 2 1 -1 10 2 1 0 'x' 2 1 1 'ten' } breakpoint do_execsql_test 1.2 { SELECT pgno, cell, field, quote(value) FROM sqlite_dbdata; } { 1 0 -1 1 1 0 0 'table' 1 0 1 'T1' 1 0 2 'T1' 1 0 3 2 1 0 4 {'CREATE TABLE T1(a, b)'} 2 0 -1 5 2 0 0 'v' 2 0 1 'five' 2 1 -1 10 2 1 0 'x' 2 1 1 'ten' } set big [string repeat big 2000] do_execsql_test 1.3 { INSERT INTO t1 VALUES(NULL, $big); SELECT value FROM sqlite_dbdata WHERE pgno=2 AND cell=2 AND field=1; } $big do_execsql_test 1.4 { DELETE FROM t1; INSERT INTO t1 VALUES(NULL, randomblob(5050)); } do_test 1.5 { execsql { SELECT quote(value) FROM sqlite_dbdata WHERE pgno=2 AND cell=0 AND field=1; } } [db one {SELECT quote(b) FROM t1}] #------------------------------------------------------------------------- reset_db db enable_load_extension 1 db eval { SELECT load_extension('../dbdata') } do_execsql_test 2.0 { CREATE TABLE t1(a); CREATE INDEX i1 ON t1(a); WITH s(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<10 ) INSERT INTO t1 SELECT randomblob(900) FROM s; } do_execsql_test 2.1 { SELECT * FROM sqlite_dbptr WHERE pgno=2; } { 2 25 2 6 2 7 2 9 2 11 2 13 2 15 2 17 2 19 2 21 } do_execsql_test 2.2 { SELECT * FROM sqlite_dbptr WHERE pgno=3; } { 3 24 3 23 } do_execsql_test 2.3 { SELECT * FROM sqlite_dbptr } { 2 25 2 6 2 7 2 9 2 11 2 13 2 15 2 17 2 19 2 21 3 24 3 23 } finish_test |
Changes to test/dbfuzz001.test.
︙ | ︙ | |||
164 165 166 167 168 169 170 | | 432: 01 ec 01 c5 01 0d 43 00 00 48 01 54 00 01 f7 01 ......C..H.T.... | 448: ec 01 c5 01 0d 42 00 00 48 01 54 00 01 f7 01 ec .....B..H.T..... | 464: 01 c5 01 0d 41 00 00 48 01 54 00 01 f7 01 ec 01 ....A..H.T...... | 480: c5 01 0d 40 00 00 48 01 54 00 01 f7 01 ec 01 c5 ...@..H.T....... | 496: 01 0d 3f 00 00 48 01 54 00 01 f7 01 ec 01 c5 01 ..?..H.T........ | end c4.db }] | > > > > > | | > > > > > > > | 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 | | 432: 01 ec 01 c5 01 0d 43 00 00 48 01 54 00 01 f7 01 ......C..H.T.... | 448: ec 01 c5 01 0d 42 00 00 48 01 54 00 01 f7 01 ec .....B..H.T..... | 464: 01 c5 01 0d 41 00 00 48 01 54 00 01 f7 01 ec 01 ....A..H.T...... | 480: c5 01 0d 40 00 00 48 01 54 00 01 f7 01 ec 01 c5 ...@..H.T....... | 496: 01 0d 3f 00 00 48 01 54 00 01 f7 01 ec 01 c5 01 ..?..H.T........ | end c4.db }] } {} ifcapable !oversize_cell_check { # Non SQLITE_ENABLE_OVERSIZE_CELL_CHECK builds: do_test dbfuzz001-101a { db eval {PRAGMA writable_schema=on; PRAGMA integrity_check} } {/Fragmentation of 384 bytes reported as 0 on page 8/} } else { # SQLITE_ENABLE_OVERSIZE_CELL_CHECK builds: do_catchsql_test dbfuzz001-101b { PRAGMA writable_schema=on; PRAGMA integrity_check; } {1 {database disk image is malformed}} } # The DELETE query below deletes the very last cell from page 8. # Prior to a certain fix to sqlite3BtreeDelete() and because of the # corruption to the freeblock list on page 8, this would fail to # cause a rebalance operation, which would leave the btree in a weird # state that would lead to segfaults and or assertion faults. # |
︙ | ︙ | |||
266 267 268 269 270 271 272 | | 496: 07 40 18 00 04 02 01 04 03 03 02 01 04 03 02 02 .@.............. | end x/c03.db }] catchsql {INSERT INTO t3 SELECT * FROM t2;} } {1 {database disk image is malformed}} | | | 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 | | 496: 07 40 18 00 04 02 01 04 03 03 02 01 04 03 02 02 .@.............. | end x/c03.db }] catchsql {INSERT INTO t3 SELECT * FROM t2;} } {1 {database disk image is malformed}} do_test dbfuzz001-310 { sqlite3 db {} db deserialize [decode_hexdb { | size 3584 pagesize 512 filename x/c02.db | page 1 offset 0 | 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3. | 16: 02 00 01 01 00 40 20 20 00 00 00 0c 00 00 00 07 .....@ ........ | 32: 00 00 00 00 00 00 00 00 00 00 00 08 00 00 00 04 ................ |
︙ | ︙ | |||
289 290 291 292 293 294 295 | | 320: 41 54 45 20 49 4e 44 45 58 20 74 33 78 20 4f 4e ATE INDEX t3x ON | 336: 20 74 33 28 78 29 2e 04 06 17 15 11 01 45 69 6e t3(x).......Ein | 352: 64 65 78 74 32 63 64 74 32 05 43 52 45 41 54 45 dext2cdt2.CREATE | 368: 20 49 4e 44 45 58 20 74 32 63 64 20 4f 4e 20 74 INDEX t2cd ON t | 384: 32 28 63 2c 64 29 28 05 06 17 11 11 01 3d 74 61 2(c,d)(......=ta | 400: 62 6c 65 74 33 74 33 07 43 52 45 41 54 45 20 54 blet3t3.CREATE T | 416: 41 42 4c 45 20 74 33 28 63 2c 78 2c 65 2c 66 29 ABLE t3(c,x,e,f) | | | 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 | | 320: 41 54 45 20 49 4e 44 45 58 20 74 33 78 20 4f 4e ATE INDEX t3x ON | 336: 20 74 33 28 78 29 2e 04 06 17 15 11 01 45 69 6e t3(x).......Ein | 352: 64 65 78 74 32 63 64 74 32 05 43 52 45 41 54 45 dext2cdt2.CREATE | 368: 20 49 4e 44 45 58 20 74 32 63 64 20 4f 4e 20 74 INDEX t2cd ON t | 384: 32 28 63 2c 64 29 28 05 06 17 11 11 01 3d 74 61 2(c,d)(......=ta | 400: 62 6c 65 74 33 74 33 07 43 52 45 41 54 45 20 54 blet3t3.CREATE T | 416: 41 42 4c 45 20 74 33 28 63 2c 78 2c 65 2c 66 29 ABLE t3(c,x,e,f) | 432: 28 02 06 17 11 11 01 3d 74 61 62 6c 65 74 32 74 (......=tablet2t | 448: 32 32 43 52 45 41 54 45 20 54 41 42 4c 45 20 74 22CREATE TABLE t | 464: 32 28 63 2c 64 2c 65 2c 66 29 24 01 06 17 11 11 2(c,d,e,f)$..... | 480: 01 35 74 61 62 6c 65 74 31 74 31 02 43 52 45 41 .5tablet1t1.CREA | 496: 54 45 20 54 41 42 4c 45 20 74 31 28 61 2c 62 29 TE TABLE t1(a,b) | page 2 offset 512 | 0: 0d 00 00 00 04 01 cf 00 01 fa 01 f3 01 de 01 cf ................ | 160: 00 00 20 00 00 00 00 00 00 00 00 00 00 00 00 00 .. ............. |
︙ | ︙ | |||
343 344 345 346 347 348 349 | | 16: 01 e0 01 d4 01 cb 01 c2 00 00 00 00 00 00 00 00 ................ | 448: 00 00 07 08 02 17 65 69 67 68 74 07 07 02 17 65 ......eight....e | 464: 69 67 68 74 0a 06 02 07 40 18 00 00 00 00 00 00 ight....@....... | 480: 0a 05 02 07 40 18 00 00 00 00 00 00 03 04 02 01 ....@........... | 496: 04 03 03 02 01 04 03 02 02 01 02 03 01 02 01 02 ................ | end x/c02.db }] | | | > > > > | > > | > | 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 | | 16: 01 e0 01 d4 01 cb 01 c2 00 00 00 00 00 00 00 00 ................ | 448: 00 00 07 08 02 17 65 69 67 68 74 07 07 02 17 65 ......eight....e | 464: 69 67 68 74 0a 06 02 07 40 18 00 00 00 00 00 00 ight....@....... | 480: 0a 05 02 07 40 18 00 00 00 00 00 00 03 04 02 01 ....@........... | 496: 04 03 03 02 01 04 03 02 02 01 02 03 01 02 01 02 ................ | end x/c02.db }] } {} extra_schema_checks 0 do_catchsql_test dbfuzz001-320 { PRAGMA integrity_check; } {1 {database disk image is malformed}} do_catchsql_test dbfuzz001-330 { DELETE FROM t3 WHERE x IN (SELECT x FROM t4); } {1 {database disk image is malformed}} extra_schema_checks 1 finish_test |
Changes to test/dbfuzz2.c.
︙ | ︙ | |||
27 28 29 30 31 32 33 | ** ** Any of these tables can be virtual tables, for example FTS or RTree tables. ** ** To run this test: ** ** mkdir dir ** cp dbfuzz2-seed*.db dir | | < > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > | < < < < > > > > > > > > | > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | < > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | ** ** Any of these tables can be virtual tables, for example FTS or RTree tables. ** ** To run this test: ** ** mkdir dir ** cp dbfuzz2-seed*.db dir ** clang-6.0 -I. -g -O1 -fsanitize=fuzzer -DTHREADSAFE=0 \ ** -DSQLITE_ENABLE_DBSTAT_VTAB dbfuzz2.c sqlite3.c -ldl ** ./a.out dir */ #include <assert.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdarg.h> #include <ctype.h> #include <stdint.h> #ifndef _WIN32 #include <sys/time.h> #include <sys/resource.h> #endif #include "sqlite3.h" /* ** This is the is the SQL that is run against the database. */ static const char *azSql[] = { "PRAGMA integrity_check;", "SELECT * FROM sqlite_schema;", "SELECT sum(length(name)) FROM dbstat;", "UPDATE t1 SET b=a, a=b WHERE a<b;", "ALTER TABLE t1 RENAME TO alkjalkjdfiiiwuer987lkjwer82mx97sf98788s9789s;", "INSERT INTO t3 SELECT * FROM t2;", "DELETE FROM t3 WHERE x IN (SELECT x FROM t4);", "REINDEX;", "DROP TABLE t3;", "VACUUM;", }; /* Output verbosity level. 0 means complete silence */ int eVerbosity = 0; /* True to activate PRAGMA vdbe_debug=on */ static int bVdbeDebug = 0; /* Maximum size of the in-memory database file */ static sqlite3_int64 szMax = 104857600; /* Progress handler callback data */ static int nCb = 0; /* Number of callbacks seen so far */ static int mxCb = 250000; /* Maximum allowed callbacks */ /***** Copy/paste from ext/misc/memtrace.c ***************************/ /* The original memory allocation routines */ static sqlite3_mem_methods memtraceBase; static FILE *memtraceOut; /* Methods that trace memory allocations */ static void *memtraceMalloc(int n){ if( memtraceOut ){ fprintf(memtraceOut, "MEMTRACE: allocate %d bytes\n", memtraceBase.xRoundup(n)); } return memtraceBase.xMalloc(n); } static void memtraceFree(void *p){ if( p==0 ) return; if( memtraceOut ){ fprintf(memtraceOut, "MEMTRACE: free %d bytes\n", memtraceBase.xSize(p)); } memtraceBase.xFree(p); } static void *memtraceRealloc(void *p, int n){ if( p==0 ) return memtraceMalloc(n); if( n==0 ){ memtraceFree(p); return 0; } if( memtraceOut ){ fprintf(memtraceOut, "MEMTRACE: resize %d -> %d bytes\n", memtraceBase.xSize(p), memtraceBase.xRoundup(n)); } return memtraceBase.xRealloc(p, n); } static int memtraceSize(void *p){ return memtraceBase.xSize(p); } static int memtraceRoundup(int n){ return memtraceBase.xRoundup(n); } static int memtraceInit(void *p){ return memtraceBase.xInit(p); } static void memtraceShutdown(void *p){ memtraceBase.xShutdown(p); } /* The substitute memory allocator */ static sqlite3_mem_methods ersaztMethods = { memtraceMalloc, memtraceFree, memtraceRealloc, memtraceSize, memtraceRoundup, memtraceInit, memtraceShutdown }; /* Begin tracing memory allocations to out. */ int sqlite3MemTraceActivate(FILE *out){ int rc = SQLITE_OK; if( memtraceBase.xMalloc==0 ){ rc = sqlite3_config(SQLITE_CONFIG_GETMALLOC, &memtraceBase); if( rc==SQLITE_OK ){ rc = sqlite3_config(SQLITE_CONFIG_MALLOC, &ersaztMethods); } } memtraceOut = out; return rc; } /* Deactivate memory tracing */ int sqlite3MemTraceDeactivate(void){ int rc = SQLITE_OK; if( memtraceBase.xMalloc!=0 ){ rc = sqlite3_config(SQLITE_CONFIG_MALLOC, &memtraceBase); if( rc==SQLITE_OK ){ memset(&memtraceBase, 0, sizeof(memtraceBase)); } } memtraceOut = 0; return rc; } /***** End copy/paste from ext/misc/memtrace.c ***************************/ /* ** Progress handler callback ** ** Count the number of callbacks and cause an abort once the limit is ** reached. */ static int progress_handler(void *pNotUsed){ nCb++; if( nCb<mxCb ) return 0; if( eVerbosity>=1 ){ printf("-- Progress limit of %d reached\n", mxCb); } return 1; } /* libFuzzer invokes this routine with fuzzed database files (in aData). ** This routine run SQLite against the malformed database to see if it ** can provoke a failure or malfunction. */ int LLVMFuzzerTestOneInput(const uint8_t *aData, size_t nByte){ unsigned char *a; sqlite3 *db; int rc; int i; sqlite3_int64 x; char *zErr = 0; if( eVerbosity>=1 ){ printf("************** nByte=%d ***************\n", (int)nByte); fflush(stdout); } if( sqlite3_initialize() ) return 0; rc = sqlite3_open(0, &db); if( rc ) return 1; a = sqlite3_malloc64(nByte+1); if( a==0 ) return 1; memcpy(a, aData, nByte); sqlite3_deserialize(db, "main", a, nByte, nByte, SQLITE_DESERIALIZE_RESIZEABLE | SQLITE_DESERIALIZE_FREEONCLOSE); x = szMax; #ifdef SQLITE_FCNTL_SIZE_LIMIT sqlite3_file_control(db, "main", SQLITE_FCNTL_SIZE_LIMIT, &x); #endif if( bVdbeDebug ){ sqlite3_exec(db, "PRAGMA vdbe_debug=ON", 0, 0, 0); } if( mxCb>0 ){ sqlite3_progress_handler(db, 10, progress_handler, 0); } #ifdef SQLITE_TESTCTRL_PRNG_SEED sqlite3_test_control(SQLITE_TESTCTRL_PRNG_SEED, 1, db); #endif for(i=0; i<sizeof(azSql)/sizeof(azSql[0]); i++){ if( eVerbosity>=1 ){ printf("%s\n", azSql[i]); fflush(stdout); } zErr = 0; nCb = 0; rc = sqlite3_exec(db, azSql[i], 0, 0, &zErr); if( rc && eVerbosity>=1 ){ printf("-- rc=%d zErr=%s\n", rc, zErr); } sqlite3_free(zErr); } rc = sqlite3_close(db); if( rc!=SQLITE_OK ){ fprintf(stdout, "sqlite3_close() returns %d\n", rc); } if( sqlite3_memory_used()!=0 ){ int nAlloc = 0; int nNotUsed = 0; sqlite3_status(SQLITE_STATUS_MALLOC_COUNT, &nAlloc, &nNotUsed, 0); fprintf(stderr,"Memory leak: %lld bytes in %d allocations\n", sqlite3_memory_used(), nAlloc); exit(1); } return 0; } /* ** Return the number of "v" characters in a string. Return 0 if there ** are any characters in the string other than "v". */ static int numberOfVChar(const char *z){ int N = 0; while( z[0] && z[0]=='v' ){ z++; N++; } return z[0]==0 ? N : 0; } /* libFuzzer invokes this routine once when the executable starts, to ** process the command-line arguments. */ int LLVMFuzzerInitialize(int *pArgc, char ***pArgv){ int i, j, n; int argc = *pArgc; char **argv = *pArgv; for(i=j=1; i<argc; i++){ char *z = argv[i]; if( z[0]=='-' ){ z++; if( z[0]=='-' ) z++; if( z[0]=='v' && (n = numberOfVChar(z))>0 ){ eVerbosity += n; continue; } if( strcmp(z,"vdbe-debug")==0 ){ bVdbeDebug = 1; continue; } if( strcmp(z,"limit")==0 ){ if( i+1==argc ){ fprintf(stderr, "missing argument to %s\n", argv[i]); exit(1); } mxCb = strtol(argv[++i], 0, 0); continue; } if( strcmp(z,"memtrace")==0 ){ sqlite3MemTraceActivate(stdout); continue; } if( strcmp(z,"max-db-size")==0 ){ if( i+1==argc ){ fprintf(stderr, "missing argument to %s\n", argv[i]); exit(1); } szMax = strtol(argv[++i], 0, 0); continue; } if( strcmp(z, "lookaside")==0 ){ int sz, nSlot; if( i+2>=argc ){ fprintf(stderr, "--lookaside requires two arguments: slot-size num-slots\n"); exit(1); } sz = atoi(argv[++i]); nSlot = atoi(argv[++i]); sqlite3_config(SQLITE_CONFIG_LOOKASIDE, sz, nSlot); continue; } #ifndef _WIN32 if( strcmp(z,"max-stack")==0 || strcmp(z,"max-data")==0 || strcmp(z,"max-as")==0 ){ struct rlimit x,y; int resource = RLIMIT_STACK; char *zType = "RLIMIT_STACK"; if( i+1==argc ){ fprintf(stderr, "missing argument to %s\n", argv[i]); exit(1); } if( z[4]=='d' ){ resource = RLIMIT_DATA; zType = "RLIMIT_DATA"; } if( z[4]=='a' ){ resource = RLIMIT_AS; zType = "RLIMIT_AS"; } memset(&x,0,sizeof(x)); getrlimit(resource, &x); y.rlim_cur = atoi(argv[++i]); y.rlim_max = x.rlim_cur; setrlimit(resource, &y); memset(&y,0,sizeof(y)); getrlimit(resource, &y); printf("%s changed from %d to %d\n", zType, (int)x.rlim_cur, (int)y.rlim_cur); continue; } #endif /* _WIN32 */ } argv[j++] = argv[i]; } argv[j] = 0; *pArgc = j; return 0; } #ifdef STANDALONE /* ** Read an entire file into memory. Space to hold the file comes ** from malloc(). */ static unsigned char *readFile(const char *zName, int *pnByte){ FILE *in = fopen(zName, "rb"); long nIn; size_t nRead; unsigned char *pBuf; if( in==0 ) return 0; fseek(in, 0, SEEK_END); nIn = ftell(in); rewind(in); pBuf = malloc( nIn+1 ); if( pBuf==0 ){ fclose(in); return 0; } nRead = fread(pBuf, nIn, 1, in); fclose(in); if( nRead!=1 ){ free(pBuf); return 0; } pBuf[nIn] = 0; if( pnByte ) *pnByte = nIn; return pBuf; } #endif /* STANDALONE */ #ifdef STANDALONE int main(int argc, char **argv){ int i; LLVMFuzzerInitialize(&argc, &argv); for(i=1; i<argc; i++){ unsigned char *pIn; int nIn; pIn = readFile(argv[i], &nIn); if( pIn ){ LLVMFuzzerTestOneInput((const uint8_t*)pIn, (size_t)nIn); free(pIn); } } #ifdef RUSAGE_SELF if( eVerbosity>0 ){ struct rusage x; printf("SQLite %s\n", sqlite3_sourceid()); memset(&x, 0, sizeof(x)); if( getrusage(RUSAGE_SELF, &x)==0 ){ printf("Maximum RSS = %ld KB\n", x.ru_maxrss); } } #endif return 0; } #endif /*STANDALONE*/ |
Changes to test/dbstatus.test.
︙ | ︙ | |||
59 60 61 62 63 64 65 | proc lookaside {db} { expr { $::lookaside_buffer_size * [lindex [sqlite3_db_status $db SQLITE_DBSTATUS_LOOKASIDE_USED 0] 1] } } | | | 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | proc lookaside {db} { expr { $::lookaside_buffer_size * [lindex [sqlite3_db_status $db SQLITE_DBSTATUS_LOOKASIDE_USED 0] 1] } } ifcapable stat4 { set STAT3 1 } else { set STAT3 0 } #--------------------------------------------------------------------------- # Run the dbstatus-2 and dbstatus-3 tests with several of different |
︙ | ︙ |
Added test/decimal.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 | # 2017 December 9 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix decimal if {[catch {load_static_extension db decimal} error]} { puts "Skipping decimal tests, hit load error: $error" finish_test; return } do_execsql_test 1000 { SELECT decimal(1); } {1} do_execsql_test 1010 { SELECT decimal(1.0); } {1.0} do_execsql_test 1020 { SELECT decimal(0001.0); } {1.0} do_execsql_test 1030 { SELECT decimal(+0001.0); } {1.0} do_execsql_test 1040 { SELECT decimal(-0001.0); } {-1.0} do_execsql_test 1050 { SELECT decimal(1.0e72); } {1000000000000000000000000000000000000000000000000000000000000000000000000} # 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123 do_execsql_test 1060 { SELECT decimal(1.0e-72); } {0.0000000000000000000000000000000000000000000000000000000000000000000000010} # 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123 do_execsql_test 1070 { SELECT decimal(-123e-4); } {-0.0123} do_execsql_test 1080 { SELECT decimal(+123e+4); } {1230000.0} do_execsql_test 2000 { CREATE TABLE t1(seq INTEGER PRIMARY KEY, val TEXT); INSERT INTO t1 VALUES (1, '-9999e99'), (2, '-9998.000e+99'), (3, '-9999.0'), (4, '-1'), (5, '-9999e-20'), (6, '0'), (7, '1e-30'), (8, '1e-29'), (9, '1'), (10,'1.00000000000000001'), (11,'+1.00001'), (12,'99e+99'); SELECT *, '|' FROM t1 AS a, t1 AS b WHERE a.seq<b.seq AND decimal_cmp(a.val,b.val)>=0; } {} do_execsql_test 2010 { SELECT *, '|' FROM t1 AS a, t1 AS b WHERE a.seq<>b.seq AND decimal_cmp(a.val,b.val)==0; } {} do_execsql_test 2020 { SELECT *, '|' FROM t1 AS a, t1 AS b WHERE a.seq>b.seq AND decimal_cmp(a.val,b.val)<=0; } {} do_execsql_test 2030 { SELECT seq FROM t1 ORDER BY val COLLATE decimal; } {1 2 3 4 5 6 7 8 9 10 11 12} do_execsql_test 2040 { SELECT seq FROM t1 ORDER BY val COLLATE decimal DESC; } {12 11 10 9 8 7 6 5 4 3 2 1} do_execsql_test 3000 { CREATE TABLE t3(seq INTEGER PRIMARY KEY, val TEXT); WITH RECURSIVE c(x) AS (VALUES(1) UNION SELECT x+1 FROM c WHERE x<10) INSERT INTO t3(seq, val) SELECT x, x FROM c; WITH RECURSIVE c(x) AS (VALUES(1) UNION SELECT x+1 FROM c WHERE x<5) INSERT INTO t3(seq, val) SELECT x+10, x*1000 FROM c; SELECT decimal(val) FROM t3 ORDER BY seq; } {1 2 3 4 5 6 7 8 9 10 1000 2000 3000 4000 5000} do_execsql_test 3020 { SELECT decimal_add(val,'0.5') FROM t3 WHERE seq>5 ORDER BY seq } {6.5 7.5 8.5 9.5 10.5 1000.5 2000.5 3000.5 4000.5 5000.5} do_execsql_test 3030 { SELECT decimal_add(val,'-10') FROM t3 ORDER BY seq; } {-9 -8 -7 -6 -5 -4 -3 -2 -1 0 990 1990 2990 3990 4990} do_execsql_test 4000 { SELECT decimal_sum(val) FROM t3; } {15055} do_execsql_test 4010 { SELECT decimal_sum(decimal_add(val,val||'e+10')) FROM t3; } {150550000015055} do_execsql_test 4010 { SELECT decimal_sum(decimal_add(val||'e+20',decimal_add(val,val||'e-20'))) FROM t3; } {1505500000000000000015055.00000000000000015055} do_execsql_test 5000 { WITH RECURSIVE c(x,y,z) AS ( VALUES(0,'1','1') UNION ALL SELECT x+1, decimal_mul(y,'2'), decimal_mul(z,'0.5') FROM c WHERE x<32 ) SELECT count(*) FROM c WHERE decimal_mul(y,z)='1'; } {33} do_execsql_test 5100 { SELECT decimal_mul('1234.00','2.00'); } {2468.00} do_execsql_test 5101 { SELECT decimal_mul('1234.00','2.0000'); } {2468.00} do_execsql_test 5102 { SELECT decimal_mul('1234.0000','2.000'); } {2468.000} do_execsql_test 5103 { SELECT decimal_mul('1234.0000','2'); } {2468} if {[catch {load_static_extension db ieee754} error]} { puts "Skipping ieee754 tests, hit load error: $error" finish_test; return } do_execsql_test 6000 { CREATE TABLE pow2(x INTEGER PRIMARY KEY, v TEXT); WITH RECURSIVE c(x,v) AS ( VALUES(0,'1') UNION ALL SELECT x+1, decimal_mul(v,'2') FROM c WHERE x+1<=971 ) INSERT INTO pow2(x,v) SELECT x, v FROM c; WITH RECURSIVE c(x,v) AS ( VALUES(-1,'0.5') UNION ALL SELECT x-1, decimal_mul(v,'0.5') FROM c WHERE x-1>=-1075 ) INSERT INTO pow2(x,v) SELECT x, v FROM c; } {} do_execsql_test 6010 { WITH c(n) AS (SELECT ieee754_from_blob(x'0000000000000001')) SELECT decimal_mul(ieee754_mantissa(c.n),pow2.v) FROM pow2, c WHERE pow2.x=ieee754_exponent(c.n); } {0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004940656458412465441765687928682213723650598026143247644255856825006755072702087518652998363616359923797965646954457177309266567103559397963987747960107818781263007131903114045278458171678489821036887186360569987307230500063874091535649843873124733972731696151400317153853980741262385655911710266585566867681870395603106249319452715914924553293054565444011274801297099995419319894090804165633245247571478690147267801593552386115501348035264934720193790268107107491703332226844753335720832431936092382893458368060106011506169809753078342277318329247904982524730776375927247874656084778203734469699533647017972677717585125660551199131504891101451037862738167250955837389733598993664809941164205702637090279242767544565229087538682506419718265533447265625} do_execsql_test 6020 { WITH c(n) AS (SELECT ieee754_from_blob(x'7fefffffffffffff')) SELECT decimal_mul(ieee754_mantissa(c.n),pow2.v) FROM pow2, c WHERE pow2.x=ieee754_exponent(c.n); } {179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368} do_execsql_test 6100 { SELECT ieee754(ieee754_from_blob(x'0000000000000001')); } {ieee754(1,-1074)} do_execsql_test 6110 { SELECT ieee754(ieee754_from_blob(x'7fefffffffffffff')); } {ieee754(9007199254740991,971)} do_execsql_test 6120 { SELECT printf('%.8e',ieee754_from_blob(x'0000000000000001')); } {4.94065646e-324} do_execsql_test 6130 { SELECT printf('%.8e',ieee754_from_blob(x'ffefffffffffffff')); } {-1.79769313e+308} finish_test |
Changes to test/default.test.
︙ | ︙ | |||
123 124 125 126 127 128 129 130 131 | } {1 {default value of column [b] is not constant}} do_catchsql_test default-4.3 { CREATE TABLE t2(a TEXT, b TEXT DEFAULT(abs(:xyz))); } {1 {default value of column [b] is not constant}} do_catchsql_test default-4.4 { CREATE TABLE t2(a TEXT, b TEXT DEFAULT(98+coalesce(5,:xyz))); } {1 {default value of column [b] is not constant}} finish_test | > > > > > > > > > | 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 | } {1 {default value of column [b] is not constant}} do_catchsql_test default-4.3 { CREATE TABLE t2(a TEXT, b TEXT DEFAULT(abs(:xyz))); } {1 {default value of column [b] is not constant}} do_catchsql_test default-4.4 { CREATE TABLE t2(a TEXT, b TEXT DEFAULT(98+coalesce(5,:xyz))); } {1 {default value of column [b] is not constant}} # 2020-03-09 out-of-bounds memory access discovered by "Eternal Sakura" # and reported to chromium. # reset_db do_catchsql_test default-5.1 { CREATE TABLE t1 (a,b DEFAULT(random() NOTNULL IN (RAISE(IGNORE),2,3))); INSERT INTO t1(a) VALUES(1); } {1 {RAISE() may only be used within a trigger-program}} finish_test |
Changes to test/delete4.test.
︙ | ︙ | |||
55 56 57 58 59 60 61 | SELECT x FROM t1; } {1 3 5 7} #------------------------------------------------------------------------- # reset_db | | > | > > > > > > > | 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 | SELECT x FROM t1; } {1 3 5 7} #------------------------------------------------------------------------- # reset_db do_execsql_test 3.0.1 { CREATE TABLE t1(a, b, PRIMARY KEY(a, b)) WITHOUT ROWID; INSERT INTO t1 VALUES(1, 2); INSERT INTO t1 VALUES(2, 4); INSERT INTO t1 VALUES(1, 5); DELETE FROM t1 WHERE a=1; SELECT printf('(%d)',changes()); SELECT * FROM t1; } {(2) 2 4} do_execsql_test 3.0.2 { WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<100) INSERT INTO t1(a,b) SELECT x, x+1 FROM c; SELECT printf('(%d)',changes()); DELETE FROM t1; SELECT printf('(%d)',changes()); } {(100) (101)} #------------------------------------------------------------------------- # DELETE statement that uses the OR optimization # reset_db do_execsql_test 3.1 { CREATE TABLE t1(i INTEGER PRIMARY KEY, a, b); |
︙ | ︙ | |||
178 179 180 181 182 183 184 185 | do_execsql_test 6.1 { DROP TABLE IF EXISTS t2; CREATE TABLE t2(x INT); INSERT INTO t2(x) VALUES(1),(2),(3),(4),(5); DELETE FROM t2 WHERE EXISTS(SELECT 1 FROM t2 AS v WHERE v.x=t2.x+1); SELECT x FROM t2; } {5} | > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | do_execsql_test 6.1 { DROP TABLE IF EXISTS t2; CREATE TABLE t2(x INT); INSERT INTO t2(x) VALUES(1),(2),(3),(4),(5); DELETE FROM t2 WHERE EXISTS(SELECT 1 FROM t2 AS v WHERE v.x=t2.x+1); SELECT x FROM t2; } {5} #------------------------------------------------------------------------- # Test the effect of failing to find a table row based on an index key # within a DELETE. Either because the db is corrupt, or a trigger on another # row already deleted the entry, or because a BEFORE trigger on the current # row has already deleted it. # do_execsql_test 7.1.0 { CREATE TABLE t3(id INT PRIMARY KEY, a, b) WITHOUT ROWID; CREATE INDEX t3a ON t3(a); CREATE INDEX t3b ON t3(b); INSERT INTO t3 VALUES(1, 1, 1); INSERT INTO t3 VALUES(2, 2, 2); INSERT INTO t3 VALUES(3, 3, 3); INSERT INTO t3 VALUES(4, 4, 1); } do_execsql_test 7.1.1 { DELETE FROM t3 WHERE a=4 OR b=1; } do_execsql_test 7.1.2 { SELECT * FROM t3; } { 2 2 2 3 3 3 } do_execsql_test 7.2.0 { CREATE TABLE t4(a PRIMARY KEY, b) WITHOUT ROWID; CREATE INDEX t4i ON t4(b); INSERT INTO t4 VALUES(1, 'hello'); INSERT INTO t4 VALUES(2, 'world'); CREATE TABLE t5(a PRIMARY KEY, b) WITHOUT ROWID; CREATE INDEX t5i ON t5(b); INSERT INTO t5 VALUES(1, 'hello'); INSERT INTO t5 VALUES(3, 'world'); PRAGMA writable_schema = 1; UPDATE sqlite_master SET rootpage = ( SELECT rootpage FROM sqlite_master WHERE name = 't5' ) WHERE name = 't4'; } db close sqlite3 db test.db do_execsql_test 7.2.1 { DELETE FROM t4 WHERE b='world' } reset_db do_execsql_test 7.3.0 { CREATE TABLE t3(id INT PRIMARY KEY, a, b) WITHOUT ROWID; INSERT INTO t3 VALUES(1, 2, 3); INSERT INTO t3 VALUES(4, 5, 6); INSERT INTO t3 VALUES(7, 8, 9); CREATE TRIGGER t3t BEFORE DELETE ON t3 BEGIN DELETE FROM t3 WHERE id=old.id+3; END; } do_execsql_test 7.3.1 { DELETE FROM t3 WHERE a IN(2, 5, 8); SELECT * FROM t3; } {} do_execsql_test 7.3.2 { DROP TRIGGER t3t; INSERT INTO t3 VALUES(1, 2, 3); INSERT INTO t3 VALUES(4, 5, 6); INSERT INTO t3 VALUES(7, 8, 9); CREATE TRIGGER t3t BEFORE DELETE ON t3 BEGIN DELETE FROM t3 WHERE id=old.id; END; } do_execsql_test 7.3.3 { DELETE FROM t3 WHERE a IN(2, 5, 8); SELECT * FROM t3; } {} finish_test |
Changes to test/descidx1.test.
︙ | ︙ | |||
18 19 20 21 22 23 24 | source $testdir/tester.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 | | > | 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | source $testdir/tester.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 #db eval {PRAGMA legacy_file_format=OFF} sqlite3_db_config db LEGACY_FILE_FORMAT 0 # This procedure sets the value of the file-format in file 'test.db' # to $newval. Also, the schema cookie is incremented. # proc set_file_format {newval} { hexio_write test.db 44 [hexio_render_int32 $newval] set schemacookie [hexio_get_int [hexio_read test.db 40 4]] |
︙ | ︙ | |||
295 296 297 298 299 300 301 | # the get_file_format command. # ifcapable legacyformat { do_test descidx1-6.1 { db close forcedelete test.db test.db-journal sqlite3 db test.db | | | | | | | > < | 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 | # the get_file_format command. # ifcapable legacyformat { do_test descidx1-6.1 { db close forcedelete test.db test.db-journal sqlite3 db test.db sqlite3_db_config db LEGACY_FILE_FORMAT } {1} } else { do_test descidx1-6.1 { db close forcedelete test.db test.db-journal sqlite3 db test.db sqlite3_db_config db LEGACY_FILE_FORMAT } {0} } do_test descidx1-6.2 { sqlite3_db_config db LEGACY_FILE_FORMAT 1 sqlite3_db_config db LEGACY_FILE_FORMAT } {1} do_test descidx1-6.3 { execsql { CREATE TABLE t1(a,b,c); } get_file_format } {1} ifcapable vacuum { # Verify that the file format is preserved across a vacuum. do_test descidx1-6.3.1 { execsql {VACUUM} get_file_format } {1} } do_test descidx1-6.4 { db close forcedelete test.db test.db-journal sqlite3 db test.db sqlite3_db_config db LEGACY_FILE_FORMAT 0 sqlite3_db_config db LEGACY_FILE_FORMAT } {0} do_test descidx1-6.5 { execsql { CREATE TABLE t1(a,b,c); CREATE INDEX i1 ON t1(a ASC, b DESC, c ASC); INSERT INTO t1 VALUES(1,2,3); INSERT INTO t1 VALUES(1,1,0); INSERT INTO t1 VALUES(1,2,1); INSERT INTO t1 VALUES(1,3,4); } get_file_format } {4} ifcapable vacuum { # Verify that the file format is preserved across a vacuum. do_test descidx1-6.6 { execsql {VACUUM} get_file_format } {4} do_test descidx1-6.7 { sqlite3_db_config db LEGACY_FILE_FORMAT 1 execsql { VACUUM; } get_file_format } {4} } finish_test |
Changes to test/descidx2.test.
︙ | ︙ | |||
19 20 21 22 23 24 25 | # 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 | | > | 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | # 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 #db eval {PRAGMA legacy_file_format=OFF} sqlite3_db_config db LEGACY_FILE_FORMAT 0 # This procedure sets the value of the file-format in file 'test.db' # to $newval. Also, the schema cookie is incremented. # proc set_file_format {newval} { hexio_write test.db 44 [hexio_render_int32 $newval] set schemacookie [hexio_get_int [hexio_read test.db 40 4]] |
︙ | ︙ |
Changes to test/descidx3.test.
︙ | ︙ | |||
22 23 24 25 26 27 28 | # do_not_use_codec ifcapable !bloblit { finish_test return } | | > | 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | # do_not_use_codec ifcapable !bloblit { finish_test return } #db eval {PRAGMA legacy_file_format=OFF} sqlite3_db_config db LEGACY_FILE_FORMAT 0 # This procedure sets the value of the file-format in file 'test.db' # to $newval. Also, the schema cookie is incremented. # proc set_file_format {newval} { hexio_write test.db 44 [hexio_render_int32 $newval] set schemacookie [hexio_get_int [hexio_read test.db 40 4]] |
︙ | ︙ |
Changes to test/distinct.test.
︙ | ︙ | |||
26 27 28 29 30 31 32 | proc is_distinct_noop {sql} { set sql1 $sql set sql2 [string map {DISTINCT ""} $sql] set program1 [list] set program2 [list] db eval "EXPLAIN $sql1" { | | | < | | | 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 | proc is_distinct_noop {sql} { set sql1 $sql set sql2 [string map {DISTINCT ""} $sql] set program1 [list] set program2 [list] db eval "EXPLAIN $sql1" { if {$opcode != "Noop" && $opcode != "Explain"} { lappend program1 $opcode } } db eval "EXPLAIN $sql2" { if {$opcode != "Noop" && $opcode != "Explain"} { lappend program2 $opcode } } return [expr {$program1==$program2}] } proc do_distinct_noop_test {tn sql} { uplevel [list do_test $tn [list is_distinct_noop $sql] 1] } proc do_distinct_not_noop_test {tn sql} { uplevel [list do_test $tn [list is_distinct_noop $sql] 0] } proc do_temptables_test {tn sql temptables} { uplevel [list do_test $tn [subst -novar { set ret "" db eval "EXPLAIN [set sql]" { if {$opcode == "OpenEphemeral" || $opcode == "SorterOpen"} { if {$p5!=8 && $p5!=0} { error "p5 = $p5" } if {$p5==8} { lappend ret hash } else { lappend ret btree } } } set ret |
︙ | ︙ | |||
124 125 126 127 128 129 130 | 18 1 "SELECT DISTINCT c1, c2 FROM t3" 19 1 "SELECT DISTINCT c1 FROM t3" 20 1 "SELECT DISTINCT * FROM t3" 21 0 "SELECT DISTINCT c2 FROM t3" 22 0 "SELECT DISTINCT * FROM (SELECT 1, 2, 3 UNION SELECT 4, 5, 6)" | < | 123 124 125 126 127 128 129 130 131 132 133 134 135 136 | 18 1 "SELECT DISTINCT c1, c2 FROM t3" 19 1 "SELECT DISTINCT c1 FROM t3" 20 1 "SELECT DISTINCT * FROM t3" 21 0 "SELECT DISTINCT c2 FROM t3" 22 0 "SELECT DISTINCT * FROM (SELECT 1, 2, 3 UNION SELECT 4, 5, 6)" 24 0 "SELECT DISTINCT rowid/2 FROM t1" 25 1 "SELECT DISTINCT rowid/2, rowid FROM t1" 26.1 0 "SELECT DISTINCT rowid/2, b FROM t1 WHERE c = ?" 26.2 1 "SELECT DISTINCT rowid/2, b FROM t4 WHERE c = ?" } { if {$noop} { |
︙ | ︙ | |||
264 265 266 267 268 269 270 | } {jjj} do_execsql_test 6.2 { CREATE TABLE nnn(x); SELECT (SELECT 'mmm' UNION SELECT DISTINCT max(name) ORDER BY 1) FROM sqlite_master; } {mmm} | > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | } {jjj} do_execsql_test 6.2 { CREATE TABLE nnn(x); SELECT (SELECT 'mmm' UNION SELECT DISTINCT max(name) ORDER BY 1) FROM sqlite_master; } {mmm} #------------------------------------------------------------------------- # Ticket [9c944882] # reset_db do_execsql_test 7.0 { CREATE TABLE t1(a INTEGER PRIMARY KEY); CREATE TABLE t3(a INTEGER PRIMARY KEY); CREATE TABLE t4(x); CREATE TABLE t5(y); INSERT INTO t5 VALUES(1), (2), (2); INSERT INTO t1 VALUES(2); INSERT INTO t3 VALUES(2); INSERT INTO t4 VALUES(2); } do_execsql_test 7.1 { WITH t2(b) AS ( SELECT DISTINCT y FROM t5 ORDER BY y ) SELECT * FROM t4 CROSS JOIN t3 CROSS JOIN t1 WHERE (t1.a=t3.a) AND (SELECT count(*) FROM t2 AS y WHERE t4.x!='abc')=t1.a } {2 2 2} # 2021-04-06 forum post https://sqlite.org/forum/forumpost/66954e9ece reset_db do_execsql_test 8.0 { CREATE TABLE person ( pid INT) ; CREATE UNIQUE INDEX idx ON person ( pid ) WHERE pid == 1; INSERT INTO person VALUES (1), (10), (10); SELECT DISTINCT pid FROM person where pid = 10; } {10} finish_test |
Changes to test/distinct2.test.
︙ | ︙ | |||
225 226 227 228 229 230 231 232 233 | CREATE TABLE t2(x PRIMARY KEY); INSERT INTO t2 VALUES('yes'); SELECT DISTINCT a FROM t1, t2 WHERE x=b; ANALYZE; SELECT DISTINCT a FROM t1, t2 WHERE x=b; } {1 1} finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | CREATE TABLE t2(x PRIMARY KEY); INSERT INTO t2 VALUES('yes'); SELECT DISTINCT a FROM t1, t2 WHERE x=b; ANALYZE; SELECT DISTINCT a FROM t1, t2 WHERE x=b; } {1 1} #------------------------------------------------------------------------- reset_db do_execsql_test 2000 { CREATE TABLE t0 (c0, c1, c2, PRIMARY KEY (c0, c1)); CREATE TABLE t1 (c2); INSERT INTO t0(c2) VALUES (0),(1),(3),(4),(5),(6),(7),(8),(9),(10),(11); INSERT INTO t0(c1) VALUES ('a'); INSERT INTO t1(c2) VALUES (0); } do_execsql_test 2010 { SELECT DISTINCT t0.c0, t1._rowid_, t0.c1 FROM t1 CROSS JOIN t0 ORDER BY t0.c0; } {{} 1 {} {} 1 a} do_execsql_test 1.2 { ANALYZE; } do_execsql_test 2020 { SELECT DISTINCT t0.c0, t1._rowid_, t0.c1 FROM t1 CROSS JOIN t0 ORDER BY t0.c0; } {{} 1 {} {} 1 a} do_execsql_test 2030 { CREATE TABLE t2(a, b, c); CREATE INDEX t2ab ON t2(a, b); WITH c(i) AS (SELECT 1 UNION ALL SELECT i+1 FROM c WHERE i<64) INSERT INTO t2 SELECT 'one', i%2, 'one' FROM c; WITH c(i) AS (SELECT 1 UNION ALL SELECT i+1 FROM c WHERE i<64) INSERT INTO t2 SELECT 'two', i%2, 'two' FROM c; CREATE TABLE t3(x INTEGER PRIMARY KEY); INSERT INTO t3 VALUES(1); ANALYZE; } do_execsql_test 2040 { SELECT DISTINCT a, b, x FROM t3 CROSS JOIN t2 ORDER BY a, +b; } { one 0 1 one 1 1 two 0 1 two 1 1 } #------------------------------------------------------------------------- # reset_db do_execsql_test 3000 { CREATE TABLE t0 (c0, c1 NOT NULL DEFAULT 1, c2, PRIMARY KEY (c0, c1)); INSERT INTO t0(c2) VALUES (NULL), (NULL), (NULL), (NULL), (NULL), (NULL), (NULL), (NULL), (NULL), (NULL), (NULL); INSERT INTO t0(c2) VALUES('a'); } do_execsql_test 3010 { SELECT DISTINCT * FROM t0 WHERE NULL IS t0.c0; } { {} 1 {} {} 1 a } do_execsql_test 3020 { ANALYZE; } do_execsql_test 3030 { SELECT DISTINCT * FROM t0 WHERE NULL IS c0; } { {} 1 {} {} 1 a } finish_test |
Changes to test/distinctagg.test.
︙ | ︙ | |||
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | # focus of this script is the DISTINCT modifier on aggregate functions. # # $Id: distinctagg.test,v 1.3 2009/02/09 13:19:28 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl do_test distinctagg-1.1 { execsql { CREATE TABLE t1(a,b,c); INSERT INTO t1 VALUES(1,2,3); INSERT INTO t1 VALUES(1,3,4); INSERT INTO t1 VALUES(1,3,5); SELECT count(distinct a), count(distinct b), count(distinct c), count(all a) FROM t1; } } {1 2 3 3} do_test distinctagg-1.2 { execsql { | > | | 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 | # focus of this script is the DISTINCT modifier on aggregate functions. # # $Id: distinctagg.test,v 1.3 2009/02/09 13:19:28 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix distinctagg do_test distinctagg-1.1 { execsql { CREATE TABLE t1(a,b,c); INSERT INTO t1 VALUES(1,2,3); INSERT INTO t1 VALUES(1,3,4); INSERT INTO t1 VALUES(1,3,5); SELECT count(distinct a), count(distinct b), count(distinct c), count(all a) FROM t1; } } {1 2 3 3} do_test distinctagg-1.2 { execsql { SELECT b, count(distinct c) FROM t1 GROUP BY b } } {2 1 3 2} do_test distinctagg-1.3 { execsql { INSERT INTO t1 SELECT a+1, b+3, c+5 FROM t1; INSERT INTO t1 SELECT a+2, b+6, c+10 FROM t1; INSERT INTO t1 SELECT a+4, b+12, c+20 FROM t1; |
︙ | ︙ | |||
54 55 56 57 58 59 60 61 62 | } } {1 {DISTINCT aggregates must have exactly one argument}} do_test distinctagg-2.2 { catchsql { SELECT group_concat(distinct a,b) FROM t1; } } {1 {DISTINCT aggregates must have exactly one argument}} finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | } } {1 {DISTINCT aggregates must have exactly one argument}} do_test distinctagg-2.2 { catchsql { SELECT group_concat(distinct a,b) FROM t1; } } {1 {DISTINCT aggregates must have exactly one argument}} #-------------------------------------------------------------------------- reset_db do_execsql_test 3.0 { CREATE TABLE t1(a, b, c); CREATE TABLE t2(d, e, f); INSERT INTO t1 VALUES (1, 1, 1); INSERT INTO t1 VALUES (2, 2, 2); INSERT INTO t1 VALUES (3, 3, 3); INSERT INTO t1 VALUES (4, 1, 4); INSERT INTO t1 VALUES (5, 2, 1); INSERT INTO t1 VALUES (5, 3, 2); INSERT INTO t1 VALUES (4, 1, 3); INSERT INTO t1 VALUES (3, 2, 4); INSERT INTO t1 VALUES (2, 3, 1); INSERT INTO t1 VALUES (1, 1, 2); INSERT INTO t2 VALUES('a', 'a', 'a'); INSERT INTO t2 VALUES('b', 'b', 'b'); INSERT INTO t2 VALUES('c', 'c', 'c'); CREATE INDEX t1a ON t1(a); CREATE INDEX t1bc ON t1(b, c); } foreach {tn use_eph sql res} { 1 0 "SELECT count(DISTINCT a) FROM t1" 5 2 0 "SELECT count(DISTINCT b) FROM t1" 3 3 1 "SELECT count(DISTINCT c) FROM t1" 4 4 0 "SELECT count(DISTINCT c) FROM t1 WHERE b=3" 3 5 0 "SELECT count(DISTINCT rowid) FROM t1" 10 6 0 "SELECT count(DISTINCT a) FROM t1, t2" 5 7 0 "SELECT count(DISTINCT a) FROM t2, t1" 5 8 1 "SELECT count(DISTINCT a+b) FROM t1, t2, t2, t2" 6 9 0 "SELECT count(DISTINCT c) FROM t1 WHERE c=2" 1 10 1 "SELECT count(DISTINCT t1.rowid) FROM t1, t2" 10 } { do_test 3.$tn.1 { set prg [db eval "EXPLAIN $sql"] set idx [lsearch $prg OpenEphemeral] expr {$idx>=0} } $use_eph do_execsql_test 3.$tn.2 $sql $res } do_execsql_test 3.10 { SELECT a, count(DISTINCT b) FROM t1 GROUP BY a; } { 1 1 2 2 3 2 4 1 5 2 } #-------------------------------------------------------------------------- reset_db do_execsql_test 3.0 { CREATE TABLE t1(a, b, c); CREATE INDEX t1a ON t1(a); CREATE INDEX t1bc ON t1(b, c); INSERT INTO t1 VALUES(1, 'A', 1); INSERT INTO t1 VALUES(1, 'A', 1); INSERT INTO t1 VALUES(2, 'A', 2); INSERT INTO t1 VALUES(2, 'A', 2); INSERT INTO t1 VALUES(1, 'B', 1); INSERT INTO t1 VALUES(2, 'B', 2); INSERT INTO t1 VALUES(3, 'B', 3); INSERT INTO t1 VALUES(NULL, 'B', NULL); INSERT INTO t1 VALUES(NULL, 'C', NULL); INSERT INTO t1 VALUES('d', 'D', 'd'); CREATE TABLE t2(d, e, f); CREATE INDEX t2def ON t2(d, e, f); INSERT INTO t2 VALUES(1, 1, 'a'); INSERT INTO t2 VALUES(1, 1, 'a'); INSERT INTO t2 VALUES(1, 2, 'a'); INSERT INTO t2 VALUES(1, 2, 'a'); INSERT INTO t2 VALUES(1, 2, 'b'); INSERT INTO t2 VALUES(1, 3, 'b'); INSERT INTO t2 VALUES(1, 3, 'a'); INSERT INTO t2 VALUES(1, 3, 'b'); INSERT INTO t2 VALUES(2, 3, 'x'); INSERT INTO t2 VALUES(2, 3, 'y'); INSERT INTO t2 VALUES(2, 3, 'z'); CREATE TABLE t3(x, y, z); INSERT INTO t3 VALUES(1,1,1); INSERT INTO t3 VALUES(2,2,2); } foreach {tn use_eph sql res} { 1 0 "SELECT count(DISTINCT c) FROM t1 GROUP BY b" {2 3 0 1} 2 1 "SELECT count(DISTINCT a) FROM t1 GROUP BY b" {2 3 0 1} 3 1 "SELECT count(DISTINCT a) FROM t1 GROUP BY b+c" {0 1 1 1 1} 4 0 "SELECT count(DISTINCT f) FROM t2 GROUP BY d, e" {1 2 2 3} 5 1 "SELECT count(DISTINCT f) FROM t2 GROUP BY d" {2 3} 6 0 "SELECT count(DISTINCT f) FROM t2 WHERE d IS 1 GROUP BY e" {1 2 2} } { do_test 4.$tn.1 { set prg [db eval "EXPLAIN $sql"] set idx [lsearch $prg OpenEphemeral] expr {$idx>=0} } $use_eph do_execsql_test 4.$tn.2 $sql $res } set t3root [db one {SELECT rootpage FROM sqlite_schema WHERE name='t3'}] foreach {tn use_t3 sql res} { 1 1 "SELECT count(*) FROM t3" 2 2 0 "SELECT count(*) FROM t1" 10 2 1 "SELECT count(DISTINCT a) FROM t1, t3" 4 3 1 "SELECT count(DISTINCT a) FROM t1 LEFT JOIN t3" 4 4 1 "SELECT count(DISTINCT a) FROM t1 LEFT JOIN t3 WHERE t3.x=1" 4 5 1 "SELECT count(DISTINCT a) FROM t1 LEFT JOIN t3 WHERE t3.x=0" 0 6 1 "SELECT count(DISTINCT a) FROM t1 LEFT JOIN t3 ON (t3.x=0)" 4 7 1 "SELECT count(DISTINCT x) FROM t1 LEFT JOIN t3" 2 8 1 "SELECT count(DISTINCT x) FROM t1 LEFT JOIN t3 WHERE t3.x=1" 1 9 1 "SELECT count(DISTINCT x) FROM t1 LEFT JOIN t3 WHERE t3.x=0" 0 10 1 "SELECT count(DISTINCT x) FROM t1 LEFT JOIN t3 ON (t3.x=0)" 0 } { do_test 5.$tn.1 { set bUse 0 db eval "EXPLAIN $sql" a { if {$a(opcode)=="OpenRead" && $a(p2)==$t3root} {set bUse 1} } set bUse } $use_t3 do_execsql_test 5.$tn.2 $sql $res } #------------------------------------------------------------------------- reset_db do_execsql_test 6.0 { CREATE TABLE t1(a, b); CREATE TABLE t2(c, d); INSERT INTO t1 VALUES(123,456); INSERT INTO t2 VALUES(123,456); } do_execsql_test 6.1 { SELECT count(DISTINCT c) FROM t1 LEFT JOIN t2; } {1} do_execsql_test 7.0 { CREATE TABLE v1 ( v2 UNIQUE, v3 AS( TYPEOF ( NULL ) ) UNIQUE ); SELECT COUNT ( DISTINCT TRUE ) FROM v1 GROUP BY likelihood ( v3 , 0.100000 ); } finish_test |
Changes to test/e_blobbytes.test.
︙ | ︙ | |||
9 10 11 12 13 14 15 16 17 18 19 20 21 22 | # #*********************************************************************** # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix e_blobbytes do_execsql_test 1.0 { CREATE TABLE q1(r INTEGER PRIMARY KEY, s TEXT); WITH d(a, b) AS ( SELECT 0, '' UNION ALL SELECT a+1, b||'.' FROM d WHERE a<10000 | > > > > > | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | # #*********************************************************************** # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix e_blobbytes ifcapable !incrblob { finish_test return } do_execsql_test 1.0 { CREATE TABLE q1(r INTEGER PRIMARY KEY, s TEXT); WITH d(a, b) AS ( SELECT 0, '' UNION ALL SELECT a+1, b||'.' FROM d WHERE a<10000 |
︙ | ︙ |
Changes to test/e_blobclose.test.
︙ | ︙ | |||
9 10 11 12 13 14 15 16 17 18 19 20 21 22 | # #*********************************************************************** # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix e_blobclose set dots [string repeat . 40] do_execsql_test 1.0 { CREATE TABLE x1(a INTEGER PRIMARY KEY, b DOTS); INSERT INTO x1 VALUES(-1, $dots); INSERT INTO x1 VALUES(-10, $dots); INSERT INTO x1 VALUES(-100, $dots); | > > > > > | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | # #*********************************************************************** # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix e_blobclose ifcapable !incrblob { finish_test return } set dots [string repeat . 40] do_execsql_test 1.0 { CREATE TABLE x1(a INTEGER PRIMARY KEY, b DOTS); INSERT INTO x1 VALUES(-1, $dots); INSERT INTO x1 VALUES(-10, $dots); INSERT INTO x1 VALUES(-100, $dots); |
︙ | ︙ |
Changes to test/e_blobopen.test.
︙ | ︙ | |||
9 10 11 12 13 14 15 16 17 18 19 20 21 22 | # #*********************************************************************** # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix e_blobopen forcedelete test.db2 do_execsql_test 1.0 { ATTACH 'test.db2' AS aux; CREATE TABLE main.t1(a INTEGER PRIMARY KEY, b TEXT, c BLOB); | > > > > > | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | # #*********************************************************************** # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix e_blobopen ifcapable !incrblob { finish_test return } forcedelete test.db2 do_execsql_test 1.0 { ATTACH 'test.db2' AS aux; CREATE TABLE main.t1(a INTEGER PRIMARY KEY, b TEXT, c BLOB); |
︙ | ︙ |
Changes to test/e_blobwrite.test.
︙ | ︙ | |||
9 10 11 12 13 14 15 16 17 18 19 20 21 22 | # #*********************************************************************** # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix e_blobwrite #-------------------------------------------------------------------------- # EVIDENCE-OF: R-62898-22698 This function is used to write data into an # open BLOB handle from a caller-supplied buffer. N bytes of data are # copied from the buffer Z into the open BLOB, starting at offset # iOffset. # | > > > > > | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | # #*********************************************************************** # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix e_blobwrite ifcapable !incrblob { finish_test return } #-------------------------------------------------------------------------- # EVIDENCE-OF: R-62898-22698 This function is used to write data into an # open BLOB handle from a caller-supplied buffer. N bytes of data are # copied from the buffer Z into the open BLOB, starting at offset # iOffset. # |
︙ | ︙ |
Changes to test/e_changes.test.
︙ | ︙ | |||
21 22 23 24 25 26 27 | uplevel [list \ do_test $tn "concat \[execsql {$sql}\] \[db changes\]" $res ] } #-------------------------------------------------------------------------- | | | | | | 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | uplevel [list \ do_test $tn "concat \[execsql {$sql}\] \[db changes\]" $res ] } #-------------------------------------------------------------------------- # EVIDENCE-OF: R-58361-29089 The changes() function returns the number # of database rows that were changed or inserted or deleted by the most # recently completed INSERT, DELETE, or UPDATE statement, exclusive of # statements in lower-level triggers. # do_execsql_test 1.0 { CREATE TABLE t1(a, b); CREATE TABLE t2(x, y, PRIMARY KEY(x, y)) WITHOUT ROWID; CREATE INDEX i1 ON t1(a); CREATE INDEX i2 ON t2(y); } |
︙ | ︙ | |||
104 105 106 107 108 109 110 | do_test 1.$tn.11 { db changes } 0 do_changes_test 1.$tn.12 COMMIT 0 } #-------------------------------------------------------------------------- | | > | > | 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 | do_test 1.$tn.11 { db changes } 0 do_changes_test 1.$tn.12 COMMIT 0 } #-------------------------------------------------------------------------- # X-EVIDENCE-OF: R-44877-05564 Executing any other type of SQL statement # does not modify the value returned by this function. # reset_db do_changes_test 2.1 { CREATE TABLE t1(x) } 0 do_changes_test 2.2 { WITH d(y) AS (SELECT 1 UNION ALL SELECT y+1 FROM d WHERE y<47) INSERT INTO t1 SELECT y FROM d; } 47 # The statement above set changes() to 47. Check that none of the following # modify this. do_changes_test 2.3 { SELECT count(x) FROM t1 } {47 47} do_changes_test 2.4 { DROP TABLE t1 } 47 do_changes_test 2.5 { CREATE TABLE t1(x) } 47 ifcapable altertable { do_changes_test 2.6 { ALTER TABLE t1 ADD COLUMN b } 47 } #-------------------------------------------------------------------------- # EVIDENCE-OF: R-53938-27527 Only changes made directly by the INSERT, # UPDATE or DELETE statement are considered - auxiliary changes caused # by triggers, foreign key actions or REPLACE constraint resolution are # not counted. |
︙ | ︙ |
Changes to test/e_createtable.test.
︙ | ︙ | |||
391 392 393 394 395 396 397 | do_createtable_tests 1.2.2 { 1 "CREATE TABLE main.abc(a, b, c)" {} 2 "CREATE TABLE temp.helloworld(x)" {} 3 {CREATE TABLE auxa."t 1"(x, y)} {} 4 {CREATE TABLE auxb.xyz(z)} {} } drop_all_tables | > | | | | | | | | | | | > > | | | | | | | > > | | | | | | | | | > > | | | | | | | | | > | 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 | do_createtable_tests 1.2.2 { 1 "CREATE TABLE main.abc(a, b, c)" {} 2 "CREATE TABLE temp.helloworld(x)" {} 3 {CREATE TABLE auxa."t 1"(x, y)} {} 4 {CREATE TABLE auxb.xyz(z)} {} } drop_all_tables if {[permutation]!="maindbname"} { do_createtable_tests 1.3 -tclquery { unset -nocomplain X array set X [table_list] list $X(main) $X(temp) $X(auxa) $X(auxb) } { 1 "CREATE TABLE main.abc(a, b, c)" {abc {} {} {}} 2 "CREATE TABLE main.t1(a, b, c)" {{abc t1} {} {} {}} 3 "CREATE TABLE temp.tmp(a, b, c)" {{abc t1} tmp {} {}} 4 "CREATE TABLE auxb.tbl(x, y)" {{abc t1} tmp {} tbl} 5 "CREATE TABLE auxb.t1(k, v)" {{abc t1} tmp {} {t1 tbl}} 6 "CREATE TABLE auxa.next(c, d)" {{abc t1} tmp next {t1 tbl}} } } # EVIDENCE-OF: R-18895-27365 If the "TEMP" or "TEMPORARY" keyword occurs # between the "CREATE" and "TABLE" then the new table is created in the # temp database. # drop_all_tables if {[permutation]!="maindbname"} { do_createtable_tests 1.4 -tclquery { unset -nocomplain X array set X [table_list] list $X(main) $X(temp) $X(auxa) $X(auxb) } { 1 "CREATE TEMP TABLE t1(a, b)" {{} t1 {} {}} 2 "CREATE TEMPORARY TABLE t2(a, b)" {{} {t1 t2} {} {}} } } # EVIDENCE-OF: R-23976-43329 It is an error to specify both a # schema-name and the TEMP or TEMPORARY keyword, unless the schema-name # is "temp". # drop_all_tables do_createtable_tests 1.5.1 -error { temporary table name must be unqualified } { 1 "CREATE TEMP TABLE main.t1(a, b)" {} 2 "CREATE TEMPORARY TABLE auxa.t2(a, b)" {} 3 "CREATE TEMP TABLE auxb.t3(a, b)" {} 4 "CREATE TEMPORARY TABLE main.xxx(x)" {} } drop_all_tables if {[permutation]!="maindbname"} { do_createtable_tests 1.5.2 -tclquery { unset -nocomplain X array set X [table_list] list $X(main) $X(temp) $X(auxa) $X(auxb) } { 1 "CREATE TEMP TABLE temp.t1(a, b)" {{} t1 {} {}} 2 "CREATE TEMPORARY TABLE temp.t2(a, b)" {{} {t1 t2} {} {}} 3 "CREATE TEMP TABLE TEMP.t3(a, b)" {{} {t1 t2 t3} {} {}} 4 "CREATE TEMPORARY TABLE TEMP.xxx(x)" {{} {t1 t2 t3 xxx} {} {}} } } # EVIDENCE-OF: R-31997-24564 If no schema name is specified and the TEMP # keyword is not present then the table is created in the main database. # drop_all_tables if {[permutation]!="maindbname"} { do_createtable_tests 1.6 -tclquery { unset -nocomplain X array set X [table_list] list $X(main) $X(temp) $X(auxa) $X(auxb) } { 1 "CREATE TABLE t1(a, b)" {t1 {} {} {}} 2 "CREATE TABLE t2(a, b)" {{t1 t2} {} {} {}} 3 "CREATE TABLE t3(a, b)" {{t1 t2 t3} {} {} {}} 4 "CREATE TABLE xxx(x)" {{t1 t2 t3 xxx} {} {} {}} } } drop_all_tables do_execsql_test e_createtable-1.7.0 { CREATE TABLE t1(x, y); CREATE INDEX i1 ON t1(x); CREATE VIEW v1 AS SELECT * FROM t1; |
︙ | ︙ | |||
1260 1261 1262 1263 1264 1265 1266 | 11 "INSERT INTO t2 VALUES('brambles', NULL)" {} 12 "INSERT INTO t2 VALUES(X'ABCDEF', NULL)" {} 13 "INSERT INTO t2 VALUES(NULL, NULL)" {} 14 "INSERT INTO t2 VALUES(NULL, NULL)" {} } | | | | > | 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 | 11 "INSERT INTO t2 VALUES('brambles', NULL)" {} 12 "INSERT INTO t2 VALUES(X'ABCDEF', NULL)" {} 13 "INSERT INTO t2 VALUES(NULL, NULL)" {} 14 "INSERT INTO t2 VALUES(NULL, NULL)" {} } # EVIDENCE-OF: R-40010-16873 Unless the column is an INTEGER PRIMARY KEY # or the table is a WITHOUT ROWID table or a STRICT table or the column # is declared NOT NULL, 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 |
︙ | ︙ | |||
1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 | CREATE TABLE t4(s, u INT PRIMARY KEY, v) WITHOUT ROWID; INSERT INTO t4 VALUES(1, NULL, 2); } {1 {NOT NULL constraint failed: t4.u}} do_catchsql_test 4.5.5 { CREATE TABLE t5(s, u INT PRIMARY KEY NOT NULL, v); INSERT INTO t5 VALUES(1, NULL, 2); } {1 {NOT NULL constraint failed: t5.u}} # EVIDENCE-OF: R-00227-21080 A UNIQUE constraint is similar to a PRIMARY # KEY constraint, except that a single table may have any number of # UNIQUE constraints. # drop_all_tables do_createtable_tests 4.6 { | > > > > > > > > | 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 | CREATE TABLE t4(s, u INT PRIMARY KEY, v) WITHOUT ROWID; INSERT INTO t4 VALUES(1, NULL, 2); } {1 {NOT NULL constraint failed: t4.u}} do_catchsql_test 4.5.5 { CREATE TABLE t5(s, u INT PRIMARY KEY NOT NULL, v); INSERT INTO t5 VALUES(1, NULL, 2); } {1 {NOT NULL constraint failed: t5.u}} do_catchsql_test 4.5.6 { CREATE TABLE t6(s INT, u INT PRIMARY KEY, v INT) STRICT; INSERT INTO t6 VALUES(1, NULL, 2); } {1 {NOT NULL constraint failed: t6.u}} do_catchsql_test 4.5.7 { CREATE TABLE t7(s INT, u INT PRIMARY KEY NOT NULL, v INT) STRICT; INSERT INTO t7 VALUES(1, NULL, 2); } {1 {NOT NULL constraint failed: t7.u}} # EVIDENCE-OF: R-00227-21080 A UNIQUE constraint is similar to a PRIMARY # KEY constraint, except that a single table may have any number of # UNIQUE constraints. # drop_all_tables do_createtable_tests 4.6 { |
︙ | ︙ | |||
1381 1382 1383 1384 1385 1386 1387 | # do_execsql_test 4.10.0 { CREATE TABLE t1(a, b PRIMARY KEY); CREATE TABLE t2(a, b, c, UNIQUE(b, c)); } do_createtable_tests 4.10 { 1 "EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE b = 5" | | | | | 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 | # do_execsql_test 4.10.0 { CREATE TABLE t1(a, b PRIMARY KEY); CREATE TABLE t2(a, b, c, UNIQUE(b, c)); } do_createtable_tests 4.10 { 1 "EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE b = 5" {/*SEARCH t1 USING INDEX sqlite_autoindex_t1_1 (b=?)*/} 2 "EXPLAIN QUERY PLAN SELECT * FROM t2 ORDER BY b, c" {/*SCAN t2 USING INDEX sqlite_autoindex_t2_1*/} 3 "EXPLAIN QUERY PLAN SELECT * FROM t2 WHERE b=10 AND c>10" {/*SEARCH t2 USING INDEX sqlite_autoindex_t2_1 (b=? AND c>?)*/} } # EVIDENCE-OF: R-45493-35653 A CHECK constraint may be attached to a # column definition or specified as a table constraint. In practice it # makes no difference. # # All the tests that deal with CHECK constraints below (4.11.* and |
︙ | ︙ | |||
1421 1422 1423 1424 1425 1426 1427 | CREATE TABLE t2(a, b, CHECK( a||b )); INSERT INTO x2 VALUES(1, 'xx'); INSERT INTO x2 VALUES(1, 'yy'); INSERT INTO t2 SELECT * FROM x2; } do_createtable_tests 4.11 -error {CHECK constraint failed: %s} { | | | | | | | | | | | | 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 | CREATE TABLE t2(a, b, CHECK( a||b )); INSERT INTO x2 VALUES(1, 'xx'); INSERT INTO x2 VALUES(1, 'yy'); INSERT INTO t2 SELECT * FROM x2; } do_createtable_tests 4.11 -error {CHECK constraint failed: %s} { 1a "INSERT INTO x1 VALUES('one', 0)" {b>0} 1b "INSERT INTO t1 VALUES('one', -4.0)" {b>0} 2a "INSERT INTO x2 VALUES('abc', 1)" {a||b} 2b "INSERT INTO t2 VALUES('abc', 1)" {a||b} 3a "INSERT INTO x2 VALUES(0, 'abc')" {a||b} 3b "INSERT INTO t2 VALUES(0, 'abc')" {a||b} 4a "UPDATE t1 SET b=-1 WHERE rowid=1" {b>0} 4b "UPDATE x1 SET b=-1 WHERE rowid=1" {b>0} 4a "UPDATE x2 SET a='' WHERE rowid=1" {a||b} 4b "UPDATE t2 SET a='' WHERE rowid=1" {a||b} } # EVIDENCE-OF: R-34109-39108 If the CHECK expression evaluates to NULL, # or any other non-zero value, it is not a constraint violation. # do_createtable_tests 4.12 { 1a "INSERT INTO x1 VALUES('one', NULL)" {} |
︙ | ︙ | |||
1627 1628 1629 1630 1631 1632 1633 | CREATE TABLE t4(a, b CHECK (b!=10)); INSERT INTO t4 VALUES(1, 2); INSERT INTO t4 VALUES(3, 4); } do_execsql_test 4.18.2 { BEGIN; INSERT INTO t4 VALUES(5, 6) } do_catchsql_test 4.18.3 { INSERT INTO t4 SELECT a+4, b+4 FROM t4 | | | 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 | CREATE TABLE t4(a, b CHECK (b!=10)); INSERT INTO t4 VALUES(1, 2); INSERT INTO t4 VALUES(3, 4); } do_execsql_test 4.18.2 { BEGIN; INSERT INTO t4 VALUES(5, 6) } do_catchsql_test 4.18.3 { INSERT INTO t4 SELECT a+4, b+4 FROM t4 } {1 {CHECK constraint failed: b!=10}} do_test e_createtable-4.18.4 { sqlite3_get_autocommit db } 0 do_execsql_test 4.18.5 { SELECT * FROM t4 } {1 2 3 4 5 6} # EVIDENCE-OF: R-19114-56113 Different constraints within the same table # may have different default conflict resolution algorithms. # do_execsql_test 4.19.0 { |
︙ | ︙ |
Changes to test/e_droptrigger.test.
︙ | ︙ | |||
123 124 125 126 127 128 129 | droptrigger_reopen_db execsql $droptrigger execsql " INSERT INTO $tbl VALUES('1', '2') " set ::triggers_fired } $after } | | | | 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 | droptrigger_reopen_db execsql $droptrigger execsql " INSERT INTO $tbl VALUES('1', '2') " set ::triggers_fired } $after } # EVIDENCE-OF: R-04950-25529 Once removed, the trigger definition is no # longer present in the sqlite_schema (or sqlite_temp_schema) table and # is not fired by any subsequent INSERT, UPDATE or DELETE statements. # # Test cases e_droptrigger-1.* test the first part of this statement # (that dropped triggers do not appear in the schema table), and tests # droptrigger-2.* test that dropped triggers are not fired by INSERT # statements. The following tests verify that they are not fired by # UPDATE or DELETE statements. |
︙ | ︙ |
Changes to test/e_dropview.test.
︙ | ︙ | |||
122 123 124 125 126 127 128 | # set databasedata [list_all_data] do_execsql_test 3.1.0 { SELECT * FROM temp.v1 } {{a temp} {b temp}} do_execsql_test 3.1.1 { DROP VIEW temp.v1 } {} do_catchsql_test 3.1.2 { SELECT * FROM temp.v1 } {1 {no such table: temp.v1}} do_test 3.1.3 { list_all_views } {main.v1 main.v2 aux.v1 aux.v2 aux.v3} | | | | | | | | | | | | | | | | 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 | # set databasedata [list_all_data] do_execsql_test 3.1.0 { SELECT * FROM temp.v1 } {{a temp} {b temp}} do_execsql_test 3.1.1 { DROP VIEW temp.v1 } {} do_catchsql_test 3.1.2 { SELECT * FROM temp.v1 } {1 {no such table: temp.v1}} do_test 3.1.3 { list_all_views } {main.v1 main.v2 aux.v1 aux.v2 aux.v3} do_test 3.1.4 { string compare [list_all_data] $databasedata } 0 do_execsql_test 3.2.0 { SELECT * FROM v1 } {{a main} {b main}} do_execsql_test 3.2.1 { DROP VIEW v1 } {} do_catchsql_test 3.2.2 { SELECT * FROM main.v1 } {1 {no such table: main.v1}} do_test 3.2.3 { list_all_views } {main.v2 aux.v1 aux.v2 aux.v3} do_test 3.2.4 { string compare [list_all_data] $databasedata } 0 do_execsql_test 3.3.0 { SELECT * FROM v2 } {{a main} {b main}} do_execsql_test 3.3.1 { DROP VIEW v2 } {} do_catchsql_test 3.3.2 { SELECT * FROM main.v2 } {1 {no such table: main.v2}} do_test 3.3.3 { list_all_views } {aux.v1 aux.v2 aux.v3} do_test 3.3.4 { string compare [list_all_data] $databasedata } 0 do_execsql_test 3.4.0 { SELECT * FROM v1 } {{a aux} {b aux}} do_execsql_test 3.4.1 { DROP VIEW v1 } {} do_catchsql_test 3.4.2 { SELECT * FROM v1 } {1 {no such table: v1}} do_test 3.4.3 { list_all_views } {aux.v2 aux.v3} do_test 3.4.4 { string compare [list_all_data] $databasedata } 0 do_execsql_test 3.5.0 { SELECT * FROM aux.v2 } {{a aux} {b aux}} do_execsql_test 3.5.1 { DROP VIEW aux.v2 } {} do_catchsql_test 3.5.2 { SELECT * FROM aux.v2 } {1 {no such table: aux.v2}} do_test 3.5.3 { list_all_views } {aux.v3} do_test 3.5.4 { string compare [list_all_data] $databasedata } 0 do_execsql_test 3.6.0 { SELECT * FROM v3 } {{a aux} {b aux}} do_execsql_test 3.6.1 { DROP VIEW v3 } {} do_catchsql_test 3.6.2 { SELECT * FROM v3 } {1 {no such table: v3}} do_test 3.6.3 { list_all_views } {} do_test 3.6.4 { string compare [list_all_data] $databasedata } 0 # EVIDENCE-OF: R-25558-37487 If the specified view cannot be found and # the IF EXISTS clause is not present, it is an error. # do_dropview_tests 4 -repair { dropview_reopen_db } -errorformat { |
︙ | ︙ | |||
175 176 177 178 179 180 181 | # an IF EXISTS clause is present in the DROP VIEW statement, then the # statement is a no-op. # do_dropview_tests 5 -repair { dropview_reopen_db } -tclquery { list_all_views | | | | | | 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 | # an IF EXISTS clause is present in the DROP VIEW statement, then the # statement is a no-op. # do_dropview_tests 5 -repair { dropview_reopen_db } -tclquery { list_all_views #expr {[list_all_views] == "main.v1 main.v2 temp.v1 aux.v1 aux.v2 aux.v3"} } { 1 "DROP VIEW IF EXISTS xx" "main.v1 main.v2 temp.v1 aux.v1 aux.v2 aux.v3" 2 "DROP VIEW IF EXISTS main.xx" "main.v1 main.v2 temp.v1 aux.v1 aux.v2 aux.v3" 3 "DROP VIEW IF EXISTS temp.v2" "main.v1 main.v2 temp.v1 aux.v1 aux.v2 aux.v3" } finish_test |
Changes to test/e_expr.test.
︙ | ︙ | |||
80 81 82 83 84 85 86 | db func regexp -argcount 2 regexfunc #------------------------------------------------------------------------- # Test cases e_expr-1.* attempt to verify that all binary operators listed # in the documentation exist and that the relative precedences of the # operators are also as the documentation suggests. # | | | | 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 | db func regexp -argcount 2 regexfunc #------------------------------------------------------------------------- # Test cases e_expr-1.* attempt to verify that all binary operators listed # in the documentation exist and that the relative precedences of the # operators are also as the documentation suggests. # # X-EVIDENCE-OF: R-15514-65163 SQLite understands the following binary # operators, in order from highest to lowest precedence: || * / % + - # << >> & | < <= > >= = == != <> IS IS # NOT IN LIKE GLOB MATCH REGEXP AND OR # # X-EVIDENCE-OF: R-38759-38789 Operators IS and IS NOT have the same # precedence as =. # unset -nocomplain untested foreach op1 $oplist { foreach op2 $oplist { set untested($op1,$op2) 1 |
︙ | ︙ | |||
176 177 178 179 180 181 182 | SELECT 0 == 0 < 2, (0 == 0) < 2, 0 == (0 < 2) } {0 1 0} #------------------------------------------------------------------------- # Check that the four unary prefix operators mentioned in the # documentation exist. # | | | 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 | SELECT 0 == 0 < 2, (0 == 0) < 2, 0 == (0 < 2) } {0 1 0} #------------------------------------------------------------------------- # Check that the four unary prefix operators mentioned in the # documentation exist. # # X-EVIDENCE-OF: R-13958-53419 Supported unary prefix operators are these: # - + ~ NOT # do_execsql_test e_expr-2.1 { SELECT - 10 } {-10} do_execsql_test e_expr-2.2 { SELECT + 10 } {10} do_execsql_test e_expr-2.3 { SELECT ~ 10 } {-11} do_execsql_test e_expr-2.4 { SELECT NOT 10 } {0} |
︙ | ︙ | |||
250 251 252 253 254 255 256 | do_execsql_test e_expr-5.$tn "SELECT $a || $b" [list "${as}${bs}"] } #------------------------------------------------------------------------- # Test the % operator. # | | > | | 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 | do_execsql_test e_expr-5.$tn "SELECT $a || $b" [list "${as}${bs}"] } #------------------------------------------------------------------------- # Test the % operator. # # EVIDENCE-OF: R-53431-59159 The % operator casts both of its operands # to type INTEGER and then computes the remainder after dividing the # left integer by the right integer. # do_execsql_test e_expr-6.1 {SELECT 72%5} {2} do_execsql_test e_expr-6.2 {SELECT 72%-5} {2} do_execsql_test e_expr-6.3 {SELECT -72%-5} {-2} do_execsql_test e_expr-6.4 {SELECT -72%5} {-2} do_execsql_test e_expr-6.5 {SELECT 72.35%5} {2.0} |
︙ | ︙ | |||
363 364 365 366 367 368 369 | string compare [reverse_str $zLeft] [reverse_str $zRight] } db collate reverse reverse_collate # EVIDENCE-OF: R-59577-33471 The COLLATE operator is a unary postfix # operator that assigns a collating sequence to an expression. # | | | 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 | string compare [reverse_str $zLeft] [reverse_str $zRight] } db collate reverse reverse_collate # EVIDENCE-OF: R-59577-33471 The COLLATE operator is a unary postfix # operator that assigns a collating sequence to an expression. # # X-EVIDENCE-OF: R-36231-30731 The COLLATE operator has a higher # precedence (binds more tightly) than any binary operator and any unary # prefix operator except "~". # do_execsql_test e_expr-9.1 { SELECT 'abcd' < 'bbbb' COLLATE reverse } 0 do_execsql_test e_expr-9.2 { SELECT ('abcd' < 'bbbb') COLLATE reverse } 1 do_execsql_test e_expr-9.3 { SELECT 'abcd' <= 'bbbb' COLLATE reverse } 0 do_execsql_test e_expr-9.4 { SELECT ('abcd' <= 'bbbb') COLLATE reverse } 1 |
︙ | ︙ | |||
855 856 857 858 859 860 861 | do_test e_expr-13.1.$tn { set ::xcount 0 set a [execsql "SELECT $expr"] list $::xcount $a } [list $nEval $res] } | | | 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 | do_test e_expr-13.1.$tn { set ::xcount 0 set a [execsql "SELECT $expr"] list $::xcount $a } [list $nEval $res] } # X-EVIDENCE-OF: R-05155-34454 The precedence of the BETWEEN operator is # the same as the precedence as operators == and != and LIKE and groups # left to right. # # Therefore, BETWEEN groups more tightly than operator "AND", but less # so than "<". # do_execsql_test e_expr-13.2.1 { SELECT 1 == 10 BETWEEN 0 AND 2 } 1 |
︙ | ︙ | |||
1009 1010 1011 1012 1013 1014 1015 | do_test e_expr-15.1.4 { set likeargs } {def abc X} db close sqlite3 db test.db # EVIDENCE-OF: R-22868-25880 The LIKE operator can be made case # sensitive using the case_sensitive_like pragma. # | | > | | > | > | | > | > | 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 | do_test e_expr-15.1.4 { set likeargs } {def abc X} db close sqlite3 db test.db # EVIDENCE-OF: R-22868-25880 The LIKE operator can be made case # sensitive using the case_sensitive_like pragma. # do_execsql_test e_expr-16.1.1 { SELECT 'abcxyz' LIKE 'ABC%' } 1 do_execsql_test e_expr-16.1.1b { SELECT 'abc%xyz' LIKE 'ABC\%x%' ESCAPE '\' } 1 do_execsql_test e_expr-16.1.2 { PRAGMA case_sensitive_like = 1 } {} do_execsql_test e_expr-16.1.3 { SELECT 'abcxyz' LIKE 'ABC%' } 0 do_execsql_test e_expr-16.1.3b { SELECT 'abc%xyz' LIKE 'ABC\%X%' ESCAPE '\' } 0 do_execsql_test e_expr-16.1.4 { SELECT 'ABCxyz' LIKE 'ABC%' } 1 do_execsql_test e_expr-16.1.4b { SELECT 'ABC%xyz' LIKE 'ABC\%x%' ESCAPE '\' } 1 do_execsql_test e_expr-16.1.5 { PRAGMA case_sensitive_like = 0 } {} do_execsql_test e_expr-16.1.6 { SELECT 'abcxyz' LIKE 'ABC%' } 1 do_execsql_test e_expr-16.1.6b { SELECT 'abc%xyz' LIKE 'ABC\%X%' ESCAPE '\' } 1 do_execsql_test e_expr-16.1.7 { SELECT 'ABCxyz' LIKE 'ABC%' } 1 do_execsql_test e_expr-16.1.7b { SELECT 'ABC%xyz' LIKE 'ABC\%X%' ESCAPE '\' } 1 # EVIDENCE-OF: R-52087-12043 The GLOB operator is similar to LIKE but # uses the Unix file globbing syntax for its wildcards. # # EVIDENCE-OF: R-09813-17279 Also, GLOB is case sensitive, unlike LIKE. # do_execsql_test e_expr-17.1.1 { SELECT 'abcxyz' GLOB 'abc%' } 0 |
︙ | ︙ | |||
1130 1131 1132 1133 1134 1135 1136 | do_execsql_test e_expr-19.2.3 { SELECT 'X' NOT MATCH 'Y' } 0 do_test e_expr-19.2.4 { set matchargs } {Y X} sqlite3 db test.db #------------------------------------------------------------------------- # Test cases for the testable statements related to the CASE expression. # | | | 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 | do_execsql_test e_expr-19.2.3 { SELECT 'X' NOT MATCH 'Y' } 0 do_test e_expr-19.2.4 { set matchargs } {Y X} sqlite3 db test.db #------------------------------------------------------------------------- # Test cases for the testable statements related to the CASE expression. # # EVIDENCE-OF: R-57495-24088 There are two fundamental forms of the CASE # expression: those with a base expression and those without. # do_execsql_test e_expr-20.1 { SELECT CASE WHEN 1 THEN 'true' WHEN 0 THEN 'false' ELSE 'else' END; } {true} do_execsql_test e_expr-20.2 { SELECT CASE 0 WHEN 1 THEN 'true' WHEN 0 THEN 'false' ELSE 'else' END; |
︙ | ︙ | |||
1226 1227 1228 1229 1230 1231 1232 | } {null} db nullvalue {} # EVIDENCE-OF: R-13943-13592 A NULL result is considered untrue when # evaluating WHEN terms. # do_execsql_test e_expr-21.4.1 { | | | | | | 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 | } {null} db nullvalue {} # EVIDENCE-OF: R-13943-13592 A NULL result is considered untrue when # evaluating WHEN terms. # do_execsql_test e_expr-21.4.1 { SELECT CASE WHEN NULL THEN 'A' WHEN 1 THEN 'B' END, iif(NULL,8,99); } {B 99} do_execsql_test e_expr-21.4.2 { SELECT CASE WHEN 0 THEN 'A' WHEN NULL THEN 'B' ELSE 'C' END, iif(0,8,99); } {C 99} # EVIDENCE-OF: R-38620-19499 In a CASE with a base expression, the base # expression is evaluated just once and the result is compared against # the evaluation of each WHEN expression from left to right. # # Note: This test case tests the "evaluated just once" part of the above # statement. Tests associated with the next two statements test that the |
︙ | ︙ | |||
1635 1636 1637 1638 1639 1640 1641 | CAST(-9223372036854775809.0 AS INT) } integer -9223372036854775808 do_expr_test e_expr-31.2.4 { CAST(9223372036854775809.0 AS INT) } integer 9223372036854775807 | | | > > > | > > > | > > > > > > > > > > > > > > > > > > > > > > > > > | 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 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 | CAST(-9223372036854775809.0 AS INT) } integer -9223372036854775808 do_expr_test e_expr-31.2.4 { CAST(9223372036854775809.0 AS INT) } integer 9223372036854775807 # EVIDENCE-OF: R-55084-10555 Casting a TEXT or BLOB value into NUMERIC # yields either an INTEGER or a REAL result. # # EVIDENCE-OF: R-48945-04866 If the input text looks like an integer # (there is no decimal point nor exponent) and the value is small enough # to fit in a 64-bit signed integer, then the result will be INTEGER. # # EVIDENCE-OF: R-47045-23194 Input text that looks like floating point # (there is a decimal point and/or an exponent) and the text describes a # value that can be losslessly converted back and forth between IEEE 754 # 64-bit float and a 51-bit signed integer, then the result is INTEGER. # do_expr_test e_expr-32.1.1 { CAST('45' AS NUMERIC) } integer 45 do_expr_test e_expr-32.1.2 { CAST('45.0' AS NUMERIC) } integer 45 do_expr_test e_expr-32.1.3 { CAST('45.2' AS NUMERIC) } real 45.2 do_expr_test e_expr-32.1.4 { CAST('11abc' AS NUMERIC) } integer 11 do_expr_test e_expr-32.1.5 { CAST('11.1abc' AS NUMERIC) } real 11.1 do_expr_test e_expr-32.1.6 {CAST( '9.223372036e14' AS NUMERIC)} integer 922337203600000 do_expr_test e_expr-32.1.7 {CAST('-9.223372036e14' AS NUMERIC)} integer -922337203600000 do_test e_expr-32.1.8 { set expr {CAST( '9.223372036e15' AS NUMERIC)} db eval "SELECT typeof($expr) AS type, printf('%.5e',$expr) AS value" break; list $type $value } {real 9.22337e+15} do_test e_expr-32.1.9 { set expr {CAST('-9.223372036e15' AS NUMERIC)} db eval "SELECT typeof($expr) AS type, printf('%.5e',$expr) AS value" break; list $type $value } {real -9.22337e+15} # EVIDENCE-OF: R-50300-26941 Any text input that describes a value # outside the range of a 64-bit signed integer yields a REAL result. # do_expr_test e_expr-32.1.20 { CAST('9223372036854775807' AS numeric) } \ integer 9223372036854775807 do_expr_test e_expr-32.1.21 { CAST('9223372036854775808' AS numeric) } \ real 9.22337203685478e+18 do_expr_test e_expr-32.1.22 { CAST('-9223372036854775808' AS numeric) } \ integer -9223372036854775808 do_expr_test e_expr-32.1.23 { CAST('-9223372036854775809' AS numeric) } \ real -9.22337203685478e+18 # EVIDENCE-OF: R-30347-18702 Casting a REAL or INTEGER value to NUMERIC # is a no-op, even if a real value could be losslessly converted to an # integer. # do_expr_test e_expr-32.2.1 { CAST(13.0 AS NUMERIC) } real 13.0 do_expr_test e_expr-32.2.2 { CAST(13.5 AS NUMERIC) } real 13.5 |
︙ | ︙ | |||
1692 1693 1694 1695 1696 1697 1698 | SELECT typeof(CAST(x AS NUMERIC)), CAST(x AS NUMERIC)||'' FROM t1; } [list \ integer 9000000000000000001 \ integer 9000000000000000001 \ integer 9000000000000000001 \ integer 9000000000000000001 \ integer 9000000000000000001 \ | | | | | 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 | SELECT typeof(CAST(x AS NUMERIC)), CAST(x AS NUMERIC)||'' FROM t1; } [list \ integer 9000000000000000001 \ integer 9000000000000000001 \ integer 9000000000000000001 \ integer 9000000000000000001 \ integer 9000000000000000001 \ real 9.0e+18 \ integer 9223372036854775807 \ integer 9223372036854775807 \ integer 9223372036854775807 \ real 9.22337203685478e+18 \ real 9.22337203685478e+18 \ real 9.22337203685478e+18 \ real 9.22337203685478e+18 \ integer -5 \ integer -5 \ ] # EVIDENCE-OF: R-64550-29191 Note that the result from casting any # non-BLOB value into a BLOB and the result from casting any BLOB value # into a non-BLOB value may be different depending on whether the |
︙ | ︙ | |||
1876 1877 1878 1879 1880 1881 1882 | } { do_catchsql_test e_expr-35.2.$tn $sql $M } # EVIDENCE-OF: R-18318-14995 The value of a subquery expression is the # first row of the result from the enclosed SELECT statement. # | < < < | 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 | } { do_catchsql_test e_expr-35.2.$tn $sql $M } # EVIDENCE-OF: R-18318-14995 The value of a subquery expression is the # first row of the result from the enclosed SELECT statement. # do_execsql_test e_expr-36.3.1 { CREATE TABLE t4(x, y); INSERT INTO t4 VALUES(1, 'one'); INSERT INTO t4 VALUES(2, 'two'); INSERT INTO t4 VALUES(3, 'three'); } {} |
︙ | ︙ | |||
1915 1916 1917 1918 1919 1920 1921 | do_expr_test e_expr-36.4.$tn $expr null {} } # EVIDENCE-OF: R-62477-06476 For example, the values NULL, 0.0, 0, # 'english' and '0' are all considered to be false. # do_execsql_test e_expr-37.1 { | | | | | | | | | | | | | | | | | | | | | | 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 | do_expr_test e_expr-36.4.$tn $expr null {} } # EVIDENCE-OF: R-62477-06476 For example, the values NULL, 0.0, 0, # 'english' and '0' are all considered to be false. # do_execsql_test e_expr-37.1 { SELECT CASE WHEN NULL THEN 'true' ELSE 'false' END, iif(NULL,'true','false'); } {false false} do_execsql_test e_expr-37.2 { SELECT CASE WHEN 0.0 THEN 'true' ELSE 'false' END, iif(0.0,'true','false'); } {false false} do_execsql_test e_expr-37.3 { SELECT CASE WHEN 0 THEN 'true' ELSE 'false' END, iif(0,'true','false'); } {false false} do_execsql_test e_expr-37.4 { SELECT CASE WHEN 'engligh' THEN 'true' ELSE 'false' END, iif('engligh','true','false'); } {false false} do_execsql_test e_expr-37.5 { SELECT CASE WHEN '0' THEN 'true' ELSE 'false' END, iif('0','true','false'); } {false false} # EVIDENCE-OF: R-55532-10108 Values 1, 1.0, 0.1, -0.1 and '1english' are # considered to be true. # do_execsql_test e_expr-37.6 { SELECT CASE WHEN 1 THEN 'true' ELSE 'false' END, iif(1,'true','false'); } {true true} do_execsql_test e_expr-37.7 { SELECT CASE WHEN 1.0 THEN 'true' ELSE 'false' END, iif(1.0,'true','false'); } {true true} do_execsql_test e_expr-37.8 { SELECT CASE WHEN 0.1 THEN 'true' ELSE 'false' END, iif(0.1,'true','false'); } {true true} do_execsql_test e_expr-37.9 { SELECT CASE WHEN -0.1 THEN 'true' ELSE 'false' END, iif(-0.1,'true','false'); } {true true} do_execsql_test e_expr-37.10 { SELECT CASE WHEN '1english' THEN 'true' ELSE 'false' END, iif('1engl','true','false'); } {true true} finish_test |
Changes to test/e_fkey.test.
︙ | ︙ | |||
988 989 990 991 992 993 994 | } } {} do_detail_test e_fkey-25.2 { PRAGMA foreign_keys = OFF; EXPLAIN QUERY PLAN DELETE FROM artist WHERE 1; EXPLAIN QUERY PLAN SELECT rowid FROM track WHERE trackartist = ?; } { | | | | | | 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 | } } {} do_detail_test e_fkey-25.2 { PRAGMA foreign_keys = OFF; EXPLAIN QUERY PLAN DELETE FROM artist WHERE 1; EXPLAIN QUERY PLAN SELECT rowid FROM track WHERE trackartist = ?; } { {SCAN artist} {SCAN track} } do_detail_test e_fkey-25.3 { PRAGMA foreign_keys = ON; EXPLAIN QUERY PLAN DELETE FROM artist WHERE 1; } { {SCAN artist} {SCAN track} } do_test e_fkey-25.4 { execsql { INSERT INTO artist VALUES(5, 'artist 5'); INSERT INTO artist VALUES(6, 'artist 6'); INSERT INTO artist VALUES(7, 'artist 7'); INSERT INTO track VALUES(1, 'track 1', 5); |
︙ | ︙ | |||
1113 1114 1115 1116 1117 1118 1119 | } {} do_test e_fkey-27.2 { eqp { INSERT INTO artist VALUES(?, ?) } } {} do_detail_test e_fkey-27.3 { EXPLAIN QUERY PLAN UPDATE artist SET artistid = ?, artistname = ? } { | | | | | | | 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 | } {} do_test e_fkey-27.2 { eqp { INSERT INTO artist VALUES(?, ?) } } {} do_detail_test e_fkey-27.3 { EXPLAIN QUERY PLAN UPDATE artist SET artistid = ?, artistname = ? } { {SCAN artist} {SEARCH track USING COVERING INDEX trackindex (trackartist=?)} {SEARCH track USING COVERING INDEX trackindex (trackartist=?)} } do_detail_test e_fkey-27.4 { EXPLAIN QUERY PLAN DELETE FROM artist } { {SCAN artist} {SEARCH track USING COVERING INDEX trackindex (trackartist=?)} } ########################################################################### ### SECTION 4.1: Composite Foreign Key Constraints ########################################################################### #------------------------------------------------------------------------- |
︙ | ︙ | |||
2051 2052 2053 2054 2055 2056 2057 | do_test e_fkey-44.5 { execsql { SELECT quote(c) FROM cB } } {NULL} #------------------------------------------------------------------------- # Test SET DEFAULT actions. # | | | | 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 | do_test e_fkey-44.5 { execsql { SELECT quote(c) FROM cB } } {NULL} #------------------------------------------------------------------------- # Test SET DEFAULT actions. # # EVIDENCE-OF: R-55814-22637 The "SET DEFAULT" actions are similar to # "SET NULL", except that each of the child key columns is set to # contain the column's default value instead of NULL. # drop_all_tables do_test e_fkey-45.1 { execsql { CREATE TABLE pA(x PRIMARY KEY); CREATE TABLE cA(c DEFAULT X'0000' REFERENCES pA ON DELETE SET DEFAULT); CREATE TABLE cB(c DEFAULT X'9999' REFERENCES pA ON UPDATE SET DEFAULT); |
︙ | ︙ | |||
2503 2504 2505 2506 2507 2508 2509 | # clause, unless the default value of the new column is NULL. Attempting # to do so returns an error. # proc test_efkey_6 {tn zAlter isError} { drop_all_tables do_test e_fkey-56.$tn.1 " | | > | | | > | | > | 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 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 | # clause, unless the default value of the new column is NULL. Attempting # to do so returns an error. # proc test_efkey_6 {tn zAlter isError} { drop_all_tables do_test e_fkey-56.$tn.1 " execsql { CREATE TABLE tbl(a, b); INSERT INTO tbl VALUES(1, 2); } [list catchsql $zAlter] " [lindex {{0 {}} {1 {Cannot add a REFERENCES column with non-NULL default value}}} $isError] } ifcapable altertable { test_efkey_6 1 "ALTER TABLE tbl ADD COLUMN c REFERENCES xx" 0 test_efkey_6 2 "ALTER TABLE tbl ADD COLUMN c DEFAULT NULL REFERENCES xx" 0 test_efkey_6 3 "ALTER TABLE tbl ADD COLUMN c DEFAULT 0 REFERENCES xx" 1 } #------------------------------------------------------------------------- # Test that ALTER TABLE adjusts REFERENCES clauses when the parent table # is RENAMED. # # EVIDENCE-OF: R-47080-02069 If an "ALTER TABLE ... RENAME TO" command # is used to rename a table that is the parent table of one or more # foreign key constraints, the definitions of the foreign key # constraints are modified to refer to the parent table by its new name # # Test that these adjustments are visible in the sqlite_master table. # # EVIDENCE-OF: R-43040-62530 The text of the child CREATE TABLE # statement or statements stored in the sqlite_schema table are modified # to reflect the new parent table name. # ifcapable altertable { do_test e_fkey-56.1 { drop_all_tables execsql { CREATE TABLE 'p 1 "parent one"'(a REFERENCES 'p 1 "parent one"', b, PRIMARY KEY(b)); CREATE TABLE c1(c, d REFERENCES 'p 1 "parent one"' ON UPDATE CASCADE); CREATE TABLE c2(e, f, FOREIGN KEY(f) REFERENCES 'p 1 "parent one"' ON UPDATE CASCADE); |
︙ | ︙ | |||
2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 | execsql { SELECT sql FROM sqlite_master WHERE type = 'table'} } [list \ {CREATE TABLE "p"(a REFERENCES "p", b, PRIMARY KEY(b))} \ {CREATE TABLE c1(c, d REFERENCES "p" ON UPDATE CASCADE)} \ {CREATE TABLE c2(e, f, FOREIGN KEY(f) REFERENCES "p" ON UPDATE CASCADE)} \ {CREATE TABLE c3(e, 'f col 2', FOREIGN KEY('f col 2') REFERENCES "p" ON UPDATE CASCADE)} \ ] #------------------------------------------------------------------------- # Check that a DROP TABLE does an implicit DELETE FROM. Which does not # cause any triggers to fire, but does fire foreign key actions. # # EVIDENCE-OF: R-14208-23986 If foreign key constraints are enabled when # it is prepared, the DROP TABLE command performs an implicit DELETE to | > | 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 | execsql { SELECT sql FROM sqlite_master WHERE type = 'table'} } [list \ {CREATE TABLE "p"(a REFERENCES "p", b, PRIMARY KEY(b))} \ {CREATE TABLE c1(c, d REFERENCES "p" ON UPDATE CASCADE)} \ {CREATE TABLE c2(e, f, FOREIGN KEY(f) REFERENCES "p" ON UPDATE CASCADE)} \ {CREATE TABLE c3(e, 'f col 2', FOREIGN KEY('f col 2') REFERENCES "p" ON UPDATE CASCADE)} \ ] } #------------------------------------------------------------------------- # Check that a DROP TABLE does an implicit DELETE FROM. Which does not # cause any triggers to fire, but does fire foreign key actions. # # EVIDENCE-OF: R-14208-23986 If foreign key constraints are enabled when # it is prepared, the DROP TABLE command performs an implicit DELETE to |
︙ | ︙ | |||
2765 2766 2767 2768 2769 2770 2771 2772 2773 | # 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 # TABLE commands described above only apply if foreign keys are enabled. # do_test e_fkey-61.1.1 { drop_all_tables | > | | 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 | # 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 # TABLE commands described above only apply if foreign keys are enabled. # ifcapable altertable { do_test e_fkey-61.1.1 { drop_all_tables execsql { CREATE TABLE t1(a, b) ; INSERT INTO t1 VALUES(1, 2) } catchsql { ALTER TABLE t1 ADD COLUMN c DEFAULT 'xxx' REFERENCES t2 } } {1 {Cannot add a REFERENCES column with non-NULL default value}} do_test e_fkey-61.1.2 { execsql { PRAGMA foreign_keys = OFF } execsql { ALTER TABLE t1 ADD COLUMN c DEFAULT 'xxx' REFERENCES t2 } execsql { SELECT sql FROM sqlite_master WHERE name = 't1' } } {{CREATE TABLE t1(a, b, c DEFAULT 'xxx' REFERENCES t2)}} |
︙ | ︙ | |||
2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 | DROP TABLE p; SELECT * FROM c; } } {x} do_test e_fkey-61.3.3 { execsql { PRAGMA foreign_keys = ON } } {} ########################################################################### ### SECTION 6: Limits and Unsupported Features ########################################################################### #------------------------------------------------------------------------- # Test that MATCH clauses are parsed, but SQLite treats every foreign key | > | 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 | DROP TABLE p; SELECT * FROM c; } } {x} do_test e_fkey-61.3.3 { execsql { PRAGMA foreign_keys = ON } } {} } ########################################################################### ### SECTION 6: Limits and Unsupported Features ########################################################################### #------------------------------------------------------------------------- # Test that MATCH clauses are parsed, but SQLite treats every foreign key |
︙ | ︙ |
Changes to test/e_select.test.
︙ | ︙ | |||
163 164 165 166 167 168 169 | 2002.1 "SELECT ALL 1, 2, 3 GROUP BY 2 HAVING count(*)=1" {1 2 3} 2002.2 "SELECT ALL 1, 2, 3 GROUP BY 2 HAVING count(*)>1" {} 0101.1 "SELECT count(*), max(a) FROM t1 GROUP BY b" {1 a 1 c 1 b} 0102.1 "SELECT count(*), max(a) FROM t1 GROUP BY b HAVING count(*)=1" { 1 a 1 c 1 b } | | | < | < | | < | | 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 | 2002.1 "SELECT ALL 1, 2, 3 GROUP BY 2 HAVING count(*)=1" {1 2 3} 2002.2 "SELECT ALL 1, 2, 3 GROUP BY 2 HAVING count(*)>1" {} 0101.1 "SELECT count(*), max(a) FROM t1 GROUP BY b" {1 a 1 c 1 b} 0102.1 "SELECT count(*), max(a) FROM t1 GROUP BY b HAVING count(*)=1" { 1 a 1 c 1 b } 0102.2 "SELECT count(*), max(a) FROM t1 GROUP BY b HAVING count(*)=2" {} 1101.1 "SELECT DISTINCT count(*), max(a) FROM t1 GROUP BY b" {1 a 1 c 1 b} 1102.1 "SELECT DISTINCT count(*), max(a) FROM t1 GROUP BY b HAVING count(*)=1" { 1 a 1 c 1 b } 1102.2 "SELECT DISTINCT count(*), max(a) FROM t1 GROUP BY b HAVING count(*)=2" {} 2101.1 "SELECT ALL count(*), max(a) FROM t1 GROUP BY b" {1 a 1 c 1 b} 2102.1 "SELECT ALL count(*), max(a) FROM t1 GROUP BY b HAVING count(*)=1" { 1 a 1 c 1 b } 2102.2 "SELECT ALL count(*), max(a) FROM t1 GROUP BY b HAVING count(*)=2" {} 0011.1 "SELECT 1, 2, 3 WHERE 1 GROUP BY 2" {1 2 3} 0012.1 "SELECT 1, 2, 3 WHERE 0 GROUP BY 2 HAVING count(*)=1" {} 0012.2 "SELECT 1, 2, 3 WHERE 0 GROUP BY 2 HAVING count(*)>1" {} 1011.1 "SELECT DISTINCT 1, 2, 3 WHERE 0 GROUP BY 2" {} 1012.1 "SELECT DISTINCT 1, 2, 3 WHERE 1 GROUP BY 2 HAVING count(*)=1" {1 2 3} 1012.2 "SELECT DISTINCT 1, 2, 3 WHERE NULL GROUP BY 2 HAVING count(*)>1" {} 2011.1 "SELECT ALL 1, 2, 3 WHERE 1 GROUP BY 2" {1 2 3} 2012.1 "SELECT ALL 1, 2, 3 WHERE 0 GROUP BY 2 HAVING count(*)=1" {} 2012.2 "SELECT ALL 1, 2, 3 WHERE 'abc' GROUP BY 2 HAVING count(*)>1" {} 0111.1 "SELECT count(*), max(a) FROM t1 WHERE a='a' GROUP BY b" {1 a} 0112.1 "SELECT count(*), max(a) FROM t1 WHERE a='c' GROUP BY b HAVING count(*)=1" {1 c} 0112.2 "SELECT count(*), max(a) FROM t1 WHERE 0 GROUP BY b HAVING count(*)=2" {} 1111.1 "SELECT DISTINCT count(*), max(a) FROM t1 WHERE a<'c' GROUP BY b" {1 a 1 b} 1112.1 "SELECT DISTINCT count(*), max(a) FROM t1 WHERE a>'a' GROUP BY b HAVING count(*)=1" { 1 c 1 b } 1112.2 "SELECT DISTINCT count(*), max(a) FROM t1 WHERE 0 GROUP BY b HAVING count(*)=2" {} 2111.1 "SELECT ALL count(*), max(a) FROM t1 WHERE b>'one' GROUP BY b" {1 c 1 b} 2112.1 "SELECT ALL count(*), max(a) FROM t1 WHERE a!='b' GROUP BY b HAVING count(*)=1" { 1 a 1 c } 2112.2 "SELECT ALL count(*), max(a) FROM t1 WHERE 0 GROUP BY b HAVING count(*)=2" {} } # -- syntax diagram result-column # do_select_tests e_select-0.3 { 1 "SELECT * FROM t1" {a one b two c three} |
︙ | ︙ | |||
1003 1004 1005 1006 1007 1008 1009 | CREATE TABLE b3(a COLLATE nocase, b COLLATE binary); INSERT INTO b3 VALUES('abc', 'abc'); INSERT INTO b3 VALUES('aBC', 'aBC'); INSERT INTO b3 VALUES('Def', 'Def'); INSERT INTO b3 VALUES('dEF', 'dEF'); } {} | | > | | | | 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 | CREATE TABLE b3(a COLLATE nocase, b COLLATE binary); INSERT INTO b3 VALUES('abc', 'abc'); INSERT INTO b3 VALUES('aBC', 'aBC'); INSERT INTO b3 VALUES('Def', 'Def'); INSERT INTO b3 VALUES('dEF', 'dEF'); } {} # EVIDENCE-OF: R-40855-36147 If the SELECT statement is an aggregate # query with a GROUP BY clause, then each of the expressions specified # as part of the GROUP BY clause is evaluated for each row of the # dataset according to the processing rules stated below for ORDER BY # expressions. Each row is then assigned to a "group" based on the # results; rows for which the results of evaluating the GROUP BY # expressions are the same get assigned to the same group. # # These tests also show that the following is not untrue: # # EVIDENCE-OF: R-25883-55063 The expressions in the GROUP BY clause do # not have to be expressions that appear in the result. # do_select_tests e_select-4.9 { |
︙ | ︙ |
Changes to test/e_totalchanges.test.
︙ | ︙ | |||
28 29 30 31 32 33 34 | CREATE INDEX t1_b ON t1(b); CREATE TABLE t2(x, y, PRIMARY KEY(x, y)) WITHOUT ROWID; CREATE INDEX t2_y ON t2(y); } #-------------------------------------------------------------------------- | | | | < | 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | CREATE INDEX t1_b ON t1(b); CREATE TABLE t2(x, y, PRIMARY KEY(x, y)) WITHOUT ROWID; CREATE INDEX t2_y ON t2(y); } #-------------------------------------------------------------------------- # EVIDENCE-OF: R-38914-26427 The total_changes() function returns the # number of row changes caused by INSERT, UPDATE or DELETE statements # since the current database connection was opened. # # 1.1.*: different types of I/U/D statements, # 1.2.*: trigger programs. # do_tc_test 1.1.1 { INSERT INTO t1 VALUES(1, 2); INSERT INTO t1 VALUES(3, 4); |
︙ | ︙ | |||
91 92 93 94 95 96 97 | UPDATE t1 SET b='c'; -- 1 + 1 + 2 DELETE FROM t1; -- 1 + 1 + 1 } {9} #-------------------------------------------------------------------------- # EVIDENCE-OF: R-61766-15253 Executing any other type of SQL statement # does not affect the value returned by sqlite3_total_changes(). | > | | | | | | | | | | | | | | | | | | > | 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 | UPDATE t1 SET b='c'; -- 1 + 1 + 2 DELETE FROM t1; -- 1 + 1 + 1 } {9} #-------------------------------------------------------------------------- # EVIDENCE-OF: R-61766-15253 Executing any other type of SQL statement # does not affect the value returned by sqlite3_total_changes(). ifcapable altertable { do_tc_test 2.1 { INSERT INTO t1 VALUES(1, 2), (3, 4); INSERT INTO t2 VALUES(1, 2), (3, 4); } {15} do_tc_test 2.2 { SELECT count(*) FROM t1; } {2 15} do_tc_test 2.3 { CREATE TABLE t4(a, b); ALTER TABLE t4 ADD COLUMN c; CREATE INDEX i4 ON t4(c); ALTER TABLE t4 RENAME TO t5; ANALYZE; BEGIN; DROP TABLE t2; ROLLBACK; VACUUM; } {15} } #-------------------------------------------------------------------------- # EVIDENCE-OF: R-36043-10590 Changes made as part of foreign key # actions are included in the count, but those made as part of REPLACE # constraint resolution are not. # |
︙ | ︙ |
Changes to test/e_uri.test.
︙ | ︙ | |||
21 22 23 24 25 26 27 28 29 30 31 32 33 34 | testvfs tvfs tvfs filter xOpen tvfs script parse_uri_open_cb set ::uri_open [list] set DB [sqlite3_open_v2 $uri { SQLITE_OPEN_READWRITE SQLITE_OPEN_CREATE SQLITE_OPEN_WAL } tvfs] set fileName [sqlite3_db_filename $DB main] sqlite3_close $DB forcedelete $fileName tvfs delete tvfs2 delete | > | 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | testvfs tvfs tvfs filter xOpen tvfs script parse_uri_open_cb set ::uri_open [list] set DB [sqlite3_open_v2 $uri { SQLITE_OPEN_READWRITE SQLITE_OPEN_CREATE SQLITE_OPEN_WAL SQLITE_OPEN_EXRESCODE } tvfs] set fileName [sqlite3_db_filename $DB main] sqlite3_close $DB forcedelete $fileName tvfs delete tvfs2 delete |
︙ | ︙ |
Changes to test/e_vacuum.test.
︙ | ︙ | |||
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 | # entries in any tables that do not have an explicit INTEGER PRIMARY # KEY. # # Tests e_vacuum-3.1.1 - 3.1.2 demonstrate that rowids can change when # a database is VACUUMed. Tests e_vacuum-3.1.3 - 3.1.4 show that adding # an INTEGER PRIMARY KEY column to a table stops this from happening. # do_execsql_test e_vacuum-3.1.1 { CREATE TABLE t4(x); INSERT INTO t4(x) VALUES('x'); INSERT INTO t4(x) VALUES('y'); INSERT INTO t4(x) VALUES('z'); DELETE FROM t4 WHERE x = 'y'; SELECT rowid, x FROM t4; } {1 x 3 z} do_execsql_test e_vacuum-3.1.2 { VACUUM; SELECT rowid, x FROM t4; } {1 x 2 z} do_execsql_test e_vacuum-3.1.3 { CREATE TABLE t5(x, y INTEGER PRIMARY KEY); INSERT INTO t5(x) VALUES('x'); INSERT INTO t5(x) VALUES('y'); INSERT INTO t5(x) VALUES('z'); DELETE FROM t5 WHERE x = 'y'; SELECT rowid, x FROM t5; } {1 x 3 z} do_execsql_test e_vacuum-3.1.4 { VACUUM; SELECT rowid, x FROM t5; } {1 x 3 z} | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | 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 | # entries in any tables that do not have an explicit INTEGER PRIMARY # KEY. # # Tests e_vacuum-3.1.1 - 3.1.2 demonstrate that rowids can change when # a database is VACUUMed. Tests e_vacuum-3.1.3 - 3.1.4 show that adding # an INTEGER PRIMARY KEY column to a table stops this from happening. # # Update 2019-01-07: Rowids are now preserved by VACUUM. # do_execsql_test e_vacuum-3.1.1 { CREATE TABLE t4(x); INSERT INTO t4(x) VALUES('x'); INSERT INTO t4(x) VALUES('y'); INSERT INTO t4(x) VALUES('z'); DELETE FROM t4 WHERE x = 'y'; SELECT rowid, x FROM t4; } {1 x 3 z} do_execsql_test e_vacuum-3.1.2 { VACUUM; SELECT rowid, x FROM t4; } {1 x 2 z} # Rowids are preserved if an INTEGER PRIMARY KEY is used do_execsql_test e_vacuum-3.1.3 { CREATE TABLE t5(x, y INTEGER PRIMARY KEY); INSERT INTO t5(x) VALUES('x'); INSERT INTO t5(x) VALUES('y'); INSERT INTO t5(x) VALUES('z'); DELETE FROM t5 WHERE x = 'y'; SELECT rowid, x FROM t5; } {1 x 3 z} do_execsql_test e_vacuum-3.1.4 { VACUUM; SELECT rowid, x FROM t5; } {1 x 3 z} # Rowid is preserved for VACUUM INTO do_execsql_test e_vacuum-3.1.5 { DROP TABLE t5; CREATE TABLE t5(x); INSERT INTO t5(x) VALUES('x'); INSERT INTO t5(x) VALUES('y'); INSERT INTO t5(x) VALUES('z'); DELETE FROM t5 WHERE x = 'y'; SELECT rowid, x FROM t5; } {1 x 3 z} forcedelete test2.db do_execsql_test e_vacuum-3.1.6 { VACUUM INTO 'test2.db'; ATTACH 'test2.db' AS aux1; SELECT rowid, x FROM aux1.t5; DETACH aux1; } {1 x 3 z} # Rowids are not renumbered if the table being vacuumed # has indexes. do_execsql_test e_vacuum-3.1.7 { DROP TABLE t5; CREATE TABLE t5(x,y,z); INSERT INTO t5(x) VALUES('x'); INSERT INTO t5(x) VALUES('y'); INSERT INTO t5(x) VALUES('z'); UPDATE t5 SET y=x, z=random(); DELETE FROM t5 WHERE x = 'y'; CREATE INDEX t5x ON t5(x); CREATE UNIQUE INDEX t5y ON t5(y); CREATE INDEX t5zxy ON t5(z,x,y); SELECT rowid, x FROM t5; } {1 x 3 z} do_execsql_test e_vacuum-3.1.8 { VACUUM; SELECT rowid, x FROM t5; } {1 x 3 z} # EVIDENCE-OF: R-12218-18073 A VACUUM will fail if there is an open # transaction on the database connection that is attempting to run the # VACUUM. # do_execsql_test e_vacuum-3.2.1.1 { BEGIN } {} do_catchsql_test e_vacuum-3.2.1.2 { VACUUM } {1 {cannot VACUUM from within a transaction}} do_execsql_test e_vacuum-3.2.1.3 { COMMIT } {} do_execsql_test e_vacuum-3.2.1.4 { VACUUM } {} |
︙ | ︙ |
Changes to test/enc.test.
︙ | ︙ | |||
164 165 166 167 168 169 170 171 172 | } {} do_test enc-11.2 { set cp200 "\u00C8" execsql { SELECT count(*) FROM ab WHERE a = $::cp200; } } {2} finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | } {} do_test enc-11.2 { set cp200 "\u00C8" execsql { SELECT count(*) FROM ab WHERE a = $::cp200; } } {2} #------------------------------------------------------------------------- reset_db forcedelete test.db2 forcedelete test.db3 do_execsql_test enc-12.0 { PRAGMA encoding = 'utf-8'; CREATE TABLE t1(a, b, c); INSERT INTO t1 VALUES('a', 'b', 'c'); ATTACH 'test.db3' AS aux; CREATE TABLE aux.t3(x, y, z); INSERT INTO t3 VALUES('xxx', 'yyy', 'zzz'); PRAGMA encoding; } {UTF-8} do_test enc-12.1 { sqlite3 db2 test.db2 db2 eval { PRAGMA encoding = 'UTF-16le'; CREATE TABLE t2(d, e, f); INSERT INTO t2 VALUES('d', 'e', 'f'); PRAGMA encoding; } } {UTF-16le} do_test enc-12.2 { db2 backup test.db db2 close } {} do_catchsql_test enc-12.3 { SELECT * FROM t2; } {1 {attached databases must use the same text encoding as main database}} db close sqlite3 db test.db3 do_execsql_test enc-12.4 { SELECT * FROM t3; PRAGMA encoding = 'UTF-16le'; SELECT * FROM t3; } {xxx yyy zzz xxx yyy zzz} db close sqlite3 db test.db3 breakpoint do_execsql_test enc-12.5 { PRAGMA encoding = 'UTF-16le'; PRAGMA encoding; } {UTF-8} reset_db do_execsql_test enc-12.6 { PRAGMA encoding = 'UTF-8'; CREATE TEMP TABLE t1(a, b, c); INSERT INTO t1 VALUES('xxx', 'yyy', 'zzz'); } do_test enc-12.7 { sqlite3 db2 test.db2 db2 backup test.db db2 close db eval { SELECT * FROM t1; } } {xxx yyy zzz} do_catchsql_test enc-12.8 { SELECT * FROM t2; SELECT * FROM t1; } {1 {attached databases must use the same text encoding as main database}} db close sqlite3 db test.db do_execsql_test enc-12.9 { CREATE TEMP TABLE t1(a, b, c); INSERT INTO t1 VALUES('xxx', 'yyy', 'zzz'); } do_execsql_test enc-12.10 { SELECT * FROM t2; SELECT * FROM t1; } {d e f xxx yyy zzz} finish_test |
Changes to test/enc2.test.
︙ | ︙ | |||
9 10 11 12 13 14 15 | # #*********************************************************************** # This file implements regression tests for SQLite library. The focus of # this file is testing the SQLite routines used for converting between the # various suported unicode encodings (UTF-8, UTF-16, UTF-16le and # UTF-16be). # | < | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | # #*********************************************************************** # This file implements regression tests for SQLite library. The focus of # this file is testing the SQLite routines used for converting between the # various suported unicode encodings (UTF-8, UTF-16, UTF-16le and # UTF-16be). # set testdir [file dirname $argv0] source $testdir/tester.tcl # If UTF16 support is disabled, ignore the tests in this file # ifcapable {!utf16} { |
︙ | ︙ | |||
547 548 549 550 551 552 553 554 555 | } db close sqlite3 db test.db db eval { SELECT name FROM sqlite_master } } {t1 t2} finish_test | > > > > > > > > > > > > > | 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 | } db close sqlite3 db test.db db eval { SELECT name FROM sqlite_master } } {t1 t2} # 2020-01-15 ticket a08879a4a476eea9 # Do not allow a database connection encoding change unless *all* # attached databases are empty. # reset_db do_execsql_test enc2-11.10 { PRAGMA encoding=UTF8; CREATE TEMP TABLE t1(x); INSERT INTO t1 VALUES('this is a test'); PRAGMA encoding=UTF16; SELECT * FROM t1; } {{this is a test}} finish_test |
Changes to test/eqp.test.
︙ | ︙ | |||
41 42 43 44 45 46 47 | } do_eqp_test 1.2 { SELECT * FROM t2, t1 WHERE t1.a=1 OR t1.b=2; } { QUERY PLAN |--MULTI-INDEX OR | > | > | | | > | > | | | | | | | | > > > > > > > > > > > > > > > > > > > > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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 | } do_eqp_test 1.2 { SELECT * FROM t2, t1 WHERE t1.a=1 OR t1.b=2; } { QUERY PLAN |--MULTI-INDEX OR | |--INDEX 1 | | `--SEARCH t1 USING INDEX i1 (a=?) | `--INDEX 2 | `--SEARCH t1 USING INDEX i2 (b=?) `--SCAN t2 } do_eqp_test 1.3 { SELECT * FROM t2 CROSS JOIN t1 WHERE t1.a=1 OR t1.b=2; } { QUERY PLAN |--SCAN t2 `--MULTI-INDEX OR |--INDEX 1 | `--SEARCH t1 USING INDEX i1 (a=?) `--INDEX 2 `--SEARCH t1 USING INDEX i2 (b=?) } do_eqp_test 1.3 { SELECT a FROM t1 ORDER BY a } { QUERY PLAN `--SCAN t1 USING COVERING INDEX i1 } do_eqp_test 1.4 { SELECT a FROM t1 ORDER BY +a } { QUERY PLAN |--SCAN t1 USING COVERING INDEX i1 `--USE TEMP B-TREE FOR ORDER BY } do_eqp_test 1.5 { SELECT a FROM t1 WHERE a=4 } { QUERY PLAN `--SEARCH t1 USING COVERING INDEX i1 (a=?) } do_eqp_test 1.6 { SELECT DISTINCT count(*) FROM t3 GROUP BY a; } { QUERY PLAN |--SCAN t3 |--USE TEMP B-TREE FOR GROUP BY `--USE TEMP B-TREE FOR DISTINCT } do_eqp_test 1.7.1 { SELECT * FROM t3 JOIN (SELECT 1) } { QUERY PLAN |--MATERIALIZE SUBQUERY xxxxxx | `--SCAN CONSTANT ROW |--SCAN SUBQUERY xxxxxx `--SCAN t3 } do_eqp_test 1.7.2 { SELECT * FROM t3 JOIN (SELECT 1) AS v1 } { QUERY PLAN |--MATERIALIZE v1 | `--SCAN CONSTANT ROW |--SCAN v1 `--SCAN t3 } do_eqp_test 1.7.3 { SELECT * FROM t3 AS xx JOIN (SELECT 1) AS yy } { QUERY PLAN |--MATERIALIZE yy | `--SCAN CONSTANT ROW |--SCAN yy `--SCAN xx } do_eqp_test 1.8 { SELECT * FROM t3 JOIN (SELECT 1 UNION SELECT 2) } { QUERY PLAN |--MATERIALIZE SUBQUERY xxxxxx | `--COMPOUND QUERY | |--LEFT-MOST SUBQUERY | | `--SCAN CONSTANT ROW | `--UNION USING TEMP B-TREE | `--SCAN CONSTANT ROW |--SCAN SUBQUERY xxxxxx `--SCAN t3 } do_eqp_test 1.9 { SELECT * FROM t3 JOIN (SELECT 1 EXCEPT SELECT a FROM t3 LIMIT 17) AS abc } { QUERY PLAN |--MATERIALIZE abc | `--COMPOUND QUERY | |--LEFT-MOST SUBQUERY | | `--SCAN CONSTANT ROW | `--EXCEPT USING TEMP B-TREE | `--SCAN t3 |--SCAN abc `--SCAN t3 } do_eqp_test 1.10 { SELECT * FROM t3 JOIN (SELECT 1 INTERSECT SELECT a FROM t3 LIMIT 17) AS abc } { QUERY PLAN |--MATERIALIZE abc | `--COMPOUND QUERY | |--LEFT-MOST SUBQUERY | | `--SCAN CONSTANT ROW | `--INTERSECT USING TEMP B-TREE | `--SCAN t3 |--SCAN abc `--SCAN t3 } do_eqp_test 1.11 { SELECT * FROM t3 JOIN (SELECT 1 UNION ALL SELECT a FROM t3 LIMIT 17) abc } { QUERY PLAN |--MATERIALIZE abc | `--COMPOUND QUERY | |--LEFT-MOST SUBQUERY | | `--SCAN CONSTANT ROW | `--UNION ALL | `--SCAN t3 |--SCAN abc `--SCAN t3 } #------------------------------------------------------------------------- # Test cases eqp-2.* - tests for single select statements. # drop_all_tables do_execsql_test 2.1 { CREATE TABLE t1(x INT, y INT, ex TEXT); CREATE TABLE t2(x INT, y INT, ex TEXT); CREATE INDEX t2i1 ON t2(x); } det 2.2.1 "SELECT DISTINCT min(x), max(x) FROM t1 GROUP BY x ORDER BY 1" { QUERY PLAN |--SCAN t1 |--USE TEMP B-TREE FOR GROUP BY |--USE TEMP B-TREE FOR DISTINCT `--USE TEMP B-TREE FOR ORDER BY } det 2.2.2 "SELECT DISTINCT min(x), max(x) FROM t2 GROUP BY x ORDER BY 1" { QUERY PLAN |--SCAN t2 USING COVERING INDEX t2i1 |--USE TEMP B-TREE FOR DISTINCT `--USE TEMP B-TREE FOR ORDER BY } det 2.2.3 "SELECT DISTINCT * FROM t1" { QUERY PLAN |--SCAN t1 `--USE TEMP B-TREE FOR DISTINCT } det 2.2.4 "SELECT DISTINCT * FROM t1, t2" { QUERY PLAN |--SCAN t1 |--SCAN t2 `--USE TEMP B-TREE FOR DISTINCT } det 2.2.5 "SELECT DISTINCT * FROM t1, t2 ORDER BY t1.x" { QUERY PLAN |--SCAN t1 |--SCAN t2 |--USE TEMP B-TREE FOR DISTINCT `--USE TEMP B-TREE FOR ORDER BY } det 2.2.6 "SELECT DISTINCT t2.x FROM t1, t2 ORDER BY t2.x" { QUERY PLAN |--SCAN t2 USING COVERING INDEX t2i1 `--SCAN t1 } det 2.3.1 "SELECT max(x) FROM t2" { QUERY PLAN `--SEARCH t2 USING COVERING INDEX t2i1 } det 2.3.2 "SELECT min(x) FROM t2" { QUERY PLAN `--SEARCH t2 USING COVERING INDEX t2i1 } det 2.3.3 "SELECT min(x), max(x) FROM t2" { QUERY PLAN `--SCAN t2 USING COVERING INDEX t2i1 } det 2.4.1 "SELECT * FROM t1 WHERE rowid=?" { QUERY PLAN `--SEARCH t1 USING INTEGER PRIMARY KEY (rowid=?) } #------------------------------------------------------------------------- # Test cases eqp-3.* - tests for select statements that use sub-selects. # do_eqp_test 3.1.1 { SELECT (SELECT x FROM t1 AS sub) FROM t1; } { QUERY PLAN |--SCAN t1 `--SCALAR SUBQUERY xxxxxx `--SCAN sub } do_eqp_test 3.1.2 { SELECT * FROM t1 WHERE (SELECT x FROM t1 AS sub); } { QUERY PLAN |--SCAN t1 `--SCALAR SUBQUERY xxxxxx `--SCAN sub } do_eqp_test 3.1.3 { SELECT * FROM t1 WHERE (SELECT x FROM t1 AS sub ORDER BY y); } { QUERY PLAN |--SCAN t1 `--SCALAR SUBQUERY xxxxxx |--SCAN sub `--USE TEMP B-TREE FOR ORDER BY } do_eqp_test 3.1.4 { SELECT * FROM t1 WHERE (SELECT x FROM t2 ORDER BY x); } { QUERY PLAN |--SCAN t1 `--SCALAR SUBQUERY xxxxxx `--SCAN t2 USING COVERING INDEX t2i1 } det 3.2.1 { SELECT * FROM (SELECT * FROM t1 ORDER BY x LIMIT 10) ORDER BY y LIMIT 5 } { QUERY PLAN |--CO-ROUTINE SUBQUERY xxxxxx | |--SCAN t1 | `--USE TEMP B-TREE FOR ORDER BY |--SCAN SUBQUERY xxxxxx `--USE TEMP B-TREE FOR ORDER BY } det 3.2.2 { SELECT * FROM (SELECT * FROM t1 ORDER BY x LIMIT 10) AS x1, (SELECT * FROM t2 ORDER BY x LIMIT 10) AS x2 ORDER BY x2.y LIMIT 5 } { QUERY PLAN |--MATERIALIZE x1 | |--SCAN t1 | `--USE TEMP B-TREE FOR ORDER BY |--MATERIALIZE x2 | `--SCAN t2 USING INDEX t2i1 |--SCAN x1 |--SCAN x2 `--USE TEMP B-TREE FOR ORDER BY } det 3.3.1 { SELECT * FROM t1 WHERE y IN (SELECT y FROM t2) } { QUERY PLAN |--SCAN t1 `--LIST SUBQUERY xxxxxx `--SCAN t2 } det 3.3.2 { SELECT * FROM t1 WHERE y IN (SELECT y FROM t2 WHERE t1.x!=t2.x) } { QUERY PLAN |--SCAN t1 `--CORRELATED LIST SUBQUERY xxxxxx `--SCAN t2 } det 3.3.3 { SELECT * FROM t1 WHERE EXISTS (SELECT y FROM t2 WHERE t1.x!=t2.x) } { QUERY PLAN |--SCAN t1 `--CORRELATED SCALAR SUBQUERY xxxxxx `--SCAN t2 } #------------------------------------------------------------------------- # Test cases eqp-4.* - tests for composite select statements. # do_eqp_test 4.1.1 { SELECT * FROM t1 UNION ALL SELECT * FROM t2 } { QUERY PLAN `--COMPOUND QUERY |--LEFT-MOST SUBQUERY | `--SCAN t1 `--UNION ALL `--SCAN t2 } do_eqp_test 4.1.2 { SELECT * FROM t1 UNION ALL SELECT * FROM t2 ORDER BY 2 } { QUERY PLAN `--MERGE (UNION ALL) |--LEFT | |--SCAN t1 | `--USE TEMP B-TREE FOR ORDER BY `--RIGHT |--SCAN t2 `--USE TEMP B-TREE FOR ORDER BY } do_eqp_test 4.1.3 { SELECT * FROM t1 UNION SELECT * FROM t2 ORDER BY 2 } { QUERY PLAN `--MERGE (UNION) |--LEFT | |--SCAN t1 | `--USE TEMP B-TREE FOR ORDER BY `--RIGHT |--SCAN t2 `--USE TEMP B-TREE FOR ORDER BY } do_eqp_test 4.1.4 { SELECT * FROM t1 INTERSECT SELECT * FROM t2 ORDER BY 2 } { QUERY PLAN `--MERGE (INTERSECT) |--LEFT | |--SCAN t1 | `--USE TEMP B-TREE FOR ORDER BY `--RIGHT |--SCAN t2 `--USE TEMP B-TREE FOR ORDER BY } do_eqp_test 4.1.5 { SELECT * FROM t1 EXCEPT SELECT * FROM t2 ORDER BY 2 } { QUERY PLAN `--MERGE (EXCEPT) |--LEFT | |--SCAN t1 | `--USE TEMP B-TREE FOR ORDER BY `--RIGHT |--SCAN t2 `--USE TEMP B-TREE FOR ORDER BY } do_eqp_test 4.2.2 { SELECT * FROM t1 UNION ALL SELECT * FROM t2 ORDER BY 1 } { QUERY PLAN `--MERGE (UNION ALL) |--LEFT | |--SCAN t1 | `--USE TEMP B-TREE FOR ORDER BY `--RIGHT `--SCAN t2 USING INDEX t2i1 } do_eqp_test 4.2.3 { SELECT * FROM t1 UNION SELECT * FROM t2 ORDER BY 1 } { QUERY PLAN `--MERGE (UNION) |--LEFT | |--SCAN t1 | `--USE TEMP B-TREE FOR ORDER BY `--RIGHT |--SCAN t2 USING INDEX t2i1 `--USE TEMP B-TREE FOR RIGHT PART OF ORDER BY } do_eqp_test 4.2.4 { SELECT * FROM t1 INTERSECT SELECT * FROM t2 ORDER BY 1 } { QUERY PLAN `--MERGE (INTERSECT) |--LEFT | |--SCAN t1 | `--USE TEMP B-TREE FOR ORDER BY `--RIGHT |--SCAN t2 USING INDEX t2i1 `--USE TEMP B-TREE FOR RIGHT PART OF ORDER BY } do_eqp_test 4.2.5 { SELECT * FROM t1 EXCEPT SELECT * FROM t2 ORDER BY 1 } { QUERY PLAN `--MERGE (EXCEPT) |--LEFT | |--SCAN t1 | `--USE TEMP B-TREE FOR ORDER BY `--RIGHT |--SCAN t2 USING INDEX t2i1 `--USE TEMP B-TREE FOR RIGHT PART OF ORDER BY } do_eqp_test 4.3.1 { SELECT x FROM t1 UNION SELECT x FROM t2 } { QUERY PLAN `--COMPOUND QUERY |--LEFT-MOST SUBQUERY | `--SCAN t1 `--UNION USING TEMP B-TREE `--SCAN t2 USING COVERING INDEX t2i1 } do_eqp_test 4.3.2 { SELECT x FROM t1 UNION SELECT x FROM t2 UNION SELECT x FROM t1 } { QUERY PLAN `--COMPOUND QUERY |--LEFT-MOST SUBQUERY | `--SCAN t1 |--UNION USING TEMP B-TREE | `--SCAN t2 USING COVERING INDEX t2i1 `--UNION USING TEMP B-TREE `--SCAN t1 } do_eqp_test 4.3.3 { SELECT x FROM t1 UNION SELECT x FROM t2 UNION SELECT x FROM t1 ORDER BY 1 } { QUERY PLAN `--MERGE (UNION) |--LEFT | `--MERGE (UNION) | |--LEFT | | |--SCAN t1 | | `--USE TEMP B-TREE FOR ORDER BY | `--RIGHT | `--SCAN t2 USING COVERING INDEX t2i1 `--RIGHT |--SCAN t1 `--USE TEMP B-TREE FOR ORDER BY } if 0 { #------------------------------------------------------------------------- # This next block of tests verifies that the examples on the # lang_explain.html page are correct. # drop_all_tables # XVIDENCE-OF: R-47779-47605 sqlite> EXPLAIN QUERY PLAN SELECT a, b # FROM t1 WHERE a=1; # 0|0|0|SCAN t1 # do_execsql_test 5.1.0 { CREATE TABLE t1(a INT, b INT, ex TEXT) } det 5.1.1 "SELECT a, b FROM t1 WHERE a=1" { 0 0 0 {SCAN t1} } # XVIDENCE-OF: R-55852-17599 sqlite> CREATE INDEX i1 ON t1(a); # sqlite> EXPLAIN QUERY PLAN SELECT a, b FROM t1 WHERE a=1; # 0|0|0|SEARCH t1 USING INDEX i1 # do_execsql_test 5.2.0 { CREATE INDEX i1 ON t1(a) } det 5.2.1 "SELECT a, b FROM t1 WHERE a=1" { 0 0 0 {SEARCH t1 USING INDEX i1 (a=?)} } # XVIDENCE-OF: R-21179-11011 sqlite> CREATE INDEX i2 ON t1(a, b); # sqlite> EXPLAIN QUERY PLAN SELECT a, b FROM t1 WHERE a=1; # 0|0|0|SEARCH t1 USING COVERING INDEX i2 (a=?) # do_execsql_test 5.3.0 { CREATE INDEX i2 ON t1(a, b) } det 5.3.1 "SELECT a, b FROM t1 WHERE a=1" { 0 0 0 {SEARCH t1 USING COVERING INDEX i2 (a=?)} } # XVIDENCE-OF: R-09991-48941 sqlite> EXPLAIN QUERY PLAN # SELECT t1.*, t2.* FROM t1, t2 WHERE t1.a=1 AND t1.b>2; # 0|0|0|SEARCH t1 USING COVERING INDEX i2 (a=? AND b>?) # 0|1|1|SCAN t2 # do_execsql_test 5.4.0 {CREATE TABLE t2(c INT, d INT, ex TEXT)} det 5.4.1 "SELECT t1.a, t2.c FROM t1, t2 WHERE t1.a=1 AND t1.b>2" { 0 0 0 {SEARCH t1 USING COVERING INDEX i2 (a=? AND b>?)} 0 1 1 {SCAN t2} } # XVIDENCE-OF: R-33626-61085 sqlite> EXPLAIN QUERY PLAN # SELECT t1.*, t2.* FROM t2, t1 WHERE t1.a=1 AND t1.b>2; # 0|0|1|SEARCH t1 USING COVERING INDEX i2 (a=? AND b>?) # 0|1|0|SCAN t2 # det 5.5 "SELECT t1.a, t2.c FROM t2, t1 WHERE t1.a=1 AND t1.b>2" { 0 0 1 {SEARCH t1 USING COVERING INDEX i2 (a=? AND b>?)} 0 1 0 {SCAN t2} } # XVIDENCE-OF: R-04002-25654 sqlite> CREATE INDEX i3 ON t1(b); # sqlite> EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a=1 OR b=2; # 0|0|0|SEARCH t1 USING COVERING INDEX i2 (a=?) # 0|0|0|SEARCH t1 USING INDEX i3 (b=?) # do_execsql_test 5.5.0 {CREATE INDEX i3 ON t1(b)} det 5.6.1 "SELECT a, b FROM t1 WHERE a=1 OR b=2" { 0 0 0 {SEARCH t1 USING COVERING INDEX i2 (a=?)} 0 0 0 {SEARCH t1 USING INDEX i3 (b=?)} } # XVIDENCE-OF: R-24577-38891 sqlite> EXPLAIN QUERY PLAN # SELECT c, d FROM t2 ORDER BY c; # 0|0|0|SCAN t2 # 0|0|0|USE TEMP B-TREE FOR ORDER BY # det 5.7 "SELECT c, d FROM t2 ORDER BY c" { 0 0 0 {SCAN t2} 0 0 0 {USE TEMP B-TREE FOR ORDER BY} } # XVIDENCE-OF: R-58157-12355 sqlite> CREATE INDEX i4 ON t2(c); # sqlite> EXPLAIN QUERY PLAN SELECT c, d FROM t2 ORDER BY c; # 0|0|0|SCAN t2 USING INDEX i4 # do_execsql_test 5.8.0 {CREATE INDEX i4 ON t2(c)} det 5.8.1 "SELECT c, d FROM t2 ORDER BY c" { 0 0 0 {SCAN t2 USING INDEX i4} } # XVIDENCE-OF: R-13931-10421 sqlite> EXPLAIN QUERY PLAN SELECT # (SELECT b FROM t1 WHERE a=0), (SELECT a FROM t1 WHERE b=t2.c) FROM t2; # 0|0|0|SCAN t2 # 0|0|0|EXECUTE SCALAR SUBQUERY 1 # 1|0|0|SEARCH t1 USING COVERING INDEX i2 (a=?) # 0|0|0|EXECUTE CORRELATED SCALAR SUBQUERY 2 # 2|0|0|SEARCH t1 USING INDEX i3 (b=?) # det 5.9 { SELECT (SELECT b FROM t1 WHERE a=0), (SELECT a FROM t1 WHERE b=t2.c) FROM t2 } { 0 0 0 {SCAN t2 USING COVERING INDEX i4} 0 0 0 {EXECUTE SCALAR SUBQUERY 1} 1 0 0 {SEARCH t1 USING COVERING INDEX i2 (a=?)} 0 0 0 {EXECUTE CORRELATED SCALAR SUBQUERY 2} 2 0 0 {SEARCH t1 USING INDEX i3 (b=?)} } # XVIDENCE-OF: R-50892-45943 sqlite> EXPLAIN QUERY PLAN # SELECT count(*) FROM (SELECT max(b) AS x FROM t1 GROUP BY a) GROUP BY x; # 1|0|0|SCAN t1 USING COVERING INDEX i2 # 0|0|0|SCAN SUBQUERY 1 # 0|0|0|USE TEMP B-TREE FOR GROUP BY # det 5.10 { SELECT count(*) FROM (SELECT max(b) AS x FROM t1 GROUP BY a) GROUP BY x } { 1 0 0 {SCAN t1 USING COVERING INDEX i2} 0 0 0 {SCAN SUBQUERY 1} 0 0 0 {USE TEMP B-TREE FOR GROUP BY} } # XVIDENCE-OF: R-46219-33846 sqlite> EXPLAIN QUERY PLAN # SELECT * FROM (SELECT * FROM t2 WHERE c=1), t1; # 0|0|0|SEARCH t2 USING INDEX i4 (c=?) # 0|1|1|SCAN t1 # det 5.11 "SELECT a, b FROM (SELECT * FROM t2 WHERE c=1), t1" { 0 0 0 {SEARCH t2 USING INDEX i4 (c=?)} 0 1 1 {SCAN t1 USING COVERING INDEX i2} } # XVIDENCE-OF: R-37879-39987 sqlite> EXPLAIN QUERY PLAN # SELECT a FROM t1 UNION SELECT c FROM t2; # 1|0|0|SCAN t1 # 2|0|0|SCAN t2 # 0|0|0|COMPOUND SUBQUERIES 1 AND 2 USING TEMP B-TREE (UNION) # det 5.12 "SELECT a,b FROM t1 UNION SELECT c, 99 FROM t2" { 1 0 0 {SCAN t1 USING COVERING INDEX i2} 2 0 0 {SCAN t2 USING COVERING INDEX i4} 0 0 0 {COMPOUND SUBQUERIES 1 AND 2 USING TEMP B-TREE (UNION)} } # XVIDENCE-OF: R-44864-63011 sqlite> EXPLAIN QUERY PLAN # SELECT a FROM t1 EXCEPT SELECT d FROM t2 ORDER BY 1; # 1|0|0|SCAN t1 USING COVERING INDEX i2 # 2|0|0|SCAN t2 2|0|0|USE TEMP B-TREE FOR ORDER BY # 0|0|0|COMPOUND SUBQUERIES 1 AND 2 (EXCEPT) # det 5.13 "SELECT a FROM t1 EXCEPT SELECT d FROM t2 ORDER BY 1" { 1 0 0 {SCAN t1 USING COVERING INDEX i1} 2 0 0 {SCAN t2} 2 0 0 {USE TEMP B-TREE FOR ORDER BY} 0 0 0 {COMPOUND SUBQUERIES 1 AND 2 (EXCEPT)} } if {![nonzero_reserved_bytes]} { #------------------------------------------------------------------------- # The following tests - eqp-6.* - test that the example C code on |
︙ | ︙ | |||
639 640 641 642 643 644 645 | set data }] [list $res] } do_peqp_test 6.1 { SELECT a, b FROM t1 EXCEPT SELECT d, 99 FROM t2 ORDER BY 1 } [string trimleft { | | | | | | | | | | | | | | | 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 | set data }] [list $res] } do_peqp_test 6.1 { SELECT a, b FROM t1 EXCEPT SELECT d, 99 FROM t2 ORDER BY 1 } [string trimleft { 1 0 0 SCAN t1 USING COVERING INDEX i2 2 0 0 SCAN t2 2 0 0 USE TEMP B-TREE FOR ORDER BY 0 0 0 COMPOUND SUBQUERIES 1 AND 2 (EXCEPT) }] } } #------------------------------------------------------------------------- # The following tests - eqp-7.* - test that queries that use the OP_Count # optimization return something sensible with EQP. # drop_all_tables do_execsql_test 7.0 { CREATE TABLE t1(a INT, b INT, ex CHAR(100)); CREATE TABLE t2(a INT, b INT, ex CHAR(100)); CREATE INDEX i1 ON t2(a); } det 7.1 "SELECT count(*) FROM t1" { QUERY PLAN `--SCAN t1 } det 7.2 "SELECT count(*) FROM t2" { QUERY PLAN `--SCAN t2 USING COVERING INDEX i1 } do_execsql_test 7.3 { INSERT INTO t1(a,b) VALUES(1, 2); INSERT INTO t1(a,b) VALUES(3, 4); INSERT INTO t2(a,b) VALUES(1, 2); INSERT INTO t2(a,b) VALUES(3, 4); INSERT INTO t2(a,b) VALUES(5, 6); ANALYZE; } db close sqlite3 db test.db det 7.4 "SELECT count(*) FROM t1" { QUERY PLAN `--SCAN t1 } det 7.5 "SELECT count(*) FROM t2" { QUERY PLAN `--SCAN t2 USING COVERING INDEX i1 } #------------------------------------------------------------------------- # The following tests - eqp-8.* - test that queries that use the OP_Count # optimization return something sensible with EQP. # drop_all_tables do_execsql_test 8.0 { CREATE TABLE t1(a, b, c, PRIMARY KEY(b, c)) WITHOUT ROWID; CREATE TABLE t2(a, b, c); } det 8.1.1 "SELECT * FROM t2" { QUERY PLAN `--SCAN t2 } det 8.1.2 "SELECT * FROM t2 WHERE rowid=?" { QUERY PLAN `--SEARCH t2 USING INTEGER PRIMARY KEY (rowid=?) } det 8.1.3 "SELECT count(*) FROM t2" { QUERY PLAN `--SCAN t2 } det 8.2.1 "SELECT * FROM t1" { QUERY PLAN `--SCAN t1 } det 8.2.2 "SELECT * FROM t1 WHERE b=?" { QUERY PLAN `--SEARCH t1 USING PRIMARY KEY (b=?) } det 8.2.3 "SELECT * FROM t1 WHERE b=? AND c=?" { QUERY PLAN `--SEARCH t1 USING PRIMARY KEY (b=? AND c=?) } det 8.2.4 "SELECT count(*) FROM t1" { QUERY PLAN `--SCAN t1 } # 2018-08-16: While working on Fossil I discovered that EXPLAIN QUERY PLAN # did not describe IN operators implemented using a ROWID lookup. These # test cases ensure that problem as been fixed. # do_execsql_test 9.0 { |
︙ | ︙ | |||
806 807 808 809 810 811 812 | substr(event.comment,instr(event.comment,':')+1) FROM thread, blob, event WHERE blob.rid=thread.last AND event.objid=thread.last ORDER BY 1; } { QUERY PLAN | | | | | | | | | 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 | substr(event.comment,instr(event.comment,':')+1) FROM thread, blob, event WHERE blob.rid=thread.last AND event.objid=thread.last ORDER BY 1; } { QUERY PLAN |--MATERIALIZE thread | |--SCAN x USING INDEX forumthread | |--USING ROWID SEARCH ON TABLE private FOR IN-OPERATOR | |--CORRELATED SCALAR SUBQUERY xxxxxx | | |--SEARCH forumpost USING COVERING INDEX forumthread (froot=?) | | `--USING ROWID SEARCH ON TABLE private FOR IN-OPERATOR | `--USE TEMP B-TREE FOR ORDER BY |--SCAN thread |--SEARCH blob USING INTEGER PRIMARY KEY (rowid=?) |--SEARCH event USING INTEGER PRIMARY KEY (rowid=?) `--USE TEMP B-TREE FOR ORDER BY } finish_test |
Changes to test/exclusive.test.
︙ | ︙ | |||
506 507 508 509 510 511 512 513 514 515 516 | sqlite3 db test.db } {} do_execsql_test exclusive-6.5 { PRAGMA locking_mode = EXCLUSIVE; SELECT * FROM sqlite_master; } {exclusive} } ;# atomic_batch_write==0 finish_test | > > > > > > > > > > > > > > > > > > > > > > > > | 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 | sqlite3 db test.db } {} do_execsql_test exclusive-6.5 { PRAGMA locking_mode = EXCLUSIVE; SELECT * FROM sqlite_master; } {exclusive} # 2019-12-26 ticket fb3b3024ea238d5c if {[permutation]!="journaltest"} { # The custom VFS used by the "journaltest" permutation cannot open the # shared-memory file. So, while it is able to switch the db file to # journal_mode=WAL when locking_mode=EXCLUSIVE, it can no longer access # it once the locking_mode is changed back to NORMAL. do_test exclusive-7.1 { db close forcedelete test.db test.db-journal test.db-wal sqlite3 db test.db # The following sequence of pragmas would trigger an assert() # associated with Pager.changeCountDone inside of assert_pager_state(), # prior to the fix. db eval { PRAGMA locking_mode = EXCLUSIVE; PRAGMA journal_mode = WAL; PRAGMA locking_mode = NORMAL; PRAGMA user_version; PRAGMA journal_mode = DELETE; } } {exclusive wal normal 0 delete} } } ;# atomic_batch_write==0 finish_test |
Changes to test/expr.test.
︙ | ︙ | |||
1031 1032 1033 1034 1035 1036 1037 1038 1039 | } {0} do_execsql_test expr-15.$tn.6 { SELECT sum(CASE WHEN x THEN 0 ELSE 1 END) FROM t1 WHERE x } {0} } finish_test | > > > > > > > > > > > > > > > > > > > > | 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 | } {0} do_execsql_test expr-15.$tn.6 { SELECT sum(CASE WHEN x THEN 0 ELSE 1 END) FROM t1 WHERE x } {0} } reset_db sqlite3_test_control SQLITE_TESTCTRL_INTERNAL_FUNCTIONS db do_execsql_test expr-16.1 { CREATE TABLE t1(a,b,c); CREATE TABLE dual(dummy); INSERT INTO dual VALUES('X'); } {} do_execsql_test expr-16.100 { SELECT implies_nonnull_row( (b=1 AND 0)>(b=3 AND 0),a) FROM dual LEFT JOIN t1; } {0} do_execsql_test expr-16.101 { SELECT implies_nonnull_row( (b=1 AND 0)>(b=3 AND a=4),a) FROM dual LEFT JOIN t1; } {1} do_execsql_test expr-16.102 { SELECT implies_nonnull_row( (b=1 AND a=2)>(b=3 AND a=4),a) FROM dual LEFT JOIN t1; } {1} finish_test |
Added test/expr2.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 | # 2019 May 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. The # focus of this file is testing expressions. # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix expr2 do_execsql_test 1.0 { CREATE TABLE t0(c0); INSERT INTO t0(c0) VALUES ('val'); } do_execsql_test 1.1 { SELECT * FROM t0 WHERE ( ( (0 IS NOT FALSE) OR NOT (0 IS FALSE OR (t0.c0 = 1)) ) IS 0 ) } {val} do_execsql_test 1.2.1 { SELECT ( (0 IS NOT FALSE) OR NOT (0 IS FALSE OR (t0.c0 = 1)) ) IS 0 FROM t0 } {1} do_execsql_test 1.2.2 { SELECT ( (0 IS NOT FALSE) OR NOT (0 IS 0 OR (t0.c0 = 1)) ) IS 0 FROM t0 } {1} do_execsql_test 1.3 { SELECT ( (0 IS NOT FALSE) OR NOT (0 IS FALSE OR (t0.c0 = 1)) ) FROM t0 } {0} do_execsql_test 1.4.1 { SELECT (0 IS NOT FALSE) FROM t0 } {0} do_execsql_test 1.4.2 { SELECT NOT (0 IS FALSE OR (t0.c0 = 1)) FROM t0 } {0} finish_test |
Added test/exprfault.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 | # 2021 April 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 file implements regression tests for SQLite library. # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix exprfault do_execsql_test 1.0 { CREATE TABLE t1(a); CREATE TABLE t2(d); } faultsim_save_and_close do_faultsim_test 1.1 -faults oom* -prep { faultsim_restore_and_reopen } -body { execsql { SELECT a = ( SELECT d FROM (SELECT d FROM t2) ) FROM t1 } } -test { faultsim_test_result {0 {}} } finish_test |
Added test/external_reader.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 | # 2021 April 2 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # set testdir [file dirname $argv0] source $testdir/tester.tcl source $testdir/lock_common.tcl set testprefix external_reader ifcapable !wal { finish_test return } if {$::tcl_platform(platform)!="unix"} { finish_test return } do_multiclient_test tn { set bExternal 1 if {[info commands db3]!=""} { set bExternal 0 } do_test 1.$tn.0 { sql1 { PRAGMA journal_mode = wal; CREATE TABLE t1(a, b); INSERT INTO t1 VALUES(1, 2); } } {wal} do_test 1.$tn.1 { sql2 { SELECT * FROM t1 } } {1 2} do_test 1.$tn.2 { code1 { file_control_external_reader db } } {0} do_test 1.$tn.3 { sql2 { BEGIN; SELECT * FROM t1; } } {1 2} do_test 1.$tn.4 { code1 { file_control_external_reader db } } $bExternal do_test 1.$tn.5 { sql2 { COMMIT } } {} do_test 1.$tn.6 { code1 { file_control_external_reader db } } 0 } finish_test |
Changes to test/fallocate.test.
︙ | ︙ | |||
66 67 68 69 70 71 72 73 74 75 76 77 78 79 | hexio_get_int [hexio_read test.db-journal 16 4] } else { set {} 1024 } } {1024} do_test fallocate-1.8 { execsql { COMMIT } } {} #------------------------------------------------------------------------- # The following tests - fallocate-2.* - test that things work in WAL # mode as well. # set skipwaltests [expr { [permutation]=="journaltest" || [permutation]=="inmemory_journal" | > > > > > > > > > | 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 | hexio_get_int [hexio_read test.db-journal 16 4] } else { set {} 1024 } } {1024} do_test fallocate-1.8 { execsql { COMMIT } } {} do_test fallocate-1.8 { set nPg [db one {PRAGMA page_count}] set nFile [expr [file size test.db] / 1024] list [expr $nPg<100] [expr $nFile>100] } {1 1} do_execsql_test fallocate-1.9 { PRAGMA max_page_count = 100; } {100} #------------------------------------------------------------------------- # The following tests - fallocate-2.* - test that things work in WAL # mode as well. # set skipwaltests [expr { [permutation]=="journaltest" || [permutation]=="inmemory_journal" |
︙ | ︙ |
Added test/filter1.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 | # 2018 May 8 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix filter1 ifcapable !windowfunc { finish_test return } do_execsql_test 1.0 { CREATE TABLE t1(a); CREATE INDEX i1 ON t1(a); INSERT INTO t1 VALUES(1), (2), (3), (4), (5), (6), (7), (8), (9); } do_execsql_test 1.1 { SELECT sum(a) FROM t1; } 45 do_execsql_test 1.2 { SELECT sum(a) FILTER( WHERE a<5 ) FROM t1; } 10 do_execsql_test 1.3 { SELECT sum(a) FILTER( WHERE a>9 ), sum(a) FILTER( WHERE a>8 ), sum(a) FILTER( WHERE a>7 ), sum(a) FILTER( WHERE a>6 ), sum(a) FILTER( WHERE a>5 ), sum(a) FILTER( WHERE a>4 ), sum(a) FILTER( WHERE a>3 ), sum(a) FILTER( WHERE a>2 ), sum(a) FILTER( WHERE a>1 ), sum(a) FILTER( WHERE a>0 ) FROM t1; } {{} 9 17 24 30 35 39 42 44 45} do_execsql_test 1.4 { SELECT max(a) FILTER (WHERE (a % 2)==0) FROM t1 } {8} do_execsql_test 1.5 { SELECT min(a) FILTER (WHERE a>4) FROM t1 } {5} do_execsql_test 1.6 { SELECT count(*) FILTER (WHERE a!=5) FROM t1 } {8} do_execsql_test 1.7 { SELECT min(a) FILTER (WHERE a>3) FROM t1 GROUP BY (a%2) ORDER BY 1; } {4 5} do_execsql_test 1.8 { CREATE VIEW vv AS SELECT sum(a) FILTER( WHERE a>9 ), sum(a) FILTER( WHERE a>8 ), sum(a) FILTER( WHERE a>7 ), sum(a) FILTER( WHERE a>6 ), sum(a) FILTER( WHERE a>5 ), sum(a) FILTER( WHERE a>4 ), sum(a) FILTER( WHERE a>3 ), sum(a) FILTER( WHERE a>2 ), sum(a) FILTER( WHERE a>1 ), sum(a) FILTER( WHERE a>0 ) FROM t1; SELECT * FROM vv; } {{} 9 17 24 30 35 39 42 44 45} #------------------------------------------------------------------------- # Test some errors: # # .1 FILTER on a non-aggregate function, # .2 Window function in FILTER clause, # .3 Aggregate function in FILTER clause, # reset_db do_execsql_test 2.0 { CREATE TABLE t1(a); INSERT INTO t1 VALUES(1), (2), (3), (4), (5), (6), (7), (8), (9); } do_catchsql_test 2.1 { SELECT upper(a) FILTER (WHERE a=1) FROM t1 } {1 {FILTER may not be used with non-aggregate upper()}} do_catchsql_test 2.2 { SELECT sum(a) FILTER (WHERE 1 - max(a) OVER () > 0) FROM t1 } {1 {misuse of window function max()}} do_catchsql_test 2.3 { SELECT sum(a) FILTER (WHERE 1 - count(a)) FROM t1 } {1 {misuse of aggregate function count()}} #------------------------------------------------------------------------- reset_db do_execsql_test 3.0 { CREATE TABLE t1(a,b); INSERT INTO t1 VALUES(1, 1); } do_execsql_test 3.1 { SELECT b, max(a) FILTER (WHERE b='x') FROM t1; } {1 {}} do_execsql_test 3.2 { CREATE TABLE t2(a, b, c); INSERT INTO t2 VALUES(1, 2, 3); INSERT INTO t2 VALUES(1, 3, 4); INSERT INTO t2 VALUES(2, 5, 6); INSERT INTO t2 VALUES(2, 7, 8); } do_execsql_test 3.3 { SELECT a, c, max(b) FILTER (WHERE c='x') FROM t2 GROUP BY a; } {1 3 {} 2 6 {}} do_execsql_test 3.4 { DELETE FROM t2; INSERT INTO t2 VALUES(1, 5, 'x'); INSERT INTO t2 VALUES(1, 2, 3); INSERT INTO t2 VALUES(1, 4, 'x'); INSERT INTO t2 VALUES(2, 5, 6); INSERT INTO t2 VALUES(2, 7, 8); } do_execsql_test 3.5 { SELECT a, c, max(b) FILTER (WHERE c='x') FROM t2 GROUP BY a; } {1 x 5 2 6 {}} #------------------------------------------------------------------------- reset_db do_execsql_test 4.0 { CREATE TABLE t1(a, b, c); INSERT INTO t1 VALUES('a', 0, 5); INSERT INTO t1 VALUES('a', 1, 10); INSERT INTO t1 VALUES('a', 0, 15); INSERT INTO t1 VALUES('b', 0, 5); INSERT INTO t1 VALUES('b', 1, 1000); INSERT INTO t1 VALUES('b', 0, 5); INSERT INTO t1 VALUES('c', 0, 1); INSERT INTO t1 VALUES('c', 1, 2); INSERT INTO t1 VALUES('c', 0, 3); } do_execsql_test 4.1 { SELECT avg(c) FILTER (WHERE b!=1) AS h FROM t1 GROUP BY a ORDER BY h; } {2.0 5.0 10.0} do_execsql_test 4.2 { SELECT avg(c) FILTER (WHERE b!=1) AS h FROM t1 GROUP BY a ORDER BY (h+1.0); } {2.0 5.0 10.0} do_execsql_test 4.3 { SELECT a, avg(c) FILTER (WHERE b!=1) AS h FROM t1 GROUP BY a ORDER BY avg(c); } {c 2.0 a 10.0 b 5.0} do_execsql_test 4.4 { SELECT a, avg(c) FILTER (WHERE b!=1) FROM t1 GROUP BY a ORDER BY 2 } {c 2.0 b 5.0 a 10.0} #------------------------------------------------------------------------- reset_db do_execsql_test 5.0 { CREATE TABLE t1(a, b); INSERT INTO t1 VALUES(1, 2); INSERT INTO t1 VALUES(1, 3); } do_execsql_test 5.1 { SELECT count(*) FILTER (WHERE b>2) FROM (SELECT * FROM t1) } {1} do_execsql_test 5.2 { SELECT count(*) FILTER (WHERE b>2) OVER () FROM (SELECT * FROM t1) } {1 1} do_execsql_test 5.3 { SELECT count(*) FILTER (WHERE b>2) OVER (ORDER BY b) FROM (SELECT * FROM t1) } {0 1} #------------------------------------------------------------------------- reset_db do_execsql_test 6.0 { CREATE TABLE t1(a,b); INSERT INTO t1 VALUES(1,1); INSERT INTO t1 VALUES(2,2); CREATE TABLE t2(x,y); INSERT INTO t2 VALUES(1,1); } do_execsql_test 6.1 { SELECT (SELECT COUNT(a) FILTER(WHERE x) FROM t2) FROM t1; } {1 1} do_execsql_test 6.2 { SELECT (SELECT COUNT(a+x) FROM t2) FROM t1; } {1 1} do_execsql_test 6.3 { SELECT (SELECT COUNT(a) FROM t2) FROM t1; } {2} #------------------------------------------------------------------------- reset_db do_execsql_test 7.0 { CREATE TABLE t1(a INTEGER PRIMARY KEY, b); INSERT INTO t1 VALUES(321, 100000); INSERT INTO t1 VALUES(111, 110000); INSERT INTO t1 VALUES(444, 120000); INSERT INTO t1 VALUES(222, 130000); } do_execsql_test 7.1 { SELECT max(a), max(a) FILTER (WHERE b<12345), b FROM t1; } { 444 {} 120000 } finish_test |
Added test/filter2.tcl.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 | # 2018 May 19 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # source [file join [file dirname $argv0] pg_common.tcl] #========================================================================= start_test filter2 "2019 July 2" ifcapable !windowfunc execsql_test 1.0 { DROP TABLE IF EXISTS t1; CREATE TABLE t1(a INTEGER PRIMARY KEY, b INTEGER); INSERT INTO t1 VALUES (1, 7), (2, 3), (3, 5), (4, 30), (5, 26), (6, 23), (7, 27), (8, 3), (9, 17), (10, 26), (11, 33), (12, 25), (13, NULL), (14, 47), (15, 36), (16, 13), (17, 45), (18, 31), (19, 11), (20, 36), (21, 37), (22, 21), (23, 22), (24, 14), (25, 16), (26, 3), (27, 7), (28, 29), (29, 50), (30, 38), (31, 3), (32, 36), (33, 12), (34, 4), (35, 46), (36, 3), (37, 48), (38, 23), (39, NULL), (40, 24), (41, 5), (42, 46), (43, 11), (44, NULL), (45, 18), (46, 25), (47, 15), (48, 18), (49, 23); } execsql_test 1.1 { SELECT sum(b) FROM t1 } execsql_test 1.2 { SELECT sum(b) FILTER (WHERE a<10) FROM t1 } execsql_test 1.3 { SELECT count(DISTINCT b) FROM t1 } execsql_test 1.4 { SELECT count(DISTINCT b) FILTER (WHERE a!=19) FROM t1 } execsql_test 1.5 { SELECT min(b) FILTER (WHERE a>19), min(b) FILTER (WHERE a>0), max(a+b) FILTER (WHERE a>19), max(b+a) FILTER (WHERE a BETWEEN 10 AND 40) FROM t1; } execsql_test 1.6 { SELECT min(b), min(b), max(a+b), max(b+a) FROM t1 GROUP BY (a%10) ORDER BY 1, 2, 3, 4; } execsql_test 1.7 { SELECT min(b) FILTER (WHERE a>19), min(b) FILTER (WHERE a>0), max(a+b) FILTER (WHERE a>19), max(b+a) FILTER (WHERE a BETWEEN 10 AND 40) FROM t1 GROUP BY (a%10) ORDER BY 1, 2, 3, 4; } execsql_test 1.8 { SELECT sum(a+b) FILTER (WHERE a=NULL) FROM t1 } execsql_test 1.9 { SELECT (a%5) FROM t1 GROUP BY (a%5) HAVING sum(b) FILTER (WHERE b<20) > 34 ORDER BY 1 } execsql_test 1.10 { SELECT (a%5), sum(b) FILTER (WHERE b<20) AS bbb FROM t1 GROUP BY (a%5) HAVING sum(b) FILTER (WHERE b<20) >34 ORDER BY 1 } execsql_test 1.11 { SELECT (a%5), sum(b) FILTER (WHERE b<20) AS bbb FROM t1 GROUP BY (a%5) HAVING sum(b) FILTER (WHERE b<20) >34 ORDER BY 2 } execsql_test 1.12 { SELECT (a%5), sum(b) FILTER (WHERE b<20) AS bbb, count(distinct b) FILTER (WHERE b<20 OR a=13) AS ccc FROM t1 GROUP BY (a%5) ORDER BY 2 } execsql_test 1.13 { SELECT string_agg(CAST(b AS TEXT), '_') FILTER (WHERE b%2!=0), string_agg(CAST(b AS TEXT), '_') FILTER (WHERE b%2!=1), count(*) FILTER (WHERE b%2!=0), count(*) FILTER (WHERE b%2!=1) FROM t1; } execsql_float_test 1.14 { SELECT avg(b) FILTER (WHERE b>a), avg(b) FILTER (WHERE b<a) FROM t1 GROUP BY (a%2) ORDER BY 1,2; } execsql_test 1.15 { SELECT a/5, sum(b) FILTER (WHERE a%5=0), sum(b) FILTER (WHERE a%5=1), sum(b) FILTER (WHERE a%5=2), sum(b) FILTER (WHERE a%5=3), sum(b) FILTER (WHERE a%5=4) FROM t1 GROUP BY (a/5) ORDER BY 1; } finish_test |
Added test/filter2.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 | # 2019 July 2 # # 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. # #################################################### # DO NOT EDIT! THIS FILE IS AUTOMATICALLY GENERATED! #################################################### set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix filter2 ifcapable !windowfunc { finish_test ; return } do_execsql_test 1.0 { DROP TABLE IF EXISTS t1; CREATE TABLE t1(a INTEGER PRIMARY KEY, b INTEGER); INSERT INTO t1 VALUES (1, 7), (2, 3), (3, 5), (4, 30), (5, 26), (6, 23), (7, 27), (8, 3), (9, 17), (10, 26), (11, 33), (12, 25), (13, NULL), (14, 47), (15, 36), (16, 13), (17, 45), (18, 31), (19, 11), (20, 36), (21, 37), (22, 21), (23, 22), (24, 14), (25, 16), (26, 3), (27, 7), (28, 29), (29, 50), (30, 38), (31, 3), (32, 36), (33, 12), (34, 4), (35, 46), (36, 3), (37, 48), (38, 23), (39, NULL), (40, 24), (41, 5), (42, 46), (43, 11), (44, NULL), (45, 18), (46, 25), (47, 15), (48, 18), (49, 23); } {} do_execsql_test 1.1 { SELECT sum(b) FROM t1 } {1041} do_execsql_test 1.2 { SELECT sum(b) FILTER (WHERE a<10) FROM t1 } {141} do_execsql_test 1.3 { SELECT count(DISTINCT b) FROM t1 } {31} do_execsql_test 1.4 { SELECT count(DISTINCT b) FILTER (WHERE a!=19) FROM t1 } {31} do_execsql_test 1.5 { SELECT min(b) FILTER (WHERE a>19), min(b) FILTER (WHERE a>0), max(a+b) FILTER (WHERE a>19), max(b+a) FILTER (WHERE a BETWEEN 10 AND 40) FROM t1; } {3 3 88 85} do_execsql_test 1.6 { SELECT min(b), min(b), max(a+b), max(b+a) FROM t1 GROUP BY (a%10) ORDER BY 1, 2, 3, 4; } {3 3 58 58 3 3 66 66 3 3 71 71 3 3 88 88 4 4 61 61 5 5 54 54 7 7 85 85 11 11 79 79 16 16 81 81 24 24 68 68} do_execsql_test 1.7 { SELECT min(b) FILTER (WHERE a>19), min(b) FILTER (WHERE a>0), max(a+b) FILTER (WHERE a>19), max(b+a) FILTER (WHERE a BETWEEN 10 AND 40) FROM t1 GROUP BY (a%10) ORDER BY 1, 2, 3, 4; } {3 3 58 58 3 3 71 39 4 4 38 61 7 7 85 85 11 5 54 45 16 16 81 81 18 3 66 61 21 3 88 68 23 11 79 79 24 24 68 68} do_execsql_test 1.8 { SELECT sum(a+b) FILTER (WHERE a=NULL) FROM t1 } {{}} do_execsql_test 1.9 { SELECT (a%5) FROM t1 GROUP BY (a%5) HAVING sum(b) FILTER (WHERE b<20) > 34 ORDER BY 1 } {3 4} do_execsql_test 1.10 { SELECT (a%5), sum(b) FILTER (WHERE b<20) AS bbb FROM t1 GROUP BY (a%5) HAVING sum(b) FILTER (WHERE b<20) >34 ORDER BY 1 } {3 49 4 46} do_execsql_test 1.11 { SELECT (a%5), sum(b) FILTER (WHERE b<20) AS bbb FROM t1 GROUP BY (a%5) HAVING sum(b) FILTER (WHERE b<20) >34 ORDER BY 2 } {4 46 3 49} do_execsql_test 1.12 { SELECT (a%5), sum(b) FILTER (WHERE b<20) AS bbb, count(distinct b) FILTER (WHERE b<20 OR a=13) AS ccc FROM t1 GROUP BY (a%5) ORDER BY 2 } {2 25 3 0 34 2 1 34 4 4 46 4 3 49 5} do_execsql_test 1.13 { SELECT group_concat(CAST(b AS TEXT), '_') FILTER (WHERE b%2!=0), group_concat(CAST(b AS TEXT), '_') FILTER (WHERE b%2!=1), count(*) FILTER (WHERE b%2!=0), count(*) FILTER (WHERE b%2!=1) FROM t1; } {7_3_5_23_27_3_17_33_25_47_13_45_31_11_37_21_3_7_29_3_3_23_5_11_25_15_23 30_26_26_36_36_22_14_16_50_38_36_12_4_46_48_24_46_18_18 27 19} do_test 1.14 { set myres {} foreach r [db eval {SELECT avg(b) FILTER (WHERE b>a), avg(b) FILTER (WHERE b<a) FROM t1 GROUP BY (a%2) ORDER BY 1,2;}] { lappend myres [format %.4f [set r]] } set res2 {30.8333 13.7273 31.4167 13.0000} set i 0 foreach r [set myres] r2 [set res2] { if {[set r]<([set r2]-0.0001) || [set r]>([set r2]+0.0001)} { error "list element [set i] does not match: got=[set r] expected=[set r2]" } incr i } set {} {} } {} do_execsql_test 1.15 { SELECT a/5, sum(b) FILTER (WHERE a%5=0), sum(b) FILTER (WHERE a%5=1), sum(b) FILTER (WHERE a%5=2), sum(b) FILTER (WHERE a%5=3), sum(b) FILTER (WHERE a%5=4) FROM t1 GROUP BY (a/5) ORDER BY 1; } {0 {} 7 3 5 30 1 26 23 27 3 17 2 26 33 25 {} 47 3 36 13 45 31 11 4 36 37 21 22 14 5 16 3 7 29 50 6 38 3 36 12 4 7 46 3 48 23 {} 8 24 5 46 11 {} 9 18 25 15 18 23} finish_test |
Added test/filterfault.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 | # 2018 May 8 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix filterfault ifcapable !windowfunc { finish_test return } do_execsql_test 1.0 { CREATE TABLE t1(a, b, c, d); INSERT INTO t1 VALUES(1, 2, 3, 4); INSERT INTO t1 VALUES(5, 6, 7, 8); INSERT INTO t1 VALUES(9, 10, 11, 12); } faultsim_save_and_close do_faultsim_test 1 -faults oom-t* -prep { faultsim_restore_and_reopen } -body { execsql { SELECT sum(a) FILTER (WHERE b<5), count() FILTER (WHERE d!=c) FROM t1 GROUP BY c ORDER BY 1; } } -test { faultsim_test_result {0 {{} 1 {} 1 1 1}} } finish_test |
Changes to test/fkey1.test.
︙ | ︙ | |||
217 218 219 220 221 222 223 224 225 226 | INSERT INTO c1 VALUES(1); } {1 {foreign key mismatch - "c1" referencing "p1"}} do_execsql_test 6.2 { CREATE UNIQUE INDEX p1x2 ON p1(x); INSERT INTO c1 VALUES(1); } {} finish_test | > > > > > > > > > > > > > > > > > > > | 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 | INSERT INTO c1 VALUES(1); } {1 {foreign key mismatch - "c1" referencing "p1"}} do_execsql_test 6.2 { CREATE UNIQUE INDEX p1x2 ON p1(x); INSERT INTO c1 VALUES(1); } {} # 2021-07-03 https://sqlite.org/forum/forumpost/a6b0c05277 # 2021-07-07 https://sqlite.org/forum/forumpost/79c9e4797d # Failure to allocate enough registers in the VDBE for a # PRAGMA foreign_key_check when the foreign key has more # columns than the table. # reset_db do_execsql_test 7.1 { PRAGMA foreign_keys=OFF; CREATE TABLE t1(a,b,c,FOREIGN KEY(a,a,a,a,a,a,a,a,a,a,a,a,a,a) REFERENCES t0); INSERT INTO t1 VALUES(1,2,3); PRAGMA foreign_key_check; } {t1 1 t0 0} do_execsql_test 7.2 { DROP TABLE t1; CREATE TABLE t1(a,b,c AS(1),d, FOREIGN KEY(c,d,b,a,b,d,b,c) REFERENCES t0); PRAGMA foreign_key_check; } {} finish_test |
Changes to test/fkey2.test.
︙ | ︙ | |||
413 414 415 416 417 418 419 | INSERT INTO ab VALUES(1, 'b'); INSERT INTO cd VALUES(1, 'd'); INSERT INTO ef VALUES(1, 'e'); } } {} do_test fkey2-3.1.3 { catchsql { UPDATE ab SET a = 5 } | | | | 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 | INSERT INTO ab VALUES(1, 'b'); INSERT INTO cd VALUES(1, 'd'); INSERT INTO ef VALUES(1, 'e'); } } {} do_test fkey2-3.1.3 { catchsql { UPDATE ab SET a = 5 } } {1 {CHECK constraint failed: e!=5}} do_test fkey2-3.1.4 { execsql { SELECT * FROM ab } } {1 b} do_test fkey2-3.1.4 { execsql BEGIN; catchsql { UPDATE ab SET a = 5 } } {1 {CHECK constraint failed: e!=5}} do_test fkey2-3.1.5 { execsql COMMIT; execsql { SELECT * FROM ab; SELECT * FROM cd; SELECT * FROM ef } } {1 b 1 d 1 e} do_test fkey2-3.2.1 { execsql BEGIN; |
︙ | ︙ | |||
951 952 953 954 955 956 957 958 959 960 961 962 963 964 | drop_all_tables ifcapable altertable { do_test fkey2-14.1.1 { # Adding a column with a REFERENCES clause is not supported. execsql { CREATE TABLE t1(a PRIMARY KEY); CREATE TABLE t2(a, b); } catchsql { ALTER TABLE t2 ADD COLUMN c REFERENCES t1 } } {0 {}} do_test fkey2-14.1.2 { catchsql { ALTER TABLE t2 ADD COLUMN d DEFAULT NULL REFERENCES t1 } } {0 {}} do_test fkey2-14.1.3 { | > | 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 | drop_all_tables ifcapable altertable { do_test fkey2-14.1.1 { # Adding a column with a REFERENCES clause is not supported. execsql { CREATE TABLE t1(a PRIMARY KEY); CREATE TABLE t2(a, b); INSERT INTO t2 VALUES(1,2); } catchsql { ALTER TABLE t2 ADD COLUMN c REFERENCES t1 } } {0 {}} do_test fkey2-14.1.2 { catchsql { ALTER TABLE t2 ADD COLUMN d DEFAULT NULL REFERENCES t1 } } {0 {}} do_test fkey2-14.1.3 { |
︙ | ︙ | |||
983 984 985 986 987 988 989 | # Test the sqlite_rename_parent() function directly. # proc test_rename_parent {zCreate zOld zNew} { db eval {SELECT sqlite_rename_table( 'main', 'table', 't1', $zCreate, $zOld, $zNew, 0 )} } | | | | 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 | # Test the sqlite_rename_parent() function directly. # proc test_rename_parent {zCreate zOld zNew} { db eval {SELECT sqlite_rename_table( 'main', 'table', 't1', $zCreate, $zOld, $zNew, 0 )} } sqlite3_test_control SQLITE_TESTCTRL_INTERNAL_FUNCTIONS db do_test fkey2-14.2.1.1 { test_rename_parent {CREATE TABLE t1(a REFERENCES t2)} t2 t3 } {{CREATE TABLE t1(a REFERENCES "t3")}} do_test fkey2-14.2.1.2 { test_rename_parent {CREATE TABLE t1(a REFERENCES t2)} t4 t3 } {{CREATE TABLE t1(a REFERENCES t2)}} do_test fkey2-14.2.1.3 { test_rename_parent {CREATE TABLE t1(a REFERENCES "t2")} t2 t3 } {{CREATE TABLE t1(a REFERENCES "t3")}} sqlite3_test_control SQLITE_TESTCTRL_INTERNAL_FUNCTIONS db # Test ALTER TABLE RENAME TABLE a bit. # do_test fkey2-14.2.2.1 { drop_all_tables execsql { CREATE TABLE t1(a PRIMARY KEY, b REFERENCES t1); |
︙ | ︙ | |||
1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 | # drop_all_tables do_test fkey2-14.1tmp.1 { # Adding a column with a REFERENCES clause is not supported. execsql { CREATE TEMP TABLE t1(a PRIMARY KEY); CREATE TEMP TABLE t2(a, b); } catchsql { ALTER TABLE t2 ADD COLUMN c REFERENCES t1 } } {0 {}} do_test fkey2-14.1tmp.2 { catchsql { ALTER TABLE t2 ADD COLUMN d DEFAULT NULL REFERENCES t1 } } {0 {}} do_test fkey2-14.1tmp.3 { | > | 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 | # drop_all_tables do_test fkey2-14.1tmp.1 { # Adding a column with a REFERENCES clause is not supported. execsql { CREATE TEMP TABLE t1(a PRIMARY KEY); CREATE TEMP TABLE t2(a, b); INSERT INTO temp.t2 VALUES(1,2); } catchsql { ALTER TABLE t2 ADD COLUMN c REFERENCES t1 } } {0 {}} do_test fkey2-14.1tmp.2 { catchsql { ALTER TABLE t2 ADD COLUMN d DEFAULT NULL REFERENCES t1 } } {0 {}} do_test fkey2-14.1tmp.3 { |
︙ | ︙ | |||
1066 1067 1068 1069 1070 1071 1072 | PRAGMA foreign_keys = off; ALTER TABLE t2 ADD COLUMN h DEFAULT 'text' REFERENCES t1; PRAGMA foreign_keys = on; SELECT sql FROM temp.sqlite_master WHERE name='t2'; } } {{CREATE TABLE t2(a, b, c REFERENCES t1, d DEFAULT NULL REFERENCES t1, e REFERENCES t1 DEFAULT NULL, h DEFAULT 'text' REFERENCES t1)}} | | | | 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 | PRAGMA foreign_keys = off; ALTER TABLE t2 ADD COLUMN h DEFAULT 'text' REFERENCES t1; PRAGMA foreign_keys = on; SELECT sql FROM temp.sqlite_master WHERE name='t2'; } } {{CREATE TABLE t2(a, b, c REFERENCES t1, d DEFAULT NULL REFERENCES t1, e REFERENCES t1 DEFAULT NULL, h DEFAULT 'text' REFERENCES t1)}} sqlite3_test_control SQLITE_TESTCTRL_INTERNAL_FUNCTIONS db do_test fkey2-14.2tmp.1.1 { test_rename_parent {CREATE TABLE t1(a REFERENCES t2)} t2 t3 } {{CREATE TABLE t1(a REFERENCES "t3")}} do_test fkey2-14.2tmp.1.2 { test_rename_parent {CREATE TABLE t1(a REFERENCES t2)} t4 t3 } {{CREATE TABLE t1(a REFERENCES t2)}} do_test fkey2-14.2tmp.1.3 { test_rename_parent {CREATE TABLE t1(a REFERENCES "t2")} t2 t3 } {{CREATE TABLE t1(a REFERENCES "t3")}} sqlite3_test_control SQLITE_TESTCTRL_INTERNAL_FUNCTIONS db # Test ALTER TABLE RENAME TABLE a bit. # do_test fkey2-14.2tmp.2.1 { drop_all_tables execsql { CREATE TEMP TABLE t1(a PRIMARY KEY, b REFERENCES t1); |
︙ | ︙ | |||
1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 | drop_all_tables do_test fkey2-14.1aux.1 { # Adding a column with a REFERENCES clause is not supported. execsql { ATTACH ':memory:' AS aux; CREATE TABLE aux.t1(a PRIMARY KEY); CREATE TABLE aux.t2(a, b); } catchsql { ALTER TABLE t2 ADD COLUMN c REFERENCES t1 } } {0 {}} do_test fkey2-14.1aux.2 { catchsql { ALTER TABLE t2 ADD COLUMN d DEFAULT NULL REFERENCES t1 } } {0 {}} do_test fkey2-14.1aux.3 { | > | 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 | drop_all_tables do_test fkey2-14.1aux.1 { # Adding a column with a REFERENCES clause is not supported. execsql { ATTACH ':memory:' AS aux; CREATE TABLE aux.t1(a PRIMARY KEY); CREATE TABLE aux.t2(a, b); INSERT INTO aux.t2(a,b) VALUES(1,2); } catchsql { ALTER TABLE t2 ADD COLUMN c REFERENCES t1 } } {0 {}} do_test fkey2-14.1aux.2 { catchsql { ALTER TABLE t2 ADD COLUMN d DEFAULT NULL REFERENCES t1 } } {0 {}} do_test fkey2-14.1aux.3 { |
︙ | ︙ | |||
1150 1151 1152 1153 1154 1155 1156 | PRAGMA foreign_keys = off; ALTER TABLE t2 ADD COLUMN h DEFAULT 'text' REFERENCES t1; PRAGMA foreign_keys = on; SELECT sql FROM aux.sqlite_master WHERE name='t2'; } } {{CREATE TABLE t2(a, b, c REFERENCES t1, d DEFAULT NULL REFERENCES t1, e REFERENCES t1 DEFAULT NULL, h DEFAULT 'text' REFERENCES t1)}} | | | | 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 | PRAGMA foreign_keys = off; ALTER TABLE t2 ADD COLUMN h DEFAULT 'text' REFERENCES t1; PRAGMA foreign_keys = on; SELECT sql FROM aux.sqlite_master WHERE name='t2'; } } {{CREATE TABLE t2(a, b, c REFERENCES t1, d DEFAULT NULL REFERENCES t1, e REFERENCES t1 DEFAULT NULL, h DEFAULT 'text' REFERENCES t1)}} sqlite3_test_control SQLITE_TESTCTRL_INTERNAL_FUNCTIONS db do_test fkey2-14.2aux.1.1 { test_rename_parent {CREATE TABLE t1(a REFERENCES t2)} t2 t3 } {{CREATE TABLE t1(a REFERENCES "t3")}} do_test fkey2-14.2aux.1.2 { test_rename_parent {CREATE TABLE t1(a REFERENCES t2)} t4 t3 } {{CREATE TABLE t1(a REFERENCES t2)}} do_test fkey2-14.2aux.1.3 { test_rename_parent {CREATE TABLE t1(a REFERENCES "t2")} t2 t3 } {{CREATE TABLE t1(a REFERENCES "t3")}} sqlite3_test_control SQLITE_TESTCTRL_INTERNAL_FUNCTIONS db # Test ALTER TABLE RENAME TABLE a bit. # do_test fkey2-14.2aux.2.1 { drop_all_tables execsql { CREATE TABLE aux.t1(a PRIMARY KEY, b REFERENCES t1); |
︙ | ︙ |
Changes to test/fkey5.test.
︙ | ︙ | |||
11 12 13 14 15 16 17 | # This file implements regression tests for SQLite library. # # This file tests the PRAGMA foreign_key_check command. # # EVIDENCE-OF: R-15402-03103 PRAGMA schema.foreign_key_check; PRAGMA # schema.foreign_key_check(table-name); # | | | | | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | # This file implements regression tests for SQLite library. # # This file tests the PRAGMA foreign_key_check command. # # EVIDENCE-OF: R-15402-03103 PRAGMA schema.foreign_key_check; PRAGMA # schema.foreign_key_check(table-name); # # EVIDENCE-OF: R-41653-15278 The foreign_key_check pragma checks the # database, or the table called "table-name", for foreign key # constraints that are violated. The foreign_key_check pragma returns # one row output for each foreign key violation. set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix fkey5 ifcapable {!foreignkey} { finish_test |
︙ | ︙ | |||
425 426 427 428 429 430 431 432 433 | do_execsql_test 11.0 { CREATE TABLE tt(y); CREATE TABLE c11(x REFERENCES tt(y)); } do_catchsql_test 11.1 { PRAGMA foreign_key_check; } {1 {foreign key mismatch - "c11" referencing "tt"}} finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | do_execsql_test 11.0 { CREATE TABLE tt(y); CREATE TABLE c11(x REFERENCES tt(y)); } do_catchsql_test 11.1 { PRAGMA foreign_key_check; } {1 {foreign key mismatch - "c11" referencing "tt"}} # 2020-07-03 Bug in foreign_key_check discovered while working on the # forum reports that pragma_foreign_key_check does not accept an argument: # If two separate schemas seem to reference one another, that causes # problems for foreign_key_check. # reset_db do_execsql_test 12.0 { ATTACH ':memory:' as aux; CREATE TABLE aux.t1(a INTEGER PRIMARY KEY, b TEXT REFERENCES t2); CREATE TABLE main.t2(x TEXT PRIMARY KEY, y INT); INSERT INTO main.t2 VALUES('abc',11),('def',22),('xyz',99); INSERT INTO aux.t1 VALUES(5,'abc'),(7,'xyz'),(9,'oops'); PRAGMA foreign_key_check=t1; } {t1 5 t2 0 t1 7 t2 0 t1 9 t2 0} do_execsql_test 12.1 { CREATE TABLE aux.t2(x TEXT PRIMARY KEY, y INT); INSERT INTO aux.t2 VALUES('abc',11),('def',22),('xyz',99); PRAGMA foreign_key_check=t1; } {t1 9 t2 0} # 2020-07-03: the pragma_foreign_key_check virtual table should # accept arguments for the table name and/or schema name. # ifcapable vtab { do_execsql_test 13.0 { SELECT *, 'x' FROM pragma_foreign_key_check('t1'); } {t1 9 t2 0 x} do_catchsql_test 13.1 { SELECT *, 'x' FROM pragma_foreign_key_check('t1','main'); } {1 {no such table: main.t1}} do_execsql_test 13.2 { SELECT *, 'x' FROM pragma_foreign_key_check('t1','aux'); } {t1 9 t2 0 x} } ifcapable vtab { reset_db do_execsql_test 13.10 { PRAGMA foreign_keys=OFF; CREATE TABLE t1(a INTEGER PRIMARY KEY, b TEXT REFERENCES t2); CREATE TABLE t2(x TEXT PRIMARY KEY, y INT); CREATE TABLE t3(w TEXT, z INT REFERENCES t1); INSERT INTO t2 VALUES('abc',11),('def',22),('xyz',99); INSERT INTO t1 VALUES(5,'abc'),(7,'xyz'),(9,'oops'); INSERT INTO t3 VALUES(11,7),(22,19); } {} do_execsql_test 13.11 { SELECT x.*, '|' FROM sqlite_schema, pragma_foreign_key_check(name) AS x WHERE type='table' ORDER BY x."table"; } {t1 9 t2 0 | t3 2 t1 0 |} do_execsql_test 13.12 { SELECT *, '|' FROM pragma_foreign_key_check AS x ORDER BY x."table"; } {t1 9 t2 0 | t3 2 t1 0 |} } finish_test |
Changes to test/fkey7.test.
︙ | ︙ | |||
78 79 80 81 82 83 84 85 | INSERT INTO c4 VALUES(1), (2), (3); ANALYZE; INSERT INTO p4(id) VALUES(4); } } finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | INSERT INTO c4 VALUES(1), (2), (3); ANALYZE; INSERT INTO p4(id) VALUES(4); } } do_execsql_test 4.0 { PRAGMA foreign_keys = true; CREATE TABLE parent( p PRIMARY KEY ); CREATE TABLE child( c UNIQUE REFERENCES parent(p) ); } do_catchsql_test 4.1 { INSERT OR FAIL INTO child VALUES(123), (123); } {1 {FOREIGN KEY constraint failed}} do_execsql_test 4.2 { SELECT * FROM child; } {} do_execsql_test 4.3 { PRAGMA foreign_key_check; } {} do_catchsql_test 4.4 { INSERT INTO parent VALUES(123); INSERT OR FAIL INTO child VALUES(123), (123); } {1 {UNIQUE constraint failed: child.c}} do_execsql_test 4.5 { SELECT * FROM child; } {123} do_execsql_test 4.6 { PRAGMA foreign_key_check; } {} finish_test |
Changes to test/fkey8.test.
︙ | ︙ | |||
160 161 162 163 164 165 166 167 | END; } do_catchsql_test 2.3.1 { DELETE FROM p3 WHERE a=1 } {1 {FOREIGN KEY constraint failed}} finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | END; } do_catchsql_test 2.3.1 { DELETE FROM p3 WHERE a=1 } {1 {FOREIGN KEY constraint failed}} do_execsql_test 3.0 { PRAGMA foreign_keys=ON; CREATE TABLE t2( a PRIMARY KEY, b, c, d, e, FOREIGN KEY(b, c) REFERENCES t2(d, e) ) WITHOUT ROWID; CREATE UNIQUE INDEX idx ON t2(d, e); INSERT INTO t2 VALUES(1, 'one', 'one', 'one', 'one'); -- row is parent of self INSERT INTO t2 VALUES(2, 'one', 'one', 'one', NULL); -- parent is row 1 } do_catchsql_test 3.1 { DELETE FROM t2 WHERE a=1; } {1 {FOREIGN KEY constraint failed}} do_execsql_test 4.0 { CREATE TABLE t1 ( c1 PRIMARY KEY, c2 NUMERIC, FOREIGN KEY(c1) REFERENCES t1(c2) ) WITHOUT ROWID ; CREATE INDEX t1c1 ON t1(c1); CREATE UNIQUE INDEX t1c1unique ON t1(c2); } do_catchsql_test 4.1 { INSERT OR REPLACE INTO t1 VALUES(10000, 20000); } {1 {FOREIGN KEY constraint failed}} do_execsql_test 4.2 { INSERT OR REPLACE INTO t1 VALUES(20000, 20000); } #------------------------------------------------------------------------- reset_db do_execsql_test 5.0 { PRAGMA foreign_keys = true; CREATE TABLE parent( p TEXT PRIMARY KEY ); CREATE TABLE child( c INTEGER UNIQUE, FOREIGN KEY(c) REFERENCES parent(p) DEFERRABLE INITIALLY DEFERRED ); BEGIN; INSERT INTO child VALUES(123); INSERT INTO parent VALUES('123'); COMMIT; } do_execsql_test 5.1 { PRAGMA integrity_check; } {ok} do_execsql_test 5.2 { INSERT INTO parent VALUES(1200); BEGIN; INSERT INTO child VALUES(456); UPDATE parent SET p = '456' WHERE p=1200; COMMIT; } do_execsql_test 5.3 { PRAGMA integrity_check; } {ok} finish_test |
Changes to test/fordelete.test.
︙ | ︙ | |||
44 45 46 47 48 49 50 | if {$R(opcode)=="OpenWrite"} { set root $R(p2) set csr $R(p1) if {[info exists T($root)]} { set M($csr) $T($root) } set obj $T($root) set O($obj) "" | | | 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | if {$R(opcode)=="OpenWrite"} { set root $R(p2) set csr $R(p1) if {[info exists T($root)]} { set M($csr) $T($root) } set obj $T($root) set O($obj) "" if {$R(p5) & 0x08} { set O($obj) * } else { set O($obj) "" } } } |
︙ | ︙ |
Changes to test/format4.test.
︙ | ︙ | |||
13 14 15 16 17 18 19 | # This file implements tests to verify that the new serial_type # values of 8 (integer 0) and 9 (integer 1) work correctly. # set testdir [file dirname $argv0] source $testdir/tester.tcl | | > | 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | # This file implements tests to verify that the new serial_type # values of 8 (integer 0) and 9 (integer 1) work correctly. # set testdir [file dirname $argv0] source $testdir/tester.tcl #db eval {PRAGMA legacy_file_format=OFF} sqlite3_db_config db LEGACY_FILE_FORMAT 0 # The size of the database depends on whether or not autovacuum # is enabled. # ifcapable autovacuum { if {[db one {PRAGMA auto_vacuum}]} { set small 3072 |
︙ | ︙ |
Changes to test/fts3_common.tcl.
︙ | ︙ | |||
39 40 41 42 43 44 45 46 47 48 49 50 51 52 | # Todo. # # fts3_doclist TBL TERM WHERE # Todo. # # # #------------------------------------------------------------------------- # USAGE: fts3_build_db_1 SWITCHES N # # Build a sample FTS table in the database opened by database connection # [db]. The name of the new table is "t1". # | > > > > | 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | # Todo. # # fts3_doclist TBL TERM WHERE # Todo. # # # ifcapable fts3 { sqlite3_fts3_may_be_corrupt 0 } #------------------------------------------------------------------------- # USAGE: fts3_build_db_1 SWITCHES N # # Build a sample FTS table in the database opened by database connection # [db]. The name of the new table is "t1". # |
︙ | ︙ |
Changes to test/fts3aa.test.
︙ | ︙ | |||
246 247 248 249 250 251 252 253 254 | do_execsql_test 9.1 { CREATE VIRTUAL TABLE t9 USING fts4(a, "", '---'); } do_execsql_test 9.2 { CREATE VIRTUAL TABLE t10 USING fts3(<, b, c); } expand_all_sql db finish_test | > > > > > > > > > > > | 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 | do_execsql_test 9.1 { CREATE VIRTUAL TABLE t9 USING fts4(a, "", '---'); } do_execsql_test 9.2 { CREATE VIRTUAL TABLE t10 USING fts3(<, b, c); } do_execsql_test 10.0 { CREATE VIRTUAL TABLE z1 USING fts3; INSERT INTO z1 VALUES('one two three'),('four one five'),('six two five'); CREATE TRIGGER z1r1 AFTER DELETE ON z1_content BEGIN DELETE FROM z1; END; } do_catchsql_test 10.1 { DELETE FROM z1; } {1 {SQL logic error}} expand_all_sql db finish_test |
Changes to test/fts3atoken.test.
︙ | ︙ | |||
82 83 84 85 86 87 88 89 90 91 92 | INSERT INTO t1(content) VALUES('There was movement at the station'); INSERT INTO t1(content) VALUES('For the word has passed around'); INSERT INTO t1(content) VALUES('That the colt from ol regret had got'); SELECT content FROM t1 WHERE content MATCH 'movement' } } {{There was movement at the station}} sqlite3_db_config db SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER 0 do_catchsql_test 1.6 { SELECT fts3_tokenizer('blah', fts3_tokenizer('simple')) IS NULL; } {1 {fts3tokenize disabled}} | > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | INSERT INTO t1(content) VALUES('There was movement at the station'); INSERT INTO t1(content) VALUES('For the word has passed around'); INSERT INTO t1(content) VALUES('That the colt from ol regret had got'); SELECT content FROM t1 WHERE content MATCH 'movement' } } {{There was movement at the station}} unset -nocomplain simple blah2name simplename set simplename "simple" set blah2name "blah2" set simple [db one {SELECT fts3_tokenizer('simple')}] sqlite3_db_config db SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER 0 do_catchsql_test 1.6 { SELECT fts3_tokenizer('blah', fts3_tokenizer('simple')) IS NULL; } {1 {fts3tokenize disabled}} do_test fts3atoken-1.7 { execsql { SELECT fts3_tokenizer('blah2', $simple) IS NULL; } } {1} # With ENABLE_FTS3_TOKENIZER off, the fts3_tokenzer(1) function # returns NULL unless the first parameter is a bound parameter. # If the first parameter is a bound parameter, then fts3_tokenizer(1) # returns the actual pointer value as a BLOB. # do_test fts3atoken-1.8 { execsql { SELECT fts3_tokenizer($blah2name) == fts3_tokenizer($simplename), typeof(fts3_tokenizer($blah2name)), typeof(fts3_tokenizer('blah2')), typeof(fts3_tokenizer($simplename)), typeof(fts3_tokenizer('simple')); } } {1 blob null blob null} # With ENABLE_FTS3_TOKENIZER on, fts3_tokenizer() always returns # the BLOB pointer, regardless the parameter # sqlite3_db_config db SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER 1 do_test fts3atoken-1.9 { execsql { SELECT fts3_tokenizer('blah2') == fts3_tokenizer('simple'), typeof(fts3_tokenizer($blah2name)), typeof(fts3_tokenizer('blah2')), typeof(fts3_tokenizer($simplename)), typeof(fts3_tokenizer('simple')); } } {1 blob blob blob blob} # 2019-12-31: The fts3_tokenizer() function can never be invoked from # within a trigger or view. # do_catchsql_test fts3atoken-1.10 { CREATE VIEW v110(x) AS SELECT fts3_tokenizer('tok110', fts3_tokenizer('simple')) IS NULL; } {0 {}} do_catchsql_test fts3atoken-1.11 { SELECT * FROM v110; } {1 {unsafe use of fts3_tokenizer()}} do_catchsql_test fts3atoken-1.12 { CREATE TABLE t110(a,b); CREATE TRIGGER r110 AFTER INSERT ON t110 BEGIN SELECT fts3_tokenizer('tok110', fts3_tokenizer('simple')) IS NULL; END; } {0 {}} do_catchsql_test fts3atoken-1.13 { INSERT INTO t110(a,b) VALUES(1,2); } {1 {unsafe use of fts3_tokenizer()}} do_catchsql_test fts3atoken-1.14 { SELECT * FROM t110; } {0 {}} #-------------------------------------------------------------------------- # Test cases fts3atoken-2.* test error cases in the scalar function based # API for getting and setting tokenizers. # do_test fts3atoken-2.1 { catchsql { SELECT fts3_tokenizer('nosuchtokenizer'); } } {1 {unknown tokenizer: nosuchtokenizer}} #-------------------------------------------------------------------------- # Test cases fts3atoken-3.* test the three built-in tokenizers with a # simple input string via the built-in test function. This is as much # to test the test function as the tokenizer implementations. # sqlite3_db_config db SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER 1 do_test fts3atoken-3.1 { execsql { SELECT fts3_tokenizer_test('simple', 'I don''t see how'); } } {{0 i I 1 don don 2 t t 3 see see 4 how how}} do_test fts3atoken-3.2 { execsql { |
︙ | ︙ |
Changes to test/fts3auto.test.
︙ | ︙ | |||
566 567 568 569 570 571 572 573 574 575 576 577 578 579 | do_fts3query_test 4.$tn.3.5 -deferred five t1 {one NEAR/3 five} do_fts3query_test 4.$tn.4.1 -deferred fi* t1 {on* AND fi*} do_fts3query_test 4.$tn.4.2 -deferred fi* t1 {on* NEAR fi*} do_fts3query_test 4.$tn.4.3 -deferred fi* t1 {on* NEAR/1 fi*} do_fts3query_test 4.$tn.4.4 -deferred fi* t1 {on* NEAR/2 fi*} do_fts3query_test 4.$tn.4.5 -deferred fi* t1 {on* NEAR/3 fi*} } #-------------------------------------------------------------------------- # The following test cases - fts3auto-5.* - focus on using prefix indexes. # set chunkconfig [fts3_configure_incr_load 1 1] foreach {tn create pending} { | > > > > > > > | 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 | do_fts3query_test 4.$tn.3.5 -deferred five t1 {one NEAR/3 five} do_fts3query_test 4.$tn.4.1 -deferred fi* t1 {on* AND fi*} do_fts3query_test 4.$tn.4.2 -deferred fi* t1 {on* NEAR fi*} do_fts3query_test 4.$tn.4.3 -deferred fi* t1 {on* NEAR/1 fi*} do_fts3query_test 4.$tn.4.4 -deferred fi* t1 {on* NEAR/2 fi*} do_fts3query_test 4.$tn.4.5 -deferred fi* t1 {on* NEAR/3 fi*} ifcapable fts4_deferred { db eval {UPDATE t1_stat SET value=x'' WHERE id=0} do_catchsql_test 4.$tn.4.6 { SELECT docid FROM t1 WHERE t1 MATCH 'on* NEAR/3 fi*' } {1 {database disk image is malformed}} } } #-------------------------------------------------------------------------- # The following test cases - fts3auto-5.* - focus on using prefix indexes. # set chunkconfig [fts3_configure_incr_load 1 1] foreach {tn create pending} { |
︙ | ︙ |
Changes to test/fts3aux1.test.
︙ | ︙ | |||
101 102 103 104 105 106 107 | db func rec rec # Use EQP to show that the WHERE expression "term='braid'" uses a different # index number (1) than "+term='braid'" (0). # do_execsql_test 2.1.1.1 { EXPLAIN QUERY PLAN SELECT * FROM terms WHERE term='braid' | | | | 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 | db func rec rec # Use EQP to show that the WHERE expression "term='braid'" uses a different # index number (1) than "+term='braid'" (0). # do_execsql_test 2.1.1.1 { EXPLAIN QUERY PLAN SELECT * FROM terms WHERE term='braid' } {/*SCAN terms VIRTUAL TABLE INDEX 1:*/} do_execsql_test 2.1.1.2 { EXPLAIN QUERY PLAN SELECT * FROM terms WHERE +term='braid' } {/*SCAN terms VIRTUAL TABLE INDEX 0:*/} # Now show that using "term='braid'" means the virtual table returns # only 1 row to SQLite, but "+term='braid'" means all 19 are returned. # do_test 2.1.2.1 { set cnt 0 execsql { SELECT * FROM terms_v WHERE rec('cnt', term) AND term='braid' } |
︙ | ︙ | |||
150 151 152 153 154 155 156 | # Special case: term=NULL # do_execsql_test 2.1.5 { SELECT * FROM terms WHERE term=NULL } {} do_execsql_test 2.2.1.1 { EXPLAIN QUERY PLAN SELECT * FROM terms WHERE term>'brain' | | | | | | | | 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 | # Special case: term=NULL # do_execsql_test 2.1.5 { SELECT * FROM terms WHERE term=NULL } {} do_execsql_test 2.2.1.1 { EXPLAIN QUERY PLAN SELECT * FROM terms WHERE term>'brain' } {/*SCAN terms VIRTUAL TABLE INDEX 2:*/} do_execsql_test 2.2.1.2 { EXPLAIN QUERY PLAN SELECT * FROM terms WHERE +term>'brain' } {/*SCAN terms VIRTUAL TABLE INDEX 0:*/} do_execsql_test 2.2.1.3 { EXPLAIN QUERY PLAN SELECT * FROM terms WHERE term<'brain' } {/*SCAN terms VIRTUAL TABLE INDEX 4:*/} do_execsql_test 2.2.1.4 { EXPLAIN QUERY PLAN SELECT * FROM terms WHERE +term<'brain' } {/*SCAN terms VIRTUAL TABLE INDEX 0:*/} do_execsql_test 2.2.1.5 { EXPLAIN QUERY PLAN SELECT * FROM terms WHERE term BETWEEN 'brags' AND 'brain' } {/*SCAN terms VIRTUAL TABLE INDEX 6:*/} do_execsql_test 2.2.1.6 { EXPLAIN QUERY PLAN SELECT * FROM terms WHERE +term BETWEEN 'brags' AND 'brain' } {/*SCAN terms VIRTUAL TABLE INDEX 0:*/} do_test 2.2.2.1 { set cnt 0 execsql { SELECT * FROM terms WHERE rec('cnt', term) AND term>'brain' } set cnt } {18} do_test 2.2.2.2 { |
︙ | ︙ | |||
331 332 333 334 335 336 337 | 5 1 "ORDER BY documents" 6 1 "ORDER BY documents DESC" 7 1 "ORDER BY occurrences ASC" 8 1 "ORDER BY occurrences" 9 1 "ORDER BY occurrences DESC" } { | | | 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 | 5 1 "ORDER BY documents" 6 1 "ORDER BY documents DESC" 7 1 "ORDER BY occurrences ASC" 8 1 "ORDER BY occurrences" 9 1 "ORDER BY occurrences DESC" } { set res {SCAN terms VIRTUAL TABLE INDEX 0:} if {$sort} { append res {*USE TEMP B-TREE FOR ORDER BY} } set res "/*$res*/" set sql "SELECT * FROM terms $orderby" do_execsql_test 2.3.1.$tn "EXPLAIN QUERY PLAN $sql" $res } |
︙ | ︙ | |||
409 410 411 412 413 414 415 | do_execsql_test $tn $sql $r2 } do_plansql_test 4.2 { SELECT y FROM x2, terms WHERE y = term AND col = '*' } { QUERY PLAN | | | | | | | | | | 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 | do_execsql_test $tn $sql $r2 } do_plansql_test 4.2 { SELECT y FROM x2, terms WHERE y = term AND col = '*' } { QUERY PLAN |--SCAN x2 `--SCAN terms VIRTUAL TABLE INDEX 1: } { a b c d e f g h i j k l } do_plansql_test 4.3 { SELECT y FROM terms, x2 WHERE y = term AND col = '*' } { QUERY PLAN |--SCAN x2 `--SCAN terms VIRTUAL TABLE INDEX 1: } { a b c d e f g h i j k l } do_plansql_test 4.4 { SELECT y FROM x3, terms WHERE y = term AND col = '*' } { QUERY PLAN |--SCAN terms VIRTUAL TABLE INDEX 0: `--SEARCH x3 USING COVERING INDEX i1 (y=?) } { a b c d e f g h i j k l } do_plansql_test 4.5 { SELECT y FROM terms, x3 WHERE y = term AND occurrences>1 AND col = '*' } { QUERY PLAN |--SCAN terms VIRTUAL TABLE INDEX 0: `--SEARCH x3 USING COVERING INDEX i1 (y=?) } { a k l } #------------------------------------------------------------------------- # 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 |
︙ | ︙ |
Changes to test/fts3aux2.test.
︙ | ︙ | |||
136 137 138 139 140 141 142 143 144 | do_execsql_test 1.4.6 { SELECT term, col, documents, occurrences, languageid FROM terms WHERE term>='e' AND term<'seven' AND languageid=2 } { eight * 1 1 2 eight 1 1 1 2 five * 1 1 2 five 0 1 1 2 } finish_test | > > > > > > > > > > > > > > > > > > > > > > > > | 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 | do_execsql_test 1.4.6 { SELECT term, col, documents, occurrences, languageid FROM terms WHERE term>='e' AND term<'seven' AND languageid=2 } { eight * 1 1 2 eight 1 1 1 2 five * 1 1 2 five 0 1 1 2 } #------------------------------------------------------------------------- do_execsql_test 2.0 { CREATE VIRTUAL TABLE ft USING fts3(); INSERT INTO ft VALUES('a_234567890123456789'); INSERT INTO ft VALUES('b_234567890123456789'); INSERT INTO ft VALUES('c_234567890123456789'); CREATE VIRTUAL TABLE t2 USING fts4aux(ft); } do_execsql_test 2.1 { SELECT term FROM t2 WHERE term=X'625f323334353637383930313233343536373839'; } do_execsql_test 2.2 { SELECT term FROM t2 WHERE term<X'625f003334353637383930313233343536373839'; } { 234567890123456789 234567890123456789 a a b b } do_execsql_test 2.3 { SELECT term FROM t2 WHERE term=X'625f003334353637383930313233343536373839'; } finish_test |
Changes to test/fts3corrupt.test.
︙ | ︙ | |||
161 162 163 164 165 166 167 168 169 | do_test 5.2.1 { sqlite3_extended_errcode db } SQLITE_CORRUPT_VTAB do_catchsql_test 5.3 { UPDATE t1_stat SET value = NULL; SELECT matchinfo(t1, 'nxa') FROM t1 WHERE t1 MATCH 't*'; } {1 {database disk image is malformed}} do_test 5.3.1 { sqlite3_extended_errcode db } SQLITE_CORRUPT_VTAB finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | do_test 5.2.1 { sqlite3_extended_errcode db } SQLITE_CORRUPT_VTAB do_catchsql_test 5.3 { UPDATE t1_stat SET value = NULL; SELECT matchinfo(t1, 'nxa') FROM t1 WHERE t1 MATCH 't*'; } {1 {database disk image is malformed}} do_test 5.3.1 { sqlite3_extended_errcode db } SQLITE_CORRUPT_VTAB # 2019-11-18 https://bugs.chromium.org/p/chromium/issues/detail?id=1025467 # bug1 db close sqlite3 db :memory: do_catchsql_test 6.10 { CREATE VIRTUAL TABLE f using fts3(a,b); CREATE TABLE f_stat(id INTEGER PRIMARY KEY, value BLOB); INSERT INTO f_segdir VALUES (2000, 0,0,0, '16', ''); INSERT INTO f_segdir VALUES (1999, 0,0,0, '0 18', x'000131030102000103323334050101010200'); INSERT INTO f_segments (blockid) values (16); INSERT INTO f_segments values (0, x''); INSERT INTO f_stat VALUES (1,x'cf0f01'); INSERT INTO f(f) VALUES ("merge=1"); } {1 {database disk image is malformed}} # 2020-03-02 https://bugs.chromium.org/p/chromium/issues/detail?id=1057441 # The ticket complains of use of an uninitialized value. That part is harmless. # The only reason to fix this is the failure to detect a subtly corrupt # inverted index. # reset_db do_catchsql_test 7.10 { CREATE VIRTUAL TABLE f USING fts3(a,b); INSERT INTO f_segdir VALUES (0,0,1,0,'0 0',x'01010101020101'); SELECT matchinfo( f , 'pcx') FROM f WHERE b MATCH x'c533'; } {1 {database disk image is malformed}} finish_test |
Changes to test/fts3corrupt2.test.
︙ | ︙ | |||
12 13 14 15 16 17 18 19 20 21 22 23 24 25 | set testdir [file dirname $argv0] source $testdir/tester.tcl # If SQLITE_ENABLE_FTS3 is not defined, omit this file. ifcapable !fts3 { finish_test ; return } set ::testprefix fts3corrupt2 set data [list] lappend data {*}{ "amxtvoo adqwroyhz auq aithtir avniqnuynvf axp ahibayfynig agbicpm" "ajdtebs anteaxr aieynenwmd awpl alo akxcrwow aoxftge aoqvgul" "amcfvdr auz apu aebelm ahuxyz aqc asyafdb agulvhvqu" "apepwfyz azkhdvkw aenyelxzbk aslnitbyet aycdsdcpgr aqzzdbc agfi axnypydou" | > | 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | set testdir [file dirname $argv0] source $testdir/tester.tcl # If SQLITE_ENABLE_FTS3 is not defined, omit this file. ifcapable !fts3 { finish_test ; return } set ::testprefix fts3corrupt2 sqlite3_fts3_may_be_corrupt 1 set data [list] lappend data {*}{ "amxtvoo adqwroyhz auq aithtir avniqnuynvf axp ahibayfynig agbicpm" "ajdtebs anteaxr aieynenwmd awpl alo akxcrwow aoxftge aoqvgul" "amcfvdr auz apu aebelm ahuxyz aqc asyafdb agulvhvqu" "apepwfyz azkhdvkw aenyelxzbk aslnitbyet aycdsdcpgr aqzzdbc agfi axnypydou" |
︙ | ︙ | |||
98 99 100 101 102 103 104 | catchsql { SELECT * FROM t2 WHERE t2 MATCH 'a*' } set {} {} } {} } execsql { UPDATE t2_segdir SET root = $blob WHERE rowid = $rowid } } } | < | 99 100 101 102 103 104 105 106 107 108 109 110 111 | catchsql { SELECT * FROM t2 WHERE t2 MATCH 'a*' } set {} {} } {} } execsql { UPDATE t2_segdir SET root = $blob WHERE rowid = $rowid } } } finish_test |
Changes to test/fts3corrupt4.test.
︙ | ︙ | |||
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | # focus of this script is testing the FTS3 module. # # $Id: fts3aa.test,v 1.1 2007/08/20 17:38:42 shess Exp $ # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix fts3corrupt4 # If SQLITE_ENABLE_FTS3 is defined, omit this file. ifcapable !fts3 { finish_test return } do_execsql_test 1.0 { BEGIN; CREATE VIRTUAL TABLE ft USING fts3; INSERT INTO ft VALUES('aback'); INSERT INTO ft VALUES('abaft'); INSERT INTO ft VALUES('abandon'); | > > > > > | 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 | # focus of this script is testing the FTS3 module. # # $Id: fts3aa.test,v 1.1 2007/08/20 17:38:42 shess Exp $ # set testdir [file dirname $argv0] source $testdir/tester.tcl source $testdir/fts3_common.tcl set testprefix fts3corrupt4 # If SQLITE_ENABLE_FTS3 is defined, omit this file. ifcapable !fts3 { finish_test return } sqlite3_fts3_may_be_corrupt 1 database_may_be_corrupt extra_schema_checks 0 do_execsql_test 1.0 { BEGIN; CREATE VIRTUAL TABLE ft USING fts3; INSERT INTO ft VALUES('aback'); INSERT INTO ft VALUES('abaft'); INSERT INTO ft VALUES('abandon'); |
︙ | ︙ | |||
140 141 142 143 144 145 146 147 148 | UPDATE ft_segdir SET root = blob('0101056162633132FFFFFFFF070236030132030136'); } do_catchsql_test 3.1 { SELECT * FROM ft WHERE ft MATCH 'abc20' } {1 {database disk image is malformed}} finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 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 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 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 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 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 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 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 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 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 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 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 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 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 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 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 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 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 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 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 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 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 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 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 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 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 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 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 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 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 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 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 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 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 3940 3941 3942 3943 3944 3945 3946 3947 3948 3949 3950 3951 3952 3953 3954 3955 3956 3957 3958 3959 3960 3961 3962 3963 3964 3965 3966 3967 3968 3969 3970 3971 3972 3973 3974 3975 3976 3977 3978 3979 3980 3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994 3995 3996 3997 3998 3999 4000 4001 4002 4003 4004 4005 4006 4007 4008 4009 4010 4011 4012 4013 4014 4015 4016 4017 4018 4019 4020 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 4034 4035 4036 4037 4038 4039 4040 4041 4042 4043 4044 4045 4046 4047 4048 4049 4050 4051 4052 4053 4054 4055 4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075 4076 4077 4078 4079 4080 4081 4082 4083 4084 4085 4086 4087 4088 4089 4090 4091 4092 4093 4094 4095 4096 4097 4098 4099 4100 4101 4102 4103 4104 4105 4106 4107 4108 4109 4110 4111 4112 4113 4114 4115 4116 4117 4118 4119 4120 4121 4122 4123 4124 4125 4126 4127 4128 4129 4130 4131 4132 4133 4134 4135 4136 4137 4138 4139 4140 4141 4142 4143 4144 4145 4146 4147 4148 4149 4150 4151 4152 4153 4154 4155 4156 4157 4158 4159 4160 4161 4162 4163 4164 4165 4166 4167 4168 4169 4170 4171 4172 4173 4174 4175 4176 4177 4178 4179 4180 4181 4182 4183 4184 4185 4186 4187 4188 4189 4190 4191 4192 4193 4194 4195 4196 4197 4198 4199 4200 4201 4202 4203 4204 4205 4206 4207 4208 4209 4210 4211 4212 4213 4214 4215 4216 4217 4218 4219 4220 4221 4222 4223 4224 4225 4226 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 4258 4259 4260 4261 4262 4263 4264 4265 4266 4267 4268 4269 4270 4271 4272 4273 4274 4275 4276 4277 4278 4279 4280 4281 4282 4283 4284 4285 4286 4287 4288 4289 4290 4291 4292 4293 4294 4295 4296 4297 4298 4299 4300 4301 4302 4303 4304 4305 4306 4307 4308 4309 4310 4311 4312 4313 4314 4315 4316 4317 4318 4319 4320 4321 4322 4323 4324 4325 4326 4327 4328 4329 4330 4331 4332 4333 4334 4335 4336 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 4389 4390 4391 4392 4393 4394 4395 4396 4397 4398 4399 4400 4401 4402 4403 4404 4405 4406 4407 4408 4409 4410 4411 4412 4413 4414 4415 4416 4417 4418 4419 4420 4421 4422 4423 4424 4425 4426 4427 4428 4429 4430 4431 4432 4433 4434 4435 4436 4437 4438 4439 4440 4441 4442 4443 4444 4445 4446 4447 4448 4449 4450 4451 4452 4453 4454 4455 4456 4457 4458 4459 4460 4461 4462 4463 4464 4465 4466 4467 4468 4469 4470 4471 4472 4473 4474 4475 4476 4477 4478 4479 4480 4481 4482 4483 4484 4485 4486 4487 4488 4489 4490 4491 4492 4493 4494 4495 4496 4497 4498 4499 4500 4501 4502 4503 4504 4505 4506 4507 4508 4509 4510 4511 4512 4513 4514 4515 4516 4517 4518 4519 4520 4521 4522 4523 4524 4525 4526 4527 4528 4529 4530 4531 4532 4533 4534 4535 4536 4537 4538 4539 4540 4541 4542 4543 4544 4545 4546 4547 4548 4549 4550 4551 4552 4553 4554 4555 4556 4557 4558 4559 4560 4561 4562 4563 4564 4565 4566 4567 4568 4569 4570 4571 4572 4573 4574 4575 4576 4577 4578 4579 4580 4581 4582 4583 4584 4585 4586 4587 4588 4589 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 4834 4835 4836 4837 4838 4839 4840 4841 4842 4843 4844 4845 4846 4847 4848 4849 4850 4851 4852 4853 4854 4855 4856 4857 4858 4859 4860 4861 4862 4863 4864 4865 4866 4867 4868 4869 4870 4871 4872 4873 4874 4875 4876 4877 4878 4879 4880 4881 4882 4883 4884 4885 4886 4887 4888 4889 4890 4891 4892 4893 4894 4895 4896 4897 4898 4899 4900 4901 4902 4903 4904 4905 4906 4907 4908 4909 4910 4911 4912 4913 4914 4915 4916 4917 4918 4919 4920 4921 4922 4923 4924 4925 4926 4927 4928 4929 4930 4931 4932 4933 4934 4935 4936 4937 4938 4939 4940 4941 4942 4943 4944 4945 4946 4947 4948 4949 4950 4951 4952 4953 4954 4955 4956 4957 4958 4959 4960 4961 4962 4963 4964 4965 4966 4967 4968 4969 4970 4971 4972 4973 4974 4975 4976 4977 4978 4979 4980 4981 4982 4983 4984 4985 4986 4987 4988 4989 4990 4991 4992 4993 4994 4995 4996 4997 4998 4999 5000 5001 5002 5003 5004 5005 5006 5007 5008 5009 5010 5011 5012 5013 5014 5015 5016 5017 5018 5019 5020 5021 5022 5023 5024 5025 5026 5027 5028 5029 5030 5031 5032 5033 5034 5035 5036 5037 5038 5039 5040 5041 5042 5043 5044 5045 5046 5047 5048 5049 5050 5051 5052 5053 5054 5055 5056 5057 5058 5059 5060 5061 5062 5063 5064 5065 5066 5067 5068 5069 5070 5071 5072 5073 5074 5075 5076 5077 5078 5079 5080 5081 5082 5083 5084 5085 5086 5087 5088 5089 5090 5091 5092 5093 5094 5095 5096 5097 5098 5099 5100 5101 5102 5103 5104 5105 5106 5107 5108 5109 5110 5111 5112 5113 5114 5115 5116 5117 5118 5119 5120 5121 5122 5123 5124 5125 5126 5127 5128 5129 5130 5131 5132 5133 5134 5135 5136 5137 5138 5139 5140 5141 5142 5143 5144 5145 5146 5147 5148 5149 5150 5151 5152 5153 5154 5155 5156 5157 5158 5159 5160 5161 5162 5163 5164 5165 5166 5167 5168 5169 5170 5171 5172 5173 5174 5175 5176 5177 5178 5179 5180 5181 5182 5183 5184 5185 5186 5187 5188 5189 5190 5191 5192 5193 5194 5195 5196 5197 5198 5199 5200 5201 5202 5203 5204 5205 5206 5207 5208 5209 5210 5211 5212 5213 5214 5215 5216 5217 5218 5219 5220 5221 5222 5223 5224 5225 5226 5227 5228 5229 5230 5231 5232 5233 5234 5235 5236 5237 5238 5239 5240 5241 5242 5243 5244 5245 5246 5247 5248 5249 5250 5251 5252 5253 5254 5255 5256 5257 5258 5259 5260 5261 5262 5263 5264 5265 5266 5267 5268 5269 5270 5271 5272 5273 5274 5275 5276 5277 5278 5279 5280 5281 5282 5283 5284 5285 5286 5287 5288 5289 5290 5291 5292 5293 5294 5295 5296 5297 5298 5299 5300 5301 5302 5303 5304 5305 5306 5307 5308 5309 5310 5311 5312 5313 5314 5315 5316 5317 5318 5319 5320 5321 5322 5323 5324 5325 5326 5327 5328 5329 5330 5331 5332 5333 5334 5335 5336 5337 5338 5339 5340 5341 5342 5343 5344 5345 5346 5347 5348 5349 5350 5351 5352 5353 5354 5355 5356 5357 5358 5359 5360 5361 5362 5363 5364 5365 5366 5367 5368 5369 5370 5371 5372 5373 5374 5375 5376 5377 5378 5379 5380 5381 5382 5383 5384 5385 5386 5387 5388 5389 5390 5391 5392 5393 5394 5395 5396 5397 5398 5399 5400 5401 5402 5403 5404 5405 5406 5407 5408 5409 5410 5411 5412 5413 5414 5415 5416 5417 5418 5419 5420 5421 5422 5423 5424 5425 5426 5427 5428 5429 5430 5431 5432 5433 5434 5435 5436 5437 5438 5439 5440 5441 5442 5443 5444 5445 5446 5447 5448 5449 5450 5451 5452 5453 5454 5455 5456 5457 5458 5459 5460 5461 5462 5463 5464 5465 5466 5467 5468 5469 5470 5471 5472 5473 5474 5475 5476 5477 5478 5479 5480 5481 5482 5483 5484 5485 5486 5487 5488 5489 5490 5491 5492 5493 5494 5495 5496 5497 5498 5499 5500 5501 5502 5503 5504 5505 5506 5507 5508 5509 5510 5511 5512 5513 5514 5515 5516 5517 5518 5519 5520 5521 5522 5523 5524 5525 5526 5527 5528 5529 5530 5531 5532 5533 5534 5535 5536 5537 5538 5539 5540 5541 5542 5543 5544 5545 5546 5547 5548 5549 5550 5551 5552 5553 5554 5555 5556 5557 5558 5559 5560 5561 5562 5563 5564 5565 5566 5567 5568 5569 5570 5571 5572 5573 5574 5575 5576 5577 5578 5579 5580 5581 5582 5583 5584 5585 5586 5587 5588 5589 5590 5591 5592 5593 5594 5595 5596 5597 5598 5599 5600 5601 5602 5603 5604 5605 5606 5607 5608 5609 5610 5611 5612 5613 5614 5615 5616 5617 5618 5619 5620 5621 5622 5623 5624 5625 5626 5627 5628 5629 5630 5631 5632 5633 5634 5635 5636 5637 5638 5639 5640 5641 5642 5643 5644 5645 5646 5647 5648 5649 5650 5651 5652 5653 5654 5655 5656 5657 5658 5659 5660 5661 5662 5663 5664 5665 5666 5667 5668 5669 5670 5671 5672 5673 5674 5675 5676 5677 5678 5679 5680 5681 5682 5683 5684 5685 5686 5687 5688 5689 5690 5691 5692 5693 5694 5695 5696 5697 5698 5699 5700 5701 5702 5703 5704 5705 5706 5707 5708 5709 5710 5711 5712 5713 5714 5715 5716 5717 5718 5719 5720 5721 5722 5723 5724 5725 5726 5727 5728 5729 5730 5731 5732 5733 5734 5735 5736 5737 5738 5739 5740 5741 5742 5743 5744 5745 5746 5747 5748 5749 5750 5751 5752 5753 5754 5755 5756 5757 5758 5759 5760 5761 5762 5763 5764 5765 5766 5767 5768 5769 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 5809 5810 5811 5812 5813 5814 5815 5816 5817 5818 5819 5820 5821 5822 5823 5824 5825 5826 5827 5828 5829 5830 5831 5832 5833 5834 5835 5836 5837 5838 5839 5840 5841 5842 5843 5844 5845 5846 5847 5848 5849 5850 5851 5852 5853 5854 5855 5856 5857 5858 5859 5860 5861 5862 5863 5864 5865 5866 5867 5868 5869 5870 5871 5872 5873 5874 5875 5876 5877 5878 5879 5880 5881 5882 5883 5884 5885 5886 5887 5888 5889 5890 5891 5892 5893 5894 5895 5896 5897 5898 5899 5900 5901 5902 5903 5904 5905 5906 5907 5908 5909 5910 5911 5912 5913 5914 5915 5916 5917 5918 5919 5920 5921 5922 5923 5924 5925 5926 5927 5928 5929 5930 5931 5932 5933 5934 5935 5936 5937 5938 5939 5940 5941 5942 5943 5944 5945 5946 5947 5948 5949 5950 5951 5952 5953 5954 5955 5956 5957 5958 5959 5960 5961 5962 5963 5964 5965 5966 5967 5968 5969 5970 5971 5972 5973 5974 5975 5976 5977 5978 5979 5980 5981 5982 5983 5984 5985 5986 5987 5988 5989 5990 5991 5992 5993 5994 5995 5996 5997 5998 5999 6000 6001 6002 6003 6004 6005 6006 6007 6008 6009 6010 6011 6012 6013 6014 6015 6016 6017 6018 6019 6020 6021 6022 6023 6024 6025 6026 6027 6028 6029 6030 6031 6032 6033 6034 6035 6036 6037 6038 6039 6040 6041 6042 6043 6044 6045 6046 6047 6048 6049 6050 6051 6052 6053 6054 6055 6056 6057 6058 6059 6060 6061 6062 6063 6064 6065 6066 6067 6068 6069 6070 6071 6072 6073 6074 6075 6076 6077 6078 6079 6080 6081 6082 6083 6084 6085 6086 6087 6088 6089 6090 6091 6092 6093 6094 6095 6096 6097 6098 6099 6100 6101 6102 6103 6104 6105 6106 6107 6108 6109 6110 6111 6112 6113 6114 6115 6116 6117 6118 6119 6120 6121 6122 6123 6124 6125 6126 6127 6128 6129 6130 6131 6132 6133 6134 6135 6136 6137 6138 6139 6140 6141 6142 6143 6144 6145 6146 6147 6148 6149 6150 6151 6152 6153 6154 6155 6156 6157 6158 6159 6160 6161 6162 6163 6164 6165 6166 6167 6168 6169 6170 6171 6172 6173 6174 6175 6176 6177 6178 6179 6180 6181 6182 6183 6184 6185 6186 6187 6188 6189 6190 6191 6192 6193 6194 6195 6196 6197 6198 6199 6200 6201 6202 6203 6204 6205 6206 6207 6208 6209 6210 6211 6212 6213 6214 6215 6216 6217 6218 6219 6220 6221 6222 6223 6224 6225 6226 6227 6228 6229 6230 6231 6232 6233 6234 6235 6236 6237 6238 6239 6240 6241 6242 6243 6244 6245 6246 6247 6248 6249 6250 6251 6252 6253 6254 6255 6256 6257 6258 6259 6260 6261 6262 6263 6264 6265 6266 6267 6268 6269 6270 6271 6272 6273 6274 6275 6276 6277 6278 6279 6280 6281 6282 6283 6284 6285 6286 6287 6288 6289 6290 6291 6292 6293 6294 6295 6296 6297 6298 6299 6300 6301 6302 6303 6304 6305 6306 6307 6308 6309 6310 6311 6312 6313 6314 6315 6316 6317 6318 6319 6320 6321 6322 6323 6324 6325 6326 6327 6328 6329 6330 6331 6332 6333 6334 6335 6336 6337 6338 6339 6340 6341 6342 6343 6344 6345 6346 6347 6348 6349 6350 6351 6352 6353 6354 6355 6356 6357 6358 6359 6360 6361 6362 6363 6364 6365 6366 6367 6368 6369 6370 6371 6372 6373 6374 6375 6376 6377 6378 6379 6380 6381 6382 6383 6384 6385 6386 6387 6388 6389 6390 6391 6392 6393 6394 6395 6396 6397 6398 6399 6400 6401 6402 6403 6404 6405 6406 6407 6408 6409 6410 6411 6412 6413 6414 6415 6416 6417 6418 6419 6420 6421 6422 6423 6424 6425 6426 6427 6428 6429 6430 6431 6432 6433 6434 6435 6436 6437 6438 6439 6440 6441 6442 6443 6444 6445 6446 6447 6448 6449 6450 6451 6452 6453 6454 6455 6456 6457 6458 6459 6460 6461 6462 6463 6464 6465 6466 6467 6468 6469 6470 6471 6472 6473 6474 6475 6476 6477 6478 6479 6480 6481 6482 6483 6484 6485 6486 6487 6488 6489 6490 6491 6492 6493 6494 6495 6496 6497 6498 6499 6500 6501 6502 6503 6504 6505 6506 6507 6508 6509 6510 6511 6512 6513 6514 6515 6516 6517 6518 6519 6520 6521 6522 6523 6524 6525 6526 6527 6528 6529 6530 6531 6532 6533 6534 6535 6536 6537 6538 6539 6540 6541 6542 6543 6544 6545 6546 6547 6548 6549 6550 6551 6552 6553 6554 6555 6556 6557 6558 6559 6560 6561 6562 6563 6564 6565 6566 6567 6568 6569 6570 6571 6572 6573 6574 6575 6576 6577 6578 6579 6580 6581 6582 6583 6584 6585 6586 6587 6588 6589 6590 6591 6592 6593 6594 6595 6596 6597 6598 6599 6600 6601 6602 6603 6604 6605 6606 6607 6608 6609 6610 6611 6612 6613 6614 6615 6616 6617 6618 6619 6620 6621 6622 6623 6624 6625 6626 6627 6628 6629 6630 6631 6632 6633 6634 6635 6636 6637 6638 6639 6640 6641 6642 6643 6644 6645 6646 6647 6648 6649 6650 6651 6652 6653 6654 6655 6656 6657 6658 6659 6660 6661 6662 6663 6664 6665 6666 6667 6668 6669 6670 6671 6672 6673 6674 6675 6676 6677 6678 6679 6680 6681 6682 6683 6684 6685 6686 6687 6688 6689 6690 6691 6692 6693 6694 6695 6696 6697 6698 6699 6700 6701 6702 6703 6704 6705 6706 6707 6708 6709 6710 6711 6712 6713 6714 6715 6716 6717 6718 6719 6720 6721 6722 6723 6724 6725 6726 6727 6728 6729 6730 6731 6732 6733 6734 6735 6736 6737 6738 6739 6740 6741 6742 6743 6744 6745 6746 6747 6748 6749 6750 6751 6752 6753 6754 6755 6756 6757 6758 6759 6760 6761 6762 6763 6764 6765 6766 6767 6768 6769 6770 6771 6772 6773 6774 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 6808 6809 6810 6811 6812 6813 6814 6815 6816 6817 6818 6819 6820 6821 6822 6823 6824 6825 6826 6827 6828 6829 6830 6831 6832 6833 6834 6835 6836 6837 6838 6839 6840 6841 6842 6843 6844 6845 6846 6847 6848 6849 6850 6851 6852 6853 6854 6855 6856 6857 6858 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 6892 6893 6894 6895 6896 6897 6898 6899 6900 6901 6902 6903 6904 6905 6906 6907 6908 6909 6910 6911 6912 6913 6914 6915 6916 6917 6918 6919 6920 6921 6922 6923 6924 6925 6926 6927 6928 6929 6930 6931 6932 6933 6934 6935 6936 6937 6938 6939 6940 6941 6942 6943 6944 6945 6946 6947 6948 6949 6950 6951 6952 6953 6954 6955 6956 6957 6958 6959 6960 6961 6962 6963 6964 6965 6966 6967 6968 6969 6970 6971 6972 6973 6974 6975 6976 6977 6978 6979 6980 6981 6982 6983 6984 6985 6986 6987 6988 6989 6990 6991 6992 6993 6994 6995 6996 6997 6998 6999 7000 7001 7002 7003 7004 7005 7006 7007 7008 7009 7010 7011 7012 7013 7014 7015 7016 7017 7018 7019 7020 7021 7022 7023 7024 7025 7026 7027 7028 7029 7030 7031 7032 7033 7034 7035 7036 7037 7038 7039 7040 7041 7042 7043 7044 7045 7046 7047 7048 7049 7050 7051 7052 7053 7054 7055 7056 7057 7058 7059 7060 7061 7062 7063 7064 7065 7066 7067 7068 7069 7070 7071 7072 7073 7074 7075 7076 7077 7078 7079 7080 7081 7082 7083 7084 7085 7086 7087 7088 7089 7090 7091 7092 7093 7094 7095 7096 7097 7098 7099 7100 7101 7102 7103 7104 7105 7106 7107 7108 7109 7110 7111 7112 7113 7114 7115 7116 7117 7118 7119 7120 7121 7122 7123 7124 7125 7126 7127 7128 7129 7130 7131 7132 7133 7134 7135 7136 7137 7138 7139 7140 7141 7142 7143 7144 7145 7146 7147 7148 7149 7150 7151 7152 7153 7154 7155 7156 7157 7158 7159 7160 7161 7162 7163 7164 7165 7166 7167 7168 7169 7170 7171 7172 7173 7174 7175 7176 7177 7178 7179 7180 7181 7182 7183 7184 7185 7186 7187 7188 7189 7190 7191 7192 7193 7194 7195 7196 7197 7198 7199 7200 7201 7202 7203 7204 7205 7206 7207 7208 7209 7210 7211 7212 7213 7214 7215 7216 7217 7218 7219 7220 7221 7222 7223 7224 7225 7226 7227 7228 7229 7230 7231 7232 | UPDATE ft_segdir SET root = blob('0101056162633132FFFFFFFF070236030132030136'); } do_catchsql_test 3.1 { SELECT * FROM ft WHERE ft MATCH 'abc20' } {1 {database disk image is malformed}} #------------------------------------------------------------------------- reset_db do_execsql_test 4.0 { CREATE VIRTUAL TABLE t1 USING fts3(); INSERT INTO t1 VALUES('one two three'); UPDATE t1_segdir SET start_block = 1; } do_catchsql_test 4.1 { SELECT * FROM t1 WHERE t1 MATCH 'one'; } {1 {database disk image is malformed}} do_catchsql_test 4.2 { SELECT * FROM t1 WHERE t1 MATCH 'two'; } {1 {database disk image is malformed}} do_catchsql_test 4.3 { SELECT * FROM t1 WHERE t1 MATCH 'three'; } {1 {database disk image is malformed}} do_execsql_test 4.4 { INSERT INTO t1(t1) VALUES('optimize'); } #------------------------------------------------------------------------- reset_db do_test 5.0 { sqlite3 db {} db deserialize [decode_hexdb { | size 24576 pagesize 4096 filename c15.db | page 1 offset 0 | 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3. | 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 04 .....@ ........ | 32: 00 00 00 00 00 00 00 00 00 00 00 04 00 00 00 04 ................ | 48: 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 ................ | 96: 00 00 00 00 0d 0e f9 00 06 0d ec 00 0f cd 0f 69 ...............i | 112: 0f 01 0e 10 0e c6 0d ec 00 00 00 00 00 00 00 00 ................ | 3552: 00 00 00 00 00 00 00 00 00 00 00 00 22 06 06 17 ................ | 3568: 11 11 01 31 74 61 62 6c 65 74 32 74 32 06 43 52 ...1tablet2t2.CR | 3584: 45 41 54 45 20 54 41 42 4c 45 20 74 32 28 78 29 EATE TABLE t2(x) | 3600: 81 33 04 07 17 1f 1f 01 82 35 74 61 62 6c 65 74 .3.......5tablet | 3616: 31 5f 73 65 67 64 69 72 74 31 5f 73 65 67 64 69 1_segdirt1_segdi | 3632: 72 04 43 52 45 41 54 45 20 54 41 42 4c 45 20 27 r.CREATE TABLE ' | 3648: 74 31 5f 73 65 67 64 69 72 27 28 6c 65 76 65 6c t1_segdir'(level | 3664: 20 49 4e 54 45 47 45 52 2c 69 64 78 20 49 4e 54 INTEGER,idx INT | 3680: 45 47 45 52 2c 73 74 61 72 74 5f 62 6c 6f 63 6b EGER,start_block | 3696: 20 49 4e 54 45 47 45 52 2c 6c 65 61 76 65 73 5f INTEGER,leaves_ | 3712: 65 6e 64 5f 62 6c 6f 63 6b 20 49 4e 54 45 47 45 end_block INTEGE | 3728: 52 2c 65 6e 64 5f 62 6c 6f 63 6b 20 49 4e 54 45 R,end_block INTE | 3744: 47 45 52 2c 72 6f 6f 74 20 42 4c 4f 42 2c 50 52 GER,root BLOB,PR | 3760: 49 4d 41 52 59 20 4b 45 59 28 6c 65 76 65 6c 2c IMARY KEY(level, | 3776: 20 69 64 78 29 29 31 05 06 17 45 1f 01 00 69 6e idx))1...E...in | 3792: 64 65 78 73 71 6c 69 74 65 5f 61 75 74 6f 69 6e dexsqlite_autoin | 3808: 64 65 79 5f 74 31 5f 73 65 67 64 69 72 5f 31 74 dey_t1_segdir_1t | 3824: 31 5f 73 65 67 64 69 72 05 00 00 00 08 00 00 00 1_segdir........ | 3840: 00 66 03 07 17 23 23 01 81 13 74 61 62 6c 65 74 .f...##...tablet | 3856: 31 5f 73 65 67 6d 65 6e 74 73 74 31 5f 73 65 67 1_segmentst1_seg | 3872: 6d 65 6e 74 73 03 43 52 45 41 54 45 20 54 41 42 ments.CREATE TAB | 3888: 4c 45 20 27 74 31 5f 73 65 67 6d 65 6e 74 73 27 LE 't1_segments' | 3904: 28 62 6c 6f 63 6b 69 64 20 49 4e 54 45 47 45 52 (blockid INTEGER | 3920: 20 50 52 49 4d 41 52 59 20 4b 45 59 2c 20 62 6c PRIMARY KEY, bl | 3936: 6f 63 6b 20 42 4c 4f 42 29 62 02 07 17 21 21 01 ock BLOB)b...!!. | 3952: 81 0f 74 61 62 6c 65 74 31 5f 63 6f 6e 74 65 6e ..tablet1_conten | 3968: 74 74 31 5f 63 6f 6e 74 65 6e 74 02 43 52 45 41 tt1_content.CREA | 3984: 54 45 20 54 41 42 4c 45 20 27 74 31 5f 63 6f 6e TE TABLE 't1_con | 4000: 74 65 6e 74 27 28 64 6f 63 69 64 20 49 4e 54 45 tent'(docid INTE | 4016: 47 45 52 20 50 52 49 4d 41 52 59 20 4b 45 59 2c GER PRIMARY KEY, | 4032: 20 27 63 30 63 6f 6e 74 65 6e 74 27 29 31 01 06 'c0content')1.. | 4048: 17 11 11 08 51 74 61 62 6c 65 74 31 74 31 43 52 ....Qtablet1t1CR | 4064: 45 41 54 45 20 56 49 52 54 55 41 4c 20 54 41 42 EATE VIRTUAL TAB | 4080: 4c 45 20 74 31 20 55 53 49 4e 47 20 66 74 73 33 LE t1 USING fts3 | page 2 offset 4096 | 0: 0d 00 00 00 03 0f e0 00 0f f6 0f ec 0f e0 00 00 ................ | 4064: 0a 03 03 00 1b 61 62 61 6e 64 6f 6e 08 02 03 00 .....abandon.... | 4080: 17 61 62 61 66 74 08 01 03 00 17 61 62 61 63 6b .abaft.....aback | page 3 offset 8192 | 0: 0d 00 00 00 00 10 00 00 00 00 00 00 00 00 00 00 ................ | page 4 offset 12288 | 0: 0d 00 00 00 01 0f d6 00 0f d6 00 00 00 00 00 00 ................ | 4048: 00 00 00 00 00 00 28 01 07 08 08 08 08 15 46 30 ......(.......F0 | 4064: 20 32 39 00 05 61 62 61 63 6b 03 01 02 00 03 02 29..aback...... | 4080: 66 74 03 02 02 00 03 04 6e 64 6f 60 30 30 20 00 ft......ndo`00 . | page 5 offset 16384 | 0: a0 00 00 00 10 ff b0 00 ff fb 00 00 00 00 00 00 ................ | 4080: 00 00 00 00 00 00 00 00 00 00 00 04 04 08 08 09 ................ | page 6 offset 20480 | 0: 0d 00 00 00 05 0f b8 00 0f f4 0f e9 0f d6 0f c7 ................ | 16: 0f b8 27 74 31 5f 63 6f 6e 74 65 6e 74 27 28 64 ..'t1_content'(d | 32: 6f 63 69 64 20 49 4e 54 45 47 45 52 20 50 52 49 ocid INTEGER PRI | 48: 4d 41 52 59 20 4b 45 59 2c 20 27 63 30 63 6f 6e MARY KEY, 'c0con | 64: 74 65 6e 74 27 29 31 01 06 17 11 11 08 51 74 61 tent')1......Qta | 80: 62 6c 65 74 31 74 31 43 52 45 41 54 45 20 56 49 blet1t1CREATE VI | 96: 52 54 55 41 4c 20 54 41 42 4c 45 20 74 31 20 55 RTUAL TABLE t1 U | 112: 53 49 4e 47 20 66 74 73 33 0d 00 00 00 03 0f e0 SING fts3....... | 128: 00 0f f6 0f ec 0f e0 00 00 00 00 00 00 00 00 00 ................ | 4016: 00 00 00 00 00 00 00 00 0d 05 02 23 61 75 74 6f ...........#auto | 4032: 6d 65 72 67 65 3d 35 0d 04 02 23 6d 65 72 67 65 merge=5...#merge | 4048: 3d 31 30 30 2c 38 11 03 02 2b 69 6e 74 65 67 72 =100,8...+integr | 4064: 69 74 79 2d 63 68 65 63 6b 09 02 02 1b 72 65 62 ity-check....reb | 4080: 75 69 6c 64 0a 01 02 1d 6f 70 74 69 6d 69 7a 65 uild....optimize | end c15.db }]} {} do_catchsql_test 5.1 { SELECT * FROM t1 WHERE t1 MATCH 'abandon'; } {1 {malformed database schema (sqlite_autoindey_t1_segdir_1) - orphan index}} #------------------------------------------------------------------------- reset_db database_may_be_corrupt do_execsql_test 6.0 { CREATE VIRTUAL TABLE Table0 USING fts3(); INSERT INTO Table0_segdir VALUES(1,NULL,1,NULL,NULL,NULL); } do_catchsql_test 6.1 { SELECT * FROM Table0 WHERE Table0 MATCH 'a'; } {0 {}} do_catchsql_test 6.2 { INSERT INTO Table0(Table0) VALUES('optimize'); } {0 {}} #------------------------------------------------------------------------- reset_db do_test 7.0 { sqlite3 db {} db deserialize [decode_hexdb { | size 32768 pagesize 4096 filename crash-04bb6e7c811ce9.db | page 1 offset 0 | 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3. | 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 07 .....@ ........ | 32: 00 00 00 00 00 00 00 00 00 00 00 06 00 00 00 04 ................ | 48: 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 ................ | 96: 00 00 00 00 0d 0e ef 00 07 0d 4d 00 0f bd 0f 5f ..........M...._ | 112: 0e f7 0e 06 0e bc 0d a4 0d 4d 00 00 00 00 00 00 .........M...... | 3392: 00 00 00 00 00 00 00 00 00 00 00 00 00 55 07 07 .............U.. | 3408: 17 1b 1b 01 81 01 74 61 62 6c 65 74 31 5f 73 74 ......tablet1_st | 3424: 61 74 74 31 5f 73 74 61 74 07 43 52 45 41 54 45 att1_stat.CREATE | 3440: 20 54 41 42 4c 45 20 27 74 31 5f 73 74 61 74 27 TABLE 't1_stat' | 3456: 28 69 64 20 49 4e 54 45 47 45 52 20 50 52 49 4d (id INTEGER PRIM | 3472: 41 52 59 20 4b 45 59 2c 20 76 61 6c 75 65 20 42 ARY KEY, value B | 3488: 4c 4f 42 29 60 06 07 17 21 21 01 81 0b 74 61 62 LOB)`...!!...tab | 3504: 6c 65 74 31 5f 64 6f 63 73 69 7a 65 74 31 5f 64 let1_docsizet1_d | 3520: 6f 63 73 69 7a 65 06 43 52 45 41 54 45 20 54 41 ocsize.CREATE TA | 3536: 42 4c 45 20 27 74 31 5f 64 6f 63 73 69 7a 65 27 BLE 't1_docsize' | 3552: 28 64 6f 63 69 64 20 49 4e 54 45 47 45 52 20 50 (docid INTEGER P | 3568: 52 49 4d 41 52 59 20 4b 45 59 2c 20 73 69 7a 65 RIMARY KEY, size | 3584: 20 42 4c 4f 42 29 81 33 04 07 17 1f 1f 01 82 35 BLOB).3.......5 | 3600: 74 61 62 6c 65 74 31 5f 73 65 67 64 69 72 74 31 tablet1_segdirt1 | 3616: 5f 73 65 67 64 69 72 04 43 52 45 41 54 45 20 54 _segdir.CREATE T | 3632: 41 42 4c 45 20 27 74 31 5f 73 65 67 64 69 72 27 ABLE 't1_segdir' | 3648: 28 6c 65 76 65 6c 20 49 4e 54 45 47 45 52 2c 69 (level INTEGER,i | 3664: 64 78 20 49 4e 54 45 47 45 52 2c 73 74 61 72 74 dx INTEGER,start | 3680: 5f 62 6c 6f 63 6b 20 49 4e 54 45 47 45 52 2c 6c _block INTEGER,l | 3696: 65 61 76 65 73 5f 65 6e 64 5f 62 6c 6f 63 6b 20 eaves_end_block | 3712: 49 4e 54 45 47 45 52 2c 65 6e 64 5f 62 6c 6f 63 INTEGER,end_bloc | 3728: 6b 20 49 4e 54 45 47 45 52 2c 72 6f 6f 74 20 42 k INTEGER,root B | 3744: 4c 4f 42 2c 50 52 49 4d 41 52 59 20 4b 45 59 28 LOB,PRIMARY KEY( | 3760: 6c 65 76 65 6c 2c 20 69 64 78 29 29 31 05 06 17 level, idx))1... | 3776: 45 1f 01 00 69 6e 64 65 78 73 71 6c 69 74 65 5f E...indexsqlite_ | 3792: 61 75 74 6f 69 6e 64 65 78 5f 74 31 5f 73 65 67 autoindex_t1_seg | 3808: 64 69 72 5f 31 74 31 5f 73 65 67 64 69 72 05 00 dir_1t1_segdir.. | 3824: 00 00 08 00 00 00 00 66 03 07 17 23 23 01 81 13 .......f...##... | 3840: 74 61 62 6c 65 74 31 5f 73 65 67 6d 65 6e 74 73 tablet1_segments | 3856: 74 31 5f 73 65 67 6d 65 6e 74 73 03 43 52 45 41 t1_segments.CREA | 3872: 54 45 20 54 41 42 4c 45 20 27 74 31 5f 73 65 67 TE TABLE 't1_seg | 3888: 6d 65 6e 74 73 27 28 62 6c 6f 63 6b 69 64 20 49 ments'(blockid I | 3904: 4e 54 45 47 45 52 20 50 52 49 4d 41 52 59 20 4b NTEGER PRIMARY K | 3920: 45 59 2c 20 62 6c 6f 63 6b 20 42 4c 4f 42 29 5c EY, block BLOB). | 3936: 02 07 17 21 21 01 81 03 74 61 62 6c 65 74 31 5f ...!!...tablet1_ | 3952: 63 6f 6e 74 65 6e 74 74 31 5f 63 6f 6e 74 65 6e contentt1_conten | 3968: 74 02 43 52 45 41 54 45 20 54 41 42 4c 45 20 27 t.CREATE TABLE ' | 3984: 74 31 5f 63 6f 6e 74 65 6e 74 27 28 64 6f 63 69 t1_content'(doci | 4000: 64 20 49 4e 54 45 47 45 52 20 50 52 49 4d 41 52 d INTEGER PRIMAR | 4016: 59 20 4b 45 59 2c 20 27 63 30 61 27 29 41 01 06 Y KEY, 'c0a')A.. | 4032: 17 11 11 08 71 74 61 62 6c 65 74 31 74 31 43 52 ....qtablet1t1CR | 4048: 45 41 54 45 20 56 49 52 54 55 41 4c 20 54 41 42 EATE VIRTUAL TAB | 4064: 4c 45 20 74 31 20 55 53 49 4e 47 20 66 74 73 34 LE t1 USING fts4 | 4080: 28 61 2c 70 72 65 66 69 78 3d 27 31 2c 32 27 29 (a,prefix='1,2') | page 2 offset 4096 | 0: 0d 00 00 00 08 0e 1f 00 0f c4 0f 7c 0f 34 0f 07 ...........|.4.. | 16: 0e c3 0e 97 0e 63 0e 1f 00 00 00 00 00 00 00 00 .....c.......... | 3600: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 42 ...............B | 3616: 08 04 00 81 09 73 75 6e 74 20 69 6e 20 63 75 6c .....sunt in cul | 3632: 70 61 20 71 75 69 20 6f 66 66 69 63 69 61 20 64 pa qui officia d | 3648: 65 73 65 72 75 6e 74 20 6d 6f 6c 6c 69 74 20 61 eserunt mollit a | 3664: 6e 69 6d 20 69 64 20 65 73 74 20 6c 61 62 6f 72 nim id est labor | 3680: 75 6d 2e 32 07 03 00 6b 45 78 63 65 70 74 65 75 um.2...kExcepteu | 3696: 72 20 73 69 6e 74 20 6f 63 63 61 65 63 67 42 06 r sint occaecgB. | 3712: 37 57 06 96 46 17 46 17 42 06 e6 f6 e2 07 07 26 7W..F.F.B......& | 3728: f6 96 46 56 e7 42 c2 a0 60 30 05 b6 36 96 c6 c7 ..FV.B..`0..6... | 3744: 56 d2 06 46 f6 c6 f7 26 52 06 57 52 06 67 56 7c V..F...&R.WR.gV| | 3760: 65 3f 04 20 6e 75 6c 6c 61 20 70 61 72 69 61 74 e?. nulla pariat | 3776: 75 72 2e 42 05 04 00 81 09 44 75 69 73 20 61 75 ur.B.....Duis au | 3792: 74 65 20 69 72 75 72 65 20 64 6f 6c 6f 72 20 69 te irure dolor i | 3808: 6e 20 72 65 70 72 65 68 65 6e 64 65 72 69 74 20 n reprehenderit | 3824: 69 6e 20 76 6f 6c 75 70 74 61 74 65 20 76 65 6c in voluptate vel | 3840: 69 74 20 65 73 73 65 2b 04 03 00 5d 6e 69 73 69 it esse+...]nisi | 3856: 20 75 74 20 61 6c 69 71 75 69 70 20 65 78 20 65 ut aliquip ex e | 3872: 61 20 63 6f 6d 6d 6f 64 6f 20 63 6f 6e 73 65 71 a commodo conseq | 3888: 75 61 74 2e 46 03 04 00 81 11 55 74 20 65 6e 69 uat.F.....Ut eni | 3904: 6d 20 61 64 20 6d 69 6e 69 6d 20 76 65 6e 69 61 m ad minim venia | 3920: 6d 2c 20 71 75 69 73 20 6e 6f 73 74 72 75 64 20 m, quis nostrud | 3936: 65 78 65 72 63 69 74 61 74 69 6f 6e 20 75 6c 6c exercitation ull | 3952: 61 6d 63 6f 20 6c 61 62 6f 72 69 73 46 02 04 00 amco laborisF... | 3968: 81 11 73 65 64 20 64 6f 20 65 69 75 73 6d 6f 64 ..sed do eiusmod | 3984: 20 74 65 6d 70 6f 72 20 69 6e 63 69 64 69 64 75 tempor incididu | 4000: 6e 74 20 75 74 20 6c 61 62 6f 72 65 20 65 74 20 nt ut labore et | 4016: 64 6f 6c 6f 72 65 20 6d 61 67 6e 61 20 61 6c 69 dolore magna ali | 4032: 71 75 61 2e 3a 01 03 00 7b 4c 6f 72 65 6d 20 69 qua.:....Lorem i | 4048: 70 73 75 6d 20 64 6f 6c 6f 72 20 73 69 72 12 29 psum dolor sir.) | 4064: 0d 65 74 2c 20 63 6f 6e 73 65 63 74 65 74 75 72 .et, consectetur | 4080: 20 61 64 69 70 69 73 63 69 6e 67 20 65 6c 69 74 adipiscing elit | page 3 offset 8192 | 0: 0d 00 00 00 00 10 30 00 10 17 50 30 80 20 00 00 ......0...P0. .. | 16: 27 46 50 30 20 50 00 00 27 56 c0 30 30 a0 00 10 'FP0 P..'V.00... | 32: 17 40 90 20 70 00 10 20 00 10 30 00 00 27 66 50 .@. p.. ..0..'fP | 48: 60 30 60 00 20 a0 00 10 16 f0 30 50 90 08 20 a0 `0`. .....0P.. . | 64: 20 80 20 80 80 81 78 40 20 40 03 02 03 23 53 10 . ...x@ @...#S. | 80: 00 16 11 30 10 60 40 00 10 c0 00 10 40 00 00 00 ...0.`@.....@... | 96: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 78 24 ..............x$ | 112: 41 71 83 37 10 27 97 60 10 40 00 00 16 41 10 10 Aq.7.'.`.@...A.. | 128: 40 00 10 30 90 00 30 20 50 00 10 30 00 20 70 00 @..0..0 P..0. p. | 144: 00 16 51 b0 10 90 00 10 40 70 00 10 30 80 00 10 ..Q.....@p..0... | 160: 50 30 00 10 b0 00 10 40 00 10 20 00 10 b0 00 00 P0.....@.. ..... | 176: 16 60 30 60 50 00 00 16 90 f0 10 30 00 10 60 00 .`0`P......0..`. | 192: 30 40 40 40 00 30 30 90 00 00 16 c0 c0 10 20 00 0@@@.00....... . | 208: 10 80 00 10 b0 00 50 c0 00 00 16 d0 90 20 b0 00 ......P...... .. | 224: 10 50 00 50 80 00 00 16 e0 c0 30 80 00 10 20 00 .P.P......0... . | 240: 20 60 00 10 60 00 00 16 f0 60 70 40 00 10 60 00 `..`....`p@..`. | 256: 00 17 00 60 60 70 00 10 70 00 00 17 10 60 30 70 ...``p..p....`0p | 272: 00 50 50 00 00 17 20 30 50 70 00 00 17 30 c0 10 .PP... 0Pp...0.. | 288: 50 00 10 20 00 50 30 00 10 20 00 00 17 40 30 20 P.. .P0.. ...@0 | 304: 50 00 00 17 50 a0 20 70 00 10 20 a0 00 10 30 00 P...P. p.. ...0. | 320: 00 17 60 70 30 60 00 20 90 30 08 52 60 10 80 80 ..`p0`. .0.R`... | 336: 80 80 81 78 a3 e3 02 03 63 63 50 00 26 16 40 30 ...x....ccP.&.@0 | 352: 30 40 00 20 86 97 06 97 36 36 96 e6 70 30 10 80 0@. ....66..p0.. | 368: 00 10 56 c6 97 17 56 10 30 20 c0 00 50 26 97 00 ..V...V.0 ..P&.. | 384: 30 40 40 00 10 36 d6 57 40 30 10 60 00 10 36 e6 0@@..6.W@0.`..6. | 400: 96 d0 30 80 90 00 10 37 57 46 50 30 50 30 00 00 ..0....7WFP0P0.. | 416: 66 36 96 c6 c7 56 d0 30 60 20 00 10 66 f6 d6 d6 f6...V.0` ..f... | 432: f6 46 f0 30 40 70 00 20 96 e7 36 56 37 46 57 47 .F.0@p. ..6V7FWG | 448: 57 20 30 10 70 00 50 47 17 56 17 40 30 40 80 00 W 0.p.PG.V.@0@.. | 464: 10 47 56 c7 06 10 30 80 40 00 20 77 06 96 46 17 .GV...0.@. w..F. | 480: 46 17 40 30 70 50 00 00 86 46 57 36 57 27 56 e7 F.@0pP...FW6W'V. | 496: 40 30 80 70 00 10 16 f0 30 20 30 00 20 36 c6 f7 @0.p....0 0. 6.. | 512: 20 60 10 40 00 40 50 00 50 16 50 60 20 a0 00 40 `.@.@P.P.P` ..@ | 528: 30 00 10 37 56 97 30 30 50 20 00 00 26 56 10 30 0..7V.00P ..&V.0 | 544: 40 60 00 10 66 97 57 36 d6 f6 40 30 20 40 00 10 @`..f.W6..@0 @.. | 560: 36 c6 97 40 30 10 90 00 15 35 14 c6 97 46 52 06 6..@0....5...FR. | 576: 66 f7 26 d6 17 42 03 30 01 00 00 10 10 04 02 02 f.&..B.0........ | 592: 00 00 00 00 00 00 00 00 70 00 00 00 00 00 00 00 ........p....... | 608: 00 00 00 00 60 00 00 00 40 00 00 00 00 00 00 00 ....`...@....... | page 4 offset 12288 | 0: 0d 00 00 00 03 0a a6 00 0d 57 0c 4a 0a a6 00 00 .........W.J.... | 2720: 00 00 00 00 00 00 83 21 03 08 02 08 08 08 17 86 .......!........ | 2736: 30 08 00 30 20 34 30 32 00 02 61 64 06 01 08 00 0..0 402..ad.... | 2752: 02 04 00 01 01 6c 06 02 0c 00 02 04 00 01 01 6d .....l.........m | 2768: 03 01 06 00 01 01 6e 03 08 00 00 91 01 75 03 05 ......n......u.. | 2784: 03 00 00 02 63 69 03 06 02 00 01 01 6f 07 01 07 ....ci......o... | 2800: 00 03 07 03 00 01 01 75 06 07 05 00 01 04 00 00 .......u........ | 2816: 02 64 65 03 08 07 00 01 01 6f 0d 01 04 00 01 03 .de......o...... | 2832: 09 00 03 05 00 01 03 00 01 01 75 03 05 02 00 00 ..........u..... | 2848: 02 65 61 03 04 06 00 01 01 69 03 02 04 00 01 01 .ea......i...... | 2864: 6c 03 01 09 00 01 01 6e 30 03 03 00 01 01 73 06 l......n0.....s. | 2880: 05 0b 00 03 0b 00 01 01 74 03 02 09 00 01 01 75 ........t......u | 2896: 03 06 04 00 01 01 78 09 03 09 00 01 05 00 03 02 ......x......... | 2912: 00 00 02 66 75 03 06 05 00 00 02 69 64 03 08 0a ...fu......id... | 2928: 00 01 01 6e 0a 02 06 00 03 06 04 00 03 03 00 01 ...n............ | 2944: 01 70 03 01 03 00 01 01 72 03 05 04 00 00 02 6c .p......r......l | 2960: 61 09 02 08 00 01 0b 00 05 0c 00 01 01 6f 03 01 a............o.. | 2976: 02 00 00 02 6d 61 03 02 0b 00 01 01 69 03 03 05 ....ma......i... | 2992: 00 01 01 6f 03 08 08 00 00 02 6e 69 03 04 02 00 ...o......ni.... | 3008: 01 01 6f 06 03 08 00 04 06 00 01 01 75 03 06 06 ..o.........u... | 3024: 00 00 02 6f 63 03 07 04 00 01 01 66 03 08 06 00 ...oc......f.... | 3040: 00 02 70 61 03 06 07 00 01 01 72 03 07 07 00 00 ..pa......r..... | 3056: 02 71 75 06 03 07 00 05 05 00 00 02 72 65 03 05 .qu.........re.. | 3072: 07 00 00 02 73 65 03 02 02 00 01 01 69 06 01 05 ....se......i... | 3088: 00 06 03 00 01 01 75 03 08 02 00 00 02 74 65 03 ......u......te. | 3104: 02 05 00 00 02 75 6c 03 03 0a 00 01 01 74 09 02 .....ul......t.. | 3120: 07 00 01 02 00 01 03 00 00 02 76 65 06 03 06 00 ..........ve.... | 3136: 02 0a 00 01 01 6f 03 05 09 00 82 0a 02 08 02 08 .....o.......... | 3152: 08 08 17 84 02 04 00 30 20 32 35 31 00 01 61 13 .......0 251..a. | 3168: 01 06 04 00 01 0c 00 01 04 00 01 04 00 01 03 00 ................ | 3184: 03 09 00 00 01 63 10 01 07 00 03 07 03 00 02 02 .....c.......... | 3200: 00 01 05 00 01 04 00 00 01 64 11 01 04 00 01 03 .........d...... | 3216: 09 00 03 02 05 00 01 03 00 02 07 00 00 01 65 1b ..............e. | 3232: 01 09 00 01 04 01 70 00 03 01 80 00 05 03 00 01 ......p......... | 3248: 0b 00 01 04 00 01 02 00 01 0b 00 00 01 66 03 06 .............f.. | 3264: 05 00 00 01 69 0f 01 03 00 01 06 00 03 04 04 04 ....i........... | 3280: 00 03 03 09 00 00 01 6c 0c 01 02 00 01 08 00 01 .......l........ | 3296: 0b 00 05 0c 00 00 01 6d 09 02 0b 00 01 05 00 05 .......m........ | 3312: 08 00 00 01 6e 0c 03 08 00 01 02 00 02 06 00 01 ....n........... | 3328: 06 00 00 01 6f 06 07 04 00 01 06 00 00 01 70 06 ....o.........p. | 3344: 06 07 00 01 07 00 00 01 71 06 03 07 00 05 05 00 ........q....... | 3360: 00 01 72 03 05 07 00 00 01 73 0c 01 05 00 01 02 ..r......s...... | 3376: 00 05 03 00 01 02 00 00 01 74 03 02 05 00 00 01 .........t...... | 3392: 75 0a 02 07 00 01 02 0a 00 01 03 00 00 01 76 07 u.............v. | 3408: 03 06 00 02 09 03 00 85 26 01 08 08 08 08 08 17 ........&....... | 3424: 8a 3e 30 20 36 36 35 00 02 61 64 03 03 04 00 02 .>0 665..ad..... | 3440: 08 69 70 69 73 63 69 6e 67 03 01 08 00 01 05 6c .ipiscing......l | 3456: 69 71 75 61 03 02 0c 00 05 02 69 70 03 04 04 00 iqua......ip.... | 3472: 01 03 6d 65 74 03 01 06 00 01 03 6e 69 6d 03 08 ..met......nim.. | 3488: 09 00 01 03 75 74 65 03 05 03 00 00 06 63 69 6c ....ute......cil | 3504: 6c 75 6d 03 06 02 00 01 06 6f 6d 6d 6f 64 6f 03 lum......ommodo. | 3520: 04 07 00 02 09 6e 73 65 63 74 65 74 75 72 03 01 .....nsectetur.. | 3536: 07 00 05 04 71 75 61 74 03 04 08 00 01 04 75 6c ....quat......ul | 3552: 70 61 03 08 04 00 02 07 70 69 64 61 74 61 74 03 pa......pidatat. | 3568: 07 05 00 00 08 64 65 73 65 72 75 6e 74 03 08 07 .....deserunt... | 3584: 00 01 01 6f 03 02 03 00 02 03 6c 6f 72 06 01 04 ...o......lor... | 3600: 00 04 05 00 05 01 65 06 02 0a 00 04 03 00 01 03 ......e......... | 3616: 75 69 73 03 05 02 00 00 02 65 61 03 04 06 00 01 uis......ea..... | 3632: 06 69 75 73 6d 6f 64 03 02 04 00 01 03 6c 69 74 .iusmod......lit | 3648: 03 01 09 00 01 03 6e 69 6d 03 03 03 00 01 03 73 ......nim......s | 3664: 73 65 03 05 0b 00 02 01 74 03 08 0b 00 01 01 74 se......t......t | 3680: 03 02 09 00 01 01 75 03 06 04 00 01 01 78 03 04 ......u......x.. | 3696: 05 00 02 07 63 65 70 74 65 75 72 03 07 02 00 02 ....cepteur..... | 3712: 0a 65 72 63 69 74 61 74 69 6f 6e 03 03 09 00 00 .ercitation..... | 3728: 06 66 75 67 69 61 74 03 06 05 00 00 02 69 64 03 .fugiat......id. | 3744: 08 0a 00 01 01 6e 07 05 06 04 00 03 03 00 02 08 .....n.......... | 3760: 63 69 64 69 64 75 6e 74 03 02 06 00 01 04 70 73 cididunt......ps | 3776: 75 6d 03 01 03 00 01 04 72 75 72 65 03 05 04 00 um......rure.... | 3792: 00 06 6c 61 62 6f 72 65 03 02 08 00 05 02 69 73 ..labore......is | 3808: 03 03 0b 00 05 02 75 6d 03 08 0c 00 01 04 6f 72 ......um......or | 3824: 65 6d 03 01 02 00 00 05 6d 61 67 6e 61 03 02 0b em......magna... | 3840: 00 01 04 69 6e 69 6d 03 03 05 00 01 05 6f 6c 6c ...inim......oll | 3856: 69 74 03 08 08 00 00 04 6e 69 73 69 03 04 02 00 it......nisi.... | 3872: 01 02 6f 6e 03 07 06 00 02 05 73 74 72 75 64 03 ..on......strud. | 3888: 03 08 00 01 04 75 6c 6c 61 03 06 06 00 00 08 6f .....ulla......o | 3904: 63 63 61 65 63 61 74 03 07 04 00 01 06 66 66 69 ccaecat......ffi | 3920: 63 69 61 03 08 06 00 00 08 70 61 72 69 61 74 75 cia......pariatu | 3936: 72 03 06 07 00 01 07 72 6f 69 64 65 6e 74 03 07 r......roident.. | 3952: 07 00 00 03 71 75 69 03 08 05 00 03 01 73 03 03 ....qui......s.. | 3968: 07 00 00 0d 72 65 70 72 65 68 65 6e 64 65 72 69 ....reprehenderi | 3984: 74 03 05 07 00 00 03 73 65 64 03 02 02 00 01 03 t......sed...... | 4000: 69 6e 74 03 07 03 00 02 01 74 03 01 05 00 01 03 int......t...... | 4016: 75 6e 74 03 08 02 00 00 06 74 65 6d 70 6f 72 03 unt......tempor. | 4032: 02 05 00 00 07 75 6c 6c 61 6d 63 6f 03 03 0a 00 .....ullamco.... | 4048: 01 01 74 09 02 07 00 01 02 00 01 03 00 00 05 76 ..t............v | 4064: 65 6c 69 74 03 05 0a 00 02 04 6e 69 61 6d 03 03 elit......niam.. | 4080: 06 00 01 08 6f 6c 75 70 74 61 74 65 03 05 09 00 ....oluptate.... | page 5 offset 16384 | 0: 0a 00 00 00 03 0f eb 00 0f fb 0f f3 0f eb 00 00 ................ | 4064: 00 00 00 00 00 00 00 00 00 00 00 07 04 02 08 01 ................ | 4080: 08 00 03 07 04 02 08 01 04 00 02 04 04 08 08 09 ................ | page 6 offset 20480 | 0: 0d 00 00 00 08 0f d0 00 0f fa 0f f4 0f ee 0f e8 ................ | 16: 0f e2 0f dc 0f d6 0f d0 00 00 00 00 00 00 00 00 ................ | 4048: 04 08 03 00 0e 0b 04 07 03 00 0e 06 04 06 03 00 ................ | 4064: 0e 06 04 05 03 00 0e 0a 04 04 03 00 0e 07 04 03 ................ | 4080: 03 00 0e 0a 04 02 03 00 0e 0b 04 01 03 00 0e 08 ................ | page 7 offset 24576 | 0: 0d 00 00 00 01 0f f7 00 0f f7 00 00 00 00 00 00 ................ | 4080: 00 00 00 00 00 00 00 07 00 03 00 14 08 45 b5 03 .............E.. | page 8 offset 28672 | 0: 6f ee cd e1 f1 ee 1a ca be ed ee ec de ac f1 cb o............... | 16: f1 ee 1a ce de ee f1 ee 0a cc de ed ae 90 87 88 ................ | 32: ec 5e dc ec fc 11 72 32 75 0a da be ec ed eb de .^....r2u....... | 48: ce c1 aa e0 ae ec 1f c1 ee 99 c2 aa e0 a9 ad 15 ................ | 64: 0e ec ab ef 1e e0 48 ad 15 04 24 80 00 00 00 00 ......H...$..... | 80: 00 00 00 00 e0 00 00 00 04 2c 80 00 10 42 4e c1 .........,...BN. | 96: 20 4b 45 59 2c 6e 6f 64 65 6e 6f 2c 61 30 29 46 KEY,nodeno,a0)F | 112: 02 06 17 11 11 08 7b 74 61 62 6c 65 74 31 74 31 .......tablet1t1 | 128: 43 52 45 41 54 e1 ec eb ea eb eb ac ee ce be de CREAT........... | 144: ee f1 ee 1a ca ba de 47 80 30 00 14 90 47 70 30 .......G.0...Gp0 | 160: 00 11 60 47 60 30 00 15 f0 47 50 30 00 10 f0 47 ..`G`0...GP0...G | 176: 40 30 00 11 f0 47 45 20 30 00 11 d0 45 10 30 00 @0...GE 0...E.0. | 192: 12 10 45 00 30 00 14 e0 44 f0 30 00 11 e0 44 e0 ..E.0...D.0...D. | 208: 30 00 12 a0 44 d0 30 00 15 e0 44 c0 30 00 10 40 0...D.0...D.0..@ | 224: 44 b0 30 00 15 10 44 a0 30 00 14 c0 44 90 30 00 D.0...D.0...D.0. | 240: 16 20 44 80 30 00 52 45 41 54 45 20 54 41 42 4c . D.0.REATE TABL | 256: 45 20 27 74 31 5f 63 6f 6e 74 65 6e 74 27 28 69 E 't1_content'(i | 272: 64 20 49 4e 54 45 47 45 52 20 50 52 49 4d 41 52 d INTEGER PRIMAR | 288: 59 20 4b 45 59 2c 20 63 30 29 69 03 07 17 19 19 Y KEY, c0)i..... | 304: 01 81 2d 74 61 62 6c 65 74 31 5f 69 64 78 74 31 ..-tablet1_idxt1 | 320: 5f 69 64 78 03 43 52 45 41 54 45 20 54 41 42 4c _idx.CREATE TABL | 336: 45 20 27 70 31 5f 69 64 78 03 6e 69 6d 03 03 03 E 'p1_idx.nim... | 352: 00 01 03 73 73 65 03 05 0b 00 02 01 74 03 08 0b ...sse......t... | 368: 00 01 01 74 03 02 09 00 01 01 75 03 06 04 00 01 ...t......u..... | 384: 01 78 03 04 05 00 02 07 63 65 70 74 65 75 72 03 .x......cepteur. | 400: 07 02 00 02 0a 65 72 63 69 74 61 74 69 6f 6e 03 .....ercitation. | 416: 03 09 00 00 06 66 75 67 69 61 74 03 06 05 00 00 .....fugiat..... | 432: 02 69 64 03 08 0a 00 01 01 6e 07 05 06 04 00 03 .id......n...... | 448: 03 00 02 08 63 69 64 69 64 75 6e 74 03 02 06 00 ....cididunt.... | 464: 01 04 70 73 75 6d 03 01 03 00 01 04 72 75 72 65 ..psum......rure | 480: 03 05 04 00 00 06 6c 61 62 6f 72 65 03 02 08 00 ......labore.... | 496: 05 02 69 73 03 03 0b 00 05 02 75 6d 03 08 0c 00 ..is......um.... | 512: 01 04 6f 72 65 6d 03 01 02 00 00 05 6d 61 67 6e ..orem......magn | 528: 61 03 02 0b 00 01 04 69 6e 69 6d 03 03 05 00 01 a......inim..... | 544: 05 6f 6c 6c 69 74 03 08 08 00 00 04 6e 69 73 69 .ollit......nisi | 560: 03 04 02 00 01 02 6f 6e 03 07 06 00 02 05 73 74 ......on......st | 576: 72 75 64 03 03 08 00 01 04 75 6c 6c 61 03 06 06 rud......ulla... | 592: 00 00 08 6f 63 63 61 65 63 61 74 03 07 04 00 01 ...occaecat..... | 608: 06 66 66 69 63 69 61 03 08 06 00 00 08 70 61 72 .fficia......par | 624: 69 61 74 75 72 03 06 07 00 01 07 72 6f ed ce de iatur......ro... | 640: 69 64 65 6e 74 03 07 07 00 00 03 71 75 69 03 08 ident......qui.. | 656: 05 00 03 01 73 03 03 07 00 00 0d 72 65 70 72 65 ....s......repre | 672: 68 65 6e 64 65 72 69 74 03 05 07 00 00 03 73 65 henderit......se | 688: 64 03 02 02 00 01 03 69 6e 74 03 07 03 00 02 01 d......int...... | 704: 74 03 01 05 00 01 03 75 6e 74 03 08 02 00 00 06 t......unt...... | 720: 74 65 6d 70 6f 72 03 02 05 00 00 07 75 6c 6c 61 tempor......ulla | 736: 6d 63 6f 03 03 0a 00 01 01 74 09 02 07 00 01 02 mco......t...... | 752: 00 01 03 00 00 05 76 65 6c 69 74 03 05 0a 00 02 ......velit..... | 768: 04 6e 69 61 6d 03 03 06 00 01 08 6f 6c 75 70 74 .niam......olupt | 784: 61 74 65 03 05 09 00 0a 00 00 00 03 0f eb 00 0f ate............. | 800: fb 0f f3 0f eb 00 00 00 00 00 00 00 00 00 00 00 ................ | end crash-04bb6e7c811ce9.db }]} {} do_catchsql_test 7.1 { SELECT matchinfo(t1,'y') FROM t1 WHERE t1 MATCH 'e*'; } {1 {database disk image is malformed}} #------------------------------------------------------------------------- reset_db do_test 8.0 { sqlite3 db {} db deserialize [decode_hexdb { | size 28672 pagesize 4096 filename crash-7948058d822acb.db | page 1 offset 0 | 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3. | 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 07 .....@ ........ | 32: 00 00 00 00 00 00 00 00 00 00 00 06 00 00 00 04 ................ | 48: 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 ................ | 96: 00 00 00 00 0d 0e ef 00 07 0d 4d 00 0f bd 0f 5f ..........M...._ | 112: 0e f7 0e 06 0e bc 0d a4 0d 4d 00 00 00 00 00 00 .........M...... | 3392: 00 00 00 00 00 00 00 00 00 00 00 00 00 55 07 07 .............U.. | 3408: 17 1b 1b 01 81 01 74 61 62 6c 65 74 31 5f 73 74 ......tablet1_st | 3424: 61 74 74 31 5f 73 74 61 74 07 43 52 45 41 54 45 att1_stat.CREATE | 3440: 20 54 41 42 4c 45 20 27 74 31 5f 73 74 61 74 27 TABLE 't1_stat' | 3456: 28 69 64 20 49 4e 54 45 47 45 52 20 50 52 49 4d (id INTEGER PRIM | 3472: 41 52 59 20 4b 45 59 2c 20 76 61 6c 75 65 20 42 ARY KEY, value B | 3488: 4c 4f 42 29 60 06 07 17 21 21 01 81 0b 74 61 62 LOB)`...!!...tab | 3504: 6c 65 74 31 5f 64 6f 63 73 69 7a 65 74 31 5f 64 let1_docsizet1_d | 3520: 6f 63 73 69 7a 65 06 43 52 45 41 54 45 20 54 41 ocsize.CREATE TA | 3536: 42 4c 45 20 27 74 31 5f 64 6f 63 73 69 7a 65 27 BLE 't1_docsize' | 3552: 28 64 6f 63 69 64 20 49 4e 54 45 47 45 52 20 50 (docid INTEGER P | 3568: 52 49 4d 41 52 59 20 4b 45 59 2c 20 73 69 7a 65 RIMARY KEY, size | 3584: 20 42 4c 4f 42 29 81 33 04 07 17 1f 1f 01 82 35 BLOB).3.......5 | 3600: 74 61 62 6c 65 74 31 5f 73 65 67 64 69 72 74 31 tablet1_segdirt1 | 3616: 5f 73 65 67 64 69 72 04 43 52 45 41 54 45 20 54 _segdir.CREATE T | 3632: 41 42 4c 45 20 27 74 31 5f 73 65 67 64 69 72 27 ABLE 't1_segdir' | 3648: 28 6c 65 76 65 6c 20 49 4e 54 45 47 45 52 2c 69 (level INTEGER,i | 3664: 64 78 20 49 4e 54 45 47 45 52 2c 73 74 61 72 74 dx INTEGER,start | 3680: 5f 62 6c 6f 63 6b 20 49 4e 54 45 47 45 52 2c 6c _block INTEGER,l | 3696: 65 61 76 65 73 5f 65 6e 64 5f 62 6c 6f 63 6b 20 eaves_end_block | 3712: 49 4e 54 45 47 45 52 2c 65 6e 64 5f 62 6c 6f 63 INTEGER,end_bloc | 3728: 6b 20 49 4e 54 45 47 45 52 2c 72 6f 6f 74 20 42 k INTEGER,root B | 3744: 4c 4f 42 2c 50 52 49 4d 41 52 59 20 4b 45 59 28 LOB,PRIMARY KEY( | 3760: 6c 65 76 65 6c 2c 20 69 64 78 29 29 31 05 06 17 level, idx))1... | 3776: 45 1f 01 00 69 6e 64 65 78 73 71 6c 69 74 65 5f E...indexsqlite_ | 3792: 61 75 74 6f 69 6e 64 65 78 5f 74 31 5f 73 65 67 autoindex_t1_seg | 3808: 64 69 72 5f 31 74 31 5f 73 65 67 64 69 72 05 00 dir_1t1_segdir.. | 3824: 00 00 08 00 00 00 00 66 03 07 17 23 23 01 81 13 .......f...##... | 3840: 74 61 62 6c 65 74 31 5f 73 65 67 6d 65 6e 74 73 tablet1_segments | 3856: 74 31 5f 73 65 67 6d 65 6e 74 73 03 43 52 45 41 t1_segments.CREA | 3872: 54 45 20 54 41 42 4c 45 20 27 74 31 5f 73 65 67 TE TABLE 't1_seg | 3888: 6d 65 6e 74 73 27 28 62 6c 6f 63 6b 69 64 20 49 ments'(blockid I | 3904: 4e 54 45 47 45 52 20 50 52 49 4d 41 52 59 20 4b NTEGER PRIMARY K | 3920: 45 59 2c 20 62 6c 6f 63 6b 20 42 4c 4f 42 29 5c EY, block BLOB). | 3936: 02 07 17 21 21 01 81 03 74 61 62 6c 65 74 31 5f ...!!...tablet1_ | 3952: 63 6f 6e 74 65 6e 74 74 31 5f 63 6f 6e 74 65 6e contentt1_conten | 3968: 74 02 43 52 45 41 54 45 20 54 41 42 4c 45 20 27 t.CREATE TABLE ' | 3984: 74 31 5f 63 6f 6e 74 65 6e 74 27 28 64 6f 63 69 t1_content'(doci | 4000: 64 20 49 4e 54 45 47 45 52 20 50 52 49 4d 41 52 d INTEGER PRIMAR | 4016: 59 20 4b 45 59 2c 20 27 63 30 61 27 29 41 01 06 Y KEY, 'c0a')A.. | 4032: 17 11 11 08 71 74 61 62 6c 65 74 31 74 31 43 52 ....qtablet1t1CR | 4048: 45 41 54 45 20 56 49 52 54 55 41 4c 20 54 41 42 EATE VIRTUAL TAB | 4064: 4c 45 20 74 31 20 55 53 49 4e 47 20 66 74 73 34 LE t1 USING fts4 | 4080: 28 61 2c 70 72 65 66 69 78 3d 27 31 2c 32 27 29 (a,prefix='1,2') | page 2 offset 4096 | 0: 0d 00 00 00 08 0e 1f 00 0f c4 0f 7c 0f 34 0f 07 ...........|.4.. | 16: 0e c3 0e 97 0e 63 0e 1f 00 00 00 00 00 00 00 00 .....c.......... | 3600: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 42 ...............B | 3616: 08 04 00 81 09 73 75 6e 74 20 69 6e 20 63 75 6c .....sunt in cul | 3632: 70 61 20 71 75 69 20 6f 66 66 69 63 69 61 20 64 pa qui officia d | 3648: 65 73 65 72 75 6e 74 20 6d 6f 6c 6c 69 74 20 61 eserunt mollit a | 3664: 6e 69 6d 20 69 64 20 65 73 74 20 6c 61 62 6f 72 nim id est labor | 3680: 75 6d 2e 32 07 03 00 6b 45 78 63 65 70 74 65 75 um.2...kExcepteu | 3696: 72 20 73 69 6e 74 20 6f 63 63 61 65 63 67 42 06 r sint occaecgB. | 3712: 37 57 06 96 46 17 46 17 42 06 e6 f6 e2 07 07 26 7W..F.F.B......& | 3728: f6 96 46 56 e7 42 c2 a0 60 30 05 b6 36 96 c6 c7 ..FV.B..`0..6... | 3744: 56 d2 06 46 f6 c6 f7 26 52 06 57 52 06 67 56 7c V..F...&R.WR.gV| | 3760: 65 3f 04 20 6e 75 6c 6c 61 20 70 61 72 69 61 74 e?. nulla pariat | 3776: 75 72 2e 42 05 04 00 81 09 44 75 69 73 20 61 75 ur.B.....Duis au | 3792: 74 65 20 69 72 75 72 65 20 64 6f 6c 6f 72 20 69 te irure dolor i | 3808: 6e 20 72 65 70 72 65 68 65 6e 64 65 72 69 74 20 n reprehenderit | 3824: 69 6e 20 76 6f 6c 75 70 74 61 74 65 20 76 65 6c in voluptate vel | 3840: 69 74 20 65 73 73 65 2b 04 03 00 5d 6e 69 73 69 it esse+...]nisi | 3856: 20 75 74 20 61 7c 69 71 75 69 70 20 65 78 20 65 ut a|iquip ex e | 3872: 61 20 63 6f 6d 6d 6f 64 6f 20 63 6f 6e 73 65 71 a commodo conseq | 3888: 75 61 74 2e 46 03 04 00 81 11 55 74 20 65 6e 69 uat.F.....Ut eni | 3904: 6d 20 61 64 20 6d 69 6e 69 6d 20 76 65 6e 69 61 m ad minim venia | 3920: 6d 2c 20 71 75 69 73 20 6e 6f 73 74 72 75 64 20 m, quis nostrud | 3936: 65 78 65 72 63 69 74 61 74 69 6f 6e 20 75 6c 6c exercitation ull | 3952: 61 6d 63 6f 20 6c 61 62 6f 72 69 73 46 02 04 00 amco laborisF... | 3968: 81 11 73 65 64 20 64 6f 20 65 69 75 73 6d 6f 64 ..sed do eiusmod | 3984: 20 74 65 6d 70 6f 72 20 69 6e 63 69 64 69 64 75 tempor incididu | 4000: 6e 74 20 75 74 20 6c 61 62 6f 72 65 20 65 74 20 nt ut labore et | 4016: 64 6f 6c 6f 72 65 20 6d 61 67 6e 61 20 61 6c 69 dolore magna ali | 4032: 71 75 61 2e 3a 01 03 00 7b 4c 6f 72 65 6d 20 69 qua.:....Lorem i | 4048: 70 73 75 6d 20 64 6f 6c 6f 72 20 73 69 74 20 61 psum dolor sit a | 4064: 6d 65 74 2c 20 63 6f 6e 73 65 63 74 65 74 75 72 met, consectetur | 4080: 20 61 64 69 70 69 73 63 69 6e 67 20 65 6c 69 74 adipiscing elit | page 3 offset 8192 | 0: 0d 00 00 00 00 10 00 00 00 00 00 00 00 00 00 00 ................ | page 4 offset 12288 | 0: 0d 00 00 00 03 0a a6 00 0d 57 0c 4a 0a a6 00 00 .........W.J.... | 2720: 00 00 00 00 00 00 83 21 03 08 02 08 08 08 17 86 .......!........ | 2736: 30 08 00 30 20 34 30 32 00 02 61 64 06 01 08 00 0..0 402..ad.... | 2752: 02 04 00 01 01 6c 06 02 0c 00 02 04 00 01 01 6d .....l.........m | 2768: 03 01 06 00 01 01 6e 03 08 00 00 91 01 75 03 05 ......n......u.. | 2784: 03 00 00 02 63 69 03 06 02 00 01 01 6f 07 01 07 ....ci......o... | 2800: 00 03 07 03 00 01 01 75 06 07 05 00 01 04 00 00 .......u........ | 2816: 02 64 65 03 08 07 00 01 01 6f 0d 01 04 00 01 03 .de......o...... | 2832: 09 00 03 05 00 01 03 00 01 01 75 03 05 02 00 00 ..........u..... | 2848: 02 65 61 03 04 06 00 01 01 69 03 02 04 00 01 01 .ea......i...... | 2864: 6c 03 01 09 00 01 01 6e 30 03 03 00 01 01 73 06 l......n0.....s. | 2880: 05 0b 00 03 0b 00 01 01 74 03 02 09 00 01 01 75 ........t......u | 2896: 03 06 04 00 01 01 78 09 03 09 00 01 05 00 03 02 ......x......... | 2912: 00 00 02 66 75 03 06 05 00 00 02 69 64 03 08 0a ...fu......id... | 2928: 00 01 01 6e 0a 02 06 00 03 06 04 00 03 03 00 01 ...n............ | 2944: 01 70 03 01 03 00 01 01 72 03 05 04 00 00 02 6c .p......r......l | 2960: 61 09 02 08 00 01 0b 00 05 0c 00 01 01 6f 03 01 a............o.. | 2976: 02 00 00 02 6d 61 03 02 0b 00 01 01 69 03 03 05 ....ma......i... | 2992: 00 01 01 6f 03 08 08 00 00 02 6e 69 03 04 02 00 ...o......ni.... | 3008: 01 01 6f 06 03 08 00 04 06 00 01 01 75 03 06 06 ..o.........u... | 3024: 00 00 02 6f 63 03 07 04 00 01 01 66 03 08 06 00 ...oc......f.... | 3040: 00 02 70 61 03 06 07 00 01 01 72 03 07 07 00 00 ..pa......r..... | 3056: 02 71 75 06 03 07 00 05 05 00 00 02 72 65 03 05 .qu.........re.. | 3072: 07 00 00 02 73 65 03 02 02 00 01 01 69 06 01 05 ....se......i... | 3088: 00 06 03 00 01 01 75 03 08 02 00 00 02 74 65 03 ......u......te. | 3104: 02 05 00 00 02 75 6c 03 03 0a 00 01 01 74 09 02 .....ul......t.. | 3120: 07 00 01 02 00 01 03 00 00 02 76 65 06 03 06 00 ..........ve.... | 3136: 02 0a 00 01 01 6f 03 05 09 00 82 0a 02 08 02 08 .....o.......... | 3152: 08 08 17 84 02 04 00 30 20 32 35 31 00 01 61 13 .......0 251..a. | 3168: 01 06 04 00 01 0c 00 01 04 00 01 04 00 01 03 00 ................ | 3184: 03 09 00 00 01 63 10 01 07 00 03 07 03 00 02 02 .....c.......... | 3200: 00 01 05 00 01 04 00 00 01 64 11 01 04 00 01 03 .........d...... | 3216: 09 00 03 02 05 00 01 03 00 02 07 00 00 01 65 1b ..............e. | 3232: 01 09 00 01 04 07 00 01 03 00 80 00 15 03 00 01 ................ | 3248: 0b 00 01 04 00 01 02 00 01 0b 00 00 01 66 03 06 .............f.. | 3264: 05 00 00 01 69 0f 01 03 00 01 06 00 03 04 04 04 ....i........... | 3280: 00 03 03 09 00 00 01 6c 0c 01 02 00 01 08 00 01 .......l........ | 3296: 0b 00 05 0c 00 00 01 6d 09 02 0b 00 01 05 00 05 .......m........ | 3312: 08 00 00 01 6e 0c 03 08 00 01 02 00 02 06 00 01 ....n........... | 3328: 06 00 00 01 6f 06 07 04 00 01 06 00 00 01 70 06 ....o.........p. | 3344: 06 07 00 01 07 00 00 01 71 06 03 07 00 05 05 00 ........q....... | 3360: 00 01 72 03 05 07 00 00 01 73 0c 01 05 00 01 02 ..r......s...... | 3376: 00 05 03 00 01 02 00 00 01 74 03 02 05 00 00 01 .........t...... | 3392: 75 0a 02 07 00 01 02 0a 00 01 03 00 00 01 76 07 u.............v. | 3408: 03 06 00 02 09 03 00 85 26 01 08 08 08 08 08 17 ........&....... | 3424: 8a 3e 30 20 36 36 35 00 02 61 64 03 03 04 00 02 .>0 665..ad..... | 3440: 08 69 70 69 73 63 69 6e 67 03 01 08 00 01 05 6c .ipiscing......l | 3456: 69 71 75 61 03 02 0c 00 05 02 69 70 03 04 04 00 iqua......ip.... | 3472: 01 03 6d 65 74 03 01 06 00 01 03 6e 69 6d 03 08 ..met......nim.. | 3488: 09 00 01 03 75 74 65 03 05 03 00 00 06 63 69 6c ....ute......cil | 3504: 6c 75 6d 03 06 02 00 01 06 6f 6d 6d 6f 64 6f 03 lum......ommodo. | 3520: 04 07 00 02 09 6e 73 65 63 74 65 74 75 72 03 01 .....nsectetur.. | 3536: 07 00 05 04 71 75 61 74 03 04 08 00 01 04 75 6c ....quat......ul | 3552: 70 61 03 08 04 00 02 07 70 69 64 61 74 61 74 03 pa......pidatat. | 3568: 07 05 00 00 08 64 65 73 65 72 75 6e 74 03 08 07 .....deserunt... | 3584: 00 01 01 6f 03 02 03 00 02 03 6c 6f 72 06 01 04 ...o......lor... | 3600: 00 40 05 00 05 01 65 06 02 0a 00 04 03 00 01 03 .@....e......... | 3616: 75 69 73 03 05 02 00 00 02 65 61 03 04 06 00 01 uis......ea..... | 3632: 06 69 75 73 6d 6f 64 03 02 04 00 01 03 6c 69 74 .iusmod......lit | 3648: 03 01 09 00 01 03 6e 69 6d 03 03 03 00 01 03 73 ......nim......s | 3664: 73 65 03 05 0b 00 02 01 74 03 08 0b 00 01 01 74 se......t......t | 3680: 03 02 09 00 01 01 75 03 06 04 00 01 01 78 03 04 ......u......x.. | 3696: 05 00 02 07 63 65 70 74 65 75 72 03 07 02 00 02 ....cepteur..... | 3712: 0a 65 72 63 69 74 61 74 69 6f 6e 03 03 09 00 00 .ercitation..... | 3728: 06 66 75 67 69 61 74 03 06 05 00 00 02 69 64 03 .fugiat......id. | 3744: 08 0a 00 01 01 6e 07 05 06 04 00 03 03 00 02 08 .....n.......... | 3760: 63 69 64 69 64 75 6e 74 03 02 06 00 01 04 70 73 cididunt......ps | 3776: 75 6d 03 01 03 00 01 04 72 75 72 65 03 05 04 00 um......rure.... | 3792: 00 06 6c 61 62 6f 72 65 03 02 08 00 05 02 69 73 ..labore......is | 3808: 03 03 0b 00 05 02 75 6d 03 08 0c 00 01 04 6f 72 ......um......or | 3824: 65 6d 03 01 02 00 00 05 6d 61 67 6e 61 03 02 0b em......magna... | 3840: 00 01 04 69 6e 69 6d 03 03 05 00 01 05 6f 6c 6c ...inim......oll | 3856: 69 74 03 08 08 00 00 04 6e 69 73 69 03 04 02 00 it......nisi.... | 3872: 01 02 6f 6e 03 07 06 00 02 05 73 74 72 75 64 03 ..on......strud. | 3888: 03 08 00 01 04 75 6c 6c 61 03 06 06 00 00 08 6f .....ulla......o | 3904: 63 63 61 65 63 61 74 03 07 04 00 01 06 66 66 69 ccaecat......ffi | 3920: 63 69 61 03 08 06 00 00 08 70 61 72 69 61 74 75 cia......pariatu | 3936: 72 03 06 07 00 01 07 72 6f 69 64 65 6e 74 03 07 r......roident.. | 3952: 07 00 00 03 71 75 69 03 08 05 00 03 01 73 03 03 ....qui......s.. | 3968: 07 00 00 0d 72 65 70 72 65 68 65 6e 64 65 72 69 ....reprehenderi | 3984: 74 03 05 07 00 00 03 73 65 64 03 02 02 00 01 03 t......sed...... | 4000: 69 6e 74 03 07 03 00 02 01 74 03 01 05 00 01 03 int......t...... | 4016: 75 6e 74 03 08 02 00 00 06 74 65 6d 70 6f 72 03 unt......tempor. | 4032: 02 05 00 00 07 75 6c 6c 61 6d 63 6f 03 03 0a 00 .....ullamco.... | 4048: 01 01 74 09 02 07 00 01 02 00 01 03 00 00 05 76 ..t............v | 4064: 65 6c 69 74 03 05 0a 00 02 04 6e 69 61 6d 03 03 elit......niam.. | 4080: 06 00 01 08 6f 6c 75 70 74 61 74 65 03 05 09 00 ....oluptate.... | page 5 offset 16384 | 0: 0a 00 00 00 03 0f eb 00 0f fb 0f f3 0f eb 00 00 ................ | 4064: 00 00 00 00 00 00 00 00 00 00 00 07 04 02 08 01 ................ | 4080: 08 00 03 07 04 02 08 01 04 00 02 04 04 08 08 09 ................ | page 6 offset 20480 | 0: 0d 00 00 00 08 0f d0 00 0f fa 0f f4 0f ee 0f e8 ................ | 16: 0f e2 0f dc 0f d6 0f d0 00 00 00 00 00 00 00 00 ................ | 4048: 04 08 03 00 0e 0b 04 07 03 00 0e 06 04 06 03 00 ................ | 4064: 0e 06 04 05 03 00 0e 0a 04 04 03 00 0e 07 04 03 ................ | 4080: 03 00 0e 0a 04 02 03 00 0e 0b 04 01 03 00 0e 08 ................ | page 7 offset 24576 | 0: 0d 00 00 00 01 0f f7 00 0f f7 00 00 00 00 00 00 ................ | 4080: 00 00 00 00 00 00 00 07 00 03 00 14 08 45 b5 03 .............E.. | end crash-7948058d822acb.db }]} {} do_catchsql_test 8.1 { SELECT matchinfo(t1,'x') FROM t1 WHERE t1 MATCH 'e*'; } {1 {database disk image is malformed}} #------------------------------------------------------------------------- reset_db do_test 9.0 { sqlite3 db {} db deserialize [decode_hexdb { | size 28672 pagesize 4096 filename crash-e1c6cbfdf643e9.db | page 1 offset 0 | 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3. | 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 07 .....@ ........ | 32: 00 00 00 02 00 00 00 01 00 00 00 07 00 00 00 04 ................ | 48: 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 ................ | 96: 00 00 00 00 0d 0e b1 00 06 0d a4 00 0f 8d 0f 21 ...............! | 112: 0e b9 0d c8 0e 7e 0d a4 0d a4 00 00 00 00 00 00 .....~.......... | 3488: 00 00 00 00 22 07 06 17 11 11 01 31 74 61 62 6c ...........1tabl | 3504: 65 74 32 74 32 07 43 52 45 41 54 45 20 54 41 42 et2t2.CREATE TAB | 3520: 4c 45 20 74 32 28 78 29 81 33 05 07 17 1f 1f 01 LE t2(x).3...... | 3536: 82 35 74 61 62 6c 65 74 31 5f 73 65 67 64 69 72 .5tablet1_segdir | 3552: 74 31 5f 73 65 67 64 69 72 05 43 52 45 41 54 45 t1_segdir.CREATE | 3568: 20 54 41 42 4c 45 20 27 74 31 5f 73 65 67 64 69 TABLE 't1_segdi | 3584: 72 27 28 6c 65 76 65 6c 20 49 4e 54 45 47 45 52 r'(level INTEGER | 3600: 2c 69 64 78 20 49 4e 54 45 47 45 52 2c 73 74 61 ,idx INTEGER,sta | 3616: 72 74 5f 62 6c 6f 63 6b 20 49 4e 54 45 47 45 52 rt_block INTEGER | 3632: 2c 6c 65 61 76 65 73 5f 65 6e 64 5f 62 6c 6f 63 ,leaves_end_bloc | 3648: 6b 20 49 4e 54 45 47 45 52 2c 65 6e 64 5f 62 6c k INTEGER,end_bl | 3664: 6f 63 6b 20 49 4e 54 45 47 45 52 2c 72 6f 6f 74 ock INTEGER,root | 3680: 20 42 4c 4f 42 2c 50 52 49 4d 41 52 59 20 4b 45 BLOB,PRIMARY KE | 3696: 59 28 6c 65 76 65 6c 2c 20 69 64 78 29 29 31 06 Y(level, idx))1. | 3712: 06 17 45 1f 01 00 69 6e 64 65 78 73 71 6c 69 74 ..E...indexsqlit | 3728: 65 5f 61 75 74 6f 69 6e 64 65 78 5f 74 31 5f 73 e_autoindex_t1_s | 3744: 65 67 64 69 72 5f 31 74 31 5f 73 65 67 64 69 72 egdir_1t1_segdir | 3760: 06 0f c7 00 08 00 00 00 00 66 04 07 17 23 23 01 .........f...##. | 3776: 81 13 74 61 62 6c 65 74 31 5f 73 65 67 6d 65 6e ..tablet1_segmen | 3792: 74 73 74 31 5f 73 65 67 6d 65 6e 74 73 04 43 52 tst1_segments.CR | 3808: 45 41 54 45 20 54 41 42 4c 45 20 27 74 31 5f 73 EATE TABLE 't1_s | 3824: 65 67 6d 65 6e 74 73 27 28 62 6c 6f 63 6b 69 64 egments'(blockid | 3840: 20 49 4e 54 45 47 45 52 20 50 52 49 4d 41 52 59 INTEGER PRIMARY | 3856: 20 4b 45 59 2c 20 62 6c 6f 63 6b 20 42 4c 4f 42 KEY, block BLOB | 3872: 29 6a 03 07 17 21 21 01 81 1f 74 61 62 6c 65 74 )j...!!...tablet | 3888: 31 5f 63 6f 6e 74 65 6e 74 74 31 5f 63 6f 6e 74 1_contentt1_cont | 3904: 65 6e 74 03 43 52 45 41 54 45 20 54 41 42 4c 45 ent.CREATE TABLE | 3920: 20 27 74 31 5f 63 6f 6e 74 65 6e 74 27 28 64 6f 't1_content'(do | 3936: 63 69 64 20 49 4e 54 45 47 45 52 20 50 52 49 4d cid INTEGER PRIM | 3952: 41 52 59 20 4b 45 59 2c 20 27 63 30 61 27 2c 20 ARY KEY, 'c0a', | 3968: 27 63 31 62 27 2c 20 27 63 32 63 27 29 38 02 06 'c1b', 'c2c')8.. | 3984: 17 11 11 08 5f 74 61 62 6c 65 74 31 74 31 43 52 ...._tablet1t1CR | 4000: 45 41 54 45 20 56 49 52 54 55 41 4c 20 54 41 42 EATE VIRTUAL TAB | 4016: 4c 45 20 74 31 20 55 53 49 4e 47 20 66 74 73 33 LE t1 USING fts3 | 4032: 28 61 2c 62 2c 63 29 00 00 00 39 00 00 00 00 00 (a,b,c)...9..... | page 3 offset 8192 | 0: 0d 00 00 00 25 0b 48 00 0f d8 0f af 0f 86 0f 74 ....%.H........t | 16: 0f 61 0f 4e 0f 2f 0f 0f 0e ef 0e d7 0e be 0e a5 .a.N./.......... | 32: 0e 8d 0e 74 0e 5b 0e 40 0e 24 0e 08 0d ef 0d d5 ...t.[.@.$...... | 48: 0d bb 0d a0 0d 84 0d 68 0d 4f 0d 35 0d 1b 0c fb .......h.O.5.... | 64: 0c da 0c b9 0c 99 0c 78 0c 57 0c 3e 0c 24 0c 0a .......x.W.>.$.. | 80: 0b 48 00 00 00 00 00 00 00 00 00 00 00 00 00 00 .H.............. | 2880: 00 00 00 00 00 00 00 00 81 3f 25 06 00 82 7f 00 .........?%..... | 2896: 00 43 4f 4d 50 49 4c 45 52 3d 67 63 63 2d 35 2e .COMPILER=gcc-5. | 2912: 34 2e 30 20 32 30 31 36 30 36 30 39 20 44 45 42 4.0 20160609 DEB | 2928: 55 47 20 45 4e 41 42 4c 45 20 44 42 53 54 41 54 UG ENABLE DBSTAT | 2944: 20 56 54 41 42 20 45 4e 41 42 4c 45 20 46 54 53 VTAB ENABLE FTS | 2960: 34 20 45 4e 41 42 4c 45 20 46 54 53 35 20 45 4e 4 ENABLE FTS5 EN | 2976: 41 42 4c 45 20 47 45 4f 50 4f 4c 59 20 45 4e 41 ABLE GEOPOLY ENA | 2992: 42 4c 45 20 4a 53 4f 4e 31 20 45 4e 41 42 4c 45 BLE JSON1 ENABLE | 3008: 20 4d 45 4d 53 59 53 35 20 45 4e 41 42 4c 45 20 MEMSYS5 ENABLE | 3024: 52 54 52 45 45 20 4d 41 58 20 4d 45 4d 4f 52 59 RTREE MAX MEMORY | 3040: 3d 35 30 30 30 30 30 30 30 20 4f 4d 49 54 20 4c =50000000 OMIT L | 3056: 4f 41 44 20 45 58 54 45 4e 53 49 4f 4e 20 54 48 OAD EXTENSION TH | 3072: 52 45 41 44 53 41 46 45 3d 30 18 24 05 00 25 0f READSAFE=0.$..%. | 3088: 19 54 48 52 45 41 44 53 41 46 45 3d 30 58 42 49 .THREADSAFE=0XBI | 3104: 4e 41 52 59 18 23 05 00 25 0f 19 54 48 52 45 41 NARY.#..%..THREA | 3120: 44 53 41 46 45 3d 30 58 4e 4f 43 41 53 45 17 22 DSAFE=0XNOCASE.. | 3136: 05 00 25 0f 17 54 48 52 45 41 44 53 41 46 45 3d ..%..THREADSAFE= | 3152: 30 58 52 54 52 49 4d 1f 21 05 00 33 0f 19 4f 4d 0XRTRIM.!..3..OM | 3168: 49 54 20 4c 4f 41 44 20 35 58 54 45 4e 53 49 4f IT LOAD 5XTENSIO | 3184: 4e 58 42 49 4e 41 52 59 1f 20 05 00 33 0f 19 4f NXBINARY. ..3..O | 3200: 4d 49 54 20 4c 4f 41 44 20 45 58 54 45 4e 53 49 MIT LOAD EXTENSI | 3216: 4f 4e 58 4e 4f 43 41 53 45 1e 1f 05 00 33 0f 17 ONXNOCASE....3.. | 3232: 4f 4d 49 54 20 4c 4f 41 44 20 45 58 54 45 4e 53 OMIT LOAD EXTENS | 3248: 49 4f 4e 58 52 54 52 49 4d 1f 1e 05 00 33 0f 19 IONXRTRIM....3.. | 3264: 4d 41 58 20 4d 45 4d 4f 52 59 3d 35 30 30 30 30 MAX MEMORY=50000 | 3280: 30 30 30 58 42 49 4e 41 52 59 1f 1d 05 00 33 0f 000XBINARY....3. | 3296: 19 4d 41 58 20 4d 45 4d 4f 52 59 3d 35 30 30 30 .MAX MEMORY=5000 | 3312: 30 30 30 30 58 4e 4f 43 41 53 45 1e 1c 05 00 33 0000XNOCASE....3 | 3328: 0f 17 4d 41 58 20 4d 45 4d 4f 52 59 3d 35 30 30 ..MAX MEMORY=500 | 3344: 30 30 30 30 30 58 52 54 52 49 4d 18 1b 05 00 25 00000XRTRIM....% | 3360: 0f 19 45 4e 41 42 4c 45 20 52 54 52 45 45 58 42 ..ENABLE RTREEXB | 3376: 49 4e 41 52 59 18 1a 05 00 25 0f 19 45 4e 41 42 INARY....%..ENAB | 3392: 4c 45 20 52 54 52 45 45 58 4e 4f 43 41 53 45 17 LE RTREEXNOCASE. | 3408: 19 05 00 25 0f 17 45 4e 41 42 4c 45 20 52 54 52 ...%..ENABLE RTR | 3424: 45 45 58 52 54 52 49 4d 1a 18 05 00 29 0f 19 45 EEXRTRIM....)..E | 3440: 4e 41 42 4c 45 20 4d 45 4d 53 59 53 35 58 42 49 NABLE MEMSYS5XBI | 3456: 4e 41 52 59 1a 17 05 00 29 0f 19 45 4e 41 42 4c NARY....)..ENABL | 3472: 45 20 4d 45 4d 53 59 53 35 58 4e 4f 43 41 53 45 E MEMSYS5XNOCASE | 3488: 19 16 05 00 29 0f 17 45 4e 41 42 4c 45 20 4d 45 ....)..ENABLE ME | 3504: 4d 53 59 53 35 58 52 54 52 49 4d 18 15 05 00 25 MSYS5XRTRIM....% | 3520: 0f 19 45 4e 41 42 4c 45 20 4a 53 4f 4e 31 58 42 ..ENABLE JSON1XB | 3536: 49 4e 41 52 59 18 14 05 00 25 0f 19 45 4e 41 42 INARY....%..ENAB | 3552: 4c 45 20 4a 53 4f 4e 31 58 4e 4f 43 41 53 45 17 LE JSON1XNOCASE. | 3568: 13 05 00 25 1f 17 45 4e 41 42 4c 45 20 4a 53 4f ...%..ENABLE JSO | 3584: 4e 31 58 52 54 52 49 4d 1a 12 05 00 29 0f 19 45 N1XRTRIM....)..E | 3600: 4e 41 42 4c 45 20 47 45 4f 50 4f 4c 59 58 42 49 NABLE GEOPOLYXBI | 3616: 4e 41 52 59 1a 11 05 00 29 0f 19 45 4e 41 42 4c NARY....)..ENABL | 3632: 45 20 47 45 4f 50 4f 4c 59 58 4e 4f 43 41 53 45 E GEOPOLYXNOCASE | 3648: 19 10 05 00 29 0f 17 45 4e 41 42 4c 45 20 47 45 ....)..ENABLE GE | 3664: 4f 50 4f 4c 59 58 52 54 52 49 4d 17 0f 05 00 23 OPOLYXRTRIM....# | 3680: 0f 19 45 4e 41 42 4c 45 20 46 54 53 35 58 42 49 ..ENABLE FTS5XBI | 3696: 4e 41 52 59 17 0e 05 00 23 0f 19 45 4e 41 42 4c NARY....#..ENABL | 3712: 45 20 46 54 53 35 58 4e 4f 43 41 53 45 16 0d 05 E FTS5XNOCASE... | 3728: 00 23 0f 17 44 4e 41 42 4c 45 20 46 54 53 35 58 .#..DNABLE FTS5X | 3744: 52 54 52 49 4d 17 0c 05 00 23 0f 19 45 4e 41 42 RTRIM....#..ENAB | 3760: 4c 45 20 46 54 53 34 58 42 49 4e 41 52 59 17 0b LE FTS4XBINARY.. | 3776: 05 00 23 0f 19 45 4e 41 42 4c 45 20 46 54 53 34 ..#..ENABLE FTS4 | 3792: 58 4e 4f 43 41 53 45 16 0a 05 00 23 0f 17 45 4e XNOCASE....#..EN | 3808: 41 42 4c 45 20 46 54 53 34 58 52 54 52 49 4d 1e ABLE FTS4XRTRIM. | 3824: 09 05 00 31 0f 19 45 4e 41 42 4c 45 20 44 42 53 ...1..ENABLE DBS | 3840: 54 41 54 20 56 54 41 42 58 42 49 4e 41 52 59 1e TAT VTABXBINARY. | 3856: 08 05 00 31 0f 19 45 4e 41 42 4c 45 20 44 42 53 ...1..ENABLE DBS | 3872: 54 41 54 20 56 54 41 42 58 4e 4f 43 41 53 45 1d TAT VTABXNOCASE. | 3888: 07 05 00 31 0f 17 45 4e 41 42 4c 45 20 44 42 53 ...1..ENABLE DBS | 3904: 54 41 54 20 56 54 41 42 58 52 54 52 49 4d 11 06 TAT VTABXRTRIM.. | 3920: 05 00 17 0f 19 44 45 42 55 47 58 42 49 4e 41 52 .....DEBUGXBINAR | 3936: 59 11 05 05 00 17 0f 19 44 45 42 55 47 58 4e 4f Y.......DEBUGXNO | 3952: 43 41 53 45 10 04 05 00 17 0f 17 44 45 42 55 47 CASE.......DEBUG | 3968: 58 52 54 52 49 4d 27 03 05 00 43 0f 19 43 4f 4d XRTRIM'...C..COM | 3984: 50 49 4c 45 52 3d 67 63 63 2d 35 2e 34 2e 30 20 PILER=gcc-5.4.0 | 4000: 32 30 31 36 30 36 30 39 58 42 49 4e 41 52 59 27 20160609XBINARY' | 4016: 02 05 00 43 0f 19 43 4f 4d 50 49 4c 45 52 3d 67 ...C..COMPILER=g | 4032: 63 63 2d 35 2e 34 2e 30 20 32 30 31 36 30 36 30 cc-5.4.0 2016060 | 4048: 39 58 4e 4f 43 41 53 45 26 01 05 00 43 0f 17 43 9XNOCASE&...C..C | 4064: 4f 4d 50 49 4c 45 52 3d 67 63 63 2d 35 2e 34 2e OMPILER=gcc-5.4. | 4080: 30 20 32 30 31 36 30 36 30 39 58 52 54 52 49 4d 0 20160609XRTRIM | page 4 offset 12288 | 0: 0d 00 00 00 00 10 00 00 00 00 00 00 00 00 00 00 ................ | page 5 offset 16384 | 0: 0d 00 00 00 02 0b a0 00 0c ad 0b a0 00 00 00 00 ................ | 2976: 82 0a 02 08 08 09 08 08 17 84 06 30 20 32 35 33 ...........0 253 | 2992: 00 01 30 04 25 06 1b 00 00 08 32 30 31 36 30 36 ..0.%.....201606 | 3008: 30 39 03 25 07 00 00 01 34 03 25 05 00 00 01 35 09.%....4.%....5 | 3024: 03 25 04 00 01 07 30 30 30 30 30 30 30 03 25 1a .%....0000000.%. | 3040: 00 00 08 63 6f 6d 70 69 6c 65 72 03 25 02 00 00 ...compiler.%... | 3056: 06 64 62 73 74 61 74 03 25 0a 00 01 04 65 62 75 .dbstat.%....ebu | 3072: 67 03 25 08 00 00 06 65 6e 61 62 6c 65 09 25 09 g.%....enable.%. | 3088: 05 04 04 04 04 04 00 01 08 78 74 65 6e 73 69 6f .........xtensio | 3104: 6e 03 25 1d 00 00 04 66 74 73 34 03 25 0d 00 03 n.%....fts4.%... | 3120: 01 35 03 25 0f 00 00 03 67 63 63 03 25 03 00 01 .5.%....gcc.%... | 3136: 06 65 6f 70 6f 6c 79 03 25 11 00 00 05 6a 73 6f .eopoly.%....jso | 3152: 6e 31 03 25 13 00 00 04 6c 6f 61 64 03 25 1c 00 n1.%....load.%.. | 3168: 00 03 6d 61 78 03 25 18 00 01 05 65 6d 6f 72 79 ..max.%....emory | 3184: 03 25 19 00 03 04 73 79 73 35 03 25 15 00 00 04 .%....sys5.%.... | 3200: 6f 6d 69 74 03 25 1b 00 00 05 72 74 72 65 65 03 omit.%....rtree. | 3216: 25 17 00 00 0a 74 68 72 65 61 64 73 61 66 65 03 %....threadsafe. | 3232: 25 1e 00 00 04 76 74 61 62 03 25 0b 00 86 50 01 %....vtab.%...P. | 3248: 08 08 08 08 08 17 8d 12 30 20 38 33 35 00 01 30 ........0 835..0 | 3264: 12 01 06 00 01 06 00 01 06 00 1f 03 00 01 03 00 ................ | 3280: 01 03 00 00 08 32 30 31 36 30 36 30 39 09 01 07 .....20160609... | 3296: 00 01 07 00 01 07 00 00 01 34 09 01 05 00 01 05 .........4...... | 3312: 00 01 05 00 00 01 35 09 01 04 00 01 04 00 01 04 ......5......... | 3328: 00 01 07 30 30 30 30 30 30 30 09 1c 04 00 01 04 ...0000000...... | 3344: 00 01 04 00 00 06 62 69 6e 61 72 79 3c 03 01 02 ......binary<... | 3360: 02 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 ................ | 3376: 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 00 ................ | 3392: 03 01 02 02 00 03 01 02 02 00 03 01 02 02 00 03 ................ | 3408: 01 02 02 00 03 01 02 02 00 00 08 63 6f 6d 70 69 ...........compi | 3424: 6c 65 72 09 01 02 00 01 02 00 01 02 00 00 06 64 ler............d | 3440: 62 73 74 61 74 09 07 03 00 01 03 00 01 03 00 01 bstat........... | 3456: 04 65 62 75 67 09 04 02 00 01 02 00 01 02 00 00 .ebug........... | 3472: 06 65 6e 61 62 6c 65 3f 07 02 00 01 02 00 01 02 .enable?........ | 3488: 00 01 02 00 01 02 00 01 02 00 01 02 00 01 02 00 ................ | 3504: 01 02 00 01 02 00 01 02 00 01 02 00 01 01 00 01 ................ | 3520: 02 00 01 02 00 01 02 00 01 02 00 01 02 00 01 02 ................ | 3536: 00 01 02 00 01 02 00 01 08 78 74 65 6e 73 69 6f .........xtensio | 3552: 6e 09 1f 04 00 01 04 00 01 04 00 00 04 66 74 73 n............fts | 3568: 34 09 0a 03 00 01 03 00 01 03 00 03 01 35 09 0d 4............5.. | 3584: 03 00 01 03 00 01 03 00 00 03 67 63 63 09 01 03 ..........gcc... | 3600: 00 01 03 00 01 03 00 01 06 65 6f 70 6f 6c 79 09 .........eopoly. | 3616: 10 03 00 01 03 00 01 03 00 00 05 6a 73 6f 6e 31 ...........json1 | 3632: 09 13 03 00 01 03 00 01 03 00 00 04 6c 6f 61 64 ............load | 3648: 09 1f 03 00 01 03 00 01 03 00 00 03 6d 61 78 09 ............max. | 3664: 1c 02 00 01 02 00 01 02 00 01 05 65 6d 6f 72 79 ...........emory | 3680: 09 1c 03 00 01 03 00 01 03 00 03 04 73 79 73 35 ............sys5 | 3696: 09 16 03 00 01 03 00 01 03 00 00 06 6e 6f 63 61 ............noca | 3712: 73 65 3c 02 01 02 02 00 03 01 02 02 00 03 01 02 se<............. | 3728: 02 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 ................ | 3744: 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 00 ................ | 3760: 03 01 02 02 00 03 01 02 02 00 03 01 02 02 00 00 ................ | 3776: 04 6f 6d 69 74 09 1f 02 00 01 02 00 01 02 00 00 .omit........... | 3792: 05 72 74 72 65 65 09 19 03 00 01 03 00 01 03 00 .rtree.......... | 3808: 03 02 69 6d 3c 01 01 02 02 00 03 01 02 02 00 03 ..im<........... | 3824: 01 02 02 00 03 01 02 02 00 03 01 02 02 00 03 01 ................ | 3840: 02 02 00 03 01 02 02 00 03 01 02 02 00 03 01 02 ................ | 3856: 02 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 ................ | 3872: 00 00 0a 74 68 72 65 61 64 73 61 66 65 09 22 02 ...threadsafe... | 3888: 00 01 02 00 0a 12 00 00 04 76 74 61 62 09 07 04 .........vtab... | 3904: 00 01 04 00 01 04 00 00 01 78 b4 01 01 01 01 02 .........x...... | 3920: 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 ................ | 3936: 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 01 ................ | 3952: 01 01 02 00 01 01 01 02 00 01 01 01 02 00 01 01 ................ | 3968: 01 02 00 01 01 01 02 00 01 01 01 02 00 01 01 01 ................ | 3984: 02 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 ................ | 4000: 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 ................ | 4016: 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 01 ................ | 4032: 01 01 02 00 01 01 01 02 00 01 01 01 02 00 01 01 ................ | 4048: 01 02 00 01 01 01 02 00 01 01 01 02 00 01 01 01 ................ | 4064: 02 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 ................ | 4080: 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 ................ | page 6 offset 20480 | 0: 0a 00 00 00 02 0f f5 00 0f fb 0f f5 00 00 00 00 ................ | 4080: 00 00 00 00 00 05 04 08 09 01 02 04 04 08 08 09 ................ | page 7 offset 24576 | 0: 0d 00 00 00 05 0f b8 00 0f f4 0f e9 0f d6 0f c7 ................ | 16: 0f b8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ | 4016: 00 00 00 00 00 00 00 00 0d 05 02 23 61 75 74 6f ...........#auto | 4032: 6d 65 72 67 65 3d 35 0d 04 02 23 6d 65 72 67 65 merge=5...#merge | 4048: 3d 31 30 30 2c 38 11 03 02 2b 69 6e 74 65 67 72 =100,8...+integr | 4064: 69 74 79 2d 63 68 65 63 6b 09 02 02 1b 72 65 62 ity-check....reb | 4080: 75 69 6c 64 0a 01 02 1d 6f 70 74 69 6d 69 7a 65 uild....optimize | end crash-e1c6cbfdf643e9.db }]} {} do_execsql_test 9.1 { SELECT count(*) FROM t1 WHERE t1 MATCH '"json1 enable"'; } {1} #------------------------------------------------------------------------- reset_db do_test 10.0 { sqlite3 db {} db deserialize [decode_hexdb { | size 28672 pagesize 4096 filename crash-c3a971f0061039.db | page 1 offset 0 | 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3. | 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 07 .....@ ........ | 32: 00 00 00 02 00 00 00 01 00 00 00 07 00 00 00 04 ................ | 48: 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 ................ | 96: 00 00 00 00 0d 0e b1 00 06 0d a4 00 0f 8d 0f 21 ...............! | 112: 0e b9 0d c8 0e 7e 0d a4 0d a4 00 00 00 00 00 00 .....~.......... | 3488: 00 00 00 00 22 07 06 17 11 11 01 31 74 61 62 6c ...........1tabl | 3504: 65 74 32 74 32 07 43 52 45 41 54 45 20 54 41 42 et2t2.CREATE TAB | 3520: 4c 45 20 74 32 28 78 29 81 33 05 07 17 1f 1f 01 LE t2(x).3...... | 3536: 82 35 74 61 62 6c 65 74 31 5f 73 65 67 64 69 72 .5tablet1_segdir | 3552: 74 31 5f 73 65 67 64 69 72 05 43 52 45 41 54 45 t1_segdir.CREATE | 3568: 20 54 41 42 4c 45 20 27 74 31 5f 73 65 67 64 69 TABLE 't1_segdi | 3584: 72 27 28 6c 65 76 65 6c 20 49 4e 54 45 47 45 52 r'(level INTEGER | 3600: 2c 69 64 78 20 49 4e 54 45 47 45 52 2c 73 74 61 ,idx INTEGER,sta | 3616: 72 74 5f 62 6c 6f 63 6b 20 49 4e 54 45 47 45 52 rt_block INTEGER | 3632: 2c 6c 65 61 76 65 73 5f 65 6e 64 5f 62 6c 6f 63 ,leaves_end_bloc | 3648: 6b 20 49 4e 54 45 47 45 52 2c 65 6e 64 5f 62 6c k INTEGER,end_bl | 3664: 6f 63 6b 20 49 4e 54 45 47 45 52 2c 72 6f 6f 74 ock INTEGER,root | 3680: 20 42 4c 4f 42 2c 50 52 49 4d 41 52 59 20 4b 45 BLOB,PRIMARY KE | 3696: 59 28 6c 65 76 65 6c 2c 20 69 64 78 29 29 31 06 Y(level, idx))1. | 3712: 06 17 45 1f 01 00 69 6e 64 65 78 73 71 6c 69 74 ..E...indexsqlit | 3728: 65 5f 61 75 74 6f 69 6e 64 65 78 5f 74 31 5f 73 e_autoindex_t1_s | 3744: 65 67 64 69 72 5f 31 74 31 5f 73 65 67 64 69 72 egdir_1t1_segdir | 3760: 06 0f c7 00 08 00 00 00 00 66 04 07 17 23 23 01 .........f...##. | 3776: 81 13 74 61 62 6c 65 74 31 5f 73 65 67 6d 65 6e ..tablet1_segmen | 3792: 74 73 74 31 5f 73 65 67 6d 65 6e 74 73 04 43 52 tst1_segments.CR | 3808: 45 41 54 45 20 54 41 42 4c 45 20 27 74 31 5f 73 EATE TABLE 't1_s | 3824: 65 67 6d 65 6e 74 73 27 28 62 6c 6f 63 6b 69 64 egments'(blockid | 3840: 20 49 4e 54 45 47 45 52 20 50 52 49 4d 41 52 59 INTEGER PRIMARY | 3856: 20 4b 45 59 2c 20 62 6c 6f 63 6b 20 42 4c 4f 42 KEY, block BLOB | 3872: 29 6a 03 07 17 21 21 01 81 1f 74 61 62 6c 65 74 )j...!!...tablet | 3888: 31 5f 63 6f 6e 74 65 6e 74 74 31 5f 63 6f 6e 74 1_contentt1_cont | 3904: 65 6e 74 03 43 52 45 41 54 45 20 54 41 42 4c 45 ent.CREATE TABLE | 3920: 20 27 74 31 5f 63 6f 6e 74 65 6e 74 27 28 64 6f 't1_content'(do | 3936: 63 69 64 20 49 4e 54 45 47 45 52 20 50 52 49 4d cid INTEGER PRIM | 3952: 41 52 59 30 4b 45 59 2c 20 27 63 30 61 27 2c 20 ARY0KEY, 'c0a', | 3968: 27 63 31 62 27 2c 20 27 63 32 63 27 29 38 02 06 'c1b', 'c2c')8.. | 3984: 17 11 11 08 5f 74 61 62 6c 65 74 31 74 31 43 52 ...._tablet1t1CR | 4000: 45 41 54 45 20 56 49 52 54 55 41 4c 20 54 41 42 EATE VIRTUAL TAB | 4016: 4c 45 20 74 31 20 55 53 49 4e 47 20 66 74 73 33 LE t1 USING fts3 | 4032: 28 61 2c 62 2c 63 29 00 00 00 39 00 00 00 00 00 (a,b,c)...9..... | page 3 offset 8192 | 0: 0d 00 00 00 25 0b 48 00 0f d8 0f af 0f 86 0f 74 ....%.H........t | 16: 0f 61 0f 4e 0f 2f 0f 0f 0e ef 0e d7 0e be 0e a5 .a.N./.......... | 32: 0e 8d 0e 74 0e 5b 0e 40 0e 24 0e 08 0d ef 0d d5 ...t.[.@.$...... | 48: 0d bb 0d a0 0d 84 0d 68 0d 4f 0d 35 0d 1b 0c fb .......h.O.5.... | 64: 0c da 0c b9 0c 99 0c 78 0c 57 0c 3e 0c 24 0c 0a .......x.W.>.$.. | 80: 0b 48 00 00 00 00 00 00 00 00 00 00 00 00 00 00 .H.............. | 2880: 00 00 00 00 00 00 00 00 81 3f 25 06 00 82 7f 00 .........?%..... | 2896: 00 43 4f 4d 50 49 4c 45 52 3d 67 63 63 2d 35 2e .COMPILER=gcc-5. | 2912: 34 2e 30 20 32 30 31 36 30 36 30 39 20 44 45 42 4.0 20160609 DEB | 2928: 55 47 20 45 4e 41 42 4c 45 20 44 42 53 54 41 54 UG ENABLE DBSTAT | 2944: 20 56 54 41 42 20 45 4e 41 42 4c 45 20 46 54 53 VTAB ENABLE FTS | 2960: 34 20 45 4e 41 42 4c 45 20 46 54 53 35 20 45 4e 4 ENABLE FTS5 EN | 2976: 41 42 4c 45 20 47 45 4f 50 4f 4c 59 20 45 4e 41 ABLE GEOPOLY ENA | 2992: 42 4c 45 20 4a 53 4f 4e 31 20 45 4e 41 42 4c 45 BLE JSON1 ENABLE | 3008: 20 4d 45 4d 53 59 53 35 20 45 4e 41 42 4c 45 1f MEMSYS5 ENABLE. | 3024: 52 54 52 45 45 20 4d 41 58 20 4d 45 4d 4f 52 59 RTREE MAX MEMORY | 3040: 3d 35 30 30 30 30 30 30 30 20 4f 4d 49 54 20 4c =50000000 OMIT L | 3056: 4f 41 44 20 45 58 54 45 4e 53 49 4f 4e 20 54 48 OAD EXTENSION TH | 3072: 52 45 41 44 53 41 46 45 3d 30 18 24 05 00 25 0f READSAFE=0.$..%. | 3088: 19 54 48 52 45 41 44 53 41 46 45 3d 30 58 42 49 .THREADSAFE=0XBI | 3104: 4e 41 52 59 18 23 05 00 25 0f 19 54 48 52 45 41 NARY.#..%..THREA | 3120: 44 53 41 46 45 3d 30 58 4e 4f 43 41 53 45 17 22 DSAFE=0XNOCASE.. | 3136: 05 00 25 0f 17 54 48 52 45 41 44 53 41 46 45 3d ..%..THREADSAFE= | 3152: 30 58 52 54 52 49 4d 1f 21 05 00 33 0f 19 4f 4d 0XRTRIM.!..3..OM | 3168: 49 54 20 4c 4f 41 44 20 45 58 54 45 4e 53 49 4f IT LOAD EXTENSIO | 3184: 4e 58 43 49 4e 41 52 59 1f 20 05 00 33 0f 19 4f NXCINARY. ..3..O | 3200: 4d 49 54 20 4c 4f 41 44 20 45 58 54 45 4e 53 49 MIT LOAD EXTENSI | 3216: 4f 4e 58 4e 4f 43 41 53 45 1e 1f 05 00 33 0f 17 ONXNOCASE....3.. | 3232: 4f 4d 49 54 20 4c 4f 41 44 20 45 58 54 45 4e 53 OMIT LOAD EXTENS | 3248: 49 4f 4e 58 52 54 52 49 4d 1f 1e 05 00 33 0f 19 IONXRTRIM....3.. | 3264: 4d 41 58 20 4d 45 4d 4f 52 59 3d 35 30 30 30 30 MAX MEMORY=50000 | 3280: 30 30 30 58 42 49 4e 41 52 59 1f 1d 05 00 33 0f 000XBINARY....3. | 3296: 19 4d 41 58 20 4d 45 4d 4f 52 59 3d 35 30 30 30 .MAX MEMORY=5000 | 3312: 30 30 30 30 58 4e 4f 43 41 53 45 1e 1c 05 00 33 0000XNOCASE....3 | 3328: 0f 17 4d 41 58 20 4d 45 4d 4f 52 59 3d 35 30 30 ..MAX MEMORY=500 | 3344: 30 30 30 30 30 58 52 54 52 49 4d 18 1b 05 00 25 00000XRTRIM....% | 3360: 0f 19 45 4e 41 42 4c 45 20 52 54 52 45 45 58 42 ..ENABLE RTREEXB | 3376: 49 4e 41 52 59 18 1a 05 00 25 0f 19 45 4e 41 42 INARY....%..ENAB | 3392: 4c 45 20 52 54 52 45 45 58 4e 4f 43 41 53 45 17 LE RTREEXNOCASE. | 3408: 19 05 00 25 0f 17 45 4e 41 42 4c 45 20 52 54 52 ...%..ENABLE RTR | 3424: 45 45 58 52 54 52 49 4d 1a 18 05 00 29 0f 19 45 EEXRTRIM....)..E | 3440: 4e 41 42 4c 45 20 4d 45 4d 53 59 53 35 58 42 49 NABLE MEMSYS5XBI | 3456: 4e 41 52 59 1a 17 05 00 29 0f 19 45 4e 41 42 4c NARY....)..ENABL | 3472: 45 20 4d 45 4d 53 59 53 35 58 4e 4f 43 41 53 45 E MEMSYS5XNOCASE | 3488: 19 16 05 00 29 0f 17 45 4e 41 42 4c 45 20 4d 45 ....)..ENABLE ME | 3504: 4d 53 59 53 35 58 52 54 52 49 4d 18 15 09 00 25 MSYS5XRTRIM....% | 3520: 0f 19 45 4e 41 42 4c 45 20 4a 53 4f 4e 31 58 42 ..ENABLE JSON1XB | 3536: 49 4e 41 52 59 18 14 05 00 25 0f 19 45 4e 41 42 INARY....%..ENAB | 3552: 4c 45 20 4a 53 4f 4e 31 58 4e 4f 43 41 53 45 17 LE JSON1XNOCASE. | 3568: 13 05 00 25 0f 17 45 4e 41 42 4c 45 20 4a 53 4f ...%..ENABLE JSO | 3584: 4e 31 58 52 54 52 49 4d 1a 12 05 00 29 0f 19 45 N1XRTRIM....)..E | 3600: 4e 41 42 4c 45 20 47 45 4f 50 4f 4c 59 58 42 49 NABLE GEOPOLYXBI | 3616: 4e 41 52 59 1a 11 05 00 29 0f 19 45 4e 41 42 4c NARY....)..ENABL | 3632: 45 20 47 45 4f 50 4f 4c 59 58 4e 4f 43 41 53 45 E GEOPOLYXNOCASE | 3648: 19 10 05 00 29 0f 17 45 4e 41 42 4c 46 20 47 45 ....)..ENABLF GE | 3664: 4f 50 4f 4c 59 58 52 54 52 49 4d 17 0f 05 00 23 OPOLYXRTRIM....# | 3680: 0f 19 45 4e 41 42 4c 45 20 46 54 53 35 58 42 49 ..ENABLE FTS5XBI | 3696: 4e 41 52 59 17 0e 05 00 23 0f 19 45 4e 41 42 4c NARY....#..ENABL | 3712: 45 20 46 54 53 35 58 4e 4f 43 41 53 45 16 0d 05 E FTS5XNOCASE... | 3728: 00 23 0f 17 45 4e 41 42 4c 45 20 46 54 53 35 58 .#..ENABLE FTS5X | 3744: 52 54 52 49 4d 17 0c 05 00 23 0f 19 45 4e 41 42 RTRIM....#..ENAB | 3760: 4c 45 20 46 54 53 34 58 42 49 4e 41 52 59 17 0b LE FTS4XBINARY.. | 3776: 05 00 23 0f 19 45 4e 41 42 4c 45 20 46 54 53 34 ..#..ENABLE FTS4 | 3792: 58 4e 4f 43 41 53 45 16 0a 05 00 23 0f 17 45 4e XNOCASE....#..EN | 3808: 41 42 4c 45 20 46 54 53 34 58 52 54 52 49 4d 1e ABLE FTS4XRTRIM. | 3824: 09 05 00 31 0f 19 45 4e 41 42 4c 45 20 44 42 53 ...1..ENABLE DBS | 3840: 54 41 54 20 56 54 41 42 58 42 49 4e 41 52 59 1e TAT VTABXBINARY. | 3856: 08 05 00 31 0f 19 45 4e 41 42 4c 45 20 44 42 53 ...1..ENABLE DBS | 3872: 54 41 54 20 56 54 41 42 58 4e 4f 43 41 53 45 1d TAT VTABXNOCASE. | 3888: 07 05 00 31 0f 17 45 4e 41 42 4c 45 20 44 42 53 ...1..ENABLE DBS | 3904: 54 41 54 20 56 54 41 42 58 52 54 52 49 4d 11 06 TAT VTABXRTRIM.. | 3920: 05 00 17 0f 19 44 45 42 55 47 58 42 49 4e 41 52 .....DEBUGXBINAR | 3936: 59 11 05 05 00 17 0f 19 44 45 42 55 47 58 4e 4f Y.......DEBUGXNO | 3952: 43 41 53 45 10 04 05 00 17 0f 17 44 45 42 55 47 CASE.......DEBUG | 3968: 58 52 54 52 49 4d 27 03 05 00 43 0f 19 43 4f 4d XRTRIM'...C..COM | 3984: 50 49 4c 45 52 3d 67 63 63 2d 35 2e 34 2e 30 20 PILER=gcc-5.4.0 | 4000: 32 30 31 36 30 36 30 39 58 42 49 4e 41 52 59 27 20160609XBINARY' | 4016: 02 05 00 43 0f 19 43 4f 4d 50 49 4c 45 52 3d 67 ...C..COMPILER=g | 4032: 63 63 2d 35 2e 34 2e 30 20 32 30 31 36 30 36 30 cc-5.4.0 2016060 | 4048: 39 58 4e 4f 43 41 53 45 26 01 05 00 43 0f 17 43 9XNOCASE&...C..C | 4064: 4f 4d 50 49 4c 45 52 3d 67 63 63 2d 35 2e 34 2e OMPILER=gcc-5.4. | 4080: 30 20 32 30 31 36 30 36 30 39 58 52 54 52 49 4d 0 20160609XRTRIM | page 4 offset 12288 | 0: 0d 00 00 00 00 10 00 00 00 00 00 00 00 00 00 00 ................ | page 5 offset 16384 | 0: 0d 00 00 00 02 0b a0 00 0c ad 0b a0 00 00 00 00 ................ | 2976: 82 0a 02 08 08 09 08 08 17 84 06 30 20 32 35 33 ...........0 253 | 2992: 00 01 30 04 25 06 1b 00 00 08 32 30 31 36 30 36 ..0.%.....201606 | 3008: 30 39 03 25 07 00 00 01 34 03 25 05 00 00 01 35 09.%....4.%....5 | 3024: 03 25 04 00 01 07 30 30 30 30 30 30 30 03 25 1a .%....0000000.%. | 3040: 00 00 08 63 6f 6d 70 69 6c 65 72 03 25 02 00 00 ...compiler.%... | 3056: 06 64 62 73 74 61 74 03 25 0a 00 01 04 65 62 75 .dbstat.%....ebu | 3072: 67 03 25 08 00 00 06 65 6e 61 62 6c 65 09 25 09 g.%....enable.%. | 3088: 05 04 04 04 04 04 00 01 08 78 74 65 6e 73 69 6f .........xtensio | 3104: 6e 03 25 1d 00 00 04 66 74 73 34 03 25 0d 00 03 n.%....fts4.%... | 3120: 01 35 03 25 0f 00 00 03 67 63 63 03 25 03 00 01 .5.%....gcc.%... | 3136: 06 65 6f 70 6f 6c 79 03 25 11 00 00 05 6a 73 6f .eopoly.%....jso | 3152: 6e 31 03 25 13 00 00 04 6c 6f 61 64 03 25 1c 00 n1.%....load.%.. | 3168: 00 03 6d 61 78 03 25 18 00 01 05 65 6d 6f 72 79 ..max.%....emory | 3184: 03 25 19 00 03 04 73 79 73 35 03 25 15 00 00 04 .%....sys5.%.... | 3200: 6f 6d 69 74 03 25 1b 00 00 05 72 74 72 65 65 03 omit.%....rtree. | 3216: 25 17 00 00 0a 74 68 72 65 61 64 73 61 66 65 03 %....threadsafe. | 3232: 25 1e 00 00 04 76 74 61 62 03 25 0b 00 86 50 01 %....vtab.%...P. | 3248: 08 08 08 08 09 17 8d 12 30 20 38 33 35 00 01 30 ........0 835..0 | 3264: 12 01 06 00 01 06 00 01 06 00 1f 03 00 01 03 00 ................ | 3280: 01 03 00 00 08 32 30 31 36 30 36 30 39 09 01 07 .....20160609... | 3296: 00 01 07 00 01 07 00 00 01 34 09 01 05 00 01 05 .........4...... | 3312: 00 01 05 00 00 01 35 09 01 04 00 01 04 00 01 04 ......5......... | 3328: 00 01 07 30 30 30 30 30 30 30 09 1c 04 00 01 04 ...0000000...... | 3344: 00 01 04 00 00 06 62 69 6e 61 72 79 3c 03 01 02 ......binary<... | 3360: 02 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 ................ | 3376: 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 00 ................ | 3392: 03 01 02 02 00 03 01 02 02 00 03 01 02 02 00 03 ................ | 3408: 01 02 02 00 03 01 02 02 00 00 08 63 6f 6d 70 69 ...........compi | 3424: 6c 65 72 09 01 02 00 01 02 00 01 02 00 00 06 64 ler............d | 3440: 62 73 74 61 74 09 07 03 00 01 03 00 01 03 00 01 bstat........... | 3456: 04 65 62 75 67 09 04 02 00 01 02 00 01 02 00 00 .ebug........... | 3472: 06 65 6e 61 62 6c 65 3f 07 02 00 01 02 00 01 02 .enable?........ | 3488: 00 01 02 00 01 02 00 01 02 00 01 02 00 01 02 00 ................ | 3504: 01 02 00 01 02 00 01 02 00 01 02 00 01 02 00 01 ................ | 3520: 02 00 01 02 00 01 02 00 01 02 00 01 02 00 01 02 ................ | 3536: 00 01 02 00 01 02 00 01 08 78 74 65 6e 73 69 6f .........xtensio | 3552: 6e 09 1f 04 00 01 04 00 01 04 00 00 04 66 74 73 n............fts | 3568: 34 09 0a 03 00 01 03 00 01 03 00 03 01 35 09 0d 4............5.. | 3584: 03 00 01 03 00 01 03 00 00 03 67 63 63 09 01 03 ..........gcc... | 3600: 00 01 03 00 01 03 00 01 06 65 6f 70 6f 6c 79 09 .........eopoly. | 3616: 10 03 00 01 03 00 01 03 00 00 05 6a 73 6f 6e 31 ...........json1 | 3632: 09 13 03 00 01 03 00 01 03 00 00 04 6c 6f 61 64 ............load | 3648: 09 1f 03 00 01 03 00 01 03 00 00 03 6d 61 78 09 ............max. | 3664: 1c 02 00 01 02 00 01 02 00 01 05 65 6d 6f 72 79 ...........emory | 3680: 09 1c 03 00 01 03 00 01 03 00 03 04 73 79 73 35 ............sys5 | 3696: 09 16 03 00 01 03 00 01 03 00 00 06 6e 6f 63 61 ............noca | 3712: 73 65 3c 02 01 02 02 00 03 01 02 02 00 03 01 02 se<............. | 3728: 02 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 ................ | 3744: 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 00 ................ | 3760: 03 01 02 02 00 03 01 02 02 00 03 01 02 02 00 00 ................ | 3776: 04 6f 6d 69 74 09 1f 02 00 01 02 00 01 02 00 00 .omit........... | 3792: 05 72 74 72 65 65 09 19 03 00 01 03 00 01 03 00 .rtree.......... | 3808: 03 02 69 6d 3c 01 01 02 02 00 03 01 02 02 00 03 ..im<........... | 3824: 01 02 02 00 03 01 02 02 00 03 01 02 02 00 03 01 ................ | 3840: 02 02 00 03 01 02 02 00 03 01 02 02 00 03 01 02 ................ | 3856: 02 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 ................ | 3872: 00 00 0a 74 68 72 65 61 64 73 61 66 65 09 22 02 ...threadsafe... | 3888: 00 01 02 00 02 02 00 00 04 76 74 61 62 09 07 04 .........vtab... | 3904: 00 01 04 00 01 04 00 00 01 78 b4 01 01 01 01 02 .........x...... | 3920: 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 ................ | 3936: 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 01 ................ | 3952: 01 01 02 00 01 01 01 02 00 01 01 01 02 00 01 01 ................ | 3968: 01 02 00 01 01 01 02 00 01 01 01 02 00 01 01 01 ................ | 3984: 02 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 ................ | 4000: 10 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 ................ | 4016: 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 01 ................ | 4032: 01 01 02 00 01 01 01 02 00 01 01 01 02 00 01 01 ................ | 4048: 01 02 00 01 01 01 02 00 01 01 01 02 00 01 01 01 ................ | 4064: 02 00 01 01 02 02 00 01 01 01 02 00 01 01 01 02 ................ | 4080: 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 ................ | page 6 offset 20480 | 0: 0a 00 00 00 02 0f f5 00 0f fb 0f f5 00 00 00 00 ................ | 4080: 00 00 00 00 00 05 04 08 09 01 02 04 04 08 08 09 ................ | page 7 offset 24576 | 0: 0d 00 00 00 05 0f b8 00 0f f4 0f e9 0f d6 0f c7 ................ | 16: 0f b8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ | 4016: 00 00 00 00 00 00 00 00 0d 05 02 23 61 75 74 6f ...........#auto | 4032: 6d 65 72 67 65 3d 35 0d 04 02 23 6d 65 72 67 65 merge=5...#merge | 4048: 3d 31 30 30 2c 38 11 03 02 2b 69 6e 74 65 67 72 =100,8...+integr | 4064: 69 74 79 2d 63 68 65 63 6b 09 02 02 1b 72 65 62 ity-check....reb | 4080: 75 69 6c 64 0a 01 02 1d 6f 70 74 69 6d 69 7a 65 uild....optimize | end crash-c3a971f0061039.db }]} {} do_catchsql_test 10.1 { WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<100) INSERT OR IGNORE INTO t1(a,c) SELECT x,null FROM c UNION ALL SELECT 180-x,printf('[%,d]',x*-5844627) FROM c; } {0 {}} do_catchsql_test 10.3 { INSERT INTO t1(t1) VALUES('optimize'); } {1 {database disk image is malformed}} #------------------------------------------------------------------------- reset_db do_test 11.0 { sqlite3 db {} db deserialize [decode_hexdb { | size 28672 pagesize 4096 filename crash-843cb8447eaf14.db | page 1 offset 0 | 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3. | 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 07 .....@ ........ | 32: 00 00 00 02 00 00 00 01 00 00 00 07 00 00 00 04 ................ | 48: 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 ................ | 96: 00 00 00 00 0d 0e b1 00 06 0d a4 00 0f 8d 0f 21 ...............! | 112: 0e b9 0d c8 0e 7e 0d a4 0d a4 00 00 00 00 00 00 .....~.......... | 3488: 00 00 00 00 22 07 06 17 11 11 01 31 74 61 62 6c ...........1tabl | 3504: 65 74 32 74 32 07 43 52 45 41 54 45 20 54 41 42 et2t2.CREATE TAB | 3520: 4c 45 20 74 32 28 78 29 81 33 05 07 17 1f 1f 01 LE t2(x).3...... | 3536: 82 35 74 61 62 6c 65 74 31 5f 73 65 67 64 69 72 .5tablet1_segdir | 3552: 74 31 5f 73 65 67 64 69 72 05 43 52 45 41 54 45 t1_segdir.CREATE | 3568: 20 54 41 42 4c 45 20 27 74 31 5f 73 65 67 64 69 TABLE 't1_segdi | 3584: 72 27 28 6c 65 76 65 6c 20 49 4e 54 45 47 45 52 r'(level INTEGER | 3600: 2c 69 64 78 20 49 4e 54 45 47 45 52 2c 73 74 61 ,idx INTEGER,sta | 3616: 72 74 5f 62 6c 6f 63 6b 20 49 4e 54 45 47 45 52 rt_block INTEGER | 3632: 2c 6c 65 61 76 65 73 5f 65 6e 64 5f 62 6c 6f 63 ,leaves_end_bloc | 3648: 6b 20 49 4e 54 45 47 45 52 2c 65 6e 64 5f 62 6c k INTEGER,end_bl | 3664: 6f 63 6b 20 49 4e 54 45 47 45 52 2c 72 6f 6f 74 ock INTEGER,root | 3680: 20 42 4c 4f 42 2c 50 52 49 4d 41 52 59 20 4b 45 BLOB,PRIMARY KE | 3696: 59 28 6c 65 76 65 6c 2c 20 69 64 78 29 29 31 06 Y(level, idx))1. | 3712: 06 17 45 1f 01 00 69 6e 64 65 78 73 71 6c 69 74 ..E...indexsqlit | 3728: 65 5f 61 75 74 6f 69 6e 64 65 78 5f 74 31 5f 73 e_autoindex_t1_s | 3744: 65 67 64 69 72 5f 31 74 31 5f 73 65 67 64 69 72 egdir_1t1_segdir | 3760: 06 0f c7 00 08 00 00 00 00 66 04 07 17 23 23 01 .........f...##. | 3776: 81 13 74 61 62 6c 65 74 31 5f 73 65 67 6d 65 6e ..tablet1_segmen | 3792: 74 73 74 31 5f 73 65 67 6d 65 6e 74 73 04 43 52 tst1_segments.CR | 3808: 45 41 54 45 20 54 41 42 4c 45 20 27 74 31 5f 73 EATE TABLE 't1_s | 3824: 65 67 6d 65 6e 74 73 27 28 62 6c 6f 63 6b 69 64 egments'(blockid | 3840: 20 49 4e 54 45 47 45 52 20 50 52 49 4d 41 52 59 INTEGER PRIMARY | 3856: 20 4b 45 59 2c 20 62 6c 6f 63 6b 20 42 4c 4f 42 KEY, block BLOB | 3872: 29 6a 03 07 17 21 21 01 81 1f 74 61 62 6c 65 74 )j...!!...tablet | 3888: 31 5f 63 6f 6e 74 65 6e 74 74 31 5f 63 6f 6e 74 1_contentt1_cont | 3904: 65 6e 74 03 43 52 45 41 54 45 20 54 41 42 4c 45 ent.CREATE TABLE | 3920: 20 27 74 31 5f 63 6f 6e 74 65 6e 74 27 28 64 6f 't1_content'(do | 3936: 63 69 64 20 49 4e 54 45 47 45 52 20 50 52 49 4d cid INTEGER PRIM | 3952: 41 52 59 20 4b 45 59 2c 20 27 63 30 61 27 2c 20 ARY KEY, 'c0a', | 3968: 27 63 31 62 27 2c 20 27 63 32 63 27 29 38 02 06 'c1b', 'c2c')8.. | 3984: 17 11 11 08 5f 74 61 62 6c 65 74 31 74 31 43 52 ...._tablet1t1CR | 4000: 45 41 54 45 20 56 49 52 54 55 41 4c 20 54 41 42 EATE VIRTUAL TAB | 4016: 4c 45 20 74 31 20 55 53 49 4e 47 20 66 74 73 33 LE t1 USING fts3 | 4032: 28 61 2c 62 2c 63 29 00 00 00 39 00 00 00 00 00 (a,b,c)...9..... | page 3 offset 8192 | 0: 0d 00 00 00 25 0b 48 00 0f d8 0f af 0f 86 0f 74 ....%.H........t | 16: 0f 61 0f 4e 0f 2f 0f 0f 0e ef 0e d7 0e be 0e a5 .a.N./.......... | 32: 0e 8d 0e 74 0e 5b 0e 40 0e 24 0e 08 0d ef 0d d4 ...t.[.@.$...... | 48: dd bb 0d a0 0d 84 0d 68 0d 4f 0d 35 0d 1b 0c fb .......h.O.5.... | 64: 0c da 0c b9 35 99 0c 78 0c 57 0c 3e 0c 24 0c 0a ....5..x.W.>.$.. | 80: 0b 48 00 00 00 00 00 00 00 00 00 00 00 00 00 00 .H.............. | 2880: 00 00 00 00 00 00 00 00 81 3f 25 06 00 82 7f 00 .........?%..... | 2896: 00 43 4f 4d 50 49 4c 45 52 3d 67 63 63 2d 35 2e .COMPILER=gcc-5. | 2912: 34 2e 30 20 32 30 31 36 30 36 30 39 20 44 45 42 4.0 20160609 DEB | 2928: 55 47 20 45 4e 41 42 4c 45 20 44 42 53 54 41 54 UG ENABLE DBSTAT | 2944: 20 56 54 41 42 20 45 4e 41 42 4c 45 20 46 54 53 VTAB ENABLE FTS | 2960: 34 20 45 4e 41 42 4c 45 20 46 54 53 35 20 45 4e 4 ENABLE FTS5 EN | 2976: 41 42 4c 45 20 47 45 4f 50 4f 4c 59 20 45 4e 41 ABLE GEOPOLY ENA | 2992: 42 4c 45 20 4a 53 4f 4e 31 20 45 4e 41 42 4c 45 BLE JSON1 ENABLE | 3008: 20 4d 45 4d 53 59 53 35 20 45 4e 41 42 4c 45 20 MEMSYS5 ENABLE | 3024: 52 54 52 45 45 20 4d 41 58 20 4d 45 4d 4f 52 59 RTREE MAX MEMORY | 3040: 3d 35 30 30 30 30 30 30 30 20 4f 4d 49 54 20 4c =50000000 OMIT L | 3056: 4f 41 44 20 45 58 54 45 4e 53 49 4f 4e 20 54 48 OAD EXTENSION TH | 3072: 52 45 41 44 53 41 46 45 3d 30 18 24 05 00 25 0f READSAFE=0.$..%. | 3088: 19 54 48 52 45 41 44 53 41 46 45 3d 30 58 42 49 .THREADSAFE=0XBI | 3104: 4e 41 52 59 18 23 05 00 25 0f 19 54 48 52 45 41 NARY.#..%..THREA | 3120: 44 53 41 46 45 3d 30 58 4e 4f 43 41 53 45 17 22 DSAFE=0XNOCASE.. | 3136: 05 00 25 0f 17 54 48 52 45 41 44 53 41 46 45 3d ..%..THREADSAFE= | 3152: 30 58 52 54 52 49 4d 1f 21 05 00 33 0f 19 4f 4d 0XRTRIM.!..3..OM | 3168: 49 54 20 4c 4f 41 44 20 45 58 54 45 4e 53 49 4f IT LOAD EXTENSIO | 3184: 4e 58 42 49 4e 41 52 59 1f 20 05 00 33 0f 19 4f NXBINARY. ..3..O | 3200: 4d 49 54 20 4c 4f 41 44 20 45 58 54 45 4e 53 49 MIT LOAD EXTENSI | 3216: 4f 4e 58 4e 4f 43 41 53 45 1e 1f 05 00 33 0f 17 ONXNOCASE....3.. | 3232: 4f 4d 49 54 20 4c 4f 41 44 20 45 58 54 45 4e 53 OMIT LOAD EXTENS | 3248: 49 4f 4e 58 52 54 52 49 4d 1f 1e 05 00 33 0f 19 IONXRTRIM....3.. | 3264: 4d 41 58 20 4d 45 4d 4f 52 59 3d 35 30 30 30 30 MAX MEMORY=50000 | 3280: 30 30 30 58 42 49 4e 41 52 59 1f 1d 05 00 33 0f 000XBINARY....3. | 3296: 19 4d 41 58 20 4d 45 4d 4f 52 59 3d 35 30 30 30 .MAX MEMORY=5000 | 3312: 30 30 30 30 58 4e 4f 43 41 53 45 1e 1c 05 00 33 0000XNOCASE....3 | 3328: 0f 17 4d 41 58 20 4d 45 4d 4f 52 59 3d 35 30 30 ..MAX MEMORY=500 | 3344: 30 30 30 30 30 58 52 54 52 49 4d 18 1b 05 00 25 00000XRTRIM....% | 3360: 0f 19 45 4e 41 42 4c 45 20 52 54 52 45 45 58 42 ..ENABLE RTREEXB | 3376: 49 4e 41 52 59 18 1a 05 00 25 0f 19 45 4e 41 42 INARY....%..ENAB | 3392: 4c 45 20 52 54 52 45 45 58 4e 4f 43 41 53 45 17 LE RTREEXNOCASE. | 3408: 19 05 00 25 0f 17 45 4e 41 42 4c 45 20 52 54 52 ...%..ENABLE RTR | 3424: 45 45 58 52 54 52 49 4d 1a 18 05 00 29 0f 19 45 EEXRTRIM....)..E | 3440: 4e 41 42 4c 45 20 4d 45 4d 53 59 53 35 58 42 49 NABLE MEMSYS5XBI | 3456: 4e 41 52 59 1a 17 05 00 29 0f 19 45 4e 41 42 4c NARY....)..ENABL | 3472: 45 20 4d 45 4d 53 59 53 35 58 4e 4f 43 41 53 45 E MEMSYS5XNOCASE | 3488: 19 16 05 00 29 0f 17 45 4e 41 42 4c 45 20 4d 45 ....)..ENABLE ME | 3504: 4d 53 59 53 35 58 52 54 52 49 4d 18 15 05 00 25 MSYS5XRTRIM....% | 3520: 0f 19 45 4e 41 42 4c 45 20 4a 53 4f 4e 31 58 42 ..ENABLE JSON1XB | 3536: 49 4e 41 52 59 18 14 05 00 25 0f 19 45 4e 41 42 INARY....%..ENAB | 3552: 4c 45 20 4a 53 4f 4e 31 58 4e 4f 43 41 53 45 17 LE JSON1XNOCASE. | 3568: 13 05 00 25 0f 17 45 4e 41 42 4c 45 20 4a 53 4f ...%..ENABLE JSO | 3584: 4e 31 58 52 54 52 49 4d 1a 12 05 00 29 0f 19 45 N1XRTRIM....)..E | 3600: 4e 41 42 4c 45 20 47 45 4f 50 4f 4c 59 58 42 49 NABLE GEOPOLYXBI | 3616: 4e 41 52 59 1a 11 05 00 29 0f 19 45 4e 41 42 4c NARY....)..ENABL | 3632: 45 20 47 45 4f 50 4f 4c 59 58 4e 4f 43 41 53 45 E GEOPOLYXNOCASE | 3648: 19 10 05 00 29 0f 17 45 4e 41 42 4c 45 20 47 45 ....)..ENABLE GE | 3664: 4f 50 4f 4c 59 58 52 54 52 49 4d 17 0f 05 00 23 OPOLYXRTRIM....# | 3680: 0f 19 45 4e 41 42 4c 45 20 46 54 53 35 58 42 49 ..ENABLE FTS5XBI | 3696: 4e 41 52 59 17 0e 05 00 23 0f 19 45 4e 41 42 4c NARY....#..ENABL | 3712: 45 20 46 54 53 35 58 4e 4f 43 41 53 45 16 0d 05 E FTS5XNOCASE... | 3728: 00 23 0f 17 45 4e 41 42 4c 45 20 46 54 53 35 58 .#..ENABLE FTS5X | 3744: 52 54 52 49 4d 17 0c 05 00 23 0f 19 45 4e 41 42 RTRIM....#..ENAB | 3760: 4c 45 20 46 54 53 34 58 42 49 4e 41 52 59 17 0b LE FTS4XBINARY.. | 3776: 05 00 23 0f 19 45 4e 41 42 4c 45 20 46 54 53 34 ..#..ENABLE FTS4 | 3792: 58 4e 4f 43 41 53 45 16 0a 05 00 23 0f 17 45 4e XNOCASE....#..EN | 3808: 41 42 4c 45 20 46 54 53 34 58 52 54 52 49 4d 1e ABLE FTS4XRTRIM. | 3824: 09 05 00 31 0f 19 45 4e 41 42 4c 45 20 44 42 53 ...1..ENABLE DBS | 3840: 54 41 54 20 56 54 41 42 58 42 49 4e 41 52 59 1e TAT VTABXBINARY. | 3856: 08 05 00 31 0f 19 45 4e 41 42 4c 45 20 44 42 53 ...1..ENABLE DBS | 3872: 54 41 54 20 56 54 41 42 58 4e 4f 43 41 53 45 1d TAT VTABXNOCASE. | 3888: 07 05 00 31 0f 17 45 4e 41 42 4c 45 20 44 42 53 ...1..ENABLE DBS | 3904: 54 41 54 20 56 54 41 42 58 52 54 52 49 4d 11 06 TAT VTABXRTRIM.. | 3920: 05 00 17 0f 19 44 45 42 55 47 58 42 49 4e 41 52 .....DEBUGXBINAR | 3936: 59 11 05 05 00 17 0f 19 44 45 42 55 47 58 4e 4f Y.......DEBUGXNO | 3952: 43 41 53 45 10 04 05 00 17 0f 17 44 45 42 55 47 CASE.......DEBUG | 3968: 58 52 54 52 49 4d 27 03 05 00 43 0f 19 43 4f 4d XRTRIM'...C..COM | 3984: 50 49 4c 45 52 3d 67 63 63 2d 35 2e 34 2e 30 20 PILER=gcc-5.4.0 | 4000: 32 30 31 36 30 36 30 39 58 42 49 4e 41 52 59 27 20160609XBINARY' | 4016: 02 05 00 43 0f 19 43 4f 4d 50 49 4c 45 52 3d 67 ...C..COMPILER=g | 4032: 63 63 2d 35 2e 34 2e 30 20 32 30 31 36 30 36 30 cc-5.4.0 2016060 | 4048: 39 58 4e 4f 43 41 53 45 26 01 05 00 43 0f 17 43 9XNOCASE&...C..C | 4064: 4f 4d 50 49 4c 45 52 3d 67 63 63 2d 35 2e 34 2e OMPILER=gcc-5.4. | 4080: 30 20 32 30 31 36 30 36 30 39 58 52 54 52 49 4d 0 20160609XRTRIM | page 4 offset 12288 | 0: 0d 00 00 00 00 10 00 00 00 00 00 00 00 00 00 00 ................ | page 5 offset 16384 | 0: 0d 00 00 00 02 0b a0 00 0c ad 0b a0 00 00 00 00 ................ | 2976: 82 0a 02 08 08 09 08 08 17 84 06 30 20 32 35 33 ...........0 253 | 2992: 00 01 30 04 25 06 1b 00 00 08 32 30 31 36 30 36 ..0.%.....201606 | 3008: 30 39 03 25 07 00 00 01 34 03 25 05 00 00 01 35 09.%....4.%....5 | 3024: 03 25 04 00 01 07 30 30 30 30 30 30 30 03 25 1a .%....0000000.%. | 3040: 00 00 08 63 6f 6d 70 69 6c 65 72 03 25 02 00 00 ...compiler.%... | 3056: 06 64 62 73 74 61 74 03 25 0a 00 01 04 65 62 75 .dbstat.%....ebu | 3072: 67 03 25 08 00 00 06 65 6e 61 62 6c 65 09 25 09 g.%....enable.%. | 3088: 05 04 04 04 04 04 00 01 08 78 74 65 6e 73 69 6f .........xtensio | 3104: 6e 03 25 1d 00 00 04 66 74 73 34 03 25 0d 00 03 n.%....fts4.%... | 3120: 01 35 03 25 0f 00 00 03 67 63 63 03 25 03 00 01 .5.%....gcc.%... | 3136: 06 65 6f 70 6f 6c 79 03 25 11 00 00 05 6a 73 6f .eopoly.%....jso | 3152: 6e 31 03 25 13 00 00 04 6c 6f 61 64 03 25 1c 00 n1.%....load.%.. | 3168: 00 03 6d 61 78 03 25 18 00 01 05 65 6d 6f 72 79 ..max.%....emory | 3184: 03 25 19 00 03 04 73 79 73 35 03 25 15 00 00 04 .%....sys5.%.... | 3200: 6f 6d 69 74 03 25 1b 00 00 05 72 74 72 65 65 03 omit.%....rtree. | 3216: 25 17 00 00 0a 74 68 72 65 61 64 73 61 66 65 03 %....threadsafe. | 3232: 25 1e 00 00 04 76 74 61 62 03 25 0b 00 86 50 01 %....vtab.%...P. | 3248: 08 08 08 08 08 17 8d 12 30 20 38 33 35 00 01 30 ........0 835..0 | 3264: 12 01 06 00 01 06 00 01 06 00 1f 03 00 01 03 00 ................ | 3280: 01 03 00 00 08 32 30 31 36 30 36 30 39 09 01 07 .....20160609... | 3296: 00 01 07 00 01 07 00 00 01 34 09 01 05 00 01 05 .........4...... | 3312: 00 01 05 00 00 01 35 09 01 04 00 01 04 00 01 04 ......5......... | 3328: 00 01 07 30 30 30 30 30 30 30 09 1c 04 00 01 04 ...0000000...... | 3344: 00 01 04 00 00 06 62 69 6e 61 72 79 3c 03 01 02 ......binary<... | 3360: 02 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 ................ | 3376: 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 00 ................ | 3392: 03 01 02 02 00 03 01 02 02 00 03 01 02 02 00 03 ................ | 3408: 01 02 02 00 03 01 02 02 00 00 08 63 6f 6d 70 69 ...........compi | 3424: 6c 65 72 09 01 02 00 01 02 00 01 02 00 00 06 64 ler............d | 3440: 62 73 74 61 74 09 07 03 00 01 03 00 01 03 00 01 bstat........... | 3456: 04 65 62 75 67 09 04 02 00 01 02 00 01 02 00 00 .ebug........... | 3472: 06 65 6e 61 62 6c 65 3f 07 02 00 01 02 00 01 02 .enable?........ | 3488: 00 01 02 00 01 02 00 01 02 00 01 02 00 01 02 00 ................ | 3504: 01 02 00 01 02 00 01 02 00 01 02 00 01 01 00 01 ................ | 3520: 02 00 01 02 00 01 02 00 01 02 00 01 02 00 01 02 ................ | 3536: 00 01 02 00 01 02 00 01 08 78 74 65 6e 73 69 6f .........xtensio | 3552: 6e 09 1f 04 00 01 04 00 01 04 00 00 04 66 74 73 n............fts | 3568: 34 09 0a 03 00 01 03 00 01 03 00 03 01 35 09 0d 4............5.. | 3584: 03 00 01 03 00 01 03 00 00 03 67 63 63 09 01 03 ..........gcc... | 3600: 00 01 03 00 01 03 00 01 06 65 6f 70 6f 6c 79 09 .........eopoly. | 3616: 10 03 00 01 03 00 01 03 00 00 05 6a 73 6f 6e 31 ...........json1 | 3632: 09 13 03 00 01 03 00 01 03 00 00 04 6c 6f 61 64 ............load | 3648: 09 1f 03 00 01 03 00 01 03 00 00 03 6d 61 78 09 ............max. | 3664: 1c 02 00 01 02 00 01 02 00 01 05 65 6d 6f 72 79 ...........emory | 3680: 09 1c 03 00 01 03 00 01 03 00 03 04 73 79 73 35 ............sys5 | 3696: 09 16 03 00 01 03 00 01 03 00 00 06 6e 6f 63 61 ............noca | 3712: 73 65 3c 02 01 02 02 00 03 01 02 02 00 03 01 02 se<............. | 3728: 02 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 ................ | 3744: 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 00 ................ | 3760: 03 01 02 02 00 03 01 02 02 00 03 01 02 02 00 00 ................ | 3776: 04 6f 6d 69 74 09 1f 02 00 01 02 00 01 02 00 00 .omit........... | 3792: 05 72 74 72 65 65 09 19 03 00 01 03 00 01 03 00 .rtree.......... | 3808: 03 02 69 6d 3c 01 01 02 02 00 03 01 02 02 00 03 ..im<........... | 3824: 01 02 02 00 03 01 02 02 00 03 01 02 02 00 03 01 ................ | 3840: 02 02 00 03 01 02 02 00 03 01 a2 02 00 03 01 02 ................ | 3856: 02 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 ................ | 3872: 00 00 0a 74 68 72 65 61 64 73 61 66 65 09 22 02 ...threadsafe... | 3888: 00 01 02 00 01 02 00 00 04 76 74 61 62 09 07 04 .........vtab... | 3904: 00 01 04 00 01 04 00 00 01 78 b4 01 01 01 01 02 .........x...... | 3920: 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 ................ | 3936: 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 01 ................ | 3952: 01 01 02 00 01 01 01 02 00 01 01 01 02 00 01 01 ................ | 3968: 01 02 00 01 01 01 02 00 01 01 01 02 00 01 01 01 ................ | 3984: 02 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 ................ | 4000: 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 ................ | 4016: 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 01 ................ | 4032: 01 01 02 00 01 01 01 02 00 01 01 01 02 00 01 01 ................ | 4048: 01 02 00 01 01 01 02 00 01 01 01 02 00 01 01 01 ................ | 4064: 02 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 ................ | 4080: 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 ................ | page 6 offset 20480 | 0: 0a 00 00 00 02 0f f5 00 0f fb 0f f5 00 00 00 00 ................ | 4080: 00 00 00 00 00 05 04 08 09 01 02 04 04 08 08 09 ................ | page 7 offset 24576 | 0: 0d 00 00 00 05 0f b8 00 0f f4 0f e9 0f d6 0f c7 ................ | 16: 0f b8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ | 4016: 00 00 00 00 00 00 00 00 0d 05 02 23 61 75 74 6f ...........#auto | 4032: 6d 65 72 67 65 3d 35 0d 04 02 23 6d 65 72 67 65 merge=5...#merge | 4048: 3d 31 30 30 2c 38 11 03 02 2b 69 6e 74 65 67 72 =100,8...+integr | 4064: 69 74 79 2d 63 68 65 63 6b 09 02 02 1b 72 65 62 ity-check....reb | 4080: 75 69 6c 64 0a 01 02 1d 6f 70 74 69 6d 69 7a 65 uild....optimize | end crash-843cb8447eaf14.db }]} {} do_catchsql_test 11.1 { SELECT rowid, quote(matchinfo(t1,'pcxybs')) FROM t1 WHERE t1 MATCH 'e*' } {1 {database disk image is malformed}} #------------------------------------------------------------------------- reset_db do_test 12.0 { sqlite3 db {} db deserialize [decode_hexdb { | size 28672 pagesize 4096 filename c81b.db | page 1 offset 0 | 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3. | 16: 10 00 01 01 00 40 20 20 00 00 00 01 00 00 00 07 .....@ ........ | 32: 00 00 00 02 00 00 00 01 00 00 00 01 00 00 00 04 ................ | 48: 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 ................ | 80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 ................ | 96: 00 2e 30 38 0d 0e b1 00 06 0d a4 00 0f 8d 0f 21 ..08...........! | 112: 0e b9 0d c8 0e 7e 0d a4 0d a4 00 00 00 00 00 00 .....~.......... | 3488: 00 00 00 00 22 07 06 17 11 11 01 31 74 61 62 6c ...........1tabl | 3504: 65 74 32 74 32 07 43 52 45 41 54 45 20 54 41 42 et2t2.CREATE TAB | 3520: 4c 45 20 74 32 28 78 29 81 33 05 07 17 1f 1f 01 LE t2(x).3...... | 3536: 82 35 74 61 62 6c 65 74 31 5f 73 65 67 64 69 72 .5tablet1_segdir | 3552: 74 31 5f 73 65 67 64 69 72 05 43 52 45 41 54 45 t1_segdir.CREATE | 3568: 20 54 41 42 4c 45 20 27 74 31 5f 73 65 67 64 69 TABLE 't1_segdi | 3584: 72 27 28 6c 65 76 65 6c 20 49 4e 54 45 47 45 52 r'(level INTEGER | 3600: 2c 69 64 78 20 49 4e 54 45 47 45 52 2c 73 74 61 ,idx INTEGER,sta | 3616: 72 74 5f 62 6c 6f 63 6b 20 49 4e 54 45 47 45 52 rt_block INTEGER | 3632: 2c 6c 65 61 76 65 73 5f 65 6e 64 5f 62 6c 6f 63 ,leaves_end_bloc | 3648: 6b 20 49 4e 54 45 47 45 52 2c 65 6e 64 5f 62 6c k INTEGER,end_bl | 3664: 6f 63 6b 20 49 4e 54 45 47 45 62 2c 72 6f 6f 74 ock INTEGEb,root | 3680: 20 42 4c 4f 42 2c 50 52 49 4d 41 52 59 20 4b 45 BLOB,PRIMARY KE | 3696: 59 28 6c 65 76 65 6c 2c 20 69 64 78 29 29 31 06 Y(level, idx))1. | 3712: 06 17 45 1f 01 00 69 6e 64 65 78 73 71 6c 69 74 ..E...indexsqlit | 3728: 65 5f 61 75 74 6f 69 6e 64 65 78 5f 74 31 5f 73 e_autoindex_t1_s | 3744: 65 67 64 69 72 5f 31 74 31 5f 73 65 67 64 69 72 egdir_1t1_segdir | 3760: 06 0f c7 00 08 00 00 00 00 66 04 07 17 23 23 01 .........f...##. | 3776: 81 13 74 61 62 6c 65 74 31 5f 73 65 67 6d 65 6e ..tablet1_segmen | 3792: 74 73 74 31 5f 73 65 67 6d 65 6e 74 73 04 43 52 tst1_segments.CR | 3808: 45 41 54 45 20 54 41 42 4c 45 20 27 74 31 5f 73 EATE TABLE 't1_s | 3824: 65 67 6d 65 6e 74 73 27 28 62 6c 6f 63 6b 69 64 egments'(blockid | 3840: 20 49 4e 54 45 47 45 52 20 50 52 49 4d 41 52 59 INTEGER PRIMARY | 3856: 20 4b 45 59 2c 20 62 6c 6f 63 6b 20 42 4c 4f 42 KEY, block BLOB | 3872: 29 6a 03 07 17 21 21 01 81 1f 74 61 62 6c 65 74 )j...!!...tablet | 3888: 31 5f 63 6f 6e 74 65 6e 74 74 31 5f 63 6f 6e 74 1_contentt1_cont | 3904: 65 6e 74 03 43 52 45 41 54 45 20 54 41 42 4c 45 ent.CREATE TABLE | 3920: 20 27 74 31 5f 63 6f 6e 74 65 6e 74 27 28 64 6f 't1_content'(do | 3936: 63 69 64 20 49 4e 54 45 47 45 52 20 50 52 49 4d cid INTEGER PRIM | 3952: 41 52 59 20 4b 45 59 2c 20 27 63 30 61 27 2c 20 ARY KEY, 'c0a', | 3968: 27 63 31 62 27 2c 20 27 63 32 63 27 29 38 02 06 'c1b', 'c2c')8.. | 3984: 17 11 11 08 5f 74 61 62 6c 65 74 31 74 31 43 52 ...._tablet1t1CR | 4000: 45 41 54 45 20 56 49 52 54 55 41 4c 20 54 41 42 EATE VIRTUAL TAB | 4016: 4c 45 20 74 31 20 55 53 49 4e 47 20 66 74 73 33 LE t1 USING fts3 | 4032: 28 61 2c 62 2c 63 29 00 00 00 39 00 00 00 00 00 (a,b,c)...9..... | page 3 offset 8192 | 0: 0d 00 00 00 25 0b 48 00 0f d8 0f af 0f 86 0f 74 ....%.H........t | 16: 0f 61 0f 4e 0f 2f 0f 0f 0e ef 0e d7 0e be 0e a5 .a.N./.......... | 32: 0e 8d 0e 74 0e 5b 0e 40 0e 24 0e 08 0d ef 0d d5 ...t.[.@.$...... | 48: 0d bb 0d a0 0d 84 0d 68 0d 4f 0d 35 0d 1b 0c fb .......h.O.5.... | 64: 0c da 0c b9 0c 99 0c 78 0c 57 0c 3e 0c 24 0c 0a .......x.W.>.$.. | 80: 0b 48 00 00 00 00 00 00 00 00 00 00 00 00 00 00 .H.............. | 2880: 00 00 00 00 00 00 00 00 81 3f 25 06 00 82 7f 00 .........?%..... | 2896: 00 43 4f 4d 50 49 4c 45 52 3d 67 63 63 2d 35 2e .COMPILER=gcc-5. | 2912: 34 2e 30 20 32 30 31 36 30 36 30 39 20 44 45 42 4.0 20160609 DEB | 2928: 55 47 20 45 4e 41 42 4c 45 20 44 42 53 54 41 54 UG ENABLE DBSTAT | 2944: 20 56 54 41 42 20 45 4e 41 42 4c 45 20 46 54 53 VTAB ENABLE FTS | 2960: 34 20 45 4e 41 42 4c 45 20 46 54 53 35 20 45 4e 4 ENABLE FTS5 EN | 2976: 41 42 4c 45 20 47 45 4f 50 4f 4c 59 20 46 4e 41 ABLE GEOPOLY FNA | 2992: 42 4c 45 20 4a 53 4f 4e 31 20 45 4e 41 42 4c 45 BLE JSON1 ENABLE | 3008: 20 4d 45 4d 53 59 53 35 20 45 4e 41 42 4c 45 20 MEMSYS5 ENABLE | 3024: 52 54 52 45 45 20 4d 41 58 20 4d 45 4d 4f 52 59 RTREE MAX MEMORY | 3040: 3d 35 30 30 30 30 30 30 30 20 4f 4d 49 54 20 4c =50000000 OMIT L | 3056: 4f 41 44 20 45 58 54 45 4e 53 49 4f 4e 20 54 48 OAD EXTENSION TH | 3072: 52 45 41 44 53 41 46 45 3d 30 18 24 05 00 0f 25 READSAFE=0.$...% | 3088: 19 58 54 48 52 45 41 44 53 41 46 45 3d 30 42 49 .XTHREADSAFE=0BI | 3104: 4e 41 52 59 18 23 05 00 0f 25 19 58 54 48 52 45 NARY.#...%.XTHRE | 3120: 41 44 53 41 46 45 3d 30 4e 4f 43 41 53 45 17 22 ADSAFE=0NOCASE.. | 3136: 05 00 0f 25 17 58 54 48 52 45 41 44 53 41 46 45 ...%.XTHREADSAFE | 3152: 3d 30 52 54 52 49 4d 1f 21 05 00 0f 33 19 58 4f =0RTRIM.!...3.XO | 3168: 4d 49 54 20 4c 4f 41 44 20 45 58 54 45 4e 53 49 MIT LOAD EXTENSI | 3184: 4f 4e 42 49 4e 41 52 59 1f 20 05 00 0f 33 19 58 ONBINARY. ...3.X | 3200: 4f 4d 49 54 20 4c 4f 41 44 20 45 58 54 45 4e 53 OMIT LOAD EXTENS | 3216: 49 4f 4e 4e 4f 43 41 53 45 1e 1f 05 00 0f 33 17 IONNOCASE.....3. | 3232: 58 4f 4d 49 54 20 4c 4f 41 44 20 45 58 54 45 4e XOMIT LOAD EXTEN | 3248: 53 49 4f 4e 52 54 52 49 4d 1f 1e 05 00 0f 33 19 SIONRTRIM.....3. | 3264: 58 4d 41 58 20 4d 45 4d 4f 52 59 3d 35 30 30 30 XMAX MEMORY=5000 | 3280: 30 30 30 30 42 49 4e 41 52 59 1f 1d 05 00 0f 33 0000BINARY.....3 | 3296: 19 58 4d 41 58 20 4d 45 4d 4f 52 59 3d 35 30 30 .XMAX MEMORY=500 | 3312: 30 30 30 30 30 4e 4f 43 41 53 45 1e 1c 05 00 0f 00000NOCASE..... | 3328: 33 17 58 4d 41 58 20 4d 45 4d 4f 52 59 3d 35 30 3.XMAX MEMORY=50 | 3344: 30 30 30 30 30 30 52 54 52 49 4d 18 1b 05 00 0f 000000RTRIM..... | 3360: 25 19 58 45 4e 41 42 4c 45 20 52 54 52 45 45 42 %.XENABLE RTREEB | 3376: 49 4e 41 52 59 18 1a 05 00 0f 25 19 58 45 4e 41 INARY.....%.XENA | 3392: 42 4c 45 20 52 54 52 45 45 4e 4f 43 41 53 45 17 BLE RTREENOCASE. | 3408: 19 05 00 0f 25 17 58 45 4e 41 42 4c 45 20 52 54 ....%.XENABLE RT | 3424: 52 45 45 52 54 52 49 4d 1a 18 05 00 0f 29 19 58 REERTRIM.....).X | 3440: 45 4e 41 42 4c 45 20 4d 45 4d 53 59 53 35 42 49 ENABLE MEMSYS5BI | 3456: 4e 41 52 59 1a 17 05 00 0f 29 19 58 45 4e 41 42 NARY.....).XENAB | 3472: 4c 45 20 4d 45 4d 53 59 53 35 4e 4f 43 41 53 45 LE MEMSYS5NOCASE | 3488: 19 16 05 00 0f 29 17 58 45 4e 41 42 4c 45 20 4d .....).XENABLE M | 3504: 45 4d 53 59 53 35 52 54 52 49 4d 18 15 05 00 0f EMSYS5RTRIM..... | 3520: 25 19 58 45 4e 41 42 4c 45 20 4a 53 4f 4e 31 42 %.XENABLE JSON1B | 3536: 49 4e 41 52 59 18 14 05 00 0f 25 19 58 45 4e 41 INARY.....%.XENA | 3552: 42 4c 45 20 4a 53 4f 4e 31 4e 4f 43 41 53 45 17 BLE JSON1NOCASE. | 3568: 13 05 00 0f 25 17 58 45 4e 41 42 4c 45 20 4a 53 ....%.XENABLE JS | 3584: 4f 4e 31 52 54 52 49 4d 1a 12 05 00 0f 29 19 58 ON1RTRIM.....).X | 3600: 45 4e 41 42 4c 45 20 47 45 4f 50 4f 4c 59 42 49 ENABLE GEOPOLYBI | 3616: 4e 41 52 59 1a 11 05 00 0f 29 19 58 45 4e 41 1e NARY.....).XENA. | 3632: 4c 45 20 47 45 4f 50 4f 4c 59 4e 4f 43 41 53 45 LE GEOPOLYNOCASE | 3648: 19 10 05 00 0f 29 17 58 45 4e 41 42 4c 45 20 47 .....).XENABLE G | 3664: 45 4f 50 4f 4c 59 52 54 52 49 4d 17 0f 05 00 0f EOPOLYRTRIM..... | 3680: 23 19 58 45 4e 41 42 4c 45 20 46 54 53 35 42 49 #.XENABLE FTS5BI | 3696: 4e 41 52 59 17 0e 05 00 0f 23 19 58 55 4e 41 42 NARY.....#.XUNAB | 3712: 4c 45 20 46 54 53 35 4e 4f 43 41 53 45 16 0d 05 LE FTS5NOCASE... | 3728: 00 0f 23 17 58 45 4e 41 42 4c 45 20 46 54 53 35 ..#.XENABLE FTS5 | 3744: 52 54 52 49 4d 17 0c 05 00 0f 23 19 58 45 4e 41 RTRIM.....#.XENA | 3760: 42 4c 45 20 46 54 53 34 42 49 4e 41 52 59 17 0b BLE FTS4BINARY.. | 3776: 05 00 0f 23 19 58 45 4e 41 42 4c 45 20 46 54 53 ...#.XENABLE FTS | 3792: 35 4e 4f 43 40 53 45 16 0a 05 00 0f 23 17 58 45 5NOC@SE.....#.XE | 3808: 4e 41 42 4c 45 20 46 54 53 34 52 54 52 49 4d 1e NABLE FTS4RTRIM. | 3824: 09 05 00 0f 31 19 58 45 4e 41 42 4c 35 20 44 42 ....1.XENABL5 DB | 3840: 53 54 41 54 20 56 54 41 42 42 49 4e 41 52 59 1e STAT VTABBINARY. | 3856: 08 05 00 0f 31 19 58 45 4e 41 42 4c 45 20 44 42 ....1.XENABLE DB | 3872: 53 54 41 54 20 56 54 41 42 4e 4f 43 41 53 45 1d STAT VTABNOCASE. | 3888: 07 05 00 0f 31 17 58 45 4e 41 42 4c 45 20 44 42 ....1.XENABLE DB | 3904: 53 54 41 54 20 56 54 41 42 52 54 52 49 4d 11 06 STAT VTABRTRIM.. | 3920: 05 00 0f 17 19 58 44 45 42 55 47 42 49 4e 41 52 .....XDEBUGBINAR | 3936: 59 11 05 05 00 0f 17 19 58 44 45 42 55 47 4e 4f Y.......XDEBUGNO | 3952: 43 41 53 45 10 04 05 00 0f 17 17 58 44 45 42 55 CASE.......XDEBU | 3968: 47 52 54 52 49 4d 27 03 05 00 0f 43 19 58 43 4f GRTRIM'....C.XCO | 3984: 4d 50 49 4c 45 52 3d 67 63 63 2d 35 2e 34 2e 30 MPILER=gcc-5.4.0 | 4000: 20 32 30 31 36 30 36 30 39 42 49 4e 41 52 59 27 20160609BINARY' | 4016: 02 05 00 0f 43 19 58 43 4f 4d 50 49 4c 45 52 3d ....C.XCOMPILER= | 4032: 67 63 63 2d 35 2e 34 2e 30 20 32 30 31 36 30 36 gcc-5.4.0 201606 | 4048: 30 39 4e 4f 43 41 53 45 26 01 05 00 0f 43 17 58 09NOCASE&....C.X | 4064: 43 4f 4d 50 49 4c 45 52 3d 67 63 63 2d 35 2e 34 COMPILER=gcc-5.4 | 4080: 2e 30 20 32 30 31 36 30 36 30 39 52 54 52 49 4d .0 20160609RTRIM | page 4 offset 12288 | 0: 0d 00 00 00 00 10 00 00 00 00 00 00 00 00 00 00 ................ | page 5 offset 16384 | 0: 0d 00 00 00 03 07 bb 00 0c ad 0b a0 07 bb 00 00 ................ | 1968: 00 00 00 00 00 00 00 00 00 00 00 87 62 03 08 08 ............b... | 1984: 01 08 08 17 8f 34 02 30 20 39 38 30 00 01 30 1e .....4.0 980..0. | 2000: 01 01 01 06 00 01 01 01 06 00 01 01 01 06 00 1f ................ | 2016: 01 01 03 00 01 01 01 03 00 01 01 01 03 00 00 08 ................ | 2032: 32 30 31 36 30 36 30 39 0f 01 01 01 07 00 01 01 20160609........ | 2048: 01 07 00 01 01 01 07 00 00 01 34 0f 01 01 01 05 ..........4..... | 2064: 00 01 01 01 05 00 01 01 01 05 00 00 01 35 0f 01 .............5.. | 2080: 01 01 04 00 01 01 01 04 00 01 01 01 04 00 01 07 ................ | 2096: 30 30 30 30 30 30 30 0f 1c 01 01 04 00 01 01 01 0000000......... | 2112: 04 00 01 01 01 04 00 00 06 62 69 6e 61 72 79 3c .........binary< | 2128: 03 01 02 02 00 03 01 02 02 00 03 01 02 02 00 03 ................ | 2144: 01 02 02 00 03 01 02 02 00 03 01 02 02 00 03 01 ................ | 2160: 02 02 00 03 01 02 02 00 03 01 02 02 00 03 01 02 ................ | 2176: 02 00 03 01 02 02 00 03 01 02 02 00 00 08 63 6f ..............co | 2192: 6d 70 69 6c 65 72 0f 01 01 01 02 00 01 01 01 02 mpiler.......... | 2208: 00 01 01 01 02 00 00 06 64 62 73 74 61 74 0f 07 ........dbstat.. | 2224: 01 01 03 00 01 01 01 03 00 01 01 01 03 00 01 04 ................ | 2240: 65 62 75 67 0f 04 01 01 02 00 01 01 01 02 00 01 ebug............ | 2256: 01 01 02 00 00 03 65 6e 61 05 11 01 01 02 00 03 ......ena....... | 2272: 03 62 6c 35 05 09 01 01 02 00 05 01 65 5a 07 01 .bl5........eZ.. | 2288: 01 02 00 01 01 01 02 00 02 01 01 02 00 01 01 01 ................ | 2304: 02 00 01 01 01 02 00 01 01 01 02 00 02 01 01 02 ................ | 2320: 00 01 01 01 02 00 02 01 01 02 00 01 01 01 02 00 ................ | 2336: 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 01 ................ | 2352: 01 01 02 00 01 01 01 02 00 01 01 01 02 00 01 01 ................ | 2368: 01 02 00 01 01 01 02 00 01 08 78 74 65 6e 73 69 ..........xtensi | 2384: 6f 6e 0f 1f 01 01 04 00 01 01 01 04 00 01 01 01 on.............. | 2400: 04 00 00 04 66 74 73 34 0a 0a 01 01 03 00 02 01 ....fts4........ | 2416: 01 03 00 03 01 35 14 0b 01 01 03 00 02 01 01 03 .....5.......... | 2432: 00 01 01 01 03 00 01 01 01 03 00 00 03 67 63 63 .............gcc | 2448: 0f 01 01 01 03 00 01 01 01 03 00 01 01 01 03 00 ................ | 2464: 01 06 65 6f 70 6f 6c 79 0f 10 01 01 03 00 01 01 ..eopoly........ | 2480: 01 04 00 01 01 01 03 00 00 05 6a 73 6f 6e 31 0f ..........json1. | 2496: 13 01 01 03 00 01 01 01 03 00 01 01 01 03 00 00 ................ | 2512: 02 6c 65 05 11 01 01 03 00 01 03 6f 61 64 0f 1f .le........oad.. | 2528: 01 01 03 00 01 01 01 03 00 01 01 01 03 00 00 03 ................ | 2544: 6d 61 78 0f 1c 01 01 02 00 01 01 01 02 00 01 01 max............. | 2560: 01 02 00 01 05 65 6d 6f 72 79 0f 1c 01 01 03 00 .....emory...... | 2576: 01 01 01 03 00 01 01 01 03 00 03 04 73 79 73 35 ............sys5 | 2592: 0f 16 01 01 03 00 01 01 01 03 00 01 01 01 03 00 ................ | 2608: 00 03 6e 6f 63 05 0b 01 02 02 00 03 03 61 73 65 ..noc........ase | 2624: 37 02 01 02 02 00 03 01 02 02 00 03 01 02 02 00 7............... | 2640: 06 01 02 02 00 03 01 02 02 00 03 01 02 02 00 03 ................ | 2656: 01 02 02 00 03 01 02 02 00 03 01 02 02 00 03 01 ................ | 2672: 02 02 00 03 01 02 02 00 00 04 6f 6d 69 74 0f 1f ..........omit.. | 2688: 01 01 02 00 01 01 01 02 00 01 01 01 02 00 00 05 ................ | 2704: 72 74 72 65 65 0f 19 01 01 03 00 01 01 01 03 00 rtree........... | 2720: 01 01 01 03 00 03 02 69 6d 3c 01 01 02 02 00 03 .......im<...... | 2736: 01 02 02 00 03 01 02 02 00 03 01 02 02 00 03 01 ................ | 2752: 02 02 00 03 01 02 02 00 03 01 02 02 00 03 01 02 ................ | 2768: 02 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 ................ | 2784: 00 03 01 02 02 00 00 02 73 65 05 0b 01 02 03 00 ........se...... | 2800: 00 0a 74 68 72 65 61 64 73 61 66 65 0f 22 01 01 ..threadsafe.... | 2816: 02 00 01 01 01 02 00 01 01 01 02 00 00 06 75 6e ..............un | 2832: 61 62 6c 65 05 0e 01 01 02 00 00 04 76 74 61 62 able........vtab | 2848: 0f 07 01 01 04 00 01 01 01 04 00 01 01 01 04 00 ................ | 2864: 00 01 78 6c 01 02 00 01 02 00 01 02 00 01 02 00 ..xl............ | 2880: 01 02 00 01 02 00 01 02 00 01 02 00 01 02 00 01 ................ | 2896: 02 00 01 02 00 01 02 00 01 02 00 01 02 00 01 02 ................ | 2912: 00 01 02 00 01 02 00 01 02 00 01 02 00 01 02 00 ................ | 2928: 01 02 00 01 02 00 01 02 00 01 02 00 01 02 00 01 ................ | 2944: 02 00 01 02 00 01 02 00 01 02 00 01 02 00 01 02 ................ | 2960: 00 01 02 00 01 02 00 01 02 00 01 02 00 01 02 00 ................ | 2976: 82 0a 02 08 08 09 08 08 17 84 06 30 20 32 35 33 ...........0 253 | 2992: 00 01 30 04 25 06 1b 00 00 08 32 30 31 36 30 36 ..0.%.....201606 | 3008: 30 39 03 25 07 00 00 01 34 03 25 05 00 00 01 35 09.%....4.%....5 | 3024: 03 25 04 00 01 07 30 30 30 30 30 30 30 03 25 1a .%....0000000.%. | 3040: 00 00 08 63 6f 6d 70 69 6c 65 72 03 25 02 00 00 ...compiler.%... | 3056: 06 64 62 73 74 61 74 03 25 0a 00 01 04 65 62 75 .dbstat.%....ebu | 3072: 67 03 25 08 00 00 06 65 6e 61 62 6c 65 09 25 09 g.%....enable.%. | 3088: 05 04 04 04 04 04 00 01 08 78 74 65 6e 73 69 6f .........xtensio | 3104: 6e 03 25 1d 00 00 04 66 74 73 34 03 25 0d 00 03 n.%....fts4.%... | 3120: 11 35 03 25 0f 00 00 03 67 63 63 03 25 03 00 01 .5.%....gcc.%... | 3136: 06 65 6f 70 6f 6c 79 03 25 11 00 00 05 6a 73 6f .eopoly.%....jso | 3152: 6e 31 03 25 13 00 00 04 6c 6f 61 64 03 25 1c 00 n1.%....load.%.. | 3168: 00 03 6d 61 78 03 25 18 00 01 05 65 6d 6f 72 79 ..max.%....emory | 3184: 03 25 19 00 03 04 73 79 73 35 03 25 15 00 00 04 .%....sys5.%.... | 3200: 6f 6d 69 74 03 25 1b 00 00 05 72 74 72 65 65 03 omit.%....rtree. | 3216: 25 17 00 00 0a 74 68 72 65 61 64 73 61 66 65 03 %....threadsafe. | 3232: 25 1e 00 00 04 76 74 61 62 03 25 0b 00 86 50 01 %....vtab.%...P. | 3248: 08 08 08 08 08 17 8d 12 30 20 38 33 35 00 01 30 ........0 835..0 | 3264: 12 00 f6 00 01 06 00 01 06 00 1f 03 00 01 03 00 ................ | 3280: 01 03 00 00 08 32 30 31 36 30 36 30 39 09 01 07 .....20160609... | 3296: 00 01 07 00 01 07 00 00 01 34 09 01 05 00 01 05 .........4...... | 3312: 00 01 05 00 00 01 35 09 01 04 00 01 04 00 01 04 ......5......... | 3328: 00 01 07 30 30 30 30 30 30 30 09 1c 04 00 01 04 ...0000000...... | 3344: 00 01 04 00 00 06 62 69 6e 61 72 79 3c 03 01 02 ......binary<... | 3360: 02 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 ................ | 3376: 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 00 ................ | 3392: 03 01 02 02 00 03 01 02 02 00 03 01 02 02 00 03 ................ | 3408: 01 02 02 00 03 01 02 02 00 00 08 63 6f 6d 70 69 ...........compi | 3424: 6c 65 72 09 01 02 00 01 02 00 01 02 00 00 06 64 ler............d | 3440: 62 73 74 61 74 09 07 03 00 01 03 00 01 03 00 01 bstat........... | 3456: 04 65 62 75 67 09 04 02 00 01 02 00 01 02 00 00 .ebug........... | 3472: 06 65 6e 61 62 6c 65 3f 07 02 00 01 02 00 01 01 .enable?........ | 3488: 00 01 02 00 01 02 00 01 02 00 01 02 00 01 02 00 ................ | 3504: 01 02 00 01 02 00 01 02 00 01 02 00 01 02 10 01 ................ | 3520: 02 00 01 02 00 01 02 00 01 02 00 01 02 00 01 02 ................ | 3536: 00 01 02 00 01 02 00 01 08 78 74 65 6e 73 69 6f .........xtensio | 3552: 6e 09 1f 04 00 01 04 00 01 04 00 00 04 66 74 73 n............fts | 3568: 34 09 0a 03 00 01 03 00 01 03 00 03 01 35 09 0d 4............5.. | 3584: 03 00 01 03 00 01 03 00 00 03 67 63 63 09 01 03 ..........gcc... | 3600: 00 01 03 00 01 03 00 01 06 65 6f 70 6f 6c 79 09 .........eopoly. | 3616: 10 03 00 01 03 00 01 03 00 00 05 6a 73 6f 6e 31 ...........json1 | 3632: 09 13 03 00 01 03 00 01 03 00 00 04 6c 6f 61 64 ............load | 3648: 09 1f 03 00 01 03 00 01 03 00 00 03 6d 61 78 09 ............max. | 3664: 1c 02 00 01 02 00 01 02 00 01 05 65 6d 6f 72 79 ...........emory | 3680: 09 1c 03 00 01 03 00 01 03 00 03 04 73 79 73 35 ............sys5 | 3696: 09 16 03 00 01 03 00 01 03 00 00 06 6e 6f 63 61 ............noca | 3712: 73 65 3c 02 01 02 02 00 03 01 02 02 00 03 01 02 se<............. | 3728: 02 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 ................ | 3744: 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 00 ................ | 3760: 03 01 02 02 00 03 01 02 02 00 03 01 02 02 00 00 ................ | 3776: 04 6f 6d 69 74 09 1f 02 00 01 02 00 01 02 00 00 .omit........... | 3792: 05 72 74 72 65 65 09 19 03 00 01 03 00 01 03 00 .rtree.......... | 3808: 03 02 69 6d 3c 01 01 02 02 00 03 01 02 02 00 03 ..im<........... | 3824: 01 02 02 00 03 01 02 02 00 03 01 02 02 00 03 01 ................ | 3840: 02 02 00 03 01 02 02 00 03 01 02 02 00 03 01 02 ................ | 3856: 02 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 ................ | 3872: 00 00 0a 74 68 72 65 61 64 73 61 66 65 09 22 02 ...threadsafe... | 3888: 00 01 02 00 02 02 00 00 04 76 74 61 62 09 07 04 .........vtab... | 3904: 00 01 04 00 01 04 00 00 01 78 b4 01 01 01 01 02 .........x...... | 3920: 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 ................ | 3936: 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 01 ................ | 3952: 01 01 02 00 01 01 01 02 00 01 01 01 02 00 01 01 ................ | 3968: 01 02 00 01 01 01 02 00 01 01 01 02 00 01 01 01 ................ | 3984: 02 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 ................ | 4000: 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 ................ | 4016: 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 01 ................ | 4032: 01 01 02 00 01 01 01 02 00 01 01 01 02 00 01 01 ................ | 4048: 01 02 00 01 01 01 02 00 01 01 01 02 00 01 01 01 ................ | 4064: 02 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 ................ | 4080: 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 ................ | page 6 offset 20480 | 0: 0a 00 00 00 03 0f ee 00 0f fb 0f f5 0f ee 00 00 ................ | 4064: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 06 04 ................ | 4080: 08 01 01 02 03 05 04 08 09 01 02 04 04 08 08 09 ................ | page 7 offset 24576 | 0: 0d 00 00 00 05 0f b8 00 0f f4 0f e9 0f d6 0f c7 ................ | 16: 0f b8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ | 4016: 00 00 00 00 00 00 00 00 0d 05 02 23 61 75 74 6f ...........#auto | 4032: 6d 65 72 67 65 3d 35 0c f4 02 23 6d 65 72 67 65 merge=5...#merge | 4048: 3d 31 30 30 2c 38 11 03 02 2b 69 6e 74 65 67 72 =100,8...+integr | 4064: 69 74 79 2d 63 68 65 63 6b 09 02 02 1b 72 65 62 ity-check....reb | 4080: 75 69 6c 64 0a 01 02 1d 6f 70 74 69 6d 69 7a 65 uild....optimize | end c81b.db }]} {} do_catchsql_test 12.1 { SELECT rowid, quote(matchinfo(t1,'pcxybspcxybs')) FROM t1 WHERE t1 MATCH 'e*e*' } {1 {database disk image is malformed}} #------------------------------------------------------------------------- reset_db do_test 13.0 { sqlite3 db {} db deserialize [decode_hexdb { | size 28672 pagesize 4096 filename crash-c666cfde112dee.db | page 1 offset 0 | 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3. | 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 07 .....@ ........ | 32: 00 00 00 02 00 00 00 01 00 00 00 07 00 00 00 04 ................ | 48: 00 00 00 00 00 00 00 07 00 00 00 01 00 00 00 00 ................ | 96: 00 00 00 00 0d 0e b1 00 06 0d a4 00 0f 8d 0f 21 ...............! | 112: 0e b9 0d c8 0e 7e 0d a4 0d a4 00 00 00 00 00 00 .....~.......... | 3488: 00 00 00 00 22 07 06 17 11 11 01 31 74 61 62 6c ...........1tabl | 3504: 65 74 32 74 32 07 43 52 45 41 54 45 20 54 41 42 et2t2.CREATE TAB | 3520: 4c 45 20 74 32 28 78 29 81 33 05 07 17 1f 1f 01 LE t2(x).3...... | 3536: 82 35 74 61 62 6c 65 74 31 5f 73 65 67 64 69 72 .5tablet1_segdir | 3552: 74 31 5f 73 65 67 64 69 72 05 43 52 45 41 54 45 t1_segdir.CREATE | 3568: 20 54 41 42 4c 45 20 27 74 31 5f 73 65 67 64 69 TABLE 't1_segdi | 3584: 72 27 28 6c 65 76 65 6c 20 49 4e 54 45 47 45 52 r'(level INTEGER | 3600: 2c 69 64 78 20 49 4e 54 45 47 45 52 2c 73 74 61 ,idx INTEGER,sta | 3616: 72 74 5f 62 6c 6f 63 6b 20 49 4e 54 45 47 45 52 rt_block INTEGER | 3632: 2c 6c 65 61 76 65 73 5f 65 6e 64 5f 62 6c 6f 63 ,leaves_end_bloc | 3648: 6b 20 49 4e 54 45 47 45 52 2c 65 6e 64 5f 62 6c k INTEGER,end_bl | 3664: 6f 63 6b 20 49 4e 54 45 47 45 62 2c 72 6f 6f 74 ock INTEGEb,root | 3680: 20 42 4c 4f 42 2c 50 52 49 4d 41 52 59 20 4b 45 BLOB,PRIMARY KE | 3696: 59 28 6c 65 76 65 6c 2c 20 69 64 78 29 29 31 06 Y(level, idx))1. | 3712: 06 17 45 1f 01 00 69 6e 64 65 78 73 71 6c 69 74 ..E...indexsqlit | 3728: 65 5f 61 75 74 6f 69 6e 64 65 78 5f 74 31 5f 73 e_autoindex_t1_s | 3744: 65 67 64 69 72 5f 31 74 31 5f 73 65 67 64 69 72 egdir_1t1_segdir | 3760: 06 0f c7 00 08 00 00 00 00 66 04 07 17 23 23 01 .........f...##. | 3776: 81 13 74 61 62 6c 65 74 31 5f 73 65 67 6d 65 6e ..tablet1_segmen | 3792: 74 73 74 31 5f 73 65 67 6d 65 6e 74 73 04 43 52 tst1_segments.CR | 3808: 45 41 54 45 20 54 41 42 4c 45 20 27 74 31 5f 73 EATE TABLE 't1_s | 3824: 65 67 6d 65 6e 74 73 27 28 62 6c 6f 63 6b 69 64 egments'(blockid | 3840: 20 49 4e 54 45 47 45 52 20 50 52 49 4d 41 52 59 INTEGER PRIMARY | 3856: 20 4b 45 59 2c 20 62 6c 6f 63 6b 20 42 4c 4f 42 KEY, block BLOB | 3872: 29 6a 03 07 17 21 21 01 81 1f 74 61 62 6c 65 74 )j...!!...tablet | 3888: 31 5f 63 6f 6e 74 65 6e 74 74 31 5f 63 6f 6e 74 1_contentt1_cont | 3904: 65 6e 74 03 43 52 45 41 54 45 20 54 41 42 4c 45 ent.CREATE TABLE | 3920: 20 27 74 31 5f 63 6f 6e 74 65 6e 74 27 28 64 6f 't1_content'(do | 3936: 63 69 64 20 49 4e 54 45 47 45 52 20 50 52 49 4d cid INTEGER PRIM | 3952: 41 52 59 20 4b 45 59 2c 20 27 63 30 61 27 2c 20 ARY KEY, 'c0a', | 3968: 27 63 31 62 27 2c 20 27 63 32 63 27 29 38 02 06 'c1b', 'c2c')8.. | 3984: 17 11 11 08 5f 74 61 62 6c 65 74 31 74 31 43 52 ...._tablet1t1CR | 4000: 45 41 54 45 20 56 49 52 54 55 41 4c 20 54 41 42 EATE VIRTUAL TAB | 4016: 4c 45 20 74 31 20 55 53 49 4e 47 20 66 74 73 33 LE t1 USING fts3 | 4032: 28 61 2c 62 2c 63 29 00 00 00 39 00 00 00 00 00 (a,b,c)...9..... | page 3 offset 8192 | 0: 0d 00 00 00 25 0b 48 00 0f d8 0f af 0f 86 0f 74 ....%.H........t | 16: 0f 61 0f 4e 0f 2f 0f 0f 0e ef 0e d7 0e be 0e a5 .a.N./.......... | 32: 0e 8d 0e 74 0e 5b 0e 40 0e 24 0e 08 0d ef 0d d5 ...t.[.@.$...... | 48: 0d bb 0d a0 0d 84 0d 68 0d 4f 0d 35 0d 1b 0c fb .......h.O.5.... | 64: 0c da 0c b9 0c 99 0c 78 0c 57 0c 3e 0c 24 0c 0a .......x.W.>.$.. | 80: 0b 48 00 00 00 00 00 00 00 00 00 00 00 00 00 00 .H.............. | 2880: 00 00 00 00 00 00 00 00 81 3f 25 06 00 82 7f 00 .........?%..... | 2896: 00 43 4f 4d 50 49 4c 45 52 3d 67 63 63 2d 35 2e .COMPILER=gcc-5. | 2912: 34 23 00 20 32 30 31 36 30 36 30 39 20 44 45 42 4#. 20160609 DEB | 2928: 55 47 20 45 4e 41 42 4c 45 20 44 42 53 54 41 54 UG ENABLE DBSTAT | 2944: 20 56 54 41 42 20 45 4e 41 42 4c 45 20 46 54 53 VTAB ENABLE FTS | 2960: 34 20 45 4e 41 42 4c 45 20 46 54 53 35 20 45 4e 4 ENABLE FTS5 EN | 2976: 41 42 4c 45 20 47 45 4f 50 4f 4c 59 20 45 4e 41 ABLE GEOPOLY ENA | 2992: 42 4c 45 20 4a 53 4f 4e 31 20 45 4e 41 42 4c 45 BLE JSON1 ENABLE | 3008: 20 4d 45 4d 53 59 53 35 20 45 4e 41 42 4c 45 20 MEMSYS5 ENABLE | 3024: 52 54 52 45 45 20 4d 41 58 20 4d 45 4d 4f 52 59 RTREE MAX MEMORY | 3040: 3d 35 30 30 30 30 30 30 30 20 4f 4d 49 54 20 4c =50000000 OMIT L | 3056: 4f 41 44 20 45 58 54 45 4e 53 49 4f 4e 20 54 48 OAD EXTENSION TH | 3072: 52 45 41 44 53 41 46 45 3d 30 18 24 05 00 25 0f READSAFE=0.$..%. | 3088: 19 54 48 52 45 41 44 53 41 46 45 3d 30 58 42 49 .THREADSAFE=0XBI | 3104: 4e 41 52 59 18 23 05 00 25 0f 19 54 48 52 45 41 NARY.#..%..THREA | 3120: 44 53 41 46 45 3d 30 58 4e 4f 43 41 53 45 17 22 DSAFE=0XNOCASE.. | 3136: 05 00 25 0f 17 54 48 52 45 41 44 53 41 46 45 3d ..%..THREADSAFE= | 3152: 30 58 52 54 52 49 4d 1f 21 05 00 33 0f 19 4f 4d 0XRTRIM.!..3..OM | 3168: 49 54 20 4c 4f 41 44 20 45 58 54 45 4e 53 49 4f IT LOAD EXTENSIO | 3184: 4e 58 42 49 4e 41 52 59 1f 20 05 00 33 0f 19 4f NXBINARY. ..3..O | 3200: 4d 49 54 20 4c 4f 41 44 20 45 58 54 45 4e 53 49 MIT LOAD EXTENSI | 3216: 4f 4e 58 4e 4f 43 41 53 45 1e 1f 05 00 33 0f 17 ONXNOCASE....3.. | 3232: 4f 4d 49 54 20 4c 4f 41 44 20 45 58 54 45 4e 53 OMIT LOAD EXTENS | 3248: 49 4f 4e 58 52 54 52 49 4d 1f 1e 05 00 33 0f 19 IONXRTRIM....3.. | 3264: 4d 41 58 20 4d 45 4d 4f 52 59 3d 35 30 30 30 30 MAX MEMORY=50000 | 3280: 30 30 30 58 42 49 4e 41 52 59 1f 1d 05 00 33 0f 000XBINARY....3. | 3296: 19 4d 41 58 20 4d 45 4d 4f 52 59 3d 35 30 30 30 .MAX MEMORY=5000 | 3312: 30 30 30 30 58 4e 4f 43 41 53 45 1e 1c 05 00 33 0000XNOCASE....3 | 3328: 0f 17 4d 41 58 20 4d 45 4d 4f 52 59 3d 35 30 30 ..MAX MEMORY=500 | 3344: 30 30 30 30 30 58 52 54 53 49 4d 18 1b 05 00 25 00000XRTSIM....% | 3360: 0f 19 45 4e 41 42 4c 45 20 52 54 52 45 45 58 42 ..ENABLE RTREEXB | 3376: 49 4e 41 52 59 18 1a 05 00 25 0f 19 45 4e 41 42 INARY....%..ENAB | 3392: 4c 45 20 52 54 52 45 45 58 4e 4f 43 41 53 45 17 LE RTREEXNOCASE. | 3408: 19 05 00 25 0f 17 45 4e 41 42 4c 45 20 52 54 52 ...%..ENABLE RTR | 3424: 45 45 58 52 54 52 49 4d 1a 18 05 00 29 0f 19 45 EEXRTRIM....)..E | 3440: 4e 41 42 4c 45 20 4d 45 4d 53 59 53 35 58 42 49 NABLE MEMSYS5XBI | 3456: 4e 41 52 59 1a 17 05 00 29 0f 19 45 4e 41 42 4c NARY....)..ENABL | 3472: 45 20 4d 45 4d 53 59 53 35 58 4e 4f 43 41 53 45 E MEMSYS5XNOCASE | 3488: 19 16 05 00 29 0f 17 45 4e 41 42 4c 45 20 4d 45 ....)..ENABLE ME | 3504: 4d 53 59 53 35 58 52 54 52 49 4d 18 15 05 00 25 MSYS5XRTRIM....% | 3520: 0f 19 45 4e 41 42 4c 45 20 4a 53 4f 4e 31 58 42 ..ENABLE JSON1XB | 3536: 49 4e 41 52 59 18 14 05 00 25 0f 19 45 4e 41 42 INARY....%..ENAB | 3552: 4c 45 20 4a 53 4f 4e 31 58 4e 4f 43 41 53 45 17 LE JSON1XNOCASE. | 3568: 13 05 00 25 0f 17 45 4e 41 52 4c 45 20 4a 53 4f ...%..ENARLE JSO | 3584: 4e 31 58 52 54 52 49 4d 1a 12 05 00 29 0f 19 45 N1XRTRIM....)..E | 3600: 4e 41 42 4c 45 20 47 45 4f 50 4f 4c 59 58 42 49 NABLE GEOPOLYXBI | 3616: 4e 41 52 59 1a 11 05 00 29 0f 19 45 4e 41 1e 4c NARY....)..ENA.L | 3632: 45 20 47 45 4f 50 4f 4c 59 58 4e 4f 43 41 53 45 E GEOPOLYXNOCASE | 3648: 19 10 05 00 29 0f 17 45 4e 41 42 4c 45 20 47 45 ....)..ENABLE GE | 3664: 4f 50 4f 4c 59 58 52 54 52 49 4d 17 0f 05 00 23 OPOLYXRTRIM....# | 3680: 0f 19 45 4e 41 42 4c 45 20 46 54 53 35 58 42 49 ..ENABLE FTS5XBI | 3696: 4e 41 52 59 17 0e 05 00 23 0f 19 45 4e 41 42 4c NARY....#..ENABL | 3712: 45 20 46 54 53 35 58 4e 4f 43 41 53 45 16 0d 05 E FTS5XNOCASE... | 3728: 00 23 0f 17 45 4e 41 42 4c 45 20 46 54 59 e5 58 .#..ENABLE FTY.X | 3744: 52 54 52 49 4d 17 0c 05 00 23 0f 19 45 4e 41 42 RTRIM....#..ENAB | 3760: 4c 45 20 46 54 53 34 58 42 49 4e 41 52 59 17 0b LE FTS4XBINARY.. | 3776: 05 00 23 0f 19 45 4e 41 42 4c 45 20 46 54 53 35 ..#..ENABLE FTS5 | 3792: 58 4e 4f 43 40 53 45 16 0a 05 00 23 0f 17 45 4e XNOC@SE....#..EN | 3808: 41 42 4c 45 20 46 54 53 34 58 52 54 52 49 4d 1e ABLE FTS4XRTRIM. | 3824: 09 05 00 31 0f 19 45 4e 41 42 4c 45 20 44 42 53 ...1..ENABLE DBS | 3840: 54 41 54 20 56 54 41 42 58 42 49 4e 41 52 59 1e TAT VTABXBINARY. | 3856: 08 05 00 31 0f 19 45 4e 41 42 4c 45 20 44 42 53 ...1..ENABLE DBS | 3872: 54 41 54 20 56 54 41 42 58 4e 4f 43 41 53 45 1d TAT VTABXNOCASE. | 3888: 07 05 00 31 0f 17 45 4e 41 42 4c 45 20 44 42 53 ...1..ENABLE DBS | 3904: 54 41 54 20 56 54 41 42 58 52 54 52 49 4d 11 06 TAT VTABXRTRIM.. | 3920: 05 00 17 0f 19 44 45 42 55 47 58 42 49 4e 41 52 .....DEBUGXBINAR | 3936: 59 11 05 05 00 17 0f 19 44 45 42 55 47 58 4e 4f Y.......DEBUGXNO | 3952: 43 41 53 45 10 04 05 00 17 0f 17 44 45 42 55 47 CASE.......DEBUG | 3968: 58 52 54 52 49 4d 27 03 05 00 43 0f 19 43 4f 4d XRTRIM'...C..COM | 3984: 50 49 4c 45 52 3d 67 63 63 2d 35 2e 34 2e 30 20 PILER=gcc-5.4.0 | 4000: 32 30 31 36 30 36 30 39 58 42 49 4e 41 52 59 27 20160609XBINARY' | 4016: 02 05 00 43 0f 19 43 4f 4d 50 49 4c 45 52 3d 67 ...C..COMPILER=g | 4032: 63 63 2d 35 2e 34 2f 30 20 32 30 31 36 30 36 30 cc-5.4/0 2016060 | 4048: 39 58 4e 4f 43 41 53 45 26 01 05 00 43 0f 17 43 9XNOCASE&...C..C | 4064: 4f 4d 50 49 4c 45 52 3d 67 63 63 2d 35 2e 34 2e OMPILER=gcc-5.4. | 4080: 30 20 32 30 31 36 30 36 30 39 58 52 54 52 49 4d 0 20160609XRTRIM | page 4 offset 12288 | 0: 0d 00 00 00 00 10 00 00 00 00 00 00 00 00 00 00 ................ | page 5 offset 16384 | 0: 0d 00 00 00 02 0b a0 00 0c ad 0b a0 00 00 00 00 ................ | 2976: 82 0a 02 08 08 09 08 08 17 84 06 30 20 32 35 33 ...........0 253 | 2992: 00 01 30 04 25 06 1b 00 00 08 32 30 31 36 30 36 ..0.%.....201606 | 3008: 30 39 03 25 07 00 00 01 34 03 25 05 00 00 01 35 09.%....4.%....5 | 3024: 03 25 04 00 01 07 30 30 30 30 30 30 30 03 25 1a .%....0000000.%. | 3040: 00 00 08 63 6f 6d 70 69 6c 65 72 03 25 02 00 00 ...compiler.%... | 3056: 06 64 62 73 74 61 74 03 25 0a 00 01 04 65 62 75 .dbstat.%....ebu | 3072: 67 03 25 08 00 00 06 65 6e 61 62 6c 65 09 25 09 g.%....enable.%. | 3088: 05 04 04 04 04 04 00 01 08 78 74 65 6e 73 69 6f .........xtensio | 3104: 6e 03 25 1d 00 00 04 66 74 73 34 03 25 0d 00 03 n.%....fts4.%... | 3120: 01 35 03 25 0f 00 00 03 67 63 63 03 25 03 00 01 .5.%....gcc.%... | 3136: 06 65 6f 70 6f 6c 79 03 25 11 00 00 05 6a 73 6f .eopoly.%....jso | 3152: 6e 31 03 25 13 41 00 04 6c 6f 61 64 03 25 1c 00 n1.%.A..load.%.. | 3168: 00 03 6d 61 78 03 25 18 00 01 05 65 6d 6f 72 79 ..max.%....emory | 3184: 03 25 19 00 03 04 73 79 73 35 03 25 15 00 00 04 .%....sys5.%.... | 3200: 6f 6d 69 74 03 25 1b 00 00 05 72 74 72 65 65 03 omit.%....rtree. | 3216: 25 17 00 00 0a 74 68 72 65 61 64 73 61 66 65 03 %....threadsafe. | 3232: 25 1e 00 00 04 76 74 61 62 03 25 0b 00 86 50 01 %....vtab.%...P. | 3248: 08 08 08 08 08 17 8d 12 30 20 38 33 35 00 01 30 ........0 835..0 | 3264: 12 01 06 00 01 06 00 01 06 00 1f 03 00 01 03 00 ................ | 3280: 01 03 00 00 08 32 30 31 36 30 36 30 39 09 01 07 .....20160609... | 3296: 00 01 07 00 01 07 00 00 01 34 09 01 05 00 01 05 .........4...... | 3312: 00 01 05 00 00 01 35 09 01 04 00 01 04 00 01 04 ......5......... | 3328: 00 01 07 30 30 30 30 30 30 30 09 1c 04 00 01 04 ...0000000...... | 3344: 00 01 04 00 00 06 62 69 6e 61 72 79 3c 03 02 02 ......binary<... | 3360: 02 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 ................ | 3376: 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 00 ................ | 3392: 03 01 02 02 00 03 01 02 02 00 03 01 02 02 00 03 ................ | 3408: 01 02 02 00 03 01 02 02 00 00 08 63 6f 6d 70 69 ...........compi | 3424: 6c 65 72 09 01 02 00 01 02 00 01 02 00 00 06 64 ler............d | 3440: 62 73 74 61 74 09 f2 03 00 01 03 00 01 03 00 01 bstat........... | 3456: 04 65 62 75 67 09 04 02 00 01 02 00 01 02 00 00 .ebug........... | 3472: 06 65 6e 61 62 6c 65 3f 07 02 00 01 02 00 01 02 .enable?........ | 3488: 00 01 02 00 01 02 00 01 02 00 01 02 00 57 02 00 .............W.. | 3504: 01 02 00 01 01 00 01 02 00 01 02 00 01 02 10 01 ................ | 3520: 02 00 01 02 00 01 02 00 01 02 00 01 02 00 01 02 ................ | 3536: 00 01 02 00 01 02 00 01 08 78 74 64 6e 73 69 6f .........xtdnsio | 3552: 6e 09 1f 04 00 01 04 00 01 03 00 00 04 66 74 73 n............fts | 3568: 34 09 0a 03 00 01 03 00 01 03 00 03 01 35 09 0d 4............5.. | 3584: 03 00 01 03 00 01 03 00 00 03 57 63 63 09 01 03 ..........Wcc... | 3600: 00 01 03 00 01 03 00 01 06 65 6f 70 6f 6c 79 09 .........eopoly. | 3616: 10 03 00 01 03 00 01 03 00 00 05 6a 73 6f 6e 31 ...........json1 | 3632: 09 13 03 00 01 03 00 01 03 00 00 04 6c 6f 61 64 ............load | 3648: 09 1f 03 00 01 03 00 01 03 00 00 03 6d 61 78 09 ............max. | 3664: 1c 02 00 01 02 00 01 02 00 01 05 65 6d 6f 72 79 ...........emory | 3680: 09 1c 03 00 01 03 00 01 03 00 03 04 73 79 73 35 ............sys5 | 3696: 09 16 03 00 01 03 00 01 03 00 00 06 6e 6f 63 61 ............noca | 3712: 73 65 3c 02 01 02 02 00 03 01 02 02 00 03 01 02 se<............. | 3728: 02 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 ................ | 3744: 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 00 ................ | 3760: 03 01 02 02 00 03 01 02 02 00 03 01 02 02 00 00 ................ | 3776: 04 6f 6d 69 74 09 1f 02 00 01 02 00 01 02 00 00 .omit........... | 3792: 05 72 74 72 65 65 09 19 03 00 01 03 00 01 03 00 .rtree.......... | 3808: 03 02 69 6d 3c 01 01 02 02 00 03 01 02 02 00 03 ..im<........... | 3824: 01 02 02 00 03 01 02 02 00 03 01 02 02 00 03 01 ................ | 3840: 02 02 00 03 01 02 02 00 03 01 02 02 00 03 01 02 ................ | 3856: 02 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 ................ | 3872: 00 00 0a 74 68 72 65 61 64 73 61 66 65 09 22 02 ...threadsafe... | 3888: 00 01 02 00 02 02 00 00 04 76 74 61 62 09 07 04 .........vtab... | 3904: 00 01 04 00 01 04 00 00 01 78 b4 01 01 01 01 02 .........x...... | 3920: 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 ................ | 3936: 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 01 ................ | 3952: 01 01 02 00 01 01 01 02 00 01 01 01 02 00 01 01 ................ | 3968: 01 02 00 01 01 01 02 00 01 01 01 02 00 01 01 01 ................ | 3984: 02 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 ................ | 4000: 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 ................ | 4016: 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 01 ................ | 4032: 01 01 02 00 01 01 01 02 00 01 01 01 02 00 01 01 ................ | 4048: 01 02 00 01 01 01 02 00 01 01 01 02 00 01 01 01 ................ | 4064: 02 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 ................ | 4080: 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 ................ | page 6 offset 20480 | 0: 0a 00 00 00 02 0f f5 00 0f fb 0f f5 00 00 00 00 ................ | 4080: 00 00 00 00 00 05 04 08 09 01 02 04 04 08 08 09 ................ | page 7 offset 24576 | 0: 0d 00 00 00 05 0f b8 00 0f f4 0f e9 0f d6 0f c7 ................ | 16: 0f b8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ | 4016: 00 00 00 00 00 00 00 00 0d 05 02 23 61 75 74 6f ...........#auto | 4032: 6d 65 72 67 65 3d 35 0d 04 02 23 6d 65 72 67 65 merge=5...#merge | 4048: 3d 31 30 30 2c 38 11 03 02 2b 69 6e 74 65 67 72 =100,8...+integr | 4064: 69 74 79 2d 63 68 65 63 6b 09 02 02 1b 72 65 62 ity-check....reb | 4080: 75 69 6c 64 0a 01 02 1d 6f 70 74 69 6d 69 7a 65 uild....optimize | end crash-c666cfde112dee.db }]} {} do_catchsql_test 13.1 { SELECT quote(matchinfo(t1,'pcxybs'))==0 FROM t1 WHERE b MATCH 'e*'; } {0 {}} #------------------------------------------------------------------------- reset_db do_test 14.0 { sqlite3 db {} db deserialize [decode_hexdb { | size 28672 pagesize 4096 filename crash-f7b636a855e1d2.db | page 1 offset 0 | 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3. | 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 07 .....@ ........ | 32: 00 00 00 00 00 00 00 00 00 00 00 06 00 00 00 04 ................ | 48: 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 ................ | 96: 00 00 00 00 0d 0e ef 00 07 0d 4d 00 0f bd 0f 5f ..........M...._ | 112: 0e f7 0e 06 0e bc 0d a4 0d 4d 00 00 00 00 00 00 .........M...... | 3392: 00 00 00 00 00 00 00 00 00 00 00 00 00 55 07 07 .............U.. | 3408: 17 1b 1b 01 81 01 74 61 62 6c 65 74 31 5f 73 74 ......tablet1_st | 3424: 61 74 74 31 5f 73 74 61 74 07 43 52 45 41 54 45 att1_stat.CREATE | 3440: 20 54 41 42 4c 45 20 27 74 31 5f 73 74 61 74 27 TABLE 't1_stat' | 3456: 28 69 64 20 49 4e 54 45 47 45 52 20 50 52 49 4d (id INTEGER PRIM | 3472: 41 52 59 20 4b 45 59 2c 20 76 61 6c 75 65 20 42 ARY KEY, value B | 3488: 4c 4f 42 29 60 06 07 17 21 21 01 81 0b 74 61 62 LOB)`...!!...tab | 3504: 6c 65 74 31 5f 64 6f 63 73 69 7a 65 74 31 5f 64 let1_docsizet1_d | 3520: 6f 63 73 69 7a 65 06 43 52 45 41 54 45 20 54 41 ocsize.CREATE TA | 3536: 42 4c 45 20 27 74 31 5f 64 6f 63 73 69 7a 65 27 BLE 't1_docsize' | 3552: 28 64 6f 63 69 64 20 49 4e 54 45 47 45 52 20 50 (docid INTEGER P | 3568: 52 49 4d 41 52 59 20 4b 45 59 2c 20 73 69 7a 65 RIMARY KEY, size | 3584: 20 42 4c 4f 42 29 81 33 04 07 17 1f 1f 01 82 35 BLOB).3.......5 | 3600: 74 61 62 6c 65 74 31 5f 73 65 67 64 69 72 74 31 tablet1_segdirt1 | 3616: 5f 73 65 67 64 69 25 04 43 52 45 41 54 45 20 54 _segdi%.CREATE T | 3632: 41 42 4c 45 20 27 74 31 5f 73 65 67 64 69 72 27 ABLE 't1_segdir' | 3648: 28 6c 65 76 65 6c 20 49 4e 54 45 47 45 52 2c 69 (level INTEGER,i | 3664: 64 78 20 49 4e 54 45 47 45 52 2c 73 74 61 72 74 dx INTEGER,start | 3680: 5f 62 6c 6f 63 6b 20 49 4e 54 45 47 45 52 2c 6c _block INTEGER,l | 3696: 65 61 76 65 73 5f 65 6e 64 5f 62 6c 6f 63 6b 20 eaves_end_block | 3712: 49 4e 54 45 47 45 52 2c 65 6e 64 5f 62 6c 6f 63 INTEGER,end_bloc | 3728: 6b 20 49 4e 54 45 47 45 52 2c 72 6f 6f 74 20 42 k INTEGER,root B | 3744: 4c 4f 42 2c 50 52 49 4d 41 52 59 20 4b 45 59 28 LOB,PRIMARY KEY( | 3760: 6c 65 76 65 6c 2c 20 69 64 78 29 29 31 05 06 17 level, idx))1... | 3776: 45 1f 01 00 69 6e 64 65 78 73 71 6c 69 74 65 5f E...indexsqlite_ | 3792: 61 75 74 6f 69 6e 64 65 78 5f 74 31 5f 73 65 67 autoindex_t1_seg | 3808: 64 69 72 5f 31 74 31 5f 73 65 67 64 69 72 05 00 dir_1t1_segdir.. | 3824: 00 00 08 00 00 00 00 66 03 07 17 23 23 01 81 13 .......f...##... | 3840: 74 61 62 6c 65 74 31 5f 73 65 67 6d 65 6e 74 73 tablet1_segments | 3856: 74 31 5f 73 65 67 6d 65 6e 74 73 03 43 52 45 41 t1_segments.CREA | 3872: 54 45 20 54 41 42 4c 45 20 27 74 31 5f 73 65 67 TE TABLE 't1_seg | 3888: 6d 65 6e 74 73 27 28 62 6c 6f 63 6b 69 64 20 49 ments'(blockid I | 3904: 4e 54 45 47 45 52 20 50 52 49 4d 41 52 59 20 4b NTEGER PRIMARY K | 3920: 45 59 2c 20 62 6c 6f 63 6b 20 42 4c 4f 42 29 5c EY, block BLOB). | 3936: 02 07 17 21 21 01 81 03 74 61 62 6c 65 74 31 5f ...!!...tablet1_ | 3952: 63 6f 6e 74 65 6e 74 74 31 5f 63 6f 6e 74 65 6e contentt1_conten | 3968: 74 02 43 52 45 41 54 45 20 54 41 42 4c 45 20 27 t.CREATE TABLE ' | 3984: 74 31 5f 63 6f 6e 74 65 6e 74 27 28 64 6f 63 69 t1_content'(doci | 4000: 64 20 49 4e 54 45 47 45 52 20 50 52 49 4d 41 52 d INTEGER PRIMAR | 4016: 59 20 4b 45 59 2c 20 27 63 30 61 27 29 41 01 06 Y KEY, 'c0a')A.. | 4032: 17 11 11 08 71 74 61 62 6c 65 74 31 74 31 43 52 ....qtablet1t1CR | 4048: 45 41 54 45 20 56 49 52 54 55 41 4c 20 54 41 42 EATE VIRTUAL TAB | 4064: 4c 45 20 74 31 20 55 53 49 4e 47 20 66 74 73 34 LE t1 USING fts4 | 4080: 28 61 2c 70 72 65 66 69 78 3d 27 31 2c 32 27 29 (a,prefix='1,2') | page 2 offset 4096 | 0: 0d 00 00 00 08 0e 1f 00 0f c4 0f 7c 0f 34 0f 07 ...........|.4.. | 16: 0e c3 0e 97 0e 63 0e 1f 00 00 00 00 00 00 00 00 .....c.......... | 3600: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 42 ...............B | 3616: 08 04 00 81 09 73 75 6e 74 20 69 6e 20 63 75 6c .....sunt in cul | 3632: 70 61 20 71 75 69 20 6f 66 66 69 63 69 61 20 64 pa qui officia d | 3648: 65 73 65 72 75 6e 74 20 6d 6f 6c 6c 69 74 20 61 eserunt mollit a | 3664: 6e 69 6d 20 69 64 20 65 73 74 20 6c 61 62 6f 72 nim id est labor | 3680: 75 6d 2e 32 07 03 01 6b 45 78 63 65 70 74 65 75 um.2...kExcepteu | 3696: 72 20 73 69 6e 74 20 6f 63 63 61 65 63 61 74 20 r sint occaecat | 3712: 63 75 70 69 64 61 74 61 74 20 6e 6f 6e 20 70 72 cupidatat non pr | 3728: 6f 69 64 65 6e 74 2c 2a 06 03 00 5b 63 69 6c 6c oident,*...[cill | 3744: 75 6d 20 64 6f 6c 6f 72 65 20 65 75 20 66 75 67 um dolore eu fug | 3760: 69 61 74 20 6e 75 6c 6c 61 20 70 61 72 69 61 74 iat nulla pariat | 3776: 75 72 2e 43 05 04 00 81 09 44 75 69 73 20 61 75 ur.C.....Duis au | 3792: 74 65 20 69 72 75 72 65 20 64 6f 6c 6f 72 20 69 te irure dolor i | 3808: 6e 20 72 65 70 72 65 68 65 6e 64 65 72 69 74 20 n reprehenderit | 3824: 69 6e 20 76 6f 6c 75 70 74 61 74 65 20 76 65 6c in voluptate vel | 3840: 69 74 20 65 73 73 65 2b 14 03 00 5d 6e 69 73 69 it esse+...]nisi | 3856: 20 75 74 20 61 6c 69 71 75 69 70 20 65 78 20 65 ut aliquip ex e | 3872: 61 20 63 6f 6d 6d 6f 64 6f 20 63 6f 6e 73 65 71 a commodo conseq | 3888: 75 61 74 2e 46 03 04 00 81 11 55 74 20 65 6e 69 uat.F.....Ut eni | 3904: 6d 20 61 64 20 6d 69 6e 69 6d 20 76 65 6e 69 61 m ad minim venia | 3920: 6d 2c 20 71 75 69 73 20 6e 6f 73 74 72 75 64 20 m, quis nostrud | 3936: 65 78 65 72 63 69 74 61 74 69 6f 6e 20 75 6c 6c exercitation ull | 3952: 61 6d 63 6f 20 6c 61 62 6f 72 69 73 46 02 04 00 amco laborisF... | 3968: 81 11 73 65 64 20 64 6f 20 65 69 75 73 6d 6f 64 ..sed do eiusmod | 3984: 20 74 65 6d 70 6f 72 20 69 6e 63 69 64 69 64 75 tempor incididu | 4000: 6e 74 20 75 74 20 6c 61 62 6f 72 65 20 65 74 20 nt ut labore et | 4016: 64 6f 6c 6f 72 65 20 6d 61 67 6e 61 20 61 6c 69 dolore magna ali | 4032: 71 75 61 2e 3a 01 03 00 7b 4c 6f 72 65 6d 20 69 qua.:....Lorem i | 4048: 70 73 75 6d 20 64 6f 6c 6f 72 20 73 69 74 20 61 psum dolor sit a | 4064: 6d 65 74 2c 20 63 6f 6e 73 65 63 74 65 74 75 72 met, consectetur | 4080: 20 61 64 69 70 69 73 63 69 6e 67 20 65 6c 69 74 adipiscing elit | page 3 offset 8192 | 0: 0d 00 00 00 00 10 00 00 00 00 00 00 00 00 00 00 ................ | page 4 offset 12288 | 0: 0d 00 00 00 03 0a a6 00 0d 57 0c 4a 0a a6 00 00 .........W.J.... | 2720: 00 00 00 00 00 00 83 21 03 08 02 08 08 08 17 86 .......!........ | 2736: 30 08 00 30 20 34 30 32 00 02 61 64 06 01 08 00 0..0 402..ad.... | 2752: 02 04 00 01 01 6c 06 02 0c 00 02 04 00 01 01 6d .....l.........m | 2768: 03 01 06 00 01 01 6e 03 08 09 00 01 01 75 03 05 ......n......u.. | 2784: 03 00 00 02 63 69 03 06 01 00 01 01 6f 07 01 07 ....ci......o... | 2800: 00 03 07 03 00 01 01 75 06 07 05 00 01 04 00 00 .......u........ | 2816: 02 64 65 03 08 07 00 01 01 6f 0d 01 04 00 01 03 .de......o...... | 2832: 09 00 03 05 00 01 03 00 01 01 75 03 05 02 00 00 ..........u..... | 2848: 02 65 61 03 04 06 00 01 01 69 03 02 04 00 01 01 .ea......i...... | 2864: 6c 03 01 09 00 01 01 6e 03 03 03 00 01 01 73 06 l......n......s. | 2880: 05 0b 00 03 0b 00 01 01 74 03 02 09 00 01 01 75 ........t......u | 2896: 03 06 04 00 01 01 78 09 03 09 00 01 05 00 03 02 ......x......... | 2912: 00 00 02 66 75 03 06 05 00 00 02 69 64 03 08 0a ...fu......id... | 2928: 00 01 01 6e 0a 02 06 00 03 06 04 00 03 03 00 01 ...n............ | 2944: 01 70 03 01 13 00 01 01 72 03 05 04 00 00 02 6c .p......r......l | 2960: 61 09 02 08 00 01 0b 00 05 0c 00 01 01 6f 03 01 a............o.. | 2976: 02 00 00 02 6d 61 03 02 0b 00 01 01 69 03 04 05 ....ma......i... | 2992: 00 01 01 6f 03 08 08 00 00 02 6e 69 03 04 02 00 ...o......ni.... | 3008: 01 01 6f 06 03 08 00 04 06 00 01 01 75 03 06 06 ..o.........u... | 3024: 00 00 02 6f 63 03 07 04 00 01 01 66 03 08 06 00 ...oc......f.... | 3040: 00 02 70 61 03 06 07 00 01 01 72 03 07 07 00 00 ..pa......r..... | 3056: 02 71 75 06 03 07 00 05 05 00 00 02 72 65 03 05 .qu.........re.. | 3072: 07 00 00 02 73 65 03 02 02 00 01 01 69 06 01 05 ....se......i... | 3088: 00 06 03 00 01 01 75 03 08 02 00 00 02 74 65 03 ......u......te. | 3104: 03 05 00 00 02 75 6c 03 03 0a 00 01 01 74 09 02 .....ul......t.. | 3120: 07 00 01 02 00 01 03 00 00 02 76 65 06 03 06 00 ..........ve.... | 3136: 02 0a 00 01 01 6f 03 05 09 00 82 0a 02 08 02 08 .....o.......... | 3152: 08 08 17 84 02 04 00 30 20 32 35 31 00 01 61 13 .......0 251..a. | 3168: 01 06 04 00 01 0c 00 01 04 00 01 04 00 01 03 00 ................ | 3184: 03 09 00 00 01 63 10 01 07 00 03 07 03 00 02 02 .....c.......... | 3200: 00 01 05 00 01 04 00 00 01 64 11 01 04 00 01 03 .........d...... | 3216: 09 00 03 02 05 00 01 03 00 02 07 00 00 01 65 1b ..............e. | 3232: 01 09 00 01 04 07 00 01 03 08 00 01 05 03 00 01 ................ | 3248: 0b 00 01 04 00 01 02 00 01 0b 00 00 01 66 03 06 .............f.. | 3264: 05 00 00 01 69 0f 01 03 00 01 06 00 03 04 04 04 ....i........... | 3280: 00 03 03 09 00 00 01 6c 0c 01 02 00 01 08 00 01 .......l........ | 3296: 0b 00 05 0c 00 00 01 6d 09 02 0b 00 01 05 00 05 .......m........ | 3312: 08 00 00 01 6e 0c 03 08 00 01 02 00 02 06 00 01 ....n........... | 3328: 06 00 00 01 6f 06 07 04 00 01 06 00 00 01 70 06 ....o.........p. | 3344: 06 07 00 01 07 00 00 01 71 06 03 07 00 05 05 00 ........q....... | 3360: 00 01 72 03 05 08 00 00 01 73 0c 01 05 00 01 02 ..r......s...... | 3376: 00 05 03 00 01 02 00 00 01 74 03 02 05 00 00 01 .........t...... | 3392: 75 0a 02 07 00 01 02 0a 00 01 03 00 00 01 76 07 u.............v. | 3408: 03 06 00 02 09 03 00 85 26 01 08 08 08 08 08 17 ........&....... | 3424: 8a 3e 30 20 36 36 35 00 02 61 64 03 03 04 00 02 .>0 665..ad..... | 3440: 08 69 70 69 73 63 69 6e 67 03 01 08 00 01 05 6c .ipiscing......l | 3456: 69 71 75 61 03 02 0c 00 05 02 69 70 03 04 04 00 iqua......ip.... | 3472: 01 03 6d 65 74 03 01 06 00 01 03 6e 69 6d 03 08 ..met......nim.. | 3488: 09 00 01 03 75 74 65 03 05 03 00 00 06 63 69 6c ....ute......cil | 3504: 6c 75 6d 03 06 02 00 01 06 6f 6d 6d 6f 64 6f 03 lum......ommodo. | 3520: 04 07 00 02 09 6e 73 65 63 74 65 74 75 72 03 01 .....nsectetur.. | 3536: 07 00 05 04 71 75 61 74 03 04 08 00 01 04 75 6c ....quat......ul | 3552: 70 61 03 08 04 00 02 07 70 69 64 61 74 61 74 03 pa......pidatat. | 3568: 07 05 00 00 08 64 65 73 65 72 75 6e 74 03 08 07 .....deserunt... | 3584: 00 01 01 6f 03 02 03 00 02 03 6c 6f 72 06 01 04 ...o......lor... | 3600: 00 04 05 00 05 01 65 06 02 0a 00 04 03 00 01 03 ......e......... | 3616: 75 69 73 03 05 02 00 00 02 65 61 03 04 06 00 01 uis......ea..... | 3632: 06 69 75 73 6d 6f 64 03 02 04 00 01 03 6c 69 74 .iusmod......lit | 3648: 03 01 09 00 01 03 6e 69 6d 03 03 03 00 01 03 73 ......nim......s | 3664: 73 65 03 05 0b 00 02 01 73 03 08 0b 00 01 01 74 se......s......t | 3680: 03 02 09 00 01 01 75 03 06 04 00 01 01 78 03 04 ......u......x.. | 3696: 05 00 02 07 63 65 70 74 65 75 72 03 07 02 00 02 ....cepteur..... | 3712: 0a 65 72 63 69 74 61 74 69 6f 6e 03 03 09 00 00 .ercitation..... | 3728: 06 66 75 67 69 61 74 03 06 05 00 00 02 69 64 03 .fugiat......id. | 3744: 08 0a 00 01 01 6e 07 05 06 04 00 03 03 00 02 08 .....n.......... | 3760: 63 69 64 69 64 75 6e 74 03 02 06 00 01 04 70 73 cididunt......ps | 3776: 75 6d 03 01 03 00 01 04 72 75 72 65 03 05 04 00 um......rure.... | 3792: 00 06 6c 61 62 6f 72 65 03 02 08 00 05 02 69 73 ..labore......is | 3808: 03 03 0b 00 05 02 75 6d 03 08 0c 00 01 04 6f 72 ......um......or | 3824: 65 6d 03 01 02 00 00 05 6d 61 67 6e 61 03 02 0b em......magna... | 3840: 00 01 04 69 6e 69 6d 03 03 05 00 01 05 6f 6c 6c ...inim......oll | 3856: 69 74 03 08 08 00 00 04 6e 69 73 69 03 04 02 00 it......nisi.... | 3872: 01 02 6f 6e 03 07 06 00 02 05 73 74 72 75 64 03 ..on......strud. | 3888: 03 08 00 01 04 75 6c 6c 61 03 06 06 00 00 08 6f .....ulla......o | 3904: 63 63 61 65 63 61 74 03 07 04 00 01 06 66 66 69 ccaecat......ffi | 3920: 63 69 61 03 08 06 00 00 08 70 61 72 69 61 74 75 cia......pariatu | 3936: 72 03 06 07 00 01 07 72 6f 69 64 65 6e 74 03 07 r......roident.. | 3952: 07 00 00 03 71 75 69 03 08 05 00 03 01 73 03 03 ....qui......s.. | 3968: 07 00 00 0d 72 65 70 72 65 68 65 6e 64 65 72 69 ....reprehenderi | 3984: 74 03 05 07 00 00 03 73 65 64 03 02 02 00 01 03 t......sed...... | 4000: 69 6e 74 03 07 03 00 02 01 74 03 01 05 00 01 03 int......t...... | 4016: 75 6e 74 03 08 02 00 00 06 74 65 6d 70 6f 72 03 unt......tempor. | 4032: 02 05 00 00 07 75 6c 6c 61 6d 63 6f 03 03 0a 00 .....ullamco.... | 4048: 01 01 74 09 02 07 00 01 02 00 01 03 00 00 05 76 ..t............v | 4064: 65 6c 69 74 03 05 0a 00 02 04 6e 69 61 6d 03 03 elit......niam.. | 4080: 06 00 01 08 6f 6c 75 70 74 61 74 65 03 05 09 00 ....oluptate.... | page 5 offset 16384 | 0: 0a 00 00 00 03 0f eb 00 0f fb 0f f3 0f eb 00 00 ................ | 4064: 00 00 00 00 00 00 00 00 00 00 00 07 04 02 08 01 ................ | 4080: 08 00 03 07 04 02 08 01 04 00 02 04 04 08 08 09 ................ | page 6 offset 20480 | 0: 0d 00 00 00 08 0f d0 00 0f fa 0f f4 0f ee 0f e8 ................ | 16: 0f e2 0f dc 0f d6 0f d0 00 00 00 00 00 00 00 00 ................ | 4048: 04 08 03 00 0e 0b 04 07 03 00 0e 06 04 06 03 00 ................ | 4064: 0e 06 04 05 03 00 0e 0a 04 04 03 00 0e 07 04 03 ................ | 4080: 03 00 0e 0a 04 02 03 00 0e 0b 04 01 03 00 0e 08 ................ | page 7 offset 24576 | 0: 0d 00 00 00 01 0f f7 00 0f f7 00 00 00 00 00 00 ................ | 4080: 00 00 00 00 00 00 00 07 00 03 00 14 08 45 b5 03 .............E.. | end crash-f7b636a855e1d2.db }]} {} do_execsql_test 14.1 { PRAGMA writable_schema = 1; WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<10) INSERT INTO t1(a) SELECT randomblob(3000) FROM c; } do_catchsql_test 14.2 { INSERT INTO t1(t1) VALUES('optimize'); } {1 {database disk image is malformed}} #------------------------------------------------------------------------- reset_db do_execsql_test 15.0 { CREATE VIRTUAL TABLE t1 USING fts3(a, content=""); INSERT INTO t1_segdir VALUES(0,0,0,0,'0 665',X'000261640303040002086970697363696e670301080001056c6971756103020c00050269700304040001036d65740301060001036e6a6d03080900010375746503050300000663696c6c756d0306020001066f6d6d6f646f0304070002096e736563746574757203010700050471756174030408000104756c7061030804000207706964617461740307050000086465736572756e740308070001016f0302030002036c6f720601040004050005016506020a00040300010375697303050200000265610304060001066975736d6f640302040001036c69740301090001036e696d13030300010373736503050b0002017403080b0001017403020900010175030604000101780304050002076365707465757203070100020a65726369746174696f6e030309000006667567696174030605000002696403080a0001016e070506040003030002086369646964756e740302060001047073756d030103000104727572650305040000066c61626f7265030208000502697303030b000502756d03080c0001046f72656d0301020000056d61676e6103020b000104696e696d0303050001056f6c6c69740308080000046e6973690304020001026f6e0307060002057374727564030308000104756c6c610306060000086f636361656361740307040001066666696369610308060000087061726961747572030607000107726f6964656e740307070000037175690308050003017303030700000d726570726568656e6465726974030507000003736564030202000103696e7403070300020174030105000103756e7403080200000674656d706f72030205000007756c6c616d636f03030a0001017409020700010200010300000576656c697403050a0002046e69616d0303060001086f6c75707461746503050900'); } do_execsql_test 15.1 { SELECT quote(matchinfo(t1, t1 ))==0 FROM t1 WHERE t1 MATCH 'e*'; } {0 0 0 0 0 0} #------------------------------------------------------------------------- reset_db do_test 16.0 { sqlite3 db {} db deserialize [decode_hexdb { | size 28672 pagesize 4096 filename crash-de7e8cb026385a.db | page 1 offset 0 | 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3. | 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 07 .....@ ........ | 32: 00 00 00 00 00 00 00 00 00 00 00 06 00 00 00 04 ................ | 48: 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 ................ | 96: 00 00 00 00 0d 0e ef 00 07 0d 4d 00 0f bd 0f 5f ..........M...._ | 112: 0e f7 0e 06 0e bc 0d a4 0d 4d 00 00 00 00 00 00 .........M...... | 3392: 00 00 00 00 00 00 00 00 00 00 00 00 00 55 07 07 .............U.. | 3408: 17 1b 1b 01 81 01 74 61 62 6c 65 74 31 5f 73 74 ......tablet1_st | 3424: 61 74 74 31 5f 73 74 61 74 07 43 52 45 41 54 45 att1_stat.CREATE | 3440: 20 54 41 42 4c 45 20 27 74 31 5f 73 74 61 74 27 TABLE 't1_stat' | 3456: 28 69 64 20 49 af 54 45 47 45 52 20 50 52 49 4d (id I.TEGER PRIM | 3472: 41 52 59 20 4b 45 59 2c 20 76 61 6c 75 65 20 42 ARY KEY, value B | 3488: 4c 4f 42 29 60 06 07 17 21 21 01 81 0b 74 61 62 LOB)`...!!...tab | 3504: 6c 65 74 31 5f 64 6f 63 73 69 7a 65 74 31 5f 64 let1_docsizet1_d | 3520: 6f 63 73 69 7a 65 06 43 52 45 41 54 45 20 54 41 ocsize.CREATE TA | 3536: 42 4c 45 20 27 74 31 5f 64 6f 63 73 69 7a 65 27 BLE 't1_docsize' | 3552: 28 64 6f 63 69 64 20 49 4e 54 45 47 45 52 20 50 (docid INTEGER P | 3568: 52 49 4d 41 52 59 20 4b 45 59 2c 20 73 69 7a 65 RIMARY KEY, size | 3584: 20 42 4c 4f 42 29 81 33 04 07 17 1f 1f 01 82 35 BLOB).3.......5 | 3600: 74 61 62 6c 65 74 31 5f 73 65 67 64 69 72 74 31 tablet1_segdirt1 | 3616: 5f 73 65 67 64 69 72 04 43 52 45 41 54 45 20 54 _segdir.CREATE T | 3632: 41 42 4c 45 20 27 74 31 5f 73 65 67 64 69 72 27 ABLE 't1_segdir' | 3648: 28 6c 65 76 65 6c 20 49 4e 54 45 47 45 52 2c 69 (level INTEGER,i | 3664: 64 78 20 49 4e 54 45 47 45 52 2c 73 74 61 72 74 dx INTEGER,start | 3680: 5f 62 6c 6f 63 6b 20 49 4e 54 45 47 45 52 2c 6c _block INTEGER,l | 3696: 65 61 76 65 73 5f 65 6e 64 5f 62 6c 6f 63 6b 20 eaves_end_block | 3712: 49 4e 54 45 47 45 52 2c 65 6e 64 5f 62 6c 6f 63 INTEGER,end_bloc | 3728: 6b 20 49 4e 54 45 47 45 52 2c 72 6f 6f 74 20 42 k INTEGER,root B | 3744: 4c 4f 42 2c 50 52 49 4d 41 52 59 20 4b 45 59 28 LOB,PRIMARY KEY( | 3760: 6c 65 76 65 6c 2c 20 69 64 78 29 29 31 05 06 17 level, idx))1... | 3776: 45 1f 01 00 69 6e 64 65 78 73 71 6c 69 74 65 5f E...indexsqlite_ | 3792: 61 75 74 6f 69 6e 64 65 78 5f 74 31 5f 73 65 67 autoindex_t1_seg | 3808: 64 69 72 5f 31 74 31 5f 73 65 67 64 69 72 05 00 dir_1t1_segdir.. | 3824: 00 00 08 00 00 00 00 66 03 07 17 23 23 01 81 13 .......f...##... | 3840: 74 61 62 6c 65 74 31 5f 73 65 67 6d 65 6e 74 73 tablet1_segments | 3856: 74 31 5f 73 65 67 6d 65 6e 74 73 03 43 52 45 41 t1_segments.CREA | 3872: 54 45 20 54 41 42 4c 45 20 27 74 31 5f 73 65 67 TE TABLE 't1_seg | 3888: 6d 65 6e 74 73 27 28 62 6c 6f 63 6b 69 64 20 49 ments'(blockid I | 3904: 4e 54 45 47 45 52 20 50 52 49 4d 41 52 59 20 4b NTEGER PRIMARY K | 3920: 45 59 2c 20 62 6c 6f 63 6b 20 42 4c 4f 42 29 5c EY, block BLOB). | 3936: 02 07 17 21 21 01 81 03 74 61 62 6c 65 74 31 5f ...!!...tablet1_ | 3952: 63 6f 6e 74 65 6e 74 74 31 5f 63 6f 6e 74 65 6e contentt1_conten | 3968: 74 02 43 52 45 41 54 45 20 54 41 42 4c 45 20 27 t.CREATE TABLE ' | 3984: 74 31 5f 63 6f 6e 74 65 6e 74 27 28 64 6f 63 69 t1_content'(doci | 4000: 64 20 49 4e 54 45 47 45 52 20 50 52 49 4d 41 52 d INTEGER PRIMAR | 4016: 59 20 4b 45 59 2c 20 27 63 30 61 27 29 41 01 06 Y KEY, 'c0a')A.. | 4032: 17 11 11 08 71 74 61 62 6c 65 74 31 74 31 43 52 ....qtablet1t1CR | 4048: 45 41 54 45 20 56 49 52 54 55 41 4c 20 54 41 42 EATE VIRTUAL TAB | 4064: 4c 45 20 74 31 20 55 53 49 4e 47 20 66 74 73 34 LE t1 USING fts4 | 4080: 28 61 2c 70 72 65 66 69 78 3d 27 31 2c 32 27 29 (a,prefix='1,2') | page 2 offset 4096 | 0: 0d 00 00 00 08 0e 1f 00 0f c4 0f 7c 0f 34 0f 07 ...........|.4.. | 16: 0e c3 0e 97 0e 63 0e 1f 00 00 00 00 00 00 00 00 .....c.......... | 3600: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 42 ...............B | 3616: 08 04 00 81 09 73 75 6e 74 20 69 6e 20 63 75 6c .....sunt in cul | 3632: 70 61 20 71 75 69 20 6f 66 66 69 63 69 61 20 64 pa qui officia d | 3648: 65 73 65 72 75 6e 74 20 6d 6f 6c 6c 69 74 20 61 eserunt mollit a | 3664: 6e 69 6d 20 69 64 20 65 73 74 20 6c 61 62 6f 72 nim id est labor | 3680: 75 6d 2e 32 07 03 00 6b 45 78 63 65 70 74 65 75 um.2...kExcepteu | 3696: 72 20 73 69 6e 74 20 6f 63 63 61 65 63 61 74 20 r sint occaecat | 3712: 63 75 70 69 64 61 74 61 74 20 6e 6f 6e 20 70 72 cupidatat non pr | 3728: 6f 69 64 65 6e 74 2c 2a 06 03 00 5b 63 69 6c 6c oident,*...[cill | 3744: 75 6d 20 64 6f 6c 6f 72 65 20 65 75 20 66 75 67 um dolore eu fug | 3760: 69 61 74 20 6e 75 6c 6c 61 20 70 61 72 69 61 74 iat nulla pariat | 3776: 75 72 2e 42 05 04 00 81 09 44 75 69 73 20 61 75 ur.B.....Duis au | 3792: 74 65 20 69 72 75 72 65 21 64 6f 6c 6f 72 20 69 te irure!dolor i | 3808: 6e 20 72 65 70 72 65 68 65 6e 64 65 72 69 74 20 n reprehenderit | 3824: 69 6e 20 76 6f 6c 75 70 74 61 74 65 20 76 65 6c in voluptate vel | 3840: 69 74 20 65 73 74 65 2b 04 03 00 5d 6e 69 73 69 it este+...]nisi | 3856: 20 75 74 20 61 6c 69 71 75 69 70 20 65 78 20 65 ut aliquip ex e | 3872: 61 20 63 6f 6d 6d 6f 64 6f 20 63 6f 6e 73 65 71 a commodo conseq | 3888: 75 61 74 2e 46 03 04 00 81 11 55 74 20 65 6e 69 uat.F.....Ut eni | 3904: 6d 20 61 64 20 6d 69 6e 69 6d 20 76 65 6e 69 61 m ad minim venia | 3920: 6d 2c 20 71 75 69 73 20 6e 6f 73 74 72 75 64 20 m, quis nostrud | 3936: 65 78 65 72 63 69 74 61 74 69 6f 6e 20 75 6c 6c exercitation ull | 3952: 61 6d 63 6f 20 6c 61 62 6f 72 69 73 46 02 04 00 amco laborisF... | 3968: 81 11 73 65 64 20 64 6f 20 65 69 75 73 6d 6f 64 ..sed do eiusmod | 3984: 20 74 65 6d 70 6f 72 20 69 6e 63 69 64 69 64 75 tempor incididu | 4000: 6e 74 20 75 74 20 6c 61 62 6f 72 65 20 65 74 20 nt ut labore et | 4016: 64 6f 6c 6f 72 65 20 6d 61 67 6e 61 20 51 6c 69 dolore magna Qli | 4032: 71 75 61 2e 3a 01 03 00 7b 4c 6f 72 65 6d 20 69 qua.:....Lorem i | 4048: 70 73 75 6d 20 64 6f 6c 6f 72 20 73 69 74 e5 61 psum dolor sit.a | 4064: 6d 65 74 2c 20 63 6f 6e 73 65 63 74 65 74 75 72 met, consectetur | 4080: 20 61 64 69 70 69 73 63 69 6e 67 20 65 6c 69 74 adipiscing elit | page 3 offset 8192 | 0: 0d 00 00 00 00 10 00 00 00 00 00 00 00 00 00 00 ................ | page 4 offset 12288 | 0: 0d 00 00 00 03 0a a6 00 0d 57 0c 4a 0a a6 00 00 .........W.J.... | 2720: 00 00 00 00 00 00 83 21 03 08 02 08 08 08 17 86 .......!........ | 2736: 30 08 00 30 20 34 30 32 00 02 61 64 06 01 08 00 0..0 402..ad.... | 2752: 02 04 00 01 01 6c 06 02 0c 00 02 04 00 01 01 6d .....l.........m | 2768: 03 01 06 00 01 01 6e 03 08 09 00 01 01 75 03 05 ......n......u.. | 2784: 03 00 00 02 63 69 03 06 02 00 01 01 6f 07 01 07 ....ci......o... | 2800: 00 03 07 03 00 01 01 75 06 07 05 00 01 04 00 00 .......u........ | 2816: 02 64 65 03 08 07 00 01 01 6f 0d 01 04 00 01 03 .de......o...... | 2832: 09 00 03 05 00 01 03 00 01 01 75 03 05 02 00 00 ..........u..... | 2848: 02 65 61 03 04 06 00 01 01 69 03 02 04 00 01 01 .ea......i...... | 2864: 6c 03 01 09 00 01 01 6e 03 03 03 00 01 01 73 06 l......n......s. | 2880: 05 0b 00 03 0b 00 01 01 74 03 02 09 00 01 01 75 ........t......u | 2896: 03 06 04 00 01 01 78 09 03 09 00 01 05 00 03 02 ......x......... | 2912: 00 00 02 66 75 03 06 05 00 00 02 69 64 03 08 0a ...fu......id... | 2928: 00 01 01 6e 0a 02 06 00 03 06 04 00 03 03 00 01 ...n............ | 2944: 01 70 03 01 03 00 01 01 72 03 05 04 00 00 02 6c .p......r......l | 2960: 61 09 02 08 00 01 0b 00 05 0c 00 01 01 6f 03 01 a............o.. | 2976: 02 00 00 02 6d 61 03 02 0b 00 01 01 69 03 03 05 ....ma......i... | 2992: 00 01 01 6f 03 08 08 00 00 02 6e 69 03 04 02 00 ...o......ni.... | 3008: 01 01 6f 06 03 08 00 04 06 00 01 01 75 03 06 06 ..o.........u... | 3024: 00 00 02 6f 63 03 07 04 00 01 01 66 03 08 06 00 ...oc......f.... | 3040: 00 02 70 61 03 06 07 00 01 01 72 03 07 07 00 00 ..pa......r..... | 3056: 02 71 75 06 03 07 00 05 05 00 00 02 72 65 03 05 .qu.........re.. | 3072: 07 00 00 02 73 65 03 02 02 00 01 01 69 06 01 05 ....se......i... | 3088: 00 06 03 00 01 01 75 03 08 02 00 00 02 74 65 03 ......u......te. | 3104: 02 05 00 00 02 75 6c 03 03 0a 00 01 01 74 09 02 .....ul......t.. | 3120: 07 00 01 02 00 01 03 00 00 02 76 65 06 03 06 00 ..........ve.... | 3136: 02 0a 00 01 01 6f 03 05 09 00 82 0a 02 08 12 08 .....o.......... | 3152: 08 08 17 84 02 04 00 30 20 32 35 31 00 01 61 23 .......0 251..a# | 3168: 01 06 04 00 01 0c 00 01 04 00 01 04 00 01 03 00 ................ | 3184: 03 09 00 00 01 63 10 01 07 00 03 07 03 00 02 02 .....c.......... | 3200: 00 01 05 00 01 04 00 00 01 64 11 01 04 00 01 03 .........d...... | 3216: 09 00 03 02 05 00 01 13 00 02 07 00 00 01 65 1b ..............e. | 3232: 01 09 00 01 04 07 00 01 03 08 00 01 05 03 00 01 ................ | 3248: 0b 00 01 04 00 01 02 00 01 0b 00 00 01 66 03 06 .............f.. | 3264: 05 00 00 01 69 0f 01 03 00 01 06 00 03 04 04 04 ....i........... | 3280: 00 03 03 09 00 00 01 6c 0c 01 02 00 01 08 00 01 .......l........ | 3296: 0b 00 05 0c 00 10 01 6d 09 02 0b 00 01 05 00 05 .......m........ | 3312: 08 00 00 01 6e 0c 03 08 00 01 02 00 02 06 00 01 ....n........... | 3328: 06 00 00 01 6f 06 07 04 00 01 06 00 00 01 70 06 ....o.........p. | 3344: 06 07 00 01 07 00 00 01 71 06 03 07 00 05 05 00 ........q....... | 3360: 00 01 72 03 05 07 00 00 01 73 0c 01 05 00 01 02 ..r......s...... | 3376: 00 05 03 00 01 02 00 00 01 74 03 02 05 00 00 01 .........t...... | 3392: 75 0a 02 07 00 01 02 0a 00 01 03 00 00 01 76 07 u.............v. | 3408: 03 06 00 02 09 03 00 85 26 01 08 08 08 08 08 17 ........&....... | 3424: 8a 3e 30 20 36 36 35 00 02 61 64 03 03 04 00 02 .>0 665..ad..... | 3440: 08 69 70 69 73 63 69 6e 67 03 01 08 00 01 05 6c .ipiscing......l | 3456: 69 71 75 61 03 02 0c 00 05 02 69 70 03 04 04 00 iqua......ip.... | 3472: 01 03 6d 65 74 03 01 06 00 01 03 6e 69 6d 03 08 ..met......nim.. | 3488: 09 00 01 03 75 74 65 03 05 03 00 00 06 63 69 6c ....ute......cil | 3504: 6c 75 6d 03 06 02 00 01 06 6f 6d 6d 6f 64 6f 03 lum......ommodo. | 3520: 04 07 00 02 09 6e 73 65 63 74 65 74 75 72 03 01 .....nsectetur.. | 3536: 07 00 05 04 71 75 61 74 03 04 08 00 01 04 75 6c ....quat......ul | 3552: 70 61 03 08 04 00 02 07 70 69 64 61 74 61 74 03 pa......pidatat. | 3568: 07 05 00 00 08 64 65 73 65 72 75 6e 74 03 08 07 .....deserunt... | 3584: 00 01 01 6f 03 02 03 00 02 03 6c 6f 72 06 01 04 ...o......lor... | 3600: 00 04 05 00 05 01 65 06 02 0a 00 04 03 00 01 03 ......e......... | 3616: 75 69 73 03 05 02 00 00 02 65 61 03 04 06 00 01 uis......ea..... | 3632: 06 69 75 73 6d 6f 64 03 02 04 00 01 03 6c 69 74 .iusmod......lit | 3648: 03 01 09 00 01 03 6e 69 6d 03 03 03 00 01 03 73 ......nim......s | 3664: 73 65 03 05 0b 00 02 01 74 03 08 0b 00 01 01 74 se......t......t | 3680: 03 02 09 00 01 01 75 03 06 04 00 01 01 78 03 04 ......u......x.. | 3696: 05 00 02 07 63 65 70 74 65 75 72 03 07 02 00 02 ....cepteur..... | 3712: 0a 65 72 63 69 74 61 74 69 6f 6e 03 03 09 00 00 .ercitation..... | 3728: 06 66 75 67 69 61 74 03 06 05 00 00 02 69 64 03 .fugiat......id. | 3744: 08 0a 00 01 01 6e 07 05 06 04 00 03 03 00 02 08 .....n.......... | 3760: 63 69 64 69 64 75 7e 74 03 02 06 00 01 04 70 73 cididu~t......ps | 3776: 75 6d 03 01 03 00 01 03 72 75 72 65 03 05 04 00 um......rure.... | 3792: 00 06 6c 61 62 6f 72 65 03 02 08 00 05 02 69 73 ..labore......is | 3808: 03 03 0b 00 05 02 75 6d 03 08 0c 00 01 04 6f 72 ......um......or | 3824: 65 6d 03 01 02 00 00 05 6d 61 67 6e 61 03 02 0b em......magna... | 3840: 00 01 04 69 6e 69 6d 03 03 05 00 01 05 6f 6c 6c ...inim......oll | 3856: 69 74 03 08 08 00 00 04 6e 69 73 69 03 04 02 00 it......nisi.... | 3872: 01 02 6f 6e 03 07 06 00 02 05 73 74 72 75 64 03 ..on......strud. | 3888: 03 08 00 01 04 75 6c 6c 61 03 06 06 00 00 08 6f .....ulla......o | 3904: 63 63 61 65 63 61 74 03 07 04 00 01 06 66 66 69 ccaecat......ffi | 3920: 63 69 61 03 08 06 00 00 08 70 61 72 69 61 74 75 cia......pariatu | 3936: 72 03 06 07 00 01 07 72 6f 69 64 65 6e 74 03 07 r......roident.. | 3952: 07 00 00 03 71 75 69 03 08 05 00 03 01 73 03 03 ....qui......s.. | 3968: 07 00 00 0d 72 65 70 72 65 68 65 6e 64 65 72 69 ....reprehenderi | 3984: 74 03 05 07 00 00 03 73 65 64 03 02 02 00 01 03 t......sed...... | 4000: 69 6e 74 03 07 03 00 02 01 74 03 01 05 00 01 03 int......t...... | 4016: 75 6e 74 03 08 02 00 00 06 74 65 6d 70 6f 72 03 unt......tempor. | 4032: 02 05 00 00 07 75 6c 6c 61 6d 63 6f 03 03 0a 00 .....ullamco.... | 4048: 01 01 74 09 02 07 00 01 02 00 01 03 00 00 05 76 ..t............v | 4064: 65 6c 69 74 03 05 0a 00 02 04 6e 69 61 6d 03 03 elit......niam.. | 4080: 06 00 01 08 6f 6c 75 70 74 61 74 65 03 05 09 00 ....oluptate.... | page 5 offset 16384 | 0: 0a 00 00 00 03 0f eb 00 0f fb 0f f3 0f eb 00 00 ................ | 4064: 00 00 00 00 00 00 00 00 00 00 00 07 04 02 08 01 ................ | 4080: 08 00 03 07 04 02 08 03 a4 00 02 04 04 08 08 09 ................ | page 6 offset 20480 | 0: 0d 00 00 00 08 0f d0 00 0f fa 0f f4 0f ee 0f e8 ................ | 16: 0f e2 0f dc 0f d6 0f d0 00 00 00 00 00 00 00 00 ................ | 4048: 04 08 03 00 0e 0b 04 07 03 00 0e 06 04 06 03 00 ................ | 4064: 0e 06 04 05 03 00 0e 0a 04 04 03 00 0e 07 04 03 ................ | 4080: 03 00 0e 0a 04 02 03 00 0e 0b 04 01 03 00 0e 08 ................ | page 7 offset 24576 | 0: 0d 00 00 00 01 0f f7 00 0f f7 00 00 00 00 00 00 ................ | 4080: 00 00 00 00 00 00 00 07 00 03 00 14 08 45 b5 03 .............E.. | end crash-de7e8cb026385a.db }]} {} do_catchsql_test 16.1 { INSERT INTO t1(t1) VALUES('optimize'); } {0 {}} #------------------------------------------------------------------------- reset_db do_test 17.0 { sqlite3 db {} db deserialize [decode_hexdb { .open --hexdb | size 28672 pagesize 4096 filename crash-f15972acf5bc1c.db | page 1 offset 0 | 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3. | 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 07 .....@ ........ | 32: 00 00 00 02 00 00 00 01 00 00 00 07 00 00 00 04 ................ | 48: 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 ................ | 96: 00 00 00 00 0d 0e b1 00 06 0d a4 00 0f 8d 0f 21 ...............! | 112: 0e b9 0d c8 0e 7e 0d a4 0d a4 00 00 00 00 00 00 .....~.......... | 3488: 00 00 00 00 22 07 06 17 11 11 01 31 74 61 62 6c ...........1tabl | 3504: 65 74 32 74 32 07 43 52 45 41 54 45 20 54 41 42 et2t2.CREATE TAB | 3520: 4c 45 20 74 32 28 78 29 81 33 05 07 17 1f 1f 01 LE t2(x).3...... | 3536: 82 35 74 61 62 6c 65 74 31 5f 73 65 67 64 69 72 .5tablet1_segdir | 3552: 74 31 5f 73 65 67 64 69 72 05 43 52 45 41 54 45 t1_segdir.CREATE | 3568: 20 54 41 42 4c 45 20 27 74 31 5f 73 65 67 64 69 TABLE 't1_segdi | 3584: 72 27 28 6c 65 76 65 6c 20 49 4e 54 45 47 45 52 r'(level INTEGER | 3600: 2c 69 64 78 20 49 4e 54 45 47 45 52 2c 73 74 61 ,idx INTEGER,sta | 3616: 72 74 5f 62 6c 6f 63 6b 20 49 4e 54 45 47 45 52 rt_block INTEGER | 3632: 2c 6c 65 61 76 65 73 5f 65 6e 64 5f 62 6c 6f 63 ,leaves_end_bloc | 3648: 6b 20 49 4e 54 45 47 45 52 2c 65 6e 64 5f 62 6c k INTEGER,end_bl | 3664: 6f 63 6b 20 49 4e 54 45 47 45 52 2c 72 6f 6f 74 ock INTEGER,root | 3680: 20 42 4c 4f 42 2c 50 52 49 4d 41 52 59 20 4b 45 BLOB,PRIMARY KE | 3696: 59 28 6c 65 76 65 6c 2c 20 69 64 78 29 29 31 06 Y(level, idx))1. | 3712: 06 17 45 1f 01 00 69 6e 64 65 78 73 71 6c 69 74 ..E...indexsqlit | 3728: 65 5f 61 75 74 6f 69 6e 64 65 78 5f 74 31 5f 73 e_autoindex_t1_s | 3744: 65 67 64 69 72 5f 31 74 31 5f 73 65 67 64 69 72 egdir_1t1_segdir | 3760: 06 0f c7 00 08 00 00 00 00 66 04 07 17 23 23 01 .........f...##. | 3776: 81 13 74 61 62 6c 65 74 31 5f 73 65 67 6d 65 6e ..tablet1_segmen | 3792: 74 73 74 31 5f 73 65 67 6d 65 6e 74 73 04 43 52 tst1_segments.CR | 3808: 45 41 54 45 20 54 41 42 4c 45 20 27 74 31 5f 73 EATE TABLE 't1_s | 3824: 65 67 6d 65 6e 74 73 27 28 62 6c 6f 63 6b 69 64 egments'(blockid | 3840: 20 49 4e 54 45 47 45 52 20 50 52 49 4d 41 52 59 INTEGER PRIMARY | 3856: 20 4b 45 59 2c 20 62 6c 6f 63 6b 20 42 4c 4f 42 KEY, block BLOB | 3872: 29 6a 03 07 17 21 21 01 81 1f 74 61 62 6c 65 74 )j...!!...tablet | 3888: 31 5f 63 6f 6e 74 65 6e 74 74 31 5f 63 6f 6e 74 1_contentt1_cont | 3904: 65 6e 74 03 43 52 45 41 54 45 20 54 41 42 4c 45 ent.CREATE TABLE | 3920: 20 27 74 31 5f 63 6f 6e 74 65 6e 74 27 28 64 6f 't1_content'(do | 3936: 63 69 64 20 49 4e 54 45 47 45 52 20 50 52 49 4d cid INTEGER PRIM | 3952: 41 52 59 20 4b 45 59 2c 20 27 63 30 61 27 2c 20 ARY KEY, 'c0a', | 3968: 27 63 31 62 27 2c 20 27 63 32 63 27 29 38 02 06 'c1b', 'c2c')8.. | 3984: 17 11 11 08 5f 74 61 62 6c 65 74 31 74 31 43 52 ...._tablet1t1CR | 4000: 45 41 54 45 20 56 49 52 54 55 41 4c 20 54 41 42 EATE VIRTUAL TAB | 4016: 4c 45 20 74 31 20 55 53 49 4e 47 20 66 74 73 33 LE t1 USING fts3 | 4032: 28 61 2c 62 2c 63 29 00 00 00 39 00 00 00 00 00 (a,b,c)...9..... | page 3 offset 8192 | 0: 0d 00 00 00 25 0b 48 00 0f d8 0f af 0f 86 0f 74 ....%.H........t | 16: 0f 61 0f 4e 0f 2f 0f 0f 0e ef 0e d7 0e be 0e a5 .a.N./.......... | 32: 0e 8d 0e 74 0e 5b 0e 40 0e 24 0e 08 0d ef 0d d5 ...t.[.@.$...... | 48: 0d bb 0d a0 0d 84 03 28 0d 4f 0d 35 0d 1b 0c fb .......(.O.5.... | 64: 0c da 0c b9 0c 99 0c 78 0c 57 0c 3e 0c 24 0c 0a .......x.W.>.$.. | 80: 0b 48 00 00 00 00 00 00 00 00 00 00 00 00 00 00 .H.............. | 2880: 00 00 00 00 00 00 00 00 81 3f 25 06 00 72 7f 00 .........?%..r.. | 2896: 00 43 4f 4d 50 49 4c 45 52 3d 67 63 63 2d 35 2e .COMPILER=gcc-5. | 2912: 34 2e 30 20 32 30 31 36 30 36 30 39 20 44 45 42 4.0 20160609 DEB | 2928: 55 47 20 45 4e 41 42 4c 45 20 44 42 53 54 41 54 UG ENABLE DBSTAT | 2944: 20 56 54 41 42 20 45 4e 41 42 4c 45 20 46 54 53 VTAB ENABLE FTS | 2960: 34 20 45 4e 41 42 4c 45 20 46 54 53 35 20 45 4e 4 ENABLE FTS5 EN | 2976: 41 42 4c 45 20 47 45 4f 50 4f 4c 59 20 45 4e 41 ABLE GEOPOLY ENA | 2992: 42 4c 45 20 4a 53 4f 4e 31 20 45 4e 41 42 4c 45 BLE JSON1 ENABLE | 3008: 20 4d 45 4d 53 59 53 35 20 45 4e 41 42 4c 45 20 MEMSYS5 ENABLE | 3024: 52 54 52 45 45 20 4d 41 58 20 4d 45 4d 4f 52 59 RTREE MAX MEMORY | 3040: 3d 35 30 30 30 30 30 30 30 20 4f 4d 49 54 20 4c =50000000 OMIT L | 3056: 4f 41 43 20 45 58 54 45 4e 53 49 4f 4e 20 54 48 OAC EXTENSION TH | 3072: 52 45 41 44 53 41 46 45 3d 30 18 24 05 00 25 0f READSAFE=0.$..%. | 3088: 19 54 48 52 45 41 44 53 41 46 45 3d 30 58 42 49 .THREADSAFE=0XBI | 3104: 4e 41 52 59 18 23 05 00 25 0f 19 54 48 52 45 41 NARY.#..%..THREA | 3120: 44 53 41 46 45 3d 30 58 4e 4f 43 41 53 45 17 22 DSAFE=0XNOCASE.. | 3136: 05 00 25 0f 17 54 48 52 45 41 44 53 41 46 45 3d ..%..THREADSAFE= | 3152: 30 58 52 54 52 49 4d 1f 21 05 00 33 0f 19 4f 4d 0XRTRIM.!..3..OM | 3168: 49 54 20 4c 4f 41 44 20 45 58 54 45 4e 53 49 4f IT LOAD EXTENSIO | 3184: 4e 58 42 49 4e 41 52 59 1f 20 05 00 33 0f 19 4f NXBINARY. ..3..O | 3200: 4d 49 54 20 4c 4f 41 44 20 45 58 54 45 4e 53 49 MIT LOAD EXTENSI | 3216: 4f 4e 58 4e 4f 43 41 53 45 1e 1f 05 00 33 0f 17 ONXNOCASE....3.. | 3232: 4f 4d 49 54 20 4c 4f 41 44 20 45 58 54 45 4e 53 OMIT LOAD EXTENS | 3248: 49 4f 4e 58 52 54 52 49 4d 1f 1e 05 00 33 0f 19 IONXRTRIM....3.. | 3264: 4d 41 58 20 4d 45 4d 4f 52 59 3d 35 30 30 30 30 MAX MEMORY=50000 | 3280: 30 30 30 58 42 49 4e 41 52 59 1f 1d 05 00 33 0f 000XBINARY....3. | 3296: 19 4d 41 58 20 4d 45 4d 4f 52 59 3d 35 30 30 30 .MAX MEMORY=5000 | 3312: 30 30 30 30 58 4e 4f 43 41 53 45 1e 1c 05 00 33 0000XNOCASE....3 | 3328: 0f 17 4d 41 58 20 4d 45 4d 4f 52 59 3d 35 30 30 ..MAX MEMORY=500 | 3344: 30 30 30 30 30 58 52 54 52 49 4d 18 1b 05 00 25 00000XRTRIM....% | 3360: 0f 19 45 4e 41 42 4c 45 20 52 54 52 45 45 58 42 ..ENABLE RTREEXB | 3376: 49 4e 41 52 59 18 1a 05 00 25 0f 19 45 4e 41 42 INARY....%..ENAB | 3392: 4c 45 20 52 54 52 45 45 58 4e 4f 43 41 53 45 17 LE RTREEXNOCASE. | 3408: 19 05 00 25 0f 17 45 4e 41 42 4c 45 20 52 54 52 ...%..ENABLE RTR | 3424: 45 45 58 52 54 52 49 4d 1a 18 05 00 29 0f 19 45 EEXRTRIM....)..E | 3440: 4e 41 42 4c 45 20 4d 45 4d 53 59 53 35 58 42 49 NABLE MEMSYS5XBI | 3456: 4e 41 52 59 1a 17 05 00 29 0f 19 45 4e 41 42 4c NARY....)..ENABL | 3472: 45 20 4d 45 4d 53 59 53 35 58 4e 4f 43 41 53 45 E MEMSYS5XNOCASE | 3488: 19 16 05 00 29 0f 17 45 4e 41 42 4c 45 20 4d 45 ....)..ENABLE ME | 3504: 4d 53 59 53 35 58 52 54 52 49 4d 18 14 05 00 25 MSYS5XRTRIM....% | 3520: 0f 19 45 4e 41 42 4c 45 20 4a 53 4f 4e 31 58 42 ..ENABLE JSON1XB | 3536: 49 4e 41 52 59 18 14 05 00 25 0f 19 45 4e 41 42 INARY....%..ENAB | 3552: 4c 45 20 4a 53 4f 4e 31 58 4e 4f 43 41 53 45 17 LE JSON1XNOCASE. | 3568: 13 05 00 25 0f 17 45 4e 41 42 4c 45 20 4a 53 4f ...%..ENABLE JSO | 3584: 4e 31 58 52 54 52 49 4d 1a 12 05 00 29 0f 19 45 N1XRTRIM....)..E | 3600: 4e 41 42 4c 45 20 47 45 4f 50 4f 4c 59 58 42 49 NABLE GEOPOLYXBI | 3616: 4e 41 52 59 1a 11 05 00 29 0f 19 45 4e 41 42 4c NARY....)..ENABL | 3632: 45 20 47 45 4f 50 4f 4c 59 58 4e 4f 43 41 53 45 E GEOPOLYXNOCASE | 3648: 19 10 05 00 29 0f 17 45 4e 41 42 4c 45 20 47 45 ....)..ENABLE GE | 3664: 4f 50 4f 4c 59 58 52 54 52 49 4d 17 0f 05 00 23 OPOLYXRTRIM....# | 3680: 0f 19 45 4e 41 42 4c 45 20 46 54 53 35 58 42 49 ..ENABLE FTS5XBI | 3696: 4e 41 52 59 17 0e 05 00 23 0f 19 45 4e 41 42 4c NARY....#..ENABL | 3712: 45 20 46 54 53 35 58 4e 4f 43 41 53 45 16 0d 05 E FTS5XNOCASE... | 3728: 00 23 0f 17 45 4e 41 42 4c 45 20 46 54 53 35 58 .#..ENABLE FTS5X | 3744: 52 54 52 49 4d 17 0c 05 00 23 0f 19 45 4e 41 42 RTRIM....#..ENAB | 3760: 4c 45 20 46 54 53 34 58 42 49 4e 41 52 59 17 0b LE FTS4XBINARY.. | 3776: 05 00 23 0f 19 45 4e 41 42 4c 45 20 46 54 53 34 ..#..ENABLE FTS4 | 3792: 58 4e 4f 43 41 53 45 16 0a 05 00 23 0f 17 45 4e XNOCASE....#..EN | 3808: 41 42 4c 45 20 46 54 53 34 58 52 54 52 49 4d 1e ABLE FTS4XRTRIM. | 3824: 09 05 00 31 0f 19 45 4e 41 42 4c 45 20 44 42 53 ...1..ENABLE DBS | 3840: 54 41 54 20 56 54 41 42 58 42 49 4e 41 52 59 1e TAT VTABXBINARY. | 3856: 08 05 00 31 0f 19 45 4e 41 42 4c 45 20 44 42 53 ...1..ENABLE DBS | 3872: 54 41 54 20 56 54 41 42 58 4e 4f 43 41 53 45 1d TAT VTABXNOCASE. | 3888: 07 05 00 31 0f 17 45 4e 41 42 4c 45 20 44 42 53 ...1..ENABLE DBS | 3904: 54 41 54 20 56 54 41 42 58 52 54 52 49 4d 11 06 TAT VTABXRTRIM.. | 3920: 05 00 17 0f 19 44 45 42 55 47 58 42 49 4e 41 52 .....DEBUGXBINAR | 3936: 59 11 05 05 00 17 0e 19 44 45 42 55 47 58 4e 4f Y.......DEBUGXNO | 3952: 43 41 53 45 10 04 05 00 17 0f 17 44 45 42 55 47 CASE.......DEBUG | 3968: 58 52 54 52 49 4d 27 03 05 00 43 0f 19 43 4f 4d XRTRIM'...C..COM | 3984: 50 49 4c 45 52 3d 67 63 63 2d 35 2e 34 2e 30 20 PILER=gcc-5.4.0 | 4000: 32 30 31 36 30 36 30 39 58 42 49 4e 41 52 59 27 20160609XBINARY' | 4016: 02 05 00 43 0f 19 43 4f 4d 50 49 4c 45 52 3d 67 ...C..COMPILER=g | 4032: 63 63 2d 35 2e 34 2e 30 20 32 30 31 36 30 36 30 cc-5.4.0 2016060 | 4048: 39 58 4e 4f 43 41 53 45 26 01 05 00 43 0f 17 43 9XNOCASE&...C..C | 4064: 4f 4d 50 49 4c 45 52 3d 67 63 63 2d 35 2e 34 2e OMPILER=gcc-5.4. | 4080: 30 20 32 30 31 36 30 36 30 39 58 52 54 52 49 4d 0 20160609XRTRIM | page 4 offset 12288 | 0: 0d 00 00 00 00 10 00 00 00 00 00 00 00 00 00 00 ................ | page 5 offset 16384 | 0: 0d 00 00 00 02 0b a0 00 0c ad 0b a0 00 00 00 00 ................ | 2976: 82 0a 02 08 08 09 08 08 17 84 06 30 20 32 35 33 ...........0 253 | 2992: 00 01 30 04 25 06 1b 00 00 08 32 30 31 36 30 36 ..0.%.....201606 | 3008: 30 39 03 25 07 00 00 01 34 03 25 05 00 00 01 35 09.%....4.%....5 | 3024: 03 25 04 00 01 07 30 30 30 30 30 30 30 03 25 1a .%....0000000.%. | 3040: 00 00 08 63 6f 6d 70 69 6c 65 72 03 25 02 00 00 ...compiler.%... | 3056: 06 64 62 73 74 61 74 03 25 0a 00 01 04 65 62 75 .dbstat.%....ebu | 3072: 67 03 25 08 00 00 06 65 6e 61 62 6c 65 09 25 09 g.%....enable.%. | 3088: 05 04 04 04 04 04 00 01 08 78 74 65 6e 73 69 6f .........xtensio | 3104: 6e 03 25 1d 00 00 04 66 74 73 34 03 25 0d 00 03 n.%....fts4.%... | 3120: 01 35 03 25 0f 00 00 03 67 63 63 03 25 03 00 01 .5.%....gcc.%... | 3136: 06 65 6f 70 6f 6c 79 03 25 11 00 00 05 6a 73 6f .eopoly.%....jso | 3152: 6e 31 03 25 13 00 00 04 6c 6f 61 64 03 25 1c 00 n1.%....load.%.. | 3168: 00 03 6d 61 78 03 25 18 00 01 05 65 6d 6f 72 79 ..max.%....emory | 3184: 03 25 19 00 03 04 73 79 73 4d 03 25 15 00 00 04 .%....sysM.%.... | 3200: 6f 6d 69 74 03 25 1b 00 00 05 72 74 72 65 65 03 omit.%....rtree. | 3216: 25 17 00 00 0a 74 68 72 65 61 64 73 61 66 65 03 %....threadsafe. | 3232: 25 0e 00 00 04 76 74 61 62 03 25 0b 00 86 50 01 %....vtab.%...P. | 3248: 08 08 08 08 08 17 8d 12 30 20 38 33 35 00 01 30 ........0 835..0 | 3264: 12 01 06 00 01 06 00 01 06 00 1f 03 00 01 03 00 ................ | 3280: 01 03 00 00 08 32 30 31 36 30 36 30 39 09 01 07 .....20160609... | 3296: 00 01 07 00 01 07 00 00 01 34 09 01 05 00 01 05 .........4...... | 3312: 00 01 05 00 00 01 35 09 01 04 00 01 04 00 01 04 ......5......... | 3328: 00 01 07 30 30 30 30 30 30 30 09 1c 04 00 01 04 ...0000000...... | 3344: 00 01 04 00 00 06 62 69 6e 61 72 79 3c 03 01 02 ......binary<... | 3360: 02 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 ................ | 3376: 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 00 ................ | 3392: 03 01 02 02 00 03 01 02 02 00 03 01 02 02 00 03 ................ | 3408: 01 02 02 00 03 01 02 02 00 00 08 63 6f 6d 70 69 ...........compi | 3424: 6c 65 72 09 01 02 00 01 02 00 01 02 00 00 06 64 ler............d | 3440: 62 73 74 61 74 09 07 03 00 01 03 00 01 03 00 01 bstat........... | 3456: 04 65 62 75 67 09 04 02 00 01 02 00 01 02 00 00 .ebug........... | 3472: 06 65 6e 61 62 6c 65 3f 07 02 00 01 02 00 01 02 .enable?........ | 3488: 00 01 02 00 01 02 00 01 02 00 01 02 00 01 02 00 ................ | 3504: 01 02 00 01 02 00 01 02 00 01 02 00 01 02 00 01 ................ | 3520: 02 00 01 02 00 01 02 00 01 02 00 01 02 00 01 02 ................ | 3536: 00 01 02 00 01 02 00 01 08 78 74 65 6e 73 69 6f .........xtensio | 3552: 6e 09 1f 04 00 01 04 00 01 04 00 00 04 66 74 73 n............fts | 3568: 34 09 0a 03 00 01 03 00 01 03 00 03 01 35 09 0d 4............5.. | 3584: 03 00 01 03 00 01 03 00 00 03 67 63 63 09 01 03 ..........gcc... | 3600: 00 01 03 00 01 03 00 01 06 65 6f 70 6f 6c 79 09 .........eopoly. | 3616: 10 03 00 01 03 00 01 03 00 00 05 6a 73 6f 6e 31 ...........json1 | 3632: 09 13 03 00 01 03 00 01 03 00 00 04 6c 6f 61 64 ............load | 3648: 09 1f 03 00 01 03 00 01 03 00 00 03 6d 61 78 09 ............max. | 3664: 1c 02 00 01 02 00 01 02 00 01 05 65 6d 6f 72 79 ...........emory | 3680: 09 1c 03 00 01 03 00 01 03 00 03 04 73 79 73 35 ............sys5 | 3696: 09 16 03 00 01 03 00 01 03 00 00 06 6e 6f 63 61 ............noca | 3712: 73 65 3c 02 01 02 02 00 03 01 02 02 00 03 01 02 se<............. | 3728: 02 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 ................ | 3744: 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 00 ................ | 3760: 03 01 02 02 00 03 01 02 02 00 03 01 02 02 00 00 ................ | 3776: 04 6f 6d 69 74 09 1f 02 00 01 02 00 01 02 00 00 .omit........... | 3792: 05 72 74 72 65 65 09 19 03 00 01 03 00 01 03 00 .rtree.......... | 3808: 03 02 69 6d 3c 01 01 02 02 00 03 01 02 02 00 03 ..im<........... | 3824: 01 02 02 00 03 01 02 02 00 03 01 02 02 00 03 01 ................ | 3840: 02 02 00 03 01 02 02 00 03 01 02 02 00 03 01 02 ................ | 3856: 02 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 ................ | 3872: 00 00 0a 74 68 72 65 61 64 73 61 66 65 09 22 02 ...threadsafe... | 3888: 00 01 02 00 01 02 00 00 04 76 74 61 62 09 07 04 .........vtab... | 3904: 00 01 04 00 01 04 00 00 01 78 b4 01 01 01 01 02 .........x...... | 3920: 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 ................ | 3936: 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 01 ................ | 3952: 01 01 02 00 01 01 01 02 00 01 01 01 02 00 01 01 ................ | 3968: 01 02 00 01 01 01 02 00 01 01 01 02 00 01 01 01 ................ | 3984: 02 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 ................ | 4000: 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 ................ | 4016: 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 01 ................ | 4032: 01 01 02 00 01 01 01 02 00 01 01 01 02 00 01 01 ................ | 4048: 01 02 00 01 01 01 02 00 01 01 01 02 00 01 01 01 ................ | 4064: 02 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 ................ | 4080: 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 ................ | page 6 offset 20480 | 0: 0a 00 00 00 02 0f f5 00 0f fb 0f f5 00 00 00 00 ................ | 4080: 00 00 00 00 00 05 04 08 09 01 02 04 04 08 08 09 ................ | page 7 offset 24576 | 0: 0d 00 00 00 05 0f b8 00 0f f4 0f e9 10 d6 0f c7 ................ | 16: 0f b8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ | 4016: 00 00 00 00 00 00 00 00 0d 05 02 23 61 75 74 6f ...........#auto | 4032: 6d 65 72 67 65 3d 35 0d 04 02 23 6d 65 72 67 65 merge=5...#merge | 4048: 3d 31 30 30 2c 38 11 03 02 2b 69 6e 74 65 67 72 =100,8...+integr | 4064: 69 74 79 2d 63 68 65 63 6b 09 02 02 1b 72 65 62 ity-check....reb | 4080: 75 69 6c 64 0a 01 02 1d 6f 70 74 69 6d 69 7a 65 uild....optimize | end crash-f15972acf5bc1c.db }]} {} do_execsql_test 17.1 { BEGIN; INSERT INTO t1(t1) SELECT x FROM t2; UPDATE t1 SET b=quote(zeroblob(200)) WHERE a MATCH 'thread*'; } do_catchsql_test 17.2 { DROP TABLE IF EXISTS t1; } {1 {SQL logic error}} do_execsql_test 17.3 { INSERT INTO t1(t1) VALUES('optimize'); } do_catchsql_test 17.4 { DROP TABLE IF EXISTS t1; } {1 {SQL logic error}} #------------------------------------------------------------------------- reset_db do_test 18.0 { sqlite3 db {} db deserialize [decode_hexdb { | size 32768 pagesize 4096 filename crash-4ce32d0608aff1.db | page 1 offset 0 | 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3. | 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 07 .....@ ........ | 32: 00 00 00 02 00 00 00 01 00 00 00 07 00 00 00 04 ................ | 48: 00 00 00 00 00 00 00 07 00 00 00 01 00 00 00 00 ................ | 96: 00 00 00 00 0d 0e b1 00 06 0d a4 00 0f 8d 0f 21 ...............! | 112: 0e b9 0d c8 0e 7e 0d a4 0d a4 00 00 00 00 00 00 .....~.......... | 3488: 00 00 00 00 22 07 06 17 11 11 01 31 74 61 62 6c ...........1tabl | 3504: 65 74 32 74 32 07 43 52 45 41 54 45 20 54 41 42 et2t2.CREATE TAB | 3520: 4c 45 20 74 32 28 78 29 81 33 05 07 17 1f 1f 01 LE t2(x).3...... | 3536: 82 35 74 61 62 6c 65 74 31 5f 73 65 67 64 69 72 .5tablet1_segdir | 3552: 74 31 5f 73 65 67 64 69 72 05 43 52 45 41 54 45 t1_segdir.CREATE | 3568: 20 54 41 42 4c 45 20 27 74 31 5f 73 65 67 64 69 TABLE 't1_segdi | 3584: 72 27 28 6c 65 76 65 6c 20 49 4e 54 45 47 45 52 r'(level INTEGER | 3600: 2c 69 64 78 20 49 4e 54 45 47 45 52 2c 73 74 61 ,idx INTEGER,sta | 3616: 72 74 5f 62 6c 6f 63 6b 20 49 4e 54 45 47 45 52 rt_block INTEGER | 3632: 2c 6c 65 61 76 65 73 5f 65 6e 64 5f 62 6c 6f 63 ,leaves_end_bloc | 3648: 6b 20 49 4e 54 45 47 45 52 2c 65 6e 64 5f 62 6c k INTEGER,end_bl | 3664: 6f 63 6b 20 49 4e 54 45 47 45 62 2c 72 6f 6f 74 ock INTEGEb,root | 3680: 20 42 4c 4f 42 2c 50 52 49 4d 41 52 59 20 4b 45 BLOB,PRIMARY KE | 3696: 59 28 6c 65 76 65 6c 2c 20 69 64 78 29 29 31 06 Y(level, idx))1. | 3712: 06 17 45 1f 01 00 69 6e 64 65 78 73 71 6c 69 74 ..E...indexsqlit | 3728: 65 5f 61 75 74 6f 69 6e 64 65 78 5f 74 31 5f 73 e_autoindex_t1_s | 3744: 65 67 64 69 72 5f 31 74 31 5f 73 65 67 64 69 72 egdir_1t1_segdir | 3760: 06 0f c7 00 08 00 00 00 00 66 04 07 17 23 23 01 .........f...##. | 3776: 81 13 74 61 62 6c 65 74 31 5f 73 65 67 6d 65 6e ..tablet1_segmen | 3792: 74 73 74 31 5f 73 65 67 6d 65 6e 74 73 04 43 52 tst1_segments.CR | 3808: 45 41 54 45 20 54 41 42 4c 45 20 27 74 31 5f 73 EATE TABLE 't1_s | 3824: 65 67 6d 65 6e 74 73 27 28 62 6c 6f 63 6b 69 64 egments'(blockid | 3840: 20 49 4e 54 45 47 45 52 20 50 52 49 4d 41 52 59 INTEGER PRIMARY | 3856: 20 4b 45 59 2c 20 62 6c 6f 63 6b 20 42 4c 4f 42 KEY, block BLOB | 3872: 29 6a 03 07 17 21 21 01 81 1f 74 61 62 6c 65 74 )j...!!...tablet | 3888: 31 5f 63 6f 6e 74 65 6e 74 74 31 5f 63 6f 6e 74 1_contentt1_cont | 3904: 65 6e 74 03 43 52 45 41 54 45 20 54 41 42 4c 45 ent.CREATE TABLE | 3920: 20 27 74 31 5f 63 6f 6e 74 65 6e 74 27 28 64 6f 't1_content'(do | 3936: 63 69 64 20 49 4e 54 45 47 45 52 20 50 52 49 4d cid INTEGER PRIM | 3952: 41 52 59 20 4b 45 59 2c 20 27 63 30 61 27 2c 20 ARY KEY, 'c0a', | 3968: 27 63 31 62 27 2c 20 27 63 32 63 27 29 38 02 06 'c1b', 'c2c')8.. | 3984: 17 11 11 08 5f 74 61 62 6c 65 74 31 74 31 43 52 ...._tablet1t1CR | 4000: 45 41 54 45 20 56 49 52 54 55 41 4c 20 54 41 42 EATE VIRTUAL TAB | 4016: 4c 45 20 74 31 20 55 53 49 4e 47 20 66 74 73 33 LE t1 USING fts3 | 4032: 28 61 2c 62 2c 63 29 00 00 00 39 00 00 00 00 00 (a,b,c)...9..... | page 3 offset 8192 | 0: 0d 00 00 00 25 0b 48 00 0f d8 0f af 0f 86 0f 74 ....%.H........t | 16: 0f 61 0f 4e 0f 2f 0f 0f 0e ef 0e d7 0e be 0e a5 .a.N./.......... | 32: 0e 8d 0e 74 0e 5b 0e 40 0e 24 0e 08 0d ef 0d d5 ...t.[.@.$...... | 48: 0d bb 0d a0 0d 84 0d 68 0d 4f 0d 35 0d 1b 0c fb .......h.O.5.... | 64: 0c da 0c b9 0c 99 0c 78 0c 57 0c 3e 0c 24 0c 0a .......x.W.>.$.. | 80: 0b 48 00 00 00 00 00 00 00 00 00 00 00 00 00 00 .H.............. | 2880: 00 00 00 00 00 00 00 00 81 3f 25 06 00 82 7f 00 .........?%..... | 2896: 00 43 4f 4d 50 49 4c 45 52 3d 67 63 63 2d 35 2e .COMPILER=gcc-5. | 2912: 34 23 00 20 32 30 31 36 30 36 30 39 20 44 45 42 4#. 20160609 DEB | 2928: 55 47 20 45 4e 41 42 4c 45 20 44 42 53 54 41 54 UG ENABLE DBSTAT | 2944: 20 56 54 41 42 20 45 4e 41 42 4c 45 20 46 54 53 VTAB ENABLE FTS | 2960: 34 20 45 4e 41 42 4c 45 20 46 54 53 35 20 45 4e 4 ENABLE FTS5 EN | 2976: 41 42 4c 45 20 47 45 4f 50 4f 4c 59 20 45 4e 41 ABLE GEOPOLY ENA | 2992: 42 4c 45 20 4a 53 4f 4e 31 20 45 4e 41 42 4c 45 BLE JSON1 ENABLE | 3008: 20 4d 45 4d 53 59 53 35 20 45 4e 41 42 4c 45 20 MEMSYS5 ENABLE | 3024: 52 54 52 45 45 20 4d 41 58 20 4d 45 4d 4f 52 59 RTREE MAX MEMORY | 3040: 3d 35 30 30 30 30 30 30 30 20 4f 4d 49 54 20 4c =50000000 OMIT L | 3056: 4f 41 44 20 45 58 54 45 4e 53 49 4f 4e 20 54 48 OAD EXTENSION TH | 3072: 52 45 41 44 53 41 46 45 3d 30 18 24 05 00 25 0f READSAFE=0.$..%. | 3088: 19 54 48 52 45 41 44 53 41 46 45 3d 30 58 42 49 .THREADSAFE=0XBI | 3104: 4e 41 52 59 18 23 05 00 25 0f 19 54 48 52 45 41 NARY.#..%..THREA | 3120: 44 53 41 46 45 3d 30 58 4e 4f 43 41 53 45 17 22 DSAFE=0XNOCASE.. | 3136: 05 00 25 0f 17 54 48 52 45 41 44 53 41 46 45 3d ..%..THREADSAFE= | 3152: 30 58 52 54 52 49 4d 1f 21 05 00 33 0f 19 4f 4d 0XRTRIM.!..3..OM | 3168: 49 54 20 4c 4f 41 44 20 45 58 54 45 4e 53 49 4f IT LOAD EXTENSIO | 3184: 4e 58 42 49 4e 41 52 59 1f 20 05 00 33 0f 19 4f NXBINARY. ..3..O | 3200: 4d 49 54 20 4c 4f 41 44 20 45 58 54 45 4e 53 49 MIT LOAD EXTENSI | 3216: 4f 4e 58 4e 4f 43 41 53 45 1e 1f 05 00 33 0f 17 ONXNOCASE....3.. | 3232: 4f 4d 49 54 20 4c 4f 41 44 20 45 58 54 45 4e 53 OMIT LOAD EXTENS | 3248: 49 4f 4e 58 52 54 52 49 4d 1f 1e 05 00 33 0f 19 IONXRTRIM....3.. | 3264: 4d 41 58 20 4d 45 4d 4f 52 59 3d 35 30 30 30 30 MAX MEMORY=50000 | 3280: 30 30 30 58 42 49 4e 41 52 59 1f 1d 05 00 33 0f 000XBINARY....3. | 3296: 19 4d 41 58 20 4d 45 4d 4f 52 59 3d 35 30 30 30 .MAX MEMORY=5000 | 3312: 30 30 30 30 58 4e 4f 43 41 53 45 1e 1c 05 00 33 0000XNOCASE....3 | 3328: 0f 17 4d 41 58 20 4d 45 4d 4f 52 59 3d 35 30 30 ..MAX MEMORY=500 | 3344: 30 30 30 30 30 58 52 54 53 49 4d 18 1b 05 00 25 00000XRTSIM....% | 3360: 0f 19 45 4e 41 42 4c 45 20 52 54 52 45 45 58 42 ..ENABLE RTREEXB | 3376: 49 4e 41 52 59 18 1a 05 00 25 0f 19 45 4e 41 42 INARY....%..ENAB | 3392: 4c 45 20 52 54 52 45 45 58 4e 4f 43 41 53 45 17 LE RTREEXNOCASE. | 3408: 19 05 00 25 0f 17 45 4e 41 42 4c 45 20 52 54 52 ...%..ENABLE RTR | 3424: 45 45 58 52 54 52 49 4d 1a 18 05 00 29 0f 19 45 EEXRTRIM....)..E | 3440: 4e 41 42 4c 45 20 4d 45 4d 53 59 53 35 58 42 49 NABLE MEMSYS5XBI | 3456: 4e 41 52 59 1a 17 05 00 29 0f 19 45 4e 41 42 4c NARY....)..ENABL | 3472: 45 20 4d 45 4d 53 59 53 35 58 4e 4f 43 41 53 45 E MEMSYS5XNOCASE | 3488: 19 16 05 00 29 0f 17 45 4e 41 42 4c 45 20 4d 45 ....)..ENABLE ME | 3504: 4d 53 59 53 35 58 52 54 52 49 4d 18 15 05 00 25 MSYS5XRTRIM....% | 3520: 0f 19 45 4e 41 42 4c 45 20 4a 53 4f 4e 31 58 42 ..ENABLE JSON1XB | 3536: 49 4e 41 52 59 18 14 05 00 25 0f 19 45 4e 41 42 INARY....%..ENAB | 3552: 4c 45 20 4a 53 4f 4e 31 58 4e 4f 43 41 53 45 17 LE JSON1XNOCASE. | 3568: 13 05 00 25 0f 17 45 4e 41 52 4c 45 20 4a 53 4f ...%..ENARLE JSO | 3584: 4e 31 58 52 54 52 49 4d 1a 12 05 00 29 0f 19 45 N1XRTRIM....)..E | 3600: 4e 41 42 4c 45 20 47 45 4f 50 4f 4c 59 58 42 49 NABLE GEOPOLYXBI | 3616: 4e 41 52 59 1a 11 05 00 29 0f 19 45 4e 41 1e 4c NARY....)..ENA.L | 3632: 45 20 47 45 4f 50 4f 4c 59 58 4e 4f 43 41 53 45 E GEOPOLYXNOCASE | 3648: 19 10 05 00 29 0f 17 45 4e 41 42 4c 45 20 47 55 ....)..ENABLE GU | 3664: 4f 50 4f 4c 59 58 52 54 52 49 4d 17 0f 05 00 23 OPOLYXRTRIM....# | 3680: 0f 19 45 4e 41 42 4c 45 20 46 54 53 35 58 42 49 ..ENABLE FTS5XBI | 3696: 4e 41 52 59 17 0e 05 00 23 0f 19 45 4e 41 42 4c NARY....#..ENABL | 3712: 45 20 46 54 53 35 58 4e 4f 43 41 53 45 16 0d 05 E FTS5XNOCASE... | 3728: 00 23 0f 17 45 4e 41 42 4c 45 20 46 54 59 e5 58 .#..ENABLE FTY.X | 3744: 52 54 52 49 4d 17 0c 05 00 23 0f 19 45 4e 41 42 RTRIM....#..ENAB | 3760: 4c 45 20 46 54 53 34 58 42 49 4e 41 52 59 17 0b LE FTS4XBINARY.. | 3776: 05 00 23 0f 19 45 4e 41 42 4c 45 20 46 54 53 35 ..#..ENABLE FTS5 | 3792: 58 4e 4f 43 40 53 45 16 0a 05 00 23 0f 17 45 4e XNOC@SE....#..EN | 3808: 41 42 4c 45 20 46 54 53 34 58 52 54 52 49 4d 1e ABLE FTS4XRTRIM. | 3824: 09 05 00 31 0f 19 45 4e 41 42 4c 45 20 44 42 53 ...1..ENABLE DBS | 3840: 54 41 54 20 56 54 41 42 58 42 49 4e 41 52 59 1e TAT VTABXBINARY. | 3856: 08 05 00 31 0f 19 45 4e 41 42 4c 45 20 44 42 53 ...1..ENABLE DBS | 3872: 54 41 54 20 56 54 41 42 58 4e 4f 43 41 53 45 1d TAT VTABXNOCASE. | 3888: 07 05 00 31 0f 17 45 4e 41 42 4c 45 20 44 42 53 ...1..ENABLE DBS | 3904: 54 41 54 20 56 54 41 42 58 52 54 52 49 4d 11 06 TAT VTABXRTRIM.. | 3920: 05 00 17 0f 19 44 45 42 55 47 58 42 49 4e 41 52 .....DEBUGXBINAR | 3936: 59 11 05 05 00 17 0f 19 44 45 42 55 47 58 4e 4f Y.......DEBUGXNO | 3952: 43 41 53 45 10 04 05 00 17 0f 17 44 45 42 55 47 CASE.......DEBUG | 3968: 58 52 54 52 49 4d 27 03 05 00 43 0f 19 43 4f 4d XRTRIM'...C..COM | 3984: 50 49 4c 45 52 3d 67 63 63 2d 35 2e 34 2e 30 20 PILER=gcc-5.4.0 | 4000: 32 30 31 36 30 36 30 39 58 42 49 4e 41 52 59 27 20160609XBINARY' | 4016: 02 05 00 43 0f 19 43 4f 4d 50 49 4c 45 52 3d 67 ...C..COMPILER=g | 4032: 63 63 25 75 2e 34 2f 30 20 32 30 31 36 30 36 30 cc%u.4/0 2016060 | 4048: 39 58 4e 4f 43 41 53 45 26 01 05 00 43 0f 17 43 9XNOCASE&...C..C | 4064: 4f 4d 50 49 4c 45 52 3d 67 63 63 2d 35 2e 34 2e OMPILER=gcc-5.4. | 4080: 30 20 32 30 31 36 30 36 30 39 58 52 54 52 49 4d 0 20160609XRTRIM | page 4 offset 12288 | 0: 0d 00 00 00 00 10 00 00 00 00 00 00 00 00 00 00 ................ | page 5 offset 16384 | 0: 0d 00 00 00 02 0b a0 00 0c ad 0b a0 00 00 00 00 ................ | 2976: 82 0a 02 08 08 09 08 08 17 84 06 30 20 32 35 33 ...........0 253 | 2992: 00 01 30 04 25 06 1b 00 00 08 32 30 31 36 30 36 ..0.%.....201606 | 3008: 30 39 03 25 07 00 00 01 34 03 25 05 00 00 01 35 09.%....4.%....5 | 3024: 03 25 04 00 01 07 30 30 30 30 30 30 30 03 25 1a .%....0000000.%. | 3040: 00 00 08 63 6f 6d 70 69 6c 65 72 03 25 02 00 00 ...compiler.%... | 3056: 06 64 62 73 74 61 74 03 25 0a 00 01 04 65 62 75 .dbstat.%....ebu | 3072: 67 03 25 08 00 00 06 65 6e 61 62 6c 65 09 25 09 g.%....enable.%. | 3088: 05 04 04 04 04 04 00 01 08 78 74 65 6e 73 69 6f .........xtensio | 3104: 6e 03 25 1d 00 00 04 66 74 73 34 03 25 0d 00 03 n.%....fts4.%... | 3120: 01 35 03 25 0f 00 00 03 67 63 63 03 25 03 00 01 .5.%....gcc.%... | 3136: 06 65 6f 70 6f 6c 79 03 25 11 00 00 05 6a 73 6f .eopoly.%....jso | 3152: 6e 31 03 25 13 41 00 04 6c 6f 61 64 03 25 1c 00 n1.%.A..load.%.. | 3168: 00 03 6d 61 78 03 25 18 00 01 05 65 6d 6f 72 79 ..max.%....emory | 3184: 03 25 19 00 03 04 73 79 73 35 03 25 15 00 00 04 .%....sys5.%.... | 3200: 6f 6d 69 74 03 25 1b 00 00 05 72 74 72 65 65 03 omit.%....rtree. | 3216: 25 17 00 00 0a 74 68 72 65 61 64 73 61 56 65 03 %....threadsaVe. | 3232: 25 1e 00 00 04 76 74 61 62 03 25 0b 00 86 50 01 %....vtab.%...P. | 3248: 08 08 08 08 08 17 8d 12 30 20 38 33 35 00 01 30 ........0 835..0 | 3264: 12 01 06 00 01 06 00 01 06 00 1f 03 00 01 03 00 ................ | 3280: 01 03 00 00 08 32 30 31 36 30 36 30 39 09 01 07 .....20160609... | 3296: 00 01 07 00 01 07 00 00 01 34 09 01 05 00 01 05 .........4...... | 3312: 00 01 05 00 00 01 35 09 01 04 00 01 04 00 01 04 ......5......... | 3328: 00 01 07 30 30 30 30 30 30 30 09 1c 04 00 01 04 ...0000000...... | 3344: 00 01 04 00 00 06 62 69 6e 61 72 79 3c 03 02 02 ......binary<... | 3360: 02 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 ................ | 3376: 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 00 ................ | 3392: 03 01 02 02 00 03 01 02 02 00 03 01 02 02 00 03 ................ | 3408: 01 02 02 00 03 01 02 02 00 00 08 63 6f 6d 70 69 ...........compi | 3424: 6c 65 72 09 01 02 00 01 02 00 01 02 00 00 06 64 ler............d | 3440: 62 73 74 61 74 09 f2 03 00 01 03 00 01 03 00 01 bstat........... | 3456: 04 65 62 75 67 09 04 02 00 01 02 00 01 02 00 00 .ebug........... | 3472: 06 65 6e 61 62 6c 65 3f 07 02 00 01 02 00 01 02 .enable?........ | 3488: 00 01 02 00 01 02 00 01 02 00 01 02 00 57 02 00 .............W.. | 3504: 01 02 00 01 01 00 01 02 00 11 02 00 01 02 10 01 ................ | 3520: 02 00 01 02 00 01 02 00 01 02 00 01 02 00 01 02 ................ | 3536: 00 01 02 00 01 02 00 01 08 78 74 64 6e 73 69 6f .........xtdnsio | 3552: 6e 09 1f 04 00 01 04 00 01 03 00 00 04 66 74 73 n............fts | 3568: 34 09 0a 03 00 01 03 00 01 03 00 03 01 35 09 0d 4............5.. | 3584: 03 00 01 03 00 01 03 00 00 03 57 63 63 09 01 03 ..........Wcc... | 3600: 00 01 03 00 01 03 00 01 06 65 6f 70 6f 6c 79 09 .........eopoly. | 3616: 10 03 00 01 03 00 01 03 00 00 05 6a 73 6f 6e 31 ...........json1 | 3632: 09 13 03 00 01 03 00 01 03 00 00 04 6c 6f 61 64 ............load | 3648: 09 1f 03 00 01 03 00 01 03 00 00 03 6d 61 78 09 ............max. | 3664: 1c 02 00 01 02 00 01 02 00 01 05 65 6d 6f 72 79 ...........emory | 3680: 09 1c 03 00 01 03 00 01 03 00 03 04 73 79 73 35 ............sys5 | 3696: 09 16 03 00 01 03 00 01 03 00 00 06 6e 6f 63 61 ............noca | 3712: 73 65 3c 02 01 02 02 00 03 01 02 02 00 03 01 02 se<............. | 3728: 02 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 ................ | 3744: 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 00 ................ | 3760: 03 01 02 02 00 03 01 02 02 00 03 01 02 02 00 00 ................ | 3776: 04 6f 6d 69 74 09 1f 02 00 01 02 00 01 02 00 00 .omit........... | 3792: 05 72 74 72 65 65 09 19 03 00 01 03 00 01 03 00 .rtree.......... | 3808: 03 02 69 6d 3c 01 01 02 02 00 03 01 02 02 00 03 ..im<........... | 3824: 01 02 02 00 03 01 02 02 00 03 01 02 02 00 03 01 ................ | 3840: 02 02 00 03 01 02 02 00 03 01 02 02 00 03 01 02 ................ | 3856: 02 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 ................ | 3872: 00 00 0a 74 68 72 65 61 64 73 61 66 65 09 22 02 ...threadsafe... | 3888: 00 01 02 00 02 02 00 00 04 76 74 61 62 09 07 04 .........vtab... | 3904: 00 01 04 00 01 04 00 00 01 78 b4 01 01 01 01 02 .........x...... | 3920: 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 ................ | 3936: 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 01 ................ | 3952: 01 01 02 00 01 01 01 02 00 01 01 01 02 00 01 01 ................ | 3968: 01 02 00 01 01 01 02 00 01 01 01 02 00 01 01 01 ................ | 3984: 02 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 ................ | 4000: 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 ................ | 4016: 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 01 ................ | 4032: 01 01 02 00 01 01 01 02 00 01 01 01 02 00 01 01 ................ | 4048: 01 02 00 01 01 01 02 00 01 01 01 02 00 01 01 01 ................ | 4064: 02 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 ................ | 4080: 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 ................ | page 6 offset 20480 | 0: 0a 00 00 00 02 0f f5 00 0f fb 0f f5 00 00 00 00 ................ | 4080: 00 00 00 00 00 05 04 08 09 01 02 04 04 08 08 09 ................ | page 7 offset 24576 | 0: 0d 00 00 00 05 0f b8 00 0f f4 0f e9 0f d6 0f c7 ................ | 16: 0f b8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ | 4064: 00 00 00 00 00 0d 05 02 23 61 75 74 6f 6d 65 72 ........#automer | 4080: 67 65 3d 35 0d 04 02 23 6d 65 72 67 65 3d 31 30 ge=5...#merge=10 | page 8 offset 28672 | 0: 30 2c 38 11 03 02 2b 69 6e 74 65 67 72 69 74 79 0,8...+integrity | 16: 2d 63 68 65 63 6b 09 02 02 1b 72 65 62 75 69 6c -check....rebuil | 32: 64 0a 01 02 1d 6f 70 74 69 6d 69 7a 65 00 00 00 d....optimize... | end crash-4ce32d0608aff1.db }]} {} do_catchsql_test 18.1 { SELECT quote(matchinfo(t1,'pcxybs'))==0 FROM t1 WHERE b MATCH 'e*'; } {0 {}} #------------------------------------------------------------------------- reset_db do_test 19.0 { sqlite3 db {} db deserialize [decode_hexdb { | size 28672 pagesize 4096 filename crash-526ea445f41c02.db | page 1 offset 0 | 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3. | 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 07 .....@ ........ | 32: 00 00 00 02 00 00 00 01 00 00 00 07 00 00 00 04 ................ | 48: 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 ................ | 96: 00 00 00 00 0d 0e b1 00 06 0d a4 00 0f 8d 0f 21 ...............! | 112: 0e b9 0d c8 0e 7e 0d a4 00 00 00 00 00 00 00 00 .....~.......... | 3488: 00 00 00 00 22 07 06 17 11 11 01 31 74 61 62 6c ...........1tabl | 3504: 65 74 32 74 32 07 43 52 45 41 54 45 20 54 41 42 et2t2.CREATE TAB | 3520: 4c 45 20 74 32 28 78 29 81 33 05 07 17 1f 1f 01 LE t2(x).3...... | 3536: 82 35 74 61 62 6c 65 74 31 5f 73 65 67 64 69 72 .5tablet1_segdir | 3552: 74 31 5f 73 65 67 64 69 72 05 43 52 45 41 54 45 t1_segdir.CREATE | 3568: 20 54 41 42 4c 45 20 27 74 31 5f 73 65 67 64 69 TABLE 't1_segdi | 3584: 72 27 28 6c 65 76 65 6c 20 49 4e 54 45 47 45 52 r'(level INTEGER | 3600: 2c 69 64 78 20 49 4e 54 45 47 45 52 2c 73 74 61 ,idx INTEGER,sta | 3616: 72 74 5f 62 6c 6f 63 6b 20 49 4e 54 45 47 45 52 rt_block INTEGER | 3632: 2c 6c 65 61 76 65 73 5f 65 6e 64 5f 62 6c 6f 63 ,leaves_end_bloc | 3648: 6b 20 49 4e 54 45 47 45 52 2c 65 6e 64 5f 62 6c k INTEGER,end_bl | 3664: 6f 63 6b 20 49 4e 54 45 47 45 52 2c 72 6f 6f 74 ock INTEGER,root | 3680: 20 42 4c 4f 42 2c 50 52 49 4d 41 52 59 20 4b 45 BLOB,PRIMARY KE | 3696: 59 28 6c 65 76 65 6c 2c 20 69 64 78 29 29 31 06 Y(level, idx))1. | 3712: 06 17 45 1f 01 00 69 6e 64 65 78 73 71 6c 69 74 ..E...indexsqlit | 3728: 65 5f 61 75 74 6f 69 6e 64 65 78 5f 74 31 5f 73 e_autoindex_t1_s | 3744: 65 67 64 69 72 5f 31 74 31 5f 73 65 67 64 69 72 egdir_1t1_segdir | 3760: 06 0f c7 00 08 00 00 00 00 66 04 07 17 23 23 01 .........f...##. | 3776: 81 13 74 61 62 6c 65 74 31 5f 73 65 67 6d 65 6e ..tablet1_segmen | 3792: 74 73 74 31 5f 73 65 67 6d 65 6e 74 73 04 43 52 tst1_segments.CR | 3808: 45 41 54 45 20 54 41 42 4c 45 20 27 74 31 5f 73 EATE TABLE 't1_s | 3824: 65 67 6d 65 6e 74 73 27 28 62 6c 6f 63 6b 69 64 egments'(blockid | 3840: 20 49 4e 54 45 47 45 52 20 50 52 49 4d 41 52 59 INTEGER PRIMARY | 3856: 20 4b 45 59 2c 20 62 6c 6f 63 6b 20 42 4c 4f 42 KEY, block BLOB | 3872: 29 6a 03 07 17 21 21 01 81 1f 74 61 62 6c 65 74 )j...!!...tablet | 3888: 31 5f 63 6f 6e 74 65 6e 74 74 31 5f 63 6f 6e 74 1_contentt1_cont | 3904: 65 6e 74 03 43 52 45 41 54 45 20 54 41 42 4c 45 ent.CREATE TABLE | 3920: 20 27 74 31 5f 63 6f 6e 74 65 6e 74 27 28 64 6f 't1_content'(do | 3936: 63 69 64 20 49 4e 54 45 47 45 52 20 50 52 49 4d cid INTEGER PRIM | 3952: 41 52 59 20 4b 45 59 2c 20 27 63 30 61 27 2c 20 ARY KEY, 'c0a', | 3968: 27 63 31 62 27 2c 20 27 63 32 63 27 29 38 02 06 'c1b', 'c2c')8.. | 3984: 17 11 11 08 5f 74 61 62 6c 65 74 31 74 41 43 52 ...._tablet1tACR | 4000: 45 41 54 45 20 56 49 52 54 55 41 4c 20 54 41 42 EATE VIRTUAL TAB | 4016: 4c 45 20 74 31 20 55 53 49 4e 47 20 66 74 73 33 LE t1 USING fts3 | 4032: 28 61 2c 62 2c 63 29 00 00 00 39 00 00 00 00 00 (a,b,c)...9..... | page 3 offset 8192 | 0: 0d 00 00 00 25 0b 48 00 0f d8 0f af 0f 86 0f 74 ....%.H........t | 16: 0f 61 0f 4e 0f 2f 0f 0f 0e ef 0e d7 0e be 0e a5 .a.N./.......... | 32: 0e 8d 0e 74 0e 5b 0e 40 0e 24 0e 08 0d ef 0d d5 ...t.[.@.$...... | 48: 0d bb 0d a0 0d 84 0d 68 0d 4f 0d 35 0d 1b 0c fb .......h.O.5.... | 64: 0c da 0c b9 0c 99 0c 78 0c 57 0c 3e 0c 24 0c 0a .......x.W.>.$.. | 80: 0b 48 00 00 00 00 00 00 00 00 00 00 00 00 00 00 .H.............. | 2880: 00 00 00 00 00 00 00 00 81 3f 25 06 00 82 7f 00 .........?%..... | 2896: 00 43 4f 4d 50 49 4c 45 52 3d 67 63 63 2d 35 2f .COMPILER=gcc-5/ | 2912: 34 2e 30 20 32 30 31 36 30 36 30 39 20 44 45 42 4.0 20160609 DEB | 2928: 55 47 20 45 4e 41 42 4c 45 20 44 42 53 54 41 54 UG ENABLE DBSTAT | 2944: 20 56 54 41 42 20 45 4e 41 42 4c 45 20 46 54 53 VTAB ENABLE FTS | 2960: 34 20 45 4e 41 42 4c 45 20 46 54 53 35 20 45 4e 4 ENABLE FTS5 EN | 2976: 41 42 4c 45 20 47 45 4f 50 4f 4c 59 20 45 4e 41 ABLE GEOPOLY ENA | 2992: 42 4c 45 20 4a 53 4f 4e 31 20 45 4e 41 42 4c 45 BLE JSON1 ENABLE | 3008: 20 4d 45 4d 53 59 53 35 20 45 4e 41 42 4c 45 20 MEMSYS5 ENABLE | 3024: 52 54 52 45 45 20 4d 41 58 20 4d 45 4d 4f 52 59 RTREE MAX MEMORY | 3040: 3d 35 30 30 30 30 30 30 30 20 4f 4d 49 54 20 4c =50000000 OMIT L | 3056: 4f 41 44 20 45 58 54 45 4e 53 49 4f 4e 20 54 48 OAD EXTENSION TH | 3072: 52 45 41 44 53 41 46 45 3d 30 18 24 05 00 25 0f READSAFE=0.$..%. | 3088: 19 54 48 52 45 41 44 53 41 46 45 3d 30 58 42 49 .THREADSAFE=0XBI | 3104: 4e 41 52 59 18 23 05 00 25 0f 19 54 48 52 45 41 NARY.#..%..THREA | 3120: 44 53 41 46 45 3d 30 58 4e 4f 43 41 53 45 17 22 DSAFE=0XNOCASE.. | 3136: 05 00 25 0f 17 54 48 52 45 41 44 53 41 46 45 3d ..%..THREADSAFE= | 3152: 30 58 52 54 52 49 4d 1f 21 05 00 33 0f 19 4f 4d 0XRTRIM.!..3..OM | 3168: 49 54 20 4c 4f 41 44 20 45 58 54 45 4e 53 49 4f IT LOAD EXTENSIO | 3184: 4e 58 42 49 4e 41 52 59 1f 20 05 00 33 0f 19 4f NXBINARY. ..3..O | 3200: 4d 49 54 20 4c 4f 41 44 20 45 58 54 45 4e 53 49 MIT LOAD EXTENSI | 3216: 4f 4e 58 4e 4f 43 41 53 45 1e 1f 05 00 33 0f 17 ONXNOCASE....3.. | 3232: 4f 4d 49 54 20 4c 4f 41 44 20 45 58 54 45 4e 53 OMIT LOAD EXTENS | 3248: 49 4f 4e 58 52 54 52 49 4d 1f 1e 05 00 33 0f 19 IONXRTRIM....3.. | 3264: 4d 41 58 20 4d 45 4d 4f 52 59 3d 35 30 30 30 30 MAX MEMORY=50000 | 3280: 30 30 30 58 42 49 4e 41 52 59 1f 1d 05 00 33 0f 000XBINARY....3. | 3296: 19 4d 41 58 20 4d 45 4d 4f 52 59 3d 35 30 30 30 .MAX MEMORY=5000 | 3312: 30 30 30 30 58 4e 4f 43 41 53 45 1e 1c 05 00 33 0000XNOCASE....3 | 3328: 0f 17 4d 41 58 20 4d 45 4d 4f 52 59 3d 35 30 30 ..MAX MEMORY=500 | 3344: 30 30 30 30 30 58 52 54 52 49 4d 18 1b 05 00 25 00000XRTRIM....% | 3360: 0f 19 45 4e 41 42 4c 45 20 52 54 52 45 45 58 42 ..ENABLE RTREEXB | 3376: 49 4e 41 52 59 18 1a 05 00 25 0f 19 45 4e 41 42 INARY....%..ENAB | 3392: 4c 45 20 52 54 52 45 45 58 4e 4f 43 41 53 45 17 LE RTREEXNOCASE. | 3408: 19 05 00 25 0f 17 45 4e 41 42 4c 45 20 52 54 52 ...%..ENABLE RTR | 3424: 45 45 58 52 54 52 49 4d 1a 18 05 00 29 0f 19 45 EEXRTRIM....)..E | 3440: 4e 41 42 4c 45 20 4d 45 4d 53 59 53 35 58 42 49 NABLE MEMSYS5XBI | 3456: 4e 41 52 59 1a 17 05 00 29 0f 19 45 4e 41 42 4c NARY....)..ENABL | 3472: 45 20 4d 45 4d 53 59 53 35 58 4e 4f 43 41 53 45 E MEMSYS5XNOCASE | 3488: 19 16 05 00 29 0f 17 45 4e 41 42 4c 45 20 4d 45 ....)..ENABLE ME | 3504: 4d 53 59 53 35 58 52 54 52 49 4d 18 15 05 00 25 MSYS5XRTRIM....% | 3520: 0f 19 45 4e 41 42 4c 45 20 4a 53 4f 4e 31 58 42 ..ENABLE JSON1XB | 3536: 49 4e 41 52 59 18 14 05 00 25 0f 19 45 4e 41 42 INARY....%..ENAB | 3552: 4c 45 20 4a 53 4f 4e 31 58 4e 4f 43 41 53 45 17 LE JSON1XNOCASE. | 3568: 13 05 00 25 0f 17 45 4e 41 42 4c 45 20 4a 53 4f ...%..ENABLE JSO | 3584: 4e 31 58 52 54 52 49 4d 1a 12 05 00 29 0f 19 45 N1XRTRIM....)..E | 3600: 4e 41 42 4c 45 20 47 45 4f 50 4f 4c 59 58 42 49 NABLE GEOPOLYXBI | 3616: 4e 41 52 59 1a 11 05 00 29 0f 19 45 4e 41 42 4c NARY....)..ENABL | 3632: 45 20 47 45 4f 50 4f 4c 59 58 4e 4f 43 41 53 45 E GEOPOLYXNOCASE | 3648: 19 10 05 00 29 0f 17 45 4e 41 42 4c 45 20 47 45 ....)..ENABLE GE | 3664: 4f 50 4f 4c 59 58 52 54 52 49 4d 17 0f 05 00 23 OPOLYXRTRIM....# | 3680: 0f 19 45 4e 41 42 4c 45 20 46 54 53 35 58 42 49 ..ENABLE FTS5XBI | 3696: 4f 41 52 59 17 0e 05 00 23 0f 19 45 4e 41 42 4c OARY....#..ENABL | 3712: 45 20 46 54 53 35 58 4e 4f 43 41 53 45 16 0d 05 E FTS5XNOCASE... | 3728: 00 23 0f 17 45 4e 41 42 4c 45 20 46 54 53 35 58 .#..ENABLE FTS5X | 3744: 52 54 52 49 4d 17 0c 05 00 23 0f 19 45 4e 41 42 RTRIM....#..ENAB | 3760: 4c 45 20 46 54 53 34 58 42 49 4e 41 52 59 17 0b LE FTS4XBINARY.. | 3776: 05 00 23 0f 19 45 4e 41 42 4d f5 20 46 54 53 34 ..#..ENABM. FTS4 | 3792: 58 4e 4f 43 41 53 45 16 0a 05 00 23 0f 17 45 4e XNOCASE....#..EN | 3808: 41 52 4c 45 20 46 54 53 34 58 52 54 52 49 4d 1e ARLE FTS4XRTRIM. | 3824: 09 05 00 31 0f 19 45 4e 41 42 4c 45 20 44 42 53 ...1..ENABLE DBS | 3840: 54 41 54 20 56 54 41 42 58 42 49 4e 41 52 59 1e TAT VTABXBINARY. | 3856: 08 05 00 31 0f 19 45 4e 41 42 4c 45 20 44 42 53 ...1..ENABLE DBS | 3872: 54 41 54 20 56 54 41 42 58 4e 4f 43 41 53 45 1d TAT VTABXNOCASE. | 3888: 07 05 00 31 0f 17 45 4e 41 42 4c 45 20 44 42 53 ...1..ENABLE DBS | 3904: 54 41 54 20 56 54 41 42 58 52 54 52 49 4d 11 06 TAT VTABXRTRIM.. | 3920: 05 00 17 0f 19 44 45 42 55 47 58 42 49 4e 41 52 .....DEBUGXBINAR | 3936: 59 11 05 05 00 17 0f 19 44 45 42 55 47 58 4e 4f Y.......DEBUGXNO | 3952: 43 41 53 45 10 04 05 00 17 0f 17 44 45 42 55 47 CASE.......DEBUG | 3968: 58 52 54 52 49 4d 27 03 05 00 43 0f 19 43 4f 4d XRTRIM'...C..COM | 3984: 50 49 4c 45 52 3d 67 63 63 2d 35 2e 34 2e 30 20 PILER=gcc-5.4.0 | 4000: 32 30 31 36 30 36 30 39 58 42 49 4e 41 52 59 27 20160609XBINARY' | 4016: 02 04 00 43 0f 19 43 4f 4d 50 49 4c 45 52 3d 67 ...C..COMPILER=g | 4032: 63 63 2d 35 2e 34 2e 30 20 32 30 31 36 30 36 30 cc-5.4.0 2016060 | 4048: 39 58 4e 4f 43 41 53 45 26 01 05 00 43 0f 17 43 9XNOCASE&...C..C | 4064: 4f 4d 50 49 4c 45 52 3d 67 63 63 2d 35 2e 34 2e OMPILER=gcc-5.4. | 4080: 30 20 32 30 31 36 30 36 30 39 58 52 54 52 49 4d 0 20160609XRTRIM | page 4 offset 12288 | 0: 0d 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ | page 5 offset 16384 | 0: 0d 00 00 00 02 0b a0 00 0c ad 0b a0 00 00 00 00 ................ | 2976: 82 0a 02 08 08 09 08 08 17 84 06 30 20 32 35 33 ...........0 253 | 2992: 00 01 30 04 25 06 1b 00 00 08 32 30 31 36 30 36 ..0.%.....201606 | 3008: 30 39 03 25 07 00 00 01 34 03 25 05 00 00 01 35 09.%....4.%....5 | 3024: 03 25 04 00 01 07 30 30 30 30 30 30 30 03 25 1a .%....0000000.%. | 3040: 00 00 08 63 6f 6d 70 69 6c 65 72 03 25 02 00 00 ...compiler.%... | 3056: 06 64 62 73 74 61 74 03 25 0a 00 01 04 65 62 75 .dbstat.%....ebu | 3072: 67 03 25 08 00 00 06 65 6e 61 62 6c 65 09 25 09 g.%....enable.%. | 3088: 05 04 04 04 04 04 00 01 08 78 74 65 6e 73 69 6f .........xtensio | 3104: 6e 03 25 1d 00 00 04 66 74 73 34 03 25 0d 00 03 n.%....fts4.%... | 3120: 01 35 03 25 0f 00 00 03 67 63 63 03 25 03 00 01 .5.%....gcc.%... | 3136: 06 65 6f 70 6f 6c 79 03 25 11 00 00 05 6a 73 6f .eopoly.%....jso | 3152: 6e 31 03 25 13 00 00 04 6c 6f 61 64 03 25 1c 00 n1.%....load.%.. | 3168: 00 03 6d 61 78 03 25 18 00 01 05 65 6d 6f 72 79 ..max.%....emory | 3184: 03 25 19 00 03 04 73 79 73 35 03 25 15 00 00 04 .%....sys5.%.... | 3200: 6f 6d 69 74 03 25 1b 00 00 05 72 74 72 65 65 03 omit.%....rtree. | 3216: 25 17 00 00 0a 74 68 72 65 61 64 73 61 66 65 03 %....threadsafe. | 3232: 25 1e 00 00 04 76 74 61 62 03 25 0b 00 86 50 01 %....vtab.%...P. | 3248: 08 08 08 08 08 17 8d 12 30 20 38 33 35 00 01 30 ........0 835..0 | 3264: 12 01 06 00 01 06 00 01 06 00 1f 03 00 01 03 00 ................ | 3280: 01 03 00 00 08 32 30 31 36 30 36 30 39 09 01 07 .....20160609... | 3296: 00 01 07 00 01 07 00 00 01 34 09 01 05 00 01 05 .........4...... | 3312: 00 01 05 00 00 01 35 09 01 04 00 01 04 00 01 04 ......5......... | 3328: 00 01 07 30 30 30 30 30 30 30 09 1c 04 00 01 04 ...0000000...... | 3344: 00 01 04 00 00 06 62 69 6e 61 72 79 3c 03 01 02 ......binary<... | 3360: 02 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 ................ | 3376: 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 00 ................ | 3392: 03 01 02 02 00 03 01 02 02 00 03 01 02 02 00 03 ................ | 3408: 01 02 02 00 03 01 02 02 00 00 08 63 6f 6d 70 69 ...........compi | 3424: 6c 65 72 09 01 02 00 01 02 00 01 02 00 00 06 64 ler............d | 3440: 62 73 74 61 74 09 07 03 00 01 03 00 01 03 00 01 bstat........... | 3456: 04 65 62 75 67 09 04 02 00 01 02 00 01 02 00 00 .ebug........... | 3472: 06 65 6e 61 62 6c 65 3f 07 02 00 01 02 00 01 02 .enable?........ | 3488: 00 01 02 00 01 02 00 01 02 00 01 02 00 01 02 00 ................ | 3504: 01 02 00 01 02 00 01 02 00 01 02 00 01 02 00 01 ................ | 3520: 02 00 01 02 00 01 02 00 01 02 00 01 02 00 01 02 ................ | 3536: 00 01 02 00 01 02 00 01 08 78 74 65 6e 73 69 6f .........xtensio | 3552: 6e 09 1f 04 00 01 04 00 01 04 00 00 04 66 74 73 n............fts | 3568: 34 09 0a 03 00 01 03 00 01 03 00 03 01 35 09 0d 4............5.. | 3584: 03 00 01 03 00 01 03 00 00 03 67 63 63 09 01 03 ..........gcc... | 3600: 00 01 03 00 01 03 00 01 06 65 6f 70 6f 6c 79 09 .........eopoly. | 3616: 10 03 00 01 03 00 01 03 00 00 05 6a 73 6f 6e 31 ...........json1 | 3632: 09 13 03 00 01 03 00 01 03 00 00 04 6c 6f 61 64 ............load | 3648: 09 1f 03 00 01 03 00 01 03 00 00 03 6d 61 78 09 ............max. | 3664: 1c 02 00 01 02 00 01 02 00 01 05 65 6d 6f 72 79 ...........emory | 3680: 09 1c 03 00 01 03 00 01 03 00 03 04 73 79 73 35 ............sys5 | 3696: 09 16 03 00 01 03 00 01 03 00 00 06 6e 6f 63 61 ............noca | 3712: 73 65 3c 02 01 02 02 00 03 01 02 02 00 03 01 02 se<............. | 3728: 02 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 ................ | 3744: 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 00 ................ | 3760: 03 01 02 02 00 13 01 02 02 00 03 01 02 02 00 00 ................ | 3776: 04 6f 6d 69 74 09 1f 02 00 01 12 00 01 02 00 00 .omit........... | 3792: 05 72 74 72 65 65 09 19 03 00 01 81 00 01 03 00 .rtree.......... | 3808: 03 02 69 6d 3c 01 01 02 02 00 03 01 02 02 00 03 ..im<........... | 3824: 01 02 02 00 03 01 02 02 00 03 01 02 02 00 03 01 ................ | 3840: 02 02 00 03 01 02 02 00 03 01 02 02 00 03 01 02 ................ | 3856: 02 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 ................ | 3872: 00 00 0a 74 68 72 65 61 64 73 61 66 65 09 22 02 ...threadsafe... | 3888: 00 01 02 00 01 02 00 00 04 76 74 61 62 09 07 04 .........vtab... | 3904: 00 01 04 00 01 04 00 00 01 78 b4 01 01 01 01 02 .........x...... | 3920: 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 ................ | 3936: 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 01 ................ | 3952: 01 01 02 00 01 01 01 02 00 01 01 01 02 00 01 01 ................ | 3968: 01 02 00 01 01 01 02 00 01 01 01 02 00 01 01 01 ................ | 3984: 02 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 ................ | 4000: 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 ................ | 4016: 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 01 ................ | 4032: 01 01 02 00 01 01 01 02 00 01 01 01 02 00 01 01 ................ | 4048: 01 02 00 01 01 01 02 00 01 01 01 02 00 01 01 01 ................ | 4064: 02 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 ................ | 4080: 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 ................ | page 6 offset 20480 | 0: 0a 00 00 00 02 0f f5 00 0f fb 0f f5 00 00 00 00 ................ | 4080: 00 00 00 00 00 05 04 08 09 01 02 04 04 08 08 09 ................ | page 7 offset 24576 | 0: 0d 00 00 00 05 0f b8 00 0f f4 0f e9 0f d6 0f c7 ................ | 16: 0f b8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ | 4016: 00 00 00 00 00 00 00 00 0d 05 02 23 61 75 74 6f ...........#auto | 4032: 6d 65 72 67 65 3d 35 0d 04 02 23 6d 65 72 67 65 merge=5...#merge | 4048: 3d 31 30 30 2c 38 11 03 02 2b 69 6e 74 65 67 72 =100,8...+integr | 4064: 69 74 79 2d 63 68 65 63 6b 09 02 02 1b 72 65 62 ity-check....reb | 4080: 75 69 6c 64 0a 01 02 1d 6f 70 74 69 6d 69 7a 65 uild....optimize | end crash-526ea445f41c02.db }]} {} do_catchsql_test 19.1 { PRAGMA writable_schema = 1; SELECT rowid,a,c,snippet(t1,85101090932165,-1,10) FROM t1 WHERE a MATCH 'rtree'; } {1 {database disk image is malformed}} #------------------------------------------------------------------------- reset_db do_test 20.0 { sqlite3 db {} db deserialize [decode_hexdb { .open --hexdb | size 28672 pagesize 4096 filename crash-afecd03c862e58.db | page 1 offset 0 | 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3. | 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 07 .....@ ........ | 32: 00 00 00 00 00 00 00 00 00 00 00 06 00 00 00 04 ................ | 96: 00 00 00 00 0d 0e ef 00 07 0d 4d 00 0f bd 0f 5f ..........M...._ | 112: 0e f7 0e 06 0e bc 0d a4 0d 4d 00 00 01 00 00 00 .........M...... | 3392: 00 00 00 00 00 00 00 00 00 00 00 00 00 55 07 07 .............U.. | 3408: 17 1b 1b 01 81 01 74 61 62 6c 65 74 31 5f 73 74 ......tablet1_st | 3424: 61 74 74 31 5f 73 74 61 74 07 43 52 45 41 54 45 att1_stat.CREATE | 3440: 20 54 41 42 4c 45 20 27 74 31 5f 73 74 61 74 27 TABLE 't1_stat' | 3456: 28 69 64 20 49 4e 54 45 47 45 52 20 50 52 49 4d (id INTEGER PRIM | 3472: 41 52 59 20 4b 45 59 2c 20 76 61 6c 75 65 20 42 ARY KEY, value B | 3488: 4c 4f 42 29 60 06 07 17 21 21 01 81 0b 74 61 62 LOB)`...!!...tab | 3504: 6c 65 74 31 5f 64 6f 63 73 69 7a 65 74 31 5f 64 let1_docsizet1_d | 3520: 6f 63 73 69 7a 65 06 43 52 45 41 54 45 20 54 41 ocsize.CREATE TA | 3536: 42 4c 45 20 27 74 31 5f 64 6f 63 73 69 7a 65 27 BLE 't1_docsize' | 3552: 28 64 6f 63 69 64 20 49 4e 54 45 47 45 52 20 50 (docid INTEGER P | 3568: 52 49 4d 41 52 59 30 4b 45 59 2c 20 73 69 7a 65 RIMARY0KEY, size | 3584: 20 42 4c 4f 42 29 81 33 04 07 17 1f 1f 01 82 35 BLOB).3.......5 | 3600: 74 61 62 6c 65 74 31 5f 73 65 67 64 69 72 74 31 tablet1_segdirt1 | 3616: 5f 73 65 67 64 69 25 04 43 52 45 41 54 45 20 54 _segdi%.CREATE T | 3632: 41 42 4c 45 20 27 74 31 5f 73 65 67 64 69 72 27 ABLE 't1_segdir' | 3648: 28 6c 65 76 65 6c 20 49 4e 54 45 47 45 52 2c 69 (level INTEGER,i | 3664: 64 78 20 49 4e 54 45 47 45 52 2c 73 74 61 72 74 dx INTEGER,start | 3680: 5f 62 6c 6f 63 6b 20 49 4e 54 45 47 45 52 2c 6c _block INTEGER,l | 3696: 65 61 76 65 73 5f 65 6e 64 5f 62 6c 6f 63 6b 20 eaves_end_block | 3712: 49 4d 54 45 47 45 52 2c 65 6e 64 5f 62 6c 6f 63 IMTEGER,end_bloc | 3728: 6b 20 49 4e 54 45 47 45 52 2c 72 6f 6f 74 20 42 k INTEGER,root B | 3744: 4c 4f 42 2c 50 52 49 4d 41 52 59 20 4b 45 59 28 LOB,PRIMARY KEY( | 3760: 6c 65 76 65 6c 2c 20 69 64 78 29 29 31 05 06 17 level, idx))1... | 3776: 45 1f 01 00 69 6e 64 65 78 73 71 6c 69 74 65 5f E...indexsqlite_ | 3792: 61 75 74 6f 69 6e 64 65 78 5f 74 31 5f 73 65 67 autoindex_t1_seg | 3808: 64 69 72 5f 31 74 31 5f 73 65 67 64 69 72 05 00 dir_1t1_segdir.. | 3824: 00 00 08 00 00 00 00 66 03 07 17 23 23 01 81 13 .......f...##... | 3840: 74 61 62 6c 65 74 31 5f 73 65 67 6d 65 6e 74 73 tablet1_segments | 3856: 74 31 5f 73 65 67 6d 65 6e 74 73 03 43 52 45 41 t1_segments.CREA | 3872: 54 45 20 54 41 42 4c 45 20 27 74 31 5f 73 65 67 TE TABLE 't1_seg | 3888: 6d 65 6e 74 73 27 28 62 6c 6f 63 6b 69 64 20 49 ments'(blockid I | 3904: 4e 54 45 47 45 52 20 50 52 49 4d 41 52 59 20 4b NTEGER PRIMARY K | 3920: 45 59 2c 20 62 6c 6f 63 6b 20 42 4c 4f 42 29 5c EY, block BLOB). | 3936: 02 07 17 21 21 01 81 03 74 61 62 6c 65 74 31 5f ...!!...tablet1_ | 3952: 63 6f 6e 74 65 6e 74 74 31 5f 63 6f 6e 74 65 6e contentt1_conten | 3968: 74 02 43 52 45 41 54 45 20 54 41 42 4c 45 20 27 t.CREATE TABLE ' | 3984: 74 31 5f 63 6f 6e 74 65 6e 74 27 28 64 6f 63 69 t1_content'(doci | 4000: 64 20 49 4e 54 45 47 45 52 20 50 52 49 4d 41 52 d INTEGER PRIMAR | 4016: 59 20 4b 45 59 2c 20 27 63 30 61 27 29 41 01 06 Y KEY, 'c0a')A.. | 4032: 17 11 11 08 71 74 61 62 6c 65 74 31 74 31 43 52 ....qtablet1t1CR | 4048: 45 41 54 45 20 56 49 52 54 55 41 4c 20 54 41 42 EATE VIRTUAL TAB | 4064: 4c 45 20 74 31 20 55 53 49 4e 47 20 66 74 73 34 LE t1 USING fts4 | 4080: 28 61 2c 70 72 65 66 69 78 3d 27 31 2c 32 27 29 (a,prefix='1,2') | page 2 offset 4096 | 0: 0d 00 00 00 08 0e 1f 00 0f c4 0f 7c 0f 34 0f 07 ...........|.4.. | 16: 0e c3 0e 97 0e 63 0e 1f 00 00 00 00 00 00 00 00 .....c.......... | 3600: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 42 ...............B | 3616: 08 04 00 81 09 73 75 6e 74 20 69 6e 20 63 75 6c .....sunt in cul | 3632: 70 61 20 71 75 68 20 6f 66 66 69 63 69 61 20 64 pa quh officia d | 3648: 65 73 65 72 75 6e 74 20 6d 6f 6c 6c 69 74 20 61 eserunt mollit a | 3664: 6e 69 6d 20 69 64 20 65 73 74 20 6c 61 62 6f 72 nim id est labor | 3680: 75 6d 2e 32 07 03 01 6b 45 78 63 65 70 74 65 75 um.2...kExcepteu | 3696: 72 20 73 69 6e 74 20 6f 63 63 61 65 63 61 74 20 r sint occaecat | 3712: 63 75 70 69 64 61 74 61 74 20 6e 6f 6e 20 70 72 cupidatat non pr | 3728: 6f 69 64 65 6e 74 2c 2a 06 03 00 5b 63 69 6c 6c oident,*...[cill | 3744: 75 6d 20 64 6f 6c 6f 72 65 20 65 75 20 66 75 67 um dolore eu fug | 3760: 69 61 74 20 6e 75 6c 6c 61 20 70 61 72 69 61 74 iat nulla pariat | 3776: 75 72 2e 43 05 04 00 81 09 44 75 69 73 20 61 75 ur.C.....Duis au | 3792: 74 65 20 69 72 75 72 65 20 64 6f 6c 6f 72 20 69 te irure dolor i | 3808: 6e 20 72 65 70 72 65 68 65 6e 64 65 72 69 74 20 n reprehenderit | 3824: 69 6e 20 76 6f 6c 75 70 74 61 74 65 20 76 65 6c in voluptate vel | 3840: 69 74 20 65 73 73 65 2b 14 03 00 5d 6e 69 73 69 it esse+...]nisi | 3856: 20 75 74 20 61 6c 69 71 75 69 70 20 65 78 20 65 ut aliquip ex e | 3872: 61 20 63 6f 6d 6d 6f 64 6f 20 63 6f 6e 73 65 71 a commodo conseq | 3888: 75 61 74 2e 46 03 04 00 81 11 55 74 20 65 6e 69 uat.F.....Ut eni | 3904: 6d 20 61 63 20 6d 69 6e 69 6d 20 76 65 6e 69 61 m ac minim venia | 3920: 6d 2c 20 71 75 69 73 20 6e 6f 73 74 72 75 64 20 m, quis nostrud | 3936: 65 78 65 72 63 69 74 61 74 69 6f 6e 20 75 6c 6c exercitation ull | 3952: 61 6d 63 6f 20 6c 61 62 6f 72 69 73 46 02 04 00 amco laborisF... | 3968: 81 11 73 65 64 20 64 6f 20 65 69 75 73 6d 6f 64 ..sed do eiusmod | 3984: 20 74 65 6d 70 6f 72 20 69 6e 63 69 64 69 64 75 tempor incididu | 4000: 6e 74 20 75 74 20 6c 61 62 6f 72 65 20 65 74 20 nt ut labore et | 4016: 64 6f 6c 6f 72 65 20 6d 61 67 6e 61 20 61 6c 69 dolore magna ali | 4032: 71 75 61 2e 3a 01 03 00 7b 4c 6f 72 65 6d 20 69 qua.:....Lorem i | 4048: 70 73 75 6d 20 64 6f 6c 6f 72 20 73 69 74 20 61 psum dolor sit a | 4064: 6d 65 74 2c 20 63 6f 6e 73 65 63 74 65 74 75 72 met, consectetur | 4080: 20 61 64 69 70 69 73 63 69 6e 67 20 65 6c 69 74 adipiscing elit | page 3 offset 8192 | 0: 0d 00 00 00 00 10 00 00 00 00 00 00 00 00 00 00 ................ | page 4 offset 12288 | 0: 0d 00 00 00 03 0a a6 00 0d 57 0c 4a 0a a6 00 00 .........W.J.... | 2720: 00 00 00 00 00 00 83 21 03 08 02 08 08 08 17 86 .......!........ | 2736: 30 08 00 30 20 34 30 32 00 02 61 64 06 01 08 00 0..0 402..ad.... | 2752: 02 04 00 01 01 6c 06 02 0c 00 02 04 00 01 01 6d .....l.........m | 2768: 03 01 06 00 01 01 6e 03 08 09 00 01 01 75 03 05 ......n......u.. | 2784: 03 00 00 02 63 69 03 06 01 00 01 01 6f 07 01 07 ....ci......o... | 2800: 00 03 07 03 00 01 01 75 06 07 05 00 01 04 00 00 .......u........ | 2816: 02 64 65 03 08 07 00 01 01 6f 0d 01 04 00 01 03 .de......o...... | 2832: 09 00 03 05 00 01 03 00 01 01 75 03 05 02 00 00 ..........u..... | 2848: 02 65 61 03 04 06 00 01 01 69 03 02 04 00 01 01 .ea......i...... | 2864: 6c 03 01 09 00 01 01 6e 03 03 03 00 01 01 73 06 l......n......s. | 2880: 05 0b 00 03 0b 00 01 01 74 03 02 09 00 01 01 75 ........t......u | 2896: 03 06 04 00 01 01 78 09 03 09 00 01 05 00 03 02 ......x......... | 2912: 00 00 02 66 75 03 06 05 00 00 02 69 64 03 08 0a ...fu......id... | 2928: 00 01 01 6e 0a 02 06 00 03 06 04 00 03 03 00 01 ...n............ | 2944: 01 70 03 01 13 00 01 01 72 03 05 04 00 00 02 6c .p......r......l | 2960: 61 09 02 08 00 01 0b 00 05 0c 00 01 01 6f 03 01 a............o.. | 2976: 02 00 00 02 6d 61 03 02 0b 00 01 01 69 03 03 05 ....ma......i... | 2992: 00 01 01 6f 03 08 08 00 00 02 6e 69 03 04 02 00 ...o......ni.... | 3008: 01 01 6f 06 03 08 00 04 06 00 01 01 75 03 06 06 ..o.........u... | 3024: 00 00 02 6f 63 03 07 04 00 01 01 66 03 08 06 00 ...oc......f.... | 3040: 00 02 70 61 03 06 07 00 01 01 72 03 07 07 00 00 ..pa......r..... | 3056: 02 71 75 06 03 07 00 05 05 00 00 02 72 65 03 05 .qu.........re.. | 3072: 07 00 00 02 73 65 03 02 02 00 01 01 69 06 01 05 ....se......i... | 3088: 00 06 03 00 01 01 75 03 08 02 00 00 02 74 65 03 ......u......te. | 3104: 03 05 00 00 02 72 bc 03 03 0a 00 01 01 74 09 02 .....r.......t.. | 3120: 07 00 01 02 00 01 03 00 00 02 76 65 06 03 06 00 ..........ve.... | 3136: 02 0a 00 01 01 6f 03 05 09 00 82 0a 02 08 02 08 .....o.......... | 3152: 08 08 17 84 02 04 00 30 20 32 35 31 00 01 61 13 .......0 251..a. | 3168: 01 06 04 00 01 0c 00 01 04 00 01 04 00 01 03 00 ................ | 3184: 03 09 00 00 01 63 10 01 07 00 03 07 03 00 02 02 .....c.......... | 3200: 00 01 05 00 01 04 00 00 01 64 11 01 04 00 01 03 .........d...... | 3216: 09 00 03 02 05 00 01 03 00 02 07 00 00 01 65 1b ..............e. | 3232: 01 09 00 01 04 07 00 01 03 08 00 01 05 03 00 01 ................ | 3248: 0b 00 01 04 00 01 02 00 01 0b 00 00 01 66 03 06 .............f.. | 3264: 05 00 00 01 69 0f 01 03 00 01 06 00 02 04 04 04 ....i........... | 3280: 00 03 03 09 00 00 01 6c 0c 01 02 00 01 08 00 01 .......l........ | 3296: 0b 00 05 0c 00 00 01 6d 09 02 0b 00 01 05 00 05 .......m........ | 3312: 08 00 00 01 6e 0c 03 08 00 01 02 00 02 06 00 01 ....n........... | 3328: 06 00 f0 01 6f 06 07 04 00 01 06 00 00 01 70 06 ....o.........p. | 3344: 06 07 00 01 07 00 00 01 71 06 03 07 00 05 05 00 ........q....... | 3360: 00 01 72 03 05 08 00 00 01 73 0c 01 05 00 01 02 ..r......s...... | 3376: 00 05 03 00 01 02 00 00 01 74 03 02 05 00 00 01 .........t...... | 3392: 75 0a 02 07 00 01 02 0a 00 01 03 00 00 01 76 07 u.............v. | 3408: 03 06 00 02 09 03 00 85 26 01 08 08 08 08 08 17 ........&....... | 3424: 8a 3e 30 21 36 36 35 00 02 61 64 03 03 04 00 02 .>0!665..ad..... | 3440: 08 69 70 69 73 63 69 6e 67 03 01 08 00 01 05 6c .ipiscing......l | 3456: 69 71 75 61 03 02 0c 00 05 02 69 70 03 04 04 00 iqua......ip.... | 3472: 01 03 6d 65 74 03 01 06 00 01 03 6e 69 6d 03 08 ..met......nim.. | 3488: 09 00 01 03 75 74 65 03 05 03 00 00 06 63 69 6c ....ute......cil | 3504: 6c 75 6d 03 06 02 00 01 06 6f 6d 6d 6f 64 6f 03 lum......ommodo. | 3520: 04 07 00 02 09 6e 73 65 63 74 65 74 75 72 03 01 .....nsectetur.. | 3536: 07 00 05 04 71 75 61 74 03 04 08 00 01 04 75 6c ....quat......ul | 3552: 70 61 03 08 04 00 02 07 70 69 64 61 74 61 74 03 pa......pidatat. | 3568: 07 05 00 00 08 64 65 73 65 72 75 6e 74 03 08 07 .....deserunt... | 3584: 00 01 01 6f 03 02 03 00 02 03 6c 6f 72 06 01 04 ...o......lor... | 3600: 00 04 05 00 05 01 65 06 02 0a 00 04 03 00 01 03 ......e......... | 3616: 75 69 73 03 05 02 00 00 02 65 61 03 04 06 00 01 uis......ea..... | 3632: 06 69 75 73 6d 6f 64 03 02 04 00 01 03 6c 69 74 .iusmod......lit | 3648: 03 01 09 00 01 03 6e 69 6d 03 03 03 00 01 03 73 ......nim......s | 3664: 73 65 03 05 0b 00 02 01 74 03 08 0b 00 01 01 74 se......t......t | 3680: 03 02 09 00 01 01 75 03 06 04 00 01 01 78 03 04 ......u......x.. | 3696: 05 00 02 07 63 65 70 74 65 75 72 03 07 02 00 02 ....cepteur..... | 3712: 0a 65 72 63 69 74 61 74 69 6f 6e 03 03 09 00 00 .ercitation..... | 3728: 06 66 75 67 69 61 74 03 06 05 00 00 02 69 64 03 .fugiat......id. | 3744: 08 0a 00 01 01 6e 07 05 06 04 00 03 03 00 02 08 .....n.......... | 3760: 63 69 64 69 64 75 6e 74 03 02 06 00 01 04 70 73 cididunt......ps | 3776: 75 6d 03 01 03 00 01 04 72 75 72 65 03 05 04 00 um......rure.... | 3792: 00 06 6c 61 62 6f 72 65 03 02 08 00 05 02 69 73 ..labore......is | 3808: 03 03 0b 00 05 02 75 6d 03 08 0c 00 01 04 6f 72 ......um......or | 3824: 65 6d 03 01 02 00 00 05 6d 61 67 6e 61 03 02 0b em......magna... | 3840: 00 01 04 69 6e 69 6d 03 03 05 00 01 05 6f 6c 6c ...inim......oll | 3856: 69 74 03 08 08 00 00 04 6e 69 73 69 03 04 02 00 it......nisi.... | 3872: 01 02 6f 6e 03 07 06 00 02 05 73 74 72 75 64 03 ..on......strud. | 3888: 03 08 00 01 04 75 6c 6c 61 03 06 06 00 00 08 6f .....ulla......o | 3904: 63 63 61 65 63 61 74 03 07 04 00 01 06 66 66 69 ccaecat......ffi | 3920: 63 69 61 03 08 06 00 00 08 70 61 72 69 61 74 75 cia......pariatu | 3936: 72 03 06 07 00 01 07 72 6f 69 64 65 6e 74 03 07 r......roident.. | 3952: 07 00 00 03 71 75 69 03 08 05 00 03 01 73 03 03 ....qui......s.. | 3968: 07 00 00 0d 72 65 41 72 65 68 65 6e 64 65 72 69 ....reArehenderi | 3984: 74 03 05 07 00 00 03 73 65 64 03 02 02 00 01 03 t......sed...... | 4000: 69 6e 74 03 07 03 00 02 01 74 03 01 05 00 01 03 int......t...... | 4016: 75 6e 74 03 08 02 00 00 06 74 65 6d 70 6f 72 03 unt......tempor. | 4032: 02 05 00 00 07 75 6c 6c 61 6d 63 6f 03 03 0a 00 .....ullamco.... | 4048: 01 01 74 09 02 07 00 01 02 00 01 03 00 00 05 76 ..t............v | 4064: 65 6c 69 74 03 05 0a 00 02 04 6e 69 61 6d 03 03 elit......niam.. | 4080: 06 00 01 08 70 6c 75 70 74 61 74 65 03 05 09 00 ....pluptate.... | page 5 offset 16384 | 0: 0a 00 00 00 03 0f eb 00 0f fb 0f f3 0f eb 00 00 ................ | 4064: 00 00 00 00 00 00 00 00 00 00 00 07 04 02 08 01 ................ | 4080: 08 00 03 07 04 0a 98 01 04 00 02 04 04 08 08 09 ................ | page 6 offset 20480 | 0: 0d 00 00 00 08 0f d0 00 0f fa 0f f4 0f ee 0f e8 ................ | 16: 0f e2 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ | 4048: 04 08 03 00 0e 0b 04 07 03 00 0e 06 04 06 03 00 ................ | 4064: 0e 06 04 05 03 00 0e 0a 04 04 03 00 0e 07 04 03 ................ | 4080: 03 00 0e 0a 04 02 03 00 0e 0b 04 01 03 00 0e 08 ................ | page 7 offset 24576 | 0: 0d 00 00 00 01 0f f7 00 0f f7 00 00 00 00 00 00 ................ | 4080: 00 00 00 00 00 00 00 07 00 03 00 14 08 45 b5 03 .............E.. | end crash-afecd03c862e58.db }]} {} do_execsql_test 20.1 { PRAGMA writable_schema = 1; BEGIN; WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<10) INSERT INTO t1(a) SELECT randomblob(3000) FROM c; } do_execsql_test 20.2 { INSERT INTO t1(t1) VALUES('optimize'); } #------------------------------------------------------------------------- reset_db do_test 21.0 { sqlite3 db {} db deserialize [decode_hexdb { | size 28672 pagesize 4096 filename crash-18cc014e42e828.db | page 1 offset 0 | 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3. | 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 07 .....@ ........ | 32: 00 00 00 02 00 00 00 01 00 00 00 07 00 00 00 04 ................ | 96: 00 00 00 00 0d 0e b1 00 06 0d a4 00 0f 8d 0f 21 ...............! | 112: 0e b9 0d c8 0e 7e 0d a4 00 00 00 00 00 00 00 00 .....~.......... | 3488: 00 00 00 00 22 07 06 17 11 11 01 31 74 61 62 6c ...........1tabl | 3504: 66 74 32 74 32 07 43 52 45 41 54 45 20 54 41 42 ft2t2.CREATE TAB | 3520: 4c 45 20 74 32 28 78 29 81 33 05 07 17 1f 1f 01 LE t2(x).3...... | 3536: 82 35 74 61 62 6c 65 74 31 5f 73 75 67 64 69 72 .5tablet1_sugdir | 3552: 74 31 5f 73 65 67 64 69 72 05 43 52 45 41 54 45 t1_segdir.CREATE | 3568: 20 54 41 42 4c 45 20 27 74 31 5f 73 65 67 64 69 TABLE 't1_segdi | 3584: 72 27 28 6c 65 76 65 6c 20 49 4e 54 45 47 45 52 r'(level INTEGER | 3600: 2c 69 64 78 20 49 4e 54 45 47 45 52 2c 73 74 61 ,idx INTEGER,sta | 3616: 72 74 5f 62 6c 6f 63 6b 20 49 4e 54 46 47 45 52 rt_block INTFGER | 3632: 2c 6c 65 61 76 65 73 5f 65 6e 64 5f 62 6c 6f 63 ,leaves_end_bloc | 3648: 6b 20 49 4e 54 45 47 45 52 2c 65 6e 64 5f 62 6c k INTEGER,end_bl | 3664: 6f 63 6b 20 49 4e 54 45 47 45 62 2c 72 6f 6f 74 ock INTEGEb,root | 3680: 20 42 4c 4f 42 2c 50 52 49 4d 41 52 59 20 4b 45 BLOB,PRIMARY KE | 3696: 59 28 6c 65 76 65 6c 2c 20 69 64 78 29 29 31 06 Y(level, idx))1. | 3712: 06 17 45 1f 01 00 69 6e 64 65 78 73 71 6c 69 74 ..E...indexsqlit | 3728: 65 5f 61 75 74 6f 69 6e 64 65 78 5f 74 31 5f 73 e_autoindex_t1_s | 3744: 65 67 64 69 72 5f 31 74 31 5f 73 65 67 64 69 72 egdir_1t1_segdir | 3760: 06 0f c7 00 08 00 00 00 00 66 04 07 17 23 23 01 .........f...##. | 3776: 81 13 74 61 62 6c 65 74 31 5f 73 65 67 6d 65 6e ..tablet1_segmen | 3792: 74 73 74 31 5f 73 65 67 6d 65 6e 74 73 04 43 52 tst1_segments.CR | 3808: 45 41 54 45 20 54 41 42 4c 45 20 27 74 31 5f 73 EATE TABLE 't1_s | 3824: 65 67 6d 65 6e 74 73 27 28 62 6c 6f 63 6b 69 64 egments'(blockid | 3840: 20 49 4e 54 45 47 45 52 20 50 52 49 4d 41 52 59 INTEGER PRIMARY | 3856: 20 4b 45 59 2c 20 62 6c 6f 63 6b 20 42 4c 4f 42 KEY, block BLOB | 3872: 29 6a 03 07 17 21 21 01 81 1f 74 61 62 6c 65 74 )j...!!...tablet | 3888: 31 5f 63 6f 6e 74 65 6e 74 74 31 5f 63 6f 6e 74 1_contentt1_cont | 3904: 65 6e 74 03 43 52 45 41 54 45 20 54 41 42 4c 45 ent.CREATE TABLE | 3920: 20 27 74 31 5f 63 6f 6e 74 65 6e 74 27 28 64 6f 't1_content'(do | 3936: 63 69 64 20 49 4e 54 45 47 45 52 20 50 52 49 4d cid INTEGER PRIM | 3952: 41 52 59 20 4b 45 59 2c 20 27 63 30 61 27 2c 20 ARY KEY, 'c0a', | 3968: 27 63 31 62 27 2c 20 27 63 32 63 27 29 38 02 06 'c1b', 'c2c')8.. | 3984: 17 11 11 08 5f 74 61 62 6c 65 74 31 74 31 43 52 ...._tablet1t1CR | 4000: 45 41 54 45 20 56 49 52 54 55 41 4c 20 54 41 42 EATE VIRTUAL TAB | 4016: 4c 45 20 74 31 20 55 53 49 4e 47 20 66 74 73 33 LE t1 USING fts3 | 4032: 28 61 2c 62 2c 63 29 00 00 00 00 00 00 00 00 00 (a,b,c)......... | page 3 offset 8192 | 0: 0d 00 00 00 25 0b 48 00 0f d8 0f af 0f 86 0f 74 ....%.H........t | 16: 0f 61 0f 4e 0f 2f 0f 0f 0e ef 0e d7 0e be 0e a5 .a.N./.......... | 32: 0e 8d 0e 74 0e 5b 0e 40 0e 24 0e 08 0d ef 0d d5 ...t.[.@.$...... | 48: 0d bb 0d a0 0d 84 0d 68 0d 4e 0d 35 0d 1b 0c fb .......h.N.5.... | 64: 0c da 0c b9 0c 99 0c 78 0c 57 0c 3e 0c 24 00 00 .......x.W.>.$.. | 2880: 00 00 00 00 00 00 00 00 81 3f 25 06 00 82 7f 00 .........?%..... | 2896: 00 43 4f 4d 50 49 4c 45 52 3d 67 63 63 2d 35 2e .COMPILER=gcc-5. | 2912: 34 23 00 20 32 30 31 36 30 36 30 39 20 44 45 42 4#. 20160609 DEB | 2928: 55 47 20 45 4e 41 42 4c 45 20 44 42 53 54 41 54 UG ENABLE DBSTAT | 2944: 20 56 54 41 42 20 45 4e 41 42 4c 45 20 46 43 53 VTAB ENABLE FCS | 2960: 34 20 45 4e 41 42 4c 45 20 46 54 53 35 20 45 4e 4 ENABLE FTS5 EN | 2976: 41 42 4c 45 20 47 45 4f 50 4f 4c 59 20 45 4e 41 ABLE GEOPOLY ENA | 2992: 42 4c 45 20 4a 53 4f 4e 31 20 45 4e 41 42 4c 45 BLE JSON1 ENABLE | 3008: 20 4d 45 4d 53 59 53 35 20 45 4e 41 42 4c 45 20 MEMSYS5 ENABLE | 3024: 52 54 52 45 45 20 4d 41 58 20 4d 45 4d 4f 52 59 RTREE MAX MEMORY | 3040: 3d 35 30 30 30 30 30 30 30 20 4f 4d 49 54 20 4c =50000000 OMIT L | 3056: 4f 41 44 20 45 58 54 45 4e 53 49 4f 4e 20 54 48 OAD EXTENSION TH | 3072: 52 45 41 44 53 41 46 45 3d 30 18 24 05 00 25 0f READSAFE=0.$..%. | 3088: 19 54 48 52 45 41 44 53 41 46 45 3d 30 58 42 49 .THREADSAFE=0XBI | 3104: 4e 41 52 59 18 23 05 00 25 0f 19 54 48 52 45 41 NARY.#..%..THREA | 3120: 44 53 41 46 45 3d 30 58 4e 4f 43 41 53 45 17 22 DSAFE=0XNOCASE.. | 3136: 05 00 25 0f 17 54 48 52 45 41 44 53 41 46 45 3d ..%..THREADSAFE= | 3152: 30 58 52 54 52 49 4d 20 21 05 00 33 0f 19 4f 4d 0XRTRIM !..3..OM | 3168: 49 54 20 4c 4f 41 44 20 45 58 54 45 4e 53 49 4f IT LOAD EXTENSIO | 3184: 4e 58 42 49 4e 41 52 59 1f 20 05 00 33 0f 19 4f NXBINARY. ..3..O | 3200: 4d 49 54 20 4c 4f 41 44 20 45 58 54 45 4e 53 49 MIT LOAD EXTENSI | 3216: 4f 4e 58 4e 4f 43 41 53 45 1e 1f 05 00 33 0f 17 ONXNOCASE....3.. | 3232: 4f 4d 49 54 20 4c 4f 41 44 20 45 58 54 45 4e 53 OMIT LOAD EXTENS | 3248: 49 4f 4e 58 52 54 52 49 4d 1f 1e 05 00 33 0f 19 IONXRTRIM....3.. | 3264: 4d 41 58 20 4d 45 4d 4f 52 59 3d 35 30 30 30 30 MAX MEMORY=50000 | 3280: 30 30 30 58 42 49 4e 41 52 59 1f 1d 05 00 33 0f 000XBINARY....3. | 3296: 19 4d 41 58 20 4d 45 4d 4f 52 59 3d 35 30 30 30 .MAX MEMORY=5000 | 3312: 30 30 30 30 58 4e 4f 43 41 53 45 1e 1c 05 00 33 0000XNOCASE....3 | 3328: 0f 17 4d 41 58 20 4d 45 4d 4f 52 59 3d 35 30 30 ..MAX MEMORY=500 | 3344: 30 30 30 30 30 58 52 54 52 49 4d 18 1b 05 00 25 00000XRTRIM....% | 3360: 0f 19 45 4e 41 42 4c 45 20 52 54 52 45 45 58 42 ..ENABLE RTREEXB | 3376: 49 4e 41 52 59 18 1a 05 00 25 0f 19 45 4e 41 42 INARY....%..ENAB | 3392: 4c 45 20 52 54 52 45 45 58 4e 4f 43 41 53 45 17 LE RTREEXNOCASE. | 3408: 19 05 00 25 0f 17 45 4e 41 42 4c 45 20 52 54 52 ...%..ENABLE RTR | 3424: 45 45 58 52 54 52 49 4d 1a 18 05 00 29 0f 19 45 EEXRTRIM....)..E | 3440: 4e 41 42 4c 45 20 4d 45 4d 53 59 53 35 58 42 49 NABLE MEMSYS5XBI | 3456: 4e 41 52 59 1a 17 05 00 29 0f 19 45 4e 41 42 4c NARY....)..ENABL | 3472: 45 20 4d 45 4d 53 59 53 35 58 4e 4f 43 41 53 45 E MEMSYS5XNOCASE | 3488: 19 16 05 00 29 0f 17 45 4e 41 42 4c 45 20 4d 45 ....)..ENABLE ME | 3504: 4d 53 59 53 35 58 52 54 52 49 4d 18 15 05 00 25 MSYS5XRTRIM....% | 3520: 0f 19 45 4e 41 42 4c 45 20 4a 53 4f 4e 31 58 42 ..ENABLE JSON1XB | 3536: 49 4e 41 52 59 18 14 05 00 25 0f 19 45 4e 41 42 INARY....%..ENAB | 3552: 4c 45 20 4a 53 4f 4e 31 58 4e 4f 43 41 53 45 17 LE JSON1XNOCASE. | 3568: 13 05 00 25 0f 17 45 4e 41 42 4c 45 20 4a 53 4f ...%..ENABLE JSO | 3584: 4e 31 58 52 54 52 49 4d 1a 12 05 00 29 0f 19 45 N1XRTRIM....)..E | 3600: 4e 41 42 4c 45 20 47 45 4f 50 4f 4c 59 58 42 39 NABLE GEOPOLYXB9 | 3616: 4e 41 52 59 1a 11 05 00 29 0f 19 45 4e 41 1e 4c NARY....)..ENA.L | 3632: 45 20 47 45 4f 50 4f 4c 59 58 4e 4f 43 41 53 45 E GEOPOLYXNOCASE | 3648: 19 10 05 00 29 0f 17 45 4e 41 42 4c 45 20 47 45 ....)..ENABLE GE | 3664: 4f 50 4f 4c 59 58 52 54 52 49 4d 17 0f 05 00 23 OPOLYXRTRIM....# | 3680: 0f 19 45 4e 41 42 4c 45 20 46 54 53 35 58 42 49 ..ENABLE FTS5XBI | 3696: 4e 41 52 59 17 0e 05 00 23 0f 19 45 4e 41 42 4c NARY....#..ENABL | 3712: 45 20 46 54 53 35 58 4e 4f 43 41 53 45 16 0d 05 E FTS5XNOCASE... | 3728: 00 23 0f 16 45 4e 41 42 4c 45 20 46 54 53 35 58 .#..ENABLE FTS5X | 3744: 52 54 52 49 4d 17 0c 05 00 23 0f 19 45 4e 41 42 RTRIM....#..ENAB | 3760: 4c 45 20 46 54 53 34 58 42 48 4e 41 52 59 17 0b LE FTS4XBHNARY.. | 3776: 05 00 23 0e 19 45 4e 41 42 4c 45 20 46 54 53 35 ..#..ENABLE FTS5 | 3792: 58 4e 4f 43 40 53 45 16 0a 05 00 23 0f 17 45 4e XNOC@SE....#..EN | 3808: 41 42 4c 45 20 46 54 53 34 58 52 2e 52 49 4d 1e ABLE FTS4XR.RIM. | 3824: 09 05 00 31 0f 19 45 4e 41 42 4c 45 20 44 42 53 ...1..ENABLE DBS | 3840: 54 41 54 20 56 54 41 42 58 42 49 4e 41 52 59 1e TAT VTABXBINARY. | 3856: 08 05 00 31 0f 19 45 4e 41 42 4c 45 20 44 42 53 ...1..ENABLE DBS | 3872: 54 41 54 20 56 54 41 42 58 4e 4f 43 41 53 45 1d TAT VTABXNOCASE. | 3888: 07 05 00 31 0f 17 45 4e 41 42 4c 45 20 44 42 53 ...1..ENABLE DBS | 3904: 54 41 54 20 56 54 41 42 58 52 54 52 49 4d 11 06 TAT VTABXRTRIM.. | 3920: 05 00 17 0f 19 44 45 42 55 47 58 42 49 4e 41 52 .....DEBUGXBINAR | 3936: 59 11 05 05 00 17 0f 19 44 45 42 55 47 58 4e 4f Y.......DEBUGXNO | 3952: 43 41 53 45 10 04 05 00 17 0f 17 44 45 42 55 47 CASE.......DEBUG | 3968: 58 52 54 52 49 4d 27 03 05 00 43 0f 19 43 4f 4d XRTRIM'...C..COM | 3984: 50 49 4c 45 52 3d 67 63 63 2d 35 2e 34 2e 30 20 PILER=gcc-5.4.0 | 4000: 32 30 31 36 30 36 30 39 58 42 49 da 41 52 59 27 20160609XBI.ARY' | 4016: 02 05 00 43 0f 19 43 4f 4d 50 49 4c 45 52 3d 67 ...C..COMPILER=g | 4032: 63 63 2d 35 2e 34 2e 30 20 32 30 31 36 30 36 30 cc-5.4.0 2016060 | 4048: 39 58 4e 4f 43 41 53 45 26 01 05 00 43 0f 17 43 9XNOCASE&...C..C | 4064: 4f 4d 50 49 4c 45 52 3d 67 63 63 2d 00 00 00 00 OMPILER=gcc-.... | page 5 offset 16384 | 0: 0d 00 00 00 02 0b a0 00 0c ad 0b a0 00 00 00 00 ................ | 2976: 82 0a 02 08 08 09 08 08 17 84 06 30 20 32 35 33 ...........0 253 | 2992: 00 01 30 04 25 06 1b 00 00 08 32 30 31 36 30 36 ..0.%.....201606 | 3008: 30 3a 03 25 07 00 00 01 34 03 25 05 00 00 01 35 0:.%....4.%....5 | 3024: 03 25 04 00 01 07 30 30 30 30 30 30 30 03 25 1a .%....0000000.%. | 3040: 00 00 08 63 6f 6d 70 69 6c 65 72 03 25 02 00 00 ...compiler.%... | 3056: 06 64 62 73 74 61 74 03 25 0a 00 01 04 65 62 75 .dbstat.%....ebu | 3072: 67 03 25 08 00 00 06 65 6e 61 62 6c 65 09 25 09 g.%....enable.%. | 3088: 05 04 04 04 04 04 00 01 08 78 74 65 6e 73 69 6f .........xtensio | 3104: 6e 03 25 1d 00 00 04 66 74 73 34 03 25 0d 00 03 n.%....fts4.%... | 3120: 01 35 03 25 0f 00 00 03 57 63 63 03 25 03 00 01 .5.%....Wcc.%... | 3136: 06 65 6f 70 6f 6c 79 03 25 11 00 00 05 6a 73 6f .eopoly.%....jso | 3152: 6e 31 03 25 13 00 00 04 6c 6f 61 64 03 25 1c 00 n1.%....load.%.. | 3168: 00 03 6d 61 78 03 25 18 00 01 05 65 6d 6f 72 79 ..max.%....emory | 3184: 03 25 19 00 03 04 73 79 73 35 03 25 15 00 00 04 .%....sys5.%.... | 3200: 6f 6d 69 74 03 25 1b 00 00 05 72 74 72 65 65 03 omit.%....rtree. | 3216: 25 17 00 00 0a 74 68 72 65 64 64 73 61 66 65 03 %....threddsafe. | 3232: 25 1e 00 00 04 76 74 61 62 03 25 0b 00 86 50 01 %....vtab.%...P. | 3248: 08 08 08 08 08 17 8d 12 30 20 38 33 35 00 01 30 ........0 835..0 | 3264: 12 01 06 00 01 06 00 01 06 00 1f 03 00 01 03 00 ................ | 3280: 01 03 00 00 08 32 30 31 36 30 36 30 39 09 01 07 .....20160609... | 3296: 00 01 07 00 01 07 00 00 01 34 09 01 05 00 01 05 .........4...... | 3312: 00 01 05 00 00 01 35 09 01 04 00 01 04 00 01 04 ......5......... | 3328: 00 01 07 30 30 30 30 30 30 30 09 1c 04 00 01 04 ...0000000...... | 3344: 00 01 04 00 00 06 62 69 6e 61 72 79 3c 03 01 02 ......binary<... | 3360: 02 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 ................ | 3376: 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 00 ................ | 3392: 03 01 02 02 00 03 01 02 02 00 03 01 02 02 00 03 ................ | 3408: 01 02 02 00 03 01 02 02 00 00 08 63 6f 6d 70 69 ...........compi | 3424: 6c 65 72 09 01 02 00 01 02 00 01 02 00 00 06 64 ler............d | 3440: 62 73 74 61 74 09 07 03 00 01 03 00 01 03 00 01 bstat........... | 3456: 04 65 62 75 67 09 04 02 00 01 02 00 01 02 00 00 .ebug........... | 3472: 06 65 6e 61 62 6c 65 3f 07 02 00 01 02 00 01 12 .enable?........ | 3488: 00 01 02 00 01 02 00 01 02 00 01 02 0e 97 02 00 ................ | 3504: 01 02 00 01 cb 00 01 02 00 01 02 00 01 02 10 01 ................ | 3520: 02 00 01 02 00 01 02 01 01 02 00 01 02 00 01 02 ................ | 3536: 00 01 02 00 01 02 00 01 08 78 74 65 6e 73 69 6f .........xtensio | 3552: 6e 09 1f 04 00 01 04 00 01 04 00 00 04 66 74 73 n............fts | 3568: 34 09 0a 03 00 01 03 00 01 03 00 03 01 35 09 0d 4............5.. | 3584: 03 00 01 03 00 01 03 00 00 03 67 63 63 09 01 03 ..........gcc... | 3600: 00 01 03 00 01 03 00 01 06 65 6f 70 6f 6c 79 09 .........eopoly. | 3616: 10 03 00 01 03 00 01 03 00 00 05 6a 73 6f 6e 31 ...........json1 | 3632: 09 13 03 00 01 03 00 01 03 00 00 04 6c 6f 61 64 ............load | 3648: 09 1f 03 00 01 03 00 01 03 00 00 03 6d 61 78 09 ............max. | 3664: 1c 02 00 01 02 00 01 02 00 01 05 65 6d 6f 72 79 ...........emory | 3680: 09 1c 03 00 01 03 00 01 03 00 03 04 73 79 73 35 ............sys5 | 3696: 09 16 03 00 01 03 00 01 03 00 00 06 6e 6f 63 61 ............noca | 3712: 73 65 3c 02 01 02 02 00 03 01 02 02 00 03 01 02 se<............. | 3728: 02 00 03 01 02 02 00 03 01 02 02 00 ab 01 02 02 ................ | 3744: 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 00 ................ | 3760: 03 01 02 02 00 03 01 02 02 00 03 01 02 02 00 00 ................ | 3776: 04 6f 6d 69 74 09 1f 12 00 01 02 00 01 02 00 00 .omit........... | 3792: 05 72 74 72 65 65 09 19 03 00 01 03 00 01 03 00 .rtree.......... | 3808: 03 02 69 6d 3c 01 01 02 02 00 03 01 02 02 00 03 ..im<........... | 3824: 01 02 02 00 03 01 02 02 00 03 01 02 02 00 03 01 ................ | 3840: 02 02 00 03 01 02 01 f0 03 01 02 02 00 03 01 02 ................ | 3856: 02 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 ................ | 3872: 00 00 0a 74 68 72 65 61 64 73 61 66 65 09 22 02 ...threadsafe... | 3888: 00 01 02 00 02 02 00 00 04 76 74 61 62 09 07 04 .........vtab... | 3904: 00 01 04 00 01 04 00 00 01 78 b4 01 01 01 08 a2 .........x...... | 3920: 00 01 01 01 02 00 01 01 01 02 00 02 01 01 02 00 ................ | 3936: 01 01 01 01 ff f1 01 01 02 00 01 01 01 02 00 01 ................ | 3952: 01 01 02 00 01 01 01 02 00 01 01 01 02 00 01 01 ................ | 3968: 01 02 00 01 01 01 02 00 01 01 01 02 00 01 01 01 ................ | 3984: 02 00 01 01 01 02 00 01 01 01 02 01 01 01 01 02 ................ | 4000: 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 ................ | 4016: 01 01 01 02 00 01 01 01 02 00 01 01 01 03 00 01 ................ | 4032: 01 01 02 00 01 01 01 02 00 01 01 01 02 00 01 01 ................ | 4048: 01 02 00 01 01 01 02 00 01 01 01 02 00 01 01 01 ................ | 4064: 02 00 01 01 01 02 00 01 02 01 02 00 01 01 01 02 ................ | 4080: 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 ................ | page 6 offset 20480 | 0: 0a 00 00 00 02 0f f5 00 0f fb 0f f5 00 00 00 00 ................ | 4080: 00 00 00 00 00 05 04 08 09 01 02 04 04 08 08 09 ................ | page 7 offset 24576 | 0: 0d 00 00 00 05 0f b8 00 00 00 00 00 00 00 00 00 ................ | 4016: 00 00 00 00 00 00 00 00 0d 05 02 23 61 75 74 6f ...........#auto | 4032: 6d 65 72 67 65 3d 35 0d 04 02 23 6d 65 72 67 65 merge=5...#merge | 4048: 3d 31 30 30 2c 38 11 03 02 2b 69 6e 74 65 67 72 =100,8...+integr | 4064: 69 74 79 2d 63 68 65 63 6b 09 02 02 1b 72 65 62 ity-check....reb | 4080: 75 69 6c 64 0a 01 02 1d 00 00 00 00 00 00 00 00 uild............ | end crash-18cc014e42e828.db }]} {} do_catchsql_test 21.1 { PRAGMA writable_schema = 1; SELECT offsets(t1) FROM t1 WHERE t1 MATCH 'R*'; } {1 {database disk image is malformed}} #------------------------------------------------------------------------- reset_db do_test 22.0 { sqlite3 db {} db deserialize [decode_hexdb { | size 28672 pagesize 4096 filename crash-b794c89d922ac9.db | page 1 offset 0 | 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3. | 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 07 .....@ ........ | 32: 00 00 00 02 00 00 00 01 00 00 00 07 00 00 00 00 ................ | 96: 00 00 00 00 0d 0e b1 00 06 0d a4 00 0f 8d 0f 21 ...............! | 112: 0e b9 0d c8 0e 7e 0d a4 00 00 00 00 00 00 00 00 .....~.......... | 3488: 00 00 00 00 22 07 06 17 11 11 01 31 74 61 62 6c ...........1tabl | 3504: 65 74 32 74 32 07 43 52 45 41 54 45 20 54 41 42 et2t2.CREATE TAB | 3520: 4c 45 20 74 32 28 78 29 81 33 05 07 17 1f 1f 01 LE t2(x).3...... | 3536: 82 35 74 61 61 6c 65 74 31 5f 73 65 67 64 69 72 .5taalet1_segdir | 3552: 74 31 5f 73 65 67 64 69 72 05 43 52 45 41 54 45 t1_segdir.CREATE | 3568: 20 54 41 42 4c 45 20 27 74 31 5f 73 65 67 64 69 TABLE 't1_segdi | 3584: 72 27 28 6c 65 76 65 6c 20 49 4e 54 45 47 45 52 r'(level INTEGER | 3600: 2c 69 64 78 20 49 4e 54 45 47 45 52 2c 73 74 61 ,idx INTEGER,sta | 3616: 72 74 5f 62 6c 6f 63 6b 20 49 4e 54 45 47 45 52 rt_block INTEGER | 3632: 2c 6c 65 61 76 65 73 5f 65 6e 64 5f 62 6c 6f 63 ,leaves_end_bloc | 3648: 6b 20 49 4e 54 45 47 45 52 2c 65 6e 64 5f 62 6c k INTEGER,end_bl | 3664: 6f 63 6b 20 49 4e 54 45 47 45 52 2c 72 6f 6f 74 ock INTEGER,root | 3680: 20 42 4c 4f 42 2c 50 52 49 4d 41 52 59 20 4b 45 BLOB,PRIMARY KE | 3696: 59 28 6c 65 76 65 6c 2c 20 69 64 78 29 29 31 06 Y(level, idx))1. | 3712: 06 17 45 1f 01 00 69 6e 64 65 78 73 71 6c 69 74 ..E...indexsqlit | 3728: 65 5f 61 75 74 6f 69 6e 64 65 78 5f 74 31 5f 73 e_autoindex_t1_s | 3744: 65 67 64 69 72 5f 31 74 31 5f 73 65 67 64 69 72 egdir_1t1_segdir | 3760: 06 0f c7 00 08 00 00 00 00 66 04 07 17 23 23 01 .........f...##. | 3776: 81 13 74 61 62 6c 65 74 31 5f 73 65 67 6d 65 6e ..tablet1_segmen | 3792: 74 73 74 31 5f 73 65 67 6d 65 6e 74 73 04 43 52 tst1_segments.CR | 3808: 45 41 54 45 20 54 41 42 4c 45 20 27 74 31 5f 73 EATE TABLE 't1_s | 3824: 65 67 6d 65 6e 74 73 27 28 62 6c 6f 63 6b 69 64 egments'(blockid | 3840: 20 49 4e 54 45 47 45 52 20 50 52 49 4d 41 52 59 INTEGER PRIMARY | 3856: 20 4b 45 59 2c 20 62 6c 6f 63 6b 20 42 4c 4f 42 KEY, block BLOB | 3872: 29 6a 03 07 17 21 21 01 81 1f 74 61 62 6c 65 74 )j...!!...tablet | 3888: 31 5f 63 6f 6e 84 65 6e 74 74 31 5f 63 6f 6e 74 1_con.entt1_cont | 3904: 65 6e 74 03 43 52 45 41 54 45 20 54 41 42 4c 45 ent.CREATE TABLE | 3920: 20 27 74 31 5f 63 6f 6e 74 65 6e 74 27 28 64 6f 't1_content'(do | 3936: 63 69 64 20 49 4e 54 45 47 45 52 20 50 52 49 4d cid INTEGER PRIM | 3952: 41 52 59 20 4b 45 59 2c 20 27 63 30 61 27 2c 20 ARY KEY, 'c0a', | 3968: 27 63 31 62 27 2c 20 27 63 32 63 27 29 38 02 06 'c1b', 'c2c')8.. | 3984: 17 11 11 08 5f 74 61 62 6c 65 74 31 74 31 43 52 ...._tablet1t1CR | 4000: 45 41 54 45 20 56 49 52 54 55 41 4c 20 54 41 42 EATE VIRTUAL TAB | 4016: 4c 45 20 74 31 20 55 53 49 4e 47 20 66 74 73 33 LE t1 USING fts3 | 4032: 28 61 2c 62 2c 63 29 00 00 00 00 00 00 00 00 00 (a,b,c)......... | page 3 offset 8192 | 0: 0d 00 00 00 25 0b 48 00 0f d8 0f af 0f 86 0f 74 ....%.H........t | 16: 0f 61 0f 4e 0f 2f 0f 0f 0e ef 0e d7 0e be 0e a5 .a.N./.......... | 32: 0e 8d 0e 74 0e 5b 0e 40 0e 24 0e 08 0d ef 0d d5 ...t.[.@.$...... | 48: 0d bb 0d a0 0d 84 0d 68 0d 4f 0d 35 0d 1b 0c fb .......h.O.5.... | 64: 0c da 0c b9 0c 99 0c 78 0c 57 0c 3e 0c 24 0c 0a .......x.W.>.$.. | 80: 0b 48 00 00 00 00 00 00 00 00 00 00 00 00 00 00 .H.............. | 2880: 00 00 00 00 00 00 00 00 81 3f 25 06 00 82 7f 00 .........?%..... | 2896: 00 43 4f 4d 50 49 4c 45 52 3d 67 63 63 2d 35 2e .COMPILER=gcc-5. | 2912: 34 2e 30 20 32 30 31 36 30 36 30 39 20 44 45 42 4.0 20160609 DEB | 2928: 55 47 20 45 4e 41 42 4c 45 20 44 42 53 54 41 54 UG ENABLE DBSTAT | 2944: 20 56 54 41 42 20 45 4e 41 42 4c 45 20 46 54 53 VTAB ENABLE FTS | 2960: 34 20 45 4e 41 42 4c 45 20 46 54 53 35 20 45 4e 4 ENABLE FTS5 EN | 2976: 41 42 4c 45 20 47 45 4f 50 4f 4c 59 20 45 4e 41 ABLE GEOPOLY ENA | 2992: 42 4c 45 20 4a 53 4f 4e 31 20 45 4e 41 42 4c 45 BLE JSON1 ENABLE | 3008: 20 4d 45 4d 53 49 53 35 20 45 4e 41 42 4c 45 20 MEMSIS5 ENABLE | 3024: 52 54 52 45 45 20 4d 41 58 20 4d 45 4d 4f 52 59 RTREE MAX MEMORY | 3040: 3d 35 30 30 30 30 30 30 30 20 4f 4d 49 54 20 4c =50000000 OMIT L | 3056: 4f 41 44 20 45 58 54 45 4e 53 49 4f 4e 20 54 48 OAD EXTENSION TH | 3072: 52 45 41 44 53 41 46 45 3d 30 18 24 05 00 26 0f READSAFE=0.$..&. | 3088: 19 54 48 52 45 41 44 53 41 46 45 3d 30 58 42 49 .THREADSAFE=0XBI | 3104: 4e 41 52 59 18 23 05 00 25 0f 19 54 48 52 45 41 NARY.#..%..THREA | 3120: 44 53 41 46 45 3d 30 58 4e 4f 43 41 53 45 17 22 DSAFE=0XNOCASE.. | 3136: 05 00 25 0f 17 54 48 52 45 41 44 53 41 46 45 3d ..%..THREADSAFE= | 3152: 30 58 52 54 52 49 4d 1f 21 05 00 33 0f 19 4f 4d 0XRTRIM.!..3..OM | 3168: 49 54 20 4c 4f 41 44 20 45 58 54 45 4e 53 49 4f IT LOAD EXTENSIO | 3184: 4e 58 42 49 4e 41 52 59 1f 20 05 00 33 0f 19 4f NXBINARY. ..3..O | 3200: 4d 49 54 20 4c 4f 41 44 20 45 58 54 45 4e 53 49 MIT LOAD EXTENSI | 3216: 4f 4e 58 4e 4f 43 41 53 45 1e 1f 05 00 33 0f 17 ONXNOCASE....3.. | 3232: 4f 4d 49 54 20 4c 4f 41 44 20 45 58 54 45 4e 53 OMIT LOAD EXTENS | 3248: 49 4f 4e 58 52 54 52 49 4d 1f 1e 05 00 33 0f 19 IONXRTRIM....3.. | 3264: 4d 41 58 20 4d 45 4d 4f 52 59 3d 35 30 30 30 30 MAX MEMORY=50000 | 3280: 30 30 30 58 42 49 4e 41 52 59 1f 1d 05 00 33 0f 000XBINARY....3. | 3296: 19 4d 41 58 20 4d 45 4d 4f 52 59 3d 35 30 30 30 .MAX MEMORY=5000 | 3312: 30 30 30 30 58 4e 4f 43 41 53 45 1e 1c 05 00 33 0000XNOCASE....3 | 3328: 0f 17 4d 41 58 20 4d 45 4d 4f 52 59 3d 35 30 30 ..MAX MEMORY=500 | 3344: 30 30 30 30 30 58 52 54 52 49 4d 18 1b 05 00 25 00000XRTRIM....% | 3360: 0f 19 45 4e 41 42 4c 45 20 52 54 52 45 45 58 42 ..ENABLE RTREEXB | 3376: 49 4e 41 52 59 18 1a 05 00 25 0f 19 45 4e 41 42 INARY....%..ENAB | 3392: 4c 55 20 52 54 52 45 45 58 4e 4f 43 41 53 45 17 LU RTREEXNOCASE. | 3408: 19 05 00 25 0f 17 45 4e 41 42 4c 45 20 52 54 52 ...%..ENABLE RTR | 3424: 45 45 58 52 54 52 49 4d 1a 18 05 00 29 0f 19 45 EEXRTRIM....)..E | 3440: 4e 41 42 4c 45 20 4d 45 4d 53 59 53 35 58 42 49 NABLE MEMSYS5XBI | 3456: 4e 41 52 59 1a 17 05 00 29 0f 19 45 4e 41 42 4c NARY....)..ENABL | 3472: 45 20 4d 45 4d 53 59 53 35 58 4e 4f 43 41 53 45 E MEMSYS5XNOCASE | 3488: 19 16 05 00 29 0f 17 45 4e 41 42 4c 45 20 4d 45 ....)..ENABLE ME | 3504: 4d 53 59 53 35 58 52 54 52 49 4d 18 15 05 00 25 MSYS5XRTRIM....% | 3520: 0f 19 45 4e 41 42 4c 45 20 4a 53 4f 4e 31 58 42 ..ENABLE JSON1XB | 3536: 49 4e 41 52 59 18 14 05 00 25 0f 19 45 4e 41 42 INARY....%..ENAB | 3552: 4c 45 20 4a 53 4f 4e 31 58 4e 4f 43 41 53 45 17 LE JSON1XNOCASE. | 3568: 13 05 00 25 0f 17 45 4e 41 42 4c 45 20 4a 53 4f ...%..ENABLE JSO | 3584: 4e 31 58 52 54 52 49 4d 1a 12 05 00 29 0f 19 45 N1XRTRIM....)..E | 3600: 4e 41 42 4c 45 20 47 45 4f 50 4f 4c 59 58 42 49 NABLE GEOPOLYXBI | 3616: 4e 41 52 59 1a 11 05 00 29 0f 19 45 4e 41 42 4c NARY....)..ENABL | 3632: 45 20 47 45 4f 50 4f 4c 59 58 4e 4f 43 41 53 45 E GEOPOLYXNOCASE | 3648: 19 10 05 00 29 0f 17 45 4e 41 42 4c 45 20 47 45 ....)..ENABLE GE | 3664: 4f 50 4f 4c 59 58 52 54 52 49 4d 17 0f 05 00 23 OPOLYXRTRIM....# | 3680: 0f 19 45 4e 41 42 4c 45 20 46 54 53 35 58 42 49 ..ENABLE FTS5XBI | 3696: 4e 41 52 59 17 0e 05 00 23 0f 19 45 4e 41 42 4c NARY....#..ENABL | 3712: 45 20 46 54 53 35 58 4e 4f 43 41 53 45 16 0d 05 E FTS5XNOCASE... | 3728: 00 23 0f 17 45 4e 41 42 4c 45 20 46 54 53 35 58 .#..ENABLE FTS5X | 3744: 52 54 52 49 4d 17 0c 05 00 23 0f 19 45 4e 41 42 RTRIM....#..ENAB | 3760: 4c 45 19 46 54 53 34 58 42 49 4e 41 52 59 17 0b LE.FTS4XBINARY.. | 3776: 05 00 23 0f 19 45 4e 41 42 4e f5 20 46 54 53 34 ..#..ENABN. FTS4 | 3792: 58 4e 4f 43 41 53 45 16 0a 05 00 23 0f 17 45 4e XNOCASE....#..EN | 3808: 41 42 4c 45 20 46 54 53 34 58 52 54 52 49 4d 1e ABLE FTS4XRTRIM. | 3824: 09 05 00 31 0f 19 45 4e 41 42 4c 45 20 44 42 53 ...1..ENABLE DBS | 3840: 54 41 54 20 56 54 41 42 58 42 49 4e 41 52 59 1e TAT VTABXBINARY. | 3856: 08 05 00 31 0f 19 45 4e 41 42 4c 45 20 44 42 53 ...1..ENABLE DBS | 3872: 54 41 54 20 56 54 41 42 58 4e 4f 43 41 53 45 1d TAT VTABXNOCASE. | 3888: 07 05 00 31 0f 17 45 4e 41 42 4c 45 20 44 41 53 ...1..ENABLE DAS | 3904: 54 41 54 20 56 54 41 42 58 52 54 52 49 4d 11 06 TAT VTABXRTRIM.. | 3920: 05 00 17 0f 19 44 45 42 55 47 58 42 49 4e 41 52 .....DEBUGXBINAR | 3936: 59 11 05 05 00 17 0f 19 44 45 42 55 47 58 4e 4f Y.......DEBUGXNO | 3952: 43 41 53 45 10 04 05 00 17 ab 17 44 45 42 55 47 CASE.......DEBUG | 3968: 48 52 54 52 49 4d 27 03 05 00 43 0f 19 43 4f 4d HRTRIM'...C..COM | 3984: 50 49 4c 45 52 3d 67 63 63 2d 35 2e 34 2e 30 20 PILER=gcc-5.4.0 | 4000: 32 30 31 36 30 36 30 39 58 43 49 4e 41 52 59 27 20160609XCINARY' | 4016: 02 04 00 43 0f 19 43 4f 4d 50 49 4c 45 52 3d 67 ...C..COMPILER=g | 4032: 63 63 2d 35 2e 34 2e 30 20 32 30 31 36 30 36 30 cc-5.4.0 2016060 | 4048: 39 58 4e 4f 43 41 53 45 26 01 05 00 43 0f 17 43 9XNOCASE&...C..C | 4064: 4f 4d 50 49 4c 45 52 3d 67 63 63 2d 35 2e 34 2e OMPILER=gcc-5.4. | 4080: 30 20 32 30 31 36 30 36 30 39 58 52 54 52 49 4d 0 20160609XRTRIM | page 4 offset 12288 | 0: 0d 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ | page 5 offset 16384 | 0: 0d 00 00 00 02 0b a0 00 0c ad 0b a0 00 00 00 00 ................ | 2976: 82 0a 02 08 08 09 08 08 17 84 06 30 20 32 35 33 ...........0 253 | 2992: 00 01 30 04 25 06 1b 00 00 08 32 30 31 36 30 36 ..0.%.....201606 | 3008: 30 39 03 25 07 00 00 01 34 03 25 05 00 00 01 35 09.%....4.%....5 | 3024: 03 25 04 00 01 07 30 30 30 30 30 30 30 03 25 1a .%....0000000.%. | 3040: 00 00 08 63 6f 6d 70 69 6c 65 72 03 25 02 00 00 ...compiler.%... | 3056: 06 64 62 73 74 61 74 03 25 0a 00 01 04 65 62 75 .dbstat.%....ebu | 3072: 67 03 25 08 00 00 06 65 6e 61 62 6c 65 09 25 09 g.%....enable.%. | 3088: 05 04 04 04 04 04 00 01 08 78 74 65 6e 73 69 6f .........xtensio | 3104: 6e 03 25 1d 00 00 04 66 74 73 34 03 25 0d 00 03 n.%....fts4.%... | 3120: 01 35 03 25 0f 00 00 03 67 63 63 03 25 03 00 01 .5.%....gcc.%... | 3136: 06 65 6f 70 6f 6c 79 03 25 11 00 00 05 6a 73 6f .eopoly.%....jso | 3152: 6e 31 03 25 13 00 00 04 6c 6f 61 64 03 25 1c 00 n1.%....load.%.. | 3168: 00 03 6d 61 78 03 25 18 00 01 05 65 6d 6f 72 79 ..max.%....emory | 3184: 03 25 19 00 03 04 73 79 73 35 03 25 15 00 00 04 .%....sys5.%.... | 3200: 6f 6d 69 74 03 25 1b 00 00 05 72 74 72 65 65 03 omit.%....rtree. | 3216: 25 17 00 00 0a 74 68 72 65 61 64 73 61 66 65 03 %....threadsafe. | 3232: 25 1e 00 00 04 76 74 61 62 03 25 0b 00 86 50 01 %....vtab.%...P. | 3248: 08 08 08 08 08 17 8d 12 30 20 38 33 35 00 01 30 ........0 835..0 | 3264: 12 01 06 00 01 06 00 01 06 00 1f 03 00 01 03 00 ................ | 3280: 01 03 00 00 08 32 30 31 36 30 36 30 39 09 01 07 .....20160609... | 3296: 00 01 07 00 01 07 00 00 01 34 09 01 05 00 01 05 .........4...... | 3312: 00 01 05 00 00 01 35 09 01 04 00 01 04 00 01 04 ......5......... | 3328: 00 01 07 30 30 30 30 30 30 30 09 1c 04 00 01 04 ...0000000...... | 3344: 00 01 04 00 00 06 62 69 6e 61 72 79 3c 03 01 02 ......binary<... | 3360: 02 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 ................ | 3376: 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 00 ................ | 3392: 03 01 02 02 00 03 01 02 02 00 03 01 02 02 00 03 ................ | 3408: 01 02 02 00 03 01 02 02 00 00 08 63 6f 6d 70 69 ...........compi | 3424: 6c 65 72 09 01 02 00 01 02 00 01 02 00 00 06 64 ler............d | 3440: 62 73 74 61 74 09 07 03 00 01 03 00 01 03 00 01 bstat........... | 3456: 04 65 62 75 67 09 04 02 00 01 02 00 01 02 00 00 .ebug........... | 3472: 06 65 6e 61 62 6c 65 3f 07 02 00 01 02 00 01 02 .enable?........ | 3488: 00 01 02 00 01 02 00 01 02 00 01 02 00 01 02 00 ................ | 3504: 01 02 00 01 02 00 01 02 00 01 02 00 01 02 00 01 ................ | 3520: 02 00 01 02 00 01 02 00 01 02 00 01 02 00 01 02 ................ | 3536: 00 01 02 00 01 02 00 01 08 78 74 65 6e 73 69 6f .........xtensio | 3552: 6e 09 1f 04 00 01 04 00 01 04 00 00 04 66 74 73 n............fts | 3568: 34 09 0a 03 d4 01 02 ff 01 03 00 03 01 35 09 0d 4............5.. | 3584: 03 00 01 03 00 01 03 00 00 03 67 64 d3 09 01 03 ..........gd.... | 3600: 00 01 03 00 01 03 00 01 06 65 6f 70 6f 6c 79 09 .........eopoly. | 3616: 10 03 00 01 03 00 01 03 00 00 05 6a 73 6f 6e 31 ...........json1 | 3632: 19 13 03 00 01 03 00 01 03 00 00 04 6c 6f 61 64 ............load | 3648: 09 1f 03 00 01 03 00 01 03 00 00 03 6d 61 78 09 ............max. | 3664: 1c 02 00 01 02 00 01 02 00 01 05 65 6d 6f 72 79 ...........emory | 3680: 09 1c 03 00 01 03 00 01 03 00 03 04 73 79 73 35 ............sys5 | 3696: 09 16 03 00 01 03 00 01 03 00 00 06 6e 6f 63 61 ............noca | 3712: 73 65 3c 02 01 02 02 00 03 01 02 02 00 03 01 02 se<............. | 3728: 02 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 ................ | 3744: 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 00 ................ | 3760: 03 01 02 02 00 03 01 02 02 00 03 01 02 02 00 00 ................ | 3776: 04 6f 6d 69 74 09 1f 02 00 01 12 00 01 02 00 00 .omit........... | 3792: 05 72 74 72 65 65 09 19 03 00 01 07 80 00 f3 00 .rtree.......... | 3808: 03 02 69 6d 3c 01 01 02 02 00 03 01 02 02 00 03 ..im<........... | 3824: 01 02 02 00 03 01 02 02 00 03 01 02 02 00 03 01 ................ | 3840: 02 02 00 03 01 02 02 00 03 01 02 02 00 03 01 02 ................ | 3856: 02 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 ................ | 3872: 00 00 0a 74 68 72 65 61 64 73 61 66 65 09 22 02 ...threadsafe... | 3888: 00 01 02 00 01 02 00 00 04 76 74 61 62 09 07 04 .........vtab... | 3904: 00 01 04 00 01 04 00 00 01 78 b4 01 01 01 01 02 .........x...... | 3920: 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 ................ | 3936: 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 01 ................ | 3952: 01 01 02 00 01 01 01 02 00 01 01 01 02 00 01 01 ................ | 3968: 01 02 00 01 01 01 02 00 01 01 01 02 00 01 01 01 ................ | 3984: 02 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 ................ | 4000: 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 ................ | 4016: 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 01 ................ | 4032: 01 01 02 00 01 01 01 02 00 01 01 01 02 00 01 01 ................ | 4048: 01 02 00 01 01 01 02 00 01 01 01 02 00 01 01 01 ................ | 4064: 02 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 ................ | 4080: 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 ................ | page 6 offset 20480 | 0: 0a 00 00 00 02 0f f5 00 0f fb 0f f5 00 00 00 00 ................ | 4080: 00 00 00 00 00 05 04 08 09 01 02 04 04 08 08 09 ................ | page 7 offset 24576 | 0: 0d 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ | 4016: 00 00 00 00 00 00 00 00 0d 05 02 23 61 75 74 6f ...........#auto | 4032: 6d 65 72 67 65 3d 35 0d 04 02 23 6d 65 72 67 65 merge=5...#merge | 4048: 3d 31 30 30 2c 38 11 03 02 2b 69 6e 74 65 67 72 =100,8...+integr | 4064: 69 74 79 2d 63 68 65 63 6b 09 02 02 1b 72 65 62 ity-check....reb | end crash-b794c89d922ac9.db }]} {} do_catchsql_test 22.1 { PRAGMA writable_schema = 1; SELECT snippet(t1,'', '', '--',-1,01)==0 FROM t1 WHERE a MATCH 'rtree OR json1rtree OR json1'; } {0 {0 0 0 0 0 0 0}} #------------------------------------------------------------------------- reset_db do_test 23.0 { sqlite3 db {} db deserialize [decode_hexdb { .open --hexdb | size 28672 pagesize 4096 filename crash-670b15f2955a36.db | page 1 offset 0 | 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3. | 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 07 .....@ ........ | 32: 00 00 00 02 10 00 00 01 00 00 00 07 00 00 00 00 ................ | 96: 00 00 00 00 0d 0e b1 00 06 0d a4 00 0f 8d 0f 21 ...............! | 112: 0e b9 0d c8 0e 7e 0d a4 00 00 00 00 00 00 00 00 .....~.......... | 3488: 00 00 00 00 22 07 06 17 11 11 01 31 74 61 62 6c ...........1tabl | 3504: 65 74 32 74 32 07 43 52 45 41 54 45 20 54 41 42 et2t2.CREATE TAB | 3520: 4c 45 20 74 32 28 78 29 81 33 05 07 17 1f 1f 01 LE t2(x).3...... | 3536: 82 35 74 61 62 6c 65 74 31 5f 73 65 67 64 69 72 .5tablet1_segdir | 3552: 74 31 5f 73 65 67 64 69 72 05 43 52 45 41 54 45 t1_segdir.CREATE | 3568: 20 54 41 42 4c 45 20 27 74 31 5f 73 65 67 64 69 TABLE 't1_segdi | 3584: 72 27 28 6c 65 76 65 6c 20 49 4e 54 45 47 45 52 r'(level INTEGER | 3600: 2c 69 64 78 20 49 4e 54 45 47 45 52 2c 73 74 61 ,idx INTEGER,sta | 3616: 72 74 5f 62 6c 6f 63 6b 20 49 4e 54 45 47 45 52 rt_block INTEGER | 3632: 2c 6c 65 61 76 65 73 5f 65 6e 64 5f 62 6c 6f 63 ,leaves_end_bloc | 3648: 6b 20 49 4e 54 45 47 45 52 2c 65 6e 64 5f 62 6c k INTEGER,end_bl | 3664: 6f 63 6b 20 49 4e 54 45 47 45 52 2c 72 6f 6f 74 ock INTEGER,root | 3680: 20 42 4c 4f 42 2c 50 52 49 4d 41 52 59 20 4b 45 BLOB,PRIMARY KE | 3696: 59 28 6c 65 76 65 6c 2c 20 69 64 78 29 29 31 06 Y(level, idx))1. | 3712: 06 17 45 1f 01 00 69 6e 64 65 78 73 71 6c 69 74 ..E...indexsqlit | 3728: 65 5f 61 75 74 6f 69 6e 64 65 78 5f 74 31 5f 73 e_autoindex_t1_s | 3744: 65 67 64 69 72 5f 31 74 31 5f 73 65 67 64 69 72 egdir_1t1_segdir | 3760: 06 0f c7 00 08 00 00 00 00 66 04 07 17 23 23 01 .........f...##. | 3776: 81 13 74 61 62 6c 75 74 31 5f 73 65 67 6d 65 6e ..tablut1_segmen | 3792: 74 73 74 31 5f 73 65 67 6d 65 6e 74 73 04 43 52 tst1_segments.CR | 3808: 45 41 54 45 20 54 41 42 4c 45 20 27 74 31 5f 73 EATE TABLE 't1_s | 3824: 65 67 6d 65 6e 74 73 27 28 62 6c 6f 63 6b 69 64 egments'(blockid | 3840: 20 49 4e 54 45 47 45 42 20 50 52 49 4d 41 52 59 INTEGEB PRIMARY | 3856: 20 4b 45 59 2c 20 62 6c 6f 63 6b 20 42 4c 4f 42 KEY, block BLOB | 3872: 29 6a 03 07 17 21 21 01 81 1f 74 61 62 6c 65 74 )j...!!...tablet | 3888: 31 5f 63 6f 6e 74 65 6e 74 74 31 5f 63 6f 6e 74 1_contentt1_cont | 3904: 65 6e 74 03 43 52 45 41 54 45 20 54 41 42 4c 45 ent.CREATE TABLE | 3920: 20 27 74 31 5f 63 6f 6e 74 65 6e 74 27 28 64 6f 't1_content'(do | 3936: 63 69 64 20 49 4e 54 45 47 45 52 20 50 52 49 4d cid INTEGER PRIM | 3952: 41 52 59 20 4b 45 59 2c 20 27 63 30 61 27 2c 20 ARY KEY, 'c0a', | 3968: 27 63 31 62 27 2c 20 27 63 32 63 27 29 38 02 06 'c1b', 'c2c')8.. | 3984: 17 11 11 08 5f 74 61 62 6c 65 74 31 74 31 43 52 ...._tablet1t1CR | 4000: 45 41 54 45 20 56 49 52 54 55 41 4c 20 54 41 42 EATE VIRTUAL TAB | 4016: 4c 45 20 74 31 20 55 53 49 4e 47 20 66 74 73 33 LE t1 USING fts3 | 4032: 28 61 2c 62 2c 63 29 00 00 00 00 00 00 00 00 00 (a,b,c)......... | page 3 offset 8192 | 0: 0d 00 00 00 25 0b 48 01 0f d8 00 2f 0f 86 0f 74 ....%.H..../...t | 16: 0f 61 0f 4e 0f 2f 0f 0f 0e ef 0e d7 0e be 0e a5 .a.N./.......... | 32: 0e 8d 0e 74 0e 5a fe 40 0e 24 0e 08 0d ef 0d d5 ...t.Z.@.$...... | 48: 0d bb 0d a0 0d 84 0d 68 0d 4f 81 35 0d 1b 0c fb .......h.O.5.... | 64: 0c da 0c b9 0c 99 0c 78 0c 57 0c 3e 00 00 00 00 .......x.W.>.... | 2880: 00 00 00 00 00 00 00 00 81 3f 25 06 00 82 7f 10 .........?%..... | 2896: 00 43 4f 4d 50 49 4c 45 52 3d 67 63 63 2d 35 2e .COMPILER=gcc-5. | 2912: 34 2e 30 20 32 30 31 36 30 36 30 39 20 44 45 42 4.0 20160609 DEB | 2928: 55 47 20 45 4e 41 42 4c 45 20 44 42 53 54 41 54 UG ENABLE DBSTAT | 2944: 20 56 54 41 42 20 45 4e 41 42 4c 45 20 46 54 53 VTAB ENABLE FTS | 2960: 34 20 45 4e 41 42 4c 45 20 46 54 53 35 20 45 4e 4 ENABLE FTS5 EN | 2976: 41 42 4c 45 20 47 45 4f 50 4f 4c 59 20 45 4e 41 ABLE GEOPOLY ENA | 2992: 42 4c 45 20 4a 53 4f 4e 31 20 45 4e 41 42 4c 45 BLE JSON1 ENABLE | 3008: 20 4d 45 4d 53 59 53 35 20 45 4e 41 42 4c 45 20 MEMSYS5 ENABLE | 3024: 52 54 52 45 45 20 4d 41 58 20 4d 45 4d 4f 52 59 RTREE MAX MEMORY | 3040: 3d 35 30 30 30 30 30 30 30 20 4f 4d 49 54 20 4c =50000000 OMIT L | 3056: 4f 41 44 20 45 58 54 45 4e 53 49 4f 4e 20 54 48 OAD EXTENSION TH | 3072: 52 45 41 44 53 41 46 45 3d 30 18 24 05 00 35 0f READSAFE=0.$..5. | 3088: 19 54 48 52 45 41 44 53 41 46 45 3d 30 58 42 49 .THREADSAFE=0XBI | 3104: 4e 41 52 59 18 23 55 00 25 0f 19 54 48 52 45 41 NARY.#U.%..THREA | 3120: 44 53 41 46 45 3d 30 58 4e 4f 43 41 53 45 17 22 DSAFE=0XNOCASE.. | 3136: 05 00 25 0f 17 54 48 52 45 41 44 53 41 46 45 3d ..%..THREADSAFE= | 3152: 30 58 52 54 52 49 4d 1f 21 05 00 33 0f 19 4f 4d 0XRTRIM.!..3..OM | 3168: 49 54 20 4c 4f 41 44 20 45 58 54 45 4e 53 49 4f IT LOAD EXTENSIO | 3184: 4e 58 42 49 4e 41 52 59 1f 20 05 00 33 0f 19 4f NXBINARY. ..3..O | 3200: 4d 49 54 20 4c 4f 41 44 20 45 58 54 45 4e 53 49 MIT LOAD EXTENSI | 3216: 4f 4e 58 4e 4f 43 41 53 45 1e 1f 05 00 33 0f 17 ONXNOCASE....3.. | 3232: 4f 4d 49 54 20 4c 4f 41 44 20 45 58 54 45 4e 53 OMIT LOAD EXTENS | 3248: 49 4f 4e 58 52 54 52 49 4d 1f 1e 05 00 33 0f 19 IONXRTRIM....3.. | 3264: 4d 41 58 20 4d 45 4d 4f 52 59 3d 35 30 30 30 30 MAX MEMORY=50000 | 3280: 30 30 30 58 42 49 4e 41 52 59 1f 1d 05 00 33 0f 000XBINARY....3. | 3296: 19 4d 41 58 20 4d 45 4d 4f 52 59 3d 35 30 30 30 .MAX MEMORY=5000 | 3312: 30 30 30 30 58 4e 4f 43 41 53 45 1e 1c 05 00 33 0000XNOCASE....3 | 3328: 0f 17 4d 41 58 20 4d 45 4d 4f 52 59 3d 35 30 30 ..MAX MEMORY=500 | 3344: 30 30 30 30 30 58 52 54 52 49 4d 18 1b 05 00 25 00000XRTRIM....% | 3360: 0f 19 45 4e 41 42 4c 44 20 52 54 52 45 45 58 42 ..ENABLD RTREEXB | 3376: 49 4e 41 52 59 18 1a 05 00 25 0f 19 45 4e 41 42 INARY....%..ENAB | 3392: 4c 45 20 52 54 52 45 45 58 4e 4f 43 41 53 45 17 LE RTREEXNOCASE. | 3408: 19 05 00 24 0f 17 45 4e 40 42 4c 45 20 52 54 52 ...$..EN@BLE RTR | 3424: 45 45 58 52 54 52 49 4d 1a 18 05 00 29 0f 19 45 EEXRTRIM....)..E | 3440: 4e 41 42 4c 45 20 4d 45 4d 53 59 53 35 58 42 49 NABLE MEMSYS5XBI | 3456: 4e 41 52 59 1a 17 05 00 29 0f 19 45 4d 41 42 4c NARY....)..EMABL | 3472: 45 20 4d 45 4d 53 59 53 35 58 4e 4f 43 41 4c 45 E MEMSYS5XNOCALE | 3488: 19 16 05 00 29 0f 17 45 4e 41 42 4c 45 20 4d 45 ....)..ENABLE ME | 3504: 4e 53 59 53 35 58 52 54 52 49 4d 18 15 05 00 25 NSYS5XRTRIM....% | 3520: 0f 19 45 4e 41 42 4c 45 20 4a 53 4f 4e 31 58 42 ..ENABLE JSON1XB | 3536: 49 4e 41 52 59 18 14 05 00 25 0f 19 45 4e 41 42 INARY....%..ENAB | 3552: 4c 45 20 4a 53 4f 4e 31 58 4e 4f 43 41 53 45 17 LE JSON1XNOCASE. | 3568: 13 05 00 25 0f 17 45 4e 41 42 4c 45 20 4a 53 4f ...%..ENABLE JSO | 3584: 4e 31 58 52 54 5f b9 4d 1a 12 05 00 29 0f 19 45 N1XRT_.M....)..E | 3600: 4e 41 42 4c 45 20 47 45 4f 50 31 4c 59 58 42 49 NABLE GEOP1LYXBI | 3616: 4e 41 52 58 1a 11 05 00 29 0f 19 45 4e 41 42 4c NARX....)..ENABL | 3632: 45 20 47 45 4f 50 4f 4c 59 58 4e 4f 43 41 53 45 E GEOPOLYXNOCASE | 3648: 19 10 05 00 29 0f 17 45 4e 41 42 4c 45 20 57 45 ....)..ENABLE WE | 3664: 4f 50 4f 4c 59 48 52 54 52 49 4d 17 0f 05 00 23 OPOLYHRTRIM....# | 3680: 0f 19 45 4e 41 42 4c 45 20 46 54 53 35 58 42 49 ..ENABLE FTS5XBI | 3696: 4e 41 53 59 17 0e 05 00 23 0f 19 45 4e 40 42 4b NASY....#..EN@BK | 3712: 45 20 46 54 53 35 58 4e 4f 43 41 53 45 16 0d 05 E FTS5XNOCASE... | 3728: 00 23 0f 17 45 4e 41 42 4c 45 20 46 54 53 35 58 .#..ENABLE FTS5X | 3744: 52 54 52 49 4d 17 0c 05 00 23 0f 19 45 4e 41 42 RTRIM....#..ENAB | 3760: 4c 45 20 46 54 94 34 58 42 49 4e 41 52 59 17 0b LE FT.4XBINARY.. | 3776: 05 00 23 0f 19 45 4e 41 42 4c 43 70 46 54 53 34 ..#..ENABLCpFTS4 | 3792: 58 4e 4f 43 41 53 45 16 0a 05 00 23 0f 17 45 4e XNOCASE....#..EN | 3808: 41 42 4c 45 20 46 54 53 34 58 52 54 52 49 4d 1e ABLE FTS4XRTRIM. | 3824: 09 05 00 31 0f 19 45 4e 41 42 4c 45 20 44 42 53 ...1..ENABLE DBS | 3840: 54 41 54 20 56 54 41 42 58 42 49 4e 41 52 59 1e TAT VTABXBINARY. | 3856: 08 05 00 31 0f 19 45 4e 41 42 4c 45 20 44 32 53 ...1..ENABLE D2S | 3872: 54 41 54 20 56 54 41 42 58 4e 4f 43 41 53 45 1d TAT VTABXNOCASE. | 3888: 07 05 00 31 0f 17 45 4e 41 42 4c 45 20 44 42 53 ...1..ENABLE DBS | 3904: 54 41 54 20 56 54 41 42 58 52 54 52 49 4d 11 06 TAT VTABXRTRIM.. | 3920: 05 0b 27 0f 19 44 45 42 55 47 58 42 49 4e 41 52 ..'..DEBUGXBINAR | 3936: 59 11 05 05 00 17 0f 19 44 45 42 55 47 58 4e 4f Y.......DEBUGXNO | 3952: 43 41 53 45 10 03 05 00 17 0f 17 44 45 42 55 47 CASE.......DEBUG | 3968: 58 52 54 52 49 4d 27 03 05 00 43 0f 19 43 4f 4d XRTRIM'...C..COM | 3984: 50 49 4c 45 52 3d 67 63 63 2d 35 2e 34 2e 30 20 PILER=gcc-5.4.0 | 4000: 32 30 31 36 30 36 30 39 58 42 49 4e 41 52 59 27 20160609XBINARY' | 4016: 02 05 00 43 0f 19 43 4f 4d 50 49 4c 35 52 3d 67 ...C..COMPIL5R=g | 4032: 63 63 2d 35 2e 34 2e 30 20 32 30 31 36 30 36 30 cc-5.4.0 2016060 | 4048: 39 58 4e 4f 43 41 53 45 26 01 05 00 43 0f 02 43 9XNOCASE&...C..C | 4064: 4f 4d 50 49 4c 45 52 3d 67 63 63 2d 35 2e 34 2e OMPILER=gcc-5.4. | 4080: 30 20 32 30 31 36 30 36 30 39 58 00 00 00 00 00 0 20160609X..... | page 5 offset 16384 | 0: 0d 00 00 00 02 0b a0 00 0c ad 0b a0 00 00 00 00 ................ | 2976: 82 0a 02 08 08 09 08 08 17 84 06 30 20 32 35 33 ...........0 253 | 2992: 00 01 30 04 25 06 1b 00 00 08 32 30 31 36 30 36 ..0.%.....201606 | 3008: 30 39 03 25 07 00 00 01 34 03 25 05 00 00 01 35 09.%....4.%....5 | 3024: 03 25 04 00 01 07 30 30 30 30 30 30 30 08 55 1a .%....0000000.U. | 3040: 00 00 08 63 6f 6d 70 69 6c 65 72 03 25 02 00 00 ...compiler.%... | 3056: 06 64 62 73 74 61 74 03 25 0a 00 01 04 65 61 75 .dbstat.%....eau | 3072: 67 03 25 08 00 00 06 65 6e 61 62 6c 65 09 25 09 g.%....enable.%. | 3088: 05 04 04 04 04 04 00 01 08 78 74 65 6e 73 69 6f .........xtensio | 3104: 6e 03 25 1d 00 00 04 66 74 73 34 03 25 0d 00 03 n.%....fts4.%... | 3120: 01 35 03 25 0f 00 00 0c 97 63 63 03 25 03 00 01 .5.%.....cc.%... | 3136: 06 65 6f 70 6f 6c 7a 03 25 11 00 00 05 6a 73 6f .eopolz.%....jso | 3152: 6e 31 03 25 13 00 00 04 6c 6f 61 64 03 25 1c 00 n1.%....load.%.. | 3168: 00 03 6d 61 78 03 25 18 00 01 05 65 6d 6f 72 79 ..max.%....emory | 3184: 03 25 3d f0 03 04 73 79 73 35 03 25 15 00 00 04 .%=...sys5.%.... | 3200: 6f 6d 69 74 03 25 1b 00 00 05 72 74 72 65 65 03 omit.%....rtree. | 3216: 25 17 00 00 0a 74 68 72 65 61 64 73 61 66 65 03 %....threadsafe. | 3232: 25 1e 00 00 04 76 74 61 62 03 25 0b 00 86 50 01 %....vtab.%...P. | 3248: 08 08 08 09 08 17 8d 12 30 20 38 33 37 e3 aa e0 ........0 837... | 3264: 12 d1 06 00 01 06 00 01 06 00 1f 03 00 01 03 00 ................ | 3280: 01 03 00 00 08 32 30 31 36 30 36 30 49 09 01 07 .....2016060I... | 3296: 00 01 07 00 01 07 00 00 01 34 09 01 05 00 01 05 .........4...... | 3312: 00 01 05 00 00 01 35 09 01 04 00 01 04 00 01 04 ......5......... | 3328: 00 01 07 30 30 30 30 30 30 30 09 1c 04 00 01 04 ...0000000...... | 3344: 00 01 04 00 00 06 62 69 6e 61 72 79 3c 03 01 02 ......binary<... | 3360: 02 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 ................ | 3376: 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 00 ................ | 3392: 03 01 02 02 00 03 01 02 02 00 03 01 02 02 00 03 ................ | 3408: 01 02 02 00 03 01 02 02 00 00 08 63 6f 6d 70 69 ...........compi | 3424: 6c 65 72 09 01 02 00 01 02 00 01 02 00 00 06 64 ler............d | 3440: 62 73 74 61 74 09 07 03 00 01 03 00 01 03 00 01 bstat........... | 3456: 04 65 62 75 67 09 04 01 f0 01 02 00 01 02 00 00 .ebug........... | 3472: 06 65 6e 61 62 6c 65 3f 07 02 00 01 02 00 01 02 .enable?........ | 3488: 00 01 02 00 01 02 00 01 02 00 01 02 00 01 02 00 ................ | 3504: 01 02 00 01 02 00 01 02 00 01 02 00 01 02 00 01 ................ | 3520: 02 00 01 02 00 01 02 00 01 02 00 01 02 00 01 02 ................ | 3536: 00 01 02 00 01 02 00 01 08 78 74 65 6e 73 69 6f .........xtensio | 3552: 6e 09 1f 04 00 01 04 00 01 04 00 00 04 66 74 73 n............fts | 3568: 34 09 0a 03 f3 01 03 00 01 03 00 19 01 35 09 0d 4............5.. | 3584: 03 00 01 03 00 01 03 00 00 03 67 63 63 09 01 03 ..........gcc... | 3600: 00 01 03 00 01 03 00 01 06 65 6f 70 6f 6c 79 09 .........eopoly. | 3616: 10 03 00 01 03 00 01 03 00 00 05 6a 73 6f 6e 31 ...........json1 | 3632: 09 13 03 00 01 03 00 00 f3 00 00 04 6c 6f 61 64 ............load | 3648: 09 1f 03 00 01 03 00 01 03 00 00 03 6d 61 78 09 ............max. | 3664: 1c 02 00 01 02 00 01 02 00 01 05 65 6d 6f 72 79 ...........emory | 3680: 09 1c 03 00 01 03 00 01 03 00 03 04 73 79 73 35 ............sys5 | 3696: 09 16 03 00 01 03 00 01 03 00 00 06 6e 6f 63 61 ............noca | 3712: 73 65 3c 02 01 02 02 00 03 01 02 02 00 03 01 02 se<............. | 3728: 02 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 ................ | 3744: 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 00 ................ | 3760: 03 01 02 02 00 03 01 02 02 00 46 01 02 02 00 00 ..........F..... | 3776: 04 6f 6d 69 74 09 1f 02 00 01 02 00 01 02 00 00 .omit........... | 3792: 05 72 74 72 64 65 09 19 03 00 01 03 00 01 03 00 .rtrde.......... | 3808: 03 02 69 6d 3c 01 01 02 02 00 03 01 02 02 00 03 ..im<........... | 3824: 01 02 02 00 03 01 02 01 ff 03 01 02 02 00 03 01 ................ | 3840: 02 02 00 03 01 02 02 00 03 01 02 02 00 03 01 02 ................ | 3856: 02 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 ................ | 3872: 00 00 0a 74 68 72 65 61 64 73 61 66 65 09 22 02 ...threadsafe... | 3888: 00 01 02 00 01 02 00 00 04 76 74 61 62 09 07 04 .........vtab... | 3904: 00 01 04 00 01 04 00 00 01 78 b4 01 01 01 01 02 .........x...... | 3920: 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 ................ | 3936: 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 01 ................ | 3952: 01 01 02 00 01 01 01 02 00 01 01 01 02 00 01 01 ................ | 3968: 01 02 00 01 01 01 02 00 01 01 01 02 00 01 01 01 ................ | 3984: 02 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 ................ | 4000: 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 ................ | 4016: 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 01 ................ | 4032: 01 01 02 00 01 01 01 02 00 01 01 01 02 00 01 01 ................ | 4048: 01 02 00 01 01 01 02 00 01 01 01 02 00 01 01 01 ................ | 4064: 02 00 01 01 01 02 00 01 01 01 02 00 01 01 02 02 ................ | 4080: 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 ................ | page 6 offset 20480 | 0: 0a 00 00 00 02 0f f5 00 0f fb 0f f5 00 00 00 00 ................ | 4080: 00 00 00 00 00 05 04 08 09 01 02 04 04 08 09 09 ................ | page 7 offset 24576 | 0: 0d 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ | 4016: 00 00 00 00 00 00 00 00 0d 05 02 23 61 75 74 6f ...........#auto | 4032: 6d 65 71 97 65 3d 35 0d 04 02 23 6d 65 72 67 65 meq.e=5...#merge | 4048: 3d 31 30 30 2c 38 11 03 02 2b 69 6e 74 65 67 72 =100,8...+integr | 4064: 69 74 79 00 00 00 00 00 00 00 00 00 00 00 00 00 ity............. | end crash-670b15f2955a36.db }]} {} do_catchsql_test 23.1 { PRAGMA writable_schema = 1; SELECT 'FyzLy'FROM t1 WHERE t1 MATCH 'j'; } {1 {database disk image is malformed}} #------------------------------------------------------------------------- reset_db do_test 24.0 { sqlite3 db {} db deserialize [decode_hexdb { .open --hexdb | size 28672 pagesize 4096 filename crash-369d042958c29b.db | page 1 offset 0 | 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3. | 16: 10 00 01 01 00 40 20 20 00 00 03 10 00 00 00 00 .....@ ........ | 96: 00 00 00 00 0d 0e b1 00 06 0d a4 00 0f 8d 0f 21 ...............! | 112: 0e b9 0d c8 0e 7e 0d a4 00 00 00 00 00 00 00 00 .....~.......... | 3488: 00 00 00 00 22 07 06 17 11 11 01 31 74 61 62 6c ...........1tabl | 3504: 65 74 32 74 32 07 43 52 45 41 54 45 20 54 41 42 et2t2.CREATE TAB | 3520: 4c 45 20 74 32 28 78 29 81 33 05 07 17 1f 1f 01 LE t2(x).3...... | 3536: 82 35 74 61 62 6c 65 74 31 5f 73 65 67 64 69 72 .5tablet1_segdir | 3552: 74 31 5f 73 65 67 64 69 72 05 43 52 45 41 54 45 t1_segdir.CREATE | 3568: 20 54 41 42 4c 45 20 27 74 31 5f 73 65 67 64 69 TABLE 't1_segdi | 3584: 72 27 28 6c 65 76 65 6c 20 49 4e 54 45 47 45 52 r'(level INTEGER | 3600: 2c 69 64 78 20 49 4e 54 45 47 45 52 2c 73 74 61 ,idx INTEGER,sta | 3616: 72 74 5f 62 6c 6f 63 6b 20 49 4e 54 45 47 45 52 rt_block INTEGER | 3632: 2c 6c 65 61 76 65 73 5f 65 6e 64 5f 62 6c 6f 63 ,leaves_end_bloc | 3648: 6b 20 49 4e 54 45 47 45 52 2c 65 6e 64 5f 62 6c k INTEGER,end_bl | 3664: 6f 63 6b 20 49 4e 54 45 47 45 52 2c 72 6f 6f 74 ock INTEGER,root | 3680: 20 42 4c 4f 42 2c 50 52 49 4d 41 52 59 20 4b 45 BLOB,PRIMARY KE | 3696: 59 28 6c 65 76 65 6c 2c 20 69 64 78 29 29 31 06 Y(level, idx))1. | 3712: 06 17 45 1f 01 00 69 6e 64 65 78 73 71 6c 69 74 ..E...indexsqlit | 3728: 65 5f 61 75 74 6f 69 6e 64 65 78 5f 74 31 5f 73 e_autoindex_t1_s | 3744: 65 67 64 69 72 5f 31 74 31 5f 73 65 67 64 69 72 egdir_1t1_segdir | 3760: 06 0f c7 00 08 00 10 00 00 66 04 07 17 23 23 01 .........f...##. | 3776: 81 13 74 61 62 6c 65 74 31 5f 73 65 67 6d 65 6e ..tablet1_segmen | 3792: 64 73 74 31 5f 73 65 67 6d 65 6e 74 73 04 43 52 dst1_segments.CR | 3808: 45 41 54 45 20 54 41 42 4c 45 20 27 74 31 5f 73 EATE TABLE 't1_s | 3824: 65 67 6d 65 6e 74 73 27 28 62 6c 6f 63 6b 69 64 egments'(blockid | 3840: 20 49 4e 54 45 47 45 52 20 50 52 49 4d 41 52 59 INTEGER PRIMARY | 3856: 20 4b 45 59 2c 20 62 6c 6f 63 6b 20 42 4c 4f 42 KEY, block BLOB | 3872: 29 6a 03 07 17 21 21 01 81 1f 74 61 62 6c 65 74 )j...!!...tablet | 3888: 31 4f 63 6f 6e 74 65 6e 74 74 31 5f 63 6f 6e 74 1Ocontentt1_cont | 3904: 65 6e 74 03 43 52 45 41 54 45 20 54 41 42 4c 45 ent.CREATE TABLE | 3920: 20 27 74 31 5f 63 6f 6e 74 65 6e 74 27 28 64 6f 't1_content'(do | 3936: 63 69 64 20 49 4e 54 45 47 45 52 20 50 52 39 4d cid INTEGER PR9M | 3952: 41 52 59 20 4b 45 59 2c 20 27 63 30 61 27 2c 20 ARY KEY, 'c0a', | 3968: 27 63 31 62 27 2c 20 27 63 32 63 27 29 38 02 06 'c1b', 'c2c')8.. | 3984: 17 11 11 08 5f 74 61 62 6c 65 74 31 74 31 43 52 ...._tablet1t1CR | 4000: 45 41 54 45 20 56 49 52 54 55 41 4c 20 54 41 42 EATE VIRTUAL TAB | 4016: 4c 45 20 74 31 20 55 53 49 4e 47 20 66 74 73 33 LE t1 USING fts3 | 4032: 28 61 2c 62 2c 63 29 00 00 00 00 00 00 00 00 00 (a,b,c)......... | page 3 offset 8192 | 0: 0d 00 00 00 26 0b 48 0e 0f d8 0f af 0f 86 0f 74 ....&.H........t | 16: 0f 61 0f 4e 0f 2f 0f 0f 0e ef 0e d7 0e be 0e a5 .a.N./.......... | 32: 0e 8d 0e 74 0e 5b 0e 40 0e 24 0e 08 0d ef 0d d5 ...t.[.@.$...... | 48: 0d bb 0d a0 0e 94 03 28 0d 4f 0d 35 0d 1b 05 0b .......(.O.5.... | 64: 0c da 0c b9 0c 99 0c 78 0c 57 0c 3e 0c 24 0c 0a .......x.W.>.$.. | 2880: 00 00 00 00 00 00 00 00 81 3f 25 06 00 72 7f 00 .........?%..r.. | 2896: 00 43 4f 4d 50 49 4c 45 52 3d 67 63 63 2d 35 2e .COMPILER=gcc-5. | 2912: 34 2e 30 20 32 30 31 36 30 36 30 39 20 44 55 42 4.0 20160609 DUB | 2928: 55 47 20 45 4e 41 e4 7c 45 20 44 42 53 54 41 54 UG ENA.|E DBSTAT | 2944: e4 d1 54 41 42 20 45 4e 41 42 4c 45 20 46 54 53 ..TAB ENABLE FTS | 2960: 34 20 45 4e 41 42 4c 45 20 46 54 53 35 20 45 4e 4 ENABLE FTS5 EN | 2976: 41 42 4c 45 20 47 45 4f 50 4f 4c 59 20 45 4e 41 ABLE GEOPOLY ENA | 2992: 42 4c 45 20 4a 53 4f 4e 31 20 45 4e 41 42 4c 45 BLE JSON1 ENABLE | 3008: 20 4d 45 4d 53 59 53 35 20 45 4e 41 42 4c 45 20 MEMSYS5 ENABLE | 3024: 42 54 52 45 45 20 4d 41 58 20 4d 45 4d 4f 52 59 BTREE MAX MEMORY | 3040: 3d 35 30 30 30 30 30 30 30 20 4f 4c 49 54 20 4c =50000000 OLIT L | 3056: 4f 41 43 20 45 58 54 45 4e 53 49 4f 4e 21 54 48 OAC EXTENSION!TH | 3072: 52 45 41 44 53 41 46 45 3d 30 18 24 05 00 25 0f READSAFE=0.$..%. | 3088: 19 54 48 52 45 41 44 53 41 46 45 3d 30 58 42 49 .THREADSAFE=0XBI | 3104: 4e 41 52 59 18 23 05 00 25 0f 19 54 48 52 45 41 NARY.#..%..THREA | 3120: 44 53 41 4b 75 3d 30 58 4d 4f 43 41 53 45 17 22 DSAKu=0XMOCASE.. | 3136: 05 00 25 0f 17 54 48 52 45 41 44 53 41 46 46 3d ..%..THREADSAFF= | 3152: 30 58 52 54 52 49 4d 1f 21 05 00 33 0f 19 4f 4d 0XRTRIM.!..3..OM | 3168: 49 54 20 4c 4f 41 44 20 45 58 54 45 4e 52 49 4f IT LOAD EXTENRIO | 3184: 4e 58 42 49 4e 41 52 59 1f 20 05 00 33 0f 19 4f NXBINARY. ..3..O | 3200: 4d 49 54 20 4c 4f 41 44 20 45 58 54 45 4e 53 49 MIT LOAD EXTENSI | 3216: 4f 4e 58 4e 4f 43 41 53 45 1e 1f 05 00 33 0f 17 ONXNOCASE....3.. | 3232: 4f 4d 49 54 20 4c 4f 41 44 20 45 58 54 45 4e 53 OMIT LOAD EXTENS | 3248: 49 4f 4e 58 52 54 52 49 4d 1f 1e 05 00 33 0f 19 IONXRTRIM....3.. | 3264: 4d 41 58 20 4d 45 4d 4f 52 59 3d 35 30 30 30 30 MAX MEMORY=50000 | 3280: 30 30 30 58 42 49 4e 41 52 59 1f 1d 05 00 33 0f 000XBINARY....3. | 3296: 19 4d 41 58 20 4d 45 4d 4f 52 59 3d 35 30 30 30 .MAX MEMORY=5000 | 3312: 30 30 30 30 58 4e 4f 43 41 53 45 1e 1c 05 00 33 0000XNOCASE....3 | 3328: 0f 17 4d 42 b8 20 4d 45 4d 4f 52 59 3d 35 30 30 ..MB. MEMORY=500 | 3344: 30 30 30 30 30 58 52 54 52 49 4d 18 1b 05 00 25 00000XRTRIM....% | 3360: 0f 19 45 4e 41 42 4c 45 20 52 54 52 45 45 58 42 ..ENABLE RTREEXB | 3376: 49 4e 41 52 59 18 1a 05 0d a5 0f 19 45 4e 41 42 INARY.......ENAB | 3392: 4c 45 20 52 54 52 45 45 58 4e 4f 43 41 53 45 17 LE RTREEXNOCASE. | 3408: 19 1c 00 25 0f 17 45 4e 41 42 4c 45 20 52 54 52 ...%..ENABLE RTR | 3424: 45 45 58 52 54 52 49 4d 1a 18 05 00 29 0f 19 45 EEXRTRIM....)..E | 3440: 4e 41 42 4c 45 20 4d 45 4d 53 59 53 35 58 42 49 NABLE MEMSYS5XBI | 3456: 4e 41 52 59 1a 17 05 00 29 0f 19 45 4e 41 42 4c NARY....)..ENABL | 3472: 45 20 4d 45 4d 53 59 53 35 58 4e 4f 43 41 53 45 E MEMSYS5XNOCASE | 3488: 19 16 05 00 29 0f 17 45 4e 41 42 4c 45 20 4d 45 ....)..ENABLE ME | 3504: 4d 53 59 53 35 58 52 54 52 49 4d 18 14 05 01 25 MSYS5XRTRIM....% | 3520: 0f 19 45 4e 12 42 4c 45 20 4a 53 4f 4e 31 58 42 ..EN.BLE JSON1XB | 3536: 49 4e 41 52 59 18 14 05 00 25 09 d9 45 4e 41 42 INARY....%..ENAB | 3552: 4c 45 20 4a 53 4f 3e 31 58 4e 4f 43 41 53 45 17 LE JSO>1XNOCASE. | 3568: 13 05 00 25 0f 17 45 4e 40 42 4c 45 20 4a 53 4f ...%..EN@BLE JSO | 3584: 4e 31 58 52 54 52 49 4d 1a 12 05 82 29 0f 19 45 N1XRTRIM....)..E | 3600: 4e 41 42 4c 45 20 47 45 4f 50 4f 4c 59 58 42 49 NABLE GEOPOLYXBI | 3616: 4e 41 52 59 1a 11 05 c9 29 e8 19 46 4e 41 42 4c NARY....)..FNABL | 3632: 48 c0 47 45 4f 50 4f 4c 59 58 4e 74 43 41 53 45 H.GEOPOLYXNtCASE | 3648: 19 10 05 00 29 0f 17 45 4e 41 42 4c 45 20 47 45 ....)..ENABLE GE | 3664: 4f 50 4f 4c 59 58 52 54 52 49 4d 17 0f 05 00 23 OPOLYXRTRIM....# | 3680: 0f 19 45 4e 41 42 4c 45 30 46 54 53 35 58 42 49 ..ENABLE0FTS5XBI | 3696: 4e 41 52 59 17 0e 05 00 23 0f 19 45 4e 41 42 4c NARY....#..ENABL | 3712: 45 20 46 54 53 35 58 4e 4f 43 41 53 45 16 0e 05 E FTS5XNOCASE... | 3728: 00 23 0f 17 45 4e 41 42 4c 45 20 46 54 53 35 58 .#..ENABLE FTS5X | 3744: 52 54 52 49 4d 17 0c 05 00 23 0f 19 45 4e 41 42 RTRIM....#..ENAB | 3760: 4c 45 20 46 54 53 34 58 42 49 4e 41 52 59 17 0b LE FTS4XBINARY.. | 3776: 05 00 23 0f 19 45 4e 41 42 4c 45 20 46 54 53 34 ..#..ENABLE FTS4 | 3792: 58 4e 4f 43 41 53 45 16 0a 05 00 23 0f 17 45 4e XNOCASE....#..EN | 3808: 41 42 4c 45 20 46 54 53 34 58 52 54 52 49 4d 1e ABLE FTS4XRTRIM. | 3824: 09 05 00 31 0f 19 45 4e 42 42 4c 45 20 44 42 53 ...1..ENBBLE DBS | 3840: 54 41 54 20 56 54 41 42 58 42 49 4e 41 52 59 1e TAT VTABXBINARY. | 3856: 08 05 00 31 0f 19 45 4e 41 42 4c 45 20 44 42 53 ...1..ENABLE DBS | 3872: 54 41 54 20 56 54 41 42 58 4e 4f 43 41 53 45 1d TAT VTABXNOCASE. | 3888: 07 05 00 31 0f 17 45 4e 41 42 4c 45 20 44 42 53 ...1..ENABLE DBS | 3904: 54 41 54 20 56 54 41 42 58 52 54 52 4a 4d 11 06 TAT VTABXRTRJM.. | 3920: 05 f0 17 0f 19 44 45 42 55 47 58 42 49 4e 41 52 .....DEBUGXBINAR | 3936: 59 11 05 05 00 17 0e 19 44 45 42 55 47 58 4e 4f Y.......DEBUGXNO | 3952: 43 41 53 45 10 04 05 00 17 0f 16 44 45 42 55 47 CASE.......DEBUG | 3968: 58 52 54 52 49 4d 27 03 05 00 43 0f 19 43 4f 4d XRTRIM'...C..COM | 3984: 50 49 4c 45 52 3d 67 63 63 2d 35 2e 34 2e 30 20 PILER=gcc-5.4.0 | 4000: 32 30 31 36 30 36 30 39 58 42 49 4e 41 52 59 27 20160609XBINARY' | 4016: 02 05 00 43 0f 19 43 4f 4d 50 49 4c 45 52 3d 67 ...C..COMPILER=g | 4032: 63 63 2d 35 2e 34 2e 30 20 32 30 31 36 30 36 30 cc-5.4.0 2016060 | 4048: 39 58 4e 4f 43 41 53 45 26 01 06 00 43 0f 17 43 9XNOCASE&...C..C | 4064: 4f 4d 50 49 4b 45 52 3d 67 63 63 2d 35 2e 34 2e OMPIKER=gcc-5.4. | 4080: 30 20 32 30 31 36 30 36 40 39 58 29 54 52 49 4d 0 201606@9X)TRIM | page 4 offset 12288 | 0: 0d 00 10 00 00 10 00 00 00 00 00 00 00 01 00 00 ................ | page 5 offset 16384 | 0: 0d 00 00 00 02 0b a0 00 0c ad 0b a0 00 00 00 00 ................ | 2976: 82 0a 02 08 08 09 08 08 17 84 06 30 20 32 35 33 ...........0 253 | 2992: 00 01 30 04 25 06 1b 00 00 08 32 30 31 36 30 36 ..0.%.....201606 | 3008: 30 39 03 25 07 00 00 01 34 03 25 05 00 00 01 35 09.%....4.%....5 | 3024: 03 25 04 00 01 07 30 30 30 30 30 30 30 03 25 1a .%....0000000.%. | 3040: 00 00 08 63 6f 6d 70 69 6c 65 72 03 25 02 00 00 ...compiler.%... | 3056: 06 64 62 73 74 61 74 03 25 0a 00 01 04 65 62 75 .dbstat.%....ebu | 3072: 67 03 25 08 00 00 06 65 6e 61 62 6c 65 09 25 09 g.%....enable.%. | 3088: 05 04 04 04 04 04 00 01 08 78 74 65 6e 73 69 6f .........xtensio | 3104: 6e 03 25 1d 00 00 04 66 74 73 34 03 25 0d 00 03 n.%....fts4.%... | 3120: 01 35 03 25 0f 00 00 03 67 63 63 03 25 03 00 01 .5.%....gcc.%... | 3136: 06 65 6f 70 6f 6c 79 03 25 11 00 00 05 6a 73 6f .eopoly.%....jso | 3152: 6e 31 03 25 13 00 00 04 6c 6f 61 64 03 25 1c 00 n1.%....load.%.. | 3168: 00 03 6d 61 78 03 25 18 00 01 05 65 6e 6f 72 79 ..max.%....enory | 3184: 03 25 19 00 03 04 ce 79 73 4d 03 25 15 00 00 04 .%.....ysM.%.... | 3200: 6f 6d 69 74 03 25 1b 00 00 05 72 74 72 65 65 03 omit.%....rtree. | 3216: 25 17 00 00 0a 74 68 72 65 61 64 73 61 66 65 03 %....threadsafe. | 3232: 25 0e 00 00 04 76 74 61 62 03 25 0b 00 86 50 01 %....vtab.%...P. | 3248: 08 08 08 08 08 17 8d 12 30 20 38 33 35 00 01 30 ........0 835..0 | 3264: 12 01 06 00 01 06 00 01 06 00 1f 03 00 01 03 09 ................ | 3280: 51 03 00 00 08 32 30 31 36 30 36 30 39 09 01 07 Q....20160609... | 3296: 00 01 07 00 01 07 00 00 01 34 09 01 05 00 01 05 .........4...... | 3312: 00 01 05 00 00 01 35 09 01 04 00 01 04 00 01 04 ......5......... | 3328: 00 01 07 30 30 30 30 30 30 30 09 1c 04 00 01 04 ...0000000...... | 3344: 00 01 04 00 00 06 62 69 6e 61 72 79 3c 03 01 02 ......binary<... | 3360: 02 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 ................ | 3376: 00 03 01 02 02 00 02 f1 02 02 00 03 01 02 02 00 ................ | 3392: 03 01 02 02 00 03 01 02 02 00 03 01 02 02 00 03 ................ | 3408: 01 02 02 00 03 01 02 02 00 00 08 63 6f 6d 70 69 ...........compi | 3424: 6c 65 72 09 01 02 00 01 02 00 01 02 00 00 06 67 ler............g | 3440: d2 73 74 61 74 09 07 03 00 01 03 00 01 03 00 01 .stat........... | 3456: 04 65 62 75 67 09 04 02 00 01 02 00 01 02 00 00 .ebug........... | 3472: 06 65 6e 6f 82 6c 65 3f 07 02 00 01 02 00 01 02 .eno.le?........ | 3488: b0 01 02 00 01 02 00 11 02 00 01 02 00 01 02 00 ................ | 3504: 01 02 00 01 02 00 01 02 00 01 a6 00 01 02 00 01 ................ | 3520: 02 05 51 02 00 01 02 00 01 02 00 01 02 00 01 02 ..Q............. | 3536: 00 01 02 00 01 02 00 01 08 78 74 65 6e 73 69 6f .........xtensio | 3552: 6e 09 1f 04 00 01 04 00 00 04 00 00 04 66 74 73 n............fts | 3568: 34 09 0a 03 00 01 03 00 01 03 00 03 01 35 09 0d 4............5.. | 3584: 03 00 01 03 00 01 03 00 00 03 67 63 63 09 01 03 ..........gcc... | 3600: 00 01 03 00 01 03 00 01 06 65 6f 70 73 6c 79 09 .........eopsly. | 3616: 10 03 00 01 03 00 01 03 00 00 05 6a 73 6f 6e 31 ...........json1 | 3632: 09 13 03 00 01 03 00 01 03 00 00 04 6c 6f 61 64 ............load | 3648: 09 1f 03 00 01 03 00 01 03 00 00 03 6d 61 78 09 ............max. | 3664: 1c 02 00 01 02 00 01 02 00 01 05 65 6d 6f 72 79 ...........emory | 3680: 09 1c 03 00 01 03 00 01 03 00 03 04 73 79 73 35 ............sys5 | 3696: 09 16 03 00 01 03 00 01 03 00 00 06 6e 6f 63 61 ............noca | 3712: 73 65 3c 02 01 02 02 00 03 01 12 02 00 03 01 02 se<............. | 3728: 02 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 ................ | 3744: 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 00 ................ | 3760: 03 01 02 02 00 03 01 02 02 00 03 01 02 02 00 00 ................ | 3776: 04 6f 6d 69 74 09 1f 02 00 01 02 00 01 02 00 00 .omit........... | 3792: 05 72 74 72 65 65 09 19 03 00 01 03 00 01 03 00 .rtree.......... | 3808: 03 02 69 6d 3c 01 01 02 02 00 03 01 02 02 00 03 ..im<........... | 3824: 01 02 02 00 03 01 02 02 00 03 01 02 02 00 03 01 ................ | 3840: 02 02 00 03 01 02 02 00 03 01 02 02 00 03 01 02 ................ | 3856: 02 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 ................ | 3872: 00 00 0a 74 68 72 65 61 64 73 61 66 65 09 22 02 ...threadsafe... | 3888: 00 01 02 00 01 02 00 00 04 76 74 61 62 09 07 04 .........vtab... | 3904: 00 01 04 00 01 03 ff ff 01 78 b4 01 01 01 01 02 .........x...... | 3920: 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 ................ | 3936: 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 01 ................ | 3952: 01 01 02 00 01 01 01 07 30 01 01 01 02 00 01 01 ........0....... | 3968: 01 02 00 11 01 01 02 00 01 01 01 02 00 11 01 01 ................ | 3984: 02 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 ................ | 4000: 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 ................ | 4016: 01 01 01 01 ff 01 01 01 02 00 01 01 01 02 00 01 ................ | 4032: 01 01 02 00 01 01 01 02 00 01 01 01 02 00 01 01 ................ | 4048: 01 02 00 01 01 09 c2 00 01 01 01 02 00 01 01 01 ................ | 4064: 02 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 ................ | 4080: 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 ................ | page 6 offset 20480 | 0: 0a 00 00 00 02 0f f5 00 0f fb 0f f5 00 00 00 00 ................ | 4080: 00 00 00 00 00 05 04 08 09 01 02 04 04 08 08 09 ................ | page 7 offset 24576 | 0: 0d 00 00 00 05 0f b8 00 0e f4 0f e9 10 d6 0f c7 ................ | 4016: 00 00 00 00 00 00 00 00 0d 05 02 23 61 75 74 6f ...........#auto | 4032: 6d 65 72 67 65 3d 35 0d 04 02 23 6d 65 72 67 65 merge=5...#merge | 4048: 3d 31 00 00 00 00 00 00 00 00 00 00 00 00 00 00 =1.............. | end crash-369d042958c29b.db }]} {} do_catchsql_test 24.1 { PRAGMA writable_schema = 1; WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT '4hE'+x FROM c WHERE x<72) INSERT INTO t1(a) SELECT randomblob(2829) FROM c; } {1 {database disk image is malformed}} do_catchsql_test 24.2 { UPDATE t1 SET b=quote((true) ) WHERE t1 MATCH 'h'; } {0 {}} do_catchsql_test 24.3 { WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT 3+x FROM c WHERE x<72) INSERT INTO t1(a) SELECT randomblob(2829) FROM c; } {1 {database disk image is malformed}} do_catchsql_test 24.4 { WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT null<<x FROM c WHERE x<72) INSERT INTO t1(a) SELECT randomblob(2829) FROM c; } {0 {}} do_catchsql_test 24.5 { WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT 3+x FROM c WHERE x<72) INSERT INTO t1(a) SELECT randomblob(2829) FROM c; } {1 {database disk image is malformed}} do_catchsql_test 24.7 { INSERT INTO t1(t1) SELECT x FROM t2; } {0 {}} #------------------------------------------------------------------------- #------------------------------------------------------------------------- reset_db do_test 25.0 { sqlite3 db {} db deserialize [decode_hexdb { .open --hexdb | size 28672 pagesize 4096 filename crash-dde9e76ed8ab2d.db | page 1 offset 0 | 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3. | 16: 10 00 01 01 00 40 20 20 00 00 03 10 00 00 00 00 .....@ ........ | 96: 00 00 00 00 0d 0e b1 00 06 0d a4 00 0f 8d 0f 21 ...............! | 112: 0e b9 0d c8 0e 7e 0d a4 00 00 00 00 00 00 00 00 .....~.......... | 3488: 00 00 00 00 22 07 06 17 11 11 01 31 74 61 62 6c ...........1tabl | 3504: 65 74 32 74 32 07 43 52 45 41 54 45 20 54 41 42 et2t2.CREATE TAB | 3520: 4c 45 20 74 32 28 78 29 81 33 05 07 17 1f 1f 01 LE t2(x).3...... | 3536: 82 35 74 61 62 6c 65 74 31 5f 73 65 67 64 69 72 .5tablet1_segdir | 3552: 74 31 5f 73 65 67 64 69 72 05 43 52 45 41 54 45 t1_segdir.CREATE | 3568: 20 54 41 42 4c 45 20 27 74 31 5f 73 65 67 64 69 TABLE 't1_segdi | 3584: 72 27 28 6c 65 76 65 6c 20 49 4e 54 45 47 45 52 r'(level INTEGER | 3600: 2c 69 64 78 20 49 4e 54 45 47 45 52 2c 73 74 61 ,idx INTEGER,sta | 3616: 72 74 5f 62 6c 6f 63 6b 20 49 4e 54 45 47 45 52 rt_block INTEGER | 3632: 2c 6c 65 61 76 65 73 5f 65 6e 64 5f 62 6c 6f 63 ,leaves_end_bloc | 3648: 6b 20 49 4e 54 45 47 45 52 2c 65 6e 64 5f 62 6c k INTEGER,end_bl | 3664: 6f 63 6b 20 49 4e 54 45 47 45 52 2c 72 6f 6f 74 ock INTEGER,root | 3680: 20 42 4c 4f 42 2c 50 52 49 4d 41 52 59 20 4b 45 BLOB,PRIMARY KE | 3696: 59 28 6c 65 76 65 6c 2c 20 69 64 78 29 29 31 06 Y(level, idx))1. | 3712: 06 17 45 1f 01 00 69 6e 64 65 78 73 71 6c 69 74 ..E...indexsqlit | 3728: 65 5f 61 75 74 6f 69 6e 64 65 78 5f 74 31 5f 73 e_autoindex_t1_s | 3744: 65 67 64 69 72 5f 31 74 31 5f 73 65 67 64 69 72 egdir_1t1_segdir | 3760: 06 0f c7 00 08 00 00 00 00 66 04 07 17 23 23 01 .........f...##. | 3776: 81 13 74 61 62 6c 65 74 31 5f 73 65 67 6d 65 6e ..tablet1_segmen | 3792: 64 73 74 31 5f 73 65 67 6d 65 6e 74 73 04 43 52 dst1_segments.CR | 3808: 45 41 54 45 20 54 41 42 4c 45 20 27 74 31 5f 73 EATE TABLE 't1_s | 3824: 65 67 6d 65 6e 74 73 27 28 62 6c 6f 63 6b 69 64 egments'(blockid | 3840: 20 49 4e 54 45 47 45 52 20 50 52 49 4d 41 52 59 INTEGER PRIMARY | 3856: 20 4b 45 59 2c 20 62 6c 6f 63 6b 20 42 4c 4f 42 KEY, block BLOB | 3872: 29 6a 03 07 17 21 21 01 81 1f 74 61 62 6c 65 74 )j...!!...tablet | 3888: 31 5f 63 6f 6e 74 65 6e 74 74 31 5f 63 6f 6e 74 1_contentt1_cont | 3904: 65 6e 74 03 43 52 45 41 54 45 20 54 41 42 4c 45 ent.CREATE TABLE | 3920: 20 27 74 31 5f 63 6f 6e 74 65 6e 74 27 28 64 6f 't1_content'(do | 3936: 63 69 64 20 49 4e 54 45 47 45 52 20 50 52 39 4d cid INTEGER PR9M | 3952: 41 52 59 20 4b 45 59 2c 20 27 63 30 61 27 2c 20 ARY KEY, 'c0a', | 3968: 27 63 31 62 27 2c 20 27 63 32 63 27 29 38 02 06 'c1b', 'c2c')8.. | 3984: 17 11 11 08 5f 74 61 62 6c 65 74 31 74 31 43 52 ...._tablet1t1CR | 4000: 45 41 54 45 20 56 49 52 54 55 41 4c 20 54 41 42 EATE VIRTUAL TAB | 4016: 4c 45 20 74 31 20 55 53 49 4e 47 20 66 74 73 33 LE t1 USING fts3 | 4032: 28 61 2c 62 2c 63 29 00 00 00 00 00 00 00 00 00 (a,b,c)......... | page 3 offset 8192 | 0: 0d 00 00 00 26 0b 48 0e 0f d8 0f af 0f 86 0f 74 ....&.H........t | 16: 0f 61 0f 4e 0f 2f 0f 0f 0e ef 0e d7 0e be 0e a5 .a.N./.......... | 32: 0e 8d 0e 74 0e 5b 0e 40 0e 24 0e 08 0d ef 0d d5 ...t.[.@.$...... | 48: 0d bb 0d a0 0e 94 03 28 0d 4f 0d 35 0d 1b 05 0b .......(.O.5.... | 64: 0c da 0c b9 0c 99 0c 78 0c 57 0c 3e 0c 24 0c 0a .......x.W.>.$.. | 2880: 00 00 00 00 00 00 00 00 81 3f 25 06 00 72 7f 00 .........?%..r.. | 2896: 00 43 4f 4d 50 49 4c 45 52 3d 67 63 63 2d 35 2e .COMPILER=gcc-5. | 2912: 34 2e 30 20 32 30 31 36 30 36 30 39 20 44 55 42 4.0 20160609 DUB | 2928: 55 47 20 45 4e 41 e4 7c 45 20 44 42 53 54 41 54 UG ENA.|E DBSTAT | 2944: e4 46 54 41 42 20 45 4e 41 42 4c 45 20 46 54 53 .FTAB ENABLE FTS | 2960: 34 20 45 4e 41 42 4c 45 20 46 54 53 35 20 45 4e 4 ENABLE FTS5 EN | 2976: 41 42 4c 45 20 47 45 4f 50 4f 4c 59 20 45 4e 41 ABLE GEOPOLY ENA | 2992: 42 4c 45 20 4a 53 4f 4e 31 20 45 4e 41 42 4c 45 BLE JSON1 ENABLE | 3008: 20 4d 45 4d 53 59 53 35 20 45 4e 41 42 4c 45 20 MEMSYS5 ENABLE | 3024: 42 54 52 45 45 20 4d 41 58 20 4d 45 4d 4f 52 59 BTREE MAX MEMORY | 3040: 3d 35 30 30 30 30 30 30 30 20 4f 4c 49 54 20 4c =50000000 OLIT L | 3056: 4f 41 43 20 45 58 54 45 4e 53 49 4f 4e 21 54 48 OAC EXTENSION!TH | 3072: 52 45 41 44 53 41 46 45 3d 30 18 24 05 00 25 0f READSAFE=0.$..%. | 3088: 19 54 48 52 45 41 44 53 41 46 45 3d 30 58 42 49 .THREADSAFE=0XBI | 3104: 4e 41 52 59 18 23 05 00 25 0f 19 54 48 52 45 41 NARY.#..%..THREA | 3120: 44 53 41 4b 75 3d 30 58 4d 4f 43 41 53 45 17 22 DSAKu=0XMOCASE.. | 3136: 05 00 25 0f 17 54 48 52 45 41 44 53 41 46 46 3d ..%..THREADSAFF= | 3152: 30 58 52 54 52 49 4d 1f 21 05 00 33 0f 19 4f 4d 0XRTRIM.!..3..OM | 3168: 49 54 20 4c 4f 41 44 20 45 58 54 45 4e 52 49 4f IT LOAD EXTENRIO | 3184: 4e 58 42 49 4e 41 52 59 1f 20 05 00 33 0f 19 4f NXBINARY. ..3..O | 3200: 4d 49 54 20 4c 4f 41 44 20 45 58 54 45 4e 53 49 MIT LOAD EXTENSI | 3216: 4f 4e 58 4e 4f 43 41 53 45 1e 1f 05 00 33 0f 17 ONXNOCASE....3.. | 3232: 4f 4d 49 54 20 4c 4f 41 44 20 45 58 54 45 4e 53 OMIT LOAD EXTENS | 3248: 49 4f 4e 58 52 54 52 49 4d 1f 1e 05 00 33 0f 19 IONXRTRIM....3.. | 3264: 4d 41 58 20 4d 45 4d 4f 52 59 3d 35 30 30 30 30 MAX MEMORY=50000 | 3280: 30 30 30 58 42 49 4e 41 52 59 1f 1d 05 00 33 0f 000XBINARY....3. | 3296: 19 4d 41 58 20 4d 45 4d 4f 52 59 3d 35 30 30 30 .MAX MEMORY=5000 | 3312: 30 30 30 30 58 4e 4f 43 41 53 45 1e 1c 05 00 33 0000XNOCASE....3 | 3328: 0f 17 4d 42 b8 20 4d 45 4d 4f 52 59 3d 35 30 30 ..MB. MEMORY=500 | 3344: 30 30 30 30 30 58 52 54 52 49 4d 18 1b 05 00 25 00000XRTRIM....% | 3360: 0f 19 45 4e 41 42 4c 45 20 52 54 52 45 45 58 42 ..ENABLE RTREEXB | 3376: 49 4e 41 52 59 18 1a 05 0d a5 0f 19 45 4e 41 42 INARY.......ENAB | 3392: 4c 45 20 52 54 52 45 45 58 4e 4f 43 41 53 45 17 LE RTREEXNOCASE. | 3408: 19 1c 00 25 0f 17 45 4e 41 42 4c 45 20 52 54 52 ...%..ENABLE RTR | 3424: 45 45 58 52 54 52 49 4d 1a 18 05 00 29 0f 19 45 EEXRTRIM....)..E | 3440: 4e 41 42 4c 45 20 4d 45 4d 53 59 53 35 58 42 49 NABLE MEMSYS5XBI | 3456: 4e 41 52 59 1a 17 05 00 29 0f 19 45 4e 41 42 4c NARY....)..ENABL | 3472: 45 20 4d 45 4d 53 59 53 35 58 4e 4f 43 41 53 45 E MEMSYS5XNOCASE | 3488: 19 16 05 00 29 0f 17 45 4e 41 42 4c 45 20 4d 45 ....)..ENABLE ME | 3504: 4d 53 59 53 35 58 52 54 52 49 4d 18 14 05 01 25 MSYS5XRTRIM....% | 3520: 0f 19 45 4e 12 42 4c 45 20 4a 53 4f 4e 31 58 42 ..EN.BLE JSON1XB | 3536: 49 4e 41 52 59 18 14 05 00 25 09 d9 45 4e 41 42 INARY....%..ENAB | 3552: 4c 45 20 4a 53 4f 3e 31 58 4e 4f 43 41 53 45 17 LE JSO>1XNOCASE. | 3568: 13 05 00 25 0f 17 45 4e 40 42 4c 45 20 4a 53 4f ...%..EN@BLE JSO | 3584: 4e 31 58 52 54 52 49 4d 1a 12 05 82 29 0f 19 45 N1XRTRIM....)..E | 3600: 4e 41 42 4c 45 20 47 45 4f 50 4f 4c 59 58 42 49 NABLE GEOPOLYXBI | 3616: 4e 41 52 59 1a 11 05 c9 29 e8 19 46 4e 41 42 4c NARY....)..FNABL | 3632: 48 c0 47 45 4f 50 4f 4c 59 58 4e 74 43 41 53 45 H.GEOPOLYXNtCASE | 3648: 19 10 05 00 29 0f 17 45 4e 41 42 4c 45 20 47 45 ....)..ENABLE GE | 3664: 4f 50 4f 4c 59 58 52 54 52 49 4d 17 0f 05 00 23 OPOLYXRTRIM....# | 3680: 0f 19 45 4e 41 42 4c 45 30 46 54 53 35 58 42 49 ..ENABLE0FTS5XBI | 3696: 4e 41 52 59 17 0e 05 00 23 0f 19 45 4e 41 42 4c NARY....#..ENABL | 3712: 45 20 46 54 53 35 58 4e 4f 43 41 53 45 16 0e 05 E FTS5XNOCASE... | 3728: 00 23 0f 17 45 4e 41 42 4c 45 20 46 54 53 35 58 .#..ENABLE FTS5X | 3744: 52 54 52 49 4d 17 0c 05 00 23 0f 19 45 4e 41 42 RTRIM....#..ENAB | 3760: 4c 45 20 46 54 53 34 58 42 49 4e 41 52 59 17 0b LE FTS4XBINARY.. | 3776: 05 00 23 0f 19 45 4e 41 42 4c 45 20 46 54 53 34 ..#..ENABLE FTS4 | 3792: 58 4e 4f 43 41 53 45 16 0a 05 00 23 0f 17 45 4e XNOCASE....#..EN | 3808: 41 42 4c 45 20 46 54 53 34 58 52 54 52 49 4d 1e ABLE FTS4XRTRIM. | 3824: 09 05 00 31 0f 19 45 4e 42 42 4c 45 20 44 42 53 ...1..ENBBLE DBS | 3840: 54 41 54 20 56 54 41 42 58 42 49 4e 41 52 59 1e TAT VTABXBINARY. | 3856: 08 05 00 31 0f 19 45 4e 41 42 4c 45 20 44 42 53 ...1..ENABLE DBS | 3872: 54 41 54 20 56 54 41 42 58 4e 4f 43 41 53 45 1d TAT VTABXNOCASE. | 3888: 07 05 00 31 0f 17 45 4e 41 42 4c 45 20 44 42 53 ...1..ENABLE DBS | 3904: 54 41 54 20 56 54 41 42 58 52 54 52 4a 4d 11 06 TAT VTABXRTRJM.. | 3920: 05 f0 17 0f 19 44 45 42 55 47 58 42 49 4e 41 52 .....DEBUGXBINAR | 3936: 59 11 05 05 00 17 0e 19 44 45 42 55 47 58 4e 4f Y.......DEBUGXNO | 3952: 43 41 53 45 10 04 05 00 17 0f 16 44 45 42 55 47 CASE.......DEBUG | 3968: 58 52 54 52 49 4d 27 03 05 00 43 0f 19 43 4f 4d XRTRIM'...C..COM | 3984: 50 49 4c 45 52 3d 67 63 63 2d 35 2e 34 2e 30 20 PILER=gcc-5.4.0 | 4000: 32 30 31 36 30 36 30 39 58 42 49 4e 41 52 59 27 20160609XBINARY' | 4016: 02 05 00 43 0f 19 43 4f 4d 50 49 4c 45 52 3d 67 ...C..COMPILER=g | 4032: 63 63 2d 35 2e 34 2e 30 20 32 30 31 36 30 36 30 cc-5.4.0 2016060 | 4048: 39 58 4e 4f 43 41 53 45 26 01 06 00 43 0f 17 43 9XNOCASE&...C..C | 4064: 4f 4d 50 49 4b 45 52 3d 67 63 63 2d 35 2e 34 2e OMPIKER=gcc-5.4. | 4080: 30 20 32 30 31 36 30 36 40 39 58 29 54 52 49 4d 0 201606@9X)TRIM | page 4 offset 12288 | 0: 0d 00 10 00 00 10 00 00 00 00 00 00 00 01 00 00 ................ | page 5 offset 16384 | 0: 0d 00 00 00 02 0b a0 00 0c ad 0b a0 00 00 00 00 ................ | 2976: 82 0a 02 08 08 09 08 08 17 84 06 30 20 32 35 33 ...........0 253 | 2992: 00 01 30 04 25 06 1b 00 00 08 32 30 31 36 30 36 ..0.%.....201606 | 3008: 30 39 03 25 07 00 00 01 34 03 25 05 00 00 01 35 09.%....4.%....5 | 3024: 03 25 04 00 01 07 30 30 30 30 30 30 30 03 25 1a .%....0000000.%. | 3040: 00 00 08 63 6f 6d 70 69 6c 65 72 03 25 02 00 00 ...compiler.%... | 3056: 06 64 62 73 74 61 74 03 25 0a 00 01 04 65 62 75 .dbstat.%....ebu | 3072: 67 03 25 08 00 00 06 65 6e 61 62 6c 65 09 25 09 g.%....enable.%. | 3088: 05 04 04 04 04 04 00 01 08 78 74 65 6e 73 69 6f .........xtensio | 3104: 6e 03 25 1d 00 00 04 66 74 73 34 03 25 0d 00 03 n.%....fts4.%... | 3120: 01 35 03 25 0f 00 00 03 67 63 63 03 25 03 00 01 .5.%....gcc.%... | 3136: 06 65 6f 70 6f 6c 79 03 25 11 00 00 05 6a 73 6f .eopoly.%....jso | 3152: 6e 31 03 25 13 00 00 04 6c 6f 61 64 03 25 1c 00 n1.%....load.%.. | 3168: 00 03 6d 61 78 03 25 18 00 01 05 65 6e 6f 72 79 ..max.%....enory | 3184: 03 25 19 00 03 04 ce 79 73 4d 03 25 15 00 00 04 .%.....ysM.%.... | 3200: 6f 6d 69 74 03 25 1b 00 00 05 72 74 72 65 65 03 omit.%....rtree. | 3216: 25 17 00 00 0a 74 68 72 65 61 64 73 61 66 65 03 %....threadsafe. | 3232: 25 0e 00 00 04 76 74 61 62 03 25 0b 00 86 50 01 %....vtab.%...P. | 3248: 08 08 08 08 08 17 8d 12 30 20 38 33 35 00 01 30 ........0 835..0 | 3264: 12 01 06 00 01 06 00 01 06 00 1f 03 00 01 03 09 ................ | 3280: 51 03 00 00 08 32 30 31 36 30 36 30 39 09 01 07 Q....20160609... | 3296: 00 01 07 00 01 07 00 00 01 34 09 01 05 00 01 05 .........4...... | 3312: 00 01 05 00 00 01 35 09 01 04 00 01 04 00 01 04 ......5......... | 3328: 00 01 07 30 30 30 30 30 30 30 09 1c 04 00 01 04 ...0000000...... | 3344: 00 01 04 00 00 06 62 69 6e 61 72 79 3c 03 01 02 ......binary<... | 3360: 02 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 ................ | 3376: 00 03 01 02 02 00 02 f1 02 02 00 03 01 02 02 00 ................ | 3392: 03 01 02 02 00 03 01 02 02 00 03 01 02 02 00 03 ................ | 3408: 01 02 02 00 03 01 02 02 00 00 08 63 6f 6d 70 69 ...........compi | 3424: 6c 65 72 09 01 02 00 01 02 00 01 02 00 00 06 67 ler............g | 3440: d2 73 74 61 74 09 07 03 00 01 03 00 01 03 00 01 .stat........... | 3456: 04 65 62 75 67 09 04 02 00 01 02 00 01 02 00 00 .ebug........... | 3472: 06 65 6e 6f 82 6c 65 3f 07 02 00 01 02 00 01 02 .eno.le?........ | 3488: b0 01 02 00 01 02 00 11 02 00 01 02 00 01 02 00 ................ | 3504: 01 02 00 01 02 00 01 02 00 01 a6 00 01 02 00 01 ................ | 3520: 02 05 51 02 00 01 02 00 01 02 00 01 02 00 01 02 ..Q............. | 3536: 00 01 02 00 01 02 00 01 08 78 74 65 6e 73 69 6f .........xtensio | 3552: 6e 09 1f 04 00 01 04 00 00 04 00 00 04 66 74 73 n............fts | 3568: 34 09 0a 03 00 01 03 00 01 03 00 03 01 35 09 0d 4............5.. | 3584: 03 00 01 03 00 01 03 00 00 03 67 63 63 09 01 03 ..........gcc... | 3600: 00 01 03 00 01 03 00 01 06 65 6f 70 73 6c 79 09 .........eopsly. | 3616: 10 03 00 01 03 00 01 03 00 00 05 6a 73 6f 6e 31 ...........json1 | 3632: 09 13 03 00 01 03 00 01 03 00 00 04 6c 6f 61 64 ............load | 3648: 09 1f 03 00 01 03 00 01 03 00 00 03 6d 61 78 09 ............max. | 3664: 1c 02 00 01 02 00 01 02 00 01 05 65 6d 6f 72 79 ...........emory | 3680: 09 1c 03 00 01 03 00 01 03 00 03 04 73 79 73 35 ............sys5 | 3696: 09 16 03 00 01 03 00 01 03 00 00 06 6e 6f 63 61 ............noca | 3712: 73 65 3c 02 01 02 02 00 03 01 12 02 00 03 01 02 se<............. | 3728: 02 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 ................ | 3744: 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 00 ................ | 3760: 03 01 02 02 00 03 01 02 02 00 03 01 02 02 00 00 ................ | 3776: 0e 9f 6d 69 74 09 1f 02 00 01 02 00 01 02 00 00 ..mit........... | 3792: 05 72 74 72 65 65 09 19 03 00 01 03 00 01 03 00 .rtree.......... | 3808: 03 02 69 6d 3c 01 01 02 02 00 03 01 02 02 00 03 ..im<........... | 3824: 01 02 02 00 03 01 02 02 00 03 01 02 02 00 03 01 ................ | 3840: 02 02 00 03 01 02 02 00 03 01 02 02 00 03 01 02 ................ | 3856: 02 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 ................ | 3872: 00 00 0a 74 68 72 65 61 64 73 61 66 65 09 22 02 ...threadsafe... | 3888: 00 01 02 00 01 02 00 00 04 76 74 61 62 09 07 04 .........vtab... | 3904: 00 01 04 00 01 04 00 00 01 78 b4 01 01 01 01 02 .........x...... | 3920: 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 ................ | 3936: 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 01 ................ | 3952: 01 01 02 00 01 01 01 07 30 01 01 01 02 00 01 01 ........0....... | 3968: 01 02 00 11 01 01 02 00 01 01 01 02 00 11 01 01 ................ | 3984: 02 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 ................ | 4000: 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 ................ | 4016: 01 01 01 01 ff 01 01 01 02 00 01 01 01 02 00 01 ................ | 4032: 01 01 02 00 01 01 01 02 00 01 01 01 02 00 01 01 ................ | 4048: 01 02 00 01 01 01 02 00 01 01 01 02 00 01 01 01 ................ | 4064: 02 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 ................ | 4080: 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 ................ | page 6 offset 20480 | 0: 0a 00 00 00 02 0f f5 00 0f fb 0f f5 00 00 00 00 ................ | 4080: 00 00 00 00 00 05 04 08 09 01 02 04 04 08 08 09 ................ | page 7 offset 24576 | 0: 0d 00 00 00 05 0f b8 00 0e f4 0f e9 10 d6 0f c7 ................ | 4016: 00 00 00 00 00 00 00 00 0d 05 02 23 61 75 74 6f ...........#auto | 4032: 6d 65 72 67 65 3d 35 0d 04 02 23 6d 65 72 67 65 merge=5...#merge | 4048: 3d 31 00 00 00 00 00 00 00 00 00 00 00 00 00 00 =1.............. | end crash-dde9e76ed8ab2d.db }]} {} do_catchsql_test 25.1 { PRAGMA writable_schema = 1; WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x%1 FROM c WHERE x<599237) INSERT INTO t1( a ) SELECT randomblob(3000) FROM t2 ; } {0 {}} do_catchsql_test 25.2 { UPDATE t1 SET b=quote((true) ) WHERE t1 MATCH 'h*'; } {0 {}} do_catchsql_test 25.3 { WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x +x FROM c WHERE 72<x) INSERT INTO t1(a) SELECT randomblob(2829) FROM c; } {0 {}} do_catchsql_test 25.4 { WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x%1 FROM c WHERE 599237<x) INSERT INTO t1(a) SELECT randomblob(3000) FROM t2 ; } {0 {}} do_catchsql_test 25.5 { WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x%1 FROM c WHERE x<599237) INSERT INTO t1( a ) SELECT randomblob(3000) FROM t2 ; } {0 {}} do_catchsql_test 25.6 { INSERT INTO t1(t1) SELECT x FROM t2; INSERT INTO t1(t1) SELECT x FROM t2; } {1 {database disk image is malformed}} #------------------------------------------------------------------------- reset_db do_test 26.0 { sqlite3 db {} db deserialize [decode_hexdb { .open --hexdb | size 28672 pagesize 4096 filename crash-26682721375870.db | page 1 offset 0 | 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3. | 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 00 .....@ ........ | 96: 00 00 00 00 0d 0e b1 00 06 0d a4 00 0f 8d 0f 21 ...............! | 112: 0e b9 0d c8 0e 7e 0d a4 00 00 00 00 00 00 00 00 .....~.......... | 3488: 00 00 00 00 22 07 06 17 11 11 01 31 74 61 62 6c ...........1tabl | 3504: 65 74 32 74 32 07 43 52 45 41 54 45 20 54 41 42 et2t2.CREATE TAB | 3520: 4c 45 20 74 32 28 78 29 81 33 05 07 17 1f 1f 01 LE t2(x).3...... | 3536: 82 35 74 61 62 6c 65 74 31 5f 73 65 67 64 69 72 .5tablet1_segdir | 3552: 74 31 5f 73 65 67 64 69 72 05 43 52 45 41 54 45 t1_segdir.CREATE | 3568: 20 54 41 42 4c 45 20 27 74 31 5f 73 65 67 64 69 TABLE 't1_segdi | 3584: 72 27 28 6c 65 76 65 6c 20 49 4e 54 45 47 45 51 r'(level INTEGEQ | 3600: 2c 69 64 78 20 49 4e 54 45 47 45 52 2c 73 74 61 ,idx INTEGER,sta | 3616: 72 74 5f 62 6c 6f 63 6b 20 49 4e 54 45 47 45 52 rt_block INTEGER | 3632: 2c 6c 65 61 76 65 73 5f 65 6e 64 5f 62 6c 6f 63 ,leaves_end_bloc | 3648: 6b 20 49 4e 54 45 47 45 52 2c 65 6e 64 5f 62 6c k INTEGER,end_bl | 3664: 6f 63 6b 20 49 4e 54 45 47 45 62 2c 72 6f 6f 74 ock INTEGEb,root | 3680: 20 42 4c 4f 42 2c 50 52 49 4d 41 52 59 20 4b 45 BLOB,PRIMARY KE | 3696: 59 28 6c 65 76 65 6c 2c 20 69 64 78 29 29 31 06 Y(level, idx))1. | 3712: 06 17 45 1f 01 00 69 6e 64 65 78 73 71 6c 69 74 ..E...indexsqlit | 3728: 65 5f 61 75 74 6f 69 6e 64 65 78 5f 74 31 5f 73 e_autoindex_t1_s | 3744: 65 67 64 69 72 5f 31 74 31 5f 73 65 67 64 69 72 egdir_1t1_segdir | 3760: 06 0f c7 00 08 00 00 00 00 66 04 07 17 23 23 01 .........f...##. | 3776: 81 13 74 61 62 6c 65 74 31 5f 73 65 66 6d 65 6e ..tablet1_sefmen | 3792: 74 73 74 31 5f 73 65 67 6d 65 6e 74 73 04 43 52 tst1_segments.CR | 3808: 45 41 54 45 20 54 41 42 4c 45 20 27 74 31 5f 73 EATE TABLE 't1_s | 3824: 65 67 6d 65 6e 74 73 27 28 62 6c 6f 63 6b 69 64 egments'(blockid | 3840: 20 49 4e 54 45 47 45 52 20 50 52 49 4d 41 52 59 INTEGER PRIMARY | 3856: 20 4b 45 59 2c 20 62 6c 6f 63 6b 20 42 4c 4f 42 KEY, block BLOB | 3872: 29 6a 03 07 17 21 21 01 81 1f 74 61 62 6c 65 74 )j...!!...tablet | 3888: 31 5f 63 6f 6e 74 65 6e 74 74 31 5f 63 6f 6e 74 1_contentt1_cont | 3904: 65 6e 74 03 43 52 45 41 54 45 20 54 41 42 4c 45 ent.CREATE TABLE | 3920: 20 27 74 31 5f 63 6f 6e 74 65 6e 74 27 28 64 6f 't1_content'(do | 3936: 63 69 64 20 49 4e 54 45 47 45 52 20 50 52 49 4d cid INTEGER PRIM | 3952: 41 52 59 20 4b 45 59 2c 20 27 63 30 61 27 2c 20 ARY KEY, 'c0a', | 3968: 27 63 31 62 27 2c 20 27 63 32 63 27 29 38 02 06 'c1b', 'c2c')8.. | 3984: 17 11 11 08 5f 74 61 62 6c 65 74 31 74 31 43 52 ...._tablet1t1CR | 4000: 45 41 54 45 20 56 49 52 54 55 41 4c 20 54 41 42 EATE VIRTUAL TAB | 4016: 4c 45 20 74 31 20 55 53 49 4e 47 20 66 74 73 33 LE t1 USING fts3 | 4032: 28 61 2c 62 2c 63 29 00 00 00 00 00 00 00 00 00 (a,b,c)......... | page 3 offset 8192 | 0: 0d 00 00 00 25 0b 48 00 0f d8 0f af 0f 86 0f 74 ....%.H........t | 16: 0f 61 0f 4e 0f 2f 0f 0f 0e ef 0e d7 0e be 0e a5 .a.N./.......... | 32: 0e 8d 0e 74 0e 5b 0e 40 0e 24 0e 08 0d ef 00 00 ...t.[.@.$...... | 2880: 00 00 00 00 00 00 00 00 81 3f 25 06 00 82 7f 00 .........?%..... | 2896: 00 43 4f 4d 50 49 4c 45 52 3d 67 63 63 2d 35 2e .COMPILER=gcc-5. | 2912: 34 23 00 20 32 2f 31 36 30 36 30 39 20 44 45 42 4#. 2/160609 DEB | 2928: 55 47 20 45 4e 41 42 4c 45 20 44 42 53 54 41 54 UG ENABLE DBSTAT | 2944: 20 56 54 41 42 20 45 4e 41 42 4c 45 20 46 54 53 VTAB ENABLE FTS | 2960: 34 20 45 4e 41 42 4c 45 20 46 54 53 35 20 45 4e 4 ENABLE FTS5 EN | 2976: 41 42 4c 45 20 47 45 4f 50 4f 4c 59 20 45 4e 41 ABLE GEOPOLY ENA | 2992: 42 4c 45 20 4a 53 4f 4e 31 20 45 4e 41 42 4c 45 BLE JSON1 ENABLE | 3008: 20 4d 45 4d 53 59 53 35 20 45 4e 41 42 4c 45 20 MEMSYS5 ENABLE | 3024: 52 54 52 45 45 20 4d 41 58 20 4d 45 4d 4f 52 59 RTREE MAX MEMORY | 3040: 3d 35 30 30 30 30 30 30 30 20 4f 4d 49 54 20 4c =50000000 OMIT L | 3056: 4f 41 44 20 45 58 54 45 4e 53 59 4f 4e 20 54 48 OAD EXTENSYON TH | 3072: 52 45 41 44 53 41 46 45 3d 30 18 24 05 00 25 0f READSAFE=0.$..%. | 3088: 19 54 48 52 45 41 44 53 41 46 45 3d 30 58 42 49 .THREADSAFE=0XBI | 3104: 4e 41 52 59 18 23 05 00 25 0f 19 54 48 52 45 41 NARY.#..%..THREA | 3120: 44 53 41 46 45 3d 30 58 4e 4f 43 41 53 45 17 22 DSAFE=0XNOCASE.. | 3136: 05 00 25 0f 17 54 38 52 45 41 44 53 41 46 45 3d ..%..T8READSAFE= | 3152: 30 58 52 54 52 49 4d 1f 21 05 00 33 0f 19 4f 4d 0XRTRIM.!..3..OM | 3168: 49 54 20 4c 4f 41 44 20 45 58 54 45 fc 53 49 4f IT LOAD EXTE.SIO | 3184: 4e 68 42 49 4e 4a c2 59 1f 20 05 00 33 0f 19 4f NhBINJ.Y. ..3..O | 3200: 4d 49 54 20 4c 4f 41 44 20 45 58 54 45 4e 53 49 MIT LOAD EXTENSI | 3216: 4f 4e 58 4e 4f 43 41 53 45 1e 1f 05 00 33 0f 17 ONXNOCASE....3.. | 3232: 4f 4d 49 54 20 4c 4f 41 44 20 45 58 54 45 4e 53 OMIT LOAD EXTENS | 3248: 49 4f 4e 58 52 54 52 49 4d 1f 1e 05 00 33 0f 19 IONXRTRIM....3.. | 3264: 4d 41 58 20 4d 45 4d 4f 52 59 3d 35 30 2f 30 30 MAX MEMORY=50/00 | 3280: 30 30 30 58 42 49 4e 41 52 59 1f 1d 05 00 33 0f 000XBINARY....3. | 3296: 19 4d 41 58 20 4d 45 4d 4f 52 59 3d 35 30 30 30 .MAX MEMORY=5000 | 3312: 30 30 30 30 48 4e 4f 43 41 53 45 1e 1c 05 00 33 0000HNOCASE....3 | 3328: 0f 17 4d 41 58 20 4d 45 4d 4f 52 59 3d 35 30 30 ..MAX MEMORY=500 | 3344: 30 30 30 30 30 58 52 54 52 49 4d 18 1b 05 00 25 00000XRTRIM....% | 3360: 0f 19 45 4e 41 42 4c 45 20 52 54 52 45 45 58 42 ..ENABLE RTREEXB | 3376: 49 4e 41 52 59 18 1a 05 00 25 0f 19 45 4e 41 42 INARY....%..ENAB | 3392: 4c 45 20 52 54 52 45 45 58 4e 4f 53 41 53 45 17 LE RTREEXNOSASE. | 3408: 19 05 00 25 0f 17 45 4e 41 42 4c 45 20 52 54 52 ...%..ENABLE RTR | 3424: 45 45 58 52 54 52 49 4d 1a 18 05 00 29 0f 19 45 EEXRTRIM....)..E | 3440: 4e 41 42 4c 45 20 4d 45 4d 53 59 53 35 58 42 49 NABLE MEMSYS5XBI | 3456: 4e 41 52 59 1a 17 05 00 29 0f 19 45 4e 41 42 4c NARY....)..ENABL | 3472: 45 20 4d 45 4d 53 59 53 35 58 4e 4f 43 41 53 45 E MEMSYS5XNOCASE | 3488: 19 16 05 00 29 0f 17 45 4e 41 42 4c 45 20 4d 45 ....)..ENABLE ME | 3504: 4d 53 59 53 35 58 52 54 52 49 4d 18 15 05 00 25 MSYS5XRTRIM....% | 3520: 0f 19 45 4e 41 42 4c 45 20 4a 53 4f 4e 31 58 42 ..ENABLE JSON1XB | 3536: 49 4e 41 52 59 18 14 05 00 25 0f 19 45 4e 42 42 INARY....%..ENBB | 3552: 4d 45 20 4a 53 4f 4e 31 58 4e 4f 43 41 53 45 17 ME JSON1XNOCASE. | 3568: 13 05 00 25 0f 17 45 4e 41 42 4c 45 20 4a 53 4f ...%..ENABLE JSO | 3584: 4e 31 58 52 54 52 49 4d 1a 12 05 00 29 0f 19 45 N1XRTRIM....)..E | 3600: 4e 41 42 4c 45 20 47 45 4f 50 4f 4c 59 58 42 49 NABLE GEOPOLYXBI | 3616: 4e 41 52 59 1a 11 05 00 29 0f 19 45 4e 41 1e 4c NARY....)..ENA.L | 3632: 45 20 47 45 4f 50 4f 4c 59 58 4e 4f 43 41 53 45 E GEOPOLYXNOCASE | 3648: 19 10 05 00 29 0f 17 45 4e 41 42 4c 45 20 47 45 ....)..ENABLE GE | 3664: 4f 50 4f 4c 59 58 62 54 52 49 4d 17 0f 05 00 23 OPOLYXbTRIM....# | 3680: 0f 19 45 4e 41 42 4c 45 20 46 54 53 35 58 42 49 ..ENABLE FTS5XBI | 3696: 4e 41 52 59 17 0e 05 00 23 0f 19 45 4e 41 42 4c NARY....#..ENABL | 3712: 45 20 46 54 fc 35 58 4e 4f 43 41 53 45 16 0d 05 E FT.5XNOCASE... | 3728: 00 23 0f 17 45 4e 41 42 4c 45 20 46 54 53 35 58 .#..ENABLE FTS5X | 3744: 52 54 52 49 4d 17 0c 05 00 23 0f 19 45 4e 41 42 RTRIM....#..ENAB | 3760: 4c 45 20 46 54 53 34 58 42 49 4e 41 52 59 17 0b LE FTS4XBINARY.. | 3776: 05 00 23 0f 19 45 4e 41 42 4c 45 20 46 54 53 35 ..#..ENABLE FTS5 | 3792: 58 4e 4f 43 40 53 45 16 0a 05 00 23 0f 17 45 4e XNOC@SE....#..EN | 3808: 41 42 4c 45 20 56 54 53 34 58 52 54 52 49 4d 1e ABLE VTS4XRTRIM. | 3824: 09 05 00 31 0f 19 45 4e 41 42 4c 45 20 44 42 53 ...1..ENABLE DBS | 3840: 54 41 54 20 56 54 41 42 58 42 49 4e 41 b3 58 1e TAT VTABXBINA.X. | 3856: 08 05 00 31 0f 19 45 4e 40 42 4c 45 20 44 42 53 ...1..EN@BLE DBS | 3872: 54 41 54 20 56 54 41 42 58 4e 4f 43 41 53 45 1d TAT VTABXNOCASE. | 3888: 07 05 00 31 0f 17 45 4e 41 42 4c 45 20 45 42 53 ...1..ENABLE EBS | 3904: 54 41 54 20 56 54 41 42 58 52 54 52 49 4d 11 06 TAT VTABXRTRIM.. | 3920: 05 00 17 0f 19 44 45 42 55 47 58 42 49 4e 41 52 .....DEBUGXBINAR | 3936: 59 11 05 05 00 17 0f 19 44 45 42 55 47 58 4e 4f Y.......DEBUGXNO | 3952: 43 41 53 45 10 04 05 00 17 0f 17 44 45 42 55 47 CASE.......DEBUG | 3968: 58 52 54 52 49 4d 27 03 05 00 43 0f 19 43 4f 4d XRTRIM'...C..COM | 3984: 50 49 4c 45 52 3d 67 63 63 2d 35 2e 34 2e 30 20 PILER=gcc-5.4.0 | 4000: 32 30 31 36 30 36 30 39 58 4b 19 4e 41 52 59 27 20160609XK.NARY' | 4016: 02 05 00 43 0f 19 43 4f 4d 50 49 4c 45 52 3d 67 ...C..COMPILER=g | 4032: 63 63 2d 35 2e 34 2e 30 20 32 30 31 36 30 36 30 cc-5.4.0 2016060 | page 5 offset 16384 | 0: 0d 00 00 00 02 0b a0 00 0c ad 0b a0 00 00 00 00 ................ | 2976: 82 0a 02 08 08 09 08 08 17 84 06 30 20 32 34 33 ...........0 243 | 2992: 00 01 30 04 25 06 1b 00 00 08 32 30 31 36 30 36 ..0.%.....201606 | 3008: 30 39 03 25 07 00 00 01 34 03 25 05 00 00 01 35 09.%....4.%....5 | 3024: 03 25 04 00 01 07 30 30 30 30 30 30 30 03 25 1a .%....0000000.%. | 3040: 00 00 08 63 6f 6d 70 69 6c 65 72 03 25 02 00 00 ...compiler.%... | 3056: 06 64 62 73 74 51 74 03 25 0a 00 01 04 65 62 75 .dbstQt.%....ebu | 3072: 67 03 25 08 00 00 06 65 6e 61 62 6c 65 09 25 09 g.%....enable.%. | 3088: 05 04 04 04 04 04 00 01 08 78 74 65 6e 73 69 6f .........xtensio | 3104: 6e 03 25 1d 00 00 04 66 74 73 34 03 25 0d 00 03 n.%....fts4.%... | 3120: 01 35 03 25 0f 00 00 03 67 63 63 03 25 03 00 01 .5.%....gcc.%... | 3136: 06 65 6f 70 6f 6c 79 03 25 11 00 00 05 6a 73 6f .eopoly.%....jso | 3152: 6e 31 03 25 13 00 00 04 6c 6f 61 64 03 25 1c 00 n1.%....load.%.. | 3168: 00 03 6d 61 78 03 25 18 00 01 05 65 6d 6f 72 79 ..max.%....emory | 3184: 03 25 19 00 03 04 73 79 73 35 03 25 15 00 00 04 .%....sys5.%.... | 3200: 6f 6d 69 74 03 25 1b 00 00 05 72 74 72 65 65 03 omit.%....rtree. | 3216: 25 17 00 00 0a 74 68 72 65 61 64 73 61 66 65 03 %....threadsafe. | 3232: 25 1e 00 00 04 76 74 61 62 03 25 0b 00 86 50 01 %....vtab.%...P. | 3248: 08 08 08 08 08 17 8d 12 30 20 38 33 35 00 01 30 ........0 835..0 | 3264: 12 01 06 00 01 06 00 01 06 00 1e f3 00 01 03 00 ................ | 3280: 01 03 00 00 08 32 30 31 36 30 36 30 39 09 01 07 .....20160609... | 3296: 00 01 07 00 01 07 00 00 01 34 09 01 05 00 01 05 .........4...... | 3312: 00 01 05 00 00 01 35 09 01 04 00 01 04 00 01 04 ......5......... | 3328: 00 01 07 30 30 30 30 2f 30 30 09 1c 04 00 01 04 ...0000/00...... | 3344: 00 01 04 00 00 06 62 69 6e 61 72 79 3c 03 01 02 ......binary<... | 3360: 02 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 ................ | 3376: 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 00 ................ | 3392: 03 01 02 02 00 03 01 02 02 00 03 01 02 02 00 03 ................ | 3408: 01 02 02 00 03 01 02 02 00 00 08 63 6f 6d 70 69 ...........compi | 3424: 6c 65 72 09 01 02 00 01 02 00 01 02 00 00 06 64 ler............d | 3440: 62 73 74 61 74 09 07 03 00 01 03 00 01 03 00 01 bstat........... | 3456: 04 65 62 75 67 09 04 02 00 01 02 00 01 02 00 00 .ebug........... | 3472: 06 65 6e 61 62 6c 65 3f 07 02 00 01 02 00 01 02 .enable?........ | 3488: 00 01 02 00 01 02 00 01 01 f0 01 02 00 57 02 00 .............W.. | 3504: 01 02 00 01 02 00 01 02 00 01 02 00 01 02 10 01 ................ | 3520: 02 00 01 02 00 01 02 00 01 02 00 01 02 00 01 02 ................ | 3536: 00 00 02 00 01 02 00 01 08 78 74 65 6e 73 69 6f .........xtensio | 3552: 6e 09 1f 04 00 01 04 00 01 04 00 00 04 66 74 73 n............fts | 3568: 34 09 0a 03 00 01 03 00 01 03 00 03 01 35 09 0d 4............5.. | 3584: 03 00 01 03 00 a9 03 00 00 03 67 63 63 09 01 03 ..........gcc... | 3600: 00 01 03 00 01 03 00 01 06 65 6f 70 6f 6c 79 09 .........eopoly. | 3616: 10 03 00 01 03 00 01 03 00 00 05 6a 73 6f 6e 31 ...........json1 | 3632: 09 13 03 00 01 03 00 01 03 00 00 04 6c 6f 61 64 ............load | 3648: 09 1f 03 00 01 03 00 01 03 00 00 03 6d 61 78 09 ............max. | 3664: 1c 02 0b 31 02 00 01 02 00 01 05 65 6d 6f 72 79 ...1.......emory | 3680: 09 1c 03 00 01 03 00 01 03 00 03 04 73 79 73 35 ............sys5 | 3696: 09 16 03 00 01 03 00 01 03 00 00 06 6e 6f 63 61 ............noca | 3712: 73 65 3c 02 01 02 02 00 03 01 02 02 00 03 01 02 se<............. | 3728: 02 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 ................ | 3744: 00 03 01 02 02 00 f3 01 02 02 00 03 01 02 02 00 ................ | 3760: 03 01 02 02 00 03 01 02 02 00 03 01 02 02 00 00 ................ | 3776: 04 6f 6d 69 74 09 1f 02 00 01 02 00 01 02 00 00 .omit........... | 3792: 05 72 74 72 65 65 09 19 03 00 01 03 00 01 03 00 .rtree.......... | 3808: 03 02 69 6d 3c 01 01 02 02 00 03 01 02 02 00 03 ..im<........... | 3824: 01 02 02 00 03 01 02 02 00 03 01 02 02 00 03 01 ................ | 3840: 02 02 00 03 01 02 02 00 03 01 02 02 00 03 01 02 ................ | 3856: 02 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 ................ | 3872: 00 00 0a 74 68 72 65 61 64 63 61 66 65 09 22 02 ...threadcafe... | 3888: 00 01 02 00 02 02 00 00 04 76 74 61 62 09 07 04 .........vtab... | 3904: 00 01 04 00 01 04 00 00 01 78 b4 01 01 01 01 02 .........x...... | 3920: 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 ................ | 3936: 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 01 ................ | 3952: 01 01 02 00 01 01 01 02 00 01 01 01 02 00 01 01 ................ | 3968: 01 02 00 01 01 01 02 00 01 01 01 02 00 01 01 01 ................ | 3984: 02 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 ................ | 4000: 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 ................ | 4016: 01 01 01 02 00 01 01 01 02 00 01 00 01 02 00 01 ................ | 4032: 01 01 02 00 01 01 00 e2 00 01 01 01 02 00 01 01 ................ | 4048: 01 02 00 01 01 01 02 00 01 01 01 02 00 01 01 01 ................ | 4064: 02 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 ................ | 4080: 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 ................ | page 6 offset 20480 | 0: 0a 00 00 00 02 0f f5 00 0f fb 0f f5 00 00 00 00 ................ | 4080: 00 00 00 00 00 05 04 08 09 01 02 04 04 08 08 09 ................ | page 7 offset 24576 | 0: 0d 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ | 4016: 00 00 00 00 00 00 00 00 0d 05 02 23 61 00 00 00 ...........#a... | end crash-26682721375870.db }]} {} do_execsql_test 26.1 { PRAGMA writable_schema = 1; SELECT count(*) FROM ( SELECT t1, (t1) FROM t1 WHERE b MATCH 'x' ) } 34 #------------------------------------------------------------------------- reset_db do_test 27.0 { sqlite3 db {} db deserialize [decode_hexdb { .open --hexdb | size 28672 pagesize 4096 filename crash-23ddd777a03bfd.db | page 1 offset 0 | 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3. | 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 00 .....@ ........ | 96: 00 00 00 00 0d 0e b1 00 06 0d a4 00 0f 8d 0f 21 ...............! | 112: 0e b9 0d c8 0e 7e 0d a4 00 00 00 00 00 00 00 00 .....~.......... | 3488: 00 00 00 00 22 07 06 17 11 11 01 31 74 61 62 6c ...........1tabl | 3504: 65 74 32 74 32 07 43 52 45 41 54 45 20 54 41 42 et2t2.CREATE TAB | 3520: 4c 45 20 74 32 28 78 29 81 33 05 07 17 1f 1f 01 LE t2(x).3...... | 3536: 82 35 74 61 62 6c 65 74 31 5f 73 65 67 64 69 72 .5tablet1_segdir | 3552: 74 31 5f 73 65 67 64 69 72 05 43 52 45 41 54 45 t1_segdir.CREATE | 3568: 20 54 41 42 4c 45 20 27 74 31 5f 73 65 67 64 69 TABLE 't1_segdi | 3584: 72 27 28 6c 65 76 65 6c 20 49 4e 54 45 47 45 52 r'(level INTEGER | 3600: 2c 69 64 78 20 49 4e 54 45 47 45 52 2c 73 74 61 ,idx INTEGER,sta | 3616: 72 74 5f 62 6c 6f 63 6b 20 49 4e 54 45 47 45 52 rt_block INTEGER | 3632: 2c 6c 65 61 76 65 73 5f 65 6e 64 5f 62 6c 6f 63 ,leaves_end_bloc | 3648: 6b 20 49 4e 54 45 47 45 52 2c 65 6e 64 5f 62 6c k INTEGER,end_bl | 3664: 6f 63 6b 20 49 4e 54 45 47 45 52 2c 72 6f 6f 74 ock INTEGER,root | 3680: 20 42 4c 4f 42 2c 50 52 49 4d 41 52 59 20 4b 45 BLOB,PRIMARY KE | 3696: 59 28 6c 65 76 65 6c 2c 20 69 64 78 29 29 31 06 Y(level, idx))1. | 3712: 06 17 45 1f 01 00 69 6e 64 65 78 73 71 6c 69 74 ..E...indexsqlit | 3728: 65 5f 61 75 74 6f 69 6e 64 65 78 5f 74 31 5f 73 e_autoindex_t1_s | 3744: 65 67 64 69 72 5f 31 74 31 5f 73 65 67 64 69 72 egdir_1t1_segdir | 3760: 06 0f c7 00 08 00 00 00 00 66 04 07 17 23 23 01 .........f...##. | 3776: 81 13 74 61 62 6c 65 74 31 5f 73 65 67 6d 65 6e ..tablet1_segmen | 3792: 64 73 74 31 5f 73 65 67 6d 65 6e 73 73 04 43 52 dst1_segmenss.CR | 3808: 45 41 54 45 20 54 41 42 4c 45 20 27 74 31 5f 73 EATE TABLE 't1_s | 3824: 65 67 6d 65 6e 74 73 27 28 62 6c 6f 63 6b 69 64 egments'(blockid | 3840: 20 49 4e 54 45 47 45 52 20 50 52 49 4d 4e 72 59 INTEGER PRIMNrY | 3856: 20 4b 45 59 2c 20 62 6c 6f 63 6b 20 42 4c 4f 42 KEY, block BLOB | 3872: 29 6a 03 07 17 21 21 01 81 1f 74 61 62 6c 65 74 )j...!!...tablet | 3888: 31 5f 63 6f 6e 74 65 6e 74 74 31 5f 63 6f 6e 74 1_contentt1_cont | 3904: 65 6e 74 04 43 52 45 41 54 45 20 54 41 42 4c 45 ent.CREATE TABLE | 3920: 20 27 74 31 5f 63 6f 6e 74 65 6e 74 27 28 64 6f 't1_content'(do | 3936: 63 69 64 20 49 4e 54 45 47 45 52 20 50 52 39 4d cid INTEGER PR9M | 3952: 41 52 59 20 4b 45 59 2c 20 27 63 30 61 27 2c 20 ARY KEY, 'c0a', | 3968: 27 63 31 62 27 2c 20 27 63 32 63 27 29 38 02 06 'c1b', 'c2c')8.. | 3984: 17 11 11 08 5f 74 61 62 6c 65 74 31 74 31 43 52 ...._tablet1t1CR | 4000: 45 41 54 45 20 56 49 52 54 55 41 4c 20 54 41 42 EATE VIRTUAL TAB | 4016: 4c 45 20 74 31 20 55 53 49 4e 47 20 66 74 73 33 LE t1 USING fts3 | 4032: 28 61 2c 62 2c 63 29 00 00 00 00 00 00 00 00 00 (a,b,c)......... | page 3 offset 8192 | 0: 0d 00 00 00 26 0b 48 0e 0f d8 0f af 0f 86 0f 74 ....&.H........t | 16: 0f 61 0f 4e 0f 2f 0f 0f 0e ef 0e 00 00 00 00 00 .a.N./.......... | 2880: 00 00 00 00 00 00 00 00 81 3f 25 06 00 72 7f 00 .........?%..r.. | 2896: 00 43 4f 4d 50 49 4c 45 52 3d 67 63 63 2d 35 2e .COMPILER=gcc-5. | 2912: 34 2e 30 20 32 30 31 36 30 36 30 39 20 44 55 42 4.0 20160609 DUB | 2928: 55 47 20 45 4e 41 e4 7c 45 20 44 42 53 54 41 54 UG ENA.|E DBSTAT | 2944: e4 46 54 41 42 20 45 4e 41 42 4c 45 20 46 54 53 .FTAB ENABLE FTS | 2960: 34 20 45 4e 41 42 4c 45 20 46 54 53 35 20 45 4e 4 ENABLE FTS5 EN | 2976: 41 42 4c 45 20 47 45 4f 50 4f 4c 59 20 45 4e 41 ABLE GEOPOLY ENA | 2992: 42 4c 45 20 4a 53 4f 4e 31 20 45 4e 41 42 4c 45 BLE JSON1 ENABLE | 3008: 20 4d 45 4d 53 59 53 35 20 45 4e 41 42 4c 45 20 MEMSYS5 ENABLE | 3024: 42 54 52 45 45 20 4d 41 58 20 4d 45 4d 4f 52 59 BTREE MAX MEMORY | 3040: 3d 35 30 30 30 30 30 30 30 20 4f 4c 49 54 20 4c =50000000 OLIT L | 3056: 4f 41 43 20 45 58 54 45 4e 53 49 4f 4e 21 54 48 OAC EXTENSION!TH | 3072: 52 45 41 44 53 41 46 45 3d 30 18 24 05 00 25 0f READSAFE=0.$..%. | 3088: 19 54 48 52 45 41 44 53 41 46 45 3d 30 58 42 49 .THREADSAFE=0XBI | 3104: 4e 41 52 59 18 23 05 00 25 0f 19 54 48 52 45 41 NARY.#..%..THREA | 3120: 44 53 41 4b 75 3d 30 58 4d 4f 43 41 53 45 17 22 DSAKu=0XMOCASE.. | 3136: 05 00 25 0f 17 54 48 52 45 41 44 53 41 46 46 3d ..%..THREADSAFF= | 3152: 30 58 52 54 52 49 4d 1f 21 05 00 33 0f 19 4f 4d 0XRTRIM.!..3..OM | 3168: 49 54 20 4c 4f 41 44 20 45 58 54 45 4e 52 49 4f IT LOAD EXTENRIO | 3184: 4e 58 42 49 4e 41 52 59 0f 20 05 00 33 0f 19 4f NXBINARY. ..3..O | 3200: 4d 49 54 20 4c 4f 41 44 20 45 58 54 45 4e 43 49 MIT LOAD EXTENCI | 3216: 4f 4e 58 4e 4f 43 41 53 45 1e 1f 05 00 33 0f 17 ONXNOCASE....3.. | 3232: 4f 4d 49 54 20 4c 4f 41 44 20 45 58 54 45 4e 53 OMIT LOAD EXTENS | 3248: 49 4f 4e 58 52 5d 12 49 4d 1f 1e 05 00 33 0f 19 IONXR].IM....3.. | 3264: 4d 41 58 20 4d 45 4d 4f 52 59 3d 35 30 30 30 30 MAX MEMORY=50000 | 3280: 30 30 30 58 42 49 4e 41 52 59 1f 1d 05 00 33 0f 000XBINARY....3. | 3296: 19 4d 41 58 20 4d 45 4d 4f 52 59 3d 35 30 30 30 .MAX MEMORY=5000 | 3312: 30 30 30 30 58 4f 4f 43 41 53 45 1e 1c 05 00 33 0000XOOCASE....3 | 3328: 0f 17 4d 41 b8 20 4d 45 4d 4f 52 59 3d 35 30 3c ..MA. MEMORY=50< | 3344: 30 30 30 30 30 58 52 54 52 49 4d 18 1b 05 00 25 00000XRTRIM....% | 3360: 0f 19 45 4e 41 42 4c 45 20 52 54 52 45 45 58 42 ..ENABLE RTREEXB | 3376: 49 4e 41 52 59 18 1a 05 0d a5 0f 19 45 4e 41 42 INARY.......ENAB | 3392: 4c 45 20 52 54 52 45 45 58 4e 4f 43 41 53 45 17 LE RTREEXNOCASE. | 3408: 19 1c 00 25 0f 17 45 4e 41 42 4c 45 20 52 54 52 ...%..ENABLE RTR | 3424: 45 45 58 52 54 52 49 4d 1a 18 05 00 29 0f 19 45 EEXRTRIM....)..E | 3440: 4e 41 42 4c 45 20 4d 45 4d 53 59 53 35 58 42 49 NABLE MEMSYS5XBI | 3456: 4e 41 53 59 1a 17 05 00 29 0f 19 45 4e 41 42 4c NASY....)..ENABL | 3472: 45 20 4d 45 4d 53 59 53 35 58 4e 4f 43 41 53 45 E MEMSYS5XNOCASE | 3488: 19 16 05 00 29 0f 17 45 4e 41 42 4c 45 20 4d 45 ....)..ENABLE ME | 3504: 4d 53 59 53 35 58 52 54 52 49 4d 18 14 05 01 25 MSYS5XRTRIM....% | 3520: 0f 19 45 4e 12 42 4c 45 20 4a 53 4f 4e 31 58 42 ..EN.BLE JSON1XB | 3536: 49 4e 41 52 59 18 14 05 00 25 09 d9 45 4e 41 42 INARY....%..ENAB | 3552: 4c 45 20 4a 53 4f 3e 31 58 4e 4f 43 41 53 45 17 LE JSO>1XNOCASE. | 3568: 13 05 00 25 0f 17 45 4e 40 42 4c 45 20 4a 53 4f ...%..EN@BLE JSO | 3584: 4e 31 58 52 54 52 49 4d 1a 12 05 82 29 0f 19 45 N1XRTRIM....)..E | 3600: 4e 41 42 4c 45 20 47 45 4f 50 4f 4d 59 58 42 49 NABLE GEOPOMYXBI | 3616: 4e 41 52 59 1a 11 05 c9 29 e8 19 46 4e 41 42 4c NARY....)..FNABL | 3632: 48 c0 47 45 4f 50 4f 4c 59 58 4e 74 43 41 53 45 H.GEOPOLYXNtCASE | 3648: 19 10 05 00 29 0f 17 45 4e 41 42 4c 45 20 47 45 ....)..ENABLE GE | 3664: 4f 50 4f 4c 59 58 52 54 52 49 4d 17 0f 05 00 23 OPOLYXRTRIM....# | 3680: 0f 19 45 4e 41 42 4c 45 30 46 54 53 35 58 42 49 ..ENABLE0FTS5XBI | 3696: 4e 41 52 59 17 0e 05 00 23 0f 19 45 4e 41 42 4c NARY....#..ENABL | 3712: 45 20 46 54 53 35 58 4e 4f 4a e1 53 45 16 0e 05 E FTS5XNOJ.SE... | 3728: 00 23 0f 17 45 4e 41 42 4c 45 20 46 54 53 35 58 .#..ENABLE FTS5X | 3744: 52 54 52 49 4d 17 0c 05 00 23 0f 19 45 4e 41 42 RTRIM....#..ENAB | 3760: 4c 45 20 46 54 53 34 58 42 49 4e 41 52 59 17 0b LE FTS4XBINARY.. | 3776: 05 00 23 0f 19 45 4e 41 42 4c 45 20 46 54 53 34 ..#..ENABLE FTS4 | 3792: 58 4e 4f 43 41 53 45 16 0a 05 00 23 0f 17 55 4e XNOCASE....#..UN | 3808: 41 42 4c 45 20 46 54 53 34 58 52 54 52 49 4d 1e ABLE FTS4XRTRIM. | 3824: 09 05 00 31 0f 19 45 4e 42 42 4c 45 20 44 42 53 ...1..ENBBLE DBS | 3840: 54 41 54 20 56 54 41 42 58 42 49 4e 41 52 59 1e TAT VTABXBINARY. | 3856: 08 05 00 31 0f 19 45 4e 41 42 4c 45 20 44 42 53 ...1..ENABLE DBS | 3872: 54 41 54 20 56 54 41 42 58 4e 4f 43 41 53 45 1d TAT VTABXNOCASE. | 3888: 07 05 00 31 0f 17 45 4e 41 42 4c 45 20 44 42 53 ...1..ENABLE DBS | 3904: 54 41 54 20 56 54 41 42 58 52 54 52 4a 4d 11 06 TAT VTABXRTRJM.. | 3920: 05 f0 17 0f 29 44 45 42 55 47 58 42 49 4e 41 52 ....)DEBUGXBINAR | 3936: 59 11 05 05 00 17 0e 19 44 45 42 55 47 58 4e 4f Y.......DEBUGXNO | 3952: 43 41 53 45 10 04 05 00 17 0f 16 44 45 42 55 47 CASE.......DEBUG | 3968: 58 52 54 52 49 4d 27 03 05 00 43 0f 19 43 4f 4d XRTRIM'...C..COM | 3984: 50 49 4c 45 52 3d 67 63 63 2d 35 2e 34 2e 30 20 PILER=gcc-5.4.0 | 4000: 32 30 31 36 30 36 30 39 58 42 49 4e 41 52 59 27 20160609XBINARY' | 4016: 02 05 00 43 0f 19 43 4f 4d 50 49 4c 45 52 3d 67 ...C..COMPILER=g | 4032: 63 63 2d 35 2e 34 2e 30 20 32 30 31 36 30 36 30 cc-5.4.0 2016060 | 4048: 39 58 4e 4f 43 41 53 45 26 01 06 00 43 0f 17 43 9XNOCASE&...C..C | 4064: 4f 4d 50 49 4b 45 52 3d 67 63 63 2d 35 2e 34 2e OMPIKER=gcc-5.4. | 4080: 30 20 32 30 31 36 30 36 40 39 58 29 54 52 49 4d 0 201606@9X)TRIM | page 4 offset 12288 | 0: 0d 00 10 00 00 10 00 00 00 00 00 00 00 00 00 00 ................ | 16: 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ | page 5 offset 16384 | 0: 0d 00 00 00 02 0b a0 00 0c ad 0b a0 00 00 00 00 ................ | 2976: 82 0a 02 08 08 09 08 08 17 84 06 30 20 32 35 33 ...........0 253 | 2992: 00 01 30 04 25 06 1b 00 00 08 32 30 31 36 30 36 ..0.%.....201606 | 3008: 30 39 03 25 07 00 00 01 34 03 25 05 00 00 01 35 09.%....4.%....5 | 3024: 03 25 04 00 01 07 30 30 30 30 30 30 30 03 25 1a .%....0000000.%. | 3040: 00 00 08 63 6f 6d 70 69 6c 65 72 03 25 02 00 00 ...compiler.%... | 3056: 06 64 62 73 74 61 74 03 25 0a 00 01 04 65 62 75 .dbstat.%....ebu | 3072: 67 03 25 08 00 00 06 65 6e 61 62 7c 65 09 25 09 g.%....enab|e.%. | 3088: 05 04 04 04 04 04 00 01 08 78 74 65 6e 73 69 6f .........xtensio | 3104: 6e 03 25 1d 00 00 04 66 74 73 34 03 25 0d 00 03 n.%....fts4.%... | 3120: 01 35 03 25 0f 00 00 03 67 63 63 03 25 03 00 01 .5.%....gcc.%... | 3136: 06 65 6f 70 6f 6c 79 03 25 11 00 00 05 6a 73 6f .eopoly.%....jso | 3152: 6e 31 03 25 13 00 00 04 6c 6f 61 64 03 25 1c 00 n1.%....load.%.. | 3168: 00 03 6d 61 78 03 25 18 00 01 05 65 6e 6f 72 79 ..max.%....enory | 3184: 03 25 19 00 03 04 ce 79 73 4d 03 25 15 00 00 04 .%.....ysM.%.... | 3200: 6f 6d 69 74 03 25 1b 00 00 05 72 74 72 65 65 03 omit.%....rtree. | 3216: 25 17 00 00 0a 74 68 72 65 61 64 73 61 66 65 03 %....threadsafe. | 3232: 25 0e 00 00 04 76 74 61 62 03 25 0b 00 86 50 01 %....vtab.%...P. | 3248: 08 08 08 08 08 17 8d 12 30 20 38 33 35 00 01 30 ........0 835..0 | 3264: 12 01 06 00 01 06 00 01 06 00 1f 03 00 01 03 00 ................ | 3280: 01 03 00 00 08 32 30 31 36 30 36 30 39 09 01 07 .....20160609... | 3296: 00 01 07 00 01 07 00 00 01 34 09 01 05 00 01 05 .........4...... | 3312: 00 01 05 00 00 01 35 09 01 04 00 01 04 00 01 04 ......5......... | 3328: 00 01 07 30 30 30 30 30 30 30 09 1c 04 00 01 04 ...0000000...... | 3344: 00 01 04 00 00 06 62 69 6e 61 72 79 3c 03 01 02 ......binary<... | 3360: 02 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 ................ | 3376: 00 03 01 02 02 00 02 f1 02 02 00 03 01 02 02 00 ................ | 3392: 03 01 02 02 00 03 01 02 02 00 03 01 02 02 00 03 ................ | 3408: 01 01 f2 00 03 01 02 02 00 00 08 63 6f 6d 70 69 ...........compi | 3424: 6c 65 72 09 01 02 00 01 02 00 01 02 00 00 06 67 ler............g | 3440: d2 73 74 61 74 09 07 03 00 01 03 00 01 03 00 01 .stat........... | 3456: 04 65 62 75 67 09 04 02 00 01 02 00 01 02 00 00 .ebug........... | 3472: 06 65 6e 6f 82 6c 65 3f 07 02 00 01 02 00 01 02 .eno.le?........ | 3488: b0 01 02 00 01 02 00 11 0a f0 01 02 00 01 02 00 ................ | 3504: 01 02 00 01 02 00 01 02 00 01 a6 00 01 02 00 02 ................ | 3520: 02 05 51 02 00 01 02 00 01 02 00 01 02 00 01 02 ..Q............. | 3536: 00 01 02 00 01 02 00 01 08 78 74 65 6e 73 69 6f .........xtensio | 3552: 6e 09 1f 04 00 01 04 00 00 04 00 00 04 66 74 73 n............fts | 3568: 34 09 0a 03 00 01 03 00 01 03 00 03 01 35 09 0d 4............5.. | 3584: 03 00 01 03 00 01 03 00 00 03 67 63 63 09 01 03 ..........gcc... | 3600: 00 01 03 00 01 03 00 01 06 65 6f 70 73 6c 79 09 .........eopsly. | 3616: 10 03 00 01 03 00 01 03 00 00 05 6a 73 6f 6e 31 ...........json1 | 3632: 09 13 03 00 01 03 00 01 03 00 00 04 6c 6f 61 64 ............load | 3648: 09 1f 03 00 01 03 00 01 03 00 00 03 6d 61 78 09 ............max. | 3664: 1c 02 00 01 02 00 01 02 00 01 05 65 6d 6f 72 79 ...........emory | 3680: 09 1c 03 00 01 03 00 01 03 00 03 04 73 79 73 35 ............sys5 | 3696: 09 16 03 00 01 03 00 01 03 00 00 06 6e 6f 63 61 ............noca | 3712: 73 65 3c 02 01 02 02 00 03 01 12 02 00 03 01 02 se<............. | 3728: 02 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 ................ | 3744: 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 00 ................ | 3760: 03 01 02 02 00 03 01 02 02 00 03 01 02 02 00 00 ................ | 3776: 04 6f 6d 69 74 09 1f 02 00 01 02 00 01 02 00 00 .omit........... | 3792: 05 72 74 72 65 65 09 19 03 00 01 03 00 01 03 00 .rtree.......... | 3808: 03 02 69 6d 3c 01 01 02 02 00 03 01 02 02 00 03 ..im<........... | 3824: 01 02 02 00 03 01 02 02 00 03 01 02 02 00 03 01 ................ | 3840: 02 02 00 03 01 02 02 00 03 01 02 02 00 03 01 02 ................ | 3856: 02 00 03 01 02 02 01 e3 01 02 02 00 03 01 02 02 ................ | 3872: 00 00 0a 74 68 72 65 61 64 73 61 66 65 09 22 02 ...threadsafe... | 3888: 00 01 02 00 01 02 00 00 04 76 74 61 62 09 07 04 .........vtab... | 3904: 00 01 04 00 01 04 00 00 01 78 b4 01 01 01 01 02 .........x...... | 3920: 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 ................ | 3936: 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 01 ................ | 3952: 01 01 01 f0 01 01 01 07 30 01 01 01 02 00 01 01 ........0....... | 3968: 01 02 00 ea 01 01 02 00 01 01 01 02 00 11 01 01 ................ | 3984: 02 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 ................ | 4000: 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 ................ | 4016: 01 01 01 01 ff 01 01 01 02 00 01 01 01 02 00 01 ................ | 4032: 01 01 02 00 01 11 01 02 00 01 01 01 02 00 01 01 ................ | 4048: 01 02 00 01 01 01 02 00 01 01 01 02 00 01 01 01 ................ | 4064: 02 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 ................ | 4080: 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 ................ | page 6 offset 20480 | 0: 0a 00 00 00 02 0f f5 00 0f fb 0f f5 01 00 00 00 ................ | 4080: 00 00 00 00 00 05 04 08 09 01 02 04 04 08 08 09 ................ | page 7 offset 24576 | 0: 0d 00 00 00 05 0f b8 00 0e f4 0f e9 10 d6 0f c7 ................ | 4016: 00 00 00 00 00 00 00 00 0f 85 02 23 61 75 74 6f ...........#auto | 4032: 6d 65 72 67 65 3d 35 0d 04 02 23 6d 65 72 67 65 merge=5...#merge | 4048: 3d 31 00 00 00 00 00 00 00 00 00 00 00 00 00 00 =1.............. | end crash-23ddd777a03bfd.db }]} {} do_catchsql_test 27.2 { PRAGMA writable_schema = 1; WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x GLOB 2.16770 FROM x) INSERT INTO t1(a) SELECT randomblob(3000) FROM t2 ; } {1 {database disk image is malformed}} do_catchsql_test 27.3 { WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT 3+x FROM c WHERE x<2.653) INSERT INTO t1(a) SELECT randomblob(-current_time) FROM c; } {1 {database disk image is malformed}} do_catchsql_test 27.4 { UPDATE t1 SET b=quote((true) ) WHERE t1 MATCH 'h*h*'; } {0 {}} do_catchsql_test 27.5 { WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT 3+x FROM c WHERE x<2.653) INSERT INTO t1(a) SELECT randomblob(-current_time) FROM c; } {1 {database disk image is malformed}} do_catchsql_test 27.5 { INSERT INTO t1(t1) SELECT x FROM t2; } {1 {database disk image is malformed}} do_catchsql_test 27.6 { INSERT INTO t1(t1) SELECT x FROM t2; } {1 {database disk image is malformed}} #------------------------------------------------------------------------- reset_db do_test 28.0 { sqlite3 db {} db deserialize [decode_hexdb { .open --hexdb | size 28672 pagesize 4096 filename crash-159ac1ca51ed55.db | page 1 offset 0 | 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3. | 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 00 .....@ ........ | 96: 00 00 00 00 0d 0e b1 00 06 0d a4 00 0f 8d 0f 21 ...............! | 112: 0e b9 0d c8 0e 7e 0d a4 00 00 00 00 00 00 00 00 .....~.......... | 3488: 00 00 00 00 22 07 06 17 11 11 01 31 74 61 62 6c ...........1tabl | 3504: 65 74 32 74 32 07 43 52 45 41 54 45 20 54 41 42 et2t2.CREATE TAB | 3520: 4c 45 20 74 32 28 78 29 81 33 05 07 17 1f 1f 01 LE t2(x).3...... | 3536: 82 35 74 61 62 6c 65 74 31 5f 73 65 67 64 69 72 .5tablet1_segdir | 3552: 74 31 5f 73 65 67 64 69 72 05 43 52 45 41 54 45 t1_segdir.CREATE | 3568: 20 54 41 42 4c 45 20 27 74 31 5f 73 65 67 64 69 TABLE 't1_segdi | 3584: 72 27 28 6c 65 76 65 6c 20 49 4e 54 45 47 45 52 r'(level INTEGER | 3600: 2c 69 64 78 20 49 4e 54 45 47 45 52 2c 73 74 61 ,idx INTEGER,sta | 3616: 72 74 5f 62 6c 6f 63 6b 20 49 4e 54 45 47 45 52 rt_block INTEGER | 3632: 2c 6c 65 61 76 65 73 5f 65 6e 64 5f 62 6c 6f 63 ,leaves_end_bloc | 3648: 6b 20 49 4e 54 45 47 45 52 2c 65 6e 64 5f 62 6c k INTEGER,end_bl | 3664: 6f 63 6b 20 49 4e 54 45 47 45 52 2c 72 6f 6f 74 ock INTEGER,root | 3680: 20 42 4c 4f 42 2c 50 52 49 4d 41 52 59 20 4b 45 BLOB,PRIMARY KE | 3696: 59 28 6c 65 76 65 6c 2c 20 69 64 78 29 29 31 06 Y(level, idx))1. | 3712: 06 17 45 1f 01 00 69 6e 64 65 78 73 71 6c 69 74 ..E...indexsqlit | 3728: 65 5f 61 75 74 6f 69 6e 64 65 78 5f 74 31 5f 73 e_autoindex_t1_s | 3744: 65 67 64 69 72 5f 31 74 31 5f 73 65 67 64 69 72 egdir_1t1_segdir | 3760: 06 0f c7 00 08 00 10 00 00 66 04 07 17 23 23 01 .........f...##. | 3776: 81 13 74 61 62 6c 65 74 31 5f 73 65 67 6d 65 6e ..tablet1_segmen | 3792: 64 73 74 31 5f 73 65 67 6d 65 6e 74 73 04 43 52 dst1_segments.CR | 3808: 45 41 54 45 20 54 41 42 4c 45 20 27 74 31 5f 73 EATE TABLE 't1_s | 3824: 65 67 6d 65 6e 74 73 27 28 62 6c 6f 63 6b 69 64 egments'(blockid | 3840: 20 49 4e 54 45 47 45 52 20 50 52 49 4d 41 52 59 INTEGER PRIMARY | 3856: 20 4b 45 59 2c 20 62 6c 6f 63 6b 20 42 4c 4f 42 KEY, block BLOB | 3872: 29 6a 03 07 17 21 21 01 81 1f 74 61 62 6c 65 74 )j...!!...tablet | 3888: 31 4f 63 6f 6e 74 65 6e 74 74 31 5f 63 6f 6e 74 1Ocontentt1_cont | 3904: 65 6e 74 03 43 52 45 41 54 45 20 54 41 42 4c 45 ent.CREATE TABLE | 3920: 20 27 74 31 5f 63 6f 6e 74 65 6e 74 27 28 64 6f 't1_content'(do | 3936: 63 69 64 20 49 4e 54 45 43 a5 52 20 50 52 39 4d cid INTEC.R PR9M | 3952: 41 52 59 20 4b 45 59 2c 20 27 63 30 61 27 2c 20 ARY KEY, 'c0a', | 3968: 27 63 31 62 27 2c 20 27 63 32 63 27 29 38 02 06 'c1b', 'c2c')8.. | 3984: 17 11 11 08 5f 74 61 62 6c 65 74 31 74 31 43 52 ...._tablet1t1CR | 4000: 45 41 54 45 20 56 49 52 54 55 41 4c 20 54 41 42 EATE VIRTUAL TAB | 4016: 4c 45 20 74 31 20 55 53 49 4e 47 20 66 74 73 33 LE t1 USING fts3 | 4032: 28 61 2c 62 2c 63 29 00 00 00 00 00 00 00 00 00 (a,b,c)......... | page 3 offset 8192 | 0: 0d 00 00 00 26 0b 48 00 00 00 00 00 00 00 00 00 ....&.H......... | 2880: 00 00 00 00 00 00 00 00 81 3f 25 06 00 72 7f 00 .........?%..r.. | 2896: 00 43 4f 4d 50 49 4c 45 52 3d 67 63 63 2d 35 2e .COMPILER=gcc-5. | 2912: 34 2e 30 20 32 30 31 36 30 36 30 39 20 44 55 42 4.0 20160609 DUB | 2928: 55 47 20 45 4e 41 e4 7c 45 20 44 42 53 54 41 54 UG ENA.|E DBSTAT | 2944: e4 46 54 41 42 20 45 4e 41 42 4c 45 20 46 54 53 .FTAB ENABLE FTS | 2960: 34 20 45 4e 41 42 4c 45 20 46 54 53 35 20 45 4e 4 ENABLE FTS5 EN | 2976: 41 42 1f 45 20 47 45 4f 50 4f 4c 59 20 45 4e 41 AB.E GEOPOLY ENA | 2992: 42 4c 45 20 4a 53 4f 4e 31 20 45 4e 41 42 4c 45 BLE JSON1 ENABLE | 3008: 20 4d 45 4d 53 59 53 35 20 45 4e 41 42 4c 45 20 MEMSYS5 ENABLE | 3024: 42 54 52 45 45 20 4d 41 58 20 4d 45 4d 4f 52 59 BTREE MAX MEMORY | 3040: 3d 35 30 30 30 30 30 30 30 20 4f 4c 49 54 20 4c =50000000 OLIT L | 3056: 4f 41 43 20 45 58 54 45 4e 53 49 4f 4e 21 54 48 OAC EXTENSION!TH | 3072: 52 45 41 44 53 41 46 45 3d 2f 18 24 05 00 25 0f READSAFE=/.$..%. | 3088: 19 54 48 52 45 41 44 53 41 46 45 3d 30 58 42 49 .THREADSAFE=0XBI | 3104: 4e 41 52 59 18 23 05 00 25 0f 19 54 48 52 45 41 NARY.#..%..THREA | 3120: 44 53 41 4b 75 3d 30 58 4d 4f 43 41 53 45 17 22 DSAKu=0XMOCASE.. | 3136: 05 00 25 0f 17 54 48 52 45 41 44 53 41 46 46 3d ..%..THREADSAFF= | 3152: 30 58 52 54 52 49 4d 1f 21 05 00 33 0f 19 4f 4d 0XRTRIM.!..3..OM | 3168: 49 54 20 4c 4f 41 44 20 45 58 54 45 4e 52 49 4f IT LOAD EXTENRIO | 3184: 4e 58 42 49 4e 41 52 59 1f 20 05 00 33 0f 19 4f NXBINARY. ..3..O | 3200: 4d 49 54 20 4c 4f 41 44 20 45 58 54 45 4e 53 49 MIT LOAD EXTENSI | 3216: 4f 4e 58 4e 4f 43 41 53 45 1e 1f 05 00 33 0f 17 ONXNOCASE....3.. | 3232: 4f 4d 49 54 20 4c 4f 41 44 20 45 58 54 45 4e 53 OMIT LOAD EXTENS | 3248: 49 4f 4e 58 52 54 52 49 4d 1f 1e 05 00 33 0f 19 IONXRTRIM....3.. | 3264: 4d 41 58 20 4d 45 4d 4f 52 59 3d 35 30 30 30 30 MAX MEMORY=50000 | 3280: 30 30 30 58 42 49 4e 41 52 59 1f 1d 05 00 33 0f 000XBINARY....3. | 3296: 19 4d 41 58 20 4d 45 4d 4f 52 59 3d 35 30 30 30 .MAX MEMORY=5000 | 3312: 30 30 30 30 58 4e 4f 43 41 53 45 1e 1c 05 00 33 0000XNOCASE....3 | 3328: 0f 17 4d 42 b8 20 4d 45 4d 4f 52 59 3d 35 30 30 ..MB. MEMORY=500 | 3344: 30 30 30 30 30 58 52 54 52 4a 4d 18 1b 05 00 25 00000XRTRJM....% | 3360: 0f 19 45 4e 41 42 4c 45 20 52 54 52 45 45 58 42 ..ENABLE RTREEXB | 3376: 49 4e 41 52 59 18 1a 05 0d a5 0f 19 45 4e 41 42 INARY.......ENAB | 3392: 4c 45 20 52 54 52 45 45 58 4e 4f 43 41 53 45 17 LE RTREEXNOCASE. | 3408: 19 1c 00 25 0f 17 45 4e 41 42 4c 45 20 52 54 52 ...%..ENABLE RTR | 3424: 45 45 58 52 54 52 49 4d 1a 18 05 00 29 0f 19 45 EEXRTRIM....)..E | 3440: 4e 41 42 4c 45 20 4d 45 4d 53 59 53 35 58 42 49 NABLE MEMSYS5XBI | 3456: 4e 41 52 59 1a 17 05 00 29 0f 19 45 4e 41 42 4c NARY....)..ENABL | 3472: 45 20 4d 45 4d 53 59 53 35 58 4e 4f 43 41 53 45 E MEMSYS5XNOCASE | 3488: 19 16 05 00 29 0f 17 45 4e 41 42 4c 45 20 4d 45 ....)..ENABLE ME | 3504: 4d 53 59 53 35 58 52 54 52 49 4d 18 14 05 01 25 MSYS5XRTRIM....% | 3520: 0f 19 45 4e 12 42 4c 45 20 4a 53 4f 4e 31 58 42 ..EN.BLE JSON1XB | 3536: 49 4e 41 52 59 18 14 05 00 25 09 d9 45 4e 41 42 INARY....%..ENAB | 3552: 4c 45 20 4a 53 4f 3e 31 58 4e 4f 43 41 53 45 17 LE JSO>1XNOCASE. | 3568: 13 05 00 25 0f 17 44 4e 40 42 4c 45 20 4a 53 4f ...%..DN@BLE JSO | 3584: 4e 31 58 52 54 52 49 4d 1a 12 05 82 29 0f 19 45 N1XRTRIM....)..E | 3600: 4e 41 42 4c 45 20 47 45 4f 50 4f 4c 59 58 42 49 NABLE GEOPOLYXBI | 3616: 4e 41 52 59 1a 11 05 c9 29 e8 19 46 4e 41 42 4c NARY....)..FNABL | 3632: 48 c0 47 45 4f 50 4f 4c 59 58 4e 74 43 41 53 45 H.GEOPOLYXNtCASE | 3648: 19 10 05 00 29 0f 17 45 4e 41 42 4c 45 20 47 45 ....)..ENABLE GE | 3664: 4f 50 4f 4c 59 58 52 54 52 49 4d 17 0f 05 00 23 OPOLYXRTRIM....# | 3680: 0f 19 45 4e 41 42 4c 45 30 46 54 53 35 58 42 49 ..ENABLE0FTS5XBI | 3696: 4e 41 52 59 17 0e 05 00 23 0f 19 45 4e 41 42 4c NARY....#..ENABL | 3712: 45 20 46 54 53 35 58 4e 4f 43 41 53 45 16 0e 05 E FTS5XNOCASE... | 3728: 00 23 0f 17 45 4e 41 42 4c 45 20 46 54 53 35 58 .#..ENABLE FTS5X | 3744: 52 54 52 49 4d 17 0c 05 00 23 0f 19 45 4e 41 42 RTRIM....#..ENAB | 3760: 4c 45 20 46 54 53 34 58 42 49 4e 41 52 59 17 0b LE FTS4XBINARY.. | 3776: 04 ff 23 0f 19 45 4e 41 42 4c 45 20 46 54 53 34 ..#..ENABLE FTS4 | 3792: 58 4e 4f 43 41 53 45 16 0a 05 00 23 0f 17 45 4e XNOCASE....#..EN | 3808: 41 42 4c 45 20 46 54 53 34 58 52 54 52 49 4d 1e ABLE FTS4XRTRIM. | 3824: 09 05 00 31 0f 19 45 4e 42 42 4c 45 20 44 42 53 ...1..ENBBLE DBS | 3840: 54 41 54 20 56 54 41 42 58 42 49 4e 41 52 59 1e TAT VTABXBINARY. | 3856: 08 05 00 31 0f 19 45 4e 41 42 4c 45 20 44 42 53 ...1..ENABLE DBS | 3872: 54 41 54 20 56 54 41 42 58 4e 4f 43 41 53 45 1d TAT VTABXNOCASE. | 3888: 07 05 00 31 0f 17 45 4e 41 42 4c 45 20 44 42 53 ...1..ENABLE DBS | 3904: 54 41 54 20 56 54 41 42 58 52 54 52 4a 4d 11 06 TAT VTABXRTRJM.. | 3920: 05 f0 17 0f 19 44 45 42 55 47 58 42 49 4e 41 52 .....DEBUGXBINAR | 3936: 59 11 05 09 b0 17 0e 19 44 45 42 55 47 58 4e 4f Y.......DEBUGXNO | 3952: 43 41 53 45 10 04 05 00 17 0f 16 44 45 42 55 47 CASE.......DEBUG | 3968: 58 52 54 52 49 4d 27 03 05 00 43 0f 19 43 4f 4d XRTRIM'...C..COM | 3984: 50 49 4c 45 52 3d 67 63 63 2d 35 2e 34 2e 30 20 PILER=gcc-5.4.0 | 4000: 32 30 31 36 30 36 30 39 58 42 49 4e 41 52 59 27 20160609XBINARY' | 4016: 02 05 00 43 0f 19 43 4f 4d 50 49 4c 45 52 4d 67 ...C..COMPILERMg | 4032: 63 63 2d 35 2e 34 2e 30 20 32 30 31 36 30 36 30 cc-5.4.0 2016060 | 4048: 39 58 4e 4f 43 41 53 45 26 01 06 00 43 0f 17 43 9XNOCASE&...C..C | 4064: 4f 4d 50 49 4b 45 52 3d 67 63 63 2d 35 2e 34 2e OMPIKER=gcc-5.4. | 4080: 30 20 32 30 31 36 30 36 40 39 58 29 54 52 49 4d 0 201606@9X)TRIM | page 4 offset 12288 | 0: 0d 00 10 00 00 10 00 00 00 00 00 00 00 00 00 00 ................ | page 5 offset 16384 | 0: 0d 00 00 00 02 0b a0 00 00 00 00 00 00 00 00 00 ................ | 2976: 82 0a 02 08 08 09 08 08 17 84 06 30 20 32 35 33 ...........0 253 | 2992: 00 01 30 04 25 06 1b 00 00 08 32 30 31 36 30 36 ..0.%.....201606 | 3008: 30 39 03 25 07 00 00 01 34 03 25 05 00 00 01 35 09.%....4.%....5 | 3024: 03 25 04 00 4d 07 30 30 30 30 30 30 30 03 25 1a .%..M.0000000.%. | 3040: 00 00 08 63 6f 6d 70 69 6c 65 72 03 25 02 00 00 ...compiler.%... | 3056: 06 64 62 73 74 61 74 03 25 0a 00 01 04 65 62 75 .dbstat.%....ebu | 3072: 67 03 25 08 00 00 06 65 6e 61 62 6c 65 09 25 09 g.%....enable.%. | 3088: 05 04 04 04 04 04 00 01 08 78 74 65 6e 73 69 6f .........xtensio | 3104: 6e 03 25 1d 00 00 04 66 74 73 34 03 25 0d 00 03 n.%....fts4.%... | 3120: 01 35 03 25 0f 00 00 03 67 63 63 03 25 03 00 01 .5.%....gcc.%... | 3136: 06 65 6f 70 6f 6c 79 03 25 10 ff ff f5 6a 73 6f .eopoly.%....jso | 3152: 6e 31 03 25 13 00 00 04 6c 6f 61 64 03 25 1c 00 n1.%....load.%.. | 3168: 00 03 6d 71 78 03 25 18 00 01 05 65 6e 6f 72 79 ..mqx.%....enory | 3184: 03 25 19 00 03 04 ce 79 73 4d 03 25 15 00 00 04 .%.....ysM.%.... | 3200: 6f 6d 69 74 03 25 1b 00 00 05 72 74 72 65 65 03 omit.%....rtree. | 3216: 25 17 00 00 0a 7f 08 72 65 61 64 73 61 66 65 03 %......readsafe. | 3232: 25 0e 00 00 04 76 75 61 62 03 25 0b 00 86 50 01 %....vuab.%...P. | 3248: 08 08 08 08 08 17 8d 12 30 20 38 33 35 00 01 30 ........0 835..0 | 3264: 12 01 06 00 01 06 00 01 06 00 1f 03 00 01 03 09 ................ | 3280: 51 03 00 00 09 32 30 31 36 30 36 30 39 09 01 07 Q....20160609... | 3296: 00 01 07 00 01 07 00 00 01 34 09 01 05 00 01 05 .........4...... | 3312: 00 01 05 00 00 01 35 09 01 04 00 01 03 ff 01 04 ......5......... | 3328: 00 01 07 30 30 30 30 30 30 30 09 1c 04 00 01 04 ...0000000...... | 3344: 00 01 04 00 00 06 62 69 6e 61 72 79 3c 03 01 02 ......binary<... | 3360: 02 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 ................ | 3376: 00 03 01 02 02 00 02 f1 02 02 00 03 01 02 02 00 ................ | 3392: 03 01 02 02 00 03 01 02 02 00 03 01 02 02 00 03 ................ | 3408: 01 02 02 00 03 01 02 02 00 00 08 63 6f 6d 70 69 ...........compi | 3424: 6c 65 72 09 01 02 00 01 02 00 01 02 00 00 06 67 ler............g | 3440: d2 73 74 61 74 09 07 03 00 01 03 00 01 03 00 01 .stat........... | 3456: 04 65 62 75 67 09 04 02 00 01 02 00 01 02 00 00 .ebug........... | 3472: 06 65 6e 6f 82 6c 65 3f 07 02 00 01 02 00 01 02 .eno.le?........ | 3488: b0 01 02 00 00 f2 00 11 02 00 01 02 00 01 02 00 ................ | 3504: 01 02 00 01 02 00 01 02 00 01 a6 00 01 02 00 01 ................ | 3520: 02 05 51 02 00 01 02 00 01 02 00 01 02 00 01 02 ..Q............. | 3536: 00 01 02 00 01 02 00 01 08 78 74 65 6e 73 69 6f .........xtensio | 3552: 6e 09 1f 04 00 01 04 00 00 04 00 00 04 66 74 73 n............fts | 3568: 34 09 0a 03 00 01 03 00 01 03 00 03 01 35 09 0d 4............5.. | 3584: 03 00 01 03 00 01 03 00 00 03 67 63 63 09 01 03 ..........gcc... | 3600: 00 01 03 00 01 03 00 01 06 65 6f 70 73 6c 79 09 .........eopsly. | 3616: 10 03 00 01 03 00 01 03 00 00 05 6a 73 6f 6e 31 ...........json1 | 3632: 09 13 03 00 01 03 00 01 03 00 00 04 6c 6f 61 64 ............load | 3648: 09 1f 03 00 01 03 00 01 03 00 00 03 6d 61 78 09 ............max. | 3664: 1c 02 00 01 02 00 01 02 00 01 05 65 6d 6f 72 79 ...........emory | 3680: 09 1c 03 00 01 03 00 01 03 00 03 04 73 79 73 35 ............sys5 | 3696: 09 16 03 00 01 03 00 01 03 00 00 06 6e 6f 63 61 ............noca | 3712: 73 65 3c 02 01 02 02 00 03 01 12 02 00 03 01 02 se<............. | 3728: 02 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 ................ | 3744: 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 00 ................ | 3760: 0f 71 02 02 00 03 01 02 02 00 03 6f 02 02 00 00 .q.........o.... | 3776: 04 6f 6d 69 74 09 1f 02 00 01 02 00 01 02 00 00 .omit........... | 3792: 05 72 74 72 65 65 09 19 03 00 01 03 00 01 03 00 .rtree.......... | 3808: 03 02 69 6d 3c 01 01 02 02 00 03 01 02 02 00 03 ..im<........... | 3824: 01 02 02 00 03 01 02 02 00 03 01 02 02 00 03 01 ................ | 3840: 02 02 00 03 01 02 02 00 03 01 02 02 00 03 01 02 ................ | 3856: 02 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 ................ | 3872: 00 00 0a 74 68 72 65 61 64 73 61 66 65 09 22 02 ...threadsafe... | 3888: 00 01 02 00 01 02 00 00 04 76 74 61 62 09 07 04 .........vtab... | 3904: 00 01 04 00 01 04 00 00 01 78 b4 01 01 01 01 02 .........x...... | 3920: 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 ................ | 3936: 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 01 ................ | 3952: 01 01 02 00 01 01 01 07 30 01 01 01 02 00 01 01 ........0....... | 3968: 01 02 00 11 01 01 02 00 01 01 01 02 00 11 01 01 ................ | 3984: 02 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 ................ | 4000: 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 ................ | 4016: 01 01 01 01 ff 01 01 01 02 00 01 01 01 02 00 01 ................ | 4032: 01 01 02 00 01 01 01 02 00 01 01 01 02 00 01 01 ................ | 4048: 01 02 00 01 01 01 02 00 01 01 01 02 00 01 01 01 ................ | 4064: 02 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 ................ | 4080: 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 ................ | page 6 offset 20480 | 0: 0a 00 00 00 02 0f f5 00 00 00 00 00 00 00 00 00 ................ | 4080: 00 00 00 00 00 05 04 08 09 01 02 04 04 08 08 09 ................ | page 7 offset 24576 | 0: 0d 00 00 00 05 0f b8 00 0e f4 0f e9 10 d6 0f c7 ................ | 4016: 00 00 00 00 00 00 00 00 0d 05 02 23 61 75 74 6f ...........#auto | 4032: 6d 65 72 67 65 3d 35 0d 04 02 23 6d 65 72 67 65 merge=5...#merge | 4048: 3d 31 00 00 00 00 00 00 00 00 00 00 00 00 00 00 =1.............. | end crash-159ac1ca51ed55.db }]} {} do_catchsql_test 28.1 { PRAGMA writable_schema = 1; WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT 3+x FROM c WHERE x<72) INSERT INTO t1(a) SELECT randomblob(2829) FROM c; } {1 {database disk image is malformed}} do_catchsql_test 28.2 { UPDATE t1 SET b=quote((true) ) WHERE t1 MATCH 'h'; } {0 {}} do_catchsql_test 28.3 { WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT 3+x FROM c WHERE x<72) INSERT INTO t1(a) SELECT randomblob(2829) FROM c; } {1 {database disk image is malformed}} do_catchsql_test 28.4 { WITH c(x) AS (VALUES(1) UNION ALL SELECT 3<<x FROM c WHERE x<72) INSERT INTO t1(a) SELECT randomblob(2829) FROM c; } {0 {}} do_catchsql_test 28.5 { WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT 3+x FROM c WHERE x<72) INSERT INTO t1(a) SELECT randomblob(2829) FROM c; } {1 {database disk image is malformed}} do_catchsql_test 28.6 { WITH c(x) AS (VALUES(1) UNION ALL SELECT 3<<x FROM c WHERE x<72) INSERT INTO t1(a) SELECT randomblob(2829) FROM c; } {0 {}} do_catchsql_test 28.7 { WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+3 FROM c WHERE x<72) INSERT INTO t1(a) SELECT randomblob(2829) FROM c; } {1 {database disk image is malformed}} do_catchsql_test 28.8 { INSERT INTO t1(t1) SELECT x FROM t2; } {0 {}} #------------------------------------------------------------------------- # reset_db do_test 29.0 { sqlite3 db {} db deserialize [decode_hexdb { .open --hexdb | size 28672 pagesize 4096 filename crash-53f41622dd3bf6.db | page 1 offset 0 | 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3. | 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 00 .....@ ........ | 96: 00 00 00 00 0d 0e b1 00 06 0d a4 00 0f 8d 0f 21 ...............! | 112: 0e b9 0d c8 0e 7e 0d a4 00 00 00 00 00 00 00 00 .....~.......... | 3488: 00 00 00 00 22 07 06 17 11 11 01 31 74 61 62 6c ...........1tabl | 3504: 65 74 32 74 32 07 43 52 45 41 54 45 20 54 41 42 et2t2.CREATE TAB | 3520: 4c 45 20 74 32 28 78 29 81 33 05 07 17 1f 1f 01 LE t2(x).3...... | 3536: 82 35 74 61 62 6c 65 74 31 5f 73 65 67 54 69 72 .5tablet1_segTir | 3552: 74 31 5f 73 65 67 64 69 72 05 43 52 45 41 54 45 t1_segdir.CREATE | 3568: 20 54 41 42 4c 45 20 27 74 31 5f 73 65 67 64 69 TABLE 't1_segdi | 3584: 72 27 28 6c 65 76 65 6c 20 49 4e 54 45 47 45 52 r'(level INTEGER | 3600: 2c 69 64 78 20 49 4d 54 45 47 45 52 2c 73 74 61 ,idx IMTEGER,sta | 3616: 72 74 5f 62 6c 6f 63 6b 20 49 4e 54 45 47 45 52 rt_block INTEGER | 3632: 2c 6c 65 61 76 65 73 5f 65 6e 64 5f 62 6c 6f 63 ,leaves_end_bloc | 3648: 6b 20 49 4e 54 45 47 45 52 2c 65 6e 64 5f 62 6c k INTEGER,end_bl | 3664: 6f 63 6b 20 49 4e 54 45 47 45 52 2c 72 6f 6f 74 ock INTEGER,root | 3680: 20 42 4c 4f 42 2c 50 52 49 4d 41 52 59 20 4b 45 BLOB,PRIMARY KE | 3696: 59 28 6c 65 76 65 6c 2c 20 69 64 78 29 29 31 06 Y(level, idx))1. | 3712: 06 17 45 1f 01 00 69 6e 64 65 78 73 71 6c 69 74 ..E...indexsqlit | 3728: 65 5f 61 75 74 6f 69 6e 64 65 78 5f 74 31 5f 73 e_autoindex_t1_s | 3744: 65 67 64 69 72 5f 31 74 31 5f 73 65 67 64 69 72 egdir_1t1_segdir | 3760: 06 0f c7 00 08 00 00 00 00 66 04 07 17 23 23 01 .........f...##. | 3776: 81 13 74 61 62 6c 65 74 31 5f 73 65 67 6d 65 6e ..tablet1_segmen | 3792: 74 73 74 31 5f 73 65 67 6d 65 6e 74 73 04 43 52 tst1_segments.CR | 3808: 45 41 54 45 20 54 41 42 4c 45 20 27 74 31 5f 73 EATE TABLE 't1_s | 3824: 65 67 6d 65 6e 74 73 27 28 62 6c 6f 63 6b 69 64 egments'(blockid | 3840: 20 49 4e 54 45 47 45 52 20 50 52 49 4d 41 52 59 INTEGER PRIMARY | 3856: 20 4b 45 59 2c 20 62 6c 6f 63 6b 20 42 4c 4f 42 KEY, block BLOB | 3872: 29 6a 03 07 17 21 21 01 81 1f 74 61 62 6c 65 74 )j...!!...tablet | 3888: 31 5f 63 6f 6e 74 65 6e 74 74 31 5f 63 6f 6e 74 1_contentt1_cont | 3904: 65 6e 74 03 43 52 45 41 54 45 20 54 41 42 4c 45 ent.CREATE TABLE | 3920: 20 27 74 31 5f 63 6f 6e 74 65 6e 74 27 28 64 6f 't1_content'(do | 3936: 63 69 64 20 49 4e 54 45 47 45 52 20 50 52 39 4d cid INTEGER PR9M | 3952: 41 52 59 20 4b 45 59 2c 20 27 63 30 61 27 2c 20 ARY KEY, 'c0a', | 3968: 27 63 31 62 27 2c 20 27 63 32 63 27 29 38 12 06 'c1b', 'c2c')8.. | 3984: 17 11 11 08 5f 74 61 6b 3c 65 74 31 74 31 43 52 ...._tak<et1t1CR | 4000: 45 41 54 45 20 56 49 52 54 55 41 4c 20 54 41 42 EATE VIRTUAL TAB | 4016: 4c 45 20 74 31 20 55 53 49 4e 47 20 66 74 73 33 LE t1 USING fts3 | 4032: 28 61 2c 62 2c 63 29 00 00 00 00 00 00 00 00 00 (a,b,c)......... | page 3 offset 8192 | 0: 0d 00 00 00 25 0b 48 00 0f d8 0f af 0f 86 0f 74 ....%.H........t | 16: 0f 61 0f 4e 0f 2f 0f 0f 0e ef 0e d7 0e be 0e a5 .a.N./.......... | 32: 0e 8d 0e 74 0e 5b 0e 40 0e 24 0e 08 0d ef 0d d5 ...t.[.@.$...... | 48: 0d bb 0d a0 0d 84 03 28 0d 4f 0d 35 0d 1b 0c fb .......(.O.5.... | 64: 0c da 0c b9 0c 99 0c 78 0c 57 0c 3e 0c 24 0c 0a .......x.W.>.$.. | 80: 0b 48 00 00 00 00 00 00 00 00 00 00 00 00 00 00 .H.............. | 2880: 00 00 00 00 00 00 00 00 81 3f 25 06 00 72 7f 00 .........?%..r.. | 2896: 00 43 4f 4d 50 49 4c 45 52 3d 67 63 63 2d 35 2e .COMPILER=gcc-5. | 2912: 34 2e 30 20 32 30 31 36 30 36 30 39 21 44 45 42 4.0 20160609!DEB | 2928: 55 47 20 45 4e 41 42 4c 45 20 44 42 53 54 41 54 UG ENABLE DBSTAT | 2944: 20 56 54 41 42 20 45 4e 41 42 4c 46 20 46 54 53 VTAB ENABLF FTS | 2960: 34 20 45 4e 41 42 4c 45 20 46 54 53 35 20 45 4e 4 ENABLE FTS5 EN | 2976: 41 42 4c 45 20 47 45 4f 50 4f 4c 59 20 45 4e 41 ABLE GEOPOLY ENA | 2992: 42 4c 55 20 4a 53 4f 4e 31 20 45 4e 41 42 4c 45 BLU JSON1 ENABLE | 3008: 20 4d 45 4d 53 59 53 35 20 45 4e 41 42 4c 45 20 MEMSYS5 ENABLE | 3024: 52 54 52 45 45 56 4d 41 58 20 4d 45 4d 4f 52 59 RTREEVMAX MEMORY | 3040: 3d 35 30 30 30 30 30 30 30 20 4f 4d 49 54 20 4c =50000000 OMIT L | 3056: 4f 42 43 20 45 58 54 45 4e 53 49 4f 4e 20 54 48 OBC EXTENSION TH | 3072: 52 45 41 44 53 41 46 45 3d 40 18 24 05 00 25 0f READSAFE=@.$..%. | 3088: 19 54 48 52 45 41 44 53 41 46 45 3d 30 58 42 49 .THREADSAFE=0XBI | 3104: 4e 41 52 59 18 23 05 00 25 0f 19 54 48 52 45 41 NARY.#..%..THREA | 3120: 44 53 41 46 45 3d 31 58 4e 4f 43 41 53 45 17 22 DSAFE=1XNOCASE.. | 3136: 05 00 25 0f 17 54 48 52 45 41 44 43 41 46 45 3d ..%..THREADCAFE= | 3152: 30 58 52 54 52 49 4d 1f 21 05 00 33 0f 19 4f 4d 0XRTRIM.!..3..OM | 3168: 49 54 20 4c 4f 41 44 20 45 58 54 45 4e 53 49 4f IT LOAD EXTENSIO | 3184: 4e 58 42 49 4e 41 52 59 1f 20 05 00 33 0f 19 4f NXBINARY. ..3..O | 3200: 4d 49 54 20 4c 4f 41 44 20 45 58 54 45 4e 53 48 MIT LOAD EXTENSH | 3216: cf 4e 58 4e 4f 43 41 53 45 1e 1f 05 00 33 0f 17 .NXNOCASE....3.. | 3232: 4f 4d 49 54 20 4c 4f 41 44 20 45 58 54 45 4e 53 OMIT LOAD EXTENS | 3248: 49 4f 4e 58 52 54 52 49 4d 1f 1e 05 00 33 0f 19 IONXRTRIM....3.. | 3264: 4d 41 58 20 4d 45 4d 4f 52 59 2d 35 30 30 30 30 MAX MEMORY-50000 | 3280: 30 30 30 58 42 49 4e 41 52 59 1f 1d 05 00 33 0f 000XBINARY....3. | 3296: 19 4d 41 58 20 4d 45 4d 4f 52 59 3d 35 30 30 30 .MAX MEMORY=5000 | 3312: 30 30 30 30 58 4e 4f 43 41 53 45 1e 1c 05 00 33 0000XNOCASE....3 | 3328: 0f 17 4d 41 58 20 4d 45 4d 4f 52 59 3d 35 30 30 ..MAX MEMORY=500 | 3344: 30 30 30 30 30 58 52 54 52 49 4d 18 1b 05 00 25 00000XRTRIM....% | 3360: 0f 19 45 4e 41 42 4c 45 20 52 54 52 45 45 58 42 ..ENABLE RTREEXB | 3376: 49 4e 41 52 49 18 1a 05 0d a5 0f 19 45 4e 41 42 INARI.......ENAB | 3392: 4c 45 20 52 54 52 45 45 58 4e 4f be 31 53 45 17 LE RTREEXNO.1SE. | 3408: 19 05 00 25 0f 17 45 4e 41 42 4c 45 20 52 54 51 ...%..ENABLE RTQ | 3424: 45 45 58 52 54 52 49 4d 1a 18 05 00 29 0f 19 45 EEXRTRIM....)..E | 3440: 4e 41 42 4c 45 20 4d 45 4d 53 59 53 35 58 42 49 NABLE MEMSYS5XBI | 3456: 4e 41 52 59 1a 17 05 00 29 0f 19 45 4e 41 42 4c NARY....)..ENABL | 3472: 45 20 4d 45 4d 53 59 53 35 58 4e 4f 43 41 53 45 E MEMSYS5XNOCASE | 3488: 19 16 05 00 29 0f 17 45 4e 41 42 4c 45 20 4d 45 ....)..ENABLE ME | 3504: 4d 53 59 53 37 f8 52 54 52 49 4d 18 14 05 00 25 MSYS7.RTRIM....% | 3520: 0f 19 45 4e 41 42 4c 45 20 4a 53 4f 4e 31 58 42 ..ENABLE JSON1XB | 3536: 49 4e 41 52 59 18 14 05 00 25 0f 19 45 4e 41 42 INARY....%..ENAB | 3552: 4c 45 20 4a 53 4f 3e 31 58 4e 4f 43 41 53 45 17 LE JSO>1XNOCASE. | 3568: 13 05 00 25 0f 17 45 4e 41 42 4c 45 20 4a 53 4f ...%..ENABLE JSO | 3584: 4e 31 58 52 54 52 49 4d 1a 12 05 00 29 0f 19 45 N1XRTRIM....)..E | 3600: 4e 41 42 4c 45 20 47 45 4f 50 4f 4c 59 58 42 49 NABLE GEOPOLYXBI | 3616: 4e 41 52 59 1a 11 05 00 29 0f 19 45 4e 41 42 4c NARY....)..ENABL | 3632: 48 c0 47 45 4f 50 4f 4c 40 58 4e 4f 43 41 53 45 H.GEOPOL@XNOCASE | 3648: 19 10 05 00 29 0f 17 45 4e 41 42 4c 45 20 47 45 ....)..ENABLE GE | 3664: 4f 50 4f 4c 59 58 52 54 51 49 4d 17 0f 05 00 23 OPOLYXRTQIM....# | 3680: 0f 19 45 4e 41 42 4c 45 20 46 54 53 35 58 42 49 ..ENABLE FTS5XBI | 3696: 4e 41 52 59 17 0e 05 00 23 0f 19 45 4e 41 42 4c NARY....#..ENABL | 3712: 45 20 46 54 53 35 58 4e 4f 43 41 53 45 16 0d 05 E FTS5XNOCASE... | 3728: 00 23 0f 17 45 4e 41 42 4c 45 20 46 54 53 35 58 .#..ENABLE FTS5X | 3744: 52 54 52 49 4d 17 0c 05 00 23 0f 19 45 4e 41 42 RTRIM....#..ENAB | 3760: 4c 45 20 46 54 53 34 58 42 49 4d 41 52 59 17 0b LE FTS4XBIMARY.. | 3776: 05 00 23 0f 19 45 4e 31 42 4c 45 20 46 1a 53 34 ..#..EN1BLE F.S4 | 3792: 58 4e 4f 43 41 53 45 16 0a 05 00 23 0f 17 45 4e XNOCASE....#..EN | 3808: 41 42 4c 45 20 46 54 53 34 58 52 54 52 49 4d 1e ABLE FTS4XRTRIM. | 3824: 09 05 00 31 0f 19 45 4e 41 42 4c 45 20 44 42 53 ...1..ENABLE DBS | 3840: 54 41 54 20 56 54 41 42 58 42 49 4e 41 52 59 1e TAT VTABXBINARY. | 3856: 08 05 00 31 0f 19 45 4e 41 42 4c 45 20 44 42 53 ...1..ENABLE DBS | 3872: 54 41 54 20 56 54 41 42 58 4e 4f 43 41 53 45 1d TAT VTABXNOCASE. | 3888: 07 05 00 31 0f 17 45 4e 41 42 4c 45 20 44 42 53 ...1..ENABLE DBS | 3904: 54 96 54 20 56 54 41 42 58 52 54 52 49 4d 11 06 T.T VTABXRTRIM.. | 3920: 05 00 17 0f 1e e4 45 42 55 47 58 42 49 4e 41 52 ......EBUGXBINAR | 3936: 59 11 05 05 00 17 0e 19 44 45 42 55 47 58 4e 4f Y.......DEBUGXNO | 3952: 43 41 53 45 10 04 05 00 17 0f 17 44 45 42 55 47 CASE.......DEBUG | 3968: 58 52 54 52 49 4d 27 03 05 01 43 0f 19 43 4f 4d XRTRIM'...C..COM | 3984: 50 49 4c 45 52 3d 67 63 63 2d 35 2e 34 2e 30 20 PILER=gcc-5.4.0 | 4000: 32 30 31 36 30 36 30 39 58 42 49 4e 41 52 59 27 20160609XBINARY' | 4016: 02 05 00 43 0f 19 43 4f 4d 50 49 4c 45 52 3d 67 ...C..COMPILER=g | 4032: 63 63 2d 35 2e 34 2e 30 40 32 30 31 36 30 36 30 cc-5.4.0@2016060 | 4048: 39 58 4e 4f 43 41 53 45 26 01 05 00 43 0f 17 43 9XNOCASE&...C..C | 4064: 4f 4d 4f 49 4c 45 52 3d 67 63 63 2d 35 2e 34 2e OMOILER=gcc-5.4. | 4080: 30 20 32 30 31 36 30 36 30 39 58 52 54 52 49 4d 0 20160609XRTRIM | page 4 offset 12288 | 0: 0d 00 00 01 00 10 00 00 00 00 00 00 00 00 00 00 ................ | page 5 offset 16384 | 0: 0d 00 00 00 02 0b a0 00 0c ad 0b a0 00 00 00 00 ................ | 2976: 82 0a 02 08 08 09 08 08 17 84 06 30 20 32 35 33 ...........0 253 | 2992: 00 01 30 04 25 06 1b 00 00 08 32 30 31 36 30 36 ..0.%.....201606 | 3008: 30 39 03 25 07 00 00 01 34 03 25 05 00 00 01 35 09.%....4.%....5 | 3024: 03 25 04 00 01 07 30 30 30 30 30 30 30 03 25 1a .%....0000000.%. | 3040: 00 00 08 63 6f 6d 70 69 6c 65 72 03 25 02 00 00 ...compiler.%... | 3056: 06 64 62 73 74 61 74 03 25 0a 00 01 04 65 62 75 .dbstat.%....ebu | 3072: 67 03 25 08 00 00 06 65 6e 61 62 6c 65 09 25 09 g.%....enable.%. | 3088: 05 04 04 04 04 04 00 01 08 78 74 65 6e 73 69 6f .........xtensio | 3104: 6e 03 25 1d 00 00 04 66 74 73 34 03 25 0d 00 03 n.%....fts4.%... | 3120: 01 35 03 25 0f 00 00 03 67 63 63 03 25 03 00 01 .5.%....gcc.%... | 3136: 06 65 6f 70 6f 6c 79 03 25 11 00 00 05 6a 73 6f .eopoly.%....jso | 3152: 6e 31 03 25 13 00 00 04 6c 6f 61 64 03 25 1c 00 n1.%....load.%.. | 3168: 00 03 6d 61 78 03 25 18 00 01 05 65 6d 6f 72 79 ..max.%....emory | 3184: 03 25 19 00 03 04 73 79 73 4d 03 25 15 00 00 04 .%....sysM.%.... | 3200: 6e 6d 69 74 03 25 1b 00 00 05 72 74 72 65 65 03 nmit.%....rtree. | 3216: 25 17 00 00 0a 74 68 72 65 61 64 73 61 66 65 03 %....threadsafe. | 3232: 25 0e 00 00 04 76 74 61 62 03 25 0b 00 86 50 01 %....vtab.%...P. | 3248: 08 08 08 08 08 17 8d 12 30 20 38 33 35 00 01 30 ........0 835..0 | 3264: 12 01 06 00 01 06 00 01 06 00 1f 03 00 01 03 00 ................ | 3280: 01 03 00 00 08 32 30 31 36 30 36 30 39 09 01 bd .....20160609... | 3296: 00 01 07 00 01 07 00 00 01 34 09 01 05 00 01 05 .........4...... | 3312: 00 01 06 00 00 01 35 09 01 04 00 01 04 00 02 04 ......5......... | 3328: 00 01 07 30 30 e6 30 30 30 30 09 1c 04 00 01 04 ...00.0000...... | 3344: 00 01 04 00 00 06 62 69 6e 61 72 79 3c 03 01 02 ......binary<... | 3360: 02 00 03 01 02 02 00 04 01 02 02 10 03 01 02 02 ................ | 3376: 00 0f 71 02 12 00 03 01 02 02 00 03 01 65 02 00 ..q..........e.. | 3392: 03 01 02 02 00 03 01 02 02 00 03 01 02 02 00 03 ................ | 3408: 01 0d a2 00 03 01 02 02 00 00 08 63 3b 6d 70 69 ...........c;mpi | 3424: 6c 65 72 09 01 02 00 01 02 00 01 02 00 00 06 64 ler............d | 3440: 62 73 74 61 74 09 07 03 00 01 03 00 01 03 00 01 bstat........... | 3456: 04 65 62 75 67 09 04 02 00 01 02 00 01 02 00 00 .ebug........... | 3472: 06 65 6e 61 62 6c 65 3f 07 02 00 01 02 00 01 02 .enable?........ | 3488: 00 01 02 00 01 02 00 01 01 f0 01 02 00 01 02 00 ................ | 3504: 01 02 00 01 02 00 01 02 00 01 02 00 01 02 00 01 ................ | 3520: 02 00 01 02 00 01 02 00 01 02 00 01 02 00 01 02 ................ | 3536: 00 01 02 00 01 02 00 01 08 78 74 65 6e 73 69 6f .........xtensio | 3552: 6e 09 1f 04 00 01 04 00 01 04 00 00 04 66 74 73 n............fts | 3568: 34 09 0a 03 00 01 03 00 01 03 00 03 01 35 09 0d 4............5.. | 3584: 03 00 01 03 00 01 03 00 00 03 67 63 63 09 01 03 ..........gcc... | 3600: 00 01 03 00 01 03 00 01 06 65 6f 70 6f 6c 79 09 .........eopoly. | 3616: 10 03 00 01 03 00 01 03 00 00 05 6a 73 6f 6e 31 ...........json1 | 3632: 09 13 03 00 01 03 00 01 03 00 00 04 6c 6f 61 64 ............load | 3648: 09 1f 03 00 01 03 00 01 03 00 00 03 6d 61 78 09 ............max. | 3664: 1c 02 00 01 02 00 01 02 00 01 05 65 6d 6f 72 79 ...........emory | 3680: 09 1c 03 00 01 03 00 01 03 00 03 04 73 79 73 35 ............sys5 | 3696: 09 16 03 00 01 03 00 01 03 00 00 06 6e 6f 63 61 ............noca | 3712: 73 65 3c 02 01 02 02 00 03 01 02 02 00 03 01 02 se<............. | 3728: 02 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 ................ | 3744: 00 03 01 02 02 00 03 01 02 02 00 03 01 02 01 f0 ................ | 3760: 03 01 02 02 05 93 01 02 02 00 03 01 02 02 00 00 ................ | 3776: 04 6f 6d 69 74 09 1f 02 00 01 02 00 01 02 00 00 .omit........... | 3792: 05 72 8a 72 65 65 09 19 03 00 01 03 00 11 03 00 .r.ree.......... | 3808: 03 02 69 6d 3c 01 01 02 02 00 03 01 02 02 00 03 ..im<........... | 3824: 01 02 02 00 03 01 02 02 00 03 01 02 02 00 03 01 ................ | 3840: 02 02 00 03 01 02 02 00 03 01 02 02 00 03 01 02 ................ | 3856: 02 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 ................ | 3872: 00 00 0a 74 68 72 65 61 64 73 61 66 65 09 22 02 ...threadsafe... | 3888: 00 01 02 00 01 02 00 00 04 76 75 61 62 09 07 04 .........vuab... | 3904: 00 01 04 00 01 04 00 00 61 78 b4 01 01 01 01 02 ........ax...... | 3920: 00 01 01 01 02 00 00 f1 01 02 00 01 01 01 02 00 ................ | 3936: 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 01 ................ | 3952: 01 01 02 00 01 01 01 02 00 01 01 01 02 00 01 01 ................ | 3968: 01 02 00 01 01 01 01 ff 01 01 01 02 00 01 01 01 ................ | 3984: 02 00 01 01 01 02 00 01 01 01 02 09 01 01 01 02 ................ | 4000: 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 ................ | 4016: 01 01 01 02 00 01 02 01 02 00 01 01 01 02 00 01 ................ | 4032: 01 01 02 00 01 01 01 02 00 01 01 01 02 00 01 01 ................ | 4048: 01 02 00 01 01 01 02 00 01 01 01 02 00 01 01 01 ................ | 4064: 02 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 ................ | 4080: 00 01 01 11 02 00 01 01 01 02 00 01 01 01 02 00 ................ | page 6 offset 20480 | 0: 0a 00 00 00 02 0f f5 00 0f fb 1f f5 00 00 00 00 ................ | 4080: 00 00 00 00 00 05 04 08 09 01 02 04 04 08 08 09 ................ | page 7 offset 24576 | 0: 0d 00 00 00 05 0f b8 00 0f f4 0f e9 10 d6 0f c7 ................ | 4016: 00 00 00 00 00 00 00 00 0d 05 02 23 61 75 74 6f ...........#auto | 4032: 6d 65 72 67 65 3d 35 0d 04 02 23 6d 65 72 67 65 merge=5...#merge | 4048: 3d 31 00 00 00 00 00 00 00 00 00 00 00 00 00 00 =1.............. | end crash-53f41622dd3bf6.db }]} {} do_catchsql_test 29.1 { PRAGMA writable_schema = 1; INSERT INTO t1(a) SELECT X'819192E578DE3F'; UPDATE t1 SET b=quote(zeroblob(current_date)) WHERE t1 MATCH 't*'; INSERT INTO t1(b) VALUES(x'78'); INSERT INTO t1(t1) SELECT x FROM t2; } {1 {database disk image is malformed}} #------------------------------------------------------------------------- # reset_db do_test 30.0 { sqlite3 db {} db deserialize [decode_hexdb { | size 28672 pagesize 4096 filename crash-e6e3857edf9b26.db | page 1 offset 0 | 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3. | 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 00 .....@ ........ | 96: 00 00 00 00 0d 0e b1 00 06 0d a4 00 0f 8d 0f 21 ...............! | 112: 0e b9 0d c8 0e 7e 0d a4 00 00 00 00 00 00 00 00 .....~.......... | 3488: 00 00 00 00 22 07 06 17 11 11 01 31 74 61 62 6c ...........1tabl | 3504: 65 74 32 74 32 07 43 52 45 41 54 45 20 54 41 42 et2t2.CREATE TAB | 3520: 4c 45 20 74 32 28 78 29 81 33 05 07 17 1f 1f 01 LE t2(x).3...... | 3536: 82 35 74 61 62 6c 65 74 31 5f 73 65 67 64 69 72 .5tablet1_segdir | 3552: 74 31 5f 73 65 67 64 69 72 05 43 52 45 41 54 45 t1_segdir.CREATE | 3568: 20 54 41 42 4c 45 20 27 74 31 5f 73 65 67 64 69 TABLE 't1_segdi | 3584: 72 27 28 6c 65 76 65 6c 20 49 4e 54 45 47 45 52 r'(level INTEGER | 3600: 2c 69 64 78 20 49 4e 54 45 47 45 52 2c 73 74 61 ,idx INTEGER,sta | 3616: 72 74 5f 62 6c 6f 63 6b 20 49 4e 54 45 47 45 52 rt_block INTEGER | 3632: 2c 6c 65 61 76 65 73 5f 65 6e 64 5f 62 6c 6f 63 ,leaves_end_bloc | 3648: 6b 20 49 4e 54 45 47 45 52 2c 65 6e 64 5f 62 6c k INTEGER,end_bl | 3664: 6f 63 6b 20 49 4e 54 45 47 45 62 2c 72 6f 6f 74 ock INTEGEb,root | 3680: 20 42 4c 4f 42 2c 50 52 49 4d 41 52 59 20 4b 45 BLOB,PRIMARY KE | 3696: 59 28 6c 65 76 65 6c 2c 20 69 64 78 29 29 31 06 Y(level, idx))1. | 3712: 06 17 45 1f 01 00 69 6e 64 65 78 73 71 6c 69 74 ..E...indexsqlit | 3728: 65 5f 61 75 74 6f 69 6e 64 65 78 5f 74 31 5f 73 e_autoindex_t1_s | 3744: 65 67 64 69 72 5f 31 74 31 5f 73 65 67 64 69 72 egdir_1t1_segdir | 3760: 06 0f c7 00 08 00 00 00 00 66 04 07 17 23 23 01 .........f...##. | 3776: 81 13 74 61 62 6c 65 74 31 5f 73 65 67 6d 65 6e ..tablet1_segmen | 3792: 74 73 74 31 5f 73 65 67 6d 65 6e 74 73 04 43 52 tst1_segments.CR | 3808: 45 41 54 45 20 54 41 42 4c 45 20 27 74 31 5f 73 EATE TABLE 't1_s | 3824: 65 67 6d 65 6e 74 73 27 28 62 6c 6f 63 6b 69 64 egments'(blockid | 3840: 20 49 4e 54 45 47 45 52 20 50 52 49 4d 41 52 59 INTEGER PRIMARY | 3856: 20 4b 45 59 2c 20 62 6c 6f 63 6b 20 42 4c 4f 42 KEY, block BLOB | 3872: 29 6a 03 07 17 21 21 01 81 1f 74 61 62 6c 65 74 )j...!!...tablet | 3888: 31 5f 63 6f 6e 74 65 6e 74 74 31 5f 63 6f 6e 74 1_contentt1_cont | 3904: 65 6e 74 03 43 52 45 41 54 45 20 54 41 42 4c 45 ent.CREATE TABLE | 3920: 20 27 74 31 5f 63 6f 6e 74 65 6e 74 27 28 64 6f 't1_content'(do | 3936: 63 69 64 20 49 4e 54 45 47 45 52 20 50 52 49 4d cid INTEGER PRIM | 3952: 41 52 59 20 4b 45 59 2c 20 27 63 30 61 27 2c 20 ARY KEY, 'c0a', | 3968: 27 63 31 62 27 2c 20 27 63 32 63 27 29 38 02 06 'c1b', 'c2c')8.. | 3984: 17 11 11 08 5f 74 61 62 6c 65 74 31 74 31 43 52 ...._tablet1t1CR | 4000: 45 41 54 45 20 56 49 52 54 55 41 4c 20 54 41 42 EATE VIRTUAL TAB | 4016: 4c 45 20 74 31 20 55 53 49 4e 47 20 66 74 73 33 LE t1 USING fts3 | 4032: 28 61 2c 62 2c 63 29 00 00 00 00 00 00 00 00 00 (a,b,c)......... | page 3 offset 8192 | 0: 0d 00 00 00 25 0b 48 00 0f d8 0f af 0f 86 0f 74 ....%.H........t | 16: 0f 61 0f 4e 0f 2f 0f 0f 0e ef 0e d7 0e be 0e a5 .a.N./.......... | 32: 0e 8d 0e 74 0e 5b 0e 40 0e 24 0e 08 0d ef 00 00 ...t.[.@.$...... | 2880: 00 00 00 00 00 00 00 00 81 3f 25 06 00 82 7e f0 .........?%...~. | 2896: 00 43 4f 4d 50 49 4c 45 52 3d 67 63 63 2d 35 2e .COMPILER=gcc-5. | 2912: 34 23 00 20 32 30 31 36 30 36 30 39 20 44 45 42 4#. 20160609 DEB | 2928: 55 47 20 45 4e 41 42 4c 45 20 44 42 53 54 41 54 UG ENABLE DBSTAT | 2944: 20 56 54 41 42 20 45 4e 42 92 4c 45 20 46 54 53 VTAB ENB.LE FTS | 2960: 34 20 45 4e 41 42 4c 45 20 46 54 53 35 20 45 4e 4 ENABLE FTS5 EN | 2976: 41 42 4c 45 20 47 45 4f 50 4f 4c 59 20 45 4e 41 ABLE GEOPOLY ENA | 2992: 42 4c 45 1f 4a 53 4f 4e 31 20 45 4e 41 42 4c 49 BLE.JSON1 ENABLI | 3008: 00 4d 45 4d 53 59 53 35 20 45 4e 41 42 4c 45 20 .MEMSYS5 ENABLE | 3024: 52 54 52 45 45 20 4d 41 58 20 4d 45 4d 4f 52 59 RTREE MAX MEMORY | 3040: 3d 35 30 30 30 30 30 30 30 20 4f 4d 49 54 20 4c =50000000 OMIT L | 3056: 4f 41 44 20 45 58 54 45 4e 53 49 4f 4e 20 54 48 OAD EXTENSION TH | 3072: 52 45 41 44 53 41 46 45 3d 30 18 24 05 00 25 0f READSAFE=0.$..%. | 3088: 19 54 48 52 45 41 44 53 41 46 45 3d 30 58 42 49 .THREADSAFE=0XBI | 3104: 4e 41 52 59 18 23 05 00 25 0f 19 54 48 52 45 41 NARY.#..%..THREA | 3120: 44 53 41 46 45 3d 30 88 4e 4f 43 41 53 45 17 22 DSAFE=0.NOCASE.. | 3136: 05 00 25 0f 17 54 48 52 45 41 44 53 41 46 45 3d ..%..THREADSAFE= | 3152: 30 58 52 54 52 49 4d 1f 21 05 00 33 0f 19 4f 4d 0XRTRIM.!..3..OM | 3168: 49 54 20 4c 4f 41 44 20 45 58 54 45 4e 53 49 4f IT LOAD EXTENSIO | 3184: 4e 58 42 49 4e 41 52 59 1f 20 05 00 33 0f 19 4f NXBINARY. ..3..O | 3200: 4d 49 54 20 4c 4f 41 44 20 45 58 54 45 4e 53 49 MIT LOAD EXTENSI | 3216: 4f 4e 58 4e 4f 43 41 53 45 1e 20 05 00 33 0f 17 ONXNOCASE. ..3.. | 3232: 4f 4d 49 54 20 4c 4f 41 54 20 45 58 54 45 4e 53 OMIT LOAT EXTENS | 3248: 49 4f 4e 58 52 54 52 49 4d 1f 1e 04 00 33 0f 19 IONXRTRIM....3.. | 3264: 82 41 58 20 4d 45 4d 4f 52 59 3d 35 30 30 30 30 .AX MEMORY=50000 | 3280: 30 30 30 58 42 49 4e 41 52 59 1f 1d 05 00 33 0f 000XBINARY....3. | 3296: 19 4d 41 58 20 4d 45 4d 4f 52 59 3d 35 30 30 30 .MAX MEMORY=5000 | 3312: 30 30 30 30 58 4e 4f 43 41 53 45 1e 1c 05 00 33 0000XNOCASE....3 | 3328: 0f 17 4d 41 58 20 4d 45 4d fa 52 59 3d 35 30 20 ..MAX MEM.RY=50 | 3344: 30 30 30 30 30 58 52 54 52 49 4d 18 1b 05 00 25 00000XRTRIM....% | 3360: 0f 19 45 4e 41 42 4c 45 20 52 53 52 45 45 58 42 ..ENABLE RSREEXB | 3376: 49 4e 41 52 59 18 1a 05 00 25 0f 19 45 4e 41 42 INARY....%..ENAB | 3392: 4c 45 20 52 54 52 45 45 58 4e 4f 53 41 53 45 17 LE RTREEXNOSASE. | 3408: 19 05 00 25 0f 17 45 4e 42 42 4c 45 20 52 54 52 ...%..ENBBLE RTR | 3424: 45 45 58 52 54 52 49 4d 1a 18 05 00 29 0f 19 45 EEXRTRIM....)..E | 3440: 4e 41 42 4c 45 20 4d 45 4d 53 5a 53 35 58 42 49 NABLE MEMSZS5XBI | 3456: 4e 41 52 59 1a 17 05 00 29 0f 19 45 4e 41 42 3c NARY....)..ENAB< | 3472: 45 20 4d 45 4d 53 59 53 35 58 4e 4f 43 41 53 45 E MEMSYS5XNOCASE | 3488: 19 16 05 00 29 0f 17 45 4e 41 42 4c 45 20 4d 45 ....)..ENABLE ME | 3504: 4d 53 59 53 35 58 52 54 52 49 4d 18 15 05 00 25 MSYS5XRTRIM....% | 3520: 0f 19 45 4e 41 42 4c 45 20 4a 53 4f 4e 31 58 42 ..ENABLE JSON1XB | 3536: 49 4e 41 52 59 18 14 05 00 25 0f 19 45 4e 41 42 INARY....%..ENAB | 3552: 4c 45 20 4a 53 4f 4e 31 58 4e 4f 43 41 53 45 17 LE JSON1XNOCASE. | 3568: 13 05 00 25 0f 17 45 4e 41 42 4c 45 20 4a 53 4f ...%..ENABLE JSO | 3584: 4e 31 58 52 54 52 49 4d 1a 12 05 00 29 0f 19 45 N1XRTRIM....)..E | 3600: 4e 31 42 4c 45 20 47 45 4e 50 4f 4c 59 58 42 49 N1BLE GENPOLYXBI | 3616: 4e 41 52 59 1a 11 05 00 29 0f 19 45 4e f2 1e 4c NARY....)..EN..L | 3632: 45 20 47 45 4f 50 4f 4c 59 58 4e 4f 43 41 53 45 E GEOPOLYXNOCASE | 3648: 19 10 05 00 29 0f 17 45 4e 41 42 4c 45 20 47 45 ....)..ENABLE GE | 3664: 4f 50 4f 4c 59 58 52 54 52 49 4d 17 0f 05 00 23 OPOLYXRTRIM....# | 3680: 0f 19 45 4e 41 42 4c 45 20 46 54 53 35 58 42 49 ..ENABLE FTS5XBI | 3696: 4e 41 52 59 17 0e 05 00 23 0f 19 45 4e 41 42 3c NARY....#..ENAB< | 3712: 45 20 46 54 53 35 58 4e 4f 43 41 53 45 16 0d 05 E FTS5XNOCASE... | 3728: 00 23 0f 17 45 4e 41 42 4c 45 20 46 54 53 35 58 .#..ENABLE FTS5X | 3744: 52 54 52 49 4d 17 0c 05 00 23 0f 19 45 4e 41 42 RTRIM....#..ENAB | 3760: 4c 45 20 46 54 53 34 58 42 49 4e 41 52 59 17 0b LE FTS4XBINARY.. | 3776: 05 00 23 0f 19 45 4e 41 43 4c 45 20 46 54 53 35 ..#..ENACLE FTS5 | 3792: 58 4e 4f 43 40 53 45 16 0a 05 00 23 0f 17 45 4e XNOC@SE....#..EN | 3808: 41 42 4c 45 20 46 54 53 34 58 52 54 52 49 4d 1e ABLE FTS4XRTRIM. | 3824: 09 05 00 31 0f 19 45 4e 41 42 4c 45 20 44 42 53 ...1..ENABLE DBS | 3840: 54 41 55 20 56 54 41 42 58 42 49 4e 41 52 59 1e TAU VTABXBINARY. | 3856: 08 05 00 31 0f 19 45 4e 41 42 4c 45 20 44 42 53 ...1..ENABLE DBS | 3872: 54 41 54 20 56 54 41 42 58 4e 4f 43 41 53 45 1d TAT VTABXNOCASE. | 3888: 07 05 00 31 0f 17 45 4e 41 42 4c 45 20 44 42 53 ...1..ENABLE DBS | 3904: 54 41 54 20 56 54 41 42 58 52 54 62 49 4d 11 06 TAT VTABXRTbIM.. | 3920: 05 00 17 0f 19 44 45 42 54 47 58 42 49 4e 41 52 .....DEBTGXBINAR | 3936: 59 11 05 05 00 17 0f 19 54 45 42 55 47 58 4e 4f Y.......TEBUGXNO | 3952: 43 41 53 45 10 04 05 00 17 0f 17 44 45 42 55 47 CASE.......DEBUG | 3968: 68 52 54 52 49 4d 27 03 05 00 43 0f 19 43 4f 4d hRTRIM'...C..COM | 3984: 50 49 4c 45 52 3d 67 63 63 2d 35 2e 34 2e 30 20 PILER=gcc-5.4.0 | 4000: 32 30 31 36 30 36 30 39 58 42 49 4e 41 52 59 27 20160609XBINARY' | 4016: 02 05 00 43 0f 19 43 4f 4d 50 49 4c 45 52 3d 67 ...C..COMPILER=g | 4032: 63 63 2d 35 2e 34 2e 30 20 32 30 31 36 30 36 30 cc-5.4.0 2016060 | 4048: 39 58 4f 4f 43 41 53 45 26 01 05 00 43 0f 17 43 9XOOCASE&...C..C | 4064: 4f 4d 50 49 4c 45 52 3d 67 63 63 2d 35 2e 34 2e OMPILER=gcc-5.4. | 4080: 30 20 32 30 31 36 30 36 30 39 58 52 54 52 49 4d 0 20160609XRTRIM | page 4 offset 12288 | 0: 0d 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ | page 5 offset 16384 | 0: 0d 00 00 00 02 0b a0 00 0c ad 0b a0 00 00 00 00 ................ | 2976: 82 0a 02 08 08 09 08 08 17 84 06 30 20 32 35 33 ...........0 253 | 2992: 00 01 30 04 25 06 1b 00 00 08 32 30 31 36 30 36 ..0.%.....201606 | 3008: 30 39 03 25 07 00 00 01 34 03 25 05 00 00 01 35 09.%....4.%....5 | 3024: 03 25 04 00 01 07 30 30 30 30 30 30 30 03 25 1a .%....0000000.%. | 3040: 00 00 08 63 6f 6d 70 69 6c 65 72 03 25 02 00 00 ...compiler.%... | 3056: 06 64 62 73 74 61 74 03 25 0a 00 01 04 65 62 75 .dbstat.%....ebu | 3072: 67 03 25 08 00 00 06 65 6e 61 62 6c 65 09 25 09 g.%....enable.%. | 3088: 05 04 04 04 04 04 00 01 08 78 74 65 6e 73 69 6f .........xtensio | 3104: 6e 03 25 1d 00 00 04 66 74 73 34 03 25 0d 00 03 n.%....fts4.%... | 3120: 01 35 03 25 0f 00 00 03 67 63 63 03 25 03 00 01 .5.%....gcc.%... | 3136: 06 65 6f 70 6f 6c 79 03 25 11 00 00 05 6a 73 6f .eopoly.%....jso | 3152: 6e 31 03 25 14 00 e8 04 6c 6f 61 64 03 25 1c 00 n1.%....load.%.. | 3168: 00 03 6d 61 78 03 25 18 00 01 05 65 6d 6f 72 79 ..max.%....emory | 3184: 03 25 19 00 03 04 73 79 73 35 03 25 15 00 00 04 .%....sys5.%.... | 3200: 6f 6d 69 74 03 25 1b 00 00 05 72 74 72 65 65 03 omit.%....rtree. | 3216: 25 17 00 00 0a 74 68 72 65 61 64 73 61 66 65 03 %....threadsafe. | 3232: 25 1e 00 00 04 76 74 61 62 03 25 0b 00 86 50 01 %....vtab.%...P. | 3248: 08 08 08 08 08 17 8d 12 30 20 38 33 35 00 01 30 ........0 835..0 | 3264: 12 01 06 00 01 06 00 01 06 00 1f 03 00 01 03 00 ................ | 3280: 01 03 00 00 08 32 30 31 36 30 36 30 39 09 01 07 .....20160609... | 3296: 00 01 07 00 01 07 00 00 01 34 09 01 05 00 01 05 .........4...... | 3312: 00 01 05 00 00 01 35 09 01 04 00 01 04 00 01 04 ......5......... | 3328: 00 01 07 30 30 30 30 30 30 30 09 1c 04 00 01 04 ...0000000...... | 3344: 00 01 04 00 00 06 62 69 6e 61 72 79 3c 03 01 02 ......binary<... | 3360: 02 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 ................ | 3376: 00 03 01 02 f2 00 03 01 02 02 00 03 01 02 02 00 ................ | 3392: 03 01 02 02 00 03 01 02 02 00 03 01 02 02 00 03 ................ | 3408: 01 02 02 00 03 01 02 02 00 00 08 63 6f 6d 70 69 ...........compi | 3424: 6c 65 72 09 01 02 00 01 02 00 01 02 00 00 06 64 ler............d | 3440: 62 73 74 61 74 09 07 03 00 01 03 00 01 03 00 01 bstat........... | 3456: 04 65 62 75 67 09 04 02 00 01 02 00 01 02 00 00 .ebug........... | 3472: 06 65 6e 60 62 6c 65 3f 07 02 00 01 02 00 01 01 .en`ble?........ | 3488: ff f1 b1 00 00 02 3f 01 01 f0 f1 02 00 57 02 00 ......?......W.. | 3504: 01 02 00 01 02 00 01 02 00 01 02 00 01 02 10 01 ................ | 3520: 02 00 01 02 00 01 02 00 01 02 01 01 02 00 01 02 ................ | 3536: 00 01 02 00 00 f2 00 01 08 78 74 65 6e 73 69 6f .........xtensio | 3552: 6e 09 1f 04 00 01 04 00 01 04 00 00 04 66 74 73 n............fts | 3568: 34 09 0a 03 00 01 03 00 01 03 00 03 01 35 09 0d 4............5.. | 3584: 03 00 01 03 00 01 03 00 00 03 67 63 63 09 01 03 ..........gcc... | 3600: 00 01 03 00 01 03 00 01 06 65 6f 70 6f 6c 79 09 .........eopoly. | 3616: 10 03 00 01 03 00 01 03 00 00 b3 6a 73 6f 6e 31 ...........json1 | 3632: 09 13 03 00 01 03 00 01 03 00 00 04 6c 6f 61 64 ............load | 3648: 09 1f 03 00 01 03 00 01 03 00 00 03 6d 61 78 09 ............max. | 3664: 1c 02 00 01 02 00 01 02 00 01 05 65 6d 6f 72 79 ...........emory | 3680: 09 1c 03 00 01 03 00 01 03 00 03 04 73 79 73 35 ............sys5 | 3696: 09 16 03 00 01 03 00 01 03 cc 00 06 6e 6f 63 61 ............noca | 3712: 73 65 3c 02 01 02 02 00 03 01 02 02 00 03 01 02 se<............. | 3728: 02 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 ................ | 3744: 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 00 ................ | 3760: 03 01 02 02 00 03 01 02 02 00 03 01 02 02 00 00 ................ | 3776: 04 6f 6d 69 74 09 1f 02 00 01 02 00 01 02 00 00 .omit........... | 3792: 05 72 74 62 65 65 09 19 03 00 01 03 00 01 03 00 .rtbee.......... | 3808: 03 02 69 6d 3c 01 01 02 02 00 03 01 02 02 00 03 ..im<........... | 3824: 01 02 02 00 03 01 02 02 00 03 01 02 02 00 03 01 ................ | 3840: 02 02 00 03 01 02 02 00 03 01 02 02 00 03 01 02 ................ | 3856: 02 00 03 01 02 02 00 03 01 02 01 00 03 01 02 02 ................ | 3872: 00 00 0a 74 68 72 65 61 64 73 61 66 65 09 22 02 ...threadsafe... | 3888: 00 01 02 00 02 02 00 00 04 76 74 61 62 09 07 04 .........vtab... | 3904: 00 01 03 00 01 04 00 00 01 78 b4 01 01 01 01 02 .........x...... | 3920: 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 ................ | 3936: 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 01 ................ | 3952: 01 01 02 00 01 01 01 02 00 01 01 01 02 00 01 01 ................ | 3968: 01 02 00 01 01 01 02 00 01 01 01 02 00 01 01 01 ................ | 3984: 02 01 01 01 01 02 00 01 01 01 02 00 01 01 01 02 ................ | 4000: 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 ................ | 4016: 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 01 ................ | 4032: 01 01 02 00 01 01 01 da 00 01 01 01 02 00 01 01 ................ | 4048: 01 02 00 01 01 01 01 ff ff 01 01 02 00 01 01 01 ................ | 4064: 02 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 ................ | 4080: 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 ................ | page 6 offset 20480 | 0: 0a 00 00 00 02 0f f5 00 0f fb 0f f5 01 00 00 00 ................ | 4080: 00 00 00 00 00 05 04 08 09 01 02 04 04 08 08 09 ................ | page 7 offset 24576 | 0: 01 6f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 .o.............. | end crash-e6e3857edf9b26.db }]} {} do_execsql_test 30.1 { UPDATE t1 SET b=a; } do_catchsql_test 30.2 { SELECT (matchinfo(null)) FROM t1 WHERE t1 MATCH 'ee*e*e*e*e*e*e*Re*e*e*e**' } {1 {database disk image is malformed}} #------------------------------------------------------------------------- # reset_db do_execsql_test 31.0 { CREATE VIRTUAL TABLE t1 USING fts3(a,b,c); INSERT INTO t1_segdir VALUES(0,0,0,0,'0 592',X'00016dcb048ce6fbd3b2d68bfebf0101020200808080808080808020010202008080808080808080100102020080808080808080800801020200808080808080808004010202008080808080808080020102020080808080808080800101020200808080808080804001020200808080808080802001020200808080808080801001020200808080808080800801020200808080808080800401020200808080808080800201020200808080808080800101020200808080808080400102020080808080808020010202008080808080801001020200808080808080080102020080808080808004010202008080808080800201020200808080808080010102020080808080804001020200808080808020010202008080808080100102020080808080800801020200808080808004010202008080808080020102020080808080800101020200808080804001020200808080802001020200808080801001020200808080800801020200808080800401020200808080800201020200808080800101020200808080400102020080808020010202008080801001020200808080080102020080808004010202008080800201020200808080010102020080804001020200808020010202008080100102020080800801020200808004010202008080020102020080800101020200804001020200802001020200801001020200800801020200800401020200800201020200800101020200400102020020010202001001020200080102020004010202000201020200010102020001010202008080808080808080800101020200'); INSERT INTO t1_segdir VALUES(0,1,0,0,'0 18',X'00026d6d0d8ee6fbd3b2d68bfe7f01020200'); } do_catchsql_test 31.1 { SELECT (matchinfo(t1, c ) ) FROM t1 WHERE t1 MATCH 'M*M*M*M*'; } {1 {database disk image is malformed}} #------------------------------------------------------------------------- # reset_db do_test 32.0 { sqlite3 db {} db deserialize [decode_hexdb { .open --hexdb | size 24576 pagesize 4096 filename crash-74fdbc96edbc04.db | page 1 offset 0 | 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3. | 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 00 .....@ ........ | 96: 00 00 00 00 0d 0e b1 00 06 0d a4 00 0f 8d 0f 21 ...............! | 112: 0e b9 0d c8 0e 7e 0d a4 00 00 00 00 00 00 00 00 .....~.......... | 3488: 00 00 00 00 22 07 06 17 11 11 01 31 74 61 62 6c ...........1tabl | 3504: 65 74 32 74 32 07 43 52 45 41 54 45 20 54 41 42 et2t2.CREATE TAB | 3520: 4c 45 20 74 32 28 78 29 81 33 05 07 17 1f 1f 01 LE t2(x).3...... | 3536: 82 35 74 61 62 6c 65 74 31 5f 73 65 67 64 69 72 .5tablet1_segdir | 3552: 74 31 5f 73 65 67 64 69 72 05 43 52 45 41 54 45 t1_segdir.CREATE | 3568: 20 54 41 42 4c 45 20 27 74 31 5f 73 65 67 64 69 TABLE 't1_segdi | 3584: 72 27 28 6c 65 76 65 6c 20 49 4e 54 45 47 45 52 r'(level INTEGER | 3600: 2c 69 64 78 20 49 4e 54 45 47 44 52 2c 73 74 61 ,idx INTEGDR,sta | 3616: 72 74 5f 62 6c 6f 63 6b 20 49 4e 54 45 47 45 52 rt_block INTEGER | 3632: 2c 6c 65 61 76 65 73 5f 65 6e 64 5f 62 6c 6f 63 ,leaves_end_bloc | 3648: 6b 20 49 4e 54 45 47 45 52 2c 65 6e 64 5f 62 6c k INTEGER,end_bl | 3664: 6f 63 6b 20 49 4e 54 45 47 45 52 2c 72 6f 6f 74 ock INTEGER,root | 3680: 20 42 4c 4f 42 2c 50 52 49 4d 41 52 59 20 4b 45 BLOB,PRIMARY KE | 3696: 59 28 6c 65 76 65 6c 2c 20 69 64 78 29 29 31 06 Y(level, idx))1. | 3712: 06 17 45 1f 01 00 6a 6e 64 65 78 73 71 6c 69 74 ..E...jndexsqlit | 3728: 65 5f 61 75 74 6f 69 6e 64 65 78 5f 74 31 5f 73 e_autoindex_t1_s | 3744: 65 67 64 69 72 5f 31 74 31 5f 73 65 67 64 69 72 egdir_1t1_segdir | 3760: 06 0f c7 00 08 00 00 00 00 66 04 07 17 23 23 01 .........f...##. | 3776: 81 13 74 61 62 6c 65 74 31 5f 73 65 67 6d 65 6e ..tablet1_segmen | 3792: 74 73 74 31 5f 73 65 67 6d 65 6e 74 73 03 43 52 tst1_segments.CR | 3808: 45 41 54 45 20 54 41 42 4c 45 20 27 74 31 5f 73 EATE TABLE 't1_s | 3824: 65 67 6d 65 6e 74 73 27 28 62 6c 6f 63 6b 69 64 egments'(blockid | 3840: 20 49 4e 54 45 47 45 52 20 50 52 49 4d 41 52 5a INTEGER PRIMARZ | 3856: 20 4b 45 59 2c 20 62 6c 6f 63 6b 20 42 4c 4f 42 KEY, block BLOB | 3872: 29 6a 03 07 17 21 21 01 81 1f 74 61 62 6c 65 74 )j...!!...tablet | 3888: 31 5f 63 6f 6e 74 65 6e 74 74 31 5f 63 6f 6e 74 1_contentt1_cont | 3904: 65 6e 74 03 43 52 45 41 54 45 20 54 41 42 4c 45 ent.CREATE TABLE | 3920: 20 27 74 31 5f 63 6f 6e 74 65 6e 74 27 28 64 6f 't1_content'(do | 3936: 63 69 64 20 49 4e 54 45 47 45 52 20 50 52 49 4d cid INTEGER PRIM | 3952: 41 52 59 20 4b 45 59 2c 20 27 63 30 61 27 2c 20 ARY KEY, 'c0a', | 3968: 27 63 31 62 27 2c 20 27 63 32 63 27 29 38 02 06 'c1b', 'c2c')8.. | 3984: 17 11 11 08 5f 74 61 62 6c 65 74 31 74 31 43 52 ...._tablet1t1CR | 4000: 45 41 54 45 20 56 49 52 54 55 41 4c 20 54 41 42 EATE VIRTUAL TAB | 4016: 4c 45 20 74 31 20 55 53 49 4e 47 20 66 74 73 33 LE t1 USING fts3 | 4032: 28 61 2c 62 2c 63 29 00 00 00 00 00 00 00 00 00 (a,b,c)......... | page 3 offset 8192 | 0: 0d 00 00 00 25 0b 48 00 0f d8 0f af 0f 86 0f 74 ....%.H........t | 16: 0f 61 0f 4e 0f 2f 0f 0f 0e ef 0e d7 0e be 0e a5 .a.N./.......... | 32: 0e 8d 0e 74 0e 5b 0e 40 0e 24 0e 08 0d ef 0d d5 ...t.[.@.$...... | 48: 0d bb 0d a0 0d 84 0d 68 0d 50 0d 35 0d 1b 0c fb .......h.P.5.... | 64: 0c da 0c b8 fc 99 0c 78 0c 57 0c 3e 0c 24 0c 0a .......x.W.>.$.. | 80: 0b 48 00 00 00 00 00 00 00 00 00 00 00 00 00 00 .H.............. | 2880: 00 00 00 00 00 00 00 00 81 3f 25 06 00 82 7f 00 .........?%..... | 2896: 00 43 4f 4d 50 49 4c 45 52 3d 67 63 63 2d 35 2e .COMPILER=gcc-5. | 2912: 34 2e 30 20 32 30 31 36 30 36 30 39 20 44 45 42 4.0 20160609 DEB | 2928: 55 47 20 45 4e 41 42 4c 45 20 44 42 53 54 7e 54 UG ENABLE DBST~T | 2944: 20 56 54 41 42 20 45 4e 41 42 4c 45 20 46 54 53 VTAB ENABLE FTS | 2960: 44 20 45 4e 41 42 4c 45 20 46 54 53 35 20 45 4e D ENABLE FTS5 EN | 2976: 41 42 4c 45 20 47 45 4f 50 4f 4c 59 20 45 4e 41 ABLE GEOPOLY ENA | 2992: 42 4c 45 20 4a 53 4f 4e 31 20 45 4e 41 42 4c 45 BLE JSON1 ENABLE | 3008: 20 4d 45 4d 53 59 53 35 20 45 4e 41 42 4c 45 20 MEMSYS5 ENABLE | 3024: 52 54 52 45 45 20 4d 41 58 20 4d 45 4d 4f 52 59 RTREE MAX MEMORY | 3040: 3d 35 30 30 30 30 30 30 30 20 4f 4d 49 54 20 4c =50000000 OMIT L | 3056: 4f 41 44 20 45 58 54 45 4e 53 49 4f 4e 20 54 48 OAD EXTENSION TH | 3072: 52 45 41 44 53 41 46 45 3d 30 18 24 05 00 25 0f READSAFE=0.$..%. | 3088: 19 54 48 52 45 41 44 54 41 46 45 3d 30 58 42 49 .THREADTAFE=0XBI | 3104: 4e 41 52 59 18 23 05 00 25 0f 19 54 48 52 45 41 NARY.#..%..THREA | 3120: 44 53 41 46 45 3d 30 bd 4e 4f 43 41 53 45 17 22 DSAFE=0.NOCASE.. | 3136: 05 00 25 0f 17 54 48 52 45 41 44 53 41 46 45 3d ..%..THREADSAFE= | 3152: 30 58 52 54 52 49 4d 1f 21 05 00 33 0f 19 4f 4d 0XRTRIM.!..3..OM | 3168: 49 54 20 4c 4f 41 44 20 45 58 54 45 4e 53 49 4e IT LOAD EXTENSIN | 3184: 4e 58 42 49 4e 41 52 59 1f 20 05 00 33 0f 19 4f NXBINARY. ..3..O | 3200: 4d 49 54 20 4c 4f 41 44 20 45 58 54 45 4e 53 49 MIT LOAD EXTENSI | 3216: 4f 4e 58 4e 4f 43 41 53 45 1e 1f 05 00 33 0f 17 ONXNOCASE....3.. | 3232: 4f 4d 49 54 20 4c 4f 41 44 20 45 58 54 45 4e 53 OMIT LOAD EXTENS | 3248: 49 4f 4e 58 52 54 52 49 4d 1f 1e 05 00 33 0f 19 IONXRTRIM....3.. | 3264: 4d 41 58 1f 4d 45 4d 4f 52 59 3d 35 30 30 30 30 MAX.MEMORY=50000 | 3280: 30 30 30 58 42 49 4e 41 52 59 1f 1d 05 00 33 0f 000XBINARY....3. | 3296: 19 4d 41 58 20 4d 45 4d 4f 52 59 3d 35 30 30 30 .MAX MEMORY=5000 | 3312: 30 30 30 30 58 4e 4f 43 41 53 45 1e 1c 05 00 33 0000XNOCASE....3 | 3328: 0f 17 4d 41 58 20 4d 44 4d 4f 52 59 3d 35 30 30 ..MAX MDMORY=500 | 3344: 30 30 30 30 30 58 52 54 52 49 4d 18 1b 05 00 25 00000XRTRIM....% | 3360: 0f 19 45 4e 41 42 4c 45 20 52 54 52 45 45 58 42 ..ENABLE RTREEXB | 3376: 49 4e 41 52 59 18 1a 05 00 25 0f 19 45 4e 41 42 INARY....%..ENAB | 3392: 4c 55 20 52 54 52 45 45 58 4e 4f 43 41 53 45 17 LU RTREEXNOCASE. | 3408: 19 05 00 25 0f 17 45 4e 41 42 4c 45 20 52 54 52 ...%..ENABLE RTR | 3424: 45 45 58 52 54 52 49 4d 1a 18 05 00 29 0f 19 45 EEXRTRIM....)..E | 3440: 4e 41 42 4c 45 20 4d 45 4d 53 59 53 35 58 42 49 NABLE MEMSYS5XBI | 3456: 4e 41 52 59 1a 17 05 00 29 0f 19 45 4e 41 42 4c NARY....)..ENABL | 3472: 45 20 4d 45 4d 53 59 53 35 58 4e 3f 43 41 53 45 E MEMSYS5XN?CASE | 3488: 19 16 05 00 29 0f 17 45 4e a1 42 4c 45 20 4d 45 ....)..EN.BLE ME | 3504: 4d 53 59 53 35 58 52 54 52 49 4d 18 15 05 00 25 MSYS5XRTRIM....% | 3520: 0f 19 45 4e 41 42 4c 45 20 4a 53 4f 4e 31 58 42 ..ENABLE JSON1XB | 3536: 49 4e 41 52 59 18 14 05 00 25 0f 19 45 4e 41 42 INARY....%..ENAB | 3552: 4c 45 20 4a 53 4f 4e 31 58 4e 4f 43 41 53 45 17 LE JSON1XNOCASE. | 3568: 13 05 00 25 0f 17 45 4e 41 42 4c 45 20 4a 53 4f ...%..ENABLE JSO | 3584: 4e 31 58 52 54 52 49 4d 1a 12 05 00 29 0f 19 45 N1XRTRIM....)..E | 3600: 4e 41 42 4c 45 20 47 45 4f 50 5f 4c 59 58 42 49 NABLE GEOP_LYXBI | 3616: 4e 41 52 59 1a 11 05 00 29 0f 19 45 4e 41 42 4c NARY....)..ENABL | 3632: 45 20 47 45 4f 50 4f 4c 59 58 4b bf 43 41 53 45 E GEOPOLYXK.CASE | 3648: 19 10 05 00 29 0f 17 45 4e 41 42 4c 45 20 47 45 ....)..ENABLE GE | 3664: 4f 50 4f 4c 59 58 52 54 52 49 4d 17 0f 05 00 23 OPOLYXRTRIM....# | 3680: 0f 19 45 4e 41 42 4c 55 20 46 54 53 35 58 42 49 ..ENABLU FTS5XBI | 3696: 4e 4b a2 59 17 0e 05 00 23 0f 19 45 4e 41 42 4c NK.Y....#..ENABL | 3712: 45 20 46 54 52 35 58 4e 4f 43 41 53 45 16 0d 05 E FTR5XNOCASE... | 3728: 00 23 0f 17 45 4e 41 42 4c 45 20 46 54 53 35 58 .#..ENABLE FTS5X | 3744: 52 54 52 49 4d 17 0b 05 00 23 0f 19 45 4e 41 42 RTRIM....#..ENAB | 3760: 4c 45 20 46 54 53 34 58 42 49 4e 41 52 59 17 0b LE FTS4XBINARY.. | 3776: 05 00 23 0f 19 45 4e 41 42 4c 45 20 46 54 53 34 ..#..ENABLE FTS4 | 3792: 58 4e 4f 43 41 53 45 16 0a 05 00 23 0f 17 45 4e XNOCASE....#..EN | 3808: 41 42 4c 45 20 46 54 53 34 58 52 54 52 49 4d 1e ABLE FTS4XRTRIM. | 3824: 09 05 07 e1 0f 19 45 4e 41 42 4c 45 20 44 42 53 ......ENABLE DBS | 3840: 54 41 54 20 56 54 41 42 58 42 49 4e 41 52 59 1e TAT VTABXBINARY. | 3856: 18 05 00 31 0f 19 45 4e 41 42 4c 45 20 44 42 53 ...1..ENABLE DBS | 3872: 54 41 54 20 56 54 41 41 18 4e 4f 43 41 53 45 1d TAT VTAA.NOCASE. | 3888: 07 05 00 31 0f 17 45 4e 41 42 4c 45 20 44 32 53 ...1..ENABLE D2S | 3904: 54 41 54 20 56 54 41 42 58 52 54 52 49 4d 11 06 TAT VTABXRTRIM.. | 3920: 05 00 17 0f 19 44 45 42 55 47 58 42 49 4e 41 52 .....DEBUGXBINAR | 3936: 59 11 05 05 00 17 0f 19 44 45 00 00 00 00 00 00 Y.......DE...... | page 5 offset 16384 | 0: 0d 00 00 00 02 0b a0 00 0c ad 0b a0 01 00 00 00 ................ | 2976: 82 0a 02 08 08 09 08 08 17 84 06 30 20 32 35 33 ...........0 253 | 2992: 00 01 30 04 25 06 1b 00 00 08 32 30 31 36 30 36 ..0.%.....201606 | 3008: 30 38 03 25 07 00 00 01 34 03 25 05 00 00 01 35 08.%....4.%....5 | 3024: 03 25 13 00 01 07 30 30 30 30 30 30 30 03 25 1a .%....0000000.%. | 3040: 00 00 08 63 6f 6d 70 69 6c 65 72 03 25 02 00 00 ...compiler.%... | 3056: 06 64 62 73 74 61 74 03 25 0a 00 01 04 65 62 75 .dbstat.%....ebu | 3072: 67 03 25 08 00 00 06 65 6e 61 62 6c 65 09 25 09 g.%....enable.%. | 3088: 05 04 04 04 04 04 00 01 08 78 74 65 6e 73 69 6f .........xtensio | 3104: 6e 03 25 1d 00 00 04 66 74 73 34 03 25 0d 00 03 n.%....fts4.%... | 3120: 01 35 03 25 0f 00 00 03 67 63 63 03 25 03 00 01 .5.%....gcc.%... | 3136: 06 65 6f 70 6f 6c 79 03 25 11 00 00 05 6a 73 6f .eopoly.%....jso | 3152: 6e 31 03 25 13 00 00 04 6c 6f 61 64 03 25 1c 00 n1.%....load.%.. | 3168: 00 03 6d 62 78 03 25 18 00 01 05 65 6d 6f 72 79 ..mbx.%....emory | 3184: 03 25 19 00 03 04 73 c8 73 35 03 25 15 00 00 04 .%....s.s5.%.... | 3200: 6f 6d 69 74 03 25 1b 00 00 05 72 74 72 65 65 03 omit.%....rtree. | 3216: 25 17 00 00 0a 74 68 72 65 61 64 73 61 66 65 03 %....threadsafe. | 3232: 25 1e 00 00 04 76 74 61 62 03 25 0b 00 86 50 01 %....vtab.%...P. | 3248: 08 08 08 08 08 17 8d 12 30 20 38 33 35 00 01 30 ........0 835..0 | 3264: 12 01 06 00 01 06 00 01 06 00 1f 03 00 01 03 00 ................ | 3280: 01 03 00 00 08 32 30 31 36 30 36 30 39 09 01 07 .....20160609... | 3296: 00 01 07 00 01 07 00 00 01 34 09 01 05 00 01 05 .........4...... | 3312: 00 01 05 00 00 01 35 09 01 04 00 01 04 00 02 04 ......5......... | 3328: 00 01 07 30 2f 30 30 30 30 30 09 1c 04 00 01 04 ...0/00000...... | 3344: 00 01 04 00 00 06 62 69 6e 61 72 79 3c 03 01 02 ......binary<... | 3360: 02 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 ................ | 3376: 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 00 ................ | 3392: 03 01 02 02 00 03 01 02 02 00 03 01 02 02 00 03 ................ | 3408: 01 02 02 00 03 01 02 02 00 00 08 63 6f 6d 70 69 ...........compi | 3424: 6c 65 72 09 01 02 00 01 02 00 01 02 00 00 06 64 ler............d | 3440: 62 73 74 61 74 09 07 03 00 01 03 00 01 03 00 01 bstat........... | 3456: 04 65 62 75 67 09 04 02 00 01 02 00 01 02 00 00 .ebug........... | 3472: 06 65 6e 61 6c 2c 65 3f 07 02 00 01 02 00 01 02 .enal,e?........ | 3488: 00 01 02 00 01 02 00 01 02 00 01 02 00 01 02 00 ................ | 3504: 01 02 00 01 02 00 01 02 00 01 01 ff f1 02 00 01 ................ | 3520: 02 00 01 02 00 01 02 00 f1 02 00 01 02 00 01 4f ...............O | 3536: 00 01 02 00 01 02 00 01 08 78 74 65 6e 73 69 6f .........xtensio | 3552: 6e 09 1f 04 00 01 04 00 01 04 00 00 04 66 74 73 n............fts | 3568: 34 09 0a 03 00 01 03 00 00 f3 00 03 01 35 09 0d 4............5.. | 3584: 03 00 01 04 00 01 03 00 00 03 67 63 63 09 01 03 ..........gcc... | 3600: 00 01 03 00 01 03 00 01 06 65 6f 70 6f 6c 79 09 .........eopoly. | 3616: 10 03 00 01 03 00 01 03 00 00 05 6a 73 6f 6e 31 ...........json1 | 3632: 09 13 03 00 01 02 ff 01 03 00 00 04 6c 6f 61 63 ............loac | 3648: 09 1f 03 00 01 03 00 01 03 00 00 03 6d 61 78 09 ............max. | 3664: 1c 02 00 01 02 00 01 02 00 01 05 64 6d 6f 72 79 ...........dmory | 3680: 09 1c 03 00 01 03 00 01 03 00 03 04 73 79 73 35 ............sys5 | 3696: 09 16 02 f0 01 03 00 01 03 00 00 06 6e 6f 63 61 ............noca | 3712: 73 65 3c 02 01 02 02 00 03 01 02 02 00 03 01 02 se<............. | 3728: 02 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 ................ | 3744: 00 03 01 02 02 00 03 01 02 02 00 4b 01 02 02 00 ...........K.... | 3760: 03 01 02 02 00 03 01 02 02 00 03 01 02 02 00 00 ................ | 3776: 04 6f 6d 69 74 09 1f 02 00 01 02 00 01 02 00 00 .omit........... | 3792: 05 72 74 72 65 65 09 19 03 00 01 03 00 01 03 00 .rtree.......... | 3808: 03 02 69 6d 3c 01 01 02 02 00 03 01 02 02 00 03 ..im<........... | 3824: 01 02 02 00 03 01 02 02 00 03 01 02 02 00 03 01 ................ | 3840: 02 02 00 03 01 02 02 00 03 01 02 02 00 03 01 02 ................ | 3856: 02 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 ................ | 3872: 00 00 0a 74 68 72 65 61 64 73 61 66 65 09 22 02 ...threadsafe... | 3888: 00 01 02 00 01 02 00 00 04 76 74 61 62 09 07 04 .........vtab... | 3904: 00 01 04 00 01 04 00 00 01 78 b4 01 01 01 01 02 .........x...... | 3920: 00 01 f4 01 02 00 01 02 01 02 00 01 01 01 02 ff ................ | 3936: 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 01 ................ | 3952: 01 01 02 ae 01 01 01 02 00 01 01 01 02 00 01 01 ................ | 3968: 01 12 00 01 01 01 02 00 01 01 01 02 00 01 01 01 ................ | 3984: 12 00 01 01 01 02 01 01 01 01 02 00 01 01 01 02 ................ | 4000: 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 ................ | 4016: 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 01 ................ | 4032: 01 01 02 00 01 01 01 02 00 01 01 01 02 00 01 01 ................ | 4048: 01 02 00 01 01 01 02 00 01 76 01 02 00 01 01 01 .........v...... | 4064: 02 00 01 01 01 02 01 01 01 01 02 00 01 01 01 02 ................ | 4080: 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 ................ | page 6 offset 20480 | 0: 0a 00 00 00 02 0f f5 00 0f fb 0f f5 00 00 00 00 ................ | 4080: 00 00 00 00 00 05 04 08 09 01 02 04 04 08 08 09 ................ | end crash-74fdbc96edbc04.db }]} {} do_catchsql_test 32.1 { UPDATE t1 SET b=quote(zeroblob(6.51158946e+5)) WHERE a MATCH '*t*'; } {1 {database disk image is malformed}} #do_catchsql_test 32.2 { # UPDATE t1 SET b=((- '' )) WHERE a MATCH '0*t'; #} {1 {database disk image is malformed}} #------------------------------------------------------------------------- # ifcapable icu { reset_db do_catchsql_test 33.0 { CREATE VIRTUAL TABLE f USING fts3(a,b,tokenize=icu); CREATE TABLE 'f_docsize'(docid INTEGER PRIMARY KEY, size BLOB); CREATE TABLE 'f_stat'(id INTEGER PRIMARY KEY, value BLOB); INSERT INTO f VALUES (1, '1234'); INSERT INTO f_stat VALUES (1,x'0000000165656565db6569746565c5c52bc5c5c53e3a003bc502ffffffffc5c5c53e3a003bc502fffffffffb8b2afbfb6565f0740100650000000165656565db6569746565c5c52bc5c5c53e3a003bc502ffffffffc5c5c53e3a003b8b00c5c5c5c5c5bfc5'); INSERT INTO f(f) VALUES ('merge=198,49'); } {1 {database disk image is malformed}} } #------------------------------------------------------------------------- # reset_db do_execsql_test 34.0 { CREATE VIRTUAL TABLE f USING fts3(a,b); INSERT INTO f VALUES (1, '1234'); INSERT INTO f_segdir VALUES (1,255,0,0,'1 255',x'00'); UPDATE f_segdir SET level = 0 WHERE level IN ( SELECT level FROM f_segdir LIMIT 1 OFFSET 1 ); INSERT INTO f_segdir VALUES (255,249,0,121,'0 0',x'00'); INSERT INTO f_content VALUES (255,0,x'ff'); INSERT INTO f_segdir VALUES (1,255,16,0,'1 255',x'00'); } do_catchsql_test 34.1 { UPDATE f SET b = x'00' WHERE b IN (SELECT b FROM f LIMIT 1 OFFSET 0); } {1 {database disk image is malformed}} #------------------------------------------------------------------------- # reset_db do_execsql_test 35.0 { CREATE VIRTUAL TABLE f USING fts3(a,b); INSERT INTO f_segdir VALUES (1,255,0,0,'1 255',x'0001ff000001ff000001ff000001ff000001ff00c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5bec5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5'); } do_catchsql_test 35.1 { INSERT INTO f(f) VALUES ('integrity-check'); } {1 {database disk image is malformed}} reset_db do_catchsql_test 36.0 { CREATE VIRTUAL TABLE f USING fts3(a,tokenize=porter); CREATE TABLE 'f_stat'(id INTEGER PRIMARY KEY, value BLOB); INSERT INTO f VALUES (1); INSERT INTO f_stat VALUES (1,x'00000000000101010119013d00ffff0400fa83717b71a69297979701f63d010101010101010101010101190000000000000000fa83717b71a601f63d01010101010101010101010119013d00ffffff0400fa83717b71a69297979701f63d010101010101010101010101190000000000000000fa83717b71a69201f63d010101f63d01010101010101010101010119013d00ffffff0400fa83717b71a6929797010101010101010101010119013d00ffff01f63d01010101010101010101010119013d00ffffff0400fa83717b71a69297979701f63d00fa03ffffffa69297979701f63d010101000000000101010101197e9797976567656565ffa63535354e'); INSERT INTO f(f) VALUES ('merge=53,216'); } {0 {}} #------------------------------------------------------------------------- # reset_db do_execsql_test 36.0 { CREATE VIRTUAL TABLE f USING fts3(a,b); CREATE TABLE 'f_stat'(id INTEGER PRIMARY KEY, value BLOB); INSERT INTO f_stat VALUES (1,x'11014101000101c5c5014b010164c5014b010101c50101c5c5010201010101014101000101c5c5014b010101c5014b010101c50101c5c501010100c50101c5c5010101010101e40201010101014101000201010101014101000101010201010101014101000101c5c503b5fefefe3afeffffc5c5c5c50101010101010201010101014101adadadadadadadadadadadad91adadadadadadadad0101c50101c5c501f9ffffffffffffffff0001010102010101010140f5000101c5c5014b010101c50101c5c501010101e6010201010101014101000101c5c5014b010101c50101c5c5010101114b0101c5c50101010a0101020101e60101'); } do_catchsql_test 36.1 { INSERT INTO f(f) VALUES ('merge=59,59'); } {1 {database disk image is malformed}} #------------------------------------------------------------------------- # reset_db do_execsql_test 37.0 { CREATE VIRTUAL TABLE f USING fts3(a,b); INSERT INTO f_segdir VALUES (28,0,0,0,'0 0',x'00'); INSERT INTO f_segdir VALUES (0,241,0,0,'0 0',x'0001000030310000f1'); } do_catchsql_test 37.1 { INSERT INTO f VALUES (0,x'00'); } {1 {database disk image is malformed}} #------------------------------------------------------------------------- # reset_db do_test 38.0 { sqlite3 db {} db deserialize [decode_hexdb { .open --hexdb | size 24576 pagesize 4096 filename crash-1cc4f8a70485ce.db | page 1 offset 0 | 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3. | 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 00 .....@ ........ | 96: 00 00 00 00 0d 0e b1 00 06 0d a4 00 0f 8d 0f 21 ...............! | 112: 0e b9 0d c8 0e 7e 0d a4 00 00 00 00 00 00 00 00 .....~.......... | 3488: 00 00 00 00 22 07 06 17 11 11 01 31 74 61 62 6c ...........1tabl | 3504: 65 74 32 74 32 07 43 52 45 41 54 45 20 54 41 42 et2t2.CREATE TAB | 3520: 4c 45 20 74 32 28 78 29 81 33 05 07 17 1f 1f 01 LE t2(x).3...... | 3536: 82 35 74 61 62 6c 65 74 31 5f 73 65 67 64 69 72 .5tablet1_segdir | 3552: 74 31 5f 73 65 67 64 69 72 05 43 52 45 41 54 45 t1_segdir.CREATE | 3568: 20 54 41 42 4c 45 20 27 74 31 5f 73 65 67 64 69 TABLE 't1_segdi | 3584: 72 27 28 6c 65 76 65 6c 20 49 4e 54 45 47 45 52 r'(level INTEGER | 3600: 2c 69 64 78 20 49 4e 54 45 47 45 52 2c 73 74 61 ,idx INTEGER,sta | 3616: 72 74 5f 62 6c 6f 63 6b 20 49 4e 54 45 47 45 52 rt_block INTEGER | 3632: 2c 6c 65 61 76 65 73 5f 65 6e 64 5f 62 6c 6f 63 ,leaves_end_bloc | 3648: 6b 20 49 4e 54 45 47 45 52 2c 65 6e 64 5f 62 6c k INTEGER,end_bl | 3664: 6f 63 6b 20 49 4e 54 45 47 45 62 2c 72 6f 6f 74 ock INTEGEb,root | 3680: 20 42 4c 4f 42 2c 50 52 49 4d 41 52 59 20 4b 45 BLOB,PRIMARY KE | 3696: 59 28 6c 65 76 65 6c 2c 20 69 64 78 29 29 31 06 Y(level, idx))1. | 3712: 06 17 45 1f 01 00 69 6e 64 65 78 73 71 6c 69 74 ..E...indexsqlit | 3728: 65 5f 61 75 74 6f 69 6e 64 65 78 5f 74 31 5f 73 e_autoindex_t1_s | 3744: 65 67 64 69 72 5f 31 74 31 5f 73 65 67 64 69 72 egdir_1t1_segdir | 3760: 06 0f c7 00 08 00 00 00 00 66 04 07 17 23 23 01 .........f...##. | 3776: 81 13 74 61 62 6c 65 74 31 5f 73 65 67 6d 65 6e ..tablet1_segmen | 3792: 74 73 74 31 5f 73 65 67 6d 65 6e 74 73 04 43 52 tst1_segments.CR | 3808: 45 41 54 45 20 54 41 42 4c 45 20 27 74 31 5f 73 EATE TABLE 't1_s | 3824: 65 67 6d 65 6e 74 73 27 28 62 6c 6f 63 6b 69 64 egments'(blockid | 3840: 20 49 4e 54 45 47 45 52 20 50 52 49 4d 41 52 59 INTEGER PRIMARY | 3856: 20 4b 45 59 2c 20 62 6c 6f 63 6b 20 42 4c 4f 42 KEY, block BLOB | 3872: 29 6a 03 07 17 21 21 01 81 1f 74 61 62 6c 65 74 )j...!!...tablet | 3888: 31 5f 63 6f 6e 74 65 6e 74 74 31 5f 63 6f 6e 74 1_contentt1_cont | 3904: 65 6e 74 03 43 52 45 41 54 45 20 54 41 42 4c 45 ent.CREATE TABLE | 3920: 20 27 74 31 5f 63 6f 6e 74 65 6e 74 27 28 64 6f 't1_content'(do | 3936: 63 69 64 20 49 4e 54 45 47 45 52 20 50 52 49 4d cid INTEGER PRIM | 3952: 41 52 59 20 4b 45 59 2c 20 27 63 30 61 27 2c 20 ARY KEY, 'c0a', | 3968: 27 63 31 62 27 2c 20 27 63 32 63 27 29 38 02 06 'c1b', 'c2c')8.. | 3984: 17 11 11 08 5f 74 61 62 6c 65 74 31 74 31 43 52 ...._tablet1t1CR | 4000: 45 41 54 45 20 56 49 52 54 55 41 4c 20 54 41 42 EATE VIRTUAL TAB | 4016: 4c 45 20 74 31 20 55 53 49 4e 47 20 66 74 73 33 LE t1 USING fts3 | 4032: 28 61 2c 62 2c 63 29 00 00 00 00 00 00 00 00 00 (a,b,c)......... | page 3 offset 8192 | 0: 0d 00 00 00 25 0b 48 00 0f d8 0f af 0f 86 0f 74 ....%.H........t | 16: 0f 61 0f 4e 0f 2f 0f 0f 0e ef 0e d7 0e be 0e a5 .a.N./.......... | 32: 0e 8d 0e 74 0e 5b 0e 40 0e 24 0e 08 0d ef 00 00 ...t.[.@.$...... | 2880: 00 00 00 00 00 00 00 00 81 3f 25 06 00 82 7e f0 .........?%...~. | 2896: 00 43 4f 4d 50 49 4c 45 52 3d 67 63 63 2d 35 2e .COMPILER=gcc-5. | 2912: 34 23 00 20 42 30 31 36 2f 36 30 39 20 44 45 42 4#. B016/609 DEB | 2928: 55 47 20 45 4e 41 42 4c 45 20 44 42 53 54 41 54 UG ENABLE DBSTAT | 2944: 20 56 54 41 42 20 45 4e 42 92 4c 45 20 46 54 53 VTAB ENB.LE FTS | 2960: 34 20 45 4e 41 42 4c 45 20 46 54 53 35 20 45 4e 4 ENABLE FTS5 EN | 2976: 41 42 4c 45 20 47 45 4f 50 4f 4c 59 20 45 4e 41 ABLE GEOPOLY ENA | 2992: 42 5c 45 1f 4a 53 4f 4e 31 20 45 4e 41 42 4c 45 B.E.JSON1 ENABLE | 3008: 20 4d 45 4d 53 59 53 35 20 45 4e 41 42 4c 45 20 MEMSYS5 ENABLE | 3024: 52 54 52 45 45 20 4d 41 58 20 4d 45 4d 4f 52 59 RTREE MAX MEMORY | 3040: 3d 35 30 30 30 30 30 30 30 20 4f 4d 49 54 20 4c =50000000 OMIT L | 3056: 4f 41 44 20 45 58 54 45 4e 53 49 4f 4e 20 54 48 OAD EXTENSION TH | 3072: 52 45 41 44 53 41 46 45 3d 30 18 24 05 00 25 0f READSAFE=0.$..%. | 3088: 19 54 48 52 45 41 44 53 41 46 45 3d 30 58 42 49 .THREADSAFE=0XBI | 3104: 4e 41 52 59 18 23 05 00 25 0f 19 54 48 52 45 41 NARY.#..%..THREA | 3120: 44 53 41 46 45 3d 30 88 4e 4f 43 41 53 45 17 22 DSAFE=0.NOCASE.. | 3136: 05 00 25 0f 17 54 48 52 45 41 44 53 41 46 45 3d ..%..THREADSAFE= | 3152: 30 58 52 54 52 49 4d 1f 21 05 00 33 0f 19 4f 4d 0XRTRIM.!..3..OM | 3168: 49 54 20 4c 4f 41 44 20 45 58 54 45 4e 53 49 4f IT LOAD EXTENSIO | 3184: 4e 58 42 49 4e 41 52 59 1f 20 05 00 33 0f 19 4f NXBINARY. ..3..O | 3200: 4d 49 54 20 4c 4f 41 44 20 45 58 54 45 4e 53 49 MIT LOAD EXTENSI | 3216: 4f 4e 58 4e 4f 43 41 53 45 1e 1f 05 00 33 0f 17 ONXNOCASE....3.. | 3232: 4f 4d 49 54 20 4c 4f 41 54 20 45 58 54 45 4e 53 OMIT LOAT EXTENS | 3248: 49 4f 4e 58 52 54 52 49 4d 1f 1e 04 00 33 0f 19 IONXRTRIM....3.. | 3264: 82 41 58 20 4d 45 4d 4f 52 59 3d 35 30 30 30 30 .AX MEMORY=50000 | 3280: 30 30 30 58 42 49 4e 41 52 59 1f 1d 05 00 33 0f 000XBINARY....3. | 3296: 19 4d 41 58 20 4d 45 4d 4f 52 59 3d 35 30 30 30 .MAX MEMORY=5000 | 3312: 30 30 30 30 58 4e 4f 43 41 53 45 1e 1c 05 00 33 0000XNOCASE....3 | 3328: 0f 17 4d 41 58 20 4d 45 4d fa 52 59 3d 35 30 20 ..MAX MEM.RY=50 | 3344: 30 30 30 30 30 58 52 54 52 49 4d 18 1b 05 00 25 00000XRTRIM....% | 3360: 0f 19 45 4e 41 42 4c 45 20 52 54 52 45 45 58 42 ..ENABLE RTREEXB | 3376: 49 4e 41 52 59 18 1a 05 00 25 0f 19 45 4e 41 42 INARY....%..ENAB | 3392: 4c 45 20 52 54 52 45 45 58 4e 4f 43 41 53 45 17 LE RTREEXNOCASE. | 3408: 19 05 00 25 0f 17 45 4e 42 42 4c 45 20 52 54 52 ...%..ENBBLE RTR | 3424: 45 45 58 52 54 52 49 4d 1a 18 05 00 29 0f 19 45 EEXRTRIM....)..E | 3440: 4e 41 42 4c 45 20 4d 45 4d 53 59 53 35 58 42 49 NABLE MEMSYS5XBI | 3456: 4e 41 52 59 1a 17 05 00 29 0f 19 45 4e 41 42 3c NARY....)..ENAB< | 3472: 45 20 4d 45 4d 53 59 53 35 58 4e 4f 43 41 53 45 E MEMSYS5XNOCASE | 3488: 19 16 05 00 29 0f 17 45 4e 41 42 4c 45 20 4d 45 ....)..ENABLE ME | 3504: 4d 53 59 53 35 58 52 54 52 49 4d 18 15 05 00 25 MSYS5XRTRIM....% | 3520: 0f 19 45 4e 41 42 4c 45 20 4a 53 4f 4e 31 58 42 ..ENABLE JSON1XB | 3536: 49 4e 41 52 59 18 14 05 00 25 0f 19 45 4e 41 42 INARY....%..ENAB | 3552: 4c 45 20 4a 53 4f 4e 31 58 4e 4f 43 41 53 45 17 LE JSON1XNOCASE. | 3568: 13 05 00 25 0f 17 45 4e 41 42 4c 45 20 4a 53 4f ...%..ENABLE JSO | 3584: 4e 31 58 52 54 52 49 4d 95 12 05 00 29 0f 19 45 N1XRTRIM....)..E | 3600: 4e 31 42 4c 45 20 47 45 4e 50 4f 4c 59 58 42 49 N1BLE GENPOLYXBI | 3616: 4e 41 52 59 1a 11 05 00 29 0f 19 45 3e f2 1e 4c NARY....)..E>..L | 3632: 45 20 47 45 4f 50 4f 4c 59 58 4e 4f 43 41 53 45 E GEOPOLYXNOCASE | 3648: 19 10 05 00 29 0f 17 45 4e 41 42 4c 45 20 47 45 ....)..ENABLE GE | 3664: 4f 50 4f 4c 59 58 52 54 52 49 4d 17 0f 05 00 23 OPOLYXRTRIM....# | 3680: 0f 19 45 4e 41 42 4c 45 20 46 54 53 35 58 42 49 ..ENABLE FTS5XBI | 3696: 4e 41 52 59 17 0e 05 00 23 0f 19 45 4e 41 42 3c NARY....#..ENAB< | 3712: 45 20 46 54 53 35 58 4e 4f 43 41 53 45 16 0d 05 E FTS5XNOCASE... | 3728: 00 23 0f 17 45 4e 41 42 4c 45 20 46 54 53 35 58 .#..ENABLE FTS5X | 3744: 5d 24 52 49 4d 17 0c 05 00 23 0f 19 45 4e 41 42 ]$RIM....#..ENAB | 3760: 4c 45 20 46 54 53 34 58 42 49 4e 41 52 59 17 0b LE FTS4XBINARY.. | 3776: 05 00 23 0f 19 45 4e 41 42 4c 45 20 46 54 53 35 ..#..ENABLE FTS5 | 3792: 58 4e 4f 43 40 53 45 16 0a 05 00 23 0f 17 45 4e XNOC@SE....#..EN | 3808: 41 42 4c 45 20 46 54 53 34 58 52 54 52 49 4d 1e ABLE FTS4XRTRIM. | 3824: 09 05 00 31 0f 19 45 4e 41 42 4c 45 20 44 42 53 ...1..ENABLE DBS | 3840: 54 41 54 20 56 54 41 42 58 42 49 4e 41 52 59 1e TAT VTABXBINARY. | 3856: 08 05 00 31 0f 19 45 4e 41 42 4c 45 20 44 42 53 ...1..ENABLE DBS | 3872: 54 41 54 20 56 54 41 42 58 4e 4f 43 41 53 45 1d TAT VTABXNOCASE. | 3888: 07 05 00 31 0f 17 45 4e 41 42 4b 45 20 44 42 53 ...1..ENABKE DBS | 3904: 54 41 54 20 56 53 41 42 58 52 54 62 49 4d 11 06 TAT VSABXRTbIM.. | 3920: 05 00 17 0f 19 44 45 42 54 47 58 42 49 4e 41 52 .....DEBTGXBINAR | 3936: 59 11 05 05 00 17 0f 19 44 45 42 55 47 58 4e 4f Y.......DEBUGXNO | 3952: 43 41 53 45 10 04 05 00 17 0f 17 44 45 42 55 47 CASE.......DEBUG | 3968: 68 52 54 52 49 4d 27 03 05 00 43 0f 19 43 4f 4d hRTRIM'...C..COM | 3984: 50 49 4c 45 52 3d 67 63 63 2d 35 2e 34 2e 30 20 PILER=gcc-5.4.0 | 4000: 32 30 31 36 30 36 30 39 58 42 49 4e 41 52 59 27 20160609XBINARY' | 4016: 02 05 00 43 0f 19 43 4f 4d 50 49 4c 45 52 3d 67 ...C..COMPILER=g | 4032: 63 63 2d 35 2e 34 2e 30 20 32 30 31 36 30 36 30 cc-5.4.0 2016060 | 4048: 39 58 4f 4f 43 41 53 45 26 01 05 00 43 0f 17 43 9XOOCASE&...C..C | 4064: 4f 4d 50 49 4c 45 52 3d 67 63 63 2d 35 2e 34 2e OMPILER=gcc-5.4. | 4080: 30 20 32 30 31 36 30 36 30 39 58 52 54 52 49 4d 0 20160609XRTRIM | page 4 offset 12288 | 0: 0d 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ | page 5 offset 16384 | 0: 0d 00 00 00 02 0b a0 00 0c ad 0b a0 00 00 00 00 ................ | 2976: 82 0a 02 08 08 09 08 08 17 84 06 30 20 32 35 33 ...........0 253 | 2992: 00 01 30 04 25 06 1b 00 00 08 32 30 31 36 8c 36 ..0.%.....2016.6 | 3008: 30 39 03 25 07 00 00 01 34 03 25 05 00 00 01 35 09.%....4.%....5 | 3024: 03 25 04 00 01 07 30 30 30 30 30 30 30 03 25 1a .%....0000000.%. | 3040: 00 00 08 63 6f 5d 70 69 6c 65 72 03 25 02 00 00 ...co]piler.%... | 3056: 06 64 62 73 74 61 74 03 25 0a 00 01 04 65 62 75 .dbstat.%....ebu | 3072: 67 03 25 08 00 00 06 65 6e 61 62 6c 65 09 25 09 g.%....enable.%. | 3088: 05 04 04 04 04 04 00 01 08 78 74 65 7e 73 69 6f .........xte~sio | 3104: 6e 03 25 1d 00 00 04 66 74 73 34 03 25 0d 00 03 n.%....fts4.%... | 3120: 01 35 03 25 0f 00 00 03 67 63 63 03 25 03 00 01 .5.%....gcc.%... | 3136: 06 65 6f 70 7f 6c 79 03 25 11 00 00 05 6a 73 6f .eop.ly.%....jso | 3152: 6e 31 03 25 14 00 e8 04 6c 6f 61 64 03 25 1c 00 n1.%....load.%.. | 3168: 00 03 6d 61 78 03 25 18 00 01 05 65 6d 6f 72 79 ..max.%....emory | 3184: 03 25 19 00 03 04 73 79 73 35 03 25 15 00 00 04 .%....sys5.%.... | 3200: 6f 6d 69 74 03 25 1b 00 00 05 72 74 72 65 65 03 omit.%....rtree. | 3216: 25 17 00 00 0a 74 68 72 65 61 64 73 61 66 65 03 %....threadsafe. | 3232: 25 1e 00 00 04 76 74 61 62 03 25 0b 00 86 50 01 %....vtab.%...P. | 3248: 08 08 08 08 08 17 8d 12 30 20 38 33 35 00 01 30 ........0 835..0 | 3264: 12 01 06 00 01 06 00 01 06 00 1f 03 00 01 03 00 ................ | 3280: 01 03 00 00 08 32 30 31 36 30 36 30 39 09 01 07 .....20160609... | 3296: 00 01 07 00 01 07 00 00 01 34 09 01 05 00 01 05 .........4...... | 3312: 00 01 05 00 00 01 35 09 01 04 00 01 04 00 01 04 ......5......... | 3328: 00 01 07 30 30 30 30 30 30 30 09 1c 04 00 01 04 ...0000000...... | 3344: 00 01 04 00 00 06 62 69 6e 61 72 79 3c 03 01 02 ......binary<... | 3360: 02 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 ................ | 3376: 00 03 01 02 c2 00 03 01 02 02 00 03 01 04 82 00 ................ | 3392: 03 01 02 02 00 03 01 02 02 00 03 01 02 02 00 03 ................ | 3408: 01 02 02 00 03 01 02 02 00 00 08 63 6f 6d 70 69 ...........compi | 3424: 6c 65 72 09 01 02 00 01 02 00 01 02 00 00 06 64 ler............d | 3440: 62 73 74 61 74 09 07 03 00 01 03 00 01 03 00 01 bstat........... | 3456: 04 65 62 75 67 09 04 02 00 01 02 00 01 02 00 00 .ebug........... | 3472: 06 65 6e 60 62 6c 65 3f 07 02 00 01 02 92 e1 a4 .en`ble?........ | 3488: ff fc a2 8c 95 b2 3f 01 01 f0 f1 02 00 57 02 00 ......?......W.. | 3504: 01 02 00 01 02 00 01 02 00 01 02 00 01 02 10 01 ................ | 3520: 02 00 01 02 00 01 02 00 01 02 01 01 02 00 01 02 ................ | 3536: 00 01 02 00 00 f2 00 01 08 78 74 65 6e 73 69 6f .........xtensio | 3552: 6e 09 1f 04 00 01 04 00 01 04 00 00 04 66 74 73 n............fts | 3568: 34 09 0a 03 00 01 03 00 01 03 00 03 01 35 09 0d 4............5.. | 3584: 03 00 01 03 00 01 03 00 00 03 67 63 63 09 01 03 ..........gcc... | 3600: 00 01 03 00 01 03 00 01 06 65 5f 70 6f 6c 79 09 .........e_poly. | 3616: 10 03 00 01 03 00 01 03 00 00 b3 6a 73 6f 6e 31 ...........json1 | 3632: 09 13 03 00 01 03 00 01 03 00 00 04 6c 6f 61 64 ............load | 3648: 09 1f 03 00 01 03 00 01 03 00 00 03 6d 61 78 09 ............max. | 3664: 1c 02 00 01 02 00 01 02 00 01 05 65 6d 6f 72 79 ...........emory | 3680: 09 1c 03 00 01 03 00 01 03 00 03 04 73 79 73 35 ............sys5 | 3696: 09 16 03 00 01 03 00 01 03 cc 00 06 6e 6f 63 61 ............noca | 3712: 73 65 3c 02 01 02 02 00 03 01 02 02 00 03 01 02 se<............. | 3728: 02 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 ................ | 3744: 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 00 ................ | 3760: 03 01 02 02 00 03 01 02 02 00 03 01 02 02 00 00 ................ | 3776: 04 6f 6d 69 74 09 1f 02 00 01 02 00 01 02 00 00 .omit........... | 3792: 05 72 74 62 65 65 09 19 03 00 01 03 00 01 03 00 .rtbee.......... | 3808: 03 02 69 6d 3c 01 01 02 02 00 03 01 02 02 00 03 ..im<........... | 3824: 01 02 02 00 03 01 02 02 00 03 01 02 02 00 03 01 ................ | 3840: 02 02 00 03 01 02 02 00 03 01 02 02 00 03 01 02 ................ | 3856: 02 00 03 01 02 02 00 03 01 02 01 00 03 01 02 02 ................ | 3872: 00 00 0a 74 68 72 65 61 64 73 61 66 65 09 22 02 ...threadsafe... | 3888: 00 01 02 00 02 02 00 00 04 76 74 61 62 09 07 04 .........vtab... | 3904: 00 01 03 00 01 04 00 00 01 78 b4 01 01 01 01 02 .........x...... | 3920: 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 ................ | 3936: 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 01 ................ | 3952: 01 01 02 00 01 01 01 02 00 01 01 01 02 00 01 01 ................ | 3968: 01 02 00 01 01 01 02 00 01 01 01 02 00 01 01 01 ................ | 3984: 02 01 01 01 01 02 00 01 01 01 02 00 01 01 01 02 ................ | 4000: 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 ................ | 4016: 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 01 ................ | 4032: 01 01 02 00 01 01 01 da 00 00 f1 01 02 00 01 01 ................ | 4048: 01 02 00 01 01 01 01 ff ff 01 01 02 00 01 01 01 ................ | 4064: 02 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 ................ | 4080: 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 ................ | page 6 offset 20480 | 0: 0a 00 00 00 02 0f f5 00 0f fb 0f f5 01 00 00 00 ................ | 4080: 00 00 00 00 00 05 04 08 09 01 02 04 04 08 08 09 ................ | end crash-1cc4f8a70485ce.db }]} {} do_execsql_test 38.1 { UPDATE t1 SET b=a; } do_catchsql_test 38.2 { SELECT b FROM t1 WHERE a MATCH 'e*e*e*e*e*e*e*e*e*e*e*e*e*e*e*e*' } {1 {database disk image is malformed}} #------------------------------------------------------------------------- reset_db set saved $sqlite_fts3_enable_parentheses set sqlite_fts3_enable_parentheses 1 do_execsql_test 39.0 { CREATE VIRTUAL TABLE t0 USING fts3( col0 INTEGER PRIMARY KEY, col1 VARCHAR(8), col2 BINARY, col3 BINARY ); INSERT INTO t0_content VALUES(1,1,'1234','aaaa','bbbb'); INSERT INTO t0_segdir VALUES(0,0,0,0,'0 42',X'000131030782000103323334050101010200000461616161050101020200000462626262050101030200'); } do_test 39.1 { catch { db eval { SELECT rowid FROM t0 WHERE t0 MATCH '1 NEAR 1' } } } 0 do_test 39.2 { catch { db eval { SELECT matchinfo(t0,'yxy') FROM t0 WHERE t0 MATCH x'2b0a312b0a312a312a2a0b5d0a0b0b0a312a0a0b0b0a312a0b310a392a0b0a27312a2a0b5d0a312a0b310a31315d0b310a312a316d2a0b313b15bceaa50a312a0b0a27312a2a0b5d0a312a0b310a312b0b2a310a312a0b2a0b2a0b2e5d0a0bff313336e34a2a312a0b0a3c310b0a0b4b4b0b4b2a4bec40322b2a0b310a0a312a0a0a0a0a0a0a0a0a0b310a312a2a2a0b5d0a0b0b0a312a0b310a312a0b0a4e4541530b310a5df5ced70a0a0a0a0a4f520a0a0a0a0a0a0a312a0b0a4e4541520b310a5d616161610a0a0a0a4f520a0a0a0a0a0a312b0a312a312a0a0a0a0a0a0a004a0b0a310b220a0b0a310a4a22310a0b0a7e6fe0e0e030e0e0e0e0e01176e02000e0e0e0e0e01131320226310a0b0a310a4a22310a0b0a310a766f8b8b4ee0e0300ae0090909090909090909090909090909090909090909090909090909090909090947aaaa540b09090909090909090909090909090909090909090909090909090909090909fae0e0f2f22164e0e0f273e07fefefef7d6dfafafafa6d6d6d6d'; } } } 0 set sqlite_fts3_enable_parentheses $saved #------------------------------------------------------------------------- reset_db set saved $sqlite_fts3_enable_parentheses set sqlite_fts3_enable_parentheses 1 do_execsql_test 40.1 { CREATE VIRTUAL TABLE t0 USING fts3(col0 INTEGER PRIMARY KEY, col1, col2 ,col3 ); INSERT INTO t0_segdir VALUES(0,0,0,0,'0 42', X'0001310301020001033233340500010102000004616161bc050101020200000462626262050101030200' ); } do_execsql_test 40.2 { SELECT 0==matchinfo(t0,'sx') FROM t0 WHERE t0 MATCH '1* 2 3 4 5 6 OR 1'; } 0 set sqlite_fts3_enable_parentheses $saved #------------------------------------------------------------------------- reset_db do_execsql_test 41.1 { CREATE VIRTUAL TABLE t1 USING fts3(a,b,c); INSERT INTO t1_segdir VALUES(0,0,0,0,'0 835',X'000130120106000106000106001f030001030001030000083230313630363039090107000107000107000001340901050001050001050000013509010400010400010400010730303030303030091c0400010400010400000662696e6172793c0301020200030102020003010202000301020200030102020003010202000301020200030102020003010202000301020200030102020003010202000008636f3870696c657209010200010200010200000664627374617409070300010300010300010465627567090402000102000102000006656e61626c653f07020001020001020001020001020001020001020001020001020001030001010002020001020001020001020001120001020001020001020001020001020001087874656e73696f6e091f0400010400010400000466747334090a0300010300010400030135090d03000103000103000003676363090103000103000103000106656f706f6c790910030001030001030000056a736f6e310913030001030001030000046c6f6164091f030001030001030000036d6178091c02000102000102000105656d6f7279091c03000103000103000304737973350916030001030001030000066e6f636173653c02010202000301020200030102020003010202000301020200030102020003010202000301020200030102020003010202000301020200030102020000046f6d6974091f020001020001020000057274726565091903000103000103000302696d3c010102020003010202000301020200030102020003010202000301020200030102020003010202000301020200030102020003010202000301020200000a746872656164736166650922020001020001020000047674616209070400010400010400000178b401010101020001010102000101010200010101020001010102000101010200010101020001010102000101010200010101020001010102000101010200010101020001010102000101010200010101020001010102000101010200010101020001010102000101010200010101020001010102000101010200010101020001010102000101010200010101020001010102000101010200010101020001010102000101010200010101020001010102000101010200'); } do_execsql_test 41.2 { SELECT offsets(t1) FROM t1 WHERE t1 MATCH 'rtree ner "json1^enable"'; } #------------------------------------------------------------------------- do_execsql_test 42.1 { CREATE VIRTUAL TABLE f USING fts3(a, b); } do_execsql_test 42.2 { INSERT INTO f_segdir VALUES(0,2,1111,0,0,X'00'); INSERT INTO f_segdir VALUES(0,3,0 ,0,0,X'00013003010200'); } do_execsql_test 42.3 { INSERT INTO f(f) VALUES ('merge=107,2'); } #------------------------------------------------------------------------- reset_db set saved $sqlite_fts3_enable_parentheses set sqlite_fts3_enable_parentheses 1 do_execsql_test 43.1 { CREATE VIRTUAL TABLE def USING fts3(xyz); INSERT INTO def_segdir VALUES(0,0,0,0,0, X'0001310301c9000103323334050d81'); } {} do_execsql_test 43.2 { SELECT rowid FROM def WHERE def MATCH '1 NEAR 1' } {1} set sqlite_fts3_enable_parentheses $saved #------------------------------------------------------------------------- reset_db do_execsql_test 44.1 { CREATE VIRTUAL TABLE t0 USING fts3(col0 INTEGER PRIMARY KEY,col1 VARCHAR(8),col2 BINARY,col3 BINARY); INSERT INTO t0_content VALUES(0,NULL,NULL,NULL,NULL); INSERT INTO t0_segdir VALUES(0,0,0,0,'0 42',X'00013103010200010332333405010201ba00000461616161050101020200000462626262050101030200'); } do_execsql_test 44.2 { SELECT matchinfo(t0, t0) IS NULL FROM t0 WHERE t0 MATCH '1*' } {0} #------------------------------------------------------------------------- # reset_db do_test 45.0 { sqlite3 db {} db deserialize [decode_hexdb { .open --hexdb | size 24576 pagesize 4096 filename crash-65c98512cc9e49.db | page 1 offset 0 | 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3. | 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 06 .....@ ........ | 96: 00 00 00 00 0d 0e fc 00 06 0d bc 00 0f ca 0f 6c ...............l | 112: 0f 04 0e 13 0e c9 0d bc 00 00 00 00 00 00 00 00 ................ | 3504: 00 00 00 00 00 00 00 00 00 00 00 00 55 06 07 17 ............U... | 3520: 1b 1b 01 81 01 74 61 62 6c 65 78 31 5f 73 74 61 .....tablex1_sta | 3536: 74 78 31 5f 73 74 61 74 06 43 52 45 41 54 45 20 tx1_stat.CREATE | 3552: 54 41 42 4c 45 20 27 78 31 5f 73 74 61 74 27 28 TABLE 'x1_stat'( | 3568: 69 64 20 49 4e 54 45 47 45 52 20 50 52 49 4d 41 id INTEGER PRIMA | 3584: 52 59 20 4b 45 59 2c 20 76 61 6c 75 65 20 42 4c RY KEY, value BL | 3600: 41 82 29 81 33 04 07 17 1f 1f 01 82 35 74 61 62 A.).3.......5tab | 3616: 6c 65 78 31 5f 73 65 67 64 69 72 78 31 5f 73 65 lex1_segdirx1_se | 3632: 67 64 69 72 04 43 52 45 41 54 45 20 54 41 42 4c gdir.CREATE TABL | 3648: 45 20 27 78 31 5f 73 65 67 64 69 72 27 28 6c 65 E 'x1_segdir'(le | 3664: 76 65 6c 20 49 4e 54 45 47 45 52 2c 69 64 78 20 vel INTEGER,idx | 3680: 49 4e 54 45 47 45 52 2c 73 74 61 72 74 5f 62 6c INTEGER,start_bl | 3696: 6f 63 6b 20 49 4e 54 45 47 45 52 2c 6c 65 61 76 ock INTEGER,leav | 3712: 65 73 5f 65 6e 64 5f 62 6c 6f 63 6b 20 49 4e 54 es_end_block INT | 3728: 45 47 45 52 2c 65 6e 64 5f 62 6c 6f 63 6b 20 49 EGER,end_block I | 3744: 4e 54 45 47 45 52 2c 72 6f 6f 74 20 42 4c 4f 42 NTEGER,root BLOB | 3760: 2c 50 52 49 4d 41 52 59 20 4b 45 59 28 6c 65 76 ,PRIMARY KEY(lev | 3776: 65 6c 2c 20 69 64 78 29 29 31 05 06 17 45 1f 01 el, idx))1...E.. | 3792: 00 69 6e 64 65 78 73 71 6c 69 74 65 5f 61 75 74 .indexsqlite_aut | 3808: 6f 69 6e 64 65 78 5f 78 31 5f 73 65 67 64 69 72 oindex_x1_segdir | 3824: 5f 31 78 31 5f 73 65 67 64 69 72 05 00 00 00 08 _1x1_segdir..... | 3840: 60 00 00 00 66 03 07 17 23 23 01 81 13 74 61 62 `...f...##...tab | 3856: 6c 65 78 31 5f 73 65 67 6d 65 6e 74 73 78 31 5f lex1_segmentsx1_ | 3872: 73 65 67 6d 65 6e 74 73 03 43 52 45 41 54 45 20 segments.CREATE | 3888: 54 41 42 4c 45 20 27 78 31 5f 73 65 67 6d 65 6e TABLE 'x1_segmen | 3904: 74 73 27 28 62 6c 6f 63 6b 69 64 20 49 4e 54 45 ts'(blockid INTE | 3920: 47 45 52 20 50 52 49 4d 41 52 59 20 4b 45 59 2c GER PRIMARY KEY, | 3936: 20 62 6c 6f 63 6b 20 42 4c 4f 42 29 5c 02 07 17 block BLOB).... | 3952: 21 21 01 81 03 74 61 62 6c 65 78 31 5f 63 6f 6e !!...tablex1_con | 3968: 74 65 6e 74 78 31 5f 63 6f 6e 74 65 6e 74 02 43 tentx1_content.C | 3984: 52 45 41 54 45 20 54 41 42 4c 45 20 27 78 31 5f REATE TABLE 'x1_ | 4000: 63 6f 6e 74 65 6e 74 27 28 64 6f 63 69 64 20 49 content'(docid I | 4016: 4e 54 45 47 45 52 20 50 52 49 4d 41 52 59 20 4b NTEGER PRIMARY K | 4032: 45 59 2c 20 27 63 30 78 27 29 34 01 06 17 11 11 EY, 'c0x')4..... | 4048: 08 57 74 61 62 6c 65 78 31 78 31 43 52 45 41 54 .Wtablex1x1CREAT | 4064: 45 20 56 49 52 54 55 41 4c 20 54 41 42 4c 45 20 E VIRTUAL TABLE | 4080: 78 31 20 55 53 49 4e 47 20 66 74 73 33 28 78 29 x1 USING fts3(x) | page 2 offset 4096 | 0: 0d 00 00 00 11 0f 77 f0 0f f8 0f f0 0f e8 0f e0 ......w......... | 16: 0f d8 0f d0 0f c8 0f c0 00 00 00 00 00 00 00 00 ................ | 3952: 00 00 00 00 00 00 00 00 06 11 03 00 13 77 78 79 .............wxy | 3968: 06 10 03 00 13 74 75 76 06 0f 03 00 13 71 33 73 .....tuv.....q3s | 3984: 06 0e 03 00 13 6e 6f 70 06 0d 03 00 13 6b 6c 6d .....nop.....klm | 4000: 06 0c 03 04 c3 68 69 6a 06 0b 03 00 13 65 66 67 .....hij.....efg | 4016: 06 0a 03 00 13 62 63 64 06 09 03 00 13 79 7a 61 .....bcd.....yza | 4032: 06 08 03 00 13 76 77 78 06 07 03 00 13 73 74 75 .....vwx.....stu | 4048: 06 06 03 00 13 70 71 72 06 05 03 00 13 6d 6e 6f .....pqr.....mno | 4064: 06 03 03 00 13 6a 6b 6c 06 03 03 00 13 67 68 69 .....jkl.....ghi | 4080: 06 02 02 00 03 64 65 66 06 01 03 00 13 61 52 63 .....def.....aRc | page 3 offset 8192 | 0: 0d 00 00 00 03 0f a7 00 0f b5 0f a7 0f fa 01 00 ................ | 4000: 00 00 00 00 00 00 00 0c 02 03 00 1e 00 03 6b 6c ..............kl | 4016: 6d 03 0d 02 00 43 01 04 00 81 0a 00 03 61 62 63 m....C.......abc | 4032: 03 0b 32 00 00 03 62 63 64 03 0a 02 00 00 03 64 ..2...bcd......d | 4048: 69 26 03 02 02 00 00 03 65 66 67 03 0b 02 00 00 i&......efg..... | 4064: 03 67 68 69 03 03 02 00 00 03 68 69 6a 03 0c 02 .ghi......hij... | 4080: 00 00 03 6a 6a 2c 03 04 02 00 03 81 00 03 00 00 ...jj,.......... | page 4 offset 12288 | 0: 0d 0f 3a 00 05 0f 25 00 0f 9e 0f 88 0f 43 0f 25 ..:...%......C.% | 16: 0f 72 00 00 00 00 00 00 00 00 00 00 00 00 00 00 .r.............. | 3856: 00 00 00 00 00 00 00 00 00 56 01 08 08 13 1e 03 .........V...... | 3872: 30 20 39 00 03 13 05 07 08 08 18 08 13 1e 30 20 0 9...........0 | 3888: 39 00 03 77 78 79 03 11 02 00 0f 6c 00 09 01 08 9..wxy.....l.... | 3904: 08 15 54 27 04 07 09 01 08 08 15 42 02 30 20 33 ..T'.......B.0 3 | 3920: 36 00 03 6e 6f 70 03 0e 02 00 00 03 71 72 73 03 6..nop......qrs. | 3936: 0f 02 00 00 03 74 75 76 03 10 02 00 0f cf b1 06 .....tuv........ | 3952: 01 08 14 06 07 01 08 09 01 1b 14 02 02 31 32 38 .............128 | 3968: 20 2d 37 32 10 01 01 6b 14 03 07 09 09 08 08 15 -72...k........ | 3984: 1e 30 20 33 36 00 03 79 7a 61 03 09 02 00 2f 02 .0 36..yza..../. | 4000: 07 09 08 08 08 15 54 30 20 33 36 00 03 6d 6e 6f ......T0 36..mno | 4016: 03 05 02 00 00 03 70 71 72 03 06 02 00 00 03 73 ......pqr......s | 4032: 74 75 03 07 02 00 00 03 76 77 78 03 08 02 00 00 tu......vwx..... | 4048: 00 00 4a 08 08 08 15 54 30 20 33 36 00 03 61 62 ..J....T0 36..ab | 4064: 63 03 01 02 00 00 03 64 65 66 03 02 02 00 00 03 c......def...... | 4080: 67 68 69 03 03 67 00 00 03 6a 6b 6c 03 04 02 00 ghi..g...jkl.... | page 5 offset 16384 | 0: 0a 0f e7 00 05 0f da 00 0f e1 0f fa 0f f4 0f ed ................ | 16: 0f da 0f 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ | 4048: 00 00 00 00 00 00 00 1a 01 03 06 04 01 08 01 02 ................ | 4064: 06 05 04 08 08 01 05 00 00 00 06 01 03 06 04 09 ................ | 4080: 02 01 02 04 05 04 09 09 01 03 05 04 09 08 01 02 ................ | page 6 offset 20480 | 0: 0d 00 10 00 01 0f f9 00 0f f9 00 00 00 00 00 00 ................ | 4080: 00 00 00 00 00 00 00 00 00 05 01 03 00 10 01 03 ................ | end crash-65c98512cc9e49.db }]} {} do_catchsql_test 45.2 { INSERT INTO x1(x1) VALUES( 'merge=1' ) } {1 {database disk image is malformed}} #------------------------------------------------------------------------- reset_db set saved $sqlite_fts3_enable_parentheses set sqlite_fts3_enable_parentheses 1 do_execsql_test 46.1 { CREATE VIRTUAL TABLE t0 USING fts3(a INTEGER PRIMARY KEY,b,c,d); INSERT INTO t0_segdir VALUES(0,0,0,0,'0 42',X'0001310301c9000103323334050d8000f200000461616161050101020200000462626262050101030200'); } {} do_catchsql_test 46.2 { SELECT * FROM t0 WHERE t0 MATCH x'2b0a312b0a312a312a2a0b5d0a0b0b0a312a0a0b0b0a312a0b310a392a0b0a27312a2a0b5d0a312a0b310a31315d0b310a312a316d2a0b313b15bceaa50a312a0b0a27312a2a0b5d0a312a0b310a312b0b2a310a312a0b2a0b2a0b2e5d0a0bff313336e34a2a312a0b0a3c310b0a0b4b4b0b4b2a4bec40322b2a0b310a0a312a0a0a0a0a0a0a0a0a0b310a312a2a2a0b5d0a0b0b0a312a0b310a312a0b0a4e4541530b310a5df5ced70a0a0a0a0a4f520a0a0a0a0a0a0a312a0b0a4e4541520b310a5d616161610a0a0a0a4f520a0a0a0a0a0a312b0a312a312a0a0a0a0a0a0a004a0b0a310b220a0b0a310a4a22310a0b0a7e6fe0e0e030e0e0e0e0e01176e02000e0e0e0e0e01131320226310a0b0a310a4a22310a0b0a310a766f8b8b4ee0e0300ae0090909090909090909090909090909090909090909090909090909090909090947aaaa540b09090909090909090909090909090909090909090909090909090909090909fae0e0f2f22164e0e0f273e07fefefef7d6dfafafafa6d6d6d6d'; } {1 {database disk image is malformed}} set sqlite_fts3_enable_parentheses $saved extra_schema_checks 1 #------------------------------------------------------------------------- reset_db do_execsql_test 47.1 { CREATE VIRTUAL TABLE t1 USING fts3(a,b,c); } do_execsql_test 47.2 { INSERT INTO t1_segdir VALUES(0,0,0,0,0,X'000130120106000106000106001f030001030001030000083230313630363039090107000107000107000001340901050001050001050000013509010400010400010400010730303030303030091c0400010400010400000662696e6172793c0301020200030102020003010202000301020200030102020003010202000301020200030102020003010202000301020200030102020003010202000008636f6d70696c657209010200010200010200000664627374617409070300010300010300010465627567090402000102000102000006656e61626c653f07020001020001020001020001020001020001020001020001020001020001020001020001010001020001020001020001020001020001020001020001020001087874656e73696f6e091f0400010400010400000466747334090a0300010300010300030135090d03000103000103000003676363090103000103000103000106656f706f6c790910030001030001030000056a736f6e310913030001030001030000046c6f6164091f030001030001030000036d6178091c02000102000102000105656d6f7279091c03000103000103000304737973350916030001030001030000066e6f636173653c02010202000301020200030102020003010202000301020200030102020003010202000301020200030102020003010202000301020200030102020000046f6d6974091f020001020001020000057274726565091903000103000103000302696d3c01010202000301020200030102020003010202000301020200030102020003010202000301a202000301020200030102020003010202000301020200000a746872656164736166650922020001020001020000047674616209070400010400010400000178b401010101020001010102000101010200010101020001010102000101010200010101020001010102000101010200010101020001010102000101010200010101020001010102000101010200010101020001010102000101010200010101020001010102000101010200010101020001010102000101010200010101020001010102000101010200010101020001010102000101010200010101020001010102000101010200010101020001010102000101010200'); INSERT INTO t1_segdir VALUES(0,1,0,0,0,X'0001300425061b000008323031363036303903250700000134032505000001350325040001073030303030303003251a000008636f6d70696c657203250200000664627374617403250a00010465627567032508000006656e61626c650925090504040404040001087874656e73696f6e03251d0000046674733403250d0003013503250f000003676363032503000106656f706f6c790325110000056a736f6e310325130000046c6f616403251c0000036d6178032518000105656d6f7279032519000304737973350325150000046f6d697403251b000005727472656503251700000a7468726561647361666503251e0000047674616333250b00'); } do_catchsql_test 47.3 { SELECT matchinfo(t1) FROM t1 WHERE t1 MATCH '"json1 enable"'; } {1 {database disk image is malformed}} #------------------------------------------------------------------------- # reset_db do_test 48.0 { sqlite3 db {} db deserialize [decode_hexdb { .open --hexdb | size 20480 pagesize 4096 filename sql038051.txt.db | page 1 offset 0 | 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3. | 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 00 .....@ ........ | 96: 00 00 00 00 0d 0e fc 00 05 0e 13 00 0f ca 0f 6c ...............l | 112: 0f 04 0e 13 0e c9 00 00 00 00 00 00 00 00 00 00 ................ | 3600: 00 00 00 81 33 04 07 17 1f 1f 01 82 35 74 61 62 ....3.......5tab | 3616: 6c 65 78 31 5f 73 65 67 64 69 72 78 31 5f 73 65 lex1_segdirx1_se | 3632: 67 64 69 72 04 43 52 45 41 54 45 20 54 41 42 4c gdir.CREATE TABL | 3648: 45 20 27 78 31 5f 73 65 67 64 69 72 27 28 6c 65 E 'x1_segdir'(le | 3664: 76 65 6c 20 49 4e 54 45 47 45 52 2c 69 64 78 20 vel INTEGER,idx | 3680: 49 4e 54 45 47 45 52 2c 73 74 61 72 74 5f 62 6c INTEGER,start_bl | 3696: 6f 63 6b 20 49 4e 54 45 47 45 52 2c 6c 65 61 76 ock INTEGER,leav | 3712: 65 73 5f 65 6e 64 5f 62 6c 6f 63 6b 20 49 4e 54 es_end_block INT | 3728: 45 47 45 52 2c 65 6e 64 5f 62 6c 6f 63 6b 20 49 EGER,end_block I | 3744: 4e 54 45 47 45 52 2c 72 6f 6f 74 20 42 4c 4f 42 NTEGER,root BLOB | 3760: 2c 50 52 49 4d 41 52 59 20 4b 45 59 28 6c 65 76 ,PRIMARY KEY(lev | 3776: 65 6c 2c 20 69 64 78 29 29 31 05 06 17 45 1f 01 el, idx))1...E.. | 3792: 00 69 6e 64 65 78 73 71 6c 69 74 65 5f 61 75 74 .indexsqlite_aut | 3808: 6f 69 6e 64 65 78 5f 78 31 5f 73 65 67 64 69 72 oindex_x1_segdir | 3824: 5f 31 78 31 5f 73 65 67 64 69 72 05 00 00 00 08 _1x1_segdir..... | 3840: 00 00 00 00 66 03 07 17 23 23 01 81 13 74 61 62 ....f...##...tab | 3856: 6c 65 78 31 5f 73 65 67 6d 65 6e 74 73 78 31 5f lex1_segmentsx1_ | 3872: 73 65 67 6d 65 6e 74 73 03 43 52 45 41 54 45 20 segments.CREATE | 3888: 54 41 42 4c 45 20 27 78 31 5f 73 65 67 6d 65 6e TABLE 'x1_segmen | 3904: 74 73 27 28 62 6c 6f 63 6b 69 64 20 49 4e 54 45 ts'(blockid INTE | 3920: 47 45 52 20 50 52 49 4d 41 52 59 20 4b 45 59 2c GER PRIMARY KEY, | 3936: 20 62 6c 6f 63 6b 20 42 4c 4f 42 29 5c 02 07 17 block BLOB).... | 3952: 21 21 01 81 03 74 61 62 6c 65 78 31 5f 63 6f 6e !!...tablex1_con | 3968: 74 65 6e 74 78 31 5f 63 6f 6e 74 65 6e 74 02 43 tentx1_content.C | 3984: 52 45 41 54 45 20 54 41 42 4c 45 20 27 78 31 5f REATE TABLE 'x1_ | 4000: 63 6f 6e 74 65 6e 74 27 28 64 6f 63 69 64 20 49 content'(docid I | 4016: 4e 54 45 47 45 52 20 50 52 49 4d 41 52 59 20 4b NTEGER PRIMARY K | 4032: 45 59 2c 20 27 63 30 78 27 29 34 01 06 17 11 11 EY, 'c0x')4..... | 4048: 08 57 74 61 62 6c 65 78 31 78 31 43 52 45 41 54 .Wtablex1x1CREAT | 4064: 45 20 56 49 52 54 55 41 4c 20 54 41 42 4c 45 20 E VIRTUAL TABLE | 4080: 78 31 20 55 53 49 4e 47 20 66 74 73 33 28 78 29 x1 USING fts3(x) | page 2 offset 4096 | 0: 0d 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ | 3920: 00 00 00 2e 04 03 00 63 62 72 61 69 6e 73 74 65 .......cbrainste | 3936: 6d 20 62 72 61 69 6e 73 74 65 6d 73 20 62 72 61 m brainstems bra | 3952: 69 6e 73 74 6f 72 6d 20 62 72 61 69 6e 73 74 6f instorm brainsto | 3968: 72 6d 73 2b 03 03 00 5d 62 72 61 69 6e 20 62 72 rms+...]brain br | 3984: 61 69 6e 63 68 69 6c 64 20 62 72 61 69 6e 65 64 ainchild brained | 4000: 20 62 72 61 69 6e 69 6e 67 20 62 72 61 69 6e 73 braining brains | 4016: 26 02 03 00 53 62 72 61 67 73 20 62 72 61 69 64 &...Sbrags braid | 4032: 20 62 72 61 69 64 65 64 20 62 72 61 69 64 69 6e braided braidin | 4048: 67 20 62 72 61 69 64 73 26 01 03 00 53 62 72 61 g braids&...Sbra | 4064: 65 73 20 62 72 61 67 20 62 72 61 67 67 65 64 20 es brag bragged | 4080: 62 72 61 c3 67 65 72 20 62 72 61 67 67 69 6e 67 bra.ger bragging | page 3 offset 8192 | 0: 0d 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 ................ | page 4 offset 12288 | 0: 0d 00 00 00 04 0f 20 00 0f c8 0f 90 0f 54 0f 20 ...... ......T. | 3872: 32 04 07 08 01 08 08 15 58 03 30 20 33 38 00 09 2.......X.0 38.. | 3888: 62 72 61 69 6e 73 74 65 6d 03 04 02 00 09 01 73 brainstem......s | 3904: 03 04 03 00 07 03 6f 72 6d 03 04 04 00 0a 01 73 ......orm......s | 3920: 03 04 05 00 3a 03 07 08 01 08 08 15 68 02 30 20 ....:.......h.0 | 3936: 34 36 00 05 62 72 61 69 6e 03 03 02 00 05 05 63 46..brain......c | 3952: 68 69 6c 64 03 03 03 00 05 02 65 64 03 03 04 00 hild......ed.... | 3968: 05 03 69 6e 67 03 03 05 00 05 01 73 03 03 06 00 ..ing......s.... | 3984: 36 02 07 08 09 08 08 15 62 30 20 34 33 00 05 62 6.......b0 43..b | 4000: 72 61 67 73 03 02 02 00 03 02 69 64 03 02 03 00 rags......id.... | 4016: 05 02 65 64 03 02 04 00 05 03 69 6e 67 03 02 05 ..ed......ing... | 4032: 00 05 01 73 03 02 06 00 36 01 07 08 08 08 08 15 ...s....6....... | 4048: 62 30 20 34 33 00 05 62 72 61 65 73 03 01 02 00 b0 43..braes.... | 4064: 03 01 68 03 01 03 00 04 03 67 65 74 03 01 04 00 ..h......get.... | 4080: 06 01 72 03 01 05 00 05 03 69 6e 67 03 01 06 00 ..r......ing.... | page 5 offset 16384 | 0: 0a 00 00 00 04 0f e7 00 0f fb 0f f5 0f ee 0f e7 ................ | 4064: 00 00 00 00 00 00 00 06 04 08 01 01 03 04 06 04 ................ | 4080: 08 01 01 02 03 05 04 08 09 01 02 04 04 08 08 09 ................ | end sql038051.txt.db }]} {} do_catchsql_test 48.1 { INSERT INTO x1(x1) VALUES('nodesize=24'),('merge=3,4'); INSERT INTO x1(x1) VALUES( 'merge=3,4' ),('merge=3,4'); } {1 {database disk image is malformed}} #------------------------------------------------------------------------- # reset_db do_test 49.0 { sqlite3 db {} db deserialize [decode_hexdb { .open --hexdb | size 28672 pagesize 4096 filename crash-58821b8eae6883.db | page 1 offset 0 | 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3. | 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 07 .....@ ........ | 32: 00 00 00 00 00 00 00 00 00 00 00 06 00 00 00 04 ................ | 96: 00 00 00 00 0d 0e ef 00 07 0d 4d 00 0f bd 0f 5f ..........M...._ | 112: 0e f7 0e 06 0e bc 0d a4 0d 4d 00 00 00 00 00 00 .........M...... | 3392: 00 00 00 00 00 00 00 00 00 00 00 00 00 55 07 07 .............U.. | 3408: 17 1b 1b 01 81 01 74 61 62 6c 65 74 31 5f 73 74 ......tablet1_st | 3424: 61 74 74 31 5f 73 74 61 74 07 43 52 45 41 54 45 att1_stat.CREATE | 3440: 20 54 41 42 4c 45 20 27 74 31 5f 73 74 61 74 27 TABLE 't1_stat' | 3456: 28 69 64 20 49 4e 54 45 47 45 52 20 50 52 49 4d (id INTEGER PRIM | 3472: 41 52 59 20 4b 45 59 2c 20 76 61 6c 75 65 20 42 ARY KEY, value B | 3488: 4c 4f 42 29 60 06 07 17 21 21 01 81 0b 74 61 62 LOB)`...!!...tab | 3504: 6c 65 74 31 5f 64 6f 63 73 69 7a 65 74 31 5f 64 let1_docsizet1_d | 3520: 6f 63 73 69 7a 65 06 43 52 45 41 54 45 20 54 41 ocsize.CREATE TA | 3536: 42 4c 45 20 27 74 31 5f 64 6f 63 73 69 7a 65 27 BLE 't1_docsize' | 3552: 28 64 6f 63 69 64 20 49 4e 54 45 47 45 52 20 50 (docid INTEGER P | 3568: 52 49 4d 41 52 59 20 4b 45 59 2c 20 73 69 7a 65 RIMARY KEY, size | 3584: 20 42 4c 4f 42 29 81 33 04 07 17 1f 1f 01 82 35 BLOB).3.......5 | 3600: 74 61 62 6c 65 74 31 5f 73 65 67 64 69 72 74 31 tablet1_segdirt1 | 3616: 5f 73 65 67 64 69 72 04 43 52 45 41 54 45 20 54 _segdir.CREATE T | 3632: 41 42 4c 45 20 27 74 31 5f 73 65 67 64 69 72 27 ABLE 't1_segdir' | 3648: 28 6c 65 76 65 6c 20 49 4e 54 45 47 45 52 2c 69 (level INTEGER,i | 3664: 64 78 20 49 4e 54 45 47 45 52 2c 73 74 61 72 74 dx INTEGER,start | 3680: 5f 62 6c 6f 63 6b 20 49 4e 54 45 47 45 52 2c 6c _block INTEGER,l | 3696: 65 61 76 65 73 5f 65 6e 64 5f 62 6c 6f 63 6b 20 eaves_end_block | 3712: 49 4e 54 45 47 45 52 2c 65 6e 64 5f 62 6c 6f 63 INTEGER,end_bloc | 3728: 6b 20 49 4e 54 45 47 45 52 2c 72 6f 6f 74 20 42 k INTEGER,root B | 3744: 4c 4f 42 2c 50 52 49 4d 41 52 59 20 4b 45 59 28 LOB,PRIMARY KEY( | 3760: 6c 65 76 65 6c 2c 20 69 64 78 29 29 31 05 06 17 level, idx))1... | 3776: 45 1f 01 00 69 6e 64 65 78 73 71 6c 69 74 65 5f E...indexsqlite_ | 3792: 61 75 74 6f 69 6e 64 65 78 5f 74 31 5f 73 65 67 autoindex_t1_seg | 3808: 64 69 72 5f 31 74 31 5f 73 65 67 64 69 72 05 00 dir_1t1_segdir.. | 3824: 00 00 08 00 00 00 00 66 03 07 17 23 23 01 81 13 .......f...##... | 3840: 74 61 62 6c 65 74 31 5f 73 65 67 6d 65 6e 74 73 tablet1_segments | 3856: 74 31 5f 73 65 67 6d 65 6e 74 73 03 43 52 45 41 t1_segments.CREA | 3872: 54 45 20 54 41 42 4c 45 20 27 74 31 5f 73 65 67 TE TABLE 't1_seg | 3888: 6d 65 6e 74 73 27 28 62 6c 6f 63 6b 69 64 20 49 ments'(blockid I | 3904: 4e 54 45 47 45 52 20 f9 52 49 4d 41 52 59 20 4b NTEGER .RIMARY K | 3920: 45 59 2c 20 62 6c 6f 63 6b 20 42 4c 4f 42 29 5c EY, block BLOB). | 3936: 02 07 17 21 21 01 81 03 74 61 62 6c 65 74 31 5f ...!!...tablet1_ | 3952: 63 6f 6e 74 65 6e 74 74 31 5f 63 6f 6e 74 65 6e contentt1_conten | 3968: 74 02 43 52 45 41 54 45 20 54 41 42 4c 45 20 27 t.CREATE TABLE ' | 3984: 74 31 5f 63 6f 6e 74 65 6e 74 27 28 64 6f 63 69 t1_content'(doci | 4000: 64 20 49 4e 54 45 47 45 52 20 50 52 49 4d 41 52 d INTEGER PRIMAR | 4016: 59 20 4b 45 59 2c 20 27 63 30 61 27 29 41 01 06 Y KEY, 'c0a')A.. | 4032: 17 11 11 08 71 74 61 62 6c 65 74 31 74 31 43 52 ....qtablet1t1CR | 4048: 45 41 54 45 20 56 49 52 54 55 41 4c 20 54 41 42 EATE VIRTUAL TAB | 4064: 4c 45 20 74 31 20 55 53 49 4e 47 20 66 74 73 34 LE t1 USING fts4 | 4080: 28 61 2c 70 72 65 66 69 78 3d 27 32 2c 32 27 29 (a,prefix='2,2') | page 2 offset 4096 | 0: 0d 00 00 00 08 0e 1f 00 0f c4 0f 7c 0f 34 0f 07 ...........|.4.. | 16: 0e c3 0e 97 0e 00 00 00 00 00 00 00 00 00 00 00 ................ | 3600: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 42 ...............B | 3616: 08 04 00 81 09 73 75 6e 74 20 69 6e 20 63 75 6c .....sunt in cul | 3632: 70 61 20 71 75 69 20 6f 66 66 69 63 69 61 20 64 pa qui officia d | 3648: 65 73 65 72 75 6e 74 20 6d 6f 6c 6c 69 74 20 61 eserunt mollit a | 3664: 6e 69 6d 20 69 64 20 65 73 74 20 6c 61 62 6f 72 nim id est labor | 3680: 75 6d 2e 32 07 03 00 6b 45 78 63 65 70 74 65 75 um.2...kExcepteu | 3696: 72 20 73 69 6e 74 20 6f 63 63 61 65 63 61 74 20 r sint occaecat | 3712: 63 75 70 69 64 61 74 61 74 20 6e 6f 6e 20 70 72 cupidatat non pr | 3728: 6f 69 64 65 6e 74 2c 2a 06 03 00 5b 63 69 6c 6c oident,*...[cill | 3744: 75 6d 20 64 6f 6c 6f 72 65 20 65 75 20 66 75 67 um dolore eu fug | 3760: 69 61 74 20 6e 75 6c 6c 61 20 70 61 72 69 61 74 iat nulla pariat | 3776: 75 72 2e 42 05 04 00 81 09 44 75 69 73 20 61 75 ur.B.....Duis au | 3792: 74 65 20 69 72 75 72 65 20 64 6f 6c 6f 72 20 69 te irure dolor i | 3808: 6e 20 72 65 70 72 65 68 65 6e 64 65 72 69 74 20 n reprehenderit | 3824: 69 6e 20 76 6f 6c 75 70 74 61 74 65 20 76 65 6c in voluptate vel | 3840: 69 74 20 65 73 73 65 2b 04 03 00 5d 6e 69 73 69 it esse+...]nisi | 3856: 20 75 74 20 61 6c 69 71 75 69 70 20 65 78 20 65 ut aliquip ex e | 3872: 61 20 63 6f 6d 6d 6f 64 6f 20 63 6f 6e 73 65 71 a commodo conseq | 3888: 75 61 74 2e 46 03 04 00 81 11 55 74 20 65 6e 69 uat.F.....Ut eni | 3904: 6d 20 61 64 20 6d 69 6e 69 6d 20 76 65 6e 69 61 m ad minim venia | 3920: 6d 2c 20 71 75 69 73 20 6e 6f 73 74 72 75 64 20 m, quis nostrud | 3936: 65 78 65 72 63 69 74 61 74 69 6f 6e 20 75 6c 6c exercitation ull | 3952: 61 6d 63 6f 20 6c 61 62 6f 72 69 73 46 02 04 00 amco laborisF... | 3968: 81 11 73 65 64 20 64 6f 20 65 69 75 73 6d 6f 64 ..sed do eiusmod | 3984: 20 74 65 6d 70 6f 72 20 69 6e 63 69 64 69 64 75 tempor incididu | 4000: 6e 74 20 75 74 20 6c 61 62 6f 72 65 20 65 74 20 nt ut labore et | 4016: 64 6f 6c 6f 72 65 20 6d 61 67 6e 61 20 61 6c 69 dolore magna ali | 4032: 71 75 61 2e 3a 01 03 00 7b 4c 6f 72 65 6d 20 69 qua.:....Lorem i | 4048: 70 73 75 6d 20 64 6f 6c 6f 72 20 73 69 74 20 61 psum dolor sit a | 4064: 6d 65 74 2c 20 63 6f 6e 73 65 63 74 65 74 75 72 met, consectetur | 4080: 20 61 64 69 70 69 73 63 69 6e 67 20 65 00 01 00 adipiscing e... | page 4 offset 12288 | 0: 0d 00 00 00 03 0a a6 00 0d 57 0c 4a 0a a6 00 00 .........W.J.... | 2720: 00 00 00 00 00 00 83 21 03 08 02 08 08 08 17 86 .......!........ | 2736: 30 08 00 30 20 34 30 32 00 02 61 64 06 01 08 00 0..0 402..ad.... | 2752: 02 04 00 01 01 6c 06 02 0c 00 02 04 00 01 01 6d .....l.........m | 2768: 03 01 06 00 01 01 6e 03 08 09 00 01 01 75 03 05 ......n......u.. | 2784: 03 00 00 02 63 69 03 06 02 00 01 01 6f 07 01 07 ....ci......o... | 2800: 00 03 07 03 00 01 01 75 06 07 05 00 01 04 00 00 .......u........ | 2816: 02 64 65 03 08 07 00 01 01 6f 0d 01 04 00 01 03 .de......o...... | 2832: 09 00 03 05 00 01 03 00 01 01 75 03 05 02 00 00 ..........u..... | 2848: 02 65 61 03 04 06 00 01 01 69 03 02 04 00 01 01 .ea......i...... | 2864: 6c 03 01 09 00 01 01 6e 03 03 03 00 01 01 73 06 l......n......s. | 2880: 05 0b 00 03 0b 00 01 01 74 03 02 09 00 01 01 75 ........t......u | 2896: 03 06 04 00 01 01 78 09 03 09 00 01 05 00 03 02 ......x......... | 2912: 00 00 02 66 75 03 06 05 00 00 02 69 64 03 08 0a ...fu......id... | 2928: 00 01 01 6e 0a 02 06 00 03 06 04 00 03 03 00 01 ...n............ | 2944: 01 70 03 01 03 00 01 01 72 03 05 04 00 00 02 6c .p......r......l | 2960: 61 09 02 08 00 01 0b 00 05 0c 00 01 01 6f 03 01 a............o.. | 2976: 02 00 00 02 6d 61 03 02 0b 00 01 01 69 03 03 05 ....ma......i... | 2992: 00 01 01 6f 03 08 08 00 00 02 6e 69 03 04 02 00 ...o......ni.... | 3008: 01 01 6f 06 03 08 00 04 06 00 01 01 75 03 06 06 ..o.........u... | 3024: 00 00 02 6f 63 03 07 04 00 01 01 66 03 08 06 00 ...oc......f.... | 3040: 00 02 70 61 03 06 07 00 01 01 72 03 07 07 00 00 ..pa......r..... | 3056: 02 71 75 06 03 07 00 05 05 00 00 02 72 65 03 05 .qu.........re.. | 3072: 07 00 00 02 73 65 03 02 02 00 01 01 69 06 01 05 ....se......i... | 3088: 00 06 03 00 01 01 75 03 08 02 00 00 02 74 65 03 ......u......te. | 3104: 02 05 00 00 02 75 6c 03 03 0a 00 01 01 74 09 02 .....ul......t.. | 3120: 07 00 01 02 00 01 03 00 00 02 76 65 06 03 06 00 ..........ve.... | 3136: 02 0a 00 01 01 6f 03 05 09 00 82 0a 02 08 02 08 .....o.......... | 3152: 08 08 17 84 02 04 00 30 20 32 35 31 00 01 61 13 .......0 251..a. | 3168: 01 06 04 00 01 0c 00 01 04 00 01 04 00 01 03 00 ................ | 3184: 03 09 00 00 01 63 10 01 07 00 03 07 03 00 02 02 .....c.......... | 3200: 00 01 05 00 01 04 00 00 01 64 11 01 04 00 01 03 .........d...... | 3216: 09 00 03 02 05 00 01 03 00 02 07 00 00 01 65 1b ..............e. | 3232: 01 09 00 01 04 07 00 01 03 08 00 01 05 03 00 01 ................ | 3248: 0b 00 01 04 00 01 02 00 01 0b 00 00 01 66 03 06 .............f.. | 3264: 05 00 00 01 69 0f 01 03 00 01 06 00 03 04 04 04 ....i........... | 3280: 00 03 03 09 00 00 01 6c 0c 01 02 00 01 08 00 01 .......l........ | 3296: 0b 00 05 0c 00 00 01 6d 09 02 0b 00 01 05 00 05 .......m........ | 3312: 08 00 00 01 6e 0c 03 08 00 01 02 00 02 06 00 01 ....n........... | 3328: 06 00 00 01 6f 06 07 04 00 01 06 00 00 01 70 06 ....o.........p. | 3344: 06 07 00 01 07 00 00 01 71 06 03 07 00 05 05 00 ........q....... | 3360: 00 01 72 03 05 07 00 00 01 73 0c 01 05 00 01 02 ..r......s...... | 3376: 00 05 03 00 01 02 00 00 01 74 03 02 05 00 00 01 .........t...... | 3392: 75 0a 02 07 00 01 02 0a 00 01 03 00 00 01 76 07 u.............v. | 3408: 03 06 00 02 09 03 00 85 26 01 08 08 08 08 08 17 ........&....... | 3424: 8a 3e 30 20 36 36 35 00 02 61 65 03 03 04 00 02 .>0 665..ae..... | 3440: 08 69 70 69 73 63 69 6e 67 03 01 08 00 01 05 6c .ipiscing......l | 3456: 69 71 75 61 03 02 0c 00 05 02 69 70 03 04 04 00 iqua......ip.... | 3472: 01 03 6d 65 74 03 01 06 00 01 03 6e 69 6d 03 08 ..met......nim.. | 3488: 09 00 01 03 75 74 65 03 05 03 00 00 06 63 69 6c ....ute......cil | 3504: 6c 75 6d 03 06 02 00 01 06 6f 6d 6d 6f 64 6f 03 lum......ommodo. | 3520: 04 07 00 02 09 6e 73 65 63 74 65 74 b5 72 03 01 .....nsectet.r.. | 3536: 07 00 05 04 71 75 61 74 03 04 08 00 01 04 75 6c ....quat......ul | 3552: 70 61 03 08 04 00 02 07 70 69 64 61 74 61 74 03 pa......pidatat. | 3568: 07 05 00 00 08 64 65 73 65 72 75 6e 74 03 08 07 .....deserunt... | 3584: 00 01 01 6f 03 02 03 00 02 03 6c 6f 72 06 01 04 ...o......lor... | 3600: 00 04 05 00 05 01 65 06 02 0a 00 04 03 00 01 03 ......e......... | 3616: 75 69 73 03 05 02 00 00 02 65 61 03 04 06 00 01 uis......ea..... | 3632: 06 69 75 73 6d 6f 64 03 02 04 00 01 03 6c 69 74 .iusmod......lit | 3648: 03 01 09 00 01 03 6e 69 6d 03 03 03 00 01 03 73 ......nim......s | 3664: 73 65 03 05 0b 00 02 01 74 03 08 0b 00 01 01 74 se......t......t | 3680: 03 02 09 00 01 01 75 03 06 04 00 01 01 78 03 04 ......u......x.. | 3696: 05 00 02 07 63 65 70 74 65 75 72 03 07 02 00 02 ....cepteur..... | 3712: 0a 65 72 63 69 74 61 74 69 6f 6e 03 03 09 00 00 .ercitation..... | 3728: 06 66 75 67 69 61 74 03 06 05 00 00 02 69 64 03 .fugiat......id. | 3744: 08 0a 00 01 01 6e 07 05 06 04 00 03 03 00 02 08 .....n.......... | 3760: 63 69 64 69 64 75 6e 74 03 02 06 00 01 04 70 73 cididunt......ps | 3776: 75 6d 03 01 03 00 01 04 72 75 72 65 03 05 04 00 um......rure.... | 3792: 00 06 6c 61 62 6f 72 65 03 02 08 00 05 02 69 73 ..labore......is | 3808: 03 03 0b 00 05 02 75 6d 03 08 0c 00 01 04 6f 72 ......um......or | 3824: 65 6d 03 01 02 00 00 05 6d 61 67 6e 61 03 02 0b em......magna... | 3840: 00 01 04 69 6e 69 6d 03 03 05 00 01 05 6f 6c 6c ...inim......oll | 3856: 69 74 03 08 08 00 00 04 6e 69 73 69 03 04 02 00 it......nisi.... | 3872: 01 02 6f 6e 03 07 06 00 02 05 73 74 72 75 64 03 ..on......strud. | 3888: 03 08 00 01 04 75 6c 6c 61 03 06 06 00 00 08 6f .....ulla......o | 3904: 63 63 61 65 63 61 74 03 07 04 00 01 06 66 66 69 ccaecat......ffi | 3920: 63 69 61 03 08 06 00 00 08 70 61 72 69 61 74 75 cia......pariatu | 3936: 72 03 06 07 00 01 07 72 6f 69 64 65 6e 74 03 07 r......roident.. | 3952: 07 00 00 03 71 75 69 03 08 05 00 03 01 73 03 03 ....qui......s.. | 3968: 07 00 00 0d 72 65 70 72 65 68 65 6e 64 65 72 69 ....reprehenderi | 3984: 74 03 05 07 00 00 03 73 65 64 03 02 02 00 01 03 t......sed...... | 4000: 69 6e 74 03 07 03 00 02 01 74 03 01 05 00 01 03 int......t...... | 4016: 75 6e 74 03 08 02 00 00 06 74 65 6d 70 6f 72 03 unt......tempor. | 4032: 02 05 00 00 07 75 6c 6c 61 6d 63 6f 03 03 0a 00 .....ullamco.... | 4048: 01 01 74 09 02 07 00 01 02 00 01 03 00 00 05 76 ..t............v | 4064: 65 6c 69 74 03 05 0a 00 02 04 6e 69 61 6d 03 03 elit......niam.. | 4080: 06 00 01 08 6f 6c 75 70 74 61 74 65 03 05 09 00 ....oluptate.... | page 5 offset 16384 | 0: 0a 00 00 00 03 0f eb 00 0f fb 0f f3 0f eb 00 00 ................ | 4064: 00 00 00 00 00 00 00 00 00 00 00 07 04 02 08 01 ................ | 4080: 08 00 03 07 04 02 08 01 04 00 02 04 04 08 08 09 ................ | page 6 offset 20480 | 0: 0d 00 00 00 08 0f d0 00 0f fa 0f f4 0f ee 0f e8 ................ | 16: 0f e2 0f dc 0f d6 0f d0 00 00 00 00 00 00 00 00 ................ | 4048: 04 08 03 00 0e 0b 04 07 03 00 0e 06 04 06 03 00 ................ | 4064: 0e 06 04 05 03 00 0e 0a 04 04 03 00 0e 07 04 03 ................ | 4080: 03 00 0e 0a 04 02 03 00 0e 0b 04 01 03 00 0e 08 ................ | page 7 offset 24576 | 0: 0d 00 00 00 01 0f f7 00 0f f7 00 00 00 00 01 00 ................ | 4080: 00 00 00 00 00 00 00 07 00 03 00 14 08 45 b5 03 .............E.. | end crash-58821b8eae6883.db }]} {} do_catchsql_test 49.1 { SAVEPOINT one; DELETE FROM t1 WHERE t1 MATCH 'c*'; SELECT matchinfo(t1,'pcx') IS NULL FROM t1 WHERE t1 MATCH 'f*e*'; } {0 0} #------------------------------------------------------------------------- # reset_db do_test 50.0 { sqlite3 db {} db deserialize [decode_hexdb { .open --hexdb | size 28672 pagesize 4096 filename crash-14ab65782c9c45.db | page 1 offset 0 | 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3. | 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 07 .....@ ........ | 32: 00 00 00 02 00 00 00 01 00 00 00 00 00 00 00 00 ................ | 96: 00 00 00 00 0d 0e b1 00 06 0d a4 00 0f 8d 0f 21 ...............! | 112: 0e b9 0d c8 0e 7e 0d a4 00 00 00 00 00 00 00 00 .....~.......... | 3488: 00 00 00 00 22 07 06 17 11 11 01 31 74 61 62 6c ...........1tabl | 3504: 65 74 32 74 32 07 43 52 45 41 54 45 20 54 41 42 et2t2.CREATE TAB | 3520: 4c 45 20 74 32 28 78 29 81 33 05 07 17 1f 1f 01 LE t2(x).3...... | 3536: 82 35 74 61 62 6c 65 74 31 5f 73 65 67 64 69 72 .5tablet1_segdir | 3552: 74 31 5f 73 65 67 64 69 72 05 43 52 45 41 54 45 t1_segdir.CREATE | 3568: 20 54 41 42 4c 45 20 27 74 31 5f 73 65 67 64 69 TABLE 't1_segdi | 3584: 72 27 28 6c 65 76 65 6c 20 49 4e 54 45 47 45 52 r'(level INTEGER | 3600: 2c 69 64 78 20 49 4e 54 45 47 45 52 2c 73 74 61 ,idx INTEGER,sta | 3616: 72 74 5f 62 6c 6f 63 6b 20 49 4e 54 45 47 45 52 rt_block INTEGER | 3632: 2c 6c 65 61 76 65 73 5f 65 6e 64 5f 62 6c 6f 63 ,leaves_end_bloc | 3648: 6b 20 49 4e 54 45 47 45 52 2c 65 6e 64 5f 62 6c k INTEGER,end_bl | 3664: 6f 63 6b 20 49 4e 54 45 47 45 52 2c 72 6f 6f 74 ock INTEGER,root | 3680: 20 42 4c 4f 42 2c 50 52 49 4d 41 52 59 20 4b 45 BLOB,PRIMARY KE | 3696: 59 28 6c 65 76 65 6c 2c 20 69 64 78 29 29 31 06 Y(level, idx))1. | 3712: 06 17 45 1f 01 00 69 6e 64 65 78 73 71 6c 69 74 ..E...indexsqlit | 3728: 65 5f 61 75 74 6f 69 6e 64 65 78 5f 74 31 5f 73 e_autoindex_t1_s | 3744: 65 67 64 69 72 5f 31 74 31 5f 73 65 68 64 69 72 egdir_1t1_sehdir | 3760: 06 0f c7 00 08 00 00 00 00 66 04 07 17 23 23 01 .........f...##. | 3776: 81 13 74 61 62 6c 65 74 31 5f 73 65 67 6d 65 6e ..tablet1_segmen | 3792: 74 73 74 31 5f 73 65 67 6d 65 6e 74 73 04 43 52 tst1_segments.CR | 3808: 45 41 54 45 20 54 41 42 4c 45 20 27 74 31 5f 73 EATE TABLE 't1_s | 3824: 65 67 6d 65 6e 74 73 27 28 62 6c 6f 63 6b 69 64 egments'(blockid | 3840: 20 49 4e 54 45 47 45 52 20 50 52 49 4d 41 52 59 INTEGER PRIMARY | 3856: 20 4b 45 59 2c 20 62 6c 6f 63 6b 20 42 4c 4f 42 KEY, block BLOB | 3872: 29 6a 03 07 17 21 21 01 81 1f 74 61 62 6c 65 74 )j...!!...tablet | 3888: 31 5f 63 6f 6e 74 65 6e 74 74 31 5f 63 6f 6e 74 1_contentt1_cont | 3904: 65 6e 74 03 43 52 45 41 54 45 20 54 41 42 4c 45 ent.CREATE TABLE | 3920: 20 27 74 31 5f 63 6f 6e 74 65 6e 74 27 28 64 6f 't1_content'(do | 3936: 63 69 64 20 49 4e 54 45 47 45 52 20 50 52 49 4d cid INTEGER PRIM | 3952: 41 52 59 20 4b 45 59 2c 20 27 63 30 61 27 2c 20 ARY KEY, 'c0a', | 3968: 27 62 31 62 27 2c 20 27 63 32 63 27 29 38 02 06 'b1b', 'c2c')8.. | 3984: 17 11 11 08 5f 74 61 62 6c 65 74 31 74 31 43 52 ...._tablet1t1CR | 4000: 45 41 54 45 20 56 49 52 54 55 41 4c 20 54 41 42 EATE VIRTUAL TAB | 4016: 4c 45 20 74 31 20 55 53 49 4e 47 20 66 74 73 33 LE t1 USING fts3 | 4032: 28 61 2c 62 2c 63 29 00 00 00 00 00 00 00 00 00 (a,b,c)......... | page 3 offset 8192 | 0: 0d 00 00 00 25 0b 48 00 0f d8 0f af 0f 86 0f 74 ....%.H........t | 16: 0f 61 0f 4e 0f 2f 0f 0f 0e ef 0e d7 0e be 0e a5 .a.N./.......... | 32: 0e 8d 0e 74 0e 5b 0e 40 0e 24 0e 08 0d ef 0d d5 ...t.[.@.$...... | 48: 0d bb 0d a0 0d 84 0d 00 00 00 00 00 00 00 00 00 ................ | 2880: 00 00 00 00 00 00 00 00 81 f9 25 06 00 82 7f 00 ..........%..... | 2896: 00 43 4f 4d 50 49 4c 45 52 3d 67 63 63 2d 35 2e .COMPILER=gcc-5. | 2912: 34 2e 30 20 32 30 31 36 30 36 30 39 20 44 45 42 4.0 20160609 DEB | 2928: 55 47 20 45 4e 41 42 4c 45 20 44 42 53 54 41 54 UG ENABLE DBSTAT | 2944: 20 56 54 41 42 20 45 4e 41 42 4c 45 20 46 54 53 VTAB ENABLE FTS | 2960: 34 20 45 4e 41 42 4c 45 20 46 54 53 35 20 45 4e 4 ENABLE FTS5 EN | 2976: 41 42 4c 45 20 47 45 4f 50 4f 4c 59 20 45 4e 41 ABLE GEOPOLY ENA | 2992: 42 4c 45 20 4a 53 4f 4e 31 20 45 4e 41 42 4c 45 BLE JSON1 ENABLE | 3008: 20 4d 45 4d 53 59 53 35 20 45 4e 41 42 4c 45 20 MEMSYS5 ENABLE | 3024: 52 54 52 45 45 20 4d 41 58 20 4d 45 4d 4f 52 59 RTREE MAX MEMORY | 3040: 3d 37 a0 30 30 30 30 f2 30 20 4f 4d 49 54 20 4c =7.0000.0 OMIT L | 3056: 4f 41 44 20 45 58 54 45 4e 53 49 4f 4e 20 54 48 OAD EXTENSION TH | 3072: 52 45 41 44 53 41 46 45 3d 30 18 24 05 00 25 0f READSAFE=0.$..%. | 3088: 19 54 48 52 45 41 44 53 41 46 45 3d 30 58 42 49 .THREADSAFE=0XBI | 3104: 4e 41 52 59 18 23 05 00 25 0f 19 54 48 52 45 41 NARY.#..%..THREA | 3120: 44 53 41 46 45 3d 30 58 4e 4f 43 41 53 45 17 22 DSAFE=0XNOCASE.. | 3136: 05 00 25 0f 17 54 48 52 45 41 54 53 41 46 45 3d ..%..THREATSAFE= | 3152: 30 58 52 54 52 49 4d 1f 21 05 00 33 0f 19 4f 4d 0XRTRIM.!..3..OM | 3168: 49 54 20 5c 4f 41 44 20 45 58 54 45 4e 53 49 4f IT .OAD EXTENSIO | 3184: 4e 58 42 49 4e 41 52 59 1f 20 05 00 33 0f 19 4f NXBINARY. ..3..O | 3200: 4d 49 54 20 4c 4f 41 44 20 45 58 54 45 4e 53 49 MIT LOAD EXTENSI | 3216: 4f 4e 58 4e 4f 43 41 53 46 1e 1f 05 00 33 0f 17 ONXNOCASF....3.. | 3232: 4f 4d 49 54 20 4c 4f 41 44 20 45 58 54 45 4e 53 OMIT LOAD EXTENS | 3248: 49 4f 4e 58 52 44 52 49 4d 1f 1e 05 00 33 0f 19 IONXRDRIM....3.. | 3264: 4d 41 68 20 4d 45 4d 4f 52 59 3d 35 30 30 30 30 MAh MEMORY=50000 | 3280: 30 30 30 58 42 49 4e 41 52 59 1f 1d 05 00 33 0f 000XBINARY....3. | 3296: 19 4d 41 58 20 4d 45 4d 4f 52 59 3d 35 30 30 30 .MAX MEMORY=5000 | 3312: 30 30 30 30 58 4e 4f 43 41 53 45 1e 1c 05 00 33 0000XNOCASE....3 | 3328: 0f 16 4d 41 58 20 4d 45 4d 4f 52 59 3d 35 30 30 ..MAX MEMORY=500 | 3344: 30 30 30 30 30 58 52 54 52 49 4d 18 1b 05 00 25 00000XRTRIM....% | 3360: 0f 19 45 4e 41 42 4c 45 20 52 54 52 45 45 58 42 ..ENABLE RTREEXB | 3376: 49 4e 41 52 59 18 1a 05 00 25 0f 19 45 4e 41 42 INARY....%..ENAB | 3392: 4c 45 20 52 54 52 45 45 58 4e 4f 43 41 53 45 17 LE RTREEXNOCASE. | 3408: 19 05 00 25 0f 17 45 4e 41 42 4c 45 20 52 54 52 ...%..ENABLE RTR | 3424: 45 45 58 52 54 52 49 4d 1a 18 05 00 29 0f 19 45 EEXRTRIM....)..E | 3440: 4e 41 42 4c 45 20 4d 45 43 53 59 53 35 58 42 49 NABLE MECSYS5XBI | 3456: 4e 41 52 59 1a 17 05 00 29 0f 19 45 4e 41 42 4c NARY....)..ENABL | 3472: 45 20 4d 45 4d 53 59 53 35 58 4e 4f 43 41 53 45 E MEMSYS5XNOCASE | 3488: 19 16 05 00 29 0f 17 45 4e 41 42 4c 45 20 4d 45 ....)..ENABLE ME | 3504: 4d 53 59 53 35 58 52 54 52 49 4d 18 15 05 00 25 MSYS5XRTRIM....% | 3520: 0f 19 45 4e 41 42 4c 45 20 4a 53 4f 4e 31 58 42 ..ENABLE JSON1XB | 3536: 49 4e 41 52 59 18 14 05 00 25 0f 19 45 4e 41 42 INARY....%..ENAB | 3552: 4c 45 20 4a 53 4f 4e 31 58 4e 4f 43 41 53 45 17 LE JSON1XNOCASE. | 3568: 13 05 00 25 0f 17 45 4e 41 42 4c 45 20 4a 53 4f ...%..ENABLE JSO | 3584: 4e 31 58 52 54 52 49 4d 1a 12 05 00 29 0f 19 45 N1XRTRIM....)..E | 3600: 4e 41 42 4c 45 20 47 45 4f 50 4f 4c 59 58 42 49 NABLE GEOPOLYXBI | 3616: 4e 41 52 59 1a 11 05 00 29 0f 19 45 4e 41 42 4c NARY....)..ENABL | 3632: 45 20 47 45 4f 50 4f 4c 59 58 4e 4f 43 41 53 45 E GEOPOLYXNOCASE | 3648: 19 10 05 00 29 0f 17 45 4e 41 42 4c 45 20 47 45 ....)..ENABLE GE | 3664: 4f 50 4f 4c 59 58 52 54 52 49 4d 17 0f 05 00 23 OPOLYXRTRIM....# | 3680: 0f 19 45 4e 41 42 4c 45 20 46 54 53 35 58 42 49 ..ENABLE FTS5XBI | 3696: 4e 41 52 59 17 0e 05 00 23 0f 19 45 4e 41 42 4c NARY....#..ENABL | 3712: 45 20 46 54 53 35 58 4e 4f 43 41 53 45 16 0d 05 E FTS5XNOCASE... | 3728: 00 23 0f 17 45 4e 41 42 4c 45 20 46 54 53 35 58 .#..ENABLE FTS5X | 3744: 52 54 52 49 4d 17 0c 05 00 23 0f 19 45 4e 41 42 RTRIM....#..ENAB | 3760: 4c 45 20 46 54 53 34 58 42 49 4e 41 52 59 17 0b LE FTS4XBINARY.. | 3776: 05 00 23 0f 19 45 4e 41 42 4c 45 20 46 54 53 34 ..#..ENABLE FTS4 | 3792: 58 4e 4f 43 41 53 45 16 0a 05 00 23 0f 17 45 4e XNOCASE....#..EN | 3808: 41 42 4c 46 20 46 54 53 34 58 52 54 52 49 4d 1e ABLF FTS4XRTRIM. | 3824: 09 05 00 31 0f 19 45 4e 41 42 4c 45 20 44 42 53 ...1..ENABLE DBS | 3840: 54 41 54 20 56 54 41 42 58 42 49 4e 41 52 59 1e TAT VTABXBINARY. | 3856: 08 05 00 31 0f 19 45 4e 41 42 4c 45 20 44 42 53 ...1..ENABLE DBS | 3872: 55 41 54 20 56 54 41 42 58 4e 4f 43 41 53 45 1d UAT VTABXNOCASE. | 3888: 07 05 00 31 0f 17 45 4e 41 42 4c 45 20 44 42 53 ...1..ENABLE DBS | 3904: 54 41 54 20 56 54 41 42 58 52 54 52 49 4d 11 06 TAT VTABXRTRIM.. | 3920: 05 00 17 0f 19 44 45 42 55 47 58 42 49 4e 41 52 .....DEBUGXBINAR | 3936: 59 11 05 05 00 17 0f 19 44 45 42 55 47 58 4e 4f Y.......DEBUGXNO | 3952: 43 41 53 45 10 04 05 00 17 0f 17 44 45 42 55 47 CASE.......DEBUG | 3968: 58 52 54 52 49 4d 27 03 05 00 43 0f 19 43 4f 4d XRTRIM'...C..COM | 3984: 50 49 4c 45 52 3d 67 63 63 2d 35 2e 34 2e 30 20 PILER=gcc-5.4.0 | 4000: 32 30 31 36 30 36 30 39 58 42 49 4e 41 52 59 27 20160609XBINARY' | 4016: 02 05 00 43 0f 19 43 4f 4d 50 49 4c 45 52 3d 67 ...C..COMPILER=g | 4032: 63 63 2d 35 2e 34 2e 30 20 32 30 31 36 30 36 30 cc-5.4.0 2016060 | 4048: 39 58 4e 4f 43 41 53 45 00 00 00 00 00 00 00 00 9XNOCASE........ | page 5 offset 16384 | 0: 0d 00 00 00 02 0b a0 00 0c ad 0b a0 00 00 00 00 ................ | 2976: 82 0a 02 08 08 09 08 08 17 84 06 30 20 32 35 33 ...........0 253 | 2992: 00 01 30 04 25 06 1b 00 00 08 32 30 31 36 30 36 ..0.%.....201606 | 3008: 30 39 03 25 07 00 00 01 34 03 25 05 00 00 01 35 09.%....4.%....5 | 3024: 03 25 04 00 01 07 30 30 30 30 30 30 30 03 25 1a .%....0000000.%. | 3040: 00 00 08 63 6f 6d 70 69 6c 65 72 03 25 02 00 00 ...compiler.%... | 3056: 06 64 62 73 74 61 74 03 25 0a 00 01 04 65 62 75 .dbstat.%....ebu | 3072: 67 03 25 08 00 00 06 65 6e 61 62 6c 65 09 25 09 g.%....enable.%. | 3088: 05 04 04 04 04 04 00 01 08 78 74 65 6e 73 69 6f .........xtensio | 3104: 6e 03 25 1d 00 00 04 66 74 73 34 03 25 0d 00 03 n.%....fts4.%... | 3120: 01 35 03 25 0f 00 00 03 67 63 63 03 25 03 00 01 .5.%....gcc.%... | 3136: 06 65 6f 70 6f 6c 79 03 25 11 00 00 05 6a 73 6f .eopoly.%....jso | 3152: 6e 31 03 25 13 00 00 04 6c 6f 61 64 03 25 1c 00 n1.%....load.%.. | 3168: 00 03 6d 61 78 03 25 18 00 01 05 65 6d 6f 72 79 ..max.%....emory | 3184: 03 25 19 00 03 04 73 79 73 35 03 25 15 00 00 04 .%....sys5.%.... | 3200: 6f 6d 69 74 03 25 1b 00 00 05 72 74 72 65 65 03 omit.%....rtree. | 3216: 25 17 00 00 0a 74 68 72 65 61 64 73 61 66 65 03 %....threadsafe. | 3232: 25 1e 00 00 04 76 74 61 62 03 25 0b 00 86 50 01 %....vtab.%...P. | 3248: 08 08 08 08 08 17 8d 12 30 20 38 33 35 00 01 30 ........0 835..0 | 3264: 12 01 06 00 01 06 00 01 06 00 1f 03 00 01 03 00 ................ | 3280: 01 03 00 00 08 32 30 31 36 30 36 30 39 09 01 07 .....20160609... | 3296: 00 01 07 00 01 07 00 00 01 34 09 01 05 00 01 05 .........4...... | 3312: 00 01 05 00 00 01 35 09 01 04 00 01 04 00 01 04 ......5......... | 3328: 00 01 07 30 30 30 30 30 30 30 09 1c 04 00 01 04 ...0000000...... | 3344: 00 01 04 00 00 06 62 69 6e 61 72 79 3c 03 01 02 ......binary<... | 3360: 02 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 ................ | 3376: 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 00 ................ | 3392: 03 01 02 02 00 03 01 02 02 00 03 01 02 02 00 03 ................ | 3408: 01 02 02 00 03 01 02 02 00 00 08 63 6f 38 70 69 ...........co8pi | 3424: 6c 65 72 09 01 02 00 01 02 00 01 02 00 00 06 64 ler............d | 3440: 52 73 74 61 74 09 07 03 00 01 03 00 01 03 00 01 Rstat........... | 3456: 04 65 62 75 67 09 04 02 00 01 02 00 01 02 00 00 .ebug........... | 3472: 06 65 6e 61 62 6c 65 3f 07 02 00 01 02 00 01 01 .enable?........ | 3488: ff f1 02 00 01 02 00 01 02 00 01 02 00 01 02 00 ................ | 3504: 01 02 00 01 03 00 01 01 00 02 02 00 01 02 00 01 ................ | 3520: 02 00 01 02 00 01 12 00 01 02 00 01 02 00 01 02 ................ | 3536: 00 01 02 00 01 02 00 01 08 78 74 65 6e 73 69 6f .........xtensio | 3552: 6e 09 1f 04 00 01 04 00 01 04 00 00 04 66 74 73 n............fts | 3568: 34 09 0a 03 00 01 03 00 01 04 00 03 01 35 09 0d 4............5.. | 3584: 03 00 01 03 00 01 03 00 00 03 67 63 63 09 01 03 ..........gcc... | 3600: 00 01 03 0b 01 13 00 01 06 65 6f 70 6f 6c 79 09 .........eopoly. | 3616: 10 03 00 01 03 00 01 03 00 00 05 6a 83 6f 6e 31 ...........j.on1 | 3632: 09 13 03 00 01 03 00 01 03 00 00 04 6c 6f 61 64 ............load | 3648: 09 1f 03 00 01 03 00 01 03 00 00 03 6d 61 78 09 ............max. | 3664: 1c 02 00 01 02 00 01 02 00 01 05 65 6d 6f 72 79 ...........emory | 3680: 09 1c 03 00 01 03 00 01 03 00 03 04 73 79 73 35 ............sys5 | 3696: 09 16 03 00 01 03 00 01 03 00 00 06 6e 6f 63 61 ............noca | 3712: 73 65 3c 02 01 02 02 00 03 01 02 02 00 03 01 02 se<............. | 3728: 02 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 ................ | 3744: 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 00 ................ | 3760: 03 01 02 02 00 03 01 02 02 00 03 01 02 02 00 00 ................ | 3776: 04 6f 6d 69 74 09 1f 02 00 01 02 00 01 02 00 00 .omit........... | 3792: 05 72 74 72 65 65 09 19 03 00 01 03 00 01 03 00 .rtree.......... | 3808: 03 02 69 6d 3c 01 01 02 02 00 03 01 02 02 00 03 ..im<........... | 3824: 01 02 02 00 03 01 02 02 00 03 01 02 02 00 03 01 ................ | 3840: 02 02 00 03 01 02 02 00 03 01 02 02 00 03 01 02 ................ | 3856: 02 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 ................ | 3872: 00 00 0a 74 68 72 65 61 64 73 61 66 65 09 22 02 ...threadsafe... | 3888: 00 01 02 00 01 02 00 00 04 76 74 61 62 09 07 04 .........vtab... | 3904: 00 01 04 00 01 04 00 00 01 78 b4 01 01 01 01 02 .........x...... | 3920: 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 ................ | 3936: 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 01 ................ | 3952: 01 01 02 00 01 01 01 02 00 01 01 01 02 00 01 01 ................ | 3968: 01 02 00 01 01 01 02 00 01 01 01 02 00 01 01 01 ................ | 3984: 02 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 ................ | 4000: 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 ................ | 4016: 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 01 ................ | 4032: 01 01 02 00 01 01 01 02 00 01 01 01 02 00 01 01 ................ | 4048: 01 02 00 01 01 01 02 00 01 01 01 02 00 01 01 01 ................ | 4064: 02 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 ................ | 4080: 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 ................ | page 6 offset 20480 | 0: 0a 00 00 00 02 0f f5 00 0f fb 0f f5 00 00 00 00 ................ | 4080: 00 00 00 00 00 05 04 08 09 01 02 04 04 08 08 09 ................ | page 7 offset 24576 | 0: 0d 00 00 00 05 0f b8 00 0f f4 0f 00 00 00 00 00 ................ | 4016: 00 00 00 00 00 00 00 00 0d 05 02 23 61 75 74 6f ...........#auto | 4032: 6d 65 72 67 65 3d 35 0d 04 02 23 6d 65 72 67 65 merge=5...#merge | 4048: 3d 31 30 30 2c 38 11 03 02 2b 69 6e 74 65 67 72 =100,8...+integr | 4064: 69 74 79 2d 63 68 65 63 6b 09 02 02 00 00 00 00 ity-check....... | end crash-14ab65782c9c45.db }]} {} do_execsql_test 50.1 { SELECT NULL FROM t1 WHERE t1 MATCH '"^enable"' } { {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} } #------------------------------------------------------------------------- # reset_db do_test 51.0 { sqlite3 db {} db deserialize [decode_hexdb { .open --hexdb | size 28672 pagesize 4096 filename crash-11cf359576eb28.db | page 1 offset 0 | 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3. | 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 07 .....@ ........ | 32: 00 00 00 02 00 00 00 01 00 00 00 07 00 00 00 04 ................ | 96: 00 00 00 00 0d 0e b1 00 06 0d a4 00 0f 8d 0f 21 ...............! | 112: 0e b9 0d c8 0e 7e 0d a4 0d a4 00 00 00 00 00 00 .....~.......... | 3488: 00 00 00 00 22 07 06 17 11 11 01 31 74 61 62 6c ...........1tabl | 3504: 65 74 32 74 32 07 43 52 45 41 54 45 20 54 41 42 et2t2.CREATE TAB | 3520: 4c 45 20 74 32 28 78 29 81 33 05 07 17 1f 1f 01 LE t2(x).3...... | 3536: 82 35 74 61 62 6c 65 74 31 5f 73 65 67 64 69 72 .5tablet1_segdir | 3552: 74 31 5f 73 65 67 64 69 72 05 43 52 45 41 54 45 t1_segdir.CREATE | 3568: 20 54 41 42 4c 45 20 27 74 31 5f 73 65 67 64 69 TABLE 't1_segdi | 3584: 72 27 28 6c 65 76 65 6c 20 49 4e 54 45 47 45 52 r'(level INTEGER | 3600: 2c 69 64 78 20 49 4e 54 45 47 45 52 2c 73 74 61 ,idx INTEGER,sta | 3616: 72 74 5f 62 6c 6f 63 6b 20 49 4e 54 45 47 45 52 rt_block INTEGER | 3632: 2c 6c 65 61 76 65 73 5f 65 6e 64 5f 62 6c 6f 63 ,leaves_end_bloc | 3648: 6b 20 49 4e 54 45 47 45 52 2c 65 6e 64 5f 62 6c k INTEGER,end_bl | 3664: 6f 63 6b 20 49 4e 54 45 47 45 52 2c 72 6f 6f 74 ock INTEGER,root | 3680: 20 42 4c 4f 42 2c 50 52 49 4d 41 52 59 20 4b 45 BLOB,PRIMARY KE | 3696: 59 28 6c 65 76 65 6c 2c 20 69 64 78 29 29 31 06 Y(level, idx))1. | 3712: 06 17 45 1f 01 00 69 6e 64 65 78 73 71 6c 69 74 ..E...indexsqlit | 3728: 65 5f 61 75 74 6f 69 6e 64 65 78 5f 74 31 5f 73 e_autoindex_t1_s | 3744: 65 67 64 69 72 5f 31 74 31 5f 73 65 67 64 69 72 egdir_1t1_segdir | 3760: 06 0f c7 00 08 00 00 00 00 66 04 07 17 23 23 01 .........f...##. | 3776: 81 13 74 61 62 6c 65 74 31 5f 73 65 67 6d 65 6e ..tablet1_segmen | 3792: 74 73 74 31 5f 73 65 67 6d 65 6e 74 73 04 43 52 tst1_segments.CR | 3808: 45 41 54 45 20 54 41 42 4c 45 20 27 74 31 5f 73 EATE TABLE 't1_s | 3824: 65 67 6d 65 6e 74 73 27 28 62 6c 6f 63 6b 69 64 egments'(blockid | 3840: 20 49 4e 54 45 47 45 52 20 50 51 49 4d 41 52 59 INTEGER PQIMARY | 3856: 20 4b 45 59 2c 20 62 6c 6f 63 6b 20 42 4c 4f 42 KEY, block BLOB | 3872: 29 6a 03 07 17 21 21 01 81 1f 74 61 62 6c 65 74 )j...!!...tablet | 3888: 31 5f 63 6f 6e 74 65 6e 74 74 31 5f 63 6f 6e 74 1_contentt1_cont | 3904: 65 6e 74 03 43 52 45 41 54 45 20 54 41 42 4c 45 ent.CREATE TABLE | 3920: 20 27 74 31 5f 63 6f 6e 74 65 6e 74 27 28 64 6f 't1_content'(do | 3936: 63 69 64 20 49 4e 54 45 47 45 52 20 50 52 49 4d cid INTEGER PRIM | 3952: 41 52 59 20 4b 45 59 2c 20 27 63 30 61 27 2c 20 ARY KEY, 'c0a', | 3968: 27 63 31 62 27 2c 20 27 63 32 63 27 29 38 02 06 'c1b', 'c2c')8.. | 3984: 17 11 11 08 5f 74 61 62 6c 65 74 31 74 31 43 52 ...._tablet1t1CR | 4000: 45 41 54 45 20 56 49 52 54 55 41 4c 20 54 41 42 EATE VIRTUAL TAB | 4016: 4c 45 20 74 31 20 55 53 49 4e 47 20 66 74 73 33 LE t1 USING fts3 | 4032: 28 61 2c 62 2c 63 29 00 00 00 00 00 00 00 00 00 (a,b,c)......... | page 3 offset 8192 | 0: 0d 00 00 00 25 0b 48 00 0f d8 0f af 0f 86 0f 74 ....%.H........t | 16: 0f 61 0f 4e 0f 2f 0f 0f 0e ef 0e d7 0e be 0e a5 .a.N./.......... | 32: 0e 8d 0e 74 0e 5b 0e 40 0e 24 0e 08 0d ef 0d d5 ...t.[.@.$...... | 48: 0d bb 0d a0 0d 84 0d 68 0d 4f 0d 35 0d 1b 0c fb .......h.O.5.... | 64: 0c da 0c b9 0c 99 0c 78 0c 57 0c 3e 0c 24 0c 0a .......x.W.>.$.. | 80: 0b 48 00 00 00 00 00 00 00 00 00 00 00 00 00 00 .H.............. | 2880: 00 00 00 00 00 00 00 00 81 3f 25 06 00 82 7f 00 .........?%..... | 2896: 00 43 4f 4d 50 49 4c 45 52 3d 67 63 63 2d 35 2e .COMPILER=gcc-5. | 2912: 34 2e 30 20 32 30 31 36 30 36 30 39 20 44 45 42 4.0 20160609 DEB | 2928: 55 47 20 45 4e 41 42 4c 45 20 44 42 53 54 41 54 UG ENABLE DBSTAT | 2944: 20 56 54 41 42 20 45 4e 41 42 4c 45 20 46 54 53 VTAB ENABLE FTS | 2960: 34 20 45 4e 41 42 4c 45 20 46 54 53 35 20 45 4e 4 ENABLE FTS5 EN | 2976: 41 42 4c 45 20 47 45 4f 59 0f 4c 59 20 45 4e 41 ABLE GEOY.LY ENA | 2992: 42 4c 45 20 4a 53 4f 4e 31 20 45 4e 41 42 4c 45 BLE JSON1 ENABLE | 3008: 20 4d 45 4d 53 59 53 35 20 45 4e 41 42 4c 45 20 MEMSYS5 ENABLE | 3024: 52 54 52 45 45 20 4d 41 58 20 4d 45 4d 4f 52 59 RTREE MAX MEMORY | 3040: 3d 35 30 30 30 30 30 30 30 20 4f 4d 49 54 20 4d =50000000 OMIT M | 3056: 4f 41 44 20 45 58 54 45 4e 53 49 4f 4e 20 54 48 OAD EXTENSION TH | 3072: 52 45 41 44 53 41 46 45 3d 30 18 24 05 00 25 0f READSAFE=0.$..%. | 3088: 19 54 48 52 45 41 44 53 41 46 45 3d 30 58 42 49 .THREADSAFE=0XBI | 3104: 4e 41 52 59 18 23 05 00 25 0f 19 54 48 52 45 41 NARY.#..%..THREA | 3120: 44 53 41 46 45 3d 30 58 4e 4f 43 41 53 45 17 22 DSAFE=0XNOCASE.. | 3136: 05 00 25 0f 17 54 48 52 45 41 44 53 41 46 45 3d ..%..THREADSAFE= | 3152: 30 58 52 54 52 49 4d 1f 21 05 00 33 0f 19 4f 4d 0XRTRIM.!..3..OM | 3168: 49 54 20 4c 4f 41 44 20 45 58 54 45 4e 53 49 4f IT LOAD EXTENSIO | 3184: 4e 58 42 49 4e 41 52 59 1f 20 05 00 33 0f 19 4f NXBINARY. ..3..O | 3200: 4d 49 54 20 4c 4f 41 44 20 45 58 54 45 4e 53 49 MIT LOAD EXTENSI | 3216: 4f 4e 58 4e 4f 43 41 53 45 1e 1f 05 00 33 0f 17 ONXNOCASE....3.. | 3232: 4f 4d 49 54 20 4c 4f 41 44 20 45 58 54 45 4e 53 OMIT LOAD EXTENS | 3248: 49 4f 4e 58 52 54 52 49 4d 1f 1e 05 00 33 0f 19 IONXRTRIM....3.. | 3264: 4d 41 58 20 4d 45 4d 4f 52 59 3d 35 30 30 30 30 MAX MEMORY=50000 | 3280: 30 30 30 58 42 49 4e 41 52 59 1f 1d 05 00 33 0f 000XBINARY....3. | 3296: 19 4d 41 58 20 4d 45 4d 4f 52 59 3d 35 30 30 30 .MAX MEMORY=5000 | 3312: 30 30 30 30 58 4e 4f 43 41 53 45 1e 1c 05 00 33 0000XNOCASE....3 | 3328: 0f 17 4d 41 58 20 4d 45 4d 4f 52 59 3d 35 30 30 ..MAX MEMORY=500 | 3344: 30 30 30 30 30 58 52 54 52 49 4d 18 1b 05 00 25 00000XRTRIM....% | 3360: 0f 19 45 4e 41 42 4c 45 20 52 54 52 45 45 58 42 ..ENABLE RTREEXB | 3376: 49 4e 41 52 59 18 1a 05 00 25 0f 19 45 4e 41 42 INARY....%..ENAB | 3392: 4c 45 20 52 54 52 45 45 58 4e 4f 43 41 53 45 17 LE RTREEXNOCASE. | 3408: 19 05 00 25 0f 17 45 4e 41 42 4c 45 20 52 54 52 ...%..ENABLE RTR | 3424: 45 45 58 52 54 52 49 4d 1a 18 05 00 29 0f 19 45 EEXRTRIM....)..E | 3440: 4e 41 42 4c 45 20 4d 45 4d 53 59 53 35 58 42 49 NABLE MEMSYS5XBI | 3456: 4e 41 52 59 1a 17 05 00 29 0f 19 45 4e 41 42 4c NARY....)..ENABL | 3472: 45 20 4d 45 4d 53 59 53 35 58 4e 4f 43 41 53 45 E MEMSYS5XNOCASE | 3488: 19 16 05 00 29 0f 17 45 4e 41 42 4c 45 20 4d 45 ....)..ENABLE ME | 3504: 4d 53 59 53 35 58 52 54 52 49 4d 18 15 05 00 25 MSYS5XRTRIM....% | 3520: 0f 19 45 4e 41 42 4c 45 20 4a 53 4f 4e 31 58 42 ..ENABLE JSON1XB | 3536: 49 4e 41 52 59 18 14 05 00 25 0f 19 45 4e 41 42 INARY....%..ENAB | 3552: 4c 45 20 4a 53 4f 4e 31 58 4e 4f 43 41 53 45 17 LE JSON1XNOCASE. | 3568: 13 05 00 25 0f 17 45 4e 41 42 4c 45 20 4a 53 4f ...%..ENABLE JSO | 3584: 4e 31 58 52 54 52 49 4d 1a 12 05 00 29 0f 19 45 N1XRTRIM....)..E | 3600: 4e 41 42 4c 45 20 47 45 4f 50 4f 4c 59 58 42 49 NABLE GEOPOLYXBI | 3616: 4e 41 52 59 1a 11 05 00 29 0f 19 45 4e 41 42 4c NARY....)..ENABL | 3632: 45 20 47 45 4f 50 4f 4c 59 58 4e 4f 43 41 53 45 E GEOPOLYXNOCASE | 3648: 19 10 05 00 29 0f 17 45 4e 41 42 4c 45 20 47 45 ....)..ENABLE GE | 3664: 4f 50 4f 4c 59 58 52 54 52 49 4d 17 0f 05 00 23 OPOLYXRTRIM....# | 3680: 0f 19 45 4e 41 42 4c 45 20 46 54 53 35 58 42 49 ..ENABLE FTS5XBI | 3696: 4e 41 52 59 17 0e 05 00 23 0f 19 45 4e 41 42 4c NARY....#..ENABL | 3712: 45 20 46 54 53 35 58 4e 4f 43 41 53 45 16 0d 05 E FTS5XNOCASE... | 3728: 00 23 0f 17 45 4e 41 42 4c 45 20 46 54 53 35 58 .#..ENABLE FTS5X | 3744: 52 54 52 49 4d 17 0c 05 00 23 0f 19 45 4e 41 42 RTRIM....#..ENAB | 3760: 4c 45 20 46 54 53 34 58 42 49 4e 41 52 59 17 0b LE FTS4XBINARY.. | 3776: 05 00 23 0f 19 45 4e 41 42 4c 45 20 46 54 53 34 ..#..ENABLE FTS4 | 3792: 58 4e 4f 43 41 53 45 16 0a 05 00 23 0f 17 45 4e XNOCASE....#..EN | 3808: 41 42 4c 45 20 46 54 53 34 58 52 54 52 49 4d 1e ABLE FTS4XRTRIM. | 3824: 09 05 00 31 0f 19 45 4e 41 42 4c 45 20 44 42 53 ...1..ENABLE DBS | 3840: 54 41 54 20 56 54 41 42 58 42 49 4e 41 52 59 1e TAT VTABXBINARY. | 3856: 08 05 00 31 0f 19 45 4e 41 42 4c 45 20 44 42 53 ...1..ENABLE DBS | 3872: 54 41 54 20 56 54 41 42 58 4e 4f 43 41 53 45 1d TAT VTABXNOCASE. | 3888: 07 05 00 31 0f 17 45 4e 41 42 4c 45 20 44 42 53 ...1..ENABLE DBS | 3904: 54 41 54 20 56 54 41 42 58 52 54 52 49 4d 11 06 TAT VTABXRTRIM.. | 3920: 05 00 17 0f 19 44 45 42 55 47 58 42 49 4e 41 52 .....DEBUGXBINAR | 3936: 59 11 05 05 00 17 0f 19 44 45 42 55 47 58 4e 4f Y.......DEBUGXNO | 3952: 43 41 53 45 10 04 05 00 17 0f 17 44 45 42 55 47 CASE.......DEBUG | 3968: 58 52 54 52 49 4d 27 03 05 00 43 10 19 43 4f 4d XRTRIM'...C..COM | 3984: 50 49 4c 45 52 3d 67 63 63 2d 35 2e 34 2e 30 20 PILER=gcc-5.4.0 | 4000: 32 30 31 36 30 36 30 39 58 42 49 4e 41 52 59 27 20160609XBINARY' | 4016: 02 05 00 43 0f 19 43 4f 4d 50 49 4c 45 52 3d 67 ...C..COMPILER=g | 4032: 63 63 2d 35 2e 34 2e 30 20 32 30 31 36 30 36 30 cc-5.4.0 2016060 | 4048: 39 58 4e 4f 43 41 53 45 26 01 05 00 43 0f 17 43 9XNOCASE&...C..C | 4064: 4f 4d 50 49 4c 45 52 3d 67 63 63 2d 35 2e 34 2e OMPILER=gcc-5.4. | 4080: 30 20 32 30 31 36 30 36 30 39 58 52 54 52 49 4d 0 20160609XRTRIM | page 4 offset 12288 | 0: 0d 00 00 00 00 10 00 00 00 00 00 00 00 00 00 00 ................ | page 5 offset 16384 | 0: 0d 00 00 00 02 0b a0 00 0c ad 0b a0 00 00 00 00 ................ | 2976: 82 0a 02 08 08 09 08 08 17 84 06 30 20 32 35 33 ...........0 253 | 2992: 00 01 30 04 25 06 1b 00 00 08 32 30 31 36 30 36 ..0.%.....201606 | 3008: 30 39 03 25 07 00 00 01 34 03 25 05 00 00 01 35 09.%....4.%....5 | 3024: 03 25 04 00 01 07 30 30 30 30 30 30 30 03 25 1a .%....0000000.%. | 3040: 00 00 08 63 6f 6d 70 69 6c 65 72 03 25 02 00 00 ...compiler.%... | 3056: 06 64 62 73 74 61 74 03 25 0a 00 01 04 65 62 75 .dbstat.%....ebu | 3072: 67 03 25 08 00 00 06 65 6e 61 62 6c 65 09 25 09 g.%....enable.%. | 3088: 05 04 04 04 04 04 00 01 08 78 74 65 6e 73 69 6f .........xtensio | 3104: 6e 03 25 1d 00 00 04 66 74 73 34 03 25 0d 00 03 n.%....fts4.%... | 3120: 01 35 03 25 0f 00 00 03 67 63 63 03 25 03 00 01 .5.%....gcc.%... | 3136: 06 65 6f 70 6f 6c 79 03 25 11 00 00 05 6a 73 6f .eopoly.%....jso | 3152: 6e 31 03 25 13 00 00 04 6c 6f 61 64 03 25 1c 00 n1.%....load.%.. | 3168: 00 03 6d 61 78 03 25 18 00 01 05 65 6d 6f 72 79 ..max.%....emory | 3184: 03 25 19 00 03 04 73 79 73 35 03 25 15 00 00 04 .%....sys5.%.... | 3200: 6f 6d 69 74 03 25 1b 00 00 05 72 74 72 65 65 03 omit.%....rtree. | 3216: 25 17 00 00 0a 74 68 72 65 61 64 73 61 66 65 03 %....threadsafe. | 3232: 25 1e 00 00 04 76 74 61 62 03 25 0b 00 86 50 01 %....vtab.%...P. | 3248: 08 08 08 08 08 17 8d 12 30 20 38 33 35 00 01 30 ........0 835..0 | 3264: 12 01 06 00 01 06 00 01 06 00 1f 03 00 01 03 00 ................ | 3280: 01 03 00 00 08 32 30 31 36 30 36 30 39 09 01 07 .....20160609... | 3296: 00 01 07 00 01 07 00 00 01 34 09 01 05 00 01 05 .........4...... | 3312: 00 01 05 00 00 01 35 09 01 04 00 01 04 00 01 04 ......5......... | 3328: 00 01 07 30 30 30 30 30 30 30 09 1c 04 00 01 04 ...0000000...... | 3344: 00 01 04 00 00 06 62 69 6e 61 72 79 3c 03 01 02 ......binary<... | 3360: 02 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 ................ | 3376: 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 5f ..............._ | 3392: 03 01 02 02 00 03 01 02 02 00 03 01 02 02 00 03 ................ | 3408: 01 02 02 00 03 01 02 02 00 00 08 63 6f 6d 70 69 ...........compi | 3424: 6c 65 72 09 01 02 00 01 02 00 01 02 00 00 06 64 ler............d | 3440: 62 73 74 61 74 09 07 03 00 01 03 00 01 03 00 01 bstat........... | 3456: 04 65 62 75 67 09 04 02 00 01 02 00 01 02 00 00 .ebug........... | 3472: 06 65 6e 61 62 6c 65 3f 07 02 00 01 02 00 01 02 .enable?........ | 3488: 00 01 02 00 01 02 00 01 02 00 01 02 00 01 02 00 ................ | 3504: 01 02 00 01 02 00 01 02 00 01 02 00 01 02 00 01 ................ | 3520: 02 00 01 01 00 01 02 00 01 02 00 01 02 00 01 02 ................ | 3536: 00 01 02 00 01 02 00 01 08 78 74 65 6e 73 69 6f .........xtensio | 3552: 6e 09 1f 04 00 01 04 00 01 04 00 00 04 66 74 73 n............fts | 3568: 34 09 0a 03 00 01 03 00 01 03 00 03 01 35 09 0d 4............5.. | 3584: 03 00 01 03 00 01 03 00 00 03 67 63 63 09 01 03 ..........gcc... | 3600: 00 01 03 00 01 03 00 01 06 65 6f 70 6f 6c 79 09 .........eopoly. | 3616: 10 03 00 01 03 00 01 03 00 00 05 6a 73 6f 6e 31 ...........json1 | 3632: 09 13 03 00 01 03 00 01 03 00 00 04 6c 6f 61 64 ............load | 3648: 09 1f 03 00 01 03 00 01 03 00 00 03 6d 61 78 09 ............max. | 3664: 1c 02 00 01 02 00 01 02 00 01 05 65 6d 6f 72 79 ...........emory | 3680: 09 1c 03 00 01 03 00 01 03 00 03 04 73 79 73 35 ............sys5 | 3696: 09 16 03 00 01 03 00 01 03 00 00 06 6e 6f 63 61 ............noca | 3712: 73 65 3c 02 01 02 02 00 03 01 02 02 00 03 01 02 se<............. | 3728: 02 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 ................ | 3744: 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 00 ................ | 3760: 03 01 02 02 00 03 01 02 02 00 03 01 02 02 00 00 ................ | 3776: 04 6f 6d 69 74 09 1f 02 00 01 02 00 01 02 00 00 .omit........... | 3792: 05 72 74 72 65 65 09 19 03 00 01 03 00 01 03 00 .rtree.......... | 3808: 03 02 69 6d 3c 01 01 02 02 00 03 01 02 02 00 03 ..im<........... | 3824: 01 02 02 00 03 01 02 02 00 03 01 02 02 00 03 01 ................ | 3840: 02 02 00 03 01 02 02 00 03 01 02 02 00 03 01 02 ................ | 3856: 02 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 ................ | 3872: 00 00 0a 74 68 72 65 61 64 73 61 66 65 09 22 02 ...threadsafe... | 3888: 00 01 02 00 01 02 00 00 04 76 74 61 62 09 07 04 .........vtab... | 3904: 00 01 04 00 01 04 00 00 01 78 b4 01 01 01 01 02 .........x...... | 3920: 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 ................ | 3936: 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 01 ................ | 3952: 01 01 03 00 01 01 01 02 00 01 01 01 02 00 01 01 ................ | 3968: 01 02 00 01 01 01 02 00 01 01 01 02 00 01 01 01 ................ | 3984: 02 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 ................ | 4000: 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 ................ | 4016: 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 01 ................ | 4032: 01 01 02 00 01 01 01 02 00 01 01 01 02 00 01 01 ................ | 4048: 01 02 00 01 01 01 02 00 01 01 01 02 00 01 01 01 ................ | 4064: 02 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 ................ | 4080: 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 ................ | page 6 offset 20480 | 0: 0a 00 00 00 02 0f f5 00 0f fb 0f f5 00 00 00 00 ................ | 4080: 00 00 00 00 00 05 04 08 09 01 02 04 04 08 08 09 ................ | page 7 offset 24576 | 0: 0d 00 00 00 05 0f b8 00 0f f4 0f e9 0f d6 00 00 ................ | 4016: 00 00 00 00 00 00 00 00 0d 05 02 23 61 75 74 6f ...........#auto | 4032: 6d 65 72 67 65 3d 35 0d 04 02 23 6d 65 72 67 65 merge=5...#merge | 4048: 3d 31 30 30 2c 38 11 03 02 2b 69 6e 74 65 67 72 =100,8...+integr | 4064: 69 74 79 2d 63 68 65 63 6b 09 02 02 1b 72 65 62 ity-check....reb | 4080: 75 69 6c 64 0a 01 02 1d 6f 70 74 69 6d 69 7a 65 uild....optimize | end crash-11cf359576eb28.db }]} {} set saved $sqlite_fts3_enable_parentheses set sqlite_fts3_enable_parentheses 1 do_catchsql_test 51.1 { SELECT 'xyzzy',offsets(t1) FROM t1 WHERE t1 MATCH 'rtree OR json1''rtree NEAR "json1 enable"'; } {1 {database disk image is malformed}} set sqlite_fts3_enable_parentheses $saved #------------------------------------------------------------------------- # reset_db do_test 52.0 { sqlite3 db {} db deserialize [decode_hexdb { .open --hexdb | size 28672 pagesize 4096 filename crash-fd33f4b1c8348b.db | page 1 offset 0 | 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3. | 16: 10 00 01 01 00 40 20 20 00 00 00 92 00 00 00 07 .....@ ........ | 32: 00 00 00 00 00 00 00 00 00 00 00 07 00 00 00 04 ................ | 96: 00 00 00 00 0d 0e ef 00 08 0d 13 00 0f bd 0f 5f ..............._ | 112: 0e f7 0e 06 0e bc 0d a4 0d 4d 0d 13 00 00 00 00 .........M...... | 3344: 00 00 00 38 08 06 17 11 11 08 5f 74 61 62 6c 65 ...8......_table | 3360: 74 32 74 32 43 52 45 41 54 45 20 56 49 52 54 55 t2t2CREATE VIRTU | 3376: 41 4c 20 54 41 42 4c 45 20 74 32 20 55 53 49 4e AL TABLE t2 USIN | 3392: 47 20 66 74 73 34 61 75 78 28 74 31 29 55 07 07 G fts4aux(t1)U.. | 3408: 17 1b 1b 01 81 01 74 61 62 6c 65 74 31 5f 73 74 ......tablet1_st | 3424: 61 74 74 31 5f 73 74 61 74 07 43 52 45 41 54 45 att1_stat.CREATE | 3440: 20 54 41 42 4c 45 20 27 74 31 5f 73 74 61 74 27 TABLE 't1_stat' | 3456: 28 69 64 20 49 4e 54 45 47 45 52 20 50 52 49 4d (id INTEGER PRIM | 3472: 41 52 59 20 4b 45 59 2c 20 76 61 6c 75 65 20 42 ARY KEY, value B | 3488: 4c 4f 42 29 60 06 07 17 21 21 01 81 0b 74 61 62 LOB)`...!!...tab | 3504: 6c 65 74 31 5f 64 6f 63 73 69 7a 65 74 31 5f 64 let1_docsizet1_d | 3520: 6f 63 73 69 7a 65 06 43 52 45 41 54 45 20 54 41 ocsize.CREATE TA | 3536: 42 4c 45 20 27 74 31 5f 64 6f 63 73 69 7a 65 27 BLE 't1_docsize' | 3552: 28 64 6f 63 69 64 20 49 4e 54 45 47 45 52 20 50 (docid INTEGER P | 3568: 52 49 4d 41 52 59 20 4b 45 59 2c 20 73 69 7a 65 RIMARY KEY, size | 3584: 20 42 4c 4f 42 29 81 33 04 07 17 1f 1f 01 82 35 BLOB).3.......5 | 3600: 74 61 62 6c 65 74 31 5f 73 65 67 64 69 72 74 31 tablet1_segdirt1 | 3616: 5f 73 65 67 64 69 72 04 43 52 45 41 54 45 20 54 _segdir.CREATE T | 3632: 41 42 4c 45 20 27 74 31 5f 73 65 67 64 69 72 27 ABLE 't1_segdir' | 3648: 28 6c 65 76 65 6c 20 49 4e 54 45 47 45 52 2c 69 (level INTEGER,i | 3664: 64 78 20 49 4e 64 45 47 45 52 2c 73 74 61 72 74 dx INdEGER,start | 3680: 5f 62 6c 6f 63 6b 20 49 4e 54 45 47 45 52 2c 6c _block INTEGER,l | 3696: 65 61 76 65 73 5f 65 6e 64 5f 62 6c 6f 63 6b 20 eaves_end_block | 3712: 49 4e 54 45 47 45 52 2c 65 6e 64 5f 62 6c 6f 63 INTEGER,end_bloc | 3728: 6b 20 49 4e 54 45 47 45 52 2c 72 6f 6f 74 20 42 k INTEGER,root B | 3744: 4c 4f 42 2c 50 52 49 4d 41 52 59 20 4b 45 59 28 LOB,PRIMARY KEY( | 3760: 6c 65 76 65 6c 2c 20 69 64 78 29 29 31 05 06 17 level, idx))1... | 3776: 45 1f 01 00 69 6e 64 65 78 73 71 6c 69 74 65 5f E...indexsqlite_ | 3792: 61 75 74 6f 69 6e 64 65 78 5f 74 31 5f 73 65 67 autoindex_t1_seg | 3808: 64 69 72 5f 31 74 31 5f 73 65 67 64 69 72 05 00 dir_1t1_segdir.. | 3824: 00 00 08 00 00 00 00 66 03 07 17 23 23 01 81 13 .......f...##... | 3840: 74 61 62 6c 65 74 31 5f 73 65 67 6d 65 6e 74 73 tablet1_segments | 3856: 74 31 5f 73 65 67 6d 65 6e 74 73 03 43 52 45 41 t1_segments.CREA | 3872: 54 45 20 54 41 42 4c 45 20 27 74 31 5f 73 65 67 TE TABLE 't1_seg | 3888: 6d 65 6e 74 73 27 28 62 6c 6f 63 6b 69 64 20 49 ments'(blockid I | 3904: 4e 54 45 47 45 52 20 50 52 49 4d 41 52 59 20 4b NTEGER PRIMARY K | 3920: 45 59 2c 20 62 6c 6f 63 6b 20 42 4c 4f 42 29 5c EY, block BLOB). | 3936: 02 07 17 21 21 01 81 03 74 61 62 6c 65 74 31 5f ...!!...tablet1_ | 3952: 63 6f 6e 74 65 6e 74 74 31 5f 63 6f 6e 74 65 6e contentt1_conten | 3968: 74 02 43 52 45 41 54 45 20 54 41 42 4c 45 20 27 t.CREATE TABLE ' | 3984: 74 31 5f 63 6f 6e 74 65 6e 74 27 28 64 6f 63 69 t1_content'(doci | 4000: 64 20 49 4e 54 45 47 45 52 e6 50 52 49 4d 41 52 d INTEGER.PRIMAR | 4016: 59 20 4b 45 59 2c 20 27 63 30 61 27 29 41 01 06 Y KEY, 'c0a')A.. | 4032: 17 11 11 08 71 74 61 62 6c 65 74 31 74 31 43 52 ....qtablet1t1CR | 4048: 45 41 54 45 20 56 49 52 54 55 41 4c 20 54 41 42 EATE VIRTUAL TAB | 4064: 4c 45 20 74 31 20 55 53 49 4e 47 20 66 74 73 34 LE t1 USING fts4 | 4080: 28 61 2c 70 72 65 66 69 78 3d 27 31 2c 32 27 29 (a,prefix='1,2') | page 2 offset 4096 | 0: 0d 00 00 00 08 0e 22 00 0f c4 0f 00 00 00 00 00 ................ | 3616: 00 00 42 08 04 00 81 09 73 75 6e 74 20 69 6e 20 ..B.....sunt in | 3632: 63 75 6c 70 61 20 71 75 69 20 6f 66 66 69 63 69 culpa qui offici | 3648: 61 20 64 65 73 65 72 75 6e 74 20 6d 6f 6c 6c 69 a deserunt molli | 3664: 74 20 61 6e 69 6d 20 69 64 20 65 73 74 20 7c 61 t anim id est |a | 3680: 62 6f 72 75 6d 2e 32 07 03 00 6b 45 78 63 65 70 borum.2...kExcep | 3696: 74 65 75 72 20 73 69 6e 74 20 6f 63 63 61 65 63 teur sint occaec | 3712: 61 74 20 63 75 70 69 64 61 74 61 74 20 6e 6f 6e at cupidatat non | 3728: 20 70 72 6f 69 64 65 6e 74 2c 29 06 03 00 59 63 proident,)...Yc | 3744: 69 6c 6c 75 6d 20 64 6f 6c 6f 72 65 20 65 20 66 illum dolore e f | 3760: 75 67 69 61 74 20 6e 75 6c 6c 61 20 70 61 72 69 ugiat nulla pari | 3776: 61 74 75 72 2e 42 05 04 00 81 09 44 75 69 73 20 atur.B.....Duis | 3792: 61 75 74 65 20 69 72 75 72 65 20 64 6f 6c 6f 72 aute irure dolor | 3808: 20 69 6e 20 72 65 60 72 65 68 65 6e 64 65 72 69 in re`rehenderi | 3824: 74 20 69 6e 20 76 70 6c 75 70 74 61 74 65 20 76 t in vpluptate v | 3840: 65 6c 69 72 c0 65 73 73 65 29 04 03 00 59 6e 69 elir.esse)...Yni | 3856: 73 6a 20 75 74 20 61 6c 69 71 75 69 70 20 65 20 sj ut aliquip e | 3872: 65 20 63 6f 6d 6d 6f 64 6f 20 63 6f 6e 73 65 71 e commodo conseq | 3888: 75 61 74 2e 46 03 04 00 29 11 55 74 20 65 6e 69 uat.F...).Ut eni | 3904: 6d 20 61 64 20 6d 69 6e 69 6d 20 76 65 6e 69 61 m ad minim venia | 3920: 6d 2c 20 71 75 69 73 20 6e 6f 73 74 72 75 64 20 m, quis nostrud | 3936: 65 78 65 72 63 69 7a 71 74 69 6f 6e 20 75 6c 6c exercizqtion ull | 3952: 61 6d 63 6f 20 6c 61 62 6f 72 69 73 46 02 04 00 amco laborisF... | 3968: 81 11 73 65 64 20 64 6f 20 65 69 75 73 6d 6f 64 ..sed do eiusmod | 3984: 20 74 65 6d 70 6f 72 20 69 6e 63 69 64 69 64 75 tempor incididu | 4000: 6e 74 20 75 74 20 6c 61 62 6f 72 65 20 65 74 20 nt ut labore et | 4016: 64 6f 6c 6f 72 65 20 6d 61 67 6e 61 20 61 6c 69 dolore magna ali | 4032: 71 75 61 2e 3a 01 03 00 7b 4c 6f 72 65 6d 20 69 qua.:....Lorem i | 4048: 72 63 75 6d 20 64 6f 6c 6f 72 20 73 69 74 20 61 rcum dolor sit a | 4064: 6d 65 74 2c 20 63 6f 6e 78 65 63 74 65 64 75 72 met, conxectedur | 4080: 20 61 64 69 70 69 73 00 00 00 00 00 00 00 00 00 adipis......... | page 4 offset 12288 | 0: 0d 00 00 00 03 0a c1 00 0d 61 0c 54 0a c1 00 00 .........a.T.... | 2752: 00 83 10 03 08 02 08 08 08 17 86 0e 08 00 30 20 ..............0 | 2768: 33 38 35 00 02 61 64 06 01 08 00 02 04 00 01 01 385..ad......... | 2784: 6c 06 02 0c 00 02 04 00 01 01 6d 03 01 06 10 01 l.........m..... | 2800: 01 6e 03 08 09 00 01 01 75 03 05 03 00 00 02 63 .n......u......c | 2816: 69 03 06 02 00 01 01 6f 07 01 07 00 03 07 03 00 i......o........ | 2832: 01 01 75 06 75 05 00 01 04 00 00 02 64 65 03 08 ..u.u.......de.. | 2848: 07 00 01 01 6f 0d 01 04 00 01 03 09 00 03 05 00 ....o........... | 2864: 01 03 00 01 01 75 03 05 02 00 00 02 65 69 03 02 .....u......ei.. | 2880: 04 00 01 01 6c 03 01 44 00 01 01 6e 03 03 03 00 ....l..D...n.... | 2896: 01 01 73 06 05 0b 00 03 0b 00 01 01 74 03 02 09 ..s.........t... | 2912: 00 01 01 78 06 03 09 00 04 02 00 00 02 66 75 03 ...x.........fu. | 2928: 06 05 00 00 02 69 64 03 08 0a 00 01 01 6e 0a 02 .....id......n.. | 2944: 06 00 03 06 04 00 03 03 00 01 01 70 03 01 03 00 ...........p.... | 2960: 01 01 72 03 05 04 00 00 02 6c 61 09 02 08 00 01 ..r......la..... | 2976: 0b 00 05 0c 00 01 01 6f 03 01 02 00 00 02 6d 61 .......o......ma | 2992: 03 02 0b 00 01 01 69 03 03 05 00 01 01 6f 03 08 ......i......o.. | 3008: 08 00 00 02 6e 69 03 04 02 00 01 01 6f 06 03 08 ....ni......o... | 3024: 00 04 06 00 01 01 75 03 06 06 00 00 02 6f 63 03 ......u......oc. | 3040: 07 04 00 01 01 66 03 08 06 00 00 02 70 61 03 06 .....f......pa.. | 3056: 07 00 01 11 72 03 07 07 00 00 02 71 75 06 03 07 ....r......qu... | 3072: 00 05 05 00 00 02 72 65 03 05 07 00 00 02 73 65 ......re......se | 3088: 03 02 02 00 01 01 69 06 01 05 00 06 03 00 01 01 ......i......... | 3104: 75 03 08 02 00 00 02 74 65 03 02 05 00 00 02 75 u......te......u | 3120: 6c 13 03 0a 00 01 01 74 09 02 07 00 01 02 00 01 l......t........ | 3136: 02 ff ff 02 76 65 06 03 06 00 02 0a 00 01 01 6f ....ve.........o | 3152: 03 05 09 00 82 0a 02 08 02 08 08 08 17 84 02 04 ................ | 3168: 00 30 20 32 35 31 00 01 61 13 01 06 04 00 01 0c .0 251..a....... | 3184: 00 01 04 00 01 04 00 01 03 00 03 09 00 00 01 63 ...............c | 3200: 10 01 07 00 03 07 03 00 02 02 00 01 05 00 01 04 ................ | 3216: 00 00 01 64 11 01 04 00 01 03 09 00 03 02 05 00 ...d............ | 3232: 01 03 00 02 07 00 00 01 65 1b 01 09 00 01 04 07 ........e....... | 3248: 00 01 03 08 00 01 05 03 00 01 1c eb 01 04 00 01 ................ | 3264: 0e 80 01 0b 00 00 01 66 03 06 05 00 00 01 69 0f .......f......i. | 3280: 01 03 00 01 06 0b 23 04 04 04 00 03 03 09 00 00 ......#......... | 3296: 01 6c 0c 01 02 00 01 08 00 01 0b 00 05 0c 00 00 .l.............. | 3312: 01 6d 09 02 0b 00 01 05 00 05 08 00 00 01 6e 0c .m............n. | 3328: 03 08 00 01 02 00 02 06 00 01 06 00 00 01 6f 06 ..............o. | 3344: 07 04 00 01 06 00 00 01 70 06 06 07 00 01 07 00 ........p....... | 3360: 00 01 71 06 03 07 00 05 05 00 00 01 72 03 05 07 ..q.........r... | 3376: 00 00 02 73 0c 01 05 00 01 02 00 05 03 00 01 02 ...s............ | 3392: 00 00 01 74 03 02 05 00 00 01 75 0a 02 07 00 01 ...t......u..... | 3408: 02 0a 00 01 03 00 00 01 76 07 03 06 00 02 09 03 ........v....... | 3424: 00 85 1c 01 08 08 08 08 08 17 8a 2a 30 20 36 35 ...........*0 65 | 3440: 35 00 02 61 64 03 03 04 00 02 08 69 70 69 73 63 5..ad......ipisc | 3456: 69 6e 67 03 01 08 00 01 05 6c 69 71 75 61 03 02 ing......liqua.. | 3472: 0c 00 05 02 69 70 03 04 04 00 01 03 6d 65 74 03 ....ip......met. | 3488: 01 06 00 01 03 6e 69 6d 03 08 09 00 01 03 75 74 .....nim......ut | 3504: 65 03 05 03 00 00 06 63 69 6c 6c 75 6d 03 06 02 e......cillum... | 3520: 00 01 06 6f 6d 6d 6f 64 6f 03 04 07 00 02 09 6e ...ommodo......n | 3536: 73 65 63 74 65 74 75 72 03 01 07 00 05 04 71 75 sectetur......qu | 3552: 61 73 03 04 08 00 01 04 75 6c 70 61 03 08 04 00 as......ulpa.... | 3568: 02 07 70 69 64 61 74 61 74 03 07 05 00 00 08 64 ..pidatat......d | 3584: 65 73 65 72 75 6e 74 03 08 07 00 01 01 6f 03 09 eserunt......o.. | 3600: b3 00 02 03 6c 6f 72 06 01 04 00 04 05 00 05 01 ....lor......... | 3616: 65 06 02 0a 00 04 03 00 01 03 75 69 73 03 05 02 e.........uis... | 3632: 00 00 01 65 07 04 05 03 00 02 04 00 01 06 69 75 ...e..........iu | 3648: 73 6d 6f 64 03 02 04 00 01 03 6c 69 74 03 01 09 smod......lit... | 3664: 00 01 03 6e 69 6d 03 03 03 00 01 03 73 73 65 03 ...nim......sse. | 3680: 05 0b 00 02 01 74 03 08 0b 00 01 01 74 03 02 09 .....t......t... | 3696: 00 01 08 78 63 65 70 64 65 75 72 03 07 02 00 02 ...xcepdeur..... | 3712: 0a 65 72 63 69 74 61 74 69 6f 6e 03 03 09 00 00 .ercitation..... | 3728: 06 66 75 67 69 61 74 03 06 05 00 00 02 69 64 03 .fugiat......id. | 3744: 08 0a 00 01 01 6e 07 05 06 04 00 03 03 00 02 08 .....n.......... | 3760: 63 69 64 69 64 75 6e 74 03 02 06 00 01 04 70 73 cididunt......ps | 3776: 75 6c f3 01 03 00 01 04 72 75 72 65 03 05 04 00 ul......rure.... | 3792: 00 06 6c 61 62 6f 72 65 03 02 08 00 05 02 69 73 ..labore......is | 3808: 03 03 0b 00 05 02 75 6d 03 08 0c 00 01 04 6f 72 ......um......or | 3824: 65 6d 03 01 02 00 00 05 6d 61 67 6e 61 03 02 0b em......magna... | 3840: 00 01 04 69 6e 69 6d 03 03 05 00 01 05 6f 6c 6c ...inim......oll | 3856: 69 74 03 08 08 00 00 04 6e 69 73 69 03 04 02 00 it......nisi.... | 3872: 01 02 6f 6e 03 07 06 00 02 05 73 74 72 75 64 03 ..on......strud. | 3888: 03 08 00 01 04 75 6c 6c 61 03 06 06 00 00 08 6f .....ulla......o | 3904: 63 63 61 65 63 61 74 03 07 04 00 01 06 66 66 69 ccaecat......ffi | 3920: 63 69 61 03 08 06 00 00 08 70 61 72 69 61 74 75 cia......pariatu | 3936: 72 03 06 07 00 01 07 72 6f 69 64 65 6e 74 03 07 r......roident.. | 3952: 07 00 00 03 71 75 69 03 08 15 00 03 01 73 03 03 ....qui......s.. | 3968: 07 00 00 0d 72 65 70 72 65 68 65 6e 64 65 72 69 ....reprehenderi | 3984: 74 03 05 07 00 00 03 73 65 64 03 02 01 ff ff f0 t......sed...... | 4000: b9 6e 74 03 07 03 00 02 01 74 03 01 05 00 01 03 .nt......t...... | 4016: 75 6e 74 03 08 02 00 00 06 74 65 6d 70 6f 72 03 unt......tempor. | 4032: 02 05 00 00 07 75 6c 6c 61 6d 63 6f 03 03 0a 00 .....ullamco.... | 4048: 01 01 74 09 02 07 00 01 02 00 01 03 00 00 05 76 ..t............v | 4064: 65 6c 69 74 03 05 0a 00 02 04 6e 69 61 6d 03 03 elit......niam.. | 4080: 06 00 01 08 6f 6c 75 70 74 61 74 65 03 05 09 00 ....oluptate.... | page 5 offset 16384 | 0: 0a 00 00 00 03 0f eb 00 0f fb 0f f3 00 00 00 00 ................ | 4064: 00 00 00 00 00 00 00 00 00 00 00 07 04 02 08 01 ................ | 4080: 08 00 03 07 04 02 08 01 04 00 02 04 04 08 08 09 ................ | page 6 offset 20480 | 0: 0d 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 ................ | 4048: 04 08 03 00 0e 0b 04 07 03 00 0e 06 04 06 03 00 ................ | 4064: 0e 06 04 05 03 00 0e 0a 04 04 03 00 0e 07 04 03 ................ | 4080: 03 00 0d fa 04 02 03 00 0e 0b 04 00 00 00 00 00 ................ | page 7 offset 24576 | 4080: 00 00 00 00 00 00 00 07 00 03 00 00 00 00 00 00 ................ | end crash-fd33f4b1c8348b.db }]} {} do_catchsql_test 52.1 { SELECT * FROM t1, t2; } {1 {database disk image is malformed}} finish_test |
Added test/fts3corrupt5.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 | # 2019 May 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. # #************************************************************************* # # set testdir [file dirname $argv0] source $testdir/tester.tcl source $testdir/fts3_common.tcl set testprefix fts3corrupt5 # If SQLITE_ENABLE_FTS3 is defined, omit this file. ifcapable !fts3 { finish_test return } sqlite3_fts3_may_be_corrupt 1 do_execsql_test 1.0 { BEGIN; CREATE VIRTUAL TABLE ft USING fts3(a, b, c); INSERT INTO ft VALUES('one', 'one', 'one'); COMMIT; } do_execsql_test 1.1 { SELECT * FROM ft WHERE ft MATCH 'b:one' } {one one one} do_execsql_test 1.2 { SELECT quote(root) FROM ft_segdir; } {X'00036F6E6509010201010201020200'} breakpoint foreach {tn val q bCorrupt} { 1 X'00036F6E650901' 'b:one' 1 2 X'00036F6E6509010201010201FFFFFF' 'c:one' 1 3 X'00036F6E6501' 'b:one' 1 4 X'00036F6E650101' 'b:one' 1 5 X'00036F6E650100' 'b:one' 0 } { do_execsql_test 1.3.$tn.1 "UPDATE ft_segdir SET root = $val" set res {0 {}} if {$bCorrupt} { set res {1 {database disk image is malformed}}} do_catchsql_test 1.3.$tn.2 { SELECT * FROM ft WHERE ft MATCH $q } $res } finish_test |
Added test/fts3corrupt6.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 | # 2020 June 8 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #************************************************************************* # This file implements regression tests for SQLite library. The # focus of this script is testing the FTS3 module. # set testdir [file dirname $argv0] source $testdir/tester.tcl source $testdir/fts3_common.tcl set testprefix fts3corrupt6 # If SQLITE_ENABLE_FTS3 is defined, omit this file. ifcapable !fts3 { finish_test return } set ::saved_sqlite_fts3_enable_parentheses $::sqlite_fts3_enable_parentheses set sqlite_fts3_enable_parentheses 1 sqlite3_fts3_may_be_corrupt 1 database_may_be_corrupt do_execsql_test 1.0 { BEGIN TRANSACTION; CREATE TABLE t_content(col0 INTEGER); PRAGMA writable_schema=ON; CREATE VIRTUAL TABLE t0 USING fts3(col0 INTEGER PRIMARY KEY,col1 VARCHAR(8),col2 BINARY,col3 BINARY); INSERT INTO t0_content VALUES(0,NULL,NULL,NULL,NULL); INSERT INTO t0_segdir VALUES(0,0,0,0,'0 42',X'000131030102000103323334050101010200000461616161050101020200000462626262050101030200'); COMMIT; } do_execsql_test 1.1 { SELECT 0+matchinfo(t0,'yxyyxy') FROM t0 WHERE t0 MATCH CAST( x'2b0a312b0a312a312a2a0b5d0a0b0b0a312a0a0b0b0a312a0b310a392a0b0a27312a2a0b5d0a312a0b310a31315d0b310a312a316d2a0b313b15bceaa50a312a0b0a27312a2a0b5d0a312a0b310a312b0b2a310a312a0b2a0b2a0b2e5d0a0bff313336e34a2a312a0b0a3c310b0a0b4b4b0b4b2a4bec40322b2a0b310a0a312a0a0a0a0a0a0a0a0a0b310a312a2a2a0b5d0a0b0b0a312a0b310a312a0b0a4e4541530b310a5df5ced70a0a0a0a0a4f520a0a0a0a0a0a0a312a0b0a4e4541520b310a5d616161610a0a0a0a4f520a0a0a0a0a0a312b0a312a312a0a0a0a0a0a0a004a0b0a310b220a0b0a310a4a22310a0b0a7e6fe0e0e030e0e0e0e0e01176e02000e0e0e0e0e01131320226310a0b0a310a4a22310a0b0a310a766f8b8b4ee0e0300ae0090909090909090909090909090909090909090909090909090909090909090947aaaa540b09090909090909090909090909090909090909090909090909090909090909fae0e0f2f22164e0e0f273e07fefefef7d6dfafafafa6d6d6d6d' AS TEXT); } {0} do_execsql_test 1.2 { CREATE VIRTUAL TABLE t1 USING fts3(col0 INTEGER PRIMARY KEY,col1 VARCHAR(8),col2 BINARY,col3 BINARY); INSERT INTO t1_content VALUES(0,NULL,NULL,NULL,NULL); INSERT INTO t1_segdir VALUES(0,0,0,0,'0 42',X'000131030102000103323334050101010200000461616161050101020200000462626262050101030200'); } do_execsql_test 1.3 { SELECT 42+matchinfo(t1,'yxyyxy') FROM t1 WHERE t1 MATCH x'2b0a312b0a312a312a2a0b5d0a0b0b0a312a0a0b0b0a312a0b310a392a0b0a27312a2a0b5d0a312a0b310a31315d0b310a312a316d2a0b313b15bceaa50a312a0b0a27312a2a0b5d0a312a0b310a312b0b2a310a312a0b2a0b2a0b2e5d0a0bff313336e34a2a312a0b0a3c310b0a0b4b4b0b4b2a4bec40322b2a0b310a0a312a0a0a0a0a0a0a0a0a0b310a312a2a2a0b5d0a0b0b0a312a0b310a312a0b0a4e4541530b310a5df5ced70a0a0a0a0a4f520a0a0a0a0a0a0a312a0b0a4e4541520b310a5d616161610a0a0a0a4f520a0a0a0a0a0a312b0a312a312a0a0a0a0a0a0a004a0b0a310b220a0b0a310a4a22310a0b0a7e6fe0e0e030e0e0e0e0e01176e02000e0e0e0e0e01131320226310a0b0a310a4a22310a0b0a310a766f8b8b4ee0e0300ae0090909090909090909090909090909090909090909090909090909090909090947aaaa540b09090909090909090909090909090909090909090909090909090909090909fae0e0f2f22164e0e0f273e07fefefef7d6dfafafafa6d6d6d6d'; } {42} #------------------------------------------------------------------------- reset_db do_execsql_test 2.0 { CREATE VIRTUAL TABLE t0 USING fts3(a); INSERT INTO t0_segdir VALUES(0,0,0,0,'0 42',X'000131030782000103323334050100fff200010461616161050101020200000462626262050101030200'); } do_execsql_test 2.1 { SELECT count(*) FROM t0 WHERE t0 MATCH '(1 NEAR 1) AND (aaaa OR 1)'; } 1 #------------------------------------------------------------------------- reset_db do_execsql_test 3.0 { CREATE VIRTUAL TABLE main.Table0 USING fts3(); INSERT INTO Table0 VALUES (1), (printf('%8.1280000X') ), (1), (printf('%8.1280000X') ), (1) ; INSERT INTO Table0 VALUES (0), (printf('%8.1280000X%8.1280000X') ), (1), (printf('%1280000.1280000X%#1280000.1280000E%8.1280000X') ), (1) ; INSERT INTO Table0 VALUES (1) ; UPDATE Table0_segdir SET start_block = 1; INSERT INTO Table0 VALUES (1) ; INSERT INTO Table0(Table0) VALUES('merge=6,8'); } set sqlite_fts3_enable_parentheses $saved_sqlite_fts3_enable_parentheses finish_test |
Changes to test/fts3cov.test.
︙ | ︙ | |||
93 94 95 96 97 98 99 | do_test fts3cov-2.2 { set root [db one {SELECT root FROM t1_segdir}] read_fts3varint [string range $root 1 end] left_child execsql { DELETE FROM t1_segments WHERE blockid = $left_child } } {} do_error_test fts3cov-2.3 { SELECT * FROM t1 WHERE t1 MATCH 'c*' | | | | 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 | do_test fts3cov-2.2 { set root [db one {SELECT root FROM t1_segdir}] read_fts3varint [string range $root 1 end] left_child execsql { DELETE FROM t1_segments WHERE blockid = $left_child } } {} do_error_test fts3cov-2.3 { SELECT * FROM t1 WHERE t1 MATCH 'c*' } {database disk image is malformed} # Test the "replaced with NULL" case: do_test fts3cov-2.4 { execsql { INSERT INTO t1_segments VALUES($left_child, NULL) } } {} do_error_test fts3cov-2.5 { SELECT * FROM t1 WHERE t1 MATCH 'cloud' } {database disk image is malformed} #-------------------------------------------------------------------------- # The following tests are to test the effects of OOM errors while storing # terms in the pending-hash table. Specifically, while creating doclist # blobs to store in the table. More specifically, to test OOM errors while # appending column numbers to doclists. For example, if a doclist consists # of: |
︙ | ︙ |
Changes to test/fts3expr4.test.
︙ | ︙ | |||
64 65 66 67 68 69 70 | AND {PHRASE 3 0 lol+} {PHRASE 3 0 h4h+} } do_icu_expr_test 3.2 {*lOl* *h4h*} { AND {AND {AND {PHRASE 3 0 *} {PHRASE 3 0 lol+}} {PHRASE 3 0 *}} {PHRASE 3 0 h4h+} } | | | 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 | AND {PHRASE 3 0 lol+} {PHRASE 3 0 h4h+} } do_icu_expr_test 3.2 {*lOl* *h4h*} { AND {AND {AND {PHRASE 3 0 *} {PHRASE 3 0 lol+}} {PHRASE 3 0 *}} {PHRASE 3 0 h4h+} } do_simple_expr_test 3.3 { * } {} do_simple_expr_test 3.4 { *a } { PHRASE 3 0 a } do_simple_expr_test 3.5 { a*b } { AND {PHRASE 3 0 a+} {PHRASE 3 0 b} } do_simple_expr_test 3.6 { *a*b } { AND {PHRASE 3 0 a+} {PHRASE 3 0 b} } do_simple_expr_test 3.7 { *"abc" } { PHRASE 3 0 abc } do_simple_expr_test 3.8 { "abc"* } { PHRASE 3 0 abc } do_simple_expr_test 3.8 { "ab*c" } { PHRASE 3 0 ab+ c } |
︙ | ︙ |
Changes to test/fts3expr5.test.
︙ | ︙ | |||
17 18 19 20 21 22 23 24 25 26 27 28 29 30 | set testprefix fts3expr5 # If SQLITE_ENABLE_FTS3 is defined, omit this file. ifcapable !fts3 { finish_test return } #------------------------------------------------------------------------- # Various forms of empty phrase expressions. # do_execsql_test 1.0 { CREATE VIRTUAL TABLE t0 USING fts3(x); SELECT rowid FROM t0 WHERE x MATCH ''; | > > > > | 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | set testprefix fts3expr5 # If SQLITE_ENABLE_FTS3 is defined, omit this file. ifcapable !fts3 { finish_test return } proc test_fts3expr {expr} { db one {SELECT fts3_exprtest('simple', $expr, 'a', 'b', 'c')} } #------------------------------------------------------------------------- # Various forms of empty phrase expressions. # do_execsql_test 1.0 { CREATE VIRTUAL TABLE t0 USING fts3(x); SELECT rowid FROM t0 WHERE x MATCH ''; |
︙ | ︙ | |||
40 41 42 43 44 45 46 47 48 | } {} do_execsql_test 1.4 { SELECT rowid FROM t0 WHERE x MATCH '"" NOT ""'; } {} do_execsql_test 1.5 { SELECT rowid FROM t0 WHERE x MATCH '""""'; } {} finish_test | > > > > > > > > > > > > > > | 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | } {} do_execsql_test 1.4 { SELECT rowid FROM t0 WHERE x MATCH '"" NOT ""'; } {} do_execsql_test 1.5 { SELECT rowid FROM t0 WHERE x MATCH '""""'; } {} #------------------------------------------------------------------------- # Various forms of empty phrase expressions. # set sqlite_fts3_enable_parentheses 1 do_test 2.0 { test_fts3expr {(a:123)(b:234)()(c:456)} } {AND {AND {PHRASE 0 0 123} {PHRASE 1 0 234}} {PHRASE 2 0 456}} do_test 2.1 { test_fts3expr {(a:123)(b:234)(c:456)} } {AND {AND {PHRASE 0 0 123} {PHRASE 1 0 234}} {PHRASE 2 0 456}} do_test 2.2 { list [catch { test_fts3expr {"123" AND ( )} } msg] $msg } {1 {Error parsing expression}} finish_test |
Added test/fts3f.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 | # 2006 September 9 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #************************************************************************* # This file implements regression tests for SQLite library. The # focus of this script is testing the FTS3 module. # # $Id: fts3aa.test,v 1.1 2007/08/20 17:38:42 shess Exp $ # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix fts3f # If SQLITE_ENABLE_FTS3 is defined, omit this file. ifcapable !fts3 { finish_test return } do_execsql_test 1.0 { CREATE VIRTUAL TABLE ft USING fts3(x); BEGIN; INSERT INTO ft VALUES('a one'), ('b one'), ('c one'); } do_test 1.1 { set ret [list] db eval { SELECT docid FROM ft WHERE ft MATCH 'one' } { if { $docid==2 } { db eval COMMIT } lappend ret $docid } set ret } {1 2 3} do_execsql_test 1.2 { BEGIN; INSERT INTO ft VALUES('a one'), ('b one'), ('c one'); } do_execsql_test 1.3 { SELECT docid, optimize(ft) FROM ft WHERE ft MATCH 'one' } { 1 {Index optimized} 2 {Index already optimal} 3 {Index already optimal} 4 {Index already optimal} 5 {Index already optimal} 6 {Index already optimal} } finish_test |
Changes to test/fts3fault.test.
︙ | ︙ | |||
235 236 237 238 239 240 241 242 243 | do_faultsim_test 10.1 -prep { faultsim_delete_and_reopen } -body { execsql { CREATE VIRTUAL TABLE t1 USING fts4(a, b, languageid=d) } } -test { faultsim_test_result {0 {}} } finish_test | > > > > > > > > > > > > > > > > | 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 | do_faultsim_test 10.1 -prep { faultsim_delete_and_reopen } -body { execsql { CREATE VIRTUAL TABLE t1 USING fts4(a, b, languageid=d) } } -test { faultsim_test_result {0 {}} } #------------------------------------------------------------------------- reset_db do_execsql_test 11.0 { CREATE VIRTUAL TABLE t1 USING fts3(a, b); } faultsim_save_and_close do_faultsim_test 11 -faults oom* -prep { faultsim_restore_and_reopen } -body { execsql { DROP TABLE t1 } } -test { faultsim_test_result {0 {}} } finish_test |
Added test/fts3fuzz001.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 | # 2012-12-21 # # 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 corrupt database files. set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable !deserialize||!fts3 { finish_test return } database_may_be_corrupt do_test fts3fuzz001-100 { sqlite3 db {} db deserialize [decode_hexdb { | size 24576 pagesize 4096 filename c6.db | page 1 offset 0 | 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3. | 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 06 .....@ ........ | 32: 00 00 00 00 00 00 00 00 00 00 00 05 00 00 00 04 ................ | 48: 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 ................ | 96: 00 00 00 00 0d 0e f9 00 06 0d ec 00 0f cd 0f 69 ...............i | 112: 0f 01 0e 10 0e c6 0d ec 00 00 00 00 00 00 00 00 ................ | 3552: 00 00 00 00 00 00 00 00 00 00 00 00 22 06 06 17 ............"... | 3568: 11 11 01 31 74 61 62 6c 65 74 32 74 32 06 43 52 ...1tablet2t2.CR | 3584: 45 41 54 45 20 54 41 42 4c 45 20 74 32 28 78 29 EATE TABLE t2(x) | 3600: 81 33 04 07 17 1f 1f 01 82 35 74 61 62 6c 65 74 .3.......5tablet | 3616: 31 5f 73 65 67 64 69 72 74 31 5f 73 65 67 64 69 1_segdirt1_segdi | 3632: 72 04 43 52 45 41 54 45 20 54 41 42 4c 45 20 27 r.CREATE TABLE ' | 3648: 74 31 5f 73 65 67 64 69 72 27 28 6c 65 76 65 6c t1_segdir'(level | 3664: 20 49 4e 54 45 47 45 52 2c 69 64 78 20 49 4e 54 INTEGER,idx INT | 3680: 45 47 45 52 2c 73 74 61 72 74 5f 62 6c 6f 63 6b EGER,start_block | 3696: 20 49 4e 54 45 47 45 52 2c 6c 65 61 76 65 73 5f INTEGER,leaves_ | 3712: 65 6e 64 5f 62 6c 6f 63 6b 20 49 4e 54 45 47 45 end_block INTEGE | 3728: 52 2c 65 6e 64 5f 62 6c 6f 63 6b 20 49 4e 54 45 R,end_block INTE | 3744: 47 45 52 2c 72 6f 6f 74 20 42 4c 4f 42 2c 50 52 GER,root BLOB,PR | 3760: 49 4d 41 52 59 20 4b 45 59 28 6c 65 76 65 6c 2c IMARY KEY(level, | 3776: 20 69 64 78 29 29 31 05 06 17 45 1f 01 00 69 6e idx))1...E...in | 3792: 64 65 78 73 71 6c 69 74 65 5f 61 75 74 6f 69 6e dexsqlite_autoin | 3808: 64 65 78 5f 74 15 f7 36 56 76 46 97 25 f3 17 43 dex_t..6VvF.%..C | 3824: 15 5f 73 65 67 64 69 72 05 00 00 00 08 00 00 00 ._segdir........ | 3840: 00 66 03 07 17 23 23 01 81 13 74 61 62 6c 65 74 .f...##...tablet | 3856: 31 5f 73 65 67 6d 65 6e 74 73 74 31 5f 73 65 67 1_segmentst1_seg | 3872: 6d 65 6e 74 73 03 43 52 45 41 54 45 20 54 41 42 ments.CREATE TAB | 3888: 4c 45 20 27 74 31 5f 73 65 67 6d 65 6e 74 73 27 LE 't1_segments' | 3904: 28 62 6c 6f 63 6b 69 64 20 49 4e 54 45 47 45 52 (blockid INTEGER | 3920: 20 50 52 49 4d 41 52 59 20 4b 45 59 2c 20 62 6c PRIMARY KEY, bl | 3936: 6f 63 6b 20 42 4c 4f 42 29 62 02 07 17 21 21 01 ock BLOB)b...!!. | 3952: 81 0f 74 61 62 6c 65 74 31 5f 63 6f 6e 74 65 6e ..tablet1_conten | 3968: 74 74 31 5f 63 6f 6e 74 65 6e 74 02 43 52 45 41 tt1_content.CREA | 3984: 54 45 20 54 41 42 4c 45 20 27 74 31 5f 63 6f 6e TE TABLE 't1_con | 4000: 74 65 6e 74 27 28 64 6f 63 69 64 20 49 4e 54 45 tent'(docid INTE | 4016: 47 45 52 20 50 52 49 4d 41 52 59 20 4b 45 59 2c GER PRIMARY KEY, | 4032: 20 27 63 30 63 6f 6e 74 65 6e 74 27 29 31 01 06 'c0content')1.. | 4048: 17 11 11 08 51 74 61 62 6c 65 74 31 74 31 43 52 ....Qtablet1t1CR | 4064: 45 41 54 45 20 56 49 52 54 55 41 4c 20 54 41 42 EATE VIRTUAL TAB | 4080: 4c 45 20 74 31 20 55 53 49 4e 47 20 66 74 73 33 LE t1 USING fts3 | page 2 offset 4096 | 0: 0d 00 00 00 03 0f e0 00 0f f6 0f ec 0f e0 00 00 ................ | 4064: 0a 03 03 00 1b 61 62 61 6e 64 6f 6e 08 02 03 00 .....abandon.... | 4080: 17 61 62 61 66 74 08 01 03 00 17 61 62 61 63 6b .abaft.....aback | page 3 offset 8192 | 0: 0d 00 00 00 00 10 00 00 00 00 00 00 00 00 00 00 ................ | page 4 offset 12288 | 0: 0d 00 00 00 01 0f d6 00 0f 00 00 00 00 00 00 00 ................ | 4048: 00 00 00 00 00 00 28 01 07 08 08 08 08 15 46 30 ......(.......F0 | 4064: 20 32 39 00 05 61 62 61 63 6b 03 01 02 00 03 02 29..aback...... | 4080: 66 74 03 02 02 00 03 04 6e 64 6f 6e 03 03 02 00 ft......ndon.... | page 5 offset 16384 | 0: 0a 00 00 00 01 0f fb 00 0f fb 00 00 00 00 00 00 ................ | 4080: 00 00 00 00 00 00 00 00 00 00 00 04 04 08 08 09 ................ | page 6 offset 20480 | 0: 0d 00 00 00 05 0f b8 00 0f f4 0f e9 0f d6 0f c7 ................ | 16: 0f b8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ | 4016: 00 00 00 00 00 00 00 00 0d 05 02 23 61 75 74 6f ...........#auto | 4032: 6d 65 72 67 65 3d 35 0d 04 02 23 6d 65 72 67 65 merge=5...#merge | 4048: 3d 31 30 30 2c 38 11 03 02 2b 69 6e 74 65 67 72 =100,8...+integr | 4064: 69 74 79 3d 63 68 65 63 6b 09 02 02 1b 72 65 62 ity=check....reb | 4080: 75 69 6c 64 0a 01 02 1d 6f 70 74 69 6d 69 7a 65 uild....optimize | end c6.db }] catchsql { PRAGMA writable_schema=on; -- disable schema corruption detection INSERT INTO t1(t1) SELECT x FROM t2; } } {1 {database disk image is malformed}} do_test fts3fuzz001-110 { catchsql { INSERT INTO t1(t1) VALUES('integrity-check'); } } {1 {database disk image is malformed}} do_test fts3fuzz001-120 { catchsql { INSERT INTO t1(t1) VALUES('optimize'); } } {1 {database disk image is malformed}} do_test fts3fuzz001-121 { catchsql { INSERT INTO t1(t1) VALUES('integrity-check'); } } {1 {database disk image is malformed}} finish_test |
Changes to test/fts3join.test.
︙ | ︙ | |||
93 94 95 96 97 98 99 | do_eqp_test 4.2 { SELECT * FROM t4 LEFT JOIN ( SELECT docid, * FROM ft4 WHERE ft4 MATCH ? ) AS rr ON t4.rowid=rr.docid WHERE t4.y = ?; } { QUERY PLAN | | | | | | 93 94 95 96 97 98 99 100 101 102 103 104 105 106 | do_eqp_test 4.2 { SELECT * FROM t4 LEFT JOIN ( SELECT docid, * FROM ft4 WHERE ft4 MATCH ? ) AS rr ON t4.rowid=rr.docid WHERE t4.y = ?; } { QUERY PLAN |--MATERIALIZE rr | `--SCAN ft4 VIRTUAL TABLE INDEX 3: |--SCAN t4 `--SEARCH rr USING AUTOMATIC COVERING INDEX (docid=?) } finish_test |
Added test/fts3matchinfo2.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 | # 2020-05-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 implements regression tests for the FTS3 module. The focus # of this file is tables created with the "matchinfo=fts3" option. # set testdir [file dirname $argv0] source $testdir/tester.tcl # If SQLITE_ENABLE_FTS3 is not defined, omit this file. ifcapable !fts3 { finish_test ; return } set sqlite_fts3_enable_parentheses 1 # Crash case found by cyg0810 at gmail.com 2020-05-14. Reported to # chromium (which is not vulnerable) who kindly referred it to us. # do_execsql_test 1.0 { CREATE TABLE t_content(col0 INTEGER); CREATE VIRTUAL TABLE t0 USING fts3(col0 INTEGER PRIMARY KEY,col1 VARCHAR(8),col2 BINARY,col3 BINARY); INSERT INTO t0 VALUES (1, '1234','aaaa','bbbb'); SELECT hex(matchinfo(t0,'yxy')) FROM t0 WHERE t0 MATCH x'2b0a312b0a312a312a2a0b5d0a0b0b0a312a0a0b0b0a312a0b310a392a0b0a27312a2a0b5d0a312a0b310a31315d0b310a312a316d2a0b313b15bceaa50a312a0b0a27312a2a0b5d0a312a0b310a312b0b2a310a312a0b2a0b2a0b2e5d0a0bff313336e34a2a312a0b0a3c310b0a0b4b4b0b4b2a4bec40322b2a0b310a0a312a0a0a0a0a0a0a0a0a0b310a312a2a2a0b5d0a0b0b0a312a0b310a312a0b0a4e4541530b310a5df5ced70a0a0a0a0a4f520a0a0a0a0a0a0a312a0b0a4e4541520b310a5d616161610a0a0a0a4f520a0a0a0a0a0a312b0a312a312a0a0a0a0a0a0a004a0b0a310b220a0b0a310a4a22310a0b0a7e6fe0e0e030e0e0e0e0e01176e02000e0e0e0e0e01131320226310a0b0a310a4a22310a0b0a310a766f8b8b4ee0e0300ae0090909090909090909090909090909090909090909090909090909090909090947aaaa540b09090909090909090909090909090909090909090909090909090909090909fae0e0f2f22164e0e0f273e07fefefef7d6dfafafafa6d6d6d6d'; } {/000000.*0000000/} set sqlite_fts3_enable_parentheses 0 finish_test |
Changes to test/fts3misc.test.
︙ | ︙ | |||
222 223 224 225 226 227 228 229 230 | INSERT INTO t6 SELECT 'x x x x x x x x x x x' FROM s; COMMIT; } do_execsql_test 6.1 { SELECT rowid FROM t6 WHERE t6 MATCH 'b OR "x a"' } {50001 50002 50003 50004} finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | INSERT INTO t6 SELECT 'x x x x x x x x x x x' FROM s; COMMIT; } do_execsql_test 6.1 { SELECT rowid FROM t6 WHERE t6 MATCH 'b OR "x a"' } {50001 50002 50003 50004} #------------------------------------------------------------------------- # reset_db do_execsql_test 7.0 { CREATE VIRTUAL TABLE vt0 USING fts3(c0); INSERT INTO vt0 VALUES (x'00'); } do_execsql_test 7.1 { INSERT INTO vt0(vt0) VALUES('integrity-check'); } #------------------------------------------------------------------------- # Ticket [8a6fa2bb]. # reset_db do_execsql_test 7.0.1 { CREATE VIRTUAL TABLE vt0 USING fts4(c0, order=DESC); INSERT INTO vt0(c0) VALUES (0), (0); } do_execsql_test 7.0.2 { INSERT INTO vt0(vt0) VALUES('integrity-check'); } reset_db do_execsql_test 7.1.1 { CREATE VIRTUAL TABLE vt0 USING fts4(c0, order=ASC); INSERT INTO vt0(c0) VALUES (0), (0); } do_execsql_test 7.1.2 { INSERT INTO vt0(vt0) VALUES('integrity-check'); } do_execsql_test 7.2.1 { CREATE VIRTUAL TABLE ft USING fts4(c0, c1, order=DESC, prefix=1); INSERT INTO ft VALUES('a b c d', 'hello world'); INSERT INTO ft VALUES('negative', 'positive'); INSERT INTO ft VALUES('hello world', 'a b c d'); } do_execsql_test 7.2.2 { INSERT INTO vt0(vt0) VALUES('integrity-check'); } #------------------------------------------------------------------------- # Ticket [745f1abc]. # reset_db do_execsql_test 8.1 { CREATE VIRTUAL TABLE vt0 USING fts4(c0, prefix=1); } do_execsql_test 8.2 { BEGIN; INSERT INTO vt0 VALUES (0); INSERT INTO vt0(vt0) VALUES('optimize'); COMMIT; } do_execsql_test 8.3 { INSERT INTO vt0(vt0) VALUES('integrity-check'); } #------------------------------------------------------------------------- # reset_db do_execsql_test 9.0 { CREATE VIRTUAL TABLE t1 using fts4(mailcontent); insert into t1(rowid, mailcontent) values (-4764623217061966105, 'we are going to upgrade'), (8324454597464624651, 'we are going to upgrade'); } do_execsql_test 9.1 { INSERT INTO t1(t1) VALUES('integrity-check'); } do_execsql_test 9.2 { SELECT rowid FROM t1 WHERE t1 MATCH 'upgrade'; } { -4764623217061966105 8324454597464624651 } #------------------------------------------------------------------------- reset_db do_execsql_test 10.0 { CREATE VIRTUAL TABLE f USING fts3(a,b); CREATE TABLE 'f_stat'(id INTEGER PRIMARY KEY, value BLOB); INSERT INTO f_stat VALUES (1,x'3b3b3b3b3b3b3b28ffffffffffffffffff1807f9073481f1d43bc93b3b3b3b3b3b3b3b3b3b18073b3b3b3b3b3b3b9b003b'); } {} do_catchsql_test 10.1 { INSERT INTO f(f) VALUES ('merge=69,59'); } {1 {database disk image is malformed}} #------------------------------------------------------------------------- do_execsql_test 11.0 { CREATE VIRTUAL TABLE xyz USING fts3(); } do_execsql_test 11.1 { SELECT * FROM xyz WHERE xyz MATCH 'a NEAR/4294836224 a'; } finish_test |
Changes to test/fts3offsets.test.
︙ | ︙ | |||
113 114 115 116 117 118 119 120 121 122 123 | 6 {(A) x} 5 {(A) (B) (C)} 4 {(A) (B) (C) x x x x x x x B} 3 {(A) x x x x x x x x x C} 2 {(A) x x x x x x x x x x x B} 1 {(A) (B) (C)} } set sqlite_fts3_enable_parentheses 0 finish_test | > > > > > > > > > > > > | 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 | 6 {(A) x} 5 {(A) (B) (C)} 4 {(A) (B) (C) x x x x x x x B} 3 {(A) x x x x x x x x x C} 2 {(A) x x x x x x x x x x x B} 1 {(A) (B) (C)} } do_execsql_test 1.5.0 { CREATE VIRTUAL TABLE x1 USING fts3(x); INSERT INTO x1 VALUES('A A A'); INSERT INTO x1 VALUES('A A A'); } do_execsql_test 1.5.1 { SELECT offsets(x1) FROM x1 WHERE x1 MATCH 'a OR b AND c NEAR d' } { {0 0 0 1 0 0 2 1 0 0 4 1} {0 0 0 1 0 0 2 1 0 0 4 1} } set sqlite_fts3_enable_parentheses 0 finish_test |
Changes to test/fts3query.test.
︙ | ︙ | |||
115 116 117 118 119 120 121 | CREATE TABLE bt(title); } } {} do_eqp_test fts3query-4.2 { SELECT t1.number FROM t1, ft WHERE t1.number=ft.rowid ORDER BY t1.date } { QUERY PLAN | | | | | | | | | | 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 | CREATE TABLE bt(title); } } {} do_eqp_test fts3query-4.2 { SELECT t1.number FROM t1, ft WHERE t1.number=ft.rowid ORDER BY t1.date } { QUERY PLAN |--SCAN t1 USING COVERING INDEX i1 `--SCAN ft VIRTUAL TABLE INDEX 1: } do_eqp_test fts3query-4.3 { SELECT t1.number FROM ft, t1 WHERE t1.number=ft.rowid ORDER BY t1.date } { QUERY PLAN |--SCAN t1 USING COVERING INDEX i1 `--SCAN ft VIRTUAL TABLE INDEX 1: } do_eqp_test fts3query-4.4 { SELECT t1.number FROM t1, bt WHERE t1.number=bt.rowid ORDER BY t1.date } { QUERY PLAN |--SCAN t1 USING COVERING INDEX i1 `--SEARCH bt USING INTEGER PRIMARY KEY (rowid=?) } do_eqp_test fts3query-4.5 { SELECT t1.number FROM bt, t1 WHERE t1.number=bt.rowid ORDER BY t1.date } { QUERY PLAN |--SCAN t1 USING COVERING INDEX i1 `--SEARCH bt USING INTEGER PRIMARY KEY (rowid=?) } # Test that calling matchinfo() with the wrong number of arguments, or with # an invalid argument returns an error. # do_execsql_test 5.1 { |
︙ | ︙ |
Changes to test/fts3snippet.test.
︙ | ︙ | |||
551 552 553 554 555 556 557 558 559 560 561 562 | set x35 [string trim [string repeat "x " 35]] execsql "INSERT INTO t4 VALUES('$x35 E $x35 F $x35 G $x35');" llength [db one { SELECT snippet(t4, '', '', '', 0, 64) FROM t4 WHERE t4 MATCH 'E' }] } {64} set sqlite_fts3_enable_parentheses 0 finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | set x35 [string trim [string repeat "x " 35]] execsql "INSERT INTO t4 VALUES('$x35 E $x35 F $x35 G $x35');" llength [db one { SELECT snippet(t4, '', '', '', 0, 64) FROM t4 WHERE t4 MATCH 'E' }] } {64} do_test 4.3 { llength [db one { SELECT snippet(t4, '', '', '', 0, 150) FROM t4 WHERE t4 MATCH 'E' }] } {64} #------------------------------------------------------------------------- # Request a snippet from a query with more than 64 phrases. # do_execsql_test 5.0 { CREATE VIRTUAL TABLE t5 USING fts3(x); INSERT INTO t5 VALUES('a1 a2 a3'); INSERT INTO t5 VALUES('a4 a5 a6'); INSERT INTO t5 VALUES('a70 a71 a72'); } do_execsql_test 5.1 { SELECT snippet(t5, '[', ']') FROM t5 WHERE t5 MATCH 'a1 OR a2 OR a3 OR a4 OR a5 OR a6 OR a7 OR a8 OR a9 OR a10 OR ' || 'a11 OR a12 OR a13 OR a14 OR a15 OR a16 OR a17 OR a18 OR a19 OR a10 OR ' || 'a21 OR a22 OR a23 OR a24 OR a25 OR a26 OR a27 OR a28 OR a29 OR a20 OR ' || 'a31 OR a32 OR a33 OR a34 OR a35 OR a36 OR a37 OR a38 OR a39 OR a30 OR ' || 'a41 OR a42 OR a43 OR a44 OR a45 OR a46 OR a47 OR a48 OR a49 OR a40 OR ' || 'a51 OR a52 OR a53 OR a54 OR a55 OR a56 OR a57 OR a58 OR a59 OR a50 OR ' || 'a61 OR a62 OR a63 OR a64 OR a65 OR a66 OR a67 OR a68 OR a69 OR a60 OR ' || 'a71 OR a72 OR a73 OR a74 OR a75 OR a76 OR a77 OR a78 OR a79 OR a70' } { {[a1] [a2] [a3]} {[a4] [a5] [a6]} {[a70] [a71] [a72]} } set sqlite_fts3_enable_parentheses 0 finish_test |
Added test/fts3snippet2.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 | # 2020-05-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. # #************************************************************************* # # The tests in this file test the FTS3 auxillary functions offsets(), # snippet() and matchinfo() work. At time of writing, running this file # provides full coverage of fts3_snippet.c. # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix fts3snippet # If SQLITE_ENABLE_FTS3 is not defined, omit this file. ifcapable !fts3 { finish_test ; return } source $testdir/fts3_common.tcl set sqlite_fts3_enable_parentheses 1 #------------------------------------------------------------------------- # Request a snippet from a query with more than 64 phrases. # reset_db do_execsql_test 1.0 { CREATE VIRTUAL TABLE f USING fts3(b); INSERT INTO f VALUES ( x'746e6e6d64612e082a011065616e656d655a616c702a2f65732e0f42014001380230018218'); } do_execsql_test 1.1 { SELECT length(snippet(f))>0 FROM f WHERE b MATCH x'1065616e656d655a616c702a2f65732e0f42014001380230018218021001081e0a3d746e6e6d64612e082a010f42014001380230018218021001081e0a3d746e6e6d64612e082a011065616e656d655a616c702a2f65732e0f42014001380230018218021001081e0a3d746e6e6d64612e082a011065616e656d655a616c702a2f65732e0f42014001380230018218021001081e0a3d746e6e6d64612e082a011065616e656d655a616c702a2f0a3d746e6e6d64612e082a011065616e656d655a616c702a2f65732e0f42014001018218021001081e0a3d746e6e6d64612e082a011065616e656d655a616c702a018218021001081e0a3d746e6e6d64612e082a011065616e656d655a616c2a2f65732e0f42014001380230018218021001081e0a3d746e6e6d64612e082a011065616e656d655a616c702a2f65732e0f42014001380230018218021001081e0a3d746e6e6d64612e082a011065616e656d655a616c702a2f65732e0f42014001380230018218021001081e0a3d746e6e6d64612e082a011065616e656d655a616c702a2f65732e0f42014001380230018218021001081e0a3d746e6e6d64612e0f42'; } {1} reset_db do_execsql_test 2.0 { CREATE VIRTUAL TABLE t0 USING fts3(col0 INTEGER PRIMARY KEY,col1 VARCHAR(8),col2 BINARY,col3 BINARY); INSERT INTO t0 VALUES (1, '1234','aaaa','bbbb'); SELECT snippet(t0) FROM t0 WHERE t0 MATCH x'0a4d4d4d4d320a4f52d70a310a310a4e4541520a0a31f6ce0a4f520a0a310a310a310a4f520a75fc2a242424' ; } {<b>1</b>} reset_db do_execsql_test 2.1 { CREATE VIRTUAL TABLE t0 USING fts3( col0 INTEGER PRIMARY KEY,col1 VARCHAR(8),col2 BINARY,col3 BINARY ); INSERT INTO t0 VALUES ('one', '1234','aaaa','bbbb'); } do_execsql_test 2.2 { SELECT snippet(t0) FROM t0 WHERE t0 MATCH '(def AND (one NEAR abc)) OR one' } {<b>one</b>} set sqlite_fts3_enable_parentheses 0 finish_test |
Changes to test/fts3varint.test.
︙ | ︙ | |||
106 107 108 109 110 111 112 | 576460752303423487 576460752303423488 576460752303423489 } do_fts3_varint_test 2.60 { 1152921504606846975 1152921504606846976 1152921504606846977 } do_fts3_varint_test 2.61 { 2305843009213693951 2305843009213693952 2305843009213693953 } do_fts3_varint_test 2.62 { 4611686018427387903 4611686018427387904 4611686018427387905 } | > > | | | > | 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 | 576460752303423487 576460752303423488 576460752303423489 } do_fts3_varint_test 2.60 { 1152921504606846975 1152921504606846976 1152921504606846977 } do_fts3_varint_test 2.61 { 2305843009213693951 2305843009213693952 2305843009213693953 } do_fts3_varint_test 2.62 { 4611686018427387903 4611686018427387904 4611686018427387905 } if {![catch {fts3_test_varint 18446744073709551615}]} { do_fts3_varint_test 2.63 { 9223372036854775807 9223372036854775808 9223372036854775809 } do_fts3_varint_test 3.0 { 18446744073709551615 -18446744073709551615 } } finish_test |
Changes to test/fts4aa.test.
︙ | ︙ | |||
186 187 188 189 190 191 192 193 194 | set ii 0 foreach {q r} [array get fts4aa_res] { incr ii do_test fts4aa-4.$ii { db eval {SELECT docid FROM t1 WHERE words MATCH $::q ORDER BY docid} } $r } finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | set ii 0 foreach {q r} [array get fts4aa_res] { incr ii do_test fts4aa-4.$ii { db eval {SELECT docid FROM t1 WHERE words MATCH $::q ORDER BY docid} } $r } # 2019-11-16 https://bugs.chromium.org/p/chromium/issues/detail?id=1025472 # db close sqlite3 db :memory: do_execsql_test fts4aa-5.10 { CREATE VIRTUAL TABLE t1 USING fts4(a, b, c, d, e,f,g,h,i,j,k,l,m,n,o,p,q,r); INSERT INTO t1 VALUES('X Y', '2', '3', '4', '5', '6', '7', '8', '9', '0', 'a','b','c','d','e','f','g','h'); UPDATE t1_docsize SET size=x'88' WHERE docid=1; } {} do_catchsql_test fts4aa-5.20 { SELECT quote(matchinfo(t1, 'l')) FROM t1 WHERE t1 MATCH 'X Y'; } {1 {database disk image is malformed}} do_execsql_test fts4aa-5.30 { DROP TABLE t1; CREATE VIRTUAL TABLE t1 USING fts4(a,b,c,d); INSERT INTO t1 VALUES('one two','three four','five six','seven eight'); } {} do_catchsql_test fts4aa-5.40 { UPDATE t1_stat SET value=x'01010101' WHERE id=0; SELECT quote(matchinfo(t1,'a')) FROM t1 WHERE t1 MATCH 'one two'; } {1 {database disk image is malformed}} do_catchsql_test fts4aa-5.50 { UPDATE t1_stat SET value=x'010101' WHERE id=0; SELECT quote(matchinfo(t1,'a')) FROM t1 WHERE t1 MATCH 'one two'; } {1 {database disk image is malformed}} do_catchsql_test fts4aa-5.60 { UPDATE t1_stat SET value=x'01' WHERE id=0; SELECT quote(matchinfo(t1,'a')) FROM t1 WHERE t1 MATCH 'one two'; } {1 {database disk image is malformed}} do_catchsql_test fts4aa-5.70 { UPDATE t1_stat SET value=x'' WHERE id=0; SELECT quote(matchinfo(t1,'a')) FROM t1 WHERE t1 MATCH 'one two'; } {1 {database disk image is malformed}} # 2019-11-18 https://bugs.chromium.org/p/chromium/issues/detail?id=1025467 db close sqlite3 db :memory: if {$tcl_platform(byteOrder)=="littleEndian"} { set res {X'0200000000000000000000000E0000000E00000001000000010000000100000001000000'} } else { set res {X'0000000200000000000000000000000E0000000E00000001000000010000000100000001'} } do_catchsql_test fts4aa-6.10 { CREATE VIRTUAL TABLE f USING fts4(); INSERT INTO f_segdir VALUES (77,91,0,0,'255 77',x'0001308000004d5c4ddddddd4d4d7b4d4d4d614d8019ff4d05000001204d4d2e4d6e4d4d4d4b4d6c4d004d4d4d4d4d4d3d000000004d5d4d4d645d4d004d4d4d4d4d4d4d4d4d454d6910004d05ffff054d646c4d004d5d4d4d4d4d3d000000004d4d4d4d4d4d4d4d4d4d4d69624d4d4d04004d4d4d4d4d604d4ce1404d554d45'); INSERT INTO f_segdir VALUES (77,108,0,0,'255 77',x'0001310000fa64004d4d4d3c5d4d654d4d4d614d8000ff4d05000001204d4d2e4d6e4d4d4dff4d4d4d4d4d4d00104d4d4d4d000000004d4d4d0400311d4d4d4d4d4d4d4d4d4d684d6910004d05ffff054d4d6c4d004d4d4d4d4d4d3d000000004d4d4d4d644d4d4d4d4d4d69624d4d4d03ed4d4d4d4d4d604d4ce1404d550080'); INSERT INTO f_stat VALUES (0,x'80808080100000000064004d4d4d3c4d4d654d4d4d614d8000ff4df6ff1a00204d4d2e4d6e4d4d4d104d4d4d4d4d4d00104d4d4d4d4d4d69574d4d4d000031044d4d4d3e4d4d4c4d05004d6910'); SELECT quote(matchinfo(f,'pnax')) from f where f match '0 1'; } {1 {database disk image is malformed}} # 2019-11-18 Detect infinite loop in fts3SelectLeaf() db close sqlite3 db :memory: do_catchsql_test fts4aa-7.10 { CREATE VIRTUAL TABLE f USING fts4(); INSERT INTO f_segdir VALUES (63,60,60,60,'60 60',x'3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c483c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c20003c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c283c3c3c3c3c3c3c3c3c3c3c223c3c3c3c3c3c3c3c3c'); INSERT INTO f_segments VALUES (60,x'3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c5a3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c2a3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c5e3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c803c3c3c3c3c3c233c3c3c3c1c3c3c3c3c3c3c3c3c3c3c3c1b3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c273c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c1a3c3c3c3c3c3c000200003c3c3c3c3c3c3c3c3c3c3c3c3c383c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d898d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d3c3c3c3c3c3c3c3c3c3cba3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c1c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c00023c3c3c3c3c3c383c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3cbc3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c2c3c3c3c403c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c16161616161616163c3c3c3c3c3c3c3c3c3c3c3c3c583c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c2b3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c1c013c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c20003c3c3c3c3c3c3c3c3c3c3c800000003c3c3c3c3c3c3c2c3c3c3c3c3c3c353c08080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808f4080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808083c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c323c3c3c3c3c3c3c3c3c3c3c4f3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3cfcfcfcfcfcfcfcfcfcfcfc10fcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfd02fcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfc03e8fcfcfcfc3c3c3c3c3c3c8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d8d3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c553c3c3c3c3c3c3c3c3c3c3c3c3c573c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c000000803c3c4dd5d5a6d52cf3d5d5d5d5d5d5d5d5d5d5d5d5d5d53c3c3c3c3f3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c2d3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c013c3c3c3c00643c3c3c3ce93c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c263c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c363c3c3c3c3c3c3c3c3c3c3c3c3c3c543c3c3c3c3c3c3c3c3c3c273c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c330000003c3c3c3c3c3c3c3c3c3c3c3c3c3c4d3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c000010003c3c3c3c3c3c413c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c1c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c403c3c3c3c3c3c3c3c3c3c3c3cec0000fa3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c2d3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c4c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c5e3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c1b3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c593c3c3c3c3c3c243c3c373c3c3c3c3cff3c3c3c3c3c3c3c3c3c3c3c3c3c000080003c3c3c3c3c3c3c3c3c3c353c3c3c3c3c3d3c3c3c3c3c3c3c3c3c3c3c3c4d3c3c3c3c3c3c3c3c3c3c3c3c3c40003c3c3c3c3c293c3c3c3c3c3c3c3c3c3d3c3c3c3c3c3c3c3c353c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c4f3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3f3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3cff7f3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c2d3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3ca43c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3cbf3c3c3c3c3c3c3c3c3c008000003c3c3c3c3c3c3c3c343c3c373c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c593c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c'); SELECT * from f where f match '0'; } {1 {database disk image is malformed}} finish_test |
Changes to test/fts4content.test.
︙ | ︙ | |||
629 630 631 632 633 634 635 636 637 638 | # Test cases 11.* # reset_db do_catchsql_test 11.1 { CREATE VIRTUAL TABLE x1 USING fts4(content=x1); } {1 {vtable constructor called recursively: x1}} finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | # Test cases 11.* # reset_db do_catchsql_test 11.1 { CREATE VIRTUAL TABLE x1 USING fts4(content=x1); } {1 {vtable constructor called recursively: x1}} #--------------------------------------------------------------------------- # Check that an fts4 table cannot be its own content table. # reset_db breakpoint do_execsql_test 12.1.1 { CREATE VIRTUAL TABLE t1 USING fts4(a, content=t1 ); INSERT INTO t1(rowid, a) VALUES(1, 'abc'); } do_catchsql_test 12.1.2 { SELECT * FROM t1; } {1 {SQL logic error}} do_catchsql_test 12.1.3 { SELECT * FROM t1('abc'); } {1 {SQL logic error}} do_catchsql_test 12.1.4 { SELECT count(*) FROM t1; } {1 {SQL logic error}} reset_db do_execsql_test 12.2.1 { CREATE VIRTUAL TABLE t1 USING fts4(a, content=t2 ); CREATE VIRTUAL TABLE t2 USING fts4(a, content=t1 ); INSERT INTO t1(rowid, a) VALUES(1, 'abc'); } do_catchsql_test 12.2.2 { SELECT * FROM t1; } {1 {SQL logic error}} do_catchsql_test 12.2.3 { SELECT * FROM t1('abc'); } {1 {SQL logic error}} do_catchsql_test 12.2.4 { SELECT count(*) FROM t1; } {1 {SQL logic error}} finish_test |
Changes to test/fts4langid.test.
︙ | ︙ | |||
485 486 487 488 489 490 491 492 | } {1 2 5} do_execsql_test 5.4.$lid.5 { SELECT count(*) FROM t6_segdir; SELECT count(*) FROM t6_segments; } {1 2} } finish_test | > > > > > > > > > > > > > > > | 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 | } {1 2 5} do_execsql_test 5.4.$lid.5 { SELECT count(*) FROM t6_segdir; SELECT count(*) FROM t6_segments; } {1 2} } reset_db do_execsql_test 6.0 { CREATE VIRTUAL TABLE vt0 USING fts4(c0, languageid="lid"); INSERT INTO vt0 VALUES ('a'), ('b'); BEGIN; UPDATE vt0 SET lid = 1 WHERE lid=0; } do_execsql_test 6.1 { INSERT INTO vt0(vt0) VALUES('integrity-check'); } do_execsql_test 6.2 { COMMIT; INSERT INTO vt0(vt0) VALUES('integrity-check'); } finish_test |
Changes to test/fts4merge.test.
︙ | ︙ | |||
322 323 324 325 326 327 328 | expr { ([db total_changes] - $x)>1 } } {0} do_test 7.5 { set x [db total_changes] execsql { INSERT INTO t1(t1) VALUES('merge=200,10') } expr { ([db total_changes] - $x)>1 } } {0} | | > > > > > > > > > > > > > > > | 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 | expr { ([db total_changes] - $x)>1 } } {0} do_test 7.5 { set x [db total_changes] execsql { INSERT INTO t1(t1) VALUES('merge=200,10') } expr { ([db total_changes] - $x)>1 } } {0} } #------------------------------------------------------------------------- # Test cases 8.* - ticket [bf1aab89]. # set testprefix fts4merge reset_db do_execsql_test 8.0 { CREATE VIRTUAL TABLE t1 USING fts4(a, order=DESC); INSERT INTO t1(a) VALUES (0); INSERT INTO t1(a) VALUES (0); UPDATE t1 SET a = NULL; } do_execsql_test 8.1 { INSERT INTO t1(t1) VALUES('merge=1,4'); } finish_test |
Added test/fts4merge5.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 | # 2019 October 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 implements regression tests for SQLite library. The # focus of this script is testing the FTS4 module. # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix fts4merge5 # If SQLITE_ENABLE_FTS3 is defined, omit this file. ifcapable !fts3 { finish_test return } source $testdir/genesis.tcl do_execsql_test 1.1 { CREATE TABLE t1(docid, words); } fts_kjv_genesis do_execsql_test 1.2 { CREATE VIRTUAL TABLE x1 USING fts3; INSERT INTO x1(x1) VALUES('nodesize=64'); INSERT INTO x1(x1) VALUES('maxpending=64'); } do_execsql_test 1.3 { INSERT INTO x1(docid, content) SELECT * FROM t1; } for {set tn 1} {1} {incr tn} { set tc1 [db total_changes] do_execsql_test 1.4.$tn.1 { INSERT INTO x1(x1) VALUES('merge=1,2'); } set tc2 [db total_changes] if {($tc2 - $tc1)<2} break do_execsql_test 1.4.$tn.1 { INSERT INTO x1(x1) VALUES('integrity-check'); } } finish_test |
Added test/fts4min.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 | # 2020 February 27 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #************************************************************************* # set testdir [file dirname $argv0] source $testdir/tester.tcl source $testdir/fts3_common.tcl set ::testprefix fts4min # If SQLITE_ENABLE_FTS3 is defined, omit this file. ifcapable !fts3 { finish_test return } #------------------------------------------------------------------ do_execsql_test 0.0 { CREATE TABLE t1(a NOT NULL, b); CREATE INDEX i1 ON t1(a); } do_execsql_test 1.0 { CREATE VIRTUAL TABLE ft USING fts3(c); INSERT INTO ft(docid, c) VALUES(22, 'hello world'); INSERT INTO ft(docid, c) VALUES(44, 'hello world'); INSERT INTO ft(docid, c) VALUES(11, 'hello world'); } do_eqp_test 1.1.1 { SELECT max(rowid) FROM ft } {VIRTUAL TABLE INDEX 0:DESC} do_eqp_test 1.1.2 { SELECT min(rowid) FROM ft } {VIRTUAL TABLE INDEX 0:ASC} do_execsql_test 1.2.1 { SELECT max(rowid) FROM ft } {44} do_execsql_test 1.2.2 { SELECT min(rowid) FROM ft } {11} finish_test |
Added test/fts4record.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 | # 2019 September 18 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #************************************************************************* # This file implements regression tests for SQLite library. The # focus of this script is testing the FTS4 module. # # set testdir [file dirname $argv0] source $testdir/tester.tcl source $testdir/fts3_common.tcl set testprefix fts4record # If SQLITE_ENABLE_FTS3 is defined, omit this file. ifcapable !fts3 { finish_test return } sqlite3_fts3_may_be_corrupt 1 do_execsql_test 1.0 { CREATE VIRTUAL TABLE t1 USING fts4(x); INSERT INTO t1 VALUES('terma terma terma termb'); } do_execsql_test 1.1 { SELECT quote(root) FROM t1_segdir } { X'00057465726D6105010203030004016203010500' } proc make_record_wrapper {args} { make_fts3record $args } db func record make_record_wrapper do_execsql_test 1.2 { select quote( record(0, 5, 'terma', 5, 1, 2, 3, 3, 0, 4, 1, 'b' , 3, 1, 5, 0 ) ); } { X'00057465726D6105010203030004016203010500' } do_execsql_test 1.3.1 { UPDATE t1_segdir SET root = record(0, 5, 'terma', 5, 1, 2, 3, 3, 0, 4, 1, 'b' , 3, 1, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 ); } do_catchsql_test 1.3.2 { SELECT snippet(t1) FROM t1 WHERE t1 MATCH 'term*' } {1 {database disk image is malformed}} do_execsql_test 1.4.1 { UPDATE t1_segdir SET root = record(0, 5, 'terma', 5, 1, 2, 3, 3, 0, 4, 1, 'b' , 4, 1, 5, 256, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 ); } do_catchsql_test 1.4.2 { SELECT snippet(t1) FROM t1 WHERE t1 MATCH 'term*' } {1 {database disk image is malformed}} do_execsql_test 1.4.3 { SELECT quote(root) FROM t1_segdir } { X'00057465726D610501020303000401620401058002010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010100' } do_execsql_test 1.5.1 { UPDATE t1_segdir SET root = record(0, 5, 'terma', 5, 1, 2, 3, 3, 0, 4, 1, 'b' , 4, 1, 5, 256, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 ); } do_catchsql_test 1.4.2 { SELECT snippet(t1) FROM t1 WHERE t1 MATCH 'term*' } {1 {database disk image is malformed}} do_execsql_test 1.4.3 { SELECT quote(root) FROM t1_segdir } { X'00057465726D610501020303000401620401058002010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010100' } do_execsql_test 1.5.1 { UPDATE t1_segdir SET root = X'00057465726D61050102030300040162040105FF00010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010100' } do_catchsql_test 1.5.2 { SELECT snippet(t1) FROM t1 WHERE t1 MATCH 'term*' } {1 {database disk image is malformed}} do_catchsql_test 1.5.3 { INSERT INTO t1(t1) VALUES('integrity-check'); } {1 {database disk image is malformed}} finish_test |
Added test/fts4rename.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 | # 2019 April 30 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #************************************************************************* # set testdir [file dirname $argv0] source $testdir/tester.tcl source $testdir/fts3_common.tcl set ::testprefix fts4rename # If SQLITE_ENABLE_FTS3 is defined, omit this file. ifcapable !fts3 { finish_test return } do_execsql_test 1.0 { CREATE VIRTUAL TABLE temp.t1 USING fts3(a); BEGIN; CREATE TABLE t2(x); } {} do_catchsql_test 1.1 { ALTER TABLE t1_content RENAME c0a TO docid; } {1 {error in table t1_content after rename: duplicate column name: docid}} do_catchsql_test 1.2 { UPDATE t1 SET Col0 = 1 ; } {1 {no such column: Col0}} do_catchsql_test 1.3 { ROLLBACK; DROP TABLE t1; } {0 {}} finish_test |
Changes to test/fts4umlaut.test.
︙ | ︙ | |||
18 19 20 21 22 23 24 | ifcapable !fts3 { finish_test return } do_execsql_test 1.0 { | | | 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | ifcapable !fts3 { finish_test return } do_execsql_test 1.0 { CREATE VIRTUAL TABLE t1 USING fts4(x, tokenize=unicode61); CREATE VIRTUAL TABLE t2 USING fts4( x, tokenize=unicode61 "remove_diacritics=2" ); } foreach {tn q res1 res2} { |
︙ | ︙ | |||
45 46 47 48 49 50 51 | } $res1 do_execsql_test 1.$tn.2 { DELETE FROM t1; INSERT INTO t1(rowid, x) VALUES (1, $q); SELECT count(*) FROM t1 WHERE t1 MATCH 'Ha Noi' } $res1 | | | < | 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | } $res1 do_execsql_test 1.$tn.2 { DELETE FROM t1; INSERT INTO t1(rowid, x) VALUES (1, $q); SELECT count(*) FROM t1 WHERE t1 MATCH 'Ha Noi' } $res1 do_execsql_test 1.$tn.3 { DELETE FROM t2; INSERT INTO t2(rowid, x) VALUES (1, 'Ha Noi'); SELECT count(*) FROM t2 WHERE t2 MATCH $q } $res2 do_execsql_test 1.$tn.4 { DELETE FROM t2; INSERT INTO t2(rowid, x) VALUES (1, $q); SELECT count(*) FROM t2 WHERE t2 MATCH 'Ha Noi' } $res2 } finish_test |
Changes to test/fts4unicode.test.
︙ | ︙ | |||
562 563 564 565 566 567 568 569 570 | CREATE VIRTUAL TABLE ft1 USING fts3tokenize( "unicode61", "tokenchars=@.", "separators=1234567890" ); SELECT token FROM ft1 WHERE input = 'berlin@street123sydney.road'; } { berlin@street sydney.road } finish_test | > > > > > > > > > > > > > > > > > > | 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 | CREATE VIRTUAL TABLE ft1 USING fts3tokenize( "unicode61", "tokenchars=@.", "separators=1234567890" ); SELECT token FROM ft1 WHERE input = 'berlin@street123sydney.road'; } { berlin@street sydney.road } # Test for embedded nul characters in fts4 unicode index. # do_execsql_test 12.0 { CREATE VIRTUAL TABLE t12 USING fts4(tokenize=unicode61); INSERT INTO t12 VALUES('abc' || char(0) || 'def'); SELECT hex(CAST(content AS blob)) FROM t12; } {61626300646566} do_execsql_test 12.1 { INSERT INTO t12(t12) VALUES('integrity-check'); } {} do_execsql_test 12.2 { CREATE VIRTUAL TABLE t12aux USING fts4aux(t12); SELECT * FROM t12aux; } {abc * 1 1 abc 0 1 1} do_execsql_test 12.3 { SELECT hex(CAST(content AS blob)) FROM t12 WHERE t12 MATCH 'abc' } {61626300646566} finish_test |
Added test/fts4upfrom.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 | # 2020 February 24 # # 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 UPDATE statements with FROM clauses # against FTS4 tables. # # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix fts4upfrom # If SQLITE_ENABLE_FTS3 is defined, omit this file. ifcapable !fts3 { finish_test return } foreach {tn create_table} { 0 { CREATE VIRTUAL TABLE ft USING fts5(a, b, c) } 1 { CREATE VIRTUAL TABLE ft USING fts3(a, b, c) } 2 { CREATE TABLE ft(a, b, c) } 3 { CREATE TABLE real(a, b, c); CREATE INDEX i1 ON real(a); CREATE VIEW ft AS SELECT rowid, a, b, c FROM real; CREATE TRIGGER tr1 INSTEAD OF INSERT ON ft BEGIN INSERT INTO real(rowid, a, b, c) VALUES(new.rowid, new.a, new.b, new.c); END; CREATE TRIGGER tr2 INSTEAD OF UPDATE ON ft BEGIN UPDATE real SET rowid=new.rowid, a=new.a, b=new.b, c=new.c WHERE rowid=old.rowid; END; } } { if {$tn==0} { ifcapable !fts5 { continue } } catchsql { DROP VIEW IF EXISTS changes } catchsql { DROP TABLE IF EXISTS ft } catchsql { DROP VIEW IF EXISTS ft } execsql $create_table do_execsql_test 1.$tn.0 { INSERT INTO ft(a, b, c) VALUES('a', NULL, 'apple'); INSERT INTO ft(a, b, c) VALUES('b', NULL, 'banana'); INSERT INTO ft(a, b, c) VALUES('c', NULL, 'cherry'); INSERT INTO ft(a, b, c) VALUES('d', NULL, 'damson plum'); } do_execsql_test 1.$tn.1 { SELECT a, b, c FROM ft ORDER BY rowid; } { a {} apple b {} banana c {} cherry d {} {damson plum} } do_execsql_test 1.$tn.2 { UPDATE ft SET b=o.c FROM ft AS o WHERE (ft.a == char(unicode(o.a)+1)) } do_execsql_test 1.$tn.3 { SELECT a, b, c FROM ft ORDER BY rowid; } { a {} apple b apple banana c banana cherry d cherry {damson plum} } do_catchsql_test 1.$tn.4 { UPDATE ft SET c=v FROM changes WHERE a=k; } {1 {no such table: changes}} do_execsql_test 1.$tn.5 { create view changes(k, v) AS VALUES( 'd', 'dewberry' ) UNION ALL VALUES( 'c', 'clementine' ) UNION ALL VALUES( 'b', 'blueberry' ) UNION ALL VALUES( 'a', 'apricot' ) ; } do_execsql_test 1.$tn.6 { UPDATE ft SET c=v FROM changes WHERE a=k; } do_execsql_test 1.$tn.7 { SELECT rowid, a, b, c FROM ft ORDER BY rowid; } { 1 a {} apricot 2 b apple blueberry 3 c banana clementine 4 d cherry dewberry } do_execsql_test 1.$tn.8 " WITH x1(o, n) AS ( VALUES(1, 11) UNION ALL VALUES(2, 12) UNION ALL VALUES(3, 13) UNION ALL VALUES(4, 14) ) SELECT ft.rowid, a, b, c, o, n FROM ft, x1 WHERE ft.rowid = o; " { 1 a {} apricot 1 11 2 b apple blueberry 2 12 3 c banana clementine 3 13 4 d cherry dewberry 4 14 } set ROWID rowid if {$tn==1} { set ROWID docid } do_execsql_test 1.$tn.9 " WITH x1(o, n) AS ( VALUES(1, 11) UNION ALL VALUES(2, 12) UNION ALL VALUES(3, 13) UNION ALL VALUES(4, 14) ) UPDATE ft SET $ROWID = n FROM x1 WHERE ft.rowid = o; SELECT rowid, a, b, c FROM ft ORDER BY rowid; " { 11 a {} apricot 12 b apple blueberry 13 c banana clementine 14 d cherry dewberry } } finish_test |
Changes to test/func.test.
︙ | ︙ | |||
311 312 313 314 315 316 317 318 319 320 321 322 323 324 | } {99999999999995.0} do_test func-4.37 { execsql {SELECT round(9999999999999.55,1);} } {9999999999999.6} do_test func-4.38 { execsql {SELECT round(9999999999999.556,2);} } {9999999999999.56} } # Test the upper() and lower() functions # do_test func-5.1 { execsql {SELECT upper(t1) FROM tbl1} } {THIS PROGRAM IS FREE SOFTWARE} | > > > | 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 | } {99999999999995.0} do_test func-4.37 { execsql {SELECT round(9999999999999.55,1);} } {9999999999999.6} do_test func-4.38 { execsql {SELECT round(9999999999999.556,2);} } {9999999999999.56} do_test func-4.39 { string tolower [db eval {SELECT round(1e500), round(-1e500);}] } {inf -inf} } # Test the upper() and lower() functions # do_test func-5.1 { execsql {SELECT upper(t1) FROM tbl1} } {THIS PROGRAM IS FREE SOFTWARE} |
︙ | ︙ | |||
1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 | } {null} do_test func-22.21 { execsql {SELECT typeof(trim(NULL,'xyz'));} } {null} do_test func-22.22 { execsql {SELECT typeof(trim('hello',NULL));} } {null} # This is to test the deprecated sqlite3_aggregate_count() API. # ifcapable deprecated { do_test func-23.1 { sqlite3_create_aggregate db execsql { | > > > > > > > | 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 | } {null} do_test func-22.21 { execsql {SELECT typeof(trim(NULL,'xyz'));} } {null} do_test func-22.22 { execsql {SELECT typeof(trim('hello',NULL));} } {null} # 2021-06-15 - infinite loop due to unsigned character counter # overflow, reported by Zimuzo Ezeozue # do_execsql_test func-22.23 { SELECT trim('xyzzy',x'c0808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080'); } {xyzzy} # This is to test the deprecated sqlite3_aggregate_count() API. # ifcapable deprecated { do_test func-23.1 { sqlite3_create_aggregate db execsql { |
︙ | ︙ | |||
1387 1388 1389 1390 1391 1392 1393 1394 | } # Test char(). # do_execsql_test func-31.1 { SELECT char(), length(char()), typeof(char()) } {{} 0 text} finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | } # Test char(). # do_execsql_test func-31.1 { SELECT char(), length(char()), typeof(char()) } {{} 0 text} # sqlite3_value_frombind() # do_execsql_test func-32.100 { SELECT test_frombind(1,2,3,4); } {0} do_execsql_test func-32.110 { SELECT test_frombind(1,2,?,4); } {4} do_execsql_test func-32.120 { SELECT test_frombind(1,(?),4,?+7); } {2} do_execsql_test func-32.130 { DROP TABLE IF EXISTS t1; CREATE TABLE t1(a,b,c,e,f); INSERT INTO t1 VALUES(1,2.5,'xyz',x'e0c1b2a3',null); SELECT test_frombind(a,b,c,e,f,$xyz) FROM t1; } {32} do_execsql_test func-32.140 { SELECT test_frombind(a,b,c,e,f,$xyz+f) FROM t1; } {0} do_execsql_test func-32.150 { SELECT test_frombind(x.a,y.b,x.c,:123,y.e,x.f,$xyz+y.f) FROM t1 x, t1 y; } {8} # 2019-08-15 # Direct-only functions. # proc testdirectonly {x} {return [expr {$x*2}]} do_test func-33.1 { db func testdirectonly -directonly testdirectonly db eval {SELECT testdirectonly(15)} } {30} do_catchsql_test func-33.2 { CREATE VIEW v33(y) AS SELECT testdirectonly(15); SELECT * FROM v33; } {1 {unsafe use of testdirectonly()}} do_execsql_test func-33.3 { SELECT * FROM (SELECT testdirectonly(15)) AS v33; } {30} do_execsql_test func-33.4 { WITH c(x) AS (SELECT testdirectonly(15)) SELECT * FROM c; } {30} do_catchsql_test func-33.5 { WITH c(x) AS (SELECT * FROM v33) SELECT * FROM c; } {1 {unsafe use of testdirectonly()}} do_execsql_test func-33.10 { CREATE TABLE t33a(a,b); CREATE TABLE t33b(x,y); CREATE TRIGGER r1 AFTER INSERT ON t33a BEGIN INSERT INTO t33b(x,y) VALUES(testdirectonly(new.a),new.b); END; } {} do_catchsql_test func-33.11 { INSERT INTO t33a VALUES(1,2); } {1 {unsafe use of testdirectonly()}} ifcapable altertable { do_execsql_test func-33.20 { ALTER TABLE t33a RENAME COLUMN a TO aaa; SELECT sql FROM sqlite_master WHERE name='r1'; } {{CREATE TRIGGER r1 AFTER INSERT ON t33a BEGIN INSERT INTO t33b(x,y) VALUES(testdirectonly(new.aaa),new.b); END}} } # 2020-01-09 Yongheng fuzzer find # The bug is in the register-validity debug logic, not in the SQLite core # and as such it only impacts debug builds. Release builds work fine. # reset_db do_execsql_test func-34.10 { CREATE TABLE t1(a INT CHECK( datetime( 0, 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,a) ) ); INSERT INTO t1(a) VALUES(1),(2); SELECT * FROM t1; } {1 2} # 2020-03-11 COALESCE() should short-circuit # See also ticket 3c9eadd2a6ba0aa5 # Both issues stem from the fact that functions that could # throw exceptions were being factored out into initialization # code. The fix was to put those function calls inside of # OP_Once instead. # reset_db do_execsql_test func-35.100 { CREATE TABLE t1(x); SELECT coalesce(x, abs(-9223372036854775808)) FROM t1; } {} do_execsql_test func-35.110 { SELECT coalesce(x, 'xyz' LIKE printf('%.1000000c','y')) FROM t1; } {} do_execsql_test func-35.200 { CREATE TABLE t0(c0 CHECK(ABS(-9223372036854775808))); PRAGMA integrity_check; } {ok} finish_test |
Changes to test/func3.test.
︙ | ︙ | |||
149 150 151 152 153 154 155 156 157 158 159 160 161 162 | # the code generator optimizes away so that it consumes no CPU cycles at # run-time (that is, during calls to sqlite3_step()). # do_test func3-5.39 { db eval {EXPLAIN SELECT unlikely(min(1.0+'2.0',4*11))} } [db eval {EXPLAIN SELECT min(1.0+'2.0',4*11)}] # EVIDENCE-OF: R-23735-03107 The likely(X) function returns the argument # X unchanged. # do_execsql_test func3-5.50 { SELECT likely(9223372036854775807); } {9223372036854775807} | > > > > > > > > > > > > > | 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 | # the code generator optimizes away so that it consumes no CPU cycles at # run-time (that is, during calls to sqlite3_step()). # do_test func3-5.39 { db eval {EXPLAIN SELECT unlikely(min(1.0+'2.0',4*11))} } [db eval {EXPLAIN SELECT min(1.0+'2.0',4*11)}] # Unlikely() does not preserve the affinity of X. # ticket https://www.sqlite.org/src/tktview/0c620df60b # do_execsql_test func3-5.40 { SELECT likely(CAST(1 AS INT))=='1'; } 0 do_execsql_test func3-5.41 { SELECT unlikely(CAST(1 AS INT))=='1'; } 0 do_execsql_test func3-5.41 { SELECT likelihood(CAST(1 AS INT),0.5)=='1'; } 0 # EVIDENCE-OF: R-23735-03107 The likely(X) function returns the argument # X unchanged. # do_execsql_test func3-5.50 { SELECT likely(9223372036854775807); } {9223372036854775807} |
︙ | ︙ | |||
180 181 182 183 184 185 186 187 188 189 190 | # code generator optimizes away so that it consumes no CPU cycles at # run-time (that is, during calls to sqlite3_step()). # do_test func3-5.59 { db eval {EXPLAIN SELECT likely(min(1.0+'2.0',4*11))} } [db eval {EXPLAIN SELECT min(1.0+'2.0',4*11)}] finish_test | > > > > > > > > | 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 | # code generator optimizes away so that it consumes no CPU cycles at # run-time (that is, during calls to sqlite3_step()). # do_test func3-5.59 { db eval {EXPLAIN SELECT likely(min(1.0+'2.0',4*11))} } [db eval {EXPLAIN SELECT min(1.0+'2.0',4*11)}] # Test the outcome of specifying NULL xStep and xFinal pointers (normally # used to delete any existing function) and a non-NULL xDestroy when there # is no existing function to destroy. # do_test func3-6.0 { sqlite3_create_function_v2 db nofunc 1 utf8 } {} finish_test |
Changes to test/func4.test.
︙ | ︙ | |||
377 378 379 380 381 382 383 | x INTEGER CHECK(tointeger(x) IS NOT NULL) ); } {} do_test func4-3.2 { catchsql { INSERT INTO t1 (x) VALUES (NULL); } | | | | | | | | | | | | | | | | | | | | | | | | | 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 | x INTEGER CHECK(tointeger(x) IS NOT NULL) ); } {} do_test func4-3.2 { catchsql { INSERT INTO t1 (x) VALUES (NULL); } } {1 {CHECK constraint failed: tointeger(x) IS NOT NULL}} do_test func4-3.3 { catchsql { INSERT INTO t1 (x) VALUES (NULL); } } {1 {CHECK constraint failed: tointeger(x) IS NOT NULL}} do_test func4-3.4 { catchsql { INSERT INTO t1 (x) VALUES (''); } } {1 {CHECK constraint failed: tointeger(x) IS NOT NULL}} do_test func4-3.5 { catchsql { INSERT INTO t1 (x) VALUES ('bad'); } } {1 {CHECK constraint failed: tointeger(x) IS NOT NULL}} do_test func4-3.6 { catchsql { INSERT INTO t1 (x) VALUES ('1234bad'); } } {1 {CHECK constraint failed: tointeger(x) IS NOT NULL}} do_test func4-3.7 { catchsql { INSERT INTO t1 (x) VALUES ('1234.56bad'); } } {1 {CHECK constraint failed: tointeger(x) IS NOT NULL}} do_test func4-3.8 { catchsql { INSERT INTO t1 (x) VALUES (1234); } } {0 {}} do_test func4-3.9 { catchsql { INSERT INTO t1 (x) VALUES (1234.56); } } {1 {CHECK constraint failed: tointeger(x) IS NOT NULL}} do_test func4-3.10 { catchsql { INSERT INTO t1 (x) VALUES ('1234'); } } {0 {}} do_test func4-3.11 { catchsql { INSERT INTO t1 (x) VALUES ('1234.56'); } } {1 {CHECK constraint failed: tointeger(x) IS NOT NULL}} do_test func4-3.12 { catchsql { INSERT INTO t1 (x) VALUES (ZEROBLOB(4)); } } {1 {CHECK constraint failed: tointeger(x) IS NOT NULL}} do_test func4-3.13 { catchsql { INSERT INTO t1 (x) VALUES (X''); } } {1 {CHECK constraint failed: tointeger(x) IS NOT NULL}} do_test func4-3.14 { catchsql { INSERT INTO t1 (x) VALUES (X'1234'); } } {1 {CHECK constraint failed: tointeger(x) IS NOT NULL}} do_test func4-3.15 { catchsql { INSERT INTO t1 (x) VALUES (X'12345678'); } } {1 {CHECK constraint failed: tointeger(x) IS NOT NULL}} do_test func4-3.16 { catchsql { INSERT INTO t1 (x) VALUES ('1234.00'); } } {0 {}} do_test func4-3.17 { catchsql { INSERT INTO t1 (x) VALUES (1234.00); } } {0 {}} do_test func4-3.18 { catchsql { INSERT INTO t1 (x) VALUES ('-9223372036854775809'); } } {0 {}} if {$highPrecision(1)} { do_test func4-3.19 { catchsql { INSERT INTO t1 (x) VALUES (9223372036854775808); } } {1 {CHECK constraint failed: tointeger(x) IS NOT NULL}} } do_execsql_test func4-3.20 { SELECT x FROM t1 WHERE x>0 ORDER BY x; } {1234 1234 1234 1234} ifcapable floatingpoint { do_execsql_test func4-4.1 { CREATE TABLE t2( x REAL CHECK(toreal(x) IS NOT NULL) ); } {} do_test func4-4.2 { catchsql { INSERT INTO t2 (x) VALUES (NULL); } } {1 {CHECK constraint failed: toreal(x) IS NOT NULL}} do_test func4-4.3 { catchsql { INSERT INTO t2 (x) VALUES (NULL); } } {1 {CHECK constraint failed: toreal(x) IS NOT NULL}} do_test func4-4.4 { catchsql { INSERT INTO t2 (x) VALUES (''); } } {1 {CHECK constraint failed: toreal(x) IS NOT NULL}} do_test func4-4.5 { catchsql { INSERT INTO t2 (x) VALUES ('bad'); } } {1 {CHECK constraint failed: toreal(x) IS NOT NULL}} do_test func4-4.6 { catchsql { INSERT INTO t2 (x) VALUES ('1234bad'); } } {1 {CHECK constraint failed: toreal(x) IS NOT NULL}} do_test func4-4.7 { catchsql { INSERT INTO t2 (x) VALUES ('1234.56bad'); } } {1 {CHECK constraint failed: toreal(x) IS NOT NULL}} do_test func4-4.8 { catchsql { INSERT INTO t2 (x) VALUES (1234); } } {0 {}} do_test func4-4.9 { catchsql { |
︙ | ︙ | |||
529 530 531 532 533 534 535 | INSERT INTO t2 (x) VALUES ('1234.56'); } } {0 {}} do_test func4-4.12 { catchsql { INSERT INTO t2 (x) VALUES (ZEROBLOB(4)); } | | | | | | 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 | INSERT INTO t2 (x) VALUES ('1234.56'); } } {0 {}} do_test func4-4.12 { catchsql { INSERT INTO t2 (x) VALUES (ZEROBLOB(4)); } } {1 {CHECK constraint failed: toreal(x) IS NOT NULL}} do_test func4-4.13 { catchsql { INSERT INTO t2 (x) VALUES (X''); } } {1 {CHECK constraint failed: toreal(x) IS NOT NULL}} do_test func4-4.14 { catchsql { INSERT INTO t2 (x) VALUES (X'1234'); } } {1 {CHECK constraint failed: toreal(x) IS NOT NULL}} do_test func4-4.15 { catchsql { INSERT INTO t2 (x) VALUES (X'12345678'); } } {1 {CHECK constraint failed: toreal(x) IS NOT NULL}} do_execsql_test func4-4.16 { SELECT x FROM t2 ORDER BY x; } {1234.0 1234.0 1234.56 1234.56} } } ifcapable floatingpoint { |
︙ | ︙ |
Changes to test/func5.test.
︙ | ︙ | |||
49 50 51 52 53 54 55 56 57 | } {1 2 3 4 5 6 7 8} sqlite3_create_function db do_execsql_test func5-2.2 { SELECT x, y FROM t2 WHERE x+counter1('hello')=counter1('hello')+x ORDER BY +x; } {} do_execsql_test func5-2.3 { SELECT x, y FROM t2 | > | | 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | } {1 2 3 4 5 6 7 8} sqlite3_create_function db do_execsql_test func5-2.2 { SELECT x, y FROM t2 WHERE x+counter1('hello')=counter1('hello')+x ORDER BY +x; } {} set cvalue [db one {SELECT counter2('hello')+1}] do_execsql_test func5-2.3 { SELECT x, y FROM t2 WHERE x+counter2('hello')=$cvalue+x ORDER BY +x; } {1 2 3 4 5 6 7 8} finish_test |
Added test/func7.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 | # 2020-12-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. # #************************************************************************* # # Test cases for SQL functions based off the standard math library # set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable !mathlib { finish_test return } do_execsql_test func7-100 { SELECT ceil(99.9), ceiling(-99.01), floor(17), floor(-17.99); } {100.0 -99.0 17 -18.0} do_execsql_test func7-110 { SELECT quote(ceil(NULL)), ceil('-99.99'); } {NULL -99.0} do_execsql_test func7-200 { SELECT round(ln(5),2), log(100.0), log(100), log(2,'256'); } {1.61 2.0 2.0 8.0} do_execsql_test func7-210 { SELECT ln(-5), log(-5,100.0); } {{} {}} # Test cases derived from PostgreSQL documentation # do_execsql_test func7-pg-100 { SELECT abs(-17.4) } {17.4} do_execsql_test func7-pg-110 { SELECT ceil(42.2) } {43.0} do_execsql_test func7-pg-120 { SELECT ceil(-42.2) } {-42.0} do_execsql_test func7-pg-130 { SELECT round(exp(1.0),7) } {2.7182818} do_execsql_test func7-pg-140 { SELECT floor(42.8) } {42.0} do_execsql_test func7-pg-150 { SELECT floor(-42.8) } {-43.0} do_execsql_test func7-pg-160 { SELECT round(ln(2.0),7) } {0.6931472} do_execsql_test func7-pg-170 { SELECT log(100.0) } {2.0} do_execsql_test func7-pg-180 { SELECT log10(1000.0) } {3.0} do_execsql_test func7-pg-190 { SELECT log(2.0, 64.0) } {6.0} do_execsql_test func7-pg-200 { SELECT mod(9,4); } {1.0} do_execsql_test func7-pg-210 { SELECT round(pi(),7); } {3.1415927} do_execsql_test func7-pg-220 { SELECT power(9,3); } {729.0} do_execsql_test func7-pg-230 { SELECT round(radians(45.0),7); } {0.7853982} do_execsql_test func7-pg-240 { SELECT round(42.4); } {42.0} do_execsql_test func7-pg-250 { SELECT round(42.4382,2); } {42.44} do_execsql_test func7-pg-260 { SELECT sign(-8.4); } {-1} do_execsql_test func7-pg-270 { SELECT round( sqrt(2), 7); } {1.4142136} do_execsql_test func7-pg-280 { SELECT trunc(42.8), trunc(-42.8); } {42.0 -42.0} do_execsql_test func7-pg-300 { SELECT acos(1); } {0.0} do_execsql_test func7-pg-301 { SELECT degrees(acos(0.5)); } {60.0} do_execsql_test func7-pg-310 { SELECT round( asin(1), 7); } {1.5707963} do_execsql_test func7-pg-311 { SELECT degrees( asin(0.5) ); } {30.0} do_execsql_test func7-pg-320 { SELECT round( atan(1), 7); } {0.7853982} do_execsql_test func7-pg-321 { SELECT degrees( atan(1) ); } {45.0} do_execsql_test func7-pg-330 { SELECT round( atan2(1,0), 7); } {1.5707963} do_execsql_test func7-pg-331 { SELECT degrees( atan2(1,0) ); } {90.0} do_execsql_test func7-pg-400 { SELECT cos(0); } {1.0} do_execsql_test func7-pg-401 { SELECT cos( radians(60.0) ); } {0.5} do_execsql_test func7-pg-400 { SELECT cos(0); } {1.0} do_execsql_test func7-pg-410 { SELECT round( sin(1), 7); } {0.841471} do_execsql_test func7-pg-411 { SELECT sin( radians(30) ); } {0.5} do_execsql_test func7-pg-420 { SELECT round( tan(1), 7); } {1.5574077} do_execsql_test func7-pg-421 { SELECT tan( radians(45) ); } {1.0} do_execsql_test func7-pg-500 { SELECT round( sinh(1), 7); } {1.1752012} do_execsql_test func7-pg-510 { SELECT round( cosh(0), 7); } {1.0} do_execsql_test func7-pg-520 { SELECT round( tanh(1), 7); } {0.7615942} do_execsql_test func7-pg-530 { SELECT round( asinh(1), 7); } {0.8813736} do_execsql_test func7-pg-540 { SELECT round( acosh(1), 7); } {0.0} do_execsql_test func7-pg-550 { SELECT round( atanh(0.5), 7); } {0.5493061} # Test cases derived from MySQL documentation # do_execsql_test func7-mysql-100 { SELECT acos(1); } {0.0} do_execsql_test func7-mysql-110 { SELECT acos(1.0001); } {{}} do_execsql_test func7-mysql-120 { SELECT round( acos(0.0), 7); } {1.5707963} do_execsql_test func7-mysql-130 { SELECT round( asin(0.2), 7); } {0.2013579} do_execsql_test func7-mysql-140 { SELECT asin('foo'); } {{}} ;# Note: MySQL returns 0 here, not NULL. # SQLite deliberately returns NULL. # SQLServer and Oracle throw an error. do_execsql_test func7-mysql-150 { SELECT round( atan(2), 7), round( atan(-2), 7); } {1.1071487 -1.1071487} do_execsql_test func7-mysql-160 { SELECT round( atan2(-2,2), 7), round( atan2(pi(),0), 7); } {-0.7853982 1.5707963} do_execsql_test func7-mysql-170 { SELECT ceiling(1.23), ceiling(-1.23); } {2.0 -1.0} do_execsql_test func7-mysql-180 { SELECT cos(pi()); } {-1.0} do_execsql_test func7-mysql-190 { SELECT degrees(pi()), degrees(pi()/2); } {180.0 90.0} do_execsql_test func7-mysql-190 { SELECT round( exp(2), 7), round( exp(-2), 7), exp(0); } {7.3890561 0.1353353 1.0} do_execsql_test func7-mysql-200 { SELECT floor(1.23), floor(-1.23); } {1.0 -2.0} do_execsql_test func7-mysql-210 { SELECT round(ln(2),7), quote(ln(-2)); } {0.6931472 NULL} #do_execsql_test func7-mysql-220 { # SELECT round(log(2),7), log(-2); #} {0.6931472 NULL} # log() means natural logarithm in MySQL do_execsql_test func7-mysql-230 { SELECT log(2,65536), log(10,100), quote(log(1,100)), quote(log(0,100)); } {16.0 2.0 NULL NULL} do_execsql_test func7-mysql-240 { SELECT log2(65536), quote(log2(-100)), quote(log2(0)); } {16.0 NULL NULL} do_execsql_test func7-mysql-250 { SELECT round(log10(2),7), log10(100), quote(log10(-100)); } {0.30103 2.0 NULL} do_execsql_test func7-mysql-260 { SELECT mod(234,10), 253%7, mod(29,9), 29%9; } {4.0 1 2.0 2} do_execsql_test func7-mysql-270 { SELECT mod(34.5,3); } {1.5} do_execsql_test func7-mysql-280 { SELECT pow(2,2), pow(2,-2); } {4.0 0.25} do_execsql_test func7-mysql-281 { SELECT power(2,2), power(2,-2); } {4.0 0.25} do_execsql_test func7-mysql-290 { SELECT round(radians(90),7); } {1.5707963} do_execsql_test func7-mysql-300 { SELECT sign(-32), sign(0), sign(234); } {-1 0 1} do_execsql_test func7-mysql-310 { SELECT sin(pi()) BETWEEN -1.0e-15 AND 1.0e-15; } {1} do_execsql_test func7-mysql-320 { SELECT sqrt(4), round(sqrt(20),7), quote(sqrt(-16)); } {2.0 4.472136 NULL} do_execsql_test func7-mysql-330 { SELECT tan(pi()) BETWEEN -1.0e-15 AND 1.0e-15; } {1} do_execsql_test func7-mysql-331 { SELECT round(tan(pi()+1),7); } {1.5574077} finish_test |
Changes to test/fuzz_common.tcl.
︙ | ︙ | |||
359 360 361 362 363 364 365 366 367 368 369 370 371 372 | set ::fuzzyopts(-repeats) $::REPEATS array set ::fuzzyopts $args lappend ::fuzzyopts(-errorlist) {parser stack overflow} lappend ::fuzzyopts(-errorlist) {ORDER BY} lappend ::fuzzyopts(-errorlist) {GROUP BY} lappend ::fuzzyopts(-errorlist) {datatype mismatch} for {set ii 0} {$ii < $::fuzzyopts(-repeats)} {incr ii} { do_test ${testname}.$ii { set ::sql [subst $::fuzzyopts(-template)] puts $::log $::sql flush $::log set rc [catch {execsql $::sql} msg] | > | 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 | set ::fuzzyopts(-repeats) $::REPEATS array set ::fuzzyopts $args lappend ::fuzzyopts(-errorlist) {parser stack overflow} lappend ::fuzzyopts(-errorlist) {ORDER BY} lappend ::fuzzyopts(-errorlist) {GROUP BY} lappend ::fuzzyopts(-errorlist) {datatype mismatch} lappend ::fuzzyopts(-errorlist) {non-deterministic functions prohibited} for {set ii 0} {$ii < $::fuzzyopts(-repeats)} {incr ii} { do_test ${testname}.$ii { set ::sql [subst $::fuzzyopts(-template)] puts $::log $::sql flush $::log set rc [catch {execsql $::sql} msg] |
︙ | ︙ |
Changes to test/fuzzcheck.c.
1 2 3 4 5 6 7 8 9 10 11 12 13 | /* ** 2015-05-25 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** ** This is a utility program designed to aid running regressions tests on | | < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | /* ** 2015-05-25 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** ** This is a utility program designed to aid running regressions tests on ** the SQLite library using data from external fuzzers. ** ** This program reads content from an SQLite database file with the following ** schema: ** ** CREATE TABLE db( ** dbid INTEGER PRIMARY KEY, -- database id ** dbcontent BLOB -- database disk file image |
︙ | ︙ | |||
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 | ** tables. Then do "./fuzzcheck new.db" to run the tests. ** ** DEBUGGING HINTS: ** ** If fuzzcheck does crash, it can be run in the debugger and the content ** of the global variable g.zTextName[] will identify the specific XSQL and ** DB values that were running when the crash occurred. */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdarg.h> #include <ctype.h> #include "sqlite3.h" #define ISSPACE(X) isspace((unsigned char)(X)) #define ISDIGIT(X) isdigit((unsigned char)(X)) #ifdef __unix__ # include <signal.h> # include <unistd.h> #endif | > > > > > > > > > > > > > > > > < | | | < | | | | | 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 | ** tables. Then do "./fuzzcheck new.db" to run the tests. ** ** DEBUGGING HINTS: ** ** If fuzzcheck does crash, it can be run in the debugger and the content ** of the global variable g.zTextName[] will identify the specific XSQL and ** DB values that were running when the crash occurred. ** ** DBSQLFUZZ: (Added 2020-02-25) ** ** The dbsqlfuzz fuzzer includes both a database file and SQL to run against ** that database in its input. This utility can now process dbsqlfuzz ** input files. Load such files using the "--load-dbsql FILE ..." command-line ** option. ** ** Dbsqlfuzz inputs are ordinary text. The first part of the file is text ** that describes the content of the database (using a lot of hexadecimal), ** then there is a divider line followed by the SQL to run against the ** database. Because they are ordinary text, dbsqlfuzz inputs are stored ** in the XSQL table, as if they were ordinary SQL inputs. The isDbSql() ** function can look at a text string and determine whether or not it is ** a valid dbsqlfuzz input. */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdarg.h> #include <ctype.h> #include <assert.h> #include "sqlite3.h" #define ISSPACE(X) isspace((unsigned char)(X)) #define ISDIGIT(X) isdigit((unsigned char)(X)) #ifdef __unix__ # include <signal.h> # include <unistd.h> #endif #include <stddef.h> #if !defined(_MSC_VER) # include <stdint.h> #endif #if defined(_MSC_VER) typedef unsigned char uint8_t; #endif /* ** Files in the virtual file system. */ typedef struct VFile VFile; struct VFile { char *zFilename; /* Filename. NULL for delete-on-close. From malloc() */ int sz; /* Size of the file in bytes */ int nRef; /* Number of references to this file */ unsigned char *a; /* Content of the file. From malloc() */ }; typedef struct VHandle VHandle; struct VHandle { sqlite3_file base; /* Base class. Must be first */ VFile *pVFile; /* The underlying file */ }; |
︙ | ︙ | |||
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 | #define MX_FILE_SZ 10000000 /* ** All global variables are gathered into the "g" singleton. */ static struct GlobalVars { const char *zArgv0; /* Name of program */ VFile aFile[MX_FILE]; /* The virtual filesystem */ int nDb; /* Number of template databases */ Blob *pFirstDb; /* Content of first template database */ int nSql; /* Number of SQL scripts */ Blob *pFirstSql; /* First SQL script */ unsigned int uRandom; /* Seed for the SQLite PRNG */ char zTestName[100]; /* Name of current test */ } g; /* ** Print an error message and quit. */ static void fatalError(const char *zFormat, ...){ va_list ap; | > > > | < < | < | | > > > > > > > | > > | | 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 | #define MX_FILE_SZ 10000000 /* ** All global variables are gathered into the "g" singleton. */ static struct GlobalVars { const char *zArgv0; /* Name of program */ const char *zDbFile; /* Name of database file */ VFile aFile[MX_FILE]; /* The virtual filesystem */ int nDb; /* Number of template databases */ Blob *pFirstDb; /* Content of first template database */ int nSql; /* Number of SQL scripts */ Blob *pFirstSql; /* First SQL script */ unsigned int uRandom; /* Seed for the SQLite PRNG */ char zTestName[100]; /* Name of current test */ } g; /* ** Print an error message and quit. */ static void fatalError(const char *zFormat, ...){ va_list ap; fprintf(stderr, "%s", g.zArgv0); if( g.zDbFile ) fprintf(stderr, " %s", g.zDbFile); if( g.zTestName[0] ) fprintf(stderr, " (%s)", g.zTestName); fprintf(stderr, ": "); va_start(ap, zFormat); vfprintf(stderr, zFormat, ap); va_end(ap); fprintf(stderr, "\n"); exit(1); } /* ** signal handler */ #ifdef __unix__ static void signalHandler(int signum){ const char *zSig; if( signum==SIGABRT ){ zSig = "abort"; }else if( signum==SIGALRM ){ zSig = "timeout"; }else if( signum==SIGSEGV ){ zSig = "segfault"; }else{ zSig = "signal"; } fatalError(zSig); } #endif /* ** Set the an alarm to go off after N seconds. Disable the alarm ** if N==0 */ |
︙ | ︙ | |||
193 194 195 196 197 198 199 | static int progressHandler(void *pVdbeLimitFlag){ if( *(int*)pVdbeLimitFlag ) fatalError("too many VDBE cycles"); return 1; } #endif /* | | | 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 | static int progressHandler(void *pVdbeLimitFlag){ if( *(int*)pVdbeLimitFlag ) fatalError("too many VDBE cycles"); return 1; } #endif /* ** Reallocate memory. Show an error and quit if unable. */ static void *safe_realloc(void *pOld, int szNew){ void *pNew = realloc(pOld, szNew<=0 ? 1 : szNew); if( pNew==0 ) fatalError("unable to realloc for %d bytes", szNew); return pNew; } |
︙ | ︙ | |||
276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 | pNew->nRef = 0; pNew->sz = sz; pNew->a = safe_realloc(0, sz); if( sz>0 ) memcpy(pNew->a, pData, sz); return pNew; } /* ** Implementation of the "readfile(X)" SQL function. The entire content ** of the file named X is read and returned as a BLOB. NULL is returned ** if the file does not exist or is unreadable. */ static void readfileFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ const char *zName; FILE *in; long nIn; | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | > | | 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 | pNew->nRef = 0; pNew->sz = sz; pNew->a = safe_realloc(0, sz); if( sz>0 ) memcpy(pNew->a, pData, sz); return pNew; } /* Return true if the line is all zeros */ static int allZero(unsigned char *aLine){ int i; for(i=0; i<16 && aLine[i]==0; i++){} return i==16; } /* ** Render a database and query as text that can be input into ** the CLI. */ static void renderDbSqlForCLI( FILE *out, /* Write to this file */ const char *zFile, /* Name of the database file */ unsigned char *aDb, /* Database content */ int nDb, /* Number of bytes in aDb[] */ unsigned char *zSql, /* SQL content */ int nSql /* Bytes of SQL */ ){ fprintf(out, ".print ******* %s *******\n", zFile); if( nDb>100 ){ int i, j; /* Loop counters */ int pgsz; /* Size of each page */ int lastPage = 0; /* Last page number shown */ int iPage; /* Current page number */ unsigned char *aLine; /* Single line to display */ unsigned char buf[16]; /* Fake line */ unsigned char bShow[256]; /* Characters ok to display */ memset(bShow, '.', sizeof(bShow)); for(i=' '; i<='~'; i++){ if( i!='{' && i!='}' && i!='"' && i!='\\' ) bShow[i] = i; } pgsz = (aDb[16]<<8) | aDb[17]; if( pgsz==0 ) pgsz = 65536; if( pgsz<512 || (pgsz&(pgsz-1))!=0 ) pgsz = 4096; fprintf(out,".open --hexdb\n"); fprintf(out,"| size %d pagesize %d filename %s\n",nDb,pgsz,zFile); for(i=0; i<nDb; i += 16){ if( i+16>nDb ){ memset(buf, 0, sizeof(buf)); memcpy(buf, aDb+i, nDb-i); aLine = buf; }else{ aLine = aDb + i; } if( allZero(aLine) ) continue; iPage = i/pgsz + 1; if( lastPage!=iPage ){ fprintf(out,"| page %d offset %d\n", iPage, (iPage-1)*pgsz); lastPage = iPage; } fprintf(out,"| %5d:", i-(iPage-1)*pgsz); for(j=0; j<16; j++) fprintf(out," %02x", aLine[j]); fprintf(out," "); for(j=0; j<16; j++){ unsigned char c = (unsigned char)aLine[j]; fputc( bShow[c], stdout); } fputc('\n', stdout); } fprintf(out,"| end %s\n", zFile); }else{ fprintf(out,".open :memory:\n"); } fprintf(out,".testctrl prng_seed 1 db\n"); fprintf(out,".testctrl internal_functions\n"); fprintf(out,"%.*s", nSql, zSql); if( nSql>0 && zSql[nSql-1]!='\n' ) fprintf(out, "\n"); } /* ** Read the complete content of a file into memory. Add a 0x00 terminator ** and return a pointer to the result. ** ** The file content is held in memory obtained from sqlite_malloc64() which ** should be freed by the caller. */ static char *readFile(const char *zFilename, long *sz){ FILE *in; long nIn; unsigned char *pBuf; *sz = 0; if( zFilename==0 ) return 0; in = fopen(zFilename, "rb"); if( in==0 ) return 0; fseek(in, 0, SEEK_END); *sz = nIn = ftell(in); rewind(in); pBuf = sqlite3_malloc64( nIn+1 ); if( pBuf && 1==fread(pBuf, nIn, 1, in) ){ pBuf[nIn] = 0; fclose(in); return (char*)pBuf; } sqlite3_free(pBuf); *sz = 0; fclose(in); return 0; } /* ** Implementation of the "readfile(X)" SQL function. The entire content ** of the file named X is read and returned as a BLOB. NULL is returned ** if the file does not exist or is unreadable. */ static void readfileFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ long nIn; void *pBuf; const char *zName = (const char*)sqlite3_value_text(argv[0]); if( zName==0 ) return; pBuf = readFile(zName, &nIn); if( pBuf ){ sqlite3_result_blob(context, pBuf, nIn, sqlite3_free); } } /* ** Implementation of the "readtextfile(X)" SQL function. The text content ** of the file named X through the end of the file or to the first \000 ** character, whichever comes first, is read and returned as TEXT. NULL ** is returned if the file does not exist or is unreadable. */ static void readtextfileFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ const char *zName; FILE *in; long nIn; char *pBuf; zName = (const char*)sqlite3_value_text(argv[0]); if( zName==0 ) return; in = fopen(zName, "rb"); if( in==0 ) return; fseek(in, 0, SEEK_END); nIn = ftell(in); rewind(in); pBuf = sqlite3_malloc64( nIn+1 ); if( pBuf && 1==fread(pBuf, nIn, 1, in) ){ pBuf[nIn] = 0; sqlite3_result_text(context, pBuf, -1, sqlite3_free); }else{ sqlite3_free(pBuf); } fclose(in); } /* |
︙ | ︙ | |||
396 397 398 399 400 401 402 | while( p ){ pNext = p->pNext; free(p); p = pNext; } } | < | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | while( p ){ pNext = p->pNext; free(p); p = pNext; } } /* Return the current wall-clock time ** ** The number of milliseconds since the julian epoch. ** 1907-01-01 00:00:00 -> 210866716800000 ** 2021-01-01 00:00:00 -> 212476176000000 */ static sqlite3_int64 timeOfDay(void){ static sqlite3_vfs *clockVfs = 0; sqlite3_int64 t; if( clockVfs==0 ){ clockVfs = sqlite3_vfs_find(0); if( clockVfs==0 ) return 0; } if( clockVfs->iVersion>=1 && clockVfs->xCurrentTimeInt64!=0 ){ clockVfs->xCurrentTimeInt64(clockVfs, &t); }else{ double r; clockVfs->xCurrentTime(clockVfs, &r); t = (sqlite3_int64)(r*86400000.0); } return t; } /*************************************************************************** ** Code to process combined database+SQL scripts generated by the ** dbsqlfuzz fuzzer. */ /* An instance of the following object is passed by pointer as the ** client data to various callbacks. */ typedef struct FuzzCtx { sqlite3 *db; /* The database connection */ sqlite3_int64 iCutoffTime; /* Stop processing at this time. */ sqlite3_int64 iLastCb; /* Time recorded for previous progress callback */ sqlite3_int64 mxInterval; /* Longest interval between two progress calls */ unsigned nCb; /* Number of progress callbacks */ unsigned mxCb; /* Maximum number of progress callbacks allowed */ unsigned execCnt; /* Number of calls to the sqlite3_exec callback */ int timeoutHit; /* True when reaching a timeout */ } FuzzCtx; /* Verbosity level for the dbsqlfuzz test runner */ static int eVerbosity = 0; /* True to activate PRAGMA vdbe_debug=on */ static int bVdbeDebug = 0; /* Timeout for each fuzzing attempt, in milliseconds */ static int giTimeout = 10000; /* Defaults to 10 seconds */ /* Maximum number of progress handler callbacks */ static unsigned int mxProgressCb = 2000; /* Maximum string length in SQLite */ static int lengthLimit = 1000000; /* Maximum expression depth */ static int depthLimit = 500; /* Limit on the amount of heap memory that can be used */ static sqlite3_int64 heapLimit = 100000000; /* Maximum byte-code program length in SQLite */ static int vdbeOpLimit = 25000; /* Maximum size of the in-memory database */ static sqlite3_int64 maxDbSize = 104857600; /* OOM simulation parameters */ static unsigned int oomCounter = 0; /* Simulate OOM when equals 1 */ static unsigned int oomRepeat = 0; /* Number of OOMs in a row */ static void*(*defaultMalloc)(int) = 0; /* The low-level malloc routine */ /* This routine is called when a simulated OOM occurs. It is broken ** out as a separate routine to make it easy to set a breakpoint on ** the OOM */ void oomFault(void){ if( eVerbosity ){ printf("Simulated OOM fault\n"); } if( oomRepeat>0 ){ oomRepeat--; }else{ oomCounter--; } } /* This routine is a replacement malloc() that is used to simulate ** Out-Of-Memory (OOM) errors for testing purposes. */ static void *oomMalloc(int nByte){ if( oomCounter ){ if( oomCounter==1 ){ oomFault(); return 0; }else{ oomCounter--; } } return defaultMalloc(nByte); } /* Register the OOM simulator. This must occur before any memory ** allocations */ static void registerOomSimulator(void){ sqlite3_mem_methods mem; sqlite3_shutdown(); sqlite3_config(SQLITE_CONFIG_GETMALLOC, &mem); defaultMalloc = mem.xMalloc; mem.xMalloc = oomMalloc; sqlite3_config(SQLITE_CONFIG_MALLOC, &mem); } /* Turn off any pending OOM simulation */ static void disableOom(void){ oomCounter = 0; oomRepeat = 0; } /* ** Translate a single byte of Hex into an integer. ** This routine only works if h really is a valid hexadecimal ** character: 0..9a..fA..F */ static unsigned char hexToInt(unsigned int h){ #ifdef SQLITE_EBCDIC h += 9*(1&~(h>>4)); /* EBCDIC */ #else h += 9*(1&(h>>6)); /* ASCII */ #endif return h & 0xf; } /* ** The first character of buffer zIn[0..nIn-1] is a '['. This routine ** checked to see if the buffer holds "[NNNN]" or "[+NNNN]" and if it ** does it makes corresponding changes to the *pK value and *pI value ** and returns true. If the input buffer does not match the patterns, ** no changes are made to either *pK or *pI and this routine returns false. */ static int isOffset( const unsigned char *zIn, /* Text input */ int nIn, /* Bytes of input */ unsigned int *pK, /* half-byte cursor to adjust */ unsigned int *pI /* Input index to adjust */ ){ int i; unsigned int k = 0; unsigned char c; for(i=1; i<nIn && (c = zIn[i])!=']'; i++){ if( !isxdigit(c) ) return 0; k = k*16 + hexToInt(c); } if( i==nIn ) return 0; *pK = 2*k; *pI += i; return 1; } /* ** Decode the text starting at zIn into a binary database file. ** The maximum length of zIn is nIn bytes. Store the binary database ** file in space obtained from sqlite3_malloc(). ** ** Return the number of bytes of zIn consumed. Or return -1 if there ** is an error. One potential error is that the recipe specifies a ** database file larger than MX_FILE_SZ bytes. ** ** Abort on an OOM. */ static int decodeDatabase( const unsigned char *zIn, /* Input text to be decoded */ int nIn, /* Bytes of input text */ unsigned char **paDecode, /* OUT: decoded database file */ int *pnDecode /* OUT: Size of decoded database */ ){ unsigned char *a, *aNew; /* Database under construction */ int mx = 0; /* Current size of the database */ sqlite3_uint64 nAlloc = 4096; /* Space allocated in a[] */ unsigned int i; /* Next byte of zIn[] to read */ unsigned int j; /* Temporary integer */ unsigned int k; /* half-byte cursor index for output */ unsigned int n; /* Number of bytes of input */ unsigned char b = 0; if( nIn<4 ) return -1; n = (unsigned int)nIn; a = sqlite3_malloc64( nAlloc ); if( a==0 ){ fprintf(stderr, "Out of memory!\n"); exit(1); } memset(a, 0, (size_t)nAlloc); for(i=k=0; i<n; i++){ unsigned char c = (unsigned char)zIn[i]; if( isxdigit(c) ){ k++; if( k & 1 ){ b = hexToInt(c)*16; }else{ b += hexToInt(c); j = k/2 - 1; if( j>=nAlloc ){ sqlite3_uint64 newSize; if( nAlloc==MX_FILE_SZ || j>=MX_FILE_SZ ){ if( eVerbosity ){ fprintf(stderr, "Input database too big: max %d bytes\n", MX_FILE_SZ); } sqlite3_free(a); return -1; } newSize = nAlloc*2; if( newSize<=j ){ newSize = (j+4096)&~4095; } if( newSize>MX_FILE_SZ ){ if( j>=MX_FILE_SZ ){ sqlite3_free(a); return -1; } newSize = MX_FILE_SZ; } aNew = sqlite3_realloc64( a, newSize ); if( aNew==0 ){ sqlite3_free(a); return -1; } a = aNew; assert( newSize > nAlloc ); memset(a+nAlloc, 0, (size_t)(newSize - nAlloc)); nAlloc = newSize; } if( j>=(unsigned)mx ){ mx = (j + 4095)&~4095; if( mx>MX_FILE_SZ ) mx = MX_FILE_SZ; } assert( j<nAlloc ); a[j] = b; } }else if( zIn[i]=='[' && i<n-3 && isOffset(zIn+i, nIn-i, &k, &i) ){ continue; }else if( zIn[i]=='\n' && i<n-4 && memcmp(zIn+i,"\n--\n",4)==0 ){ i += 4; break; } } *pnDecode = mx; *paDecode = a; return i; } /* ** Progress handler callback. ** ** The argument is the cutoff-time after which all processing should ** stop. So return non-zero if the cut-off time is exceeded. */ static int progress_handler(void *pClientData) { FuzzCtx *p = (FuzzCtx*)pClientData; sqlite3_int64 iNow = timeOfDay(); int rc = iNow>=p->iCutoffTime; sqlite3_int64 iDiff = iNow - p->iLastCb; /* printf("time-remaining: %lld\n", p->iCutoffTime - iNow); */ if( iDiff > p->mxInterval ) p->mxInterval = iDiff; p->nCb++; if( rc==0 && p->mxCb>0 && p->mxCb<=p->nCb ) rc = 1; if( rc && !p->timeoutHit && eVerbosity>=2 ){ printf("Timeout on progress callback %d\n", p->nCb); fflush(stdout); p->timeoutHit = 1; } return rc; } /* ** Disallow debugging pragmas such as "PRAGMA vdbe_debug" and ** "PRAGMA parser_trace" since they can dramatically increase the ** amount of output without actually testing anything useful. ** ** Also block ATTACH if attaching a file from the filesystem. */ static int block_troublesome_sql( void *Notused, int eCode, const char *zArg1, const char *zArg2, const char *zArg3, const char *zArg4 ){ (void)Notused; (void)zArg2; (void)zArg3; (void)zArg4; if( eCode==SQLITE_PRAGMA ){ if( sqlite3_stricmp("busy_timeout",zArg1)==0 && (zArg2==0 || strtoll(zArg2,0,0)>100 || strtoll(zArg2,0,10)>100) ){ return SQLITE_DENY; }else if( eVerbosity==0 ){ if( sqlite3_strnicmp("vdbe_", zArg1, 5)==0 || sqlite3_stricmp("parser_trace", zArg1)==0 || sqlite3_stricmp("temp_store_directory", zArg1)==0 ){ return SQLITE_DENY; } }else if( sqlite3_stricmp("oom",zArg1)==0 && zArg2!=0 && zArg2[0]!=0 ){ oomCounter = atoi(zArg2); } }else if( eCode==SQLITE_ATTACH ){ /* Deny the ATTACH if it is attaching anything other than an in-memory ** database. */ if( zArg1==0 ) return SQLITE_DENY; if( strcmp(zArg1,":memory:")==0 ) return SQLITE_OK; if( sqlite3_strglob("file:*[?]vfs=memdb", zArg1)==0 && sqlite3_strglob("file:*[^/a-zA-Z0-9_.]*[?]vfs=memdb", zArg1)!=0 ){ return SQLITE_OK; } return SQLITE_DENY; } return SQLITE_OK; } /* ** Run the SQL text */ static int runDbSql(sqlite3 *db, const char *zSql){ int rc; sqlite3_stmt *pStmt; while( isspace(zSql[0]&0x7f) ) zSql++; if( zSql[0]==0 ) return SQLITE_OK; if( eVerbosity>=4 ){ printf("RUNNING-SQL: [%s]\n", zSql); fflush(stdout); } rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0); if( rc==SQLITE_OK ){ while( (rc = sqlite3_step(pStmt))==SQLITE_ROW ){ if( eVerbosity>=5 ){ int j; for(j=0; j<sqlite3_column_count(pStmt); j++){ if( j ) printf(","); switch( sqlite3_column_type(pStmt, j) ){ case SQLITE_NULL: { printf("NULL"); break; } case SQLITE_INTEGER: case SQLITE_FLOAT: { printf("%s", sqlite3_column_text(pStmt, j)); break; } case SQLITE_BLOB: { int n = sqlite3_column_bytes(pStmt, j); int i; const unsigned char *a; a = (const unsigned char*)sqlite3_column_blob(pStmt, j); printf("x'"); for(i=0; i<n; i++){ printf("%02x", a[i]); } printf("'"); break; } case SQLITE_TEXT: { int n = sqlite3_column_bytes(pStmt, j); int i; const unsigned char *a; a = (const unsigned char*)sqlite3_column_blob(pStmt, j); printf("'"); for(i=0; i<n; i++){ if( a[i]=='\'' ){ printf("''"); }else{ putchar(a[i]); } } printf("'"); break; } } /* End switch() */ } /* End for() */ printf("\n"); fflush(stdout); } /* End if( eVerbosity>=5 ) */ } /* End while( SQLITE_ROW */ if( rc!=SQLITE_DONE && eVerbosity>=4 ){ printf("SQL-ERROR: (%d) %s\n", rc, sqlite3_errmsg(db)); fflush(stdout); } }else if( eVerbosity>=4 ){ printf("SQL-ERROR (%d): %s\n", rc, sqlite3_errmsg(db)); fflush(stdout); } /* End if( SQLITE_OK ) */ return sqlite3_finalize(pStmt); } /* Invoke this routine to run a single test case */ int runCombinedDbSqlInput( const uint8_t *aData, /* Combined DB+SQL content */ size_t nByte, /* Size of aData in bytes */ int iTimeout, /* Use this timeout */ int bScript, /* If true, just render CLI output */ int iSqlId /* SQL identifier */ ){ int rc; /* SQLite API return value */ int iSql; /* Index in aData[] of start of SQL */ unsigned char *aDb = 0; /* Decoded database content */ int nDb = 0; /* Size of the decoded database */ int i; /* Loop counter */ int j; /* Start of current SQL statement */ char *zSql = 0; /* SQL text to run */ int nSql; /* Bytes of SQL text */ FuzzCtx cx; /* Fuzzing context */ if( nByte<10 ) return 0; if( sqlite3_initialize() ) return 0; if( sqlite3_memory_used()!=0 ){ int nAlloc = 0; int nNotUsed = 0; sqlite3_status(SQLITE_STATUS_MALLOC_COUNT, &nAlloc, &nNotUsed, 0); fprintf(stderr,"memory leak prior to test start:" " %lld bytes in %d allocations\n", sqlite3_memory_used(), nAlloc); exit(1); } memset(&cx, 0, sizeof(cx)); iSql = decodeDatabase((unsigned char*)aData, (int)nByte, &aDb, &nDb); if( iSql<0 ) return 0; nSql = (int)(nByte - iSql); if( bScript ){ char zName[100]; sqlite3_snprintf(sizeof(zName),zName,"dbsql%06d.db",iSqlId); renderDbSqlForCLI(stdout, zName, aDb, nDb, (unsigned char*)(aData+iSql), nSql); sqlite3_free(aDb); return 0; } if( eVerbosity>=3 ){ printf( "****** %d-byte input, %d-byte database, %d-byte script " "******\n", (int)nByte, nDb, nSql); fflush(stdout); } rc = sqlite3_open(0, &cx.db); if( rc ){ sqlite3_free(aDb); return 1; } if( bVdbeDebug ){ sqlite3_exec(cx.db, "PRAGMA vdbe_debug=ON", 0, 0, 0); } /* Invoke the progress handler frequently to check to see if we ** are taking too long. The progress handler will return true ** (which will block further processing) if more than giTimeout seconds have ** elapsed since the start of the test. */ cx.iLastCb = timeOfDay(); cx.iCutoffTime = cx.iLastCb + (iTimeout<giTimeout ? iTimeout : giTimeout); cx.mxCb = mxProgressCb; #ifndef SQLITE_OMIT_PROGRESS_CALLBACK sqlite3_progress_handler(cx.db, 10, progress_handler, (void*)&cx); #endif /* Set a limit on the maximum size of a prepared statement, and the ** maximum length of a string or blob */ if( vdbeOpLimit>0 ){ sqlite3_limit(cx.db, SQLITE_LIMIT_VDBE_OP, vdbeOpLimit); } if( lengthLimit>0 ){ sqlite3_limit(cx.db, SQLITE_LIMIT_LENGTH, lengthLimit); } if( depthLimit>0 ){ sqlite3_limit(cx.db, SQLITE_LIMIT_EXPR_DEPTH, depthLimit); } sqlite3_limit(cx.db, SQLITE_LIMIT_LIKE_PATTERN_LENGTH, 100); sqlite3_hard_heap_limit64(heapLimit); if( nDb>=20 && aDb[18]==2 && aDb[19]==2 ){ aDb[18] = aDb[19] = 1; } rc = sqlite3_deserialize(cx.db, "main", aDb, nDb, nDb, SQLITE_DESERIALIZE_RESIZEABLE | SQLITE_DESERIALIZE_FREEONCLOSE); if( rc ){ fprintf(stderr, "sqlite3_deserialize() failed with %d\n", rc); goto testrun_finished; } if( maxDbSize>0 ){ sqlite3_int64 x = maxDbSize; sqlite3_file_control(cx.db, "main", SQLITE_FCNTL_SIZE_LIMIT, &x); } /* For high debugging levels, turn on debug mode */ if( eVerbosity>=5 ){ sqlite3_exec(cx.db, "PRAGMA vdbe_debug=ON;", 0, 0, 0); } /* Block debug pragmas and ATTACH/DETACH. But wait until after ** deserialize to do this because deserialize depends on ATTACH */ sqlite3_set_authorizer(cx.db, block_troublesome_sql, 0); /* Consistent PRNG seed */ #ifdef SQLITE_TESTCTRL_PRNG_SEED sqlite3_table_column_metadata(cx.db, 0, "x", 0, 0, 0, 0, 0, 0); sqlite3_test_control(SQLITE_TESTCTRL_PRNG_SEED, 1, cx.db); #else sqlite3_randomness(0,0); #endif zSql = sqlite3_malloc( nSql + 1 ); if( zSql==0 ){ fprintf(stderr, "Out of memory!\n"); }else{ memcpy(zSql, aData+iSql, nSql); zSql[nSql] = 0; for(i=j=0; zSql[i]; i++){ if( zSql[i]==';' ){ char cSaved = zSql[i+1]; zSql[i+1] = 0; if( sqlite3_complete(zSql+j) ){ rc = runDbSql(cx.db, zSql+j); j = i+1; } zSql[i+1] = cSaved; if( rc==SQLITE_INTERRUPT || progress_handler(&cx) ){ goto testrun_finished; } } } if( j<i ){ runDbSql(cx.db, zSql+j); } } testrun_finished: sqlite3_free(zSql); rc = sqlite3_close(cx.db); if( rc!=SQLITE_OK ){ fprintf(stdout, "sqlite3_close() returns %d\n", rc); } if( eVerbosity>=2 && !bScript ){ fprintf(stdout, "Peak memory usages: %f MB\n", sqlite3_memory_highwater(1) / 1000000.0); } if( sqlite3_memory_used()!=0 ){ int nAlloc = 0; int nNotUsed = 0; sqlite3_status(SQLITE_STATUS_MALLOC_COUNT, &nAlloc, &nNotUsed, 0); fprintf(stderr,"Memory leak: %lld bytes in %d allocations\n", sqlite3_memory_used(), nAlloc); exit(1); } sqlite3_hard_heap_limit64(0); sqlite3_soft_heap_limit64(0); return 0; } /* ** END of the dbsqlfuzz code ***************************************************************************/ /* Look at a SQL text and try to determine if it begins with a database ** description, such as would be found in a dbsqlfuzz test case. Return ** true if this does appear to be a dbsqlfuzz test case and false otherwise. */ static int isDbSql(unsigned char *a, int n){ unsigned char buf[12]; int i; if( n>4 && memcmp(a,"\n--\n",4)==0 ) return 1; while( n>0 && isspace(a[0]) ){ a++; n--; } for(i=0; n>0 && i<8; n--, a++){ if( isxdigit(a[0]) ) buf[i++] = a[0]; } if( i==8 && memcmp(buf,"53514c69",8)==0 ) return 1; return 0; } /* Implementation of the isdbsql(TEXT) SQL function. */ static void isDbSqlFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ int n = sqlite3_value_bytes(argv[0]); unsigned char *a = (unsigned char*)sqlite3_value_blob(argv[0]); sqlite3_result_int(context, a!=0 && n>0 && isDbSql(a,n)); } /* Methods for the VHandle object */ static int inmemClose(sqlite3_file *pFile){ VHandle *p = (VHandle*)pFile; VFile *pVFile = p->pVFile; pVFile->nRef--; |
︙ | ︙ | |||
713 714 715 716 717 718 719 | /* ** Rebuild the database file. ** ** (1) Remove duplicate entries ** (2) Put all entries in order ** (3) Vacuum */ | | > | | | > > > > | 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 | /* ** Rebuild the database file. ** ** (1) Remove duplicate entries ** (2) Put all entries in order ** (3) Vacuum */ static void rebuild_database(sqlite3 *db, int dbSqlOnly){ int rc; char *zSql; zSql = sqlite3_mprintf( "BEGIN;\n" "CREATE TEMP TABLE dbx AS SELECT DISTINCT dbcontent FROM db;\n" "DELETE FROM db;\n" "INSERT INTO db(dbid, dbcontent) " " SELECT NULL, dbcontent FROM dbx ORDER BY 2;\n" "DROP TABLE dbx;\n" "CREATE TEMP TABLE sx AS SELECT DISTINCT sqltext FROM xsql %s;\n" "DELETE FROM xsql;\n" "INSERT INTO xsql(sqlid,sqltext) " " SELECT NULL, sqltext FROM sx ORDER BY 2;\n" "DROP TABLE sx;\n" "COMMIT;\n" "PRAGMA page_size=1024;\n" "VACUUM;\n", dbSqlOnly ? " WHERE isdbsql(sqltext)" : "" ); rc = sqlite3_exec(db, zSql, 0, 0, 0); sqlite3_free(zSql); if( rc ) fatalError("cannot rebuild: %s", sqlite3_errmsg(db)); } /* ** Return the value of a hexadecimal digit. Return -1 if the input ** is not a hex digit. */ |
︙ | ︙ | |||
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 | v *= aMult[i].iMult; break; } } if( v>0x7fffffff ) fatalError("parameter too large - max 2147483648"); return (int)(isNeg? -v : v); } /* ** Print sketchy documentation for this utility program */ static void showHelp(void){ printf("Usage: %s [options] SOURCE-DB ?ARGS...?\n", g.zArgv0); printf( "Read databases and SQL scripts from SOURCE-DB and execute each script against\n" "each database, checking for crashes and memory leaks.\n" "Options:\n" " --cell-size-check Set the PRAGMA cell_size_check=ON\n" " --dbid N Use only the database where dbid=N\n" " --export-db DIR Write databases to files(s) in DIR. Works with --dbid\n" " --export-sql DIR Write SQL to file(s) in DIR. Also works with --sqlid\n" " --help Show this help text\n" " --info Show information about SOURCE-DB w/o running tests\n" " --limit-mem N Limit memory used by test SQLite instance to N bytes\n" " --limit-vdbe Panic if any test runs for more than 100,000 cycles\n" | > > > > > > > > > > > > > > > | | > > > > > | > > > > > | | > > > > > | > > | 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 | v *= aMult[i].iMult; break; } } if( v>0x7fffffff ) fatalError("parameter too large - max 2147483648"); return (int)(isNeg? -v : v); } /* ** Return the number of "v" characters in a string. Return 0 if there ** are any characters in the string other than "v". */ static int numberOfVChar(const char *z){ int N = 0; while( z[0] && z[0]=='v' ){ z++; N++; } return z[0]==0 ? N : 0; } /* ** Print sketchy documentation for this utility program */ static void showHelp(void){ printf("Usage: %s [options] SOURCE-DB ?ARGS...?\n", g.zArgv0); printf( "Read databases and SQL scripts from SOURCE-DB and execute each script against\n" "each database, checking for crashes and memory leaks.\n" "Options:\n" " --cell-size-check Set the PRAGMA cell_size_check=ON\n" " --dbid N Use only the database where dbid=N\n" " --export-db DIR Write databases to files(s) in DIR. Works with --dbid\n" " --export-sql DIR Write SQL to file(s) in DIR. Also works with --sqlid\n" " --help Show this help text\n" " --info Show information about SOURCE-DB w/o running tests\n" " --limit-depth N Limit expression depth to N. Default: 500\n" " --limit-heap N Limit heap memory to N. Default: 100M\n" " --limit-mem N Limit memory used by test SQLite instance to N bytes\n" " --limit-vdbe Panic if any test runs for more than 100,000 cycles\n" " --load-sql FILE.. Load SQL scripts fron files into SOURCE-DB\n" " --load-db FILE.. Load template databases from files into SOURCE_DB\n" " --load-dbsql FILE.. Load dbsqlfuzz outputs into the xsql table\n" " ^^^^------ Use \"-\" for FILE to read filenames from stdin\n" " -m TEXT Add a description to the database\n" " --native-vfs Use the native VFS for initially empty database files\n" " --native-malloc Turn off MEMSYS3/5 and Lookaside\n" " --oss-fuzz Enable OSS-FUZZ testing\n" " --prng-seed N Seed value for the PRGN inside of SQLite\n" " -q|--quiet Reduced output\n" " --rebuild Rebuild and vacuum the database file\n" " --result-trace Show the results of each SQL command\n" " --script Output CLI script instead of running tests\n" " --skip N Skip the first N test cases\n" " --spinner Use a spinner to show progress\n" " --sqlid N Use only SQL where sqlid=N\n" " --timeout N Maximum time for any one test in N millseconds\n" " -v|--verbose Increased output. Repeat for more output.\n" " --vdbe-debug Activate VDBE debugging.\n" ); } int main(int argc, char **argv){ sqlite3_int64 iBegin; /* Start time of this program */ int quietFlag = 0; /* True if --quiet or -q */ int verboseFlag = 0; /* True if --verbose or -v */ char *zInsSql = 0; /* SQL statement for --load-db or --load-sql */ int iFirstInsArg = 0; /* First argv[] for --load-db or --load-sql */ sqlite3 *db = 0; /* The open database connection */ sqlite3_stmt *pStmt; /* A prepared statement */ int rc; /* Result code from SQLite interface calls */ Blob *pSql; /* For looping over SQL scripts */ Blob *pDb; /* For looping over template databases */ int i; /* Loop index for the argv[] loop */ int dbSqlOnly = 0; /* Only use scripts that are dbsqlfuzz */ int onlySqlid = -1; /* --sqlid */ int onlyDbid = -1; /* --dbid */ int nativeFlag = 0; /* --native-vfs */ int rebuildFlag = 0; /* --rebuild */ int vdbeLimitFlag = 0; /* --limit-vdbe */ int infoFlag = 0; /* --info */ int nSkip = 0; /* --skip */ int bScript = 0; /* --script */ int bSpinner = 0; /* True for --spinner */ int timeoutTest = 0; /* undocumented --timeout-test flag */ int runFlags = 0; /* Flags sent to runSql() */ char *zMsg = 0; /* Add this message */ int nSrcDb = 0; /* Number of source databases */ char **azSrcDb = 0; /* Array of source database names */ int iSrcDb; /* Loop over all source databases */ int nTest = 0; /* Total number of tests performed */ char *zDbName = ""; /* Appreviated name of a source database */ const char *zFailCode = 0; /* Value of the TEST_FAILURE env variable */ int cellSzCkFlag = 0; /* --cell-size-check */ int sqlFuzz = 0; /* True for SQL fuzz. False for DB fuzz */ int iTimeout = 120000; /* Default 120-second timeout */ int nMem = 0; /* Memory limit override */ int nMemThisDb = 0; /* Memory limit set by the CONFIG table */ char *zExpDb = 0; /* Write Databases to files in this directory */ char *zExpSql = 0; /* Write SQL to files in this directory */ void *pHeap = 0; /* Heap for use by SQLite */ int ossFuzz = 0; /* enable OSS-FUZZ testing */ int ossFuzzThisDb = 0; /* ossFuzz value for this particular database */ int nativeMalloc = 0; /* Turn off MEMSYS3/5 and lookaside if true */ sqlite3_vfs *pDfltVfs; /* The default VFS */ int openFlags4Data; /* Flags for sqlite3_open_v2() */ int bTimer = 0; /* Show elapse time for each test */ int nV; /* How much to increase verbosity with -vvvv */ sqlite3_int64 tmStart; /* Start of each test */ sqlite3_config(SQLITE_CONFIG_URI,1); registerOomSimulator(); sqlite3_initialize(); iBegin = timeOfDay(); #ifdef __unix__ signal(SIGALRM, signalHandler); signal(SIGSEGV, signalHandler); signal(SIGABRT, signalHandler); #endif g.zArgv0 = argv[0]; openFlags4Data = SQLITE_OPEN_READONLY; zFailCode = getenv("TEST_FAILURE"); pDfltVfs = sqlite3_vfs_find(0); inmemVfsRegister(1); for(i=1; i<argc; i++){ |
︙ | ︙ | |||
891 892 893 894 895 896 897 | if( i>=argc-1 ) fatalError("missing arguments on %s", argv[i]); onlyDbid = integerValue(argv[++i]); }else if( strcmp(z,"export-db")==0 ){ if( i>=argc-1 ) fatalError("missing arguments on %s", argv[i]); zExpDb = argv[++i]; }else | | | | > > > | | | > < | > > > > > > > > > | 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 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 | if( i>=argc-1 ) fatalError("missing arguments on %s", argv[i]); onlyDbid = integerValue(argv[++i]); }else if( strcmp(z,"export-db")==0 ){ if( i>=argc-1 ) fatalError("missing arguments on %s", argv[i]); zExpDb = argv[++i]; }else if( strcmp(z,"export-sql")==0 || strcmp(z,"export-dbsql")==0 ){ if( i>=argc-1 ) fatalError("missing arguments on %s", argv[i]); zExpSql = argv[++i]; }else if( strcmp(z,"help")==0 ){ showHelp(); return 0; }else if( strcmp(z,"info")==0 ){ infoFlag = 1; }else if( strcmp(z,"limit-depth")==0 ){ if( i>=argc-1 ) fatalError("missing arguments on %s", argv[i]); depthLimit = integerValue(argv[++i]); }else if( strcmp(z,"limit-heap")==0 ){ if( i>=argc-1 ) fatalError("missing arguments on %s", argv[i]); heapLimit = integerValue(argv[++i]); }else if( strcmp(z,"limit-mem")==0 ){ if( i>=argc-1 ) fatalError("missing arguments on %s", argv[i]); nMem = integerValue(argv[++i]); }else if( strcmp(z,"limit-vdbe")==0 ){ vdbeLimitFlag = 1; }else if( strcmp(z,"load-sql")==0 ){ zInsSql = "INSERT INTO xsql(sqltext)" "VALUES(CAST(readtextfile(?1) AS text))"; iFirstInsArg = i+1; openFlags4Data = SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE; break; }else if( strcmp(z,"load-db")==0 ){ zInsSql = "INSERT INTO db(dbcontent) VALUES(readfile(?1))"; iFirstInsArg = i+1; openFlags4Data = SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE; break; }else if( strcmp(z,"load-dbsql")==0 ){ zInsSql = "INSERT INTO xsql(sqltext)" "VALUES(readfile(?1))"; iFirstInsArg = i+1; openFlags4Data = SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE; dbSqlOnly = 1; break; }else if( strcmp(z,"m")==0 ){ if( i>=argc-1 ) fatalError("missing arguments on %s", argv[i]); zMsg = argv[++i]; openFlags4Data = SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE; }else if( strcmp(z,"native-malloc")==0 ){ |
︙ | ︙ | |||
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 | if( strcmp(z,"prng-seed")==0 ){ if( i>=argc-1 ) fatalError("missing arguments on %s", argv[i]); g.uRandom = atoi(argv[++i]); }else if( strcmp(z,"quiet")==0 || strcmp(z,"q")==0 ){ quietFlag = 1; verboseFlag = 0; }else if( strcmp(z,"rebuild")==0 ){ rebuildFlag = 1; openFlags4Data = SQLITE_OPEN_READWRITE; }else if( strcmp(z,"result-trace")==0 ){ runFlags |= SQL_OUTPUT; }else if( strcmp(z,"sqlid")==0 ){ if( i>=argc-1 ) fatalError("missing arguments on %s", argv[i]); onlySqlid = integerValue(argv[++i]); }else if( strcmp(z,"timeout")==0 ){ if( i>=argc-1 ) fatalError("missing arguments on %s", argv[i]); iTimeout = integerValue(argv[++i]); }else if( strcmp(z,"timeout-test")==0 ){ timeoutTest = 1; #ifndef __unix__ fatalError("timeout is not available on non-unix systems"); #endif }else | > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > | 1716 1717 1718 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 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 | if( strcmp(z,"prng-seed")==0 ){ if( i>=argc-1 ) fatalError("missing arguments on %s", argv[i]); g.uRandom = atoi(argv[++i]); }else if( strcmp(z,"quiet")==0 || strcmp(z,"q")==0 ){ quietFlag = 1; verboseFlag = 0; eVerbosity = 0; }else if( strcmp(z,"rebuild")==0 ){ rebuildFlag = 1; openFlags4Data = SQLITE_OPEN_READWRITE; }else if( strcmp(z,"result-trace")==0 ){ runFlags |= SQL_OUTPUT; }else if( strcmp(z,"script")==0 ){ bScript = 1; }else if( strcmp(z,"skip")==0 ){ if( i>=argc-1 ) fatalError("missing arguments on %s", argv[i]); nSkip = atoi(argv[++i]); }else if( strcmp(z,"spinner")==0 ){ bSpinner = 1; }else if( strcmp(z,"timer")==0 ){ bTimer = 1; }else if( strcmp(z,"sqlid")==0 ){ if( i>=argc-1 ) fatalError("missing arguments on %s", argv[i]); onlySqlid = integerValue(argv[++i]); }else if( strcmp(z,"timeout")==0 ){ if( i>=argc-1 ) fatalError("missing arguments on %s", argv[i]); iTimeout = integerValue(argv[++i]); }else if( strcmp(z,"timeout-test")==0 ){ timeoutTest = 1; #ifndef __unix__ fatalError("timeout is not available on non-unix systems"); #endif }else if( strcmp(z,"vdbe-debug")==0 ){ bVdbeDebug = 1; }else if( strcmp(z,"verbose")==0 ){ quietFlag = 0; verboseFlag++; eVerbosity++; if( verboseFlag>1 ) runFlags |= SQL_TRACE; }else if( (nV = numberOfVChar(z))>=1 ){ quietFlag = 0; verboseFlag += nV; eVerbosity += nV; if( verboseFlag>1 ) runFlags |= SQL_TRACE; }else if( strcmp(z,"version")==0 ){ int ii; const char *zz; printf("SQLite %s %s\n", sqlite3_libversion(), sqlite3_sourceid()); for(ii=0; (zz = sqlite3_compileoption_get(ii))!=0; ii++){ printf("%s\n", zz); } return 0; }else if( strcmp(z,"is-dbsql")==0 ){ i++; for(i++; i<argc; i++){ long nData; char *aData = readFile(argv[i], &nData); printf("%d %s\n", isDbSql((unsigned char*)aData,nData), argv[i]); sqlite3_free(aData); } exit(0); }else { fatalError("unknown option: %s", argv[i]); } }else{ nSrcDb++; azSrcDb = safe_realloc(azSrcDb, nSrcDb*sizeof(azSrcDb[0])); |
︙ | ︙ | |||
995 996 997 998 999 1000 1001 1002 1003 1004 | if( zInsSql ){ fatalError("cannot import into more than one database"); } } /* Process each source database separately */ for(iSrcDb=0; iSrcDb<nSrcDb; iSrcDb++){ rc = sqlite3_open_v2(azSrcDb[iSrcDb], &db, openFlags4Data, pDfltVfs->zName); if( rc ){ | > > > > > > > > > | > | | 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 | if( zInsSql ){ fatalError("cannot import into more than one database"); } } /* Process each source database separately */ for(iSrcDb=0; iSrcDb<nSrcDb; iSrcDb++){ char *zRawData = 0; long nRawData = 0; g.zDbFile = azSrcDb[iSrcDb]; rc = sqlite3_open_v2(azSrcDb[iSrcDb], &db, openFlags4Data, pDfltVfs->zName); if( rc==SQLITE_OK ){ rc = sqlite3_exec(db, "SELECT count(*) FROM sqlite_schema", 0, 0, 0); } if( rc ){ sqlite3_close(db); zRawData = readFile(azSrcDb[iSrcDb], &nRawData); if( zRawData==0 ){ fatalError("input file \"%s\" is not recognized\n", azSrcDb[iSrcDb]); } sqlite3_open(":memory:", &db); } /* Print the description, if there is one */ if( infoFlag ){ int n; zDbName = azSrcDb[iSrcDb]; i = (int)strlen(zDbName) - 1; |
︙ | ︙ | |||
1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 | && (n = sqlite3_column_int(pStmt,0))>0 ){ printf(" - %d scripts", n); } sqlite3_finalize(pStmt); printf("\n"); sqlite3_close(db); continue; } rc = sqlite3_exec(db, "CREATE TABLE IF NOT EXISTS db(\n" " dbid INTEGER PRIMARY KEY, -- database id\n" " dbcontent BLOB -- database disk file image\n" | > | 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 | && (n = sqlite3_column_int(pStmt,0))>0 ){ printf(" - %d scripts", n); } sqlite3_finalize(pStmt); printf("\n"); sqlite3_close(db); sqlite3_free(zRawData); continue; } rc = sqlite3_exec(db, "CREATE TABLE IF NOT EXISTS db(\n" " dbid INTEGER PRIMARY KEY, -- database id\n" " dbcontent BLOB -- database disk file image\n" |
︙ | ︙ | |||
1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 | if( zMsg ){ char *zSql; zSql = sqlite3_mprintf( "DELETE FROM readme; INSERT INTO readme(msg) VALUES(%Q)", zMsg); rc = sqlite3_exec(db, zSql, 0, 0, 0); sqlite3_free(zSql); if( rc ) fatalError("cannot change description: %s", sqlite3_errmsg(db)); } ossFuzzThisDb = ossFuzz; /* If the CONFIG(name,value) table exists, read db-specific settings ** from that table */ if( sqlite3_table_column_metadata(db,0,"config",0,0,0,0,0,0)==SQLITE_OK ){ rc = sqlite3_prepare_v2(db, "SELECT name, value FROM config", -1, &pStmt, 0); if( rc ) fatalError("cannot prepare query of CONFIG table: %s", sqlite3_errmsg(db)); while( SQLITE_ROW==sqlite3_step(pStmt) ){ const char *zName = (const char *)sqlite3_column_text(pStmt,0); if( zName==0 ) continue; if( strcmp(zName, "oss-fuzz")==0 ){ ossFuzzThisDb = sqlite3_column_int(pStmt,1); if( verboseFlag ) printf("Config: oss-fuzz=%d\n", ossFuzzThisDb); } | > > > > > > > > > > > > > > > | < < < < < > > > > > > > > > > > > > > > > > | > | | | > | | 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 | if( zMsg ){ char *zSql; zSql = sqlite3_mprintf( "DELETE FROM readme; INSERT INTO readme(msg) VALUES(%Q)", zMsg); rc = sqlite3_exec(db, zSql, 0, 0, 0); sqlite3_free(zSql); if( rc ) fatalError("cannot change description: %s", sqlite3_errmsg(db)); } if( zRawData ){ zInsSql = "INSERT INTO xsql(sqltext) VALUES(?1)"; rc = sqlite3_prepare_v2(db, zInsSql, -1, &pStmt, 0); if( rc ) fatalError("cannot prepare statement [%s]: %s", zInsSql, sqlite3_errmsg(db)); sqlite3_bind_text(pStmt, 1, zRawData, nRawData, SQLITE_STATIC); sqlite3_step(pStmt); rc = sqlite3_reset(pStmt); if( rc ) fatalError("insert failed for %s", argv[i]); sqlite3_finalize(pStmt); rebuild_database(db, dbSqlOnly); zInsSql = 0; sqlite3_free(zRawData); zRawData = 0; } ossFuzzThisDb = ossFuzz; /* If the CONFIG(name,value) table exists, read db-specific settings ** from that table */ if( sqlite3_table_column_metadata(db,0,"config",0,0,0,0,0,0)==SQLITE_OK ){ rc = sqlite3_prepare_v2(db, "SELECT name, value FROM config", -1, &pStmt, 0); if( rc ) fatalError("cannot prepare query of CONFIG table: %s", sqlite3_errmsg(db)); while( SQLITE_ROW==sqlite3_step(pStmt) ){ const char *zName = (const char *)sqlite3_column_text(pStmt,0); if( zName==0 ) continue; if( strcmp(zName, "oss-fuzz")==0 ){ ossFuzzThisDb = sqlite3_column_int(pStmt,1); if( verboseFlag ) printf("Config: oss-fuzz=%d\n", ossFuzzThisDb); } if( strcmp(zName, "limit-mem")==0 ){ nMemThisDb = sqlite3_column_int(pStmt,1); if( verboseFlag ) printf("Config: limit-mem=%d\n", nMemThisDb); } } sqlite3_finalize(pStmt); } if( zInsSql ){ sqlite3_create_function(db, "readfile", 1, SQLITE_UTF8, 0, readfileFunc, 0, 0); sqlite3_create_function(db, "readtextfile", 1, SQLITE_UTF8, 0, readtextfileFunc, 0, 0); sqlite3_create_function(db, "isdbsql", 1, SQLITE_UTF8, 0, isDbSqlFunc, 0, 0); rc = sqlite3_prepare_v2(db, zInsSql, -1, &pStmt, 0); if( rc ) fatalError("cannot prepare statement [%s]: %s", zInsSql, sqlite3_errmsg(db)); rc = sqlite3_exec(db, "BEGIN", 0, 0, 0); if( rc ) fatalError("cannot start a transaction"); for(i=iFirstInsArg; i<argc; i++){ if( strcmp(argv[i],"-")==0 ){ /* A filename of "-" means read multiple filenames from stdin */ char zLine[2000]; while( rc==0 && fgets(zLine,sizeof(zLine),stdin)!=0 ){ size_t kk = strlen(zLine); while( kk>0 && zLine[kk-1]<=' ' ) kk--; sqlite3_bind_text(pStmt, 1, zLine, (int)kk, SQLITE_STATIC); if( verboseFlag ) printf("loading %.*s\n", (int)kk, zLine); sqlite3_step(pStmt); rc = sqlite3_reset(pStmt); if( rc ) fatalError("insert failed for %s", zLine); } }else{ sqlite3_bind_text(pStmt, 1, argv[i], -1, SQLITE_STATIC); if( verboseFlag ) printf("loading %s\n", argv[i]); sqlite3_step(pStmt); rc = sqlite3_reset(pStmt); if( rc ) fatalError("insert failed for %s", argv[i]); } } sqlite3_finalize(pStmt); rc = sqlite3_exec(db, "COMMIT", 0, 0, 0); if( rc ) fatalError("cannot commit the transaction: %s", sqlite3_errmsg(db)); rebuild_database(db, dbSqlOnly); sqlite3_close(db); return 0; } rc = sqlite3_exec(db, "PRAGMA query_only=1;", 0, 0, 0); if( rc ) fatalError("cannot set database to query-only"); if( zExpDb!=0 || zExpSql!=0 ){ sqlite3_create_function(db, "writefile", 2, SQLITE_UTF8, 0, |
︙ | ︙ | |||
1174 1175 1176 1177 1178 1179 1180 | g.pFirstDb->id = 1; g.pFirstDb->seq = 0; g.nDb = 1; sqlFuzz = 1; } /* Print the description, if there is one */ | | | > | > | | | | | > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > | 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 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 | g.pFirstDb->id = 1; g.pFirstDb->seq = 0; g.nDb = 1; sqlFuzz = 1; } /* Print the description, if there is one */ if( !quietFlag && !bScript ){ zDbName = azSrcDb[iSrcDb]; i = (int)strlen(zDbName) - 1; while( i>0 && zDbName[i-1]!='/' && zDbName[i-1]!='\\' ){ i--; } zDbName += i; sqlite3_prepare_v2(db, "SELECT msg FROM readme", -1, &pStmt, 0); if( pStmt && sqlite3_step(pStmt)==SQLITE_ROW ){ printf("%s: %s\n", zDbName, sqlite3_column_text(pStmt,0)); } sqlite3_finalize(pStmt); } /* Rebuild the database, if requested */ if( rebuildFlag ){ if( !quietFlag ){ printf("%s: rebuilding... ", zDbName); fflush(stdout); } rebuild_database(db, 0); if( !quietFlag ) printf("done\n"); } /* Close the source database. Verify that no SQLite memory allocations are ** outstanding. */ sqlite3_close(db); if( sqlite3_memory_used()>0 ){ fatalError("SQLite has memory in use before the start of testing"); } /* Limit available memory, if requested */ sqlite3_shutdown(); if( nMemThisDb>0 && nMem==0 ){ if( !nativeMalloc ){ pHeap = realloc(pHeap, nMemThisDb); if( pHeap==0 ){ fatalError("failed to allocate %d bytes of heap memory", nMem); } sqlite3_config(SQLITE_CONFIG_HEAP, pHeap, nMemThisDb, 128); }else{ sqlite3_hard_heap_limit64((sqlite3_int64)nMemThisDb); } }else{ sqlite3_hard_heap_limit64(0); } /* Disable lookaside with the --native-malloc option */ if( nativeMalloc ){ sqlite3_config(SQLITE_CONFIG_LOOKASIDE, 0, 0); } /* Reset the in-memory virtual filesystem */ formatVfs(); /* Run a test using each SQL script against each database. */ if( !verboseFlag && !quietFlag && !bSpinner && !bScript ){ printf("%s:", zDbName); } for(pSql=g.pFirstSql; pSql; pSql=pSql->pNext){ tmStart = timeOfDay(); if( isDbSql(pSql->a, pSql->sz) ){ sqlite3_snprintf(sizeof(g.zTestName), g.zTestName, "sqlid=%d",pSql->id); if( bScript ){ /* No progress output */ }else if( bSpinner ){ int nTotal =g.nSql; int idx = pSql->seq; printf("\r%s: %d/%d ", zDbName, idx, nTotal); fflush(stdout); }else if( verboseFlag ){ printf("%s\n", g.zTestName); fflush(stdout); }else if( !quietFlag ){ static int prevAmt = -1; int idx = pSql->seq; int amt = idx*10/(g.nSql); if( amt!=prevAmt ){ printf(" %d%%", amt*10); fflush(stdout); prevAmt = amt; } } if( nSkip>0 ){ nSkip--; }else{ runCombinedDbSqlInput(pSql->a, pSql->sz, iTimeout, bScript, pSql->id); } nTest++; if( bTimer && !bScript ){ sqlite3_int64 tmEnd = timeOfDay(); printf("%lld %s\n", tmEnd - tmStart, g.zTestName); } g.zTestName[0] = 0; disableOom(); continue; } for(pDb=g.pFirstDb; pDb; pDb=pDb->pNext){ int openFlags; const char *zVfs = "inmem"; sqlite3_snprintf(sizeof(g.zTestName), g.zTestName, "sqlid=%d,dbid=%d", pSql->id, pDb->id); if( bScript ){ /* No progress output */ }else if( bSpinner ){ int nTotal = g.nDb*g.nSql; int idx = pSql->seq*g.nDb + pDb->id - 1; printf("\r%s: %d/%d ", zDbName, idx, nTotal); fflush(stdout); }else if( verboseFlag ){ printf("%s\n", g.zTestName); fflush(stdout); }else if( !quietFlag ){ static int prevAmt = -1; int idx = pSql->seq*g.nDb + pDb->id - 1; int amt = idx*10/(g.nDb*g.nSql); if( amt!=prevAmt ){ printf(" %d%%", amt*10); fflush(stdout); prevAmt = amt; } } if( nSkip>0 ){ nSkip--; continue; } if( bScript ){ char zName[100]; sqlite3_snprintf(sizeof(zName), zName, "db%06d.db", pDb->id>1 ? pDb->id : pSql->id); renderDbSqlForCLI(stdout, zName, pDb->a, pDb->sz, pSql->a, pSql->sz); continue; } createVFile("main.db", pDb->sz, pDb->a); sqlite3_randomness(0,0); if( ossFuzzThisDb ){ #ifndef SQLITE_OSS_FUZZ fatalError("--oss-fuzz not supported: recompile" " with -DSQLITE_OSS_FUZZ"); |
︙ | ︙ | |||
1265 1266 1267 1268 1269 1270 1271 | zVfs = 0; } rc = sqlite3_open_v2("main.db", &db, openFlags, zVfs); if( rc ) fatalError("cannot open inmem database"); sqlite3_limit(db, SQLITE_LIMIT_LENGTH, 100000000); sqlite3_limit(db, SQLITE_LIMIT_LIKE_PATTERN_LENGTH, 50); if( cellSzCkFlag ) runSql(db, "PRAGMA cell_size_check=ON", runFlags); | | > > > > > > > > > > > > > > > > > | | | 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 2261 2262 2263 2264 2265 2266 2267 2268 | zVfs = 0; } rc = sqlite3_open_v2("main.db", &db, openFlags, zVfs); if( rc ) fatalError("cannot open inmem database"); sqlite3_limit(db, SQLITE_LIMIT_LENGTH, 100000000); sqlite3_limit(db, SQLITE_LIMIT_LIKE_PATTERN_LENGTH, 50); if( cellSzCkFlag ) runSql(db, "PRAGMA cell_size_check=ON", runFlags); setAlarm((iTimeout+999)/1000); /* Enable test functions */ sqlite3_test_control(SQLITE_TESTCTRL_INTERNAL_FUNCTIONS, db); #ifndef SQLITE_OMIT_PROGRESS_CALLBACK if( sqlFuzz || vdbeLimitFlag ){ sqlite3_progress_handler(db, 100000, progressHandler, &vdbeLimitFlag); } #endif #ifdef SQLITE_TESTCTRL_PRNG_SEED sqlite3_test_control(SQLITE_TESTCTRL_PRNG_SEED, 1, db); #endif if( bVdbeDebug ){ sqlite3_exec(db, "PRAGMA vdbe_debug=ON", 0, 0, 0); } do{ runSql(db, (char*)pSql->a, runFlags); }while( timeoutTest ); setAlarm(0); sqlite3_exec(db, "PRAGMA temp_store_directory=''", 0, 0, 0); sqlite3_close(db); } if( sqlite3_memory_used()>0 ){ fatalError("memory leak: %lld bytes outstanding", sqlite3_memory_used()); } reformatVfs(); nTest++; if( bTimer ){ sqlite3_int64 tmEnd = timeOfDay(); printf("%lld %s\n", tmEnd - tmStart, g.zTestName); } g.zTestName[0] = 0; /* Simulate an error if the TEST_FAILURE environment variable is "5". ** This is used to verify that automated test script really do spot ** errors that occur in this test program. */ if( zFailCode ){ if( zFailCode[0]=='5' && zFailCode[1]==0 ){ fatalError("simulated failure"); }else if( zFailCode[0]!=0 ){ /* If TEST_FAILURE is something other than 5, just exit the test ** early */ printf("\nExit early due to TEST_FAILURE being set\n"); iSrcDb = nSrcDb-1; goto sourcedb_cleanup; } } } } if( bScript ){ /* No progress output */ }else if( bSpinner ){ int nTotal = g.nDb*g.nSql; printf("\r%s: %d/%d \n", zDbName, nTotal, nTotal); }else if( !quietFlag && !verboseFlag ){ printf(" 100%% - %d tests\n", g.nDb*g.nSql); } /* Clean up at the end of processing a single source database */ sourcedb_cleanup: blobListFree(g.pFirstSql); blobListFree(g.pFirstDb); reformatVfs(); } /* End loop over all source databases */ if( !quietFlag && !bScript ){ sqlite3_int64 iElapse = timeOfDay() - iBegin; printf("fuzzcheck: 0 errors out of %d tests in %d.%03d seconds\n" "SQLite %s %s\n", nTest, (int)(iElapse/1000), (int)(iElapse%1000), sqlite3_libversion(), sqlite3_sourceid()); } free(azSrcDb); free(pHeap); return 0; } |
Changes to test/fuzzdata1.db.
cannot compute difference between binary files
Changes to test/fuzzdata7.db.
cannot compute difference between binary files
Added test/fuzzdata8.db.
cannot compute difference between binary files
Changes to test/fuzzerfault.test.
︙ | ︙ | |||
84 85 86 87 88 89 90 91 92 | 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 | > > > > > > > > > > > > > > > > > > > | 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 | 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}} } #------------------------------------------------------------------------- reset_db do_execsql_test 4.0 { CREATE TABLE t1_a(a INTEFDR PRIMARY KEY, b TEXT); CREATE TABLE t3_a(k FnTEGER PRIMARY KEY, v TEXT); CREATE TABLE t3_b(k INTEÀ5R PRIMARY KEY, v TEXT); CREATE VIEW t3 AS SELECT * FROM t3_a UNION ALL SELECT * FROM t3_b; } faultsim_save_and_close do_faultsim_test 4 -faults oom-t* -prep { faultsim_restore_and_reopen } -body { execsql { SELECT 1 FROM t1_a LEFT JOIN t3 ON ((1+1) AND k=1) } } -test { faultsim_test_result {0 {}} } finish_test |
Added test/gencol1.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 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 | # 2019-10-31 # # 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 generated columns. # set testdir [file dirname $argv0] source $testdir/tester.tcl # ticket 830277d9db6c3ba1 on 2019-10-31 do_execsql_test gencol1-100 { CREATE TABLE t0(c0 AS(TYPEOF(c1)), c1); INSERT INTO t0(c1) VALUES(0); CREATE TABLE t1(x AS (typeof(y)), y); INSERT INTO t1 SELECT * FROM t0; SELECT * FROM t1; } {integer 0} foreach {tn schema} { 1 { CREATE TABLE t1( a INT, b TEXT, c ANY, w INT GENERATED ALWAYS AS (a*10), x TEXT AS (typeof(c)), y TEXT AS (substr(b,a,a+2)) ); } 2 { CREATE TABLE t1( w INT GENERATED ALWAYS AS (a*10), x TEXT AS (typeof(c)), y TEXT AS (substr(b,a,a+2)), a INT, b TEXT, c ANY ); } 3 { CREATE TABLE t1( w INT GENERATED ALWAYS AS (a*10), a INT, x TEXT AS (typeof(c)) STORED, b TEXT, y TEXT AS (substr(b,a,a+2)), c ANY ); } 4 { CREATE TABLE t1( a INTEGER PRIMARY KEY, w INT GENERATED ALWAYS AS (a*10), b TEXT, x TEXT AS (typeof(c)), y TEXT AS (substr(b,a,a+2)) STORED, c ANY ); } 5 { CREATE TABLE t1( w INT GENERATED ALWAYS AS (a*10), a INT, x TEXT AS (typeof(c)), b TEXT, y TEXT AS (substr(b,a,a+2)) STORED, c ANY, PRIMARY KEY(a,b) ) WITHOUT ROWID; } 6 { CREATE TABLE t1( w INT GENERATED ALWAYS AS (m*5), m INT AS (a*2) STORED, a INT, x TEXT AS (typeof(c)), b TEXT, y TEXT AS (substr(b,m/2,m/2+2)) STORED, c ANY, PRIMARY KEY(a,b) ); } 7 { CREATE TABLE t1( w INT GENERATED ALWAYS AS (m*5), m INT AS (a*2) NOT NULL, a INT, x TEXT AS (typeof(c)) CHECK (x<>'blank'), b TEXT, y TEXT AS (substr(b,m/2,m/2+2)) STORED, c ANY, PRIMARY KEY(b,a) ) WITHOUT ROWID; } } { catch {db close} sqlite3 db :memory: db eval $schema do_execsql_test gencol1-2.$tn.100 { INSERT INTO t1(a,b,c) VALUES(1,'abcdef',5.5),(3,'cantaloupe',NULL); SELECT w, x, y, '|' FROM t1 ORDER BY a; } {10 real abc | 30 null ntalo |} do_execsql_test gencol1-2.$tn.101 { SELECT w, x, y, '|' FROM t1 ORDER BY w; } {10 real abc | 30 null ntalo |} do_execsql_test gencol1-2.$tn.102 { SELECT a FROM t1 WHERE w=30; } {3} do_execsql_test gencol1-2.$tn.103 { SELECT a FROM t1 WHERE x='real'; } {1} do_execsql_test gencol1-2.$tn.104 { SELECT a FROM t1 WHERE y LIKE '%tal%' OR x='real' ORDER BY b; } {1 3} do_execsql_test gencol1-2.$tn.110 { CREATE INDEX t1w ON t1(w); SELECT a FROM t1 WHERE w=10; } {1} do_execsql_test gencol1-2.$tn.120 { CREATE INDEX t1x ON t1(x) WHERE w BETWEEN 20 AND 40; SELECT a FROM t1 WHERE x='null' AND w BETWEEN 20 AND 40; } {3} do_execsql_test gencol1-2.$tn.121 { SELECT a FROM t1 WHERE x='real'; } {1} do_execsql_test gencol1-2.$tn.130 { VACUUM; PRAGMA integrity_check; } {ok} do_execsql_test gencol1-2.$tn.140 { UPDATE t1 SET a=a+100 WHERE w<20; SELECT a, w, '|' FROM t1 ORDER BY w; } {3 30 | 101 1010 |} do_execsql_test gencol1-2.$tn.150 { INSERT INTO t1 VALUES(4,'jambalaya','Chef John'),(15,87719874135,0); SELECT w, x, y, '|' FROM t1 ORDER BY w; } {30 null ntalo | 40 text balaya | 150 integer {} | 1010 real {} |} } # 2019-10-31 ticket b9befa4b83a660cc db close sqlite3 db :memory: do_execsql_test gencol1-3.100 { PRAGMA foreign_keys = true; CREATE TABLE t0(c0 PRIMARY KEY, c1, c2 AS (c0+c1-c3) REFERENCES t0, c3); INSERT INTO t0 VALUES (0, 0, 0), (11, 5, 5); UPDATE t0 SET c1 = c0, c3 = c0; SELECT *, '|' FROM t0 ORDER BY +c0; } {0 0 0 0 | 11 11 11 11 |} do_catchsql_test gencol1-3.110 { UPDATE t0 SET c1 = c0, c3 = c0+1; } {1 {FOREIGN KEY constraint failed}} # 2019-11-01 ticket c28a01da72f8957c db close sqlite3 db :memory: do_execsql_test gencol1-4.100 { CREATE TABLE t0 ( c0, c1 a UNIQUE AS (1), c2, c3 REFERENCES t0(c1) ); PRAGMA foreign_keys = true; INSERT INTO t0(c0,c2,c3) VALUES(0,0,1); } {} do_catchsql_test gencol1-4.110 { REPLACE INTO t0(c0,c2,c3) VALUES(0,0,0),(0,0,0); } {1 {FOREIGN KEY constraint failed}} # 2019-11-01 Problem found while adding new foreign key test cases in TH3. db close sqlite3 db :memory: do_execsql_test gencol1-5.100 { PRAGMA foreign_keys=ON; CREATE TABLE t1( gcb AS (b*1), a INTEGER PRIMARY KEY, gcc AS (c+0), b UNIQUE, gca AS (1*a+0), c UNIQUE ) WITHOUT ROWID; INSERT INTO t1 VALUES(1,2,3); INSERT INTO t1 VALUES(4,5,6); INSERT INTO t1 VALUES(7,8,9); CREATE TABLE t1a( gcx AS (x+0) REFERENCES t1(a) ON DELETE CASCADE, id, x, gcid AS (1*id) ); INSERT INTO t1a VALUES(1, 1); INSERT INTO t1a VALUES(2, 4); INSERT INTO t1a VALUES(3, 7); DELETE FROM t1 WHERE b=5; SELECT id,x,'|' FROM t1a ORDER BY id; } {1 1 | 3 7 |} do_catchsql_test gencol1-6.10 { DROP TABLE IF EXISTS t0; CREATE TABLE t0(c0 NOT NULL AS(c1), c1); REPLACE INTO t0(c1) VALUES(NULL); } {1 {NOT NULL constraint failed: t0.c0}} # 2019-11-06 ticket https://www.sqlite.org/src/info/2399f5986134f79c # 2019-12-27 ticket https://www.sqlite.org/src/info/5fbc159eeb092130 # 2019-12-27 ticket https://www.sqlite.org/src/info/37823501c68a09f9 # # All of the above tickets deal with NOT NULL ON CONFLICT REPLACE # constraints on tables that have generated columns. # reset_db do_execsql_test gencol1-7.10 { CREATE TABLE t0 (c0 GENERATED ALWAYS AS (1), c1 UNIQUE, c2 UNIQUE); INSERT INTO t0(c1) VALUES (1); SELECT quote(0 = t0.c2 OR t0.c1 BETWEEN t0.c2 AND 1) FROM t0; } {NULL} do_execsql_test gencol1-7.11 { DROP TABLE t0; CREATE TABLE t0(c0 NOT NULL DEFAULT 'xyz', c1 AS(c0) NOT NULL); REPLACE INTO t0(c0) VALUES(NULL); SELECT * FROM t0; } {xyz xyz} do_execsql_test gencol1-7.12 { DROP TABLE t0; CREATE TABLE t0(c0 NOT NULL DEFAULT 'xyz', c1 AS(c0) STORED NOT NULL); REPLACE INTO t0(c0) VALUES(NULL); SELECT * FROM t0; } {xyz xyz} do_execsql_test gencol1-7.20 { CREATE TABLE t1( a NOT NULL DEFAULT 'aaa', b AS(c) NOT NULL, c NOT NULL DEFAULT 'ccc'); REPLACE INTO t1(a,c) VALUES(NULL,NULL); SELECT * FROM t1; } {aaa ccc ccc} do_execsql_test gencol1-7.21 { DROP TABLE t1; CREATE TABLE t1( a NOT NULL DEFAULT 'aaa', b AS(c) STORED NOT NULL, c NOT NULL DEFAULT 'ccc'); REPLACE INTO t1(a,c) VALUES(NULL,NULL); SELECT * FROM t1; } {aaa ccc ccc} do_execsql_test gencol1-7.30 { CREATE TABLE t2( a NOT NULL DEFAULT 'aaa', b AS(a) NOT NULL, c NOT NULL DEFAULT 'ccc'); REPLACE INTO t2(a,c) VALUES(NULL,NULL); SELECT * FROM t2; } {aaa aaa ccc} do_execsql_test gencol1-7.31 { DROP TABLE t2; CREATE TABLE t2( a NOT NULL DEFAULT 'aaa', b AS(a) STORED NOT NULL, c NOT NULL DEFAULT 'ccc'); REPLACE INTO t2(a,c) VALUES(NULL,NULL); SELECT * FROM t2; } {aaa aaa ccc} do_execsql_test gencol1-7.40 { CREATE TABLE t3(a NOT NULL DEFAULT 123, b AS(a) UNIQUE); REPLACE INTO t3 VALUES(NULL); SELECT * FROM t3; } {123 123} do_execsql_test gencol1-7.41 { SELECT * FROM t3 WHERE b=123; } {123 123} do_execsql_test gencol1-7.50 { CREATE TABLE t4(a NOT NULL DEFAULT 123, b AS(a*10+4) STORED UNIQUE); REPLACE INTO t4 VALUES(NULL); SELECT * FROM t4; } {123 1234} do_execsql_test gencol1-7.51 { SELECT * FROM t4 WHERE b=1234; } {123 1234} # 2019-11-06 ticket 4fc08501f4e56692 do_execsql_test gencol1-8.10 { DROP TABLE IF EXISTS t0; CREATE TABLE t0( c0 AS (('a', 9) < ('b', c1)), c1 AS (1), c2 CHECK (1 = c1) ); INSERT INTO t0 VALUES (0),(99); SELECT * FROM t0; } {1 1 0 1 1 99} do_catchsql_test gencol1-8.20 { DROP TABLE IF EXISTS t0; CREATE TABLE t0( c0, c1 AS(c0 + c2), c2 AS(c1) CHECK(c2) ); UPDATE t0 SET c0 = NULL; } {1 {generated column loop on "c2"}} # 2019-11-21 Problems in the new generated column logic # reported by Yongheng Chen and Rui Zhong reset_db do_execsql_test gencol1-9.10 { PRAGMA foreign_keys=OFF; CREATE TABLE t1(aa , bb AS (17) UNIQUE); INSERT INTO t1 VALUES(17); CREATE TABLE t2(cc); INSERT INTO t2 VALUES(41); SELECT * FROM t2 JOIN t1 WHERE t1.bb=t1.aa AND t1.bb=17; } {41 17 17} do_execsql_test gencol1-9.20 { CREATE TABLE t3(aa INT PRIMARY KEY, bb UNIQUE AS(aa)); INSERT INTO t3 VALUES(1); SELECT 100, * FROM t3; DELETE FROM t3 WHERE (SELECT bb FROM t3); SELECT 200, * FROM t3; } {100 1 1} # 2019-12-04 Generated column in a CREATE TABLE IF NOT EXISTS that # does already exist. # sqlite3 db :memory: do_execsql_test gencol1-10.10 { CREATE TABLE t1(aa,bb); CREATE TABLE IF NOT EXISTS t1(aa, bb AS (aa+1)); PRAGMA integrity_check; } {ok} # 2019-12-06 Found by mrigger # sqlite3 db :memory: do_execsql_test gencol1-11.10 { PRAGMA foreign_keys = true; CREATE TABLE t0( c0, c1 INTEGER PRIMARY KEY, c2 BLOB UNIQUE DEFAULT x'00', c3 BLOB GENERATED ALWAYS AS (1), FOREIGN KEY(c1) REFERENCES t0(c2) ); } do_catchsql_test gencol1-11.20 { INSERT OR REPLACE INTO t0(c0, c1) VALUES (2, 1), (1, 0) } {1 {FOREIGN KEY constraint failed}} do_execsql_test gencol1-11.30 { DROP TABLE t0; CREATE TABLE t0( c0, c1 INTEGER PRIMARY KEY, c3 BLOB GENERATED ALWAYS AS (1), c2 BLOB UNIQUE DEFAULT x'00', FOREIGN KEY(c1) REFERENCES t0(c2) ); } do_catchsql_test gencol1-11.40 { INSERT OR REPLACE INTO t0(c0, c1) VALUES (2, 1), (1, 0) } {1 {FOREIGN KEY constraint failed}} do_execsql_test gencol1-11.50 { DROP TABLE t0; CREATE TABLE t0( c0, c3 BLOB GENERATED ALWAYS AS (1), c1 INTEGER PRIMARY KEY, c2 BLOB UNIQUE DEFAULT x'00', FOREIGN KEY(c1) REFERENCES t0(c2) ); } do_catchsql_test gencol1-11.60 { INSERT OR REPLACE INTO t0(c0, c1) VALUES (2, 1), (1, 0) } {1 {FOREIGN KEY constraint failed}} do_execsql_test gencol1-11.70 { DROP TABLE t0; CREATE TABLE t0( c3 BLOB GENERATED ALWAYS AS (1), c0, c1 INTEGER PRIMARY KEY, c2 BLOB UNIQUE DEFAULT x'00', FOREIGN KEY(c1) REFERENCES t0(c2) ); } do_catchsql_test gencol1-11.80 { INSERT OR REPLACE INTO t0(c0, c1) VALUES (2, 1), (1, 0) } {1 {FOREIGN KEY constraint failed}} # 2019-12-09 ticket bd8c280671ba44a7 # With generated columns, the sqlite3ExprGetColumnOfTable() routine might # generate a code sequence that does not end with OP_Column. So check to # make sure that the last instruction generated is an OP_column prior to # applying the OPFLAG_TYPEOFARG optimization to NOT NULL checks in the # PRAGMA integrity_check code. # sqlite3 db :memory: do_execsql_test gencol1-12.10 { CREATE TABLE t0 (c0, c1 NOT NULL AS (c0==0)); INSERT INTO t0(c0) VALUES (0); PRAGMA integrity_check; } {ok} # 2019-12-09 bug report from Yongheng Chen # Ensure that the SrcList_item.colUsed field is set correctly when a # generated column appears in the USING clause of a join. # do_execsql_test gencol1-13.10 { CREATE TABLE t1(x, y AS(x+1)); INSERT INTO t1 VALUES(10); SELECT y FROM t1 JOIN t1 USING (y,y); } {11} do_execsql_test gencol1-13.11 { SELECT 123 FROM t1 JOIN t1 USING (x); } {123} do_execsql_test gencol1-13.11 { SELECT 456 FROM t1 JOIN t1 USING (x,x); } {456} do_execsql_test gencol1-13.20 { CREATE INDEX t1y ON t1(y); SELECT y FROM t1 JOIN t1 USING (y,y); } {11} do_execsql_test gencol1-13.21 { CREATE INDEX t1x ON t1(x); SELECT 123 FROM t1 JOIN t1 USING (x); } {123} do_execsql_test gencol1-13.22 { SELECT 456 FROM t1 JOIN t1 USING (x,x); } {456} # 2019-12-14 ticket b439bfcfb7deedc6 # sqlite3 db :memory: do_execsql_test gencol1-14.10 { CREATE TABLE t0(c0 AS(1 >= 1), c1 UNIQUE AS(TYPEOF(c0)), c2); INSERT INTO t0 VALUES(0); REINDEX; SELECT * FROM t0; } {1 integer 0} do_catchsql_test gencol1-14.10 { INSERT INTO t0 VALUES(2); } {1 {UNIQUE constraint failed: t0.c1}} # 2019-12-14 gramfuzz1 find # The schema is malformed in that it has a subquery on a generated # column expression. This will be loaded if writable_schema=ON. SQLite # must not use such an expression during code generation as the code generator # will add bits of content to the expression tree that might be allocated # from lookaside. But the schema is not tied to a particular database # connection, so the use of lookaside memory is prohibited. The fix # is to change the generated column expression to NULL before adding it # to the schema. # reset_db do_test gencol1-15.10 { sqlite3 db {} db deserialize [decode_hexdb { | size 8192 pagesize 4096 filename c27.db | page 1 offset 0 | 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3. | 16: 10 00 01 01 00 40 20 20 00 00 00 01 00 00 00 02 .....@ ........ | 32: 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 04 ................ | 48: 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 ................ | 80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 ................ | 96: 00 2e 3f d8 0d 00 00 00 01 0f ba 00 0f ba 00 00 ..?............. | 4016: 00 00 00 00 00 00 00 00 00 00 44 01 06 17 11 11 ..........D..... | 4032: 01 75 74 61 62 6c 65 74 31 74 31 02 43 52 45 41 .utablet1t1.CREA | 4048: 54 45 20 54 41 42 4c 45 20 74 31 28 61 20 49 4e TE TABLE t1(a IN | 4064: 54 2c 20 62 20 41 53 28 28 56 41 4c 55 45 53 28 T, b AS((VALUES( | 4080: 31 29 29 20 49 53 20 75 6e 6b 6e 6f 77 6e 29 29 1)) IS unknown)) | page 2 offset 4096 | 0: 0d 00 00 00 00 10 00 00 00 00 00 00 00 00 00 00 ................ | end c27.db }]} {} do_execsql_test gencol1-15.20 { PRAGMA writable_schema=ON; REPLACE INTO t1 VALUES(9); SELECT a, quote(b) FROM t1 } {9 NULL} # 2019-12-16 ticket 3b84b42943644d6f # When a table is the right table of a LEFT JOIN and the ON clause is # false, make sure any generated columns evaluate to NULL. reset_db do_execsql_test gencol1-16.10 { CREATE TABLE t0(c0); CREATE TABLE t1(c1, c2 AS(1)); INSERT INTO t0 VALUES(0); SELECT c0, c1, c2 FROM t0 LEFT JOIN t1; } {0 {} {}} do_execsql_test gencol1-16.20 { DROP TABLE t1; CREATE TABLE t1(c1, c2 AS (c1 ISNULL)); SELECT c0, c1, c2 FROM t0 LEFT JOIN t1; } {0 {} {}} do_execsql_test gencol1-16.30 { INSERT INTO t1(c1) VALUES(1),(NULL); SELECT * FROM t1; } {1 0 {} 1} do_execsql_test gencol1-16.40 { SELECT c0, c1, c2 FROM t0 LEFT JOIN t1 ON c0=c1; } {0 {} {}} # 2019-12-20 ticket e0a8120553f4b082 # Generated columns with REAL affinity need to have an OP_RealAffinity # opcode applied, even when the column value is extracted from an index. # reset_db do_execsql_test gencol1-17.10 { CREATE TABLE t0(c0 REAL AS(1) UNIQUE, c1 INT); INSERT INTO t0 VALUES(''); SELECT quote(c0), quote(c1) from t0; } {1.0 ''} do_execsql_test gencol1-17.20 { SELECT *, (1 BETWEEN CAST(t0.c0 AS TEXT) AND t0.c0) FROM t0; } {1.0 {} 0} do_execsql_test gencol1-17.30 { SELECT * FROM t0 WHERE (1 BETWEEN CAST(t0.c0 AS TEXT) AND t0.c0); } {} do_execsql_test gencol1-17.40 { CREATE TABLE t1(a TEXT AS(b) COLLATE nocase, b TEXT, c INT, d DEFAULT 1); INSERT INTO t1(b,c) VALUES('abc',11),('DEF',22),('ghi',33); SELECT a FROM t1 WHERE b='DEF' AND a='def'; } {DEF} do_execsql_test gencol1-17.50 { CREATE INDEX t1bca ON t1(b,c,a); SELECT a FROM t1 WHERE b='DEF' AND a='def'; } {DEF} # 2019-12-26 ticket ec8abb025e78f40c # An index on a virtual column with a constant value (why would anybody # ever do such a thing?) can cause problems for a one-pass DELETE. # reset_db do_execsql_test gencol1-18.10 { CREATE TABLE t0(c0 UNIQUE AS(0), c1, c2); INSERT INTO t0(c1) VALUES(0); SELECT * FROM t0; } {0 0 {}} do_execsql_test gencol1-18.20 { UPDATE t0 SET c1=0, c2=0 WHERE c0>=0; SELECT * FROM t0; } {0 0 0} # 2019-12-27 ticket de4b04149b9fdeae # reset_db do_catchsql_test gencol1-19.10 { CREATE TABLE t0( c0 INT AS(2) UNIQUE, c1 TEXT UNIQUE, FOREIGN KEY(c0) REFERENCES t0(c1) ); INSERT INTO t0(c1) VALUES(0.16334143182538696), (0); } {1 {UNIQUE constraint failed: t0.c0}} # 2020-06-29 forum bug report. # https://sqlite.org/forum/forumpost/73b9a8ccfb # do_execsql_test gencol1-20.1 { CREATE TEMPORARY TABLE tab ( prim DATE PRIMARY KEY, a INTEGER, comp INTEGER AS (a), b INTEGER, x INTEGER ); -- Add some data INSERT INTO tab (prim, a, b) VALUES ('2001-01-01', 0, 0); -- Check that each column is 0 like I expect SELECT * FROM tab; } {2001-01-01 0 0 0 {}} do_execsql_test gencol1-20.2 { -- Do an UPSERT on the b column INSERT INTO tab (prim, b) VALUES ('2001-01-01',5) ON CONFLICT(prim) DO UPDATE SET b=excluded.b; -- Now b is NULL rather than 5 SELECT * FROM tab; } {2001-01-01 0 0 5 {}} # 2021-07-30 forum https://sqlite.org/forum/forumpost/ff3ffe09251c105b?t=h # ifcapable vtab { reset_db do_execsql_test gencol1-21.1 { CREATE TABLE t1( a integer primary key, b int generated always as (a+5), c text GENERATED ALWAYS as (printf('%08x',a)), d Generated Always AS ('xyzzy'), e int Always default(5) ); INSERT INTO t1(a) VALUES(5); SELECT name, type FROM pragma_table_xinfo('t1'); } {a INTEGER b INT c TEXT d {} e INT} } # 2021-09-07 forum https://sqlite.org/forum/forumpost/699b44b3ee # reset_db do_execsql_test gencol1-22.1 { CREATE TABLE t0(a PRIMARY KEY,b TEXT AS ('2') UNIQUE); INSERT INTO t0(a) VALUES(2); SELECT * FROM t0 AS x JOIN t0 AS y WHERE x.b='2' AND (y.a=2 OR (x.b LIKE '2*' AND y.a=x.b)); } {2 2 2 2} finish_test |
Changes to test/having.test.
︙ | ︙ | |||
61 62 63 64 65 66 67 | 2 "SELECT a, sum(b) FROM t1 GROUP BY a HAVING sum(b)>5 AND a=2" "SELECT a, sum(b) FROM t1 WHERE a=2 GROUP BY a HAVING sum(b)>5" 3 "SELECT a, sum(b) FROM t1 GROUP BY a COLLATE binary HAVING a=2" "SELECT a, sum(b) FROM t1 WHERE a=2 GROUP BY a COLLATE binary" | | | | 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 | 2 "SELECT a, sum(b) FROM t1 GROUP BY a HAVING sum(b)>5 AND a=2" "SELECT a, sum(b) FROM t1 WHERE a=2 GROUP BY a HAVING sum(b)>5" 3 "SELECT a, sum(b) FROM t1 GROUP BY a COLLATE binary HAVING a=2" "SELECT a, sum(b) FROM t1 WHERE a=2 GROUP BY a COLLATE binary" 5 "SELECT a, sum(b) FROM t1 GROUP BY a COLLATE binary HAVING 1" "SELECT a, sum(b) FROM t1 WHERE 1 GROUP BY a COLLATE binary" 6 "SELECT count(*) FROM t1,t2 WHERE a=c GROUP BY b, d HAVING b=d" "SELECT count(*) FROM t1,t2 WHERE a=c AND b=d GROUP BY b, d" 7 { SELECT count(*) FROM t1,t2 WHERE a=c GROUP BY b, d HAVING b=d COLLATE nocase |
︙ | ︙ | |||
150 151 152 153 154 155 156 | # result as the following. But it does not. # set ::nondeter_ret 0 do_execsql_test 4.3 { SELECT a, sum(b) FROM t3 WHERE nondeter(a) GROUP BY a } {1 4 2 2} | > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | # result as the following. But it does not. # set ::nondeter_ret 0 do_execsql_test 4.3 { SELECT a, sum(b) FROM t3 WHERE nondeter(a) GROUP BY a } {1 4 2 2} #------------------------------------------------------------------------- reset_db do_execsql_test 5.0 { CREATE TABLE t1(a, b); CREATE TABLE t2(x, y); INSERT INTO t1 VALUES('a', 'b'); } # The WHERE clause (a=2), uses an aggregate column from the outer query. # If the HAVING term (0) is moved into the WHERE clause in this case, # SQLite would at one point optimize (a=2 AND 0) to simply (0). Which # is logically correct, but happened to cause problems in aggregate # processing for the outer query. This test case verifies that those # problems are no longer present. do_execsql_test 5.1 { SELECT min(b), ( SELECT x FROM t2 WHERE a=2 GROUP BY y HAVING 0 ) FROM t1; } {b {}} # From chromium # https://bugs.chromium.org/p/chromium/issues/detail?id=1161869 # do_execsql_test 5.2 { SELECT EXISTS ( SELECT * FROM ( SELECT * FROM ( SELECT 1 ) WHERE Col0 = 1 GROUP BY 1 ) WHERE 0 ) FROM (SELECT 1 Col0) GROUP BY 1 } {0} finish_test |
Changes to test/hook.test.
︙ | ︙ | |||
138 139 140 141 142 143 144 | catchsql { DROP TABLE t1; } unset -nocomplain ::update_hook set ::update_hook {} db update_hook [list lappend ::update_hook] # | | | < | 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 | catchsql { DROP TABLE t1; } unset -nocomplain ::update_hook set ::update_hook {} db update_hook [list lappend ::update_hook] # # EVIDENCE-OF: R-24531-54682 The update hook is not invoked when # internal system tables are modified (i.e. sqlite_sequence). # execsql { CREATE TABLE t1(a INTEGER PRIMARY KEY, b); CREATE TABLE t1w(a INT PRIMARY KEY, b) WITHOUT ROWID; } set ::update_hook } {} |
︙ | ︙ | |||
674 675 676 677 678 679 680 | do_preupdate_test 7.4.2.3 { UPDATE t5 SET b = 5 WHERE a = 'a' } { DELETE main t5 1 1 a 1 } | > | | | | | | | | | | | | | | | | | | | | | | | | > | 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 | do_preupdate_test 7.4.2.3 { UPDATE t5 SET b = 5 WHERE a = 'a' } { DELETE main t5 1 1 a 1 } ifcapable altertable { do_execsql_test 7.5.1.0 { CREATE TABLE t7(a, b); INSERT INTO t7 VALUES('one', 'two'); INSERT INTO t7 VALUES('three', 'four'); ALTER TABLE t7 ADD COLUMN c DEFAULT NULL; } do_preupdate_test 7.5.1.1 { DELETE FROM t7 WHERE a = 'one' } { DELETE main t7 1 1 one two {} } do_preupdate_test 7.5.1.2 { UPDATE t7 SET b = 'five' } { UPDATE main t7 2 2 three four {} three five {} } do_execsql_test 7.5.2.0 { CREATE TABLE t8(a, b); INSERT INTO t8 VALUES('one', 'two'); INSERT INTO t8 VALUES('three', 'four'); ALTER TABLE t8 ADD COLUMN c DEFAULT 'xxx'; } } if 0 { # At time of writing, these two are broken. They demonstrate that the # sqlite3_preupdate_old() method does not handle the case where ALTER TABLE # has been used to add a column with a default value other than NULL. # |
︙ | ︙ | |||
845 846 847 848 849 850 851 | DELETE main t4 1 1 3 abc DELETE main t3 1 1 2 abc DELETE main t2 1 1 1 abc DELETE main t1 1 1 0 abc } # No preupdate callbacks for modifying sqlite_master. | > | | | | | | > > > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | > | 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 | DELETE main t4 1 1 3 abc DELETE main t3 1 1 2 abc DELETE main t2 1 1 1 abc DELETE main t1 1 1 0 abc } # No preupdate callbacks for modifying sqlite_master. ifcapable altertable { do_preupdate_test 8.1 { CREATE TABLE x1(x, y); } { } do_preupdate_test 8.2 { ALTER TABLE x1 ADD COLUMN z } { } do_preupdate_test 8.3 { ALTER TABLE x1 RENAME TO y1 } { } do_preupdate_test 8.4 { CREATE INDEX y1x ON y1(x) } { } do_preupdate_test 8.5 { CREATE VIEW v1 AS SELECT * FROM y1 } { } do_preupdate_test 8.6 { DROP TABLE y1 } { } } #------------------------------------------------------------------------- reset_db db preupdate hook preupdate_hook ifcapable altertable { do_execsql_test 9.0 { CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c); CREATE TABLE t2(a, b INTEGER PRIMARY KEY); } do_preupdate_test 9.1 { INSERT INTO t1 VALUES(456, NULL, NULL); } { INSERT main t1 456 456 0 456 {} {} } do_execsql_test 9.2 { ALTER TABLE t1 ADD COLUMN d; } do_preupdate_test 9.3 { INSERT INTO t1(a, b, c) VALUES(457, NULL, NULL); } { INSERT main t1 457 457 0 457 {} {} {} } do_preupdate_test 9.4 { DELETE FROM t1 WHERE a=456 } { DELETE main t1 456 456 0 456 {} {} {} } do_preupdate_test 9.5 { INSERT INTO t2 DEFAULT VALUES; } { INSERT main t2 1 1 0 {} 1 } do_preupdate_test 9.6 { INSERT INTO t1 DEFAULT VALUES; } { INSERT main t1 458 458 0 458 {} {} {} } } do_execsql_test 10.0 { CREATE TABLE t3(a, b INTEGER PRIMARY KEY); } do_preupdate_test 10.1 { INSERT INTO t3 DEFAULT VALUES |
︙ | ︙ | |||
953 954 955 956 957 958 959 | preupdate {DELETE main sqlite_stat1 1 1} preupdate {DELETE main sqlite_stat1 2 2} preupdate {INSERT main sqlite_stat1 1 1} preupdate {INSERT main sqlite_stat1 2 2} }] } | > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | preupdate {DELETE main sqlite_stat1 1 1} preupdate {DELETE main sqlite_stat1 2 2} preupdate {INSERT main sqlite_stat1 1 1} preupdate {INSERT main sqlite_stat1 2 2} }] } #------------------------------------------------------------------------- # Test that the pre-update hook is fired for INSERT statements that use # the xfer optimization on without rowid tables. # reset_db do_execsql_test 12.1 { CREATE TABLE t1(a INTEGER PRIMARY KEY, b); CREATE TABLE t2(a INTEGER PRIMARY KEY, b) WITHOUT ROWID; INSERT INTO t1 VALUES(1, 2); INSERT INTO t1 VALUES(3, 4); INSERT INTO t2 VALUES(5, 6); INSERT INTO t2 VALUES(7, 8); CREATE TABLE t3 (a INTEGER PRIMARY KEY, b) WITHOUT ROWID; } db preupdate hook preupdate_cb db update_hook update_cb proc preupdate_cb {args} { lappend ::res "preupdate" $args } proc update_cb {args} { lappend ::res "update" $args } set ::res [list] do_test 12.2 { execsql VACUUM set ::res } {} do_test 12.3 { set ::res [list] execsql { INSERT INTO t3 SELECT a, b FROM t2 } set ::res } {preupdate {INSERT main t3 0 0} preupdate {INSERT main t3 0 0}} do_test 12.4 { execsql { DELETE FROM t3 } set ::res [list] execsql { INSERT INTO t3 SELECT * FROM t2 } set ::res } {preupdate {INSERT main t3 0 0} preupdate {INSERT main t3 0 0}} do_execsql_test 12.5 { CREATE TABLE t4(a COLLATE nocase PRIMARY KEY, b) WITHOUT ROWID; INSERT INTO t4 VALUES('abc', 1); INSERT INTO t4 VALUES('DEF', 2); } set ::res [list] do_test 12.6 { execsql VACUUM set ::res } {} do_catchsql_test 12.6 { INSERT INTO t4 VALUES('def', 3); } {1 {UNIQUE constraint failed: t4.a}} finish_test |
Changes to test/icu.test.
︙ | ︙ | |||
141 142 143 144 145 146 147 148 149 | do_catchsql_test icu-5.5 {SELECT 'abc' REGEXP } {1 {incomplete input}} do_catchsql_test icu-5.6 {SELECT 'abc' REGEXP, 1} {1 {near ",": syntax error}} do_malloc_test icu-6.10 -sqlbody { SELECT upper(char(0xfb04,0xdf,0xfb04,0xe8,0xfb04)); } } finish_test | > > > > > > > > > > > > > > > > > > | 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 | do_catchsql_test icu-5.5 {SELECT 'abc' REGEXP } {1 {incomplete input}} do_catchsql_test icu-5.6 {SELECT 'abc' REGEXP, 1} {1 {near ",": syntax error}} do_malloc_test icu-6.10 -sqlbody { SELECT upper(char(0xfb04,0xdf,0xfb04,0xe8,0xfb04)); } } # 2020-03-19 # The ESCAPE clause on LIKE takes precedence over wildcards # do_execsql_test idu-6.0 { DROP TABLE IF EXISTS t1; CREATE TABLE t1(id INTEGER PRIMARY KEY, x TEXT); INSERT INTO t1 VALUES (1,'abcde'), (2,'abc_'), (3,'abc__'), (4,'abc%'), (5,'abc%%'); SELECT id FROM t1 WHERE x LIKE 'abc%%' ESCAPE '%'; } {4} do_execsql_test icu-6.1 { SELECT id FROM t1 WHERE x LIKE 'abc__' ESCAPE '_'; } {2} finish_test |
Changes to test/ieee754.test.
︙ | ︙ | |||
19 20 21 22 23 24 25 | foreach {id float rep} { 1 1.0 1,0 2 2.0 2,0 3 0.5 1,-1 4 1.5 3,-1 5 0.0 0,-1075 | | | | 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | foreach {id float rep} { 1 1.0 1,0 2 2.0 2,0 3 0.5 1,-1 4 1.5 3,-1 5 0.0 0,-1075 6 4.9406564584124654e-324 1,-1074 7 2.2250738585072009e-308 4503599627370495,-1074 8 2.2250738585072014e-308 1,-1022 } { do_test ieee754-100-$id-1 { db eval "SELECT ieee754($float);" } "ieee754($rep)" do_test ieee754-100-$id-2 { db eval "SELECT ieee754($rep)==$float;" |
︙ | ︙ |
Changes to test/in.test.
︙ | ︙ | |||
328 329 330 331 332 333 334 | SELECT * FROM t5; } } {111} do_test in-10.2 { catchsql { INSERT INTO t5 VALUES(4); } | | | 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 | SELECT * FROM t5; } } {111} do_test in-10.2 { catchsql { INSERT INTO t5 VALUES(4); } } {1 {CHECK constraint failed: a IN (111,222,333)}} # Ticket #1821 # # Type affinity applied to the right-hand side of an IN operator. # do_test in-11.1 { execsql { |
︙ | ︙ | |||
646 647 648 649 650 651 652 653 654 | do_execsql_test in-14.0 { CREATE TABLE c1(a); INSERT INTO c1 VALUES(1), (2), (4), (3); } do_execsql_test in-14.1 { SELECT * FROM c1 WHERE a IN (SELECT a FROM c1) ORDER BY 1 } {1 2 3 4} finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | do_execsql_test in-14.0 { CREATE TABLE c1(a); INSERT INTO c1 VALUES(1), (2), (4), (3); } do_execsql_test in-14.1 { SELECT * FROM c1 WHERE a IN (SELECT a FROM c1) ORDER BY 1 } {1 2 3 4} # 2019-02-20 Ticket https://www.sqlite.org/src/tktview/df46dfb631f75694fbb97033b69 # do_execsql_test in-15.0 { DROP TABLE IF EXISTS t1; CREATE TABLE IF NOT EXISTS t1(id INTEGER PRIMARY KEY); INSERT INTO t1 VALUES(1); SELECT a.id FROM t1 AS a JOIN t1 AS b ON a.id=b.id WHERE a.id IN (1,2,3); } {1} do_execsql_test in-15.1 { DROP TABLE IF EXISTS t2; CREATE TABLE t2(a INTEGER PRIMARY KEY,b); INSERT INTO t2 VALUES(1,11); INSERT INTO t2 VALUES(2,22); INSERT INTO t2 VALUES(3,33); SELECT b, a IN (3,4,5) FROM t2 ORDER BY b; } {11 0 22 0 33 1} do_execsql_test in-15.2 { DROP TABLE IF EXISTS t3; CREATE TABLE t3(x INTEGER PRIMARY KEY); INSERT INTO t3 VALUES(8); SELECT CASE WHEN x NOT IN (5,6,7) THEN 'yes' ELSE 'no' END FROM t3; SELECT CASE WHEN x NOT IN (NULL,6,7) THEN 'yes' ELSE 'no' END FROM t3; } {yes no} do_execsql_test in-15.3 { SELECT CASE WHEN x NOT IN (5,6,7) OR x=0 THEN 'yes' ELSE 'no' END FROM t3; SELECT CASE WHEN x NOT IN (NULL,6,7) OR x=0 THEN 'yes' ELSE 'no' END FROM t3; } {yes no} do_execsql_test in-15.4 { DROP TABLE IF EXISTS t4; CREATE TABLE t4(a INTEGER PRIMARY KEY, b INT); WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<20) INSERT INTO t4(a,b) SELECT x, x+100 FROM c; SELECT b FROM t4 WHERE a IN (3,null,8) ORDER BY +b; } {103 108} do_execsql_test in-15.5 { SELECT b FROM t4 WHERE a NOT IN (3,null,8); } {} do_execsql_test in-15.6 { DROP TABLE IF EXISTS t5; DROP TABLE IF EXISTS t6; CREATE TABLE t5(id INTEGER PRIMARY KEY, name TEXT); CREATE TABLE t6(id INTEGER PRIMARY KEY, name TEXT, t5_id INT); INSERT INTO t5 VALUES(1,'Alice'),(2,'Emma'); INSERT INTO t6 VALUES(1,'Bob',1),(2,'Cindy',1),(3,'Dave',2); SELECT a.* FROM t5 AS 'a' JOIN t5 AS 'b' ON b.id=a.id WHERE b.id IN ( SELECT t6.t5_id FROM t6 WHERE name='Bob' AND t6.t5_id IS NOT NULL AND t6.id IN ( SELECT id FROM (SELECT t6.id, count(*) AS x FROM t6 WHERE name='Bob' ) AS 't' WHERE x=1 ) AND t6.id IN (1,id) ); } {1 Alice} #------------------------------------------------------------------------- reset_db do_execsql_test in-16.0 { CREATE TABLE x1(a, b); INSERT INTO x1(a) VALUES(1), (2), (3), (4), (5), (6); CREATE INDEX x1i ON x1(a, b); } do_execsql_test in-16.1 { SELECT * FROM x1 WHERE a IN (SELECT a FROM x1 WHERE (a%2)==0) ORDER BY a DESC, b; } {6 {} 4 {} 2 {}} do_execsql_test in-16.2 { SELECT * FROM x1 WHERE a IN (SELECT a FROM x1 WHERE (a%7)==0) ORDER BY a DESC, b; } {} # 2019-06-11 # https://www.sqlite.org/src/info/57353f8243c637c0 # do_execsql_test in-17.1 { SELECT 1 IN ('1'); } 0 do_execsql_test in-17.2 { SELECT 1 IN ('1' COLLATE nocase); } 0 do_execsql_test in-17.3 { SELECT 1 IN (CAST('1' AS text)); } 0 do_execsql_test in-17.4 { SELECT 1 IN (CAST('1' AS text) COLLATE nocase); } 0 # 2019-08-27 ticket https://sqlite.org/src/info/dbaf8a6820be1ece # do_execsql_test in-18.1 { DROP TABLE IF EXISTS t0; CREATE TABLE t0(c0 INT UNIQUE); INSERT INTO t0(c0) VALUES (1); SELECT * FROM t0 WHERE '1' IN (t0.c0); } {} # 2019-09-02 ticket https://www.sqlite.org/src/info/2841e99d104c6436 # For the IN_INDEX_NOOP optimization, apply REAL affinity to the LHS # values prior to comparison if the RHS has REAL affinity. # # Also ticket https://sqlite.org/src/info/29f635e0af71234b # do_execsql_test in-19.10 { DROP TABLE IF EXISTS t0; CREATE TABLE t0(c0 REAL UNIQUE); INSERT INTO t0(c0) VALUES(2.0625E00); SELECT 1 FROM t0 WHERE c0 IN ('2.0625'); } {1} do_execsql_test in-19.20 { SELECT c0 IN ('2.0625') FROM t0; } {1} do_execsql_test in-19.21 { SELECT c0 = ('2.0625') FROM t0; } {1} do_execsql_test in-19.22 { SELECT c0 = ('0.20625e+01') FROM t0; } {1} do_execsql_test in-19.30 { SELECT c0 IN ('2.0625',2,3) FROM t0; } {1} do_execsql_test in-19.40 { DROP TABLE t0; CREATE TABLE t0(c0 TEXT, c1 REAL, c2, PRIMARY KEY(c2, c0, c1)); CREATE INDEX i0 ON t0(c1 IN (c0)); INSERT INTO t0(c0, c2) VALUES (0, NULL) ON CONFLICT(c2, c1, c0) DO NOTHING; PRAGMA integrity_check; } {ok} # Ticket f3ff1472887 # do_execsql_test in-20.1 { SELECT (1 IN (2 IS TRUE)); } {1} finish_test |
Changes to test/in4.test.
︙ | ︙ | |||
9 10 11 12 13 14 15 16 17 18 19 20 21 22 | # #*********************************************************************** # # $Id: in4.test,v 1.4 2009/06/05 17:09:12 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl do_test in4-1.1 { execsql { CREATE TABLE t1(a, b); CREATE INDEX i1 ON t1(a); } } {} | > | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | # #*********************************************************************** # # $Id: in4.test,v 1.4 2009/06/05 17:09:12 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix in4 do_test in4-1.1 { execsql { CREATE TABLE t1(a, b); CREATE INDEX i1 ON t1(a); } } {} |
︙ | ︙ | |||
222 223 224 225 226 227 228 | do_execsql_test in4-3.42 { EXPLAIN SELECT * FROM t3 WHERE x IN (10,11); } {/OpenEphemeral/} do_execsql_test in4-3.43 { SELECT * FROM t3 WHERE x IN (10); } {10 10 10} | > > > | | | | | 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 | do_execsql_test in4-3.42 { EXPLAIN SELECT * FROM t3 WHERE x IN (10,11); } {/OpenEphemeral/} do_execsql_test in4-3.43 { SELECT * FROM t3 WHERE x IN (10); } {10 10 10} # This test would verify that the "X IN (Y)" -> "X==Y" optimization # was working. But we have now taken that optimization out. #do_execsql_test in4-3.44 { # EXPLAIN # SELECT * FROM t3 WHERE x IN (10); #} {~/OpenEphemeral/} do_execsql_test in4-3.45 { SELECT * FROM t3 WHERE x NOT IN (10,11,99999); } {1 1 1} do_execsql_test in4-3.46 { EXPLAIN SELECT * FROM t3 WHERE x NOT IN (10,11,99999); } {/OpenEphemeral/} |
︙ | ︙ | |||
322 323 324 325 326 327 328 | INSERT INTO t6b VALUES(4,44),(5,55),(6,66); SELECT * FROM t6a, t6b WHERE a=3 AND b IN (c); } {3 4 4 44} do_execsql_test in4-6.1-eqp { EXPLAIN QUERY PLAN SELECT * FROM t6a, t6b WHERE a=3 AND b IN (c); | | > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | INSERT INTO t6b VALUES(4,44),(5,55),(6,66); SELECT * FROM t6a, t6b WHERE a=3 AND b IN (c); } {3 4 4 44} do_execsql_test in4-6.1-eqp { EXPLAIN QUERY PLAN SELECT * FROM t6a, t6b WHERE a=3 AND b IN (c); } {~/SCAN t6a/} do_execsql_test in4-6.2 { SELECT * FROM t6a, t6b WHERE a=3 AND c IN (b); } {3 4 4 44} do_execsql_test in4-6.2-eqp { EXPLAIN QUERY PLAN SELECT * FROM t6a, t6b WHERE a=3 AND c IN (b); } {~/SCAN/} reset_db do_execsql_test 7.0 { CREATE TABLE t1(a, b, c); CREATE TABLE t2(d, e); CREATE INDEX t1bc ON t1(c, b); INSERT INTO t2(e) VALUES(1); INSERT INTO t1 VALUES(NULL, NULL, NULL); } do_execsql_test 7.1 { SELECT * FROM t2 LEFT JOIN t1 ON c = d AND b IN (10,10,10); } {{} 1 {} {} {}} ifcapable rtree { reset_db do_execsql_test 7.2 { CREATE VIRTUAL TABLE t1 USING rtree(a, b, c); CREATE TABLE t2(d INTEGER, e INT); INSERT INTO t2(e) VALUES(1); } do_execsql_test 7.3 { SELECT * FROM t2 LEFT JOIN t1 ON c IN (d) AND b IN (10,10,10); } {{} 1 {} {} {}} } #------------------------------------------------------------------------- reset_db do_execsql_test 8.0 { CREATE TABLE t1(x INTEGER PRIMARY KEY, y); CREATE UNIQUE INDEX t1y ON t1(y); INSERT INTO t1 VALUES(111, 'AAA'),(222, 'BBB'),(333, 'CCC'); CREATE TABLE t2(z); INSERT INTO t2 VALUES('BBB'),('AAA'); ANALYZE sqlite_schema; INSERT INTO sqlite_stat1 VALUES('t1', 't1y','100 1'); } db close sqlite3 db test.db do_execsql_test 8.1 { SELECT t1.x FROM t2 CROSS JOIN t1 WHERE t2.z = t1.y; } {222 111} do_execsql_test 8.2 { SELECT t1.x FROM t2 CROSS JOIN t1 WHERE t2.z = t1.y AND +t1.x IN (111, 222); } {222 111} do_execsql_test 8.3 { SELECT t1.x FROM t2 CROSS JOIN t1 WHERE t2.z = t1.y AND t1.x IN (111, 222); } {222 111} # 2021-06-02 forum post https://sqlite.org/forum/forumpost/b4fcb8a598 # OP_SeekScan changes from check-in 4a43430fd23f8835 on 2020-09-30 causes # performance regression. # reset_db do_execsql_test 9.0 { CREATE TABLE node(node_id INTEGER PRIMARY KEY); CREATE TABLE edge(node_from INT, node_to INT); CREATE TABLE sub_nodes(node_id INTEGER PRIMARY KEY); CREATE INDEX edge_from_to ON edge(node_from,node_to); CREATE INDEX edge_to_from ON edge(node_to,node_from); ANALYZE; DELETE FROM sqlite_stat1; INSERT INTO sqlite_stat1 VALUES ('sub_nodes',NULL,'1000000'), ('edge','edge_to_from','20000000 2 2'), ('edge','edge_from_to','20000000 2 2'), ('node',NULL,'10000000'); ANALYZE sqlite_schema; } {} do_eqp_test 9.1 { SELECT count(*) FROM edge WHERE node_from IN sub_nodes AND node_to IN sub_nodes; } { QUERY PLAN |--SEARCH edge USING COVERING INDEX edge_to_from (node_to=?) |--USING ROWID SEARCH ON TABLE sub_nodes FOR IN-OPERATOR `--USING ROWID SEARCH ON TABLE sub_nodes FOR IN-OPERATOR } # ^^^^^ the key to the above is that the index should only use a single # term (node_to=?), not two terms (node_to=? AND node_from=). # dbsqlfuzz case # reset_db do_execsql_test 10.0 { CREATE TABLE t1(a,b,c,d,PRIMARY KEY(a,b,c)) WITHOUT ROWID; INSERT INTO t1(a,b,c,d) VALUES (0,-2,2,3), (0,2,3,4), (0,5,8,10), (1,7,11,13); ANALYZE sqlite_schema; INSERT INTO sqlite_stat1 VALUES('t1','t1','10 3 2 1'); ANALYZE sqlite_schema; PRAGMA reverse_unordered_selects(1); SELECT d FROM t1 WHERE 0=a AND b IN (-17,-4,-3,1,5,25,7798); } {10} # 2021-06-13 dbsqlfuzz e41762333a4d6e90a49e628f488d0873b2dba4c5 # The opcode that preceeds OP_SeekScan is usually OP_IdxGT, but can # sometimes be OP_IdxGE # reset_db do_execsql_test 11.0 { CREATE TABLE t1(a TEXT, b INT, c INT, d INT); INSERT INTO t1 VALUES('abc',123,4,5); INSERT INTO t1 VALUES('xyz',1,'abcdefxyz',99); CREATE INDEX t1abc ON t1(b,b,c); ANALYZE sqlite_schema; INSERT INTO sqlite_stat1 VALUES('t1','t1abc','10000 5 00 2003 10'); ANALYZE sqlite_schema; } {} do_execsql_test 11.1 { SELECT * FROM t1 WHERE b IN (345, (SELECT 1 FROM t1 WHERE b IN (345 NOT GLOB 510) AND c GLOB 'abc*xyz')) AND c BETWEEN 'abc' AND 'xyz'; } {xyz 1 abcdefxyz 99} do_execsql_test 11.2 { EXPLAIN SELECT * FROM t1 WHERE b IN (345, (SELECT 1 FROM t1 WHERE b IN (345 NOT GLOB 510) AND c GLOB 'abc*xyz')) AND c BETWEEN 'abc' AND 'xyz'; } {/ SeekScan /} # 2021-06-25 ticket 6dcbfd11cf666e21 # Another problem with OP_SeekScan # reset_db do_execsql_test 12.0 { CREATE TABLE t1(a,b,c); CREATE INDEX t1abc ON t1(a,b,c); CREATE INDEX t1bca on t1(b,c,a); INSERT INTO t1 VALUES(56,1119,1115); INSERT INTO t1 VALUES(57,1147,1137); INSERT INTO t1 VALUES(100,1050,1023); INSERT INTO t1 VALUES(101,1050,1023); ANALYZE sqlite_schema; INSERT INTO sqlite_stat1 VALUES('t1','t1abc','358677 2 2 1'); INSERT INTO sqlite_stat1 VALUES('t1','t1bca','358677 4 2 1'); ANALYZE sqlite_schema; SELECT * FROM t1 NOT INDEXED WHERE (b = 1137 AND c IN (97, 98)) OR (b = 1119 AND c IN (1115, 1023)); } {56 1119 1115} do_execsql_test 12.1 { SELECT * FROM t1 WHERE (b = 1137 AND c IN (97, 98)) OR (b = 1119 AND c IN (1115, 1023)); } {56 1119 1115} # 2021-11-02 ticket 5981a8c041a3c2f3 # Another OP_SeekScan problem. # reset_db do_execsql_test 13.0 { CREATE TABLE t1(id INTEGER PRIMARY KEY, a INT, b INT, c INT); INSERT INTO t1 VALUES(10,1,2,5); INSERT INTO t1 VALUES(20,1,3,5); INSERT INTO t1 VALUES(30,1,2,4); INSERT INTO t1 VALUES(40,1,3,4); ANALYZE sqlite_master; INSERT INTO sqlite_stat1 VALUES('t1','t1x','84000 3 2 1'); CREATE INDEX t1x ON t1(a,b,c); PRAGMA writable_schema=RESET; SELECT * FROM t1 WHERE a=1 AND b IN (2,3) AND c BETWEEN 4 AND 5 ORDER BY +id; } {10 1 2 5 20 1 3 5 30 1 2 4 40 1 3 4} finish_test |
Changes to test/in5.test.
︙ | ︙ | |||
244 245 246 247 248 249 250 251 252 | CREATE TABLE t9(a INTEGER PRIMARY KEY); INSERT INTO t9 VALUES (44), (45); } do_execsql_test 9.1 { SELECT * FROM t9 WHERE a IN (44, 45, 44, 45) } {44 45} finish_test | > > > > > > > > > > > > > > > > > | 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 | CREATE TABLE t9(a INTEGER PRIMARY KEY); INSERT INTO t9 VALUES (44), (45); } do_execsql_test 9.1 { SELECT * FROM t9 WHERE a IN (44, 45, 44, 45) } {44 45} #------------------------------------------------------------------------- # Test that ticket c7a117190 is fixed. # reset_db do_execsql_test 9.0 { CREATE TABLE t0(c0); CREATE VIEW v0(c0) AS SELECT LOWER(CAST('1e500' AS TEXT)) FROM t0; INSERT INTO t0(c0) VALUES (NULL); } do_execsql_test 9.1 { SELECT lower('1e500') FROM t0 WHERE rowid NOT IN (0, 0, lower('1e500')); } {1e500} do_execsql_test 9.2 { SELECT lower('1e500') FROM t0 WHERE rowid != lower('1e500'); } {1e500} finish_test |
Changes to test/in6.test.
︙ | ︙ | |||
73 74 75 76 77 78 79 80 | SELECT d, f FROM t1 LEFT JOIN t2 ON (e=d) WHERE a=100 AND b IN (200,201,202,204) AND c IN (300,302,301,305) ORDER BY +d; } {1 {} 2 {} 3 {} 4 {} 5 {} 8 {} 9 {}} finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | SELECT d, f FROM t1 LEFT JOIN t2 ON (e=d) WHERE a=100 AND b IN (200,201,202,204) AND c IN (300,302,301,305) ORDER BY +d; } {1 {} 2 {} 3 {} 4 {} 5 {} 8 {} 9 {}} # 2020-03-16 ticket 82b588d342d515d1 # Ensure that the IN-early-out optimization works with LEFT JOINs # reset_db do_execsql_test in6-3.100 { CREATE TABLE t1(a); INSERT INTO t1 VALUES(0); CREATE TABLE t2(b, c, d); INSERT INTO t2(b,c,d) VALUES(4,5,3),(4,5,4),(4,5,8); CREATE INDEX t2bcd ON t2(b, c, d); SELECT * FROM t1 LEFT JOIN t2 ON b=NULL AND c=5 AND d IN (2,3,4); } {0 {} {} {}} do_execsql_test in6-3.110 { CREATE TABLE v0(v1); CREATE TABLE v3(v5, v4); INSERT INTO v0 VALUES(0); CREATE INDEX v9 ON v3(v4, v4, v5); SELECT quote(v5) FROM v0 LEFT JOIN v3 ON v4 = NULL AND v5 IN(0); } {NULL} # 2021-04-29 forum https://sqlite.org/forum/forumpost/6a3ec138e9 # An early OP_IsNull bypass might skip over the OP_Affinity and # cause the OP_IfNoHope to jump on a false-positive, resulting in # incomplete output. # reset_db do_execsql_test in6-3.120 { CREATE TABLE t1(a TEXT, b TEXT); INSERT INTO t1 VALUES(null,10),(0,10),(10,10); CREATE INDEX t1ab ON t1(a,b); SELECT quote(a), quote(b), '|' FROM t1 WHERE b in (SELECT a FROM t1) AND a=0; } {'0' '10' |} do_execsql_test in6-3.130 { CREATE TABLE t2(x TEXT); INSERT INTO t2(x) VALUES(NULL),(0),(10); SELECT quote(x), quote(a), quote(b), 'x' FROM t2 LEFT JOIN t1 ON a=x AND b in (null,0,10); } {NULL NULL NULL x '0' '0' '10' x '10' '10' '10' x} finish_test |
Changes to test/incrblob3.test.
︙ | ︙ | |||
9 10 11 12 13 14 15 16 17 18 19 20 21 22 | # #*********************************************************************** # # set testdir [file dirname $argv0] source $testdir/tester.tcl sqlite3 db test.db sqlite3_db_config_lookaside db 0 0 0 do_execsql_test incrblob3-1.1 { CREATE TABLE blobs(k INTEGER PRIMARY KEY, v BLOB); INSERT INTO blobs VALUES(1, zeroblob(100)); | > > > > > | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | # #*********************************************************************** # # set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable !incrblob { finish_test return } sqlite3 db test.db sqlite3_db_config_lookaside db 0 0 0 do_execsql_test incrblob3-1.1 { CREATE TABLE blobs(k INTEGER PRIMARY KEY, v BLOB); INSERT INTO blobs VALUES(1, zeroblob(100)); |
︙ | ︙ |
Changes to test/incrblobfault.test.
︙ | ︙ | |||
9 10 11 12 13 14 15 16 17 18 19 20 21 22 | # #*********************************************************************** # # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix incrblobfault do_execsql_test 1.0 { CREATE TABLE blob(x INTEGER PRIMARY KEY, v BLOB); INSERT INTO blob VALUES(1, 'hello world'); INSERT INTO blob VALUES(2, 'world hello'); | > > > > > | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | # #*********************************************************************** # # set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable !incrblob { finish_test return } set testprefix incrblobfault do_execsql_test 1.0 { CREATE TABLE blob(x INTEGER PRIMARY KEY, v BLOB); INSERT INTO blob VALUES(1, 'hello world'); INSERT INTO blob VALUES(2, 'world hello'); |
︙ | ︙ |
Changes to test/incrvacuum.test.
︙ | ︙ | |||
828 829 830 831 832 833 834 | db eval { SELECT a FROM t3 } { if {$a==3} { db eval COMMIT } lappend res $a } set res } {1 2 3 4} } | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | db eval { SELECT a FROM t3 } { if {$a==3} { db eval COMMIT } lappend res $a } set res } {1 2 3 4} } # 2021-04-05 dbsqlfuzz cced0668cfd4da4eb2382cb9dd26c17c64aaff76 # # This is an incremental vacuum database that has one free page that # needs to be filled. After removing the last page from the end of # the database file to fill the free page slot, the last page that # is left is the tail of an overflow chain. # # But the size of the database file is shorter than the actual data # so that after incremental vacuum runs, the file is actually too # small to hold the last page of the overflow chain. # # At one point this caused an assertion fault in # sqlite3PagerTruncateImage(). # do_test incrvacuum-17.0 { sqlite3 db {} database_may_be_corrupt db deserialize [decode_hexdb { | size 20480 pagesize 4096 filename x2.db | page 1 offset 0 | 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3. | 16: 10 00 01 01 00 40 20 20 00 00 00 05 00 00 00 07 .....@ ........ | 32: 00 00 00 04 00 00 00 01 00 00 00 03 00 00 00 04 ................ | 48: 00 00 00 00 00 00 00 03 00 00 00 01 00 00 00 00 ................ | 64: 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 ................ | 80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 05 ................ | 96: 00 2e 53 60 0d 0f dc 00 01 0f b8 00 0f b8 0f b8 ..S`............ | 4016: 00 00 00 00 00 00 00 00 22 02 06 17 11 11 01 31 ...............1 | 4032: 74 61 62 6c 65 74 32 74 32 03 43 52 45 41 54 45 tablet2t2.CREATE | 4048: 20 54 41 42 4c 45 20 74 32 28 79 29 00 00 00 24 TABLE t2(y)...$ | 4064: 11 11 01 31 74 61 62 6c 65 74 31 74 31 03 43 52 ...1tablet1t1.CR | 4080: 45 41 54 45 20 54 41 42 4c 45 20 74 31 28 78 29 EATE TABLE t1(x) | page 2 offset 4096 | 0: 01 00 00 00 00 02 00 00 00 00 03 00 00 00 03 04 ................ | 16: 00 00 00 05 03 00 00 00 03 00 00 00 00 00 00 00 ................ | page 3 offset 8192 | 0: 0d 00 00 00 02 05 47 00 08 dd 05 47 00 00 00 00 ......G....G.... | 1344: 00 00 00 00 00 00 00 a7 0b 02 03 ce 1c 00 00 00 ................ | 2256: 00 00 00 00 00 00 00 00 00 00 00 00 07 ce 14 01 ................ | 2272: 04 81 9c 2c 00 00 00 00 00 00 00 00 00 00 00 00 ...,............ | 4080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 05 ................ | page 4 offset 12288 | 0: 00 00 00 00 00 00 00 00 08 dd 05 47 00 00 00 00 ...........G.... | 1344: 00 00 00 00 00 00 00 a7 0b 02 03 ce 1c 00 00 00 ................ | 2256: 00 00 00 00 00 00 00 00 00 00 00 00 07 ce 14 01 ................ | 2272: 04 81 9c 2c 00 00 00 00 00 00 00 00 00 00 00 00 ...,............ | 4080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 05 ................ | page 5 offset 16384 | 0: 00 00 00 06 00 00 00 00 00 00 00 00 00 00 00 00 ................ | end x2.db }]} {} do_catchsql_test incrvacuum-17.1 { PRAGMA writable_schema=ON; PRAGMA incremental_vacuum(10); } {0 {}} finish_test |
Changes to test/index.test.
︙ | ︙ | |||
734 735 736 737 738 739 740 | CREATE TEMP TABLE t6(x); INSERT INTO temp.t6 values(1),(5),(9); CREATE INDEX temp.i21 ON t6(x); SELECT x FROM t6 ORDER BY x DESC; } } {0 {9 5 1}} | > > > > > > > > > | > > > > > > > > > > > > > > > > > | 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 | CREATE TEMP TABLE t6(x); INSERT INTO temp.t6 values(1),(5),(9); CREATE INDEX temp.i21 ON t6(x); SELECT x FROM t6 ORDER BY x DESC; } } {0 {9 5 1}} # 2019-05-01 ticket https://www.sqlite.org/src/info/3be1295b264be2fa do_execsql_test index-22.0 { DROP TABLE IF EXISTS t1; CREATE TABLE t1(a, b TEXT); CREATE UNIQUE INDEX IF NOT EXISTS x1 ON t1(b==0); CREATE INDEX IF NOT EXISTS x2 ON t1(a || 0) WHERE b; INSERT INTO t1(a,b) VALUES('a',1),('a',0); SELECT a, b, '|' FROM t1; } {a 1 | a 0 |} # 2019-05-10 ticket https://www.sqlite.org/src/info/ae0f637bddc5290b do_execsql_test index-23.0 { DROP TABLE t1; CREATE TABLE t1(a TEXT, b REAL); CREATE UNIQUE INDEX t1x1 ON t1(a GLOB b); INSERT INTO t1(a,b) VALUES('0.0','1'),('1.0','1'); SELECT * FROM t1; REINDEX; } {0.0 1.0 1.0 1.0} do_execsql_test index-23.1 { DROP TABLE t1; CREATE TABLE t1(a REAL); CREATE UNIQUE INDEX index_0 ON t1(TYPEOF(a)); INSERT OR IGNORE INTO t1(a) VALUES (0.1),(FALSE); SELECT * FROM t1; REINDEX; } {0.1} finish_test |
Changes to test/index6.test.
︙ | ︙ | |||
154 155 156 157 158 159 160 | } } {500} do_test index6-2.2 { execsql { EXPLAIN QUERY PLAN SELECT * FROM t2 WHERE a=5; } | | | | | | | 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 | } } {500} do_test index6-2.2 { execsql { EXPLAIN QUERY PLAN SELECT * FROM t2 WHERE a=5; } } {/(SEARCH|SCAN) t2 USING INDEX t2a1 /} ifcapable stat4 { execsql ANALYZE do_test index6-2.3stat4 { execsql { EXPLAIN QUERY PLAN SELECT * FROM t2 WHERE a IS NOT NULL; } } {/(SEARCH|SCAN) t2 USING INDEX t2a1 /} } else { do_test index6-2.3stat4 { execsql { EXPLAIN QUERY PLAN SELECT * FROM t2 WHERE a IS NOT NULL AND a>0; } } {/(SEARCH|SCANE) t2 USING INDEX t2a1 /} } do_test index6-2.4 { execsql { EXPLAIN QUERY PLAN SELECT * FROM t2 WHERE a IS NULL; } } {~/INDEX t2a1/} do_execsql_test index6-2.101 { DROP INDEX t2a1; UPDATE t2 SET a=b, b=b+10000; SELECT b FROM t2 WHERE a=15; } {10015} do_execsql_test index6-2.102 { |
︙ | ︙ | |||
315 316 317 318 319 320 321 | INSERT INTO t8b VALUES('dummy', 4); } {} do_eqp_test index6-8.1 { SELECT * FROM t8a LEFT JOIN t8b ON (x = 'value' AND y = a) } { QUERY PLAN | | | | 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 | INSERT INTO t8b VALUES('dummy', 4); } {} do_eqp_test index6-8.1 { SELECT * FROM t8a LEFT JOIN t8b ON (x = 'value' AND y = a) } { QUERY PLAN |--SCAN t8a `--SEARCH t8b USING INDEX i8c (y=?) } do_execsql_test index6-8.2 { SELECT * FROM t8a LEFT JOIN t8b ON (x = 'value' AND y = a) } { 1 one value 1 2 two {} {} |
︙ | ︙ | |||
406 407 408 409 410 411 412 413 | SELECT 'one', * FROM t2 WHERE x NOT IN (SELECT a FROM t1); CREATE INDEX t1a ON t1(a) WHERE b=1; SELECT 'two', * FROM t2 WHERE x NOT IN (SELECT a FROM t1); } {} do_execsql_test index6-12.2 { SELECT x FROM t2 WHERE x IN (SELECT a FROM t1) ORDER BY +x; } {1 2} finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | SELECT 'one', * FROM t2 WHERE x NOT IN (SELECT a FROM t1); CREATE INDEX t1a ON t1(a) WHERE b=1; SELECT 'two', * FROM t2 WHERE x NOT IN (SELECT a FROM t1); } {} do_execsql_test index6-12.2 { SELECT x FROM t2 WHERE x IN (SELECT a FROM t1) ORDER BY +x; } {1 2} # 2019-05-04 # Ticket https://www.sqlite.org/src/tktview/5c6955204c392ae763a95 # Theorem prover error # do_execsql_test index6-13.1 { DROP TABLE IF EXISTS t0; CREATE TABLE t0(c0); CREATE INDEX index_0 ON t0(c0) WHERE c0 NOT NULL; INSERT INTO t0(c0) VALUES (NULL); SELECT * FROM t0 WHERE c0 OR 1; } {{}} # 2019-05-11 # Ticket https://sqlite.org/src/tktview/8025674847 reset_db do_execsql_test index6-14.1 { CREATE TABLE IF NOT EXISTS t0 (c0, c1); CREATE INDEX IF NOT EXISTS i0 ON t0(c0, c1) WHERE c0 NOT NULL; INSERT INTO t0(c0, c1) VALUES(NULL, 'row'); SELECT * FROM t0 WHERE t0.c0 IS NOT 1; } {{} row} do_execsql_test index6-14.2 { SELECT * FROM t0 WHERE CASE c0 WHEN 0 THEN 0 ELSE 1 END; } {{} row} # 2019-08-30 # Ticket https://www.sqlite.org/src/info/a6408d42b9f44462 # Ticket https://www.sqlite.org/src/info/fba33c8b1df6a915 # https://sqlite.org/src/info/bac716244fddac1fe841 # do_execsql_test index6-15.1 { DROP TABLE t0; CREATE TABLE t0(c0); INSERT INTO t0(c0) VALUES (NULL); CREATE INDEX i0 ON t0(1) WHERE c0 NOT NULL; SELECT 1 FROM t0 WHERE (t0.c0 IS FALSE) IS FALSE; } {1} do_execsql_test index6-15.2 { SELECT 1 FROM t0 WHERE (t0.c0 IS FALSE) BETWEEN FALSE AND TRUE; } {1} do_execsql_test index6-15.3 { SELECT 1 FROM t0 WHERE TRUE BETWEEN (t0.c0 IS FALSE) AND TRUE; } {1} do_execsql_test index6-15.4 { SELECT 1 FROM t0 WHERE FALSE BETWEEN FALSE AND (t0.c0 IS FALSE); } {1} do_execsql_test index6-15.5 { SELECT 1 FROM t0 WHERE (c0 IS FALSE) IN (FALSE); } {1} # 2019-09-03 # Ticket https://sqlite.org/src/info/767a8cbc6d20bd68 do_execsql_test index6-16.1 { DROP TABLE t0; CREATE TABLE t0(c0 COLLATE NOCASE, c1); CREATE INDEX i0 ON t0(0) WHERE c0 >= c1; INSERT INTO t0 VALUES('a', 'B'); SELECT c1 <= c0, c0 >= c1 FROM t0; } {1 0} do_execsql_test index6-16.2 { SELECT 2 FROM t0 WHERE c0 >= c1; } {} do_execsql_test index6-16.3 { SELECT 3 FROM t0 WHERE c1 <= c0; } {3} # 2019-11-02 # Ticket https://sqlite.org/src/tktview/a9efb42811fa41ee286e8 db close sqlite3 db :memory: do_execsql_test index6-17.1 { CREATE TABLE t0(c0); CREATE INDEX i0 ON t0(0) WHERE c0 GLOB c0; INSERT INTO t0 VALUES (0); CREATE UNIQUE INDEX i1 ON t0(0); PRAGMA integrity_check; } {ok} do_execsql_test index6-17.2 { CREATE UNIQUE INDEX i2 ON t0(0); REPLACE INTO t0 VALUES(0); PRAGMA integrity_check; } {ok} do_execsql_test index6-17.3 { SELECT COUNT(*) FROM t0 WHERE t0.c0 GLOB t0.c0; } {1} # 2021-05-29 # Forum https://sqlite.org/forum/forumpost/d813704d7c reset_db do_execsql_test index6-18.1 { CREATE TABLE t1(a INT, b INT); INSERT INTO t1 VALUES(10,10); CREATE UNIQUE INDEX t1b ON t1(b) WHERE a>NULL; SELECT * FROM t1 WHERE a IS NOT NULL; } {10 10} finish_test |
Changes to test/index7.test.
︙ | ︙ | |||
109 110 111 112 113 114 115 | INSERT INTO t1(a,b,c) VALUES('abcde',1,101),('abdef',2,102),('xyz',3,103),('abcz',4,104); SELECT c FROM t1 WHERE a NOT LIKE 'abc%' AND a=7 ORDER BY +b; } {7} do_execsql_test index7-1.7eqp { EXPLAIN QUERY PLAN SELECT b FROM t1 WHERE a NOT LIKE 'abc%' AND a=7 ORDER BY +b; | | | 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 | INSERT INTO t1(a,b,c) VALUES('abcde',1,101),('abdef',2,102),('xyz',3,103),('abcz',4,104); SELECT c FROM t1 WHERE a NOT LIKE 'abc%' AND a=7 ORDER BY +b; } {7} do_execsql_test index7-1.7eqp { EXPLAIN QUERY PLAN SELECT b FROM t1 WHERE a NOT LIKE 'abc%' AND a=7 ORDER BY +b; } {/SEARCH t1 USING COVERING INDEX bad1 /} do_execsql_test index7-1.8 { DELETE FROM t1 WHERE c>=101; DROP INDEX IF EXISTS bad1; } {} do_test index7-1.10 { execsql { |
︙ | ︙ | |||
182 183 184 185 186 187 188 | CREATE INDEX t1c ON t1(c); ANALYZE; SELECT idx, stat FROM sqlite_stat1 ORDER BY idx; PRAGMA integrity_check; } } {t1 {15 1} t1a {10 1} t1b {8 1} t1c {15 1} ok} | | | | | | | | 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 | CREATE INDEX t1c ON t1(c); ANALYZE; SELECT idx, stat FROM sqlite_stat1 ORDER BY idx; PRAGMA integrity_check; } } {t1 {15 1} t1a {10 1} t1b {8 1} t1c {15 1} ok} # Queries use partial indices at appropriate times. # do_test index7-2.1 { execsql { CREATE TABLE t2(a,b PRIMARY KEY) without rowid; INSERT INTO t2(a,b) SELECT value, value FROM nums WHERE value<1000; UPDATE t2 SET a=NULL WHERE b%5==0; CREATE INDEX t2a1 ON t2(a) WHERE a IS NOT NULL; SELECT count(*) FROM t2 WHERE a IS NOT NULL; } } {800} do_test index7-2.2 { execsql { EXPLAIN QUERY PLAN SELECT * FROM t2 WHERE a=5; } } {/(SCAN|SEARCH) t2 USING COVERING INDEX t2a1 /} ifcapable stat4 { do_test index7-2.3stat4 { execsql { EXPLAIN QUERY PLAN SELECT * FROM t2 WHERE a IS NOT NULL; } } {/(SCAN|SEARCH) t2 USING COVERING INDEX t2a1 /} } else { do_test index7-2.3stat4 { execsql { EXPLAIN QUERY PLAN SELECT * FROM t2 WHERE a IS NOT NULL AND a>0; } } {/(SCAN|SEARCH) t2 USING COVERING INDEX t2a1 /} } do_test index7-2.4 { execsql { EXPLAIN QUERY PLAN SELECT * FROM t2 WHERE a IS NULL; } } {~/INDEX t2a1/} do_execsql_test index7-2.101 { DROP INDEX t2a1; UPDATE t2 SET a=b, b=b+10000; SELECT b FROM t2 WHERE a=15; } {10015} do_execsql_test index7-2.102 { |
︙ | ︙ | |||
317 318 319 320 321 322 323 | INSERT INTO t4 VALUES('def', 'xyz'); SELECT * FROM v4 WHERE d='xyz' AND c='def' } { def xyz } do_eqp_test index7-6.4 { SELECT * FROM v4 WHERE d='xyz' AND c='def' | | > > > > > > > > > > > > > > > > > > > > > > > > | 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 | INSERT INTO t4 VALUES('def', 'xyz'); SELECT * FROM v4 WHERE d='xyz' AND c='def' } { def xyz } do_eqp_test index7-6.4 { SELECT * FROM v4 WHERE d='xyz' AND c='def' } {SEARCH t4 USING INDEX i4 (c=?)} do_catchsql_test index7-6.5 { CREATE INDEX t5a ON t5(a) WHERE a=#1; } {1 {near "#1": syntax error}} do_execsql_test index7-7.0 { CREATE TABLE t6(x, y); INSERT INTO t6 VALUES(1, 1); INSERT INTO t6 VALUES(0, 0); SELECT * FROM t6 WHERE y IS TRUE ORDER BY x; } {1 1} do_execsql_test index7-7.1 { CREATE INDEX i6 ON t6(x) WHERE y IS NOT TRUE; SELECT * FROM t6 WHERE y IS TRUE ORDER BY x; } {1 1} # 2020-05-27. tag-20200527-1. # Incomplete stat1 information on a table with few rows should still use the # index. reset_db do_execsql_test index7-8.1 { CREATE TABLE t1(x INTEGER PRIMARY KEY, y); CREATE INDEX t1y ON t1(y) WHERE y IS NOT NULL; INSERT INTO t1(x) VALUES(1),(2); ANALYZE; EXPLAIN QUERY PLAN SELECT 1 FROM t1 WHERE y=5; } {/SEARCH t1 USING COVERING INDEX t1y/} finish_test |
Changes to test/index8.test.
︙ | ︙ | |||
37 38 39 40 41 42 43 | # Prior to the fix, the following EQP would show a table scan and a sort # rather than an index scan. # do_execsql_test 1.0eqp { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE c=4 ORDER BY a, b LIMIT 2; | | | 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | # Prior to the fix, the following EQP would show a table scan and a sort # rather than an index scan. # do_execsql_test 1.0eqp { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE c=4 ORDER BY a, b LIMIT 2; } {/SCAN t1 USING INDEX t1abc/} # If we change the index so that it no longer covers the WHERE clause, # then we should (correctly) revert to using a table scan. # do_execsql_test 1.1 { DROP INDEX t1abc; CREATE INDEX t1abd ON t1(a,b,d); |
︙ | ︙ |
Changes to test/indexedby.test.
︙ | ︙ | |||
38 39 40 41 42 43 44 | uplevel "execsql {EXPLAIN QUERY PLAN $sql}" } # These tests are to check that "EXPLAIN QUERY PLAN" is working as expected. # do_eqp_test indexedby-1.2 { select * from t1 WHERE a = 10; | | | | | | 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | uplevel "execsql {EXPLAIN QUERY PLAN $sql}" } # These tests are to check that "EXPLAIN QUERY PLAN" is working as expected. # do_eqp_test indexedby-1.2 { select * from t1 WHERE a = 10; } {SEARCH t1 USING INDEX i1 (a=?)} do_eqp_test indexedby-1.3 { select * from t1 ; } {SCAN t1} do_eqp_test indexedby-1.4 { select * from t1, t2 WHERE c = 10; } { QUERY PLAN |--SEARCH t2 USING INDEX i3 (c=?) `--SCAN t1 } # Parser tests. Test that an INDEXED BY or NOT INDEX clause can be # attached to a table in the FROM clause, but not to a sub-select or # SQL view. Also test that specifying an index that does not exist or # is attached to a different table is detected as an error. # |
︙ | ︙ | |||
86 87 88 89 90 91 92 | # EVIDENCE-OF: R-15800-25719 If index-name does not exist or cannot be # used for the query, then the preparation of the SQL statement fails. # do_test indexedby-2.4 { catchsql { SELECT * FROM t1 INDEXED BY i3 WHERE a = 'one' AND b = 'two'} } {1 {no such index: i3}} | | | | | | 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 | # EVIDENCE-OF: R-15800-25719 If index-name does not exist or cannot be # used for the query, then the preparation of the SQL statement fails. # do_test indexedby-2.4 { catchsql { SELECT * FROM t1 INDEXED BY i3 WHERE a = 'one' AND b = 'two'} } {1 {no such index: i3}} # EVIDENCE-OF: R-05301-32681 If the query optimizer is unable to use the # index specified by the INDEXED BY clause, then the query will fail # with an error. do_test indexedby-2.4.1 { catchsql { SELECT b FROM t1 INDEXED BY i1 WHERE b = 'two' } } {0 {}} do_test indexedby-2.5 { catchsql { SELECT * FROM t1 INDEXED BY i5 WHERE a = 'one' AND b = 'two'} } {1 {no such index: i5}} do_test indexedby-2.6 { catchsql { SELECT * FROM t1 INDEXED BY WHERE a = 'one' AND b = 'two'} } {1 {near "WHERE": syntax error}} |
︙ | ︙ | |||
114 115 116 117 118 119 120 | # index shall be used when accessing the preceding table, including # implied indices create by UNIQUE and PRIMARY KEY constraints. However, # the rowid can still be used to look up entries even when "NOT INDEXED" # is specified. # do_eqp_test indexedby-3.1 { SELECT * FROM t1 WHERE a = 'one' AND b = 'two' | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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 | # index shall be used when accessing the preceding table, including # implied indices create by UNIQUE and PRIMARY KEY constraints. However, # the rowid can still be used to look up entries even when "NOT INDEXED" # is specified. # do_eqp_test indexedby-3.1 { SELECT * FROM t1 WHERE a = 'one' AND b = 'two' } {/SEARCH t1 USING INDEX/} do_eqp_test indexedby-3.1.1 { SELECT * FROM t1 NOT INDEXED WHERE a = 'one' AND b = 'two' } {SCAN t1} do_eqp_test indexedby-3.1.2 { SELECT * FROM t1 NOT INDEXED WHERE rowid=1 } {/SEARCH t1 USING INTEGER PRIMARY KEY .rowid=/} do_eqp_test indexedby-3.2 { SELECT * FROM t1 INDEXED BY i1 WHERE a = 'one' AND b = 'two' } {SEARCH t1 USING INDEX i1 (a=?)} do_eqp_test indexedby-3.3 { SELECT * FROM t1 INDEXED BY i2 WHERE a = 'one' AND b = 'two' } {SEARCH t1 USING INDEX i2 (b=?)} do_test indexedby-3.4 { catchsql { SELECT * FROM t1 INDEXED BY i2 WHERE a = 'one' } } {0 {}} do_test indexedby-3.5 { catchsql { SELECT * FROM t1 INDEXED BY i2 ORDER BY a } } {0 {}} do_test indexedby-3.6 { catchsql { SELECT * FROM t1 INDEXED BY i1 WHERE a = 'one' } } {0 {}} do_test indexedby-3.7 { catchsql { SELECT * FROM t1 INDEXED BY i1 ORDER BY a } } {0 {}} do_eqp_test indexedby-3.8 { SELECT * FROM t3 INDEXED BY sqlite_autoindex_t3_1 ORDER BY e } {SCAN t3 USING INDEX sqlite_autoindex_t3_1} do_eqp_test indexedby-3.9 { SELECT * FROM t3 INDEXED BY sqlite_autoindex_t3_1 WHERE e = 10 } {SEARCH t3 USING INDEX sqlite_autoindex_t3_1 (e=?)} do_test indexedby-3.10 { catchsql { SELECT * FROM t3 INDEXED BY sqlite_autoindex_t3_1 WHERE f = 10 } } {0 {}} do_test indexedby-3.11 { catchsql { SELECT * FROM t3 INDEXED BY sqlite_autoindex_t3_2 WHERE f = 10 } } {1 {no such index: sqlite_autoindex_t3_2}} # Tests for multiple table cases. # do_eqp_test indexedby-4.1 { SELECT * FROM t1, t2 WHERE a = c } { QUERY PLAN |--SCAN t1 `--SEARCH t2 USING INDEX i3 (c=?) } do_eqp_test indexedby-4.2 { SELECT * FROM t1 INDEXED BY i1, t2 WHERE a = c } { QUERY PLAN |--SCAN t1 USING INDEX i1 `--SEARCH t2 USING INDEX i3 (c=?) } do_test indexedby-4.3 { catchsql { SELECT * FROM t1 INDEXED BY i1, t2 INDEXED BY i3 WHERE a=c } } {0 {}} do_test indexedby-4.4 { catchsql { SELECT * FROM t2 INDEXED BY i3, t1 INDEXED BY i1 WHERE a=c } } {0 {}} # Test embedding an INDEXED BY in a CREATE VIEW statement. This block # also tests that nothing bad happens if an index refered to by # a CREATE VIEW statement is dropped and recreated. # do_execsql_test indexedby-5.1 { CREATE VIEW v2 AS SELECT * FROM t1 INDEXED BY i1 WHERE a > 5; EXPLAIN QUERY PLAN SELECT * FROM v2 } {/*SEARCH t1 USING INDEX i1 (a>?)*/} do_execsql_test indexedby-5.2 { EXPLAIN QUERY PLAN SELECT * FROM v2 WHERE b = 10 } {/*SEARCH t1 USING INDEX i1 (a>?)*/} do_test indexedby-5.3 { execsql { DROP INDEX i1 } catchsql { SELECT * FROM v2 } } {1 {no such index: i1}} do_test indexedby-5.4 { # Recreate index i1 in such a way as it cannot be used by the view query. execsql { CREATE INDEX i1 ON t1(b) } catchsql { SELECT * FROM v2 } } {0 {}} do_test indexedby-5.5 { # Drop and recreate index i1 again. This time, create it so that it can # be used by the query. execsql { DROP INDEX i1 ; CREATE INDEX i1 ON t1(a) } catchsql { SELECT * FROM v2 } } {0 {}} # Test that "NOT INDEXED" may use the rowid index, but not others. # do_eqp_test indexedby-6.1 { SELECT * FROM t1 WHERE b = 10 ORDER BY rowid } {SEARCH t1 USING INDEX i2 (b=?)} do_eqp_test indexedby-6.2 { SELECT * FROM t1 NOT INDEXED WHERE b = 10 ORDER BY rowid } {SCAN t1} # EVIDENCE-OF: R-40297-14464 The INDEXED BY phrase forces the SQLite # query planner to use a particular named index on a DELETE, SELECT, or # UPDATE statement. # # Test that "INDEXED BY" can be used in a DELETE statement. # do_eqp_test indexedby-7.1 { DELETE FROM t1 WHERE a = 5 } {SEARCH t1 USING INDEX i1 (a=?)} do_eqp_test indexedby-7.2 { DELETE FROM t1 NOT INDEXED WHERE a = 5 } {SCAN t1} do_eqp_test indexedby-7.3 { DELETE FROM t1 INDEXED BY i1 WHERE a = 5 } {SEARCH t1 USING INDEX i1 (a=?)} do_eqp_test indexedby-7.4 { DELETE FROM t1 INDEXED BY i1 WHERE a = 5 AND b = 10 } {SEARCH t1 USING INDEX i1 (a=?)} do_eqp_test indexedby-7.5 { DELETE FROM t1 INDEXED BY i2 WHERE a = 5 AND b = 10 } {SEARCH t1 USING INDEX i2 (b=?)} do_test indexedby-7.6 { catchsql { DELETE FROM t1 INDEXED BY i2 WHERE a = 5} } {0 {}} # Test that "INDEXED BY" can be used in an UPDATE statement. # do_eqp_test indexedby-8.1 { UPDATE t1 SET rowid=rowid+1 WHERE a = 5 } {SEARCH t1 USING COVERING INDEX i1 (a=?)} do_eqp_test indexedby-8.2 { UPDATE t1 NOT INDEXED SET rowid=rowid+1 WHERE a = 5 } {SCAN t1} do_eqp_test indexedby-8.3 { UPDATE t1 INDEXED BY i1 SET rowid=rowid+1 WHERE a = 5 } {SEARCH t1 USING COVERING INDEX i1 (a=?)} do_eqp_test indexedby-8.4 { UPDATE t1 INDEXED BY i1 SET rowid=rowid+1 WHERE a = 5 AND b = 10 } {SEARCH t1 USING INDEX i1 (a=?)} do_eqp_test indexedby-8.5 { UPDATE t1 INDEXED BY i2 SET rowid=rowid+1 WHERE a = 5 AND b = 10 } {SEARCH t1 USING INDEX i2 (b=?)} do_test indexedby-8.6 { catchsql { UPDATE t1 INDEXED BY i2 SET rowid=rowid+1 WHERE a = 5} } {0 {}} # Test that bug #3560 is fixed. # do_test indexedby-9.1 { execsql { CREATE TABLE maintable( id integer); CREATE TABLE joinme(id_int integer, id_text text); CREATE INDEX joinme_id_text_idx on joinme(id_text); CREATE INDEX joinme_id_int_idx on joinme(id_int); } } {} do_test indexedby-9.2 { catchsql { select * from maintable as m inner join joinme as j indexed by joinme_id_text_idx on ( m.id = j.id_int) } } {0 {}} do_test indexedby-9.3 { catchsql { select * from maintable, joinme INDEXED by joinme_id_text_idx } } {0 {}} # Make sure we can still create tables, indices, and columns whose name # is "indexed". # do_test indexedby-10.1 { execsql { CREATE TABLE indexed(x,y); |
︙ | ︙ | |||
334 335 336 337 338 339 340 | SELECT a,b,rowid FROM x1 INDEXED BY x1i WHERE a=1 AND b=1 AND rowid='3'; } {1 1 3} do_execsql_test 11.4 { SELECT a,b,rowid FROM x1 INDEXED BY x1i WHERE a=1 AND b=1 AND rowid='3.0'; } {1 1 3} do_eqp_test 11.5 { SELECT a,b,rowid FROM x1 INDEXED BY x1i WHERE a=1 AND b=1 AND rowid='3.0'; | | | | 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 | SELECT a,b,rowid FROM x1 INDEXED BY x1i WHERE a=1 AND b=1 AND rowid='3'; } {1 1 3} do_execsql_test 11.4 { SELECT a,b,rowid FROM x1 INDEXED BY x1i WHERE a=1 AND b=1 AND rowid='3.0'; } {1 1 3} do_eqp_test 11.5 { SELECT a,b,rowid FROM x1 INDEXED BY x1i WHERE a=1 AND b=1 AND rowid='3.0'; } {SEARCH x1 USING COVERING INDEX x1i (a=? AND b=? AND rowid=?)} do_execsql_test 11.6 { CREATE TABLE x2(c INTEGER PRIMARY KEY, a, b TEXT); CREATE INDEX x2i ON x2(a, b); INSERT INTO x2 VALUES(1, 1, 1); INSERT INTO x2 VALUES(2, 1, 1); INSERT INTO x2 VALUES(3, 1, 1); INSERT INTO x2 VALUES(4, 1, 1); } do_execsql_test 11.7 { SELECT a,b,c FROM x2 INDEXED BY x2i WHERE a=1 AND b=1 AND c=3; } {1 1 3} do_execsql_test 11.8 { SELECT a,b,c FROM x2 INDEXED BY x2i WHERE a=1 AND b=1 AND c='3'; } {1 1 3} do_execsql_test 11.9 { SELECT a,b,c FROM x2 INDEXED BY x2i WHERE a=1 AND b=1 AND c='3.0'; } {1 1 3} do_eqp_test 11.10 { SELECT a,b,c FROM x2 INDEXED BY x2i WHERE a=1 AND b=1 AND c='3.0'; } {SEARCH x2 USING COVERING INDEX x2i (a=? AND b=? AND rowid=?)} #------------------------------------------------------------------------- # Check INDEXED BY works (throws an exception) with partial indexes that # cannot be used. do_execsql_test 12.1 { CREATE TABLE o1(x INTEGER PRIMARY KEY, y, z); CREATE INDEX p1 ON o1(z); |
︙ | ︙ |
Changes to test/indexexpr1.test.
︙ | ︙ | |||
71 72 73 74 75 76 77 | } {2 3 5} do_execsql_test indexexpr1-150eqp { EXPLAIN QUERY PLAN SELECT rowid FROM t1 WHERE substr(a,b,3) IN ('and','l_t','xyz') ORDER BY +rowid; } {/USING INDEX t1abx/} | > | | | | | | | | | | | | > | | | 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 | } {2 3 5} do_execsql_test indexexpr1-150eqp { EXPLAIN QUERY PLAN SELECT rowid FROM t1 WHERE substr(a,b,3) IN ('and','l_t','xyz') ORDER BY +rowid; } {/USING INDEX t1abx/} ifcapable altertable { do_execsql_test indexexpr1-160 { ALTER TABLE t1 ADD COLUMN d; UPDATE t1 SET d=length(a); CREATE INDEX t1a2 ON t1(SUBSTR(a, 27, 3)) WHERE d>=29; SELECT rowid, b, c FROM t1 WHERE substr(a,27,3)=='ord' AND d>=29; } {1 1 1} do_execsql_test indexexpr1-160eqp { EXPLAIN QUERY PLAN SELECT rowid, b, c FROM t1 WHERE substr(a,27,3)=='ord' AND d>=29; } {/USING INDEX t1a2/} } # ORDER BY using an indexed expression # do_execsql_test indexexpr1-170 { CREATE INDEX t1alen ON t1(length(a)); SELECT length(a) FROM t1 ORDER BY length(a); } {20 25 27 29 38 52} do_execsql_test indexexpr1-170eqp { EXPLAIN QUERY PLAN SELECT length(a) FROM t1 ORDER BY length(a); } {/SCAN t1 USING INDEX t1alen/} do_execsql_test indexexpr1-171 { SELECT length(a) FROM t1 ORDER BY length(a) DESC; } {52 38 29 27 25 20} do_execsql_test indexexpr1-171eqp { EXPLAIN QUERY PLAN SELECT length(a) FROM t1 ORDER BY length(a) DESC; } {/SCAN t1 USING INDEX t1alen/} do_execsql_test indexexpr1-200 { DROP TABLE t1; CREATE TABLE t1(id ANY PRIMARY KEY, a,b,c) WITHOUT ROWID; INSERT INTO t1(id,a,b,c) VALUES(1,'In_the_beginning_was_the_Word',1,1), (2,'and_the_Word_was_with_God',1,2), |
︙ | ︙ | |||
162 163 164 165 166 167 168 | } {2 3 5} do_execsql_test indexexpr1-250eqp { EXPLAIN QUERY PLAN SELECT id FROM t1 WHERE substr(a,b,3) IN ('and','l_t','xyz') ORDER BY +id; } {/USING INDEX t1abx/} | > | | | | | | | | | | | | > | | 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 | } {2 3 5} do_execsql_test indexexpr1-250eqp { EXPLAIN QUERY PLAN SELECT id FROM t1 WHERE substr(a,b,3) IN ('and','l_t','xyz') ORDER BY +id; } {/USING INDEX t1abx/} ifcapable altertable { do_execsql_test indexexpr1-260 { ALTER TABLE t1 ADD COLUMN d; UPDATE t1 SET d=length(a); CREATE INDEX t1a2 ON t1(SUBSTR(a, 27, 3)) WHERE d>=29; SELECT id, b, c FROM t1 WHERE substr(a,27,3)=='ord' AND d>=29; } {1 1 1} do_execsql_test indexexpr1-260eqp { EXPLAIN QUERY PLAN SELECT id, b, c FROM t1 WHERE substr(a,27,3)=='ord' AND d>=29; } {/USING INDEX t1a2/} } do_catchsql_test indexexpr1-300 { CREATE TABLE t2(a,b,c); INSERT INTO t2 VALUES(1,2,3); CREATE INDEX t2x1 ON t2(a,b+random()); } {1 {non-deterministic functions prohibited in index expressions}} do_catchsql_test indexexpr1-301 { CREATE INDEX t2x1 ON t2(julianday('now',a)); } {1 {non-deterministic use of julianday() in an index}} do_catchsql_test indexexpr1-310 { CREATE INDEX t2x2 ON t2(a,b+(SELECT 15)); } {1 {subqueries prohibited in index expressions}} do_catchsql_test indexexpr1-320 { CREATE TABLE e1(x,y,UNIQUE(y,substr(x,1,5))); } {1 {expressions prohibited in PRIMARY KEY and UNIQUE constraints}} do_catchsql_test indexexpr1-330 { |
︙ | ︙ | |||
441 442 443 444 445 446 447 | INSERT INTO t1 VALUES('1234',0),('001234',2),('01234',1); SELECT b FROM t1 WHERE lower(a)='1234' ORDER BY +b; } {0 1 2 3} do_execsql_test indexexpr-1620 { SELECT b FROM t1 WHERE lower(a)='01234' ORDER BY +b; } {} | > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | INSERT INTO t1 VALUES('1234',0),('001234',2),('01234',1); SELECT b FROM t1 WHERE lower(a)='1234' ORDER BY +b; } {0 1 2 3} do_execsql_test indexexpr-1620 { SELECT b FROM t1 WHERE lower(a)='01234' ORDER BY +b; } {} # 2019-08-09 https://www.sqlite.org/src/info/9080b6227fabb466 # ExprImpliesExpr theorem prover bug: # "(NULL IS FALSE) IS FALSE" does not imply "NULL IS NULL" # do_execsql_test indexexpr-1700 { DROP TABLE IF EXISTS t0; CREATE TABLE t0(c0); INSERT INTO t0(c0) VALUES (0); CREATE INDEX i0 ON t0(NULL > c0) WHERE (NULL NOT NULL); SELECT * FROM t0 WHERE ((NULL IS FALSE) IS FALSE); } {0} # 2019-09-02 https://www.sqlite.org/src/tktview/57af00b6642ecd6848 # When the expression of an an index-on-expression references a # table column of type REAL that is actually holding an MEM_IntReal # value, be sure to use the REAL value and not the INT value when # computing the expression. # ifcapable like_match_blobs { do_execsql_test indexexpr-1800 { DROP TABLE IF EXISTS t0; CREATE TABLE t0(c0 REAL, c1 TEXT); CREATE INDEX i0 ON t0(+c0, c0); INSERT INTO t0(c0) VALUES(0); SELECT CAST(+ t0.c0 AS BLOB) LIKE 0 FROM t0; } {0} do_execsql_test indexexpr-1810 { SELECT CAST(+ t0.c0 AS BLOB) LIKE '0.0' FROM t0; } {1} do_execsql_test indexexpr-1820 { DROP TABLE IF EXISTS t1; CREATE TABLE t1(x REAL); CREATE INDEX t1x ON t1(x, +x); INSERT INTO t1(x) VALUES(2); SELECT +x FROM t1 WHERE x=2; } {2.0} } finish_test |
Changes to test/indexexpr2.test.
︙ | ︙ | |||
89 90 91 92 93 94 95 | do_eqp_test 3.3.1 { SELECT json_extract(x, '$.b') FROM t2 WHERE json_extract(x, '$.b') IS NOT NULL AND json_extract(x, '$.a') IS NULL GROUP BY json_extract(x, '$.b') COLLATE nocase ORDER BY json_extract(x, '$.b') COLLATE nocase; } [string map {"\n " \n} { QUERY PLAN | | | | 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 | do_eqp_test 3.3.1 { SELECT json_extract(x, '$.b') FROM t2 WHERE json_extract(x, '$.b') IS NOT NULL AND json_extract(x, '$.a') IS NULL GROUP BY json_extract(x, '$.b') COLLATE nocase ORDER BY json_extract(x, '$.b') COLLATE nocase; } [string map {"\n " \n} { QUERY PLAN |--SCAN t2 `--USE TEMP B-TREE FOR GROUP BY }] do_execsql_test 3.3.2 { CREATE INDEX i3 ON t3(json_extract(x, '$.a'), json_extract(x, '$.b')); } {} do_eqp_test 3.3.3 { SELECT json_extract(x, '$.b') FROM t3 WHERE json_extract(x, '$.b') IS NOT NULL AND json_extract(x, '$.a') IS NULL GROUP BY json_extract(x, '$.b') COLLATE nocase ORDER BY json_extract(x, '$.b') COLLATE nocase; } [string map {"\n " \n} { QUERY PLAN |--SEARCH t3 USING INDEX i3 (<expr>=?) `--USE TEMP B-TREE FOR GROUP BY }] } do_execsql_test 3.4.0 { CREATE TABLE t4(a, b); INSERT INTO t4 VALUES('.ABC', 1); |
︙ | ︙ | |||
150 151 152 153 154 155 156 | do_execsql_test 3.4.5 { CREATE INDEX i4 ON t4( Substr(a,-2) COLLATE nocase ); SELECT * FROM t4 ORDER BY Substr(a,-2) COLLATE nocase; } {.ABC1 1 .abc2 2 .ABC3 3 .abc4 4} do_execsql_test 3.4.5eqp { EXPLAIN QUERY PLAN SELECT * FROM t4 ORDER BY Substr(a,-2) COLLATE nocase; | | | 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 | do_execsql_test 3.4.5 { CREATE INDEX i4 ON t4( Substr(a,-2) COLLATE nocase ); SELECT * FROM t4 ORDER BY Substr(a,-2) COLLATE nocase; } {.ABC1 1 .abc2 2 .ABC3 3 .abc4 4} do_execsql_test 3.4.5eqp { EXPLAIN QUERY PLAN SELECT * FROM t4 ORDER BY Substr(a,-2) COLLATE nocase; } {/SCAN t4 USING INDEX i4/} do_execsql_test 3.4.6 { SELECT * FROM t4 ORDER BY Substr(a,-2) COLLATE binary; } {.ABC1 1 .ABC3 3 .abc2 2 .abc4 4} # 2014-09-15: Verify that UPDATEs of columns not referenced by a # index on expression do not modify the index. # |
︙ | ︙ | |||
245 246 247 248 249 250 251 | CREATE INDEX t5a ON t5( abs(a) ); CREATE INDEX t5b ON t5( abs(b) ); } do_execsql_test 5.4 { SELECT * FROM t5 WHERE abs(a)=2 or abs(b)=9; } {2 4 3 9} | > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | CREATE INDEX t5a ON t5( abs(a) ); CREATE INDEX t5b ON t5( abs(b) ); } do_execsql_test 5.4 { SELECT * FROM t5 WHERE abs(a)=2 or abs(b)=9; } {2 4 3 9} #------------------------------------------------------------------------- do_execsql_test 6.0 { CREATE TABLE x1(a INTEGER PRIMARY KEY, b); INSERT INTO x1 VALUES (1, 123), (2, '123'), (3, '123abc'), (4, 123.0), (5, 1234); } do_execsql_test 6.1.1 { SELECT a, b FROM x1 WHERE CAST(b AS INTEGER) = 123; } {1 123 2 123 3 123abc 4 123.0} do_execsql_test 6.1.2 { CREATE INDEX x1i ON x1( CAST(b AS INTEGER) ); SELECT a, b FROM x1 WHERE CAST(b AS INTEGER) = 123; } {1 123 2 123 3 123abc 4 123.0} do_eqp_test 6.1.3 { SELECT a, b FROM x1 WHERE CAST(b AS INTEGER) = 123; } {SEARCH x1 USING INDEX x1i (<expr>=?)} do_execsql_test 6.2.1 { SELECT a, b FROM x1 WHERE CAST(b AS TEXT) = 123; } {1 123 2 123} do_execsql_test 6.2.2 { CREATE INDEX x1i2 ON x1( CAST(b AS TEXT) ); SELECT a, b FROM x1 WHERE CAST(b AS TEXT) = 123; } {1 123 2 123} do_eqp_test 6.2.3 { SELECT a, b FROM x1 WHERE CAST(b AS TEXT) = 123; } {SEARCH x1 USING INDEX x1i2 (<expr>=?)} do_execsql_test 7.0 { CREATE TABLE IF NOT EXISTS t0(c0); INSERT INTO t0(c0) VALUES (-9223372036854775808); BEGIN; } do_catchsql_test 7.1 { CREATE INDEX i0 ON t0(ABS(c0)); } {1 {integer overflow}} do_execsql_test 7.2 { COMMIT; SELECT sql FROM sqlite_master WHERE tbl_name = 't0'; CREATE INDEX i0 ON t0(c0); } {{CREATE TABLE t0(c0)}} do_execsql_test 7.3 { REINDEX; } {} #------------------------------------------------------------------------- reset_db do_execsql_test 8.0 { CREATE TABLE t0(c0); CREATE INDEX i0 ON t0(c0) WHERE c0 NOT NULL; INSERT INTO t0(c0) VALUES (NULL); } do_execsql_test 8.1.1 { SELECT * FROM t0 WHERE ~('' BETWEEN t0.c0 AND TRUE); } {{}} do_execsql_test 8.1.2 { SELECT ~('' BETWEEN t0.c0 AND TRUE) FROM t0; } {-1} foreach {tn expr} { 1 " 0 == (34 BETWEEN c0 AND 33)" 2 " 1 != (34 BETWEEN c0 AND 33)" 3 "-1 < (34 BETWEEN c0 AND 33)" 4 "-1 <= (34 BETWEEN c0 AND 33)" 5 " 1 > (34 BETWEEN c0 AND 33)" 6 " 1 >= (34 BETWEEN c0 AND 33)" 7 " 1 - (34 BETWEEN c0 AND 33)" 8 "-1 + (34 BETWEEN c0 AND 33)" 9 " 1 | (34 BETWEEN c0 AND 33)" 10 " 1 << (34 BETWEEN c0 AND 33)" 11 " 1 >> (34 BETWEEN c0 AND 33)" 12 " 1 || (34 BETWEEN c0 AND 33)" } { do_execsql_test 8.3.$tn.1 "SELECT * FROM t0 WHERE $expr ORDER BY c0" { {} } do_execsql_test 8.3.$tn.2 "SELECT ($expr) IS TRUE FROM t0" { 1 } } do_execsql_test 8.4 { CREATE TABLE t1(a, b); INSERT INTO t1 VALUES(1, 2), (3, 4); CREATE TABLE t2(x, y); } foreach {tn expr} { 1 " 0 == (a=0 AND y=1)" 2 " 1 != (a=0 AND y=1)" 3 "-1 < (a=0 AND y=1)" 4 "-1 <= (a=0 AND y=1)" 5 " 1 > (a=0 AND y=1)" 6 " 1 >= (a=0 AND y=1)" 7 " 1 - (a=0 AND y=1)" 8 "-1 + (a=0 AND y=1)" 9 " 1 | (a=0 AND y=1)" 10 "1 << (a=0 AND y=1)" 11 "1 >> (a=0 AND y=1)" 12 "1 || (a=0 AND y=1)" 13 " 0 == (10 BETWEEN y AND b)" 14 " 1 != (10 BETWEEN y AND b)" 15 "-1 < (10 BETWEEN y AND b)" 16 "-1 <= (10 BETWEEN y AND b)" 17 " 1 > (10 BETWEEN y AND b)" 18 " 1 >= (10 BETWEEN y AND b)" 19 " 1 - (10 BETWEEN y AND b)" 20 "-1 + (10 BETWEEN y AND b)" 21 " 1 | (10 BETWEEN y AND b)" 22 " 1 << (10 BETWEEN y AND b)" 23 " 1 >> (10 BETWEEN y AND b)" 24 " 1 || (10 BETWEEN y AND b)" 25 " 1 || (10 BETWEEN y AND b)" } { do_execsql_test 8.5.$tn.1 " SELECT * FROM t1 LEFT JOIN t2 WHERE $expr " {1 2 {} {} 3 4 {} {}} do_execsql_test 8.5.$tn.2 " SELECT ($expr) IS TRUE FROM t1 LEFT JOIN t2 " {1 1} } finish_test |
Changes to test/indexfault.test.
︙ | ︙ | |||
332 333 334 335 336 337 338 339 340 341 342 | faultsim_restore_and_reopen set ::nReadCall 0 sqlite3_soft_heap_limit 0 } -body { execsql { CREATE INDEX i1 ON t1(x) } faultsim_test_result {0 {}} } uninstall_custom_faultsim finish_test | > > > > > > > > > > | 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 | faultsim_restore_and_reopen set ::nReadCall 0 sqlite3_soft_heap_limit 0 } -body { execsql { CREATE INDEX i1 ON t1(x) } faultsim_test_result {0 {}} } do_faultsim_test 5 -prep { reset_db } -body { execsql { CREATE TABLE reallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallylongname(a PRIMARY KEY) WITHOUT ROWID; } } -test { faultsim_test_result {0 {}} } uninstall_custom_faultsim finish_test |
Changes to test/insert.test.
|
| | < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | # 2001-09-15 # # 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 the INSERT statement. # set testdir [file dirname $argv0] source $testdir/tester.tcl # Try to insert into a non-existant table. # do_test insert-1.1 { |
︙ | ︙ | |||
445 446 447 448 449 450 451 | CREATE TABLE t13(a INTEGER PRIMARY KEY,b UNIQUE); CREATE INDEX t13x1 ON t13(-b=b); INSERT INTO t13 VALUES(1,5),(6,2); REPLACE INTO t13 SELECT b,0 FROM t13; SELECT * FROM t13 ORDER BY +b; } {2 0 6 2 1 5} | > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | CREATE TABLE t13(a INTEGER PRIMARY KEY,b UNIQUE); CREATE INDEX t13x1 ON t13(-b=b); INSERT INTO t13 VALUES(1,5),(6,2); REPLACE INTO t13 SELECT b,0 FROM t13; SELECT * FROM t13 ORDER BY +b; } {2 0 6 2 1 5} # 2019-01-17. From the chromium fuzzer. # do_execsql_test insert-14.1 { DROP TABLE IF EXISTS t14; CREATE TABLE t14(x INTEGER PRIMARY KEY); INSERT INTO t14 VALUES(CASE WHEN 1 THEN null END); SELECT x FROM t14; } {1} integrity_check insert-14.2 # 2019-08-12. # do_execsql_test insert-15.1 { DROP TABLE IF EXISTS t1; DROP TABLE IF EXISTS t2; CREATE TABLE t1(a INTEGER PRIMARY KEY, b TEXT); CREATE INDEX i1 ON t1(b); CREATE TABLE t2(a, b); INSERT INTO t2 VALUES(4, randomblob(31000)); INSERT INTO t2 VALUES(4, randomblob(32000)); INSERT INTO t2 VALUES(4, randomblob(33000)); REPLACE INTO t1 SELECT a, b FROM t2; SELECT a, length(b) FROM t1; } {4 33000} # 2019-10-16 # ticket https://www.sqlite.org/src/info/a8a4847a2d96f5de # On a REPLACE INTO, if an AFTER trigger adds back the conflicting # row, you can end up with the wrong number of rows in an index. # db close sqlite3 db :memory: do_catchsql_test insert-16.1 { PRAGMA recursive_triggers = true; CREATE TABLE t0(c0,c1); CREATE UNIQUE INDEX i0 ON t0(c0); INSERT INTO t0(c0,c1) VALUES(123,1); CREATE TRIGGER tr0 AFTER DELETE ON t0 BEGIN INSERT INTO t0 VALUES(123,2); END; REPLACE INTO t0(c0,c1) VALUES(123,3); } {1 {UNIQUE constraint failed: t0.c0}} do_execsql_test insert-16.2 { SELECT * FROM t0; } {123 1} integrity_check insert-16.3 do_catchsql_test insert-16.4 { CREATE TABLE t1(a INTEGER PRIMARY KEY, b); CREATE INDEX t1b ON t1(b); INSERT INTO t1 VALUES(1, 'one'); CREATE TRIGGER tr3 AFTER DELETE ON t1 BEGIN INSERT INTO t1 VALUES(1, 'three'); END; REPLACE INTO t1 VALUES(1, 'two'); } {1 {UNIQUE constraint failed: t1.a}} integrity_check insert-16.5 do_catchsql_test insert-16.6 { PRAGMA foreign_keys = 1; CREATE TABLE p1(a, b UNIQUE); CREATE TABLE c1(c, d REFERENCES p1(b) ON DELETE CASCADE); CREATE TRIGGER tr6 AFTER DELETE ON c1 BEGIN INSERT INTO p1 VALUES(4, 1); END; INSERT INTO p1 VALUES(1, 1); INSERT INTO c1 VALUES(2, 1); REPLACE INTO p1 VALUES(3, 1);2 } {1 {UNIQUE constraint failed: p1.b}} integrity_check insert-16.7 # 2019-10-25 ticket c1e19e12046d23fe do_catchsql_test insert-17.1 { PRAGMA temp.recursive_triggers = true; DROP TABLE IF EXISTS t0; CREATE TABLE t0(aa, bb); CREATE UNIQUE INDEX t0bb ON t0(bb); CREATE TRIGGER "r17.1" BEFORE DELETE ON t0 BEGIN INSERT INTO t0(aa,bb) VALUES(99,1); END; INSERT INTO t0(aa,bb) VALUES(10,20); REPLACE INTO t0(aa,bb) VALUES(30,20); } {1 {UNIQUE constraint failed: t0.rowid}} integrity_check insert-17.2 do_catchsql_test insert-17.3 { DROP TABLE IF EXISTS t1; CREATE TABLE t1(a, b UNIQUE, c UNIQUE); INSERT INTO t1(a,b,c) VALUES(1,1,1),(2,2,2),(3,3,3),(4,4,4); CREATE TRIGGER "r17.3" AFTER DELETE ON t1 WHEN OLD.c<>3 BEGIN INSERT INTO t1(rowid,a,b,c) VALUES(100,100,100,3); END; REPLACE INTO t1(rowid,a,b,c) VALUES(200,1,2,3); } {1 {UNIQUE constraint failed: t1.c}} integrity_check insert-17.4 do_execsql_test insert-17.5 { CREATE TABLE t2(a INTEGER PRIMARY KEY, b); CREATE UNIQUE INDEX t2b ON t2(b); INSERT INTO t2(a,b) VALUES(1,1),(2,2),(3,3),(4,4); CREATE TABLE fire(x); CREATE TRIGGER t2r1 AFTER DELETE ON t2 BEGIN INSERT INTO fire VALUES(old.a); END; UPDATE OR REPLACE t2 SET a=4, b=3 WHERE a=1; SELECT *, 'x' FROM t2 ORDER BY a; } {2 2 x 4 3 x} do_execsql_test insert-17.6 { SELECT x FROM fire ORDER BY x; } {3 4} do_execsql_test insert-17.7 { DELETE FROM t2; DELETE FROM fire; INSERT INTO t2(a,b) VALUES(1,1),(2,2),(3,3),(4,4); UPDATE OR REPLACE t2 SET a=1, b=3 WHERE a=1; SELECT *, 'x' FROM t2 ORDER BY a; } {1 3 x 2 2 x 4 4 x} do_execsql_test insert-17.8 { SELECT x FROM fire ORDER BY x; } {3} do_execsql_test insert-17.10 { CREATE TABLE t3(a INTEGER PRIMARY KEY, b INT, c INT, d INT); CREATE UNIQUE INDEX t3bpi ON t3(b) WHERE c<=d; CREATE UNIQUE INDEX t3d ON t3(d); INSERT INTO t3(a,b,c,d) VALUES(1,1,1,1),(2,1,3,2),(3,4,5,6); CREATE TRIGGER t3r1 AFTER DELETE ON t3 BEGIN SELECT 'hi'; END; REPLACE INTO t3(a,b,c,d) VALUES(4,4,8,9); } {} do_execsql_test insert-17.11 { SELECT *, 'x' FROM t3 ORDER BY a; } {1 1 1 1 x 2 1 3 2 x 4 4 8 9 x} do_execsql_test insert-17.12 { REPLACE INTO t3(a,b,c,d) VALUES(5,1,11,2); SELECT *, 'x' FROM t3 ORDER BY a; } {1 1 1 1 x 4 4 8 9 x 5 1 11 2 x} do_execsql_test insert-17.13 { DELETE FROM t3; INSERT INTO t3(a,b,c,d) VALUES(1,1,1,1),(2,1,3,2),(3,4,5,6); DROP TRIGGER t3r1; CREATE TRIGGER t3r1 AFTER DELETE ON t3 BEGIN INSERT INTO t3(b,c,d) VALUES(old.b,old.c,old.d); END; } {} do_catchsql_test insert-17.14 { REPLACE INTO t3(a,b,c,d) VALUES(4,4,8,9); } {1 {UNIQUE constraint failed: t3.b}} do_catchsql_test insert-17.15 { REPLACE INTO t3(a,b,c,d) VALUES(5,1,11,2); } {1 {UNIQUE constraint failed: t3.d}} finish_test |
Changes to test/insert4.test.
︙ | ︙ | |||
30 31 32 33 34 35 36 37 | # proc xferopt_test {testname N} { do_test $testname {set ::sqlite3_xferopt_count} $N } # Create tables used for testing. # execsql { | > < | | 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 | # proc xferopt_test {testname N} { do_test $testname {set ::sqlite3_xferopt_count} $N } # Create tables used for testing. # sqlite3_db_config db LEGACY_FILE_FORMAT 0 execsql { CREATE TABLE t1(a int, b int, check(b>a)); CREATE TABLE t2(x int, y int); CREATE VIEW v2 AS SELECT y, x FROM t2; CREATE TABLE t3(a int, b int); } # Ticket #2252. Make sure the an INSERT from identical tables # does not violate constraints. # do_test insert4-1.1 { set sqlite3_xferopt_count 0 execsql { DELETE FROM t1; DELETE FROM t2; INSERT INTO t2 VALUES(9,1); } catchsql { INSERT INTO t1 SELECT * FROM t2; } } {1 {CHECK constraint failed: b>a}} xferopt_test insert4-1.2 0 do_test insert4-1.3 { execsql { SELECT * FROM t1; } } {} |
︙ | ︙ | |||
98 99 100 101 102 103 104 | xferopt_test insert4-2.3.2 0 do_test insert4-2.3.3 { catchsql { DELETE FROM t1; INSERT INTO t1 SELECT * FROM t2 LIMIT 1; SELECT * FROM t1; } | | | | 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 | xferopt_test insert4-2.3.2 0 do_test insert4-2.3.3 { catchsql { DELETE FROM t1; INSERT INTO t1 SELECT * FROM t2 LIMIT 1; SELECT * FROM t1; } } {1 {CHECK constraint failed: b>a}} xferopt_test insert4-2.3.4 0 # Do not run the transfer optimization if there is a DISTINCT # do_test insert4-2.4.1 { execsql { DELETE FROM t3; INSERT INTO t3 SELECT DISTINCT * FROM t2; SELECT * FROM t3; } } {9 1 1 9} xferopt_test insert4-2.4.2 0 do_test insert4-2.4.3 { catchsql { DELETE FROM t1; INSERT INTO t1 SELECT DISTINCT * FROM t2; } } {1 {CHECK constraint failed: b>a}} xferopt_test insert4-2.4.4 0 # The following procedure constructs two tables then tries to transfer # data from one table to the other. Checks are made to make sure the # transfer is successful and that the transfer optimization was used or # not, as appropriate. # |
︙ | ︙ | |||
312 313 314 315 316 317 318 | do_test insert4-6.6 { execsql { CREATE TABLE t6b(x CHECK( x<>'abc' COLLATE nocase )); } catchsql { INSERT INTO t6b SELECT * FROM t6a; } | | | | 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 | do_test insert4-6.6 { execsql { CREATE TABLE t6b(x CHECK( x<>'abc' COLLATE nocase )); } catchsql { INSERT INTO t6b SELECT * FROM t6a; } } {1 {CHECK constraint failed: x<>'abc' COLLATE nocase}} do_test insert4-6.7 { execsql { DROP TABLE t6b; CREATE TABLE t6b(x CHECK( x COLLATE nocase <>'abc' )); } catchsql { INSERT INTO t6b SELECT * FROM t6a; } } {1 {CHECK constraint failed: x COLLATE nocase <>'abc'}} # Ticket [6284df89debdfa61db8073e062908af0c9b6118e] # Disable the xfer optimization if the destination table contains # a foreign key constraint # ifcapable foreignkey { do_test insert4-7.1 { |
︙ | ︙ | |||
594 595 596 597 598 599 600 | do_test 10.3 { execsql { PRAGMA integrity_check } set sqlite3_xferopt_count 0 execsql { INSERT INTO x SELECT * FROM t8 } set sqlite3_xferopt_count } {1} | > > | > > > > > > > > > > > > > > > > > > | 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 | do_test 10.3 { execsql { PRAGMA integrity_check } set sqlite3_xferopt_count 0 execsql { INSERT INTO x SELECT * FROM t8 } set sqlite3_xferopt_count } {1} #------------------------------------------------------------------------- # xfer transfer between tables where the source has an empty partial index. # do_execsql_test 11.0 { CREATE TABLE t9(a, b, c); CREATE INDEX t9a ON t9(a); CREATE INDEX t9b ON t9(b) WHERE c=0; INSERT INTO t9 VALUES(1, 1, 1); INSERT INTO t9 VALUES(2, 2, 2); INSERT INTO t9 VALUES(3, 3, 3); CREATE TABLE t10(a, b, c); CREATE INDEX t10a ON t10(a); CREATE INDEX t10b ON t10(b) WHERE c=0; INSERT INTO t10 SELECT * FROM t9; SELECT * FROM t10; PRAGMA integrity_check; } {1 1 1 2 2 2 3 3 3 ok} finish_test |
Added test/insertfault.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 | # 2019-01-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. # #*********************************************************************** # # Test cases for INSERT set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix insertfault do_execsql_test 1.0 { CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c, d DEFAULT true); INSERT INTO t1 DEFAULT VALUES; SELECT * FROM t1; } {1 {} {} 1} faultsim_save_and_close breakpoint do_faultsim_test 1 -faults oom* -prep { faultsim_restore_and_reopen db eval { SELECT * FROM sqlite_master } } -body { execsql { SELECT * FROM t1 } } -test { faultsim_test_result {0 {1 {} {} 1}} } finish_test |
Changes to test/instr.test.
︙ | ︙ | |||
252 253 254 255 256 257 258 259 260 | SELECT instr(X'', 'abc') } 0 do_execsql_test instr-1.64 { CREATE TABLE x1(a, b); INSERT INTO x1 VALUES(X'', 'abc'); SELECT instr(a, b) FROM x1; } 0 finish_test | > > > > > > > > > > > > > > > > > > > > > | 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 | SELECT instr(X'', 'abc') } 0 do_execsql_test instr-1.64 { CREATE TABLE x1(a, b); INSERT INTO x1 VALUES(X'', 'abc'); SELECT instr(a, b) FROM x1; } 0 # 2019-09-16 ticket https://www.sqlite.org/src/info/587791f92620090e # do_execsql_test instr-2.0 { DROP TABLE IF EXISTS t0; CREATE TABLE t0(c0 PRIMARY KEY, c1); INSERT INTO t0(c0) VALUES (x'bb'), (0); SELECT COUNT(*) FROM t0 WHERE INSTR(x'aabb', t0.c0) ORDER BY t0.c0, t0.c1; } {1} do_execsql_test instr-2.1 { SELECT quote(c0) FROM t0 WHERE INSTR(x'aabb', t0.c0) ORDER BY t0.c0, t0.c1; } {X'BB'} do_execsql_test instr-2.2 { DROP TABLE IF EXISTS t1; CREATE TABLE t1(x); INSERT INTO t1(x) VALUES('text'),(x'bb'); SELECT quote(x) FROM t1 WHERE instr(x'aabb',x); } {X'BB'} do_execsql_test instr-2.3 { SELECT quote(x) FROM t1 WHERE x>'zzz' AND instr(x'aabb',x); } {X'BB'} finish_test |
Changes to test/instrfault.test.
︙ | ︙ | |||
65 66 67 68 69 70 71 | faultsim_test_result {0 31} sqlite3_finalize $::stmt } do_faultsim_test 1.$enc.4 -faults oom-t* -prep { set ::stmt [sqlite3_prepare_v2 db "SELECT instr(?, ?)" -1 dummy] sqlite3_bind_blob $::stmt 1 $::HAYSTACK [string length $::HAYSTACK] | | | 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 | faultsim_test_result {0 31} sqlite3_finalize $::stmt } do_faultsim_test 1.$enc.4 -faults oom-t* -prep { set ::stmt [sqlite3_prepare_v2 db "SELECT instr(?, ?)" -1 dummy] sqlite3_bind_blob $::stmt 1 $::HAYSTACK [string length $::HAYSTACK] sqlite3_bind_blob $::stmt 2 $::NEEDLE [string length $::NEEDLE] } -body { set rc [sqlite3_step $::stmt] if {$rc=="SQLITE_NOMEM"} { error "out of memory" } sqlite3_column_int $::stmt 0 } -test { faultsim_test_result {0 31} sqlite3_finalize $::stmt |
︙ | ︙ |
Changes to test/intarray.test.
︙ | ︙ | |||
43 44 45 46 47 48 49 | set ia4 [sqlite3_intarray_create db ia4] db eval { SELECT type, name FROM temp.sqlite_master ORDER BY name } } {table ia1 table ia2 table ia3 table ia4} | | | | | | 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | set ia4 [sqlite3_intarray_create db ia4] db eval { SELECT type, name FROM temp.sqlite_master ORDER BY name } } {table ia1 table ia2 table ia3 table ia4} # Verify the ability to DROP and recreate an intarray virtual table. do_test intarray-1.1b { db eval {DROP TABLE ia1} set rc [catch {sqlite3_intarray_create db ia1} ia1] lappend rc $ia1 } {/0 [0-9A-Z]+/} do_test intarray-1.2 { db eval { SELECT b FROM t1 WHERE a IN ia3 ORDER BY a } } {} |
︙ | ︙ |
Changes to test/intpkey.test.
︙ | ︙ | |||
125 126 127 128 129 130 131 | } } {4 one two} do_test intpkey-1.12.2 { execsql { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a==4; } | | | 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 | } } {4 one two} do_test intpkey-1.12.2 { execsql { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a==4; } } {/SEARCH t1 /} # Try to insert a non-integer value into the primary key field. This # should result in a data type mismatch. # do_test intpkey-1.13.1 { set r [catch {execsql { INSERT INTO t1 VALUES('x','y','z'); |
︙ | ︙ |
Added test/intreal.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 | # 2019-05-03 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # Tests to exercise the MEM_IntReal representation of Mem objects. # set testdir [file dirname $argv0] source $testdir/tester.tcl set ::testprefix intreal sqlite3_create_function db do_execsql_test 100 { SELECT intreal(5); } {5.0} do_execsql_test 110 { SELECT intreal(5)=5, 6=intreal(6); } {1 1} do_execsql_test 120 { SELECT intreal(7)=7.0, 8.0=intreal(8); } {1 1} do_execsql_test 130 { SELECT typeof(intreal(9)); } {real} do_execsql_test 140 { SELECT 'a'||intreal(11)||'z'; } {a11.0z} do_execsql_test 150 { SELECT max(1.0,intreal(2),3.0), max(1,intreal(2),3); } {3.0 3} do_execsql_test 160 { SELECT max(1.0,intreal(4),3.0), max(1,intreal(4),3); } {4.0 4.0} do_execsql_test 170 { SELECT max(1.0,intreal(2),intreal(3),4.0), max(1,intreal(2),intreal(3),4); } {4.0 4} do_execsql_test 180 { SELECT max(1.0,intreal(5),intreal(3),4.0), max(1,intreal(5),intreal(3),4); } {5.0 5.0} #------------------------------------------------------------------------- do_execsql_test 2.1 { CREATE TABLE t2(a REAL); INSERT INTO t2 VALUES( 836627109860825358 ); SELECT substr(a,1,4) FROM t2 WHERE a = CAST(836627109860825358 AS REAL); } {8.36} do_execsql_test 2.2 { CREATE INDEX i2 ON t2(a); SELECT substr(a,1,4) FROM t2 WHERE a = CAST(836627109860825358 AS REAL); } {8.36} do_execsql_test 2.3 { CREATE TABLE t0 (c0); CREATE TABLE t1 (c1 REAL); INSERT INTO t1(c1) VALUES (8366271098608253588); INSERT INTO t0(c0) VALUES ('a'); } set D [db one {SELECT c1 FROM t1}] do_execsql_test 2.4 { SELECT * FROM t1 WHERE (t1.c1 = CAST(8366271098608253588 AS REAL)); } $D do_execsql_test 2.5 { SELECT * FROM t0, t1 WHERE (t1.c1 = CAST(8366271098608253588 AS REAL)); } [list a $D] do_execsql_test 2.6 { SELECT * FROM t0, t1 WHERE ( t1.c1 >= CAST(8366271098608253588 AS REAL) AND t1.c1 <= CAST(8366271098608253588 AS REAL) ); } [list a $D] # 2019-07-29 ticket ba2f4585cf495231 # db close sqlite3 db :memory: do_execsql_test 3.0 { CREATE TABLE t0 (c0 REAL, c1); CREATE UNIQUE INDEX i0 ON t0(c1, 0 | c0); INSERT INTO t0(c0) VALUES (4750228396194493326), (0); UPDATE OR REPLACE t0 SET c0 = 'a', c1 = ''; SELECT * FROM t0 ORDER BY t0.c1; PRAGMA integrity_check; } {a {} ok} finish_test |
Changes to test/io.test.
︙ | ︙ | |||
636 637 638 639 640 641 642 643 | # 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 | > > | 636 637 638 639 640 641 642 643 644 645 | # 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 unregister_devsim finish_test |
Changes to test/ioerr.test.
︙ | ︙ | |||
330 331 332 333 334 335 336 337 338 339 340 341 342 343 | db eval { CREATE TABLE t1(x) } db eval { INSERT INTO t1 VALUES(randomblob(1100)); } } -tclbody { db eval { INSERT INTO t1 VALUES(randomblob(2000)); } } sqlite3_simulate_device -char {} -sectorsize 0 catch {db close} do_ioerr_test ioerr-13 -ckrefcount true -erc 1 -sqlprep { PRAGMA auto_vacuum = incremental; CREATE TABLE t1(x); CREATE TABLE t2(x); INSERT INTO t2 VALUES(randomblob(1500)); INSERT INTO t2 SELECT randomblob(1500) FROM t2; | > | 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 | db eval { CREATE TABLE t1(x) } db eval { INSERT INTO t1 VALUES(randomblob(1100)); } } -tclbody { db eval { INSERT INTO t1 VALUES(randomblob(2000)); } } sqlite3_simulate_device -char {} -sectorsize 0 catch {db close} unregister_devsim do_ioerr_test ioerr-13 -ckrefcount true -erc 1 -sqlprep { PRAGMA auto_vacuum = incremental; CREATE TABLE t1(x); CREATE TABLE t2(x); INSERT INTO t2 VALUES(randomblob(1500)); INSERT INTO t2 SELECT randomblob(1500) FROM t2; |
︙ | ︙ |
Changes to test/istrue.test.
︙ | ︙ | |||
108 109 110 111 112 113 114 | e BOOLEAN CHECK(e IS NOT FALSE) ); INSERT INTO t2 VALUES(1,true,false,null,null); SELECT * FROM t2; } {1 1 0 {} {}} do_catchsql_test istrue-521 { INSERT INTO t2 VALUES(2,false,false,null,null); | | | | | | 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 | e BOOLEAN CHECK(e IS NOT FALSE) ); INSERT INTO t2 VALUES(1,true,false,null,null); SELECT * FROM t2; } {1 1 0 {} {}} do_catchsql_test istrue-521 { INSERT INTO t2 VALUES(2,false,false,null,null); } {1 {CHECK constraint failed: b IS TRUE}} do_catchsql_test istrue-522 { INSERT INTO t2 VALUES(2,true,true,null,null); } {1 {CHECK constraint failed: c IS FALSE}} do_catchsql_test istrue-523 { INSERT INTO t2 VALUES(2,true,false,true,null); } {1 {CHECK constraint failed: d IS NOT TRUE}} do_catchsql_test istrue-524 { INSERT INTO t2 VALUES(2,true,false,null,false); } {1 {CHECK constraint failed: e IS NOT FALSE}} foreach {tn val} [list 1 NaN 2 -NaN 3 NaN0 4 -NaN0 5 Inf 6 -Inf] { do_execsql_test istrue-600.$tn.1 { DROP TABLE IF EXISTS t1; CREATE TABLE t1(x); } do_test istrue-600.$tn.2 { |
︙ | ︙ | |||
139 140 141 142 143 144 145 | SELECT x IS TRUE FROM t1; } [expr {$tn in [list 5 6] ? {1} : {0}}] do_execsql_test istrue-600.$tn.4 { SELECT x IS FALSE FROM t1; } {0} } | > | | | | | | | | | | | | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | SELECT x IS TRUE FROM t1; } [expr {$tn in [list 5 6] ? {1} : {0}}] do_execsql_test istrue-600.$tn.4 { SELECT x IS FALSE FROM t1; } {0} } ifcapable altertable { do_execsql_test istrue-700 { CREATE TABLE t7( a INTEGER PRIMARY KEY, b BOOLEAN DEFAULT false, c BOOLEAN DEFAULT true ); INSERT INTO t7(a) VALUES(1); INSERT INTO t7(a,b,c) VALUES(2,true,false); ALTER TABLE t7 ADD COLUMN d BOOLEAN DEFAULT false; ALTER TABLE t7 ADD COLUMN e BOOLEAN DEFAULT true; INSERT INTO t7(a,b,c) VALUES(3,true,false); INSERT INTO t7 VALUES(4,false,true,true,false); SELECT *,'x' FROM t7 ORDER BY a; } {1 0 1 0 1 x 2 1 0 0 1 x 3 1 0 0 1 x 4 0 1 1 0 x} } do_execsql_test istrue-710 { SELECT 0.5 IS TRUE COLLATE NOCASE; SELECT 0.5 IS TRUE COLLATE RTRIM; SELECT 0.5 IS TRUE COLLATE BINARY; SELECT 0.5 IS TRUE; SELECT 0.5 COLLATE NOCASE IS TRUE; SELECT 0.0 IS FALSE; SELECT 0.0 IS FALSE COLLATE NOCASE; SELECT 0.0 IS FALSE COLLATE RTRIM; SELECT 0.0 IS FALSE COLLATE BINARY; } {1 1 1 1 1 1 1 1 1} # 2020-06-12 bug report from Chromium # https://bugs.chromium.org/p/chromium/issues/detail?id=1094247 do_catchsql_test istrue-800 { SELECT 9 IN (false.false); } {1 {no such column: false.false}} do_execsql_test istrue-810 { CREATE TABLE t8(a INT, true INT, false INT, d INT); INSERT INTO t8(a,true,false,d) VALUES(5,6,7,8),(4,3,2,1),('a','b','c','d'); SELECT * FROM t8 ORDER BY false; } {4 3 2 1 5 6 7 8 a b c d} do_catchsql_test istrue-820 { SELECT 9 IN (false.false) FROM t8; } {1 {no such column: false.false}} do_execsql_test istrue-830 { CREATE TABLE false(true INT, false INT, x INT CHECK (5 IN (false.false))); } {} do_execsql_test istrue-840 { INSERT INTO False VALUES(4,5,6); } {} do_catchsql_test istrue-841 { INSERT INTO False VALUES(5,6,7); } {1 {CHECK constraint failed: 5 IN (false.false)}} do_execsql_test istrue-850 { SELECT 9 IN (false.false) FROM false; } {0} do_execsql_test istrue-851 { SELECT 5 IN (false.false) FROM false; } {1} finish_test |
Changes to test/join.test.
︙ | ︙ | |||
667 668 669 670 671 672 673 | jointest join-12.2 30 {0 1} jointest join-12.3 63 {0 1} jointest join-12.4 64 {0 1} jointest join-12.5 65 {1 {at most 64 tables in a join}} jointest join-12.6 66 {1 {at most 64 tables in a join}} jointest join-12.7 127 {1 {at most 64 tables in a join}} jointest join-12.8 128 {1 {at most 64 tables in a join}} | > > > > > | | | | | | > | | | | | | < < > > | 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 | jointest join-12.2 30 {0 1} jointest join-12.3 63 {0 1} jointest join-12.4 64 {0 1} jointest join-12.5 65 {1 {at most 64 tables in a join}} jointest join-12.6 66 {1 {at most 64 tables in a join}} jointest join-12.7 127 {1 {at most 64 tables in a join}} jointest join-12.8 128 {1 {at most 64 tables in a join}} # As of 2019-01-17, the number of elements in a SrcList is limited # to 200. The following tests still run, but the answer is now # an SQLITE_NOMEM error. # # jointest join-12.9 1000 {1 {at most 64 tables in a join}} # # If SQLite is built with SQLITE_MEMDEBUG, then the huge number of realloc() # calls made by the following test cases are too time consuming to run. # Without SQLITE_MEMDEBUG, realloc() is fast enough that these are not # a problem. # # ifcapable pragma&&compileoption_diags { # if {[lsearch [db eval {PRAGMA compile_options}] MEMDEBUG]<0} { # jointest join-12.10 65534 {1 {at most 64 tables in a join}} # jointest join-12.11 65535 {1 {too many references to "t14": max 65535}} # jointest join-12.12 65536 {1 {too many references to "t14": max 65535}} # jointest join-12.13 65537 {1 {too many references to "t14": max 65535}} # } # } #------------------------------------------------------------------------- # Test a problem with reordering tables following a LEFT JOIN. # do_execsql_test join-13.0 { CREATE TABLE aa(a); |
︙ | ︙ | |||
802 803 804 805 806 807 808 | WHERE CASE WHEN FALSE THEN a=x ELSE 1 END; } {1 2 {} {} x 3 4 {} {} x} do_execsql_test join-15.105 { SELECT *, 'x' FROM t1 LEFT JOIN t2 WHERE a IN (1,3,x,y); } {1 2 {} {} x 3 4 {} {} x} | | > > > > > | 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 | WHERE CASE WHEN FALSE THEN a=x ELSE 1 END; } {1 2 {} {} x 3 4 {} {} x} do_execsql_test join-15.105 { SELECT *, 'x' FROM t1 LEFT JOIN t2 WHERE a IN (1,3,x,y); } {1 2 {} {} x 3 4 {} {} x} do_execsql_test join-15.106a { SELECT *, 'x' FROM t1 LEFT JOIN t2 WHERE NOT ( 'x'='y' AND t2.y=1 ); } {1 2 {} {} x 3 4 {} {} x} do_execsql_test join-15.106b { SELECT *, 'x' FROM t1 LEFT JOIN t2 WHERE ~ ( 'x'='y' AND t2.y=1 ); } {1 2 {} {} x 3 4 {} {} x} do_execsql_test join-15.107 { SELECT *, 'x' FROM t1 LEFT JOIN t2 WHERE t2.y IS NOT 'abc' } {1 2 {} {} x 3 4 {} {} x} do_execsql_test join-15.110 { DROP TABLE t1; |
︙ | ︙ | |||
839 840 841 842 843 844 845 846 847 | ON x3 IS TRUE AND b4=a3 JOIN (SELECT x AS x4 FROM t2) ON x4<=CASE WHEN x3 THEN CASE WHEN a4 THEN 1 ELSE -1 END ELSE 0 END LEFT JOIN (SELECT a AS a5, b AS b5 FROM t1) ON x4 IS TRUE AND b5=a4 ORDER BY a1, a2, a3, a4, a5; } {1 {} {} {} {} 1 11 {} {} {} 1 12 {} {} {} 1 12 121 {} {} 1 13 {} {} {}} finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | ON x3 IS TRUE AND b4=a3 JOIN (SELECT x AS x4 FROM t2) ON x4<=CASE WHEN x3 THEN CASE WHEN a4 THEN 1 ELSE -1 END ELSE 0 END LEFT JOIN (SELECT a AS a5, b AS b5 FROM t1) ON x4 IS TRUE AND b5=a4 ORDER BY a1, a2, a3, a4, a5; } {1 {} {} {} {} 1 11 {} {} {} 1 12 {} {} {} 1 12 121 {} {} 1 13 {} {} {}} # 2019-02-05 Ticket https://www.sqlite.org/src/tktview/5948e09b8c415bc45da5c # Error in join due to the LEFT JOIN strength reduction optimization. # do_execsql_test join-16.100 { DROP TABLE IF EXISTS t1; DROP TABLE IF EXISTS t2; CREATE TABLE t1(a INT); INSERT INTO t1(a) VALUES(1); CREATE TABLE t2(b INT); SELECT a, b FROM t1 LEFT JOIN t2 ON 0 WHERE (b IS NOT NULL)=0; } {1 {}} # 2019-08-17 ticket https://sqlite.org/src/tktview/6710d2f7a13a299728ab # Ensure that constants that derive from the right-hand table of a LEFT JOIN # are never factored out, since they are not really constant. # do_execsql_test join-17.100 { DROP TABLE IF EXISTS t1; CREATE TABLE t1(x); INSERT INTO t1(x) VALUES(0),(1); SELECT * FROM t1 LEFT JOIN (SELECT abs(1) AS y FROM t1) ON x WHERE NOT(y='a'); } {1 1 1 1} do_execsql_test join-17.110 { SELECT * FROM t1 LEFT JOIN (SELECT abs(1)+2 AS y FROM t1) ON x WHERE NOT(y='a'); } {1 3 1 3} #------------------------------------------------------------------------- reset_db do_execsql_test join-18.1 { CREATE TABLE t0(a); CREATE TABLE t1(b); CREATE VIEW v0 AS SELECT a FROM t1 LEFT JOIN t0; INSERT INTO t1 VALUES (1); } {} do_execsql_test join-18.2 { SELECT * FROM v0 WHERE NOT(v0.a IS FALSE); } {{}} do_execsql_test join-18.3 { SELECT * FROM t1 LEFT JOIN t0 WHERE NOT(a IS FALSE); } {1 {}} do_execsql_test join-18.4 { SELECT NOT(v0.a IS FALSE) FROM v0 } {1} #------------------------------------------------------------------------- reset_db do_execsql_test join-19.0 { CREATE TABLE t1(a); CREATE TABLE t2(b); INSERT INTO t1(a) VALUES(0); CREATE VIEW v0(c) AS SELECT t2.b FROM t1 LEFT JOIN t2; } do_execsql_test join-19.1 { SELECT * FROM v0 WHERE v0.c NOTNULL NOTNULL; } {{}} do_execsql_test join-19.2 { SELECT * FROM t1 LEFT JOIN t2 } {0 {}} do_execsql_test join-19.3 { SELECT * FROM t1 LEFT JOIN t2 WHERE (b IS NOT NULL) IS NOT NULL; } {0 {}} do_execsql_test join-19.4 { SELECT (b IS NOT NULL) IS NOT NULL FROM t1 LEFT JOIN t2 } {1} do_execsql_test join-19.5 { SELECT * FROM t1 LEFT JOIN t2 WHERE (b IS NOT NULL AND b IS NOT NULL) IS NOT NULL; } {0 {}} # 2019-11-02 ticket 623eff57e76d45f6 # The optimization of exclusing the WHERE expression of a partial index # from the WHERE clause of the query if the index is used does not work # of the table of the index is the right-hand table of a LEFT JOIN. # db close sqlite3 db :memory: do_execsql_test join-20.1 { CREATE TABLE t1(c1); CREATE TABLE t0(c0); INSERT INTO t0(c0) VALUES (0); SELECT * FROM t0 LEFT JOIN t1 WHERE NULL IN (c1); } {} do_execsql_test join-20.2 { CREATE INDEX t1x ON t1(0) WHERE NULL IN (c1); SELECT * FROM t0 LEFT JOIN t1 WHERE NULL IN (c1); } {} # 2019-11-30 ticket 7f39060a24b47353 # Do not allow a WHERE clause term to qualify a partial index on the # right table of a LEFT JOIN. # do_execsql_test join-21.10 { DROP TABLE t0; DROP TABLE t1; CREATE TABLE t0(aa); CREATE TABLE t1(bb); INSERT INTO t0(aa) VALUES (1); INSERT INTO t1(bb) VALUES (1); SELECT 11, * FROM t1 LEFT JOIN t0 WHERE aa ISNULL; SELECT 12, * FROM t1 LEFT JOIN t0 WHERE +aa ISNULL; SELECT 13, * FROM t1 LEFT JOIN t0 ON aa ISNULL; SELECT 14, * FROM t1 LEFT JOIN t0 ON +aa ISNULL; CREATE INDEX i0 ON t0(aa) WHERE aa ISNULL; SELECT 21, * FROM t1 LEFT JOIN t0 WHERE aa ISNULL; SELECT 22, * FROM t1 LEFT JOIN t0 WHERE +aa ISNULL; SELECT 23, * FROM t1 LEFT JOIN t0 ON aa ISNULL; SELECT 24, * FROM t1 LEFT JOIN t0 ON +aa ISNULL; } {13 1 {} 14 1 {} 23 1 {} 24 1 {}} # 2019-12-18 problem with a LEFT JOIN where the RHS is a view. # Detected by Yongheng and Rui. # Follows from the optimization attempt of check-in 41c27bc0ff1d3135 # on 2017-04-18 # reset_db do_execsql_test join-22.10 { CREATE TABLE t0(a, b); CREATE INDEX t0a ON t0(a); INSERT INTO t0 VALUES(10,10),(10,11),(10,12); SELECT DISTINCT c FROM t0 LEFT JOIN (SELECT a+1 AS c FROM t0) ORDER BY c ; } {11} # 2019-12-22 ticket 7929c1efb2d67e98 # reset_db ifcapable vtab { do_execsql_test join-23.10 { CREATE TABLE t0(c0); INSERT INTO t0(c0) VALUES(123); CREATE VIEW v0(c0) AS SELECT 0 GROUP BY 1; SELECT t0.c0, v0.c0, vt0.name FROM v0, t0 LEFT JOIN pragma_table_info('t0') AS vt0 ON vt0.name LIKE 'c0' WHERE v0.c0 == 0; } {123 0 c0} } #------------------------------------------------------------------------- reset_db do_execsql_test join-24.1 { CREATE TABLE t1(a PRIMARY KEY, x); CREATE TABLE t2(b INT); CREATE INDEX t1aa ON t1(a, a); INSERT INTO t1 VALUES('abc', 'def'); INSERT INTO t2 VALUES(1); } do_execsql_test join-24.2 { SELECT * FROM t2 JOIN t1 WHERE a='abc' AND x='def'; } {1 abc def} do_execsql_test join-24.3 { SELECT * FROM t2 JOIN t1 WHERE a='abc' AND x='abc'; } {} do_execsql_test join-24.2 { SELECT * FROM t2 LEFT JOIN t1 ON a=0 WHERE (x='x' OR x IS NULL); } {1 {} {}} # 2020-09-30 ticket 66e4b0e271c47145 # The query flattener inserts an "expr AND expr" expression as a substitution # for the column of a view where that view column is part of an ON expression # of a LEFT JOIN. # reset_db do_execsql_test join-25.1 { CREATE TABLE t0(c0 INT); CREATE VIEW v0 AS SELECT (NULL AND 5) as c0 FROM t0; INSERT INTO t0(c0) VALUES (NULL); SELECT count(*) FROM v0 LEFT JOIN t0 ON v0.c0; } {1} finish_test |
Changes to test/join2.test.
︙ | ︙ | |||
109 110 111 112 113 114 115 | CREATE TABLE t3_2(v3, k3 PRIMARY KEY) WITHOUT ROWID; } do_eqp_test 3.1 { SELECT v2 FROM t1 LEFT JOIN t2 USING (k2) LEFT JOIN t3_1 USING (k3); } { QUERY PLAN | | | | | | 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 | CREATE TABLE t3_2(v3, k3 PRIMARY KEY) WITHOUT ROWID; } do_eqp_test 3.1 { SELECT v2 FROM t1 LEFT JOIN t2 USING (k2) LEFT JOIN t3_1 USING (k3); } { QUERY PLAN |--SCAN t1 `--SEARCH t2 USING INTEGER PRIMARY KEY (rowid=?) } do_eqp_test 3.2 { SELECT v2 FROM t1 LEFT JOIN t2 USING (k2) LEFT JOIN t3_2 USING (k3); } { QUERY PLAN |--SCAN t1 `--SEARCH t2 USING INTEGER PRIMARY KEY (rowid=?) } #------------------------------------------------------------------------- # Test that tables other than the rightmost can be omitted from a # LEFT JOIN query. # do_execsql_test 4.0 { |
︙ | ︙ | |||
157 158 159 160 161 162 163 | SELECT v1, v3 FROM c1 LEFT JOIN c2 LEFT JOIN c3 ON (c3.k=v1+1); } {2 v3 2 v3 1112 {} 1112 {}} do_eqp_test 4.1.5 { SELECT v1, v3 FROM c1 LEFT JOIN c2 ON (c2.k=v1) LEFT JOIN c3 ON (c3.k=v2); } { QUERY PLAN | | | | | | | 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 | SELECT v1, v3 FROM c1 LEFT JOIN c2 LEFT JOIN c3 ON (c3.k=v1+1); } {2 v3 2 v3 1112 {} 1112 {}} do_eqp_test 4.1.5 { SELECT v1, v3 FROM c1 LEFT JOIN c2 ON (c2.k=v1) LEFT JOIN c3 ON (c3.k=v2); } { QUERY PLAN |--SCAN c1 |--SEARCH c2 USING INTEGER PRIMARY KEY (rowid=?) `--SEARCH c3 USING INTEGER PRIMARY KEY (rowid=?) } do_eqp_test 4.1.6 { SELECT v1, v3 FROM c1 LEFT JOIN c2 ON (c2.k=v1) LEFT JOIN c3 ON (c3.k=v1+1); } { QUERY PLAN |--SCAN c1 `--SEARCH c3 USING INTEGER PRIMARY KEY (rowid=?) } do_execsql_test 4.2.0 { DROP TABLE c1; DROP TABLE c2; DROP TABLE c3; CREATE TABLE c1(k UNIQUE, v1); |
︙ | ︙ | |||
204 205 206 207 208 209 210 | SELECT v1, v3 FROM c1 LEFT JOIN c2 LEFT JOIN c3 ON (c3.k=v1+1); } {2 v3 2 v3 1112 {} 1112 {}} do_eqp_test 4.2.5 { SELECT v1, v3 FROM c1 LEFT JOIN c2 ON (c2.k=v1) LEFT JOIN c3 ON (c3.k=v2); } { QUERY PLAN | | | | | | | 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 | SELECT v1, v3 FROM c1 LEFT JOIN c2 LEFT JOIN c3 ON (c3.k=v1+1); } {2 v3 2 v3 1112 {} 1112 {}} do_eqp_test 4.2.5 { SELECT v1, v3 FROM c1 LEFT JOIN c2 ON (c2.k=v1) LEFT JOIN c3 ON (c3.k=v2); } { QUERY PLAN |--SCAN c1 |--SEARCH c2 USING INDEX sqlite_autoindex_c2_1 (k=?) `--SEARCH c3 USING INDEX sqlite_autoindex_c3_1 (k=?) } do_eqp_test 4.2.6 { SELECT v1, v3 FROM c1 LEFT JOIN c2 ON (c2.k=v1) LEFT JOIN c3 ON (c3.k=v1+1); } { QUERY PLAN |--SCAN c1 `--SEARCH c3 USING INDEX sqlite_autoindex_c3_1 (k=?) } # 2017-11-23 (Thanksgiving day) # OSSFuzz found an assertion fault in the new LEFT JOIN eliminator code. # do_execsql_test 4.3.0 { DROP TABLE IF EXISTS t1; |
︙ | ︙ | |||
247 248 249 250 251 252 253 | CREATE TABLE s1 (a INTEGER PRIMARY KEY); CREATE TABLE s2 (a INTEGER PRIMARY KEY); CREATE TABLE s3 (a INTEGER); CREATE UNIQUE INDEX ndx on s3(a); } do_eqp_test 5.1 { SELECT s1.a FROM s1 left join s2 using (a); | | | | > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | CREATE TABLE s1 (a INTEGER PRIMARY KEY); CREATE TABLE s2 (a INTEGER PRIMARY KEY); CREATE TABLE s3 (a INTEGER); CREATE UNIQUE INDEX ndx on s3(a); } do_eqp_test 5.1 { SELECT s1.a FROM s1 left join s2 using (a); } {SCAN s1} do_eqp_test 5.2 { SELECT s1.a FROM s1 left join s3 using (a); } {SCAN s1} do_execsql_test 6.0 { CREATE TABLE u1(a INTEGER PRIMARY KEY, b, c); CREATE TABLE u2(a INTEGER PRIMARY KEY, b, c); CREATE INDEX u1ab ON u1(b, c); } do_eqp_test 6.1 { SELECT u2.* FROM u2 LEFT JOIN u1 ON( u1.a=u2.a AND u1.b=u2.b AND u1.c=u2.c ); } {SCAN u2} db close sqlite3 db :memory: do_execsql_test 7.0 { CREATE TABLE t1(a,b); INSERT INTO t1 VALUES(1,2),(3,4),(5,6); CREATE TABLE t2(c,d); INSERT INTO t2 VALUES(2,4),(3,6); CREATE TABLE t3(x); INSERT INTO t3 VALUES(9); CREATE VIEW test AS SELECT *, 'x' FROM t1 LEFT JOIN (SELECT * FROM t2, t3) ON (c=b AND x=9) WHERE c IS NULL; SELECT * FROM test; } {3 4 {} {} {} x 5 6 {} {} {} x} #------------------------------------------------------------------------- # Ticket [dfd66334]. # reset_db do_execsql_test 8.0 { CREATE TABLE t0(c0); CREATE TABLE t1(c0); } do_execsql_test 8.1 { SELECT * FROM t0 LEFT JOIN t1 WHERE (t1.c0 BETWEEN 0 AND 0) > ('' AND t0.c0); } #------------------------------------------------------------------------- # Ticket [45f4bf4eb] reported by Manuel Rigger (2020-04-25) # # Follow up error reported by Eric Speckman on the SQLite forum # https://sqlite.org/forum/info/c49496d24d35bd7c (2020-08-19) # reset_db do_execsql_test 9.0 { CREATE TABLE t0(c0 INT); CREATE VIEW v0(c0) AS SELECT CAST(t0.c0 AS INTEGER) FROM t0; INSERT INTO t0(c0) VALUES (0); } do_execsql_test 9.1 { SELECT typeof(c0), c0 FROM v0 WHERE c0>='0' } {integer 0} do_execsql_test 9.2 { SELECT * FROM t0, v0 WHERE v0.c0 >= '0'; } {0 0} do_execsql_test 9.3 { SELECT * FROM t0 LEFT JOIN v0 WHERE v0.c0 >= '0'; } {0 0} do_execsql_test 9.4 { SELECT * FROM t0 LEFT JOIN v0 ON v0.c0 >= '0'; } {0 0} do_execsql_test 9.5 { SELECT * FROM t0 LEFT JOIN v0 ON v0.c0 >= '0' WHERE TRUE UNION SELECT 0,0 WHERE 0; } {0 0} do_execsql_test 9.10 { CREATE TABLE t1 (aaa); INSERT INTO t1 VALUES(23456); CREATE TABLE t2(bbb); CREATE VIEW v2(ccc) AS SELECT bbb IS 1234 FROM t2; SELECT ccc, ccc IS NULL AS ddd FROM t1 LEFT JOIN v2; } {{} 1} optimization_control db query-flattener 0 do_execsql_test 9.11 { SELECT ccc, ccc IS NULL AS ddd FROM t1 LEFT JOIN v2; } {{} 1} finish_test |
Changes to test/join5.test.
︙ | ︙ | |||
236 237 238 239 240 241 242 243 244 245 246 247 248 249 | SELECT ifnull(z, '!!!') FROM t3 LEFT JOIN t4 ON (x=y); } {!!!} do_execsql_test 6.3.2 { CREATE INDEX t4i ON t4(y, ifnull(z, '!!!')); SELECT ifnull(z, '!!!') FROM t3 LEFT JOIN t4 ON (x=y); } {!!!} #------------------------------------------------------------------------- # reset_db do_execsql_test 7.0 { CREATE TABLE t1(x); INSERT INTO t1 VALUES(1); | > > > > > > > > > > > > | 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 | SELECT ifnull(z, '!!!') FROM t3 LEFT JOIN t4 ON (x=y); } {!!!} do_execsql_test 6.3.2 { CREATE INDEX t4i ON t4(y, ifnull(z, '!!!')); SELECT ifnull(z, '!!!') FROM t3 LEFT JOIN t4 ON (x=y); } {!!!} # 2019-02-08 https://sqlite.org/src/info/4e8e4857d32d401f reset_db do_execsql_test 6.100 { CREATE TABLE t1(aa, bb); CREATE INDEX t1x1 on t1(abs(aa), abs(bb)); INSERT INTO t1 VALUES(-2,-3),(+2,-3),(-2,+3),(+2,+3); SELECT * FROM (t1) WHERE ((abs(aa)=1 AND 1=2) OR abs(aa)=2) AND abs(bb)=3 ORDER BY +1, +2; } {-2 -3 -2 3 2 -3 2 3} #------------------------------------------------------------------------- # reset_db do_execsql_test 7.0 { CREATE TABLE t1(x); INSERT INTO t1 VALUES(1); |
︙ | ︙ | |||
261 262 263 264 265 266 267 | do_eqp_test 7.2 { SELECT * FROM t1 LEFT JOIN t2 ON ( t2.x = t1.x AND (t2.y=? OR (t2.y=? AND t2.z IS NOT NULL)) ); } { QUERY PLAN | | > | > | | | > > > > > > > > > > > > > > > > > > > > > | 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 | do_eqp_test 7.2 { SELECT * FROM t1 LEFT JOIN t2 ON ( t2.x = t1.x AND (t2.y=? OR (t2.y=? AND t2.z IS NOT NULL)) ); } { QUERY PLAN |--SCAN t1 `--MULTI-INDEX OR |--INDEX 1 | `--SEARCH t2 USING INDEX t2xy (x=? AND y=?) `--INDEX 2 `--SEARCH t2 USING INDEX t2xy (x=? AND y=?) } do_execsql_test 7.3 { CREATE TABLE t3(x); CREATE TABLE t4(x, y, z); CREATE INDEX t4xy ON t4(x, y); CREATE INDEX t4xz ON t4(x, z); WITH s(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<50000) INSERT INTO t4 SELECT i/10, i, i FROM s; ANALYZE; } do_eqp_test 7.4 { SELECT * FROM t3 LEFT JOIN t4 ON (t4.x = t3.x) WHERE (t4.y = ? OR t4.z = ?); } { QUERY PLAN |--SCAN t3 `--SEARCH t4 USING INDEX t4xz (x=?) } reset_db do_execsql_test 8.0 { CREATE TABLE t0 (c0, c1, PRIMARY KEY (c0, c1)); CREATE TABLE t1 (c0); INSERT INTO t1 VALUES (2); INSERT INTO t0 VALUES(0, 10); INSERT INTO t0 VALUES(1, 10); INSERT INTO t0 VALUES(2, 10); INSERT INTO t0 VALUES(3, 10); } do_execsql_test 8.1 { SELECT * FROM t0, t1 WHERE (t0.c1 >= 1 OR t0.c1 < 1) AND t0.c0 IN (1, t1.c0) ORDER BY 1; } { 1 10 2 2 10 2 } finish_test |
Changes to test/join6.test.
︙ | ︙ | |||
143 144 145 146 147 148 149 150 151 152 153 154 155 156 | execsql { SELECT * FROM t1 NATURAL JOIN t2 NATURAL JOIN (SELECT 5 AS c, 91 AS x, 93 AS z UNION SELECT 6, 99, 95) } } {1 91 92 3 93 5} } | > > > > > > > > > > > > > > > > | 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 | execsql { SELECT * FROM t1 NATURAL JOIN t2 NATURAL JOIN (SELECT 5 AS c, 91 AS x, 93 AS z UNION SELECT 6, 99, 95) } } {1 91 92 3 93 5} } do_execsql_test join6-5.1 { CREATE TABLE tx(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o PRIMARY KEY) WITHOUT ROWID; INSERT INTO tx VALUES( 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 ); } {} do_execsql_test joint6-5.2 { SELECT o FROM tx NATURAL JOIN tx; } {15} do_execsql_test join6-5.3 { CREATE TABLE ty(a,Ñ,x6,x7,x8,Q,I,v,x1,L,E,x2,x3,x4,x5,s,g PRIMARY KEY,b,c) WITHOUT ROWID; SELECT a FROM ty NATURAL JOIN ty; } |
︙ | ︙ |
Changes to test/journal3.test.
︙ | ︙ | |||
34 35 36 37 38 39 40 41 42 43 44 45 | 1 00644 2 00666 3 00600 4 00755 } { db close #set effective [format %.5o [expr $permissions & ~$umask]] set effective $permissions do_test journal3-1.2.$tn.1 { catch { forcedelete test.db-journal } file attributes test.db -permissions $permissions file attributes test.db -permissions | > > > > | | | 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 | 1 00644 2 00666 3 00600 4 00755 } { db close #set effective [format %.5o [expr $permissions & ~$umask]] set res "/[regsub {^00} $permissions {0.}]/" if {$tcl_version>=8.7} { regsub {^00} $permissions {0o} permissions } set effective $permissions do_test journal3-1.2.$tn.1 { catch { forcedelete test.db-journal } file attributes test.db -permissions $permissions file attributes test.db -permissions } $res do_test journal3-1.2.$tn.2 { file exists test.db-journal } {0} do_test journal3-1.2.$tn.3 { sqlite3 db test.db execsql { BEGIN; INSERT INTO tx DEFAULT VALUES; } file exists test.db-journal } {1} do_test journal3-1.2.$tn.4 { file attr test.db-journal -perm } $res do_execsql_test journal3-1.2.$tn.5 { ROLLBACK } {} } } finish_test |
Changes to test/jrnlmode.test.
︙ | ︙ | |||
61 62 63 64 65 66 67 | do_test jrnlmode-1.2 { execsql { PRAGMA journal_mode; PRAGMA main.journal_mode; PRAGMA temp.journal_mode; } } [list persist persist [temp_journal_mode persist]] | | > > > > > > > > > | 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 | do_test jrnlmode-1.2 { execsql { PRAGMA journal_mode; PRAGMA main.journal_mode; PRAGMA temp.journal_mode; } } [list persist persist [temp_journal_mode persist]] do_test jrnlmode-1.4a { # When defensive is on, unable to set journal_mode to OFF sqlite3_db_config db DEFENSIVE 1 execsql { PRAGMA journal_mode = off; } } {persist} do_test jrnlmode-1.4b { # When defensive is on, unable to set journal_mode to OFF sqlite3_db_config db DEFENSIVE 0 execsql { PRAGMA journal_mode = off; } } {off} do_test jrnlmode-1.5 { execsql { PRAGMA journal_mode; |
︙ | ︙ |
Changes to test/json101.test.
︙ | ︙ | |||
827 828 829 830 831 832 833 834 835 | } {a 1 integer 1 2 {} {$.a} {$} b 2 integer 2 4 {} {$.b} {$}} do_execsql_test json-15.120 { SELECT * FROM (JSON_EACH('{"a":1, "b":2}')); } {a 1 integer 1 2 {} {$.a} {$} b 2 integer 2 4 {} {$.b} {$}} do_execsql_test json-15.130 { SELECT xyz.* FROM (JSON_EACH('{"a":1, "b":2}')) AS xyz; } {a 1 integer 1 2 {} {$.a} {$} b 2 integer 2 4 {} {$.b} {$}} finish_test | > > > > > > > > > > > > > > > | 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 | } {a 1 integer 1 2 {} {$.a} {$} b 2 integer 2 4 {} {$.b} {$}} do_execsql_test json-15.120 { SELECT * FROM (JSON_EACH('{"a":1, "b":2}')); } {a 1 integer 1 2 {} {$.a} {$} b 2 integer 2 4 {} {$.b} {$}} do_execsql_test json-15.130 { SELECT xyz.* FROM (JSON_EACH('{"a":1, "b":2}')) AS xyz; } {a 1 integer 1 2 {} {$.a} {$} b 2 integer 2 4 {} {$.b} {$}} # 2019-11-10 # Mailing list bug report on the handling of surrogate pairs # in JSON. # do_execsql_test json-16.10 { SELECT length(json_extract('"abc\uD834\uDD1Exyz"','$')); } {7} do_execsql_test json-16.20 { SELECT length(json_extract('"\uD834\uDD1E"','$')); } {1} do_execsql_test json-16.30 { SELECT unicode(json_extract('"\uD834\uDD1E"','$')); } {119070} finish_test |
Changes to test/json104.test.
︙ | ︙ | |||
9 10 11 12 13 14 15 16 17 18 19 20 21 22 | # #*********************************************************************** # This file implements tests for json_patch(A,B) SQL function. # set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable !json1 { finish_test return } # This is the example from pages 2 and 3 of RFC-7396 | > | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | # #*********************************************************************** # This file implements tests for json_patch(A,B) SQL function. # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix json104 ifcapable !json1 { finish_test return } # This is the example from pages 2 and 3 of RFC-7396 |
︙ | ︙ | |||
120 121 122 123 124 125 126 127 128 129 130 | } {{{"e":null,"a":1}}} do_execsql_test json104-313 { SELECT json_patch('[1,2]','{"a":"b","c":null}'); } {{{"a":"b"}}} do_execsql_test json104-314 { SELECT json_patch('{}','{"a":{"bb":{"ccc":null}}}'); } {{{"a":{"bb":{}}}}} finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | } {{{"e":null,"a":1}}} do_execsql_test json104-313 { SELECT json_patch('[1,2]','{"a":"b","c":null}'); } {{{"a":"b"}}} do_execsql_test json104-314 { SELECT json_patch('{}','{"a":{"bb":{"ccc":null}}}'); } {{{"a":{"bb":{}}}}} do_execsql_test json104-320 { SELECT json_patch('{"x":{"one":1}}','{"x":{"two":2},"x":"three"}'); } {{{"x":"three"}}} #------------------------------------------------------------------------- do_execsql_test 401 { CREATE TABLE obj(x); INSERT INTO obj VALUES('{"a":1,"b":2}'); SELECT * FROM obj; } {{{"a":1,"b":2}}} do_execsql_test 402 { UPDATE obj SET x = json_insert(x, '$.c', 3); SELECT * FROM obj; } {{{"a":1,"b":2,"c":3}}} do_execsql_test 403 { SELECT json_extract(x, '$.b') FROM obj; SELECT json_extract(x, '$."b"') FROM obj; } {2 2} do_execsql_test 404 { UPDATE obj SET x = json_set(x, '$."b"', 555); SELECT json_extract(x, '$.b') FROM obj; SELECT json_extract(x, '$."b"') FROM obj; } {555 555} do_execsql_test 405 { UPDATE obj SET x = json_set(x, '$."d"', 4); SELECT json_extract(x, '$."d"') FROM obj; } {4} finish_test |
Added test/json105.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 | # 2019-11-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 tests for "[#]" extension to json-path # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix json104 ifcapable !json1 { finish_test return } # This is the example from pages 2 and 3 of RFC-7396 db eval { CREATE TABLE t1(j); INSERT INTO t1(j) VALUES('{"a":1,"b":[1,[2,3],4],"c":99}'); } proc json_extract_test {testnum path result} { do_execsql_test json105-1.$testnum "SELECT quote(json_extract(j,$path)) FROM t1" $result } json_extract_test 10 {'$.b[#]'} NULL json_extract_test 20 {'$.b[#-1]'} 4 json_extract_test 30 {'$.b[#-2]'} {'[2,3]'} json_extract_test 31 {'$.b[#-02]'} {'[2,3]'} json_extract_test 40 {'$.b[#-3]'} 1 json_extract_test 50 {'$.b[#-4]'} NULL json_extract_test 60 {'$.b[#-2][#-1]'} 3 json_extract_test 70 {'$.b[0]','$.b[#-1]'} {'[1,4]'} json_extract_test 100 {'$.a[#-1]'} NULL json_extract_test 110 {'$.b[#-000001]'} 4 proc json_remove_test {testnum path result} { do_execsql_test json105-2.$testnum "SELECT quote(json_remove(j,$path)) FROM t1" $result } json_remove_test 10 {'$.b[#]'} {'{"a":1,"b":[1,[2,3],4],"c":99}'} json_remove_test 20 {'$.b[#-0]'} {'{"a":1,"b":[1,[2,3],4],"c":99}'} json_remove_test 30 {'$.b[#-1]'} {'{"a":1,"b":[1,[2,3]],"c":99}'} json_remove_test 40 {'$.b[#-2]'} {'{"a":1,"b":[1,4],"c":99}'} json_remove_test 50 {'$.b[#-3]'} {'{"a":1,"b":[[2,3],4],"c":99}'} json_remove_test 60 {'$.b[#-4]'} {'{"a":1,"b":[1,[2,3],4],"c":99}'} json_remove_test 70 {'$.b[#-2][#-1]'} {'{"a":1,"b":[1,[2],4],"c":99}'} json_remove_test 100 {'$.b[0]','$.b[#-1]'} {'{"a":1,"b":[[2,3]],"c":99}'} json_remove_test 110 {'$.b[#-1]','$.b[0]'} {'{"a":1,"b":[[2,3]],"c":99}'} json_remove_test 120 {'$.b[#-1]','$.b[#-2]'} {'{"a":1,"b":[[2,3]],"c":99}'} json_remove_test 130 {'$.b[#-1]','$.b[#-1]'} {'{"a":1,"b":[1],"c":99}'} json_remove_test 140 {'$.b[#-2]','$.b[#-1]'} {'{"a":1,"b":[1],"c":99}'} proc json_insert_test {testnum x result} { do_execsql_test json105-3.$testnum "SELECT quote(json_insert(j,$x)) FROM t1" $result } json_insert_test 10 {'$.b[#]','AAA'} {'{"a":1,"b":[1,[2,3],4,"AAA"],"c":99}'} json_insert_test 20 {'$.b[1][#]','AAA'} {'{"a":1,"b":[1,[2,3,"AAA"],4],"c":99}'} json_insert_test 30 {'$.b[1][#]','AAA','$.b[#]','BBB'} \ {'{"a":1,"b":[1,[2,3,"AAA"],4,"BBB"],"c":99}'} json_insert_test 40 {'$.b[#]','AAA','$.b[#]','BBB'} \ {'{"a":1,"b":[1,[2,3],4,"AAA","BBB"],"c":99}'} proc json_set_test {testnum x result} { do_execsql_test json105-4.$testnum "SELECT quote(json_set(j,$x)) FROM t1" $result } json_set_test 10 {'$.b[#]','AAA'} {'{"a":1,"b":[1,[2,3],4,"AAA"],"c":99}'} json_set_test 20 {'$.b[1][#]','AAA'} {'{"a":1,"b":[1,[2,3,"AAA"],4],"c":99}'} json_set_test 30 {'$.b[1][#]','AAA','$.b[#]','BBB'} \ {'{"a":1,"b":[1,[2,3,"AAA"],4,"BBB"],"c":99}'} json_set_test 40 {'$.b[#]','AAA','$.b[#]','BBB'} \ {'{"a":1,"b":[1,[2,3],4,"AAA","BBB"],"c":99}'} json_set_test 50 {'$.b[#-1]','AAA'} {'{"a":1,"b":[1,[2,3],"AAA"],"c":99}'} json_set_test 60 {'$.b[1][#-1]','AAA'} {'{"a":1,"b":[1,[2,"AAA"],4],"c":99}'} json_set_test 70 {'$.b[1][#-1]','AAA','$.b[#-1]','BBB'} \ {'{"a":1,"b":[1,[2,"AAA"],"BBB"],"c":99}'} json_set_test 80 {'$.b[#-1]','AAA','$.b[#-1]','BBB'} \ {'{"a":1,"b":[1,[2,3],"BBB"],"c":99}'} proc json_replace_test {testnum x result} { do_execsql_test json105-5.$testnum "SELECT quote(json_replace(j,$x)) FROM t1" $result } json_replace_test 10 {'$.b[#]','AAA'} {'{"a":1,"b":[1,[2,3],4],"c":99}'} json_replace_test 20 {'$.b[1][#]','AAA'} {'{"a":1,"b":[1,[2,3],4],"c":99}'} json_replace_test 30 {'$.b[1][#]','AAA','$.b[#]','BBB'} \ {'{"a":1,"b":[1,[2,3],4],"c":99}'} json_replace_test 40 {'$.b[#]','AAA','$.b[#]','BBB'} \ {'{"a":1,"b":[1,[2,3],4],"c":99}'} json_replace_test 50 {'$.b[#-1]','AAA'} {'{"a":1,"b":[1,[2,3],"AAA"],"c":99}'} json_replace_test 60 {'$.b[1][#-1]','AAA'} {'{"a":1,"b":[1,[2,"AAA"],4],"c":99}'} json_replace_test 70 {'$.b[1][#-1]','AAA','$.b[#-1]','BBB'} \ {'{"a":1,"b":[1,[2,"AAA"],"BBB"],"c":99}'} json_replace_test 80 {'$.b[#-1]','AAA','$.b[#-1]','BBB'} \ {'{"a":1,"b":[1,[2,3],"BBB"],"c":99}'} do_catchsql_test json105-6.10 { SELECT json_extract(j, '$.b[#-]') FROM t1; } {1 {JSON path error near '[#-]'}} do_catchsql_test json105-6.20 { SELECT json_extract(j, '$.b[#9]') FROM t1; } {1 {JSON path error near '[#9]'}} do_catchsql_test json105-6.30 { SELECT json_extract(j, '$.b[#+2]') FROM t1; } {1 {JSON path error near '[#+2]'}} do_catchsql_test json105-6.40 { SELECT json_extract(j, '$.b[#-1') FROM t1; } {1 {JSON path error near '[#-1'}} do_catchsql_test json105-6.50 { SELECT json_extract(j, '$.b[#-1x]') FROM t1; } {1 {JSON path error near '[#-1x]'}} finish_test |
Changes to test/kvtest.c.
︙ | ︙ | |||
903 904 905 906 907 908 909 | continue; } fatalError("unknown option: \"%s\"", argv[i]); } if( eType==PATH_DB ){ /* Recover any prior crashes prior to starting the timer */ sqlite3_open(zDb, &db); | | | 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 | continue; } fatalError("unknown option: \"%s\"", argv[i]); } if( eType==PATH_DB ){ /* Recover any prior crashes prior to starting the timer */ sqlite3_open(zDb, &db); sqlite3_exec(db, "SELECT rowid FROM sqlite_schema LIMIT 1", 0, 0, 0); sqlite3_close(db); db = 0; } tmStart = timeOfDay(); if( eType==PATH_DB ){ char *zSql; rc = sqlite3_open(zDb, &db); |
︙ | ︙ |
Changes to test/like.test.
︙ | ︙ | |||
13 14 15 16 17 18 19 20 21 22 23 24 25 26 | # in particular the optimizations that occur to help those operators # run faster. # # $Id: like.test,v 1.13 2009/06/07 23:45:11 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # Create some sample data to work with. # do_test like-1.0 { execsql { CREATE TABLE t1(x TEXT); } | > | 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | # in particular the optimizations that occur to help those operators # run faster. # # $Id: like.test,v 1.13 2009/06/07 23:45:11 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix like # Create some sample data to work with. # do_test like-1.0 { execsql { CREATE TABLE t1(x TEXT); } |
︙ | ︙ | |||
163 164 165 166 167 168 169 | db cache flush set data [execsql $sql] if {$::sqlite_sort_count} {set x sort} {set x nosort} lappend data $x set eqp [execsql "EXPLAIN QUERY PLAN $sql"] # puts eqp=$eqp foreach {a b c x} $eqp { | | | | | | | 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 | db cache flush set data [execsql $sql] if {$::sqlite_sort_count} {set x sort} {set x nosort} lappend data $x set eqp [execsql "EXPLAIN QUERY PLAN $sql"] # puts eqp=$eqp foreach {a b c x} $eqp { if {[regexp {(SCAN|SEARCH) (\w+ AS )?(\w+) USING COVERING INDEX (\w+)\y} \ $x all ss as tab idx]} { lappend data {} $idx } elseif {[regexp {(SCAN|SEARCH) (\w+ AS )?(\w+) USING.* INDEX (\w+)\y} \ $x all ss as tab idx]} { lappend data $tab $idx } elseif {[regexp {(SCAN|SEARCH) (\w+ AS )?(\w+)\y} $x all ss as tab]} { lappend data $tab * } } return $data } # Perform tests on the like optimization. |
︙ | ︙ | |||
721 722 723 724 725 726 727 | }] } {0 {x hello}} ifcapable explain { do_test like-9.4.3 { set res [sqlite3_exec_hex db { EXPLAIN QUERY PLAN SELECT x FROM t2 WHERE x LIKE '%ff%25' }] | | | 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 | }] } {0 {x hello}} ifcapable explain { do_test like-9.4.3 { set res [sqlite3_exec_hex db { EXPLAIN QUERY PLAN SELECT x FROM t2 WHERE x LIKE '%ff%25' }] regexp {SCAN t2} $res } {1} } do_test like-9.5.1 { set res [sqlite3_exec_hex db { SELECT x FROM t2 WHERE x LIKE '%fe%25' }] } {0 {}} |
︙ | ︙ | |||
1031 1032 1033 1034 1035 1036 1037 | # Performance testing for patterns with many wildcards. These LIKE and GLOB # patterns were quite slow with SQLite 3.15.2 and earlier. # do_test like-14.1 { set x [lindex [time { db one {SELECT 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaz'GLOB'*a*a*a*a*a*a*a*a*y'} }] 0] | > | | > | | | 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 | # Performance testing for patterns with many wildcards. These LIKE and GLOB # patterns were quite slow with SQLite 3.15.2 and earlier. # do_test like-14.1 { set x [lindex [time { db one {SELECT 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaz'GLOB'*a*a*a*a*a*a*a*a*y'} }] 0] set tlimit [expr {1000 * $::sqlite_options(configslower)}] puts -nonewline " ($x ms - want less than $tlimit) " expr {$x<$tlimit} } {1} ifcapable !icu { do_test like-14.2 { set x [lindex [time { db one {SELECT 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaz'LIKE'%a%a%a%a%a%a%a%a%y'} }] 0] set tlimit [expr {1000 * $::sqlite_options(configslower)}] puts -nonewline " ($x ms - want less than $tlimit) " expr {$x<$tlimit} } {1} } ifcapable !icu { # As of 2017-07-27 (3.21.0) the LIKE optimization works with ESCAPE as # long as the ESCAPE is a single-byte literal. # |
︙ | ︙ | |||
1090 1091 1092 1093 1094 1095 1096 1097 1098 | SELECT y FROM t15 WHERE x LIKE '/%bc%' ESCAPE '/'; } {22} do_execsql_test like-15.121 { EXPLAIN QUERY PLAN SELECT y FROM t15 WHERE x LIKE '/%bc%' ESCAPE '/'; } {/SEARCH/} } finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | SELECT y FROM t15 WHERE x LIKE '/%bc%' ESCAPE '/'; } {22} do_execsql_test like-15.121 { EXPLAIN QUERY PLAN SELECT y FROM t15 WHERE x LIKE '/%bc%' ESCAPE '/'; } {/SEARCH/} } #------------------------------------------------------------------------- # Tests for ticket [b1d8c79314]. # reset_db do_execsql_test 16.0 { CREATE TABLE t1(a INTEGER COLLATE NOCASE); CREATE INDEX i1 ON t1(a); INSERT INTO t1 VALUES(' 1x'); INSERT INTO t1 VALUES(' 1-'); } do_execsql_test 16.1 { SELECT * FROM t1 WHERE a LIKE ' 1%'; } {{ 1x} { 1-}} do_execsql_test 16.2 { SELECT * FROM t1 WHERE a LIKE ' 1-'; } {{ 1-}} # 2020-03-19 # The ESCAPE clause on LIKE takes precedence over wildcards # do_execsql_test 17.0 { DROP TABLE IF EXISTS t1; CREATE TABLE t1(id INTEGER PRIMARY KEY, x TEXT); INSERT INTO t1 VALUES (1,'abcde'), (2,'abc_'), (3,'abc__'), (4,'abc%'), (5,'abc%%'); SELECT id FROM t1 WHERE x LIKE 'abc%%' ESCAPE '%'; } {4} do_execsql_test 17.1 { SELECT id FROM t1 WHERE x LIKE 'abc__' ESCAPE '_'; } {2} # 2021-02-15 ticket c0aeea67d58ae0fd # do_execsql_test 17.1 { SELECT 'x' LIKE '%' ESCAPE '_'; } {1} finish_test |
Changes to test/like3.test.
︙ | ︙ | |||
121 122 123 124 125 126 127 | INSERT INTO t5a(x) VALUES('/abc'),(123),(-234); SELECT x FROM t5a WHERE x LIKE '/%'; } {/abc} do_eqp_test like3-5.101 { SELECT x FROM t5a WHERE x LIKE '/%'; } { QUERY PLAN | | | | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | INSERT INTO t5a(x) VALUES('/abc'),(123),(-234); SELECT x FROM t5a WHERE x LIKE '/%'; } {/abc} do_eqp_test like3-5.101 { SELECT x FROM t5a WHERE x LIKE '/%'; } { QUERY PLAN `--SCAN t5a } do_execsql_test like3-5.110 { SELECT x FROM t5a WHERE x LIKE '/a%'; } {/abc} ifcapable !icu { do_eqp_test like3-5.111 { SELECT x FROM t5a WHERE x LIKE '/a%'; } { QUERY PLAN `--SEARCH t5a USING COVERING INDEX sqlite_autoindex_t5a_1 (x>? AND x<?) } } do_execsql_test like3-5.120 { SELECT x FROM t5a WHERE x LIKE '^12%' ESCAPE '^'; } {123} do_eqp_test like3-5.121 { SELECT x FROM t5a WHERE x LIKE '^12%' ESCAPE '^'; } { QUERY PLAN `--SCAN t5a } do_execsql_test like3-5.122 { SELECT x FROM t5a WHERE x LIKE '^-2%' ESCAPE '^'; } {-234} do_eqp_test like3-5.123 { SELECT x FROM t5a WHERE x LIKE '^12%' ESCAPE '^'; } { QUERY PLAN `--SCAN t5a } do_execsql_test like3-5.200 { CREATE TABLE t5b(x INT UNIQUE COLLATE binary); INSERT INTO t5b(x) VALUES('/abc'),(123),(-234); SELECT x FROM t5b WHERE x GLOB '/*'; } {/abc} do_eqp_test like3-5.201 { SELECT x FROM t5b WHERE x GLOB '/*'; } { QUERY PLAN `--SCAN t5b } do_execsql_test like3-5.210 { SELECT x FROM t5b WHERE x GLOB '/a*'; } {/abc} do_eqp_test like3-5.211 { SELECT x FROM t5b WHERE x GLOB '/a*'; } { QUERY PLAN `--SEARCH t5b USING COVERING INDEX sqlite_autoindex_t5b_1 (x>? AND x<?) } # 2019-05-01 # another case of the above reported on the mailing list by Manuel Rigger. # do_execsql_test like3-5.300 { CREATE TABLE t5c (c0 REAL); CREATE INDEX t5c_0 ON t5c(c0 COLLATE NOCASE); INSERT INTO t5c(rowid, c0) VALUES (99,'+/'); SELECT * FROM t5c WHERE (c0 LIKE '+/'); } {+/} # 2019-05-08 # Yet another case for the above from Manuel Rigger. # do_execsql_test like3-5.400 { DROP TABLE IF EXISTS t0; CREATE TABLE t0(c0 INT UNIQUE COLLATE NOCASE); INSERT INTO t0(c0) VALUES ('./'); SELECT * FROM t0 WHERE t0.c0 LIKE './'; } {./} # 2019-06-14 # Ticket https://www.sqlite.org/src/info/ce8717f0885af975 do_execsql_test like3-5.410 { DROP TABLE IF EXISTS t0; CREATE TABLE t0(c0 INT UNIQUE COLLATE NOCASE); INSERT INTO t0(c0) VALUES ('.1%'); SELECT * FROM t0 WHERE t0.c0 LIKE '.1%'; } {.1%} # 2019-09-03 # Ticket https://www.sqlite.org/src/info/0f0428096f do_execsql_test like3-5.420 { DROP TABLE IF EXISTS t0; CREATE TABLE t0(c0 UNIQUE); INSERT INTO t0(c0) VALUES(-1); SELECT * FROM t0 WHERE t0.c0 GLOB '-*'; } {-1} do_execsql_test like3-5.421 { SELECT t0.c0 GLOB '-*' FROM t0; } {1} # 2019-02-27 # Verify that the LIKE optimization works with an ESCAPE clause when # using PRAGMA case_sensitive_like=ON. # ifcapable !icu { do_execsql_test like3-6.100 { DROP TABLE IF EXISTS t1; CREATE TABLE t1(path TEXT COLLATE nocase PRIMARY KEY,a,b,c) WITHOUT ROWID; } do_eqp_test like3-6.110 { SELECT * FROM t1 WHERE path LIKE 'a%'; } { QUERY PLAN `--SEARCH t1 USING PRIMARY KEY (path>? AND path<?) } do_eqp_test like3-6.120 { SELECT * FROM t1 WHERE path LIKE 'a%' ESCAPE 'x'; } { QUERY PLAN `--SEARCH t1 USING PRIMARY KEY (path>? AND path<?) } do_execsql_test like3-6.200 { DROP TABLE IF EXISTS t2; CREATE TABLE t2(path TEXT,x,y,z); CREATE INDEX t2path ON t2(path COLLATE nocase); CREATE INDEX t2path2 ON t2(path); } do_eqp_test like3-6.210 { SELECT * FROM t2 WHERE path LIKE 'a%'; } { QUERY PLAN `--SEARCH t2 USING INDEX t2path (path>? AND path<?) } do_eqp_test like3-6.220 { SELECT * FROM t2 WHERE path LIKE 'a%' ESCAPE '\'; } { QUERY PLAN `--SEARCH t2 USING INDEX t2path (path>? AND path<?) } db eval {PRAGMA case_sensitive_like=ON} do_eqp_test like3-6.230 { SELECT * FROM t2 WHERE path LIKE 'a%'; } { QUERY PLAN `--SEARCH t2 USING INDEX t2path2 (path>? AND path<?) } do_eqp_test like3-6.240 { SELECT * FROM t2 WHERE path LIKE 'a%' ESCAPE '\'; } { QUERY PLAN `--SEARCH t2 USING INDEX t2path2 (path>? AND path<?) } } finish_test |
Changes to test/limit.test.
︙ | ︙ | |||
637 638 639 640 641 642 643 644 645 | do_execsql_test limit-14.6 { SELECT 123 LIMIT -1 OFFSET 0 } {123} do_execsql_test limit-14.7 { SELECT 123 LIMIT -1 OFFSET 1 } {} finish_test | > > > > > > > > > > > > > > > > > > > > > > > | 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 | do_execsql_test limit-14.6 { SELECT 123 LIMIT -1 OFFSET 0 } {123} do_execsql_test limit-14.7 { SELECT 123 LIMIT -1 OFFSET 1 } {} # 2021-03-05 dbsqlfuzz crash-d811039c9f44f2d43199d5889fcf4085ef6221b9 # reset_db do_execsql_test limit-15.1 { CREATE TABLE t1(a PRIMARY KEY, b TEXT); CREATE TABLE t4(c PRIMARY KEY, d); CREATE TABLE t5(e PRIMARY KEY, f); CREATE TABLE t6(g, h); CREATE TABLE t3_a(k, v); CREATE TABLE t3_b(k, v); CREATE VIEW t3 AS SELECT * FROM t3_a UNION ALL SELECT * FROM t3_b; INSERT INTO t5(e,f) VALUES(500000,'orange'); INSERT INTO t4(c,d) VALUES(300000,'blue'),(400,'green'),(8000,'grey'); INSERT INTO t1(a,b) VALUES(300000,'purple'); INSERT INTO t3_a VALUES(300000,'yellow'),(500,'pink'),(8000,'red'); INSERT INTO t6 default values; SELECT ( SELECT 100000 FROM (SELECT 200000 FROM t6 WHERE a = ( SELECT 300000 FROM t3 WHERE a ) ), (SELECT 400000 FROM t5 WHERE e=500000), (SELECT 600000 FROM t4 WHERE c=a) ) FROM t1; } {100000} finish_test |
Changes to test/lock_common.tcl.
︙ | ︙ | |||
11 12 13 14 15 16 17 | # This file contains code used by several different test scripts. The # code in this file allows testfixture to control another process (or # processes) to test locking. # proc do_multiclient_test {varname script} { | | < | < > > > > | 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 | # This file contains code used by several different test scripts. The # code in this file allows testfixture to control another process (or # processes) to test locking. # proc do_multiclient_test {varname script} { foreach {tn code} [list 1 { if {[info exists ::G(valgrind)]} { db close ; continue } set ::code2_chan [launch_testfixture] set ::code3_chan [launch_testfixture] proc code2 {tcl} { testfixture $::code2_chan $tcl } proc code3 {tcl} { testfixture $::code3_chan $tcl } } 2 { proc code2 {tcl} { uplevel #0 $tcl } proc code3 {tcl} { uplevel #0 $tcl } }] { # Do not run multi-process tests with the unix-excl VFS. # if {$tn==1 && [permutation]=="unix-excl"} continue faultsim_delete_and_reopen proc code1 {tcl} { uplevel #0 $tcl } # Open connections [db2] and [db3]. Depending on which iteration this # is, the connections may be created in this interpreter, or in # interpreters running in other OS processes. As such, the [db2] and [db3] |
︙ | ︙ |
Changes to test/mallocA.test.
︙ | ︙ | |||
92 93 94 95 96 97 98 | faultsim_test_result [list 0 2] } do_faultsim_test 6.2 -faults oom* -body { execsql { SELECT rowid FROM t1 WHERE a='abc' AND b<'y' } } -test { faultsim_test_result [list 0 {1 2}] } | < < < < < < < < < < < < < < < < < < | 92 93 94 95 96 97 98 99 100 101 102 103 104 105 | faultsim_test_result [list 0 2] } do_faultsim_test 6.2 -faults oom* -body { execsql { SELECT rowid FROM t1 WHERE a='abc' AND b<'y' } } -test { faultsim_test_result [list 0 {1 2}] } do_execsql_test 7.0 { PRAGMA cache_size = 5; } do_faultsim_test 7 -faults oom-trans* -prep { } -body { execsql { |
︙ | ︙ |
Changes to test/mallocK.test.
︙ | ︙ | |||
119 120 121 122 123 124 125 | } {1} ifcapable stat4 { do_eqp_test 6.1 { SELECT DISTINCT c FROM t3 WHERE b BETWEEN '.xx..' AND '.xxxx'; } [string map {"\n " \n} { QUERY PLAN | | | 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 | } {1} ifcapable stat4 { do_eqp_test 6.1 { SELECT DISTINCT c FROM t3 WHERE b BETWEEN '.xx..' AND '.xxxx'; } [string map {"\n " \n} { QUERY PLAN |--SEARCH t3 USING INDEX i3 (ANY(a) AND b>? AND b<?) `--USE TEMP B-TREE FOR DISTINCT }] } do_faultsim_test 6 -faults oom* -body { db cache flush db eval { SELECT DISTINCT c FROM t3 WHERE b BETWEEN '.xx..' AND '.xxxx' } |
︙ | ︙ |
Changes to test/memdb1.test.
︙ | ︙ | |||
67 68 69 70 71 72 73 74 75 76 77 78 79 80 | DROP TABLE t2; PRAGMA page_count; } {116} do_execsql_test 140 { VACUUM; PRAGMA page_count; } {2} # Build a largish on-disk database and serialize it. Verify that the # serialization works. # db close forcedelete test.db sqlite3 db test.db | > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | DROP TABLE t2; PRAGMA page_count; } {116} do_execsql_test 140 { VACUUM; PRAGMA page_count; } {2} do_test 150 { catch {db deserialize -unknown 1 $db1} msg set msg } {unknown option: -unknown} do_test 151 { db deserialize -readonly 1 $db1 db eval {SELECT * FROM t1} } {1 2} do_test 152 { catchsql {INSERT INTO t1 VALUES(3,4);} } {1 {attempt to write a readonly database}} breakpoint do_test 160 { db deserialize -maxsize 32768 $db1 db eval {SELECT * FROM t1} } {1 2} do_test 161 { db eval {INSERT INTO t1 VALUES(3,4); SELECT * FROM t1} } {1 2 3 4} do_test 162 { catchsql {INSERT INTO t1 VALUES(5,randomblob(100000))} } {1 {database or disk is full}} # Build a largish on-disk database and serialize it. Verify that the # serialization works. # db close forcedelete test.db sqlite3 db test.db |
︙ | ︙ | |||
128 129 130 131 132 133 134 135 136 137 138 139 140 141 | } {ok} do_execsql_test 410 { CREATE TABLE t4(a,b); INSERT INTO t4 VALUES('hello','world!'); PRAGMA integrity_check; SELECT * FROM t4; } {ok hello world!} # Deserialize something that is not a database. # db close sqlite3 db do_test 500 { set rc [catch {db deserialize not-a-database} msg] | > > > > > > > > > > | 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 | } {ok} do_execsql_test 410 { CREATE TABLE t4(a,b); INSERT INTO t4 VALUES('hello','world!'); PRAGMA integrity_check; SELECT * FROM t4; } {ok hello world!} do_execsql_test 420 { PRAGMA journal_mode=TRUNCATE; PRAGMA journal_mode=OFF; PRAGMA journal_mode=DELETE; PRAGMA journal_mode=WAL; PRAGMA journal_mode=PERSIST; PRAGMA journal_mode=MEMORY; PRAGMA journal_mode=OFF; PRAGMA journal_mode=DELETE; } {truncate off delete delete persist memory off delete} # Deserialize something that is not a database. # db close sqlite3 db do_test 500 { set rc [catch {db deserialize not-a-database} msg] |
︙ | ︙ | |||
150 151 152 153 154 155 156 | do_test 600 { set rc [catch {db deserialize} msg] lappend rc $msg } {1 {wrong # args: should be "db deserialize ?DATABASE? VALUE"}} do_test 610 { set rc [catch {db deserialize a b c} msg] lappend rc $msg | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | do_test 600 { set rc [catch {db deserialize} msg] lappend rc $msg } {1 {wrong # args: should be "db deserialize ?DATABASE? VALUE"}} do_test 610 { set rc [catch {db deserialize a b c} msg] lappend rc $msg } {1 {unknown option: a}} do_test 620 { set rc [catch {db serialize a b} msg] lappend rc $msg } {1 {wrong # args: should be "db serialize ?DATABASE?"}} # 2021-07-19 https://sqlite.org/forum/forumpost/e1cbb5f450b98aa6 # The TEMP database cannot participate in serialization or # deserialization. # reset_db do_test 650 { db eval { CREATE TEMP TABLE t0(a); CREATE TABLE t1(x); WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<1000) INSERT INTO t1(x) SELECT random() FROM c; } set rc [catch {db deserialize temp [db serialize main]} err] lappend rc err } {1 err} #------------------------------------------------------------------------- ifcapable vtab { reset_db do_execsql_test 700 { CREATE TABLE t1(a, b); PRAGMA schema_version = 0; } do_test 710 { set ser [db serialize main] db close sqlite3 db db deserialize main $ser catchsql { CREATE VIRTUAL TABLE t1 USING rtree(id, a, b, c, d); } } {1 {table t1 already exists}} } #------------------------------------------------------------------------- # dbsqlfuzz 0a13dfb474d4f2f11a48a2ea57075c96fb456dd7 # if {[wal_is_capable]} { reset_db do_execsql_test 800 { PRAGMA auto_vacuum = 0; PRAGMA page_size = 8192; PRAGMA journal_mode = wal; CREATE TABLE t1(x, y); INSERT INTO t1 VALUES(1, 2); CREATE TABLE t2(x, y); } {wal} db close set fd [open test.db] fconfigure $fd -translation binary -encoding binary set data [read $fd [expr 20*1024]] sqlite3 db "" db deserialize $data do_execsql_test 810 { PRAGMA locking_mode = exclusive; SELECT * FROM t1 } {exclusive 1 2} do_execsql_test 820 { INSERT INTO t1 VALUES(3, 4); SELECT * FROM t1; } {1 2 3 4} do_catchsql_test 830 { PRAGMA wal_checkpoint; } {1 {database disk image is malformed}} } finish_test |
Added test/memjournal.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 | # 2021 May 24 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # Tests focused on the in-memory journal. # set testdir [file dirname $argv0] source $testdir/tester.tcl source $testdir/malloc_common.tcl set testprefix memjournal do_execsql_test 1.0 { PRAGMA journal_mode = memory; CREATE TABLE t1(a); } {memory} set nRow [expr 1] do_execsql_test 1.1 { BEGIN; INSERT INTO t1 VALUES( randomblob(500) ); } {} do_test 1.2 { for {set i 1} {$i <= 500} {incr i} { execsql { SAVEPOINT one; UPDATE t1 SET a=randomblob(500); } execsql { SAVEPOINT abc } execsql { UPDATE t1 SET a=randomblob(500) WHERE rowid<=$i AND 0 } execsql { RELEASE abc } } } {} do_execsql_test 1.3 { COMMIT; } finish_test |
Changes to test/minmax.test.
︙ | ︙ | |||
290 291 292 293 294 295 296 297 298 | } } {34 1234} # Ticket #658: Test the min()/max() optimization when the FROM clause # is a subquery. # ifcapable {compound && subquery} { do_test minmax-9.1 { execsql { | > > > > > | | | | | | 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 | } } {34 1234} # Ticket #658: Test the min()/max() optimization when the FROM clause # is a subquery. # ifcapable {compound && subquery} { do_test minmax-9.0 { execsql { SELECT max(rowid) AS yy FROM t4 UNION SELECT max(rowid) FROM t5 } } {3} do_test minmax-9.1 { execsql { SELECT max(yy) FROM ( SELECT max(rowid) AS yy FROM t4 UNION SELECT max(rowid) FROM t5 ) } } {3} do_test minmax-9.2 { execsql { SELECT max(yy) FROM ( SELECT max(rowid) AS yy FROM t4 EXCEPT SELECT max(rowid) FROM t5 ) } } {{}} } ;# ifcapable compound&&subquery # If there is a NULL in an aggregate max() or min(), ignore it. An # aggregate min() or max() will only return NULL if all values are NULL. |
︙ | ︙ | |||
637 638 639 640 641 642 643 | SELECT min(a) FROM t14 WHERE b='2' AND a>'50'; } {100} do_execsql_test 14.2 { CREATE INDEX t14ba ON t14(b,a); SELECT min(a) FROM t14 WHERE b='2' AND a>'50'; } {100} | > | > > > > > > > > > | 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 | SELECT min(a) FROM t14 WHERE b='2' AND a>'50'; } {100} do_execsql_test 14.2 { CREATE INDEX t14ba ON t14(b,a); SELECT min(a) FROM t14 WHERE b='2' AND a>'50'; } {100} # 2021-08-21. https://sqlite.org/forum/forumpost/cfcb4b461d # reset_db do_execsql_test 15.1 { CREATE TABLE t1(a); CREATE TABLE t2(b); CREATE TABLE t3(c); INSERT INTO t1 VALUES(0); INSERT INTO t2 VALUES(5); SELECT MIN((SELECT b FROM t2 UNION SELECT x FROM (SELECT x FROM (SELECT 1 AS x WHERE t1.a=1) UNION ALL SELECT c FROM t3))) FROM t1; } {5} finish_test |
Changes to test/minmax2.test.
︙ | ︙ | |||
17 18 19 20 21 22 23 24 | # # $Id: minmax2.test,v 1.2 2008/01/05 17:39:30 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl do_test minmax2-1.0 { execsql { | > < | 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | # # $Id: minmax2.test,v 1.2 2008/01/05 17:39:30 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl do_test minmax2-1.0 { sqlite3_db_config db LEGACY_FILE_FORMAT 0 execsql { BEGIN; CREATE TABLE t1(x, y); INSERT INTO t1 VALUES(1,1); INSERT INTO t1 VALUES(2,2); INSERT INTO t1 VALUES(3,2); INSERT INTO t1 VALUES(4,3); INSERT INTO t1 VALUES(5,3); |
︙ | ︙ | |||
279 280 281 282 283 284 285 286 287 | } } {34 1234} # Ticket #658: Test the min()/max() optimization when the FROM clause # is a subquery. # ifcapable {compound && subquery} { do_test minmax2-9.1 { execsql { | > > > > > | | | | | | 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 | } } {34 1234} # Ticket #658: Test the min()/max() optimization when the FROM clause # is a subquery. # ifcapable {compound && subquery} { do_test minmax2-9.0 { execsql { SELECT max(rowid) FROM t4 UNION SELECT max(rowid) FROM t5 } } {3} do_test minmax2-9.1 { execsql { SELECT max(yy) FROM ( SELECT max(rowid) AS yy FROM t4 UNION SELECT max(rowid) FROM t5 ) } } {3} do_test minmax2-9.2 { execsql { SELECT max(yy) FROM ( SELECT max(rowid) AS yy FROM t4 EXCEPT SELECT max(rowid) FROM t5 ) } } {{}} } ;# ifcapable compound&&subquery # If there is a NULL in an aggregate max() or min(), ignore it. An # aggregate min() or max() will only return NULL if all values are NULL. |
︙ | ︙ |
Changes to test/minmax4.test.
︙ | ︙ | |||
15 16 17 18 19 20 21 22 23 24 25 26 27 28 | # # Demonstration that the value returned for p is on the same row as # the maximum q. # set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable !compound { finish_test return } do_test minmax4-1.1 { | > | 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | # # Demonstration that the value returned for p is on the same row as # the maximum q. # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix minmax4 ifcapable !compound { finish_test return } do_test minmax4-1.1 { |
︙ | ︙ | |||
144 145 146 147 148 149 150 | } {1 2 1 4 4 2 3 3 5 5} do_test minmax4-2.7 { db eval { SELECT a, min(b), b, min(c), c FROM t2 GROUP BY a ORDER BY a; } } {1 1 {} 2 2 2 3 3 5 5} | > > > > > > > > > > | > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | } {1 2 1 4 4 2 3 3 5 5} do_test minmax4-2.7 { db eval { SELECT a, min(b), b, min(c), c FROM t2 GROUP BY a ORDER BY a; } } {1 1 {} 2 2 2 3 3 5 5} #------------------------------------------------------------------------- foreach {tn sql} { 1 { CREATE INDEX i1 ON t1(a) } 2 { CREATE INDEX i1 ON t1(a DESC) } 3 { } } { reset_db do_execsql_test 3.$tn.0 { CREATE TABLE t1(a, b); INSERT INTO t1 VALUES(NULL, 1); } execsql $sql do_execsql_test 3.$tn.1 { SELECT min(a), b FROM t1; } {{} 1} do_execsql_test 3.$tn.2 { SELECT min(a), b FROM t1 WHERE a<50; } {{} {}} do_execsql_test 3.$tn.3 { INSERT INTO t1 VALUES(2, 2); } do_execsql_test 3.$tn.4 { SELECT min(a), b FROM t1; } {2 2} do_execsql_test 3.$tn.5 { SELECT min(a), b FROM t1 WHERE a<50; } {2 2} } #------------------------------------------------------------------------- reset_db do_execsql_test 4.0 { CREATE TABLE t0 (c0, c1); CREATE INDEX i0 ON t0(c1, c1 + 1 DESC); INSERT INTO t0(c0) VALUES (1); } do_execsql_test 4.1 { SELECT MIN(t0.c1), t0.c0 FROM t0 WHERE t0.c1 ISNULL; } {{} 1} #------------------------------------------------------------------------- reset_db do_execsql_test 5.0 { CREATE TABLE t1 (a, b); INSERT INTO t1 VALUES(123, NULL); CREATE INDEX i1 ON t1(a, b DESC); } do_execsql_test 5.1 { SELECT MIN(a) FROM t1 WHERE a=123; } {123} #------------------------------------------------------------------------- # Tests for ticket f8a7060ece. # reset_db do_execsql_test 6.1.0 { CREATE TABLE t1(a, b, c); INSERT INTO t1 VALUES(NULL, 1, 'x'); CREATE INDEX i1 ON t1(a); } do_execsql_test 6.1.1 { SELECT min(a), b, c FROM t1 WHERE c='x'; } {{} 1 x} do_execsql_test 6.1.2 { INSERT INTO t1 VALUES(1, 2, 'y'); } {} do_execsql_test 6.1.3 { SELECT min(a), b, c FROM t1 WHERE c='x'; } {{} 1 x} do_execsql_test 6.2.0 { CREATE TABLE t0(c0 UNIQUE, c1); INSERT INTO t0(c1) VALUES (0); INSERT INTO t0(c0) VALUES (0); CREATE VIEW v0(c0, c1) AS SELECT t0.c1, t0.c0 FROM t0 WHERE CAST(t0.rowid AS INT) = 1; } do_execsql_test 6.2.1 { SELECT c0, c1 FROM v0; } {0 {}} do_execsql_test 6.2.2 { SELECT v0.c0, MIN(v0.c1) FROM v0; } {0 {}} finish_test |
Changes to test/misc1.test.
︙ | ︙ | |||
724 725 726 727 728 729 730 | CREATE TABLE abc(a, b, c); SELECT randomblob(min(max(coalesce(EXISTS (SELECT 1 FROM ( SELECT (SELECT 2147483647) NOT IN (SELECT 2147483649 UNION ALL SELECT DISTINCT -1) IN (SELECT 2147483649), 'fault', (SELECT ALL -1 INTERSECT SELECT 'experiments') IN (SELECT ALL 56.1 ORDER BY 'experiments' DESC) FROM (SELECT DISTINCT 2147483648, 'hardware' UNION ALL SELECT -2147483648, 'experiments' ORDER BY 2147483648 LIMIT 1 OFFSET 123456789.1234567899) GROUP BY (SELECT ALL 0 INTERSECT SELECT 'in') IN (SELECT DISTINCT 'experiments' ORDER BY zeroblob(1000) LIMIT 56.1 OFFSET -456) HAVING EXISTS (SELECT 'fault' EXCEPT SELECT DISTINCT 56.1) UNION SELECT 'The', 'The', 2147483649 UNION ALL SELECT DISTINCT 'hardware', 'first', 'experiments' ORDER BY 'hardware' LIMIT 123456789.1234567899 OFFSET -2147483647)) NOT IN (SELECT (SELECT DISTINCT (SELECT 'The') FROM abc ORDER BY EXISTS (SELECT -1 INTERSECT SELECT ALL NULL) ASC) IN (SELECT DISTINCT EXISTS (SELECT ALL 123456789.1234567899 ORDER BY 1 ASC, NULL DESC) FROM sqlite_master INTERSECT SELECT 456)), (SELECT ALL 'injection' UNION ALL SELECT ALL (SELECT DISTINCT 'first' UNION SELECT DISTINCT 'The') FROM (SELECT 456, 'in', 2147483649))),1), 500)), 'first', EXISTS (SELECT DISTINCT 456 FROM abc ORDER BY 'experiments' DESC) FROM abc; } {} # 2017-12-29 # # The following behaviors (duplicate column names on an INSERT or UPDATE) | > > > > > > > | > | > > > > > > > > > > > > > | 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 | CREATE TABLE abc(a, b, c); SELECT randomblob(min(max(coalesce(EXISTS (SELECT 1 FROM ( SELECT (SELECT 2147483647) NOT IN (SELECT 2147483649 UNION ALL SELECT DISTINCT -1) IN (SELECT 2147483649), 'fault', (SELECT ALL -1 INTERSECT SELECT 'experiments') IN (SELECT ALL 56.1 ORDER BY 'experiments' DESC) FROM (SELECT DISTINCT 2147483648, 'hardware' UNION ALL SELECT -2147483648, 'experiments' ORDER BY 2147483648 LIMIT 1 OFFSET 123456789.1234567899) GROUP BY (SELECT ALL 0 INTERSECT SELECT 'in') IN (SELECT DISTINCT 'experiments' ORDER BY zeroblob(1000) LIMIT 56.1 OFFSET -456) HAVING EXISTS (SELECT 'fault' EXCEPT SELECT DISTINCT 56.1) UNION SELECT 'The', 'The', 2147483649 UNION ALL SELECT DISTINCT 'hardware', 'first', 'experiments' ORDER BY 'hardware' LIMIT 123456789.1234567899 OFFSET -2147483647)) NOT IN (SELECT (SELECT DISTINCT (SELECT 'The') FROM abc ORDER BY EXISTS (SELECT -1 INTERSECT SELECT ALL NULL) ASC) IN (SELECT DISTINCT EXISTS (SELECT ALL 123456789.1234567899 ORDER BY 1 ASC, NULL DESC) FROM sqlite_master INTERSECT SELECT 456)), (SELECT ALL 'injection' UNION ALL SELECT ALL (SELECT DISTINCT 'first' UNION SELECT DISTINCT 'The') FROM (SELECT 456, 'in', 2147483649))),1), 500)), 'first', EXISTS (SELECT DISTINCT 456 FROM abc ORDER BY 'experiments' DESC) FROM abc; } {} # 2017-12-29 # # The following behaviors (duplicate column names on an INSERT or UPDATE) # are undocumented. <<--- Not so. There is a long-standing requirement # in lang_update.in to say that when the columns to be updated appear more # than once in an UPDATE statement that only the rightmost expression is used. # See e_update-1.6.* for the tests. This is unfortunate, since omitting # that requirement would greatly simplify the fix to the problem identified # by forum post https://sqlite.org/forum/info/16ca0e9f32c38567 # # These tests are added to ensure that historical behavior # does not change accidentally. # # For duplication columns on an INSERT, the first value is used. # For duplication columns on an UPDATE, the last value is used. # do_execsql_test misc1-27.0 { CREATE TABLE dup1(a,b,c); INSERT INTO dup1(a,b,c,a,b,c) VALUES(1,2,3,4,5,6); SELECT a,b,c FROM dup1; } {1 2 3} do_execsql_test misc1-27.1 { UPDATE dup1 SET a=7, b=8, c=9, a=10, b=11, c=12; SELECT a,b,c FROM dup1; } {10 11 12} # 2018-12-20 # # The Cursor.seekOp debugging value set incorrectly # in OP_NotExists. # sqlite3 db :memory: do_execsql_test misc1-28.0 { CREATE TABLE t1(x); CREATE UNIQUE INDEX t1x ON t1(x) WHERE x=1; INSERT OR ABORT INTO t1 DEFAULT VALUES; UPDATE OR REPLACE t1 SET x = 1; PRAGMA integrity_check; SELECT * FROM t1; } {ok 1} finish_test |
Changes to test/misc2.test.
︙ | ︙ | |||
50 51 52 53 54 55 56 | CREATE TABLE t1(a,b,c); INSERT INTO t1 VALUES(1,2,3); CREATE TABLE t2(a,b,c); INSERT INTO t2 VALUES(7,8,9); } } {} ifcapable subquery { | | < | > > > > | < | | < | | < > > > | | 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 | CREATE TABLE t1(a,b,c); INSERT INTO t1 VALUES(1,2,3); CREATE TABLE t2(a,b,c); INSERT INTO t2 VALUES(7,8,9); } } {} ifcapable subquery { do_catchsql_test misc2-2.2 { SELECT rowid, * FROM (SELECT * FROM t1, t2); } {1 {no such column: rowid}} do_catchsql_test misc2-2.2b { SELECT 'rowid', * FROM (SELECT * FROM t1, t2); } {0 {rowid 1 2 3 7 8 9}} } ifcapable view { do_catchsql_test misc2-2.3 { CREATE VIEW v1 AS SELECT * FROM t1, t2; SELECT rowid, * FROM v1; } {1 {no such column: rowid}} do_catchsql_test misc2-2.3b { SELECT 'rowid', * FROM v1; } {0 {rowid 1 2 3 7 8 9}} } ;# ifcapable view # Ticket #2002 and #1952. ifcapable subquery { do_test misc2-2.4 { execsql2 { SELECT * FROM (SELECT a, b AS 'a', c AS 'a', 4 AS 'a' FROM t1) |
︙ | ︙ |
Changes to test/misc7.test.
︙ | ︙ | |||
223 224 225 226 227 228 229 230 231 232 233 234 235 236 | register_echo_module [sqlite3_connection_pointer db] execsql { CREATE VIRTUAL TABLE t1 USING echo(abc); SELECT a FROM t1 WHERE a = 1 ORDER BY b; } } {1} set sqlite_where_trace 0 # Specify an ORDER BY clause that cannot be indexed. do_test misc7-11 { execsql { SELECT t1.a, t2.a FROM t1, t1 AS t2 ORDER BY 2 LIMIT 1; } } {1 1} | > > > | 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 | register_echo_module [sqlite3_connection_pointer db] execsql { CREATE VIRTUAL TABLE t1 USING echo(abc); SELECT a FROM t1 WHERE a = 1 ORDER BY b; } } {1} set sqlite_where_trace 0 do_catchsql_test misc7-10.1 { INSERT INTO t1(a,b,c) VALUES(12345,2,3) ON CONFLICT(a) DO NOTHING; } {1 {UPSERT not implemented for virtual table "t1"}} # Specify an ORDER BY clause that cannot be indexed. do_test misc7-11 { execsql { SELECT t1.a, t2.a FROM t1, t1 AS t2 ORDER BY 2 LIMIT 1; } } {1 1} |
︙ | ︙ | |||
273 274 275 276 277 278 279 | do_execsql_test misc7-14.0 { CREATE TABLE abc(a PRIMARY KEY, b, c); } do_eqp_test misc7-14.1 { SELECT * FROM abc AS t2 WHERE rowid = 1; } { QUERY PLAN | | | | | 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 | do_execsql_test misc7-14.0 { CREATE TABLE abc(a PRIMARY KEY, b, c); } do_eqp_test misc7-14.1 { SELECT * FROM abc AS t2 WHERE rowid = 1; } { QUERY PLAN `--SEARCH t2 USING INTEGER PRIMARY KEY (rowid=?) } do_eqp_test misc7-14.2 { SELECT * FROM abc AS t2 WHERE a = 1; } { QUERY PLAN `--SEARCH t2 USING INDEX sqlite_autoindex_abc_1 (a=?) } do_eqp_test misc7-14.3 { SELECT * FROM abc AS t2 ORDER BY a; } { QUERY PLAN `--SCAN t2 USING INDEX sqlite_autoindex_abc_1 } } db close forcedelete test.db forcedelete test.db-journal sqlite3 db test.db |
︙ | ︙ | |||
448 449 450 451 452 453 454 | do_test misc7-17.4 { db close sqlite3 db test.db catchsql { SELECT count(*) FROM t3; } | | > | 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 | do_test misc7-17.4 { db close sqlite3 db test.db catchsql { SELECT count(*) FROM t3; } } {1 {malformed database schema (t3) - invalid rootpage}} } } # Ticket #2470 # reset_db do_test misc7-18.1 { execsql { CREATE TABLE table_1 (col_10); CREATE TABLE table_2 ( col_1, col_2, col_3, col_4, col_5, col_6, col_7, col_8, col_9, col_10 ); |
︙ | ︙ |
Changes to test/misc8.test.
︙ | ︙ | |||
96 97 98 99 100 101 102 | 0 8 {} 10 {} {} 0 9 {} 10 {} {} 0 10 {} 10 {} {} } # 2016-02-26: An assertion fault found by the libFuzzer project # | | | | 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 | 0 8 {} 10 {} {} 0 9 {} 10 {} {} 0 10 {} 10 {} {} } # 2016-02-26: An assertion fault found by the libFuzzer project # do_catchsql_test misc8-3.0 { SELECT * FROM ( (SELECT 0 AS i) AS x1, (SELECT 1) AS x2 ) AS x3, (SELECT 6 AS j UNION ALL SELECT 7) AS x4 WHERE i<rowid ORDER BY 1; } {1 {no such column: rowid}} # The SQLITE_DBCONFIG_MAINDBNAME interface # db close forcedelete test.db test2.db sqlite3 db test.db do_execsql_test misc8-4.0 { |
︙ | ︙ | |||
128 129 130 131 132 133 134 | do_execsql_test misc8-4.1 { PRAGMA database_list; } {/0 main .* 2 aux2/} dbconfig_maindbname_icecube db do_execsql_test misc8-4.2 { SELECT name FROM icecube.sqlite_master; } {t1} | | | | | 128 129 130 131 132 133 134 135 136 137 138 139 140 141 | do_execsql_test misc8-4.1 { PRAGMA database_list; } {/0 main .* 2 aux2/} dbconfig_maindbname_icecube db do_execsql_test misc8-4.2 { SELECT name FROM icecube.sqlite_master; } {t1} do_test misc8-4.3 { regexp {0 icecube .* 2 aux2} [db eval {PRAGMA database_list}] } 1 finish_test |
Changes to test/mmap1.test.
︙ | ︙ | |||
8 9 10 11 12 13 14 | # May you share freely, never taking more than you give. # #*********************************************************************** # set testdir [file dirname $argv0] source $testdir/tester.tcl | | | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | # May you share freely, never taking more than you give. # #*********************************************************************** # set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable !mmap||!incrblob { finish_test return } source $testdir/lock_common.tcl set testprefix mmap1 proc nRead {db} { |
︙ | ︙ |
Changes to test/multiplex.test.
︙ | ︙ | |||
178 179 180 181 182 183 184 185 186 187 188 189 190 191 | INSERT INTO t1 VALUES(2, randomblob(1100)); } } {} do_test multiplex-2.1.3 { file size [multiplex_name test.x 0] } {4096} do_test multiplex-2.1.4 { execsql { INSERT INTO t1 VALUES(3, randomblob(1100)) } } {} do_test multiplex-2.2.1 { execsql { INSERT INTO t1 VALUES(3, randomblob(1100)) } } {} do_test multiplex-2.2.3 { file size [multiplex_name test.x 0] } {6144} do_test multiplex-2.3.1 { | > > > > > | 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 | INSERT INTO t1 VALUES(2, randomblob(1100)); } } {} do_test multiplex-2.1.3 { file size [multiplex_name test.x 0] } {4096} do_test multiplex-2.1.4 { execsql { INSERT INTO t1 VALUES(3, randomblob(1100)) } } {} do_execsql_test multiplex-2.1.5 { PRAGMA multiplex_enabled; PRAGMA multiplex_filecount; PRAGMA multiplex_chunksize; } {1 1 2147418112} do_test multiplex-2.2.1 { execsql { INSERT INTO t1 VALUES(3, randomblob(1100)) } } {} do_test multiplex-2.2.3 { file size [multiplex_name test.x 0] } {6144} do_test multiplex-2.3.1 { |
︙ | ︙ | |||
263 264 265 266 267 268 269 270 271 272 273 274 275 276 | do_test multiplex-2.5.8 { db eval {SELECT a,length(b) FROM t1 WHERE a=4} } {4 4000} do_test multiplex-2.5.9 { file size [multiplex_name test.x 0] } [list $g_chunk_size] do_test multiplex-2.5.10 { file size [multiplex_name test.x 1] } [list $g_chunk_size] do_test multiplex-2.5.99 { db close sqlite3_multiplex_shutdown } {SQLITE_OK} | > > > > > > > > > > > > | 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 | do_test multiplex-2.5.8 { db eval {SELECT a,length(b) FROM t1 WHERE a=4} } {4 4000} do_test multiplex-2.5.9 { file size [multiplex_name test.x 0] } [list $g_chunk_size] do_test multiplex-2.5.10 { file size [multiplex_name test.x 1] } [list $g_chunk_size] do_execsql_test multiplex-2.5.11 { PRAGMA multiplex_enabled; PRAGMA multiplex_filecount; PRAGMA multiplex_chunksize; } {1 3 65536} sqlite3 db test.x do_execsql_test multiplex-2.5.12 { PRAGMA multiplex_filecount; PRAGMA multiplex_chunksize; } {3 65536} do_test multiplex-2.5.99 { db close sqlite3_multiplex_shutdown } {SQLITE_OK} |
︙ | ︙ |
Changes to test/mutex1.test.
︙ | ︙ | |||
34 35 36 37 38 39 40 | incr var(total) $value } } #------------------------------------------------------------------------- # Tests mutex1-1.* test that sqlite3_config() returns SQLITE_MISUSE if # is called at the wrong time. And that the first time sqlite3_initialize | | | 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | incr var(total) $value } } #------------------------------------------------------------------------- # Tests mutex1-1.* test that sqlite3_config() returns SQLITE_MISUSE if # is called at the wrong time. And that the first time sqlite3_initialize # is called it obtains the 'static_main' mutex 3 times and a recursive # mutex (sqlite3Config.pInitMutex) twice. Subsequent calls are no-ops # that do not require any mutexes. # do_test mutex1-1.0 { install_mutex_counters 1 } {SQLITE_MISUSE} |
︙ | ︙ | |||
71 72 73 74 75 76 77 | do_test mutex1-1.6 { sqlite3_initialize } {SQLITE_OK} do_test mutex1-1.7 { mutex_counters counters | | | | | | 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 | do_test mutex1-1.6 { sqlite3_initialize } {SQLITE_OK} do_test mutex1-1.7 { mutex_counters counters # list $counters(total) $counters(static_main) expr {$counters(total)>0} } {1} do_test mutex1-1.8 { clear_mutex_counters sqlite3_initialize } {SQLITE_OK} do_test mutex1-1.9 { mutex_counters counters list $counters(total) $counters(static_main) } {0 0} #------------------------------------------------------------------------- # Tests mutex1-2.* test the three thread-safety related modes that # can be selected using sqlite3_config: # # * Serialized mode, # * Multi-threaded mode, # * Single-threaded mode. # ifcapable threadsafe1&&shared_cache { set enable_shared_cache [sqlite3_enable_shared_cache 1] foreach {mode mutexes} { singlethread {} multithread { fast static_app1 static_app2 static_app3 static_lru static_main static_mem static_open static_prng static_pmem static_vfs1 static_vfs2 static_vfs3 } serialized { fast recursive static_app1 static_app2 static_app3 static_lru static_main static_mem static_open static_prng static_pmem static_vfs1 static_vfs2 static_vfs3 } } { do_test mutex1.2.$mode.1 { catch {db close} |
︙ | ︙ |
Added test/noop_update.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 | # 2020 September 01 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix noop_update if {[db eval {PRAGMA noop_update}]==""} { finish_test return } do_execsql_test 1.0 { CREATE TABLE t1(x, y); INSERT INTO t1 VALUES('a', 111); } do_execsql_test 1.1 { UPDATE t1 SET y=222 WHERE x='a'; SELECT * FROM t1; } {a 222} do_execsql_test 1.2 { PRAGMA noop_update = 1; UPDATE t1 SET y=333 WHERE x='a'; SELECT * FROM t1; } {a 222} finish_test |
Changes to test/normalize.test.
︙ | ︙ | |||
343 344 345 346 347 348 349 350 351 352 353 354 355 356 | 0x2 {0 {SELECT x FROM t1 WHERE x=?;}} 760 {SELECT x FROM t1 WHERE x IN ([x] IS NOT NULL, NULL, 1, 'a', "b", x'00');} 0x2 {0 {SELECT x FROM t1 WHERE x IN(x IS NOT NULL,?,?,?,b,?);}} } { do_test $tnum { set code [catch { set STMT [sqlite3_prepare_v3 $DB $sql -1 $flags TAIL] sqlite3_normalized_sql $STMT } res] if {[info exists STMT]} { | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | 0x2 {0 {SELECT x FROM t1 WHERE x=?;}} 760 {SELECT x FROM t1 WHERE x IN ([x] IS NOT NULL, NULL, 1, 'a', "b", x'00');} 0x2 {0 {SELECT x FROM t1 WHERE x IN(x IS NOT NULL,?,?,?,b,?);}} 800 {ATTACH "normalize800.db" AS somefile;} 0x2 {0 {ATTACH"normalize800.db"AS somefile;}} 810 {ATTACH DATABASE "normalize810.db" AS somefile;} 0x2 {0 {ATTACH DATABASE"normalize810.db"AS somefile;}} 900 {INSERT INTO t1 (x) VALUES("sl1"), (1), ("sl2"), ('i');} 0x2 {0 {INSERT INTO t1(x)VALUES(?),(?),(?),(?);}} 910 {UPDATE t1 SET x = "sl1" WHERE x IN (1, "sl2", 'i');} 0x2 {0 {UPDATE t1 SET x=?WHERE x IN(?,?,?);}} 920 {UPDATE t1 SET x = "y" WHERE x IN (1, "sl1", 'i');} 0x2 {0 {UPDATE t1 SET x=y WHERE x IN(?,?,?);}} 930 {DELETE FROM t1 WHERE x IN (1, "sl1", 'i');} 0x2 {0 {DELETE FROM t1 WHERE x IN(?,?,?);}} } { do_test $tnum { set code [catch { set STMT [sqlite3_prepare_v3 $DB $sql -1 $flags TAIL] sqlite3_normalized_sql $STMT } res] if {[info exists STMT]} { |
︙ | ︙ |
Added test/notnull2.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 | # 2021 February 15 # # 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 optimizations associated with "IS NULL" # and "IS NOT NULL" operators on columns with NOT NULL constraints. # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix notnull2 do_execsql_test 1.0 { CREATE TABLE t1(a, b); CREATE TABLE t2(c, d NOT NULL); WITH x(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM x WHERE i<1000 ) INSERT INTO t1 SELECT i, i FROM x; INSERT INTO t2 SELECT * FROM t1; } proc do_vmstep_test {tn sql nstep {res {}}} { uplevel [list do_execsql_test $tn.0 $sql $res] set vmstep [db status vmstep] if {[string range $nstep 0 0]=="+"} { set body "if {$vmstep<$nstep} { error \"got $vmstep, expected more than [string range $nstep 1 end]\" }" } else { set body "if {$vmstep>$nstep} { error \"got $vmstep, expected less than $nstep\" }" } # set name "$tn.vmstep=$vmstep,expect=$nstep" set name "$tn.1" uplevel [list do_test $name $body {}] } do_vmstep_test 1.1.1 { SELECT * FROM t1 LEFT JOIN t2 WHERE a=c AND d IS NULL; } 100 {} do_vmstep_test 1.1.2 { SELECT * FROM t1 LEFT JOIN t2 WHERE a=c AND c IS NULL; } +1000 {} do_vmstep_test 1.2.1 { SELECT * FROM ( SELECT * FROM t2 ) WHERE d IS NULL } 100 {} do_vmstep_test 1.2.2 { SELECT * FROM ( SELECT * FROM t2 ) WHERE c IS NULL } +1000 {} do_vmstep_test 1.3.1 { SELECT * FROM t2 WHERE d IS NULL } 100 {} do_vmstep_test 1.3.2 { SELECT * FROM t2 WHERE c IS NULL } +1000 {} do_vmstep_test 1.4.1 { SELECT (d IS NOT NULL) FROM t2 WHERE 0==( d IS NOT NULL ) } 100 {} do_vmstep_test 1.4.2 { SELECT * FROM t2 WHERE 0==( c IS NOT NULL ) } +1000 {} do_vmstep_test 1.5.1 { SELECT count(*) FROM t2 WHERE EXISTS( SELECT t2.d IS NULL FROM t1 WHERE t1.a=450 ) } 10000 {1000} do_vmstep_test 1.5.2 { SELECT count(*) FROM t2 WHERE EXISTS( SELECT t2.c IS NULL FROM t1 WHERE t1.a=450 ) } +100000 {1000} #------------------------------------------------------------------------- reset_db do_execsql_test 2.0 { CREATE TABLE T1(a INTEGER PRIMARY KEY, b); CREATE TABLE T3(k, v); } do_execsql_test 2.1 { SELECT * FROM (SELECT a, b FROM t1) LEFT JOIN t3 ON a IS NULL; } #------------------------------------------------------------------------- reset_db do_execsql_test 3.0 { CREATE TABLE t0(c0 PRIMARY KEY); INSERT INTO t0(c0) VALUES (0); } do_execsql_test 3.1 { SELECT * FROM t0 WHERE ((c0 NOT NULL) AND 1) OR (c0 == NULL); } {0} # 2021-07-22 https://sqlite.org/forum/forumpost/2078b7edd2 # reset_db do_execsql_test 4.0 { SELECT *, '/' FROM ( SELECT NULL val FROM (SELECT 1) UNION ALL SELECT 'missing' FROM (SELECT 1) ) a LEFT JOIN (SELECT 1) ON a.val IS NULL; } {{} 1 / missing {} /} do_execsql_test 4.1 { CREATE TABLE t1(a INT); INSERT INTO t1(a) VALUES(1); CREATE TABLE t2(b INT); SELECT * FROM (SELECT 3 AS c FROM t1) AS t3 LEFT JOIN t2 ON c IS NULL; } {3 {}} finish_test |
Added test/notnullfault.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 | # 2021 February 15 # # 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 optimizations associated with "IS NULL" # and "IS NOT NULL" operators on columns with NOT NULL constraints. # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix notnullfault do_execsql_test 1.0 { CREATE TABLE t1(a, b); CREATE TABLE t2(c, d NOT NULL); } faultsim_save_and_close do_faultsim_test 1 -prep { faultsim_restore_and_reopen } -body { execsql { SELECT * FROM t2 WHERE d NOT NULL } } -test { faultsim_test_result {0 {}} } #------------------------------------------------------------------------- reset_db do_execsql_test 2.0 { CREATE TABLE t1(a, b, c); CREATE TABLE t2(a, b, c, PRIMARY KEY(a, b, c)) WITHOUT ROWID; } faultsim_save_and_close do_faultsim_test 2.1 -faults oom-t* -prep { faultsim_restore_and_reopen } -body { execsql { SELECT dense_rank() OVER win FROM t2 WINDOW win AS (ORDER BY c IS NULL) } } -test { faultsim_test_result {0 {}} } finish_test |
Changes to test/null.test.
︙ | ︙ | |||
292 293 294 295 296 297 298 299 300 | SELECT * FROM t5 WHERE a = 1 AND b IS NULL; } {1 {} one 1 {} i} do_execsql_test null-9.3 { SELECT * FROM t5 WHERE a IS NULL AND b = 'x'; } {{} x two {} x ii} finish_test | > > > > > > > | 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 | SELECT * FROM t5 WHERE a = 1 AND b IS NULL; } {1 {} one 1 {} i} do_execsql_test null-9.3 { SELECT * FROM t5 WHERE a IS NULL AND b = 'x'; } {{} x two {} x ii} # 2020-09-30 ticket 5c4e7aa793943803 reset_db do_execsql_test null-10.1 { CREATE TABLE t0(c0 PRIMARY KEY DESC); INSERT INTO t0(c0) VALUES (0); SELECT * FROM t0 WHERE t0.c0 > NULL; } {} finish_test |
Added test/nulls1.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 | # 2019 August 10 # # 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. # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix nulls1 do_execsql_test 1.0 { DROP TABLE IF EXISTS t3; CREATE TABLE t3(a INTEGER); INSERT INTO t3 VALUES(NULL), (10), (30), (20), (NULL); } {} for {set a 0} {$a < 3} {incr a} { foreach {tn limit} { 1 "" 2 "LIMIT 10" } { do_execsql_test 1.$a.$tn.1 " SELECT a FROM t3 ORDER BY a nULLS FIRST $limit " {{} {} 10 20 30} do_execsql_test 1.$a.$tn.2 " SELECT a FROM t3 ORDER BY a nULLS LAST $limit " {10 20 30 {} {}} do_execsql_test 1.$a.$tn.3 " SELECT a FROM t3 ORDER BY a DESC nULLS FIRST $limit " {{} {} 30 20 10} do_execsql_test 1.$a.$tn.4 " SELECT a FROM t3 ORDER BY a DESC nULLS LAST $limit " {30 20 10 {} {}} } switch $a { 0 { execsql { CREATE INDEX i1 ON t3(a) } } 1 { execsql { DROP INDEX i1 ; CREATE INDEX i1 ON t3(a DESC) } } } } #------------------------------------------------------------------------- reset_db do_execsql_test 2.0 { CREATE TABLE t2(a, b, c); CREATE INDEX i2 ON t2(a, b); INSERT INTO t2 VALUES(1, 1, 1); INSERT INTO t2 VALUES(1, NULL, 2); INSERT INTO t2 VALUES(1, NULL, 3); INSERT INTO t2 VALUES(1, 4, 4); } do_execsql_test 2.1 { SELECT * FROM t2 WHERE a=1 ORDER BY b NULLS LAST } { 1 1 1 1 4 4 1 {} 2 1 {} 3 } do_execsql_test 2.2 { SELECT * FROM t2 WHERE a=1 ORDER BY b DESC NULLS FIRST } { 1 {} 3 1 {} 2 1 4 4 1 1 1 } #------------------------------------------------------------------------- # reset_db do_execsql_test 3.0 { CREATE TABLE t1(a, b, c, d, UNIQUE (b)); } foreach {tn sql err} { 1 { CREATE INDEX i1 ON t1(a ASC NULLS LAST) } LAST 2 { CREATE INDEX i1 ON t1(a ASC NULLS FIRST) } FIRST 3 { CREATE INDEX i1 ON t1(a, b ASC NULLS LAST) } LAST 4 { CREATE INDEX i1 ON t1(a, b ASC NULLS FIRST) } FIRST 5 { CREATE INDEX i1 ON t1(a DESC NULLS LAST) } LAST 6 { CREATE INDEX i1 ON t1(a DESC NULLS FIRST) } FIRST 7 { CREATE INDEX i1 ON t1(a, b DESC NULLS LAST) } LAST 8 { CREATE INDEX i1 ON t1(a, b DESC NULLS FIRST) } FIRST 9 { CREATE TABLE t2(a, b, PRIMARY KEY(a DESC, b NULLS FIRST)) } FIRST 10 { CREATE TABLE t2(a, b, UNIQUE(a DESC NULLS FIRST, b)) } FIRST 11 { INSERT INTO t1 VALUES(1, 2, 3, 4) ON CONFLICT (b DESC NULLS LAST) DO UPDATE SET a = a+1 } LAST 12 { CREATE TRIGGER tr1 AFTER INSERT ON t1 BEGIN INSERT INTO t1 VALUES(1, 2, 3, 4) ON CONFLICT (b DESC NULLS FIRST) DO UPDATE SET a = a+1; END } FIRST } { do_catchsql_test 3.1.$tn $sql "1 {unsupported use of NULLS $err}" } do_execsql_test 3.2 { CREATE TABLE first(nulls, last); INSERT INTO first(last, nulls) VALUES(100,200), (300,400), (200,300); SELECT * FROM first ORDER BY nulls; } { 200 100 300 200 400 300 } #------------------------------------------------------------------------- # ifcapable vtab { register_echo_module db do_execsql_test 4.0 { CREATE TABLE tx(a INTEGER PRIMARY KEY, b, c); CREATE INDEX i1 ON tx(b); INSERT INTO tx VALUES(1, 1, 1); INSERT INTO tx VALUES(2, NULL, 2); INSERT INTO tx VALUES(3, 3, 3); INSERT INTO tx VALUES(4, NULL, 4); INSERT INTO tx VALUES(5, 5, 5); CREATE VIRTUAL TABLE te USING echo(tx); } do_execsql_test 4.1 { SELECT * FROM tx ORDER BY b NULLS FIRST; } {2 {} 2 4 {} 4 1 1 1 3 3 3 5 5 5} do_execsql_test 4.2 { SELECT * FROM te ORDER BY b NULLS FIRST; } {2 {} 2 4 {} 4 1 1 1 3 3 3 5 5 5} do_execsql_test 4.3 { SELECT * FROM tx ORDER BY b NULLS LAST; } {1 1 1 3 3 3 5 5 5 2 {} 2 4 {} 4} do_execsql_test 4.4 { SELECT * FROM te ORDER BY b NULLS LAST; } {1 1 1 3 3 3 5 5 5 2 {} 2 4 {} 4} } #------------------------------------------------------------------------- # do_execsql_test 5.0 { CREATE TABLE t4(a, b, c); INSERT INTO t4 VALUES(1, 1, 11); INSERT INTO t4 VALUES(1, 2, 12); INSERT INTO t4 VALUES(1, NULL, 1); INSERT INTO t4 VALUES(2, NULL, 1); INSERT INTO t4 VALUES(2, 2, 12); INSERT INTO t4 VALUES(2, 1, 11); INSERT INTO t4 VALUES(3, NULL, 1); INSERT INTO t4 VALUES(3, 2, 12); INSERT INTO t4 VALUES(3, NULL, 3); } do_execsql_test 5.1 { SELECT * FROM t4 WHERE a IN (1, 2, 3) ORDER BY a, b NULLS LAST } { 1 1 11 1 2 12 1 {} 1 2 1 11 2 2 12 2 {} 1 3 2 12 3 {} 1 3 {} 3 } do_execsql_test 5.2 { CREATE INDEX t4ab ON t4(a, b); SELECT * FROM t4 WHERE a IN (1, 2, 3) ORDER BY a, b NULLS LAST } { 1 1 11 1 2 12 1 {} 1 2 1 11 2 2 12 2 {} 1 3 2 12 3 {} 1 3 {} 3 } do_eqp_test 5.3 { SELECT * FROM t4 WHERE a IN (1, 2, 3) ORDER BY a, b NULLS LAST } { QUERY PLAN `--SEARCH t4 USING INDEX t4ab (a=?) } do_execsql_test 5.4 { SELECT * FROM t4 WHERE a IN (1, 2, 3) ORDER BY a DESC, b DESC NULLS FIRST } { 3 {} 3 3 {} 1 3 2 12 2 {} 1 2 2 12 2 1 11 1 {} 1 1 2 12 1 1 11 } do_eqp_test 5.5 { SELECT * FROM t4 WHERE a IN (1, 2, 3) ORDER BY a DESC, b DESC NULLS FIRST } { QUERY PLAN `--SEARCH t4 USING INDEX t4ab (a=?) } #------------------------------------------------------------------------- # do_execsql_test 6.0 { CREATE TABLE t5(a, b, c); WITH s(i) AS ( VALUES(1) UNION ALL SELECT i+1 FROM s WHERE i<200 ) INSERT INTO t5 SELECT i%2, CASE WHEN (i%10)==0 THEN NULL ELSE i END, i FROM s; } set res1 [db eval { SELECT a,b FROM t5 WHERE a=1 ORDER BY b NULLS LAST, c }] set res2 [db eval { SELECT a,b FROM t5 WHERE a=1 ORDER BY b DESC NULLS FIRST, c DESC }] do_execsql_test 6.1.1 { CREATE INDEX t5ab ON t5(a, b, c); SELECT a,b FROM t5 WHERE a=1 ORDER BY b NULLS LAST, c; } $res1 do_eqp_test 6.1.2 { SELECT a,b FROM t5 WHERE a=1 ORDER BY b NULLS LAST, c; } { QUERY PLAN `--SEARCH t5 USING COVERING INDEX t5ab (a=?) } do_execsql_test 6.2.1 { SELECT a,b FROM t5 WHERE a=1 ORDER BY b DESC NULLS FIRST, c DESC } $res2 do_eqp_test 6.2.2 { SELECT a,b FROM t5 WHERE a=1 ORDER BY b DESC NULLS FIRST, c DESC } { QUERY PLAN `--SEARCH t5 USING COVERING INDEX t5ab (a=?) } #------------------------------------------------------------------------- do_execsql_test 7.0 { CREATE TABLE t71(a, b, c); CREATE INDEX t71abc ON t71(a, b, c); SELECT * FROM t71 WHERE a=1 AND b=2 ORDER BY c NULLS LAST; SELECT * FROM t71 WHERE a=1 AND b=2 ORDER BY c DESC NULLS FIRST; SELECT * FROM t71 ORDER BY a NULLS LAST; SELECT * FROM t71 ORDER BY a DESC NULLS FIRST; } # 2019-12-18 gramfuzz1 find # NULLS LAST not allows on an INTEGER PRIMARY KEY. # do_catchsql_test 8.0 { CREATE TABLE t80(a, b INTEGER, PRIMARY KEY(b NULLS LAST)) WITHOUT ROWID; } {1 {unsupported use of NULLS LAST}} #------------------------------------------------------------------------- reset_db do_execsql_test 9.0 { CREATE TABLE v0 (c1, c2, c3); CREATE INDEX v3 ON v0 (c1, c2, c3); } do_execsql_test 9.1 { ANALYZE sqlite_master; INSERT INTO sqlite_stat1 VALUES('v0','v3','648 324 81'); ANALYZE sqlite_master; } do_execsql_test 9.2 { INSERT INTO v0 VALUES (1, 10, 'b'), (1, 10, 'd'), (1, 10, NULL), (2, 10, 'a'), (2, 10, NULL), (1, 10, 'c'), (2, 10, 'b'), (1, 10, 'a'), (1, 10, NULL), (2, 10, NULL), (2, 10, 'd'), (2, 10, 'c'); } do_execsql_test 9.3 { SELECT c1, c2, ifnull(c3, 'NULL') FROM v0 WHERE c2=10 ORDER BY c1, c3 NULLS LAST } { 1 10 a 1 10 b 1 10 c 1 10 d 1 10 NULL 1 10 NULL 2 10 a 2 10 b 2 10 c 2 10 d 2 10 NULL 2 10 NULL } do_eqp_test 9.4 { SELECT c1, c2, ifnull(c3, 'NULL') FROM v0 WHERE c2=10 ORDER BY c1, c3 NULLS LAST } {SEARCH v0 USING COVERING INDEX v3 (ANY(c1) AND c2=?)} # 2020-03-01 ticket e12a0ae526bb51c7 # NULLS LAST on a LEFT JOIN # reset_db do_execsql_test 10.10 { CREATE TABLE t1(x); INSERT INTO t1(x) VALUES('X'); CREATE TABLE t2(c, d); CREATE INDEX t2dc ON t2(d, c); SELECT c FROM t1 LEFT JOIN t2 ON d=NULL ORDER BY d, c NULLS LAST; } {{}} do_execsql_test 10.20 { INSERT INTO t2(c,d) VALUES(5,'X'),(6,'Y'),(7,'Z'),(3,'A'),(4,'B'); SELECT c FROM t1 LEFT JOIN t2 ON d=x ORDER BY d, c NULLS LAST; } {5} do_execsql_test 10.30 { UPDATE t2 SET d='X'; UPDATE t2 SET c=NULL WHERE c=6; SELECT c FROM t1 LEFT JOIN t2 ON d=x ORDER BY d NULLS FIRST, c NULLS FIRST; } {{} 3 4 5 7} do_execsql_test 10.40 { SELECT c FROM t1 LEFT JOIN t2 ON d=x ORDER BY d NULLS LAST, c NULLS LAST; } {3 4 5 7 {}} do_execsql_test 10.41 { SELECT c FROM t1 LEFT JOIN t2 ON d=x ORDER BY c NULLS LAST; } {3 4 5 7 {}} do_execsql_test 10.42 { SELECT c FROM t1 LEFT JOIN t2 ON d=x ORDER BY +d NULLS LAST, +c NULLS LAST; } {3 4 5 7 {}} do_execsql_test 10.50 { INSERT INTO t1(x) VALUES(NULL),('Y'); SELECT x, c, d, '|' FROM t1 LEFT JOIN t2 ON d=x ORDER BY d NULLS LAST, c NULLS LAST; } {X 3 X | X 4 X | X 5 X | X 7 X | X {} X | {} {} {} | Y {} {} |} do_execsql_test 10.51 { SELECT x, c, d, '|' FROM t1 LEFT JOIN t2 ON d=x ORDER BY +d NULLS LAST, +c NULLS LAST; } {X 3 X | X 4 X | X 5 X | X 7 X | X {} X | {} {} {} | Y {} {} |} finish_test |
Changes to test/optfuzz-db01.c.
︙ | ︙ | |||
941 942 943 944 945 946 947 | 41, 32, 85, 78, 73, 79, 78, 32, 65, 76, 76, 32, 83, 69, 76, 69, 67, 84, 32, 120, 43, 49, 32, 70, 82, 79, 77, 32, 99, 48, 32, 87, 72, 69, 82, 69, 32,120, 60, 57, 41, 10, 32, 32, 83, 69, 76, 69, 67, 84, 32,120, 44, 32, 98, 44, 32, 99, 44, 32,100, 44, 32,101, 32, 70, 82, 79, 77, 32, 99, 48, 32, 74, 79, 73, 78, 32,116, 49, 32, 79, 78, 32, 40,116, 49, 46, 97, 61, 53, 48, 45, 99, 48, 46,120, 41, }; | < | 941 942 943 944 945 946 947 | 41, 32, 85, 78, 73, 79, 78, 32, 65, 76, 76, 32, 83, 69, 76, 69, 67, 84, 32, 120, 43, 49, 32, 70, 82, 79, 77, 32, 99, 48, 32, 87, 72, 69, 82, 69, 32,120, 60, 57, 41, 10, 32, 32, 83, 69, 76, 69, 67, 84, 32,120, 44, 32, 98, 44, 32, 99, 44, 32,100, 44, 32,101, 32, 70, 82, 79, 77, 32, 99, 48, 32, 74, 79, 73, 78, 32,116, 49, 32, 79, 78, 32, 40,116, 49, 46, 97, 61, 53, 48, 45, 99, 48, 46,120, 41, }; |
Changes to test/optfuzz.c.
︙ | ︙ | |||
22 23 24 25 26 27 28 | ** is printed and the program returns non-zero. */ /* Include the SQLite amalgamation, after making appropriate #defines. */ #define SQLITE_THREADSAFE 0 #define SQLITE_OMIT_LOAD_EXTENSION 1 | < | 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | ** is printed and the program returns non-zero. */ /* Include the SQLite amalgamation, after making appropriate #defines. */ #define SQLITE_THREADSAFE 0 #define SQLITE_OMIT_LOAD_EXTENSION 1 #include "sqlite3.c" /* Content of the read-only test database */ #include "optfuzz-db01.c" /* ** Prepare a single SQL statement. Panic if anything goes wrong |
︙ | ︙ |
Changes to test/orderby1.test.
︙ | ︙ | |||
512 513 514 515 516 517 518 | CREATE INDEX i1 ON t1(a); } do_eqp_test 8.1 { SELECT * FROM t1 ORDER BY a, b; } { QUERY PLAN | | | 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 | CREATE INDEX i1 ON t1(a); } do_eqp_test 8.1 { SELECT * FROM t1 ORDER BY a, b; } { QUERY PLAN |--SCAN t1 USING INDEX i1 `--USE TEMP B-TREE FOR RIGHT PART OF ORDER BY } do_execsql_test 8.2 { WITH cnt(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM cnt WHERE i<10000 ) |
︙ | ︙ | |||
554 555 556 557 558 559 560 561 562 | do_execsql_test 10.0 { CREATE TABLE t10(a,b); INSERT INTO t10 VALUES(1,2),(8,9),(3,4),(5,4),(0,7); CREATE INDEX t10b ON t10(b); SELECT b, rowid, '^' FROM t10 ORDER BY b, a LIMIT 4; } {2 1 ^ 4 3 ^ 4 4 ^ 7 5 ^} finish_test | > > > > | 554 555 556 557 558 559 560 561 562 563 564 565 566 | do_execsql_test 10.0 { CREATE TABLE t10(a,b); INSERT INTO t10 VALUES(1,2),(8,9),(3,4),(5,4),(0,7); CREATE INDEX t10b ON t10(b); SELECT b, rowid, '^' FROM t10 ORDER BY b, a LIMIT 4; } {2 1 ^ 4 3 ^ 4 4 ^ 7 5 ^} do_catchsql_test 11.0 { VALUES(2) EXCEPT SELECT '' ORDER BY abc } {1 {1st ORDER BY term does not match any column in the result set}} finish_test |
Changes to test/orderby5.test.
︙ | ︙ | |||
122 123 124 125 126 127 128 129 130 | DROP TABLE t3; CREATE TABLE t3(a INTEGER PRIMARY KEY, b, c, d, e, f) WITHOUT rowid; CREATE INDEX t3bcde ON t3(b, c, d, e); EXPLAIN QUERY PLAN SELECT a FROM t3 WHERE b=2 AND c=3 ORDER BY d DESC, e DESC, b, c, a DESC; } {~/B-TREE/} finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | DROP TABLE t3; CREATE TABLE t3(a INTEGER PRIMARY KEY, b, c, d, e, f) WITHOUT rowid; CREATE INDEX t3bcde ON t3(b, c, d, e); EXPLAIN QUERY PLAN SELECT a FROM t3 WHERE b=2 AND c=3 ORDER BY d DESC, e DESC, b, c, a DESC; } {~/B-TREE/} #------------------------------------------------------------------------- do_execsql_test 4.1.0 { CREATE TABLE t4(b COLLATE nocase); INSERT INTO t4 VALUES('abc'); INSERT INTO t4 VALUES('ABC'); INSERT INTO t4 VALUES('aBC'); } do_execsql_test 4.1.1 { SELECT * FROM t4 ORDER BY b COLLATE binary } {ABC aBC abc} do_execsql_test 4.1.2 { SELECT * FROM t4 WHERE b='abc' ORDER BY b COLLATE binary } {ABC aBC abc} do_execsql_test 4.2.1 { CREATE TABLE Records(typeID INTEGER, key TEXT COLLATE nocase, value TEXT); CREATE INDEX RecordsIndex ON Records(typeID, key, value); } do_execsql_test 4.2.2 { explain query plan SELECT typeID, key, value FROM Records WHERE typeID = 2 AND key = 'x' ORDER BY key, value; } {~/TEMP B-TREE/} do_execsql_test 4.2.3 { explain query plan SELECT typeID, key, value FROM Records WHERE typeID = 2 AND (key = 'x' COLLATE binary) ORDER BY key, value; } {~/TEMP B-TREE/} do_execsql_test 4.2.4 { explain query plan SELECT typeID, key, value FROM Records WHERE typeID = 2 ORDER BY key, value; } {~/TEMP B-TREE/} db collate hello [list string match] do_execsql_test 4.3.1 { CREATE TABLE t5(a INTEGER PRIMARY KEY, b COLLATE hello, c, d); } db close sqlite3 db test.db do_catchsql_test 4.3.2 { SELECT a FROM t5 WHERE b='def' ORDER BY b; } {1 {no such collation sequence: hello}} # 2020-02-13 ticket 41c1456a6e61c0e7 do_execsql_test 4.4.0 { DROP TABLE t1; CREATE TABLE t1(a); DROP TABLE t2; CREATE TABLE t2(b INTEGER PRIMARY KEY, c INT); SELECT DISTINCT * FROM t1 LEFT JOIN t2 ON b=c AND b=(SELECT a FROM t1) WHERE c>10; } {} finish_test |
Added test/orderbyA.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 | # 2019-09-21 # # 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 cases where the expressions in a GROUP BY # clause are the same as those in the ORDER BY clause. # set testdir [file dirname $argv0] source $testdir/tester.tcl set ::testprefix orderbyA proc do_sortcount_test {tn sql cnt res} { set eqp [execsql "EXPLAIN QUERY PLAN $sql"] set rcnt [regexp -all {USE TEMP} $eqp] uplevel [list do_test $tn.1 [list set {} $rcnt] $cnt] uplevel [list do_execsql_test $tn.2 $sql $res] } do_execsql_test 1.0 { CREATE TABLE t1(a, b, c); INSERT INTO t1 VALUES('one', 1, 11); INSERT INTO t1 VALUES('three', 7, 11); INSERT INTO t1 VALUES('one', 2, 11); INSERT INTO t1 VALUES('one', 3, 11); INSERT INTO t1 VALUES('two', 4, 11); INSERT INTO t1 VALUES('two', 6, 11); INSERT INTO t1 VALUES('three', 8, 11); INSERT INTO t1 VALUES('two', 5, 11); INSERT INTO t1 VALUES('three', 9, 11); } foreach {tn idx} { 1 {} 2 {CREATE INDEX i1 ON t1(a)} 3 {CREATE INDEX i1 ON t1(a DESC)} } { execsql { DROP INDEX IF EXISTS i1 } execsql $idx # $match is the number of temp-table sorts we expect if the GROUP BY # can use the same sort order as the ORDER BY. $nomatch is the number # of expected sorts if the GROUP BY and ORDER BY are not compatible. set match 1 set nomatch 2 if {$tn>=2} { set match 0 set nomatch 1 } do_sortcount_test 1.$tn.1.1 { SELECT a, sum(b) FROM t1 GROUP BY a ORDER BY a } $match {one 6 three 24 two 15} do_sortcount_test 1.$tn.1.2 { SELECT a, sum(b) FROM t1 GROUP BY a ORDER BY a DESC } $match {two 15 three 24 one 6} do_sortcount_test 1.$tn.2.1 { SELECT a, sum(b) FROM t1 GROUP BY a ORDER BY a||'' } $nomatch {one 6 three 24 two 15} do_sortcount_test 1.$tn.2.2 { SELECT a, sum(b) FROM t1 GROUP BY a ORDER BY a||'' DESC } $nomatch {two 15 three 24 one 6} do_sortcount_test 1.$tn.3.1 { SELECT a, sum(b) FROM t1 GROUP BY a ORDER BY a NULLS LAST } $nomatch {one 6 three 24 two 15} do_sortcount_test 1.$tn.3.2 { SELECT a, sum(b) FROM t1 GROUP BY a ORDER BY a DESC NULLS FIRST } $nomatch {two 15 three 24 one 6} } #------------------------------------------------------------------------- do_execsql_test 2.0 { CREATE TABLE t2(a, b, c); INSERT INTO t2 VALUES(1, 'one', 1); INSERT INTO t2 VALUES(1, 'two', 2); INSERT INTO t2 VALUES(1, 'one', 3); INSERT INTO t2 VALUES(1, 'two', 4); INSERT INTO t2 VALUES(1, 'one', 5); INSERT INTO t2 VALUES(1, 'two', 6); INSERT INTO t2 VALUES(2, 'one', 7); INSERT INTO t2 VALUES(2, 'two', 8); INSERT INTO t2 VALUES(2, 'one', 9); INSERT INTO t2 VALUES(2, 'two', 10); INSERT INTO t2 VALUES(2, 'one', 11); INSERT INTO t2 VALUES(2, 'two', 12); INSERT INTO t2 VALUES(NULL, 'one', 13); INSERT INTO t2 VALUES(NULL, 'two', 14); INSERT INTO t2 VALUES(NULL, 'one', 15); INSERT INTO t2 VALUES(NULL, 'two', 16); INSERT INTO t2 VALUES(NULL, 'one', 17); INSERT INTO t2 VALUES(NULL, 'two', 18); } foreach {tn idx} { 1 {} 2 { CREATE INDEX i2 ON t2(a, b) } 3 { CREATE INDEX i2 ON t2(a DESC, b DESC) } 4 { CREATE INDEX i2 ON t2(a, b DESC) } 5 { CREATE INDEX i2 ON t2(a DESC, b) } } { execsql { DROP INDEX IF EXISTS i2 } execsql $idx set nSort [expr ($tn==2 || $tn==3) ? 0 : 1] do_sortcount_test 2.$tn.1.1 { SELECT a, b, sum(c) FROM t2 GROUP BY a, b ORDER BY a, b; } $nSort {{} one 45 {} two 48 1 one 9 1 two 12 2 one 27 2 two 30} do_sortcount_test 2.$tn.1.2 { SELECT a, b, sum(c) FROM t2 GROUP BY a, b ORDER BY a DESC, b DESC; } $nSort {2 two 30 2 one 27 1 two 12 1 one 9 {} two 48 {} one 45} set nSort [expr ($tn==4 || $tn==5) ? 0 : 1] do_sortcount_test 2.$tn.2.1 { SELECT a, b, sum(c) FROM t2 GROUP BY a, b ORDER BY a, b DESC; } $nSort { {} two 48 {} one 45 1 two 12 1 one 9 2 two 30 2 one 27 } do_sortcount_test 2.$tn.2.2 { SELECT a, b, sum(c) FROM t2 GROUP BY a, b ORDER BY a DESC, b; } $nSort { 2 one 27 2 two 30 1 one 9 1 two 12 {} one 45 {} two 48 } # ORDER BY can never piggyback on the GROUP BY sort if it uses # non-standard NULLS behaviour. set nSort [expr $tn==1 ? 2 : 1] do_sortcount_test 2.$tn.3.1 { SELECT a, b, sum(c) FROM t2 GROUP BY a, b ORDER BY a, b DESC NULLS FIRST; } $nSort { {} two 48 {} one 45 1 two 12 1 one 9 2 two 30 2 one 27 } do_sortcount_test 2.$tn.3.2 { SELECT a, b, sum(c) FROM t2 GROUP BY a, b ORDER BY a DESC, b NULLS LAST; } $nSort { 2 one 27 2 two 30 1 one 9 1 two 12 {} one 45 {} two 48 } } finish_test |
Changes to test/oserror.test.
︙ | ︙ | |||
48 49 50 51 52 53 54 55 56 | # # The xOpen() method of the unix VFS calls getcwd() as well as open(). # Although this does not appear to be documented in the man page, on OSX # a call to getcwd() may fail if there are no free file descriptors. So # an error may be reported for either open() or getcwd() here. # if {![clang_sanitize_address]} { do_test 1.1.1 { set ::log [list] | > > > | | | > > > > | > > > > > | > | | | | > | 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 | # # The xOpen() method of the unix VFS calls getcwd() as well as open(). # Although this does not appear to be documented in the man page, on OSX # a call to getcwd() may fail if there are no free file descriptors. So # an error may be reported for either open() or getcwd() here. # if {![clang_sanitize_address]} { unset -nocomplain rc unset -nocomplain nOpen set nOpen 20000 do_test 1.1.1 { set ::log [list] set ::rc [catch { for {set i 0} {$i < $::nOpen} {incr i} { sqlite3 dbh_$i test.db -readonly 1 } } msg] if {$::rc==0} { # Some system (ex: Debian) are able to create 20000+ file descriptiors # such systems will not fail here set x ok } elseif {$::rc==1 && $msg=="unable to open database file"} { set x ok } else { set x [list $::rc $msg] } } {ok} do_test 1.1.2 { catch { for {set i 0} {$i < $::nOpen} {incr i} { dbh_$i close } } } $::rc if {$rc} { do_re_test 1.1.3 { lindex $::log 0 } {^os_unix.c:\d+: \(\d+\) (open|getcwd)\(.*test.db\) - } } } # Test a failure in open() due to the path being a directory. # do_test 1.2.1 { file mkdir dir.db |
︙ | ︙ |
Changes to test/ossfuzz.c.
︙ | ︙ | |||
150 151 152 153 154 155 156 157 158 159 160 161 162 163 | cx.iCutoffTime = cx.iLastCb + 10000; /* Now + 10 seconds */ #ifndef SQLITE_OMIT_PROGRESS_CALLBACK sqlite3_progress_handler(cx.db, 10, progress_handler, (void*)&cx); #endif /* Set a limit on the maximum size of a prepared statement */ sqlite3_limit(cx.db, SQLITE_LIMIT_VDBE_OP, 25000); /* Bit 1 of the selector enables foreign key constraints */ sqlite3_db_config(cx.db, SQLITE_DBCONFIG_ENABLE_FKEY, uSelector&1, &rc); uSelector >>= 1; /* Do not allow debugging pragma statements that might cause excess output */ sqlite3_set_authorizer(cx.db, block_debug_pragmas, 0); | > > > > > > > > | 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 | cx.iCutoffTime = cx.iLastCb + 10000; /* Now + 10 seconds */ #ifndef SQLITE_OMIT_PROGRESS_CALLBACK sqlite3_progress_handler(cx.db, 10, progress_handler, (void*)&cx); #endif /* Set a limit on the maximum size of a prepared statement */ sqlite3_limit(cx.db, SQLITE_LIMIT_VDBE_OP, 25000); /* Limit total memory available to SQLite to 20MB */ sqlite3_hard_heap_limit64(20000000); /* Set a limit on the maximum length of a string or BLOB. Without this ** limit, fuzzers will invoke randomblob(N) for a large N, and the process ** will timeout trying to generate the huge blob */ sqlite3_limit(cx.db, SQLITE_LIMIT_LENGTH, 50000); /* Bit 1 of the selector enables foreign key constraints */ sqlite3_db_config(cx.db, SQLITE_DBCONFIG_ENABLE_FKEY, uSelector&1, &rc); uSelector >>= 1; /* Do not allow debugging pragma statements that might cause excess output */ sqlite3_set_authorizer(cx.db, block_debug_pragmas, 0); |
︙ | ︙ |
Changes to test/pager1.test.
︙ | ︙ | |||
17 18 19 20 21 22 23 24 25 26 27 28 29 30 | source $testdir/wal_common.tcl set testprefix pager1 if {[atomic_batch_write test.db]} { finish_test return } # Do not use a codec for tests in this file, as the database file is # manipulated directly using tcl scripts (using the [hexio_write] command). # do_not_use_codec # | > > > > | 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | source $testdir/wal_common.tcl set testprefix pager1 if {[atomic_batch_write test.db]} { finish_test return } ifcapable !incrblob { finish_test return } # Do not use a codec for tests in this file, as the database file is # manipulated directly using tcl scripts (using the [hexio_write] command). # do_not_use_codec # |
︙ | ︙ | |||
272 273 274 275 276 277 278 | INSERT INTO t1 VALUES(1, randomblob(1500)); INSERT INTO t1 VALUES(2, randomblob(1500)); INSERT INTO t1 VALUES(3, randomblob(1500)); SELECT * FROM counter; } {3 0} do_catchsql_test pager1-3.1.3 { INSERT INTO t1 SELECT a+3, randomblob(1500) FROM t1 | | | 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 | INSERT INTO t1 VALUES(1, randomblob(1500)); INSERT INTO t1 VALUES(2, randomblob(1500)); INSERT INTO t1 VALUES(3, randomblob(1500)); SELECT * FROM counter; } {3 0} do_catchsql_test pager1-3.1.3 { INSERT INTO t1 SELECT a+3, randomblob(1500) FROM t1 } {1 {CHECK constraint failed: i<5}} do_execsql_test pager1-3.4 { SELECT * FROM counter } {3 0} do_execsql_test pager1-3.5 { SELECT a FROM t1 } {1 2 3} do_execsql_test pager1-3.6 { COMMIT } {} foreach {tn sql tcl} { 7 { PRAGMA synchronous = NORMAL ; PRAGMA temp_store = 0 } { testvfs tv -default 1 |
︙ | ︙ | |||
1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 | db close tv delete #------------------------------------------------------------------------- # Test specal "PRAGMA journal_mode=OFF" test cases. # faultsim_delete_and_reopen do_execsql_test pager1-14.1.1 { PRAGMA journal_mode = OFF; CREATE TABLE t1(a, b); BEGIN; INSERT INTO t1 VALUES(1, 2); COMMIT; | > > > > > > | 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 | db close tv delete #------------------------------------------------------------------------- # Test specal "PRAGMA journal_mode=OFF" test cases. # # Do not run these tests for SQLITE_ENABLE_ZIPVFS builds. Such builds # cause the pager to enter the error state if a statement transaction # cannot be rolled back due to a prior "PRAGMA journal_mode=OFF". Which # causes these tests to fail. # if {[info commands zip_register]==""} { faultsim_delete_and_reopen do_execsql_test pager1-14.1.1 { PRAGMA journal_mode = OFF; CREATE TABLE t1(a, b); BEGIN; INSERT INTO t1 VALUES(1, 2); COMMIT; |
︙ | ︙ | |||
1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 | do_catchsql_test pager1-14.1.4 { BEGIN; INSERT INTO t1(rowid, a, b) SELECT a+3, b, b FROM t1; INSERT INTO t1(rowid, a, b) SELECT a+3, b, b FROM t1; } {1 {UNIQUE constraint failed: t1.rowid}} do_execsql_test pager1-14.1.5 { COMMIT; SELECT * FROM t1; } {1 2 2 2} #------------------------------------------------------------------------- # Test opening and closing the pager sub-system with different values # for the sqlite3_vfs.szOsFile variable. # faultsim_delete_and_reopen do_execsql_test pager1-15.0 { | > > > | 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 | do_catchsql_test pager1-14.1.4 { BEGIN; INSERT INTO t1(rowid, a, b) SELECT a+3, b, b FROM t1; INSERT INTO t1(rowid, a, b) SELECT a+3, b, b FROM t1; } {1 {UNIQUE constraint failed: t1.rowid}} do_execsql_test pager1-14.1.5 { COMMIT; } do_execsql_test pager1-14.1.6 { SELECT * FROM t1; } {1 2 2 2} } #------------------------------------------------------------------------- # Test opening and closing the pager sub-system with different values # for the sqlite3_vfs.szOsFile variable. # faultsim_delete_and_reopen do_execsql_test pager1-15.0 { |
︙ | ︙ | |||
1926 1927 1928 1929 1930 1931 1932 | db2 close do_test pager1-18.4 { hexio_write test.db [expr ($pgno-1)*1024] 90000000 sqlite3 db2 test.db catchsql { SELECT length(x||'') FROM t2 } db2 } {1 {database disk image is malformed}} db2 close | > > | | | | | | | | | | | | | | > > | 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 | db2 close do_test pager1-18.4 { hexio_write test.db [expr ($pgno-1)*1024] 90000000 sqlite3 db2 test.db catchsql { SELECT length(x||'') FROM t2 } db2 } {1 {database disk image is malformed}} db2 close extra_schema_checks 0 ifcapable altertable { do_test pager1-18.5 { sqlite3 db "" sqlite3_db_config db DEFENSIVE 0 execsql { CREATE TABLE t1(a, b); CREATE TABLE t2(a, b); PRAGMA writable_schema = 1; UPDATE sqlite_master SET rootpage=5 WHERE tbl_name = 't1'; PRAGMA writable_schema = 0; ALTER TABLE t1 RENAME TO x1; } catchsql { SELECT * FROM x1 } } {1 {database disk image is malformed}} db close } extra_schema_checks 1 do_test pager1-18.6 { faultsim_delete_and_reopen db func a_string a_string execsql { PRAGMA page_size = 1024; CREATE TABLE t1(x); |
︙ | ︙ |
Changes to test/permutations.test.
︙ | ︙ | |||
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 | vtab_err.test walslow.test walcrash.test walcrash3.test walthread.test rtree3.test indexfault.test securedel2.test sort3.test sort4.test fts4growth.test fts4growth2.test bigsort.test walprotocol.test mmap4.test fuzzer2.test walcrash2.test e_fkey.test backup.test fts4merge.test fts4merge2.test fts4merge4.test fts4check.test fts3cov.test fts3snippet.test fts3corrupt2.test fts3an.test fts3defer.test fts4langid.test fts3sort.test fts5unicode.test rtree4.test }] if {[info exists ::env(QUICKTEST_INCLUDE)]} { set allquicktests [concat $allquicktests $::env(QUICKTEST_INCLUDE)] } if {[info exists ::env(QUICKTEST_OMIT)]} { | > > > > > > > > > | > > > > > > | | > > | 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 | vtab_err.test walslow.test walcrash.test walcrash3.test walthread.test rtree3.test indexfault.test securedel2.test sort3.test sort4.test fts4growth.test fts4growth2.test bigsort.test walprotocol.test mmap4.test fuzzer2.test walcrash2.test e_fkey.test backup.test fts4merge.test fts4merge2.test fts4merge4.test fts4check.test fts4merge5.test fts3cov.test fts3snippet.test fts3corrupt2.test fts3an.test fts3defer.test fts4langid.test fts3sort.test fts5unicode.test rtree4.test sessionbig.test }] if {[info exists ::env(QUICKTEST_INCLUDE)]} { set allquicktests [concat $allquicktests $::env(QUICKTEST_INCLUDE)] } if {[info exists ::env(QUICKTEST_OMIT)]} { # If environment variable QUICKTEST_OMIT is set, it is a comma-separated # list of regular expressions to match against test file names in # the "allquicktests" set. Any matches are excluded. Only the filename # is matched, not any directory component of the path. set all [list] foreach a $allquicktests { set bIn 1 foreach x [split $::env(QUICKTEST_OMIT) ,] { if {[regexp $x [file tail $a]]} { set bIn 0 break } } if {$bIn} { lappend all $a } } set allquicktests $all } # If the TEST_FAILURE environment variable is set, it means that we what to # deliberately provoke test failures in order to test the test infrastructure. # Only the main.test module is needed for this. # if {[info exists ::env(TEST_FAILURE)]} { |
︙ | ︙ | |||
165 166 167 168 169 170 171 172 173 174 175 176 177 178 | "Very" quick test suite. Runs in 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* *bigfile* *_err* \ *fts5corrupt* *fts5big* *fts5aj* ] test_suite "extraquick" -prefix "" -description { "Extra" quick test suite. Runs in a few minutes on a workstation. This test suite is the same as the "veryquick" tests, except that slower tests are omitted. } -files [ test_set $allquicktests -exclude *malloc* *ioerr* *fault* *bigfile* *_err* \ | > > > > > > | 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 | "Very" quick test suite. Runs in 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* *bigfile* *_err* \ *fts5corrupt* *fts5big* *fts5aj* ] test_suite "shell" -prefix "" -description { Run tests of the command-line shell } -files [ test_set [glob $testdir/shell*.test] ] test_suite "extraquick" -prefix "" -description { "Extra" quick test suite. Runs in a few minutes on a workstation. This test suite is the same as the "veryquick" tests, except that slower tests are omitted. } -files [ test_set $allquicktests -exclude *malloc* *ioerr* *fault* *bigfile* *_err* \ |
︙ | ︙ | |||
426 427 428 429 430 431 432 | # Define the coverage related test suites: # # coverage-wal # test_suite "coverage-wal" -description { Coverage tests for file wal.c. } -files { | | > | > > > > | | > > > | | | 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 | # Define the coverage related test suites: # # coverage-wal # test_suite "coverage-wal" -description { Coverage tests for file wal.c. } -files { wal.test wal2.test wal3.test wal4.test wal5.test wal64k.test wal6.test wal7.test wal8.test wal9.test walbak.test walbig.test walblock.test walcksum.test walcrash2.test walcrash3.test walcrash4.test walcrash.test walfault.test walhook.test walmode.test walnoshm.test waloverwrite.test walpersist.test walprotocol2.test walprotocol.test walro2.test walrofault.test walro.test walshared.test walslow.test walvfs.test walfault2.test nockpt.test snapshot2.test snapshot3.test snapshot4.test snapshot_fault.test snapshot.test snapshot_up.test } test_suite "coverage-pager" -description { Coverage tests for file pager.c. } -files { pager1.test pager2.test pagerfault.test pagerfault2.test walfault.test walbak.test journal2.test tkt-9d68c883.test } test_suite "coverage-analyze" -description { Coverage tests for file analyze.c. } -files { analyze3.test analyze4.test analyze5.test analyze6.test analyze7.test analyze8.test analyze9.test analyze.test mallocA.test } test_suite "coverage-sorter" -description { Coverage tests for file vdbesort.c. } -files { sort.test sortfault.test } |
︙ | ︙ | |||
612 613 614 615 616 617 618 | test_suite "utf16" -description { Run tests using UTF-16 databases } -presql { pragma encoding = 'UTF-16' } -files { alter.test alter3.test analyze.test analyze3.test analyze4.test analyze5.test analyze6.test | | | 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 | test_suite "utf16" -description { Run tests using UTF-16 databases } -presql { pragma encoding = 'UTF-16' } -files { alter.test alter3.test analyze.test analyze3.test analyze4.test analyze5.test analyze6.test analyze7.test analyze8.test analyze9.test auth.test bind.test blob.test capi2.test capi3.test collate1.test collate2.test collate3.test collate4.test collate5.test collate6.test conflict.test date.test delete.test expr.test fkey1.test func.test hook.test index.test insert2.test insert.test interrupt.test in.test intpkey.test ioerr.test join2.test join.test lastinsert.test laststmtchanges.test limit.test lock2.test lock.test main.test memdb.test minmax.test misc1.test misc2.test misc3.test notnull.test |
︙ | ︙ | |||
740 741 742 743 744 745 746 | e_fts3.test fts3cov.test fts3malloc.test fts3rnd.test fts3snippet.test mmapfault.test sessionfault.test sessionfault2.test # Exclude test scripts that use tcl IO to access journal files or count # the number of fsync() calls. pager.test exclusive.test jrnlmode.test sync.test misc1.test journal1.test conflict.test crash8.test tkt3457.test io.test | | | 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 | e_fts3.test fts3cov.test fts3malloc.test fts3rnd.test fts3snippet.test mmapfault.test sessionfault.test sessionfault2.test # Exclude test scripts that use tcl IO to access journal files or count # the number of fsync() calls. pager.test exclusive.test jrnlmode.test sync.test misc1.test journal1.test conflict.test crash8.test tkt3457.test io.test journal3.test 8_3_names.test shmlock.test pager1.test async4.test corrupt.test filefmt.test pager2.test corrupt5.test corruptA.test pageropt.test # Exclude stmt.test, which expects sub-journals to use temporary files. stmt.test symlink.test |
︙ | ︙ | |||
954 955 956 957 958 959 960 | } -shutdown { unregister_jt_vfs } -files [test_set $::allquicktests -exclude { wal* incrvacuum.test ioerr.test corrupt4.test io.test crash8.test async4.test bigfile.test backcompat.test e_wal* fstat.test mmap2.test pager1.test syscall.test tkt3457.test *malloc* mmap* multiplex* nolock* pager2.test *fault* rowal* snapshot* superlock* symlink.test | | > | 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 | } -shutdown { unregister_jt_vfs } -files [test_set $::allquicktests -exclude { wal* incrvacuum.test ioerr.test corrupt4.test io.test crash8.test async4.test bigfile.test backcompat.test e_wal* fstat.test mmap2.test pager1.test syscall.test tkt3457.test *malloc* mmap* multiplex* nolock* pager2.test *fault* rowal* snapshot* superlock* symlink.test delete_db.test shmlock.test chunksize.test busy2.test avfs.test external_reader.test }] if {[info commands register_demovfs] != ""} { test_suite "demovfs" -description { Check that the demovfs (code in test_demovfs.c) more or less works. } -initialize { register_demovfs |
︙ | ︙ | |||
1020 1021 1022 1023 1024 1025 1026 | } -files [ test_set [glob -nocomplain $::testdir/../ext/rbu/*.test] -exclude rbu.test ] test_suite "no_optimization" -description { Run test scripts with optimizations disabled using the sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS) interface. | | > > | | | | | > | | 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 | } -files [ test_set [glob -nocomplain $::testdir/../ext/rbu/*.test] -exclude rbu.test ] test_suite "no_optimization" -description { Run test scripts with optimizations disabled using the sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS) interface. } -files [ test_set \ [glob -nocomplain $::testdir/window*.test] \ where.test where2.test where3.test where4.test where5.test \ where6.test where7.test where8.test where9.test \ whereA.test whereB.test wherelimit.test \ select1.test select2.test select3.test select4.test select5.test \ select7.test select8.test selectA.test selectC.test \ -exclude windowpushd.test ] -dbconfig { optimization_control $::dbhandle all 0 } test_suite "prepare" -description { Run tests with the db connection using sqlite3_prepare() instead of _v2(). } -dbconfig { $::dbhandle version -use-legacy-prepare 1 |
︙ | ︙ | |||
1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 | } -shutdown { catch {db close} sqlite3_shutdown sqlite3_config_sorterref -1 sqlite3_initialize autoinstall_test_functions } # End of tests ############################################################################# # run_tests NAME OPTIONS # # where available options are: | > > > > > > > > > > | 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 | } -shutdown { catch {db close} sqlite3_shutdown sqlite3_config_sorterref -1 sqlite3_initialize autoinstall_test_functions } test_suite "maindbname" -prefix "" -description { Run the "veryquick" test suite with SQLITE_DBCONFIG_MAINDBNAME used to set the name of database 0 to "icecube". } -files [ test_set $allquicktests -exclude *malloc* *ioerr* *fault* *bigfile* *_err* \ *fts5corrupt* *fts5big* *fts5aj* ] -dbconfig { dbconfig_maindbname_icecube $::dbhandle } # End of tests ############################################################################# # run_tests NAME OPTIONS # # where available options are: |
︙ | ︙ | |||
1089 1090 1091 1092 1093 1094 1095 | set ::G(perm:name) $name set ::G(perm:prefix) $options(-prefix) set ::G(isquick) 1 set ::G(perm:dbconfig) $options(-dbconfig) set ::G(perm:presql) $options(-presql) | | > > > > > | > > > > > > > > > > > > < | 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 | set ::G(perm:name) $name set ::G(perm:prefix) $options(-prefix) set ::G(isquick) 1 set ::G(perm:dbconfig) $options(-dbconfig) set ::G(perm:presql) $options(-presql) set filelist [lsort $options(-files)] if {[info exists ::env(TCLTEST_PART)]} { regexp {^([0-9]*)/([0-9]*)$} $::env(TCLTEST_PART) -> A B set nFile [expr {([llength $filelist]+$B-1)/$B}] set filelist [lrange $filelist [expr ($A-1)*$nFile] [expr $A*$nFile-1]] } foreach file $filelist { if {[file tail $file] == $file} { set file [file join $::testdir $file] } if {[info exists ::env(SQLITE_TEST_PATTERN_LIST)]} { set ok 0 foreach p $::env(SQLITE_TEST_PATTERN_LIST) { set p [string map {% *} $p] if {[string match $p [file tail $file]]} {set ok 1 ; break} } if {!$ok} continue } uplevel $options(-initialize) slave_test_file $file uplevel $options(-shutdown) unset -nocomplain ::G(perm:sqlite3_args) } unset ::G(perm:name) unset ::G(perm:prefix) unset ::G(perm:dbconfig) unset ::G(perm:presql) |
︙ | ︙ | |||
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 | # See if the first argument is a named test-suite. # set suite [file tail [lindex $argv 0]] if {[info exists ::testspec($suite)]} { set S $::testspec($suite) set i 1 } else { set S [list] set i 0 } set extra "" if {$i < [llength $argv] && [string range [lindex $argv $i] 0 0]!="-" } { set files [list] for {} {$i < [llength $argv]} {incr i} { set pattern [string map {% *} [lindex $argv $i]] if {[string range $pattern 0 0]=="-"} break foreach f $::alltests { set tail [file tail $f] if {[lsearch $files $f]<0 && [string match $pattern $tail]} { lappend files $f } } } set extra [list -files $files] } | > | > | 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 | # See if the first argument is a named test-suite. # set suite [file tail [lindex $argv 0]] if {[info exists ::testspec($suite)]} { set S $::testspec($suite) set i 1 } else { set suite default set S [list] set i 0 } set extra "" if {$i < [llength $argv] && [string range [lindex $argv $i] 0 0]!="-" } { set files [list] for {} {$i < [llength $argv]} {incr i} { set pattern [string map {% *} [lindex $argv $i]] if {[string range $pattern 0 0]=="-"} break foreach f $::alltests { set tail [file tail $f] if {[lsearch $files $f]<0 && [string match $pattern $tail]} { lappend files $f } } } set extra [list -files $files] } eval [list run_tests $suite] $S $extra } } main $argv set argv {} finish_test } |
Changes to test/pg_common.tcl.
︙ | ︙ | |||
14 15 16 17 18 19 20 21 22 23 24 25 26 27 | package require Pgtcl set db [pg_connect -conninfo "dbname=postgres user=postgres password=postgres"] sqlite3 sqlite "" proc execsql {sql} { set lSql [list] set frag "" while {[string length $sql]>0} { set i [string first ";" $sql] if {$i>=0} { append frag [string range $sql 0 $i] set sql [string range $sql $i+1 end] | > > | 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | package require Pgtcl set db [pg_connect -conninfo "dbname=postgres user=postgres password=postgres"] sqlite3 sqlite "" proc execsql {sql} { set sql [string map {{WITHOUT ROWID} {}} $sql] set lSql [list] set frag "" while {[string length $sql]>0} { set i [string first ";" $sql] if {$i>=0} { append frag [string range $sql 0 $i] set sql [string range $sql $i+1 end] |
︙ | ︙ | |||
36 37 38 39 40 41 42 43 44 45 46 47 | } if {$frag != ""} { lappend lSql $frag } #puts $lSql set ret "" foreach stmt $lSql { set res [pg_exec $::db $stmt] set err [pg_result $res -error] if {$err!=""} { error $err } for {set i 0} {$i < [pg_result $res -numTuples]} {incr i} { | > > < | > > > > > | > | > > | > > > > > > > > > > > > > > > > | 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 | } if {$frag != ""} { lappend lSql $frag } #puts $lSql set ret "" set nChar 0 foreach stmt $lSql { set res [pg_exec $::db $stmt] set err [pg_result $res -error] if {$err!=""} { error $err } for {set i 0} {$i < [pg_result $res -numTuples]} {incr i} { set t [pg_result $res -getTuple $i] set nNew [string length $t] if {$nChar>0 && ($nChar+$nNew+3)>75} { append ret "\n " set nChar 0 } else { if {$nChar>0} { append ret " " incr nChar 3 } } incr nChar $nNew append ret $t } pg_result $res -clear } set ret } proc execsql_test {tn sql} { set res [execsql $sql] set sql [string map {string_agg group_concat} $sql] # set sql [string map [list {NULLS FIRST} {}] $sql] # set sql [string map [list {NULLS LAST} {}] $sql] puts $::fd "do_execsql_test $tn {" puts $::fd " [string trim $sql]" puts $::fd "} {$res}" puts $::fd "" } proc errorsql_test {tn sql} { set rc [catch {execsql $sql} msg] if {$rc==0} { error "errorsql_test SQL did not cause an error!" } set msg [lindex [split [string trim $msg] "\n"] 0] puts $::fd "# PG says $msg" set sql [string map {string_agg group_concat} $sql] puts $::fd "do_test $tn { catch { execsql {" puts $::fd " [string trim $sql]" puts $::fd "} } } 1" puts $::fd "" } # Same as [execsql_test], except coerce all results to floating point values # with two decimal points. # proc execsql_float_test {tn sql} { set F "%.4f" set T 0.0001 |
︙ | ︙ | |||
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 | puts $::fd [subst -nocommands { do_test $tn { set myres {} foreach r [db eval {$sql}] { lappend myres [format $F [set r]] } set res2 {$res2} foreach r [set myres] r2 [set res2] { if {[set r]<([set r2]-$T) || [set r]>([set r2]+$T)} { error "list element [set i] does not match: got=[set r] expected=[set r2]" } } set {} {} } {} }] } proc start_test {name date} { | > > | 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 | puts $::fd [subst -nocommands { do_test $tn { set myres {} foreach r [db eval {$sql}] { lappend myres [format $F [set r]] } set res2 {$res2} set i 0 foreach r [set myres] r2 [set res2] { if {[set r]<([set r2]-$T) || [set r]>([set r2]+$T)} { error "list element [set i] does not match: got=[set r] expected=[set r2]" } incr i } set {} {} } {} }] } proc start_test {name date} { |
︙ | ︙ |
Changes to test/pragma.test.
︙ | ︙ | |||
247 248 249 250 251 252 253 254 255 256 257 258 259 260 | } {0} do_test pragma-1.14.4 { execsql { PRAGMA synchronous=10; PRAGMA synchronous; } } {2} } ;# ifcapable pager_pragmas # Test turning "flag" pragmas on and off. # ifcapable debug { # Pragma "vdbe_listing" is only available if compiled with SQLITE_DEBUG # | > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | } {0} do_test pragma-1.14.4 { execsql { PRAGMA synchronous=10; PRAGMA synchronous; } } {2} do_execsql_test 1.15.1 { PRAGMA default_cache_size = 0; } do_execsql_test 1.15.2 { PRAGMA default_cache_size; } $DFLT_CACHE_SZ do_execsql_test 1.15.3 { PRAGMA default_cache_size = -500; } do_execsql_test 1.15.4 { PRAGMA default_cache_size; } 500 do_execsql_test 1.15.3 { PRAGMA default_cache_size = 500; } do_execsql_test 1.15.4 { PRAGMA default_cache_size; } 500 db close hexio_write test.db 48 FFFFFF00 sqlite3 db test.db do_execsql_test 1.15.4 { PRAGMA default_cache_size; } 256 } ;# ifcapable pager_pragmas # Test turning "flag" pragmas on and off. # ifcapable debug { # Pragma "vdbe_listing" is only available if compiled with SQLITE_DEBUG # |
︙ | ︙ | |||
358 359 360 361 362 363 364 | } } {{row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2} {row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2}} do_test pragma-3.5 { execsql { PRAGMA integrity_check=4 } } {{row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2} {row 1 missing from index i2}} | | > > | | < | > > > | 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 | } } {{row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2} {row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2}} do_test pragma-3.5 { execsql { PRAGMA integrity_check=4 } } {{row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2} {row 1 missing from index i2}} do_catchsql_test pragma-3.6 { PRAGMA integrity_check=xyz } {1 {no such table: xyz}} do_catchsql_test pragma-3.6b { PRAGMA integrity_check=t2 } {0 {{row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2}}} do_catchsql_test pragma-3.6c { PRAGMA integrity_check=sqlite_schema } {0 ok} do_test pragma-3.7 { execsql { PRAGMA integrity_check=0 } } {{row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2} {row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2}} # Add additional corruption by appending unused pages to the end of |
︙ | ︙ | |||
394 395 396 397 398 399 400 | } {ok} do_test pragma-3.8.1 { execsql {PRAGMA quick_check} } {ok} do_test pragma-3.8.2 { execsql {PRAGMA QUICK_CHECK} } {ok} | | > > > > > > | 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 | } {ok} do_test pragma-3.8.1 { execsql {PRAGMA quick_check} } {ok} do_test pragma-3.8.2 { execsql {PRAGMA QUICK_CHECK} } {ok} do_test pragma-3.9a { execsql { ATTACH 'testerr.db' AS t2; PRAGMA integrity_check } } {{*** in database t2 *** Page 4 is never used Page 5 is never used Page 6 is never used} {row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2}} do_execsql_test pragma-3.9b { PRAGMA t2.integrity_check=t2; } {{row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2}} do_execsql_test pragma-3.9c { PRAGMA t2.integrity_check=sqlite_schema; } {ok} do_test pragma-3.10 { execsql { PRAGMA integrity_check=1 } } {{*** in database t2 *** Page 4 is never used}} do_test pragma-3.11 { |
︙ | ︙ | |||
493 494 495 496 497 498 499 | db eval {PRAGMA integrity_check} } {ok} } # Verify that PRAGMA integrity_check catches UNIQUE and NOT NULL # constraint violations. # | > | | | | | | | | | | | | | | | | | | | | | | | > | | 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 | db eval {PRAGMA integrity_check} } {ok} } # Verify that PRAGMA integrity_check catches UNIQUE and NOT NULL # constraint violations. # ifcapable altertable { sqlite3_db_config db DEFENSIVE 0 do_execsql_test pragma-3.20 { CREATE TABLE t1(a,b); CREATE INDEX t1a ON t1(a); INSERT INTO t1 VALUES(1,1),(2,2),(3,3),(2,4),(NULL,5),(NULL,6); PRAGMA writable_schema=ON; UPDATE sqlite_master SET sql='CREATE UNIQUE INDEX t1a ON t1(a)' WHERE name='t1a'; UPDATE sqlite_master SET sql='CREATE TABLE t1(a NOT NULL,b)' WHERE name='t1'; PRAGMA writable_schema=OFF; ALTER TABLE t1 RENAME TO t1x; PRAGMA integrity_check; } {{non-unique entry in index t1a} {NULL value in t1x.a} {non-unique entry in index t1a} {NULL value in t1x.a}} do_execsql_test pragma-3.21 { PRAGMA integrity_check(3); } {{non-unique entry in index t1a} {NULL value in t1x.a} {non-unique entry in index t1a}} do_execsql_test pragma-3.22 { PRAGMA integrity_check(2); } {{non-unique entry in index t1a} {NULL value in t1x.a}} do_execsql_test pragma-3.23 { PRAGMA integrity_check(1); } {{non-unique entry in index t1a}} } # PRAGMA integrity check (or more specifically the sqlite3BtreeCount() # interface) used to leave index cursors in an inconsistent state # which could result in an assertion fault in sqlite3BtreeKey() # called from saveCursorPosition() if content is removed from the # index while the integrity_check is still running. This test verifies # that problem has been fixed. # do_test pragma-3.30 { catch { db close } delete_file test.db sqlite3 db test.db db eval { CREATE TABLE t1(a,b,c); WITH RECURSIVE c(i) AS (VALUES(1) UNION ALL SELECT i+1 FROM c WHERE i<100) INSERT INTO t1(a,b,c) SELECT i, printf('xyz%08x',i), 2000-i FROM c; |
︙ | ︙ | |||
776 777 778 779 780 781 782 | ); } capture_pragma db out {PRAGMA table_info(test_table)} db eval {SELECT cid, "name", type, "notnull", dflt_value, pk FROM out ORDER BY cid} } [concat \ {0 one INT 1 -1 0} \ | | | 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 | ); } capture_pragma db out {PRAGMA table_info(test_table)} db eval {SELECT cid, "name", type, "notnull", dflt_value, pk FROM out ORDER BY cid} } [concat \ {0 one INT 1 -1 0} \ {1 two TEXT 0 {} 0} \ {2 three {VARCHAR(45, 65)} 0 'abcde' 0} \ {3 four REAL 0 X'abcdef' 0} \ {4 five {} 0 CURRENT_TIME 0} \ ] do_test pragma-6.8 { execsql { CREATE TABLE t68(a,b,c,PRIMARY KEY(a,b,a,c)); |
︙ | ︙ | |||
1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 | sqlite3 db2 test.db do_test 23.1 { db eval { CREATE TABLE t1(a INTEGER PRIMARY KEY,b,c,d); CREATE INDEX i1 ON t1(b,c); CREATE INDEX i2 ON t1(c,d); CREATE INDEX i2x ON t1(d COLLATE nocase, c DESC); CREATE TABLE t2(x INTEGER REFERENCES t1); } db2 eval {SELECT name FROM sqlite_master} | > | | 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 | sqlite3 db2 test.db do_test 23.1 { db eval { CREATE TABLE t1(a INTEGER PRIMARY KEY,b,c,d); CREATE INDEX i1 ON t1(b,c); CREATE INDEX i2 ON t1(c,d); CREATE INDEX i2x ON t1(d COLLATE nocase, c DESC); CREATE INDEX i3 ON t1(d,b+c,c); CREATE TABLE t2(x INTEGER REFERENCES t1); } db2 eval {SELECT name FROM sqlite_master} } {t1 i1 i2 i2x i3 t2} do_test 23.2a { db eval { DROP INDEX i2; CREATE INDEX i2 ON t1(c,d,b); } capture_pragma db2 out {PRAGMA index_info(i2)} db2 eval {SELECT cid, name, '|' FROM out ORDER BY seqno} |
︙ | ︙ | |||
1860 1861 1862 1863 1864 1865 1866 | } {2 c 0 BINARY 1 | 3 d 0 BINARY 1 | 1 b 0 BINARY 1 | -1 {} 0 BINARY 0 |} # (The first column of output from PRAGMA index_xinfo is...) # EVIDENCE-OF: R-00197-14279 The rank of the column within the index. (0 # means left-most. Key columns come before auxiliary columns.) # # (The second column of output from PRAGMA index_xinfo is...) | | | | | > > > > | 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 | } {2 c 0 BINARY 1 | 3 d 0 BINARY 1 | 1 b 0 BINARY 1 | -1 {} 0 BINARY 0 |} # (The first column of output from PRAGMA index_xinfo is...) # EVIDENCE-OF: R-00197-14279 The rank of the column within the index. (0 # means left-most. Key columns come before auxiliary columns.) # # (The second column of output from PRAGMA index_xinfo is...) # EVIDENCE-OF: R-06603-49335 The rank of the column within the table # being indexed, or -1 if the index-column is the rowid of the table # being indexed and -2 if the index is on an expression. # # (The third column of output from PRAGMA index_xinfo is...) # EVIDENCE-OF: R-40641-22898 The name of the column being indexed, or # NULL if the index-column is the rowid of the table being indexed or an # expression. # # (The fourth column of output from PRAGMA index_xinfo is...) # EVIDENCE-OF: R-11847-09179 1 if the index-column is sorted in reverse # (DESC) order by the index and 0 otherwise. # # (The fifth column of output from PRAGMA index_xinfo is...) # EVIDENCE-OF: R-15313-19540 The name for the collating sequence used to # compare values in the index-column. # # (The sixth column of output from PRAGMA index_xinfo is...) # EVIDENCE-OF: R-14310-64553 1 if the index-column is a key column and 0 # if the index-column is an auxiliary column. # do_test 23.2c { db2 eval {PRAGMA index_xinfo(i2)} } {0 2 c 0 BINARY 1 1 3 d 0 BINARY 1 2 1 b 0 BINARY 1 3 -1 {} 0 BINARY 0} do_test 23.2d { db2 eval {PRAGMA index_xinfo(i2x)} } {0 3 d 0 nocase 1 1 2 c 1 BINARY 1 2 -1 {} 0 BINARY 0} do_test 23.2e { db2 eval {PRAGMA index_xinfo(i3)} } {0 3 d 0 BINARY 1 1 -2 {} 0 BINARY 1 2 2 c 0 BINARY 1 3 -1 {} 0 BINARY 0} # EVIDENCE-OF: R-64103-17776 PRAGMA schema.index_list(table-name); This # pragma returns one row for each index associated with the given table. # # (The first column of output from PRAGMA index_list is...) # EVIDENCE-OF: R-02753-24748 A sequence number assigned to each index # for internal tracking purposes. |
︙ | ︙ | |||
1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 | # (The fourth column of output from PRAGMA index_list is...) # EVIDENCE-OF: R-36609-39554 "c" if the index was created by a CREATE # INDEX statement, "u" if the index was created by a UNIQUE constraint, # or "pk" if the index was created by a PRIMARY KEY constraint. # do_test 23.3 { db eval { CREATE INDEX i3 ON t1(d,b,c); } capture_pragma db2 out {PRAGMA index_list(t1)} db2 eval {SELECT seq, name, "unique", origin, '|' FROM out ORDER BY seq} } {0 i3 0 c | 1 i2 0 c | 2 i2x 0 c | 3 i1 0 c |} | > > | | | | | | | | > | 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 | # (The fourth column of output from PRAGMA index_list is...) # EVIDENCE-OF: R-36609-39554 "c" if the index was created by a CREATE # INDEX statement, "u" if the index was created by a UNIQUE constraint, # or "pk" if the index was created by a PRIMARY KEY constraint. # do_test 23.3 { db eval { DROP INDEX IF EXISTS i3; CREATE INDEX i3 ON t1(d,b,c); } capture_pragma db2 out {PRAGMA index_list(t1)} db2 eval {SELECT seq, name, "unique", origin, '|' FROM out ORDER BY seq} } {0 i3 0 c | 1 i2 0 c | 2 i2x 0 c | 3 i1 0 c |} ifcapable altertable { do_test 23.4 { db eval { ALTER TABLE t1 ADD COLUMN e; } db2 eval { PRAGMA table_info(t1); } } {/4 e {} 0 {} 0/} } do_test 23.5 { db eval { DROP TABLE t2; CREATE TABLE t2(x, y INTEGER REFERENCES t1); } db2 eval { PRAGMA foreign_key_list(t2); |
︙ | ︙ |
Changes to test/pragma3.test.
︙ | ︙ | |||
250 251 252 253 254 255 256 257 258 | } {2 111 222} do_test pragma3-430 { db2 eval {PRAGMA data_version; SELECT * FROM t1;} } {3 111 222} db2 close } } finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | } {2 111 222} do_test pragma3-430 { db2 eval {PRAGMA data_version; SELECT * FROM t1;} } {3 111 222} db2 close } } #------------------------------------------------------------------------- # Check that empty write transactions do not cause the return of "PRAGMA # data_version" to be decremented with journal_mode=PERSIST and # locking_mode=EXCLUSIVE # foreach {tn sql} { A { } B { PRAGMA journal_mode = PERSIST; PRAGMA locking_mode = EXCLUSIVE; } } { reset_db execsql $sql do_execsql_test pragma3-510$tn { CREATE TABLE t1(x, y); INSERT INTO t1 VALUES(1, 2); PRAGMA data_version; } {1} do_execsql_test pragma3-520$tn { BEGIN EXCLUSIVE; COMMIT; PRAGMA data_version; } {1} } finish_test |
Changes to test/pragma4.test.
︙ | ︙ | |||
40 41 42 43 44 45 46 | 10 "PRAGMA defer_foreign_keys = 1" 11 "PRAGMA empty_result_callbacks = 1" 12 "PRAGMA encoding = 'utf-8'" 13 "PRAGMA foreign_keys = 1" 14 "PRAGMA full_column_names = 1" 15 "PRAGMA fullfsync = 1" 16 "PRAGMA ignore_check_constraints = 1" | < | 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | 10 "PRAGMA defer_foreign_keys = 1" 11 "PRAGMA empty_result_callbacks = 1" 12 "PRAGMA encoding = 'utf-8'" 13 "PRAGMA foreign_keys = 1" 14 "PRAGMA full_column_names = 1" 15 "PRAGMA fullfsync = 1" 16 "PRAGMA ignore_check_constraints = 1" 18 "PRAGMA page_size = 511" 19 "PRAGMA page_size = 512" 20 "PRAGMA query_only = false" 21 "PRAGMA read_uncommitted = true" 22 "PRAGMA recursive_triggers = false" 23 "PRAGMA reverse_unordered_selects = false" 24 "PRAGMA schema_version = 211" |
︙ | ︙ | |||
117 118 119 120 121 122 123 | 0 d {} 0 {} 0 1 e {} 0 {} 0 2 f {} 0 {} 0 } do_test 4.1.4 { sqlite3 db3 test.db sqlite3 db2 test.db2 execsql { DROP TABLE t1 } db3 execsql { DROP TABLE t2 } db2 | | > > > > > | > > | 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 | 0 d {} 0 {} 0 1 e {} 0 {} 0 2 f {} 0 {} 0 } do_test 4.1.4 { sqlite3 db3 test.db sqlite3 db2 test.db2 execsql { DROP TABLE t1 } db3 execsql { DROP TABLE t2 } db2 } {} if {[permutation]=="prepare"} { do_catchsql_test 4.1.5a { PRAGMA table_info(t1) } {1 {database schema has changed}} } do_execsql_test 4.1.5 { PRAGMA table_info(t1) } do_execsql_test 4.1.6 { PRAGMA table_info(t2) } db2 close db3 close reset_db forcedelete test.db2 do_execsql_test 4.2.1 { |
︙ | ︙ | |||
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 | } do_test 4.3.4 { sqlite3 db3 test.db sqlite3 db2 test.db2 execsql { DROP INDEX i1 } db3 execsql { DROP INDEX i2 } db2 } {} ifcapable vtab { do_execsql_test 4.3.5 { SELECT * FROM pragma_index_info('i1') } do_execsql_test 4.3.6 { SELECT * FROM pragma_index_info('i2') } } execsql {SELECT * FROM main.sqlite_master, aux.sqlite_master} do_execsql_test 4.4.0 { CREATE INDEX main.i1 ON t1(b, c); CREATE INDEX aux.i2 ON t2(e, f); } ifcapable vtab { do_execsql_test 4.4.1 { SELECT * FROM pragma_index_list('t1') } {0 i1 0 c 0} do_execsql_test 4.4.2 { SELECT * FROM pragma_index_list('t2') } {0 i2 0 c 0} } do_test 4.4.3 { execsql { DROP INDEX i1 } db3 execsql { DROP INDEX i2 } db2 } {} ifcapable vtab { do_execsql_test 4.4.5 { SELECT * FROM pragma_index_list('t1') } {} do_execsql_test 4.4.6 { SELECT * FROM pragma_index_list('t2') } {} } execsql {SELECT * FROM main.sqlite_master, aux.sqlite_master} do_execsql_test 4.5.0 { | > > > > | 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 | } do_test 4.3.4 { sqlite3 db3 test.db sqlite3 db2 test.db2 execsql { DROP INDEX i1 } db3 execsql { DROP INDEX i2 } db2 } {} if {[permutation]=="prepare"} { catchsql { SELECT * FROM sqlite_master } } ifcapable vtab { do_execsql_test 4.3.5 { SELECT * FROM pragma_index_info('i1') } do_execsql_test 4.3.6 { SELECT * FROM pragma_index_info('i2') } } execsql {SELECT * FROM main.sqlite_master, aux.sqlite_master} do_execsql_test 4.4.0 { CREATE INDEX main.i1 ON t1(b, c); CREATE INDEX aux.i2 ON t2(e, f); } ifcapable vtab { do_execsql_test 4.4.1 { SELECT * FROM pragma_index_list('t1') } {0 i1 0 c 0} do_execsql_test 4.4.2 { SELECT * FROM pragma_index_list('t2') } {0 i2 0 c 0} } do_test 4.4.3 { execsql { DROP INDEX i1 } db3 execsql { DROP INDEX i2 } db2 } {} if {[permutation]=="prepare"} { catchsql { SELECT * FROM sqlite_master, aux.sqlite_master } } ifcapable vtab { do_execsql_test 4.4.5 { SELECT * FROM pragma_index_list('t1') } {} do_execsql_test 4.4.6 { SELECT * FROM pragma_index_list('t2') } {} } execsql {SELECT * FROM main.sqlite_master, aux.sqlite_master} do_execsql_test 4.5.0 { |
︙ | ︙ | |||
212 213 214 215 216 217 218 219 220 221 222 223 224 225 | 0 0 t2 r d {NO ACTION} {NO ACTION} NONE } } do_test 4.5.3 { execsql { DROP TABLE c1 } db3 execsql { DROP TABLE c2 } db2 } {} ifcapable vtab { do_execsql_test 4.5.4 { SELECT * FROM pragma_foreign_key_list('c1') } do_execsql_test 4.5.5 { SELECT * FROM pragma_foreign_key_list('c2') } } execsql {SELECT * FROM main.sqlite_master, aux.sqlite_master} do_execsql_test 4.6.0 { | > > > | 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 | 0 0 t2 r d {NO ACTION} {NO ACTION} NONE } } do_test 4.5.3 { execsql { DROP TABLE c1 } db3 execsql { DROP TABLE c2 } db2 } {} if {[permutation]=="prepare"} { catchsql { SELECT * FROM sqlite_master, aux.sqlite_master } } ifcapable vtab { do_execsql_test 4.5.4 { SELECT * FROM pragma_foreign_key_list('c1') } do_execsql_test 4.5.5 { SELECT * FROM pragma_foreign_key_list('c2') } } execsql {SELECT * FROM main.sqlite_master, aux.sqlite_master} do_execsql_test 4.6.0 { |
︙ | ︙ | |||
237 238 239 240 241 242 243 244 245 | do_test 4.6.3 { execsql { DROP TABLE c2 } db2 } {} do_execsql_test 4.6.4 { pragma foreign_key_check('c1') } {c1 1 t1 0} do_catchsql_test 4.6.5 { pragma foreign_key_check('c2') } {1 {no such table: c2}} finish_test | > > > > > > > > > > | 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 | do_test 4.6.3 { execsql { DROP TABLE c2 } db2 } {} do_execsql_test 4.6.4 { pragma foreign_key_check('c1') } {c1 1 t1 0} do_catchsql_test 4.6.5 { pragma foreign_key_check('c2') } {1 {no such table: c2}} do_execsql_test 5.0 { CREATE TABLE t4(a DEFAULT 'abc' /* comment */, b DEFAULT -1 -- comment , c DEFAULT +4.0 /* another comment */ ); PRAGMA table_info = t4; } { 0 a {} 0 'abc' 0 1 b {} 0 -1 0 2 c {} 0 +4.0 0 } finish_test |
Changes to test/pragma5.test.
1 2 3 4 5 6 7 8 9 10 11 12 13 | # 2017 August 25 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. # # This file implements tests for the PRAGMA command. Specifically, | | | > > > > > | > | | 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 | # 2017 August 25 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. # # This file implements tests for the PRAGMA command. Specifically, # those pragmas that are not disabled at build time by setting: # # -DSQLITE_OMIT_INTROSPECTION_PRAGMAS # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix pragma5 if { [catch {db one "SELECT count(*) FROM pragma_function_list"}] } { finish_test return } db function external external do_execsql_test 1.0 { PRAGMA table_info(pragma_function_list) } { 0 name {} 0 {} 0 1 builtin {} 0 {} 0 2 type {} 0 {} 0 3 enc {} 0 {} 0 4 narg {} 0 {} 0 5 flags {} 0 {} 0 } do_execsql_test 1.1 { SELECT DISTINCT name, builtin FROM pragma_function_list WHERE name='upper' AND builtin } {upper 1} do_execsql_test 1.2 { SELECT DISTINCT name, builtin FROM pragma_function_list WHERE name LIKE 'exter%'; } {external 0} ifcapable fts5 { do_execsql_test 2.0 { PRAGMA table_info(pragma_module_list) } { 0 name {} 0 {} 0 |
︙ | ︙ |
Added test/prefixes.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 | # 2018-01-15 # # 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 prefixes.c extension # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix unionvtab ifcapable !vtab { finish_test return } load_static_extension db prefixes foreach {tn zLeft zRight expected} { 1 abcdxxx abcyy 3 2 abcdxxx bcyyy 0 3 abcdxxx ab 2 4 ab abcd 2 5 "xyz\u1234xz" "xyz\u1234xy" 5 6 "xyz\u1234" "xyz\u1234xy" 4 7 "xyz\u1234" "xyz\u1234" 4 8 "xyz\u1234xy" "xyz\u1234" 4 9 "xyz\u1234xy" "xyz\u1233" 3 10 "xyz\u1234xy" "xyz\u1235" 3 } { do_execsql_test 1.$tn { SELECT prefix_length($zLeft, $zRight) } $expected } do_execsql_test 2.0 { CREATE TABLE t1(k TEXT UNIQUE, v INTEGER); INSERT INTO t1 VALUES ('aback', 1), ('abaft', 2), ('abandon', 3), ('abandoned', 4), ('abandoning', 5), ('abandonment', 6), ('abandons', 7), ('abase', 8), ('abased', 9), ('abasement', 10), ('abasements', 11), ('abases', 12), ('abash', 13), ('abashed', 14), ('abashes', 15), ('abashing', 16), ('abasing', 17), ('abate', 18), ('abated', 19), ('abatement', 20), ('abatements', 21); } foreach {tn INPUT expected} { 1 abatementt abatement 2 abashet abash 3 abandonio abandon 4 abasemenu abase } { do_execsql_test 2.$tn { WITH finder(str) AS ( SELECT (SELECT max(k) FROM t1 WHERE k<=$INPUT) UNION ALL SELECT ( SELECT max(k) FROM t1 WHERE k<=substr($INPUT, 1, prefix_length(finder.str, $INPUT)) ) FROM finder WHERE length(finder.str)>0 ) SELECT str FROM finder WHERE length(str)==prefix_length(str, $INPUT) LIMIT 1 } $expected } finish_test |
Changes to test/printf.test.
︙ | ︙ | |||
534 535 536 537 538 539 540 | } {abc: 1 1 (0.0) :xyz} do_test printf-2.1.2.8 { sqlite3_mprintf_double {abc: %d %d (%1.1e) :xyz} 1 1 1.0e-20 } {abc: 1 1 (1.0e-20) :xyz} do_test printf-2.1.2.9 { sqlite3_mprintf_double {abc: %d %d (%1.1g) :xyz} 1 1 1.0e-20 } {abc: 1 1 (1e-20) :xyz} | > | | | > | 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 | } {abc: 1 1 (0.0) :xyz} do_test printf-2.1.2.8 { sqlite3_mprintf_double {abc: %d %d (%1.1e) :xyz} 1 1 1.0e-20 } {abc: 1 1 (1.0e-20) :xyz} do_test printf-2.1.2.9 { sqlite3_mprintf_double {abc: %d %d (%1.1g) :xyz} 1 1 1.0e-20 } {abc: 1 1 (1e-20) :xyz} if {$SQLITE_MAX_LENGTH<=[expr 1000*1000*1000]} { do_test printf-2.1.2.10 { sqlite3_mprintf_double {abc: %*.*f} 2000000000 1000000000 1.0e-20 } {} } do_test printf-2.1.3.1 { sqlite3_mprintf_double {abc: (%*.*f) :xyz} 1 1 1.0 } {abc: (1.0) :xyz} do_test printf-2.1.3.2 { sqlite3_mprintf_double {abc: (%*.*e) :xyz} 1 1 1.0 } {abc: (1.0e+00) :xyz} do_test printf-2.1.3.3 { |
︙ | ︙ | |||
3772 3773 3774 3775 3776 3777 3778 3779 3780 | do_test printf-malloc-$::iRepeat.$nTestNum { expr {($nFail>0 && $z eq "") || ($nFail==$nBenign && $z eq $zSuccess)} } {1} if {$nFail == 0} break incr nTestNum } } finish_test | > > > > > > > | 3774 3775 3776 3777 3778 3779 3780 3781 3782 3783 3784 3785 3786 3787 3788 3789 | do_test printf-malloc-$::iRepeat.$nTestNum { expr {($nFail>0 && $z eq "") || ($nFail==$nBenign && $z eq $zSuccess)} } {1} if {$nFail == 0} break incr nTestNum } } # 2020-05-23 # ticket 23439ea582241138 # do_execsql_test printf-16.1 { SELECT printf('%.*g',2147483647,0.01); } {0.01} finish_test |
Changes to test/quote.test.
︙ | ︙ | |||
12 13 14 15 16 17 18 19 20 21 22 23 24 25 | # focus of this file is the ability to specify table and column names # as quoted strings. # # $Id: quote.test,v 1.7 2007/04/25 11:32:30 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # Create a table with a strange name and with strange column names. # do_test quote-1.0 { catchsql {CREATE TABLE '@abc' ( '#xyz' int, '!pqr' text );} } {0 {}} | > | 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | # focus of this file is the ability to specify table and column names # as quoted strings. # # $Id: quote.test,v 1.7 2007/04/25 11:32:30 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix quote # Create a table with a strange name and with strange column names. # do_test quote-1.0 { catchsql {CREATE TABLE '@abc' ( '#xyz' int, '!pqr' text );} } {0 {}} |
︙ | ︙ | |||
80 81 82 83 84 85 86 | # do_test quote-1.6 { set r [catch { execsql {DROP TABLE '@abc'} } msg ] lappend r $msg } {0 {}} | | > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | # do_test quote-1.6 { set r [catch { execsql {DROP TABLE '@abc'} } msg ] lappend r $msg } {0 {}} #------------------------------------------------------------------------- # Check that it is not possible to use double-quotes for a string # constant in a CHECK constraint or CREATE INDEX statement. However, # SQLite can load such a schema from disk. # reset_db sqlite3_db_config db SQLITE_DBCONFIG_DQS_DDL 0 sqlite3_db_config db SQLITE_DBCONFIG_DQS_DML 1 do_execsql_test 2.0 { CREATE TABLE t1(x, y, z); } foreach {tn sql errname} { 1 { CREATE TABLE xyz(a, b, c CHECK (c!="null") ) } null 2 { CREATE INDEX i2 ON t1(x, y, z||"abc") } abc 3 { CREATE INDEX i3 ON t1("w") } w 4 { CREATE INDEX i4 ON t1(x) WHERE z="w" } w } { do_catchsql_test 2.1.$tn $sql [list 1 "no such column: $errname"] } do_execsql_test 2.2 { PRAGMA writable_schema = 1; CREATE TABLE xyz(a, b, c CHECK (c!="null") ); CREATE INDEX i2 ON t1(x, y, z||"abc"); CREATE INDEX i3 ON t1("w"||""); CREATE INDEX i4 ON t1(x) WHERE z="w"; } db close sqlite3 db test.db do_execsql_test 2.3.1 { INSERT INTO xyz VALUES(1, 2, 3); } do_catchsql_test 2.3.2 { INSERT INTO xyz VALUES(1, 2, 'null'); } {1 {CHECK constraint failed: c!="null"}} do_execsql_test 2.4 { INSERT INTO t1 VALUES(1, 2, 3); INSERT INTO t1 VALUES(4, 5, 'w'); SELECT * FROM t1 WHERE z='w'; } {4 5 w} do_execsql_test 2.5 { SELECT sql FROM sqlite_master; } { {CREATE TABLE t1(x, y, z)} {CREATE TABLE xyz(a, b, c CHECK (c!="null") )} {CREATE INDEX i2 ON t1(x, y, z||"abc")} {CREATE INDEX i3 ON t1("w"||"")} {CREATE INDEX i4 ON t1(x) WHERE z="w"} } # 2021-03-13 # ticket 1c24a659e6d7f3a1 ifcapable altertable { reset_db do_catchsql_test 3.0 { CREATE TABLE t1(a,b); CREATE INDEX x1 on t1("b"); ALTER TABLE t1 DROP COLUMN b; } {1 {error in index x1 after drop column: no such column: b}} do_catchsql_test 3.1 { DROP TABLE t1; CREATE TABLE t1(a,"b"); CREATE INDEX x1 on t1("b"); ALTER TABLE t1 DROP COLUMN b; } {1 {error in index x1 after drop column: no such column: b}} do_catchsql_test 3.2 { DROP TABLE t1; CREATE TABLE t1(a,'b'); CREATE INDEX x1 on t1("b"); ALTER TABLE t1 DROP COLUMN b; } {1 {error in index x1 after drop column: no such column: b}} do_catchsql_test 3.3 { DROP TABLE t1; CREATE TABLE t1(a,"b"); CREATE INDEX x1 on t1('b'); ALTER TABLE t1 DROP COLUMN b; } {1 {error in index x1 after drop column: no such column: b}} do_catchsql_test 3.4 { DROP TABLE t1; CREATE TABLE t1(a, b, c); CREATE INDEX x1 ON t1("a"||"b"); INSERT INTO t1 VALUES(1,2,3),(1,4,5); ALTER TABLE t1 DROP COLUMN b; } {1 {error in index x1 after drop column: no such column: b}} do_catchsql_test 3.5 { DROP TABLE t1; CREATE TABLE t1(a, b, c); CREATE INDEX x1 ON t1("a"||"x"); INSERT INTO t1 VALUES(1,2,3),(1,4,5); ALTER TABLE t1 DROP COLUMN b; } {0 {}} } finish_test |
Added test/recover.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 | # 2019 April 23 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # # Test the shell tool ".ar" command. # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix recover ifcapable !vtab { finish_test; return } set CLI [test_find_cli] proc compare_result {db1 db2 sql} { set r1 [$db1 eval $sql] set r2 [$db2 eval $sql] if {$r1 != $r2} { puts "r1: $r1" puts "r2: $r2" error "mismatch for $sql" } return "" } proc compare_dbs {db1 db2} { compare_result $db1 $db2 "SELECT sql FROM sqlite_master ORDER BY 1" foreach tbl [$db1 eval {SELECT name FROM sqlite_master WHERE type='table'}] { compare_result $db1 $db2 "SELECT * FROM $tbl" } } proc do_recover_test {tn {tsql {}} {res {}}} { set fd [open "|$::CLI test.db .recover"] fconfigure $fd -encoding binary fconfigure $fd -translation binary set sql [read $fd] close $fd forcedelete test.db2 sqlite3 db2 test.db2 execsql $sql db2 if {$tsql==""} { uplevel [list do_test $tn [list compare_dbs db db2] {}] } else { uplevel [list do_execsql_test -db db2 $tn $tsql $res] } db2 close } set doc { hello world } do_execsql_test 1.1.1 { CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c); INSERT INTO t1 VALUES(1, 4, X'1234567800'); INSERT INTO t1 VALUES(2, 'test', 8.1); INSERT INTO t1 VALUES(3, $doc, 8.4); } do_recover_test 1.1.2 do_execsql_test 1.2.1 " DELETE FROM t1; INSERT INTO t1 VALUES(13, 'hello\r\nworld', 13); " do_recover_test 1.2.2 do_execsql_test 1.3.1 " CREATE TABLE t2(i INTEGER PRIMARY KEY AUTOINCREMENT, b, c); INSERT INTO t2 VALUES(NULL, 1, 2); INSERT INTO t2 VALUES(NULL, 3, 4); INSERT INTO t2 VALUES(NULL, 5, 6); CREATE TABLE t3(i INTEGER PRIMARY KEY AUTOINCREMENT, b, c); INSERT INTO t3 VALUES(NULL, 1, 2); INSERT INTO t3 VALUES(NULL, 3, 4); INSERT INTO t3 VALUES(NULL, 5, 6); DELETE FROM t2; " do_recover_test 1.3.2 #------------------------------------------------------------------------- reset_db do_execsql_test 2.1.0 { PRAGMA auto_vacuum = 0; CREATE TABLE t1(a, b, c, PRIMARY KEY(b, c)) WITHOUT ROWID; INSERT INTO t1 VALUES(1, 2, 3); INSERT INTO t1 VALUES(4, 5, 6); INSERT INTO t1 VALUES(7, 8, 9); } do_recover_test 2.1.1 do_execsql_test 2.2.0 { PRAGMA writable_schema = 1; DELETE FROM sqlite_master WHERE name='t1'; } do_recover_test 2.2.1 { SELECT name FROM sqlite_master } {lost_and_found} do_execsql_test 2.3.0 { CREATE TABLE lost_and_found(a, b, c); } do_recover_test 2.3.1 { SELECT name FROM sqlite_master } {lost_and_found lost_and_found_0} do_execsql_test 2.4.0 { CREATE TABLE lost_and_found_0(a, b, c); } do_recover_test 2.4.1 { SELECT name FROM sqlite_master; SELECT * FROM lost_and_found_1; } {lost_and_found lost_and_found_0 lost_and_found_1 2 2 3 {} 2 3 1 2 2 3 {} 5 6 4 2 2 3 {} 8 9 7 } #------------------------------------------------------------------------- reset_db do_recover_test 3.0 finish_test |
Changes to test/regexp1.test.
︙ | ︙ | |||
23 24 25 26 27 28 29 30 31 32 33 | 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.'); SELECT x FROM t1 WHERE y REGEXP '^For ' ORDER BY x; } } {1 3} do_execsql_test regexp1-1.2 { SELECT x FROM t1 WHERE y REGEXP 'by|in' ORDER BY x; } {1 2 3 4} | > > > > > > > > > > > > > | > > > > > > > > > | > > > > > > > > > | 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 | 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.'); SELECT x FROM t1 WHERE y REGEXP '^For ' ORDER BY x; } } {1 3} do_execsql_test regexp1-1.1.2 { SELECT regexpi('abc','ABC'); } {1} do_execsql_test regexp1-1.1.3 { SELECT regexpi('ABC','ABC'); } {1} do_execsql_test regexp1-1.1.4 { SELECT regexpi('ABC','abc'); } {1} do_execsql_test regexp1-1.1.5 { SELECT regexpi('ABC.','ABC'); } {0} do_execsql_test regexp1-1.2 { SELECT x FROM t1 WHERE y REGEXP 'by|in' ORDER BY x; } {1 2 3 4} do_execsql_test regexp1-1.3.1 { SELECT x FROM t1 WHERE y REGEXP 'by|Christ' ORDER BY x; } {1 2 4} do_execsql_test regexp1-1.3.2 { SELECT x FROM t1 WHERE regexp('by|christ',y) ORDER BY x; } {1 2} do_execsql_test regexp1-1.3.3 { SELECT x FROM t1 WHERE regexpi('by|christ',y) ORDER BY x; } {1 2 4} do_execsql_test regexp1-1.3.4 { SELECT x FROM t1 WHERE regexpi('BY|CHRIST',y) ORDER BY x; } {1 2 4} do_execsql_test regexp1-1.4 { SELECT x FROM t1 WHERE y REGEXP 'shal+ al+' ORDER BY x; } {4} do_execsql_test regexp1-1.5.1 { SELECT x FROM t1 WHERE y REGEXP 'shall x*y*z*all' ORDER BY x; } {4} do_execsql_test regexp1-1.5.2 { SELECT x FROM t1 WHERE regexp('shall x*y*z*all',y) ORDER BY x; } {4} do_execsql_test regexp1-1.5.3 { SELECT x FROM t1 WHERE regexp('SHALL x*y*z*all',y) ORDER BY x; } {} do_execsql_test regexp1-1.5.4 { SELECT x FROM t1 WHERE regexpi('SHALL x*y*z*all',y) ORDER BY x; } {4} do_execsql_test regexp1-1.6 { SELECT x FROM t1 WHERE y REGEXP 'shallx?y? ?z?all' ORDER BY x; } {4} do_execsql_test regexp1-1.7 { SELECT x FROM t1 WHERE y REGEXP 'r{2}' ORDER BY x; } {2} do_execsql_test regexp1-1.8 { |
︙ | ︙ |
Changes to test/regexp2.test.
︙ | ︙ | |||
116 117 118 119 120 121 122 123 124 | INSERT INTO t5 VALUES ('^a.*'), ('^b.*'), ('^c.*'); INSERT INTO t6 VALUES ('eab'), ('abc'), ('bcd'), ('cde'), ('dea'); DELETE FROM t5; SELECT * FROM t6; } {eab dea} finish_test | > > > > > > > > > > > > > > > > > > > > | 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 | INSERT INTO t5 VALUES ('^a.*'), ('^b.*'), ('^c.*'); INSERT INTO t6 VALUES ('eab'), ('abc'), ('bcd'), ('cde'), ('dea'); DELETE FROM t5; SELECT * FROM t6; } {eab dea} # 2021-06-04 Forum https://sqlite.org/forum/forumpost/9104f0d9e7 # do_execsql_test 4.1 {SELECT 'abc' REGEXP '\W'} {0} do_execsql_test 4.2 {SELECT 'a c' REGEXP '\W'} {1} do_execsql_test 4.3 {SELECT ' ' REGEXP '\W'} {1} do_execsql_test 4.4 {SELECT 'abc' REGEXP '\w'} {1} do_execsql_test 4.5 {SELECT 'a c' REGEXP '\w'} {1} do_execsql_test 4.6 {SELECT ' ' REGEXP '\w'} {0} do_execsql_test 4.7 {SELECT 'abc' REGEXP '\D'} {1} do_execsql_test 4.8 {SELECT 'abc' REGEXP '[^a-z]'} {0} do_execsql_test 4.9 {SELECT 'a c' REGEXP '[^a-z]'} {1} do_execsql_test 4.10 {SELECT ' ' REGEXP '[^a-z]'} {1} do_execsql_test 4.11 {SELECT 'abc' REGEXP '[a-z]'} {1} do_execsql_test 4.12 {SELECT 'a c' REGEXP '[a-z]'} {1} do_execsql_test 4.13 {SELECT ' ' REGEXP '[a-z]'} {0} do_execsql_test 4.14 {SELECT 'abc' REGEXP '[^a-z]{2}'} {0} do_execsql_test 4.15 {SELECT 'a c' REGEXP '[^a-z]{2}'} {0} do_execsql_test 4.16 {SELECT ' ' REGEXP '[^a-z]{2}'} {1} do_execsql_test 4.17 {SELECT 'abc' REGEXP '\W{1,1}'} {0} do_execsql_test 4.18 {SELECT 'abc' REGEXP '\W{1}'} {0} finish_test |
Changes to test/reindex.test.
︙ | ︙ | |||
11 12 13 14 15 16 17 18 19 20 21 22 23 24 | # This file implements regression tests for SQLite library. # This file implements tests for the REINDEX command. # # $Id: reindex.test,v 1.4 2008/07/12 14:52:20 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # There is nothing to test if REINDEX is disable for this build. # ifcapable {!reindex} { finish_test return } | > | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | # This file implements regression tests for SQLite library. # This file implements tests for the REINDEX command. # # $Id: reindex.test,v 1.4 2008/07/12 14:52:20 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix reindex # There is nothing to test if REINDEX is disable for this build. # ifcapable {!reindex} { finish_test return } |
︙ | ︙ | |||
163 164 165 166 167 168 169 170 171 | REINDEX; } db2 } {1 {no such collation sequence: c2}} do_test reindex-3.99 { db2 close } {} finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | REINDEX; } db2 } {1 {no such collation sequence: c2}} do_test reindex-3.99 { db2 close } {} #------------------------------------------------------------------------- foreach {tn wo} {1 "" 2 "WITHOUT ROWID"} { reset_db eval [string map [list %without_rowid% $wo] { do_execsql_test 4.$tn.0 { CREATE TABLE t0 ( c0 INTEGER PRIMARY KEY DESC, c1 UNIQUE DEFAULT NULL ) %without_rowid% ; INSERT INTO t0(c0) VALUES (1), (2), (3), (4), (5); SELECT c0 FROM t0 WHERE c1 IS NULL ORDER BY 1; } {1 2 3 4 5} do_execsql_test 4.$tn.1 { REINDEX; } do_execsql_test 4.$tn.2 { SELECT c0 FROM t0 WHERE c1 IS NULL ORDER BY 1; } {1 2 3 4 5} do_execsql_test 4.$tn.3 { SELECT c0 FROM t0 WHERE c1 IS NULL AND c0 IN (1,2,3,4,5); } {1 2 3 4 5} do_execsql_test 4.$tn.4 { PRAGMA integrity_check; } {ok} }] } finish_test |
Deleted test/releasetest.tcl.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Added test/releasetest_data.tcl.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 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 | # 2019 August 01 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # # This file implements a program that produces scripts (either shell scripts # or batch files) to implement a particular test that is part of the SQLite # release testing procedure. For example, to run veryquick.test with a # specified set of -D compiler switches. # # A "configuration" is a set of options passed to [./configure] and [make] # to build the SQLite library in a particular fashion. A "platform" is a # list of tests; most platforms are named after the hardware/OS platform # that the tests will be run on as part of the release procedure. Each # "test" is a combination of a configuration and a makefile target (e.g. # "fulltest"). The program may be invoked as follows: # set USAGE { $argv0 script ?-msvc? CONFIGURATION TARGET Given a configuration and make target, return a bash (or, if -msvc is specified, batch) script to execute the test. The first argument passed to the script must be a directory containing SQLite source code. $argv0 configurations List available configurations. $argv0 platforms List available platforms. $argv0 tests ?-nodebug? PLATFORM List tests in a specified platform. If the -nodebug switch is specified, synthetic debug/ndebug configurations are omitted. Each test is a combination of a configuration and a makefile target. } # Omit comments (text between # and \n) in a long multi-line string. # proc strip_comments {in} { regsub -all {#[^\n]*\n} $in {} out return $out } array set ::Configs [strip_comments { "Default" { -O2 --disable-amalgamation --disable-shared --enable-session } "Sanitize" { CC=clang -fsanitize=address,undefined -DSQLITE_ENABLE_STAT4 -DCONFIG_SLOWDOWN_FACTOR=5.0 --enable-debug --enable-all } "Stdcall" { -DUSE_STDCALL=1 -O2 } "Have-Not" { # The "Have-Not" configuration sets all possible -UHAVE_feature options # in order to verify that the code works even on platforms that lack # these support services. -DHAVE_FDATASYNC=0 -DHAVE_GMTIME_R=0 -DHAVE_ISNAN=0 -DHAVE_LOCALTIME_R=0 -DHAVE_LOCALTIME_S=0 -DHAVE_MALLOC_USABLE_SIZE=0 -DHAVE_STRCHRNUL=0 -DHAVE_USLEEP=0 -DHAVE_UTIME=0 } "Unlock-Notify" { -O2 -DSQLITE_ENABLE_UNLOCK_NOTIFY -DSQLITE_THREADSAFE -DSQLITE_TCL_DEFAULT_FULLMUTEX=1 } "User-Auth" { -O2 -DSQLITE_USER_AUTHENTICATION=1 } "Secure-Delete" { -O2 -DSQLITE_SECURE_DELETE=1 -DSQLITE_SOUNDEX=1 } "Update-Delete-Limit" { -O2 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_UPDATE_DELETE_LIMIT=1 -DSQLITE_ENABLE_STMT_SCANSTATUS -DSQLITE_LIKE_DOESNT_MATCH_BLOBS -DSQLITE_ENABLE_CURSOR_HINTS --enable-json1 } "Check-Symbols" { -DSQLITE_MEMDEBUG=1 -DSQLITE_ENABLE_FTS3_PARENTHESIS=1 -DSQLITE_ENABLE_FTS3=1 -DSQLITE_ENABLE_RTREE=1 -DSQLITE_ENABLE_MEMSYS5=1 -DSQLITE_ENABLE_MEMSYS3=1 -DSQLITE_ENABLE_COLUMN_METADATA=1 -DSQLITE_ENABLE_UPDATE_DELETE_LIMIT=1 -DSQLITE_SECURE_DELETE=1 -DSQLITE_SOUNDEX=1 -DSQLITE_ENABLE_ATOMIC_WRITE=1 -DSQLITE_ENABLE_MEMORY_MANAGEMENT=1 -DSQLITE_ENABLE_OVERSIZE_CELL_CHECK=1 -DSQLITE_ENABLE_STAT4 -DSQLITE_ENABLE_STMT_SCANSTATUS --enable-json1 --enable-fts5 --enable-session } "Debug-One" { --disable-shared -O2 -funsigned-char -DSQLITE_DEBUG=1 -DSQLITE_MEMDEBUG=1 -DSQLITE_MUTEX_NOOP=1 -DSQLITE_TCL_DEFAULT_FULLMUTEX=1 -DSQLITE_ENABLE_FTS3=1 -DSQLITE_ENABLE_RTREE=1 -DSQLITE_ENABLE_MEMSYS5=1 -DSQLITE_ENABLE_COLUMN_METADATA=1 -DSQLITE_ENABLE_STAT4 -DSQLITE_ENABLE_HIDDEN_COLUMNS -DSQLITE_MAX_ATTACHED=125 -DSQLITE_MUTATION_TEST --enable-fts5 --enable-json1 } "Debug-Two" { -DSQLITE_DEFAULT_MEMSTATUS=0 -DSQLITE_MAX_EXPR_DEPTH=0 --enable-debug } "Fast-One" { -O6 -DSQLITE_ENABLE_FTS4=1 -DSQLITE_ENABLE_RTREE=1 -DSQLITE_ENABLE_STAT4 -DSQLITE_ENABLE_RBU -DSQLITE_MAX_ATTACHED=125 -DSQLITE_MAX_MMAP_SIZE=12884901888 -DSQLITE_ENABLE_SORTER_MMAP=1 -DLONGDOUBLE_TYPE=double --enable-session } "Device-One" { -O2 -DSQLITE_DEBUG=1 -DSQLITE_DEFAULT_AUTOVACUUM=1 -DSQLITE_DEFAULT_CACHE_SIZE=64 -DSQLITE_DEFAULT_PAGE_SIZE=1024 -DSQLITE_DEFAULT_TEMP_CACHE_SIZE=32 -DSQLITE_DISABLE_LFS=1 -DSQLITE_ENABLE_ATOMIC_WRITE=1 -DSQLITE_ENABLE_IOTRACE=1 -DSQLITE_ENABLE_MEMORY_MANAGEMENT=1 -DSQLITE_MAX_PAGE_SIZE=4096 -DSQLITE_OMIT_LOAD_EXTENSION=1 -DSQLITE_OMIT_PROGRESS_CALLBACK=1 -DSQLITE_OMIT_VIRTUALTABLE=1 -DSQLITE_ENABLE_HIDDEN_COLUMNS -DSQLITE_TEMP_STORE=3 --enable-json1 } "Device-Two" { -DSQLITE_4_BYTE_ALIGNED_MALLOC=1 -DSQLITE_DEFAULT_AUTOVACUUM=1 -DSQLITE_DEFAULT_CACHE_SIZE=1000 -DSQLITE_DEFAULT_LOCKING_MODE=0 -DSQLITE_DEFAULT_PAGE_SIZE=1024 -DSQLITE_DEFAULT_TEMP_CACHE_SIZE=1000 -DSQLITE_DISABLE_LFS=1 -DSQLITE_ENABLE_FTS3=1 -DSQLITE_ENABLE_MEMORY_MANAGEMENT=1 -DSQLITE_ENABLE_RTREE=1 -DSQLITE_MAX_COMPOUND_SELECT=50 -DSQLITE_MAX_PAGE_SIZE=32768 -DSQLITE_OMIT_TRACE=1 -DSQLITE_TEMP_STORE=3 -DSQLITE_THREADSAFE=2 --enable-json1 --enable-fts5 --enable-session } "Locking-Style" { -O2 -DSQLITE_ENABLE_LOCKING_STYLE=1 } "Apple" { -Os -DHAVE_GMTIME_R=1 -DHAVE_ISNAN=1 -DHAVE_LOCALTIME_R=1 -DHAVE_PREAD=1 -DHAVE_PWRITE=1 -DHAVE_UTIME=1 -DSQLITE_DEFAULT_CACHE_SIZE=1000 -DSQLITE_DEFAULT_CKPTFULLFSYNC=1 -DSQLITE_DEFAULT_MEMSTATUS=1 -DSQLITE_DEFAULT_PAGE_SIZE=1024 -DSQLITE_DISABLE_PAGECACHE_OVERFLOW_STATS=1 -DSQLITE_ENABLE_API_ARMOR=1 -DSQLITE_ENABLE_AUTO_PROFILE=1 -DSQLITE_ENABLE_FLOCKTIMEOUT=1 -DSQLITE_ENABLE_FTS3=1 -DSQLITE_ENABLE_FTS3_PARENTHESIS=1 -DSQLITE_ENABLE_FTS3_TOKENIZER=1 -DSQLITE_ENABLE_PERSIST_WAL=1 -DSQLITE_ENABLE_PURGEABLE_PCACHE=1 -DSQLITE_ENABLE_RTREE=1 -DSQLITE_ENABLE_SNAPSHOT=1 # -DSQLITE_ENABLE_SQLLOG=1 -DSQLITE_ENABLE_UPDATE_DELETE_LIMIT=1 -DSQLITE_MAX_LENGTH=2147483645 -DSQLITE_MAX_VARIABLE_NUMBER=500000 # -DSQLITE_MEMDEBUG=1 -DSQLITE_NO_SYNC=1 -DSQLITE_OMIT_AUTORESET=1 -DSQLITE_OMIT_LOAD_EXTENSION=1 -DSQLITE_PREFER_PROXY_LOCKING=1 -DSQLITE_SERIES_CONSTRAINT_VERIFY=1 -DSQLITE_THREADSAFE=2 -DSQLITE_USE_URI=1 -DSQLITE_WRITE_WALFRAME_PREBUFFERED=1 -DUSE_GUARDED_FD=1 -DUSE_PREAD=1 --enable-json1 --enable-fts5 } "Extra-Robustness" { -DSQLITE_ENABLE_OVERSIZE_CELL_CHECK=1 -DSQLITE_MAX_ATTACHED=62 } "Devkit" { -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_MAX_ATTACHED=30 -DSQLITE_ENABLE_COLUMN_METADATA -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_FTS5 -DSQLITE_ENABLE_FTS4_PARENTHESIS -DSQLITE_DISABLE_FTS4_DEFERRED -DSQLITE_ENABLE_RTREE --enable-json1 --enable-fts5 } "No-lookaside" { -DSQLITE_TEST_REALLOC_STRESS=1 -DSQLITE_OMIT_LOOKASIDE=1 } "Valgrind" { -DSQLITE_ENABLE_STAT4 -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_RTREE -DSQLITE_ENABLE_HIDDEN_COLUMNS -DCONFIG_SLOWDOWN_FACTOR=8.0 --enable-json1 } "Windows-Memdebug" { MEMDEBUG=1 DEBUG=3 } "Windows-Win32Heap" { WIN32HEAP=1 DEBUG=4 } # The next group of configurations are used only by the # Failure-Detection platform. They are all the same, but we need # different names for them all so that they results appear in separate # subdirectories. # Fail0 {-O0} Fail2 {-O0} Fail3 {-O0} Fail4 {-O0} FuzzFail1 {-O0} FuzzFail2 {-O0} }] if {$tcl_platform(os)=="Darwin"} { lappend Configs(Apple) -DSQLITE_ENABLE_LOCKING_STYLE=1 } array set ::Platforms [strip_comments { Linux-x86_64 { "Check-Symbols*" "" checksymbols "Fast-One" QUICKTEST_INCLUDE=rbu.test "fuzztest test" "Debug-One" "" "mptest test" "Debug-Two" "" test "Have-Not" "" test "Secure-Delete" "" test "Unlock-Notify" QUICKTEST_INCLUDE=notify2.test test "User-Auth" "" tcltest "Update-Delete-Limit" "" test "Extra-Robustness" "" test "Device-Two" "" "threadtest test" "No-lookaside" "" test "Devkit" "" test "Apple" "" test "Sanitize*" "" test "Device-One" "" alltest "Default" "" "threadtest fuzztest alltest" "Valgrind*" "" valgrindtest } Linux-i686 { "Devkit" "" test "Have-Not" "" test "Unlock-Notify" QUICKTEST_INCLUDE=notify2.test test "Device-One" "" test "Device-Two" "" test "Default" "" "threadtest fuzztest alltest" } Darwin-i386 { "Locking-Style" "" "mptest test" "Have-Not" "" test "Apple" "" "threadtest fuzztest alltest" } Darwin-x86_64 { "Locking-Style" "" "mptest test" "Have-Not" "" test "Apple" "" "threadtest fuzztest alltest" } Darwin-arm64 { "Locking-Style" "" "mptest test" "Have-Not" "" test "Apple" "" "threadtest fuzztest alltest" } "Windows NT-intel" { "Stdcall" "" test "Have-Not" "" test "Windows-Memdebug*" "" test "Windows-Win32Heap*" "" test "Default" "" "mptest fulltestonly" } "Windows NT-amd64" { "Stdcall" "" test "Have-Not" "" test "Windows-Memdebug*" "" test "Windows-Win32Heap*" "" test "Default" "" "mptest fulltestonly" } # The Failure-Detection platform runs various tests that deliberately # fail. This is used as a test of this script to verify that this script # correctly identifies failures. # Failure-Detection { Fail0* "TEST_FAILURE=0" test Sanitize* "TEST_FAILURE=1" test Fail2* "TEST_FAILURE=2" valgrindtest Fail3* "TEST_FAILURE=3" valgrindtest Fail4* "TEST_FAILURE=4" test FuzzFail1* "TEST_FAILURE=5" test FuzzFail2* "TEST_FAILURE=5" valgrindtest } }] #-------------------------------------------------------------------------- #-------------------------------------------------------------------------- #-------------------------------------------------------------------------- # End of configuration section. #-------------------------------------------------------------------------- #-------------------------------------------------------------------------- #-------------------------------------------------------------------------- # Configuration verification: Check that each entry in the list of configs # specified for each platforms exists. # foreach {key value} [array get ::Platforms] { foreach {v vars t} $value { if {[string range $v end end]=="*"} { set v [string range $v 0 end-1] } if {0==[info exists ::Configs($v)]} { puts stderr "No such configuration: \"$v\"" exit -1 } } } proc usage {} { global argv0 puts stderr [subst $::USAGE] exit 1 } proc is_prefix {p str min} { set n [string length $p] if {$n<$min} { return 0 } if {[string range $str 0 [expr $n-1]]!=$p} { return 0 } return 1 } proc main_configurations {} { foreach k [lsort [array names ::Configs]] { puts $k } } proc main_platforms {} { foreach k [lsort [array names ::Platforms]] { puts "\"$k\"" } } proc main_script {args} { set bMsvc 0 set nArg [llength $args] if {$nArg==3} { if {![is_prefix [lindex $args 0] -msvc 2]} usage set bMsvc 1 } elseif {$nArg<2 || $nArg>3} { usage } set config [lindex $args end-1] set target [lindex $args end] set opts [list] ;# OPTS value set cflags [expr {$bMsvc ? "-Zi" : "-g"}] ;# CFLAGS value set makeOpts [list] ;# Extra args for [make] set configOpts [list] ;# Extra args for [configure] if {$::tcl_platform(platform)=="windows" || $bMsvc} { lappend opts -DSQLITE_OS_WIN=1 } else { lappend opts -DSQLITE_OS_UNIX=1 } # Figure out if this is a synthetic ndebug or debug configuration. # set bRemoveDebug 0 if {[string match *-ndebug $config]} { set bRemoveDebug 1 set config [string range $config 0 end-7] } if {[string match *-debug $config]} { lappend opts -DSQLITE_DEBUG lappend opts -DSQLITE_EXTRA_IFNULLROW set config [string range $config 0 end-6] } regexp {^(.*)-[0-9]+} $config -> config # Ensure that the named configuration exists. # if {![info exists ::Configs($config)]} { puts stderr "No such config: $config" exit 1 } # Loop through the parameters of the nominated configuration, updating # $opts, $cflags, $makeOpts and $configOpts along the way. Rules are as # follows: # # 1. If the parameter begins with a "*", discard it. # # 2. If $bRemoveDebug is set and the parameter is -DSQLITE_DEBUG or # -DSQLITE_DEBUG=1, discard it # # 3. If the parameter begins with "-D", add it to $opts. # # 4. If the parameter begins with "--" add it to $configOpts. Unless # this command is preparing a script for MSVC - then add an # equivalent to $makeOpts or $opts. # # 5. If the parameter begins with "-" add it to $cflags. If in MSVC # mode and the parameter is an -O<integer> option, instead add # an OPTIMIZATIONS=<integer> switch to $makeOpts. # # 6. If none of the above apply, add the parameter to $makeOpts # foreach param $::Configs($config) { if {[string range $param 0 0]=="*"} continue if {$bRemoveDebug} { if {$param=="-DSQLITE_DEBUG" || $param=="-DSQLITE_DEBUG=1" || $param=="-DSQLITE_MEMDEBUG" || $param=="-DSQLITE_MEMDEBUG=1" || $param=="--enable-debug" } { continue } } if {[string range $param 0 1]=="-D"} { lappend opts $param continue } if {[string range $param 0 1]=="--"} { if {$bMsvc} { switch -- $param { --disable-amalgamation { lappend makeOpts USE_AMALGAMATION=0 } --disable-shared { lappend makeOpts USE_CRT_DLL=0 DYNAMIC_SHELL=0 } --enable-fts5 { lappend opts -DSQLITE_ENABLE_FTS5 } --enable-json1 { lappend opts -DSQLITE_ENABLE_JSON1 } --enable-shared { lappend makeOpts USE_CRT_DLL=1 DYNAMIC_SHELL=1 } --enable-session { lappend opts -DSQLITE_ENABLE_PREUPDATE_HOOK lappend opts -DSQLITE_ENABLE_SESSION } default { error "Cannot translate $param for MSVC" } } } else { lappend configOpts $param } continue } if {[string range $param 0 0]=="-"} { if {$bMsvc && [regexp -- {^-O(\d+)$} $param -> level]} { lappend makeOpts OPTIMIZATIONS=$level } else { lappend cflags $param } continue } lappend makeOpts $param } # Some configurations specify -DHAVE_USLEEP=0. For all others, add # -DHAVE_USLEEP=1. # if {[lsearch $opts "-DHAVE_USLEEP=0"]<0} { lappend opts -DHAVE_USLEEP=1 } if {$bMsvc==0} { puts {set -e} puts {} puts {if [ "$#" -ne 1 ] ; then} puts { echo "Usage: $0 <sqlite-src-dir>" } puts { exit -1 } puts {fi } puts {SRCDIR=$1} puts {} puts "TCL=\"[::tcl::pkgconfig get libdir,install]\"" puts "\$SRCDIR/configure --with-tcl=\$TCL $configOpts" puts {} puts {OPTS=" -DSQLITE_NO_SYNC=1"} foreach o $opts { puts "OPTS=\"\$OPTS $o\"" } puts {} puts "CFLAGS=\"$cflags\"" puts {} puts "make $target \"CFLAGS=\$CFLAGS\" \"OPTS=\$OPTS\" $makeOpts" } else { puts {set SRCDIR=%1} set makecmd "nmake /f %SRCDIR%\\Makefile.msc TOP=%SRCDIR% $target " append makecmd "\"CFLAGS=$cflags\" \"OPTS=$opts\" $makeOpts" puts "set TMP=%CD%" puts $makecmd } } proc main_tests {args} { set bNodebug 0 set nArg [llength $args] if {$nArg==2} { if {[is_prefix [lindex $args 0] -nodebug 2]} { set bNodebug 1 } elseif {[is_prefix [lindex $args 0] -debug 2]} { set bNodebug 0 } else usage } elseif {$nArg==0 || $nArg>2} { usage } set p [lindex $args end] if {![info exists ::Platforms($p)]} { puts stderr "No such platform: $p" exit 1 } set lTest [list] foreach {config vars target} $::Platforms($p) { if {[string range $config end end]=="*"} { set config [string range $config 0 end-1] } elseif {$bNodebug==0} { set dtarget test if {[lsearch $target fuzztest]<0 && [lsearch $target test]<0} { set dtarget tcltest } if {$vars!=""} { set dtarget "$vars $dtarget" } if {[string first SQLITE_DEBUG $::Configs($config)]>=0 || [string first --enable-debug $::Configs($config)]>=0 } { lappend lTest "$config-ndebug \"$dtarget\"" } else { lappend lTest "$config-debug \"$dtarget\"" } } if {[llength $target]==1 && ([string match "*TEST_FAILURE*" $vars] || ( [lsearch $target "valgrindtest"]<0 && [lsearch $target "alltest"]<0 && [lsearch $target "fulltestonly"]<0 && ![string match Sanitize* $config] ))} { if {$vars!=""} { set target "$vars $target" } lappend lTest "$config \"$target\"" } else { set idir -1 foreach t $target { if {$t=="valgrindtest" || $t=="alltest" || $t=="fulltestonly" || [string match Sanitize* $config] } { if {$vars!=""} { set t "$vars $t" } for {set ii 1} {$ii<=4} {incr ii} { lappend lTest "$config-[incr idir] \"TCLTEST_PART=$ii/4 $t\"" } } else { if {$vars!=""} { set t "$vars $t" } lappend lTest "$config-[incr idir] \"$t\"" } } } } foreach l $lTest { puts $l } } if {[llength $argv]==0} { usage } set cmd [lindex $argv 0] set n [expr [llength $argv]-1] if {[string match ${cmd}* configurations] && $n==0} { main_configurations } elseif {[string match ${cmd}* script]} { main_script {*}[lrange $argv 1 end] } elseif {[string match ${cmd}* platforms] && $n==0} { main_platforms } elseif {[string match ${cmd}* tests]} { main_tests {*}[lrange $argv 1 end] } else { usage } |
Changes to test/resetdb.test.
︙ | ︙ | |||
66 67 68 69 70 71 72 | # Thoroughly corrupt the database file by overwriting the first # page with randomness. sqlite3_db_config db DEFENSIVE 0 catchsql { UPDATE sqlite_dbpage SET data=randomblob(4096) WHERE pgno=1; PRAGMA quick_check; } | | | > > > > | 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 | # Thoroughly corrupt the database file by overwriting the first # page with randomness. sqlite3_db_config db DEFENSIVE 0 catchsql { UPDATE sqlite_dbpage SET data=randomblob(4096) WHERE pgno=1; PRAGMA quick_check; } } {1 {file is not a database}} do_test 201 { catchsql { PRAGMA quick_check; } db2 } {1 {file is not a database}} do_test 210 { # Reset the database file using SQLITE_DBCONFIG_RESET_DATABASE sqlite3_db_config db RESET_DB 1 db eval VACUUM sqlite3_db_config db RESET_DB 0 # If using sqlite3_prepare() instead of _v2() or _v3(), the block # below raises an SQLITE_SCHEMA error. The following fixes this. if {[permutation]=="prepare"} { catchsql "SELECT * FROM sqlite_master" db2 } # Verify that the reset took, even on the separate database connection catchsql { PRAGMA page_count; PRAGMA page_size; PRAGMA quick_check; PRAGMA journal_mode; } db2 |
︙ | ︙ |
Added test/returning1.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 | # 2021-01-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 implements regression tests for SQLite library. The # focus of this file is the new RETURNING clause # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix returning1 do_execsql_test 1.0 { CREATE TABLE t1(a INTEGER PRIMARY KEY,b,c DEFAULT 'pax'); INSERT INTO t1(b) VALUES(10),('happy'),(NULL) RETURNING a,b,c; } {1 10 pax 2 happy pax 3 {} pax} do_execsql_test 1.1 { SELECT * FROM t1; } {1 10 pax 2 happy pax 3 {} pax} do_execsql_test 1.2 { INSERT INTO t1(b,c) VALUES(5,99) RETURNING b,c,a,rowid; } {5 99 4 4} do_execsql_test 1.3 { SELECT * FROM t1; } {1 10 pax 2 happy pax 3 {} pax 4 5 99} do_execsql_test 1.4 { INSERT INTO t1 DEFAULT VALUES RETURNING *; } {5 {} pax} do_execsql_test 1.5 { SELECT * FROM t1; } {1 10 pax 2 happy pax 3 {} pax 4 5 99 5 {} pax} do_execsql_test 1.6 { CREATE TABLE t2(x,y,z); INSERT INTO t2 VALUES(11,12,13),(21,'b','c'),(31,'b-value',4.75); } do_execsql_test 1.7 { INSERT INTO t1 SELECT * FROM t2 RETURNING *; } {11 12 13 21 b c 31 b-value 4.75} do_execsql_test 1.8 { SELECT *, '|' FROM t1; } {1 10 pax | 2 happy pax | 3 {} pax | 4 5 99 | 5 {} pax | 11 12 13 | 21 b c | 31 b-value 4.75 |} do_execsql_test 2.1 { UPDATE t1 SET c='bellum' WHERE c='pax' RETURNING rowid, b, '|'; } {1 10 | 2 happy | 3 {} | 5 {} |} do_execsql_test 2.2 { SELECT *, '|' FROM t1; } {1 10 bellum | 2 happy bellum | 3 {} bellum | 4 5 99 | 5 {} bellum | 11 12 13 | 21 b c | 31 b-value 4.75 |} do_execsql_test 3.1 { DELETE FROM t1 WHERE c='bellum' RETURNING rowid, *, '|'; } {1 1 10 bellum | 2 2 happy bellum | 3 3 {} bellum | 5 5 {} bellum |} do_execsql_test 3.2 { SELECT *, '|' FROM t1; } {4 5 99 | 11 12 13 | 21 b c | 31 b-value 4.75 |} do_execsql_test 4.1 { CREATE TABLE t4(a INT, b INT DEFAULT 1234, c INT DEFAULT -16); CREATE UNIQUE INDEX t4a ON t4(a); INSERT INTO t4(a,b,c) VALUES(1,2,3); } {} do_execsql_test 4.2 { INSERT INTO t4(a,b,c) VALUES(1,22,33) ON CONFLICT(a) DO UPDATE SET b=44 RETURNING *; } {1 44 3} do_execsql_test 4.3 { SELECT * FROM t4; } {1 44 3} do_execsql_test 4.4 { DELETE FROM t4; INSERT INTO t4 VALUES(1,2,3),(4,5,6),(7,8,9); } {} do_execsql_test 4.5 { INSERT INTO t4(a,b,c) VALUES(2,3,4),(4,5,6),(5,6,7) ON CONFLICT(a) DO UPDATE SET b=100 RETURNING *, '|'; } {2 3 4 | 4 100 6 | 5 6 7 |} #------------------------------------------------------------------------- # Test RETURNING on a table with virtual columns. # reset_db do_execsql_test 5.0 { CREATE TABLE t1(xyz); CREATE TABLE t2(a as (1+1), b); } do_execsql_test 5.1 { UPDATE t2 SET b='123' WHERE b='abc' RETURNING (SELECT b FROM t1); } {} do_execsql_test 5.2 { INSERT INTO t2(b) VALUES('abc'); } do_execsql_test 5.3 { UPDATE t2 SET b='123' WHERE b='abc' RETURNING (SELECT b FROM t1); } {{}} do_execsql_test 5.4 { INSERT INTO t2(b) VALUES('abc'); INSERT INTO t1(xyz) VALUES(1); UPDATE t2 SET b='123' WHERE b='abc' RETURNING b; } {123} do_execsql_test 5.5 { INSERT INTO t2(b) VALUES('abc'); UPDATE t2 SET b='123' WHERE b='abc' RETURNING (SELECT b FROM t1); } {123} # Ticket 132994c8b1063bfb reset_db do_catchsql_test 6.0 { CREATE TABLE t1(id INTEGER PRIMARY KEY); CREATE TABLE t2(x INT, y INT); INSERT INTO t1 VALUES(1),(2),(4),(9); INSERT INTO t2 VALUES(3,7), (4,25), (5,99); UPDATE t1 SET id=id+y FROM t2 WHERE t1.id=t2.x RETURNING t2.*; } {1 {RETURNING may not use "TABLE.*" wildcards}} do_catchsql_test 6.1 { UPDATE t1 SET id=id+y FROM t2 WHERE t1.id=t2.x RETURNING *, '|'; SELECT * FROM t1 ORDER BY id; } {0 {29 | 1 2 9 29}} # Forum https://sqlite.org/forum/forumpost/85aef8bc01 # Do not silently ignore nonsense table names in the RETURNING clause. # Raise an error. # reset_db do_execsql_test 7.1 { CREATE TABLE t1(a INT, b INT); CREATE TABLE t2(x INT, y INT); INSERT INTO t1(a,b) VALUES(1,2); INSERT INTO t2(x,y) VALUES(1,30); } {} do_catchsql_test 7.2 { UPDATE t1 SET b=b+1 RETURNING new.b; } {1 {no such column: new.b}} do_catchsql_test 7.3 { UPDATE t1 SET b=b+1 RETURNING old.b; } {1 {no such column: old.b}} do_catchsql_test 7.4 { UPDATE t1 SET b=b+1 RETURNING another.b; } {1 {no such column: another.b}} do_catchsql_test 7.5 { UPDATE t1 SET b=b+y FROM t2 WHERE t2.x=t1.a RETURNING t2.x; } {1 {no such column: t2.x}} do_catchsql_test 7.6 { UPDATE t1 SET b=b+y FROM t2 WHERE t2.x=t1.a RETURNING t1.b; } {0 32} # This is goofy: The RETURNING clause does not honor the alias # for the table being modified. This might change in the future. # do_catchsql_test 7.7 { UPDATE t1 AS alias SET b=123 RETURNING alias.b; } {1 {no such column: alias.b}} do_catchsql_test 7.8 { UPDATE t1 AS alias SET b=alias.b+1000 RETURNING t1.b; } {0 1032} # Forum: https://sqlite.org/forum/info/34c81d83c9177f46 reset_db do_execsql_test 8.1 { CREATE TABLE t1(a); CREATE TABLE t2(b,c); INSERT INTO t1 VALUES(1); INSERT INTO t2 VALUES(3,40); } {} do_catchsql_test 8.2 { INSERT INTO t1 VALUES(3) RETURNING a, (SELECT c FROM t2 WHERE new.a=t2.b) AS x; } {1 {no such column: new.a}} do_catchsql_test 8.3 { INSERT INTO t1 VALUES(3) RETURNING a, (SELECT c FROM t2 WHERE old.a=t2.b) AS x; } {1 {no such column: old.a}} do_catchsql_test 8.4 { INSERT INTO t1 VALUES(3) RETURNING a, (SELECT c FROM t2 WHERE t1.a=t2.b) AS x; } {0 {3 40}} ifcapable vtab { # dbsqlfuzz finds/crash-486f791cbe2dc45839310073e71367a1d8ad22dd do_catchsql_test 9.1 { UPDATE pragma_encoding SET encoding='UTF-8' RETURNING a, b, *; } {1 {table pragma_encoding may not be modified}} } ;# ifcapable vtab # dbsqlfuzz crash-0081f863d7b2002045ac2361879fc80dfebb98f1 reset_db do_execsql_test 10.1 { CREATE TABLE t1_a(a, b); CREATE VIEW t1 AS SELECT a, b FROM t1_a; INSERT INTO t1_a VALUES('x', 'y'); INSERT INTO t1_a VALUES('x', 'y'); INSERT INTO t1_a VALUES('x', 'y'); CREATE TABLE log(op, r, a, b); } do_execsql_test 10.2 { CREATE TRIGGER tr1 INSTEAD OF INSERT ON t1 BEGIN INSERT INTO log VALUES('insert', new.rowid, new.a, new.b); END; CREATE TRIGGER tr2 INSTEAD OF UPDATE ON t1 BEGIN INSERT INTO log VALUES('update', new.rowid, new.a, new.b); END; } do_catchsql_test 10.3 { INSERT INTO t1(a, b) VALUES(1234, 5678) RETURNING rowid; } {1 {no such column: rowid}} do_catchsql_test 10.3 { UPDATE t1 SET a='z' WHERE b='y' RETURNING rowid; } {1 {no such column: rowid}} do_execsql_test 10.4 { SELECT * FROM log; } {} # 2021-04-27 dbsqlfuzz 78b9400770ef8cc7d9427dfba26f4fcf46ea7dc2 # Returning clauses on TEMP tables with triggers. # reset_db do_execsql_test 11.1 { CREATE TEMP TABLE t1(a,b); CREATE TEMP TABLE t2(c,d); CREATE TEMP TABLE t3(e,f); CREATE TEMP TABLE log(op,x,y); CREATE TEMP TRIGGER t1r1 AFTER INSERT ON t1 BEGIN INSERT INTO log(op,x,y) VALUES('I1',new.a,new.b); END; CREATE TEMP TRIGGER t1r2 BEFORE DELETE ON t1 BEGIN INSERT INTO log(op,x,y) VALUES('D1',old.a,old.b); END; CREATE TEMP TRIGGER t2r3 AFTER UPDATE ON t1 BEGIN INSERT INTO log(op,x,y) VALUES('U1',new.a,new.b); END; CREATE TEMP TRIGGER t2r1 BEFORE INSERT ON t2 BEGIN INSERT INTO log(op,x,y) VALUES('I2',new.c,new.d); END; CREATE TEMP TRIGGER t3r1 AFTER DELETE ON t3 BEGIN INSERT INTO log(op,x,y) VALUES('D3',old.e,old.f); END; CREATE TEMP TRIGGER t3r2 BEFORE UPDATE ON t3 BEGIN INSERT INTO log(op,x,y) VALUES('U3',new.e,new.f); END; INSERT INTO t1(a,b) VALUES(1,2),('happy','glad') RETURNING a, b, '|'; } {1 2 | happy glad |} do_execsql_test 11.2 { UPDATE t1 SET b=9 WHERE a=1 RETURNING a, b, 'x'; } {1 9 x} do_execsql_test 11.3 { DELETE FROM t1 WHERE a<>'xray' RETURNING a, b, '@'; } {1 9 @ happy glad @} do_execsql_test 11.4 { SELECT * FROM log; DELETE FROM log; } {I1 1 2 I1 happy glad U1 1 9 D1 1 9 D1 happy glad} do_execsql_test 11.5 { INSERT INTO t2 VALUES('bravo','charlie') RETURNING d, c, 'z'; } {charlie bravo z} do_execsql_test 11.6 { SELECT * FROM log; DELETE FROM log; } {I2 bravo charlie} do_execsql_test 11.7 { INSERT INTO t3(e) VALUES(1),(2),(3) RETURNING 'I', e; UPDATE t3 SET f=e+100 RETURNING 'U', e, f; DELETE FROM t3 WHERE f>100 RETURNING 'D', e, f; } {I 1 I 2 I 3 U 1 101 U 2 102 U 3 103 D 1 101 D 2 102 D 3 103} do_execsql_test 11.6 { SELECT * FROM log; DELETE FROM log; } {U3 1 101 U3 2 102 U3 3 103 D3 1 101 D3 2 102 D3 3 103} reset_db do_execsql_test 11.11 { CREATE TEMP TABLE t1(a,b); CREATE TRIGGER r1 BEFORE INSERT ON t1 BEGIN SELECT 1; END; DELETE FROM t1 RETURNING *; DROP TRIGGER r1; INSERT INTO t1 VALUES(5,30); } {} do_execsql_test 11.12 { SELECT * FROM t1; } {5 30} # RETURNING column names are dequoted. # https://sqlite.org/forum/forumpost/033daf0b32 # reset_db do_test 12.1 { db eval {CREATE TABLE t1(x INT, y INT)} unset -nocomplain cname db eval {INSERT INTO t1(x) VALUES(1) RETURNING "x";} cname {} lsort [array names cname] } {* x} do_test 12.2 { unset -nocomplain cname db eval {INSERT INTO t1(x) VALUES(2) RETURNING [x];} cname {} lsort [array names cname] } {* x} do_test 12.3 { unset -nocomplain cname db eval {INSERT INTO t1(x) VALUES(3) RETURNING x AS [xyz];} cname {} lsort [array names cname] } {* xyz} do_test 12.4 { unset -nocomplain cname db eval {INSERT INTO t1(x,y) VALUES(4,5) RETURNING "x"+"y";} cname {} lsort [array names cname] } {{"x"+"y"} *} ifcapable rtree { #------------------------------------------------------------------------- # Based on dbsqlfuzz find crash-ffbba524cac354b2a61bfd677cec9d2a4333f49a reset_db do_execsql_test 13.0 { CREATE VIRTUAL TABLE t1 USING rtree(a, b, c); CREATE TABLE t2(x); } do_execsql_test 13.1 { INSERT INTO t1(a,b,c) VALUES(1,2,3) RETURNING (SELECT b FROM t2); } {{}} } ;# end ifcapable rtree finish_test |
Changes to test/rollback2.test.
︙ | ︙ | |||
97 98 99 100 101 102 103 | } #-------------------------------------------------------------------- # Try with some index scans # do_eqp_test 3.1 { SELECT i FROM t1 WHERE (i%2)==0 ORDER BY h DESC; | | | 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 | } #-------------------------------------------------------------------- # Try with some index scans # do_eqp_test 3.1 { SELECT i FROM t1 WHERE (i%2)==0 ORDER BY h DESC; } {SCAN t1 USING INDEX i1} do_rollback_test 3.2 -setup { BEGIN; DELETE FROM t1 WHERE (i%2)==1; } -select { SELECT i FROM t1 WHERE (i%2)==0 ORDER BY h DESC; } -result { 40 38 36 34 32 30 28 26 24 22 20 18 16 14 12 10 8 6 4 2 |
︙ | ︙ | |||
127 128 129 130 131 132 133 | # Now with some index scans that feature overflow keys. # set leader [string repeat "abcdefghij" 70] do_execsql_test 4.1 { UPDATE t1 SET h = $leader || h; } do_eqp_test 4.2 { SELECT i FROM t1 WHERE (i%2)==0 ORDER BY h ASC; | | | 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 | # Now with some index scans that feature overflow keys. # set leader [string repeat "abcdefghij" 70] do_execsql_test 4.1 { UPDATE t1 SET h = $leader || h; } do_eqp_test 4.2 { SELECT i FROM t1 WHERE (i%2)==0 ORDER BY h ASC; } {SCAN t1 USING INDEX i1} do_rollback_test 4.3 -setup { BEGIN; DELETE FROM t1 WHERE (i%2)==1; } -select { SELECT i FROM t1 WHERE (i%2)==0 ORDER BY h ASC; } -result { 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 |
︙ | ︙ |
Added test/round1.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 | # 2019-05-24 # # 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 rounding behavior of floating point values. # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix round1 expr srand(0) unset -nocomplain iTest for {set iTest 1} {$iTest<=50000} {incr iTest} { set x1 [expr int(rand()*100000)] set x2 [expr int(rand()*100000)+1000*int(rand()*10000)] set n [expr int(rand()*8)+1] set x3 [string range [format %09d $x2] [expr {9-$n}] end] set r $x1.$x3 set ans [string trimright $r 0] if {[string match *. $ans]} {set ans ${ans}0} do_test $iTest/$n/${r}4=>$ans { set x [db one "SELECT round(${r}4,$n)"] } $ans set x4 [string range [format %09d [expr {$x2+1}]] [expr {9-$n}] end] if {[string trim $x3 9]==""} {incr x1} set r2 $x1.$x4 set ans [string trimright $r2 0] if {[string match *. $ans]} {set ans ${ans}0} do_test $iTest/$n/${r}5=>$ans { set x [db one "SELECT round(${r}5,$n)"] } $ans } finish_test |
Changes to test/rowid.test.
︙ | ︙ | |||
14 15 16 17 18 19 20 21 22 23 24 25 26 27 | # # EVIDENCE-OF: R-36924-43758 By default, every row in SQLite has a # special column, usually called the "rowid", that uniquely identifies # that row within the table. set testdir [file dirname $argv0] source $testdir/tester.tcl # Basic ROWID functionality tests. # do_test rowid-1.1 { execsql { CREATE TABLE t1(x int, y int); INSERT INTO t1 VALUES(1,2); | > | 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | # # EVIDENCE-OF: R-36924-43758 By default, every row in SQLite has a # special column, usually called the "rowid", that uniquely identifies # that row within the table. set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix rowid # Basic ROWID functionality tests. # do_test rowid-1.1 { execsql { CREATE TABLE t1(x int, y int); INSERT INTO t1 VALUES(1,2); |
︙ | ︙ | |||
655 656 657 658 659 660 661 662 663 664 665 666 667 668 | do_test rowid-11.3 { execsql {SELECT rowid, a FROM t5 WHERE rowid<'abc'} } {1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8} do_test rowid-11.4 { execsql {SELECT rowid, a FROM t5 WHERE rowid<='abc'} } {1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8} # Test the automatic generation of rowids when the table already contains # a rowid with the maximum value. # # Once the maximum rowid is taken, rowids are normally chosen at # random. By by reseting the random number generator, we can cause # the rowid guessing loop to collide with prior rowids, and test the # loop out to its limit of 100 iterations. After 100 collisions, the | > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | do_test rowid-11.3 { execsql {SELECT rowid, a FROM t5 WHERE rowid<'abc'} } {1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8} do_test rowid-11.4 { execsql {SELECT rowid, a FROM t5 WHERE rowid<='abc'} } {1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8} do_test rowid-11.asc.1 { execsql {SELECT rowid, a FROM t5 WHERE rowid>'abc' ORDER BY 1 ASC} } {} do_test rowid-11.asc.2 { execsql {SELECT rowid, a FROM t5 WHERE rowid>='abc' ORDER BY 1 ASC} } {} do_test rowid-11.asc.3 { execsql {SELECT rowid, a FROM t5 WHERE rowid<'abc' ORDER BY 1 ASC} } {1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8} do_test rowid-11.asc.4 { execsql {SELECT rowid, a FROM t5 WHERE rowid<='abc' ORDER BY 1 ASC} } {1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8} do_test rowid-11.desc.1 { execsql {SELECT rowid, a FROM t5 WHERE rowid>'abc' ORDER BY 1 DESC} } {} do_test rowid-11.desc.2 { execsql {SELECT rowid, a FROM t5 WHERE rowid>='abc' ORDER BY 1 DESC} } {} do_test rowid-11.desc.3 { execsql {SELECT rowid, a FROM t5 WHERE rowid<'abc' ORDER BY 1 DESC} } {8 8 7 7 6 6 5 5 4 4 3 3 2 2 1 1} do_test rowid-11.desc.4 { execsql {SELECT rowid, a FROM t5 WHERE rowid<='abc' ORDER BY 1 DESC} } {8 8 7 7 6 6 5 5 4 4 3 3 2 2 1 1} # Test the automatic generation of rowids when the table already contains # a rowid with the maximum value. # # Once the maximum rowid is taken, rowids are normally chosen at # random. By by reseting the random number generator, we can cause # the rowid guessing loop to collide with prior rowids, and test the # loop out to its limit of 100 iterations. After 100 collisions, the |
︙ | ︙ | |||
714 715 716 717 718 719 720 721 722 | db function addrow rowid_addrow_func do_execsql_test rowid-13.1 { CREATE TABLE t13(x); INSERT INTO t13(rowid,x) VALUES(1234,5); SELECT rowid, x, addrow(rowid+1000), '|' FROM t13 LIMIT 3; SELECT last_insert_rowid(); } {1234 5 2234 | 2234 4990756 3234 | 3234 10458756 4234 | 4234} finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | db function addrow rowid_addrow_func do_execsql_test rowid-13.1 { CREATE TABLE t13(x); INSERT INTO t13(rowid,x) VALUES(1234,5); SELECT rowid, x, addrow(rowid+1000), '|' FROM t13 LIMIT 3; SELECT last_insert_rowid(); } {1234 5 2234 | 2234 4990756 3234 | 3234 10458756 4234 | 4234} #------------------------------------------------------------------------- do_execsql_test rowid-14.0 { CREATE TABLE t14(x INTEGER PRIMARY KEY); INSERT INTO t14(x) VALUES (100); } do_execsql_test rowid-14.1 { SELECT * FROM t14 WHERE x < 'a' ORDER BY rowid ASC; } {100} do_execsql_test rowid-14.2 { SELECT * FROM t14 WHERE x < 'a' ORDER BY rowid DESC; } {100} do_execsql_test rowid-14.3 { DELETE FROM t14; SELECT * FROM t14 WHERE x < 'a' ORDER BY rowid ASC; } {} do_execsql_test rowid-14.4 { SELECT * FROM t14 WHERE x < 'a' ORDER BY rowid DESC; } {} reset_db do_execsql_test rowid-15.0 { PRAGMA reverse_unordered_selects=true; CREATE TABLE t1 (c0, c1); CREATE TABLE t2 (c0 INT UNIQUE); INSERT INTO t1(c0, c1) VALUES (0, 0), (0, NULL); INSERT INTO t2(c0) VALUES (1); } do_execsql_test rowid-15.1 { SELECT t2.c0, t1.c1 FROM t1, t2 WHERE (t2.rowid <= 'a') OR (t1.c0 <= t2.c0) LIMIT 100 } {1 {} 1 0} do_execsql_test rowid-15.2 { SELECT 1, NULL INTERSECT SELECT * FROM ( SELECT t2.c0, t1.c1 FROM t1, t2 WHERE ((t2.rowid <= 'a')) OR (t1.c0 <= t2.c0) ORDER BY 'a' DESC LIMIT 100 ); } {1 {}} #------------------------------------------------------------------------- # Check that an unqualified "rowid" can be used in join queries so long # as only one of the source objects has a rowid column. # reset_db do_execsql_test 16.0 { CREATE TABLE t1(x); CREATE TABLE t2(y PRIMARY KEY) WITHOUT ROWID; CREATE VIEW v1 AS SELECT x FROM t1; CREATE TABLE t3(z); INSERT INTO t1(rowid, x) VALUES(1, 1); INSERT INTO t2(y) VALUES(2); INSERT INTO t3(rowid, z) VALUES(3, 3); } do_execsql_test 16.1 { SELECT rowid FROM t1, t2; } {1} do_execsql_test 16.2 { SELECT rowid FROM t1, v1; } {1} do_execsql_test 16.3 { SELECT rowid FROM t3, v1; } {3} do_execsql_test 16.4 { SELECT rowid FROM t3, (SELECT 123); } {3} do_execsql_test 16.5 { SELECT rowid FROM t2, t1; } {1} do_execsql_test 16.6 { SELECT rowid FROM v1, t1; } {1} do_execsql_test 16.7 { SELECT rowid FROM v1, t3; } {3} do_execsql_test 16.8 { SELECT rowid FROM (SELECT 123), t3; } {3} do_catchsql_test 16.5 { SELECT rowid FROM t1, t3; } {1 {no such column: rowid}} finish_test |
Changes to test/rowvalue.test.
︙ | ︙ | |||
171 172 173 174 175 176 177 | INSERT INTO xy VALUES(3, 3, 3); INSERT INTO xy VALUES(4, 4, 4); } foreach {tn sql res eqp} { 1 "SELECT * FROM xy WHERE (i, j) IS (2, 2)" {2 2 2} | | | | | | | 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 | INSERT INTO xy VALUES(3, 3, 3); INSERT INTO xy VALUES(4, 4, 4); } foreach {tn sql res eqp} { 1 "SELECT * FROM xy WHERE (i, j) IS (2, 2)" {2 2 2} "SEARCH xy USING INTEGER PRIMARY KEY (rowid=?)" 2 "SELECT * FROM xy WHERE (k, j) < (2, 3)" {1 1 1 2 2 2} "SCAN xy" 3 "SELECT * FROM xy WHERE (i, j) < (2, 3)" {1 1 1 2 2 2} "SEARCH xy USING INTEGER PRIMARY KEY (rowid<?)" 4 "SELECT * FROM xy WHERE (i, j) > (2, 1)" {2 2 2 3 3 3 4 4 4} "SEARCH xy USING INTEGER PRIMARY KEY (rowid>?)" 5 "SELECT * FROM xy WHERE (i, j) > ('2', 1)" {2 2 2 3 3 3 4 4 4} "SEARCH xy USING INTEGER PRIMARY KEY (rowid>?)" } { do_eqp_test 7.$tn.1 $sql $eqp do_execsql_test 7.$tn.2 $sql $res } do_execsql_test 8.0 { |
︙ | ︙ | |||
552 553 554 555 556 557 558 559 560 | # do_execsql_test 21.0 { DROP TABLE IF EXISTS t1; CREATE TABLE t1(a,b,PRIMARY KEY(b,b)); INSERT INTO t1 VALUES(1,2),(3,4),(5,6); SELECT * FROM t1 WHERE (a,b) IN (VALUES(1,2)); } {1 2} finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | # do_execsql_test 21.0 { DROP TABLE IF EXISTS t1; CREATE TABLE t1(a,b,PRIMARY KEY(b,b)); INSERT INTO t1 VALUES(1,2),(3,4),(5,6); SELECT * FROM t1 WHERE (a,b) IN (VALUES(1,2)); } {1 2} # 2019-08-09: Multi-column subquery on the RHS of an IN operator. # do_execsql_test 22.100 { SELECT (SELECT 3,4 UNION SELECT 5,6 ORDER BY 1) IN (SELECT 3,4); SELECT (SELECT 3,4 UNION SELECT 5,6 ORDER BY 1) IN (SELECT 5,6); SELECT (SELECT 5,6 UNION SELECT 3,4 ORDER BY 1) IN (SELECT 3,4); SELECT (SELECT 5,6 UNION SELECT 3,4 ORDER BY 1) IN (SELECT 5,6); SELECT (SELECT 3,4 UNION SELECT 5,6 ORDER BY 1 DESC) IN (SELECT 3,4); SELECT (SELECT 3,4 UNION SELECT 5,6 ORDER BY 1 DESC) IN (SELECT 5,6); SELECT (SELECT 5,6 UNION SELECT 3,4 ORDER BY 1 DESC) IN (SELECT 3,4); SELECT (SELECT 5,6 UNION SELECT 3,4 ORDER BY 1 DESC) IN (SELECT 5,6); } {1 0 1 0 0 1 0 1} # 2019-10-21 Ticket b47e3627ecaadbde # do_execsql_test 23.100 { DROP TABLE IF EXISTS t0; CREATE TABLE t0(aa COLLATE NOCASE, bb); INSERT INTO t0 VALUES('a', 'A'); SELECT (+bb,1) >= (aa, 1), (aa,1)<=(+bb,1) FROM t0; SELECT 2 FROM t0 WHERE (+bb,1) >= (aa,1); SELECT 3 FROM t0 WHERE (aa,1) <= (+bb,1); } {0 1 3} do_execsql_test 23.110 { SELECT (SELECT +bb,1) >= (aa, 1), (aa,1)<=(SELECT +bb,1) FROM t0; SELECT 2 FROM t0 WHERE (SELECT +bb,1) >= (aa,1); SELECT 3 FROM t0 WHERE (aa,1) <= (SELECT +bb,1); } {0 1 3} # 2019-10-22 Ticket 6ef984af8972c2eb do_execsql_test 24.100 { DROP TABLE t0; CREATE TABLE t0(c0 TEXT PRIMARY KEY); INSERT INTO t0(c0) VALUES (''); SELECT (t0.c0, TRUE) > (CAST(0 AS REAL), FALSE) FROM t0; SELECT 2 FROM t0 WHERE (t0.c0, TRUE) > (CAST('' AS REAL), FALSE); } {1 2} # 2019-10-23 Ticket 135c9da7513e5a97 do_execsql_test 25.10 { DROP TABLE t0; CREATE TABLE t0(c0 UNIQUE); INSERT INTO t0(c0) VALUES('a'); SELECT (t0.c0, 0) < ('B' COLLATE NOCASE, 0) FROM t0; SELECT 2 FROM t0 WHERE (t0.c0, 0) < ('B' COLLATE NOCASE, 0); } {1 2} do_execsql_test 25.20 { SELECT ('B' COLLATE NOCASE, 0)> (t0.c0, 0) FROM t0; SELECT 2 FROM t0 WHERE ('B' COLLATE NOCASE, 0)> (t0.c0, 0); } {1 2} do_execsql_test 25.30 { SELECT ('B', 0)> (t0.c0 COLLATE nocase, 0) FROM t0; SELECT 2 FROM t0 WHERE ('B', 0)> (t0.c0 COLLATE nocase, 0); } {1 2} do_execsql_test 25.40 { SELECT (t0.c0 COLLATE nocase, 0) < ('B', 0) FROM t0; SELECT 2 FROM t0 WHERE (t0.c0 COLLATE nocase, 0) < ('B', 0); } {1 2} # 2019-11-04 Ticket 02aa2bd02f97d0f2 # The TK_VECTOR operator messes up sqlite3ExprImpliesNonNull() which # causes incorrect LEFT JOIN strength reduction. TK_VECTOR should be # treated the same as TK_OR. # db close sqlite3 db :memory: do_execsql_test 26.10 { CREATE TABLE t0(c0); CREATE TABLE t1(c1); INSERT INTO t1(c1) VALUES (0); SELECT (c0, x'') != (NULL, 0) FROM t1 LEFT JOIN t0; } {1} do_execsql_test 26.20 { SELECT 2 FROM t1 LEFT JOIN t0 ON (c0, x'') != (NULL, 0); } {2} do_execsql_test 26.30 { SELECT 3 FROM t1 LEFT JOIN t0 WHERE (c0, x'') != (NULL, 0); } {3} # 2019-12-30 ticket 892575cdba4e1e36 # reset_db do_catchsql_test 27.10 { CREATE TABLE t0(c0 CHECK(((0, 0) > (0, c0)))); INSERT INTO t0(c0) VALUES(0) ON CONFLICT(c0) DO UPDATE SET c0 = 3; } {1 {ON CONFLICT clause does not match any PRIMARY KEY or UNIQUE constraint}} # 2021-02-03 # https://bugs.chromium.org/p/chromium/issues/detail?id=1173511 # Faulty assert() statement. # reset_db do_catchsql_test 28.10 { CREATE TABLE t0(c0 PRIMARY KEY, c1); CREATE TRIGGER trigger0 BEFORE DELETE ON t0 BEGIN SELECT (SELECT c0,c1 FROM t0) FROM t0; END ; DELETE FROM t0; } {1 {sub-select returns 2 columns - expected 1}} # 2021-03-19 # dbsqlfuzz find of a NEVER(). do_catchsql_test 29.1 { SELECT (SELECT 1 WHERE ((SELECT 1 WHERE (2,(2,0)) IS (2,(20))),(2,0)) IS (2,(20))) WHERE (2,(2,0)) IS (2 IN(SELECT 1 WHERE (2,(2,2,0)) IS (2,(20))),(20)); } {1 {row value misused}} #------------------------------------------------------------------------- reset_db do_execsql_test 30.0 { CREATE TABLE t1(x, y, z); CREATE TABLE t2(a, b); INSERT INTO t1 VALUES(1000, 2000, 3000); INSERT INTO t2 VALUES(NULL, NULL); } do_execsql_test 30.1 { UPDATE t2 SET (a,b)=( SELECT max( t1.x ) OVER( PARTITION BY sum( (SELECT t1.y) ) ), 2 ) FROM t1; } {} do_execsql_test 30.2 { SELECT * FROM t2 } {1000 2} reset_db do_execsql_test 30.3 { CREATE TABLE t1(x INT PRIMARY KEY, y, z); CREATE TABLE t2(a,b,c,d,e,PRIMARY KEY(a,b))WITHOUT ROWID; UPDATE t2 SET (d,d,a)=(SELECT EXISTS(SELECT 1 IN(SELECT max( 1 IN(SELECT x ORDER BY 1)) OVER(PARTITION BY sum((SELECT y FROM t1 UNION SELECT x ORDER BY 1)))INTERSECT SELECT EXISTS(SELECT 1 FROM t1 UNION SELECT x ORDER BY 1) ORDER BY 1) ORDERa)|9 AS blob, 2, 3) FROM t1 WHERE x<a; } finish_test |
Changes to test/rowvalue4.test.
︙ | ︙ | |||
181 182 183 184 185 186 187 | CREATE INDEX c1ab ON c1(a, b); CREATE INDEX c1cd ON c1(c, d); ANALYZE; } do_eqp_test 3.1.1 { SELECT * FROM c1 WHERE a=1 AND c=2 } \ | | | | | | | | | | | 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 | CREATE INDEX c1ab ON c1(a, b); CREATE INDEX c1cd ON c1(c, d); ANALYZE; } do_eqp_test 3.1.1 { SELECT * FROM c1 WHERE a=1 AND c=2 } \ {SEARCH c1 USING INDEX c1cd (c=?)} do_eqp_test 3.1.2 { SELECT * FROM c1 WHERE a=1 AND b>'d' AND c=2 } \ {SEARCH c1 USING INDEX c1cd (c=?)} do_eqp_test 3.1.3 { SELECT * FROM c1 WHERE a=1 AND b>'l' AND c=2 } \ {SEARCH c1 USING INDEX c1ab (a=? AND b>?)} do_eqp_test 3.2.1 { SELECT * FROM c1 WHERE a=1 AND c>1 } \ {SEARCH c1 USING INDEX c1cd (c>?)} do_eqp_test 3.2.2 { SELECT * FROM c1 WHERE a=1 AND c>0 } \ {SEARCH c1 USING INDEX c1ab (a=?)} do_eqp_test 3.2.3 { SELECT * FROM c1 WHERE a=1 AND c>=1 } \ {SEARCH c1 USING INDEX c1ab (a=?)} do_eqp_test 3.2.4 { SELECT * FROM c1 WHERE a=1 AND (c, d)>(1, 'c') } \ {SEARCH c1 USING INDEX c1ab (a=?)} do_eqp_test 3.2.5 { SELECT * FROM c1 WHERE a=1 AND (c, d)>(1, 'o') } \ {SEARCH c1 USING INDEX c1cd ((c,d)>(?,?))} do_eqp_test 3.2.6 { SELECT * FROM c1 WHERE a=1 AND (c, +b)>(1, 'c') } \ {SEARCH c1 USING INDEX c1ab (a=?)} } #------------------------------------------------------------------------ do_execsql_test 5.0 { CREATE TABLE d1(x, y); |
︙ | ︙ | |||
230 231 232 233 234 235 236 | do_eqp_test 5.1 { SELECT * FROM d2 WHERE (a, b) IN (SELECT x, y FROM d1) AND (c) IN (SELECT y FROM d1) } { QUERY PLAN | | | | | | | | | | | | 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 | do_eqp_test 5.1 { SELECT * FROM d2 WHERE (a, b) IN (SELECT x, y FROM d1) AND (c) IN (SELECT y FROM d1) } { QUERY PLAN |--SEARCH d2 USING INDEX d2ab (a=? AND b=?) |--LIST SUBQUERY xxxxxx | `--SCAN d1 `--LIST SUBQUERY xxxxxx `--SCAN d1 } do_execsql_test 6.0 { CREATE TABLE e1(a, b, c, d, e); CREATE INDEX e1ab ON e1(a, b); CREATE INDEX e1cde ON e1(c, d, e); } do_eqp_test 6.1 { SELECT * FROM e1 WHERE (a, b) > (?, ?) } {SEARCH e1 USING INDEX e1ab ((a,b)>(?,?))} do_eqp_test 6.2 { SELECT * FROM e1 WHERE (a, b) < (?, ?) } {SEARCH e1 USING INDEX e1ab ((a,b)<(?,?))} do_eqp_test 6.3 { SELECT * FROM e1 WHERE c = ? AND (d, e) > (?, ?) } {SEARCH e1 USING INDEX e1cde (c=? AND (d,e)>(?,?))} do_eqp_test 6.4 { SELECT * FROM e1 WHERE c = ? AND (d, e) < (?, ?) } {SEARCH e1 USING INDEX e1cde (c=? AND (d,e)<(?,?))} do_eqp_test 6.5 { SELECT * FROM e1 WHERE (d, e) BETWEEN (?, ?) AND (?, ?) AND c = ? } {SEARCH e1 USING INDEX e1cde (c=? AND (d,e)>(?,?) AND (d,e)<(?,?))} #------------------------------------------------------------------------- do_execsql_test 7.1 { CREATE TABLE f1(a, b, c); CREATE INDEX f1ab ON f1(a, b); } |
︙ | ︙ |
Changes to test/rowvalue7.test.
︙ | ︙ | |||
51 52 53 54 55 56 57 58 | UPDATE t1 SET (c,d) = (SELECT x,y,z FROM t2 WHERE w=a); } {1 {2 columns assigned 3 values}} do_catchsql_test 2.2 { UPDATE t1 SET (b,c,d) = (SELECT x,y FROM t2 WHERE w=a); } {1 {3 columns assigned 2 values}} finish_test | > > > > > > > > > > | 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | UPDATE t1 SET (c,d) = (SELECT x,y,z FROM t2 WHERE w=a); } {1 {2 columns assigned 3 values}} do_catchsql_test 2.2 { UPDATE t1 SET (b,c,d) = (SELECT x,y FROM t2 WHERE w=a); } {1 {3 columns assigned 2 values}} # 2019-08-26 # ticket https://www.sqlite.org/src/info/78acc9d40f0786e8 # do_catchsql_test 3.0 { DROP TABLE IF EXISTS t1; CREATE TABLE t1(a,b); INSERT INTO t1 VALUES(1,2); UPDATE t1 SET (a,a,a,b)=(SELECT 99,100); } {1 {4 columns assigned 2 values}} finish_test |
Changes to test/rowvalue9.test.
︙ | ︙ | |||
293 294 295 296 297 298 299 | do_execsql_test 7.3 { SELECT * FROM g2 WHERE (x, y) IN ( SELECT a, b FROM g1 ORDER BY 1, 2 LIMIT 10 ); } { 1 4 1 5 } | > | > > > > > > > > > > > > | 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 | do_execsql_test 7.3 { SELECT * FROM g2 WHERE (x, y) IN ( SELECT a, b FROM g1 ORDER BY 1, 2 LIMIT 10 ); } { 1 4 1 5 } #------------------------------------------------------------------------- # do_execsql_test 8.1 { CREATE TABLE t1(a ,b FLOAT); CREATE INDEX t1x1 ON t1(a,b,a,a,a,a,a,a,a,a,a,b); } do_catchsql_test 8.2 { SELECT a FROM t1 NATURAL JOIN t1 WHERE (a,b)> (SELECT 2 IN (SELECT 2,2), 2); } {1 {sub-select returns 2 columns - expected 1}} finish_test |
Added test/rowvalueA.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 | # 2021 July 6 # # 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. # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix rowvalueA do_execsql_test 1.0 { SELECT (1, 2) IN ( (3, 4), (5, 6), (1, 3) ); } {0} do_execsql_test 1.1 { SELECT (1, 2) IN ( (3, 4), (5, 6), (1, 2) ); } {1} do_execsql_test 1.2 { SELECT (1, 2) IN ( (3, 2) ); } {0} do_execsql_test 1.3 { SELECT (1, 2) IN ( (1, 2) ); } {1} do_execsql_test 1.4 { SELECT (1, 2) IN ( ); } {0} do_execsql_test 1.5 { SELECT (1, 2) NOT IN ( ); } {1} for {set ii 0} {$ii < 2000} {incr ii} { lappend L "($ii, $ii)" } do_execsql_test 1.6.1 " SELECT (400,400) IN ( [join $L ,] ) " 1 do_execsql_test 1.6.2 " SELECT (1500,1500) IN ( [join $L ,] ) " 1 do_execsql_test 1.6.2 " SELECT (1500,1499) IN ( [join $L ,] ) " 0 #------------------------------------------------------------------------- do_catchsql_test 2.0 { SELECT (1, 2) IN ( (1, 2), (3, 4, 5), (5, 6) ) } {1 {IN(...) element has 3 terms - expected 2}} do_catchsql_test 2.1 { SELECT (1, 2) IN ( (1, 2), 4, (5, 6) ) } {1 {IN(...) element has 1 term - expected 2}} do_catchsql_test 2.2 { SELECT (1, 2, 3) IN ( (1, 2), (3, 4), (5, 6) ) } {1 {IN(...) element has 2 terms - expected 3}} do_catchsql_test 2.3 { SELECT 2 IN ( (1, 2), (3, 4), (5, 6) ) } {1 {row value misused}} finish_test |
Changes to test/rowvaluefault.test.
︙ | ︙ | |||
63 64 65 66 67 68 69 70 71 | do_faultsim_test 6 -faults oom* -body { execsql { SELECT fou FROM xyz WHERE (one, two, thr) BETWEEN ('B', 'B', 'B') AND ('C', 'C', 'C') } } -test { faultsim_test_result {0 {2 3}} } finish_test | > > > > > > > > > > > > > > > > > > | 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 | do_faultsim_test 6 -faults oom* -body { execsql { SELECT fou FROM xyz WHERE (one, two, thr) BETWEEN ('B', 'B', 'B') AND ('C', 'C', 'C') } } -test { faultsim_test_result {0 {2 3}} } do_faultsim_test 7 -faults oom* -body { execsql { SELECT fou FROM xyz WHERE (one, two, thr) IN ( ('a','b','c'), ('A','A','A'), (1,2,3) ); } } -test { faultsim_test_result {0 1} } do_faultsim_test 8 -faults oom* -body { execsql { SELECT fou FROM xyz WHERE (two, one) IN ( ('a','b','c'), ('A','A','A'), (1,2,3) ); } } -test { faultsim_test_result {1 {IN(...) element has 3 terms - expected 2}} } finish_test |
Added test/rowvaluevtab.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 | # 2018 October 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. # #*********************************************************************** # set testdir [file dirname $argv0] source $testdir/tester.tcl set ::testprefix rowvaluevtab ifcapable !vtab { finish_test return } register_echo_module db do_execsql_test 1.0 { CREATE TABLE t1(a, b, c); CREATE INDEX t1b ON t1(b); INSERT INTO t1 VALUES('one', 1, 1); INSERT INTO t1 VALUES('two', 1, 2); INSERT INTO t1 VALUES('three', 1, 3); INSERT INTO t1 VALUES('four', 2, 1); INSERT INTO t1 VALUES('five', 2, 2); INSERT INTO t1 VALUES('six', 2, 3); INSERT INTO t1 VALUES('seven', 3, 1); INSERT INTO t1 VALUES('eight', 3, 2); INSERT INTO t1 VALUES('nine', 3, 3); WITH s(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<10000 ) INSERT INTO t1 SELECT NULL, NULL, NULL FROM s; CREATE VIRTUAL TABLE e1 USING echo(t1); } proc do_vfilter4_test {tn sql expected} { set res [list] db eval "explain $sql" { if {$opcode=="VFilter"} { lappend res $p4 } } uplevel [list do_test $tn [list set {} $res] [list {*}$expected]] } do_execsql_test 1.1 { SELECT a FROM e1 WHERE (b, c) = (2, 2) } {five} do_vfilter4_test 1.1f { SELECT a FROM e1 WHERE (b, c) = (?, ?) } {{SELECT rowid, a, b, c FROM 't1' WHERE b = ?}} do_execsql_test 1.2 { SELECT a FROM e1 WHERE (b, c) > (2, 2) } {six seven eight nine} do_vfilter4_test 1.2f { SELECT a FROM e1 WHERE (b, c) > (2, 2) } { {SELECT rowid, a, b, c FROM 't1' WHERE b >= ?} } do_execsql_test 1.3 { SELECT a FROM e1 WHERE (b, c) >= (2, 2) } {five six seven eight nine} do_vfilter4_test 1.3f { SELECT a FROM e1 WHERE (b, c) >= (2, 2) } { {SELECT rowid, a, b, c FROM 't1' WHERE b >= ?} } do_execsql_test 1.3 { SELECT a FROM e1 WHERE (b, c) BETWEEN (1, 2) AND (2, 3) } {two three four five six} do_vfilter4_test 1.3f { SELECT a FROM e1 WHERE (b, c) BETWEEN (1, 2) AND (2, 3) } { {SELECT rowid, a, b, c FROM 't1' WHERE b >= ? AND b <= ?} } do_execsql_test 1.4 { SELECT a FROM e1 WHERE (b, c) IN ( VALUES(2, 2) ) } {five} do_vfilter4_test 1.4f { SELECT a FROM e1 WHERE (b, c) IN ( VALUES(2, 2) ) } {{SELECT rowid, a, b, c FROM 't1' WHERE b = ?}} finish_test |
Changes to test/scanstatus.test.
︙ | ︙ | |||
41 42 43 44 45 46 47 | } uplevel [list do_test $tn [list set {} $ret] [list {*}$res]] } do_execsql_test 1.1 { SELECT count(*) FROM t1, t2; } 6 do_scanstatus_test 1.2 { | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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 | } uplevel [list do_test $tn [list set {} $ret] [list {*}$res]] } do_execsql_test 1.1 { SELECT count(*) FROM t1, t2; } 6 do_scanstatus_test 1.2 { nLoop 1 nVisit 2 nEst 1048576.0 zName t1 zExplain {SCAN t1} nLoop 2 nVisit 6 nEst 1048576.0 zName t2 zExplain {SCAN t2} } do_execsql_test 1.3 { ANALYZE; SELECT count(*) FROM t1, t2; } 6 do_scanstatus_test 1.4 { nLoop 1 nVisit 2 nEst 2.0 zName t1 zExplain {SCAN t1} nLoop 2 nVisit 6 nEst 3.0 zName t2 zExplain {SCAN t2} } do_execsql_test 1.5 { ANALYZE } do_execsql_test 1.6 { SELECT count(*) FROM t1, t2 WHERE t2.rowid>1; } 4 do_scanstatus_test 1.7 { nLoop 1 nVisit 2 nEst 2.0 zName t2 zExplain {SEARCH t2 USING INTEGER PRIMARY KEY (rowid>?)} nLoop 2 nVisit 4 nEst 2.0 zName t1 zExplain {SCAN t1} } do_execsql_test 1.8 { SELECT count(*) FROM t1, t2 WHERE t2.rowid>1; } 4 do_scanstatus_test 1.9 { nLoop 2 nVisit 4 nEst 2.0 zName t2 zExplain {SEARCH t2 USING INTEGER PRIMARY KEY (rowid>?)} nLoop 4 nVisit 8 nEst 2.0 zName t1 zExplain {SCAN t1} } do_test 1.9 { sqlite3_stmt_scanstatus_reset [db version -last-stmt-ptr] } {} do_scanstatus_test 1.10 { nLoop 0 nVisit 0 nEst 2.0 zName t2 zExplain {SEARCH t2 USING INTEGER PRIMARY KEY (rowid>?)} nLoop 0 nVisit 0 nEst 2.0 zName t1 zExplain {SCAN t1} } #------------------------------------------------------------------------- # Try a few different types of scans. # reset_db do_execsql_test 2.1 { CREATE TABLE x1(i INTEGER PRIMARY KEY, j); INSERT INTO x1 VALUES(1, 'one'); INSERT INTO x1 VALUES(2, 'two'); INSERT INTO x1 VALUES(3, 'three'); INSERT INTO x1 VALUES(4, 'four'); CREATE INDEX x1j ON x1(j); SELECT * FROM x1 WHERE i=2; } {2 two} do_scanstatus_test 2.2 { nLoop 1 nVisit 1 nEst 1.0 zName x1 zExplain {SEARCH x1 USING INTEGER PRIMARY KEY (rowid=?)} } do_execsql_test 2.3.1 { SELECT * FROM x1 WHERE j='two' } {2 two} do_scanstatus_test 2.3.2 { nLoop 1 nVisit 1 nEst 10.0 zName x1j zExplain {SEARCH x1 USING COVERING INDEX x1j (j=?)} } do_execsql_test 2.4.1 { SELECT * FROM x1 WHERE j<'two' } {4 four 1 one 3 three} do_scanstatus_test 2.4.2 { nLoop 1 nVisit 3 nEst 262144.0 zName x1j zExplain {SEARCH x1 USING COVERING INDEX x1j (j<?)} } do_execsql_test 2.5.1 { SELECT * FROM x1 WHERE j>='two' } {2 two} do_scanstatus_test 2.5.2 { nLoop 1 nVisit 1 nEst 262144.0 zName x1j zExplain {SEARCH x1 USING COVERING INDEX x1j (j>?)} } do_execsql_test 2.6.1 { SELECT * FROM x1 WHERE j BETWEEN 'three' AND 'two' } {3 three 2 two} do_scanstatus_test 2.6.2 { nLoop 1 nVisit 2 nEst 16384.0 zName x1j zExplain {SEARCH x1 USING COVERING INDEX x1j (j>? AND j<?)} } do_execsql_test 2.7.1 { CREATE TABLE x2(i INTEGER, j, k); INSERT INTO x2 SELECT i, j, i || ' ' || j FROM x1; CREATE INDEX x2j ON x2(j); CREATE INDEX x2ij ON x2(i, j); SELECT * FROM x2 WHERE j BETWEEN 'three' AND 'two' } {3 three {3 three} 2 two {2 two}} do_scanstatus_test 2.7.2 { nLoop 1 nVisit 2 nEst 16384.0 zName x2j zExplain {SEARCH x2 USING INDEX x2j (j>? AND j<?)} } do_execsql_test 2.8.1 { SELECT * FROM x2 WHERE i=1 AND j='two' } do_scanstatus_test 2.8.2 { nLoop 1 nVisit 0 nEst 8.0 zName x2ij zExplain {SEARCH x2 USING INDEX x2ij (i=? AND j=?)} } do_execsql_test 2.9.1 { SELECT * FROM x2 WHERE i=5 AND j='two' } do_scanstatus_test 2.9.2 { nLoop 1 nVisit 0 nEst 8.0 zName x2ij zExplain {SEARCH x2 USING INDEX x2ij (i=? AND j=?)} } do_execsql_test 2.10.1 { SELECT * FROM x2 WHERE i=3 AND j='three' } {3 three {3 three}} do_scanstatus_test 2.10.2 { nLoop 1 nVisit 1 nEst 8.0 zName x2ij zExplain {SEARCH x2 USING INDEX x2ij (i=? AND j=?)} } #------------------------------------------------------------------------- # Try with queries that use the OR optimization. # do_execsql_test 3.1 { CREATE TABLE a1(a, b, c, d); CREATE INDEX a1a ON a1(a); CREATE INDEX a1bc ON a1(b, c); WITH d(x) AS (SELECT 1 UNION ALL SELECT x+1 AS n FROM d WHERE n<=100) INSERT INTO a1 SELECT x, x, x, x FROM d; } do_execsql_test 3.2.1 { SELECT d FROM a1 WHERE (a=4 OR b=13) } {4 13} do_scanstatus_test 3.2.2 { nLoop 1 nVisit 1 nEst 10.0 zName a1a zExplain {SEARCH a1 USING INDEX a1a (a=?)} nLoop 1 nVisit 1 nEst 10.0 zName a1bc zExplain {SEARCH a1 USING INDEX a1bc (b=?)} } do_execsql_test 3.2.1 { SELECT count(*) FROM a1 WHERE (a BETWEEN 4 AND 12) OR (b BETWEEN 40 AND 60) } {30} do_scanstatus_test 3.2.2 { nLoop 1 nVisit 9 nEst 16384.0 zName a1a zExplain {SEARCH a1 USING INDEX a1a (a>? AND a<?)} nLoop 1 nVisit 21 nEst 16384.0 zName a1bc zExplain {SEARCH a1 USING INDEX a1bc (b>? AND b<?)} } do_execsql_test 3.3.1 { SELECT count(*) FROM a1 AS x, a1 AS y WHERE (x.a BETWEEN 4 AND 12) AND (y.b BETWEEN 1 AND 10) } {90} do_scanstatus_test 3.2.2 { nLoop 1 nVisit 10 nEst 16384.0 zName a1bc zExplain {SEARCH y USING COVERING INDEX a1bc (b>? AND b<?)} nLoop 10 nVisit 90 nEst 16384.0 zName a1a zExplain {SEARCH x USING COVERING INDEX a1a (a>? AND a<?)} } do_execsql_test 3.4.1 { SELECT count(*) FROM a1 WHERE a IN (1, 5, 10, 15); } {4} do_scanstatus_test 3.4.2 { nLoop 1 nVisit 4 nEst 40.0 zName a1a zExplain {SEARCH a1 USING COVERING INDEX a1a (a=?)} } do_execsql_test 3.4.1 { SELECT count(*) FROM a1 WHERE rowid IN (1, 5, 10, 15); } {4} do_scanstatus_test 3.4.2 { nLoop 1 nVisit 4 nEst 4.0 zName a1 zExplain {SEARCH a1 USING INTEGER PRIMARY KEY (rowid=?)} } #------------------------------------------------------------------------- # Test that scanstatus() data is not available for searches performed # by triggers. # # It is available for searches performed as part of FK processing, but # not FK action processing. # do_execsql_test 4.0 { CREATE TABLE t1(a, b, c); CREATE TABLE t2(x PRIMARY KEY, y, z); CREATE TRIGGER tr1 AFTER INSERT ON t1 BEGIN SELECT * FROM t2 WHERE x BETWEEN 20 AND 40; END; WITH d(x) AS (SELECT 1 UNION ALL SELECT x+1 AS n FROM d WHERE n<=100) INSERT INTO t2 SELECT x, x*2, x*3 FROM d; } do_execsql_test 4.1.1 { INSERT INTO t1 VALUES(1, 2, 3); } do_scanstatus_test 4.1.2 {} do_execsql_test 4.2 { CREATE TABLE p1(x PRIMARY KEY); INSERT INTO p1 VALUES(1), (2), (3), (4); CREATE TABLE c1(y REFERENCES p1); INSERT INTO c1 VALUES(1), (2), (3); PRAGMA foreign_keys=on; } do_execsql_test 4.2.1 { DELETE FROM p1 WHERE x=4 } do_scanstatus_test 4.2.2 { nLoop 1 nVisit 1 nEst 1.0 zName sqlite_autoindex_p1_1 zExplain {SEARCH p1 USING INDEX sqlite_autoindex_p1_1 (x=?)} nLoop 1 nVisit 3 nEst 262144.0 zName c1 zExplain {SCAN c1} } #------------------------------------------------------------------------- # Further tests of different scan types. # reset_db proc tochar {i} { |
︙ | ︙ | |||
309 310 311 312 313 314 315 | } do_execsql_test 5.1.1 { SELECT count(*) FROM t1 WHERE a IN (SELECT b FROM t1 AS ii) } {2} do_scanstatus_test 5.1.2 { nLoop 1 nVisit 10 nEst 10.0 zName t1bc | | | | | | | | | | | | | | | 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 | } do_execsql_test 5.1.1 { SELECT count(*) FROM t1 WHERE a IN (SELECT b FROM t1 AS ii) } {2} do_scanstatus_test 5.1.2 { nLoop 1 nVisit 10 nEst 10.0 zName t1bc zExplain {SCAN ii USING COVERING INDEX t1bc} nLoop 1 nVisit 2 nEst 8.0 zName sqlite_autoindex_t1_1 zExplain {SEARCH t1 USING COVERING INDEX sqlite_autoindex_t1_1 (a=?)} } do_execsql_test 5.2.1 { SELECT count(*) FROM t1 WHERE a IN (0, 1) } {2} do_scanstatus_test 5.2.2 { nLoop 1 nVisit 2 nEst 2.0 zName sqlite_autoindex_t1_1 zExplain {SEARCH t1 USING COVERING INDEX sqlite_autoindex_t1_1 (a=?)} } do_eqp_test 5.3.1 { SELECT count(*) FROM t2 WHERE y = 'j'; } {SEARCH t2 USING COVERING INDEX t2xy (ANY(x) AND y=?)} do_execsql_test 5.3.2 { SELECT count(*) FROM t2 WHERE y = 'j'; } {19} do_scanstatus_test 5.3.3 { nLoop 1 nVisit 19 nEst 56.0 zName t2xy zExplain {SEARCH t2 USING COVERING INDEX t2xy (ANY(x) AND y=?)} } do_eqp_test 5.4.1 { SELECT count(*) FROM t1, t2 WHERE y = c; } { QUERY PLAN |--SCAN t1 USING COVERING INDEX t1bc `--SEARCH t2 USING COVERING INDEX t2xy (ANY(x) AND y=?) } do_execsql_test 5.4.2 { SELECT count(*) FROM t1, t2 WHERE y = c; } {200} do_scanstatus_test 5.4.3 { nLoop 1 nVisit 10 nEst 10.0 zName t1bc zExplain {SCAN t1 USING COVERING INDEX t1bc} nLoop 10 nVisit 200 nEst 56.0 zName t2xy zExplain {SEARCH t2 USING COVERING INDEX t2xy (ANY(x) AND y=?)} } do_eqp_test 5.5.1 { SELECT count(*) FROM t1, t3 WHERE y = c; } { QUERY PLAN |--SCAN t3 `--SEARCH t1 USING AUTOMATIC COVERING INDEX (c=?) } do_execsql_test 5.5.2 { SELECT count(*) FROM t1, t3 WHERE y = c; } {200} do_scanstatus_test 5.5.3 { nLoop 1 nVisit 501 nEst 480.0 zName t3 zExplain {SCAN t3} nLoop 501 nVisit 200 nEst 20.0 zName auto-index zExplain {SEARCH t1 USING AUTOMATIC COVERING INDEX (c=?)} } #------------------------------------------------------------------------- # Virtual table scans # ifcapable fts3 { do_execsql_test 6.0 { |
︙ | ︙ | |||
388 389 390 391 392 393 394 | INSERT INTO ft1 VALUES('a d e f b j j c g d'); } do_execsql_test 6.1.1 { SELECT count(*) FROM ft1 WHERE ft1 MATCH 'd' } {6} do_scanstatus_test 6.1.2 { nLoop 1 nVisit 6 nEst 24.0 zName ft1 zExplain | | | 388 389 390 391 392 393 394 395 396 397 398 399 400 | INSERT INTO ft1 VALUES('a d e f b j j c g d'); } do_execsql_test 6.1.1 { SELECT count(*) FROM ft1 WHERE ft1 MATCH 'd' } {6} do_scanstatus_test 6.1.2 { nLoop 1 nVisit 6 nEst 24.0 zName ft1 zExplain {SCAN ft1 VIRTUAL TABLE INDEX 3:} } } finish_test |
Changes to test/schema.test.
︙ | ︙ | |||
205 206 207 208 209 210 211 | do_test schema-7.4 { sqlite3_finalize $::STMT } {SQLITE_SCHEMA} } #--------------------------------------------------------------------- # Tests 8.1 and 8.2 check that prepared statements are invalidated when | | > > > | | > > > > > > > > > | 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 | do_test schema-7.4 { sqlite3_finalize $::STMT } {SQLITE_SCHEMA} } #--------------------------------------------------------------------- # Tests 8.1 and 8.2 check that prepared statements are invalidated when # the authorization function is set to a non-null function. Tests 8.11 # and 8.12 verify that no invalidations occur when the authorizer is # cleared. # ifcapable auth { proc noop_auth {args} {return SQLITE_OK} do_test schema-8.1 { set ::STMT [sqlite3_prepare $::DB {SELECT * FROM sqlite_master} -1 TAIL] db auth noop_auth sqlite3_step $::STMT } {SQLITE_ERROR} do_test schema-8.2 { sqlite3_finalize $::STMT } {SQLITE_SCHEMA} do_test schema-8.11 { set ::STMT [sqlite3_prepare $::DB {SELECT * FROM sqlite_master} -1 TAIL] db auth {} sqlite3_step $::STMT } {SQLITE_ROW} do_test schema-8.12 { sqlite3_finalize $::STMT } {SQLITE_OK} } #--------------------------------------------------------------------- # schema-9.1: Test that if a table is dropped by one database connection, # other database connections are aware of the schema change. # schema-9.2: Test that if a view is dropped by one database connection, # other database connections are aware of the schema change. |
︙ | ︙ |
Changes to test/schema3.test.
︙ | ︙ | |||
11 12 13 14 15 16 17 18 19 20 21 22 23 24 | # This file implements regression tests for SQLite library. # set testdir [file dirname $argv0] source $testdir/tester.tcl source $testdir/malloc_common.tcl source $testdir/lock_common.tcl # This block tests that if one client modifies the database schema, a # second client updates its internal cache of the database schema before # executing any queries. Specifically, it does not return a "no such column" # or "no such table" error if the table or column in question does exist # but was added after the second client loaded its cache of the database # schema. | > > > > > > | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | # This file implements regression tests for SQLite library. # set testdir [file dirname $argv0] source $testdir/tester.tcl source $testdir/malloc_common.tcl source $testdir/lock_common.tcl # If SQLITE_OMIT_ALTERTABLE is defined, omit this file. ifcapable !altertable { finish_test return } # This block tests that if one client modifies the database schema, a # second client updates its internal cache of the database schema before # executing any queries. Specifically, it does not return a "no such column" # or "no such table" error if the table or column in question does exist # but was added after the second client loaded its cache of the database # schema. |
︙ | ︙ |
Changes to test/select1.test.
︙ | ︙ | |||
1076 1077 1078 1079 1080 1081 1082 | catchsql {SELECT 1 FROM (SELECT *)} } {1 {no tables specified}} # 2015-04-17: assertion fix. do_catchsql_test select1-16.2 { SELECT 1 FROM sqlite_master LIMIT 1,#1; } {1 {near "#1": syntax error}} | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | catchsql {SELECT 1 FROM (SELECT *)} } {1 {no tables specified}} # 2015-04-17: assertion fix. do_catchsql_test select1-16.2 { SELECT 1 FROM sqlite_master LIMIT 1,#1; } {1 {near "#1": syntax error}} # 2019-01-16 Chromium bug 922312 # Sorting with a LIMIT clause using SRT_EphemTab and SRT_Table # do_execsql_test select1-17.1 { DROP TABLE IF EXISTS t1; DROP TABLE IF EXISTS t2; CREATE TABLE t1(x); INSERT INTO t1 VALUES(1); CREATE TABLE t2(y,z); INSERT INTO t2 VALUES(2,3); CREATE INDEX t2y ON t2(y); SELECT * FROM t1,(SELECT * FROM t2 WHERE y=2 ORDER BY y,z); } {1 2 3} do_execsql_test select1-17.2 { SELECT * FROM t1,(SELECT * FROM t2 WHERE y=2 ORDER BY y,z LIMIT 4); } {1 2 3} do_execsql_test select1-17.3 { SELECT * FROM t1,(SELECT * FROM t2 WHERE y=2 UNION ALL SELECT * FROM t2 WHERE y=3 ORDER BY y,z LIMIT 4); } {1 2 3} # 2019-07-24 Ticket https://sqlite.org/src/tktview/c52b09c7f38903b1311 # do_execsql_test select1-18.1 { DROP TABLE IF EXISTS t1; DROP TABLE IF EXISTS t2; CREATE TABLE t1(c); CREATE TABLE t2(x PRIMARY KEY, y); INSERT INTO t1(c) VALUES(123); INSERT INTO t2(x) VALUES(123); SELECT x FROM t2, t1 WHERE x BETWEEN c AND null OR x AND x IN ((SELECT x FROM (SELECT x FROM t2, t1 WHERE x BETWEEN (SELECT x FROM (SELECT x COLLATE rtrim FROM t2, t1 WHERE x BETWEEN c AND null OR x AND x IN (c)), t1 WHERE x BETWEEN c AND null OR x AND x IN (c)) AND null OR NOT EXISTS(SELECT -4.81 FROM t1, t2 WHERE x BETWEEN c AND null OR x AND x IN ((SELECT x FROM (SELECT x FROM t2, t1 WHERE x BETWEEN (SELECT x FROM (SELECT x BETWEEN c AND null OR x AND x IN (c)), t1 WHERE x BETWEEN c AND null OR x AND x IN (c)) AND null OR x AND x IN (c)), t1 WHERE x BETWEEN c AND null OR x AND x IN (c)))) AND x IN (c) ), t1 WHERE x BETWEEN c AND null OR x AND x IN (c))); } {} do_execsql_test select1-18.2 { DROP TABLE IF EXISTS t1; DROP TABLE IF EXISTS t2; CREATE TABLE t1(c); CREATE TABLE t2(x PRIMARY KEY, y); INSERT INTO t1(c) VALUES(123); INSERT INTO t2(x) VALUES(123); SELECT x FROM t2, t1 WHERE x BETWEEN c AND (c+1) OR x AND x IN ((SELECT x FROM (SELECT x FROM t2, t1 WHERE x BETWEEN (SELECT x FROM (SELECT x COLLATE rtrim FROM t2, t1 WHERE x BETWEEN c AND (c+1) OR x AND x IN (c)), t1 WHERE x BETWEEN c AND (c+1) OR x AND x IN (c)) AND (c+1) OR NOT EXISTS(SELECT -4.81 FROM t1, t2 WHERE x BETWEEN c AND (c+1) OR x AND x IN ((SELECT x FROM (SELECT x FROM t2, t1 WHERE x BETWEEN (SELECT x FROM (SELECT x BETWEEN c AND (c+1) OR x AND x IN (c)), t1 WHERE x BETWEEN c AND (c+1) OR x AND x IN (c)) AND (c+1) OR x AND x IN (c)), t1 WHERE x BETWEEN c AND (c+1) OR x AND x IN (c)))) AND x IN (c) ), t1 WHERE x BETWEEN c AND (c+1) OR x AND x IN (c))); } {123} do_execsql_test select1-18.3 { SELECT 1 FROM t1 WHERE ( SELECT 2 FROM t2 WHERE ( SELECT 3 FROM ( SELECT x FROM t2 WHERE x=c OR x=(SELECT x FROM (VALUES(0))) ) WHERE x>c OR x=c ) ); } {1} do_execsql_test select1-18.4 { SELECT 1 FROM t1, t2 WHERE ( SELECT 3 FROM ( SELECT x FROM t2 WHERE x=c OR x=(SELECT x FROM (VALUES(0))) ) WHERE x>c OR x=c ); } {1} # 2019-12-17 gramfuzz find # do_execsql_test select1-19.10 { DROP TABLE IF EXISTS t1; CREATE TABLE t1(x); } {} do_catchsql_test select1-19.20 { INSERT INTO t1 SELECT 1,2,3,4,5,6,7 UNION ALL SELECT 1,2,3,4,5,6,7 ORDER BY 1; } {1 {table t1 has 1 columns but 7 values were supplied}} do_catchsql_test select1-19.21 { INSERT INTO t1 SELECT 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 UNION ALL SELECT 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 ORDER BY 1; } {1 {table t1 has 1 columns but 15 values were supplied}} # 2020-01-01 Found by Yongheng's fuzzer # reset_db do_execsql_test select1-20.10 { CREATE TABLE t1 ( a INTEGER PRIMARY KEY, b AS('Y') UNIQUE ); INSERT INTO t1(a) VALUES (10); SELECT * FROM t1 JOIN t1 USING(a,b) WHERE ((SELECT t1.a FROM t1 AS x GROUP BY b) AND b=0) OR a = 10; } {10 Y} do_execsql_test select1-20.20 { SELECT ifnull(a, max((SELECT 123))), count(a) FROM t1 ; } {10 1} # 2020-10-02 dbsqlfuzz find reset_db do_execsql_test select1-21.1 { CREATE TABLE t1(a IMTEGES PRIMARY KEY,R); CREATE TABLE t2(x UNIQUE); CREATE VIEW v1a(z,y) AS SELECT x IS NULL, x FROM t2; SELECT a,(+a)b,(+a)b,(+a)b,NOT EXISTS(SELECT null FROM t2),CASE z WHEN 487 THEN 992 WHEN 391 THEN 203 WHEN 10 THEN '?k<D Q' END,'' FROM t1 LEFT JOIN v1a ON z=b; } {} finish_test |
Changes to test/select3.test.
︙ | ︙ | |||
256 257 258 259 260 261 262 263 264 | } } {real} do_test select3-8.2 { execsql { SELECT typeof(sum(a3)) FROM a GROUP BY a1; } } {real} finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | } } {real} do_test select3-8.2 { execsql { SELECT typeof(sum(a3)) FROM a GROUP BY a1; } } {real} # 2019-05-09 ticket https://www.sqlite.org/src/tktview/6c1d3febc00b22d457c7 # unset -nocomplain x foreach {id x} { 100 127 101 128 102 -127 103 -128 104 -129 110 32767 111 32768 112 -32767 113 -32768 114 -32769 120 2147483647 121 2147483648 122 -2147483647 123 -2147483648 124 -2147483649 130 140737488355327 131 140737488355328 132 -140737488355327 133 -140737488355328 134 -140737488355329 140 9223372036854775807 141 -9223372036854775807 142 -9223372036854775808 143 9223372036854775806 144 9223372036854775805 145 -9223372036854775806 146 -9223372036854775805 } { set x [expr {$x+0}] do_execsql_test select3-8.$id { DROP TABLE IF EXISTS t1; CREATE TABLE t1 (c0, c1 REAL PRIMARY KEY); INSERT INTO t1(c0, c1) VALUES (0, $x), (0, 0); UPDATE t1 SET c0 = NULL; UPDATE OR REPLACE t1 SET c1 = 1; SELECT DISTINCT * FROM t1 WHERE (t1.c0 IS NULL); PRAGMA integrity_check; } {{} 1.0 ok} } # 2020-03-10 ticket e0c2ad1aa8a9c691 reset_db do_execsql_test select3-9.100 { CREATE TABLE t0(c0 REAL, c1 REAL GENERATED ALWAYS AS (c0)); INSERT INTO t0(c0) VALUES (1); SELECT * FROM t0 GROUP BY c0; } {1.0 1.0} reset_db do_execsql_test select3.10.100 { CREATE TABLE t1(a, b); CREATE TABLE t2(c, d); SELECT max(t1.a), (SELECT 'xyz' FROM (SELECT * FROM t2 WHERE 0) WHERE t1.b=1) FROM t1; } {{} {}} finish_test |
Changes to test/select4.test.
︙ | ︙ | |||
1001 1002 1003 1004 1005 1006 1007 | SELECT a AS x, sum(b) AS y FROM t1 GROUP BY a LIMIT 3 UNION SELECT 98 AS x, 99 AS y ) AS w WHERE y>=20 ORDER BY +x; } {1 {LIMIT clause should come after UNION not before}} | > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | SELECT a AS x, sum(b) AS y FROM t1 GROUP BY a LIMIT 3 UNION SELECT 98 AS x, 99 AS y ) AS w WHERE y>=20 ORDER BY +x; } {1 {LIMIT clause should come after UNION not before}} # 2020-04-03 ticket 51166be0159fd2ce from Yong Heng. # Adverse interaction between the constant propagation and push-down # optimizations. # reset_db do_execsql_test select4-18.1 { CREATE VIEW v0(v0) AS WITH v0 AS(SELECT 0 v0) SELECT(SELECT min(v0) OVER()) FROM v0 GROUP BY v0; SELECT *FROM v0 v1 JOIN v0 USING(v0) WHERE datetime(v0) = (v0.v0)AND v0 = 10; } {} do_execsql_test select4-18.2 { CREATE VIEW t1(aa) AS WITH t2(bb) AS (SELECT 123) SELECT (SELECT min(bb) OVER()) FROM t2 GROUP BY bb; SELECT * FROM t1; } {123} do_execsql_test select4-18.3 { SELECT * FROM t1 AS z1 JOIN t1 AS z2 USING(aa) WHERE abs(z1.aa)=z2.aa AND z1.aa=123; } {123} # 2021-03-31 Fix an assert() problem in the logic at the end of sqlite3Select() # that validates AggInfo. The checks to ensure that AggInfo.aCol[].pCExpr # references a valid expression was looking at an expression that had been # deleted by the truth optimization in sqlite3ExprAnd() which was invoked by # the push-down optimization. This is harmless in delivery builds, as that code # only runs with SQLITE_DEBUG. But it should still be fixed. The problem # was discovered by dbsqlfuzz (crash-dece7b67a3552ed7e571a7bda903afd1f7bd9b21) # reset_db do_execsql_test select4-19.1 { CREATE TABLE t1(x); INSERT INTO t1 VALUES(99); SELECT sum((SELECT 1 FROM (SELECT 2 WHERE x IS NULL) WHERE 0)) FROM t1; } {{}} finish_test |
Changes to test/select5.test.
︙ | ︙ | |||
8 9 10 11 12 13 14 | # 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 aggregate functions and the # GROUP BY and HAVING clauses of SELECT statements. # | < | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | # 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 aggregate functions and the # GROUP BY and HAVING clauses of SELECT statements. # set testdir [file dirname $argv0] source $testdir/tester.tcl # Build some test data # execsql { |
︙ | ︙ | |||
247 248 249 250 251 252 253 | } {two 3 one 6} do_test select5-8.8 { execsql { SELECT a, count(*) FROM t8a, t8b GROUP BY a ORDER BY 2; } } {two 3 one 9} | | | > > > > > > | | 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 | } {two 3 one 6} do_test select5-8.8 { execsql { SELECT a, count(*) FROM t8a, t8b GROUP BY a ORDER BY 2; } } {two 3 one 9} # 2021-04-26 forum https://sqlite.org/forum/forumpost/74330094d8 reset_db do_execsql_test select5-9.1 { CREATE TABLE t1(a INT, b INT); INSERT INTO t1(a,b) VALUES(1,null),(null,null),(1,null); CREATE UNIQUE INDEX t1b ON t1(abs(b)); SELECT quote(a), quote(b), '|' FROM t1 GROUP BY a, abs(b); } {NULL NULL | 1 NULL |} finish_test |
Changes to test/select6.test.
︙ | ︙ | |||
8 9 10 11 12 13 14 | # 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 SELECT statements that contain # subqueries in their FROM clause. # | < | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | # 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 SELECT statements that contain # subqueries in their FROM clause. # set testdir [file dirname $argv0] source $testdir/tester.tcl # Omit this whole file if the library is build without subquery support. ifcapable !subquery { finish_test |
︙ | ︙ | |||
609 610 611 612 613 614 615 | DROP TABLE t2; CREATE TABLE t1(x); CREATE TABLE t2(y, z); SELECT ( SELECT y FROM t2 WHERE z = cnt ) FROM ( SELECT count(*) AS cnt FROM t1 ); } {{}} | > > | > > > > > > > > > > > > > > | 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 | DROP TABLE t2; CREATE TABLE t1(x); CREATE TABLE t2(y, z); SELECT ( SELECT y FROM t2 WHERE z = cnt ) FROM ( SELECT count(*) AS cnt FROM t1 ); } {{}} # 2019-05-29 ticket https://www.sqlite.org/src/info/c41afac34f15781f # A LIMIT clause in a subquery is incorrectly applied to a subquery. # do_execsql_test 12.100 { DROP TABLE t1; DROP TABLE t2; CREATE TABLE t1(a); INSERT INTO t1 VALUES(1); INSERT INTO t1 VALUES(2); CREATE TABLE t2(b); INSERT INTO t2 VALUES(3); SELECT * FROM ( SELECT * FROM (SELECT * FROM t1 LIMIT 1) UNION ALL SELECT * from t2); } {1 3} finish_test |
Changes to test/select9.test.
︙ | ︙ | |||
432 433 434 435 436 437 438 | UNION ALL SELECT x, y FROM t52; CREATE INDEX t51x ON t51(x); CREATE INDEX t52x ON t52(x); EXPLAIN QUERY PLAN SELECT * FROM v5 WHERE x='12345' ORDER BY y; } | | | | | 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 | UNION ALL SELECT x, y FROM t52; CREATE INDEX t51x ON t51(x); CREATE INDEX t52x ON t52(x); EXPLAIN QUERY PLAN SELECT * FROM v5 WHERE x='12345' ORDER BY y; } } {~/SCAN/} ;# Uses indices with "*" do_test select9-5.2 { db eval { EXPLAIN QUERY PLAN SELECT x, y FROM v5 WHERE x='12345' ORDER BY y; } } {~/SCAN/} ;# Uses indices with "x, y" do_test select9-5.3 { db eval { EXPLAIN QUERY PLAN SELECT x, y FROM v5 WHERE +x='12345' ORDER BY y; } } {/SCAN/} ;# Full table scan if the "+x" prevents index usage. # 2013-07-09: Ticket [490a4b7235624298]: # "WHERE 0" on the first element of a UNION causes an assertion fault # do_execsql_test select9-6.1 { CREATE TABLE t61(a); CREATE TABLE t62(b); |
︙ | ︙ |
Changes to test/selectA.test.
︙ | ︙ | |||
1335 1336 1337 1338 1339 1340 1341 | UNION ALL SELECT a, b FROM t4 WHERE f()==f() ORDER BY 1,2 } { QUERY PLAN `--MERGE (UNION ALL) |--LEFT | | | | 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 | UNION ALL SELECT a, b FROM t4 WHERE f()==f() ORDER BY 1,2 } { QUERY PLAN `--MERGE (UNION ALL) |--LEFT | |--SCAN t5 USING INDEX i2 | `--USE TEMP B-TREE FOR RIGHT PART OF ORDER BY `--RIGHT |--SCAN t4 USING INDEX i1 `--USE TEMP B-TREE FOR RIGHT PART OF ORDER BY } do_execsql_test 4.1.3 { SELECT c, d FROM t5 UNION ALL SELECT a, b FROM t4 WHERE f()==f() |
︙ | ︙ | |||
1442 1443 1444 1445 1446 1447 1448 | DROP TABLE IF EXISTS t2; CREATE TABLE t1(a INTEGER); CREATE TABLE t2(b TEXT); INSERT INTO t2(b) VALUES('12345'); SELECT * FROM (SELECT a FROM t1 UNION SELECT b FROM t2) WHERE a=a; } {12345} | > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | DROP TABLE IF EXISTS t2; CREATE TABLE t1(a INTEGER); CREATE TABLE t2(b TEXT); INSERT INTO t2(b) VALUES('12345'); SELECT * FROM (SELECT a FROM t1 UNION SELECT b FROM t2) WHERE a=a; } {12345} # 2020-06-15 ticket 8f157e8010b22af0 # reset_db do_execsql_test 7.1 { CREATE TABLE t1(c1); INSERT INTO t1 VALUES(12),(123),(1234),(NULL),('abc'); CREATE TABLE t2(c2); INSERT INTO t2 VALUES(44),(55),(123); CREATE TABLE t3(c3,c4); INSERT INTO t3 VALUES(66,1),(123,2),(77,3); CREATE VIEW t4 AS SELECT c3 FROM t3; CREATE VIEW t5 AS SELECT c3 FROM t3 ORDER BY c4; } do_execsql_test 7.2 { SELECT * FROM t1, t2 WHERE c1=(SELECT 123 INTERSECT SELECT c2 FROM t4) AND c1=123; } {123 123} do_execsql_test 7.3 { SELECT * FROM t1, t2 WHERE c1=(SELECT 123 INTERSECT SELECT c2 FROM t5) AND c1=123; } {123 123} do_execsql_test 7.4 { CREATE TABLE a(b); CREATE VIEW c(d) AS SELECT b FROM a ORDER BY b; SELECT sum(d) OVER( PARTITION BY(SELECT 0 FROM c JOIN a WHERE b =(SELECT b INTERSECT SELECT d FROM c) AND b = 123)) FROM c; } {} #------------------------------------------------------------------------- reset_db do_execsql_test 8.0 { CREATE TABLE x1(x); CREATE TABLE t1(a, b, c, d); CREATE INDEX t1a ON t1(a); CREATE INDEX t1b ON t1(b); } do_execsql_test 8.1 { SELECT 'ABCD' FROM t1 WHERE (a=? OR b=?) AND (0 OR (SELECT 'xyz' INTERSECT SELECT a ORDER BY 1)) } {} finish_test |
Changes to test/selectC.test.
︙ | ︙ | |||
257 258 259 260 261 262 263 | SELECT * FROM x1, x4 } { a 21 a 22 a 23 a 24 a 25 a 302 a 303 a 301 b 21 b 22 b 23 b 24 b 25 b 302 b 303 b 301 } do_execsql_test 5.3 { | | | | | 257 258 259 260 261 262 263 264 265 266 267 268 269 270 | SELECT * FROM x1, x4 } { a 21 a 22 a 23 a 24 a 25 a 302 a 303 a 301 b 21 b 22 b 23 b 24 b 25 b 302 b 303 b 301 } do_execsql_test 5.3 { SELECT * FROM x1, (SELECT b FROM vvv UNION ALL SELECT c from x3) ORDER BY 1,2; } { a 21 a 22 a 23 a 24 a 25 a 301 a 302 a 303 b 21 b 22 b 23 b 24 b 25 b 301 b 302 b 303 } finish_test |
Changes to test/selectD.test.
︙ | ︙ | |||
165 166 167 168 169 170 171 | 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; | | | 165 166 167 168 169 170 171 172 173 174 | 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 x2 USING AUTOMATIC/} finish_test |
Changes to test/sessionfuzz.c.
︙ | ︙ | |||
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 | " sessionfuzz run FILE ... -- Run against fuzzed changeset FILE\n" " sessionfuzz run SQLAR ... -- Run against all files in the SQL Archive\n" ; #include <stdio.h> #include <string.h> #include <assert.h> #include "zlib.h" /* ** Implementation of the "sqlar_uncompress(X,SZ)" SQL function ** ** Parameter SZ is interpreted as an integer. If it is less than or ** equal to zero, then this function returns a copy of X. Or, if ** SZ is equal to the size of X when interpreted as a blob, also ** return a copy of X. Otherwise, decompress blob X using zlib ** utility function uncompress() and return the results (another ** blob). */ static void sqlarUncompressFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ uLong nData; uLongf sz; assert( argc==2 ); sz = sqlite3_value_int(argv[1]); if( sz<=0 || sz==(nData = sqlite3_value_bytes(argv[0])) ){ sqlite3_result_value(context, argv[0]); }else{ const Bytef *pData= sqlite3_value_blob(argv[0]); Bytef *pOut = sqlite3_malloc(sz); if( Z_OK!=uncompress(pOut, &sz, pData, nData) ){ sqlite3_result_error(context, "error in uncompress()", -1); }else{ sqlite3_result_blob(context, pOut, sz, SQLITE_TRANSIENT); } sqlite3_free(pOut); } } /* Run a chunk of SQL. If any errors happen, print an error message ** and exit. */ static void runSql(sqlite3 *db, const char *zSql){ | > > > > > > | 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 | " sessionfuzz run FILE ... -- Run against fuzzed changeset FILE\n" " sessionfuzz run SQLAR ... -- Run against all files in the SQL Archive\n" ; #include <stdio.h> #include <string.h> #include <assert.h> #ifndef OMIT_ZLIB #include "zlib.h" #endif /* ** Implementation of the "sqlar_uncompress(X,SZ)" SQL function ** ** Parameter SZ is interpreted as an integer. If it is less than or ** equal to zero, then this function returns a copy of X. Or, if ** SZ is equal to the size of X when interpreted as a blob, also ** return a copy of X. Otherwise, decompress blob X using zlib ** utility function uncompress() and return the results (another ** blob). */ static void sqlarUncompressFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ #ifdef OMIT_ZLIB sqlite3_result_value(context, argv[0]); #else uLong nData; uLongf sz; assert( argc==2 ); sz = sqlite3_value_int(argv[1]); if( sz<=0 || sz==(nData = sqlite3_value_bytes(argv[0])) ){ sqlite3_result_value(context, argv[0]); }else{ const Bytef *pData= sqlite3_value_blob(argv[0]); Bytef *pOut = sqlite3_malloc(sz); if( Z_OK!=uncompress(pOut, &sz, pData, nData) ){ sqlite3_result_error(context, "error in uncompress()", -1); }else{ sqlite3_result_blob(context, pOut, sz, SQLITE_TRANSIENT); } sqlite3_free(pOut); } #endif } /* Run a chunk of SQL. If any errors happen, print an error message ** and exit. */ static void runSql(sqlite3 *db, const char *zSql){ |
︙ | ︙ | |||
826 827 828 829 830 831 832 | static int conflictCall( void *NotUsed, int eConflict, sqlite3_changeset_iter *p ){ (void)NotUsed; (void)p; | < | 832 833 834 835 836 837 838 839 840 841 842 843 844 845 | static int conflictCall( void *NotUsed, int eConflict, sqlite3_changeset_iter *p ){ (void)NotUsed; (void)p; return SQLITE_CHANGESET_OMIT; } /* ** Reset the database file */ static void db_reset(sqlite3 *db){ |
︙ | ︙ |
Changes to test/shared.test.
︙ | ︙ | |||
156 157 158 159 160 161 162 | # Commit the connection 1 transaction. execsql { COMMIT; } } {} do_test shared-$av.2.1 { | | < < | | 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 | # Commit the connection 1 transaction. execsql { COMMIT; } } {} do_test shared-$av.2.1 { # Open connection db3 to the database. if {$::tcl_platform(platform)=="unix"} { sqlite3 db3 "file:test.db?cache=private" -uri 1 } else { sqlite3 db3 TEST.DB } set ::sqlite_open_file_count expr $sqlite_open_file_count-($extrafds_prelock+$extrafds_postlock) } {2} do_test shared-$av.2.2 { |
︙ | ︙ | |||
796 797 798 799 800 801 802 | INSERT INTO de VALUES('Pataya', 30000); } db2 } {} do_test shared-$av.10.3 { # An external connection should be able to read the database, but not # prepare a write operation. if {$::tcl_platform(platform)=="unix"} { | | | 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 | INSERT INTO de VALUES('Pataya', 30000); } db2 } {} do_test shared-$av.10.3 { # An external connection should be able to read the database, but not # prepare a write operation. if {$::tcl_platform(platform)=="unix"} { sqlite3 db3 "file:test.db?cache=private" -uri 1 } else { sqlite3 db3 TEST.DB } execsql { SELECT * FROM ab; } db3 catchsql { |
︙ | ︙ |
Changes to test/shared3.test.
︙ | ︙ | |||
66 67 68 69 70 71 72 | # The cache-size should now be 10 pages. However at one point there was # a bug that caused the cache size to return to the default value when # a second connection was opened on the shared-cache (as happened in # test case shared3-2.3 above). The goal of the following tests is to # ensure that the cache-size really is 10 pages. # | | | | | < > | > | | 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 | # The cache-size should now be 10 pages. However at one point there was # a bug that caused the cache size to return to the default value when # a second connection was opened on the shared-cache (as happened in # test case shared3-2.3 above). The goal of the following tests is to # ensure that the cache-size really is 10 pages. # #if {$::tcl_platform(platform)=="unix"} { # set alternative_name ./test.db #} else { # set alternative_name TEST.DB #} do_test shared3-2.6 { #sqlite3 db3 $alternative_name sqlite3 db3 "file:./test.db?cache=private" -uri 1 catchsql {select count(*) from sqlite_master} db3 } {0 1} do_test shared3-2.7 { execsql { BEGIN; INSERT INTO t1 VALUES(10, randomblob(5000)) } db1 catchsql {select count(*) from sqlite_master} db3 } {0 1} do_test shared3-2.8 { db3 close execsql { INSERT INTO t1 VALUES(10, randomblob(10000)) } db1 # If the pager-cache is really still limited to 10 pages, then the INSERT # statement above should have caused the pager to grab an exclusive lock # on the database file so that the cache could be spilled. # catch { sqlite3 db3 "file:./test.db?cache=private" -uri 1 } catchsql {select count(*) from sqlite_master} db3 } {1 {database is locked}} db1 close db2 close db3 close |
︙ | ︙ |
Changes to test/shell1.test.
︙ | ︙ | |||
14 15 16 17 18 19 20 21 22 23 24 25 26 27 | # # Test plan: # # shell1-1.*: Basic command line option handling. # shell1-2.*: Basic "dot" command token parsing. # shell1-3.*: Basic test that "dot" command can be called. # set testdir [file dirname $argv0] source $testdir/tester.tcl set CLI [test_find_cli] db close forcedelete test.db test.db-journal test.db-wal sqlite3 db test.db | > > | 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | # # Test plan: # # shell1-1.*: Basic command line option handling. # shell1-2.*: Basic "dot" command token parsing. # shell1-3.*: Basic test that "dot" command can be called. # shell1-{4-8}.*: Test various "dot" commands's functionality. # shell1-9.*: Basic test that "dot" commands and SQL intermix ok. # set testdir [file dirname $argv0] source $testdir/tester.tcl set CLI [test_find_cli] db close forcedelete test.db test.db-journal test.db-wal sqlite3 db test.db |
︙ | ︙ | |||
47 48 49 50 51 52 53 | do_test shell1-1.1.2 { catchcmd "test.db \"select+3\" \"select+4\"" "" } {0 {3 4}} # error on extra options do_test shell1-1.1.3 { catchcmd "test.db FOO test.db BAD" ".quit" | | > > > > | | 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 | do_test shell1-1.1.2 { catchcmd "test.db \"select+3\" \"select+4\"" "" } {0 {3 4}} # error on extra options do_test shell1-1.1.3 { catchcmd "test.db FOO test.db BAD" ".quit" } {1 {Error: in prepare, near "FOO": syntax error (1)}} # -help do_test shell1-1.2.1 { set res [catchcmd "-help test.db" ""] set rc [lindex $res 0] list $rc \ [regexp {Usage} $res] \ [regexp {\-init} $res] \ [regexp {\-version} $res] } {1 1 1 1} # -init filename read/process named file forcedelete FOO set out [open FOO w] puts $out "" close $out do_test shell1-1.3.1 { catchcmd "-init FOO test.db" "" } {0 {}} do_test shell1-1.3.2 { catchcmd "-init FOO test.db .quit BAD" "" } {0 {}} do_test shell1-1.3.3 { catchcmd "-init FOO test.db BAD .quit" "" } {1 {Error: in prepare, near "BAD": syntax error (1)}} # -echo print commands before execution do_test shell1-1.4.1 { catchcmd "-echo test.db" "" } {0 {}} # -[no]header turn headers on or off |
︙ | ︙ | |||
195 196 197 198 199 200 201 | catchcmd "test.db" ".explain \"OFF" } {0 {}} do_test shell1-2.2.4 { catchcmd "test.db" ".explain \'OFF" } {0 {}} do_test shell1-2.2.5 { catchcmd "test.db" ".mode \"insert FOO" | | | | 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 | catchcmd "test.db" ".explain \"OFF" } {0 {}} do_test shell1-2.2.4 { catchcmd "test.db" ".explain \'OFF" } {0 {}} do_test shell1-2.2.5 { catchcmd "test.db" ".mode \"insert FOO" } {1 {Error: mode should be one of: ascii box column csv html insert json line list markdown quote table tabs tcl}} do_test shell1-2.2.6 { catchcmd "test.db" ".mode \'insert FOO" } {1 {Error: mode should be one of: ascii box column csv html insert json line list markdown quote table tabs tcl}} # check multiple tokens, and quoted tokens do_test shell1-2.3.1 { catchcmd "test.db" ".explain 1" } {0 {}} do_test shell1-2.3.2 { catchcmd "test.db" ".explain on" |
︙ | ︙ | |||
226 227 228 229 230 231 232 | do_test shell1-2.3.7 { catchcmd "test.db" ".\'explain\' \'OFF\'" } {0 {}} # check quoted args are unquoted do_test shell1-2.4.1 { catchcmd "test.db" ".mode FOO" | | > | 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 | do_test shell1-2.3.7 { catchcmd "test.db" ".\'explain\' \'OFF\'" } {0 {}} # check quoted args are unquoted do_test shell1-2.4.1 { catchcmd "test.db" ".mode FOO" } {1 {Error: mode should be one of: ascii box column csv html insert json line list markdown quote table tabs tcl}} do_test shell1-2.4.2 { catchcmd "test.db" ".mode csv" } {0 {}} do_test shell1-2.4.2 { catchcmd "test.db" ".mode \"csv\"" } {0 {}} #---------------------------------------------------------------------------- # Test cases shell1-3.*: Basic test that "dot" command can be called. # # .backup ?DB? FILE Backup DB (default "main") to FILE do_test shell1-3.1.1 { catchcmd "test.db" ".backup" } {1 {missing FILENAME argument on .backup}} forcedelete FOO do_test shell1-3.1.2 { catchcmd "test.db" ".backup FOO" } {0 {}} do_test shell1-3.1.3 { catchcmd "test.db" ".backup FOO BAR" } {1 {Error: unknown database FOO}} do_test shell1-3.1.4 { |
︙ | ︙ | |||
293 294 295 296 297 298 299 | [regexp {COMMIT;} $res] } {1 1} do_test shell1-3.4.2 { set res [catchcmd "test.db" ".dump FOO"] list [regexp {BEGIN TRANSACTION;} $res] \ [regexp {COMMIT;} $res] } {1 1} | > | | | | | 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 | [regexp {COMMIT;} $res] } {1 1} do_test shell1-3.4.2 { set res [catchcmd "test.db" ".dump FOO"] list [regexp {BEGIN TRANSACTION;} $res] \ [regexp {COMMIT;} $res] } {1 1} # The .dump command now accepts multiple arguments #do_test shell1-3.4.3 { # # too many arguments # catchcmd "test.db" ".dump FOO BAD" #} {1 {Usage: .dump ?--preserve-rowids? ?--newlines? ?LIKE-PATTERN?}} # .echo ON|OFF Turn command echo on or off do_test shell1-3.5.1 { catchcmd "test.db" ".echo" } {1 {Usage: .echo on|off}} do_test shell1-3.5.2 { catchcmd "test.db" ".echo ON" |
︙ | ︙ | |||
384 385 386 387 388 389 390 | [regexp {.quit} $res] \ [regexp {.show} $res] } {1 1 1} # .import FILE TABLE Import data from FILE into TABLE do_test shell1-3.11.1 { catchcmd "test.db" ".import" | | | < < < | | 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 | [regexp {.quit} $res] \ [regexp {.show} $res] } {1 1 1} # .import FILE TABLE Import data from FILE into TABLE do_test shell1-3.11.1 { catchcmd "test.db" ".import" } {/1 .ERROR: missing FILE argument.*/} do_test shell1-3.11.2 { catchcmd "test.db" ".import FOO" } {/1 .ERROR: missing TABLE argument.*/} do_test shell1-3.11.3 { # too many arguments catchcmd "test.db" ".import FOO BAR BAD" } {/1 .ERROR: extra argument: "BAD".*./} # .indexes ?TABLE? Show names of all indexes # If TABLE specified, only show indexes for tables # matching LIKE pattern TABLE. do_test shell1-3.12.1 { catchcmd "test.db" ".indexes" } {0 {}} |
︙ | ︙ | |||
428 429 430 431 432 433 434 | # tabs Tab-separated values # tcl TCL list elements do_test shell1-3.13.1 { catchcmd "test.db" ".mode" } {0 {current output mode: list}} do_test shell1-3.13.2 { catchcmd "test.db" ".mode FOO" | | | 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 | # tabs Tab-separated values # tcl TCL list elements do_test shell1-3.13.1 { catchcmd "test.db" ".mode" } {0 {current output mode: list}} do_test shell1-3.13.2 { catchcmd "test.db" ".mode FOO" } {1 {Error: mode should be one of: ascii box column csv html insert json line list markdown quote table tabs tcl}} do_test shell1-3.13.3 { catchcmd "test.db" ".mode csv" } {0 {}} do_test shell1-3.13.4 { catchcmd "test.db" ".mode column" } {0 {}} do_test shell1-3.13.5 { |
︙ | ︙ | |||
461 462 463 464 465 466 467 | # extra arguments ignored catchcmd "test.db" ".mode tcl BAD" } {0 {}} # don't allow partial mode type matches do_test shell1-3.13.12 { catchcmd "test.db" ".mode l" | | | | 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 | # extra arguments ignored catchcmd "test.db" ".mode tcl BAD" } {0 {}} # don't allow partial mode type matches do_test shell1-3.13.12 { catchcmd "test.db" ".mode l" } {1 {Error: mode should be one of: ascii box column csv html insert json line list markdown quote table tabs tcl}} do_test shell1-3.13.13 { catchcmd "test.db" ".mode li" } {1 {Error: mode should be one of: ascii box column csv html insert json line list markdown quote table tabs tcl}} do_test shell1-3.13.14 { catchcmd "test.db" ".mode lin" } {0 {}} # .nullvalue STRING Print STRING in place of NULL values do_test shell1-3.14.1 { catchcmd "test.db" ".nullvalue" |
︙ | ︙ | |||
491 492 493 494 495 496 497 | } {0 {}} do_test shell1-3.15.2 { catchcmd "test.db" ".output FOO" } {0 {}} do_test shell1-3.15.3 { # too many arguments catchcmd "test.db" ".output FOO BAD" | | > > > > > > > | > > > > > > > | 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 | } {0 {}} do_test shell1-3.15.2 { catchcmd "test.db" ".output FOO" } {0 {}} do_test shell1-3.15.3 { # too many arguments catchcmd "test.db" ".output FOO BAD" } {1 {ERROR: extra parameter: "BAD". Usage: .output ?FILE? Send output to FILE or stdout if FILE is omitted If FILE begins with '|' then open it as a pipe. Options: --bom Prefix output with a UTF8 byte-order mark -e Send output to the system text editor -x Send output as CSV to a spreadsheet child process exited abnormally}} # .output stdout Send output to the screen do_test shell1-3.16.1 { catchcmd "test.db" ".output stdout" } {0 {}} do_test shell1-3.16.2 { # too many arguments catchcmd "test.db" ".output stdout BAD" } {1 {ERROR: extra parameter: "BAD". Usage: .output ?FILE? Send output to FILE or stdout if FILE is omitted If FILE begins with '|' then open it as a pipe. Options: --bom Prefix output with a UTF8 byte-order mark -e Send output to the system text editor -x Send output as CSV to a spreadsheet child process exited abnormally}} # .prompt MAIN CONTINUE Replace the standard prompts do_test shell1-3.17.1 { catchcmd "test.db" ".prompt" } {0 {}} do_test shell1-3.17.2 { catchcmd "test.db" ".prompt FOO" |
︙ | ︙ | |||
567 568 569 570 571 572 573 | } {0 {}} do_test shell1-3.21.2 { catchcmd "test.db" ".schema FOO" } {0 {}} do_test shell1-3.21.3 { # too many arguments catchcmd "test.db" ".schema FOO BAD" | | | 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 | } {0 {}} do_test shell1-3.21.2 { catchcmd "test.db" ".schema FOO" } {0 {}} do_test shell1-3.21.3 { # too many arguments catchcmd "test.db" ".schema FOO BAD" } {1 {Usage: .schema ?--indent? ?--nosys? ?LIKE-PATTERN?}} do_test shell1-3.21.4 { catchcmd "test.db" { CREATE TABLE t1(x); CREATE VIEW v2 AS SELECT x+1 AS y FROM t1; CREATE VIEW v1 AS SELECT y+1 FROM v2; } |
︙ | ︙ | |||
621 622 623 624 625 626 627 | # too many arguments catchcmd "test.db" ".show BAD" } {1 {Usage: .show}} # .stats ON|OFF Turn stats on or off #do_test shell1-3.23b.1 { # catchcmd "test.db" ".stats" | | | | 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 | # too many arguments catchcmd "test.db" ".show BAD" } {1 {Usage: .show}} # .stats ON|OFF Turn stats on or off #do_test shell1-3.23b.1 { # catchcmd "test.db" ".stats" #} {1 {Usage: .stats on|off|stmt|vmstep}} do_test shell1-3.23b.2 { catchcmd "test.db" ".stats ON" } {0 {}} do_test shell1-3.23b.3 { catchcmd "test.db" ".stats OFF" } {0 {}} do_test shell1-3.23b.4 { # too many arguments catchcmd "test.db" ".stats OFF BAD" } {1 {Usage: .stats ?on|off|stmt|vmstep?}} # Ticket 7be932dfa60a8a6b3b26bcf7623ec46e0a403ddb 2018-06-07 # Adverse interaction between .stats and .eqp # do_test shell1-3.23b.5 { catchcmd "test.db" [string map {"\n " "\n"} { CREATE TEMP TABLE t1(x); |
︙ | ︙ | |||
693 694 695 696 697 698 699 | # this should be treated the same as a '0' width for col 1 and 2 } {0 {}} do_test shell1-3.26.4 { catchcmd "test.db" ".width 1 1" # this should be treated the same as a '1' width for col 1 and 2 } {0 {}} do_test shell1-3.26.5 { | | | | 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 | # this should be treated the same as a '0' width for col 1 and 2 } {0 {}} do_test shell1-3.26.4 { catchcmd "test.db" ".width 1 1" # this should be treated the same as a '1' width for col 1 and 2 } {0 {}} do_test shell1-3.26.5 { catchcmd "test.db" ".mode column\n.header off\n.width 10 -10\nSELECT 'abcdefg', 123456;" # this should be treated the same as a '1' width for col 1 and 2 } {0 {abcdefg 123456}} do_test shell1-3.26.6 { catchcmd "test.db" ".mode column\n.header off\n.width -10 10\nSELECT 'abcdefg', 123456;" # this should be treated the same as a '1' width for col 1 and 2 } {0 { abcdefg 123456 }} # .timer ON|OFF Turn the CPU timer measurement on or off do_test shell1-3.27.1 { catchcmd "test.db" ".timer" |
︙ | ︙ | |||
1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 | # command channels opened for it as textual ones), the carriage # return character (and on Windows, the end-of-file character) # cannot be used here. # if {$i==0x0D || ($tcl_platform(platform)=="windows" && $i==0x1A)} { continue } if {$i>=0xE0 && $tcl_platform(os)=="OpenBSD"} continue if {$i>=0xE0 && $i<=0xEF && $tcl_platform(os)=="Linux"} continue set hex [format %02X $i] set char [subst \\x$hex]; set oldChar $char set escapes [list] if {$tcl_platform(platform)=="windows"} { # | > > | 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 | # command channels opened for it as textual ones), the carriage # return character (and on Windows, the end-of-file character) # cannot be used here. # if {$i==0x0D || ($tcl_platform(platform)=="windows" && $i==0x1A)} { continue } # Tcl 8.7 maps 0x80 through 0x9f into valid UTF8. So skip those tests. if {$i>=0x80 && $i<=0x9f} continue if {$i>=0xE0 && $tcl_platform(os)=="OpenBSD"} continue if {$i>=0xE0 && $i<=0xEF && $tcl_platform(os)=="Linux"} continue set hex [format %02X $i] set char [subst \\x$hex]; set oldChar $char set escapes [list] if {$tcl_platform(platform)=="windows"} { # |
︙ | ︙ | |||
1147 1148 1149 1150 1151 1152 1153 1154 1155 | } {0 {CREATE TABLE WWW (x TEXT PRIMARY KEY); CREATE TABLE ___ (x TEXT PRIMARY KEY);}} do_test shell1-7.1.7 { catchcmd "test.db" ".schema \\\\_\\\\_\\\\_" } {0 {CREATE TABLE ___ (x TEXT PRIMARY KEY);}} } finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | } {0 {CREATE TABLE WWW (x TEXT PRIMARY KEY); CREATE TABLE ___ (x TEXT PRIMARY KEY);}} do_test shell1-7.1.7 { catchcmd "test.db" ".schema \\\\_\\\\_\\\\_" } {0 {CREATE TABLE ___ (x TEXT PRIMARY KEY);}} } # Test case for the ieee754 and decimal extensions in the shell. # See the "floatingpoint.html" file in the documentation for more # information. # do_test shell1-8.1 { catchcmd ":memory:" { -- The pow2 table will hold all the necessary powers of two. CREATE TABLE pow2(x INTEGER PRIMARY KEY, v TEXT); WITH RECURSIVE c(x,v) AS ( VALUES(0,'1') UNION ALL SELECT x+1, decimal_mul(v,'2') FROM c WHERE x+1<=971 ) INSERT INTO pow2(x,v) SELECT x, v FROM c; WITH RECURSIVE c(x,v) AS ( VALUES(-1,'0.5') UNION ALL SELECT x-1, decimal_mul(v,'0.5') FROM c WHERE x-1>=-1075 ) INSERT INTO pow2(x,v) SELECT x, v FROM c; -- This query finds the decimal representation of each value in the "c" table. WITH c(n) AS (VALUES(47.49)) ----XXXXX----------- Replace with whatever you want SELECT decimal_mul(ieee754_mantissa(c.n),pow2.v) FROM pow2, c WHERE pow2.x=ieee754_exponent(c.n); } } {0 47.49000000000000198951966012828052043914794921875} do_test shell1-8.2 { catchcmd :memory: { .mode box SELECT ieee754(47.49) AS x; } } {0 {┌───────────────────────────────┐ │ x │ ├───────────────────────────────┤ │ ieee754(6683623321994527,-47) │ └───────────────────────────────┘}} do_test shell1-8.3 { catchcmd ":memory: --box" { select ieee754(6683623321994527,-47) as x; } } {0 {┌───────┐ │ x │ ├───────┤ │ 47.49 │ └───────┘}} do_test shell1-8.4 { catchcmd ":memory: --table" {SELECT ieee754_mantissa(47.49) AS M, ieee754_exponent(47.49) AS E;} } {0 {+------------------+-----+ | M | E | +------------------+-----+ | 6683623321994527 | -47 | +------------------+-----+}} #---------------------------------------------------------------------------- # Test cases shell1-9.*: Basic test that "dot" commands and SQL intermix ok. # do_test shell1-9.1 { catchcmd :memory: { .mode csv /* x */ select 1,2; --x -- .nada ; .mode csv --x select 2,1; select 3,4; } } {0 {1,2 2,1 3,4}} finish_test |
Changes to test/shell2.test.
︙ | ︙ | |||
39 40 41 42 43 44 45 | set fexist [file exist foo.db] list $rc $fexist } {{0 {}} 1} # Shell silently ignores extra parameters. # Ticket [f5cb008a65]. do_test shell2-1.2.1 { | | < > | | | 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 | set fexist [file exist foo.db] list $rc $fexist } {{0 {}} 1} # Shell silently ignores extra parameters. # Ticket [f5cb008a65]. do_test shell2-1.2.1 { catchcmdex {:memory: "select+3" "select+4"} } {0 {3 4 }} # Test a problem reported on the mailing list. The shell was at one point # returning the generic SQLITE_ERROR message ("SQL error or missing database") # instead of the "too many levels..." message in the test below. # do_test shell2-1.3 { catchcmd "-batch test.db" { PRAGMA recursive_triggers = ON; CREATE TABLE t5(a PRIMARY KEY, b, c); INSERT INTO t5 VALUES(1, 2, 3); CREATE TRIGGER au_tble AFTER UPDATE ON t5 BEGIN UPDATE OR IGNORE t5 SET a = new.a, c = 10; END; UPDATE OR REPLACE t5 SET a = 4 WHERE a = 1; } } {1 {Error: near line 9: stepping, too many levels of trigger recursion (1)}} # Shell not echoing all commands with echo on. # Ticket [eb620916be]. # Test with echo off |
︙ | ︙ | |||
119 120 121 122 123 124 125 | 1}} # Test with echo on using dot command and # multiple commands per line. # NB. whitespace is important do_test shell2-1.4.5 { forcedelete foo.db | | | 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 | 1}} # Test with echo on using dot command and # multiple commands per line. # NB. whitespace is important do_test shell2-1.4.5 { forcedelete foo.db catchcmdex "foo.db" {.echo ON CREATE TABLE foo1(a); INSERT INTO foo1(a) VALUES(1); CREATE TABLE foo2(b); INSERT INTO foo2(b) VALUES(1); SELECT * FROM foo1; SELECT * FROM foo2; INSERT INTO foo1(a) VALUES(2); INSERT INTO foo2(b) VALUES(2); SELECT * FROM foo1; SELECT * FROM foo2; |
︙ | ︙ | |||
151 152 153 154 155 156 157 | }} # Test with echo on and headers on using dot command and # multiple commands per line. # NB. whitespace is important do_test shell2-1.4.6 { forcedelete foo.db | | | 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 | }} # Test with echo on and headers on using dot command and # multiple commands per line. # NB. whitespace is important do_test shell2-1.4.6 { forcedelete foo.db catchcmdex "foo.db" {.echo ON .headers ON CREATE TABLE foo1(a); INSERT INTO foo1(a) VALUES(1); CREATE TABLE foo2(b); INSERT INTO foo2(b) VALUES(1); SELECT * FROM foo1; SELECT * FROM foo2; INSERT INTO foo1(a) VALUES(2); INSERT INTO foo2(b) VALUES(2); |
︙ | ︙ |
Changes to test/shell3.test.
︙ | ︙ | |||
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | # $Id: shell2.test,v 1.7 2009/07/17 16:54:48 shaneh Exp $ # # Test plan: # # shell3-1.*: Basic tests for running SQL statments from command line. # shell3-2.*: Basic tests for running SQL file from command line. # set testdir [file dirname $argv0] source $testdir/tester.tcl set CLI [test_find_cli] db close forcedelete test.db test.db-journal test.db-wal sqlite3 db test.db # There are inconsistencies in command-line argument quoting on Windows. # In particular, individual applications are responsible for command-line # parsing in Windows, not the shell. Depending on whether the sqlite3.exe # program is compiled with MinGW or MSVC, the command-line parsing is # different. This causes problems for the tests below. To avoid # issues, these tests are disabled for windows. | > > | 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | # $Id: shell2.test,v 1.7 2009/07/17 16:54:48 shaneh Exp $ # # Test plan: # # shell3-1.*: Basic tests for running SQL statments from command line. # shell3-2.*: Basic tests for running SQL file from command line. # shell3-3.*: Basic tests for processing odd SQL constructs. # set testdir [file dirname $argv0] source $testdir/tester.tcl set CLI [test_find_cli] db close forcedelete test.db test.db-journal test.db-wal sqlite3 db test.db # There are inconsistencies in command-line argument quoting on Windows. # In particular, individual applications are responsible for command-line # parsing in Windows, not the shell. Depending on whether the sqlite3.exe # program is compiled with MinGW or MSVC, the command-line parsing is # different. This causes problems for the tests below. To avoid # issues, these tests are disabled for windows. |
︙ | ︙ | |||
62 63 64 65 66 67 68 | catchcmd "foo.db \"CREATE TABLE t1(a); DROP TABLE t1;\"" } {0 {}} do_test shell3-1.6 { catchcmd "foo.db" ".tables" } {0 {}} do_test shell3-1.7 { catchcmd "foo.db \"CREATE TABLE\"" | | | 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 | catchcmd "foo.db \"CREATE TABLE t1(a); DROP TABLE t1;\"" } {0 {}} do_test shell3-1.6 { catchcmd "foo.db" ".tables" } {0 {}} do_test shell3-1.7 { catchcmd "foo.db \"CREATE TABLE\"" } {1 {Error: in prepare, incomplete input (1)}} #---------------------------------------------------------------------------- # shell3-2.*: Basic tests for running SQL file from command line. # # Run SQL file from command line do_test shell3-2.1 { |
︙ | ︙ | |||
92 93 94 95 96 97 98 | catchcmd "foo.db" "CREATE TABLE t1(a); DROP TABLE t1;" } {0 {}} do_test shell3-2.6 { catchcmd "foo.db" ".tables" } {0 {}} do_test shell3-2.7 { catchcmd "foo.db" "CREATE TABLE" | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | catchcmd "foo.db" "CREATE TABLE t1(a); DROP TABLE t1;" } {0 {}} do_test shell3-2.6 { catchcmd "foo.db" ".tables" } {0 {}} do_test shell3-2.7 { catchcmd "foo.db" "CREATE TABLE" } {1 {Error: near line 1: in prepare, incomplete input (1)}} #---------------------------------------------------------------------------- # shell3-3.*: Basic tests for processing odd SQL constructs. # # Run combinations of odd identifiers, comments, semicolon placement do_test shell3-3.1 { forcedelete foo.db set rc [ catchcmd "foo.db" {CREATE TABLE t1(" a--. " --x ); CREATE TABLE t2("a[""b""]"); .header on INSERT INTO t1 VALUES (' x''y'); INSERT INTO t2 VALUES (' /*. .*/ x ''y'); SELECT * from t1 limit 1; SELECT * from t2 limit 1; } ] set fexist [file exist foo.db] list $rc $fexist } {{0 { a--. x'y a["b"] /*. .*/ x 'y}} 1} finish_test |
Changes to test/shell4.test.
︙ | ︙ | |||
62 63 64 65 66 67 68 | } {0 {}} do_test shell4-1.3.3 { catchcmd "test.db" ".stats OFF" } {0 {}} do_test shell4-1.3.4 { # too many arguments catchcmd "test.db" ".stats OFF BAD" | | | 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 | } {0 {}} do_test shell4-1.3.3 { catchcmd "test.db" ".stats OFF" } {0 {}} do_test shell4-1.3.4 { # too many arguments catchcmd "test.db" ".stats OFF BAD" } {1 {Usage: .stats ?on|off|stmt|vmstep?}} # NB. whitespace is important do_test shell4-1.4.1 { set res [catchcmd "test.db" {.show}] list [regexp {stats: off} $res] } {1} |
︙ | ︙ | |||
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 | SELECT 1; }] list [regexp {Memory Used} $res] \ [regexp {Heap Usage} $res] \ [regexp {Autoindex Inserts} $res] } {1 1 1} do_test shell4-2.1 { catchcmd ":memory:" "CREATE TABLE t1(x);\n.trace --unknown" } {1 {Unknown option "--unknown" on ".trace"}} do_test shell4-2.2 { catchcmd ":memory:" "CREATE TABLE t1(x);\n.trace off\n.trace off\n" } {0 {}} do_test shell4-2.3 { catchcmd ":memory:" ".trace stdout\n.dump\n.trace off\n" } {/^0 {PRAGMA.*}$/} | > < | 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 | SELECT 1; }] list [regexp {Memory Used} $res] \ [regexp {Heap Usage} $res] \ [regexp {Autoindex Inserts} $res] } {1 1 1} ifcapable trace { do_test shell4-2.1 { catchcmd ":memory:" "CREATE TABLE t1(x);\n.trace --unknown" } {1 {Unknown option "--unknown" on ".trace"}} do_test shell4-2.2 { catchcmd ":memory:" "CREATE TABLE t1(x);\n.trace off\n.trace off\n" } {0 {}} do_test shell4-2.3 { catchcmd ":memory:" ".trace stdout\n.dump\n.trace off\n" } {/^0 {PRAGMA.*}$/} do_test shell4-2.4 { catchcmd ":memory:" ".trace stdout\nCREATE TABLE t1(x);SELECT * FROM t1;" } {0 {CREATE TABLE t1(x); SELECT * FROM t1;}} do_test shell4-2.5 { catchcmd ":memory:" "CREATE TABLE t1(x);\n.trace stdout\nSELECT * FROM t1;" } {0 {SELECT * FROM t1;}} |
︙ | ︙ |
Changes to test/shell5.test.
︙ | ︙ | |||
28 29 30 31 32 33 34 | #---------------------------------------------------------------------------- # Test cases shell5-1.*: Basic handling of the .import and .separator commands. # # .import FILE TABLE Import data from FILE into TABLE do_test shell5-1.1.1 { catchcmd "test.db" ".import" | | | < < < | | 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | #---------------------------------------------------------------------------- # Test cases shell5-1.*: Basic handling of the .import and .separator commands. # # .import FILE TABLE Import data from FILE into TABLE do_test shell5-1.1.1 { catchcmd "test.db" ".import" } {/1 .ERROR: missing FILE argument.*/} do_test shell5-1.1.2 { catchcmd "test.db" ".import FOO" } {/1 .ERROR: missing TABLE argument.*/} do_test shell5-1.1.3 { # too many arguments catchcmd "test.db" ".import FOO BAR BAD" } {/1 .ERROR: extra argument.*/} # .separator STRING Change separator used by output mode and .import do_test shell5-1.2.1 { catchcmd "test.db" ".separator" } {1 {Usage: .separator COL ?ROW?}} do_test shell5-1.2.2 { catchcmd "test.db" ".separator ONE" |
︙ | ︙ | |||
454 455 456 457 458 459 460 461 462 | catchcmd test.db [string trim { .mode csv CREATE TABLE t7(a, b, c); .import shell5.csv t7 }] db eval { SELECT * FROM t7 ORDER BY a } } {1 2 3 4 5 {} 6 7 8} finish_test | > > > > > > > > > > > > > > > | 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 | catchcmd test.db [string trim { .mode csv CREATE TABLE t7(a, b, c); .import shell5.csv t7 }] db eval { SELECT * FROM t7 ORDER BY a } } {1 2 3 4 5 {} 6 7 8} do_test shell5-4.3 { forcedelete shell5.csv set fd [open shell5.csv w] puts $fd ",," puts $fd "1,2,3" close $fd catchcmd test.db [string trim { .mode csv CREATE TABLE t8(a, b, c); .import -skip 1 shell5.csv t8 .nullvalue # }] db eval { SELECT * FROM t8 } } {1 2 3} finish_test |
Changes to test/shell8.test.
︙ | ︙ | |||
39 40 41 42 43 44 45 46 47 48 49 50 51 52 | set path [file join $dirname $f] file mkdir [file dirname $path] set fd [open $path w] puts -nonewline $fd $d close $fd } } proc dir_to_list {dirname {n -1}} { if {$n<0} {set n [llength [file split $dirname]]} set res [list] foreach f [glob -nocomplain $dirname/*] { set mtime [file mtime $f] | > > > > | 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | set path [file join $dirname $f] file mkdir [file dirname $path] set fd [open $path w] puts -nonewline $fd $d close $fd } } proc dir_content {dirname} { lsort [glob -nocomplain $dirname/*] } proc dir_to_list {dirname {n -1}} { if {$n<0} {set n [llength [file split $dirname]]} set res [list] foreach f [glob -nocomplain $dirname/*] { set mtime [file mtime $f] |
︙ | ︙ | |||
166 167 168 169 170 171 172 | after 2000 catchcmd test_ar.db $x1 dir_to_list ar1 } $expected } } | | > > > > > > | > > | > > > > > > > | 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 | after 2000 catchcmd test_ar.db $x1 dir_to_list ar1 } $expected } } do_test 2.1.1 { populate_dir ar2 { file1 "abcd" file2 "efgh" junk1 "j1" junk2 "j2" dir1/file3 "ijkl" } populate_dir ar4 { file2 "efgh" } catchcmd shell8.db {.ar -c} catchcmd shell8.db {.ar -C ar2 -i .} catchcmd shell8.db {.ar -r ./file2 ./dir1} catchcmd shell8.db {.ar -g -r ./ju*2} catchcmd shell8.db {.ar -C ar4 -x .} regsub -all {ar4} [dir_content ar4] ar2 } {ar2/file1 ar2/file2 ar2/junk1} finish_test |
Added test/shmlock.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 | # 2018 December 6 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix shmlock ifcapable !wal {finish_test ; return } sqlite3 db2 test.db sqlite3 db3 test.db do_execsql_test 1.0 { PRAGMA journal_mode = wal; CREATE TABLE t1(a, b); INSERT INTO t1 VALUES(1, 2); } {wal} do_test 1.1 { execsql { SELECT * FROM t1 } db2 } {1 2} do_test 1.2 { execsql { SELECT * FROM t1 } db3 } {1 2} foreach {tn dbhandle cmd res} { 1 db {shared lock 7 1} OK 2 db2 {exclusive lock 7 1} BUSY 3 db {shared unlock 7 1} OK 4 db2 {exclusive lock 7 1} OK 5 db {shared lock 7 1} BUSY 6 db {exclusive lock 7 1} BUSY 7 db2 {exclusive unlock 7 1} OK 8 db {exclusive lock 0 8} OK 9 db {exclusive unlock 0 8} OK 10 db2 {exclusive lock 0 8} OK 11 db2 {exclusive unlock 0 8} OK 12 db {shared lock 0 1} OK 13 db2 {shared lock 0 1} OK 14 db3 {shared lock 0 1} OK 15 db3 {shared unlock 0 1} OK 16 db3 {exclusive lock 0 1} BUSY 17 db2 {shared unlock 0 1} OK 18 db3 {exclusive lock 0 1} BUSY 19 db {shared unlock 0 1} OK 20 db3 {exclusive lock 0 1} OK 21 db3 {exclusive unlock 0 1} OK 22 db {shared lock 3 1} OK 23 db2 {exclusive lock 2 2} BUSY 24 db {shared lock 2 1} OK 25 db2 {exclusive lock 0 5} BUSY 26 db2 {exclusive lock 0 4} BUSY 27 db2 {exclusive lock 0 3} BUSY 28 db {shared unlock 3 1} OK 29 db2 {exclusive lock 2 2} BUSY 28 db {shared unlock 2 1} OK 29 db2 {exclusive lock 2 2} OK 29 db2 {exclusive unlock 2 2} OK } { do_test 1.3.$tn [list vfs_shmlock $dbhandle main {*}$cmd] "SQLITE_$res" } db close db2 close db3 close if {[permutation]=="unix-excl"} { do_test 2.0 { for {set i 0} {$i < 256} {incr i} { sqlite3 db$i test.db execsql { SELECT * FROM t1 } db$i } for {set i 0} {$i < 255} {incr i} { set rc [vfs_shmlock db$i main shared lock 4 1] if {$rc != "SQLITE_OK"} { error $rc } } vfs_shmlock db255 main shared lock 4 1 } {SQLITE_BUSY} do_test 2.1 { vfs_shmlock db255 main exclusive lock 4 1 } SQLITE_BUSY do_test 2.2 { vfs_shmlock db0 main shared unlock 4 1 } SQLITE_OK do_test 2.3 { vfs_shmlock db255 main shared lock 4 1 } SQLITE_OK do_test 2.4 { vfs_shmlock db255 main shared unlock 4 1 } SQLITE_OK do_test 2.5 { vfs_shmlock db255 main exclusive lock 4 1 } SQLITE_BUSY do_test 2.6 { for {set i 1} {$i < 255} {incr i} { set rc [vfs_shmlock db255 main exclusive lock 4 1] if {$rc != "SQLITE_BUSY"} { error $rc } set rc [vfs_shmlock db$i main shared unlock 4 1] if {$rc != "SQLITE_OK"} { error $rc } } vfs_shmlock db255 main exclusive lock 4 1 } {SQLITE_OK} vfs_shmlock db255 main exclusive unlock 4 1 for {set i 0} {$i < 256} {incr i} { db$i close } } sqlite3 db0 test.db sqlite3 db1 test.db do_test 3.1 { execsql { SELECT * FROM t1 } db0 } {1 2} do_test 3.2 { execsql { SELECT * FROM t1 } db1 } {1 2} if {$tcl_platform(platform)=="windows"} { set isWindows 1 } else { set isWindows 0 } set L(0) {n n n n n n n n} set L(1) {n n n n n n n n} proc random_lock_test {idx} { global L set iSlot [expr int(rand()*8)] if {[expr int(rand()*2)]} { # Unlock operation if {[lindex $L($idx) $iSlot]!="n"} { vfs_shmlock db$idx main [lindex $L($idx) $iSlot] unlock $iSlot 1 lset L($idx) $iSlot n } } else { # Lock operation if {[lindex $L($idx) $iSlot]=="n"} { set locktype [lindex {e s} [expr int(rand()*2)]] set n 1 if {$locktype=="e"} { for {set l $iSlot} {$l<8 && [lindex $L($idx) $l]=="n"} {incr l} {} set n [expr int(rand()*($l-$iSlot))+1] # The LockFile() and UnlockFile() apis on windows require that # every unlock correspond exactly to a prior lock. Hence, we cannot # lock arbitrary ranges in this test on windows. if {$::isWindows} {set n 1} # puts "iSlot=$iSlot l=$l L=$L($idx)" # puts "$iSlot $n" } set res [vfs_shmlock db$idx main $locktype lock $iSlot $n] set bBusy 0 for {set i $iSlot} {$i<($iSlot+$n)} {incr i} { set other [lindex $L([expr ($idx+1)%2]) $i] if {($other!="n" && $locktype=="e")||($other=="e" && $locktype=="s")} { if {$res != "SQLITE_BUSY"} { error "BUSY not detected" } set bBusy 1 break } } if {$bBusy==0} { if {$res != "SQLITE_OK"} { error "BUSY false-positive" } for {set i $iSlot} {$i<($iSlot+$n)} {incr i} { lset L($idx) $i $locktype } } } } } set nStep 100000 for {set i 0} {$i < $nStep} {incr i} { random_lock_test 0 random_lock_test 1 } db0 close db1 close finish_test |
Changes to test/shrink.test.
︙ | ︙ | |||
20 21 22 23 24 25 26 | unset -nocomplain baseline do_test shrink-1.1 { db eval { PRAGMA cache_size = 2000; CREATE TABLE t1(x,y); INSERT INTO t1 VALUES(randomblob(1000000),1); } | | | 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | unset -nocomplain baseline do_test shrink-1.1 { db eval { PRAGMA cache_size = 2000; CREATE TABLE t1(x,y); INSERT INTO t1 VALUES(randomblob(1000000),1); } set ::baseline [sqlite3_memory_used] # EVIDENCE-OF: R-58814-63508 The sqlite3_db_release_memory(D) interface # attempts to free as much heap memory as possible from database # connection D. sqlite3_db_release_memory db expr {$::baseline > [sqlite3_memory_used]+500000} } {1} do_test shrink-1.2 { |
︙ | ︙ |
Changes to test/skipscan1.test.
︙ | ︙ | |||
230 231 232 233 234 235 236 | EXPLAIN QUERY PLAN SELECT xh, loc FROM t5 WHERE loc >= 'M' AND loc < 'N'; } {/.*COVERING INDEX t5i1 .*/} do_execsql_test skipscan1-5.2 { ANALYZE; DELETE FROM sqlite_stat1; DROP TABLE IF EXISTS sqlite_stat4; | < | 230 231 232 233 234 235 236 237 238 239 240 241 242 243 | EXPLAIN QUERY PLAN SELECT xh, loc FROM t5 WHERE loc >= 'M' AND loc < 'N'; } {/.*COVERING INDEX t5i1 .*/} do_execsql_test skipscan1-5.2 { ANALYZE; DELETE FROM sqlite_stat1; DROP TABLE IF EXISTS sqlite_stat4; INSERT INTO sqlite_stat1 VALUES('t5','t5i1','2702931 3 2 2 2 2'); INSERT INTO sqlite_stat1 VALUES('t5','t5i2','2702931 686 2 2 2'); ANALYZE sqlite_master; } {} db cache flush do_execsql_test skipscan1-5.3 { EXPLAIN QUERY PLAN |
︙ | ︙ | |||
338 339 340 341 342 343 344 | } {/USING INDEX t9a_ab .ANY.a. AND b=./} optimization_control db skip-scan 0 do_execsql_test skipscan1-9.3 { EXPLAIN QUERY PLAN SELECT * FROM t9a WHERE b IN (SELECT x FROM t9b WHERE y!=5); | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | } {/USING INDEX t9a_ab .ANY.a. AND b=./} optimization_control db skip-scan 0 do_execsql_test skipscan1-9.3 { EXPLAIN QUERY PLAN SELECT * FROM t9a WHERE b IN (SELECT x FROM t9b WHERE y!=5); } {/{SCAN t9a}/} optimization_control db skip-scan 1 do_execsql_test skipscan1-2.1 { CREATE TABLE t6(a TEXT, b INT, c INT, d INT); CREATE INDEX t6abc ON t6(a,b,c); INSERT INTO t6 VALUES('abc',123,4,5); ANALYZE; DELETE FROM sqlite_stat1; INSERT INTO sqlite_stat1 VALUES('t6','t6abc','10000 5000 2000 10'); ANALYZE sqlite_master; DELETE FROM t6; } {} do_execsql_test skipscan1-2.2eqp { EXPLAIN QUERY PLAN SELECT a,b,c,d,'|' FROM t6 WHERE d<>99 AND b=345 ORDER BY a; } {/* USING INDEX t6abc (ANY(a) AND b=?)*/} do_execsql_test skipscan1-2.2 { SELECT a,b,c,d,'|' FROM t6 WHERE d<>99 AND b=345 ORDER BY a; } {} do_execsql_test skipscan1-2.3eqp { EXPLAIN QUERY PLAN SELECT a,b,c,d,'|' FROM t6 WHERE d<>99 AND b=345 ORDER BY a DESC; } {/* USING INDEX t6abc (ANY(a) AND b=?)*/} do_execsql_test skipscan1-2.3 { SELECT a,b,c,d,'|' FROM t6 WHERE d<>99 AND b=345 ORDER BY a DESC; } {} # 2019-07-29 Ticket ced41c7c7d6b4d36 # A skipscan query is not order-distinct # db close sqlite3 db :memory: do_execsql_test skipscan1-3.1 { CREATE TABLE t1 (c1, c2, c3, c4, PRIMARY KEY(c4, c3)); INSERT INTO t1 VALUES(3,0,1,NULL); INSERT INTO t1 VALUES(0,4,1,NULL); INSERT INTO t1 VALUES(5,6,1,NULL); INSERT INTO t1 VALUES(0,4,1,NULL); ANALYZE sqlite_master; INSERT INTO sqlite_stat1 VALUES('t1','sqlite_autoindex_t1_1','18 18 6'); ANALYZE sqlite_master; SELECT DISTINCT quote(c1), quote(c2), quote(c3), quote(c4), '|' FROM t1 WHERE t1.c3 = 1; } {3 0 1 NULL | 0 4 1 NULL | 5 6 1 NULL |} do_eqp_test skipscan1-3.2 { SELECT DISTINCT quote(c1), quote(c2), quote(c3), quote(c4), '|' FROM t1 WHERE t1.c3 = 1; } { QUERY PLAN |--SEARCH t1 USING INDEX sqlite_autoindex_t1_1 (ANY(c4) AND c3=?) `--USE TEMP B-TREE FOR DISTINCT } # 2020-01-06 ticket 304017f5f04a0035 # reset_db do_execsql_test skipscan1-4.10 { CREATE TABLE t1(a,b INT); INSERT INTO t1(a,b) VALUES(1,2),(3,3),(4,5); CREATE UNIQUE INDEX i1 ON t1(b,b,a,a,a,a,a,b,a); ANALYZE; DROP TABLE IF EXISTS sqlite_stat4; INSERT INTO sqlite_stat1 VALUES('t1','i1','30 30 30 2 2 2 2 2 2 2'); ANALYZE sqlite_master; SELECT DISTINCT a FROM t1 WHERE a = b AND a = 3 AND b IN (1,3,2,4) AND b >= 0 AND a <= 10; } {3} finish_test |
Changes to test/skipscan2.test.
︙ | ︙ | |||
153 154 155 156 157 158 159 | role TEXT NOT NULL, height INT NOT NULL, -- in cm CHECK( role IN ('student','teacher') ) ) WITHOUT ROWID; CREATE INDEX peoplew_idx1 ON peoplew(role, height); INSERT INTO peoplew(name,role,height) SELECT name, role, height FROM people; | < | 153 154 155 156 157 158 159 160 161 162 163 164 165 166 | role TEXT NOT NULL, height INT NOT NULL, -- in cm CHECK( role IN ('student','teacher') ) ) WITHOUT ROWID; CREATE INDEX peoplew_idx1 ON peoplew(role, height); INSERT INTO peoplew(name,role,height) SELECT name, role, height FROM people; SELECT name FROM peoplew WHERE height>=180 ORDER BY +name; } {David Jack Patrick Quiana Xavier} do_execsql_test skipscan2-2.2 { SELECT name FROM peoplew WHERE role IN (SELECT DISTINCT role FROM peoplew) AND height>=180 ORDER BY +name; } {David Jack Patrick Quiana Xavier} |
︙ | ︙ | |||
195 196 197 198 199 200 201 | for {set i 0} {$i < 1000} {incr i} { execsql { INSERT INTO t3 VALUES($i%2, $i, 'xyz') } } execsql { ANALYZE } } {} do_eqp_test skipscan2-3.3eqp { SELECT * FROM t3 WHERE b=42; | | > | 194 195 196 197 198 199 200 201 202 203 204 205 | for {set i 0} {$i < 1000} {incr i} { execsql { INSERT INTO t3 VALUES($i%2, $i, 'xyz') } } execsql { ANALYZE } } {} do_eqp_test skipscan2-3.3eqp { SELECT * FROM t3 WHERE b=42; } {SEARCH t3 USING PRIMARY KEY (ANY(a) AND b=?)} finish_test |
Changes to test/skipscan5.test.
︙ | ︙ | |||
26 27 28 29 30 31 32 | do_execsql_test 1.1 { CREATE TABLE t1(a INT, b INT, c INT); CREATE INDEX i1 ON t1(a, b); } {} expr srand(4) do_test 1.2 { | | | | | | | | | | | 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 | do_execsql_test 1.1 { CREATE TABLE t1(a INT, b INT, c INT); CREATE INDEX i1 ON t1(a, b); } {} expr srand(4) do_test 1.2 { for {set i 0} {$i < 1000} {incr i} { set a [expr int(rand()*4.0) + 1] set b [expr int(rand()*20.0) + 1] execsql { INSERT INTO t1 VALUES($a, $b, NULL) } } execsql ANALYZE } {} foreach {tn q res} { 1 "b = 5" {/*ANY(a) AND b=?*/} 2 "b > 12 AND b < 16" {/*ANY(a) AND b>? AND b<?*/} 3 "b > 2 AND b < 16" {/*SCAN t1*/} 4 "b > 18 AND b < 25" {/*ANY(a) AND b>? AND b<?*/} 5 "b > 16" {/*ANY(a) AND b>?*/} 6 "b > 5" {/*SCAN t1*/} 7 "b < 15" {/*SCAN t1*/} 8 "b < 5" {/*ANY(a) AND b<?*/} 9 "5 > b" {/*ANY(a) AND b<?*/} 10 "b = '5'" {/*ANY(a) AND b=?*/} 11 "b > '12' AND b < '16'" {/*ANY(a) AND b>? AND b<?*/} 12 "b > '2' AND b < '16'" {/*SCAN t1*/} 13 "b > '18' AND b < '25'" {/*ANY(a) AND b>? AND b<?*/} 14 "b > '16'" {/*ANY(a) AND b>?*/} 15 "b > '5'" {/*SCAN t1*/} 16 "b < '15'" {/*SCAN t1*/} 17 "b < '5'" {/*ANY(a) AND b<?*/} 18 "'5' > b" {/*ANY(a) AND b<?*/} } { set sql "EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE $q" do_execsql_test 1.3.$tn $sql $res } |
︙ | ︙ | |||
100 101 102 103 104 105 106 | execsql { INSERT INTO t2 VALUES($a, $b, $c, $d) } } execsql ANALYZE } {} foreach {tn2 q res} { 1 { c BETWEEN 'd' AND 'e' } {/*ANY(a) AND ANY(b) AND c>? AND c<?*/} | | | | | | 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 | execsql { INSERT INTO t2 VALUES($a, $b, $c, $d) } } execsql ANALYZE } {} foreach {tn2 q res} { 1 { c BETWEEN 'd' AND 'e' } {/*ANY(a) AND ANY(b) AND c>? AND c<?*/} 2 { c BETWEEN 'b' AND 'r' } {/*SCAN t2*/} 3 { c > 'q' } {/*ANY(a) AND ANY(b) AND c>?*/} 4 { c > 'e' } {/*SCAN t2*/} 5 { c < 'q' } {/*SCAN t2*/} 6 { c < 'b' } {/*ANY(a) AND ANY(b) AND c<?*/} } { set sql "EXPLAIN QUERY PLAN SELECT * FROM t2 WHERE $q" do_execsql_test 2.$tn.$tn2 $sql $res } } |
︙ | ︙ | |||
165 166 167 168 169 170 171 | incr c } execsql ANALYZE } {} foreach {tn q res} { 1 "b BETWEEN -10000 AND -8000" {/*ANY(a) AND b>? AND b<?*/} | | | | | 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 | incr c } execsql ANALYZE } {} foreach {tn q res} { 1 "b BETWEEN -10000 AND -8000" {/*ANY(a) AND b>? AND b<?*/} 2 "b BETWEEN -10000 AND 'qqq'" {/*SCAN t3*/} 3 "b < X'5555'" {/*SCAN t3*/} 4 "b > X'5555'" {/*ANY(a) AND b>?*/} 5 "b > 'zzz'" {/*ANY(a) AND b>?*/} 6 "b < 'zzz'" {/*SCAN t3*/} } { set sql "EXPLAIN QUERY PLAN SELECT * FROM t3 WHERE $q" do_execsql_test 3.3.$tn $sql $res } finish_test |
Changes to test/skipscan6.test.
︙ | ︙ | |||
175 176 177 178 179 180 181 | t3 t3_ba {100 20 1 1} } # Use index "t3_a", as (a=?) is expected to match only a single row. # do_eqp_test 3.1 { SELECT * FROM t3 WHERE a = ? AND c = ? | | | | 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 | t3 t3_ba {100 20 1 1} } # Use index "t3_a", as (a=?) is expected to match only a single row. # do_eqp_test 3.1 { SELECT * FROM t3 WHERE a = ? AND c = ? } {SEARCH t3 USING INDEX t3_a (a=?)} # The same query on table t2. This should use index "t2_a", for the # same reason. At one point though, it was mistakenly using a skip-scan. # do_eqp_test 3.2 { SELECT * FROM t2 WHERE a = ? AND c = ? } {SEARCH t2 USING INDEX t2_a (a=?)} finish_test |
Changes to test/snapshot_fault.test.
︙ | ︙ | |||
217 218 219 220 221 222 223 224 225 226 | db eval COMMIT } -body { sqlite3_snapshot_recover db main } -test { faultsim_test_result {0 {}} {1 SQLITE_IOERR} } finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > | 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 | db eval COMMIT } -body { sqlite3_snapshot_recover db main } -test { faultsim_test_result {0 {}} {1 SQLITE_IOERR} } #------------------------------------------------------------------------- # Test the handling of faults that occur within sqlite3_snapshot_get(). # reset_db do_execsql_test 5.0 { PRAGMA page_size = 512; PRAGMA journal_mode = wal; PRAGMA wal_autocheckpoint = 0; CREATE TABLE t1(zzz); INSERT INTO t1 VALUES(randomblob( 5000 )); PRAGMA user_version = 211; } {wal 0} faultsim_save_and_close do_faultsim_test 5 -prep { faultsim_restore_and_reopen execsql { SELECT count(*) FROM sqlite_master } execsql BEGIN } -body { sqlite3_snapshot_get_blob db main set {} {} } -test { execsql END faultsim_test_result {0 {}} {1 SQLITE_IOERR} {1 SQLITE_NOMEM} } finish_test |
Changes to test/sorterref.test.
︙ | ︙ | |||
9 10 11 12 13 14 15 16 17 18 19 20 21 22 | # #*********************************************************************** # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix sorterref do_execsql_test 1.0 { CREATE TABLE t1(a, b, c); INSERT INTO t1 VALUES(1, 2, 3); INSERT INTO t1 VALUES(4, 5, 6); ALTER TABLE t1 ADD COLUMN d DEFAULT 'string'; INSERT INTO t1 VALUES(7, 8, 9, 'text'); | > > > > > > | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | # #*********************************************************************** # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix sorterref # If SQLITE_OMIT_ALTERTABLE is defined, omit this file. ifcapable !altertable { finish_test return } do_execsql_test 1.0 { CREATE TABLE t1(a, b, c); INSERT INTO t1 VALUES(1, 2, 3); INSERT INTO t1 VALUES(4, 5, 6); ALTER TABLE t1 ADD COLUMN d DEFAULT 'string'; INSERT INTO t1 VALUES(7, 8, 9, 'text'); |
︙ | ︙ |
Changes to test/speedtest1.c.
1 2 3 4 5 6 7 8 9 | /* ** A program for performance testing. ** ** The available command-line options are described below: */ static const char zHelp[] = "Usage: %s [--options] DATABASE\n" "Options:\n" " --autovacuum Enable AUTOVACUUM mode\n" | | > > > > > < > > > > > > > > > > > > > > > > > > > > > < > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* ** A program for performance testing. ** ** The available command-line options are described below: */ static const char zHelp[] = "Usage: %s [--options] DATABASE\n" "Options:\n" " --autovacuum Enable AUTOVACUUM mode\n" " --cachesize N Set the cache size to N\n" " --checkpoint Run PRAGMA wal_checkpoint after each test case\n" " --exclusive Enable locking_mode=EXCLUSIVE\n" " --explain Like --sqlonly but with added EXPLAIN keywords\n" " --heap SZ MIN Memory allocator uses SZ bytes & min allocation MIN\n" " --incrvacuum Enable incremenatal vacuum mode\n" " --journal M Set the journal_mode to M\n" " --key KEY Set the encryption key to KEY\n" " --lookaside N SZ Configure lookaside for N slots of SZ bytes each\n" " --memdb Use an in-memory database\n" " --mmap SZ MMAP the first SZ bytes of the database file\n" " --multithread Set multithreaded mode\n" " --nomemstat Disable memory statistics\n" " --nosync Set PRAGMA synchronous=OFF\n" " --notnull Add NOT NULL constraints to table columns\n" " --output FILE Store SQL output in FILE\n" " --pagesize N Set the page size to N\n" " --pcache N SZ Configure N pages of pagecache each of size SZ bytes\n" " --primarykey Use PRIMARY KEY instead of UNIQUE where appropriate\n" " --repeat N Repeat each SELECT N times (default: 1)\n" " --reprepare Reprepare each statement upon every invocation\n" " --reserve N Reserve N bytes on each database page\n" " --serialized Set serialized threading mode\n" " --singlethread Set single-threaded mode - disables all mutexing\n" " --sqlonly No-op. Only show the SQL that would have been run.\n" " --shrink-memory Invoke sqlite3_db_release_memory() frequently.\n" " --size N Relative test size. Default=100\n" " --strict Use STRICT table where appropriate\n" " --stats Show statistics at the end\n" " --temp N N from 0 to 9. 0: no temp table. 9: all temp tables\n" " --testset T Run test-set T (main, cte, rtree, orm, fp, debug)\n" " --trace Turn on SQL tracing\n" " --threads N Use up to N threads for sorting\n" " --utf16be Set text encoding to UTF-16BE\n" " --utf16le Set text encoding to UTF-16LE\n" " --verify Run additional verification steps.\n" " --without-rowid Use WITHOUT ROWID where appropriate\n" ; #include "sqlite3.h" #include <assert.h> #include <stdio.h> #include <stdlib.h> #include <stdarg.h> #include <string.h> #include <ctype.h> #ifndef _WIN32 # include <unistd.h> #else # include <io.h> #endif #define ISSPACE(X) isspace((unsigned char)(X)) #define ISDIGIT(X) isdigit((unsigned char)(X)) #if SQLITE_VERSION_NUMBER<3005000 # define sqlite3_int64 sqlite_int64 #endif typedef sqlite3_uint64 u64; /* ** State structure for a Hash hash in progress */ typedef struct HashContext HashContext; struct HashContext { unsigned char isInit; /* True if initialized */ unsigned char i, j; /* State variables */ unsigned char s[256]; /* State variables */ unsigned char r[32]; /* Result */ }; /* All global state is held in this structure */ static struct Global { sqlite3 *db; /* The open database connection */ sqlite3_stmt *pStmt; /* Current SQL statement */ sqlite3_int64 iStart; /* Start-time for the current test */ sqlite3_int64 iTotal; /* Total time */ int bWithoutRowid; /* True for --without-rowid */ int bReprepare; /* True to reprepare the SQL on each rerun */ int bSqlOnly; /* True to print the SQL once only */ int bExplain; /* Print SQL with EXPLAIN prefix */ int bVerify; /* Try to verify that results are correct */ int bMemShrink; /* Call sqlite3_db_release_memory() often */ int eTemp; /* 0: no TEMP. 9: always TEMP. */ int szTest; /* Scale factor for test iterations */ int nRepeat; /* Repeat selects this many times */ int doCheckpoint; /* Run PRAGMA wal_checkpoint after each trans */ int nReserve; /* Reserve bytes */ const char *zWR; /* Might be WITHOUT ROWID */ const char *zNN; /* Might be NOT NULL */ const char *zPK; /* Might be UNIQUE or PRIMARY KEY */ unsigned int x, y; /* Pseudo-random number generator state */ u64 nResByte; /* Total number of result bytes */ int nResult; /* Size of the current result */ char zResult[3000]; /* Text of the current result */ #ifndef SPEEDTEST_OMIT_HASH FILE *hashFile; /* Store all hash results in this file */ HashContext hash; /* Hash of all output */ #endif } g; /* Return " TEMP" or "", as appropriate for creating a table. */ static const char *isTemp(int N){ return g.eTemp>=N ? " TEMP" : ""; } /* Print an error message and exit */ static void fatal_error(const char *zMsg, ...){ va_list ap; va_start(ap, zMsg); vfprintf(stderr, zMsg, ap); va_end(ap); exit(1); } #ifndef SPEEDTEST_OMIT_HASH /**************************************************************************** ** Hash algorithm used to verify that compilation is not miscompiled ** in such a was as to generate an incorrect result. */ /* ** Initialize a new hash. iSize determines the size of the hash ** in bits and should be one of 224, 256, 384, or 512. Or iSize ** can be zero to use the default hash size of 256 bits. */ static void HashInit(void){ unsigned int k; g.hash.i = 0; g.hash.j = 0; for(k=0; k<256; k++) g.hash.s[k] = k; } /* ** Make consecutive calls to the HashUpdate function to add new content ** to the hash */ static void HashUpdate( const unsigned char *aData, unsigned int nData ){ unsigned char t; unsigned char i = g.hash.i; unsigned char j = g.hash.j; unsigned int k; if( g.hashFile ) fwrite(aData, 1, nData, g.hashFile); for(k=0; k<nData; k++){ j += g.hash.s[i] + aData[k]; t = g.hash.s[j]; g.hash.s[j] = g.hash.s[i]; g.hash.s[i] = t; i++; } g.hash.i = i; g.hash.j = j; } /* ** After all content has been added, invoke HashFinal() to compute ** the final hash. The hash result is stored in g.hash.r[]. */ static void HashFinal(void){ unsigned int k; unsigned char t, i, j; i = g.hash.i; j = g.hash.j; for(k=0; k<32; k++){ i++; t = g.hash.s[i]; j += t; g.hash.s[i] = g.hash.s[j]; g.hash.s[j] = t; t += g.hash.s[i]; g.hash.r[k] = g.hash.s[t]; } } /* End of the Hash hashing logic *****************************************************************************/ #endif /* SPEEDTEST_OMIT_HASH */ /* ** Return the value of a hexadecimal digit. Return -1 if the input ** is not a hex digit. */ static int hexDigitValue(char c){ if( c>='0' && c<='9' ) return c - '0'; if( c>='a' && c<='f' ) return c - 'a' + 10; |
︙ | ︙ | |||
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 | sqlite3_free(zName); g.nResult = 0; g.iStart = speedtest1_timestamp(); g.x = 0xad131d0b; g.y = 0x44f9eac8; } /* Complete a test case */ void speedtest1_end_test(void){ sqlite3_int64 iElapseTime = speedtest1_timestamp() - g.iStart; if( !g.bSqlOnly ){ g.iTotal += iElapseTime; printf("%4d.%03ds\n", (int)(iElapseTime/1000), (int)(iElapseTime%1000)); } if( g.pStmt ){ sqlite3_finalize(g.pStmt); g.pStmt = 0; } } /* Report end of testing */ void speedtest1_final(void){ if( !g.bSqlOnly ){ printf(" TOTAL%.*s %4d.%03ds\n", NAMEWIDTH-5, zDots, (int)(g.iTotal/1000), (int)(g.iTotal%1000)); } } /* Print an SQL statement to standard output */ static void printSql(const char *zSql){ int n = (int)strlen(zSql); while( n>0 && (zSql[n-1]==';' || ISSPACE(zSql[n-1])) ){ n--; } | > > > > > > > > > > > > > > > > > > > | 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 | sqlite3_free(zName); g.nResult = 0; g.iStart = speedtest1_timestamp(); g.x = 0xad131d0b; g.y = 0x44f9eac8; } /* Forward reference */ void speedtest1_exec(const char*,...); /* Complete a test case */ void speedtest1_end_test(void){ sqlite3_int64 iElapseTime = speedtest1_timestamp() - g.iStart; if( g.doCheckpoint ) speedtest1_exec("PRAGMA wal_checkpoint;"); if( !g.bSqlOnly ){ g.iTotal += iElapseTime; printf("%4d.%03ds\n", (int)(iElapseTime/1000), (int)(iElapseTime%1000)); } if( g.pStmt ){ sqlite3_finalize(g.pStmt); g.pStmt = 0; } } /* Report end of testing */ void speedtest1_final(void){ if( !g.bSqlOnly ){ printf(" TOTAL%.*s %4d.%03ds\n", NAMEWIDTH-5, zDots, (int)(g.iTotal/1000), (int)(g.iTotal%1000)); } if( g.bVerify ){ #ifndef SPEEDTEST_OMIT_HASH int i; #endif printf("Verification Hash: %llu ", g.nResByte); #ifndef SPEEDTEST_OMIT_HASH HashUpdate((const unsigned char*)"\n", 1); HashFinal(); for(i=0; i<24; i++){ printf("%02x", g.hash.r[i]); } if( g.hashFile && g.hashFile!=stdout ) fclose(g.hashFile); #endif printf("\n"); } } /* Print an SQL statement to standard output */ static void printSql(const char *zSql){ int n = (int)strlen(zSql); while( n>0 && (zSql[n-1]==';' || ISSPACE(zSql[n-1])) ){ n--; } |
︙ | ︙ | |||
367 368 369 370 371 372 373 374 375 376 377 378 379 380 | int rc = sqlite3_exec(g.db, zSql, 0, 0, &zErrMsg); if( zErrMsg ) fatal_error("SQL error: %s\n%s\n", zErrMsg, zSql); if( rc!=SQLITE_OK ) fatal_error("exec error: %s\n", sqlite3_errmsg(g.db)); } sqlite3_free(zSql); speedtest1_shrink_memory(); } /* Prepare an SQL statement */ void speedtest1_prepare(const char *zFormat, ...){ va_list ap; char *zSql; va_start(ap, zFormat); zSql = sqlite3_vmprintf(zFormat, ap); | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | int rc = sqlite3_exec(g.db, zSql, 0, 0, &zErrMsg); if( zErrMsg ) fatal_error("SQL error: %s\n%s\n", zErrMsg, zSql); if( rc!=SQLITE_OK ) fatal_error("exec error: %s\n", sqlite3_errmsg(g.db)); } sqlite3_free(zSql); speedtest1_shrink_memory(); } /* Run SQL and return the first column of the first row as a string. The ** returned string is obtained from sqlite_malloc() and must be freed by ** the caller. */ char *speedtest1_once(const char *zFormat, ...){ va_list ap; char *zSql; sqlite3_stmt *pStmt; char *zResult = 0; va_start(ap, zFormat); zSql = sqlite3_vmprintf(zFormat, ap); va_end(ap); if( g.bSqlOnly ){ printSql(zSql); }else{ int rc = sqlite3_prepare_v2(g.db, zSql, -1, &pStmt, 0); if( rc ){ fatal_error("SQL error: %s\n", sqlite3_errmsg(g.db)); } if( sqlite3_step(pStmt)==SQLITE_ROW ){ const char *z = (const char*)sqlite3_column_text(pStmt, 0); if( z ) zResult = sqlite3_mprintf("%s", z); } sqlite3_finalize(pStmt); } sqlite3_free(zSql); speedtest1_shrink_memory(); return zResult; } /* Prepare an SQL statement */ void speedtest1_prepare(const char *zFormat, ...){ va_list ap; char *zSql; va_start(ap, zFormat); zSql = sqlite3_vmprintf(zFormat, ap); |
︙ | ︙ | |||
400 401 402 403 404 405 406 407 408 409 410 411 412 413 | g.nResult = 0; while( sqlite3_step(g.pStmt)==SQLITE_ROW ){ n = sqlite3_column_count(g.pStmt); for(i=0; i<n; i++){ const char *z = (const char*)sqlite3_column_text(g.pStmt, i); if( z==0 ) z = "nil"; len = (int)strlen(z); if( g.nResult+len<sizeof(g.zResult)-2 ){ if( g.nResult>0 ) g.zResult[g.nResult++] = ' '; memcpy(g.zResult + g.nResult, z, len+1); g.nResult += len; } } } | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | g.nResult = 0; while( sqlite3_step(g.pStmt)==SQLITE_ROW ){ n = sqlite3_column_count(g.pStmt); for(i=0; i<n; i++){ const char *z = (const char*)sqlite3_column_text(g.pStmt, i); if( z==0 ) z = "nil"; len = (int)strlen(z); #ifndef SPEEDTEST_OMIT_HASH if( g.bVerify ){ int eType = sqlite3_column_type(g.pStmt, i); unsigned char zPrefix[2]; zPrefix[0] = '\n'; zPrefix[1] = "-IFTBN"[eType]; if( g.nResByte ){ HashUpdate(zPrefix, 2); }else{ HashUpdate(zPrefix+1, 1); } if( eType==SQLITE_FLOAT ){ /* Omit the value of floating-point results from the verification ** hash. The only thing we record is the fact that the result was ** a floating-point value. */ g.nResByte += 2; }else if( eType==SQLITE_BLOB ){ int nBlob = sqlite3_column_bytes(g.pStmt, i); int iBlob; unsigned char zChar[2]; const unsigned char *aBlob = sqlite3_column_blob(g.pStmt, i); for(iBlob=0; iBlob<nBlob; iBlob++){ zChar[0] = "0123456789abcdef"[aBlob[iBlob]>>4]; zChar[1] = "0123456789abcdef"[aBlob[iBlob]&15]; HashUpdate(zChar,2); } g.nResByte += nBlob*2 + 2; }else{ HashUpdate((unsigned char*)z, len); g.nResByte += len + 2; } } #endif if( g.nResult+len<sizeof(g.zResult)-2 ){ if( g.nResult>0 ) g.zResult[g.nResult++] = ' '; memcpy(g.zResult + g.nResult, z, len+1); g.nResult += len; } } } |
︙ | ︙ | |||
532 533 534 535 536 537 538 | char zNum[2000]; /* A number name */ sz = n = g.szTest*500; zNum[0] = 0; maxb = roundup_allones(sz); speedtest1_begin_test(100, "%d INSERTs into table with no index", n); speedtest1_exec("BEGIN"); | | | | | | 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 | char zNum[2000]; /* A number name */ sz = n = g.szTest*500; zNum[0] = 0; maxb = roundup_allones(sz); speedtest1_begin_test(100, "%d INSERTs into table with no index", n); speedtest1_exec("BEGIN"); speedtest1_exec("CREATE%s TABLE z1(a INTEGER %s, b INTEGER %s, c TEXT %s);", isTemp(9), g.zNN, g.zNN, g.zNN); speedtest1_prepare("INSERT INTO z1 VALUES(?1,?2,?3); -- %d times", n); for(i=1; i<=n; i++){ x1 = swizzle(i,maxb); speedtest1_numbername(x1, zNum, sizeof(zNum)); sqlite3_bind_int64(g.pStmt, 1, (sqlite3_int64)x1); sqlite3_bind_int(g.pStmt, 2, i); sqlite3_bind_text(g.pStmt, 3, zNum, -1, SQLITE_STATIC); speedtest1_run(); } speedtest1_exec("COMMIT"); speedtest1_end_test(); n = sz; speedtest1_begin_test(110, "%d ordered INSERTS with one index/PK", n); speedtest1_exec("BEGIN"); speedtest1_exec( "CREATE%s TABLE z2(a INTEGER %s %s, b INTEGER %s, c TEXT %s) %s", isTemp(5), g.zNN, g.zPK, g.zNN, g.zNN, g.zWR); speedtest1_prepare("INSERT INTO z2 VALUES(?1,?2,?3); -- %d times", n); for(i=1; i<=n; i++){ x1 = swizzle(i,maxb); speedtest1_numbername(x1, zNum, sizeof(zNum)); sqlite3_bind_int(g.pStmt, 1, i); sqlite3_bind_int64(g.pStmt, 2, (sqlite3_int64)x1); sqlite3_bind_text(g.pStmt, 3, zNum, -1, SQLITE_STATIC); speedtest1_run(); |
︙ | ︙ | |||
593 594 595 596 597 598 599 | 0, groupStep, groupFinal); #endif n = 25; speedtest1_begin_test(130, "%d SELECTS, numeric BETWEEN, unindexed", n); speedtest1_exec("BEGIN"); speedtest1_prepare( | | | | 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 | 0, groupStep, groupFinal); #endif n = 25; speedtest1_begin_test(130, "%d SELECTS, numeric BETWEEN, unindexed", n); speedtest1_exec("BEGIN"); speedtest1_prepare( "SELECT count(*), avg(b), sum(length(c)), group_concat(c) FROM z1\n" " WHERE b BETWEEN ?1 AND ?2; -- %d times", n ); for(i=1; i<=n; i++){ if( (i-1)%g.nRepeat==0 ){ x1 = speedtest1_random()%maxb; x2 = speedtest1_random()%10 + sz/5000 + x1; } sqlite3_bind_int(g.pStmt, 1, x1); sqlite3_bind_int(g.pStmt, 2, x2); speedtest1_run(); } speedtest1_exec("COMMIT"); speedtest1_end_test(); n = 10; speedtest1_begin_test(140, "%d SELECTS, LIKE, unindexed", n); speedtest1_exec("BEGIN"); speedtest1_prepare( "SELECT count(*), avg(b), sum(length(c)), group_concat(c) FROM z1\n" " WHERE c LIKE ?1; -- %d times", n ); for(i=1; i<=n; i++){ if( (i-1)%g.nRepeat==0 ){ x1 = speedtest1_random()%maxb; zNum[0] = '%'; len = speedtest1_numbername(i, zNum+1, sizeof(zNum)-2); |
︙ | ︙ | |||
635 636 637 638 639 640 641 | speedtest1_end_test(); n = 10; speedtest1_begin_test(142, "%d SELECTS w/ORDER BY, unindexed", n); speedtest1_exec("BEGIN"); speedtest1_prepare( | | | | | | | | | | | 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 | speedtest1_end_test(); n = 10; speedtest1_begin_test(142, "%d SELECTS w/ORDER BY, unindexed", n); speedtest1_exec("BEGIN"); speedtest1_prepare( "SELECT a, b, c FROM z1 WHERE c LIKE ?1\n" " ORDER BY a; -- %d times", n ); for(i=1; i<=n; i++){ if( (i-1)%g.nRepeat==0 ){ x1 = speedtest1_random()%maxb; zNum[0] = '%'; len = speedtest1_numbername(i, zNum+1, sizeof(zNum)-2); zNum[len] = '%'; zNum[len+1] = 0; } sqlite3_bind_text(g.pStmt, 1, zNum, len+1, SQLITE_STATIC); speedtest1_run(); } speedtest1_exec("COMMIT"); speedtest1_end_test(); n = 10; /* g.szTest/5; */ speedtest1_begin_test(145, "%d SELECTS w/ORDER BY and LIMIT, unindexed", n); speedtest1_exec("BEGIN"); speedtest1_prepare( "SELECT a, b, c FROM z1 WHERE c LIKE ?1\n" " ORDER BY a LIMIT 10; -- %d times", n ); for(i=1; i<=n; i++){ if( (i-1)%g.nRepeat==0 ){ x1 = speedtest1_random()%maxb; zNum[0] = '%'; len = speedtest1_numbername(i, zNum+1, sizeof(zNum)-2); zNum[len] = '%'; zNum[len+1] = 0; } sqlite3_bind_text(g.pStmt, 1, zNum, len+1, SQLITE_STATIC); speedtest1_run(); } speedtest1_exec("COMMIT"); speedtest1_end_test(); speedtest1_begin_test(150, "CREATE INDEX five times"); speedtest1_exec("BEGIN;"); speedtest1_exec("CREATE UNIQUE INDEX t1b ON z1(b);"); speedtest1_exec("CREATE INDEX t1c ON z1(c);"); speedtest1_exec("CREATE UNIQUE INDEX t2b ON z2(b);"); speedtest1_exec("CREATE INDEX t2c ON z2(c DESC);"); speedtest1_exec("CREATE INDEX t3bc ON t3(b,c);"); speedtest1_exec("COMMIT;"); speedtest1_end_test(); n = sz/5; speedtest1_begin_test(160, "%d SELECTS, numeric BETWEEN, indexed", n); speedtest1_exec("BEGIN"); speedtest1_prepare( "SELECT count(*), avg(b), sum(length(c)), group_concat(a) FROM z1\n" " WHERE b BETWEEN ?1 AND ?2; -- %d times", n ); for(i=1; i<=n; i++){ if( (i-1)%g.nRepeat==0 ){ x1 = speedtest1_random()%maxb; x2 = speedtest1_random()%10 + sz/5000 + x1; } sqlite3_bind_int(g.pStmt, 1, x1); sqlite3_bind_int(g.pStmt, 2, x2); speedtest1_run(); } speedtest1_exec("COMMIT"); speedtest1_end_test(); n = sz/5; speedtest1_begin_test(161, "%d SELECTS, numeric BETWEEN, PK", n); speedtest1_exec("BEGIN"); speedtest1_prepare( "SELECT count(*), avg(b), sum(length(c)), group_concat(a) FROM z2\n" " WHERE a BETWEEN ?1 AND ?2; -- %d times", n ); for(i=1; i<=n; i++){ if( (i-1)%g.nRepeat==0 ){ x1 = speedtest1_random()%maxb; x2 = speedtest1_random()%10 + sz/5000 + x1; } sqlite3_bind_int(g.pStmt, 1, x1); sqlite3_bind_int(g.pStmt, 2, x2); speedtest1_run(); } speedtest1_exec("COMMIT"); speedtest1_end_test(); n = sz/5; speedtest1_begin_test(170, "%d SELECTS, text BETWEEN, indexed", n); speedtest1_exec("BEGIN"); speedtest1_prepare( "SELECT count(*), avg(b), sum(length(c)), group_concat(a) FROM z1\n" " WHERE c BETWEEN ?1 AND (?1||'~'); -- %d times", n ); for(i=1; i<=n; i++){ if( (i-1)%g.nRepeat==0 ){ x1 = swizzle(i, maxb); len = speedtest1_numbername(x1, zNum, sizeof(zNum)-1); } |
︙ | ︙ | |||
755 756 757 758 759 760 761 | " a INTEGER %s %s,\n" " b INTEGER %s,\n" " c TEXT %s\n" ") %s", isTemp(1), g.zNN, g.zPK, g.zNN, g.zNN, g.zWR); speedtest1_exec("CREATE INDEX t4b ON t4(b)"); speedtest1_exec("CREATE INDEX t4c ON t4(c)"); | | | | | | | | | | | | 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 | " a INTEGER %s %s,\n" " b INTEGER %s,\n" " c TEXT %s\n" ") %s", isTemp(1), g.zNN, g.zPK, g.zNN, g.zNN, g.zWR); speedtest1_exec("CREATE INDEX t4b ON t4(b)"); speedtest1_exec("CREATE INDEX t4c ON t4(c)"); speedtest1_exec("INSERT INTO t4 SELECT * FROM z1"); speedtest1_exec("COMMIT"); speedtest1_end_test(); n = sz; speedtest1_begin_test(190, "DELETE and REFILL one table", n); speedtest1_exec("DELETE FROM z2;"); speedtest1_exec("INSERT INTO z2 SELECT * FROM z1;"); speedtest1_end_test(); speedtest1_begin_test(200, "VACUUM"); speedtest1_exec("VACUUM"); speedtest1_end_test(); speedtest1_begin_test(210, "ALTER TABLE ADD COLUMN, and query"); speedtest1_exec("ALTER TABLE z2 ADD COLUMN d INT DEFAULT 123"); speedtest1_exec("SELECT sum(d) FROM z2"); speedtest1_end_test(); n = sz/5; speedtest1_begin_test(230, "%d UPDATES, numeric BETWEEN, indexed", n); speedtest1_exec("BEGIN"); speedtest1_prepare( "UPDATE z2 SET d=b*2 WHERE b BETWEEN ?1 AND ?2; -- %d times", n ); for(i=1; i<=n; i++){ x1 = speedtest1_random()%maxb; x2 = speedtest1_random()%10 + sz/5000 + x1; sqlite3_bind_int(g.pStmt, 1, x1); sqlite3_bind_int(g.pStmt, 2, x2); speedtest1_run(); } speedtest1_exec("COMMIT"); speedtest1_end_test(); n = sz; speedtest1_begin_test(240, "%d UPDATES of individual rows", n); speedtest1_exec("BEGIN"); speedtest1_prepare( "UPDATE z2 SET d=b*3 WHERE a=?1; -- %d times", n ); for(i=1; i<=n; i++){ x1 = speedtest1_random()%sz + 1; sqlite3_bind_int(g.pStmt, 1, x1); speedtest1_run(); } speedtest1_exec("COMMIT"); speedtest1_end_test(); speedtest1_begin_test(250, "One big UPDATE of the whole %d-row table", sz); speedtest1_exec("UPDATE z2 SET d=b*4"); speedtest1_end_test(); speedtest1_begin_test(260, "Query added column after filling"); speedtest1_exec("SELECT sum(d) FROM z2"); speedtest1_end_test(); n = sz/5; speedtest1_begin_test(270, "%d DELETEs, numeric BETWEEN, indexed", n); speedtest1_exec("BEGIN"); speedtest1_prepare( "DELETE FROM z2 WHERE b BETWEEN ?1 AND ?2; -- %d times", n ); for(i=1; i<=n; i++){ x1 = speedtest1_random()%maxb + 1; x2 = speedtest1_random()%10 + sz/5000 + x1; sqlite3_bind_int(g.pStmt, 1, x1); sqlite3_bind_int(g.pStmt, 2, x2); speedtest1_run(); |
︙ | ︙ | |||
852 853 854 855 856 857 858 | speedtest1_run(); } speedtest1_exec("COMMIT"); speedtest1_end_test(); speedtest1_begin_test(290, "Refill two %d-row tables using REPLACE", sz); | | | | | | | | | | | | | | 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 | speedtest1_run(); } speedtest1_exec("COMMIT"); speedtest1_end_test(); speedtest1_begin_test(290, "Refill two %d-row tables using REPLACE", sz); speedtest1_exec("REPLACE INTO z2(a,b,c) SELECT a,b,c FROM z1"); speedtest1_exec("REPLACE INTO t3(a,b,c) SELECT a,b,c FROM z1"); speedtest1_end_test(); speedtest1_begin_test(300, "Refill a %d-row table using (b&1)==(a&1)", sz); speedtest1_exec("DELETE FROM z2;"); speedtest1_exec("INSERT INTO z2(a,b,c)\n" " SELECT a,b,c FROM z1 WHERE (b&1)==(a&1);"); speedtest1_exec("INSERT INTO z2(a,b,c)\n" " SELECT a,b,c FROM z1 WHERE (b&1)<>(a&1);"); speedtest1_end_test(); n = sz/5; speedtest1_begin_test(310, "%d four-ways joins", n); speedtest1_exec("BEGIN"); speedtest1_prepare( "SELECT z1.c FROM z1, z2, t3, t4\n" " WHERE t4.a BETWEEN ?1 AND ?2\n" " AND t3.a=t4.b\n" " AND z2.a=t3.b\n" " AND z1.c=z2.c" ); for(i=1; i<=n; i++){ x1 = speedtest1_random()%sz + 1; x2 = speedtest1_random()%10 + x1 + 4; sqlite3_bind_int(g.pStmt, 1, x1); sqlite3_bind_int(g.pStmt, 2, x2); speedtest1_run(); } speedtest1_exec("COMMIT"); speedtest1_end_test(); speedtest1_begin_test(320, "subquery in result set", n); speedtest1_prepare( "SELECT sum(a), max(c),\n" " avg((SELECT a FROM z2 WHERE 5+z2.b=z1.b) AND rowid<?1), max(c)\n" " FROM z1 WHERE rowid<?1;" ); sqlite3_bind_int(g.pStmt, 1, est_square_root(g.szTest)*50); speedtest1_run(); speedtest1_end_test(); sz = n = g.szTest*700; zNum[0] = 0; |
︙ | ︙ | |||
1107 1108 1109 1110 1111 1112 1113 | speedtest1_run(); speedtest1_end_test(); nElem = 10000*g.szTest; speedtest1_begin_test(400, "EXCEPT operator on %d-element tables", nElem); speedtest1_prepare( "WITH RECURSIVE \n" | | | | | 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 | speedtest1_run(); speedtest1_end_test(); nElem = 10000*g.szTest; speedtest1_begin_test(400, "EXCEPT operator on %d-element tables", nElem); speedtest1_prepare( "WITH RECURSIVE \n" " z1(x) AS (VALUES(2) UNION ALL SELECT x+2 FROM z1 WHERE x<%d),\n" " z2(y) AS (VALUES(3) UNION ALL SELECT y+3 FROM z2 WHERE y<%d)\n" "SELECT count(x), avg(x) FROM (\n" " SELECT x FROM z1 EXCEPT SELECT y FROM z2 ORDER BY 1\n" ");", nElem, nElem ); speedtest1_run(); speedtest1_end_test(); } |
︙ | ︙ | |||
1143 1144 1145 1146 1147 1148 1149 | int i; char zFP1[100]; char zFP2[100]; n = g.szTest*5000; speedtest1_begin_test(100, "Fill a table with %d FP values", n*2); speedtest1_exec("BEGIN"); | | | | | | | | > > > > > > > > > > > > > | 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 | int i; char zFP1[100]; char zFP2[100]; n = g.szTest*5000; speedtest1_begin_test(100, "Fill a table with %d FP values", n*2); speedtest1_exec("BEGIN"); speedtest1_exec("CREATE%s TABLE z1(a REAL %s, b REAL %s);", isTemp(1), g.zNN, g.zNN); speedtest1_prepare("INSERT INTO z1 VALUES(?1,?2); -- %d times", n); for(i=1; i<=n; i++){ speedtest1_random_ascii_fp(zFP1); speedtest1_random_ascii_fp(zFP2); sqlite3_bind_text(g.pStmt, 1, zFP1, -1, SQLITE_STATIC); sqlite3_bind_text(g.pStmt, 2, zFP2, -1, SQLITE_STATIC); speedtest1_run(); } speedtest1_exec("COMMIT"); speedtest1_end_test(); n = g.szTest/25 + 2; speedtest1_begin_test(110, "%d range queries", n); speedtest1_prepare("SELECT sum(b) FROM z1 WHERE a BETWEEN ?1 AND ?2"); for(i=1; i<=n; i++){ speedtest1_random_ascii_fp(zFP1); speedtest1_random_ascii_fp(zFP2); sqlite3_bind_text(g.pStmt, 1, zFP1, -1, SQLITE_STATIC); sqlite3_bind_text(g.pStmt, 2, zFP2, -1, SQLITE_STATIC); speedtest1_run(); } speedtest1_end_test(); speedtest1_begin_test(120, "CREATE INDEX three times"); speedtest1_exec("BEGIN;"); speedtest1_exec("CREATE INDEX t1a ON z1(a);"); speedtest1_exec("CREATE INDEX t1b ON z1(b);"); speedtest1_exec("CREATE INDEX t1ab ON z1(a,b);"); speedtest1_exec("COMMIT;"); speedtest1_end_test(); n = g.szTest/3 + 2; speedtest1_begin_test(130, "%d indexed range queries", n); speedtest1_prepare("SELECT sum(b) FROM z1 WHERE a BETWEEN ?1 AND ?2"); for(i=1; i<=n; i++){ speedtest1_random_ascii_fp(zFP1); speedtest1_random_ascii_fp(zFP2); sqlite3_bind_text(g.pStmt, 1, zFP1, -1, SQLITE_STATIC); sqlite3_bind_text(g.pStmt, 2, zFP2, -1, SQLITE_STATIC); speedtest1_run(); } speedtest1_end_test(); n = g.szTest*5000; speedtest1_begin_test(140, "%d calls to round()", n); speedtest1_exec("SELECT sum(round(a,2)+round(b,4)) FROM z1;"); speedtest1_end_test(); speedtest1_begin_test(150, "%d printf() calls", n*4); speedtest1_exec( "WITH c(fmt) AS (VALUES('%%g'),('%%e'),('%%!g'),('%%.20f'))" "SELECT sum(printf(fmt,a)) FROM z1, c" ); speedtest1_end_test(); } #ifdef SQLITE_ENABLE_RTREE /* Generate two numbers between 1 and mx. The first number is less than ** the second. Usually the numbers are near each other but can sometimes ** be far apart. */ |
︙ | ︙ | |||
1270 1271 1272 1273 1274 1275 1276 | sqlite3_bind_int(g.pStmt, 7, z1); speedtest1_run(); } speedtest1_exec("COMMIT"); speedtest1_end_test(); speedtest1_begin_test(101, "Copy from rtree to a regular table"); | | | | | 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 | sqlite3_bind_int(g.pStmt, 7, z1); speedtest1_run(); } speedtest1_exec("COMMIT"); speedtest1_end_test(); speedtest1_begin_test(101, "Copy from rtree to a regular table"); speedtest1_exec("CREATE TABLE z1(id INTEGER PRIMARY KEY,x0,x1,y0,y1,z0,z1)"); speedtest1_exec("INSERT INTO z1 SELECT * FROM rt1"); speedtest1_end_test(); n = g.szTest*200; speedtest1_begin_test(110, "%d one-dimensional intersect slice queries", n); speedtest1_prepare("SELECT count(*) FROM rt1 WHERE x0>=?1 AND x1<=?2"); iStep = mxCoord/n; for(i=0; i<n; i++){ sqlite3_bind_int(g.pStmt, 1, i*iStep); sqlite3_bind_int(g.pStmt, 2, (i+1)*iStep); speedtest1_run(); aCheck[i] = atoi(g.zResult); } speedtest1_end_test(); if( g.bVerify ){ n = g.szTest*200; speedtest1_begin_test(111, "Verify result from 1-D intersect slice queries"); speedtest1_prepare("SELECT count(*) FROM z1 WHERE x0>=?1 AND x1<=?2"); iStep = mxCoord/n; for(i=0; i<n; i++){ sqlite3_bind_int(g.pStmt, 1, i*iStep); sqlite3_bind_int(g.pStmt, 2, (i+1)*iStep); speedtest1_run(); if( aCheck[i]!=atoi(g.zResult) ){ fatal_error("Count disagree step %d: %d..%d. %d vs %d", |
︙ | ︙ | |||
1318 1319 1320 1321 1322 1323 1324 | aCheck[i] = atoi(g.zResult); } speedtest1_end_test(); if( g.bVerify ){ n = g.szTest*200; speedtest1_begin_test(121, "Verify result from 1-D overlap slice queries"); | | | 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 | aCheck[i] = atoi(g.zResult); } speedtest1_end_test(); if( g.bVerify ){ n = g.szTest*200; speedtest1_begin_test(121, "Verify result from 1-D overlap slice queries"); speedtest1_prepare("SELECT count(*) FROM z1 WHERE y1>=?1 AND y0<=?2"); iStep = mxCoord/n; for(i=0; i<n; i++){ sqlite3_bind_int(g.pStmt, 1, i*iStep); sqlite3_bind_int(g.pStmt, 2, (i+1)*iStep); speedtest1_run(); if( aCheck[i]!=atoi(g.zResult) ){ fatal_error("Count disagree step %d: %d..%d. %d vs %d", |
︙ | ︙ | |||
1414 1415 1416 1417 1418 1419 1420 | sqlite3_bind_int(g.pStmt, 1, i*iStep); speedtest1_run(); aCheck[i] = atoi(g.zResult); } speedtest1_end_test(); speedtest1_begin_test(170, "Restore deleted entries using INSERT OR IGNORE"); | | | 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 | sqlite3_bind_int(g.pStmt, 1, i*iStep); speedtest1_run(); aCheck[i] = atoi(g.zResult); } speedtest1_end_test(); speedtest1_begin_test(170, "Restore deleted entries using INSERT OR IGNORE"); speedtest1_exec("INSERT OR IGNORE INTO rt1 SELECT * FROM z1"); speedtest1_end_test(); } #endif /* SQLITE_ENABLE_RTREE */ /* ** A testset that does key/value storage on tables with many columns. ** This is the kind of workload generated by ORMs such as CoreData. |
︙ | ︙ | |||
1699 1700 1701 1702 1703 1704 1705 | char zNum[2000]; /* A number name */ const int NROW = 500*g.szTest; const int NROW2 = 100*g.szTest; speedtest1_exec( "BEGIN;" | | | | | | | | | | 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 | char zNum[2000]; /* A number name */ const int NROW = 500*g.szTest; const int NROW2 = 100*g.szTest; speedtest1_exec( "BEGIN;" "CREATE TABLE z1(rowid INTEGER PRIMARY KEY, i INTEGER, t TEXT);" "CREATE TABLE z2(rowid INTEGER PRIMARY KEY, i INTEGER, t TEXT);" "CREATE TABLE t3(rowid INTEGER PRIMARY KEY, i INTEGER, t TEXT);" "CREATE VIEW v1 AS SELECT rowid, i, t FROM z1;" "CREATE VIEW v2 AS SELECT rowid, i, t FROM z2;" "CREATE VIEW v3 AS SELECT rowid, i, t FROM t3;" ); for(jj=1; jj<=3; jj++){ speedtest1_prepare("INSERT INTO t%d VALUES(NULL,?1,?2)", jj); for(ii=0; ii<NROW; ii++){ int x1 = speedtest1_random() % NROW; speedtest1_numbername(x1, zNum, sizeof(zNum)); sqlite3_bind_int(g.pStmt, 1, x1); sqlite3_bind_text(g.pStmt, 2, zNum, -1, SQLITE_STATIC); speedtest1_run(); } } speedtest1_exec( "CREATE INDEX i1 ON z1(t);" "CREATE INDEX i2 ON z2(t);" "CREATE INDEX i3 ON t3(t);" "COMMIT;" ); speedtest1_begin_test(100, "speed4p-join1"); speedtest1_prepare( "SELECT * FROM z1, z2, t3 WHERE z1.oid = z2.oid AND z2.oid = t3.oid" ); speedtest1_run(); speedtest1_end_test(); speedtest1_begin_test(110, "speed4p-join2"); speedtest1_prepare( "SELECT * FROM z1, z2, t3 WHERE z1.t = z2.t AND z2.t = t3.t" ); speedtest1_run(); speedtest1_end_test(); speedtest1_begin_test(120, "speed4p-view1"); for(jj=1; jj<=3; jj++){ speedtest1_prepare("SELECT * FROM v%d WHERE rowid = ?", jj); |
︙ | ︙ | |||
1769 1770 1771 1772 1773 1774 1775 | speedtest1_run(); } } speedtest1_end_test(); speedtest1_begin_test(150, "speed4p-subselect1"); speedtest1_prepare("SELECT " | | | | | | 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 | speedtest1_run(); } } speedtest1_end_test(); speedtest1_begin_test(150, "speed4p-subselect1"); speedtest1_prepare("SELECT " "(SELECT t FROM z1 WHERE rowid = ?1)," "(SELECT t FROM z2 WHERE rowid = ?1)," "(SELECT t FROM t3 WHERE rowid = ?1)" ); for(jj=0; jj<NROW2; jj++){ sqlite3_bind_int(g.pStmt, 1, jj*3); speedtest1_run(); } speedtest1_end_test(); speedtest1_begin_test(160, "speed4p-rowid-update"); speedtest1_exec("BEGIN"); speedtest1_prepare("UPDATE z1 SET i=i+1 WHERE rowid=?1"); for(jj=0; jj<NROW2; jj++){ sqlite3_bind_int(g.pStmt, 1, jj); speedtest1_run(); } speedtest1_exec("COMMIT"); speedtest1_end_test(); speedtest1_exec("CREATE TABLE t5(t TEXT PRIMARY KEY, i INTEGER);"); speedtest1_begin_test(170, "speed4p-insert-ignore"); speedtest1_exec("INSERT OR IGNORE INTO t5 SELECT t, i FROM z1"); speedtest1_end_test(); speedtest1_exec( "CREATE TABLE log(op TEXT, r INTEGER, i INTEGER, t TEXT);" "CREATE TABLE t4(rowid INTEGER PRIMARY KEY, i INTEGER, t TEXT);" "CREATE TRIGGER t4_trigger1 AFTER INSERT ON t4 BEGIN" " INSERT INTO log VALUES('INSERT INTO t4', new.rowid, new.i, new.t);" |
︙ | ︙ | |||
1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 | fclose(in); } #endif #if SQLITE_VERSION_NUMBER<3006018 # define sqlite3_sourceid(X) "(before 3.6.18)" #endif static int xCompileOptions(void *pCtx, int nVal, char **azVal, char **azCol){ printf("-- Compile option: %s\n", azVal[0]); return SQLITE_OK; } int main(int argc, char **argv){ | > > > > | 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 | fclose(in); } #endif #if SQLITE_VERSION_NUMBER<3006018 # define sqlite3_sourceid(X) "(before 3.6.18)" #endif #if SQLITE_CKSUMVFS_STATIC int sqlite3_register_cksumvfs(const char*); #endif static int xCompileOptions(void *pCtx, int nVal, char **azVal, char **azCol){ printf("-- Compile option: %s\n", azVal[0]); return SQLITE_OK; } int main(int argc, char **argv){ |
︙ | ︙ | |||
1970 1971 1972 1973 1974 1975 1976 | int noSync = 0; /* True for --nosync */ int pageSize = 0; /* Desired page size. 0 means default */ int nPCache = 0, szPCache = 0;/* --pcache configuration */ int doPCache = 0; /* True if --pcache is seen */ int showStats = 0; /* True for --stats */ int nThread = 0; /* --threads value */ int mmapSize = 0; /* How big of a memory map to use */ | > | > > > > | > > | 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 | int noSync = 0; /* True for --nosync */ int pageSize = 0; /* Desired page size. 0 means default */ int nPCache = 0, szPCache = 0;/* --pcache configuration */ int doPCache = 0; /* True if --pcache is seen */ int showStats = 0; /* True for --stats */ int nThread = 0; /* --threads value */ int mmapSize = 0; /* How big of a memory map to use */ int memDb = 0; /* --memdb. Use an in-memory database */ char *zTSet = "main"; /* Which --testset torun */ int doTrace = 0; /* True for --trace */ const char *zEncoding = 0; /* --utf16be or --utf16le */ const char *zDbName = 0; /* Name of the test database */ void *pHeap = 0; /* Allocated heap space */ void *pLook = 0; /* Allocated lookaside space */ void *pPCache = 0; /* Allocated storage for pcache */ int iCur, iHi; /* Stats values, current and "highwater" */ int i; /* Loop counter */ int rc; /* API return code */ #ifdef SQLITE_CKSUMVFS_STATIC sqlite3_register_cksumvfs(0); #endif /* Display the version of SQLite being tested */ printf("-- Speedtest1 for SQLite %s %.48s\n", sqlite3_libversion(), sqlite3_sourceid()); /* Process command-line arguments */ g.zWR = ""; g.zNN = ""; g.zPK = "UNIQUE"; g.szTest = 100; g.nRepeat = 1; for(i=1; i<argc; i++){ const char *z = argv[i]; if( z[0]=='-' ){ do{ z++; }while( z[0]=='-' ); if( strcmp(z,"autovacuum")==0 ){ doAutovac = 1; }else if( strcmp(z,"cachesize")==0 ){ if( i>=argc-1 ) fatal_error("missing argument on %s\n", argv[i]); i++; cacheSize = integerValue(argv[i]); }else if( strcmp(z,"exclusive")==0 ){ doExclusive = 1; }else if( strcmp(z,"checkpoint")==0 ){ g.doCheckpoint = 1; }else if( strcmp(z,"explain")==0 ){ g.bSqlOnly = 1; g.bExplain = 1; }else if( strcmp(z,"heap")==0 ){ if( i>=argc-2 ) fatal_error("missing arguments on %s\n", argv[i]); nHeap = integerValue(argv[i+1]); mnHeap = integerValue(argv[i+2]); |
︙ | ︙ | |||
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 | if( i>=argc-1 ) fatal_error("missing argument on %s\n", argv[i]); zKey = argv[++i]; }else if( strcmp(z,"lookaside")==0 ){ if( i>=argc-2 ) fatal_error("missing arguments on %s\n", argv[i]); nLook = integerValue(argv[i+1]); szLook = integerValue(argv[i+2]); i += 2; #if SQLITE_VERSION_NUMBER>=3006000 }else if( strcmp(z,"multithread")==0 ){ sqlite3_config(SQLITE_CONFIG_MULTITHREAD); }else if( strcmp(z,"nomemstat")==0 ){ sqlite3_config(SQLITE_CONFIG_MEMSTATUS, 0); #endif #if SQLITE_VERSION_NUMBER>=3007017 }else if( strcmp(z, "mmap")==0 ){ if( i>=argc-1 ) fatal_error("missing argument on %s\n", argv[i]); mmapSize = integerValue(argv[++i]); #endif }else if( strcmp(z,"nosync")==0 ){ noSync = 1; }else if( strcmp(z,"notnull")==0 ){ g.zNN = "NOT NULL"; }else if( strcmp(z,"pagesize")==0 ){ if( i>=argc-1 ) fatal_error("missing argument on %s\n", argv[i]); pageSize = integerValue(argv[++i]); }else if( strcmp(z,"pcache")==0 ){ if( i>=argc-2 ) fatal_error("missing arguments on %s\n", argv[i]); nPCache = integerValue(argv[i+1]); szPCache = integerValue(argv[i+2]); | > > > > > > > > > > > > > > > > > > | 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 2261 2262 2263 2264 2265 2266 2267 | if( i>=argc-1 ) fatal_error("missing argument on %s\n", argv[i]); zKey = argv[++i]; }else if( strcmp(z,"lookaside")==0 ){ if( i>=argc-2 ) fatal_error("missing arguments on %s\n", argv[i]); nLook = integerValue(argv[i+1]); szLook = integerValue(argv[i+2]); i += 2; }else if( strcmp(z,"memdb")==0 ){ memDb = 1; #if SQLITE_VERSION_NUMBER>=3006000 }else if( strcmp(z,"multithread")==0 ){ sqlite3_config(SQLITE_CONFIG_MULTITHREAD); }else if( strcmp(z,"nomemstat")==0 ){ sqlite3_config(SQLITE_CONFIG_MEMSTATUS, 0); #endif #if SQLITE_VERSION_NUMBER>=3007017 }else if( strcmp(z, "mmap")==0 ){ if( i>=argc-1 ) fatal_error("missing argument on %s\n", argv[i]); mmapSize = integerValue(argv[++i]); #endif }else if( strcmp(z,"nosync")==0 ){ noSync = 1; }else if( strcmp(z,"notnull")==0 ){ g.zNN = "NOT NULL"; }else if( strcmp(z,"output")==0 ){ #ifdef SPEEDTEST_OMIT_HASH fatal_error("The --output option is not supported with" " -DSPEEDTEST_OMIT_HASH\n"); #else if( i>=argc-1 ) fatal_error("missing argument on %s\n", argv[i]); i++; if( strcmp(argv[i],"-")==0 ){ g.hashFile = stdout; }else{ g.hashFile = fopen(argv[i], "wb"); if( g.hashFile==0 ){ fatal_error("cannot open \"%s\" for writing\n", argv[i]); } } #endif }else if( strcmp(z,"pagesize")==0 ){ if( i>=argc-1 ) fatal_error("missing argument on %s\n", argv[i]); pageSize = integerValue(argv[++i]); }else if( strcmp(z,"pcache")==0 ){ if( i>=argc-2 ) fatal_error("missing arguments on %s\n", argv[i]); nPCache = integerValue(argv[i+1]); szPCache = integerValue(argv[i+2]); |
︙ | ︙ | |||
2093 2094 2095 2096 2097 2098 2099 2100 | nThread = integerValue(argv[++i]); }else if( strcmp(z,"utf16le")==0 ){ zEncoding = "utf16le"; }else if( strcmp(z,"utf16be")==0 ){ zEncoding = "utf16be"; }else if( strcmp(z,"verify")==0 ){ g.bVerify = 1; }else if( strcmp(z,"without-rowid")==0 ){ | > > > > > > > > > > > | > > > > > > > > > | 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 | nThread = integerValue(argv[++i]); }else if( strcmp(z,"utf16le")==0 ){ zEncoding = "utf16le"; }else if( strcmp(z,"utf16be")==0 ){ zEncoding = "utf16be"; }else if( strcmp(z,"verify")==0 ){ g.bVerify = 1; #ifndef SPEEDTEST_OMIT_HASH HashInit(); #endif }else if( strcmp(z,"reserve")==0 ){ if( i>=argc-1 ) fatal_error("missing argument on %s\n", argv[i]); g.nReserve = atoi(argv[++i]); }else if( strcmp(z,"without-rowid")==0 ){ if( strstr(g.zWR,"WITHOUT")!=0 ){ /* no-op */ }else if( strstr(g.zWR,"STRICT")!=0 ){ g.zWR = "WITHOUT ROWID,STRICT"; }else{ g.zWR = "WITHOUT ROWID"; } g.zPK = "PRIMARY KEY"; }else if( strcmp(z,"strict")==0 ){ if( strstr(g.zWR,"STRICT")!=0 ){ /* no-op */ }else if( strstr(g.zWR,"WITHOUT")!=0 ){ g.zWR = "WITHOUT ROWID,STRICT"; }else{ g.zWR = "STRICT"; } }else if( strcmp(z, "help")==0 || strcmp(z,"?")==0 ){ printf(zHelp, argv[0]); exit(0); }else{ fatal_error("unknown option: %s\nUse \"%s -?\" for help\n", argv[i], argv[0]); } |
︙ | ︙ | |||
2131 2132 2133 2134 2135 2136 2137 | rc = sqlite3_config(SQLITE_CONFIG_PAGECACHE, pPCache, szPCache, nPCache); if( rc ) fatal_error("pcache configuration failed: %d\n", rc); } if( nLook>=0 ){ sqlite3_config(SQLITE_CONFIG_LOOKASIDE, 0, 0); } #endif | > | | | > > > > > > | 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 2400 2401 2402 2403 | rc = sqlite3_config(SQLITE_CONFIG_PAGECACHE, pPCache, szPCache, nPCache); if( rc ) fatal_error("pcache configuration failed: %d\n", rc); } if( nLook>=0 ){ sqlite3_config(SQLITE_CONFIG_LOOKASIDE, 0, 0); } #endif sqlite3_initialize(); /* Open the database and the input file */ if( sqlite3_open(memDb ? ":memory:" : zDbName, &g.db) ){ fatal_error("Cannot open database file: %s\n", zDbName); } #if SQLITE_VERSION_NUMBER>=3006001 if( nLook>0 && szLook>0 ){ pLook = malloc( nLook*szLook ); rc = sqlite3_db_config(g.db, SQLITE_DBCONFIG_LOOKASIDE,pLook,szLook,nLook); if( rc ) fatal_error("lookaside configuration failed: %d\n", rc); } #endif if( g.nReserve>0 ){ sqlite3_file_control(g.db, 0, SQLITE_FCNTL_RESERVE_BYTES, &g.nReserve); } /* Set database connection options */ sqlite3_create_function(g.db, "random", 0, SQLITE_UTF8, 0, randomFunc, 0, 0); #ifndef SQLITE_OMIT_DEPRECATED if( doTrace ) sqlite3_trace(g.db, traceCallback, 0); #endif if( memDb>0 ){ speedtest1_exec("PRAGMA temp_store=memory"); } if( mmapSize>0 ){ speedtest1_exec("PRAGMA mmap_size=%d", mmapSize); } speedtest1_exec("PRAGMA threads=%d", nThread); if( zKey ){ speedtest1_exec("PRAGMA key('%s')", zKey); } |
︙ | ︙ | |||
2179 2180 2181 2182 2183 2184 2185 | speedtest1_exec("PRAGMA locking_mode=EXCLUSIVE"); } if( zJMode ){ speedtest1_exec("PRAGMA journal_mode=%s", zJMode); } if( g.bExplain ) printf(".explain\n.echo on\n"); | > > > > > > > > > > > > | | | | | | | | | | | | | | | | | | | > > | > > > > > > > > > > > | > > > > > > > > > > > > > | 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 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 | speedtest1_exec("PRAGMA locking_mode=EXCLUSIVE"); } if( zJMode ){ speedtest1_exec("PRAGMA journal_mode=%s", zJMode); } if( g.bExplain ) printf(".explain\n.echo on\n"); do{ char *zThisTest = zTSet; char *zComma = strchr(zThisTest,','); if( zComma ){ *zComma = 0; zTSet = zComma+1; }else{ zTSet = ""; } if( g.iTotal>0 || zComma!=0 ){ printf(" Begin testset \"%s\"\n", zThisTest); } if( strcmp(zThisTest,"main")==0 ){ testset_main(); }else if( strcmp(zThisTest,"debug1")==0 ){ testset_debug1(); }else if( strcmp(zThisTest,"orm")==0 ){ testset_orm(); }else if( strcmp(zThisTest,"cte")==0 ){ testset_cte(); }else if( strcmp(zThisTest,"fp")==0 ){ testset_fp(); }else if( strcmp(zThisTest,"trigger")==0 ){ testset_trigger(); }else if( strcmp(zThisTest,"rtree")==0 ){ #ifdef SQLITE_ENABLE_RTREE testset_rtree(6, 147); #else fatal_error("compile with -DSQLITE_ENABLE_RTREE to enable " "the R-Tree tests\n"); #endif }else{ fatal_error("unknown testset: \"%s\"\n" "Choices: cte debug1 fp main orm rtree trigger\n", zThisTest); } if( zTSet[0] ){ char *zSql, *zObj; speedtest1_begin_test(999, "Reset the database"); while( 1 ){ zObj = speedtest1_once( "SELECT name FROM main.sqlite_master" " WHERE sql LIKE 'CREATE %%TABLE%%'"); if( zObj==0 ) break; zSql = sqlite3_mprintf("DROP TABLE main.\"%w\"", zObj); speedtest1_exec(zSql); sqlite3_free(zSql); sqlite3_free(zObj); } while( 1 ){ zObj = speedtest1_once( "SELECT name FROM temp.sqlite_master" " WHERE sql LIKE 'CREATE %%TABLE%%'"); if( zObj==0 ) break; zSql = sqlite3_mprintf("DROP TABLE main.\"%w\"", zObj); speedtest1_exec(zSql); sqlite3_free(zSql); sqlite3_free(zObj); } speedtest1_end_test(); } }while( zTSet[0] ); speedtest1_final(); if( showStats ){ sqlite3_exec(g.db, "PRAGMA compile_options", xCompileOptions, 0, 0); } /* Database connection statistics printed after both prepared statements |
︙ | ︙ |
Changes to test/sqldiff1.test.
︙ | ︙ | |||
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 | db backup test2.db db eval { ATTACH 'test2.db' AS x2; DELETE FROM x2.t1 WHERE a=49; DELETE FROM x2.t2 WHERE a=48; INSERT INTO x2.t1(a,b) VALUES(1234,'hello'); INSERT INTO x2.t2(a,b) VALUES(50.5,'xyzzy'); CREATE TABLE x2.t3(a,b,c); INSERT INTO x2.t3 VALUES(111,222,333); CREATE TABLE main.t4(x,y,z); INSERT INTO t4 SELECT * FROM t3; } set line "exec $PROG test.db test2.db" unset -nocomplain ::MSG catch {eval $line} ::MSG } {0} do_test sqldiff-1.1 { set ::MSG } {DELETE FROM t1 WHERE a=49; INSERT INTO t1(a,b) VALUES(1234,'hello'); DELETE FROM t2 WHERE a=48; INSERT INTO t2(a,b) VALUES(50.5,'xyzzy'); CREATE TABLE t3(a,b,c); INSERT INTO t3(rowid,a,b,c) VALUES(1,111,222,333); DROP TABLE t4;} finish_test | > > > > > > > > > | 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 | db backup test2.db db eval { ATTACH 'test2.db' AS x2; DELETE FROM x2.t1 WHERE a=49; DELETE FROM x2.t2 WHERE a=48; INSERT INTO x2.t1(a,b) VALUES(1234,'hello'); INSERT INTO x2.t2(a,b) VALUES(50.5,'xyzzy'); INSERT INTO x2.t2(a,b) VALUES(51.5,''); INSERT INTO x2.t2(a,b) VALUES(52.5,''||X'0d0a'); INSERT INTO x2.t2(a,b) VALUES(53.5,'one'||X'0a0d'); INSERT INTO x2.t2(a,b) VALUES(54.5,'one'||X'0a'||'two'); CREATE TABLE x2.t3(a,b,c); INSERT INTO x2.t3 VALUES(111,222,333); CREATE TABLE main.t4(x,y,z); INSERT INTO t4 SELECT * FROM t3; } set line "exec $PROG test.db test2.db" unset -nocomplain ::MSG catch {eval $line} ::MSG } {0} do_test sqldiff-1.1 { set ::MSG } {DELETE FROM t1 WHERE a=49; INSERT INTO t1(a,b) VALUES(1234,'hello'); DELETE FROM t2 WHERE a=48; INSERT INTO t2(a,b) VALUES(50.5,'xyzzy'); INSERT INTO t2(a,b) VALUES(51.5,''); INSERT INTO t2(a,b) VALUES(52.5,''||X'0d0a'); INSERT INTO t2(a,b) VALUES(53.5,'one'||X'0a0d'); INSERT INTO t2(a,b) VALUES(54.5,'one'||X'0a' ||'two'); CREATE TABLE t3(a,b,c); INSERT INTO t3(rowid,a,b,c) VALUES(1,111,222,333); DROP TABLE t4;} finish_test |
Changes to test/sqllimits1.test.
︙ | ︙ | |||
289 290 291 292 293 294 295 | do_test sqllimits1-5.9 { set ::str [string repeat A 65537] set ::rep [string repeat B 65537] catchsql { SELECT replace($::str, 'A', $::rep) } } {1 {string or blob too big}} do_test sqllimits1-5.10 { | > > > > > | > | | 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 | do_test sqllimits1-5.9 { set ::str [string repeat A 65537] set ::rep [string repeat B 65537] catchsql { SELECT replace($::str, 'A', $::rep) } } {1 {string or blob too big}} do_test sqllimits1-5.10 { # Prior to 3.37.0 strftime() allocated a large static buffer into # which to format its output. Using that strategy, 2100 repeats was # enough to exceed 100KiB and provoke the error. As of 3.37.0 strftime() # uses the StrAccum functions, so it requires 12100 to fail. # # set ::str [string repeat %J 2100] set ::str [string repeat %J 12100] catchsql { SELECT length(strftime($::str, '2003-10-31')) } } {1 {string or blob too big}} do_test sqllimits1-5.11 { set ::str1 [string repeat A [expr {$SQLITE_LIMIT_LENGTH - 10}]] set ::str2 [string repeat B [expr {$SQLITE_LIMIT_LENGTH - 10}]] catchsql { SELECT $::str1 || $::str2 } } {1 {string or blob too big}} |
︙ | ︙ | |||
368 369 370 371 372 373 374 | } } {1 {string or blob too big}} db eval {DROP TABLE t4} sqlite3_limit db SQLITE_LIMIT_SQL_LENGTH 0x7fffffff set strvalue [string repeat A $::SQLITE_LIMIT_LENGTH] do_test sqllimits1-5.16 { | | | | | 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 | } } {1 {string or blob too big}} db eval {DROP TABLE t4} sqlite3_limit db SQLITE_LIMIT_SQL_LENGTH 0x7fffffff set strvalue [string repeat A $::SQLITE_LIMIT_LENGTH] do_test sqllimits1-5.16 { catchsql "SELECT '$strvalue' AS x" } [list 0 $strvalue] do_test sqllimits1-5.17.1 { catchsql "SELECT 'A$strvalue'" } [list 1 {string or blob too big}] do_test sqllimits1-5.17.2 { sqlite3_limit db SQLITE_LIMIT_LENGTH 0x7fffffff catchsql {SELECT 'A' || $::strvalue} } [list 0 A$strvalue] do_test sqllimits1-5.17.3 { sqlite3_limit db SQLITE_LIMIT_LENGTH $SQLITE_LIMIT_LENGTH catchsql {SELECT 'A' || $::strvalue} } [list 1 {string or blob too big}] set blobvalue [string repeat 41 $::SQLITE_LIMIT_LENGTH] do_test sqllimits1-5.18 { catchsql "SELECT x'$blobvalue' AS x" } [list 0 $strvalue] do_test sqllimits1-5.19 { catchsql "SELECT '41$blobvalue'" } [list 1 {string or blob too big}] unset blobvalue ifcapable datetime { set strvalue [string repeat D [expr {$SQLITE_LIMIT_LENGTH-11}]] do_test sqllimits1-5.20 { catchsql {SELECT strftime('%Y ' || $::strvalue, '2008-01-02')} } [list 0 [list "2008 $strvalue"]] do_test sqllimits1-5.21 { catchsql {SELECT strftime('%Y-%m-%d ' || $::strvalue, '2008-01-02')} } {1 {string or blob too big}} } |
︙ | ︙ | |||
859 860 861 862 863 864 865 | } } {1 {LIKE or GLOB pattern too complex}} #-------------------------------------------------------------------- # This test case doesn't really belong with the other limits tests. # It is in this file because it is taxing to run, like the limits tests. # | > > > > > | | | | | | | | < > | > > > > > > > > > > | 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 | } } {1 {LIKE or GLOB pattern too complex}} #-------------------------------------------------------------------- # This test case doesn't really belong with the other limits tests. # It is in this file because it is taxing to run, like the limits tests. # # Update for 3.37.0: strftime() used to allocate a large static buffer # into which it would write its result. With that implementation, the # following would trigger an SQLITE_TOOBIG error. But strftime() now # uses the StrAccum functions, causing this test to fail. # #do_test sqllimits1-16.1 { # set ::N [expr int(([expr pow(2,32)]/50) + 1)] # expr (($::N*50) & 0xffffffff)<55 #} {1} #do_test sqllimits1-16.2 { # set ::format "[string repeat A 60][string repeat "%J" $::N]" # catchsql { # SELECT strftime($::format, 1); # } #} {1 {string or blob too big}} do_catchsql_test sqllimits1.17.0 { SELECT *,*,*,*,*,*,*,* FROM ( SELECT *,*,*,*,*,*,*,* FROM ( SELECT *,*,*,*,*,*,*,* FROM ( SELECT *,*,*,*,*,*,*,* FROM ( SELECT *,*,*,*,*,*,*,* FROM ( SELECT 1,2,3,4,5,6,7,8,9,10 ) )))) } "1 {too many columns in result set}" foreach {key value} [array get saved] { catch {set $key $value} } #------------------------------------------------------------------------- # At one point the following caused an assert() to fail. # sqlite3_limit db SQLITE_LIMIT_LENGTH 10000 set nm [string repeat x 10000] do_catchsql_test sqllimits1-17.1 " CREATE TABLE $nm (x PRIMARY KEY) " {1 {string or blob too big}} finish_test |
Added test/startup.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 | /* ** 2021-01-01 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** ** This file implements a program used to measure the start-up performance ** of SQLite. ** ** To use: ** ** ./startup init ** valgrind --tool=cachegrind ./startup run ** ** ** The "./startup init" command creates the test database file named ** "startup.db". The performance test is run by the "./startup run" ** command. That command does nothing but open the database file and ** parse the entire schema. */ #include <stdio.h> #include <unistd.h> #include <string.h> #include <stdlib.h> #include <ctype.h> #include "sqlite3.h" static const char zHelp[] = "Usage: %s COMMAND\n" "Commands:\n" " init Initialized the startup.db database file\n" " run Run the startup performance test\n" "Options:\n" " --dbname NAME Set the name of the test database file\n" " --heap SZ MIN Memory allocator uses SZ bytes & min allocation MIN\n" " --stats Show statistics at the end\n" /* TBD " --journal M Set the journal_mode to M\n" " --lookaside N SZ Configure lookaside for N slots of SZ bytes each\n" " --mmap SZ MMAP the first SZ bytes of the database file\n" " --multithread Set multithreaded mode\n" " --nomemstat Disable memory statistics\n" " --pagesize N Set the page size to N\n" " --pcache N SZ Configure N pages of pagecache each of size SZ bytes\n" " --serialized Set serialized threading mode\n" " --singlethread Set single-threaded mode - disables all mutexing\n" " --utf16be Set text encoding to UTF-16BE\n" " --utf16le Set text encoding to UTF-16LE\n" " --utf8 Set text encoding to UTF-8\n" */ ; static void usage(const char *argv0){ printf(zHelp, argv0); exit(1); } /* ** The test schema is derived from the Fossil repository for SQLite itself. ** The schema covers the repository, the local checkout database, and ** the global configuration database. */ static const char zTestSchema[] = "CREATE TABLE repo_blob(\n" " rid INTEGER PRIMARY KEY,\n" " rcvid INTEGER,\n" " size INTEGER,\n" " uuid TEXT UNIQUE NOT NULL,\n" " content BLOB,\n" " CHECK( length(uuid)>=40 AND rid>0 )\n" ");\n" "CREATE TABLE repo_delta(\n" " rid INTEGER PRIMARY KEY,\n" " srcid INTEGER NOT NULL REFERENCES blob\n" ");\n" "CREATE TABLE repo_rcvfrom(\n" " rcvid INTEGER PRIMARY KEY,\n" " uid INTEGER REFERENCES user,\n" " mtime DATETIME,\n" " nonce TEXT UNIQUE,\n" " ipaddr TEXT\n" ");\n" "CREATE TABLE repo_private(rid INTEGER PRIMARY KEY);\n" "CREATE TABLE repo_accesslog(\n" " uname TEXT,\n" " ipaddr TEXT,\n" " success BOOLEAN,\n" " mtime TIMESTAMP);\n" "CREATE TABLE repo_user(\n" " uid INTEGER PRIMARY KEY,\n" " login TEXT UNIQUE,\n" " pw TEXT,\n" " cap TEXT,\n" " cookie TEXT,\n" " ipaddr TEXT,\n" " cexpire DATETIME,\n" " info TEXT,\n" " mtime DATE,\n" " photo BLOB\n" ");\n" "CREATE TABLE repo_reportfmt(\n" " rn INTEGER PRIMARY KEY,\n" " owner TEXT,\n" " title TEXT UNIQUE,\n" " mtime INTEGER,\n" " cols TEXT,\n" " sqlcode TEXT\n" ");\n" "CREATE TABLE repo_sqlite_stat2(tbl,idx,sampleno,sample);\n" "CREATE TABLE repo_sqlite_stat1(tbl,idx,stat);\n" "CREATE TABLE repo_sqlite_stat3(tbl,idx,neq,nlt,ndlt,sample);\n" "CREATE TABLE repo_config(\n" " name TEXT PRIMARY KEY NOT NULL,\n" " value CLOB, mtime INTEGER,\n" " CHECK( typeof(name)='text' AND length(name)>=1 )\n" ") WITHOUT ROWID;\n" "CREATE TABLE repo_shun(uuid PRIMARY KEY,\n" " mtime INTEGER,\n" " scom TEXT) WITHOUT ROWID;\n" "CREATE TABLE repo_concealed(\n" " hash TEXT PRIMARY KEY,\n" " content TEXT\n" ", mtime INTEGER) WITHOUT ROWID;\n" "CREATE TABLE repo_admin_log(\n" " id INTEGER PRIMARY KEY,\n" " time INTEGER, -- Seconds since 1970\n" " page TEXT, -- path of page\n" " who TEXT, -- User who made the change\n" " what TEXT -- What changed\n" ");\n" "CREATE TABLE repo_unversioned(\n" " name TEXT PRIMARY KEY,\n" " rcvid INTEGER,\n" " mtime DATETIME,\n" " hash TEXT,\n" " sz INTEGER,\n" " encoding INT,\n" " content BLOB\n" ") WITHOUT ROWID;\n" "CREATE TABLE repo_subscriber(\n" " subscriberId INTEGER PRIMARY KEY,\n" " subscriberCode BLOB DEFAULT (randomblob(32)) UNIQUE,\n" " semail TEXT UNIQUE COLLATE nocase,\n" " suname TEXT,\n" " sverified BOOLEAN DEFAULT true,\n" " sdonotcall BOOLEAN,\n" " sdigest BOOLEAN,\n" " ssub TEXT,\n" " sctime INTDATE,\n" " mtime INTDATE,\n" " smip TEXT\n" ");\n" "CREATE TABLE repo_pending_alert(\n" " eventid TEXT PRIMARY KEY,\n" " sentSep BOOLEAN DEFAULT false,\n" " sentDigest BOOLEAN DEFAULT false\n" ", sentMod BOOLEAN DEFAULT false) WITHOUT ROWID;\n" "CREATE INDEX repo_delta_i1 ON repo_delta(srcid);\n" "CREATE INDEX repo_blob_rcvid ON repo_blob(rcvid);\n" "CREATE INDEX repo_subscriberUname\n" " ON repo_subscriber(suname) WHERE suname IS NOT NULL;\n" "CREATE VIEW repo_artifact(rid,rcvid,size,atype,srcid,hash,content) AS\n" " SELECT blob.rid,rcvid,size,1,srcid,uuid,content\n" " FROM repo_blob LEFT JOIN repo_delta ON (blob.rid=delta.rid);\n" "CREATE TABLE repo_filename(\n" " fnid INTEGER PRIMARY KEY,\n" " name TEXT UNIQUE\n" ");\n" "CREATE TABLE repo_mlink(\n" " mid INTEGER,\n" " fid INTEGER,\n" " pmid INTEGER,\n" " pid INTEGER,\n" " fnid INTEGER REFERENCES filename,\n" " pfnid INTEGER,\n" " mperm INTEGER,\n" " isaux BOOLEAN DEFAULT 0\n" ");\n" "CREATE INDEX repo_mlink_i1 ON repo_mlink(mid);\n" "CREATE INDEX repo_mlink_i2 ON repo_mlink(fnid);\n" "CREATE INDEX repo_mlink_i3 ON repo_mlink(fid);\n" "CREATE INDEX repo_mlink_i4 ON repo_mlink(pid);\n" "CREATE TABLE repo_plink(\n" " pid INTEGER REFERENCES blob,\n" " cid INTEGER REFERENCES blob,\n" " isprim BOOLEAN,\n" " mtime DATETIME,\n" " baseid INTEGER REFERENCES blob,\n" " UNIQUE(pid, cid)\n" ");\n" "CREATE INDEX repo_plink_i2 ON repo_plink(cid,pid);\n" "CREATE TABLE repo_leaf(rid INTEGER PRIMARY KEY);\n" "CREATE TABLE repo_event(\n" " type TEXT,\n" " mtime DATETIME,\n" " objid INTEGER PRIMARY KEY,\n" " tagid INTEGER,\n" " uid INTEGER REFERENCES user,\n" " bgcolor TEXT,\n" " euser TEXT,\n" " user TEXT,\n" " ecomment TEXT,\n" " comment TEXT,\n" " brief TEXT,\n" " omtime DATETIME\n" ");\n" "CREATE INDEX repo_event_i1 ON repo_event(mtime);\n" "CREATE TABLE repo_phantom(\n" " rid INTEGER PRIMARY KEY\n" ");\n" "CREATE TABLE repo_orphan(\n" " rid INTEGER PRIMARY KEY,\n" " baseline INTEGER\n" ");\n" "CREATE INDEX repo_orphan_baseline ON repo_orphan(baseline);\n" "CREATE TABLE repo_unclustered(\n" " rid INTEGER PRIMARY KEY\n" ");\n" "CREATE TABLE repo_unsent(\n" " rid INTEGER PRIMARY KEY\n" ");\n" "CREATE TABLE repo_tag(\n" " tagid INTEGER PRIMARY KEY,\n" " tagname TEXT UNIQUE\n" ");\n" "CREATE TABLE repo_tagxref(\n" " tagid INTEGER REFERENCES tag,\n" " tagtype INTEGER,\n" " srcid INTEGER REFERENCES blob,\n" " origid INTEGER REFERENCES blob,\n" " value TEXT,\n" " mtime TIMESTAMP,\n" " rid INTEGER REFERENCE blob,\n" " UNIQUE(rid, tagid)\n" ");\n" "CREATE INDEX repo_tagxref_i1 ON repo_tagxref(tagid, mtime);\n" "CREATE TABLE repo_backlink(\n" " target TEXT,\n" " srctype INT,\n" " srcid INT,\n" " mtime TIMESTAMP,\n" " UNIQUE(target, srctype, srcid)\n" ");\n" "CREATE INDEX repo_backlink_src ON repo_backlink(srcid, srctype);\n" "CREATE TABLE repo_attachment(\n" " attachid INTEGER PRIMARY KEY,\n" " isLatest BOOLEAN DEFAULT 0,\n" " mtime TIMESTAMP,\n" " src TEXT,\n" " target TEXT,\n" " filename TEXT,\n" " comment TEXT,\n" " user TEXT\n" ");\n" "CREATE INDEX repo_attachment_idx1\n" " ON repo_attachment(target, filename, mtime);\n" "CREATE INDEX repo_attachment_idx2 ON repo_attachment(src);\n" "CREATE TABLE repo_cherrypick(\n" " parentid INT,\n" " childid INT,\n" " isExclude BOOLEAN DEFAULT false,\n" " PRIMARY KEY(parentid, childid)\n" ") WITHOUT ROWID;\n" "CREATE INDEX repo_cherrypick_cid ON repo_cherrypick(childid);\n" "CREATE TABLE repo_ticket(\n" " -- Do not change any column that begins with tkt_\n" " tkt_id INTEGER PRIMARY KEY,\n" " tkt_uuid TEXT UNIQUE,\n" " tkt_mtime DATE,\n" " tkt_ctime DATE,\n" " -- Add as many fields as required below this line\n" " type TEXT,\n" " status TEXT,\n" " subsystem TEXT,\n" " priority TEXT,\n" " severity TEXT,\n" " foundin TEXT,\n" " private_contact TEXT,\n" " resolution TEXT,\n" " title TEXT,\n" " comment TEXT\n" ");\n" "CREATE TABLE repo_ticketchng(\n" " -- Do not change any column that begins with tkt_\n" " tkt_id INTEGER REFERENCES ticket,\n" " tkt_rid INTEGER REFERENCES blob,\n" " tkt_mtime DATE,\n" " -- Add as many fields as required below this line\n" " login TEXT,\n" " username TEXT,\n" " mimetype TEXT,\n" " icomment TEXT\n" ");\n" "CREATE INDEX repo_ticketchng_idx1 ON repo_ticketchng(tkt_id, tkt_mtime);\n" "CREATE TRIGGER repo_alert_trigger1\n" "AFTER INSERT ON repo_event BEGIN\n" " INSERT INTO repo_pending_alert(eventid)\n" " SELECT printf('%.1c%d',new.type,new.objid) WHERE true\n" " ON CONFLICT(eventId) DO NOTHING;\n" "END;\n" "CREATE TABLE repo_vcache(\n" " vid INTEGER, -- check-in ID\n" " fname TEXT, -- filename\n" " rid INTEGER, -- artifact ID\n" " PRIMARY KEY(vid,fname)\n" ") WITHOUT ROWID;\n" "CREATE TABLE localdb_vvar(\n" " name TEXT PRIMARY KEY NOT NULL,\n" " value CLOB,\n" " CHECK( typeof(name)='text' AND length(name)>=1 )\n" ");\n" "CREATE TABLE localdb_vfile(\n" " id INTEGER PRIMARY KEY,\n" " vid INTEGER REFERENCES blob,\n" " chnged INT DEFAULT 0,\n" " deleted BOOLEAN DEFAULT 0,\n" " isexe BOOLEAN,\n" " islink BOOLEAN,\n" " rid INTEGER,\n" " mrid INTEGER,\n" " mtime INTEGER,\n" " pathname TEXT,\n" " origname TEXT, mhash,\n" " UNIQUE(pathname,vid)\n" ");\n" "CREATE TABLE localdb_sqlite_stat1(tbl,idx,stat);\n" "CREATE TABLE localdb_vcache(\n" " vid INTEGER, -- check-in ID\n" " fname TEXT, -- filename\n" " rid INTEGER, -- artifact ID\n" " PRIMARY KEY(vid,fname)\n" ") WITHOUT ROWID;\n" "CREATE TABLE localdb_stash(\n" " stashid INTEGER PRIMARY KEY,\n" " vid INTEGER,\n" " hash TEXT,\n" " comment TEXT,\n" " ctime TIMESTAMP\n" ");\n" "CREATE TABLE localdb_stashfile(\n" " stashid INTEGER REFERENCES stash,\n" " isAdded BOOLEAN,\n" " isRemoved BOOLEAN,\n" " isExec BOOLEAN,\n" " isLink BOOLEAN,\n" " rid INTEGER,\n" " hash TEXT,\n" " origname TEXT,\n" " newname TEXT,\n" " delta BLOB,\n" " PRIMARY KEY(newname, stashid)\n" ");\n" "CREATE TABLE localdb_vmerge(\n" " id INTEGER REFERENCES vfile,\n" " merge INTEGER,\n" " mhash TEXT\n" ");\n" "CREATE UNIQUE INDEX localdb_vmergex1 ON localdb_vmerge(id,mhash);\n" "CREATE TRIGGER localdb_vmerge_ck1 AFTER INSERT ON localdb_vmerge\n" "WHEN new.mhash IS NULL BEGIN\n" " SELECT raise(FAIL,\n" " 'trying to update a newer checkout with an older version of Fossil');\n" "END;\n" "CREATE TABLE configdb_global_config(\n" " name TEXT PRIMARY KEY,\n" " value TEXT\n" ");\n" "CREATE TABLE configdb_sqlite_stat1(tbl,idx,stat);\n" ; #ifdef __linux__ #include <sys/types.h> #include <unistd.h> /* ** Attempt to display I/O stats on Linux using /proc/PID/io */ static void displayLinuxIoStats(FILE *out){ FILE *in; char z[200]; sqlite3_snprintf(sizeof(z), z, "/proc/%d/io", getpid()); in = fopen(z, "rb"); if( in==0 ) return; while( fgets(z, sizeof(z), in)!=0 ){ static const struct { const char *zPattern; const char *zDesc; } aTrans[] = { { "rchar: ", "Bytes received by read():" }, { "wchar: ", "Bytes sent to write():" }, { "syscr: ", "Read() system calls:" }, { "syscw: ", "Write() system calls:" }, { "read_bytes: ", "Bytes rcvd from storage:" }, { "write_bytes: ", "Bytes sent to storage:" }, { "cancelled_write_bytes: ", "Cancelled write bytes:" }, }; int i; for(i=0; i<sizeof(aTrans)/sizeof(aTrans[0]); i++){ int n = (int)strlen(aTrans[i].zPattern); if( strncmp(aTrans[i].zPattern, z, n)==0 ){ fprintf(out, "-- %-28s %s", aTrans[i].zDesc, &z[n]); break; } } } fclose(in); } #endif /* ** Return the value of a hexadecimal digit. Return -1 if the input ** is not a hex digit. */ static int hexDigitValue(char c){ if( c>='0' && c<='9' ) return c - '0'; if( c>='a' && c<='f' ) return c - 'a' + 10; if( c>='A' && c<='F' ) return c - 'A' + 10; return -1; } /* ** Interpret zArg as an integer value, possibly with suffixes. */ static int integerValue(const char *zArg){ sqlite3_int64 v = 0; static const struct { char *zSuffix; int iMult; } aMult[] = { { "KiB", 1024 }, { "MiB", 1024*1024 }, { "GiB", 1024*1024*1024 }, { "KB", 1000 }, { "MB", 1000000 }, { "GB", 1000000000 }, { "K", 1000 }, { "M", 1000000 }, { "G", 1000000000 }, }; int i; int isNeg = 0; if( zArg[0]=='-' ){ isNeg = 1; zArg++; }else if( zArg[0]=='+' ){ zArg++; } if( zArg[0]=='0' && zArg[1]=='x' ){ int x; zArg += 2; while( (x = hexDigitValue(zArg[0]))>=0 ){ v = (v<<4) + x; zArg++; } }else{ while( isdigit(zArg[0]) ){ v = v*10 + zArg[0] - '0'; zArg++; } } for(i=0; i<sizeof(aMult)/sizeof(aMult[0]); i++){ if( sqlite3_stricmp(aMult[i].zSuffix, zArg)==0 ){ v *= aMult[i].iMult; break; } } if( v>0x7fffffff ){ printf("ERROR: parameter too large - max 2147483648\n"); exit(1); } return (int)(isNeg? -v : v); } int main(int argc, char **argv){ const char *zCmd = 0; int i; int bAutovac = 0; int showStats = 0; const char *zDbName = "./startup.db"; int nHeap = 0; int mnHeap = 0; for(i=1; i<argc; i++){ const char *z = argv[i]; if( z[0]!='-' ){ if( zCmd ){ usage(argv[0]); } zCmd = z; continue; } if( z[1]=='-' ) z++; if( strcmp(z, "-autovacuum")==0 ){ bAutovac = 1; }else if( strcmp(z, "-dbname")==0 ){ if( i==argc-1 ){ printf("ERROR: missing argument on \"%s\"\n", argv[0]); exit(1); } zDbName = argv[++i]; }else if( strcmp(z,"-heap")==0 ){ if( i>=argc-2 ){ printf("ERROR: missing arguments on %s\n", argv[i]); exit(1); } nHeap = integerValue(argv[i+1]); mnHeap = integerValue(argv[i+2]); i += 2; }else if( strcmp(z,"-stats")==0 ){ showStats = 1; }else { printf("ERROR: unknown option \"%s\"\n", argv[i]); usage(argv[0]); } } if( zCmd==0 ){ printf("ERROR: no COMMAND specified\n"); usage(argv[0]); } if( strcmp(zCmd, "run")==0 ){ sqlite3 *db; int rc; char *zErr = 0; void *pHeap = 0; if( nHeap>0 ){ pHeap = malloc( nHeap ); if( pHeap==0 ){ printf("ERROR: cannot allocate %d-byte heap\n", nHeap); exit(1); } rc = sqlite3_config(SQLITE_CONFIG_HEAP, pHeap, nHeap, mnHeap); if( rc ){ printf("ERROR: heap configuration failed: %d\n", rc); exit(1); } } rc = sqlite3_open(zDbName, &db); if( rc ){ printf("SQLite error: %s\n", sqlite3_errmsg(db)); }else{ sqlite3_exec(db, "PRAGMA synchronous", 0, 0, &zErr); } if( zErr ){ printf("ERROR: %s\n", zErr); sqlite3_free(zErr); } if( showStats ){ int iCur, iHi; sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_USED, &iCur, &iHi, 0); printf("-- Lookaside Slots Used: %d (max %d)\n", iCur,iHi); sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_HIT, &iCur, &iHi, 0); printf("-- Successful lookasides: %d\n", iHi); sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE, &iCur,&iHi,0); printf("-- Lookaside size faults: %d\n", iHi); sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL, &iCur,&iHi,0); printf("-- Lookaside OOM faults: %d\n", iHi); sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_USED, &iCur, &iHi, 0); printf("-- Pager Heap Usage: %d bytes\n", iCur); sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_HIT, &iCur, &iHi, 1); printf("-- Page cache hits: %d\n", iCur); sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_MISS, &iCur, &iHi, 1); printf("-- Page cache misses: %d\n", iCur); sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_WRITE, &iCur, &iHi, 1); printf("-- Page cache writes: %d\n", iCur); sqlite3_db_status(db, SQLITE_DBSTATUS_SCHEMA_USED, &iCur, &iHi, 0); printf("-- Schema Heap Usage: %d bytes\n", iCur); sqlite3_db_status(db, SQLITE_DBSTATUS_STMT_USED, &iCur, &iHi, 0); printf("-- Statement Heap Usage: %d bytes\n", iCur); } sqlite3_close(db); free(pHeap); /* Global memory usage statistics printed after the database connection ** has closed. Memory usage should be zero at this point. */ if( showStats ){ int iCur, iHi; sqlite3_status(SQLITE_STATUS_MEMORY_USED, &iCur, &iHi, 0); printf("-- Memory Used (bytes): %d (max %d)\n", iCur,iHi); sqlite3_status(SQLITE_STATUS_MALLOC_COUNT, &iCur, &iHi, 0); printf("-- Outstanding Allocations: %d (max %d)\n", iCur,iHi); sqlite3_status(SQLITE_STATUS_PAGECACHE_OVERFLOW, &iCur, &iHi, 0); printf("-- Pcache Overflow Bytes: %d (max %d)\n", iCur,iHi); sqlite3_status(SQLITE_STATUS_MALLOC_SIZE, &iCur, &iHi, 0); printf("-- Largest Allocation: %d bytes\n",iHi); sqlite3_status(SQLITE_STATUS_PAGECACHE_SIZE, &iCur, &iHi, 0); printf("-- Largest Pcache Allocation: %d bytes\n",iHi); #ifdef __linux__ displayLinuxIoStats(stdout); #endif } return 0; } if( strcmp(zCmd, "init")==0 ){ sqlite3 *db; char *zAux; char *zErr = 0; int rc; unlink(zDbName); zAux = sqlite3_mprintf("%s-journal", zDbName); unlink(zAux); sqlite3_free(zAux); zAux = sqlite3_mprintf("%s-wal", zDbName); unlink(zAux); sqlite3_free(zAux); rc = sqlite3_open(zDbName, &db); if( rc ){ printf("SQLite error: %s\n", sqlite3_errmsg(db)); }else{ sqlite3_exec(db, "BEGIN", 0, 0, 0); sqlite3_exec(db, zTestSchema, 0, 0, &zErr); sqlite3_exec(db, "COMMIT", 0, 0, 0); } if( zErr ){ printf("ERROR: %s\n", zErr); sqlite3_free(zErr); } sqlite3_close(db); return 0; } } |
Changes to test/stat.test.
︙ | ︙ | |||
32 33 34 35 36 37 38 | register_dbstat_vtab db do_execsql_test stat-0.0 { PRAGMA table_info(dbstat); } {/0 name TEXT .* 1 path TEXT .* 9 pgsize INTEGER/} # Attempts to drop an eponymous virtual table are a no-op. | | > > | 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | register_dbstat_vtab db do_execsql_test stat-0.0 { PRAGMA table_info(dbstat); } {/0 name TEXT .* 1 path TEXT .* 9 pgsize INTEGER/} # Attempts to drop an eponymous virtual table are a no-op. do_catchsql_test stat-0.1a { DROP TABLE dbstat; } {1 {table dbstat may not be dropped}} do_execsql_test stat-0.1b { PRAGMA table_info=dbstat; } {/0 name TEXT .* 1 path TEXT .* 9 pgsize INTEGER/} db close forcedelete test.db sqlite3 db test.db db func a_string a_string |
︙ | ︙ | |||
55 56 57 58 59 60 61 | if {[wal_is_capable]} { do_execsql_test stat-0.1 { PRAGMA journal_mode = WAL; PRAGMA journal_mode = delete; SELECT name, path, pageno, pagetype, ncell, payload, unused, mx_payload FROM stat; | | | 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | if {[wal_is_capable]} { do_execsql_test stat-0.1 { PRAGMA journal_mode = WAL; PRAGMA journal_mode = delete; SELECT name, path, pageno, pagetype, ncell, payload, unused, mx_payload FROM stat; } {wal delete sqlite_schema / 1 leaf 0 0 916 0} } do_test stat-1.0 { execsql { CREATE TABLE t1(a, b); CREATE INDEX i1 ON t1(b); INSERT INTO t1(rowid, a, b) VALUES(2, 2, 3); |
︙ | ︙ | |||
81 82 83 84 85 86 87 | SELECT name, path, pageno, pagetype, ncell, payload, unused, mx_payload FROM stat WHERE name = 'i1'; } } {i1 / 3 leaf 2 10 1000 5} do_test stat-1.3 { execsql { SELECT name, path, pageno, pagetype, ncell, payload, unused, mx_payload | | | | | 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 | SELECT name, path, pageno, pagetype, ncell, payload, unused, mx_payload FROM stat WHERE name = 'i1'; } } {i1 / 3 leaf 2 10 1000 5} do_test stat-1.3 { execsql { SELECT name, path, pageno, pagetype, ncell, payload, unused, mx_payload FROM stat WHERE name = 'sqlite_schema'; } } {sqlite_schema / 1 leaf 2 77 831 40} do_test stat-1.4 { execsql { DROP TABLE t1; } } {} do_execsql_test stat-2.1 { CREATE TABLE t3(a PRIMARY KEY, b); INSERT INTO t3(rowid, a, b) VALUES(2, a_string(111), a_string(222)); INSERT INTO t3 SELECT a_string(110+rowid), a_string(221+rowid) FROM t3 ORDER BY rowid; INSERT INTO t3 SELECT a_string(110+rowid), a_string(221+rowid) FROM t3 ORDER BY rowid; INSERT INTO t3 SELECT a_string(110+rowid), a_string(221+rowid) FROM t3 ORDER BY rowid; INSERT INTO t3 SELECT a_string(110+rowid), a_string(221+rowid) FROM t3 ORDER BY rowid; INSERT INTO t3 SELECT a_string(110+rowid), a_string(221+rowid) FROM t3 ORDER BY rowid; SELECT name, path, pageno, pagetype, ncell, payload, unused, mx_payload FROM stat WHERE name != 'sqlite_schema' ORDER BY name; } [list \ sqlite_autoindex_t3_1 / 3 internal 3 368 623 125 \ sqlite_autoindex_t3_1 /000/ 8 leaf 8 946 46 123 \ sqlite_autoindex_t3_1 /001/ 9 leaf 8 988 2 131 \ sqlite_autoindex_t3_1 /002/ 15 leaf 7 857 137 132 \ sqlite_autoindex_t3_1 /003/ 20 leaf 6 739 257 129 \ t3 / 2 internal 15 0 907 0 \ |
︙ | ︙ | |||
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 | t3 /00a/ 17 leaf 2 698 308 350 \ t3 /00b/ 18 leaf 2 706 300 354 \ t3 /00c/ 19 leaf 2 714 292 358 \ t3 /00d/ 21 leaf 2 722 284 362 \ t3 /00e/ 22 leaf 2 730 276 366 \ t3 /00f/ 23 leaf 2 738 268 370 \ ] # With every index entry overflowing, make sure no pages are missed # (other than the locking page which is 64 in this test build.) # do_execsql_test stat-2.2 { UPDATE t3 SET a=a||hex(randomblob(700)); VACUUM; SELECT pageno FROM stat EXCEPT SELECT pageno-1 FROM stat; } {64 136} do_execsql_test stat-2.3 { DROP TABLE t3; VACUUM; } {} do_execsql_test stat-3.1 { CREATE TABLE t4(x); CREATE INDEX i4 ON t4(x); INSERT INTO t4(rowid, x) VALUES(2, a_string(7777)); SELECT name, path, pageno, pagetype, ncell, payload, unused, mx_payload | > > > > > > > > | > > > > > > > > > | 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 | t3 /00a/ 17 leaf 2 698 308 350 \ t3 /00b/ 18 leaf 2 706 300 354 \ t3 /00c/ 19 leaf 2 714 292 358 \ t3 /00d/ 21 leaf 2 722 284 362 \ t3 /00e/ 22 leaf 2 730 276 366 \ t3 /00f/ 23 leaf 2 738 268 370 \ ] do_execsql_test stat-2.1agg { SELECT * FROM dbstat WHERE aggregate=TRUE ORDER BY name; } [list \ sqlite_autoindex_t3_1 {} 5 {} 32 3898 1065 132 {} 5120 \ sqlite_schema {} 1 {} 2 84 824 49 {} 1024 \ t3 {} 17 {} 47 11188 5815 370 {} 17408 \ ] # With every index entry overflowing, make sure no pages are missed # (other than the locking page which is 64 in this test build.) # do_execsql_test stat-2.2 { UPDATE t3 SET a=a||hex(randomblob(700)); VACUUM; SELECT pageno FROM stat EXCEPT SELECT pageno-1 FROM stat; } {64 136} do_execsql_test stat-2.3 { DROP TABLE t3; VACUUM; } {} do_execsql_test stat-3.1 { CREATE TABLE t4(x); CREATE INDEX i4 ON t4(x); INSERT INTO t4(rowid, x) VALUES(2, a_string(7777)); SELECT name, path, pageno, pagetype, ncell, payload, unused, mx_payload FROM stat WHERE name != 'sqlite_schema' ORDER BY name; } [list \ i4 / 3 leaf 1 103 905 7782 \ i4 /000+000000 4 overflow 0 1020 0 0 \ i4 /000+000001 5 overflow 0 1020 0 0 \ i4 /000+000002 6 overflow 0 1020 0 0 \ i4 /000+000003 7 overflow 0 1020 0 0 \ i4 /000+000004 8 overflow 0 1020 0 0 \ i4 /000+000005 9 overflow 0 1020 0 0 \ i4 /000+000006 10 overflow 0 1020 0 0 \ i4 /000+000007 11 overflow 0 539 481 0 \ t4 / 2 leaf 1 640 367 7780 \ t4 /000+000000 12 overflow 0 1020 0 0 \ t4 /000+000001 13 overflow 0 1020 0 0 \ t4 /000+000002 14 overflow 0 1020 0 0 \ t4 /000+000003 15 overflow 0 1020 0 0 \ t4 /000+000004 16 overflow 0 1020 0 0 \ t4 /000+000005 17 overflow 0 1020 0 0 \ t4 /000+000006 18 overflow 0 1020 0 0 \ ] do_execsql_test stat-3.2 { SELECT *, '|' FROM dbstat WHERE aggregate=TRUE ORDER BY name; } [list \ i4 {} 9 {} 1 7782 1386 7782 {} 9216 | \ sqlite_schema {} 1 {} 2 74 834 40 {} 1024 | \ t4 {} 8 {} 1 7780 367 7780 {} 8192 | \ ] do_execsql_test stat-4.1 { CREATE TABLE t5(x); CREATE INDEX i5 ON t5(x); SELECT name, path, pageno, pagetype, ncell, payload, unused, mx_payload FROM stat WHERE name = 't5' OR name = 'i5'; } [list \ |
︙ | ︙ | |||
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 | SELECT name, path, pageno, pagetype, ncell, payload, unused, mx_payload FROM stat WHERE name = 't1'; } [list \ t1 / 2 leaf 2 993 5 1517 \ t1 /000+000000 3 overflow 0 1020 0 0 \ t1 /001+000000 4 overflow 0 1020 0 0 \ ] do_catchsql_test stat-6.1 { CREATE VIRTUAL TABLE temp.s2 USING dbstat(mainx); } {1 {no such database: mainx}} #------------------------------------------------------------------------- # Test that the argument passed to the dbstat constructor is dequoted # before it is matched against the names of attached databases. # forcedelete test.db2 do_execsql_test 7.1 { ATTACH 'test.db2' AS '123'; PRAGMA "123".auto_vacuum = OFF; CREATE TABLE "123".x1(a, b); INSERT INTO x1 VALUES(1, 2); } do_execsql_test 7.1.1 { SELECT * FROM dbstat('123'); } { | > > > > > > > > > > | | | | | | > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | SELECT name, path, pageno, pagetype, ncell, payload, unused, mx_payload FROM stat WHERE name = 't1'; } [list \ t1 / 2 leaf 2 993 5 1517 \ t1 /000+000000 3 overflow 0 1020 0 0 \ t1 /001+000000 4 overflow 0 1020 0 0 \ ] do_execsql_test stat-5.20 { SELECT name, quote(path), pageno, quote(pagetype), ncell, payload, unused, mx_payload, '|' FROM dbstat('main',1); } {sqlite_schema NULL 1 NULL 1 34 878 34 | tx NULL 1 NULL 0 0 1016 0 |} do_execsql_test stat-5.21 { SELECT name, quote(path), pageno, quote(pagetype), ncell, payload, unused, mx_payload, '|' FROM dbstat('aux1',1); } {sqlite_schema NULL 1 NULL 1 34 878 34 | t1 NULL 3 NULL 2 3033 5 1517 |} do_catchsql_test stat-6.1 { CREATE VIRTUAL TABLE temp.s2 USING dbstat(mainx); } {1 {no such database: mainx}} #------------------------------------------------------------------------- # Test that the argument passed to the dbstat constructor is dequoted # before it is matched against the names of attached databases. # forcedelete test.db2 do_execsql_test 7.1 { ATTACH 'test.db2' AS '123'; PRAGMA "123".auto_vacuum = OFF; CREATE TABLE "123".x1(a, b); INSERT INTO x1 VALUES(1, 2); } do_execsql_test 7.1.1 { SELECT * FROM dbstat('123'); } { sqlite_schema / 1 leaf 1 37 875 37 0 1024 x1 / 2 leaf 1 4 1008 4 1024 1024 } do_execsql_test 7.1.2 { SELECT * FROM dbstat(123); } { sqlite_schema / 1 leaf 1 37 875 37 0 1024 x1 / 2 leaf 1 4 1008 4 1024 1024 } do_execsql_test 7.1.3 { CREATE VIRTUAL TABLE x2 USING dbstat('123'); SELECT * FROM x2; } { sqlite_schema / 1 leaf 1 37 875 37 0 1024 x1 / 2 leaf 1 4 1008 4 1024 1024 } do_execsql_test 7.1.4 { CREATE VIRTUAL TABLE x3 USING dbstat(123); SELECT * FROM x3; } { sqlite_schema / 1 leaf 1 37 875 37 0 1024 x1 / 2 leaf 1 4 1008 4 1024 1024 } do_execsql_test 7.2 { DETACH 123; DROP TABLE x2; DROP TABLE x3; ATTACH 'test.db2' AS '123corp'; } do_execsql_test 7.2.1 { SELECT * FROM dbstat('123corp'); } { sqlite_schema / 1 leaf 1 37 875 37 0 1024 x1 / 2 leaf 1 4 1008 4 1024 1024 } do_catchsql_test 7.2.2 { SELECT * FROM dbstat(123corp); } {1 {unrecognized token: "123corp"}} do_execsql_test 7.2.3 { CREATE VIRTUAL TABLE x2 USING dbstat('123corp'); SELECT * FROM x2; } { sqlite_schema / 1 leaf 1 37 875 37 0 1024 x1 / 2 leaf 1 4 1008 4 1024 1024 } do_catchsql_test 7.2.4 { CREATE VIRTUAL TABLE x3 USING dbstat(123corp); SELECT * FROM x3; } {1 {unrecognized token: "123corp"}} do_execsql_test 8.1 { CREATE VIRTUAL TABLE st4 USING dbstat; } do_execsql_test 8.2 { SELECT * FROM st4 WHERE st4.aggregate = NULL; } do_execsql_test 8.3 { SELECT aggregate=1 FROM st4 WHERE aggregate = 5 } do_execsql_test 8.4 { SELECT * FROM st4 WHERE name = NULL; } {} do_execsql_test 8.5 { SELECT * FROM st4 WHERE schema = NULL; } {} #------------------------------------------------------------------------- reset_db breakpoint do_catchsql_test 9.1 { CREATE TABLE dbstat(x, y); DROP TABLE nosuchdb.dbstat; } {/1 {(no such table: nosuchdb.dbstat|table dbstat may not be dropped)}/} finish_test |
Changes to test/statfault.test.
︙ | ︙ | |||
37 38 39 40 41 42 43 | execsql { SELECT 1 FROM sqlite_master LIMIT 1 } } -body { execsql { SELECT count(*) FROM sss } } -test { faultsim_test_result {0 8} } | > > > > > > > > | > > | 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | execsql { SELECT 1 FROM sqlite_master LIMIT 1 } } -body { execsql { SELECT count(*) FROM sss } } -test { faultsim_test_result {0 8} } do_faultsim_test 2 -faults * -prep { faultsim_restore_and_reopen register_dbstat_vtab db execsql { SELECT 1 FROM sqlite_master LIMIT 1 } } -body { db eval { SELECT * FROM sss } { db eval { SELECT randomblob(5000) } } } -test { faultsim_test_result {0 {}} } finish_test |
Added test/strict1.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 | # 2021-08-18 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # # This file implements regression tests for SQLite library. The # focus of this file is testing STRICT tables. # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix strict1 # STRICT tables have on a limited number of allowed datatypes. # do_catchsql_test strict1-1.1 { CREATE TABLE t1(a) STRICT; } {1 {missing datatype for t1.a}} do_catchsql_test strict1-1.2 { CREATE TABLE t1(a PRIMARY KEY) STRICT, WITHOUT ROWID; } {1 {missing datatype for t1.a}} do_catchsql_test strict1-1.3 { CREATE TABLE t1(a PRIMARY KEY) WITHOUT ROWID, STRICT; } {1 {missing datatype for t1.a}} do_catchsql_test strict1-1.4 { CREATE TABLE t1(a BANJO PRIMARY KEY) WITHOUT ROWID, STRICT; } {1 {unknown datatype for t1.a: "BANJO"}} do_catchsql_test strict1-1.5 { CREATE TABLE t1(a TEXT PRIMARY KEY, b INT, c INTEGER, d REAL, e BLOB, f DATE) strict; } {1 {unknown datatype for t1.f: "DATE"}} do_catchsql_test strict1-1.6 { CREATE TABLE t1(a TEXT PRIMARY KEY, b INT, c INTEGER, d REAL, e BLOB, f TEXT(50)) WITHOUT ROWID, STRICT; } {1 {unknown datatype for t1.f: "TEXT(50)"}} do_execsql_test strict1-2.0 { CREATE TABLE t1( a INT, b INTEGER, c BLOB, d TEXT, e REAL ) STRICT; } {} ifcapable vtab { do_execsql_test strict1-2.0a { SELECT strict FROM pragma_table_list('t1'); } {1} } do_catchsql_test strict1-2.1 { INSERT INTO t1(a) VALUES('xyz'); } {1 {cannot store TEXT value in INT column t1.a}} do_catchsql_test strict1-2.2 { INSERT INTO t1(b) VALUES('xyz'); } {1 {cannot store TEXT value in INTEGER column t1.b}} do_catchsql_test strict1-2.3 { INSERT INTO t1(c) VALUES('xyz'); } {1 {cannot store TEXT value in BLOB column t1.c}} do_catchsql_test strict1-2.4 { INSERT INTO t1(d) VALUES(x'3142536475'); } {1 {cannot store BLOB value in TEXT column t1.d}} do_catchsql_test strict1-2.5 { INSERT INTO t1(e) VALUES('xyz'); } {1 {cannot store TEXT value in REAL column t1.e}} do_execsql_test strict1-3.1 { INSERT INTO t1(a, b) VALUES(1,2),('3','4'),(5.0, 6.0),(null,null); SELECT a, b, '|' FROM t1; } {1 2 | 3 4 | 5 6 | {} {} |} do_catchsql_test strict1-3.2 { INSERT INTO t1(a) VALUES(1.2); } {1 {cannot store REAL value in INT column t1.a}} do_catchsql_test strict1-3.3 { INSERT INTO t1(a) VALUES(x'313233'); } {1 {cannot store BLOB value in INT column t1.a}} do_catchsql_test strict1-3.4 { INSERT INTO t1(b) VALUES(1.2); } {1 {cannot store REAL value in INTEGER column t1.b}} do_catchsql_test strict1-3.5 { INSERT INTO t1(b) VALUES(x'313233'); } {1 {cannot store BLOB value in INTEGER column t1.b}} do_execsql_test strict1-4.1 { DELETE FROM t1; INSERT INTO t1(c) VALUES(x'313233'), (NULL); SELECT typeof(c), c FROM t1; } {blob 123 null {}} do_catchsql_test strict1-4.2 { INSERT INTO t1(c) VALUES('456'); } {1 {cannot store TEXT value in BLOB column t1.c}} do_execsql_test strict1-5.1 { DELETE FROM t1; INSERT INTO t1(d) VALUES('xyz'),(4),(5.5),(NULL); SELECT typeof(d), d FROM t1; } {text xyz text 4 text 5.5 null {}} do_catchsql_test strict1-5.2 { INSERT INTO t1(d) VALUES(x'4567'); } {1 {cannot store BLOB value in TEXT column t1.d}} do_execsql_test strict1-6.1 { DELETE FROM t1; INSERT INTO t1(e) VALUES(1),(2.5),('3'),('4.5'),(6.0),(NULL); SELECT typeof(e), e FROM t1; } {real 1.0 real 2.5 real 3.0 real 4.5 real 6.0 null {}} do_catchsql_test strict1-6.2 { INSERT INTO t1(e) VALUES('xyz'); } {1 {cannot store TEXT value in REAL column t1.e}} do_catchsql_test strict1-6.3 { INSERT INTO t1(e) VALUES(x'3456'); } {1 {cannot store BLOB value in REAL column t1.e}} ifcapable altertable { do_execsql_test strict1-7.1 { DROP TABLE IF EXISTS t4; CREATE TABLE t4( a INT AS (b*2) VIRTUAL, b INT AS (c*2) STORED, c INT PRIMARY KEY ) STRICT; INSERT INTO t4(c) VALUES(1); SELECT * FROM t4; } {4 2 1} do_catchsql_test strict1-7.2 { ALTER TABLE t4 ADD COLUMN d VARCHAR; } {1 {error in table t4 after add column: unknown datatype for t4.d: "VARCHAR"}} do_catchsql_test strict1-7.3 { ALTER TABLE t4 ADD COLUMN d; } {1 {error in table t4 after add column: missing datatype for t4.d}} } finish_test |
Added test/strict2.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 | # 2021-08-19 # # 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 STRICT tables. # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix strict2 # PRAGMA integrity_check on a STRICT table should verify that # all of the values are of the correct type. # do_execsql_test strict2-1.1 { CREATE TABLE t1( a INT, b INTEGER, c TEXT, d REAL, e BLOB ) STRICT; CREATE TABLE t1nn( a INT NOT NULL, b INTEGER NOT NULL, c TEXT NOT NULL, d REAL NOT NULL, e BLOB NOT NULL ) STRICT; CREATE TABLE t2(a,b,c,d,e); INSERT INTO t1(a,b,c,d,e) VALUES(1,1,'one',1.0,x'b1'),(2,2,'two',2.25,x'b2b2b2'); PRAGMA writable_schema=on; UPDATE sqlite_schema SET rootpage=(SELECT rootpage FROM sqlite_schema WHERE name='t1'); } {} db close sqlite3 db test.db do_execsql_test strict2-1.2 { PRAGMA quick_check('t1'); } {ok} do_execsql_test strict2-1.3 { UPDATE t2 SET a=2.5 WHERE b=2; PRAGMA quick_check('t1'); } {{non-INT value in t1.a}} do_execsql_test strict2-1.4 { UPDATE t2 SET a='xyz' WHERE b=2; PRAGMA quick_check('t1'); } {{non-INT value in t1.a}} do_execsql_test strict2-1.5 { UPDATE t2 SET a=x'445566' WHERE b=2; PRAGMA quick_check('t1'); } {{non-INT value in t1.a}} do_execsql_test strict2-1.6 { UPDATE t2 SET a=2.5 WHERE b=2; PRAGMA quick_check('t1nn'); } {{non-INT value in t1nn.a}} do_execsql_test strict2-1.7 { UPDATE t2 SET a='xyz' WHERE b=2; PRAGMA quick_check('t1nn'); } {{non-INT value in t1nn.a}} do_execsql_test strict2-1.8 { UPDATE t2 SET a=x'445566' WHERE b=2; PRAGMA quick_check('t1nn'); } {{non-INT value in t1nn.a}} do_execsql_test strict2-1.13 { UPDATE t2 SET a=2 WHERE b=2; UPDATE t2 SET b=2.5 WHERE a=2; PRAGMA quick_check('t1'); } {{non-INTEGER value in t1.b}} do_execsql_test strict2-1.14 { UPDATE t2 SET b='two' WHERE a=2; PRAGMA quick_check('t1'); } {{non-INTEGER value in t1.b}} do_execsql_test strict2-1.15 { UPDATE t2 SET b=x'b0b1b2b3b4' WHERE a=2; PRAGMA quick_check('t1'); } {{non-INTEGER value in t1.b}} do_execsql_test strict2-1.16 { UPDATE t2 SET b=NULL WHERE a=2; PRAGMA quick_check('t1'); } {ok} do_execsql_test strict2-1.17 { UPDATE t2 SET b=2.5 WHERE a=2; PRAGMA quick_check('t1nn'); } {{non-INTEGER value in t1nn.b}} do_execsql_test strict2-1.18 { UPDATE t2 SET b=NULL WHERE a=2; PRAGMA quick_check('t1nn'); } {{NULL value in t1nn.b}} do_execsql_test strict2-1.23 { UPDATE t2 SET b=2 WHERE a=2; UPDATE t2 SET c=9 WHERE a=2; PRAGMA quick_check('t1'); } {{non-TEXT value in t1.c}} do_execsql_test strict2-1.24 { UPDATE t2 SET c=9.5 WHERE a=2; PRAGMA quick_check('t1'); } {{non-TEXT value in t1.c}} do_execsql_test strict2-1.25 { UPDATE t2 SET c=x'b0b1b2b3b4' WHERE a=2; PRAGMA quick_check('t1'); } {{non-TEXT value in t1.c}} do_execsql_test strict2-1.33 { UPDATE t2 SET c='two' WHERE a=2; UPDATE t2 SET d=9 WHERE a=2; PRAGMA quick_check('t1'); } {ok} do_execsql_test strict2-1.34 { UPDATE t2 SET d='nine' WHERE a=2; PRAGMA quick_check('t1'); } {{non-REAL value in t1.d}} do_execsql_test strict2-1.35 { UPDATE t2 SET d=x'b0b1b2b3b4' WHERE a=2; PRAGMA quick_check('t1'); } {{non-REAL value in t1.d}} do_execsql_test strict2-1.43 { UPDATE t2 SET d=2.5 WHERE a=2; UPDATE t2 SET e=9 WHERE a=2; PRAGMA quick_check('t1'); } {{non-BLOB value in t1.e}} do_execsql_test strict2-1.44 { UPDATE t2 SET e=9.5 WHERE a=2; PRAGMA quick_check('t1'); } {{non-BLOB value in t1.e}} do_execsql_test strict2-1.45 { UPDATE t2 SET e='hello' WHERE a=2; PRAGMA quick_check('t1'); } {{non-BLOB value in t1.e}} do_execsql_test strict2-2.0 { DROP TABLE IF EXISTS t2; CREATE TABLE t2(a INT, b ANY) STRICT; INSERT INTO t2(a,b) VALUES(1,2),(3,4.5),(5,'six'),(7,x'8888'),(9,NULL); PRAGMA integrity_check(t2); } {ok} do_execsql_test strict2-3.0 { DROP TABLE IF EXISTS t1; CREATE TABLE t1(id ANY PRIMARY KEY, x TEXT); INSERT INTO t1 VALUES(1,2),('three','four'),(x'5555','six'),(NULL,'eight'); PRAGMA writable_schema=ON; UPDATE sqlite_schema SET sql=(sql||'STRICT') WHERE name='t1'; PRAGMA writable_schema=RESET; PRAGMA integrity_check(t1); } {{NULL value in t1.id}} finish_test |
Changes to test/subquery2.test.
︙ | ︙ | |||
193 194 195 196 197 198 199 200 201 | } } { do_catchsql_test 4.$tn $sql [list {*}{ 1 {ORDER BY clause should come after UNION ALL not before} }] } finish_test | > > > > > > > > > > > > > > > > > | 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 | } } { do_catchsql_test 4.$tn $sql [list {*}{ 1 {ORDER BY clause should come after UNION ALL not before} }] } #------------------------------------------------------------------------- # Test that ticket [9cdc5c46] is fixed. # reset_db do_execsql_test 5.0 { CREATE TABLE t1(x); INSERT INTO t1 VALUES('ALFKI'); INSERT INTO t1 VALUES('ANATR'); CREATE TABLE t2(y, z); CREATE INDEX t2y ON t2 (y); INSERT INTO t2 VALUES('ANATR', '1997-08-08 00:00:00'); INSERT INTO t2 VALUES('ALFKI', '1997-08-25 00:00:00'); } do_execsql_test 5.1 { SELECT ( SELECT y FROM t2 WHERE x = y ORDER BY y, z) FROM t1; } {ALFKI ANATR} finish_test |
Changes to test/substr.test.
1 2 3 4 5 6 7 8 9 10 11 12 13 | # 2007 May 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 implements regression tests for SQLite library. The # focus of this file is testing the built-in SUBSTR() functions. # | < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | # 2007 May 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 implements regression tests for SQLite library. The # focus of this file is testing the built-in SUBSTR() functions. # set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable !tclvar { finish_test return |
︙ | ︙ | |||
35 36 37 38 39 40 41 | execsql { SELECT substr(t, $i1, $i2) FROM t1 } }] [list $result] set qstr '[string map {' ''} $string]' do_test substr-$id.2 [subst { execsql { | | | | 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 | execsql { SELECT substr(t, $i1, $i2) FROM t1 } }] [list $result] set qstr '[string map {' ''} $string]' do_test substr-$id.2 [subst { execsql { SELECT substring($qstr, $i1, $i2) } }] [list $result] } proc subblob-test {id hex i1 i2 hexresult} { db eval " DELETE FROM t1; INSERT INTO t1(b) VALUES(x'$hex') " do_test substr-$id.1 [subst { execsql { SELECT hex(substr(b, $i1, $i2)) FROM t1 } }] [list $hexresult] do_test substr-$id.2 [subst { execsql { SELECT hex(substring(x'$hex', $i1, $i2)) } }] [list $hexresult] } # Basic SUBSTR functionality # substr-test 1.1 abcdefg 1 1 a |
︙ | ︙ | |||
89 90 91 92 93 94 95 | do_test substr-1.91 { db eval {SELECT ifnull(substr(NULL,1),'nil')} } nil do_test substr-1.92 { db eval {SELECT ifnull(substr('abcdefg',NULL,1),'nil')} } nil do_test substr-1.93 { | | | 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 | do_test substr-1.91 { db eval {SELECT ifnull(substr(NULL,1),'nil')} } nil do_test substr-1.92 { db eval {SELECT ifnull(substr('abcdefg',NULL,1),'nil')} } nil do_test substr-1.93 { db eval {SELECT ifnull(substring('abcdefg',NULL),'nil')} } nil do_test substr-1.94 { db eval {SELECT ifnull(substr('abcdefg',1,NULL),'nil')} } nil # Make sure everything works with long unicode characters # |
︙ | ︙ | |||
145 146 147 148 149 150 151 | execsql { SELECT substr(t, $idx) FROM t1 } }] [list $result] set qstr '[string map {' ''} $string]' do_test substr-$id.2 [subst { execsql { | | | 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 | execsql { SELECT substr(t, $idx) FROM t1 } }] [list $result] set qstr '[string map {' ''} $string]' do_test substr-$id.2 [subst { execsql { SELECT substring($qstr, $idx) } }] [list $result] } substr-2-test 5.1 abcdefghijklmnop 5 efghijklmnop substr-2-test 5.2 abcdef -5 bcdef finish_test |
Changes to test/symlink.test.
︙ | ︙ | |||
33 34 35 36 37 38 39 40 41 42 43 | forcedelete test.db2 do_test 1.1 { file link test.db2 test.db sqlite3 db2 test.db2 sqlite3_db_filename db2 main } [file join [pwd] test.db] # Test that if the symlink points to a file that does not exists, it is # created when it is opened. # do_test 1.2.1 { | > > > > > > > > > > > > > > > > > > > | | 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 | forcedelete test.db2 do_test 1.1 { file link test.db2 test.db sqlite3 db2 test.db2 sqlite3_db_filename db2 main } [file join [pwd] test.db] # But not with the -nofollow flag # do_test 1.1.2 { db2 close set rc [catch {sqlite3 db2 test.db2 -nofollow 1} msg] lappend rc $msg } {1 {unable to open database file}} # If the main database is successfully opened with -nofollow, then -nofollow # is also used for ATTACH. # do_test 1.1.3 { catch {db2 close} sqlite3 db2 test.db -nofollow 1 } {} do_test 1.1.4 { catchsql {ATTACH 'test.db2' AS aux1;} db2 } {1 {unable to open database: test.db2}} # Test that if the symlink points to a file that does not exists, it is # created when it is opened. # do_test 1.2.1 { catch {db2 close} db close forcedelete test.db file exists test.db } 0 do_test 1.2.2 { sqlite3 db2 test.db2 file exists test.db |
︙ | ︙ |
Added test/symlink2.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 | # 2019 November 18 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this file is testing that SQLite can follow symbolic links. # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix symlink2 # This only runs on Windows. if {$::tcl_platform(platform)!="windows"} { finish_test return } proc createWin32Symlink { link target } { exec -- $::env(ComSpec) /c mklink \ [file nativename $link] [file nativename $target] return "" } proc deleteWin32Symlink { link } { exec -- $::env(ComSpec) /c del [file nativename $link] return "" } proc canCreateWin32Symlink {} { set link [file join $::testdir lnk[pid].sym] if {[file exists $link]} { return 0 } set target [info nameofexecutable] if {[catch {createWin32Symlink $link $target}] == 0} { deleteWin32Symlink $link return 1 } return 0 } # Creating symlinks may require administrator privileges on Windows. if {![canCreateWin32Symlink]} { finish_test return } # Ensure that test.db has been created. # do_execsql_test 1.0 { CREATE TABLE t1(x, y); INSERT INTO t1 VALUES(1,9999); } do_test 2.0 { createWin32Symlink link.db test.db } {} do_test 2.1 { file exists test.db } {1} do_test 2.2 { file exists link.db } {1} do_test 3.1 { execsql { SELECT x, y FROM t1; } db } {1 9999} do_test 3.2 { sqlite3 db2 link.db execsql { SELECT x, y FROM t1; } db2 } {1 9999} do_test 3.3 { sqlite3 db3 test.db -nofollow true execsql { SELECT x, y FROM t1; } db3 } {1 9999} do_test 3.4 { db3 close } {} do_test 3.5 { list [catch { sqlite3 db4 link.db -nofollow true execsql { SELECT x, y FROM t1; } db4 } res] $res } {1 {unable to open database file}} catch {db4 close} do_test 4.0 { db2 close deleteWin32Symlink link.db } {} do_test 4.1 { file exists test.db } {1} do_test 4.2 { file exists link.db } {0} do_test 5.1 { execsql { SELECT x, y FROM t1; } db } {1 9999} finish_test |
Changes to test/tabfunc01.test.
︙ | ︙ | |||
28 29 30 31 32 33 34 | do_execsql_test tabfunc01-1.1 { SELECT *, '|' FROM generate_series WHERE start=1 AND stop=9 AND step=2; } {1 | 3 | 5 | 7 | 9 |} do_execsql_test tabfunc01-1.1b { PRAGMA table_xinfo(generate_series); } {0 value {} 0 {} 0 0 1 start {} 0 {} 0 1 2 stop {} 0 {} 0 1 3 step {} 0 {} 0 1} do_execsql_test tabfunc01-1.2 { | | > > > > > > | 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | do_execsql_test tabfunc01-1.1 { SELECT *, '|' FROM generate_series WHERE start=1 AND stop=9 AND step=2; } {1 | 3 | 5 | 7 | 9 |} do_execsql_test tabfunc01-1.1b { PRAGMA table_xinfo(generate_series); } {0 value {} 0 {} 0 0 1 start {} 0 {} 0 1 2 stop {} 0 {} 0 1 3 step {} 0 {} 0 1} do_execsql_test tabfunc01-1.2 { SELECT *, '|' FROM generate_series(0) LIMIT 5; } {0 | 1 | 2 | 3 | 4 |} do_catchsql_test tabfunc01-1.2b { SELECT *, '|' FROM generate_series LIMIT 5; } {1 {first argument to "generate_series()" missing or unusable}} do_catchsql_test tabfunc01-1.2c { SELECT *, '|' FROM generate_series(value) LIMIT 5; } {1 {first argument to "generate_series()" missing or unusable}} do_catchsql_test tabfunc01-1.3 { CREATE VIRTUAL TABLE t1 USING generate_series; } {1 {no such module: generate_series}} do_execsql_test tabfunc01-1.4 { SELECT * FROM generate_series(1,9,2); } {1 3 5 7 9} do_execsql_test tabfunc01-1.5 { |
︙ | ︙ | |||
100 101 102 103 104 105 106 | } {2 1 | 2 2 | 3 1 | 3 2 | 3 3 |} do_execsql_test tabfunc01-2.2 { SELECT *, '|' FROM (SELECT x FROM t1) AS y, generate_series(1,y.x) ORDER BY 1, 2; } {2 1 | 2 2 | 3 1 | 3 2 | 3 3 |} do_execsql_test tabfunc01-2.50 { | | | 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 | } {2 1 | 2 2 | 3 1 | 3 2 | 3 3 |} do_execsql_test tabfunc01-2.2 { SELECT *, '|' FROM (SELECT x FROM t1) AS y, generate_series(1,y.x) ORDER BY 1, 2; } {2 1 | 2 2 | 3 1 | 3 2 | 3 3 |} do_execsql_test tabfunc01-2.50 { SELECT * FROM generate_series(0) LIMIT 5; } {0 1 2 3 4} do_execsql_test tabfunc01-3.1 { SELECT DISTINCT value FROM generate_series(1,x), t1 ORDER BY 1; } {1 2 3} # Eponymous virtual table exists in all schemas. |
︙ | ︙ | |||
213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 | do_test tabfunc01-750 { db eval { SELECT aa.value, bb.value, '|' FROM carray(inttoptr($PTR4),5,'double') AS aa JOIN carray(inttoptr($PTR5),5,'char*') AS bb ON aa.rowid=bb.rowid; } } {5.0 x5 | 7.0 x7 | 13.0 x13 | 17.0 x17 | 23.0 x23 |} # Free up memory allocations intarray_addr int64array_addr doublearray_addr textarray_addr finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 | do_test tabfunc01-750 { db eval { SELECT aa.value, bb.value, '|' FROM carray(inttoptr($PTR4),5,'double') AS aa JOIN carray(inttoptr($PTR5),5,'char*') AS bb ON aa.rowid=bb.rowid; } } {5.0 x5 | 7.0 x7 | 13.0 x13 | 17.0 x17 | 23.0 x23 |} # ticket https://www.sqlite.org/src/info/2ae0c599b735d59e do_test tabfunc01-751 { db eval { SELECT aa.value, bb.value, '|' FROM carray(inttoptr($PTR4),5,'double') AS aa LEFT JOIN carray(inttoptr($PTR5),5,'char*') AS bb ON aa.rowid=bb.rowid; } } {5.0 x5 | 7.0 x7 | 13.0 x13 | 17.0 x17 | 23.0 x23 |} ifcapable altertable { do_test tabfunc01-800 { catchsql { ALTER TABLE generate_series ADD COLUMN col2; } } {1 {virtual tables may not be altered}} do_test tabfunc01-810 { catchsql { ALTER TABLE generate_series RENAME TO flubber; } } {1 {table generate_series may not be altered}} do_test tabfunc01-820 { catchsql { ALTER TABLE generate_series RENAME start TO flubber; } } {1 {table generate_series may not be altered}} do_test tabfunc01-830 { catchsql { ALTER TABLE generate_series DROP COLUMN start; } } {1 {table generate_series may not be altered}} do_test tabfunc01-900 { catchsql { ALTER TABLE pragma_compile_options ADD COLUMN col2; } } {1 {virtual tables may not be altered}} do_test tabfunc01-910 { catchsql { ALTER TABLE pragma_compile_options RENAME TO flubber; } } {1 {table pragma_compile_options may not be altered}} do_test tabfunc01-920 { catchsql { ALTER TABLE pragma_compile_options RENAME start TO flubber; } } {1 {table pragma_compile_options may not be altered}} do_test tabfunc01-930 { catchsql { ALTER TABLE pragma_compile_options DROP COLUMN start; } } {1 {table pragma_compile_options may not be altered}} } # Free up memory allocations intarray_addr int64array_addr doublearray_addr textarray_addr finish_test |
Changes to test/tclsqlite.test.
︙ | ︙ | |||
17 18 19 20 21 22 23 24 25 26 | # # $Id: tclsqlite.test,v 1.73 2009/03/16 13:19:36 danielk1977 Exp $ catch {sqlite3} set testdir [file dirname $argv0] source $testdir/tester.tcl # Check the error messages generated by tclsqlite # | > | | | 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 | # # $Id: tclsqlite.test,v 1.73 2009/03/16 13:19:36 danielk1977 Exp $ catch {sqlite3} set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix tcl # Check the error messages generated by tclsqlite # set r "sqlite_orig HANDLE ?FILENAME? ?-vfs VFSNAME? ?-readonly BOOLEAN? ?-create BOOLEAN? ?-nofollow BOOLEAN? ?-nomutex BOOLEAN? ?-fullmutex BOOLEAN? ?-uri BOOLEAN?" if {[sqlite3 -has-codec]} { append r " ?-key CODECKEY?" } do_test tcl-1.1 { set v [catch {sqlite3 -bogus} msg] regsub {really_sqlite3} $msg {sqlite3} msg lappend v $msg } [list 1 "wrong # args: should be \"$r\""] do_test tcl-1.1.1 { set v [catch {sqlite3} msg] regsub {really_sqlite3} $msg {sqlite3} msg lappend v $msg } [list 1 "wrong # args: should be \"$r\""] do_test tcl-1.2 { set v [catch {db bogus} msg] lappend v $msg } {1 {bad option "bogus": must be authorizer, backup, bind_fallback, busy, cache, changes, close, collate, collation_needed, commit_hook, complete, config, copy, deserialize, enable_load_extension, errorcode, eval, exists, function, incrblob, interrupt, last_insert_rowid, nullvalue, onecolumn, preupdate, profile, progress, rekey, restore, rollback_hook, serialize, status, timeout, total_changes, trace, trace_v2, transaction, unlock_notify, update_hook, version, or wal_hook}} do_test tcl-1.2.1 { set v [catch {db cache bogus} msg] lappend v $msg } {1 {bad option "bogus": must be flush or size}} do_test tcl-1.2.2 { set v [catch {db cache} msg] lappend v $msg |
︙ | ︙ | |||
161 162 163 164 165 166 167 | catch {unset ::result} do_test tcl-2.1 { execsql "CREATE TABLE t\u0123x(a int, b\u1235 float)" } {} ifcapable schema_pragmas { do_test tcl-2.2 { execsql "PRAGMA table_info(t\u0123x)" | | | 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 | catch {unset ::result} do_test tcl-2.1 { execsql "CREATE TABLE t\u0123x(a int, b\u1235 float)" } {} ifcapable schema_pragmas { do_test tcl-2.2 { execsql "PRAGMA table_info(t\u0123x)" } "0 a INT 0 {} 0 1 b\u1235 float 0 {} 0" } do_test tcl-2.3 { execsql "INSERT INTO t\u0123x VALUES(1,2.3)" db eval "SELECT * FROM t\u0123x" result break set result(*) } "a b\u1235" |
︙ | ︙ | |||
366 367 368 369 370 371 372 | if {$n<=0} {return 0} set nm1 [expr {$n-1}] return [expr {[db eval {SELECT r1($nm1)}]+$n}] } db function r1 userfunc_r1 execsql {SELECT r1(10)} } {55} | > | | | | 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 | if {$n<=0} {return 0} set nm1 [expr {$n-1}] return [expr {[db eval {SELECT r1($nm1)}]+$n}] } db function r1 userfunc_r1 execsql {SELECT r1(10)} } {55} # Fails under -fsanitize=address,undefined due to stack overflow # do_test tcl-9.11 { # execsql {SELECT r1(100)} # } {5050} } # Tests for the new transaction method # do_test tcl-10.1 { db transaction {} } {} |
︙ | ︙ | |||
707 708 709 710 711 712 713 | unset -nocomplain x db eval -withoutnulls {SELECT * FROM t1} x { lappend res $x(a) [array names x] } set res } {1 {a b *} 2 {a *} 3 {a b *}} | > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | unset -nocomplain x db eval -withoutnulls {SELECT * FROM t1} x { lappend res $x(a) [array names x] } set res } {1 {a b *} 2 {a *} 3 {a b *}} #------------------------------------------------------------------------- # Test the -type option to [db function]. # reset_db proc add {a b} { return [expr $a + $b] } proc ret {a} { return $a } db function add_i -returntype integer add db function add_r -ret real add db function add_t -return text add db function add_b -returntype blob add db function add_a -returntype any add db function ret_i -returntype int ret db function ret_r -returntype real ret db function ret_t -returntype text ret db function ret_b -returntype blob ret db function ret_a -r any ret do_execsql_test 17.0 { SELECT quote( add_i(2, 3) ); SELECT quote( add_r(2, 3) ); SELECT quote( add_t(2, 3) ); SELECT quote( add_b(2, 3) ); SELECT quote( add_a(2, 3) ); } {5 5.0 '5' X'35' 5} do_execsql_test 17.1 { SELECT quote( add_i(2.2, 3.3) ); SELECT quote( add_r(2.2, 3.3) ); SELECT quote( add_t(2.2, 3.3) ); SELECT quote( add_b(2.2, 3.3) ); SELECT quote( add_a(2.2, 3.3) ); } {5.5 5.5 '5.5' X'352E35' 5.5} do_execsql_test 17.2 { SELECT quote( ret_i(2.5) ); SELECT quote( ret_r(2.5) ); SELECT quote( ret_t(2.5) ); SELECT quote( ret_b(2.5) ); SELECT quote( ret_a(2.5) ); } {2.5 2.5 '2.5' X'322E35' 2.5} do_execsql_test 17.3 { SELECT quote( ret_i('2.5') ); SELECT quote( ret_r('2.5') ); SELECT quote( ret_t('2.5') ); SELECT quote( ret_b('2.5') ); SELECT quote( ret_a('2.5') ); } {2.5 2.5 '2.5' X'322E35' '2.5'} do_execsql_test 17.4 { SELECT quote( ret_i('abc') ); SELECT quote( ret_r('abc') ); SELECT quote( ret_t('abc') ); SELECT quote( ret_b('abc') ); SELECT quote( ret_a('abc') ); } {'abc' 'abc' 'abc' X'616263' 'abc'} do_execsql_test 17.5 { SELECT quote( ret_i(X'616263') ); SELECT quote( ret_r(X'616263') ); SELECT quote( ret_t(X'616263') ); SELECT quote( ret_b(X'616263') ); SELECT quote( ret_a(X'616263') ); } {'abc' 'abc' 'abc' X'616263' X'616263'} do_test 17.6.1 { list [catch { db function xyz -return object ret } msg] $msg } {1 {bad type "object": must be integer, real, text, blob, or any}} do_test 17.6.2 { list [catch { db function xyz -return ret } msg] $msg } {1 {option requires an argument: -return}} do_test 17.6.3 { list [catch { db function xyz -n object ret } msg] $msg } {1 {bad option "-n": must be -argcount, -deterministic, -directonly, -innocuous, or -returntype}} # 2019-02-28: The "bind_fallback" command. # do_test 18.100 { unset -nocomplain bindings abc def ghi jkl mno e01 e02 set bindings(abc) [expr {1+2}] set bindings(def) {hello} set bindings(ghi) [expr {3.1415926*1.0}] proc bind_callback {nm} { global bindings set n2 [string range $nm 1 end] if {[info exists bindings($n2)]} { return $bindings($n2) } if {[string match e* $n2]} { error "no such variable: $nm" } return -code return {} } db bind_fallback bind_callback db eval {SELECT $abc, typeof($abc), $def, typeof($def), $ghi, typeof($ghi)} } {3 integer hello text 3.1415926 real} do_test 18.110 { db eval {SELECT quote(@def), typeof(@def)} } {X'68656C6C6F' blob} do_execsql_test 18.120 { SELECT typeof($mno); } {null} do_catchsql_test 18.130 { SELECT $e01; } {1 {no such variable: $e01}} do_test 18.140 { db bind_fallback } {bind_callback} do_test 18.200 { db bind_fallback {} db eval {SELECT $abc, typeof($abc), $def, typeof($def), $ghi, typeof($ghi)} } {{} null {} null {} null} do_test 18.300 { unset -nocomplain bindings proc bind_callback {nm} {lappend ::bindings $nm} db bind_fallback bind_callback db eval {SELECT $abc, @def, $ghi(123), :mno} set bindings } {{$abc} @def {$ghi(123)} :mno} do_test 18.900 { set rc [catch {db bind_fallback a b} msg] lappend rc $msg } {1 {wrong # args: should be "db bind_fallback ?CALLBACK?"}} do_test 18.910 { db bind_fallback bind_fallback_does_not_exist } {} do_catchsql_test 19.911 { SELECT $abc, typeof($abc), $def, typeof($def), $ghi, typeof($ghi); } {1 {invalid command name "bind_fallback_does_not_exist"}} db bind_fallback {} #------------------------------------------------------------------------- do_test 20.0 { db transaction { db close } } {} do_test 20.1 { sqlite3 db test.db set rc [catch { db eval {SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3} { db close } } msg] list $rc $msg } {1 {invalid command name "db"}} proc closedb {} { db close return 10 } proc func1 {} { return 1 } sqlite3 db test.db db func closedb closedb db func func1 func1 do_test 20.2 { set rc [catch { db eval { SELECT closedb(),func1() UNION ALL SELECT 20,30 UNION ALL SELECT 30,40 } } msg] list $rc $msg } {0 {10 1 20 30 30 40}} finish_test |
Changes to test/tempdb2.test.
︙ | ︙ | |||
93 94 95 96 97 98 99 | } do_execsql_test 2.2 { SELECT b FROM t1 WHERE a = 10001; } "[int2str 1001][int2str 1001][int2str 1001]" finish_test | < | 93 94 95 96 97 98 99 | } do_execsql_test 2.2 { SELECT b FROM t1 WHERE a = 10001; } "[int2str 1001][int2str 1001][int2str 1001]" finish_test |
Changes to test/tester.tcl.
︙ | ︙ | |||
84 85 86 87 88 89 90 91 92 93 94 95 96 97 | # # Command to test whether or not --verbose=1 was specified on the command # line (returns 0 for not-verbose, 1 for verbose and 2 for "verbose in the # output file only"). # # verbose # # Set the precision of FP arithmatic used by the interpreter. And # configure SQLite to take database file locks on the page that begins # 64KB into the database file instead of the one 1GB in. This means # the code that handles that special case can be tested without creating # very large database files. # | > > > | 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 | # # Command to test whether or not --verbose=1 was specified on the command # line (returns 0 for not-verbose, 1 for verbose and 2 for "verbose in the # output file only"). # # verbose # # Only run this script once. If sourced a second time, make it a no-op if {[info exists ::tester_tcl_has_run]} return # Set the precision of FP arithmatic used by the interpreter. And # configure SQLite to take database file locks on the page that begins # 64KB into the database file instead of the one 1GB in. This means # the code that handles that special case can be tested without creating # very large database files. # |
︙ | ︙ | |||
125 126 127 128 129 130 131 132 133 134 135 136 137 138 | if {[info exists ::G(perm:presql)]} { [lindex $args 0] eval $::G(perm:presql) } 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 } | > | 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 | if {[info exists ::G(perm:presql)]} { [lindex $args 0] eval $::G(perm:presql) } if {[info exists ::G(perm:dbconfig)]} { set ::dbhandle [lindex $args 0] uplevel #0 $::G(perm:dbconfig) } [lindex $args 0] cache size 3 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 } |
︙ | ︙ | |||
169 170 171 172 173 174 175 176 | proc get_pwd {} { if {$::tcl_platform(platform) eq "windows"} { # # NOTE: Cannot use [file normalize] here because it would alter the # case of the result to what Tcl considers canonical, which would # defeat the purpose of this procedure. # return [string map [list \\ /] \ | > > > > > > | | 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 | proc get_pwd {} { if {$::tcl_platform(platform) eq "windows"} { # # NOTE: Cannot use [file normalize] here because it would alter the # case of the result to what Tcl considers canonical, which would # defeat the purpose of this procedure. # if {[info exists ::env(ComSpec)]} { set comSpec $::env(ComSpec) } else { # NOTE: Hard-code the typical default value. set comSpec {C:\Windows\system32\cmd.exe} } return [string map [list \\ /] \ [string trim [exec -- $comSpec /c echo %CD%]]] } else { return [pwd] } } # Copy file $from into $to. This is used because some versions of # TCL for windows (notably the 8.4.1 binary package shipped with the |
︙ | ︙ | |||
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 | # Print a HELP message and exit # proc print_help_and_quit {} { puts {Options: --pause Wait for user input before continuing --soft-heap-limit=N Set the soft-heap-limit to N --maxerror=N Quit after N errors --verbose=(0|1) Control the amount of output. Default '1' --output=FILE set --verbose=2 and output to FILE. Implies -q -q Shorthand for --verbose=0 --help This message } exit 1 } # The following block only runs the first time this file is sourced. It # does not run in slave interpreters (since the ::cmdlinearg array is # populated before the test script is run in slave interpreters). # if {[info exists cmdlinearg]==0} { # Parse any options specified in the $argv array. This script accepts the # following options: # # --pause # --soft-heap-limit=NN # --maxerror=NN # --malloctrace=N # --backtrace=N # --binarylog=N # --soak=N # --file-retries=N # --file-retry-delay=N # --start=[$permutation:]$testfile # --match=$pattern # --verbose=$val # --output=$filename # -q Reduce output # --testdir=$dir Run tests in subdirectory $dir # --help # set cmdlinearg(soft-heap-limit) 0 set cmdlinearg(maxerror) 1000 set cmdlinearg(malloctrace) 0 set cmdlinearg(backtrace) 10 set cmdlinearg(binarylog) 0 set cmdlinearg(soak) 0 set cmdlinearg(file-retries) 0 set cmdlinearg(file-retry-delay) 0 | > > > | 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 | # Print a HELP message and exit # proc print_help_and_quit {} { puts {Options: --pause Wait for user input before continuing --soft-heap-limit=N Set the soft-heap-limit to N --hard-heap-limit=N Set the hard-heap-limit to N --maxerror=N Quit after N errors --verbose=(0|1) Control the amount of output. Default '1' --output=FILE set --verbose=2 and output to FILE. Implies -q -q Shorthand for --verbose=0 --help This message } exit 1 } # The following block only runs the first time this file is sourced. It # does not run in slave interpreters (since the ::cmdlinearg array is # populated before the test script is run in slave interpreters). # if {[info exists cmdlinearg]==0} { # Parse any options specified in the $argv array. This script accepts the # following options: # # --pause # --soft-heap-limit=NN # --hard-heap-limit=NN # --maxerror=NN # --malloctrace=N # --backtrace=N # --binarylog=N # --soak=N # --file-retries=N # --file-retry-delay=N # --start=[$permutation:]$testfile # --match=$pattern # --verbose=$val # --output=$filename # -q Reduce output # --testdir=$dir Run tests in subdirectory $dir # --help # set cmdlinearg(soft-heap-limit) 0 set cmdlinearg(hard-heap-limit) 0 set cmdlinearg(maxerror) 1000 set cmdlinearg(malloctrace) 0 set cmdlinearg(backtrace) 10 set cmdlinearg(binarylog) 0 set cmdlinearg(soak) 0 set cmdlinearg(file-retries) 0 set cmdlinearg(file-retry-delay) 0 |
︙ | ︙ | |||
446 447 448 449 450 451 452 453 454 455 456 457 458 459 | puts -nonewline "Press RETURN to begin..." flush stdout gets stdin } {^-+soft-heap-limit=.+$} { foreach {dummy cmdlinearg(soft-heap-limit)} [split $a =] break } {^-+maxerror=.+$} { foreach {dummy cmdlinearg(maxerror)} [split $a =] break } {^-+malloctrace=.+$} { foreach {dummy cmdlinearg(malloctrace)} [split $a =] break if {$cmdlinearg(malloctrace)} { if {0==$::sqlite_options(memdebug)} { | > > > | 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 | puts -nonewline "Press RETURN to begin..." flush stdout gets stdin } {^-+soft-heap-limit=.+$} { foreach {dummy cmdlinearg(soft-heap-limit)} [split $a =] break } {^-+hard-heap-limit=.+$} { foreach {dummy cmdlinearg(hard-heap-limit)} [split $a =] break } {^-+maxerror=.+$} { foreach {dummy cmdlinearg(maxerror)} [split $a =] break } {^-+malloctrace=.+$} { foreach {dummy cmdlinearg(malloctrace)} [split $a =] break if {$cmdlinearg(malloctrace)} { if {0==$::sqlite_options(memdebug)} { |
︙ | ︙ | |||
572 573 574 575 576 577 578 579 580 581 582 583 584 | set ::G(output_fd) [open $cmdlinearg(output) w] fconfigure $::G(output_fd) -buffering line } if {$cmdlinearg(verbose)==""} { set cmdlinearg(verbose) 1 } } # Update the soft-heap-limit each time this script is run. In that # way if an individual test file changes the soft-heap-limit, it # will be reset at the start of the next test file. # | > > > > | > | 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 | set ::G(output_fd) [open $cmdlinearg(output) w] fconfigure $::G(output_fd) -buffering line } if {$cmdlinearg(verbose)==""} { set cmdlinearg(verbose) 1 } if {[info commands vdbe_coverage]!=""} { vdbe_coverage start } } # Update the soft-heap-limit each time this script is run. In that # way if an individual test file changes the soft-heap-limit, it # will be reset at the start of the next test file. # sqlite3_soft_heap_limit64 $cmdlinearg(soft-heap-limit) sqlite3_hard_heap_limit64 $cmdlinearg(hard-heap-limit) # Create a test database # proc reset_db {} { catch {db close} forcedelete test.db forcedelete test.db-journal |
︙ | ︙ | |||
767 768 769 770 771 772 773 774 775 776 777 778 779 780 | if {![info exists ::G(match)] || [string match $::G(match) $name]} { if {[catch {uplevel #0 "$cmd;\n"} result]} { output2_if_no_verbose -nonewline $name... output2 "\nError: $result" fail_test $name } else { if {[regexp {^[~#]?/.*/$} $expected]} { # "expected" is of the form "/PATTERN/" then the result if correct if # regular expression PATTERN matches the result. "~/PATTERN/" means # the regular expression must not match. if {[string index $expected 0]=="~"} { set re [string range $expected 2 end-1] if {[string index $re 0]=="*"} { | > > > | 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 | if {![info exists ::G(match)] || [string match $::G(match) $name]} { if {[catch {uplevel #0 "$cmd;\n"} result]} { output2_if_no_verbose -nonewline $name... output2 "\nError: $result" fail_test $name } else { if {[permutation]=="maindbname"} { set result [string map [list [string tolower ICECUBE] main] $result] } if {[regexp {^[~#]?/.*/$} $expected]} { # "expected" is of the form "/PATTERN/" then the result if correct if # regular expression PATTERN matches the result. "~/PATTERN/" means # the regular expression must not match. if {[string index $expected 0]=="~"} { set re [string range $expected 2 end-1] if {[string index $re 0]=="*"} { |
︙ | ︙ | |||
883 884 885 886 887 888 889 | # puts [dumpbytes $msg] list $rc $msg } proc filepath_normalize {p} { # test cases should be written to assume "unix"-like file paths if {$::tcl_platform(platform)!="unix"} { | | | | 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 | # puts [dumpbytes $msg] list $rc $msg } proc filepath_normalize {p} { # test cases should be written to assume "unix"-like file paths if {$::tcl_platform(platform)!="unix"} { string map [list \\ / \{/ / .db\} .db] \ [regsub -nocase -all {[a-z]:[/\\]+} $p {/}] } { set p } } proc do_filepath_test {name cmd expected} { uplevel [list do_test $name [ subst -nocommands { filepath_normalize [ $cmd ] } |
︙ | ︙ | |||
937 938 939 940 941 942 943 944 945 946 947 948 949 950 | } if {[llength $args]==2} { foreach {testname sql} $args {} set result "" } elseif {[llength $args]==3} { foreach {testname sql result} $args {} } else { error [string trim { wrong # args: should be "do_execsql_test ?-db DB? testname sql ?result?" }] } fix_testname testname | > > > > > > | 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 | } if {[llength $args]==2} { foreach {testname sql} $args {} set result "" } elseif {[llength $args]==3} { foreach {testname sql result} $args {} # With some versions of Tcl on windows, if $result is all whitespace but # contains some CR/LF characters, the [list {*}$result] below returns a # copy of $result instead of a zero length string. Not clear exactly why # this is. The following is a workaround. if {[llength $result]==0} { set result "" } } else { error [string trim { wrong # args: should be "do_execsql_test ?-db DB? testname sql ?result?" }] } fix_testname testname |
︙ | ︙ | |||
1169 1170 1171 1172 1173 1174 1175 | output2 "CREATE TABLE IF NOT EXISTS time(version, script, test, us);" foreach {test us} $::speed_trial_times { output2 "INSERT INTO time VALUES('$vers', '$name', '$test', $us);" } } } | | | | | | > > > > > > > > > > > > > > > > > > > > > > > | | > | 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 | output2 "CREATE TABLE IF NOT EXISTS time(version, script, test, us);" foreach {test us} $::speed_trial_times { output2 "INSERT INTO time VALUES('$vers', '$name', '$test', $us);" } } } # Clear out left-over configuration setup from the end of a test # proc finish_test_precleanup {} { catch {db1 close} catch {db2 close} catch {db3 close} catch {unregister_devsim} catch {unregister_jt_vfs} catch {unregister_demovfs} } # Run this routine last # proc finish_test {} { global argv finish_test_precleanup if {[llength $argv]>0} { # If additional test scripts are specified on the command-line, # run them also, before quitting. proc finish_test {} { finish_test_precleanup return } foreach extra $argv { puts "Running \"$extra\"" db_delete_and_reopen uplevel #0 source $extra } } catch {db close} if {0==[info exists ::SLAVE]} { finalize_testing } } proc finalize_testing {} { global sqlite_open_file_count set omitList [set_test_counter omit_list] catch {db close} catch {db2 close} catch {db3 close} vfs_unlink_test sqlite3 db {} # sqlite3_clear_tsd_memdebug db close sqlite3_reset_auto_extension sqlite3_soft_heap_limit64 0 sqlite3_hard_heap_limit64 0 set nTest [incr_ntest] set nErr [set_test_counter errors] set nKnown 0 if {[file readable known-problems.txt]} { set fd [open known-problems.txt] set content [read $fd] |
︙ | ︙ | |||
1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 | sqlite3_memdebug_log stop sqlite3_memdebug_log clear if {[sqlite3_memory_used]>0} { output2 "Writing leaks.tcl..." sqlite3_memdebug_log sync memdebug_log_sql leaks.tcl } } foreach f [glob -nocomplain test.db-*-journal] { forcedelete $f } foreach f [glob -nocomplain test.db-mj*] { forcedelete $f } exit [expr {$nErr>0}] } # Display memory statistics for analysis and debugging purposes. # proc show_memstats {} { set x [sqlite3_status SQLITE_STATUS_MEMORY_USED 0] set y [sqlite3_status SQLITE_STATUS_MALLOC_SIZE 0] set val [format {now %10d max %10d max-size %10d} \ | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | sqlite3_memdebug_log stop sqlite3_memdebug_log clear if {[sqlite3_memory_used]>0} { output2 "Writing leaks.tcl..." sqlite3_memdebug_log sync memdebug_log_sql leaks.tcl } } if {[info commands vdbe_coverage]!=""} { vdbe_coverage_report } foreach f [glob -nocomplain test.db-*-journal] { forcedelete $f } foreach f [glob -nocomplain test.db-mj*] { forcedelete $f } exit [expr {$nErr>0}] } proc vdbe_coverage_report {} { puts "Writing vdbe coverage report to vdbe_coverage.txt" set lSrc [list] set iLine 0 if {[file exists ../sqlite3.c]} { set fd [open ../sqlite3.c] set iLine while { ![eof $fd] } { set line [gets $fd] incr iLine if {[regexp {^/\** Begin file (.*\.c) \**/} $line -> file]} { lappend lSrc [list $iLine $file] } } close $fd } set fd [open vdbe_coverage.txt w] foreach miss [vdbe_coverage report] { foreach {line branch never} $miss {} set nextfile "" while {[llength $lSrc]>0 && [lindex $lSrc 0 0] < $line} { set nextfile [lindex $lSrc 0 1] set lSrc [lrange $lSrc 1 end] } if {$nextfile != ""} { puts $fd "" puts $fd "### $nextfile ###" } puts $fd "Vdbe branch $line: never $never (path $branch)" } close $fd } # Display memory statistics for analysis and debugging purposes. # proc show_memstats {} { set x [sqlite3_status SQLITE_STATUS_MEMORY_USED 0] set y [sqlite3_status SQLITE_STATUS_MALLOC_SIZE 0] set val [format {now %10d max %10d max-size %10d} \ |
︙ | ︙ | |||
1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 | # $crashfile gets compared to the native filename in # cfSync(), which can be different then what TCL uses by # default, so here we force it to the "nativename" format. set cfile [string map {\\ \\\\} [file nativename [file join [get_pwd] $crashfile]]] set f [open crash.tcl w] puts $f "sqlite3_crash_enable 1 $dfltvfs" puts $f "sqlite3_crashparams $blocksize $dc $crashdelay $cfile" puts $f "sqlite3_test_control_pending_byte $::sqlite_pending_byte" # This block sets the cache size of the main database to 10 # pages. This is done in case the build is configured to omit # "PRAGMA cache_size". if {$opendb!=""} { puts $f $opendb puts $f {db eval {SELECT * FROM sqlite_master;}} | > > > | 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 | # $crashfile gets compared to the native filename in # cfSync(), which can be different then what TCL uses by # default, so here we force it to the "nativename" format. set cfile [string map {\\ \\\\} [file nativename [file join [get_pwd] $crashfile]]] set f [open crash.tcl w] puts $f "sqlite3_initialize ; sqlite3_shutdown" puts $f "catch { install_malloc_faultsim 1 }" puts $f "sqlite3_crash_enable 1 $dfltvfs" puts $f "sqlite3_crashparams $blocksize $dc $crashdelay $cfile" puts $f "sqlite3_test_control_pending_byte $::sqlite_pending_byte" puts $f "autoinstall_test_functions" # This block sets the cache size of the main database to 10 # pages. This is done in case the build is configured to omit # "PRAGMA cache_size". if {$opendb!=""} { puts $f $opendb puts $f {db eval {SELECT * FROM sqlite_master;}} |
︙ | ︙ | |||
1657 1658 1659 1660 1661 1662 1663 | if {[string length $sql]>0} { puts $f "db eval {" puts $f "$sql" puts $f "}" } close $f set r [catch { | | > > > | 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 | if {[string length $sql]>0} { puts $f "db eval {" puts $f "$sql" puts $f "}" } close $f set r [catch { exec [info nameofexec] crash.tcl >@stdout 2>@stdout } msg] # Windows/ActiveState TCL returns a slightly different # error message. We map that to the expected message # so that we don't have to change all of the test # cases. if {$::tcl_platform(platform)=="windows"} { if {$msg=="child killed: unknown signal"} { set msg "child process exited abnormally" } } if {$r && [string match {*ERROR: LeakSanitizer*} $msg]} { set msg "child process exited abnormally" } lappend r $msg } # crash_on_write ?-devchar DEVCHAR? CRASHDELAY SQL # |
︙ | ︙ | |||
1830 1831 1832 1833 1834 1835 1836 | # at least N IO operations performed by SQLite as a result of # the script, the Nth will fail. do_test $testname.$n.3 { set ::sqlite_io_error_hit 0 set ::sqlite_io_error_hardhit 0 set r [catch $::ioerrorbody msg] set ::errseen $r | > | | | | | | | | | | | | | | | > | 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 | # at least N IO operations performed by SQLite as a result of # the script, the Nth will fail. do_test $testname.$n.3 { set ::sqlite_io_error_hit 0 set ::sqlite_io_error_hardhit 0 set r [catch $::ioerrorbody msg] set ::errseen $r if {[info commands db]!=""} { set rc [sqlite3_errcode db] if {$::ioerropts(-erc)} { # If we are in extended result code mode, make sure all of the # IOERRs we get back really do have their extended code values. # If an extended result code is returned, the sqlite3_errcode # TCLcommand will return a string of the form: SQLITE_IOERR+nnnn # where nnnn is a number if {[regexp {^SQLITE_IOERR} $rc] && ![regexp {IOERR\+\d} $rc]} { return $rc } } else { # If we are not in extended result code mode, make sure no # extended error codes are returned. if {[regexp {\+\d} $rc]} { return $rc } } } # The test repeats as long as $::go is non-zero. $::go starts out # as 1. When a test runs to completion without hitting an I/O # error, that means there is no point in continuing with this test # case so set $::go to zero. # |
︙ | ︙ | |||
2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 | foreach f $lStack { set frames($f) 1 } } set tbl2 "CREATE TABLE ${database}.frame(frame INTEGER PRIMARY KEY, line);\n" set tbl3 "CREATE TABLE ${database}.file(name PRIMARY KEY, content);\n" foreach f [array names frames] { set addr [format %x $f] | > > | | 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 | foreach f $lStack { set frames($f) 1 } } set tbl2 "CREATE TABLE ${database}.frame(frame INTEGER PRIMARY KEY, line);\n" set tbl3 "CREATE TABLE ${database}.file(name PRIMARY KEY, content);\n" set pid [pid] foreach f [array names frames] { set addr [format %x $f] set cmd "eu-addr2line --pid=$pid $addr" set line [eval exec $cmd] append sql "INSERT INTO ${database}.frame VALUES($f, '$line');\n" set file [lindex [split $line :] 0] set files($file) 1 } |
︙ | ︙ | |||
2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 | set sqlite_fts3_enable_parentheses 0 # During testing, assume that all database files are well-formed. The # few test cases that deliberately corrupt database files should rescind # this setting by invoking "database_can_be_corrupt" # database_never_corrupt source $testdir/thread_common.tcl source $testdir/malloc_common.tcl | > > > | 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 | set sqlite_fts3_enable_parentheses 0 # During testing, assume that all database files are well-formed. The # few test cases that deliberately corrupt database files should rescind # this setting by invoking "database_can_be_corrupt" # database_never_corrupt extra_schema_checks 1 source $testdir/thread_common.tcl source $testdir/malloc_common.tcl set tester_tcl_has_run 1 |
Changes to test/threadtest3.c.
︙ | ︙ | |||
28 29 30 31 32 33 34 35 36 | ** ./a.out walthread3 -- Run the "walthread3" test ** ./a.out 'wal*' -- Run all of the wal* tests ** ./a.out --help -- List all available tests ** ** The exit status is non-zero if any test fails. */ | > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | ** ./a.out walthread3 -- Run the "walthread3" test ** ./a.out 'wal*' -- Run all of the wal* tests ** ./a.out --help -- List all available tests ** ** The exit status is non-zero if any test fails. */ /* ** The "Set Error Line" macro. */ #define SEL(e) ((e)->iLine = ((e)->rc ? (e)->iLine : __LINE__)) /* Database functions */ #define opendb(w,x,y,z) (SEL(w), opendb_x(w,x,y,z)) #define closedb(y,z) (SEL(y), closedb_x(y,z)) /* Functions to execute SQL */ #define sql_script(x,y,z) (SEL(x), sql_script_x(x,y,z)) #define integrity_check(x,y) (SEL(x), integrity_check_x(x,y)) #define execsql_i64(x,y,...) (SEL(x), execsql_i64_x(x,y,__VA_ARGS__)) #define execsql_text(x,y,z,...) (SEL(x), execsql_text_x(x,y,z,__VA_ARGS__)) #define execsql(x,y,...) (SEL(x), (void)execsql_i64_x(x,y,__VA_ARGS__)) #define sql_script_printf(x,y,z,...) ( \ SEL(x), sql_script_printf_x(x,y,z,__VA_ARGS__) \ ) /* Thread functions */ #define launch_thread(w,x,y,z) (SEL(w), launch_thread_x(w,x,y,z)) #define join_all_threads(y,z) (SEL(y), join_all_threads_x(y,z)) /* Timer functions */ #define setstoptime(y,z) (SEL(y), setstoptime_x(y,z)) #define timetostop(z) (SEL(z), timetostop_x(z)) /* Report/clear errors. */ #define test_error(z, ...) test_error_x(z, sqlite3_mprintf(__VA_ARGS__)) #define clear_error(y,z) clear_error_x(y, z) /* File-system operations */ #define filesize(y,z) (SEL(y), filesize_x(y,z)) #define filecopy(x,y,z) (SEL(x), filecopy_x(x,y,z)) #define PTR2INT(x) ((int)((intptr_t)x)) #define INT2PTR(x) ((void*)((intptr_t)x)) /* ** End of test code/infrastructure interface macros. *************************************************************************/ #include <sqlite3.h> #ifdef _WIN32 # include <stdio.h> # include <string.h> # include <assert.h> # include <process.h> # include <windows.h> # include <sys/types.h> # include <sys/stat.h> # include <errno.h> # include <fcntl.h> # include <io.h> #else # include <unistd.h> # include <stdio.h> # include <pthread.h> # include <assert.h> # include <sys/types.h> # include <sys/stat.h> # include <string.h> # include <fcntl.h> # include <errno.h> # define O_BINARY 0 #endif #include "test_multiplex.h" /* Required to link test_multiplex.c */ #ifndef SQLITE_OMIT_WSD int sqlite3PendingByte = 0x40000000; #endif /* * This code implements the MD5 message-digest algorithm. * The algorithm is due to Ron Rivest. This code was * written by Colin Plumb in 1993, no copyright is claimed. * This code is in the public domain; do with it what you wish. * * Equivalent code is available from RSA Data Security, Inc. * This code has been tested against that, and is equivalent, * except that you don't need to include two pages of legalese * with every copy. * * To compute the message digest of a chunk of bytes, declare an * MD5Context structure, pass it to MD5Init, call MD5Update as * needed on buffers full of bytes, and then call MD5Final, which * will fill a supplied 16-byte array with the digest. */ /* * If compiled on a machine that doesn't have a 32-bit integer, * you just set "uint32" to the appropriate datatype for an * unsigned 32-bit integer. For example: * * cc -Duint32='unsigned long' md5.c * */ #ifndef uint32 # define uint32 unsigned int #endif struct MD5Context { int isInit; uint32 buf[4]; uint32 bits[2]; union { unsigned char in[64]; uint32 in32[16]; } u; }; typedef struct MD5Context MD5Context; /* * Note: this code is harmless on little-endian machines. */ static void byteReverse (unsigned char *buf, unsigned longs){ uint32 t; do { t = (uint32)((unsigned)buf[3]<<8 | buf[2]) << 16 | ((unsigned)buf[1]<<8 | buf[0]); *(uint32 *)buf = t; buf += 4; } while (--longs); } /* The four core functions - F1 is optimized somewhat */ /* #define F1(x, y, z) (x & y | ~x & z) */ #define F1(x, y, z) (z ^ (x & (y ^ z))) #define F2(x, y, z) F1(z, x, y) #define F3(x, y, z) (x ^ y ^ z) #define F4(x, y, z) (y ^ (x | ~z)) /* This is the central step in the MD5 algorithm. */ #define MD5STEP(f, w, x, y, z, data, s) \ ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x ) /* * The core of the MD5 algorithm, this alters an existing MD5 hash to * reflect the addition of 16 longwords of new data. MD5Update blocks * the data and converts bytes into longwords for this routine. */ static void MD5Transform(uint32 buf[4], const uint32 in[16]){ register uint32 a, b, c, d; a = buf[0]; b = buf[1]; c = buf[2]; d = buf[3]; MD5STEP(F1, a, b, c, d, in[ 0]+0xd76aa478, 7); MD5STEP(F1, d, a, b, c, in[ 1]+0xe8c7b756, 12); MD5STEP(F1, c, d, a, b, in[ 2]+0x242070db, 17); MD5STEP(F1, b, c, d, a, in[ 3]+0xc1bdceee, 22); MD5STEP(F1, a, b, c, d, in[ 4]+0xf57c0faf, 7); MD5STEP(F1, d, a, b, c, in[ 5]+0x4787c62a, 12); MD5STEP(F1, c, d, a, b, in[ 6]+0xa8304613, 17); MD5STEP(F1, b, c, d, a, in[ 7]+0xfd469501, 22); MD5STEP(F1, a, b, c, d, in[ 8]+0x698098d8, 7); MD5STEP(F1, d, a, b, c, in[ 9]+0x8b44f7af, 12); MD5STEP(F1, c, d, a, b, in[10]+0xffff5bb1, 17); MD5STEP(F1, b, c, d, a, in[11]+0x895cd7be, 22); MD5STEP(F1, a, b, c, d, in[12]+0x6b901122, 7); MD5STEP(F1, d, a, b, c, in[13]+0xfd987193, 12); MD5STEP(F1, c, d, a, b, in[14]+0xa679438e, 17); MD5STEP(F1, b, c, d, a, in[15]+0x49b40821, 22); MD5STEP(F2, a, b, c, d, in[ 1]+0xf61e2562, 5); MD5STEP(F2, d, a, b, c, in[ 6]+0xc040b340, 9); MD5STEP(F2, c, d, a, b, in[11]+0x265e5a51, 14); MD5STEP(F2, b, c, d, a, in[ 0]+0xe9b6c7aa, 20); MD5STEP(F2, a, b, c, d, in[ 5]+0xd62f105d, 5); MD5STEP(F2, d, a, b, c, in[10]+0x02441453, 9); MD5STEP(F2, c, d, a, b, in[15]+0xd8a1e681, 14); MD5STEP(F2, b, c, d, a, in[ 4]+0xe7d3fbc8, 20); MD5STEP(F2, a, b, c, d, in[ 9]+0x21e1cde6, 5); MD5STEP(F2, d, a, b, c, in[14]+0xc33707d6, 9); MD5STEP(F2, c, d, a, b, in[ 3]+0xf4d50d87, 14); MD5STEP(F2, b, c, d, a, in[ 8]+0x455a14ed, 20); MD5STEP(F2, a, b, c, d, in[13]+0xa9e3e905, 5); MD5STEP(F2, d, a, b, c, in[ 2]+0xfcefa3f8, 9); MD5STEP(F2, c, d, a, b, in[ 7]+0x676f02d9, 14); MD5STEP(F2, b, c, d, a, in[12]+0x8d2a4c8a, 20); MD5STEP(F3, a, b, c, d, in[ 5]+0xfffa3942, 4); MD5STEP(F3, d, a, b, c, in[ 8]+0x8771f681, 11); MD5STEP(F3, c, d, a, b, in[11]+0x6d9d6122, 16); MD5STEP(F3, b, c, d, a, in[14]+0xfde5380c, 23); MD5STEP(F3, a, b, c, d, in[ 1]+0xa4beea44, 4); MD5STEP(F3, d, a, b, c, in[ 4]+0x4bdecfa9, 11); MD5STEP(F3, c, d, a, b, in[ 7]+0xf6bb4b60, 16); MD5STEP(F3, b, c, d, a, in[10]+0xbebfbc70, 23); MD5STEP(F3, a, b, c, d, in[13]+0x289b7ec6, 4); MD5STEP(F3, d, a, b, c, in[ 0]+0xeaa127fa, 11); MD5STEP(F3, c, d, a, b, in[ 3]+0xd4ef3085, 16); MD5STEP(F3, b, c, d, a, in[ 6]+0x04881d05, 23); MD5STEP(F3, a, b, c, d, in[ 9]+0xd9d4d039, 4); MD5STEP(F3, d, a, b, c, in[12]+0xe6db99e5, 11); MD5STEP(F3, c, d, a, b, in[15]+0x1fa27cf8, 16); MD5STEP(F3, b, c, d, a, in[ 2]+0xc4ac5665, 23); MD5STEP(F4, a, b, c, d, in[ 0]+0xf4292244, 6); MD5STEP(F4, d, a, b, c, in[ 7]+0x432aff97, 10); MD5STEP(F4, c, d, a, b, in[14]+0xab9423a7, 15); MD5STEP(F4, b, c, d, a, in[ 5]+0xfc93a039, 21); MD5STEP(F4, a, b, c, d, in[12]+0x655b59c3, 6); MD5STEP(F4, d, a, b, c, in[ 3]+0x8f0ccc92, 10); MD5STEP(F4, c, d, a, b, in[10]+0xffeff47d, 15); MD5STEP(F4, b, c, d, a, in[ 1]+0x85845dd1, 21); MD5STEP(F4, a, b, c, d, in[ 8]+0x6fa87e4f, 6); MD5STEP(F4, d, a, b, c, in[15]+0xfe2ce6e0, 10); MD5STEP(F4, c, d, a, b, in[ 6]+0xa3014314, 15); MD5STEP(F4, b, c, d, a, in[13]+0x4e0811a1, 21); MD5STEP(F4, a, b, c, d, in[ 4]+0xf7537e82, 6); MD5STEP(F4, d, a, b, c, in[11]+0xbd3af235, 10); MD5STEP(F4, c, d, a, b, in[ 2]+0x2ad7d2bb, 15); MD5STEP(F4, b, c, d, a, in[ 9]+0xeb86d391, 21); buf[0] += a; buf[1] += b; buf[2] += c; buf[3] += d; } /* * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious * initialization constants. */ static void MD5Init(MD5Context *ctx){ ctx->isInit = 1; ctx->buf[0] = 0x67452301; ctx->buf[1] = 0xefcdab89; ctx->buf[2] = 0x98badcfe; ctx->buf[3] = 0x10325476; ctx->bits[0] = 0; ctx->bits[1] = 0; } /* * Update context to reflect the concatenation of another buffer full * of bytes. */ static void MD5Update(MD5Context *ctx, const unsigned char *buf, unsigned int len){ uint32 t; /* Update bitcount */ t = ctx->bits[0]; if ((ctx->bits[0] = t + ((uint32)len << 3)) < t) ctx->bits[1]++; /* Carry from low to high */ ctx->bits[1] += len >> 29; t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ /* Handle any leading odd-sized chunks */ if ( t ) { unsigned char *p = (unsigned char *)ctx->u.in + t; t = 64-t; if (len < t) { memcpy(p, buf, len); return; } memcpy(p, buf, t); byteReverse(ctx->u.in, 16); MD5Transform(ctx->buf, (uint32 *)ctx->u.in); buf += t; len -= t; } /* Process data in 64-byte chunks */ while (len >= 64) { memcpy(ctx->u.in, buf, 64); byteReverse(ctx->u.in, 16); MD5Transform(ctx->buf, (uint32 *)ctx->u.in); buf += 64; len -= 64; } /* Handle any remaining bytes of data. */ memcpy(ctx->u.in, buf, len); } /* * Final wrapup - pad to 64-byte boundary with the bit pattern * 1 0* (64-bit count of bits processed, MSB-first) */ static void MD5Final(unsigned char digest[16], MD5Context *ctx){ unsigned count; unsigned char *p; /* Compute number of bytes mod 64 */ count = (ctx->bits[0] >> 3) & 0x3F; /* Set the first char of padding to 0x80. This is safe since there is always at least one byte free */ p = ctx->u.in + count; *p++ = 0x80; /* Bytes of padding needed to make 64 bytes */ count = 64 - 1 - count; /* Pad out to 56 mod 64 */ if (count < 8) { /* Two lots of padding: Pad the first block to 64 bytes */ memset(p, 0, count); byteReverse(ctx->u.in, 16); MD5Transform(ctx->buf, (uint32 *)ctx->u.in); /* Now fill the next block with 56 bytes */ memset(ctx->u.in, 0, 56); } else { /* Pad block to 56 bytes */ memset(p, 0, count-8); } byteReverse(ctx->u.in, 14); /* Append length in bits and transform */ ctx->u.in32[14] = ctx->bits[0]; ctx->u.in32[15] = ctx->bits[1]; MD5Transform(ctx->buf, (uint32 *)ctx->u.in); byteReverse((unsigned char *)ctx->buf, 4); memcpy(digest, ctx->buf, 16); memset(ctx, 0, sizeof(*ctx)); /* In case it is sensitive */ } /* ** Convert a 128-bit MD5 digest into a 32-digit base-16 number. */ static void MD5DigestToBase16(unsigned char *digest, char *zBuf){ static char const zEncode[] = "0123456789abcdef"; int i, j; for(j=i=0; i<16; i++){ int a = digest[i]; zBuf[j++] = zEncode[(a>>4)&0xf]; zBuf[j++] = zEncode[a & 0xf]; } zBuf[j] = 0; } /* ** During testing, the special md5sum() aggregate function is available. ** inside SQLite. The following routines implement that function. */ static void md5step(sqlite3_context *context, int argc, sqlite3_value **argv){ MD5Context *p; int i; if( argc<1 ) return; p = sqlite3_aggregate_context(context, sizeof(*p)); if( p==0 ) return; if( !p->isInit ){ MD5Init(p); } for(i=0; i<argc; i++){ const char *zData = (char*)sqlite3_value_text(argv[i]); if( zData ){ MD5Update(p, (unsigned char*)zData, strlen(zData)); } } } static void md5finalize(sqlite3_context *context){ MD5Context *p; unsigned char digest[16]; char zBuf[33]; p = sqlite3_aggregate_context(context, sizeof(*p)); MD5Final(digest,p); MD5DigestToBase16(digest, zBuf); sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT); } /* ** End of copied md5sum() code. **************************************************************************/ typedef sqlite3_int64 i64; typedef struct Error Error; typedef struct Sqlite Sqlite; typedef struct Statement Statement; typedef struct Threadset Threadset; typedef struct Thread Thread; /* Total number of errors in this process so far. */ static int nGlobalErr = 0; struct Error { int rc; int iLine; char *zErr; }; struct Sqlite { sqlite3 *db; /* Database handle */ Statement *pCache; /* Linked list of cached statements */ int nText; /* Size of array at aText[] */ char **aText; /* Stored text results */ }; struct Statement { sqlite3_stmt *pStmt; /* Pre-compiled statement handle */ Statement *pNext; /* Next statement in linked-list */ }; struct Thread { int iTid; /* Thread number within test */ void* pArg; /* Pointer argument passed by caller */ #ifdef _WIN32 uintptr_t winTid; /* Thread handle */ #else pthread_t tid; /* Thread id */ #endif char *(*xProc)(int, void*); /* Thread main proc */ char *zRes; /* Value returned by xProc */ Thread *pNext; /* Next in this list of threads */ }; struct Threadset { int iMaxTid; /* Largest iTid value allocated so far */ Thread *pThread; /* Linked list of threads */ }; static void free_err(Error *p){ sqlite3_free(p->zErr); p->zErr = 0; p->rc = 0; } static void print_err(Error *p){ if( p->rc!=SQLITE_OK ){ int isWarn = 0; if( p->rc==SQLITE_SCHEMA ) isWarn = 1; if( sqlite3_strglob("* - no such table: *",p->zErr)==0 ) isWarn = 1; printf("%s: (%d) \"%s\" at line %d\n", isWarn ? "Warning" : "Error", p->rc, p->zErr, p->iLine); if( !isWarn ) nGlobalErr++; fflush(stdout); } } static void print_and_free_err(Error *p){ print_err(p); free_err(p); } static void system_error(Error *pErr, int iSys){ pErr->rc = iSys; #if _WIN32 pErr->zErr = sqlite3_mprintf("%s", strerror(iSys)); #else pErr->zErr = (char *)sqlite3_malloc(512); strerror_r(iSys, pErr->zErr, 512); pErr->zErr[511] = '\0'; #endif } static void sqlite_error( Error *pErr, Sqlite *pDb, const char *zFunc ){ pErr->rc = sqlite3_errcode(pDb->db); pErr->zErr = sqlite3_mprintf( "sqlite3_%s() - %s (%d)", zFunc, sqlite3_errmsg(pDb->db), sqlite3_extended_errcode(pDb->db) ); } static void test_error_x( Error *pErr, char *zErr ){ if( pErr->rc==SQLITE_OK ){ pErr->rc = 1; pErr->zErr = zErr; }else{ sqlite3_free(zErr); } } static void clear_error_x( Error *pErr, int rc ){ if( pErr->rc==rc ){ pErr->rc = SQLITE_OK; sqlite3_free(pErr->zErr); pErr->zErr = 0; } } static int busyhandler(void *pArg, int n){ sqlite3_sleep(10); return 1; } static void opendb_x( Error *pErr, /* IN/OUT: Error code */ Sqlite *pDb, /* OUT: Database handle */ const char *zFile, /* Database file name */ int bDelete /* True to delete db file before opening */ ){ if( pErr->rc==SQLITE_OK ){ int rc; int flags = SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE | SQLITE_OPEN_URI; if( bDelete ) unlink(zFile); rc = sqlite3_open_v2(zFile, &pDb->db, flags, 0); if( rc ){ sqlite_error(pErr, pDb, "open"); sqlite3_close(pDb->db); pDb->db = 0; }else{ sqlite3_create_function( pDb->db, "md5sum", -1, SQLITE_UTF8, 0, 0, md5step, md5finalize ); sqlite3_busy_handler(pDb->db, busyhandler, 0); sqlite3_exec(pDb->db, "PRAGMA synchronous=OFF", 0, 0, 0); } } } static void closedb_x( Error *pErr, /* IN/OUT: Error code */ Sqlite *pDb /* OUT: Database handle */ ){ int rc; int i; Statement *pIter; Statement *pNext; for(pIter=pDb->pCache; pIter; pIter=pNext){ pNext = pIter->pNext; sqlite3_finalize(pIter->pStmt); sqlite3_free(pIter); } for(i=0; i<pDb->nText; i++){ sqlite3_free(pDb->aText[i]); } sqlite3_free(pDb->aText); rc = sqlite3_close(pDb->db); if( rc && pErr->rc==SQLITE_OK ){ pErr->zErr = sqlite3_mprintf("%s", sqlite3_errmsg(pDb->db)); } memset(pDb, 0, sizeof(Sqlite)); } static void sql_script_x( Error *pErr, /* IN/OUT: Error code */ Sqlite *pDb, /* Database handle */ const char *zSql /* SQL script to execute */ ){ if( pErr->rc==SQLITE_OK ){ pErr->rc = sqlite3_exec(pDb->db, zSql, 0, 0, &pErr->zErr); } } static void sql_script_printf_x( Error *pErr, /* IN/OUT: Error code */ Sqlite *pDb, /* Database handle */ const char *zFormat, /* SQL printf format string */ ... /* Printf args */ ){ va_list ap; /* ... printf arguments */ va_start(ap, zFormat); if( pErr->rc==SQLITE_OK ){ char *zSql = sqlite3_vmprintf(zFormat, ap); pErr->rc = sqlite3_exec(pDb->db, zSql, 0, 0, &pErr->zErr); sqlite3_free(zSql); } va_end(ap); } static Statement *getSqlStatement( Error *pErr, /* IN/OUT: Error code */ Sqlite *pDb, /* Database handle */ const char *zSql /* SQL statement */ ){ Statement *pRet; int rc; for(pRet=pDb->pCache; pRet; pRet=pRet->pNext){ if( 0==strcmp(sqlite3_sql(pRet->pStmt), zSql) ){ return pRet; } } pRet = sqlite3_malloc(sizeof(Statement)); rc = sqlite3_prepare_v2(pDb->db, zSql, -1, &pRet->pStmt, 0); if( rc!=SQLITE_OK ){ sqlite_error(pErr, pDb, "prepare_v2"); return 0; } assert( 0==strcmp(sqlite3_sql(pRet->pStmt), zSql) ); pRet->pNext = pDb->pCache; pDb->pCache = pRet; return pRet; } static sqlite3_stmt *getAndBindSqlStatement( Error *pErr, /* IN/OUT: Error code */ Sqlite *pDb, /* Database handle */ va_list ap /* SQL followed by parameters */ ){ Statement *pStatement; /* The SQLite statement wrapper */ sqlite3_stmt *pStmt; /* The SQLite statement to return */ int i; /* Used to iterate through parameters */ pStatement = getSqlStatement(pErr, pDb, va_arg(ap, const char *)); if( !pStatement ) return 0; pStmt = pStatement->pStmt; for(i=1; i<=sqlite3_bind_parameter_count(pStmt); i++){ const char *zName = sqlite3_bind_parameter_name(pStmt, i); void * pArg = va_arg(ap, void*); switch( zName[1] ){ case 'i': sqlite3_bind_int64(pStmt, i, *(i64 *)pArg); break; default: pErr->rc = 1; pErr->zErr = sqlite3_mprintf("Cannot discern type: \"%s\"", zName); pStmt = 0; break; } } return pStmt; } static i64 execsql_i64_x( Error *pErr, /* IN/OUT: Error code */ Sqlite *pDb, /* Database handle */ ... /* SQL and pointers to parameter values */ ){ i64 iRet = 0; if( pErr->rc==SQLITE_OK ){ sqlite3_stmt *pStmt; /* SQL statement to execute */ va_list ap; /* ... arguments */ va_start(ap, pDb); pStmt = getAndBindSqlStatement(pErr, pDb, ap); if( pStmt ){ int first = 1; while( SQLITE_ROW==sqlite3_step(pStmt) ){ if( first && sqlite3_column_count(pStmt)>0 ){ iRet = sqlite3_column_int64(pStmt, 0); } first = 0; } if( SQLITE_OK!=sqlite3_reset(pStmt) ){ sqlite_error(pErr, pDb, "reset"); } } va_end(ap); } return iRet; } static char * execsql_text_x( Error *pErr, /* IN/OUT: Error code */ Sqlite *pDb, /* Database handle */ int iSlot, /* Db handle slot to store text in */ ... /* SQL and pointers to parameter values */ ){ char *zRet = 0; if( iSlot>=pDb->nText ){ int nByte = sizeof(char *)*(iSlot+1); pDb->aText = (char **)sqlite3_realloc(pDb->aText, nByte); memset(&pDb->aText[pDb->nText], 0, sizeof(char*)*(iSlot+1-pDb->nText)); pDb->nText = iSlot+1; } if( pErr->rc==SQLITE_OK ){ sqlite3_stmt *pStmt; /* SQL statement to execute */ va_list ap; /* ... arguments */ va_start(ap, iSlot); pStmt = getAndBindSqlStatement(pErr, pDb, ap); if( pStmt ){ int first = 1; while( SQLITE_ROW==sqlite3_step(pStmt) ){ if( first && sqlite3_column_count(pStmt)>0 ){ zRet = sqlite3_mprintf("%s", sqlite3_column_text(pStmt, 0)); sqlite3_free(pDb->aText[iSlot]); pDb->aText[iSlot] = zRet; } first = 0; } if( SQLITE_OK!=sqlite3_reset(pStmt) ){ sqlite_error(pErr, pDb, "reset"); } } va_end(ap); } return zRet; } static void integrity_check_x( Error *pErr, /* IN/OUT: Error code */ Sqlite *pDb /* Database handle */ ){ if( pErr->rc==SQLITE_OK ){ Statement *pStatement; /* Statement to execute */ char *zErr = 0; /* Integrity check error */ pStatement = getSqlStatement(pErr, pDb, "PRAGMA integrity_check"); if( pStatement ){ sqlite3_stmt *pStmt = pStatement->pStmt; while( SQLITE_ROW==sqlite3_step(pStmt) ){ const char *z = (const char*)sqlite3_column_text(pStmt, 0); if( strcmp(z, "ok") ){ if( zErr==0 ){ zErr = sqlite3_mprintf("%s", z); }else{ zErr = sqlite3_mprintf("%z\n%s", zErr, z); } } } sqlite3_reset(pStmt); if( zErr ){ pErr->zErr = zErr; pErr->rc = 1; } } } } #ifdef _WIN32 static unsigned __stdcall launch_thread_main(void *pArg){ Thread *p = (Thread *)pArg; p->zRes = p->xProc(p->iTid, p->pArg); _endthreadex(0); return 0; /* NOT REACHED */ } #else static void *launch_thread_main(void *pArg){ Thread *p = (Thread *)pArg; p->zRes = p->xProc(p->iTid, p->pArg); return 0; } #endif static void launch_thread_x( Error *pErr, /* IN/OUT: Error code */ Threadset *pThreads, /* Thread set */ char *(*xProc)(int, void*), /* Proc to run */ void *pArg /* Argument passed to thread proc */ ){ if( pErr->rc==SQLITE_OK ){ int iTid = ++pThreads->iMaxTid; Thread *p; int rc; p = (Thread *)sqlite3_malloc(sizeof(Thread)); memset(p, 0, sizeof(Thread)); p->iTid = iTid; p->pArg = pArg; p->xProc = xProc; #ifdef _WIN32 rc = SQLITE_OK; p->winTid = _beginthreadex(0, 0, launch_thread_main, (void*)p, 0, 0); if( p->winTid==0 ) rc = errno ? errno : rc; #else rc = pthread_create(&p->tid, NULL, launch_thread_main, (void *)p); #endif if( rc!=0 ){ system_error(pErr, rc); sqlite3_free(p); }else{ p->pNext = pThreads->pThread; pThreads->pThread = p; } } } static void join_all_threads_x( Error *pErr, /* IN/OUT: Error code */ Threadset *pThreads /* Thread set */ ){ Thread *p; Thread *pNext; for(p=pThreads->pThread; p; p=pNext){ #ifndef _WIN32 void *ret; #endif int rc; pNext = p->pNext; #ifdef _WIN32 do { rc = WaitForSingleObjectEx((HANDLE)p->winTid, INFINITE, TRUE); }while( rc==WAIT_IO_COMPLETION ); CloseHandle((HANDLE)p->winTid); #else rc = pthread_join(p->tid, &ret); #endif if( rc!=0 ){ if( pErr->rc==SQLITE_OK ) system_error(pErr, rc); }else{ printf("Thread %d says: %s\n", p->iTid, (p->zRes==0 ? "..." : p->zRes)); fflush(stdout); } sqlite3_free(p->zRes); sqlite3_free(p); } pThreads->pThread = 0; } #ifdef _WIN32 # define THREADTEST3_STAT _stat #else # define THREADTEST3_STAT stat #endif static i64 filesize_x( Error *pErr, const char *zFile ){ i64 iRet = 0; if( pErr->rc==SQLITE_OK ){ struct THREADTEST3_STAT sStat; if( THREADTEST3_STAT(zFile, &sStat) ){ iRet = -1; }else{ iRet = sStat.st_size; } } return iRet; } static void filecopy_x( Error *pErr, const char *zFrom, const char *zTo ){ if( pErr->rc==SQLITE_OK ){ i64 nByte = filesize_x(pErr, zFrom); if( nByte<0 ){ test_error_x(pErr, sqlite3_mprintf("no such file: %s", zFrom)); }else{ i64 iOff; char aBuf[1024]; int fd1; int fd2; unlink(zTo); fd1 = open(zFrom, O_RDONLY|O_BINARY); if( fd1<0 ){ system_error(pErr, errno); return; } fd2 = open(zTo, O_RDWR|O_CREAT|O_EXCL|O_BINARY, 0644); if( fd2<0 ){ system_error(pErr, errno); close(fd1); return; } iOff = 0; while( iOff<nByte ){ int nCopy = sizeof(aBuf); if( nCopy+iOff>nByte ){ nCopy = nByte - iOff; } if( nCopy!=read(fd1, aBuf, nCopy) ){ system_error(pErr, errno); break; } if( nCopy!=write(fd2, aBuf, nCopy) ){ system_error(pErr, errno); break; } iOff += nCopy; } close(fd1); close(fd2); } } } /* ** Used by setstoptime() and timetostop(). */ static double timelimit = 0.0; static double currentTime(void){ double t; static sqlite3_vfs *pTimelimitVfs = 0; if( pTimelimitVfs==0 ) pTimelimitVfs = sqlite3_vfs_find(0); if( pTimelimitVfs->iVersion>=2 && pTimelimitVfs->xCurrentTimeInt64!=0 ){ sqlite3_int64 tm; pTimelimitVfs->xCurrentTimeInt64(pTimelimitVfs, &tm); t = tm/86400000.0; }else{ pTimelimitVfs->xCurrentTime(pTimelimitVfs, &t); } return t; } static void setstoptime_x( Error *pErr, /* IN/OUT: Error code */ int nMs /* Milliseconds until "stop time" */ ){ if( pErr->rc==SQLITE_OK ){ double t = currentTime(); timelimit = t + ((double)nMs)/(1000.0*60.0*60.0*24.0); } } static int timetostop_x( Error *pErr /* IN/OUT: Error code */ ){ int ret = 1; if( pErr->rc==SQLITE_OK ){ double t = currentTime(); ret = (t >= timelimit); } return ret; } /************************************************************************* ************************************************************************** ************************************************************************** ** End infrastructure. Begin tests. */ |
︙ | ︙ | |||
98 99 100 101 102 103 104 | static char *walthread1_ckpt_thread(int iTid, void *pArg){ Error err = {0}; /* Error code and message */ Sqlite db = {0}; /* SQLite database connection */ int nCkpt = 0; /* Checkpoints so far */ opendb(&err, &db, "test.db", 0); while( !timetostop(&err) ){ | | | 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 | static char *walthread1_ckpt_thread(int iTid, void *pArg){ Error err = {0}; /* Error code and message */ Sqlite db = {0}; /* SQLite database connection */ int nCkpt = 0; /* Checkpoints so far */ opendb(&err, &db, "test.db", 0); while( !timetostop(&err) ){ sqlite3_sleep(500); execsql(&err, &db, "PRAGMA wal_checkpoint"); if( err.rc==SQLITE_OK ) nCkpt++; clear_error(&err, SQLITE_BUSY); } closedb(&err, &db); print_and_free_err(&err); |
︙ | ︙ | |||
546 547 548 549 550 551 552 | setstoptime(&err, nMs); sqlite3_enable_shared_cache(1); launch_thread(&err, &threads, dynamic_triggers_2, 0); launch_thread(&err, &threads, dynamic_triggers_2, 0); | | > | 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 | setstoptime(&err, nMs); sqlite3_enable_shared_cache(1); launch_thread(&err, &threads, dynamic_triggers_2, 0); launch_thread(&err, &threads, dynamic_triggers_2, 0); sqlite3_sleep(2*1000); sqlite3_enable_shared_cache(0); launch_thread(&err, &threads, dynamic_triggers_2, 0); launch_thread(&err, &threads, dynamic_triggers_1, 0); join_all_threads(&err, &threads); print_and_free_err(&err); } #include "tt3_checkpoint.c" #include "tt3_index.c" #include "tt3_lookaside1.c" #include "tt3_vacuum.c" #include "tt3_stress.c" #include "tt3_shared.c" int main(int argc, char **argv){ struct ThreadTest { void (*xTest)(int); /* Routine for running this test */ const char *zTest; /* Name of this test */ int nMs; /* How long to run this test, in milliseconds */ } aTest[] = { |
︙ | ︙ | |||
588 589 590 591 592 593 594 595 596 597 598 599 600 601 | { checkpoint_starvation_2, "checkpoint_starvation_2", 10000 }, { create_drop_index_1, "create_drop_index_1", 10000 }, { lookaside1, "lookaside1", 10000 }, { vacuum1, "vacuum1", 10000 }, { stress1, "stress1", 10000 }, { stress2, "stress2", 60000 }, }; static char *substArgv[] = { 0, "*", 0 }; int i, iArg; int nTestfound = 0; sqlite3_config(SQLITE_CONFIG_MULTITHREAD); if( argc<2 ){ | > | 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 | { checkpoint_starvation_2, "checkpoint_starvation_2", 10000 }, { create_drop_index_1, "create_drop_index_1", 10000 }, { lookaside1, "lookaside1", 10000 }, { vacuum1, "vacuum1", 10000 }, { stress1, "stress1", 10000 }, { stress2, "stress2", 60000 }, { shared1, "shared1", 10000 }, }; static char *substArgv[] = { 0, "*", 0 }; int i, iArg; int nTestfound = 0; sqlite3_config(SQLITE_CONFIG_MULTITHREAD); if( argc<2 ){ |
︙ | ︙ |
Added test/threadtest5.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 | /* ** 2021-05-12 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** ** Testing threading behavior when multiple database connections in separate ** threads of the same process are all talking to the same database file. ** ** For best results, ensure that SQLite is compiled with HAVE_USLEEP=1 ** ** Only works on unix platforms. ** ** Usage: ** ** ./threadtest5 ?DATABASE? ** ** If DATABASE is omitted, it defaults to using file:/mem?vfs=memdb. */ #include "sqlite3.h" #include <pthread.h> #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <string.h> #include <stdarg.h> /* Name of the in-memory database */ static char *zDbName = 0; /* True for debugging */ static int eVerbose = 0; /* If rc is not SQLITE_OK, then print an error message and stop ** the test. */ static void error_out(int rc, const char *zCtx, int lineno){ if( rc!=SQLITE_OK ){ fprintf(stderr, "error %d at %d in \"%s\"\n", rc, lineno, zCtx); exit(-1); } } #if 0 /* Return the number of milliseconds since the Julian epoch (-4714-11-24). */ static sqlite3_int64 gettime(void){ sqlite3_int64 tm; sqlite3_vfs *pVfs = sqlite3_vfs_find(0); pVfs->xCurrentTimeInt64(pVfs, &tm); return tm; } #endif /* Run the SQL in the second argument. */ static int exec( sqlite3 *db, const char *zId, int lineno, const char *zFormat, ... ){ int rc; va_list ap; char *zSql; va_start(ap, zFormat); zSql = sqlite3_vmprintf(zFormat, ap); va_end(ap); if( eVerbose){ printf("%s:%d: [%s]\n", zId, lineno, zSql); fflush(stdout); } rc = sqlite3_exec(db, zSql, 0, 0, 0); if( rc && eVerbose ){ printf("%s:%d: return-code %d\n", zId, lineno, rc); fflush(stdout); } sqlite3_free(zSql); return rc; } /* Generate a perpared statement from the input SQL */ static sqlite3_stmt *prepare( sqlite3 *db, const char *zId, int lineno, const char *zFormat, ... ){ int rc; va_list ap; char *zSql; sqlite3_stmt *pStmt = 0; va_start(ap, zFormat); zSql = sqlite3_vmprintf(zFormat, ap); va_end(ap); if( eVerbose){ printf("%s:%d: [%s]\n", zId, lineno, zSql); fflush(stdout); } rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0); if( rc ){ printf("%s:%d: ERROR - %s\n", zId, lineno, sqlite3_errmsg(db)); exit(-1); } sqlite3_free(zSql); return pStmt; } /* ** Wait for table zTable to exist in the schema. */ static void waitOnTable(sqlite3 *db, const char *zWorker, const char *zTable){ while(1){ int eFound = 0; sqlite3_stmt *q = prepare(db, zWorker, __LINE__, "SELECT 1 FROM sqlite_schema WHERE name=%Q", zTable); if( sqlite3_step(q)==SQLITE_ROW && sqlite3_column_int(q,0)!=0 ){ eFound = 1; } sqlite3_finalize(q); if( eFound ) return; sqlite3_sleep(1); } } /* ** Return true if x is a prime number */ static int isPrime(int x){ int i; if( x<2 ) return 1; for(i=2; i*i<=x; i++){ if( (x%i)==0 ) return 0; } return 1; } /* Each worker thread runs an instance of the following */ static void *worker(void *pArg){ int rc; const char *zName = (const char*)pArg; sqlite3 *db = 0; if( eVerbose ){ printf("%s: startup\n", zName); fflush(stdout); } rc = sqlite3_open(zDbName, &db); error_out(rc, "sqlite3_open", __LINE__); sqlite3_busy_timeout(db, 2000); while( 1 ){ sqlite3_stmt *q1; int tid = -1; q1 = prepare(db, zName, __LINE__, "UPDATE task SET doneby=%Q" " WHERE tid=(SELECT tid FROM task WHERE doneby IS NULL LIMIT 1)" "RETURNING tid", zName ); if( sqlite3_step(q1)==SQLITE_ROW ){ tid = sqlite3_column_int(q1,0); } sqlite3_finalize(q1); if( tid<0 ) break; if( eVerbose ){ printf("%s: starting task %d\n", zName, tid); fflush(stdout); } if( tid==1 ){ exec(db, zName, __LINE__, "CREATE TABLE IF NOT EXISTS p1(x INTEGER PRIMARY KEY);" ); }else if( tid>=2 && tid<=51 ){ int a, b, i; waitOnTable(db, zName, "p1"); a = (tid-2)*200 + 1; b = a+200; for(i=a; i<b; i++){ if( isPrime(i) ){ exec(db, zName, __LINE__, "INSERT INTO p1(x) VALUES(%d)", i); } } }else if( tid==52 ){ exec(db, zName, __LINE__, "CREATE TABLE IF NOT EXISTS p2(x INTEGER PRIMARY KEY);" "WITH RECURSIVE" " c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<10000)" "INSERT INTO p2(x) SELECT x FROM c;" ); }else if( tid>=53 && tid<=62 ){ int a, b, i; waitOnTable(db, zName, "p2"); a = (tid-53)*10 + 2; b = a+9; for(i=a; i<=b; i++){ exec(db, zName, __LINE__, "DELETE FROM p2 WHERE x>%d AND (x %% %d)==0", i, i); } } if( eVerbose ){ printf("%s: completed task %d\n", zName, tid); fflush(stdout); } sqlite3_sleep(1); } sqlite3_close(db); if( eVerbose ){ printf("%s: exit\n", zName); fflush(stdout); } return 0; } /* Print a usage comment and die */ static void usage(const char *argv0){ printf("Usage: %s [options]\n", argv0); printf( " -num-workers N Run N worker threads\n" " -v Debugging output\n" ); exit(1); } /* Maximum number of threads */ #define MX_WORKER 100 /* ** Main routine */ int main(int argc, char **argv){ int i; int nWorker = 4; int rc; sqlite3 *db = 0; sqlite3_stmt *q; pthread_t aWorker[MX_WORKER]; char aWorkerName[MX_WORKER][8]; for(i=1; i<argc; i++){ const char *zArg = argv[i]; if( zArg[0]!='-' ){ if( zDbName==0 ){ zDbName = argv[i]; continue; } printf("unknown argument: %s\n", zArg); usage(argv[0]); } if( zArg[1]=='-' ) zArg++; if( strcmp(zArg, "-v")==0 ){ eVerbose = 1; continue; } if( strcmp(zArg, "-num-workers")==0 && i+1<argc ){ nWorker = atoi(argv[++i]); if( nWorker<1 || nWorker>MX_WORKER ){ printf("number of threads must be between 1 and %d\n", MX_WORKER); exit(1); } continue; } printf("unknown option: %s\n", argv[i]); usage(argv[0]); } if( zDbName==0 ) zDbName = "file:/mem?vfs=memdb"; sqlite3_config(SQLITE_CONFIG_URI, (int)1); rc = sqlite3_open(zDbName, &db); error_out(rc, "sqlite3_open", __LINE__); rc = exec(db, "SETUP", __LINE__, "DROP TABLE IF EXISTS task;\n" "DROP TABLE IF EXISTS p1;\n" "DROP TABLE IF EXISTS p2;\n" "DROP TABLE IF EXISTS verify;\n" "CREATE TABLE IF NOT EXISTS task(\n" " tid INTEGER PRIMARY KEY,\n" " doneby TEXT\n" ");\n" "WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<100)" "INSERT INTO task(tid) SELECT x FROM c;\n" ); error_out(rc, "sqlite3_exec", __LINE__); for(i=0; i<nWorker; i++){ sqlite3_snprintf(sizeof(aWorkerName[i]), aWorkerName[i], "W%02d", i); pthread_create(&aWorker[i], 0, worker, aWorkerName[i]); } for(i=0; i<nWorker; i++){ pthread_join(aWorker[i], 0); } for(i=0; i<nWorker; i++){ q = prepare(db, "MAIN", __LINE__, "SELECT group_concat(tid,',') FROM task WHERE doneby=%Q", aWorkerName[i]); if( sqlite3_step(q)==SQLITE_ROW ){ printf("%s: %s\n", aWorkerName[i], sqlite3_column_text(q,0)); } sqlite3_finalize(q); } q = prepare(db, "MAIN", __LINE__, "SELECT count(*) FROM p2"); if( sqlite3_step(q)!=SQLITE_ROW || sqlite3_column_int(q,0)<10 ){ printf("incorrect result\n"); exit(-1); } sqlite3_finalize(q); q = prepare(db, "MAIN", __LINE__, "SELECT x FROM p1 EXCEPT SELECT x FROM p2"); if( sqlite3_step(q)==SQLITE_ROW ){ printf("incorrect result\n"); exit(-1); } sqlite3_finalize(q); q = prepare(db, "MAIN", __LINE__, "SELECT x FROM p2 EXCEPT SELECT x FROM p1"); if( sqlite3_step(q)==SQLITE_ROW ){ printf("incorrect result\n"); exit(-1); } sqlite3_finalize(q); printf("OK\n"); sqlite3_close(db); return 0; } |
Added test/tkt-18458b1a.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 | # 2019 September 10 # # 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. In particular, # that problems related to ticket [18458b1a] have been fixed. # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix tkt-18458b1a foreach tn {1 2} { reset_db if {$tn==1} { # Disable the flattener and push-down optimizations optimization_control db query-flattener 0 optimization_control db push-down 0 } else { # Enable them optimization_control db query-flattener 1 optimization_control db push-down 1 } db cache size 0 do_execsql_test $tn.1.1 { CREATE TABLE t0(c0 COLLATE NOCASE); INSERT INTO t0(c0) VALUES ('B'); CREATE VIEW v0(c0, c1) AS SELECT DISTINCT t0.c0, 'a' FROM t0; } do_execsql_test $tn.1.2 { SELECT count(*) FROM v0 WHERE c1 >= c0; } 1 do_execsql_test $tn.1.3 { SELECT count(*) FROM v0 WHERE NOT NOT (c1 >= c0); } 1 do_execsql_test $tn.1.4 { SELECT count(*) FROM v0 WHERE ((c1 >= c0) OR 0+0); } 1 } finish_test |
Changes to test/tkt-2d1a5c67d.test.
︙ | ︙ | |||
15 16 17 18 19 20 21 | # # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix tkt-2d1a5c67d | | | 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | # # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix tkt-2d1a5c67d ifcapable {!vtab || !incrblob} {finish_test; return} if {[wal_is_capable]==0} {finish_test; return} for {set ii 1} {$ii<=10} {incr ii} { do_test tkt-2d1a5c67d.1.$ii { db close forcedelete test.db test.db-wal sqlite3 db test.db |
︙ | ︙ |
Changes to test/tkt-385a5b56b9.test.
︙ | ︙ | |||
31 32 33 34 35 36 37 | do_execsql_test 2.0 { CREATE TABLE t2(x, y NOT NULL); CREATE UNIQUE INDEX t2x ON t2(x); CREATE UNIQUE INDEX t2y ON t2(y); } do_eqp_test 2.1 { SELECT DISTINCT x FROM t2 } \ | | | | | | 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | do_execsql_test 2.0 { CREATE TABLE t2(x, y NOT NULL); CREATE UNIQUE INDEX t2x ON t2(x); CREATE UNIQUE INDEX t2y ON t2(y); } do_eqp_test 2.1 { SELECT DISTINCT x FROM t2 } \ {SCAN t2 USING COVERING INDEX t2x} do_eqp_test 2.2 { SELECT DISTINCT y FROM t2 } \ {SCAN t2 USING COVERING INDEX t2y} do_eqp_test 2.3 { SELECT DISTINCT x, y FROM t2 WHERE y=10 } \ {SEARCH t2 USING INDEX t2y (y=?)} do_eqp_test 2.4 { SELECT DISTINCT x, y FROM t2 WHERE x=10 } \ {SEARCH t2 USING INDEX t2x (x=?)} finish_test |
Changes to test/tkt-3a77c9714e.test.
|
| | | 1 2 3 4 5 6 7 8 | # 2011-12-06 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. |
︙ | ︙ | |||
64 65 66 67 68 69 70 | SELECT SrcWord, B.Id as BeginningId, B.Title || E.Title As Connected FROM Beginnings B LEFT JOIN Endings E ON B.EndingId=E.EndingId WHERE Connected=SrcWord LIMIT 1 ) ) } {FACTORING FACTOR SWIMMING SWIMM} | > | > > > > > > > > > > > > > | 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 | SELECT SrcWord, B.Id as BeginningId, B.Title || E.Title As Connected FROM Beginnings B LEFT JOIN Endings E ON B.EndingId=E.EndingId WHERE Connected=SrcWord LIMIT 1 ) ) } {FACTORING FACTOR SWIMMING SWIMM} # Similar problem discovered by dbsqlfuzz on 2019-09-18 # do_execsql_test 3.0 { DROP TABLE IF EXISTS t1; CREATE TABLE t1(i INT PRIMARY KEY, a, b); INSERT INTO t1 VALUES(NULL,'one','i'); CREATE INDEX i1a ON t1(a); CREATE INDEX i1b ON t1(b); SELECT (SELECT 1 FROM (SELECT 1 FROM t1 WHERE a=1 OR b='i') WHERE a='o' OR b IN (SELECT a=('b' IN (SELECT 'a')))) FROM t1; } {{}} finish_test |
Changes to test/tkt-78e04e52ea.test.
︙ | ︙ | |||
37 38 39 40 41 42 43 | } {0 {} {} 0 {} 0 1 x CHAR(100) 0 {} 0} do_test tkt-78e04-1.3 { execsql { CREATE INDEX i1 ON ""("" COLLATE nocase); } } {} do_test tkt-78e04-1.4 { | | | | | | 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 | } {0 {} {} 0 {} 0 1 x CHAR(100) 0 {} 0} do_test tkt-78e04-1.3 { execsql { CREATE INDEX i1 ON ""("" COLLATE nocase); } } {} do_test tkt-78e04-1.4 { db eval {EXPLAIN QUERY PLAN SELECT "" FROM "" WHERE "" LIKE '1e5%';} } {/*SCAN USING COVERING INDEX i1*/} do_test tkt-78e04-1.5 { execsql { DROP TABLE ""; SELECT name FROM sqlite_master; } } {t2} do_test tkt-78e04-2.1 { execsql { CREATE INDEX "" ON t2(x); EXPLAIN QUERY PLAN SELECT * FROM t2 WHERE x=5; } } {/*SEARCH t2 USING COVERING INDEX (x=?)*/} do_test tkt-78e04-2.2 { execsql { DROP INDEX ""; EXPLAIN QUERY PLAN SELECT * FROM t2 WHERE x=2; } } {/*SCAN t2*/} finish_test |
Changes to test/tkt-8454a207b9.test.
︙ | ︙ | |||
13 14 15 16 17 18 19 20 21 22 23 24 25 26 | # it tests that ticket [8454a207b9fd2243c4c6b7a73f67ea0315717c1a]. Verify # that a negative default value on an added text column actually comes # out negative. # set testdir [file dirname $argv0] source $testdir/tester.tcl do_test tkt-8454a207b9.1 { db eval { CREATE TABLE t1(a); INSERT INTO t1 VALUES(1); ALTER TABLE t1 ADD COLUMN b TEXT DEFAULT -123.0; SELECT b, typeof(b) FROM t1; | > > > > > > | 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | # it tests that ticket [8454a207b9fd2243c4c6b7a73f67ea0315717c1a]. Verify # that a negative default value on an added text column actually comes # out negative. # set testdir [file dirname $argv0] source $testdir/tester.tcl # If SQLITE_OMIT_ALTERTABLE is defined, omit this file. ifcapable !altertable { finish_test return } do_test tkt-8454a207b9.1 { db eval { CREATE TABLE t1(a); INSERT INTO t1 VALUES(1); ALTER TABLE t1 ADD COLUMN b TEXT DEFAULT -123.0; SELECT b, typeof(b) FROM t1; |
︙ | ︙ |
Added test/tkt-a7debbe0.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 | # 2019 September 10 # # 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. In particular, # that problems related to ticket a7debbe0ad1 have been fixed. # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix tkt-a7debbe0 foreach tn {1 2} { reset_db if {$tn==1} { # Disable the flattener optimization_control db query-flattener 0 } else { # Enable the flattener optimization_control db query-flattener 1 } do_execsql_test $tn.1.0 { CREATE TABLE t0(xyz INTEGER); INSERT INTO t0(xyz) VALUES(456); CREATE VIEW v2(a, B) AS SELECT 'a', 'B' COLLATE NOCASE FROM t0; CREATE TABLE t2(a, B COLLATE NOCASE); INSERT INTO t2 VALUES('a', 'B'); CREATE VIEW v3(a, B) AS SELECT 'a' COLLATE BINARY, 'B' COLLATE NOCASE FROM t0; CREATE VIEW v4(a, B) AS SELECT 'a', +CAST('B' COLLATE NOCASE AS TEXT) FROM t0; CREATE VIEW v5(a, B) AS SELECT 'a', ('B' COLLATE NOCASE) || '' FROM t0; } # Table t2 and views v2 through v5 should all be equivalent. do_execsql_test $tn.1.1.1 { SELECT a >= B FROM t2; } 1 do_execsql_test $tn.1.1.2 { SELECT 'a' >= 'B' COLLATE NOCASE } 0 do_execsql_test $tn.1.1.3 { SELECT a >= B FROM v2 } 1 do_execsql_test $tn.1.1.4 { SELECT a >= B FROM v3 } 1 do_execsql_test $tn.1.1.5 { SELECT a >= B FROM v4 } 1 do_execsql_test $tn.1.1.6 { SELECT a >= B FROM v5 } 1 do_execsql_test $tn.1.2.1 { SELECT B < a FROM t2 } 0 do_execsql_test $tn.1.2.2 { SELECT 'B' COLLATE NOCASE < 'a' } 0 do_execsql_test $tn.1.2.3 { SELECT B < a FROM v2 } 0 do_execsql_test $tn.1.2.4 { SELECT B < a FROM v3 } 0 do_execsql_test $tn.1.2.5 { SELECT a < B FROM v4 } 0 do_execsql_test $tn.1.2.6 { SELECT a < B FROM v5 } 0 #------------------------------------------------------------------------- do_execsql_test $tn.2.0 { CREATE TABLE t5(a, b COLLATE NOCASE); INSERT INTO t5 VALUES(1, 'XYZ'); } # Result should be 0, as column "xyz" from the sub-query has implicit # collation sequence BINARY. do_execsql_test $tn.2.1 { SELECT xyz==b FROM ( SELECT a, 'xyz' AS xyz FROM t5 ), t5; } {0} # Result should be 1, as literal 'xyz' has no collation sequence, so # the comparison uses the implicit collation sequence of the RHS - NOCASE. do_execsql_test $tn.2.2 { SELECT 'xyz'==b FROM ( SELECT a, 'xyz' AS xyz FROM t5 ), t5; } {1} #----------------------------------------------------------------------- # The test case submitted with the ticket. # do_execsql_test $tn.3.0 { DROP TABLE t0; DROP VIEW v2; CREATE TABLE t0(c0); INSERT INTO t0(c0) VALUES(''); CREATE VIEW v2(c0, c1) AS SELECT 'B' COLLATE NOCASE, 'a' FROM t0 ORDER BY t0.c0; SELECT SUM(count) FROM ( SELECT v2.c1 BETWEEN v2.c0 AND v2.c1 as count FROM v2 ); } 1 # The result is 1, as the collation used is the implicit collation sequence # of v2.c1 - BINARY. do_execsql_test $tn.3.1 { SELECT v2.c1 BETWEEN v2.c0 AND v2.c1 as count FROM v2; } 1 } finish_test |
Changes to test/tkt-a8a0d2996a.test.
︙ | ︙ | |||
80 81 82 83 84 85 86 | SELECT '100x'+'-2y'; } {98} do_execsql_test 4.3 { SELECT '100x'+'4.5y'; } {104.5} do_execsql_test 4.4 { SELECT '-9223372036854775807x'-'1x'; | | | | | | 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 | SELECT '100x'+'-2y'; } {98} do_execsql_test 4.3 { SELECT '100x'+'4.5y'; } {104.5} do_execsql_test 4.4 { SELECT '-9223372036854775807x'-'1x'; } {-9223372036854775808} do_execsql_test 4.5 { SELECT '9223372036854775806x'+'1x'; } {9223372036854775807} do_execsql_test 4.6 { SELECT '1234x'/'10y', '1234x'/'10.y', '1234x'/'1e1y'; } {123 123.4 123.4} finish_test |
Changes to test/tkt-b75a9ca6b0.test.
︙ | ︙ | |||
28 29 30 31 32 33 34 | INSERT INTO t1 VALUES (3, 1); } do_execsql_test 1.1 { CREATE INDEX i1 ON t1(x, y); } | | | | 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | INSERT INTO t1 VALUES (3, 1); } do_execsql_test 1.1 { CREATE INDEX i1 ON t1(x, y); } set idxscan {SCAN t1 USING COVERING INDEX i1} set tblscan {SCAN t1} set grpsort {USE TEMP B-TREE FOR GROUP BY} set sort {USE TEMP B-TREE FOR ORDER BY} foreach {tn q res eqp} [subst -nocommands { 1 "SELECT * FROM t1 GROUP BY x, y ORDER BY x,y" {1 3 2 2 3 1} {$idxscan} |
︙ | ︙ | |||
56 57 58 59 60 61 62 | 6 "SELECT * FROM t1 GROUP BY y ORDER BY x" {1 3 2 2 3 1} {$tblscan*$grpsort*$sort} 7 "SELECT * FROM t1 GROUP BY x, y ORDER BY x, y DESC" {1 3 2 2 3 1} {$idxscan*$sort} 8 "SELECT * FROM t1 GROUP BY x, y ORDER BY x DESC, y DESC" | | | 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | 6 "SELECT * FROM t1 GROUP BY y ORDER BY x" {1 3 2 2 3 1} {$tblscan*$grpsort*$sort} 7 "SELECT * FROM t1 GROUP BY x, y ORDER BY x, y DESC" {1 3 2 2 3 1} {$idxscan*$sort} 8 "SELECT * FROM t1 GROUP BY x, y ORDER BY x DESC, y DESC" {3 1 2 2 1 3} {$idxscan} 9 "SELECT * FROM t1 GROUP BY x, y ORDER BY x ASC, y ASC" {1 3 2 2 3 1} {$idxscan} 10 "SELECT * FROM t1 GROUP BY x, y ORDER BY x COLLATE nocase, y" {1 3 2 2 3 1} {$idxscan*$sort} |
︙ | ︙ |
Changes to test/tkt-cbd054fa6b.test.
︙ | ︙ | |||
12 13 14 15 16 17 18 | # This file implements tests to verify that ticket [cbd054fa6b] has been # fixed. # set testdir [file dirname $argv0] source $testdir/tester.tcl | | | 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | # This file implements tests to verify that ticket [cbd054fa6b] has been # fixed. # set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable !stat4 { finish_test return } proc s {blob} { set ret "" binary scan $blob c* bytes |
︙ | ︙ | |||
51 52 53 54 55 56 57 | INSERT INTO t1 VALUES (NULL, 'H'); INSERT INTO t1 VALUES (NULL, 'I'); SELECT count(*) FROM t1; } } {10} do_test tkt-cbd05-1.2 { db eval { ANALYZE; } | < | | | | | | < < < < < < | 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | INSERT INTO t1 VALUES (NULL, 'H'); INSERT INTO t1 VALUES (NULL, 'I'); SELECT count(*) FROM t1; } } {10} do_test tkt-cbd05-1.2 { db eval { ANALYZE; } db eval { PRAGMA writable_schema = 1; CREATE VIEW vvv AS SELECT tbl,idx,neq,nlt,ndlt,test_extract(sample,0) AS sample FROM sqlite_stat4; PRAGMA writable_schema = 0; } } {} do_test tkt-cbd05-1.3 { execsql { SELECT tbl,idx,group_concat(s(sample),' ') FROM vvv WHERE idx = 't1_x' |
︙ | ︙ |
Changes to test/tkt-f67b41381a.test.
︙ | ︙ | |||
10 11 12 13 14 15 16 17 18 19 20 21 22 23 | #*********************************************************************** # Test that ticket f67b41381a has been resolved. # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix tkt-f67b41381a do_execsql_test 1.0 { CREATE TABLE t1(a); INSERT INTO t1 VALUES(1); ALTER TABLE t1 ADD COLUMN b DEFAULT 2; CREATE TABLE t2(a, b); INSERT INTO t2 SELECT * FROM t1; | > > > > > | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | #*********************************************************************** # Test that ticket f67b41381a has been resolved. # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix tkt-f67b41381a ifcapable !altertable { finish_test return } do_execsql_test 1.0 { CREATE TABLE t1(a); INSERT INTO t1 VALUES(1); ALTER TABLE t1 ADD COLUMN b DEFAULT 2; CREATE TABLE t2(a, b); INSERT INTO t2 SELECT * FROM t1; |
︙ | ︙ |
Changes to test/tkt2854.test.
︙ | ︙ | |||
24 25 26 27 28 29 30 | # Open 3 database connections. Connection "db" and "db2" share a cache. # Connection "db3" has its own cache. # do_test tkt2854-1.1 { sqlite3 db test.db sqlite3 db2 test.db | < < < < < < < < < | < | 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | # Open 3 database connections. Connection "db" and "db2" share a cache. # Connection "db3" has its own cache. # do_test tkt2854-1.1 { sqlite3 db test.db sqlite3 db2 test.db sqlite3 db3 "file:test.db?cache=private" -uri 1 db eval { CREATE TABLE abc(a, b, c); } } {} # Check that an exclusive lock cannot be obtained if some other |
︙ | ︙ |
Changes to test/tkt3292.test.
︙ | ︙ | |||
16 17 18 19 20 21 22 23 | # # $Id: tkt3292.test,v 1.1 2008/08/13 14:07:41 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl do_test tkt3292-1.1 { execsql { | > < | 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | # # $Id: tkt3292.test,v 1.1 2008/08/13 14:07:41 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl do_test tkt3292-1.1 { sqlite3_db_config db LEGACY_FILE_FORMAT 0 execsql { CREATE TABLE t1(a INTEGER PRIMARY KEY, b INT); INSERT INTO t1 VALUES(0, 1); INSERT INTO t1 VALUES(1, 1); INSERT INTO t1 VALUES(2, 1); CREATE INDEX i1 ON t1(b); SELECT * FROM t1 WHERE b>=1; } |
︙ | ︙ |
Changes to test/tkt3442.test.
︙ | ︙ | |||
36 37 38 39 40 41 42 | # These tests perform an EXPLAIN QUERY PLAN on both versions of the # SELECT referenced in ticket #3442 (both '5000' and "5000") # and verify that the query plan is the same. # do_eqp_test tkt3442-1.2 { SELECT node FROM listhash WHERE id='5000' LIMIT 1; | | | | | 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 | # These tests perform an EXPLAIN QUERY PLAN on both versions of the # SELECT referenced in ticket #3442 (both '5000' and "5000") # and verify that the query plan is the same. # do_eqp_test tkt3442-1.2 { SELECT node FROM listhash WHERE id='5000' LIMIT 1; } {SEARCH listhash USING INDEX ididx (id=?)} do_eqp_test tkt3442-1.3 { SELECT node FROM listhash WHERE id="5000" LIMIT 1; } {SEARCH listhash USING INDEX ididx (id=?)} # Some extra tests testing other permutations of 5000. # do_eqp_test tkt3442-1.4 { SELECT node FROM listhash WHERE id=5000 LIMIT 1; } {SEARCH listhash USING INDEX ididx (id=?)} do_test tkt3442-1.5 { catchsql { SELECT node FROM listhash WHERE id=[5000] LIMIT 1; } } {1 {no such column: 5000}} |
︙ | ︙ |
Changes to test/tkt3793.test.
︙ | ︙ | |||
9 10 11 12 13 14 15 | # #*********************************************************************** # This file implements regression tests for SQLite library. # # This file implements tests to verify that ticket #3793 has been # fixed. # | < < < < < | < | < < | | < | 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 | # #*********************************************************************** # This file implements regression tests for SQLite library. # # This file implements tests to verify that ticket #3793 has been # fixed. # set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable !shared_cache||!attach { finish_test return } set ::enable_shared_cache [sqlite3_enable_shared_cache 1] do_test tkt3793-1.1 { db close sqlite3 db "file:test.db" -uri 1 sqlite3 db1 "file:test.db?cache=private" -uri 1 sqlite3 db2 "file:test.db?cache=shared" -uri 1 execsql { BEGIN; CREATE TABLE t1(a, b); CREATE TABLE t2(a PRIMARY KEY, b); INSERT INTO t1 VALUES(randstr(50,50), randstr(50,50)); INSERT INTO t1 SELECT randstr(50,50), randstr(50,50) FROM t1; INSERT INTO t1 SELECT randstr(50,50), randstr(50,50) FROM t1; |
︙ | ︙ |
Changes to test/tkt3810.test.
︙ | ︙ | |||
79 80 81 82 83 84 85 86 87 | execsql {DROP TABLE t1} execsql { SELECT name FROM sqlite_temp_master; } } {} db2 close finish_test | > > > > > > > > > > > > > > > > | 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 | execsql {DROP TABLE t1} execsql { SELECT name FROM sqlite_temp_master; } } {} db2 close # 2020-11-06 forum post https://sqlite.org/forum/forumpost/157dc791df # reset_db do_test tkt3810-100 { db eval { ATTACH ':memory:' AS aux1; CREATE TABLE aux1.t1(x); CREATE TEMP TRIGGER r1 DELETE ON t1 BEGIN SELECT *; END; CREATE VIEW t1 AS SELECT *; } catch {db eval { CREATE VIRTUAL TABLE t2 USING nosuchmodule; }} db eval {CREATE TABLE t3(z);} } {} finish_test |
Changes to test/tpch01.test.
︙ | ︙ | |||
161 162 163 164 165 166 167 | and p_type = 'LARGE PLATED STEEL' ) as all_nations group by o_year order by o_year;}] set ::eqpres | | | | | | | | | 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 | and p_type = 'LARGE PLATED STEEL' ) as all_nations group by o_year order by o_year;}] set ::eqpres } {/*SEARCH part USING INDEX bootleg_pti *SEARCH lineitem USING INDEX lpki2*/} do_test tpch01-1.1b { set ::eqpres } {/.* customer .* n1 .*/} do_test tpch01-1.1c { set ::eqpres } {/.* supplier .* n2 .*/} do_eqp_test tpch01-1.2 { select c_custkey, c_name, sum(l_extendedprice * (1 - l_discount)) as revenue, c_acctbal, n_name, c_address, c_phone, c_comment from customer, orders, lineitem, nation where c_custkey = o_custkey and l_orderkey = o_orderkey and o_orderdate >= '1994-08-01' and o_orderdate < date('1994-08-01', '+3 month') and l_returnflag = 'R' and c_nationkey = n_nationkey group by c_custkey, c_name, c_acctbal, c_phone, n_name, c_address, c_comment order by revenue desc; } { QUERY PLAN |--SEARCH orders USING INDEX odi (O_ORDERDATE>? AND O_ORDERDATE<?) |--SEARCH customer USING INDEX cpki (C_CUSTKEY=?) |--SEARCH nation USING INDEX npki (N_NATIONKEY=?) |--SEARCH lineitem USING INDEX lpki (L_ORDERKEY=?) |--USE TEMP B-TREE FOR GROUP BY `--USE TEMP B-TREE FOR ORDER BY } finish_test |
Changes to test/trace3.test.
︙ | ︙ | |||
246 247 248 249 250 251 252 253 254 | do_test trace3-11.2 { set ::stmtlist(record) {} db trace_v2 trace_v2_record 8 db close set ::stmtlist(record) } {/^-?\d+$/} finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | do_test trace3-11.2 { set ::stmtlist(record) {} db trace_v2 trace_v2_record 8 db close set ::stmtlist(record) } {/^-?\d+$/} #------------------------------------------------------------------------- reset_db do_test 12.1.0 { set ::STMT [sqlite3_prepare_v2 $DB \ "SELECT ?1 || ?1 || ?1 || ?2 || ?3 || ?4 || ? || ?1 || ?" -1 TAIL ] sqlite3_bind_parameter_count $::STMT } {6} do_test 12.1.1 { sqlite3_bind_text $STMT 1 "A" 1 sqlite3_bind_text $STMT 2 "B" 1 sqlite3_bind_text $STMT 3 "C" 1 sqlite3_bind_text $STMT 4 "D" 1 sqlite3_bind_text $STMT 5 "E" 1 sqlite3_bind_text $STMT 6 "F" 1 sqlite3_expanded_sql $STMT } {SELECT 'A' || 'A' || 'A' || 'B' || 'C' || 'D' || 'E' || 'A' || 'F'} do_test 12.1.2 { sqlite3_step $STMT sqlite3_column_text $STMT 0 } {AAABCDEAF} do_test 12.1.3 { sqlite3_finalize $STMT } {SQLITE_OK} do_test 12.2.0 { execsql { CREATE TABLE nameFtsFuzzySearchTable( word, distance, langid, score, top, scope ); } set ::STMT [sqlite3_prepare_v2 $DB { SELECT substr(word,1,length(?1)-1) AS term, distance, langid, score FROM nameFtsFuzzySearchTable WHERE word MATCH (?1) AND abs(?1) = abs(term) AND top = ?2 AND distance > ?3 AND scope = ?4 AND langid = ? GROUP BY term, langid HAVING (1.0 - ((distance / 100.0) / CAST( length(?1) - 1 AS REAL ))) >= ? } -1 TAIL] sqlite3_bind_parameter_count $::STMT } {6} do_test 12.1.1 { sqlite3_bind_text $STMT 1 "A" 1 sqlite3_bind_text $STMT 2 "B" 1 sqlite3_bind_text $STMT 3 "C" 1 sqlite3_bind_text $STMT 4 "D" 1 sqlite3_bind_text $STMT 5 "E" 1 sqlite3_bind_text $STMT 6 "F" 1 sqlite3_expanded_sql $STMT } { SELECT substr(word,1,length('A')-1) AS term, distance, langid, score FROM nameFtsFuzzySearchTable WHERE word MATCH ('A') AND abs('A') = abs(term) AND top = 'B' AND distance > 'C' AND scope = 'D' AND langid = 'E' GROUP BY term, langid HAVING (1.0 - ((distance / 100.0) / CAST( length('A') - 1 AS REAL ))) >= 'F' } do_test 12.1.2 { sqlite3_finalize $STMT } {SQLITE_OK} finish_test |
Changes to test/trans.test.
1 2 3 4 5 6 7 8 9 10 11 12 13 | # 2001 September 15 # # 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 database locks. # | < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | # 2001 September 15 # # 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 database locks. # set testdir [file dirname $argv0] source $testdir/tester.tcl # Create several tables to work with. # |
︙ | ︙ | |||
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 | CREATE TABLE two(a int PRIMARY KEY, b text); INSERT INTO two VALUES(1,'I'); INSERT INTO two VALUES(5,'V'); INSERT INTO two VALUES(10,'X'); SELECT b FROM two ORDER BY a; } } {I V X} do_test trans-1.9 { sqlite3 altdb test.db execsql {SELECT b FROM one ORDER BY a} altdb } {one two three} do_test trans-1.10 { execsql {SELECT b FROM two ORDER BY a} altdb } {I V X} integrity_check trans-1.11 wal_check_journal_mode trans-1.12 # Basic transactions # do_test trans-2.1 { set v [catch {execsql {BEGIN}} msg] lappend v $msg } {0 {}} do_test trans-2.2 { set v [catch {execsql {END}} msg] lappend v $msg } {0 {}} do_test trans-2.3 { set v [catch {execsql {BEGIN TRANSACTION}} msg] lappend v $msg | > > > > > > > > > > > > > > > > | 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 | CREATE TABLE two(a int PRIMARY KEY, b text); INSERT INTO two VALUES(1,'I'); INSERT INTO two VALUES(5,'V'); INSERT INTO two VALUES(10,'X'); SELECT b FROM two ORDER BY a; } } {I V X} do_test trans-1.2.1 { sqlite3_txn_state db } {0} do_test trans-1.2.2 { sqlite3_txn_state db main } {0} do_test trans-1.2.3 { sqlite3_txn_state db temp } {0} do_test trans-1.2.4 { sqlite3_txn_state db no-such-schema } {-1} do_test trans-1.9 { sqlite3 altdb test.db execsql {SELECT b FROM one ORDER BY a} altdb } {one two three} do_test trans-1.10 { execsql {SELECT b FROM two ORDER BY a} altdb } {I V X} integrity_check trans-1.11 wal_check_journal_mode trans-1.12 # Basic transactions # do_test trans-2.1 { set v [catch {execsql {BEGIN}} msg] lappend v $msg } {0 {}} do_test trans-2.1b { sqlite3_txn_state db } {0} do_test trans-2.2 { set v [catch {execsql {END}} msg] lappend v $msg } {0 {}} do_test trans-2.3 { set v [catch {execsql {BEGIN TRANSACTION}} msg] lappend v $msg |
︙ | ︙ | |||
91 92 93 94 95 96 97 98 99 100 101 102 103 104 | do_test trans-3.1 { execsql { BEGIN; UPDATE one SET a = 0 WHERE 0; SELECT a FROM one ORDER BY a; } } {1 2 3} do_test trans-3.2 { catchsql { SELECT a FROM two ORDER BY a; } altdb } {0 {1 5 10}} do_test trans-3.3 { | > > > > > > > > > > | 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 | do_test trans-3.1 { execsql { BEGIN; UPDATE one SET a = 0 WHERE 0; SELECT a FROM one ORDER BY a; } } {1 2 3} do_test trans-3.1b { sqlite3_txn_state db } {2} do_test trans-3.1c { sqlite3_txn_state db main } {2} do_test trans-3.1d { sqlite3_txn_state db temp } {0} do_test trans-3.2 { catchsql { SELECT a FROM two ORDER BY a; } altdb } {0 {1 5 10}} do_test trans-3.3 { |
︙ | ︙ | |||
135 136 137 138 139 140 141 142 143 144 145 146 147 148 | catchsql { SELECT a FROM one ORDER BY a; } altdb } {0 {1 2 3}} do_test trans-3.10 { execsql {END TRANSACTION} } {} do_test trans-3.11 { set v [catch {execsql { SELECT a FROM two ORDER BY a; } altdb} msg] lappend v $msg } {0 {1 4 5 10}} | > > > > | 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 | catchsql { SELECT a FROM one ORDER BY a; } altdb } {0 {1 2 3}} do_test trans-3.10 { execsql {END TRANSACTION} } {} do_test trans-3.10b { sqlite3_txn_state db } {0} do_test trans-3.11 { set v [catch {execsql { SELECT a FROM two ORDER BY a; } altdb} msg] lappend v $msg } {0 {1 4 5 10}} |
︙ | ︙ | |||
248 249 250 251 252 253 254 255 256 257 258 259 260 261 | do_test trans-5.1 { execsql {SELECT name FROM sqlite_master WHERE type='table' ORDER BY name} } {} do_test trans-5.2 { execsql {BEGIN TRANSACTION} execsql {SELECT name FROM sqlite_master WHERE type='table' ORDER BY name} } {} do_test trans-5.3 { execsql {CREATE TABLE one(a text, b int)} execsql {SELECT name FROM sqlite_master WHERE type='table' ORDER BY name} } {one} do_test trans-5.4 { execsql {SELECT a,b FROM one ORDER BY b} } {} | > > > > > > > > > | 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 | do_test trans-5.1 { execsql {SELECT name FROM sqlite_master WHERE type='table' ORDER BY name} } {} do_test trans-5.2 { execsql {BEGIN TRANSACTION} execsql {SELECT name FROM sqlite_master WHERE type='table' ORDER BY name} } {} do_test trans-5.2b { sqlite3_txn_state db } {1} do_test trans-5.2c { sqlite3_txn_state db main } {1} do_test trans-5.2d { sqlite3_txn_state db temp } {0} do_test trans-5.3 { execsql {CREATE TABLE one(a text, b int)} execsql {SELECT name FROM sqlite_master WHERE type='table' ORDER BY name} } {one} do_test trans-5.4 { execsql {SELECT a,b FROM one ORDER BY b} } {} |
︙ | ︙ |
Changes to test/transitive1.test.
︙ | ︙ | |||
340 341 342 343 344 345 346 | do_execsql_test transitive1-560 { CREATE INDEX c1x ON c1(x); SELECT * FROM c1 WHERE x=y AND y=z AND z='abc'; } {ABC ABC abc} do_execsql_test transitive1-560eqp { EXPLAIN QUERY PLAN SELECT * FROM c1 WHERE x=y AND y=z AND z='abc'; | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | do_execsql_test transitive1-560 { CREATE INDEX c1x ON c1(x); SELECT * FROM c1 WHERE x=y AND y=z AND z='abc'; } {ABC ABC abc} do_execsql_test transitive1-560eqp { EXPLAIN QUERY PLAN SELECT * FROM c1 WHERE x=y AND y=z AND z='abc'; } {/SCAN c1/} do_execsql_test transitive1-570 { SELECT * FROM c1 WHERE x=y AND z=y AND z='abc'; } {} do_execsql_test transitive1-570eqp { EXPLAIN QUERY PLAN SELECT * FROM c1 WHERE x=y AND z=y AND z='abc'; } {/SEARCH c1 USING INDEX c1x/} # 2021-05-04 forum https://sqlite.org/forum/forumpost/eb8613976a reset_db do_execsql_test transitive1-600 { CREATE TABLE t0(a0 INT, b1 INT); CREATE INDEX t0b1 ON t0(b1); CREATE TABLE t1(w,x,y,z3 INT); INSERT INTO t0(a0, b1) VALUES (0,1); INSERT INTO t1(w,x,y,z3) VALUES (7,8,9,1); } {} do_execsql_test transitive1-610 { SELECT ALL * FROM t0,t1 WHERE b1=z3 AND a0=z3; } {} do_execsql_test transitive1-620 { SELECT ALL * FROM t0,t1 WHERE likely(b1=z3) AND a0=z3; } {} do_execsql_test transitive1-630 { DROP TABLE t0; DROP TABLE t1; CREATE TABLE t0(c0 INT, c1 INT UNIQUE); CREATE TABLE t1(c0 INT); INSERT INTO t0(c0, c1) VALUES (0, 1); INSERT INTO t1(c0) VALUES (1); SELECT ALL * FROM t1 NATURAL JOIN t0 WHERE (t1.c0=t0.c1); SELECT ALL * FROM t1 NATURAL JOIN t0 WHERE (likely(t1.c0=t0.c1)); SELECT ALL * FROM t1,t0 WHERE (likely(t1.c0=t0.c1) AND t1.c0=t0.c0); } {} #------------------------------------------------------------------------- # 2021-08-31 forum https://sqlite.org/forum/forumpost/8d1b58f112 reset_db do_execsql_test transitive1-700 { CREATE TABLE t1(a INT PRIMARY KEY); INSERT INTO t1(a) VALUES(1),(2),(3); CREATE TABLE t2(x INTEGER PRIMARY KEY,y INT); INSERT INTO t2(y) VALUES(2),(3); } do_execsql_test transitive1-710 { SELECT * FROM t1 CROSS JOIN t2 WHERE t2.y=t1.a AND t1.a=t2.x } {} do_execsql_test transitive1-720 { SELECT * FROM t1 CROSS JOIN t2 WHERE likely(t2.y=t1.a) AND unlikely(t1.a=t2.x) } {} # 2021-10-04 forum https://sqlite.org/forum/forumpost/a65cacbf5e1c41ba # reset_db do_execsql_test transitive1-800 { CREATE TABLE t1(a INT); INSERT INTO t1 VALUES(0),(3); CREATE TABLE t2(b INT UNIQUE, c INT); INSERT INTO t2 VALUES(1,4) ,(0,5); SELECT * FROM t1 WHERE EXISTS (SELECT 1 FROM t2 WHERE c=a AND b IS a); SELECT * FROM t1 WHERE EXISTS (SELECT 1 FROM t2 WHERE a=c AND a IS b); SELECT * FROM t1 WHERE EXISTS (SELECT 1 FROM t2 WHERE a=c AND b IS a); SELECT * FROM t1 WHERE EXISTS (SELECT 1 FROM t2 WHERE c=a AND a IS b); } {} do_execsql_test transitive1-810 { CREATE TABLE t3(a INTEGER PRIMARY KEY,b); INSERT INTO t3(a,b) VALUES(1,2),(5,5),(7,11); SELECT * FROM t3 WHERE a=b AND a='5'; } {5 5} do_execsql_test transitive1-811 { SELECT * FROM t3 WHERE a=b AND a='4'; } {} do_execsql_test transitive1-812 { SELECT * FROM t3 WHERE a=b AND a='7'; } {} do_execsql_test transitive1-813 { SELECT * FROM t3 WHERE a=b AND a='5x'; } {} finish_test |
Changes to test/trigger1.test.
︙ | ︙ | |||
763 764 765 766 767 768 769 770 771 | } {1 2 2} do_execsql_test trigger1-19.1 { DELETE FROM t19; INSERT INTO t19(a,b,c) VALUES(1,2,3); UPDATE t19 SET c=CASE WHEN b=2 THEN b ELSE b+99 END WHERE a=1; SELECT * FROM t19; } {1 2 2} finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | } {1 2 2} do_execsql_test trigger1-19.1 { DELETE FROM t19; INSERT INTO t19(a,b,c) VALUES(1,2,3); UPDATE t19 SET c=CASE WHEN b=2 THEN b ELSE b+99 END WHERE a=1; SELECT * FROM t19; } {1 2 2} # 2019-08-26 Chromium sqlite3_fts3_lpm_fuzzer find. # db close sqlite3 db :memory: do_execsql_test trigger1-20.1 { CREATE TABLE t20_1(x); ATTACH ':memory:' AS aux; CREATE TABLE aux.t20_2(y); CREATE TABLE aux.t20_3(z); CREATE TEMP TRIGGER r20_3 AFTER INSERT ON t20_2 BEGIN UPDATE t20_3 SET z=z+1; END; DETACH aux; DROP TRIGGER r20_3; } {} # 2019-10-24 ticket 50c09fc2cf0d91ce # db close sqlite3 db :memory: do_execsql_test trigger1-21.1 { PRAGMA recursive_triggers = true; CREATE TABLE t0(a, b, c UNIQUE); CREATE UNIQUE INDEX i0 ON t0(b) WHERE a; CREATE TRIGGER tr0 AFTER DELETE ON t0 BEGIN DELETE FROM t0; END; INSERT INTO t0(a,b,c) VALUES(0,0,9),(1,1,1); REPLACE INTO t0(a,b,c) VALUES(2,0,9); SELECT * FROM t0; } {2 0 9} # 2020-01-04 From Yongheng # The test case below caused problems for the register validity # tracking logic. There was no bug in the release build. The # only problem was a false-positive in the register validity # tracking. # reset_db do_execsql_test trigger1-22.10 { CREATE TABLE t1( a INTEGER PRIMARY KEY, b DOUBLE ); CREATE TRIGGER x AFTER UPDATE ON t1 BEGIN SELECT sum(b)OVER(ORDER BY (SELECT b FROM t1 AS x WHERE b IN (t1.a,127,t1.b) GROUP BY b)) FROM t1 GROUP BY a; END; CREATE TEMP TRIGGER x BEFORE INSERT ON t1 BEGIN UPDATE t1 SET b=randomblob(10) WHERE b >= 'E' AND a < (SELECT a FROM t1 WHERE a<22 GROUP BY b); END; INSERT INTO t1(b) VALUES('Y'),('X'),('Z'); SELECT a, CASE WHEN typeof(b)='text' THEN quote(b) ELSE '<blob>' END, '|' FROM t1; } {1 <blob> | 2 'X' | 3 'Z' |} finish_test |
Changes to test/trigger2.test.
︙ | ︙ | |||
45 46 47 48 49 50 51 52 53 54 55 56 57 58 | # trigger2-6.2[a-f]: UPDATE statements # # 7. & 8. Triggers on views fire correctly. # set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable {!trigger} { finish_test return } # The tests in this file were written before SQLite supported recursive # trigger invocation, and some tests depend on that to pass. So disable | > | 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | # trigger2-6.2[a-f]: UPDATE statements # # 7. & 8. Triggers on views fire correctly. # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix trigger2 ifcapable {!trigger} { finish_test return } # The tests in this file were written before SQLite supported recursive # trigger invocation, and some tests depend on that to pass. So disable |
︙ | ︙ | |||
748 749 750 751 752 753 754 755 756 | CREATE TRIGGER trig1 INSTEAD OF DELETE ON v3 BEGIN SELECT 1; END; DELETE FROM v3 WHERE a = 1; } } {} } ;# ifcapable view | > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > | 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 | CREATE TRIGGER trig1 INSTEAD OF DELETE ON v3 BEGIN SELECT 1; END; DELETE FROM v3 WHERE a = 1; } } {} integrity_check trigger2-9.99 # 2019-11-02 Problem found by TH3, related to generated column support. db close sqlite3 db :memory: do_execsql_test trigger2-10.1 { CREATE TABLE t1(a,b,c,d); CREATE VIEW v2(a,b,c,d) AS SELECT * FROM t1; CREATE TRIGGER v2ins INSTEAD OF INSERT ON v2 BEGIN INSERT INTO t1(a,b,c,d) VALUES(new.a, new.b, new.c, new.d); END; INSERT INTO v2(a,d) VALUES(11,14); SELECT * FROM t1; } {11 {} {} 14} } ;# ifcapable view #------------------------------------------------------------------------- reset_db do_execsql_test 11.1 { CREATE TABLE t1(a INT PRIMARY KEY, b, c REAL, d, e); CREATE TABLE t2(a INT, b, c REAL, d, e, PRIMARY KEY(a,b)) WITHOUT ROWID; CREATE UNIQUE INDEX t2c ON t2(c); CREATE UNIQUE INDEX t2d ON t2(d); CREATE UNIQUE INDEX t2e ON t2(e); } do_catchsql_test 11.2 { CREATE TRIGGER r1 BEFORE INSERT ON t1 BEGIN INSERT INTO t2(a,b,c,d,e) VALUES(91,NULL,93,94,?1) ON CONFLICT(b,a) DO NOTHING ON CONFLICT DO UPDATE SET b=?1; END; } {1 {trigger cannot use variables}} finish_test |
Changes to test/trigger9.test.
︙ | ︙ | |||
238 239 240 241 242 243 244 | END; CREATE TRIGGER tr3 INSTEAD OF INSERT ON v1 BEGIN INSERT INTO log VALUES('insert'); END; } | | | | < | < < | 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 | END; CREATE TRIGGER tr3 INSTEAD OF INSERT ON v1 BEGIN INSERT INTO log VALUES('insert'); END; } do_catchsql_test 4.2 { DELETE FROM v1 WHERE rowid=1; } {1 {no such column: rowid}} do_catchsql_test 4.3 { UPDATE v1 SET a=b WHERE rowid=2; } {1 {no such column: rowid}} finish_test |
Changes to test/triggerC.test.
︙ | ︙ | |||
1037 1038 1039 1040 1041 1042 1043 1044 1045 | END; INSERT INTO x1 VALUES('go!'); } do_execsql_test 15.2.2 { SELECT * FROM x2; } {1 2 3 4} do_execsql_test 15.2.3 { SELECT * FROM """x2"""; } {3 11 x y} finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | END; INSERT INTO x1 VALUES('go!'); } do_execsql_test 15.2.2 { SELECT * FROM x2; } {1 2 3 4} do_execsql_test 15.2.3 { SELECT * FROM """x2"""; } {3 11 x y} #------------------------------------------------------------------------- # At one point queries such as the following were causing segfaults. # do_catchsql_test 16.1 { SELECT raise(ABORT, 'msg') FROM sqlite_master UNION SELECT 1 ORDER BY raise(IGNORE); } {1 {1st ORDER BY term does not match any column in the result set}} do_catchsql_test 16.2 { SELECT count(*) FROM sqlite_master GROUP BY raise(IGNORE) HAVING raise(ABORT, 'msg'); } {1 {RAISE() may only be used within a trigger-program}} #------------------------------------------------------------------------- # Datatype mismatch on IPK when there are BEFORE triggers. # do_execsql_test 17.0 { CREATE TABLE xyz(x INTEGER PRIMARY KEY, y, z); CREATE TRIGGER xyz_tr BEFORE INSERT ON xyz BEGIN SELECT new.x; END; } do_catchsql_test 17.1 { INSERT INTO xyz VALUES('hello', 2, 3); } {1 {datatype mismatch}} finish_test |
Changes to test/triggerE.test.
︙ | ︙ | |||
54 55 56 57 58 59 60 61 62 63 64 65 66 67 | 3 { BEFORE DELETE ON t1 BEGIN SELECT * FROM (SELECT * FROM (SELECT ?)); END; } 5 { BEFORE DELETE ON t1 BEGIN SELECT * FROM t2 GROUP BY ?; END; } 6 { BEFORE DELETE ON t1 BEGIN SELECT * FROM t2 LIMIT ?; END; } 7 { BEFORE DELETE ON t1 BEGIN SELECT * FROM t2 ORDER BY ?; END; } 8 { BEFORE UPDATE ON t1 BEGIN UPDATE t2 SET c = ?; END; } 9 { BEFORE UPDATE ON t1 BEGIN UPDATE t2 SET c = 1 WHERE d = ?; END; } 10 { AFTER INSERT ON t1 BEGIN SELECT * FROM pragma_stats(?); END; } } { catchsql {drop trigger tr1} do_catchsql_test 1.1.$tn "CREATE TRIGGER tr1 $defn" [list 1 $errmsg] do_catchsql_test 1.2.$tn "CREATE TEMP TRIGGER tr1 $defn" [list 1 $errmsg] } #------------------------------------------------------------------------- | > > | 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 | 3 { BEFORE DELETE ON t1 BEGIN SELECT * FROM (SELECT * FROM (SELECT ?)); END; } 5 { BEFORE DELETE ON t1 BEGIN SELECT * FROM t2 GROUP BY ?; END; } 6 { BEFORE DELETE ON t1 BEGIN SELECT * FROM t2 LIMIT ?; END; } 7 { BEFORE DELETE ON t1 BEGIN SELECT * FROM t2 ORDER BY ?; END; } 8 { BEFORE UPDATE ON t1 BEGIN UPDATE t2 SET c = ?; END; } 9 { BEFORE UPDATE ON t1 BEGIN UPDATE t2 SET c = 1 WHERE d = ?; END; } 10 { AFTER INSERT ON t1 BEGIN SELECT * FROM pragma_stats(?); END; } 11 { BEFORE INSERT ON t1 BEGIN INSERT INTO t1 SELECT max(b) OVER(ORDER BY $1) FROM t1; END } } { catchsql {drop trigger tr1} do_catchsql_test 1.1.$tn "CREATE TRIGGER tr1 $defn" [list 1 $errmsg] do_catchsql_test 1.2.$tn "CREATE TEMP TRIGGER tr1 $defn" [list 1 $errmsg] } #------------------------------------------------------------------------- |
︙ | ︙ |
Changes to test/triggerF.test.
︙ | ︙ | |||
16 17 18 19 20 21 22 | ifcapable {!trigger} { finish_test return } foreach {tn sql log} { | | | 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | ifcapable {!trigger} { finish_test return } foreach {tn sql log} { 1 {} {} 2 { CREATE TRIGGER trd AFTER DELETE ON t1 BEGIN INSERT INTO log VALUES(old.a || old.b || (SELECT count(*) FROM t1)); END; } {1one2 2two1 3three1} |
︙ | ︙ |
Changes to test/triggerG.test.
︙ | ︙ | |||
70 71 72 73 74 75 76 77 78 | SELECT 0x2147483648e0e0099 AS y WHERE y; END; } do_catchsql_test 310 { INSERT INTO t4 VALUES(1); } {1 {hex literal too big: 0x2147483648e0e0099}} finish_test | > > > > > > > > > > > > > > > > | 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 | SELECT 0x2147483648e0e0099 AS y WHERE y; END; } do_catchsql_test 310 { INSERT INTO t4 VALUES(1); } {1 {hex literal too big: 0x2147483648e0e0099}} #------------------------------------------------------------------------- # do_execsql_test 400 { CREATE VIEW v0(a) AS SELECT 1234; CREATE TRIGGER t0001 INSTEAD OF DELETE ON v0 BEGIN SELECT old.a; END; } do_execsql_test 405 { SELECT a FROM v0; } {1234} do_execsql_test 410 { DELETE FROM v0; } finish_test |
Added test/triggerupfrom.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 | # 2020 July 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. # #*********************************************************************** # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix triggerupfrom do_execsql_test 1.0 { CREATE TABLE map(k, v); INSERT INTO map VALUES(1, 'one'), (2, 'two'), (3, 'three'), (4, 'four'); CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c); CREATE TRIGGER tr AFTER INSERT ON t1 BEGIN UPDATE t1 SET c = v FROM map WHERE k=new.a AND a=new.a; END; } do_execsql_test 1.1 { INSERT INTO t1(a) VALUES(1); } do_execsql_test 1.2 { SELECT a, c FROM t1 ORDER BY a; } {1 one} do_execsql_test 1.3 { INSERT INTO t1(a) VALUES(2), (3), (4), (5); SELECT a, c FROM t1 ORDER BY a; } {1 one 2 two 3 three 4 four 5 {}} forcedelete test.db2 do_execsql_test 2.0 { ATTACH 'test.db2' AS aux; CREATE TABLE aux.t3(x, y); INSERT INTO aux.t3 VALUES('x', 'y'); } do_catchsql_test 2.1 { CREATE TRIGGER tr2 AFTER INSERT ON t1 BEGIN UPDATE t1 SET b = y FROM aux.t3 WHERE k=new.a; END; } {1 {trigger tr2 cannot reference objects in database aux}} do_execsql_test 2.2 { CREATE TEMP TRIGGER tr2 AFTER INSERT ON t1 BEGIN UPDATE t1 SET b = y FROM aux.t3 WHERE a=new.a; END; INSERT INTO t1(a) VALUES(10), (20); SELECT * FROM t1; } { 1 {} one 2 {} two 3 {} three 4 {} four 5 {} {} 10 y {} 20 y {} } do_execsql_test 2.3 { CREATE TABLE link(f, t); INSERT INTO link VALUES(5, 2), (20, 10), (2, 1); CREATE TRIGGER tr3 BEFORE DELETE ON t1 BEGIN UPDATE t1 SET b=coalesce(old.b,old.c) FROM main.link WHERE a=t AND old.a=f; END; DELETE FROM t1 WHERE a=2; SELECT * FROM t1; } { 1 two one 3 {} three 4 {} four 5 {} {} 10 y {} 20 y {} } db close sqlite3 db "" do_catchsql_test 2.4 { ATTACH 'test.db' AS yyy; SELECT * FROM t1; } {1 {malformed database schema (tr3) - trigger tr3 cannot reference objects in database main}} #------------------------------------------------------------------------- reset_db forcedelete test.db2 do_execsql_test 3.0 { CREATE TABLE mmm(x, y); INSERT INTO mmm VALUES(1, 'one'); INSERT INTO mmm VALUES(2, 'two'); INSERT INTO mmm VALUES(3, 'three'); ATTACH 'test.db2' AS aux; CREATE TABLE aux.t1(a, b); CREATE TABLE aux.mmm(x, y); INSERT INTO aux.mmm VALUES(1, 'ONE'); INSERT INTO aux.mmm VALUES(2, 'TWO'); INSERT INTO aux.mmm VALUES(3, 'THREE'); CREATE TRIGGER aux.ttt AFTER INSERT ON t1 BEGIN UPDATE t1 SET b=y FROM mmm WHERE x=new.a AND a=new.a; END; INSERT INTO t1(a) VALUES (2); SELECT * FROM t1; } {2 TWO} #------------------------------------------------------------------------- # Test that INSTEAD OF UPDATE triggers on views work with UPDATE...FROM # statements. Including, if the library is built with ENABLE_HIDDEN_COLUMNS, # that they work correctly on views with hidden columns. # reset_db do_execsql_test 4.0 { CREATE TABLE t1(k, a, b); INSERT INTO t1 VALUES('a', 1, 'one'); INSERT INTO t1 VALUES('b', 2, 'two'); INSERT INTO t1 VALUES('c', 3, 'three'); INSERT INTO t1 VALUES('d', 4, 'four'); CREATE TABLE log(x); CREATE VIEW v1 AS SELECT k, a, b AS __hidden__b FROM t1; CREATE TRIGGER tr1 INSTEAD OF UPDATE ON v1 BEGIN INSERT INTO log VALUES( '('||old.a||','||old.__hidden__b||')->('||new.a||','||new.__hidden__b||')' ); END; } ifcapable hiddencolumns { do_execsql_test 4.1-hc-enabled { SELECT * FROM v1 } {a 1 b 2 c 3 d 4} } else { do_execsql_test 4.1-hc-disabled { SELECT * FROM v1 } {a 1 one b 2 two c 3 three d 4 four} } do_execsql_test 4.2 { UPDATE v1 SET a='xyz' WHERE k IN ('a', 'c'); SELECT * FROM log; DELETE FROM log; } { (1,one)->(xyz,one) (3,three)->(xyz,three) } do_execsql_test 4.3 { CREATE TABLE map(k, v); INSERT INTO map VALUES('b', 'twelve'); INSERT INTO map VALUES('d', 'fourteen'); UPDATE v1 SET a=map.v FROM map WHERE v1.k=map.k; SELECT * FROM log; DELETE FROM log; } { (2,two)->(twelve,two) (4,four)->(fourteen,four) } finish_test |
Added test/trustschema1.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 | # 2020-01-08 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # # Test cases for managing execution of code snippets found in untrusted # schemas. # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix trustschema1 # edgy functions used in generated columns # proc f1 {x} {return $x} do_test 1.100 { db function f1 -innocuous -deterministic f1 db function f2 -deterministic f1 db function f3 -directonly -deterministic f1 db eval { CREATE TABLE t1(a, b AS (f1(a+1)), c AS (f2(a+2))); INSERT INTO t1 VALUES(100),(200); } } {} do_catchsql_test 1.110 { SELECT a, b, c FROM t1; } {0 {100 101 102 200 201 202}} do_execsql_test 1.120 { PRAGMA trusted_schema=OFF; } {} do_catchsql_test 1.130 { SELECT a, b FROM t1; } {0 {100 101 200 201}} do_catchsql_test 1.140 { SELECT a, b, c FROM t1; } {1 {unsafe use of f2()}} do_catchsql_test 1.150 { PRAGMA trusted_schema=ON; DROP TABLE t1; CREATE TABLE t1(a, b AS (f3(a+1))); } {1 {unsafe use of f3()}} do_execsql_test 1.160 { PRAGMA trusted_schema=OFF; CREATE TEMP TABLE temp1(a,b AS (f3(a+1))); INSERT INTO temp1(a) VALUES(100),(900); SELECT * FROM temp1; } {100 101 900 901} # edgy functions used in CHECK constraints # do_catchsql_test 1.200 { PRAGMA trusted_schema=ON; CREATE TABLE t2(a,b,c,CHECK(f3(c)==c)); } {1 {unsafe use of f3()}} do_catchsql_test 1.210 { PRAGMA trusted_schema=Off; CREATE TABLE t2(a,b,c,CHECK(f2(c)==c)); } {1 {unsafe use of f2()}} do_catchsql_test 1.211 { PRAGMA trusted_schema=On; CREATE TABLE t2(a,b,c,CHECK(f2(c)==c)); } {0 {}} do_catchsql_test 1.220 { INSERT INTO t2 VALUES(1,2,3); SELECT * FROM t2; } {0 {1 2 3}} do_catchsql_test 1.230 { PRAGMA trusted_schema=off; INSERT INTO t2 VALUES(4,5,6); } {1 {unsafe use of f2()}} do_execsql_test 1.231 { SELECT * FROM t2; } {1 2 3} # Ok to put as many edgy functions as you want in a # TEMP table. do_execsql_test 1.240 { PRAGMA trusted_schema=OFF; CREATE TEMP TABLE temp2(a, b, CHECK(f3(b)==b)); INSERT INTO temp2(a,b) VALUES(1,2),('x','y'); SELECT * FROM temp2; } {1 2 x y} # edgy functions used in DEFAULT constraints # do_catchsql_test 1.300 { CREATE TABLE t3(a,b DEFAULT(f2(25))); } {0 {}} do_catchsql_test 1.310 { PRAGMA trusted_schema=Off; INSERT INTO t3(a) VALUES(1); } {1 {unsafe use of f2()}} do_catchsql_test 1.311 { INSERT INTO t3(a,b) VALUES(1,2); } {0 {}} do_execsql_test 1.320 { CREATE TEMP TABLE temp3(a, b DEFAULT(f3(31))); INSERT INTO temp3(a) VALUES(22); SELECT * FROM temp3; } {22 31} # edgy functions used in partial indexes. # do_execsql_test 1.400 { CREATE TABLE t4(a,b,c); INSERT INTO t4 VALUES(1,2,3),('a','b','c'),(4,'d',0); SELECT * FROM t4; CREATE TEMP TABLE temp4(a,b,c); INSERT INTO temp4 SELECT * FROM t4; } {1 2 3 a b c 4 d 0} do_catchsql_test 1.410 { CREATE INDEX t4a ON t4(a) WHERE f3(c); } {1 {unsafe use of f3()}} do_catchsql_test 1.420 { PRAGMA trusted_schema=OFF; CREATE INDEX t4a ON t4(a) WHERE f2(c); } {1 {unsafe use of f2()}} do_execsql_test 1.421 { CREATE INDEX t4a ON t4(a) WHERE f1(c); SELECT a FROM t4 WHERE f1(c) ORDER BY a; } {1} do_execsql_test 1.430 { PRAGMA trusted_schema=ON; CREATE INDEX t4b ON t4(b) WHERE f2(c); SELECT b FROM t4 WHERE f2(c) ORDER BY b; } {2} do_execsql_test 1.440 { PRAGMA trusted_schema=OFF; CREATE INDEX temp4a ON temp4(a) WHERE f3(c); SELECT a FROM temp4 WHERE f2(c) ORDER BY a; } {1} # edgy functions used in index expressions # do_execsql_test 1.500 { CREATE TABLE t5(a,b,c); INSERT INTO t5 VALUES(1,2,3),(4,5,6),(7,0,-3); SELECT * FROM t5; CREATE TEMP TABLE temp5(a,b,c); INSERT INTO temp5 SELECT * FROM t5; } {1 2 3 4 5 6 7 0 -3} do_catchsql_test 1.510 { CREATE INDEX t5x1 ON t5(a+f3(b)); } {1 {unsafe use of f3()}} do_catchsql_test 1.520 { PRAGMA trusted_schema=OFF; CREATE INDEX t5x1 ON t5(a+f2(b)); } {1 {unsafe use of f2()}} do_execsql_test 1.521 { CREATE INDEX t5x1 ON t5(a+f1(b)); SELECT * FROM t5 INDEXED BY t5x1 WHERE a+f1(b)=3; } {1 2 3} do_execsql_test 1.530 { PRAGMA trusted_schema=ON; CREATE INDEX t5x2 ON t5(b+f2(c)); SELECT * FROM t5 INDEXED BY t5x2 WHERE b+f2(c)=11; } {4 5 6} do_execsql_test 1.540 { PRAGMA trusted_schema=OFF; CREATE INDEX temp5x1 ON temp5(a+f3(b)); SELECT * FROM temp5 INDEXED BY temp5x1 WHERE a+f3(b)=7; } {7 0 -3} # edgy functions in VIEWs # reset_db db function f1 -innocuous -deterministic f1 db function f2 -deterministic f1 db function f3 -directonly -deterministic f1 do_execsql_test 2.100 { CREATE TABLE t1(a,b,c); INSERT INTO t1 VALUES(1,2,3),(100,50,75),(-11,22,-33); CREATE VIEW v1a AS SELECT f3(a+b) FROM t1; SELECT f3(a+b) FROM t1; } {3 150 11} do_catchsql_test 2.110 { PRAGMA trusted_schema=ON; SELECT * FROM v1a; } {1 {unsafe use of f3()}} do_catchsql_test 2.111 { PRAGMA trusted_schema=OFF; SELECT * FROM v1a; } {1 {unsafe use of f3()}} do_execsql_test 2.120 { DROP VIEW v1a; CREATE TEMP VIEW v1a AS SELECT f3(a+b) FROM t1; SELECT * FROM v1a; } {3 150 11} do_execsql_test 2.130 { CREATE VIEW v1b AS SELECT f2(b+c) FROM t1; SELECT f2(b+c) FROM t1; } {5 125 -11} do_catchsql_test 2.140 { PRAGMA trusted_schema=ON; SELECT * FROM v1b; } {0 {5 125 -11}} do_catchsql_test 2.141 { PRAGMA trusted_schema=OFF; SELECT * FROM v1b; } {1 {unsafe use of f2()}} do_execsql_test 2.150 { DROP VIEW v1b; CREATE TEMP VIEW v1b AS SELECT f2(b+c) FROM t1; SELECT * FROM v1b; } {5 125 -11} # edgy functions inside of triggers # do_execsql_test 3.100 { DELETE FROM t1; CREATE TABLE t2(x); CREATE TRIGGER r1 AFTER INSERT ON t1 BEGIN INSERT INTO t2(x) SELECT f3(new.a); END; } {} do_catchsql_test 3.110 { INSERT INTO t1 VALUES(7,6,5); } {1 {unsafe use of f3()}} do_execsql_test 3.111 { SELECT * FROM t1; SELECT * FROM t2; } {} do_execsql_test 3.120 { DROP TRIGGER r1; CREATE TRIGGER r1 AFTER INSERT ON t1 BEGIN INSERT INTO t2(x) SELECT f2(new.a)+100; END; PRAGMA trusted_schema=ON; INSERT INTO t1 VALUES(7,6,5); SELECT * FROM t1, t2; } {7 6 5 107} do_catchsql_test 3.130 { DELETE FROM t1; DELETE FROM t2; PRAGMA trusted_schema=OFF; INSERT INTO t1 VALUES(7,6,5); } {1 {unsafe use of f2()}} do_execsql_test 3.131 { SELECT * FROM t1; SELECT * FROM t2; } {} finish_test |
Changes to test/tt3_checkpoint.c.
︙ | ︙ | |||
71 72 73 74 75 76 77 | Sqlite db = {0}; opendb(&err, &db, "test.db", 0); while( !timetostop(&err) ){ i64 iCount1, iCount2; sql_script(&err, &db, "BEGIN"); iCount1 = execsql_i64(&err, &db, "SELECT count(x) FROM t1"); | | | 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 | Sqlite db = {0}; opendb(&err, &db, "test.db", 0); while( !timetostop(&err) ){ i64 iCount1, iCount2; sql_script(&err, &db, "BEGIN"); iCount1 = execsql_i64(&err, &db, "SELECT count(x) FROM t1"); sqlite3_sleep(CHECKPOINT_STARVATION_READMS); iCount2 = execsql_i64(&err, &db, "SELECT count(x) FROM t1"); sql_script(&err, &db, "COMMIT"); if( iCount1!=iCount2 ){ test_error(&err, "Isolation failure - %lld %lld", iCount1, iCount2); } } |
︙ | ︙ | |||
103 104 105 106 107 108 109 | "CREATE TABLE t1(x);" ); setstoptime(&err, nMs); for(i=0; i<4; i++){ launch_thread(&err, &threads, checkpoint_starvation_reader, 0); | | | 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 | "CREATE TABLE t1(x);" ); setstoptime(&err, nMs); for(i=0; i<4; i++){ launch_thread(&err, &threads, checkpoint_starvation_reader, 0); sqlite3_sleep(CHECKPOINT_STARVATION_READMS/4); } sqlite3_wal_hook(db.db, checkpoint_starvation_walhook, (void *)p); while( !timetostop(&err) ){ sql_script(&err, &db, "INSERT INTO t1 VALUES(randomblob(1200))"); nInsert++; } |
︙ | ︙ |
Added test/tt3_shared.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 | /* ** 2020 September 5 ** ** 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. ** ************************************************************************* ** ** */ /* */ static char *shared_thread1(int iTid, void *pArg){ Error err = {0}; /* Error code and message */ while( !timetostop(&err) ){ Sqlite db = {0}; /* SQLite database connection */ opendb(&err, &db, "test.db", 0); sql_script(&err, &db, "SELECT * FROM t1"); closedb(&err, &db); } print_and_free_err(&err); return sqlite3_mprintf("done!"); } static void shared1(int nMs){ Error err = {0}; Sqlite db = {0}; /* SQLite database connection */ Threadset threads = {0}; int ii; opendb(&err, &db, "test.db", 1); sql_script(&err, &db, "CREATE TABLE t1(x)"); closedb(&err, &db); setstoptime(&err, nMs); sqlite3_enable_shared_cache(1); for(ii=0; ii<5; ii++){ launch_thread(&err, &threads, shared_thread1, 0); } join_all_threads(&err, &threads); sqlite3_enable_shared_cache(0); print_and_free_err(&err); } |
Changes to test/tt3_stress.c.
︙ | ︙ | |||
37 38 39 40 41 42 43 | ** Thread 2. Open and close database connections. */ static char *stress_thread_2(int iTid, void *pArg){ Error err = {0}; /* Error code and message */ Sqlite db = {0}; /* SQLite database connection */ while( !timetostop(&err) ){ opendb(&err, &db, "test.db", 0); | | | 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | ** Thread 2. Open and close database connections. */ static char *stress_thread_2(int iTid, void *pArg){ Error err = {0}; /* Error code and message */ Sqlite db = {0}; /* SQLite database connection */ while( !timetostop(&err) ){ opendb(&err, &db, "test.db", 0); sql_script(&err, &db, "SELECT * FROM sqlite_schema;"); clear_error(&err, SQLITE_LOCKED); closedb(&err, &db); } print_and_free_err(&err); return sqlite3_mprintf("ok"); } |
︙ | ︙ | |||
262 263 264 265 266 267 268 | static char *stress2_workload19(int iTid, void *pArg){ Error err = {0}; /* Error code and message */ Sqlite db = {0}; /* SQLite database connection */ const char *zDb = (const char*)pArg; while( !timetostop(&err) ){ opendb(&err, &db, zDb, 0); | | | 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 | static char *stress2_workload19(int iTid, void *pArg){ Error err = {0}; /* Error code and message */ Sqlite db = {0}; /* SQLite database connection */ const char *zDb = (const char*)pArg; while( !timetostop(&err) ){ opendb(&err, &db, zDb, 0); sql_script(&err, &db, "SELECT * FROM sqlite_schema;"); clear_error(&err, SQLITE_LOCKED); closedb(&err, &db); } print_and_free_err(&err); return sqlite3_mprintf("ok"); } |
︙ | ︙ | |||
358 359 360 361 362 363 364 | launch_thread(&err, &threads, stress2_workload19, (void*)zDb); launch_thread(&err, &threads, stress2_workload19, (void*)zDb); join_all_threads(&err, &threads); sqlite3_enable_shared_cache(0); print_and_free_err(&err); } | < < < < | 358 359 360 361 362 363 364 | launch_thread(&err, &threads, stress2_workload19, (void*)zDb); launch_thread(&err, &threads, stress2_workload19, (void*)zDb); join_all_threads(&err, &threads); sqlite3_enable_shared_cache(0); print_and_free_err(&err); } |
Changes to test/tt3_vacuum.c.
︙ | ︙ | |||
19 20 21 22 23 24 25 | ** */ static char *vacuum1_thread_writer(int iTid, void *pArg){ Error err = {0}; /* Error code and message */ Sqlite db = {0}; /* SQLite database connection */ | < > | 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | ** */ static char *vacuum1_thread_writer(int iTid, void *pArg){ Error err = {0}; /* Error code and message */ Sqlite db = {0}; /* SQLite database connection */ i64 i = 0; opendb(&err, &db, "test.db", 0); while( !timetostop(&err) ){ i++; /* Insert lots of rows. Then delete some. */ execsql(&err, &db, "WITH loop(i) AS (SELECT 1 UNION ALL SELECT i+1 FROM loop WHERE i<100) " "INSERT INTO t1 SELECT randomblob(50), randomblob(2500) FROM loop" |
︙ | ︙ |
Added test/unionall.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 | # 2020-12-16 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this file is flattening UNION ALL sub-queries. # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix unionall do_execsql_test 1.0 { CREATE TABLE t1_a(a INTEGER PRIMARY KEY, b TEXT); CREATE TABLE t1_b(c INTEGER PRIMARY KEY, d TEXT); CREATE TABLE t1_c(e INTEGER PRIMARY KEY, f TEXT); INSERT INTO t1_a VALUES(1, 'one'), (4, 'four'); INSERT INTO t1_b VALUES(2, 'two'), (5, 'five'); INSERT INTO t1_c VALUES(3, 'three'), (6, 'six'); CREATE VIEW t1 AS SELECT a, b FROM t1_a UNION ALL SELECT c, d FROM t1_b UNION ALL SELECT e, f FROM t1_c; CREATE TABLE i1(x); INSERT INTO i1 VALUES(2), (5), (6), (1); } do_execsql_test 1.1 { SELECT a, b FROM ( SELECT a, b FROM t1_a UNION ALL SELECT c, d FROM t1_b UNION ALL SELECT e, f FROM t1_c ) ORDER BY a } { 1 one 2 two 3 three 4 four 5 five 6 six } do_execsql_test 1.2 { SELECT a, b FROM t1 ORDER BY a } { 1 one 2 two 3 three 4 four 5 five 6 six } do_execsql_test 1.3 { SELECT a, b FROM i1, t1 WHERE a=x ORDER BY a } {1 one 2 two 5 five 6 six} #------------------------------------------------------------------------- reset_db do_execsql_test 2.1.0 { CREATE TABLE t1(x, y); INSERT INTO t1 VALUES(1, 'one'); INSERT INTO t1 VALUES(1, 'ONE'); INSERT INTO t1 VALUES(2, 'two'); INSERT INTO t1 VALUES(2, 'TWO'); INSERT INTO t1 VALUES(3, 'three'); INSERT INTO t1 VALUES(3, 'THREE'); } do_execsql_test 2.1.1 { WITH s(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<3 ) SELECT * FROM ( SELECT 0 AS i UNION ALL SELECT i FROM s UNION ALL SELECT 0 ), t1 WHERE x=i; } { 1 1 one 1 1 ONE 2 2 two 2 2 TWO 3 3 three 3 3 THREE } do_catchsql_test 2.1.2 { WITH s(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<3 UNION ALL SELECT 4 ) SELECT * FROM s, t1 WHERE x=i; } {1 {circular reference: s}} do_execsql_test 2.2.0 { CREATE TABLE t2_a(k INTEGER PRIMARY KEY, v TEXT); CREATE TABLE t2_b(k INTEGER PRIMARY KEY, v TEXT); CREATE VIEW t2 AS SELECT * FROM t2_a UNION ALL SELECT * FROM t2_b; CREATE TRIGGER t2_insert INSTEAD OF INSERT ON t2 BEGIN INSERT INTO t2_a SELECT new.k, new.v WHERE (new.k%2)==0; INSERT INTO t2_b SELECT new.k, new.v WHERE (new.k%2)==1; END; INSERT INTO t2 VALUES(5, 'v'), (4, 'iv'), (3, 'iii'), (2, 'ii'); } do_execsql_test 2.2.1 { SELECT * FROM t1, t2 WHERE x=k; } { 2 two 2 ii 2 TWO 2 ii 3 three 3 iii 3 THREE 3 iii } do_execsql_test 2.2.2 { SELECT * FROM t1 LEFT JOIN t2 ON (x=k); } { 1 one {} {} 1 ONE {} {} 2 two 2 ii 2 TWO 2 ii 3 three 3 iii 3 THREE 3 iii } do_execsql_test 2.2.3 { SELECT x1.*, x2.* FROM t2 AS x1, t2 AS x2 WHERE x1.k=x2.k+1 } { 4 iv 3 iii 3 iii 2 ii 5 v 4 iv } do_execsql_test 2.2.4 { SELECT * FROM t1, t2 WHERE x=k ORDER BY y; } { 3 THREE 3 iii 2 TWO 2 ii 3 three 3 iii 2 two 2 ii } do_execsql_test 2.2.5 { SELECT * FROM t1, t2 WHERE x=k ORDER BY y||''; } { 3 THREE 3 iii 2 TWO 2 ii 3 three 3 iii 2 two 2 ii } do_execsql_test 2.2.6 { SELECT * FROM t1, t2 WHERE x=k ORDER BY v } { 2 two 2 ii 2 TWO 2 ii 3 three 3 iii 3 THREE 3 iii } do_execsql_test 2.2.7 { SELECT * FROM t1, t2 WHERE x=k ORDER BY v||'' } { 2 two 2 ii 2 TWO 2 ii 3 three 3 iii 3 THREE 3 iii } do_execsql_test 2.2.8 { SELECT * FROM t1, t2 WHERE x=k ORDER BY k,v||'' } { 2 two 2 ii 2 TWO 2 ii 3 three 3 iii 3 THREE 3 iii } do_execsql_test 2.2.9a { SELECT * FROM t1, t2 ORDER BY +k } { 1 one 2 ii 1 ONE 2 ii 2 two 2 ii 2 TWO 2 ii 3 three 2 ii 3 THREE 2 ii 1 one 3 iii 1 ONE 3 iii 2 two 3 iii 2 TWO 3 iii 3 three 3 iii 3 THREE 3 iii 1 one 4 iv 1 ONE 4 iv 2 two 4 iv 2 TWO 4 iv 3 three 4 iv 3 THREE 4 iv 1 one 5 v 1 ONE 5 v 2 two 5 v 2 TWO 5 v 3 three 5 v 3 THREE 5 v } do_execsql_test 2.2.9b { SELECT * FROM t1, t2 ORDER BY k } { 1 one 2 ii 1 ONE 2 ii 2 two 2 ii 2 TWO 2 ii 3 three 2 ii 3 THREE 2 ii 1 one 3 iii 1 ONE 3 iii 2 two 3 iii 2 TWO 3 iii 3 three 3 iii 3 THREE 3 iii 1 one 4 iv 1 ONE 4 iv 2 two 4 iv 2 TWO 4 iv 3 three 4 iv 3 THREE 4 iv 1 one 5 v 1 ONE 5 v 2 two 5 v 2 TWO 5 v 3 three 5 v 3 THREE 5 v } #------------------------------------------------------------------------- reset_db do_execsql_test 3.0 { CREATE TABLE t1(c INTEGER PRIMARY KEY, d TEXT); INSERT INTO t1 VALUES(1,2); CREATE TABLE t3_a(k INTEGER PRIMARY KEY, v TEXT); INSERT INTO t3_a VALUES(2,'ii'); CREATE TABLE t3_b(k INTEGER PRIMARY KEY, v TEXT); CREATE VIEW t3 AS SELECT * FROM t3_a UNION ALL SELECT * FROM t3_b; } {} do_execsql_test 3.1 { SELECT * FROM t1, t3 ORDER BY k; } {1 2 2 ii} reset_db do_execsql_test 4.0 { CREATE TABLE t1_a(a INTEGER PRIMARY KEY, b TEXT); INSERT INTO t1_a VALUES(123, 't1_a'); CREATE TABLE t1_b(c INTEGER PRIMARY KEY, d TEXT); CREATE VIEW t1 AS SELECT a, b FROM t1_a UNION ALL SELECT c, d FROM t1_b; CREATE TABLE t3_a(k INTEGER PRIMARY KEY, v TEXT); INSERT INTO t3_a VALUES(456, 't3_a'); CREATE TABLE t3_b(k INTEGER PRIMARY KEY, v TEXT); CREATE VIEW t3 AS SELECT * FROM t3_a UNION ALL SELECT * FROM t3_b; } do_execsql_test 4.1 { SELECT * FROM t1, t3 ORDER BY k; } {123 t1_a 456 t3_a} do_execsql_test 4.2 { SELECT * FROM (SELECT * FROM t1, t3) ORDER BY k; } {123 t1_a 456 t3_a} do_execsql_test 4.3 { SELECT * FROM (SELECT * FROM t1, t3), ( SELECT max(a) OVER () FROM t1 UNION ALL SELECT min(a) OVER () FROM t1 ) ORDER BY k; } { 123 t1_a 456 t3_a 123 123 t1_a 456 t3_a 123 } do_execsql_test 4.3 { SELECT * FROM (SELECT * FROM t1, t3), ( SELECT group_concat(a) OVER (ORDER BY a), group_concat(a) OVER (ORDER BY a), group_concat(a) OVER (ORDER BY a), group_concat(a) OVER (ORDER BY a), group_concat(a) OVER (ORDER BY a), group_concat(a) OVER (ORDER BY a), group_concat(a) OVER (ORDER BY a), group_concat(a) OVER (ORDER BY a), group_concat(a) OVER (ORDER BY a) FROM t1 ) ORDER BY k; } { 123 t1_a 456 t3_a 123 123 123 123 123 123 123 123 123 } do_execsql_test 4.3 { SELECT * FROM (SELECT * FROM t1, t3) AS o, ( SELECT * FROM t1 LEFT JOIN t3 ON a=k ); } { 123 t1_a 456 t3_a 123 t1_a {} {} } # 2020-12-30: dbsqlfuzz find reset_db do_execsql_test 5.1 { CREATE TABLE t1_a(a INTEGER PRIMARY KEY, b TEXT); INSERT INTO t1_a VALUES(1,'one'); INSERT INTO t1_a VALUES(0,NULL); CREATE TABLE t1_b(c INTEGER PRIMARY KEY, d TEXT); INSERT INTO t1_b VALUES(2,'two'); INSERT INTO t1_b VALUES(5,'five'); CREATE TABLE t1_c(e INTEGER PRIMARY KEY, f TEXT); INSERT INTO t1_c VALUES(3,'three'); INSERT INTO t1_c VALUES(6,'six'); CREATE TABLE t2(k,v); INSERT INTO t2 VALUES(5,'v'); INSERT INTO t2 VALUES(4,'iv'); INSERT INTO t2 VALUES(3,'iii'); INSERT INTO t2 VALUES(2,'ii'); CREATE TABLE t3_a(k INTEGER PRIMARY KEY, v TEXT); INSERT INTO t3_a VALUES(2,'ii'); INSERT INTO t3_a VALUES(4,'iv'); CREATE TABLE t3_b(k INTEG5R PRIMARY KEY, v TEXT); INSERT INTO t3_b VALUES(NULL,'iii'); INSERT INTO t3_b VALUES(NULL,'v'); CREATE VIEW t1 AS SELECT a, b FROM t1_a UNION ALL SELECT c, d FROM t1_b UNION ALL SELECT e, f FROM t1_c; CREATE VIEW t3 AS SELECT * FROM t3_a UNION ALL SELECT * FROM t3_b; CREATE TRIGGER t3_insert INSTEAD OF INSERT ON t3 BEGIN INSERT INTO t3_a SELECT new.k, new.v WHERE (new.k%2)==0; INSERT INTO t3_b SELECT new.k, new.v WHERE (new.k%2)==1; END; } {} do_execsql_test 5.10 { SELECT *, '+' FROM t1 LEFT JOIN t2 ON (a NOT IN(SELECT v FROM t1, t3 WHERE a=k)=NOT EXISTS(SELECT 1 FROM t1 LEFT JOIN t3 ON (a=k))); } {0 {} {} {} + 1 one {} {} + 2 two {} {} + 5 five {} {} + 3 three {} {} + 6 six {} {} +} do_execsql_test 5.20 { SELECT *, '+' FROM t1 LEFT JOIN t3 ON (a NOT IN(SELECT v FROM t1 LEFT JOIN t2 ON (a=k))=k); } {0 {} {} {} + 1 one {} {} + 2 two {} {} + 5 five {} {} + 3 three {} {} + 6 six {} {} +} reset_db do_execsql_test 6.0 { CREATE TABLE t1(a,b); INSERT INTO t1 VALUES(1,2); CREATE TABLE t2(a,b); INSERT INTO t2 VALUES(3,4); CREATE TABLE t3(a,b); INSERT INTO t3 VALUES(5,6); CREATE TABLE t4(a,b); INSERT INTO t4 VALUES(7,8); CREATE TABLE t5(a,b); INSERT INTO t5 VALUES(9,10); } do_execsql_test 6.1 { WITH x(c) AS ( SELECT 1000 FROM t1 UNION ALL SELECT 800 FROM t2 ), y(d) AS ( SELECT 100 FROM t3 UNION ALL SELECT 400 FROM t4 ) SELECT * FROM t5, x, y; } { 9 10 1000 100 9 10 1000 400 9 10 800 100 9 10 800 400 } # 2021-04-26 dbsqlfuzz 88ed5c66789fced139d148aed823cba7c0926dd7 reset_db do_execsql_test 7.1 { WITH c1(x) AS (VALUES(0) UNION ALL SELECT 100+x FROM c1 WHERE x<100 UNION ALL SELECT 1+x FROM c1 WHERE x<1) SELECT x, y, '|' FROM c1 AS x1, (SELECT x+1 AS y FROM c1 WHERE x<1 UNION ALL SELECT 1+x FROM c1 WHERE 1<x) AS x2 ORDER BY x, y; } {0 1 | 0 101 | 0 102 | 1 1 | 1 101 | 1 102 | 100 1 | 100 101 | 100 102 | 101 1 | 101 101 | 101 102 |} finish_test |
Added test/unionall2.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 | # 2020-12-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 file is flattening UNION ALL sub-queries. # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix unionall2 do_execsql_test 1.0 { CREATE TABLE t1(a, b); CREATE TABLE t2(c, d); CREATE VIEW v1 AS SELECT * FROM t1, t2; CREATE VIEW v2 AS SELECT * FROM t1, t2; CREATE VIEW vA AS SELECT * FROM v1, ( SELECT * FROM t1 LEFT JOIN t2 ON (a=c) ) UNION ALL SELECT * FROM v1, v2 } do_execsql_test 1.1 { SELECT 1 FROM vA, vA, vA, vA, vA, vA, vA, vA, vA, vA } #------------------------------------------------------------------------- do_execsql_test 2.1 { CREATE TABLE y1(a INTEGER, b); CREATE TABLE y2(c INTEGER, d); CREATE TABLE x3_a(a INTEGER PRIMARY KEY, b TEXT); CREATE TABLE x3_b(c INTEGER PRIMARY KEY, d TEXT); } do_execsql_test 2.2 { SELECT * FROM y1 CROSS JOIN y2 WHERE y1.a=y2.c AND y2.c IN ( SELECT a FROM x3_a UNION ALL SELECT c FROM x3_b ORDER BY 1 ) } finish_test |
Added test/unionallfault.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 | # 2020-12-16 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix unionallfault do_execsql_test 1.0 { CREATE TABLE t1(x,y,z); CREATE TABLE t3(x,y,z); } faultsim_save_and_close do_faultsim_test 1 -faults oom-t* -prep { faultsim_restore_and_reopen } -body { execsql { SELECT * FROM t1, ( SELECT x FROM t1 UNION ALL SELECT y FROM t1 ), t3 } } -test { faultsim_test_result {0 {}} } finish_test |
Changes to test/unionvtab.test.
︙ | ︙ | |||
369 370 371 372 373 374 375 | do_execsql_test 4.3.3 { SELECT * FROM sl WHERE rowid<=-9223372036854775808 } { -9223372036854775808 one } do_execsql_test 4.3.4 { SELECT * FROM sl WHERE rowid<-9223372036854775808 | | | | 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 | do_execsql_test 4.3.3 { SELECT * FROM sl WHERE rowid<=-9223372036854775808 } { -9223372036854775808 one } do_execsql_test 4.3.4 { SELECT * FROM sl WHERE rowid<-9223372036854775808 } {} do_execsql_test 4.4.1 { SELECT * FROM sl WHERE rowid<9223372036854775807 } { -9223372036854775808 one -9223372036854775807 two -9223372036854775806 three 9223372036854775805 four 9223372036854775806 five } do_execsql_test 4.4.2 { SELECT * FROM sl WHERE rowid<=9223372036854775807 } { -9223372036854775808 one -9223372036854775807 two -9223372036854775806 three 9223372036854775805 four 9223372036854775806 five 9223372036854775807 six } do_execsql_test 4.4.3 { SELECT * FROM sl WHERE rowid>=9223372036854775807 } { 9223372036854775807 six } do_execsql_test 4.4.4 { SELECT * FROM sl WHERE rowid>9223372036854775807 } {} #------------------------------------------------------------------------- # More than 8 source tables. # do_execsql_test 5.0 { CREATE TABLE c0(one, two INTEGER PRIMARY KEY); CREATE TABLE c1(one, two INTEGER PRIMARY KEY); |
︙ | ︙ |
Changes to test/unordered.test.
︙ | ︙ | |||
36 37 38 39 40 41 42 | if {$idxmode == "unordered"} { execsql { UPDATE sqlite_stat1 SET stat = stat || ' unordered' } } db close sqlite3 db test.db foreach {tn sql r(ordered) r(unordered)} { 1 "SELECT * FROM t1 ORDER BY a" | | | | | | | | | | | | | | | | 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 | if {$idxmode == "unordered"} { execsql { UPDATE sqlite_stat1 SET stat = stat || ' unordered' } } db close sqlite3 db test.db foreach {tn sql r(ordered) r(unordered)} { 1 "SELECT * FROM t1 ORDER BY a" {SCAN t1 USING INDEX i1} {SCAN t1*USE TEMP B-TREE FOR ORDER BY} 2 "SELECT * FROM t1 WHERE a > 100" {SEARCH t1 USING INDEX i1 (a>?)} {SCAN t1} 3 "SELECT * FROM t1 WHERE a = ? ORDER BY rowid" {SEARCH t1 USING INDEX i1 (a=?)} {SEARCH t1 USING INDEX i1 (a=?)*USE TEMP B-TREE FOR ORDER BY} 4 "SELECT max(a) FROM t1" {SEARCH t1 USING COVERING INDEX i1} {SEARCH t1} 5 "SELECT group_concat(b) FROM t1 GROUP BY a" {SCAN t1 USING INDEX i1} {SCAN t1*USE TEMP B-TREE FOR GROUP BY} 6 "SELECT * FROM t1 WHERE a = ?" {SEARCH t1 USING INDEX i1 (a=?)} {SEARCH t1 USING INDEX i1 (a=?)} 7 "SELECT count(*) FROM t1" {SCAN t1 USING COVERING INDEX i1} {SCAN t1} } { do_eqp_test 1.$idxmode.$tn $sql $r($idxmode) } } finish_test |
Changes to test/update.test.
︙ | ︙ | |||
615 616 617 618 619 620 621 | } {1 {no such column: nosuchcol}} } ;# ifcapable {trigger} # Ticket [https://www.sqlite.org/src/tktview/43107840f1c02] on 2014-10-29 # An assertion fault on UPDATE # | > | | | | | | | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | } {1 {no such column: nosuchcol}} } ;# ifcapable {trigger} # Ticket [https://www.sqlite.org/src/tktview/43107840f1c02] on 2014-10-29 # An assertion fault on UPDATE # ifcapable altertable { do_execsql_test update-15.1 { CREATE TABLE t15(a INTEGER PRIMARY KEY, b); INSERT INTO t15(a,b) VALUES(10,'abc'),(20,'def'),(30,'ghi'); ALTER TABLE t15 ADD COLUMN c; CREATE INDEX t15c ON t15(c); INSERT INTO t15(a,b) VALUES(5,'zyx'),(15,'wvu'),(25,'tsr'),(35,'qpo'); UPDATE t15 SET c=printf("y%d",a) WHERE c IS NULL; SELECT a,b,c,'|' FROM t15 ORDER BY a; } {5 zyx y5 | 10 abc y10 | 15 wvu y15 | 20 def y20 | 25 tsr y25 | 30 ghi y30 | 35 qpo y35 |} } # Unreleased bug in UPDATE caused by the UPSERT changes. # Found by OSSFuzz as soon as the UPSERT changes landed on trunk. # Never released into the wild. 2018-04-19. # do_execsql_test update-16.1 { CREATE TABLE t16(a INTEGER PRIMARY KEY ON CONFLICT REPLACE, b UNIQUE); INSERT INTO t16(a,b) VALUES(1,2),(3,4),(5,6); UPDATE t16 SET a=a; SELECT * FROM t16 ORDER BY +a; } {1 2 3 4 5 6} # 2019-12-09 gramfuzz find # If a partial index that does not reference any column of its table (which is you # must admit is a very strange index, but one that is allowed) is used by an UPDATE # statement, void the use of OP_DeferredSeek on the main loop, as the seek will not # be resolved prior to the OP_Delete. # do_execsql_test update-17.10 { DROP TABLE IF EXISTS t1; CREATE TABLE t1(x,y); INSERT INTO t1(x) VALUES(1); CREATE INDEX t1x1 ON t1(1) WHERE 3; UPDATE t1 SET x=2, y=3 WHERE 3; SELECT * FROM t1; } {2 3} # 2019-12-22 ticket 5ad2aa6921faa1ee # Make a hard-copy of values that need to be run through OP_RealAffinity # rather than a soft-copy. This is not strictly necessary, but it avoids # a memory-accounting assert(). # reset_db do_execsql_test update-18.10 { PRAGMA encoding = 'UTF16'; CREATE TABLE t0(c0 REAL, c1); INSERT INTO t0(c0,c1) VALUES('xyz',11),('uvw',22); CREATE INDEX i0 ON t0(c1) WHERE c0 GLOB 3; CREATE INDEX i1 ON t0(c0,c1) WHERE typeof(c0)='text' AND typeof(c1)='integer'; UPDATE t0 SET c1=345; SELECT * FROM t0; } {xyz 345 uvw 345} # 2019-12-22 ticket c62c5e58524b204d # This is really the same underlying problem as 5ad2aa6921faa1ee # reset_db do_execsql_test update-18.20 { PRAGMA encoding = 'utf16'; CREATE TABLE t0(c0 TEXT); CREATE INDEX i0 ON t0(0 LIKE COALESCE(c0, 0)); INSERT INTO t0(c0) VALUES (0), (0); SELECT * FROM t0; } {0 0} # 2019-12-28 assertion fault reported by Yongheng # Similar to ticket ec8abb025e78f40c # An UPDATE was reaching the OP_Delete after running OP_DeferredSeek # without ever hitting an OP_Column. The enhanced solution is to # fix OP_Delete so that it can do the seek itself. # reset_db do_execsql_test update-19.10 { CREATE TABLE t1( a TEXT, b INTEGER PRIMARY KEY UNIQUE ); INSERT INTO t1 VALUES(1,2); UPDATE t1 SET a = quote(b) WHERE b>=2; SELECT * FROM t1; } {2 2} # 2019-12-29 ticket https://www.sqlite.org/src/info/314cc133e5ada126 # REPLACE conflict resolution during an UPDATE causes a DELETE trigger # to fire. If that DELETE trigger subsequently modifies the row # being updated, bad things can happen. Prevent this by prohibiting # triggers from making changes to the table being updated while doing # REPLACE conflict resolution on the UPDATE. # # See also tickets: # https://www.sqlite.org/src/info/c1e19e12046d23fe 2019-10-25 # https://www.sqlite.org/src/info/a8a4847a2d96f5de 2019-10-16 # reset_db do_execsql_test update-20.10 { PRAGMA recursive_triggers = true; CREATE TABLE t1(a UNIQUE ON CONFLICT REPLACE, b); INSERT INTO t1(a,b) VALUES(4,12),(9,13); CREATE INDEX i0 ON t1(b); CREATE TRIGGER tr0 DELETE ON t1 BEGIN UPDATE t1 SET b = a; END; PRAGMA integrity_check; } {ok} do_catchsql_test update-20.20 { UPDATE t1 SET a=0; } {1 {constraint failed}} do_execsql_test update-20.30 { PRAGMA integrity_check; } {ok} finish_test |
Changes to test/update2.test.
︙ | ︙ | |||
211 212 213 214 215 216 217 218 219 | do_execsql_test 6.1 { UPDATE d1 SET a = a+2 WHERE a>0 OR b>0; } do_execsql_test 6.2 { SELECT * FROM d1; } {3 2} finish_test | > > > > > > > > > > > > > > > > | 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 | do_execsql_test 6.1 { UPDATE d1 SET a = a+2 WHERE a>0 OR b>0; } do_execsql_test 6.2 { SELECT * FROM d1; } {3 2} # 2019-01-22 Bug in UPDATE OR REPLACE discovered by the # Matt Denton's LPM fuzzer # do_execsql_test 7.100 { DROP TABLE IF EXISTS t1; CREATE TABLE t1(x,y); CREATE UNIQUE INDEX t1x1 ON t1(x) WHERE x IS NOT NULL; INSERT INTO t1(x) VALUES(NULL),(NULL); CREATE INDEX t1x2 ON t1(y); SELECT quote(x), quote(y), '|' FROM t1; } {NULL NULL | NULL NULL |} do_execsql_test 7.110 { UPDATE OR REPLACE t1 SET x=1; SELECT quote(x), quote(y), '|' FROM t1; } {1 NULL |} finish_test |
Added test/upfrom1.tcl.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 | # 2020 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. # #*********************************************************************** # source [file join [file dirname $argv0] pg_common.tcl] #========================================================================= start_test upfrom1 "2020 April 22" foreach {tn wo} { 1 "WITHOUT ROWID" 2 "" } { eval [string map [list %TN% $tn %WITHOUT_ROWID% $wo] { execsql_test 1.%TN%.0 { DROP TABLE IF EXISTS t2; CREATE TABLE t2(a INTEGER PRIMARY KEY, b INTEGER, c INTEGER) %WITHOUT_ROWID%; INSERT INTO t2 VALUES(1, 2, 3); INSERT INTO t2 VALUES(4, 5, 6); INSERT INTO t2 VALUES(7, 8, 9); DROP TABLE IF EXISTS chng; CREATE TABLE chng(a INTEGER, b INTEGER, c INTEGER); INSERT INTO chng VALUES(1, 100, 1000); INSERT INTO chng VALUES(7, 700, 7000); } execsql_test 1.%TN%.1 { SELECT * FROM t2; } execsql_test 1.%TN%.2 { UPDATE t2 SET b = chng.b, c = chng.c FROM chng WHERE chng.a = t2.a; SELECT * FROM t2 ORDER BY a; } execsql_test 1.%TN%.3 { DELETE FROM t2; INSERT INTO t2 VALUES(1, 2, 3); INSERT INTO t2 VALUES(4, 5, 6); INSERT INTO t2 VALUES(7, 8, 9); } execsql_test 1.%TN%.4 { UPDATE t2 SET (b, c) = (SELECT b, c FROM chng WHERE a=t2.a) WHERE a IN (SELECT a FROM chng); SELECT * FROM t2 ORDER BY a; } execsql_test 1.%TN%.5 { DROP TABLE IF EXISTS t3; CREATE TABLE t3(a INTEGER PRIMARY KEY, b INTEGER, c TEXT) %WITHOUT_ROWID%; INSERT INTO t3 VALUES(1, 1, 'one'); INSERT INTO t3 VALUES(2, 2, 'two'); INSERT INTO t3 VALUES(3, 3, 'three'); DROP TABLE IF EXISTS t4; CREATE TABLE t4(x TEXT); INSERT INTO t4 VALUES('five'); SELECT * FROM t3 ORDER BY a; } execsql_test 1.%TN%.6 { UPDATE t3 SET c=x FROM t4; SELECT * FROM t3 ORDER BY a; } }]} execsql_test 2.1 { DROP TABLE IF EXISTS t5; DROP TABLE IF EXISTS m1; DROP TABLE IF EXISTS m2; CREATE TABLE t5(a INTEGER PRIMARY KEY, b TEXT, c TEXT); CREATE TABLE m1(x INTEGER PRIMARY KEY, y TEXT); CREATE TABLE m2(u INTEGER PRIMARY KEY, v TEXT); INSERT INTO t5 VALUES(1, 'one', 'ONE'); INSERT INTO t5 VALUES(2, 'two', 'TWO'); INSERT INTO t5 VALUES(3, 'three', 'THREE'); INSERT INTO t5 VALUES(4, 'four', 'FOUR'); INSERT INTO m1 VALUES(1, 'i'); INSERT INTO m1 VALUES(2, 'ii'); INSERT INTO m1 VALUES(3, 'iii'); INSERT INTO m2 VALUES(1, 'I'); INSERT INTO m2 VALUES(3, 'II'); INSERT INTO m2 VALUES(4, 'III'); } execsql_test 2.2 { UPDATE t5 SET b=y, c=v FROM m1 LEFT JOIN m2 ON (x=u) WHERE x=a; SELECT * FROM t5 ORDER BY a; } errorsql_test 2.3.1 { UPDATE t5 SET b=1 FROM t5; } errorsql_test 2.3.2 { UPDATE t5 AS apples SET b=1 FROM t5 AS apples; } finish_test |
Added test/upfrom1.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 | # 2020 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. # #################################################### # DO NOT EDIT! THIS FILE IS AUTOMATICALLY GENERATED! #################################################### set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix upfrom1 do_execsql_test 1.1.0 { DROP TABLE IF EXISTS t2; CREATE TABLE t2(a INTEGER PRIMARY KEY, b INTEGER, c INTEGER) WITHOUT ROWID; INSERT INTO t2 VALUES(1, 2, 3); INSERT INTO t2 VALUES(4, 5, 6); INSERT INTO t2 VALUES(7, 8, 9); DROP TABLE IF EXISTS chng; CREATE TABLE chng(a INTEGER, b INTEGER, c INTEGER); INSERT INTO chng VALUES(1, 100, 1000); INSERT INTO chng VALUES(7, 700, 7000); } {} do_execsql_test 1.1.1 { SELECT * FROM t2; } {1 2 3 4 5 6 7 8 9} do_execsql_test 1.1.2 { UPDATE t2 SET b = chng.b, c = chng.c FROM chng WHERE chng.a = t2.a; SELECT * FROM t2 ORDER BY a; } {1 100 1000 4 5 6 7 700 7000} do_execsql_test 1.1.3 { DELETE FROM t2; INSERT INTO t2 VALUES(1, 2, 3); INSERT INTO t2 VALUES(4, 5, 6); INSERT INTO t2 VALUES(7, 8, 9); } {} do_execsql_test 1.1.4 { UPDATE t2 SET (b, c) = (SELECT b, c FROM chng WHERE a=t2.a) WHERE a IN (SELECT a FROM chng); SELECT * FROM t2 ORDER BY a; } {1 100 1000 4 5 6 7 700 7000} do_execsql_test 1.1.5 { DROP TABLE IF EXISTS t3; CREATE TABLE t3(a INTEGER PRIMARY KEY, b INTEGER, c TEXT) WITHOUT ROWID; INSERT INTO t3 VALUES(1, 1, 'one'); INSERT INTO t3 VALUES(2, 2, 'two'); INSERT INTO t3 VALUES(3, 3, 'three'); DROP TABLE IF EXISTS t4; CREATE TABLE t4(x TEXT); INSERT INTO t4 VALUES('five'); SELECT * FROM t3 ORDER BY a; } {1 1 one 2 2 two 3 3 three} do_execsql_test 1.1.6 { UPDATE t3 SET c=x FROM t4; SELECT * FROM t3 ORDER BY a; } {1 1 five 2 2 five 3 3 five} do_execsql_test 1.2.0 { DROP TABLE IF EXISTS t2; CREATE TABLE t2(a INTEGER PRIMARY KEY, b INTEGER, c INTEGER) ; INSERT INTO t2 VALUES(1, 2, 3); INSERT INTO t2 VALUES(4, 5, 6); INSERT INTO t2 VALUES(7, 8, 9); DROP TABLE IF EXISTS chng; CREATE TABLE chng(a INTEGER, b INTEGER, c INTEGER); INSERT INTO chng VALUES(1, 100, 1000); INSERT INTO chng VALUES(7, 700, 7000); } {} do_execsql_test 1.2.1 { SELECT * FROM t2; } {1 2 3 4 5 6 7 8 9} do_execsql_test 1.2.2 { UPDATE t2 SET b = chng.b, c = chng.c FROM chng WHERE chng.a = t2.a; SELECT * FROM t2 ORDER BY a; } {1 100 1000 4 5 6 7 700 7000} do_execsql_test 1.2.3 { DELETE FROM t2; INSERT INTO t2 VALUES(1, 2, 3); INSERT INTO t2 VALUES(4, 5, 6); INSERT INTO t2 VALUES(7, 8, 9); } {} do_execsql_test 1.2.4 { UPDATE t2 SET (b, c) = (SELECT b, c FROM chng WHERE a=t2.a) WHERE a IN (SELECT a FROM chng); SELECT * FROM t2 ORDER BY a; } {1 100 1000 4 5 6 7 700 7000} do_execsql_test 1.2.5 { DROP TABLE IF EXISTS t3; CREATE TABLE t3(a INTEGER PRIMARY KEY, b INTEGER, c TEXT) ; INSERT INTO t3 VALUES(1, 1, 'one'); INSERT INTO t3 VALUES(2, 2, 'two'); INSERT INTO t3 VALUES(3, 3, 'three'); DROP TABLE IF EXISTS t4; CREATE TABLE t4(x TEXT); INSERT INTO t4 VALUES('five'); SELECT * FROM t3 ORDER BY a; } {1 1 one 2 2 two 3 3 three} do_execsql_test 1.2.6 { UPDATE t3 SET c=x FROM t4; SELECT * FROM t3 ORDER BY a; } {1 1 five 2 2 five 3 3 five} do_execsql_test 2.1 { DROP TABLE IF EXISTS t5; DROP TABLE IF EXISTS m1; DROP TABLE IF EXISTS m2; CREATE TABLE t5(a INTEGER PRIMARY KEY, b TEXT, c TEXT); CREATE TABLE m1(x INTEGER PRIMARY KEY, y TEXT); CREATE TABLE m2(u INTEGER PRIMARY KEY, v TEXT); INSERT INTO t5 VALUES(1, 'one', 'ONE'); INSERT INTO t5 VALUES(2, 'two', 'TWO'); INSERT INTO t5 VALUES(3, 'three', 'THREE'); INSERT INTO t5 VALUES(4, 'four', 'FOUR'); INSERT INTO m1 VALUES(1, 'i'); INSERT INTO m1 VALUES(2, 'ii'); INSERT INTO m1 VALUES(3, 'iii'); INSERT INTO m2 VALUES(1, 'I'); INSERT INTO m2 VALUES(3, 'II'); INSERT INTO m2 VALUES(4, 'III'); } {} do_execsql_test 2.2 { UPDATE t5 SET b=y, c=v FROM m1 LEFT JOIN m2 ON (x=u) WHERE x=a; SELECT * FROM t5 ORDER BY a; } {1 i I 2 ii {} 3 iii II 4 four FOUR} # PG says ERROR: table name "t5" specified more than once do_test 2.3.1 { catch { execsql { UPDATE t5 SET b=1 FROM t5; } } } 1 # PG says ERROR: table name "apples" specified more than once do_test 2.3.2 { catch { execsql { UPDATE t5 AS apples SET b=1 FROM t5 AS apples; } } } 1 # Problem found by OSSFuzz on 2020-07-20 # https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=24282 # reset_db do_execsql_test 3.1 { CREATE TABLE t0(a); CREATE TABLE t1(b); UPDATE t1 SET b=sum(a) FROM t0; SELECT * FROM t0, t1; } {} # Problem described by forum post https://sqlite.org/forum/forumpost/a274248080 # reset_db do_execsql_test 4.1 { CREATE TABLE t1(x INT); INSERT INTO t1 VALUES(1); CREATE TABLE t2(y INT); INSERT INTO t2 VALUES(2); WITH t1 AS (SELECT y+100 AS x FROM t2) UPDATE t1 SET x=(SELECT x FROM t1); SELECT x, y FROM t1, t2; } {102 2} do_execsql_test 4.2 { WITH t1 AS (SELECT y+100 AS x FROM t2) UPDATE t1 SET x=x+y FROM t2; SELECT x, y FROM t1, t2; } {104 2} # 2021-05-20 # Forum https://sqlite.org/forum/forumpost/339f487de5 by Yu Liang # A bad assert() # reset_db do_execsql_test 5.1 { CREATE TABLE t1(a); INSERT INTO t1(a) VALUES(5); CREATE VIEW t2 AS SELECT a FROM t1 UNION ALL SELECT a FROM t1; CREATE TABLE t3(b,c); INSERT INTO t3(b,c) VALUES(1,2); UPDATE t3 SET (c,b) = (SELECT 3,4) FROM t1, t2; SELECT * FROM t3; } {4 3} finish_test |
Added test/upfrom2.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 | # 2020 April 29 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix upfrom2 # Test cases: # # 1.*: Test that triggers are fired correctly for UPDATE FROM statements, # and only once for each row. Except for INSTEAD OF triggers on # views - these are fired once for each row returned by the join, # including duplicates. # # 2.*: Test adding ORDER BY and LIMIT clauses with UPDATE FROM statements. # # 5.*: Test that specifying the target table name or alias in the FROM # clause of an UPDATE statement is an error. # foreach {tn wo} { 1 "" 2 "WITHOUT ROWID" } { reset_db eval [string map [list %WO% $wo %TN% $tn] { do_execsql_test 1.%TN%.0 { CREATE TABLE log(t TEXT); CREATE TABLE t1(x PRIMARY KEY, y, z UNIQUE) %WO%; CREATE INDEX t1y ON t1(y); INSERT INTO t1 VALUES(1, 'i', 'one'); INSERT INTO t1 VALUES(2, 'ii', 'two'); INSERT INTO t1 VALUES(3, 'iii', 'three'); INSERT INTO t1 VALUES(4, 'iv', 'four'); CREATE TRIGGER tr1 BEFORE UPDATE ON t1 BEGIN INSERT INTO log VALUES(old.z || '->' || new.z); END; CREATE TRIGGER tr2 AFTER UPDATE ON t1 BEGIN INSERT INTO log VALUES(old.y || '->' || new.y); END; } do_execsql_test 1.%TN%.1 { WITH data(k, v) AS ( VALUES(3, 'thirty'), (1, 'ten') ) UPDATE t1 SET z=v FROM data WHERE x=k; SELECT * FROM t1; SELECT * FROM log; } { 1 i ten 2 ii two 3 iii thirty 4 iv four one->ten i->i three->thirty iii->iii } do_execsql_test 1.%TN%.2 { CREATE TABLE t2(a, b); CREATE TABLE t3(k, v); INSERT INTO t3 VALUES(5, 'v'); INSERT INTO t3 VALUES(12, 'xii'); INSERT INTO t2 VALUES(2, 12); INSERT INTO t2 VALUES(3, 5); DELETE FROM log; UPDATE t1 SET y=v FROM t2, t3 WHERE t1.x=t2.a AND t3.k=t2.b; SELECT * FROM t1; SELECT * FROM log; } { 1 i ten 2 xii two 3 v thirty 4 iv four two->two ii->xii thirty->thirty iii->v } do_execsql_test 1.%TN%.3 { DELETE FROM log; WITH data(k, v) AS ( VALUES(1, 'seven'), (1, 'eight'), (2, 'eleven'), (2, 'twelve') ) UPDATE t1 SET z=v FROM data WHERE x=k; SELECT * FROM t1; SELECT * FROM log; } { 1 i eight 2 xii twelve 3 v thirty 4 iv four ten->eight i->i two->twelve xii->xii } do_test 1.%TN%.4 { db changes } {2} do_execsql_test 1.%TN%.5 { CREATE VIEW v1 AS SELECT * FROM t1; CREATE TRIGGER v1tr INSTEAD OF UPDATE ON v1 BEGIN UPDATE t1 SET y=new.y, z=new.z WHERE x=new.x; END; DELETE FROM log; WITH data(k, v) AS ( VALUES(3, 'thirteen'), (3, 'fourteen'), (4, 'fifteen'), (4, 'sixteen') ) UPDATE v1 SET z=v FROM data WHERE x=k; } do_execsql_test 1.%TN%.6 { SELECT * FROM v1; SELECT * FROM log; } { 1 i eight 2 xii twelve 3 v fourteen 4 iv sixteen thirty->thirteen v->v thirteen->fourteen v->v four->fifteen iv->iv fifteen->sixteen iv->iv } #-------------------------------------------------------------- do_execsql_test 1.%TN%.7 { CREATE TABLE o1(w, x, y, z UNIQUE, PRIMARY KEY(w, x)) %WO%; CREATE INDEX o1y ON t1(y); INSERT INTO o1 VALUES(0, 0, 'i', 'one'); INSERT INTO o1 VALUES(0, 1, 'ii', 'two'); INSERT INTO o1 VALUES(1, 0, 'iii', 'three'); INSERT INTO o1 VALUES(1, 1, 'iv', 'four'); CREATE TRIGGER tro1 BEFORE UPDATE ON o1 BEGIN INSERT INTO log VALUES(old.z || '->' || new.z); END; CREATE TRIGGER tro2 AFTER UPDATE ON o1 BEGIN INSERT INTO log VALUES(old.y || '->' || new.y); END; } do_execsql_test 1.%TN%.8 { DELETE FROM log; WITH data(k, v) AS ( VALUES(3, 'thirty'), (1, 'ten') ) UPDATE o1 SET z=v FROM data WHERE (1+x+w*2)=k; SELECT * FROM o1; SELECT * FROM log; } { 0 0 i ten 0 1 ii two 1 0 iii thirty 1 1 iv four one->ten i->i three->thirty iii->iii } do_execsql_test 1.%TN%.9 { DELETE FROM log; UPDATE o1 SET y=v FROM t2, t3 WHERE (1+o1.w*2+o1.x)=t2.a AND t3.k=t2.b; SELECT * FROM o1; SELECT * FROM log; } { 0 0 i ten 0 1 xii two 1 0 v thirty 1 1 iv four two->two ii->xii thirty->thirty iii->v } do_execsql_test 1.%TN%.10 { DELETE FROM log; WITH data(k, v) AS ( VALUES(1, 'seven'), (1, 'eight'), (2, 'eleven'), (2, 'twelve') ) UPDATE o1 SET z=v FROM data WHERE (1+w*2+x)=k; SELECT * FROM o1; SELECT * FROM log; } { 0 0 i eight 0 1 xii twelve 1 0 v thirty 1 1 iv four ten->eight i->i two->twelve xii->xii } do_test 1.%TN%.11 { db changes } {2} do_execsql_test 1.%TN%.12 { CREATE VIEW w1 AS SELECT * FROM o1; CREATE TRIGGER w1tr INSTEAD OF UPDATE ON w1 BEGIN UPDATE o1 SET y=new.y, z=new.z WHERE w=new.w AND x=new.x; END; DELETE FROM log; WITH data(k, v) AS ( VALUES(3, 'thirteen'), (3, 'fourteen'), (4, 'fifteen'), (4, 'sixteen') ) UPDATE w1 SET z=v FROM data WHERE (1+w*2+x)=k; } do_execsql_test 1.%TN%.13 { SELECT * FROM w1; SELECT * FROM log; } { 0 0 i eight 0 1 xii twelve 1 0 v fourteen 1 1 iv sixteen thirty->thirteen v->v thirteen->fourteen v->v four->fifteen iv->iv fifteen->sixteen iv->iv } }] } ifcapable update_delete_limit { foreach {tn wo} { 1 "" 2 "WITHOUT ROWID" } { reset_db eval [string map [list %WO% $wo %TN% $tn] { do_execsql_test 2.%TN%.1 { CREATE TABLE x1(a INTEGER PRIMARY KEY, b) %WO%; INSERT INTO x1 VALUES (1, 'one'), (2, 'two'), (3, 'three'), (4, 'four'), (5, 'five'), (6, 'six'), (7, 'seven'), (8, 'eight'); } do_execsql_test 2.%TN%.2 { CREATE TABLE data1(x, y); INSERT INTO data1 VALUES (1, 'eleven'), (1, 'twenty-one'), (2, 'twelve'), (2, 'twenty-two'), (3, 'thirteen'), (3, 'twenty-three'), (4, 'fourteen'), (4, 'twenty-four'); } do_execsql_test 2.%TN%.3 { UPDATE x1 SET b=y FROM data1 WHERE a=x ORDER BY a LIMIT 3; SELECT * FROM x1; } { 1 eleven 2 twelve 3 thirteen 4 four 5 five 6 six 7 seven 8 eight } do_execsql_test 2.%TN%.4 { UPDATE x1 SET b=b||y FROM data1 WHERE a=x ORDER BY b LIMIT 3; SELECT * FROM x1; } { 1 eleveneleven 2 twelve 3 thirteenthirteen 4 fourfourteen 5 five 6 six 7 seven 8 eight } do_catchsql_test 2.%TN%.5 { UPDATE x1 SET b=b||b ORDER BY b; } {1 {ORDER BY without LIMIT on UPDATE}} do_catchsql_test 2.%TN%.6 { UPDATE x1 SET b=b||y FROM data1 WHERE a=x ORDER BY b; } {1 {ORDER BY without LIMIT on UPDATE}} #----------------------------------------------------------------------- do_execsql_test 2.%TN%.6 { DROP TABLE x1; CREATE TABLE x1(u, v, b, PRIMARY KEY(u, v)) %WO%; INSERT INTO x1 VALUES (0, 1, 'one'), (1, 0, 'two'), (1, 1, 'three'), (2, 0, 'four'), (2, 1, 'five'), (3, 0, 'six'), (3, 1, 'seven'), (4, 0, 'eight'); } do_execsql_test 2.%TN%.7 { UPDATE x1 SET b=y FROM data1 WHERE (u*2+v)=x ORDER BY u, v LIMIT 3; SELECT * FROM x1; } { 0 1 eleven 1 0 twelve 1 1 thirteen 2 0 four 2 1 five 3 0 six 3 1 seven 4 0 eight } do_execsql_test 2.%TN%.8 { UPDATE x1 SET b=b||y FROM data1 WHERE (u*2+v)=x ORDER BY b LIMIT 3; SELECT * FROM x1; } { 0 1 eleveneleven 1 0 twelve 1 1 thirteenthirteen 2 0 fourfourteen 2 1 five 3 0 six 3 1 seven 4 0 eight } }] }} reset_db do_execsql_test 3.0 { CREATE TABLE data(x, y, z); CREATE VIEW t1 AS SELECT * FROM data; CREATE TRIGGER t1_insert INSTEAD OF INSERT ON t1 BEGIN INSERT INTO data VALUES(new.x, new.y, new.z); END; CREATE TRIGGER t1_update INSTEAD OF UPDATE ON t1 BEGIN INSERT INTO log VALUES(old.z || '->' || new.z); END; CREATE TABLE log(t TEXT); INSERT INTO t1 VALUES(1, 'i', 'one'); INSERT INTO t1 VALUES(2, 'ii', 'two'); INSERT INTO t1 VALUES(3, 'iii', 'three'); INSERT INTO t1 VALUES(4, 'iv', 'four'); } do_execsql_test 3.1 { WITH input(k, v) AS ( VALUES(3, 'thirty'), (1, 'ten') ) UPDATE t1 SET z=v FROM input WHERE x=k; } foreach {tn sql} { 2 { CREATE TABLE x1(a INT PRIMARY KEY, b, c) WITHOUT ROWID; } 1 { CREATE TABLE x1(a INTEGER PRIMARY KEY, b, c); } 3 { CREATE TABLE x1(a INT PRIMARY KEY, b, c); } } { reset_db execsql $sql do_execsql_test 4.$tn.0 { INSERT INTO x1 VALUES(1, 1, 1); INSERT INTO x1 VALUES(2, 2, 2); INSERT INTO x1 VALUES(3, 3, 3); INSERT INTO x1 VALUES(4, 4, 4); INSERT INTO x1 VALUES(5, 5, 5); CREATE TABLE map(o, t); INSERT INTO map VALUES(3, 30), (4, 40), (1, 10); } do_execsql_test 4.$tn.1 { UPDATE x1 SET a=t FROM map WHERE a=o; SELECT * FROM x1 ORDER BY a; } {2 2 2 5 5 5 10 1 1 30 3 3 40 4 4} } reset_db do_execsql_test 5.0 { CREATE TABLE x1(a, b, c); CREATE TABLE x2(a, b, c); } foreach {tn update nm} { 1 "UPDATE x1 SET a=5 FROM x1" x1 2 "UPDATE x1 AS grapes SET a=5 FROM x1 AS grapes" grapes 3 "UPDATE x1 SET a=5 FROM x2, x1" x1 4 "UPDATE x1 AS grapes SET a=5 FROM x2, x1 AS grapes" grapes } { do_catchsql_test 5.$tn $update \ "1 {target object/alias may not appear in FROM clause: $nm}" } #-------------------------------------------------------------------------- reset_db do_execsql_test 6.0 { CREATE TABLE t1(a); } do_execsql_test 6.1 { UPDATE t1 SET a = 1 FROM ( SELECT * FROM t1 ) } {} do_execsql_test 6.2 { UPDATE t1 SET a = 1 FROM ( SELECT * FROM t1 UNION ALL SELECT * FROM t1 ) } {} finish_test |
Added test/upfrom3.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 | # 2020 July 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. # #*********************************************************************** # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix upfrom3 # Test plan: # # 1.*: Test UPDATE ... FROM statements that modify IPK fields. And that # modify "INTEGER PRIMARY KEY" fields on WITHOUT ROWID tables. # # 2.*: Test UPDATE ... FROM statements that modify PK fields of WITHOUT # ROWID tables. # # 3.*: Test that UPDATE ... FROM statements are not confused if there # are multiple tables of the same name in attached databases. # # 4.*: Tests for UPDATE ... FROM statements and foreign keys. # foreach {tn wo} { 1 "" 2 "WITHOUT ROWID" } { reset_db eval [string map [list %WO% $wo %TN% $tn] { do_execsql_test 1.%TN%.0 { CREATE TABLE log(t TEXT); CREATE TABLE t1(x INTEGER PRIMARY KEY, y, z UNIQUE) %WO%; CREATE INDEX t1y ON t1(y); INSERT INTO t1 VALUES(1, 'i', 'one'); INSERT INTO t1 VALUES(2, 'ii', 'two'); INSERT INTO t1 VALUES(3, 'iii', 'three'); INSERT INTO t1 VALUES(4, 'iv', 'four'); } do_execsql_test 1.%TN%.1 { CREATE TABLE x1(o, n); INSERT INTO x1 VALUES(1, 11); INSERT INTO x1 VALUES(2, 12); INSERT INTO x1 VALUES(3, 13); INSERT INTO x1 VALUES(4, 14); UPDATE t1 SET x=n FROM x1 WHERE x=o; SELECT x, y, z FROM t1 ORDER BY 1; } { 11 i one 12 ii two 13 iii three 14 iv four } do_test 1.%TN%.2 { db changes } 4 do_execsql_test 1.%TN%.3 { INSERT INTO x1 VALUES(11, 21); INSERT INTO x1 VALUES(12, 22); INSERT INTO x1 VALUES(13, 23); INSERT INTO x1 VALUES(14, 24); INSERT INTO x1 VALUES(21, 31); INSERT INTO x1 VALUES(22, 32); INSERT INTO x1 VALUES(23, 33); INSERT INTO x1 VALUES(24, 34); UPDATE t1 SET x=n FROM x1 WHERE x=o; SELECT x, y, z FROM t1 ORDER BY 1; } { 21 i one 22 ii two 23 iii three 24 iv four } do_execsql_test 1.%TN%.4 { UPDATE t1 SET x=n FROM x1 WHERE x=o; SELECT x, y, z FROM t1 ORDER BY 1; } { 31 i one 32 ii two 33 iii three 34 iv four } do_execsql_test 1.%TN%.5 { INSERT INTO x1 VALUES(31, 32); INSERT INTO x1 VALUES(33, 34); UPDATE OR REPLACE t1 SET x=n FROM x1 WHERE x=o; SELECT x, y, z FROM t1 ORDER BY 1; } { 32 i one 34 iii three } do_execsql_test 1.%TN%.6 { INSERT INTO t1 VALUES(33, 'ii', 'two'); INSERT INTO t1 VALUES(35, 'iv', 'four'); } do_execsql_test 1.%TN%.7 { CREATE TABLE x2(o, n, zz); INSERT INTO x2 VALUES(32, 41, 'four'); INSERT INTO x2 VALUES(33, 42, 'three'); UPDATE OR IGNORE t1 SET x=n, z=zz FROM x2 WHERE x=o; SELECT x, y, z FROM t1 ORDER BY 1; } { 32 i one 33 ii two 34 iii three 35 iv four } do_execsql_test 1.%TN%.8 { UPDATE OR REPLACE t1 SET x=n, z=zz FROM x2 WHERE x=o; SELECT x, y, z FROM t1 ORDER BY 1; } { 41 i four 42 ii three } }] } do_execsql_test 2.1.1 { CREATE TABLE u1(a, b, c, PRIMARY KEY(b, c)) WITHOUT ROWID; INSERT INTO u1 VALUES(0, 0, 0); INSERT INTO u1 VALUES(1, 0, 1); INSERT INTO u1 VALUES(2, 1, 0); INSERT INTO u1 VALUES(3, 1, 1); } do_execsql_test 2.1.2 { CREATE TABLE map(f, t); INSERT INTO map VALUES(0, 10); INSERT INTO map VALUES(1, 11); UPDATE u1 SET c=t FROM map WHERE c=f; SELECT * FROM u1 ORDER BY a; } { 0 0 10 1 0 11 2 1 10 3 1 11 } do_execsql_test 2.1.3 { UPDATE u1 SET b=t FROM map WHERE b=f; SELECT * FROM u1 ORDER BY a; } { 0 10 10 1 10 11 2 11 10 3 11 11 } do_execsql_test 2.1.4 { CREATE TABLE map2(o1, o2, n1, n2); INSERT INTO map2 VALUES (10, 10, 50, 50), (10, 11, 50, 60), (11, 10, 60, 50), (11, 11, 60, 60); UPDATE u1 SET b=n1, c=n2 FROM map2 WHERE b=o1 AND c=o2; SELECT * FROM u1 ORDER BY a; } { 0 50 50 1 50 60 2 60 50 3 60 60 } #------------------------------------------------------------------------- foreach {tn wo} { 1 "" 2 "WITHOUT ROWID" } { reset_db forcedelete test.db2 eval [string map [list %WO% $wo %TN% $tn] { do_execsql_test 3.$tn.1 { CREATE TABLE g1(a, b, c, PRIMARY KEY(a, b)) %WO%; INSERT INTO g1 VALUES(1, 1, 1); ATTACH 'test.db2' AS aux; CREATE TABLE aux.g1(a, b, c, PRIMARY KEY(a, b)) %WO%; INSERT INTO aux.g1 VALUES(10, 1, 10); INSERT INTO aux.g1 VALUES(20, 2, 20); INSERT INTO aux.g1 VALUES(30, 3, 30); } do_execsql_test 3.$tn.2 { UPDATE aux.g1 SET c=101 FROM main.g1; } do_execsql_test 3.$tn.3 { SELECT * FROM aux.g1; } {10 1 101 20 2 101 30 3 101} do_execsql_test 3.$tn.4 { UPDATE g1 SET c=101 FROM g1 AS g2; } do_execsql_test 3.$tn.5 { SELECT * FROM g1; } {1 1 101} }] } #------------------------------------------------------------------------- reset_db foreach {tn wo} { 1 "" 2 "WITHOUT ROWID" } { reset_db forcedelete test.db2 eval [string map [list %WO% $wo %TN% $tn] { do_execsql_test 4.$tn.1 { CREATE TABLE p1(a INTEGER PRIMARY KEY, b) %WO%; CREATE TABLE c1(x PRIMARY KEY, y REFERENCES p1 ON UPDATE CASCADE) %WO%; PRAGMA foreign_keys = 1; INSERT INTO p1 VALUES(1, 'one'); INSERT INTO p1 VALUES(11, 'eleven'); INSERT INTO p1 VALUES(111, 'eleventyone'); INSERT INTO c1 VALUES('a', 1); INSERT INTO c1 VALUES('b', 11); INSERT INTO c1 VALUES('c', 111); } do_execsql_test 4.$tn.2 { CREATE TABLE map(f, t); INSERT INTO map VALUES('a', 111); INSERT INTO map VALUES('c', 112); } do_catchsql_test 4.$tn.3 { UPDATE c1 SET y=t FROM map WHERE x=f; } {1 {FOREIGN KEY constraint failed}} do_execsql_test 4.$tn.4 { INSERT INTO map VALUES('eleven', 12); INSERT INTO map VALUES('eleventyone', 112); UPDATE p1 SET a=t FROM map WHERE b=f; } do_execsql_test 4.$tn.5 { SELECT * FROM c1 } {a 1 b 12 c 112} }] } finish_test |
Added test/upfromfault.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 | # 2020 April 29 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix upfromfault foreach {tn sql} { 1 { CREATE TABLE t1(x PRIMARY KEY, y, z UNIQUE); CREATE INDEX t1y ON t1(y); } 2 { CREATE TABLE t1(x PRIMARY KEY, y, z UNIQUE) WITHOUT ROWID; CREATE INDEX t1y ON t1(y); } 3 { CREATE TABLE t1(x, y, z UNIQUE, PRIMARY KEY(x,y)) WITHOUT ROWID; } 4 { CREATE VIRTUAL TABLE t1 USING fts5(x, y, z); } 5 { CREATE TABLE real(x, y, z); CREATE VIEW t1 AS SELECT * FROM real; CREATE TRIGGER t1_insert INSTEAD OF INSERT ON t1 BEGIN INSERT INTO real VALUES(new.x, new.y, new.z); END; CREATE TRIGGER t1_update INSTEAD OF UPDATE ON t1 BEGIN INSERT INTO log VALUES(old.z || '->' || new.z); UPDATE real SET y=new.y, z=new.z WHERE x=old.x; END; } } { if {$tn<5} continue reset_db ifcapable !fts5 { if {$tn==4} continue } execsql $sql do_execsql_test 1.$tn.0 { CREATE TABLE log(t TEXT); INSERT INTO t1 VALUES(1, 'i', 'one'); INSERT INTO t1 VALUES(2, 'ii', 'two'); INSERT INTO t1 VALUES(3, 'iii', 'three'); INSERT INTO t1 VALUES(4, 'iv', 'four'); } if {$tn!=4 && $tn!=5} { do_execsql_test 1.$tn.0b { CREATE TRIGGER tr1 BEFORE UPDATE ON t1 BEGIN INSERT INTO log VALUES(old.z || '->' || new.z); END; CREATE TRIGGER tr2 AFTER UPDATE ON t1 BEGIN INSERT INTO log VALUES(old.y || '->' || new.y); END; } } faultsim_save_and_close do_faultsim_test 1.$tn -prep { faultsim_restore_and_reopen execsql { SELECT * FROM t1 } } -body { execsql { WITH data(k, v) AS ( VALUES(3, 'thirty'), (1, 'ten') ) UPDATE t1 SET z=v FROM data WHERE x=k; } } -test { faultsim_test_result {0 {}} {1 {vtable constructor failed: t1}} if {$testrc==0} { set res [execsql { SELECT * FROM t1 }] if {$res!="1 i ten 2 ii two 3 iii thirty 4 iv four"} { error "unexpected result: $res" } } } } reset_db do_execsql_test 2.0 { CREATE TABLE t1(a, b, c); CREATE TABLE t2(x, y, z); } faultsim_save_and_close do_faultsim_test 2.1 -prep { faultsim_restore_and_reopen } -body { execsql { CREATE TRIGGER tr1 AFTER INSERT ON t1 BEGIN UPDATE t2 SET x=a FROM t1 WHERE c=z; END; } } -test { faultsim_test_result {0 {}} } faultsim_restore_and_reopen do_execsql_test 2.2 { CREATE TRIGGER tr1 AFTER INSERT ON t1 BEGIN UPDATE t1 SET a=x FROM t2 WHERE c=z; END; INSERT INTO t2 VALUES(1, 1, 1); INSERT INTO t2 VALUES(2, 2, 2); INSERT INTO t2 VALUES(3, 3, 3); } faultsim_save_and_close do_faultsim_test 2.3 -prep { faultsim_restore_and_reopen } -body { execsql { INSERT INTO t1 VALUES(NULL, NULL, 1), (NULL, NULL, 3); } } -test { faultsim_test_result {0 {}} if {$testrc==0} { set res [execsql { SELECT * FROM t1 }] if {$res!="1 {} 1 3 {} 3"} { error "unexpected result: $res" } } } finish_test |
Changes to test/upsert1.test.
︙ | ︙ | |||
206 207 208 209 210 211 212 213 214 | DELETE FROM t1; INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5); INSERT INTO t1(a,b,c,d,e) VALUES(1,2,33,44,5) ON CONFLICT(b) DO UPDATE SET c=excluded.c; SELECT * FROM t1; } {1 2 33 4 5} finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | DELETE FROM t1; INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5); INSERT INTO t1(a,b,c,d,e) VALUES(1,2,33,44,5) ON CONFLICT(b) DO UPDATE SET c=excluded.c; SELECT * FROM t1; } {1 2 33 4 5} # 2019-08-30 ticket https://sqlite.org/src/info/5a3dba8104421320 do_execsql_test upsert1-800 { DROP TABLE IF EXISTS t0; CREATE TABLE t0(c0 REAL UNIQUE, c1); CREATE UNIQUE INDEX test800i0 ON t0(0 || c1); INSERT INTO t0(c0, c1) VALUES (1, 2), (2, 1); INSERT INTO t0(c0) VALUES (1) ON CONFLICT(c0) DO UPDATE SET c1=excluded.c0; PRAGMA integrity_check; REINDEX; } {ok} # 2019-12-06 gramfuzz find sqlite3 db :memory: do_execsql_test upsert1-900 { CREATE VIEW t1(a) AS SELECT 1; CREATE TRIGGER t1r1 INSTEAD OF INSERT ON t1 BEGIN SELECT 2; END; } do_catchsql_test upsert1-910 { INSERT INTO t1 VALUES(3) ON CONFLICT(x) DO NOTHING; } {1 {cannot UPSERT a view}} # 2019-12-26 ticket 7c13db5c3bf74001 reset_db do_catchsql_test upsert1-1000 { CREATE TABLE t0(c0 PRIMARY KEY, c1, c2 UNIQUE) WITHOUT ROWID; INSERT OR FAIL INTO t0(c2) VALUES (0), (NULL) ON CONFLICT(c2) DO UPDATE SET c1 = c0; } {1 {NOT NULL constraint failed: t0.c0}} finish_test |
Added test/upsert5.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 406 407 408 409 410 411 | # 2020-12-11 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # # Test cases for generalized UPSERT set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix upsert5 foreach {tn sql} { 1 { CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c UNIQUE, d UNIQUE, e UNIQUE) } 2 { CREATE TABLE t1(a INT PRIMARY KEY, b, c UNIQUE, d UNIQUE, e UNIQUE) } 3 { CREATE TABLE t1(a INT PRIMARY KEY, b, c UNIQUE, d UNIQUE, e UNIQUE) WITHOUT ROWID} 4 { CREATE TABLE t1(e UNIQUE, d UNIQUE, c UNIQUE, a INTEGER PRIMARY KEY, b) } 5 { CREATE TABLE t1(e UNIQUE, d UNIQUE, c UNIQUE, a INT PRIMARY KEY, b) } 6 { CREATE TABLE t1(e UNIQUE, d UNIQUE, c UNIQUE, a INT PRIMARY KEY, b) WITHOUT ROWID} } { reset_db execsql $sql do_execsql_test 1.$tn.100 { DELETE FROM t1; INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5); INSERT INTO t1(a,b,c,d,e) VALUES(1,NULL,3,4,5) ON CONFLICT(a) DO UPDATE SET b='a' ON CONFLICT(c) DO UPDATE SET b='c' ON CONFLICT(d) DO UPDATE SET b='d' ON CONFLICT(e) DO UPDATE SET b='e'; SELECT a,b,c,d,e FROM t1; } {1 a 3 4 5} do_execsql_test 1.$tn.101 { DELETE FROM t1; INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5); INSERT INTO t1(a,b,c,d,e) VALUES(91,NULL,3,4,5) ON CONFLICT(a) DO UPDATE SET b='a' ON CONFLICT(c) DO UPDATE SET b='c' ON CONFLICT(d) DO UPDATE SET b='d' ON CONFLICT(e) DO UPDATE SET b='e'; SELECT a,b,c,d,e FROM t1; } {1 c 3 4 5} do_execsql_test 1.$tn.102 { DELETE FROM t1; INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5); INSERT INTO t1(a,b,c,d,e) VALUES(91,NULL,93,4,5) ON CONFLICT(a) DO UPDATE SET b='a' ON CONFLICT(c) DO UPDATE SET b='c' ON CONFLICT(d) DO UPDATE SET b='d' ON CONFLICT(e) DO UPDATE SET b='e'; SELECT a,b,c,d,e FROM t1; } {1 d 3 4 5} do_execsql_test 1.$tn.103 { DELETE FROM t1; INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5); INSERT INTO t1(a,b,c,d,e) VALUES(91,NULL,93,94,5) ON CONFLICT(a) DO UPDATE SET b='a' ON CONFLICT(c) DO UPDATE SET b='c' ON CONFLICT(d) DO UPDATE SET b='d' ON CONFLICT(e) DO UPDATE SET b='e'; SELECT a,b,c,d,e FROM t1; } {1 e 3 4 5} do_execsql_test 1.$tn.200 { DELETE FROM t1; INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5); INSERT INTO t1(a,b,c,d,e) VALUES(1,NULL,93,94,95) ON CONFLICT(c) DO UPDATE SET b='c' ON CONFLICT(a) DO UPDATE SET b='a' ON CONFLICT(d) DO UPDATE SET b='d' ON CONFLICT(e) DO UPDATE SET b='e'; SELECT a,b,c,d,e FROM t1; } {1 a 3 4 5} do_execsql_test 1.$tn.201 { DELETE FROM t1; INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5); INSERT INTO t1(a,b,c,d,e) VALUES(1,NULL,3,94,95) ON CONFLICT(c) DO UPDATE SET b='c' ON CONFLICT(a) DO UPDATE SET b='a' ON CONFLICT(d) DO UPDATE SET b='d' ON CONFLICT(e) DO UPDATE SET b='e'; SELECT a,b,c,d,e FROM t1; } {1 c 3 4 5} do_execsql_test 1.$tn.202 { DELETE FROM t1; INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5); INSERT INTO t1(a,b,c,d,e) VALUES(1,NULL,3,4,5) ON CONFLICT(c) DO UPDATE SET b='c' ON CONFLICT(a) DO UPDATE SET b='a' ON CONFLICT(d) DO UPDATE SET b='d' ON CONFLICT(e) DO UPDATE SET b='e'; SELECT a,b,c,d,e FROM t1; } {1 c 3 4 5} do_execsql_test 1.$tn.203 { DELETE FROM t1; INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5); INSERT INTO t1(a,b,c,d,e) VALUES(1,NULL,93,94,5) ON CONFLICT(c) DO UPDATE SET b='c' ON CONFLICT(a) DO UPDATE SET b='a' ON CONFLICT(d) DO UPDATE SET b='d' ON CONFLICT(e) DO UPDATE SET b='e'; SELECT a,b,c,d,e FROM t1; } {1 a 3 4 5} do_execsql_test 1.$tn.204 { DELETE FROM t1; INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5); INSERT INTO t1(a,b,c,d,e) VALUES(1,NULL,93,4,95) ON CONFLICT(c) DO UPDATE SET b='c' ON CONFLICT(a) DO UPDATE SET b='a' ON CONFLICT(d) DO UPDATE SET b='d' ON CONFLICT(e) DO UPDATE SET b='e'; SELECT a,b,c,d,e FROM t1; } {1 a 3 4 5} do_execsql_test 1.$tn.210 { DELETE FROM t1; INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5); INSERT INTO t1(a,b,c,d,e) VALUES(1,NULL,93,94,95) ON CONFLICT(c) DO UPDATE SET b='c' ON CONFLICT(d) DO UPDATE SET b='d' ON CONFLICT(a) DO UPDATE SET b='a' ON CONFLICT(e) DO UPDATE SET b='e'; SELECT a,b,c,d,e FROM t1; } {1 a 3 4 5} do_execsql_test 1.$tn.211 { DELETE FROM t1; INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5); INSERT INTO t1(a,b,c,d,e) VALUES(1,NULL,93,4,95) ON CONFLICT(c) DO UPDATE SET b='c' ON CONFLICT(d) DO UPDATE SET b='d' ON CONFLICT(a) DO UPDATE SET b='a' ON CONFLICT(e) DO UPDATE SET b='e'; SELECT a,b,c,d,e FROM t1; } {1 d 3 4 5} do_execsql_test 1.$tn.212 { DELETE FROM t1; INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5); INSERT INTO t1(a,b,c,d,e) VALUES(1,NULL,93,94,5) ON CONFLICT(c) DO UPDATE SET b='c' ON CONFLICT(d) DO UPDATE SET b='d' ON CONFLICT(a) DO UPDATE SET b='a' ON CONFLICT(e) DO UPDATE SET b='e'; SELECT a,b,c,d,e FROM t1; } {1 a 3 4 5} do_execsql_test 1.$tn.213 { DELETE FROM t1; INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5); INSERT INTO t1(a,b,c,d,e) VALUES(91,NULL,93,94,5) ON CONFLICT(c) DO UPDATE SET b='c' ON CONFLICT(d) DO UPDATE SET b='d' ON CONFLICT(a) DO UPDATE SET b='a' ON CONFLICT(e) DO UPDATE SET b='e'; SELECT a,b,c,d,e FROM t1; } {1 e 3 4 5} do_execsql_test 1.$tn.214 { DELETE FROM t1; INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5); INSERT INTO t1(a,b,c,d,e) VALUES(91,NULL,93,94,5) ON CONFLICT(c) DO UPDATE SET b='c' ON CONFLICT(d) DO UPDATE SET b='d' ON CONFLICT(e) DO UPDATE SET b='e' ON CONFLICT(a) DO UPDATE SET b='a'; SELECT a,b,c,d,e FROM t1; } {1 e 3 4 5} do_execsql_test 1.$tn.215 { DELETE FROM t1; INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5); INSERT INTO t1(a,b,c,d,e) VALUES(1,NULL,93,94,5) ON CONFLICT(c) DO UPDATE SET b='c' ON CONFLICT(d) DO UPDATE SET b='d' ON CONFLICT(e) DO UPDATE SET b='e' ON CONFLICT(a) DO UPDATE SET b='a'; SELECT a,b,c,d,e FROM t1; } {1 e 3 4 5} do_execsql_test 1.$tn.216 { DELETE FROM t1; INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5); INSERT INTO t1(a,b,c,d,e) VALUES(1,NULL,93,94,95) ON CONFLICT(c) DO UPDATE SET b='c' ON CONFLICT(d) DO UPDATE SET b='d' ON CONFLICT(e) DO UPDATE SET b='e' ON CONFLICT(a) DO UPDATE SET b='a'; SELECT a,b,c,d,e FROM t1; } {1 a 3 4 5} do_execsql_test 1.$tn.300 { DELETE FROM t1; INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5); INSERT INTO t1(a,b,c,d,e) VALUES(1,NULL,93,94,95) ON CONFLICT(c) DO UPDATE SET b='c' ON CONFLICT(d) DO UPDATE SET b='d' ON CONFLICT(a) DO UPDATE SET b='a1' ON CONFLICT(a) DO UPDATE SET b='a2' ON CONFLICT(a) DO UPDATE SET b='a3' ON CONFLICT(a) DO UPDATE SET b='a4' ON CONFLICT(a) DO UPDATE SET b='a5' ON CONFLICT(e) DO UPDATE SET b='e'; SELECT a,b,c,d,e FROM t1; } {1 a1 3 4 5} do_execsql_test 1.$tn.301 { DELETE FROM t1; INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5); INSERT INTO t1(a,b,c,d,e) VALUES(91,NULL,93,94,5) ON CONFLICT(c) DO UPDATE SET b='c' ON CONFLICT(d) DO UPDATE SET b='d' ON CONFLICT(a) DO UPDATE SET b='a1' ON CONFLICT(a) DO UPDATE SET b='a2' ON CONFLICT(a) DO UPDATE SET b='a3' ON CONFLICT(a) DO UPDATE SET b='a4' ON CONFLICT(a) DO UPDATE SET b='a5' ON CONFLICT(e) DO UPDATE SET b='e'; SELECT a,b,c,d,e FROM t1; } {1 e 3 4 5} do_execsql_test 1.$tn.400 { DELETE FROM t1; INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5); INSERT INTO t1(a,b,c,d,e) VALUES(1,NULL,93,94,95) ON CONFLICT(c) DO UPDATE SET b='c' ON CONFLICT(d) DO UPDATE SET b='d' ON CONFLICT DO UPDATE set b='x'; SELECT a,b,c,d,e FROM t1; } {1 x 3 4 5} do_execsql_test 1.$tn.401 { DELETE FROM t1; INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5); INSERT INTO t1(a,b,c,d,e) VALUES(91,NULL,93,94,5) ON CONFLICT(c) DO UPDATE SET b='c' ON CONFLICT(d) DO UPDATE SET b='d' ON CONFLICT DO UPDATE set b='x'; SELECT a,b,c,d,e FROM t1; } {1 x 3 4 5} do_execsql_test 1.$tn.402 { DELETE FROM t1; INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5); INSERT INTO t1(a,b,c,d,e) VALUES(1,NULL,93,94,95) ON CONFLICT(c) DO UPDATE SET b='c' ON CONFLICT(d) DO UPDATE SET b='d' ON CONFLICT DO UPDATE set b='x'; SELECT a,b,c,d,e FROM t1; } {1 x 3 4 5} do_execsql_test 1.$tn.403 { DELETE FROM t1; INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5); INSERT INTO t1(a,b,c,d,e) VALUES(91,NULL,3,94,95) ON CONFLICT(c) DO UPDATE SET b='c' ON CONFLICT(d) DO UPDATE SET b='d' ON CONFLICT DO UPDATE set b='x'; SELECT a,b,c,d,e FROM t1; } {1 c 3 4 5} do_execsql_test 1.$tn.404 { DELETE FROM t1; INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5); INSERT INTO t1(a,b,c,d,e) VALUES(91,NULL,3,4,95) ON CONFLICT(c) DO UPDATE SET b='c' ON CONFLICT(d) DO UPDATE SET b='d' ON CONFLICT DO UPDATE set b='x'; SELECT a,b,c,d,e FROM t1; } {1 c 3 4 5} do_execsql_test 1.$tn.405 { DELETE FROM t1; INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5); INSERT INTO t1(a,b,c,d,e) VALUES(1,NULL,93,4,5) ON CONFLICT(c) DO UPDATE SET b='c' ON CONFLICT(d) DO UPDATE SET b='d' ON CONFLICT DO UPDATE set b='x'; SELECT a,b,c,d,e FROM t1; } {1 d 3 4 5} do_execsql_test 1.$tn.410 { DELETE FROM t1; INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5); INSERT INTO t1(a,b,c,d,e) VALUES(1,NULL,93,94,95) ON CONFLICT DO UPDATE set b='x'; SELECT a,b,c,d,e FROM t1; } {1 x 3 4 5} do_execsql_test 1.$tn.411 { DELETE FROM t1; INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5); INSERT INTO t1(a,b,c,d,e) VALUES(91,NULL,93,94,5) ON CONFLICT DO UPDATE set b='x'; SELECT a,b,c,d,e FROM t1; } {1 x 3 4 5} do_execsql_test 1.$tn.412 { DELETE FROM t1; INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5); INSERT INTO t1(a,b,c,d,e) VALUES(91,NULL,93,4,95) ON CONFLICT DO UPDATE set b='x'; SELECT a,b,c,d,e FROM t1; } {1 x 3 4 5} do_execsql_test 1.$tn.413 { DELETE FROM t1; INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5); INSERT INTO t1(a,b,c,d,e) VALUES(91,NULL,3,94,95) ON CONFLICT DO UPDATE set b='x'; SELECT a,b,c,d,e FROM t1; } {1 x 3 4 5} do_execsql_test 1.$tn.420 { DELETE FROM t1; INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5); INSERT INTO t1(a,b,c,d,e) VALUES(1,NULL,93,94,95) ON CONFLICT(c) DO NOTHING ON CONFLICT(d) DO NOTHING ON CONFLICT DO UPDATE set b='x'; SELECT a,b,c,d,e FROM t1; } {1 x 3 4 5} do_execsql_test 1.$tn.421 { DELETE FROM t1; INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5); INSERT INTO t1(a,b,c,d,e) VALUES(91,NULL,93,94,5) ON CONFLICT(c) DO NOTHING ON CONFLICT(d) DO NOTHING ON CONFLICT DO UPDATE set b='x'; SELECT a,b,c,d,e FROM t1; } {1 x 3 4 5} do_execsql_test 1.$tn.422 { DELETE FROM t1; INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5); INSERT INTO t1(a,b,c,d,e) VALUES(91,NULL,93,4,95) ON CONFLICT(c) DO NOTHING ON CONFLICT(d) DO NOTHING ON CONFLICT DO UPDATE set b='x'; SELECT a,b,c,d,e FROM t1; } {1 2 3 4 5} do_execsql_test 1.$tn.423 { DELETE FROM t1; INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5); INSERT INTO t1(a,b,c,d,e) VALUES(91,NULL,3,94,95) ON CONFLICT(c) DO NOTHING ON CONFLICT(d) DO NOTHING ON CONFLICT DO UPDATE set b='x'; SELECT a,b,c,d,e FROM t1; } {1 2 3 4 5} do_execsql_test 1.$tn.500 { DELETE FROM t1; INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5); INSERT INTO t1(a,b,c,d,e) VALUES(1,NULL,93,94,95) ON CONFLICT(c) DO UPDATE SET b='c' ON CONFLICT(d) DO UPDATE SET b='d' ON CONFLICT DO NOTHING; SELECT a,b,c,d,e FROM t1; } {1 2 3 4 5} do_execsql_test 1.$tn.501 { DELETE FROM t1; INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5); INSERT INTO t1(a,b,c,d,e) VALUES(91,NULL,93,94,5) ON CONFLICT(c) DO UPDATE SET b='c' ON CONFLICT(d) DO UPDATE SET b='d' ON CONFLICT DO NOTHING; SELECT a,b,c,d,e FROM t1; } {1 2 3 4 5} do_execsql_test 1.$tn.502 { DELETE FROM t1; INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5); INSERT INTO t1(a,b,c,d,e) VALUES(1,NULL,93,94,95) ON CONFLICT(c) DO UPDATE SET b='c' ON CONFLICT(d) DO UPDATE SET b='d' ON CONFLICT DO NOTHING; SELECT a,b,c,d,e FROM t1; } {1 2 3 4 5} do_execsql_test 1.$tn.503 { DELETE FROM t1; INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5); INSERT INTO t1(a,b,c,d,e) VALUES(91,NULL,3,94,95) ON CONFLICT(c) DO UPDATE SET b='c' ON CONFLICT(d) DO UPDATE SET b='d' ON CONFLICT DO NOTHING; SELECT a,b,c,d,e FROM t1; } {1 c 3 4 5} do_execsql_test 1.$tn.504 { DELETE FROM t1; INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5); INSERT INTO t1(a,b,c,d,e) VALUES(91,NULL,3,4,95) ON CONFLICT(c) DO UPDATE SET b='c' ON CONFLICT(d) DO UPDATE SET b='d' ON CONFLICT DO NOTHING; SELECT a,b,c,d,e FROM t1; } {1 c 3 4 5} do_execsql_test 1.$tn.505 { DELETE FROM t1; INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5); INSERT INTO t1(a,b,c,d,e) VALUES(1,NULL,93,4,5) ON CONFLICT(c) DO UPDATE SET b='c' ON CONFLICT(d) DO UPDATE SET b='d' ON CONFLICT DO NOTHING; SELECT a,b,c,d,e FROM t1; } {1 d 3 4 5} } #-------------------------------------------------------------------------- reset_db do_execsql_test 2.0 { CREATE TABLE t2(a, b, c REAL, d, e, PRIMARY KEY(a,b)) WITHOUT ROWID; CREATE UNIQUE INDEX t2c ON t2(c); } do_catchsql_test 2.1 { INSERT INTO t2(a,b,c,e,d) VALUES(1,2,3,4,5) ON CONFLICT(c) DO UPDATE SET b='' ON CONFLICT((SELECT t2 FROM nosuchtable)) DO NOTHING; } {1 {no such table: nosuchtable}} finish_test |
Changes to test/vacuum-into.test.
︙ | ︙ | |||
61 62 63 64 65 66 67 68 69 | CREATE TABLE t2(name TEXT); INSERT INTO t2 VALUES(':memory:'); VACUUM main INTO (SELECT name FROM t2); } {} do_catchsql_test vacuum-into-310 { VACUUM INTO null; } {1 {non-text filename}} finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | CREATE TABLE t2(name TEXT); INSERT INTO t2 VALUES(':memory:'); VACUUM main INTO (SELECT name FROM t2); } {} do_catchsql_test vacuum-into-310 { VACUUM INTO null; } {1 {non-text filename}} do_catchsql_test vacuum-into-320 { VACUUM INTO x; } {1 {no such column: x}} do_catchsql_test vacuum-into-330 { VACUUM INTO t1.nosuchcol; } {1 {no such column: t1.nosuchcol}} do_catchsql_test vacuum-into-340 { VACUUM INTO main.t1.nosuchcol; } {1 {no such column: main.t1.nosuchcol}} forcedelete test.db2 db func target target proc target {} { return "test.db2" } do_test vacuum-into-410 { execsql { VACUUM INTO target() } file exists test.db2 } 1 do_catchsql_test vacuum-into-420 { VACUUM INTO target2() } {1 {no such function: target2}} # The ability to VACUUM INTO a read-only database db close sqlite3 db test.db -readonly 1 forcedelete test.db2 do_execsql_test vacuum-into-500 { VACUUM INTO 'test.db2'; } sqlite3 db2 test.db2 do_test vacuum-into-510 { db2 eval {SELECT name FROM sqlite_master ORDER BY 1} } {t1 t1b t2} db2 close db close # Change the page-size on a VACUUM INTO even if the original # database is in WAL mode. # if {[wal_is_capable]} { forcedelete test.db forcedelete test.db2 do_test vacuum-into-600 { sqlite3 db test.db db eval { PRAGMA page_size=4096; PRAGMA journal_mode=WAL; CREATE TABLE t1(a); INSERT INTO t1 VALUES(19); CREATE INDEX t1a ON t1(a); PRAGMA integrity_check; } } {wal ok} do_execsql_test vacuum-into-610 { PRAGMA page_size; } {4096} do_execsql_test vacuum-into-620 { PRAGMA page_size=1024; VACUUM INTO 'test.db2'; } {} do_test vacuum-into-630 { sqlite3 db test.db2 db eval { PRAGMA page_size; PRAGMA integrity_check; } } {1024 ok} } finish_test |
Changes to test/vacuum2.test.
︙ | ︙ | |||
52 53 54 55 56 57 58 | execsql { CREATE TABLE t1(x); CREATE TABLE t2(y); INSERT INTO t1 VALUES(1); } hexio_get_int [hexio_read test.db 24 4] } [expr {[hexio_get_int [hexio_read test.db 24 4]]+3}] | | | 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | execsql { CREATE TABLE t1(x); CREATE TABLE t2(y); INSERT INTO t1 VALUES(1); } hexio_get_int [hexio_read test.db 24 4] } [expr {[hexio_get_int [hexio_read test.db 24 4]]+3}] do_test vacuum2-2.2 { execsql { VACUUM } hexio_get_int [hexio_read test.db 24 4] } [expr {[hexio_get_int [hexio_read test.db 24 4]]+1}] ############################################################################ |
︙ | ︙ |
Changes to test/vacuum3.test.
︙ | ︙ | |||
77 78 79 80 81 82 83 | # Test cases vacuum3-2.* convert a simple 3-page database between a # few different page sizes. # do_test vacuum3-2.1 { execsql { PRAGMA page_size = 1024; VACUUM; | > > | > > > > > > > > | 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 | # Test cases vacuum3-2.* convert a simple 3-page database between a # few different page sizes. # do_test vacuum3-2.1 { execsql { PRAGMA page_size = 1024; VACUUM; } ifcapable altertable { execsql { ALTER TABLE t1 ADD COLUMN d; } } else { execsql { DROP TABLE t1; CREATE TABLE t1(a, b, c, d); INSERT INTO t1 VALUES(1, 2, 3, NULL); } } execsql { UPDATE t1 SET d = randomblob(1000); } file size test.db } {3072} do_test vacuum3-2.2 { execsql { PRAGMA page_size } } {1024} |
︙ | ︙ |
Added test/vacuum6.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 | # 2016-08-19 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # # This file implements a test for VACUUM on attached databases. # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix vacuum6 # If the VACUUM statement is disabled in the current build, skip all # the tests in this file. # ifcapable !vacuum { finish_test return } do_execsql_test 1.0 { CREATE TABLE t1(x INTEGER PRIMARY KEY, y); INSERT INTO t1 VALUES(1, 1); } {} do_execsql_test 1.1 { VACUUM } reset_db do_execsql_test 1.2 { CREATE TABLE t1(x,b); CREATE INDEX x1 ON t1(x); CREATE INDEX x2 ON t1(x); CREATE INDEX x3 ON t1(x); INSERT INTO t1 SELECT 2,''; VACUUM; } #------------------------------------------------------------------------- # reset_db foreach {tn sz} {1 400 2 4000 3 9999} { reset_db do_execsql_test 2.$tn.1 { CREATE TABLE t1(a INTEGER PRIMARY KEY, b); WITH s(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<100 ) INSERT INTO t1 SELECT i, randomblob($sz) FROM s; } do_execsql_test 2.$tn.2 { vacuum; } do_execsql_test 2.$tn.3 { PRAGMA integrity_check; } {ok} } reset_db do_execsql_test 3.0 { PRAGMA page_size = 1024; CREATE TABLE t1(x INTEGER PRIMARY KEY, y); INSERT INTO t1 VALUES(2, randomblob(1200)); } {} do_execsql_test 3.1 { PRAGMA page_size = 512; VACUUM; } do_execsql_test 3.2 { PRAGMA integrity_check } {ok} #------------------------------------------------------------------------- # reset_db do_execsql_test 4.0 { CREATE TABLE tx(a, b); CREATE INDEX i1 ON tx(b); WITH s(i) AS ( SELECT 8000 UNION ALL SELECT i+1 FROM s WHERE i<10000 ) INSERT INTO tx SELECT i, randomblob(i) FROM s; SELECT sum(length(b)) FROM tx; } {18009000} foreach {tn pgsz av} { 1 2048 0 2 1024 1 3 65536 0 4 8192 1 5 512 0 6 4096 1 } { do_execsql_test 4.1.$tn.1 " PRAGMA page_size = $pgsz; PRAGMA auto_vacuum = $av; " do_execsql_test 4.1.$tn.2 VACUUM integrity_check 4.1.$tn.3 } finish_test |
Changes to test/view.test.
︙ | ︙ | |||
34 35 36 37 38 39 40 41 42 43 44 45 46 47 | do_test view-1.1 { execsql { BEGIN; CREATE VIEW IF NOT EXISTS v1 AS SELECT a,b FROM t1; SELECT * FROM v1 ORDER BY a; } } {1 2 4 5 7 8} do_test view-1.2 { catchsql { ROLLBACK; SELECT * FROM v1 ORDER BY a; } } {1 {no such table: v1}} do_test view-1.3 { | > > > > > > > > > > > > > > > > > > > > > > | 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 | do_test view-1.1 { execsql { BEGIN; CREATE VIEW IF NOT EXISTS v1 AS SELECT a,b FROM t1; SELECT * FROM v1 ORDER BY a; } } {1 2 4 5 7 8} do_test view-1.1.100 { db config enable_view off catchsql { SELECT * FROM v1 ORDER BY a; } } {1 {access to view "v1" prohibited}} do_execsql_test view-1.1.101 { CREATE TEMP VIEW v1temp AS SELECT a, b FROM t1; SELECT * FROM v1temp ORDER BY a; } {1 2 4 5 7 8} do_test view-1.1.110 { db config enable_view on catchsql { SELECT * FROM v1 ORDER BY a; SELECT * FROM v1temp ORDER BY a; } } {0 {1 2 4 5 7 8 1 2 4 5 7 8}} ifcapable vtab { do_execsql_test view-1.1.120 { SELECT name, type FROM pragma_table_list('v1'); } {v1 view} } do_test view-1.2 { catchsql { ROLLBACK; SELECT * FROM v1 ORDER BY a; } } {1 {no such table: v1}} do_test view-1.3 { |
︙ | ︙ | |||
696 697 698 699 700 701 702 703 704 | set res [list {SQLITE_DELETE sqlite_stat1 {} main {}}] ifcapable stat4 { lappend res {SQLITE_DELETE sqlite_stat4 {} main {}} } do_test view-25.2 { set log "" db eval {DROP TABLE t25;} set log } $res finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | set res [list {SQLITE_DELETE sqlite_stat1 {} main {}}] ifcapable stat4 { lappend res {SQLITE_DELETE sqlite_stat4 {} main {}} } do_test view-25.2 { set log "" db eval {DROP TABLE t25;} set log } $res #------------------------------------------------------------------------- do_execsql_test view-26.0 { CREATE TABLE t16(a, b, c UNIQUE); INSERT INTO t16 VALUES(1, 1, 1); INSERT INTO t16 VALUES(2, 2, 2); INSERT INTO t16 VALUES(3, 3, 3); CREATE VIEW v16 AS SELECT max(a) AS mx, min(b) AS mn FROM t16 GROUP BY c; SELECT * FROM v16 AS one, v16 AS two WHERE one.mx=1; } { 1 1 1 1 1 1 2 2 1 1 3 3 } do_execsql_test view-26.1 { WITH v17(x,y) AS (SELECT max(a), min(b) FROM t16 GROUP BY c) SELECT * FROM v17 AS one, v17 AS two WHERE one.x=1; } { 1 1 1 1 1 1 2 2 1 1 3 3 } #------------------------------------------------------------------------- reset_db do_execsql_test view-27.0 { CREATE TABLE t0(c0 TEXT, c1); INSERT INTO t0(c0, c1) VALUES (-1, 0); CREATE VIEW v0(c0, c1) AS SELECT t0.c0, AVG(t0.c1) FROM t0; } do_execsql_test view-27.1 { SELECT c0, typeof(c0), c1, typeof(c1) FROM v0; } { -1 text 0.0 real } do_execsql_test view-27.2 { SELECT c0<c1 FROM v0 } 1 do_execsql_test view-27.3 { SELECT c1<c0 FROM v0 } 0 do_execsql_test view-27.4 { SELECT 1 FROM v0 WHERE c1<c0 } {} do_execsql_test view-27.5 { SELECT 1 FROM v0 WHERE c0<c1 } {1} do_execsql_test view-27.6 { SELECT c0<c1 FROM (SELECT t0.c0 AS c0, AVG(t0.c1) AS c1 FROM t0) } 1 do_execsql_test view-27.7 { SELECT c1<c0 FROM (SELECT t0.c0 AS c0, AVG(t0.c1) AS c1 FROM t0) } 0 do_execsql_test view-27.8 { SELECT 1 FROM (SELECT t0.c0 AS c0, AVG(t0.c1) AS c1 FROM t0) WHERE c1<c0 } {} do_execsql_test view-27.9 { SELECT 1 FROM (SELECT t0.c0 AS c0, AVG(t0.c1) AS c1 FROM t0) WHERE c0<c1 } {1} #------------------------------------------------------------------------- reset_db do_execsql_test view-28.0 { CREATE TABLE t0(c0 TEXT); CREATE VIEW v0(c0) AS SELECT t0.c0 FROM t0; INSERT INTO t0(c0) VALUES ('0'); } do_execsql_test view-28.1 { SELECT 0 IN (c0) FROM t0; } {0} do_execsql_test view-28.2 { SELECT 0 IN (c0) FROM (SELECT c0 FROM t0); } {0} #------------------------------------------------------------------------- # 2020-10-26. https://sqlite.org/forum/forumpost/daa2c728cc # reset_db do_catchsql_test view-29.0 { CREATE TABLE t1(a,b,c); CREATE VIEW IF NOT EXISTS IF AS SELECT null; } {1 {malformed database schema (IF) - near "AS": syntax error}} do_catchsql_test view-29.1 { CREATE TABLE t2(c,d,e); SELECT name FROM sqlite_schema ORDER BY name; } {0 {t1 t2}} finish_test |
Added test/view2.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 | # 2021 May 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. The # focus of this file is testing VIEW statements. # # $Id: view.test,v 1.39 2008/12/14 14:45:21 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # Omit this entire file if the library is not configured with views enabled. ifcapable !view { finish_test return } set testprefix view2 do_execsql_test 1.0 { CREATE TABLE t1(x, y); INSERT INTO t1 VALUES(1, 2); CREATE VIEW v1 AS SELECT * FROM ( WITH x1 AS (SELECT y, x FROM t1) SELECT * FROM x1 ); } do_execsql_test 1.1 { SELECT * FROM v1 } {2 1} do_execsql_test 1.2 { CREATE VIEW v3 AS SELECT * FROM main.t1; WITH t1(a, b) AS ( SELECT 3, 4 ) SELECT * FROM v3; } {1 2} breakpoint do_execsql_test 1.3 { CREATE VIEW v2 AS SELECT * FROM t1; WITH t1(a, b) AS ( SELECT 3, 4 ) SELECT * FROM v2; } {1 2} finish_test |
Changes to test/vtab1.test.
︙ | ︙ | |||
870 871 872 873 874 875 876 877 878 879 880 881 882 883 | } } {31429} do_test vtab1.7-13 { execsql { SELECT rowid, a, b, c FROM real_abc } } {} ifcapable attach { do_test vtab1.8-1 { set echo_module "" execsql { ATTACH 'test2.db' AS aux; CREATE VIRTUAL TABLE aux.e2 USING echo(real_abc); | > > > > > > > > | 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 | } } {31429} do_test vtab1.7-13 { execsql { SELECT rowid, a, b, c FROM real_abc } } {} # PRAGMA index_info and index_xinfo are no-ops on a virtual table do_test vtab1.7-14 { execsql { PRAGMA index_info('echo_abc'); PRAGMA index_xinfo('echo_abc'); } } {} ifcapable attach { do_test vtab1.8-1 { set echo_module "" execsql { ATTACH 'test2.db' AS aux; CREATE VIRTUAL TABLE aux.e2 USING echo(real_abc); |
︙ | ︙ | |||
971 972 973 974 975 976 977 978 979 980 981 982 983 984 | } [list \ xBestIndex {SELECT rowid, a, b, c FROM 'r'} \ xFilter {SELECT rowid, a, b, c FROM 'r'} \ ] proc match_func {args} {return ""} do_test vtab1.10-6 { set echo_module "" db function match match_func execsql { SELECT * FROM e WHERE match('pattern', rowid, 'pattern2'); } set echo_module } [list \ xBestIndex {SELECT rowid, a, b, c FROM 'r'} \ | > | 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 | } [list \ xBestIndex {SELECT rowid, a, b, c FROM 'r'} \ xFilter {SELECT rowid, a, b, c FROM 'r'} \ ] proc match_func {args} {return ""} do_test vtab1.10-6 { set echo_module "" sqlite_delete_function db match db function match match_func execsql { SELECT * FROM e WHERE match('pattern', rowid, 'pattern2'); } set echo_module } [list \ xBestIndex {SELECT rowid, a, b, c FROM 'r'} \ |
︙ | ︙ | |||
1299 1300 1301 1302 1303 1304 1305 | INSERT INTO t6 VALUES(3, '8James'); INSERT INTO t6 VALUES(4, '8John'); INSERT INTO t6 VALUES(5, 'Phillip'); INSERT INTO t6 VALUES(6, 'Bartholomew'); CREATE VIRTUAL TABLE e6 USING echo(t6); } | > | | | | | | | | | | | | > > > | | | | | | > | | | > > > | | | 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 | INSERT INTO t6 VALUES(3, '8James'); INSERT INTO t6 VALUES(4, '8John'); INSERT INTO t6 VALUES(5, 'Phillip'); INSERT INTO t6 VALUES(6, 'Bartholomew'); CREATE VIRTUAL TABLE e6 USING echo(t6); } ifcapable !icu { foreach {tn sql res filter} { 1.1 "SELECT a FROM e6 WHERE b>'8James'" {4 2 6 1 5} {xFilter {SELECT rowid, a, b FROM 't6' WHERE b > ?} 8James} 1.2 "SELECT a FROM e6 WHERE b>='8' AND b<'9'" {3 4} {xFilter {SELECT rowid, a, b FROM 't6' WHERE b >= ? AND b < ?} 8 9} 1.3 "SELECT a FROM e6 WHERE b LIKE '8J%'" {3 4} {xFilter {SELECT rowid, a, b FROM 't6' WHERE b >= ? AND b < ? AND b like ?} 8J 8k 8J%} 1.4 "SELECT a FROM e6 WHERE b LIKE '8j%'" {3 4} {xFilter {SELECT rowid, a, b FROM 't6' WHERE b >= ? AND b < ? AND b like ?} 8J 8k 8j%} 1.5 "SELECT a FROM e6 WHERE b LIKE '8%'" {3 4} {xFilter {SELECT rowid, a, b FROM 't6' WHERE b like ?} 8%} } { set echo_module {} do_execsql_test 18.$tn.1 $sql $res do_test 18.$tn.2 { lrange $::echo_module 2 end } $filter } } do_execsql_test 18.2.0 { PRAGMA case_sensitive_like = ON } foreach {tn sql res filter} { 2.1 "SELECT a FROM e6 WHERE b LIKE '8%'" {3 4} {xFilter {SELECT rowid, a, b FROM 't6' WHERE b like ?} 8%} 2.2 "SELECT a FROM e6 WHERE b LIKE '8j%'" {} {xFilter {SELECT rowid, a, b FROM 't6' WHERE b >= ? AND b < ? AND b like ?} 8j 8k 8j%} 2.3 "SELECT a FROM e6 WHERE b LIKE '8J%'" {3 4} {xFilter {SELECT rowid, a, b FROM 't6' WHERE b >= ? AND b < ? AND b like ?} 8J 8K 8J%} } { set echo_module {} do_execsql_test 18.$tn.1 $sql $res do_test 18.$tn.2 { lrange $::echo_module 2 end } $filter } do_execsql_test 18.2.x { PRAGMA case_sensitive_like = OFF } #------------------------------------------------------------------------- # Test that it is ok to override and existing module. # do_test 19.1 { sqlite3 db2 test.db register_echo_module [sqlite3_connection_pointer db2] } SQLITE_OK do_test 19.2 { register_echo_module [sqlite3_connection_pointer db2] } SQLITE_OK do_test 19.3 { db2 close } {} #------------------------------------------------------------------------- # Test that the bug fixed by [b0c1ba655d69] really is fixed. # |
︙ | ︙ | |||
1536 1537 1538 1539 1540 1541 1542 1543 1544 | CREATE VIRTUAL TABLE t5 USING fts3(); SAVEPOINT b; ROLLBACK TO a; SAVEPOINT c; RELEASE a; } } finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 | CREATE VIRTUAL TABLE t5 USING fts3(); SAVEPOINT b; ROLLBACK TO a; SAVEPOINT c; RELEASE a; } } # 2021-07-04 https://sqlite.org/forum/forumpost/16ca0e9f32 # Yu Liang crash involving UPDATE on a virtual table with # a duplicate column in a vector changeset and invoking the # query flattener for UNION ALL. # reset_db register_echo_module db do_catchsql_test 25.0 { CREATE TABLE t0(a); CREATE VIRTUAL TABLE t1 USING echo(t0); WITH t3(a) AS (SELECT * FROM t1 UNION ALL SELECT * FROM t1) UPDATE t1 SET (a,a) = (SELECT 1, 0) FROM t3; } {0 {}} #-------------------------------------------------------------------------- # reset_db load_static_extension db wholenumber do_execsql_test 26.1 { CREATE VIRTUAL TABLE t1 USING wholenumber; CREATE TABLE tx(a, b, c); } do_test 26.2 { sqlite3 db2 test.db db2 eval { CREATE TABLE ty(x, y) } db2 close } {} do_execsql_test 26.3 { SELECT value FROM t1 WHERE value<5 } {1 2 3 4} finish_test |
Changes to test/vtabA.test.
︙ | ︙ | |||
124 125 126 127 128 129 130 | lappend ret [get_decltype t1e $c] } set ret } do_test vtabA-2.1 { analyse_parse {(a text, b integer hidden, c hidden)} {a b c} | | | 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 | lappend ret [get_decltype t1e $c] } set ret } do_test vtabA-2.1 { analyse_parse {(a text, b integer hidden, c hidden)} {a b c} } {a TEXT integer {}} do_test vtabA-2.2 { analyse_parse {(a hidden , b integerhidden, c hidden1)} {a b c} } {{b c} {} integerhidden hidden1} do_test vtabA-2.3 { analyse_parse {(a HiDden, b HIDDEN, c hidden)} {a b c} |
︙ | ︙ |
Changes to test/vtabH.test.
︙ | ︙ | |||
26 27 28 29 30 31 32 | do_execsql_test 1.0 { CREATE TABLE t6(a, b TEXT); CREATE INDEX i6 ON t6(b, a); CREATE VIRTUAL TABLE e6 USING echo(t6); } | > | | > | > | > | | | > > > > > > > > > > > | | | | | | | | | > | 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 | do_execsql_test 1.0 { CREATE TABLE t6(a, b TEXT); CREATE INDEX i6 ON t6(b, a); CREATE VIRTUAL TABLE e6 USING echo(t6); } ifcapable !icu { foreach {tn sql expect} { 1 "SELECT * FROM e6 WHERE b LIKE '8abc'" { xBestIndex {SELECT rowid, a, b FROM 't6' WHERE b >= ? AND b < ? AND b like ?} xFilter {SELECT rowid, a, b FROM 't6' WHERE b >= ? AND b < ? AND b like ?} 8ABC 8abd 8abc } 2 "SELECT * FROM e6 WHERE b GLOB '8abc'" { xBestIndex {SELECT rowid, a, b FROM 't6' WHERE b >= ? AND b < ? AND b glob ?} xFilter {SELECT rowid, a, b FROM 't6' WHERE b >= ? AND b < ? AND b glob ?} 8abc 8abd 8abc } 3 "SELECT * FROM e6 WHERE b LIKE '8e/'" { xBestIndex {SELECT rowid, a, b FROM 't6' WHERE b like ?} xFilter {SELECT rowid, a, b FROM 't6' WHERE b like ?} 8e/ } 4 "SELECT * FROM e6 WHERE b GLOB '8e/'" { xBestIndex {SELECT rowid, a, b FROM 't6' WHERE b glob ?} xFilter {SELECT rowid, a, b FROM 't6' WHERE b glob ?} 8e/ } } { do_test 1.$tn { set echo_module {} execsql $sql set ::echo_module } [list {*}$expect] } } #-------------------------------------------------------------------------- register_tclvar_module db set ::xyz 10 |
︙ | ︙ |
Changes to test/vtabJ.test.
︙ | ︙ | |||
117 118 119 120 121 122 123 124 125 126 | SELECT name, value FROM tclvar where name = 'xx'; } {xx att} do_execsql_test 181 { DELETE FROM tclvar WHERE name BETWEEN 'xx' AND 'xx' OR name='xx'; SELECT name, value FROM tclvar where name = 'xx'; } {} finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | SELECT name, value FROM tclvar where name = 'xx'; } {xx att} do_execsql_test 181 { DELETE FROM tclvar WHERE name BETWEEN 'xx' AND 'xx' OR name='xx'; SELECT name, value FROM tclvar where name = 'xx'; } {} #------------------------------------------------------------------------- do_execsql_test 200 { CREATE TABLE var(k TEXT, v TEXT); INSERT INTO var VALUES('testvar1', 10); INSERT INTO var VALUES('testvar2', 20); INSERT INTO var VALUES('testvar3', 30); } do_test 210 { foreach {testvar1 testvar2 testvar3} {1 2 3} {} execsql { UPDATE tclvar SET value = var.v FROM var WHERE name = var.k; } list $testvar1 $testvar2 $testvar3 } {10 20 30} do_test 220 { execsql { CREATE TABLE nam(k TEXT, v TEXT); INSERT INTO nam VALUES('testvar1', 'tv1'); INSERT INTO nam VALUES('testvar2', 'tv2'); INSERT INTO nam VALUES('testvar3', 'tv3'); UPDATE tclvar SET fullname = nam.v FROM nam WHERE name = nam.k; } list $tv1 $tv2 $tv3 } {10 20 30} finish_test |
Added test/vtabK.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 | # 2020-09-24 # # 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 tests for a strange scenario discovered by # dbsqlfuzz (0ad6d441f9bf3dfc32626a9900bc1700495b16f9) in which a # virtual table is named "sqlite_stat1". # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix vtabK ifcapable !vtab||!rtree||!fts5 { finish_test return } do_execsql_test 100 { CREATE TABLE t1(x); INSERT INTO t1 VALUES(123); PRAGMA writable_schema=ON; CREATE VIRTUAL TABLE sqlite_stat1 USING fts5(a); PRAGMA writable_schema=OFF; CREATE VIRTUAL TABLE t3 USING fts5(b); INSERT INTO t3 VALUES('this is a test'); } do_catchsql_test 110 { CREATE VIRTUAL TABLE t2 USING rtree(id,x,y); } {1 {no such column: stat}} do_execsql_test 120 { SELECT * FROM t1; } {123} do_execsql_test 130 { INSERT INTO t3(b) VALUES('Four score and seven years ago'); SELECT * FROM t3 WHERE t3 MATCH 'this'; } {{this is a test}} do_execsql_test 140 { SELECT * FROM t3 WHERE t3 MATCH 'four seven'; } {{Four score and seven years ago}} do_execsql_test 150 { INSERT INTO sqlite_stat1(a) VALUES('We hold these truths to be self-evident...'); SELECT * FROM sqlite_stat1; } {{We hold these truths to be self-evident...}} do_catchsql_test 160 { ANALYZE; } {1 {database disk image is malformed}} do_execsql_test 170 { PRAGMA integrity_check; } {ok} # Follow-on dbsqlfuzz bc02a0cde82dee801a8d6f653d2831680f87dca1 reset_db do_execsql_test 200 { CREATE TABLE t1(a); INSERT INTO t1 VALUES('Ebed-malech'); CREATE TABLE x(a); PRAGMA writable_schema=ON; CREATE VIRTUAL TABLE sqlite_stat1 USING fts5(a); } {} do_catchsql_test 210 { CREATE VIRTUAL TABLE t2 USING rtree(id,x,y); } {1 {no such column: stat}} do_execsql_test 220 { SELECT * FROM t1; } {Ebed-malech} # Follow-on dbsqlfuzz a097eaad43c3c845b236126df92fb49b25449b0c reset_db do_catchsql_test 300 { CREATE VIRTUAL TABLE t1 USING rtree(a,b,c); CREATE TABLE t2(x); ALTER TABLE t2 ADD d GENERATED ALWAYS AS (c IN (SELECT 1 FROM t1)) VIRTUAL; } {1 {error in table t2 after add column: subqueries prohibited in generated columns}} finish_test |
Added test/vtabdrop.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 | # 2018 December 28 # # 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. # #*********************************************************************** # # The tests in this file test edge cases surrounding DROP TABLE on # virtual tables. # set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable !vtab { finish_test ; return } source $testdir/fts3_common.tcl source $testdir/malloc_common.tcl set testprefix vtabdrop #------------------------------------------------------------------------- # Test that if a DROP TABLE is executed against an rtree table, but the # xDestroy() call fails, the rtree table is not dropped, the sqlite_master # table is not modified and the internal schema remains intact. # ifcapable rtree { do_execsql_test 1.0 { CREATE VIRTUAL TABLE rt USING rtree(id, x1, x2); CREATE TABLE t1(x, y); INSERT INTO t1 VALUES(1, 2); } do_test 1.1 { execsql { BEGIN; INSERT INTO t1 VALUES(3, 4); } db eval { SELECT * FROM t1 } { catchsql { DROP TABLE rt } } execsql COMMIT } {} do_execsql_test 1.2 { SELECT name FROM sqlite_master ORDER BY 1; SELECT * FROM t1; SELECT * FROM rt; } {rt rt_node rt_parent rt_rowid t1 1 2 3 4} db close sqlite3 db test.db do_execsql_test 1.3 { SELECT name FROM sqlite_master ORDER BY 1; } {rt rt_node rt_parent rt_rowid t1} } #------------------------------------------------------------------------- # Same as tests 1.*, except with fts5 instead of rtree. # ifcapable fts5 { reset_db do_execsql_test 2.0 { CREATE VIRTUAL TABLE ft USING fts5(x); CREATE TABLE t1(x, y); INSERT INTO t1 VALUES(1, 2); } do_test 2.1 { execsql { BEGIN; INSERT INTO t1 VALUES(3, 4); } db eval { SELECT * FROM t1 } { catchsql { DROP TABLE ft } } execsql COMMIT } {} do_execsql_test 2.2 { SELECT name FROM sqlite_master ORDER BY 1; } {ft ft_config ft_content ft_data ft_docsize ft_idx t1} db close sqlite3 db test.db do_execsql_test 2.3 { SELECT name FROM sqlite_master ORDER BY 1; } {ft ft_config ft_content ft_data ft_docsize ft_idx t1} } #------------------------------------------------------------------------- # Same as tests 1.*, except with fts3 instead of rtree. # ifcapable fts3 { reset_db do_execsql_test 2.0 { CREATE VIRTUAL TABLE ft USING fts3(x); CREATE TABLE t1(x, y); INSERT INTO t1 VALUES(1, 2); } do_test 2.1 { execsql { BEGIN; INSERT INTO t1 VALUES(3, 4); } db eval { SELECT * FROM t1 } { catchsql { DROP TABLE ft } } execsql COMMIT } {} do_execsql_test 2.2 { SELECT name FROM sqlite_master ORDER BY 1; } {ft ft_content ft_segdir ft_segments sqlite_autoindex_ft_segdir_1 t1} db close sqlite3 db test.db do_execsql_test 2.3 { SELECT name FROM sqlite_master ORDER BY 1; } {ft ft_content ft_segdir ft_segments sqlite_autoindex_ft_segdir_1 t1} } finish_test |
Changes to test/wal.test.
︙ | ︙ | |||
39 40 41 42 43 44 45 46 47 48 49 50 51 52 | proc sqlite3_wal {args} { eval sqlite3 $args [lindex $args 0] eval { PRAGMA auto_vacuum = 0 } [lindex $args 0] eval { PRAGMA page_size = 1024 } [lindex $args 0] eval { PRAGMA journal_mode = wal } [lindex $args 0] eval { PRAGMA synchronous = normal } [lindex $args 0] function blob blob } proc log_deleted {logfile} { return [expr [file exists $logfile]==0] } # | > | 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | proc sqlite3_wal {args} { eval sqlite3 $args [lindex $args 0] eval { PRAGMA auto_vacuum = 0 } [lindex $args 0] eval { PRAGMA page_size = 1024 } [lindex $args 0] eval { PRAGMA journal_mode = wal } [lindex $args 0] eval { PRAGMA synchronous = normal } [lindex $args 0] function blob blob db timeout 1000 } proc log_deleted {logfile} { return [expr [file exists $logfile]==0] } # |
︙ | ︙ | |||
1293 1294 1295 1296 1297 1298 1299 | # # 3. Using connection 1, checkpoint the database. Make sure all # the data is present and the database is not corrupt. # # At one point, SQLite was failing to grow the mapping of the wal-index # file in step 3 and the checkpoint was corrupting the database file. # | > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | > | 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 | # # 3. Using connection 1, checkpoint the database. Make sure all # the data is present and the database is not corrupt. # # At one point, SQLite was failing to grow the mapping of the wal-index # file in step 3 and the checkpoint was corrupting the database file. # if {[permutation]!="unix-excl"} { do_test wal-20.1 { catch {db close} forcedelete test.db test.db-wal test.db-journal sqlite3 db test.db execsql { PRAGMA journal_mode = WAL; CREATE TABLE t1(x); INSERT INTO t1 VALUES(randomblob(900)); SELECT count(*) FROM t1; } } {wal 1} do_test wal-20.2 { set ::buddy [launch_testfixture] testfixture $::buddy { sqlite3 db test.db db transaction { db eval { PRAGMA wal_autocheckpoint = 0; INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 2 */ INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 4 */ INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 8 */ INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 16 */ INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 32 */ INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 64 */ INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 128 */ INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 256 */ INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 512 */ INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 1024 */ INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 2048 */ INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 4096 */ INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 8192 */ INSERT INTO t1 SELECT randomblob(900) FROM t1; /* 16384 */ } } } } {0} do_test wal-20.3 { close $::buddy execsql { PRAGMA wal_checkpoint } execsql { SELECT count(*) FROM t1 } } {16384} do_test wal-20.4 { db close sqlite3 db test.db execsql { SELECT count(*) FROM t1 } } {16384} integrity_check wal-20.5 } catch { db2 close } catch { db close } do_test wal-21.1 { faultsim_delete_and_reopen execsql { |
︙ | ︙ | |||
1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 | sqlite3 db test.db do_test wal-25.$mode { db eval "PRAGMA journal_mode=$mode" db eval {ATTACH 'test2.db' AS t2; PRAGMA journal_mode=WAL;} } {wal} db close } test_restore_config_pagecache finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 | sqlite3 db test.db do_test wal-25.$mode { db eval "PRAGMA journal_mode=$mode" db eval {ATTACH 'test2.db' AS t2; PRAGMA journal_mode=WAL;} } {wal} db close } # 2021-03-10 forum post https://sqlite.org/forum/forumpost/a006d86f72 # file delete test.db sqlite3 db test.db db eval {PRAGMA journal_mode=WAL} for {set i 0} {$i<$SQLITE_MAX_ATTACHED} {incr i} { do_test wal-26.1.$i { file delete attached-$i.db db eval "ATTACH 'attached-$i.db' AS a$i;" db eval "PRAGMA a$i.journal_mode=WAL;" db eval "CREATE TABLE a$i.t$i (x);" db eval "INSERT INTO t$i VALUES(zeroblob(10000));" db eval "DELETE FROM t$i;" db eval "INSERT INTO t$i VALUES(randomblob(10000));" expr {[file size attached-$i.db-wal]>10000} } {1} } for {set i [expr {$SQLITE_MAX_ATTACHED-1}]} {$i>=0} {incr i -1} { do_test wal-26.2.$i { db eval "PRAGMA a$i.wal_checkpoint(TRUNCATE);" file size attached-$i.db-wal } {0} for {set j 0} {$j<$i} {incr j} { do_test wal-26.2.$i.$j { expr {[file size attached-$j.db-wal]>10000} } {1} } } db close test_restore_config_pagecache finish_test |
Changes to test/wal2.test.
︙ | ︙ | |||
81 82 83 84 85 86 87 | } } {4 10} do_test wal2-1.1 { execsql { SELECT count(a), sum(a) FROM t1 } db2 } {4 10} set RECOVER [list \ | | > > > > | | 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 | } } {4 10} do_test wal2-1.1 { execsql { SELECT count(a), sum(a) FROM t1 } db2 } {4 10} set RECOVER [list \ {0 1 lock exclusive} {1 2 lock exclusive} \ {4 1 lock exclusive} {4 1 unlock exclusive} \ {5 1 lock exclusive} {5 1 unlock exclusive} \ {6 1 lock exclusive} {6 1 unlock exclusive} \ {7 1 lock exclusive} {7 1 unlock exclusive} \ {1 2 unlock exclusive} {0 1 unlock exclusive} \ ] set READ [list \ {4 1 lock shared} {4 1 unlock shared} \ ] set INITSLOT [list \ {4 1 lock exclusive} {4 1 unlock exclusive} \ ] |
︙ | ︙ | |||
353 354 355 356 357 358 359 | # required the client grabs all exclusive locks (just as it would for a # recovery performed as a pre-cursor to a normal database transaction). # set expected_locks [list] lappend expected_locks {1 1 lock exclusive} ;# Lock checkpoint lappend expected_locks {0 1 lock exclusive} ;# Lock writer lappend expected_locks {2 1 lock exclusive} ;# Lock recovery | | > > > > > > > > | | 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 | # required the client grabs all exclusive locks (just as it would for a # recovery performed as a pre-cursor to a normal database transaction). # set expected_locks [list] lappend expected_locks {1 1 lock exclusive} ;# Lock checkpoint lappend expected_locks {0 1 lock exclusive} ;# Lock writer lappend expected_locks {2 1 lock exclusive} ;# Lock recovery # lappend expected_locks {4 4 lock exclusive} ;# Lock all aReadMark[] lappend expected_locks {4 1 lock exclusive} ;# Lock aReadMark[1] lappend expected_locks {4 1 unlock exclusive} ;# Unlock aReadMark[1] lappend expected_locks {5 1 lock exclusive} lappend expected_locks {5 1 unlock exclusive} lappend expected_locks {6 1 lock exclusive} lappend expected_locks {6 1 unlock exclusive} lappend expected_locks {7 1 lock exclusive} lappend expected_locks {7 1 unlock exclusive} lappend expected_locks {2 1 unlock exclusive} ;# Unlock recovery # lappend expected_locks {4 4 unlock exclusive} ;# Unlock all aReadMark[] lappend expected_locks {0 1 unlock exclusive} ;# Unlock writer lappend expected_locks {3 1 lock exclusive} ;# Lock aReadMark[0] lappend expected_locks {3 1 unlock exclusive} ;# Unlock aReadMark[0] lappend expected_locks {1 1 unlock exclusive} ;# Unlock checkpoint do_test wal2-5.1 { proc tvfs_cb {method args} { set ::shm_file [lindex $args 0] |
︙ | ︙ | |||
584 585 586 587 588 589 590 | testvfs tvfs tvfs script tvfs_cb sqlite3 db test.db -vfs tvfs set {} {} } {} set RECOVERY { | | > > > > | | 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 | testvfs tvfs tvfs script tvfs_cb sqlite3 db test.db -vfs tvfs set {} {} } {} set RECOVERY { {0 1 lock exclusive} {1 2 lock exclusive} {4 1 lock exclusive} {4 1 unlock exclusive} {5 1 lock exclusive} {5 1 unlock exclusive} {6 1 lock exclusive} {6 1 unlock exclusive} {7 1 lock exclusive} {7 1 unlock exclusive} {1 2 unlock exclusive} {0 1 unlock exclusive} } set READMARK0_READ { {3 1 lock shared} {3 1 unlock shared} } set READMARK0_WRITE { {3 1 lock shared} {0 1 lock exclusive} {3 1 unlock shared} |
︙ | ︙ | |||
1044 1045 1046 1047 1048 1049 1050 | 2 00666 3 00600 4 00755 } { set effective [format %.5o [expr $permissions & ~$umask]] do_test wal2-12.2.$tn.1 { file attributes test.db -permissions $permissions | | | > | 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 | 2 00666 3 00600 4 00755 } { set effective [format %.5o [expr $permissions & ~$umask]] do_test wal2-12.2.$tn.1 { file attributes test.db -permissions $permissions string map {o 0} [file attributes test.db -permissions] } $permissions do_test wal2-12.2.$tn.2 { list [file exists test.db-wal] [file exists test.db-shm] } {0 0} do_test wal2-12.2.$tn.3 { sqlite3 db test.db execsql { INSERT INTO tx DEFAULT VALUES } list [file exists test.db-wal] [file exists test.db-shm] } {1 1} do_test wal2-12.2.$tn.4 { set x [list [file attr test.db-wal -perm] [file attr test.db-shm -perm]] string map {o 0} $x } [list $effective $effective] do_test wal2-12.2.$tn.5 { db close list [file exists test.db-wal] [file exists test.db-shm] } {0 0} } } |
︙ | ︙ | |||
1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 | file attr test.db -perm $db_perm file attr test.db-wal -perm $wal_perm file attr test.db-shm -perm $shm_perm set L [file attr test.db -perm] lappend L [file attr test.db-wal -perm] lappend L [file attr test.db-shm -perm] } [list $db_perm $wal_perm $shm_perm] # If $can_open is true, then it should be possible to open a database # handle. Otherwise, if $can_open is 0, attempting to open the db # handle throws an "unable to open database file" exception. # set r(1) {0 ok} | > | 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 | file attr test.db -perm $db_perm file attr test.db-wal -perm $wal_perm file attr test.db-shm -perm $shm_perm set L [file attr test.db -perm] lappend L [file attr test.db-wal -perm] lappend L [file attr test.db-shm -perm] string map {o 0} $L } [list $db_perm $wal_perm $shm_perm] # If $can_open is true, then it should be possible to open a database # handle. Otherwise, if $can_open is 0, attempting to open the db # handle throws an "unable to open database file" exception. # set r(1) {0 ok} |
︙ | ︙ |
Added test/walfault2.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 | # 2010 May 03 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this file is testing the operation of the library in # "PRAGMA journal_mode=WAL" mode. # set testdir [file dirname $argv0] source $testdir/tester.tcl source $testdir/malloc_common.tcl source $testdir/lock_common.tcl ifcapable !wal {finish_test ; return } set testprefix walfault2 #------------------------------------------------------------------------- # Inject faults while truncating the wal file. # do_execsql_test 1.0 { PRAGMA auto_vacuum = 0; CREATE TABLE t1(a, b); PRAGMA journal_mode = wal; WITH s(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM s LIMIT 30 ) INSERT INTO t1 SELECT randomblob(400), randomblob(400) FROM s; } {wal} faultsim_save_and_close do_faultsim_test 1 -prep { catch { db close } faultsim_restore sqlite3 db file:test.db?psow=0 -uri 1 file_control_powersafe_overwrite db 0 execsql { PRAGMA wal_checkpoint; PRAGMA journal_size_limit = 10000; PRAGMA synchronous = full; } } -body { execsql { INSERT INTO t1 VALUES(1,1) } } -test { faultsim_test_result {0 {}} } #------------------------------------------------------------------------- # Inject faults while rewriting checksums. # reset_db do_execsql_test 2.0 { PRAGMA auto_vacuum = 0; CREATE TABLE t1(a, b); PRAGMA journal_mode = wal; WITH s(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM s LIMIT 30 ) INSERT INTO t1 SELECT randomblob(400), randomblob(400) FROM s; } {wal} faultsim_save_and_close do_faultsim_test 2 -prep { faultsim_restore_and_reopen execsql { PRAGMA cache_size = 2; BEGIN; UPDATE t1 SET a=randomblob(400); UPDATE t1 SET b=randomblob(400); UPDATE t1 SET a=randomblob(400); UPDATE t1 SET b=randomblob(400); UPDATE t1 SET a=randomblob(400); UPDATE t1 SET b=randomblob(400); UPDATE t1 SET a=randomblob(400); UPDATE t1 SET b=randomblob(400); } } -body { execsql COMMIT } -test { faultsim_test_result {0 {}} } finish_test |
Changes to test/walprotocol.test.
︙ | ︙ | |||
48 49 50 51 52 53 54 | do_test 1.1 { testvfs T T filter xShmLock T script lock_callback set ::locks [list] sqlite3 db test.db -vfs T execsql { SELECT * FROM x } | | | > > > > | > | | > > > > | > | 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 | do_test 1.1 { testvfs T T filter xShmLock T script lock_callback set ::locks [list] sqlite3 db test.db -vfs T execsql { SELECT * FROM x } lrange $::locks 0 11 } [list {0 1 lock exclusive} {1 2 lock exclusive} \ {4 1 lock exclusive} {4 1 unlock exclusive} \ {5 1 lock exclusive} {5 1 unlock exclusive} \ {6 1 lock exclusive} {6 1 unlock exclusive} \ {7 1 lock exclusive} {7 1 unlock exclusive} \ {1 2 unlock exclusive} \ {0 1 unlock exclusive} \ ] do_test 1.2 { db close set ::locks [list] sqlite3 db test.db -vfs T execsql { SELECT * FROM x } lrange $::locks 0 11 } [list {0 1 lock exclusive} {1 2 lock exclusive} \ {4 1 lock exclusive} {4 1 unlock exclusive} \ {5 1 lock exclusive} {5 1 unlock exclusive} \ {6 1 lock exclusive} {6 1 unlock exclusive} \ {7 1 lock exclusive} {7 1 unlock exclusive} \ {1 2 unlock exclusive} \ {0 1 unlock exclusive} \ ] proc lock_callback {method filename handle lock} { if {$lock == "1 2 lock exclusive"} { return SQLITE_BUSY } return SQLITE_OK } puts "# Warning: This next test case causes SQLite to call xSleep(1) 100 times." puts "# Normally this equates to a delay of roughly 10 seconds, but if SQLite" |
︙ | ︙ | |||
97 98 99 100 101 102 103 | return SQLITE_OK } do_test 1.5 { db close set ::locks [list] sqlite3 db test.db -vfs T catchsql { SELECT * FROM x } | | | 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 | return SQLITE_OK } do_test 1.5 { db close set ::locks [list] sqlite3 db test.db -vfs T catchsql { SELECT * FROM x } } {0 z} db close T delete #------------------------------------------------------------------------- # do_test 2.1 { forcedelete test.db test.db-journal test.db wal |
︙ | ︙ | |||
156 157 158 159 160 161 162 | sqlite3 db2 test.db puts "# Warning: Another slow test!" do_test 2.5 { execsql { SELECT * FROM b } } {Tehran Qom Markazi Qazvin Gilan Ardabil} do_test 2.6 { set ::r | | | 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 | sqlite3 db2 test.db puts "# Warning: Another slow test!" do_test 2.5 { execsql { SELECT * FROM b } } {Tehran Qom Markazi Qazvin Gilan Ardabil} do_test 2.6 { set ::r } {0 {Tehran Qom Markazi Qazvin Gilan Ardabil}} db close db2 close faultsim_restore_and_reopen sqlite3 db2 test.db T filter xShmLock |
︙ | ︙ | |||
178 179 180 181 182 183 184 | unset ::r puts "# Warning: Last one!" do_test 2.7 { execsql { SELECT * FROM b } } {Tehran Qom Markazi Qazvin Gilan Ardabil} do_test 2.8 { set ::r | | | 188 189 190 191 192 193 194 195 196 197 198 199 200 201 | unset ::r puts "# Warning: Last one!" do_test 2.7 { execsql { SELECT * FROM b } } {Tehran Qom Markazi Qazvin Gilan Ardabil} do_test 2.8 { set ::r } {0 {Tehran Qom Markazi Qazvin Gilan Ardabil}} db close db2 close T delete finish_test |
Added test/walsetlk.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 | # 2020 May 06 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # set testdir [file dirname $argv0] source $testdir/tester.tcl source $testdir/lock_common.tcl set testprefix walsetlk ifcapable !wal {finish_test ; return } db timeout 1000 #------------------------------------------------------------------------- # 1.*: Test that nothing goes wrong if recovery is forced while opening # a write transaction or performing a checkpoint with blocking locks. # do_execsql_test 1.0 { CREATE TABLE t1(x, y); PRAGMA journal_mode = wal; INSERT INTO t1 VALUES(1, 2); INSERT INTO t1 VALUES(3, 4); INSERT INTO t1 VALUES(5, 6); INSERT INTO t1 VALUES(7, 8); } {wal} sqlite3 db2 test.db db2 timeout 1000 do_execsql_test -db db2 1.1 { SELECT * FROM t1 } {1 2 3 4 5 6 7 8} set fd [open test.db-shm r+] puts $fd "blahblahblahblah" flush $fd do_execsql_test 1.2 { BEGIN; INSERT INTO t1 VALUES(9, 10); } do_execsql_test -db db2 1.3 { SELECT * FROM t1 } {1 2 3 4 5 6 7 8} do_test 1.4 { list [catch {db2 eval { BEGIN EXCLUSIVE }} msg] $msg } {1 {database is locked}} do_execsql_test 1.5 { COMMIT } do_execsql_test -db db2 1.6 { SELECT * FROM t1 } {1 2 3 4 5 6 7 8 9 10} puts $fd "blahblahblahblah" flush $fd do_execsql_test -db db2 1.7 { PRAGMA wal_checkpoint = TRUNCATE } {0 0 0} do_test 1.8 { file size test.db-wal } 0 close $fd db close db2 close #------------------------------------------------------------------------- do_multiclient_test tn { do_test 2.$tn.1 { sql1 { PRAGMA journal_mode = wal; CREATE TABLE t1(s, v); INSERT INTO t1 VALUES(1, 2); INSERT INTO t1 VALUES(3, 4); INSERT INTO t1 VALUES(5, 6); } code1 { db timeout 2000 } } {} do_test 2.$tn.2 { sql2 { BEGIN; INSERT INTO t1 VALUES(7, 8); } } {} do_test 2.$tn.3 { set us [lindex [time { catch {db eval "BEGIN EXCLUSIVE"} }] 0] expr $us>1000000 && $us<4000000 } {1} do_test 2.$tn.4 { sql2 { COMMIT } sql1 { SELECT * FROM t1 } } {1 2 3 4 5 6 7 8} do_test 2.$tn.5 { sql2 { BEGIN; INSERT INTO t1 VALUES(9, 10); } } {} do_test 2.$tn.6 { set us [lindex [time { catch {db eval "PRAGMA wal_checkpoint=RESTART"} }] 0] expr $us>1000000 && $us<4000000 } {1} do_test 2.$tn.7 { sql2 { COMMIT; BEGIN; SELECT * FROM t1; } } {1 2 3 4 5 6 7 8 9 10} do_test 2.$tn.8 { set us [lindex [time { catch {db eval "PRAGMA wal_checkpoint=RESTART"} }] 0] expr $us>1000000 && $us<4000000 } {1} do_test 2.$tn.9 { sql3 { INSERT INTO t1 VALUES(11, 12); } sql2 { COMMIT; BEGIN; SELECT * FROM t1; } sql3 { INSERT INTO t1 VALUES(13, 14); } } {} do_test 2.$tn.10 { set us [lindex [time { catch {db eval "PRAGMA wal_checkpoint=RESTART"} }] 0] expr $us>1000000 && $us<4000000 } {1} do_test 2.$tn.11 { sql3 { BEGIN; SELECT * FROM t1; } sql1 { INSERT INTO t1 VALUES(15, 16); } } {} do_test 2.$tn.12 { set us [lindex [time { catch {db eval "PRAGMA wal_checkpoint=RESTART"} }] 0] expr $us>1000000 && $us<4000000 } {1} do_test 2.$tn.13 { sql2 { COMMIT; BEGIN; SELECT * FROM t1; } sql1 { INSERT INTO t1 VALUES(17, 18); } } {} do_test 2.$tn.14 { set us [lindex [time { catch {db eval "PRAGMA wal_checkpoint=RESTART"} }] 0] expr $us>1000000 && $us<4000000 } {1} } #------------------------------------------------------------------------- reset_db sqlite3 db2 test.db db2 timeout 1000 do_execsql_test 3.0 { PRAGMA journal_mode = wal; CREATE TABLE x1(x, y); BEGIN; INSERT INTO x1 VALUES(1, 2); } {wal} do_test 3.1 { list [catch { db2 eval {BEGIN EXCLUSIVE} } msg] $msg } {1 {database is locked}} finish_test |
Added test/walvfs.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 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 | # 2018 December 23 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this file is testing the operation of the library in # "PRAGMA journal_mode=WAL" mode. # 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 walvfs ifcapable !wal {finish_test ; return } db close testvfs tvfs tvfs script xSync tvfs filter xSync set ::sync_count 0 proc xSync {method file args} { if {[file tail $file]=="test.db-wal"} { incr ::sync_count } } #------------------------------------------------------------------------- # Test that if IOCAP_SEQUENTIAL is set, the wal-header is not synced to # disk immediately after it is written. # sqlite3 db test.db -vfs tvfs do_execsql_test 1.0 { PRAGMA auto_vacuum = 0; PRAGMA journal_mode = wal; PRAGMA synchronous = normal; CREATE TABLE t1(a, b, c); INSERT INTO t1 VALUES(1, 2, 3); INSERT INTO t1 VALUES(4, 5, 6); INSERT INTO t1 VALUES(7, 8, 9); PRAGMA wal_checkpoint; } {wal 0 5 5} set ::sync_count 0 do_test 1.1 { execsql { INSERT INTO t1 VALUES(10, 11, 12) } set ::sync_count } 1 db close tvfs devchar sequential sqlite3 db test.db -vfs tvfs do_execsql_test 1.2 { PRAGMA synchronous = normal; INSERT INTO t1 VALUES(13, 14, 15); INSERT INTO t1 VALUES(16, 17, 18); PRAGMA wal_checkpoint; } {0 4 4} set ::sync_count 0 do_test 1.3 { execsql { INSERT INTO t1 VALUES(10, 11, 12) } set ::sync_count } 0 #------------------------------------------------------------------------- # Test that "PRAGMA journal_size_limit" works in wal mode. # reset_db do_execsql_test 2.0 { PRAGMA journal_size_limit = 10000; CREATE TABLE t1(x); PRAGMA journal_mode = wal; WITH s(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM s LIMIT 20 ) INSERT INTO t1 SELECT randomblob(750) FROM s; } {10000 wal} do_test 2.1 { expr [file size test.db-wal]>12000 } {1} do_test 2.2 { execsql { PRAGMA wal_checkpoint; INSERT INTO t1 VALUES(randomblob(750)); } file size test.db-wal } {10000} do_test 2.3 { execsql { PRAGMA journal_size_limit = 8000; PRAGMA wal_checkpoint; INSERT INTO t1 VALUES(randomblob(750)); } file size test.db-wal } {8000} #------------------------------------------------------------------------- # Test that a checkpoint may be interrupted using sqlite3_interrupt(). # And that the error code is SQLITE_NOMEM, not SQLITE_INTERRUPT, if # an OOM error occurs just before the sqlite3_interrupt() call. # reset_db db close sqlite3 db test.db -vfs tvfs tvfs filter {} do_execsql_test 3.0 { CREATE TABLE t1(x); PRAGMA journal_mode = wal; WITH s(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM s LIMIT 20 ) INSERT INTO t1 SELECT randomblob(750) FROM s; } {wal} tvfs filter xWrite tvfs script xWrite set ::cnt 2 proc xWrite {method file args} { if {[file tail $file]=="test.db"} { incr ::cnt -1 if {$::cnt==0} { sqlite3_interrupt db } } return SQLITE_OK } do_catchsql_test 3.1 { PRAGMA wal_checkpoint } {1 interrupted} set ::cnt 2 proc xWrite {method file args} { if {[file tail $file]=="test.db"} { incr ::cnt -1 if {$::cnt==0} { sqlite3_memdebug_fail 1 -repeat 0 # For this test to pass, the following statement must call malloc() at # least once. Even if the lookaside is enabled. set ::xwrite_stmt_res [catchsql { SELECT hex(randomblob(4000)) }] sqlite3_interrupt db } } return SQLITE_OK } set ::xwrite_stmt_res "" do_catchsql_test 3.2 { PRAGMA wal_checkpoint } {1 {out of memory}} do_test 3.2.2 { set ::xwrite_stmt_res } {1 {out of memory}} unset ::xwrite_stmt_res #------------------------------------------------------------------------- # reset_db db close do_test 4.0 { sqlite3 db test.db -vfs tvfs execsql { CREATE TABLE t1(x); PRAGMA journal_mode = wal; WITH s(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM s LIMIT 20 ) INSERT INTO t1 SELECT randomblob(750) FROM s; } db } {wal} db close tvfs filter xShmMap tvfs script xShmMap proc xShmMap {method file args} { return SQLITE_READONLY } sqlite3 db test.db -vfs tvfs do_catchsql_test 4.1 { SELECT count(*) FROM t1 } {1 {attempt to write a readonly database}} set ::cnt 5 tvfs filter {xShmMap xShmLock} proc xShmMap {method file name args} { switch -- $method { xShmMap { return SQLITE_READONLY } xShmLock { if {$args == "{0 1 lock shared}"} { incr ::cnt -1 if {$::cnt>0} { return SQLITE_BUSY } } } } return SQLITE_OK } do_catchsql_test 4.2 { SELECT count(*) FROM t1 } {1 {attempt to write a readonly database}} #------------------------------------------------------------------------- # reset_db db close sqlite3 db test.db -vfs tvfs tvfs filter {} do_execsql_test 5.0 { PRAGMA auto_vacuum = 0; PRAGMA page_size = 1024; CREATE TABLE t1(x); PRAGMA journal_mode = wal; WITH s(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM s LIMIT 20 ) INSERT INTO t1 SELECT randomblob(750) FROM s; } {wal} do_execsql_test 5.1 { SELECT count(*) FROM t1 } {20} do_test 5.2 { vfs_set_readmark db main 1 100 vfs_set_readmark db main 2 100 vfs_set_readmark db main 3 100 vfs_set_readmark db main 4 100 } {100} do_execsql_test 5.3 { SELECT count(*) FROM t1 } {20} do_test 5.3 { list [vfs_set_readmark db main 1] \ [vfs_set_readmark db main 2] \ [vfs_set_readmark db main 3] \ [vfs_set_readmark db main 4] } {24 100 100 100} tvfs script xShmLock tvfs filter xShmLock set ::cnt 20 proc xShmLock {args} { incr ::cnt -1 if {$::cnt>0} { return SQLITE_BUSY } return SQLITE_OK } do_test 5.4 { vfs_set_readmark db main 1 100 execsql { SELECT count(*) FROM t1 } } {20} vfs_set_readmark db main 1 100 vfs_set_readmark db main 2 100 vfs_set_readmark db main 3 100 vfs_set_readmark db main 4 100 tvfs script xShmMapLock tvfs filter {xShmLock xShmMap} proc xShmMapLock {method args} { if {$method=="xShmMap"} { return "SQLITE_READONLY" } return SQLITE_BUSY } sqlite3 db2 test.db -vfs tvfs breakpoint do_test 5.5 { list [catch { execsql { SELECT count(*) FROM t1 } db2 } msg] $msg } {1 {attempt to write a readonly database}} tvfs filter {} vfs_set_readmark db main 1 1 do_test 5.6 { list [catch { execsql { SELECT count(*) FROM t1 } db2 } msg] $msg } {0 20} db2 close db close #------------------------------------------------------------------------- # Cause an SQLITE_PROTOCOL while attempting to restart the wal file. # reset_db tvfs filter {} db close sqlite3 db test.db -vfs tvfs do_execsql_test 6.0 { PRAGMA auto_vacuum = 0; PRAGMA page_size = 1024; CREATE TABLE t1(x); PRAGMA journal_mode = wal; WITH s(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM s LIMIT 20 ) INSERT INTO t1 SELECT randomblob(750) FROM s; } {wal} do_test 6.1 { execsql { PRAGMA wal_checkpoint } set {} {} } {} tvfs filter xShmLock tvfs script xShmLock set ::flag 0 proc xShmLock {method file handle spec} { if {$::flag && [lrange $spec 2 end]=="lock shared"} { return SQLITE_BUSY } if {$spec=="3 1 unlock shared"} { set ::flag 1 } return SQLITE_OK } puts "# WARNING: This next test takes around 12 seconds" do_catchsql_test 6.2 { INSERT INTO t1 VALUES(1); } {1 {locking protocol}} #------------------------------------------------------------------------- # Check that a checkpoint fails if it cannot get the CHECKPOINTER lock # reset_db tvfs filter {} db close sqlite3 db test.db -vfs tvfs do_execsql_test 7.0 { PRAGMA auto_vacuum = 0; PRAGMA page_size = 1024; CREATE TABLE t1(x); PRAGMA journal_mode = wal; WITH s(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM s LIMIT 20 ) INSERT INTO t1 SELECT randomblob(750) FROM s; } {wal} tvfs script xShmLock tvfs filter xShmLock proc xShmLock {method file handle spec} { if {$spec=="1 1 lock exclusive"} { return SQLITE_BUSY } return SQLITE_OK } do_execsql_test 7.1 { PRAGMA wal_checkpoint } {1 -1 -1} #------------------------------------------------------------------------- # Check that the page cache is correctly flushed if a checkpointer using # a version 2 VFS makes a checkpoint with an out-of-date cache. # reset_db testvfs tvfs2 -iversion 2 db close sqlite3 db test.db -vfs tvfs2 do_execsql_test 8.0 { PRAGMA auto_vacuum = 0; PRAGMA page_size = 1024; CREATE TABLE t1(x); PRAGMA journal_mode = wal; WITH s(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM s LIMIT 20 ) INSERT INTO t1 SELECT randomblob(75) FROM s; } {wal} do_execsql_test 8.1 { SELECT count(*) FROM t1 } {20} do_test 8.2 { sqlite3 db2 test.db -vfs tvfs2 execsql { INSERT INTO t1 VALUES(randomblob(75)); } db2 db2 close } {} do_execsql_test 8.3 { PRAGMA wal_checkpoint; SELECT count(*) FROM t1 } {0 5 5 21} db close tvfs2 delete #------------------------------------------------------------------------- reset_db db close sqlite3 db test.db -vfs tvfs do_execsql_test 9.0 { PRAGMA auto_vacuum = 0; PRAGMA page_size = 1024; CREATE TABLE t1(x); PRAGMA journal_mode = wal; WITH s(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM s LIMIT 20 ) INSERT INTO t1 SELECT randomblob(75) FROM s; } {wal} sqlite3 db2 test.db -vfs tvfs tvfs filter {xShmMap xShmLock} tvfs script xShmMap proc xShmMap {method file handle args} { switch -- $method { xShmMap { return "SQLITE_READONLY_CANTINIT" } xShmLock { if {$args=="{3 1 lock shared}"} { return "SQLITE_IOERR" } } } } do_test 9.1 { catchsql { SELECT count(*) FROM t1 } db2 } {1 {disk I/O error}} db close db2 close tvfs delete finish_test |
Added test/wapp.tcl.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 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 | # Copyright (c) 2017 D. Richard Hipp # # This program is free software; you can redistribute it and/or # modify it under the terms of the Simplified BSD License (also # known as the "2-Clause License" or "FreeBSD License".) # # This program is distributed in the hope that it will be useful, # but without any warranty; without even the implied warranty of # merchantability or fitness for a particular purpose. # #--------------------------------------------------------------------------- # # Design rules: # # (1) All identifiers in the global namespace begin with "wapp" # # (2) Indentifiers intended for internal use only begin with "wappInt" # package require Tcl 8.6 # Add text to the end of the HTTP reply. No interpretation or transformation # of the text is performs. The argument should be enclosed within {...} # proc wapp {txt} { global wapp dict append wapp .reply $txt } # Add text to the page under construction. Do no escaping on the text. # # Though "unsafe" in general, there are uses for this kind of thing. # For example, if you want to return the complete, unmodified content of # a file: # # set fd [open content.html rb] # wapp-unsafe [read $fd] # close $fd # # You could do the same thing using ordinary "wapp" instead of "wapp-unsafe". # The difference is that wapp-safety-check will complain about the misuse # of "wapp", but it assumes that the person who write "wapp-unsafe" understands # the risks. # # Though occasionally necessary, the use of this interface should be minimized. # proc wapp-unsafe {txt} { global wapp dict append wapp .reply $txt } # Add text to the end of the reply under construction. The following # substitutions are made: # # %html(...) Escape text for inclusion in HTML # %url(...) Escape text for use as a URL # %qp(...) Escape text for use as a URI query parameter # %string(...) Escape text for use within a JSON string # %unsafe(...) No transformations of the text # # The substitutions above terminate at the first ")" character. If the # text of the TCL string in ... contains ")" characters itself, use instead: # # %html%(...)% # %url%(...)% # %qp%(...)% # %string%(...)% # %unsafe%(...)% # # In other words, use "%(...)%" instead of "(...)" to include the TCL string # to substitute. # # The %unsafe substitution should be avoided whenever possible, obviously. # In addition to the substitutions above, the text also does backslash # escapes. # # The wapp-trim proc works the same as wapp-subst except that it also removes # whitespace from the left margin, so that the generated HTML/CSS/Javascript # does not appear to be indented when delivered to the client web browser. # if {$tcl_version>=8.7} { proc wapp-subst {txt} { global wapp regsub -all -command \ {%(html|url|qp|string|unsafe){1,1}?(|%)\((.+)\)\2} $txt wappInt-enc txt dict append wapp .reply [subst -novariables -nocommand $txt] } proc wapp-trim {txt} { global wapp regsub -all {\n\s+} [string trim $txt] \n txt regsub -all -command \ {%(html|url|qp|string|unsafe){1,1}?(|%)\((.+)\)\2} $txt wappInt-enc txt dict append wapp .reply [subst -novariables -nocommand $txt] } proc wappInt-enc {all mode nu1 txt} { return [uplevel 2 "wappInt-enc-$mode \"$txt\""] } } else { proc wapp-subst {txt} { global wapp regsub -all {%(html|url|qp|string|unsafe){1,1}?(|%)\((.+)\)\2} $txt \ {[wappInt-enc-\1 "\3"]} txt dict append wapp .reply [uplevel 1 [list subst -novariables $txt]] } proc wapp-trim {txt} { global wapp regsub -all {\n\s+} [string trim $txt] \n txt regsub -all {%(html|url|qp|string|unsafe){1,1}?(|%)\((.+)\)\2} $txt \ {[wappInt-enc-\1 "\3"]} txt dict append wapp .reply [uplevel 1 [list subst -novariables $txt]] } } # There must be a wappInt-enc-NAME routine for each possible substitution # in wapp-subst. Thus there are routines for "html", "url", "qp", and "unsafe". # # wappInt-enc-html Escape text so that it is safe to use in the # body of an HTML document. # # wappInt-enc-url Escape text so that it is safe to pass as an # argument to href= and src= attributes in HTML. # # wappInt-enc-qp Escape text so that it is safe to use as the # value of a query parameter in a URL or in # post data or in a cookie. # # wappInt-enc-string Escape ", ', \, and < for using inside of a # javascript string literal. The < character # is escaped to prevent "</script>" from causing # problems in embedded javascript. # # wappInt-enc-unsafe Perform no encoding at all. Unsafe. # proc wappInt-enc-html {txt} { return [string map {& & < < > > \" " \\ \} $txt] } proc wappInt-enc-unsafe {txt} { return $txt } proc wappInt-enc-url {s} { if {[regsub -all {[^-{}@~?=#_.:/a-zA-Z0-9]} $s {[wappInt-%HHchar {&}]} s]} { set s [subst -novar -noback $s] } if {[regsub -all {[{}]} $s {[wappInt-%HHchar \\&]} s]} { set s [subst -novar -noback $s] } return $s } proc wappInt-enc-qp {s} { if {[regsub -all {[^-{}_.a-zA-Z0-9]} $s {[wappInt-%HHchar {&}]} s]} { set s [subst -novar -noback $s] } if {[regsub -all {[{}]} $s {[wappInt-%HHchar \\&]} s]} { set s [subst -novar -noback $s] } return $s } proc wappInt-enc-string {s} { return [string map {\\ \\\\ \" \\\" ' \\' < \\u003c} $s] } # This is a helper routine for wappInt-enc-url and wappInt-enc-qp. It returns # an appropriate %HH encoding for the single character c. If c is a unicode # character, then this routine might return multiple bytes: %HH%HH%HH # proc wappInt-%HHchar {c} { if {$c==" "} {return +} return [regsub -all .. [binary encode hex [encoding convertto utf-8 $c]] {%&}] } # Undo the www-url-encoded format. # # HT: This code stolen from ncgi.tcl # proc wappInt-decode-url {str} { set str [string map [list + { } "\\" "\\\\" \[ \\\[ \] \\\]] $str] regsub -all -- \ {%([Ee][A-Fa-f0-9])%([89ABab][A-Fa-f0-9])%([89ABab][A-Fa-f0-9])} \ $str {[encoding convertfrom utf-8 [binary decode hex \1\2\3]]} str regsub -all -- \ {%([CDcd][A-Fa-f0-9])%([89ABab][A-Fa-f0-9])} \ $str {[encoding convertfrom utf-8 [binary decode hex \1\2]]} str regsub -all -- {%([0-7][A-Fa-f0-9])} $str {\\u00\1} str return [subst -novar $str] } # Reset the document back to an empty string. # proc wapp-reset {} { global wapp dict set wapp .reply {} } # Change the mime-type of the result document. # proc wapp-mimetype {x} { global wapp dict set wapp .mimetype $x } # Change the reply code. # proc wapp-reply-code {x} { global wapp dict set wapp .reply-code $x } # Set a cookie # proc wapp-set-cookie {name value} { global wapp dict lappend wapp .new-cookies $name $value } # Unset a cookie # proc wapp-clear-cookie {name} { wapp-set-cookie $name {} } # Add extra entries to the reply header # proc wapp-reply-extra {name value} { global wapp dict lappend wapp .reply-extra $name $value } # Specifies how the web-page under construction should be cached. # The argument should be one of: # # no-cache # max-age=N (for some integer number of seconds, N) # private,max-age=N # proc wapp-cache-control {x} { wapp-reply-extra Cache-Control $x } # Redirect to a different web page # proc wapp-redirect {uri} { wapp-reply-code {307 Redirect} wapp-reply-extra Location $uri } # Return the value of a wapp parameter # proc wapp-param {name {dflt {}}} { global wapp if {![dict exists $wapp $name]} {return $dflt} return [dict get $wapp $name] } # Return true if a and only if the wapp parameter $name exists # proc wapp-param-exists {name} { global wapp return [dict exists $wapp $name] } # Set the value of a wapp parameter # proc wapp-set-param {name value} { global wapp dict set wapp $name $value } # Return all parameter names that match the GLOB pattern, or all # names if the GLOB pattern is omitted. # proc wapp-param-list {{glob {*}}} { global wapp return [dict keys $wapp $glob] } # By default, Wapp does not decode query parameters and POST parameters # for cross-origin requests. This is a security restriction, designed to # help prevent cross-site request forgery (CSRF) attacks. # # As a consequence of this restriction, URLs for sites generated by Wapp # that contain query parameters will not work as URLs found in other # websites. You cannot create a link from a second website into a Wapp # website if the link contains query planner, by default. # # Of course, it is sometimes desirable to allow query parameters on external # links. For URLs for which this is safe, the application should invoke # wapp-allow-xorigin-params. This procedure tells Wapp that it is safe to # go ahead and decode the query parameters even for cross-site requests. # # In other words, for Wapp security is the default setting. Individual pages # need to actively disable the cross-site request security if those pages # are safe for cross-site access. # proc wapp-allow-xorigin-params {} { global wapp if {![dict exists $wapp .qp] && ![dict get $wapp SAME_ORIGIN]} { wappInt-decode-query-params } } # Set the content-security-policy. # # The default content-security-policy is very strict: "default-src 'self'" # The default policy prohibits the use of in-line javascript or CSS. # # Provide an alternative CSP as the argument. Or use "off" to disable # the CSP completely. # proc wapp-content-security-policy {val} { global wapp if {$val=="off"} { dict unset wapp .csp } else { dict set wapp .csp $val } } # Examine the bodys of all procedures in this program looking for # unsafe calls to various Wapp interfaces. Return a text string # containing warnings. Return an empty string if all is ok. # # This routine is advisory only. It misses some constructs that are # dangerous and flags others that are safe. # proc wapp-safety-check {} { set res {} foreach p [info procs] { set ln 0 foreach x [split [info body $p] \n] { incr ln if {[regexp {^[ \t]*wapp[ \t]+([^\n]+)} $x all tail] && [string index $tail 0]!="\173" && [regexp {[[$]} $tail] } { append res "$p:$ln: unsafe \"wapp\" call: \"[string trim $x]\"\n" } if {[regexp {^[ \t]*wapp-(subst|trim)[ \t]+[^\173]} $x all cx]} { append res "$p:$ln: unsafe \"wapp-$cx\" call: \"[string trim $x]\"\n" } } } return $res } # Return a string that descripts the current environment. Applications # might find this useful for debugging. # proc wapp-debug-env {} { global wapp set out {} foreach var [lsort [dict keys $wapp]] { if {[string index $var 0]=="."} continue append out "$var = [list [dict get $wapp $var]]\n" } append out "\[pwd\] = [list [pwd]]\n" return $out } # Tracing function for each HTTP request. This is overridden by wapp-start # if tracing is enabled. # proc wappInt-trace {} {} # Start up a listening socket. Arrange to invoke wappInt-new-connection # for each inbound HTTP connection. # # port Listen on this TCP port. 0 means to select a port # that is not currently in use # # wappmode One of "scgi", "remote-scgi", "server", or "local". # # fromip If not {}, then reject all requests from IP addresses # other than $fromip # proc wappInt-start-listener {port wappmode fromip} { if {[string match *scgi $wappmode]} { set type SCGI set server [list wappInt-new-connection \ wappInt-scgi-readable $wappmode $fromip] } else { set type HTTP set server [list wappInt-new-connection \ wappInt-http-readable $wappmode $fromip] } if {$wappmode=="local" || $wappmode=="scgi"} { set x [socket -server $server -myaddr 127.0.0.1 $port] } else { set x [socket -server $server $port] } set coninfo [chan configure $x -sockname] set port [lindex $coninfo 2] if {$wappmode=="local"} { wappInt-start-browser http://127.0.0.1:$port/ } elseif {$fromip!=""} { puts "Listening for $type requests on TCP port $port from IP $fromip" } else { puts "Listening for $type requests on TCP port $port" } } # Start a web-browser and point it at $URL # proc wappInt-start-browser {url} { global tcl_platform if {$tcl_platform(platform)=="windows"} { exec cmd /c start $url & } elseif {$tcl_platform(os)=="Darwin"} { exec open $url & } elseif {[catch {exec xdg-open $url}]} { exec firefox $url & } } # This routine is a "socket -server" callback. The $chan, $ip, and $port # arguments are added by the socket command. # # Arrange to invoke $callback when content is available on the new socket. # The $callback will process inbound HTTP or SCGI content. Reject the # request if $fromip is not an empty string and does not match $ip. # proc wappInt-new-connection {callback wappmode fromip chan ip port} { upvar #0 wappInt-$chan W if {$fromip!="" && ![string match $fromip $ip]} { close $chan return } set W [dict create REMOTE_ADDR $ip REMOTE_PORT $port WAPP_MODE $wappmode \ .header {}] fconfigure $chan -blocking 0 -translation binary fileevent $chan readable [list $callback $chan] } # Close an input channel # proc wappInt-close-channel {chan} { if {$chan=="stdout"} { # This happens after completing a CGI request exit 0 } else { unset ::wappInt-$chan close $chan } } # Process new text received on an inbound HTTP request # proc wappInt-http-readable {chan} { if {[catch [list wappInt-http-readable-unsafe $chan] msg]} { puts stderr "$msg\n$::errorInfo" wappInt-close-channel $chan } } proc wappInt-http-readable-unsafe {chan} { upvar #0 wappInt-$chan W wapp wapp if {![dict exists $W .toread]} { # If the .toread key is not set, that means we are still reading # the header set line [string trimright [gets $chan]] set n [string length $line] if {$n>0} { if {[dict get $W .header]=="" || [regexp {^\s+} $line]} { dict append W .header $line } else { dict append W .header \n$line } if {[string length [dict get $W .header]]>100000} { error "HTTP request header too big - possible DOS attack" } } elseif {$n==0} { # We have reached the blank line that terminates the header. global argv0 set a0 [file normalize $argv0] dict set W SCRIPT_FILENAME $a0 dict set W DOCUMENT_ROOT [file dir $a0] if {[wappInt-parse-header $chan]} { catch {close $chan} return } set len 0 if {[dict exists $W CONTENT_LENGTH]} { set len [dict get $W CONTENT_LENGTH] } if {$len>0} { # Still need to read the query content dict set W .toread $len } else { # There is no query content, so handle the request immediately set wapp $W wappInt-handle-request $chan 0 } } } else { # If .toread is set, that means we are reading the query content. # Continue reading until .toread reaches zero. set got [read $chan [dict get $W .toread]] dict append W CONTENT $got dict set W .toread [expr {[dict get $W .toread]-[string length $got]}] if {[dict get $W .toread]<=0} { # Handle the request as soon as all the query content is received set wapp $W wappInt-handle-request $chan 0 } } } # Decode the HTTP request header. # # This routine is always running inside of a [catch], so if # any problems arise, simply raise an error. # proc wappInt-parse-header {chan} { upvar #0 wappInt-$chan W set hdr [split [dict get $W .header] \n] if {$hdr==""} {return 1} set req [lindex $hdr 0] dict set W REQUEST_METHOD [set method [lindex $req 0]] if {[lsearch {GET HEAD POST} $method]<0} { error "unsupported request method: \"[dict get $W REQUEST_METHOD]\"" } set uri [lindex $req 1] set split_uri [split $uri ?] set uri0 [lindex $split_uri 0] if {![regexp {^/[-.a-z0-9_/]*$} $uri0]} { error "invalid request uri: \"$uri0\"" } dict set W REQUEST_URI $uri0 dict set W PATH_INFO $uri0 set uri1 [lindex $split_uri 1] dict set W QUERY_STRING $uri1 set n [llength $hdr] for {set i 1} {$i<$n} {incr i} { set x [lindex $hdr $i] if {![regexp {^(.+): +(.*)$} $x all name value]} { error "invalid header line: \"$x\"" } set name [string toupper $name] switch -- $name { REFERER {set name HTTP_REFERER} USER-AGENT {set name HTTP_USER_AGENT} CONTENT-LENGTH {set name CONTENT_LENGTH} CONTENT-TYPE {set name CONTENT_TYPE} HOST {set name HTTP_HOST} COOKIE {set name HTTP_COOKIE} ACCEPT-ENCODING {set name HTTP_ACCEPT_ENCODING} default {set name .hdr:$name} } dict set W $name $value } return 0 } # Decode the QUERY_STRING parameters from a GET request or the # application/x-www-form-urlencoded CONTENT from a POST request. # # This routine sets the ".qp" element of the ::wapp dict as a signal # that query parameters have already been decoded. # proc wappInt-decode-query-params {} { global wapp dict set wapp .qp 1 if {[dict exists $wapp QUERY_STRING]} { foreach qterm [split [dict get $wapp QUERY_STRING] &] { set qsplit [split $qterm =] set nm [lindex $qsplit 0] if {[regexp {^[a-z][a-z0-9]*$} $nm]} { dict set wapp $nm [wappInt-decode-url [lindex $qsplit 1]] } } } if {[dict exists $wapp CONTENT_TYPE] && [dict exists $wapp CONTENT]} { set ctype [dict get $wapp CONTENT_TYPE] if {$ctype=="application/x-www-form-urlencoded"} { foreach qterm [split [string trim [dict get $wapp CONTENT]] &] { set qsplit [split $qterm =] set nm [lindex $qsplit 0] if {[regexp {^[a-z][-a-z0-9_]*$} $nm]} { dict set wapp $nm [wappInt-decode-url [lindex $qsplit 1]] } } } elseif {[string match multipart/form-data* $ctype]} { regexp {^(.*?)\r\n(.*)$} [dict get $wapp CONTENT] all divider body set ndiv [string length $divider] while {[string length $body]} { set idx [string first $divider $body] set unit [string range $body 0 [expr {$idx-3}]] set body [string range $body [expr {$idx+$ndiv+2}] end] if {[regexp {^Content-Disposition: form-data; (.*?)\r\n\r\n(.*)$} \ $unit unit hdr content]} { if {[regexp {name="(.*)"; filename="(.*)"\r\nContent-Type: (.*?)$}\ $hdr hr name filename mimetype]} { dict set wapp $name.filename \ [string map [list \\\" \" \\\\ \\] $filename] dict set wapp $name.mimetype $mimetype dict set wapp $name.content $content } elseif {[regexp {name="(.*)"} $hdr hr name]} { dict set wapp $name $content } } } } } } # Invoke application-supplied methods to generate a reply to # a single HTTP request. # # This routine always runs within [catch], so handle exceptions by # invoking [error]. # proc wappInt-handle-request {chan useCgi} { global wapp dict set wapp .reply {} dict set wapp .mimetype {text/html; charset=utf-8} dict set wapp .reply-code {200 Ok} dict set wapp .csp {default-src 'self'} # Set up additional CGI environment values # if {![dict exists $wapp HTTP_HOST]} { dict set wapp BASE_URL {} } elseif {[dict exists $wapp HTTPS]} { dict set wapp BASE_URL https://[dict get $wapp HTTP_HOST] } else { dict set wapp BASE_URL http://[dict get $wapp HTTP_HOST] } if {![dict exists $wapp REQUEST_URI]} { dict set wapp REQUEST_URI / } elseif {[regsub {\?.*} [dict get $wapp REQUEST_URI] {} newR]} { # Some servers (ex: nginx) append the query parameters to REQUEST_URI. # These need to be stripped off dict set wapp REQUEST_URI $newR } if {[dict exists $wapp SCRIPT_NAME]} { dict append wapp BASE_URL [dict get $wapp SCRIPT_NAME] } else { dict set wapp SCRIPT_NAME {} } if {![dict exists $wapp PATH_INFO]} { # If PATH_INFO is missing (ex: nginx) then construct it set URI [dict get $wapp REQUEST_URI] set skip [string length [dict get $wapp SCRIPT_NAME]] dict set wapp PATH_INFO [string range $URI $skip end] } if {[regexp {^/([^/]+)(.*)$} [dict get $wapp PATH_INFO] all head tail]} { dict set wapp PATH_HEAD $head dict set wapp PATH_TAIL [string trimleft $tail /] } else { dict set wapp PATH_INFO {} dict set wapp PATH_HEAD {} dict set wapp PATH_TAIL {} } dict set wapp SELF_URL [dict get $wapp BASE_URL]/[dict get $wapp PATH_HEAD] # Parse query parameters from the query string, the cookies, and # POST data # if {[dict exists $wapp HTTP_COOKIE]} { foreach qterm [split [dict get $wapp HTTP_COOKIE] {;}] { set qsplit [split [string trim $qterm] =] set nm [lindex $qsplit 0] if {[regexp {^[a-z][-a-z0-9_]*$} $nm]} { dict set wapp $nm [wappInt-decode-url [lindex $qsplit 1]] } } } set same_origin 0 if {[dict exists $wapp HTTP_REFERER]} { set referer [dict get $wapp HTTP_REFERER] set base [dict get $wapp BASE_URL] if {$referer==$base || [string match $base/* $referer]} { set same_origin 1 } } dict set wapp SAME_ORIGIN $same_origin if {$same_origin} { wappInt-decode-query-params } # Invoke the application-defined handler procedure for this page # request. If an error occurs while running that procedure, generate # an HTTP reply that contains the error message. # wapp-before-dispatch-hook wappInt-trace set mname [dict get $wapp PATH_HEAD] if {[catch { if {$mname!="" && [llength [info proc wapp-page-$mname]]>0} { wapp-page-$mname } else { wapp-default } } msg]} { if {[wapp-param WAPP_MODE]=="local" || [wapp-param WAPP_MODE]=="server"} { puts "ERROR: $::errorInfo" } wapp-reset wapp-reply-code "500 Internal Server Error" wapp-mimetype text/html wapp-trim { <h1>Wapp Application Error</h1> <pre>%html($::errorInfo)</pre> } dict unset wapp .new-cookies } # Transmit the HTTP reply # if {$chan=="stdout"} { puts $chan "Status: [dict get $wapp .reply-code]\r" } else { puts $chan "HTTP/1.1 [dict get $wapp .reply-code]\r" puts $chan "Server: wapp\r" puts $chan "Connection: close\r" } if {[dict exists $wapp .reply-extra]} { foreach {name value} [dict get $wapp .reply-extra] { puts $chan "$name: $value\r" } } if {[dict exists $wapp .csp]} { puts $chan "Content-Security-Policy: [dict get $wapp .csp]\r" } set mimetype [dict get $wapp .mimetype] puts $chan "Content-Type: $mimetype\r" if {[dict exists $wapp .new-cookies]} { foreach {nm val} [dict get $wapp .new-cookies] { if {[regexp {^[a-z][-a-z0-9_]*$} $nm]} { if {$val==""} { puts $chan "Set-Cookie: $nm=; HttpOnly; Path=/; Max-Age=1\r" } else { set val [wappInt-enc-url $val] puts $chan "Set-Cookie: $nm=$val; HttpOnly; Path=/\r" } } } } if {[string match text/* $mimetype]} { set reply [encoding convertto utf-8 [dict get $wapp .reply]] if {[regexp {\ygzip\y} [wapp-param HTTP_ACCEPT_ENCODING]]} { catch { set x [zlib gzip $reply] set reply $x puts $chan "Content-Encoding: gzip\r" } } } else { set reply [dict get $wapp .reply] } puts $chan "Content-Length: [string length $reply]\r" puts $chan \r puts -nonewline $chan $reply flush $chan wappInt-close-channel $chan } # This routine runs just prior to request-handler dispatch. The # default implementation is a no-op, but applications can override # to do additional transformations or checks. # proc wapp-before-dispatch-hook {} {return} # Process a single CGI request # proc wappInt-handle-cgi-request {} { global wapp env foreach key { CONTENT_LENGTH CONTENT_TYPE DOCUMENT_ROOT HTTP_ACCEPT_ENCODING HTTP_COOKIE HTTP_HOST HTTP_REFERER HTTP_USER_AGENT HTTPS PATH_INFO QUERY_STRING REMOTE_ADDR REQUEST_METHOD REQUEST_URI REMOTE_USER SCRIPT_FILENAME SCRIPT_NAME SERVER_NAME SERVER_PORT SERVER_PROTOCOL } { if {[info exists env($key)]} { dict set wapp $key $env($key) } } set len 0 if {[dict exists $wapp CONTENT_LENGTH]} { set len [dict get $wapp CONTENT_LENGTH] } if {$len>0} { fconfigure stdin -translation binary dict set wapp CONTENT [read stdin $len] } dict set wapp WAPP_MODE cgi fconfigure stdout -translation binary wappInt-handle-request stdout 1 } # Process new text received on an inbound SCGI request # proc wappInt-scgi-readable {chan} { if {[catch [list wappInt-scgi-readable-unsafe $chan] msg]} { puts stderr "$msg\n$::errorInfo" wappInt-close-channel $chan } } proc wappInt-scgi-readable-unsafe {chan} { upvar #0 wappInt-$chan W wapp wapp if {![dict exists $W .toread]} { # If the .toread key is not set, that means we are still reading # the header. # # An SGI header is short. This implementation assumes the entire # header is available all at once. # dict set W .remove_addr [dict get $W REMOTE_ADDR] set req [read $chan 15] set n [string length $req] scan $req %d:%s len hdr incr len [string length "$len:,"] append hdr [read $chan [expr {$len-15}]] foreach {nm val} [split $hdr \000] { if {$nm==","} break dict set W $nm $val } set len 0 if {[dict exists $W CONTENT_LENGTH]} { set len [dict get $W CONTENT_LENGTH] } if {$len>0} { # Still need to read the query content dict set W .toread $len } else { # There is no query content, so handle the request immediately dict set W SERVER_ADDR [dict get $W .remove_addr] set wapp $W wappInt-handle-request $chan 0 } } else { # If .toread is set, that means we are reading the query content. # Continue reading until .toread reaches zero. set got [read $chan [dict get $W .toread]] dict append W CONTENT $got dict set W .toread [expr {[dict get $W .toread]-[string length $got]}] if {[dict get $W .toread]<=0} { # Handle the request as soon as all the query content is received dict set W SERVER_ADDR [dict get $W .remove_addr] set wapp $W wappInt-handle-request $chan 0 } } } # Start up the wapp framework. Parameters are a list passed as the # single argument. # # -server $PORT Listen for HTTP requests on this TCP port $PORT # # -local $PORT Listen for HTTP requests on 127.0.0.1:$PORT # # -scgi $PORT Listen for SCGI requests on 127.0.0.1:$PORT # # -remote-scgi $PORT Listen for SCGI requests on TCP port $PORT # # -cgi Handle a single CGI request # # With no arguments, the behavior is called "auto". In "auto" mode, # if the GATEWAY_INTERFACE environment variable indicates CGI, then run # as CGI. Otherwise, start an HTTP server bound to the loopback address # only, on an arbitrary TCP port, and automatically launch a web browser # on that TCP port. # # Additional options: # # -fromip GLOB Reject any incoming request where the remote # IP address does not match the GLOB pattern. This # value defaults to '127.0.0.1' for -local and -scgi. # # -nowait Do not wait in the event loop. Return immediately # after all event handlers are established. # # -trace "puts" each request URL as it is handled, for # debugging # # -lint Run wapp-safety-check on the application instead # of running the application itself # # -Dvar=value Set TCL global variable "var" to "value" # # proc wapp-start {arglist} { global env set mode auto set port 0 set nowait 0 set fromip {} set n [llength $arglist] for {set i 0} {$i<$n} {incr i} { set term [lindex $arglist $i] if {[string match --* $term]} {set term [string range $term 1 end]} switch -glob -- $term { -server { incr i; set mode "server" set port [lindex $arglist $i] } -local { incr i; set mode "local" set fromip 127.0.0.1 set port [lindex $arglist $i] } -scgi { incr i; set mode "scgi" set fromip 127.0.0.1 set port [lindex $arglist $i] } -remote-scgi { incr i; set mode "remote-scgi" set port [lindex $arglist $i] } -cgi { set mode "cgi" } -fromip { incr i set fromip [lindex $arglist $i] } -nowait { set nowait 1 } -trace { proc wappInt-trace {} { set q [wapp-param QUERY_STRING] set uri [wapp-param BASE_URL][wapp-param PATH_INFO] if {$q!=""} {append uri ?$q} puts $uri } } -lint { set res [wapp-safety-check] if {$res!=""} { puts "Potential problems in this code:" puts $res exit 1 } else { exit } } -D*=* { if {[regexp {^.D([^=]+)=(.*)$} $term all var val]} { set ::$var $val } } default { error "unknown option: $term" } } } if {$mode=="auto"} { if {[info exists env(GATEWAY_INTERFACE)] && [string match CGI/1.* $env(GATEWAY_INTERFACE)]} { set mode cgi } else { set mode local } } if {$mode=="cgi"} { wappInt-handle-cgi-request } else { wappInt-start-listener $port $mode $fromip if {!$nowait} { vwait ::forever } } } # Call this version 1.0 package provide wapp 1.0 |
Added test/wapptest.tcl.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 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 | #!/bin/sh # \ exec wapptclsh "$0" ${1+"$@"} # package required wapp source [file join [file dirname [info script]] wapp.tcl] # Variables set by the "control" form: # # G(platform) - User selected platform. # G(test) - Set to "Normal", "Veryquick", "Smoketest" or "Build-Only". # G(keep) - Boolean. True to delete no files after each test. # G(msvc) - Boolean. True to use MSVC as the compiler. # G(tcl) - Use Tcl from this directory for builds. # G(jobs) - How many sub-processes to run simultaneously. # set G(platform) $::tcl_platform(os)-$::tcl_platform(machine) set G(test) Normal set G(keep) 1 set G(msvc) 0 set G(tcl) [::tcl::pkgconfig get libdir,install] set G(jobs) 3 set G(debug) 0 set G(noui) 0 set G(stdout) 0 proc wapptest_init {} { global G set lSave [list platform test keep msvc tcl jobs debug noui stdout] foreach k $lSave { set A($k) $G($k) } array unset G foreach k $lSave { set G($k) $A($k) } # The root of the SQLite source tree. set G(srcdir) [file dirname [file dirname [info script]]] set G(sqlite_version) "unknown" # Either "config", "running" or "stopped": set G(state) "config" set G(hostname) "(unknown host)" catch { set G(hostname) [exec hostname] } set G(host) $G(hostname) append G(host) " $::tcl_platform(os) $::tcl_platform(osVersion)" append G(host) " $::tcl_platform(machine) $::tcl_platform(byteOrder)" } proc wapptest_run {} { global G set_test_array set G(state) "running" wapptest_openlog wapptest_output "Running the following for $G(platform). $G(jobs) jobs." foreach t $G(test_array) { set config [dict get $t config] set target [dict get $t target] wapptest_output [format " %-25s%s" $config $target] } wapptest_output [string repeat * 70] } proc releasetest_data {args} { global G set rtd [file join $G(srcdir) test releasetest_data.tcl] set fd [open "|[info nameofexecutable] $rtd $args" r+] set ret [read $fd] close $fd return $ret } # Generate the text for the box at the top of the UI. The current SQLite # version, according to fossil, along with a warning if there are # uncommitted changes in the checkout. # proc generate_fossil_info {} { global G set pwd [pwd] cd $G(srcdir) set rc [catch { set r1 [exec fossil info] set r2 [exec fossil changes] }] cd $pwd if {$rc} return foreach line [split $r1 "\n"] { if {[regexp {^checkout: *(.*)$} $line -> co]} { wapp-trim { <br> %html($co) } } } if {[string trim $r2]!=""} { wapp-trim { <br><span class=warning> WARNING: Uncommitted changes in checkout </span> } } } # If the application is in "config" state, set the contents of the # ::G(test_array) global to reflect the tests that will be run. If the # app is in some other state ("running" or "stopped"), this command # is a no-op. # proc set_test_array {} { global G if { $G(state)=="config" } { set G(test_array) [list] set debug "-debug" if {$G(debug)==0} { set debug "-nodebug"} foreach {config target} [releasetest_data tests $debug $G(platform)] { # If using MSVC, do not run sanitize or valgrind tests. Or the # checksymbols test. if {$G(msvc) && ( "Sanitize" == $config || "checksymbols" in $target || "valgrindtest" in $target )} { continue } # If the test mode is not "Normal", override the target. # if {$target!="checksymbols" && $G(platform)!="Failure-Detection"} { switch -- $G(test) { Veryquick { set target quicktest } Smoketest { set target smoketest } Build-Only { set target testfixture if {$::tcl_platform(platform)=="windows"} { set target testfixture.exe } } } } lappend G(test_array) [dict create config $config target $target] } } } proc count_tests_and_errors {name logfile} { global G set fd [open $logfile rb] set seen 0 while {![eof $fd]} { set line [gets $fd] if {[regexp {(\d+) errors out of (\d+) tests} $line all nerr ntest]} { incr G(test.$name.nError) $nerr incr G(test.$name.nTest) $ntest set seen 1 if {$nerr>0} { set G(test.$name.errmsg) $line } } if {[regexp {runtime error: +(.*)} $line all msg]} { # skip over "value is outside range" errors if {[regexp {.* is outside the range of representable} $line]} { # noop } else { incr G(test.$name.nError) if {$G(test.$name.errmsg)==""} { set G(test.$name.errmsg) $msg } } } if {[regexp {fatal error +(.*)} $line all msg]} { incr G(test.$name.nError) if {$G(test.$name.errmsg)==""} { set G(test.$name.errmsg) $msg } } if {[regexp {ERROR SUMMARY: (\d+) errors.*} $line all cnt] && $cnt>0} { incr G(test.$name.nError) if {$G(test.$name.errmsg)==""} { set G(test.$name.errmsg) $all } } if {[regexp {^VERSION: 3\.\d+.\d+} $line]} { set v [string range $line 9 end] if {$G(sqlite_version) eq "unknown"} { set G(sqlite_version) $v } elseif {$G(sqlite_version) ne $v} { set G(test.$name.errmsg) "version conflict: {$G(sqlite_version)} vs. {$v}" } } } close $fd if {$G(test) == "Build-Only"} { incr G(test.$name.nTest) if {$G(test.$name.nError)>0} { set errmsg "Build failed" } } elseif {!$seen} { set G(test.$name.errmsg) "Test did not complete" if {[file readable core]} { append G(test.$name.errmsg) " - core file exists" } } } proc wapptest_output {str} { global G if {$G(stdout)} { puts $str } if {[info exists G(log)]} { puts $G(log) $str flush $G(log) } } proc wapptest_openlog {} { global G set G(log) [open wapptest-out.txt w+] } proc wapptest_closelog {} { global G close $G(log) unset G(log) } proc format_seconds {seconds} { set min [format %.2d [expr ($seconds / 60) % 60]] set hr [format %.2d [expr $seconds / 3600]] set sec [format %.2d [expr $seconds % 60]] return "$hr:$min:$sec" } # This command is invoked once a slave process has finished running its # tests, successfully or otherwise. Parameter $name is the name of the # test, $rc the exit code returned by the slave process. # proc slave_test_done {name rc} { global G set G(test.$name.done) [clock seconds] set G(test.$name.nError) 0 set G(test.$name.nTest) 0 set G(test.$name.errmsg) "" if {$rc} { incr G(test.$name.nError) } if {[file exists $G(test.$name.log)]} { count_tests_and_errors $name $G(test.$name.log) } # If the "keep files" checkbox is clear, delete all files except for # the executables and test logs. And any core file that is present. if {$G(keep)==0} { set keeplist { testfixture testfixture.exe sqlite3 sqlite3.exe test.log test-out.txt core wapptest_make.sh wapptest_configure.sh wapptest_run.tcl } foreach f [glob -nocomplain [file join $G(test.$name.dir) *]] { set t [file tail $f] if {[lsearch $keeplist $t]<0} { catch { file delete -force $f } } } } # Format a message regarding the success or failure of hte test. set t [format_seconds [expr $G(test.$name.done) - $G(test.$name.start)]] set res "OK" if {$G(test.$name.nError)} { set res "FAILED" } set dots [string repeat . [expr 60 - [string length $name]]] set msg "$name $dots $res ($t)" wapptest_output $msg if {[info exists G(test.$name.errmsg)] && $G(test.$name.errmsg)!=""} { wapptest_output " $G(test.$name.errmsg)" } } # This is a fileevent callback invoked each time a file-descriptor that # connects this process to a slave process is readable. # proc slave_fileevent {name} { global G set fd $G(test.$name.channel) if {[eof $fd]} { fconfigure $fd -blocking 1 set rc [catch { close $fd }] unset G(test.$name.channel) slave_test_done $name $rc } else { set line [gets $fd] if {[string trim $line] != ""} { puts "Trace : $name - \"$line\"" } } do_some_stuff } # Return the contents of the "slave script" - the script run by slave # processes to actually perform the test. All it does is execute the # test script already written to disk (wapptest_cmd.sh or wapptest_cmd.bat). # proc wapptest_slave_script {} { global G if {$G(msvc)==0} { set dir [file join .. $G(srcdir)] set res [subst -nocommands { set rc [catch "exec sh wapptest_cmd.sh {$dir} >>& test.log" ] exit [set rc] }] } else { set dir [file nativename [file normalize $G(srcdir)]] set dir [string map [list "\\" "\\\\"] $dir] set res [subst -nocommands { set rc [catch "exec wapptest_cmd.bat {$dir} >>& test.log" ] exit [set rc] }] } set res } # Launch a slave process to run a test. # proc slave_launch {name target dir} { global G catch { file mkdir $dir } msg foreach f [glob -nocomplain [file join $dir *]] { catch { file delete -force $f } } set G(test.$name.dir) $dir # Write the test command to wapptest_cmd.sh|bat. # set ext sh if {$G(msvc)} { set ext bat } set fd1 [open [file join $dir wapptest_cmd.$ext] w] if {$G(msvc)} { puts $fd1 [releasetest_data script -msvc $name $target] } else { puts $fd1 [releasetest_data script $name $target] } close $fd1 # Write the wapptest_run.tcl script to the test directory. To run the # commands in the other two files. # set fd3 [open [file join $dir wapptest_run.tcl] w] puts $fd3 [wapptest_slave_script] close $fd3 set pwd [pwd] cd $dir set fd [open "|[info nameofexecutable] wapptest_run.tcl" r+] cd $pwd set G(test.$name.channel) $fd fconfigure $fd -blocking 0 fileevent $fd readable [list slave_fileevent $name] } proc do_some_stuff {} { global G # Count the number of running jobs. A running job has an entry named # "channel" in its dictionary. set nRunning 0 set bFinished 1 foreach j $G(test_array) { set name [dict get $j config] if { [info exists G(test.$name.channel)]} { incr nRunning } if {![info exists G(test.$name.done)]} { set bFinished 0 } } if {$bFinished} { set nError 0 set nTest 0 set nConfig 0 foreach j $G(test_array) { set name [dict get $j config] incr nError $G(test.$name.nError) incr nTest $G(test.$name.nTest) incr nConfig } set G(result) "$nError errors from $nTest tests in $nConfig configurations." wapptest_output [string repeat * 70] wapptest_output $G(result) catch { append G(result) " SQLite version $G(sqlite_version)" wapptest_output " SQLite version $G(sqlite_version)" } set G(state) "stopped" wapptest_closelog if {$G(noui)} { exit 0 } } else { set nLaunch [expr $G(jobs) - $nRunning] foreach j $G(test_array) { if {$nLaunch<=0} break set name [dict get $j config] if { ![info exists G(test.$name.channel)] && ![info exists G(test.$name.done)] } { set target [dict get $j target] set dir [string tolower [string map {" " _ "-" _} $name]] set G(test.$name.start) [clock seconds] set G(test.$name.log) [file join $dir test.log] slave_launch $name $target $dir incr nLaunch -1 } } } } proc generate_select_widget {label id lOpt opt} { wapp-trim { <label> %string($label) </label> <select id=%string($id) name=%string($id)> } foreach o $lOpt { set selected "" if {$o==$opt} { set selected " selected=1" } wapp-subst "<option $selected>$o</option>" } wapp-trim { </select> } } proc generate_main_page {{extra {}}} { global G set_test_array set hostname $G(hostname) wapp-trim { <html> <head> <title> %html($hostname): wapptest.tcl </title> <link rel="stylesheet" type="text/css" href="style.css"/> </head> <body> } set host $G(host) wapp-trim { <div class="border">%string($host) } generate_fossil_info wapp-trim { </div> <div class="border" id=controls> <form action="control" method="post" name="control"> } # Build the "platform" select widget. set lOpt [releasetest_data platforms] generate_select_widget Platform control_platform $lOpt $G(platform) # Build the "test" select widget. set lOpt [list Normal Veryquick Smoketest Build-Only] generate_select_widget Test control_test $lOpt $G(test) # Build the "jobs" select widget. Options are 1 to 8. generate_select_widget Jobs control_jobs {1 2 3 4 5 6 7 8} $G(jobs) switch $G(state) { config { set txt "Run Tests!" set id control_run } running { set txt "STOP Tests!" set id control_stop } stopped { set txt "Reset!" set id control_reset } } wapp-trim { <div class=right> <input id=%string($id) name=%string($id) type=submit value="%string($txt)"> </input> </div> } wapp-trim { <br><br> <label> Tcl: </label> <input id="control_tcl" name="control_tcl"></input> <label> Keep files: </label> <input id="control_keep" name="control_keep" type=checkbox value=1> </input> <label> Use MSVC: </label> <input id="control_msvc" name="control_msvc" type=checkbox value=1> <label> Debug tests: </label> <input id="control_debug" name="control_debug" type=checkbox value=1> </input> } wapp-trim { </form> } wapp-trim { </div> <div id=tests> } wapp-page-tests set script "script/$G(state).js" wapp-trim { </div> <script src=%string($script)></script> </body> </html> } } proc wapp-default {} { generate_main_page } proc wapp-page-tests {} { global G wapp-trim { <table class="border" width=100%> } foreach t $G(test_array) { set config [dict get $t config] set target [dict get $t target] set class "testwait" set seconds "" if {[info exists G(test.$config.log)]} { if {[info exists G(test.$config.channel)]} { set class "testrunning" set seconds [expr [clock seconds] - $G(test.$config.start)] } elseif {[info exists G(test.$config.done)]} { if {$G(test.$config.nError)>0} { set class "testfail" } else { set class "testdone" } set seconds [expr $G(test.$config.done) - $G(test.$config.start)] } set seconds [format_seconds $seconds] } wapp-trim { <tr class=%string($class)> <td class="nowrap"> %html($config) <td class="padleft nowrap"> %html($target) <td class="padleft nowrap"> %html($seconds) <td class="padleft nowrap"> } if {[info exists G(test.$config.log)]} { set log $G(test.$config.log) set uri "log/$log" wapp-trim { <a href=%url($uri)> %html($log) </a> } } if {[info exists G(test.$config.errmsg)] && $G(test.$config.errmsg)!=""} { set errmsg $G(test.$config.errmsg) wapp-trim { <tr class=testfail> <td> <td class="padleft" colspan=3> %html($errmsg) } } } wapp-trim { </table> } if {[info exists G(result)]} { set res $G(result) wapp-trim { <div class=border id=result> %string($res) </div> } } } # URI: /control # # Whenever the form at the top of the application page is submitted, it # is submitted here. # proc wapp-page-control {} { global G if {$::G(state)=="config"} { set lControls [list platform test tcl jobs keep msvc debug] set G(msvc) 0 set G(keep) 0 set G(debug) 0 } else { set lControls [list jobs] } foreach v $lControls { if {[wapp-param-exists control_$v]} { set G($v) [wapp-param control_$v] } } if {[wapp-param-exists control_run]} { # This is a "run test" command. wapptest_run } if {[wapp-param-exists control_stop]} { # A "STOP tests" command. set G(state) "stopped" set G(result) "Test halted by user" foreach j $G(test_array) { set name [dict get $j config] if { [info exists G(test.$name.channel)] } { close $G(test.$name.channel) unset G(test.$name.channel) slave_test_done $name 1 } } wapptest_closelog } if {[wapp-param-exists control_reset]} { # A "reset app" command. set G(state) "config" wapptest_init } if {$::G(state) == "running"} { do_some_stuff } wapp-redirect / } # URI: /style.css # # Return the stylesheet for the application main page. # proc wapp-page-style.css {} { wapp-subst { /* The boxes with black borders use this class */ .border { border: 3px groove #444444; padding: 1em; margin-top: 1em; margin-bottom: 1em; } /* Float to the right (used for the Run/Stop/Reset button) */ .right { float: right; } /* Style for the large red warning at the top of the page */ .warning { color: red; font-weight: bold; } /* Styles used by cells in the test table */ .padleft { padding-left: 5ex; } .nowrap { white-space: nowrap; } /* Styles for individual tests, depending on the outcome */ .testwait { } .testrunning { color: blue } .testdone { color: green } .testfail { color: red } } } # URI: /script/${state}.js # # The last part of this URI is always "config.js", "running.js" or # "stopped.js", depending on the state of the application. It returns # the javascript part of the front-end for the requested state to the # browser. # proc wapp-page-script {} { regexp {[^/]*$} [wapp-param REQUEST_URI] script set tcl $::G(tcl) set keep $::G(keep) set msvc $::G(msvc) set debug $::G(debug) wapp-subst { var lElem = \["control_platform", "control_test", "control_msvc", "control_jobs", "control_debug" \]; lElem.forEach(function(e) { var elem = document.getElementById(e); elem.addEventListener("change", function() { control.submit() } ); }) elem = document.getElementById("control_tcl"); elem.value = "%string($tcl)" elem = document.getElementById("control_keep"); elem.checked = %string($keep); elem = document.getElementById("control_msvc"); elem.checked = %string($msvc); elem = document.getElementById("control_debug"); elem.checked = %string($debug); } if {$script != "config.js"} { wapp-subst { var lElem = \["control_platform", "control_test", "control_tcl", "control_keep", "control_msvc", "control_debug" \]; lElem.forEach(function(e) { var elem = document.getElementById(e); elem.disabled = true; }) } } if {$script == "running.js"} { wapp-subst { function reload_tests() { fetch('tests') .then( data => data.text() ) .then( data => { document.getElementById("tests").innerHTML = data; }) .then( data => { if( document.getElementById("result") ){ document.location = document.location; } else { setTimeout(reload_tests, 1000) } }); } setTimeout(reload_tests, 1000) } } } # URI: /env # # This is for debugging only. Serves no other purpose. # proc wapp-page-env {} { wapp-allow-xorigin-params wapp-trim { <h1>Wapp Environment</h1>\n<pre> <pre>%html([wapp-debug-env])</pre> } } # URI: /log/dirname/test.log # # This URI reads file "dirname/test.log" from disk, wraps it in a <pre> # block, and returns it to the browser. Use for viewing log files. # proc wapp-page-log {} { set log [string range [wapp-param REQUEST_URI] 5 end] set fd [open $log] set data [read $fd] close $fd wapp-trim { <pre> %html($data) </pre> } } # Print out a usage message. Then do [exit 1]. # proc wapptest_usage {} { puts stderr { This Tcl script is used to test various configurations of SQLite. By default it uses "wapp" to provide an interactive interface. Supported command line options (all optional) are: --platform PLATFORM (which tests to run) --smoketest (run "make smoketest" only) --veryquick (run veryquick.test only) --buildonly (build executables, do not run tests) --jobs N (number of concurrent jobs) --tcl DIR (where to find tclConfig.sh) --deletefiles (delete extra files after each test) --msvc (Use MS Visual C) --debug (Also run [n]debugging versions of tests) --noui (do not use wapp) } exit 1 } # Sort command line arguments into two groups: those that belong to wapp, # and those that belong to the application. set WAPPARG(-server) 1 set WAPPARG(-local) 1 set WAPPARG(-scgi) 1 set WAPPARG(-remote-scgi) 1 set WAPPARG(-fromip) 1 set WAPPARG(-nowait) 0 set WAPPARG(-cgi) 0 set lWappArg [list] set lTestArg [list] for {set i 0} {$i < [llength $argv]} {incr i} { set arg [lindex $argv $i] if {[string range $arg 0 1]=="--"} { set arg [string range $arg 1 end] } if {[info exists WAPPARG($arg)]} { lappend lWappArg $arg if {$WAPPARG($arg)} { incr i lappend lWappArg [lindex $argv $i] } } else { lappend lTestArg $arg } } wapptest_init for {set i 0} {$i < [llength $lTestArg]} {incr i} { set opt [lindex $lTestArg $i] if {[string range $opt 0 1]=="--"} { set opt [string range $opt 1 end] } switch -- $opt { -platform { if {$i==[llength $lTestArg]-1} { wapptest_usage } incr i set arg [lindex $lTestArg $i] set lPlatform [releasetest_data platforms] if {[lsearch $lPlatform $arg]<0} { puts stderr "No such platform: $arg. Platforms are: $lPlatform" exit -1 } set G(platform) $arg } -smoketest { set G(test) Smoketest } -veryquick { set G(test) Veryquick } -buildonly { set G(test) Build-Only } -jobs { if {$i==[llength $lTestArg]-1} { wapptest_usage } incr i set G(jobs) [lindex $lTestArg $i] } -tcl { if {$i==[llength $lTestArg]-1} { wapptest_usage } incr i set G(tcl) [lindex $lTestArg $i] } -deletefiles { set G(keep) 0 } -msvc { set G(msvc) 1 } -debug { set G(debug) 1 } -noui { set G(noui) 1 set G(stdout) 1 } -stdout { set G(stdout) 1 } default { puts stderr "Unrecognized option: [lindex $lTestArg $i]" wapptest_usage } } } if {$G(noui)==0} { wapp-start $lWappArg } else { wapptest_run do_some_stuff vwait forever } |
Changes to test/where.test.
︙ | ︙ | |||
66 67 68 69 70 71 72 | count {SELECT x, y, w FROM t1 WHERE w=10} } {3 121 10 3} do_test where-1.1.1b { count {SELECT x, y, w FROM t1 WHERE w IS 10} } {3 121 10 3} do_eqp_test where-1.1.2 { SELECT x, y, w FROM t1 WHERE w=10 | | | | | | 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 | count {SELECT x, y, w FROM t1 WHERE w=10} } {3 121 10 3} do_test where-1.1.1b { count {SELECT x, y, w FROM t1 WHERE w IS 10} } {3 121 10 3} do_eqp_test where-1.1.2 { SELECT x, y, w FROM t1 WHERE w=10 } {*SEARCH t1 USING INDEX i1w (w=?)*} do_eqp_test where-1.1.2b { SELECT x, y, w FROM t1 WHERE w IS 10 } {*SEARCH t1 USING INDEX i1w (w=?)*} do_test where-1.1.3 { db status step } {0} do_test where-1.1.4 { db eval {SELECT x, y, w FROM t1 WHERE +w=10} } {3 121 10} do_test where-1.1.5 { db status step } {99} do_eqp_test where-1.1.6 { SELECT x, y, w FROM t1 WHERE +w=10 } {*SCAN t1*} do_test where-1.1.7 { count {SELECT x, y, w AS abc FROM t1 WHERE abc=10} } {3 121 10 3} do_eqp_test where-1.1.8 { SELECT x, y, w AS abc FROM t1 WHERE abc=10 } {*SEARCH t1 USING INDEX i1w (w=?)*} do_test where-1.1.9 { db status step } {0} do_test where-1.2.1 { count {SELECT x, y, w FROM t1 WHERE w=11} } {3 144 11 3} do_test where-1.2.2 { |
︙ | ︙ | |||
114 115 116 117 118 119 120 | count {SELECT w, x, y FROM t1 WHERE 11=w AND x>2} } {11 3 144 3} do_test where-1.4.1b { count {SELECT w, x, y FROM t1 WHERE 11 IS w AND x>2} } {11 3 144 3} do_eqp_test where-1.4.2 { SELECT w, x, y FROM t1 WHERE 11=w AND x>2 | | | | | | | | 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 | count {SELECT w, x, y FROM t1 WHERE 11=w AND x>2} } {11 3 144 3} do_test where-1.4.1b { count {SELECT w, x, y FROM t1 WHERE 11 IS w AND x>2} } {11 3 144 3} do_eqp_test where-1.4.2 { SELECT w, x, y FROM t1 WHERE 11=w AND x>2 } {*SEARCH t1 USING INDEX i1w (w=?)*} do_eqp_test where-1.4.2b { SELECT w, x, y FROM t1 WHERE 11 IS w AND x>2 } {*SEARCH t1 USING INDEX i1w (w=?)*} do_test where-1.4.3 { count {SELECT w AS a, x AS b, y FROM t1 WHERE 11=a AND b>2} } {11 3 144 3} do_eqp_test where-1.4.4 { SELECT w AS a, x AS b, y FROM t1 WHERE 11=a AND b>2 } {*SEARCH t1 USING INDEX i1w (w=?)*} do_test where-1.5 { count {SELECT x, y FROM t1 WHERE y<200 AND w=11 AND x>2} } {3 144 3} do_eqp_test where-1.5.2 { SELECT x, y FROM t1 WHERE y<200 AND w=11 AND x>2 } {*SEARCH t1 USING INDEX i1w (w=?)*} do_test where-1.6 { count {SELECT x, y FROM t1 WHERE y<200 AND x>2 AND w=11} } {3 144 3} do_test where-1.7 { count {SELECT x, y FROM t1 WHERE w=11 AND y<200 AND x>2} } {3 144 3} do_test where-1.8 { count {SELECT x, y FROM t1 WHERE w>10 AND y=144 AND x=3} } {3 144 3} do_eqp_test where-1.8.2 { SELECT x, y FROM t1 WHERE w>10 AND y=144 AND x=3 } {*SEARCH t1 USING INDEX i1xy (x=? AND y=?)*} do_eqp_test where-1.8.3 { SELECT x, y FROM t1 WHERE y=144 AND x=3 } {*SEARCH t1 USING COVERING INDEX i1xy (x=? AND y=?)*} do_test where-1.9 { count {SELECT x, y FROM t1 WHERE y=144 AND w>10 AND x=3} } {3 144 3} do_test where-1.10 { count {SELECT x, y FROM t1 WHERE x=3 AND w>=10 AND y=121} } {3 121 3} do_test where-1.11 { |
︙ | ︙ | |||
486 487 488 489 490 491 492 | SELECT * FROM t1 WHERE x IN (1,7) AND y NOT IN (6400,8100) ORDER BY 1; } } {2 1 9 3 1 16 6} do_test where-5.14 { count { SELECT * FROM t1 WHERE x IN (1,7) AND y IN (9,10) ORDER BY 1; } | | | | 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 | SELECT * FROM t1 WHERE x IN (1,7) AND y NOT IN (6400,8100) ORDER BY 1; } } {2 1 9 3 1 16 6} do_test where-5.14 { count { SELECT * FROM t1 WHERE x IN (1,7) AND y IN (9,10) ORDER BY 1; } } {2 1 9 5} do_test where-5.15 { count { SELECT * FROM t1 WHERE x IN (1,7) AND y IN (9,16) ORDER BY 1; } } {2 1 9 3 1 16 9} do_test where-5.100 { db eval { SELECT w, x, y FROM t1 WHERE x IN (1,5) AND y IN (9,8,3025,1000,3969) ORDER BY x, y } } {2 1 9 54 5 3025 62 5 3969} do_test where-5.101 { |
︙ | ︙ | |||
1421 1422 1423 1424 1425 1426 1427 | CREATE TABLE t1(a INT); CREATE INDEX t1a ON t1(a); INSERT INTO t1(a) VALUES(NULL),(NULL),(42),(NULL),(NULL); CREATE TABLE t2(dummy INT); SELECT count(*) FROM t1 LEFT JOIN t2 ON a IS NOT NULL; } {5} | > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 | CREATE TABLE t1(a INT); CREATE INDEX t1a ON t1(a); INSERT INTO t1(a) VALUES(NULL),(NULL),(42),(NULL),(NULL); CREATE TABLE t2(dummy INT); SELECT count(*) FROM t1 LEFT JOIN t2 ON a IS NOT NULL; } {5} # 20190-02-22: A bug introduced by checkin # https://www.sqlite.org/src/info/fa792714ae62fa98. # do_execsql_test where-23.0 { DROP TABLE IF EXISTS t1; DROP TABLE IF EXISTS t2; CREATE TABLE t1(a INTEGER PRIMARY KEY); INSERT INTO t1(a) VALUES(1),(2),(3); CREATE TABLE t2(x INTEGER PRIMARY KEY, y INT); INSERT INTO t2(y) VALUES(2),(3); SELECT * FROM t1, t2 WHERE a=y AND y=3; } {3 2 3} #------------------------------------------------------------------------- # reset_db do_execsql_test where-24.0 { CREATE TABLE t1(a INTEGER PRIMARY KEY, b); INSERT INTO t1 VALUES(1, 'one'); INSERT INTO t1 VALUES(2, 'two'); INSERT INTO t1 VALUES(3, 'three'); INSERT INTO t1 VALUES(4, 'four'); } foreach {tn sql res} { 1 "SELECT b FROM t1" {one two three four} 2 "SELECT b FROM t1 WHERE a<4" {one two three} 3 "SELECT b FROM t1 WHERE a>1" {two three four} 4 "SELECT b FROM t1 WHERE a>1 AND a<4" {two three} 5 "SELECT b FROM t1 WHERE a>? AND a<4" {} 6 "SELECT b FROM t1 WHERE a>1 AND a<?" {} 7 "SELECT b FROM t1 WHERE a>? AND a<?" {} 7 "SELECT b FROM t1 WHERE a>=? AND a<=4" {} 8 "SELECT b FROM t1 WHERE a>=1 AND a<=?" {} 9 "SELECT b FROM t1 WHERE a>=? AND a<=?" {} } { set rev [list] foreach r $res { set rev [concat $r $rev] } do_execsql_test where-24.$tn.1 "$sql" $res do_execsql_test where-24.$tn.2 "$sql ORDER BY rowid" $res do_execsql_test where-24.$tn.3 "$sql ORDER BY rowid DESC" $rev do_execsql_test where-24-$tn.4 " BEGIN; DELETE FROM t1; $sql; $sql ORDER BY rowid; $sql ORDER BY rowid DESC; ROLLBACK; " } #------------------------------------------------------------------------- # reset_db do_execsql_test where-25.0 { CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c); CREATE UNIQUE INDEX i1 ON t1(c); INSERT INTO t1 VALUES(1, 'one', 'i'); INSERT INTO t1 VALUES(2, 'two', 'ii'); CREATE TABLE t2(a INTEGER PRIMARY KEY, b, c); CREATE UNIQUE INDEX i2 ON t2(c); INSERT INTO t2 VALUES(1, 'one', 'i'); INSERT INTO t2 VALUES(2, 'two', 'ii'); INSERT INTO t2 VALUES(3, 'three', 'iii'); PRAGMA writable_schema = 1; UPDATE sqlite_schema SET rootpage = ( SELECT rootpage FROM sqlite_schema WHERE name = 'i2' ) WHERE name = 'i1'; } db close sqlite3 db test.db do_catchsql_test where-25.1 { DELETE FROM t1 WHERE c='iii' } {1 {database disk image is malformed}} do_catchsql_test where-25.2 { INSERT INTO t1 VALUES(4, 'four', 'iii') ON CONFLICT(c) DO UPDATE SET b=NULL } {1 {database disk image is malformed}} reset_db do_execsql_test where-25.3 { CREATE TABLE t1(a PRIMARY KEY, b, c) WITHOUT ROWID; CREATE UNIQUE INDEX i1 ON t1(c); INSERT INTO t1 VALUES(1, 'one', 'i'); INSERT INTO t1 VALUES(2, 'two', 'ii'); CREATE TABLE t2(a INTEGER PRIMARY KEY, b, c); CREATE UNIQUE INDEX i2 ON t2(c); INSERT INTO t2 VALUES(1, 'one', 'i'); INSERT INTO t2 VALUES(2, 'two', 'ii'); INSERT INTO t2 VALUES(3, 'three', 'iii'); PRAGMA writable_schema = 1; UPDATE sqlite_schema SET rootpage = ( SELECT rootpage FROM sqlite_schema WHERE name = 'i2' ) WHERE name = 'i1'; } db close sqlite3 db test.db do_catchsql_test where-25.4 { SELECT * FROM t1 WHERE c='iii' } {0 {}} do_catchsql_test where-25.5 { INSERT INTO t1 VALUES(4, 'four', 'iii') ON CONFLICT(c) DO UPDATE SET b=NULL } {1 {corrupt database}} # 2019-08-21 Ticket https://www.sqlite.org/src/info/d9f584e936c7a8d0 # db close sqlite3 db :memory: do_execsql_test where-26.1 { CREATE TABLE t0(c0 INTEGER PRIMARY KEY, c1 TEXT); INSERT INTO t0(c0, c1) VALUES (1, 'a'); CREATE TABLE t1(c0 INT PRIMARY KEY, c1 TEXT); INSERT INTO t1(c0, c1) VALUES (1, 'a'); SELECT * FROM t0 WHERE '-1' BETWEEN 0 AND t0.c0; } {1 a} do_execsql_test where-26.2 { SELECT * FROM t1 WHERE '-1' BETWEEN 0 AND t1.c0; } {1 a} do_execsql_test where-26.3 { SELECT * FROM t0 WHERE '-1'>=0 AND '-1'<=t0.c0; } {1 a} do_execsql_test where-26.4 { SELECT * FROM t1 WHERE '-1'>=0 AND '-1'<=t1.c0; } {1 a} do_execsql_test where-26.5 { SELECT '-1' BETWEEN 0 AND t0.c0 FROM t0; } {1} do_execsql_test where-26.6 { SELECT '-1' BETWEEN 0 AND t1.c0 FROM t1; } {1} do_execsql_test where-26.7 { SELECT '-1'>=0 AND '-1'<=t0.c0 FROM t0; } {1} do_execsql_test where-26.8 { SELECT '-1'>=0 AND '-1'<=t1.c0 FROM t1; } {1} # 2021-07-19 https://sqlite.org/forum/forumpost/2bdb86a068 # Lose of precision when doing comparisons between integer and # floating point values that are near 9223372036854775807 in the # OP_SeekGE opcode (and similar). # # Valgrind documentation acknowledges that under valgrind, FP calculations # may not be as accurate as on x86/amd64 hardware. This seems to be causing # these tests to fail. # # https://valgrind.org/docs/manual/manual-core.html#manual-core.limits # if {[permutation]!="valgrind"} { reset_db do_execsql_test where-27.1 { CREATE TABLE t1(a INTEGER PRIMARY KEY); INSERT INTO t1(a) VALUES(9223372036854775807); SELECT 1 FROM t1 WHERE a>=(9223372036854775807+1); } {} do_execsql_test where-27.2 { SELECT a>=9223372036854775807+1 FROM t1; } {0} } finish_test |
Changes to test/where2.test.
︙ | ︙ | |||
72 73 74 75 76 77 78 | set ::sqlite_sort_count 0 set data [execsql $sql] if {$::sqlite_sort_count} {set x sort} {set x nosort} lappend data $x set eqp [execsql "EXPLAIN QUERY PLAN $sql"] # puts eqp=$eqp foreach {a b c x} $eqp { | > > | | | | 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 | set ::sqlite_sort_count 0 set data [execsql $sql] if {$::sqlite_sort_count} {set x sort} {set x nosort} lappend data $x set eqp [execsql "EXPLAIN QUERY PLAN $sql"] # puts eqp=$eqp foreach {a b c x} $eqp { if {[regexp {SCAN CONSTANT} $x]} { # noop } elseif {[regexp {(SCAN|SEARCH) (\w+ AS )?(\w+) USING.* INDEX (\w+)\y} \ $x all ss as tab idx]} { lappend data $tab $idx } elseif {[regexp {(SCAN|SEARCH) (\w+ AS )?(\w+)\y} $x all ss as tab]} { lappend data $tab * } } return $data } |
︙ | ︙ | |||
749 750 751 752 753 754 755 | do_execsql_test where2-12.1 { CREATE TABLE t12(x INTEGER PRIMARY KEY, y INT, z CHAR(100)); CREATE INDEX t12y ON t12(y); EXPLAIN QUERY PLAN SELECT a.x, b.x FROM t12 AS a JOIN t12 AS b ON a.y=b.x WHERE (b.x=$abc OR b.y=$abc); | | | 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 | do_execsql_test where2-12.1 { CREATE TABLE t12(x INTEGER PRIMARY KEY, y INT, z CHAR(100)); CREATE INDEX t12y ON t12(y); EXPLAIN QUERY PLAN SELECT a.x, b.x FROM t12 AS a JOIN t12 AS b ON a.y=b.x WHERE (b.x=$abc OR b.y=$abc); } {/SEARCH b .*SEARCH b /} } # Verify that all necessary OP_OpenRead opcodes occur in the OR optimization. # do_execsql_test where2-13.1 { CREATE TABLE t13(a,b); CREATE INDEX t13a ON t13(a); |
︙ | ︙ |
Changes to test/where3.test.
︙ | ︙ | |||
107 108 109 110 111 112 113 | # proc queryplan {sql} { set ::sqlite_sort_count 0 set data [execsql $sql] set eqp [execsql "EXPLAIN QUERY PLAN $sql"] # puts eqp=$eqp foreach {a b c x} $eqp { | > > | | | | 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 | # proc queryplan {sql} { set ::sqlite_sort_count 0 set data [execsql $sql] set eqp [execsql "EXPLAIN QUERY PLAN $sql"] # puts eqp=$eqp foreach {a b c x} $eqp { if {[regexp {SCAN CONSTANT} $x]} { # noop } elseif {[regexp {(SCAN|SEARCH) (\w+ AS )?(\w+) USING.* INDEX (\w+)\y} \ $x all ss as tab idx]} { lappend data $tab $idx } elseif {[regexp {(SCAN|SEARCH) (\w+ AS )?(\w+)\y} $x all ss as tab]} { lappend data $tab * } } return $data } |
︙ | ︙ | |||
236 237 238 239 240 241 242 | INSERT INTO t302 VALUES(4,5); ANALYZE; } do_eqp_test where3-3.0a { SELECT * FROM t302, t301 WHERE t302.x=5 AND t301.a=t302.y; } { QUERY PLAN | | | | | | | | | | | | | | | 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 | INSERT INTO t302 VALUES(4,5); ANALYZE; } do_eqp_test where3-3.0a { SELECT * FROM t302, t301 WHERE t302.x=5 AND t301.a=t302.y; } { QUERY PLAN |--SCAN t302 `--SEARCH t301 USING INTEGER PRIMARY KEY (rowid=?) } do_eqp_test where3-3.1 { SELECT * FROM t301, t302 WHERE t302.x=5 AND t301.a=t302.y; } { QUERY PLAN |--SCAN t302 `--SEARCH t301 USING INTEGER PRIMARY KEY (rowid=?) } do_execsql_test where3-3.2 { SELECT * FROM t301 WHERE c=3 AND a IS NULL; } {} do_execsql_test where3-3.3 { SELECT * FROM t301 WHERE c=3 AND a IS NOT NULL; } {1 2 3 2 2 3} if 0 { # Query planner no longer does this # Verify that when there are multiple tables in a join which must be # full table scans that the query planner attempts put the table with # the fewest number of output rows as the outer loop. # do_execsql_test where3-4.0 { CREATE TABLE t400(a INTEGER PRIMARY KEY, b, c); CREATE TABLE t401(p INTEGER PRIMARY KEY, q, r); CREATE TABLE t402(x INTEGER PRIMARY KEY, y, z); EXPLAIN QUERY PLAN SELECT * FROM t400, t401, t402 WHERE t402.z GLOB 'abc*'; } { 0 0 2 {SCAN t402} 0 1 0 {SCAN t400} 0 2 1 {SCAN t401} } do_execsql_test where3-4.1 { EXPLAIN QUERY PLAN SELECT * FROM t400, t401, t402 WHERE t401.r GLOB 'abc*'; } { 0 0 1 {SCAN t401} 0 1 0 {SCAN t400} 0 2 2 {SCAN t402} } do_execsql_test where3-4.2 { EXPLAIN QUERY PLAN SELECT * FROM t400, t401, t402 WHERE t400.c GLOB 'abc*'; } { 0 0 0 {SCAN t400} 0 1 1 {SCAN t401} 0 2 2 {SCAN t402} } } ;# endif # Verify that a performance regression encountered by firefox # has been fixed. # do_execsql_test where3-5.0 { |
︙ | ︙ | |||
317 318 319 320 321 322 323 | FROM aaa JOIN bbb ON bbb.id = aaa.parent WHERE aaa.fk = 'constant' AND LENGTH(bbb.title) > 0 AND bbb.parent = 4 ORDER BY bbb.title COLLATE NOCASE ASC; } { QUERY PLAN | | | | | | | | | | 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 | FROM aaa JOIN bbb ON bbb.id = aaa.parent WHERE aaa.fk = 'constant' AND LENGTH(bbb.title) > 0 AND bbb.parent = 4 ORDER BY bbb.title COLLATE NOCASE ASC; } { QUERY PLAN |--SEARCH aaa USING INDEX aaa_333 (fk=?) |--SEARCH bbb USING INTEGER PRIMARY KEY (rowid=?) `--USE TEMP B-TREE FOR ORDER BY } do_eqp_test where3-5.1 { SELECT bbb.title AS tag_title FROM aaa JOIN aaa AS bbb ON bbb.id = aaa.parent WHERE aaa.fk = 'constant' AND LENGTH(bbb.title) > 0 AND bbb.parent = 4 ORDER BY bbb.title COLLATE NOCASE ASC; } { QUERY PLAN |--SEARCH aaa USING INDEX aaa_333 (fk=?) |--SEARCH bbb USING INTEGER PRIMARY KEY (rowid=?) `--USE TEMP B-TREE FOR ORDER BY } do_eqp_test where3-5.2 { SELECT bbb.title AS tag_title FROM bbb JOIN aaa ON bbb.id = aaa.parent WHERE aaa.fk = 'constant' AND LENGTH(bbb.title) > 0 AND bbb.parent = 4 ORDER BY bbb.title COLLATE NOCASE ASC; } { QUERY PLAN |--SEARCH aaa USING INDEX aaa_333 (fk=?) |--SEARCH bbb USING INTEGER PRIMARY KEY (rowid=?) `--USE TEMP B-TREE FOR ORDER BY } do_eqp_test where3-5.3 { SELECT bbb.title AS tag_title FROM aaa AS bbb JOIN aaa ON bbb.id = aaa.parent WHERE aaa.fk = 'constant' AND LENGTH(bbb.title) > 0 AND bbb.parent = 4 ORDER BY bbb.title COLLATE NOCASE ASC; } { QUERY PLAN |--SEARCH aaa USING INDEX aaa_333 (fk=?) |--SEARCH bbb USING INTEGER PRIMARY KEY (rowid=?) `--USE TEMP B-TREE FOR ORDER BY } # Name resolution with NATURAL JOIN and USING # do_test where3-6.setup { db eval { |
︙ | ︙ |
Changes to test/where7.test.
︙ | ︙ | |||
23349 23350 23351 23352 23353 23354 23355 | AND t302.c3 > 1287603136 AND (t301.c4 = 1407449685622784 OR t301.c8 = 1407424651264000) ORDER BY t302.c5 LIMIT 200; } { QUERY PLAN |--MULTI-INDEX OR | > | > | | | 23349 23350 23351 23352 23353 23354 23355 23356 23357 23358 23359 23360 23361 23362 23363 23364 | AND t302.c3 > 1287603136 AND (t301.c4 = 1407449685622784 OR t301.c8 = 1407424651264000) ORDER BY t302.c5 LIMIT 200; } { QUERY PLAN |--MULTI-INDEX OR | |--INDEX 1 | | `--SEARCH t301 USING COVERING INDEX t301_c4 (c4=?) | `--INDEX 2 | `--SEARCH t301 USING INTEGER PRIMARY KEY (rowid=?) |--SEARCH t302 USING INDEX t302_c8_c3 (c8=? AND c3>?) `--USE TEMP B-TREE FOR ORDER BY } finish_test |
Changes to test/where9.test.
︙ | ︙ | |||
358 359 360 361 362 363 364 | ifcapable explain { do_eqp_test where9-3.1 { SELECT t2.a FROM t1, t2 WHERE t1.a=80 AND ((t1.c=t2.c AND t1.d=t2.d) OR t1.f=t2.f) } [string map {"\n " \n} { QUERY PLAN | | > | > | | > | > | | 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 | ifcapable explain { do_eqp_test where9-3.1 { SELECT t2.a FROM t1, t2 WHERE t1.a=80 AND ((t1.c=t2.c AND t1.d=t2.d) OR t1.f=t2.f) } [string map {"\n " \n} { QUERY PLAN |--SEARCH t1 USING INTEGER PRIMARY KEY (rowid=?) `--MULTI-INDEX OR |--INDEX 1 | `--SEARCH t2 USING INDEX t2d (d=?) `--INDEX 3 `--SEARCH t2 USING COVERING INDEX t2f (f=?) }] do_eqp_test where9-3.2 { SELECT coalesce(t2.a,9999) FROM t1 LEFT JOIN t2 ON (t1.c+1=t2.c AND t1.d=t2.d) OR (t1.f||'x')=t2.f WHERE t1.a=80 } [string map {"\n " \n} { QUERY PLAN |--SEARCH t1 USING INTEGER PRIMARY KEY (rowid=?) `--MULTI-INDEX OR |--INDEX 1 | `--SEARCH t2 USING INDEX t2d (d=?) `--INDEX 2 `--SEARCH t2 USING COVERING INDEX t2f (f=?) }] } # Make sure that INDEXED BY and multi-index OR clauses play well with # one another. # do_test where9-4.1 { |
︙ | ︙ | |||
418 419 420 421 422 423 424 | do_test where9-4.5 { catchsql { SELECT a FROM t1 INDEXED BY t1b WHERE +b>1000 AND (c=31031 OR d IS NULL) ORDER BY +a } | | | | > | > | | | | 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 | do_test where9-4.5 { catchsql { SELECT a FROM t1 INDEXED BY t1b WHERE +b>1000 AND (c=31031 OR d IS NULL) ORDER BY +a } } {0 {92 93 97}} do_test where9-4.6 { count_steps { SELECT a FROM t1 NOT INDEXED WHERE b>1000 AND (c=31031 OR d IS NULL) ORDER BY +a } } {92 93 97 scan 98 sort 1} do_test where9-4.7 { catchsql { SELECT a FROM t1 INDEXED BY t1c WHERE b>1000 AND (c=31031 OR d IS NULL) ORDER BY +a } } {0 {92 93 97}} do_test where9-4.8 { catchsql { SELECT a FROM t1 INDEXED BY t1d WHERE b>1000 AND (c=31031 OR d IS NULL) ORDER BY +a } } {0 {92 93 97}} # The (c=31031 OR d IS NULL) clause is preferred over b>1000 because # the former is an equality test which is expected to return fewer rows. # do_eqp_test where9-5.1 { SELECT a FROM t1 WHERE b>1000 AND (c=31031 OR d IS NULL) } { QUERY PLAN `--MULTI-INDEX OR |--INDEX 1 | `--SEARCH t1 USING INDEX t1c (c=?) `--INDEX 2 `--SEARCH t1 USING INDEX t1d (d=?) } # In contrast, b=1000 is preferred over any OR-clause. # do_eqp_test where9-5.2 { SELECT a FROM t1 WHERE b=1000 AND (c=31031 OR d IS NULL) } {SEARCH t1 USING INDEX t1b (b=?)} # Likewise, inequalities in an AND are preferred over inequalities in # an OR. # do_eqp_test where9-5.3 { SELECT a FROM t1 WHERE b>1000 AND (c>=31031 OR d IS NULL) } {SEARCH t1 USING INDEX t1b (b>?)} ############################################################################ # Make sure OR-clauses work correctly on UPDATE and DELETE statements. do_test where9-6.2.1 { db eval {SELECT count(*) FROM t1 UNION ALL SELECT a FROM t1 WHERE a>=85} } {99 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99} |
︙ | ︙ | |||
766 767 768 769 770 771 772 | do_test where9-6.8.1 { catchsql { DELETE FROM t1 INDEXED BY t1b WHERE (+b IS NULL AND c NOT NULL AND d NOT NULL) OR (b NOT NULL AND c IS NULL AND d NOT NULL) OR (b NOT NULL AND c NOT NULL AND d IS NULL) } | | | | | 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 | do_test where9-6.8.1 { catchsql { DELETE FROM t1 INDEXED BY t1b WHERE (+b IS NULL AND c NOT NULL AND d NOT NULL) OR (b NOT NULL AND c IS NULL AND d NOT NULL) OR (b NOT NULL AND c NOT NULL AND d IS NULL) } } {0 {}} do_test where9-6.8.2 { catchsql { UPDATE t1 INDEXED BY t1b SET a=a+100 WHERE (+b IS NULL AND c NOT NULL AND d NOT NULL) OR (b NOT NULL AND c IS NULL AND d NOT NULL) OR (b NOT NULL AND c NOT NULL AND d IS NULL) } } {0 {}} set solution_possible 0 ifcapable stat4 { if {[permutation] != "no_optimization"} { set solution_possible 1 } } if $solution_possible { # When STAT3 is enabled, the "b NOT NULL" terms get translated # into b>NULL, which can be satified by the index t1b. It is a very # expensive way to do the query, but it works, and so a solution is possible. do_test where9-6.8.3-stat4 { |
︙ | ︙ | |||
808 809 810 811 812 813 814 | do_test where9-6.8.3 { catchsql { UPDATE t1 INDEXED BY t1b SET a=a+100 WHERE (b IS NULL AND c NOT NULL AND d NOT NULL) OR (b NOT NULL AND c IS NULL AND d NOT NULL) OR (b NOT NULL AND c NOT NULL AND d IS NULL) } | | | | 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 | do_test where9-6.8.3 { catchsql { UPDATE t1 INDEXED BY t1b SET a=a+100 WHERE (b IS NULL AND c NOT NULL AND d NOT NULL) OR (b NOT NULL AND c IS NULL AND d NOT NULL) OR (b NOT NULL AND c NOT NULL AND d IS NULL) } } {0 {}} do_test where9-6.8.4 { catchsql { DELETE FROM t1 INDEXED BY t1b WHERE (b IS NULL AND c NOT NULL AND d NOT NULL) OR (b NOT NULL AND c IS NULL AND d NOT NULL) OR (b NOT NULL AND c NOT NULL AND d IS NULL) } } {0 {}} } ############################################################################ # Test cases where terms inside an OR series are combined with AND terms # external to the OR clause. In other words, cases where # # x AND (y OR z) # |
︙ | ︙ | |||
850 851 852 853 854 855 856 | CREATE INDEX t5ye ON t5(y, e); CREATE INDEX t5yf ON t5(y, f); CREATE INDEX t5yg ON t5(y, g); CREATE TABLE t6(a, b, c, e, d, f, g, x, y); INSERT INTO t6 SELECT * FROM t5; ANALYZE t5; } | < < < < < | 856 857 858 859 860 861 862 863 864 865 866 867 868 869 | CREATE INDEX t5ye ON t5(y, e); CREATE INDEX t5yf ON t5(y, f); CREATE INDEX t5yg ON t5(y, g); CREATE TABLE t6(a, b, c, e, d, f, g, x, y); INSERT INTO t6 SELECT * FROM t5; ANALYZE t5; } } {} do_test where9-7.1.1 { count_steps { SELECT a FROM t5 WHERE x='y' AND (b=913 OR c=27027) ORDER BY a; } } {79 81 83 scan 0 sort 1} do_test where9-7.1.2 { |
︙ | ︙ | |||
977 978 979 980 981 982 983 | INSERT INTO t102 VALUES ('1'); SELECT * FROM t102 AS t0 LEFT JOIN t102 AS t1 ON t1.id GLOB 'abc%' JOIN t102 AS t2 ON (t2.id = t0.id OR (t2.id<>555 AND t2.id=t1.id)); } } {1 {} 1} | > > > > > > > | > > > > > > > > > > | 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 | INSERT INTO t102 VALUES ('1'); SELECT * FROM t102 AS t0 LEFT JOIN t102 AS t1 ON t1.id GLOB 'abc%' JOIN t102 AS t2 ON (t2.id = t0.id OR (t2.id<>555 AND t2.id=t1.id)); } } {1 {} 1} # dbsqlfuzz 9df1d53c24c4c96af0dae15ee764897af415ac76 # The MULTI-INDEX OR processing evaluates the same WHERE-clause sub-expression # twice. But if that sub-expression contains a UNION ALL SELECT statement # subject to query flattening, the sub-expression might be transformed in a # way that it can only be code-generated once. An assert() will fail on # the second attempt to generate code from the same sub-expression. # The solution is to make a copy of sub-expressions used by MULTI-INDEX OR # reset_db do_execsql_test where9-11.1 { CREATE TABLE t1(a INTEGER PRIMARY KEY, b TEXT); CREATE TABLE t2_a(k INTEGER PRIMARY KEY, v TEXT); CREATE TABLE t2_b(k INTEGER PRIMARY KEY, v TEXT); CREATE VIEW t2 AS SELECT * FROM t2_a UNION ALL SELECT * FROM t2_b; SELECT 1 FROM t1 JOIN t1 USING(a) WHERE (a=1) OR (a=2 AND (SELECT 4 FROM t2,(SELECT 5 FROM t1 ORDER BY a) WHERE a)); } {} finish_test |
Changes to test/whereA.test.
︙ | ︙ | |||
165 166 167 168 169 170 171 172 173 174 | PRAGMA reverse_unordered_selects=on; DROP TABLE IF EXISTS t1; CREATE TABLE t1(a,b); INSERT INTO t1 VALUES(1,2); CREATE INDEX t1b ON t1(b); SELECT a FROM t1 WHERE b=-99 OR b>1; } {1} finish_test | > > > > > > > > > > > > > > > | 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 | PRAGMA reverse_unordered_selects=on; DROP TABLE IF EXISTS t1; CREATE TABLE t1(a,b); INSERT INTO t1 VALUES(1,2); CREATE INDEX t1b ON t1(b); SELECT a FROM t1 WHERE b=-99 OR b>1; } {1} # 2020-10-02 OSSFuzz find for an issue introduced by a check-in # on the previous day. # reset_db do_execsql_test whereA-6.1 { CREATE TABLE t1(a, b); CREATE INDEX t1aa ON t1(a,a); INSERT INTO t1 VALUES(1,2); ANALYZE; UPDATE sqlite_stat1 SET stat='27 3 3' WHERE idx='t1aa'; ANALYZE sqlite_schema; PRAGMA reverse_unordered_selects (1) ; SELECT a FROM t1 WHERE a=1 OR a=2; } {1} finish_test |
Changes to test/whereD.test.
︙ | ︙ | |||
332 333 334 335 336 337 338 339 340 341 342 343 344 345 | } {3 7 11 search 7} do_searchcount_test 6.6.3 { SELECT c FROM x1 WHERE c=11 OR a=1 OR b=6 } {11 3 7 search 7} do_searchcount_test 6.6.4 { SELECT c FROM x1 WHERE b=6 OR c=11 OR a=1 } {7 11 3 search 7} #------------------------------------------------------------------------- # do_execsql_test 7.0 { CREATE TABLE y1(a, b); CREATE TABLE y2(x, y); CREATE INDEX y2xy ON y2(x, y); | > > > > > > > > > > > > > > > > | 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 | } {3 7 11 search 7} do_searchcount_test 6.6.3 { SELECT c FROM x1 WHERE c=11 OR a=1 OR b=6 } {11 3 7 search 7} do_searchcount_test 6.6.4 { SELECT c FROM x1 WHERE b=6 OR c=11 OR a=1 } {7 11 3 search 7} # 2020-02-22 ticket aa4378693018aa99 # In the OP_Column opcode, if a cursor is marked with OP_NullRow # (because it is the right table of a LEFT JOIN that does not match) # then do not substitute index cursors, as the index cursors do not # have the VdbeCursor.nullRow flag set. # do_execsql_test 6.7 { DROP TABLE IF EXISTS t1; DROP TABLE IF EXISTS t2; CREATE TABLE t1(a UNIQUE, b UNIQUE); INSERT INTO t1(a,b) VALUES(null,2); CREATE VIEW t2 AS SELECT * FROM t1 WHERE b<10 OR a<7 ORDER BY b; SELECT t1.* FROM t1 LEFT JOIN t2 ON abs(t1.a)=abs(t2.b); } {{} 2} #------------------------------------------------------------------------- # do_execsql_test 7.0 { CREATE TABLE y1(a, b); CREATE TABLE y2(x, y); CREATE INDEX y2xy ON y2(x, y); |
︙ | ︙ |
Changes to test/whereE.test.
︙ | ︙ | |||
13 14 15 16 17 18 19 20 21 22 23 24 25 26 | # is making good planning decisions. # set testdir [file dirname $argv0] source $testdir/tester.tcl set ::testprefix whereE do_execsql_test 1.1 { CREATE TABLE t1(a,b); INSERT INTO t1 VALUES(1,10), (2,20), (3,30), (2,22), (3, 33); INSERT INTO t1 SELECT * FROM t1; INSERT INTO t1 SELECT * FROM t1; INSERT INTO t1 SELECT * FROM t1; | > > > > > > | 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | # is making good planning decisions. # set testdir [file dirname $argv0] source $testdir/tester.tcl set ::testprefix whereE # If SQLITE_OMIT_ALTERTABLE is defined, omit this file. ifcapable !altertable { finish_test return } do_execsql_test 1.1 { CREATE TABLE t1(a,b); INSERT INTO t1 VALUES(1,10), (2,20), (3,30), (2,22), (3, 33); INSERT INTO t1 SELECT * FROM t1; INSERT INTO t1 SELECT * FROM t1; INSERT INTO t1 SELECT * FROM t1; |
︙ | ︙ | |||
43 44 45 46 47 48 49 | INSERT INTO t2 SELECT x+32, (x+32)*11 FROM t2; INSERT INTO t2 SELECT x+64, (x+32)*11 FROM t2; ALTER TABLE t2 ADD COLUMN z; UPDATE t2 SET z=2; CREATE UNIQUE INDEX t2zx ON t2(z,x); EXPLAIN QUERY PLAN SELECT x FROM t1, t2 WHERE a=z AND c=x; | | | | | | 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | INSERT INTO t2 SELECT x+32, (x+32)*11 FROM t2; INSERT INTO t2 SELECT x+64, (x+32)*11 FROM t2; ALTER TABLE t2 ADD COLUMN z; UPDATE t2 SET z=2; CREATE UNIQUE INDEX t2zx ON t2(z,x); EXPLAIN QUERY PLAN SELECT x FROM t1, t2 WHERE a=z AND c=x; } {/.*SCAN t1.*SEARCH t2.*/} do_execsql_test 1.2 { EXPLAIN QUERY PLAN SELECT x FROM t2, t1 WHERE a=z AND c=x; } {/.*SCAN t1.*SEARCH t2.*/} do_execsql_test 1.3 { ANALYZE; EXPLAIN QUERY PLAN SELECT x FROM t1, t2 WHERE a=z AND c=x; } {/.*SCAN t1.*SEARCH t2.*/} do_execsql_test 1.4 { EXPLAIN QUERY PLAN SELECT x FROM t2, t1 WHERE a=z AND c=x; } {/.*SCAN t1.*SEARCH t2.*/} finish_test |
Changes to test/whereF.test.
︙ | ︙ | |||
59 60 61 62 63 64 65 | foreach {tn sql} { 1 "SELECT * FROM t1, t2 WHERE t1.a=t2.e AND t2.d<t1.b AND t1.c!=10" 2 "SELECT * FROM t2, t1 WHERE t1.a=t2.e AND t2.d<t1.b AND t1.c!=10" 3 "SELECT * FROM t2 CROSS JOIN t1 WHERE t1.a=t2.e AND t2.d<t1.b AND t1.c!=10" } { do_test 1.$tn { db eval "EXPLAIN QUERY PLAN $sql" | | | | 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 | foreach {tn sql} { 1 "SELECT * FROM t1, t2 WHERE t1.a=t2.e AND t2.d<t1.b AND t1.c!=10" 2 "SELECT * FROM t2, t1 WHERE t1.a=t2.e AND t2.d<t1.b AND t1.c!=10" 3 "SELECT * FROM t2 CROSS JOIN t1 WHERE t1.a=t2.e AND t2.d<t1.b AND t1.c!=10" } { do_test 1.$tn { db eval "EXPLAIN QUERY PLAN $sql" } {/.*SCAN t2\y.*SEARCH t1\y.*/} } do_execsql_test 2.0 { DROP TABLE t1; DROP TABLE t2; CREATE TABLE t1(a, b, c); CREATE TABLE t2(d, e, f); CREATE UNIQUE INDEX i1 ON t1(a); CREATE UNIQUE INDEX i2 ON t1(b); CREATE UNIQUE INDEX i3 ON t2(d); } {} foreach {tn sql} { 1 "SELECT * FROM t1, t2 WHERE t1.a>? AND t2.d>t1.c AND t1.b=t2.e" 2 "SELECT * FROM t2, t1 WHERE t1.a>? AND t2.d>t1.c AND t1.b=t2.e" 3 "SELECT * FROM t2 CROSS JOIN t1 WHERE t1.a>? AND t2.d>t1.c AND t1.b=t2.e" } { do_test 2.$tn { db eval "EXPLAIN QUERY PLAN $sql" } {/.*SCAN t2\y.*SEARCH t1\y.*/} } do_execsql_test 3.0 { DROP TABLE t1; DROP TABLE t2; CREATE TABLE t1(a, b, c); CREATE TABLE t2(d, e, f); |
︙ | ︙ | |||
105 106 107 108 109 110 111 | WHERE t2.d=t1.b AND t1.a=(t2.d+1) AND t1.b = (t2.e+1)} 3 {SELECT t1.a, t1.b, t2.d, t2.e FROM t2 CROSS JOIN t1 WHERE t2.d=t1.b AND t1.a=(t2.d+1) AND t1.b = (t2.e+1)} } { do_test 3.$tn { db eval "EXPLAIN QUERY PLAN $sql" | | | 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 | WHERE t2.d=t1.b AND t1.a=(t2.d+1) AND t1.b = (t2.e+1)} 3 {SELECT t1.a, t1.b, t2.d, t2.e FROM t2 CROSS JOIN t1 WHERE t2.d=t1.b AND t1.a=(t2.d+1) AND t1.b = (t2.e+1)} } { do_test 3.$tn { db eval "EXPLAIN QUERY PLAN $sql" } {/.*SCAN t2\y.*SEARCH t1\y.*/} } do_execsql_test 4.0 { CREATE TABLE t4(a,b,c,d,e, PRIMARY KEY(a,b,c)); CREATE INDEX t4adc ON t4(a,d,c); CREATE UNIQUE INDEX t4aebc ON t4(a,e,b,c); EXPLAIN QUERY PLAN SELECT rowid FROM t4 WHERE a=? AND b=?; |
︙ | ︙ |
Changes to test/whereG.test.
︙ | ︙ | |||
152 153 154 155 156 157 158 | # do_execsql_test whereG-3.0 { CREATE TABLE a(a1 PRIMARY KEY, a2); CREATE TABLE b(b1 PRIMARY KEY, b2); } {} do_eqp_test whereG-3.1 { SELECT * FROM a, b WHERE b1=a1 AND a2=5; | | | | | | 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 | # do_execsql_test whereG-3.0 { CREATE TABLE a(a1 PRIMARY KEY, a2); CREATE TABLE b(b1 PRIMARY KEY, b2); } {} do_eqp_test whereG-3.1 { SELECT * FROM a, b WHERE b1=a1 AND a2=5; } {/.*SCAN a.*SEARCH b USING INDEX .*b_1 .b1=..*/} do_eqp_test whereG-3.2 { SELECT * FROM a, b WHERE a1=b1 AND a2=5; } {/.*SCAN a.*SEARCH b USING INDEX .*b_1 .b1=..*/} do_eqp_test whereG-3.3 { SELECT * FROM a, b WHERE a2=5 AND b1=a1; } {/.*SCAN a.*SEARCH b USING INDEX .*b_1 .b1=..*/} do_eqp_test whereG-3.4 { SELECT * FROM a, b WHERE a2=5 AND a1=b1; } {/.*SCAN a.*SEARCH b USING INDEX .*b_1 .b1=..*/} # Ticket [1e64dd782a126f48d78c43a664844a41d0e6334e]: # Incorrect result in a nested GROUP BY/DISTINCT due to the use of an OP_SCopy # where an OP_Copy was needed. # do_execsql_test whereG-4.0 { CREATE TABLE t4(x); |
︙ | ︙ | |||
191 192 193 194 195 196 197 | do_execsql_test 5.1 { CREATE TABLE t1(a, b, c); CREATE INDEX i1 ON t1(a, b); } do_eqp_test 5.1.2 { SELECT * FROM t1 WHERE a>? | | | | | | | > > > > > | | | > | | | 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 | do_execsql_test 5.1 { CREATE TABLE t1(a, b, c); CREATE INDEX i1 ON t1(a, b); } do_eqp_test 5.1.2 { SELECT * FROM t1 WHERE a>? } {SEARCH t1 USING INDEX i1 (a>?)} do_eqp_test 5.1.3 { SELECT * FROM t1 WHERE likelihood(a>?, 0.9) } {SCAN t1} do_eqp_test 5.1.4 { SELECT * FROM t1 WHERE likely(a>?) } {SCAN t1} do_test 5.2 { for {set i 0} {$i < 100} {incr i} { execsql { INSERT INTO t1 VALUES('abc', $i, $i); } } execsql { INSERT INTO t1 SELECT 'def', b, c FROM t1; } execsql { ANALYZE } } {} do_eqp_test 5.2.2 { SELECT * FROM t1 WHERE likelihood(b>?, 0.01) } {SEARCH t1 USING INDEX i1 (ANY(a) AND b>?)} do_eqp_test 5.2.3 { SELECT * FROM t1 WHERE likelihood(b>?, 0.9) } {SCAN t1} do_eqp_test 5.2.4 { SELECT * FROM t1 WHERE likely(b>?) } {SCAN t1} ifcapable stat4 { do_eqp_test 5.3.1.stat4 { SELECT * FROM t1 WHERE a=? } {SCAN t1} } else { do_eqp_test 5.3.1 { SELECT * FROM t1 WHERE a=? } {SEARCH t1 USING INDEX i1} } do_eqp_test 5.3.2 { SELECT * FROM t1 WHERE likelihood(a=?, 0.9) } {SCAN t1} do_eqp_test 5.3.3 { SELECT * FROM t1 WHERE likely(a=?) } {SCAN t1} # 2015-06-18 # Ticket [https://www.sqlite.org/see/tktview/472f0742a1868fb58862bc588ed70] # do_execsql_test 6.0 { DROP TABLE IF EXISTS t1; CREATE TABLE t1(i int, x, y, z); |
︙ | ︙ | |||
262 263 264 265 266 267 268 | do_execsql_test 7.2 { SELECT likelihood(a,0.5), x FROM t1, t2 ORDER BY 1, 2; } {1 3 1 4 9 3 9 4} do_execsql_test 7.3 { SELECT coalesce(a,a), x FROM t1, t2 ORDER BY 1, 2; } {1 3 1 4 9 3 9 4} | > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | do_execsql_test 7.2 { SELECT likelihood(a,0.5), x FROM t1, t2 ORDER BY 1, 2; } {1 3 1 4 9 3 9 4} do_execsql_test 7.3 { SELECT coalesce(a,a), x FROM t1, t2 ORDER BY 1, 2; } {1 3 1 4 9 3 9 4} # 2019-08-22 # Ticket https://www.sqlite.org/src/info/7e07a3dbf5a8cd26 # do_execsql_test 8.1 { DROP TABLE IF EXISTS t0; CREATE TABLE t0 (c0); INSERT INTO t0(c0) VALUES ('a'); SELECT LIKELY(t0.rowid) <= '0' FROM t0; } {1} do_execsql_test 8.2 { SELECT * FROM t0 WHERE LIKELY(t0.rowid) <= '0'; } {a} do_execsql_test 8.3 { SELECT (t0.rowid) <= '0' FROM t0; } {0} do_execsql_test 8.4 { SELECT * FROM t0 WHERE (t0.rowid) <= '0'; } {} do_execsql_test 8.5 { SELECT unlikely(t0.rowid) <= '0', likelihood(t0.rowid,0.5) <= '0' FROM t0; } {1 1} do_execsql_test 8.6 { SELECT * FROM t0 WHERE unlikely(t0.rowid) <= '0'; } {a} do_execsql_test 8.7 { SELECT * FROM t0 WHERE likelihood(t0.rowid, 0.5) <= '0'; } {a} do_execsql_test 8.8 { SELECT unlikely(t0.rowid <= '0'), likely(t0.rowid <= '0'), likelihood(t0.rowid <= '0',0.5) FROM t0; } {0 0 0} do_execsql_test 8.9 { SELECT * FROM t0 WHERE unlikely(t0.rowid <= '0'); } {} do_execsql_test 8.10 { SELECT * FROM t0 WHERE likelihood(t0.rowid <= '0', 0.5); } {} # 2019-12-31: assertion fault discovered by Yongheng's fuzzer. # Harmless memIsValid() due to the code generators failure to # release the registers used by OP_ResultRow. # do_execsql_test 9.10 { DROP TABLE IF EXISTS t1; CREATE TABLE t1(a, b FLOAT); INSERT INTO t1(a) VALUES(''),(NULL),('X'),(NULL); SELECT coalesce(max(quote(a)),10) FROM t1 GROUP BY a; } {NULL '' 'X'} # 2020-06-14: assert() changed back into testcase() # ticket 9fb26d37cefaba40 # reset_db do_execsql_test 10.1 { CREATE TABLE a(b TEXT); INSERT INTO a VALUES(0),(4),(9); CREATE TABLE c(d NUM); CREATE VIEW f(g, h) AS SELECT b, 0 FROM a UNION SELECT d, d FROM c; SELECT g = g FROM f GROUP BY h; } {1} reset_db do_execsql_test 11.0 { CREATE TABLE t1(x PRIMARY KEY, y); INSERT INTO t1 VALUES('AAA', 'BBB'); CREATE TABLE t2(z); INSERT INTO t2 VALUES('t2'); CREATE TABLE t3(x PRIMARY KEY, y); INSERT INTO t3 VALUES('AAA', 'AAA'); } do_execsql_test 11.1.1 { SELECT * FROM t1 JOIN t2 ON unlikely(x=y) AND y='AAA' } do_execsql_test 11.1.2 { SELECT * FROM t1 JOIN t2 ON likely(x=y) AND y='AAA' } do_execsql_test 11.1.3 { SELECT * FROM t1 JOIN t2 ON x=y AND y='AAA' } do_execsql_test 11.2.1 { SELECT * FROM t3 JOIN t2 ON unlikely(x=y) AND y='AAA' } {AAA AAA t2} do_execsql_test 11.2.2 { SELECT * FROM t3 JOIN t2 ON likely(x=y) AND y='AAA' } {AAA AAA t2} do_execsql_test 11.2.3 { SELECT * FROM t3 JOIN t2 ON x=y AND y='AAA' } {AAA AAA t2} # 2021-06-14 forum https://sqlite.org/forum/forumpost/3b940c437a # Affinity problem when a likely() function is used as a column in # an index. # reset_db do_execsql_test 12.0 { CREATE TABLE t1(a REAL); INSERT INTO t1(a) VALUES(123); CREATE INDEX t1x1 ON t1(likely(a)); SELECT typeof(likely(a)) FROM t1 NOT INDEXED; SELECT typeof(likely(a)) FROM t1 INDEXED BY t1x1; } {real real} do_execsql_test 12.1 { CREATE INDEX t1x2 ON t1(abs(a)); SELECT typeof(abs(a)) FROM t1 NOT INDEXED; SELECT typeof(abs(a)) FROM t1 INDEXED BY t1x2; } {real real} finish_test |
Changes to test/whereI.test.
︙ | ︙ | |||
27 28 29 30 31 32 33 | } do_eqp_test 1.1 { SELECT a FROM t1 WHERE b='b' OR c='x' } { QUERY PLAN `--MULTI-INDEX OR | > | > | | 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | } do_eqp_test 1.1 { SELECT a FROM t1 WHERE b='b' OR c='x' } { QUERY PLAN `--MULTI-INDEX OR |--INDEX 1 | `--SEARCH t1 USING INDEX i1 (b=?) `--INDEX 2 `--SEARCH t1 USING INDEX i2 (c=?) } do_execsql_test 1.2 { SELECT a FROM t1 WHERE b='b' OR c='x' } {2 3} do_execsql_test 1.3 { |
︙ | ︙ | |||
57 58 59 60 61 62 63 | } do_eqp_test 2.1 { SELECT a FROM t2 WHERE b='b' OR c='x' } { QUERY PLAN `--MULTI-INDEX OR | > | > | | 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 | } do_eqp_test 2.1 { SELECT a FROM t2 WHERE b='b' OR c='x' } { QUERY PLAN `--MULTI-INDEX OR |--INDEX 1 | `--SEARCH t2 USING INDEX i3 (b=?) `--INDEX 2 `--SEARCH t2 USING INDEX i4 (c=?) } do_execsql_test 2.2 { SELECT a FROM t2 WHERE b='b' OR c='x' } {ii iii} do_execsql_test 2.3 { |
︙ | ︙ |
Changes to test/whereJ.test.
︙ | ︙ | |||
398 399 400 401 402 403 404 | # This one should use index "idx_c". do_eqp_test 3.4 { SELECT * FROM t1 WHERE a = 4 AND b BETWEEN 20 AND 80 -- Matches 80 rows AND c BETWEEN 150 AND 160 -- Matches 10 rows | | | | 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 | # This one should use index "idx_c". do_eqp_test 3.4 { SELECT * FROM t1 WHERE a = 4 AND b BETWEEN 20 AND 80 -- Matches 80 rows AND c BETWEEN 150 AND 160 -- Matches 10 rows } {SEARCH t1 USING INDEX idx_c (c>? AND c<?)} # This one should use index "idx_ab". do_eqp_test 3.5 { SELECT * FROM t1 WHERE a = 5 AND b BETWEEN 20 AND 80 -- Matches 1 row AND c BETWEEN 150 AND 160 -- Matches 10 rows } {SEARCH t1 USING INDEX idx_ab (a=? AND b>? AND b<?)} ########################################################################################### # Reset the database and setup for a test case derived from actual SQLite users # db close sqlite3 db test.db |
︙ | ︙ | |||
629 630 631 632 633 634 635 | px WHERE cx.code = '2990' AND cx.type=2 AND px.cx_id = cx.cx_id AND px.px_tid = 0 AND px.le_id = le.le_id; | | | 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 | px WHERE cx.code = '2990' AND cx.type=2 AND px.cx_id = cx.cx_id AND px.px_tid = 0 AND px.le_id = le.le_id; } {/.*SCAN cx.*SEARCH px.*SEARCH le.*/} # The following test is derived from a performance problem reported from # the field. Notice the multiple indexes with the same initial tables, # and the unusual WHERE clause terms. # do_test 5.1 { |
︙ | ︙ |
Changes to test/whereK.test.
︙ | ︙ | |||
29 30 31 32 33 34 35 | INSERT INTO t1(a,b,c) SELECT x, x/10, x%10 FROM c; CREATE INDEX t1bc ON t1(b,c); SELECT a FROM t1 WHERE b>9 OR b=9 ORDER BY +a; } {90 91 92 93 94 95 96 97 98 99} do_execsql_test 1.1eqp { EXPLAIN QUERY PLAN SELECT a FROM t1 WHERE b>9 OR b=9 ORDER BY +a; | | | | | | | 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 | INSERT INTO t1(a,b,c) SELECT x, x/10, x%10 FROM c; CREATE INDEX t1bc ON t1(b,c); SELECT a FROM t1 WHERE b>9 OR b=9 ORDER BY +a; } {90 91 92 93 94 95 96 97 98 99} do_execsql_test 1.1eqp { EXPLAIN QUERY PLAN SELECT a FROM t1 WHERE b>9 OR b=9 ORDER BY +a; } {/SEARCH t1 USING INDEX t1bc/} do_execsql_test 1.2 { SELECT a FROM t1 WHERE b>8 OR (b=8 AND c>7) ORDER BY +a; } {88 89 90 91 92 93 94 95 96 97 98 99} do_execsql_test 1.2eqp { EXPLAIN QUERY PLAN SELECT a FROM t1 WHERE b>8 OR (b=8 AND c>7) ORDER BY +a; } {/SEARCH t1 USING INDEX t1bc/} do_execsql_test 1.3 { SELECT a FROM t1 WHERE (b=8 AND c>7) OR b>8 ORDER BY +a; } {88 89 90 91 92 93 94 95 96 97 98 99} do_execsql_test 1.3eqp { EXPLAIN QUERY PLAN SELECT a FROM t1 WHERE (b=8 AND c>7) OR b>8 ORDER BY +a; } {/SEARCH t1 USING INDEX t1bc/} do_execsql_test 1.4 { SELECT a FROM t1 WHERE (b=8 AND c>7) OR 8<b ORDER BY +a; } {88 89 90 91 92 93 94 95 96 97 98 99} do_execsql_test 1.4eqp { EXPLAIN QUERY PLAN SELECT a FROM t1 WHERE (b=8 AND c>7) OR 8<b ORDER BY +a; } {/SEARCH t1 USING INDEX t1bc/} do_execsql_test 1.5 { SELECT a FROM t1 WHERE (b=8 AND c>7) OR (b>8 AND c NOT IN (4,5,6)) ORDER BY +a; } {88 89 90 91 92 93 97 98 99} do_execsql_test 1.5eqp { EXPLAIN QUERY PLAN SELECT a FROM t1 WHERE (b=8 AND c>7) OR (b>8 AND c NOT IN (4,5,6)) ORDER BY +a; } {/SEARCH t1 USING INDEX t1bc/} finish_test |
Changes to test/whereL.test.
︙ | ︙ | |||
22 23 24 25 26 27 28 | CREATE TABLE t3(a INT PRIMARY KEY, j, k, l, m); CREATE VIEW v4 AS SELECT * FROM t2 UNION ALL SELECT * FROM t3; } do_eqp_test 110 { SELECT * FROM t1, v4 WHERE t1.a=?1 AND v4.a=t1.a; } { QUERY PLAN | < | | > | | | < | | | | | 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 | CREATE TABLE t3(a INT PRIMARY KEY, j, k, l, m); CREATE VIEW v4 AS SELECT * FROM t2 UNION ALL SELECT * FROM t3; } do_eqp_test 110 { SELECT * FROM t1, v4 WHERE t1.a=?1 AND v4.a=t1.a; } { QUERY PLAN `--COMPOUND QUERY |--LEFT-MOST SUBQUERY | |--SEARCH t1 USING INDEX sqlite_autoindex_t1_1 (a=?) | `--SEARCH t2 USING INDEX sqlite_autoindex_t2_1 (a=?) `--UNION ALL |--SEARCH t1 USING INDEX sqlite_autoindex_t1_1 (a=?) `--SEARCH t3 USING INDEX sqlite_autoindex_t3_1 (a=?) } # The scan of the t1 table goes first since that enables the ORDER BY # sort to be omitted. This would not be possible without constant # propagation because without it the t1 table would depend on t3. # do_eqp_test 120 { SELECT * FROM t1, t2, t3 WHERE t1.a=t2.a AND t2.a=t3.j AND t3.j=5 ORDER BY t1.a; } { QUERY PLAN |--SEARCH t1 USING INDEX sqlite_autoindex_t1_1 (a=?) |--SEARCH t2 USING INDEX sqlite_autoindex_t2_1 (a=?) `--SCAN t3 } # Constant propagation in the face of collating sequences: # do_execsql_test 200 { CREATE TABLE c3(x COLLATE binary, y COLLATE nocase, z COLLATE binary); CREATE INDEX c3x ON c3(x); |
︙ | ︙ | |||
117 118 119 120 121 122 123 124 125 | do_execsql_test 400 { CREATE TABLE x(a, b, c); CREATE TABLE y(a, b); INSERT INTO x VALUES (1, 0, 1); INSERT INTO y VALUES (1, 2); SELECT x.a FROM x JOIN y ON x.c = y.a WHERE x.b = 1 AND x.b = 1; } {} finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | do_execsql_test 400 { CREATE TABLE x(a, b, c); CREATE TABLE y(a, b); INSERT INTO x VALUES (1, 0, 1); INSERT INTO y VALUES (1, 2); SELECT x.a FROM x JOIN y ON x.c = y.a WHERE x.b = 1 AND x.b = 1; } {} # 2020-01-07: ticket 82ac75ba0093e5dc # Incorrect join result due to mishandling of affinity in constant # propagation. # reset_db do_execsql_test 500 { PRAGMA automatic_index=OFF; CREATE TABLE t0(c0); INSERT INTO t0 VALUES('0'); CREATE VIEW v0(c0) AS SELECT CAST(0 AS INT) FROM t0; SELECT 200, * FROM t0, v0 WHERE 0 = t0.c0 AND t0.c0 = v0.c0; } {} do_execsql_test 510 { SELECT 200, * FROM t0, v0 WHERE t0.c0 = 0 AND t0.c0 = v0.c0; } {} do_execsql_test 520 { SELECT 200, * FROM t0, v0 WHERE 0 = t0.c0 AND v0.c0 = t0.c0; } {} do_execsql_test 530 { SELECT 200, * FROM t0, v0 WHERE t0.c0 = 0 AND v0.c0 = t0.c0; } {} # 2020-02-13: ticket 1dcb4d44964846ad # A problem introduced while making optimizations on the fixes above. # reset_db do_execsql_test 600 { CREATE TABLE t1(x TEXT); CREATE TABLE t2(y TEXT); INSERT INTO t1 VALUES('good'),('bad'); INSERT INTO t2 VALUES('good'),('bad'); SELECT * FROM t1 JOIN t2 ON x=y WHERE x='good' AND y='good'; } {good good} # 2020-04-24: Another test case for the previous (1dcb4d44964846ad) # ticket. The test case comes from # https://stackoverflow.com/questions/61399253/sqlite3-different-result-in-console-compared-to-python-script/ # Output verified against postgresql. # do_execsql_test 610 { CREATE TABLE tableA( ID int, RunYearMonth int ); INSERT INTO tableA VALUES(1,202003),(2,202003),(3,202003),(4,202004), (5,202004),(6,202004),(7,202004),(8,202004); CREATE TABLE tableB ( ID int, RunYearMonth int ); INSERT INTO tableB VALUES(1,202004),(2,202004),(3,202004),(4,202004), (5,202004); SELECT * FROM ( SELECT * FROM tableA WHERE RunYearMonth = 202004 ) AS A INNER JOIN ( SELECT * FROM tableB WHERE RunYearMonth = 202004 ) AS B ON A.ID = B.ID AND A.RunYearMonth = B.RunYearMonth; } {4 202004 4 202004 5 202004 5 202004} finish_test |
Added test/whereM.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 | # 2021 May 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. # #*********************************************************************** # Tests focused on the "constant propagation" that occurs within the # WHERE clause of a SELECT statemente. # set testdir [file dirname $argv0] source $testdir/tester.tcl source $testdir/malloc_common.tcl set testprefix whereM do_execsql_test 1.0 { CREATE TABLE t1(a, b INTEGER, c TEXT, d REAL, e BLOB); INSERT INTO t1 VALUES(10.0, 10.0, 10.0, 10.0, 10.0); SELECT * FROM t1; } { 10.0 10 10.0 10.0 10.0 } do_execsql_test 1.1.1 { SELECT a=10, a = '10.0', a LIKE '10.0' FROM t1; } {1 0 1} do_execsql_test 1.1.2 { SELECT count(*) FROM t1 WHERE a=10 AND a = '10.0' } {0} do_execsql_test 1.1.3 { SELECT count(*) FROM t1 WHERE a=10 AND a LIKE '10.0' } {1} do_execsql_test 1.1.4 { SELECT count(*) FROM t1 WHERE a='10.0' AND a LIKE '10.0' } {0} do_execsql_test 1.2.1 { SELECT b=10, b = '10.0', b LIKE '10.0', b LIKE '10' FROM t1; } {1 1 0 1} do_execsql_test 1.2.2 { SELECT count(*) FROM t1 WHERE b=10 AND b = '10.0' } {1} do_execsql_test 1.2.3 { SELECT count(*) FROM t1 WHERE b=10 AND b LIKE '10.0' } {0} do_execsql_test 1.2.4 { SELECT count(*) FROM t1 WHERE b='10.0' AND b LIKE '10.0' } {0} do_execsql_test 1.2.3 { SELECT count(*) FROM t1 WHERE b=10 AND b LIKE '10' } {1} do_execsql_test 1.2.4 { SELECT count(*) FROM t1 WHERE b='10.0' AND b LIKE '10' } {1} do_execsql_test 1.3.1 { SELECT c=10, c = 10.0, c = '10.0', c LIKE '10.0' FROM t1; } {0 1 1 1} do_execsql_test 1.3.2 { SELECT count(*) FROM t1 WHERE c=10 AND c = '10.0' } {0} do_execsql_test 1.3.3 { SELECT count(*) FROM t1 WHERE c=10 AND c LIKE '10.0' } {0} do_execsql_test 1.3.4 { SELECT count(*) FROM t1 WHERE c='10.0' AND c LIKE '10.0' } {1} do_execsql_test 1.3.5 { SELECT count(*) FROM t1 WHERE c=10.0 AND c = '10.0' } {1} do_execsql_test 1.3.6 { SELECT count(*) FROM t1 WHERE c=10.0 AND c LIKE '10.0' } {1} do_execsql_test 1.4.1 { SELECT d=10, d = 10.0, d = '10.0', d LIKE '10.0', d LIKE '10' FROM t1; } {1 1 1 1 0} do_execsql_test 1.4.2 { SELECT count(*) FROM t1 WHERE d=10 AND d = '10.0' } {1} do_execsql_test 1.4.3 { SELECT count(*) FROM t1 WHERE d=10 AND d LIKE '10.0' } {1} do_execsql_test 1.4.4 { SELECT count(*) FROM t1 WHERE d='10.0' AND d LIKE '10.0' } {1} do_execsql_test 1.4.5 { SELECT count(*) FROM t1 WHERE d='10' AND d LIKE '10.0' } {1} do_execsql_test 1.5.1 { SELECT e=10, e = '10.0', e LIKE '10.0', e LIKE '10' FROM t1; } {1 0 1 0} do_execsql_test 1.5.2 { SELECT count(*) FROM t1 WHERE e=10 AND e = '10.0' } {0} do_execsql_test 1.5.3 { SELECT count(*) FROM t1 WHERE e=10 AND e LIKE '10.0' } {1} do_execsql_test 1.5.4 { SELECT count(*) FROM t1 WHERE e='10.0' AND e LIKE '10.0' } {0} do_execsql_test 1.5.5 { SELECT count(*) FROM t1 WHERE e=10.0 AND e LIKE '10.0' } {1} finish_test |
Changes to test/wherefault.test.
︙ | ︙ | |||
51 52 53 54 55 56 57 58 59 | set iii [expr $i*$i] db eval { INSERT INTO t1 VALUES($i, $ii, $iii) } } db eval COMMIT } -sqlbody { SELECT count(*) FROM t1 WHERE a BETWEEN 5 AND 995 OR b BETWEEN 5 AND 900000; } finish_test | > > > > > > > > > > > > > > > > > > > > > > > > | 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 | set iii [expr $i*$i] db eval { INSERT INTO t1 VALUES($i, $ii, $iii) } } db eval COMMIT } -sqlbody { SELECT count(*) FROM t1 WHERE a BETWEEN 5 AND 995 OR b BETWEEN 5 AND 900000; } reset_db do_execsql_test 3.0 { PRAGMA writable_schema = 1; BEGIN TRANSACTION; CREATE TABLE t1( a INT AS (c*11), b TEXT AS (substr(d,1,3)) STORED, c INTEGEB PRIMARI KEY, d TEXT ); CREATE INDEX t1a ON t1(a); COMMIT; } faultsim_save_and_close do_faultsim_test 3.1 -faults oom* -prep { faultsim_restore_and_reopen } -body { execsql { SELECT * FROM (SELECT a FROM t1 NATURAL JOIN t1 WHERE a IN (SELECT b FROM t1 ORDER BY b)) WHERE (SELECT a FROM t1 NATURAL JOIN (SELECT * FROM (SELECT a FROM t1 NATURAL JOIN t1 WHERE a IN (SELECT CASE b WHEN 82 THEN 207 WHEN 869 THEN 406 WHEN 85 THEN 83 WHEN 705 THEN 698 ELSE 1992229051 END%5 FROM t1 ORDER BY b)) WHERE (SELECT a FROM t1 NATURAL JOIN (SELECT b FROM t1 ORDER BY b) WHERE a IN (SELECT b FROM t1 ORDER BY b))) WHERE a ); } } -test { faultsim_test_result {0 {}} } finish_test |
Changes to test/wherelimit.test.
︙ | ︙ | |||
90 91 92 93 94 95 96 97 98 | execsql {SELECT count(*) FROM t1} } {20} do_test wherelimit-1.3 { # limit 5 execsql {DELETE FROM t1 ORDER BY x LIMIT 5} execsql {SELECT count(*) FROM t1} } {15} do_test wherelimit-1.4 { # limit 5, offset 2 | > > > > > > > > | > > | | | | 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 | execsql {SELECT count(*) FROM t1} } {20} do_test wherelimit-1.3 { # limit 5 execsql {DELETE FROM t1 ORDER BY x LIMIT 5} execsql {SELECT count(*) FROM t1} } {15} create_test_data 4 do_test wherelimit-1.3b { # limit 5 execsql {DELETE FROM t1 RETURNING x, y, '|' ORDER BY x, y LIMIT 5} } {1 1 | 1 2 | 1 3 | 1 4 | 2 1 |} do_test wherelimit-1.3c { execsql {SELECT count(*) FROM t1} } {11} do_test wherelimit-1.4 { # limit 5, offset 2 execsql {DELETE FROM t1 RETURNING x, y, '|' ORDER BY x LIMIT 5 OFFSET 2} } {2 4 | 3 1 | 3 2 | 3 3 | 3 4 |} do_test wherelimit-1.4cnt { execsql {SELECT count(*) FROM t1} } {6} do_test wherelimit-1.5 { # limit 5, offset -2 execsql {DELETE FROM t1 ORDER BY x LIMIT 5 OFFSET -2} execsql {SELECT count(*) FROM t1} } {1} do_test wherelimit-1.6 { # limit -5 (no limit), offset 2 execsql {DELETE FROM t1 ORDER BY x LIMIT 2, -5} execsql {SELECT count(*) FROM t1} } {1} do_test wherelimit-1.7 { # limit 5, offset -2 (no offset) execsql {DELETE FROM t1 ORDER BY x LIMIT -2, 5} execsql {SELECT count(*) FROM t1} } {0} create_test_data 5 do_test wherelimit-1.8 { |
︙ | ︙ | |||
223 224 225 226 227 228 229 | } {36} do_test wherelimit-3.1 { execsql {UPDATE t1 SET y=1 WHERE x=1} execsql {SELECT count(*) FROM t1 WHERE y=1} } {11} create_test_data 6 do_test wherelimit-3.2 { | | > > | 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 | } {36} do_test wherelimit-3.1 { execsql {UPDATE t1 SET y=1 WHERE x=1} execsql {SELECT count(*) FROM t1 WHERE y=1} } {11} create_test_data 6 do_test wherelimit-3.2 { execsql {UPDATE t1 SET y=1 WHERE x=1 RETURNING x, y, '|' LIMIT 5} } {1 1 | 1 1 | 1 1 | 1 1 | 1 1 |} do_test wherelimit-3.2cnt { execsql {SELECT count(*) FROM t1 WHERE y=1} } {10} do_test wherelimit-3.3 { # limit 5 execsql {UPDATE t1 SET y=2 WHERE x=2 ORDER BY x LIMIT 5} execsql {SELECT count(*) FROM t1 WHERE y=2} } {9} |
︙ | ︙ |
Changes to test/wherelimit2.test.
︙ | ︙ | |||
214 215 216 217 218 219 220 | do_execsql_test 4.1 { BEGIN; DELETE FROM x1 ORDER BY a LIMIT 2; SELECT a FROM x1; ROLLBACK; } {3 4 5 6} | > > | | | > > | | | | 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 | do_execsql_test 4.1 { BEGIN; DELETE FROM x1 ORDER BY a LIMIT 2; SELECT a FROM x1; ROLLBACK; } {3 4 5 6} # 2020-06-03: Query planner improved so that a solution is possible. # #do_catchsql_test 4.2 { # DELETE FROM x1 INDEXED BY x1bc WHERE d=3 LIMIT 1; #} {1 {no query solution}} do_execsql_test 4.3 { DELETE FROM x1 INDEXED BY x1bc WHERE b=3 LIMIT 1; SELECT a FROM x1; } {1 2 3 4 6} # 2020-06-03: Query planner improved so that a solution is possible. # #do_catchsql_test 4.4 { # UPDATE x1 INDEXED BY x1bc SET d=5 WHERE d=3 LIMIT 1; #} {1 {no query solution}} do_execsql_test 4.5 { UPDATE x1 INDEXED BY x1bc SET d=5 WHERE b=2 LIMIT 1; SELECT a, d FROM x1; } {1 1 2 2 3 5 4 3 6 1} #------------------------------------------------------------------------- |
︙ | ︙ |
Deleted test/wild001.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to test/win32longpath.test.
︙ | ︙ | |||
20 21 22 23 24 25 26 | set testprefix win32longpath do_test 1.0 { file_control_vfsname db } win32 db close | > | > > > > > > > > > > > > > > > > | 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 | set testprefix win32longpath do_test 1.0 { file_control_vfsname db } win32 db close set rawPath [get_pwd] set path [file nativename $rawPath] sqlite3 db [file join $path test.db] -vfs win32-longpath do_test 1.1 { file_control_vfsname db } win32-longpath do_test 1.2 { db eval { BEGIN EXCLUSIVE; CREATE TABLE t1(x); INSERT INTO t1 VALUES(1); INSERT INTO t1 VALUES(2); INSERT INTO t1 VALUES(3); INSERT INTO t1 VALUES(4); SELECT x FROM t1 ORDER BY x; COMMIT; } } {1 2 3 4} set longPath(1) \\\\?\\$path\\[pid] set uriPath(1a) %5C%5C%3F%5C$path\\[pid] set uriPath(1b) %5C%5C%3F%5C$rawPath/[pid] make_win32_dir $longPath(1) set longPath(2) $longPath(1)\\[string repeat X 255] set uriPath(2a) $uriPath(1a)\\[string repeat X 255] set uriPath(2b) $uriPath(1b)/[string repeat X 255] make_win32_dir $longPath(2) set longPath(3) $longPath(2)\\[string repeat Y 255] set uriPath(3a) $uriPath(2a)\\[string repeat Y 255] set uriPath(3b) $uriPath(2b)/[string repeat Y 255] make_win32_dir $longPath(3) set fileName $longPath(3)\\test.db set uri(1a) file:$uriPath(3a)\\test.db set uri(1b) file:$uriPath(3b)/test.db set uri(1c) file:///$uriPath(3a)\\test.db set uri(1d) file:///$uriPath(3b)/test.db set uri(1e) file://localhost/$uriPath(3a)\\test.db set uri(1f) file://localhost/$uriPath(3b)/test.db do_test 1.3 { list [catch {sqlite3 db2 [string range $fileName 4 end]} msg] $msg } {1 {unable to open database file}} sqlite3 db3 $fileName -vfs win32-longpath do_test 1.4 { |
︙ | ︙ | |||
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 | SELECT x FROM t1 ORDER BY x; COMMIT; } } {5 6 7 8 9 10 11 12} db3 close # puts " Database exists \{[exists_win32_path $fileName]\}" do_delete_win32_file $fileName # puts " Files remaining \{[find_win32_file $longPath(3)\\*]\}" do_remove_win32_dir $longPath(3) do_remove_win32_dir $longPath(2) do_remove_win32_dir $longPath(1) finish_test | > > > > > > > > > > > > | 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 | SELECT x FROM t1 ORDER BY x; COMMIT; } } {5 6 7 8 9 10 11 12} db3 close # puts " Database exists \{[exists_win32_path $fileName]\}" foreach tn {1a 1b 1c 1d 1e 1f} { sqlite3 db3 $uri($tn) -vfs win32-longpath -uri 1 -translatefilename 0 do_test 1.7.$tn { db3 eval { SELECT x FROM t1 ORDER BY x; } } {5 6 7 8 9 10 11 12} db3 close } do_delete_win32_file $fileName # puts " Files remaining \{[find_win32_file $longPath(3)\\*]\}" do_remove_win32_dir $longPath(3) do_remove_win32_dir $longPath(2) do_remove_win32_dir $longPath(1) finish_test |
Changes to test/window1.test.
︙ | ︙ | |||
253 254 255 256 257 258 259 260 261 262 263 264 265 266 | } {1 {no such column: x}} do_catchsql_test 7.1.6 { SELECT trim(x) OVER (ORDER BY y) FROM t1; } {1 {trim() may not be used as a window function}} do_catchsql_test 7.1.7 { SELECT max(x) OVER abc FROM t1 WINDOW def AS (ORDER BY y); } {1 {no such window: abc}} do_execsql_test 7.2 { SELECT lead(y) OVER win, lead(y, 2) OVER win, lead(y, 3, 'default') OVER win FROM t1 | > > > | 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 | } {1 {no such column: x}} do_catchsql_test 7.1.6 { SELECT trim(x) OVER (ORDER BY y) FROM t1; } {1 {trim() may not be used as a window function}} do_catchsql_test 7.1.7 { SELECT max(x) OVER abc FROM t1 WINDOW def AS (ORDER BY y); } {1 {no such window: abc}} do_catchsql_test 7.1.8 { SELECT row_number(x) OVER () FROM t1 } {1 {wrong number of arguments to function row_number()}} do_execsql_test 7.2 { SELECT lead(y) OVER win, lead(y, 2) OVER win, lead(y, 3, 'default') OVER win FROM t1 |
︙ | ︙ | |||
367 368 369 370 371 372 373 374 375 376 377 378 379 380 | WITH aaa(x, y, z) AS ( SELECT x, y, max(y) OVER xyz FROM t4 WINDOW xyz AS (ORDER BY x) ) SELECT *, min(z) OVER (ORDER BY x) FROM aaa ORDER BY 1; } {1 g g g 2 i i g 3 l l g 4 g l g 5 a l g 6 m m g} #------------------------------------------------------------------------- # do_execsql_test 10.0 { CREATE TABLE sales(emp TEXT PRIMARY KEY, region, total); INSERT INTO sales VALUES ('Alice', 'North', 34), ('Frank', 'South', 22), | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | WITH aaa(x, y, z) AS ( SELECT x, y, max(y) OVER xyz FROM t4 WINDOW xyz AS (ORDER BY x) ) SELECT *, min(z) OVER (ORDER BY x) FROM aaa ORDER BY 1; } {1 g g g 2 i i g 3 l l g 4 g l g 5 a l g 6 m m g} do_catchsql_test 9.4 { -- 2021-04-17 dbsqlfuzz d9cf66100064952b66951845dfab41de1c124611 DROP TABLE IF EXISTS t1; CREATE TABLE t1(a,b,c,d); DROP TABLE IF EXISTS t2; CREATE TABLE t2(x,y); CREATE TRIGGER r1 AFTER INSERT ON t1 BEGIN INSERT INTO t2(x,y) SELECT a, max(d) OVER w1 FROM t1 WINDOW w1 AS (PARTITION BY EXISTS(SELECT 1 FROM t1 WHERE c=?1) ); END; } {1 {trigger cannot use variables}} do_catchsql_test 9.4.2 { CREATE TRIGGER r1 AFTER INSERT ON t1 BEGIN INSERT INTO t1(a,b) SELECT a, max(d) OVER w1 FROM t1 WINDOW w1 AS ( ORDER BY a ROWS BETWEEN ? PRECEDING AND UNBOUNDED FOLLOWING ); END; } {1 {trigger cannot use variables}} do_catchsql_test 9.4.3 { CREATE TRIGGER r1 AFTER INSERT ON t1 BEGIN INSERT INTO t1(a,b) SELECT a, max(d) OVER w1 FROM t1 WINDOW w1 AS ( ORDER BY a ROWS BETWEEN UNBOUNDED PRECEDING AND ? FOLLOWING ); END; } {1 {trigger cannot use variables}} #------------------------------------------------------------------------- # do_execsql_test 10.0 { CREATE TABLE sales(emp TEXT PRIMARY KEY, region, total); INSERT INTO sales VALUES ('Alice', 'North', 34), ('Frank', 'South', 22), |
︙ | ︙ | |||
587 588 589 590 591 592 593 | 1 1 2 2 } do_execsql_test 13.5 { SELECT a, rank() OVER(ORDER BY b) FROM t1 INTERSECT SELECT a, rank() OVER(ORDER BY b DESC) FROM t1; | | < | 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 | 1 1 2 2 } do_execsql_test 13.5 { SELECT a, rank() OVER(ORDER BY b) FROM t1 INTERSECT SELECT a, rank() OVER(ORDER BY b DESC) FROM t1; } {} # 2018-12-06 # https://www.sqlite.org/src/info/f09fcd17810f65f7 # Assertion fault when window functions are used. # # Root cause is the query flattener invoking sqlite3ExprDup() on # expressions that contain subqueries with window functions. The |
︙ | ︙ | |||
616 617 618 619 620 621 622 623 624 | CREATE TABLE t2(c); INSERT INTO t2(c) VALUES(1); SELECT y, y+1, y+2 FROM ( SELECT c IN ( SELECT (row_number() OVER()) FROM t1 ) AS y FROM t2 ); } {1 2 3} finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 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 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 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 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 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 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 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 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 | CREATE TABLE t2(c); INSERT INTO t2(c) VALUES(1); SELECT y, y+1, y+2 FROM ( SELECT c IN ( SELECT (row_number() OVER()) FROM t1 ) AS y FROM t2 ); } {1 2 3} # 2018-12-31 # https://www.sqlite.org/src/info/d0866b26f83e9c55 # Window function in correlated subquery causes assertion fault # do_catchsql_test 15.0 { WITH t(id, parent) AS ( SELECT CAST(1 AS INT), CAST(NULL AS INT) UNION ALL SELECT 2, NULL UNION ALL SELECT 3, 1 UNION ALL SELECT 4, 1 UNION ALL SELECT 5, 2 UNION ALL SELECT 6, 2 ), q AS ( SELECT t.*, ROW_NUMBER() OVER (ORDER BY t.id) AS rn FROM t WHERE parent IS NULL UNION ALL SELECT t.*, ROW_NUMBER() OVER (ORDER BY t.id) AS rn FROM q JOIN t ON t.parent = q.id ) SELECT * FROM q; } {1 {cannot use window functions in recursive queries}} do_execsql_test 15.1 { DROP TABLE IF EXISTS t1; DROP TABLE IF EXISTS t2; CREATE TABLE t1(x); INSERT INTO t1 VALUES('a'), ('b'), ('c'); CREATE TABLE t2(a, b); INSERT INTO t2 VALUES('X', 1), ('X', 2), ('Y', 2), ('Y', 3); SELECT x, ( SELECT sum(b) OVER (PARTITION BY a ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) FROM t2 WHERE b<x ) FROM t1; } {a 3 b 3 c 3} do_execsql_test 15.2 { SELECT( WITH c AS( VALUES(1) ) SELECT '' FROM c,c ) x WHERE x+x; } {} #------------------------------------------------------------------------- do_execsql_test 16.0 { CREATE TABLE t7(a,b); INSERT INTO t7(rowid, a, b) VALUES (1, 1, 3), (2, 10, 4), (3, 100, 2); } do_execsql_test 16.1 { SELECT rowid, sum(a) OVER (PARTITION BY b IN (SELECT rowid FROM t7)) FROM t7; } { 2 10 1 101 3 101 } do_execsql_test 16.2 { SELECT rowid, sum(a) OVER w1 FROM t7 WINDOW w1 AS (PARTITION BY b IN (SELECT rowid FROM t7)); } { 2 10 1 101 3 101 } #------------------------------------------------------------------------- do_execsql_test 17.0 { CREATE TABLE t8(a); INSERT INTO t8 VALUES(1), (2), (3); } do_execsql_test 17.1 { SELECT +sum(0) OVER () ORDER BY +sum(0) OVER (); } {0} do_execsql_test 17.2 { select +sum(a) OVER () FROM t8 ORDER BY +sum(a) OVER () DESC; } {6 6 6} do_execsql_test 17.3 { SELECT 10+sum(a) OVER (ORDER BY a) FROM t8 ORDER BY 10+sum(a) OVER (ORDER BY a) DESC; } {16 13 11} #------------------------------------------------------------------------- # Test error cases from chaining window definitions. # reset_db do_execsql_test 18.0 { DROP TABLE IF EXISTS t1; CREATE TABLE t1(a INTEGER PRIMARY KEY, b TEXT, c TEXT, d INTEGER); INSERT INTO t1 VALUES(1, 'odd', 'one', 1); INSERT INTO t1 VALUES(2, 'even', 'two', 2); INSERT INTO t1 VALUES(3, 'odd', 'three', 3); INSERT INTO t1 VALUES(4, 'even', 'four', 4); INSERT INTO t1 VALUES(5, 'odd', 'five', 5); INSERT INTO t1 VALUES(6, 'even', 'six', 6); } foreach {tn sql error} { 1 { SELECT c, sum(d) OVER win2 FROM t1 WINDOW win1 AS (ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING), win2 AS (win1 ORDER BY b) } {cannot override frame specification of window: win1} 2 { SELECT c, sum(d) OVER win2 FROM t1 WINDOW win1 AS (), win2 AS (win4 ORDER BY b) } {no such window: win4} 3 { SELECT c, sum(d) OVER win2 FROM t1 WINDOW win1 AS (), win2 AS (win1 PARTITION BY d) } {cannot override PARTITION clause of window: win1} 4 { SELECT c, sum(d) OVER win2 FROM t1 WINDOW win1 AS (ORDER BY b), win2 AS (win1 ORDER BY d) } {cannot override ORDER BY clause of window: win1} } { do_catchsql_test 18.1.$tn $sql [list 1 $error] } foreach {tn sql error} { 1 { SELECT c, sum(d) OVER (win1 ORDER BY b) FROM t1 WINDOW win1 AS (ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING) } {cannot override frame specification of window: win1} 2 { SELECT c, sum(d) OVER (win4 ORDER BY b) FROM t1 WINDOW win1 AS () } {no such window: win4} 3 { SELECT c, sum(d) OVER (win1 PARTITION BY d) FROM t1 WINDOW win1 AS () } {cannot override PARTITION clause of window: win1} 4 { SELECT c, sum(d) OVER (win1 ORDER BY d) FROM t1 WINDOW win1 AS (ORDER BY b) } {cannot override ORDER BY clause of window: win1} } { do_catchsql_test 18.2.$tn $sql [list 1 $error] } do_execsql_test 18.3.1 { SELECT group_concat(c, '.') OVER (PARTITION BY b ORDER BY c) FROM t1 } {four four.six four.six.two five five.one five.one.three} do_execsql_test 18.3.2 { SELECT group_concat(c, '.') OVER (win1 ORDER BY c) FROM t1 WINDOW win1 AS (PARTITION BY b) } {four four.six four.six.two five five.one five.one.three} do_execsql_test 18.3.3 { SELECT group_concat(c, '.') OVER win2 FROM t1 WINDOW win1 AS (PARTITION BY b), win2 AS (win1 ORDER BY c) } {four four.six four.six.two five five.one five.one.three} do_execsql_test 18.3.4 { SELECT group_concat(c, '.') OVER (win2) FROM t1 WINDOW win1 AS (PARTITION BY b), win2 AS (win1 ORDER BY c) } {four four.six four.six.two five five.one five.one.three} do_execsql_test 18.3.5 { SELECT group_concat(c, '.') OVER win5 FROM t1 WINDOW win1 AS (PARTITION BY b), win2 AS (win1), win3 AS (win2), win4 AS (win3), win5 AS (win4 ORDER BY c) } {four four.six four.six.two five five.one five.one.three} #------------------------------------------------------------------------- # Test RANGE <expr> PRECEDING/FOLLOWING when there are string, blob # and NULL values in the dataset. # reset_db do_execsql_test 19.0 { CREATE TABLE t1(a, b); INSERT INTO t1 VALUES (1, 1), (2, 2), (3, 3), (4, 4), (5, 5), ('a', 6), ('b', 7), ('c', 8), ('d', 9), ('e', 10); } do_execsql_test 19.1 { SELECT a, sum(b) OVER (ORDER BY a) FROM t1; } {1 1 2 3 3 6 4 10 5 15 a 21 b 28 c 36 d 45 e 55} do_execsql_test 19.2.1 { SELECT a, sum(b) OVER ( ORDER BY a RANGE BETWEEN 1 PRECEDING AND 1 FOLLOWING ) FROM t1; } {1 3 2 6 3 9 4 12 5 9 a 6 b 7 c 8 d 9 e 10} do_execsql_test 19.2.2 { SELECT a, sum(b) OVER ( ORDER BY a DESC RANGE BETWEEN 1 PRECEDING AND 1 FOLLOWING ) FROM t1 ORDER BY a ASC; } {1 3 2 6 3 9 4 12 5 9 a 6 b 7 c 8 d 9 e 10} do_execsql_test 19.3.1 { SELECT a, sum(b) OVER ( ORDER BY a RANGE BETWEEN 2 PRECEDING AND 1 FOLLOWING ) FROM t1; } {1 3 2 6 3 10 4 14 5 12 a 6 b 7 c 8 d 9 e 10} do_execsql_test 19.3.2 { SELECT a, sum(b) OVER ( ORDER BY a DESC RANGE BETWEEN 1 PRECEDING AND 2 FOLLOWING ) FROM t1 ORDER BY a ASC; } {1 3 2 6 3 10 4 14 5 12 a 6 b 7 c 8 d 9 e 10} reset_db do_execsql_test 20.0 { CREATE TABLE t1(a, b); INSERT INTO t1 VALUES (NULL, 100), (NULL, 100), (1, 1), (2, 2), (3, 3), (4, 4), (5, 5), ('a', 6), ('b', 7), ('c', 8), ('d', 9), ('e', 10); } do_execsql_test 20.1 { SELECT a, sum(b) OVER (ORDER BY a) FROM t1; } { {} 200 {} 200 1 201 2 203 3 206 4 210 5 215 a 221 b 228 c 236 d 245 e 255 } do_execsql_test 20.2.1 { SELECT a, sum(b) OVER ( ORDER BY a RANGE BETWEEN 1 PRECEDING AND 1 FOLLOWING ) FROM t1; } {{} 200 {} 200 1 3 2 6 3 9 4 12 5 9 a 6 b 7 c 8 d 9 e 10} do_execsql_test 20.2.2 { SELECT a, sum(b) OVER ( ORDER BY a DESC RANGE BETWEEN 1 PRECEDING AND 1 FOLLOWING ) FROM t1 ORDER BY a ASC; } {{} 200 {} 200 1 3 2 6 3 9 4 12 5 9 a 6 b 7 c 8 d 9 e 10} do_execsql_test 20.3.1 { SELECT a, sum(b) OVER ( ORDER BY a RANGE BETWEEN 2 PRECEDING AND 1 FOLLOWING ) FROM t1; } {{} 200 {} 200 1 3 2 6 3 10 4 14 5 12 a 6 b 7 c 8 d 9 e 10} do_execsql_test 20.3.2 { SELECT a, sum(b) OVER ( ORDER BY a DESC RANGE BETWEEN 1 PRECEDING AND 2 FOLLOWING ) FROM t1 ORDER BY a ASC; } {{} 200 {} 200 1 3 2 6 3 10 4 14 5 12 a 6 b 7 c 8 d 9 e 10} #------------------------------------------------------------------------- do_execsql_test 21.0 { CREATE TABLE keyword_tab( current, exclude, filter, following, groups, no, others, over, partition, preceding, range, ties, unbounded, window ); } do_execsql_test 21.1 { SELECT current, exclude, filter, following, groups, no, others, over, partition, preceding, range, ties, unbounded, window FROM keyword_tab } #------------------------------------------------------------------------- foreach {tn expr err} { 1 4.5 0 2 NULL 1 3 0.0 0 4 0.1 0 5 -0.1 1 6 '' 1 7 '2.0' 0 8 '2.0x' 1 9 x'1234' 1 10 '1.2' 0 } { set res {0 1} if {$err} {set res {1 {frame starting offset must be a non-negative number}} } do_catchsql_test 22.$tn.1 " WITH a(x, y) AS ( VALUES(1, 2) ) SELECT sum(x) OVER ( ORDER BY y RANGE BETWEEN $expr PRECEDING AND UNBOUNDED FOLLOWING ) FROM a " $res set res {0 1} if {$err} {set res {1 {frame ending offset must be a non-negative number}} } do_catchsql_test 22.$tn.2 " WITH a(x, y) AS ( VALUES(1, 2) ) SELECT sum(x) OVER ( ORDER BY y RANGE BETWEEN UNBOUNDED PRECEDING AND $expr FOLLOWING ) FROM a " $res } #------------------------------------------------------------------------- reset_db do_execsql_test 23.0 { CREATE TABLE t5(a, b, c); CREATE INDEX t5ab ON t5(a, b); } proc do_ordercount_test {tn sql nOrderBy} { set plan [execsql "EXPLAIN QUERY PLAN $sql"] uplevel [list do_test $tn [list regexp -all ORDER $plan] $nOrderBy] } do_ordercount_test 23.1 { SELECT sum(c) OVER (ORDER BY a, b), sum(c) OVER (PARTITION BY a ORDER BY b) FROM t5 } 0 do_ordercount_test 23.2 { SELECT sum(c) OVER (ORDER BY b, a), sum(c) OVER (PARTITION BY b ORDER BY a) FROM t5 } 1 do_ordercount_test 23.3 { SELECT sum(c) OVER (ORDER BY b, a), sum(c) OVER (ORDER BY c, b) FROM t5 } 2 do_ordercount_test 23.4 { SELECT sum(c) OVER (ORDER BY b ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW), sum(c) OVER (ORDER BY b RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW), sum(c) OVER (ORDER BY b GROUPS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) FROM t5 } 1 do_ordercount_test 23.5 { SELECT sum(c) OVER (ORDER BY b+1 ROWS UNBOUNDED PRECEDING), sum(c) OVER (ORDER BY b+1 RANGE UNBOUNDED PRECEDING), sum(c) OVER (ORDER BY b+1 GROUPS UNBOUNDED PRECEDING) FROM t5 } 1 do_ordercount_test 23.6 { SELECT sum(c) OVER (ORDER BY b+1 ROWS UNBOUNDED PRECEDING), sum(c) OVER (ORDER BY b+2 RANGE UNBOUNDED PRECEDING), sum(c) OVER (ORDER BY b+3 GROUPS UNBOUNDED PRECEDING) FROM t5 } 3 do_execsql_test 24.1 { SELECT sum(44) OVER () } {44} do_execsql_test 24.2 { SELECT lead(44) OVER () } {{}} #------------------------------------------------------------------------- # reset_db do_execsql_test 25.0 { CREATE TABLE t1 ( t1_id INTEGER PRIMARY KEY ); CREATE TABLE t2 ( t2_id INTEGER PRIMARY KEY ); CREATE TABLE t3 ( t3_id INTEGER PRIMARY KEY ); INSERT INTO t1 VALUES(1), (3), (5); INSERT INTO t2 VALUES (3), (5); INSERT INTO t3 VALUES(10), (11), (12); } do_execsql_test 25.1 { SELECT t1.* FROM t1, t2 WHERE t1_id=t2_id AND t1_id IN ( SELECT t1_id + row_number() OVER ( ORDER BY t1_id ) FROM t3 ) } do_execsql_test 25.2 { SELECT t1.* FROM t1, t2 WHERE t1_id=t2_id AND t1_id IN ( SELECT row_number() OVER ( ORDER BY t1_id ) FROM t3 ) } {3} #------------------------------------------------------------------------- reset_db do_execsql_test 26.0 { CREATE TABLE t1(x); CREATE TABLE t2(c); } do_execsql_test 26.1 { SELECT ( SELECT row_number() OVER () FROM ( SELECT c FROM t1 ) ) FROM t2 } {} do_execsql_test 26.2 { INSERT INTO t1 VALUES(1), (2), (3), (4); INSERT INTO t2 VALUES(2), (6), (8), (4); SELECT c, c IN ( SELECT row_number() OVER () FROM ( SELECT c FROM t1 ) ) FROM t2 } {2 1 6 0 8 0 4 1} do_execsql_test 26.3 { DELETE FROM t1; DELETE FROM t2; INSERT INTO t2 VALUES(1), (2), (3), (4); INSERT INTO t1 VALUES(1), (1), (2), (3), (3), (3), (3), (4), (4); SELECT c, c IN ( SELECT row_number() OVER () FROM ( SELECT 1 FROM t1 WHERE x=c ) ) FROM t2 } {1 1 2 0 3 1 4 0} #------------------------------------------------------------------------- reset_db do_execsql_test 27.0 { CREATE TABLE t1(x); INSERT INTO t1 VALUES(NULL), (1), (2), (3), (4), (5); } do_execsql_test 27.1 { SELECT min(x) FROM t1; } {1} do_execsql_test 27.2 { SELECT min(x) OVER win FROM t1 WINDOW win AS (ORDER BY rowid ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING) } {1 1 1 2 3 4} #------------------------------------------------------------------------- reset_db do_execsql_test 28.1.1 { CREATE TABLE t1(a INTEGER PRIMARY KEY, b CHAR(1), c CHAR(2), d ANY); INSERT INTO t1 VALUES (3, 'C', 'cc', 1.0); INSERT INTO t1 VALUES (13,'M', 'cc', NULL); } do_execsql_test 28.1.2 { SELECT group_concat(b,'') OVER w1 FROM t1 WINDOW w1 AS (ORDER BY a RANGE BETWEEN 3 PRECEDING AND 1 PRECEDING) } { {} {} } do_execsql_test 28.2.1 { CREATE TABLE t2(a TEXT, b INTEGER); INSERT INTO t2 VALUES('A', NULL); INSERT INTO t2 VALUES('B', NULL); } do_execsql_test 28.2.1 { DROP TABLE IF EXISTS t1; CREATE TABLE t1(a INTEGER PRIMARY KEY, b CHAR(1), c CHAR(2), d ANY); INSERT INTO t1 VALUES (10,'J', 'cc', NULL), (11,'K', 'cc', 'xyz'), (13,'M', 'cc', NULL); } do_execsql_test 28.2.2 { SELECT a, b, c, quote(d), group_concat(b,'') OVER w1, '|' FROM t1 WINDOW w1 AS (ORDER BY d DESC RANGE BETWEEN 7.0 PRECEDING AND 2.5 PRECEDING) ORDER BY c, d, a; } { 10 J cc NULL JM | 13 M cc NULL JM | 11 K cc 'xyz' K | } #------------------------------------------------------------------------- reset_db do_execsql_test 29.1 { DROP TABLE IF EXISTS t1; CREATE TABLE t1(a INTEGER PRIMARY KEY, b CHAR(1), c CHAR(2), d ANY); INSERT INTO t1 VALUES (1, 'A', 'aa', 2.5), (2, 'B', 'bb', 3.75), (3, 'C', 'cc', 1.0), (4, 'D', 'cc', 8.25), (5, 'E', 'bb', 6.5), (6, 'F', 'aa', 6.5), (7, 'G', 'aa', 6.0), (8, 'H', 'bb', 9.0), (9, 'I', 'aa', 3.75), (10,'J', 'cc', NULL), (11,'K', 'cc', 'xyz'), (12,'L', 'cc', 'xyZ'), (13,'M', 'cc', NULL); } do_execsql_test 29.2 { SELECT a, b, c, quote(d), group_concat(b,'') OVER w1, '|' FROM t1 WINDOW w1 AS (PARTITION BY c ORDER BY d DESC RANGE BETWEEN 7.0 PRECEDING AND 2.5 PRECEDING) ORDER BY c, d, a; } { 1 A aa 2.5 FG | 9 I aa 3.75 F | 7 G aa 6 {} | 6 F aa 6.5 {} | 2 B bb 3.75 HE | 5 E bb 6.5 H | 8 H bb 9 {} | 10 J cc NULL JM | 13 M cc NULL JM | 3 C cc 1 {} | 4 D cc 8.25 {} | 12 L cc 'xyZ' L | 11 K cc 'xyz' K | } # 2019-07-18 # Check-in [7ef7b23cbb1b9ace] (which was itself a fix for ticket # https://www.sqlite.org/src/info/1be72aab9) introduced a new problem # if the LHS of a BETWEEN operator is a WINDOW function. The problem # was found by (the recently enhanced) dbsqlfuzz. # do_execsql_test 30.0 { DROP TABLE IF EXISTS t1; CREATE TABLE t1(a, b, c); INSERT INTO t1 VALUES('BB','aa',399); SELECT count () OVER win1 NOT BETWEEN 'a' AND 'mmm', count () OVER win3 FROM t1 WINDOW win1 AS (ORDER BY a GROUPS BETWEEN 4 PRECEDING AND 1 FOLLOWING EXCLUDE CURRENT ROW), win2 AS (PARTITION BY b ORDER BY a), win3 AS (win2 RANGE BETWEEN 5.2 PRECEDING AND true PRECEDING ); } {1 1} #------------------------------------------------------------------------- reset_db do_execsql_test 31.1 { CREATE TABLE t1(a, b); CREATE TABLE t2(c, d); CREATE TABLE t3(e, f); INSERT INTO t1 VALUES(1, 1); INSERT INTO t2 VALUES(1, 1); INSERT INTO t3 VALUES(1, 1); } do_execsql_test 31.2 { SELECT d IN (SELECT sum(c) OVER (ORDER BY e+c) FROM t3) FROM ( SELECT * FROM t2 ); } {1} do_execsql_test 31.3 { SELECT d IN (SELECT sum(c) OVER (PARTITION BY d ORDER BY e+c) FROM t3) FROM ( SELECT * FROM t2 ); } {1} do_catchsql_test 31.3 { SELECT d IN ( SELECT sum(c) OVER ( ROWS BETWEEN d FOLLOWING AND UNBOUNDED FOLLOWING) FROM t3 ) FROM ( SELECT * FROM t2 ); } {1 {frame starting offset must be a non-negative integer}} do_catchsql_test 31.3 { SELECT d IN ( SELECT sum(c) OVER ( ROWS BETWEEN CURRENT ROW AND c FOLLOWING) FROM t3 ) FROM ( SELECT * FROM t2 ); } {1 {frame ending offset must be a non-negative integer}} # 2019-11-16 chromium issue 1025467 ifcapable altertable { db close sqlite3 db :memory: do_catchsql_test 32.10 { CREATE VIEW a AS SELECT NULL INTERSECT SELECT NULL ORDER BY s() OVER R; CREATE TABLE a0 AS SELECT 0; ALTER TABLE a0 RENAME TO S; } {1 {error in view a: 1st ORDER BY term does not match any column in the result set}} } reset_db do_execsql_test 33.1 { CREATE TABLE t1(aa, bb); INSERT INTO t1 VALUES(1, 2); INSERT INTO t1 VALUES(5, 6); CREATE TABLE t2(x); INSERT INTO t2 VALUES(1); } do_execsql_test 33.2 { SELECT (SELECT DISTINCT sum(aa) OVER() FROM t1 ORDER BY 1), x FROM t2 ORDER BY 1; } {6 1} reset_db do_execsql_test 34.1 { CREATE TABLE t1(a,b,c); } do_execsql_test 34.2 { SELECT avg(a) OVER ( ORDER BY (SELECT sum(b) OVER () FROM t1 ORDER BY ( SELECT total(d) OVER (ORDER BY c) FROM (SELECT 1 AS d) ORDER BY 1 ) ) ) FROM t1; } #------------------------------------------------------------------------- reset_db do_catchsql_test 35.0 { SELECT * WINDOW f AS () ORDER BY name COLLATE nocase; } {1 {no tables specified}} do_catchsql_test 35.1 { VALUES(1) INTERSECT SELECT * WINDOW f AS () ORDER BY x COLLATE nocase; } {1 {no tables specified}} do_execsql_test 35.2 { CREATE TABLE t1(x); INSERT INTO t1 VALUES(1), (2), (3); VALUES(1) INTERSECT SELECT sum(x) OVER f FROM t1 WINDOW f AS (ORDER BY x) ORDER BY 1; } {1} do_execsql_test 35.3 { VALUES(8) EXCEPT SELECT sum(x) OVER f FROM t1 WINDOW f AS (ORDER BY x) ORDER BY 1; } {8} do_execsql_test 35.4 { VALUES(1) UNION SELECT sum(x) OVER f FROM t1 WINDOW f AS (ORDER BY x) ORDER BY 1; } {1 3 6} # 2019-12-07 gramfuzz find # do_execsql_test 36.10 { VALUES(count(*)OVER()); } {1} do_execsql_test 36.20 { VALUES(count(*)OVER()),(2); } {1 2} do_execsql_test 36.30 { VALUES(2),(count(*)OVER()); } {2 1} do_execsql_test 36.40 { VALUES(2),(3),(count(*)OVER()),(4),(5); } {2 3 1 4 5} # 2019-12-17 crash test case found by Yongheng and Rui # See check-in 1ca0bd982ab1183b # reset_db do_execsql_test 37.10 { CREATE TABLE t0(a UNIQUE, b PRIMARY KEY); CREATE VIEW v0(c) AS SELECT max((SELECT count(a)OVER(ORDER BY 1))) FROM t0; SELECT c FROM v0 WHERE c BETWEEN 10 AND 20; } {} do_execsql_test 37.20 { DROP VIEW v0; CREATE VIEW v0(c) AS SELECT max((SELECT count(a)OVER(ORDER BY 1234))) FROM t0; SELECT c FROM v0 WHERE c BETWEEN -10 AND 20; } {} # 2019-12-20 mrigger reported problem with a FILTER clause on an aggregate # in a join. # reset_db do_catchsql_test 38.10 { CREATE TABLE t0(c0); CREATE TABLE t1(c0, c1 UNIQUE); INSERT INTO t0(c0) VALUES(1); INSERT INTO t1(c0,c1) VALUES(2,3); SELECT COUNT(*) FROM t0, t1 WHERE (SELECT AVG(0) FILTER(WHERE t1.c1)); } {1 {misuse of aggregate: AVG()}} do_execsql_test 38.20 { SELECT COUNT(*), AVG(1) FILTER(WHERE t1.c1) FROM t0, t1; } {1 1.0} do_catchsql_test 38.30 { SELECT COUNT(*) FROM t0, t1 WHERE (SELECT AVG(1) FILTER(WHERE t1.c1)); } {1 {misuse of aggregate: AVG()}} reset_db do_execsql_test 39.1 { CREATE TABLE t0(c0 UNIQUE); } do_execsql_test 39.2 { SELECT FIRST_VALUE(0) OVER(); } {0} do_execsql_test 39.3 { SELECT * FROM t0 WHERE(c0, 0) IN(SELECT FIRST_VALUE(0) OVER(), 0); } do_execsql_test 39.4 { SELECT * FROM t0 WHERE (t0.c0, 1) IN(SELECT NTILE(1) OVER(), 0 FROM t0); } ifcapable rtree { # 2019-12-25 ticket d87336c81c7d0873 # reset_db do_catchsql_test 40.1 { CREATE VIRTUAL TABLE t0 USING rtree(c0, c1, c2); SELECT * FROM t0 WHERE ((0,0) IN (SELECT COUNT(*),LAG(5)OVER(PARTITION BY 0) FROM t0),0)<=(c1,0); } {0 {}} } #------------------------------------------------------------------------- reset_db do_execsql_test 41.1 { CREATE TABLE t1(a, b, c); INSERT INTO t1 VALUES(NULL,'bb',355); INSERT INTO t1 VALUES('CC','aa',158); INSERT INTO t1 VALUES('GG','bb',929); INSERT INTO t1 VALUES('FF','Rb',574); } do_execsql_test 41.2 { SELECT min(c) OVER ( ORDER BY a RANGE BETWEEN 5.2 PRECEDING AND 0.1 PRECEDING ) FROM t1 } {355 158 574 929} do_execsql_test 41.2 { SELECT min(c) OVER ( ORDER BY a RANGE BETWEEN 5.2 PRECEDING AND 0.1 PRECEDING ) << 100 FROM t1 } {0 0 0 0} do_execsql_test 41.3 { SELECT min(c) OVER win3 << first_value(c) OVER win3, min(c) OVER win3 << first_value(c) OVER win3 FROM t1 WINDOW win3 AS ( PARTITION BY 6 ORDER BY a RANGE BETWEEN 5.2 PRECEDING AND 0.1 PRECEDING ); } {0 0 0 0 0 0 0 0} #------------------------------------------------------------------------- reset_db do_execsql_test 42.1 { CREATE TABLE t1(a, b, c); INSERT INTO t1 VALUES(1, 1, 1); INSERT INTO t1 VALUES(2, 2, 2); } do_execsql_test 42.2 { SELECT * FROM t1 WHERE (0, 0) IN ( SELECT count(*), 0 FROM t1 ) } {} do_execsql_test 42.3 { SELECT * FROM t1 WHERE (2, 0) IN ( SELECT count(*), 0 FROM t1 ) } {1 1 1 2 2 2} do_execsql_test 42.3 { SELECT count(*), max(a) OVER () FROM t1 GROUP BY c; } {1 2 1 2} do_execsql_test 42.4 { SELECT sum(a), max(b) OVER () FROM t1; } {3 1} do_execsql_test 42.5 { CREATE TABLE t2(a, b); INSERT INTO t2 VALUES('a', 1); INSERT INTO t2 VALUES('a', 2); INSERT INTO t2 VALUES('a', 3); INSERT INTO t2 VALUES('b', 4); INSERT INTO t2 VALUES('b', 5); INSERT INTO t2 VALUES('b', 6); } do_execsql_test 42.6 { SELECT a, sum(b), sum( sum(b) ) OVER (ORDER BY a) FROM t2 GROUP BY a; } {a 6 6 b 15 21} do_execsql_test 42.7 { SELECT sum(b), sum( sum(b) ) OVER (ORDER BY a) FROM t2; } {21 21} #------------------------------------------------------------------------- reset_db do_execsql_test 43.1.1 { CREATE TABLE t1(x INTEGER PRIMARY KEY); INSERT INTO t1 VALUES (10); } do_catchsql_test 43.1.2 { SELECT count() OVER() AS m FROM t1 ORDER BY (SELECT m); } {1 {misuse of aliased window function m}} reset_db do_execsql_test 43.2.1 { CREATE TABLE t1(a INTEGER PRIMARY KEY, b INTEGER); INSERT INTO t1(a, b) VALUES(1, 10); -- 10 INSERT INTO t1(a, b) VALUES(2, 15); -- 25 INSERT INTO t1(a, b) VALUES(3, -5); -- 20 INSERT INTO t1(a, b) VALUES(4, -5); -- 15 INSERT INTO t1(a, b) VALUES(5, 20); -- 35 INSERT INTO t1(a, b) VALUES(6, -11); -- 24 } do_execsql_test 43.2.2 { SELECT a, sum(b) OVER (ORDER BY a) AS abc FROM t1 ORDER BY 2 } { 1 10 4 15 3 20 6 24 2 25 5 35 } do_execsql_test 43.2.3 { SELECT a, sum(b) OVER (ORDER BY a) AS abc FROM t1 ORDER BY abc } { 1 10 4 15 3 20 6 24 2 25 5 35 } do_execsql_test 43.2.4 { SELECT a, sum(b) OVER (ORDER BY a) AS abc FROM t1 ORDER BY abc+5 } { 1 10 4 15 3 20 6 24 2 25 5 35 } do_catchsql_test 43.2.5 { SELECT a, sum(b) OVER (ORDER BY a) AS abc FROM t1 ORDER BY (SELECT abc) } {1 {misuse of aliased window function abc}} do_catchsql_test 43.2.6 { SELECT a, 1+sum(b) OVER (ORDER BY a) AS abc FROM t1 ORDER BY (SELECT abc) } {1 {misuse of aliased window function abc}} #------------------------------------------------------------------------- reset_db do_execsql_test 44.1 { CREATE TABLE t0(c0); } do_catchsql_test 44.2.1 { SELECT ntile(0) OVER (); } {1 {argument of ntile must be a positive integer}} do_catchsql_test 44.2.2 { SELECT (0, 0) IN(SELECT MIN(c0), NTILE(0) OVER()) FROM t0; } {1 {argument of ntile must be a positive integer}} do_execsql_test 44.3.1 { SELECT ntile(1) OVER (); } {1} do_execsql_test 44.3.2 { SELECT (0, 0) IN(SELECT MIN(c0), NTILE(1) OVER()) FROM t0; } {0} do_execsql_test 44.4.2 { INSERT INTO t0 VALUES(2), (1), (0); SELECT (0, 1) IN(SELECT MIN(c0), NTILE(1) OVER()) FROM t0; } {1} #------------------------------------------------------------------------- reset_db do_execsql_test 45.1 { CREATE TABLE t0(x); CREATE TABLE t1(a); INSERT INTO t1 VALUES(1000); INSERT INTO t1 VALUES(1000); INSERT INTO t0 VALUES(10000); } do_execsql_test 45.2 { SELECT * FROM ( SELECT sum (a) OVER() FROM t1 UNION ALL SELECT x FROM t0 ); } {2000 2000 10000} #------------------------------------------------------------------------- reset_db do_execsql_test 46.1 { CREATE TABLE t1 (a); CREATE INDEX i1 ON t1(a); INSERT INTO t1 VALUES (10); } do_execsql_test 46.2 { SELECT (SELECT sum(a) OVER(ORDER BY a)) FROM t1 } 10 do_execsql_test 46.3 { SELECT * FROM t1 WHERE (SELECT sum(a) OVER(ORDER BY a)); } 10 do_execsql_test 46.4 { SELECT * FROM t1 NATURAL JOIN t1 WHERE a=1 OR ((SELECT sum(a)OVER(ORDER BY a)) AND a<=10) } 10 #------------------------------------------------------------------------- reset_db do_execsql_test 47.0 { CREATE TABLE t1( a, e, f, g UNIQUE, h UNIQUE ); } do_execsql_test 47.1 { CREATE VIEW t2(k) AS SELECT e FROM t1 WHERE g = 'abc' OR h BETWEEN 10 AND f; } do_catchsql_test 47.2 { SELECT 234 FROM t2 WHERE k=1 OR (SELECT k FROM t2 WHERE (SELECT sum(a) OVER() FROM t1 GROUP BY 1)); } {1 {misuse of window function sum()}} #------------------------------------------------------------------------- reset_db do_execsql_test 48.0 { CREATE TABLE t1(a); INSERT INTO t1 VALUES(1); INSERT INTO t1 VALUES(2); INSERT INTO t1 VALUES(3); SELECT (SELECT max(x)OVER(ORDER BY x) + min(x)OVER(ORDER BY x)) FROM (SELECT (SELECT sum(a) FROM t1) AS x FROM t1); } {12 12 12} do_execsql_test 48.1 { SELECT (SELECT max(x)OVER(ORDER BY x) + min(x)OVER(ORDER BY x)) FROM (SELECT (SELECT sum(a) FROM t1 GROUP BY a) AS x FROM t1); } {2 2 2} #------------------------------------------------------------------------- reset_db do_execsql_test 49.1 { CREATE TABLE t1 (a PRIMARY KEY); INSERT INTO t1 VALUES(1); } do_execsql_test 49.2 { SELECT b AS c FROM ( SELECT a AS b FROM ( SELECT a FROM t1 WHERE a=1 OR (SELECT sum(a) OVER ()) ) WHERE b=1 OR b<10 ) WHERE c=1 OR c>=10; } {1} #------------------------------------------------------------------------- reset_db do_execsql_test 50.0 { CREATE TABLE t1 (a DOUBLE PRIMARY KEY); INSERT INTO t1 VALUES(10.0); } do_execsql_test 50.1 { SELECT * FROM t1 WHERE a%1 OR (SELECT sum(a) OVER (ORDER BY a%2)) } {10.0} do_execsql_test 50.2 { SELECT * FROM ( SELECT * FROM t1 WHERE a%1 OR (SELECT sum(a) OVER (ORDER BY a%2)) ) WHERE a=1 OR ( (SELECT sum(a) OVER (ORDER BY a%4)) AND a<=10 ) } {10.0} do_execsql_test 50.3 { SELECT a FROM ( SELECT * FROM ( SELECT * FROM t1 WHERE a%1 OR (SELECT sum(a) OVER (ORDER BY a%2)) ) WHERE a=1 OR ( (SELECT sum(a) OVER (ORDER BY a%4)) AND a<=10 ) ) WHERE a=1 OR a=10.0 } {10.0} do_execsql_test 50.4 { SELECT a FROM ( SELECT * FROM ( SELECT * FROM t1 WHERE a%1 OR (SELECT sum(a) OVER (ORDER BY a%2)) ) WHERE a=1 OR ( (SELECT sum(a) OVER (ORDER BY a%4)) AND a<=10 ) ) WHERE a=1 OR ((SELECT sum(a) OVER(ORDER BY a%8)) AND 10<=a) } {10.0} do_execsql_test 50.5 { SELECT * FROM (SELECT * FROM t1 NATURAL JOIN t1 WHERE a%1 OR ((SELECT sum(a)OVER(ORDER BY a)) AND a<=10)) NATURAL JOIN t1 WHERE a=1 OR ((SELECT sum((SELECT * FROM (SELECT * FROM (SELECT * FROM t1 NATURAL JOIN t1 WHERE a%1 OR ((SELECT sum(a)OVER(ORDER BY a)) AND a<=10)) NATURAL JOIN t1 WHERE a=1 OR ((SELECT sum((SELECT * FROM t1 NATURAL JOIN t1 WHERE a=1 OR ((SELECT sum(a)OVER(ORDER BY a)) AND a<=10)))OVER(ORDER BY a% 1 )) AND a<=10)) NATURAL JOIN t1 WHERE a=1 OR ((SELECT sum(a)OVER(ORDER BY a)) AND 10<=a)))OVER(ORDER BY a%5)) AND a<=10); } {10.0} # 2020-04-03 ticket af4556bb5c285c08 # reset_db do_catchsql_test 51.1 { CREATE TABLE a(b, c); SELECT c FROM a GROUP BY c HAVING(SELECT(sum(b) OVER(ORDER BY b), sum(b) OVER(PARTITION BY min(DISTINCT c), c ORDER BY b))); } {1 {row value misused}} #------------------------------------------------------------------------- reset_db do_execsql_test 52.1 { CREATE TABLE t1(a, b, c); INSERT INTO t1 VALUES('AA','bb',356); INSERT INTO t1 VALUES('CC','aa',158); INSERT INTO t1 VALUES('BB','aa',399); INSERT INTO t1 VALUES('FF','bb',938); } do_execsql_test 52.2 { SELECT count() OVER win1, sum(c) OVER win2, first_value(c) OVER win2, count(a) OVER (ORDER BY b) FROM t1 WINDOW win1 AS (ORDER BY a), win2 AS (PARTITION BY 6 ORDER BY a RANGE BETWEEN 5 PRECEDING AND 0 PRECEDING ); } { 1 356 356 4 2 399 399 2 3 158 158 2 4 938 938 4 } do_execsql_test 52.3 { SELECT count() OVER (), sum(c) OVER win2, first_value(c) OVER win2, count(a) OVER (ORDER BY b) FROM t1 WINDOW win1 AS (ORDER BY a), win2 AS (PARTITION BY 6 COLLATE binary ORDER BY a RANGE BETWEEN 5 PRECEDING AND 0 PRECEDING ); } { 4 356 356 4 4 399 399 2 4 158 158 2 4 938 938 4 } do_execsql_test 52.4 { SELECT count() OVER win1, sum(c) OVER win2, first_value(c) OVER win2, count(a) OVER (ORDER BY b) FROM t1 WINDOW win1 AS (ORDER BY a), win2 AS (PARTITION BY 6 COLLATE binary ORDER BY a RANGE BETWEEN 5 PRECEDING AND 0 PRECEDING ); } { 1 356 356 4 2 399 399 2 3 158 158 2 4 938 938 4 } # 2020-05-23 # ticket 7a5279a25c57adf1 # reset_db do_execsql_test 53.0 { CREATE TABLE a(c UNIQUE); INSERT INTO a VALUES(4),(0),(9),(-9); SELECT a.c FROM a JOIN a AS b ON a.c=4 JOIN a AS e ON a.c=e.c WHERE a.c=(SELECT (SELECT coalesce(lead(2) OVER(),0) + sum(d.c)) FROM a AS d WHERE a.c); } {4 4 4 4} #------------------------------------------------------------------------- reset_db do_execsql_test 54.1 { CREATE TABLE t1(a VARCHAR(20), b FLOAT); INSERT INTO t1 VALUES('1',10.0); } do_catchsql_test 54.2 { SELECT * FROM ( SELECT sum(b) OVER() AS c FROM t1 UNION SELECT b AS c FROM t1 ) WHERE c>10; } {0 {}} do_execsql_test 54.3 { INSERT INTO t1 VALUES('2',5.0); INSERT INTO t1 VALUES('3',15.0); } do_catchsql_test 54.4 { SELECT * FROM ( SELECT sum(b) OVER() AS c FROM t1 UNION SELECT b AS c FROM t1 ) WHERE c>10; } {0 {15.0 30.0}} # 2020-06-05 ticket c8d3b9f0a750a529 reset_db do_execsql_test 55.1 { CREATE TABLE a(b); SELECT (SELECT b FROM a GROUP BY b HAVING (SELECT COUNT()OVER() + lead(b)OVER(ORDER BY SUM(DISTINCT b) + b)) ) FROM a UNION SELECT 99 ORDER BY 1; } {99} #------------------------------------------------------------------------ reset_db do_execsql_test 56.1 { CREATE TABLE t1(a, b INTEGER); CREATE TABLE t2(c, d); } do_catchsql_test 56.2 { SELECT avg(b) FROM t1 UNION ALL SELECT min(c) OVER () FROM t2 ORDER BY nosuchcolumn; } {1 {1st ORDER BY term does not match any column in the result set}} reset_db do_execsql_test 57.1 { CREATE TABLE t4(a, b, c, d, e); } do_catchsql_test 57.2 { SELECT b FROM t4 UNION SELECT a FROM t4 ORDER BY ( SELECT sum(x) OVER() FROM ( SELECT c AS x FROM t4 UNION SELECT d FROM t4 ORDER BY (SELECT e FROM t4) ) ); } {1 {1st ORDER BY term does not match any column in the result set}} # 2020-06-06 various dbsqlfuzz finds and # ticket 0899cf62f597d7e7 # reset_db do_execsql_test 57.1 { CREATE TABLE t1(a, b, c); INSERT INTO t1 VALUES(NULL,NULL,NULL); SELECT sum(a), min(b) OVER (), count(c) OVER (ORDER BY b) FROM t1; } {{} {} 0} do_execsql_test 57.2 { CREATE TABLE v0 ( v1 INTEGER PRIMARY KEY ) ; INSERT INTO v0 VALUES ( 10 ) ; SELECT DISTINCT v1, lead(v1) OVER() FROM v0 GROUP BY v1 ORDER BY 2; } {10 {}} do_catchsql_test 57.3 { DROP TABLE t1; CREATE TABLE t1(a); INSERT INTO t1(a) VALUES(22); CREATE TABLE t3(y); INSERT INTO t3(y) VALUES(5),(11),(-9); SELECT ( SELECT max(y) OVER( ORDER BY (SELECT x FROM (SELECT sum(y) AS x FROM t1))) ) FROM t3; } {1 {misuse of aggregate: sum()}} # 2020-06-06 ticket 1f6f353b684fc708 reset_db do_execsql_test 58.1 { CREATE TABLE a(a, b, c); INSERT INTO a VALUES(1, 2, 3); INSERT INTO a VALUES(4, 5, 6); SELECT sum(345+b) OVER (ORDER BY b), sum(avg(678)) OVER (ORDER BY c) FROM a; } {347 678.0} # 2020-06-06 ticket e5504e987e419fb0 do_catchsql_test 59.1 { DROP TABLE IF EXISTS t1; CREATE TABLE t1(x INTEGER PRIMARY KEY); INSERT INTO t1 VALUES (123); SELECT ntile( (SELECT sum(x)) ) OVER(ORDER BY x), min(x) OVER(ORDER BY x) FROM t1; } {1 {misuse of aggregate: sum()}} # 2020-06-07 ticket f7d890858f361402 do_execsql_test 60.1 { DROP TABLE IF EXISTS t1; CREATE TABLE t1 (x INTEGER PRIMARY KEY); INSERT INTO t1 VALUES (99); SELECT EXISTS(SELECT count(*) OVER() FROM t1 ORDER BY sum(x) OVER()); } {1} # 2020-06-07 test case generated by dbsqlfuzz showing how an AggInfo # object might be referenced after the sqlite3Select() call that created # it returns. This proves the need to persist all AggInfo objects until # the Parse object is destroyed. # reset_db do_catchsql_test 61.1 { CREATE TABLE t1(a); INSERT INTO t1 VALUES(5),(NULL),('seventeen'); SELECT (SELECT max(x)OVER(ORDER BY x) % min(x)OVER(ORDER BY CASE x WHEN 889 THEN x WHEN x THEN x END)) FROM (SELECT (SELECT sum(CAST(a IN(SELECT (SELECT max(x)OVER(ORDER BY CASE x WHEN 889 THEN 299 WHEN 863 THEN 863 END)) FROM (SELECT (SELECT sum(CAST((SELECT (SELECT max(x)OVER(ORDER BY x) / min(x)OVER(ORDER BY CASE x WHEN 889 THEN 299 WHEN -true THEN 863 END)) FROM (SELECT (SELECT sum(CAST(a IN(SELECT (SELECT max(x) & sum ( a )OVER(ORDER BY CASE x WHEN -8 THEN 299 WHEN 863 THEN 863 END)) FROM (SELECT (SELECT sum(CAST(a AS )) FROM t1) AS x FROM t1)) AS t1 )) FROM t1) AS x FROM t1)) AS x )) FROM t1) AS x FROM t1)) AS real)) FROM t1) AS x FROM t1); } {0 {{} {} {}}} foreach tn {1 2} { if {$tn==2} { optimization_control db query-flattener 0 } do_catchsql_test 61.2.$tn { SELECT (SELECT max(x)OVER(ORDER BY x) / min(x) OVER() ) FROM ( SELECT (SELECT sum(a) FROM t1 ) AS x FROM t1 ) } {0 {1.0 1.0 1.0}} } reset_db optimization_control db all 0 do_execsql_test 61.3.0 { CREATE TABLE t1(a); CREATE TABLE t2(y); } do_execsql_test 61.3.1 { SELECT ( SELECT count(a) OVER ( ORDER BY (SELECT sum(y) FROM t2) ) + total(a) OVER() ) FROM t1 } {} do_execsql_test 61.4.2 { SELECT ( SELECT count(a) OVER ( ORDER BY sum(a) ) + total(a) OVER() ) FROM t1 } {0.0} do_catchsql_test 61.4.3 { SELECT sum(a) OVER ( ORDER BY a ) FROM t1 ORDER BY (SELECT sum(a) FROM t2) } {1 {misuse of aggregate: sum()}} do_execsql_test 61.4.4 { SELECT sum(a) OVER ( ORDER BY a ) FROM t1 ORDER BY (SELECT sum(y) FROM t2) } #------------------------------------------------------------------------- reset_db do_execsql_test 62.1 { CREATE TABLE t1(a VARCHAR(20), b FLOAT); INSERT INTO t1 VALUES('1',10.0); } do_execsql_test 62.2 { SELECT * FROM ( SELECT sum(b) OVER() AS c FROM t1 UNION SELECT b AS c FROM t1 ) WHERE c>10; } do_execsql_test 62.3 { INSERT INTO t1 VALUES('2',5.0); INSERT INTO t1 VALUES('3',15.0); } do_execsql_test 62.4 { SELECT * FROM ( SELECT sum(b) OVER() AS c FROM t1 UNION SELECT b AS c FROM t1 ) WHERE c>10; } {15.0 30.0} #------------------------------------------------------------------------- reset_db do_execsql_test 63.1 { CREATE TABLE t1(b, x); CREATE TABLE t2(c, d); CREATE TABLE t3(e, f); } do_execsql_test 63.2 { SELECT max(b) OVER( ORDER BY SUM( (SELECT c FROM t2 UNION SELECT x ORDER BY c) ) ) FROM t1; } {{}} do_execsql_test 63.3 { SELECT sum(b) over( ORDER BY ( SELECT max(b) OVER( ORDER BY sum( (SELECT x AS c UNION SELECT 1234 ORDER BY c) ) ) AS e ORDER BY e ) ) FROM t1; } {{}} #------------------------------------------------------------------------- reset_db do_execsql_test 64.1 { CREATE TABLE t1(a INTEGER PRIMARY KEY, b); INSERT INTO t1 VALUES(1, 'abcd'); INSERT INTO t1 VALUES(2, 'BCDE'); INSERT INTO t1 VALUES(3, 'cdef'); INSERT INTO t1 VALUES(4, 'DEFG'); } do_execsql_test 64.2 { SELECT rowid, max(b COLLATE nocase)||'' FROM t1 GROUP BY rowid ORDER BY max(b COLLATE nocase)||''; } {1 abcd 2 BCDE 3 cdef 4 DEFG} do_execsql_test 64.3 { SELECT count() OVER (), rowid, max(b COLLATE nocase)||'' FROM t1 GROUP BY rowid ORDER BY max(b COLLATE nocase)||''; } {4 1 abcd 4 2 BCDE 4 3 cdef 4 4 DEFG} do_execsql_test 64.4 { SELECT count() OVER (), rowid, max(b COLLATE nocase) FROM t1 GROUP BY rowid ORDER BY max(b COLLATE nocase); } {4 1 abcd 4 2 BCDE 4 3 cdef 4 4 DEFG} #------------------------------------------------------------------------- reset_db do_execsql_test 65.1 { CREATE TABLE t1(c1); INSERT INTO t1 VALUES('abcd'); } do_execsql_test 65.2 { SELECT max(c1 COLLATE nocase) IN (SELECT 'aBCd') FROM t1; } {1} do_execsql_test 65.3 { SELECT count() OVER (), group_concat(c1 COLLATE nocase) IN (SELECT 'aBCd') FROM t1; } {1 1} do_execsql_test 65.4 { SELECT COUNT() OVER () LIKE lead(102030) OVER( ORDER BY sum('abcdef' COLLATE nocase) IN (SELECT 54321) ) FROM t1; } {{}} #------------------------------------------------------------------------- reset_db do_execsql_test 66.1 { CREATE TABLE t1(a INTEGER); INSERT INTO t1 VALUES(3578824042033200656); INSERT INTO t1 VALUES(3029012920382354029); } foreach {tn spec} { 1 "ORDER BY a RANGE BETWEEN 0.3 PRECEDING AND 10 FOLLOWING" 2 "ORDER BY a RANGE BETWEEN 0.3 PRECEDING AND 0.1 PRECEDING" 3 "ORDER BY a RANGE BETWEEN 0.3 FOLLOWING AND 10 FOLLOWING" 4 "ORDER BY a DESC RANGE BETWEEN 0.3 PRECEDING AND 10 FOLLOWING" 5 "ORDER BY a NULLS LAST RANGE BETWEEN 0.3 PRECEDING AND 10 FOLLOWING" 6 "ORDER BY a RANGE BETWEEN 1.0 PRECEDING AND 2.0 PRECEDING" } { do_execsql_test 66.2.$tn " SELECT total(a) OVER ( $spec ) FROM t1 ORDER BY a " { 3.02901292038235e+18 3.5788240420332e+18 } } do_execsql_test 66.3 { CREATE TABLE t2(a INTEGER); INSERT INTO t2 VALUES(45); INSERT INTO t2 VALUES(30); } foreach {tn spec res} { 1 "ORDER BY a RANGE BETWEEN 0.3 PRECEDING AND 10 FOLLOWING" {30.0 45.0} 2 "ORDER BY a RANGE BETWEEN 0.3 PRECEDING AND 0.1 PRECEDING" {0.0 0.0} 3 "ORDER BY a RANGE BETWEEN 0.3 FOLLOWING AND 10 FOLLOWING" {0.0 0.0} 4 "ORDER BY a DESC RANGE BETWEEN 0.3 PRECEDING AND 10 FOLLOWING" {30.0 45.0} 5 "ORDER BY a NULLS LAST RANGE BETWEEN 0.3 PRECEDING AND 10 FOLLOWING" {30.0 45.0} 6 "ORDER BY a RANGE BETWEEN 1.0 PRECEDING AND 2.0 PRECEDING" {0.0 0.0} } { do_execsql_test 66.2.$tn " SELECT total(a) OVER ( $spec ) FROM t2 ORDER BY a " $res } #------------------------------------------------------------------------- reset_db do_execsql_test 67.0 { CREATE TABLE t1(a, b, c); CREATE TABLE t2(a, b, c); } do_catchsql_test 67.1 { SELECT a,c,b FROM t1 INTERSECT SELECT a,b,c FROM t1 ORDER BY ( SELECT nth_value(a,2) OVER w1 WINDOW w1 AS ( ORDER BY ((SELECT 1 FROM v1)) ) ) } {1 {no such table: v1}} do_catchsql_test 67.2 { SELECT a,c,b FROM t1 INTERSECT SELECT a,b,c FROM t1 ORDER BY ( SELECT nth_value(a,2) OVER w1 WINDOW w1 AS ( ORDER BY ((SELECT 1 FROM t2)) ) ) } {1 {1st ORDER BY term does not match any column in the result set}} # 2021-05-07 # Do not allow aggregate functions in the ORDER BY clause even if # there are window functions in the result set. # Forum: /forumpost/540fdfef77 # reset_db do_catchsql_test 68.0 { CREATE TABLE t1(a,b); INSERT INTO t1(a,b) VALUES(0,0),(1,1),(2,4),(3,9),(4,99); SELECT rowid, a, b, sum(a)OVER() FROM t1 ORDER BY count(b); } {1 {misuse of aggregate: count()}} # 2021-05-22 # Forum https://sqlite.org/forum/forumpost/7e484e225c # reset_db do_catchsql_test 69.0 { CREATE TABLE t1(a,b); CREATE INDEX t1ba ON t1(b,a); SELECT * FROM t1 WHERE b = (SELECT b FROM t1 ORDER BY lead(b) OVER () AND sum(a)); } {1 {misuse of aggregate: sum()}} do_catchsql_test 69.1 { SELECT * FROM t1 WHERE b >= (SELECT b FROM t1 ORDER BY lead(b) OVER () AND sum(a)); } {1 {misuse of aggregate: sum()}} do_catchsql_test 69.2 { SELECT * FROM t1 WHERE b <= (SELECT b FROM t1 ORDER BY lead(b) OVER () AND sum(a)); } {1 {misuse of aggregate: sum()}} # 2021-06-23 # Forum https://sqlite.org/forum/forumpost/31e0432608 # reset_db do_execsql_test 70.0 { CREATE TABLE t1(a); } do_execsql_test 70.1 { SELECT substr(a,4,lag(a,7) OVER(PARTITION BY 'cf23' ORDER BY 2)) AS ca0 FROM t1 ORDER BY ca0; } do_execsql_test 70.2 { SELECT substr(a,4,lag(a,7) OVER(PARTITION BY 'cf23' ORDER BY likely(2))) AS ca0 FROM t1 ORDER BY ca0; } # 2021-11-07 # Bug report from Wang Ke # https://sqlite.org/forum/forumpost/9ba4f60ff8 reset_db do_catchsql_test 71.0 { CREATE TABLE t0(a); SELECT a FROM t0, (SELECT a AS b FROM t0) WHERE (a,1)=(SELECT 2,2 UNION SELECT sum(b),max(b) OVER(ORDER BY b) ORDER BY 2) AND b=4 ORDER BY b; } {/1 {.*}/} finish_test |
Changes to test/window2.tcl.
︙ | ︙ | |||
413 414 415 416 417 418 419 | execsql_test 4.8.4 { SELECT b, sum(b) OVER ( ORDER BY a ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING ) FROM t2 ORDER BY 1, 2; } | > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | execsql_test 4.8.4 { SELECT b, sum(b) OVER ( ORDER BY a ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING ) FROM t2 ORDER BY 1, 2; } execsql_float_test 4.9 { SELECT rank() OVER win AS rank, cume_dist() OVER win AS cume_dist FROM t1 WINDOW win AS (ORDER BY 1); } execsql_test 4.10 { SELECT count(*) OVER (ORDER BY b) FROM t1 } execsql_test 4.11 { SELECT count(distinct a) FILTER (WHERE b='odd') FROM t1 } ========== execsql_test 5.0 { DROP TABLE IF EXISTS t1; CREATE TABLE t1(x INTEGER, y INTEGER); INSERT INTO t1 VALUES(10, 1); INSERT INTO t1 VALUES(20, 2); INSERT INTO t1 VALUES(3, 3); INSERT INTO t1 VALUES(2, 4); INSERT INTO t1 VALUES(1, 5); } execsql_float_test 5.1 { SELECT avg(x) OVER (ORDER BY y) AS z FROM t1 ORDER BY z; } ========== execsql_test 6.0 { DROP TABLE IF EXISTS t0; CREATE TABLE t0(c0 INTEGER UNIQUE); INSERT INTO t0 VALUES(0); } execsql_test 6.1 { SELECT DENSE_RANK() OVER(), LAG(0) OVER() FROM t0; } execsql_test 6.2 { SELECT * FROM t0 WHERE (0, t0.c0) IN (SELECT DENSE_RANK() OVER(), LAG(0) OVER() FROM t0); } ========== execsql_test 7.0 { DROP TABLE IF EXISTS t1; CREATE TABLE t1(a INTEGER, b INTEGER, c INTEGER); INSERT INTO t1 VALUES(1, 1, 1); INSERT INTO t1 VALUES(1, 2, 2); INSERT INTO t1 VALUES(3, 3, 3); INSERT INTO t1 VALUES(3, 4, 4); } execsql_test 7.1 { SELECT c, sum(c) OVER win1 FROM t1 WINDOW win1 AS (ORDER BY b) } execsql_test 7.2 { SELECT c, sum(c) OVER win1 FROM t1 WINDOW win1 AS (PARTITION BY 1 ORDER BY b) } execsql_test 7.3 { SELECT c, sum(c) OVER win1 FROM t1 WINDOW win1 AS (ORDER BY 1) } finish_test |
Changes to test/window2.test.
︙ | ︙ | |||
322 323 324 325 326 327 328 | } {} do_execsql_test 4.1 { SELECT a, sum(b) OVER ( PARTITION BY (b%10) ORDER BY b ) FROM t2 ORDER BY a; | | > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | } {} do_execsql_test 4.1 { SELECT a, sum(b) OVER ( PARTITION BY (b%10) ORDER BY b ) FROM t2 ORDER BY a; } {1 0 2 754 3 251 4 754 5 101 6 1247 7 132 8 266 9 6 10 950 11 667 12 1052 13 535 14 128 15 428 16 250 17 336 18 1122 19 368 20 6 21 1247 22 1000 23 92 24 368 25 584 26 320 27 1000 28 24 29 478 30 133 31 1049 32 1090 33 632 34 101 35 54 36 54 37 1049 38 450 39 145 40 354 41 21 42 764 43 754 44 424 45 1122 46 930 47 42 48 930 49 352 50 535 51 42 52 118 53 536 54 6 55 1122 56 86 57 770 58 255 59 50 60 52 61 950 62 75 63 354 64 2 65 536 66 160 67 352 68 536 69 54 70 675 71 276 72 950 73 868 74 678 75 667 76 4 77 1184 78 160 79 120 80 584 81 266 82 133 83 405 84 468 85 6 86 806 87 166 88 500 89 1090 90 552 91 251 92 27 93 424 94 687 95 1215 96 450 97 32 98 360 99 1052 100 868 101 2 102 66 103 754 104 450 105 145 106 5 107 687 108 24 109 302 110 806 111 251 112 42 113 24 114 30 115 128 116 128 117 50 118 1215 119 86 120 687 121 683 122 672 123 178 124 24 125 24 126 299 127 178 128 770 129 535 130 1052 131 270 132 255 133 675 134 632 135 266 136 6 137 21 138 930 139 411 140 754 141 133 142 340 143 535 144 46 145 250 146 132 147 132 148 354 149 500 150 770 151 276 152 360 153 354 154 27 155 552 156 552 157 602 158 266 159 1049 160 675 161 384 162 667 163 27 164 101 165 166 166 32 167 42 168 18 169 336 170 1122 171 276 172 1122 173 266 174 50 175 178 176 276 177 1247 178 6 179 1215 180 604 181 360 182 212 183 120 184 210 185 1090 186 10 187 1090 188 266 189 66 190 250 191 266 192 360 193 120 194 128 195 178 196 770 197 92 198 634 199 38 200 21} do_execsql_test 4.2 { SELECT a, sum(b) OVER ( PARTITION BY (b%10) ORDER BY b RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ) FROM t2 ORDER BY a; } {1 0 2 754 3 251 4 754 5 101 6 1247 7 132 8 266 9 6 10 950 11 667 12 1052 13 535 14 128 15 428 16 250 17 336 18 1122 19 368 20 6 21 1247 22 1000 23 92 24 368 25 584 26 320 27 1000 28 24 29 478 30 133 31 1049 32 1090 33 632 34 101 35 54 36 54 37 1049 38 450 39 145 40 354 41 21 42 764 43 754 44 424 45 1122 46 930 47 42 48 930 49 352 50 535 51 42 52 118 53 536 54 6 55 1122 56 86 57 770 58 255 59 50 60 52 61 950 62 75 63 354 64 2 65 536 66 160 67 352 68 536 69 54 70 675 71 276 72 950 73 868 74 678 75 667 76 4 77 1184 78 160 79 120 80 584 81 266 82 133 83 405 84 468 85 6 86 806 87 166 88 500 89 1090 90 552 91 251 92 27 93 424 94 687 95 1215 96 450 97 32 98 360 99 1052 100 868 101 2 102 66 103 754 104 450 105 145 106 5 107 687 108 24 109 302 110 806 111 251 112 42 113 24 114 30 115 128 116 128 117 50 118 1215 119 86 120 687 121 683 122 672 123 178 124 24 125 24 126 299 127 178 128 770 129 535 130 1052 131 270 132 255 133 675 134 632 135 266 136 6 137 21 138 930 139 411 140 754 141 133 142 340 143 535 144 46 145 250 146 132 147 132 148 354 149 500 150 770 151 276 152 360 153 354 154 27 155 552 156 552 157 602 158 266 159 1049 160 675 161 384 162 667 163 27 164 101 165 166 166 32 167 42 168 18 169 336 170 1122 171 276 172 1122 173 266 174 50 175 178 176 276 177 1247 178 6 179 1215 180 604 181 360 182 212 183 120 184 210 185 1090 186 10 187 1090 188 266 189 66 190 250 191 266 192 360 193 120 194 128 195 178 196 770 197 92 198 634 199 38 200 21} do_execsql_test 4.3 { SELECT b, sum(b) OVER ( ORDER BY b ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ) FROM t2 ORDER BY b; } {0 0 1 1 1 2 2 4 2 6 2 8 3 11 3 14 4 18 5 23 6 29 7 36 7 43 7 50 8 58 8 66 8 74 9 83 9 92 9 101 10 111 11 122 11 133 12 145 12 157 12 169 13 182 13 195 14 209 15 224 15 239 15 254 16 270 16 286 16 302 17 319 19 338 20 358 21 379 21 400 22 422 22 444 23 467 23 490 23 513 24 537 25 562 26 588 26 614 26 640 27 667 27 694 28 722 29 751 29 780 29 809 30 839 30 869 30 899 31 930 31 961 32 993 33 1026 33 1059 33 1092 33 1125 33 1158 34 1192 34 1226 34 1260 34 1294 35 1329 35 1364 36 1400 36 1436 36 1472 36 1508 37 1545 37 1582 38 1620 38 1658 39 1697 39 1736 39 1775 40 1815 41 1856 41 1897 41 1938 42 1980 43 2023 43 2066 44 2110 44 2154 46 2200 46 2246 47 2293 47 2340 47 2387 47 2434 49 2483 50 2533 51 2584 52 2636 53 2689 54 2743 55 2798 55 2853 56 2909 56 2965 56 3021 57 3078 58 3136 58 3194 58 3252 58 3310 59 3369 59 3428 59 3487 59 3546 60 3606 61 3667 61 3728 62 3790 62 3852 63 3915 64 3979 65 4044 65 4109 65 4174 66 4240 67 4307 68 4375 69 4444 70 4514 72 4586 72 4658 72 4730 73 4803 73 4876 73 4949 74 5023 74 5097 74 5171 74 5245 74 5319 75 5394 75 5469 75 5544 76 5620 77 5697 77 5774 78 5852 78 5930 79 6009 80 6089 80 6169 81 6250 81 6331 81 6412 82 6494 83 6577 84 6661 84 6745 84 6829 84 6913 85 6998 85 7083 85 7168 86 7254 87 7341 87 7428 88 7516 89 7605 89 7694 89 7783 90 7873 90 7963 90 8053 91 8144 91 8235 91 8326 91 8417 91 8508 93 8601 93 8694 93 8787 94 8881 95 8976 95 9071 95 9166 96 9262 96 9358 96 9454 97 9551 97 9648 98 9746 98 9844 99 9943 99 10042 99 10141} do_execsql_test 4.4 { SELECT b, sum(b) OVER ( ORDER BY b RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING ) FROM t2 ORDER BY b; } {0 10141 1 10141 1 10141 2 10141 2 10141 2 10141 3 10141 3 10141 4 10141 5 10141 6 10141 7 10141 7 10141 7 10141 8 10141 8 10141 8 10141 9 10141 9 10141 9 10141 10 10141 11 10141 11 10141 12 10141 12 10141 12 10141 13 10141 13 10141 14 10141 15 10141 15 10141 15 10141 16 10141 16 10141 16 10141 17 10141 19 10141 20 10141 21 10141 21 10141 22 10141 22 10141 23 10141 23 10141 23 10141 24 10141 25 10141 26 10141 26 10141 26 10141 27 10141 27 10141 28 10141 29 10141 29 10141 29 10141 30 10141 30 10141 30 10141 31 10141 31 10141 32 10141 33 10141 33 10141 33 10141 33 10141 33 10141 34 10141 34 10141 34 10141 34 10141 35 10141 35 10141 36 10141 36 10141 36 10141 36 10141 37 10141 37 10141 38 10141 38 10141 39 10141 39 10141 39 10141 40 10141 41 10141 41 10141 41 10141 42 10141 43 10141 43 10141 44 10141 44 10141 46 10141 46 10141 47 10141 47 10141 47 10141 47 10141 49 10141 50 10141 51 10141 52 10141 53 10141 54 10141 55 10141 55 10141 56 10141 56 10141 56 10141 57 10141 58 10141 58 10141 58 10141 58 10141 59 10141 59 10141 59 10141 59 10141 60 10141 61 10141 61 10141 62 10141 62 10141 63 10141 64 10141 65 10141 65 10141 65 10141 66 10141 67 10141 68 10141 69 10141 70 10141 72 10141 72 10141 72 10141 73 10141 73 10141 73 10141 74 10141 74 10141 74 10141 74 10141 74 10141 75 10141 75 10141 75 10141 76 10141 77 10141 77 10141 78 10141 78 10141 79 10141 80 10141 80 10141 81 10141 81 10141 81 10141 82 10141 83 10141 84 10141 84 10141 84 10141 84 10141 85 10141 85 10141 85 10141 86 10141 87 10141 87 10141 88 10141 89 10141 89 10141 89 10141 90 10141 90 10141 90 10141 91 10141 91 10141 91 10141 91 10141 91 10141 93 10141 93 10141 93 10141 94 10141 95 10141 95 10141 95 10141 96 10141 96 10141 96 10141 97 10141 97 10141 98 10141 98 10141 99 10141 99 10141 99 10141} do_execsql_test 4.5 { SELECT b, sum(b) OVER ( ORDER BY b RANGE BETWEEN CURRENT ROW AND CURRENT ROW ) FROM t2 ORDER BY b; } {0 0 1 2 1 2 2 6 2 6 2 6 3 6 3 6 4 4 5 5 6 6 7 21 7 21 7 21 8 24 8 24 8 24 9 27 9 27 9 27 10 10 11 22 11 22 12 36 12 36 12 36 13 26 13 26 14 14 15 45 15 45 15 45 16 48 16 48 16 48 17 17 19 19 20 20 21 42 21 42 22 44 22 44 23 69 23 69 23 69 24 24 25 25 26 78 26 78 26 78 27 54 27 54 28 28 29 87 29 87 29 87 30 90 30 90 30 90 31 62 31 62 32 32 33 165 33 165 33 165 33 165 33 165 34 136 34 136 34 136 34 136 35 70 35 70 36 144 36 144 36 144 36 144 37 74 37 74 38 76 38 76 39 117 39 117 39 117 40 40 41 123 41 123 41 123 42 42 43 86 43 86 44 88 44 88 46 92 46 92 47 188 47 188 47 188 47 188 49 49 50 50 51 51 52 52 53 53 54 54 55 110 55 110 56 168 56 168 56 168 57 57 58 232 58 232 58 232 58 232 59 236 59 236 59 236 59 236 60 60 61 122 61 122 62 124 62 124 63 63 64 64 65 195 65 195 65 195 66 66 67 67 68 68 69 69 70 70 72 216 72 216 72 216 73 219 73 219 73 219 74 370 74 370 74 370 74 370 74 370 75 225 75 225 75 225 76 76 77 154 77 154 78 156 78 156 79 79 80 160 80 160 81 243 81 243 81 243 82 82 83 83 84 336 84 336 84 336 84 336 85 255 85 255 85 255 86 86 87 174 87 174 88 88 89 267 89 267 89 267 90 270 90 270 90 270 91 455 91 455 91 455 91 455 91 455 93 279 93 279 93 279 94 94 95 285 95 285 95 285 96 288 96 288 96 288 97 194 97 194 98 196 98 196 99 297 99 297 99 297} do_execsql_test 4.6.1 { SELECT b, sum(b) OVER ( RANGE BETWEEN CURRENT ROW AND CURRENT ROW ) FROM t2 ORDER BY b; } {0 10141 1 10141 1 10141 2 10141 2 10141 2 10141 3 10141 3 10141 4 10141 5 10141 6 10141 7 10141 7 10141 7 10141 8 10141 8 10141 8 10141 9 10141 9 10141 9 10141 10 10141 11 10141 11 10141 12 10141 12 10141 12 10141 13 10141 13 10141 14 10141 15 10141 15 10141 15 10141 16 10141 16 10141 16 10141 17 10141 19 10141 20 10141 21 10141 21 10141 22 10141 22 10141 23 10141 23 10141 23 10141 24 10141 25 10141 26 10141 26 10141 26 10141 27 10141 27 10141 28 10141 29 10141 29 10141 29 10141 30 10141 30 10141 30 10141 31 10141 31 10141 32 10141 33 10141 33 10141 33 10141 33 10141 33 10141 34 10141 34 10141 34 10141 34 10141 35 10141 35 10141 36 10141 36 10141 36 10141 36 10141 37 10141 37 10141 38 10141 38 10141 39 10141 39 10141 39 10141 40 10141 41 10141 41 10141 41 10141 42 10141 43 10141 43 10141 44 10141 44 10141 46 10141 46 10141 47 10141 47 10141 47 10141 47 10141 49 10141 50 10141 51 10141 52 10141 53 10141 54 10141 55 10141 55 10141 56 10141 56 10141 56 10141 57 10141 58 10141 58 10141 58 10141 58 10141 59 10141 59 10141 59 10141 59 10141 60 10141 61 10141 61 10141 62 10141 62 10141 63 10141 64 10141 65 10141 65 10141 65 10141 66 10141 67 10141 68 10141 69 10141 70 10141 72 10141 72 10141 72 10141 73 10141 73 10141 73 10141 74 10141 74 10141 74 10141 74 10141 74 10141 75 10141 75 10141 75 10141 76 10141 77 10141 77 10141 78 10141 78 10141 79 10141 80 10141 80 10141 81 10141 81 10141 81 10141 82 10141 83 10141 84 10141 84 10141 84 10141 84 10141 85 10141 85 10141 85 10141 86 10141 87 10141 87 10141 88 10141 89 10141 89 10141 89 10141 90 10141 90 10141 90 10141 91 10141 91 10141 91 10141 91 10141 91 10141 93 10141 93 10141 93 10141 94 10141 95 10141 95 10141 95 10141 96 10141 96 10141 96 10141 97 10141 97 10141 98 10141 98 10141 99 10141 99 10141 99 10141} do_execsql_test 4.6.2 { SELECT b, sum(b) OVER () FROM t2 ORDER BY b; } {0 10141 1 10141 1 10141 2 10141 2 10141 2 10141 3 10141 3 10141 4 10141 5 10141 6 10141 7 10141 7 10141 7 10141 8 10141 8 10141 8 10141 9 10141 9 10141 9 10141 10 10141 11 10141 11 10141 12 10141 12 10141 12 10141 13 10141 13 10141 14 10141 15 10141 15 10141 15 10141 16 10141 16 10141 16 10141 17 10141 19 10141 20 10141 21 10141 21 10141 22 10141 22 10141 23 10141 23 10141 23 10141 24 10141 25 10141 26 10141 26 10141 26 10141 27 10141 27 10141 28 10141 29 10141 29 10141 29 10141 30 10141 30 10141 30 10141 31 10141 31 10141 32 10141 33 10141 33 10141 33 10141 33 10141 33 10141 34 10141 34 10141 34 10141 34 10141 35 10141 35 10141 36 10141 36 10141 36 10141 36 10141 37 10141 37 10141 38 10141 38 10141 39 10141 39 10141 39 10141 40 10141 41 10141 41 10141 41 10141 42 10141 43 10141 43 10141 44 10141 44 10141 46 10141 46 10141 47 10141 47 10141 47 10141 47 10141 49 10141 50 10141 51 10141 52 10141 53 10141 54 10141 55 10141 55 10141 56 10141 56 10141 56 10141 57 10141 58 10141 58 10141 58 10141 58 10141 59 10141 59 10141 59 10141 59 10141 60 10141 61 10141 61 10141 62 10141 62 10141 63 10141 64 10141 65 10141 65 10141 65 10141 66 10141 67 10141 68 10141 69 10141 70 10141 72 10141 72 10141 72 10141 73 10141 73 10141 73 10141 74 10141 74 10141 74 10141 74 10141 74 10141 75 10141 75 10141 75 10141 76 10141 77 10141 77 10141 78 10141 78 10141 79 10141 80 10141 80 10141 81 10141 81 10141 81 10141 82 10141 83 10141 84 10141 84 10141 84 10141 84 10141 85 10141 85 10141 85 10141 86 10141 87 10141 87 10141 88 10141 89 10141 89 10141 89 10141 90 10141 90 10141 90 10141 91 10141 91 10141 91 10141 91 10141 91 10141 93 10141 93 10141 93 10141 94 10141 95 10141 95 10141 95 10141 96 10141 96 10141 96 10141 97 10141 97 10141 98 10141 98 10141 99 10141 99 10141 99 10141} do_execsql_test 4.6.3 { SELECT b, sum(b) OVER ( RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING ) FROM t2 ORDER BY b; } {0 10141 1 10141 1 10141 2 10141 2 10141 2 10141 3 10141 3 10141 4 10141 5 10141 6 10141 7 10141 7 10141 7 10141 8 10141 8 10141 8 10141 9 10141 9 10141 9 10141 10 10141 11 10141 11 10141 12 10141 12 10141 12 10141 13 10141 13 10141 14 10141 15 10141 15 10141 15 10141 16 10141 16 10141 16 10141 17 10141 19 10141 20 10141 21 10141 21 10141 22 10141 22 10141 23 10141 23 10141 23 10141 24 10141 25 10141 26 10141 26 10141 26 10141 27 10141 27 10141 28 10141 29 10141 29 10141 29 10141 30 10141 30 10141 30 10141 31 10141 31 10141 32 10141 33 10141 33 10141 33 10141 33 10141 33 10141 34 10141 34 10141 34 10141 34 10141 35 10141 35 10141 36 10141 36 10141 36 10141 36 10141 37 10141 37 10141 38 10141 38 10141 39 10141 39 10141 39 10141 40 10141 41 10141 41 10141 41 10141 42 10141 43 10141 43 10141 44 10141 44 10141 46 10141 46 10141 47 10141 47 10141 47 10141 47 10141 49 10141 50 10141 51 10141 52 10141 53 10141 54 10141 55 10141 55 10141 56 10141 56 10141 56 10141 57 10141 58 10141 58 10141 58 10141 58 10141 59 10141 59 10141 59 10141 59 10141 60 10141 61 10141 61 10141 62 10141 62 10141 63 10141 64 10141 65 10141 65 10141 65 10141 66 10141 67 10141 68 10141 69 10141 70 10141 72 10141 72 10141 72 10141 73 10141 73 10141 73 10141 74 10141 74 10141 74 10141 74 10141 74 10141 75 10141 75 10141 75 10141 76 10141 77 10141 77 10141 78 10141 78 10141 79 10141 80 10141 80 10141 81 10141 81 10141 81 10141 82 10141 83 10141 84 10141 84 10141 84 10141 84 10141 85 10141 85 10141 85 10141 86 10141 87 10141 87 10141 88 10141 89 10141 89 10141 89 10141 90 10141 90 10141 90 10141 91 10141 91 10141 91 10141 91 10141 91 10141 93 10141 93 10141 93 10141 94 10141 95 10141 95 10141 95 10141 96 10141 96 10141 96 10141 97 10141 97 10141 98 10141 98 10141 99 10141 99 10141 99 10141} do_execsql_test 4.6.4 { SELECT b, sum(b) OVER ( RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING ) FROM t2 ORDER BY b; } {0 10141 1 10141 1 10141 2 10141 2 10141 2 10141 3 10141 3 10141 4 10141 5 10141 6 10141 7 10141 7 10141 7 10141 8 10141 8 10141 8 10141 9 10141 9 10141 9 10141 10 10141 11 10141 11 10141 12 10141 12 10141 12 10141 13 10141 13 10141 14 10141 15 10141 15 10141 15 10141 16 10141 16 10141 16 10141 17 10141 19 10141 20 10141 21 10141 21 10141 22 10141 22 10141 23 10141 23 10141 23 10141 24 10141 25 10141 26 10141 26 10141 26 10141 27 10141 27 10141 28 10141 29 10141 29 10141 29 10141 30 10141 30 10141 30 10141 31 10141 31 10141 32 10141 33 10141 33 10141 33 10141 33 10141 33 10141 34 10141 34 10141 34 10141 34 10141 35 10141 35 10141 36 10141 36 10141 36 10141 36 10141 37 10141 37 10141 38 10141 38 10141 39 10141 39 10141 39 10141 40 10141 41 10141 41 10141 41 10141 42 10141 43 10141 43 10141 44 10141 44 10141 46 10141 46 10141 47 10141 47 10141 47 10141 47 10141 49 10141 50 10141 51 10141 52 10141 53 10141 54 10141 55 10141 55 10141 56 10141 56 10141 56 10141 57 10141 58 10141 58 10141 58 10141 58 10141 59 10141 59 10141 59 10141 59 10141 60 10141 61 10141 61 10141 62 10141 62 10141 63 10141 64 10141 65 10141 65 10141 65 10141 66 10141 67 10141 68 10141 69 10141 70 10141 72 10141 72 10141 72 10141 73 10141 73 10141 73 10141 74 10141 74 10141 74 10141 74 10141 74 10141 75 10141 75 10141 75 10141 76 10141 77 10141 77 10141 78 10141 78 10141 79 10141 80 10141 80 10141 81 10141 81 10141 81 10141 82 10141 83 10141 84 10141 84 10141 84 10141 84 10141 85 10141 85 10141 85 10141 86 10141 87 10141 87 10141 88 10141 89 10141 89 10141 89 10141 90 10141 90 10141 90 10141 91 10141 91 10141 91 10141 91 10141 91 10141 93 10141 93 10141 93 10141 94 10141 95 10141 95 10141 95 10141 96 10141 96 10141 96 10141 97 10141 97 10141 98 10141 98 10141 99 10141 99 10141 99 10141} do_execsql_test 4.7.1 { SELECT b, sum(b) OVER ( ROWS BETWEEN CURRENT ROW AND CURRENT ROW ) FROM t2 ORDER BY 1, 2; } {0 0 1 1 1 1 2 2 2 2 2 2 3 3 3 3 4 4 5 5 6 6 7 7 7 7 7 7 8 8 8 8 8 8 9 9 9 9 9 9 10 10 11 11 11 11 12 12 12 12 12 12 13 13 13 13 14 14 15 15 15 15 15 15 16 16 16 16 16 16 17 17 19 19 20 20 21 21 21 21 22 22 22 22 23 23 23 23 23 23 24 24 25 25 26 26 26 26 26 26 27 27 27 27 28 28 29 29 29 29 29 29 30 30 30 30 30 30 31 31 31 31 32 32 33 33 33 33 33 33 33 33 33 33 34 34 34 34 34 34 34 34 35 35 35 35 36 36 36 36 36 36 36 36 37 37 37 37 38 38 38 38 39 39 39 39 39 39 40 40 41 41 41 41 41 41 42 42 43 43 43 43 44 44 44 44 46 46 46 46 47 47 47 47 47 47 47 47 49 49 50 50 51 51 52 52 53 53 54 54 55 55 55 55 56 56 56 56 56 56 57 57 58 58 58 58 58 58 58 58 59 59 59 59 59 59 59 59 60 60 61 61 61 61 62 62 62 62 63 63 64 64 65 65 65 65 65 65 66 66 67 67 68 68 69 69 70 70 72 72 72 72 72 72 73 73 73 73 73 73 74 74 74 74 74 74 74 74 74 74 75 75 75 75 75 75 76 76 77 77 77 77 78 78 78 78 79 79 80 80 80 80 81 81 81 81 81 81 82 82 83 83 84 84 84 84 84 84 84 84 85 85 85 85 85 85 86 86 87 87 87 87 88 88 89 89 89 89 89 89 90 90 90 90 90 90 91 91 91 91 91 91 91 91 91 91 93 93 93 93 93 93 94 94 95 95 95 95 95 95 96 96 96 96 96 96 97 97 97 97 98 98 98 98 99 99 99 99 99 99} do_execsql_test 4.7.2 { SELECT b, sum(b) OVER ( ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ) FROM t2 ORDER BY 1, 2; } {0 0 1 3379 1 5443 2 372 2 4473 2 7074 3 2916 3 9096 4 4049 5 5643 6 1047 7 2205 7 7081 7 10141 8 1553 8 5926 8 6422 9 4883 9 7932 9 8497 10 9544 11 5727 11 6433 12 2825 12 5918 12 8582 13 5190 13 8570 14 8596 15 3189 15 6023 15 8924 16 1942 16 1958 16 3590 17 10134 19 7474 20 5946 21 5464 21 9682 22 3029 22 6140 23 212 23 1926 23 8520 24 2626 25 3331 26 337 26 7539 26 7565 27 1270 27 10035 28 3217 29 1649 29 4355 29 7326 30 4215 30 9400 30 9853 31 5977 31 6008 32 2857 33 370 33 4326 33 8175 33 8909 33 9661 34 6414 34 6516 34 8958 34 9925 35 2151 35 5638 36 3701 36 7818 36 8785 36 8994 37 4597 37 8557 38 735 38 9891 39 842 39 7513 39 9721 40 3475 41 115 41 4874 41 5906 42 4185 43 2754 43 3518 44 7072 44 9765 46 1041 46 1316 47 2198 47 3378 47 7612 47 7923 49 6482 50 9450 51 5778 52 9370 53 4408 54 1448 55 3174 55 6876 56 2913 56 3435 56 3574 57 7223 58 5248 58 7876 58 9318 58 9823 59 697 59 2813 59 6665 59 7455 60 6821 61 2426 61 4944 62 904 62 8658 63 4471 64 8407 65 2116 65 5177 65 5603 66 8142 67 1620 68 803 69 9260 70 7396 72 4833 72 8004 72 8076 73 5017 73 5716 73 6213 74 74 74 189 74 2365 74 5538 74 7297 75 3665 75 6951 75 8343 76 3964 77 1903 77 7028 78 1394 78 4293 79 6292 80 4677 80 7692 81 542 81 4045 81 8488 82 10117 83 10008 84 1826 84 4761 84 9534 84 9628 85 2602 85 2711 85 7166 86 2291 87 4560 87 5865 88 6380 89 461 89 3306 89 3790 90 3119 90 6606 90 7782 91 995 91 2517 91 3007 91 8749 91 8876 93 1742 93 2051 93 8268 94 4143 95 5112 95 6118 95 9191 96 638 96 5344 96 6761 97 1243 97 1545 98 3888 98 5442 99 311 99 1146 99 9093} do_execsql_test 4.7.3 { SELECT b, sum(b) OVER ( ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING ) FROM t2 ORDER BY 1, 2; } {0 10141 1 10141 1 10141 2 10141 2 10141 2 10141 3 10141 3 10141 4 10141 5 10141 6 10141 7 10141 7 10141 7 10141 8 10141 8 10141 8 10141 9 10141 9 10141 9 10141 10 10141 11 10141 11 10141 12 10141 12 10141 12 10141 13 10141 13 10141 14 10141 15 10141 15 10141 15 10141 16 10141 16 10141 16 10141 17 10141 19 10141 20 10141 21 10141 21 10141 22 10141 22 10141 23 10141 23 10141 23 10141 24 10141 25 10141 26 10141 26 10141 26 10141 27 10141 27 10141 28 10141 29 10141 29 10141 29 10141 30 10141 30 10141 30 10141 31 10141 31 10141 32 10141 33 10141 33 10141 33 10141 33 10141 33 10141 34 10141 34 10141 34 10141 34 10141 35 10141 35 10141 36 10141 36 10141 36 10141 36 10141 37 10141 37 10141 38 10141 38 10141 39 10141 39 10141 39 10141 40 10141 41 10141 41 10141 41 10141 42 10141 43 10141 43 10141 44 10141 44 10141 46 10141 46 10141 47 10141 47 10141 47 10141 47 10141 49 10141 50 10141 51 10141 52 10141 53 10141 54 10141 55 10141 55 10141 56 10141 56 10141 56 10141 57 10141 58 10141 58 10141 58 10141 58 10141 59 10141 59 10141 59 10141 59 10141 60 10141 61 10141 61 10141 62 10141 62 10141 63 10141 64 10141 65 10141 65 10141 65 10141 66 10141 67 10141 68 10141 69 10141 70 10141 72 10141 72 10141 72 10141 73 10141 73 10141 73 10141 74 10141 74 10141 74 10141 74 10141 74 10141 75 10141 75 10141 75 10141 76 10141 77 10141 77 10141 78 10141 78 10141 79 10141 80 10141 80 10141 81 10141 81 10141 81 10141 82 10141 83 10141 84 10141 84 10141 84 10141 84 10141 85 10141 85 10141 85 10141 86 10141 87 10141 87 10141 88 10141 89 10141 89 10141 89 10141 90 10141 90 10141 90 10141 91 10141 91 10141 91 10141 91 10141 91 10141 93 10141 93 10141 93 10141 94 10141 95 10141 95 10141 95 10141 96 10141 96 10141 96 10141 97 10141 97 10141 98 10141 98 10141 99 10141 99 10141 99 10141} do_execsql_test 4.7.4 { SELECT b, sum(b) OVER ( ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING ) FROM t2 ORDER BY 1, 2; } {0 10141 1 4699 1 6763 2 3069 2 5670 2 9771 3 1048 3 7228 4 6096 5 4503 6 9100 7 7 7 3067 7 7943 8 3727 8 4223 8 8596 9 1653 9 2218 9 5267 10 607 11 3719 11 4425 12 1571 12 4235 12 7328 13 1584 13 4964 14 1559 15 1232 15 4133 15 6967 16 6567 16 8199 16 8215 17 24 19 2686 20 4215 21 480 21 4698 22 4023 22 7134 23 1644 23 8238 23 9952 24 7539 25 6835 26 2602 26 2628 26 9830 27 133 27 8898 28 6952 29 2844 29 5815 29 8521 30 318 30 771 30 5956 31 4164 31 4195 32 7316 33 513 33 1265 33 1999 33 5848 33 9804 34 250 34 1217 34 3659 34 3761 35 4538 35 8025 36 1183 36 1392 36 2359 36 6476 37 1621 37 5581 38 288 38 9444 39 459 39 2667 39 9338 40 6706 41 4276 41 5308 41 10067 42 5998 43 6666 43 7430 44 420 44 3113 46 8871 46 9146 47 2265 47 2576 47 6810 47 7990 49 3708 50 741 51 4414 52 823 53 5786 54 8747 55 3320 55 7022 56 6623 56 6762 56 7284 57 2975 58 376 58 881 58 2323 58 4951 59 2745 59 3535 59 7387 59 9503 60 3380 61 5258 61 7776 62 1545 62 9299 63 5733 64 1798 65 4603 65 5029 65 8090 66 2065 67 8588 68 9406 69 950 70 2815 72 2137 72 2209 72 5380 73 4001 73 4498 73 5197 74 2918 74 4677 74 7850 74 10026 74 10141 75 1873 75 3265 75 6551 76 6253 77 3190 77 8315 78 5926 78 8825 79 3928 80 2529 80 5544 81 1734 81 6177 81 9680 82 106 83 216 84 597 84 691 84 5464 84 8399 85 3060 85 7515 85 7624 86 7936 87 4363 87 5668 88 3849 89 6440 89 6924 89 9769 90 2449 90 3625 90 7112 91 1356 91 1483 91 7225 91 7715 91 9237 93 1966 93 8183 93 8492 94 6092 95 1045 95 4118 95 5124 96 3476 96 4893 96 9599 97 8693 97 8995 98 4797 98 6351 99 1147 99 9094 99 9929} do_execsql_test 4.8.1 { SELECT b, sum(b) OVER ( ORDER BY a ROWS BETWEEN CURRENT ROW AND CURRENT ROW ) FROM t2 ORDER BY 1, 2; } {0 0 1 1 1 1 2 2 2 2 2 2 3 3 3 3 4 4 5 5 6 6 7 7 7 7 7 7 8 8 8 8 8 8 9 9 9 9 9 9 10 10 11 11 11 11 12 12 12 12 12 12 13 13 13 13 14 14 15 15 15 15 15 15 16 16 16 16 16 16 17 17 19 19 20 20 21 21 21 21 22 22 22 22 23 23 23 23 23 23 24 24 25 25 26 26 26 26 26 26 27 27 27 27 28 28 29 29 29 29 29 29 30 30 30 30 30 30 31 31 31 31 32 32 33 33 33 33 33 33 33 33 33 33 34 34 34 34 34 34 34 34 35 35 35 35 36 36 36 36 36 36 36 36 37 37 37 37 38 38 38 38 39 39 39 39 39 39 40 40 41 41 41 41 41 41 42 42 43 43 43 43 44 44 44 44 46 46 46 46 47 47 47 47 47 47 47 47 49 49 50 50 51 51 52 52 53 53 54 54 55 55 55 55 56 56 56 56 56 56 57 57 58 58 58 58 58 58 58 58 59 59 59 59 59 59 59 59 60 60 61 61 61 61 62 62 62 62 63 63 64 64 65 65 65 65 65 65 66 66 67 67 68 68 69 69 70 70 72 72 72 72 72 72 73 73 73 73 73 73 74 74 74 74 74 74 74 74 74 74 75 75 75 75 75 75 76 76 77 77 77 77 78 78 78 78 79 79 80 80 80 80 81 81 81 81 81 81 82 82 83 83 84 84 84 84 84 84 84 84 85 85 85 85 85 85 86 86 87 87 87 87 88 88 89 89 89 89 89 89 90 90 90 90 90 90 91 91 91 91 91 91 91 91 91 91 93 93 93 93 93 93 94 94 95 95 95 95 95 95 96 96 96 96 96 96 97 97 97 97 98 98 98 98 99 99 99 99 99 99} do_execsql_test 4.8.2 { SELECT b, sum(b) OVER ( ORDER BY a ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ) FROM t2 ORDER BY 1, 2; } {0 0 1 3379 1 5443 2 372 2 4473 2 7074 3 2916 3 9096 4 4049 5 5643 6 1047 7 2205 7 7081 7 10141 8 1553 8 5926 8 6422 9 4883 9 7932 9 8497 10 9544 11 5727 11 6433 12 2825 12 5918 12 8582 13 5190 13 8570 14 8596 15 3189 15 6023 15 8924 16 1942 16 1958 16 3590 17 10134 19 7474 20 5946 21 5464 21 9682 22 3029 22 6140 23 212 23 1926 23 8520 24 2626 25 3331 26 337 26 7539 26 7565 27 1270 27 10035 28 3217 29 1649 29 4355 29 7326 30 4215 30 9400 30 9853 31 5977 31 6008 32 2857 33 370 33 4326 33 8175 33 8909 33 9661 34 6414 34 6516 34 8958 34 9925 35 2151 35 5638 36 3701 36 7818 36 8785 36 8994 37 4597 37 8557 38 735 38 9891 39 842 39 7513 39 9721 40 3475 41 115 41 4874 41 5906 42 4185 43 2754 43 3518 44 7072 44 9765 46 1041 46 1316 47 2198 47 3378 47 7612 47 7923 49 6482 50 9450 51 5778 52 9370 53 4408 54 1448 55 3174 55 6876 56 2913 56 3435 56 3574 57 7223 58 5248 58 7876 58 9318 58 9823 59 697 59 2813 59 6665 59 7455 60 6821 61 2426 61 4944 62 904 62 8658 63 4471 64 8407 65 2116 65 5177 65 5603 66 8142 67 1620 68 803 69 9260 70 7396 72 4833 72 8004 72 8076 73 5017 73 5716 73 6213 74 74 74 189 74 2365 74 5538 74 7297 75 3665 75 6951 75 8343 76 3964 77 1903 77 7028 78 1394 78 4293 79 6292 80 4677 80 7692 81 542 81 4045 81 8488 82 10117 83 10008 84 1826 84 4761 84 9534 84 9628 85 2602 85 2711 85 7166 86 2291 87 4560 87 5865 88 6380 89 461 89 3306 89 3790 90 3119 90 6606 90 7782 91 995 91 2517 91 3007 91 8749 91 8876 93 1742 93 2051 93 8268 94 4143 95 5112 95 6118 95 9191 96 638 96 5344 96 6761 97 1243 97 1545 98 3888 98 5442 99 311 99 1146 99 9093} do_execsql_test 4.8.3 { SELECT b, sum(b) OVER ( ORDER BY a ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING ) FROM t2 ORDER BY 1, 2; } {0 10141 1 10141 1 10141 2 10141 2 10141 2 10141 3 10141 3 10141 4 10141 5 10141 6 10141 7 10141 7 10141 7 10141 8 10141 8 10141 8 10141 9 10141 9 10141 9 10141 10 10141 11 10141 11 10141 12 10141 12 10141 12 10141 13 10141 13 10141 14 10141 15 10141 15 10141 15 10141 16 10141 16 10141 16 10141 17 10141 19 10141 20 10141 21 10141 21 10141 22 10141 22 10141 23 10141 23 10141 23 10141 24 10141 25 10141 26 10141 26 10141 26 10141 27 10141 27 10141 28 10141 29 10141 29 10141 29 10141 30 10141 30 10141 30 10141 31 10141 31 10141 32 10141 33 10141 33 10141 33 10141 33 10141 33 10141 34 10141 34 10141 34 10141 34 10141 35 10141 35 10141 36 10141 36 10141 36 10141 36 10141 37 10141 37 10141 38 10141 38 10141 39 10141 39 10141 39 10141 40 10141 41 10141 41 10141 41 10141 42 10141 43 10141 43 10141 44 10141 44 10141 46 10141 46 10141 47 10141 47 10141 47 10141 47 10141 49 10141 50 10141 51 10141 52 10141 53 10141 54 10141 55 10141 55 10141 56 10141 56 10141 56 10141 57 10141 58 10141 58 10141 58 10141 58 10141 59 10141 59 10141 59 10141 59 10141 60 10141 61 10141 61 10141 62 10141 62 10141 63 10141 64 10141 65 10141 65 10141 65 10141 66 10141 67 10141 68 10141 69 10141 70 10141 72 10141 72 10141 72 10141 73 10141 73 10141 73 10141 74 10141 74 10141 74 10141 74 10141 74 10141 75 10141 75 10141 75 10141 76 10141 77 10141 77 10141 78 10141 78 10141 79 10141 80 10141 80 10141 81 10141 81 10141 81 10141 82 10141 83 10141 84 10141 84 10141 84 10141 84 10141 85 10141 85 10141 85 10141 86 10141 87 10141 87 10141 88 10141 89 10141 89 10141 89 10141 90 10141 90 10141 90 10141 91 10141 91 10141 91 10141 91 10141 91 10141 93 10141 93 10141 93 10141 94 10141 95 10141 95 10141 95 10141 96 10141 96 10141 96 10141 97 10141 97 10141 98 10141 98 10141 99 10141 99 10141 99 10141} do_execsql_test 4.8.4 { SELECT b, sum(b) OVER ( ORDER BY a ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING ) FROM t2 ORDER BY 1, 2; } {0 10141 1 4699 1 6763 2 3069 2 5670 2 9771 3 1048 3 7228 4 6096 5 4503 6 9100 7 7 7 3067 7 7943 8 3727 8 4223 8 8596 9 1653 9 2218 9 5267 10 607 11 3719 11 4425 12 1571 12 4235 12 7328 13 1584 13 4964 14 1559 15 1232 15 4133 15 6967 16 6567 16 8199 16 8215 17 24 19 2686 20 4215 21 480 21 4698 22 4023 22 7134 23 1644 23 8238 23 9952 24 7539 25 6835 26 2602 26 2628 26 9830 27 133 27 8898 28 6952 29 2844 29 5815 29 8521 30 318 30 771 30 5956 31 4164 31 4195 32 7316 33 513 33 1265 33 1999 33 5848 33 9804 34 250 34 1217 34 3659 34 3761 35 4538 35 8025 36 1183 36 1392 36 2359 36 6476 37 1621 37 5581 38 288 38 9444 39 459 39 2667 39 9338 40 6706 41 4276 41 5308 41 10067 42 5998 43 6666 43 7430 44 420 44 3113 46 8871 46 9146 47 2265 47 2576 47 6810 47 7990 49 3708 50 741 51 4414 52 823 53 5786 54 8747 55 3320 55 7022 56 6623 56 6762 56 7284 57 2975 58 376 58 881 58 2323 58 4951 59 2745 59 3535 59 7387 59 9503 60 3380 61 5258 61 7776 62 1545 62 9299 63 5733 64 1798 65 4603 65 5029 65 8090 66 2065 67 8588 68 9406 69 950 70 2815 72 2137 72 2209 72 5380 73 4001 73 4498 73 5197 74 2918 74 4677 74 7850 74 10026 74 10141 75 1873 75 3265 75 6551 76 6253 77 3190 77 8315 78 5926 78 8825 79 3928 80 2529 80 5544 81 1734 81 6177 81 9680 82 106 83 216 84 597 84 691 84 5464 84 8399 85 3060 85 7515 85 7624 86 7936 87 4363 87 5668 88 3849 89 6440 89 6924 89 9769 90 2449 90 3625 90 7112 91 1356 91 1483 91 7225 91 7715 91 9237 93 1966 93 8183 93 8492 94 6092 95 1045 95 4118 95 5124 96 3476 96 4893 96 9599 97 8693 97 8995 98 4797 98 6351 99 1147 99 9094 99 9929} do_test 4.9 { set myres {} foreach r [db eval {SELECT rank() OVER win AS rank, cume_dist() OVER win AS cume_dist FROM t1 WINDOW win AS (ORDER BY 1);}] { lappend myres [format %.4f [set r]] } set res2 {1.0000 1.0000 1.0000 1.0000 1.0000 1.0000 1.0000 1.0000 1.0000 1.0000 1.0000 1.0000} set i 0 foreach r [set myres] r2 [set res2] { if {[set r]<([set r2]-0.0001) || [set r]>([set r2]+0.0001)} { error "list element [set i] does not match: got=[set r] expected=[set r2]" } incr i } set {} {} } {} do_execsql_test 4.10 { SELECT count(*) OVER (ORDER BY b) FROM t1 } {3 3 3 6 6 6} do_execsql_test 4.11 { SELECT count(distinct a) FILTER (WHERE b='odd') FROM t1 } {3} #========================================================================== do_execsql_test 5.0 { DROP TABLE IF EXISTS t1; CREATE TABLE t1(x INTEGER, y INTEGER); INSERT INTO t1 VALUES(10, 1); INSERT INTO t1 VALUES(20, 2); INSERT INTO t1 VALUES(3, 3); INSERT INTO t1 VALUES(2, 4); INSERT INTO t1 VALUES(1, 5); } {} do_test 5.1 { set myres {} foreach r [db eval {SELECT avg(x) OVER (ORDER BY y) AS z FROM t1 ORDER BY z;}] { lappend myres [format %.4f [set r]] } set res2 {7.2000 8.7500 10.0000 11.0000 15.0000} set i 0 foreach r [set myres] r2 [set res2] { if {[set r]<([set r2]-0.0001) || [set r]>([set r2]+0.0001)} { error "list element [set i] does not match: got=[set r] expected=[set r2]" } incr i } set {} {} } {} #========================================================================== do_execsql_test 6.0 { DROP TABLE IF EXISTS t0; CREATE TABLE t0(c0 INTEGER UNIQUE); INSERT INTO t0 VALUES(0); } {} do_execsql_test 6.1 { SELECT DENSE_RANK() OVER(), LAG(0) OVER() FROM t0; } {1 {}} do_execsql_test 6.2 { SELECT * FROM t0 WHERE (0, t0.c0) IN (SELECT DENSE_RANK() OVER(), LAG(0) OVER() FROM t0); } {} #========================================================================== do_execsql_test 7.0 { DROP TABLE IF EXISTS t1; CREATE TABLE t1(a INTEGER, b INTEGER, c INTEGER); INSERT INTO t1 VALUES(1, 1, 1); INSERT INTO t1 VALUES(1, 2, 2); INSERT INTO t1 VALUES(3, 3, 3); INSERT INTO t1 VALUES(3, 4, 4); } {} do_execsql_test 7.1 { SELECT c, sum(c) OVER win1 FROM t1 WINDOW win1 AS (ORDER BY b) } {1 1 2 3 3 6 4 10} do_execsql_test 7.2 { SELECT c, sum(c) OVER win1 FROM t1 WINDOW win1 AS (PARTITION BY 1 ORDER BY b) } {1 1 2 3 3 6 4 10} do_execsql_test 7.3 { SELECT c, sum(c) OVER win1 FROM t1 WINDOW win1 AS (ORDER BY 1) } {1 10 2 10 3 10 4 10} finish_test |
Changes to test/window3.tcl.
︙ | ︙ | |||
17 18 19 20 21 22 23 | start_test window3 "2018 May 31" ifcapable !windowfunc execsql_test 1.0 { DROP TABLE IF EXISTS t2; CREATE TABLE t2(a INTEGER PRIMARY KEY, b INTEGER); INSERT INTO t2(a, b) VALUES | < | 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | start_test window3 "2018 May 31" ifcapable !windowfunc execsql_test 1.0 { DROP TABLE IF EXISTS t2; CREATE TABLE t2(a INTEGER PRIMARY KEY, b INTEGER); INSERT INTO t2(a, b) VALUES (10,89), (11,81), (12,96), (13,59), (14,38), (15,68), (16,39), (17,62), (18,91), (19,46), (20,6), (21,99), (22,97), (23,27), (24,46), (25,78), (26,54), (27,97), (28,8), (29,67), (30,29), (31,93), (32,84), (33,77), (34,23), (35,16), (36,16), (37,93), (38,65), (39,35), (40,47), (41,7), (42,86), (43,74), (44,61), (45,91), (46,85), (47,24), (48,85), (49,43), (50,59), (51,12), (52,32), (53,56), (54,3), (55,91), (56,22), (57,90), (58,55), (59,15), (60,28), (61,89), (62,25), (63,47), (64,1), (65,56), |
︙ | ︙ | |||
69 70 71 72 73 74 75 76 77 78 79 80 81 82 | 11 "ROWS BETWEEN 4 PRECEDING AND 2 FOLLOWING" 12 "ROWS BETWEEN CURRENT ROW AND 4 FOLLOWING" 13 "ROWS BETWEEN 2 FOLLOWING AND 4 FOLLOWING" 14 "ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING" 15 "ROWS BETWEEN 4 PRECEDING AND UNBOUNDED FOLLOWING" 16 "ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING" 17 "ROWS BETWEEN 4 FOLLOWING AND UNBOUNDED FOLLOWING" } { execsql_test 1.$tn.2.1 "SELECT max(b) OVER ( ORDER BY a $window ) FROM t2" execsql_test 1.$tn.2.2 "SELECT min(b) OVER ( ORDER BY a $window ) FROM t2" execsql_test 1.$tn.3.1 " SELECT row_number() OVER ( ORDER BY a $window ) FROM t2 " | > > > > > | 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 | 11 "ROWS BETWEEN 4 PRECEDING AND 2 FOLLOWING" 12 "ROWS BETWEEN CURRENT ROW AND 4 FOLLOWING" 13 "ROWS BETWEEN 2 FOLLOWING AND 4 FOLLOWING" 14 "ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING" 15 "ROWS BETWEEN 4 PRECEDING AND UNBOUNDED FOLLOWING" 16 "ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING" 17 "ROWS BETWEEN 4 FOLLOWING AND UNBOUNDED FOLLOWING" 18 "ROWS BETWEEN 4 PRECEDING AND UNBOUNDED FOLLOWING EXCLUDE CURRENT ROW" 19 "ROWS BETWEEN 4 PRECEDING AND UNBOUNDED FOLLOWING EXCLUDE TIES" 20 "ROWS BETWEEN 4 PRECEDING AND UNBOUNDED FOLLOWING EXCLUDE GROUP" } { execsql_test 1.$tn.2.1 "SELECT max(b) OVER ( ORDER BY a $window ) FROM t2" execsql_test 1.$tn.2.2 "SELECT min(b) OVER ( ORDER BY a $window ) FROM t2" execsql_test 1.$tn.3.1 " SELECT row_number() OVER ( ORDER BY a $window ) FROM t2 " |
︙ | ︙ | |||
302 303 304 305 306 307 308 309 310 311 312 313 314 315 | " execsql_test 1.$tn.14.5 " SELECT string_agg(CAST(b AS TEXT), '.') OVER ( ORDER BY b%10,a $window ) FROM t2 " execsql_test 1.$tn.14.6 " SELECT string_agg(CAST(b AS TEXT), '.') OVER (PARTITION BY b%2,a ORDER BY b%10 $window) FROM t2 " execsql_test 1.$tn.15.1 " SELECT count(*) OVER win, string_agg(CAST(b AS TEXT), '.') FILTER (WHERE a%2=0) OVER win FROM t2 WINDOW win AS (ORDER BY a $window) " | > > > > > > > > > > > > > > > > > > > > > > | 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 | " execsql_test 1.$tn.14.5 " SELECT string_agg(CAST(b AS TEXT), '.') OVER ( ORDER BY b%10,a $window ) FROM t2 " execsql_test 1.$tn.14.6 " SELECT string_agg(CAST(b AS TEXT), '.') OVER (PARTITION BY b%2,a ORDER BY b%10 $window) FROM t2 " execsql_test 1.$tn.14.7 " SELECT string_agg(CAST(b AS TEXT), '.') OVER (win1 ORDER BY b%10 $window) FROM t2 WINDOW win1 AS (PARTITION BY b%2,a) ORDER BY 1 " execsql_test 1.$tn.14.8 " SELECT string_agg(CAST(b AS TEXT), '.') OVER (win1 $window) FROM t2 WINDOW win1 AS (PARTITION BY b%2,a ORDER BY b%10) ORDER BY 1 " execsql_test 1.$tn.14.9 " SELECT string_agg(CAST(b AS TEXT), '.') OVER win2 FROM t2 WINDOW win1 AS (PARTITION BY b%2,a ORDER BY b%10), win2 AS (win1 $window) ORDER BY 1 " execsql_test 1.$tn.15.1 " SELECT count(*) OVER win, string_agg(CAST(b AS TEXT), '.') FILTER (WHERE a%2=0) OVER win FROM t2 WINDOW win AS (ORDER BY a $window) " |
︙ | ︙ |
Changes to test/window3.test.
cannot compute difference between binary files
Changes to test/window4.tcl.
|
| | | 1 2 3 4 5 6 7 8 | ## 2018 May 19 # # 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. |
︙ | ︙ | |||
381 382 383 384 385 386 387 | execsql_test 11.4 { SELECT * FROM ( SELECT NTILE(256) OVER (ORDER BY total) - 1 AS nt FROM t8 ) sub; } | > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | execsql_test 11.4 { SELECT * FROM ( SELECT NTILE(256) OVER (ORDER BY total) - 1 AS nt FROM t8 ) sub; } execsql_test 11.5 { SELECT sum( min(t) ) OVER () FROM t8 GROUP BY total; } execsql_test 11.5 { SELECT sum( max(t) ) OVER () FROM t8 GROUP BY total; } execsql_test 11.7 { SELECT sum( min(t) ) OVER () FROM t8; } execsql_test 11.8 { SELECT sum( max(t) ) OVER () FROM t8; } execsql_test 12.0 { DROP TABLE IF EXISTS t2; CREATE TABLE t2(a INTEGER); INSERT INTO t2 VALUES(1), (2), (3); } execsql_test 12.1 { SELECT (SELECT min(a) OVER ()) FROM t2 } execsql_float_test 12.2 { SELECT (SELECT avg(a)) FROM t2 ORDER BY 1 } execsql_float_test 12.3 { SELECT (SELECT avg(a) UNION SELECT min(a) OVER ()) FROM t2 GROUP BY a ORDER BY 1 } finish_test |
Changes to test/window4.test.
︙ | ︙ | |||
146 147 148 149 150 151 152 | SELECT a, lag(b, 3, 'abc') OVER (ORDER BY a) FROM t4 } {1 abc 2 abc 3 abc 4 A 5 B 6 C 7 D 8 E 9 F 10 G} do_execsql_test 2.4.1 { SELECT group_concat(b, '.') OVER ( ORDER BY a ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING ) FROM t4 | | > | 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 | SELECT a, lag(b, 3, 'abc') OVER (ORDER BY a) FROM t4 } {1 abc 2 abc 3 abc 4 A 5 B 6 C 7 D 8 E 9 F 10 G} do_execsql_test 2.4.1 { SELECT group_concat(b, '.') OVER ( ORDER BY a ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING ) FROM t4 } {A.B.C.D.E.F.G.H.I.J B.C.D.E.F.G.H.I.J C.D.E.F.G.H.I.J D.E.F.G.H.I.J E.F.G.H.I.J F.G.H.I.J G.H.I.J H.I.J I.J J} do_execsql_test 3.0 { DROP TABLE IF EXISTS t5; CREATE TABLE t5(a INTEGER PRIMARY KEY, b TEXT, c TEXT, d INTEGER); INSERT INTO t5 VALUES(1, 'A', 'one', 5); INSERT INTO t5 VALUES(2, 'B', 'two', 4); INSERT INTO t5 VALUES(3, 'A', 'three', 3); |
︙ | ︙ | |||
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 | do_test 9.3 { set myres {} foreach r [db eval {SELECT x, percent_rank() OVER (PARTITION BY x ORDER BY x) FROM t2}] { lappend myres [format %.4f [set r]] } set res2 {1.0000 0.0000 1.0000 0.0000 1.0000 0.0000 4.0000 0.0000 4.0000 0.0000 6.0000 0.0000 7.0000 0.0000} foreach r [set myres] r2 [set res2] { if {[set r]<([set r2]-0.0001) || [set r]>([set r2]+0.0001)} { error "list element [set i] does not match: got=[set r] expected=[set r2]" } } set {} {} } {} do_execsql_test 9.4 { SELECT x, rank() OVER (ORDER BY x) FROM t2 ORDER BY 1,2 } {1 1 1 1 1 1 4 4 4 4 6 6 7 7} do_execsql_test 9.5 { SELECT DISTINCT x, rank() OVER (ORDER BY x) FROM t2 ORDER BY 1,2 } {1 1 4 4 6 6 7 7} do_test 9.6 { set myres {} foreach r [db eval {SELECT percent_rank() OVER () FROM t1}] { lappend myres [format %.4f [set r]] } set res2 {0.0000 0.0000 0.0000} foreach r [set myres] r2 [set res2] { if {[set r]<([set r2]-0.0001) || [set r]>([set r2]+0.0001)} { error "list element [set i] does not match: got=[set r] expected=[set r2]" } } set {} {} } {} do_test 9.7 { set myres {} foreach r [db eval {SELECT cume_dist() OVER () FROM t1}] { lappend myres [format %.4f [set r]] } set res2 {1.0000 1.0000 1.0000} foreach r [set myres] r2 [set res2] { if {[set r]<([set r2]-0.0001) || [set r]>([set r2]+0.0001)} { error "list element [set i] does not match: got=[set r] expected=[set r2]" } } set {} {} } {} do_execsql_test 10.0 { DROP TABLE IF EXISTS t7; CREATE TABLE t7(id INTEGER PRIMARY KEY, a INTEGER, b INTEGER); | > > > > > > | 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 | do_test 9.3 { set myres {} foreach r [db eval {SELECT x, percent_rank() OVER (PARTITION BY x ORDER BY x) FROM t2}] { lappend myres [format %.4f [set r]] } set res2 {1.0000 0.0000 1.0000 0.0000 1.0000 0.0000 4.0000 0.0000 4.0000 0.0000 6.0000 0.0000 7.0000 0.0000} set i 0 foreach r [set myres] r2 [set res2] { if {[set r]<([set r2]-0.0001) || [set r]>([set r2]+0.0001)} { error "list element [set i] does not match: got=[set r] expected=[set r2]" } incr i } set {} {} } {} do_execsql_test 9.4 { SELECT x, rank() OVER (ORDER BY x) FROM t2 ORDER BY 1,2 } {1 1 1 1 1 1 4 4 4 4 6 6 7 7} do_execsql_test 9.5 { SELECT DISTINCT x, rank() OVER (ORDER BY x) FROM t2 ORDER BY 1,2 } {1 1 4 4 6 6 7 7} do_test 9.6 { set myres {} foreach r [db eval {SELECT percent_rank() OVER () FROM t1}] { lappend myres [format %.4f [set r]] } set res2 {0.0000 0.0000 0.0000} set i 0 foreach r [set myres] r2 [set res2] { if {[set r]<([set r2]-0.0001) || [set r]>([set r2]+0.0001)} { error "list element [set i] does not match: got=[set r] expected=[set r2]" } incr i } set {} {} } {} do_test 9.7 { set myres {} foreach r [db eval {SELECT cume_dist() OVER () FROM t1}] { lappend myres [format %.4f [set r]] } set res2 {1.0000 1.0000 1.0000} set i 0 foreach r [set myres] r2 [set res2] { if {[set r]<([set r2]-0.0001) || [set r]>([set r2]+0.0001)} { error "list element [set i] does not match: got=[set r] expected=[set r2]" } incr i } set {} {} } {} do_execsql_test 10.0 { DROP TABLE IF EXISTS t7; CREATE TABLE t7(id INTEGER PRIMARY KEY, a INTEGER, b INTEGER); |
︙ | ︙ | |||
1312 1313 1314 1315 1316 1317 1318 1319 1320 | } {0 1 2} do_execsql_test 11.4 { SELECT * FROM ( SELECT NTILE(256) OVER (ORDER BY total) - 1 AS nt FROM t8 ) sub; } {0 1 2} finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | } {0 1 2} do_execsql_test 11.4 { SELECT * FROM ( SELECT NTILE(256) OVER (ORDER BY total) - 1 AS nt FROM t8 ) sub; } {0 1 2} do_execsql_test 11.5 { SELECT sum( min(t) ) OVER () FROM t8 GROUP BY total; } {5 5} do_execsql_test 11.5 { SELECT sum( max(t) ) OVER () FROM t8 GROUP BY total; } {10 10} do_execsql_test 11.7 { SELECT sum( min(t) ) OVER () FROM t8; } {0} do_execsql_test 11.8 { SELECT sum( max(t) ) OVER () FROM t8; } {10} do_execsql_test 12.0 { DROP TABLE IF EXISTS t2; CREATE TABLE t2(a INTEGER); INSERT INTO t2 VALUES(1), (2), (3); } {} do_execsql_test 12.1 { SELECT (SELECT min(a) OVER ()) FROM t2 } {1 2 3} do_test 12.2 { set myres {} foreach r [db eval {SELECT (SELECT avg(a)) FROM t2 ORDER BY 1}] { lappend myres [format %.4f [set r]] } set res2 {2.0000} set i 0 foreach r [set myres] r2 [set res2] { if {[set r]<([set r2]-0.0001) || [set r]>([set r2]+0.0001)} { error "list element [set i] does not match: got=[set r] expected=[set r2]" } incr i } set {} {} } {} do_test 12.3 { set myres {} foreach r [db eval {SELECT (SELECT avg(a) UNION SELECT min(a) OVER ()) FROM t2 GROUP BY a ORDER BY 1}] { lappend myres [format %.4f [set r]] } set res2 {1.0000 2.0000 3.0000} set i 0 foreach r [set myres] r2 [set res2] { if {[set r]<([set r2]-0.0001) || [set r]>([set r2]+0.0001)} { error "list element [set i] does not match: got=[set r] expected=[set r2]" } incr i } set {} {} } {} finish_test |
Changes to test/window6.test.
︙ | ︙ | |||
215 216 217 218 219 220 221 | do_execsql_test 9.0 { WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<5) SELECT x, group_concat(x) OVER (ORDER BY x ROWS 2 PRECEDING) FROM c; } { 1 1 2 1,2 3 1,2,3 4 2,3,4 5 3,4,5 } | | | | | | | | | | | | | 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 | do_execsql_test 9.0 { WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<5) SELECT x, group_concat(x) OVER (ORDER BY x ROWS 2 PRECEDING) FROM c; } { 1 1 2 1,2 3 1,2,3 4 2,3,4 5 3,4,5 } #do_catchsql_test 9.1 { # WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<5) # SELECT x, group_concat(x) OVER (ORDER BY x RANGE 2 PRECEDING) # FROM c; #} {1 {RANGE must use only UNBOUNDED or CURRENT ROW}} # #do_catchsql_test 9.2 { # WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<5) # SELECT x, group_concat(x) OVER (ORDER BY x RANGE BETWEEN UNBOUNDED PRECEDING AND 2 FOLLOWING) # FROM c; #} {1 {RANGE must use only UNBOUNDED or CURRENT ROW}} do_catchsql_test 9.3 { WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<5) SELECT count(DISTINCT x) OVER (ORDER BY x) FROM c; } {1 {DISTINCT is not supported for window functions}} do_catchsql_test 9.4 { |
︙ | ︙ | |||
258 259 260 261 262 263 264 | 4 "BETWEEN 4 FOLLOWING AND 2 PRECEDING" } { do_catchsql_test 9.7.$tn " WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<5) SELECT count() OVER ( ORDER BY x ROWS $frame ) FROM c; | | | 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 | 4 "BETWEEN 4 FOLLOWING AND 2 PRECEDING" } { do_catchsql_test 9.7.$tn " WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<5) SELECT count() OVER ( ORDER BY x ROWS $frame ) FROM c; " {1 {unsupported frame specification}} } do_catchsql_test 9.8.1 { WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<5) SELECT count() OVER ( ORDER BY x ROWS BETWEEN a PRECEDING AND 2 FOLLOWING ) FROM c; |
︙ | ︙ | |||
332 333 334 335 336 337 338 339 340 | do_execsql_test 11.2 { SELECT a, (SELECT y FROM t3 WHERE x=a), sum(a) OVER (ORDER BY a) FROM t1 ORDER BY a; } { 10 ten 10 15 fifteen 25 20 {} 65 20 {} 65 25 {} 90 30 thirty 150 30 thirty 150 50 {} 200 } finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | do_execsql_test 11.2 { SELECT a, (SELECT y FROM t3 WHERE x=a), sum(a) OVER (ORDER BY a) FROM t1 ORDER BY a; } { 10 ten 10 15 fifteen 25 20 {} 65 20 {} 65 25 {} 90 30 thirty 150 30 thirty 150 50 {} 200 } do_execsql_test 11.3.1 { SELECT a, sum(a) OVER win FROM t1 WINDOW win AS (ORDER BY a ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) } { 10 10 15 25 20 45 20 65 25 90 30 120 30 150 50 200 } do_execsql_test 11.3.2 { SELECT a, sum(a) OVER win FROM t1 WINDOW win AS (ORDER BY a ROWS BETWEEN UNBOUNDED PRECEDING AND 0 FOLLOWING) } { 10 10 15 25 20 45 20 65 25 90 30 120 30 150 50 200 } do_execsql_test 11.3.3 { SELECT a, sum(a) OVER win FROM t1 WINDOW win AS (ORDER BY a ROWS BETWEEN UNBOUNDED PRECEDING AND 0 PRECEDING) } { 10 10 15 25 20 45 20 65 25 90 30 120 30 150 50 200 } do_execsql_test 11.4.1 { SELECT y, group_concat(y, '.') OVER win FROM t3 WINDOW win AS ( ORDER BY y RANGE BETWEEN UNBOUNDED PRECEDING AND 10 PRECEDING ); } { fifteen fifteen ten fifteen.ten thirty fifteen.ten.thirty } finish_test |
Added test/window7.tcl.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 | # 2018 May 19 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # source [file join [file dirname $argv0] pg_common.tcl] #========================================================================= start_test window7 "2019 March 01" ifcapable !windowfunc execsql_test 1.0 { DROP TABLE IF EXISTS t3; CREATE TABLE t3(a INTEGER, b INTEGER); INSERT INTO t3 VALUES (1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6), (7, 7), (8, 8), (9, 9), (0, 10), (1, 11), (2, 12), (3, 13), (4, 14), (5, 15), (6, 16), (7, 17), (8, 18), (9, 19), (0, 20), (1, 21), (2, 22), (3, 23), (4, 24), (5, 25), (6, 26), (7, 27), (8, 28), (9, 29), (0, 30), (1, 31), (2, 32), (3, 33), (4, 34), (5, 35), (6, 36), (7, 37), (8, 38), (9, 39), (0, 40), (1, 41), (2, 42), (3, 43), (4, 44), (5, 45), (6, 46), (7, 47), (8, 48), (9, 49), (0, 50), (1, 51), (2, 52), (3, 53), (4, 54), (5, 55), (6, 56), (7, 57), (8, 58), (9, 59), (0, 60), (1, 61), (2, 62), (3, 63), (4, 64), (5, 65), (6, 66), (7, 67), (8, 68), (9, 69), (0, 70), (1, 71), (2, 72), (3, 73), (4, 74), (5, 75), (6, 76), (7, 77), (8, 78), (9, 79), (0, 80), (1, 81), (2, 82), (3, 83), (4, 84), (5, 85), (6, 86), (7, 87), (8, 88), (9, 89), (0, 90), (1, 91), (2, 92), (3, 93), (4, 94), (5, 95), (6, 96), (7, 97), (8, 98), (9, 99), (0, 100); } execsql_test 1.1 { SELECT a, sum(b) FROM t3 GROUP BY a ORDER BY 1; } execsql_test 1.2 { SELECT a, sum(b) OVER ( ORDER BY a GROUPS BETWEEN CURRENT ROW AND CURRENT ROW ) FROM t3 ORDER BY 1; } execsql_test 1.3 { SELECT a, sum(b) OVER ( ORDER BY a GROUPS BETWEEN 0 PRECEDING AND 0 FOLLOWING ) FROM t3 ORDER BY 1; } execsql_test 1.4 { SELECT a, sum(b) OVER ( ORDER BY a GROUPS BETWEEN 2 PRECEDING AND 2 FOLLOWING ) FROM t3 ORDER BY 1; } execsql_test 1.5 { SELECT a, sum(b) OVER ( ORDER BY a RANGE BETWEEN 0 PRECEDING AND 0 FOLLOWING ) FROM t3 ORDER BY 1; } execsql_test 1.6 { SELECT a, sum(b) OVER ( ORDER BY a RANGE BETWEEN 2 PRECEDING AND 2 FOLLOWING ) FROM t3 ORDER BY 1; } execsql_test 1.7 { SELECT a, sum(b) OVER ( ORDER BY a RANGE BETWEEN 2 PRECEDING AND 1 FOLLOWING ) FROM t3 ORDER BY 1; } execsql_test 1.8.1 { SELECT a, sum(b) OVER ( ORDER BY a RANGE BETWEEN 0 PRECEDING AND 1 FOLLOWING ) FROM t3 ORDER BY 1; } execsql_test 1.8.2 { SELECT a, sum(b) OVER ( ORDER BY a DESC RANGE BETWEEN 0 PRECEDING AND 1 FOLLOWING ) FROM t3 ORDER BY 1; } finish_test |
Added test/window7.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 | # 2019 March 01 # # 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. # #################################################### # DO NOT EDIT! THIS FILE IS AUTOMATICALLY GENERATED! #################################################### set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix window7 ifcapable !windowfunc { finish_test ; return } do_execsql_test 1.0 { DROP TABLE IF EXISTS t3; CREATE TABLE t3(a INTEGER, b INTEGER); INSERT INTO t3 VALUES (1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6), (7, 7), (8, 8), (9, 9), (0, 10), (1, 11), (2, 12), (3, 13), (4, 14), (5, 15), (6, 16), (7, 17), (8, 18), (9, 19), (0, 20), (1, 21), (2, 22), (3, 23), (4, 24), (5, 25), (6, 26), (7, 27), (8, 28), (9, 29), (0, 30), (1, 31), (2, 32), (3, 33), (4, 34), (5, 35), (6, 36), (7, 37), (8, 38), (9, 39), (0, 40), (1, 41), (2, 42), (3, 43), (4, 44), (5, 45), (6, 46), (7, 47), (8, 48), (9, 49), (0, 50), (1, 51), (2, 52), (3, 53), (4, 54), (5, 55), (6, 56), (7, 57), (8, 58), (9, 59), (0, 60), (1, 61), (2, 62), (3, 63), (4, 64), (5, 65), (6, 66), (7, 67), (8, 68), (9, 69), (0, 70), (1, 71), (2, 72), (3, 73), (4, 74), (5, 75), (6, 76), (7, 77), (8, 78), (9, 79), (0, 80), (1, 81), (2, 82), (3, 83), (4, 84), (5, 85), (6, 86), (7, 87), (8, 88), (9, 89), (0, 90), (1, 91), (2, 92), (3, 93), (4, 94), (5, 95), (6, 96), (7, 97), (8, 98), (9, 99), (0, 100); } {} do_execsql_test 1.1 { SELECT a, sum(b) FROM t3 GROUP BY a ORDER BY 1; } {0 550 1 460 2 470 3 480 4 490 5 500 6 510 7 520 8 530 9 540} do_execsql_test 1.2 { SELECT a, sum(b) OVER ( ORDER BY a GROUPS BETWEEN CURRENT ROW AND CURRENT ROW ) FROM t3 ORDER BY 1; } {0 550 0 550 0 550 0 550 0 550 0 550 0 550 0 550 0 550 0 550 1 460 1 460 1 460 1 460 1 460 1 460 1 460 1 460 1 460 1 460 2 470 2 470 2 470 2 470 2 470 2 470 2 470 2 470 2 470 2 470 3 480 3 480 3 480 3 480 3 480 3 480 3 480 3 480 3 480 3 480 4 490 4 490 4 490 4 490 4 490 4 490 4 490 4 490 4 490 4 490 5 500 5 500 5 500 5 500 5 500 5 500 5 500 5 500 5 500 5 500 6 510 6 510 6 510 6 510 6 510 6 510 6 510 6 510 6 510 6 510 7 520 7 520 7 520 7 520 7 520 7 520 7 520 7 520 7 520 7 520 8 530 8 530 8 530 8 530 8 530 8 530 8 530 8 530 8 530 8 530 9 540 9 540 9 540 9 540 9 540 9 540 9 540 9 540 9 540 9 540} do_execsql_test 1.3 { SELECT a, sum(b) OVER ( ORDER BY a GROUPS BETWEEN 0 PRECEDING AND 0 FOLLOWING ) FROM t3 ORDER BY 1; } {0 550 0 550 0 550 0 550 0 550 0 550 0 550 0 550 0 550 0 550 1 460 1 460 1 460 1 460 1 460 1 460 1 460 1 460 1 460 1 460 2 470 2 470 2 470 2 470 2 470 2 470 2 470 2 470 2 470 2 470 3 480 3 480 3 480 3 480 3 480 3 480 3 480 3 480 3 480 3 480 4 490 4 490 4 490 4 490 4 490 4 490 4 490 4 490 4 490 4 490 5 500 5 500 5 500 5 500 5 500 5 500 5 500 5 500 5 500 5 500 6 510 6 510 6 510 6 510 6 510 6 510 6 510 6 510 6 510 6 510 7 520 7 520 7 520 7 520 7 520 7 520 7 520 7 520 7 520 7 520 8 530 8 530 8 530 8 530 8 530 8 530 8 530 8 530 8 530 8 530 9 540 9 540 9 540 9 540 9 540 9 540 9 540 9 540 9 540 9 540} do_execsql_test 1.4 { SELECT a, sum(b) OVER ( ORDER BY a GROUPS BETWEEN 2 PRECEDING AND 2 FOLLOWING ) FROM t3 ORDER BY 1; } {0 1480 0 1480 0 1480 0 1480 0 1480 0 1480 0 1480 0 1480 0 1480 0 1480 1 1960 1 1960 1 1960 1 1960 1 1960 1 1960 1 1960 1 1960 1 1960 1 1960 2 2450 2 2450 2 2450 2 2450 2 2450 2 2450 2 2450 2 2450 2 2450 2 2450 3 2400 3 2400 3 2400 3 2400 3 2400 3 2400 3 2400 3 2400 3 2400 3 2400 4 2450 4 2450 4 2450 4 2450 4 2450 4 2450 4 2450 4 2450 4 2450 4 2450 5 2500 5 2500 5 2500 5 2500 5 2500 5 2500 5 2500 5 2500 5 2500 5 2500 6 2550 6 2550 6 2550 6 2550 6 2550 6 2550 6 2550 6 2550 6 2550 6 2550 7 2600 7 2600 7 2600 7 2600 7 2600 7 2600 7 2600 7 2600 7 2600 7 2600 8 2100 8 2100 8 2100 8 2100 8 2100 8 2100 8 2100 8 2100 8 2100 8 2100 9 1590 9 1590 9 1590 9 1590 9 1590 9 1590 9 1590 9 1590 9 1590 9 1590} do_execsql_test 1.5 { SELECT a, sum(b) OVER ( ORDER BY a RANGE BETWEEN 0 PRECEDING AND 0 FOLLOWING ) FROM t3 ORDER BY 1; } {0 550 0 550 0 550 0 550 0 550 0 550 0 550 0 550 0 550 0 550 1 460 1 460 1 460 1 460 1 460 1 460 1 460 1 460 1 460 1 460 2 470 2 470 2 470 2 470 2 470 2 470 2 470 2 470 2 470 2 470 3 480 3 480 3 480 3 480 3 480 3 480 3 480 3 480 3 480 3 480 4 490 4 490 4 490 4 490 4 490 4 490 4 490 4 490 4 490 4 490 5 500 5 500 5 500 5 500 5 500 5 500 5 500 5 500 5 500 5 500 6 510 6 510 6 510 6 510 6 510 6 510 6 510 6 510 6 510 6 510 7 520 7 520 7 520 7 520 7 520 7 520 7 520 7 520 7 520 7 520 8 530 8 530 8 530 8 530 8 530 8 530 8 530 8 530 8 530 8 530 9 540 9 540 9 540 9 540 9 540 9 540 9 540 9 540 9 540 9 540} do_execsql_test 1.6 { SELECT a, sum(b) OVER ( ORDER BY a RANGE BETWEEN 2 PRECEDING AND 2 FOLLOWING ) FROM t3 ORDER BY 1; } {0 1480 0 1480 0 1480 0 1480 0 1480 0 1480 0 1480 0 1480 0 1480 0 1480 1 1960 1 1960 1 1960 1 1960 1 1960 1 1960 1 1960 1 1960 1 1960 1 1960 2 2450 2 2450 2 2450 2 2450 2 2450 2 2450 2 2450 2 2450 2 2450 2 2450 3 2400 3 2400 3 2400 3 2400 3 2400 3 2400 3 2400 3 2400 3 2400 3 2400 4 2450 4 2450 4 2450 4 2450 4 2450 4 2450 4 2450 4 2450 4 2450 4 2450 5 2500 5 2500 5 2500 5 2500 5 2500 5 2500 5 2500 5 2500 5 2500 5 2500 6 2550 6 2550 6 2550 6 2550 6 2550 6 2550 6 2550 6 2550 6 2550 6 2550 7 2600 7 2600 7 2600 7 2600 7 2600 7 2600 7 2600 7 2600 7 2600 7 2600 8 2100 8 2100 8 2100 8 2100 8 2100 8 2100 8 2100 8 2100 8 2100 8 2100 9 1590 9 1590 9 1590 9 1590 9 1590 9 1590 9 1590 9 1590 9 1590 9 1590} do_execsql_test 1.7 { SELECT a, sum(b) OVER ( ORDER BY a RANGE BETWEEN 2 PRECEDING AND 1 FOLLOWING ) FROM t3 ORDER BY 1; } {0 1010 0 1010 0 1010 0 1010 0 1010 0 1010 0 1010 0 1010 0 1010 0 1010 1 1480 1 1480 1 1480 1 1480 1 1480 1 1480 1 1480 1 1480 1 1480 1 1480 2 1960 2 1960 2 1960 2 1960 2 1960 2 1960 2 1960 2 1960 2 1960 2 1960 3 1900 3 1900 3 1900 3 1900 3 1900 3 1900 3 1900 3 1900 3 1900 3 1900 4 1940 4 1940 4 1940 4 1940 4 1940 4 1940 4 1940 4 1940 4 1940 4 1940 5 1980 5 1980 5 1980 5 1980 5 1980 5 1980 5 1980 5 1980 5 1980 5 1980 6 2020 6 2020 6 2020 6 2020 6 2020 6 2020 6 2020 6 2020 6 2020 6 2020 7 2060 7 2060 7 2060 7 2060 7 2060 7 2060 7 2060 7 2060 7 2060 7 2060 8 2100 8 2100 8 2100 8 2100 8 2100 8 2100 8 2100 8 2100 8 2100 8 2100 9 1590 9 1590 9 1590 9 1590 9 1590 9 1590 9 1590 9 1590 9 1590 9 1590} do_execsql_test 1.8.1 { SELECT a, sum(b) OVER ( ORDER BY a RANGE BETWEEN 0 PRECEDING AND 1 FOLLOWING ) FROM t3 ORDER BY 1; } {0 1010 0 1010 0 1010 0 1010 0 1010 0 1010 0 1010 0 1010 0 1010 0 1010 1 930 1 930 1 930 1 930 1 930 1 930 1 930 1 930 1 930 1 930 2 950 2 950 2 950 2 950 2 950 2 950 2 950 2 950 2 950 2 950 3 970 3 970 3 970 3 970 3 970 3 970 3 970 3 970 3 970 3 970 4 990 4 990 4 990 4 990 4 990 4 990 4 990 4 990 4 990 4 990 5 1010 5 1010 5 1010 5 1010 5 1010 5 1010 5 1010 5 1010 5 1010 5 1010 6 1030 6 1030 6 1030 6 1030 6 1030 6 1030 6 1030 6 1030 6 1030 6 1030 7 1050 7 1050 7 1050 7 1050 7 1050 7 1050 7 1050 7 1050 7 1050 7 1050 8 1070 8 1070 8 1070 8 1070 8 1070 8 1070 8 1070 8 1070 8 1070 8 1070 9 540 9 540 9 540 9 540 9 540 9 540 9 540 9 540 9 540 9 540} do_execsql_test 1.8.2 { SELECT a, sum(b) OVER ( ORDER BY a DESC RANGE BETWEEN 0 PRECEDING AND 1 FOLLOWING ) FROM t3 ORDER BY 1; } {0 550 0 550 0 550 0 550 0 550 0 550 0 550 0 550 0 550 0 550 1 1010 1 1010 1 1010 1 1010 1 1010 1 1010 1 1010 1 1010 1 1010 1 1010 2 930 2 930 2 930 2 930 2 930 2 930 2 930 2 930 2 930 2 930 3 950 3 950 3 950 3 950 3 950 3 950 3 950 3 950 3 950 3 950 4 970 4 970 4 970 4 970 4 970 4 970 4 970 4 970 4 970 4 970 5 990 5 990 5 990 5 990 5 990 5 990 5 990 5 990 5 990 5 990 6 1010 6 1010 6 1010 6 1010 6 1010 6 1010 6 1010 6 1010 6 1010 6 1010 7 1030 7 1030 7 1030 7 1030 7 1030 7 1030 7 1030 7 1030 7 1030 7 1030 8 1050 8 1050 8 1050 8 1050 8 1050 8 1050 8 1050 8 1050 8 1050 8 1050 9 1070 9 1070 9 1070 9 1070 9 1070 9 1070 9 1070 9 1070 9 1070 9 1070} finish_test |
Added test/window8.tcl.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 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 | # 2018 May 19 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # source [file join [file dirname $argv0] pg_common.tcl] #========================================================================= start_test window8 "2019 March 01" ifcapable !windowfunc execsql_test 1.0 { DROP TABLE IF EXISTS t3; CREATE TABLE t3(a TEXT, b TEXT, c INTEGER); INSERT INTO t3 VALUES ('HH', 'bb', 355), ('CC', 'aa', 158), ('BB', 'aa', 399), ('FF', 'bb', 938), ('HH', 'aa', 480), ('FF', 'bb', 870), ('JJ', 'aa', 768), ('JJ', 'aa', 899), ('GG', 'bb', 929), ('II', 'bb', 421), ('GG', 'bb', 844), ('FF', 'bb', 574), ('CC', 'bb', 822), ('GG', 'bb', 938), ('BB', 'aa', 660), ('HH', 'aa', 979), ('BB', 'bb', 792), ('DD', 'aa', 845), ('JJ', 'bb', 354), ('FF', 'bb', 295), ('JJ', 'aa', 234), ('BB', 'bb', 840), ('AA', 'aa', 934), ('EE', 'aa', 113), ('AA', 'bb', 309), ('BB', 'aa', 412), ('AA', 'aa', 911), ('AA', 'bb', 572), ('II', 'aa', 398), ('II', 'bb', 250), ('II', 'aa', 652), ('BB', 'bb', 633), ('AA', 'aa', 239), ('FF', 'aa', 670), ('BB', 'bb', 705), ('HH', 'bb', 963), ('CC', 'bb', 346), ('II', 'bb', 671), ('BB', 'aa', 247), ('AA', 'aa', 223), ('GG', 'aa', 480), ('HH', 'aa', 790), ('FF', 'aa', 208), ('BB', 'bb', 711), ('EE', 'aa', 777), ('DD', 'bb', 716), ('CC', 'aa', 759), ('CC', 'aa', 430), ('CC', 'aa', 607), ('DD', 'bb', 794), ('GG', 'aa', 148), ('GG', 'aa', 634), ('JJ', 'bb', 257), ('DD', 'bb', 959), ('FF', 'bb', 726), ('BB', 'aa', 762), ('JJ', 'bb', 336), ('GG', 'aa', 335), ('HH', 'bb', 330), ('GG', 'bb', 160), ('JJ', 'bb', 839), ('FF', 'aa', 618), ('BB', 'aa', 393), ('EE', 'bb', 629), ('FF', 'aa', 667), ('AA', 'bb', 870), ('FF', 'bb', 102), ('JJ', 'aa', 113), ('DD', 'aa', 224), ('AA', 'bb', 627), ('HH', 'bb', 730), ('II', 'bb', 443), ('HH', 'bb', 133), ('EE', 'bb', 252), ('II', 'bb', 805), ('BB', 'bb', 786), ('EE', 'bb', 768), ('HH', 'bb', 683), ('DD', 'bb', 238), ('DD', 'aa', 256); } foreach {tn frame} { 1 { GROUPS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING } 2 { GROUPS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW } 3 { GROUPS BETWEEN UNBOUNDED PRECEDING AND 1 FOLLOWING } 4 { GROUPS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING } 5 { GROUPS BETWEEN 1 PRECEDING AND 2 PRECEDING } 6 { GROUPS BETWEEN 2 PRECEDING AND 1 PRECEDING } 7 { GROUPS BETWEEN 3 PRECEDING AND 1 PRECEDING } 8 { GROUPS BETWEEN 3 PRECEDING AND 0 PRECEDING } 9 { GROUPS BETWEEN 2 PRECEDING AND CURRENT ROW } 10 { GROUPS BETWEEN 3 PRECEDING AND 0 FOLLOWING } 11 { GROUPS BETWEEN 2 PRECEDING AND UNBOUNDED FOLLOWING } 12 { GROUPS BETWEEN CURRENT ROW AND 0 FOLLOWING } 13 { GROUPS BETWEEN CURRENT ROW AND 1 FOLLOWING } 14 { GROUPS BETWEEN CURRENT ROW AND 100 FOLLOWING } 15 { GROUPS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING } 16 { GROUPS BETWEEN 0 FOLLOWING AND 0 FOLLOWING } 17 { GROUPS BETWEEN 1 FOLLOWING AND 0 FOLLOWING } 18 { GROUPS BETWEEN 1 FOLLOWING AND 5 FOLLOWING } 19 { GROUPS BETWEEN 1 FOLLOWING AND UNBOUNDED FOLLOWING } } { execsql_test 1.$tn.1 " SELECT a, b, sum(c) OVER (ORDER BY a $frame) FROM t3 ORDER BY 1, 2, 3; " execsql_test 1.$tn.2 " SELECT a, b, sum(c) OVER (ORDER BY a,b $frame) FROM t3 ORDER BY 1, 2, 3; " execsql_test 1.$tn.3 " SELECT a, b, rank() OVER (ORDER BY a $frame) FROM t3 ORDER BY 1, 2, 3; " execsql_test 1.$tn.4 " SELECT a, b, max(c) OVER (ORDER BY a,b $frame) FROM t3 ORDER BY 1, 2, 3; " execsql_test 1.$tn.5 " SELECT a, b, min(c) OVER (ORDER BY a,b $frame) FROM t3 ORDER BY 1, 2, 3; " set f2 "$frame EXCLUDE CURRENT ROW" execsql_test 1.$tn.6 " SELECT a, b, sum(c) OVER (ORDER BY a $f2) FROM t3 ORDER BY 1, 2, 3; " execsql_test 1.$tn.7 " SELECT a, b, sum(c) OVER (ORDER BY a,b $f2) FROM t3 ORDER BY 1, 2, 3; " execsql_test 1.$tn.8 " SELECT a, b, sum(c) OVER (ORDER BY a $f2), sum(c) OVER (ORDER BY a $frame), sum(c) OVER (ORDER BY a,b $f2), sum(c) OVER (ORDER BY a,b $frame) FROM t3 ORDER BY 1, 2, 3; " } foreach {tn ex} { 1 { EXCLUDE NO OTHERS } 2 { EXCLUDE CURRENT ROW } 3 { EXCLUDE GROUP } 4 { EXCLUDE TIES } } { execsql_test 2.$tn.1 " SELECT row_number() OVER win FROM t3 WINDOW win AS ( ORDER BY c, b, a ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING $ex ) " execsql_test 2.$tn.2 " SELECT nth_value(c, 14) OVER win FROM t3 WINDOW win AS ( ORDER BY c, b, a ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING $ex ) " execsql_test 2.$tn.3 " SELECT min(c) OVER win, max(c) OVER win, sum(c) OVER win FROM t3 WINDOW win AS ( ORDER BY c, b, a ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW $ex ) ORDER BY a, b, c; " } ========== execsql_test 3.0 { DROP TABLE IF EXISTS t1; CREATE TABLE t1(a REAL, b INTEGER); INSERT INTO t1 VALUES (5, 10), (10, 20), (13, 26), (13, 26), (15, 30), (20, 40), (22,80), (30, 90); } foreach {tn frame} { 1 { ORDER BY a RANGE BETWEEN 5 PRECEDING AND 5 FOLLOWING } 2 { ORDER BY a RANGE BETWEEN 10 PRECEDING AND 5 PRECEDING } 3 { ORDER BY a RANGE BETWEEN 2 FOLLOWING AND 3 FOLLOWING } 4 { ORDER BY a DESC RANGE BETWEEN 5 PRECEDING AND 5 FOLLOWING } 5 { ORDER BY a DESC RANGE BETWEEN 10 PRECEDING AND 5 PRECEDING } 6 { ORDER BY a DESC RANGE BETWEEN 2 FOLLOWING AND 3 FOLLOWING } 7 { ORDER BY a RANGE BETWEEN 5.1 PRECEDING AND 5.3 FOLLOWING } 8 { ORDER BY a RANGE BETWEEN 10.2 PRECEDING AND 5.4 PRECEDING } 9 { ORDER BY a RANGE BETWEEN 2.6 FOLLOWING AND 3.5 FOLLOWING } 10 { ORDER BY a DESC RANGE BETWEEN 5.7 PRECEDING AND 5.8 FOLLOWING } 11 { ORDER BY a DESC RANGE BETWEEN UNBOUNDED PRECEDING AND 5.9 PRECEDING } 12 { ORDER BY a DESC RANGE BETWEEN 2.1 FOLLOWING AND UNBOUNDED FOLLOWING } 13 { ORDER BY a RANGE 5.1 PRECEDING } } { execsql_test 3.$tn " SELECT CAST(a AS INTEGER), sum(b) OVER win FROM t1 WINDOW win AS ($frame) " } ========== execsql_test 4.0 { DROP TABLE IF EXISTS t1; CREATE TABLE t1(a INTEGER, b INTEGER); INSERT INTO t1 VALUES (NULL, 1), (NULL, 2), (NULL, 3), (10, 4), (10, 5); } execsql_test 4.1.1 { SELECT sum(b) OVER ( ORDER BY a RANGE BETWEEN 5 PRECEDING AND 10 FOLLOWING ) FROM t1 ORDER BY 1; } execsql_test 4.1.2 { SELECT sum(b) OVER ( ORDER BY a DESC RANGE BETWEEN 5 PRECEDING AND 10 FOLLOWING ) FROM t1 ORDER BY 1; } execsql_test 4.2.1 { SELECT sum(b) OVER ( ORDER BY a RANGE BETWEEN 5 FOLLOWING AND 10 FOLLOWING ) FROM t1 ORDER BY 1 NULLS FIRST; } execsql_test 4.2.2 { SELECT sum(b) OVER ( ORDER BY a RANGE BETWEEN 5 FOLLOWING AND 10 FOLLOWING ) FROM t1 ORDER BY 1 NULLS LAST; } execsql_test 4.2.3 { SELECT sum(b) OVER ( ORDER BY a DESC RANGE BETWEEN 5 FOLLOWING AND 10 FOLLOWING ) FROM t1 ORDER BY 1 NULLS FIRST; } execsql_test 4.2.4 { SELECT sum(b) OVER ( ORDER BY a DESC RANGE BETWEEN 5 FOLLOWING AND 10 FOLLOWING ) FROM t1 ORDER BY 1 NULLS LAST; } execsql_test 4.3.1 { SELECT sum(b) OVER ( ORDER BY a NULLS FIRST RANGE BETWEEN UNBOUNDED PRECEDING AND 10 FOLLOWING ) FROM t1 ORDER BY 1 NULLS FIRST; } execsql_test 4.3.2 { SELECT sum(b) OVER ( ORDER BY a NULLS LAST RANGE BETWEEN UNBOUNDED PRECEDING AND 10 FOLLOWING ) FROM t1 ORDER BY 1 NULLS LAST; } execsql_test 4.4.1 { SELECT sum(b) OVER ( ORDER BY a NULLS FIRST ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING ) FROM t1 ORDER BY 1 NULLS FIRST; } execsql_test 4.4.2 { SELECT sum(b) OVER ( ORDER BY a NULLS LAST ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING ) FROM t1 ORDER BY 1 NULLS LAST; } execsql_test 4.4.3 { SELECT sum(b) OVER ( ORDER BY a DESC NULLS LAST ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING ) FROM t1 ORDER BY 1 NULLS FIRST; } execsql_test 4.4.4 { SELECT sum(b) OVER ( ORDER BY a DESC NULLS LAST ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING ) FROM t1 ORDER BY 1 NULLS LAST; } execsql_test 4.5.1 { SELECT sum(b) OVER ( ORDER BY a ASC NULLS LAST RANGE BETWEEN UNBOUNDED PRECEDING AND 10 FOLLOWING ) FROM t1 ORDER BY 1 NULLS LAST; } execsql_test 4.5.2 { SELECT sum(b) OVER ( ORDER BY a DESC NULLS FIRST RANGE BETWEEN UNBOUNDED PRECEDING AND 10 FOLLOWING ) FROM t1 ORDER BY 1 NULLS LAST; } ========== execsql_test 5.0 { INSERT INTO t3 VALUES (NULL, 'bb', 355), (NULL, 'cc', 158), (NULL, 'aa', 399), ('JJ', NULL, 839), ('FF', NULL, 618), ('BB', NULL, 393), (NULL, 'bb', 629), (NULL, NULL, 667), (NULL, NULL, 870); } foreach {tn ex} { 1 { EXCLUDE NO OTHERS } 2 { EXCLUDE CURRENT ROW } 3 { EXCLUDE GROUP } 4 { EXCLUDE TIES } } { foreach {tn2 frame} { 1 { RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING } 2 { ORDER BY a NULLS FIRST RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING } 3 { PARTITION BY coalesce(a, '') RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING } 4 { ORDER BY a NULLS FIRST GROUPS 6 PRECEDING } 5 { ORDER BY c NULLS FIRST RANGE BETWEEN 6 PRECEDING AND 7 FOLLOWING } 6 { ORDER BY c NULLS FIRST RANGE BETWEEN 0 PRECEDING AND 0 FOLLOWING } 7 { ORDER BY c NULLS FIRST, b NULLS FIRST, a NULLS FIRST ROWS BETWEEN 6 PRECEDING AND UNBOUNDED FOLLOWING } 8 { RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING } 9 { ORDER BY a NULLS LAST RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING } 10 { PARTITION BY coalesce(a, '') RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING } 11 { ORDER BY a NULLS LAST GROUPS 6 PRECEDING } 12 { ORDER BY c NULLS LAST RANGE BETWEEN 6 PRECEDING AND 7 FOLLOWING } 13 { ORDER BY c NULLS LAST RANGE BETWEEN 0 PRECEDING AND 0 FOLLOWING } 14 { ORDER BY c NULLS LAST, b NULLS LAST, a NULLS LAST ROWS BETWEEN 6 PRECEDING AND UNBOUNDED FOLLOWING } } { execsql_test 5.$tn.$tn2.1 " SELECT max(c) OVER win, min(c) OVER win, count(a) OVER win FROM t3 WINDOW win AS ( $frame $ex ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST " execsql_test 5.$tn.$tn2.2 " SELECT sum(c) FILTER (WHERE (c%2)!=0) OVER win, rank() OVER win, dense_rank() OVER win FROM t3 WINDOW win AS ( $frame $ex ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST " } } ========== execsql_test 6.0 { DROP TABLE IF EXISTS t2; CREATE TABLE t2(a TEXT, b INTEGER); INSERT INTO t2 VALUES('A', NULL); INSERT INTO t2 VALUES('B', NULL); INSERT INTO t2 VALUES('C', 1); } execsql_test 6.1 { SELECT string_agg(a, '.') OVER ( ORDER BY b NULLS FIRST RANGE BETWEEN 7 PRECEDING AND 2 PRECEDING ) FROM t2 } execsql_test 6.2 { SELECT string_agg(a, '.') OVER ( ORDER BY b DESC NULLS LAST RANGE BETWEEN 7 PRECEDING AND 2 PRECEDING ) FROM t2 } ========== execsql_test 7.0 { DROP TABLE IF EXISTS t2; CREATE TABLE t2(a INTEGER, b INTEGER); INSERT INTO t2 VALUES(1, 65); INSERT INTO t2 VALUES(2, NULL); INSERT INTO t2 VALUES(3, NULL); INSERT INTO t2 VALUES(4, NULL); INSERT INTO t2 VALUES(5, 66); INSERT INTO t2 VALUES(6, 67); } foreach {tn f ex} { 1 sum "" 2 min "" 3 sum "EXCLUDE CURRENT ROW" 4 max "EXCLUDE CURRENT ROW" } { execsql_test 7.$tn.1 " SELECT $f (a) OVER win FROM t2 WINDOW win AS ( ORDER BY b NULLS LAST RANGE BETWEEN 6 FOLLOWING AND UNBOUNDED FOLLOWING ); " execsql_test 7.$tn.2 " SELECT $f (a) OVER win FROM t2 WINDOW win AS ( ORDER BY b NULLS LAST RANGE BETWEEN 1 PRECEDING AND 2 PRECEDING ); " execsql_test 7.$tn.3 " SELECT $f (a) OVER win FROM t2 WINDOW win AS ( ORDER BY b NULLS LAST RANGE BETWEEN 2 FOLLOWING AND 1 FOLLOWING ); " execsql_test 7.$tn.4 " SELECT $f (a) OVER win FROM t2 WINDOW win AS ( ORDER BY b NULLS FIRST RANGE BETWEEN 1 PRECEDING AND 2 PRECEDING ); " execsql_test 7.$tn.5 " SELECT $f (a) OVER win FROM t2 WINDOW win AS ( ORDER BY b NULLS FIRST RANGE BETWEEN 2 FOLLOWING AND 1 FOLLOWING ); " execsql_test 7.$tn.6 " SELECT $f (a) OVER win FROM t2 WINDOW win AS ( ORDER BY b NULLS LAST RANGE BETWEEN 1000 PRECEDING AND 2 PRECEDING ); " execsql_test 7.$tn.7 " SELECT $f (a) OVER win FROM t2 WINDOW win AS ( ORDER BY b NULLS LAST RANGE BETWEEN 2000 FOLLOWING AND 1000 FOLLOWING ); " execsql_test 7.$tn.8 " SELECT $f (a) OVER win FROM t2 WINDOW win AS ( ORDER BY b NULLS FIRST RANGE BETWEEN 1000 PRECEDING AND 2000 PRECEDING ); " execsql_test 7.$tn.9 " SELECT $f (a) OVER win FROM t2 WINDOW win AS ( ORDER BY b NULLS FIRST RANGE BETWEEN 2000 FOLLOWING AND 1000 FOLLOWING ); " } ========== execsql_test 8.0 { DROP TABLE IF EXISTS tx; CREATE TABLE tx(a INTEGER PRIMARY KEY); INSERT INTO tx VALUES(1), (2), (3), (4), (5), (6); DROP TABLE IF EXISTS map; CREATE TABLE map(v INTEGER PRIMARY KEY, t TEXT); INSERT INTO map VALUES (1, 'odd'), (2, 'even'), (3, 'odd'), (4, 'even'), (5, 'odd'), (6, 'even'); } execsql_test 8.1 { SELECT sum(a) OVER ( PARTITION BY ( SELECT t FROM map WHERE v=a ) ORDER BY a ) FROM tx; } execsql_test 8.2 { SELECT sum(a) OVER win FROM tx WINDOW win AS ( PARTITION BY ( SELECT t FROM map WHERE v=a ) ORDER BY a ); } execsql_test 8.3 { WITH map2 AS ( SELECT * FROM map ) SELECT sum(a) OVER ( PARTITION BY ( SELECT t FROM map2 WHERE v=a ) ORDER BY a ) FROM tx; } execsql_test 8.4 { WITH map2 AS ( SELECT * FROM map ) SELECT sum(a) OVER win FROM tx WINDOW win AS ( PARTITION BY ( SELECT t FROM map2 WHERE v=a ) ORDER BY a ); } ========== execsql_test 9.1 { DROP TABLE IF EXISTS t1; DROP TABLE IF EXISTS t2; CREATE TABLE t1(a INTEGER); CREATE TABLE t2(y INTEGER); } execsql_test 9.2 { SELECT ( SELECT max(a) OVER ( ORDER BY (SELECT sum(a) FROM t1) ) + min(a) OVER() ) FROM t1 } finish_test |
Added test/window8.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 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 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 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 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 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 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 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 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 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 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 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 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 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 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 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 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 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 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 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 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 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 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 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 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 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 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 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 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 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 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 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 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 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 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 3940 3941 3942 3943 3944 3945 3946 3947 3948 3949 3950 3951 3952 3953 3954 3955 3956 3957 3958 3959 3960 3961 3962 3963 3964 3965 3966 3967 3968 3969 3970 3971 3972 3973 3974 3975 3976 3977 3978 3979 3980 3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994 3995 3996 3997 3998 3999 4000 4001 4002 4003 4004 4005 4006 4007 4008 4009 4010 4011 4012 4013 4014 4015 4016 4017 4018 4019 4020 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 4034 4035 4036 4037 4038 4039 4040 4041 4042 4043 4044 4045 4046 4047 4048 4049 4050 4051 4052 4053 4054 4055 4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075 4076 4077 4078 4079 4080 4081 4082 4083 4084 4085 4086 4087 4088 4089 4090 4091 4092 4093 4094 4095 4096 4097 4098 4099 4100 4101 4102 4103 4104 4105 4106 4107 4108 4109 4110 4111 4112 4113 4114 4115 4116 4117 4118 4119 4120 4121 4122 4123 4124 4125 4126 4127 4128 4129 4130 4131 4132 4133 4134 4135 4136 4137 4138 4139 4140 4141 4142 4143 4144 4145 4146 4147 4148 4149 4150 4151 4152 4153 4154 4155 4156 4157 4158 4159 4160 4161 4162 4163 4164 4165 4166 4167 4168 4169 4170 4171 4172 4173 4174 4175 4176 4177 4178 4179 4180 4181 4182 4183 4184 4185 4186 4187 4188 4189 4190 4191 4192 4193 4194 4195 4196 4197 4198 4199 4200 4201 4202 4203 4204 4205 4206 4207 4208 4209 4210 4211 4212 4213 4214 4215 4216 4217 4218 4219 4220 4221 4222 4223 4224 4225 4226 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 4258 4259 4260 4261 4262 4263 4264 4265 4266 4267 4268 4269 4270 4271 4272 4273 4274 4275 4276 4277 4278 4279 4280 4281 4282 4283 4284 4285 4286 4287 4288 4289 4290 4291 4292 4293 4294 4295 4296 4297 4298 4299 4300 4301 4302 4303 4304 4305 4306 4307 4308 4309 4310 4311 4312 4313 4314 4315 4316 4317 4318 4319 4320 4321 4322 4323 4324 4325 4326 4327 4328 4329 4330 4331 4332 4333 4334 4335 4336 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 4389 4390 4391 4392 4393 4394 4395 4396 4397 4398 4399 4400 4401 4402 4403 4404 4405 4406 4407 4408 4409 4410 4411 4412 4413 4414 4415 4416 4417 4418 4419 4420 4421 4422 4423 4424 4425 4426 4427 4428 4429 4430 4431 4432 4433 4434 4435 4436 4437 4438 4439 4440 4441 4442 4443 4444 4445 4446 4447 4448 4449 4450 4451 4452 4453 4454 4455 4456 4457 4458 4459 4460 4461 4462 4463 4464 4465 4466 4467 4468 4469 4470 4471 4472 4473 4474 4475 4476 4477 4478 4479 4480 4481 4482 4483 4484 4485 4486 4487 4488 4489 4490 4491 4492 4493 4494 4495 4496 4497 4498 4499 4500 4501 4502 4503 4504 4505 4506 4507 4508 4509 4510 4511 4512 4513 4514 4515 4516 4517 4518 4519 4520 4521 4522 4523 4524 4525 4526 4527 4528 4529 4530 4531 4532 4533 4534 4535 4536 4537 4538 4539 4540 4541 4542 4543 4544 4545 4546 4547 4548 4549 4550 4551 4552 4553 4554 4555 4556 4557 4558 4559 4560 4561 4562 4563 4564 4565 4566 4567 4568 4569 4570 4571 4572 4573 4574 4575 4576 4577 4578 4579 4580 4581 4582 4583 4584 4585 4586 4587 4588 4589 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 4834 4835 4836 4837 4838 4839 4840 4841 4842 4843 4844 4845 4846 4847 4848 4849 4850 4851 4852 4853 4854 4855 4856 4857 4858 4859 4860 4861 4862 4863 4864 4865 4866 4867 4868 4869 4870 4871 4872 4873 4874 4875 4876 4877 4878 4879 4880 4881 4882 4883 4884 4885 4886 4887 4888 4889 4890 4891 4892 4893 4894 4895 4896 4897 4898 4899 4900 4901 4902 4903 4904 4905 4906 4907 4908 4909 4910 4911 4912 4913 4914 4915 4916 4917 4918 4919 4920 4921 4922 4923 4924 4925 4926 4927 4928 4929 4930 4931 4932 4933 4934 4935 4936 4937 4938 4939 4940 4941 4942 4943 4944 4945 4946 4947 4948 4949 4950 4951 4952 4953 4954 4955 4956 4957 4958 4959 4960 4961 4962 4963 4964 4965 4966 4967 4968 4969 4970 4971 4972 4973 4974 4975 4976 4977 4978 4979 4980 4981 4982 4983 4984 4985 4986 4987 4988 4989 4990 4991 4992 4993 4994 4995 4996 4997 4998 4999 5000 5001 5002 5003 5004 5005 5006 5007 5008 5009 5010 5011 5012 5013 5014 5015 5016 5017 5018 5019 5020 5021 5022 5023 5024 5025 5026 5027 5028 5029 5030 5031 5032 5033 5034 5035 5036 5037 5038 5039 5040 5041 5042 5043 5044 5045 5046 5047 5048 5049 5050 5051 5052 5053 5054 5055 5056 5057 5058 5059 5060 5061 5062 5063 5064 5065 5066 5067 5068 5069 5070 5071 5072 5073 5074 5075 5076 5077 5078 5079 5080 5081 5082 5083 5084 5085 5086 5087 5088 5089 5090 5091 5092 5093 5094 5095 5096 5097 5098 5099 5100 5101 5102 5103 5104 5105 5106 5107 5108 5109 5110 5111 5112 5113 5114 5115 5116 5117 5118 5119 5120 5121 5122 5123 5124 5125 5126 5127 5128 5129 5130 5131 5132 5133 5134 5135 5136 5137 5138 5139 5140 5141 5142 5143 5144 5145 5146 5147 5148 5149 5150 5151 5152 5153 5154 5155 5156 5157 5158 5159 5160 5161 5162 5163 5164 5165 5166 5167 5168 5169 5170 5171 5172 5173 5174 5175 5176 5177 5178 5179 5180 5181 5182 5183 5184 5185 5186 5187 5188 5189 5190 5191 5192 5193 5194 5195 5196 5197 5198 5199 5200 5201 5202 5203 5204 5205 5206 5207 5208 5209 5210 5211 5212 5213 5214 5215 5216 5217 5218 5219 5220 5221 5222 5223 5224 5225 5226 5227 5228 5229 5230 5231 5232 5233 5234 5235 5236 5237 5238 5239 5240 5241 5242 5243 5244 5245 5246 5247 5248 5249 5250 5251 5252 5253 5254 5255 5256 5257 5258 5259 5260 5261 5262 5263 5264 5265 5266 5267 5268 5269 5270 5271 5272 5273 5274 5275 5276 5277 5278 5279 5280 5281 5282 5283 5284 5285 5286 5287 5288 5289 5290 5291 5292 5293 5294 5295 5296 5297 5298 5299 5300 5301 5302 5303 5304 5305 5306 5307 5308 5309 5310 5311 5312 5313 5314 5315 5316 5317 5318 5319 5320 5321 5322 5323 5324 5325 5326 5327 5328 5329 5330 5331 5332 5333 5334 5335 5336 5337 5338 5339 5340 5341 5342 5343 5344 5345 5346 5347 5348 5349 5350 5351 5352 5353 5354 5355 5356 5357 5358 5359 5360 5361 5362 5363 5364 5365 5366 5367 5368 5369 5370 5371 5372 5373 5374 5375 5376 5377 5378 5379 5380 5381 5382 5383 5384 5385 5386 5387 5388 5389 5390 5391 5392 5393 5394 5395 5396 5397 5398 5399 5400 5401 5402 5403 5404 5405 5406 5407 5408 5409 5410 5411 5412 5413 5414 5415 5416 5417 5418 5419 5420 5421 5422 5423 5424 5425 5426 5427 5428 5429 5430 5431 5432 5433 5434 5435 5436 5437 5438 5439 5440 5441 5442 5443 5444 5445 5446 5447 5448 5449 5450 5451 5452 5453 5454 5455 5456 5457 5458 5459 5460 5461 5462 5463 5464 5465 5466 5467 5468 5469 5470 5471 5472 5473 5474 5475 5476 5477 5478 5479 5480 5481 5482 5483 5484 5485 5486 5487 5488 5489 5490 5491 5492 5493 5494 5495 5496 5497 5498 5499 5500 5501 5502 5503 5504 5505 5506 5507 5508 5509 5510 5511 5512 5513 5514 5515 5516 5517 5518 5519 5520 5521 5522 5523 5524 5525 5526 5527 5528 5529 5530 5531 5532 5533 5534 5535 5536 5537 5538 5539 5540 5541 5542 5543 5544 5545 5546 5547 5548 5549 5550 5551 5552 5553 5554 5555 5556 5557 5558 5559 5560 5561 5562 5563 5564 5565 5566 5567 5568 5569 5570 5571 5572 5573 5574 5575 5576 5577 5578 5579 5580 5581 5582 5583 5584 5585 5586 5587 5588 5589 5590 5591 5592 5593 5594 5595 5596 5597 5598 5599 5600 5601 5602 5603 5604 5605 5606 5607 5608 5609 5610 5611 5612 5613 5614 5615 5616 5617 5618 5619 5620 5621 5622 5623 5624 5625 5626 5627 5628 5629 5630 5631 5632 5633 5634 5635 5636 5637 5638 5639 5640 5641 5642 5643 5644 5645 5646 5647 5648 5649 5650 5651 5652 5653 5654 5655 5656 5657 5658 5659 5660 5661 5662 5663 5664 5665 5666 5667 5668 5669 5670 5671 5672 5673 5674 5675 5676 5677 5678 5679 5680 5681 5682 5683 5684 5685 5686 5687 5688 5689 5690 5691 5692 5693 5694 5695 5696 5697 5698 5699 5700 5701 5702 5703 5704 5705 5706 5707 5708 5709 5710 5711 5712 5713 5714 5715 5716 5717 5718 5719 5720 5721 5722 5723 5724 5725 5726 5727 5728 5729 5730 5731 5732 5733 5734 5735 5736 5737 5738 5739 5740 5741 5742 5743 5744 5745 5746 5747 5748 5749 5750 5751 5752 5753 5754 5755 5756 5757 5758 5759 5760 5761 5762 5763 5764 5765 5766 5767 5768 5769 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 5809 5810 5811 5812 5813 5814 5815 5816 5817 5818 5819 5820 5821 5822 5823 5824 5825 5826 5827 5828 5829 5830 5831 5832 5833 5834 5835 5836 5837 5838 5839 5840 5841 5842 5843 5844 5845 5846 5847 5848 5849 5850 5851 5852 5853 5854 5855 5856 5857 5858 5859 5860 5861 5862 5863 5864 5865 5866 5867 5868 5869 5870 5871 5872 5873 5874 5875 5876 5877 5878 5879 5880 5881 5882 5883 5884 5885 5886 5887 5888 5889 5890 5891 5892 5893 5894 5895 5896 5897 5898 5899 5900 5901 5902 5903 5904 5905 5906 5907 5908 5909 5910 5911 5912 5913 5914 5915 5916 5917 5918 5919 5920 5921 5922 5923 5924 5925 5926 5927 5928 5929 5930 5931 5932 5933 5934 5935 5936 5937 5938 5939 5940 5941 5942 5943 5944 5945 5946 5947 5948 5949 5950 5951 5952 5953 5954 5955 5956 5957 5958 5959 5960 5961 5962 5963 5964 5965 5966 5967 5968 5969 5970 5971 5972 5973 5974 5975 5976 5977 5978 5979 5980 5981 5982 5983 5984 5985 5986 5987 5988 5989 5990 5991 5992 5993 5994 5995 5996 5997 5998 5999 6000 6001 6002 6003 6004 6005 6006 6007 6008 6009 6010 6011 6012 6013 6014 6015 6016 6017 6018 6019 6020 6021 6022 6023 6024 6025 6026 6027 6028 6029 6030 6031 6032 6033 6034 6035 6036 6037 6038 6039 6040 6041 6042 6043 6044 6045 6046 6047 6048 6049 6050 6051 6052 6053 6054 6055 6056 6057 6058 6059 6060 6061 6062 6063 6064 6065 6066 6067 6068 6069 6070 6071 6072 6073 6074 6075 6076 6077 6078 6079 6080 6081 6082 6083 6084 6085 6086 6087 6088 6089 6090 6091 6092 6093 6094 6095 6096 6097 6098 6099 6100 6101 6102 6103 6104 6105 6106 6107 6108 6109 6110 6111 6112 6113 6114 6115 6116 6117 6118 6119 6120 6121 6122 6123 6124 6125 6126 6127 6128 6129 6130 6131 6132 6133 6134 6135 6136 6137 6138 6139 6140 6141 6142 6143 6144 6145 6146 6147 6148 6149 6150 6151 6152 6153 6154 6155 6156 6157 6158 6159 6160 6161 6162 6163 6164 6165 6166 6167 6168 6169 6170 6171 6172 6173 6174 6175 6176 6177 6178 6179 6180 6181 6182 6183 6184 6185 6186 6187 6188 6189 6190 6191 6192 6193 6194 6195 6196 6197 6198 6199 6200 6201 6202 6203 6204 6205 6206 6207 6208 6209 6210 6211 6212 6213 6214 6215 6216 6217 6218 6219 6220 6221 6222 6223 6224 6225 6226 6227 6228 6229 6230 6231 6232 6233 6234 6235 6236 6237 6238 6239 6240 6241 6242 6243 6244 6245 6246 6247 6248 6249 6250 6251 6252 6253 6254 6255 6256 6257 6258 6259 6260 6261 6262 6263 6264 6265 6266 6267 6268 6269 6270 6271 6272 6273 6274 6275 6276 6277 6278 6279 6280 6281 6282 6283 6284 6285 6286 6287 6288 6289 6290 6291 6292 6293 6294 6295 6296 6297 6298 6299 6300 6301 6302 6303 6304 6305 6306 6307 6308 6309 6310 6311 6312 6313 6314 6315 6316 6317 6318 6319 6320 6321 6322 6323 6324 6325 6326 6327 6328 6329 6330 6331 6332 6333 6334 6335 6336 6337 6338 6339 6340 6341 6342 6343 6344 6345 6346 6347 6348 6349 6350 6351 6352 6353 6354 6355 6356 6357 6358 6359 6360 6361 6362 6363 6364 6365 6366 6367 6368 6369 6370 6371 6372 6373 6374 6375 6376 6377 6378 6379 6380 6381 6382 6383 6384 6385 6386 6387 6388 6389 6390 6391 6392 6393 6394 6395 6396 6397 6398 6399 6400 6401 6402 6403 6404 6405 6406 6407 6408 6409 6410 6411 6412 6413 6414 6415 6416 6417 6418 6419 6420 6421 6422 6423 6424 6425 6426 6427 6428 6429 6430 6431 6432 6433 6434 6435 6436 6437 6438 6439 6440 6441 6442 6443 6444 6445 6446 6447 6448 6449 6450 6451 6452 6453 6454 6455 6456 6457 6458 6459 6460 6461 6462 6463 6464 6465 6466 6467 6468 6469 6470 6471 6472 6473 6474 6475 6476 6477 6478 6479 6480 6481 6482 6483 6484 6485 6486 6487 6488 6489 6490 6491 6492 6493 6494 6495 6496 6497 6498 6499 6500 6501 6502 6503 6504 6505 6506 6507 6508 6509 6510 6511 6512 6513 6514 6515 6516 6517 6518 6519 6520 6521 6522 6523 6524 6525 6526 6527 6528 6529 6530 6531 6532 6533 6534 6535 6536 6537 6538 6539 6540 6541 6542 6543 | # 2019 March 01 # # 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. # #################################################### # DO NOT EDIT! THIS FILE IS AUTOMATICALLY GENERATED! #################################################### set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix window8 ifcapable !windowfunc { finish_test ; return } do_execsql_test 1.0 { DROP TABLE IF EXISTS t3; CREATE TABLE t3(a TEXT, b TEXT, c INTEGER); INSERT INTO t3 VALUES ('HH', 'bb', 355), ('CC', 'aa', 158), ('BB', 'aa', 399), ('FF', 'bb', 938), ('HH', 'aa', 480), ('FF', 'bb', 870), ('JJ', 'aa', 768), ('JJ', 'aa', 899), ('GG', 'bb', 929), ('II', 'bb', 421), ('GG', 'bb', 844), ('FF', 'bb', 574), ('CC', 'bb', 822), ('GG', 'bb', 938), ('BB', 'aa', 660), ('HH', 'aa', 979), ('BB', 'bb', 792), ('DD', 'aa', 845), ('JJ', 'bb', 354), ('FF', 'bb', 295), ('JJ', 'aa', 234), ('BB', 'bb', 840), ('AA', 'aa', 934), ('EE', 'aa', 113), ('AA', 'bb', 309), ('BB', 'aa', 412), ('AA', 'aa', 911), ('AA', 'bb', 572), ('II', 'aa', 398), ('II', 'bb', 250), ('II', 'aa', 652), ('BB', 'bb', 633), ('AA', 'aa', 239), ('FF', 'aa', 670), ('BB', 'bb', 705), ('HH', 'bb', 963), ('CC', 'bb', 346), ('II', 'bb', 671), ('BB', 'aa', 247), ('AA', 'aa', 223), ('GG', 'aa', 480), ('HH', 'aa', 790), ('FF', 'aa', 208), ('BB', 'bb', 711), ('EE', 'aa', 777), ('DD', 'bb', 716), ('CC', 'aa', 759), ('CC', 'aa', 430), ('CC', 'aa', 607), ('DD', 'bb', 794), ('GG', 'aa', 148), ('GG', 'aa', 634), ('JJ', 'bb', 257), ('DD', 'bb', 959), ('FF', 'bb', 726), ('BB', 'aa', 762), ('JJ', 'bb', 336), ('GG', 'aa', 335), ('HH', 'bb', 330), ('GG', 'bb', 160), ('JJ', 'bb', 839), ('FF', 'aa', 618), ('BB', 'aa', 393), ('EE', 'bb', 629), ('FF', 'aa', 667), ('AA', 'bb', 870), ('FF', 'bb', 102), ('JJ', 'aa', 113), ('DD', 'aa', 224), ('AA', 'bb', 627), ('HH', 'bb', 730), ('II', 'bb', 443), ('HH', 'bb', 133), ('EE', 'bb', 252), ('II', 'bb', 805), ('BB', 'bb', 786), ('EE', 'bb', 768), ('HH', 'bb', 683), ('DD', 'bb', 238), ('DD', 'aa', 256); } {} do_execsql_test 1.1.1 { SELECT a, b, sum(c) OVER (ORDER BY a GROUPS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa {} AA aa {} AA aa {} AA aa {} AA bb {} AA bb {} AA bb {} AA bb {} BB aa 4685 BB aa 4685 BB aa 4685 BB aa 4685 BB aa 4685 BB aa 4685 BB bb 4685 BB bb 4685 BB bb 4685 BB bb 4685 BB bb 4685 BB bb 4685 CC aa 12025 CC aa 12025 CC aa 12025 CC aa 12025 CC bb 12025 CC bb 12025 DD aa 15147 DD aa 15147 DD aa 15147 DD bb 15147 DD bb 15147 DD bb 15147 DD bb 15147 EE aa 19179 EE aa 19179 EE bb 19179 EE bb 19179 EE bb 19179 FF aa 21718 FF aa 21718 FF aa 21718 FF aa 21718 FF bb 21718 FF bb 21718 FF bb 21718 FF bb 21718 FF bb 21718 FF bb 21718 GG aa 27386 GG aa 27386 GG aa 27386 GG aa 27386 GG bb 27386 GG bb 27386 GG bb 27386 GG bb 27386 HH aa 31854 HH aa 31854 HH aa 31854 HH bb 31854 HH bb 31854 HH bb 31854 HH bb 31854 HH bb 31854 HH bb 31854 II aa 37297 II aa 37297 II bb 37297 II bb 37297 II bb 37297 II bb 37297 II bb 37297 JJ aa 40937 JJ aa 40937 JJ aa 40937 JJ aa 40937 JJ bb 40937 JJ bb 40937 JJ bb 40937 JJ bb 40937} do_execsql_test 1.1.2 { SELECT a, b, sum(c) OVER (ORDER BY a,b GROUPS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa {} AA aa {} AA aa {} AA aa {} AA bb 2307 AA bb 2307 AA bb 2307 AA bb 2307 BB aa 4685 BB aa 4685 BB aa 4685 BB aa 4685 BB aa 4685 BB aa 4685 BB bb 7558 BB bb 7558 BB bb 7558 BB bb 7558 BB bb 7558 BB bb 7558 CC aa 12025 CC aa 12025 CC aa 12025 CC aa 12025 CC bb 13979 CC bb 13979 DD aa 15147 DD aa 15147 DD aa 15147 DD bb 16472 DD bb 16472 DD bb 16472 DD bb 16472 EE aa 19179 EE aa 19179 EE bb 20069 EE bb 20069 EE bb 20069 FF aa 21718 FF aa 21718 FF aa 21718 FF aa 21718 FF bb 23881 FF bb 23881 FF bb 23881 FF bb 23881 FF bb 23881 FF bb 23881 GG aa 27386 GG aa 27386 GG aa 27386 GG aa 27386 GG bb 28983 GG bb 28983 GG bb 28983 GG bb 28983 HH aa 31854 HH aa 31854 HH aa 31854 HH bb 34103 HH bb 34103 HH bb 34103 HH bb 34103 HH bb 34103 HH bb 34103 II aa 37297 II aa 37297 II bb 38347 II bb 38347 II bb 38347 II bb 38347 II bb 38347 JJ aa 40937 JJ aa 40937 JJ aa 40937 JJ aa 40937 JJ bb 42951 JJ bb 42951 JJ bb 42951 JJ bb 42951} do_execsql_test 1.1.3 { SELECT a, b, rank() OVER (ORDER BY a GROUPS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa 1 AA aa 1 AA aa 1 AA aa 1 AA bb 1 AA bb 1 AA bb 1 AA bb 1 BB aa 9 BB aa 9 BB aa 9 BB aa 9 BB aa 9 BB aa 9 BB bb 9 BB bb 9 BB bb 9 BB bb 9 BB bb 9 BB bb 9 CC aa 21 CC aa 21 CC aa 21 CC aa 21 CC bb 21 CC bb 21 DD aa 27 DD aa 27 DD aa 27 DD bb 27 DD bb 27 DD bb 27 DD bb 27 EE aa 34 EE aa 34 EE bb 34 EE bb 34 EE bb 34 FF aa 39 FF aa 39 FF aa 39 FF aa 39 FF bb 39 FF bb 39 FF bb 39 FF bb 39 FF bb 39 FF bb 39 GG aa 49 GG aa 49 GG aa 49 GG aa 49 GG bb 49 GG bb 49 GG bb 49 GG bb 49 HH aa 57 HH aa 57 HH aa 57 HH bb 57 HH bb 57 HH bb 57 HH bb 57 HH bb 57 HH bb 57 II aa 66 II aa 66 II bb 66 II bb 66 II bb 66 II bb 66 II bb 66 JJ aa 73 JJ aa 73 JJ aa 73 JJ aa 73 JJ bb 73 JJ bb 73 JJ bb 73 JJ bb 73} do_execsql_test 1.1.4 { SELECT a, b, max(c) OVER (ORDER BY a,b GROUPS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa {} AA aa {} AA aa {} AA aa {} AA bb 934 AA bb 934 AA bb 934 AA bb 934 BB aa 934 BB aa 934 BB aa 934 BB aa 934 BB aa 934 BB aa 934 BB bb 934 BB bb 934 BB bb 934 BB bb 934 BB bb 934 BB bb 934 CC aa 934 CC aa 934 CC aa 934 CC aa 934 CC bb 934 CC bb 934 DD aa 934 DD aa 934 DD aa 934 DD bb 934 DD bb 934 DD bb 934 DD bb 934 EE aa 959 EE aa 959 EE bb 959 EE bb 959 EE bb 959 FF aa 959 FF aa 959 FF aa 959 FF aa 959 FF bb 959 FF bb 959 FF bb 959 FF bb 959 FF bb 959 FF bb 959 GG aa 959 GG aa 959 GG aa 959 GG aa 959 GG bb 959 GG bb 959 GG bb 959 GG bb 959 HH aa 959 HH aa 959 HH aa 959 HH bb 979 HH bb 979 HH bb 979 HH bb 979 HH bb 979 HH bb 979 II aa 979 II aa 979 II bb 979 II bb 979 II bb 979 II bb 979 II bb 979 JJ aa 979 JJ aa 979 JJ aa 979 JJ aa 979 JJ bb 979 JJ bb 979 JJ bb 979 JJ bb 979} do_execsql_test 1.1.5 { SELECT a, b, min(c) OVER (ORDER BY a,b GROUPS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa {} AA aa {} AA aa {} AA aa {} AA bb 223 AA bb 223 AA bb 223 AA bb 223 BB aa 223 BB aa 223 BB aa 223 BB aa 223 BB aa 223 BB aa 223 BB bb 223 BB bb 223 BB bb 223 BB bb 223 BB bb 223 BB bb 223 CC aa 223 CC aa 223 CC aa 223 CC aa 223 CC bb 158 CC bb 158 DD aa 158 DD aa 158 DD aa 158 DD bb 158 DD bb 158 DD bb 158 DD bb 158 EE aa 158 EE aa 158 EE bb 113 EE bb 113 EE bb 113 FF aa 113 FF aa 113 FF aa 113 FF aa 113 FF bb 113 FF bb 113 FF bb 113 FF bb 113 FF bb 113 FF bb 113 GG aa 102 GG aa 102 GG aa 102 GG aa 102 GG bb 102 GG bb 102 GG bb 102 GG bb 102 HH aa 102 HH aa 102 HH aa 102 HH bb 102 HH bb 102 HH bb 102 HH bb 102 HH bb 102 HH bb 102 II aa 102 II aa 102 II bb 102 II bb 102 II bb 102 II bb 102 II bb 102 JJ aa 102 JJ aa 102 JJ aa 102 JJ aa 102 JJ bb 102 JJ bb 102 JJ bb 102 JJ bb 102} do_execsql_test 1.1.6 { SELECT a, b, sum(c) OVER (ORDER BY a GROUPS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING EXCLUDE CURRENT ROW) FROM t3 ORDER BY 1, 2, 3; } {AA aa {} AA aa {} AA aa {} AA aa {} AA bb {} AA bb {} AA bb {} AA bb {} BB aa 4685 BB aa 4685 BB aa 4685 BB aa 4685 BB aa 4685 BB aa 4685 BB bb 4685 BB bb 4685 BB bb 4685 BB bb 4685 BB bb 4685 BB bb 4685 CC aa 12025 CC aa 12025 CC aa 12025 CC aa 12025 CC bb 12025 CC bb 12025 DD aa 15147 DD aa 15147 DD aa 15147 DD bb 15147 DD bb 15147 DD bb 15147 DD bb 15147 EE aa 19179 EE aa 19179 EE bb 19179 EE bb 19179 EE bb 19179 FF aa 21718 FF aa 21718 FF aa 21718 FF aa 21718 FF bb 21718 FF bb 21718 FF bb 21718 FF bb 21718 FF bb 21718 FF bb 21718 GG aa 27386 GG aa 27386 GG aa 27386 GG aa 27386 GG bb 27386 GG bb 27386 GG bb 27386 GG bb 27386 HH aa 31854 HH aa 31854 HH aa 31854 HH bb 31854 HH bb 31854 HH bb 31854 HH bb 31854 HH bb 31854 HH bb 31854 II aa 37297 II aa 37297 II bb 37297 II bb 37297 II bb 37297 II bb 37297 II bb 37297 JJ aa 40937 JJ aa 40937 JJ aa 40937 JJ aa 40937 JJ bb 40937 JJ bb 40937 JJ bb 40937 JJ bb 40937} do_execsql_test 1.1.7 { SELECT a, b, sum(c) OVER (ORDER BY a,b GROUPS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING EXCLUDE CURRENT ROW) FROM t3 ORDER BY 1, 2, 3; } {AA aa {} AA aa {} AA aa {} AA aa {} AA bb 2307 AA bb 2307 AA bb 2307 AA bb 2307 BB aa 4685 BB aa 4685 BB aa 4685 BB aa 4685 BB aa 4685 BB aa 4685 BB bb 7558 BB bb 7558 BB bb 7558 BB bb 7558 BB bb 7558 BB bb 7558 CC aa 12025 CC aa 12025 CC aa 12025 CC aa 12025 CC bb 13979 CC bb 13979 DD aa 15147 DD aa 15147 DD aa 15147 DD bb 16472 DD bb 16472 DD bb 16472 DD bb 16472 EE aa 19179 EE aa 19179 EE bb 20069 EE bb 20069 EE bb 20069 FF aa 21718 FF aa 21718 FF aa 21718 FF aa 21718 FF bb 23881 FF bb 23881 FF bb 23881 FF bb 23881 FF bb 23881 FF bb 23881 GG aa 27386 GG aa 27386 GG aa 27386 GG aa 27386 GG bb 28983 GG bb 28983 GG bb 28983 GG bb 28983 HH aa 31854 HH aa 31854 HH aa 31854 HH bb 34103 HH bb 34103 HH bb 34103 HH bb 34103 HH bb 34103 HH bb 34103 II aa 37297 II aa 37297 II bb 38347 II bb 38347 II bb 38347 II bb 38347 II bb 38347 JJ aa 40937 JJ aa 40937 JJ aa 40937 JJ aa 40937 JJ bb 42951 JJ bb 42951 JJ bb 42951 JJ bb 42951} do_execsql_test 1.1.8 { SELECT a, b, sum(c) OVER (ORDER BY a GROUPS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING EXCLUDE CURRENT ROW), sum(c) OVER (ORDER BY a GROUPS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING ), sum(c) OVER (ORDER BY a,b GROUPS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING EXCLUDE CURRENT ROW), sum(c) OVER (ORDER BY a,b GROUPS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa {} {} {} {} AA aa {} {} {} {} AA aa {} {} {} {} AA aa {} {} {} {} AA bb {} {} 2307 2307 AA bb {} {} 2307 2307 AA bb {} {} 2307 2307 AA bb {} {} 2307 2307 BB aa 4685 4685 4685 4685 BB aa 4685 4685 4685 4685 BB aa 4685 4685 4685 4685 BB aa 4685 4685 4685 4685 BB aa 4685 4685 4685 4685 BB aa 4685 4685 4685 4685 BB bb 4685 4685 7558 7558 BB bb 4685 4685 7558 7558 BB bb 4685 4685 7558 7558 BB bb 4685 4685 7558 7558 BB bb 4685 4685 7558 7558 BB bb 4685 4685 7558 7558 CC aa 12025 12025 12025 12025 CC aa 12025 12025 12025 12025 CC aa 12025 12025 12025 12025 CC aa 12025 12025 12025 12025 CC bb 12025 12025 13979 13979 CC bb 12025 12025 13979 13979 DD aa 15147 15147 15147 15147 DD aa 15147 15147 15147 15147 DD aa 15147 15147 15147 15147 DD bb 15147 15147 16472 16472 DD bb 15147 15147 16472 16472 DD bb 15147 15147 16472 16472 DD bb 15147 15147 16472 16472 EE aa 19179 19179 19179 19179 EE aa 19179 19179 19179 19179 EE bb 19179 19179 20069 20069 EE bb 19179 19179 20069 20069 EE bb 19179 19179 20069 20069 FF aa 21718 21718 21718 21718 FF aa 21718 21718 21718 21718 FF aa 21718 21718 21718 21718 FF aa 21718 21718 21718 21718 FF bb 21718 21718 23881 23881 FF bb 21718 21718 23881 23881 FF bb 21718 21718 23881 23881 FF bb 21718 21718 23881 23881 FF bb 21718 21718 23881 23881 FF bb 21718 21718 23881 23881 GG aa 27386 27386 27386 27386 GG aa 27386 27386 27386 27386 GG aa 27386 27386 27386 27386 GG aa 27386 27386 27386 27386 GG bb 27386 27386 28983 28983 GG bb 27386 27386 28983 28983 GG bb 27386 27386 28983 28983 GG bb 27386 27386 28983 28983 HH aa 31854 31854 31854 31854 HH aa 31854 31854 31854 31854 HH aa 31854 31854 31854 31854 HH bb 31854 31854 34103 34103 HH bb 31854 31854 34103 34103 HH bb 31854 31854 34103 34103 HH bb 31854 31854 34103 34103 HH bb 31854 31854 34103 34103 HH bb 31854 31854 34103 34103 II aa 37297 37297 37297 37297 II aa 37297 37297 37297 37297 II bb 37297 37297 38347 38347 II bb 37297 37297 38347 38347 II bb 37297 37297 38347 38347 II bb 37297 37297 38347 38347 II bb 37297 37297 38347 38347 JJ aa 40937 40937 40937 40937 JJ aa 40937 40937 40937 40937 JJ aa 40937 40937 40937 40937 JJ aa 40937 40937 40937 40937 JJ bb 40937 40937 42951 42951 JJ bb 40937 40937 42951 42951 JJ bb 40937 40937 42951 42951 JJ bb 40937 40937 42951 42951} do_execsql_test 1.2.1 { SELECT a, b, sum(c) OVER (ORDER BY a GROUPS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ) FROM t3 ORDER BY 1, 2, 3; } {AA aa 4685 AA aa 4685 AA aa 4685 AA aa 4685 AA bb 4685 AA bb 4685 AA bb 4685 AA bb 4685 BB aa 12025 BB aa 12025 BB aa 12025 BB aa 12025 BB aa 12025 BB aa 12025 BB bb 12025 BB bb 12025 BB bb 12025 BB bb 12025 BB bb 12025 BB bb 12025 CC aa 15147 CC aa 15147 CC aa 15147 CC aa 15147 CC bb 15147 CC bb 15147 DD aa 19179 DD aa 19179 DD aa 19179 DD bb 19179 DD bb 19179 DD bb 19179 DD bb 19179 EE aa 21718 EE aa 21718 EE bb 21718 EE bb 21718 EE bb 21718 FF aa 27386 FF aa 27386 FF aa 27386 FF aa 27386 FF bb 27386 FF bb 27386 FF bb 27386 FF bb 27386 FF bb 27386 FF bb 27386 GG aa 31854 GG aa 31854 GG aa 31854 GG aa 31854 GG bb 31854 GG bb 31854 GG bb 31854 GG bb 31854 HH aa 37297 HH aa 37297 HH aa 37297 HH bb 37297 HH bb 37297 HH bb 37297 HH bb 37297 HH bb 37297 HH bb 37297 II aa 40937 II aa 40937 II bb 40937 II bb 40937 II bb 40937 II bb 40937 II bb 40937 JJ aa 44737 JJ aa 44737 JJ aa 44737 JJ aa 44737 JJ bb 44737 JJ bb 44737 JJ bb 44737 JJ bb 44737} do_execsql_test 1.2.2 { SELECT a, b, sum(c) OVER (ORDER BY a,b GROUPS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ) FROM t3 ORDER BY 1, 2, 3; } {AA aa 2307 AA aa 2307 AA aa 2307 AA aa 2307 AA bb 4685 AA bb 4685 AA bb 4685 AA bb 4685 BB aa 7558 BB aa 7558 BB aa 7558 BB aa 7558 BB aa 7558 BB aa 7558 BB bb 12025 BB bb 12025 BB bb 12025 BB bb 12025 BB bb 12025 BB bb 12025 CC aa 13979 CC aa 13979 CC aa 13979 CC aa 13979 CC bb 15147 CC bb 15147 DD aa 16472 DD aa 16472 DD aa 16472 DD bb 19179 DD bb 19179 DD bb 19179 DD bb 19179 EE aa 20069 EE aa 20069 EE bb 21718 EE bb 21718 EE bb 21718 FF aa 23881 FF aa 23881 FF aa 23881 FF aa 23881 FF bb 27386 FF bb 27386 FF bb 27386 FF bb 27386 FF bb 27386 FF bb 27386 GG aa 28983 GG aa 28983 GG aa 28983 GG aa 28983 GG bb 31854 GG bb 31854 GG bb 31854 GG bb 31854 HH aa 34103 HH aa 34103 HH aa 34103 HH bb 37297 HH bb 37297 HH bb 37297 HH bb 37297 HH bb 37297 HH bb 37297 II aa 38347 II aa 38347 II bb 40937 II bb 40937 II bb 40937 II bb 40937 II bb 40937 JJ aa 42951 JJ aa 42951 JJ aa 42951 JJ aa 42951 JJ bb 44737 JJ bb 44737 JJ bb 44737 JJ bb 44737} do_execsql_test 1.2.3 { SELECT a, b, rank() OVER (ORDER BY a GROUPS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ) FROM t3 ORDER BY 1, 2, 3; } {AA aa 1 AA aa 1 AA aa 1 AA aa 1 AA bb 1 AA bb 1 AA bb 1 AA bb 1 BB aa 9 BB aa 9 BB aa 9 BB aa 9 BB aa 9 BB aa 9 BB bb 9 BB bb 9 BB bb 9 BB bb 9 BB bb 9 BB bb 9 CC aa 21 CC aa 21 CC aa 21 CC aa 21 CC bb 21 CC bb 21 DD aa 27 DD aa 27 DD aa 27 DD bb 27 DD bb 27 DD bb 27 DD bb 27 EE aa 34 EE aa 34 EE bb 34 EE bb 34 EE bb 34 FF aa 39 FF aa 39 FF aa 39 FF aa 39 FF bb 39 FF bb 39 FF bb 39 FF bb 39 FF bb 39 FF bb 39 GG aa 49 GG aa 49 GG aa 49 GG aa 49 GG bb 49 GG bb 49 GG bb 49 GG bb 49 HH aa 57 HH aa 57 HH aa 57 HH bb 57 HH bb 57 HH bb 57 HH bb 57 HH bb 57 HH bb 57 II aa 66 II aa 66 II bb 66 II bb 66 II bb 66 II bb 66 II bb 66 JJ aa 73 JJ aa 73 JJ aa 73 JJ aa 73 JJ bb 73 JJ bb 73 JJ bb 73 JJ bb 73} do_execsql_test 1.2.4 { SELECT a, b, max(c) OVER (ORDER BY a,b GROUPS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ) FROM t3 ORDER BY 1, 2, 3; } {AA aa 934 AA aa 934 AA aa 934 AA aa 934 AA bb 934 AA bb 934 AA bb 934 AA bb 934 BB aa 934 BB aa 934 BB aa 934 BB aa 934 BB aa 934 BB aa 934 BB bb 934 BB bb 934 BB bb 934 BB bb 934 BB bb 934 BB bb 934 CC aa 934 CC aa 934 CC aa 934 CC aa 934 CC bb 934 CC bb 934 DD aa 934 DD aa 934 DD aa 934 DD bb 959 DD bb 959 DD bb 959 DD bb 959 EE aa 959 EE aa 959 EE bb 959 EE bb 959 EE bb 959 FF aa 959 FF aa 959 FF aa 959 FF aa 959 FF bb 959 FF bb 959 FF bb 959 FF bb 959 FF bb 959 FF bb 959 GG aa 959 GG aa 959 GG aa 959 GG aa 959 GG bb 959 GG bb 959 GG bb 959 GG bb 959 HH aa 979 HH aa 979 HH aa 979 HH bb 979 HH bb 979 HH bb 979 HH bb 979 HH bb 979 HH bb 979 II aa 979 II aa 979 II bb 979 II bb 979 II bb 979 II bb 979 II bb 979 JJ aa 979 JJ aa 979 JJ aa 979 JJ aa 979 JJ bb 979 JJ bb 979 JJ bb 979 JJ bb 979} do_execsql_test 1.2.5 { SELECT a, b, min(c) OVER (ORDER BY a,b GROUPS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ) FROM t3 ORDER BY 1, 2, 3; } {AA aa 223 AA aa 223 AA aa 223 AA aa 223 AA bb 223 AA bb 223 AA bb 223 AA bb 223 BB aa 223 BB aa 223 BB aa 223 BB aa 223 BB aa 223 BB aa 223 BB bb 223 BB bb 223 BB bb 223 BB bb 223 BB bb 223 BB bb 223 CC aa 158 CC aa 158 CC aa 158 CC aa 158 CC bb 158 CC bb 158 DD aa 158 DD aa 158 DD aa 158 DD bb 158 DD bb 158 DD bb 158 DD bb 158 EE aa 113 EE aa 113 EE bb 113 EE bb 113 EE bb 113 FF aa 113 FF aa 113 FF aa 113 FF aa 113 FF bb 102 FF bb 102 FF bb 102 FF bb 102 FF bb 102 FF bb 102 GG aa 102 GG aa 102 GG aa 102 GG aa 102 GG bb 102 GG bb 102 GG bb 102 GG bb 102 HH aa 102 HH aa 102 HH aa 102 HH bb 102 HH bb 102 HH bb 102 HH bb 102 HH bb 102 HH bb 102 II aa 102 II aa 102 II bb 102 II bb 102 II bb 102 II bb 102 II bb 102 JJ aa 102 JJ aa 102 JJ aa 102 JJ aa 102 JJ bb 102 JJ bb 102 JJ bb 102 JJ bb 102} do_execsql_test 1.2.6 { SELECT a, b, sum(c) OVER (ORDER BY a GROUPS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW EXCLUDE CURRENT ROW) FROM t3 ORDER BY 1, 2, 3; } {AA aa 3751 AA aa 3774 AA aa 4446 AA aa 4462 AA bb 3815 AA bb 4058 AA bb 4113 AA bb 4376 BB aa 11263 BB aa 11365 BB aa 11613 BB aa 11626 BB aa 11632 BB aa 11778 BB bb 11185 BB bb 11233 BB bb 11239 BB bb 11314 BB bb 11320 BB bb 11392 CC aa 14388 CC aa 14540 CC aa 14717 CC aa 14989 CC bb 14325 CC bb 14801 DD aa 18334 DD aa 18923 DD aa 18955 DD bb 18220 DD bb 18385 DD bb 18463 DD bb 18941 EE aa 20941 EE aa 21605 EE bb 20950 EE bb 21089 EE bb 21466 FF aa 26716 FF aa 26719 FF aa 26768 FF aa 27178 FF bb 26448 FF bb 26516 FF bb 26660 FF bb 26812 FF bb 27091 FF bb 27284 GG aa 31220 GG aa 31374 GG aa 31519 GG aa 31706 GG bb 30916 GG bb 30925 GG bb 31010 GG bb 31694 HH aa 36318 HH aa 36507 HH aa 36817 HH bb 36334 HH bb 36567 HH bb 36614 HH bb 36942 HH bb 36967 HH bb 37164 II aa 40285 II aa 40539 II bb 40132 II bb 40266 II bb 40494 II bb 40516 II bb 40687 JJ aa 43838 JJ aa 43969 JJ aa 44503 JJ aa 44624 JJ bb 43898 JJ bb 44383 JJ bb 44401 JJ bb 44480} do_execsql_test 1.2.7 { SELECT a, b, sum(c) OVER (ORDER BY a,b GROUPS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW EXCLUDE CURRENT ROW) FROM t3 ORDER BY 1, 2, 3; } {AA aa 1373 AA aa 1396 AA aa 2068 AA aa 2084 AA bb 3815 AA bb 4058 AA bb 4113 AA bb 4376 BB aa 6796 BB aa 6898 BB aa 7146 BB aa 7159 BB aa 7165 BB aa 7311 BB bb 11185 BB bb 11233 BB bb 11239 BB bb 11314 BB bb 11320 BB bb 11392 CC aa 13220 CC aa 13372 CC aa 13549 CC aa 13821 CC bb 14325 CC bb 14801 DD aa 15627 DD aa 16216 DD aa 16248 DD bb 18220 DD bb 18385 DD bb 18463 DD bb 18941 EE aa 19292 EE aa 19956 EE bb 20950 EE bb 21089 EE bb 21466 FF aa 23211 FF aa 23214 FF aa 23263 FF aa 23673 FF bb 26448 FF bb 26516 FF bb 26660 FF bb 26812 FF bb 27091 FF bb 27284 GG aa 28349 GG aa 28503 GG aa 28648 GG aa 28835 GG bb 30916 GG bb 30925 GG bb 31010 GG bb 31694 HH aa 33124 HH aa 33313 HH aa 33623 HH bb 36334 HH bb 36567 HH bb 36614 HH bb 36942 HH bb 36967 HH bb 37164 II aa 37695 II aa 37949 II bb 40132 II bb 40266 II bb 40494 II bb 40516 II bb 40687 JJ aa 42052 JJ aa 42183 JJ aa 42717 JJ aa 42838 JJ bb 43898 JJ bb 44383 JJ bb 44401 JJ bb 44480} do_execsql_test 1.2.8 { SELECT a, b, sum(c) OVER (ORDER BY a GROUPS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW EXCLUDE CURRENT ROW), sum(c) OVER (ORDER BY a GROUPS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ), sum(c) OVER (ORDER BY a,b GROUPS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW EXCLUDE CURRENT ROW), sum(c) OVER (ORDER BY a,b GROUPS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ) FROM t3 ORDER BY 1, 2, 3; } {AA aa 3751 4685 1373 2307 AA aa 3774 4685 1396 2307 AA aa 4446 4685 2068 2307 AA aa 4462 4685 2084 2307 AA bb 3815 4685 3815 4685 AA bb 4058 4685 4058 4685 AA bb 4113 4685 4113 4685 AA bb 4376 4685 4376 4685 BB aa 11263 12025 6796 7558 BB aa 11365 12025 6898 7558 BB aa 11613 12025 7146 7558 BB aa 11626 12025 7159 7558 BB aa 11632 12025 7165 7558 BB aa 11778 12025 7311 7558 BB bb 11185 12025 11185 12025 BB bb 11233 12025 11233 12025 BB bb 11239 12025 11239 12025 BB bb 11314 12025 11314 12025 BB bb 11320 12025 11320 12025 BB bb 11392 12025 11392 12025 CC aa 14388 15147 13220 13979 CC aa 14540 15147 13372 13979 CC aa 14717 15147 13549 13979 CC aa 14989 15147 13821 13979 CC bb 14325 15147 14325 15147 CC bb 14801 15147 14801 15147 DD aa 18334 19179 15627 16472 DD aa 18923 19179 16216 16472 DD aa 18955 19179 16248 16472 DD bb 18220 19179 18220 19179 DD bb 18385 19179 18385 19179 DD bb 18463 19179 18463 19179 DD bb 18941 19179 18941 19179 EE aa 20941 21718 19292 20069 EE aa 21605 21718 19956 20069 EE bb 20950 21718 20950 21718 EE bb 21089 21718 21089 21718 EE bb 21466 21718 21466 21718 FF aa 26716 27386 23211 23881 FF aa 26719 27386 23214 23881 FF aa 26768 27386 23263 23881 FF aa 27178 27386 23673 23881 FF bb 26448 27386 26448 27386 FF bb 26516 27386 26516 27386 FF bb 26660 27386 26660 27386 FF bb 26812 27386 26812 27386 FF bb 27091 27386 27091 27386 FF bb 27284 27386 27284 27386 GG aa 31220 31854 28349 28983 GG aa 31374 31854 28503 28983 GG aa 31519 31854 28648 28983 GG aa 31706 31854 28835 28983 GG bb 30916 31854 30916 31854 GG bb 30925 31854 30925 31854 GG bb 31010 31854 31010 31854 GG bb 31694 31854 31694 31854 HH aa 36318 37297 33124 34103 HH aa 36507 37297 33313 34103 HH aa 36817 37297 33623 34103 HH bb 36334 37297 36334 37297 HH bb 36567 37297 36567 37297 HH bb 36614 37297 36614 37297 HH bb 36942 37297 36942 37297 HH bb 36967 37297 36967 37297 HH bb 37164 37297 37164 37297 II aa 40285 40937 37695 38347 II aa 40539 40937 37949 38347 II bb 40132 40937 40132 40937 II bb 40266 40937 40266 40937 II bb 40494 40937 40494 40937 II bb 40516 40937 40516 40937 II bb 40687 40937 40687 40937 JJ aa 43838 44737 42052 42951 JJ aa 43969 44737 42183 42951 JJ aa 44503 44737 42717 42951 JJ aa 44624 44737 42838 42951 JJ bb 43898 44737 43898 44737 JJ bb 44383 44737 44383 44737 JJ bb 44401 44737 44401 44737 JJ bb 44480 44737 44480 44737} do_execsql_test 1.3.1 { SELECT a, b, sum(c) OVER (ORDER BY a GROUPS BETWEEN UNBOUNDED PRECEDING AND 1 FOLLOWING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa 12025 AA aa 12025 AA aa 12025 AA aa 12025 AA bb 12025 AA bb 12025 AA bb 12025 AA bb 12025 BB aa 15147 BB aa 15147 BB aa 15147 BB aa 15147 BB aa 15147 BB aa 15147 BB bb 15147 BB bb 15147 BB bb 15147 BB bb 15147 BB bb 15147 BB bb 15147 CC aa 19179 CC aa 19179 CC aa 19179 CC aa 19179 CC bb 19179 CC bb 19179 DD aa 21718 DD aa 21718 DD aa 21718 DD bb 21718 DD bb 21718 DD bb 21718 DD bb 21718 EE aa 27386 EE aa 27386 EE bb 27386 EE bb 27386 EE bb 27386 FF aa 31854 FF aa 31854 FF aa 31854 FF aa 31854 FF bb 31854 FF bb 31854 FF bb 31854 FF bb 31854 FF bb 31854 FF bb 31854 GG aa 37297 GG aa 37297 GG aa 37297 GG aa 37297 GG bb 37297 GG bb 37297 GG bb 37297 GG bb 37297 HH aa 40937 HH aa 40937 HH aa 40937 HH bb 40937 HH bb 40937 HH bb 40937 HH bb 40937 HH bb 40937 HH bb 40937 II aa 44737 II aa 44737 II bb 44737 II bb 44737 II bb 44737 II bb 44737 II bb 44737 JJ aa 44737 JJ aa 44737 JJ aa 44737 JJ aa 44737 JJ bb 44737 JJ bb 44737 JJ bb 44737 JJ bb 44737} do_execsql_test 1.3.2 { SELECT a, b, sum(c) OVER (ORDER BY a,b GROUPS BETWEEN UNBOUNDED PRECEDING AND 1 FOLLOWING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa 4685 AA aa 4685 AA aa 4685 AA aa 4685 AA bb 7558 AA bb 7558 AA bb 7558 AA bb 7558 BB aa 12025 BB aa 12025 BB aa 12025 BB aa 12025 BB aa 12025 BB aa 12025 BB bb 13979 BB bb 13979 BB bb 13979 BB bb 13979 BB bb 13979 BB bb 13979 CC aa 15147 CC aa 15147 CC aa 15147 CC aa 15147 CC bb 16472 CC bb 16472 DD aa 19179 DD aa 19179 DD aa 19179 DD bb 20069 DD bb 20069 DD bb 20069 DD bb 20069 EE aa 21718 EE aa 21718 EE bb 23881 EE bb 23881 EE bb 23881 FF aa 27386 FF aa 27386 FF aa 27386 FF aa 27386 FF bb 28983 FF bb 28983 FF bb 28983 FF bb 28983 FF bb 28983 FF bb 28983 GG aa 31854 GG aa 31854 GG aa 31854 GG aa 31854 GG bb 34103 GG bb 34103 GG bb 34103 GG bb 34103 HH aa 37297 HH aa 37297 HH aa 37297 HH bb 38347 HH bb 38347 HH bb 38347 HH bb 38347 HH bb 38347 HH bb 38347 II aa 40937 II aa 40937 II bb 42951 II bb 42951 II bb 42951 II bb 42951 II bb 42951 JJ aa 44737 JJ aa 44737 JJ aa 44737 JJ aa 44737 JJ bb 44737 JJ bb 44737 JJ bb 44737 JJ bb 44737} do_execsql_test 1.3.3 { SELECT a, b, rank() OVER (ORDER BY a GROUPS BETWEEN UNBOUNDED PRECEDING AND 1 FOLLOWING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa 1 AA aa 1 AA aa 1 AA aa 1 AA bb 1 AA bb 1 AA bb 1 AA bb 1 BB aa 9 BB aa 9 BB aa 9 BB aa 9 BB aa 9 BB aa 9 BB bb 9 BB bb 9 BB bb 9 BB bb 9 BB bb 9 BB bb 9 CC aa 21 CC aa 21 CC aa 21 CC aa 21 CC bb 21 CC bb 21 DD aa 27 DD aa 27 DD aa 27 DD bb 27 DD bb 27 DD bb 27 DD bb 27 EE aa 34 EE aa 34 EE bb 34 EE bb 34 EE bb 34 FF aa 39 FF aa 39 FF aa 39 FF aa 39 FF bb 39 FF bb 39 FF bb 39 FF bb 39 FF bb 39 FF bb 39 GG aa 49 GG aa 49 GG aa 49 GG aa 49 GG bb 49 GG bb 49 GG bb 49 GG bb 49 HH aa 57 HH aa 57 HH aa 57 HH bb 57 HH bb 57 HH bb 57 HH bb 57 HH bb 57 HH bb 57 II aa 66 II aa 66 II bb 66 II bb 66 II bb 66 II bb 66 II bb 66 JJ aa 73 JJ aa 73 JJ aa 73 JJ aa 73 JJ bb 73 JJ bb 73 JJ bb 73 JJ bb 73} do_execsql_test 1.3.4 { SELECT a, b, max(c) OVER (ORDER BY a,b GROUPS BETWEEN UNBOUNDED PRECEDING AND 1 FOLLOWING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa 934 AA aa 934 AA aa 934 AA aa 934 AA bb 934 AA bb 934 AA bb 934 AA bb 934 BB aa 934 BB aa 934 BB aa 934 BB aa 934 BB aa 934 BB aa 934 BB bb 934 BB bb 934 BB bb 934 BB bb 934 BB bb 934 BB bb 934 CC aa 934 CC aa 934 CC aa 934 CC aa 934 CC bb 934 CC bb 934 DD aa 959 DD aa 959 DD aa 959 DD bb 959 DD bb 959 DD bb 959 DD bb 959 EE aa 959 EE aa 959 EE bb 959 EE bb 959 EE bb 959 FF aa 959 FF aa 959 FF aa 959 FF aa 959 FF bb 959 FF bb 959 FF bb 959 FF bb 959 FF bb 959 FF bb 959 GG aa 959 GG aa 959 GG aa 959 GG aa 959 GG bb 979 GG bb 979 GG bb 979 GG bb 979 HH aa 979 HH aa 979 HH aa 979 HH bb 979 HH bb 979 HH bb 979 HH bb 979 HH bb 979 HH bb 979 II aa 979 II aa 979 II bb 979 II bb 979 II bb 979 II bb 979 II bb 979 JJ aa 979 JJ aa 979 JJ aa 979 JJ aa 979 JJ bb 979 JJ bb 979 JJ bb 979 JJ bb 979} do_execsql_test 1.3.5 { SELECT a, b, min(c) OVER (ORDER BY a,b GROUPS BETWEEN UNBOUNDED PRECEDING AND 1 FOLLOWING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa 223 AA aa 223 AA aa 223 AA aa 223 AA bb 223 AA bb 223 AA bb 223 AA bb 223 BB aa 223 BB aa 223 BB aa 223 BB aa 223 BB aa 223 BB aa 223 BB bb 158 BB bb 158 BB bb 158 BB bb 158 BB bb 158 BB bb 158 CC aa 158 CC aa 158 CC aa 158 CC aa 158 CC bb 158 CC bb 158 DD aa 158 DD aa 158 DD aa 158 DD bb 113 DD bb 113 DD bb 113 DD bb 113 EE aa 113 EE aa 113 EE bb 113 EE bb 113 EE bb 113 FF aa 102 FF aa 102 FF aa 102 FF aa 102 FF bb 102 FF bb 102 FF bb 102 FF bb 102 FF bb 102 FF bb 102 GG aa 102 GG aa 102 GG aa 102 GG aa 102 GG bb 102 GG bb 102 GG bb 102 GG bb 102 HH aa 102 HH aa 102 HH aa 102 HH bb 102 HH bb 102 HH bb 102 HH bb 102 HH bb 102 HH bb 102 II aa 102 II aa 102 II bb 102 II bb 102 II bb 102 II bb 102 II bb 102 JJ aa 102 JJ aa 102 JJ aa 102 JJ aa 102 JJ bb 102 JJ bb 102 JJ bb 102 JJ bb 102} do_execsql_test 1.3.6 { SELECT a, b, sum(c) OVER (ORDER BY a GROUPS BETWEEN UNBOUNDED PRECEDING AND 1 FOLLOWING EXCLUDE CURRENT ROW) FROM t3 ORDER BY 1, 2, 3; } {AA aa 11091 AA aa 11114 AA aa 11786 AA aa 11802 AA bb 11155 AA bb 11398 AA bb 11453 AA bb 11716 BB aa 14385 BB aa 14487 BB aa 14735 BB aa 14748 BB aa 14754 BB aa 14900 BB bb 14307 BB bb 14355 BB bb 14361 BB bb 14436 BB bb 14442 BB bb 14514 CC aa 18420 CC aa 18572 CC aa 18749 CC aa 19021 CC bb 18357 CC bb 18833 DD aa 20873 DD aa 21462 DD aa 21494 DD bb 20759 DD bb 20924 DD bb 21002 DD bb 21480 EE aa 26609 EE aa 27273 EE bb 26618 EE bb 26757 EE bb 27134 FF aa 31184 FF aa 31187 FF aa 31236 FF aa 31646 FF bb 30916 FF bb 30984 FF bb 31128 FF bb 31280 FF bb 31559 FF bb 31752 GG aa 36663 GG aa 36817 GG aa 36962 GG aa 37149 GG bb 36359 GG bb 36368 GG bb 36453 GG bb 37137 HH aa 39958 HH aa 40147 HH aa 40457 HH bb 39974 HH bb 40207 HH bb 40254 HH bb 40582 HH bb 40607 HH bb 40804 II aa 44085 II aa 44339 II bb 43932 II bb 44066 II bb 44294 II bb 44316 II bb 44487 JJ aa 43838 JJ aa 43969 JJ aa 44503 JJ aa 44624 JJ bb 43898 JJ bb 44383 JJ bb 44401 JJ bb 44480} do_execsql_test 1.3.7 { SELECT a, b, sum(c) OVER (ORDER BY a,b GROUPS BETWEEN UNBOUNDED PRECEDING AND 1 FOLLOWING EXCLUDE CURRENT ROW) FROM t3 ORDER BY 1, 2, 3; } {AA aa 3751 AA aa 3774 AA aa 4446 AA aa 4462 AA bb 6688 AA bb 6931 AA bb 6986 AA bb 7249 BB aa 11263 BB aa 11365 BB aa 11613 BB aa 11626 BB aa 11632 BB aa 11778 BB bb 13139 BB bb 13187 BB bb 13193 BB bb 13268 BB bb 13274 BB bb 13346 CC aa 14388 CC aa 14540 CC aa 14717 CC aa 14989 CC bb 15650 CC bb 16126 DD aa 18334 DD aa 18923 DD aa 18955 DD bb 19110 DD bb 19275 DD bb 19353 DD bb 19831 EE aa 20941 EE aa 21605 EE bb 23113 EE bb 23252 EE bb 23629 FF aa 26716 FF aa 26719 FF aa 26768 FF aa 27178 FF bb 28045 FF bb 28113 FF bb 28257 FF bb 28409 FF bb 28688 FF bb 28881 GG aa 31220 GG aa 31374 GG aa 31519 GG aa 31706 GG bb 33165 GG bb 33174 GG bb 33259 GG bb 33943 HH aa 36318 HH aa 36507 HH aa 36817 HH bb 37384 HH bb 37617 HH bb 37664 HH bb 37992 HH bb 38017 HH bb 38214 II aa 40285 II aa 40539 II bb 42146 II bb 42280 II bb 42508 II bb 42530 II bb 42701 JJ aa 43838 JJ aa 43969 JJ aa 44503 JJ aa 44624 JJ bb 43898 JJ bb 44383 JJ bb 44401 JJ bb 44480} do_execsql_test 1.3.8 { SELECT a, b, sum(c) OVER (ORDER BY a GROUPS BETWEEN UNBOUNDED PRECEDING AND 1 FOLLOWING EXCLUDE CURRENT ROW), sum(c) OVER (ORDER BY a GROUPS BETWEEN UNBOUNDED PRECEDING AND 1 FOLLOWING ), sum(c) OVER (ORDER BY a,b GROUPS BETWEEN UNBOUNDED PRECEDING AND 1 FOLLOWING EXCLUDE CURRENT ROW), sum(c) OVER (ORDER BY a,b GROUPS BETWEEN UNBOUNDED PRECEDING AND 1 FOLLOWING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa 11091 12025 3751 4685 AA aa 11114 12025 3774 4685 AA aa 11786 12025 4446 4685 AA aa 11802 12025 4462 4685 AA bb 11155 12025 6688 7558 AA bb 11398 12025 6931 7558 AA bb 11453 12025 6986 7558 AA bb 11716 12025 7249 7558 BB aa 14385 15147 11263 12025 BB aa 14487 15147 11365 12025 BB aa 14735 15147 11613 12025 BB aa 14748 15147 11626 12025 BB aa 14754 15147 11632 12025 BB aa 14900 15147 11778 12025 BB bb 14307 15147 13139 13979 BB bb 14355 15147 13187 13979 BB bb 14361 15147 13193 13979 BB bb 14436 15147 13268 13979 BB bb 14442 15147 13274 13979 BB bb 14514 15147 13346 13979 CC aa 18420 19179 14388 15147 CC aa 18572 19179 14540 15147 CC aa 18749 19179 14717 15147 CC aa 19021 19179 14989 15147 CC bb 18357 19179 15650 16472 CC bb 18833 19179 16126 16472 DD aa 20873 21718 18334 19179 DD aa 21462 21718 18923 19179 DD aa 21494 21718 18955 19179 DD bb 20759 21718 19110 20069 DD bb 20924 21718 19275 20069 DD bb 21002 21718 19353 20069 DD bb 21480 21718 19831 20069 EE aa 26609 27386 20941 21718 EE aa 27273 27386 21605 21718 EE bb 26618 27386 23113 23881 EE bb 26757 27386 23252 23881 EE bb 27134 27386 23629 23881 FF aa 31184 31854 26716 27386 FF aa 31187 31854 26719 27386 FF aa 31236 31854 26768 27386 FF aa 31646 31854 27178 27386 FF bb 30916 31854 28045 28983 FF bb 30984 31854 28113 28983 FF bb 31128 31854 28257 28983 FF bb 31280 31854 28409 28983 FF bb 31559 31854 28688 28983 FF bb 31752 31854 28881 28983 GG aa 36663 37297 31220 31854 GG aa 36817 37297 31374 31854 GG aa 36962 37297 31519 31854 GG aa 37149 37297 31706 31854 GG bb 36359 37297 33165 34103 GG bb 36368 37297 33174 34103 GG bb 36453 37297 33259 34103 GG bb 37137 37297 33943 34103 HH aa 39958 40937 36318 37297 HH aa 40147 40937 36507 37297 HH aa 40457 40937 36817 37297 HH bb 39974 40937 37384 38347 HH bb 40207 40937 37617 38347 HH bb 40254 40937 37664 38347 HH bb 40582 40937 37992 38347 HH bb 40607 40937 38017 38347 HH bb 40804 40937 38214 38347 II aa 44085 44737 40285 40937 II aa 44339 44737 40539 40937 II bb 43932 44737 42146 42951 II bb 44066 44737 42280 42951 II bb 44294 44737 42508 42951 II bb 44316 44737 42530 42951 II bb 44487 44737 42701 42951 JJ aa 43838 44737 43838 44737 JJ aa 43969 44737 43969 44737 JJ aa 44503 44737 44503 44737 JJ aa 44624 44737 44624 44737 JJ bb 43898 44737 43898 44737 JJ bb 44383 44737 44383 44737 JJ bb 44401 44737 44401 44737 JJ bb 44480 44737 44480 44737} do_execsql_test 1.4.1 { SELECT a, b, sum(c) OVER (ORDER BY a GROUPS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa 44737 AA aa 44737 AA aa 44737 AA aa 44737 AA bb 44737 AA bb 44737 AA bb 44737 AA bb 44737 BB aa 44737 BB aa 44737 BB aa 44737 BB aa 44737 BB aa 44737 BB aa 44737 BB bb 44737 BB bb 44737 BB bb 44737 BB bb 44737 BB bb 44737 BB bb 44737 CC aa 44737 CC aa 44737 CC aa 44737 CC aa 44737 CC bb 44737 CC bb 44737 DD aa 44737 DD aa 44737 DD aa 44737 DD bb 44737 DD bb 44737 DD bb 44737 DD bb 44737 EE aa 44737 EE aa 44737 EE bb 44737 EE bb 44737 EE bb 44737 FF aa 44737 FF aa 44737 FF aa 44737 FF aa 44737 FF bb 44737 FF bb 44737 FF bb 44737 FF bb 44737 FF bb 44737 FF bb 44737 GG aa 44737 GG aa 44737 GG aa 44737 GG aa 44737 GG bb 44737 GG bb 44737 GG bb 44737 GG bb 44737 HH aa 44737 HH aa 44737 HH aa 44737 HH bb 44737 HH bb 44737 HH bb 44737 HH bb 44737 HH bb 44737 HH bb 44737 II aa 44737 II aa 44737 II bb 44737 II bb 44737 II bb 44737 II bb 44737 II bb 44737 JJ aa 44737 JJ aa 44737 JJ aa 44737 JJ aa 44737 JJ bb 44737 JJ bb 44737 JJ bb 44737 JJ bb 44737} do_execsql_test 1.4.2 { SELECT a, b, sum(c) OVER (ORDER BY a,b GROUPS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa 44737 AA aa 44737 AA aa 44737 AA aa 44737 AA bb 44737 AA bb 44737 AA bb 44737 AA bb 44737 BB aa 44737 BB aa 44737 BB aa 44737 BB aa 44737 BB aa 44737 BB aa 44737 BB bb 44737 BB bb 44737 BB bb 44737 BB bb 44737 BB bb 44737 BB bb 44737 CC aa 44737 CC aa 44737 CC aa 44737 CC aa 44737 CC bb 44737 CC bb 44737 DD aa 44737 DD aa 44737 DD aa 44737 DD bb 44737 DD bb 44737 DD bb 44737 DD bb 44737 EE aa 44737 EE aa 44737 EE bb 44737 EE bb 44737 EE bb 44737 FF aa 44737 FF aa 44737 FF aa 44737 FF aa 44737 FF bb 44737 FF bb 44737 FF bb 44737 FF bb 44737 FF bb 44737 FF bb 44737 GG aa 44737 GG aa 44737 GG aa 44737 GG aa 44737 GG bb 44737 GG bb 44737 GG bb 44737 GG bb 44737 HH aa 44737 HH aa 44737 HH aa 44737 HH bb 44737 HH bb 44737 HH bb 44737 HH bb 44737 HH bb 44737 HH bb 44737 II aa 44737 II aa 44737 II bb 44737 II bb 44737 II bb 44737 II bb 44737 II bb 44737 JJ aa 44737 JJ aa 44737 JJ aa 44737 JJ aa 44737 JJ bb 44737 JJ bb 44737 JJ bb 44737 JJ bb 44737} do_execsql_test 1.4.3 { SELECT a, b, rank() OVER (ORDER BY a GROUPS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa 1 AA aa 1 AA aa 1 AA aa 1 AA bb 1 AA bb 1 AA bb 1 AA bb 1 BB aa 9 BB aa 9 BB aa 9 BB aa 9 BB aa 9 BB aa 9 BB bb 9 BB bb 9 BB bb 9 BB bb 9 BB bb 9 BB bb 9 CC aa 21 CC aa 21 CC aa 21 CC aa 21 CC bb 21 CC bb 21 DD aa 27 DD aa 27 DD aa 27 DD bb 27 DD bb 27 DD bb 27 DD bb 27 EE aa 34 EE aa 34 EE bb 34 EE bb 34 EE bb 34 FF aa 39 FF aa 39 FF aa 39 FF aa 39 FF bb 39 FF bb 39 FF bb 39 FF bb 39 FF bb 39 FF bb 39 GG aa 49 GG aa 49 GG aa 49 GG aa 49 GG bb 49 GG bb 49 GG bb 49 GG bb 49 HH aa 57 HH aa 57 HH aa 57 HH bb 57 HH bb 57 HH bb 57 HH bb 57 HH bb 57 HH bb 57 II aa 66 II aa 66 II bb 66 II bb 66 II bb 66 II bb 66 II bb 66 JJ aa 73 JJ aa 73 JJ aa 73 JJ aa 73 JJ bb 73 JJ bb 73 JJ bb 73 JJ bb 73} do_execsql_test 1.4.4 { SELECT a, b, max(c) OVER (ORDER BY a,b GROUPS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa 979 AA aa 979 AA aa 979 AA aa 979 AA bb 979 AA bb 979 AA bb 979 AA bb 979 BB aa 979 BB aa 979 BB aa 979 BB aa 979 BB aa 979 BB aa 979 BB bb 979 BB bb 979 BB bb 979 BB bb 979 BB bb 979 BB bb 979 CC aa 979 CC aa 979 CC aa 979 CC aa 979 CC bb 979 CC bb 979 DD aa 979 DD aa 979 DD aa 979 DD bb 979 DD bb 979 DD bb 979 DD bb 979 EE aa 979 EE aa 979 EE bb 979 EE bb 979 EE bb 979 FF aa 979 FF aa 979 FF aa 979 FF aa 979 FF bb 979 FF bb 979 FF bb 979 FF bb 979 FF bb 979 FF bb 979 GG aa 979 GG aa 979 GG aa 979 GG aa 979 GG bb 979 GG bb 979 GG bb 979 GG bb 979 HH aa 979 HH aa 979 HH aa 979 HH bb 979 HH bb 979 HH bb 979 HH bb 979 HH bb 979 HH bb 979 II aa 979 II aa 979 II bb 979 II bb 979 II bb 979 II bb 979 II bb 979 JJ aa 979 JJ aa 979 JJ aa 979 JJ aa 979 JJ bb 979 JJ bb 979 JJ bb 979 JJ bb 979} do_execsql_test 1.4.5 { SELECT a, b, min(c) OVER (ORDER BY a,b GROUPS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa 102 AA aa 102 AA aa 102 AA aa 102 AA bb 102 AA bb 102 AA bb 102 AA bb 102 BB aa 102 BB aa 102 BB aa 102 BB aa 102 BB aa 102 BB aa 102 BB bb 102 BB bb 102 BB bb 102 BB bb 102 BB bb 102 BB bb 102 CC aa 102 CC aa 102 CC aa 102 CC aa 102 CC bb 102 CC bb 102 DD aa 102 DD aa 102 DD aa 102 DD bb 102 DD bb 102 DD bb 102 DD bb 102 EE aa 102 EE aa 102 EE bb 102 EE bb 102 EE bb 102 FF aa 102 FF aa 102 FF aa 102 FF aa 102 FF bb 102 FF bb 102 FF bb 102 FF bb 102 FF bb 102 FF bb 102 GG aa 102 GG aa 102 GG aa 102 GG aa 102 GG bb 102 GG bb 102 GG bb 102 GG bb 102 HH aa 102 HH aa 102 HH aa 102 HH bb 102 HH bb 102 HH bb 102 HH bb 102 HH bb 102 HH bb 102 II aa 102 II aa 102 II bb 102 II bb 102 II bb 102 II bb 102 II bb 102 JJ aa 102 JJ aa 102 JJ aa 102 JJ aa 102 JJ bb 102 JJ bb 102 JJ bb 102 JJ bb 102} do_execsql_test 1.4.6 { SELECT a, b, sum(c) OVER (ORDER BY a GROUPS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING EXCLUDE CURRENT ROW) FROM t3 ORDER BY 1, 2, 3; } {AA aa 43803 AA aa 43826 AA aa 44498 AA aa 44514 AA bb 43867 AA bb 44110 AA bb 44165 AA bb 44428 BB aa 43975 BB aa 44077 BB aa 44325 BB aa 44338 BB aa 44344 BB aa 44490 BB bb 43897 BB bb 43945 BB bb 43951 BB bb 44026 BB bb 44032 BB bb 44104 CC aa 43978 CC aa 44130 CC aa 44307 CC aa 44579 CC bb 43915 CC bb 44391 DD aa 43892 DD aa 44481 DD aa 44513 DD bb 43778 DD bb 43943 DD bb 44021 DD bb 44499 EE aa 43960 EE aa 44624 EE bb 43969 EE bb 44108 EE bb 44485 FF aa 44067 FF aa 44070 FF aa 44119 FF aa 44529 FF bb 43799 FF bb 43867 FF bb 44011 FF bb 44163 FF bb 44442 FF bb 44635 GG aa 44103 GG aa 44257 GG aa 44402 GG aa 44589 GG bb 43799 GG bb 43808 GG bb 43893 GG bb 44577 HH aa 43758 HH aa 43947 HH aa 44257 HH bb 43774 HH bb 44007 HH bb 44054 HH bb 44382 HH bb 44407 HH bb 44604 II aa 44085 II aa 44339 II bb 43932 II bb 44066 II bb 44294 II bb 44316 II bb 44487 JJ aa 43838 JJ aa 43969 JJ aa 44503 JJ aa 44624 JJ bb 43898 JJ bb 44383 JJ bb 44401 JJ bb 44480} do_execsql_test 1.4.7 { SELECT a, b, sum(c) OVER (ORDER BY a,b GROUPS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING EXCLUDE CURRENT ROW) FROM t3 ORDER BY 1, 2, 3; } {AA aa 43803 AA aa 43826 AA aa 44498 AA aa 44514 AA bb 43867 AA bb 44110 AA bb 44165 AA bb 44428 BB aa 43975 BB aa 44077 BB aa 44325 BB aa 44338 BB aa 44344 BB aa 44490 BB bb 43897 BB bb 43945 BB bb 43951 BB bb 44026 BB bb 44032 BB bb 44104 CC aa 43978 CC aa 44130 CC aa 44307 CC aa 44579 CC bb 43915 CC bb 44391 DD aa 43892 DD aa 44481 DD aa 44513 DD bb 43778 DD bb 43943 DD bb 44021 DD bb 44499 EE aa 43960 EE aa 44624 EE bb 43969 EE bb 44108 EE bb 44485 FF aa 44067 FF aa 44070 FF aa 44119 FF aa 44529 FF bb 43799 FF bb 43867 FF bb 44011 FF bb 44163 FF bb 44442 FF bb 44635 GG aa 44103 GG aa 44257 GG aa 44402 GG aa 44589 GG bb 43799 GG bb 43808 GG bb 43893 GG bb 44577 HH aa 43758 HH aa 43947 HH aa 44257 HH bb 43774 HH bb 44007 HH bb 44054 HH bb 44382 HH bb 44407 HH bb 44604 II aa 44085 II aa 44339 II bb 43932 II bb 44066 II bb 44294 II bb 44316 II bb 44487 JJ aa 43838 JJ aa 43969 JJ aa 44503 JJ aa 44624 JJ bb 43898 JJ bb 44383 JJ bb 44401 JJ bb 44480} do_execsql_test 1.4.8 { SELECT a, b, sum(c) OVER (ORDER BY a GROUPS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING EXCLUDE CURRENT ROW), sum(c) OVER (ORDER BY a GROUPS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING ), sum(c) OVER (ORDER BY a,b GROUPS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING EXCLUDE CURRENT ROW), sum(c) OVER (ORDER BY a,b GROUPS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa 43803 44737 43803 44737 AA aa 43826 44737 43826 44737 AA aa 44498 44737 44498 44737 AA aa 44514 44737 44514 44737 AA bb 43867 44737 43867 44737 AA bb 44110 44737 44110 44737 AA bb 44165 44737 44165 44737 AA bb 44428 44737 44428 44737 BB aa 43975 44737 43975 44737 BB aa 44077 44737 44077 44737 BB aa 44325 44737 44325 44737 BB aa 44338 44737 44338 44737 BB aa 44344 44737 44344 44737 BB aa 44490 44737 44490 44737 BB bb 43897 44737 43897 44737 BB bb 43945 44737 43945 44737 BB bb 43951 44737 43951 44737 BB bb 44026 44737 44026 44737 BB bb 44032 44737 44032 44737 BB bb 44104 44737 44104 44737 CC aa 43978 44737 43978 44737 CC aa 44130 44737 44130 44737 CC aa 44307 44737 44307 44737 CC aa 44579 44737 44579 44737 CC bb 43915 44737 43915 44737 CC bb 44391 44737 44391 44737 DD aa 43892 44737 43892 44737 DD aa 44481 44737 44481 44737 DD aa 44513 44737 44513 44737 DD bb 43778 44737 43778 44737 DD bb 43943 44737 43943 44737 DD bb 44021 44737 44021 44737 DD bb 44499 44737 44499 44737 EE aa 43960 44737 43960 44737 EE aa 44624 44737 44624 44737 EE bb 43969 44737 43969 44737 EE bb 44108 44737 44108 44737 EE bb 44485 44737 44485 44737 FF aa 44067 44737 44067 44737 FF aa 44070 44737 44070 44737 FF aa 44119 44737 44119 44737 FF aa 44529 44737 44529 44737 FF bb 43799 44737 43799 44737 FF bb 43867 44737 43867 44737 FF bb 44011 44737 44011 44737 FF bb 44163 44737 44163 44737 FF bb 44442 44737 44442 44737 FF bb 44635 44737 44635 44737 GG aa 44103 44737 44103 44737 GG aa 44257 44737 44257 44737 GG aa 44402 44737 44402 44737 GG aa 44589 44737 44589 44737 GG bb 43799 44737 43799 44737 GG bb 43808 44737 43808 44737 GG bb 43893 44737 43893 44737 GG bb 44577 44737 44577 44737 HH aa 43758 44737 43758 44737 HH aa 43947 44737 43947 44737 HH aa 44257 44737 44257 44737 HH bb 43774 44737 43774 44737 HH bb 44007 44737 44007 44737 HH bb 44054 44737 44054 44737 HH bb 44382 44737 44382 44737 HH bb 44407 44737 44407 44737 HH bb 44604 44737 44604 44737 II aa 44085 44737 44085 44737 II aa 44339 44737 44339 44737 II bb 43932 44737 43932 44737 II bb 44066 44737 44066 44737 II bb 44294 44737 44294 44737 II bb 44316 44737 44316 44737 II bb 44487 44737 44487 44737 JJ aa 43838 44737 43838 44737 JJ aa 43969 44737 43969 44737 JJ aa 44503 44737 44503 44737 JJ aa 44624 44737 44624 44737 JJ bb 43898 44737 43898 44737 JJ bb 44383 44737 44383 44737 JJ bb 44401 44737 44401 44737 JJ bb 44480 44737 44480 44737} do_execsql_test 1.5.1 { SELECT a, b, sum(c) OVER (ORDER BY a GROUPS BETWEEN 1 PRECEDING AND 2 PRECEDING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa {} AA aa {} AA aa {} AA aa {} AA bb {} AA bb {} AA bb {} AA bb {} BB aa {} BB aa {} BB aa {} BB aa {} BB aa {} BB aa {} BB bb {} BB bb {} BB bb {} BB bb {} BB bb {} BB bb {} CC aa {} CC aa {} CC aa {} CC aa {} CC bb {} CC bb {} DD aa {} DD aa {} DD aa {} DD bb {} DD bb {} DD bb {} DD bb {} EE aa {} EE aa {} EE bb {} EE bb {} EE bb {} FF aa {} FF aa {} FF aa {} FF aa {} FF bb {} FF bb {} FF bb {} FF bb {} FF bb {} FF bb {} GG aa {} GG aa {} GG aa {} GG aa {} GG bb {} GG bb {} GG bb {} GG bb {} HH aa {} HH aa {} HH aa {} HH bb {} HH bb {} HH bb {} HH bb {} HH bb {} HH bb {} II aa {} II aa {} II bb {} II bb {} II bb {} II bb {} II bb {} JJ aa {} JJ aa {} JJ aa {} JJ aa {} JJ bb {} JJ bb {} JJ bb {} JJ bb {}} do_execsql_test 1.5.2 { SELECT a, b, sum(c) OVER (ORDER BY a,b GROUPS BETWEEN 1 PRECEDING AND 2 PRECEDING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa {} AA aa {} AA aa {} AA aa {} AA bb {} AA bb {} AA bb {} AA bb {} BB aa {} BB aa {} BB aa {} BB aa {} BB aa {} BB aa {} BB bb {} BB bb {} BB bb {} BB bb {} BB bb {} BB bb {} CC aa {} CC aa {} CC aa {} CC aa {} CC bb {} CC bb {} DD aa {} DD aa {} DD aa {} DD bb {} DD bb {} DD bb {} DD bb {} EE aa {} EE aa {} EE bb {} EE bb {} EE bb {} FF aa {} FF aa {} FF aa {} FF aa {} FF bb {} FF bb {} FF bb {} FF bb {} FF bb {} FF bb {} GG aa {} GG aa {} GG aa {} GG aa {} GG bb {} GG bb {} GG bb {} GG bb {} HH aa {} HH aa {} HH aa {} HH bb {} HH bb {} HH bb {} HH bb {} HH bb {} HH bb {} II aa {} II aa {} II bb {} II bb {} II bb {} II bb {} II bb {} JJ aa {} JJ aa {} JJ aa {} JJ aa {} JJ bb {} JJ bb {} JJ bb {} JJ bb {}} do_execsql_test 1.5.3 { SELECT a, b, rank() OVER (ORDER BY a GROUPS BETWEEN 1 PRECEDING AND 2 PRECEDING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa 1 AA aa 1 AA aa 1 AA aa 1 AA bb 1 AA bb 1 AA bb 1 AA bb 1 BB aa 9 BB aa 9 BB aa 9 BB aa 9 BB aa 9 BB aa 9 BB bb 9 BB bb 9 BB bb 9 BB bb 9 BB bb 9 BB bb 9 CC aa 21 CC aa 21 CC aa 21 CC aa 21 CC bb 21 CC bb 21 DD aa 27 DD aa 27 DD aa 27 DD bb 27 DD bb 27 DD bb 27 DD bb 27 EE aa 34 EE aa 34 EE bb 34 EE bb 34 EE bb 34 FF aa 39 FF aa 39 FF aa 39 FF aa 39 FF bb 39 FF bb 39 FF bb 39 FF bb 39 FF bb 39 FF bb 39 GG aa 49 GG aa 49 GG aa 49 GG aa 49 GG bb 49 GG bb 49 GG bb 49 GG bb 49 HH aa 57 HH aa 57 HH aa 57 HH bb 57 HH bb 57 HH bb 57 HH bb 57 HH bb 57 HH bb 57 II aa 66 II aa 66 II bb 66 II bb 66 II bb 66 II bb 66 II bb 66 JJ aa 73 JJ aa 73 JJ aa 73 JJ aa 73 JJ bb 73 JJ bb 73 JJ bb 73 JJ bb 73} do_execsql_test 1.5.4 { SELECT a, b, max(c) OVER (ORDER BY a,b GROUPS BETWEEN 1 PRECEDING AND 2 PRECEDING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa {} AA aa {} AA aa {} AA aa {} AA bb {} AA bb {} AA bb {} AA bb {} BB aa {} BB aa {} BB aa {} BB aa {} BB aa {} BB aa {} BB bb {} BB bb {} BB bb {} BB bb {} BB bb {} BB bb {} CC aa {} CC aa {} CC aa {} CC aa {} CC bb {} CC bb {} DD aa {} DD aa {} DD aa {} DD bb {} DD bb {} DD bb {} DD bb {} EE aa {} EE aa {} EE bb {} EE bb {} EE bb {} FF aa {} FF aa {} FF aa {} FF aa {} FF bb {} FF bb {} FF bb {} FF bb {} FF bb {} FF bb {} GG aa {} GG aa {} GG aa {} GG aa {} GG bb {} GG bb {} GG bb {} GG bb {} HH aa {} HH aa {} HH aa {} HH bb {} HH bb {} HH bb {} HH bb {} HH bb {} HH bb {} II aa {} II aa {} II bb {} II bb {} II bb {} II bb {} II bb {} JJ aa {} JJ aa {} JJ aa {} JJ aa {} JJ bb {} JJ bb {} JJ bb {} JJ bb {}} do_execsql_test 1.5.5 { SELECT a, b, min(c) OVER (ORDER BY a,b GROUPS BETWEEN 1 PRECEDING AND 2 PRECEDING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa {} AA aa {} AA aa {} AA aa {} AA bb {} AA bb {} AA bb {} AA bb {} BB aa {} BB aa {} BB aa {} BB aa {} BB aa {} BB aa {} BB bb {} BB bb {} BB bb {} BB bb {} BB bb {} BB bb {} CC aa {} CC aa {} CC aa {} CC aa {} CC bb {} CC bb {} DD aa {} DD aa {} DD aa {} DD bb {} DD bb {} DD bb {} DD bb {} EE aa {} EE aa {} EE bb {} EE bb {} EE bb {} FF aa {} FF aa {} FF aa {} FF aa {} FF bb {} FF bb {} FF bb {} FF bb {} FF bb {} FF bb {} GG aa {} GG aa {} GG aa {} GG aa {} GG bb {} GG bb {} GG bb {} GG bb {} HH aa {} HH aa {} HH aa {} HH bb {} HH bb {} HH bb {} HH bb {} HH bb {} HH bb {} II aa {} II aa {} II bb {} II bb {} II bb {} II bb {} II bb {} JJ aa {} JJ aa {} JJ aa {} JJ aa {} JJ bb {} JJ bb {} JJ bb {} JJ bb {}} do_execsql_test 1.5.6 { SELECT a, b, sum(c) OVER (ORDER BY a GROUPS BETWEEN 1 PRECEDING AND 2 PRECEDING EXCLUDE CURRENT ROW) FROM t3 ORDER BY 1, 2, 3; } {AA aa {} AA aa {} AA aa {} AA aa {} AA bb {} AA bb {} AA bb {} AA bb {} BB aa {} BB aa {} BB aa {} BB aa {} BB aa {} BB aa {} BB bb {} BB bb {} BB bb {} BB bb {} BB bb {} BB bb {} CC aa {} CC aa {} CC aa {} CC aa {} CC bb {} CC bb {} DD aa {} DD aa {} DD aa {} DD bb {} DD bb {} DD bb {} DD bb {} EE aa {} EE aa {} EE bb {} EE bb {} EE bb {} FF aa {} FF aa {} FF aa {} FF aa {} FF bb {} FF bb {} FF bb {} FF bb {} FF bb {} FF bb {} GG aa {} GG aa {} GG aa {} GG aa {} GG bb {} GG bb {} GG bb {} GG bb {} HH aa {} HH aa {} HH aa {} HH bb {} HH bb {} HH bb {} HH bb {} HH bb {} HH bb {} II aa {} II aa {} II bb {} II bb {} II bb {} II bb {} II bb {} JJ aa {} JJ aa {} JJ aa {} JJ aa {} JJ bb {} JJ bb {} JJ bb {} JJ bb {}} do_execsql_test 1.5.7 { SELECT a, b, sum(c) OVER (ORDER BY a,b GROUPS BETWEEN 1 PRECEDING AND 2 PRECEDING EXCLUDE CURRENT ROW) FROM t3 ORDER BY 1, 2, 3; } {AA aa {} AA aa {} AA aa {} AA aa {} AA bb {} AA bb {} AA bb {} AA bb {} BB aa {} BB aa {} BB aa {} BB aa {} BB aa {} BB aa {} BB bb {} BB bb {} BB bb {} BB bb {} BB bb {} BB bb {} CC aa {} CC aa {} CC aa {} CC aa {} CC bb {} CC bb {} DD aa {} DD aa {} DD aa {} DD bb {} DD bb {} DD bb {} DD bb {} EE aa {} EE aa {} EE bb {} EE bb {} EE bb {} FF aa {} FF aa {} FF aa {} FF aa {} FF bb {} FF bb {} FF bb {} FF bb {} FF bb {} FF bb {} GG aa {} GG aa {} GG aa {} GG aa {} GG bb {} GG bb {} GG bb {} GG bb {} HH aa {} HH aa {} HH aa {} HH bb {} HH bb {} HH bb {} HH bb {} HH bb {} HH bb {} II aa {} II aa {} II bb {} II bb {} II bb {} II bb {} II bb {} JJ aa {} JJ aa {} JJ aa {} JJ aa {} JJ bb {} JJ bb {} JJ bb {} JJ bb {}} do_execsql_test 1.5.8 { SELECT a, b, sum(c) OVER (ORDER BY a GROUPS BETWEEN 1 PRECEDING AND 2 PRECEDING EXCLUDE CURRENT ROW), sum(c) OVER (ORDER BY a GROUPS BETWEEN 1 PRECEDING AND 2 PRECEDING ), sum(c) OVER (ORDER BY a,b GROUPS BETWEEN 1 PRECEDING AND 2 PRECEDING EXCLUDE CURRENT ROW), sum(c) OVER (ORDER BY a,b GROUPS BETWEEN 1 PRECEDING AND 2 PRECEDING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa {} {} {} {} AA aa {} {} {} {} AA aa {} {} {} {} AA aa {} {} {} {} AA bb {} {} {} {} AA bb {} {} {} {} AA bb {} {} {} {} AA bb {} {} {} {} BB aa {} {} {} {} BB aa {} {} {} {} BB aa {} {} {} {} BB aa {} {} {} {} BB aa {} {} {} {} BB aa {} {} {} {} BB bb {} {} {} {} BB bb {} {} {} {} BB bb {} {} {} {} BB bb {} {} {} {} BB bb {} {} {} {} BB bb {} {} {} {} CC aa {} {} {} {} CC aa {} {} {} {} CC aa {} {} {} {} CC aa {} {} {} {} CC bb {} {} {} {} CC bb {} {} {} {} DD aa {} {} {} {} DD aa {} {} {} {} DD aa {} {} {} {} DD bb {} {} {} {} DD bb {} {} {} {} DD bb {} {} {} {} DD bb {} {} {} {} EE aa {} {} {} {} EE aa {} {} {} {} EE bb {} {} {} {} EE bb {} {} {} {} EE bb {} {} {} {} FF aa {} {} {} {} FF aa {} {} {} {} FF aa {} {} {} {} FF aa {} {} {} {} FF bb {} {} {} {} FF bb {} {} {} {} FF bb {} {} {} {} FF bb {} {} {} {} FF bb {} {} {} {} FF bb {} {} {} {} GG aa {} {} {} {} GG aa {} {} {} {} GG aa {} {} {} {} GG aa {} {} {} {} GG bb {} {} {} {} GG bb {} {} {} {} GG bb {} {} {} {} GG bb {} {} {} {} HH aa {} {} {} {} HH aa {} {} {} {} HH aa {} {} {} {} HH bb {} {} {} {} HH bb {} {} {} {} HH bb {} {} {} {} HH bb {} {} {} {} HH bb {} {} {} {} HH bb {} {} {} {} II aa {} {} {} {} II aa {} {} {} {} II bb {} {} {} {} II bb {} {} {} {} II bb {} {} {} {} II bb {} {} {} {} II bb {} {} {} {} JJ aa {} {} {} {} JJ aa {} {} {} {} JJ aa {} {} {} {} JJ aa {} {} {} {} JJ bb {} {} {} {} JJ bb {} {} {} {} JJ bb {} {} {} {} JJ bb {} {} {} {}} do_execsql_test 1.6.1 { SELECT a, b, sum(c) OVER (ORDER BY a GROUPS BETWEEN 2 PRECEDING AND 1 PRECEDING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa {} AA aa {} AA aa {} AA aa {} AA bb {} AA bb {} AA bb {} AA bb {} BB aa 4685 BB aa 4685 BB aa 4685 BB aa 4685 BB aa 4685 BB aa 4685 BB bb 4685 BB bb 4685 BB bb 4685 BB bb 4685 BB bb 4685 BB bb 4685 CC aa 12025 CC aa 12025 CC aa 12025 CC aa 12025 CC bb 12025 CC bb 12025 DD aa 10462 DD aa 10462 DD aa 10462 DD bb 10462 DD bb 10462 DD bb 10462 DD bb 10462 EE aa 7154 EE aa 7154 EE bb 7154 EE bb 7154 EE bb 7154 FF aa 6571 FF aa 6571 FF aa 6571 FF aa 6571 FF bb 6571 FF bb 6571 FF bb 6571 FF bb 6571 FF bb 6571 FF bb 6571 GG aa 8207 GG aa 8207 GG aa 8207 GG aa 8207 GG bb 8207 GG bb 8207 GG bb 8207 GG bb 8207 HH aa 10136 HH aa 10136 HH aa 10136 HH bb 10136 HH bb 10136 HH bb 10136 HH bb 10136 HH bb 10136 HH bb 10136 II aa 9911 II aa 9911 II bb 9911 II bb 9911 II bb 9911 II bb 9911 II bb 9911 JJ aa 9083 JJ aa 9083 JJ aa 9083 JJ aa 9083 JJ bb 9083 JJ bb 9083 JJ bb 9083 JJ bb 9083} do_execsql_test 1.6.2 { SELECT a, b, sum(c) OVER (ORDER BY a,b GROUPS BETWEEN 2 PRECEDING AND 1 PRECEDING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa {} AA aa {} AA aa {} AA aa {} AA bb 2307 AA bb 2307 AA bb 2307 AA bb 2307 BB aa 4685 BB aa 4685 BB aa 4685 BB aa 4685 BB aa 4685 BB aa 4685 BB bb 5251 BB bb 5251 BB bb 5251 BB bb 5251 BB bb 5251 BB bb 5251 CC aa 7340 CC aa 7340 CC aa 7340 CC aa 7340 CC bb 6421 CC bb 6421 DD aa 3122 DD aa 3122 DD aa 3122 DD bb 2493 DD bb 2493 DD bb 2493 DD bb 2493 EE aa 4032 EE aa 4032 EE bb 3597 EE bb 3597 EE bb 3597 FF aa 2539 FF aa 2539 FF aa 2539 FF aa 2539 FF bb 3812 FF bb 3812 FF bb 3812 FF bb 3812 FF bb 3812 FF bb 3812 GG aa 5668 GG aa 5668 GG aa 5668 GG aa 5668 GG bb 5102 GG bb 5102 GG bb 5102 GG bb 5102 HH aa 4468 HH aa 4468 HH aa 4468 HH bb 5120 HH bb 5120 HH bb 5120 HH bb 5120 HH bb 5120 HH bb 5120 II aa 5443 II aa 5443 II bb 4244 II bb 4244 II bb 4244 II bb 4244 II bb 4244 JJ aa 3640 JJ aa 3640 JJ aa 3640 JJ aa 3640 JJ bb 4604 JJ bb 4604 JJ bb 4604 JJ bb 4604} do_execsql_test 1.6.3 { SELECT a, b, rank() OVER (ORDER BY a GROUPS BETWEEN 2 PRECEDING AND 1 PRECEDING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa 1 AA aa 1 AA aa 1 AA aa 1 AA bb 1 AA bb 1 AA bb 1 AA bb 1 BB aa 9 BB aa 9 BB aa 9 BB aa 9 BB aa 9 BB aa 9 BB bb 9 BB bb 9 BB bb 9 BB bb 9 BB bb 9 BB bb 9 CC aa 21 CC aa 21 CC aa 21 CC aa 21 CC bb 21 CC bb 21 DD aa 27 DD aa 27 DD aa 27 DD bb 27 DD bb 27 DD bb 27 DD bb 27 EE aa 34 EE aa 34 EE bb 34 EE bb 34 EE bb 34 FF aa 39 FF aa 39 FF aa 39 FF aa 39 FF bb 39 FF bb 39 FF bb 39 FF bb 39 FF bb 39 FF bb 39 GG aa 49 GG aa 49 GG aa 49 GG aa 49 GG bb 49 GG bb 49 GG bb 49 GG bb 49 HH aa 57 HH aa 57 HH aa 57 HH bb 57 HH bb 57 HH bb 57 HH bb 57 HH bb 57 HH bb 57 II aa 66 II aa 66 II bb 66 II bb 66 II bb 66 II bb 66 II bb 66 JJ aa 73 JJ aa 73 JJ aa 73 JJ aa 73 JJ bb 73 JJ bb 73 JJ bb 73 JJ bb 73} do_execsql_test 1.6.4 { SELECT a, b, max(c) OVER (ORDER BY a,b GROUPS BETWEEN 2 PRECEDING AND 1 PRECEDING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa {} AA aa {} AA aa {} AA aa {} AA bb 934 AA bb 934 AA bb 934 AA bb 934 BB aa 934 BB aa 934 BB aa 934 BB aa 934 BB aa 934 BB aa 934 BB bb 870 BB bb 870 BB bb 870 BB bb 870 BB bb 870 BB bb 870 CC aa 840 CC aa 840 CC aa 840 CC aa 840 CC bb 840 CC bb 840 DD aa 822 DD aa 822 DD aa 822 DD bb 845 DD bb 845 DD bb 845 DD bb 845 EE aa 959 EE aa 959 EE bb 959 EE bb 959 EE bb 959 FF aa 777 FF aa 777 FF aa 777 FF aa 777 FF bb 768 FF bb 768 FF bb 768 FF bb 768 FF bb 768 FF bb 768 GG aa 938 GG aa 938 GG aa 938 GG aa 938 GG bb 938 GG bb 938 GG bb 938 GG bb 938 HH aa 938 HH aa 938 HH aa 938 HH bb 979 HH bb 979 HH bb 979 HH bb 979 HH bb 979 HH bb 979 II aa 979 II aa 979 II bb 963 II bb 963 II bb 963 II bb 963 II bb 963 JJ aa 805 JJ aa 805 JJ aa 805 JJ aa 805 JJ bb 899 JJ bb 899 JJ bb 899 JJ bb 899} do_execsql_test 1.6.5 { SELECT a, b, min(c) OVER (ORDER BY a,b GROUPS BETWEEN 2 PRECEDING AND 1 PRECEDING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa {} AA aa {} AA aa {} AA aa {} AA bb 223 AA bb 223 AA bb 223 AA bb 223 BB aa 223 BB aa 223 BB aa 223 BB aa 223 BB aa 223 BB aa 223 BB bb 247 BB bb 247 BB bb 247 BB bb 247 BB bb 247 BB bb 247 CC aa 247 CC aa 247 CC aa 247 CC aa 247 CC bb 158 CC bb 158 DD aa 158 DD aa 158 DD aa 158 DD bb 224 DD bb 224 DD bb 224 DD bb 224 EE aa 224 EE aa 224 EE bb 113 EE bb 113 EE bb 113 FF aa 113 FF aa 113 FF aa 113 FF aa 113 FF bb 208 FF bb 208 FF bb 208 FF bb 208 FF bb 208 FF bb 208 GG aa 102 GG aa 102 GG aa 102 GG aa 102 GG bb 102 GG bb 102 GG bb 102 GG bb 102 HH aa 148 HH aa 148 HH aa 148 HH bb 160 HH bb 160 HH bb 160 HH bb 160 HH bb 160 HH bb 160 II aa 133 II aa 133 II bb 133 II bb 133 II bb 133 II bb 133 II bb 133 JJ aa 250 JJ aa 250 JJ aa 250 JJ aa 250 JJ bb 113 JJ bb 113 JJ bb 113 JJ bb 113} do_execsql_test 1.6.6 { SELECT a, b, sum(c) OVER (ORDER BY a GROUPS BETWEEN 2 PRECEDING AND 1 PRECEDING EXCLUDE CURRENT ROW) FROM t3 ORDER BY 1, 2, 3; } {AA aa {} AA aa {} AA aa {} AA aa {} AA bb {} AA bb {} AA bb {} AA bb {} BB aa 4685 BB aa 4685 BB aa 4685 BB aa 4685 BB aa 4685 BB aa 4685 BB bb 4685 BB bb 4685 BB bb 4685 BB bb 4685 BB bb 4685 BB bb 4685 CC aa 12025 CC aa 12025 CC aa 12025 CC aa 12025 CC bb 12025 CC bb 12025 DD aa 10462 DD aa 10462 DD aa 10462 DD bb 10462 DD bb 10462 DD bb 10462 DD bb 10462 EE aa 7154 EE aa 7154 EE bb 7154 EE bb 7154 EE bb 7154 FF aa 6571 FF aa 6571 FF aa 6571 FF aa 6571 FF bb 6571 FF bb 6571 FF bb 6571 FF bb 6571 FF bb 6571 FF bb 6571 GG aa 8207 GG aa 8207 GG aa 8207 GG aa 8207 GG bb 8207 GG bb 8207 GG bb 8207 GG bb 8207 HH aa 10136 HH aa 10136 HH aa 10136 HH bb 10136 HH bb 10136 HH bb 10136 HH bb 10136 HH bb 10136 HH bb 10136 II aa 9911 II aa 9911 II bb 9911 II bb 9911 II bb 9911 II bb 9911 II bb 9911 JJ aa 9083 JJ aa 9083 JJ aa 9083 JJ aa 9083 JJ bb 9083 JJ bb 9083 JJ bb 9083 JJ bb 9083} do_execsql_test 1.6.7 { SELECT a, b, sum(c) OVER (ORDER BY a,b GROUPS BETWEEN 2 PRECEDING AND 1 PRECEDING EXCLUDE CURRENT ROW) FROM t3 ORDER BY 1, 2, 3; } {AA aa {} AA aa {} AA aa {} AA aa {} AA bb 2307 AA bb 2307 AA bb 2307 AA bb 2307 BB aa 4685 BB aa 4685 BB aa 4685 BB aa 4685 BB aa 4685 BB aa 4685 BB bb 5251 BB bb 5251 BB bb 5251 BB bb 5251 BB bb 5251 BB bb 5251 CC aa 7340 CC aa 7340 CC aa 7340 CC aa 7340 CC bb 6421 CC bb 6421 DD aa 3122 DD aa 3122 DD aa 3122 DD bb 2493 DD bb 2493 DD bb 2493 DD bb 2493 EE aa 4032 EE aa 4032 EE bb 3597 EE bb 3597 EE bb 3597 FF aa 2539 FF aa 2539 FF aa 2539 FF aa 2539 FF bb 3812 FF bb 3812 FF bb 3812 FF bb 3812 FF bb 3812 FF bb 3812 GG aa 5668 GG aa 5668 GG aa 5668 GG aa 5668 GG bb 5102 GG bb 5102 GG bb 5102 GG bb 5102 HH aa 4468 HH aa 4468 HH aa 4468 HH bb 5120 HH bb 5120 HH bb 5120 HH bb 5120 HH bb 5120 HH bb 5120 II aa 5443 II aa 5443 II bb 4244 II bb 4244 II bb 4244 II bb 4244 II bb 4244 JJ aa 3640 JJ aa 3640 JJ aa 3640 JJ aa 3640 JJ bb 4604 JJ bb 4604 JJ bb 4604 JJ bb 4604} do_execsql_test 1.6.8 { SELECT a, b, sum(c) OVER (ORDER BY a GROUPS BETWEEN 2 PRECEDING AND 1 PRECEDING EXCLUDE CURRENT ROW), sum(c) OVER (ORDER BY a GROUPS BETWEEN 2 PRECEDING AND 1 PRECEDING ), sum(c) OVER (ORDER BY a,b GROUPS BETWEEN 2 PRECEDING AND 1 PRECEDING EXCLUDE CURRENT ROW), sum(c) OVER (ORDER BY a,b GROUPS BETWEEN 2 PRECEDING AND 1 PRECEDING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa {} {} {} {} AA aa {} {} {} {} AA aa {} {} {} {} AA aa {} {} {} {} AA bb {} {} 2307 2307 AA bb {} {} 2307 2307 AA bb {} {} 2307 2307 AA bb {} {} 2307 2307 BB aa 4685 4685 4685 4685 BB aa 4685 4685 4685 4685 BB aa 4685 4685 4685 4685 BB aa 4685 4685 4685 4685 BB aa 4685 4685 4685 4685 BB aa 4685 4685 4685 4685 BB bb 4685 4685 5251 5251 BB bb 4685 4685 5251 5251 BB bb 4685 4685 5251 5251 BB bb 4685 4685 5251 5251 BB bb 4685 4685 5251 5251 BB bb 4685 4685 5251 5251 CC aa 12025 12025 7340 7340 CC aa 12025 12025 7340 7340 CC aa 12025 12025 7340 7340 CC aa 12025 12025 7340 7340 CC bb 12025 12025 6421 6421 CC bb 12025 12025 6421 6421 DD aa 10462 10462 3122 3122 DD aa 10462 10462 3122 3122 DD aa 10462 10462 3122 3122 DD bb 10462 10462 2493 2493 DD bb 10462 10462 2493 2493 DD bb 10462 10462 2493 2493 DD bb 10462 10462 2493 2493 EE aa 7154 7154 4032 4032 EE aa 7154 7154 4032 4032 EE bb 7154 7154 3597 3597 EE bb 7154 7154 3597 3597 EE bb 7154 7154 3597 3597 FF aa 6571 6571 2539 2539 FF aa 6571 6571 2539 2539 FF aa 6571 6571 2539 2539 FF aa 6571 6571 2539 2539 FF bb 6571 6571 3812 3812 FF bb 6571 6571 3812 3812 FF bb 6571 6571 3812 3812 FF bb 6571 6571 3812 3812 FF bb 6571 6571 3812 3812 FF bb 6571 6571 3812 3812 GG aa 8207 8207 5668 5668 GG aa 8207 8207 5668 5668 GG aa 8207 8207 5668 5668 GG aa 8207 8207 5668 5668 GG bb 8207 8207 5102 5102 GG bb 8207 8207 5102 5102 GG bb 8207 8207 5102 5102 GG bb 8207 8207 5102 5102 HH aa 10136 10136 4468 4468 HH aa 10136 10136 4468 4468 HH aa 10136 10136 4468 4468 HH bb 10136 10136 5120 5120 HH bb 10136 10136 5120 5120 HH bb 10136 10136 5120 5120 HH bb 10136 10136 5120 5120 HH bb 10136 10136 5120 5120 HH bb 10136 10136 5120 5120 II aa 9911 9911 5443 5443 II aa 9911 9911 5443 5443 II bb 9911 9911 4244 4244 II bb 9911 9911 4244 4244 II bb 9911 9911 4244 4244 II bb 9911 9911 4244 4244 II bb 9911 9911 4244 4244 JJ aa 9083 9083 3640 3640 JJ aa 9083 9083 3640 3640 JJ aa 9083 9083 3640 3640 JJ aa 9083 9083 3640 3640 JJ bb 9083 9083 4604 4604 JJ bb 9083 9083 4604 4604 JJ bb 9083 9083 4604 4604 JJ bb 9083 9083 4604 4604} do_execsql_test 1.7.1 { SELECT a, b, sum(c) OVER (ORDER BY a GROUPS BETWEEN 3 PRECEDING AND 1 PRECEDING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa {} AA aa {} AA aa {} AA aa {} AA bb {} AA bb {} AA bb {} AA bb {} BB aa 4685 BB aa 4685 BB aa 4685 BB aa 4685 BB aa 4685 BB aa 4685 BB bb 4685 BB bb 4685 BB bb 4685 BB bb 4685 BB bb 4685 BB bb 4685 CC aa 12025 CC aa 12025 CC aa 12025 CC aa 12025 CC bb 12025 CC bb 12025 DD aa 15147 DD aa 15147 DD aa 15147 DD bb 15147 DD bb 15147 DD bb 15147 DD bb 15147 EE aa 14494 EE aa 14494 EE bb 14494 EE bb 14494 EE bb 14494 FF aa 9693 FF aa 9693 FF aa 9693 FF aa 9693 FF bb 9693 FF bb 9693 FF bb 9693 FF bb 9693 FF bb 9693 FF bb 9693 GG aa 12239 GG aa 12239 GG aa 12239 GG aa 12239 GG bb 12239 GG bb 12239 GG bb 12239 GG bb 12239 HH aa 12675 HH aa 12675 HH aa 12675 HH bb 12675 HH bb 12675 HH bb 12675 HH bb 12675 HH bb 12675 HH bb 12675 II aa 15579 II aa 15579 II bb 15579 II bb 15579 II bb 15579 II bb 15579 II bb 15579 JJ aa 13551 JJ aa 13551 JJ aa 13551 JJ aa 13551 JJ bb 13551 JJ bb 13551 JJ bb 13551 JJ bb 13551} do_execsql_test 1.7.2 { SELECT a, b, sum(c) OVER (ORDER BY a,b GROUPS BETWEEN 3 PRECEDING AND 1 PRECEDING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa {} AA aa {} AA aa {} AA aa {} AA bb 2307 AA bb 2307 AA bb 2307 AA bb 2307 BB aa 4685 BB aa 4685 BB aa 4685 BB aa 4685 BB aa 4685 BB aa 4685 BB bb 7558 BB bb 7558 BB bb 7558 BB bb 7558 BB bb 7558 BB bb 7558 CC aa 9718 CC aa 9718 CC aa 9718 CC aa 9718 CC bb 9294 CC bb 9294 DD aa 7589 DD aa 7589 DD aa 7589 DD bb 4447 DD bb 4447 DD bb 4447 DD bb 4447 EE aa 5200 EE aa 5200 EE bb 4922 EE bb 4922 EE bb 4922 FF aa 5246 FF aa 5246 FF aa 5246 FF aa 5246 FF bb 4702 FF bb 4702 FF bb 4702 FF bb 4702 FF bb 4702 FF bb 4702 GG aa 7317 GG aa 7317 GG aa 7317 GG aa 7317 GG bb 7265 GG bb 7265 GG bb 7265 GG bb 7265 HH aa 7973 HH aa 7973 HH aa 7973 HH bb 6717 HH bb 6717 HH bb 6717 HH bb 6717 HH bb 6717 HH bb 6717 II aa 8314 II aa 8314 II bb 6493 II bb 6493 II bb 6493 II bb 6493 II bb 6493 JJ aa 6834 JJ aa 6834 JJ aa 6834 JJ aa 6834 JJ bb 5654 JJ bb 5654 JJ bb 5654 JJ bb 5654} do_execsql_test 1.7.3 { SELECT a, b, rank() OVER (ORDER BY a GROUPS BETWEEN 3 PRECEDING AND 1 PRECEDING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa 1 AA aa 1 AA aa 1 AA aa 1 AA bb 1 AA bb 1 AA bb 1 AA bb 1 BB aa 9 BB aa 9 BB aa 9 BB aa 9 BB aa 9 BB aa 9 BB bb 9 BB bb 9 BB bb 9 BB bb 9 BB bb 9 BB bb 9 CC aa 21 CC aa 21 CC aa 21 CC aa 21 CC bb 21 CC bb 21 DD aa 27 DD aa 27 DD aa 27 DD bb 27 DD bb 27 DD bb 27 DD bb 27 EE aa 34 EE aa 34 EE bb 34 EE bb 34 EE bb 34 FF aa 39 FF aa 39 FF aa 39 FF aa 39 FF bb 39 FF bb 39 FF bb 39 FF bb 39 FF bb 39 FF bb 39 GG aa 49 GG aa 49 GG aa 49 GG aa 49 GG bb 49 GG bb 49 GG bb 49 GG bb 49 HH aa 57 HH aa 57 HH aa 57 HH bb 57 HH bb 57 HH bb 57 HH bb 57 HH bb 57 HH bb 57 II aa 66 II aa 66 II bb 66 II bb 66 II bb 66 II bb 66 II bb 66 JJ aa 73 JJ aa 73 JJ aa 73 JJ aa 73 JJ bb 73 JJ bb 73 JJ bb 73 JJ bb 73} do_execsql_test 1.7.4 { SELECT a, b, max(c) OVER (ORDER BY a,b GROUPS BETWEEN 3 PRECEDING AND 1 PRECEDING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa {} AA aa {} AA aa {} AA aa {} AA bb 934 AA bb 934 AA bb 934 AA bb 934 BB aa 934 BB aa 934 BB aa 934 BB aa 934 BB aa 934 BB aa 934 BB bb 934 BB bb 934 BB bb 934 BB bb 934 BB bb 934 BB bb 934 CC aa 870 CC aa 870 CC aa 870 CC aa 870 CC bb 840 CC bb 840 DD aa 840 DD aa 840 DD aa 840 DD bb 845 DD bb 845 DD bb 845 DD bb 845 EE aa 959 EE aa 959 EE bb 959 EE bb 959 EE bb 959 FF aa 959 FF aa 959 FF aa 959 FF aa 959 FF bb 777 FF bb 777 FF bb 777 FF bb 777 FF bb 777 FF bb 777 GG aa 938 GG aa 938 GG aa 938 GG aa 938 GG bb 938 GG bb 938 GG bb 938 GG bb 938 HH aa 938 HH aa 938 HH aa 938 HH bb 979 HH bb 979 HH bb 979 HH bb 979 HH bb 979 HH bb 979 II aa 979 II aa 979 II bb 979 II bb 979 II bb 979 II bb 979 II bb 979 JJ aa 963 JJ aa 963 JJ aa 963 JJ aa 963 JJ bb 899 JJ bb 899 JJ bb 899 JJ bb 899} do_execsql_test 1.7.5 { SELECT a, b, min(c) OVER (ORDER BY a,b GROUPS BETWEEN 3 PRECEDING AND 1 PRECEDING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa {} AA aa {} AA aa {} AA aa {} AA bb 223 AA bb 223 AA bb 223 AA bb 223 BB aa 223 BB aa 223 BB aa 223 BB aa 223 BB aa 223 BB aa 223 BB bb 223 BB bb 223 BB bb 223 BB bb 223 BB bb 223 BB bb 223 CC aa 247 CC aa 247 CC aa 247 CC aa 247 CC bb 158 CC bb 158 DD aa 158 DD aa 158 DD aa 158 DD bb 158 DD bb 158 DD bb 158 DD bb 158 EE aa 224 EE aa 224 EE bb 113 EE bb 113 EE bb 113 FF aa 113 FF aa 113 FF aa 113 FF aa 113 FF bb 113 FF bb 113 FF bb 113 FF bb 113 FF bb 113 FF bb 113 GG aa 102 GG aa 102 GG aa 102 GG aa 102 GG bb 102 GG bb 102 GG bb 102 GG bb 102 HH aa 102 HH aa 102 HH aa 102 HH bb 148 HH bb 148 HH bb 148 HH bb 148 HH bb 148 HH bb 148 II aa 133 II aa 133 II bb 133 II bb 133 II bb 133 II bb 133 II bb 133 JJ aa 133 JJ aa 133 JJ aa 133 JJ aa 133 JJ bb 113 JJ bb 113 JJ bb 113 JJ bb 113} do_execsql_test 1.7.6 { SELECT a, b, sum(c) OVER (ORDER BY a GROUPS BETWEEN 3 PRECEDING AND 1 PRECEDING EXCLUDE CURRENT ROW) FROM t3 ORDER BY 1, 2, 3; } {AA aa {} AA aa {} AA aa {} AA aa {} AA bb {} AA bb {} AA bb {} AA bb {} BB aa 4685 BB aa 4685 BB aa 4685 BB aa 4685 BB aa 4685 BB aa 4685 BB bb 4685 BB bb 4685 BB bb 4685 BB bb 4685 BB bb 4685 BB bb 4685 CC aa 12025 CC aa 12025 CC aa 12025 CC aa 12025 CC bb 12025 CC bb 12025 DD aa 15147 DD aa 15147 DD aa 15147 DD bb 15147 DD bb 15147 DD bb 15147 DD bb 15147 EE aa 14494 EE aa 14494 EE bb 14494 EE bb 14494 EE bb 14494 FF aa 9693 FF aa 9693 FF aa 9693 FF aa 9693 FF bb 9693 FF bb 9693 FF bb 9693 FF bb 9693 FF bb 9693 FF bb 9693 GG aa 12239 GG aa 12239 GG aa 12239 GG aa 12239 GG bb 12239 GG bb 12239 GG bb 12239 GG bb 12239 HH aa 12675 HH aa 12675 HH aa 12675 HH bb 12675 HH bb 12675 HH bb 12675 HH bb 12675 HH bb 12675 HH bb 12675 II aa 15579 II aa 15579 II bb 15579 II bb 15579 II bb 15579 II bb 15579 II bb 15579 JJ aa 13551 JJ aa 13551 JJ aa 13551 JJ aa 13551 JJ bb 13551 JJ bb 13551 JJ bb 13551 JJ bb 13551} do_execsql_test 1.7.7 { SELECT a, b, sum(c) OVER (ORDER BY a,b GROUPS BETWEEN 3 PRECEDING AND 1 PRECEDING EXCLUDE CURRENT ROW) FROM t3 ORDER BY 1, 2, 3; } {AA aa {} AA aa {} AA aa {} AA aa {} AA bb 2307 AA bb 2307 AA bb 2307 AA bb 2307 BB aa 4685 BB aa 4685 BB aa 4685 BB aa 4685 BB aa 4685 BB aa 4685 BB bb 7558 BB bb 7558 BB bb 7558 BB bb 7558 BB bb 7558 BB bb 7558 CC aa 9718 CC aa 9718 CC aa 9718 CC aa 9718 CC bb 9294 CC bb 9294 DD aa 7589 DD aa 7589 DD aa 7589 DD bb 4447 DD bb 4447 DD bb 4447 DD bb 4447 EE aa 5200 EE aa 5200 EE bb 4922 EE bb 4922 EE bb 4922 FF aa 5246 FF aa 5246 FF aa 5246 FF aa 5246 FF bb 4702 FF bb 4702 FF bb 4702 FF bb 4702 FF bb 4702 FF bb 4702 GG aa 7317 GG aa 7317 GG aa 7317 GG aa 7317 GG bb 7265 GG bb 7265 GG bb 7265 GG bb 7265 HH aa 7973 HH aa 7973 HH aa 7973 HH bb 6717 HH bb 6717 HH bb 6717 HH bb 6717 HH bb 6717 HH bb 6717 II aa 8314 II aa 8314 II bb 6493 II bb 6493 II bb 6493 II bb 6493 II bb 6493 JJ aa 6834 JJ aa 6834 JJ aa 6834 JJ aa 6834 JJ bb 5654 JJ bb 5654 JJ bb 5654 JJ bb 5654} do_execsql_test 1.7.8 { SELECT a, b, sum(c) OVER (ORDER BY a GROUPS BETWEEN 3 PRECEDING AND 1 PRECEDING EXCLUDE CURRENT ROW), sum(c) OVER (ORDER BY a GROUPS BETWEEN 3 PRECEDING AND 1 PRECEDING ), sum(c) OVER (ORDER BY a,b GROUPS BETWEEN 3 PRECEDING AND 1 PRECEDING EXCLUDE CURRENT ROW), sum(c) OVER (ORDER BY a,b GROUPS BETWEEN 3 PRECEDING AND 1 PRECEDING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa {} {} {} {} AA aa {} {} {} {} AA aa {} {} {} {} AA aa {} {} {} {} AA bb {} {} 2307 2307 AA bb {} {} 2307 2307 AA bb {} {} 2307 2307 AA bb {} {} 2307 2307 BB aa 4685 4685 4685 4685 BB aa 4685 4685 4685 4685 BB aa 4685 4685 4685 4685 BB aa 4685 4685 4685 4685 BB aa 4685 4685 4685 4685 BB aa 4685 4685 4685 4685 BB bb 4685 4685 7558 7558 BB bb 4685 4685 7558 7558 BB bb 4685 4685 7558 7558 BB bb 4685 4685 7558 7558 BB bb 4685 4685 7558 7558 BB bb 4685 4685 7558 7558 CC aa 12025 12025 9718 9718 CC aa 12025 12025 9718 9718 CC aa 12025 12025 9718 9718 CC aa 12025 12025 9718 9718 CC bb 12025 12025 9294 9294 CC bb 12025 12025 9294 9294 DD aa 15147 15147 7589 7589 DD aa 15147 15147 7589 7589 DD aa 15147 15147 7589 7589 DD bb 15147 15147 4447 4447 DD bb 15147 15147 4447 4447 DD bb 15147 15147 4447 4447 DD bb 15147 15147 4447 4447 EE aa 14494 14494 5200 5200 EE aa 14494 14494 5200 5200 EE bb 14494 14494 4922 4922 EE bb 14494 14494 4922 4922 EE bb 14494 14494 4922 4922 FF aa 9693 9693 5246 5246 FF aa 9693 9693 5246 5246 FF aa 9693 9693 5246 5246 FF aa 9693 9693 5246 5246 FF bb 9693 9693 4702 4702 FF bb 9693 9693 4702 4702 FF bb 9693 9693 4702 4702 FF bb 9693 9693 4702 4702 FF bb 9693 9693 4702 4702 FF bb 9693 9693 4702 4702 GG aa 12239 12239 7317 7317 GG aa 12239 12239 7317 7317 GG aa 12239 12239 7317 7317 GG aa 12239 12239 7317 7317 GG bb 12239 12239 7265 7265 GG bb 12239 12239 7265 7265 GG bb 12239 12239 7265 7265 GG bb 12239 12239 7265 7265 HH aa 12675 12675 7973 7973 HH aa 12675 12675 7973 7973 HH aa 12675 12675 7973 7973 HH bb 12675 12675 6717 6717 HH bb 12675 12675 6717 6717 HH bb 12675 12675 6717 6717 HH bb 12675 12675 6717 6717 HH bb 12675 12675 6717 6717 HH bb 12675 12675 6717 6717 II aa 15579 15579 8314 8314 II aa 15579 15579 8314 8314 II bb 15579 15579 6493 6493 II bb 15579 15579 6493 6493 II bb 15579 15579 6493 6493 II bb 15579 15579 6493 6493 II bb 15579 15579 6493 6493 JJ aa 13551 13551 6834 6834 JJ aa 13551 13551 6834 6834 JJ aa 13551 13551 6834 6834 JJ aa 13551 13551 6834 6834 JJ bb 13551 13551 5654 5654 JJ bb 13551 13551 5654 5654 JJ bb 13551 13551 5654 5654 JJ bb 13551 13551 5654 5654} do_execsql_test 1.8.1 { SELECT a, b, sum(c) OVER (ORDER BY a GROUPS BETWEEN 3 PRECEDING AND 0 PRECEDING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa 4685 AA aa 4685 AA aa 4685 AA aa 4685 AA bb 4685 AA bb 4685 AA bb 4685 AA bb 4685 BB aa 12025 BB aa 12025 BB aa 12025 BB aa 12025 BB aa 12025 BB aa 12025 BB bb 12025 BB bb 12025 BB bb 12025 BB bb 12025 BB bb 12025 BB bb 12025 CC aa 15147 CC aa 15147 CC aa 15147 CC aa 15147 CC bb 15147 CC bb 15147 DD aa 19179 DD aa 19179 DD aa 19179 DD bb 19179 DD bb 19179 DD bb 19179 DD bb 19179 EE aa 17033 EE aa 17033 EE bb 17033 EE bb 17033 EE bb 17033 FF aa 15361 FF aa 15361 FF aa 15361 FF aa 15361 FF bb 15361 FF bb 15361 FF bb 15361 FF bb 15361 FF bb 15361 FF bb 15361 GG aa 16707 GG aa 16707 GG aa 16707 GG aa 16707 GG bb 16707 GG bb 16707 GG bb 16707 GG bb 16707 HH aa 18118 HH aa 18118 HH aa 18118 HH bb 18118 HH bb 18118 HH bb 18118 HH bb 18118 HH bb 18118 HH bb 18118 II aa 19219 II aa 19219 II bb 19219 II bb 19219 II bb 19219 II bb 19219 II bb 19219 JJ aa 17351 JJ aa 17351 JJ aa 17351 JJ aa 17351 JJ bb 17351 JJ bb 17351 JJ bb 17351 JJ bb 17351} do_execsql_test 1.8.2 { SELECT a, b, sum(c) OVER (ORDER BY a,b GROUPS BETWEEN 3 PRECEDING AND 0 PRECEDING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa 2307 AA aa 2307 AA aa 2307 AA aa 2307 AA bb 4685 AA bb 4685 AA bb 4685 AA bb 4685 BB aa 7558 BB aa 7558 BB aa 7558 BB aa 7558 BB aa 7558 BB aa 7558 BB bb 12025 BB bb 12025 BB bb 12025 BB bb 12025 BB bb 12025 BB bb 12025 CC aa 11672 CC aa 11672 CC aa 11672 CC aa 11672 CC bb 10462 CC bb 10462 DD aa 8914 DD aa 8914 DD aa 8914 DD bb 7154 DD bb 7154 DD bb 7154 DD bb 7154 EE aa 6090 EE aa 6090 EE bb 6571 EE bb 6571 EE bb 6571 FF aa 7409 FF aa 7409 FF aa 7409 FF aa 7409 FF bb 8207 FF bb 8207 FF bb 8207 FF bb 8207 FF bb 8207 FF bb 8207 GG aa 8914 GG aa 8914 GG aa 8914 GG aa 8914 GG bb 10136 GG bb 10136 GG bb 10136 GG bb 10136 HH aa 10222 HH aa 10222 HH aa 10222 HH bb 9911 HH bb 9911 HH bb 9911 HH bb 9911 HH bb 9911 HH bb 9911 II aa 9364 II aa 9364 II bb 9083 II bb 9083 II bb 9083 II bb 9083 II bb 9083 JJ aa 8848 JJ aa 8848 JJ aa 8848 JJ aa 8848 JJ bb 7440 JJ bb 7440 JJ bb 7440 JJ bb 7440} do_execsql_test 1.8.3 { SELECT a, b, rank() OVER (ORDER BY a GROUPS BETWEEN 3 PRECEDING AND 0 PRECEDING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa 1 AA aa 1 AA aa 1 AA aa 1 AA bb 1 AA bb 1 AA bb 1 AA bb 1 BB aa 9 BB aa 9 BB aa 9 BB aa 9 BB aa 9 BB aa 9 BB bb 9 BB bb 9 BB bb 9 BB bb 9 BB bb 9 BB bb 9 CC aa 21 CC aa 21 CC aa 21 CC aa 21 CC bb 21 CC bb 21 DD aa 27 DD aa 27 DD aa 27 DD bb 27 DD bb 27 DD bb 27 DD bb 27 EE aa 34 EE aa 34 EE bb 34 EE bb 34 EE bb 34 FF aa 39 FF aa 39 FF aa 39 FF aa 39 FF bb 39 FF bb 39 FF bb 39 FF bb 39 FF bb 39 FF bb 39 GG aa 49 GG aa 49 GG aa 49 GG aa 49 GG bb 49 GG bb 49 GG bb 49 GG bb 49 HH aa 57 HH aa 57 HH aa 57 HH bb 57 HH bb 57 HH bb 57 HH bb 57 HH bb 57 HH bb 57 II aa 66 II aa 66 II bb 66 II bb 66 II bb 66 II bb 66 II bb 66 JJ aa 73 JJ aa 73 JJ aa 73 JJ aa 73 JJ bb 73 JJ bb 73 JJ bb 73 JJ bb 73} do_execsql_test 1.8.4 { SELECT a, b, max(c) OVER (ORDER BY a,b GROUPS BETWEEN 3 PRECEDING AND 0 PRECEDING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa 934 AA aa 934 AA aa 934 AA aa 934 AA bb 934 AA bb 934 AA bb 934 AA bb 934 BB aa 934 BB aa 934 BB aa 934 BB aa 934 BB aa 934 BB aa 934 BB bb 934 BB bb 934 BB bb 934 BB bb 934 BB bb 934 BB bb 934 CC aa 870 CC aa 870 CC aa 870 CC aa 870 CC bb 840 CC bb 840 DD aa 845 DD aa 845 DD aa 845 DD bb 959 DD bb 959 DD bb 959 DD bb 959 EE aa 959 EE aa 959 EE bb 959 EE bb 959 EE bb 959 FF aa 959 FF aa 959 FF aa 959 FF aa 959 FF bb 938 FF bb 938 FF bb 938 FF bb 938 FF bb 938 FF bb 938 GG aa 938 GG aa 938 GG aa 938 GG aa 938 GG bb 938 GG bb 938 GG bb 938 GG bb 938 HH aa 979 HH aa 979 HH aa 979 HH bb 979 HH bb 979 HH bb 979 HH bb 979 HH bb 979 HH bb 979 II aa 979 II aa 979 II bb 979 II bb 979 II bb 979 II bb 979 II bb 979 JJ aa 963 JJ aa 963 JJ aa 963 JJ aa 963 JJ bb 899 JJ bb 899 JJ bb 899 JJ bb 899} do_execsql_test 1.8.5 { SELECT a, b, min(c) OVER (ORDER BY a,b GROUPS BETWEEN 3 PRECEDING AND 0 PRECEDING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa 223 AA aa 223 AA aa 223 AA aa 223 AA bb 223 AA bb 223 AA bb 223 AA bb 223 BB aa 223 BB aa 223 BB aa 223 BB aa 223 BB aa 223 BB aa 223 BB bb 223 BB bb 223 BB bb 223 BB bb 223 BB bb 223 BB bb 223 CC aa 158 CC aa 158 CC aa 158 CC aa 158 CC bb 158 CC bb 158 DD aa 158 DD aa 158 DD aa 158 DD bb 158 DD bb 158 DD bb 158 DD bb 158 EE aa 113 EE aa 113 EE bb 113 EE bb 113 EE bb 113 FF aa 113 FF aa 113 FF aa 113 FF aa 113 FF bb 102 FF bb 102 FF bb 102 FF bb 102 FF bb 102 FF bb 102 GG aa 102 GG aa 102 GG aa 102 GG aa 102 GG bb 102 GG bb 102 GG bb 102 GG bb 102 HH aa 102 HH aa 102 HH aa 102 HH bb 133 HH bb 133 HH bb 133 HH bb 133 HH bb 133 HH bb 133 II aa 133 II aa 133 II bb 133 II bb 133 II bb 133 II bb 133 II bb 133 JJ aa 113 JJ aa 113 JJ aa 113 JJ aa 113 JJ bb 113 JJ bb 113 JJ bb 113 JJ bb 113} do_execsql_test 1.8.6 { SELECT a, b, sum(c) OVER (ORDER BY a GROUPS BETWEEN 3 PRECEDING AND 0 PRECEDING EXCLUDE CURRENT ROW) FROM t3 ORDER BY 1, 2, 3; } {AA aa 3751 AA aa 3774 AA aa 4446 AA aa 4462 AA bb 3815 AA bb 4058 AA bb 4113 AA bb 4376 BB aa 11263 BB aa 11365 BB aa 11613 BB aa 11626 BB aa 11632 BB aa 11778 BB bb 11185 BB bb 11233 BB bb 11239 BB bb 11314 BB bb 11320 BB bb 11392 CC aa 14388 CC aa 14540 CC aa 14717 CC aa 14989 CC bb 14325 CC bb 14801 DD aa 18334 DD aa 18923 DD aa 18955 DD bb 18220 DD bb 18385 DD bb 18463 DD bb 18941 EE aa 16256 EE aa 16920 EE bb 16265 EE bb 16404 EE bb 16781 FF aa 14691 FF aa 14694 FF aa 14743 FF aa 15153 FF bb 14423 FF bb 14491 FF bb 14635 FF bb 14787 FF bb 15066 FF bb 15259 GG aa 16073 GG aa 16227 GG aa 16372 GG aa 16559 GG bb 15769 GG bb 15778 GG bb 15863 GG bb 16547 HH aa 17139 HH aa 17328 HH aa 17638 HH bb 17155 HH bb 17388 HH bb 17435 HH bb 17763 HH bb 17788 HH bb 17985 II aa 18567 II aa 18821 II bb 18414 II bb 18548 II bb 18776 II bb 18798 II bb 18969 JJ aa 16452 JJ aa 16583 JJ aa 17117 JJ aa 17238 JJ bb 16512 JJ bb 16997 JJ bb 17015 JJ bb 17094} do_execsql_test 1.8.7 { SELECT a, b, sum(c) OVER (ORDER BY a,b GROUPS BETWEEN 3 PRECEDING AND 0 PRECEDING EXCLUDE CURRENT ROW) FROM t3 ORDER BY 1, 2, 3; } {AA aa 1373 AA aa 1396 AA aa 2068 AA aa 2084 AA bb 3815 AA bb 4058 AA bb 4113 AA bb 4376 BB aa 6796 BB aa 6898 BB aa 7146 BB aa 7159 BB aa 7165 BB aa 7311 BB bb 11185 BB bb 11233 BB bb 11239 BB bb 11314 BB bb 11320 BB bb 11392 CC aa 10913 CC aa 11065 CC aa 11242 CC aa 11514 CC bb 9640 CC bb 10116 DD aa 8069 DD aa 8658 DD aa 8690 DD bb 6195 DD bb 6360 DD bb 6438 DD bb 6916 EE aa 5313 EE aa 5977 EE bb 5803 EE bb 5942 EE bb 6319 FF aa 6739 FF aa 6742 FF aa 6791 FF aa 7201 FF bb 7269 FF bb 7337 FF bb 7481 FF bb 7633 FF bb 7912 FF bb 8105 GG aa 8280 GG aa 8434 GG aa 8579 GG aa 8766 GG bb 9198 GG bb 9207 GG bb 9292 GG bb 9976 HH aa 9243 HH aa 9432 HH aa 9742 HH bb 8948 HH bb 9181 HH bb 9228 HH bb 9556 HH bb 9581 HH bb 9778 II aa 8712 II aa 8966 II bb 8278 II bb 8412 II bb 8640 II bb 8662 II bb 8833 JJ aa 7949 JJ aa 8080 JJ aa 8614 JJ aa 8735 JJ bb 6601 JJ bb 7086 JJ bb 7104 JJ bb 7183} do_execsql_test 1.8.8 { SELECT a, b, sum(c) OVER (ORDER BY a GROUPS BETWEEN 3 PRECEDING AND 0 PRECEDING EXCLUDE CURRENT ROW), sum(c) OVER (ORDER BY a GROUPS BETWEEN 3 PRECEDING AND 0 PRECEDING ), sum(c) OVER (ORDER BY a,b GROUPS BETWEEN 3 PRECEDING AND 0 PRECEDING EXCLUDE CURRENT ROW), sum(c) OVER (ORDER BY a,b GROUPS BETWEEN 3 PRECEDING AND 0 PRECEDING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa 3751 4685 1373 2307 AA aa 3774 4685 1396 2307 AA aa 4446 4685 2068 2307 AA aa 4462 4685 2084 2307 AA bb 3815 4685 3815 4685 AA bb 4058 4685 4058 4685 AA bb 4113 4685 4113 4685 AA bb 4376 4685 4376 4685 BB aa 11263 12025 6796 7558 BB aa 11365 12025 6898 7558 BB aa 11613 12025 7146 7558 BB aa 11626 12025 7159 7558 BB aa 11632 12025 7165 7558 BB aa 11778 12025 7311 7558 BB bb 11185 12025 11185 12025 BB bb 11233 12025 11233 12025 BB bb 11239 12025 11239 12025 BB bb 11314 12025 11314 12025 BB bb 11320 12025 11320 12025 BB bb 11392 12025 11392 12025 CC aa 14388 15147 10913 11672 CC aa 14540 15147 11065 11672 CC aa 14717 15147 11242 11672 CC aa 14989 15147 11514 11672 CC bb 14325 15147 9640 10462 CC bb 14801 15147 10116 10462 DD aa 18334 19179 8069 8914 DD aa 18923 19179 8658 8914 DD aa 18955 19179 8690 8914 DD bb 18220 19179 6195 7154 DD bb 18385 19179 6360 7154 DD bb 18463 19179 6438 7154 DD bb 18941 19179 6916 7154 EE aa 16256 17033 5313 6090 EE aa 16920 17033 5977 6090 EE bb 16265 17033 5803 6571 EE bb 16404 17033 5942 6571 EE bb 16781 17033 6319 6571 FF aa 14691 15361 6739 7409 FF aa 14694 15361 6742 7409 FF aa 14743 15361 6791 7409 FF aa 15153 15361 7201 7409 FF bb 14423 15361 7269 8207 FF bb 14491 15361 7337 8207 FF bb 14635 15361 7481 8207 FF bb 14787 15361 7633 8207 FF bb 15066 15361 7912 8207 FF bb 15259 15361 8105 8207 GG aa 16073 16707 8280 8914 GG aa 16227 16707 8434 8914 GG aa 16372 16707 8579 8914 GG aa 16559 16707 8766 8914 GG bb 15769 16707 9198 10136 GG bb 15778 16707 9207 10136 GG bb 15863 16707 9292 10136 GG bb 16547 16707 9976 10136 HH aa 17139 18118 9243 10222 HH aa 17328 18118 9432 10222 HH aa 17638 18118 9742 10222 HH bb 17155 18118 8948 9911 HH bb 17388 18118 9181 9911 HH bb 17435 18118 9228 9911 HH bb 17763 18118 9556 9911 HH bb 17788 18118 9581 9911 HH bb 17985 18118 9778 9911 II aa 18567 19219 8712 9364 II aa 18821 19219 8966 9364 II bb 18414 19219 8278 9083 II bb 18548 19219 8412 9083 II bb 18776 19219 8640 9083 II bb 18798 19219 8662 9083 II bb 18969 19219 8833 9083 JJ aa 16452 17351 7949 8848 JJ aa 16583 17351 8080 8848 JJ aa 17117 17351 8614 8848 JJ aa 17238 17351 8735 8848 JJ bb 16512 17351 6601 7440 JJ bb 16997 17351 7086 7440 JJ bb 17015 17351 7104 7440 JJ bb 17094 17351 7183 7440} do_execsql_test 1.9.1 { SELECT a, b, sum(c) OVER (ORDER BY a GROUPS BETWEEN 2 PRECEDING AND CURRENT ROW ) FROM t3 ORDER BY 1, 2, 3; } {AA aa 4685 AA aa 4685 AA aa 4685 AA aa 4685 AA bb 4685 AA bb 4685 AA bb 4685 AA bb 4685 BB aa 12025 BB aa 12025 BB aa 12025 BB aa 12025 BB aa 12025 BB aa 12025 BB bb 12025 BB bb 12025 BB bb 12025 BB bb 12025 BB bb 12025 BB bb 12025 CC aa 15147 CC aa 15147 CC aa 15147 CC aa 15147 CC bb 15147 CC bb 15147 DD aa 14494 DD aa 14494 DD aa 14494 DD bb 14494 DD bb 14494 DD bb 14494 DD bb 14494 EE aa 9693 EE aa 9693 EE bb 9693 EE bb 9693 EE bb 9693 FF aa 12239 FF aa 12239 FF aa 12239 FF aa 12239 FF bb 12239 FF bb 12239 FF bb 12239 FF bb 12239 FF bb 12239 FF bb 12239 GG aa 12675 GG aa 12675 GG aa 12675 GG aa 12675 GG bb 12675 GG bb 12675 GG bb 12675 GG bb 12675 HH aa 15579 HH aa 15579 HH aa 15579 HH bb 15579 HH bb 15579 HH bb 15579 HH bb 15579 HH bb 15579 HH bb 15579 II aa 13551 II aa 13551 II bb 13551 II bb 13551 II bb 13551 II bb 13551 II bb 13551 JJ aa 12883 JJ aa 12883 JJ aa 12883 JJ aa 12883 JJ bb 12883 JJ bb 12883 JJ bb 12883 JJ bb 12883} do_execsql_test 1.9.2 { SELECT a, b, sum(c) OVER (ORDER BY a,b GROUPS BETWEEN 2 PRECEDING AND CURRENT ROW ) FROM t3 ORDER BY 1, 2, 3; } {AA aa 2307 AA aa 2307 AA aa 2307 AA aa 2307 AA bb 4685 AA bb 4685 AA bb 4685 AA bb 4685 BB aa 7558 BB aa 7558 BB aa 7558 BB aa 7558 BB aa 7558 BB aa 7558 BB bb 9718 BB bb 9718 BB bb 9718 BB bb 9718 BB bb 9718 BB bb 9718 CC aa 9294 CC aa 9294 CC aa 9294 CC aa 9294 CC bb 7589 CC bb 7589 DD aa 4447 DD aa 4447 DD aa 4447 DD bb 5200 DD bb 5200 DD bb 5200 DD bb 5200 EE aa 4922 EE aa 4922 EE bb 5246 EE bb 5246 EE bb 5246 FF aa 4702 FF aa 4702 FF aa 4702 FF aa 4702 FF bb 7317 FF bb 7317 FF bb 7317 FF bb 7317 FF bb 7317 FF bb 7317 GG aa 7265 GG aa 7265 GG aa 7265 GG aa 7265 GG bb 7973 GG bb 7973 GG bb 7973 GG bb 7973 HH aa 6717 HH aa 6717 HH aa 6717 HH bb 8314 HH bb 8314 HH bb 8314 HH bb 8314 HH bb 8314 HH bb 8314 II aa 6493 II aa 6493 II bb 6834 II bb 6834 II bb 6834 II bb 6834 II bb 6834 JJ aa 5654 JJ aa 5654 JJ aa 5654 JJ aa 5654 JJ bb 6390 JJ bb 6390 JJ bb 6390 JJ bb 6390} do_execsql_test 1.9.3 { SELECT a, b, rank() OVER (ORDER BY a GROUPS BETWEEN 2 PRECEDING AND CURRENT ROW ) FROM t3 ORDER BY 1, 2, 3; } {AA aa 1 AA aa 1 AA aa 1 AA aa 1 AA bb 1 AA bb 1 AA bb 1 AA bb 1 BB aa 9 BB aa 9 BB aa 9 BB aa 9 BB aa 9 BB aa 9 BB bb 9 BB bb 9 BB bb 9 BB bb 9 BB bb 9 BB bb 9 CC aa 21 CC aa 21 CC aa 21 CC aa 21 CC bb 21 CC bb 21 DD aa 27 DD aa 27 DD aa 27 DD bb 27 DD bb 27 DD bb 27 DD bb 27 EE aa 34 EE aa 34 EE bb 34 EE bb 34 EE bb 34 FF aa 39 FF aa 39 FF aa 39 FF aa 39 FF bb 39 FF bb 39 FF bb 39 FF bb 39 FF bb 39 FF bb 39 GG aa 49 GG aa 49 GG aa 49 GG aa 49 GG bb 49 GG bb 49 GG bb 49 GG bb 49 HH aa 57 HH aa 57 HH aa 57 HH bb 57 HH bb 57 HH bb 57 HH bb 57 HH bb 57 HH bb 57 II aa 66 II aa 66 II bb 66 II bb 66 II bb 66 II bb 66 II bb 66 JJ aa 73 JJ aa 73 JJ aa 73 JJ aa 73 JJ bb 73 JJ bb 73 JJ bb 73 JJ bb 73} do_execsql_test 1.9.4 { SELECT a, b, max(c) OVER (ORDER BY a,b GROUPS BETWEEN 2 PRECEDING AND CURRENT ROW ) FROM t3 ORDER BY 1, 2, 3; } {AA aa 934 AA aa 934 AA aa 934 AA aa 934 AA bb 934 AA bb 934 AA bb 934 AA bb 934 BB aa 934 BB aa 934 BB aa 934 BB aa 934 BB aa 934 BB aa 934 BB bb 870 BB bb 870 BB bb 870 BB bb 870 BB bb 870 BB bb 870 CC aa 840 CC aa 840 CC aa 840 CC aa 840 CC bb 840 CC bb 840 DD aa 845 DD aa 845 DD aa 845 DD bb 959 DD bb 959 DD bb 959 DD bb 959 EE aa 959 EE aa 959 EE bb 959 EE bb 959 EE bb 959 FF aa 777 FF aa 777 FF aa 777 FF aa 777 FF bb 938 FF bb 938 FF bb 938 FF bb 938 FF bb 938 FF bb 938 GG aa 938 GG aa 938 GG aa 938 GG aa 938 GG bb 938 GG bb 938 GG bb 938 GG bb 938 HH aa 979 HH aa 979 HH aa 979 HH bb 979 HH bb 979 HH bb 979 HH bb 979 HH bb 979 HH bb 979 II aa 979 II aa 979 II bb 963 II bb 963 II bb 963 II bb 963 II bb 963 JJ aa 899 JJ aa 899 JJ aa 899 JJ aa 899 JJ bb 899 JJ bb 899 JJ bb 899 JJ bb 899} do_execsql_test 1.9.5 { SELECT a, b, min(c) OVER (ORDER BY a,b GROUPS BETWEEN 2 PRECEDING AND CURRENT ROW ) FROM t3 ORDER BY 1, 2, 3; } {AA aa 223 AA aa 223 AA aa 223 AA aa 223 AA bb 223 AA bb 223 AA bb 223 AA bb 223 BB aa 223 BB aa 223 BB aa 223 BB aa 223 BB aa 223 BB aa 223 BB bb 247 BB bb 247 BB bb 247 BB bb 247 BB bb 247 BB bb 247 CC aa 158 CC aa 158 CC aa 158 CC aa 158 CC bb 158 CC bb 158 DD aa 158 DD aa 158 DD aa 158 DD bb 224 DD bb 224 DD bb 224 DD bb 224 EE aa 113 EE aa 113 EE bb 113 EE bb 113 EE bb 113 FF aa 113 FF aa 113 FF aa 113 FF aa 113 FF bb 102 FF bb 102 FF bb 102 FF bb 102 FF bb 102 FF bb 102 GG aa 102 GG aa 102 GG aa 102 GG aa 102 GG bb 102 GG bb 102 GG bb 102 GG bb 102 HH aa 148 HH aa 148 HH aa 148 HH bb 133 HH bb 133 HH bb 133 HH bb 133 HH bb 133 HH bb 133 II aa 133 II aa 133 II bb 133 II bb 133 II bb 133 II bb 133 II bb 133 JJ aa 113 JJ aa 113 JJ aa 113 JJ aa 113 JJ bb 113 JJ bb 113 JJ bb 113 JJ bb 113} do_execsql_test 1.9.6 { SELECT a, b, sum(c) OVER (ORDER BY a GROUPS BETWEEN 2 PRECEDING AND CURRENT ROW EXCLUDE CURRENT ROW) FROM t3 ORDER BY 1, 2, 3; } {AA aa 3751 AA aa 3774 AA aa 4446 AA aa 4462 AA bb 3815 AA bb 4058 AA bb 4113 AA bb 4376 BB aa 11263 BB aa 11365 BB aa 11613 BB aa 11626 BB aa 11632 BB aa 11778 BB bb 11185 BB bb 11233 BB bb 11239 BB bb 11314 BB bb 11320 BB bb 11392 CC aa 14388 CC aa 14540 CC aa 14717 CC aa 14989 CC bb 14325 CC bb 14801 DD aa 13649 DD aa 14238 DD aa 14270 DD bb 13535 DD bb 13700 DD bb 13778 DD bb 14256 EE aa 8916 EE aa 9580 EE bb 8925 EE bb 9064 EE bb 9441 FF aa 11569 FF aa 11572 FF aa 11621 FF aa 12031 FF bb 11301 FF bb 11369 FF bb 11513 FF bb 11665 FF bb 11944 FF bb 12137 GG aa 12041 GG aa 12195 GG aa 12340 GG aa 12527 GG bb 11737 GG bb 11746 GG bb 11831 GG bb 12515 HH aa 14600 HH aa 14789 HH aa 15099 HH bb 14616 HH bb 14849 HH bb 14896 HH bb 15224 HH bb 15249 HH bb 15446 II aa 12899 II aa 13153 II bb 12746 II bb 12880 II bb 13108 II bb 13130 II bb 13301 JJ aa 11984 JJ aa 12115 JJ aa 12649 JJ aa 12770 JJ bb 12044 JJ bb 12529 JJ bb 12547 JJ bb 12626} do_execsql_test 1.9.7 { SELECT a, b, sum(c) OVER (ORDER BY a,b GROUPS BETWEEN 2 PRECEDING AND CURRENT ROW EXCLUDE CURRENT ROW) FROM t3 ORDER BY 1, 2, 3; } {AA aa 1373 AA aa 1396 AA aa 2068 AA aa 2084 AA bb 3815 AA bb 4058 AA bb 4113 AA bb 4376 BB aa 6796 BB aa 6898 BB aa 7146 BB aa 7159 BB aa 7165 BB aa 7311 BB bb 8878 BB bb 8926 BB bb 8932 BB bb 9007 BB bb 9013 BB bb 9085 CC aa 8535 CC aa 8687 CC aa 8864 CC aa 9136 CC bb 6767 CC bb 7243 DD aa 3602 DD aa 4191 DD aa 4223 DD bb 4241 DD bb 4406 DD bb 4484 DD bb 4962 EE aa 4145 EE aa 4809 EE bb 4478 EE bb 4617 EE bb 4994 FF aa 4032 FF aa 4035 FF aa 4084 FF aa 4494 FF bb 6379 FF bb 6447 FF bb 6591 FF bb 6743 FF bb 7022 FF bb 7215 GG aa 6631 GG aa 6785 GG aa 6930 GG aa 7117 GG bb 7035 GG bb 7044 GG bb 7129 GG bb 7813 HH aa 5738 HH aa 5927 HH aa 6237 HH bb 7351 HH bb 7584 HH bb 7631 HH bb 7959 HH bb 7984 HH bb 8181 II aa 5841 II aa 6095 II bb 6029 II bb 6163 II bb 6391 II bb 6413 II bb 6584 JJ aa 4755 JJ aa 4886 JJ aa 5420 JJ aa 5541 JJ bb 5551 JJ bb 6036 JJ bb 6054 JJ bb 6133} do_execsql_test 1.9.8 { SELECT a, b, sum(c) OVER (ORDER BY a GROUPS BETWEEN 2 PRECEDING AND CURRENT ROW EXCLUDE CURRENT ROW), sum(c) OVER (ORDER BY a GROUPS BETWEEN 2 PRECEDING AND CURRENT ROW ), sum(c) OVER (ORDER BY a,b GROUPS BETWEEN 2 PRECEDING AND CURRENT ROW EXCLUDE CURRENT ROW), sum(c) OVER (ORDER BY a,b GROUPS BETWEEN 2 PRECEDING AND CURRENT ROW ) FROM t3 ORDER BY 1, 2, 3; } {AA aa 3751 4685 1373 2307 AA aa 3774 4685 1396 2307 AA aa 4446 4685 2068 2307 AA aa 4462 4685 2084 2307 AA bb 3815 4685 3815 4685 AA bb 4058 4685 4058 4685 AA bb 4113 4685 4113 4685 AA bb 4376 4685 4376 4685 BB aa 11263 12025 6796 7558 BB aa 11365 12025 6898 7558 BB aa 11613 12025 7146 7558 BB aa 11626 12025 7159 7558 BB aa 11632 12025 7165 7558 BB aa 11778 12025 7311 7558 BB bb 11185 12025 8878 9718 BB bb 11233 12025 8926 9718 BB bb 11239 12025 8932 9718 BB bb 11314 12025 9007 9718 BB bb 11320 12025 9013 9718 BB bb 11392 12025 9085 9718 CC aa 14388 15147 8535 9294 CC aa 14540 15147 8687 9294 CC aa 14717 15147 8864 9294 CC aa 14989 15147 9136 9294 CC bb 14325 15147 6767 7589 CC bb 14801 15147 7243 7589 DD aa 13649 14494 3602 4447 DD aa 14238 14494 4191 4447 DD aa 14270 14494 4223 4447 DD bb 13535 14494 4241 5200 DD bb 13700 14494 4406 5200 DD bb 13778 14494 4484 5200 DD bb 14256 14494 4962 5200 EE aa 8916 9693 4145 4922 EE aa 9580 9693 4809 4922 EE bb 8925 9693 4478 5246 EE bb 9064 9693 4617 5246 EE bb 9441 9693 4994 5246 FF aa 11569 12239 4032 4702 FF aa 11572 12239 4035 4702 FF aa 11621 12239 4084 4702 FF aa 12031 12239 4494 4702 FF bb 11301 12239 6379 7317 FF bb 11369 12239 6447 7317 FF bb 11513 12239 6591 7317 FF bb 11665 12239 6743 7317 FF bb 11944 12239 7022 7317 FF bb 12137 12239 7215 7317 GG aa 12041 12675 6631 7265 GG aa 12195 12675 6785 7265 GG aa 12340 12675 6930 7265 GG aa 12527 12675 7117 7265 GG bb 11737 12675 7035 7973 GG bb 11746 12675 7044 7973 GG bb 11831 12675 7129 7973 GG bb 12515 12675 7813 7973 HH aa 14600 15579 5738 6717 HH aa 14789 15579 5927 6717 HH aa 15099 15579 6237 6717 HH bb 14616 15579 7351 8314 HH bb 14849 15579 7584 8314 HH bb 14896 15579 7631 8314 HH bb 15224 15579 7959 8314 HH bb 15249 15579 7984 8314 HH bb 15446 15579 8181 8314 II aa 12899 13551 5841 6493 II aa 13153 13551 6095 6493 II bb 12746 13551 6029 6834 II bb 12880 13551 6163 6834 II bb 13108 13551 6391 6834 II bb 13130 13551 6413 6834 II bb 13301 13551 6584 6834 JJ aa 11984 12883 4755 5654 JJ aa 12115 12883 4886 5654 JJ aa 12649 12883 5420 5654 JJ aa 12770 12883 5541 5654 JJ bb 12044 12883 5551 6390 JJ bb 12529 12883 6036 6390 JJ bb 12547 12883 6054 6390 JJ bb 12626 12883 6133 6390} do_execsql_test 1.10.1 { SELECT a, b, sum(c) OVER (ORDER BY a GROUPS BETWEEN 3 PRECEDING AND 0 FOLLOWING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa 4685 AA aa 4685 AA aa 4685 AA aa 4685 AA bb 4685 AA bb 4685 AA bb 4685 AA bb 4685 BB aa 12025 BB aa 12025 BB aa 12025 BB aa 12025 BB aa 12025 BB aa 12025 BB bb 12025 BB bb 12025 BB bb 12025 BB bb 12025 BB bb 12025 BB bb 12025 CC aa 15147 CC aa 15147 CC aa 15147 CC aa 15147 CC bb 15147 CC bb 15147 DD aa 19179 DD aa 19179 DD aa 19179 DD bb 19179 DD bb 19179 DD bb 19179 DD bb 19179 EE aa 17033 EE aa 17033 EE bb 17033 EE bb 17033 EE bb 17033 FF aa 15361 FF aa 15361 FF aa 15361 FF aa 15361 FF bb 15361 FF bb 15361 FF bb 15361 FF bb 15361 FF bb 15361 FF bb 15361 GG aa 16707 GG aa 16707 GG aa 16707 GG aa 16707 GG bb 16707 GG bb 16707 GG bb 16707 GG bb 16707 HH aa 18118 HH aa 18118 HH aa 18118 HH bb 18118 HH bb 18118 HH bb 18118 HH bb 18118 HH bb 18118 HH bb 18118 II aa 19219 II aa 19219 II bb 19219 II bb 19219 II bb 19219 II bb 19219 II bb 19219 JJ aa 17351 JJ aa 17351 JJ aa 17351 JJ aa 17351 JJ bb 17351 JJ bb 17351 JJ bb 17351 JJ bb 17351} do_execsql_test 1.10.2 { SELECT a, b, sum(c) OVER (ORDER BY a,b GROUPS BETWEEN 3 PRECEDING AND 0 FOLLOWING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa 2307 AA aa 2307 AA aa 2307 AA aa 2307 AA bb 4685 AA bb 4685 AA bb 4685 AA bb 4685 BB aa 7558 BB aa 7558 BB aa 7558 BB aa 7558 BB aa 7558 BB aa 7558 BB bb 12025 BB bb 12025 BB bb 12025 BB bb 12025 BB bb 12025 BB bb 12025 CC aa 11672 CC aa 11672 CC aa 11672 CC aa 11672 CC bb 10462 CC bb 10462 DD aa 8914 DD aa 8914 DD aa 8914 DD bb 7154 DD bb 7154 DD bb 7154 DD bb 7154 EE aa 6090 EE aa 6090 EE bb 6571 EE bb 6571 EE bb 6571 FF aa 7409 FF aa 7409 FF aa 7409 FF aa 7409 FF bb 8207 FF bb 8207 FF bb 8207 FF bb 8207 FF bb 8207 FF bb 8207 GG aa 8914 GG aa 8914 GG aa 8914 GG aa 8914 GG bb 10136 GG bb 10136 GG bb 10136 GG bb 10136 HH aa 10222 HH aa 10222 HH aa 10222 HH bb 9911 HH bb 9911 HH bb 9911 HH bb 9911 HH bb 9911 HH bb 9911 II aa 9364 II aa 9364 II bb 9083 II bb 9083 II bb 9083 II bb 9083 II bb 9083 JJ aa 8848 JJ aa 8848 JJ aa 8848 JJ aa 8848 JJ bb 7440 JJ bb 7440 JJ bb 7440 JJ bb 7440} do_execsql_test 1.10.3 { SELECT a, b, rank() OVER (ORDER BY a GROUPS BETWEEN 3 PRECEDING AND 0 FOLLOWING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa 1 AA aa 1 AA aa 1 AA aa 1 AA bb 1 AA bb 1 AA bb 1 AA bb 1 BB aa 9 BB aa 9 BB aa 9 BB aa 9 BB aa 9 BB aa 9 BB bb 9 BB bb 9 BB bb 9 BB bb 9 BB bb 9 BB bb 9 CC aa 21 CC aa 21 CC aa 21 CC aa 21 CC bb 21 CC bb 21 DD aa 27 DD aa 27 DD aa 27 DD bb 27 DD bb 27 DD bb 27 DD bb 27 EE aa 34 EE aa 34 EE bb 34 EE bb 34 EE bb 34 FF aa 39 FF aa 39 FF aa 39 FF aa 39 FF bb 39 FF bb 39 FF bb 39 FF bb 39 FF bb 39 FF bb 39 GG aa 49 GG aa 49 GG aa 49 GG aa 49 GG bb 49 GG bb 49 GG bb 49 GG bb 49 HH aa 57 HH aa 57 HH aa 57 HH bb 57 HH bb 57 HH bb 57 HH bb 57 HH bb 57 HH bb 57 II aa 66 II aa 66 II bb 66 II bb 66 II bb 66 II bb 66 II bb 66 JJ aa 73 JJ aa 73 JJ aa 73 JJ aa 73 JJ bb 73 JJ bb 73 JJ bb 73 JJ bb 73} do_execsql_test 1.10.4 { SELECT a, b, max(c) OVER (ORDER BY a,b GROUPS BETWEEN 3 PRECEDING AND 0 FOLLOWING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa 934 AA aa 934 AA aa 934 AA aa 934 AA bb 934 AA bb 934 AA bb 934 AA bb 934 BB aa 934 BB aa 934 BB aa 934 BB aa 934 BB aa 934 BB aa 934 BB bb 934 BB bb 934 BB bb 934 BB bb 934 BB bb 934 BB bb 934 CC aa 870 CC aa 870 CC aa 870 CC aa 870 CC bb 840 CC bb 840 DD aa 845 DD aa 845 DD aa 845 DD bb 959 DD bb 959 DD bb 959 DD bb 959 EE aa 959 EE aa 959 EE bb 959 EE bb 959 EE bb 959 FF aa 959 FF aa 959 FF aa 959 FF aa 959 FF bb 938 FF bb 938 FF bb 938 FF bb 938 FF bb 938 FF bb 938 GG aa 938 GG aa 938 GG aa 938 GG aa 938 GG bb 938 GG bb 938 GG bb 938 GG bb 938 HH aa 979 HH aa 979 HH aa 979 HH bb 979 HH bb 979 HH bb 979 HH bb 979 HH bb 979 HH bb 979 II aa 979 II aa 979 II bb 979 II bb 979 II bb 979 II bb 979 II bb 979 JJ aa 963 JJ aa 963 JJ aa 963 JJ aa 963 JJ bb 899 JJ bb 899 JJ bb 899 JJ bb 899} do_execsql_test 1.10.5 { SELECT a, b, min(c) OVER (ORDER BY a,b GROUPS BETWEEN 3 PRECEDING AND 0 FOLLOWING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa 223 AA aa 223 AA aa 223 AA aa 223 AA bb 223 AA bb 223 AA bb 223 AA bb 223 BB aa 223 BB aa 223 BB aa 223 BB aa 223 BB aa 223 BB aa 223 BB bb 223 BB bb 223 BB bb 223 BB bb 223 BB bb 223 BB bb 223 CC aa 158 CC aa 158 CC aa 158 CC aa 158 CC bb 158 CC bb 158 DD aa 158 DD aa 158 DD aa 158 DD bb 158 DD bb 158 DD bb 158 DD bb 158 EE aa 113 EE aa 113 EE bb 113 EE bb 113 EE bb 113 FF aa 113 FF aa 113 FF aa 113 FF aa 113 FF bb 102 FF bb 102 FF bb 102 FF bb 102 FF bb 102 FF bb 102 GG aa 102 GG aa 102 GG aa 102 GG aa 102 GG bb 102 GG bb 102 GG bb 102 GG bb 102 HH aa 102 HH aa 102 HH aa 102 HH bb 133 HH bb 133 HH bb 133 HH bb 133 HH bb 133 HH bb 133 II aa 133 II aa 133 II bb 133 II bb 133 II bb 133 II bb 133 II bb 133 JJ aa 113 JJ aa 113 JJ aa 113 JJ aa 113 JJ bb 113 JJ bb 113 JJ bb 113 JJ bb 113} do_execsql_test 1.10.6 { SELECT a, b, sum(c) OVER (ORDER BY a GROUPS BETWEEN 3 PRECEDING AND 0 FOLLOWING EXCLUDE CURRENT ROW) FROM t3 ORDER BY 1, 2, 3; } {AA aa 3751 AA aa 3774 AA aa 4446 AA aa 4462 AA bb 3815 AA bb 4058 AA bb 4113 AA bb 4376 BB aa 11263 BB aa 11365 BB aa 11613 BB aa 11626 BB aa 11632 BB aa 11778 BB bb 11185 BB bb 11233 BB bb 11239 BB bb 11314 BB bb 11320 BB bb 11392 CC aa 14388 CC aa 14540 CC aa 14717 CC aa 14989 CC bb 14325 CC bb 14801 DD aa 18334 DD aa 18923 DD aa 18955 DD bb 18220 DD bb 18385 DD bb 18463 DD bb 18941 EE aa 16256 EE aa 16920 EE bb 16265 EE bb 16404 EE bb 16781 FF aa 14691 FF aa 14694 FF aa 14743 FF aa 15153 FF bb 14423 FF bb 14491 FF bb 14635 FF bb 14787 FF bb 15066 FF bb 15259 GG aa 16073 GG aa 16227 GG aa 16372 GG aa 16559 GG bb 15769 GG bb 15778 GG bb 15863 GG bb 16547 HH aa 17139 HH aa 17328 HH aa 17638 HH bb 17155 HH bb 17388 HH bb 17435 HH bb 17763 HH bb 17788 HH bb 17985 II aa 18567 II aa 18821 II bb 18414 II bb 18548 II bb 18776 II bb 18798 II bb 18969 JJ aa 16452 JJ aa 16583 JJ aa 17117 JJ aa 17238 JJ bb 16512 JJ bb 16997 JJ bb 17015 JJ bb 17094} do_execsql_test 1.10.7 { SELECT a, b, sum(c) OVER (ORDER BY a,b GROUPS BETWEEN 3 PRECEDING AND 0 FOLLOWING EXCLUDE CURRENT ROW) FROM t3 ORDER BY 1, 2, 3; } {AA aa 1373 AA aa 1396 AA aa 2068 AA aa 2084 AA bb 3815 AA bb 4058 AA bb 4113 AA bb 4376 BB aa 6796 BB aa 6898 BB aa 7146 BB aa 7159 BB aa 7165 BB aa 7311 BB bb 11185 BB bb 11233 BB bb 11239 BB bb 11314 BB bb 11320 BB bb 11392 CC aa 10913 CC aa 11065 CC aa 11242 CC aa 11514 CC bb 9640 CC bb 10116 DD aa 8069 DD aa 8658 DD aa 8690 DD bb 6195 DD bb 6360 DD bb 6438 DD bb 6916 EE aa 5313 EE aa 5977 EE bb 5803 EE bb 5942 EE bb 6319 FF aa 6739 FF aa 6742 FF aa 6791 FF aa 7201 FF bb 7269 FF bb 7337 FF bb 7481 FF bb 7633 FF bb 7912 FF bb 8105 GG aa 8280 GG aa 8434 GG aa 8579 GG aa 8766 GG bb 9198 GG bb 9207 GG bb 9292 GG bb 9976 HH aa 9243 HH aa 9432 HH aa 9742 HH bb 8948 HH bb 9181 HH bb 9228 HH bb 9556 HH bb 9581 HH bb 9778 II aa 8712 II aa 8966 II bb 8278 II bb 8412 II bb 8640 II bb 8662 II bb 8833 JJ aa 7949 JJ aa 8080 JJ aa 8614 JJ aa 8735 JJ bb 6601 JJ bb 7086 JJ bb 7104 JJ bb 7183} do_execsql_test 1.10.8 { SELECT a, b, sum(c) OVER (ORDER BY a GROUPS BETWEEN 3 PRECEDING AND 0 FOLLOWING EXCLUDE CURRENT ROW), sum(c) OVER (ORDER BY a GROUPS BETWEEN 3 PRECEDING AND 0 FOLLOWING ), sum(c) OVER (ORDER BY a,b GROUPS BETWEEN 3 PRECEDING AND 0 FOLLOWING EXCLUDE CURRENT ROW), sum(c) OVER (ORDER BY a,b GROUPS BETWEEN 3 PRECEDING AND 0 FOLLOWING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa 3751 4685 1373 2307 AA aa 3774 4685 1396 2307 AA aa 4446 4685 2068 2307 AA aa 4462 4685 2084 2307 AA bb 3815 4685 3815 4685 AA bb 4058 4685 4058 4685 AA bb 4113 4685 4113 4685 AA bb 4376 4685 4376 4685 BB aa 11263 12025 6796 7558 BB aa 11365 12025 6898 7558 BB aa 11613 12025 7146 7558 BB aa 11626 12025 7159 7558 BB aa 11632 12025 7165 7558 BB aa 11778 12025 7311 7558 BB bb 11185 12025 11185 12025 BB bb 11233 12025 11233 12025 BB bb 11239 12025 11239 12025 BB bb 11314 12025 11314 12025 BB bb 11320 12025 11320 12025 BB bb 11392 12025 11392 12025 CC aa 14388 15147 10913 11672 CC aa 14540 15147 11065 11672 CC aa 14717 15147 11242 11672 CC aa 14989 15147 11514 11672 CC bb 14325 15147 9640 10462 CC bb 14801 15147 10116 10462 DD aa 18334 19179 8069 8914 DD aa 18923 19179 8658 8914 DD aa 18955 19179 8690 8914 DD bb 18220 19179 6195 7154 DD bb 18385 19179 6360 7154 DD bb 18463 19179 6438 7154 DD bb 18941 19179 6916 7154 EE aa 16256 17033 5313 6090 EE aa 16920 17033 5977 6090 EE bb 16265 17033 5803 6571 EE bb 16404 17033 5942 6571 EE bb 16781 17033 6319 6571 FF aa 14691 15361 6739 7409 FF aa 14694 15361 6742 7409 FF aa 14743 15361 6791 7409 FF aa 15153 15361 7201 7409 FF bb 14423 15361 7269 8207 FF bb 14491 15361 7337 8207 FF bb 14635 15361 7481 8207 FF bb 14787 15361 7633 8207 FF bb 15066 15361 7912 8207 FF bb 15259 15361 8105 8207 GG aa 16073 16707 8280 8914 GG aa 16227 16707 8434 8914 GG aa 16372 16707 8579 8914 GG aa 16559 16707 8766 8914 GG bb 15769 16707 9198 10136 GG bb 15778 16707 9207 10136 GG bb 15863 16707 9292 10136 GG bb 16547 16707 9976 10136 HH aa 17139 18118 9243 10222 HH aa 17328 18118 9432 10222 HH aa 17638 18118 9742 10222 HH bb 17155 18118 8948 9911 HH bb 17388 18118 9181 9911 HH bb 17435 18118 9228 9911 HH bb 17763 18118 9556 9911 HH bb 17788 18118 9581 9911 HH bb 17985 18118 9778 9911 II aa 18567 19219 8712 9364 II aa 18821 19219 8966 9364 II bb 18414 19219 8278 9083 II bb 18548 19219 8412 9083 II bb 18776 19219 8640 9083 II bb 18798 19219 8662 9083 II bb 18969 19219 8833 9083 JJ aa 16452 17351 7949 8848 JJ aa 16583 17351 8080 8848 JJ aa 17117 17351 8614 8848 JJ aa 17238 17351 8735 8848 JJ bb 16512 17351 6601 7440 JJ bb 16997 17351 7086 7440 JJ bb 17015 17351 7104 7440 JJ bb 17094 17351 7183 7440} do_execsql_test 1.11.1 { SELECT a, b, sum(c) OVER (ORDER BY a GROUPS BETWEEN 2 PRECEDING AND UNBOUNDED FOLLOWING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa 44737 AA aa 44737 AA aa 44737 AA aa 44737 AA bb 44737 AA bb 44737 AA bb 44737 AA bb 44737 BB aa 44737 BB aa 44737 BB aa 44737 BB aa 44737 BB aa 44737 BB aa 44737 BB bb 44737 BB bb 44737 BB bb 44737 BB bb 44737 BB bb 44737 BB bb 44737 CC aa 44737 CC aa 44737 CC aa 44737 CC aa 44737 CC bb 44737 CC bb 44737 DD aa 40052 DD aa 40052 DD aa 40052 DD bb 40052 DD bb 40052 DD bb 40052 DD bb 40052 EE aa 32712 EE aa 32712 EE bb 32712 EE bb 32712 EE bb 32712 FF aa 29590 FF aa 29590 FF aa 29590 FF aa 29590 FF bb 29590 FF bb 29590 FF bb 29590 FF bb 29590 FF bb 29590 FF bb 29590 GG aa 25558 GG aa 25558 GG aa 25558 GG aa 25558 GG bb 25558 GG bb 25558 GG bb 25558 GG bb 25558 HH aa 23019 HH aa 23019 HH aa 23019 HH bb 23019 HH bb 23019 HH bb 23019 HH bb 23019 HH bb 23019 HH bb 23019 II aa 17351 II aa 17351 II bb 17351 II bb 17351 II bb 17351 II bb 17351 II bb 17351 JJ aa 12883 JJ aa 12883 JJ aa 12883 JJ aa 12883 JJ bb 12883 JJ bb 12883 JJ bb 12883 JJ bb 12883} do_execsql_test 1.11.2 { SELECT a, b, sum(c) OVER (ORDER BY a,b GROUPS BETWEEN 2 PRECEDING AND UNBOUNDED FOLLOWING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa 44737 AA aa 44737 AA aa 44737 AA aa 44737 AA bb 44737 AA bb 44737 AA bb 44737 AA bb 44737 BB aa 44737 BB aa 44737 BB aa 44737 BB aa 44737 BB aa 44737 BB aa 44737 BB bb 42430 BB bb 42430 BB bb 42430 BB bb 42430 BB bb 42430 BB bb 42430 CC aa 40052 CC aa 40052 CC aa 40052 CC aa 40052 CC bb 37179 CC bb 37179 DD aa 32712 DD aa 32712 DD aa 32712 DD bb 30758 DD bb 30758 DD bb 30758 DD bb 30758 EE aa 29590 EE aa 29590 EE bb 28265 EE bb 28265 EE bb 28265 FF aa 25558 FF aa 25558 FF aa 25558 FF aa 25558 FF bb 24668 FF bb 24668 FF bb 24668 FF bb 24668 FF bb 24668 FF bb 24668 GG aa 23019 GG aa 23019 GG aa 23019 GG aa 23019 GG bb 20856 GG bb 20856 GG bb 20856 GG bb 20856 HH aa 17351 HH aa 17351 HH aa 17351 HH bb 15754 HH bb 15754 HH bb 15754 HH bb 15754 HH bb 15754 HH bb 15754 II aa 12883 II aa 12883 II bb 10634 II bb 10634 II bb 10634 II bb 10634 II bb 10634 JJ aa 7440 JJ aa 7440 JJ aa 7440 JJ aa 7440 JJ bb 6390 JJ bb 6390 JJ bb 6390 JJ bb 6390} do_execsql_test 1.11.3 { SELECT a, b, rank() OVER (ORDER BY a GROUPS BETWEEN 2 PRECEDING AND UNBOUNDED FOLLOWING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa 1 AA aa 1 AA aa 1 AA aa 1 AA bb 1 AA bb 1 AA bb 1 AA bb 1 BB aa 9 BB aa 9 BB aa 9 BB aa 9 BB aa 9 BB aa 9 BB bb 9 BB bb 9 BB bb 9 BB bb 9 BB bb 9 BB bb 9 CC aa 21 CC aa 21 CC aa 21 CC aa 21 CC bb 21 CC bb 21 DD aa 27 DD aa 27 DD aa 27 DD bb 27 DD bb 27 DD bb 27 DD bb 27 EE aa 34 EE aa 34 EE bb 34 EE bb 34 EE bb 34 FF aa 39 FF aa 39 FF aa 39 FF aa 39 FF bb 39 FF bb 39 FF bb 39 FF bb 39 FF bb 39 FF bb 39 GG aa 49 GG aa 49 GG aa 49 GG aa 49 GG bb 49 GG bb 49 GG bb 49 GG bb 49 HH aa 57 HH aa 57 HH aa 57 HH bb 57 HH bb 57 HH bb 57 HH bb 57 HH bb 57 HH bb 57 II aa 66 II aa 66 II bb 66 II bb 66 II bb 66 II bb 66 II bb 66 JJ aa 73 JJ aa 73 JJ aa 73 JJ aa 73 JJ bb 73 JJ bb 73 JJ bb 73 JJ bb 73} do_execsql_test 1.11.4 { SELECT a, b, max(c) OVER (ORDER BY a,b GROUPS BETWEEN 2 PRECEDING AND UNBOUNDED FOLLOWING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa 979 AA aa 979 AA aa 979 AA aa 979 AA bb 979 AA bb 979 AA bb 979 AA bb 979 BB aa 979 BB aa 979 BB aa 979 BB aa 979 BB aa 979 BB aa 979 BB bb 979 BB bb 979 BB bb 979 BB bb 979 BB bb 979 BB bb 979 CC aa 979 CC aa 979 CC aa 979 CC aa 979 CC bb 979 CC bb 979 DD aa 979 DD aa 979 DD aa 979 DD bb 979 DD bb 979 DD bb 979 DD bb 979 EE aa 979 EE aa 979 EE bb 979 EE bb 979 EE bb 979 FF aa 979 FF aa 979 FF aa 979 FF aa 979 FF bb 979 FF bb 979 FF bb 979 FF bb 979 FF bb 979 FF bb 979 GG aa 979 GG aa 979 GG aa 979 GG aa 979 GG bb 979 GG bb 979 GG bb 979 GG bb 979 HH aa 979 HH aa 979 HH aa 979 HH bb 979 HH bb 979 HH bb 979 HH bb 979 HH bb 979 HH bb 979 II aa 979 II aa 979 II bb 963 II bb 963 II bb 963 II bb 963 II bb 963 JJ aa 899 JJ aa 899 JJ aa 899 JJ aa 899 JJ bb 899 JJ bb 899 JJ bb 899 JJ bb 899} do_execsql_test 1.11.5 { SELECT a, b, min(c) OVER (ORDER BY a,b GROUPS BETWEEN 2 PRECEDING AND UNBOUNDED FOLLOWING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa 102 AA aa 102 AA aa 102 AA aa 102 AA bb 102 AA bb 102 AA bb 102 AA bb 102 BB aa 102 BB aa 102 BB aa 102 BB aa 102 BB aa 102 BB aa 102 BB bb 102 BB bb 102 BB bb 102 BB bb 102 BB bb 102 BB bb 102 CC aa 102 CC aa 102 CC aa 102 CC aa 102 CC bb 102 CC bb 102 DD aa 102 DD aa 102 DD aa 102 DD bb 102 DD bb 102 DD bb 102 DD bb 102 EE aa 102 EE aa 102 EE bb 102 EE bb 102 EE bb 102 FF aa 102 FF aa 102 FF aa 102 FF aa 102 FF bb 102 FF bb 102 FF bb 102 FF bb 102 FF bb 102 FF bb 102 GG aa 102 GG aa 102 GG aa 102 GG aa 102 GG bb 102 GG bb 102 GG bb 102 GG bb 102 HH aa 113 HH aa 113 HH aa 113 HH bb 113 HH bb 113 HH bb 113 HH bb 113 HH bb 113 HH bb 113 II aa 113 II aa 113 II bb 113 II bb 113 II bb 113 II bb 113 II bb 113 JJ aa 113 JJ aa 113 JJ aa 113 JJ aa 113 JJ bb 113 JJ bb 113 JJ bb 113 JJ bb 113} do_execsql_test 1.11.6 { SELECT a, b, sum(c) OVER (ORDER BY a GROUPS BETWEEN 2 PRECEDING AND UNBOUNDED FOLLOWING EXCLUDE CURRENT ROW) FROM t3 ORDER BY 1, 2, 3; } {AA aa 43803 AA aa 43826 AA aa 44498 AA aa 44514 AA bb 43867 AA bb 44110 AA bb 44165 AA bb 44428 BB aa 43975 BB aa 44077 BB aa 44325 BB aa 44338 BB aa 44344 BB aa 44490 BB bb 43897 BB bb 43945 BB bb 43951 BB bb 44026 BB bb 44032 BB bb 44104 CC aa 43978 CC aa 44130 CC aa 44307 CC aa 44579 CC bb 43915 CC bb 44391 DD aa 39207 DD aa 39796 DD aa 39828 DD bb 39093 DD bb 39258 DD bb 39336 DD bb 39814 EE aa 31935 EE aa 32599 EE bb 31944 EE bb 32083 EE bb 32460 FF aa 28920 FF aa 28923 FF aa 28972 FF aa 29382 FF bb 28652 FF bb 28720 FF bb 28864 FF bb 29016 FF bb 29295 FF bb 29488 GG aa 24924 GG aa 25078 GG aa 25223 GG aa 25410 GG bb 24620 GG bb 24629 GG bb 24714 GG bb 25398 HH aa 22040 HH aa 22229 HH aa 22539 HH bb 22056 HH bb 22289 HH bb 22336 HH bb 22664 HH bb 22689 HH bb 22886 II aa 16699 II aa 16953 II bb 16546 II bb 16680 II bb 16908 II bb 16930 II bb 17101 JJ aa 11984 JJ aa 12115 JJ aa 12649 JJ aa 12770 JJ bb 12044 JJ bb 12529 JJ bb 12547 JJ bb 12626} do_execsql_test 1.11.7 { SELECT a, b, sum(c) OVER (ORDER BY a,b GROUPS BETWEEN 2 PRECEDING AND UNBOUNDED FOLLOWING EXCLUDE CURRENT ROW) FROM t3 ORDER BY 1, 2, 3; } {AA aa 43803 AA aa 43826 AA aa 44498 AA aa 44514 AA bb 43867 AA bb 44110 AA bb 44165 AA bb 44428 BB aa 43975 BB aa 44077 BB aa 44325 BB aa 44338 BB aa 44344 BB aa 44490 BB bb 41590 BB bb 41638 BB bb 41644 BB bb 41719 BB bb 41725 BB bb 41797 CC aa 39293 CC aa 39445 CC aa 39622 CC aa 39894 CC bb 36357 CC bb 36833 DD aa 31867 DD aa 32456 DD aa 32488 DD bb 29799 DD bb 29964 DD bb 30042 DD bb 30520 EE aa 28813 EE aa 29477 EE bb 27497 EE bb 27636 EE bb 28013 FF aa 24888 FF aa 24891 FF aa 24940 FF aa 25350 FF bb 23730 FF bb 23798 FF bb 23942 FF bb 24094 FF bb 24373 FF bb 24566 GG aa 22385 GG aa 22539 GG aa 22684 GG aa 22871 GG bb 19918 GG bb 19927 GG bb 20012 GG bb 20696 HH aa 16372 HH aa 16561 HH aa 16871 HH bb 14791 HH bb 15024 HH bb 15071 HH bb 15399 HH bb 15424 HH bb 15621 II aa 12231 II aa 12485 II bb 9829 II bb 9963 II bb 10191 II bb 10213 II bb 10384 JJ aa 6541 JJ aa 6672 JJ aa 7206 JJ aa 7327 JJ bb 5551 JJ bb 6036 JJ bb 6054 JJ bb 6133} do_execsql_test 1.11.8 { SELECT a, b, sum(c) OVER (ORDER BY a GROUPS BETWEEN 2 PRECEDING AND UNBOUNDED FOLLOWING EXCLUDE CURRENT ROW), sum(c) OVER (ORDER BY a GROUPS BETWEEN 2 PRECEDING AND UNBOUNDED FOLLOWING ), sum(c) OVER (ORDER BY a,b GROUPS BETWEEN 2 PRECEDING AND UNBOUNDED FOLLOWING EXCLUDE CURRENT ROW), sum(c) OVER (ORDER BY a,b GROUPS BETWEEN 2 PRECEDING AND UNBOUNDED FOLLOWING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa 43803 44737 43803 44737 AA aa 43826 44737 43826 44737 AA aa 44498 44737 44498 44737 AA aa 44514 44737 44514 44737 AA bb 43867 44737 43867 44737 AA bb 44110 44737 44110 44737 AA bb 44165 44737 44165 44737 AA bb 44428 44737 44428 44737 BB aa 43975 44737 43975 44737 BB aa 44077 44737 44077 44737 BB aa 44325 44737 44325 44737 BB aa 44338 44737 44338 44737 BB aa 44344 44737 44344 44737 BB aa 44490 44737 44490 44737 BB bb 43897 44737 41590 42430 BB bb 43945 44737 41638 42430 BB bb 43951 44737 41644 42430 BB bb 44026 44737 41719 42430 BB bb 44032 44737 41725 42430 BB bb 44104 44737 41797 42430 CC aa 43978 44737 39293 40052 CC aa 44130 44737 39445 40052 CC aa 44307 44737 39622 40052 CC aa 44579 44737 39894 40052 CC bb 43915 44737 36357 37179 CC bb 44391 44737 36833 37179 DD aa 39207 40052 31867 32712 DD aa 39796 40052 32456 32712 DD aa 39828 40052 32488 32712 DD bb 39093 40052 29799 30758 DD bb 39258 40052 29964 30758 DD bb 39336 40052 30042 30758 DD bb 39814 40052 30520 30758 EE aa 31935 32712 28813 29590 EE aa 32599 32712 29477 29590 EE bb 31944 32712 27497 28265 EE bb 32083 32712 27636 28265 EE bb 32460 32712 28013 28265 FF aa 28920 29590 24888 25558 FF aa 28923 29590 24891 25558 FF aa 28972 29590 24940 25558 FF aa 29382 29590 25350 25558 FF bb 28652 29590 23730 24668 FF bb 28720 29590 23798 24668 FF bb 28864 29590 23942 24668 FF bb 29016 29590 24094 24668 FF bb 29295 29590 24373 24668 FF bb 29488 29590 24566 24668 GG aa 24924 25558 22385 23019 GG aa 25078 25558 22539 23019 GG aa 25223 25558 22684 23019 GG aa 25410 25558 22871 23019 GG bb 24620 25558 19918 20856 GG bb 24629 25558 19927 20856 GG bb 24714 25558 20012 20856 GG bb 25398 25558 20696 20856 HH aa 22040 23019 16372 17351 HH aa 22229 23019 16561 17351 HH aa 22539 23019 16871 17351 HH bb 22056 23019 14791 15754 HH bb 22289 23019 15024 15754 HH bb 22336 23019 15071 15754 HH bb 22664 23019 15399 15754 HH bb 22689 23019 15424 15754 HH bb 22886 23019 15621 15754 II aa 16699 17351 12231 12883 II aa 16953 17351 12485 12883 II bb 16546 17351 9829 10634 II bb 16680 17351 9963 10634 II bb 16908 17351 10191 10634 II bb 16930 17351 10213 10634 II bb 17101 17351 10384 10634 JJ aa 11984 12883 6541 7440 JJ aa 12115 12883 6672 7440 JJ aa 12649 12883 7206 7440 JJ aa 12770 12883 7327 7440 JJ bb 12044 12883 5551 6390 JJ bb 12529 12883 6036 6390 JJ bb 12547 12883 6054 6390 JJ bb 12626 12883 6133 6390} do_execsql_test 1.12.1 { SELECT a, b, sum(c) OVER (ORDER BY a GROUPS BETWEEN CURRENT ROW AND 0 FOLLOWING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa 4685 AA aa 4685 AA aa 4685 AA aa 4685 AA bb 4685 AA bb 4685 AA bb 4685 AA bb 4685 BB aa 7340 BB aa 7340 BB aa 7340 BB aa 7340 BB aa 7340 BB aa 7340 BB bb 7340 BB bb 7340 BB bb 7340 BB bb 7340 BB bb 7340 BB bb 7340 CC aa 3122 CC aa 3122 CC aa 3122 CC aa 3122 CC bb 3122 CC bb 3122 DD aa 4032 DD aa 4032 DD aa 4032 DD bb 4032 DD bb 4032 DD bb 4032 DD bb 4032 EE aa 2539 EE aa 2539 EE bb 2539 EE bb 2539 EE bb 2539 FF aa 5668 FF aa 5668 FF aa 5668 FF aa 5668 FF bb 5668 FF bb 5668 FF bb 5668 FF bb 5668 FF bb 5668 FF bb 5668 GG aa 4468 GG aa 4468 GG aa 4468 GG aa 4468 GG bb 4468 GG bb 4468 GG bb 4468 GG bb 4468 HH aa 5443 HH aa 5443 HH aa 5443 HH bb 5443 HH bb 5443 HH bb 5443 HH bb 5443 HH bb 5443 HH bb 5443 II aa 3640 II aa 3640 II bb 3640 II bb 3640 II bb 3640 II bb 3640 II bb 3640 JJ aa 3800 JJ aa 3800 JJ aa 3800 JJ aa 3800 JJ bb 3800 JJ bb 3800 JJ bb 3800 JJ bb 3800} do_execsql_test 1.12.2 { SELECT a, b, sum(c) OVER (ORDER BY a,b GROUPS BETWEEN CURRENT ROW AND 0 FOLLOWING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa 2307 AA aa 2307 AA aa 2307 AA aa 2307 AA bb 2378 AA bb 2378 AA bb 2378 AA bb 2378 BB aa 2873 BB aa 2873 BB aa 2873 BB aa 2873 BB aa 2873 BB aa 2873 BB bb 4467 BB bb 4467 BB bb 4467 BB bb 4467 BB bb 4467 BB bb 4467 CC aa 1954 CC aa 1954 CC aa 1954 CC aa 1954 CC bb 1168 CC bb 1168 DD aa 1325 DD aa 1325 DD aa 1325 DD bb 2707 DD bb 2707 DD bb 2707 DD bb 2707 EE aa 890 EE aa 890 EE bb 1649 EE bb 1649 EE bb 1649 FF aa 2163 FF aa 2163 FF aa 2163 FF aa 2163 FF bb 3505 FF bb 3505 FF bb 3505 FF bb 3505 FF bb 3505 FF bb 3505 GG aa 1597 GG aa 1597 GG aa 1597 GG aa 1597 GG bb 2871 GG bb 2871 GG bb 2871 GG bb 2871 HH aa 2249 HH aa 2249 HH aa 2249 HH bb 3194 HH bb 3194 HH bb 3194 HH bb 3194 HH bb 3194 HH bb 3194 II aa 1050 II aa 1050 II bb 2590 II bb 2590 II bb 2590 II bb 2590 II bb 2590 JJ aa 2014 JJ aa 2014 JJ aa 2014 JJ aa 2014 JJ bb 1786 JJ bb 1786 JJ bb 1786 JJ bb 1786} do_execsql_test 1.12.3 { SELECT a, b, rank() OVER (ORDER BY a GROUPS BETWEEN CURRENT ROW AND 0 FOLLOWING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa 1 AA aa 1 AA aa 1 AA aa 1 AA bb 1 AA bb 1 AA bb 1 AA bb 1 BB aa 9 BB aa 9 BB aa 9 BB aa 9 BB aa 9 BB aa 9 BB bb 9 BB bb 9 BB bb 9 BB bb 9 BB bb 9 BB bb 9 CC aa 21 CC aa 21 CC aa 21 CC aa 21 CC bb 21 CC bb 21 DD aa 27 DD aa 27 DD aa 27 DD bb 27 DD bb 27 DD bb 27 DD bb 27 EE aa 34 EE aa 34 EE bb 34 EE bb 34 EE bb 34 FF aa 39 FF aa 39 FF aa 39 FF aa 39 FF bb 39 FF bb 39 FF bb 39 FF bb 39 FF bb 39 FF bb 39 GG aa 49 GG aa 49 GG aa 49 GG aa 49 GG bb 49 GG bb 49 GG bb 49 GG bb 49 HH aa 57 HH aa 57 HH aa 57 HH bb 57 HH bb 57 HH bb 57 HH bb 57 HH bb 57 HH bb 57 II aa 66 II aa 66 II bb 66 II bb 66 II bb 66 II bb 66 II bb 66 JJ aa 73 JJ aa 73 JJ aa 73 JJ aa 73 JJ bb 73 JJ bb 73 JJ bb 73 JJ bb 73} do_execsql_test 1.12.4 { SELECT a, b, max(c) OVER (ORDER BY a,b GROUPS BETWEEN CURRENT ROW AND 0 FOLLOWING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa 934 AA aa 934 AA aa 934 AA aa 934 AA bb 870 AA bb 870 AA bb 870 AA bb 870 BB aa 762 BB aa 762 BB aa 762 BB aa 762 BB aa 762 BB aa 762 BB bb 840 BB bb 840 BB bb 840 BB bb 840 BB bb 840 BB bb 840 CC aa 759 CC aa 759 CC aa 759 CC aa 759 CC bb 822 CC bb 822 DD aa 845 DD aa 845 DD aa 845 DD bb 959 DD bb 959 DD bb 959 DD bb 959 EE aa 777 EE aa 777 EE bb 768 EE bb 768 EE bb 768 FF aa 670 FF aa 670 FF aa 670 FF aa 670 FF bb 938 FF bb 938 FF bb 938 FF bb 938 FF bb 938 FF bb 938 GG aa 634 GG aa 634 GG aa 634 GG aa 634 GG bb 938 GG bb 938 GG bb 938 GG bb 938 HH aa 979 HH aa 979 HH aa 979 HH bb 963 HH bb 963 HH bb 963 HH bb 963 HH bb 963 HH bb 963 II aa 652 II aa 652 II bb 805 II bb 805 II bb 805 II bb 805 II bb 805 JJ aa 899 JJ aa 899 JJ aa 899 JJ aa 899 JJ bb 839 JJ bb 839 JJ bb 839 JJ bb 839} do_execsql_test 1.12.5 { SELECT a, b, min(c) OVER (ORDER BY a,b GROUPS BETWEEN CURRENT ROW AND 0 FOLLOWING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa 223 AA aa 223 AA aa 223 AA aa 223 AA bb 309 AA bb 309 AA bb 309 AA bb 309 BB aa 247 BB aa 247 BB aa 247 BB aa 247 BB aa 247 BB aa 247 BB bb 633 BB bb 633 BB bb 633 BB bb 633 BB bb 633 BB bb 633 CC aa 158 CC aa 158 CC aa 158 CC aa 158 CC bb 346 CC bb 346 DD aa 224 DD aa 224 DD aa 224 DD bb 238 DD bb 238 DD bb 238 DD bb 238 EE aa 113 EE aa 113 EE bb 252 EE bb 252 EE bb 252 FF aa 208 FF aa 208 FF aa 208 FF aa 208 FF bb 102 FF bb 102 FF bb 102 FF bb 102 FF bb 102 FF bb 102 GG aa 148 GG aa 148 GG aa 148 GG aa 148 GG bb 160 GG bb 160 GG bb 160 GG bb 160 HH aa 480 HH aa 480 HH aa 480 HH bb 133 HH bb 133 HH bb 133 HH bb 133 HH bb 133 HH bb 133 II aa 398 II aa 398 II bb 250 II bb 250 II bb 250 II bb 250 II bb 250 JJ aa 113 JJ aa 113 JJ aa 113 JJ aa 113 JJ bb 257 JJ bb 257 JJ bb 257 JJ bb 257} do_execsql_test 1.12.6 { SELECT a, b, sum(c) OVER (ORDER BY a GROUPS BETWEEN CURRENT ROW AND 0 FOLLOWING EXCLUDE CURRENT ROW) FROM t3 ORDER BY 1, 2, 3; } {AA aa 3751 AA aa 3774 AA aa 4446 AA aa 4462 AA bb 3815 AA bb 4058 AA bb 4113 AA bb 4376 BB aa 6578 BB aa 6680 BB aa 6928 BB aa 6941 BB aa 6947 BB aa 7093 BB bb 6500 BB bb 6548 BB bb 6554 BB bb 6629 BB bb 6635 BB bb 6707 CC aa 2363 CC aa 2515 CC aa 2692 CC aa 2964 CC bb 2300 CC bb 2776 DD aa 3187 DD aa 3776 DD aa 3808 DD bb 3073 DD bb 3238 DD bb 3316 DD bb 3794 EE aa 1762 EE aa 2426 EE bb 1771 EE bb 1910 EE bb 2287 FF aa 4998 FF aa 5001 FF aa 5050 FF aa 5460 FF bb 4730 FF bb 4798 FF bb 4942 FF bb 5094 FF bb 5373 FF bb 5566 GG aa 3834 GG aa 3988 GG aa 4133 GG aa 4320 GG bb 3530 GG bb 3539 GG bb 3624 GG bb 4308 HH aa 4464 HH aa 4653 HH aa 4963 HH bb 4480 HH bb 4713 HH bb 4760 HH bb 5088 HH bb 5113 HH bb 5310 II aa 2988 II aa 3242 II bb 2835 II bb 2969 II bb 3197 II bb 3219 II bb 3390 JJ aa 2901 JJ aa 3032 JJ aa 3566 JJ aa 3687 JJ bb 2961 JJ bb 3446 JJ bb 3464 JJ bb 3543} do_execsql_test 1.12.7 { SELECT a, b, sum(c) OVER (ORDER BY a,b GROUPS BETWEEN CURRENT ROW AND 0 FOLLOWING EXCLUDE CURRENT ROW) FROM t3 ORDER BY 1, 2, 3; } {AA aa 1373 AA aa 1396 AA aa 2068 AA aa 2084 AA bb 1508 AA bb 1751 AA bb 1806 AA bb 2069 BB aa 2111 BB aa 2213 BB aa 2461 BB aa 2474 BB aa 2480 BB aa 2626 BB bb 3627 BB bb 3675 BB bb 3681 BB bb 3756 BB bb 3762 BB bb 3834 CC aa 1195 CC aa 1347 CC aa 1524 CC aa 1796 CC bb 346 CC bb 822 DD aa 480 DD aa 1069 DD aa 1101 DD bb 1748 DD bb 1913 DD bb 1991 DD bb 2469 EE aa 113 EE aa 777 EE bb 881 EE bb 1020 EE bb 1397 FF aa 1493 FF aa 1496 FF aa 1545 FF aa 1955 FF bb 2567 FF bb 2635 FF bb 2779 FF bb 2931 FF bb 3210 FF bb 3403 GG aa 963 GG aa 1117 GG aa 1262 GG aa 1449 GG bb 1933 GG bb 1942 GG bb 2027 GG bb 2711 HH aa 1270 HH aa 1459 HH aa 1769 HH bb 2231 HH bb 2464 HH bb 2511 HH bb 2839 HH bb 2864 HH bb 3061 II aa 398 II aa 652 II bb 1785 II bb 1919 II bb 2147 II bb 2169 II bb 2340 JJ aa 1115 JJ aa 1246 JJ aa 1780 JJ aa 1901 JJ bb 947 JJ bb 1432 JJ bb 1450 JJ bb 1529} do_execsql_test 1.12.8 { SELECT a, b, sum(c) OVER (ORDER BY a GROUPS BETWEEN CURRENT ROW AND 0 FOLLOWING EXCLUDE CURRENT ROW), sum(c) OVER (ORDER BY a GROUPS BETWEEN CURRENT ROW AND 0 FOLLOWING ), sum(c) OVER (ORDER BY a,b GROUPS BETWEEN CURRENT ROW AND 0 FOLLOWING EXCLUDE CURRENT ROW), sum(c) OVER (ORDER BY a,b GROUPS BETWEEN CURRENT ROW AND 0 FOLLOWING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa 3751 4685 1373 2307 AA aa 3774 4685 1396 2307 AA aa 4446 4685 2068 2307 AA aa 4462 4685 2084 2307 AA bb 3815 4685 1508 2378 AA bb 4058 4685 1751 2378 AA bb 4113 4685 1806 2378 AA bb 4376 4685 2069 2378 BB aa 6578 7340 2111 2873 BB aa 6680 7340 2213 2873 BB aa 6928 7340 2461 2873 BB aa 6941 7340 2474 2873 BB aa 6947 7340 2480 2873 BB aa 7093 7340 2626 2873 BB bb 6500 7340 3627 4467 BB bb 6548 7340 3675 4467 BB bb 6554 7340 3681 4467 BB bb 6629 7340 3756 4467 BB bb 6635 7340 3762 4467 BB bb 6707 7340 3834 4467 CC aa 2363 3122 1195 1954 CC aa 2515 3122 1347 1954 CC aa 2692 3122 1524 1954 CC aa 2964 3122 1796 1954 CC bb 2300 3122 346 1168 CC bb 2776 3122 822 1168 DD aa 3187 4032 480 1325 DD aa 3776 4032 1069 1325 DD aa 3808 4032 1101 1325 DD bb 3073 4032 1748 2707 DD bb 3238 4032 1913 2707 DD bb 3316 4032 1991 2707 DD bb 3794 4032 2469 2707 EE aa 1762 2539 113 890 EE aa 2426 2539 777 890 EE bb 1771 2539 881 1649 EE bb 1910 2539 1020 1649 EE bb 2287 2539 1397 1649 FF aa 4998 5668 1493 2163 FF aa 5001 5668 1496 2163 FF aa 5050 5668 1545 2163 FF aa 5460 5668 1955 2163 FF bb 4730 5668 2567 3505 FF bb 4798 5668 2635 3505 FF bb 4942 5668 2779 3505 FF bb 5094 5668 2931 3505 FF bb 5373 5668 3210 3505 FF bb 5566 5668 3403 3505 GG aa 3834 4468 963 1597 GG aa 3988 4468 1117 1597 GG aa 4133 4468 1262 1597 GG aa 4320 4468 1449 1597 GG bb 3530 4468 1933 2871 GG bb 3539 4468 1942 2871 GG bb 3624 4468 2027 2871 GG bb 4308 4468 2711 2871 HH aa 4464 5443 1270 2249 HH aa 4653 5443 1459 2249 HH aa 4963 5443 1769 2249 HH bb 4480 5443 2231 3194 HH bb 4713 5443 2464 3194 HH bb 4760 5443 2511 3194 HH bb 5088 5443 2839 3194 HH bb 5113 5443 2864 3194 HH bb 5310 5443 3061 3194 II aa 2988 3640 398 1050 II aa 3242 3640 652 1050 II bb 2835 3640 1785 2590 II bb 2969 3640 1919 2590 II bb 3197 3640 2147 2590 II bb 3219 3640 2169 2590 II bb 3390 3640 2340 2590 JJ aa 2901 3800 1115 2014 JJ aa 3032 3800 1246 2014 JJ aa 3566 3800 1780 2014 JJ aa 3687 3800 1901 2014 JJ bb 2961 3800 947 1786 JJ bb 3446 3800 1432 1786 JJ bb 3464 3800 1450 1786 JJ bb 3543 3800 1529 1786} do_execsql_test 1.13.1 { SELECT a, b, sum(c) OVER (ORDER BY a GROUPS BETWEEN CURRENT ROW AND 1 FOLLOWING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa 12025 AA aa 12025 AA aa 12025 AA aa 12025 AA bb 12025 AA bb 12025 AA bb 12025 AA bb 12025 BB aa 10462 BB aa 10462 BB aa 10462 BB aa 10462 BB aa 10462 BB aa 10462 BB bb 10462 BB bb 10462 BB bb 10462 BB bb 10462 BB bb 10462 BB bb 10462 CC aa 7154 CC aa 7154 CC aa 7154 CC aa 7154 CC bb 7154 CC bb 7154 DD aa 6571 DD aa 6571 DD aa 6571 DD bb 6571 DD bb 6571 DD bb 6571 DD bb 6571 EE aa 8207 EE aa 8207 EE bb 8207 EE bb 8207 EE bb 8207 FF aa 10136 FF aa 10136 FF aa 10136 FF aa 10136 FF bb 10136 FF bb 10136 FF bb 10136 FF bb 10136 FF bb 10136 FF bb 10136 GG aa 9911 GG aa 9911 GG aa 9911 GG aa 9911 GG bb 9911 GG bb 9911 GG bb 9911 GG bb 9911 HH aa 9083 HH aa 9083 HH aa 9083 HH bb 9083 HH bb 9083 HH bb 9083 HH bb 9083 HH bb 9083 HH bb 9083 II aa 7440 II aa 7440 II bb 7440 II bb 7440 II bb 7440 II bb 7440 II bb 7440 JJ aa 3800 JJ aa 3800 JJ aa 3800 JJ aa 3800 JJ bb 3800 JJ bb 3800 JJ bb 3800 JJ bb 3800} do_execsql_test 1.13.2 { SELECT a, b, sum(c) OVER (ORDER BY a,b GROUPS BETWEEN CURRENT ROW AND 1 FOLLOWING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa 4685 AA aa 4685 AA aa 4685 AA aa 4685 AA bb 5251 AA bb 5251 AA bb 5251 AA bb 5251 BB aa 7340 BB aa 7340 BB aa 7340 BB aa 7340 BB aa 7340 BB aa 7340 BB bb 6421 BB bb 6421 BB bb 6421 BB bb 6421 BB bb 6421 BB bb 6421 CC aa 3122 CC aa 3122 CC aa 3122 CC aa 3122 CC bb 2493 CC bb 2493 DD aa 4032 DD aa 4032 DD aa 4032 DD bb 3597 DD bb 3597 DD bb 3597 DD bb 3597 EE aa 2539 EE aa 2539 EE bb 3812 EE bb 3812 EE bb 3812 FF aa 5668 FF aa 5668 FF aa 5668 FF aa 5668 FF bb 5102 FF bb 5102 FF bb 5102 FF bb 5102 FF bb 5102 FF bb 5102 GG aa 4468 GG aa 4468 GG aa 4468 GG aa 4468 GG bb 5120 GG bb 5120 GG bb 5120 GG bb 5120 HH aa 5443 HH aa 5443 HH aa 5443 HH bb 4244 HH bb 4244 HH bb 4244 HH bb 4244 HH bb 4244 HH bb 4244 II aa 3640 II aa 3640 II bb 4604 II bb 4604 II bb 4604 II bb 4604 II bb 4604 JJ aa 3800 JJ aa 3800 JJ aa 3800 JJ aa 3800 JJ bb 1786 JJ bb 1786 JJ bb 1786 JJ bb 1786} do_execsql_test 1.13.3 { SELECT a, b, rank() OVER (ORDER BY a GROUPS BETWEEN CURRENT ROW AND 1 FOLLOWING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa 1 AA aa 1 AA aa 1 AA aa 1 AA bb 1 AA bb 1 AA bb 1 AA bb 1 BB aa 9 BB aa 9 BB aa 9 BB aa 9 BB aa 9 BB aa 9 BB bb 9 BB bb 9 BB bb 9 BB bb 9 BB bb 9 BB bb 9 CC aa 21 CC aa 21 CC aa 21 CC aa 21 CC bb 21 CC bb 21 DD aa 27 DD aa 27 DD aa 27 DD bb 27 DD bb 27 DD bb 27 DD bb 27 EE aa 34 EE aa 34 EE bb 34 EE bb 34 EE bb 34 FF aa 39 FF aa 39 FF aa 39 FF aa 39 FF bb 39 FF bb 39 FF bb 39 FF bb 39 FF bb 39 FF bb 39 GG aa 49 GG aa 49 GG aa 49 GG aa 49 GG bb 49 GG bb 49 GG bb 49 GG bb 49 HH aa 57 HH aa 57 HH aa 57 HH bb 57 HH bb 57 HH bb 57 HH bb 57 HH bb 57 HH bb 57 II aa 66 II aa 66 II bb 66 II bb 66 II bb 66 II bb 66 II bb 66 JJ aa 73 JJ aa 73 JJ aa 73 JJ aa 73 JJ bb 73 JJ bb 73 JJ bb 73 JJ bb 73} do_execsql_test 1.13.4 { SELECT a, b, max(c) OVER (ORDER BY a,b GROUPS BETWEEN CURRENT ROW AND 1 FOLLOWING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa 934 AA aa 934 AA aa 934 AA aa 934 AA bb 870 AA bb 870 AA bb 870 AA bb 870 BB aa 840 BB aa 840 BB aa 840 BB aa 840 BB aa 840 BB aa 840 BB bb 840 BB bb 840 BB bb 840 BB bb 840 BB bb 840 BB bb 840 CC aa 822 CC aa 822 CC aa 822 CC aa 822 CC bb 845 CC bb 845 DD aa 959 DD aa 959 DD aa 959 DD bb 959 DD bb 959 DD bb 959 DD bb 959 EE aa 777 EE aa 777 EE bb 768 EE bb 768 EE bb 768 FF aa 938 FF aa 938 FF aa 938 FF aa 938 FF bb 938 FF bb 938 FF bb 938 FF bb 938 FF bb 938 FF bb 938 GG aa 938 GG aa 938 GG aa 938 GG aa 938 GG bb 979 GG bb 979 GG bb 979 GG bb 979 HH aa 979 HH aa 979 HH aa 979 HH bb 963 HH bb 963 HH bb 963 HH bb 963 HH bb 963 HH bb 963 II aa 805 II aa 805 II bb 899 II bb 899 II bb 899 II bb 899 II bb 899 JJ aa 899 JJ aa 899 JJ aa 899 JJ aa 899 JJ bb 839 JJ bb 839 JJ bb 839 JJ bb 839} do_execsql_test 1.13.5 { SELECT a, b, min(c) OVER (ORDER BY a,b GROUPS BETWEEN CURRENT ROW AND 1 FOLLOWING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa 223 AA aa 223 AA aa 223 AA aa 223 AA bb 247 AA bb 247 AA bb 247 AA bb 247 BB aa 247 BB aa 247 BB aa 247 BB aa 247 BB aa 247 BB aa 247 BB bb 158 BB bb 158 BB bb 158 BB bb 158 BB bb 158 BB bb 158 CC aa 158 CC aa 158 CC aa 158 CC aa 158 CC bb 224 CC bb 224 DD aa 224 DD aa 224 DD aa 224 DD bb 113 DD bb 113 DD bb 113 DD bb 113 EE aa 113 EE aa 113 EE bb 208 EE bb 208 EE bb 208 FF aa 102 FF aa 102 FF aa 102 FF aa 102 FF bb 102 FF bb 102 FF bb 102 FF bb 102 FF bb 102 FF bb 102 GG aa 148 GG aa 148 GG aa 148 GG aa 148 GG bb 160 GG bb 160 GG bb 160 GG bb 160 HH aa 133 HH aa 133 HH aa 133 HH bb 133 HH bb 133 HH bb 133 HH bb 133 HH bb 133 HH bb 133 II aa 250 II aa 250 II bb 113 II bb 113 II bb 113 II bb 113 II bb 113 JJ aa 113 JJ aa 113 JJ aa 113 JJ aa 113 JJ bb 257 JJ bb 257 JJ bb 257 JJ bb 257} do_execsql_test 1.13.6 { SELECT a, b, sum(c) OVER (ORDER BY a GROUPS BETWEEN CURRENT ROW AND 1 FOLLOWING EXCLUDE CURRENT ROW) FROM t3 ORDER BY 1, 2, 3; } {AA aa 11091 AA aa 11114 AA aa 11786 AA aa 11802 AA bb 11155 AA bb 11398 AA bb 11453 AA bb 11716 BB aa 9700 BB aa 9802 BB aa 10050 BB aa 10063 BB aa 10069 BB aa 10215 BB bb 9622 BB bb 9670 BB bb 9676 BB bb 9751 BB bb 9757 BB bb 9829 CC aa 6395 CC aa 6547 CC aa 6724 CC aa 6996 CC bb 6332 CC bb 6808 DD aa 5726 DD aa 6315 DD aa 6347 DD bb 5612 DD bb 5777 DD bb 5855 DD bb 6333 EE aa 7430 EE aa 8094 EE bb 7439 EE bb 7578 EE bb 7955 FF aa 9466 FF aa 9469 FF aa 9518 FF aa 9928 FF bb 9198 FF bb 9266 FF bb 9410 FF bb 9562 FF bb 9841 FF bb 10034 GG aa 9277 GG aa 9431 GG aa 9576 GG aa 9763 GG bb 8973 GG bb 8982 GG bb 9067 GG bb 9751 HH aa 8104 HH aa 8293 HH aa 8603 HH bb 8120 HH bb 8353 HH bb 8400 HH bb 8728 HH bb 8753 HH bb 8950 II aa 6788 II aa 7042 II bb 6635 II bb 6769 II bb 6997 II bb 7019 II bb 7190 JJ aa 2901 JJ aa 3032 JJ aa 3566 JJ aa 3687 JJ bb 2961 JJ bb 3446 JJ bb 3464 JJ bb 3543} do_execsql_test 1.13.7 { SELECT a, b, sum(c) OVER (ORDER BY a,b GROUPS BETWEEN CURRENT ROW AND 1 FOLLOWING EXCLUDE CURRENT ROW) FROM t3 ORDER BY 1, 2, 3; } {AA aa 3751 AA aa 3774 AA aa 4446 AA aa 4462 AA bb 4381 AA bb 4624 AA bb 4679 AA bb 4942 BB aa 6578 BB aa 6680 BB aa 6928 BB aa 6941 BB aa 6947 BB aa 7093 BB bb 5581 BB bb 5629 BB bb 5635 BB bb 5710 BB bb 5716 BB bb 5788 CC aa 2363 CC aa 2515 CC aa 2692 CC aa 2964 CC bb 1671 CC bb 2147 DD aa 3187 DD aa 3776 DD aa 3808 DD bb 2638 DD bb 2803 DD bb 2881 DD bb 3359 EE aa 1762 EE aa 2426 EE bb 3044 EE bb 3183 EE bb 3560 FF aa 4998 FF aa 5001 FF aa 5050 FF aa 5460 FF bb 4164 FF bb 4232 FF bb 4376 FF bb 4528 FF bb 4807 FF bb 5000 GG aa 3834 GG aa 3988 GG aa 4133 GG aa 4320 GG bb 4182 GG bb 4191 GG bb 4276 GG bb 4960 HH aa 4464 HH aa 4653 HH aa 4963 HH bb 3281 HH bb 3514 HH bb 3561 HH bb 3889 HH bb 3914 HH bb 4111 II aa 2988 II aa 3242 II bb 3799 II bb 3933 II bb 4161 II bb 4183 II bb 4354 JJ aa 2901 JJ aa 3032 JJ aa 3566 JJ aa 3687 JJ bb 947 JJ bb 1432 JJ bb 1450 JJ bb 1529} do_execsql_test 1.13.8 { SELECT a, b, sum(c) OVER (ORDER BY a GROUPS BETWEEN CURRENT ROW AND 1 FOLLOWING EXCLUDE CURRENT ROW), sum(c) OVER (ORDER BY a GROUPS BETWEEN CURRENT ROW AND 1 FOLLOWING ), sum(c) OVER (ORDER BY a,b GROUPS BETWEEN CURRENT ROW AND 1 FOLLOWING EXCLUDE CURRENT ROW), sum(c) OVER (ORDER BY a,b GROUPS BETWEEN CURRENT ROW AND 1 FOLLOWING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa 11091 12025 3751 4685 AA aa 11114 12025 3774 4685 AA aa 11786 12025 4446 4685 AA aa 11802 12025 4462 4685 AA bb 11155 12025 4381 5251 AA bb 11398 12025 4624 5251 AA bb 11453 12025 4679 5251 AA bb 11716 12025 4942 5251 BB aa 9700 10462 6578 7340 BB aa 9802 10462 6680 7340 BB aa 10050 10462 6928 7340 BB aa 10063 10462 6941 7340 BB aa 10069 10462 6947 7340 BB aa 10215 10462 7093 7340 BB bb 9622 10462 5581 6421 BB bb 9670 10462 5629 6421 BB bb 9676 10462 5635 6421 BB bb 9751 10462 5710 6421 BB bb 9757 10462 5716 6421 BB bb 9829 10462 5788 6421 CC aa 6395 7154 2363 3122 CC aa 6547 7154 2515 3122 CC aa 6724 7154 2692 3122 CC aa 6996 7154 2964 3122 CC bb 6332 7154 1671 2493 CC bb 6808 7154 2147 2493 DD aa 5726 6571 3187 4032 DD aa 6315 6571 3776 4032 DD aa 6347 6571 3808 4032 DD bb 5612 6571 2638 3597 DD bb 5777 6571 2803 3597 DD bb 5855 6571 2881 3597 DD bb 6333 6571 3359 3597 EE aa 7430 8207 1762 2539 EE aa 8094 8207 2426 2539 EE bb 7439 8207 3044 3812 EE bb 7578 8207 3183 3812 EE bb 7955 8207 3560 3812 FF aa 9466 10136 4998 5668 FF aa 9469 10136 5001 5668 FF aa 9518 10136 5050 5668 FF aa 9928 10136 5460 5668 FF bb 9198 10136 4164 5102 FF bb 9266 10136 4232 5102 FF bb 9410 10136 4376 5102 FF bb 9562 10136 4528 5102 FF bb 9841 10136 4807 5102 FF bb 10034 10136 5000 5102 GG aa 9277 9911 3834 4468 GG aa 9431 9911 3988 4468 GG aa 9576 9911 4133 4468 GG aa 9763 9911 4320 4468 GG bb 8973 9911 4182 5120 GG bb 8982 9911 4191 5120 GG bb 9067 9911 4276 5120 GG bb 9751 9911 4960 5120 HH aa 8104 9083 4464 5443 HH aa 8293 9083 4653 5443 HH aa 8603 9083 4963 5443 HH bb 8120 9083 3281 4244 HH bb 8353 9083 3514 4244 HH bb 8400 9083 3561 4244 HH bb 8728 9083 3889 4244 HH bb 8753 9083 3914 4244 HH bb 8950 9083 4111 4244 II aa 6788 7440 2988 3640 II aa 7042 7440 3242 3640 II bb 6635 7440 3799 4604 II bb 6769 7440 3933 4604 II bb 6997 7440 4161 4604 II bb 7019 7440 4183 4604 II bb 7190 7440 4354 4604 JJ aa 2901 3800 2901 3800 JJ aa 3032 3800 3032 3800 JJ aa 3566 3800 3566 3800 JJ aa 3687 3800 3687 3800 JJ bb 2961 3800 947 1786 JJ bb 3446 3800 1432 1786 JJ bb 3464 3800 1450 1786 JJ bb 3543 3800 1529 1786} do_execsql_test 1.14.1 { SELECT a, b, sum(c) OVER (ORDER BY a GROUPS BETWEEN CURRENT ROW AND 100 FOLLOWING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa 44737 AA aa 44737 AA aa 44737 AA aa 44737 AA bb 44737 AA bb 44737 AA bb 44737 AA bb 44737 BB aa 40052 BB aa 40052 BB aa 40052 BB aa 40052 BB aa 40052 BB aa 40052 BB bb 40052 BB bb 40052 BB bb 40052 BB bb 40052 BB bb 40052 BB bb 40052 CC aa 32712 CC aa 32712 CC aa 32712 CC aa 32712 CC bb 32712 CC bb 32712 DD aa 29590 DD aa 29590 DD aa 29590 DD bb 29590 DD bb 29590 DD bb 29590 DD bb 29590 EE aa 25558 EE aa 25558 EE bb 25558 EE bb 25558 EE bb 25558 FF aa 23019 FF aa 23019 FF aa 23019 FF aa 23019 FF bb 23019 FF bb 23019 FF bb 23019 FF bb 23019 FF bb 23019 FF bb 23019 GG aa 17351 GG aa 17351 GG aa 17351 GG aa 17351 GG bb 17351 GG bb 17351 GG bb 17351 GG bb 17351 HH aa 12883 HH aa 12883 HH aa 12883 HH bb 12883 HH bb 12883 HH bb 12883 HH bb 12883 HH bb 12883 HH bb 12883 II aa 7440 II aa 7440 II bb 7440 II bb 7440 II bb 7440 II bb 7440 II bb 7440 JJ aa 3800 JJ aa 3800 JJ aa 3800 JJ aa 3800 JJ bb 3800 JJ bb 3800 JJ bb 3800 JJ bb 3800} do_execsql_test 1.14.2 { SELECT a, b, sum(c) OVER (ORDER BY a,b GROUPS BETWEEN CURRENT ROW AND 100 FOLLOWING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa 44737 AA aa 44737 AA aa 44737 AA aa 44737 AA bb 42430 AA bb 42430 AA bb 42430 AA bb 42430 BB aa 40052 BB aa 40052 BB aa 40052 BB aa 40052 BB aa 40052 BB aa 40052 BB bb 37179 BB bb 37179 BB bb 37179 BB bb 37179 BB bb 37179 BB bb 37179 CC aa 32712 CC aa 32712 CC aa 32712 CC aa 32712 CC bb 30758 CC bb 30758 DD aa 29590 DD aa 29590 DD aa 29590 DD bb 28265 DD bb 28265 DD bb 28265 DD bb 28265 EE aa 25558 EE aa 25558 EE bb 24668 EE bb 24668 EE bb 24668 FF aa 23019 FF aa 23019 FF aa 23019 FF aa 23019 FF bb 20856 FF bb 20856 FF bb 20856 FF bb 20856 FF bb 20856 FF bb 20856 GG aa 17351 GG aa 17351 GG aa 17351 GG aa 17351 GG bb 15754 GG bb 15754 GG bb 15754 GG bb 15754 HH aa 12883 HH aa 12883 HH aa 12883 HH bb 10634 HH bb 10634 HH bb 10634 HH bb 10634 HH bb 10634 HH bb 10634 II aa 7440 II aa 7440 II bb 6390 II bb 6390 II bb 6390 II bb 6390 II bb 6390 JJ aa 3800 JJ aa 3800 JJ aa 3800 JJ aa 3800 JJ bb 1786 JJ bb 1786 JJ bb 1786 JJ bb 1786} do_execsql_test 1.14.3 { SELECT a, b, rank() OVER (ORDER BY a GROUPS BETWEEN CURRENT ROW AND 100 FOLLOWING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa 1 AA aa 1 AA aa 1 AA aa 1 AA bb 1 AA bb 1 AA bb 1 AA bb 1 BB aa 9 BB aa 9 BB aa 9 BB aa 9 BB aa 9 BB aa 9 BB bb 9 BB bb 9 BB bb 9 BB bb 9 BB bb 9 BB bb 9 CC aa 21 CC aa 21 CC aa 21 CC aa 21 CC bb 21 CC bb 21 DD aa 27 DD aa 27 DD aa 27 DD bb 27 DD bb 27 DD bb 27 DD bb 27 EE aa 34 EE aa 34 EE bb 34 EE bb 34 EE bb 34 FF aa 39 FF aa 39 FF aa 39 FF aa 39 FF bb 39 FF bb 39 FF bb 39 FF bb 39 FF bb 39 FF bb 39 GG aa 49 GG aa 49 GG aa 49 GG aa 49 GG bb 49 GG bb 49 GG bb 49 GG bb 49 HH aa 57 HH aa 57 HH aa 57 HH bb 57 HH bb 57 HH bb 57 HH bb 57 HH bb 57 HH bb 57 II aa 66 II aa 66 II bb 66 II bb 66 II bb 66 II bb 66 II bb 66 JJ aa 73 JJ aa 73 JJ aa 73 JJ aa 73 JJ bb 73 JJ bb 73 JJ bb 73 JJ bb 73} do_execsql_test 1.14.4 { SELECT a, b, max(c) OVER (ORDER BY a,b GROUPS BETWEEN CURRENT ROW AND 100 FOLLOWING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa 979 AA aa 979 AA aa 979 AA aa 979 AA bb 979 AA bb 979 AA bb 979 AA bb 979 BB aa 979 BB aa 979 BB aa 979 BB aa 979 BB aa 979 BB aa 979 BB bb 979 BB bb 979 BB bb 979 BB bb 979 BB bb 979 BB bb 979 CC aa 979 CC aa 979 CC aa 979 CC aa 979 CC bb 979 CC bb 979 DD aa 979 DD aa 979 DD aa 979 DD bb 979 DD bb 979 DD bb 979 DD bb 979 EE aa 979 EE aa 979 EE bb 979 EE bb 979 EE bb 979 FF aa 979 FF aa 979 FF aa 979 FF aa 979 FF bb 979 FF bb 979 FF bb 979 FF bb 979 FF bb 979 FF bb 979 GG aa 979 GG aa 979 GG aa 979 GG aa 979 GG bb 979 GG bb 979 GG bb 979 GG bb 979 HH aa 979 HH aa 979 HH aa 979 HH bb 963 HH bb 963 HH bb 963 HH bb 963 HH bb 963 HH bb 963 II aa 899 II aa 899 II bb 899 II bb 899 II bb 899 II bb 899 II bb 899 JJ aa 899 JJ aa 899 JJ aa 899 JJ aa 899 JJ bb 839 JJ bb 839 JJ bb 839 JJ bb 839} do_execsql_test 1.14.5 { SELECT a, b, min(c) OVER (ORDER BY a,b GROUPS BETWEEN CURRENT ROW AND 100 FOLLOWING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa 102 AA aa 102 AA aa 102 AA aa 102 AA bb 102 AA bb 102 AA bb 102 AA bb 102 BB aa 102 BB aa 102 BB aa 102 BB aa 102 BB aa 102 BB aa 102 BB bb 102 BB bb 102 BB bb 102 BB bb 102 BB bb 102 BB bb 102 CC aa 102 CC aa 102 CC aa 102 CC aa 102 CC bb 102 CC bb 102 DD aa 102 DD aa 102 DD aa 102 DD bb 102 DD bb 102 DD bb 102 DD bb 102 EE aa 102 EE aa 102 EE bb 102 EE bb 102 EE bb 102 FF aa 102 FF aa 102 FF aa 102 FF aa 102 FF bb 102 FF bb 102 FF bb 102 FF bb 102 FF bb 102 FF bb 102 GG aa 113 GG aa 113 GG aa 113 GG aa 113 GG bb 113 GG bb 113 GG bb 113 GG bb 113 HH aa 113 HH aa 113 HH aa 113 HH bb 113 HH bb 113 HH bb 113 HH bb 113 HH bb 113 HH bb 113 II aa 113 II aa 113 II bb 113 II bb 113 II bb 113 II bb 113 II bb 113 JJ aa 113 JJ aa 113 JJ aa 113 JJ aa 113 JJ bb 257 JJ bb 257 JJ bb 257 JJ bb 257} do_execsql_test 1.14.6 { SELECT a, b, sum(c) OVER (ORDER BY a GROUPS BETWEEN CURRENT ROW AND 100 FOLLOWING EXCLUDE CURRENT ROW) FROM t3 ORDER BY 1, 2, 3; } {AA aa 43803 AA aa 43826 AA aa 44498 AA aa 44514 AA bb 43867 AA bb 44110 AA bb 44165 AA bb 44428 BB aa 39290 BB aa 39392 BB aa 39640 BB aa 39653 BB aa 39659 BB aa 39805 BB bb 39212 BB bb 39260 BB bb 39266 BB bb 39341 BB bb 39347 BB bb 39419 CC aa 31953 CC aa 32105 CC aa 32282 CC aa 32554 CC bb 31890 CC bb 32366 DD aa 28745 DD aa 29334 DD aa 29366 DD bb 28631 DD bb 28796 DD bb 28874 DD bb 29352 EE aa 24781 EE aa 25445 EE bb 24790 EE bb 24929 EE bb 25306 FF aa 22349 FF aa 22352 FF aa 22401 FF aa 22811 FF bb 22081 FF bb 22149 FF bb 22293 FF bb 22445 FF bb 22724 FF bb 22917 GG aa 16717 GG aa 16871 GG aa 17016 GG aa 17203 GG bb 16413 GG bb 16422 GG bb 16507 GG bb 17191 HH aa 11904 HH aa 12093 HH aa 12403 HH bb 11920 HH bb 12153 HH bb 12200 HH bb 12528 HH bb 12553 HH bb 12750 II aa 6788 II aa 7042 II bb 6635 II bb 6769 II bb 6997 II bb 7019 II bb 7190 JJ aa 2901 JJ aa 3032 JJ aa 3566 JJ aa 3687 JJ bb 2961 JJ bb 3446 JJ bb 3464 JJ bb 3543} do_execsql_test 1.14.7 { SELECT a, b, sum(c) OVER (ORDER BY a,b GROUPS BETWEEN CURRENT ROW AND 100 FOLLOWING EXCLUDE CURRENT ROW) FROM t3 ORDER BY 1, 2, 3; } {AA aa 43803 AA aa 43826 AA aa 44498 AA aa 44514 AA bb 41560 AA bb 41803 AA bb 41858 AA bb 42121 BB aa 39290 BB aa 39392 BB aa 39640 BB aa 39653 BB aa 39659 BB aa 39805 BB bb 36339 BB bb 36387 BB bb 36393 BB bb 36468 BB bb 36474 BB bb 36546 CC aa 31953 CC aa 32105 CC aa 32282 CC aa 32554 CC bb 29936 CC bb 30412 DD aa 28745 DD aa 29334 DD aa 29366 DD bb 27306 DD bb 27471 DD bb 27549 DD bb 28027 EE aa 24781 EE aa 25445 EE bb 23900 EE bb 24039 EE bb 24416 FF aa 22349 FF aa 22352 FF aa 22401 FF aa 22811 FF bb 19918 FF bb 19986 FF bb 20130 FF bb 20282 FF bb 20561 FF bb 20754 GG aa 16717 GG aa 16871 GG aa 17016 GG aa 17203 GG bb 14816 GG bb 14825 GG bb 14910 GG bb 15594 HH aa 11904 HH aa 12093 HH aa 12403 HH bb 9671 HH bb 9904 HH bb 9951 HH bb 10279 HH bb 10304 HH bb 10501 II aa 6788 II aa 7042 II bb 5585 II bb 5719 II bb 5947 II bb 5969 II bb 6140 JJ aa 2901 JJ aa 3032 JJ aa 3566 JJ aa 3687 JJ bb 947 JJ bb 1432 JJ bb 1450 JJ bb 1529} do_execsql_test 1.14.8 { SELECT a, b, sum(c) OVER (ORDER BY a GROUPS BETWEEN CURRENT ROW AND 100 FOLLOWING EXCLUDE CURRENT ROW), sum(c) OVER (ORDER BY a GROUPS BETWEEN CURRENT ROW AND 100 FOLLOWING ), sum(c) OVER (ORDER BY a,b GROUPS BETWEEN CURRENT ROW AND 100 FOLLOWING EXCLUDE CURRENT ROW), sum(c) OVER (ORDER BY a,b GROUPS BETWEEN CURRENT ROW AND 100 FOLLOWING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa 43803 44737 43803 44737 AA aa 43826 44737 43826 44737 AA aa 44498 44737 44498 44737 AA aa 44514 44737 44514 44737 AA bb 43867 44737 41560 42430 AA bb 44110 44737 41803 42430 AA bb 44165 44737 41858 42430 AA bb 44428 44737 42121 42430 BB aa 39290 40052 39290 40052 BB aa 39392 40052 39392 40052 BB aa 39640 40052 39640 40052 BB aa 39653 40052 39653 40052 BB aa 39659 40052 39659 40052 BB aa 39805 40052 39805 40052 BB bb 39212 40052 36339 37179 BB bb 39260 40052 36387 37179 BB bb 39266 40052 36393 37179 BB bb 39341 40052 36468 37179 BB bb 39347 40052 36474 37179 BB bb 39419 40052 36546 37179 CC aa 31953 32712 31953 32712 CC aa 32105 32712 32105 32712 CC aa 32282 32712 32282 32712 CC aa 32554 32712 32554 32712 CC bb 31890 32712 29936 30758 CC bb 32366 32712 30412 30758 DD aa 28745 29590 28745 29590 DD aa 29334 29590 29334 29590 DD aa 29366 29590 29366 29590 DD bb 28631 29590 27306 28265 DD bb 28796 29590 27471 28265 DD bb 28874 29590 27549 28265 DD bb 29352 29590 28027 28265 EE aa 24781 25558 24781 25558 EE aa 25445 25558 25445 25558 EE bb 24790 25558 23900 24668 EE bb 24929 25558 24039 24668 EE bb 25306 25558 24416 24668 FF aa 22349 23019 22349 23019 FF aa 22352 23019 22352 23019 FF aa 22401 23019 22401 23019 FF aa 22811 23019 22811 23019 FF bb 22081 23019 19918 20856 FF bb 22149 23019 19986 20856 FF bb 22293 23019 20130 20856 FF bb 22445 23019 20282 20856 FF bb 22724 23019 20561 20856 FF bb 22917 23019 20754 20856 GG aa 16717 17351 16717 17351 GG aa 16871 17351 16871 17351 GG aa 17016 17351 17016 17351 GG aa 17203 17351 17203 17351 GG bb 16413 17351 14816 15754 GG bb 16422 17351 14825 15754 GG bb 16507 17351 14910 15754 GG bb 17191 17351 15594 15754 HH aa 11904 12883 11904 12883 HH aa 12093 12883 12093 12883 HH aa 12403 12883 12403 12883 HH bb 11920 12883 9671 10634 HH bb 12153 12883 9904 10634 HH bb 12200 12883 9951 10634 HH bb 12528 12883 10279 10634 HH bb 12553 12883 10304 10634 HH bb 12750 12883 10501 10634 II aa 6788 7440 6788 7440 II aa 7042 7440 7042 7440 II bb 6635 7440 5585 6390 II bb 6769 7440 5719 6390 II bb 6997 7440 5947 6390 II bb 7019 7440 5969 6390 II bb 7190 7440 6140 6390 JJ aa 2901 3800 2901 3800 JJ aa 3032 3800 3032 3800 JJ aa 3566 3800 3566 3800 JJ aa 3687 3800 3687 3800 JJ bb 2961 3800 947 1786 JJ bb 3446 3800 1432 1786 JJ bb 3464 3800 1450 1786 JJ bb 3543 3800 1529 1786} do_execsql_test 1.15.1 { SELECT a, b, sum(c) OVER (ORDER BY a GROUPS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa 44737 AA aa 44737 AA aa 44737 AA aa 44737 AA bb 44737 AA bb 44737 AA bb 44737 AA bb 44737 BB aa 40052 BB aa 40052 BB aa 40052 BB aa 40052 BB aa 40052 BB aa 40052 BB bb 40052 BB bb 40052 BB bb 40052 BB bb 40052 BB bb 40052 BB bb 40052 CC aa 32712 CC aa 32712 CC aa 32712 CC aa 32712 CC bb 32712 CC bb 32712 DD aa 29590 DD aa 29590 DD aa 29590 DD bb 29590 DD bb 29590 DD bb 29590 DD bb 29590 EE aa 25558 EE aa 25558 EE bb 25558 EE bb 25558 EE bb 25558 FF aa 23019 FF aa 23019 FF aa 23019 FF aa 23019 FF bb 23019 FF bb 23019 FF bb 23019 FF bb 23019 FF bb 23019 FF bb 23019 GG aa 17351 GG aa 17351 GG aa 17351 GG aa 17351 GG bb 17351 GG bb 17351 GG bb 17351 GG bb 17351 HH aa 12883 HH aa 12883 HH aa 12883 HH bb 12883 HH bb 12883 HH bb 12883 HH bb 12883 HH bb 12883 HH bb 12883 II aa 7440 II aa 7440 II bb 7440 II bb 7440 II bb 7440 II bb 7440 II bb 7440 JJ aa 3800 JJ aa 3800 JJ aa 3800 JJ aa 3800 JJ bb 3800 JJ bb 3800 JJ bb 3800 JJ bb 3800} do_execsql_test 1.15.2 { SELECT a, b, sum(c) OVER (ORDER BY a,b GROUPS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa 44737 AA aa 44737 AA aa 44737 AA aa 44737 AA bb 42430 AA bb 42430 AA bb 42430 AA bb 42430 BB aa 40052 BB aa 40052 BB aa 40052 BB aa 40052 BB aa 40052 BB aa 40052 BB bb 37179 BB bb 37179 BB bb 37179 BB bb 37179 BB bb 37179 BB bb 37179 CC aa 32712 CC aa 32712 CC aa 32712 CC aa 32712 CC bb 30758 CC bb 30758 DD aa 29590 DD aa 29590 DD aa 29590 DD bb 28265 DD bb 28265 DD bb 28265 DD bb 28265 EE aa 25558 EE aa 25558 EE bb 24668 EE bb 24668 EE bb 24668 FF aa 23019 FF aa 23019 FF aa 23019 FF aa 23019 FF bb 20856 FF bb 20856 FF bb 20856 FF bb 20856 FF bb 20856 FF bb 20856 GG aa 17351 GG aa 17351 GG aa 17351 GG aa 17351 GG bb 15754 GG bb 15754 GG bb 15754 GG bb 15754 HH aa 12883 HH aa 12883 HH aa 12883 HH bb 10634 HH bb 10634 HH bb 10634 HH bb 10634 HH bb 10634 HH bb 10634 II aa 7440 II aa 7440 II bb 6390 II bb 6390 II bb 6390 II bb 6390 II bb 6390 JJ aa 3800 JJ aa 3800 JJ aa 3800 JJ aa 3800 JJ bb 1786 JJ bb 1786 JJ bb 1786 JJ bb 1786} do_execsql_test 1.15.3 { SELECT a, b, rank() OVER (ORDER BY a GROUPS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa 1 AA aa 1 AA aa 1 AA aa 1 AA bb 1 AA bb 1 AA bb 1 AA bb 1 BB aa 9 BB aa 9 BB aa 9 BB aa 9 BB aa 9 BB aa 9 BB bb 9 BB bb 9 BB bb 9 BB bb 9 BB bb 9 BB bb 9 CC aa 21 CC aa 21 CC aa 21 CC aa 21 CC bb 21 CC bb 21 DD aa 27 DD aa 27 DD aa 27 DD bb 27 DD bb 27 DD bb 27 DD bb 27 EE aa 34 EE aa 34 EE bb 34 EE bb 34 EE bb 34 FF aa 39 FF aa 39 FF aa 39 FF aa 39 FF bb 39 FF bb 39 FF bb 39 FF bb 39 FF bb 39 FF bb 39 GG aa 49 GG aa 49 GG aa 49 GG aa 49 GG bb 49 GG bb 49 GG bb 49 GG bb 49 HH aa 57 HH aa 57 HH aa 57 HH bb 57 HH bb 57 HH bb 57 HH bb 57 HH bb 57 HH bb 57 II aa 66 II aa 66 II bb 66 II bb 66 II bb 66 II bb 66 II bb 66 JJ aa 73 JJ aa 73 JJ aa 73 JJ aa 73 JJ bb 73 JJ bb 73 JJ bb 73 JJ bb 73} do_execsql_test 1.15.4 { SELECT a, b, max(c) OVER (ORDER BY a,b GROUPS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa 979 AA aa 979 AA aa 979 AA aa 979 AA bb 979 AA bb 979 AA bb 979 AA bb 979 BB aa 979 BB aa 979 BB aa 979 BB aa 979 BB aa 979 BB aa 979 BB bb 979 BB bb 979 BB bb 979 BB bb 979 BB bb 979 BB bb 979 CC aa 979 CC aa 979 CC aa 979 CC aa 979 CC bb 979 CC bb 979 DD aa 979 DD aa 979 DD aa 979 DD bb 979 DD bb 979 DD bb 979 DD bb 979 EE aa 979 EE aa 979 EE bb 979 EE bb 979 EE bb 979 FF aa 979 FF aa 979 FF aa 979 FF aa 979 FF bb 979 FF bb 979 FF bb 979 FF bb 979 FF bb 979 FF bb 979 GG aa 979 GG aa 979 GG aa 979 GG aa 979 GG bb 979 GG bb 979 GG bb 979 GG bb 979 HH aa 979 HH aa 979 HH aa 979 HH bb 963 HH bb 963 HH bb 963 HH bb 963 HH bb 963 HH bb 963 II aa 899 II aa 899 II bb 899 II bb 899 II bb 899 II bb 899 II bb 899 JJ aa 899 JJ aa 899 JJ aa 899 JJ aa 899 JJ bb 839 JJ bb 839 JJ bb 839 JJ bb 839} do_execsql_test 1.15.5 { SELECT a, b, min(c) OVER (ORDER BY a,b GROUPS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa 102 AA aa 102 AA aa 102 AA aa 102 AA bb 102 AA bb 102 AA bb 102 AA bb 102 BB aa 102 BB aa 102 BB aa 102 BB aa 102 BB aa 102 BB aa 102 BB bb 102 BB bb 102 BB bb 102 BB bb 102 BB bb 102 BB bb 102 CC aa 102 CC aa 102 CC aa 102 CC aa 102 CC bb 102 CC bb 102 DD aa 102 DD aa 102 DD aa 102 DD bb 102 DD bb 102 DD bb 102 DD bb 102 EE aa 102 EE aa 102 EE bb 102 EE bb 102 EE bb 102 FF aa 102 FF aa 102 FF aa 102 FF aa 102 FF bb 102 FF bb 102 FF bb 102 FF bb 102 FF bb 102 FF bb 102 GG aa 113 GG aa 113 GG aa 113 GG aa 113 GG bb 113 GG bb 113 GG bb 113 GG bb 113 HH aa 113 HH aa 113 HH aa 113 HH bb 113 HH bb 113 HH bb 113 HH bb 113 HH bb 113 HH bb 113 II aa 113 II aa 113 II bb 113 II bb 113 II bb 113 II bb 113 II bb 113 JJ aa 113 JJ aa 113 JJ aa 113 JJ aa 113 JJ bb 257 JJ bb 257 JJ bb 257 JJ bb 257} do_execsql_test 1.15.6 { SELECT a, b, sum(c) OVER (ORDER BY a GROUPS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING EXCLUDE CURRENT ROW) FROM t3 ORDER BY 1, 2, 3; } {AA aa 43803 AA aa 43826 AA aa 44498 AA aa 44514 AA bb 43867 AA bb 44110 AA bb 44165 AA bb 44428 BB aa 39290 BB aa 39392 BB aa 39640 BB aa 39653 BB aa 39659 BB aa 39805 BB bb 39212 BB bb 39260 BB bb 39266 BB bb 39341 BB bb 39347 BB bb 39419 CC aa 31953 CC aa 32105 CC aa 32282 CC aa 32554 CC bb 31890 CC bb 32366 DD aa 28745 DD aa 29334 DD aa 29366 DD bb 28631 DD bb 28796 DD bb 28874 DD bb 29352 EE aa 24781 EE aa 25445 EE bb 24790 EE bb 24929 EE bb 25306 FF aa 22349 FF aa 22352 FF aa 22401 FF aa 22811 FF bb 22081 FF bb 22149 FF bb 22293 FF bb 22445 FF bb 22724 FF bb 22917 GG aa 16717 GG aa 16871 GG aa 17016 GG aa 17203 GG bb 16413 GG bb 16422 GG bb 16507 GG bb 17191 HH aa 11904 HH aa 12093 HH aa 12403 HH bb 11920 HH bb 12153 HH bb 12200 HH bb 12528 HH bb 12553 HH bb 12750 II aa 6788 II aa 7042 II bb 6635 II bb 6769 II bb 6997 II bb 7019 II bb 7190 JJ aa 2901 JJ aa 3032 JJ aa 3566 JJ aa 3687 JJ bb 2961 JJ bb 3446 JJ bb 3464 JJ bb 3543} do_execsql_test 1.15.7 { SELECT a, b, sum(c) OVER (ORDER BY a,b GROUPS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING EXCLUDE CURRENT ROW) FROM t3 ORDER BY 1, 2, 3; } {AA aa 43803 AA aa 43826 AA aa 44498 AA aa 44514 AA bb 41560 AA bb 41803 AA bb 41858 AA bb 42121 BB aa 39290 BB aa 39392 BB aa 39640 BB aa 39653 BB aa 39659 BB aa 39805 BB bb 36339 BB bb 36387 BB bb 36393 BB bb 36468 BB bb 36474 BB bb 36546 CC aa 31953 CC aa 32105 CC aa 32282 CC aa 32554 CC bb 29936 CC bb 30412 DD aa 28745 DD aa 29334 DD aa 29366 DD bb 27306 DD bb 27471 DD bb 27549 DD bb 28027 EE aa 24781 EE aa 25445 EE bb 23900 EE bb 24039 EE bb 24416 FF aa 22349 FF aa 22352 FF aa 22401 FF aa 22811 FF bb 19918 FF bb 19986 FF bb 20130 FF bb 20282 FF bb 20561 FF bb 20754 GG aa 16717 GG aa 16871 GG aa 17016 GG aa 17203 GG bb 14816 GG bb 14825 GG bb 14910 GG bb 15594 HH aa 11904 HH aa 12093 HH aa 12403 HH bb 9671 HH bb 9904 HH bb 9951 HH bb 10279 HH bb 10304 HH bb 10501 II aa 6788 II aa 7042 II bb 5585 II bb 5719 II bb 5947 II bb 5969 II bb 6140 JJ aa 2901 JJ aa 3032 JJ aa 3566 JJ aa 3687 JJ bb 947 JJ bb 1432 JJ bb 1450 JJ bb 1529} do_execsql_test 1.15.8 { SELECT a, b, sum(c) OVER (ORDER BY a GROUPS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING EXCLUDE CURRENT ROW), sum(c) OVER (ORDER BY a GROUPS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING ), sum(c) OVER (ORDER BY a,b GROUPS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING EXCLUDE CURRENT ROW), sum(c) OVER (ORDER BY a,b GROUPS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa 43803 44737 43803 44737 AA aa 43826 44737 43826 44737 AA aa 44498 44737 44498 44737 AA aa 44514 44737 44514 44737 AA bb 43867 44737 41560 42430 AA bb 44110 44737 41803 42430 AA bb 44165 44737 41858 42430 AA bb 44428 44737 42121 42430 BB aa 39290 40052 39290 40052 BB aa 39392 40052 39392 40052 BB aa 39640 40052 39640 40052 BB aa 39653 40052 39653 40052 BB aa 39659 40052 39659 40052 BB aa 39805 40052 39805 40052 BB bb 39212 40052 36339 37179 BB bb 39260 40052 36387 37179 BB bb 39266 40052 36393 37179 BB bb 39341 40052 36468 37179 BB bb 39347 40052 36474 37179 BB bb 39419 40052 36546 37179 CC aa 31953 32712 31953 32712 CC aa 32105 32712 32105 32712 CC aa 32282 32712 32282 32712 CC aa 32554 32712 32554 32712 CC bb 31890 32712 29936 30758 CC bb 32366 32712 30412 30758 DD aa 28745 29590 28745 29590 DD aa 29334 29590 29334 29590 DD aa 29366 29590 29366 29590 DD bb 28631 29590 27306 28265 DD bb 28796 29590 27471 28265 DD bb 28874 29590 27549 28265 DD bb 29352 29590 28027 28265 EE aa 24781 25558 24781 25558 EE aa 25445 25558 25445 25558 EE bb 24790 25558 23900 24668 EE bb 24929 25558 24039 24668 EE bb 25306 25558 24416 24668 FF aa 22349 23019 22349 23019 FF aa 22352 23019 22352 23019 FF aa 22401 23019 22401 23019 FF aa 22811 23019 22811 23019 FF bb 22081 23019 19918 20856 FF bb 22149 23019 19986 20856 FF bb 22293 23019 20130 20856 FF bb 22445 23019 20282 20856 FF bb 22724 23019 20561 20856 FF bb 22917 23019 20754 20856 GG aa 16717 17351 16717 17351 GG aa 16871 17351 16871 17351 GG aa 17016 17351 17016 17351 GG aa 17203 17351 17203 17351 GG bb 16413 17351 14816 15754 GG bb 16422 17351 14825 15754 GG bb 16507 17351 14910 15754 GG bb 17191 17351 15594 15754 HH aa 11904 12883 11904 12883 HH aa 12093 12883 12093 12883 HH aa 12403 12883 12403 12883 HH bb 11920 12883 9671 10634 HH bb 12153 12883 9904 10634 HH bb 12200 12883 9951 10634 HH bb 12528 12883 10279 10634 HH bb 12553 12883 10304 10634 HH bb 12750 12883 10501 10634 II aa 6788 7440 6788 7440 II aa 7042 7440 7042 7440 II bb 6635 7440 5585 6390 II bb 6769 7440 5719 6390 II bb 6997 7440 5947 6390 II bb 7019 7440 5969 6390 II bb 7190 7440 6140 6390 JJ aa 2901 3800 2901 3800 JJ aa 3032 3800 3032 3800 JJ aa 3566 3800 3566 3800 JJ aa 3687 3800 3687 3800 JJ bb 2961 3800 947 1786 JJ bb 3446 3800 1432 1786 JJ bb 3464 3800 1450 1786 JJ bb 3543 3800 1529 1786} do_execsql_test 1.16.1 { SELECT a, b, sum(c) OVER (ORDER BY a GROUPS BETWEEN 0 FOLLOWING AND 0 FOLLOWING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa 4685 AA aa 4685 AA aa 4685 AA aa 4685 AA bb 4685 AA bb 4685 AA bb 4685 AA bb 4685 BB aa 7340 BB aa 7340 BB aa 7340 BB aa 7340 BB aa 7340 BB aa 7340 BB bb 7340 BB bb 7340 BB bb 7340 BB bb 7340 BB bb 7340 BB bb 7340 CC aa 3122 CC aa 3122 CC aa 3122 CC aa 3122 CC bb 3122 CC bb 3122 DD aa 4032 DD aa 4032 DD aa 4032 DD bb 4032 DD bb 4032 DD bb 4032 DD bb 4032 EE aa 2539 EE aa 2539 EE bb 2539 EE bb 2539 EE bb 2539 FF aa 5668 FF aa 5668 FF aa 5668 FF aa 5668 FF bb 5668 FF bb 5668 FF bb 5668 FF bb 5668 FF bb 5668 FF bb 5668 GG aa 4468 GG aa 4468 GG aa 4468 GG aa 4468 GG bb 4468 GG bb 4468 GG bb 4468 GG bb 4468 HH aa 5443 HH aa 5443 HH aa 5443 HH bb 5443 HH bb 5443 HH bb 5443 HH bb 5443 HH bb 5443 HH bb 5443 II aa 3640 II aa 3640 II bb 3640 II bb 3640 II bb 3640 II bb 3640 II bb 3640 JJ aa 3800 JJ aa 3800 JJ aa 3800 JJ aa 3800 JJ bb 3800 JJ bb 3800 JJ bb 3800 JJ bb 3800} do_execsql_test 1.16.2 { SELECT a, b, sum(c) OVER (ORDER BY a,b GROUPS BETWEEN 0 FOLLOWING AND 0 FOLLOWING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa 2307 AA aa 2307 AA aa 2307 AA aa 2307 AA bb 2378 AA bb 2378 AA bb 2378 AA bb 2378 BB aa 2873 BB aa 2873 BB aa 2873 BB aa 2873 BB aa 2873 BB aa 2873 BB bb 4467 BB bb 4467 BB bb 4467 BB bb 4467 BB bb 4467 BB bb 4467 CC aa 1954 CC aa 1954 CC aa 1954 CC aa 1954 CC bb 1168 CC bb 1168 DD aa 1325 DD aa 1325 DD aa 1325 DD bb 2707 DD bb 2707 DD bb 2707 DD bb 2707 EE aa 890 EE aa 890 EE bb 1649 EE bb 1649 EE bb 1649 FF aa 2163 FF aa 2163 FF aa 2163 FF aa 2163 FF bb 3505 FF bb 3505 FF bb 3505 FF bb 3505 FF bb 3505 FF bb 3505 GG aa 1597 GG aa 1597 GG aa 1597 GG aa 1597 GG bb 2871 GG bb 2871 GG bb 2871 GG bb 2871 HH aa 2249 HH aa 2249 HH aa 2249 HH bb 3194 HH bb 3194 HH bb 3194 HH bb 3194 HH bb 3194 HH bb 3194 II aa 1050 II aa 1050 II bb 2590 II bb 2590 II bb 2590 II bb 2590 II bb 2590 JJ aa 2014 JJ aa 2014 JJ aa 2014 JJ aa 2014 JJ bb 1786 JJ bb 1786 JJ bb 1786 JJ bb 1786} do_execsql_test 1.16.3 { SELECT a, b, rank() OVER (ORDER BY a GROUPS BETWEEN 0 FOLLOWING AND 0 FOLLOWING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa 1 AA aa 1 AA aa 1 AA aa 1 AA bb 1 AA bb 1 AA bb 1 AA bb 1 BB aa 9 BB aa 9 BB aa 9 BB aa 9 BB aa 9 BB aa 9 BB bb 9 BB bb 9 BB bb 9 BB bb 9 BB bb 9 BB bb 9 CC aa 21 CC aa 21 CC aa 21 CC aa 21 CC bb 21 CC bb 21 DD aa 27 DD aa 27 DD aa 27 DD bb 27 DD bb 27 DD bb 27 DD bb 27 EE aa 34 EE aa 34 EE bb 34 EE bb 34 EE bb 34 FF aa 39 FF aa 39 FF aa 39 FF aa 39 FF bb 39 FF bb 39 FF bb 39 FF bb 39 FF bb 39 FF bb 39 GG aa 49 GG aa 49 GG aa 49 GG aa 49 GG bb 49 GG bb 49 GG bb 49 GG bb 49 HH aa 57 HH aa 57 HH aa 57 HH bb 57 HH bb 57 HH bb 57 HH bb 57 HH bb 57 HH bb 57 II aa 66 II aa 66 II bb 66 II bb 66 II bb 66 II bb 66 II bb 66 JJ aa 73 JJ aa 73 JJ aa 73 JJ aa 73 JJ bb 73 JJ bb 73 JJ bb 73 JJ bb 73} do_execsql_test 1.16.4 { SELECT a, b, max(c) OVER (ORDER BY a,b GROUPS BETWEEN 0 FOLLOWING AND 0 FOLLOWING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa 934 AA aa 934 AA aa 934 AA aa 934 AA bb 870 AA bb 870 AA bb 870 AA bb 870 BB aa 762 BB aa 762 BB aa 762 BB aa 762 BB aa 762 BB aa 762 BB bb 840 BB bb 840 BB bb 840 BB bb 840 BB bb 840 BB bb 840 CC aa 759 CC aa 759 CC aa 759 CC aa 759 CC bb 822 CC bb 822 DD aa 845 DD aa 845 DD aa 845 DD bb 959 DD bb 959 DD bb 959 DD bb 959 EE aa 777 EE aa 777 EE bb 768 EE bb 768 EE bb 768 FF aa 670 FF aa 670 FF aa 670 FF aa 670 FF bb 938 FF bb 938 FF bb 938 FF bb 938 FF bb 938 FF bb 938 GG aa 634 GG aa 634 GG aa 634 GG aa 634 GG bb 938 GG bb 938 GG bb 938 GG bb 938 HH aa 979 HH aa 979 HH aa 979 HH bb 963 HH bb 963 HH bb 963 HH bb 963 HH bb 963 HH bb 963 II aa 652 II aa 652 II bb 805 II bb 805 II bb 805 II bb 805 II bb 805 JJ aa 899 JJ aa 899 JJ aa 899 JJ aa 899 JJ bb 839 JJ bb 839 JJ bb 839 JJ bb 839} do_execsql_test 1.16.5 { SELECT a, b, min(c) OVER (ORDER BY a,b GROUPS BETWEEN 0 FOLLOWING AND 0 FOLLOWING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa 223 AA aa 223 AA aa 223 AA aa 223 AA bb 309 AA bb 309 AA bb 309 AA bb 309 BB aa 247 BB aa 247 BB aa 247 BB aa 247 BB aa 247 BB aa 247 BB bb 633 BB bb 633 BB bb 633 BB bb 633 BB bb 633 BB bb 633 CC aa 158 CC aa 158 CC aa 158 CC aa 158 CC bb 346 CC bb 346 DD aa 224 DD aa 224 DD aa 224 DD bb 238 DD bb 238 DD bb 238 DD bb 238 EE aa 113 EE aa 113 EE bb 252 EE bb 252 EE bb 252 FF aa 208 FF aa 208 FF aa 208 FF aa 208 FF bb 102 FF bb 102 FF bb 102 FF bb 102 FF bb 102 FF bb 102 GG aa 148 GG aa 148 GG aa 148 GG aa 148 GG bb 160 GG bb 160 GG bb 160 GG bb 160 HH aa 480 HH aa 480 HH aa 480 HH bb 133 HH bb 133 HH bb 133 HH bb 133 HH bb 133 HH bb 133 II aa 398 II aa 398 II bb 250 II bb 250 II bb 250 II bb 250 II bb 250 JJ aa 113 JJ aa 113 JJ aa 113 JJ aa 113 JJ bb 257 JJ bb 257 JJ bb 257 JJ bb 257} do_execsql_test 1.16.6 { SELECT a, b, sum(c) OVER (ORDER BY a GROUPS BETWEEN 0 FOLLOWING AND 0 FOLLOWING EXCLUDE CURRENT ROW) FROM t3 ORDER BY 1, 2, 3; } {AA aa 3751 AA aa 3774 AA aa 4446 AA aa 4462 AA bb 3815 AA bb 4058 AA bb 4113 AA bb 4376 BB aa 6578 BB aa 6680 BB aa 6928 BB aa 6941 BB aa 6947 BB aa 7093 BB bb 6500 BB bb 6548 BB bb 6554 BB bb 6629 BB bb 6635 BB bb 6707 CC aa 2363 CC aa 2515 CC aa 2692 CC aa 2964 CC bb 2300 CC bb 2776 DD aa 3187 DD aa 3776 DD aa 3808 DD bb 3073 DD bb 3238 DD bb 3316 DD bb 3794 EE aa 1762 EE aa 2426 EE bb 1771 EE bb 1910 EE bb 2287 FF aa 4998 FF aa 5001 FF aa 5050 FF aa 5460 FF bb 4730 FF bb 4798 FF bb 4942 FF bb 5094 FF bb 5373 FF bb 5566 GG aa 3834 GG aa 3988 GG aa 4133 GG aa 4320 GG bb 3530 GG bb 3539 GG bb 3624 GG bb 4308 HH aa 4464 HH aa 4653 HH aa 4963 HH bb 4480 HH bb 4713 HH bb 4760 HH bb 5088 HH bb 5113 HH bb 5310 II aa 2988 II aa 3242 II bb 2835 II bb 2969 II bb 3197 II bb 3219 II bb 3390 JJ aa 2901 JJ aa 3032 JJ aa 3566 JJ aa 3687 JJ bb 2961 JJ bb 3446 JJ bb 3464 JJ bb 3543} do_execsql_test 1.16.7 { SELECT a, b, sum(c) OVER (ORDER BY a,b GROUPS BETWEEN 0 FOLLOWING AND 0 FOLLOWING EXCLUDE CURRENT ROW) FROM t3 ORDER BY 1, 2, 3; } {AA aa 1373 AA aa 1396 AA aa 2068 AA aa 2084 AA bb 1508 AA bb 1751 AA bb 1806 AA bb 2069 BB aa 2111 BB aa 2213 BB aa 2461 BB aa 2474 BB aa 2480 BB aa 2626 BB bb 3627 BB bb 3675 BB bb 3681 BB bb 3756 BB bb 3762 BB bb 3834 CC aa 1195 CC aa 1347 CC aa 1524 CC aa 1796 CC bb 346 CC bb 822 DD aa 480 DD aa 1069 DD aa 1101 DD bb 1748 DD bb 1913 DD bb 1991 DD bb 2469 EE aa 113 EE aa 777 EE bb 881 EE bb 1020 EE bb 1397 FF aa 1493 FF aa 1496 FF aa 1545 FF aa 1955 FF bb 2567 FF bb 2635 FF bb 2779 FF bb 2931 FF bb 3210 FF bb 3403 GG aa 963 GG aa 1117 GG aa 1262 GG aa 1449 GG bb 1933 GG bb 1942 GG bb 2027 GG bb 2711 HH aa 1270 HH aa 1459 HH aa 1769 HH bb 2231 HH bb 2464 HH bb 2511 HH bb 2839 HH bb 2864 HH bb 3061 II aa 398 II aa 652 II bb 1785 II bb 1919 II bb 2147 II bb 2169 II bb 2340 JJ aa 1115 JJ aa 1246 JJ aa 1780 JJ aa 1901 JJ bb 947 JJ bb 1432 JJ bb 1450 JJ bb 1529} do_execsql_test 1.16.8 { SELECT a, b, sum(c) OVER (ORDER BY a GROUPS BETWEEN 0 FOLLOWING AND 0 FOLLOWING EXCLUDE CURRENT ROW), sum(c) OVER (ORDER BY a GROUPS BETWEEN 0 FOLLOWING AND 0 FOLLOWING ), sum(c) OVER (ORDER BY a,b GROUPS BETWEEN 0 FOLLOWING AND 0 FOLLOWING EXCLUDE CURRENT ROW), sum(c) OVER (ORDER BY a,b GROUPS BETWEEN 0 FOLLOWING AND 0 FOLLOWING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa 3751 4685 1373 2307 AA aa 3774 4685 1396 2307 AA aa 4446 4685 2068 2307 AA aa 4462 4685 2084 2307 AA bb 3815 4685 1508 2378 AA bb 4058 4685 1751 2378 AA bb 4113 4685 1806 2378 AA bb 4376 4685 2069 2378 BB aa 6578 7340 2111 2873 BB aa 6680 7340 2213 2873 BB aa 6928 7340 2461 2873 BB aa 6941 7340 2474 2873 BB aa 6947 7340 2480 2873 BB aa 7093 7340 2626 2873 BB bb 6500 7340 3627 4467 BB bb 6548 7340 3675 4467 BB bb 6554 7340 3681 4467 BB bb 6629 7340 3756 4467 BB bb 6635 7340 3762 4467 BB bb 6707 7340 3834 4467 CC aa 2363 3122 1195 1954 CC aa 2515 3122 1347 1954 CC aa 2692 3122 1524 1954 CC aa 2964 3122 1796 1954 CC bb 2300 3122 346 1168 CC bb 2776 3122 822 1168 DD aa 3187 4032 480 1325 DD aa 3776 4032 1069 1325 DD aa 3808 4032 1101 1325 DD bb 3073 4032 1748 2707 DD bb 3238 4032 1913 2707 DD bb 3316 4032 1991 2707 DD bb 3794 4032 2469 2707 EE aa 1762 2539 113 890 EE aa 2426 2539 777 890 EE bb 1771 2539 881 1649 EE bb 1910 2539 1020 1649 EE bb 2287 2539 1397 1649 FF aa 4998 5668 1493 2163 FF aa 5001 5668 1496 2163 FF aa 5050 5668 1545 2163 FF aa 5460 5668 1955 2163 FF bb 4730 5668 2567 3505 FF bb 4798 5668 2635 3505 FF bb 4942 5668 2779 3505 FF bb 5094 5668 2931 3505 FF bb 5373 5668 3210 3505 FF bb 5566 5668 3403 3505 GG aa 3834 4468 963 1597 GG aa 3988 4468 1117 1597 GG aa 4133 4468 1262 1597 GG aa 4320 4468 1449 1597 GG bb 3530 4468 1933 2871 GG bb 3539 4468 1942 2871 GG bb 3624 4468 2027 2871 GG bb 4308 4468 2711 2871 HH aa 4464 5443 1270 2249 HH aa 4653 5443 1459 2249 HH aa 4963 5443 1769 2249 HH bb 4480 5443 2231 3194 HH bb 4713 5443 2464 3194 HH bb 4760 5443 2511 3194 HH bb 5088 5443 2839 3194 HH bb 5113 5443 2864 3194 HH bb 5310 5443 3061 3194 II aa 2988 3640 398 1050 II aa 3242 3640 652 1050 II bb 2835 3640 1785 2590 II bb 2969 3640 1919 2590 II bb 3197 3640 2147 2590 II bb 3219 3640 2169 2590 II bb 3390 3640 2340 2590 JJ aa 2901 3800 1115 2014 JJ aa 3032 3800 1246 2014 JJ aa 3566 3800 1780 2014 JJ aa 3687 3800 1901 2014 JJ bb 2961 3800 947 1786 JJ bb 3446 3800 1432 1786 JJ bb 3464 3800 1450 1786 JJ bb 3543 3800 1529 1786} do_execsql_test 1.17.1 { SELECT a, b, sum(c) OVER (ORDER BY a GROUPS BETWEEN 1 FOLLOWING AND 0 FOLLOWING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa {} AA aa {} AA aa {} AA aa {} AA bb {} AA bb {} AA bb {} AA bb {} BB aa {} BB aa {} BB aa {} BB aa {} BB aa {} BB aa {} BB bb {} BB bb {} BB bb {} BB bb {} BB bb {} BB bb {} CC aa {} CC aa {} CC aa {} CC aa {} CC bb {} CC bb {} DD aa {} DD aa {} DD aa {} DD bb {} DD bb {} DD bb {} DD bb {} EE aa {} EE aa {} EE bb {} EE bb {} EE bb {} FF aa {} FF aa {} FF aa {} FF aa {} FF bb {} FF bb {} FF bb {} FF bb {} FF bb {} FF bb {} GG aa {} GG aa {} GG aa {} GG aa {} GG bb {} GG bb {} GG bb {} GG bb {} HH aa {} HH aa {} HH aa {} HH bb {} HH bb {} HH bb {} HH bb {} HH bb {} HH bb {} II aa {} II aa {} II bb {} II bb {} II bb {} II bb {} II bb {} JJ aa {} JJ aa {} JJ aa {} JJ aa {} JJ bb {} JJ bb {} JJ bb {} JJ bb {}} do_execsql_test 1.17.2 { SELECT a, b, sum(c) OVER (ORDER BY a,b GROUPS BETWEEN 1 FOLLOWING AND 0 FOLLOWING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa {} AA aa {} AA aa {} AA aa {} AA bb {} AA bb {} AA bb {} AA bb {} BB aa {} BB aa {} BB aa {} BB aa {} BB aa {} BB aa {} BB bb {} BB bb {} BB bb {} BB bb {} BB bb {} BB bb {} CC aa {} CC aa {} CC aa {} CC aa {} CC bb {} CC bb {} DD aa {} DD aa {} DD aa {} DD bb {} DD bb {} DD bb {} DD bb {} EE aa {} EE aa {} EE bb {} EE bb {} EE bb {} FF aa {} FF aa {} FF aa {} FF aa {} FF bb {} FF bb {} FF bb {} FF bb {} FF bb {} FF bb {} GG aa {} GG aa {} GG aa {} GG aa {} GG bb {} GG bb {} GG bb {} GG bb {} HH aa {} HH aa {} HH aa {} HH bb {} HH bb {} HH bb {} HH bb {} HH bb {} HH bb {} II aa {} II aa {} II bb {} II bb {} II bb {} II bb {} II bb {} JJ aa {} JJ aa {} JJ aa {} JJ aa {} JJ bb {} JJ bb {} JJ bb {} JJ bb {}} do_execsql_test 1.17.3 { SELECT a, b, rank() OVER (ORDER BY a GROUPS BETWEEN 1 FOLLOWING AND 0 FOLLOWING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa 1 AA aa 1 AA aa 1 AA aa 1 AA bb 1 AA bb 1 AA bb 1 AA bb 1 BB aa 9 BB aa 9 BB aa 9 BB aa 9 BB aa 9 BB aa 9 BB bb 9 BB bb 9 BB bb 9 BB bb 9 BB bb 9 BB bb 9 CC aa 21 CC aa 21 CC aa 21 CC aa 21 CC bb 21 CC bb 21 DD aa 27 DD aa 27 DD aa 27 DD bb 27 DD bb 27 DD bb 27 DD bb 27 EE aa 34 EE aa 34 EE bb 34 EE bb 34 EE bb 34 FF aa 39 FF aa 39 FF aa 39 FF aa 39 FF bb 39 FF bb 39 FF bb 39 FF bb 39 FF bb 39 FF bb 39 GG aa 49 GG aa 49 GG aa 49 GG aa 49 GG bb 49 GG bb 49 GG bb 49 GG bb 49 HH aa 57 HH aa 57 HH aa 57 HH bb 57 HH bb 57 HH bb 57 HH bb 57 HH bb 57 HH bb 57 II aa 66 II aa 66 II bb 66 II bb 66 II bb 66 II bb 66 II bb 66 JJ aa 73 JJ aa 73 JJ aa 73 JJ aa 73 JJ bb 73 JJ bb 73 JJ bb 73 JJ bb 73} do_execsql_test 1.17.4 { SELECT a, b, max(c) OVER (ORDER BY a,b GROUPS BETWEEN 1 FOLLOWING AND 0 FOLLOWING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa {} AA aa {} AA aa {} AA aa {} AA bb {} AA bb {} AA bb {} AA bb {} BB aa {} BB aa {} BB aa {} BB aa {} BB aa {} BB aa {} BB bb {} BB bb {} BB bb {} BB bb {} BB bb {} BB bb {} CC aa {} CC aa {} CC aa {} CC aa {} CC bb {} CC bb {} DD aa {} DD aa {} DD aa {} DD bb {} DD bb {} DD bb {} DD bb {} EE aa {} EE aa {} EE bb {} EE bb {} EE bb {} FF aa {} FF aa {} FF aa {} FF aa {} FF bb {} FF bb {} FF bb {} FF bb {} FF bb {} FF bb {} GG aa {} GG aa {} GG aa {} GG aa {} GG bb {} GG bb {} GG bb {} GG bb {} HH aa {} HH aa {} HH aa {} HH bb {} HH bb {} HH bb {} HH bb {} HH bb {} HH bb {} II aa {} II aa {} II bb {} II bb {} II bb {} II bb {} II bb {} JJ aa {} JJ aa {} JJ aa {} JJ aa {} JJ bb {} JJ bb {} JJ bb {} JJ bb {}} do_execsql_test 1.17.5 { SELECT a, b, min(c) OVER (ORDER BY a,b GROUPS BETWEEN 1 FOLLOWING AND 0 FOLLOWING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa {} AA aa {} AA aa {} AA aa {} AA bb {} AA bb {} AA bb {} AA bb {} BB aa {} BB aa {} BB aa {} BB aa {} BB aa {} BB aa {} BB bb {} BB bb {} BB bb {} BB bb {} BB bb {} BB bb {} CC aa {} CC aa {} CC aa {} CC aa {} CC bb {} CC bb {} DD aa {} DD aa {} DD aa {} DD bb {} DD bb {} DD bb {} DD bb {} EE aa {} EE aa {} EE bb {} EE bb {} EE bb {} FF aa {} FF aa {} FF aa {} FF aa {} FF bb {} FF bb {} FF bb {} FF bb {} FF bb {} FF bb {} GG aa {} GG aa {} GG aa {} GG aa {} GG bb {} GG bb {} GG bb {} GG bb {} HH aa {} HH aa {} HH aa {} HH bb {} HH bb {} HH bb {} HH bb {} HH bb {} HH bb {} II aa {} II aa {} II bb {} II bb {} II bb {} II bb {} II bb {} JJ aa {} JJ aa {} JJ aa {} JJ aa {} JJ bb {} JJ bb {} JJ bb {} JJ bb {}} do_execsql_test 1.17.6 { SELECT a, b, sum(c) OVER (ORDER BY a GROUPS BETWEEN 1 FOLLOWING AND 0 FOLLOWING EXCLUDE CURRENT ROW) FROM t3 ORDER BY 1, 2, 3; } {AA aa {} AA aa {} AA aa {} AA aa {} AA bb {} AA bb {} AA bb {} AA bb {} BB aa {} BB aa {} BB aa {} BB aa {} BB aa {} BB aa {} BB bb {} BB bb {} BB bb {} BB bb {} BB bb {} BB bb {} CC aa {} CC aa {} CC aa {} CC aa {} CC bb {} CC bb {} DD aa {} DD aa {} DD aa {} DD bb {} DD bb {} DD bb {} DD bb {} EE aa {} EE aa {} EE bb {} EE bb {} EE bb {} FF aa {} FF aa {} FF aa {} FF aa {} FF bb {} FF bb {} FF bb {} FF bb {} FF bb {} FF bb {} GG aa {} GG aa {} GG aa {} GG aa {} GG bb {} GG bb {} GG bb {} GG bb {} HH aa {} HH aa {} HH aa {} HH bb {} HH bb {} HH bb {} HH bb {} HH bb {} HH bb {} II aa {} II aa {} II bb {} II bb {} II bb {} II bb {} II bb {} JJ aa {} JJ aa {} JJ aa {} JJ aa {} JJ bb {} JJ bb {} JJ bb {} JJ bb {}} do_execsql_test 1.17.7 { SELECT a, b, sum(c) OVER (ORDER BY a,b GROUPS BETWEEN 1 FOLLOWING AND 0 FOLLOWING EXCLUDE CURRENT ROW) FROM t3 ORDER BY 1, 2, 3; } {AA aa {} AA aa {} AA aa {} AA aa {} AA bb {} AA bb {} AA bb {} AA bb {} BB aa {} BB aa {} BB aa {} BB aa {} BB aa {} BB aa {} BB bb {} BB bb {} BB bb {} BB bb {} BB bb {} BB bb {} CC aa {} CC aa {} CC aa {} CC aa {} CC bb {} CC bb {} DD aa {} DD aa {} DD aa {} DD bb {} DD bb {} DD bb {} DD bb {} EE aa {} EE aa {} EE bb {} EE bb {} EE bb {} FF aa {} FF aa {} FF aa {} FF aa {} FF bb {} FF bb {} FF bb {} FF bb {} FF bb {} FF bb {} GG aa {} GG aa {} GG aa {} GG aa {} GG bb {} GG bb {} GG bb {} GG bb {} HH aa {} HH aa {} HH aa {} HH bb {} HH bb {} HH bb {} HH bb {} HH bb {} HH bb {} II aa {} II aa {} II bb {} II bb {} II bb {} II bb {} II bb {} JJ aa {} JJ aa {} JJ aa {} JJ aa {} JJ bb {} JJ bb {} JJ bb {} JJ bb {}} do_execsql_test 1.17.8 { SELECT a, b, sum(c) OVER (ORDER BY a GROUPS BETWEEN 1 FOLLOWING AND 0 FOLLOWING EXCLUDE CURRENT ROW), sum(c) OVER (ORDER BY a GROUPS BETWEEN 1 FOLLOWING AND 0 FOLLOWING ), sum(c) OVER (ORDER BY a,b GROUPS BETWEEN 1 FOLLOWING AND 0 FOLLOWING EXCLUDE CURRENT ROW), sum(c) OVER (ORDER BY a,b GROUPS BETWEEN 1 FOLLOWING AND 0 FOLLOWING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa {} {} {} {} AA aa {} {} {} {} AA aa {} {} {} {} AA aa {} {} {} {} AA bb {} {} {} {} AA bb {} {} {} {} AA bb {} {} {} {} AA bb {} {} {} {} BB aa {} {} {} {} BB aa {} {} {} {} BB aa {} {} {} {} BB aa {} {} {} {} BB aa {} {} {} {} BB aa {} {} {} {} BB bb {} {} {} {} BB bb {} {} {} {} BB bb {} {} {} {} BB bb {} {} {} {} BB bb {} {} {} {} BB bb {} {} {} {} CC aa {} {} {} {} CC aa {} {} {} {} CC aa {} {} {} {} CC aa {} {} {} {} CC bb {} {} {} {} CC bb {} {} {} {} DD aa {} {} {} {} DD aa {} {} {} {} DD aa {} {} {} {} DD bb {} {} {} {} DD bb {} {} {} {} DD bb {} {} {} {} DD bb {} {} {} {} EE aa {} {} {} {} EE aa {} {} {} {} EE bb {} {} {} {} EE bb {} {} {} {} EE bb {} {} {} {} FF aa {} {} {} {} FF aa {} {} {} {} FF aa {} {} {} {} FF aa {} {} {} {} FF bb {} {} {} {} FF bb {} {} {} {} FF bb {} {} {} {} FF bb {} {} {} {} FF bb {} {} {} {} FF bb {} {} {} {} GG aa {} {} {} {} GG aa {} {} {} {} GG aa {} {} {} {} GG aa {} {} {} {} GG bb {} {} {} {} GG bb {} {} {} {} GG bb {} {} {} {} GG bb {} {} {} {} HH aa {} {} {} {} HH aa {} {} {} {} HH aa {} {} {} {} HH bb {} {} {} {} HH bb {} {} {} {} HH bb {} {} {} {} HH bb {} {} {} {} HH bb {} {} {} {} HH bb {} {} {} {} II aa {} {} {} {} II aa {} {} {} {} II bb {} {} {} {} II bb {} {} {} {} II bb {} {} {} {} II bb {} {} {} {} II bb {} {} {} {} JJ aa {} {} {} {} JJ aa {} {} {} {} JJ aa {} {} {} {} JJ aa {} {} {} {} JJ bb {} {} {} {} JJ bb {} {} {} {} JJ bb {} {} {} {} JJ bb {} {} {} {}} do_execsql_test 1.18.1 { SELECT a, b, sum(c) OVER (ORDER BY a GROUPS BETWEEN 1 FOLLOWING AND 5 FOLLOWING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa 22701 AA aa 22701 AA aa 22701 AA aa 22701 AA bb 22701 AA bb 22701 AA bb 22701 AA bb 22701 BB aa 19829 BB aa 19829 BB aa 19829 BB aa 19829 BB aa 19829 BB aa 19829 BB bb 19829 BB bb 19829 BB bb 19829 BB bb 19829 BB bb 19829 BB bb 19829 CC aa 22150 CC aa 22150 CC aa 22150 CC aa 22150 CC bb 22150 CC bb 22150 DD aa 21758 DD aa 21758 DD aa 21758 DD bb 21758 DD bb 21758 DD bb 21758 DD bb 21758 EE aa 23019 EE aa 23019 EE bb 23019 EE bb 23019 EE bb 23019 FF aa 17351 FF aa 17351 FF aa 17351 FF aa 17351 FF bb 17351 FF bb 17351 FF bb 17351 FF bb 17351 FF bb 17351 FF bb 17351 GG aa 12883 GG aa 12883 GG aa 12883 GG aa 12883 GG bb 12883 GG bb 12883 GG bb 12883 GG bb 12883 HH aa 7440 HH aa 7440 HH aa 7440 HH bb 7440 HH bb 7440 HH bb 7440 HH bb 7440 HH bb 7440 HH bb 7440 II aa 3800 II aa 3800 II bb 3800 II bb 3800 II bb 3800 II bb 3800 II bb 3800 JJ aa {} JJ aa {} JJ aa {} JJ aa {} JJ bb {} JJ bb {} JJ bb {} JJ bb {}} do_execsql_test 1.18.2 { SELECT a, b, sum(c) OVER (ORDER BY a,b GROUPS BETWEEN 1 FOLLOWING AND 5 FOLLOWING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa 12840 AA aa 12840 AA aa 12840 AA aa 12840 AA bb 11787 AA bb 11787 AA bb 11787 AA bb 11787 BB aa 11621 BB aa 11621 BB aa 11621 BB aa 11621 BB aa 11621 BB aa 11621 BB bb 8044 BB bb 8044 BB bb 8044 BB bb 8044 BB bb 8044 BB bb 8044 CC aa 7739 CC aa 7739 CC aa 7739 CC aa 7739 CC bb 8734 CC bb 8734 DD aa 10914 DD aa 10914 DD aa 10914 DD bb 9804 DD bb 9804 DD bb 9804 DD bb 9804 EE aa 11785 EE aa 11785 EE bb 12385 EE bb 12385 EE bb 12385 FF aa 13416 FF aa 13416 FF aa 13416 FF aa 13416 FF bb 10961 FF bb 10961 FF bb 10961 FF bb 10961 FF bb 10961 FF bb 10961 GG aa 11954 GG aa 11954 GG aa 11954 GG aa 11954 GG bb 11097 GG bb 11097 GG bb 11097 GG bb 11097 HH aa 10634 HH aa 10634 HH aa 10634 HH bb 7440 HH bb 7440 HH bb 7440 HH bb 7440 HH bb 7440 HH bb 7440 II aa 6390 II aa 6390 II bb 3800 II bb 3800 II bb 3800 II bb 3800 II bb 3800 JJ aa 1786 JJ aa 1786 JJ aa 1786 JJ aa 1786 JJ bb {} JJ bb {} JJ bb {} JJ bb {}} do_execsql_test 1.18.3 { SELECT a, b, rank() OVER (ORDER BY a GROUPS BETWEEN 1 FOLLOWING AND 5 FOLLOWING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa 1 AA aa 1 AA aa 1 AA aa 1 AA bb 1 AA bb 1 AA bb 1 AA bb 1 BB aa 9 BB aa 9 BB aa 9 BB aa 9 BB aa 9 BB aa 9 BB bb 9 BB bb 9 BB bb 9 BB bb 9 BB bb 9 BB bb 9 CC aa 21 CC aa 21 CC aa 21 CC aa 21 CC bb 21 CC bb 21 DD aa 27 DD aa 27 DD aa 27 DD bb 27 DD bb 27 DD bb 27 DD bb 27 EE aa 34 EE aa 34 EE bb 34 EE bb 34 EE bb 34 FF aa 39 FF aa 39 FF aa 39 FF aa 39 FF bb 39 FF bb 39 FF bb 39 FF bb 39 FF bb 39 FF bb 39 GG aa 49 GG aa 49 GG aa 49 GG aa 49 GG bb 49 GG bb 49 GG bb 49 GG bb 49 HH aa 57 HH aa 57 HH aa 57 HH bb 57 HH bb 57 HH bb 57 HH bb 57 HH bb 57 HH bb 57 II aa 66 II aa 66 II bb 66 II bb 66 II bb 66 II bb 66 II bb 66 JJ aa 73 JJ aa 73 JJ aa 73 JJ aa 73 JJ bb 73 JJ bb 73 JJ bb 73 JJ bb 73} do_execsql_test 1.18.4 { SELECT a, b, max(c) OVER (ORDER BY a,b GROUPS BETWEEN 1 FOLLOWING AND 5 FOLLOWING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa 870 AA aa 870 AA aa 870 AA aa 870 AA bb 845 AA bb 845 AA bb 845 AA bb 845 BB aa 959 BB aa 959 BB aa 959 BB aa 959 BB aa 959 BB aa 959 BB bb 959 BB bb 959 BB bb 959 BB bb 959 BB bb 959 BB bb 959 CC aa 959 CC aa 959 CC aa 959 CC aa 959 CC bb 959 CC bb 959 DD aa 959 DD aa 959 DD aa 959 DD bb 938 DD bb 938 DD bb 938 DD bb 938 EE aa 938 EE aa 938 EE bb 979 EE bb 979 EE bb 979 FF aa 979 FF aa 979 FF aa 979 FF aa 979 FF bb 979 FF bb 979 FF bb 979 FF bb 979 FF bb 979 FF bb 979 GG aa 979 GG aa 979 GG aa 979 GG aa 979 GG bb 979 GG bb 979 GG bb 979 GG bb 979 HH aa 963 HH aa 963 HH aa 963 HH bb 899 HH bb 899 HH bb 899 HH bb 899 HH bb 899 HH bb 899 II aa 899 II aa 899 II bb 899 II bb 899 II bb 899 II bb 899 II bb 899 JJ aa 839 JJ aa 839 JJ aa 839 JJ aa 839 JJ bb {} JJ bb {} JJ bb {} JJ bb {}} do_execsql_test 1.18.5 { SELECT a, b, min(c) OVER (ORDER BY a,b GROUPS BETWEEN 1 FOLLOWING AND 5 FOLLOWING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa 158 AA aa 158 AA aa 158 AA aa 158 AA bb 158 AA bb 158 AA bb 158 AA bb 158 BB aa 158 BB aa 158 BB aa 158 BB aa 158 BB aa 158 BB aa 158 BB bb 113 BB bb 113 BB bb 113 BB bb 113 BB bb 113 BB bb 113 CC aa 113 CC aa 113 CC aa 113 CC aa 113 CC bb 113 CC bb 113 DD aa 102 DD aa 102 DD aa 102 DD bb 102 DD bb 102 DD bb 102 DD bb 102 EE aa 102 EE aa 102 EE bb 102 EE bb 102 EE bb 102 FF aa 102 FF aa 102 FF aa 102 FF aa 102 FF bb 133 FF bb 133 FF bb 133 FF bb 133 FF bb 133 FF bb 133 GG aa 133 GG aa 133 GG aa 133 GG aa 133 GG bb 113 GG bb 113 GG bb 113 GG bb 113 HH aa 113 HH aa 113 HH aa 113 HH bb 113 HH bb 113 HH bb 113 HH bb 113 HH bb 113 HH bb 113 II aa 113 II aa 113 II bb 113 II bb 113 II bb 113 II bb 113 II bb 113 JJ aa 257 JJ aa 257 JJ aa 257 JJ aa 257 JJ bb {} JJ bb {} JJ bb {} JJ bb {}} do_execsql_test 1.18.6 { SELECT a, b, sum(c) OVER (ORDER BY a GROUPS BETWEEN 1 FOLLOWING AND 5 FOLLOWING EXCLUDE CURRENT ROW) FROM t3 ORDER BY 1, 2, 3; } {AA aa 22701 AA aa 22701 AA aa 22701 AA aa 22701 AA bb 22701 AA bb 22701 AA bb 22701 AA bb 22701 BB aa 19829 BB aa 19829 BB aa 19829 BB aa 19829 BB aa 19829 BB aa 19829 BB bb 19829 BB bb 19829 BB bb 19829 BB bb 19829 BB bb 19829 BB bb 19829 CC aa 22150 CC aa 22150 CC aa 22150 CC aa 22150 CC bb 22150 CC bb 22150 DD aa 21758 DD aa 21758 DD aa 21758 DD bb 21758 DD bb 21758 DD bb 21758 DD bb 21758 EE aa 23019 EE aa 23019 EE bb 23019 EE bb 23019 EE bb 23019 FF aa 17351 FF aa 17351 FF aa 17351 FF aa 17351 FF bb 17351 FF bb 17351 FF bb 17351 FF bb 17351 FF bb 17351 FF bb 17351 GG aa 12883 GG aa 12883 GG aa 12883 GG aa 12883 GG bb 12883 GG bb 12883 GG bb 12883 GG bb 12883 HH aa 7440 HH aa 7440 HH aa 7440 HH bb 7440 HH bb 7440 HH bb 7440 HH bb 7440 HH bb 7440 HH bb 7440 II aa 3800 II aa 3800 II bb 3800 II bb 3800 II bb 3800 II bb 3800 II bb 3800 JJ aa {} JJ aa {} JJ aa {} JJ aa {} JJ bb {} JJ bb {} JJ bb {} JJ bb {}} do_execsql_test 1.18.7 { SELECT a, b, sum(c) OVER (ORDER BY a,b GROUPS BETWEEN 1 FOLLOWING AND 5 FOLLOWING EXCLUDE CURRENT ROW) FROM t3 ORDER BY 1, 2, 3; } {AA aa 12840 AA aa 12840 AA aa 12840 AA aa 12840 AA bb 11787 AA bb 11787 AA bb 11787 AA bb 11787 BB aa 11621 BB aa 11621 BB aa 11621 BB aa 11621 BB aa 11621 BB aa 11621 BB bb 8044 BB bb 8044 BB bb 8044 BB bb 8044 BB bb 8044 BB bb 8044 CC aa 7739 CC aa 7739 CC aa 7739 CC aa 7739 CC bb 8734 CC bb 8734 DD aa 10914 DD aa 10914 DD aa 10914 DD bb 9804 DD bb 9804 DD bb 9804 DD bb 9804 EE aa 11785 EE aa 11785 EE bb 12385 EE bb 12385 EE bb 12385 FF aa 13416 FF aa 13416 FF aa 13416 FF aa 13416 FF bb 10961 FF bb 10961 FF bb 10961 FF bb 10961 FF bb 10961 FF bb 10961 GG aa 11954 GG aa 11954 GG aa 11954 GG aa 11954 GG bb 11097 GG bb 11097 GG bb 11097 GG bb 11097 HH aa 10634 HH aa 10634 HH aa 10634 HH bb 7440 HH bb 7440 HH bb 7440 HH bb 7440 HH bb 7440 HH bb 7440 II aa 6390 II aa 6390 II bb 3800 II bb 3800 II bb 3800 II bb 3800 II bb 3800 JJ aa 1786 JJ aa 1786 JJ aa 1786 JJ aa 1786 JJ bb {} JJ bb {} JJ bb {} JJ bb {}} do_execsql_test 1.18.8 { SELECT a, b, sum(c) OVER (ORDER BY a GROUPS BETWEEN 1 FOLLOWING AND 5 FOLLOWING EXCLUDE CURRENT ROW), sum(c) OVER (ORDER BY a GROUPS BETWEEN 1 FOLLOWING AND 5 FOLLOWING ), sum(c) OVER (ORDER BY a,b GROUPS BETWEEN 1 FOLLOWING AND 5 FOLLOWING EXCLUDE CURRENT ROW), sum(c) OVER (ORDER BY a,b GROUPS BETWEEN 1 FOLLOWING AND 5 FOLLOWING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa 22701 22701 12840 12840 AA aa 22701 22701 12840 12840 AA aa 22701 22701 12840 12840 AA aa 22701 22701 12840 12840 AA bb 22701 22701 11787 11787 AA bb 22701 22701 11787 11787 AA bb 22701 22701 11787 11787 AA bb 22701 22701 11787 11787 BB aa 19829 19829 11621 11621 BB aa 19829 19829 11621 11621 BB aa 19829 19829 11621 11621 BB aa 19829 19829 11621 11621 BB aa 19829 19829 11621 11621 BB aa 19829 19829 11621 11621 BB bb 19829 19829 8044 8044 BB bb 19829 19829 8044 8044 BB bb 19829 19829 8044 8044 BB bb 19829 19829 8044 8044 BB bb 19829 19829 8044 8044 BB bb 19829 19829 8044 8044 CC aa 22150 22150 7739 7739 CC aa 22150 22150 7739 7739 CC aa 22150 22150 7739 7739 CC aa 22150 22150 7739 7739 CC bb 22150 22150 8734 8734 CC bb 22150 22150 8734 8734 DD aa 21758 21758 10914 10914 DD aa 21758 21758 10914 10914 DD aa 21758 21758 10914 10914 DD bb 21758 21758 9804 9804 DD bb 21758 21758 9804 9804 DD bb 21758 21758 9804 9804 DD bb 21758 21758 9804 9804 EE aa 23019 23019 11785 11785 EE aa 23019 23019 11785 11785 EE bb 23019 23019 12385 12385 EE bb 23019 23019 12385 12385 EE bb 23019 23019 12385 12385 FF aa 17351 17351 13416 13416 FF aa 17351 17351 13416 13416 FF aa 17351 17351 13416 13416 FF aa 17351 17351 13416 13416 FF bb 17351 17351 10961 10961 FF bb 17351 17351 10961 10961 FF bb 17351 17351 10961 10961 FF bb 17351 17351 10961 10961 FF bb 17351 17351 10961 10961 FF bb 17351 17351 10961 10961 GG aa 12883 12883 11954 11954 GG aa 12883 12883 11954 11954 GG aa 12883 12883 11954 11954 GG aa 12883 12883 11954 11954 GG bb 12883 12883 11097 11097 GG bb 12883 12883 11097 11097 GG bb 12883 12883 11097 11097 GG bb 12883 12883 11097 11097 HH aa 7440 7440 10634 10634 HH aa 7440 7440 10634 10634 HH aa 7440 7440 10634 10634 HH bb 7440 7440 7440 7440 HH bb 7440 7440 7440 7440 HH bb 7440 7440 7440 7440 HH bb 7440 7440 7440 7440 HH bb 7440 7440 7440 7440 HH bb 7440 7440 7440 7440 II aa 3800 3800 6390 6390 II aa 3800 3800 6390 6390 II bb 3800 3800 3800 3800 II bb 3800 3800 3800 3800 II bb 3800 3800 3800 3800 II bb 3800 3800 3800 3800 II bb 3800 3800 3800 3800 JJ aa {} {} 1786 1786 JJ aa {} {} 1786 1786 JJ aa {} {} 1786 1786 JJ aa {} {} 1786 1786 JJ bb {} {} {} {} JJ bb {} {} {} {} JJ bb {} {} {} {} JJ bb {} {} {} {}} do_execsql_test 1.19.1 { SELECT a, b, sum(c) OVER (ORDER BY a GROUPS BETWEEN 1 FOLLOWING AND UNBOUNDED FOLLOWING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa 40052 AA aa 40052 AA aa 40052 AA aa 40052 AA bb 40052 AA bb 40052 AA bb 40052 AA bb 40052 BB aa 32712 BB aa 32712 BB aa 32712 BB aa 32712 BB aa 32712 BB aa 32712 BB bb 32712 BB bb 32712 BB bb 32712 BB bb 32712 BB bb 32712 BB bb 32712 CC aa 29590 CC aa 29590 CC aa 29590 CC aa 29590 CC bb 29590 CC bb 29590 DD aa 25558 DD aa 25558 DD aa 25558 DD bb 25558 DD bb 25558 DD bb 25558 DD bb 25558 EE aa 23019 EE aa 23019 EE bb 23019 EE bb 23019 EE bb 23019 FF aa 17351 FF aa 17351 FF aa 17351 FF aa 17351 FF bb 17351 FF bb 17351 FF bb 17351 FF bb 17351 FF bb 17351 FF bb 17351 GG aa 12883 GG aa 12883 GG aa 12883 GG aa 12883 GG bb 12883 GG bb 12883 GG bb 12883 GG bb 12883 HH aa 7440 HH aa 7440 HH aa 7440 HH bb 7440 HH bb 7440 HH bb 7440 HH bb 7440 HH bb 7440 HH bb 7440 II aa 3800 II aa 3800 II bb 3800 II bb 3800 II bb 3800 II bb 3800 II bb 3800 JJ aa {} JJ aa {} JJ aa {} JJ aa {} JJ bb {} JJ bb {} JJ bb {} JJ bb {}} do_execsql_test 1.19.2 { SELECT a, b, sum(c) OVER (ORDER BY a,b GROUPS BETWEEN 1 FOLLOWING AND UNBOUNDED FOLLOWING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa 42430 AA aa 42430 AA aa 42430 AA aa 42430 AA bb 40052 AA bb 40052 AA bb 40052 AA bb 40052 BB aa 37179 BB aa 37179 BB aa 37179 BB aa 37179 BB aa 37179 BB aa 37179 BB bb 32712 BB bb 32712 BB bb 32712 BB bb 32712 BB bb 32712 BB bb 32712 CC aa 30758 CC aa 30758 CC aa 30758 CC aa 30758 CC bb 29590 CC bb 29590 DD aa 28265 DD aa 28265 DD aa 28265 DD bb 25558 DD bb 25558 DD bb 25558 DD bb 25558 EE aa 24668 EE aa 24668 EE bb 23019 EE bb 23019 EE bb 23019 FF aa 20856 FF aa 20856 FF aa 20856 FF aa 20856 FF bb 17351 FF bb 17351 FF bb 17351 FF bb 17351 FF bb 17351 FF bb 17351 GG aa 15754 GG aa 15754 GG aa 15754 GG aa 15754 GG bb 12883 GG bb 12883 GG bb 12883 GG bb 12883 HH aa 10634 HH aa 10634 HH aa 10634 HH bb 7440 HH bb 7440 HH bb 7440 HH bb 7440 HH bb 7440 HH bb 7440 II aa 6390 II aa 6390 II bb 3800 II bb 3800 II bb 3800 II bb 3800 II bb 3800 JJ aa 1786 JJ aa 1786 JJ aa 1786 JJ aa 1786 JJ bb {} JJ bb {} JJ bb {} JJ bb {}} do_execsql_test 1.19.3 { SELECT a, b, rank() OVER (ORDER BY a GROUPS BETWEEN 1 FOLLOWING AND UNBOUNDED FOLLOWING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa 1 AA aa 1 AA aa 1 AA aa 1 AA bb 1 AA bb 1 AA bb 1 AA bb 1 BB aa 9 BB aa 9 BB aa 9 BB aa 9 BB aa 9 BB aa 9 BB bb 9 BB bb 9 BB bb 9 BB bb 9 BB bb 9 BB bb 9 CC aa 21 CC aa 21 CC aa 21 CC aa 21 CC bb 21 CC bb 21 DD aa 27 DD aa 27 DD aa 27 DD bb 27 DD bb 27 DD bb 27 DD bb 27 EE aa 34 EE aa 34 EE bb 34 EE bb 34 EE bb 34 FF aa 39 FF aa 39 FF aa 39 FF aa 39 FF bb 39 FF bb 39 FF bb 39 FF bb 39 FF bb 39 FF bb 39 GG aa 49 GG aa 49 GG aa 49 GG aa 49 GG bb 49 GG bb 49 GG bb 49 GG bb 49 HH aa 57 HH aa 57 HH aa 57 HH bb 57 HH bb 57 HH bb 57 HH bb 57 HH bb 57 HH bb 57 II aa 66 II aa 66 II bb 66 II bb 66 II bb 66 II bb 66 II bb 66 JJ aa 73 JJ aa 73 JJ aa 73 JJ aa 73 JJ bb 73 JJ bb 73 JJ bb 73 JJ bb 73} do_execsql_test 1.19.4 { SELECT a, b, max(c) OVER (ORDER BY a,b GROUPS BETWEEN 1 FOLLOWING AND UNBOUNDED FOLLOWING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa 979 AA aa 979 AA aa 979 AA aa 979 AA bb 979 AA bb 979 AA bb 979 AA bb 979 BB aa 979 BB aa 979 BB aa 979 BB aa 979 BB aa 979 BB aa 979 BB bb 979 BB bb 979 BB bb 979 BB bb 979 BB bb 979 BB bb 979 CC aa 979 CC aa 979 CC aa 979 CC aa 979 CC bb 979 CC bb 979 DD aa 979 DD aa 979 DD aa 979 DD bb 979 DD bb 979 DD bb 979 DD bb 979 EE aa 979 EE aa 979 EE bb 979 EE bb 979 EE bb 979 FF aa 979 FF aa 979 FF aa 979 FF aa 979 FF bb 979 FF bb 979 FF bb 979 FF bb 979 FF bb 979 FF bb 979 GG aa 979 GG aa 979 GG aa 979 GG aa 979 GG bb 979 GG bb 979 GG bb 979 GG bb 979 HH aa 963 HH aa 963 HH aa 963 HH bb 899 HH bb 899 HH bb 899 HH bb 899 HH bb 899 HH bb 899 II aa 899 II aa 899 II bb 899 II bb 899 II bb 899 II bb 899 II bb 899 JJ aa 839 JJ aa 839 JJ aa 839 JJ aa 839 JJ bb {} JJ bb {} JJ bb {} JJ bb {}} do_execsql_test 1.19.5 { SELECT a, b, min(c) OVER (ORDER BY a,b GROUPS BETWEEN 1 FOLLOWING AND UNBOUNDED FOLLOWING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa 102 AA aa 102 AA aa 102 AA aa 102 AA bb 102 AA bb 102 AA bb 102 AA bb 102 BB aa 102 BB aa 102 BB aa 102 BB aa 102 BB aa 102 BB aa 102 BB bb 102 BB bb 102 BB bb 102 BB bb 102 BB bb 102 BB bb 102 CC aa 102 CC aa 102 CC aa 102 CC aa 102 CC bb 102 CC bb 102 DD aa 102 DD aa 102 DD aa 102 DD bb 102 DD bb 102 DD bb 102 DD bb 102 EE aa 102 EE aa 102 EE bb 102 EE bb 102 EE bb 102 FF aa 102 FF aa 102 FF aa 102 FF aa 102 FF bb 113 FF bb 113 FF bb 113 FF bb 113 FF bb 113 FF bb 113 GG aa 113 GG aa 113 GG aa 113 GG aa 113 GG bb 113 GG bb 113 GG bb 113 GG bb 113 HH aa 113 HH aa 113 HH aa 113 HH bb 113 HH bb 113 HH bb 113 HH bb 113 HH bb 113 HH bb 113 II aa 113 II aa 113 II bb 113 II bb 113 II bb 113 II bb 113 II bb 113 JJ aa 257 JJ aa 257 JJ aa 257 JJ aa 257 JJ bb {} JJ bb {} JJ bb {} JJ bb {}} do_execsql_test 1.19.6 { SELECT a, b, sum(c) OVER (ORDER BY a GROUPS BETWEEN 1 FOLLOWING AND UNBOUNDED FOLLOWING EXCLUDE CURRENT ROW) FROM t3 ORDER BY 1, 2, 3; } {AA aa 40052 AA aa 40052 AA aa 40052 AA aa 40052 AA bb 40052 AA bb 40052 AA bb 40052 AA bb 40052 BB aa 32712 BB aa 32712 BB aa 32712 BB aa 32712 BB aa 32712 BB aa 32712 BB bb 32712 BB bb 32712 BB bb 32712 BB bb 32712 BB bb 32712 BB bb 32712 CC aa 29590 CC aa 29590 CC aa 29590 CC aa 29590 CC bb 29590 CC bb 29590 DD aa 25558 DD aa 25558 DD aa 25558 DD bb 25558 DD bb 25558 DD bb 25558 DD bb 25558 EE aa 23019 EE aa 23019 EE bb 23019 EE bb 23019 EE bb 23019 FF aa 17351 FF aa 17351 FF aa 17351 FF aa 17351 FF bb 17351 FF bb 17351 FF bb 17351 FF bb 17351 FF bb 17351 FF bb 17351 GG aa 12883 GG aa 12883 GG aa 12883 GG aa 12883 GG bb 12883 GG bb 12883 GG bb 12883 GG bb 12883 HH aa 7440 HH aa 7440 HH aa 7440 HH bb 7440 HH bb 7440 HH bb 7440 HH bb 7440 HH bb 7440 HH bb 7440 II aa 3800 II aa 3800 II bb 3800 II bb 3800 II bb 3800 II bb 3800 II bb 3800 JJ aa {} JJ aa {} JJ aa {} JJ aa {} JJ bb {} JJ bb {} JJ bb {} JJ bb {}} do_execsql_test 1.19.7 { SELECT a, b, sum(c) OVER (ORDER BY a,b GROUPS BETWEEN 1 FOLLOWING AND UNBOUNDED FOLLOWING EXCLUDE CURRENT ROW) FROM t3 ORDER BY 1, 2, 3; } {AA aa 42430 AA aa 42430 AA aa 42430 AA aa 42430 AA bb 40052 AA bb 40052 AA bb 40052 AA bb 40052 BB aa 37179 BB aa 37179 BB aa 37179 BB aa 37179 BB aa 37179 BB aa 37179 BB bb 32712 BB bb 32712 BB bb 32712 BB bb 32712 BB bb 32712 BB bb 32712 CC aa 30758 CC aa 30758 CC aa 30758 CC aa 30758 CC bb 29590 CC bb 29590 DD aa 28265 DD aa 28265 DD aa 28265 DD bb 25558 DD bb 25558 DD bb 25558 DD bb 25558 EE aa 24668 EE aa 24668 EE bb 23019 EE bb 23019 EE bb 23019 FF aa 20856 FF aa 20856 FF aa 20856 FF aa 20856 FF bb 17351 FF bb 17351 FF bb 17351 FF bb 17351 FF bb 17351 FF bb 17351 GG aa 15754 GG aa 15754 GG aa 15754 GG aa 15754 GG bb 12883 GG bb 12883 GG bb 12883 GG bb 12883 HH aa 10634 HH aa 10634 HH aa 10634 HH bb 7440 HH bb 7440 HH bb 7440 HH bb 7440 HH bb 7440 HH bb 7440 II aa 6390 II aa 6390 II bb 3800 II bb 3800 II bb 3800 II bb 3800 II bb 3800 JJ aa 1786 JJ aa 1786 JJ aa 1786 JJ aa 1786 JJ bb {} JJ bb {} JJ bb {} JJ bb {}} do_execsql_test 1.19.8 { SELECT a, b, sum(c) OVER (ORDER BY a GROUPS BETWEEN 1 FOLLOWING AND UNBOUNDED FOLLOWING EXCLUDE CURRENT ROW), sum(c) OVER (ORDER BY a GROUPS BETWEEN 1 FOLLOWING AND UNBOUNDED FOLLOWING ), sum(c) OVER (ORDER BY a,b GROUPS BETWEEN 1 FOLLOWING AND UNBOUNDED FOLLOWING EXCLUDE CURRENT ROW), sum(c) OVER (ORDER BY a,b GROUPS BETWEEN 1 FOLLOWING AND UNBOUNDED FOLLOWING ) FROM t3 ORDER BY 1, 2, 3; } {AA aa 40052 40052 42430 42430 AA aa 40052 40052 42430 42430 AA aa 40052 40052 42430 42430 AA aa 40052 40052 42430 42430 AA bb 40052 40052 40052 40052 AA bb 40052 40052 40052 40052 AA bb 40052 40052 40052 40052 AA bb 40052 40052 40052 40052 BB aa 32712 32712 37179 37179 BB aa 32712 32712 37179 37179 BB aa 32712 32712 37179 37179 BB aa 32712 32712 37179 37179 BB aa 32712 32712 37179 37179 BB aa 32712 32712 37179 37179 BB bb 32712 32712 32712 32712 BB bb 32712 32712 32712 32712 BB bb 32712 32712 32712 32712 BB bb 32712 32712 32712 32712 BB bb 32712 32712 32712 32712 BB bb 32712 32712 32712 32712 CC aa 29590 29590 30758 30758 CC aa 29590 29590 30758 30758 CC aa 29590 29590 30758 30758 CC aa 29590 29590 30758 30758 CC bb 29590 29590 29590 29590 CC bb 29590 29590 29590 29590 DD aa 25558 25558 28265 28265 DD aa 25558 25558 28265 28265 DD aa 25558 25558 28265 28265 DD bb 25558 25558 25558 25558 DD bb 25558 25558 25558 25558 DD bb 25558 25558 25558 25558 DD bb 25558 25558 25558 25558 EE aa 23019 23019 24668 24668 EE aa 23019 23019 24668 24668 EE bb 23019 23019 23019 23019 EE bb 23019 23019 23019 23019 EE bb 23019 23019 23019 23019 FF aa 17351 17351 20856 20856 FF aa 17351 17351 20856 20856 FF aa 17351 17351 20856 20856 FF aa 17351 17351 20856 20856 FF bb 17351 17351 17351 17351 FF bb 17351 17351 17351 17351 FF bb 17351 17351 17351 17351 FF bb 17351 17351 17351 17351 FF bb 17351 17351 17351 17351 FF bb 17351 17351 17351 17351 GG aa 12883 12883 15754 15754 GG aa 12883 12883 15754 15754 GG aa 12883 12883 15754 15754 GG aa 12883 12883 15754 15754 GG bb 12883 12883 12883 12883 GG bb 12883 12883 12883 12883 GG bb 12883 12883 12883 12883 GG bb 12883 12883 12883 12883 HH aa 7440 7440 10634 10634 HH aa 7440 7440 10634 10634 HH aa 7440 7440 10634 10634 HH bb 7440 7440 7440 7440 HH bb 7440 7440 7440 7440 HH bb 7440 7440 7440 7440 HH bb 7440 7440 7440 7440 HH bb 7440 7440 7440 7440 HH bb 7440 7440 7440 7440 II aa 3800 3800 6390 6390 II aa 3800 3800 6390 6390 II bb 3800 3800 3800 3800 II bb 3800 3800 3800 3800 II bb 3800 3800 3800 3800 II bb 3800 3800 3800 3800 II bb 3800 3800 3800 3800 JJ aa {} {} 1786 1786 JJ aa {} {} 1786 1786 JJ aa {} {} 1786 1786 JJ aa {} {} 1786 1786 JJ bb {} {} {} {} JJ bb {} {} {} {} JJ bb {} {} {} {} JJ bb {} {} {} {}} do_execsql_test 2.1.1 { SELECT row_number() OVER win FROM t3 WINDOW win AS ( ORDER BY c, b, a ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING EXCLUDE NO OTHERS ) } {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} do_execsql_test 2.1.2 { SELECT nth_value(c, 14) OVER win FROM t3 WINDOW win AS ( ORDER BY c, b, a ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING EXCLUDE NO OTHERS ) } {247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247} do_execsql_test 2.1.3 { SELECT min(c) OVER win, max(c) OVER win, sum(c) OVER win FROM t3 WINDOW win AS ( ORDER BY c, b, a ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW EXCLUDE NO OTHERS ) ORDER BY a, b, c; } {102 223 1358 102 239 2293 102 911 38097 102 934 39960 102 309 4159 102 572 10643 102 627 13069 102 870 35417 102 247 2540 102 393 6608 102 399 7405 102 412 7817 102 660 16277 102 762 24077 102 633 14331 102 705 19673 102 711 20384 102 786 27176 102 792 28758 102 840 32858 102 158 767 102 430 8668 102 607 11824 102 759 23315 102 346 5506 102 822 31179 102 224 1582 102 256 3298 102 845 34547 102 238 2054 102 716 21100 102 794 29552 102 959 42795 102 113 215 102 777 26390 102 252 3042 102 629 13698 102 768 25613 102 208 1135 102 618 12442 102 667 16944 102 670 17614 102 102 102 102 295 3850 102 574 11217 102 726 21826 102 870 36287 102 938 40898 102 148 609 102 335 4824 102 480 9591 102 634 14965 102 160 927 102 844 33702 102 929 39026 102 938 41836 102 480 10071 102 790 27966 102 979 44737 102 133 461 102 330 4489 102 355 6215 102 683 18968 102 730 22556 102 963 43758 102 398 7006 102 652 15617 102 250 2790 102 421 8238 102 443 9111 102 671 18285 102 805 30357 102 113 328 102 234 1816 102 768 24845 102 899 37186 102 257 3555 102 336 5160 102 354 5860 102 839 32018} do_execsql_test 2.2.1 { SELECT row_number() OVER win FROM t3 WINDOW win AS ( ORDER BY c, b, a ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING EXCLUDE CURRENT ROW ) } {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} do_execsql_test 2.2.2 { SELECT nth_value(c, 14) OVER win FROM t3 WINDOW win AS ( ORDER BY c, b, a ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING EXCLUDE CURRENT ROW ) } {250 250 250 250 250 250 250 250 250 250 250 250 250 250 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247} do_execsql_test 2.2.3 { SELECT min(c) OVER win, max(c) OVER win, sum(c) OVER win FROM t3 WINDOW win AS ( ORDER BY c, b, a ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW EXCLUDE CURRENT ROW ) ORDER BY a, b, c; } {102 208 1135 102 238 2054 102 899 37186 102 929 39026 102 295 3850 102 480 10071 102 618 12442 102 845 34547 102 239 2293 102 355 6215 102 398 7006 102 399 7405 102 652 15617 102 759 23315 102 629 13698 102 683 18968 102 705 19673 102 777 26390 102 790 27966 102 839 32018 102 148 609 102 421 8238 102 574 11217 102 730 22556 102 336 5160 102 805 30357 102 223 1358 102 252 3042 102 844 33702 102 234 1816 102 711 20384 102 792 28758 102 938 41836 102 102 102 102 768 25613 102 250 2790 102 627 13069 102 768 24845 102 160 927 102 607 11824 102 660 16277 102 667 16944 {} {} {} 102 257 3555 102 572 10643 102 716 21100 102 870 35417 102 934 39960 102 133 461 102 330 4489 102 443 9111 102 633 14331 102 158 767 102 840 32858 102 911 38097 102 938 40898 102 480 9591 102 786 27176 102 963 43758 102 113 328 102 309 4159 102 354 5860 102 671 18285 102 726 21826 102 959 42795 102 393 6608 102 634 14965 102 247 2540 102 412 7817 102 430 8668 102 670 17614 102 794 29552 102 113 215 102 224 1582 102 762 24077 102 870 36287 102 256 3298 102 335 4824 102 346 5506 102 822 31179} do_execsql_test 2.3.1 { SELECT row_number() OVER win FROM t3 WINDOW win AS ( ORDER BY c, b, a ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING EXCLUDE GROUP ) } {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} do_execsql_test 2.3.2 { SELECT nth_value(c, 14) OVER win FROM t3 WINDOW win AS ( ORDER BY c, b, a ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING EXCLUDE GROUP ) } {250 250 250 250 250 250 250 250 250 250 250 250 250 250 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247} do_execsql_test 2.3.3 { SELECT min(c) OVER win, max(c) OVER win, sum(c) OVER win FROM t3 WINDOW win AS ( ORDER BY c, b, a ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW EXCLUDE GROUP ) ORDER BY a, b, c; } {102 208 1135 102 238 2054 102 899 37186 102 929 39026 102 295 3850 102 480 10071 102 618 12442 102 845 34547 102 239 2293 102 355 6215 102 398 7006 102 399 7405 102 652 15617 102 759 23315 102 629 13698 102 683 18968 102 705 19673 102 777 26390 102 790 27966 102 839 32018 102 148 609 102 421 8238 102 574 11217 102 730 22556 102 336 5160 102 805 30357 102 223 1358 102 252 3042 102 844 33702 102 234 1816 102 711 20384 102 792 28758 102 938 41836 102 102 102 102 768 25613 102 250 2790 102 627 13069 102 768 24845 102 160 927 102 607 11824 102 660 16277 102 667 16944 {} {} {} 102 257 3555 102 572 10643 102 716 21100 102 870 35417 102 934 39960 102 133 461 102 330 4489 102 443 9111 102 633 14331 102 158 767 102 840 32858 102 911 38097 102 938 40898 102 480 9591 102 786 27176 102 963 43758 102 113 328 102 309 4159 102 354 5860 102 671 18285 102 726 21826 102 959 42795 102 393 6608 102 634 14965 102 247 2540 102 412 7817 102 430 8668 102 670 17614 102 794 29552 102 113 215 102 224 1582 102 762 24077 102 870 36287 102 256 3298 102 335 4824 102 346 5506 102 822 31179} do_execsql_test 2.4.1 { SELECT row_number() OVER win FROM t3 WINDOW win AS ( ORDER BY c, b, a ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING EXCLUDE TIES ) } {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} do_execsql_test 2.4.2 { SELECT nth_value(c, 14) OVER win FROM t3 WINDOW win AS ( ORDER BY c, b, a ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING EXCLUDE TIES ) } {247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247 247} do_execsql_test 2.4.3 { SELECT min(c) OVER win, max(c) OVER win, sum(c) OVER win FROM t3 WINDOW win AS ( ORDER BY c, b, a ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW EXCLUDE TIES ) ORDER BY a, b, c; } {102 223 1358 102 239 2293 102 911 38097 102 934 39960 102 309 4159 102 572 10643 102 627 13069 102 870 35417 102 247 2540 102 393 6608 102 399 7405 102 412 7817 102 660 16277 102 762 24077 102 633 14331 102 705 19673 102 711 20384 102 786 27176 102 792 28758 102 840 32858 102 158 767 102 430 8668 102 607 11824 102 759 23315 102 346 5506 102 822 31179 102 224 1582 102 256 3298 102 845 34547 102 238 2054 102 716 21100 102 794 29552 102 959 42795 102 113 215 102 777 26390 102 252 3042 102 629 13698 102 768 25613 102 208 1135 102 618 12442 102 667 16944 102 670 17614 102 102 102 102 295 3850 102 574 11217 102 726 21826 102 870 36287 102 938 40898 102 148 609 102 335 4824 102 480 9591 102 634 14965 102 160 927 102 844 33702 102 929 39026 102 938 41836 102 480 10071 102 790 27966 102 979 44737 102 133 461 102 330 4489 102 355 6215 102 683 18968 102 730 22556 102 963 43758 102 398 7006 102 652 15617 102 250 2790 102 421 8238 102 443 9111 102 671 18285 102 805 30357 102 113 328 102 234 1816 102 768 24845 102 899 37186 102 257 3555 102 336 5160 102 354 5860 102 839 32018} #========================================================================== do_execsql_test 3.0 { DROP TABLE IF EXISTS t1; CREATE TABLE t1(a REAL, b INTEGER); INSERT INTO t1 VALUES (5, 10), (10, 20), (13, 26), (13, 26), (15, 30), (20, 40), (22,80), (30, 90); } {} do_execsql_test 3.1 { SELECT CAST(a AS INTEGER), sum(b) OVER win FROM t1 WINDOW win AS ( ORDER BY a RANGE BETWEEN 5 PRECEDING AND 5 FOLLOWING ) } {5 30 10 112 13 102 13 102 15 142 20 150 22 120 30 90} do_execsql_test 3.2 { SELECT CAST(a AS INTEGER), sum(b) OVER win FROM t1 WINDOW win AS ( ORDER BY a RANGE BETWEEN 10 PRECEDING AND 5 PRECEDING ) } {5 {} 10 10 13 10 13 10 15 30 20 102 22 82 30 120} do_execsql_test 3.3 { SELECT CAST(a AS INTEGER), sum(b) OVER win FROM t1 WINDOW win AS ( ORDER BY a RANGE BETWEEN 2 FOLLOWING AND 3 FOLLOWING ) } {5 {} 10 52 13 30 13 30 15 {} 20 80 22 {} 30 {}} do_execsql_test 3.4 { SELECT CAST(a AS INTEGER), sum(b) OVER win FROM t1 WINDOW win AS ( ORDER BY a DESC RANGE BETWEEN 5 PRECEDING AND 5 FOLLOWING ) } {30 90 22 120 20 150 15 142 13 102 13 102 10 112 5 30} do_execsql_test 3.5 { SELECT CAST(a AS INTEGER), sum(b) OVER win FROM t1 WINDOW win AS ( ORDER BY a DESC RANGE BETWEEN 10 PRECEDING AND 5 PRECEDING ) } {30 {} 22 90 20 90 15 120 13 120 13 120 10 70 5 102} do_execsql_test 3.6 { SELECT CAST(a AS INTEGER), sum(b) OVER win FROM t1 WINDOW win AS ( ORDER BY a DESC RANGE BETWEEN 2 FOLLOWING AND 3 FOLLOWING ) } {30 {} 22 40 20 {} 15 52 13 20 13 20 10 {} 5 {}} do_execsql_test 3.7 { SELECT CAST(a AS INTEGER), sum(b) OVER win FROM t1 WINDOW win AS ( ORDER BY a RANGE BETWEEN 5.1 PRECEDING AND 5.3 FOLLOWING ) } {5 30 10 112 13 102 13 102 15 142 20 150 22 120 30 90} do_execsql_test 3.8 { SELECT CAST(a AS INTEGER), sum(b) OVER win FROM t1 WINDOW win AS ( ORDER BY a RANGE BETWEEN 10.2 PRECEDING AND 5.4 PRECEDING ) } {5 {} 10 {} 13 10 13 10 15 10 20 72 22 82 30 120} do_execsql_test 3.9 { SELECT CAST(a AS INTEGER), sum(b) OVER win FROM t1 WINDOW win AS ( ORDER BY a RANGE BETWEEN 2.6 FOLLOWING AND 3.5 FOLLOWING ) } {5 {} 10 52 13 {} 13 {} 15 {} 20 {} 22 {} 30 {}} do_execsql_test 3.10 { SELECT CAST(a AS INTEGER), sum(b) OVER win FROM t1 WINDOW win AS ( ORDER BY a DESC RANGE BETWEEN 5.7 PRECEDING AND 5.8 FOLLOWING ) } {30 90 22 120 20 150 15 142 13 102 13 102 10 112 5 30} do_execsql_test 3.11 { SELECT CAST(a AS INTEGER), sum(b) OVER win FROM t1 WINDOW win AS ( ORDER BY a DESC RANGE BETWEEN UNBOUNDED PRECEDING AND 5.9 PRECEDING ) } {30 {} 22 90 20 90 15 170 13 210 13 210 10 210 5 292} do_execsql_test 3.12 { SELECT CAST(a AS INTEGER), sum(b) OVER win FROM t1 WINDOW win AS ( ORDER BY a DESC RANGE BETWEEN 2.1 FOLLOWING AND UNBOUNDED FOLLOWING ) } {30 232 22 112 20 112 15 30 13 30 13 30 10 10 5 {}} do_execsql_test 3.13 { SELECT CAST(a AS INTEGER), sum(b) OVER win FROM t1 WINDOW win AS ( ORDER BY a RANGE 5.1 PRECEDING ) } {5 10 10 30 13 72 13 72 15 102 20 70 22 120 30 90} #========================================================================== do_execsql_test 4.0 { DROP TABLE IF EXISTS t1; CREATE TABLE t1(a INTEGER, b INTEGER); INSERT INTO t1 VALUES (NULL, 1), (NULL, 2), (NULL, 3), (10, 4), (10, 5); } {} do_execsql_test 4.1.1 { SELECT sum(b) OVER ( ORDER BY a RANGE BETWEEN 5 PRECEDING AND 10 FOLLOWING ) FROM t1 ORDER BY 1; } {6 6 6 9 9} do_execsql_test 4.1.2 { SELECT sum(b) OVER ( ORDER BY a DESC RANGE BETWEEN 5 PRECEDING AND 10 FOLLOWING ) FROM t1 ORDER BY 1; } {6 6 6 9 9} do_execsql_test 4.2.1 { SELECT sum(b) OVER ( ORDER BY a RANGE BETWEEN 5 FOLLOWING AND 10 FOLLOWING ) FROM t1 ORDER BY 1 NULLS FIRST; } {{} {} 6 6 6} do_execsql_test 4.2.2 { SELECT sum(b) OVER ( ORDER BY a RANGE BETWEEN 5 FOLLOWING AND 10 FOLLOWING ) FROM t1 ORDER BY 1 NULLS LAST; } {6 6 6 {} {}} do_execsql_test 4.2.3 { SELECT sum(b) OVER ( ORDER BY a DESC RANGE BETWEEN 5 FOLLOWING AND 10 FOLLOWING ) FROM t1 ORDER BY 1 NULLS FIRST; } {{} {} 6 6 6} do_execsql_test 4.2.4 { SELECT sum(b) OVER ( ORDER BY a DESC RANGE BETWEEN 5 FOLLOWING AND 10 FOLLOWING ) FROM t1 ORDER BY 1 NULLS LAST; } {6 6 6 {} {}} do_execsql_test 4.3.1 { SELECT sum(b) OVER ( ORDER BY a NULLS FIRST RANGE BETWEEN UNBOUNDED PRECEDING AND 10 FOLLOWING ) FROM t1 ORDER BY 1 NULLS FIRST; } {6 6 6 15 15} do_execsql_test 4.3.2 { SELECT sum(b) OVER ( ORDER BY a NULLS LAST RANGE BETWEEN UNBOUNDED PRECEDING AND 10 FOLLOWING ) FROM t1 ORDER BY 1 NULLS LAST; } {9 9 15 15 15} do_execsql_test 4.4.1 { SELECT sum(b) OVER ( ORDER BY a NULLS FIRST ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING ) FROM t1 ORDER BY 1 NULLS FIRST; } {3 6 9 9 12} do_execsql_test 4.4.2 { SELECT sum(b) OVER ( ORDER BY a NULLS LAST ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING ) FROM t1 ORDER BY 1 NULLS LAST; } {5 6 8 9 10} do_execsql_test 4.4.3 { SELECT sum(b) OVER ( ORDER BY a DESC NULLS LAST ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING ) FROM t1 ORDER BY 1 NULLS FIRST; } {5 6 8 9 10} do_execsql_test 4.4.4 { SELECT sum(b) OVER ( ORDER BY a DESC NULLS LAST ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING ) FROM t1 ORDER BY 1 NULLS LAST; } {5 6 8 9 10} do_execsql_test 4.5.1 { SELECT sum(b) OVER ( ORDER BY a ASC NULLS LAST RANGE BETWEEN UNBOUNDED PRECEDING AND 10 FOLLOWING ) FROM t1 ORDER BY 1 NULLS LAST; } {9 9 15 15 15} do_execsql_test 4.5.2 { SELECT sum(b) OVER ( ORDER BY a DESC NULLS FIRST RANGE BETWEEN UNBOUNDED PRECEDING AND 10 FOLLOWING ) FROM t1 ORDER BY 1 NULLS LAST; } {6 6 6 15 15} #========================================================================== do_execsql_test 5.0 { INSERT INTO t3 VALUES (NULL, 'bb', 355), (NULL, 'cc', 158), (NULL, 'aa', 399), ('JJ', NULL, 839), ('FF', NULL, 618), ('BB', NULL, 393), (NULL, 'bb', 629), (NULL, NULL, 667), (NULL, NULL, 870); } {} do_execsql_test 5.1.1.1 { SELECT max(c) OVER win, min(c) OVER win, count(a) OVER win FROM t3 WINDOW win AS ( RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING EXCLUDE NO OTHERS ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83} do_execsql_test 5.1.1.2 { SELECT sum(c) FILTER (WHERE (c%2)!=0) OVER win, rank() OVER win, dense_rank() OVER win FROM t3 WINDOW win AS ( RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING EXCLUDE NO OTHERS ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1} do_execsql_test 5.1.2.1 { SELECT max(c) OVER win, min(c) OVER win, count(a) OVER win FROM t3 WINDOW win AS ( ORDER BY a NULLS FIRST RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING EXCLUDE NO OTHERS ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {899 113 9 899 113 9 899 113 9 899 113 9 899 113 9 899 113 9 899 113 9 899 113 9 899 113 9 899 113 16 899 113 16 899 113 16 899 113 16 899 113 16 899 113 16 899 113 16 979 102 44 979 102 44 979 102 44 979 102 44 979 102 44 979 102 44 979 102 44 979 102 44 979 102 44 979 102 44 979 102 44 979 102 49 979 102 49 979 102 49 979 102 49 979 102 49 979 102 56 979 102 56 979 102 56 979 102 56 979 102 56 979 102 56 979 102 56 979 102 62 979 102 62 979 102 62 979 102 62 979 102 62 979 102 62 979 102 75 979 102 75 979 102 75 979 102 75 979 102 75 979 102 75 979 102 75 979 102 75 979 102 75 979 102 75 979 102 75 979 102 75 979 102 75 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 113 25 979 113 25 979 113 25 979 113 25 979 113 25 979 113 25 979 113 25 979 113 25 979 113 25 979 113 33 979 113 33 979 113 33 979 113 33 979 113 33 979 113 33 979 113 33 979 113 33} do_execsql_test 5.1.2.2 { SELECT sum(c) FILTER (WHERE (c%2)!=0) OVER win, rank() OVER win, dense_rank() OVER win FROM t3 WINDOW win AS ( ORDER BY a NULLS FIRST RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING EXCLUDE NO OTHERS ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {2947 81 11 2947 81 11 2947 81 11 2947 81 11 2947 81 11 2947 81 11 2947 81 11 2947 81 11 2947 81 11 5287 74 10 5287 74 10 5287 74 10 5287 74 10 5287 74 10 5287 74 10 5287 74 10 8400 65 9 8400 65 9 8400 65 9 8400 65 9 8400 65 9 8400 65 9 8400 65 9 8400 65 9 8400 65 9 9664 57 8 9664 57 8 9664 57 8 9664 57 8 9664 57 8 9664 57 8 9664 57 8 9664 57 8 10626 46 7 10626 46 7 10626 46 7 10626 46 7 10626 46 7 10626 46 7 10626 46 7 10626 46 7 10626 46 7 10626 46 7 10626 46 7 12145 41 6 12145 41 6 12145 41 6 12145 41 6 12145 41 6 13949 34 5 13949 34 5 13949 34 5 13949 34 5 13949 34 5 13949 34 5 13949 34 5 15315 28 4 15315 28 4 15315 28 4 15315 28 4 15315 28 4 15315 28 4 18796 15 3 18796 15 3 18796 15 3 18796 15 3 18796 15 3 18796 15 3 18796 15 3 18796 15 3 18796 15 3 18796 15 3 18796 15 3 18796 15 3 18796 15 3 21105 7 2 21105 7 2 21105 7 2 21105 7 2 21105 7 2 21105 7 2 21105 7 2 21105 7 2 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1} do_execsql_test 5.1.3.1 { SELECT max(c) OVER win, min(c) OVER win, count(a) OVER win FROM t3 WINDOW win AS ( PARTITION BY coalesce(a, '') RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING EXCLUDE NO OTHERS ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {777 113 5 777 113 5 777 113 5 777 113 5 777 113 5 805 250 7 805 250 7 805 250 7 805 250 7 805 250 7 805 250 7 805 250 7 822 158 6 822 158 6 822 158 6 822 158 6 822 158 6 822 158 6 840 247 13 840 247 13 840 247 13 840 247 13 840 247 13 840 247 13 840 247 13 840 247 13 840 247 13 840 247 13 840 247 13 840 247 13 840 247 13 870 158 0 870 158 0 870 158 0 870 158 0 870 158 0 870 158 0 899 113 9 899 113 9 899 113 9 899 113 9 899 113 9 899 113 9 899 113 9 899 113 9 899 113 9 934 223 8 934 223 8 934 223 8 934 223 8 934 223 8 934 223 8 934 223 8 934 223 8 938 102 11 938 102 11 938 102 11 938 102 11 938 102 11 938 102 11 938 102 11 938 102 11 938 102 11 938 102 11 938 102 11 938 148 8 938 148 8 938 148 8 938 148 8 938 148 8 938 148 8 938 148 8 938 148 8 959 224 7 959 224 7 959 224 7 959 224 7 959 224 7 959 224 7 959 224 7 979 133 9 979 133 9 979 133 9 979 133 9 979 133 9 979 133 9 979 133 9 979 133 9 979 133 9} do_execsql_test 5.1.3.2 { SELECT sum(c) FILTER (WHERE (c%2)!=0) OVER win, rank() OVER win, dense_rank() OVER win FROM t3 WINDOW win AS ( PARTITION BY coalesce(a, '') RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING EXCLUDE NO OTHERS ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {962 1 1 962 1 1 962 1 1 962 1 1 962 1 1 962 1 1 962 1 1 962 1 1 962 1 1 962 1 1 962 1 1 1264 1 1 1264 1 1 1264 1 1 1264 1 1 1264 1 1 1264 1 1 1264 1 1 1264 1 1 1366 1 1 1366 1 1 1366 1 1 1366 1 1 1366 1 1 1366 1 1 1519 1 1 1519 1 1 1519 1 1 1519 1 1 1519 1 1 1804 1 1 1804 1 1 1804 1 1 1804 1 1 1804 1 1 1804 1 1 1804 1 1 2050 1 1 2050 1 1 2050 1 1 2050 1 1 2050 1 1 2050 1 1 2309 1 1 2309 1 1 2309 1 1 2309 1 1 2309 1 1 2309 1 1 2309 1 1 2309 1 1 2340 1 1 2340 1 1 2340 1 1 2340 1 1 2340 1 1 2340 1 1 2340 1 1 2947 1 1 2947 1 1 2947 1 1 2947 1 1 2947 1 1 2947 1 1 2947 1 1 2947 1 1 2947 1 1 3113 1 1 3113 1 1 3113 1 1 3113 1 1 3113 1 1 3113 1 1 3113 1 1 3113 1 1 3113 1 1 3481 1 1 3481 1 1 3481 1 1 3481 1 1 3481 1 1 3481 1 1 3481 1 1 3481 1 1 3481 1 1 3481 1 1 3481 1 1 3481 1 1 3481 1 1} do_execsql_test 5.1.4.1 { SELECT max(c) OVER win, min(c) OVER win, count(a) OVER win FROM t3 WINDOW win AS ( ORDER BY a NULLS FIRST GROUPS 6 PRECEDING EXCLUDE NO OTHERS ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {870 158 0 870 158 0 870 158 0 870 158 0 870 158 0 870 158 0 934 158 8 934 158 8 934 158 8 934 158 8 934 158 8 934 158 8 934 158 8 934 158 8 934 158 21 934 158 21 934 158 21 934 158 21 934 158 21 934 158 21 934 158 21 934 158 21 934 158 21 934 158 21 934 158 21 934 158 21 934 158 21 934 158 27 934 158 27 934 158 27 934 158 27 934 158 27 934 158 27 959 102 50 959 102 50 959 102 50 959 102 50 959 102 50 959 102 50 959 102 50 959 102 50 959 102 50 959 102 50 959 102 50 959 102 58 959 102 58 959 102 58 959 102 58 959 102 58 959 102 58 959 102 58 959 102 58 959 113 39 959 113 39 959 113 39 959 113 39 959 113 39 959 158 34 959 158 34 959 158 34 959 158 34 959 158 34 959 158 34 959 158 34 979 102 53 979 102 53 979 102 53 979 102 53 979 102 53 979 102 53 979 102 53 979 102 56 979 102 56 979 102 56 979 102 56 979 102 56 979 102 56 979 102 56 979 102 56 979 102 56 979 102 59 979 102 59 979 102 59 979 102 59 979 102 59 979 102 59 979 102 59 979 102 59 979 102 59} do_execsql_test 5.1.4.2 { SELECT sum(c) FILTER (WHERE (c%2)!=0) OVER win, rank() OVER win, dense_rank() OVER win FROM t3 WINDOW win AS ( ORDER BY a NULLS FIRST GROUPS 6 PRECEDING EXCLUDE NO OTHERS ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {2050 1 1 2050 1 1 2050 1 1 2050 1 1 2050 1 1 2050 1 1 4359 7 2 4359 7 2 4359 7 2 4359 7 2 4359 7 2 4359 7 2 4359 7 2 4359 7 2 7840 15 3 7840 15 3 7840 15 3 7840 15 3 7840 15 3 7840 15 3 7840 15 3 7840 15 3 7840 15 3 7840 15 3 7840 15 3 7840 15 3 7840 15 3 9206 28 4 9206 28 4 9206 28 4 9206 28 4 9206 28 4 9206 28 4 11010 34 5 11010 34 5 11010 34 5 11010 34 5 11010 34 5 11010 34 5 11010 34 5 12368 74 10 12368 74 10 12368 74 10 12368 74 10 12368 74 10 12368 74 10 12368 74 10 12529 41 6 12529 41 6 12529 41 6 12529 41 6 12529 41 6 12705 57 8 12705 57 8 12705 57 8 12705 57 8 12705 57 8 12705 57 8 12705 57 8 12705 57 8 13491 46 7 13491 46 7 13491 46 7 13491 46 7 13491 46 7 13491 46 7 13491 46 7 13491 46 7 13491 46 7 13491 46 7 13491 46 7 13509 65 9 13509 65 9 13509 65 9 13509 65 9 13509 65 9 13509 65 9 13509 65 9 13509 65 9 13509 65 9 13949 81 11 13949 81 11 13949 81 11 13949 81 11 13949 81 11 13949 81 11 13949 81 11 13949 81 11 13949 81 11} do_execsql_test 5.1.5.1 { SELECT max(c) OVER win, min(c) OVER win, count(a) OVER win FROM t3 WINDOW win AS ( ORDER BY c NULLS FIRST RANGE BETWEEN 6 PRECEDING AND 7 FOLLOWING EXCLUDE NO OTHERS ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {102 102 1 113 113 2 113 113 2 133 133 1 148 148 1 160 158 2 160 158 2 160 158 2 208 208 1 224 223 2 224 223 2 239 234 3 239 234 3 239 234 3 252 247 3 257 247 5 257 247 5 257 250 4 257 252 3 295 295 1 309 309 1 336 330 3 336 330 3 336 330 3 346 346 1 355 354 2 355 354 2 355 354 2 399 393 4 399 393 4 399 393 4 399 393 4 399 393 4 412 412 1 421 421 1 430 430 1 443 443 1 480 480 2 480 480 2 574 572 2 574 572 2 607 607 1 618 618 2 618 618 2 634 627 4 634 627 4 634 627 4 634 627 4 634 629 3 652 652 1 667 660 2 671 667 3 671 667 3 671 667 3 671 667 3 683 683 1 711 705 2 716 705 3 716 711 2 730 726 2 730 726 2 762 759 2 768 759 4 768 762 3 768 762 3 777 777 1 792 786 3 794 786 4 794 786 4 794 790 3 805 805 1 822 822 1 845 839 5 845 839 5 845 839 5 845 839 5 845 839 5 870 870 2 870 870 2 870 870 2 899 899 1 911 911 1 934 929 2 938 929 4 938 934 3 938 934 3 963 959 2 963 959 2 979 979 1} do_execsql_test 5.1.5.2 { SELECT sum(c) FILTER (WHERE (c%2)!=0) OVER win, rank() OVER win, dense_rank() OVER win FROM t3 WINDOW win AS ( ORDER BY c NULLS FIRST RANGE BETWEEN 6 PRECEDING AND 7 FOLLOWING EXCLUDE NO OTHERS ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {{} 1 1 {} 5 4 {} 6 5 {} 6 5 {} 8 6 {} 9 7 {} 25 23 {} 34 29 {} 36 31 {} 38 33 {} 38 33 {} 40 34 {} 41 35 {} 43 37 {} 43 37 {} 50 42 {} 60 51 {} 61 52 {} 64 55 {} 64 55 {} 67 57 {} 68 58 {} 69 59 {} 70 60 {} 72 62 {} 78 67 {} 78 67 {} 78 67 {} 85 72 {} 85 72 133 4 3 223 10 8 223 11 9 226 2 2 226 2 2 239 12 10 239 13 11 239 14 12 247 15 13 257 18 16 257 19 17 295 20 18 309 21 19 335 22 20 335 23 21 335 24 22 421 35 30 443 37 32 504 16 14 504 17 15 607 42 36 683 56 47 710 26 24 710 27 25 710 27 25 711 59 50 759 62 53 759 63 54 777 66 56 805 71 61 899 81 68 911 82 69 929 83 70 929 84 71 979 89 75 1334 51 43 1416 57 48 1416 58 49 1584 29 26 1584 29 26 1584 31 27 1584 32 28 1584 32 28 1891 49 41 1922 87 73 1922 88 74 2005 52 44 2005 52 44 2005 54 45 2005 55 46 2518 45 38 2518 46 39 2518 46 39 2518 48 40 2523 73 63 2523 73 63 2523 75 64 2523 76 65 2523 77 66} do_execsql_test 5.1.6.1 { SELECT max(c) OVER win, min(c) OVER win, count(a) OVER win FROM t3 WINDOW win AS ( ORDER BY c NULLS FIRST RANGE BETWEEN 0 PRECEDING AND 0 FOLLOWING EXCLUDE NO OTHERS ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {102 102 1 113 113 2 113 113 2 133 133 1 148 148 1 158 158 1 158 158 1 160 160 1 208 208 1 223 223 1 224 224 1 234 234 1 238 238 1 239 239 1 247 247 1 250 250 1 252 252 1 256 256 1 257 257 1 295 295 1 309 309 1 330 330 1 335 335 1 336 336 1 346 346 1 354 354 1 355 355 1 355 355 1 393 393 2 393 393 2 398 398 1 399 399 1 399 399 1 412 412 1 421 421 1 430 430 1 443 443 1 480 480 2 480 480 2 572 572 1 574 574 1 607 607 1 618 618 2 618 618 2 627 627 1 629 629 1 629 629 1 633 633 1 634 634 1 652 652 1 660 660 1 667 667 1 667 667 1 670 670 1 671 671 1 683 683 1 705 705 1 711 711 1 716 716 1 726 726 1 730 730 1 759 759 1 762 762 1 768 768 2 768 768 2 777 777 1 786 786 1 790 790 1 792 792 1 794 794 1 805 805 1 822 822 1 839 839 2 839 839 2 840 840 1 844 844 1 845 845 1 870 870 2 870 870 2 870 870 2 899 899 1 911 911 1 929 929 1 934 934 1 938 938 2 938 938 2 959 959 1 963 963 1 979 979 1} do_execsql_test 5.1.6.2 { SELECT sum(c) FILTER (WHERE (c%2)!=0) OVER win, rank() OVER win, dense_rank() OVER win FROM t3 WINDOW win AS ( ORDER BY c NULLS FIRST RANGE BETWEEN 0 PRECEDING AND 0 FOLLOWING EXCLUDE NO OTHERS ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {{} 1 1 {} 5 4 {} 6 5 {} 6 5 {} 8 6 {} 9 7 {} 11 9 {} 12 10 {} 13 11 {} 16 14 {} 17 15 {} 18 16 {} 22 20 {} 24 22 {} 25 23 {} 26 24 {} 31 27 {} 34 29 {} 36 31 {} 38 33 {} 38 33 {} 40 34 {} 41 35 {} 43 37 {} 43 37 {} 49 41 {} 50 42 {} 51 43 {} 54 45 {} 59 50 {} 60 51 {} 61 52 {} 63 54 {} 64 55 {} 64 55 {} 67 57 {} 68 58 {} 69 59 {} 70 60 {} 72 62 {} 75 64 {} 76 65 {} 78 67 {} 78 67 {} 78 67 {} 84 71 {} 85 72 {} 85 72 133 4 3 223 10 8 226 2 2 226 2 2 239 14 12 247 15 13 257 19 17 295 20 18 309 21 19 335 23 21 421 35 30 443 37 32 607 42 36 627 45 38 633 48 40 671 55 46 683 56 47 705 57 48 710 27 25 710 27 25 711 58 49 759 62 53 777 66 56 786 29 26 786 29 26 798 32 28 798 32 28 805 71 61 845 77 66 899 81 68 911 82 69 929 83 70 959 87 73 963 88 74 979 89 75 1258 46 39 1258 46 39 1334 52 44 1334 52 44 1678 73 63 1678 73 63} do_execsql_test 5.1.7.1 { SELECT max(c) OVER win, min(c) OVER win, count(a) OVER win FROM t3 WINDOW win AS ( ORDER BY c NULLS FIRST, b NULLS FIRST, a NULLS FIRST ROWS BETWEEN 6 PRECEDING AND UNBOUNDED FOLLOWING EXCLUDE NO OTHERS ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 113 81 979 113 82 979 133 80 979 148 79 979 158 77 979 158 78 979 160 77 979 208 76 979 223 75 979 224 74 979 234 73 979 238 72 979 239 71 979 247 70 979 250 69 979 252 68 979 256 67 979 257 66 979 295 65 979 309 64 979 330 63 979 335 62 979 336 61 979 346 60 979 354 59 979 355 58 979 355 58 979 393 56 979 393 57 979 398 55 979 399 54 979 399 54 979 412 53 979 421 52 979 430 51 979 443 50 979 480 48 979 480 49 979 572 47 979 574 46 979 607 45 979 618 43 979 618 44 979 627 42 979 629 41 979 629 41 979 633 40 979 634 39 979 652 38 979 660 37 979 667 36 979 667 36 979 670 35 979 671 34 979 683 33 979 705 32 979 711 31 979 716 30 979 726 29 979 730 28 979 759 27 979 762 26 979 768 24 979 768 25 979 777 23 979 786 22 979 790 21 979 792 20 979 794 19 979 805 18 979 822 17 979 839 15 979 839 16 979 840 14 979 844 13 979 845 12 979 870 10 979 870 11 979 870 11 979 899 9 979 911 8 979 929 7} do_execsql_test 5.1.7.2 { SELECT sum(c) FILTER (WHERE (c%2)!=0) OVER win, rank() OVER win, dense_rank() OVER win FROM t3 WINDOW win AS ( ORDER BY c NULLS FIRST, b NULLS FIRST, a NULLS FIRST ROWS BETWEEN 6 PRECEDING AND UNBOUNDED FOLLOWING EXCLUDE NO OTHERS ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {3830 89 89 4741 88 88 5640 84 84 5640 85 85 5640 86 86 5640 87 87 6485 81 81 6485 82 82 6485 83 83 7324 80 80 8163 78 78 8163 79 79 8968 73 73 8968 74 74 8968 75 75 8968 76 76 8968 77 77 9745 69 69 9745 70 70 9745 71 71 9745 72 72 10504 65 65 10504 66 66 10504 67 67 10504 68 68 11215 64 64 11920 63 63 12603 62 62 13274 60 60 13274 61 61 13941 59 59 14608 55 55 14608 56 56 14608 57 57 14608 58 58 15241 54 54 15870 53 53 16499 52 52 17126 49 49 17126 50 50 17126 51 51 17733 44 44 17733 45 45 17733 46 46 17733 47 47 17733 48 48 18176 42 42 18176 43 43 18597 40 40 18597 41 41 18996 39 39 19395 37 37 19395 38 38 19788 36 36 20181 35 35 20536 34 34 20891 30 30 20891 31 31 20891 32 32 20891 33 33 21226 28 28 21226 29 29 21535 27 27 21830 26 26 22087 22 22 22087 23 23 22087 24 24 22087 25 25 22334 21 21 22573 17 17 22573 18 18 22573 19 19 22573 20 20 22796 11 11 22796 12 12 22796 13 13 22796 14 14 22796 15 15 22796 16 16 22929 10 10 23042 9 9 23155 1 1 23155 2 2 23155 3 3 23155 4 4 23155 5 5 23155 6 6 23155 7 7 23155 8 8} do_execsql_test 5.1.8.1 { SELECT max(c) OVER win, min(c) OVER win, count(a) OVER win FROM t3 WINDOW win AS ( RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING EXCLUDE NO OTHERS ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83} do_execsql_test 5.1.8.2 { SELECT sum(c) FILTER (WHERE (c%2)!=0) OVER win, rank() OVER win, dense_rank() OVER win FROM t3 WINDOW win AS ( RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING EXCLUDE NO OTHERS ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1} do_execsql_test 5.1.9.1 { SELECT max(c) OVER win, min(c) OVER win, count(a) OVER win FROM t3 WINDOW win AS ( ORDER BY a NULLS LAST RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING EXCLUDE NO OTHERS ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {870 158 0 870 158 0 870 158 0 870 158 0 870 158 0 870 158 0 899 113 9 899 113 9 899 113 9 899 113 9 899 113 9 899 113 9 899 113 9 899 113 9 899 113 9 899 113 16 899 113 16 899 113 16 899 113 16 899 113 16 899 113 16 899 113 16 979 102 44 979 102 44 979 102 44 979 102 44 979 102 44 979 102 44 979 102 44 979 102 44 979 102 44 979 102 44 979 102 44 979 102 49 979 102 49 979 102 49 979 102 49 979 102 49 979 102 56 979 102 56 979 102 56 979 102 56 979 102 56 979 102 56 979 102 56 979 102 62 979 102 62 979 102 62 979 102 62 979 102 62 979 102 62 979 102 75 979 102 75 979 102 75 979 102 75 979 102 75 979 102 75 979 102 75 979 102 75 979 102 75 979 102 75 979 102 75 979 102 75 979 102 75 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 113 25 979 113 25 979 113 25 979 113 25 979 113 25 979 113 25 979 113 25 979 113 25 979 113 25 979 113 33 979 113 33 979 113 33 979 113 33 979 113 33 979 113 33 979 113 33 979 113 33} do_execsql_test 5.1.9.2 { SELECT sum(c) FILTER (WHERE (c%2)!=0) OVER win, rank() OVER win, dense_rank() OVER win FROM t3 WINDOW win AS ( ORDER BY a NULLS LAST RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING EXCLUDE NO OTHERS ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {2050 84 11 2050 84 11 2050 84 11 2050 84 11 2050 84 11 2050 84 11 4997 75 10 4997 75 10 4997 75 10 4997 75 10 4997 75 10 4997 75 10 4997 75 10 4997 75 10 4997 75 10 7337 68 9 7337 68 9 7337 68 9 7337 68 9 7337 68 9 7337 68 9 7337 68 9 10450 59 8 10450 59 8 10450 59 8 10450 59 8 10450 59 8 10450 59 8 10450 59 8 10450 59 8 10450 59 8 11714 51 7 11714 51 7 11714 51 7 11714 51 7 11714 51 7 11714 51 7 11714 51 7 11714 51 7 12676 40 6 12676 40 6 12676 40 6 12676 40 6 12676 40 6 12676 40 6 12676 40 6 12676 40 6 12676 40 6 12676 40 6 12676 40 6 14195 35 5 14195 35 5 14195 35 5 14195 35 5 14195 35 5 15999 28 4 15999 28 4 15999 28 4 15999 28 4 15999 28 4 15999 28 4 15999 28 4 17365 22 3 17365 22 3 17365 22 3 17365 22 3 17365 22 3 17365 22 3 20846 9 2 20846 9 2 20846 9 2 20846 9 2 20846 9 2 20846 9 2 20846 9 2 20846 9 2 20846 9 2 20846 9 2 20846 9 2 20846 9 2 20846 9 2 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1} do_execsql_test 5.1.10.1 { SELECT max(c) OVER win, min(c) OVER win, count(a) OVER win FROM t3 WINDOW win AS ( PARTITION BY coalesce(a, '') RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING EXCLUDE NO OTHERS ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {777 113 5 777 113 5 777 113 5 777 113 5 777 113 5 805 250 7 805 250 7 805 250 7 805 250 7 805 250 7 805 250 7 805 250 7 822 158 6 822 158 6 822 158 6 822 158 6 822 158 6 822 158 6 840 247 13 840 247 13 840 247 13 840 247 13 840 247 13 840 247 13 840 247 13 840 247 13 840 247 13 840 247 13 840 247 13 840 247 13 840 247 13 870 158 0 870 158 0 870 158 0 870 158 0 870 158 0 870 158 0 899 113 9 899 113 9 899 113 9 899 113 9 899 113 9 899 113 9 899 113 9 899 113 9 899 113 9 934 223 8 934 223 8 934 223 8 934 223 8 934 223 8 934 223 8 934 223 8 934 223 8 938 102 11 938 102 11 938 102 11 938 102 11 938 102 11 938 102 11 938 102 11 938 102 11 938 102 11 938 102 11 938 102 11 938 148 8 938 148 8 938 148 8 938 148 8 938 148 8 938 148 8 938 148 8 938 148 8 959 224 7 959 224 7 959 224 7 959 224 7 959 224 7 959 224 7 959 224 7 979 133 9 979 133 9 979 133 9 979 133 9 979 133 9 979 133 9 979 133 9 979 133 9 979 133 9} do_execsql_test 5.1.10.2 { SELECT sum(c) FILTER (WHERE (c%2)!=0) OVER win, rank() OVER win, dense_rank() OVER win FROM t3 WINDOW win AS ( PARTITION BY coalesce(a, '') RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING EXCLUDE NO OTHERS ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {962 1 1 962 1 1 962 1 1 962 1 1 962 1 1 962 1 1 962 1 1 962 1 1 962 1 1 962 1 1 962 1 1 1264 1 1 1264 1 1 1264 1 1 1264 1 1 1264 1 1 1264 1 1 1264 1 1 1264 1 1 1366 1 1 1366 1 1 1366 1 1 1366 1 1 1366 1 1 1366 1 1 1519 1 1 1519 1 1 1519 1 1 1519 1 1 1519 1 1 1804 1 1 1804 1 1 1804 1 1 1804 1 1 1804 1 1 1804 1 1 1804 1 1 2050 1 1 2050 1 1 2050 1 1 2050 1 1 2050 1 1 2050 1 1 2309 1 1 2309 1 1 2309 1 1 2309 1 1 2309 1 1 2309 1 1 2309 1 1 2309 1 1 2340 1 1 2340 1 1 2340 1 1 2340 1 1 2340 1 1 2340 1 1 2340 1 1 2947 1 1 2947 1 1 2947 1 1 2947 1 1 2947 1 1 2947 1 1 2947 1 1 2947 1 1 2947 1 1 3113 1 1 3113 1 1 3113 1 1 3113 1 1 3113 1 1 3113 1 1 3113 1 1 3113 1 1 3113 1 1 3481 1 1 3481 1 1 3481 1 1 3481 1 1 3481 1 1 3481 1 1 3481 1 1 3481 1 1 3481 1 1 3481 1 1 3481 1 1 3481 1 1 3481 1 1} do_execsql_test 5.1.11.1 { SELECT max(c) OVER win, min(c) OVER win, count(a) OVER win FROM t3 WINDOW win AS ( ORDER BY a NULLS LAST GROUPS 6 PRECEDING EXCLUDE NO OTHERS ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {934 158 27 934 158 27 934 158 27 934 158 27 934 158 27 934 158 27 934 223 8 934 223 8 934 223 8 934 223 8 934 223 8 934 223 8 934 223 8 934 223 8 934 223 21 934 223 21 934 223 21 934 223 21 934 223 21 934 223 21 934 223 21 934 223 21 934 223 21 934 223 21 934 223 21 934 223 21 934 223 21 959 102 50 959 102 50 959 102 50 959 102 50 959 102 50 959 102 50 959 102 50 959 102 50 959 102 50 959 102 50 959 102 50 959 102 58 959 102 58 959 102 58 959 102 58 959 102 58 959 102 58 959 102 58 959 102 58 959 113 39 959 113 39 959 113 39 959 113 39 959 113 39 959 158 34 959 158 34 959 158 34 959 158 34 959 158 34 959 158 34 959 158 34 979 102 49 979 102 49 979 102 49 979 102 49 979 102 49 979 102 49 979 102 53 979 102 53 979 102 53 979 102 53 979 102 53 979 102 53 979 102 53 979 102 56 979 102 56 979 102 56 979 102 56 979 102 56 979 102 56 979 102 56 979 102 56 979 102 56 979 102 59 979 102 59 979 102 59 979 102 59 979 102 59 979 102 59 979 102 59 979 102 59 979 102 59} do_execsql_test 5.1.11.2 { SELECT sum(c) FILTER (WHERE (c%2)!=0) OVER win, rank() OVER win, dense_rank() OVER win FROM t3 WINDOW win AS ( ORDER BY a NULLS LAST GROUPS 6 PRECEDING EXCLUDE NO OTHERS ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {2309 1 1 2309 1 1 2309 1 1 2309 1 1 2309 1 1 2309 1 1 2309 1 1 2309 1 1 5790 9 2 5790 9 2 5790 9 2 5790 9 2 5790 9 2 5790 9 2 5790 9 2 5790 9 2 5790 9 2 5790 9 2 5790 9 2 5790 9 2 5790 9 2 7156 22 3 7156 22 3 7156 22 3 7156 22 3 7156 22 3 7156 22 3 8960 28 4 8960 28 4 8960 28 4 8960 28 4 8960 28 4 8960 28 4 8960 28 4 10479 35 5 10479 35 5 10479 35 5 10479 35 5 10479 35 5 11441 40 6 11441 40 6 11441 40 6 11441 40 6 11441 40 6 11441 40 6 11441 40 6 11441 40 6 11441 40 6 11441 40 6 11441 40 6 12368 68 9 12368 68 9 12368 68 9 12368 68 9 12368 68 9 12368 68 9 12368 68 9 12705 51 7 12705 51 7 12705 51 7 12705 51 7 12705 51 7 12705 51 7 12705 51 7 12705 51 7 13509 59 8 13509 59 8 13509 59 8 13509 59 8 13509 59 8 13509 59 8 13509 59 8 13509 59 8 13509 59 8 13949 75 10 13949 75 10 13949 75 10 13949 75 10 13949 75 10 13949 75 10 13949 75 10 13949 75 10 13949 75 10 14195 84 11 14195 84 11 14195 84 11 14195 84 11 14195 84 11 14195 84 11} do_execsql_test 5.1.12.1 { SELECT max(c) OVER win, min(c) OVER win, count(a) OVER win FROM t3 WINDOW win AS ( ORDER BY c NULLS LAST RANGE BETWEEN 6 PRECEDING AND 7 FOLLOWING EXCLUDE NO OTHERS ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {102 102 1 113 113 2 113 113 2 133 133 1 148 148 1 160 158 2 160 158 2 160 158 2 208 208 1 224 223 2 224 223 2 239 234 3 239 234 3 239 234 3 252 247 3 257 247 5 257 247 5 257 250 4 257 252 3 295 295 1 309 309 1 336 330 3 336 330 3 336 330 3 346 346 1 355 354 2 355 354 2 355 354 2 399 393 4 399 393 4 399 393 4 399 393 4 399 393 4 412 412 1 421 421 1 430 430 1 443 443 1 480 480 2 480 480 2 574 572 2 574 572 2 607 607 1 618 618 2 618 618 2 634 627 4 634 627 4 634 627 4 634 627 4 634 629 3 652 652 1 667 660 2 671 667 3 671 667 3 671 667 3 671 667 3 683 683 1 711 705 2 716 705 3 716 711 2 730 726 2 730 726 2 762 759 2 768 759 4 768 762 3 768 762 3 777 777 1 792 786 3 794 786 4 794 786 4 794 790 3 805 805 1 822 822 1 845 839 5 845 839 5 845 839 5 845 839 5 845 839 5 870 870 2 870 870 2 870 870 2 899 899 1 911 911 1 934 929 2 938 929 4 938 934 3 938 934 3 963 959 2 963 959 2 979 979 1} do_execsql_test 5.1.12.2 { SELECT sum(c) FILTER (WHERE (c%2)!=0) OVER win, rank() OVER win, dense_rank() OVER win FROM t3 WINDOW win AS ( ORDER BY c NULLS LAST RANGE BETWEEN 6 PRECEDING AND 7 FOLLOWING EXCLUDE NO OTHERS ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {{} 1 1 {} 5 4 {} 6 5 {} 6 5 {} 8 6 {} 9 7 {} 25 23 {} 34 29 {} 36 31 {} 38 33 {} 38 33 {} 40 34 {} 41 35 {} 43 37 {} 43 37 {} 50 42 {} 60 51 {} 61 52 {} 64 55 {} 64 55 {} 67 57 {} 68 58 {} 69 59 {} 70 60 {} 72 62 {} 78 67 {} 78 67 {} 78 67 {} 85 72 {} 85 72 133 4 3 223 10 8 223 11 9 226 2 2 226 2 2 239 12 10 239 13 11 239 14 12 247 15 13 257 18 16 257 19 17 295 20 18 309 21 19 335 22 20 335 23 21 335 24 22 421 35 30 443 37 32 504 16 14 504 17 15 607 42 36 683 56 47 710 26 24 710 27 25 710 27 25 711 59 50 759 62 53 759 63 54 777 66 56 805 71 61 899 81 68 911 82 69 929 83 70 929 84 71 979 89 75 1334 51 43 1416 57 48 1416 58 49 1584 29 26 1584 29 26 1584 31 27 1584 32 28 1584 32 28 1891 49 41 1922 87 73 1922 88 74 2005 52 44 2005 52 44 2005 54 45 2005 55 46 2518 45 38 2518 46 39 2518 46 39 2518 48 40 2523 73 63 2523 73 63 2523 75 64 2523 76 65 2523 77 66} do_execsql_test 5.1.13.1 { SELECT max(c) OVER win, min(c) OVER win, count(a) OVER win FROM t3 WINDOW win AS ( ORDER BY c NULLS LAST RANGE BETWEEN 0 PRECEDING AND 0 FOLLOWING EXCLUDE NO OTHERS ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {102 102 1 113 113 2 113 113 2 133 133 1 148 148 1 158 158 1 158 158 1 160 160 1 208 208 1 223 223 1 224 224 1 234 234 1 238 238 1 239 239 1 247 247 1 250 250 1 252 252 1 256 256 1 257 257 1 295 295 1 309 309 1 330 330 1 335 335 1 336 336 1 346 346 1 354 354 1 355 355 1 355 355 1 393 393 2 393 393 2 398 398 1 399 399 1 399 399 1 412 412 1 421 421 1 430 430 1 443 443 1 480 480 2 480 480 2 572 572 1 574 574 1 607 607 1 618 618 2 618 618 2 627 627 1 629 629 1 629 629 1 633 633 1 634 634 1 652 652 1 660 660 1 667 667 1 667 667 1 670 670 1 671 671 1 683 683 1 705 705 1 711 711 1 716 716 1 726 726 1 730 730 1 759 759 1 762 762 1 768 768 2 768 768 2 777 777 1 786 786 1 790 790 1 792 792 1 794 794 1 805 805 1 822 822 1 839 839 2 839 839 2 840 840 1 844 844 1 845 845 1 870 870 2 870 870 2 870 870 2 899 899 1 911 911 1 929 929 1 934 934 1 938 938 2 938 938 2 959 959 1 963 963 1 979 979 1} do_execsql_test 5.1.13.2 { SELECT sum(c) FILTER (WHERE (c%2)!=0) OVER win, rank() OVER win, dense_rank() OVER win FROM t3 WINDOW win AS ( ORDER BY c NULLS LAST RANGE BETWEEN 0 PRECEDING AND 0 FOLLOWING EXCLUDE NO OTHERS ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {{} 1 1 {} 5 4 {} 6 5 {} 6 5 {} 8 6 {} 9 7 {} 11 9 {} 12 10 {} 13 11 {} 16 14 {} 17 15 {} 18 16 {} 22 20 {} 24 22 {} 25 23 {} 26 24 {} 31 27 {} 34 29 {} 36 31 {} 38 33 {} 38 33 {} 40 34 {} 41 35 {} 43 37 {} 43 37 {} 49 41 {} 50 42 {} 51 43 {} 54 45 {} 59 50 {} 60 51 {} 61 52 {} 63 54 {} 64 55 {} 64 55 {} 67 57 {} 68 58 {} 69 59 {} 70 60 {} 72 62 {} 75 64 {} 76 65 {} 78 67 {} 78 67 {} 78 67 {} 84 71 {} 85 72 {} 85 72 133 4 3 223 10 8 226 2 2 226 2 2 239 14 12 247 15 13 257 19 17 295 20 18 309 21 19 335 23 21 421 35 30 443 37 32 607 42 36 627 45 38 633 48 40 671 55 46 683 56 47 705 57 48 710 27 25 710 27 25 711 58 49 759 62 53 777 66 56 786 29 26 786 29 26 798 32 28 798 32 28 805 71 61 845 77 66 899 81 68 911 82 69 929 83 70 959 87 73 963 88 74 979 89 75 1258 46 39 1258 46 39 1334 52 44 1334 52 44 1678 73 63 1678 73 63} do_execsql_test 5.1.14.1 { SELECT max(c) OVER win, min(c) OVER win, count(a) OVER win FROM t3 WINDOW win AS ( ORDER BY c NULLS LAST, b NULLS LAST, a NULLS LAST ROWS BETWEEN 6 PRECEDING AND UNBOUNDED FOLLOWING EXCLUDE NO OTHERS ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 113 81 979 113 82 979 133 80 979 148 79 979 158 77 979 158 78 979 160 77 979 208 76 979 223 75 979 224 74 979 234 73 979 238 72 979 239 71 979 247 70 979 250 69 979 252 68 979 256 67 979 257 66 979 295 65 979 309 64 979 330 63 979 335 62 979 336 61 979 346 60 979 354 59 979 355 57 979 355 58 979 393 56 979 393 57 979 398 55 979 399 53 979 399 54 979 412 53 979 421 52 979 430 51 979 443 50 979 480 48 979 480 49 979 572 47 979 574 46 979 607 45 979 618 43 979 618 44 979 627 42 979 629 40 979 629 41 979 633 40 979 634 39 979 652 38 979 660 37 979 667 35 979 667 36 979 670 35 979 671 34 979 683 33 979 705 32 979 711 31 979 716 30 979 726 29 979 730 28 979 759 27 979 762 26 979 768 24 979 768 25 979 777 23 979 786 22 979 790 21 979 792 20 979 794 19 979 805 18 979 822 17 979 839 15 979 839 16 979 840 14 979 844 13 979 845 12 979 870 9 979 870 10 979 870 11 979 899 9 979 911 8 979 929 7} do_execsql_test 5.1.14.2 { SELECT sum(c) FILTER (WHERE (c%2)!=0) OVER win, rank() OVER win, dense_rank() OVER win FROM t3 WINDOW win AS ( ORDER BY c NULLS LAST, b NULLS LAST, a NULLS LAST ROWS BETWEEN 6 PRECEDING AND UNBOUNDED FOLLOWING EXCLUDE NO OTHERS ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {3830 89 89 4741 88 88 5640 84 84 5640 85 85 5640 86 86 5640 87 87 6485 81 81 6485 82 82 6485 83 83 7324 80 80 8163 78 78 8163 79 79 8968 73 73 8968 74 74 8968 75 75 8968 76 76 8968 77 77 9745 69 69 9745 70 70 9745 71 71 9745 72 72 10504 65 65 10504 66 66 10504 67 67 10504 68 68 11215 64 64 11920 63 63 12603 62 62 13274 60 60 13274 61 61 13941 59 59 14608 55 55 14608 56 56 14608 57 57 14608 58 58 15241 54 54 15870 53 53 16499 52 52 17126 49 49 17126 50 50 17126 51 51 17733 44 44 17733 45 45 17733 46 46 17733 47 47 17733 48 48 18176 42 42 18176 43 43 18597 40 40 18597 41 41 18996 39 39 19395 37 37 19395 38 38 19788 36 36 20181 35 35 20536 34 34 20891 30 30 20891 31 31 20891 32 32 20891 33 33 21226 28 28 21226 29 29 21535 27 27 21830 26 26 22087 22 22 22087 23 23 22087 24 24 22087 25 25 22334 21 21 22573 17 17 22573 18 18 22573 19 19 22573 20 20 22796 11 11 22796 12 12 22796 13 13 22796 14 14 22796 15 15 22796 16 16 22929 10 10 23042 9 9 23155 1 1 23155 2 2 23155 3 3 23155 4 4 23155 5 5 23155 6 6 23155 7 7 23155 8 8} do_execsql_test 5.2.1.1 { SELECT max(c) OVER win, min(c) OVER win, count(a) OVER win FROM t3 WINDOW win AS ( RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING EXCLUDE CURRENT ROW ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {963 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 113 82} do_execsql_test 5.2.1.2 { SELECT sum(c) FILTER (WHERE (c%2)!=0) OVER win, rank() OVER win, dense_rank() OVER win FROM t3 WINDOW win AS ( RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING EXCLUDE CURRENT ROW ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {22176 1 1 22192 1 1 22196 1 1 22226 1 1 22244 1 1 22256 1 1 22310 1 1 22316 1 1 22316 1 1 22350 1 1 22378 1 1 22396 1 1 22444 1 1 22450 1 1 22472 1 1 22484 1 1 22488 1 1 22488 1 1 22522 1 1 22526 1 1 22526 1 1 22528 1 1 22548 1 1 22712 1 1 22734 1 1 22756 1 1 22756 1 1 22762 1 1 22762 1 1 22800 1 1 22800 1 1 22820 1 1 22846 1 1 22860 1 1 22898 1 1 22908 1 1 22916 1 1 22932 1 1 23022 1 1 23042 1 1 23042 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1} do_execsql_test 5.2.2.1 { SELECT max(c) OVER win, min(c) OVER win, count(a) OVER win FROM t3 WINDOW win AS ( ORDER BY a NULLS FIRST RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING EXCLUDE CURRENT ROW ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {839 113 8 899 113 8 899 113 8 899 113 8 899 113 8 899 113 8 899 113 8 899 113 8 899 113 15 899 113 15 899 113 15 899 113 15 899 113 15 899 113 15 899 113 15 899 234 8 963 113 24 979 102 43 979 102 43 979 102 43 979 102 43 979 102 43 979 102 43 979 102 43 979 102 43 979 102 43 979 102 43 979 102 48 979 102 48 979 102 48 979 102 48 979 102 48 979 102 55 979 102 55 979 102 55 979 102 55 979 102 55 979 102 55 979 102 55 979 102 61 979 102 61 979 102 61 979 102 61 979 102 61 979 102 61 979 102 74 979 102 74 979 102 74 979 102 74 979 102 74 979 102 74 979 102 74 979 102 74 979 102 74 979 102 74 979 102 74 979 102 74 979 102 74 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 113 24 979 113 24 979 113 24 979 113 24 979 113 24 979 113 24 979 113 24 979 113 24 979 113 32 979 113 32 979 113 32 979 113 32 979 113 32 979 113 32 979 113 32 979 113 32 979 113 43} do_execsql_test 5.2.2.2 { SELECT sum(c) FILTER (WHERE (c%2)!=0) OVER win, rank() OVER win, dense_rank() OVER win FROM t3 WINDOW win AS ( ORDER BY a NULLS FIRST RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING EXCLUDE CURRENT ROW ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {2048 81 11 2108 81 11 2108 81 11 2690 81 11 2834 81 11 2947 81 11 2947 81 11 2947 81 11 2947 81 11 4482 74 10 4616 74 10 4844 74 10 4866 74 10 5287 74 10 5287 74 10 5287 74 10 7421 65 9 7437 65 9 7717 65 9 8045 65 9 8267 65 9 8400 65 9 8400 65 9 8400 65 9 8400 65 9 8735 57 8 9329 57 8 9664 57 8 9664 57 8 9664 57 8 9664 57 8 9664 57 8 9664 57 8 9959 46 7 10331 46 7 10626 46 7 10626 46 7 10626 46 7 10626 46 7 10626 46 7 10626 46 7 10626 46 7 10626 46 7 10626 46 7 11368 41 6 11516 41 6 12032 41 6 12145 41 6 12145 41 6 12990 34 5 13104 34 5 13949 34 5 13949 34 5 13949 34 5 13949 34 5 13949 34 5 14556 28 4 14708 28 4 15315 28 4 15315 28 4 15315 28 4 15315 28 4 18085 15 3 18091 15 3 18163 15 3 18397 15 3 18403 15 3 18403 15 3 18549 15 3 18796 15 3 18796 15 3 18796 15 3 18796 15 3 18796 15 3 18796 15 3 20194 7 2 20478 7 2 20796 7 2 20866 7 2 20882 7 2 21105 7 2 21105 7 2 21105 7 2 22488 1 1 22526 1 1 22756 1 1 22800 1 1 23155 1 1 23155 1 1} do_execsql_test 5.2.3.1 { SELECT max(c) OVER win, min(c) OVER win, count(a) OVER win FROM t3 WINDOW win AS ( PARTITION BY coalesce(a, '') RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING EXCLUDE CURRENT ROW ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {667 158 0 671 250 6 759 158 5 768 113 4 777 113 4 777 113 4 777 113 4 777 252 4 792 247 12 805 250 6 805 250 6 805 250 6 805 250 6 805 250 6 805 398 6 822 158 5 822 158 5 822 158 5 822 158 5 822 346 5 839 113 8 840 247 12 840 247 12 840 247 12 840 247 12 840 247 12 840 247 12 840 247 12 840 247 12 840 247 12 840 247 12 840 247 12 840 393 12 845 224 6 870 102 10 870 158 0 870 158 0 870 158 0 870 158 0 870 355 0 899 113 8 899 113 8 899 113 8 899 113 8 899 113 8 899 113 8 899 113 8 899 234 8 911 223 7 929 148 7 934 223 7 934 223 7 934 223 7 934 223 7 934 223 7 934 223 7 934 239 7 938 102 10 938 102 10 938 102 10 938 102 10 938 102 10 938 102 10 938 102 10 938 102 10 938 102 10 938 148 7 938 148 7 938 148 7 938 148 7 938 148 7 938 148 7 938 160 7 938 208 10 959 224 6 959 224 6 959 224 6 959 224 6 959 224 6 959 238 6 963 133 8 979 133 8 979 133 8 979 133 8 979 133 8 979 133 8 979 133 8 979 133 8 979 330 8} do_execsql_test 5.2.3.2 { SELECT sum(c) FILTER (WHERE (c%2)!=0) OVER win, rank() OVER win, dense_rank() OVER win FROM t3 WINDOW win AS ( PARTITION BY coalesce(a, '') RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING EXCLUDE CURRENT ROW ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {295 1 1 335 1 1 607 1 1 667 1 1 742 1 1 759 1 1 845 1 1 890 1 1 929 1 1 959 1 1 962 1 1 962 1 1 962 1 1 962 1 1 962 1 1 962 1 1 962 1 1 962 1 1 962 1 1 1264 1 1 1264 1 1 1264 1 1 1264 1 1 1264 1 1 1264 1 1 1366 1 1 1366 1 1 1366 1 1 1366 1 1 1383 1 1 1398 1 1 1406 1 1 1421 1 1 1519 1 1 1519 1 1 1535 1 1 1651 1 1 1669 1 1 1682 1 1 1695 1 1 1804 1 1 1804 1 1 1804 1 1 1804 1 1 1804 1 1 1897 1 1 1919 1 1 2000 1 1 2048 1 1 2050 1 1 2050 1 1 2070 1 1 2086 1 1 2108 1 1 2108 1 1 2134 1 1 2150 1 1 2309 1 1 2309 1 1 2309 1 1 2340 1 1 2340 1 1 2340 1 1 2430 1 1 2690 1 1 2758 1 1 2770 1 1 2776 1 1 2834 1 1 2848 1 1 2947 1 1 2947 1 1 2947 1 1 2947 1 1 2980 1 1 3082 1 1 3088 1 1 3088 1 1 3113 1 1 3113 1 1 3113 1 1 3113 1 1 3234 1 1 3481 1 1 3481 1 1 3481 1 1 3481 1 1 3481 1 1 3481 1 1} do_execsql_test 5.2.4.1 { SELECT max(c) OVER win, min(c) OVER win, count(a) OVER win FROM t3 WINDOW win AS ( ORDER BY a NULLS FIRST GROUPS 6 PRECEDING EXCLUDE CURRENT ROW ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {667 158 0 870 158 0 870 158 0 870 158 0 870 158 0 870 355 0 911 158 7 934 158 7 934 158 7 934 158 7 934 158 7 934 158 7 934 158 7 934 158 7 934 158 20 934 158 20 934 158 20 934 158 20 934 158 20 934 158 20 934 158 20 934 158 20 934 158 20 934 158 20 934 158 20 934 158 20 934 158 20 934 158 26 934 158 26 934 158 26 934 158 26 934 158 26 934 158 26 934 158 33 959 102 49 959 102 49 959 102 49 959 102 49 959 102 49 959 102 49 959 102 49 959 102 49 959 102 49 959 102 49 959 102 57 959 102 57 959 102 57 959 102 57 959 102 57 959 102 57 959 102 57 959 102 57 959 113 38 959 113 38 959 113 38 959 113 38 959 113 49 959 158 33 959 158 33 959 158 33 959 158 33 959 158 33 959 158 33 959 158 38 963 102 58 979 102 52 979 102 52 979 102 52 979 102 52 979 102 52 979 102 52 979 102 52 979 102 55 979 102 55 979 102 55 979 102 55 979 102 55 979 102 55 979 102 55 979 102 55 979 102 55 979 102 58 979 102 58 979 102 58 979 102 58 979 102 58 979 102 58 979 102 58 979 102 58} do_execsql_test 5.2.4.2 { SELECT sum(c) FILTER (WHERE (c%2)!=0) OVER win, rank() OVER win, dense_rank() OVER win FROM t3 WINDOW win AS ( ORDER BY a NULLS FIRST GROUPS 6 PRECEDING EXCLUDE CURRENT ROW ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {1383 1 1 1421 1 1 1651 1 1 1695 1 1 2050 1 1 2050 1 1 3448 7 2 3732 7 2 4050 7 2 4120 7 2 4136 7 2 4359 7 2 4359 7 2 4359 7 2 7129 15 3 7135 15 3 7207 15 3 7441 15 3 7447 15 3 7447 15 3 7593 15 3 7840 15 3 7840 15 3 7840 15 3 7840 15 3 7840 15 3 7840 15 3 8447 28 4 8599 28 4 9206 28 4 9206 28 4 9206 28 4 9206 28 4 10051 34 5 10165 34 5 11010 34 5 11010 34 5 11010 34 5 11010 34 5 11010 34 5 11563 74 10 11697 74 10 11752 41 6 11776 57 8 11900 41 6 11925 74 10 11947 74 10 12368 74 10 12368 74 10 12368 74 10 12370 57 8 12416 41 6 12529 41 6 12529 41 6 12530 65 9 12546 65 9 12705 57 8 12705 57 8 12705 57 8 12705 57 8 12705 57 8 12705 57 8 12824 46 7 12826 65 9 13050 81 11 13110 81 11 13110 81 11 13154 65 9 13196 46 7 13376 65 9 13491 46 7 13491 46 7 13491 46 7 13491 46 7 13491 46 7 13491 46 7 13491 46 7 13491 46 7 13491 46 7 13509 65 9 13509 65 9 13509 65 9 13509 65 9 13692 81 11 13836 81 11 13949 81 11 13949 81 11 13949 81 11 13949 81 11} do_execsql_test 5.2.5.1 { SELECT max(c) OVER win, min(c) OVER win, count(a) OVER win FROM t3 WINDOW win AS ( ORDER BY c NULLS FIRST RANGE BETWEEN 6 PRECEDING AND 7 FOLLOWING EXCLUDE CURRENT ROW ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {{} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 113 113 1 113 113 1 158 158 1 160 158 1 160 158 2 223 223 1 224 224 1 238 234 2 239 234 2 239 238 2 252 250 2 256 252 2 257 247 4 257 247 4 257 250 3 335 330 2 336 330 2 336 335 2 355 354 1 355 354 2 355 355 1 399 393 3 399 393 3 399 393 3 399 393 3 399 393 4 480 480 1 480 480 1 572 572 1 574 574 1 618 618 1 618 618 1 633 629 2 634 627 3 634 627 3 634 627 4 634 629 3 667 667 1 670 667 2 671 667 2 671 667 2 671 667 3 711 711 1 711 711 1 716 705 2 726 726 1 730 730 1 762 762 1 768 759 3 768 762 2 768 762 2 792 790 2 792 790 2 794 786 3 794 786 3 844 839 4 845 839 4 845 839 4 845 839 4 845 839 4 870 870 1 870 870 1 870 870 2 934 934 1 938 929 3 938 934 2 938 934 2 959 959 1 963 963 1} do_execsql_test 5.2.5.2 { SELECT sum(c) FILTER (WHERE (c%2)!=0) OVER win, rank() OVER win, dense_rank() OVER win FROM t3 WINDOW win AS ( ORDER BY c NULLS FIRST RANGE BETWEEN 6 PRECEDING AND 7 FOLLOWING EXCLUDE CURRENT ROW ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {{} 1 1 {} 4 3 {} 5 4 {} 6 5 {} 6 5 {} 8 6 {} 9 7 {} 10 8 {} 14 12 {} 15 13 {} 19 17 {} 20 18 {} 21 19 {} 23 21 {} 25 23 {} 34 29 {} 35 30 {} 36 31 {} 37 32 {} 38 33 {} 38 33 {} 40 34 {} 41 35 {} 42 36 {} 43 37 {} 43 37 {} 50 42 {} 56 47 {} 60 51 {} 61 52 {} 62 53 {} 64 55 {} 64 55 {} 66 56 {} 67 57 {} 68 58 {} 69 59 {} 70 60 {} 71 61 {} 72 62 {} 78 67 {} 78 67 {} 78 67 {} 81 68 {} 82 69 {} 83 70 {} 85 72 {} 85 72 {} 89 75 113 2 2 113 2 2 223 11 9 239 12 10 239 13 11 257 18 16 335 22 20 335 24 22 355 27 25 355 27 25 504 16 14 504 17 15 705 58 49 710 26 24 711 57 48 711 59 50 759 63 54 929 84 71 959 88 74 963 87 73 1185 32 28 1185 32 28 1191 29 26 1191 29 26 1334 51 43 1334 55 46 1338 52 44 1338 52 44 1584 31 27 1678 77 66 1684 73 63 1684 73 63 1885 48 40 1889 46 39 1889 46 39 1891 45 38 1891 49 41 2005 54 45 2523 75 64 2523 76 65} do_execsql_test 5.2.6.1 { SELECT max(c) OVER win, min(c) OVER win, count(a) OVER win FROM t3 WINDOW win AS ( ORDER BY c NULLS FIRST RANGE BETWEEN 0 PRECEDING AND 0 FOLLOWING EXCLUDE CURRENT ROW ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {{} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 113 113 1 113 113 1 158 158 0 158 158 1 355 355 0 355 355 1 393 393 1 393 393 1 399 399 0 399 399 1 480 480 1 480 480 1 618 618 1 618 618 1 629 629 0 629 629 1 667 667 0 667 667 1 768 768 1 768 768 1 839 839 1 839 839 1 870 870 1 870 870 1 870 870 2 938 938 1 938 938 1} do_execsql_test 5.2.6.2 { SELECT sum(c) FILTER (WHERE (c%2)!=0) OVER win, rank() OVER win, dense_rank() OVER win FROM t3 WINDOW win AS ( ORDER BY c NULLS FIRST RANGE BETWEEN 0 PRECEDING AND 0 FOLLOWING EXCLUDE CURRENT ROW ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {{} 1 1 {} 4 3 {} 5 4 {} 6 5 {} 6 5 {} 8 6 {} 9 7 {} 10 8 {} 11 9 {} 12 10 {} 13 11 {} 14 12 {} 15 13 {} 16 14 {} 17 15 {} 18 16 {} 19 17 {} 20 18 {} 21 19 {} 22 20 {} 23 21 {} 24 22 {} 25 23 {} 26 24 {} 31 27 {} 34 29 {} 35 30 {} 36 31 {} 37 32 {} 38 33 {} 38 33 {} 40 34 {} 41 35 {} 42 36 {} 43 37 {} 43 37 {} 45 38 {} 48 40 {} 49 41 {} 50 42 {} 51 43 {} 54 45 {} 55 46 {} 56 47 {} 57 48 {} 58 49 {} 59 50 {} 60 51 {} 61 52 {} 62 53 {} 63 54 {} 64 55 {} 64 55 {} 66 56 {} 67 57 {} 68 58 {} 69 59 {} 70 60 {} 71 61 {} 72 62 {} 75 64 {} 76 65 {} 77 66 {} 78 67 {} 78 67 {} 78 67 {} 81 68 {} 82 69 {} 83 70 {} 84 71 {} 85 72 {} 85 72 {} 87 73 {} 88 74 {} 89 75 113 2 2 113 2 2 355 27 25 355 27 25 393 29 26 393 29 26 399 32 28 399 32 28 629 46 39 629 46 39 667 52 44 667 52 44 839 73 63 839 73 63} do_execsql_test 5.2.7.1 { SELECT max(c) OVER win, min(c) OVER win, count(a) OVER win FROM t3 WINDOW win AS ( ORDER BY c NULLS FIRST, b NULLS FIRST, a NULLS FIRST ROWS BETWEEN 6 PRECEDING AND UNBOUNDED FOLLOWING EXCLUDE CURRENT ROW ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {963 929 6 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 83 979 113 80 979 113 81 979 113 82 979 133 79 979 148 78 979 158 76 979 158 77 979 160 76 979 208 75 979 223 74 979 224 73 979 234 72 979 238 71 979 239 70 979 247 69 979 250 68 979 252 67 979 256 66 979 257 65 979 295 64 979 309 64 979 330 62 979 335 61 979 336 60 979 346 59 979 354 59 979 355 57 979 355 57 979 393 55 979 393 56 979 398 54 979 399 53 979 399 53 979 412 52 979 421 51 979 430 50 979 443 49 979 480 47 979 480 48 979 572 47 979 574 45 979 607 44 979 618 42 979 618 43 979 627 41 979 629 40 979 629 41 979 633 39 979 634 38 979 652 37 979 660 36 979 667 35 979 667 35 979 670 34 979 671 33 979 683 32 979 705 31 979 711 30 979 716 29 979 726 28 979 730 27 979 759 26 979 762 25 979 768 23 979 768 24 979 777 22 979 786 21 979 790 20 979 792 19 979 794 18 979 805 17 979 822 17 979 839 14 979 839 15 979 840 13 979 844 12 979 845 11 979 870 9 979 870 10 979 870 10 979 899 8 979 911 7} do_execsql_test 5.2.7.2 { SELECT sum(c) FILTER (WHERE (c%2)!=0) OVER win, rank() OVER win, dense_rank() OVER win FROM t3 WINDOW win AS ( ORDER BY c NULLS FIRST, b NULLS FIRST, a NULLS FIRST ROWS BETWEEN 6 PRECEDING AND UNBOUNDED FOLLOWING EXCLUDE CURRENT ROW ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {2851 89 89 3778 88 88 4681 87 87 5556 83 83 5574 82 82 5586 81 81 5640 84 84 5640 85 85 5640 86 86 7324 80 80 8123 77 77 8129 73 73 8129 74 74 8163 78 78 8163 79 79 8940 71 71 8968 75 75 8968 76 76 9727 66 66 9745 69 69 9745 70 70 9745 72 72 10504 65 65 10504 67 67 10504 68 68 11215 64 64 11844 62 62 11920 63 63 13274 60 60 13274 61 61 13897 58 58 13903 57 57 13925 56 56 13937 55 55 13941 59 59 15203 53 53 15241 54 54 15832 52 52 17100 48 48 17104 46 46 17104 47 47 17106 45 45 17126 49 49 17126 50 50 17126 51 51 17569 42 42 17733 44 44 18176 43 43 18597 40 40 18597 41 41 18952 37 37 18996 39 39 19395 38 38 19760 35 35 19788 36 36 20492 32 32 20492 33 33 20498 30 30 20536 34 34 20833 29 29 20871 28 28 20891 31 31 21180 27 27 21752 23 23 21830 26 26 22025 21 21 22087 22 22 22087 24 24 22087 25 25 22278 20 20 22316 19 19 22549 15 15 22557 14 14 22573 17 17 22573 18 18 22706 10 10 22796 11 11 22796 12 12 22796 13 13 22796 16 16 23022 4 4 23042 2 2 23042 3 3 23042 9 9 23155 1 1 23155 5 5 23155 6 6 23155 7 7 23155 8 8} do_execsql_test 5.2.8.1 { SELECT max(c) OVER win, min(c) OVER win, count(a) OVER win FROM t3 WINDOW win AS ( RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING EXCLUDE CURRENT ROW ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {963 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 113 82} do_execsql_test 5.2.8.2 { SELECT sum(c) FILTER (WHERE (c%2)!=0) OVER win, rank() OVER win, dense_rank() OVER win FROM t3 WINDOW win AS ( RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING EXCLUDE CURRENT ROW ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {22176 1 1 22192 1 1 22196 1 1 22226 1 1 22244 1 1 22256 1 1 22310 1 1 22316 1 1 22316 1 1 22350 1 1 22378 1 1 22396 1 1 22444 1 1 22450 1 1 22472 1 1 22484 1 1 22488 1 1 22488 1 1 22522 1 1 22526 1 1 22526 1 1 22528 1 1 22548 1 1 22712 1 1 22734 1 1 22756 1 1 22756 1 1 22762 1 1 22762 1 1 22800 1 1 22800 1 1 22820 1 1 22846 1 1 22860 1 1 22898 1 1 22908 1 1 22916 1 1 22932 1 1 23022 1 1 23042 1 1 23042 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1 23155 1 1} do_execsql_test 5.2.9.1 { SELECT max(c) OVER win, min(c) OVER win, count(a) OVER win FROM t3 WINDOW win AS ( ORDER BY a NULLS LAST RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING EXCLUDE CURRENT ROW ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {667 158 0 870 113 8 870 158 0 870 158 0 870 158 0 870 158 0 870 355 0 899 113 8 899 113 8 899 113 8 899 113 8 899 113 8 899 113 8 899 113 8 899 113 15 899 113 15 899 113 15 899 113 15 899 113 15 899 113 15 899 113 15 899 158 8 963 113 24 979 102 43 979 102 43 979 102 43 979 102 43 979 102 43 979 102 43 979 102 43 979 102 43 979 102 43 979 102 43 979 102 48 979 102 48 979 102 48 979 102 48 979 102 48 979 102 55 979 102 55 979 102 55 979 102 55 979 102 55 979 102 55 979 102 55 979 102 61 979 102 61 979 102 61 979 102 61 979 102 61 979 102 61 979 102 74 979 102 74 979 102 74 979 102 74 979 102 74 979 102 74 979 102 74 979 102 74 979 102 74 979 102 74 979 102 74 979 102 74 979 102 74 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 113 24 979 113 24 979 113 24 979 113 24 979 113 24 979 113 24 979 113 24 979 113 24 979 113 32 979 113 32 979 113 32 979 113 32 979 113 32 979 113 32 979 113 32 979 113 32 979 113 43} do_execsql_test 5.2.9.2 { SELECT sum(c) FILTER (WHERE (c%2)!=0) OVER win, rank() OVER win, dense_rank() OVER win FROM t3 WINDOW win AS ( ORDER BY a NULLS LAST RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING EXCLUDE CURRENT ROW ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {1383 84 11 1421 84 11 1651 84 11 1695 84 11 2050 84 11 2050 84 11 4098 75 10 4158 75 10 4158 75 10 4740 75 10 4884 75 10 4997 75 10 4997 75 10 4997 75 10 4997 75 10 6532 68 9 6666 68 9 6894 68 9 6916 68 9 7337 68 9 7337 68 9 7337 68 9 9471 59 8 9487 59 8 9767 59 8 10095 59 8 10317 59 8 10450 59 8 10450 59 8 10450 59 8 10450 59 8 10785 51 7 11379 51 7 11714 51 7 11714 51 7 11714 51 7 11714 51 7 11714 51 7 11714 51 7 12009 40 6 12381 40 6 12676 40 6 12676 40 6 12676 40 6 12676 40 6 12676 40 6 12676 40 6 12676 40 6 12676 40 6 12676 40 6 13418 35 5 13566 35 5 14082 35 5 14195 35 5 14195 35 5 15040 28 4 15154 28 4 15999 28 4 15999 28 4 15999 28 4 15999 28 4 15999 28 4 16606 22 3 16758 22 3 17365 22 3 17365 22 3 17365 22 3 17365 22 3 20135 9 2 20141 9 2 20213 9 2 20447 9 2 20453 9 2 20453 9 2 20599 9 2 20846 9 2 20846 9 2 20846 9 2 20846 9 2 20846 9 2 20846 9 2 22244 1 1 22528 1 1 22846 1 1 22916 1 1 22932 1 1 23155 1 1 23155 1 1 23155 1 1} do_execsql_test 5.2.10.1 { SELECT max(c) OVER win, min(c) OVER win, count(a) OVER win FROM t3 WINDOW win AS ( PARTITION BY coalesce(a, '') RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING EXCLUDE CURRENT ROW ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {667 158 0 671 250 6 759 158 5 768 113 4 777 113 4 777 113 4 777 113 4 777 252 4 792 247 12 805 250 6 805 250 6 805 250 6 805 250 6 805 250 6 805 398 6 822 158 5 822 158 5 822 158 5 822 158 5 822 346 5 839 113 8 840 247 12 840 247 12 840 247 12 840 247 12 840 247 12 840 247 12 840 247 12 840 247 12 840 247 12 840 247 12 840 247 12 840 393 12 845 224 6 870 102 10 870 158 0 870 158 0 870 158 0 870 158 0 870 355 0 899 113 8 899 113 8 899 113 8 899 113 8 899 113 8 899 113 8 899 113 8 899 234 8 911 223 7 929 148 7 934 223 7 934 223 7 934 223 7 934 223 7 934 223 7 934 223 7 934 239 7 938 102 10 938 102 10 938 102 10 938 102 10 938 102 10 938 102 10 938 102 10 938 102 10 938 102 10 938 148 7 938 148 7 938 148 7 938 148 7 938 148 7 938 148 7 938 160 7 938 208 10 959 224 6 959 224 6 959 224 6 959 224 6 959 224 6 959 238 6 963 133 8 979 133 8 979 133 8 979 133 8 979 133 8 979 133 8 979 133 8 979 133 8 979 330 8} do_execsql_test 5.2.10.2 { SELECT sum(c) FILTER (WHERE (c%2)!=0) OVER win, rank() OVER win, dense_rank() OVER win FROM t3 WINDOW win AS ( PARTITION BY coalesce(a, '') RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING EXCLUDE CURRENT ROW ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {295 1 1 335 1 1 607 1 1 667 1 1 742 1 1 759 1 1 845 1 1 890 1 1 929 1 1 959 1 1 962 1 1 962 1 1 962 1 1 962 1 1 962 1 1 962 1 1 962 1 1 962 1 1 962 1 1 1264 1 1 1264 1 1 1264 1 1 1264 1 1 1264 1 1 1264 1 1 1366 1 1 1366 1 1 1366 1 1 1366 1 1 1383 1 1 1398 1 1 1406 1 1 1421 1 1 1519 1 1 1519 1 1 1535 1 1 1651 1 1 1669 1 1 1682 1 1 1695 1 1 1804 1 1 1804 1 1 1804 1 1 1804 1 1 1804 1 1 1897 1 1 1919 1 1 2000 1 1 2048 1 1 2050 1 1 2050 1 1 2070 1 1 2086 1 1 2108 1 1 2108 1 1 2134 1 1 2150 1 1 2309 1 1 2309 1 1 2309 1 1 2340 1 1 2340 1 1 2340 1 1 2430 1 1 2690 1 1 2758 1 1 2770 1 1 2776 1 1 2834 1 1 2848 1 1 2947 1 1 2947 1 1 2947 1 1 2947 1 1 2980 1 1 3082 1 1 3088 1 1 3088 1 1 3113 1 1 3113 1 1 3113 1 1 3113 1 1 3234 1 1 3481 1 1 3481 1 1 3481 1 1 3481 1 1 3481 1 1 3481 1 1} do_execsql_test 5.2.11.1 { SELECT max(c) OVER win, min(c) OVER win, count(a) OVER win FROM t3 WINDOW win AS ( ORDER BY a NULLS LAST GROUPS 6 PRECEDING EXCLUDE CURRENT ROW ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {911 223 7 934 158 26 934 158 26 934 158 26 934 158 26 934 158 26 934 158 33 934 223 7 934 223 7 934 223 7 934 223 7 934 223 7 934 223 7 934 223 20 934 223 20 934 223 20 934 223 20 934 223 20 934 223 20 934 223 20 934 223 20 934 223 20 934 223 20 934 223 20 934 223 20 934 223 20 934 223 26 934 239 7 959 102 49 959 102 49 959 102 49 959 102 49 959 102 49 959 102 49 959 102 49 959 102 49 959 102 49 959 102 49 959 102 57 959 102 57 959 102 57 959 102 57 959 102 57 959 102 57 959 102 57 959 102 57 959 113 38 959 113 38 959 113 38 959 113 38 959 113 49 959 158 33 959 158 33 959 158 33 959 158 33 959 158 33 959 158 33 959 158 38 963 102 58 979 102 49 979 102 49 979 102 49 979 102 49 979 102 49 979 102 49 979 102 52 979 102 52 979 102 52 979 102 52 979 102 52 979 102 52 979 102 52 979 102 55 979 102 55 979 102 55 979 102 55 979 102 55 979 102 55 979 102 55 979 102 55 979 102 55 979 102 58 979 102 58 979 102 58 979 102 58 979 102 58 979 102 58 979 102 58 979 102 58} do_execsql_test 5.2.11.2 { SELECT sum(c) FILTER (WHERE (c%2)!=0) OVER win, rank() OVER win, dense_rank() OVER win FROM t3 WINDOW win AS ( ORDER BY a NULLS LAST GROUPS 6 PRECEDING EXCLUDE CURRENT ROW ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {1398 1 1 1682 1 1 2000 1 1 2070 1 1 2086 1 1 2309 1 1 2309 1 1 2309 1 1 5079 9 2 5085 9 2 5157 9 2 5391 9 2 5397 9 2 5397 9 2 5543 9 2 5790 9 2 5790 9 2 5790 9 2 5790 9 2 5790 9 2 5790 9 2 6397 22 3 6549 22 3 7156 22 3 7156 22 3 7156 22 3 7156 22 3 8001 28 4 8115 28 4 8960 28 4 8960 28 4 8960 28 4 8960 28 4 8960 28 4 9702 35 5 9850 35 5 10366 35 5 10479 35 5 10479 35 5 10774 40 6 11146 40 6 11441 40 6 11441 40 6 11441 40 6 11441 40 6 11441 40 6 11441 40 6 11441 40 6 11441 40 6 11441 40 6 11563 68 9 11697 68 9 11776 51 7 11925 68 9 11947 68 9 12368 68 9 12368 68 9 12368 68 9 12370 51 7 12530 59 8 12546 59 8 12705 51 7 12705 51 7 12705 51 7 12705 51 7 12705 51 7 12705 51 7 12826 59 8 13050 75 10 13110 75 10 13110 75 10 13154 59 8 13376 59 8 13509 59 8 13509 59 8 13509 59 8 13509 59 8 13528 84 11 13566 84 11 13692 75 10 13796 84 11 13836 75 10 13840 84 11 13949 75 10 13949 75 10 13949 75 10 13949 75 10 14195 84 11 14195 84 11} do_execsql_test 5.2.12.1 { SELECT max(c) OVER win, min(c) OVER win, count(a) OVER win FROM t3 WINDOW win AS ( ORDER BY c NULLS LAST RANGE BETWEEN 6 PRECEDING AND 7 FOLLOWING EXCLUDE CURRENT ROW ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {{} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 113 113 1 113 113 1 158 158 1 160 158 1 160 158 2 223 223 1 224 224 1 238 234 2 239 234 2 239 238 2 252 250 2 256 252 2 257 247 4 257 247 4 257 250 3 335 330 2 336 330 2 336 335 2 355 354 1 355 354 2 355 355 1 399 393 3 399 393 3 399 393 3 399 393 3 399 393 4 480 480 1 480 480 1 572 572 1 574 574 1 618 618 1 618 618 1 633 629 2 634 627 3 634 627 3 634 627 4 634 629 3 667 667 1 670 667 2 671 667 2 671 667 2 671 667 3 711 711 1 711 711 1 716 705 2 726 726 1 730 730 1 762 762 1 768 759 3 768 762 2 768 762 2 792 790 2 792 790 2 794 786 3 794 786 3 844 839 4 845 839 4 845 839 4 845 839 4 845 839 4 870 870 1 870 870 1 870 870 2 934 934 1 938 929 3 938 934 2 938 934 2 959 959 1 963 963 1} do_execsql_test 5.2.12.2 { SELECT sum(c) FILTER (WHERE (c%2)!=0) OVER win, rank() OVER win, dense_rank() OVER win FROM t3 WINDOW win AS ( ORDER BY c NULLS LAST RANGE BETWEEN 6 PRECEDING AND 7 FOLLOWING EXCLUDE CURRENT ROW ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {{} 1 1 {} 4 3 {} 5 4 {} 6 5 {} 6 5 {} 8 6 {} 9 7 {} 10 8 {} 14 12 {} 15 13 {} 19 17 {} 20 18 {} 21 19 {} 23 21 {} 25 23 {} 34 29 {} 35 30 {} 36 31 {} 37 32 {} 38 33 {} 38 33 {} 40 34 {} 41 35 {} 42 36 {} 43 37 {} 43 37 {} 50 42 {} 56 47 {} 60 51 {} 61 52 {} 62 53 {} 64 55 {} 64 55 {} 66 56 {} 67 57 {} 68 58 {} 69 59 {} 70 60 {} 71 61 {} 72 62 {} 78 67 {} 78 67 {} 78 67 {} 81 68 {} 82 69 {} 83 70 {} 85 72 {} 85 72 {} 89 75 113 2 2 113 2 2 223 11 9 239 12 10 239 13 11 257 18 16 335 22 20 335 24 22 355 27 25 355 27 25 504 16 14 504 17 15 705 58 49 710 26 24 711 57 48 711 59 50 759 63 54 929 84 71 959 88 74 963 87 73 1185 32 28 1185 32 28 1191 29 26 1191 29 26 1334 51 43 1334 55 46 1338 52 44 1338 52 44 1584 31 27 1678 77 66 1684 73 63 1684 73 63 1885 48 40 1889 46 39 1889 46 39 1891 45 38 1891 49 41 2005 54 45 2523 75 64 2523 76 65} do_execsql_test 5.2.13.1 { SELECT max(c) OVER win, min(c) OVER win, count(a) OVER win FROM t3 WINDOW win AS ( ORDER BY c NULLS LAST RANGE BETWEEN 0 PRECEDING AND 0 FOLLOWING EXCLUDE CURRENT ROW ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {{} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 113 113 1 113 113 1 158 158 0 158 158 1 355 355 0 355 355 1 393 393 1 393 393 1 399 399 0 399 399 1 480 480 1 480 480 1 618 618 1 618 618 1 629 629 0 629 629 1 667 667 0 667 667 1 768 768 1 768 768 1 839 839 1 839 839 1 870 870 1 870 870 1 870 870 2 938 938 1 938 938 1} do_execsql_test 5.2.13.2 { SELECT sum(c) FILTER (WHERE (c%2)!=0) OVER win, rank() OVER win, dense_rank() OVER win FROM t3 WINDOW win AS ( ORDER BY c NULLS LAST RANGE BETWEEN 0 PRECEDING AND 0 FOLLOWING EXCLUDE CURRENT ROW ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {{} 1 1 {} 4 3 {} 5 4 {} 6 5 {} 6 5 {} 8 6 {} 9 7 {} 10 8 {} 11 9 {} 12 10 {} 13 11 {} 14 12 {} 15 13 {} 16 14 {} 17 15 {} 18 16 {} 19 17 {} 20 18 {} 21 19 {} 22 20 {} 23 21 {} 24 22 {} 25 23 {} 26 24 {} 31 27 {} 34 29 {} 35 30 {} 36 31 {} 37 32 {} 38 33 {} 38 33 {} 40 34 {} 41 35 {} 42 36 {} 43 37 {} 43 37 {} 45 38 {} 48 40 {} 49 41 {} 50 42 {} 51 43 {} 54 45 {} 55 46 {} 56 47 {} 57 48 {} 58 49 {} 59 50 {} 60 51 {} 61 52 {} 62 53 {} 63 54 {} 64 55 {} 64 55 {} 66 56 {} 67 57 {} 68 58 {} 69 59 {} 70 60 {} 71 61 {} 72 62 {} 75 64 {} 76 65 {} 77 66 {} 78 67 {} 78 67 {} 78 67 {} 81 68 {} 82 69 {} 83 70 {} 84 71 {} 85 72 {} 85 72 {} 87 73 {} 88 74 {} 89 75 113 2 2 113 2 2 355 27 25 355 27 25 393 29 26 393 29 26 399 32 28 399 32 28 629 46 39 629 46 39 667 52 44 667 52 44 839 73 63 839 73 63} do_execsql_test 5.2.14.1 { SELECT max(c) OVER win, min(c) OVER win, count(a) OVER win FROM t3 WINDOW win AS ( ORDER BY c NULLS LAST, b NULLS LAST, a NULLS LAST ROWS BETWEEN 6 PRECEDING AND UNBOUNDED FOLLOWING EXCLUDE CURRENT ROW ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {963 929 6 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 83 979 113 80 979 113 81 979 113 82 979 133 79 979 148 78 979 158 76 979 158 77 979 160 76 979 208 75 979 223 74 979 224 73 979 234 72 979 238 71 979 239 70 979 247 69 979 250 68 979 252 67 979 256 66 979 257 65 979 295 64 979 309 63 979 330 63 979 335 61 979 336 60 979 346 59 979 354 58 979 355 56 979 355 58 979 393 55 979 393 56 979 398 54 979 399 52 979 399 53 979 412 52 979 421 51 979 430 50 979 443 49 979 480 47 979 480 48 979 572 46 979 574 46 979 607 44 979 618 42 979 618 43 979 627 41 979 629 40 979 629 40 979 633 39 979 634 38 979 652 37 979 660 36 979 667 34 979 667 35 979 670 34 979 671 33 979 683 32 979 705 31 979 711 30 979 716 29 979 726 28 979 730 27 979 759 26 979 762 25 979 768 23 979 768 24 979 777 22 979 786 21 979 790 20 979 792 19 979 794 18 979 805 17 979 822 16 979 839 15 979 839 15 979 840 13 979 844 12 979 845 11 979 870 8 979 870 9 979 870 10 979 899 8 979 911 7} do_execsql_test 5.2.14.2 { SELECT sum(c) FILTER (WHERE (c%2)!=0) OVER win, rank() OVER win, dense_rank() OVER win FROM t3 WINDOW win AS ( ORDER BY c NULLS LAST, b NULLS LAST, a NULLS LAST ROWS BETWEEN 6 PRECEDING AND UNBOUNDED FOLLOWING EXCLUDE CURRENT ROW ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {2851 89 89 3778 88 88 4681 87 87 5556 83 83 5574 82 82 5586 81 81 5640 84 84 5640 85 85 5640 86 86 7324 80 80 8123 77 77 8129 73 73 8129 74 74 8163 78 78 8163 79 79 8940 71 71 8968 75 75 8968 76 76 9727 66 66 9745 69 69 9745 70 70 9745 72 72 10504 65 65 10504 67 67 10504 68 68 11215 64 64 11844 62 62 11920 63 63 13274 60 60 13274 61 61 13897 58 58 13903 57 57 13925 56 56 13937 55 55 13941 59 59 15203 53 53 15241 54 54 15832 52 52 17100 48 48 17104 46 46 17104 47 47 17106 45 45 17126 49 49 17126 50 50 17126 51 51 17569 42 42 17733 44 44 18176 43 43 18597 40 40 18597 41 41 18952 37 37 18996 39 39 19395 38 38 19760 35 35 19788 36 36 20492 32 32 20492 33 33 20498 30 30 20536 34 34 20833 29 29 20871 28 28 20891 31 31 21180 27 27 21752 23 23 21830 26 26 22025 21 21 22087 22 22 22087 24 24 22087 25 25 22278 20 20 22316 19 19 22549 15 15 22557 14 14 22573 17 17 22573 18 18 22706 10 10 22796 11 11 22796 12 12 22796 13 13 22796 16 16 23022 4 4 23042 2 2 23042 3 3 23042 9 9 23155 1 1 23155 5 5 23155 6 6 23155 7 7 23155 8 8} do_execsql_test 5.3.1.1 { SELECT max(c) OVER win, min(c) OVER win, count(a) OVER win FROM t3 WINDOW win AS ( RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING EXCLUDE GROUP ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {{} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0} do_execsql_test 5.3.1.2 { SELECT sum(c) FILTER (WHERE (c%2)!=0) OVER win, rank() OVER win, dense_rank() OVER win FROM t3 WINDOW win AS ( RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING EXCLUDE GROUP ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {{} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1} do_execsql_test 5.3.2.1 { SELECT max(c) OVER win, min(c) OVER win, count(a) OVER win FROM t3 WINDOW win AS ( ORDER BY a NULLS FIRST RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING EXCLUDE GROUP ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {{} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 899 113 9 899 113 9 899 113 9 899 113 9 899 113 9 899 113 9 899 113 9 899 113 16 899 113 16 899 113 16 899 113 16 899 113 16 899 113 16 899 113 16 899 113 16 899 113 16 979 102 44 979 102 44 979 102 44 979 102 44 979 102 44 979 102 49 979 102 49 979 102 49 979 102 49 979 102 49 979 102 49 979 102 49 979 102 56 979 102 56 979 102 56 979 102 56 979 102 56 979 102 56 979 102 62 979 102 62 979 102 62 979 102 62 979 102 62 979 102 62 979 102 62 979 102 62 979 102 62 979 102 62 979 102 62 979 102 62 979 102 62 979 102 75 979 102 75 979 102 75 979 102 75 979 102 75 979 102 75 979 102 75 979 102 75 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 113 25 979 113 25 979 113 25 979 113 25 979 113 25 979 113 25 979 113 25 979 113 25 979 113 33 979 113 33 979 113 33 979 113 33 979 113 33 979 113 33 979 113 33 979 113 33 979 113 33 979 113 33 979 113 33} do_execsql_test 5.3.2.2 { SELECT sum(c) FILTER (WHERE (c%2)!=0) OVER win, rank() OVER win, dense_rank() OVER win FROM t3 WINDOW win AS ( ORDER BY a NULLS FIRST RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING EXCLUDE GROUP ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {{} 81 11 {} 81 11 {} 81 11 {} 81 11 {} 81 11 {} 81 11 {} 81 11 {} 81 11 {} 81 11 2947 74 10 2947 74 10 2947 74 10 2947 74 10 2947 74 10 2947 74 10 2947 74 10 5287 65 9 5287 65 9 5287 65 9 5287 65 9 5287 65 9 5287 65 9 5287 65 9 5287 65 9 5287 65 9 8400 57 8 8400 57 8 8400 57 8 8400 57 8 8400 57 8 8400 57 8 8400 57 8 8400 57 8 9664 46 7 9664 46 7 9664 46 7 9664 46 7 9664 46 7 9664 46 7 9664 46 7 9664 46 7 9664 46 7 9664 46 7 9664 46 7 10626 41 6 10626 41 6 10626 41 6 10626 41 6 10626 41 6 12145 34 5 12145 34 5 12145 34 5 12145 34 5 12145 34 5 12145 34 5 12145 34 5 13949 28 4 13949 28 4 13949 28 4 13949 28 4 13949 28 4 13949 28 4 15315 15 3 15315 15 3 15315 15 3 15315 15 3 15315 15 3 15315 15 3 15315 15 3 15315 15 3 15315 15 3 15315 15 3 15315 15 3 15315 15 3 15315 15 3 18796 7 2 18796 7 2 18796 7 2 18796 7 2 18796 7 2 18796 7 2 18796 7 2 18796 7 2 21105 1 1 21105 1 1 21105 1 1 21105 1 1 21105 1 1 21105 1 1} do_execsql_test 5.3.3.1 { SELECT max(c) OVER win, min(c) OVER win, count(a) OVER win FROM t3 WINDOW win AS ( PARTITION BY coalesce(a, '') RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING EXCLUDE GROUP ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {{} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0} do_execsql_test 5.3.3.2 { SELECT sum(c) FILTER (WHERE (c%2)!=0) OVER win, rank() OVER win, dense_rank() OVER win FROM t3 WINDOW win AS ( PARTITION BY coalesce(a, '') RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING EXCLUDE GROUP ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {{} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1} do_execsql_test 5.3.4.1 { SELECT max(c) OVER win, min(c) OVER win, count(a) OVER win FROM t3 WINDOW win AS ( ORDER BY a NULLS FIRST GROUPS 6 PRECEDING EXCLUDE GROUP ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {{} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 870 158 0 870 158 0 870 158 0 870 158 0 870 158 0 870 158 0 870 158 0 870 158 0 934 158 8 934 158 8 934 158 8 934 158 8 934 158 8 934 158 8 934 158 8 934 158 8 934 158 8 934 158 8 934 158 8 934 158 8 934 158 8 934 158 21 934 158 21 934 158 21 934 158 21 934 158 21 934 158 21 934 158 27 934 158 27 934 158 27 934 158 27 934 158 27 934 158 27 934 158 27 959 102 50 959 102 50 959 102 50 959 102 50 959 102 50 959 102 50 959 102 50 959 102 50 959 102 50 959 102 50 959 102 50 959 102 50 959 102 50 959 102 50 959 102 50 959 102 50 959 102 50 959 113 39 959 113 39 959 113 39 959 113 39 959 113 39 959 113 39 959 113 39 959 113 39 959 113 39 959 113 39 959 113 39 959 158 34 959 158 34 959 158 34 959 158 34 959 158 34 979 102 46 979 102 46 979 102 46 979 102 46 979 102 46 979 102 46 979 102 46 979 102 47 979 102 47 979 102 47 979 102 47 979 102 47 979 102 47 979 102 47 979 102 47 979 102 47} do_execsql_test 5.3.4.2 { SELECT sum(c) FILTER (WHERE (c%2)!=0) OVER win, rank() OVER win, dense_rank() OVER win FROM t3 WINDOW win AS ( ORDER BY a NULLS FIRST GROUPS 6 PRECEDING EXCLUDE GROUP ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {{} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 2050 7 2 2050 7 2 2050 7 2 2050 7 2 2050 7 2 2050 7 2 2050 7 2 2050 7 2 4359 15 3 4359 15 3 4359 15 3 4359 15 3 4359 15 3 4359 15 3 4359 15 3 4359 15 3 4359 15 3 4359 15 3 4359 15 3 4359 15 3 4359 15 3 7840 28 4 7840 28 4 7840 28 4 7840 28 4 7840 28 4 7840 28 4 9206 34 5 9206 34 5 9206 34 5 9206 34 5 9206 34 5 9206 34 5 9206 34 5 10028 74 10 10028 74 10 10028 74 10 10028 74 10 10028 74 10 10028 74 10 10028 74 10 10396 65 9 10396 65 9 10396 65 9 10396 65 9 10396 65 9 10396 65 9 10396 65 9 10396 65 9 10396 65 9 11002 81 11 11002 81 11 11002 81 11 11002 81 11 11002 81 11 11002 81 11 11002 81 11 11002 81 11 11002 81 11 11010 41 6 11010 41 6 11010 41 6 11010 41 6 11010 41 6 11441 57 8 11441 57 8 11441 57 8 11441 57 8 11441 57 8 11441 57 8 11441 57 8 11441 57 8 12529 46 7 12529 46 7 12529 46 7 12529 46 7 12529 46 7 12529 46 7 12529 46 7 12529 46 7 12529 46 7 12529 46 7 12529 46 7} do_execsql_test 5.3.5.1 { SELECT max(c) OVER win, min(c) OVER win, count(a) OVER win FROM t3 WINDOW win AS ( ORDER BY c NULLS FIRST RANGE BETWEEN 6 PRECEDING AND 7 FOLLOWING EXCLUDE GROUP ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {{} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 158 158 1 160 160 1 160 160 1 223 223 1 224 224 1 238 234 2 239 234 2 239 238 2 252 250 2 256 252 2 257 247 4 257 247 4 257 250 3 335 330 2 336 330 2 336 335 2 354 354 1 354 354 1 355 355 1 398 393 3 398 393 3 399 393 3 399 398 2 399 398 2 572 572 1 574 574 1 633 629 2 634 627 3 634 627 3 634 627 3 634 629 3 667 667 1 670 667 2 671 667 2 671 670 2 671 670 2 711 711 1 711 711 1 716 705 2 726 726 1 730 730 1 762 762 1 762 762 1 762 762 1 768 759 3 792 790 2 792 790 2 794 786 3 794 786 3 844 839 4 845 839 4 845 839 4 845 840 3 845 840 3 934 934 1 934 934 1 934 934 1 938 929 3 959 959 1 963 963 1} do_execsql_test 5.3.5.2 { SELECT sum(c) FILTER (WHERE (c%2)!=0) OVER win, rank() OVER win, dense_rank() OVER win FROM t3 WINDOW win AS ( ORDER BY c NULLS FIRST RANGE BETWEEN 6 PRECEDING AND 7 FOLLOWING EXCLUDE GROUP ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {{} 1 1 {} 2 2 {} 2 2 {} 4 3 {} 5 4 {} 6 5 {} 6 5 {} 8 6 {} 9 7 {} 10 8 {} 14 12 {} 15 13 {} 19 17 {} 20 18 {} 21 19 {} 23 21 {} 25 23 {} 27 25 {} 27 25 {} 34 29 {} 35 30 {} 36 31 {} 37 32 {} 38 33 {} 38 33 {} 40 34 {} 41 35 {} 42 36 {} 43 37 {} 43 37 {} 50 42 {} 56 47 {} 60 51 {} 61 52 {} 62 53 {} 64 55 {} 64 55 {} 66 56 {} 67 57 {} 68 58 {} 69 59 {} 70 60 {} 71 61 {} 72 62 {} 78 67 {} 78 67 {} 78 67 {} 81 68 {} 82 69 {} 83 70 {} 85 72 {} 85 72 {} 89 75 223 11 9 239 12 10 239 13 11 257 18 16 335 22 20 335 24 22 504 16 14 504 17 15 671 52 44 671 52 44 705 58 49 710 26 24 711 57 48 711 59 50 759 63 54 786 32 28 786 32 28 798 29 26 798 29 26 845 73 63 845 73 63 929 84 71 959 88 74 963 87 73 1260 46 39 1260 46 39 1334 51 43 1334 55 46 1584 31 27 1678 77 66 1885 48 40 1891 45 38 1891 49 41 2005 54 45 2523 75 64 2523 76 65} do_execsql_test 5.3.6.1 { SELECT max(c) OVER win, min(c) OVER win, count(a) OVER win FROM t3 WINDOW win AS ( ORDER BY c NULLS FIRST RANGE BETWEEN 0 PRECEDING AND 0 FOLLOWING EXCLUDE GROUP ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {{} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0} do_execsql_test 5.3.6.2 { SELECT sum(c) FILTER (WHERE (c%2)!=0) OVER win, rank() OVER win, dense_rank() OVER win FROM t3 WINDOW win AS ( ORDER BY c NULLS FIRST RANGE BETWEEN 0 PRECEDING AND 0 FOLLOWING EXCLUDE GROUP ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {{} 1 1 {} 2 2 {} 2 2 {} 4 3 {} 5 4 {} 6 5 {} 6 5 {} 8 6 {} 9 7 {} 10 8 {} 11 9 {} 12 10 {} 13 11 {} 14 12 {} 15 13 {} 16 14 {} 17 15 {} 18 16 {} 19 17 {} 20 18 {} 21 19 {} 22 20 {} 23 21 {} 24 22 {} 25 23 {} 26 24 {} 27 25 {} 27 25 {} 29 26 {} 29 26 {} 31 27 {} 32 28 {} 32 28 {} 34 29 {} 35 30 {} 36 31 {} 37 32 {} 38 33 {} 38 33 {} 40 34 {} 41 35 {} 42 36 {} 43 37 {} 43 37 {} 45 38 {} 46 39 {} 46 39 {} 48 40 {} 49 41 {} 50 42 {} 51 43 {} 52 44 {} 52 44 {} 54 45 {} 55 46 {} 56 47 {} 57 48 {} 58 49 {} 59 50 {} 60 51 {} 61 52 {} 62 53 {} 63 54 {} 64 55 {} 64 55 {} 66 56 {} 67 57 {} 68 58 {} 69 59 {} 70 60 {} 71 61 {} 72 62 {} 73 63 {} 73 63 {} 75 64 {} 76 65 {} 77 66 {} 78 67 {} 78 67 {} 78 67 {} 81 68 {} 82 69 {} 83 70 {} 84 71 {} 85 72 {} 85 72 {} 87 73 {} 88 74 {} 89 75} do_execsql_test 5.3.7.1 { SELECT max(c) OVER win, min(c) OVER win, count(a) OVER win FROM t3 WINDOW win AS ( ORDER BY c NULLS FIRST, b NULLS FIRST, a NULLS FIRST ROWS BETWEEN 6 PRECEDING AND UNBOUNDED FOLLOWING EXCLUDE GROUP ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {963 929 6 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 83 979 113 80 979 113 81 979 113 82 979 133 79 979 148 78 979 158 76 979 158 77 979 160 76 979 208 75 979 223 74 979 224 73 979 234 72 979 238 71 979 239 70 979 247 69 979 250 68 979 252 67 979 256 66 979 257 65 979 295 64 979 309 64 979 330 62 979 335 61 979 336 60 979 346 59 979 354 59 979 355 57 979 355 57 979 393 55 979 393 56 979 398 54 979 399 53 979 399 53 979 412 52 979 421 51 979 430 50 979 443 49 979 480 47 979 480 48 979 572 47 979 574 45 979 607 44 979 618 42 979 618 43 979 627 41 979 629 40 979 629 41 979 633 39 979 634 38 979 652 37 979 660 36 979 667 35 979 667 35 979 670 34 979 671 33 979 683 32 979 705 31 979 711 30 979 716 29 979 726 28 979 730 27 979 759 26 979 762 25 979 768 23 979 768 24 979 777 22 979 786 21 979 790 20 979 792 19 979 794 18 979 805 17 979 822 17 979 839 14 979 839 15 979 840 13 979 844 12 979 845 11 979 870 9 979 870 10 979 870 10 979 899 8 979 911 7} do_execsql_test 5.3.7.2 { SELECT sum(c) FILTER (WHERE (c%2)!=0) OVER win, rank() OVER win, dense_rank() OVER win FROM t3 WINDOW win AS ( ORDER BY c NULLS FIRST, b NULLS FIRST, a NULLS FIRST ROWS BETWEEN 6 PRECEDING AND UNBOUNDED FOLLOWING EXCLUDE GROUP ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {2851 89 89 3778 88 88 4681 87 87 5556 83 83 5574 82 82 5586 81 81 5640 84 84 5640 85 85 5640 86 86 7324 80 80 8123 77 77 8129 73 73 8129 74 74 8163 78 78 8163 79 79 8940 71 71 8968 75 75 8968 76 76 9727 66 66 9745 69 69 9745 70 70 9745 72 72 10504 65 65 10504 67 67 10504 68 68 11215 64 64 11844 62 62 11920 63 63 13274 60 60 13274 61 61 13897 58 58 13903 57 57 13925 56 56 13937 55 55 13941 59 59 15203 53 53 15241 54 54 15832 52 52 17100 48 48 17104 46 46 17104 47 47 17106 45 45 17126 49 49 17126 50 50 17126 51 51 17569 42 42 17733 44 44 18176 43 43 18597 40 40 18597 41 41 18952 37 37 18996 39 39 19395 38 38 19760 35 35 19788 36 36 20492 32 32 20492 33 33 20498 30 30 20536 34 34 20833 29 29 20871 28 28 20891 31 31 21180 27 27 21752 23 23 21830 26 26 22025 21 21 22087 22 22 22087 24 24 22087 25 25 22278 20 20 22316 19 19 22549 15 15 22557 14 14 22573 17 17 22573 18 18 22706 10 10 22796 11 11 22796 12 12 22796 13 13 22796 16 16 23022 4 4 23042 2 2 23042 3 3 23042 9 9 23155 1 1 23155 5 5 23155 6 6 23155 7 7 23155 8 8} do_execsql_test 5.3.8.1 { SELECT max(c) OVER win, min(c) OVER win, count(a) OVER win FROM t3 WINDOW win AS ( RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING EXCLUDE GROUP ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {{} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0} do_execsql_test 5.3.8.2 { SELECT sum(c) FILTER (WHERE (c%2)!=0) OVER win, rank() OVER win, dense_rank() OVER win FROM t3 WINDOW win AS ( RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING EXCLUDE GROUP ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {{} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1} do_execsql_test 5.3.9.1 { SELECT max(c) OVER win, min(c) OVER win, count(a) OVER win FROM t3 WINDOW win AS ( ORDER BY a NULLS LAST RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING EXCLUDE GROUP ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {{} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 870 158 0 870 158 0 870 158 0 870 158 0 870 158 0 870 158 0 870 158 0 870 158 0 870 158 0 899 113 9 899 113 9 899 113 9 899 113 9 899 113 9 899 113 9 899 113 9 899 113 16 899 113 16 899 113 16 899 113 16 899 113 16 899 113 16 899 113 16 899 113 16 899 113 16 979 102 44 979 102 44 979 102 44 979 102 44 979 102 44 979 102 49 979 102 49 979 102 49 979 102 49 979 102 49 979 102 49 979 102 49 979 102 56 979 102 56 979 102 56 979 102 56 979 102 56 979 102 56 979 102 62 979 102 62 979 102 62 979 102 62 979 102 62 979 102 62 979 102 62 979 102 62 979 102 62 979 102 62 979 102 62 979 102 62 979 102 62 979 102 75 979 102 75 979 102 75 979 102 75 979 102 75 979 102 75 979 102 75 979 102 75 979 113 25 979 113 25 979 113 25 979 113 25 979 113 25 979 113 25 979 113 25 979 113 25 979 113 33 979 113 33 979 113 33 979 113 33 979 113 33 979 113 33 979 113 33 979 113 33 979 113 33 979 113 33 979 113 33} do_execsql_test 5.3.9.2 { SELECT sum(c) FILTER (WHERE (c%2)!=0) OVER win, rank() OVER win, dense_rank() OVER win FROM t3 WINDOW win AS ( ORDER BY a NULLS LAST RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING EXCLUDE GROUP ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {{} 84 11 {} 84 11 {} 84 11 {} 84 11 {} 84 11 {} 84 11 2050 75 10 2050 75 10 2050 75 10 2050 75 10 2050 75 10 2050 75 10 2050 75 10 2050 75 10 2050 75 10 4997 68 9 4997 68 9 4997 68 9 4997 68 9 4997 68 9 4997 68 9 4997 68 9 7337 59 8 7337 59 8 7337 59 8 7337 59 8 7337 59 8 7337 59 8 7337 59 8 7337 59 8 7337 59 8 10450 51 7 10450 51 7 10450 51 7 10450 51 7 10450 51 7 10450 51 7 10450 51 7 10450 51 7 11714 40 6 11714 40 6 11714 40 6 11714 40 6 11714 40 6 11714 40 6 11714 40 6 11714 40 6 11714 40 6 11714 40 6 11714 40 6 12676 35 5 12676 35 5 12676 35 5 12676 35 5 12676 35 5 14195 28 4 14195 28 4 14195 28 4 14195 28 4 14195 28 4 14195 28 4 14195 28 4 15999 22 3 15999 22 3 15999 22 3 15999 22 3 15999 22 3 15999 22 3 17365 9 2 17365 9 2 17365 9 2 17365 9 2 17365 9 2 17365 9 2 17365 9 2 17365 9 2 17365 9 2 17365 9 2 17365 9 2 17365 9 2 17365 9 2 20846 1 1 20846 1 1 20846 1 1 20846 1 1 20846 1 1 20846 1 1 20846 1 1 20846 1 1} do_execsql_test 5.3.10.1 { SELECT max(c) OVER win, min(c) OVER win, count(a) OVER win FROM t3 WINDOW win AS ( PARTITION BY coalesce(a, '') RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING EXCLUDE GROUP ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {{} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0} do_execsql_test 5.3.10.2 { SELECT sum(c) FILTER (WHERE (c%2)!=0) OVER win, rank() OVER win, dense_rank() OVER win FROM t3 WINDOW win AS ( PARTITION BY coalesce(a, '') RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING EXCLUDE GROUP ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {{} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1} do_execsql_test 5.3.11.1 { SELECT max(c) OVER win, min(c) OVER win, count(a) OVER win FROM t3 WINDOW win AS ( ORDER BY a NULLS LAST GROUPS 6 PRECEDING EXCLUDE GROUP ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {{} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 934 158 27 934 158 27 934 158 27 934 158 27 934 158 27 934 158 27 934 158 27 934 223 8 934 223 8 934 223 8 934 223 8 934 223 8 934 223 8 934 223 8 934 223 8 934 223 8 934 223 8 934 223 8 934 223 8 934 223 8 934 223 21 934 223 21 934 223 21 934 223 21 934 223 21 934 223 21 959 102 50 959 102 50 959 102 50 959 102 50 959 102 50 959 102 50 959 102 50 959 102 50 959 102 50 959 102 50 959 102 50 959 102 50 959 102 50 959 102 50 959 102 50 959 102 50 959 102 50 959 113 39 959 113 39 959 113 39 959 113 39 959 113 39 959 113 39 959 113 39 959 113 39 959 113 39 959 113 39 959 113 39 959 158 34 959 158 34 959 158 34 959 158 34 959 158 34 979 102 46 979 102 46 979 102 46 979 102 46 979 102 46 979 102 46 979 102 46 979 102 47 979 102 47 979 102 47 979 102 47 979 102 47 979 102 47 979 102 47 979 102 47 979 102 47 979 102 49 979 102 49 979 102 49 979 102 49 979 102 49 979 102 49} do_execsql_test 5.3.11.2 { SELECT sum(c) FILTER (WHERE (c%2)!=0) OVER win, rank() OVER win, dense_rank() OVER win FROM t3 WINDOW win AS ( ORDER BY a NULLS LAST GROUPS 6 PRECEDING EXCLUDE GROUP ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {{} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 2309 9 2 2309 9 2 2309 9 2 2309 9 2 2309 9 2 2309 9 2 2309 9 2 2309 9 2 2309 9 2 2309 9 2 2309 9 2 2309 9 2 2309 9 2 5790 22 3 5790 22 3 5790 22 3 5790 22 3 5790 22 3 5790 22 3 7156 28 4 7156 28 4 7156 28 4 7156 28 4 7156 28 4 7156 28 4 7156 28 4 8960 35 5 8960 35 5 8960 35 5 8960 35 5 8960 35 5 10028 68 9 10028 68 9 10028 68 9 10028 68 9 10028 68 9 10028 68 9 10028 68 9 10396 59 8 10396 59 8 10396 59 8 10396 59 8 10396 59 8 10396 59 8 10396 59 8 10396 59 8 10396 59 8 10479 40 6 10479 40 6 10479 40 6 10479 40 6 10479 40 6 10479 40 6 10479 40 6 10479 40 6 10479 40 6 10479 40 6 10479 40 6 11002 75 10 11002 75 10 11002 75 10 11002 75 10 11002 75 10 11002 75 10 11002 75 10 11002 75 10 11002 75 10 11441 51 7 11441 51 7 11441 51 7 11441 51 7 11441 51 7 11441 51 7 11441 51 7 11441 51 7 12145 84 11 12145 84 11 12145 84 11 12145 84 11 12145 84 11 12145 84 11} do_execsql_test 5.3.12.1 { SELECT max(c) OVER win, min(c) OVER win, count(a) OVER win FROM t3 WINDOW win AS ( ORDER BY c NULLS LAST RANGE BETWEEN 6 PRECEDING AND 7 FOLLOWING EXCLUDE GROUP ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {{} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 158 158 1 160 160 1 160 160 1 223 223 1 224 224 1 238 234 2 239 234 2 239 238 2 252 250 2 256 252 2 257 247 4 257 247 4 257 250 3 335 330 2 336 330 2 336 335 2 354 354 1 354 354 1 355 355 1 398 393 3 398 393 3 399 393 3 399 398 2 399 398 2 572 572 1 574 574 1 633 629 2 634 627 3 634 627 3 634 627 3 634 629 3 667 667 1 670 667 2 671 667 2 671 670 2 671 670 2 711 711 1 711 711 1 716 705 2 726 726 1 730 730 1 762 762 1 762 762 1 762 762 1 768 759 3 792 790 2 792 790 2 794 786 3 794 786 3 844 839 4 845 839 4 845 839 4 845 840 3 845 840 3 934 934 1 934 934 1 934 934 1 938 929 3 959 959 1 963 963 1} do_execsql_test 5.3.12.2 { SELECT sum(c) FILTER (WHERE (c%2)!=0) OVER win, rank() OVER win, dense_rank() OVER win FROM t3 WINDOW win AS ( ORDER BY c NULLS LAST RANGE BETWEEN 6 PRECEDING AND 7 FOLLOWING EXCLUDE GROUP ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {{} 1 1 {} 2 2 {} 2 2 {} 4 3 {} 5 4 {} 6 5 {} 6 5 {} 8 6 {} 9 7 {} 10 8 {} 14 12 {} 15 13 {} 19 17 {} 20 18 {} 21 19 {} 23 21 {} 25 23 {} 27 25 {} 27 25 {} 34 29 {} 35 30 {} 36 31 {} 37 32 {} 38 33 {} 38 33 {} 40 34 {} 41 35 {} 42 36 {} 43 37 {} 43 37 {} 50 42 {} 56 47 {} 60 51 {} 61 52 {} 62 53 {} 64 55 {} 64 55 {} 66 56 {} 67 57 {} 68 58 {} 69 59 {} 70 60 {} 71 61 {} 72 62 {} 78 67 {} 78 67 {} 78 67 {} 81 68 {} 82 69 {} 83 70 {} 85 72 {} 85 72 {} 89 75 223 11 9 239 12 10 239 13 11 257 18 16 335 22 20 335 24 22 504 16 14 504 17 15 671 52 44 671 52 44 705 58 49 710 26 24 711 57 48 711 59 50 759 63 54 786 32 28 786 32 28 798 29 26 798 29 26 845 73 63 845 73 63 929 84 71 959 88 74 963 87 73 1260 46 39 1260 46 39 1334 51 43 1334 55 46 1584 31 27 1678 77 66 1885 48 40 1891 45 38 1891 49 41 2005 54 45 2523 75 64 2523 76 65} do_execsql_test 5.3.13.1 { SELECT max(c) OVER win, min(c) OVER win, count(a) OVER win FROM t3 WINDOW win AS ( ORDER BY c NULLS LAST RANGE BETWEEN 0 PRECEDING AND 0 FOLLOWING EXCLUDE GROUP ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {{} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0} do_execsql_test 5.3.13.2 { SELECT sum(c) FILTER (WHERE (c%2)!=0) OVER win, rank() OVER win, dense_rank() OVER win FROM t3 WINDOW win AS ( ORDER BY c NULLS LAST RANGE BETWEEN 0 PRECEDING AND 0 FOLLOWING EXCLUDE GROUP ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {{} 1 1 {} 2 2 {} 2 2 {} 4 3 {} 5 4 {} 6 5 {} 6 5 {} 8 6 {} 9 7 {} 10 8 {} 11 9 {} 12 10 {} 13 11 {} 14 12 {} 15 13 {} 16 14 {} 17 15 {} 18 16 {} 19 17 {} 20 18 {} 21 19 {} 22 20 {} 23 21 {} 24 22 {} 25 23 {} 26 24 {} 27 25 {} 27 25 {} 29 26 {} 29 26 {} 31 27 {} 32 28 {} 32 28 {} 34 29 {} 35 30 {} 36 31 {} 37 32 {} 38 33 {} 38 33 {} 40 34 {} 41 35 {} 42 36 {} 43 37 {} 43 37 {} 45 38 {} 46 39 {} 46 39 {} 48 40 {} 49 41 {} 50 42 {} 51 43 {} 52 44 {} 52 44 {} 54 45 {} 55 46 {} 56 47 {} 57 48 {} 58 49 {} 59 50 {} 60 51 {} 61 52 {} 62 53 {} 63 54 {} 64 55 {} 64 55 {} 66 56 {} 67 57 {} 68 58 {} 69 59 {} 70 60 {} 71 61 {} 72 62 {} 73 63 {} 73 63 {} 75 64 {} 76 65 {} 77 66 {} 78 67 {} 78 67 {} 78 67 {} 81 68 {} 82 69 {} 83 70 {} 84 71 {} 85 72 {} 85 72 {} 87 73 {} 88 74 {} 89 75} do_execsql_test 5.3.14.1 { SELECT max(c) OVER win, min(c) OVER win, count(a) OVER win FROM t3 WINDOW win AS ( ORDER BY c NULLS LAST, b NULLS LAST, a NULLS LAST ROWS BETWEEN 6 PRECEDING AND UNBOUNDED FOLLOWING EXCLUDE GROUP ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {963 929 6 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82 979 102 83 979 113 80 979 113 81 979 113 82 979 133 79 979 148 78 979 158 76 979 158 77 979 160 76 979 208 75 979 223 74 979 224 73 979 234 72 979 238 71 979 239 70 979 247 69 979 250 68 979 252 67 979 256 66 979 257 65 979 295 64 979 309 63 979 330 63 979 335 61 979 336 60 979 346 59 979 354 58 979 355 56 979 355 58 979 393 55 979 393 56 979 398 54 979 399 52 979 399 53 979 412 52 979 421 51 979 430 50 979 443 49 979 480 47 979 480 48 979 572 46 979 574 46 979 607 44 979 618 42 979 618 43 979 627 41 979 629 40 979 629 40 979 633 39 979 634 38 979 652 37 979 660 36 979 667 34 979 667 35 979 670 34 979 671 33 979 683 32 979 705 31 979 711 30 979 716 29 979 726 28 979 730 27 979 759 26 979 762 25 979 768 23 979 768 24 979 777 22 979 786 21 979 790 20 979 792 19 979 794 18 979 805 17 979 822 16 979 839 15 979 839 15 979 840 13 979 844 12 979 845 11 979 870 8 979 870 9 979 870 10 979 899 8 979 911 7} do_execsql_test 5.3.14.2 { SELECT sum(c) FILTER (WHERE (c%2)!=0) OVER win, rank() OVER win, dense_rank() OVER win FROM t3 WINDOW win AS ( ORDER BY c NULLS LAST, b NULLS LAST, a NULLS LAST ROWS BETWEEN 6 PRECEDING AND UNBOUNDED FOLLOWING EXCLUDE GROUP ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {2851 89 89 3778 88 88 4681 87 87 5556 83 83 5574 82 82 5586 81 81 5640 84 84 5640 85 85 5640 86 86 7324 80 80 8123 77 77 8129 73 73 8129 74 74 8163 78 78 8163 79 79 8940 71 71 8968 75 75 8968 76 76 9727 66 66 9745 69 69 9745 70 70 9745 72 72 10504 65 65 10504 67 67 10504 68 68 11215 64 64 11844 62 62 11920 63 63 13274 60 60 13274 61 61 13897 58 58 13903 57 57 13925 56 56 13937 55 55 13941 59 59 15203 53 53 15241 54 54 15832 52 52 17100 48 48 17104 46 46 17104 47 47 17106 45 45 17126 49 49 17126 50 50 17126 51 51 17569 42 42 17733 44 44 18176 43 43 18597 40 40 18597 41 41 18952 37 37 18996 39 39 19395 38 38 19760 35 35 19788 36 36 20492 32 32 20492 33 33 20498 30 30 20536 34 34 20833 29 29 20871 28 28 20891 31 31 21180 27 27 21752 23 23 21830 26 26 22025 21 21 22087 22 22 22087 24 24 22087 25 25 22278 20 20 22316 19 19 22549 15 15 22557 14 14 22573 17 17 22573 18 18 22706 10 10 22796 11 11 22796 12 12 22796 13 13 22796 16 16 23022 4 4 23042 2 2 23042 3 3 23042 9 9 23155 1 1 23155 5 5 23155 6 6 23155 7 7 23155 8 8} do_execsql_test 5.4.1.1 { SELECT max(c) OVER win, min(c) OVER win, count(a) OVER win FROM t3 WINDOW win AS ( RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING EXCLUDE TIES ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {102 102 1 113 113 1 113 113 1 133 133 1 148 148 1 158 158 0 158 158 1 160 160 1 208 208 1 223 223 1 224 224 1 234 234 1 238 238 1 239 239 1 247 247 1 250 250 1 252 252 1 256 256 1 257 257 1 295 295 1 309 309 1 330 330 1 335 335 1 336 336 1 346 346 1 354 354 1 355 355 0 355 355 1 393 393 1 393 393 1 398 398 1 399 399 0 399 399 1 412 412 1 421 421 1 430 430 1 443 443 1 480 480 1 480 480 1 572 572 1 574 574 1 607 607 1 618 618 1 618 618 1 627 627 1 629 629 0 629 629 1 633 633 1 634 634 1 652 652 1 660 660 1 667 667 0 667 667 1 670 670 1 671 671 1 683 683 1 705 705 1 711 711 1 716 716 1 726 726 1 730 730 1 759 759 1 762 762 1 768 768 1 768 768 1 777 777 1 786 786 1 790 790 1 792 792 1 794 794 1 805 805 1 822 822 1 839 839 1 839 839 1 840 840 1 844 844 1 845 845 1 870 870 0 870 870 1 870 870 1 899 899 1 911 911 1 929 929 1 934 934 1 938 938 1 938 938 1 959 959 1 963 963 1 979 979 1} do_execsql_test 5.4.1.2 { SELECT sum(c) FILTER (WHERE (c%2)!=0) OVER win, rank() OVER win, dense_rank() OVER win FROM t3 WINDOW win AS ( RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING EXCLUDE TIES ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {{} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 113 1 1 113 1 1 133 1 1 223 1 1 239 1 1 247 1 1 257 1 1 295 1 1 309 1 1 335 1 1 355 1 1 355 1 1 393 1 1 393 1 1 399 1 1 399 1 1 421 1 1 443 1 1 607 1 1 627 1 1 629 1 1 629 1 1 633 1 1 667 1 1 667 1 1 671 1 1 683 1 1 705 1 1 711 1 1 759 1 1 777 1 1 805 1 1 839 1 1 839 1 1 845 1 1 899 1 1 911 1 1 929 1 1 959 1 1 963 1 1 979 1 1} do_execsql_test 5.4.2.1 { SELECT max(c) OVER win, min(c) OVER win, count(a) OVER win FROM t3 WINDOW win AS ( ORDER BY a NULLS FIRST RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING EXCLUDE TIES ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {113 113 1 234 234 1 257 257 1 336 336 1 354 354 1 768 768 1 839 839 1 839 839 1 899 113 10 899 113 10 899 113 10 899 113 10 899 113 10 899 113 10 899 113 10 899 113 17 899 113 17 899 113 17 899 113 17 899 113 17 899 113 17 899 113 17 899 899 1 963 113 17 979 102 34 979 102 45 979 102 45 979 102 45 979 102 45 979 102 45 979 102 50 979 102 50 979 102 50 979 102 50 979 102 50 979 102 50 979 102 50 979 102 57 979 102 57 979 102 57 979 102 57 979 102 57 979 102 57 979 102 63 979 102 63 979 102 63 979 102 63 979 102 63 979 102 63 979 102 63 979 102 63 979 102 63 979 102 63 979 102 63 979 102 63 979 102 63 979 102 76 979 102 76 979 102 76 979 102 76 979 102 76 979 102 76 979 102 76 979 102 76 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 113 17 979 113 26 979 113 26 979 113 26 979 113 26 979 113 26 979 113 26 979 113 26 979 113 26 979 113 34 979 113 34 979 113 34 979 113 34 979 113 34 979 113 34 979 113 34 979 113 34 979 113 34 979 113 34} do_execsql_test 5.4.2.2 { SELECT sum(c) FILTER (WHERE (c%2)!=0) OVER win, rank() OVER win, dense_rank() OVER win FROM t3 WINDOW win AS ( ORDER BY a NULLS FIRST RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING EXCLUDE TIES ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {{} 81 11 {} 81 11 {} 81 11 {} 81 11 113 81 11 257 81 11 839 81 11 839 81 11 899 81 11 2947 74 10 2947 74 10 2947 74 10 3368 74 10 3390 74 10 3618 74 10 3752 74 10 5287 65 9 5287 65 9 5287 65 9 5287 65 9 5420 65 9 5642 65 9 5970 65 9 6250 65 9 6266 65 9 8400 57 8 8400 57 8 8400 57 8 8400 57 8 8400 57 8 8400 57 8 8735 57 8 9329 57 8 9664 46 7 9664 46 7 9664 46 7 9664 46 7 9664 46 7 9664 46 7 9664 46 7 9664 46 7 9664 46 7 9959 46 7 10331 46 7 10626 41 6 10626 41 6 10739 41 6 11255 41 6 11403 41 6 12145 34 5 12145 34 5 12145 34 5 12145 34 5 12145 34 5 12990 34 5 13104 34 5 13949 28 4 13949 28 4 13949 28 4 13949 28 4 14556 28 4 14708 28 4 15315 15 3 15315 15 3 15315 15 3 15315 15 3 15315 15 3 15315 15 3 15562 15 3 15708 15 3 15708 15 3 15714 15 3 15948 15 3 16020 15 3 16026 15 3 18796 7 2 18796 7 2 18796 7 2 19019 7 2 19035 7 2 19105 7 2 19423 7 2 19707 7 2 21105 1 1 21105 1 1 21460 1 1 21504 1 1 21734 1 1 21772 1 1} do_execsql_test 5.4.3.1 { SELECT max(c) OVER win, min(c) OVER win, count(a) OVER win FROM t3 WINDOW win AS ( PARTITION BY coalesce(a, '') RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING EXCLUDE TIES ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {102 102 1 113 113 1 113 113 1 133 133 1 148 148 1 158 158 0 158 158 1 160 160 1 208 208 1 223 223 1 224 224 1 234 234 1 238 238 1 239 239 1 247 247 1 250 250 1 252 252 1 256 256 1 257 257 1 295 295 1 309 309 1 330 330 1 335 335 1 336 336 1 346 346 1 354 354 1 355 355 0 355 355 1 393 393 1 393 393 1 398 398 1 399 399 0 399 399 1 412 412 1 421 421 1 430 430 1 443 443 1 480 480 1 480 480 1 572 572 1 574 574 1 607 607 1 618 618 1 618 618 1 627 627 1 629 629 0 629 629 1 633 633 1 634 634 1 652 652 1 660 660 1 667 667 0 667 667 1 670 670 1 671 671 1 683 683 1 705 705 1 711 711 1 716 716 1 726 726 1 730 730 1 759 759 1 762 762 1 768 768 1 768 768 1 777 777 1 786 786 1 790 790 1 792 792 1 794 794 1 805 805 1 822 822 1 839 839 1 839 839 1 840 840 1 844 844 1 845 845 1 870 870 0 870 870 1 870 870 1 899 899 1 911 911 1 929 929 1 934 934 1 938 938 1 938 938 1 959 959 1 963 963 1 979 979 1} do_execsql_test 5.4.3.2 { SELECT sum(c) FILTER (WHERE (c%2)!=0) OVER win, rank() OVER win, dense_rank() OVER win FROM t3 WINDOW win AS ( PARTITION BY coalesce(a, '') RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING EXCLUDE TIES ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {{} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 113 1 1 113 1 1 133 1 1 223 1 1 239 1 1 247 1 1 257 1 1 295 1 1 309 1 1 335 1 1 355 1 1 355 1 1 393 1 1 393 1 1 399 1 1 399 1 1 421 1 1 443 1 1 607 1 1 627 1 1 629 1 1 629 1 1 633 1 1 667 1 1 667 1 1 671 1 1 683 1 1 705 1 1 711 1 1 759 1 1 777 1 1 805 1 1 839 1 1 839 1 1 845 1 1 899 1 1 911 1 1 929 1 1 959 1 1 963 1 1 979 1 1} do_execsql_test 5.4.4.1 { SELECT max(c) OVER win, min(c) OVER win, count(a) OVER win FROM t3 WINDOW win AS ( ORDER BY a NULLS FIRST GROUPS 6 PRECEDING EXCLUDE TIES ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {158 158 0 355 355 0 399 399 0 629 629 0 667 667 0 870 158 1 870 158 1 870 158 1 870 158 1 870 158 1 870 158 1 870 870 0 911 158 1 934 158 1 934 158 9 934 158 9 934 158 9 934 158 9 934 158 9 934 158 9 934 158 9 934 158 9 934 158 9 934 158 9 934 158 9 934 158 9 934 158 9 934 158 22 934 158 22 934 158 22 934 158 22 934 158 22 934 158 22 934 158 28 934 158 28 934 158 28 934 158 28 934 158 28 934 158 28 959 102 40 959 102 51 959 102 51 959 102 51 959 102 51 959 102 51 959 102 51 959 102 51 959 102 51 959 102 51 959 102 51 959 102 51 959 102 51 959 102 51 959 102 51 959 102 51 959 113 35 959 113 40 959 113 40 959 113 40 959 113 40 959 113 40 959 113 40 959 113 40 959 113 40 959 113 40 959 113 40 959 158 28 959 158 35 959 158 35 959 158 35 959 158 35 963 102 51 979 102 47 979 102 47 979 102 47 979 102 47 979 102 47 979 102 47 979 102 47 979 102 48 979 102 48 979 102 48 979 102 48 979 102 48 979 102 48 979 102 48 979 102 48 979 102 48 979 102 51} do_execsql_test 5.4.4.2 { SELECT sum(c) FILTER (WHERE (c%2)!=0) OVER win, rank() OVER win, dense_rank() OVER win FROM t3 WINDOW win AS ( ORDER BY a NULLS FIRST GROUPS 6 PRECEDING EXCLUDE TIES ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {{} 1 1 {} 1 1 355 1 1 399 1 1 629 1 1 667 1 1 2050 7 2 2050 7 2 2050 7 2 2273 7 2 2289 7 2 2359 7 2 2677 7 2 2961 7 2 4359 15 3 4359 15 3 4359 15 3 4359 15 3 4359 15 3 4359 15 3 4606 15 3 4752 15 3 4752 15 3 4758 15 3 4992 15 3 5064 15 3 5070 15 3 7840 28 4 7840 28 4 7840 28 4 7840 28 4 8447 28 4 8599 28 4 9206 34 5 9206 34 5 9206 34 5 9206 34 5 9206 34 5 10028 74 10 10028 74 10 10028 74 10 10051 34 5 10165 34 5 10396 65 9 10396 65 9 10396 65 9 10396 65 9 10449 74 10 10471 74 10 10529 65 9 10699 74 10 10751 65 9 10833 74 10 11002 81 11 11002 81 11 11002 81 11 11002 81 11 11010 41 6 11010 41 6 11079 65 9 11115 81 11 11123 41 6 11259 81 11 11359 65 9 11375 65 9 11441 57 8 11441 57 8 11441 57 8 11441 57 8 11441 57 8 11441 57 8 11639 41 6 11776 57 8 11787 41 6 11841 81 11 11841 81 11 11901 81 11 12370 57 8 12529 46 7 12529 46 7 12529 46 7 12529 46 7 12529 46 7 12529 46 7 12529 46 7 12529 46 7 12529 46 7 12824 46 7 13196 46 7} do_execsql_test 5.4.5.1 { SELECT max(c) OVER win, min(c) OVER win, count(a) OVER win FROM t3 WINDOW win AS ( ORDER BY c NULLS FIRST RANGE BETWEEN 6 PRECEDING AND 7 FOLLOWING EXCLUDE TIES ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {102 102 1 113 113 1 113 113 1 133 133 1 148 148 1 160 158 1 160 158 2 160 158 2 208 208 1 224 223 2 224 223 2 239 234 3 239 234 3 239 234 3 252 247 3 257 247 5 257 247 5 257 250 4 257 252 3 295 295 1 309 309 1 336 330 3 336 330 3 336 330 3 346 346 1 355 354 1 355 354 2 355 354 2 399 393 3 399 393 3 399 393 3 399 393 4 399 393 4 412 412 1 421 421 1 430 430 1 443 443 1 480 480 1 480 480 1 574 572 2 574 572 2 607 607 1 618 618 1 618 618 1 634 627 3 634 627 4 634 627 4 634 627 4 634 629 3 652 652 1 667 660 2 671 667 2 671 667 3 671 667 3 671 667 3 683 683 1 711 705 2 716 705 3 716 711 2 730 726 2 730 726 2 762 759 2 768 759 4 768 762 2 768 762 2 777 777 1 792 786 3 794 786 4 794 786 4 794 790 3 805 805 1 822 822 1 845 839 4 845 839 4 845 839 5 845 839 5 845 839 5 870 870 0 870 870 1 870 870 1 899 899 1 911 911 1 934 929 2 938 929 4 938 934 2 938 934 2 963 959 2 963 959 2 979 979 1} do_execsql_test 5.4.5.2 { SELECT sum(c) FILTER (WHERE (c%2)!=0) OVER win, rank() OVER win, dense_rank() OVER win FROM t3 WINDOW win AS ( ORDER BY c NULLS FIRST RANGE BETWEEN 6 PRECEDING AND 7 FOLLOWING EXCLUDE TIES ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {{} 1 1 {} 5 4 {} 6 5 {} 6 5 {} 8 6 {} 9 7 {} 25 23 {} 34 29 {} 36 31 {} 38 33 {} 38 33 {} 40 34 {} 41 35 {} 43 37 {} 43 37 {} 50 42 {} 60 51 {} 61 52 {} 64 55 {} 64 55 {} 67 57 {} 68 58 {} 69 59 {} 70 60 {} 72 62 {} 78 67 {} 78 67 {} 78 67 {} 85 72 {} 85 72 113 2 2 113 2 2 133 4 3 223 10 8 223 11 9 239 12 10 239 13 11 239 14 12 247 15 13 257 18 16 257 19 17 295 20 18 309 21 19 335 22 20 335 23 21 335 24 22 355 27 25 355 27 25 421 35 30 443 37 32 504 16 14 504 17 15 607 42 36 683 56 47 710 26 24 711 59 50 759 62 53 759 63 54 777 66 56 805 71 61 899 81 68 911 82 69 929 83 70 929 84 71 979 89 75 1185 32 28 1185 32 28 1191 29 26 1191 29 26 1334 51 43 1338 52 44 1338 52 44 1416 57 48 1416 58 49 1584 31 27 1684 73 63 1684 73 63 1889 46 39 1889 46 39 1891 49 41 1922 87 73 1922 88 74 2005 54 45 2005 55 46 2518 45 38 2518 48 40 2523 75 64 2523 76 65 2523 77 66} do_execsql_test 5.4.6.1 { SELECT max(c) OVER win, min(c) OVER win, count(a) OVER win FROM t3 WINDOW win AS ( ORDER BY c NULLS FIRST RANGE BETWEEN 0 PRECEDING AND 0 FOLLOWING EXCLUDE TIES ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {102 102 1 113 113 1 113 113 1 133 133 1 148 148 1 158 158 0 158 158 1 160 160 1 208 208 1 223 223 1 224 224 1 234 234 1 238 238 1 239 239 1 247 247 1 250 250 1 252 252 1 256 256 1 257 257 1 295 295 1 309 309 1 330 330 1 335 335 1 336 336 1 346 346 1 354 354 1 355 355 0 355 355 1 393 393 1 393 393 1 398 398 1 399 399 0 399 399 1 412 412 1 421 421 1 430 430 1 443 443 1 480 480 1 480 480 1 572 572 1 574 574 1 607 607 1 618 618 1 618 618 1 627 627 1 629 629 0 629 629 1 633 633 1 634 634 1 652 652 1 660 660 1 667 667 0 667 667 1 670 670 1 671 671 1 683 683 1 705 705 1 711 711 1 716 716 1 726 726 1 730 730 1 759 759 1 762 762 1 768 768 1 768 768 1 777 777 1 786 786 1 790 790 1 792 792 1 794 794 1 805 805 1 822 822 1 839 839 1 839 839 1 840 840 1 844 844 1 845 845 1 870 870 0 870 870 1 870 870 1 899 899 1 911 911 1 929 929 1 934 934 1 938 938 1 938 938 1 959 959 1 963 963 1 979 979 1} do_execsql_test 5.4.6.2 { SELECT sum(c) FILTER (WHERE (c%2)!=0) OVER win, rank() OVER win, dense_rank() OVER win FROM t3 WINDOW win AS ( ORDER BY c NULLS FIRST RANGE BETWEEN 0 PRECEDING AND 0 FOLLOWING EXCLUDE TIES ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {{} 1 1 {} 5 4 {} 6 5 {} 6 5 {} 8 6 {} 9 7 {} 11 9 {} 12 10 {} 13 11 {} 16 14 {} 17 15 {} 18 16 {} 22 20 {} 24 22 {} 25 23 {} 26 24 {} 31 27 {} 34 29 {} 36 31 {} 38 33 {} 38 33 {} 40 34 {} 41 35 {} 43 37 {} 43 37 {} 49 41 {} 50 42 {} 51 43 {} 54 45 {} 59 50 {} 60 51 {} 61 52 {} 63 54 {} 64 55 {} 64 55 {} 67 57 {} 68 58 {} 69 59 {} 70 60 {} 72 62 {} 75 64 {} 76 65 {} 78 67 {} 78 67 {} 78 67 {} 84 71 {} 85 72 {} 85 72 113 2 2 113 2 2 133 4 3 223 10 8 239 14 12 247 15 13 257 19 17 295 20 18 309 21 19 335 23 21 355 27 25 355 27 25 393 29 26 393 29 26 399 32 28 399 32 28 421 35 30 443 37 32 607 42 36 627 45 38 629 46 39 629 46 39 633 48 40 667 52 44 667 52 44 671 55 46 683 56 47 705 57 48 711 58 49 759 62 53 777 66 56 805 71 61 839 73 63 839 73 63 845 77 66 899 81 68 911 82 69 929 83 70 959 87 73 963 88 74 979 89 75} do_execsql_test 5.4.7.1 { SELECT max(c) OVER win, min(c) OVER win, count(a) OVER win FROM t3 WINDOW win AS ( ORDER BY c NULLS FIRST, b NULLS FIRST, a NULLS FIRST ROWS BETWEEN 6 PRECEDING AND UNBOUNDED FOLLOWING EXCLUDE TIES ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 113 81 979 113 82 979 133 80 979 148 79 979 158 77 979 158 78 979 160 77 979 208 76 979 223 75 979 224 74 979 234 73 979 238 72 979 239 71 979 247 70 979 250 69 979 252 68 979 256 67 979 257 66 979 295 65 979 309 64 979 330 63 979 335 62 979 336 61 979 346 60 979 354 59 979 355 58 979 355 58 979 393 56 979 393 57 979 398 55 979 399 54 979 399 54 979 412 53 979 421 52 979 430 51 979 443 50 979 480 48 979 480 49 979 572 47 979 574 46 979 607 45 979 618 43 979 618 44 979 627 42 979 629 41 979 629 41 979 633 40 979 634 39 979 652 38 979 660 37 979 667 36 979 667 36 979 670 35 979 671 34 979 683 33 979 705 32 979 711 31 979 716 30 979 726 29 979 730 28 979 759 27 979 762 26 979 768 24 979 768 25 979 777 23 979 786 22 979 790 21 979 792 20 979 794 19 979 805 18 979 822 17 979 839 15 979 839 16 979 840 14 979 844 13 979 845 12 979 870 10 979 870 11 979 870 11 979 899 9 979 911 8 979 929 7} do_execsql_test 5.4.7.2 { SELECT sum(c) FILTER (WHERE (c%2)!=0) OVER win, rank() OVER win, dense_rank() OVER win FROM t3 WINDOW win AS ( ORDER BY c NULLS FIRST, b NULLS FIRST, a NULLS FIRST ROWS BETWEEN 6 PRECEDING AND UNBOUNDED FOLLOWING EXCLUDE TIES ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {3830 89 89 4741 88 88 5640 84 84 5640 85 85 5640 86 86 5640 87 87 6485 81 81 6485 82 82 6485 83 83 7324 80 80 8163 78 78 8163 79 79 8968 73 73 8968 74 74 8968 75 75 8968 76 76 8968 77 77 9745 69 69 9745 70 70 9745 71 71 9745 72 72 10504 65 65 10504 66 66 10504 67 67 10504 68 68 11215 64 64 11920 63 63 12603 62 62 13274 60 60 13274 61 61 13941 59 59 14608 55 55 14608 56 56 14608 57 57 14608 58 58 15241 54 54 15870 53 53 16499 52 52 17126 49 49 17126 50 50 17126 51 51 17733 44 44 17733 45 45 17733 46 46 17733 47 47 17733 48 48 18176 42 42 18176 43 43 18597 40 40 18597 41 41 18996 39 39 19395 37 37 19395 38 38 19788 36 36 20181 35 35 20536 34 34 20891 30 30 20891 31 31 20891 32 32 20891 33 33 21226 28 28 21226 29 29 21535 27 27 21830 26 26 22087 22 22 22087 23 23 22087 24 24 22087 25 25 22334 21 21 22573 17 17 22573 18 18 22573 19 19 22573 20 20 22796 11 11 22796 12 12 22796 13 13 22796 14 14 22796 15 15 22796 16 16 22929 10 10 23042 9 9 23155 1 1 23155 2 2 23155 3 3 23155 4 4 23155 5 5 23155 6 6 23155 7 7 23155 8 8} do_execsql_test 5.4.8.1 { SELECT max(c) OVER win, min(c) OVER win, count(a) OVER win FROM t3 WINDOW win AS ( RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING EXCLUDE TIES ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {102 102 1 113 113 1 113 113 1 133 133 1 148 148 1 158 158 0 158 158 1 160 160 1 208 208 1 223 223 1 224 224 1 234 234 1 238 238 1 239 239 1 247 247 1 250 250 1 252 252 1 256 256 1 257 257 1 295 295 1 309 309 1 330 330 1 335 335 1 336 336 1 346 346 1 354 354 1 355 355 0 355 355 1 393 393 1 393 393 1 398 398 1 399 399 0 399 399 1 412 412 1 421 421 1 430 430 1 443 443 1 480 480 1 480 480 1 572 572 1 574 574 1 607 607 1 618 618 1 618 618 1 627 627 1 629 629 0 629 629 1 633 633 1 634 634 1 652 652 1 660 660 1 667 667 0 667 667 1 670 670 1 671 671 1 683 683 1 705 705 1 711 711 1 716 716 1 726 726 1 730 730 1 759 759 1 762 762 1 768 768 1 768 768 1 777 777 1 786 786 1 790 790 1 792 792 1 794 794 1 805 805 1 822 822 1 839 839 1 839 839 1 840 840 1 844 844 1 845 845 1 870 870 0 870 870 1 870 870 1 899 899 1 911 911 1 929 929 1 934 934 1 938 938 1 938 938 1 959 959 1 963 963 1 979 979 1} do_execsql_test 5.4.8.2 { SELECT sum(c) FILTER (WHERE (c%2)!=0) OVER win, rank() OVER win, dense_rank() OVER win FROM t3 WINDOW win AS ( RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING EXCLUDE TIES ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {{} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 113 1 1 113 1 1 133 1 1 223 1 1 239 1 1 247 1 1 257 1 1 295 1 1 309 1 1 335 1 1 355 1 1 355 1 1 393 1 1 393 1 1 399 1 1 399 1 1 421 1 1 443 1 1 607 1 1 627 1 1 629 1 1 629 1 1 633 1 1 667 1 1 667 1 1 671 1 1 683 1 1 705 1 1 711 1 1 759 1 1 777 1 1 805 1 1 839 1 1 839 1 1 845 1 1 899 1 1 911 1 1 929 1 1 959 1 1 963 1 1 979 1 1} do_execsql_test 5.4.9.1 { SELECT max(c) OVER win, min(c) OVER win, count(a) OVER win FROM t3 WINDOW win AS ( ORDER BY a NULLS LAST RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING EXCLUDE TIES ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {158 158 0 355 355 0 399 399 0 629 629 0 667 667 0 870 113 1 870 158 1 870 158 1 870 158 1 870 158 1 870 158 1 870 158 1 870 158 1 870 870 0 899 113 10 899 113 10 899 113 10 899 113 10 899 113 10 899 113 10 899 113 10 899 113 17 899 113 17 899 113 17 899 113 17 899 113 17 899 113 17 899 113 17 899 158 1 963 113 17 979 102 34 979 102 45 979 102 45 979 102 45 979 102 45 979 102 45 979 102 50 979 102 50 979 102 50 979 102 50 979 102 50 979 102 50 979 102 50 979 102 57 979 102 57 979 102 57 979 102 57 979 102 57 979 102 57 979 102 63 979 102 63 979 102 63 979 102 63 979 102 63 979 102 63 979 102 63 979 102 63 979 102 63 979 102 63 979 102 63 979 102 63 979 102 63 979 102 76 979 102 76 979 102 76 979 102 76 979 102 76 979 102 76 979 102 76 979 102 76 979 113 17 979 113 26 979 113 26 979 113 26 979 113 26 979 113 26 979 113 26 979 113 26 979 113 26 979 113 34 979 113 34 979 113 34 979 113 34 979 113 34 979 113 34 979 113 34 979 113 34 979 113 34 979 113 34} do_execsql_test 5.4.9.2 { SELECT sum(c) FILTER (WHERE (c%2)!=0) OVER win, rank() OVER win, dense_rank() OVER win FROM t3 WINDOW win AS ( ORDER BY a NULLS LAST RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING EXCLUDE TIES ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {{} 84 11 {} 84 11 355 84 11 399 84 11 629 84 11 667 84 11 2050 75 10 2050 75 10 2050 75 10 2050 75 10 2163 75 10 2307 75 10 2889 75 10 2889 75 10 2949 75 10 4997 68 9 4997 68 9 4997 68 9 5418 68 9 5440 68 9 5668 68 9 5802 68 9 7337 59 8 7337 59 8 7337 59 8 7337 59 8 7470 59 8 7692 59 8 8020 59 8 8300 59 8 8316 59 8 10450 51 7 10450 51 7 10450 51 7 10450 51 7 10450 51 7 10450 51 7 10785 51 7 11379 51 7 11714 40 6 11714 40 6 11714 40 6 11714 40 6 11714 40 6 11714 40 6 11714 40 6 11714 40 6 11714 40 6 12009 40 6 12381 40 6 12676 35 5 12676 35 5 12789 35 5 13305 35 5 13453 35 5 14195 28 4 14195 28 4 14195 28 4 14195 28 4 14195 28 4 15040 28 4 15154 28 4 15999 22 3 15999 22 3 15999 22 3 15999 22 3 16606 22 3 16758 22 3 17365 9 2 17365 9 2 17365 9 2 17365 9 2 17365 9 2 17365 9 2 17612 9 2 17758 9 2 17758 9 2 17764 9 2 17998 9 2 18070 9 2 18076 9 2 20846 1 1 20846 1 1 20846 1 1 21069 1 1 21085 1 1 21155 1 1 21473 1 1 21757 1 1} do_execsql_test 5.4.10.1 { SELECT max(c) OVER win, min(c) OVER win, count(a) OVER win FROM t3 WINDOW win AS ( PARTITION BY coalesce(a, '') RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING EXCLUDE TIES ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {102 102 1 113 113 1 113 113 1 133 133 1 148 148 1 158 158 0 158 158 1 160 160 1 208 208 1 223 223 1 224 224 1 234 234 1 238 238 1 239 239 1 247 247 1 250 250 1 252 252 1 256 256 1 257 257 1 295 295 1 309 309 1 330 330 1 335 335 1 336 336 1 346 346 1 354 354 1 355 355 0 355 355 1 393 393 1 393 393 1 398 398 1 399 399 0 399 399 1 412 412 1 421 421 1 430 430 1 443 443 1 480 480 1 480 480 1 572 572 1 574 574 1 607 607 1 618 618 1 618 618 1 627 627 1 629 629 0 629 629 1 633 633 1 634 634 1 652 652 1 660 660 1 667 667 0 667 667 1 670 670 1 671 671 1 683 683 1 705 705 1 711 711 1 716 716 1 726 726 1 730 730 1 759 759 1 762 762 1 768 768 1 768 768 1 777 777 1 786 786 1 790 790 1 792 792 1 794 794 1 805 805 1 822 822 1 839 839 1 839 839 1 840 840 1 844 844 1 845 845 1 870 870 0 870 870 1 870 870 1 899 899 1 911 911 1 929 929 1 934 934 1 938 938 1 938 938 1 959 959 1 963 963 1 979 979 1} do_execsql_test 5.4.10.2 { SELECT sum(c) FILTER (WHERE (c%2)!=0) OVER win, rank() OVER win, dense_rank() OVER win FROM t3 WINDOW win AS ( PARTITION BY coalesce(a, '') RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING EXCLUDE TIES ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {{} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 113 1 1 113 1 1 133 1 1 223 1 1 239 1 1 247 1 1 257 1 1 295 1 1 309 1 1 335 1 1 355 1 1 355 1 1 393 1 1 393 1 1 399 1 1 399 1 1 421 1 1 443 1 1 607 1 1 627 1 1 629 1 1 629 1 1 633 1 1 667 1 1 667 1 1 671 1 1 683 1 1 705 1 1 711 1 1 759 1 1 777 1 1 805 1 1 839 1 1 839 1 1 845 1 1 899 1 1 911 1 1 929 1 1 959 1 1 963 1 1 979 1 1} do_execsql_test 5.4.11.1 { SELECT max(c) OVER win, min(c) OVER win, count(a) OVER win FROM t3 WINDOW win AS ( ORDER BY a NULLS LAST GROUPS 6 PRECEDING EXCLUDE TIES ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {223 223 1 239 239 1 309 309 1 572 572 1 627 627 1 870 870 1 911 911 1 934 158 22 934 158 28 934 158 28 934 158 28 934 158 28 934 158 28 934 158 28 934 223 9 934 223 9 934 223 9 934 223 9 934 223 9 934 223 9 934 223 9 934 223 9 934 223 9 934 223 9 934 223 9 934 223 9 934 223 9 934 223 22 934 223 22 934 223 22 934 223 22 934 223 22 934 934 1 959 102 40 959 102 51 959 102 51 959 102 51 959 102 51 959 102 51 959 102 51 959 102 51 959 102 51 959 102 51 959 102 51 959 102 51 959 102 51 959 102 51 959 102 51 959 102 51 959 113 35 959 113 40 959 113 40 959 113 40 959 113 40 959 113 40 959 113 40 959 113 40 959 113 40 959 113 40 959 113 40 959 158 28 959 158 35 959 158 35 959 158 35 959 158 35 963 102 51 979 102 47 979 102 47 979 102 47 979 102 47 979 102 47 979 102 47 979 102 47 979 102 48 979 102 48 979 102 48 979 102 48 979 102 48 979 102 48 979 102 48 979 102 48 979 102 48 979 102 49 979 102 49 979 102 49 979 102 49 979 102 49 979 102 49 979 102 51} do_execsql_test 5.4.11.2 { SELECT sum(c) FILTER (WHERE (c%2)!=0) OVER win, rank() OVER win, dense_rank() OVER win FROM t3 WINDOW win AS ( ORDER BY a NULLS LAST GROUPS 6 PRECEDING EXCLUDE TIES ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {{} 1 1 {} 1 1 {} 1 1 223 1 1 239 1 1 309 1 1 627 1 1 911 1 1 2309 9 2 2309 9 2 2309 9 2 2309 9 2 2309 9 2 2309 9 2 2556 9 2 2702 9 2 2702 9 2 2708 9 2 2942 9 2 3014 9 2 3020 9 2 5790 22 3 5790 22 3 5790 22 3 5790 22 3 6397 22 3 6549 22 3 7156 28 4 7156 28 4 7156 28 4 7156 28 4 7156 28 4 8001 28 4 8115 28 4 8960 35 5 8960 35 5 9073 35 5 9589 35 5 9737 35 5 10028 68 9 10028 68 9 10028 68 9 10396 59 8 10396 59 8 10396 59 8 10396 59 8 10449 68 9 10471 68 9 10479 40 6 10479 40 6 10479 40 6 10479 40 6 10479 40 6 10479 40 6 10479 40 6 10479 40 6 10479 40 6 10529 59 8 10699 68 9 10751 59 8 10774 40 6 10833 68 9 11002 75 10 11002 75 10 11002 75 10 11002 75 10 11079 59 8 11115 75 10 11146 40 6 11259 75 10 11359 59 8 11375 59 8 11441 51 7 11441 51 7 11441 51 7 11441 51 7 11441 51 7 11441 51 7 11776 51 7 11841 75 10 11841 75 10 11901 75 10 12145 84 11 12145 84 11 12370 51 7 12500 84 11 12544 84 11 12774 84 11 12812 84 11} do_execsql_test 5.4.12.1 { SELECT max(c) OVER win, min(c) OVER win, count(a) OVER win FROM t3 WINDOW win AS ( ORDER BY c NULLS LAST RANGE BETWEEN 6 PRECEDING AND 7 FOLLOWING EXCLUDE TIES ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {102 102 1 113 113 1 113 113 1 133 133 1 148 148 1 160 158 1 160 158 2 160 158 2 208 208 1 224 223 2 224 223 2 239 234 3 239 234 3 239 234 3 252 247 3 257 247 5 257 247 5 257 250 4 257 252 3 295 295 1 309 309 1 336 330 3 336 330 3 336 330 3 346 346 1 355 354 1 355 354 2 355 354 2 399 393 3 399 393 3 399 393 3 399 393 4 399 393 4 412 412 1 421 421 1 430 430 1 443 443 1 480 480 1 480 480 1 574 572 2 574 572 2 607 607 1 618 618 1 618 618 1 634 627 3 634 627 4 634 627 4 634 627 4 634 629 3 652 652 1 667 660 2 671 667 2 671 667 3 671 667 3 671 667 3 683 683 1 711 705 2 716 705 3 716 711 2 730 726 2 730 726 2 762 759 2 768 759 4 768 762 2 768 762 2 777 777 1 792 786 3 794 786 4 794 786 4 794 790 3 805 805 1 822 822 1 845 839 4 845 839 4 845 839 5 845 839 5 845 839 5 870 870 0 870 870 1 870 870 1 899 899 1 911 911 1 934 929 2 938 929 4 938 934 2 938 934 2 963 959 2 963 959 2 979 979 1} do_execsql_test 5.4.12.2 { SELECT sum(c) FILTER (WHERE (c%2)!=0) OVER win, rank() OVER win, dense_rank() OVER win FROM t3 WINDOW win AS ( ORDER BY c NULLS LAST RANGE BETWEEN 6 PRECEDING AND 7 FOLLOWING EXCLUDE TIES ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {{} 1 1 {} 5 4 {} 6 5 {} 6 5 {} 8 6 {} 9 7 {} 25 23 {} 34 29 {} 36 31 {} 38 33 {} 38 33 {} 40 34 {} 41 35 {} 43 37 {} 43 37 {} 50 42 {} 60 51 {} 61 52 {} 64 55 {} 64 55 {} 67 57 {} 68 58 {} 69 59 {} 70 60 {} 72 62 {} 78 67 {} 78 67 {} 78 67 {} 85 72 {} 85 72 113 2 2 113 2 2 133 4 3 223 10 8 223 11 9 239 12 10 239 13 11 239 14 12 247 15 13 257 18 16 257 19 17 295 20 18 309 21 19 335 22 20 335 23 21 335 24 22 355 27 25 355 27 25 421 35 30 443 37 32 504 16 14 504 17 15 607 42 36 683 56 47 710 26 24 711 59 50 759 62 53 759 63 54 777 66 56 805 71 61 899 81 68 911 82 69 929 83 70 929 84 71 979 89 75 1185 32 28 1185 32 28 1191 29 26 1191 29 26 1334 51 43 1338 52 44 1338 52 44 1416 57 48 1416 58 49 1584 31 27 1684 73 63 1684 73 63 1889 46 39 1889 46 39 1891 49 41 1922 87 73 1922 88 74 2005 54 45 2005 55 46 2518 45 38 2518 48 40 2523 75 64 2523 76 65 2523 77 66} do_execsql_test 5.4.13.1 { SELECT max(c) OVER win, min(c) OVER win, count(a) OVER win FROM t3 WINDOW win AS ( ORDER BY c NULLS LAST RANGE BETWEEN 0 PRECEDING AND 0 FOLLOWING EXCLUDE TIES ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {102 102 1 113 113 1 113 113 1 133 133 1 148 148 1 158 158 0 158 158 1 160 160 1 208 208 1 223 223 1 224 224 1 234 234 1 238 238 1 239 239 1 247 247 1 250 250 1 252 252 1 256 256 1 257 257 1 295 295 1 309 309 1 330 330 1 335 335 1 336 336 1 346 346 1 354 354 1 355 355 0 355 355 1 393 393 1 393 393 1 398 398 1 399 399 0 399 399 1 412 412 1 421 421 1 430 430 1 443 443 1 480 480 1 480 480 1 572 572 1 574 574 1 607 607 1 618 618 1 618 618 1 627 627 1 629 629 0 629 629 1 633 633 1 634 634 1 652 652 1 660 660 1 667 667 0 667 667 1 670 670 1 671 671 1 683 683 1 705 705 1 711 711 1 716 716 1 726 726 1 730 730 1 759 759 1 762 762 1 768 768 1 768 768 1 777 777 1 786 786 1 790 790 1 792 792 1 794 794 1 805 805 1 822 822 1 839 839 1 839 839 1 840 840 1 844 844 1 845 845 1 870 870 0 870 870 1 870 870 1 899 899 1 911 911 1 929 929 1 934 934 1 938 938 1 938 938 1 959 959 1 963 963 1 979 979 1} do_execsql_test 5.4.13.2 { SELECT sum(c) FILTER (WHERE (c%2)!=0) OVER win, rank() OVER win, dense_rank() OVER win FROM t3 WINDOW win AS ( ORDER BY c NULLS LAST RANGE BETWEEN 0 PRECEDING AND 0 FOLLOWING EXCLUDE TIES ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {{} 1 1 {} 5 4 {} 6 5 {} 6 5 {} 8 6 {} 9 7 {} 11 9 {} 12 10 {} 13 11 {} 16 14 {} 17 15 {} 18 16 {} 22 20 {} 24 22 {} 25 23 {} 26 24 {} 31 27 {} 34 29 {} 36 31 {} 38 33 {} 38 33 {} 40 34 {} 41 35 {} 43 37 {} 43 37 {} 49 41 {} 50 42 {} 51 43 {} 54 45 {} 59 50 {} 60 51 {} 61 52 {} 63 54 {} 64 55 {} 64 55 {} 67 57 {} 68 58 {} 69 59 {} 70 60 {} 72 62 {} 75 64 {} 76 65 {} 78 67 {} 78 67 {} 78 67 {} 84 71 {} 85 72 {} 85 72 113 2 2 113 2 2 133 4 3 223 10 8 239 14 12 247 15 13 257 19 17 295 20 18 309 21 19 335 23 21 355 27 25 355 27 25 393 29 26 393 29 26 399 32 28 399 32 28 421 35 30 443 37 32 607 42 36 627 45 38 629 46 39 629 46 39 633 48 40 667 52 44 667 52 44 671 55 46 683 56 47 705 57 48 711 58 49 759 62 53 777 66 56 805 71 61 839 73 63 839 73 63 845 77 66 899 81 68 911 82 69 929 83 70 959 87 73 963 88 74 979 89 75} do_execsql_test 5.4.14.1 { SELECT max(c) OVER win, min(c) OVER win, count(a) OVER win FROM t3 WINDOW win AS ( ORDER BY c NULLS LAST, b NULLS LAST, a NULLS LAST ROWS BETWEEN 6 PRECEDING AND UNBOUNDED FOLLOWING EXCLUDE TIES ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 113 81 979 113 82 979 133 80 979 148 79 979 158 77 979 158 78 979 160 77 979 208 76 979 223 75 979 224 74 979 234 73 979 238 72 979 239 71 979 247 70 979 250 69 979 252 68 979 256 67 979 257 66 979 295 65 979 309 64 979 330 63 979 335 62 979 336 61 979 346 60 979 354 59 979 355 57 979 355 58 979 393 56 979 393 57 979 398 55 979 399 53 979 399 54 979 412 53 979 421 52 979 430 51 979 443 50 979 480 48 979 480 49 979 572 47 979 574 46 979 607 45 979 618 43 979 618 44 979 627 42 979 629 40 979 629 41 979 633 40 979 634 39 979 652 38 979 660 37 979 667 35 979 667 36 979 670 35 979 671 34 979 683 33 979 705 32 979 711 31 979 716 30 979 726 29 979 730 28 979 759 27 979 762 26 979 768 24 979 768 25 979 777 23 979 786 22 979 790 21 979 792 20 979 794 19 979 805 18 979 822 17 979 839 15 979 839 16 979 840 14 979 844 13 979 845 12 979 870 9 979 870 10 979 870 11 979 899 9 979 911 8 979 929 7} do_execsql_test 5.4.14.2 { SELECT sum(c) FILTER (WHERE (c%2)!=0) OVER win, rank() OVER win, dense_rank() OVER win FROM t3 WINDOW win AS ( ORDER BY c NULLS LAST, b NULLS LAST, a NULLS LAST ROWS BETWEEN 6 PRECEDING AND UNBOUNDED FOLLOWING EXCLUDE TIES ) ORDER BY 1 NULLS FIRST, 2 NULLS FIRST, 3 NULLS FIRST } {3830 89 89 4741 88 88 5640 84 84 5640 85 85 5640 86 86 5640 87 87 6485 81 81 6485 82 82 6485 83 83 7324 80 80 8163 78 78 8163 79 79 8968 73 73 8968 74 74 8968 75 75 8968 76 76 8968 77 77 9745 69 69 9745 70 70 9745 71 71 9745 72 72 10504 65 65 10504 66 66 10504 67 67 10504 68 68 11215 64 64 11920 63 63 12603 62 62 13274 60 60 13274 61 61 13941 59 59 14608 55 55 14608 56 56 14608 57 57 14608 58 58 15241 54 54 15870 53 53 16499 52 52 17126 49 49 17126 50 50 17126 51 51 17733 44 44 17733 45 45 17733 46 46 17733 47 47 17733 48 48 18176 42 42 18176 43 43 18597 40 40 18597 41 41 18996 39 39 19395 37 37 19395 38 38 19788 36 36 20181 35 35 20536 34 34 20891 30 30 20891 31 31 20891 32 32 20891 33 33 21226 28 28 21226 29 29 21535 27 27 21830 26 26 22087 22 22 22087 23 23 22087 24 24 22087 25 25 22334 21 21 22573 17 17 22573 18 18 22573 19 19 22573 20 20 22796 11 11 22796 12 12 22796 13 13 22796 14 14 22796 15 15 22796 16 16 22929 10 10 23042 9 9 23155 1 1 23155 2 2 23155 3 3 23155 4 4 23155 5 5 23155 6 6 23155 7 7 23155 8 8} #========================================================================== do_execsql_test 6.0 { DROP TABLE IF EXISTS t2; CREATE TABLE t2(a TEXT, b INTEGER); INSERT INTO t2 VALUES('A', NULL); INSERT INTO t2 VALUES('B', NULL); INSERT INTO t2 VALUES('C', 1); } {} do_execsql_test 6.1 { SELECT group_concat(a, '.') OVER ( ORDER BY b NULLS FIRST RANGE BETWEEN 7 PRECEDING AND 2 PRECEDING ) FROM t2 } {A.B A.B {}} do_execsql_test 6.2 { SELECT group_concat(a, '.') OVER ( ORDER BY b DESC NULLS LAST RANGE BETWEEN 7 PRECEDING AND 2 PRECEDING ) FROM t2 } {{} A.B A.B} #========================================================================== do_execsql_test 7.0 { DROP TABLE IF EXISTS t2; CREATE TABLE t2(a INTEGER, b INTEGER); INSERT INTO t2 VALUES(1, 65); INSERT INTO t2 VALUES(2, NULL); INSERT INTO t2 VALUES(3, NULL); INSERT INTO t2 VALUES(4, NULL); INSERT INTO t2 VALUES(5, 66); INSERT INTO t2 VALUES(6, 67); } {} do_execsql_test 7.1.1 { SELECT sum (a) OVER win FROM t2 WINDOW win AS ( ORDER BY b NULLS LAST RANGE BETWEEN 6 FOLLOWING AND UNBOUNDED FOLLOWING ); } {9 9 9 9 9 9} do_execsql_test 7.1.2 { SELECT sum (a) OVER win FROM t2 WINDOW win AS ( ORDER BY b NULLS LAST RANGE BETWEEN 1 PRECEDING AND 2 PRECEDING ); } {{} {} {} 9 9 9} do_execsql_test 7.1.3 { SELECT sum (a) OVER win FROM t2 WINDOW win AS ( ORDER BY b NULLS LAST RANGE BETWEEN 2 FOLLOWING AND 1 FOLLOWING ); } {{} {} {} 9 9 9} do_execsql_test 7.1.4 { SELECT sum (a) OVER win FROM t2 WINDOW win AS ( ORDER BY b NULLS FIRST RANGE BETWEEN 1 PRECEDING AND 2 PRECEDING ); } {9 9 9 {} {} {}} do_execsql_test 7.1.5 { SELECT sum (a) OVER win FROM t2 WINDOW win AS ( ORDER BY b NULLS FIRST RANGE BETWEEN 2 FOLLOWING AND 1 FOLLOWING ); } {9 9 9 {} {} {}} do_execsql_test 7.1.6 { SELECT sum (a) OVER win FROM t2 WINDOW win AS ( ORDER BY b NULLS LAST RANGE BETWEEN 1000 PRECEDING AND 2 PRECEDING ); } {{} {} 1 9 9 9} do_execsql_test 7.1.7 { SELECT sum (a) OVER win FROM t2 WINDOW win AS ( ORDER BY b NULLS LAST RANGE BETWEEN 2000 FOLLOWING AND 1000 FOLLOWING ); } {{} {} {} 9 9 9} do_execsql_test 7.1.8 { SELECT sum (a) OVER win FROM t2 WINDOW win AS ( ORDER BY b NULLS FIRST RANGE BETWEEN 1000 PRECEDING AND 2000 PRECEDING ); } {9 9 9 {} {} {}} do_execsql_test 7.1.9 { SELECT sum (a) OVER win FROM t2 WINDOW win AS ( ORDER BY b NULLS FIRST RANGE BETWEEN 2000 FOLLOWING AND 1000 FOLLOWING ); } {9 9 9 {} {} {}} do_execsql_test 7.2.1 { SELECT min (a) OVER win FROM t2 WINDOW win AS ( ORDER BY b NULLS LAST RANGE BETWEEN 6 FOLLOWING AND UNBOUNDED FOLLOWING ); } {2 2 2 2 2 2} do_execsql_test 7.2.2 { SELECT min (a) OVER win FROM t2 WINDOW win AS ( ORDER BY b NULLS LAST RANGE BETWEEN 1 PRECEDING AND 2 PRECEDING ); } {{} {} {} 2 2 2} do_execsql_test 7.2.3 { SELECT min (a) OVER win FROM t2 WINDOW win AS ( ORDER BY b NULLS LAST RANGE BETWEEN 2 FOLLOWING AND 1 FOLLOWING ); } {{} {} {} 2 2 2} do_execsql_test 7.2.4 { SELECT min (a) OVER win FROM t2 WINDOW win AS ( ORDER BY b NULLS FIRST RANGE BETWEEN 1 PRECEDING AND 2 PRECEDING ); } {2 2 2 {} {} {}} do_execsql_test 7.2.5 { SELECT min (a) OVER win FROM t2 WINDOW win AS ( ORDER BY b NULLS FIRST RANGE BETWEEN 2 FOLLOWING AND 1 FOLLOWING ); } {2 2 2 {} {} {}} do_execsql_test 7.2.6 { SELECT min (a) OVER win FROM t2 WINDOW win AS ( ORDER BY b NULLS LAST RANGE BETWEEN 1000 PRECEDING AND 2 PRECEDING ); } {{} {} 1 2 2 2} do_execsql_test 7.2.7 { SELECT min (a) OVER win FROM t2 WINDOW win AS ( ORDER BY b NULLS LAST RANGE BETWEEN 2000 FOLLOWING AND 1000 FOLLOWING ); } {{} {} {} 2 2 2} do_execsql_test 7.2.8 { SELECT min (a) OVER win FROM t2 WINDOW win AS ( ORDER BY b NULLS FIRST RANGE BETWEEN 1000 PRECEDING AND 2000 PRECEDING ); } {2 2 2 {} {} {}} do_execsql_test 7.2.9 { SELECT min (a) OVER win FROM t2 WINDOW win AS ( ORDER BY b NULLS FIRST RANGE BETWEEN 2000 FOLLOWING AND 1000 FOLLOWING ); } {2 2 2 {} {} {}} do_execsql_test 7.3.1 { SELECT sum (a) OVER win FROM t2 WINDOW win AS ( ORDER BY b NULLS LAST RANGE BETWEEN 6 FOLLOWING AND UNBOUNDED FOLLOWING ); } {9 9 9 9 9 9} do_execsql_test 7.3.2 { SELECT sum (a) OVER win FROM t2 WINDOW win AS ( ORDER BY b NULLS LAST RANGE BETWEEN 1 PRECEDING AND 2 PRECEDING ); } {{} {} {} 9 9 9} do_execsql_test 7.3.3 { SELECT sum (a) OVER win FROM t2 WINDOW win AS ( ORDER BY b NULLS LAST RANGE BETWEEN 2 FOLLOWING AND 1 FOLLOWING ); } {{} {} {} 9 9 9} do_execsql_test 7.3.4 { SELECT sum (a) OVER win FROM t2 WINDOW win AS ( ORDER BY b NULLS FIRST RANGE BETWEEN 1 PRECEDING AND 2 PRECEDING ); } {9 9 9 {} {} {}} do_execsql_test 7.3.5 { SELECT sum (a) OVER win FROM t2 WINDOW win AS ( ORDER BY b NULLS FIRST RANGE BETWEEN 2 FOLLOWING AND 1 FOLLOWING ); } {9 9 9 {} {} {}} do_execsql_test 7.3.6 { SELECT sum (a) OVER win FROM t2 WINDOW win AS ( ORDER BY b NULLS LAST RANGE BETWEEN 1000 PRECEDING AND 2 PRECEDING ); } {{} {} 1 9 9 9} do_execsql_test 7.3.7 { SELECT sum (a) OVER win FROM t2 WINDOW win AS ( ORDER BY b NULLS LAST RANGE BETWEEN 2000 FOLLOWING AND 1000 FOLLOWING ); } {{} {} {} 9 9 9} do_execsql_test 7.3.8 { SELECT sum (a) OVER win FROM t2 WINDOW win AS ( ORDER BY b NULLS FIRST RANGE BETWEEN 1000 PRECEDING AND 2000 PRECEDING ); } {9 9 9 {} {} {}} do_execsql_test 7.3.9 { SELECT sum (a) OVER win FROM t2 WINDOW win AS ( ORDER BY b NULLS FIRST RANGE BETWEEN 2000 FOLLOWING AND 1000 FOLLOWING ); } {9 9 9 {} {} {}} do_execsql_test 7.4.1 { SELECT max (a) OVER win FROM t2 WINDOW win AS ( ORDER BY b NULLS LAST RANGE BETWEEN 6 FOLLOWING AND UNBOUNDED FOLLOWING ); } {4 4 4 4 4 4} do_execsql_test 7.4.2 { SELECT max (a) OVER win FROM t2 WINDOW win AS ( ORDER BY b NULLS LAST RANGE BETWEEN 1 PRECEDING AND 2 PRECEDING ); } {{} {} {} 4 4 4} do_execsql_test 7.4.3 { SELECT max (a) OVER win FROM t2 WINDOW win AS ( ORDER BY b NULLS LAST RANGE BETWEEN 2 FOLLOWING AND 1 FOLLOWING ); } {{} {} {} 4 4 4} do_execsql_test 7.4.4 { SELECT max (a) OVER win FROM t2 WINDOW win AS ( ORDER BY b NULLS FIRST RANGE BETWEEN 1 PRECEDING AND 2 PRECEDING ); } {4 4 4 {} {} {}} do_execsql_test 7.4.5 { SELECT max (a) OVER win FROM t2 WINDOW win AS ( ORDER BY b NULLS FIRST RANGE BETWEEN 2 FOLLOWING AND 1 FOLLOWING ); } {4 4 4 {} {} {}} do_execsql_test 7.4.6 { SELECT max (a) OVER win FROM t2 WINDOW win AS ( ORDER BY b NULLS LAST RANGE BETWEEN 1000 PRECEDING AND 2 PRECEDING ); } {{} {} 1 4 4 4} do_execsql_test 7.4.7 { SELECT max (a) OVER win FROM t2 WINDOW win AS ( ORDER BY b NULLS LAST RANGE BETWEEN 2000 FOLLOWING AND 1000 FOLLOWING ); } {{} {} {} 4 4 4} do_execsql_test 7.4.8 { SELECT max (a) OVER win FROM t2 WINDOW win AS ( ORDER BY b NULLS FIRST RANGE BETWEEN 1000 PRECEDING AND 2000 PRECEDING ); } {4 4 4 {} {} {}} do_execsql_test 7.4.9 { SELECT max (a) OVER win FROM t2 WINDOW win AS ( ORDER BY b NULLS FIRST RANGE BETWEEN 2000 FOLLOWING AND 1000 FOLLOWING ); } {4 4 4 {} {} {}} #========================================================================== do_execsql_test 8.0 { DROP TABLE IF EXISTS tx; CREATE TABLE tx(a INTEGER PRIMARY KEY); INSERT INTO tx VALUES(1), (2), (3), (4), (5), (6); DROP TABLE IF EXISTS map; CREATE TABLE map(v INTEGER PRIMARY KEY, t TEXT); INSERT INTO map VALUES (1, 'odd'), (2, 'even'), (3, 'odd'), (4, 'even'), (5, 'odd'), (6, 'even'); } {} do_execsql_test 8.1 { SELECT sum(a) OVER ( PARTITION BY ( SELECT t FROM map WHERE v=a ) ORDER BY a ) FROM tx; } {2 6 12 1 4 9} do_execsql_test 8.2 { SELECT sum(a) OVER win FROM tx WINDOW win AS ( PARTITION BY ( SELECT t FROM map WHERE v=a ) ORDER BY a ); } {2 6 12 1 4 9} do_execsql_test 8.3 { WITH map2 AS ( SELECT * FROM map ) SELECT sum(a) OVER ( PARTITION BY ( SELECT t FROM map2 WHERE v=a ) ORDER BY a ) FROM tx; } {2 6 12 1 4 9} do_execsql_test 8.4 { WITH map2 AS ( SELECT * FROM map ) SELECT sum(a) OVER win FROM tx WINDOW win AS ( PARTITION BY ( SELECT t FROM map2 WHERE v=a ) ORDER BY a ); } {2 6 12 1 4 9} #========================================================================== do_execsql_test 9.1 { DROP TABLE IF EXISTS t1; DROP TABLE IF EXISTS t2; CREATE TABLE t1(a INTEGER); CREATE TABLE t2(y INTEGER); } {} do_execsql_test 9.2 { SELECT ( SELECT max(a) OVER ( ORDER BY (SELECT sum(a) FROM t1) ) + min(a) OVER() ) FROM t1 } {} finish_test |
Added test/window9.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 | # 2019 June 8 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix window9 ifcapable !windowfunc { finish_test return } do_execsql_test 1.0 { CREATE TABLE fruits( name TEXT COLLATE NOCASE, color TEXT COLLATE NOCASE ); } do_execsql_test 1.1 { INSERT INTO fruits (name, color) VALUES ('apple', 'RED'); INSERT INTO fruits (name, color) VALUES ('APPLE', 'yellow'); INSERT INTO fruits (name, color) VALUES ('pear', 'YELLOW'); INSERT INTO fruits (name, color) VALUES ('PEAR', 'green'); } do_execsql_test 1.2 { SELECT name, color, dense_rank() OVER (ORDER BY name) FROM fruits; } { apple RED 1 APPLE yellow 1 pear YELLOW 2 PEAR green 2 } do_execsql_test 1.3 { SELECT name, color, dense_rank() OVER (PARTITION BY name ORDER BY color) FROM fruits; } { apple RED 1 APPLE yellow 2 PEAR green 1 pear YELLOW 2 } do_execsql_test 1.4 { SELECT name, color, dense_rank() OVER (ORDER BY name), dense_rank() OVER (PARTITION BY name ORDER BY color) FROM fruits; } { apple RED 1 1 APPLE yellow 1 2 PEAR green 2 1 pear YELLOW 2 2 } do_execsql_test 1.5 { SELECT name, color, dense_rank() OVER (ORDER BY name), dense_rank() OVER (PARTITION BY name ORDER BY color) FROM fruits ORDER BY color; } { PEAR green 2 1 apple RED 1 1 APPLE yellow 1 2 pear YELLOW 2 2 } do_execsql_test 2.0 { CREATE TABLE t1(a BLOB, b INTEGER, c COLLATE nocase); INSERT INTO t1 VALUES(1, 2, 'abc'); INSERT INTO t1 VALUES(3, 4, 'ABC'); } do_execsql_test 2.1.1 { SELECT c=='Abc' FROM t1 } {1 1} do_execsql_test 2.1.2 { SELECT c=='Abc', rank() OVER (ORDER BY b) FROM t1 } {1 1 1 2} do_execsql_test 2.2.1 { SELECT b=='2' FROM t1 } {1 0} do_execsql_test 2.2.2 { SELECT b=='2', rank() OVER (ORDER BY a) FROM t1 } {1 1 0 2} #------------------------------------------------------------------------- reset_db do_execsql_test 3.0 { CREATE TABLE t1(a); CREATE TABLE t2(a,b,c); } do_execsql_test 3.1 { SELECT EXISTS(SELECT 1 FROM t1 ORDER BY sum(a) OVER ()) FROM t1; } do_execsql_test 3.2 { SELECT sum(a) OVER () FROM t2 ORDER BY EXISTS(SELECT 1 FROM t2 ORDER BY sum(a) OVER ()); } do_catchsql_test 3.3 { SELECT a, sum(a) OVER (ORDER BY a DESC) FROM t2 ORDER BY EXISTS( SELECT 1 FROM t2 ORDER BY sum(a) OVER (ORDER BY a) ) OVER (ORDER BY a); } {1 {near "OVER": syntax error}} do_catchsql_test 3.4 { SELECT y, y+1, y+2 FROM ( SELECT c IN ( SELECT min(a) OVER (), (abs(row_number() OVER())+22)/19, max(a) OVER () FROM t1 ) AS y FROM t2 ); } {1 {sub-select returns 3 columns - expected 1}} #------------------------------------------------------------------------- reset_db do_execsql_test 4.0 { CREATE TABLE t1(a, b TEXT); INSERT INTO t1 VALUES('A', 1), ('A', 2), ('2', 1), ('2', 2); } do_execsql_test 4.1.1 { SELECT b, b=count(*), '1,2' FROM t1 GROUP BY b; } {1 0 1,2 2 1 1,2} do_execsql_test 4.1.2 { SELECT b, b=count(*), group_concat(b) OVER () FROM t1 GROUP BY b; } {1 0 1,2 2 1 1,2} #-------------------------------------------------------------------------- reset_db do_execsql_test 5.0 { CREATE TABLE t1(a, b, c, d, e); CREATE INDEX i1 ON t1(a, b, c, d, e); } foreach {tn sql} { 1 { SELECT sum(e) OVER (), sum(e) OVER (ORDER BY a), sum(e) OVER (PARTITION BY a ORDER BY b), sum(e) OVER (PARTITION BY a, b ORDER BY c), sum(e) OVER (PARTITION BY a, b, c ORDER BY d) FROM t1; } 2 { SELECT sum(e) OVER (PARTITION BY a ORDER BY b) FROM t1 ORDER BY a; } } { do_test 5.1.$tn { execsql "EXPLAIN QUERY PLAN $sql" } {~/ORDER/} } #------------------------------------------------------------------------- reset_db do_execsql_test 6.0 { CREATE TABLE t0(c0); INSERT INTO t0(c0) VALUES (0); } do_execsql_test 6.1 { SELECT * FROM t0 WHERE EXISTS ( SELECT MIN(c0) OVER (), CUME_DIST() OVER () FROM t0 ) >=1 AND EXISTS ( SELECT MIN(c0) OVER (), CUME_DIST() OVER () FROM t0 ) <=1; } {0} do_execsql_test 6.2 { SELECT * FROM t0 WHERE EXISTS ( SELECT MIN(c0) OVER (), CUME_DIST() OVER () FROM t0 ) BETWEEN 1 AND 1; } {0} #------------------------------------------------------------------------- reset_db do_execsql_test 7.0 { DROP TABLE IF EXISTS t1; CREATE TABLE t1(x, y); INSERT INTO t1 VALUES(10, 1); INSERT INTO t1 VALUES(20, 2); INSERT INTO t1 VALUES(3, 3); INSERT INTO t1 VALUES(2, 4); INSERT INTO t1 VALUES(1, 5); } {} do_execsql_test 7.1 { SELECT avg(x) OVER (ORDER BY y) AS z FROM t1 ORDER BY z } { 7.2 8.75 10.0 11.0 15.0 } do_execsql_test 7.2 { SELECT avg(x) OVER (ORDER BY y) z FROM t1 ORDER BY (z IS y); } { 10.0 15.0 11.0 8.75 7.2 } do_execsql_test 7.3 { SELECT avg(x) OVER (ORDER BY y) z FROM t1 ORDER BY (y IS z); } { 10.0 15.0 11.0 8.75 7.2 } do_execsql_test 7.4 { SELECT avg(x) OVER (ORDER BY y) z FROM t1 ORDER BY z + 0.0; } { 7.2 8.75 10.0 11.0 15.0 } #------------------------------------------------------------------------- reset_db do_execsql_test 8.1.1 { CREATE TABLE t1(a, b); INSERT INTO t1 VALUES(1, 2), (3, 4); SELECT min( sum(a) ) OVER () FROM t1; } {4} do_execsql_test 8.1.2 { SELECT min( sum(a) ) OVER () FROM t1 GROUP BY a; } {1 1} do_execsql_test 8.2 { CREATE VIEW v1 AS SELECT 0 AS x UNION SELECT count() OVER() FROM (SELECT 0) ORDER BY 1 ; } do_catchsql_test 8.3 { SELECT min( max((SELECT x FROM v1)) ) OVER() } {0 0} do_execsql_test 8.4 { SELECT( SELECT x UNION SELECT sum( avg((SELECT x FROM v1)) ) OVER() ) FROM v1; } {0.0 0.0} #-------------------------------------------------------------------------- reset_db do_execsql_test 9.0 { CREATE TABLE t1(a, b, c); INSERT INTO t1 VALUES(NULL,'bb',356); INSERT INTO t1 VALUES('CB','aa',158); INSERT INTO t1 VALUES('BB','aa',399); INSERT INTO t1 VALUES('FF','bb',938); } do_catchsql_test 9.1 { SELECT sum(c) OVER ( ORDER BY c RANGE BETWEEN 0 PRECEDING AND '-700' PRECEDING ) FROM t1 } {1 {frame ending offset must be a non-negative number}} finish_test |
Added test/windowA.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 | # 2019-08-30 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # Test cases for RANGE BETWEEN and especially with NULLS LAST # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix windowA ifcapable !windowfunc { finish_test return } do_execsql_test 1.0 { CREATE TABLE t1(a INTEGER PRIMARY KEY, b CHAR(1), d FLOAT); INSERT INTO t1 VALUES (1, 'A', 5.4), (2, 'B', 5.55), (3, 'C', 8.0), (4, 'D', 10.25), (5, 'E', 10.26), (6, 'N', NULL), (7, 'N', NULL); } {} do_execsql_test 1.1 { SELECT a, b, quote(d), group_concat(b,'') OVER w1 FROM t1 WINDOW w1 AS (ORDER BY d DESC NULLS LAST RANGE BETWEEN 2.50 PRECEDING AND 2.25 FOLLOWING) ORDER BY +d DESC NULLS LAST, +a; } [list \ 5 E 10.26 ED \ 4 D 10.25 EDC \ 3 C 8.0 EDC \ 2 B 5.55 CBA \ 1 A 5.4 BA \ 6 N NULL NN \ 7 N NULL NN \ ] do_execsql_test 1.2 { SELECT a, b, quote(d), group_concat(b,'') OVER w1 FROM t1 WINDOW w1 AS (ORDER BY d DESC NULLS FIRST RANGE BETWEEN 2.50 PRECEDING AND 2.25 FOLLOWING) ORDER BY +d DESC NULLS FIRST, +a; } [list \ 6 N NULL NN \ 7 N NULL NN \ 5 E 10.26 ED \ 4 D 10.25 EDC \ 3 C 8.0 EDC \ 2 B 5.55 CBA \ 1 A 5.4 BA \ ] do_execsql_test 1.3 { SELECT a, b, quote(d), group_concat(b,'') OVER w1 FROM t1 WINDOW w1 AS (ORDER BY d DESC NULLS LAST RANGE BETWEEN 2.50 PRECEDING AND UNBOUNDED FOLLOWING) ORDER BY +d DESC NULLS LAST, +a; } [list \ 5 E 10.26 EDCBANN \ 4 D 10.25 EDCBANN \ 3 C 8.0 EDCBANN \ 2 B 5.55 CBANN \ 1 A 5.4 BANN \ 6 N NULL NN \ 7 N NULL NN \ ] do_execsql_test 1.4 { SELECT a, b, quote(d), group_concat(b,'') OVER w1 FROM t1 WINDOW w1 AS (ORDER BY d DESC NULLS FIRST RANGE BETWEEN 2.50 PRECEDING AND UNBOUNDED FOLLOWING) ORDER BY +d DESC NULLS FIRST, +a; } [list \ 6 N NULL NNEDCBA \ 7 N NULL NNEDCBA \ 5 E 10.26 EDCBA \ 4 D 10.25 EDCBA \ 3 C 8.0 EDCBA \ 2 B 5.55 CBA \ 1 A 5.4 BA \ ] do_execsql_test 1.5 { SELECT a, b, quote(d), group_concat(b,'') OVER w1 FROM t1 WINDOW w1 AS (ORDER BY d DESC NULLS LAST RANGE BETWEEN 2.50 PRECEDING AND CURRENT ROW) ORDER BY +d DESC NULLS LAST, +a; } [list \ 5 E 10.26 E \ 4 D 10.25 ED \ 3 C 8.0 EDC \ 2 B 5.55 CB \ 1 A 5.4 BA \ 6 N NULL NN \ 7 N NULL NN \ ] do_execsql_test 1.6 { SELECT a, b, quote(d), group_concat(b,'') OVER w1 FROM t1 WINDOW w1 AS (ORDER BY d DESC NULLS FIRST RANGE BETWEEN 2.50 PRECEDING AND CURRENT ROW) ORDER BY +d DESC NULLS FIRST, +a; } [list \ 6 N NULL NN \ 7 N NULL NN \ 5 E 10.26 E \ 4 D 10.25 ED \ 3 C 8.0 EDC \ 2 B 5.55 CB \ 1 A 5.4 BA \ ] do_execsql_test 2.1 { SELECT a, b, quote(d), group_concat(b,'') OVER w1 FROM t1 WINDOW w1 AS (ORDER BY d DESC NULLS LAST RANGE BETWEEN UNBOUNDED PRECEDING AND 2.25 FOLLOWING) ORDER BY +d DESC NULLS LAST, +a; } [list \ 5 E 10.26 ED \ 4 D 10.25 EDC \ 3 C 8.0 EDC \ 2 B 5.55 EDCBA \ 1 A 5.4 EDCBA \ 6 N NULL EDCBANN \ 7 N NULL EDCBANN \ ] do_execsql_test 2.2 { SELECT a, b, quote(d), group_concat(b,'') OVER w1 FROM t1 WINDOW w1 AS (ORDER BY d DESC NULLS FIRST RANGE BETWEEN UNBOUNDED PRECEDING AND 2.25 FOLLOWING) ORDER BY +d DESC NULLS FIRST, +a; } [list \ 6 N NULL NN \ 7 N NULL NN \ 5 E 10.26 NNED \ 4 D 10.25 NNEDC \ 3 C 8.0 NNEDC \ 2 B 5.55 NNEDCBA \ 1 A 5.4 NNEDCBA \ ] do_execsql_test 2.3 { SELECT a, b, quote(d), group_concat(b,'') OVER w1 FROM t1 WINDOW w1 AS (ORDER BY d DESC NULLS LAST RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) ORDER BY +d DESC NULLS LAST, +a; } [list \ 5 E 10.26 EDCBANN \ 4 D 10.25 EDCBANN \ 3 C 8.0 EDCBANN \ 2 B 5.55 EDCBANN \ 1 A 5.4 EDCBANN \ 6 N NULL EDCBANN \ 7 N NULL EDCBANN \ ] do_execsql_test 2.4 { SELECT a, b, quote(d), group_concat(b,'') OVER w1 FROM t1 WINDOW w1 AS (ORDER BY d DESC NULLS FIRST RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) ORDER BY +d DESC NULLS FIRST, +a; } [list \ 6 N NULL NNEDCBA \ 7 N NULL NNEDCBA \ 5 E 10.26 NNEDCBA \ 4 D 10.25 NNEDCBA \ 3 C 8.0 NNEDCBA \ 2 B 5.55 NNEDCBA \ 1 A 5.4 NNEDCBA \ ] do_execsql_test 2.5 { SELECT a, b, quote(d), group_concat(b,'') OVER w1 FROM t1 WINDOW w1 AS (ORDER BY d DESC NULLS LAST RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) ORDER BY +d DESC NULLS LAST, +a; } [list \ 5 E 10.26 E \ 4 D 10.25 ED \ 3 C 8.0 EDC \ 2 B 5.55 EDCB \ 1 A 5.4 EDCBA \ 6 N NULL EDCBANN \ 7 N NULL EDCBANN \ ] do_execsql_test 2.6 { SELECT a, b, quote(d), group_concat(b,'') OVER w1 FROM t1 WINDOW w1 AS (ORDER BY d DESC NULLS FIRST RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) ORDER BY +d DESC NULLS FIRST, +a; } [list \ 6 N NULL NN \ 7 N NULL NN \ 5 E 10.26 NNE \ 4 D 10.25 NNED \ 3 C 8.0 NNEDC \ 2 B 5.55 NNEDCB \ 1 A 5.4 NNEDCBA \ ] do_execsql_test 3.1 { SELECT a, b, quote(d), group_concat(b,'') OVER w1 FROM t1 WINDOW w1 AS (ORDER BY d DESC NULLS LAST RANGE BETWEEN CURRENT ROW AND 2.25 FOLLOWING) ORDER BY +d DESC NULLS LAST, +a; } [list \ 5 E 10.26 ED \ 4 D 10.25 DC \ 3 C 8.0 C \ 2 B 5.55 BA \ 1 A 5.4 A \ 6 N NULL NN \ 7 N NULL NN \ ] do_execsql_test 3.2 { SELECT a, b, quote(d), group_concat(b,'') OVER w1 FROM t1 WINDOW w1 AS (ORDER BY d DESC NULLS FIRST RANGE BETWEEN CURRENT ROW AND 2.25 FOLLOWING) ORDER BY +d DESC NULLS FIRST, +a; } [list \ 6 N NULL NN \ 7 N NULL NN \ 5 E 10.26 ED \ 4 D 10.25 DC \ 3 C 8.0 C \ 2 B 5.55 BA \ 1 A 5.4 A \ ] do_execsql_test 3.3 { SELECT a, b, quote(d), group_concat(b,'') OVER w1 FROM t1 WINDOW w1 AS (ORDER BY d DESC NULLS LAST RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) ORDER BY +d DESC NULLS LAST, +a; } [list \ 5 E 10.26 EDCBANN \ 4 D 10.25 DCBANN \ 3 C 8.0 CBANN \ 2 B 5.55 BANN \ 1 A 5.4 ANN \ 6 N NULL NN \ 7 N NULL NN \ ] do_execsql_test 3.4 { SELECT a, b, quote(d), group_concat(b,'') OVER w1 FROM t1 WINDOW w1 AS (ORDER BY d DESC NULLS FIRST RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) ORDER BY +d DESC NULLS FIRST, +a; } [list \ 6 N NULL NNEDCBA \ 7 N NULL NNEDCBA \ 5 E 10.26 EDCBA \ 4 D 10.25 DCBA \ 3 C 8.0 CBA \ 2 B 5.55 BA \ 1 A 5.4 A \ ] do_execsql_test 4.0 { SELECT a, b, quote(d), group_concat(b,'') OVER w1 FROM t1 WINDOW w1 AS (ORDER BY d DESC NULLS FIRST RANGE BETWEEN 2.50 PRECEDING AND 0.5 PRECEDING) ORDER BY +d DESC NULLS FIRST, +a; } [list \ 6 N NULL NN \ 7 N NULL NN \ 5 E 10.26 {} \ 4 D 10.25 {} \ 3 C 8.0 ED \ 2 B 5.55 C \ 1 A 5.4 {} \ ] finish_test |
Added test/windowB.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 | # 2019-08-30 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # Test cases for RANGE BETWEEN and especially with NULLS LAST # and for varying separator handling by group_concat(). # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix windowB ifcapable !windowfunc { finish_test return } do_execsql_test 1.0 { CREATE TABLE t1(a, b); INSERT INTO t1 VALUES(NULL, 1); INSERT INTO t1 VALUES(NULL, 2); INSERT INTO t1 VALUES(NULL, 3); } {} foreach {tn win} { 1 { ORDER BY a RANGE BETWEEN 1 PRECEDING AND 1 FOLLOWING } 2 { ORDER BY a NULLS LAST RANGE BETWEEN 1 PRECEDING AND 1 FOLLOWING } 3 { ORDER BY a DESC RANGE BETWEEN 1 PRECEDING AND 1 FOLLOWING } 4 { ORDER BY a DESC NULLS FIRST RANGE BETWEEN 1 PRECEDING AND 1 FOLLOWING } 5 { ORDER BY a NULLS LAST RANGE BETWEEN 1 FOLLOWING AND 2 FOLLOWING } 6 { ORDER BY a DESC NULLS FIRST RANGE BETWEEN 1 FOLLOWING AND 2 FOLLOWING } 7 { ORDER BY a NULLS LAST RANGE BETWEEN 2 PRECEDING AND 1 PRECEDING } 8 { ORDER BY a DESC NULLS FIRST RANGE BETWEEN 2 PRECEDING AND 1 PRECEDING } } { do_execsql_test 1.$tn " SELECT sum(b) OVER win FROM t1 WINDOW win AS ( $win ) " {6 6 6} } do_execsql_test 1.2 { SELECT sum(b) OVER win FROM t1 WINDOW win AS ( ORDER BY a DESC NULLS FIRST RANGE BETWEEN 1 PRECEDING AND 1 FOLLOWING ) } {6 6 6} #------------------------------------------------------------------------- reset_db do_execsql_test 2.0 { CREATE TABLE t1(a, b); INSERT INTO t1 VALUES(1, NULL); INSERT INTO t1 VALUES(2, 45); INSERT INTO t1 VALUES(3, 66.2); INSERT INTO t1 VALUES(4, 'hello world'); INSERT INTO t1 VALUES(5, 'hello world'); INSERT INTO t1 VALUES(6, X'1234'); INSERT INTO t1 VALUES(7, X'1234'); INSERT INTO t1 VALUES(8, NULL); } foreach {tn win} { 1 "ORDER BY b RANGE BETWEEN 1 PRECEDING AND 2 PRECEDING" 2 "ORDER BY b RANGE BETWEEN 2 FOLLOWING AND 2 FOLLOWING" 3 "ORDER BY b NULLS LAST RANGE BETWEEN 1 PRECEDING AND 2 PRECEDING" 4 "ORDER BY b NULLS LAST RANGE BETWEEN 2 FOLLOWING AND 2 FOLLOWING" } { do_execsql_test 2.1.$tn " SELECT a, sum(a) OVER win FROM t1 WINDOW win AS ( $win ) ORDER BY 1 " {1 9 2 {} 3 {} 4 9 5 9 6 13 7 13 8 9} } #------------------------------------------------------------------------- ifcapable json1 { reset_db do_execsql_test 3.0 { CREATE TABLE testjson(id INTEGER PRIMARY KEY, j TEXT, x TEXT); INSERT INTO testjson VALUES(1, '{"a":1}', 'a'); INSERT INTO testjson VALUES(2, '{"b":2}', 'b'); INSERT INTO testjson VALUES(3, '{"c":3}', 'c'); INSERT INTO testjson VALUES(4, '{"d":4}', 'd'); } do_execsql_test 3.1 { SELECT json_group_array(json(j)) FROM testjson; } { {[{"a":1},{"b":2},{"c":3},{"d":4}]} } do_execsql_test 3.2 { SELECT json_group_array(json(j)) OVER (ORDER BY id) FROM testjson; } { {[{"a":1}]} {[{"a":1},{"b":2}]} {[{"a":1},{"b":2},{"c":3}]} {[{"a":1},{"b":2},{"c":3},{"d":4}]} } do_execsql_test 3.3 { SELECT json_group_array(json(j)) OVER ( ORDER BY id RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW EXCLUDE TIES ) FROM testjson; } { {[{"a":1}]} {[{"a":1},{"b":2}]} {[{"a":1},{"b":2},{"c":3}]} {[{"a":1},{"b":2},{"c":3},{"d":4}]} } do_execsql_test 3.4 { SELECT json_group_array(json(j)) OVER ( ORDER BY id ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING ) FROM testjson; } { {[{"a":1},{"b":2}]} {[{"a":1},{"b":2},{"c":3}]} {[{"b":2},{"c":3},{"d":4}]} {[{"c":3},{"d":4}]} } do_execsql_test 3.5 { SELECT json_group_array(json(j)) OVER ( ORDER BY id ROWS BETWEEN 2 PRECEDING AND 1 PRECEDING ) FROM testjson; } { {[]} {[{"a":1}]} {[{"a":1},{"b":2}]} {[{"b":2},{"c":3}]} } do_execsql_test 3.5a { UPDATE testjson SET j = replace(j,char(125),',"e":9'||char(125)); SELECT j FROM testjson; } { {{"a":1,"e":9}} {{"b":2,"e":9}} {{"c":3,"e":9}} {{"d":4,"e":9}} } do_execsql_test 3.5b { SELECT group_concat(x,'') OVER ( ORDER BY id ROWS BETWEEN 1 FOLLOWING AND 2 FOLLOWING ) FROM testjson ORDER BY id; } {bc cd d {}} do_execsql_test 3.5c { SELECT json_group_array(json(j)) OVER ( ORDER BY id ROWS BETWEEN 1 FOLLOWING AND 2 FOLLOWING ) FROM testjson; } { {[{"b":2,"e":9},{"c":3,"e":9}]} {[{"c":3,"e":9},{"d":4,"e":9}]} {[{"d":4,"e":9}]} {[]} } do_execsql_test 3.5d { SELECT json_group_object(x,json(j)) OVER ( ORDER BY id ROWS BETWEEN 1 FOLLOWING AND 2 FOLLOWING ) FROM testjson; } { {{"b":{"b":2,"e":9},"c":{"c":3,"e":9}}} {{"c":{"c":3,"e":9},"d":{"d":4,"e":9}}} {{"d":{"d":4,"e":9}}} {{}} } do_execsql_test 3.7b { SELECT group_concat(x,'') FILTER (WHERE id!=2) OVER ( ORDER BY id ROWS BETWEEN 2 PRECEDING AND 1 PRECEDING ) FROM testjson; } {{} a a c} do_execsql_test 3.7c { SELECT json_group_array(json(j)) FILTER (WHERE id!=2) OVER ( ORDER BY id ROWS BETWEEN 2 PRECEDING AND 1 PRECEDING ) FROM testjson } { {[]} {[{"a":1,"e":9}]} {[{"a":1,"e":9}]} {[{"c":3,"e":9}]} } do_execsql_test 3.7d { SELECT json_group_object(x,json(j)) FILTER (WHERE id!=2) OVER ( ORDER BY id ROWS BETWEEN 2 PRECEDING AND 1 PRECEDING ) FROM testjson } { {{}} {{"a":{"a":1,"e":9}}} {{"a":{"a":1,"e":9}}} {{"c":{"c":3,"e":9}}} } } #------------------------------------------------------------------------- reset_db do_execsql_test 4.0 { CREATE TABLE x(a); INSERT INTO x VALUES(1); INSERT INTO x VALUES(2); } do_execsql_test 4.1 { WITH y AS ( SELECT Row_Number() OVER (win) FROM x WINDOW win AS (PARTITION BY a) ) SELECT * FROM y; } { 1 1 } do_catchsql_test 4.2 { WITH y AS ( SELECT Row_Number() OVER (win) FROM x WINDOW win AS (PARTITION BY fake_column)) SELECT * FROM y; } {1 {no such column: fake_column}} do_catchsql_test 4.3 { SELECT 1 WINDOW win AS (PARTITION BY fake_column); } {0 1} #------------------------------------------------------------------------- reset_db do_execsql_test 5.0 { CREATE TABLE t1(a, c); CREATE INDEX i1 ON t1(a); INSERT INTO t1 VALUES(0, 421); INSERT INTO t1 VALUES(1, 844); INSERT INTO t1 VALUES(2, 1001); } do_execsql_test 5.1 { SELECT a, sum(c) OVER ( ORDER BY a RANGE BETWEEN 0 PRECEDING AND 3 PRECEDING ) FROM t1; } {0 {} 1 {} 2 {}} do_execsql_test 5.2 { INSERT INTO t1 VALUES(NULL, 123); INSERT INTO t1 VALUES(NULL, 111); INSERT INTO t1 VALUES('xyz', 222); INSERT INTO t1 VALUES('xyz', 333); SELECT a, sum(c) OVER ( ORDER BY a RANGE BETWEEN 0 PRECEDING AND 3 PRECEDING ) FROM t1; } {{} 234 {} 234 0 {} 1 {} 2 {} xyz 555 xyz 555} do_execsql_test 5.3 { SELECT a, sum(c) OVER ( ORDER BY a RANGE BETWEEN 2 FOLLOWING AND 0 FOLLOWING ) FROM t1; } {{} 234 {} 234 0 {} 1 {} 2 {} xyz 555 xyz 555} do_execsql_test 5.4 { SELECT a, sum(c) OVER ( ORDER BY a RANGE BETWEEN 0 PRECEDING AND 3 PRECEDING EXCLUDE NO OTHERS ) FROM t1; } {{} 234 {} 234 0 {} 1 {} 2 {} xyz 555 xyz 555} do_execsql_test 5.5 { SELECT a, sum(c) OVER ( ORDER BY a RANGE BETWEEN 2 FOLLOWING AND 0 FOLLOWING EXCLUDE NO OTHERS ) FROM t1; } {{} 234 {} 234 0 {} 1 {} 2 {} xyz 555 xyz 555} #------------------------------------------------------------------------- reset_db do_execsql_test 6.0 { CREATE TABLE t1(a, c); CREATE INDEX i1 ON t1(a); INSERT INTO t1 VALUES(7, 997); INSERT INTO t1 VALUES(8, 997); INSERT INTO t1 VALUES('abc', 1001); } do_execsql_test 6.1 { SELECT a, sum(c) OVER ( ORDER BY a RANGE BETWEEN 2 FOLLOWING AND 0 FOLLOWING ) FROM t1; } {7 {} 8 {} abc 1001} do_execsql_test 6.2 { SELECT a, sum(c) OVER ( ORDER BY a RANGE BETWEEN 2 FOLLOWING AND 0 FOLLOWING EXCLUDE NO OTHERS ) FROM t1; } {7 {} 8 {} abc 1001} #------------------------------------------------------------------------- reset_db do_execsql_test 7.0 { CREATE TABLE t1(a, c); CREATE INDEX i1 ON t1(a); INSERT INTO t1 VALUES(NULL, 46); INSERT INTO t1 VALUES(NULL, 45); INSERT INTO t1 VALUES(7, 997); INSERT INTO t1 VALUES(7, 1000); INSERT INTO t1 VALUES(8, 997); INSERT INTO t1 VALUES(8, 1000); INSERT INTO t1 VALUES('abc', 1001); INSERT INTO t1 VALUES('abc', 1004); INSERT INTO t1 VALUES('xyz', 3333); } do_execsql_test 7.1 { SELECT a, max(c) OVER ( ORDER BY a RANGE BETWEEN 2 FOLLOWING AND 0 FOLLOWING ) FROM t1; } {{} 46 {} 46 7 {} 7 {} 8 {} 8 {} abc 1004 abc 1004 xyz 3333} do_execsql_test 7.2 { SELECT a, min(c) OVER ( ORDER BY a RANGE BETWEEN 2 FOLLOWING AND 0 FOLLOWING ) FROM t1; } {{} 45 {} 45 7 {} 7 {} 8 {} 8 {} abc 1001 abc 1001 xyz 3333} do_execsql_test 7.3 { SELECT a, max(c) OVER ( ORDER BY a RANGE BETWEEN 0 PRECEDING AND 2 PRECEDING ) FROM t1; } {{} 46 {} 46 7 {} 7 {} 8 {} 8 {} abc 1004 abc 1004 xyz 3333} do_execsql_test 7.4 { SELECT a, min(c) OVER ( ORDER BY a RANGE BETWEEN 0 PRECEDING AND 2 PRECEDING ) FROM t1; } {{} 45 {} 45 7 {} 7 {} 8 {} 8 {} abc 1001 abc 1001 xyz 3333} #------------------------------------------------------------------------- reset_db do_execsql_test 8.0 { BEGIN TRANSACTION; CREATE TABLE t1(a, c); INSERT INTO t1 VALUES('aa', 111); INSERT INTO t1 VALUES('BB', 660); INSERT INTO t1 VALUES('CC', 938); INSERT INTO t1 VALUES('dd', 979); COMMIT; CREATE INDEX i1 ON t1(a COLLATE nocase); } do_execsql_test 8.1 { SELECT sum(c) OVER (ORDER BY a COLLATE nocase RANGE BETWEEN 10.0 PRECEDING AND 5.0 PRECEDING) FROM t1; } {111 660 938 979} do_execsql_test 9.0 { CREATE TABLE seps(x); INSERT INTO seps(x) VALUES ('1'), ('22'), ('333'), ('4444'); SELECT group_concat('-', x) OVER ( ORDER BY x ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING ) FROM seps; } {-22- -22-333- -333-4444- -4444-} finish_test |
Added test/windowC.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 | # 2021-09-29 # # 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 varying separator handling by group_concat(). # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix windowB ifcapable !windowfunc { finish_test return } do_execsql_test 1.0 { CREATE TABLE x1(i INTEGER PRIMARY KEY, x); } foreach {tn bBlob seps} { 1 0 {a b c def g} 2 0 {abcdefg {} {} abcdefg} 3 0 {a bc def ghij klmno pqrstu} 4 1 {a bc def ghij klmno pqrstu} 5 1 {, , , , , , , , , , , , ....... , ,} } { foreach type {text blob} { do_test 1.$type.$tn.1 { execsql { DELETE FROM x1 } foreach s $seps { if {$type=="text"} { execsql {INSERT INTO x1 VALUES(NULL, $s)} } else { execsql {INSERT INTO x1 VALUES(NULL, CAST ($s AS blob))} } } } {} foreach {tn2 win} { 1 "ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING" 2 "ROWS BETWEEN 2 PRECEDING AND CURRENT ROW" 3 "ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING" } { do_test 1.$type.$tn.2.$tn2 { db eval " SELECT group_concat('val', x) OVER ( ORDER BY i $win ) AS val FROM x1 " { if {[string range $val 0 2]!="val" || [string range $val end-2 end]!="val" } { error "unexpected return value: $val" } } } {} } } } # 2021-10-12 dbsqlfuzz 6c31db077a14149a7b22a1069294bdb068be8a96 # reset_db do_execsql_test 2.0 { PRAGMA encoding=UTF16; WITH separator(x) AS (VALUES(',a,'),(',bc,')), value(y) AS (VALUES(1),(x'5585d09013455178cd11ce4a')) SELECT group_concat(y,x) OVER (ORDER BY x ROWS BETWEEN 1 PRECEDING AND 1 PRECEDING) FROM separator, value; } {{} 1 蕕郐䔓硑ᇍ䫎 1} finish_test |
Added test/windowerr.tcl.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | # 2018 May 19 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # source [file join [file dirname $argv0] pg_common.tcl] #========================================================================= start_test windowerr "2019 March 01" ifcapable !windowfunc execsql_test 1.0 { DROP TABLE IF EXISTS t1; CREATE TABLE t1(a INTEGER, b INTEGER); INSERT INTO t1 VALUES(1, 1); INSERT INTO t1 VALUES(2, 2); INSERT INTO t1 VALUES(3, 3); INSERT INTO t1 VALUES(4, 4); INSERT INTO t1 VALUES(5, 5); } foreach {tn frame} { 1 "ORDER BY a ROWS BETWEEN -1 PRECEDING AND 1 FOLLOWING" 2 "ORDER BY a ROWS BETWEEN 1 PRECEDING AND -1 FOLLOWING" 3 "ORDER BY a RANGE BETWEEN -1 PRECEDING AND 1 FOLLOWING" 4 "ORDER BY a RANGE BETWEEN 1 PRECEDING AND -1 FOLLOWING" 5 "ORDER BY a GROUPS BETWEEN -1 PRECEDING AND 1 FOLLOWING" 6 "ORDER BY a GROUPS BETWEEN 1 PRECEDING AND -1 FOLLOWING" 7 "ORDER BY a,b RANGE BETWEEN 1 PRECEDING AND 1 FOLLOWING" 8 "PARTITION BY a RANGE BETWEEN 1 PRECEDING AND 1 FOLLOWING" } { errorsql_test 1.$tn " SELECT a, sum(b) OVER ( $frame ) FROM t1 ORDER BY 1 " } errorsql_test 2.1 { SELECT sum( sum(a) OVER () ) FROM t1; } errorsql_test 2.2 { SELECT sum(a) OVER () AS xyz FROM t1 ORDER BY sum(xyz); } errorsql_test 3.0 { SELECT sum(a) OVER win FROM t1 WINDOW win AS (ROWS BETWEEN 'hello' PRECEDING AND 10 FOLLOWING) } errorsql_test 3.2 { SELECT sum(a) OVER win FROM t1 WINDOW win AS (ROWS BETWEEN 10 PRECEDING AND x'ABCD' FOLLOWING) } errorsql_test 3.3 { SELECT row_number(a) OVER () FROM t1; } finish_test |
Added test/windowerr.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 | # 2019 March 01 # # 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. # #################################################### # DO NOT EDIT! THIS FILE IS AUTOMATICALLY GENERATED! #################################################### set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix windowerr ifcapable !windowfunc { finish_test ; return } do_execsql_test 1.0 { DROP TABLE IF EXISTS t1; CREATE TABLE t1(a INTEGER, b INTEGER); INSERT INTO t1 VALUES(1, 1); INSERT INTO t1 VALUES(2, 2); INSERT INTO t1 VALUES(3, 3); INSERT INTO t1 VALUES(4, 4); INSERT INTO t1 VALUES(5, 5); } {} # PG says ERROR: frame starting offset must not be negative do_test 1.1 { catch { execsql { SELECT a, sum(b) OVER ( ORDER BY a ROWS BETWEEN -1 PRECEDING AND 1 FOLLOWING ) FROM t1 ORDER BY 1 } } } 1 # PG says ERROR: frame ending offset must not be negative do_test 1.2 { catch { execsql { SELECT a, sum(b) OVER ( ORDER BY a ROWS BETWEEN 1 PRECEDING AND -1 FOLLOWING ) FROM t1 ORDER BY 1 } } } 1 # PG says ERROR: invalid preceding or following size in window function do_test 1.3 { catch { execsql { SELECT a, sum(b) OVER ( ORDER BY a RANGE BETWEEN -1 PRECEDING AND 1 FOLLOWING ) FROM t1 ORDER BY 1 } } } 1 # PG says ERROR: invalid preceding or following size in window function do_test 1.4 { catch { execsql { SELECT a, sum(b) OVER ( ORDER BY a RANGE BETWEEN 1 PRECEDING AND -1 FOLLOWING ) FROM t1 ORDER BY 1 } } } 1 # PG says ERROR: frame starting offset must not be negative do_test 1.5 { catch { execsql { SELECT a, sum(b) OVER ( ORDER BY a GROUPS BETWEEN -1 PRECEDING AND 1 FOLLOWING ) FROM t1 ORDER BY 1 } } } 1 # PG says ERROR: frame ending offset must not be negative do_test 1.6 { catch { execsql { SELECT a, sum(b) OVER ( ORDER BY a GROUPS BETWEEN 1 PRECEDING AND -1 FOLLOWING ) FROM t1 ORDER BY 1 } } } 1 # PG says ERROR: RANGE with offset PRECEDING/FOLLOWING requires exactly one ORDER BY column do_test 1.7 { catch { execsql { SELECT a, sum(b) OVER ( ORDER BY a,b RANGE BETWEEN 1 PRECEDING AND 1 FOLLOWING ) FROM t1 ORDER BY 1 } } } 1 # PG says ERROR: RANGE with offset PRECEDING/FOLLOWING requires exactly one ORDER BY column do_test 1.8 { catch { execsql { SELECT a, sum(b) OVER ( PARTITION BY a RANGE BETWEEN 1 PRECEDING AND 1 FOLLOWING ) FROM t1 ORDER BY 1 } } } 1 # PG says ERROR: aggregate function calls cannot contain window function calls do_test 2.1 { catch { execsql { SELECT sum( sum(a) OVER () ) FROM t1; } } } 1 # PG says ERROR: column "xyz" does not exist do_test 2.2 { catch { execsql { SELECT sum(a) OVER () AS xyz FROM t1 ORDER BY sum(xyz); } } } 1 # PG says ERROR: invalid input syntax for integer: "hello" do_test 3.0 { catch { execsql { SELECT sum(a) OVER win FROM t1 WINDOW win AS (ROWS BETWEEN 'hello' PRECEDING AND 10 FOLLOWING) } } } 1 # PG says ERROR: argument of ROWS must be type bigint, not type bit do_test 3.2 { catch { execsql { SELECT sum(a) OVER win FROM t1 WINDOW win AS (ROWS BETWEEN 10 PRECEDING AND x'ABCD' FOLLOWING) } } } 1 # PG says ERROR: function row_number(integer) does not exist do_test 3.3 { catch { execsql { SELECT row_number(a) OVER () FROM t1; } } } 1 finish_test |
Changes to test/windowfault.test.
︙ | ︙ | |||
24 25 26 27 28 29 30 | CREATE TABLE t1(a, b, c, d); INSERT INTO t1 VALUES(1, 2, 3, 4); INSERT INTO t1 VALUES(5, 6, 7, 8); INSERT INTO t1 VALUES(9, 10, 11, 12); } faultsim_save_and_close | | | 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | CREATE TABLE t1(a, b, c, d); INSERT INTO t1 VALUES(1, 2, 3, 4); INSERT INTO t1 VALUES(5, 6, 7, 8); INSERT INTO t1 VALUES(9, 10, 11, 12); } faultsim_save_and_close do_faultsim_test 1 -start 1 -faults oom-t* -prep { faultsim_restore_and_reopen } -body { execsql { SELECT row_number() OVER win, rank() OVER win, dense_rank() OVER win, ntile(2) OVER win, |
︙ | ︙ | |||
157 158 159 160 161 162 163 164 165 | WINDOW win1 AS (PARTITION BY a ), win2 AS (PARTITION BY b ) ORDER BY a; } } -test { faultsim_test_result {0 {1 2 5 6 9 10}} } finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | WINDOW win1 AS (PARTITION BY a ), win2 AS (PARTITION BY b ) ORDER BY a; } } -test { faultsim_test_result {0 {1 2 5 6 9 10}} } #------------------------------------------------------------------------- # The following test causes a cursor in REQURESEEK state to be passed # to sqlite3BtreeDelete(). An error is simulated within the seek operation # to restore the cursors position. # reset_db set big [string repeat x 900] do_execsql_test 9.0 { PRAGMA page_size = 512; PRAGMA cache_size = 2; CREATE TABLE t(x INTEGER PRIMARY KEY, y TEXT); WITH s(i) AS ( VALUES(1) UNION ALL SELECT i+1 FROM s WHERE i<1900 ) INSERT INTO t(y) SELECT $big FROM s; } db close testvfs tvfs -default 1 tvfs script vfs_callback tvfs filter xRead sqlite3 db test.db proc vfs_callback {method file args} { if {$file=="" && [info exists ::tmp_read_fail]} { incr ::tmp_read_fail -1 if {$::tmp_read_fail<=0} { return "SQLITE_IOERR" } } return "SQLITE_OK" } set FAULTSIM(tmpread) [list \ -injectstart tmpread_injectstart \ -injectstop tmpread_injectstop \ -injecterrlist {{1 {disk I/O error}}} \ ] proc tmpread_injectstart {iFail} { set ::tmp_read_fail $iFail } proc tmpread_injectstop {} { set ret [expr $::tmp_read_fail<=0] unset -nocomplain ::tmp_read_fail return $ret } set L [db eval {SELECT 0.0 FROM t}] do_faultsim_test 9 -end 25 -faults tmpread -body { execsql { SELECT sum(y) OVER win FROM t WINDOW win AS ( ORDER BY x ROWS BETWEEN UNBOUNDED PRECEDING AND 1800 FOLLOWING ) } } -test { faultsim_test_result [list 0 $::L] } catch {db close} tvfs delete reset_db do_execsql_test 10.0 { CREATE TABLE t1(a, b, c, d); CREATE TABLE t2(a, b, c, d); } do_faultsim_test 10 -faults oom* -prep { } -body { execsql { SELECT row_number() OVER win FROM t1 WINDOW win AS ( ORDER BY ( SELECT percent_rank() OVER win2 FROM t2 WINDOW win2 AS (ORDER BY a) ) ) } } -test { faultsim_test_result {0 {}} } #------------------------------------------------------------------------- reset_db do_execsql_test 11.0 { DROP TABLE IF EXISTS t0; CREATE TABLE t0(c0 INTEGER UNIQUE); INSERT INTO t0 VALUES(0); } {} do_faultsim_test 11.1 -faults oom* -prep { } -body { execsql { SELECT * FROM t0 WHERE (0, t0.c0) IN (SELECT DENSE_RANK() OVER(), LAG(0) OVER() FROM t0); } } -test { faultsim_test_result {0 {}} } do_faultsim_test 11.2 -faults oom* -prep { } -body { execsql { VALUES(false),(current_date collate binary) intersect values(count() not like group_concat(cast(cast(0e00 as text) as integer) <= NULL || 0.4e-0 || 0x8 & true ) over () collate rtrim); } } -test { faultsim_test_result {0 {}} } #------------------------------------------------------------------------- reset_db do_execsql_test 12.0 { CREATE TABLE t1(a, b, c); } {} do_faultsim_test 12 -faults oom* -prep { } -body { execsql { WITH v(a, b, row_number) AS ( SELECT a, b, row_number() OVER (PARTITION BY a COLLATE nocase ORDER BY b) FROM t1 ) SELECT * FROM v WHERE a=2 } } -test { faultsim_test_result {0 {}} } #------------------------------------------------------------------------- reset_db do_execsql_test 13.0 { CREATE TABLE t1(id INTEGER PRIMARY KEY, a, b); INSERT INTO t1 VALUES(1, '1', 'a'); INSERT INTO t1 VALUES(2, '22', 'b'); INSERT INTO t1 VALUES(3, '333', 'c'); INSERT INTO t1 VALUES(4, '4444', 'dddd'); INSERT INTO t1 VALUES(5, '55555', 'e'); INSERT INTO t1 VALUES(6, '666666', 'f'); INSERT INTO t1 VALUES(7, '7777777', 'gggggggggg'); } {} set queryres [list {*}{ 1b22 1b22c333 22c333dddd4444 333dddd4444e55555 4444e55555f666666 55555f666666gggggggggg7777777 666666gggggggggg7777777 }] do_execsql_test 13.1 { SELECT group_concat(a, b) OVER ( ORDER BY id RANGE BETWEEN 1 PRECEDING AND 1 FOLLOWING ) FROM t1 } $queryres do_faultsim_test 13 -faults oom* -prep { } -body { execsql { SELECT group_concat(a, b) OVER ( ORDER BY id RANGE BETWEEN 1 PRECEDING AND 1 FOLLOWING ) FROM t1 } } -test { faultsim_test_result [list 0 $::queryres] } finish_test |
Added test/windowpushd.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 | # 2021 February 23 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this file is testing the push-down optimization when # WHERE constraints are pushed down into a sub-query that uses # window functions. # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix windowpushd do_execsql_test 1.0 { CREATE TABLE t1(id INTEGER PRIMARY KEY, grp_id); CREATE INDEX i1 ON t1(grp_id); CREATE VIEW lll AS SELECT row_number() OVER (PARTITION BY grp_id), grp_id, id FROM t1 } do_execsql_test 1.1 { INSERT INTO t1 VALUES (1, 2), (2, 3), (3, 3), (4, 1), (5, 1), (6, 1), (7, 1), (8, 1), (9, 3), (10, 3), (11, 2), (12, 3), (13, 3), (14, 2), (15, 1), (16, 2), (17, 1), (18, 2), (19, 3), (20, 2) } do_execsql_test 1.2 { SELECT * FROM lll } { 1 1 4 2 1 5 3 1 6 4 1 7 5 1 8 6 1 15 7 1 17 1 2 1 2 2 11 3 2 14 4 2 16 5 2 18 6 2 20 1 3 2 2 3 3 3 3 9 4 3 10 5 3 12 6 3 13 7 3 19 } do_execsql_test 1.3 { SELECT * FROM lll WHERE grp_id=2 } { 1 2 1 2 2 11 3 2 14 4 2 16 5 2 18 6 2 20 } do_eqp_test 1.4 { SELECT * FROM lll WHERE grp_id=2 } {SEARCH t1 USING COVERING INDEX i1 (grp_id=?)} #------------------------------------------------------------------------- reset_db do_execsql_test 2.0 { CREATE TABLE t1(a, b, c, d); INSERT INTO t1 VALUES('A', 'C', 1, 0.1); INSERT INTO t1 VALUES('A', 'D', 2, 0.2); INSERT INTO t1 VALUES('A', 'E', 3, 0.3); INSERT INTO t1 VALUES('A', 'C', 4, 0.4); INSERT INTO t1 VALUES('B', 'D', 5, 0.5); INSERT INTO t1 VALUES('B', 'E', 6, 0.6); INSERT INTO t1 VALUES('B', 'C', 7, 0.7); INSERT INTO t1 VALUES('B', 'D', 8, 0.8); INSERT INTO t1 VALUES('C', 'E', 9, 0.9); INSERT INTO t1 VALUES('C', 'C', 10, 1.0); INSERT INTO t1 VALUES('C', 'D', 11, 1.1); INSERT INTO t1 VALUES('C', 'E', 12, 1.2); CREATE INDEX i1 ON t1(a); CREATE INDEX i2 ON t1(b); CREATE VIEW v1 AS SELECT a, c, max(c) OVER (PARTITION BY a) FROM t1; CREATE VIEW v2 AS SELECT a, c, max(c) OVER (PARTITION BY a), row_number() OVER () FROM t1; CREATE VIEW v3 AS SELECT b, d, max(d) OVER (PARTITION BY b), row_number() OVER (PARTITION BY b) FROM t1; CREATE TABLE t2(x, y, z); INSERT INTO t2 VALUES('W', 3, 1); INSERT INTO t2 VALUES('W', 2, 2); INSERT INTO t2 VALUES('X', 1, 4); INSERT INTO t2 VALUES('X', 5, 7); INSERT INTO t2 VALUES('Y', 1, 9); INSERT INTO t2 VALUES('Y', 4, 2); INSERT INTO t2 VALUES('Z', 3, 3); INSERT INTO t2 VALUES('Z', 3, 4); } foreach tn {0 1} { optimization_control db push-down $tn do_execsql_test 2.$tn.1.1 { SELECT * FROM v1; } { A 1 4 A 2 4 A 3 4 A 4 4 B 5 8 B 6 8 B 7 8 B 8 8 C 9 12 C 10 12 C 11 12 C 12 12 } do_execsql_test 2.$tn.1.2 { SELECT * FROM v1 WHERE a IN ('A', 'B'); } { A 1 4 A 2 4 A 3 4 A 4 4 B 5 8 B 6 8 B 7 8 B 8 8 } do_execsql_test 2.$tn.1.3 { SELECT * FROM v1 WHERE a IS 'C' } { C 9 12 C 10 12 C 11 12 C 12 12 } if {$tn==1} { do_eqp_test 2.$tn.1.4 { SELECT * FROM v1 WHERE a IN ('A', 'B'); } {USING INDEX i1 (a=?)} do_eqp_test 2.$tn.1.5 { SELECT * FROM v1 WHERE a = 'c' COLLATE nocase } {USING INDEX i1} } do_execsql_test 2.$tn.2.1 { SELECT * FROM v2; } { A 1 4 1 A 2 4 2 A 3 4 3 A 4 4 4 B 5 8 5 B 6 8 6 B 7 8 7 B 8 8 8 C 9 12 9 C 10 12 10 C 11 12 11 C 12 12 12 } do_execsql_test 2.$tn.2.2 { SELECT * FROM v2 WHERE a = 'C'; } { C 9 12 9 C 10 12 10 C 11 12 11 C 12 12 12 } do_execsql_test 2.$tn.3.1 { SELECT * FROM v3; } { C 0.1 1.0 1 C 0.4 1.0 2 C 0.7 1.0 3 C 1.0 1.0 4 D 0.2 1.1 1 D 0.5 1.1 2 D 0.8 1.1 3 D 1.1 1.1 4 E 0.3 1.2 1 E 0.6 1.2 2 E 0.9 1.2 3 E 1.2 1.2 4 } do_execsql_test 2.$tn.3.2 { SELECT * FROM v3 WHERE b<'E' } { C 0.1 1.0 1 C 0.4 1.0 2 C 0.7 1.0 3 C 1.0 1.0 4 D 0.2 1.1 1 D 0.5 1.1 2 D 0.8 1.1 3 D 1.1 1.1 4 } if {$tn==1} { do_eqp_test 2.$tn.3.3 { SELECT * FROM v3 WHERE b='E' } {SEARCH t1 USING INDEX i2 (b=?)} do_eqp_test 2.$tn.3.4 { SELECT * FROM v3 WHERE b>'C' } {SEARCH t1 USING INDEX i2 (b>?)} } do_execsql_test 2.$tn.3.5 { SELECT * FROM v3 WHERE d<0.55; } { C 0.1 1.0 1 C 0.4 1.0 2 D 0.2 1.1 1 D 0.5 1.1 2 E 0.3 1.2 1 } if {$tn==1} { do_eqp_test 2.$tn.3.6 { SELECT * FROM v3 WHERE d<0.55 } {SCAN t1 USING INDEX i2} } do_execsql_test 2.$tn.4.1 { SELECT * FROM ( SELECT x, sum(y) AS s, max(z) AS m FROM t2 GROUP BY x ) } { W 5 2 X 6 7 Y 5 9 Z 6 4 } do_execsql_test 2.$tn.4.1 { SELECT * FROM ( SELECT x, sum(y) AS s, max(z) AS m, max( max(z) ) OVER (PARTITION BY sum(y) ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING ) FROM t2 GROUP BY x ) } { W 5 2 9 Y 5 9 9 X 6 7 7 Z 6 4 7 } do_execsql_test 2.$tn.4.2 { SELECT * FROM ( SELECT x, sum(y) AS s, max(z) AS m, max( max(z) ) OVER (PARTITION BY sum(y) ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING ) FROM t2 GROUP BY x ) WHERE s=6 } { X 6 7 7 Z 6 4 7 } do_execsql_test 2.$tn.4.3 { SELECT * FROM ( SELECT x, sum(y) AS s, max(z) AS m, max( max(z) ) OVER (PARTITION BY sum(y) ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING ) FROM t2 GROUP BY x ) WHERE s<6 } { W 5 2 9 Y 5 9 9 } } finish_test |
Changes to test/with1.test.
︙ | ︙ | |||
348 349 350 351 352 353 354 | do_catchsql_test 7.4 { WITH t(id) AS ( VALUES(2) UNION ALL SELECT i FROM tree WHERE p IN (SELECT id FROM t) ) SELECT id FROM t; | | | 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 | do_catchsql_test 7.4 { WITH t(id) AS ( VALUES(2) UNION ALL SELECT i FROM tree WHERE p IN (SELECT id FROM t) ) SELECT id FROM t; } {1 {circular reference: t}} do_catchsql_test 7.5 { WITH t(id) AS ( VALUES(2) UNION ALL SELECT i FROM tree, t WHERE p = id AND p IN (SELECT id FROM t) ) |
︙ | ︙ | |||
1021 1022 1023 1024 1025 1026 1027 | WITH x1(a) AS (values(100)) INSERT INTO t1(x) SELECT * FROM (WITH x2(y) AS (SELECT * FROM x1) SELECT y+a FROM x1, x2); SELECT * FROM t1; } { QUERY PLAN | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | WITH x1(a) AS (values(100)) INSERT INTO t1(x) SELECT * FROM (WITH x2(y) AS (SELECT * FROM x1) SELECT y+a FROM x1, x2); SELECT * FROM t1; } { QUERY PLAN |--MATERIALIZE x1 | `--SCAN CONSTANT ROW |--SCAN x1 `--SCAN x1 } # 2017-10-28. # See check-in https://sqlite.org/src/info/0926df095faf72c2 # Tried to optimize co-routine processing by changing a Copy opcode # into SCopy. But OSSFuzz found two (similar) cases where that optimization # does not work. # do_execsql_test 20.1 { WITH c(i)AS(VALUES(9)UNION SELECT~i FROM c)SELECT max(5)>i fROM c; } {0} do_execsql_test 20.2 { WITH c(i)AS(VALUES(5)UNIoN SELECT 0)SELECT min(1)-i fROM c; } {1} # 2018-12-26 # Two different CTE tables with the same name appear in within a single FROM # clause due to the query-flattener optimization. make sure this does not cause # problems. This problem was discovered by Matt Denton. # do_execsql_test 21.1 { WITH RECURSIVE t21(a,b) AS ( WITH t21(x) AS (VALUES(1)) SELECT x, x FROM t21 ORDER BY 1 ) SELECT * FROM t21 AS tA, t21 AS tB } {1 1 1 1} do_execsql_test 21.1b { /* This variant from chromium bug 922312 on 2019-01-16 */ WITH RECURSIVE t21(a,b) AS ( WITH t21(x) AS (VALUES(1)) SELECT x, x FROM t21 ORDER BY 1 LIMIT 5 ) SELECT * FROM t21 AS tA, t21 AS tB } {1 1 1 1} do_execsql_test 21.2 { SELECT printf('', EXISTS (WITH RECURSIVE Table0 AS (WITH Table0 AS (SELECT DISTINCT 1) SELECT *, * FROM Table0 ORDER BY 1 DESC) SELECT * FROM Table0 NATURAL JOIN Table0)); } {{}} # 2019-01-17 # Make sure crazy nexted CTE joins terminate with an error quickly. # do_catchsql_test 22.1 { WITH RECURSIVE c AS ( WITH RECURSIVE c AS ( WITH RECURSIVE c AS ( WITH RECURSIVE c AS ( WITH c AS (VALUES(0)) SELECT 1 FROM c LEFT JOIN c ON ltrim(1) ) SELECT 1 FROM c,c,c,c,c,c,c,c,c ) SELECT 2 FROM c,c,c,c,c,c,c,c,c ) SELECT 3 FROM c,c,c,c,c,c,c,c,c ) SELECT 4 FROM c,c,c,c,c,c,c,c,c; } {1 {too many FROM clause terms, max: 200}} # 2019-05-22 # ticket https://www.sqlite.org/src/tktview/ce823231949d3abf42453c8f20 # sqlite3 db :memory: do_execsql_test 23.1 { CREATE TABLE t1(id INTEGER NULL PRIMARY KEY, name Text); INSERT INTO t1 VALUES (1, 'john'); INSERT INTO t1 VALUES (2, 'james'); INSERT INTO t1 VALUES (3, 'jingle'); INSERT INTO t1 VALUES (4, 'himer'); INSERT INTO t1 VALUES (5, 'smith'); CREATE VIEW v2 AS WITH t4(Name) AS (VALUES ('A'), ('B')) SELECT Name Name FROM t4; CREATE VIEW v3 AS WITH t4(Att, Val, Act) AS (VALUES ('C', 'D', 'E'), ('F', 'G', 'H') ) SELECT D.Id Id, P.Name Protocol, T.Att Att, T.Val Val, T.Act Act FROM t1 D CROSS JOIN v2 P CROSS JOIN t4 T; SELECT * FROM v3; } {1 A C D E 1 A F G H 1 B C D E 1 B F G H 2 A C D E 2 A F G H 2 B C D E 2 B F G H 3 A C D E 3 A F G H 3 B C D E 3 B F G H 4 A C D E 4 A F G H 4 B C D E 4 B F G H 5 A C D E 5 A F G H 5 B C D E 5 B F G H} #------------------------------------------------------------------------- reset_db do_execsql_test 24.1 { CREATE TABLE t1(a, b, c); CREATE VIEW v1 AS SELECT max(a), min(b) FROM t1 GROUP BY c; } do_test 24.1 { set program [db eval {EXPLAIN SELECT 1 FROM v1,v1,v1}] expr [lsearch $program OpenDup]>0 } {1} do_execsql_test 24.2 { ATTACH "" AS aux; CREATE VIEW aux.v3 AS VALUES(1); CREATE VIEW main.v3 AS VALUES(3); CREATE VIEW aux.v2 AS SELECT * FROM v3; CREATE VIEW main.v2 AS SELECT * FROM v3; SELECT * FROM main.v2 AS a, aux.v2 AS b, aux.v2 AS c, main.v2 AS d; } { 3 1 1 3 } # 2020-01-02 chromium ticket 1033461 # Do not allow the generated name of a CTE be "true" or "false" as # such a label might be later confused for the boolean literals of # the same name, causing inconsistencies in the abstract syntax # tree. This problem first arose in version 3.23.0 when SQLite # began recognizing "true" and "false" as boolean literals, but also # had to continue to recognize "true" and "false" as identifiers for # backwards compatibility. # foreach {id dual} { 1 {CREATE TABLE dual AS SELECT 'X' AS dummy} 2 {CREATE TEMP TABLE dual AS SELECT 'X' AS dummy} 3 {CREATE VIEW dual(dummy) AS VALUES('X')} 4 {CREATE TEMP VIEW dual(dummy) AS VALUES('X')} } { reset_db db eval $dual do_execsql_test 25.$id { WITH cte1 AS ( SELECT TRUE, ( WITH cte2 AS (SELECT avg(DISTINCT TRUE) FROM dual) SELECT 2571 FROM cte2 ) AS subquery1 FROM dual GROUP BY 1 ) SELECT (SELECT 1324 FROM cte1) FROM cte1; } {1324} } do_catchsql_test 26.0 { WITH i(x) AS ( VALUES(1) UNION ALL SELECT x+1 FRO, a.b,O. * ,I¬i O, a.b,O. * ORDER BY 1 ) SELECT x,O. * O FROM i ¬I,I? 10; } {1 {near "O": syntax error}} # 2020-09-17 ticket c51489c3b8f919c5 # DISTINCT cannot be ignored in a UNION ALL recursive CTE # reset_db do_execsql_test 26.1 { CREATE TABLE t (label VARCHAR(10), step INTEGER); INSERT INTO T VALUES('a', 1); INSERT INTO T VALUES('a', 1); INSERT INTO T VALUES('b', 1); WITH RECURSIVE cte(label, step) AS ( SELECT DISTINCT * FROM t UNION ALL SELECT label, step + 1 FROM cte WHERE step < 3 ) SELECT * FROM cte ORDER BY +label, +step; } {a 1 a 2 a 3 b 1 b 2 b 3} do_execsql_test 26.2 { WITH RECURSIVE cte(label, step) AS ( SELECT * FROM t UNION SELECT label, step + 1 FROM cte WHERE step < 3 ) SELECT * FROM cte ORDER BY +label, +step; } {a 1 a 2 a 3 b 1 b 2 b 3} do_execsql_test 26.3 { CREATE TABLE tworow(x); INSERT INTO tworow(x) VALUES(1),(2); DELETE FROM t WHERE rowid=2; WITH RECURSIVE cte(label, step) AS ( SELECT * FROM t UNION ALL SELECT DISTINCT label, step + 1 FROM cte, tworow WHERE step < 3 ) SELECT * FROM cte ORDER BY +label, +step; } {a 1 a 2 a 3 b 1 b 2 b 3} # 2021-05-20 # forum post https://sqlite.org/forum/forumpost/8590e3f6dc # reset_db do_execsql_test 27.1 { CREATE TABLE t1(k); CREATE TABLE log(k, cte_map, main_map); CREATE TABLE map(k, v); INSERT INTO map VALUES(1, 'main1'), (2, 'main2'); CREATE TRIGGER tr1 AFTER INSERT ON t1 BEGIN INSERT INTO log WITH map(k,v) AS (VALUES(1,'cte1'),(2,'cte2')) SELECT new.k, (SELECT v FROM map WHERE k=new.k), (SELECT v FROM main.map WHERE k=new.k); END; INSERT INTO t1 VALUES(1); INSERT INTO t1 VALUES(2); SELECT k, cte_map, main_map, '|' FROM log ORDER BY k; } {1 cte1 main1 | 2 cte2 main2 |} finish_test |
Changes to test/with2.test.
︙ | ︙ | |||
410 411 412 413 414 415 416 417 418 | SELECT 1 UNION ALL SELECT a+1 FROM q, v WHERE a<5 ) SELECT * FROM q; } {1 2 3 4 5} finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | SELECT 1 UNION ALL SELECT a+1 FROM q, v WHERE a<5 ) SELECT * FROM q; } {1 2 3 4 5} # 2021-03-18 # Ticket bb8a9fd4a9b7fce5 reset_db do_execsql_test 9.1 { WITH xyz(a) AS ( WITH abc AS ( SELECT 1234 ) SELECT * FROM abc ) SELECT * FROM xyz AS one, xyz AS two, ( SELECT * FROM xyz UNION ALL SELECT * FROM xyz ); } {1234 1234 1234 1234 1234 1234} ifcapable vtab { load_static_extension db series do_execsql_test 9.2 { WITH cst(rsx, rsy) AS ( SELECT 100, 100 ), cst2(minx, maxx, stepx, miny, maxy, stepy, qualitativex, qualitativey) AS ( SELECT NULL, NULL, NULL, NULL, NULL, NULL, 0, 0 ), ds0(m, n, x, y, x2, y2, title, size, mark, label, markmode) AS ( SELECT 1, 2, 3, 4, 5, 6, 7 , 8, 9, 10, 11 ), ds(m, n, x, y, x2, y2, title, size, mark, label, markmode) AS ( SELECT m, n, x, y, x2, y2, title, size, mark, label, markmode FROM ds0 WINDOW w AS (PARTITION BY m, x ORDER BY n) ), d(m, n, x, y, x2, y2, labelx,labely,title,size,mark,label,markmode) AS ( SELECT m, n, x, y, x2, y2, x, y, title, size, mark, label, markmode FROM ds, cst2 ), ylabels(y, label) AS ( SELECT y, MIN(labely) FROM d GROUP BY y ), yaxis(maxy, miny, stepy , minstepy) AS ( WITH xt0(minx, maxx) AS ( SELECT coalesce(miny, min(min(y2), min(y))), coalesce(maxy, max(max(y2), max(y))) + qualitativey FROM d, cst2 ), xt1(mx, mn) AS (SELECT maxx, minx FROM xt0), xt2(mx, mn, step) AS (SELECT mx, mn, (mx-mn) FROM xt1), xt3(mx, mn, ms) AS ( SELECT mx, mn, first_value(rs) OVER (order by x desc) AS ms FROM (SELECT mx, mn, step, f,(mx-mn) as rng, 1.0*step/f as rs, 1.0*(mx-mn)/(step/f) AS x FROM xt2, (SELECT 1 AS f UNION ALL SELECT 2 UNION ALL SELECT 4 UNION ALL SELECT 5)) AS src WHERE x < 10 limit 1), xt4(minstepy) AS ( SELECT MIN(abs(y2-y)) FROM d WHERE y2 != y ) SELECT (mx/ms)*ms, (mn/ms)*ms, coalesce(stepy, ms), coalesce(minstepy, ms, stepy) FROM xt3, cst2,xt4 ), distinct_mark_n_m(mark, ze, zem, title) AS ( SELECT DISTINCT mark, n AS ze, m AS zem, title FROM ds0 ), facet0(m, mi, title, radial) AS ( SELECT md, row_number() OVER () - 1, title, 'radial' IN (SELECT mark FROM distinct_mark_n_m WHERE zem = md) FROM (SELECT DISTINCT zem AS md, title AS title FROM distinct_mark_n_m ORDER BY 2, 1) ), facet(m, mi, xorigin, yorigin, title, radial) AS ( SELECT m, mi, rsx * 1.2 * IFNULL(CASE WHEN ( 0 ) > 0 THEN mi / ( 0 ) ELSE mi % ( 2 ) END, mi), rsy * 1.2 * IFNULL(CASE WHEN ( 2 ) > 0 THEN mi / ( 2 ) ELSE mi / ( 0 ) END, 0), title, radial FROM facet0, cst ), radygrid(m, mi, tty, wty, ttx, ttx2, xorigin, yorigin) AS ( SELECT m, mi, rsy / 2 / ((maxy-miny)/stepy) * (value-1) AS tty, coalesce(NULL, miny + stepy * (value-1)) AS wty, xorigin, xorigin+rsx, xorigin + rsx / 2, yorigin + rsy / 2 FROM generate_series(1), yaxis, cst, facet LEFT JOIN ylabels ON ylabels.y = (miny + (value-1) * stepy) WHERE radial AND stop = 1+1.0*(maxy-miny)/stepy ), ypos(m, mi, pcx, pcy, radial) AS ( SELECT m, mi, xorigin, yorigin + CASE WHEN 0 BETWEEN miny AND maxy THEN rsy - (0 - miny) * rsy / (maxy-miny) WHEN 0 >= maxy THEN 0 ELSE rsy END, radial FROM yaxis, cst, facet WHERE NOT radial UNION ALL SELECT m, mi, xorigin + rsx / 2, yorigin + (CASE WHEN 0 BETWEEN miny AND maxy THEN rsy - (0 - miny) * rsy / 2 / (maxy-miny) WHEN 0 >= maxy THEN 0 ELSE rsy END ) / 2, radial FROM yaxis, cst, facet WHERE radial ) SELECT * FROM radygrid , ypos; } {} } ;# end ifcapable vtab # 2021-03-19 # dbsqlfuzz 01b8355086998f0a452cb31208e80b9d29ca739a # # Correlated CTEs should not be materialized. # reset_db do_execsql_test 10.1 { SELECT 1 AS c WHERE ( SELECT ( WITH t1(a) AS (VALUES( c )) SELECT ( SELECT t1a.a FROM t1 AS t1a, t1 AS t1x ) FROM t1 AS xyz GROUP BY 1 ) ) } {1} # 2021-05-21 # Forum post https://sqlite.org/forum/forumpost/aa4a7a3980 # ifcapable altertable { reset_db do_execsql_test 11.1 { CREATE TABLE t1(a); CREATE VIEW v2(c) AS WITH x AS ( WITH y AS ( WITH z AS(SELECT * FROM t1) SELECT * FROM v2 ) SELECT a ) SELECT * from t1; ALTER TABLE t1 RENAME COLUMN a TO b; SELECT sql FROM sqlite_schema WHERE name='t1'; } {{CREATE TABLE t1(b)}} do_catchsql_test 11.2 { INSERT INTO t1 VALUES(55); SELECT * FROM v2; } {0 55} do_catchsql_test 11.3 { DROP VIEW v2; CREATE VIEW v2(c) AS WITH x AS ( WITH y AS ( WITH z AS(SELECT * FROM t1) SELECT * FROM v2 ) SELECT a ) SELECT * from t1, x; SELECT * FROM v2; } {1 {no such column: a}} do_catchsql_test 11.4 { DROP VIEW v2; CREATE VIEW v2(c) AS WITH x AS ( WITH y AS ( WITH z AS(SELECT * FROM t1) SELECT * FROM v2 ) SELECT * ) SELECT * from t1, x; SELECT * FROM v2; } {1 {no tables specified}} do_catchsql_test 11.5 { WITH x AS ( WITH y AS ( WITH z AS(SELECT * FROM t1) SELECT * FROM no_such_table ) SELECT a ) SELECT * from t1; } {0 55} } # 2021-05-23 dbsqlfuzz 6b7a144674e215f06ddfeb9042c873d9ee956ac0 */ reset_db ifcapable altertable { do_execsql_test 12.1 { CREATE TABLE t1(a); INSERT INTO t1 VALUES(1),('hello'),(4.25),(NULL),(x'3c626c6f623e'); CREATE VIEW v2(c) AS WITH x AS (WITH y AS (WITH z AS(SELECT * FROM t1) SELECT * FROM v2) SELECT a) SELECT * from t1; CREATE VIEW v3(c) AS WITH x AS (WITH y AS (WITH z AS(SELECT * FROM v2) SELECT * FROM v3) SELECT a) SELECT * from t1; ALTER TABLE t1 RENAME TO t1x; SELECT quote(c) FROM v3; } {1 'hello' 4.25 NULL X'3C626C6F623E'} } # 2021-08-11 https://sqlite.org/forum/forumpost/d496c3d29bc93736 reset_db do_execsql_test 13.1 { WITH t1(x) AS (SELECT 111), t2(y) AS (SELECT 222), t3(z) AS (SELECT * FROM t2 WHERE false UNION ALL SELECT * FROM t2) SELECT * FROM t1, t3; } {111 222} finish_test |
Changes to test/with3.test.
︙ | ︙ | |||
28 29 30 31 32 33 34 35 36 37 38 39 40 41 | WITH i(x) AS ( WITH j AS (SELECT 10) SELECT 5 FROM t0 UNION SELECT 8 FROM m ) SELECT * FROM i; } {1 {no such table: m}} # Additional test cases that came out of the work to # fix for Kostya's problem. # do_execsql_test 2.0 { WITH x1 AS (SELECT 10), x2 AS (SELECT 11), | > > > > > > > > | 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | WITH i(x) AS ( WITH j AS (SELECT 10) SELECT 5 FROM t0 UNION SELECT 8 FROM m ) SELECT * FROM i; } {1 {no such table: m}} # 2019-11-09 dbfuzzcheck find do_catchsql_test 1.1 { CREATE VIEW v1(x,y) AS WITH t1(a,b) AS (VALUES(1,2)) SELECT * FROM nosuchtable JOIN t1; SELECT * FROM v1; } {1 {no such table: main.nosuchtable}} # Additional test cases that came out of the work to # fix for Kostya's problem. # do_execsql_test 2.0 { WITH x1 AS (SELECT 10), x2 AS (SELECT 11), |
︙ | ︙ | |||
77 78 79 80 81 82 83 | } do_eqp_test 3.1.2 { WITH cnt(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM cnt LIMIT 1) SELECT * FROM cnt, y1 WHERE i=a } [string map {"\n " \n} { QUERY PLAN | | | | | | | | | | | | | | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | } do_eqp_test 3.1.2 { WITH cnt(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM cnt LIMIT 1) SELECT * FROM cnt, y1 WHERE i=a } [string map {"\n " \n} { QUERY PLAN |--MATERIALIZE cnt | |--SETUP | | `--SCAN CONSTANT ROW | `--RECURSIVE STEP | `--SCAN cnt |--SCAN cnt `--SEARCH y1 USING INDEX y1a (a=?) }] do_eqp_test 3.1.3 { WITH cnt(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM cnt LIMIT 1000000) SELECT * FROM cnt, y1 WHERE i=a } [string map {"\n " \n} { QUERY PLAN |--MATERIALIZE cnt | |--SETUP | | `--SCAN CONSTANT ROW | `--RECURSIVE STEP | `--SCAN cnt |--SCAN y1 `--SEARCH cnt USING AUTOMATIC COVERING INDEX (i=?) }] } do_execsql_test 3.2.1 { CREATE TABLE w1(pk INTEGER PRIMARY KEY, x INTEGER); CREATE TABLE w2(pk INTEGER PRIMARY KEY); } do_eqp_test 3.2.2 { WITH RECURSIVE c(w,id) AS (SELECT 0, (SELECT pk FROM w2 LIMIT 1) UNION ALL SELECT c.w + 1, x FROM w1, c LIMIT 1) SELECT * FROM c, w2, w1 WHERE c.id=w2.pk AND c.id=w1.pk; } { QUERY PLAN |--MATERIALIZE c | |--SETUP | | |--SCAN CONSTANT ROW | | `--SCALAR SUBQUERY xxxxxx | | `--SCAN w2 | `--RECURSIVE STEP | |--SCAN w1 | `--SCAN c |--SCAN c |--SEARCH w2 USING INTEGER PRIMARY KEY (rowid=?) `--SEARCH w1 USING INTEGER PRIMARY KEY (rowid=?) } do_execsql_test 4.0 { WITH t5(t5col1) AS ( SELECT ( WITH t3(t3col1) AS ( WITH t2 AS ( WITH t1 AS (SELECT 1 AS c1 GROUP BY 1) SELECT a.c1 FROM t1 AS a, t1 AS b WHERE anoncol1 = 1 ) SELECT (SELECT 1 FROM t2) FROM t2 ) SELECT t3col1 FROM t3 WHERE t3col1 ) FROM (SELECT 1 AS anoncol1) ) SELECT t5col1, t5col1 FROM t5 } {1 1} do_execsql_test 4.1 { SELECT EXISTS ( WITH RECURSIVE Table0 AS ( WITH RECURSIVE Table0(Col0) AS (SELECT ALL 1 ) SELECT ALL ( WITH RECURSIVE Table0 AS ( WITH RECURSIVE Table0 AS ( WITH RECURSIVE Table0 AS (SELECT DISTINCT 1 GROUP BY 1 ) SELECT DISTINCT * FROM Table0 NATURAL INNER JOIN Table0 WHERE Col0 = 1 ) SELECT ALL (SELECT DISTINCT * FROM Table0) FROM Table0 WHERE Col0 = 1 ) SELECT ALL * FROM Table0 NATURAL INNER JOIN Table0 ) FROM Table0 ) SELECT DISTINCT * FROM Table0 NATURAL INNER JOIN Table0 ); } {1} # 2020-01-18 chrome ticket 1043236 # Correct handling of the sequence: # OP_OpenEphem # OP_OpenDup # Op_OpenEphem # OP_OpenDup # do_execsql_test 4.2 { SELECT ( WITH t1(a) AS (VALUES(1)) SELECT ( WITH t2(b) AS ( WITH t3(c) AS ( WITH t4(d) AS (VALUES('elvis')) SELECT t4a.d FROM t4 AS t4a JOIN t4 AS t4b LEFT JOIN t4 AS t4c ) SELECT c FROM t3 WHERE a = 1 ) SELECT t2a.b FROM t2 AS t2a JOIN t2 AS t2x ) FROM t1 GROUP BY 1 ) GROUP BY 1; } {elvis} # 2021-02-13 # Avoid manifesting the same CTE multiple times. # do_eqp_test 5.1 { WITH RECURSIVE c(x) AS (VALUES(0) UNION ALL SELECT x+1 FROM c WHERE x<1) SELECT x1.x||x2.x||x3.x||x4.x FROM c AS x1, c AS x2, c AS x3, c AS x4 ORDER BY 1; } { QUERY PLAN |--MATERIALIZE c | |--SETUP | | `--SCAN CONSTANT ROW | `--RECURSIVE STEP | `--SCAN c |--SCAN x1 |--SCAN x2 |--SCAN x3 |--SCAN x4 `--USE TEMP B-TREE FOR ORDER BY } do_execsql_test 5.2 { WITH RECURSIVE c(x) AS (VALUES(0) UNION ALL SELECT x+1 FROM c WHERE x<1) SELECT x1.x||x2.x||x3.x||x4.x FROM c AS x1, c AS x2, c AS x3, c AS x4 ORDER BY 1; } {0000 0001 0010 0011 0100 0101 0110 0111 1000 1001 1010 1011 1100 1101 1110 1111} #------------------------------------------------------------------------- # At one point this would incorrectly report "circular reference: cte1" # do_catchsql_test 6.0 { with cte1(x, y) AS ( select 1, 2, 3 ), cte2(z) as ( select 1 from cte1 ) select * from cte2, cte1; } {1 {table cte1 has 3 values for 2 columns}} do_catchsql_test 6.1 { with cte1(x, y) AS ( select 1, 2, 3 ), cte2(z) as ( select 1 from cte1 UNION ALL SELECT z+1 FROM cte2 WHERE z<5) select * from cte2, cte1; } {1 {table cte1 has 3 values for 2 columns}} finish_test |
Added test/with5.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 | # 2020-10-19 # # 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 recursive common table expressions with # multiple recursive terms in the compound select. # set testdir [file dirname $argv0] source $testdir/tester.tcl set ::testprefix with5 ifcapable {!cte} { finish_test return } do_execsql_test 100 { CREATE TABLE link(aa INT, bb INT); CREATE INDEX link_f ON link(aa,bb); CREATE INDEX link_t ON link(bb,aa); INSERT INTO link(aa,bb) VALUES (1,3), (5,3), (7,1), (7,9), (9,9), (5,11), (11,7), (2,4), (4,6), (8,6); } {} do_execsql_test 110 { WITH RECURSIVE closure(x) AS ( VALUES(1) UNION SELECT aa FROM closure, link WHERE link.bb=closure.x UNION SELECT bb FROM closure, link WHERE link.aa=closure.x ) SELECT x FROM closure ORDER BY x; } {1 3 5 7 9 11} do_execsql_test 111 { WITH RECURSIVE closure(x) AS ( VALUES(1) UNION SELECT aa FROM link, closure WHERE link.bb=closure.x UNION SELECT bb FROM closure, link WHERE link.aa=closure.x ) SELECT x FROM closure ORDER BY x; } {1 3 5 7 9 11} do_execsql_test 112 { WITH RECURSIVE closure(x) AS ( VALUES(1) UNION SELECT bb FROM closure, link WHERE link.aa=closure.x UNION SELECT aa FROM link, closure WHERE link.bb=closure.x ) SELECT x FROM closure ORDER BY x; } {1 3 5 7 9 11} do_execsql_test 113 { WITH RECURSIVE closure(x) AS ( VALUES(1),(200),(300),(400) INTERSECT VALUES(1) UNION SELECT bb FROM closure, link WHERE link.aa=closure.x UNION SELECT aa FROM link, closure WHERE link.bb=closure.x ) SELECT x FROM closure ORDER BY x; } {1 3 5 7 9 11} do_execsql_test 114 { WITH RECURSIVE closure(x) AS ( VALUES(1),(200),(300),(400) UNION ALL VALUES(2) UNION SELECT bb FROM closure, link WHERE link.aa=closure.x UNION SELECT aa FROM link, closure WHERE link.bb=closure.x ) SELECT x FROM closure ORDER BY x; } {1 2 3 4 5 6 7 8 9 11 200 300 400} do_catchsql_test 120 { WITH RECURSIVE closure(x) AS ( VALUES(1),(200),(300),(400) UNION ALL VALUES(2) UNION ALL SELECT bb FROM closure, link WHERE link.aa=closure.x UNION SELECT aa FROM link, closure WHERE link.bb=closure.x ) SELECT x FROM closure ORDER BY x; } {1 {circular reference: closure}} do_catchsql_test 121 { WITH RECURSIVE closure(x) AS ( VALUES(1),(200),(300),(400) UNION ALL VALUES(2) UNION SELECT bb FROM closure, link WHERE link.aa=closure.x UNION ALL SELECT aa FROM link, closure WHERE link.bb=closure.x ) SELECT x FROM closure ORDER BY x; } {1 {circular reference: closure}} do_execsql_test 130 { WITH RECURSIVE closure(x) AS ( SELECT 1 AS x UNION SELECT aa FROM link JOIN closure ON bb=x UNION SELECT bb FROM link JOIN closure on aa=x ORDER BY x LIMIT 4 ) SELECT * FROM closure; } {1 3 5 7} do_execsql_test 131 { WITH RECURSIVE closure(x) AS ( SELECT 1 AS x UNION ALL SELECT 2 UNION SELECT aa FROM link JOIN closure ON bb=x UNION SELECT bb FROM link JOIN closure on aa=x ORDER BY x LIMIT 4 ) SELECT * FROM closure; } {1 2 3 4} do_execsql_test 200 { CREATE TABLE linkA(aa1,aa2); INSERT INTO linkA(aa1,aa2) VALUES(1,3),(5,7),(9,11); CREATE TABLE linkB(bb1,bb2); INSERT INTO linkB(bb1,bb2) VALUES(7,9),(11,13),(3,5); CREATE TABLE linkC(cc1,cc2); INSERT INTO linkC(cc1,cc2) VALUES(1,2),(2,4),(6,8); CREATE TABLE linkD(dd1,dd2); INSERT INTO linkD(dd1,dd2) VALUES(4,6),(100,110); } {} do_execsql_test 210 { WITH RECURSIVE closure(x) AS ( VALUES(1) UNION ALL SELECT aa2 FROM linkA JOIN closure ON x=aa1 UNION ALL SELECT bb2 FROM linkB JOIN closure ON x=bb1 UNION ALL SELECT cc2 FROM linkC JOIN closure ON x=cc1 UNION ALL SELECT dd2 FROM linkD JOIN closure ON x=dd1 ) SELECT x FROM closure ORDER BY +x; } {1 2 3 4 5 6 7 8 9 11 13} do_execsql_test 220 { CREATE TABLE linkA_ipk(aa1 INTEGER PRIMARY KEY,aa2); INSERT INTO linkA_ipk(aa1,aa2) SELECT aa1, aa2 FROM linkA; CREATE TABLE linkB_ipk(bb1 INTEGER PRIMARY KEY,bb2); INSERT INTO linkB_ipk(bb1,bb2) SELECT bb1, bb2 FROM linkB; CREATE TABLE linkC_ipk(cc1 INTEGER PRIMARY KEY,cc2); INSERT INTO linkC_ipk(cc1,cc2) SELECT cc1, cc2 FROM linkC; CREATE TABLE linkD_ipk(dd1 INTEGER PRIMARY KEY,dd2); INSERT INTO linkD_ipk(dd1,dd2) SELECT dd1, dd2 FROM linkD; WITH RECURSIVE closure(x) AS ( VALUES(1) UNION ALL SELECT aa2 FROM linkA_ipk JOIN closure ON x=aa1 UNION ALL SELECT bb2 FROM linkB_ipk JOIN closure ON x=bb1 UNION ALL SELECT cc2 FROM linkC_ipk JOIN closure ON x=cc1 UNION ALL SELECT dd2 FROM linkD_ipk JOIN closure ON x=dd1 ) SELECT x FROM closure ORDER BY +x; } {1 2 3 4 5 6 7 8 9 11 13} finish_test |
Added test/with6.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 | # 2021-02-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 file is the MATERIALIZED hint to common table expressions # set testdir [file dirname $argv0] source $testdir/tester.tcl set ::testprefix with6 ifcapable {!cte} { finish_test return } do_execsql_test 100 { WITH c(x) AS (VALUES(0),(1)) SELECT c1.x||c2.x||c3.x FROM c c1, c c2, c c3; } {000 001 010 011 100 101 110 111} do_eqp_test 101 { WITH c(x) AS (VALUES(0),(1)) SELECT c1.x||c2.x||c3.x FROM c c1, c c2, c c3; } { QUERY PLAN |--MATERIALIZE c | `--SCAN 2 CONSTANT ROWS |--SCAN c1 |--SCAN c2 `--SCAN c3 } do_execsql_test 110 { WITH c(x) AS MATERIALIZED (VALUES(0),(1)) SELECT c1.x||c2.x||c3.x FROM c c1, c c2, c c3; } {000 001 010 011 100 101 110 111} do_eqp_test 111 { WITH c(x) AS MATERIALIZED (VALUES(0),(1)) SELECT c1.x||c2.x||c3.x FROM c c1, c c2, c c3; } { QUERY PLAN |--MATERIALIZE c | `--SCAN 2 CONSTANT ROWS |--SCAN c1 |--SCAN c2 `--SCAN c3 } # Even though the CTE is not materialized, the self-join optimization # kicks in and does the materialization for us. # do_execsql_test 120 { WITH c(x) AS NOT MATERIALIZED (VALUES(0),(1)) SELECT c1.x||c2.x||c3.x FROM c c1, c c2, c c3; } {000 001 010 011 100 101 110 111} do_eqp_test 121 { WITH c(x) AS NOT MATERIALIZED (VALUES(0),(1)) SELECT c1.x||c2.x||c3.x FROM c c1, c c2, c c3; } { QUERY PLAN |--MATERIALIZE c | `--SCAN 2 CONSTANT ROWS |--SCAN c1 |--SCAN c2 `--SCAN c3 } do_execsql_test 130 { WITH c(x) AS NOT MATERIALIZED (VALUES(0),(1)) SELECT c1.x||c2.x||c3.x FROM (SELECT x FROM c LIMIT 5) AS c1, (SELECT x FROM c LIMIT 5) AS c2, (SELECT x FROM c LIMIT 5) AS c3; } {000 001 010 011 100 101 110 111} do_eqp_test 131 { WITH c(x) AS NOT MATERIALIZED (VALUES(0),(1)) SELECT c1.x||c2.x||c3.x FROM (SELECT x FROM c LIMIT 5) AS c1, (SELECT x FROM c LIMIT 5) AS c2, (SELECT x FROM c LIMIT 5) AS c3; } { QUERY PLAN |--MATERIALIZE c1 | |--CO-ROUTINE c | | `--SCAN 2 CONSTANT ROWS | `--SCAN c |--MATERIALIZE c2 | |--CO-ROUTINE c | | `--SCAN 2 CONSTANT ROWS | `--SCAN c |--MATERIALIZE c3 | |--CO-ROUTINE c | | `--SCAN 2 CONSTANT ROWS | `--SCAN c |--SCAN c1 |--SCAN c2 `--SCAN c3 } # The (SELECT x FROM c LIMIT N) subqueries get materialized once each. # Show multiple materializations are shown. But there is only one # materialization for c, shown by the "SCAN 2 CONSTANT ROWS" line. # do_execsql_test 140 { WITH c(x) AS MATERIALIZED (VALUES(0),(1)) SELECT c1.x||c2.x||c3.x FROM (SELECT x FROM c LIMIT 5) AS c1, (SELECT x FROM c LIMIT 6) AS c2, (SELECT x FROM c LIMIT 7) AS c3; } {000 001 010 011 100 101 110 111} do_eqp_test 141 { WITH c(x) AS MATERIALIZED (VALUES(0),(1)) SELECT c1.x||c2.x||c3.x FROM (SELECT x FROM c LIMIT 5) AS c1, (SELECT x FROM c LIMIT 6) AS c2, (SELECT x FROM c LIMIT 7) AS c3; } { QUERY PLAN |--MATERIALIZE c1 | |--MATERIALIZE c | | `--SCAN 2 CONSTANT ROWS | `--SCAN c |--MATERIALIZE c2 | `--SCAN c |--MATERIALIZE c3 | `--SCAN c |--SCAN c1 |--SCAN c2 `--SCAN c3 } do_execsql_test 150 { WITH c(x) AS (VALUES(0),(1)) SELECT c1.x||c2.x||c3.x FROM (SELECT x FROM c LIMIT 5) AS c1, (SELECT x FROM c LIMIT 6) AS c2, (SELECT x FROM c LIMIT 7) AS c3; } {000 001 010 011 100 101 110 111} do_eqp_test 151 { WITH c(x) AS (VALUES(0),(1)) SELECT c1.x||c2.x||c3.x FROM (SELECT x FROM c LIMIT 5) AS c1, (SELECT x FROM c LIMIT 6) AS c2, (SELECT x FROM c LIMIT 7) AS c3; } { QUERY PLAN |--MATERIALIZE c1 | |--MATERIALIZE c | | `--SCAN 2 CONSTANT ROWS | `--SCAN c |--MATERIALIZE c2 | `--SCAN c |--MATERIALIZE c3 | `--SCAN c |--SCAN c1 |--SCAN c2 `--SCAN c3 } do_execsql_test 160 { WITH c(x) AS (VALUES(0),(1)) SELECT c2.x + 100*(SELECT sum(x+1) FROM c WHERE c.x<=c2.x) FROM c AS c2 WHERE c2.x<10; } {100 301} do_eqp_test 161 { WITH c(x) AS (VALUES(0),(1)) SELECT c2.x + 100*(SELECT sum(x+1) FROM c WHERE c.x<=c2.x) FROM c AS c2 WHERE c2.x<10; } { QUERY PLAN |--MATERIALIZE c | `--SCAN 2 CONSTANT ROWS |--SCAN c2 `--CORRELATED SCALAR SUBQUERY xxxxxx `--SCAN c } do_execsql_test 170 { WITH c(x) AS NOT MATERIALIZED (VALUES(0),(1)) SELECT c2.x + 100*(SELECT sum(x+1) FROM c WHERE c.x<=c2.x) FROM c AS c2 WHERE c2.x<10; } {100 301} do_eqp_test 171 { WITH c(x) AS NOT MATERIALIZED (VALUES(0),(1)) SELECT c2.x + 100*(SELECT sum(x+1) FROM c WHERE c.x<=c2.x) FROM c AS c2 WHERE c2.x<10; } { QUERY PLAN |--CO-ROUTINE c | `--SCAN 2 CONSTANT ROWS |--SCAN c2 `--CORRELATED SCALAR SUBQUERY xxxxxx |--CO-ROUTINE c | `--SCAN 2 CONSTANT ROWS `--SCAN c } do_execsql_test 200 { CREATE TABLE t1(x); INSERT INTO t1(x) VALUES(4); CREATE VIEW t2(y) AS WITH c(z) AS (VALUES(4),(5),(6)) SELECT c1.z+c2.z*100+t1.x*10000 FROM t1, (SELECT z FROM c LIMIT 5) AS c1, (SELECT z FROM c LIMIT 5) AS c2; SELECT y FROM t2 ORDER BY y; } {40404 40405 40406 40504 40505 40506 40604 40605 40606} do_execsql_test 210 { DROP VIEW t2; CREATE VIEW t2(y) AS WITH c(z) AS NOT MATERIALIZED (VALUES(4),(5),(6)) SELECT c1.z+c2.z*100+t1.x*10000 FROM t1, (SELECT z FROM c LIMIT 5) AS c1, (SELECT z FROM c LIMIT 5) AS c2; SELECT y FROM t2 ORDER BY y; } {40404 40405 40406 40504 40505 40506 40604 40605 40606} do_eqp_test 211 { SELECT y FROM t2 ORDER BY y; } { QUERY PLAN |--MATERIALIZE c1 | |--MATERIALIZE c | | `--SCAN 3 CONSTANT ROWS | `--SCAN c |--MATERIALIZE c2 | `--SCAN c |--SCAN c1 |--SCAN c2 |--SCAN t1 `--USE TEMP B-TREE FOR ORDER BY } do_execsql_test 220 { DROP VIEW t2; CREATE VIEW t2(y) AS WITH c(z) AS MATERIALIZED (VALUES(4),(5),(6)) SELECT c1.z+c2.z*100+t1.x*10000 FROM t1, (SELECT z FROM c LIMIT 5) AS c1, (SELECT z FROM c LIMIT 5) AS c2; SELECT y FROM t2 ORDER BY y; } {40404 40405 40406 40504 40505 40506 40604 40605 40606} finish_test |
Changes to test/without_rowid1.test.
︙ | ︙ | |||
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 | # This file implements regression tests for SQLite library. The # focus of this file is testing WITHOUT ROWID tables. # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix without_rowid1 # Create and query a WITHOUT ROWID table. # do_execsql_test without_rowid1-1.0 { CREATE TABLE t1(a,b,c,d, PRIMARY KEY(c,a)) WITHOUT ROWID; CREATE INDEX t1bd ON t1(b, d); INSERT INTO t1 VALUES('journal','sherman','ammonia','helena'); INSERT INTO t1 VALUES('dynamic','juliet','flipper','command'); INSERT INTO t1 VALUES('journal','sherman','gamma','patriot'); INSERT INTO t1 VALUES('arctic','sleep','ammonia','helena'); SELECT *, '|' FROM t1 ORDER BY c, a; } {arctic sleep ammonia helena | journal sherman ammonia helena | dynamic juliet flipper command | journal sherman gamma patriot |} integrity_check without_rowid1-1.0ic do_execsql_test without_rowid1-1.1 { SELECT *, '|' FROM t1 ORDER BY +c, a; } {arctic sleep ammonia helena | journal sherman ammonia helena | dynamic juliet flipper command | journal sherman gamma patriot |} do_execsql_test without_rowid1-1.2 { SELECT *, '|' FROM t1 ORDER BY c DESC, a DESC; | > > > > > > > > > > > | 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 | # This file implements regression tests for SQLite library. The # focus of this file is testing WITHOUT ROWID tables. # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix without_rowid1 proc do_execsql_test_if_vtab {tn sql {res {}}} { ifcapable vtab { uplevel [list do_execsql_test $tn $sql $res] } } # Create and query a WITHOUT ROWID table. # do_execsql_test without_rowid1-1.0 { CREATE TABLE t1(a,b,c,d, PRIMARY KEY(c,a)) WITHOUT ROWID; CREATE INDEX t1bd ON t1(b, d); INSERT INTO t1 VALUES('journal','sherman','ammonia','helena'); INSERT INTO t1 VALUES('dynamic','juliet','flipper','command'); INSERT INTO t1 VALUES('journal','sherman','gamma','patriot'); INSERT INTO t1 VALUES('arctic','sleep','ammonia','helena'); SELECT *, '|' FROM t1 ORDER BY c, a; } {arctic sleep ammonia helena | journal sherman ammonia helena | dynamic juliet flipper command | journal sherman gamma patriot |} integrity_check without_rowid1-1.0ic do_execsql_test_if_vtab without_rowid1-1.0ixi { SELECT name, key FROM pragma_index_xinfo('t1'); } {c 1 a 1 b 0 d 0} do_execsql_test_if_vtab without_rowid1-1.0tl { SELECT wr FROM pragma_table_list('t1'); } {1} do_execsql_test without_rowid1-1.1 { SELECT *, '|' FROM t1 ORDER BY +c, a; } {arctic sleep ammonia helena | journal sherman ammonia helena | dynamic juliet flipper command | journal sherman gamma patriot |} do_execsql_test without_rowid1-1.2 { SELECT *, '|' FROM t1 ORDER BY c DESC, a DESC; |
︙ | ︙ | |||
94 95 96 97 98 99 100 | # Verify that ANALYZE works # do_execsql_test without_rowid1-1.50 { ANALYZE; SELECT * FROM sqlite_stat1 ORDER BY idx; } {t1 t1 {4 2 1} t1 t1bd {4 2 2}} | < < < < < > > > > > > > > > > > > > > > > > > | 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 | # Verify that ANALYZE works # do_execsql_test without_rowid1-1.50 { ANALYZE; SELECT * FROM sqlite_stat1 ORDER BY idx; } {t1 t1 {4 2 1} t1 t1bd {4 2 2}} ifcapable stat4 { do_execsql_test without_rowid1-1.52 { SELECT DISTINCT tbl, idx FROM sqlite_stat4 ORDER BY idx; } {t1 t1 t1 t1bd} } #---------- do_execsql_test 2.1.1 { CREATE TABLE t4 (a COLLATE nocase PRIMARY KEY, b) WITHOUT ROWID; INSERT INTO t4 VALUES('abc', 'def'); SELECT * FROM t4; } {abc def} do_execsql_test 2.1.2 { UPDATE t4 SET a = 'ABC'; SELECT * FROM t4; } {ABC def} do_execsql_test_if_vtab 2.1.3 { SELECT name, coll, key FROM pragma_index_xinfo('t4'); } {a nocase 1 b BINARY 0} do_execsql_test 2.2.1 { DROP TABLE t4; CREATE TABLE t4 (b, a COLLATE nocase PRIMARY KEY) WITHOUT ROWID; INSERT INTO t4(a, b) VALUES('abc', 'def'); SELECT * FROM t4; } {def abc} do_execsql_test 2.2.2 { UPDATE t4 SET a = 'ABC', b = 'xyz'; SELECT * FROM t4; } {xyz ABC} do_execsql_test_if_vtab 2.2.3 { SELECT name, coll, key FROM pragma_index_xinfo('t4'); } {a nocase 1 b BINARY 0} do_execsql_test 2.3.1 { CREATE TABLE t5 (a, b, PRIMARY KEY(b, a)) WITHOUT ROWID; INSERT INTO t5(a, b) VALUES('abc', 'def'); UPDATE t5 SET a='abc', b='def'; } {} do_execsql_test_if_vtab 2.3.2 { SELECT name, coll, key FROM pragma_index_xinfo('t5'); } {b BINARY 1 a BINARY 1} do_execsql_test 2.4.1 { CREATE TABLE t6 ( a COLLATE nocase, b, c UNIQUE, PRIMARY KEY(b, a) ) WITHOUT ROWID; INSERT INTO t6(a, b, c) VALUES('abc', 'def', 'ghi'); UPDATE t6 SET a='ABC', c='ghi'; } {} do_execsql_test 2.4.2 { SELECT * FROM t6 ORDER BY b, a; SELECT * FROM t6 ORDER BY c; } {ABC def ghi ABC def ghi} do_execsql_test_if_vtab 2.4.3 { SELECT name, coll, key FROM pragma_index_xinfo('t6'); } {b BINARY 1 a nocase 1 c BINARY 0} #------------------------------------------------------------------------- # Unless the destination table is completely empty, the xfer optimization # is disabled for WITHOUT ROWID tables. The following tests check for # some problems that might occur if this were not the case. # reset_db |
︙ | ︙ | |||
316 317 318 319 320 321 322 | a INT CHECK( rowid!=33 ), b TEXT PRIMARY KEY ); INSERT INTO t70a(a,b) VALUES(99,'hello'); } {} do_catchsql_test 7.2 { INSERT INTO t70a(rowid,a,b) VALUES(33,99,'xyzzy'); | | | 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 | a INT CHECK( rowid!=33 ), b TEXT PRIMARY KEY ); INSERT INTO t70a(a,b) VALUES(99,'hello'); } {} do_catchsql_test 7.2 { INSERT INTO t70a(rowid,a,b) VALUES(33,99,'xyzzy'); } {1 {CHECK constraint failed: rowid!=33}} do_catchsql_test 7.3 { CREATE TABLE t70b( a INT CHECK( rowid!=33 ), b TEXT PRIMARY KEY ) WITHOUT ROWID; } {1 {no such column: rowid}} |
︙ | ︙ | |||
351 352 353 354 355 356 357 | UPDATE t2 SET b=1 WHERE b=''; } do_execsql_test 10.1 { DELETE FROM t2 WHERE b=1 } | > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | UPDATE t2 SET b=1 WHERE b=''; } do_execsql_test 10.1 { DELETE FROM t2 WHERE b=1 } #------------------------------------------------------------------------- # UNIQUE constraint violation in an UPDATE with a multi-column PK. # reset_db do_execsql_test 10.0 { CREATE TABLE t1(a, b, c UNIQUE, PRIMARY KEY(a, b)) WITHOUT ROWID; INSERT INTO t1 VALUES('a', 'a', 1); INSERT INTO t1 VALUES('a', 'b', 2); INSERT INTO t1 VALUES('b', 'a', 3); INSERT INTO t1 VALUES('b', 'b', 4); } do_catchsql_test 10.1 { UPDATE t1 SET c=1 WHERE (a, b) = ('a', 'a'); } {0 {}} do_catchsql_test 10.2 { UPDATE t1 SET c=1 WHERE (a, b) = ('a', 'b'); } {1 {UNIQUE constraint failed: t1.c}} do_catchsql_test 10.3 { UPDATE t1 SET c=1 WHERE (a, b) = ('b', 'a'); } {1 {UNIQUE constraint failed: t1.c}} do_catchsql_test 10.4 { UPDATE t1 SET c=1 WHERE (a, b) = ('b', 'b'); } {1 {UNIQUE constraint failed: t1.c}} do_catchsql_test 10.5 { UPDATE t1 SET c=1 WHERE (a, b) = ('c', 'c'); } {0 {}} do_execsql_test 10.6 { CREATE TRIGGER t1_tr BEFORE UPDATE ON t1 BEGIN DELETE FROM t1 WHERE a = new.a; END; UPDATE t1 SET c = c+1 WHERE a = 'a'; SELECT * FROM t1; } {b a 3 b b 4} # 2019-04-29 ticket https://www.sqlite.org/src/info/3182d3879020ef3 do_execsql_test 11.1 { CREATE TABLE t11(a TEXT PRIMARY KEY, b INT) WITHOUT ROWID; CREATE INDEX t11a ON t11(a COLLATE NOCASE); INSERT INTO t11(a,b) VALUES ('A',1),('a',2); PRAGMA integrity_check; SELECT a FROM t11 ORDER BY a COLLATE binary; } {ok A a} # 2019-05-13 ticket https://www.sqlite.org/src/info/bba7b69f9849b5b do_execsql_test 12.1 { DROP TABLE IF EXISTS t0; CREATE TABLE t0 (c0 INTEGER PRIMARY KEY DESC, c1 UNIQUE DEFAULT NULL) WITHOUT ROWID; INSERT INTO t0(c0) VALUES (1), (2), (3), (4), (5); REINDEX; PRAGMA integrity_check; } {ok} # 2019-11-07 ticket https://www.sqlite.org/src/info/302027baf1374498 # The xferCompatibleIndex() function confuses a PRIMARY KEY index # with a UNIQUE index. # do_execsql_test 13.10 { DROP TABLE IF EXISTS t0; DROP TABLE IF EXISTS t1; CREATE TABLE t0( c0, c1 UNIQUE, PRIMARY KEY(c1, c1) ) WITHOUT ROWID; INSERT INTO t0(c0,c1) VALUES('abc','xyz'); CREATE TABLE t1( c0, c1 UNIQUE, PRIMARY KEY(c1, c1) ) WITHOUT ROWID; INSERT INTO t1 SELECT * FROM t0; PRAGMA integrity_check; SELECT * FROM t0, t1; } {ok abc xyz abc xyz} # 2021-05-13 https://sqlite.org/forum/forumpost/6c8960f545 reset_db ifcapable altertable { do_execsql_test 14.1 { CREATE TABLE t1(a INT PRIMARY KEY) WITHOUT ROWID; INSERT INTO t1(a) VALUES(10); ALTER TABLE t1 ADD COLUMN b INT; SELECT * FROM t1 WHERE a=20 OR (a=10 AND b=10); } {} do_execsql_test 14.2 { CREATE TABLE dual AS SELECT 'X' AS dummy; EXPLAIN QUERY PLAN SELECT * FROM dual, t1 WHERE a=10 AND b=10; } {~/b=/} } finish_test |
Changes to test/without_rowid3.test.
︙ | ︙ | |||
413 414 415 416 417 418 419 | INSERT INTO ab VALUES(1, 'b'); INSERT INTO cd VALUES(1, 'd'); INSERT INTO ef VALUES(1, 'e'); } } {} do_test without_rowid3-3.1.3 { catchsql { UPDATE ab SET a = 5 } | | | | 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 | INSERT INTO ab VALUES(1, 'b'); INSERT INTO cd VALUES(1, 'd'); INSERT INTO ef VALUES(1, 'e'); } } {} do_test without_rowid3-3.1.3 { catchsql { UPDATE ab SET a = 5 } } {1 {CHECK constraint failed: e!=5}} do_test without_rowid3-3.1.4 { execsql { SELECT * FROM ab } } {1 b} do_test without_rowid3-3.1.4 { execsql BEGIN; catchsql { UPDATE ab SET a = 5 } } {1 {CHECK constraint failed: e!=5}} do_test without_rowid3-3.1.5 { execsql COMMIT; execsql { SELECT * FROM ab; SELECT * FROM cd; SELECT * FROM ef } } {1 b 1 d 1 e} do_test without_rowid3-3.2.1 { execsql BEGIN; |
︙ | ︙ | |||
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 | drop_all_tables ifcapable altertable { do_test without_rowid3-14.1.1 { # Adding a column with a REFERENCES clause is not supported. execsql { CREATE TABLE t1(a PRIMARY KEY) WITHOUT rowid; CREATE TABLE t2(a, b); } catchsql { ALTER TABLE t2 ADD COLUMN c REFERENCES t1 } } {0 {}} do_test without_rowid3-14.1.2 { catchsql { ALTER TABLE t2 ADD COLUMN d DEFAULT NULL REFERENCES t1 } } {0 {}} do_test without_rowid3-14.1.3 { catchsql { ALTER TABLE t2 ADD COLUMN e REFERENCES t1 DEFAULT NULL} } {0 {}} do_test without_rowid3-14.1.4 { catchsql { ALTER TABLE t2 ADD COLUMN f REFERENCES t1 DEFAULT 'text'} } {1 {Cannot add a REFERENCES column with non-NULL default value}} do_test without_rowid3-14.1.5 { catchsql { ALTER TABLE t2 ADD COLUMN g DEFAULT CURRENT_TIME REFERENCES t1 } } {1 {Cannot add a REFERENCES column with non-NULL default value}} do_test without_rowid3-14.1.6 { execsql { PRAGMA foreign_keys = off; ALTER TABLE t2 ADD COLUMN h DEFAULT 'text' REFERENCES t1; PRAGMA foreign_keys = on; | > | | | | | | 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 | drop_all_tables ifcapable altertable { do_test without_rowid3-14.1.1 { # Adding a column with a REFERENCES clause is not supported. execsql { CREATE TABLE t1(a PRIMARY KEY) WITHOUT rowid; CREATE TABLE t2(a, b); INSERT INTO t2(a,b) VALUES(1,2); } catchsql { ALTER TABLE t2 ADD COLUMN c REFERENCES t1 } } {0 {}} do_test without_rowid3-14.1.2 { catchsql { ALTER TABLE t2 ADD COLUMN d DEFAULT NULL REFERENCES t1 } } {0 {}} do_test without_rowid3-14.1.3 { catchsql { ALTER TABLE t2 ADD COLUMN e REFERENCES t1 DEFAULT NULL} } {0 {}} do_test without_rowid3-14.1.4 { catchsql { ALTER TABLE t2 ADD COLUMN f REFERENCES t1 DEFAULT 'text'} } {1 {Cannot add a REFERENCES column with non-NULL default value}} do_test without_rowid3-14.1.5 { catchsql { ALTER TABLE t2 ADD COLUMN g DEFAULT CURRENT_TIME REFERENCES t1 } } {1 {Cannot add a REFERENCES column with non-NULL default value}} do_test without_rowid3-14.1.6 { execsql { PRAGMA foreign_keys = off; ALTER TABLE t2 ADD COLUMN h DEFAULT 'text' REFERENCES t1; PRAGMA foreign_keys = on; SELECT sql FROM sqlite_schema WHERE name='t2'; } } {{CREATE TABLE t2(a, b, c REFERENCES t1, d DEFAULT NULL REFERENCES t1, e REFERENCES t1 DEFAULT NULL, h DEFAULT 'text' REFERENCES t1)}} # Test the sqlite_rename_parent() function directly. # proc test_rename_parent {zCreate zOld zNew} { db eval {SELECT sqlite_rename_table( 'main', 'table', 't1', $zCreate, $zOld, $zNew, 0 )} } sqlite3_test_control SQLITE_TESTCTRL_INTERNAL_FUNCTIONS db do_test without_rowid3-14.2.1.1 { test_rename_parent {CREATE TABLE t1(a REFERENCES t2)} t2 t3 } {{CREATE TABLE t1(a REFERENCES "t3")}} do_test without_rowid3-14.2.1.2 { test_rename_parent {CREATE TABLE t1(a REFERENCES t2)} t4 t3 } {{CREATE TABLE t1(a REFERENCES t2)}} do_test without_rowid3-14.2.1.3 { test_rename_parent {CREATE TABLE t1(a REFERENCES "t2")} t2 t3 } {{CREATE TABLE t1(a REFERENCES "t3")}} sqlite3_test_control SQLITE_TESTCTRL_INTERNAL_FUNCTIONS db # Test ALTER TABLE RENAME TABLE a bit. # do_test without_rowid3-14.2.2.1 { drop_all_tables execsql { CREATE TABLE t1(a PRIMARY KEY, b REFERENCES t1) WITHOUT rowid; CREATE TABLE t2(a PRIMARY KEY, b REFERENCES t1, c REFERENCES t2) WITHOUT rowid; CREATE TABLE t3(a REFERENCES t1, b REFERENCES t2, c REFERENCES t1); } execsql { SELECT sql FROM sqlite_schema WHERE type = 'table'} } [list \ {CREATE TABLE t1(a PRIMARY KEY, b REFERENCES t1) WITHOUT rowid} \ {CREATE TABLE t2(a PRIMARY KEY, b REFERENCES t1, c REFERENCES t2) WITHOUT rowid} \ {CREATE TABLE t3(a REFERENCES t1, b REFERENCES t2, c REFERENCES t1)} \ ] do_test without_rowid3-14.2.2.2 { execsql { ALTER TABLE t1 RENAME TO t4 } execsql { SELECT sql FROM sqlite_schema WHERE type = 'table'} } [list \ {CREATE TABLE "t4"(a PRIMARY KEY, b REFERENCES "t4") WITHOUT rowid} \ {CREATE TABLE t2(a PRIMARY KEY, b REFERENCES "t4", c REFERENCES t2) WITHOUT rowid} \ {CREATE TABLE t3(a REFERENCES "t4", b REFERENCES t2, c REFERENCES "t4")} \ ] do_test without_rowid3-14.2.2.3 { |
︙ | ︙ | |||
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 | # drop_all_tables do_test without_rowid3-14.1tmp.1 { # Adding a column with a REFERENCES clause is not supported. execsql { CREATE TEMP TABLE t1(a PRIMARY KEY) WITHOUT rowid; CREATE TEMP TABLE t2(a, b); } catchsql { ALTER TABLE t2 ADD COLUMN c REFERENCES t1 } } {0 {}} do_test without_rowid3-14.1tmp.2 { catchsql { ALTER TABLE t2 ADD COLUMN d DEFAULT NULL REFERENCES t1 } } {0 {}} do_test without_rowid3-14.1tmp.3 { catchsql { ALTER TABLE t2 ADD COLUMN e REFERENCES t1 DEFAULT NULL} } {0 {}} do_test without_rowid3-14.1tmp.4 { catchsql { ALTER TABLE t2 ADD COLUMN f REFERENCES t1 DEFAULT 'text'} } {1 {Cannot add a REFERENCES column with non-NULL default value}} do_test without_rowid3-14.1tmp.5 { catchsql { ALTER TABLE t2 ADD COLUMN g DEFAULT CURRENT_TIME REFERENCES t1 } } {1 {Cannot add a REFERENCES column with non-NULL default value}} do_test without_rowid3-14.1tmp.6 { execsql { PRAGMA foreign_keys = off; ALTER TABLE t2 ADD COLUMN h DEFAULT 'text' REFERENCES t1; PRAGMA foreign_keys = on; | > | | | | | | 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 | # drop_all_tables do_test without_rowid3-14.1tmp.1 { # Adding a column with a REFERENCES clause is not supported. execsql { CREATE TEMP TABLE t1(a PRIMARY KEY) WITHOUT rowid; CREATE TEMP TABLE t2(a, b); INSERT INTO temp.t2(a,b) VALUES(1,2); } catchsql { ALTER TABLE t2 ADD COLUMN c REFERENCES t1 } } {0 {}} do_test without_rowid3-14.1tmp.2 { catchsql { ALTER TABLE t2 ADD COLUMN d DEFAULT NULL REFERENCES t1 } } {0 {}} do_test without_rowid3-14.1tmp.3 { catchsql { ALTER TABLE t2 ADD COLUMN e REFERENCES t1 DEFAULT NULL} } {0 {}} do_test without_rowid3-14.1tmp.4 { catchsql { ALTER TABLE t2 ADD COLUMN f REFERENCES t1 DEFAULT 'text'} } {1 {Cannot add a REFERENCES column with non-NULL default value}} do_test without_rowid3-14.1tmp.5 { catchsql { ALTER TABLE t2 ADD COLUMN g DEFAULT CURRENT_TIME REFERENCES t1 } } {1 {Cannot add a REFERENCES column with non-NULL default value}} do_test without_rowid3-14.1tmp.6 { execsql { PRAGMA foreign_keys = off; ALTER TABLE t2 ADD COLUMN h DEFAULT 'text' REFERENCES t1; PRAGMA foreign_keys = on; SELECT sql FROM temp.sqlite_schema WHERE name='t2'; } } {{CREATE TABLE t2(a, b, c REFERENCES t1, d DEFAULT NULL REFERENCES t1, e REFERENCES t1 DEFAULT NULL, h DEFAULT 'text' REFERENCES t1)}} sqlite3_test_control SQLITE_TESTCTRL_INTERNAL_FUNCTIONS db do_test without_rowid3-14.2tmp.1.1 { test_rename_parent {CREATE TABLE t1(a REFERENCES t2)} t2 t3 } {{CREATE TABLE t1(a REFERENCES "t3")}} do_test without_rowid3-14.2tmp.1.2 { test_rename_parent {CREATE TABLE t1(a REFERENCES t2)} t4 t3 } {{CREATE TABLE t1(a REFERENCES t2)}} do_test without_rowid3-14.2tmp.1.3 { test_rename_parent {CREATE TABLE t1(a REFERENCES "t2")} t2 t3 } {{CREATE TABLE t1(a REFERENCES "t3")}} sqlite3_test_control SQLITE_TESTCTRL_INTERNAL_FUNCTIONS db # Test ALTER TABLE RENAME TABLE a bit. # do_test without_rowid3-14.2tmp.2.1 { drop_all_tables execsql { CREATE TEMP TABLE t1(a PRIMARY KEY, b REFERENCES t1) WITHOUT rowid; CREATE TEMP TABLE t2(a PRIMARY KEY, b REFERENCES t1, c REFERENCES t2) WITHOUT rowid; CREATE TEMP TABLE t3(a REFERENCES t1, b REFERENCES t2, c REFERENCES t1); } execsql { SELECT sql FROM sqlite_temp_schema WHERE type = 'table'} } [list \ {CREATE TABLE t1(a PRIMARY KEY, b REFERENCES t1) WITHOUT rowid} \ {CREATE TABLE t2(a PRIMARY KEY, b REFERENCES t1, c REFERENCES t2) WITHOUT rowid} \ {CREATE TABLE t3(a REFERENCES t1, b REFERENCES t2, c REFERENCES t1)} \ ] do_test without_rowid3-14.2tmp.2.2 { execsql { ALTER TABLE t1 RENAME TO t4 } execsql { SELECT sql FROM temp.sqlite_schema WHERE type = 'table'} } [list \ {CREATE TABLE "t4"(a PRIMARY KEY, b REFERENCES "t4") WITHOUT rowid} \ {CREATE TABLE t2(a PRIMARY KEY, b REFERENCES "t4", c REFERENCES t2) WITHOUT rowid} \ {CREATE TABLE t3(a REFERENCES "t4", b REFERENCES t2, c REFERENCES "t4")} \ ] do_test without_rowid3-14.2tmp.2.3 { |
︙ | ︙ | |||
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 | drop_all_tables do_test without_rowid3-14.1aux.1 { # Adding a column with a REFERENCES clause is not supported. execsql { ATTACH ':memory:' AS aux; CREATE TABLE aux.t1(a PRIMARY KEY) WITHOUT rowid; CREATE TABLE aux.t2(a, b); } catchsql { ALTER TABLE t2 ADD COLUMN c REFERENCES t1 } } {0 {}} do_test without_rowid3-14.1aux.2 { catchsql { ALTER TABLE t2 ADD COLUMN d DEFAULT NULL REFERENCES t1 } } {0 {}} do_test without_rowid3-14.1aux.3 { catchsql { ALTER TABLE t2 ADD COLUMN e REFERENCES t1 DEFAULT NULL} } {0 {}} do_test without_rowid3-14.1aux.4 { catchsql { ALTER TABLE t2 ADD COLUMN f REFERENCES t1 DEFAULT 'text'} } {1 {Cannot add a REFERENCES column with non-NULL default value}} do_test without_rowid3-14.1aux.5 { catchsql { ALTER TABLE t2 ADD COLUMN g DEFAULT CURRENT_TIME REFERENCES t1 } } {1 {Cannot add a REFERENCES column with non-NULL default value}} do_test without_rowid3-14.1aux.6 { execsql { PRAGMA foreign_keys = off; ALTER TABLE t2 ADD COLUMN h DEFAULT 'text' REFERENCES t1; PRAGMA foreign_keys = on; | > | | | | | | 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 | drop_all_tables do_test without_rowid3-14.1aux.1 { # Adding a column with a REFERENCES clause is not supported. execsql { ATTACH ':memory:' AS aux; CREATE TABLE aux.t1(a PRIMARY KEY) WITHOUT rowid; CREATE TABLE aux.t2(a, b); INSERT INTO aux.t2(a,b) VALUES(1,2); } catchsql { ALTER TABLE t2 ADD COLUMN c REFERENCES t1 } } {0 {}} do_test without_rowid3-14.1aux.2 { catchsql { ALTER TABLE t2 ADD COLUMN d DEFAULT NULL REFERENCES t1 } } {0 {}} do_test without_rowid3-14.1aux.3 { catchsql { ALTER TABLE t2 ADD COLUMN e REFERENCES t1 DEFAULT NULL} } {0 {}} do_test without_rowid3-14.1aux.4 { catchsql { ALTER TABLE t2 ADD COLUMN f REFERENCES t1 DEFAULT 'text'} } {1 {Cannot add a REFERENCES column with non-NULL default value}} do_test without_rowid3-14.1aux.5 { catchsql { ALTER TABLE t2 ADD COLUMN g DEFAULT CURRENT_TIME REFERENCES t1 } } {1 {Cannot add a REFERENCES column with non-NULL default value}} do_test without_rowid3-14.1aux.6 { execsql { PRAGMA foreign_keys = off; ALTER TABLE t2 ADD COLUMN h DEFAULT 'text' REFERENCES t1; PRAGMA foreign_keys = on; SELECT sql FROM aux.sqlite_schema WHERE name='t2'; } } {{CREATE TABLE t2(a, b, c REFERENCES t1, d DEFAULT NULL REFERENCES t1, e REFERENCES t1 DEFAULT NULL, h DEFAULT 'text' REFERENCES t1)}} sqlite3_test_control SQLITE_TESTCTRL_INTERNAL_FUNCTIONS db do_test without_rowid3-14.2aux.1.1 { test_rename_parent {CREATE TABLE t1(a REFERENCES t2)} t2 t3 } {{CREATE TABLE t1(a REFERENCES "t3")}} do_test without_rowid3-14.2aux.1.2 { test_rename_parent {CREATE TABLE t1(a REFERENCES t2)} t4 t3 } {{CREATE TABLE t1(a REFERENCES t2)}} do_test without_rowid3-14.2aux.1.3 { test_rename_parent {CREATE TABLE t1(a REFERENCES "t2")} t2 t3 } {{CREATE TABLE t1(a REFERENCES "t3")}} sqlite3_test_control SQLITE_TESTCTRL_INTERNAL_FUNCTIONS db # Test ALTER TABLE RENAME TABLE a bit. # do_test without_rowid3-14.2aux.2.1 { drop_all_tables execsql { CREATE TABLE aux.t1(a PRIMARY KEY, b REFERENCES t1) WITHOUT rowid; CREATE TABLE aux.t2(a PRIMARY KEY, b REFERENCES t1, c REFERENCES t2) WITHOUT rowid; CREATE TABLE aux.t3(a REFERENCES t1, b REFERENCES t2, c REFERENCES t1); } execsql { SELECT sql FROM aux.sqlite_schema WHERE type = 'table'} } [list \ {CREATE TABLE t1(a PRIMARY KEY, b REFERENCES t1) WITHOUT rowid} \ {CREATE TABLE t2(a PRIMARY KEY, b REFERENCES t1, c REFERENCES t2) WITHOUT rowid} \ {CREATE TABLE t3(a REFERENCES t1, b REFERENCES t2, c REFERENCES t1)} \ ] do_test without_rowid3-14.2aux.2.2 { execsql { ALTER TABLE t1 RENAME TO t4 } execsql { SELECT sql FROM aux.sqlite_schema WHERE type = 'table'} } [list \ {CREATE TABLE "t4"(a PRIMARY KEY, b REFERENCES "t4") WITHOUT rowid} \ {CREATE TABLE t2(a PRIMARY KEY, b REFERENCES "t4", c REFERENCES t2) WITHOUT rowid} \ {CREATE TABLE t3(a REFERENCES "t4", b REFERENCES t2, c REFERENCES "t4")} \ ] do_test without_rowid3-14.2aux.2.3 { |
︙ | ︙ |
Changes to test/without_rowid5.test.
︙ | ︙ | |||
11 12 13 14 15 16 17 18 19 20 21 22 23 24 | # # Requirements testing for WITHOUT ROWID tables. # set testdir [file dirname $argv0] source $testdir/tester.tcl # EVIDENCE-OF: R-36924-43758 By default, every row in SQLite has a # special column, usually called the "rowid", that uniquely identifies # that row within the table. # # EVIDENCE-OF: R-32341-39358 However if the phrase "WITHOUT ROWID" is # added to the end of a CREATE TABLE statement, then the special "rowid" | > > > > | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | # # Requirements testing for WITHOUT ROWID tables. # set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable !incrblob { finish_test return } # EVIDENCE-OF: R-36924-43758 By default, every row in SQLite has a # special column, usually called the "rowid", that uniquely identifies # that row within the table. # # EVIDENCE-OF: R-32341-39358 However if the phrase "WITHOUT ROWID" is # added to the end of a CREATE TABLE statement, then the special "rowid" |
︙ | ︙ | |||
181 182 183 184 185 186 187 188 189 190 191 192 193 194 | } {1 {NOT NULL constraint failed: nnw.c}} do_catchsql_test without_rowid5-5.8 { INSERT INTO nnw VALUES(4,5,6,7,NULL) } {1 {NOT NULL constraint failed: nnw.e}} do_execsql_test without_rowid5-5.9 { SELECT count(*) FROM nnw; } {1} # EVIDENCE-OF: R-12643-30541 The incremental blob I/O mechanism does not # work for WITHOUT ROWID tables. # # EVIDENCE-OF: R-40134-30296 Table zTable is a WITHOUT ROWID table # do_execsql_test without_rowid5-6.1 { | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | } {1 {NOT NULL constraint failed: nnw.c}} do_catchsql_test without_rowid5-5.8 { INSERT INTO nnw VALUES(4,5,6,7,NULL) } {1 {NOT NULL constraint failed: nnw.e}} do_execsql_test without_rowid5-5.9 { SELECT count(*) FROM nnw; } {1} # Ticket f2be158c57aaa8c6 (2021-08-18) # NOT NULL ON CONFLICT clauses work on WITHOUT ROWID tables now. # do_test without_rowid5-5.100 { db eval { DROP TABLE IF EXISTS t5; CREATE TABLE t5( a INT NOT NULL ON CONFLICT ROLLBACK, b TEXT, c TEXT, PRIMARY KEY(a,b) ) WITHOUT ROWID; BEGIN; INSERT INTO t5(a,b,c) VALUES(1,2,3); } catch {db eval {INSERT INTO t5(a,b,c) VALUES(NULL,6,7);}} db eval { SELECT * FROM t5; } } {} do_test without_rowid5-5.101 { db eval { DROP TABLE IF EXISTS t5; CREATE TABLE t5( a INT NOT NULL ON CONFLICT ABORT, b TEXT, c TEXT, PRIMARY KEY(a,b) ) WITHOUT ROWID; BEGIN; INSERT INTO t5(a,b,c) VALUES(1,2,3); } catch {db eval {INSERT INTO t5(a,b,c) VALUES(NULL,6,7);}} db eval { COMMIT; SELECT * FROM t5; } } {1 2 3} do_test without_rowid5-5.102 { db eval { DROP TABLE IF EXISTS t5; CREATE TABLE t5( a INT NOT NULL ON CONFLICT FAIL, b TEXT, c TEXT, PRIMARY KEY(a,b) ) WITHOUT ROWID; } catch {db eval {INSERT INTO t5(a,b,c) VALUES(1,2,3),(NULL,4,5),(6,7,8);}} db eval { SELECT * FROM t5; } } {1 2 3} do_test without_rowid5-5.103 { db eval { DROP TABLE IF EXISTS t5; CREATE TABLE t5( a INT NOT NULL ON CONFLICT IGNORE, b TEXT, c TEXT, PRIMARY KEY(a,b) ) WITHOUT ROWID; INSERT INTO t5(a,b,c) VALUES(1,2,3),(NULL,4,5),(6,7,8); SELECT * FROM t5; } } {1 2 3 6 7 8} do_test without_rowid5-5.104 { db eval { DROP TABLE IF EXISTS t5; CREATE TABLE t5( a INT NOT NULL ON CONFLICT REPLACE DEFAULT 3, b TEXT, c TEXT, PRIMARY KEY(a,b) ) WITHOUT ROWID; INSERT INTO t5(a,b,c) VALUES(1,2,3),(NULL,4,5),(6,7,8); SELECT * FROM t5; } } {1 2 3 3 4 5 6 7 8} # EVIDENCE-OF: R-12643-30541 The incremental blob I/O mechanism does not # work for WITHOUT ROWID tables. # # EVIDENCE-OF: R-40134-30296 Table zTable is a WITHOUT ROWID table # do_execsql_test without_rowid5-6.1 { |
︙ | ︙ |
Changes to test/without_rowid6.test.
︙ | ︙ | |||
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | # # Verify that WITHOUT ROWID tables work correctly when the PRIMARY KEY # has redundant columns. # set testdir [file dirname $argv0] source $testdir/tester.tcl do_execsql_test without_rowid6-100 { CREATE TABLE t1(a,b,c,d,e, PRIMARY KEY(a,b,c,a,b,c,d,a,b,c)) WITHOUT ROWID; CREATE INDEX t1a ON t1(b, b); WITH RECURSIVE c(i) AS (VALUES(1) UNION ALL SELECT i+1 FROM c WHERE i<1000) INSERT INTO t1(a,b,c,d,e) SELECT i, i+1000, printf('x%dy',i), 0, 0 FROM c; ANALYZE; } {} do_execsql_test without_rowid6-110 { SELECT c FROM t1 WHERE a=123; } {x123y} do_execsql_test without_rowid6-120 { SELECT c FROM t1 WHERE b=1123; } {x123y} do_execsql_test without_rowid6-130 { | > > > > > > > | 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 | # # Verify that WITHOUT ROWID tables work correctly when the PRIMARY KEY # has redundant columns. # set testdir [file dirname $argv0] source $testdir/tester.tcl proc do_execsql_test_if_vtab {tn sql {res {}}} { ifcapable vtab { uplevel [list do_execsql_test $tn $sql $res] } } do_execsql_test without_rowid6-100 { CREATE TABLE t1(a,b,c,d,e, PRIMARY KEY(a,b,c,a,b,c,d,a,b,c)) WITHOUT ROWID; CREATE INDEX t1a ON t1(b, b); WITH RECURSIVE c(i) AS (VALUES(1) UNION ALL SELECT i+1 FROM c WHERE i<1000) INSERT INTO t1(a,b,c,d,e) SELECT i, i+1000, printf('x%dy',i), 0, 0 FROM c; ANALYZE; } {} do_execsql_test_if_vtab without_rowid6-101 { SELECT name, key FROM pragma_index_xinfo('t1'); } {a 1 b 1 c 1 d 1 e 0} do_execsql_test without_rowid6-110 { SELECT c FROM t1 WHERE a=123; } {x123y} do_execsql_test without_rowid6-120 { SELECT c FROM t1 WHERE b=1123; } {x123y} do_execsql_test without_rowid6-130 { |
︙ | ︙ | |||
47 48 49 50 51 52 53 54 55 56 | b UNIQUE, c UNIQUE, PRIMARY KEY(b) ) WITHOUT ROWID; INSERT INTO t1(a,b,c) VALUES(1,8,3),(4,5,6),(7,2,9); SELECT a FROM t1 WHERE b>3 ORDER BY b; } {4 1} do_execsql_test without_rowid6-210 { EXPLAIN QUERY PLAN SELECT a FROM t1 WHERE b>3 ORDER BY b; | > > > | | | > > > | | 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 | b UNIQUE, c UNIQUE, PRIMARY KEY(b) ) WITHOUT ROWID; INSERT INTO t1(a,b,c) VALUES(1,8,3),(4,5,6),(7,2,9); SELECT a FROM t1 WHERE b>3 ORDER BY b; } {4 1} do_execsql_test_if_vtab without_rowid6-201 { SELECT name, key FROM pragma_index_xinfo('t1'); } {b 1 a 0 c 0} do_execsql_test without_rowid6-210 { EXPLAIN QUERY PLAN SELECT a FROM t1 WHERE b>3 ORDER BY b; } {/SEARCH t1 USING PRIMARY KEY .b>../} do_execsql_test without_rowid6-220 { PRAGMA index_list(t1); } {/sqlite_autoindex_t1_2 1 pk/} do_execsql_test without_rowid6-300 { DROP TABLE IF EXISTS t1; CREATE TABLE t1( a UNIQUE, b PRIMARY KEY, c UNIQUE, UNIQUE(b) ) WITHOUT ROWID; INSERT INTO t1(a,b,c) VALUES(1,8,3),(4,5,6),(7,2,9); SELECT a FROM t1 WHERE b>3 ORDER BY b; } {4 1} do_execsql_test without_rowid6-310 { EXPLAIN QUERY PLAN SELECT a FROM t1 WHERE b>3 ORDER BY b; } {/SEARCH t1 USING PRIMARY KEY .b>../} do_execsql_test without_rowid6-320 { PRAGMA index_list(t1); } {/sqlite_autoindex_t1_2 1 pk/} do_execsql_test without_rowid6-400 { DROP TABLE IF EXISTS t1; CREATE TABLE t1( a UNIQUE, b UNIQUE PRIMARY KEY, c UNIQUE ) WITHOUT ROWID; INSERT INTO t1(a,b,c) VALUES(1,8,3),(4,5,6),(7,2,9); SELECT a FROM t1 WHERE b>3 ORDER BY b; } {4 1} do_execsql_test without_rowid6-410 { EXPLAIN QUERY PLAN SELECT a FROM t1 WHERE b>3 ORDER BY b; } {/SEARCH t1 USING PRIMARY KEY .b>../} do_execsql_test without_rowid6-420 { PRAGMA index_list(t1); } {/sqlite_autoindex_t1_2 1 pk/} do_execsql_test without_rowid6-500 { DROP TABLE IF EXISTS t1; CREATE TABLE t1(a,b,c, UNIQUE(b,c), PRIMARY KEY(b,c) ) WITHOUT ROWID; INSERT INTO t1(a,b,c) VALUES(1,8,3),(4,5,6),(7,2,9); SELECT a FROM t1 WHERE b>3 ORDER BY b; } {4 1} do_execsql_test_if_vtab without_rowid6-501 { SELECT name, key FROM pragma_index_xinfo('t1'); } {b 1 c 1 a 0} do_execsql_test without_rowid6-510 { EXPLAIN QUERY PLAN SELECT a FROM t1 WHERE b>3 ORDER BY b; } {/SEARCH t1 USING PRIMARY KEY .b>../} do_execsql_test without_rowid6-520 { PRAGMA index_list(t1); } {/sqlite_autoindex_t1_1 1 pk/} do_catchsql_test without_rowid6-600 { CREATE TABLE t6(a,b,c,PRIMARY KEY(a,rowid,b))WITHOUT ROWID; } {1 {no such column: rowid}} finish_test |
Added test/without_rowid7.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 | # 2019 July 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 file implements regression tests for SQLite library. # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix without_rowid7 proc do_execsql_test_if_vtab {tn sql {res {}}} { ifcapable vtab { uplevel [list do_execsql_test $tn $sql $res] } } do_execsql_test 1.0 { CREATE TABLE t1(a, b COLLATE nocase, PRIMARY KEY(a, a, b)) WITHOUT ROWID; } do_catchsql_test 1.1 { INSERT INTO t1 VALUES(1, 'one'), (1, 'ONE'); } {1 {UNIQUE constraint failed: t1.a, t1.b}} do_execsql_test 2.0 { CREATE TABLE t2(a, b, PRIMARY KEY(a COLLATE nocase, a)) WITHOUT ROWID; } do_execsql_test 2.1 { INSERT INTO t2 VALUES(1, 'one'); SELECT b FROM t2; } {one} do_execsql_test 2.2a { PRAGMA index_info(t2); } {0 0 a 1 0 a} do_execsql_test_if_vtab 2.2b { SELECT *, '|' FROM pragma_index_info('t2'); } {0 0 a | 1 0 a |} do_execsql_test 2.3a { PRAGMA index_xinfo(t2); } {0 0 a 0 nocase 1 1 0 a 0 BINARY 1 2 1 b 0 BINARY 0} do_execsql_test_if_vtab 2.3b { SELECT *, '|' FROM pragma_index_xinfo('t2'); } {0 0 a 0 nocase 1 | 1 0 a 0 BINARY 1 | 2 1 b 0 BINARY 0 |} do_execsql_test 2.4 { CREATE TABLE t3(a, b, PRIMARY KEY(a COLLATE nocase, a)); PRAGMA index_info(t3); } {} finish_test |
Changes to test/zeroblob.test.
︙ | ︙ | |||
15 16 17 18 19 20 21 | # # $Id: zeroblob.test,v 1.14 2009/07/14 02:33:02 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix zeroblob | | < < < > > > > | | < | | | > > | 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 | # # $Id: zeroblob.test,v 1.14 2009/07/14 02:33:02 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix zeroblob # ifcapable !incrblob { finish_test return } test_set_config_pagecache 0 0 # When zeroblob() is used for the last field of a column, then the # content of the zeroblob is never instantiated on the VDBE stack. # But it does get inserted into the database correctly. # db eval {PRAGMA cache_size=10} sqlite3_memory_highwater 1 unset -nocomplain memused set memused [sqlite3_memory_used] do_test zeroblob-1.1 { execsql { CREATE TABLE t1(a,b,c,d); } set ::sqlite3_max_blobsize 0 execsql { INSERT INTO t1 VALUES(2,3,4,zeroblob(1000000)); } } {} ifcapable incrblob { do_test zeroblob-1.1.1 { set ::sqlite3_max_blobsize } {10} do_test zeroblob-1.1.2 { expr {[sqlite3_memory_highwater]<$::memused+35000} } {1} } do_test zeroblob-1.2 { execsql { SELECT length(d) FROM t1 } } {1000000} # If a non-NULL column follows the zeroblob, then the content of |
︙ | ︙ | |||
74 75 76 77 78 79 80 | # of the blob content occurs on the stack. # do_test zeroblob-1.5 { set ::sqlite3_max_blobsize 0 execsql { INSERT INTO t1 VALUES(4,5,zeroblob(10000),zeroblob(10000)); } | > > > | | > > > > | | > | 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 | # of the blob content occurs on the stack. # do_test zeroblob-1.5 { set ::sqlite3_max_blobsize 0 execsql { INSERT INTO t1 VALUES(4,5,zeroblob(10000),zeroblob(10000)); } } {} ifcapable incrblob { do_test zeroblob-1.5.1 { set ::sqlite3_max_blobsize } {11} } do_test zeroblob-1.6 { execsql { SELECT length(c), length(d) FROM t1 } } {1 1000000 10000 1 10000 10000} # NULLs can follow the zeroblob() or be intermixed with zeroblobs and # no instantiation of the zeroblobs occurs on the stack. # do_test zeroblob-1.7 { set ::sqlite3_max_blobsize 0 execsql { INSERT INTO t1 VALUES(5,zeroblob(10000),NULL,zeroblob(10000)); } } {} ifcapable incrblob { do_test zeroblob-1.7.1 { set ::sqlite3_max_blobsize } {10} } do_test zeroblob-1.8 { execsql { SELECT length(b), length(d) FROM t1 WHERE a=5 } } {10000 10000} # Comparisons against zeroblobs work. |
︙ | ︙ | |||
210 211 212 213 214 215 216 | } {SQLITE_ROW} do_test zeroblob-7.2 { sqlite3_column_int $::STMT 0 } {450000} do_test zeroblob-7.3 { sqlite3_finalize $::STMT } {SQLITE_OK} | > | | | | | | > | 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 | } {SQLITE_ROW} do_test zeroblob-7.2 { sqlite3_column_int $::STMT 0 } {450000} do_test zeroblob-7.3 { sqlite3_finalize $::STMT } {SQLITE_OK} ifcapable incrblob { do_test zeroblob-7.4 { set ::sqlite3_max_blobsize } {0} do_test zeroblob-7.5 { expr {[sqlite3_memory_highwater]<$::memused+10000} } {1} } # Test that MakeRecord can handle a value with some real content # and a zero-blob tail. # do_test zeroblob-8.1 { llength [execsql { SELECT 'hello' AS a, zeroblob(10) as b from t1 ORDER BY a, b; |
︙ | ︙ | |||
311 312 313 314 315 316 317 318 319 320 | sqlite3_step $stmt set ret [sqlite3_column_int $stmt 0] sqlite3_reset $stmt set ret } {1000} sqlite3_finalize $stmt test_restore_config_pagecache finish_test | > > > > > > > > > > > | 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 | sqlite3_step $stmt set ret [sqlite3_column_int $stmt 0] sqlite3_reset $stmt set ret } {1000} sqlite3_finalize $stmt # 2019-01-25 https://sqlite.org/src/tktview/bb4bdb9f7f654b0bb9f34cfbac # Zeroblob truncated by an index on expression # do_execsql_test 13.100 { DROP TABLE IF EXISTS t1; CREATE TABLE t1(a,b,c); CREATE INDEX t1bbc ON t1(b, b+c); INSERT INTO t1(a,b,c) VALUES(1,zeroblob(8),3); SELECT a, quote(b), length(b), c FROM t1; } {1 X'0000000000000000' 8 3} test_restore_config_pagecache finish_test |
Added test/zeroblobfault.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 | # 2021 November 8 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix zeroblobfault set quoted_res [db one { SELECT quote(zeroblob(2000)) }] do_faultsim_test 1 -prep { sqlite3 db test.db } -body { execsql { SELECT quote(zeroblob(2000)) } } -test { faultsim_test_result [list 0 $::quoted_res] } finish_test |
Changes to test/zipfile.test.
︙ | ︙ | |||
790 791 792 793 794 795 796 797 798 | SELECT name FROM d JOIN x JOIN fsdir(d) ORDER BY 1; } {subdir subdir/x1.txt subdir/x2.txt} do_execsql_test 12.5 { SELECT name FROM d JOIN x JOIN fsdir('.', d) ORDER BY 1; } {. ./x1.txt ./x2.txt} } finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | SELECT name FROM d JOIN x JOIN fsdir(d) ORDER BY 1; } {subdir subdir/x1.txt subdir/x2.txt} do_execsql_test 12.5 { SELECT name FROM d JOIN x JOIN fsdir('.', d) ORDER BY 1; } {. ./x1.txt ./x2.txt} } # 2019-12-18 Yongheng and Rui fuzzer # do_execsql_test 13.10 { DROP TABLE IF EXISTS t0; DROP TABLE IF EXISTS t1; CREATE TABLE t0(a,b,c,d,e,f,g); REPLACE INTO t0(c,b,f) VALUES(10,10,10); CREATE VIRTUAL TABLE t1 USING zipfile('h.zip'); REPLACE INTO t1 SELECT * FROM t0; SELECT quote(name),quote(mode),quote(mtime),quote(sz),quote(rawdata), quote(data),quote(method) FROM t1; } {'' 10 10 2 X'3130' X'3130' 0} # 2019-12-23 Yongheng and Rui fuzzer # Run using valgrind to see the problem. # do_execsql_test 14.10 { DROP TABLE t1; CREATE TABLE t1(x char); INSERT INTO t1(x) VALUES('1'); INSERT INTO t1(x) SELECT zipfile(x, 'xyz') FROM t1; INSERT INTO t1(x) SELECT zipfile(x, 'uvw') FROM t1; SELECT count(*) FROM t1; PRAGMA integrity_check; } {3 ok} # 2019-12-26 More problems in zipfile from the Yongheng and Rui fuzzer # do_execsql_test 15.10 { DROP TABLE IF EXISTS t1; CREATE VIRTUAL TABLE t1 USING zipfile(null); REPLACE INTO t1 VALUES(null,null,0,null,null,null,null); } {} do_execsql_test 15.20 { DROP TABLE IF EXISTS t2; CREATE VIRTUAL TABLE t2 USING zipfile(null); REPLACE INTO t2 values(null,null,null,null,null,10,null); } {} # 2020-01-02 Yongheng fuzzer discovery # do_catchsql_test 16.10 { DELETE FROM zipfile; } {1 {zipfile: missing filename}} do_catchsql_test 16.20 { REPLACE INTO zipfile VALUES(null,null,null,null,null,123,null); } {1 {zipfile: missing filename}} # 2021-04-22 forum https://sqlite.org/forum/forumpost/d82289d69f do_execsql_test 17.1 { WITH vlist(x) AS ( VALUES(9223372036854775807), (-9223372036854775808), (9223372036854775806), (-9223372036854775807) ) SELECT DISTINCT typeof(zipfile(0,0,x,0)) FROM vlist; } {blob} finish_test |
Changes to tool/GetFile.cs.
︙ | ︙ | |||
163 164 165 166 167 168 169 | { if (message != null) Console.WriteLine(message); string fileName = Path.GetFileName( Process.GetCurrentProcess().MainModule.FileName); | | > | 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 | { if (message != null) Console.WriteLine(message); string fileName = Path.GetFileName( Process.GetCurrentProcess().MainModule.FileName); Console.WriteLine(String.Format( "usage: {0} <uri> [fileName]", fileName)); } /////////////////////////////////////////////////////////////////////// /// <summary> /// This method attempts to determine the file name portion of the /// specified URI. |
︙ | ︙ | |||
332 333 334 335 336 337 338 | // if (args == null) { Error(null, true); return (int)ExitCode.MissingArgs; } | | > > > > > > > > > > | | | | | | | | > > > > > > > > > > | 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 | // if (args == null) { Error(null, true); return (int)ExitCode.MissingArgs; } if ((args.Length < 1) || (args.Length > 2)) { Error(null, true); return (int)ExitCode.WrongNumArgs; } // // NOTE: Attempt to convert the first (and only) command line // argument to an absolute URI. // Uri uri; if (!Uri.TryCreate(args[0], UriKind.Absolute, out uri)) { Error("Could not create absolute URI from argument.", false); return (int)ExitCode.BadUri; } // // NOTE: If a file name was specified on the command line, try to // use it (without its directory name); otherwise, fallback // to using the file name portion of the URI. // string fileName = (args.Length == 2) ? Path.GetFileName(args[1]) : null; if (String.IsNullOrEmpty(fileName)) { // // NOTE: Attempt to extract the file name portion of the URI // we just created. // fileName = GetFileName(uri); if (fileName == null) { Error("Could not extract file name from URI.", false); return (int)ExitCode.BadFileName; } } // // NOTE: Grab the temporary path setup for this process. If it is // unavailable, we will not continue. // string directory = Path.GetTempPath(); if (String.IsNullOrEmpty(directory) || !Directory.Exists(directory)) { Error("Temporary directory is invalid or unavailable.", false); return (int)ExitCode.BadTempPath; } try { // // HACK: For use of the TLS 1.2 security protocol because some // web servers fail without it. In order to support the // .NET Framework 2.0+ at compilation time, must use its // integer constant here. // ServicePointManager.SecurityProtocol = (SecurityProtocolType)0xC00; using (WebClient webClient = new WebClient()) { // // NOTE: Create the event used to signal completion of the // file download. // doneEvent = new ManualResetEvent(false); |
︙ | ︙ |
Changes to tool/GetTclKit.bat.
︙ | ︙ | |||
35 36 37 38 39 40 41 | SET DUMMY2=%2 IF DEFINED DUMMY2 ( GOTO usage ) | | | | > | | 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | SET DUMMY2=%2 IF DEFINED DUMMY2 ( GOTO usage ) IF NOT DEFINED ENVDIR ( SET ENVDIR=%CD% ) %_VECHO% EnvDir = '%ENVDIR%' SET TOOLS=%~dp0 SET TOOLS=%TOOLS:~0,-1% %_VECHO% Tools = '%TOOLS%' IF NOT DEFINED windir ( |
︙ | ︙ | |||
60 61 62 63 64 65 66 | ECHO The TEMP environment variable must be set first. GOTO errors ) %_VECHO% Temp = '%TEMP%' IF NOT DEFINED TCLKIT_URI ( | | > > > > > > > > > > > > > > > > > > > > > | 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 | ECHO The TEMP environment variable must be set first. GOTO errors ) %_VECHO% Temp = '%TEMP%' IF NOT DEFINED TCLKIT_URI ( SET TCLKIT_URI=https://urn.to/r/tclsh/ ) %_VECHO% TclKitUri = '%TCLKIT_URI%' IF NOT DEFINED TCLKIT_PATCHLEVEL ( SET TCLKIT_PATCHLEVEL=8.6.6 ) %_VECHO% TclKitPatchLevel = '%TCLKIT_PATCHLEVEL%' IF NOT DEFINED TCLKIT_EXE_PATCHLEVEL ( SET TCLKIT_EXE_PATCHLEVEL=8.6.4 ) %_VECHO% TclKitExePatchLevel = '%TCLKIT_EXE_PATCHLEVEL%' IF /I "%PROCESSOR%" == "x86" ( CALL :fn_TclKitX86Variables IF ERRORLEVEL 1 ( GOTO errors ) ) ELSE IF /I "%PROCESSOR%" == "x64" ( CALL :fn_TclKitX64Variables IF ERRORLEVEL 1 ( GOTO errors ) ) ELSE ( GOTO usage ) %_VECHO% TclKitVersion = '%TCLKIT_VERSION%' %_VECHO% TclKitPatchLevel = '%TCLKIT_PATCHLEVEL%' %_VECHO% TclKitExePatchLevel = '%TCLKIT_EXE_PATCHLEVEL%' %_VECHO% TclKitNoEnv = '%TCLKIT_NOENV%' %_VECHO% TclKitNoSdk = '%TCLKIT_NOSDK%' %_VECHO% TclKitExe = '%TCLKIT_EXE%' %_VECHO% TclKitLib = '%TCLKIT_LIB%' %_VECHO% TclKitLibStub = '%TCLKIT_LIB_STUB%' %_VECHO% TclKitSdk = '%TCLKIT_SDK%' %_VECHO% TclKitSdkZip = '%TCLKIT_SDK_ZIP%' |
︙ | ︙ | |||
169 170 171 172 173 174 175 | GOTO errors ) :skip_sdkUnZip IF DEFINED TCLKIT_NOENV GOTO skip_sdkEnvironment | | | | | | | | | > > > | > | > | > > > | > | > | 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 | GOTO errors ) :skip_sdkUnZip IF DEFINED TCLKIT_NOENV GOTO skip_sdkEnvironment %__ECHO% ECHO SET TCLSH_CMD=%TEMP%\%TCLKIT_EXE%%OVERWRITE%"%ENVDIR%\SetTclKitEnv.bat" IF DEFINED TCLKIT_NOSDK GOTO skip_sdkVariables %__ECHO% ECHO SET TCLINCDIR=%TEMP%\%TCLKIT_SDK%\include%APPEND%"%ENVDIR%\SetTclKitEnv.bat" %__ECHO% ECHO SET TCLLIBDIR=%TEMP%\%TCLKIT_SDK%\lib%APPEND%"%ENVDIR%\SetTclKitEnv.bat" %__ECHO% ECHO SET LIBTCLPATH=%TEMP%\%TCLKIT_SDK%\lib%APPEND%"%ENVDIR%\SetTclKitEnv.bat" %__ECHO% ECHO SET LIBTCL=%TCLKIT_LIB%%APPEND%"%ENVDIR%\SetTclKitEnv.bat" %__ECHO% ECHO SET LIBTCLSTUB=%TCLKIT_LIB_STUB%%APPEND%"%ENVDIR%\SetTclKitEnv.bat" :skip_sdkVariables ECHO. ECHO Wrote "%ENVDIR%\SetTclKitEnv.bat". ECHO Please run it to set the necessary Tcl environment variables. ECHO. :skip_sdkEnvironment GOTO no_errors :fn_TclKitX86Variables REM REM NOTE: By default, use latest available version of the TclKit SDK REM for x86. However, the "default" TclKit executable for x86 REM is still used here because it is the only one "well-known" REM to be available for download. REM IF NOT DEFINED TCLKIT_PATCHLEVEL ( ECHO The TCLKIT_PATCHLEVEL environment variable must be set first. CALL :fn_SetErrorLevel GOTO :EOF ) SET TCLKIT_VERSION=%TCLKIT_PATCHLEVEL:.=% SET TCLKIT_VERSION=%TCLKIT_VERSION:~0,2% IF DEFINED TCLKIT_EXE_PATCHLEVEL ( SET TCLKIT_EXE=tclkit-%TCLKIT_EXE_PATCHLEVEL%.exe ) ELSE ( SET TCLKIT_EXE=tclkit-%TCLKIT_PATCHLEVEL%.exe ) SET TCLKIT_LIB=libtclkit%TCLKIT_PATCHLEVEL:.=%.lib SET TCLKIT_LIB_STUB=libtclstub%TCLKIT_VERSION:.=%.a SET TCLKIT_SDK=libtclkit-sdk-x86-%TCLKIT_PATCHLEVEL% SET TCLKIT_SDK_ZIP=%TCLKIT_SDK%.zip SET TCLKIT_FILES=%TCLKIT_EXE% IF NOT DEFINED TCLKIT_NOENV IF NOT DEFINED TCLKIT_NOSDK ( SET TCLKIT_FILES=%TCLKIT_FILES% unzip.exe %TCLKIT_SDK_ZIP% ) GOTO :EOF :fn_TclKitX64Variables REM REM NOTE: By default, use latest available version of the TclKit SDK REM for x64. However, the "default" TclKit executable for x86 REM is still used here because it is the only one "well-known" REM to be available for download. REM IF NOT DEFINED TCLKIT_PATCHLEVEL ( ECHO The TCLKIT_PATCHLEVEL environment variable must be set first. CALL :fn_SetErrorLevel GOTO :EOF ) SET TCLKIT_VERSION=%TCLKIT_PATCHLEVEL:.=% SET TCLKIT_VERSION=%TCLKIT_VERSION:~0,2% IF DEFINED TCLKIT_EXE_PATCHLEVEL ( SET TCLKIT_EXE=tclkit-%TCLKIT_EXE_PATCHLEVEL%.exe ) ELSE ( SET TCLKIT_EXE=tclkit-%TCLKIT_PATCHLEVEL%.exe ) SET TCLKIT_LIB=libtclkit%TCLKIT_PATCHLEVEL:.=%.lib SET TCLKIT_LIB_STUB=libtclstub%TCLKIT_VERSION:.=%.a SET TCLKIT_SDK=libtclkit-sdk-x64-%TCLKIT_PATCHLEVEL% SET TCLKIT_SDK_ZIP=%TCLKIT_SDK%.zip SET TCLKIT_FILES=%TCLKIT_EXE% IF NOT DEFINED TCLKIT_NOENV IF NOT DEFINED TCLKIT_NOSDK ( SET TCLKIT_FILES=%TCLKIT_FILES% unzip.exe %TCLKIT_SDK_ZIP% |
︙ | ︙ |
Deleted tool/addopcodes.tcl.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to tool/cg_anno.tcl.
|
| | > > | 1 2 3 4 5 6 7 8 9 10 | #!/bin/sh # \ exec tclsh "$0" ${1+"$@"} # # A wrapper around cg_annotate that sets appropriate command-line options # and rearranges the output so that annotated files occur in a consistent # sorted order. Used by the speed-check.tcl script. # set in [open "|cg_annotate --show=Ir --auto=yes --context=40 $argv" r] |
︙ | ︙ |
Changes to tool/dbhash.c.
︙ | ︙ | |||
58 59 60 61 62 63 64 | */ /* * blk0() and blk() perform the initial expand. * I got the idea of expanding during the round function from SSLeay * * blk0le() for little-endian and blk0be() for big-endian. */ | < < < < < < < < < < < < < < < | 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | */ /* * blk0() and blk() perform the initial expand. * I got the idea of expanding during the round function from SSLeay * * blk0le() for little-endian and blk0be() for big-endian. */ #define SHA_ROT(x,l,r) ((x) << (l) | (x) >> (r)) #define rol(x,k) SHA_ROT(x,k,32-(k)) #define ror(x,k) SHA_ROT(x,32-(k),k) #define blk0le(i) (block[i] = (ror(block[i],8)&0xFF00FF00) \ |(rol(block[i],8)&0x00FF00FF)) #define blk0be(i) block[i] #define blk(i) (block[i&15] = rol(block[(i+13)&15]^block[(i+8)&15] \ ^block[(i+2)&15]^block[i&15],1)) |
︙ | ︙ | |||
451 452 453 454 455 456 457 | ; zDb = argv[i]; rc = sqlite3_open_v2(zDb, &g.db, openFlags, 0); if( rc ){ fprintf(stderr, "cannot open database file '%s'\n", zDb); continue; } | | | | 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 | ; zDb = argv[i]; rc = sqlite3_open_v2(zDb, &g.db, openFlags, 0); if( rc ){ fprintf(stderr, "cannot open database file '%s'\n", zDb); continue; } rc = sqlite3_exec(g.db, "SELECT * FROM sqlite_schema", 0, 0, &zErrMsg); if( rc || zErrMsg ){ sqlite3_close(g.db); g.db = 0; fprintf(stderr, "'%s' is not a valid SQLite database\n", zDb); continue; } /* Start the hash */ hash_init(); /* Hash table content */ if( !omitContent ){ pStmt = db_prepare( "SELECT name FROM sqlite_schema\n" " WHERE type='table' AND sql NOT LIKE 'CREATE VIRTUAL%%'\n" " AND name NOT LIKE 'sqlite_%%'\n" " AND name LIKE '%q'\n" " ORDER BY name COLLATE nocase;\n", zLike ); while( SQLITE_ROW==sqlite3_step(pStmt) ){ |
︙ | ︙ | |||
487 488 489 490 491 492 493 | } sqlite3_finalize(pStmt); } /* Hash the database schema */ if( !omitSchema ){ hash_one_query( | | | 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 | } sqlite3_finalize(pStmt); } /* Hash the database schema */ if( !omitSchema ){ hash_one_query( "SELECT type, name, tbl_name, sql FROM sqlite_schema\n" " WHERE tbl_name LIKE '%q'\n" " ORDER BY name COLLATE nocase;\n", zLike ); } /* Finish and output the hash and close the database connection. */ hash_finish(zDb); sqlite3_close(g.db); } return 0; } |
Changes to tool/dbtotxt.c.
︙ | ︙ | |||
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 | ** databases be constructed with "zeroblob()" rather than "randomblob()" ** used for filler content and with "PRAGMA secure_delete=ON" selected to ** zero-out deleted content. */ #include <stdio.h> #include <string.h> #include <stdlib.h> /* Return true if the line is all zeros */ static int allZero(unsigned char *aLine){ int i; for(i=0; i<16 && aLine[i]==0; i++){} return i==16; } int main(int argc, char **argv){ int pgsz = 0; /* page size */ long szFile; /* Size of the input file in bytes */ FILE *in; /* Input file */ int i, j; /* Loop counters */ int nErr = 0; /* Number of errors */ const char *zInputFile = 0; /* Name of the input file */ const char *zBaseName = 0; /* Base name of the file */ int lastPage = 0; /* Last page number shown */ int iPage; /* Current page number */ unsigned char aLine[16]; /* A single line of the file */ unsigned char aHdr[100]; /* File header */ for(i=1; i<argc; i++){ if( argv[i][0]=='-' ){ const char *z = argv[i]; z++; if( z[0]=='-' ) z++; if( strcmp(z,"pagesize")==0 ){ i++; | > > > > > > | 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 | ** databases be constructed with "zeroblob()" rather than "randomblob()" ** used for filler content and with "PRAGMA secure_delete=ON" selected to ** zero-out deleted content. */ #include <stdio.h> #include <string.h> #include <stdlib.h> #include <ctype.h> /* Return true if the line is all zeros */ static int allZero(unsigned char *aLine){ int i; for(i=0; i<16 && aLine[i]==0; i++){} return i==16; } int main(int argc, char **argv){ int pgsz = 0; /* page size */ long szFile; /* Size of the input file in bytes */ FILE *in; /* Input file */ int i, j; /* Loop counters */ int nErr = 0; /* Number of errors */ const char *zInputFile = 0; /* Name of the input file */ const char *zBaseName = 0; /* Base name of the file */ int lastPage = 0; /* Last page number shown */ int iPage; /* Current page number */ unsigned char aLine[16]; /* A single line of the file */ unsigned char aHdr[100]; /* File header */ unsigned char bShow[256]; /* Characters ok to display */ memset(bShow, '.', sizeof(bShow)); for(i=' '; i<='~'; i++){ if( i!='{' && i!='}' && i!='"' && i!='\\' ) bShow[i] = (unsigned char)i; } for(i=1; i<argc; i++){ if( argv[i][0]=='-' ){ const char *z = argv[i]; z++; if( z[0]=='-' ) z++; if( strcmp(z,"pagesize")==0 ){ i++; |
︙ | ︙ | |||
83 84 85 86 87 88 89 | if( in==0 ){ fprintf(stderr, "Cannot open input file [%s]\n", zInputFile); exit(1); } fseek(in, 0, SEEK_END); szFile = ftell(in); rewind(in); | | | | | 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 | if( in==0 ){ fprintf(stderr, "Cannot open input file [%s]\n", zInputFile); exit(1); } fseek(in, 0, SEEK_END); szFile = ftell(in); rewind(in); if( szFile<100 ){ fprintf(stderr, "File too short. Minimum size is 100 bytes.\n"); exit(1); } if( fread(aHdr, 100, 1, in)!=1 ){ fprintf(stderr, "Cannot read file header\n"); exit(1); } rewind(in); if( pgsz==0 ){ pgsz = (aHdr[16]<<8) | aHdr[17]; if( pgsz==1 ) pgsz = 65536; if( pgsz<512 || (pgsz&(pgsz-1))!=0 ){ fprintf(stderr, "Invalid page size in header: %d\n", pgsz); exit(1); } } zBaseName = zInputFile; for(i=0; zInputFile[i]; i++){ if( zInputFile[i]=='/' && zInputFile[i+1]!=0 ) zBaseName = zInputFile+i+1; } printf("| size %d pagesize %d filename %s\n",(int)szFile,pgsz,zBaseName); for(i=0; i<szFile; i+=16){ int got = (int)fread(aLine, 1, 16, in); if( got!=16 ){ static int once = 1; if( once ){ |
︙ | ︙ | |||
125 126 127 128 129 130 131 | printf("| page %d offset %d\n", iPage, (iPage-1)*pgsz); lastPage = iPage; } printf("| %5d:", i-(iPage-1)*pgsz); for(j=0; j<16; j++) printf(" %02x", aLine[j]); printf(" "); for(j=0; j<16; j++){ | | | | 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 | printf("| page %d offset %d\n", iPage, (iPage-1)*pgsz); lastPage = iPage; } printf("| %5d:", i-(iPage-1)*pgsz); for(j=0; j<16; j++) printf(" %02x", aLine[j]); printf(" "); for(j=0; j<16; j++){ unsigned char c = (unsigned char)aLine[j]; fputc( bShow[c], stdout); } fputc('\n', stdout); } fclose(in); printf("| end %s\n", zBaseName); return 0; } |
Added tool/enlargedb.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 | /* ** Try to enlarge an SQLite database by appending many unused pages. ** The resulting database will fail PRAGMA integrity_check due to the ** appended unused pages, but it should work otherwise. ** ** Usage: ** ** enlargedb DATABASE N ** ** Adds N blank pages onto the end of DATABASE. N can be decimal ** or hex. The total number of pages after adding must be no greater ** than 4294967297 */ #include <stdio.h> #include <string.h> #include <stdlib.h> int main(int argc, char **argv){ char *zEnd; long long int toAppend; long long int currentSz; long long int newSz; FILE *f; size_t got; int pgsz; char zero = 0; unsigned char buf[100]; if( argc!=3 ) goto usage_error; toAppend = strtoll(argv[2], &zEnd, 0); if( zEnd==argv[2] || zEnd[0] ) goto usage_error; if( toAppend<1 ){ fprintf(stderr, "N must be at least 1\n"); exit(1); } f = fopen(argv[1], "r+b"); if( f==0 ){ fprintf(stderr, "cannot open \"%s\" for reading and writing\n", argv[1]); exit(1); } got = fread(buf, 1, sizeof(buf), f); if( got!=sizeof(buf) ) goto not_valid_db; if( strcmp((char*)buf,"SQLite format 3")!=0 ) goto not_valid_db; pgsz = (buf[16]<<8) + buf[17]; if( pgsz==1 ) pgsz = 65536; if( pgsz<512 || pgsz>65536 || (pgsz&(pgsz-1))!=0 ) goto not_valid_db; currentSz = (buf[28]<<24) + (buf[29]<<16) + (buf[30]<<8) + buf[31]; newSz = currentSz + toAppend; if( newSz > 0xffffffff ) newSz = 0xffffffff; buf[28] = (newSz>>24) & 0xff; buf[29] = (newSz>>16) & 0xff; buf[30] = (newSz>>8) & 0xff; buf[31] = newSz & 0xff; fseek(f, 28, SEEK_SET); fwrite(&buf[28],4,1,f); fseek(f, (long)(newSz*pgsz - 1), SEEK_SET); fwrite(&zero,1,1,f); fclose(f); return 0; not_valid_db: fprintf(stderr,"not a valid database: %s\n", argv[1]); exit(1); usage_error: fprintf(stderr,"Usage: %s DATABASE N\n", argv[0]); exit(1); } |
Added tool/extract-sqlite3h.tcl.
> > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | #!/usr/bin/tclsh # # Given an sqlite3.c source file identified by the command-line # argument, extract the "sqlite3.h" header file that is embedded inside # the sqlite3.c source file and write it to standard output. # if {[llength $argv]!=1} { puts stderr "Usage: $argv0 sqlite3.c >sqlite3.h" exit 1 } set in [open [lindex $argv 0] rb] while {![eof $in]} { set line [gets $in] if {[string match {* Begin file sqlite3.h *} $line]} break } while {![eof $in]} { set line [gets $in] if {[string match {* End of sqlite3.h *} $line]} break puts $line } close $in |
Changes to tool/fast_vacuum.c.
︙ | ︙ | |||
146 147 148 149 150 151 152 | sqlite3_free(zSql); /* TODO: ** Set the page_size and auto_vacuum mode for zTempDb here, if desired. */ /* The vacuum will occur inside of a transaction. Set writable_schema | | | | | | | | | | | 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 | sqlite3_free(zSql); /* TODO: ** Set the page_size and auto_vacuum mode for zTempDb here, if desired. */ /* The vacuum will occur inside of a transaction. Set writable_schema ** to ON so that we can directly update the sqlite_schema table in the ** zTempDb database. */ execSql(db, "PRAGMA writable_schema=ON"); execSql(db, "BEGIN"); /* Query the schema of the main database. Create a mirror schema ** in the temporary database. */ execExecSql(db, "SELECT 'CREATE TABLE vacuum_db.' || substr(sql,14) " " FROM sqlite_schema WHERE type='table' AND name!='sqlite_sequence'" " AND rootpage>0" ); execExecSql(db, "SELECT 'CREATE INDEX vacuum_db.' || substr(sql,14)" " FROM sqlite_schema WHERE sql LIKE 'CREATE INDEX %'" ); execExecSql(db, "SELECT 'CREATE UNIQUE INDEX vacuum_db.' || substr(sql,21) " " FROM sqlite_schema WHERE sql LIKE 'CREATE UNIQUE INDEX %'" ); /* Loop through the tables in the main database. For each, do ** an "INSERT INTO vacuum_db.xxx SELECT * FROM main.xxx;" to copy ** the contents to the temporary database. */ execExecSql(db, "SELECT 'INSERT INTO vacuum_db.' || quote(name) " "|| ' SELECT * FROM main.' || quote(name) " "FROM main.sqlite_schema " "WHERE type = 'table' AND name!='sqlite_sequence' " " AND rootpage>0" ); /* Copy over the sequence table */ execExecSql(db, "SELECT 'DELETE FROM vacuum_db.' || quote(name) " "FROM vacuum_db.sqlite_schema WHERE name='sqlite_sequence'" ); execExecSql(db, "SELECT 'INSERT INTO vacuum_db.' || quote(name) " "|| ' SELECT * FROM main.' || quote(name) " "FROM vacuum_db.sqlite_schema WHERE name=='sqlite_sequence'" ); /* Copy the triggers, views, and virtual tables from the main database ** over to the temporary database. None of these objects has any ** associated storage, so all we have to do is copy their entries ** from the SQLITE_MASTER table. */ execSql(db, "INSERT INTO vacuum_db.sqlite_schema " " SELECT type, name, tbl_name, rootpage, sql" " FROM main.sqlite_schema" " WHERE type='view' OR type='trigger'" " OR (type='table' AND rootpage=0)" ); /* Commit the transaction and close the database */ execSql(db, "COMMIT"); |
︙ | ︙ |
Changes to tool/index_usage.c.
︙ | ︙ | |||
17 18 19 20 21 22 23 | #include "sqlite3.h" #include <stdio.h> #include <stdlib.h> #include <assert.h> #include <string.h> static void usage(const char *argv0){ | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | | > > > > > > > > > > > > | > > > > > > > | | | | < > > | | | | | > | 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 | #include "sqlite3.h" #include <stdio.h> #include <stdlib.h> #include <assert.h> #include <string.h> static void usage(const char *argv0){ printf("Usage: %s [OPTIONS] DATABASE LOG\n\n", argv0); printf( "DATABASE is an SQLite database against which various statements\n" "have been run. The SQL text is stored in LOG. LOG is an SQLite\n" "database with this schema:\n" "\n" " CREATE TABLE sqllog(sql TEXT);\n" "\n" "This utility program analyzes statements contained in LOG and prints\n" "a report showing how many times each index in DATABASE is used by the\n" "statements in LOG.\n" "\n" "DATABASE only needs to contain the schema used by the statements in\n" "LOG. The content can be removed from DATABASE.\n" ); printf( "\nOPTIONS:\n\n" " --progress N Show a progress message after every N input rows\n" " -q Omit error message when parsing log entries\n" " --using NAME Print SQL statements that use index NAME\n" ); printf("\nAnalysis will be done by SQLite version %s dated %.20s\n" "checkin number %.40s. Different versions\n" "of SQLite might use different indexes.\n", sqlite3_libversion(), sqlite3_sourceid(), sqlite3_sourceid()+21); exit(1); } int main(int argc, char **argv){ sqlite3 *db = 0; /* The main database */ sqlite3_stmt *pStmt = 0; /* a query */ char *zSql; int nErr = 0; int rc; int bQuiet = 0; int i, j; const char *zUsing = 0; sqlite3_stmt *pIncrCnt = 0; int nRow = 0; int iProgress = 0; for(i=j=1; i<argc; i++){ const char *z = argv[i]; if( z[0]=='-' ){ z++; if( z[0]=='-' ) z++; if( strcmp(z,"progress")==0 ){ if( i+1<argc ){ iProgress = strtol(argv[++i],0,0); continue; } printf("The --progress option requires an argument\n"); exit(0); } if( strcmp(z,"q")==0 ){ bQuiet = 1; continue; } if( strcmp(z,"using")==0 ){ if( i+1<argc ){ zUsing = argv[++i]; continue; } printf("The --using option requires an argument\n"); exit(0); } if( strcmp(z, "help")==0 || strcmp(z, "?")==0 ){ usage(argv[0]); } printf("Unknown command-line option: \"%s\"\n", argv[i]); exit(0); }else{ if( j<i ) argv[j++] = argv[i]; } } argc = j; if( argc!=3 ) usage(argv[0]); rc = sqlite3_open_v2(argv[1], &db, SQLITE_OPEN_READONLY, 0); if( rc ){ printf("Cannot open \"%s\" for reading: %s\n", argv[1], sqlite3_errmsg(db)); goto errorOut; } rc = sqlite3_prepare_v2(db, "SELECT * FROM sqlite_schema", -1, &pStmt, 0); if( rc ){ printf("Cannot read the schema from \"%s\" - %s\n", argv[1], sqlite3_errmsg(db)); goto errorOut; } sqlite3_finalize(pStmt); pStmt = 0; rc = sqlite3_exec(db, "CREATE TABLE temp.idxu(\n" " tbl TEXT COLLATE nocase,\n" " idx TEXT COLLATE nocase,\n" " cnt INT,\n" " PRIMARY KEY(idx)\n" ") WITHOUT ROWID;", 0, 0, 0); if( rc ){ printf("Cannot create the result table - %s\n", sqlite3_errmsg(db)); goto errorOut; } rc = sqlite3_exec(db, "INSERT INTO temp.idxu(tbl,idx,cnt)" " SELECT tbl_name, name, 0 FROM sqlite_schema" " WHERE type='index' AND sql IS NOT NULL", 0, 0, 0); /* Open the LOG database */ zSql = sqlite3_mprintf("ATTACH %Q AS log", argv[2]); rc = sqlite3_exec(db, zSql, 0, 0, 0); sqlite3_free(zSql); if( rc ){ printf("Cannot open the LOG database \"%s\" - %s\n", argv[2], sqlite3_errmsg(db)); goto errorOut; } rc = sqlite3_prepare_v2(db, "SELECT sql, rowid FROM log.sqllog" " WHERE upper(substr(sql,1,5)) NOT IN ('BEGIN','COMMI','ROLLB','PRAGM')", -1, &pStmt, 0); if( rc ){ printf("Cannot read the SQLLOG table in the LOG database \"%s\" - %s\n", argv[2], sqlite3_errmsg(db)); goto errorOut; } rc = sqlite3_prepare_v2(db, "UPDATE temp.idxu SET cnt=cnt+1 WHERE idx=?1", -1, &pIncrCnt, 0); if( rc ){ printf("Cannot prepare a statement to increment a counter for " "indexes used\n"); goto errorOut; } /* Update the counts based on LOG */ while( sqlite3_step(pStmt)==SQLITE_ROW ){ const char *zLog = (const char*)sqlite3_column_text(pStmt, 0); sqlite3_stmt *pS2; if( zLog==0 ) continue; zSql = sqlite3_mprintf("EXPLAIN QUERY PLAN %s", zLog); rc = sqlite3_prepare_v2(db, zSql, -1, &pS2, 0); sqlite3_free(zSql); if( rc ){ if( !bQuiet ){ printf("Cannot compile LOG entry %d (%s): %s\n", sqlite3_column_int(pStmt, 1), zLog, sqlite3_errmsg(db)); fflush(stdout); } nErr++; }else{ nRow++; if( iProgress>0 && (nRow%iProgress)==0 ){ printf("%d...\n", nRow); fflush(stdout); } while( sqlite3_step(pS2)==SQLITE_ROW ){ const char *zExplain = (const char*)sqlite3_column_text(pS2,3); const char *z1, *z2; int n; /* printf("EXPLAIN: %s\n", zExplain); */ z1 = strstr(zExplain, " USING INDEX "); if( z1==0 ) continue; z1 += 13; for(z2=z1+1; z2[0] && z2[1]!='('; z2++){} n = z2 - z1; if( zUsing && sqlite3_strnicmp(zUsing, z1, n)==0 ){ printf("Using %s:\n%s\n", zUsing, zLog); fflush(stdout); } sqlite3_bind_text(pIncrCnt,1,z1,n,SQLITE_STATIC); sqlite3_step(pIncrCnt); sqlite3_reset(pIncrCnt); } } sqlite3_finalize(pS2); } sqlite3_finalize(pStmt); /* Generate the report */ rc = sqlite3_prepare_v2(db, "SELECT tbl, idx, cnt, " " (SELECT group_concat(name,',') FROM pragma_index_info(idx))" " FROM temp.idxu, main.sqlite_schema" " WHERE temp.idxu.tbl=main.sqlite_schema.tbl_name" " AND temp.idxu.idx=main.sqlite_schema.name" " ORDER BY cnt DESC, tbl, idx", -1, &pStmt, 0); if( rc ){ printf("Cannot query the result table - %s\n", sqlite3_errmsg(db)); goto errorOut; } while( sqlite3_step(pStmt)==SQLITE_ROW ){ printf("%10d %s on %s(%s)\n", sqlite3_column_int(pStmt, 2), sqlite3_column_text(pStmt, 1), sqlite3_column_text(pStmt, 0), sqlite3_column_text(pStmt, 3)); } sqlite3_finalize(pStmt); pStmt = 0; errorOut: sqlite3_finalize(pIncrCnt); sqlite3_finalize(pStmt); sqlite3_close(db); return nErr; } |
Changes to tool/lemon.c.
︙ | ︙ | |||
44 45 46 47 48 49 50 51 52 53 54 55 56 57 | #ifdef TEST #define MAXRHS 5 /* Set low to exercise exception code */ #else #define MAXRHS 1000 #endif static int showPrecedenceConflict = 0; static char *msort(char*,char**,int(*)(const char*,const char*)); /* ** Compilers are getting increasingly pedantic about type conversions ** as C evolves ever closer to Ada.... To work around the latest problems ** we have to define the following variant of strlen(). | > | 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | #ifdef TEST #define MAXRHS 5 /* Set low to exercise exception code */ #else #define MAXRHS 1000 #endif extern void memory_error(); static int showPrecedenceConflict = 0; static char *msort(char*,char**,int(*)(const char*,const char*)); /* ** Compilers are getting increasingly pedantic about type conversions ** as C evolves ever closer to Ada.... To work around the latest problems ** we have to define the following variant of strlen(). |
︙ | ︙ | |||
213 214 215 216 217 218 219 | void Plink_add(struct plink **, struct config *); void Plink_copy(struct plink **, struct plink *); void Plink_delete(struct plink *); /********** From the file "report.h" *************************************/ void Reprint(struct lemon *); void ReportOutput(struct lemon *); | | | 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 | void Plink_add(struct plink **, struct config *); void Plink_copy(struct plink **, struct plink *); void Plink_delete(struct plink *); /********** From the file "report.h" *************************************/ void Reprint(struct lemon *); void ReportOutput(struct lemon *); void ReportTable(struct lemon *, int, int); void ReportHeader(struct lemon *); void CompressTables(struct lemon *); void ResortStates(struct lemon *); /********** From the file "set.h" ****************************************/ void SetSize(int); /* All sets will be of size N */ char *SetNew(void); /* A new set for element 0..N */ |
︙ | ︙ | |||
287 288 289 290 291 292 293 | int nrhs; /* Number of RHS symbols */ struct symbol **rhs; /* The RHS symbols */ const char **rhsalias; /* An alias for each RHS symbol (NULL if none) */ int line; /* Line number at which code begins */ const char *code; /* The code executed when this rule is reduced */ const char *codePrefix; /* Setup code before code[] above */ const char *codeSuffix; /* Breakdown code after code[] above */ | < < > > > > | 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 | int nrhs; /* Number of RHS symbols */ struct symbol **rhs; /* The RHS symbols */ const char **rhsalias; /* An alias for each RHS symbol (NULL if none) */ int line; /* Line number at which code begins */ const char *code; /* The code executed when this rule is reduced */ const char *codePrefix; /* Setup code before code[] above */ const char *codeSuffix; /* Breakdown code after code[] above */ struct symbol *precsym; /* Precedence symbol for this rule */ int index; /* An index number for this rule */ int iRule; /* Rule number as used in the generated tables */ Boolean noCode; /* True if this rule has no associated C code */ Boolean codeEmitted; /* True if the code has been emitted already */ Boolean canReduce; /* True if this rule is ever reduced */ Boolean doesReduce; /* Reduce actions occur after optimization */ Boolean neverReduce; /* Reduce is theoretically possible, but prevented ** by actions or other outside implementation */ struct rule *nextlhs; /* Next rule with the same LHS */ struct rule *next; /* Next rule in the global list */ }; /* A configuration is a production rule of the grammar together with ** a mark (dot) showing how much of that rule has been processed so far. ** Configurations also contain a follow-set which is a list of terminal |
︙ | ︙ | |||
380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 | struct lemon { struct state **sorted; /* Table of states sorted by state number */ struct rule *rule; /* List of all rules */ struct rule *startRule; /* First rule */ int nstate; /* Number of states */ int nxstate; /* nstate with tail degenerate states removed */ int nrule; /* Number of rules */ int nsymbol; /* Number of terminal and nonterminal symbols */ int nterminal; /* Number of terminal symbols */ int minShiftReduce; /* Minimum shift-reduce action value */ int errAction; /* Error action value */ int accAction; /* Accept action value */ int noAction; /* No-op action value */ int minReduce; /* Minimum reduce action */ int maxAction; /* Maximum action value of any kind */ struct symbol **symbols; /* Sorted array of pointers to symbols */ int errorcnt; /* Number of errors */ struct symbol *errsym; /* The error symbol */ struct symbol *wildcard; /* Token that matches anything */ char *name; /* Name of the generated parser */ | > | | 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 | struct lemon { struct state **sorted; /* Table of states sorted by state number */ struct rule *rule; /* List of all rules */ struct rule *startRule; /* First rule */ int nstate; /* Number of states */ int nxstate; /* nstate with tail degenerate states removed */ int nrule; /* Number of rules */ int nruleWithAction; /* Number of rules with actions */ int nsymbol; /* Number of terminal and nonterminal symbols */ int nterminal; /* Number of terminal symbols */ int minShiftReduce; /* Minimum shift-reduce action value */ int errAction; /* Error action value */ int accAction; /* Accept action value */ int noAction; /* No-op action value */ int minReduce; /* Minimum reduce action */ int maxAction; /* Maximum action value of any kind */ struct symbol **symbols; /* Sorted array of pointers to symbols */ int errorcnt; /* Number of errors */ struct symbol *errsym; /* The error symbol */ struct symbol *wildcard; /* Token that matches anything */ char *name; /* Name of the generated parser */ char *arg; /* Declaration of the 3rd argument to parser */ char *ctx; /* Declaration of 2nd argument to constructor */ char *tokentype; /* Type of terminal symbols in the parser stack */ char *vartype; /* The default type of non-terminal symbols */ char *start; /* Name of the start symbol for the grammar */ char *stacksize; /* Size of the parser stack */ char *include; /* Code to put at the start of the C file */ char *error; /* Code to execute when an error is seen */ |
︙ | ︙ | |||
415 416 417 418 419 420 421 422 423 424 425 426 427 428 | char *outname; /* Name of the current output file */ char *tokenprefix; /* A prefix added to token names in the .h file */ int nconflict; /* Number of parsing conflicts */ int nactiontab; /* Number of entries in the yy_action[] table */ int nlookaheadtab; /* Number of entries in yy_lookahead[] */ int tablesize; /* Total table size of all tables in bytes */ int basisflag; /* Print only basis configurations */ int has_fallback; /* True if any %fallback is seen in the grammar */ int nolinenosflag; /* True if #line statements should not be printed */ char *argv0; /* Name of the program */ }; #define MemoryCheck(X) if((X)==0){ \ extern void memory_error(); \ | > | 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 | char *outname; /* Name of the current output file */ char *tokenprefix; /* A prefix added to token names in the .h file */ int nconflict; /* Number of parsing conflicts */ int nactiontab; /* Number of entries in the yy_action[] table */ int nlookaheadtab; /* Number of entries in yy_lookahead[] */ int tablesize; /* Total table size of all tables in bytes */ int basisflag; /* Print only basis configurations */ int printPreprocessed; /* Show preprocessor output on stdout */ int has_fallback; /* True if any %fallback is seen in the grammar */ int nolinenosflag; /* True if #line statements should not be printed */ char *argv0; /* Name of the program */ }; #define MemoryCheck(X) if((X)==0){ \ extern void memory_error(); \ |
︙ | ︙ | |||
479 480 481 482 483 484 485 | /****************** From the file "action.c" *******************************/ /* ** Routines processing parser actions in the LEMON parser generator. */ /* Allocate a new parser action */ static struct action *Action_new(void){ | | | | | | | | | | 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 | /****************** From the file "action.c" *******************************/ /* ** Routines processing parser actions in the LEMON parser generator. */ /* Allocate a new parser action */ static struct action *Action_new(void){ static struct action *actionfreelist = 0; struct action *newaction; if( actionfreelist==0 ){ int i; int amt = 100; actionfreelist = (struct action *)calloc(amt, sizeof(struct action)); if( actionfreelist==0 ){ fprintf(stderr,"Unable to allocate memory for a new parser action."); exit(1); } for(i=0; i<amt-1; i++) actionfreelist[i].next = &actionfreelist[i+1]; actionfreelist[amt-1].next = 0; } newaction = actionfreelist; actionfreelist = actionfreelist->next; return newaction; } /* Compare two actions for sorting purposes. Return negative, zero, or ** positive if the first action is less than, equal to, or greater than ** the first */ |
︙ | ︙ | |||
902 903 904 905 906 907 908 | Configlist_init(); /* Find the start symbol */ if( lemp->start ){ sp = Symbol_find(lemp->start); if( sp==0 ){ ErrorMsg(lemp->filename,0, | | | | | > > > | | | | 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 | Configlist_init(); /* Find the start symbol */ if( lemp->start ){ sp = Symbol_find(lemp->start); if( sp==0 ){ ErrorMsg(lemp->filename,0, "The specified start symbol \"%s\" is not " "in a nonterminal of the grammar. \"%s\" will be used as the start " "symbol instead.",lemp->start,lemp->startRule->lhs->name); lemp->errorcnt++; sp = lemp->startRule->lhs; } }else if( lemp->startRule ){ sp = lemp->startRule->lhs; }else{ ErrorMsg(lemp->filename,0,"Internal error - no start rule\n"); exit(1); } /* Make sure the start symbol doesn't occur on the right-hand side of ** any rule. Report an error if it does. (YACC would generate a new ** start symbol in this case.) */ for(rp=lemp->rule; rp; rp=rp->next){ int i; for(i=0; i<rp->nrhs; i++){ if( rp->rhs[i]==sp ){ /* FIX ME: Deal with multiterminals */ ErrorMsg(lemp->filename,0, "The start symbol \"%s\" occurs on the " "right-hand side of a rule. This will result in a parser which " "does not work properly.",sp->name); lemp->errorcnt++; } } } /* The basis configuration set for the first state ** is all rules which have the start symbol as their |
︙ | ︙ | |||
1018 1019 1020 1021 1022 1023 1024 | struct config *cfp; /* For looping thru the config closure of "stp" */ struct config *bcfp; /* For the inner loop on config closure of "stp" */ struct config *newcfg; /* */ struct symbol *sp; /* Symbol following the dot in configuration "cfp" */ struct symbol *bsp; /* Symbol following the dot in configuration "bcfp" */ struct state *newstp; /* A pointer to a successor state */ | | | 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 | struct config *cfp; /* For looping thru the config closure of "stp" */ struct config *bcfp; /* For the inner loop on config closure of "stp" */ struct config *newcfg; /* */ struct symbol *sp; /* Symbol following the dot in configuration "cfp" */ struct symbol *bsp; /* Symbol following the dot in configuration "bcfp" */ struct state *newstp; /* A pointer to a successor state */ /* Each configuration becomes complete after it contributes to a successor ** state. Initially, all configurations are incomplete */ for(cfp=stp->cfp; cfp; cfp=cfp->next) cfp->status = INCOMPLETE; /* Loop through all configurations of the state "stp" */ for(cfp=stp->cfp; cfp; cfp=cfp->next){ if( cfp->status==COMPLETE ) continue; /* Already used by inner loop */ if( cfp->dot>=cfp->rp->nrhs ) continue; /* Can't shift this config */ |
︙ | ︙ | |||
1074 1075 1076 1077 1078 1079 1080 | struct plink *plp; /* Housekeeping detail: ** Add to every propagate link a pointer back to the state to ** which the link is attached. */ for(i=0; i<lemp->nstate; i++){ stp = lemp->sorted[i]; | | | | 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 | struct plink *plp; /* Housekeeping detail: ** Add to every propagate link a pointer back to the state to ** which the link is attached. */ for(i=0; i<lemp->nstate; i++){ stp = lemp->sorted[i]; for(cfp=stp?stp->cfp:0; cfp; cfp=cfp->next){ cfp->stp = stp; } } /* Convert all backlinks into forward links. Only the forward ** links are used in the follow-set computation. */ for(i=0; i<lemp->nstate; i++){ stp = lemp->sorted[i]; for(cfp=stp?stp->cfp:0; cfp; cfp=cfp->next){ for(plp=cfp->bplp; plp; plp=plp->next){ other = plp->cfp; Plink_add(&other->fplp,cfp); } } } } |
︙ | ︙ | |||
1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 | int i; struct config *cfp; struct plink *plp; int progress; int change; for(i=0; i<lemp->nstate; i++){ for(cfp=lemp->sorted[i]->cfp; cfp; cfp=cfp->next){ cfp->status = INCOMPLETE; } } do{ progress = 0; for(i=0; i<lemp->nstate; i++){ for(cfp=lemp->sorted[i]->cfp; cfp; cfp=cfp->next){ if( cfp->status==COMPLETE ) continue; for(plp=cfp->fplp; plp; plp=plp->next){ change = SetUnion(plp->cfp->fws,cfp->fws); if( change ){ plp->cfp->status = INCOMPLETE; progress = 1; | > > | 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 | int i; struct config *cfp; struct plink *plp; int progress; int change; for(i=0; i<lemp->nstate; i++){ assert( lemp->sorted[i]!=0 ); for(cfp=lemp->sorted[i]->cfp; cfp; cfp=cfp->next){ cfp->status = INCOMPLETE; } } do{ progress = 0; for(i=0; i<lemp->nstate; i++){ assert( lemp->sorted[i]!=0 ); for(cfp=lemp->sorted[i]->cfp; cfp; cfp=cfp->next){ if( cfp->status==COMPLETE ) continue; for(plp=cfp->fplp; plp; plp=plp->next){ change = SetUnion(plp->cfp->fws,cfp->fws); if( change ){ plp->cfp->status = INCOMPLETE; progress = 1; |
︙ | ︙ | |||
1163 1164 1165 1166 1167 1168 1169 | } } } /* Add the accepting token */ if( lemp->start ){ sp = Symbol_find(lemp->start); | > > > > > > | > | 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 | } } } /* Add the accepting token */ if( lemp->start ){ sp = Symbol_find(lemp->start); if( sp==0 ){ if( lemp->startRule==0 ){ fprintf(stderr, "internal error on source line %d: no start rule\n", __LINE__); exit(1); } sp = lemp->startRule->lhs; } }else{ sp = lemp->startRule->lhs; } /* Add to the first state (which is always the starting state of the ** finite state machine) an action to ACCEPT if the lookahead is the ** start nonterminal. */ Action_add(&lemp->sorted[0]->ap,ACCEPT,sp,0); |
︙ | ︙ | |||
1290 1291 1292 1293 1294 1295 1296 | static struct config *current = 0; /* Top of list of configurations */ static struct config **currentend = 0; /* Last on list of configs */ static struct config *basis = 0; /* Top of list of basis configs */ static struct config **basisend = 0; /* End of list of basis configs */ /* Return a pointer to a new configuration */ PRIVATE struct config *newconfig(void){ | < < < < | < < < < < < < < < < | 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 | static struct config *current = 0; /* Top of list of configurations */ static struct config **currentend = 0; /* Last on list of configs */ static struct config *basis = 0; /* Top of list of basis configs */ static struct config **basisend = 0; /* End of list of basis configs */ /* Return a pointer to a new configuration */ PRIVATE struct config *newconfig(void){ return (struct config*)calloc(1, sizeof(struct config)); } /* The configuration "old" is no longer used */ PRIVATE void deleteconfig(struct config *old) { old->next = freelist; freelist = old; |
︙ | ︙ | |||
1582 1583 1584 1585 1586 1587 1588 | return pFirst; } /* ** Sort a list of rules in order of increasing iRule value */ static struct rule *Rule_sort(struct rule *rp){ | | | | 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 | return pFirst; } /* ** Sort a list of rules in order of increasing iRule value */ static struct rule *Rule_sort(struct rule *rp){ unsigned int i; struct rule *pNext; struct rule *x[32]; memset(x, 0, sizeof(x)); while( rp ){ pNext = rp->next; rp->next = 0; for(i=0; i<sizeof(x)/sizeof(x[0])-1 && x[i]; i++){ rp = Rule_merge(x[i], rp); x[i] = 0; } x[i] = rp; rp = pNext; } rp = 0; |
︙ | ︙ | |||
1616 1617 1618 1619 1620 1621 1622 | int nLabel = lemonStrlen(zLabel); printf(" %s%.*s %5d\n", zLabel, 35-nLabel, "................................", iValue); } /* The main program. Parse the command line and do it... */ | | < > > > > > > > | | 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 | int nLabel = lemonStrlen(zLabel); printf(" %s%.*s %5d\n", zLabel, 35-nLabel, "................................", iValue); } /* The main program. Parse the command line and do it... */ int main(int argc, char **argv){ static int version = 0; static int rpflag = 0; static int basisflag = 0; static int compress = 0; static int quiet = 0; static int statistics = 0; static int mhflag = 0; static int nolinenosflag = 0; static int noResort = 0; static int sqlFlag = 0; static int printPP = 0; static struct s_options options[] = { {OPT_FLAG, "b", (char*)&basisflag, "Print only the basis in report."}, {OPT_FLAG, "c", (char*)&compress, "Don't compress the action table."}, {OPT_FSTR, "d", (char*)&handle_d_option, "Output directory. Default '.'"}, {OPT_FSTR, "D", (char*)handle_D_option, "Define an %ifdef macro."}, {OPT_FLAG, "E", (char*)&printPP, "Print input file after preprocessing."}, {OPT_FSTR, "f", 0, "Ignored. (Placeholder for -f compiler options.)"}, {OPT_FLAG, "g", (char*)&rpflag, "Print grammar without actions."}, {OPT_FSTR, "I", 0, "Ignored. (Placeholder for '-I' compiler options.)"}, {OPT_FLAG, "m", (char*)&mhflag, "Output a makeheaders compatible file."}, {OPT_FLAG, "l", (char*)&nolinenosflag, "Do not print #line statements."}, {OPT_FSTR, "O", 0, "Ignored. (Placeholder for '-O' compiler options.)"}, {OPT_FLAG, "p", (char*)&showPrecedenceConflict, "Show conflicts resolved by precedence rules"}, {OPT_FLAG, "q", (char*)&quiet, "(Quiet) Don't print the report file."}, {OPT_FLAG, "r", (char*)&noResort, "Do not sort or renumber states"}, {OPT_FLAG, "s", (char*)&statistics, "Print parser stats to standard output."}, {OPT_FLAG, "S", (char*)&sqlFlag, "Generate the *.sql file describing the parser tables."}, {OPT_FLAG, "x", (char*)&version, "Print the version number."}, {OPT_FSTR, "T", (char*)handle_T_option, "Specify a template file."}, {OPT_FSTR, "W", 0, "Ignored. (Placeholder for '-W' compiler options.)"}, {OPT_FLAG,0,0,0} }; int i; int exitcode; struct lemon lem; struct rule *rp; (void)argc; OptInit(argv,options,stderr); if( version ){ printf("Lemon version 1.0\n"); exit(0); } if( OptNArgs()!=1 ){ fprintf(stderr,"Exactly one filename argument is required.\n"); exit(1); } memset(&lem, 0, sizeof(lem)); lem.errorcnt = 0; /* Initialize the machine */ Strsafe_init(); Symbol_init(); State_init(); lem.argv0 = argv[0]; lem.filename = OptArg(0); lem.basisflag = basisflag; lem.nolinenosflag = nolinenosflag; lem.printPreprocessed = printPP; Symbol_new("$"); /* Parse the input file */ Parse(&lem); if( lem.printPreprocessed || lem.errorcnt ) exit(lem.errorcnt); if( lem.nrule==0 ){ fprintf(stderr,"Empty grammar.\n"); exit(1); } lem.errsym = Symbol_find("error"); /* Count and index the symbols of the grammar */ |
︙ | ︙ | |||
1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 | /* Assign sequential rule numbers. Start with 0. Put rules that have no ** reduce action C-code associated with them last, so that the switch() ** statement that selects reduction actions will have a smaller jump table. */ for(i=0, rp=lem.rule; rp; rp=rp->next){ rp->iRule = rp->code ? i++ : -1; } for(rp=lem.rule; rp; rp=rp->next){ if( rp->iRule<0 ) rp->iRule = i++; } lem.startRule = lem.rule; lem.rule = Rule_sort(lem.rule); /* Generate a reprint of the grammar, if requested on the command line */ | > | 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 | /* Assign sequential rule numbers. Start with 0. Put rules that have no ** reduce action C-code associated with them last, so that the switch() ** statement that selects reduction actions will have a smaller jump table. */ for(i=0, rp=lem.rule; rp; rp=rp->next){ rp->iRule = rp->code ? i++ : -1; } lem.nruleWithAction = i; for(rp=lem.rule; rp; rp=rp->next){ if( rp->iRule<0 ) rp->iRule = i++; } lem.startRule = lem.rule; lem.rule = Rule_sort(lem.rule); /* Generate a reprint of the grammar, if requested on the command line */ |
︙ | ︙ | |||
1753 1754 1755 1756 1757 1758 1759 | ** generated parser tables smaller. */ if( noResort==0 ) ResortStates(&lem); /* Generate a report of the parser generated. (the "y.output" file) */ if( !quiet ) ReportOutput(&lem); /* Generate the source code for the parser */ | | | 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 | ** generated parser tables smaller. */ if( noResort==0 ) ResortStates(&lem); /* Generate a report of the parser generated. (the "y.output" file) */ if( !quiet ) ReportOutput(&lem); /* Generate the source code for the parser */ ReportTable(&lem, mhflag, sqlFlag); /* Produce a header file for use by the scanner. (This step is ** omitted if the "-m" option is used because makeheaders will ** generate the file for us.) */ if( !mhflag ) ReportHeader(&lem); } if( statistics ){ |
︙ | ︙ | |||
1871 1872 1873 1874 1875 1876 1877 | ** Inputs: ** list: Pointer to a singly-linked list of structures. ** next: Pointer to pointer to the second element of the list. ** cmp: A comparison function. ** ** Return Value: ** A pointer to the head of a sorted list containing the elements | | | 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 | ** Inputs: ** list: Pointer to a singly-linked list of structures. ** next: Pointer to pointer to the second element of the list. ** cmp: A comparison function. ** ** Return Value: ** A pointer to the head of a sorted list containing the elements ** originally in list. ** ** Side effects: ** The "next" pointers for elements in list are changed. */ #define LISTSIZE 30 static char *msort( char *list, |
︙ | ︙ | |||
1903 1904 1905 1906 1907 1908 1909 | set[i] = ep; } ep = 0; for(i=0; i<LISTSIZE; i++) if( set[i] ) ep = merge(set[i],ep,cmp,offset); return ep; } /************************ From the file "option.c" **************************/ | | > | | > > > | | | | | | | | | | | | 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 | set[i] = ep; } ep = 0; for(i=0; i<LISTSIZE; i++) if( set[i] ) ep = merge(set[i],ep,cmp,offset); return ep; } /************************ From the file "option.c" **************************/ static char **g_argv; static struct s_options *op; static FILE *errstream; #define ISOPT(X) ((X)[0]=='-'||(X)[0]=='+'||strchr((X),'=')!=0) /* ** Print the command line with a carrot pointing to the k-th character ** of the n-th field. */ static void errline(int n, int k, FILE *err) { int spcnt, i; if( g_argv[0] ){ fprintf(err,"%s",g_argv[0]); spcnt = lemonStrlen(g_argv[0]) + 1; }else{ spcnt = 0; } for(i=1; i<n && g_argv[i]; i++){ fprintf(err," %s",g_argv[i]); spcnt += lemonStrlen(g_argv[i])+1; } spcnt += k; for(; g_argv[i]; i++) fprintf(err," %s",g_argv[i]); if( spcnt<20 ){ fprintf(err,"\n%*s^-- here\n",spcnt,""); }else{ fprintf(err,"\n%*shere --^\n",spcnt-7,""); } } /* ** Return the index of the N-th non-switch argument. Return -1 ** if N is out of range. */ static int argindex(int n) { int i; int dashdash = 0; if( g_argv!=0 && *g_argv!=0 ){ for(i=1; g_argv[i]; i++){ if( dashdash || !ISOPT(g_argv[i]) ){ if( n==0 ) return i; n--; } if( strcmp(g_argv[i],"--")==0 ) dashdash = 1; } } return -1; } static char emsg[] = "Command line syntax error: "; /* ** Process a flag command line argument. */ static int handleflags(int i, FILE *err) { int v; int errcnt = 0; int j; for(j=0; op[j].label; j++){ if( strncmp(&g_argv[i][1],op[j].label,lemonStrlen(op[j].label))==0 ) break; } v = g_argv[i][0]=='-' ? 1 : 0; if( op[j].label==0 ){ if( err ){ fprintf(err,"%sundefined option.\n",emsg); errline(i,1,err); } errcnt++; }else if( op[j].arg==0 ){ /* Ignore this option */ }else if( op[j].type==OPT_FLAG ){ *((int*)op[j].arg) = v; }else if( op[j].type==OPT_FFLAG ){ (*(void(*)(int))(op[j].arg))(v); }else if( op[j].type==OPT_FSTR ){ (*(void(*)(char *))(op[j].arg))(&g_argv[i][2]); }else{ if( err ){ fprintf(err,"%smissing argument on switch.\n",emsg); errline(i,1,err); } errcnt++; } |
︙ | ︙ | |||
2000 2001 2002 2003 2004 2005 2006 | { int lv = 0; double dv = 0.0; char *sv = 0, *end; char *cp; int j; int errcnt = 0; | | | | 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 | { int lv = 0; double dv = 0.0; char *sv = 0, *end; char *cp; int j; int errcnt = 0; cp = strchr(g_argv[i],'='); assert( cp!=0 ); *cp = 0; for(j=0; op[j].label; j++){ if( strcmp(g_argv[i],op[j].label)==0 ) break; } *cp = '='; if( op[j].label==0 ){ if( err ){ fprintf(err,"%sundefined option.\n",emsg); errline(i,0,err); } |
︙ | ︙ | |||
2031 2032 2033 2034 2035 2036 2037 | case OPT_DBL: case OPT_FDBL: dv = strtod(cp,&end); if( *end ){ if( err ){ fprintf(err, "%sillegal character in floating-point argument.\n",emsg); | | | | 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 | case OPT_DBL: case OPT_FDBL: dv = strtod(cp,&end); if( *end ){ if( err ){ fprintf(err, "%sillegal character in floating-point argument.\n",emsg); errline(i,(int)((char*)end-(char*)g_argv[i]),err); } errcnt++; } break; case OPT_INT: case OPT_FINT: lv = strtol(cp,&end,0); if( *end ){ if( err ){ fprintf(err,"%sillegal character in integer argument.\n",emsg); errline(i,(int)((char*)end-(char*)g_argv[i]),err); } errcnt++; } break; case OPT_STR: case OPT_FSTR: sv = cp; |
︙ | ︙ | |||
2082 2083 2084 2085 2086 2087 2088 | } return errcnt; } int OptInit(char **a, struct s_options *o, FILE *err) { int errcnt = 0; | | | | | | | | | | | | 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 2142 2143 2144 2145 2146 2147 2148 | } return errcnt; } int OptInit(char **a, struct s_options *o, FILE *err) { int errcnt = 0; g_argv = a; op = o; errstream = err; if( g_argv && *g_argv && op ){ int i; for(i=1; g_argv[i]; i++){ if( g_argv[i][0]=='+' || g_argv[i][0]=='-' ){ errcnt += handleflags(i,err); }else if( strchr(g_argv[i],'=') ){ errcnt += handleswitch(i,err); } } } if( errcnt>0 ){ fprintf(err,"Valid command line options for \"%s\" are:\n",*a); OptPrint(); exit(1); } return 0; } int OptNArgs(void){ int cnt = 0; int dashdash = 0; int i; if( g_argv!=0 && g_argv[0]!=0 ){ for(i=1; g_argv[i]; i++){ if( dashdash || !ISOPT(g_argv[i]) ) cnt++; if( strcmp(g_argv[i],"--")==0 ) dashdash = 1; } } return cnt; } char *OptArg(int n) { int i; i = argindex(n); return i>=0 ? g_argv[i] : 0; } void OptErr(int n) { int i; i = argindex(n); if( i>=0 ) errline(i,0,errstream); |
︙ | ︙ | |||
2250 2251 2252 2253 2254 2255 2256 | #endif switch( psp->state ){ case INITIALIZE: psp->prevrule = 0; psp->preccounter = 0; psp->firstrule = psp->lastrule = 0; psp->gp->nrule = 0; | | | | | | > > | 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 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 | #endif switch( psp->state ){ case INITIALIZE: psp->prevrule = 0; psp->preccounter = 0; psp->firstrule = psp->lastrule = 0; psp->gp->nrule = 0; /* fall through */ case WAITING_FOR_DECL_OR_RULE: if( x[0]=='%' ){ psp->state = WAITING_FOR_DECL_KEYWORD; }else if( ISLOWER(x[0]) ){ psp->lhs = Symbol_new(x); psp->nrhs = 0; psp->lhsalias = 0; psp->state = WAITING_FOR_ARROW; }else if( x[0]=='{' ){ if( psp->prevrule==0 ){ ErrorMsg(psp->filename,psp->tokenlineno, "There is no prior rule upon which to attach the code " "fragment which begins on this line."); psp->errorcnt++; }else if( psp->prevrule->code!=0 ){ ErrorMsg(psp->filename,psp->tokenlineno, "Code fragment beginning on this line is not the first " "to follow the previous rule."); psp->errorcnt++; }else if( strcmp(x, "{NEVER-REDUCE")==0 ){ psp->prevrule->neverReduce = 1; }else{ psp->prevrule->line = psp->tokenlineno; psp->prevrule->code = &x[1]; psp->prevrule->noCode = 0; } }else if( x[0]=='[' ){ psp->state = PRECEDENCE_MARK_1; |
︙ | ︙ | |||
2295 2296 2297 2298 2299 2300 2301 | psp->errorcnt++; }else if( psp->prevrule==0 ){ ErrorMsg(psp->filename,psp->tokenlineno, "There is no prior rule to assign precedence \"[%s]\".",x); psp->errorcnt++; }else if( psp->prevrule->precsym!=0 ){ ErrorMsg(psp->filename,psp->tokenlineno, | | | | 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 | psp->errorcnt++; }else if( psp->prevrule==0 ){ ErrorMsg(psp->filename,psp->tokenlineno, "There is no prior rule to assign precedence \"[%s]\".",x); psp->errorcnt++; }else if( psp->prevrule->precsym!=0 ){ ErrorMsg(psp->filename,psp->tokenlineno, "Precedence mark on this line is not the first " "to follow the previous rule."); psp->errorcnt++; }else{ psp->prevrule->precsym = Symbol_new(x); } psp->state = PRECEDENCE_MARK_2; break; case PRECEDENCE_MARK_2: |
︙ | ︙ | |||
2408 2409 2410 2411 2412 2413 2414 | psp->errorcnt++; psp->state = RESYNC_AFTER_RULE_ERROR; }else{ psp->rhs[psp->nrhs] = Symbol_new(x); psp->alias[psp->nrhs] = 0; psp->nrhs++; } | | | 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 | psp->errorcnt++; psp->state = RESYNC_AFTER_RULE_ERROR; }else{ psp->rhs[psp->nrhs] = Symbol_new(x); psp->alias[psp->nrhs] = 0; psp->nrhs++; } }else if( (x[0]=='|' || x[0]=='/') && psp->nrhs>0 && ISUPPER(x[1]) ){ struct symbol *msp = psp->rhs[psp->nrhs-1]; if( msp->type!=MULTITERMINAL ){ struct symbol *origsp = msp; msp = (struct symbol *) calloc(1,sizeof(*msp)); memset(msp, 0, sizeof(*msp)); msp->type = MULTITERMINAL; msp->nsubsym = 1; |
︙ | ︙ | |||
2620 2621 2622 2623 2624 2625 2626 | if( *psp->declargslot ){ zOld = *psp->declargslot; }else{ zOld = ""; } nOld = lemonStrlen(zOld); n = nOld + nNew + 20; | | > > | | 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 | if( *psp->declargslot ){ zOld = *psp->declargslot; }else{ zOld = ""; } nOld = lemonStrlen(zOld); n = nOld + nNew + 20; addLineMacro = !psp->gp->nolinenosflag && psp->insertLineMacro && psp->tokenlineno>1 && (psp->decllinenoslot==0 || psp->decllinenoslot[0]!=0); if( addLineMacro ){ for(z=psp->filename, nBack=0; *z; z++){ if( *z=='\\' ) nBack++; } lemon_sprintf(zLine, "#line %d ", psp->tokenlineno); nLine = lemonStrlen(zLine); n += nLine + lemonStrlen(psp->filename) + nBack; |
︙ | ︙ | |||
2688 2689 2690 2691 2692 2693 2694 | } break; case WAITING_FOR_TOKEN_NAME: /* Tokens do not have to be declared before use. But they can be ** in order to control their assigned integer number. The number for ** each token is assigned when it is first seen. So by including ** | | | 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 | } break; case WAITING_FOR_TOKEN_NAME: /* Tokens do not have to be declared before use. But they can be ** in order to control their assigned integer number. The number for ** each token is assigned when it is first seen. So by including ** ** %token ONE TWO THREE. ** ** early in the grammar file, that assigns small consecutive values ** to each of the tokens ONE TWO and THREE. */ if( x[0]=='.' ){ psp->state = WAITING_FOR_DECL_OR_RULE; }else if( !ISUPPER(x[0]) ){ |
︙ | ︙ | |||
2724 2725 2726 2727 2728 2729 2730 | psp->errorcnt++; } } break; case WAITING_FOR_CLASS_ID: if( !ISLOWER(x[0]) ){ ErrorMsg(psp->filename, psp->tokenlineno, | | | 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 | psp->errorcnt++; } } break; case WAITING_FOR_CLASS_ID: if( !ISLOWER(x[0]) ){ ErrorMsg(psp->filename, psp->tokenlineno, "%%token_class must be followed by an identifier: %s", x); psp->errorcnt++; psp->state = RESYNC_AFTER_DECL_ERROR; }else if( Symbol_find(x) ){ ErrorMsg(psp->filename, psp->tokenlineno, "Symbol \"%s\" already used", x); psp->errorcnt++; psp->state = RESYNC_AFTER_DECL_ERROR; |
︙ | ︙ | |||
2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 | ** break; */ case RESYNC_AFTER_DECL_ERROR: if( x[0]=='.' ) psp->state = WAITING_FOR_DECL_OR_RULE; if( x[0]=='%' ) psp->state = WAITING_FOR_DECL_KEYWORD; break; } } /* Run the preprocessor over the input file text. The global variables ** azDefine[0] through azDefine[nDefine-1] contains the names of all defined ** macros. This routine looks for "%ifdef" and "%ifndef" and "%endif" and ** comments them out. Text in between is also commented out as appropriate. */ static void preprocess_input(char *z){ | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > | > | > > | > > | | < | | | < < | | 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 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 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 | ** break; */ case RESYNC_AFTER_DECL_ERROR: if( x[0]=='.' ) psp->state = WAITING_FOR_DECL_OR_RULE; if( x[0]=='%' ) psp->state = WAITING_FOR_DECL_KEYWORD; break; } } /* The text in the input is part of the argument to an %ifdef or %ifndef. ** Evaluate the text as a boolean expression. Return true or false. */ static int eval_preprocessor_boolean(char *z, int lineno){ int neg = 0; int res = 0; int okTerm = 1; int i; for(i=0; z[i]!=0; i++){ if( ISSPACE(z[i]) ) continue; if( z[i]=='!' ){ if( !okTerm ) goto pp_syntax_error; neg = !neg; continue; } if( z[i]=='|' && z[i+1]=='|' ){ if( okTerm ) goto pp_syntax_error; if( res ) return 1; i++; okTerm = 1; continue; } if( z[i]=='&' && z[i+1]=='&' ){ if( okTerm ) goto pp_syntax_error; if( !res ) return 0; i++; okTerm = 1; continue; } if( z[i]=='(' ){ int k; int n = 1; if( !okTerm ) goto pp_syntax_error; for(k=i+1; z[k]; k++){ if( z[k]==')' ){ n--; if( n==0 ){ z[k] = 0; res = eval_preprocessor_boolean(&z[i+1], -1); z[k] = ')'; if( res<0 ){ i = i-res; goto pp_syntax_error; } i = k; break; } }else if( z[k]=='(' ){ n++; }else if( z[k]==0 ){ i = k; goto pp_syntax_error; } } if( neg ){ res = !res; neg = 0; } okTerm = 0; continue; } if( ISALPHA(z[i]) ){ int j, k, n; if( !okTerm ) goto pp_syntax_error; for(k=i+1; ISALNUM(z[k]) || z[k]=='_'; k++){} n = k - i; res = 0; for(j=0; j<nDefine; j++){ if( strncmp(azDefine[j],&z[i],n)==0 && azDefine[j][n]==0 ){ res = 1; break; } } i = k-1; if( neg ){ res = !res; neg = 0; } okTerm = 0; continue; } goto pp_syntax_error; } return res; pp_syntax_error: if( lineno>0 ){ fprintf(stderr, "%%if syntax error on line %d.\n", lineno); fprintf(stderr, " %.*s <-- syntax error here\n", i+1, z); exit(1); }else{ return -(i+1); } } /* Run the preprocessor over the input file text. The global variables ** azDefine[0] through azDefine[nDefine-1] contains the names of all defined ** macros. This routine looks for "%ifdef" and "%ifndef" and "%endif" and ** comments them out. Text in between is also commented out as appropriate. */ static void preprocess_input(char *z){ int i, j, k; int exclude = 0; int start = 0; int lineno = 1; int start_lineno = 1; for(i=0; z[i]; i++){ if( z[i]=='\n' ) lineno++; if( z[i]!='%' || (i>0 && z[i-1]!='\n') ) continue; if( strncmp(&z[i],"%endif",6)==0 && ISSPACE(z[i+6]) ){ if( exclude ){ exclude--; if( exclude==0 ){ for(j=start; j<i; j++) if( z[j]!='\n' ) z[j] = ' '; } } for(j=i; z[j] && z[j]!='\n'; j++) z[j] = ' '; }else if( strncmp(&z[i],"%else",5)==0 && ISSPACE(z[i+5]) ){ if( exclude==1){ exclude = 0; for(j=start; j<i; j++) if( z[j]!='\n' ) z[j] = ' '; }else if( exclude==0 ){ exclude = 1; start = i; start_lineno = lineno; } for(j=i; z[j] && z[j]!='\n'; j++) z[j] = ' '; }else if( strncmp(&z[i],"%ifdef ",7)==0 || strncmp(&z[i],"%if ",4)==0 || strncmp(&z[i],"%ifndef ",8)==0 ){ if( exclude ){ exclude++; }else{ int isNot; int iBool; for(j=i; z[j] && !ISSPACE(z[j]); j++){} iBool = j; isNot = (j==i+7); while( z[j] && z[j]!='\n' ){ j++; } k = z[j]; z[j] = 0; exclude = eval_preprocessor_boolean(&z[iBool], lineno); z[j] = k; if( !isNot ) exclude = !exclude; if( exclude ){ start = i; start_lineno = lineno; } } for(j=i; z[j] && z[j]!='\n'; j++) z[j] = ' '; } |
︙ | ︙ | |||
2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 | return; } fclose(fp); filebuf[filesize] = 0; /* Make an initial pass through the file to handle %ifdef and %ifndef */ preprocess_input(filebuf); /* Now scan the text of the input file */ lineno = 1; for(cp=filebuf; (c= *cp)!=0; ){ if( c=='\n' ) lineno++; /* Keep track of the line number */ if( ISSPACE(c) ){ cp++; continue; } /* Skip all white space */ if( c=='/' && cp[1]=='/' ){ /* Skip C++ style comments */ | > > > > | 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 | return; } fclose(fp); filebuf[filesize] = 0; /* Make an initial pass through the file to handle %ifdef and %ifndef */ preprocess_input(filebuf); if( gp->printPreprocessed ){ printf("%s\n", filebuf); return; } /* Now scan the text of the input file */ lineno = 1; for(cp=filebuf; (c= *cp)!=0; ){ if( c=='\n' ) lineno++; /* Keep track of the line number */ if( ISSPACE(c) ){ cp++; continue; } /* Skip all white space */ if( c=='/' && cp[1]=='/' ){ /* Skip C++ style comments */ |
︙ | ︙ | |||
2899 2900 2901 2902 2903 2904 2905 | cp++; while( (c= *cp)!=0 && c!='\"' ){ if( c=='\n' ) lineno++; cp++; } if( c==0 ){ ErrorMsg(ps.filename,startline, | | > | 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 | cp++; while( (c= *cp)!=0 && c!='\"' ){ if( c=='\n' ) lineno++; cp++; } if( c==0 ){ ErrorMsg(ps.filename,startline, "String starting on this line is not terminated before " "the end of the file."); ps.errorcnt++; nextcp = cp; }else{ nextcp = cp+1; } }else if( c=='{' ){ /* A block of C code */ int level; |
︙ | ︙ | |||
2938 2939 2940 2941 2942 2943 2944 | if( prevc=='\\' ) prevc = 0; else prevc = c; } } } if( c==0 ){ ErrorMsg(ps.filename,ps.tokenlineno, | | > | 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 | if( prevc=='\\' ) prevc = 0; else prevc = c; } } } if( c==0 ){ ErrorMsg(ps.filename,ps.tokenlineno, "C code starting on this line is not terminated before " "the end of the file."); ps.errorcnt++; nextcp = cp; }else{ nextcp = cp+1; } }else if( ISALNUM(c) ){ /* Identifiers */ while( (c= *cp)!=0 && (ISALNUM(c) || c=='_') ) cp++; |
︙ | ︙ | |||
3380 3381 3382 3383 3384 3385 3386 | fprintf(fp,"\n"); } fclose(fp); return; } /* Search for the file "name" which is in the same directory as | | | | | 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530 | fprintf(fp,"\n"); } fclose(fp); return; } /* Search for the file "name" which is in the same directory as ** the executable */ PRIVATE char *pathsearch(char *argv0, char *name, int modemask) { const char *pathlist; char *pathbufptr = 0; char *pathbuf = 0; char *path,*cp; char c; #ifdef __WIN32__ cp = strrchr(argv0,'\\'); #else cp = strrchr(argv0,'/'); |
︙ | ︙ | |||
3419 3420 3421 3422 3423 3424 3425 | *cp = 0; lemon_sprintf(path,"%s/%s",pathbuf,name); *cp = c; if( c==0 ) pathbuf[0] = 0; else pathbuf = &cp[1]; if( access(path,modemask)==0 ) break; } | < > | > > | 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 | *cp = 0; lemon_sprintf(path,"%s/%s",pathbuf,name); *cp = c; if( c==0 ) pathbuf[0] = 0; else pathbuf = &cp[1]; if( access(path,modemask)==0 ) break; } } free(pathbufptr); } return path; } /* Given an action, compute the integer value for that action ** which is to be put in the action table of the generated machine. ** Return negative if no action should be generated. */ PRIVATE int compute_action(struct lemon *lemp, struct action *ap) { int act; switch( ap->type ){ case SHIFT: act = ap->x.stp->statenum; break; case SHIFTREDUCE: { /* Since a SHIFT is inherient after a prior REDUCE, convert any ** SHIFTREDUCE action with a nonterminal on the LHS into a simple ** REDUCE action: */ if( ap->sp->index>=lemp->nterminal && (lemp->errsym==0 || ap->sp->index!=lemp->errsym->index) ){ act = lemp->minReduce + ap->x.rp->iRule; }else{ act = lemp->minShiftReduce + ap->x.rp->iRule; } break; } case REDUCE: act = lemp->minReduce + ap->x.rp->iRule; break; |
︙ | ︙ | |||
3485 3486 3487 3488 3489 3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 | iStart = i+1; } } } fprintf(out,"%s",&line[iStart]); } } /* The next function finds the template file and opens it, returning ** a pointer to the opened file. */ PRIVATE FILE *tplt_open(struct lemon *lemp) { static char templatename[] = "lempar.c"; char buf[1000]; FILE *in; char *tpltname; char *cp; /* first, see if user specified a template filename on the command line. */ if (user_templatename != 0) { if( access(user_templatename,004)==-1 ){ fprintf(stderr,"Can't find the parser driver template file \"%s\".\n", user_templatename); | > > > > > > > > > > > | 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 | iStart = i+1; } } } fprintf(out,"%s",&line[iStart]); } } /* Skip forward past the header of the template file to the first "%%" */ PRIVATE void tplt_skip_header(FILE *in, int *lineno) { char line[LINESIZE]; while( fgets(line,LINESIZE,in) && (line[0]!='%' || line[1]!='%') ){ (*lineno)++; } } /* The next function finds the template file and opens it, returning ** a pointer to the opened file. */ PRIVATE FILE *tplt_open(struct lemon *lemp) { static char templatename[] = "lempar.c"; char buf[1000]; FILE *in; char *tpltname; char *toFree = 0; char *cp; /* first, see if user specified a template filename on the command line. */ if (user_templatename != 0) { if( access(user_templatename,004)==-1 ){ fprintf(stderr,"Can't find the parser driver template file \"%s\".\n", user_templatename); |
︙ | ︙ | |||
3525 3526 3527 3528 3529 3530 3531 | lemon_sprintf(buf,"%s.lt",lemp->filename); } if( access(buf,004)==0 ){ tpltname = buf; }else if( access(templatename,004)==0 ){ tpltname = templatename; }else{ | | | < > | 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 | lemon_sprintf(buf,"%s.lt",lemp->filename); } if( access(buf,004)==0 ){ tpltname = buf; }else if( access(templatename,004)==0 ){ tpltname = templatename; }else{ toFree = tpltname = pathsearch(lemp->argv0,templatename,0); } if( tpltname==0 ){ fprintf(stderr,"Can't find the parser driver template file \"%s\".\n", templatename); lemp->errorcnt++; return 0; } in = fopen(tpltname,"rb"); if( in==0 ){ fprintf(stderr,"Can't open the template file \"%s\".\n",tpltname); lemp->errorcnt++; } free(toFree); return in; } /* Print a #line directive line to the output file. */ PRIVATE void tplt_linedir(FILE *out, int lineno, char *filename) { fprintf(out,"#line %d \"",lineno); |
︙ | ︙ | |||
3724 3725 3726 3727 3728 3729 3730 | if( rp->nrhs==0 ){ /* If there are no RHS symbols, then writing directly to the LHS is ok */ lhsdirect = 1; }else if( rp->rhsalias[0]==0 ){ /* The left-most RHS symbol has no value. LHS direct is ok. But | | | 3868 3869 3870 3871 3872 3873 3874 3875 3876 3877 3878 3879 3880 3881 3882 | if( rp->nrhs==0 ){ /* If there are no RHS symbols, then writing directly to the LHS is ok */ lhsdirect = 1; }else if( rp->rhsalias[0]==0 ){ /* The left-most RHS symbol has no value. LHS direct is ok. But ** we have to call the destructor on the RHS symbol first. */ lhsdirect = 1; if( has_destructor(rp->rhs[0],lemp) ){ append_str(0,0,0,0); append_str(" yy_destructor(yypParser,%d,&yymsp[%d].minor);\n", 0, rp->rhs[0]->index,1-rp->nrhs); rp->codePrefix = Strsafe(append_str(0,0,0,0)); rp->noCode = 0; |
︙ | ︙ | |||
3844 3845 3846 3847 3848 3849 3850 | if( rp->rhsalias[i] ){ if( i>0 ){ int j; if( rp->lhsalias && strcmp(rp->lhsalias,rp->rhsalias[i])==0 ){ ErrorMsg(lemp->filename,rp->ruleline, "%s(%s) has the same label as the LHS but is not the left-most " "symbol on the RHS.", | | | 3988 3989 3990 3991 3992 3993 3994 3995 3996 3997 3998 3999 4000 4001 4002 | if( rp->rhsalias[i] ){ if( i>0 ){ int j; if( rp->lhsalias && strcmp(rp->lhsalias,rp->rhsalias[i])==0 ){ ErrorMsg(lemp->filename,rp->ruleline, "%s(%s) has the same label as the LHS but is not the left-most " "symbol on the RHS.", rp->rhs[i]->name, rp->rhsalias[i]); lemp->errorcnt++; } for(j=0; j<i; j++){ if( rp->rhsalias[j] && strcmp(rp->rhsalias[j],rp->rhsalias[i])==0 ){ ErrorMsg(lemp->filename,rp->ruleline, "Label %s used for multiple symbols on the RHS of a rule.", rp->rhsalias[i]); |
︙ | ︙ | |||
3946 3947 3948 3949 3950 3951 3952 | */ void print_stack_union( FILE *out, /* The output stream */ struct lemon *lemp, /* The main info structure for this parser */ int *plineno, /* Pointer to the line number */ int mhflag /* True if generating makeheaders output */ ){ | | | 4090 4091 4092 4093 4094 4095 4096 4097 4098 4099 4100 4101 4102 4103 4104 | */ void print_stack_union( FILE *out, /* The output stream */ struct lemon *lemp, /* The main info structure for this parser */ int *plineno, /* Pointer to the line number */ int mhflag /* True if generating makeheaders output */ ){ int lineno; /* The line number of the output */ char **types; /* A hash table of datatypes */ int arraysize; /* Size of the "types" array */ int maxdtlength; /* Maximum length of any ".datatype" field. */ char *stddt; /* Standardized name for a datatype */ int i,j; /* Loop counters */ unsigned hash; /* For hashing the name of a type */ const char *name; /* Name of the parser */ |
︙ | ︙ | |||
4138 4139 4140 4141 4142 4143 4144 | } } /* Generate C source code for the parser */ void ReportTable( struct lemon *lemp, | | > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > < < | > > | | | | | < | 4282 4283 4284 4285 4286 4287 4288 4289 4290 4291 4292 4293 4294 4295 4296 4297 4298 4299 4300 4301 4302 4303 4304 4305 4306 4307 4308 4309 4310 4311 4312 4313 4314 4315 4316 4317 4318 4319 4320 4321 4322 4323 4324 4325 4326 4327 4328 4329 4330 4331 4332 4333 4334 4335 4336 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 4389 4390 4391 4392 4393 4394 4395 4396 4397 4398 4399 4400 4401 4402 4403 4404 4405 4406 4407 4408 4409 4410 4411 4412 4413 4414 4415 4416 4417 4418 4419 4420 4421 4422 4423 4424 4425 4426 4427 4428 4429 4430 4431 4432 4433 4434 4435 4436 4437 4438 4439 4440 4441 4442 4443 4444 4445 | } } /* Generate C source code for the parser */ void ReportTable( struct lemon *lemp, int mhflag, /* Output in makeheaders format if true */ int sqlFlag /* Generate the *.sql file too */ ){ FILE *out, *in, *sql; char line[LINESIZE]; int lineno; struct state *stp; struct action *ap; struct rule *rp; struct acttab *pActtab; int i, j, n, sz; int nLookAhead; int szActionType; /* sizeof(YYACTIONTYPE) */ int szCodeType; /* sizeof(YYCODETYPE) */ const char *name; int mnTknOfst, mxTknOfst; int mnNtOfst, mxNtOfst; struct axset *ax; char *prefix; lemp->minShiftReduce = lemp->nstate; lemp->errAction = lemp->minShiftReduce + lemp->nrule; lemp->accAction = lemp->errAction + 1; lemp->noAction = lemp->accAction + 1; lemp->minReduce = lemp->noAction + 1; lemp->maxAction = lemp->minReduce + lemp->nrule; in = tplt_open(lemp); if( in==0 ) return; out = file_open(lemp,".c","wb"); if( out==0 ){ fclose(in); return; } if( sqlFlag==0 ){ sql = 0; }else{ sql = file_open(lemp, ".sql", "wb"); if( sql==0 ){ fclose(in); fclose(out); return; } fprintf(sql, "BEGIN;\n" "CREATE TABLE symbol(\n" " id INTEGER PRIMARY KEY,\n" " name TEXT NOT NULL,\n" " isTerminal BOOLEAN NOT NULL,\n" " fallback INTEGER REFERENCES symbol" " DEFERRABLE INITIALLY DEFERRED\n" ");\n" ); for(i=0; i<lemp->nsymbol; i++){ fprintf(sql, "INSERT INTO symbol(id,name,isTerminal,fallback)" "VALUES(%d,'%s',%s", i, lemp->symbols[i]->name, i<lemp->nterminal ? "TRUE" : "FALSE" ); if( lemp->symbols[i]->fallback ){ fprintf(sql, ",%d);\n", lemp->symbols[i]->fallback->index); }else{ fprintf(sql, ",NULL);\n"); } } fprintf(sql, "CREATE TABLE rule(\n" " ruleid INTEGER PRIMARY KEY,\n" " lhs INTEGER REFERENCES symbol(id),\n" " txt TEXT\n" ");\n" "CREATE TABLE rulerhs(\n" " ruleid INTEGER REFERENCES rule(ruleid),\n" " pos INTEGER,\n" " sym INTEGER REFERENCES symbol(id)\n" ");\n" ); for(i=0, rp=lemp->rule; rp; rp=rp->next, i++){ assert( i==rp->iRule ); fprintf(sql, "INSERT INTO rule(ruleid,lhs,txt)VALUES(%d,%d,'", rp->iRule, rp->lhs->index ); writeRuleText(sql, rp); fprintf(sql,"');\n"); for(j=0; j<rp->nrhs; j++){ struct symbol *sp = rp->rhs[j]; if( sp->type!=MULTITERMINAL ){ fprintf(sql, "INSERT INTO rulerhs(ruleid,pos,sym)VALUES(%d,%d,%d);\n", i,j,sp->index ); }else{ int k; for(k=0; k<sp->nsubsym; k++){ fprintf(sql, "INSERT INTO rulerhs(ruleid,pos,sym)VALUES(%d,%d,%d);\n", i,j,sp->subsym[k]->index ); } } } } fprintf(sql, "COMMIT;\n"); } lineno = 1; fprintf(out, "/* This file is automatically generated by Lemon from input grammar\n" "** source file \"%s\". */\n", lemp->filename); lineno += 2; /* The first %include directive begins with a C-language comment, ** then skip over the header comment of the template file */ if( lemp->include==0 ) lemp->include = ""; for(i=0; ISSPACE(lemp->include[i]); i++){ if( lemp->include[i]=='\n' ){ lemp->include += i+1; i = -1; } } if( lemp->include[0]=='/' ){ tplt_skip_header(in,&lineno); }else{ tplt_xfer(lemp->name,in,out,&lineno); } /* Generate the include code, if any */ tplt_print(out,lemp,lemp->include,&lineno); if( mhflag ){ char *incName = file_makename(lemp, ".h"); fprintf(out,"#include \"%s\"\n", incName); lineno++; free(incName); } tplt_xfer(lemp->name,in,out,&lineno); /* Generate #defines for all tokens */ if( lemp->tokenprefix ) prefix = lemp->tokenprefix; else prefix = ""; if( mhflag ){ fprintf(out,"#if INTERFACE\n"); lineno++; }else{ fprintf(out,"#ifndef %s%s\n", prefix, lemp->symbols[1]->name); } for(i=1; i<lemp->nterminal; i++){ fprintf(out,"#define %s%-30s %2d\n",prefix,lemp->symbols[i]->name,i); lineno++; } fprintf(out,"#endif\n"); lineno++; tplt_xfer(lemp->name,in,out,&lineno); /* Generate the defines */ fprintf(out,"#define YYCODETYPE %s\n", minimum_size_type(0, lemp->nsymbol, &szCodeType)); lineno++; fprintf(out,"#define YYNOCODE %d\n",lemp->nsymbol); lineno++; fprintf(out,"#define YYACTIONTYPE %s\n", |
︙ | ︙ | |||
4344 4345 4346 4347 4348 4349 4350 4351 4352 4353 4354 4355 4356 4357 | } } /* Finish rendering the constants now that the action table has ** been computed */ fprintf(out,"#define YYNSTATE %d\n",lemp->nxstate); lineno++; fprintf(out,"#define YYNRULE %d\n",lemp->nrule); lineno++; fprintf(out,"#define YYNTOKEN %d\n",lemp->nterminal); lineno++; fprintf(out,"#define YY_MAX_SHIFT %d\n",lemp->nxstate-1); lineno++; i = lemp->minShiftReduce; fprintf(out,"#define YY_MIN_SHIFTREDUCE %d\n",i); lineno++; i += lemp->nrule; fprintf(out,"#define YY_MAX_SHIFTREDUCE %d\n", i-1); lineno++; fprintf(out,"#define YY_ERROR_ACTION %d\n", lemp->errAction); lineno++; | > > | 4583 4584 4585 4586 4587 4588 4589 4590 4591 4592 4593 4594 4595 4596 4597 4598 | } } /* Finish rendering the constants now that the action table has ** been computed */ fprintf(out,"#define YYNSTATE %d\n",lemp->nxstate); lineno++; fprintf(out,"#define YYNRULE %d\n",lemp->nrule); lineno++; fprintf(out,"#define YYNRULE_WITH_ACTION %d\n",lemp->nruleWithAction); lineno++; fprintf(out,"#define YYNTOKEN %d\n",lemp->nterminal); lineno++; fprintf(out,"#define YY_MAX_SHIFT %d\n",lemp->nxstate-1); lineno++; i = lemp->minShiftReduce; fprintf(out,"#define YY_MIN_SHIFTREDUCE %d\n",i); lineno++; i += lemp->nrule; fprintf(out,"#define YY_MAX_SHIFTREDUCE %d\n", i-1); lineno++; fprintf(out,"#define YY_ERROR_ACTION %d\n", lemp->errAction); lineno++; |
︙ | ︙ | |||
4398 4399 4400 4401 4402 4403 4404 | lemp->tablesize += n*szCodeType; fprintf(out,"static const YYCODETYPE yy_lookahead[] = {\n"); lineno++; for(i=j=0; i<n; i++){ int la = acttab_yylookahead(pActtab, i); if( la<0 ) la = lemp->nsymbol; if( j==0 ) fprintf(out," /* %5d */ ", i); fprintf(out, " %4d,", la); | | > > > > > > > > > > > > > > > > | 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 | lemp->tablesize += n*szCodeType; fprintf(out,"static const YYCODETYPE yy_lookahead[] = {\n"); lineno++; for(i=j=0; i<n; i++){ int la = acttab_yylookahead(pActtab, i); if( la<0 ) la = lemp->nsymbol; if( j==0 ) fprintf(out," /* %5d */ ", i); fprintf(out, " %4d,", la); if( j==9 ){ fprintf(out, "\n"); lineno++; j = 0; }else{ j++; } } /* Add extra entries to the end of the yy_lookahead[] table so that ** yy_shift_ofst[]+iToken will always be a valid index into the array, ** even for the largest possible value of yy_shift_ofst[] and iToken. */ nLookAhead = lemp->nterminal + lemp->nactiontab; while( i<nLookAhead ){ if( j==0 ) fprintf(out," /* %5d */ ", i); fprintf(out, " %4d,", lemp->nterminal); if( j==9 ){ fprintf(out, "\n"); lineno++; j = 0; }else{ j++; } i++; } if( j>0 ){ fprintf(out, "\n"); lineno++; } fprintf(out, "};\n"); lineno++; /* Output the yy_shift_ofst[] table */ n = lemp->nxstate; while( n>0 && lemp->sorted[n-1]->iTknOfst==NO_OFFSET ) n--; fprintf(out, "#define YY_SHIFT_COUNT (%d)\n", n-1); lineno++; fprintf(out, "#define YY_SHIFT_MIN (%d)\n", mnTknOfst); lineno++; |
︙ | ︙ | |||
4484 4485 4486 4487 4488 4489 4490 | fprintf(out, "};\n"); lineno++; tplt_xfer(lemp->name,in,out,&lineno); /* Generate the table of fallback tokens. */ if( lemp->has_fallback ){ int mx = lemp->nterminal - 1; | > > | | 4741 4742 4743 4744 4745 4746 4747 4748 4749 4750 4751 4752 4753 4754 4755 4756 4757 | fprintf(out, "};\n"); lineno++; tplt_xfer(lemp->name,in,out,&lineno); /* Generate the table of fallback tokens. */ if( lemp->has_fallback ){ int mx = lemp->nterminal - 1; /* 2019-08-28: Generate fallback entries for every token to avoid ** having to do a range check on the index */ /* while( mx>0 && lemp->symbols[mx]->fallback==0 ){ mx--; } */ lemp->tablesize += (mx+1)*szCodeType; for(i=0; i<=mx; i++){ struct symbol *p = lemp->symbols[i]; if( p->fallback==0 ){ fprintf(out, " 0, /* %10s => nothing */\n", p->name); }else{ fprintf(out, " %3d, /* %10s => %s */\n", p->fallback->index, |
︙ | ︙ | |||
4590 4591 4592 4593 4594 4595 4596 | tplt_print(out,lemp,lemp->overflow,&lineno); tplt_xfer(lemp->name,in,out,&lineno); /* Generate the tables of rule information. yyRuleInfoLhs[] and ** yyRuleInfoNRhs[]. ** ** Note: This code depends on the fact that rules are number | | | 4849 4850 4851 4852 4853 4854 4855 4856 4857 4858 4859 4860 4861 4862 4863 | tplt_print(out,lemp,lemp->overflow,&lineno); tplt_xfer(lemp->name,in,out,&lineno); /* Generate the tables of rule information. yyRuleInfoLhs[] and ** yyRuleInfoNRhs[]. ** ** Note: This code depends on the fact that rules are number ** sequentially beginning with 0. */ for(i=0, rp=lemp->rule; rp; rp=rp->next, i++){ fprintf(out," %4d, /* (%d) ", rp->lhs->index, i); rule_print(out, rp); fprintf(out," */\n"); lineno++; } tplt_xfer(lemp->name,in,out,&lineno); |
︙ | ︙ | |||
4645 4646 4647 4648 4649 4650 4651 | ** empty actions. */ fprintf(out," default:\n"); lineno++; for(rp=lemp->rule; rp; rp=rp->next){ if( rp->codeEmitted ) continue; assert( rp->noCode ); fprintf(out," /* (%d) ", rp->iRule); writeRuleText(out, rp); | > > > | | 4904 4905 4906 4907 4908 4909 4910 4911 4912 4913 4914 4915 4916 4917 4918 4919 4920 4921 | ** empty actions. */ fprintf(out," default:\n"); lineno++; for(rp=lemp->rule; rp; rp=rp->next){ if( rp->codeEmitted ) continue; assert( rp->noCode ); fprintf(out," /* (%d) ", rp->iRule); writeRuleText(out, rp); if( rp->neverReduce ){ fprintf(out, " (NEVER REDUCES) */ assert(yyruleno!=%d);\n", rp->iRule); lineno++; }else if( rp->doesReduce ){ fprintf(out, " */ yytestcase(yyruleno==%d);\n", rp->iRule); lineno++; }else{ fprintf(out, " (OPTIMIZED OUT) */ assert(yyruleno!=%d);\n", rp->iRule); lineno++; } } fprintf(out," break;\n"); lineno++; |
︙ | ︙ | |||
4670 4671 4672 4673 4674 4675 4676 4677 4678 4679 4680 4681 4682 4683 4684 4685 | /* Generate code which executes when the parser accepts its input */ tplt_print(out,lemp,lemp->accept,&lineno); tplt_xfer(lemp->name,in,out,&lineno); /* Append any addition code the user desires */ tplt_print(out,lemp,lemp->extracode,&lineno); fclose(in); fclose(out); return; } /* Generate a header file for the parser */ void ReportHeader(struct lemon *lemp) { FILE *out, *in; | > > | 4932 4933 4934 4935 4936 4937 4938 4939 4940 4941 4942 4943 4944 4945 4946 4947 4948 4949 | /* Generate code which executes when the parser accepts its input */ tplt_print(out,lemp,lemp->accept,&lineno); tplt_xfer(lemp->name,in,out,&lineno); /* Append any addition code the user desires */ tplt_print(out,lemp,lemp->extracode,&lineno); acttab_free(pActtab); fclose(in); fclose(out); if( sql ) fclose(sql); return; } /* Generate a header file for the parser */ void ReportHeader(struct lemon *lemp) { FILE *out, *in; |
︙ | ︙ | |||
4914 4915 4916 4917 4918 4919 4920 | } /* Allocate a new set */ char *SetNew(void){ char *s; s = (char*)calloc( size, 1); if( s==0 ){ | < | 5178 5179 5180 5181 5182 5183 5184 5185 5186 5187 5188 5189 5190 5191 | } /* Allocate a new set */ char *SetNew(void){ char *s; s = (char*)calloc( size, 1); if( s==0 ){ memory_error(); } return s; } /* Deallocate a set */ void SetFree(char *s) |
︙ | ︙ | |||
5074 5075 5076 5077 5078 5079 5080 | newnp = &(array.tbl[i]); if( array.ht[h] ) array.ht[h]->from = &(newnp->next); newnp->next = array.ht[h]; newnp->data = oldnp->data; newnp->from = &(array.ht[h]); array.ht[h] = newnp; } | | > | 5337 5338 5339 5340 5341 5342 5343 5344 5345 5346 5347 5348 5349 5350 5351 5352 | newnp = &(array.tbl[i]); if( array.ht[h] ) array.ht[h]->from = &(newnp->next); newnp->next = array.ht[h]; newnp->data = oldnp->data; newnp->from = &(array.ht[h]); array.ht[h] = newnp; } /* free(x1a->tbl); // This program was originally for 16-bit machines. ** Don't worry about freeing memory on modern platforms. */ *x1a = array; } /* Insert the new data */ h = ph & (x1a->size-1); np = &(x1a->tbl[x1a->count++]); np->data = data; if( x1a->ht[h] ) x1a->ht[h]->from = &(np->next); |
︙ | ︙ | |||
5242 5243 5244 5245 5246 5247 5248 | if( array.ht[h] ) array.ht[h]->from = &(newnp->next); newnp->next = array.ht[h]; newnp->key = oldnp->key; newnp->data = oldnp->data; newnp->from = &(array.ht[h]); array.ht[h] = newnp; } | | > > | 5506 5507 5508 5509 5510 5511 5512 5513 5514 5515 5516 5517 5518 5519 5520 5521 5522 | if( array.ht[h] ) array.ht[h]->from = &(newnp->next); newnp->next = array.ht[h]; newnp->key = oldnp->key; newnp->data = oldnp->data; newnp->from = &(array.ht[h]); array.ht[h] = newnp; } /* free(x2a->tbl); // This program was originally written for 16-bit ** machines. Don't worry about freeing this trivial amount of memory ** on modern platforms. Just leak it. */ *x2a = array; } /* Insert the new data */ h = ph & (x2a->size-1); np = &(x2a->tbl[x2a->count++]); np->key = key; np->data = data; |
︙ | ︙ | |||
5578 5579 5580 5581 5582 5583 5584 | newnp = &(array.tbl[i]); if( array.ht[h] ) array.ht[h]->from = &(newnp->next); newnp->next = array.ht[h]; newnp->data = oldnp->data; newnp->from = &(array.ht[h]); array.ht[h] = newnp; } | | > > | 5844 5845 5846 5847 5848 5849 5850 5851 5852 5853 5854 5855 5856 5857 5858 5859 5860 | newnp = &(array.tbl[i]); if( array.ht[h] ) array.ht[h]->from = &(newnp->next); newnp->next = array.ht[h]; newnp->data = oldnp->data; newnp->from = &(array.ht[h]); array.ht[h] = newnp; } /* free(x4a->tbl); // This code was originall written for 16-bit machines. ** on modern machines, don't worry about freeing this trival amount of ** memory. */ *x4a = array; } /* Insert the new data */ h = ph & (x4a->size-1); np = &(x4a->tbl[x4a->count++]); np->data = data; if( x4a->ht[h] ) x4a->ht[h]->from = &(np->next); |
︙ | ︙ |
Changes to tool/lempar.c.
︙ | ︙ | |||
18 19 20 21 22 23 24 | ** the value of the %name directive from the grammar. Otherwise, the content ** of this template is copied straight through into the generate parser ** source file. ** ** The following is the concatenation of all %include directives from the ** input grammar file: */ | < < | < < | | | 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | ** the value of the %name directive from the grammar. Otherwise, the content ** of this template is copied straight through into the generate parser ** source file. ** ** The following is the concatenation of all %include directives from the ** input grammar file: */ /************ Begin %include sections from the grammar ************************/ %% /**************** End of %include directives **********************************/ /* These constants specify the various numeric values for terminal symbols. ***************** Begin token definitions *************************************/ %% /**************** End token definitions ***************************************/ /* The next sections is a series of control #defines. ** various aspects of the generated parser. ** YYCODETYPE is the data type used to store the integer codes ** that represent terminal and non-terminal symbols. ** "unsigned char" is used if there are fewer than ** 256 symbols. Larger types otherwise. |
︙ | ︙ | |||
223 224 225 226 227 228 229 230 231 232 233 234 235 236 | #else yyStackEntry yystack[YYSTACKDEPTH]; /* The parser's stack */ yyStackEntry *yystackEnd; /* Last entry in the stack */ #endif }; typedef struct yyParser yyParser; #ifndef NDEBUG #include <stdio.h> static FILE *yyTraceFILE = 0; static char *yyTracePrompt = 0; #endif /* NDEBUG */ #ifndef NDEBUG | > | 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 | #else yyStackEntry yystack[YYSTACKDEPTH]; /* The parser's stack */ yyStackEntry *yystackEnd; /* Last entry in the stack */ #endif }; typedef struct yyParser yyParser; #include <assert.h> #ifndef NDEBUG #include <stdio.h> static FILE *yyTraceFILE = 0; static char *yyTracePrompt = 0; #endif /* NDEBUG */ #ifndef NDEBUG |
︙ | ︙ | |||
517 518 519 520 521 522 523 | assert( stateno <= YY_SHIFT_COUNT ); #if defined(YYCOVERAGE) yycoverage[stateno][iLookAhead] = 1; #endif do{ i = yy_shift_ofst[stateno]; assert( i>=0 ); | > | > | | | > < < < < < < < | | < > | 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 | assert( stateno <= YY_SHIFT_COUNT ); #if defined(YYCOVERAGE) yycoverage[stateno][iLookAhead] = 1; #endif do{ i = yy_shift_ofst[stateno]; assert( i>=0 ); assert( i<=YY_ACTTAB_COUNT ); assert( i+YYNTOKEN<=(int)YY_NLOOKAHEAD ); assert( iLookAhead!=YYNOCODE ); assert( iLookAhead < YYNTOKEN ); i += iLookAhead; assert( i<(int)YY_NLOOKAHEAD ); if( yy_lookahead[i]!=iLookAhead ){ #ifdef YYFALLBACK YYCODETYPE iFallback; /* Fallback token */ assert( iLookAhead<sizeof(yyFallback)/sizeof(yyFallback[0]) ); iFallback = yyFallback[iLookAhead]; if( iFallback!=0 ){ #ifndef NDEBUG if( yyTraceFILE ){ fprintf(yyTraceFILE, "%sFALLBACK %s => %s\n", yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[iFallback]); } #endif assert( yyFallback[iFallback]==0 ); /* Fallback loop must terminate */ iLookAhead = iFallback; continue; } #endif #ifdef YYWILDCARD { int j = i - iLookAhead + YYWILDCARD; assert( j<(int)(sizeof(yy_lookahead)/sizeof(yy_lookahead[0])) ); if( yy_lookahead[j]==YYWILDCARD && iLookAhead>0 ){ #ifndef NDEBUG if( yyTraceFILE ){ fprintf(yyTraceFILE, "%sWILDCARD %s => %s\n", yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[YYWILDCARD]); } #endif /* NDEBUG */ return yy_action[j]; } } #endif /* YYWILDCARD */ return yy_default[stateno]; }else{ assert( i>=0 && i<(int)(sizeof(yy_action)/sizeof(yy_action[0])) ); return yy_action[i]; } }while(1); } /* ** Find the appropriate action for a parser given the non-terminal |
︙ | ︙ | |||
721 722 723 724 725 726 727 | YYACTIONTYPE yyact; /* The next action */ yyStackEntry *yymsp; /* The top of the parser's stack */ int yysize; /* Amount to pop the stack */ ParseARG_FETCH (void)yyLookahead; (void)yyLookaheadToken; yymsp = yypParser->yytos; | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 714 715 716 717 718 719 720 721 722 723 724 725 726 727 | YYACTIONTYPE yyact; /* The next action */ yyStackEntry *yymsp; /* The top of the parser's stack */ int yysize; /* Amount to pop the stack */ ParseARG_FETCH (void)yyLookahead; (void)yyLookaheadToken; yymsp = yypParser->yytos; switch( yyruleno ){ /* Beginning here are the reduction cases. A typical example ** follows: ** case 0: ** #line <lineno> <grammarfile> ** { ... } // User supplied code |
︙ | ︙ | |||
924 925 926 927 928 929 930 | }else{ fprintf(yyTraceFILE,"%sInput '%s' with pending reduce %d\n", yyTracePrompt,yyTokenName[yymajor],yyact-YY_MIN_REDUCE); } } #endif | | > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > | | 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 | }else{ fprintf(yyTraceFILE,"%sInput '%s' with pending reduce %d\n", yyTracePrompt,yyTokenName[yymajor],yyact-YY_MIN_REDUCE); } } #endif while(1){ /* Exit by "break" */ assert( yypParser->yytos>=yypParser->yystack ); assert( yyact==yypParser->yytos->stateno ); yyact = yy_find_shift_action((YYCODETYPE)yymajor,yyact); if( yyact >= YY_MIN_REDUCE ){ unsigned int yyruleno = yyact - YY_MIN_REDUCE; /* Reduce by this rule */ #ifndef NDEBUG assert( yyruleno<(int)(sizeof(yyRuleName)/sizeof(yyRuleName[0])) ); if( yyTraceFILE ){ int yysize = yyRuleInfoNRhs[yyruleno]; if( yysize ){ fprintf(yyTraceFILE, "%sReduce %d [%s]%s, pop back to state %d.\n", yyTracePrompt, yyruleno, yyRuleName[yyruleno], yyruleno<YYNRULE_WITH_ACTION ? "" : " without external action", yypParser->yytos[yysize].stateno); }else{ fprintf(yyTraceFILE, "%sReduce %d [%s]%s.\n", yyTracePrompt, yyruleno, yyRuleName[yyruleno], yyruleno<YYNRULE_WITH_ACTION ? "" : " without external action"); } } #endif /* NDEBUG */ /* Check that the stack is large enough to grow by a single entry ** if the RHS of the rule is empty. This ensures that there is room ** enough on the stack to push the LHS value */ if( yyRuleInfoNRhs[yyruleno]==0 ){ #ifdef YYTRACKMAXSTACKDEPTH if( (int)(yypParser->yytos - yypParser->yystack)>yypParser->yyhwm ){ yypParser->yyhwm++; assert( yypParser->yyhwm == (int)(yypParser->yytos - yypParser->yystack)); } #endif #if YYSTACKDEPTH>0 if( yypParser->yytos>=yypParser->yystackEnd ){ yyStackOverflow(yypParser); break; } #else if( yypParser->yytos>=&yypParser->yystack[yypParser->yystksz-1] ){ if( yyGrowStack(yypParser) ){ yyStackOverflow(yypParser); break; } } #endif } yyact = yy_reduce(yypParser,yyruleno,yymajor,yyminor ParseCTX_PARAM); }else if( yyact <= YY_MAX_SHIFTREDUCE ){ yy_shift(yypParser,yyact,(YYCODETYPE)yymajor,yyminor); #ifndef YYNOERRORRECOVERY yypParser->yyerrcnt--; #endif break; }else if( yyact==YY_ACCEPT_ACTION ){ |
︙ | ︙ | |||
985 986 987 988 989 990 991 | fprintf(yyTraceFILE,"%sDiscard input token %s\n", yyTracePrompt,yyTokenName[yymajor]); } #endif yy_destructor(yypParser, (YYCODETYPE)yymajor, &yyminorunion); yymajor = YYNOCODE; }else{ | | | < | < > | | 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 | fprintf(yyTraceFILE,"%sDiscard input token %s\n", yyTracePrompt,yyTokenName[yymajor]); } #endif yy_destructor(yypParser, (YYCODETYPE)yymajor, &yyminorunion); yymajor = YYNOCODE; }else{ while( yypParser->yytos > yypParser->yystack ){ yyact = yy_find_reduce_action(yypParser->yytos->stateno, YYERRORSYMBOL); if( yyact<=YY_MAX_SHIFTREDUCE ) break; yy_pop_parser_stack(yypParser); } if( yypParser->yytos <= yypParser->yystack || yymajor==0 ){ yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion); yy_parse_failed(yypParser); #ifndef YYNOERRORRECOVERY yypParser->yyerrcnt = -1; #endif yymajor = YYNOCODE; }else if( yymx!=YYERRORSYMBOL ){ |
︙ | ︙ | |||
1042 1043 1044 1045 1046 1047 1048 | #ifndef YYNOERRORRECOVERY yypParser->yyerrcnt = -1; #endif } break; #endif } | < > | 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 | #ifndef YYNOERRORRECOVERY yypParser->yyerrcnt = -1; #endif } break; #endif } } #ifndef NDEBUG if( yyTraceFILE ){ yyStackEntry *i; char cDiv = '['; fprintf(yyTraceFILE,"%sReturn. Stack=",yyTracePrompt); for(i=&yypParser->yystack[1]; i<=yypParser->yytos; i++){ fprintf(yyTraceFILE,"%c%s", cDiv, yyTokenName[i->major]); |
︙ | ︙ | |||
1064 1065 1066 1067 1068 1069 1070 | /* ** Return the fallback token corresponding to canonical token iToken, or ** 0 if iToken has no fallback. */ int ParseFallback(int iToken){ #ifdef YYFALLBACK | | | < < > | 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 | /* ** Return the fallback token corresponding to canonical token iToken, or ** 0 if iToken has no fallback. */ int ParseFallback(int iToken){ #ifdef YYFALLBACK assert( iToken<(int)(sizeof(yyFallback)/sizeof(yyFallback[0])) ); return yyFallback[iToken]; #else (void)iToken; return 0; #endif } |
Added tool/merge-test.tcl.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 | #!/usr/bin/tcl # # Run this script to test to see that the latest trunk changes can be # merged into LTS branches without breaking anything. # # To Use: # # * Copy this script into a directory above the sqlite checkout # * Run "fossil update trunk" and "fossil revert" # * Run "tclsh ../merge-test.tcl" (in other words run this script) # # Operation: # # This script changes to each LTS branch to be tested, merges the latest # trunk changes into the branch (without committing them) and then # runs "make test". Any errors are stored in local files. # # Limitations: # # Some LTS branches are not synced directly from trunk but rather from # other LTS branches. These other branches cannot be tested because # there is no good way to generate the intermediate merges. # ############################################################################### # Run a shell command contained in arguments. Put the return code in # global variable ::res and the output string in global variable ::result # proc safeexec {args} { global res result set res [catch "exec $args" result] } # Run the shell command contained in arguments. Print an error and exit # if anything goes wrong. # proc mustbeok {args} { global res result set res [catch "exec $args" result] if {$res} { puts "FAILED: $args" puts $result exit 1 } } # Write $content into a file named $filename. The file is overwritten if it # already exist. The file is create if it does not already exist. # proc writefile {filename content} { set fd [open $filename wb] puts $fd $content close $fd } # Run the merge-test # foreach {branch configopts} { begin-concurrent {--enable-json1} begin-concurrent-pnu {--enable-json1} wal2 {--enable-all} reuse-schema {--enable-all} } { puts $branch set errorfile ${branch}-error.txt mustbeok fossil revert mustbeok fossil up $branch safeexec fossil merge trunk if {$res} { puts " merge failed - see $errorfile" writefile $errorfile $result } else { puts " merge ok" safeexec ./configure --enable-debug {*}$configopts if {$res} { puts " configure failed - see $errorfile" writefile $errorfile $result } else { puts " configure ok" safeexec make fuzzcheck sqlite3 testfixture if {$res} { puts " build failed - see $errorfile" writefile $errorfile $result } else { puts " build ok" safeexec make test if {$res} { puts " test failed - see $errorfile" writefile $errorfile $result } else { puts " test ok" } } } } } mustbeok fossil revert mustbeok fossil up trunk puts "reset back to trunk" |
Changes to tool/mkautoconfamal.sh.
1 2 3 4 | #!/bin/sh # This script is used to build the amalgamation autoconf package. # It assumes the following: # | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 | #!/bin/sh # This script is used to build the amalgamation autoconf package. # It assumes the following: # # 1. The files "sqlite3.c", "sqlite3.h", "sqlite3ext.h", "shell.c", # and "sqlite3rc.h" are available in the current directory. # # 2. Variable $TOP is set to the full path of the root directory # of the SQLite source tree. # # 3. There is nothing of value in the ./mkpkg_tmp_dir directory. # This is important, as the script executes "rm -rf ./mkpkg_tmp_dir". # |
︙ | ︙ | |||
45 46 47 48 49 50 51 52 53 54 55 56 57 58 | fi rm -rf $TMPSPACE cp -R $TOP/autoconf $TMPSPACE cp sqlite3.c $TMPSPACE cp sqlite3.h $TMPSPACE cp sqlite3ext.h $TMPSPACE cp $TOP/sqlite3.1 $TMPSPACE cp $TOP/sqlite3.pc.in $TMPSPACE cp shell.c $TMPSPACE cp $TOP/src/sqlite3.rc $TMPSPACE cp $TOP/tool/Replace.cs $TMPSPACE cat $TMPSPACE/configure.ac | | > | 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | fi rm -rf $TMPSPACE cp -R $TOP/autoconf $TMPSPACE cp sqlite3.c $TMPSPACE cp sqlite3.h $TMPSPACE cp sqlite3ext.h $TMPSPACE cp sqlite3rc.h $TMPSPACE cp $TOP/sqlite3.1 $TMPSPACE cp $TOP/sqlite3.pc.in $TMPSPACE cp shell.c $TMPSPACE cp $TOP/src/sqlite3.rc $TMPSPACE cp $TOP/tool/Replace.cs $TMPSPACE cat $TMPSPACE/configure.ac | |
︙ | ︙ |
Changes to tool/mkctimec.tcl.
1 2 3 4 5 6 | #!/usr/bin/tclsh # # To build the # # const char **azCompileOpt[] # | | > | > > | > > > > > > > > > > < < > | | | | | > > > > > > > > < < < < < | | | > | 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 | #!/usr/bin/tclsh # # To build the # # const char **azCompileOpt[] # # definition used in src/ctime.c, run this script from # the checkout root. It alters src/ctime.c in-place. # # All Boolean compile time options which default to something # other than 0 or empty. The default is paired with the PP # symbol so that a differing define can be detected. # set boolean_defnnz_options { {SQLITE_HOMEGROWN_RECURSIVE_MUTEX 1} {SQLITE_POWERSAFE_OVERWRITE 1} {SQLITE_DEFAULT_MEMSTATUS 1} {SQLITE_OMIT_TRACE 1} {SQLITE_ALLOW_COVERING_INDEX_SCAN 1} } # All Boolean compile time options which default to 0 or empty. # set boolean_defnil_options { SQLITE_32BIT_ROWID SQLITE_4_BYTE_ALIGNED_MALLOC SQLITE_64BIT_STATS SQLITE_ALLOW_URI_AUTHORITY SQLITE_BUG_COMPATIBLE_20160819 SQLITE_CASE_SENSITIVE_LIKE SQLITE_CHECK_PAGES SQLITE_COVERAGE_TEST SQLITE_DEBUG SQLITE_DEFAULT_AUTOMATIC_INDEX SQLITE_DEFAULT_AUTOVACUUM SQLITE_DEFAULT_CKPTFULLFSYNC SQLITE_DEFAULT_FOREIGN_KEYS SQLITE_DEFAULT_LOCKING_MODE SQLITE_DEFAULT_RECURSIVE_TRIGGERS SQLITE_DEFAULT_SYNCHRONOUS SQLITE_DEFAULT_WAL_SYNCHRONOUS SQLITE_DIRECT_OVERFLOW_READ SQLITE_DISABLE_DIRSYNC SQLITE_DISABLE_FTS3_UNICODE SQLITE_DISABLE_FTS4_DEFERRED SQLITE_DISABLE_INTRINSIC SQLITE_DISABLE_LFS SQLITE_DISABLE_PAGECACHE_OVERFLOW_STATS SQLITE_DISABLE_SKIPAHEAD_DISTINCT SQLITE_ENABLE_8_3_NAMES SQLITE_ENABLE_API_ARMOR SQLITE_ENABLE_ATOMIC_WRITE SQLITE_ENABLE_BATCH_ATOMIC_WRITE SQLITE_ENABLE_BYTECODE_VTAB SQLITE_ENABLE_COLUMN_METADATA SQLITE_ENABLE_COLUMN_USED_MASK SQLITE_ENABLE_COSTMULT SQLITE_ENABLE_CURSOR_HINTS SQLITE_ENABLE_DBPAGE_VTAB SQLITE_ENABLE_DBSTAT_VTAB SQLITE_ENABLE_EXPENSIVE_ASSERT SQLITE_ENABLE_EXPLAIN_COMMENTS SQLITE_ENABLE_FTS3 SQLITE_ENABLE_FTS3_PARENTHESIS SQLITE_ENABLE_FTS3_TOKENIZER SQLITE_ENABLE_FTS4 SQLITE_ENABLE_FTS5 SQLITE_ENABLE_GEOPOLY SQLITE_ENABLE_HIDDEN_COLUMNS SQLITE_ENABLE_ICU SQLITE_ENABLE_IOTRACE SQLITE_ENABLE_JSON1 SQLITE_ENABLE_LOAD_EXTENSION SQLITE_ENABLE_LOCKING_STYLE SQLITE_ENABLE_MATH_FUNCTIONS SQLITE_ENABLE_MEMORY_MANAGEMENT SQLITE_ENABLE_MEMSYS3 SQLITE_ENABLE_MEMSYS5 SQLITE_ENABLE_MULTIPLEX SQLITE_ENABLE_NORMALIZE SQLITE_ENABLE_NULL_TRIM SQLITE_ENABLE_OFFSET_SQL_FUNC SQLITE_ENABLE_OVERSIZE_CELL_CHECK SQLITE_ENABLE_PREUPDATE_HOOK SQLITE_ENABLE_QPSG SQLITE_ENABLE_RBU SQLITE_ENABLE_RTREE SQLITE_ENABLE_SELECTTRACE SQLITE_ENABLE_SESSION SQLITE_ENABLE_SNAPSHOT SQLITE_ENABLE_SORTER_REFERENCES SQLITE_ENABLE_SQLLOG SQLITE_ENABLE_STAT4 SQLITE_ENABLE_STMT_SCANSTATUS SQLITE_ENABLE_STMTVTAB SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION SQLITE_ENABLE_UNLOCK_NOTIFY SQLITE_ENABLE_UPDATE_DELETE_LIMIT SQLITE_ENABLE_URI_00_ERROR SQLITE_ENABLE_VFSTRACE SQLITE_ENABLE_WHERETRACE SQLITE_ENABLE_ZIPVFS SQLITE_EXPLAIN_ESTIMATED_ROWS SQLITE_EXTRA_IFNULLROW SQLITE_FTS5_ENABLE_TEST_MI SQLITE_FTS5_NO_WITHOUT_ROWID SQLITE_IGNORE_AFP_LOCK_ERRORS SQLITE_IGNORE_FLOCK_LOCK_ERRORS SQLITE_INLINE_MEMCPY SQLITE_INT64_TYPE SQLITE_LIKE_DOESNT_MATCH_BLOBS SQLITE_LOCK_TRACE SQLITE_LOG_CACHE_SPILL SQLITE_MEMDEBUG SQLITE_MIXED_ENDIAN_64BIT_FLOAT SQLITE_MMAP_READWRITE SQLITE_MUTEX_NOOP SQLITE_MUTEX_OMIT SQLITE_MUTEX_PTHREADS SQLITE_MUTEX_W32 SQLITE_NEED_ERR_NAME SQLITE_NO_SYNC SQLITE_OMIT_ALTERTABLE SQLITE_OMIT_ANALYZE SQLITE_OMIT_ATTACH SQLITE_OMIT_AUTHORIZATION SQLITE_OMIT_AUTOINCREMENT SQLITE_OMIT_AUTOINIT SQLITE_OMIT_AUTOMATIC_INDEX SQLITE_OMIT_AUTORESET SQLITE_OMIT_AUTOVACUUM SQLITE_OMIT_BETWEEN_OPTIMIZATION SQLITE_OMIT_BLOB_LITERAL SQLITE_OMIT_CAST SQLITE_OMIT_CHECK SQLITE_OMIT_COMPLETE SQLITE_OMIT_COMPOUND_SELECT SQLITE_OMIT_CONFLICT_CLAUSE SQLITE_OMIT_CTE SQLITE_OMIT_DECLTYPE SQLITE_OMIT_DEPRECATED SQLITE_OMIT_DESERIALIZE SQLITE_OMIT_DISKIO SQLITE_OMIT_EXPLAIN SQLITE_OMIT_FLAG_PRAGMAS SQLITE_OMIT_FLOATING_POINT SQLITE_OMIT_FOREIGN_KEY SQLITE_OMIT_GET_TABLE SQLITE_OMIT_HEX_INTEGER SQLITE_OMIT_INCRBLOB SQLITE_OMIT_INTEGRITY_CHECK SQLITE_OMIT_INTROSPECTION_PRAGMAS SQLITE_OMIT_LIKE_OPTIMIZATION SQLITE_OMIT_LOAD_EXTENSION SQLITE_OMIT_LOCALTIME SQLITE_OMIT_LOOKASIDE SQLITE_OMIT_MEMORYDB SQLITE_OMIT_OR_OPTIMIZATION SQLITE_OMIT_PAGER_PRAGMAS |
︙ | ︙ | |||
152 153 154 155 156 157 158 | SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS SQLITE_OMIT_SHARED_CACHE SQLITE_OMIT_SHUTDOWN_DIRECTORIES SQLITE_OMIT_SUBQUERY SQLITE_OMIT_TCL_VARIABLE SQLITE_OMIT_TEMPDB SQLITE_OMIT_TEST_CONTROL | < < < | > > > > > > > > > < > | 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 | SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS SQLITE_OMIT_SHARED_CACHE SQLITE_OMIT_SHUTDOWN_DIRECTORIES SQLITE_OMIT_SUBQUERY SQLITE_OMIT_TCL_VARIABLE SQLITE_OMIT_TEMPDB SQLITE_OMIT_TEST_CONTROL SQLITE_OMIT_TRIGGER SQLITE_OMIT_TRUNCATE_OPTIMIZATION SQLITE_OMIT_UTF16 SQLITE_OMIT_VACUUM SQLITE_OMIT_VIEW SQLITE_OMIT_VIRTUALTABLE SQLITE_OMIT_WAL SQLITE_OMIT_WSD SQLITE_OMIT_XFER_OPT SQLITE_PCACHE_SEPARATE_HEADER SQLITE_PERFORMANCE_TRACE SQLITE_PREFER_PROXY_LOCKING SQLITE_PROXY_DEBUG SQLITE_REVERSE_UNORDERED_SELECTS SQLITE_RTREE_INT_ONLY SQLITE_SECURE_DELETE SQLITE_SMALL_STACK SQLITE_SOUNDEX SQLITE_SUBSTR_COMPATIBILITY SQLITE_TCL SQLITE_TEST SQLITE_UNLINK_AFTER_CLOSE SQLITE_UNTESTABLE SQLITE_USE_ALLOCA SQLITE_USE_FCNTL_TRACE SQLITE_USER_AUTHENTICATION SQLITE_USE_URI SQLITE_VDBE_COVERAGE SQLITE_WIN32_MALLOC SQLITE_ZERO_MALLOC } # All compile time options for which the assigned value is other than boolean # and is a comma-separated scalar pair. # set value2_options { SQLITE_DEFAULT_LOOKASIDE } # All compile time options for which the assigned value is other than boolean # and is a single scalar. # set value_options { SQLITE_ATOMIC_INTRINSICS SQLITE_BITMASK_TYPE SQLITE_DEFAULT_CACHE_SIZE SQLITE_DEFAULT_FILE_FORMAT SQLITE_DEFAULT_FILE_PERMISSIONS SQLITE_DEFAULT_JOURNAL_SIZE_LIMIT SQLITE_DEFAULT_LOCKING_MODE SQLITE_DEFAULT_MMAP_SIZE SQLITE_DEFAULT_PAGE_SIZE SQLITE_DEFAULT_PCACHE_INITSZ SQLITE_DEFAULT_PROXYDIR_PERMISSIONS SQLITE_DEFAULT_ROWEST SQLITE_DEFAULT_SECTOR_SIZE SQLITE_DEFAULT_SYNCHRONOUS SQLITE_DEFAULT_WAL_AUTOCHECKPOINT SQLITE_DEFAULT_WAL_SYNCHRONOUS SQLITE_DEFAULT_WORKER_THREADS SQLITE_ENABLE_8_3_NAMES SQLITE_ENABLE_CEROD SQLITE_ENABLE_LOCKING_STYLE SQLITE_EXTRA_INIT SQLITE_EXTRA_SHUTDOWN SQLITE_FTS3_MAX_EXPR_DEPTH SQLITE_INTEGRITY_CHECK_ERROR_MAX SQLITE_MALLOC_SOFT_LIMIT SQLITE_MAX_ATTACHED |
︙ | ︙ | |||
241 242 243 244 245 246 247 | SQLITE_STAT4_SAMPLES SQLITE_STMTJRNL_SPILL SQLITE_TEMP_STORE } # Options that require custom code. # | < < < < < < < > > > > > > > > > > > > > | > > > > > > > > > > > > > | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | > > | 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 | SQLITE_STAT4_SAMPLES SQLITE_STMTJRNL_SPILL SQLITE_TEMP_STORE } # Options that require custom code. # set options(COMPILER) { #if defined(__clang__) && defined(__clang_major__) "COMPILER=clang-" CTIMEOPT_VAL(__clang_major__) "." CTIMEOPT_VAL(__clang_minor__) "." CTIMEOPT_VAL(__clang_patchlevel__), #elif defined(_MSC_VER) "COMPILER=msvc-" CTIMEOPT_VAL(_MSC_VER), #elif defined(__GNUC__) && defined(__VERSION__) "COMPILER=gcc-" __VERSION__, #endif } set options(HAVE_ISNAN) { #if HAVE_ISNAN || SQLITE_HAVE_ISNAN "HAVE_ISNAN", #endif } set options(OMIT_DATETIME_FUNCS) { #if defined(SQLITE_OMIT_DATETIME_FUNCS) || defined(SQLITE_OMIT_FLOATING_POINT) "OMIT_DATETIME_FUNCS", #endif } set options(SYSTEM_MALLOC) "\ #if (!defined(SQLITE_WIN32_MALLOC) \\ && !defined(SQLITE_ZERO_MALLOC) \\ && !defined(SQLITE_MEMDEBUG) \\ ) || defined(SQLITE_SYSTEM_MALLOC) \"SYSTEM_MALLOC\", #endif " set options(THREADSAFE) { #if defined(SQLITE_THREADSAFE) "THREADSAFE=" CTIMEOPT_VAL(SQLITE_THREADSAFE), #elif defined(THREADSAFE) "THREADSAFE=" CTIMEOPT_VAL(THREADSAFE), #else "THREADSAFE=1", #endif } proc trim_name {in} { set ret $in if {[string range $in 0 6]=="SQLITE_"} { set ret [string range $in 7 end] } return $ret } foreach name_defval $boolean_defnnz_options { set b [lindex $name_defval 0] set defval [lindex $name_defval 1] set name [trim_name $b] set options($name) [subst { #ifdef $b # if $b != $defval "$name=" CTIMEOPT_VAL($b), # endif #endif }] } foreach b $boolean_defnil_options { set name [trim_name $b] set options($name) [subst { #ifdef $b "$name", #endif }] } foreach v $value_options { set name [trim_name $v] set options($name) [subst { #ifdef $v "$name=" CTIMEOPT_VAL($v), #endif }] } foreach v $value2_options { set name [trim_name $v] set options($name) [subst { #ifdef $v "$name=" CTIMEOPT_VAL2($v), #endif }] } # Split a string on a regex, return all parts in order. # Any elements with an even index may be empty. # Elements with odd indices will match the regex. proc split_on_re {re str {nrepps 1}} { set chunks {} set cix 0 set resm [regexp -all -inline -indices $re $str] if {[llength $resm]==0} { return $str } set rix 0 while {$rix < [llength $resm]} { set mre [lindex $resm $rix] incr rix $nrepps set mbx [lindex $mre 0] set mex [lindex $mre 1] lappend chunks [string range $str $cix [expr $mbx - 1]] lappend chunks [string range $str $mbx $mex] set cix [expr $mex + 1] } lappend chunks [string range $str $cix end] return $chunks } set ctime_c "src/ctime.c" if {[catch {set cfd [open $ctime_c r]}]!=0} { puts stderr "File '$ctime_c' unreadable. Run this script from checkout root." exit 1; } set ctfc [read $cfd] close $cfd set re {/\*\s+\*+\s*((BEGIN)|(END)) CODE GENERATED BY (\S+)\s+\*/\s+} set renpp 5 set ctfcChunks [split_on_re $re $ctfc $renpp] if {[llength $ctfcChunks] != 5} { puts stderr "File '$ctime_c' has too few generated code markers." exit 1; } if {[catch {set cfd [open $ctime_c w]}]!=0} { puts stderr "File '$ctime_c' unwritable." exit 1; } puts -nonewline $cfd [lindex $ctfcChunks 0] puts -nonewline $cfd [lindex $ctfcChunks 1] foreach o [lsort [array names options]] { puts $cfd [string trim $options($o)] } puts -nonewline $cfd [lindex $ctfcChunks 3] puts -nonewline $cfd [lindex $ctfcChunks 4] close $cfd |
Changes to tool/mkkeywordhash.c.
︙ | ︙ | |||
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | ** table composed of instances of the following structure. */ typedef struct Keyword Keyword; struct Keyword { char *zName; /* The keyword name */ char *zTokenType; /* Token value for this keyword */ int mask; /* Code this keyword if non-zero */ int id; /* Unique ID for this record */ int hash; /* Hash on the keyword */ int offset; /* Offset to start of name string */ int len; /* Length of this keyword, not counting final \000 */ int prefix; /* Number of characters in prefix */ int longestSuffix; /* Longest suffix that is a prefix on another word */ int iNext; /* Index in aKeywordTable[] of next with same hash */ int substrId; /* Id to another keyword this keyword is embedded in */ int substrOffset; /* Offset into substrId for start of this keyword */ char zOrigName[20]; /* Original keyword name before processing */ }; /* ** Define masks used to determine which keywords are allowed */ | > | | 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 | ** table composed of instances of the following structure. */ typedef struct Keyword Keyword; struct Keyword { char *zName; /* The keyword name */ char *zTokenType; /* Token value for this keyword */ int mask; /* Code this keyword if non-zero */ int priority; /* Put higher priorities earlier in the hash chain */ int id; /* Unique ID for this record */ int hash; /* Hash on the keyword */ int offset; /* Offset to start of name string */ int len; /* Length of this keyword, not counting final \000 */ int prefix; /* Number of characters in prefix */ int longestSuffix; /* Longest suffix that is a prefix on another word */ int iNext; /* Index in aKeywordTable[] of next with same hash */ int substrId; /* Id to another keyword this keyword is embedded in */ int substrOffset; /* Offset into substrId for start of this keyword */ char zOrigName[20]; /* Original keyword name before processing */ }; /* ** Define masks used to determine which keywords are allowed */ #if defined(SQLITE_OMIT_ALTERTABLE) || defined(SQLITE_OMIT_VIRTUALTABLE) # define ALTER 0 #else # define ALTER 0x00000001 #endif #define ALWAYS 0x00000002 #ifdef SQLITE_OMIT_ANALYZE # define ANALYZE 0 |
︙ | ︙ | |||
149 150 151 152 153 154 155 156 157 158 159 160 | # define UPSERT 0x00080000 #endif #ifdef SQLITE_OMIT_WINDOWFUNC # define WINDOWFUNC 0 #else # define WINDOWFUNC 0x00100000 #endif /* ** These are the keywords */ static Keyword aKeywordTable[] = { | > > > > > > > > > > > | | | | | | > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | > > | | | | > | | | | | > | | > | | | | | | | | | | | | | | | | | > | | | | > | | | | | | > | | | | | > | | | | | | | | | | | | | | | | | | > | | | | | | | | | | | > | | | | | | | | | | | | > > | | | < < | 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 | # define UPSERT 0x00080000 #endif #ifdef SQLITE_OMIT_WINDOWFUNC # define WINDOWFUNC 0 #else # define WINDOWFUNC 0x00100000 #endif #ifdef SQLITE_OMIT_GENERATED_COLUMNS # define GENCOL 0 #else # define GENCOL 0x00200000 #endif #ifdef SQLITE_OMIT_RETURNING # define RETURNING 0 #else # define RETURNING 0x00400000 #endif /* ** These are the keywords */ static Keyword aKeywordTable[] = { { "ABORT", "TK_ABORT", CONFLICT|TRIGGER, 0 }, { "ACTION", "TK_ACTION", FKEY, 0 }, { "ADD", "TK_ADD", ALTER, 1 }, { "AFTER", "TK_AFTER", TRIGGER, 0 }, { "ALL", "TK_ALL", ALWAYS, 0 }, { "ALTER", "TK_ALTER", ALTER, 0 }, { "ALWAYS", "TK_ALWAYS", GENCOL, 0 }, { "ANALYZE", "TK_ANALYZE", ANALYZE, 0 }, { "AND", "TK_AND", ALWAYS, 10 }, { "AS", "TK_AS", ALWAYS, 10 }, { "ASC", "TK_ASC", ALWAYS, 0 }, { "ATTACH", "TK_ATTACH", ATTACH, 1 }, { "AUTOINCREMENT", "TK_AUTOINCR", AUTOINCR, 0 }, { "BEFORE", "TK_BEFORE", TRIGGER, 0 }, { "BEGIN", "TK_BEGIN", ALWAYS, 1 }, { "BETWEEN", "TK_BETWEEN", ALWAYS, 5 }, { "BY", "TK_BY", ALWAYS, 10 }, { "CASCADE", "TK_CASCADE", FKEY, 1 }, { "CASE", "TK_CASE", ALWAYS, 5 }, { "CAST", "TK_CAST", CAST, 5 }, { "CHECK", "TK_CHECK", ALWAYS, 1 }, { "COLLATE", "TK_COLLATE", ALWAYS, 1 }, { "COLUMN", "TK_COLUMNKW", ALTER, 1 }, { "COMMIT", "TK_COMMIT", ALWAYS, 1 }, { "CONFLICT", "TK_CONFLICT", CONFLICT, 0 }, { "CONSTRAINT", "TK_CONSTRAINT", ALWAYS, 1 }, { "CREATE", "TK_CREATE", ALWAYS, 2 }, { "CROSS", "TK_JOIN_KW", ALWAYS, 3 }, { "CURRENT", "TK_CURRENT", WINDOWFUNC, 1 }, { "CURRENT_DATE", "TK_CTIME_KW", ALWAYS, 1 }, { "CURRENT_TIME", "TK_CTIME_KW", ALWAYS, 1 }, { "CURRENT_TIMESTAMP","TK_CTIME_KW", ALWAYS, 1 }, { "DATABASE", "TK_DATABASE", ATTACH, 0 }, { "DEFAULT", "TK_DEFAULT", ALWAYS, 1 }, { "DEFERRED", "TK_DEFERRED", ALWAYS, 1 }, { "DEFERRABLE", "TK_DEFERRABLE", FKEY, 1 }, { "DELETE", "TK_DELETE", ALWAYS, 10 }, { "DESC", "TK_DESC", ALWAYS, 3 }, { "DETACH", "TK_DETACH", ATTACH, 0 }, { "DISTINCT", "TK_DISTINCT", ALWAYS, 5 }, { "DO", "TK_DO", UPSERT, 2 }, { "DROP", "TK_DROP", ALWAYS, 1 }, { "END", "TK_END", ALWAYS, 1 }, { "EACH", "TK_EACH", TRIGGER, 1 }, { "ELSE", "TK_ELSE", ALWAYS, 2 }, { "ESCAPE", "TK_ESCAPE", ALWAYS, 4 }, { "EXCEPT", "TK_EXCEPT", COMPOUND, 4 }, { "EXCLUSIVE", "TK_EXCLUSIVE", ALWAYS, 1 }, { "EXCLUDE", "TK_EXCLUDE", WINDOWFUNC, 1 }, { "EXISTS", "TK_EXISTS", ALWAYS, 4 }, { "EXPLAIN", "TK_EXPLAIN", EXPLAIN, 1 }, { "FAIL", "TK_FAIL", CONFLICT|TRIGGER, 1 }, { "FILTER", "TK_FILTER", WINDOWFUNC, 4 }, { "FIRST", "TK_FIRST", ALWAYS, 4 }, { "FOLLOWING", "TK_FOLLOWING", WINDOWFUNC, 4 }, { "FOR", "TK_FOR", TRIGGER, 2 }, { "FOREIGN", "TK_FOREIGN", FKEY, 1 }, { "FROM", "TK_FROM", ALWAYS, 10 }, { "FULL", "TK_JOIN_KW", ALWAYS, 3 }, { "GENERATED", "TK_GENERATED", ALWAYS, 1 }, { "GLOB", "TK_LIKE_KW", ALWAYS, 3 }, { "GROUP", "TK_GROUP", ALWAYS, 5 }, { "GROUPS", "TK_GROUPS", WINDOWFUNC, 2 }, { "HAVING", "TK_HAVING", ALWAYS, 5 }, { "IF", "TK_IF", ALWAYS, 2 }, { "IGNORE", "TK_IGNORE", CONFLICT|TRIGGER, 1 }, { "IMMEDIATE", "TK_IMMEDIATE", ALWAYS, 1 }, { "IN", "TK_IN", ALWAYS, 10 }, { "INDEX", "TK_INDEX", ALWAYS, 1 }, { "INDEXED", "TK_INDEXED", ALWAYS, 0 }, { "INITIALLY", "TK_INITIALLY", FKEY, 1 }, { "INNER", "TK_JOIN_KW", ALWAYS, 1 }, { "INSERT", "TK_INSERT", ALWAYS, 10 }, { "INSTEAD", "TK_INSTEAD", TRIGGER, 1 }, { "INTERSECT", "TK_INTERSECT", COMPOUND, 5 }, { "INTO", "TK_INTO", ALWAYS, 10 }, { "IS", "TK_IS", ALWAYS, 5 }, { "ISNULL", "TK_ISNULL", ALWAYS, 5 }, { "JOIN", "TK_JOIN", ALWAYS, 5 }, { "KEY", "TK_KEY", ALWAYS, 1 }, { "LAST", "TK_LAST", ALWAYS, 4 }, { "LEFT", "TK_JOIN_KW", ALWAYS, 5 }, { "LIKE", "TK_LIKE_KW", ALWAYS, 5 }, { "LIMIT", "TK_LIMIT", ALWAYS, 3 }, { "MATCH", "TK_MATCH", ALWAYS, 2 }, { "MATERIALIZED", "TK_MATERIALIZED", CTE, 12 }, { "NATURAL", "TK_JOIN_KW", ALWAYS, 3 }, { "NO", "TK_NO", FKEY|WINDOWFUNC, 2 }, { "NOT", "TK_NOT", ALWAYS, 10 }, { "NOTHING", "TK_NOTHING", UPSERT, 1 }, { "NOTNULL", "TK_NOTNULL", ALWAYS, 3 }, { "NULL", "TK_NULL", ALWAYS, 10 }, { "NULLS", "TK_NULLS", ALWAYS, 3 }, { "OF", "TK_OF", ALWAYS, 3 }, { "OFFSET", "TK_OFFSET", ALWAYS, 1 }, { "ON", "TK_ON", ALWAYS, 1 }, { "OR", "TK_OR", ALWAYS, 9 }, { "ORDER", "TK_ORDER", ALWAYS, 10 }, { "OTHERS", "TK_OTHERS", WINDOWFUNC, 3 }, { "OUTER", "TK_JOIN_KW", ALWAYS, 5 }, { "OVER", "TK_OVER", WINDOWFUNC, 3 }, { "PARTITION", "TK_PARTITION", WINDOWFUNC, 3 }, { "PLAN", "TK_PLAN", EXPLAIN, 0 }, { "PRAGMA", "TK_PRAGMA", PRAGMA, 0 }, { "PRECEDING", "TK_PRECEDING", WINDOWFUNC, 3 }, { "PRIMARY", "TK_PRIMARY", ALWAYS, 1 }, { "QUERY", "TK_QUERY", EXPLAIN, 0 }, { "RAISE", "TK_RAISE", TRIGGER, 1 }, { "RANGE", "TK_RANGE", WINDOWFUNC, 3 }, { "RECURSIVE", "TK_RECURSIVE", CTE, 3 }, { "REFERENCES", "TK_REFERENCES", FKEY, 1 }, { "REGEXP", "TK_LIKE_KW", ALWAYS, 3 }, { "REINDEX", "TK_REINDEX", REINDEX, 1 }, { "RELEASE", "TK_RELEASE", ALWAYS, 1 }, { "RENAME", "TK_RENAME", ALTER, 1 }, { "REPLACE", "TK_REPLACE", CONFLICT, 10 }, { "RESTRICT", "TK_RESTRICT", FKEY, 1 }, { "RETURNING", "TK_RETURNING", RETURNING, 10 }, { "RIGHT", "TK_JOIN_KW", ALWAYS, 0 }, { "ROLLBACK", "TK_ROLLBACK", ALWAYS, 1 }, { "ROW", "TK_ROW", TRIGGER, 1 }, { "ROWS", "TK_ROWS", ALWAYS, 1 }, { "SAVEPOINT", "TK_SAVEPOINT", ALWAYS, 1 }, { "SELECT", "TK_SELECT", ALWAYS, 10 }, { "SET", "TK_SET", ALWAYS, 10 }, { "TABLE", "TK_TABLE", ALWAYS, 1 }, { "TEMP", "TK_TEMP", ALWAYS, 1 }, { "TEMPORARY", "TK_TEMP", ALWAYS, 1 }, { "THEN", "TK_THEN", ALWAYS, 3 }, { "TIES", "TK_TIES", WINDOWFUNC, 3 }, { "TO", "TK_TO", ALWAYS, 3 }, { "TRANSACTION", "TK_TRANSACTION", ALWAYS, 1 }, { "TRIGGER", "TK_TRIGGER", TRIGGER, 1 }, { "UNBOUNDED", "TK_UNBOUNDED", WINDOWFUNC, 3 }, { "UNION", "TK_UNION", COMPOUND, 3 }, { "UNIQUE", "TK_UNIQUE", ALWAYS, 1 }, { "UPDATE", "TK_UPDATE", ALWAYS, 10 }, { "USING", "TK_USING", ALWAYS, 8 }, { "VACUUM", "TK_VACUUM", VACUUM, 1 }, { "VALUES", "TK_VALUES", ALWAYS, 10 }, { "VIEW", "TK_VIEW", VIEW, 1 }, { "VIRTUAL", "TK_VIRTUAL", VTAB, 1 }, { "WHEN", "TK_WHEN", ALWAYS, 1 }, { "WHERE", "TK_WHERE", ALWAYS, 10 }, { "WINDOW", "TK_WINDOW", WINDOWFUNC, 3 }, { "WITH", "TK_WITH", CTE, 4 }, { "WITHOUT", "TK_WITHOUT", ALWAYS, 1 }, }; /* Number of keywords */ static int nKeyword = (sizeof(aKeywordTable)/sizeof(aKeywordTable[0])); /* Map all alphabetic characters into lower-case for hashing. This is ** only valid for alphabetics. In particular it does not work for '_' |
︙ | ︙ | |||
343 344 345 346 347 348 349 350 351 352 353 354 355 356 | int i; for(i=0; i<nKeyword; i++){ if( aKeywordTable[i].id==id ) break; } return &aKeywordTable[i]; } /* ** This routine does the work. The generated code is printed on standard ** output. */ int main(int argc, char **argv){ int i, j, k, h; int bestSize, bestCount; | > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | int i; for(i=0; i<nKeyword; i++){ if( aKeywordTable[i].id==id ) break; } return &aKeywordTable[i]; } /* ** If aKeyword[*pFrom-1].iNext has a higher priority that aKeyword[*pFrom-1] ** itself, then swap them. */ static void reorder(int *pFrom){ int i = *pFrom - 1; int j; if( i<0 ) return; j = aKeywordTable[i].iNext; if( j==0 ) return; j--; if( aKeywordTable[i].priority >= aKeywordTable[j].priority ) return; aKeywordTable[i].iNext = aKeywordTable[j].iNext; aKeywordTable[j].iNext = i+1; *pFrom = j+1; reorder(&aKeywordTable[i].iNext); } /* Parameter to the hash function */ #define HASH_OP ^ #define HASH_CC '^' #define HASH_C0 4 #define HASH_C1 3 #define HASH_C2 1 /* ** This routine does the work. The generated code is printed on standard ** output. */ int main(int argc, char **argv){ int i, j, k, h; int bestSize, bestCount; |
︙ | ︙ | |||
373 374 375 376 377 378 379 | /* Fill in the lengths of strings and hashes for all entries. */ for(i=0; i<nKeyword; i++){ Keyword *p = &aKeywordTable[i]; p->len = (int)strlen(p->zName); assert( p->len<sizeof(p->zOrigName) ); memcpy(p->zOrigName, p->zName, p->len+1); totalLen += p->len; | | | > | 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 | /* Fill in the lengths of strings and hashes for all entries. */ for(i=0; i<nKeyword; i++){ Keyword *p = &aKeywordTable[i]; p->len = (int)strlen(p->zName); assert( p->len<sizeof(p->zOrigName) ); memcpy(p->zOrigName, p->zName, p->len+1); totalLen += p->len; p->hash = (charMap(p->zName[0])*HASH_C0) HASH_OP (charMap(p->zName[p->len-1])*HASH_C1) HASH_OP (p->len*HASH_C2); p->id = i+1; } /* Sort the table from shortest to longest keyword */ qsort(aKeywordTable, nKeyword, sizeof(aKeywordTable[0]), keywordCompare1); /* Look for short keywords embedded in longer keywords */ |
︙ | ︙ | |||
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 | qsort(aKeywordTable, nKeyword, sizeof(aKeywordTable[0]), keywordCompare3); /* Figure out how big to make the hash table in order to minimize the ** number of collisions */ bestSize = nKeyword; bestCount = nKeyword*nKeyword; for(i=nKeyword/2; i<=2*nKeyword; i++){ for(j=0; j<i; j++) aKWHash[j] = 0; for(j=0; j<nKeyword; j++){ h = aKeywordTable[j].hash % i; aKWHash[h] *= 2; aKWHash[h]++; } for(j=count=0; j<i; j++) count += aKWHash[j]; if( count<bestCount ){ bestCount = count; bestSize = i; } } /* Compute the hash */ for(i=0; i<bestSize; i++) aKWHash[i] = 0; for(i=0; i<nKeyword; i++){ h = aKeywordTable[i].hash % bestSize; aKeywordTable[i].iNext = aKWHash[h]; aKWHash[h] = i+1; } /* Begin generating code */ printf("%s", zHdr); printf("/* Hash score: %d */\n", bestCount); printf("/* zKWText[] encodes %d bytes of keyword text in %d bytes */\n", totalLen + nKeyword, nChar+1 ); | > > | 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 | qsort(aKeywordTable, nKeyword, sizeof(aKeywordTable[0]), keywordCompare3); /* Figure out how big to make the hash table in order to minimize the ** number of collisions */ bestSize = nKeyword; bestCount = nKeyword*nKeyword; for(i=nKeyword/2; i<=2*nKeyword; i++){ if( i<=0 ) continue; for(j=0; j<i; j++) aKWHash[j] = 0; for(j=0; j<nKeyword; j++){ h = aKeywordTable[j].hash % i; aKWHash[h] *= 2; aKWHash[h]++; } for(j=count=0; j<i; j++) count += aKWHash[j]; if( count<bestCount ){ bestCount = count; bestSize = i; } } /* Compute the hash */ for(i=0; i<bestSize; i++) aKWHash[i] = 0; for(i=0; i<nKeyword; i++){ h = aKeywordTable[i].hash % bestSize; aKeywordTable[i].iNext = aKWHash[h]; aKWHash[h] = i+1; reorder(&aKWHash[h]); } /* Begin generating code */ printf("%s", zHdr); printf("/* Hash score: %d */\n", bestCount); printf("/* zKWText[] encodes %d bytes of keyword text in %d bytes */\n", totalLen + nKeyword, nChar+1 ); |
︙ | ︙ | |||
591 592 593 594 595 596 597 598 599 600 601 602 603 604 | j++; if( j>=5 ){ printf("\n"); j = 0; } } printf("%s};\n", j==0 ? "" : "\n"); printf("/* Check to see if z[0..n-1] is a keyword. If it is, write the\n"); printf("** parser symbol code for that keyword into *pType. Always\n"); printf("** return the integer n (the length of the token). */\n"); printf("static int keywordCode(const char *z, int n, int *pType){\n"); printf(" int i, j;\n"); printf(" const char *zKW;\n"); printf(" if( n>=2 ){\n"); | > > > > > > > > > > > | > | < > > > > > > | 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 | j++; if( j>=5 ){ printf("\n"); j = 0; } } printf("%s};\n", j==0 ? "" : "\n"); printf("/* Hash table decoded:\n"); for(i=0; i<bestSize; i++){ j = aKWHash[i]; printf("** %3d:", i); while( j ){ printf(" %s", aKeywordTable[j-1].zOrigName); j = aKeywordTable[j-1].iNext; } printf("\n"); } printf("*/\n"); printf("/* Check to see if z[0..n-1] is a keyword. If it is, write the\n"); printf("** parser symbol code for that keyword into *pType. Always\n"); printf("** return the integer n (the length of the token). */\n"); printf("static int keywordCode(const char *z, int n, int *pType){\n"); printf(" int i, j;\n"); printf(" const char *zKW;\n"); printf(" if( n>=2 ){\n"); printf(" i = ((charMap(z[0])*%d) %c", HASH_C0, HASH_CC); printf(" (charMap(z[n-1])*%d) %c", HASH_C1, HASH_CC); printf(" n*%d) %% %d;\n", HASH_C2, bestSize); printf(" for(i=((int)aKWHash[i])-1; i>=0; i=((int)aKWNext[i])-1){\n"); printf(" if( aKWLen[i]!=n ) continue;\n"); printf(" zKW = &zKWText[aKWOffset[i]];\n"); printf("#ifdef SQLITE_ASCII\n"); printf(" if( (z[0]&~0x20)!=zKW[0] ) continue;\n"); printf(" if( (z[1]&~0x20)!=zKW[1] ) continue;\n"); printf(" j = 2;\n"); printf(" while( j<n && (z[j]&~0x20)==zKW[j] ){ j++; }\n"); printf("#endif\n"); printf("#ifdef SQLITE_EBCDIC\n"); printf(" if( toupper(z[0])!=zKW[0] ) continue;\n"); printf(" if( toupper(z[1])!=zKW[1] ) continue;\n"); printf(" j = 2;\n"); printf(" while( j<n && toupper(z[j])==zKW[j] ){ j++; }\n"); printf("#endif\n"); printf(" if( j<n ) continue;\n"); for(i=0; i<nKeyword; i++){ printf(" testcase( i==%d ); /* %s */\n", i, aKeywordTable[i].zOrigName); } |
︙ | ︙ |
Changes to tool/mkmsvcmin.tcl.
︙ | ︙ | |||
79 80 81 82 83 84 85 | set blocks(2) [string trimleft [string map [list \\\\ \\] { Replace.exe: $(CSC) /target:exe $(TOP)\Replace.cs sqlite3.def: Replace.exe $(LIBOBJ) echo EXPORTS > sqlite3.def dumpbin /all $(LIBOBJ) \\ | | | 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 | set blocks(2) [string trimleft [string map [list \\\\ \\] { Replace.exe: $(CSC) /target:exe $(TOP)\Replace.cs sqlite3.def: Replace.exe $(LIBOBJ) echo EXPORTS > sqlite3.def dumpbin /all $(LIBOBJ) \\ | .\Replace.exe "^\s+/EXPORT:_?(sqlite3(?:session|changeset|changegroup|rebaser|rbu)?_[^@,]*)(?:@\d+|,DATA)?$$" $$1 true \\ | sort >> sqlite3.def }]] set data "#### DO NOT EDIT ####\n" append data "# This makefile is automatically " append data "generated from the [file tail $fromFileName] at\n" append data "# the root of the canonical SQLite source tree (not the\n" |
︙ | ︙ |
Changes to tool/mkopcodec.tcl.
︙ | ︙ | |||
18 19 20 21 22 23 24 | puts "#else" puts "# define OpHelp(X)" puts "#endif" puts "const char *sqlite3OpcodeName(int i)\173" puts " static const char *const azName\[\] = \173" set mx 0 | | > | 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | puts "#else" puts "# define OpHelp(X)" puts "#endif" puts "const char *sqlite3OpcodeName(int i)\173" puts " static const char *const azName\[\] = \173" set mx 0 set in [open [lindex $argv 0]] fconfigure $in -translation binary while {![eof $in]} { set line [gets $in] if {[regexp {^#define OP_} $line]} { set name [lindex $line 1] regsub {^OP_} $name {} name set i [lindex $line 2] set label($i) $name |
︙ | ︙ |
Changes to tool/mkopcodeh.tcl.
︙ | ︙ | |||
141 142 143 144 145 146 147 | set out2($name) 0 set out3($name) 0 set op($name) -1 set order($nOp) $name incr nOp } | | > > < < | > | 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 | set out2($name) 0 set out3($name) 0 set op($name) -1 set order($nOp) $name incr nOp } # The following are the opcodes that receive special processing in the # resolveP2Values() routine. Update this list whenever new cases are # added to the pOp->opcode switch within resolveP2Values(). # set rp2v_ops { OP_Transaction OP_AutoCommit OP_Savepoint OP_Checkpoint OP_Vacuum OP_JournalMode OP_VUpdate OP_VFilter OP_Next OP_SorterNext OP_Prev } # Assign the smallest values to opcodes that are processed by resolveP2Values() # to make code generation for the switch() statement smaller and faster. # set cnt -1 for {set i 0} {$i<$nOp} {incr i} { set name $order($i) if {[lsearch $rp2v_ops $name]>=0} { incr cnt while {[info exists used($cnt)]} {incr cnt} set op($name) $cnt set used($cnt) 1 set def($cnt) $name } } set mxCase1 $cnt # Assign the next group of values to JUMP opcodes # for {set i 0} {$i<$nOp} {incr i} { set name $order($i) if {$op($name)>=0} continue if {!$jump($name)} continue |
︙ | ︙ | |||
203 204 205 206 207 208 209 210 | # Generate the numeric values for all remaining opcodes, while # preserving any groupings of opcodes (i.e. those that must be # together). # for {set g 0} {$g<$nGroup} {incr g} { set gLen [llength $groups($g)] set ok 0; set start -1 while {!$ok} { | > | | 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 | # Generate the numeric values for all remaining opcodes, while # preserving any groupings of opcodes (i.e. those that must be # together). # for {set g 0} {$g<$nGroup} {incr g} { set gLen [llength $groups($g)] set ok 0; set start -1 set seek $cnt while {!$ok} { incr seek while {[info exists used($seek)]} {incr seek} set ok 1; set start $seek for {set j 0} {$j<$gLen} {incr j} { incr seek if {[info exists used($seek)]} { set ok 0; break } |
︙ | ︙ | |||
307 308 309 310 311 312 313 | puts -nonewline [format " 0x%02x," $bv($i)] if {$i%8==7} { puts "\\" } } puts "\175" puts "" | | | 309 310 311 312 313 314 315 316 317 318 319 320 321 322 | puts -nonewline [format " 0x%02x," $bv($i)] if {$i%8==7} { puts "\\" } } puts "\175" puts "" puts "/* The resolve3P2Values() routine is able to run faster if it knows" puts "** the value of the largest JUMP opcode. The smaller the maximum" puts "** JUMP opcode the better, so the mkopcodeh.tcl script that" puts "** generated this include file strives to group all JUMP opcodes" puts "** together near the beginning of the list." puts "*/" puts "#define SQLITE_MX_JUMP_OPCODE $mxJump /* Maximum JUMP opcode */" |
Changes to tool/mkpragmatab.tcl.
︙ | ︙ | |||
37 38 39 40 41 42 43 | IF: !defined(SQLITE_OMIT_FLAG_PRAGMAS) NAME: empty_result_callbacks TYPE: FLAG ARG: SQLITE_NullCallback IF: !defined(SQLITE_OMIT_FLAG_PRAGMAS) | < < < < < | 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | IF: !defined(SQLITE_OMIT_FLAG_PRAGMAS) NAME: empty_result_callbacks TYPE: FLAG ARG: SQLITE_NullCallback IF: !defined(SQLITE_OMIT_FLAG_PRAGMAS) NAME: fullfsync TYPE: FLAG ARG: SQLITE_FullFSync IF: !defined(SQLITE_OMIT_FLAG_PRAGMAS) NAME: checkpoint_fullfsync TYPE: FLAG |
︙ | ︙ | |||
108 109 110 111 112 113 114 115 116 117 118 119 120 121 | NAME: vdbe_eqp TYPE: FLAG ARG: SQLITE_VdbeEQP IF: !defined(SQLITE_OMIT_FLAG_PRAGMAS) IF: defined(SQLITE_DEBUG) NAME: ignore_check_constraints TYPE: FLAG ARG: SQLITE_IgnoreChecks IF: !defined(SQLITE_OMIT_FLAG_PRAGMAS) IF: !defined(SQLITE_OMIT_CHECK) NAME: writable_schema | > > > > > > | 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 | NAME: vdbe_eqp TYPE: FLAG ARG: SQLITE_VdbeEQP IF: !defined(SQLITE_OMIT_FLAG_PRAGMAS) IF: defined(SQLITE_DEBUG) NAME: noop_update TYPE: FLAG ARG: SQLITE_NoopUpdate IF: !defined(SQLITE_OMIT_FLAG_PRAGMAS) IF: defined(SQLITE_ENABLE_NOOP_UPDATE) NAME: ignore_check_constraints TYPE: FLAG ARG: SQLITE_IgnoreChecks IF: !defined(SQLITE_OMIT_FLAG_PRAGMAS) IF: !defined(SQLITE_OMIT_CHECK) NAME: writable_schema |
︙ | ︙ | |||
129 130 131 132 133 134 135 136 137 138 139 140 141 142 | IF: !defined(SQLITE_OMIT_FLAG_PRAGMAS) NAME: recursive_triggers TYPE: FLAG ARG: SQLITE_RecTriggers IF: !defined(SQLITE_OMIT_FLAG_PRAGMAS) NAME: foreign_keys TYPE: FLAG ARG: SQLITE_ForeignKeys IF: !defined(SQLITE_OMIT_FLAG_PRAGMAS) IF: !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER) NAME: defer_foreign_keys | > > > > > | 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 | IF: !defined(SQLITE_OMIT_FLAG_PRAGMAS) NAME: recursive_triggers TYPE: FLAG ARG: SQLITE_RecTriggers IF: !defined(SQLITE_OMIT_FLAG_PRAGMAS) NAME: trusted_schema TYPE: FLAG ARG: SQLITE_TrustedSchema IF: !defined(SQLITE_OMIT_FLAG_PRAGMAS) NAME: foreign_keys TYPE: FLAG ARG: SQLITE_ForeignKeys IF: !defined(SQLITE_OMIT_FLAG_PRAGMAS) IF: !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER) NAME: defer_foreign_keys |
︙ | ︙ | |||
227 228 229 230 231 232 233 234 235 236 237 238 239 240 | NAME: table_xinfo TYPE: TABLE_INFO FLAG: NeedSchema Result1 SchemaOpt ARG: 1 COLS: cid name type notnull dflt_value pk hidden IF: !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) NAME: stats FLAG: NeedSchema Result0 SchemaReq COLS: tbl idx wdth hght flgs IF: !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) && defined(SQLITE_DEBUG) NAME: index_info TYPE: INDEX_INFO | > > > > > > | 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 | NAME: table_xinfo TYPE: TABLE_INFO FLAG: NeedSchema Result1 SchemaOpt ARG: 1 COLS: cid name type notnull dflt_value pk hidden IF: !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) NAME: table_list TYPE: TABLE_LIST FLAG: NeedSchema Result1 COLS: schema name type ncol wr strict IF: !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) NAME: stats FLAG: NeedSchema Result0 SchemaReq COLS: tbl idx wdth hght flgs IF: !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) && defined(SQLITE_DEBUG) NAME: index_info TYPE: INDEX_INFO |
︙ | ︙ | |||
258 259 260 261 262 263 264 | NAME: database_list FLAG: NeedSchema Result0 COLS: seq name file IF: !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) NAME: function_list FLAG: Result0 | | | | | | > > > | > | | | 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 | NAME: database_list FLAG: NeedSchema Result0 COLS: seq name file IF: !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) NAME: function_list FLAG: Result0 COLS: name builtin type enc narg flags IF: !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) IF: !defined(SQLITE_OMIT_INTROSPECTION_PRAGMAS) NAME: module_list FLAG: Result0 COLS: name IF: !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) IF: !defined(SQLITE_OMIT_VIRTUALTABLE) IF: !defined(SQLITE_OMIT_INTROSPECTION_PRAGMAS) NAME: pragma_list FLAG: Result0 COLS: name IF: !defined(SQLITE_OMIT_INTROSPECTION_PRAGMAS) NAME: collation_list FLAG: Result0 COLS: seq name IF: !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) NAME: foreign_key_list FLAG: NeedSchema Result1 SchemaOpt COLS: id seq table from to on_update on_delete match IF: !defined(SQLITE_OMIT_FOREIGN_KEY) NAME: foreign_key_check FLAG: NeedSchema Result0 Result1 SchemaOpt COLS: table rowid parent fkid IF: !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER) NAME: parser_trace TYPE: FLAG ARG: SQLITE_ParserTrace IF: !defined(SQLITE_OMIT_FLAG_PRAGMAS) IF: defined(SQLITE_DEBUG) NAME: case_sensitive_like FLAG: NoColumns IF: !defined(SQLITE_OMIT_CASE_SENSITIVE_LIKE_PRAGMA) NAME: integrity_check FLAG: NeedSchema Result0 Result1 SchemaOpt IF: !defined(SQLITE_OMIT_INTEGRITY_CHECK) NAME: quick_check TYPE: INTEGRITY_CHECK FLAG: NeedSchema Result0 Result1 SchemaOpt IF: !defined(SQLITE_OMIT_INTEGRITY_CHECK) NAME: encoding FLAG: Result0 NoColumns1 IF: !defined(SQLITE_OMIT_UTF16) NAME: schema_version |
︙ | ︙ | |||
362 363 364 365 366 367 368 | COLS: timeout NAME: lock_status FLAG: Result0 COLS: database status IF: defined(SQLITE_DEBUG) || defined(SQLITE_TEST) | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | > > > > > > | 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 | COLS: timeout NAME: lock_status FLAG: Result0 COLS: database status IF: defined(SQLITE_DEBUG) || defined(SQLITE_TEST) NAME: activate_extensions IF: defined(SQLITE_ENABLE_CEROD) NAME: soft_heap_limit FLAG: Result0 NAME: hard_heap_limit FLAG: Result0 NAME: threads FLAG: Result0 NAME: analysis_limit FLAG: Result0 NAME: optimize FLAG: Result1 NeedSchema NAME: legacy_alter_table TYPE: FLAG ARG: SQLITE_LegacyAlter |
︙ | ︙ | |||
485 486 487 488 489 490 491 | error "bad pragma_def line: $line" } } record_one set allnames [lsort [array names allbyname]] # Generate #defines for all pragma type names. Group the pragmas that are | | | 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 | error "bad pragma_def line: $line" } } record_one set allnames [lsort [array names allbyname]] # Generate #defines for all pragma type names. Group the pragmas that are # omit in default builds (ex: defined(SQLITE_DEBUG)) # at the end. # puts $fd "\n/* The various pragma types */" set pnum 0 foreach name $allnames { set type [lindex $allbyname($name) 0] if {[info exists seentype($type)]} continue |
︙ | ︙ |
Changes to tool/mkshellc.tcl.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | #!/usr/bin/tclsh # # Run this script to generate the "shell.c" source file from # constituent parts. # # No arguments are required. This script determines the location # of its input files relative to the location of the script itself. # This script should be tool/mkshellc.tcl. If the directory holding # the script is $DIR, then the component parts are located in $DIR/../src # and $DIR/../ext/misc. # set topdir [file dir [file dir [file normal $argv0]]] set out stdout puts $out {/* DO NOT EDIT! ** This file is automatically generated by the script in the canonical ** SQLite source tree at tool/mkshellc.tcl. That script combines source ** code from various constituent source files of SQLite into this single ** "shell.c" file used to implement the SQLite command-line shell. ** ** Most of the code found below comes from the "src/shell.c.in" file in ** the canonical SQLite source tree. That main file contains "INCLUDE" ** lines that specify other files in the canonical source tree that are ** inserted to getnerate this complete program source file. ** ** The code from multiple files is combined into this single "shell.c" ** source file to help make the command-line program easier to compile. ** ** To modify this program, get a copy of the canonical SQLite source tree, ** edit the src/shell.c.in" and/or some of the other files that are included ** by "src/shell.c.in", then rerun the tool/mkshellc.tcl script. */} | > | > > > > | > | > > > | 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 | #!/usr/bin/tclsh # # Run this script to generate the "shell.c" source file from # constituent parts. # # No arguments are required. This script determines the location # of its input files relative to the location of the script itself. # This script should be tool/mkshellc.tcl. If the directory holding # the script is $DIR, then the component parts are located in $DIR/../src # and $DIR/../ext/misc. # set topdir [file dir [file dir [file normal $argv0]]] set out stdout fconfigure stdout -translation binary puts $out {/* DO NOT EDIT! ** This file is automatically generated by the script in the canonical ** SQLite source tree at tool/mkshellc.tcl. That script combines source ** code from various constituent source files of SQLite into this single ** "shell.c" file used to implement the SQLite command-line shell. ** ** Most of the code found below comes from the "src/shell.c.in" file in ** the canonical SQLite source tree. That main file contains "INCLUDE" ** lines that specify other files in the canonical source tree that are ** inserted to getnerate this complete program source file. ** ** The code from multiple files is combined into this single "shell.c" ** source file to help make the command-line program easier to compile. ** ** To modify this program, get a copy of the canonical SQLite source tree, ** edit the src/shell.c.in" and/or some of the other files that are included ** by "src/shell.c.in", then rerun the tool/mkshellc.tcl script. */} set in [open $topdir/src/shell.c.in] fconfigure $in -translation binary proc omit_redundant_typedefs {line} { global typedef_seen if {[regexp {^typedef .*;} $line]} { if {[info exists typedef_seen($line)]} { return "/* $line */" } set typedef_seen($line) 1 } return $line } set iLine 0 while {1} { set lx [omit_redundant_typedefs [gets $in]] if {[eof $in]} break; incr iLine if {[regexp {^INCLUDE } $lx]} { set cfile [lindex $lx 1] puts $out "/************************* Begin $cfile ******************/" # puts $out "#line 1 \"$cfile\"" set in2 [open $topdir/src/$cfile] fconfigure $in2 -translation binary while {![eof $in2]} { set lx [omit_redundant_typedefs [gets $in2]] if {[regexp {^#include "sqlite} $lx]} { set lx "/* $lx */" } if {[regexp {^# *include "test_windirent.h"} $lx]} { set lx "/* $lx */" } set lx [string map [list __declspec(dllexport) {}] $lx] puts $out $lx } close $in2 puts $out "/************************* End $cfile ********************/" # puts $out "#line [expr $iLine+1] \"shell.c.in\"" continue } puts $out $lx } close $in close $out |
Changes to tool/mksourceid.c.
︙ | ︙ | |||
536 537 538 539 540 541 542 | /* * blk0() and blk() perform the initial expand. * I got the idea of expanding during the round function from SSLeay * * blk0le() for little-endian and blk0be() for big-endian. */ | < < < < < < < < < < < < < < < < < < | 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 | /* * blk0() and blk() perform the initial expand. * I got the idea of expanding during the round function from SSLeay * * blk0le() for little-endian and blk0be() for big-endian. */ #define SHA_ROT(x,l,r) ((x) << (l) | (x) >> (r)) #define rol(x,k) SHA_ROT(x,k,32-(k)) #define ror(x,k) SHA_ROT(x,32-(k),k) #define blk0le(i) (block[i] = (ror(block[i],8)&0xFF00FF00) \ |(rol(block[i],8)&0x00FF00FF)) #define blk0be(i) block[i] #define blk(i) (block[i&15] = rol(block[(i+13)&15]^block[(i+8)&15] \ ^block[(i+2)&15]^block[i&15],1)) |
︙ | ︙ |
Changes to tool/mksqlite3c.tcl.
︙ | ︙ | |||
13 14 15 16 17 18 19 | # For example, the "parse.c" and "parse.h" files to implement the # the parser are derived from "parse.y" using lemon. And the # "keywordhash.h" files is generated by a program named "mkkeywordhash". # # After the "tsrc" directory has been created and populated, run # this script: # | | > > > > > > > > > > > > > | | > | | > > > > > > > > > | | 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 | # For example, the "parse.c" and "parse.h" files to implement the # the parser are derived from "parse.y" using lemon. And the # "keywordhash.h" files is generated by a program named "mkkeywordhash". # # After the "tsrc" directory has been created and populated, run # this script: # # tclsh mksqlite3c.tcl # # The amalgamated SQLite code will be written into sqlite3.c # set help {Usage: tclsh mksqlite3c.tcl <options> where <options> is zero or more of the following with these effects: --nostatic => Do not generate with compile-time modifiable linkage. --linemacros=? => Emit #line directives into output or not. (? = 1 or 0) --useapicall => Prepend functions with SQLITE_APICALL or SQLITE_CDECL. --srcdir $SRC => Specify the directory containing constituent sources. --help => See this. The value setting options default to --linemacros=1 and '--srcdir tsrc' . } # 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. # set addstatic 1 set linemacros 0 set useapicall 0 set srcdir tsrc for {set i 0} {$i<[llength $argv]} {incr i} { set x [lindex $argv $i] if {[regexp {^-?-nostatic$} $x]} { set addstatic 0 } elseif {[regexp {^-?-linemacros(?:=([01]))?$} $x ma ulm]} { if {$ulm == ""} {set ulm 1} set linemacros $ulm } elseif {[regexp {^-?-useapicall$} $x]} { set useapicall 1 } elseif {[regexp {^-?-srcdir$} $x]} { incr i if {$i==[llength $argv]} { error "No argument following $x" } set srcdir [lindex $argv $i] } elseif {[regexp {^-?-((help)|\?)$} $x]} { puts $help exit 0 } else { error "unknown command-line option: $x" } } set in [open $srcdir/sqlite3.h] set cnt 0 set VERSION ????? while {![eof $in]} { set line [gets $in] if {$line=="" && [eof $in]} break incr cnt regexp {#define\s+SQLITE_VERSION\s+"(.*)"} $line all VERSION |
︙ | ︙ | |||
83 84 85 86 87 88 89 90 91 92 93 94 95 96 | #define SQLITE_AMALGAMATION 1}] if {$addstatic} { puts $out \ {#ifndef SQLITE_PRIVATE # define SQLITE_PRIVATE static #endif} } # These are the header files used by SQLite. The first time any of these # files are seen in a #include statement in the C code, include the complete # text of the file in-line. The file only needs to be included once. # foreach hdr { btree.h | > > > > > > > > > > > > | 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 | #define SQLITE_AMALGAMATION 1}] if {$addstatic} { puts $out \ {#ifndef SQLITE_PRIVATE # define SQLITE_PRIVATE static #endif} } # Examine the parse.c file. If it contains lines of the form: # # "#ifndef SQLITE_ENABLE_UPDATE_LIMIT # # then set the SQLITE_UDL_CAPABLE_PARSER flag in the amalgamation. # set in [open $srcdir/parse.c] if {[regexp {ifndef SQLITE_ENABLE_UPDATE_DELETE_LIMIT} [read $in]]} { puts $out "#define SQLITE_UDL_CAPABLE_PARSER 1" } close $in # These are the header files used by SQLite. The first time any of these # files are seen in a #include statement in the C code, include the complete # text of the file in-line. The file only needs to be included once. # foreach hdr { btree.h |
︙ | ︙ | |||
127 128 129 130 131 132 133 134 135 136 137 138 139 140 | vxworks.h wal.h whereInt.h } { set available_hdr($hdr) 1 } set available_hdr(sqliteInt.h) 0 set available_hdr(sqlite3session.h) 0 # These headers should be copied into the amalgamation without modifying any # of their function declarations or definitions. set varonly_hdr(sqlite3.h) 1 # These are the functions that accept a variable number of arguments. They | > | 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 | vxworks.h wal.h whereInt.h } { set available_hdr($hdr) 1 } set available_hdr(sqliteInt.h) 0 set available_hdr(os_common.h) 0 set available_hdr(sqlite3session.h) 0 # These headers should be copied into the amalgamation without modifying any # of their function declarations or definitions. set varonly_hdr(sqlite3.h) 1 # These are the functions that accept a variable number of arguments. They |
︙ | ︙ | |||
166 167 168 169 170 171 172 | # Read the source file named $filename and write it into the # sqlite3.c output file. If any #include statements are seen, # process them appropriately. # proc copy_file {filename} { global seen_hdr available_hdr varonly_hdr cdecllist out | | | < | < | | 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 | # Read the source file named $filename and write it into the # sqlite3.c output file. If any #include statements are seen, # process them appropriately. # proc copy_file {filename} { global seen_hdr available_hdr varonly_hdr cdecllist out global addstatic linemacros useapicall srcdir set ln 0 set tail [file tail $filename] section_comment "Begin file $tail" if {$linemacros} {puts $out "#line 1 \"$filename\""} set in [open $filename r] 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]+)(\(.*)} if {[file extension $filename]==".h"} { set declpattern " *$declpattern" } set declpattern ^$declpattern\$ while {![eof $in]} { set line [string trimright [gets $in]] incr ln if {[regexp {^\s*#\s*include\s+["<]([^">]+)[">]} $line all hdr]} { if {[info exists available_hdr($hdr)]} { if {$available_hdr($hdr)} { set available_hdr($hdr) 0 section_comment "Include $hdr in the middle of $tail" copy_file $srcdir/$hdr section_comment "Continuing where we left off in $tail" if {$linemacros} {puts $out "#line [expr {$ln+1}] \"$filename\""} } else { # Comment out the entire line, replacing any nested comment # begin/end markers with the harmless substring "**". puts $out "/* [string map [list /* ** */ **] $line] */" } |
︙ | ︙ | |||
239 240 241 242 243 244 245 | if {[lsearch -exact $cdecllist $funcname] >= 0} { append line SQLITE_CDECL " " } else { append line SQLITE_APICALL " " } } append line $funcname $rest | | | 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 | if {[lsearch -exact $cdecllist $funcname] >= 0} { append line SQLITE_CDECL " " } else { append line SQLITE_APICALL " " } } append line $funcname $rest if {$funcname=="sqlite3_sourceid"} { # The sqlite3_sourceid() routine is synthesized at the end of # the amalgamation puts $out "/* $line */" } else { puts $out $line } } else { |
︙ | ︙ | |||
287 288 289 290 291 292 293 | # Process the source files. Process files containing commonly # used subroutines first in order to help the compiler find # inlining opportunities. # foreach file { | < > > | 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 | # Process the source files. Process files containing commonly # used subroutines first in order to help the compiler find # inlining opportunities. # foreach file { sqliteInt.h os_common.h ctime.c global.c status.c date.c os.c fault.c |
︙ | ︙ | |||
337 338 339 340 341 342 343 344 345 346 347 348 349 350 | vdbemem.c vdbeaux.c vdbeapi.c vdbetrace.c vdbe.c vdbeblob.c vdbesort.c memjournal.c walker.c resolve.c expr.c alter.c analyze.c | > | 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 | vdbemem.c vdbeaux.c vdbeapi.c vdbetrace.c vdbe.c vdbeblob.c vdbesort.c vdbevtab.c memjournal.c walker.c resolve.c expr.c alter.c analyze.c |
︙ | ︙ | |||
400 401 402 403 404 405 406 | sqlite3rbu.c dbstat.c dbpage.c sqlite3session.c fts5.c stmt.c } { | | < < < < < < < < < < < < < < < < < < < | < < < < | | | 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 | sqlite3rbu.c dbstat.c dbpage.c sqlite3session.c fts5.c stmt.c } { copy_file $srcdir/$file } puts $out \ "/* Return the source-id for this library */ SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; }" puts $out \ "/************************** End of sqlite3.c ******************************/" close $out |
Changes to tool/mksqlite3h.tcl.
︙ | ︙ | |||
103 104 105 106 107 108 109 | foreach file $filelist { set in [open $file] if {![regexp {sqlite\.h\.in} $file]} { puts "/******** Begin file [file tail $file] *********/" } while {![eof $in]} { | | | 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 | foreach file $filelist { set in [open $file] if {![regexp {sqlite\.h\.in} $file]} { puts "/******** Begin file [file tail $file] *********/" } while {![eof $in]} { set line [string trimright [gets $in]] # File sqlite3rtree.h contains a line "#include <sqlite3.h>". Omit this # line when copying sqlite3rtree.h into sqlite3.h. # if {[string match {*#include*[<"]sqlite3.h[>"]*} $line]} continue regsub -- --VERS-- $line $zVersion line |
︙ | ︙ |
Changes to tool/offsets.c.
︙ | ︙ | |||
71 72 73 74 75 76 77 | int rc; if( p->zErr ) return; rc = sqlite3_open(zFile, &db); if( rc ){ ofstError(p, "cannot open database file \"%s\"", zFile); goto rootAndColumn_exit; } | | | 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 | int rc; if( p->zErr ) return; rc = sqlite3_open(zFile, &db); if( rc ){ ofstError(p, "cannot open database file \"%s\"", zFile); goto rootAndColumn_exit; } zSql = sqlite3_mprintf("SELECT rootpage FROM sqlite_schema WHERE name=%Q", zTable); rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0); if( rc ) ofstError(p, "%s: [%s]", sqlite3_errmsg(db), zSql); sqlite3_free(zSql); if( p->zErr ) goto rootAndColumn_exit; if( sqlite3_step(pStmt)!=SQLITE_ROW ){ ofstError(p, "cannot find table [%s]\n", zTable); |
︙ | ︙ |
Changes to tool/omittest.tcl.
︙ | ︙ | |||
94 95 96 97 98 99 100 | if {![file exists $sqlite3_dummy]} { set wr [open $sqlite3_dummy w] puts $wr "dummy" close $wr } if {$::SKIP_RUN} { | | | 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 | if {![file exists $sqlite3_dummy]} { set wr [open $sqlite3_dummy w] puts $wr "dummy" close $wr } if {$::SKIP_RUN} { # puts "Skip testing $dir." } else { # Run the test suite. puts -nonewline "Testing $dir..." flush stdout set rc [catch { exec $::MAKEBIN -C $dir -f makefile test >& $dir/test.log }] |
︙ | ︙ | |||
123 124 125 126 127 128 129 | proc process_options {argv} { set ::MAKEBIN make ;# Default value if {$::tcl_platform(platform)=="windows"} { set ::MAKEFILE ./Makefile ;# Default value on Windows } else { set ::MAKEFILE ./Makefile.linux-gcc ;# Default value } | | | 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 | proc process_options {argv} { set ::MAKEBIN make ;# Default value if {$::tcl_platform(platform)=="windows"} { set ::MAKEFILE ./Makefile ;# Default value on Windows } else { set ::MAKEFILE ./Makefile.linux-gcc ;# Default value } set ::SKIP_RUN 1 ;# Default to attempt test set ::TARGET testfixture ;# Default thing to build for {set i 0} {$i < [llength $argv]} {incr i} { switch -regexp -- [lindex $argv $i] { -{1,2}makefile { incr i set ::MAKEFILE [lindex $argv $i] |
︙ | ︙ | |||
146 147 148 149 150 151 152 153 154 155 156 157 158 159 | incr i set ::TARGET [lindex $argv $i] } -{1,2}skip_run { set ::SKIP_RUN 1 } -{1,2}help { puts $::USAGE_MESSAGE exit } -.* { | > > > | 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 | incr i set ::TARGET [lindex $argv $i] } -{1,2}skip_run { set ::SKIP_RUN 1 } -{1,2}run { set ::SKIP_RUN 0 } -{1,2}help { puts $::USAGE_MESSAGE exit } -.* { |
︙ | ︙ | |||
188 189 190 191 192 193 194 | SQLITE_OMIT_AUTOINIT \ SQLITE_OMIT_AUTOMATIC_INDEX \ SQLITE_OMIT_AUTORESET \ SQLITE_OMIT_AUTOVACUUM \ SQLITE_OMIT_BETWEEN_OPTIMIZATION \ SQLITE_OMIT_BLOB_LITERAL \ SQLITE_OMIT_BTREECOUNT \ | | > > > > > > > > > > > | > > | 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 | SQLITE_OMIT_AUTOINIT \ SQLITE_OMIT_AUTOMATIC_INDEX \ SQLITE_OMIT_AUTORESET \ SQLITE_OMIT_AUTOVACUUM \ SQLITE_OMIT_BETWEEN_OPTIMIZATION \ SQLITE_OMIT_BLOB_LITERAL \ SQLITE_OMIT_BTREECOUNT \ SQLITE_OMIT_CASE_SENSITIVE_LIKE_PRAGMA \ SQLITE_OMIT_CAST \ SQLITE_OMIT_CHECK \ SQLITE_OMIT_COMPILEOPTION_DIAGS \ SQLITE_OMIT_COMPLETE \ SQLITE_OMIT_COMPOUND_SELECT \ SQLITE_OMIT_CONFLICT_CLAUSE \ SQLITE_OMIT_CTE \ SQLITE_OMIT_DATETIME_FUNCS \ SQLITE_OMIT_DECLTYPE \ SQLITE_OMIT_DEPRECATED \ SQLITE_OMIT_DESERIALIZE \ SQLITE_OMIT_DISKIO \ SQLITE_OMIT_EXPLAIN \ SQLITE_OMIT_FLAG_PRAGMAS \ SQLITE_OMIT_FLOATING_POINT \ SQLITE_OMIT_FOREIGN_KEY \ SQLITE_OMIT_GENERATED_COLUMNS \ SQLITE_OMIT_GET_TABLE \ SQLITE_OMIT_HEX_INTEGER \ SQLITE_OMIT_INCRBLOB \ SQLITE_OMIT_INTEGRITY_CHECK \ SQLITE_OMIT_INTROSPECTION_PRAGMAS \ SQLITE_OMIT_LIKE_OPTIMIZATION \ SQLITE_OMIT_LOAD_EXTENSION \ SQLITE_OMIT_LOCALTIME \ SQLITE_OMIT_LOOKASIDE \ SQLITE_OMIT_MEMORYDB \ SQLITE_OMIT_OR_OPTIMIZATION \ SQLITE_OMIT_PAGER_PRAGMAS \ SQLITE_OMIT_PARSER_TRACE \ SQLITE_OMIT_POPEN \ SQLITE_OMIT_PRAGMA \ SQLITE_OMIT_PROGRESS_CALLBACK \ SQLITE_OMIT_QUICKBALANCE \ SQLITE_OMIT_RANDOMNESS \ SQLITE_OMIT_REINDEX \ SQLITE_OMIT_SCHEMA_PRAGMAS \ SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS \ SQLITE_OMIT_SHARED_CACHE \ SQLITE_OMIT_SHUTDOWN_DIRECTORIES \ SQLITE_OMIT_SUBQUERY \ SQLITE_OMIT_TCL_VARIABLE \ SQLITE_OMIT_TEMPDB \ SQLITE_OMIT_TEST_CONTROL \ SQLITE_OMIT_TRACE \ SQLITE_OMIT_TRIGGER \ SQLITE_OMIT_TRUNCATE_OPTIMIZATION \ SQLITE_OMIT_UPSERT \ SQLITE_OMIT_UTF16 \ SQLITE_OMIT_VACUUM \ SQLITE_OMIT_VIEW \ SQLITE_OMIT_VIRTUALTABLE \ SQLITE_OMIT_WAL \ SQLITE_OMIT_WINDOWFUNC \ SQLITE_OMIT_WSD \ SQLITE_OMIT_XFER_OPT \ ] set ::ENABLE_SYMBOLS [list \ SQLITE_ALLOW_ROWID_IN_VIEW \ SQLITE_DISABLE_DIRSYNC \ SQLITE_DISABLE_LFS \ SQLITE_ENABLE_ATOMIC_WRITE \ SQLITE_ENABLE_COLUMN_METADATA \ SQLITE_ENABLE_EXPENSIVE_ASSERT \ SQLITE_ENABLE_FTS3 \ SQLITE_ENABLE_FTS3_PARENTHESIS \ |
︙ | ︙ |
Changes to tool/replace.tcl.
1 2 3 4 5 6 7 8 9 10 11 | #!/usr/bin/tcl # # Replace string with another string -OR- include # only lines successfully modified with a regular # expression. # fconfigure stdout -translation binary -encoding binary fconfigure stderr -translation binary -encoding binary set mode [string tolower [lindex $argv 0]] set from [lindex $argv 1] set to [lindex $argv 2] | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | #!/usr/bin/tcl # # Replace string with another string -OR- include # only lines successfully modified with a regular # expression. # fconfigure stdout -translation binary -encoding binary fconfigure stderr -translation binary -encoding binary set mode [string tolower [lindex $argv 0]] set from [lindex $argv 1] set to [lindex $argv 2] if {-1 == [lsearch -exact [list exact regsub include] $mode]} {exit 1} if {[string length $from]==0} {exit 2} while {![eof stdin]} { set line [gets stdin] if {[eof stdin]} break switch -exact $mode { exact {set line [string map [list $from $to] $line]} regsub {regsub -all -- $from $line $to line} |
︙ | ︙ |
Changes to tool/showdb.c.
︙ | ︙ | |||
16 17 18 19 20 21 22 23 24 | #endif #include <stdlib.h> #include <string.h> #include <assert.h> #include "sqlite3.h" static struct GlobalData { | > > > > > | | < < < < | | 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 | #endif #include <stdlib.h> #include <string.h> #include <assert.h> #include "sqlite3.h" typedef unsigned char u8; /* unsigned 8-bit */ typedef unsigned int u32; /* unsigned 32-bit */ typedef sqlite3_int64 i64; /* signed 64-bit */ typedef sqlite3_uint64 u64; /* unsigned 64-bit */ static struct GlobalData { u32 pagesize; /* Size of a database page */ int dbfd; /* File descriptor for reading the DB */ u32 mxPage; /* Last page number */ int perLine; /* HEX elements to print per line */ int bRaw; /* True to access db file via OS APIs */ sqlite3_file *pFd; /* File descriptor for non-raw mode */ sqlite3 *pDb; /* Database handle that owns pFd */ } g = {1024, -1, 0, 16, 0, 0, 0}; /* ** Convert the var-int format into i64. Return the number of bytes ** in the var-int. Write the var-int value into *pVal. */ static int decodeVarint(const unsigned char *z, i64 *pVal){ i64 v = 0; int i; for(i=0; i<8; i++){ v = (v<<7) + (z[i]&0x7f); if( (z[i]&0x80)==0 ){ *pVal = v; return i+1; } } v = (v<<8) + (z[i]&0xff); *pVal = v; return 9; } /* ** Extract a big-endian 32-bit integer */ static u32 decodeInt32(const u8 *z){ return (z[0]<<24) + (z[1]<<16) + (z[2]<<8) + z[3]; } /* Report an out-of-memory error and die. */ static void out_of_memory(void){ fprintf(stderr,"Out of memory...\n"); |
︙ | ︙ | |||
137 138 139 140 141 142 143 | ** ** Space to hold the content is obtained from sqlite3_malloc() and needs ** to be freed by the caller. */ static unsigned char *fileRead(sqlite3_int64 ofst, int nByte){ unsigned char *aData; int got; | | | | | 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 | ** ** Space to hold the content is obtained from sqlite3_malloc() and needs ** to be freed by the caller. */ static unsigned char *fileRead(sqlite3_int64 ofst, int nByte){ unsigned char *aData; int got; aData = sqlite3_malloc64(32+(i64)nByte); if( aData==0 ) out_of_memory(); memset(aData, 0, nByte+32); if( g.bRaw==0 ){ int rc = g.pFd->pMethods->xRead(g.pFd, (void*)aData, nByte, ofst); if( rc!=SQLITE_OK && rc!=SQLITE_IOERR_SHORT_READ ){ fprintf(stderr, "error in xRead() - %d\n", rc); exit(1); } }else{ lseek(g.dbfd, (long)ofst, SEEK_SET); got = read(g.dbfd, aData, nByte); if( got>0 && got<nByte ) memset(aData+got, 0, nByte-got); } return aData; } /* ** Return the size of the file in byte. */ static i64 fileGetsize(void){ i64 res = 0; if( g.bRaw==0 ){ int rc = g.pFd->pMethods->xFileSize(g.pFd, &res); if( rc!=SQLITE_OK ){ fprintf(stderr, "error in xFileSize() - %d\n", rc); exit(1); } }else{ |
︙ | ︙ | |||
181 182 183 184 185 186 187 | ** End of low-level file access functions. **************************************************************************/ /* ** Print a range of bytes as hex and as ascii. */ static unsigned char *print_byte_range( | | | | > > > > > > | 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 | ** End of low-level file access functions. **************************************************************************/ /* ** Print a range of bytes as hex and as ascii. */ static unsigned char *print_byte_range( sqlite3_int64 ofst, /* First byte in the range of bytes to print */ int nByte, /* Number of bytes to print */ int printOfst /* Add this amount to the index on the left column */ ){ unsigned char *aData; int i, j; const char *zOfstFmt; if( ((printOfst+nByte)&~0xfff)==0 ){ zOfstFmt = " %03x: "; }else if( ((printOfst+nByte)&~0xffff)==0 ){ zOfstFmt = " %04x: "; }else if( ((printOfst+nByte)&~0xfffff)==0 ){ zOfstFmt = " %05x: "; }else if( ((printOfst+nByte)&~0xffffff)==0 ){ zOfstFmt = " %06x: "; }else{ zOfstFmt = " %08x: "; } aData = fileRead(ofst, nByte); for(i=0; i<nByte; i += g.perLine){ int go = 0; for(j=0; j<g.perLine; j++){ if( i+j>nByte ){ break; } if( aData[i+j] ){ go = 1; break; } } if( !go && i>0 && i+g.perLine<nByte ) continue; fprintf(stdout, zOfstFmt, i+printOfst); for(j=0; j<g.perLine; j++){ if( i+j>nByte ){ fprintf(stdout, " "); }else{ fprintf(stdout,"%02x ", aData[i+j]); } |
︙ | ︙ | |||
226 227 228 229 230 231 232 | } return aData; } /* ** Print an entire page of content as hex */ | | | | | | | | | 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 | } return aData; } /* ** Print an entire page of content as hex */ static void print_page(u32 iPg){ i64 iStart; unsigned char *aData; iStart = ((i64)(iPg-1))*g.pagesize; fprintf(stdout, "Page %u: (offsets 0x%llx..0x%llx)\n", iPg, iStart, iStart+g.pagesize-1); aData = print_byte_range(iStart, g.pagesize, 0); sqlite3_free(aData); } /* Print a line of decoded output showing a 4-byte unsigned integer. */ static void print_decode_line( unsigned char *aData, /* Content being decoded */ int ofst, int nByte, /* Start and size of decode */ const char *zMsg /* Message to append */ ){ int i, j; u32 val = aData[ofst]; char zBuf[100]; sprintf(zBuf, " %03x: %02x", ofst, aData[ofst]); i = (int)strlen(zBuf); for(j=1; j<4; j++){ if( j>=nByte ){ sprintf(&zBuf[i], " "); }else{ sprintf(&zBuf[i], " %02x", aData[ofst+j]); val = val*256 + aData[ofst+j]; } i += (int)strlen(&zBuf[i]); } sprintf(&zBuf[i], " %10u", val); printf("%s %s\n", zBuf, zMsg); } /* ** Decode the database header. */ static void print_db_header(void){ |
︙ | ︙ | |||
292 293 294 295 296 297 298 299 300 301 302 303 304 305 | 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"); } /* ** Describe cell content. */ static i64 describeContent( unsigned char *a, /* Cell content */ | > | 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 | 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"); sqlite3_free(aData); } /* ** Describe cell content. */ static i64 describeContent( unsigned char *a, /* Cell content */ |
︙ | ︙ | |||
404 405 406 407 408 409 410 | unsigned char *a, /* Cell content */ int showCellContent, /* Show cell content if true */ char **pzDesc /* Store description here */ ){ int i; i64 nDesc = 0; int n = 0; | | | | | | 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 | unsigned char *a, /* Cell content */ int showCellContent, /* Show cell content if true */ char **pzDesc /* Store description here */ ){ int i; i64 nDesc = 0; int n = 0; u32 leftChild; i64 nPayload; i64 rowid; i64 nLocal; static char zDesc[1000]; i = 0; if( cType<=5 ){ leftChild = ((a[0]*256 + a[1])*256 + a[2])*256 + a[3]; a += 4; n += 4; sprintf(zDesc, "lx: %u ", leftChild); nDesc = strlen(zDesc); } if( cType!=5 ){ i = decodeVarint(a, &nPayload); a += i; n += i; sprintf(&zDesc[nDesc], "n: %lld ", nPayload); nDesc += strlen(&zDesc[nDesc]); nLocal = localPayload(nPayload, cType); }else{ nPayload = nLocal = 0; } if( cType==5 || cType==13 ){ i = decodeVarint(a, &rowid); a += i; n += i; sprintf(&zDesc[nDesc], "r: %lld ", rowid); nDesc += strlen(&zDesc[nDesc]); } if( nLocal<nPayload ){ u32 ovfl; unsigned char *b = &a[nLocal]; ovfl = ((b[0]*256 + b[1])*256 + b[2])*256 + b[3]; sprintf(&zDesc[nDesc], "ov: %u ", ovfl); nDesc += strlen(&zDesc[nDesc]); n += 4; } if( showCellContent && cType!=5 ){ nDesc += describeContent(a, nLocal, &zDesc[nDesc-1]); } *pzDesc = zDesc; |
︙ | ︙ | |||
481 482 483 484 485 486 487 | unsigned char *a, /* Page content (without the page-1 header) */ unsigned pgno, /* Page number */ int iCell, /* Cell index */ int szPgHdr, /* Size of the page header. 0 or 100 */ int ofst /* Cell begins at a[ofst] */ ){ int i, j = 0; | | | | 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 | unsigned char *a, /* Page content (without the page-1 header) */ unsigned pgno, /* Page number */ int iCell, /* Cell index */ int szPgHdr, /* Size of the page header. 0 or 100 */ int ofst /* Cell begins at a[ofst] */ ){ int i, j = 0; u32 leftChild; i64 k; i64 nPayload; i64 rowid; i64 nHdr; i64 iType; i64 nLocal; unsigned char *x = a + ofst; unsigned char *end; unsigned char cType = a[0]; int nCol = 0; int szCol[2000]; int ofstCol[2000]; int typeCol[2000]; printf("Cell[%d]:\n", iCell); if( cType<=5 ){ leftChild = ((x[0]*256 + x[1])*256 + x[2])*256 + x[3]; printBytes(a, x, 4); printf("left child page:: %u\n", leftChild); x += 4; } if( cType!=5 ){ i = decodeVarint(x, &nPayload); printBytes(a, x, i); nLocal = localPayload(nPayload, cType); if( nLocal==nPayload ){ |
︙ | ︙ | |||
618 619 620 621 622 623 624 | } if( j<nLocal ){ printBytes(a, x+j, 0); printf("... %lld bytes of content ...\n", nLocal-j); } if( nLocal<nPayload ){ printBytes(a, x+nLocal, 4); | | | 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 | } if( j<nLocal ){ printBytes(a, x+j, 0); printf("... %lld bytes of content ...\n", nLocal-j); } if( nLocal<nPayload ){ printBytes(a, x+nLocal, 4); printf("overflow-page: %u\n", decodeInt32(x+nLocal)); } } /* ** Decode a btree page */ |
︙ | ︙ | |||
725 726 727 728 729 730 731 | } } /* ** Decode a freelist trunk page. */ static void decode_trunk_page( | | | > | | | | | | | | | 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 | } } /* ** Decode a freelist trunk page. */ static void decode_trunk_page( u32 pgno, /* The page number */ int detail, /* Show leaf pages if true */ int recursive /* Follow the trunk change if true */ ){ u32 i; u32 n; unsigned char *a; while( pgno>0 ){ a = fileRead((pgno-1)*g.pagesize, g.pagesize); printf("Decode of freelist trunk page %d:\n", pgno); print_decode_line(a, 0, 4, "Next freelist trunk page"); print_decode_line(a, 4, 4, "Number of entries on this page"); if( detail ){ n = decodeInt32(&a[4]); for(i=0; i<n && i<g.pagesize/4; i++){ u32 x = decodeInt32(&a[8+4*i]); char zIdx[13]; sprintf(zIdx, "[%d]", i); printf(" %5s %7u", zIdx, x); if( i%5==4 ) printf("\n"); } if( i%5!=0 ) printf("\n"); } if( !recursive ){ pgno = 0; }else{ pgno = decodeInt32(&a[0]); } sqlite3_free(a); } } /* ** A short text comment on the use of each page. */ static char **zPageUse; /* ** Add a comment on the use of a page. */ static void page_usage_msg(u32 pgno, const char *zFormat, ...){ va_list ap; char *zMsg; va_start(ap, zFormat); zMsg = sqlite3_vmprintf(zFormat, ap); va_end(ap); if( pgno<=0 || pgno>g.mxPage ){ printf("ERROR: page %d out of range 1..%u: %s\n", pgno, g.mxPage, zMsg); sqlite3_free(zMsg); return; } if( zPageUse[pgno]!=0 ){ printf("ERROR: page %d used multiple times:\n", pgno); printf("ERROR: previous: %s\n", zPageUse[pgno]); printf("ERROR: current: %s\n", zMsg); sqlite3_free(zPageUse[pgno]); } zPageUse[pgno] = zMsg; } /* ** Find overflow pages of a cell and describe their usage. */ static void page_usage_cell( unsigned char cType, /* Page type */ unsigned char *a, /* Cell content */ u32 pgno, /* page containing the cell */ int cellno /* Index of the cell on the page */ ){ int i; int n = 0; i64 nPayload; i64 rowid; i64 nLocal; |
︙ | ︙ | |||
819 820 821 822 823 824 825 | } if( cType==5 || cType==13 ){ i = decodeVarint(a, &rowid); a += i; n += i; } if( nLocal<nPayload ){ | | | | | > > > > > > | > > | > > > | | > > > > > > > > > > > > > > | > > > > > > > | | | > > | < | > | | > > > > | > > > > | 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 | } if( cType==5 || cType==13 ){ i = decodeVarint(a, &rowid); a += i; n += i; } if( nLocal<nPayload ){ u32 ovfl = decodeInt32(a+nLocal); u32 cnt = 0; while( ovfl && (cnt++)<g.mxPage ){ page_usage_msg(ovfl, "overflow %d from cell %d of page %u", cnt, cellno, pgno); a = fileRead((ovfl-1)*(sqlite3_int64)g.pagesize, 4); ovfl = decodeInt32(a); sqlite3_free(a); } } } /* ** True if the memory is all zeros */ static int allZero(unsigned char *a, int n){ while( n && (a++)[0]==0 ){ n--; } return n==0; } /* ** Describe the usages of a b-tree page. ** ** If parent==0, then this is the root of a btree. If parent<0 then ** this is an orphan page. */ static void page_usage_btree( u32 pgno, /* Page to describe */ u32 parent, /* Parent of this page. 0 for root pages */ int idx, /* Which child of the parent */ const char *zName /* Name of the table */ ){ unsigned char *a; const char *zType = "corrupt node"; int nCell; int i; int hdr = pgno==1 ? 100 : 0; char zEntry[30]; if( pgno<=0 || pgno>g.mxPage ) return; a = fileRead((pgno-1)*g.pagesize, g.pagesize); switch( a[hdr] ){ case 0: { if( allZero(a, g.pagesize) ){ zType = "zeroed page"; }else if( parent<0 ){ return; }else{ zType = "corrupt node"; } break; } case 2: zType = "interior node of index"; break; case 5: zType = "interior node of table"; break; case 10: zType = "leaf of index"; break; case 13: zType = "leaf of table"; break; default: { if( parent<0 ) return; zType = "corrupt node"; } } nCell = a[hdr+3]*256 + a[hdr+4]; if( nCell==1 ){ sqlite3_snprintf(sizeof(zEntry),zEntry,"1 row"); }else{ sqlite3_snprintf(sizeof(zEntry),zEntry,"%d rows", nCell); } if( parent>0 ){ page_usage_msg(pgno, "%s [%s], child %d of page %d, %s", zType, zName, idx, parent, zEntry); }else if( parent==0 ){ page_usage_msg(pgno, "root %s [%s], %s", zType, zName, zEntry); }else{ page_usage_msg(pgno, "orphaned %s, %s", zType, zEntry); } if( a[hdr]==2 || a[hdr]==5 ){ int cellstart = hdr+12; u32 child; for(i=0; i<nCell; i++){ u32 cellidx; u32 ofst; cellidx = cellstart + i*2; if( cellidx+1 >= g.pagesize ){ printf("ERROR: page %d too many cells (%d)\n", pgno, nCell); break; } ofst = a[cellidx]*256 + a[cellidx+1]; if( ofst<cellidx+2 || ofst+4>=g.pagesize ){ printf("ERROR: page %d cell %d out of bounds\n", pgno, i); continue; } child = decodeInt32(a+ofst); page_usage_btree(child, pgno, i, zName); } child = decodeInt32(a+cellstart-4); page_usage_btree(child, pgno, i, zName); } if( a[hdr]==2 || a[hdr]==10 || a[hdr]==13 ){ |
︙ | ︙ | |||
891 892 893 894 895 896 897 | } sqlite3_free(a); } /* ** Determine page usage by the freelist */ | | | 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 | } sqlite3_free(a); } /* ** Determine page usage by the freelist */ static void page_usage_freelist(u32 pgno){ unsigned char *a; int cnt = 0; int i; int n; int iNext; int parent = 1; |
︙ | ︙ | |||
918 919 920 921 922 923 924 | pgno = iNext; } } /* ** Determine pages used as PTRMAP pages */ | | | | | | | | | > | > > | | 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 | pgno = iNext; } } /* ** Determine pages used as PTRMAP pages */ static void page_usage_ptrmap(u8 *a){ if( decodeInt32(a+52) ){ int usable = g.pagesize - a[20]; u64 pgno = 2; int perPage = usable/5; while( pgno<=g.mxPage ){ page_usage_msg((u32)pgno, "PTRMAP page covering %llu..%llu", pgno+1, pgno+perPage); pgno += perPage + 1; } } } /* ** Try to figure out how every page in the database file is being used. */ static void page_usage_report(const char *zPrg, const char *zDbName){ u32 i, j; int rc; sqlite3 *db; sqlite3_stmt *pStmt; unsigned char *a; char zQuery[200]; /* Avoid the pathological case */ if( g.mxPage<1 ){ printf("empty database\n"); return; } /* Open the database file */ db = openDatabase(zPrg, zDbName); /* Set up global variables zPageUse[] and g.mxPage to record page ** usages */ zPageUse = sqlite3_malloc64( sizeof(zPageUse[0])*(g.mxPage+1) ); if( zPageUse==0 ) out_of_memory(); memset(zPageUse, 0, sizeof(zPageUse[0])*(g.mxPage+1)); /* Discover the usage of each page */ a = fileRead(0, 100); page_usage_freelist(decodeInt32(a+32)); page_usage_ptrmap(a); sqlite3_free(a); page_usage_btree(1, 0, 0, "sqlite_schema"); sqlite3_exec(db, "PRAGMA writable_schema=ON", 0, 0, 0); for(j=0; j<2; j++){ sqlite3_snprintf(sizeof(zQuery), zQuery, "SELECT type, name, rootpage FROM SQLITE_MASTER WHERE rootpage" " ORDER BY rowid %s", j?"DESC":""); rc = sqlite3_prepare_v2(db, zQuery, -1, &pStmt, 0); if( rc==SQLITE_OK ){ while( sqlite3_step(pStmt)==SQLITE_ROW ){ u32 pgno = (u32)sqlite3_column_int64(pStmt, 2); page_usage_btree(pgno, 0, 0, (const char*)sqlite3_column_text(pStmt,1)); } }else{ printf("ERROR: cannot query database: %s\n", sqlite3_errmsg(db)); } rc = sqlite3_finalize(pStmt); if( rc==SQLITE_OK ) break; } sqlite3_close(db); /* Print the report and free memory used */ for(i=1; i<=g.mxPage; i++){ if( zPageUse[i]==0 ) page_usage_btree(i, -1, 0, 0); printf("%5u: %s\n", i, zPageUse[i] ? zPageUse[i] : "???"); } for(i=1; i<=g.mxPage; i++){ sqlite3_free(zPageUse[i]); } sqlite3_free(zPageUse); zPageUse = 0; } /* ** Try to figure out how every page in the database file is being used. */ static void ptrmap_coverage_report(const char *zDbName){ u64 pgno; unsigned char *aHdr; unsigned char *a; int usable; int perPage; int i; /* Avoid the pathological case */ |
︙ | ︙ | |||
1017 1018 1019 1020 1021 1022 1023 | if( aHdr[55]==0 ){ printf("database does not use PTRMAP pages\n"); return; } usable = g.pagesize - aHdr[20]; perPage = usable/5; sqlite3_free(aHdr); | | | | | | 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 | if( aHdr[55]==0 ){ printf("database does not use PTRMAP pages\n"); return; } usable = g.pagesize - aHdr[20]; perPage = usable/5; sqlite3_free(aHdr); printf("%5d: root of sqlite_schema\n", 1); for(pgno=2; pgno<=g.mxPage; pgno += perPage+1){ printf("%5llu: PTRMAP page covering %llu..%llu\n", pgno, pgno+1, pgno+perPage); a = fileRead((pgno-1)*g.pagesize, usable); for(i=0; i+5<=usable && pgno+1+i/5<=g.mxPage; i+=5){ const char *zType = "???"; u32 iFrom = decodeInt32(&a[i+1]); switch( a[i] ){ case 1: zType = "b-tree root page"; break; case 2: zType = "freelist page"; break; case 3: zType = "first page of overflow"; break; case 4: zType = "later page of overflow"; break; case 5: zType = "b-tree non-root page"; break; } printf("%5llu: %s, parent=%u\n", pgno+1+i/5, zType, iFrom); } sqlite3_free(a); } } /* ** Print a usage comment |
︙ | ︙ | |||
1094 1095 1096 1097 1098 1099 1100 | zPgSz = fileRead(16, 2); g.pagesize = zPgSz[0]*256 + zPgSz[1]*65536; if( g.pagesize==0 ) g.pagesize = 1024; sqlite3_free(zPgSz); printf("Pagesize: %d\n", g.pagesize); | | | | | | 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 | zPgSz = fileRead(16, 2); g.pagesize = zPgSz[0]*256 + zPgSz[1]*65536; if( g.pagesize==0 ) g.pagesize = 1024; sqlite3_free(zPgSz); printf("Pagesize: %d\n", g.pagesize); g.mxPage = (u32)((szFile+g.pagesize-1)/g.pagesize); printf("Available pages: 1..%u\n", g.mxPage); if( nArg==2 ){ u32 i; for(i=1; i<=g.mxPage; i++) print_page(i); }else{ int i; for(i=2; i<nArg; i++){ u32 iStart, iEnd; char *zLeft; if( strcmp(azArg[i], "dbheader")==0 ){ print_db_header(); continue; } if( strcmp(azArg[i], "pgidx")==0 ){ page_usage_report(zPrg, azArg[1]); |
︙ | ︙ | |||
1125 1126 1127 1128 1129 1130 1131 | usage(zPrg); continue; } if( !ISDIGIT(azArg[i][0]) ){ fprintf(stderr, "%s: unknown option: [%s]\n", zPrg, azArg[i]); continue; } | | | 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 | usage(zPrg); continue; } if( !ISDIGIT(azArg[i][0]) ){ fprintf(stderr, "%s: unknown option: [%s]\n", zPrg, azArg[i]); continue; } iStart = strtoul(azArg[i], &zLeft, 0); if( zLeft && strcmp(zLeft,"..end")==0 ){ iEnd = g.mxPage; }else if( zLeft && zLeft[0]=='.' && zLeft[1]=='.' ){ iEnd = strtol(&zLeft[2], 0, 0); }else if( zLeft && zLeft[0]=='b' ){ int ofst, nByte, hdrSize; unsigned char *a; |
︙ | ︙ |
Changes to tool/showlocks.c.
︙ | ︙ | |||
20 21 22 23 24 25 26 27 | /* ** Print all locks on the inode of "fd" that occur in between ** lwr and upr, inclusive. */ static int showLocksInRange(int fd, off_t lwr, off_t upr){ int cnt = 0; struct flock x; | > > > > > > > > > > > > > > > > > > > > | | | | | | | | | | > > > > > > > > > | > | > | | | > > | > > | 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 | /* ** Print all locks on the inode of "fd" that occur in between ** lwr and upr, inclusive. */ static int showLocksInRange(int fd, off_t lwr, off_t upr){ int cnt = 0; struct flock x; struct lockRange { off_t lwr; off_t upr; } *aPending = 0; int nAlloc = 1; int nPending = 0; int nDone = 0; nPending = 1; aPending = malloc( sizeof(aPending[0]) ); if( aPending==0 ){ fprintf(stderr, "out of memory\n"); exit(1); } aPending[0].lwr = lwr; aPending[0].upr = upr; for(nDone=0; nDone<nPending; nDone++){ lwr = aPending[nDone].lwr; upr = aPending[nDone].upr; if( lwr>=upr ) continue; x.l_type = F_WRLCK; x.l_whence = SEEK_SET; x.l_start = lwr; x.l_len = upr - lwr; fcntl(fd, F_GETLK, &x); if( x.l_type==F_UNLCK ) continue; printf("start: %-12d len: %-5d pid: %-5d type: %s\n", (int)x.l_start, (int)x.l_len, x.l_pid, x.l_type==F_WRLCK ? "WRLCK" : "RDLCK"); cnt++; if( nPending+2 > nAlloc ){ nAlloc = nAlloc*2 + 2; aPending = realloc(aPending, sizeof(aPending[0])*nAlloc ); } if( aPending==0 ){ fprintf(stderr, "unable to realloc for %d bytes\n", (int)sizeof(aPending[0])*(nPending+2)); exit(1); } if( lwr<x.l_start ){ aPending[nPending].lwr = lwr; aPending[nPending].upr = x.l_start; nPending++; } if( x.l_start+x.l_len<=upr ){ aPending[nPending].lwr = x.l_start + x.l_len; aPending[nPending].upr = upr; nPending++; } } free(aPending); return cnt; } int main(int argc, char **argv){ int fd; int cnt; |
︙ | ︙ |
Changes to tool/showwal.c.
︙ | ︙ | |||
113 114 115 116 117 118 119 | /* ** Read content from the file. ** ** Space to hold the content is obtained from malloc() and needs to be ** freed by the caller. */ | | | 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 | /* ** Read content from the file. ** ** Space to hold the content is obtained from malloc() and needs to be ** freed by the caller. */ static unsigned char *getContent(i64 ofst, int nByte){ unsigned char *aData; aData = malloc(nByte); if( aData==0 ) out_of_memory(); lseek(fd, ofst, SEEK_SET); read(fd, aData, nByte); return aData; } |
︙ | ︙ | |||
200 201 202 203 204 205 206 | printf("%s %s\n", zBuf, zMsg); } /* ** Print an entire page of content as hex */ static void print_frame(int iFrame){ | | | | | | | 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 | printf("%s %s\n", zBuf, zMsg); } /* ** Print an entire page of content as hex */ static void print_frame(int iFrame){ i64 iStart; unsigned char *aData; iStart = 32 + (i64)(iFrame-1)*(pagesize+24); fprintf(stdout, "Frame %d: (offsets 0x%llx..0x%llx)\n", iFrame, iStart, iStart+pagesize+24); aData = getContent(iStart, pagesize+24); print_decode_line(aData, 0, 4, 0, "Page number"); print_decode_line(aData, 4, 4, 0, "DB size, or 0 for non-commit"); print_decode_line(aData, 8, 4, 1, "Salt-1"); print_decode_line(aData,12, 4, 1, "Salt-2"); print_decode_line(aData,16, 4, 1, "Checksum-1"); print_decode_line(aData,20, 4, 1, "Checksum-2"); print_byte_range(iStart+24, pagesize, aData+24, 0); free(aData); } /* ** Summarize a single frame on a single line. */ static void print_oneline_frame(int iFrame, Cksum *pCksum){ i64 iStart; unsigned char *aData; unsigned int s0, s1; iStart = 32 + (i64)(iFrame-1)*(pagesize+24); aData = getContent(iStart, 24); extendCksum(pCksum, aData, 8, 0); extendCksum(pCksum, getContent(iStart+24, pagesize), pagesize, 0); s0 = getInt32(aData+16); s1 = getInt32(aData+20); fprintf(stdout, "Frame %4d: %6d %6d 0x%08x,%08x 0x%08x,%08x %s\n", iFrame, |
︙ | ︙ | |||
560 561 562 563 564 565 566 | } iStart = strtol(argv[i], &zLeft, 0); if( zLeft && strcmp(zLeft,"..end")==0 ){ iEnd = mxFrame; }else if( zLeft && zLeft[0]=='.' && zLeft[1]=='.' ){ iEnd = strtol(&zLeft[2], 0, 0); }else if( zLeft && zLeft[0]=='b' ){ | > | | | | 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 | } iStart = strtol(argv[i], &zLeft, 0); if( zLeft && strcmp(zLeft,"..end")==0 ){ iEnd = mxFrame; }else if( zLeft && zLeft[0]=='.' && zLeft[1]=='.' ){ iEnd = strtol(&zLeft[2], 0, 0); }else if( zLeft && zLeft[0]=='b' ){ i64 ofst; int nByte, hdrSize; unsigned char *a; if( iStart==1 ){ hdrSize = 100; ofst = hdrSize = 100; nByte = pagesize-100; }else{ hdrSize = 0; ofst = (i64)(iStart-1)*pagesize; nByte = pagesize; } ofst = 32 + hdrSize + (i64)(iStart-1)*(pagesize+24) + 24; a = getContent(ofst, nByte); decode_btree_page(a, iStart, hdrSize, zLeft+1); free(a); continue; #if !defined(_MSC_VER) }else if( zLeft && strcmp(zLeft,"truncate")==0 ){ /* Frame number followed by "truncate" truncates the WAL file |
︙ | ︙ |
Changes to tool/spaceanal.tcl.
︙ | ︙ | |||
12 13 14 15 16 17 18 | # false otherwise. # proc is_without_rowid {tname} { set t [string map {' ''} $tname] db eval "PRAGMA index_list = '$t'" o { if {$o(origin) == "pk"} { set n $o(name) | | | 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | # false otherwise. # proc is_without_rowid {tname} { set t [string map {' ''} $tname] db eval "PRAGMA index_list = '$t'" o { if {$o(origin) == "pk"} { set n $o(name) if {0==[db one { SELECT count(*) FROM sqlite_schema WHERE name=$n }]} { return 1 } } } return 0 } |
︙ | ︙ | |||
156 157 158 159 160 161 162 | puts "The SQLite database engine linked with this application\ lacks required capabilities. Recompile using the\ -DSQLITE_ENABLE_DBSTAT_VTAB compile-time option to fix\ this problem." exit 1 } | | | 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 | puts "The SQLite database engine linked with this application\ lacks required capabilities. Recompile using the\ -DSQLITE_ENABLE_DBSTAT_VTAB compile-time option to fix\ this problem." exit 1 } db eval {SELECT count(*) FROM sqlite_schema} set pageSize [expr {wide([db one {PRAGMA page_size}])}] if {$flags(-pageinfo)} { db eval {CREATE VIRTUAL TABLE temp.stat USING dbstat} db eval {SELECT name, path, pageno FROM temp.stat ORDER BY pageno} { puts "$pageno $name $path" } |
︙ | ︙ | |||
241 242 243 244 245 246 247 | db eval {CREATE TEMP TABLE dbstat AS SELECT * FROM temp.stat ORDER BY name, path} db eval {DROP TABLE temp.stat} set isCompressed 0 set compressOverhead 0 set depth 0 | | | | 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 | db eval {CREATE TEMP TABLE dbstat AS SELECT * FROM temp.stat ORDER BY name, path} db eval {DROP TABLE temp.stat} set isCompressed 0 set compressOverhead 0 set depth 0 set sql { SELECT name, tbl_name FROM sqlite_schema WHERE rootpage>0 } foreach {name tblname} [concat sqlite_schema sqlite_schema [db eval $sql]] { set is_index [expr {$name!=$tblname}] set is_without_rowid [is_without_rowid $name] db eval { SELECT sum(ncell) AS nentry, sum((pagetype=='leaf')*ncell) AS leaf_entries, |
︙ | ︙ | |||
556 557 558 559 560 561 562 | # free_percent: Percentage of file consumed by free pages (calculated). # free_percent2: Percentage of file consumed by free pages (header). # ntable: Number of tables in the db. # nindex: Number of indices in the db. # nautoindex: Number of indices created automatically. # nmanindex: Number of indices created manually. # user_payload: Number of bytes of payload in table btrees | | | 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 | # free_percent: Percentage of file consumed by free pages (calculated). # free_percent2: Percentage of file consumed by free pages (header). # ntable: Number of tables in the db. # nindex: Number of indices in the db. # nautoindex: Number of indices created automatically. # nmanindex: Number of indices created manually. # user_payload: Number of bytes of payload in table btrees # (not including sqlite_schema) # user_percent: $user_payload as a percentage of total file size. ### The following, setting $file_bytes based on the actual size of the file ### on disk, causes this tool to choke on zipvfs databases. So set it based ### on the return of [PRAGMA page_count] instead. if 0 { set file_bytes [file size $file_to_analyze] |
︙ | ︙ | |||
583 584 585 586 587 588 589 | set free_pgcnt [expr {$file_pgcnt-$inuse_pgcnt-$av_pgcnt}] set free_percent [percent $free_pgcnt $file_pgcnt] set free_pgcnt2 [db one {PRAGMA freelist_count}] set free_percent2 [percent $free_pgcnt2 $file_pgcnt] set file_pgcnt2 [expr {$inuse_pgcnt+$free_pgcnt2+$av_pgcnt}] | > > > | | | | | 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 | set free_pgcnt [expr {$file_pgcnt-$inuse_pgcnt-$av_pgcnt}] set free_percent [percent $free_pgcnt $file_pgcnt] set free_pgcnt2 [db one {PRAGMA freelist_count}] set free_percent2 [percent $free_pgcnt2 $file_pgcnt] set file_pgcnt2 [expr {$inuse_pgcnt+$free_pgcnt2+$av_pgcnt}] # Account for the lockbyte page if {$file_pgcnt2*$pageSize>1073742335} {incr file_pgcnt2} set ntable [db eval {SELECT count(*)+1 FROM sqlite_schema WHERE type='table'}] set nindex [db eval {SELECT count(*) FROM sqlite_schema WHERE type='index'}] set sql {SELECT count(*) FROM sqlite_schema WHERE name LIKE 'sqlite_autoindex%'} set nautoindex [db eval $sql] set nmanindex [expr {$nindex-$nautoindex}] # set total_payload [mem eval "SELECT sum(payload) FROM space_used"] set user_payload [mem one {SELECT int(sum(payload)) FROM space_used WHERE NOT is_index AND name NOT LIKE 'sqlite_schema'}] set user_percent [percent $user_payload $file_bytes] # Output the summary statistics calculated above. # puts "/** Disk-Space Utilization Report For $root_filename" puts "" statline {Page size in bytes} $pageSize |
︙ | ︙ | |||
724 725 726 727 728 729 730 | Pages of auto-vacuum overhead The number of pages that store data used by the database to facilitate auto-vacuum. This is zero for databases that do not support auto-vacuum. Number of tables in the database | | | 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 | Pages of auto-vacuum overhead The number of pages that store data used by the database to facilitate auto-vacuum. This is zero for databases that do not support auto-vacuum. Number of tables in the database The number of tables in the database, including the SQLITE_SCHEMA table used to store schema information. Number of indices The total number of indices in the database. Number of defined indices |
︙ | ︙ | |||
747 748 749 750 751 752 753 | Size of the file in bytes The total amount of disk space used by the entire database files. Bytes of user payload stored The total number of bytes of user payload stored in the database. The | | | 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 | Size of the file in bytes The total amount of disk space used by the entire database files. Bytes of user payload stored The total number of bytes of user payload stored in the database. The schema information in the SQLITE_SCHEMA table is not counted when computing this number. The percentage at the right shows the payload divided by the total file size. Percentage of total database The amount of the complete database file that is devoted to storing information described by this category. |
︙ | ︙ |
Changes to tool/speed-check.sh.
︙ | ︙ | |||
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 | ;; --stats) SPEEDTEST_OPTS="$SPEEDTEST_OPTS $1" ;; --without-rowid) SPEEDTEST_OPTS="$SPEEDTEST_OPTS $1" ;; --nomemstat) SPEEDTEST_OPTS="$SPEEDTEST_OPTS $1" ;; --temp) SPEEDTEST_OPTS="$SPEEDTEST_OPTS --temp 6" ;; --legacy) doWal=0 ;; --wal) doWal=1 ;; --size) shift; SIZE=$1 ;; --cachesize) shift; SPEEDTEST_OPTS="$SPEEDTEST_OPTS --cachesize $1" ;; --explain) doExplain=1 ;; --vdbeprofile) rm -f vdbe_profile.out CC_OPTS="$CC_OPTS -DVDBE_PROFILE" doCachegrind=0 | > > > > > > > > > > > > > > > > > > > | 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 | ;; --stats) SPEEDTEST_OPTS="$SPEEDTEST_OPTS $1" ;; --without-rowid) SPEEDTEST_OPTS="$SPEEDTEST_OPTS $1" ;; --strict) SPEEDTEST_OPTS="$SPEEDTEST_OPTS $1" ;; --nomemstat) SPEEDTEST_OPTS="$SPEEDTEST_OPTS $1" ;; --multithread) SPEEDTEST_OPTS="$SPEEDTEST_OPTS $1" ;; --singlethread) SPEEDTEST_OPTS="$SPEEDTEST_OPTS $1" ;; --serialized) SPEEDTEST_OPTS="$SPEEDTEST_OPTS $1" ;; --temp) SPEEDTEST_OPTS="$SPEEDTEST_OPTS --temp 6" ;; --legacy) doWal=0 CC_OPTS="$CC_OPTS -DSPEEDTEST_OMIT_HASH" ;; --verify) SPEEDTEST_OPTS="$SPEEDTEST_OPTS --verify" ;; --wal) doWal=1 ;; --size) shift; SIZE=$1 ;; --cachesize) shift; SPEEDTEST_OPTS="$SPEEDTEST_OPTS --cachesize $1" ;; --checkpoint) SPEEDTEST_OPTS="$SPEEDTEST_OPTS --checkpoint" ;; --explain) doExplain=1 ;; --vdbeprofile) rm -f vdbe_profile.out CC_OPTS="$CC_OPTS -DVDBE_PROFILE" doCachegrind=0 |
︙ | ︙ |
Changes to tool/sqldiff.c.
︙ | ︙ | |||
31 32 33 34 35 36 37 38 39 40 41 42 43 44 | */ struct GlobalVars { const char *zArgv0; /* Name of program */ int bSchemaOnly; /* Only show schema differences */ int bSchemaPK; /* Use the schema-defined PK, not the true PK */ int bHandleVtab; /* Handle fts3, fts4, fts5 and rtree vtabs */ unsigned fDebug; /* Debug flags */ sqlite3 *db; /* The database connection */ } g; /* ** Allowed values for g.fDebug */ #define DEBUG_COLUMN_NAMES 0x000001 | > | 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | */ struct GlobalVars { const char *zArgv0; /* Name of program */ int bSchemaOnly; /* Only show schema differences */ int bSchemaPK; /* Use the schema-defined PK, not the true PK */ int bHandleVtab; /* Handle fts3, fts4, fts5 and rtree vtabs */ unsigned fDebug; /* Debug flags */ int bSchemaCompare; /* Doing single-table sqlite_schema compare */ sqlite3 *db; /* The database connection */ } g; /* ** Allowed values for g.fDebug */ #define DEBUG_COLUMN_NAMES 0x000001 |
︙ | ︙ | |||
188 189 190 191 192 193 194 | int i; for(i=0; az[i]; i++) sqlite3_free(az[i]); sqlite3_free(az); } } /* | | | > > > | 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 | int i; for(i=0; az[i]; i++) sqlite3_free(az[i]); sqlite3_free(az); } } /* ** Return a list of column names [a] for the table zDb.zTab. Space to ** hold the list is obtained from sqlite3_malloc() and should released ** using namelistFree() when no longer needed. ** ** Primary key columns are listed first, followed by data columns. ** The number of columns in the primary key is returned in *pnPkey. ** ** Normally [a], the "primary key" in the previous sentence is the true ** primary key - the rowid or INTEGER PRIMARY KEY for ordinary tables ** or the declared PRIMARY KEY for WITHOUT ROWID tables. However, if ** the g.bSchemaPK flag is set, then the schema-defined PRIMARY KEY is ** used in all cases. In that case, entries that have NULL values in ** any of their primary key fields will be excluded from the analysis. ** ** If the primary key for a table is the rowid but rowid is inaccessible, ** then this routine returns a NULL pointer. ** ** [a. If the lone, named table is "sqlite_schema", "rootpage" column is ** omitted and the "type" and "name" columns are made to be the PK.] ** ** Examples: ** CREATE TABLE t1(a INT UNIQUE, b INTEGER, c TEXT, PRIMARY KEY(c)); ** *pnPKey = 1; ** az = { "rowid", "a", "b", "c", 0 } // Normal case ** az = { "c", "a", "b", 0 } // g.bSchemaPK==1 ** |
︙ | ︙ | |||
294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 | pStmt = db_prepare("PRAGMA %s.table_info=%Q", zDb, zTab); while( SQLITE_ROW==sqlite3_step(pStmt) ){ if( sqlite3_column_int(pStmt,5)>0 ) nPK++; } sqlite3_reset(pStmt); if( nPK==0 ) nPK = 1; truePk = 1; } *pnPKey = nPK; naz = nPK; az = sqlite3_malloc( sizeof(char*)*(nPK+1) ); if( az==0 ) runtimeError("out of memory"); memset(az, 0, sizeof(char*)*(nPK+1)); while( SQLITE_ROW==sqlite3_step(pStmt) ){ int iPKey; if( truePk && (iPKey = sqlite3_column_int(pStmt,5))>0 ){ | > > > > > > > > > > > > | > > > > | | | > | | | > > | 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 | pStmt = db_prepare("PRAGMA %s.table_info=%Q", zDb, zTab); while( SQLITE_ROW==sqlite3_step(pStmt) ){ if( sqlite3_column_int(pStmt,5)>0 ) nPK++; } sqlite3_reset(pStmt); if( nPK==0 ) nPK = 1; truePk = 1; } if( g.bSchemaCompare ){ assert( sqlite3_stricmp(zTab,"sqlite_schema")==0 || sqlite3_stricmp(zTab,"sqlite_master")==0 ); /* For sqlite_schema, will use type and name as the PK. */ nPK = 2; truePk = 0; } *pnPKey = nPK; naz = nPK; az = sqlite3_malloc( sizeof(char*)*(nPK+1) ); if( az==0 ) runtimeError("out of memory"); memset(az, 0, sizeof(char*)*(nPK+1)); if( g.bSchemaCompare ){ az[0] = sqlite3_mprintf("%s", "type"); az[1] = sqlite3_mprintf("%s", "name"); } while( SQLITE_ROW==sqlite3_step(pStmt) ){ char * sid = safeId((char*)sqlite3_column_text(pStmt,1)); int iPKey; if( truePk && (iPKey = sqlite3_column_int(pStmt,5))>0 ){ az[iPKey-1] = sid; }else{ if( !g.bSchemaCompare || !(strcmp(sid,"rootpage")==0 ||strcmp(sid,"name")==0 ||strcmp(sid,"type")==0)){ az = sqlite3_realloc(az, sizeof(char*)*(naz+2) ); if( az==0 ) runtimeError("out of memory"); az[naz++] = sid; } } } sqlite3_finalize(pStmt); if( az ) az[naz] = 0; /* If it is non-NULL, set *pbRowid to indicate whether or not the PK of ** this table is an implicit rowid (*pbRowid==1) or not (*pbRowid==0). */ if( pbRowid ) *pbRowid = (az[0]==0); /* If this table has an implicit rowid for a PK, figure out how to refer ** to it. There are usually three options - "rowid", "_rowid_" and "oid". ** Any of these will work, unless the table has an explicit column of the ** same name or the sqlite_schema tables are to be compared. In the latter ** case, pretend that the "true" primary key is the name column, which ** avoids extraneous diffs against the schemas due to rowid variance. */ if( az[0]==0 ){ const char *azRowid[] = { "rowid", "_rowid_", "oid" }; for(i=0; i<sizeof(azRowid)/sizeof(azRowid[0]); i++){ for(j=1; j<naz; j++){ if( sqlite3_stricmp(az[j], azRowid[i])==0 ) break; } if( j>=naz ){ |
︙ | ︙ | |||
376 377 378 379 380 381 382 | /* Could be an OOM, could be a zero-byte blob */ fprintf(out, "X''"); } break; } case SQLITE_TEXT: { const unsigned char *zArg = sqlite3_value_text(X); | < > > | > > > > > > > > > > > > > > | | | | | > | | 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 | /* Could be an OOM, could be a zero-byte blob */ fprintf(out, "X''"); } break; } case SQLITE_TEXT: { const unsigned char *zArg = sqlite3_value_text(X); if( zArg==0 ){ fprintf(out, "NULL"); }else{ int inctl = 0; int i, j; fprintf(out, "'"); for(i=j=0; zArg[i]; i++){ char c = zArg[i]; int ctl = iscntrl(c); if( ctl>inctl ){ inctl = ctl; fprintf(out, "%.*s'||X'%02x", i-j, &zArg[j], c); j = i+1; }else if( ctl ){ fprintf(out, "%02x", c); j = i+1; }else{ if( inctl ){ inctl = 0; fprintf(out, "'\n||'"); } if( c=='\'' ){ fprintf(out, "%.*s'", i-j+1, &zArg[j]); j = i+1; } } } fprintf(out, "%s'", &zArg[j]); } break; } case SQLITE_NULL: { fprintf(out, "NULL"); break; } |
︙ | ︙ | |||
412 413 414 415 416 417 418 | int nPk; /* Number of true primary key columns */ int nCol; /* Number of data columns */ int i; /* Loop counter */ sqlite3_stmt *pStmt; /* SQL statement */ const char *zSep; /* Separator string */ Str ins; /* Beginning of the INSERT statement */ | | | 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 | int nPk; /* Number of true primary key columns */ int nCol; /* Number of data columns */ int i; /* Loop counter */ sqlite3_stmt *pStmt; /* SQL statement */ const char *zSep; /* Separator string */ Str ins; /* Beginning of the INSERT statement */ pStmt = db_prepare("SELECT sql FROM aux.sqlite_schema WHERE name=%Q", zTab); if( SQLITE_ROW==sqlite3_step(pStmt) ){ fprintf(out, "%s;\n", sqlite3_column_text(pStmt,0)); } sqlite3_finalize(pStmt); if( !g.bSchemaOnly ){ az = columnNames("aux", zTab, &nPk, 0); strInit(&ins); |
︙ | ︙ | |||
462 463 464 465 466 467 468 | zSep = ","; } fprintf(out, ");\n"); } sqlite3_finalize(pStmt); strFree(&ins); } /* endif !g.bSchemaOnly */ | | > | > > > < > > > | > > > | | | 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 | zSep = ","; } fprintf(out, ");\n"); } sqlite3_finalize(pStmt); strFree(&ins); } /* endif !g.bSchemaOnly */ pStmt = db_prepare("SELECT sql FROM aux.sqlite_schema" " WHERE type='index' AND tbl_name=%Q AND sql IS NOT NULL", zTab); while( SQLITE_ROW==sqlite3_step(pStmt) ){ fprintf(out, "%s;\n", sqlite3_column_text(pStmt,0)); } sqlite3_finalize(pStmt); sqlite3_free(zId); } /* ** Compute all differences for a single table, except if the ** table name is sqlite_schema, ignore the rootpage column. */ static void diff_one_table(const char *zTab, FILE *out){ char *zId = safeId(zTab); /* Name of table (translated for us in SQL) */ char **az = 0; /* Columns in main */ char **az2 = 0; /* Columns in aux */ int nPk; /* Primary key columns in main */ int nPk2; /* Primary key columns in aux */ int n = 0; /* Number of columns in main */ int n2; /* Number of columns in aux */ int nQ; /* Number of output columns in the diff query */ int i; /* Loop counter */ const char *zSep; /* Separator string */ Str sql; /* Comparison query */ sqlite3_stmt *pStmt; /* Query statement to do the diff */ const char *zLead = /* Becomes line-comment for sqlite_schema */ (g.bSchemaCompare)? "-- " : ""; strInit(&sql); if( g.fDebug==DEBUG_COLUMN_NAMES ){ /* Simply run columnNames() on all tables of the origin ** database and show the results. This is used for testing ** and debugging of the columnNames() function. */ az = columnNames("aux",zTab, &nPk, 0); if( az==0 ){ printf("Rowid not accessible for %s\n", zId); }else{ printf("%s:", zId); for(i=0; az[i]; i++){ printf(" %s", az[i]); if( i+1==nPk ) printf(" *"); } printf("\n"); } goto end_diff_one_table; } if( sqlite3_table_column_metadata(g.db,"aux",zTab,0,0,0,0,0,0) ){ if( !sqlite3_table_column_metadata(g.db,"main",zTab,0,0,0,0,0,0) ){ /* Table missing from second database. */ if( g.bSchemaCompare ) fprintf(out, "-- 2nd DB has no %s table\n", zTab); else fprintf(out, "DROP TABLE %s;\n", zId); } goto end_diff_one_table; } if( sqlite3_table_column_metadata(g.db,"main",zTab,0,0,0,0,0,0) ){ /* Table missing from source */ if( g.bSchemaCompare ) fprintf(out, "-- 1st DB has no %s table\n", zTab); else dump_table(zTab, out); goto end_diff_one_table; } az = columnNames("main", zTab, &nPk, 0); az2 = columnNames("aux", zTab, &nPk2, 0); if( az && az2 ){ for(n=0; az[n] && az2[n]; n++){ if( sqlite3_stricmp(az[n],az2[n])!=0 ) break; } } if( az==0 || az2==0 || nPk!=nPk2 || az[n] ){ /* Schema mismatch */ fprintf(out, "%sDROP TABLE %s; -- due to schema mismatch\n", zLead, zId); dump_table(zTab, out); goto end_diff_one_table; } /* Build the comparison query */ for(n2=n; az2[n2]; n2++){ fprintf(out, "ALTER TABLE %s ADD COLUMN %s;\n", zId, safeId(az2[n2])); |
︙ | ︙ | |||
635 636 637 638 639 640 641 | if( g.fDebug & DEBUG_DIFF_SQL ){ printf("SQL for %s:\n%s\n", zId, sql.z); goto end_diff_one_table; } /* Drop indexes that are missing in the destination */ pStmt = db_prepare( | | | | | | | | | 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 | if( g.fDebug & DEBUG_DIFF_SQL ){ printf("SQL for %s:\n%s\n", zId, sql.z); goto end_diff_one_table; } /* Drop indexes that are missing in the destination */ pStmt = db_prepare( "SELECT name FROM main.sqlite_schema" " WHERE type='index' AND tbl_name=%Q" " AND sql IS NOT NULL" " AND sql NOT IN (SELECT sql FROM aux.sqlite_schema" " WHERE type='index' AND tbl_name=%Q" " AND sql IS NOT NULL)", zTab, zTab); while( SQLITE_ROW==sqlite3_step(pStmt) ){ char *z = safeId((const char*)sqlite3_column_text(pStmt,0)); fprintf(out, "DROP INDEX %s;\n", z); sqlite3_free(z); } sqlite3_finalize(pStmt); /* Run the query and output differences */ if( !g.bSchemaOnly ){ pStmt = db_prepare("%s", sql.z); while( SQLITE_ROW==sqlite3_step(pStmt) ){ int iType = sqlite3_column_int(pStmt, nPk); if( iType==1 || iType==2 ){ if( iType==1 ){ /* Change the content of a row */ fprintf(out, "%sUPDATE %s", zLead, zId); zSep = " SET"; for(i=nPk+1; i<nQ; i+=2){ if( sqlite3_column_int(pStmt,i)==0 ) continue; fprintf(out, "%s %s=", zSep, az2[(i+nPk-1)/2]); zSep = ","; printQuoted(out, sqlite3_column_value(pStmt,i+1)); } }else{ /* Delete a row */ fprintf(out, "%sDELETE FROM %s", zLead, zId); } zSep = " WHERE"; for(i=0; i<nPk; i++){ fprintf(out, "%s %s=", zSep, az2[i]); printQuoted(out, sqlite3_column_value(pStmt,i)); zSep = " AND"; } fprintf(out, ";\n"); }else{ /* Insert a row */ fprintf(out, "%sINSERT INTO %s(%s", zLead, zId, az2[0]); for(i=1; az2[i]; i++) fprintf(out, ",%s", az2[i]); fprintf(out, ") VALUES"); zSep = "("; for(i=0; i<nPk2; i++){ fprintf(out, "%s", zSep); zSep = ","; printQuoted(out, sqlite3_column_value(pStmt,i)); } for(i=nPk2+2; i<nQ; i+=2){ fprintf(out, ","); printQuoted(out, sqlite3_column_value(pStmt,i)); } fprintf(out, ");\n"); } } sqlite3_finalize(pStmt); } /* endif !g.bSchemaOnly */ /* Create indexes that are missing in the source */ pStmt = db_prepare( "SELECT sql FROM aux.sqlite_schema" " WHERE type='index' AND tbl_name=%Q" " AND sql IS NOT NULL" " AND sql NOT IN (SELECT sql FROM main.sqlite_schema" " WHERE type='index' AND tbl_name=%Q" " AND sql IS NOT NULL)", zTab, zTab); while( SQLITE_ROW==sqlite3_step(pStmt) ){ fprintf(out, "%s;\n", sqlite3_column_text(pStmt,0)); } sqlite3_finalize(pStmt); |
︙ | ︙ | |||
724 725 726 727 728 729 730 | ** Check that table zTab exists and has the same schema in both the "main" ** and "aux" databases currently opened by the global db handle. If they ** do not, output an error message on stderr and exit(1). Otherwise, if ** the schemas do match, return control to the caller. */ static void checkSchemasMatch(const char *zTab){ sqlite3_stmt *pStmt = db_prepare( | | | 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 | ** Check that table zTab exists and has the same schema in both the "main" ** and "aux" databases currently opened by the global db handle. If they ** do not, output an error message on stderr and exit(1). Otherwise, if ** the schemas do match, return control to the caller. */ static void checkSchemasMatch(const char *zTab){ sqlite3_stmt *pStmt = db_prepare( "SELECT A.sql=B.sql FROM main.sqlite_schema A, aux.sqlite_schema B" " WHERE A.name=%Q AND B.name=%Q", zTab, zTab ); if( SQLITE_ROW==sqlite3_step(pStmt) ){ if( sqlite3_column_int(pStmt,0)==0 ){ runtimeError("schema changes for table %s", safeId(zTab)); } }else{ |
︙ | ︙ | |||
1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 | int nPk = 0; /* Number of PRIMARY KEY columns */ Str sql; /* SQL for the diff query */ int i, k; /* Loop counters */ const char *zSep; /* List separator */ /* Check that the schemas of the two tables match. Exit early otherwise. */ checkSchemasMatch(zTab); pStmt = db_prepare("PRAGMA main.table_info=%Q", zTab); while( SQLITE_ROW==sqlite3_step(pStmt) ){ nCol++; azCol = sqlite3_realloc(azCol, sizeof(char*)*nCol); if( azCol==0 ) runtimeError("out of memory"); aiFlg = sqlite3_realloc(aiFlg, sizeof(int)*nCol); | > | 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 | int nPk = 0; /* Number of PRIMARY KEY columns */ Str sql; /* SQL for the diff query */ int i, k; /* Loop counters */ const char *zSep; /* List separator */ /* Check that the schemas of the two tables match. Exit early otherwise. */ checkSchemasMatch(zTab); strInit(&sql); pStmt = db_prepare("PRAGMA main.table_info=%Q", zTab); while( SQLITE_ROW==sqlite3_step(pStmt) ){ nCol++; azCol = sqlite3_realloc(azCol, sizeof(char*)*nCol); if( azCol==0 ) runtimeError("out of memory"); aiFlg = sqlite3_realloc(aiFlg, sizeof(int)*nCol); |
︙ | ︙ | |||
1561 1562 1563 1564 1565 1566 1567 | if( aiPk==0 ) runtimeError("out of memory"); } aiPk[i-1] = nCol-1; } } sqlite3_finalize(pStmt); if( nPk==0 ) goto end_changeset_one_table; | < | 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 | if( aiPk==0 ) runtimeError("out of memory"); } aiPk[i-1] = nCol-1; } } sqlite3_finalize(pStmt); if( nPk==0 ) goto end_changeset_one_table; if( nCol>nPk ){ strPrintf(&sql, "SELECT %d", SQLITE_UPDATE); for(i=0; i<nCol; i++){ if( aiFlg[i] ){ strPrintf(&sql, ",\n A.%s", azCol[i]); }else{ strPrintf(&sql, ",\n A.%s IS NOT B.%s, A.%s, B.%s", |
︙ | ︙ | |||
1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 | sqlite3_finalize(pStmt); end_changeset_one_table: while( nCol>0 ) sqlite3_free(azCol[--nCol]); sqlite3_free(azCol); sqlite3_free(aiPk); sqlite3_free(zId); } /* ** Extract the next SQL keyword or quoted string from buffer zIn and copy it ** (or a prefix of it if it will not fit) into buffer zBuf, size nBuf bytes. ** Return a pointer to the character within zIn immediately following ** the token or quoted string just extracted. */ | > > > > > > > > > > | | | | | 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 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 1825 | sqlite3_finalize(pStmt); end_changeset_one_table: while( nCol>0 ) sqlite3_free(azCol[--nCol]); sqlite3_free(azCol); sqlite3_free(aiPk); sqlite3_free(zId); sqlite3_free(aiFlg); strFree(&sql); } /* ** Return true if the ascii character passed as the only argument is a ** whitespace character. Otherwise return false. */ static int is_whitespace(char x){ return (x==' ' || x=='\t' || x=='\n' || x=='\r'); } /* ** Extract the next SQL keyword or quoted string from buffer zIn and copy it ** (or a prefix of it if it will not fit) into buffer zBuf, size nBuf bytes. ** Return a pointer to the character within zIn immediately following ** the token or quoted string just extracted. */ static const char *gobble_token(const char *zIn, char *zBuf, int nBuf){ const char *p = zIn; char *pOut = zBuf; char *pEnd = &pOut[nBuf-1]; char q = 0; /* quote character, if any */ if( p==0 ) return 0; while( is_whitespace(*p) ) p++; switch( *p ){ case '"': q = '"'; break; case '\'': q = '\''; break; case '`': q = '`'; break; case '[': q = ']'; break; } if( q ){ p++; while( *p && pOut<pEnd ){ if( *p==q ){ p++; if( *p!=q ) break; } if( pOut<pEnd ) *pOut++ = *p; p++; } }else{ while( *p && !is_whitespace(*p) && *p!='(' ){ if( pOut<pEnd ) *pOut++ = *p; p++; } } *pOut = '\0'; return p; } /* ** This function is the implementation of SQL scalar function "module_name": ** ** module_name(SQL) ** ** The only argument should be an SQL statement of the type that may appear ** in the sqlite_schema table. If the statement is a "CREATE VIRTUAL TABLE" ** statement, then the value returned is the name of the module that it ** uses. Otherwise, if the statement is not a CVT, NULL is returned. */ static void module_name_func( sqlite3_context *pCtx, int nVal, sqlite3_value **apVal ){ |
︙ | ︙ | |||
1812 1813 1814 1815 1816 1817 1818 | rc = sqlite3_create_function( g.db, "module_name", 1, SQLITE_UTF8, 0, module_name_func, 0, 0 ); assert( rc==SQLITE_OK ); return | | | | | | | | 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 1904 1905 1906 1907 1908 1909 | rc = sqlite3_create_function( g.db, "module_name", 1, SQLITE_UTF8, 0, module_name_func, 0, 0 ); assert( rc==SQLITE_OK ); return "SELECT name FROM main.sqlite_schema\n" " WHERE type='table' AND (\n" " module_name(sql) IS NULL OR \n" " module_name(sql) IN (SELECT module FROM temp.tblmap)\n" " ) AND name NOT IN (\n" " SELECT a.name || b.postfix \n" "FROM main.sqlite_schema AS a, temp.tblmap AS b \n" "WHERE module_name(a.sql) = b.module\n" " )\n" "UNION \n" "SELECT name FROM aux.sqlite_schema\n" " WHERE type='table' AND (\n" " module_name(sql) IS NULL OR \n" " module_name(sql) IN (SELECT module FROM temp.tblmap)\n" " ) AND name NOT IN (\n" " SELECT a.name || b.postfix \n" "FROM aux.sqlite_schema AS a, temp.tblmap AS b \n" "WHERE module_name(a.sql) = b.module\n" " )\n" " ORDER BY name"; }else{ return "SELECT name FROM main.sqlite_schema\n" " WHERE type='table' AND sql NOT LIKE 'CREATE VIRTUAL%%'\n" " UNION\n" "SELECT name FROM aux.sqlite_schema\n" " WHERE type='table' AND sql NOT LIKE 'CREATE VIRTUAL%%'\n" " ORDER BY name"; } } /* ** Print sketchy documentation for this utility program |
︙ | ︙ | |||
1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 | " --primarykey Use schema-defined PRIMARY KEYs\n" " --rbu Output SQL to create/populate RBU table(s)\n" " --schema Show only differences in the schema\n" " --summary Show only a summary of the differences\n" " --table TAB Show only differences in table TAB\n" " --transaction Show SQL output inside a transaction\n" " --vtab Handle fts3, fts4, fts5 and rtree tables\n" ); } int main(int argc, char **argv){ const char *zDb1 = 0; const char *zDb2 = 0; int i; | > | 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 | " --primarykey Use schema-defined PRIMARY KEYs\n" " --rbu Output SQL to create/populate RBU table(s)\n" " --schema Show only differences in the schema\n" " --summary Show only a summary of the differences\n" " --table TAB Show only differences in table TAB\n" " --transaction Show SQL output inside a transaction\n" " --vtab Handle fts3, fts4, fts5 and rtree tables\n" "See https://sqlite.org/sqldiff.html for detailed explanation.\n" ); } int main(int argc, char **argv){ const char *zDb1 = 0; const char *zDb2 = 0; int i; |
︙ | ︙ | |||
1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 | }else if( strcmp(z,"summary")==0 ){ xDiff = summarize_one_table; }else if( strcmp(z,"table")==0 ){ if( i==argc-1 ) cmdlineError("missing argument to %s", argv[i]); zTab = argv[++i]; }else if( strcmp(z,"transaction")==0 ){ useTransaction = 1; }else if( strcmp(z,"vtab")==0 ){ g.bHandleVtab = 1; }else | > > > | 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 | }else if( strcmp(z,"summary")==0 ){ xDiff = summarize_one_table; }else if( strcmp(z,"table")==0 ){ if( i==argc-1 ) cmdlineError("missing argument to %s", argv[i]); zTab = argv[++i]; g.bSchemaCompare = sqlite3_stricmp(zTab, "sqlite_schema")==0 || sqlite3_stricmp(zTab, "sqlite_master")==0; }else if( strcmp(z,"transaction")==0 ){ useTransaction = 1; }else if( strcmp(z,"vtab")==0 ){ g.bHandleVtab = 1; }else |
︙ | ︙ | |||
1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 | }else{ cmdlineError("unknown argument: %s", argv[i]); } } if( zDb2==0 ){ cmdlineError("two database arguments required"); } rc = sqlite3_open(zDb1, &g.db); if( rc ){ cmdlineError("cannot open database file \"%s\"", zDb1); } | > > > | > > | | 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 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 | }else{ cmdlineError("unknown argument: %s", argv[i]); } } if( zDb2==0 ){ cmdlineError("two database arguments required"); } if( g.bSchemaOnly && g.bSchemaCompare ){ cmdlineError("The --schema option is useless with --table %s .", zTab); } rc = sqlite3_open(zDb1, &g.db); if( rc ){ cmdlineError("cannot open database file \"%s\"", zDb1); } rc = sqlite3_exec(g.db, "SELECT * FROM sqlite_schema", 0, 0, &zErrMsg); if( rc || zErrMsg ){ cmdlineError("\"%s\" does not appear to be a valid SQLite database", zDb1); } #ifndef SQLITE_OMIT_LOAD_EXTENSION sqlite3_enable_load_extension(g.db, 1); for(i=0; i<nExt; i++){ rc = sqlite3_load_extension(g.db, azExt[i], 0, &zErrMsg); if( rc || zErrMsg ){ cmdlineError("error loading %s: %s", azExt[i], zErrMsg); } } free(azExt); #endif zSql = sqlite3_mprintf("ATTACH %Q as aux;", zDb2); rc = sqlite3_exec(g.db, zSql, 0, 0, &zErrMsg); sqlite3_free(zSql); zSql = 0; if( rc || zErrMsg ){ cmdlineError("cannot attach database \"%s\"", zDb2); } rc = sqlite3_exec(g.db, "SELECT * FROM aux.sqlite_schema", 0, 0, &zErrMsg); if( rc || zErrMsg ){ cmdlineError("\"%s\" does not appear to be a valid SQLite database", zDb2); } if( neverUseTransaction ) useTransaction = 0; if( useTransaction ) fprintf(out, "BEGIN TRANSACTION;\n"); if( xDiff==rbudiff_one_table ){ |
︙ | ︙ |
Changes to tool/sqlite3_analyzer.c.in.
︙ | ︙ | |||
10 11 12 13 14 15 16 | #define SQLITE_OMIT_DECLTYPE 1 #define SQLITE_OMIT_DEPRECATED 1 #define SQLITE_OMIT_PROGRESS_CALLBACK 1 #define SQLITE_OMIT_SHARED_CACHE 1 #define SQLITE_DEFAULT_MEMSTATUS 0 #define SQLITE_MAX_EXPR_DEPTH 0 #define SQLITE_OMIT_LOAD_EXTENSION 1 | | | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | #define SQLITE_OMIT_DECLTYPE 1 #define SQLITE_OMIT_DEPRECATED 1 #define SQLITE_OMIT_PROGRESS_CALLBACK 1 #define SQLITE_OMIT_SHARED_CACHE 1 #define SQLITE_DEFAULT_MEMSTATUS 0 #define SQLITE_MAX_EXPR_DEPTH 0 #define SQLITE_OMIT_LOAD_EXTENSION 1 #if !defined(SQLITE_AMALGAMATION) && !defined(USE_EXTERNAL_SQLITE) INCLUDE sqlite3.c #endif INCLUDE $ROOT/src/tclsqlite.c const char *sqlite3_analyzer_init_proc(Tcl_Interp *interp){ (void)interp; return |
︙ | ︙ |
Changes to tool/symbols.sh.
1 2 3 4 5 6 7 | #!/bin/sh # # Run this script in a directory that contains a valid SQLite makefile in # order to verify that unintentionally exported symbols. # make sqlite3.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 | #!/bin/sh # # Run this script in a directory that contains a valid SQLite makefile in # order to verify that unintentionally exported symbols. # make sqlite3.c echo '****** Exported symbols from a build including RTREE, FTS4 & FTS5 ******' gcc -c -DSQLITE_ENABLE_FTS3 -DSQLITE_ENABLE_RTREE \ -DSQLITE_ENABLE_MEMORY_MANAGEMENT -DSQLITE_ENABLE_STAT3 \ -DSQLITE_ENABLE_MEMSYS5 -DSQLITE_ENABLE_UNLOCK_NOTIFY \ -DSQLITE_ENABLE_COLUMN_METADATA -DSQLITE_ENABLE_ATOMIC_WRITE \ -DSQLITE_ENABLE_PREUPDATE_HOOK -DSQLITE_ENABLE_SESSION \ -DSQLITE_ENABLE_FTS5 -DSQLITE_ENABLE_GEOPOLY \ sqlite3.c nm sqlite3.o | grep ' [TD] ' | sort -k 3 echo '****** Surplus symbols from a build including RTREE, FTS4 & FTS5 ******' nm sqlite3.o | grep ' [TD] ' | egrep -v ' .*sqlite3(session|rebaser|changeset|changegroup)?_' echo '****** Dependencies of the core. No extensions. No OS interface *******' gcc -c -DSQLITE_ENABLE_MEMORY_MANAGEMENT -DSQLITE_ENABLE_STAT3 \ -DSQLITE_ENABLE_MEMSYS5 -DSQLITE_ENABLE_UNLOCK_NOTIFY \ -DSQLITE_ENABLE_COLUMN_METADATA -DSQLITE_ENABLE_ATOMIC_WRITE \ -DSQLITE_OS_OTHER -DSQLITE_THREADSAFE=0 \ sqlite3.c |
︙ | ︙ |
Changes to vsixtest/App.xaml.cpp.
︙ | ︙ |